| // Copyright (c) 2012 The Chromium Authors. All rights reserved. | |
| // Use of this source code is governed by a BSD-style license that can be | |
| // found in the LICENSE file. | |
| #include "net/third_party/quiche/src/quic/core/quic_data_writer.h" | |
| #include <cstdint> | |
| #include <cstring> | |
| #include "net/third_party/quiche/src/quic/core/quic_connection_id.h" | |
| #include "net/third_party/quiche/src/quic/core/quic_data_reader.h" | |
| #include "net/third_party/quiche/src/quic/core/quic_types.h" | |
| #include "net/third_party/quiche/src/quic/core/quic_utils.h" | |
| #include "net/third_party/quiche/src/quic/platform/api/quic_expect_bug.h" | |
| #include "net/third_party/quiche/src/quic/platform/api/quic_flags.h" | |
| #include "net/third_party/quiche/src/quic/platform/api/quic_test.h" | |
| #include "net/third_party/quiche/src/quic/test_tools/quic_test_utils.h" | |
| #include "net/third_party/quiche/src/common/platform/api/quiche_arraysize.h" | |
| #include "net/third_party/quiche/src/common/platform/api/quiche_endian.h" | |
| #include "net/third_party/quiche/src/common/platform/api/quiche_str_cat.h" | |
| #include "net/third_party/quiche/src/common/platform/api/quiche_string_piece.h" | |
| #include "net/third_party/quiche/src/common/test_tools/quiche_test_utils.h" | |
| namespace quic { | |
| namespace test { | |
| namespace { | |
| char* AsChars(unsigned char* data) { | |
| return reinterpret_cast<char*>(data); | |
| } | |
| struct TestParams { | |
| explicit TestParams(quiche::Endianness endianness) : endianness(endianness) {} | |
| quiche::Endianness endianness; | |
| }; | |
| // Used by ::testing::PrintToStringParamName(). | |
| std::string PrintToString(const TestParams& p) { | |
| return quiche::QuicheStrCat( | |
| (p.endianness == quiche::NETWORK_BYTE_ORDER ? "Network" : "Host"), | |
| "ByteOrder"); | |
| } | |
| std::vector<TestParams> GetTestParams() { | |
| std::vector<TestParams> params; | |
| for (quiche::Endianness endianness : | |
| {quiche::NETWORK_BYTE_ORDER, quiche::HOST_BYTE_ORDER}) { | |
| params.push_back(TestParams(endianness)); | |
| } | |
| return params; | |
| } | |
| class QuicDataWriterTest : public QuicTestWithParam<TestParams> {}; | |
| INSTANTIATE_TEST_SUITE_P(QuicDataWriterTests, | |
| QuicDataWriterTest, | |
| ::testing::ValuesIn(GetTestParams()), | |
| ::testing::PrintToStringParamName()); | |
| TEST_P(QuicDataWriterTest, SanityCheckUFloat16Consts) { | |
| // Check the arithmetic on the constants - otherwise the values below make | |
| // no sense. | |
| EXPECT_EQ(30, kUFloat16MaxExponent); | |
| EXPECT_EQ(11, kUFloat16MantissaBits); | |
| EXPECT_EQ(12, kUFloat16MantissaEffectiveBits); | |
| EXPECT_EQ(UINT64_C(0x3FFC0000000), kUFloat16MaxValue); | |
| } | |
| TEST_P(QuicDataWriterTest, WriteUFloat16) { | |
| struct TestCase { | |
| uint64_t decoded; | |
| uint16_t encoded; | |
| }; | |
| TestCase test_cases[] = { | |
| // Small numbers represent themselves. | |
| {0, 0}, | |
| {1, 1}, | |
| {2, 2}, | |
| {3, 3}, | |
| {4, 4}, | |
| {5, 5}, | |
| {6, 6}, | |
| {7, 7}, | |
| {15, 15}, | |
| {31, 31}, | |
| {42, 42}, | |
| {123, 123}, | |
| {1234, 1234}, | |
| // Check transition through 2^11. | |
| {2046, 2046}, | |
| {2047, 2047}, | |
| {2048, 2048}, | |
| {2049, 2049}, | |
| // Running out of mantissa at 2^12. | |
| {4094, 4094}, | |
| {4095, 4095}, | |
| {4096, 4096}, | |
| {4097, 4096}, | |
| {4098, 4097}, | |
| {4099, 4097}, | |
| {4100, 4098}, | |
| {4101, 4098}, | |
| // Check transition through 2^13. | |
| {8190, 6143}, | |
| {8191, 6143}, | |
| {8192, 6144}, | |
| {8193, 6144}, | |
| {8194, 6144}, | |
| {8195, 6144}, | |
| {8196, 6145}, | |
| {8197, 6145}, | |
| // Half-way through the exponents. | |
| {0x7FF8000, 0x87FF}, | |
| {0x7FFFFFF, 0x87FF}, | |
| {0x8000000, 0x8800}, | |
| {0xFFF0000, 0x8FFF}, | |
| {0xFFFFFFF, 0x8FFF}, | |
| {0x10000000, 0x9000}, | |
| // Transition into the largest exponent. | |
| {0x1FFFFFFFFFE, 0xF7FF}, | |
| {0x1FFFFFFFFFF, 0xF7FF}, | |
| {0x20000000000, 0xF800}, | |
| {0x20000000001, 0xF800}, | |
| {0x2003FFFFFFE, 0xF800}, | |
| {0x2003FFFFFFF, 0xF800}, | |
| {0x20040000000, 0xF801}, | |
| {0x20040000001, 0xF801}, | |
| // Transition into the max value and clamping. | |
| {0x3FF80000000, 0xFFFE}, | |
| {0x3FFBFFFFFFF, 0xFFFE}, | |
| {0x3FFC0000000, 0xFFFF}, | |
| {0x3FFC0000001, 0xFFFF}, | |
| {0x3FFFFFFFFFF, 0xFFFF}, | |
| {0x40000000000, 0xFFFF}, | |
| {0xFFFFFFFFFFFFFFFF, 0xFFFF}, | |
| }; | |
| int num_test_cases = sizeof(test_cases) / sizeof(test_cases[0]); | |
| for (int i = 0; i < num_test_cases; ++i) { | |
| char buffer[2]; | |
| QuicDataWriter writer(2, buffer, GetParam().endianness); | |
| EXPECT_TRUE(writer.WriteUFloat16(test_cases[i].decoded)); | |
| uint16_t result = *reinterpret_cast<uint16_t*>(writer.data()); | |
| if (GetParam().endianness == quiche::NETWORK_BYTE_ORDER) { | |
| result = quiche::QuicheEndian::HostToNet16(result); | |
| } | |
| EXPECT_EQ(test_cases[i].encoded, result); | |
| } | |
| } | |
| TEST_P(QuicDataWriterTest, ReadUFloat16) { | |
| struct TestCase { | |
| uint64_t decoded; | |
| uint16_t encoded; | |
| }; | |
| TestCase test_cases[] = { | |
| // There are fewer decoding test cases because encoding truncates, and | |
| // decoding returns the smallest expansion. | |
| // Small numbers represent themselves. | |
| {0, 0}, | |
| {1, 1}, | |
| {2, 2}, | |
| {3, 3}, | |
| {4, 4}, | |
| {5, 5}, | |
| {6, 6}, | |
| {7, 7}, | |
| {15, 15}, | |
| {31, 31}, | |
| {42, 42}, | |
| {123, 123}, | |
| {1234, 1234}, | |
| // Check transition through 2^11. | |
| {2046, 2046}, | |
| {2047, 2047}, | |
| {2048, 2048}, | |
| {2049, 2049}, | |
| // Running out of mantissa at 2^12. | |
| {4094, 4094}, | |
| {4095, 4095}, | |
| {4096, 4096}, | |
| {4098, 4097}, | |
| {4100, 4098}, | |
| // Check transition through 2^13. | |
| {8190, 6143}, | |
| {8192, 6144}, | |
| {8196, 6145}, | |
| // Half-way through the exponents. | |
| {0x7FF8000, 0x87FF}, | |
| {0x8000000, 0x8800}, | |
| {0xFFF0000, 0x8FFF}, | |
| {0x10000000, 0x9000}, | |
| // Transition into the largest exponent. | |
| {0x1FFE0000000, 0xF7FF}, | |
| {0x20000000000, 0xF800}, | |
| {0x20040000000, 0xF801}, | |
| // Transition into the max value. | |
| {0x3FF80000000, 0xFFFE}, | |
| {0x3FFC0000000, 0xFFFF}, | |
| }; | |
| int num_test_cases = sizeof(test_cases) / sizeof(test_cases[0]); | |
| for (int i = 0; i < num_test_cases; ++i) { | |
| uint16_t encoded_ufloat = test_cases[i].encoded; | |
| if (GetParam().endianness == quiche::NETWORK_BYTE_ORDER) { | |
| encoded_ufloat = quiche::QuicheEndian::HostToNet16(encoded_ufloat); | |
| } | |
| QuicDataReader reader(reinterpret_cast<char*>(&encoded_ufloat), 2, | |
| GetParam().endianness); | |
| uint64_t value; | |
| EXPECT_TRUE(reader.ReadUFloat16(&value)); | |
| EXPECT_EQ(test_cases[i].decoded, value); | |
| } | |
| } | |
| TEST_P(QuicDataWriterTest, RoundTripUFloat16) { | |
| // Just test all 16-bit encoded values. 0 and max already tested above. | |
| uint64_t previous_value = 0; | |
| for (uint16_t i = 1; i < 0xFFFF; ++i) { | |
| // Read the two bytes. | |
| uint16_t read_number = i; | |
| if (GetParam().endianness == quiche::NETWORK_BYTE_ORDER) { | |
| read_number = quiche::QuicheEndian::HostToNet16(read_number); | |
| } | |
| QuicDataReader reader(reinterpret_cast<char*>(&read_number), 2, | |
| GetParam().endianness); | |
| uint64_t value; | |
| // All values must be decodable. | |
| EXPECT_TRUE(reader.ReadUFloat16(&value)); | |
| // Check that small numbers represent themselves | |
| if (i < 4097) { | |
| EXPECT_EQ(i, value); | |
| } | |
| // Check there's monotonic growth. | |
| EXPECT_LT(previous_value, value); | |
| // Check that precision is within 0.5% away from the denormals. | |
| if (i > 2000) { | |
| EXPECT_GT(previous_value * 1005, value * 1000); | |
| } | |
| // Check we're always within the promised range. | |
| EXPECT_LT(value, UINT64_C(0x3FFC0000000)); | |
| previous_value = value; | |
| char buffer[6]; | |
| QuicDataWriter writer(6, buffer, GetParam().endianness); | |
| EXPECT_TRUE(writer.WriteUFloat16(value - 1)); | |
| EXPECT_TRUE(writer.WriteUFloat16(value)); | |
| EXPECT_TRUE(writer.WriteUFloat16(value + 1)); | |
| // Check minimal decoding (previous decoding has previous encoding). | |
| uint16_t encoded1 = *reinterpret_cast<uint16_t*>(writer.data()); | |
| uint16_t encoded2 = *reinterpret_cast<uint16_t*>(writer.data() + 2); | |
| uint16_t encoded3 = *reinterpret_cast<uint16_t*>(writer.data() + 4); | |
| if (GetParam().endianness == quiche::NETWORK_BYTE_ORDER) { | |
| encoded1 = quiche::QuicheEndian::NetToHost16(encoded1); | |
| encoded2 = quiche::QuicheEndian::NetToHost16(encoded2); | |
| encoded3 = quiche::QuicheEndian::NetToHost16(encoded3); | |
| } | |
| EXPECT_EQ(i - 1, encoded1); | |
| // Check roundtrip. | |
| EXPECT_EQ(i, encoded2); | |
| // Check next decoding. | |
| EXPECT_EQ(i < 4096 ? i + 1 : i, encoded3); | |
| } | |
| } | |
| TEST_P(QuicDataWriterTest, WriteConnectionId) { | |
| QuicConnectionId connection_id = | |
| TestConnectionId(UINT64_C(0x0011223344556677)); | |
| char big_endian[] = { | |
| 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, | |
| }; | |
| EXPECT_EQ(connection_id.length(), QUICHE_ARRAYSIZE(big_endian)); | |
| ASSERT_LE(connection_id.length(), 255); | |
| char buffer[255]; | |
| QuicDataWriter writer(connection_id.length(), buffer, GetParam().endianness); | |
| EXPECT_TRUE(writer.WriteConnectionId(connection_id)); | |
| quiche::test::CompareCharArraysWithHexError( | |
| "connection_id", buffer, connection_id.length(), big_endian, | |
| connection_id.length()); | |
| QuicConnectionId read_connection_id; | |
| QuicDataReader reader(buffer, connection_id.length(), GetParam().endianness); | |
| EXPECT_TRUE(reader.ReadConnectionId(&read_connection_id, | |
| QUICHE_ARRAYSIZE(big_endian))); | |
| EXPECT_EQ(connection_id, read_connection_id); | |
| } | |
| TEST_P(QuicDataWriterTest, LengthPrefixedConnectionId) { | |
| QuicConnectionId connection_id = | |
| TestConnectionId(UINT64_C(0x0011223344556677)); | |
| char length_prefixed_connection_id[] = { | |
| 0x08, 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, | |
| }; | |
| EXPECT_EQ(QUICHE_ARRAYSIZE(length_prefixed_connection_id), | |
| kConnectionIdLengthSize + connection_id.length()); | |
| char buffer[kConnectionIdLengthSize + 255] = {}; | |
| QuicDataWriter writer(QUICHE_ARRAYSIZE(buffer), buffer); | |
| EXPECT_TRUE(writer.WriteLengthPrefixedConnectionId(connection_id)); | |
| quiche::test::CompareCharArraysWithHexError( | |
| "WriteLengthPrefixedConnectionId", buffer, writer.length(), | |
| length_prefixed_connection_id, | |
| QUICHE_ARRAYSIZE(length_prefixed_connection_id)); | |
| // Verify that writing length then connection ID produces the same output. | |
| memset(buffer, 0, QUICHE_ARRAYSIZE(buffer)); | |
| QuicDataWriter writer2(QUICHE_ARRAYSIZE(buffer), buffer); | |
| EXPECT_TRUE(writer2.WriteUInt8(connection_id.length())); | |
| EXPECT_TRUE(writer2.WriteConnectionId(connection_id)); | |
| quiche::test::CompareCharArraysWithHexError( | |
| "Write length then ConnectionId", buffer, writer2.length(), | |
| length_prefixed_connection_id, | |
| QUICHE_ARRAYSIZE(length_prefixed_connection_id)); | |
| QuicConnectionId read_connection_id; | |
| QuicDataReader reader(buffer, QUICHE_ARRAYSIZE(buffer)); | |
| EXPECT_TRUE(reader.ReadLengthPrefixedConnectionId(&read_connection_id)); | |
| EXPECT_EQ(connection_id, read_connection_id); | |
| // Verify that reading length then connection ID produces the same output. | |
| uint8_t read_connection_id_length2 = 33; | |
| QuicConnectionId read_connection_id2; | |
| QuicDataReader reader2(buffer, QUICHE_ARRAYSIZE(buffer)); | |
| ASSERT_TRUE(reader2.ReadUInt8(&read_connection_id_length2)); | |
| EXPECT_EQ(connection_id.length(), read_connection_id_length2); | |
| EXPECT_TRUE(reader2.ReadConnectionId(&read_connection_id2, | |
| read_connection_id_length2)); | |
| EXPECT_EQ(connection_id, read_connection_id2); | |
| } | |
| TEST_P(QuicDataWriterTest, EmptyConnectionIds) { | |
| QuicConnectionId empty_connection_id = EmptyQuicConnectionId(); | |
| char buffer[2]; | |
| QuicDataWriter writer(QUICHE_ARRAYSIZE(buffer), buffer, | |
| GetParam().endianness); | |
| EXPECT_TRUE(writer.WriteConnectionId(empty_connection_id)); | |
| EXPECT_TRUE(writer.WriteUInt8(1)); | |
| EXPECT_TRUE(writer.WriteConnectionId(empty_connection_id)); | |
| EXPECT_TRUE(writer.WriteUInt8(2)); | |
| EXPECT_TRUE(writer.WriteConnectionId(empty_connection_id)); | |
| EXPECT_FALSE(writer.WriteUInt8(3)); | |
| EXPECT_EQ(buffer[0], 1); | |
| EXPECT_EQ(buffer[1], 2); | |
| QuicConnectionId read_connection_id = TestConnectionId(); | |
| uint8_t read_byte; | |
| QuicDataReader reader(buffer, QUICHE_ARRAYSIZE(buffer), | |
| GetParam().endianness); | |
| EXPECT_TRUE(reader.ReadConnectionId(&read_connection_id, 0)); | |
| EXPECT_EQ(read_connection_id, empty_connection_id); | |
| EXPECT_TRUE(reader.ReadUInt8(&read_byte)); | |
| EXPECT_EQ(read_byte, 1); | |
| // Reset read_connection_id to something else to verify that | |
| // ReadConnectionId properly sets it back to empty. | |
| read_connection_id = TestConnectionId(); | |
| EXPECT_TRUE(reader.ReadConnectionId(&read_connection_id, 0)); | |
| EXPECT_EQ(read_connection_id, empty_connection_id); | |
| EXPECT_TRUE(reader.ReadUInt8(&read_byte)); | |
| EXPECT_EQ(read_byte, 2); | |
| read_connection_id = TestConnectionId(); | |
| EXPECT_TRUE(reader.ReadConnectionId(&read_connection_id, 0)); | |
| EXPECT_EQ(read_connection_id, empty_connection_id); | |
| EXPECT_FALSE(reader.ReadUInt8(&read_byte)); | |
| } | |
| TEST_P(QuicDataWriterTest, WriteTag) { | |
| char CHLO[] = { | |
| 'C', | |
| 'H', | |
| 'L', | |
| 'O', | |
| }; | |
| const int kBufferLength = sizeof(QuicTag); | |
| char buffer[kBufferLength]; | |
| QuicDataWriter writer(kBufferLength, buffer, GetParam().endianness); | |
| writer.WriteTag(kCHLO); | |
| quiche::test::CompareCharArraysWithHexError("CHLO", buffer, kBufferLength, | |
| CHLO, kBufferLength); | |
| QuicTag read_chlo; | |
| QuicDataReader reader(buffer, kBufferLength, GetParam().endianness); | |
| reader.ReadTag(&read_chlo); | |
| EXPECT_EQ(kCHLO, read_chlo); | |
| } | |
| TEST_P(QuicDataWriterTest, Write16BitUnsignedIntegers) { | |
| char little_endian16[] = {0x22, 0x11}; | |
| char big_endian16[] = {0x11, 0x22}; | |
| char buffer16[2]; | |
| { | |
| uint16_t in_memory16 = 0x1122; | |
| QuicDataWriter writer(2, buffer16, GetParam().endianness); | |
| writer.WriteUInt16(in_memory16); | |
| quiche::test::CompareCharArraysWithHexError( | |
| "uint16_t", buffer16, 2, | |
| GetParam().endianness == quiche::NETWORK_BYTE_ORDER ? big_endian16 | |
| : little_endian16, | |
| 2); | |
| uint16_t read_number16; | |
| QuicDataReader reader(buffer16, 2, GetParam().endianness); | |
| reader.ReadUInt16(&read_number16); | |
| EXPECT_EQ(in_memory16, read_number16); | |
| } | |
| { | |
| uint64_t in_memory16 = 0x0000000000001122; | |
| QuicDataWriter writer(2, buffer16, GetParam().endianness); | |
| writer.WriteBytesToUInt64(2, in_memory16); | |
| quiche::test::CompareCharArraysWithHexError( | |
| "uint16_t", buffer16, 2, | |
| GetParam().endianness == quiche::NETWORK_BYTE_ORDER ? big_endian16 | |
| : little_endian16, | |
| 2); | |
| uint64_t read_number16; | |
| QuicDataReader reader(buffer16, 2, GetParam().endianness); | |
| reader.ReadBytesToUInt64(2, &read_number16); | |
| EXPECT_EQ(in_memory16, read_number16); | |
| } | |
| } | |
| TEST_P(QuicDataWriterTest, Write24BitUnsignedIntegers) { | |
| char little_endian24[] = {0x33, 0x22, 0x11}; | |
| char big_endian24[] = {0x11, 0x22, 0x33}; | |
| char buffer24[3]; | |
| uint64_t in_memory24 = 0x0000000000112233; | |
| QuicDataWriter writer(3, buffer24, GetParam().endianness); | |
| writer.WriteBytesToUInt64(3, in_memory24); | |
| quiche::test::CompareCharArraysWithHexError( | |
| "uint24", buffer24, 3, | |
| GetParam().endianness == quiche::NETWORK_BYTE_ORDER ? big_endian24 | |
| : little_endian24, | |
| 3); | |
| uint64_t read_number24; | |
| QuicDataReader reader(buffer24, 3, GetParam().endianness); | |
| reader.ReadBytesToUInt64(3, &read_number24); | |
| EXPECT_EQ(in_memory24, read_number24); | |
| } | |
| TEST_P(QuicDataWriterTest, Write32BitUnsignedIntegers) { | |
| char little_endian32[] = {0x44, 0x33, 0x22, 0x11}; | |
| char big_endian32[] = {0x11, 0x22, 0x33, 0x44}; | |
| char buffer32[4]; | |
| { | |
| uint32_t in_memory32 = 0x11223344; | |
| QuicDataWriter writer(4, buffer32, GetParam().endianness); | |
| writer.WriteUInt32(in_memory32); | |
| quiche::test::CompareCharArraysWithHexError( | |
| "uint32_t", buffer32, 4, | |
| GetParam().endianness == quiche::NETWORK_BYTE_ORDER ? big_endian32 | |
| : little_endian32, | |
| 4); | |
| uint32_t read_number32; | |
| QuicDataReader reader(buffer32, 4, GetParam().endianness); | |
| reader.ReadUInt32(&read_number32); | |
| EXPECT_EQ(in_memory32, read_number32); | |
| } | |
| { | |
| uint64_t in_memory32 = 0x11223344; | |
| QuicDataWriter writer(4, buffer32, GetParam().endianness); | |
| writer.WriteBytesToUInt64(4, in_memory32); | |
| quiche::test::CompareCharArraysWithHexError( | |
| "uint32_t", buffer32, 4, | |
| GetParam().endianness == quiche::NETWORK_BYTE_ORDER ? big_endian32 | |
| : little_endian32, | |
| 4); | |
| uint64_t read_number32; | |
| QuicDataReader reader(buffer32, 4, GetParam().endianness); | |
| reader.ReadBytesToUInt64(4, &read_number32); | |
| EXPECT_EQ(in_memory32, read_number32); | |
| } | |
| } | |
| TEST_P(QuicDataWriterTest, Write40BitUnsignedIntegers) { | |
| uint64_t in_memory40 = 0x0000001122334455; | |
| char little_endian40[] = {0x55, 0x44, 0x33, 0x22, 0x11}; | |
| char big_endian40[] = {0x11, 0x22, 0x33, 0x44, 0x55}; | |
| char buffer40[5]; | |
| QuicDataWriter writer(5, buffer40, GetParam().endianness); | |
| writer.WriteBytesToUInt64(5, in_memory40); | |
| quiche::test::CompareCharArraysWithHexError( | |
| "uint40", buffer40, 5, | |
| GetParam().endianness == quiche::NETWORK_BYTE_ORDER ? big_endian40 | |
| : little_endian40, | |
| 5); | |
| uint64_t read_number40; | |
| QuicDataReader reader(buffer40, 5, GetParam().endianness); | |
| reader.ReadBytesToUInt64(5, &read_number40); | |
| EXPECT_EQ(in_memory40, read_number40); | |
| } | |
| TEST_P(QuicDataWriterTest, Write48BitUnsignedIntegers) { | |
| uint64_t in_memory48 = 0x0000112233445566; | |
| char little_endian48[] = {0x66, 0x55, 0x44, 0x33, 0x22, 0x11}; | |
| char big_endian48[] = {0x11, 0x22, 0x33, 0x44, 0x55, 0x66}; | |
| char buffer48[6]; | |
| QuicDataWriter writer(6, buffer48, GetParam().endianness); | |
| writer.WriteBytesToUInt64(6, in_memory48); | |
| quiche::test::CompareCharArraysWithHexError( | |
| "uint48", buffer48, 6, | |
| GetParam().endianness == quiche::NETWORK_BYTE_ORDER ? big_endian48 | |
| : little_endian48, | |
| 6); | |
| uint64_t read_number48; | |
| QuicDataReader reader(buffer48, 6, GetParam().endianness); | |
| reader.ReadBytesToUInt64(6., &read_number48); | |
| EXPECT_EQ(in_memory48, read_number48); | |
| } | |
| TEST_P(QuicDataWriterTest, Write56BitUnsignedIntegers) { | |
| uint64_t in_memory56 = 0x0011223344556677; | |
| char little_endian56[] = {0x77, 0x66, 0x55, 0x44, 0x33, 0x22, 0x11}; | |
| char big_endian56[] = {0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77}; | |
| char buffer56[7]; | |
| QuicDataWriter writer(7, buffer56, GetParam().endianness); | |
| writer.WriteBytesToUInt64(7, in_memory56); | |
| quiche::test::CompareCharArraysWithHexError( | |
| "uint56", buffer56, 7, | |
| GetParam().endianness == quiche::NETWORK_BYTE_ORDER ? big_endian56 | |
| : little_endian56, | |
| 7); | |
| uint64_t read_number56; | |
| QuicDataReader reader(buffer56, 7, GetParam().endianness); | |
| reader.ReadBytesToUInt64(7, &read_number56); | |
| EXPECT_EQ(in_memory56, read_number56); | |
| } | |
| TEST_P(QuicDataWriterTest, Write64BitUnsignedIntegers) { | |
| uint64_t in_memory64 = 0x1122334455667788; | |
| unsigned char little_endian64[] = {0x88, 0x77, 0x66, 0x55, | |
| 0x44, 0x33, 0x22, 0x11}; | |
| unsigned char big_endian64[] = {0x11, 0x22, 0x33, 0x44, | |
| 0x55, 0x66, 0x77, 0x88}; | |
| char buffer64[8]; | |
| QuicDataWriter writer(8, buffer64, GetParam().endianness); | |
| writer.WriteBytesToUInt64(8, in_memory64); | |
| quiche::test::CompareCharArraysWithHexError( | |
| "uint64_t", buffer64, 8, | |
| GetParam().endianness == quiche::NETWORK_BYTE_ORDER | |
| ? AsChars(big_endian64) | |
| : AsChars(little_endian64), | |
| 8); | |
| uint64_t read_number64; | |
| QuicDataReader reader(buffer64, 8, GetParam().endianness); | |
| reader.ReadBytesToUInt64(8, &read_number64); | |
| EXPECT_EQ(in_memory64, read_number64); | |
| QuicDataWriter writer2(8, buffer64, GetParam().endianness); | |
| writer2.WriteUInt64(in_memory64); | |
| quiche::test::CompareCharArraysWithHexError( | |
| "uint64_t", buffer64, 8, | |
| GetParam().endianness == quiche::NETWORK_BYTE_ORDER | |
| ? AsChars(big_endian64) | |
| : AsChars(little_endian64), | |
| 8); | |
| read_number64 = 0u; | |
| QuicDataReader reader2(buffer64, 8, GetParam().endianness); | |
| reader2.ReadUInt64(&read_number64); | |
| EXPECT_EQ(in_memory64, read_number64); | |
| } | |
| TEST_P(QuicDataWriterTest, WriteIntegers) { | |
| char buf[43]; | |
| uint8_t i8 = 0x01; | |
| uint16_t i16 = 0x0123; | |
| uint32_t i32 = 0x01234567; | |
| uint64_t i64 = 0x0123456789ABCDEF; | |
| QuicDataWriter writer(46, buf, GetParam().endianness); | |
| for (size_t i = 0; i < 10; ++i) { | |
| switch (i) { | |
| case 0u: | |
| EXPECT_TRUE(writer.WriteBytesToUInt64(i, i64)); | |
| break; | |
| case 1u: | |
| EXPECT_TRUE(writer.WriteUInt8(i8)); | |
| EXPECT_TRUE(writer.WriteBytesToUInt64(i, i64)); | |
| break; | |
| case 2u: | |
| EXPECT_TRUE(writer.WriteUInt16(i16)); | |
| EXPECT_TRUE(writer.WriteBytesToUInt64(i, i64)); | |
| break; | |
| case 3u: | |
| EXPECT_TRUE(writer.WriteBytesToUInt64(i, i64)); | |
| break; | |
| case 4u: | |
| EXPECT_TRUE(writer.WriteUInt32(i32)); | |
| EXPECT_TRUE(writer.WriteBytesToUInt64(i, i64)); | |
| break; | |
| case 5u: | |
| case 6u: | |
| case 7u: | |
| case 8u: | |
| EXPECT_TRUE(writer.WriteBytesToUInt64(i, i64)); | |
| break; | |
| default: | |
| EXPECT_FALSE(writer.WriteBytesToUInt64(i, i64)); | |
| } | |
| } | |
| QuicDataReader reader(buf, 46, GetParam().endianness); | |
| for (size_t i = 0; i < 10; ++i) { | |
| uint8_t read8; | |
| uint16_t read16; | |
| uint32_t read32; | |
| uint64_t read64; | |
| switch (i) { | |
| case 0u: | |
| EXPECT_TRUE(reader.ReadBytesToUInt64(i, &read64)); | |
| EXPECT_EQ(0u, read64); | |
| break; | |
| case 1u: | |
| EXPECT_TRUE(reader.ReadUInt8(&read8)); | |
| EXPECT_TRUE(reader.ReadBytesToUInt64(i, &read64)); | |
| EXPECT_EQ(i8, read8); | |
| EXPECT_EQ(0xEFu, read64); | |
| break; | |
| case 2u: | |
| EXPECT_TRUE(reader.ReadUInt16(&read16)); | |
| EXPECT_TRUE(reader.ReadBytesToUInt64(i, &read64)); | |
| EXPECT_EQ(i16, read16); | |
| EXPECT_EQ(0xCDEFu, read64); | |
| break; | |
| case 3u: | |
| EXPECT_TRUE(reader.ReadBytesToUInt64(i, &read64)); | |
| EXPECT_EQ(0xABCDEFu, read64); | |
| break; | |
| case 4u: | |
| EXPECT_TRUE(reader.ReadUInt32(&read32)); | |
| EXPECT_TRUE(reader.ReadBytesToUInt64(i, &read64)); | |
| EXPECT_EQ(i32, read32); | |
| EXPECT_EQ(0x89ABCDEFu, read64); | |
| break; | |
| case 5u: | |
| EXPECT_TRUE(reader.ReadBytesToUInt64(i, &read64)); | |
| EXPECT_EQ(0x6789ABCDEFu, read64); | |
| break; | |
| case 6u: | |
| EXPECT_TRUE(reader.ReadBytesToUInt64(i, &read64)); | |
| EXPECT_EQ(0x456789ABCDEFu, read64); | |
| break; | |
| case 7u: | |
| EXPECT_TRUE(reader.ReadBytesToUInt64(i, &read64)); | |
| EXPECT_EQ(0x23456789ABCDEFu, read64); | |
| break; | |
| case 8u: | |
| EXPECT_TRUE(reader.ReadBytesToUInt64(i, &read64)); | |
| EXPECT_EQ(0x0123456789ABCDEFu, read64); | |
| break; | |
| default: | |
| EXPECT_FALSE(reader.ReadBytesToUInt64(i, &read64)); | |
| } | |
| } | |
| } | |
| TEST_P(QuicDataWriterTest, WriteBytes) { | |
| char bytes[] = {0, 1, 2, 3, 4, 5, 6, 7, 8}; | |
| char buf[QUICHE_ARRAYSIZE(bytes)]; | |
| QuicDataWriter writer(QUICHE_ARRAYSIZE(buf), buf, GetParam().endianness); | |
| EXPECT_TRUE(writer.WriteBytes(bytes, QUICHE_ARRAYSIZE(bytes))); | |
| for (unsigned int i = 0; i < QUICHE_ARRAYSIZE(bytes); ++i) { | |
| EXPECT_EQ(bytes[i], buf[i]); | |
| } | |
| } | |
| const int kVarIntBufferLength = 1024; | |
| // Encodes and then decodes a specified value, checks that the | |
| // value that was encoded is the same as the decoded value, the length | |
| // is correct, and that after decoding, all data in the buffer has | |
| // been consumed.. | |
| // Returns true if everything works, false if not. | |
| bool EncodeDecodeValue(uint64_t value_in, char* buffer, size_t size_of_buffer) { | |
| // Init the buffer to all 0, just for cleanliness. Makes for better | |
| // output if, in debugging, we need to dump out the buffer. | |
| memset(buffer, 0, size_of_buffer); | |
| // make a writer. Note that for IETF encoding | |
| // we do not care about endianness... It's always big-endian, | |
| // but the c'tor expects to be told what endianness is in force... | |
| QuicDataWriter writer(size_of_buffer, buffer, | |
| quiche::Endianness::NETWORK_BYTE_ORDER); | |
| // Try to write the value. | |
| if (writer.WriteVarInt62(value_in) != true) { | |
| return false; | |
| } | |
| // Look at the value we encoded. Determine how much should have been | |
| // used based on the value, and then check the state of the writer | |
| // to see that it matches. | |
| size_t expected_length = 0; | |
| if (value_in <= 0x3f) { | |
| expected_length = 1; | |
| } else if (value_in <= 0x3fff) { | |
| expected_length = 2; | |
| } else if (value_in <= 0x3fffffff) { | |
| expected_length = 4; | |
| } else { | |
| expected_length = 8; | |
| } | |
| if (writer.length() != expected_length) { | |
| return false; | |
| } | |
| // set up a reader, just the length we've used, no more, no less. | |
| QuicDataReader reader(buffer, expected_length, | |
| quiche::Endianness::NETWORK_BYTE_ORDER); | |
| uint64_t value_out; | |
| if (reader.ReadVarInt62(&value_out) == false) { | |
| return false; | |
| } | |
| if (value_in != value_out) { | |
| return false; | |
| } | |
| // We only write one value so there had better be nothing left to read | |
| return reader.IsDoneReading(); | |
| } | |
| // Test that 8-byte-encoded Variable Length Integers are properly laid | |
| // out in the buffer. | |
| TEST_P(QuicDataWriterTest, VarInt8Layout) { | |
| char buffer[1024]; | |
| // Check that the layout of bytes in the buffer is correct. Bytes | |
| // are always encoded big endian... | |
| memset(buffer, 0, sizeof(buffer)); | |
| QuicDataWriter writer(sizeof(buffer), static_cast<char*>(buffer), | |
| quiche::Endianness::NETWORK_BYTE_ORDER); | |
| EXPECT_TRUE(writer.WriteVarInt62(UINT64_C(0x3142f3e4d5c6b7a8))); | |
| EXPECT_EQ(static_cast<unsigned char>(*(writer.data() + 0)), | |
| (0x31 + 0xc0)); // 0xc0 for encoding | |
| EXPECT_EQ(static_cast<unsigned char>(*(writer.data() + 1)), 0x42); | |
| EXPECT_EQ(static_cast<unsigned char>(*(writer.data() + 2)), 0xf3); | |
| EXPECT_EQ(static_cast<unsigned char>(*(writer.data() + 3)), 0xe4); | |
| EXPECT_EQ(static_cast<unsigned char>(*(writer.data() + 4)), 0xd5); | |
| EXPECT_EQ(static_cast<unsigned char>(*(writer.data() + 5)), 0xc6); | |
| EXPECT_EQ(static_cast<unsigned char>(*(writer.data() + 6)), 0xb7); | |
| EXPECT_EQ(static_cast<unsigned char>(*(writer.data() + 7)), 0xa8); | |
| } | |
| // Test that 4-byte-encoded Variable Length Integers are properly laid | |
| // out in the buffer. | |
| TEST_P(QuicDataWriterTest, VarInt4Layout) { | |
| char buffer[1024]; | |
| // Check that the layout of bytes in the buffer is correct. Bytes | |
| // are always encoded big endian... | |
| memset(buffer, 0, sizeof(buffer)); | |
| QuicDataWriter writer(sizeof(buffer), static_cast<char*>(buffer), | |
| quiche::Endianness::NETWORK_BYTE_ORDER); | |
| EXPECT_TRUE(writer.WriteVarInt62(0x3243f4e5)); | |
| EXPECT_EQ(static_cast<unsigned char>(*(writer.data() + 0)), | |
| (0x32 + 0x80)); // 0x80 for encoding | |
| EXPECT_EQ(static_cast<unsigned char>(*(writer.data() + 1)), 0x43); | |
| EXPECT_EQ(static_cast<unsigned char>(*(writer.data() + 2)), 0xf4); | |
| EXPECT_EQ(static_cast<unsigned char>(*(writer.data() + 3)), 0xe5); | |
| } | |
| // Test that 2-byte-encoded Variable Length Integers are properly laid | |
| // out in the buffer. | |
| TEST_P(QuicDataWriterTest, VarInt2Layout) { | |
| char buffer[1024]; | |
| // Check that the layout of bytes in the buffer is correct. Bytes | |
| // are always encoded big endian... | |
| memset(buffer, 0, sizeof(buffer)); | |
| QuicDataWriter writer(sizeof(buffer), static_cast<char*>(buffer), | |
| quiche::Endianness::NETWORK_BYTE_ORDER); | |
| EXPECT_TRUE(writer.WriteVarInt62(0x3647)); | |
| EXPECT_EQ(static_cast<unsigned char>(*(writer.data() + 0)), | |
| (0x36 + 0x40)); // 0x40 for encoding | |
| EXPECT_EQ(static_cast<unsigned char>(*(writer.data() + 1)), 0x47); | |
| } | |
| // Test that 1-byte-encoded Variable Length Integers are properly laid | |
| // out in the buffer. | |
| TEST_P(QuicDataWriterTest, VarInt1Layout) { | |
| char buffer[1024]; | |
| // Check that the layout of bytes in the buffer | |
| // is correct. Bytes are always encoded big endian... | |
| memset(buffer, 0, sizeof(buffer)); | |
| QuicDataWriter writer(sizeof(buffer), static_cast<char*>(buffer), | |
| quiche::Endianness::NETWORK_BYTE_ORDER); | |
| EXPECT_TRUE(writer.WriteVarInt62(0x3f)); | |
| EXPECT_EQ(static_cast<unsigned char>(*(writer.data() + 0)), 0x3f); | |
| } | |
| // Test certain, targeted, values that are expected to succeed: | |
| // 0, 1, | |
| // 0x3e, 0x3f, 0x40, 0x41 (around the 1-2 byte transitions) | |
| // 0x3ffe, 0x3fff, 0x4000, 0x4001 (the 2-4 byte transition) | |
| // 0x3ffffffe, 0x3fffffff, 0x40000000, 0x40000001 (the 4-8 byte | |
| // transition) | |
| // 0x3ffffffffffffffe, 0x3fffffffffffffff, (the highest valid values) | |
| // 0xfe, 0xff, 0x100, 0x101, | |
| // 0xfffe, 0xffff, 0x10000, 0x10001, | |
| // 0xfffffe, 0xffffff, 0x1000000, 0x1000001, | |
| // 0xfffffffe, 0xffffffff, 0x100000000, 0x100000001, | |
| // 0xfffffffffe, 0xffffffffff, 0x10000000000, 0x10000000001, | |
| // 0xfffffffffffe, 0xffffffffffff, 0x1000000000000, 0x1000000000001, | |
| // 0xfffffffffffffe, 0xffffffffffffff, 0x100000000000000, 0x100000000000001, | |
| TEST_P(QuicDataWriterTest, VarIntGoodTargetedValues) { | |
| char buffer[kVarIntBufferLength]; | |
| uint64_t passing_values[] = { | |
| 0, | |
| 1, | |
| 0x3e, | |
| 0x3f, | |
| 0x40, | |
| 0x41, | |
| 0x3ffe, | |
| 0x3fff, | |
| 0x4000, | |
| 0x4001, | |
| 0x3ffffffe, | |
| 0x3fffffff, | |
| 0x40000000, | |
| 0x40000001, | |
| 0x3ffffffffffffffe, | |
| 0x3fffffffffffffff, | |
| 0xfe, | |
| 0xff, | |
| 0x100, | |
| 0x101, | |
| 0xfffe, | |
| 0xffff, | |
| 0x10000, | |
| 0x10001, | |
| 0xfffffe, | |
| 0xffffff, | |
| 0x1000000, | |
| 0x1000001, | |
| 0xfffffffe, | |
| 0xffffffff, | |
| 0x100000000, | |
| 0x100000001, | |
| 0xfffffffffe, | |
| 0xffffffffff, | |
| 0x10000000000, | |
| 0x10000000001, | |
| 0xfffffffffffe, | |
| 0xffffffffffff, | |
| 0x1000000000000, | |
| 0x1000000000001, | |
| 0xfffffffffffffe, | |
| 0xffffffffffffff, | |
| 0x100000000000000, | |
| 0x100000000000001, | |
| }; | |
| for (uint64_t test_val : passing_values) { | |
| EXPECT_TRUE( | |
| EncodeDecodeValue(test_val, static_cast<char*>(buffer), sizeof(buffer))) | |
| << " encode/decode of " << test_val << " failed"; | |
| } | |
| } | |
| // | |
| // Test certain, targeted, values where failure is expected (the | |
| // values are invalid w.r.t. IETF VarInt encoding): | |
| // 0x4000000000000000, 0x4000000000000001, ( Just above max allowed value) | |
| // 0xfffffffffffffffe, 0xffffffffffffffff, (should fail) | |
| TEST_P(QuicDataWriterTest, VarIntBadTargetedValues) { | |
| char buffer[kVarIntBufferLength]; | |
| uint64_t failing_values[] = { | |
| 0x4000000000000000, | |
| 0x4000000000000001, | |
| 0xfffffffffffffffe, | |
| 0xffffffffffffffff, | |
| }; | |
| for (uint64_t test_val : failing_values) { | |
| EXPECT_FALSE( | |
| EncodeDecodeValue(test_val, static_cast<char*>(buffer), sizeof(buffer))) | |
| << " encode/decode of " << test_val << " succeeded, but was an " | |
| << "invalid value"; | |
| } | |
| } | |
| // Following tests all try to fill the buffer with multiple values, | |
| // go one value more than the buffer can accommodate, then read | |
| // the successfully encoded values, and try to read the unsuccessfully | |
| // encoded value. The following is the number of values to encode. | |
| const int kMultiVarCount = 1000; | |
| // Test writing & reading multiple 8-byte-encoded varints | |
| TEST_P(QuicDataWriterTest, MultiVarInt8) { | |
| uint64_t test_val; | |
| char buffer[8 * kMultiVarCount]; | |
| memset(buffer, 0, sizeof(buffer)); | |
| QuicDataWriter writer(sizeof(buffer), static_cast<char*>(buffer), | |
| quiche::Endianness::NETWORK_BYTE_ORDER); | |
| // Put N values into the buffer. Adding i to the value ensures that | |
| // each value is different so we can detect if we overwrite values, | |
| // or read the same value over and over. | |
| for (int i = 0; i < kMultiVarCount; i++) { | |
| EXPECT_TRUE(writer.WriteVarInt62(UINT64_C(0x3142f3e4d5c6b7a8) + i)); | |
| } | |
| EXPECT_EQ(writer.length(), 8u * kMultiVarCount); | |
| // N+1st should fail, the buffer is full. | |
| EXPECT_FALSE(writer.WriteVarInt62(UINT64_C(0x3142f3e4d5c6b7a8))); | |
| // Now we should be able to read out the N values that were | |
| // successfully encoded. | |
| QuicDataReader reader(buffer, sizeof(buffer), | |
| quiche::Endianness::NETWORK_BYTE_ORDER); | |
| for (int i = 0; i < kMultiVarCount; i++) { | |
| EXPECT_TRUE(reader.ReadVarInt62(&test_val)); | |
| EXPECT_EQ(test_val, (UINT64_C(0x3142f3e4d5c6b7a8) + i)); | |
| } | |
| // And the N+1st should fail. | |
| EXPECT_FALSE(reader.ReadVarInt62(&test_val)); | |
| } | |
| // Test writing & reading multiple 4-byte-encoded varints | |
| TEST_P(QuicDataWriterTest, MultiVarInt4) { | |
| uint64_t test_val; | |
| char buffer[4 * kMultiVarCount]; | |
| memset(buffer, 0, sizeof(buffer)); | |
| QuicDataWriter writer(sizeof(buffer), static_cast<char*>(buffer), | |
| quiche::Endianness::NETWORK_BYTE_ORDER); | |
| // Put N values into the buffer. Adding i to the value ensures that | |
| // each value is different so we can detect if we overwrite values, | |
| // or read the same value over and over. | |
| for (int i = 0; i < kMultiVarCount; i++) { | |
| EXPECT_TRUE(writer.WriteVarInt62(UINT64_C(0x3142f3e4) + i)); | |
| } | |
| EXPECT_EQ(writer.length(), 4u * kMultiVarCount); | |
| // N+1st should fail, the buffer is full. | |
| EXPECT_FALSE(writer.WriteVarInt62(UINT64_C(0x3142f3e4))); | |
| // Now we should be able to read out the N values that were | |
| // successfully encoded. | |
| QuicDataReader reader(buffer, sizeof(buffer), | |
| quiche::Endianness::NETWORK_BYTE_ORDER); | |
| for (int i = 0; i < kMultiVarCount; i++) { | |
| EXPECT_TRUE(reader.ReadVarInt62(&test_val)); | |
| EXPECT_EQ(test_val, (UINT64_C(0x3142f3e4) + i)); | |
| } | |
| // And the N+1st should fail. | |
| EXPECT_FALSE(reader.ReadVarInt62(&test_val)); | |
| } | |
| // Test writing & reading multiple 2-byte-encoded varints | |
| TEST_P(QuicDataWriterTest, MultiVarInt2) { | |
| uint64_t test_val; | |
| char buffer[2 * kMultiVarCount]; | |
| memset(buffer, 0, sizeof(buffer)); | |
| QuicDataWriter writer(sizeof(buffer), static_cast<char*>(buffer), | |
| quiche::Endianness::NETWORK_BYTE_ORDER); | |
| // Put N values into the buffer. Adding i to the value ensures that | |
| // each value is different so we can detect if we overwrite values, | |
| // or read the same value over and over. | |
| for (int i = 0; i < kMultiVarCount; i++) { | |
| EXPECT_TRUE(writer.WriteVarInt62(UINT64_C(0x3142) + i)); | |
| } | |
| EXPECT_EQ(writer.length(), 2u * kMultiVarCount); | |
| // N+1st should fail, the buffer is full. | |
| EXPECT_FALSE(writer.WriteVarInt62(UINT64_C(0x3142))); | |
| // Now we should be able to read out the N values that were | |
| // successfully encoded. | |
| QuicDataReader reader(buffer, sizeof(buffer), | |
| quiche::Endianness::NETWORK_BYTE_ORDER); | |
| for (int i = 0; i < kMultiVarCount; i++) { | |
| EXPECT_TRUE(reader.ReadVarInt62(&test_val)); | |
| EXPECT_EQ(test_val, (UINT64_C(0x3142) + i)); | |
| } | |
| // And the N+1st should fail. | |
| EXPECT_FALSE(reader.ReadVarInt62(&test_val)); | |
| } | |
| // Test writing & reading multiple 1-byte-encoded varints | |
| TEST_P(QuicDataWriterTest, MultiVarInt1) { | |
| uint64_t test_val; | |
| char buffer[1 * kMultiVarCount]; | |
| memset(buffer, 0, sizeof(buffer)); | |
| QuicDataWriter writer(sizeof(buffer), static_cast<char*>(buffer), | |
| quiche::Endianness::NETWORK_BYTE_ORDER); | |
| // Put N values into the buffer. Adding i to the value ensures that | |
| // each value is different so we can detect if we overwrite values, | |
| // or read the same value over and over. &0xf ensures we do not | |
| // overflow the max value for single-byte encoding. | |
| for (int i = 0; i < kMultiVarCount; i++) { | |
| EXPECT_TRUE(writer.WriteVarInt62(UINT64_C(0x30) + (i & 0xf))); | |
| } | |
| EXPECT_EQ(writer.length(), 1u * kMultiVarCount); | |
| // N+1st should fail, the buffer is full. | |
| EXPECT_FALSE(writer.WriteVarInt62(UINT64_C(0x31))); | |
| // Now we should be able to read out the N values that were | |
| // successfully encoded. | |
| QuicDataReader reader(buffer, sizeof(buffer), | |
| quiche::Endianness::NETWORK_BYTE_ORDER); | |
| for (int i = 0; i < kMultiVarCount; i++) { | |
| EXPECT_TRUE(reader.ReadVarInt62(&test_val)); | |
| EXPECT_EQ(test_val, (UINT64_C(0x30) + (i & 0xf))); | |
| } | |
| // And the N+1st should fail. | |
| EXPECT_FALSE(reader.ReadVarInt62(&test_val)); | |
| } | |
| // Test writing varints with a forced length. | |
| TEST_P(QuicDataWriterTest, VarIntFixedLength) { | |
| char buffer[90]; | |
| memset(buffer, 0, sizeof(buffer)); | |
| QuicDataWriter writer(sizeof(buffer), static_cast<char*>(buffer), | |
| quiche::Endianness::NETWORK_BYTE_ORDER); | |
| writer.WriteVarInt62(1, VARIABLE_LENGTH_INTEGER_LENGTH_1); | |
| writer.WriteVarInt62(1, VARIABLE_LENGTH_INTEGER_LENGTH_2); | |
| writer.WriteVarInt62(1, VARIABLE_LENGTH_INTEGER_LENGTH_4); | |
| writer.WriteVarInt62(1, VARIABLE_LENGTH_INTEGER_LENGTH_8); | |
| writer.WriteVarInt62(63, VARIABLE_LENGTH_INTEGER_LENGTH_1); | |
| writer.WriteVarInt62(63, VARIABLE_LENGTH_INTEGER_LENGTH_2); | |
| writer.WriteVarInt62(63, VARIABLE_LENGTH_INTEGER_LENGTH_4); | |
| writer.WriteVarInt62(63, VARIABLE_LENGTH_INTEGER_LENGTH_8); | |
| writer.WriteVarInt62(64, VARIABLE_LENGTH_INTEGER_LENGTH_2); | |
| writer.WriteVarInt62(64, VARIABLE_LENGTH_INTEGER_LENGTH_4); | |
| writer.WriteVarInt62(64, VARIABLE_LENGTH_INTEGER_LENGTH_8); | |
| writer.WriteVarInt62(16383, VARIABLE_LENGTH_INTEGER_LENGTH_2); | |
| writer.WriteVarInt62(16383, VARIABLE_LENGTH_INTEGER_LENGTH_4); | |
| writer.WriteVarInt62(16383, VARIABLE_LENGTH_INTEGER_LENGTH_8); | |
| writer.WriteVarInt62(16384, VARIABLE_LENGTH_INTEGER_LENGTH_4); | |
| writer.WriteVarInt62(16384, VARIABLE_LENGTH_INTEGER_LENGTH_8); | |
| writer.WriteVarInt62(1073741823, VARIABLE_LENGTH_INTEGER_LENGTH_4); | |
| writer.WriteVarInt62(1073741823, VARIABLE_LENGTH_INTEGER_LENGTH_8); | |
| writer.WriteVarInt62(1073741824, VARIABLE_LENGTH_INTEGER_LENGTH_8); | |
| QuicDataReader reader(buffer, sizeof(buffer), | |
| quiche::Endianness::NETWORK_BYTE_ORDER); | |
| uint64_t test_val = 0; | |
| for (int i = 0; i < 4; ++i) { | |
| EXPECT_TRUE(reader.ReadVarInt62(&test_val)); | |
| EXPECT_EQ(test_val, 1u); | |
| } | |
| for (int i = 0; i < 4; ++i) { | |
| EXPECT_TRUE(reader.ReadVarInt62(&test_val)); | |
| EXPECT_EQ(test_val, 63u); | |
| } | |
| for (int i = 0; i < 3; ++i) { | |
| EXPECT_TRUE(reader.ReadVarInt62(&test_val)); | |
| EXPECT_EQ(test_val, 64u); | |
| } | |
| for (int i = 0; i < 3; ++i) { | |
| EXPECT_TRUE(reader.ReadVarInt62(&test_val)); | |
| EXPECT_EQ(test_val, 16383u); | |
| } | |
| for (int i = 0; i < 2; ++i) { | |
| EXPECT_TRUE(reader.ReadVarInt62(&test_val)); | |
| EXPECT_EQ(test_val, 16384u); | |
| } | |
| for (int i = 0; i < 2; ++i) { | |
| EXPECT_TRUE(reader.ReadVarInt62(&test_val)); | |
| EXPECT_EQ(test_val, 1073741823u); | |
| } | |
| EXPECT_TRUE(reader.ReadVarInt62(&test_val)); | |
| EXPECT_EQ(test_val, 1073741824u); | |
| // We are at the end of the buffer so this should fail. | |
| EXPECT_FALSE(reader.ReadVarInt62(&test_val)); | |
| } | |
| // Test encoding/decoding stream-id values. | |
| void EncodeDecodeStreamId(uint64_t value_in) { | |
| char buffer[1 * kMultiVarCount]; | |
| memset(buffer, 0, sizeof(buffer)); | |
| // Encode the given Stream ID. | |
| QuicDataWriter writer(sizeof(buffer), static_cast<char*>(buffer), | |
| quiche::Endianness::NETWORK_BYTE_ORDER); | |
| EXPECT_TRUE(writer.WriteVarInt62(value_in)); | |
| QuicDataReader reader(buffer, sizeof(buffer), | |
| quiche::Endianness::NETWORK_BYTE_ORDER); | |
| QuicStreamId received_stream_id; | |
| uint64_t temp; | |
| EXPECT_TRUE(reader.ReadVarInt62(&temp)); | |
| received_stream_id = static_cast<QuicStreamId>(temp); | |
| EXPECT_EQ(value_in, received_stream_id); | |
| } | |
| // Test writing & reading stream-ids of various value. | |
| TEST_P(QuicDataWriterTest, StreamId1) { | |
| // Check a 1-byte QuicStreamId, should work | |
| EncodeDecodeStreamId(UINT64_C(0x15)); | |
| // Check a 2-byte QuicStream ID. It should work. | |
| EncodeDecodeStreamId(UINT64_C(0x1567)); | |
| // Check a QuicStreamId that requires 4 bytes of encoding | |
| // This should work. | |
| EncodeDecodeStreamId(UINT64_C(0x34567890)); | |
| // Check a QuicStreamId that requires 8 bytes of encoding | |
| // but whose value is in the acceptable range. | |
| // This should work. | |
| EncodeDecodeStreamId(UINT64_C(0xf4567890)); | |
| } | |
| TEST_P(QuicDataWriterTest, WriteRandomBytes) { | |
| char buffer[20]; | |
| char expected[20]; | |
| for (size_t i = 0; i < 20; ++i) { | |
| expected[i] = 'r'; | |
| } | |
| MockRandom random; | |
| QuicDataWriter writer(20, buffer, GetParam().endianness); | |
| EXPECT_FALSE(writer.WriteRandomBytes(&random, 30)); | |
| EXPECT_TRUE(writer.WriteRandomBytes(&random, 20)); | |
| quiche::test::CompareCharArraysWithHexError("random", buffer, 20, expected, | |
| 20); | |
| } | |
| TEST_P(QuicDataWriterTest, PeekVarInt62Length) { | |
| // In range [0, 63], variable length should be 1 byte. | |
| char buffer[20]; | |
| QuicDataWriter writer(20, buffer, quiche::NETWORK_BYTE_ORDER); | |
| EXPECT_TRUE(writer.WriteVarInt62(50)); | |
| QuicDataReader reader(buffer, 20, quiche::NETWORK_BYTE_ORDER); | |
| EXPECT_EQ(1, reader.PeekVarInt62Length()); | |
| // In range (63-16383], variable length should be 2 byte2. | |
| char buffer2[20]; | |
| QuicDataWriter writer2(20, buffer2, quiche::NETWORK_BYTE_ORDER); | |
| EXPECT_TRUE(writer2.WriteVarInt62(100)); | |
| QuicDataReader reader2(buffer2, 20, quiche::NETWORK_BYTE_ORDER); | |
| EXPECT_EQ(2, reader2.PeekVarInt62Length()); | |
| // In range (16383, 1073741823], variable length should be 4 bytes. | |
| char buffer3[20]; | |
| QuicDataWriter writer3(20, buffer3, quiche::NETWORK_BYTE_ORDER); | |
| EXPECT_TRUE(writer3.WriteVarInt62(20000)); | |
| QuicDataReader reader3(buffer3, 20, quiche::NETWORK_BYTE_ORDER); | |
| EXPECT_EQ(4, reader3.PeekVarInt62Length()); | |
| // In range (1073741823, 4611686018427387903], variable length should be 8 | |
| // bytes. | |
| char buffer4[20]; | |
| QuicDataWriter writer4(20, buffer4, quiche::NETWORK_BYTE_ORDER); | |
| EXPECT_TRUE(writer4.WriteVarInt62(2000000000)); | |
| QuicDataReader reader4(buffer4, 20, quiche::NETWORK_BYTE_ORDER); | |
| EXPECT_EQ(8, reader4.PeekVarInt62Length()); | |
| } | |
| TEST_P(QuicDataWriterTest, ValidStreamCount) { | |
| char buffer[1024]; | |
| memset(buffer, 0, sizeof(buffer)); | |
| QuicDataWriter writer(sizeof(buffer), static_cast<char*>(buffer), | |
| quiche::Endianness::NETWORK_BYTE_ORDER); | |
| QuicDataReader reader(buffer, sizeof(buffer)); | |
| const QuicStreamCount write_stream_count = 0xffeeddcc; | |
| EXPECT_TRUE(writer.WriteVarInt62(write_stream_count)); | |
| QuicStreamCount read_stream_count; | |
| uint64_t temp; | |
| EXPECT_TRUE(reader.ReadVarInt62(&temp)); | |
| read_stream_count = static_cast<QuicStreamId>(temp); | |
| EXPECT_EQ(write_stream_count, read_stream_count); | |
| } | |
| TEST_P(QuicDataWriterTest, Seek) { | |
| char buffer[3] = {}; | |
| QuicDataWriter writer(QUICHE_ARRAYSIZE(buffer), buffer, | |
| GetParam().endianness); | |
| EXPECT_TRUE(writer.WriteUInt8(42)); | |
| EXPECT_TRUE(writer.Seek(1)); | |
| EXPECT_TRUE(writer.WriteUInt8(3)); | |
| char expected[] = {42, 0, 3}; | |
| for (size_t i = 0; i < QUICHE_ARRAYSIZE(expected); ++i) { | |
| EXPECT_EQ(buffer[i], expected[i]); | |
| } | |
| } | |
| TEST_P(QuicDataWriterTest, SeekTooFarFails) { | |
| char buffer[20]; | |
| // Check that one can seek to the end of the writer, but not past. | |
| { | |
| QuicDataWriter writer(QUICHE_ARRAYSIZE(buffer), buffer, | |
| GetParam().endianness); | |
| EXPECT_TRUE(writer.Seek(20)); | |
| EXPECT_FALSE(writer.Seek(1)); | |
| } | |
| // Seeking several bytes past the end fails. | |
| { | |
| QuicDataWriter writer(QUICHE_ARRAYSIZE(buffer), buffer, | |
| GetParam().endianness); | |
| EXPECT_FALSE(writer.Seek(100)); | |
| } | |
| // Seeking so far that arithmetic overflow could occur also fails. | |
| { | |
| QuicDataWriter writer(QUICHE_ARRAYSIZE(buffer), buffer, | |
| GetParam().endianness); | |
| EXPECT_TRUE(writer.Seek(10)); | |
| EXPECT_FALSE(writer.Seek(std::numeric_limits<size_t>::max())); | |
| } | |
| } | |
| TEST_P(QuicDataWriterTest, PayloadReads) { | |
| char buffer[16] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16}; | |
| char expected_first_read[4] = {1, 2, 3, 4}; | |
| char expected_remaining[12] = {5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16}; | |
| QuicDataReader reader(buffer, sizeof(buffer)); | |
| char first_read_buffer[4] = {}; | |
| EXPECT_TRUE(reader.ReadBytes(first_read_buffer, sizeof(first_read_buffer))); | |
| quiche::test::CompareCharArraysWithHexError( | |
| "first read", first_read_buffer, sizeof(first_read_buffer), | |
| expected_first_read, sizeof(expected_first_read)); | |
| quiche::QuicheStringPiece peeked_remaining_payload = | |
| reader.PeekRemainingPayload(); | |
| quiche::test::CompareCharArraysWithHexError( | |
| "peeked_remaining_payload", peeked_remaining_payload.data(), | |
| peeked_remaining_payload.length(), expected_remaining, | |
| sizeof(expected_remaining)); | |
| quiche::QuicheStringPiece full_payload = reader.FullPayload(); | |
| quiche::test::CompareCharArraysWithHexError( | |
| "full_payload", full_payload.data(), full_payload.length(), buffer, | |
| sizeof(buffer)); | |
| quiche::QuicheStringPiece read_remaining_payload = | |
| reader.ReadRemainingPayload(); | |
| quiche::test::CompareCharArraysWithHexError( | |
| "read_remaining_payload", read_remaining_payload.data(), | |
| read_remaining_payload.length(), expected_remaining, | |
| sizeof(expected_remaining)); | |
| EXPECT_TRUE(reader.IsDoneReading()); | |
| quiche::QuicheStringPiece full_payload2 = reader.FullPayload(); | |
| quiche::test::CompareCharArraysWithHexError( | |
| "full_payload2", full_payload2.data(), full_payload2.length(), buffer, | |
| sizeof(buffer)); | |
| } | |
| TEST_P(QuicDataWriterTest, StringPieceVarInt62) { | |
| char inner_buffer[16] = {1, 2, 3, 4, 5, 6, 7, 8, | |
| 9, 10, 11, 12, 13, 14, 15, 16}; | |
| quiche::QuicheStringPiece inner_payload_write(inner_buffer, | |
| sizeof(inner_buffer)); | |
| char buffer[sizeof(inner_buffer) + sizeof(uint8_t)] = {}; | |
| QuicDataWriter writer(sizeof(buffer), buffer); | |
| EXPECT_TRUE(writer.WriteStringPieceVarInt62(inner_payload_write)); | |
| EXPECT_EQ(0u, writer.remaining()); | |
| QuicDataReader reader(buffer, sizeof(buffer)); | |
| quiche::QuicheStringPiece inner_payload_read; | |
| EXPECT_TRUE(reader.ReadStringPieceVarInt62(&inner_payload_read)); | |
| quiche::test::CompareCharArraysWithHexError( | |
| "inner_payload", inner_payload_write.data(), inner_payload_write.length(), | |
| inner_payload_read.data(), inner_payload_read.length()); | |
| } | |
| } // namespace | |
| } // namespace test | |
| } // namespace quic |