| // | |
| // Copyright 2015 The ANGLE Project Authors. All rights reserved. | |
| // Use of this source code is governed by a BSD-style license that can be | |
| // found in the LICENSE file. | |
| // | |
| // BinaryStream_unittest.cpp: Unit tests of the binary stream classes. | |
| #include "common/BinaryStream.h" | |
| #include <stdint.h> | |
| #include <string> | |
| #include <vector> | |
| #include "common/PackedEnums.h" | |
| #include "common/span.h" | |
| #include "common/span_util.h" | |
| #include "common/unsafe_buffers.h" | |
| #include "gtest/gtest.h" | |
| namespace angle | |
| { | |
| // Test that errors are properly generated for overflows. | |
| TEST(BinaryInputStream, Overflow) | |
| { | |
| const uint8_t goodValue = 2; | |
| const uint8_t badValue = 255; | |
| const size_t dataSize = 1024; | |
| const size_t slopSize = 1024; | |
| std::vector<uint8_t> data(dataSize + slopSize); | |
| angle::Span<uint8_t> good_data = angle::Span(data).first(dataSize); | |
| angle::Span<uint8_t> bad_data = angle::Span(data).subspan(dataSize); | |
| std::fill(good_data.begin(), good_data.end(), goodValue); | |
| std::fill(bad_data.begin(), bad_data.end(), badValue); | |
| auto checkDataIsSafe = [=](uint8_t item) { return item == goodValue; }; | |
| { | |
| // One large read | |
| std::vector<uint8_t> outputData(dataSize); | |
| gl::BinaryInputStream stream(good_data); | |
| stream.readBytes(outputData); | |
| ASSERT_FALSE(stream.error()); | |
| ASSERT_TRUE(std::all_of(outputData.begin(), outputData.end(), checkDataIsSafe)); | |
| ASSERT_TRUE(stream.endOfStream()); | |
| } | |
| { | |
| // Two half-sized reads | |
| std::vector<uint8_t> outputData(dataSize); | |
| gl::BinaryInputStream stream(good_data); | |
| stream.readBytes(angle::Span(outputData).first(dataSize / 2)); | |
| ASSERT_FALSE(stream.error()); | |
| stream.readBytes(angle::Span(outputData).subspan(dataSize / 2)); | |
| ASSERT_FALSE(stream.error()); | |
| ASSERT_TRUE(std::all_of(outputData.begin(), outputData.end(), checkDataIsSafe)); | |
| ASSERT_TRUE(stream.endOfStream()); | |
| } | |
| { | |
| // One large read that is too big | |
| std::vector<uint8_t> outputData(dataSize + 1); | |
| gl::BinaryInputStream stream(good_data); | |
| stream.readBytes(outputData); | |
| ASSERT_TRUE(stream.error()); | |
| } | |
| { | |
| // Two reads, one that overflows the offset | |
| std::vector<uint8_t> outputData(dataSize - 1); | |
| gl::BinaryInputStream stream(good_data); | |
| stream.readBytes(outputData); | |
| ASSERT_FALSE(stream.error()); | |
| // SAFETY: required for test, span is not legitimate. | |
| ANGLE_UNSAFE_BUFFERS(stream.readBytes( | |
| angle::Span(outputData.data(), std::numeric_limits<size_t>::max() - dataSize - 2))); | |
| ASSERT_TRUE(stream.error()); | |
| } | |
| } | |
| // Test that readInt<> and writeInt<> match. | |
| TEST(BinaryStream, Int) | |
| { | |
| gl::BinaryOutputStream out; | |
| out.writeInt<int8_t>(-100); | |
| out.writeInt<int16_t>(-200); | |
| out.writeInt<int32_t>(-300); | |
| out.writeInt<int64_t>(-400); | |
| out.writeInt<uint8_t>(100); | |
| out.writeInt<uint16_t>(200); | |
| out.writeInt<uint32_t>(300); | |
| out.writeInt<uint64_t>(400); | |
| out.writeInt<size_t>(500); | |
| gl::BinaryInputStream in(out); | |
| EXPECT_EQ(in.readInt<int8_t>(), -100); | |
| EXPECT_EQ(in.readInt<int16_t>(), -200); | |
| EXPECT_EQ(in.readInt<int32_t>(), -300); | |
| EXPECT_EQ(in.readInt<int64_t>(), -400); | |
| EXPECT_EQ(in.readInt<uint8_t>(), 100u); | |
| EXPECT_EQ(in.readInt<uint16_t>(), 200u); | |
| EXPECT_EQ(in.readInt<uint32_t>(), 300u); | |
| EXPECT_EQ(in.readInt<uint64_t>(), 400u); | |
| EXPECT_EQ(in.readInt<size_t>(), 500u); | |
| EXPECT_FALSE(in.error()); | |
| EXPECT_TRUE(in.endOfStream()); | |
| } | |
| // Test that readBool and writeBool match. | |
| TEST(BinaryStream, Bool) | |
| { | |
| gl::BinaryOutputStream out; | |
| out.writeBool(true); | |
| out.writeBool(false); | |
| gl::BinaryInputStream in(out); | |
| EXPECT_EQ(in.readBool(), true); | |
| EXPECT_EQ(in.readBool(), false); | |
| EXPECT_FALSE(in.error()); | |
| EXPECT_TRUE(in.endOfStream()); | |
| } | |
| // Test that readVector and writeVector match. | |
| TEST(BinaryStream, Vector) | |
| { | |
| std::vector<unsigned int> writeData = {1, 2, 3, 4, 5}; | |
| std::vector<unsigned int> readData; | |
| gl::BinaryOutputStream out; | |
| out.writeVector(writeData); | |
| gl::BinaryInputStream in(out); | |
| in.readVector(&readData); | |
| ASSERT_EQ(writeData.size(), readData.size()); | |
| for (size_t i = 0; i < writeData.size(); ++i) | |
| { | |
| ASSERT_EQ(writeData[i], readData[i]); | |
| } | |
| } | |
| // Test that readString and writeString match. | |
| TEST(BinaryStream, String) | |
| { | |
| std::string empty; | |
| std::string hello("hello"); | |
| std::string nulls("\0\0\0", 3u); | |
| EXPECT_EQ(3u, nulls.size()); | |
| gl::BinaryOutputStream out; | |
| out.writeString(empty); | |
| out.writeString(hello); | |
| out.writeString(nulls); | |
| out.writeString(empty); | |
| out.writeString(empty); | |
| out.writeString(hello); | |
| gl::BinaryInputStream in(out); | |
| EXPECT_EQ(in.readString(), empty); | |
| EXPECT_EQ(in.readString(), hello); | |
| EXPECT_EQ(in.readString(), nulls); | |
| EXPECT_EQ(in.readString(), empty); | |
| EXPECT_EQ(in.readString(), empty); | |
| EXPECT_EQ(in.readString(), hello); | |
| EXPECT_FALSE(in.error()); | |
| EXPECT_TRUE(in.endOfStream()); | |
| } | |
| // Test that readStruct and writeStruct match. | |
| TEST(BinaryStream, Struct) | |
| { | |
| struct Pod | |
| { | |
| int count; | |
| char array[3]; | |
| }; | |
| Pod pod1 = {123, {1, 2, 3}}; | |
| gl::BinaryOutputStream out; | |
| out.writeStruct(pod1); | |
| Pod pod2; | |
| gl::BinaryInputStream in(out); | |
| in.readStruct(&pod2); | |
| EXPECT_TRUE(angle::byte_span_from_ref(pod1) == angle::byte_span_from_ref(pod2)); | |
| EXPECT_FALSE(in.error()); | |
| EXPECT_TRUE(in.endOfStream()); | |
| } | |
| // Test that readEnum and writeEnum match. | |
| TEST(BinaryStream, Enum) | |
| { | |
| enum class Color : uint8_t | |
| { | |
| kRed, | |
| kGreen, | |
| kBlue | |
| }; | |
| enum class Shorty : int16_t | |
| { | |
| kNeg = -1, | |
| kMax = 32767 | |
| }; | |
| gl::BinaryOutputStream out; | |
| out.writeEnum(Color::kRed); | |
| out.writeEnum(Shorty::kNeg); | |
| out.writeEnum(Color::kGreen); | |
| out.writeEnum(Shorty::kMax); | |
| out.writeEnum(Color::kBlue); | |
| gl::BinaryInputStream in(out); | |
| EXPECT_EQ(Color::kRed, in.readEnum<Color>()); | |
| EXPECT_EQ(Shorty::kNeg, in.readEnum<Shorty>()); | |
| EXPECT_EQ(Color::kGreen, in.readEnum<Color>()); | |
| EXPECT_EQ(Shorty::kMax, in.readEnum<Shorty>()); | |
| EXPECT_EQ(Color::kBlue, in.readEnum<Color>()); | |
| EXPECT_FALSE(in.error()); | |
| EXPECT_TRUE(in.endOfStream()); | |
| } | |
| // Test that readFloat and writeFloat match. | |
| TEST(BinaryStream, Float) | |
| { | |
| gl::BinaryOutputStream out; | |
| out.writeFloat(123.456f); | |
| out.writeFloat(-100.0f); | |
| out.writeFloat(0.0f); | |
| gl::BinaryInputStream in(out); | |
| EXPECT_EQ(123.456f, in.readFloat()); | |
| EXPECT_EQ(-100.0f, in.readFloat()); | |
| EXPECT_EQ(0.0f, in.readFloat()); | |
| EXPECT_FALSE(in.error()); | |
| EXPECT_TRUE(in.endOfStream()); | |
| } | |
| // Test that readPackedEnumMap and writePackedEnumMap match. | |
| TEST(BinaryStream, PackedEnumMap) | |
| { | |
| enum class Color : int16_t | |
| { | |
| kRed, | |
| kGreen, | |
| kBlue, | |
| EnumCount = 3 | |
| }; | |
| angle::PackedEnumMap<Color, float> map1; | |
| map1[Color::kRed] = 1.0f; | |
| map1[Color::kGreen] = 2.0f; | |
| map1[Color::kBlue] = 3.0f; | |
| gl::BinaryOutputStream out; | |
| out.writePackedEnumMap(map1); | |
| angle::PackedEnumMap<Color, float> map2; | |
| gl::BinaryInputStream in(out); | |
| in.readPackedEnumMap(&map2); | |
| EXPECT_EQ(map2[Color::kRed], 1.0f); | |
| EXPECT_EQ(map2[Color::kGreen], 2.0f); | |
| EXPECT_EQ(map2[Color::kBlue], 3.0f); | |
| EXPECT_FALSE(in.error()); | |
| EXPECT_TRUE(in.endOfStream()); | |
| } | |
| // Test that skipping ahead works as expected. | |
| TEST(BinaryStream, Skip) | |
| { | |
| gl::BinaryOutputStream out; | |
| out.writeFloat(123.456f); | |
| out.writeFloat(-100.0f); | |
| gl::BinaryInputStream in(out); | |
| in.skip(sizeof(float)); | |
| EXPECT_EQ(-100.0f, in.readFloat()); | |
| EXPECT_FALSE(in.error()); | |
| EXPECT_TRUE(in.endOfStream()); | |
| } | |
| } // namespace angle |