blob: 7ae15d2ed4af2fffca9910ca1112ae9c093eb0cf [file] [log] [blame]
// Copyright (c) 2020 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 "quiche/common/quiche_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 "quiche/common/platform/api/quiche_test.h"
#include "quiche/common/quiche_data_reader.h"
#include "quiche/common/quiche_endian.h"
#include "quiche/common/test_tools/quiche_test_utils.h"
namespace quiche {
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 QuicheDataWriterTest : public QuicheTestWithParam<TestParams> {};
INSTANTIATE_TEST_SUITE_P(QuicheDataWriterTests, QuicheDataWriterTest,
::testing::ValuesIn(GetTestParams()),
::testing::PrintToStringParamName());
TEST_P(QuicheDataWriterTest, Write16BitUnsignedIntegers) {
char little_endian16[] = {0x22, 0x11};
char big_endian16[] = {0x11, 0x22};
char buffer16[2];
{
uint16_t in_memory16 = 0x1122;
QuicheDataWriter writer(2, buffer16, GetParam().endianness);
writer.WriteUInt16(in_memory16);
test::CompareCharArraysWithHexError(
"uint16_t", buffer16, 2,
GetParam().endianness == quiche::NETWORK_BYTE_ORDER ? big_endian16
: little_endian16,
2);
uint16_t read_number16;
QuicheDataReader reader(buffer16, 2, GetParam().endianness);
reader.ReadUInt16(&read_number16);
EXPECT_EQ(in_memory16, read_number16);
}
{
uint64_t in_memory16 = 0x0000000000001122;
QuicheDataWriter writer(2, buffer16, GetParam().endianness);
writer.WriteBytesToUInt64(2, in_memory16);
test::CompareCharArraysWithHexError(
"uint16_t", buffer16, 2,
GetParam().endianness == quiche::NETWORK_BYTE_ORDER ? big_endian16
: little_endian16,
2);
uint64_t read_number16;
QuicheDataReader reader(buffer16, 2, GetParam().endianness);
reader.ReadBytesToUInt64(2, &read_number16);
EXPECT_EQ(in_memory16, read_number16);
}
}
TEST_P(QuicheDataWriterTest, Write24BitUnsignedIntegers) {
char little_endian24[] = {0x33, 0x22, 0x11};
char big_endian24[] = {0x11, 0x22, 0x33};
char buffer24[3];
uint64_t in_memory24 = 0x0000000000112233;
QuicheDataWriter writer(3, buffer24, GetParam().endianness);
writer.WriteBytesToUInt64(3, in_memory24);
test::CompareCharArraysWithHexError(
"uint24", buffer24, 3,
GetParam().endianness == quiche::NETWORK_BYTE_ORDER ? big_endian24
: little_endian24,
3);
uint64_t read_number24;
QuicheDataReader reader(buffer24, 3, GetParam().endianness);
reader.ReadBytesToUInt64(3, &read_number24);
EXPECT_EQ(in_memory24, read_number24);
}
TEST_P(QuicheDataWriterTest, Write32BitUnsignedIntegers) {
char little_endian32[] = {0x44, 0x33, 0x22, 0x11};
char big_endian32[] = {0x11, 0x22, 0x33, 0x44};
char buffer32[4];
{
uint32_t in_memory32 = 0x11223344;
QuicheDataWriter writer(4, buffer32, GetParam().endianness);
writer.WriteUInt32(in_memory32);
test::CompareCharArraysWithHexError(
"uint32_t", buffer32, 4,
GetParam().endianness == quiche::NETWORK_BYTE_ORDER ? big_endian32
: little_endian32,
4);
uint32_t read_number32;
QuicheDataReader reader(buffer32, 4, GetParam().endianness);
reader.ReadUInt32(&read_number32);
EXPECT_EQ(in_memory32, read_number32);
}
{
uint64_t in_memory32 = 0x11223344;
QuicheDataWriter writer(4, buffer32, GetParam().endianness);
writer.WriteBytesToUInt64(4, in_memory32);
test::CompareCharArraysWithHexError(
"uint32_t", buffer32, 4,
GetParam().endianness == quiche::NETWORK_BYTE_ORDER ? big_endian32
: little_endian32,
4);
uint64_t read_number32;
QuicheDataReader reader(buffer32, 4, GetParam().endianness);
reader.ReadBytesToUInt64(4, &read_number32);
EXPECT_EQ(in_memory32, read_number32);
}
}
TEST_P(QuicheDataWriterTest, 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];
QuicheDataWriter writer(5, buffer40, GetParam().endianness);
writer.WriteBytesToUInt64(5, in_memory40);
test::CompareCharArraysWithHexError(
"uint40", buffer40, 5,
GetParam().endianness == quiche::NETWORK_BYTE_ORDER ? big_endian40
: little_endian40,
5);
uint64_t read_number40;
QuicheDataReader reader(buffer40, 5, GetParam().endianness);
reader.ReadBytesToUInt64(5, &read_number40);
EXPECT_EQ(in_memory40, read_number40);
}
TEST_P(QuicheDataWriterTest, 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];
QuicheDataWriter writer(6, buffer48, GetParam().endianness);
writer.WriteBytesToUInt64(6, in_memory48);
test::CompareCharArraysWithHexError(
"uint48", buffer48, 6,
GetParam().endianness == quiche::NETWORK_BYTE_ORDER ? big_endian48
: little_endian48,
6);
uint64_t read_number48;
QuicheDataReader reader(buffer48, 6, GetParam().endianness);
reader.ReadBytesToUInt64(6., &read_number48);
EXPECT_EQ(in_memory48, read_number48);
}
TEST_P(QuicheDataWriterTest, 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];
QuicheDataWriter writer(7, buffer56, GetParam().endianness);
writer.WriteBytesToUInt64(7, in_memory56);
test::CompareCharArraysWithHexError(
"uint56", buffer56, 7,
GetParam().endianness == quiche::NETWORK_BYTE_ORDER ? big_endian56
: little_endian56,
7);
uint64_t read_number56;
QuicheDataReader reader(buffer56, 7, GetParam().endianness);
reader.ReadBytesToUInt64(7, &read_number56);
EXPECT_EQ(in_memory56, read_number56);
}
TEST_P(QuicheDataWriterTest, 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];
QuicheDataWriter writer(8, buffer64, GetParam().endianness);
writer.WriteBytesToUInt64(8, in_memory64);
test::CompareCharArraysWithHexError(
"uint64_t", buffer64, 8,
GetParam().endianness == quiche::NETWORK_BYTE_ORDER
? AsChars(big_endian64)
: AsChars(little_endian64),
8);
uint64_t read_number64;
QuicheDataReader reader(buffer64, 8, GetParam().endianness);
reader.ReadBytesToUInt64(8, &read_number64);
EXPECT_EQ(in_memory64, read_number64);
QuicheDataWriter writer2(8, buffer64, GetParam().endianness);
writer2.WriteUInt64(in_memory64);
test::CompareCharArraysWithHexError(
"uint64_t", buffer64, 8,
GetParam().endianness == quiche::NETWORK_BYTE_ORDER
? AsChars(big_endian64)
: AsChars(little_endian64),
8);
read_number64 = 0u;
QuicheDataReader reader2(buffer64, 8, GetParam().endianness);
reader2.ReadUInt64(&read_number64);
EXPECT_EQ(in_memory64, read_number64);
}
TEST_P(QuicheDataWriterTest, WriteIntegers) {
char buf[43];
uint8_t i8 = 0x01;
uint16_t i16 = 0x0123;
uint32_t i32 = 0x01234567;
uint64_t i64 = 0x0123456789ABCDEF;
QuicheDataWriter 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));
}
}
QuicheDataReader 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(QuicheDataWriterTest, WriteBytes) {
char bytes[] = {0, 1, 2, 3, 4, 5, 6, 7, 8};
char buf[ABSL_ARRAYSIZE(bytes)];
QuicheDataWriter 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]);
}
}
TEST_P(QuicheDataWriterTest, Seek) {
char buffer[3] = {};
QuicheDataWriter 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(QuicheDataWriterTest, SeekTooFarFails) {
char buffer[20];
// Check that one can seek to the end of the writer, but not past.
{
QuicheDataWriter writer(ABSL_ARRAYSIZE(buffer), buffer,
GetParam().endianness);
EXPECT_TRUE(writer.Seek(20));
EXPECT_FALSE(writer.Seek(1));
}
// Seeking several bytes past the end fails.
{
QuicheDataWriter writer(ABSL_ARRAYSIZE(buffer), buffer,
GetParam().endianness);
EXPECT_FALSE(writer.Seek(100));
}
// Seeking so far that arithmetic overflow could occur also fails.
{
QuicheDataWriter writer(ABSL_ARRAYSIZE(buffer), buffer,
GetParam().endianness);
EXPECT_TRUE(writer.Seek(10));
EXPECT_FALSE(writer.Seek(std::numeric_limits<size_t>::max()));
}
}
TEST_P(QuicheDataWriterTest, 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};
QuicheDataReader reader(buffer, sizeof(buffer));
absl::string_view previously_read_payload1 = reader.PreviouslyReadPayload();
EXPECT_TRUE(previously_read_payload1.empty());
char first_read_buffer[4] = {};
EXPECT_TRUE(reader.ReadBytes(first_read_buffer, sizeof(first_read_buffer)));
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();
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();
test::CompareCharArraysWithHexError("full_payload", full_payload.data(),
full_payload.length(), buffer,
sizeof(buffer));
absl::string_view previously_read_payload2 = reader.PreviouslyReadPayload();
test::CompareCharArraysWithHexError(
"previously_read_payload2", previously_read_payload2.data(),
previously_read_payload2.length(), first_read_buffer,
sizeof(first_read_buffer));
absl::string_view read_remaining_payload = reader.ReadRemainingPayload();
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();
test::CompareCharArraysWithHexError("full_payload2", full_payload2.data(),
full_payload2.length(), buffer,
sizeof(buffer));
absl::string_view previously_read_payload3 = reader.PreviouslyReadPayload();
test::CompareCharArraysWithHexError(
"previously_read_payload3", previously_read_payload3.data(),
previously_read_payload3.length(), buffer, sizeof(buffer));
}
} // namespace
} // namespace test
} // namespace quiche