blob: 9bde32c1773e28f29b4bf78b995cfecdd2c4545f [file]
// Copyright 2019 The Pigweed Authors
//
// Licensed under the Apache License, Version 2.0 (the "License"); you may not
// use this file except in compliance with the License. You may obtain a copy of
// the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
// License for the specific language governing permissions and limitations under
// the License.
#include "pw_varint/varint.h"
#include <cinttypes>
#include <cstdint>
#include <cstring>
#include <limits>
#include "pw_fuzzer/fuzztest.h"
#include "pw_unit_test/constexpr.h"
#include "pw_unit_test/framework.h"
namespace pw::varint {
namespace {
// Test fixtures.
extern "C" {
// Functions defined in varint_test.c which call the varint API from C.
size_t pw_varint_CallEncode32(uint32_t value,
void* out_encoded,
size_t out_encoded_size);
size_t pw_varint_CallEncode64(uint64_t value,
void* out_encoded,
size_t out_encoded_size);
size_t pw_varint_CallZigZagAndVarintEncode64(int64_t value,
void* out_encoded,
size_t out_encoded_size);
size_t pw_varint_CallDecode32(const void* encoded,
size_t encoded_size,
uint32_t* out_value);
size_t pw_varint_CallDecode64(const void* encoded,
size_t encoded_size,
uint64_t* out_value);
size_t pw_varint_CallZigZagAndVarintDecode64(const void* encoded,
size_t encoded_size,
int64_t* out_value);
} // extern "C"
// Constant expression that writes `data` from a string to a span of `bytes`.
template <size_t kStringSize>
constexpr ConstByteSpan Write(const char (&data)[kStringSize], ByteSpan bytes) {
constexpr size_t kSizeBytes = kStringSize - 1;
static_assert(kSizeBytes <= kMaxVarint64SizeBytes);
PW_ASSERT(kSizeBytes <= bytes.size());
for (size_t i = 0; i < kSizeBytes; ++i) {
bytes[i] = static_cast<std::byte>(data[i]);
}
return bytes.subspan(0, kSizeBytes);
}
// Constant expression that returns whether the `data` in a string matches a
// span of `bytes`.
template <size_t kStringSize>
[[nodiscard]] constexpr bool Compare(const char (&data)[kStringSize],
ConstByteSpan bytes) {
constexpr size_t kSizeBytes = kStringSize - 1;
if (bytes.size() < kSizeBytes) {
return false;
}
for (size_t i = 0; i < kSizeBytes; ++i) {
if (data[i] != static_cast<char>(bytes[i])) {
return false;
}
}
return true;
}
// Unit tests.
PW_CONSTEXPR_TEST(Varint, EncodeSizeUnsigned32_SmallSingleByte, {
std::byte buffer[kMaxVarint64SizeBytes] = {std::byte('\xff')};
PW_TEST_ASSERT_EQ(1u, Encode(UINT32_C(0), buffer));
PW_TEST_EXPECT_EQ(std::byte{0}, buffer[0]);
PW_TEST_ASSERT_EQ(1u, Encode(UINT32_C(1), buffer));
PW_TEST_EXPECT_EQ(std::byte{1}, buffer[0]);
PW_TEST_ASSERT_EQ(1u, Encode(UINT32_C(2), buffer));
PW_TEST_EXPECT_EQ(std::byte{2}, buffer[0]);
});
TEST(Varint, EncodeSizeUnsigned32_SmallSingleByte_C) {
std::byte buffer[kMaxVarint64SizeBytes] = {std::byte('\xff')};
ASSERT_EQ(1u, pw_varint_CallEncode64(UINT32_C(0), buffer, sizeof(buffer)));
EXPECT_EQ(std::byte{0}, buffer[0]);
ASSERT_EQ(1u, pw_varint_CallEncode64(UINT32_C(1), buffer, sizeof(buffer)));
EXPECT_EQ(std::byte{1}, buffer[0]);
ASSERT_EQ(1u, pw_varint_CallEncode64(UINT32_C(2), buffer, sizeof(buffer)));
EXPECT_EQ(std::byte{2}, buffer[0]);
}
PW_CONSTEXPR_TEST(Varint, EncodeSizeUnsigned32_LargeSingleByte, {
std::byte buffer[kMaxVarint64SizeBytes] = {std::byte('\xff')};
PW_TEST_ASSERT_EQ(1u, Encode(UINT32_C(63), buffer));
PW_TEST_EXPECT_EQ(std::byte{63}, buffer[0]);
PW_TEST_ASSERT_EQ(1u, Encode(UINT32_C(64), buffer));
PW_TEST_EXPECT_EQ(std::byte{64}, buffer[0]);
PW_TEST_ASSERT_EQ(1u, Encode(UINT32_C(126), buffer));
PW_TEST_EXPECT_EQ(std::byte{126}, buffer[0]);
PW_TEST_ASSERT_EQ(1u, Encode(UINT32_C(127), buffer));
PW_TEST_EXPECT_EQ(std::byte{127}, buffer[0]);
});
TEST(Varint, EncodeSizeUnsigned32_LargeSingleByte_C) {
std::byte buffer[kMaxVarint64SizeBytes] = {std::byte('\xff')};
ASSERT_EQ(1u, pw_varint_CallEncode64(UINT32_C(63), buffer, sizeof(buffer)));
EXPECT_EQ(std::byte{63}, buffer[0]);
ASSERT_EQ(1u, pw_varint_CallEncode64(UINT32_C(64), buffer, sizeof(buffer)));
EXPECT_EQ(std::byte{64}, buffer[0]);
ASSERT_EQ(1u, pw_varint_CallEncode64(UINT32_C(126), buffer, sizeof(buffer)));
EXPECT_EQ(std::byte{126}, buffer[0]);
ASSERT_EQ(1u, pw_varint_CallEncode64(UINT32_C(127), buffer, sizeof(buffer)));
EXPECT_EQ(std::byte{127}, buffer[0]);
}
PW_CONSTEXPR_TEST(Varint, EncodeSizeUnsigned32_MultiByte, {
std::byte buffer[kMaxVarint64SizeBytes] = {std::byte('\xff')};
PW_TEST_ASSERT_EQ(2u, Encode(UINT32_C(128), buffer));
PW_TEST_EXPECT_TRUE(Compare("\x80\x01", buffer));
PW_TEST_ASSERT_EQ(2u, Encode(UINT32_C(129), buffer));
PW_TEST_EXPECT_TRUE(Compare("\x81\x01", buffer));
PW_TEST_ASSERT_EQ(5u,
Encode(std::numeric_limits<uint32_t>::max() - 1, buffer));
PW_TEST_EXPECT_TRUE(Compare("\xfe\xff\xff\xff\x0f", buffer));
PW_TEST_ASSERT_EQ(5u, Encode(std::numeric_limits<uint32_t>::max(), buffer));
PW_TEST_EXPECT_TRUE(Compare("\xff\xff\xff\xff\x0f", buffer));
});
TEST(Varint, EncodeSizeUnsigned32_MultiByte_C) {
std::byte buffer[kMaxVarint64SizeBytes] = {std::byte('\xff')};
ASSERT_EQ(2u, pw_varint_CallEncode64(UINT32_C(128), buffer, sizeof(buffer)));
EXPECT_EQ(std::memcmp("\x80\x01", buffer, 2), 0);
ASSERT_EQ(2u, pw_varint_CallEncode64(UINT32_C(129), buffer, sizeof(buffer)));
EXPECT_EQ(std::memcmp("\x81\x01", buffer, 2), 0);
ASSERT_EQ(
5u,
pw_varint_CallEncode32(
std::numeric_limits<uint32_t>::max() - 1, buffer, sizeof(buffer)));
EXPECT_EQ(std::memcmp("\xfe\xff\xff\xff\x0f", buffer, 5), 0);
ASSERT_EQ(5u,
pw_varint_CallEncode32(
std::numeric_limits<uint32_t>::max(), buffer, sizeof(buffer)));
EXPECT_EQ(std::memcmp("\xff\xff\xff\xff\x0f", buffer, 5), 0);
// Call with 64-bit function as well
ASSERT_EQ(2u, pw_varint_CallEncode64(UINT32_C(128), buffer, sizeof(buffer)));
EXPECT_EQ(std::memcmp("\x80\x01", buffer, 2), 0);
ASSERT_EQ(2u, pw_varint_CallEncode64(UINT32_C(129), buffer, sizeof(buffer)));
EXPECT_EQ(std::memcmp("\x81\x01", buffer, 2), 0);
ASSERT_EQ(
5u,
pw_varint_CallEncode64(
std::numeric_limits<uint32_t>::max() - 1, buffer, sizeof(buffer)));
EXPECT_EQ(std::memcmp("\xfe\xff\xff\xff\x0f", buffer, 5), 0);
ASSERT_EQ(5u,
pw_varint_CallEncode64(
std::numeric_limits<uint32_t>::max(), buffer, sizeof(buffer)));
EXPECT_EQ(std::memcmp("\xff\xff\xff\xff\x0f", buffer, 5), 0);
}
PW_CONSTEXPR_TEST(Varint, EncodeSizeSigned32_SmallSingleByte, {
std::byte buffer[kMaxVarint64SizeBytes] = {std::byte('\xff')};
PW_TEST_ASSERT_EQ(1u, Encode(INT32_C(0), buffer));
PW_TEST_EXPECT_EQ(std::byte{0}, buffer[0]);
PW_TEST_ASSERT_EQ(1u, Encode(INT32_C(-1), buffer));
PW_TEST_EXPECT_EQ(std::byte{1}, buffer[0]);
PW_TEST_ASSERT_EQ(1u, Encode(INT32_C(1), buffer));
PW_TEST_EXPECT_EQ(std::byte{2}, buffer[0]);
PW_TEST_ASSERT_EQ(1u, Encode(INT32_C(-2), buffer));
PW_TEST_EXPECT_EQ(std::byte{3}, buffer[0]);
PW_TEST_ASSERT_EQ(1u, Encode(INT32_C(2), buffer));
PW_TEST_EXPECT_EQ(std::byte{4}, buffer[0]);
});
TEST(Varint, EncodeSizeSigned32_SmallSingleByte_C) {
std::byte buffer[kMaxVarint64SizeBytes] = {std::byte('\xff')};
ASSERT_EQ(1u,
pw_varint_CallZigZagAndVarintEncode64(
INT32_C(0), buffer, sizeof(buffer)));
EXPECT_EQ(std::byte{0}, buffer[0]);
ASSERT_EQ(1u,
pw_varint_CallZigZagAndVarintEncode64(
INT32_C(-1), buffer, sizeof(buffer)));
EXPECT_EQ(std::byte{1}, buffer[0]);
ASSERT_EQ(1u,
pw_varint_CallZigZagAndVarintEncode64(
INT32_C(1), buffer, sizeof(buffer)));
EXPECT_EQ(std::byte{2}, buffer[0]);
ASSERT_EQ(1u,
pw_varint_CallZigZagAndVarintEncode64(
INT32_C(-2), buffer, sizeof(buffer)));
EXPECT_EQ(std::byte{3}, buffer[0]);
ASSERT_EQ(1u,
pw_varint_CallZigZagAndVarintEncode64(
INT32_C(2), buffer, sizeof(buffer)));
EXPECT_EQ(std::byte{4}, buffer[0]);
}
PW_CONSTEXPR_TEST(Varint, EncodeSizeSigned32_LargeSingleByte, {
std::byte buffer[kMaxVarint64SizeBytes] = {std::byte('\xff')};
PW_TEST_ASSERT_EQ(1u, Encode(INT32_C(-63), buffer));
PW_TEST_EXPECT_EQ(std::byte{125}, buffer[0]);
PW_TEST_ASSERT_EQ(1u, Encode(INT32_C(63), buffer));
PW_TEST_EXPECT_EQ(std::byte{126}, buffer[0]);
PW_TEST_ASSERT_EQ(1u, Encode(INT32_C(-64), buffer));
PW_TEST_EXPECT_EQ(std::byte{127}, buffer[0]);
});
TEST(Varint, EncodeSizeSigned32_LargeSingleByte_C) {
std::byte buffer[kMaxVarint64SizeBytes] = {std::byte('\xff')};
ASSERT_EQ(1u,
pw_varint_CallZigZagAndVarintEncode64(
INT32_C(-63), buffer, sizeof(buffer)));
EXPECT_EQ(std::byte{125}, buffer[0]);
ASSERT_EQ(1u,
pw_varint_CallZigZagAndVarintEncode64(
INT32_C(63), buffer, sizeof(buffer)));
EXPECT_EQ(std::byte{126}, buffer[0]);
ASSERT_EQ(1u,
pw_varint_CallZigZagAndVarintEncode64(
INT32_C(-64), buffer, sizeof(buffer)));
EXPECT_EQ(std::byte{127}, buffer[0]);
}
PW_CONSTEXPR_TEST(Varint, EncodeSizeSigned32_MultiByte, {
std::byte buffer[kMaxVarint64SizeBytes] = {std::byte('\xff')};
PW_TEST_ASSERT_EQ(2u, Encode(INT32_C(64), buffer));
PW_TEST_EXPECT_TRUE(Compare("\x80\x01", buffer));
PW_TEST_ASSERT_EQ(2u, Encode(INT32_C(-65), buffer));
PW_TEST_EXPECT_TRUE(Compare("\x81\x01", buffer));
PW_TEST_ASSERT_EQ(2u, Encode(INT32_C(65), buffer));
PW_TEST_EXPECT_TRUE(Compare("\x82\x01", buffer));
PW_TEST_ASSERT_EQ(5u, Encode(std::numeric_limits<int32_t>::min(), buffer));
PW_TEST_EXPECT_TRUE(Compare("\xff\xff\xff\xff\x0f", buffer));
PW_TEST_ASSERT_EQ(5u, Encode(std::numeric_limits<int32_t>::max(), buffer));
PW_TEST_EXPECT_TRUE(Compare("\xfe\xff\xff\xff\x0f", buffer));
});
TEST(Varint, EncodeSizeSigned32_MultiByte_C) {
std::byte buffer[kMaxVarint64SizeBytes] = {std::byte('\xff')};
ASSERT_EQ(2u,
pw_varint_CallZigZagAndVarintEncode64(
INT32_C(64), buffer, sizeof(buffer)));
EXPECT_EQ(std::memcmp("\x80\x01", buffer, 2), 0);
ASSERT_EQ(2u,
pw_varint_CallZigZagAndVarintEncode64(
INT32_C(-65), buffer, sizeof(buffer)));
EXPECT_EQ(std::memcmp("\x81\x01", buffer, 2), 0);
ASSERT_EQ(2u,
pw_varint_CallZigZagAndVarintEncode64(
INT32_C(65), buffer, sizeof(buffer)));
EXPECT_EQ(std::memcmp("\x82\x01", buffer, 2), 0);
ASSERT_EQ(5u,
pw_varint_CallZigZagAndVarintEncode64(
std::numeric_limits<int32_t>::min(), buffer, sizeof(buffer)));
EXPECT_EQ(std::memcmp("\xff\xff\xff\xff\x0f", buffer, 5), 0);
ASSERT_EQ(5u,
pw_varint_CallZigZagAndVarintEncode64(
std::numeric_limits<int32_t>::max(), buffer, sizeof(buffer)));
EXPECT_EQ(std::memcmp("\xfe\xff\xff\xff\x0f", buffer, 5), 0);
}
PW_CONSTEXPR_TEST(Varint, EncodeSizeUnsigned64_SmallSingleByte, {
std::byte buffer[kMaxVarint64SizeBytes] = {std::byte('\xff')};
PW_TEST_ASSERT_EQ(1u, Encode(UINT64_C(0), buffer));
PW_TEST_EXPECT_EQ(std::byte{0}, buffer[0]);
PW_TEST_ASSERT_EQ(1u, Encode(UINT64_C(1), buffer));
PW_TEST_EXPECT_EQ(std::byte{1}, buffer[0]);
PW_TEST_ASSERT_EQ(1u, Encode(UINT64_C(2), buffer));
PW_TEST_EXPECT_EQ(std::byte{2}, buffer[0]);
});
TEST(Varint, EncodeSizeUnsigned64_SmallSingleByte_C) {
std::byte buffer[kMaxVarint64SizeBytes] = {std::byte('\xff')};
ASSERT_EQ(1u, pw_varint_CallEncode64(UINT64_C(0), buffer, sizeof(buffer)));
EXPECT_EQ(std::byte{0}, buffer[0]);
ASSERT_EQ(1u, pw_varint_CallEncode64(UINT64_C(1), buffer, sizeof(buffer)));
EXPECT_EQ(std::byte{1}, buffer[0]);
ASSERT_EQ(1u, pw_varint_CallEncode64(UINT64_C(2), buffer, sizeof(buffer)));
EXPECT_EQ(std::byte{2}, buffer[0]);
}
PW_CONSTEXPR_TEST(Varint, EncodeSizeUnsigned64_LargeSingleByte, {
std::byte buffer[kMaxVarint64SizeBytes] = {std::byte('\xff')};
PW_TEST_ASSERT_EQ(1u, Encode(UINT64_C(63), buffer));
PW_TEST_EXPECT_EQ(std::byte{63}, buffer[0]);
PW_TEST_ASSERT_EQ(1u, Encode(UINT64_C(64), buffer));
PW_TEST_EXPECT_EQ(std::byte{64}, buffer[0]);
PW_TEST_ASSERT_EQ(1u, Encode(UINT64_C(126), buffer));
PW_TEST_EXPECT_EQ(std::byte{126}, buffer[0]);
PW_TEST_ASSERT_EQ(1u, Encode(UINT64_C(127), buffer));
PW_TEST_EXPECT_EQ(std::byte{127}, buffer[0]);
});
TEST(Varint, EncodeSizeUnsigned64_LargeSingleByte_C) {
std::byte buffer[kMaxVarint64SizeBytes] = {std::byte('\xff')};
ASSERT_EQ(1u, pw_varint_CallEncode64(UINT64_C(63), buffer, sizeof(buffer)));
EXPECT_EQ(std::byte{63}, buffer[0]);
ASSERT_EQ(1u, pw_varint_CallEncode64(UINT64_C(64), buffer, sizeof(buffer)));
EXPECT_EQ(std::byte{64}, buffer[0]);
ASSERT_EQ(1u, pw_varint_CallEncode64(UINT64_C(126), buffer, sizeof(buffer)));
EXPECT_EQ(std::byte{126}, buffer[0]);
ASSERT_EQ(1u, pw_varint_CallEncode64(UINT64_C(127), buffer, sizeof(buffer)));
EXPECT_EQ(std::byte{127}, buffer[0]);
}
PW_CONSTEXPR_TEST(Varint, EncodeSizeUnsigned64_MultiByte, {
std::byte buffer[kMaxVarint64SizeBytes] = {std::byte('\xff')};
PW_TEST_ASSERT_EQ(2u, Encode(UINT64_C(128), buffer));
PW_TEST_EXPECT_TRUE(Compare("\x80\x01", buffer));
PW_TEST_ASSERT_EQ(2u, Encode(UINT64_C(129), buffer));
PW_TEST_EXPECT_TRUE(Compare("\x81\x01", buffer));
PW_TEST_ASSERT_EQ(5u,
Encode(std::numeric_limits<uint32_t>::max() - 1, buffer));
PW_TEST_EXPECT_TRUE(Compare("\xfe\xff\xff\xff\x0f", buffer));
PW_TEST_ASSERT_EQ(5u, Encode(std::numeric_limits<uint32_t>::max(), buffer));
PW_TEST_EXPECT_TRUE(Compare("\xff\xff\xff\xff\x0f", buffer));
PW_TEST_ASSERT_EQ(10u,
Encode(std::numeric_limits<uint64_t>::max() - 1, buffer));
PW_TEST_EXPECT_TRUE(
Compare("\xfe\xff\xff\xff\xff\xff\xff\xff\xff\x01", buffer));
PW_TEST_ASSERT_EQ(10u, Encode(std::numeric_limits<uint64_t>::max(), buffer));
PW_TEST_EXPECT_TRUE(
Compare("\xff\xff\xff\xff\xff\xff\xff\xff\xff\x01", buffer));
});
TEST(Varint, EncodeSizeUnsigned64_MultiByte_C) {
std::byte buffer[kMaxVarint64SizeBytes] = {std::byte('\xff')};
ASSERT_EQ(2u, pw_varint_CallEncode64(UINT64_C(128), buffer, sizeof(buffer)));
EXPECT_EQ(std::memcmp("\x80\x01", buffer, 2), 0);
ASSERT_EQ(2u, pw_varint_CallEncode64(UINT64_C(129), buffer, sizeof(buffer)));
EXPECT_EQ(std::memcmp("\x81\x01", buffer, 2), 0);
ASSERT_EQ(
5u,
pw_varint_CallEncode64(
std::numeric_limits<uint32_t>::max() - 1, buffer, sizeof(buffer)));
EXPECT_EQ(std::memcmp("\xfe\xff\xff\xff\x0f", buffer, 5), 0);
ASSERT_EQ(5u,
pw_varint_CallEncode64(
std::numeric_limits<uint32_t>::max(), buffer, sizeof(buffer)));
EXPECT_EQ(std::memcmp("\xff\xff\xff\xff\x0f", buffer, 5), 0);
ASSERT_EQ(
10u,
pw_varint_CallEncode64(
std::numeric_limits<uint64_t>::max() - 1, buffer, sizeof(buffer)));
EXPECT_EQ(std::memcmp("\xfe\xff\xff\xff\xff\xff\xff\xff\xff\x01", buffer, 10),
0);
ASSERT_EQ(10u,
pw_varint_CallEncode64(
std::numeric_limits<uint64_t>::max(), buffer, sizeof(buffer)));
EXPECT_EQ(std::memcmp("\xff\xff\xff\xff\xff\xff\xff\xff\xff\x01", buffer, 10),
0);
}
PW_CONSTEXPR_TEST(Varint, EncodeSizeSigned64_SmallSingleByte, {
std::byte buffer[kMaxVarint64SizeBytes] = {std::byte('\xff')};
PW_TEST_ASSERT_EQ(1u, Encode(INT64_C(0), buffer));
PW_TEST_EXPECT_EQ(std::byte{0}, buffer[0]);
PW_TEST_ASSERT_EQ(1u, Encode(INT64_C(-1), buffer));
PW_TEST_EXPECT_EQ(std::byte{1}, buffer[0]);
PW_TEST_ASSERT_EQ(1u, Encode(INT64_C(1), buffer));
PW_TEST_EXPECT_EQ(std::byte{2}, buffer[0]);
PW_TEST_ASSERT_EQ(1u, Encode(INT64_C(-2), buffer));
PW_TEST_EXPECT_EQ(std::byte{3}, buffer[0]);
PW_TEST_ASSERT_EQ(1u, Encode(INT64_C(2), buffer));
PW_TEST_EXPECT_EQ(std::byte{4}, buffer[0]);
});
TEST(Varint, EncodeSizeSigned64_SmallSingleByte_C) {
std::byte buffer[kMaxVarint64SizeBytes] = {std::byte('\xff')};
ASSERT_EQ(1u,
pw_varint_CallZigZagAndVarintEncode64(
INT64_C(0), buffer, sizeof(buffer)));
EXPECT_EQ(std::byte{0}, buffer[0]);
ASSERT_EQ(1u,
pw_varint_CallZigZagAndVarintEncode64(
INT64_C(-1), buffer, sizeof(buffer)));
EXPECT_EQ(std::byte{1}, buffer[0]);
ASSERT_EQ(1u,
pw_varint_CallZigZagAndVarintEncode64(
INT64_C(1), buffer, sizeof(buffer)));
EXPECT_EQ(std::byte{2}, buffer[0]);
ASSERT_EQ(1u,
pw_varint_CallZigZagAndVarintEncode64(
INT64_C(-2), buffer, sizeof(buffer)));
EXPECT_EQ(std::byte{3}, buffer[0]);
ASSERT_EQ(1u,
pw_varint_CallZigZagAndVarintEncode64(
INT64_C(2), buffer, sizeof(buffer)));
EXPECT_EQ(std::byte{4}, buffer[0]);
}
PW_CONSTEXPR_TEST(Varint, EncodeSizeSigned64_LargeSingleByte, {
std::byte buffer[kMaxVarint64SizeBytes] = {std::byte('\xff')};
PW_TEST_ASSERT_EQ(1u, Encode(INT64_C(-63), buffer));
PW_TEST_EXPECT_EQ(std::byte{125}, buffer[0]);
PW_TEST_ASSERT_EQ(1u, Encode(INT64_C(63), buffer));
PW_TEST_EXPECT_EQ(std::byte{126}, buffer[0]);
PW_TEST_ASSERT_EQ(1u, Encode(INT64_C(-64), buffer));
PW_TEST_EXPECT_EQ(std::byte{127}, buffer[0]);
});
TEST(Varint, EncodeSizeSigned64_LargeSingleByte_C) {
std::byte buffer[kMaxVarint64SizeBytes] = {std::byte('\xff')};
ASSERT_EQ(1u,
pw_varint_CallZigZagAndVarintEncode64(
INT64_C(-63), buffer, sizeof(buffer)));
EXPECT_EQ(std::byte{125}, buffer[0]);
ASSERT_EQ(1u,
pw_varint_CallZigZagAndVarintEncode64(
INT64_C(63), buffer, sizeof(buffer)));
EXPECT_EQ(std::byte{126}, buffer[0]);
ASSERT_EQ(1u,
pw_varint_CallZigZagAndVarintEncode64(
INT64_C(-64), buffer, sizeof(buffer)));
EXPECT_EQ(std::byte{127}, buffer[0]);
}
PW_CONSTEXPR_TEST(Varint, EncodeSizeSigned64_MultiByte, {
std::byte buffer[kMaxVarint64SizeBytes] = {std::byte('\xff')};
PW_TEST_ASSERT_EQ(2u, Encode(INT64_C(64), buffer));
PW_TEST_EXPECT_TRUE(Compare("\x80\x01", buffer));
PW_TEST_ASSERT_EQ(2u, Encode(INT64_C(-65), buffer));
PW_TEST_EXPECT_TRUE(Compare("\x81\x01", buffer));
PW_TEST_ASSERT_EQ(2u, Encode(INT64_C(65), buffer));
PW_TEST_EXPECT_TRUE(Compare("\x82\x01", buffer));
PW_TEST_ASSERT_EQ(
5u,
Encode(static_cast<int64_t>(std::numeric_limits<int32_t>::min()),
buffer));
PW_TEST_EXPECT_TRUE(Compare("\xff\xff\xff\xff\x0f", buffer));
PW_TEST_ASSERT_EQ(
5u,
Encode(static_cast<int64_t>(std::numeric_limits<int32_t>::max()),
buffer));
PW_TEST_EXPECT_TRUE(Compare("\xfe\xff\xff\xff\x0f", buffer));
PW_TEST_ASSERT_EQ(10u, Encode(std::numeric_limits<int64_t>::min(), buffer));
PW_TEST_EXPECT_TRUE(
Compare("\xff\xff\xff\xff\xff\xff\xff\xff\xff\x01", buffer));
PW_TEST_ASSERT_EQ(10u, Encode(std::numeric_limits<int64_t>::max(), buffer));
PW_TEST_EXPECT_TRUE(
Compare("\xfe\xff\xff\xff\xff\xff\xff\xff\xff\x01", buffer));
});
TEST(Varint, EncodeSizeSigned64_MultiByte_C) {
std::byte buffer[kMaxVarint64SizeBytes] = {std::byte('\xff')};
ASSERT_EQ(2u,
pw_varint_CallZigZagAndVarintEncode64(
INT64_C(64), buffer, sizeof(buffer)));
EXPECT_EQ(std::memcmp("\x80\x01", buffer, 2), 0);
ASSERT_EQ(2u,
pw_varint_CallZigZagAndVarintEncode64(
INT64_C(-65), buffer, sizeof(buffer)));
EXPECT_EQ(std::memcmp("\x81\x01", buffer, 2), 0);
ASSERT_EQ(2u,
pw_varint_CallZigZagAndVarintEncode64(
INT64_C(65), buffer, sizeof(buffer)));
EXPECT_EQ(std::memcmp("\x82\x01", buffer, 2), 0);
ASSERT_EQ(5u,
pw_varint_CallZigZagAndVarintEncode64(
static_cast<int64_t>(std::numeric_limits<int32_t>::min()),
buffer,
sizeof(buffer)));
EXPECT_EQ(std::memcmp("\xff\xff\xff\xff\x0f", buffer, 5), 0);
ASSERT_EQ(5u,
pw_varint_CallZigZagAndVarintEncode64(
static_cast<int64_t>(std::numeric_limits<int32_t>::max()),
buffer,
sizeof(buffer)));
EXPECT_EQ(std::memcmp("\xfe\xff\xff\xff\x0f", buffer, 5), 0);
ASSERT_EQ(10u,
pw_varint_CallZigZagAndVarintEncode64(
std::numeric_limits<int64_t>::min(), buffer, sizeof(buffer)));
EXPECT_EQ(std::memcmp("\xff\xff\xff\xff\xff\xff\xff\xff\xff\x01", buffer, 10),
0);
ASSERT_EQ(10u,
pw_varint_CallZigZagAndVarintEncode64(
std::numeric_limits<int64_t>::max(), buffer, sizeof(buffer)));
EXPECT_EQ(std::memcmp("\xfe\xff\xff\xff\xff\xff\xff\xff\xff\x01", buffer, 10),
0);
}
// How much to increment by for each iteration of the exhaustive encode/decode
// tests. Set the increment to 1 to test every number (this is slow).
constexpr int kIncrement = 100'000'009;
template <typename T, typename U = T>
void EncodeDecode(T value) {
std::byte buffer[kMaxVarint64SizeBytes] = {std::byte('\xff')};
size_t encoded = Encode(value, buffer);
U result;
size_t decoded = Decode(buffer, &result);
EXPECT_EQ(encoded, decoded);
ASSERT_EQ(value, result);
}
void EncodeDecodeSigned32(int32_t value) {
EncodeDecode<int32_t, int64_t>(value);
}
void EncodeDecodeUnsigned32(uint32_t value) {
EncodeDecode<uint32_t, uint64_t>(value);
}
TEST(Varint, EncodeDecodeSigned32Incremental) {
int32_t i = std::numeric_limits<int32_t>::min();
while (true) {
EncodeDecodeSigned32(i);
if (i > std::numeric_limits<int32_t>::max() - kIncrement) {
break;
}
i += kIncrement;
}
}
FUZZ_TEST(Varint, EncodeDecodeSigned32);
TEST(Varint, EncodeDecodeUnsigned32Incremental) {
uint32_t i = 0;
while (true) {
EncodeDecodeUnsigned32(i);
if (i > std::numeric_limits<uint32_t>::max() - kIncrement) {
break;
}
i += kIncrement;
}
}
FUZZ_TEST(Varint, EncodeDecodeUnsigned32);
template <typename T, typename U = T>
void EncodeDecode_C(T value) {
std::byte buffer[kMaxVarint64SizeBytes] = {std::byte('\xff')};
size_t encoded = 0;
U result(0);
size_t decoded = 0;
if constexpr (sizeof(T) <= sizeof(uint32_t)) {
encoded = pw_varint_CallEncode32(
static_cast<uint32_t>(value), buffer, sizeof(buffer));
decoded = pw_varint_CallDecode32(buffer, sizeof(buffer), &result);
} else {
encoded = pw_varint_CallEncode64(
static_cast<uint64_t>(value), buffer, sizeof(buffer));
decoded = pw_varint_CallDecode64(buffer, sizeof(buffer), &result);
}
EXPECT_EQ(encoded, decoded);
ASSERT_EQ(value, static_cast<T>(result));
}
void EncodeDecodeSigned32_C(int32_t value) {
EncodeDecode_C<int32_t, uint32_t>(value);
}
void EncodeDecodeUnsigned32_C(uint32_t value) {
EncodeDecode_C<uint32_t, uint32_t>(value);
}
TEST(Varint, EncodeDecodeSigned32Incremental_C) {
int32_t i = std::numeric_limits<int32_t>::min();
while (true) {
EncodeDecodeSigned32_C(i);
if (i > std::numeric_limits<int32_t>::max() - kIncrement) {
break;
}
i += kIncrement;
}
}
FUZZ_TEST(Varint, EncodeDecodeSigned32_C);
TEST(Varint, EncodeDecodeUnsigned32Incremental_C) {
uint32_t i = 0;
while (true) {
EncodeDecodeUnsigned32_C(i);
if (i > std::numeric_limits<uint32_t>::max() - kIncrement) {
break;
}
i += kIncrement;
}
}
FUZZ_TEST(Varint, EncodeDecodeUnsigned32_C);
PW_CONSTEXPR_TEST(Varint, DecodeSigned64_SingleByte, {
std::byte buffer[kMaxVarint64SizeBytes] = {};
int64_t value = -1234;
PW_TEST_EXPECT_EQ(Decode(Write("\x00", buffer), &value), 1u);
PW_TEST_EXPECT_EQ(value, 0);
PW_TEST_EXPECT_EQ(Decode(Write("\x01", buffer), &value), 1u);
PW_TEST_EXPECT_EQ(value, -1);
PW_TEST_EXPECT_EQ(Decode(Write("\x02", buffer), &value), 1u);
PW_TEST_EXPECT_EQ(value, 1);
PW_TEST_EXPECT_EQ(Decode(Write("\x03", buffer), &value), 1u);
PW_TEST_EXPECT_EQ(value, -2);
PW_TEST_EXPECT_EQ(Decode(Write("\x04", buffer), &value), 1u);
PW_TEST_EXPECT_EQ(value, 2);
PW_TEST_EXPECT_EQ(Decode(Write("\x04", buffer), &value), 1u);
PW_TEST_EXPECT_EQ(value, 2);
});
TEST(Varint, DecodeSigned64_SingleByte_C) {
std::byte buffer[kMaxVarint64SizeBytes] = {};
int64_t value = -1234;
auto bytes = Write("\x00", buffer);
EXPECT_EQ(
pw_varint_CallZigZagAndVarintDecode64(bytes.data(), bytes.size(), &value),
1u);
EXPECT_EQ(value, 0);
bytes = Write("\x01", buffer);
EXPECT_EQ(
pw_varint_CallZigZagAndVarintDecode64(bytes.data(), bytes.size(), &value),
1u);
EXPECT_EQ(value, -1);
bytes = Write("\x02", buffer);
EXPECT_EQ(
pw_varint_CallZigZagAndVarintDecode64(bytes.data(), bytes.size(), &value),
1u);
EXPECT_EQ(value, 1);
bytes = Write("\x03", buffer);
EXPECT_EQ(
pw_varint_CallZigZagAndVarintDecode64(bytes.data(), bytes.size(), &value),
1u);
EXPECT_EQ(value, -2);
bytes = Write("\x04", buffer);
EXPECT_EQ(
pw_varint_CallZigZagAndVarintDecode64(bytes.data(), bytes.size(), &value),
1u);
EXPECT_EQ(value, 2);
bytes = Write("\x04", buffer);
EXPECT_EQ(
pw_varint_CallZigZagAndVarintDecode64(bytes.data(), bytes.size(), &value),
1u);
EXPECT_EQ(value, 2);
}
PW_CONSTEXPR_TEST(Varint, DecodeSigned64_MultiByte, {
std::byte buffer[kMaxVarint64SizeBytes] = {};
int64_t value = -1234;
PW_TEST_EXPECT_EQ(Decode(Write("\x80\x01", buffer), &value), 2u);
PW_TEST_EXPECT_EQ(value, 64);
PW_TEST_EXPECT_EQ(Decode(Write("\x81\x01", buffer), &value), 2u);
PW_TEST_EXPECT_EQ(value, -65);
PW_TEST_EXPECT_EQ(Decode(Write("\x82\x01", buffer), &value), 2u);
PW_TEST_EXPECT_EQ(value, 65);
PW_TEST_EXPECT_EQ(Decode(Write("\xff\xff\xff\xff\x0f", buffer), &value), 5u);
PW_TEST_EXPECT_EQ(value, std::numeric_limits<int32_t>::min());
PW_TEST_EXPECT_EQ(Decode(Write("\xfe\xff\xff\xff\x0f", buffer), &value), 5u);
PW_TEST_EXPECT_EQ(value, std::numeric_limits<int32_t>::max());
PW_TEST_EXPECT_EQ(
Decode(Write("\xff\xff\xff\xff\xff\xff\xff\xff\xff\x01", buffer), &value),
10u);
PW_TEST_EXPECT_EQ(value, std::numeric_limits<int64_t>::min());
PW_TEST_EXPECT_EQ(
Decode(Write("\xfe\xff\xff\xff\xff\xff\xff\xff\xff\x01", buffer), &value),
10u);
PW_TEST_EXPECT_EQ(value, std::numeric_limits<int64_t>::max());
});
TEST(Varint, DecodeSigned64_MultiByte_C) {
std::byte buffer[kMaxVarint64SizeBytes] = {};
int64_t value = -1234;
auto bytes2 = Write("\x80\x01", buffer);
EXPECT_EQ(pw_varint_CallZigZagAndVarintDecode64(
bytes2.data(), bytes2.size(), &value),
2u);
EXPECT_EQ(value, 64);
bytes2 = Write("\x81\x01", buffer);
EXPECT_EQ(pw_varint_CallZigZagAndVarintDecode64(
bytes2.data(), bytes2.size(), &value),
2u);
EXPECT_EQ(value, -65);
bytes2 = Write("\x82\x01", buffer);
EXPECT_EQ(pw_varint_CallZigZagAndVarintDecode64(
bytes2.data(), bytes2.size(), &value),
2u);
EXPECT_EQ(value, 65);
auto bytes4 = Write("\xff\xff\xff\xff\x0f", buffer);
EXPECT_EQ(pw_varint_CallZigZagAndVarintDecode64(
bytes4.data(), bytes4.size(), &value),
5u);
EXPECT_EQ(value, std::numeric_limits<int32_t>::min());
bytes4 = Write("\xfe\xff\xff\xff\x0f", buffer);
EXPECT_EQ(pw_varint_CallZigZagAndVarintDecode64(
bytes4.data(), bytes4.size(), &value),
5u);
EXPECT_EQ(value, std::numeric_limits<int32_t>::max());
auto bytes8 = Write("\xff\xff\xff\xff\xff\xff\xff\xff\xff\x01", buffer);
EXPECT_EQ(pw_varint_CallZigZagAndVarintDecode64(
bytes8.data(), bytes8.size(), &value),
10u);
EXPECT_EQ(value, std::numeric_limits<int64_t>::min());
bytes8 = Write("\xfe\xff\xff\xff\xff\xff\xff\xff\xff\x01", buffer);
EXPECT_EQ(pw_varint_CallZigZagAndVarintDecode64(
bytes8.data(), bytes8.size(), &value),
10u);
EXPECT_EQ(value, std::numeric_limits<int64_t>::max());
}
PW_CONSTEXPR_TEST(Varint, ZigZagEncode_Int8, {
PW_TEST_EXPECT_EQ(ZigZagEncode(int8_t(0)), uint8_t(0));
PW_TEST_EXPECT_EQ(ZigZagEncode(int8_t(-1)), uint8_t(1));
PW_TEST_EXPECT_EQ(ZigZagEncode(int8_t(1)), uint8_t(2));
PW_TEST_EXPECT_EQ(ZigZagEncode(int8_t(-2)), uint8_t(3));
PW_TEST_EXPECT_EQ(ZigZagEncode(int8_t(2)), uint8_t(4));
PW_TEST_EXPECT_EQ(ZigZagEncode(int8_t(-33)), uint8_t(65));
PW_TEST_EXPECT_EQ(ZigZagEncode(int8_t(33)), uint8_t(66));
PW_TEST_EXPECT_EQ(ZigZagEncode(std::numeric_limits<int8_t>::min()),
std::numeric_limits<uint8_t>::max());
PW_TEST_EXPECT_EQ(ZigZagEncode(std::numeric_limits<int8_t>::max()),
std::numeric_limits<uint8_t>::max() - 1u);
});
PW_CONSTEXPR_TEST(Varint, ZigZagEncode_Int16, {
PW_TEST_EXPECT_EQ(ZigZagEncode(int16_t(0)), uint16_t(0));
PW_TEST_EXPECT_EQ(ZigZagEncode(int16_t(-1)), uint16_t(1));
PW_TEST_EXPECT_EQ(ZigZagEncode(int16_t(1)), uint16_t(2));
PW_TEST_EXPECT_EQ(ZigZagEncode(int16_t(-2)), uint16_t(3));
PW_TEST_EXPECT_EQ(ZigZagEncode(int16_t(2)), uint16_t(4));
PW_TEST_EXPECT_EQ(ZigZagEncode(int16_t(-3333)), uint16_t(6665));
PW_TEST_EXPECT_EQ(ZigZagEncode(int16_t(3333)), uint16_t(6666));
PW_TEST_EXPECT_EQ(ZigZagEncode(std::numeric_limits<int16_t>::min()),
std::numeric_limits<uint16_t>::max());
PW_TEST_EXPECT_EQ(ZigZagEncode(std::numeric_limits<int16_t>::max()),
std::numeric_limits<uint16_t>::max() - 1u);
});
PW_CONSTEXPR_TEST(Varint, ZigZagEncode_Int32, {
PW_TEST_EXPECT_EQ(ZigZagEncode(int32_t(0)), uint32_t(0));
PW_TEST_EXPECT_EQ(ZigZagEncode(int32_t(-1)), uint32_t(1));
PW_TEST_EXPECT_EQ(ZigZagEncode(int32_t(1)), uint32_t(2));
PW_TEST_EXPECT_EQ(ZigZagEncode(int32_t(-2)), uint32_t(3));
PW_TEST_EXPECT_EQ(ZigZagEncode(int32_t(2)), uint32_t(4));
PW_TEST_EXPECT_EQ(ZigZagEncode(int32_t(-128)), uint32_t(255));
PW_TEST_EXPECT_EQ(ZigZagEncode(int32_t(128)), uint32_t(256));
PW_TEST_EXPECT_EQ(ZigZagEncode(int32_t(-333333)), uint32_t(666665));
PW_TEST_EXPECT_EQ(ZigZagEncode(int32_t(333333)), uint32_t(666666));
PW_TEST_EXPECT_EQ(ZigZagEncode(std::numeric_limits<int32_t>::min()),
std::numeric_limits<uint32_t>::max());
PW_TEST_EXPECT_EQ(ZigZagEncode(std::numeric_limits<int32_t>::max()),
std::numeric_limits<uint32_t>::max() - 1u);
});
PW_CONSTEXPR_TEST(Varint, ZigZagEncode_Int64, {
PW_TEST_EXPECT_EQ(ZigZagEncode(int64_t(0)), uint64_t(0));
PW_TEST_EXPECT_EQ(ZigZagEncode(int64_t(-1)), uint64_t(1));
PW_TEST_EXPECT_EQ(ZigZagEncode(int64_t(1)), uint64_t(2));
PW_TEST_EXPECT_EQ(ZigZagEncode(int64_t(-2)), uint64_t(3));
PW_TEST_EXPECT_EQ(ZigZagEncode(int64_t(2)), uint64_t(4));
PW_TEST_EXPECT_EQ(ZigZagEncode(int64_t(-3333333333)), uint64_t(6666666665));
PW_TEST_EXPECT_EQ(ZigZagEncode(int64_t(3333333333)), uint64_t(6666666666));
PW_TEST_EXPECT_EQ(ZigZagEncode(std::numeric_limits<int64_t>::min()),
std::numeric_limits<uint64_t>::max());
PW_TEST_EXPECT_EQ(ZigZagEncode(std::numeric_limits<int64_t>::max()),
std::numeric_limits<uint64_t>::max() - 1u);
});
PW_CONSTEXPR_TEST(Varint, ZigZagDecode_Int8, {
PW_TEST_EXPECT_EQ(ZigZagDecode(uint8_t(0)), int8_t(0));
PW_TEST_EXPECT_EQ(ZigZagDecode(uint8_t(1)), int8_t(-1));
PW_TEST_EXPECT_EQ(ZigZagDecode(uint8_t(2)), int8_t(1));
PW_TEST_EXPECT_EQ(ZigZagDecode(uint8_t(3)), int8_t(-2));
PW_TEST_EXPECT_EQ(ZigZagDecode(uint8_t(4)), int8_t(2));
PW_TEST_EXPECT_EQ(ZigZagDecode(uint8_t(65)), int8_t(-33));
PW_TEST_EXPECT_EQ(ZigZagDecode(uint8_t(66)), int8_t(33));
PW_TEST_EXPECT_EQ(ZigZagDecode(std::numeric_limits<uint8_t>::max()),
std::numeric_limits<int8_t>::min());
PW_TEST_EXPECT_EQ(ZigZagDecode(std::numeric_limits<uint8_t>::max() - 1u),
std::numeric_limits<int8_t>::max());
});
PW_CONSTEXPR_TEST(Varint, ZigZagDecode_Int16, {
PW_TEST_EXPECT_EQ(ZigZagDecode(uint16_t(0)), int16_t(0));
PW_TEST_EXPECT_EQ(ZigZagDecode(uint16_t(1)), int16_t(-1));
PW_TEST_EXPECT_EQ(ZigZagDecode(uint16_t(2)), int16_t(1));
PW_TEST_EXPECT_EQ(ZigZagDecode(uint16_t(3)), int16_t(-2));
PW_TEST_EXPECT_EQ(ZigZagDecode(uint16_t(4)), int16_t(2));
PW_TEST_EXPECT_EQ(ZigZagDecode(uint16_t(6665)), int16_t(-3333));
PW_TEST_EXPECT_EQ(ZigZagDecode(uint16_t(6666)), int16_t(3333));
PW_TEST_EXPECT_EQ(ZigZagDecode(std::numeric_limits<uint16_t>::max()),
std::numeric_limits<int16_t>::min());
PW_TEST_EXPECT_EQ(ZigZagDecode(std::numeric_limits<uint16_t>::max() - 1u),
std::numeric_limits<int16_t>::max());
});
PW_CONSTEXPR_TEST(Varint, ZigZagDecode_Int32, {
PW_TEST_EXPECT_EQ(ZigZagDecode(uint32_t(0)), int32_t(0));
PW_TEST_EXPECT_EQ(ZigZagDecode(uint32_t(1)), int32_t(-1));
PW_TEST_EXPECT_EQ(ZigZagDecode(uint32_t(2)), int32_t(1));
PW_TEST_EXPECT_EQ(ZigZagDecode(uint32_t(3)), int32_t(-2));
PW_TEST_EXPECT_EQ(ZigZagDecode(uint32_t(4)), int32_t(2));
PW_TEST_EXPECT_EQ(ZigZagDecode(uint32_t(255)), int32_t(-128));
PW_TEST_EXPECT_EQ(ZigZagDecode(uint32_t(256)), int32_t(128));
PW_TEST_EXPECT_EQ(ZigZagDecode(uint32_t(666665)), int32_t(-333333));
PW_TEST_EXPECT_EQ(ZigZagDecode(uint32_t(666666)), int32_t(333333));
PW_TEST_EXPECT_EQ(ZigZagDecode(std::numeric_limits<uint32_t>::max()),
std::numeric_limits<int32_t>::min());
PW_TEST_EXPECT_EQ(ZigZagDecode(std::numeric_limits<uint32_t>::max() - 1u),
std::numeric_limits<int32_t>::max());
});
PW_CONSTEXPR_TEST(Varint, ZigZagDecode_Int64, {
PW_TEST_EXPECT_EQ(ZigZagDecode(uint64_t(0)), int64_t(0));
PW_TEST_EXPECT_EQ(ZigZagDecode(uint64_t(1)), int64_t(-1));
PW_TEST_EXPECT_EQ(ZigZagDecode(uint64_t(2)), int64_t(1));
PW_TEST_EXPECT_EQ(ZigZagDecode(uint64_t(3)), int64_t(-2));
PW_TEST_EXPECT_EQ(ZigZagDecode(uint64_t(4)), int64_t(2));
PW_TEST_EXPECT_EQ(ZigZagDecode(uint64_t(6666666665)), int64_t(-3333333333));
PW_TEST_EXPECT_EQ(ZigZagDecode(uint64_t(6666666666)), int64_t(3333333333));
PW_TEST_EXPECT_EQ(ZigZagDecode(std::numeric_limits<uint64_t>::max()),
std::numeric_limits<int64_t>::min());
PW_TEST_EXPECT_EQ(ZigZagDecode(std::numeric_limits<uint64_t>::max() - 1llu),
std::numeric_limits<int64_t>::max());
});
PW_CONSTEXPR_TEST(Varint, ZigZagEncodeDecode, {
PW_TEST_EXPECT_EQ(ZigZagDecode(ZigZagEncode(0)), 0);
PW_TEST_EXPECT_EQ(ZigZagDecode(ZigZagEncode(1)), 1);
PW_TEST_EXPECT_EQ(ZigZagDecode(ZigZagEncode(-1)), -1);
PW_TEST_EXPECT_EQ(ZigZagDecode(ZigZagEncode(8675309)), 8675309);
PW_TEST_EXPECT_EQ(
ZigZagDecode(ZigZagEncode(std::numeric_limits<int8_t>::min())),
std::numeric_limits<int8_t>::min());
PW_TEST_EXPECT_EQ(
ZigZagDecode(ZigZagEncode(std::numeric_limits<int8_t>::max())),
std::numeric_limits<int8_t>::max());
PW_TEST_EXPECT_EQ(
ZigZagDecode(ZigZagEncode(std::numeric_limits<int16_t>::min())),
std::numeric_limits<int16_t>::min());
PW_TEST_EXPECT_EQ(
ZigZagDecode(ZigZagEncode(std::numeric_limits<int16_t>::max())),
std::numeric_limits<int16_t>::max());
PW_TEST_EXPECT_EQ(
ZigZagDecode(ZigZagEncode(std::numeric_limits<int32_t>::min())),
std::numeric_limits<int32_t>::min());
PW_TEST_EXPECT_EQ(
ZigZagDecode(ZigZagEncode(std::numeric_limits<int32_t>::max())),
std::numeric_limits<int32_t>::max());
PW_TEST_EXPECT_EQ(
ZigZagDecode(ZigZagEncode(std::numeric_limits<int64_t>::min())),
std::numeric_limits<int64_t>::min());
PW_TEST_EXPECT_EQ(
ZigZagDecode(ZigZagEncode(std::numeric_limits<int64_t>::max())),
std::numeric_limits<int64_t>::max());
});
TEST(Varint, EncodeWithOptions_SingleByte) {
std::byte buffer[kMaxVarint64SizeBytes] = {std::byte('\xff')};
ASSERT_EQ(Encode(0u, buffer, Format::kZeroTerminatedLeastSignificant), 1u);
EXPECT_EQ(buffer[0], std::byte{0x00});
ASSERT_EQ(Encode(1u, buffer, Format::kZeroTerminatedLeastSignificant), 1u);
EXPECT_EQ(buffer[0], std::byte{0x02});
ASSERT_EQ(Encode(0x7f, buffer, Format::kZeroTerminatedLeastSignificant), 1u);
EXPECT_EQ(buffer[0], std::byte{0xfe});
ASSERT_EQ(Encode(0u, buffer, Format::kOneTerminatedLeastSignificant), 1u);
EXPECT_EQ(buffer[0], std::byte{0x01});
ASSERT_EQ(Encode(2u, buffer, Format::kOneTerminatedLeastSignificant), 1u);
EXPECT_EQ(buffer[0], std::byte{0x05});
ASSERT_EQ(Encode(0x7f, buffer, Format::kOneTerminatedLeastSignificant), 1u);
EXPECT_EQ(buffer[0], std::byte{0xff});
ASSERT_EQ(Encode(0u, buffer, Format::kZeroTerminatedMostSignificant), 1u);
EXPECT_EQ(buffer[0], std::byte{0x00});
ASSERT_EQ(Encode(7u, buffer, Format::kZeroTerminatedMostSignificant), 1u);
EXPECT_EQ(buffer[0], std::byte{0x07});
ASSERT_EQ(Encode(0x7f, buffer, Format::kZeroTerminatedMostSignificant), 1u);
EXPECT_EQ(buffer[0], std::byte{0x7f});
ASSERT_EQ(Encode(0u, buffer, Format::kOneTerminatedMostSignificant), 1u);
EXPECT_EQ(buffer[0], std::byte{0x80});
ASSERT_EQ(Encode(15u, buffer, Format::kOneTerminatedMostSignificant), 1u);
EXPECT_EQ(buffer[0], std::byte{0x8f});
ASSERT_EQ(Encode(0x7f, buffer, Format::kOneTerminatedMostSignificant), 1u);
EXPECT_EQ(buffer[0], std::byte{0xff});
}
TEST(Varint, EncodeWithOptions_MultiByte) {
std::byte buffer[kMaxVarint64SizeBytes] = {std::byte('\xff')};
ASSERT_EQ(Encode(128u, buffer, Format::kZeroTerminatedLeastSignificant), 2u);
EXPECT_TRUE(Compare("\x01\x02", buffer));
ASSERT_EQ(Encode(0xffffffff, buffer, Format::kZeroTerminatedLeastSignificant),
5u);
EXPECT_TRUE(Compare("\xff\xff\xff\xff\x1e", buffer));
ASSERT_EQ(Encode(128u, buffer, Format::kOneTerminatedLeastSignificant), 2u);
EXPECT_TRUE(Compare("\x00\x03", buffer));
ASSERT_EQ(Encode(0xffffffff, buffer, Format::kOneTerminatedLeastSignificant),
5u);
EXPECT_TRUE(Compare("\xfe\xfe\xfe\xfe\x1f", buffer));
ASSERT_EQ(Encode(128u, buffer, Format::kZeroTerminatedMostSignificant), 2u);
EXPECT_TRUE(Compare("\x80\x01", buffer));
ASSERT_EQ(Encode(0xffffffff, buffer, Format::kZeroTerminatedMostSignificant),
5u);
EXPECT_TRUE(Compare("\xff\xff\xff\xff\x0f", buffer));
ASSERT_EQ(Encode(128u, buffer, Format::kOneTerminatedMostSignificant), 2u);
EXPECT_TRUE(Compare("\x00\x81", buffer));
ASSERT_EQ(Encode(0xffffffff, buffer, Format::kOneTerminatedMostSignificant),
5u);
EXPECT_TRUE(Compare("\x7f\x7f\x7f\x7f\x8f", buffer));
}
TEST(Varint, DecodeWithOptions_SingleByte) {
std::byte buffer[kMaxVarint64SizeBytes] = {};
uint64_t value;
EXPECT_EQ(Decode(Write("\x00", buffer),
&value,
Format::kZeroTerminatedLeastSignificant),
1u);
EXPECT_EQ(value, 0u);
EXPECT_EQ(Decode(Write("\x04", buffer),
&value,
Format::kZeroTerminatedLeastSignificant),
1u);
EXPECT_EQ(value, 2u);
EXPECT_EQ(Decode(Write("\xaa", buffer),
&value,
Format::kZeroTerminatedLeastSignificant),
1u);
EXPECT_EQ(value, 85u);
EXPECT_EQ(Decode(Write("\x01", buffer),
&value,
Format::kZeroTerminatedLeastSignificant),
0u);
EXPECT_EQ(Decode(Write("\x01", buffer),
&value,
Format::kOneTerminatedLeastSignificant),
1u);
EXPECT_EQ(value, 0u);
EXPECT_EQ(Decode(Write("\x13", buffer),
&value,
Format::kOneTerminatedLeastSignificant),
1u);
EXPECT_EQ(value, 9u);
EXPECT_EQ(Decode(Write("\x00", buffer),
&value,
Format::kOneTerminatedLeastSignificant),
0u);
EXPECT_EQ(Decode(Write("\x00", buffer),
&value,
Format::kZeroTerminatedMostSignificant),
1u);
EXPECT_EQ(value, 0u);
EXPECT_EQ(Decode(Write("\x04", buffer),
&value,
Format::kZeroTerminatedMostSignificant),
1u);
EXPECT_EQ(value, 4u);
EXPECT_EQ(Decode(Write("\xff", buffer),
&value,
Format::kZeroTerminatedMostSignificant),
0u);
EXPECT_EQ(
Decode(
Write("\x80", buffer), &value, Format::kOneTerminatedMostSignificant),
1u);
EXPECT_EQ(value, 0u);
EXPECT_EQ(
Decode(
Write("\x83", buffer), &value, Format::kOneTerminatedMostSignificant),
1u);
EXPECT_EQ(value, 3u);
EXPECT_EQ(
Decode(
Write("\xaa", buffer), &value, Format::kOneTerminatedMostSignificant),
1u);
EXPECT_EQ(value, 42u);
EXPECT_EQ(
Decode(
Write("\xff", buffer), &value, Format::kOneTerminatedMostSignificant),
1u);
EXPECT_EQ(value, 127u);
EXPECT_EQ(
Decode(
Write("\x00", buffer), &value, Format::kOneTerminatedMostSignificant),
0u);
}
TEST(Varint, DecodeWithOptions_MultiByte) {
std::byte buffer[kMaxVarint64SizeBytes] = {};
uint64_t value;
EXPECT_EQ(Decode(Write("\x01\x10", buffer),
&value,
Format::kZeroTerminatedLeastSignificant),
2u);
EXPECT_EQ(value, 1024u);
EXPECT_EQ(Decode(Write("\xff\xff\xff\xfe", buffer),
&value,
Format::kZeroTerminatedLeastSignificant),
4u);
EXPECT_EQ(value, 0x0fffffffu);
EXPECT_EQ(Decode(Write("\x01\x01\x01\x01\x00", buffer),
&value,
Format::kZeroTerminatedLeastSignificant),
5u);
EXPECT_EQ(value, 0u);
EXPECT_EQ(Decode(Write("\x82\x2d", buffer),
&value,
Format::kOneTerminatedLeastSignificant),
2u);
EXPECT_EQ(value, 2881u);
EXPECT_EQ(Decode(Write("\xfe\xfe\xfe\xff", buffer),
&value,
Format::kOneTerminatedLeastSignificant),
4u);
EXPECT_EQ(value, 0x0fffffffu);
EXPECT_EQ(Decode(Write("\x00\x00\x00\x00\x01", buffer),
&value,
Format::kOneTerminatedLeastSignificant),
5u);
EXPECT_EQ(value, 0u);
EXPECT_EQ(Decode(Write("\x83\x6a", buffer),
&value,
Format::kZeroTerminatedMostSignificant),
2u);
EXPECT_EQ(value, 0b1101010'0000011u);
EXPECT_EQ(Decode(Write("\xff\xff\xff\x7f", buffer),
&value,
Format::kZeroTerminatedMostSignificant),
4u);
EXPECT_EQ(value, 0x0fffffffu);
EXPECT_EQ(Decode(Write("\x80\x80\x80\x80\x00", buffer),
&value,
Format::kZeroTerminatedMostSignificant),
5u);
EXPECT_EQ(value, 0u);
EXPECT_EQ(Decode(Write("\x6a\x83", buffer),
&value,
Format::kOneTerminatedMostSignificant),
2u);
EXPECT_EQ(value, 0b0000011'1101010u);
EXPECT_EQ(Decode(Write("\x7f\x7f\x7f\xff", buffer),
&value,
Format::kOneTerminatedMostSignificant),
4u);
EXPECT_EQ(value, 0x0fffffffu);
EXPECT_EQ(Decode(Write("\x00\x00\x00\x00\x80", buffer),
&value,
Format::kOneTerminatedMostSignificant),
5u);
EXPECT_EQ(value, 0u);
}
#define ENCODED_SIZE_TEST(function) \
TEST(Varint, function) { \
EXPECT_EQ(function(uint64_t(0u)), 1u); \
EXPECT_EQ(function(uint64_t(1u)), 1u); \
EXPECT_EQ(function(uint64_t(127u)), 1u); \
EXPECT_EQ(function(uint64_t(128u)), 2u); \
EXPECT_EQ(function(uint64_t(16383u)), 2u); \
EXPECT_EQ(function(uint64_t(16384u)), 3u); \
EXPECT_EQ(function(uint64_t(2097151u)), 3u); \
EXPECT_EQ(function(uint64_t(2097152u)), 4u); \
EXPECT_EQ(function(uint64_t(268435455u)), 4u); \
EXPECT_EQ(function(uint64_t(268435456u)), 5u); \
EXPECT_EQ(function(uint64_t(34359738367u)), 5u); \
EXPECT_EQ(function(uint64_t(34359738368u)), 6u); \
EXPECT_EQ(function(uint64_t(4398046511103u)), 6u); \
EXPECT_EQ(function(uint64_t(4398046511104u)), 7u); \
EXPECT_EQ(function(uint64_t(562949953421311u)), 7u); \
EXPECT_EQ(function(uint64_t(562949953421312u)), 8u); \
EXPECT_EQ(function(uint64_t(72057594037927935u)), 8u); \
EXPECT_EQ(function(uint64_t(72057594037927936u)), 9u); \
EXPECT_EQ(function(uint64_t(9223372036854775807u)), 9u); \
EXPECT_EQ(function(uint64_t(9223372036854775808u)), 10u); \
EXPECT_EQ(function(std::numeric_limits<uint64_t>::max()), 10u); \
EXPECT_EQ( \
static_cast<uint64_t>(function(std::numeric_limits<int64_t>::max())), \
9u); \
EXPECT_EQ(function(uint64_t(-1)), 10u); \
EXPECT_EQ( \
function(static_cast<uint64_t>(std::numeric_limits<int64_t>::min())), \
10u); \
} \
static_assert(true)
ENCODED_SIZE_TEST(EncodedSize);
ENCODED_SIZE_TEST(pw_varint_EncodedSizeBytes);
ENCODED_SIZE_TEST(PW_VARINT_ENCODED_SIZE_BYTES);
constexpr uint64_t CalculateMaxValueInBytes(size_t bytes) {
uint64_t value = 0;
for (size_t i = 0; i < bytes; ++i) {
value |= uint64_t(0x7f) << (7 * i);
}
return value;
}
PW_CONSTEXPR_TEST(Varint, MaxValueInBytes, {
static_assert(MaxValueInBytes(0) == 0);
static_assert(MaxValueInBytes(1) == 0x7f);
static_assert(MaxValueInBytes(2) == 0x3fff);
static_assert(MaxValueInBytes(3) == 0x1fffff);
static_assert(MaxValueInBytes(4) == 0x0fffffff);
static_assert(MaxValueInBytes(5) == CalculateMaxValueInBytes(5));
static_assert(MaxValueInBytes(6) == CalculateMaxValueInBytes(6));
static_assert(MaxValueInBytes(7) == CalculateMaxValueInBytes(7));
static_assert(MaxValueInBytes(8) == CalculateMaxValueInBytes(8));
static_assert(MaxValueInBytes(9) == CalculateMaxValueInBytes(9));
static_assert(MaxValueInBytes(10) == std::numeric_limits<uint64_t>::max());
static_assert(MaxValueInBytes(11) == std::numeric_limits<uint64_t>::max());
static_assert(MaxValueInBytes(100) == std::numeric_limits<uint64_t>::max());
});
} // namespace
} // namespace pw::varint