// 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]);
  }
}

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...
  QuicheDataWriter 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.
  QuicheDataReader 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(QuicheDataWriterTest, 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));
  QuicheDataWriter 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(QuicheDataWriterTest, 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));
  QuicheDataWriter 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(QuicheDataWriterTest, 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));
  QuicheDataWriter 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(QuicheDataWriterTest, 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));
  QuicheDataWriter 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(QuicheDataWriterTest, 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(QuicheDataWriterTest, 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";
  }
}
// Test writing varints with a forced length.
TEST_P(QuicheDataWriterTest, WriteVarInt62WithForcedLength) {
  char buffer[90];
  memset(buffer, 0, sizeof(buffer));
  QuicheDataWriter writer(sizeof(buffer), static_cast<char*>(buffer));

  writer.WriteVarInt62WithForcedLength(1, VARIABLE_LENGTH_INTEGER_LENGTH_1);
  writer.WriteVarInt62WithForcedLength(1, VARIABLE_LENGTH_INTEGER_LENGTH_2);
  writer.WriteVarInt62WithForcedLength(1, VARIABLE_LENGTH_INTEGER_LENGTH_4);
  writer.WriteVarInt62WithForcedLength(1, VARIABLE_LENGTH_INTEGER_LENGTH_8);

  writer.WriteVarInt62WithForcedLength(63, VARIABLE_LENGTH_INTEGER_LENGTH_1);
  writer.WriteVarInt62WithForcedLength(63, VARIABLE_LENGTH_INTEGER_LENGTH_2);
  writer.WriteVarInt62WithForcedLength(63, VARIABLE_LENGTH_INTEGER_LENGTH_4);
  writer.WriteVarInt62WithForcedLength(63, VARIABLE_LENGTH_INTEGER_LENGTH_8);

  writer.WriteVarInt62WithForcedLength(64, VARIABLE_LENGTH_INTEGER_LENGTH_2);
  writer.WriteVarInt62WithForcedLength(64, VARIABLE_LENGTH_INTEGER_LENGTH_4);
  writer.WriteVarInt62WithForcedLength(64, VARIABLE_LENGTH_INTEGER_LENGTH_8);

  writer.WriteVarInt62WithForcedLength(16383, VARIABLE_LENGTH_INTEGER_LENGTH_2);
  writer.WriteVarInt62WithForcedLength(16383, VARIABLE_LENGTH_INTEGER_LENGTH_4);
  writer.WriteVarInt62WithForcedLength(16383, VARIABLE_LENGTH_INTEGER_LENGTH_8);

  writer.WriteVarInt62WithForcedLength(16384, VARIABLE_LENGTH_INTEGER_LENGTH_4);
  writer.WriteVarInt62WithForcedLength(16384, VARIABLE_LENGTH_INTEGER_LENGTH_8);

  writer.WriteVarInt62WithForcedLength(1073741823,
                                       VARIABLE_LENGTH_INTEGER_LENGTH_4);
  writer.WriteVarInt62WithForcedLength(1073741823,
                                       VARIABLE_LENGTH_INTEGER_LENGTH_8);

  writer.WriteVarInt62WithForcedLength(1073741824,
                                       VARIABLE_LENGTH_INTEGER_LENGTH_8);

  QuicheDataReader reader(buffer, sizeof(buffer));

  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));
}

// 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(QuicheDataWriterTest, MultiVarInt8) {
  uint64_t test_val;
  char buffer[8 * kMultiVarCount];
  memset(buffer, 0, sizeof(buffer));
  QuicheDataWriter 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.
  QuicheDataReader 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(QuicheDataWriterTest, MultiVarInt4) {
  uint64_t test_val;
  char buffer[4 * kMultiVarCount];
  memset(buffer, 0, sizeof(buffer));
  QuicheDataWriter 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.
  QuicheDataReader 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(QuicheDataWriterTest, MultiVarInt2) {
  uint64_t test_val;
  char buffer[2 * kMultiVarCount];
  memset(buffer, 0, sizeof(buffer));
  QuicheDataWriter 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.
  QuicheDataReader 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(QuicheDataWriterTest, MultiVarInt1) {
  uint64_t test_val;
  char buffer[1 * kMultiVarCount];
  memset(buffer, 0, sizeof(buffer));
  QuicheDataWriter 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.
  QuicheDataReader 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_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
