blob: cbe0351fbfc4db5cd71820c32d8a5ab6e11e0743 [file] [log] [blame]
// 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 "quic/core/quic_data_writer.h"
#include <cstdint>
#include <cstring>
#include "absl/base/macros.h"
#include "absl/strings/str_cat.h"
#include "absl/strings/string_view.h"
#include "quic/core/quic_connection_id.h"
#include "quic/core/quic_data_reader.h"
#include "quic/core/quic_types.h"
#include "quic/core/quic_utils.h"
#include "quic/platform/api/quic_expect_bug.h"
#include "quic/platform/api/quic_flags.h"
#include "quic/platform/api/quic_test.h"
#include "quic/test_tools/quic_test_utils.h"
#include "common/quiche_endian.h"
#include "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 absl::StrCat(
(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(), ABSL_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, ABSL_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(ABSL_ARRAYSIZE(length_prefixed_connection_id),
kConnectionIdLengthSize + connection_id.length());
char buffer[kConnectionIdLengthSize + 255] = {};
QuicDataWriter writer(ABSL_ARRAYSIZE(buffer), buffer);
EXPECT_TRUE(writer.WriteLengthPrefixedConnectionId(connection_id));
quiche::test::CompareCharArraysWithHexError(
"WriteLengthPrefixedConnectionId", buffer, writer.length(),
length_prefixed_connection_id,
ABSL_ARRAYSIZE(length_prefixed_connection_id));
// Verify that writing length then connection ID produces the same output.
memset(buffer, 0, ABSL_ARRAYSIZE(buffer));
QuicDataWriter writer2(ABSL_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,
ABSL_ARRAYSIZE(length_prefixed_connection_id));
QuicConnectionId read_connection_id;
QuicDataReader reader(buffer, ABSL_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, ABSL_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(ABSL_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, ABSL_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[ABSL_ARRAYSIZE(bytes)];
QuicDataWriter writer(ABSL_ARRAYSIZE(buf), buf, GetParam().endianness);
EXPECT_TRUE(writer.WriteBytes(bytes, ABSL_ARRAYSIZE(bytes)));
for (unsigned int i = 0; i < ABSL_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, WriteInsecureRandomBytes) {
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.WriteInsecureRandomBytes(&random, 30));
EXPECT_TRUE(writer.WriteInsecureRandomBytes(&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(ABSL_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 < ABSL_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(ABSL_ARRAYSIZE(buffer), buffer,
GetParam().endianness);
EXPECT_TRUE(writer.Seek(20));
EXPECT_FALSE(writer.Seek(1));
}
// Seeking several bytes past the end fails.
{
QuicDataWriter writer(ABSL_ARRAYSIZE(buffer), buffer,
GetParam().endianness);
EXPECT_FALSE(writer.Seek(100));
}
// Seeking so far that arithmetic overflow could occur also fails.
{
QuicDataWriter writer(ABSL_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));
absl::string_view peeked_remaining_payload = reader.PeekRemainingPayload();
quiche::test::CompareCharArraysWithHexError(
"peeked_remaining_payload", peeked_remaining_payload.data(),
peeked_remaining_payload.length(), expected_remaining,
sizeof(expected_remaining));
absl::string_view full_payload = reader.FullPayload();
quiche::test::CompareCharArraysWithHexError(
"full_payload", full_payload.data(), full_payload.length(), buffer,
sizeof(buffer));
absl::string_view 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());
absl::string_view 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};
absl::string_view 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));
absl::string_view 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