#include <library/cpp/testing/gtest/gtest.h>
#include <library/cpp/yt/coding/varint.h>
#include <util/random/random.h>
#include <util/string/escape.h>
#include <tuple>
namespace NYT {
namespace {
using ::testing::Values;
////////////////////////////////////////////////////////////////////////////////
class TWriteVarIntTest: public ::testing::TestWithParam<std::tuple<ui64, TString> >
{ };
TEST_P(TWriteVarIntTest, Serialization)
{
ui64 value = std::get<0>(GetParam());
TString rightAnswer = std::get<1>(GetParam());
TStringStream outputStream;
WriteVarUint64(&outputStream, value);
EXPECT_EQ(rightAnswer, outputStream.Str());
}
////////////////////////////////////////////////////////////////////////////////
class TReadVarIntTest: public ::testing::TestWithParam<std::tuple<ui64, TString> >
{ };
TEST_P(TReadVarIntTest, Serialization)
{
ui64 rightAnswer = std::get<0>(GetParam());
TString input = std::get<1>(GetParam());
TStringInput inputStream(input);
ui64 value;
ReadVarUint64(&inputStream, &value);
EXPECT_EQ(rightAnswer, value);
}
TEST(TReadVarIntTest, Overflow)
{
TString input("\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80\x01", 11);
TStringInput inputStream(input);
ui64 value;
EXPECT_ANY_THROW(ReadVarUint64(&inputStream, &value));
}
////////////////////////////////////////////////////////////////////////////////
auto ValuesForVarIntTests = Values(
// Simple cases.
std::make_tuple(0x0ull, TString("\x00", 1)),
std::make_tuple(0x1ull, TString("\x01", 1)),
std::make_tuple(0x2ull, TString("\x02", 1)),
std::make_tuple(0x3ull, TString("\x03", 1)),
std::make_tuple(0x4ull, TString("\x04", 1)),
// The following "magic numbers" are critical points for varint encoding.
std::make_tuple((1ull << 7) - 1, TString("\x7f", 1)),
std::make_tuple((1ull << 7), TString("\x80\x01", 2)),
std::make_tuple((1ull << 14) - 1, TString("\xff\x7f", 2)),
std::make_tuple((1ull << 14), TString("\x80\x80\x01", 3)),
std::make_tuple((1ull << 21) - 1, TString("\xff\xff\x7f", 3)),
std::make_tuple((1ull << 21), TString("\x80\x80\x80\x01", 4)),
std::make_tuple((1ull << 28) - 1, TString("\xff\xff\xff\x7f", 4)),
std::make_tuple((1ull << 28), TString("\x80\x80\x80\x80\x01", 5)),
std::make_tuple((1ull << 35) - 1, TString("\xff\xff\xff\xff\x7f", 5)),
std::make_tuple((1ull << 35), TString("\x80\x80\x80\x80\x80\x01", 6)),
std::make_tuple((1ull << 42) - 1, TString("\xff\xff\xff\xff\xff\x7f", 6)),
std::make_tuple((1ull << 42), TString("\x80\x80\x80\x80\x80\x80\x01", 7)),
std::make_tuple((1ull << 49) - 1, TString("\xff\xff\xff\xff\xff\xff\x7f", 7)),
std::make_tuple((1ull << 49), TString("\x80\x80\x80\x80\x80\x80\x80\x01", 8)),
std::make_tuple((1ull << 56) - 1, TString("\xff\xff\xff\xff\xff\xff\xff\x7f", 8)),
std::make_tuple((1ull << 56), TString("\x80\x80\x80\x80\x80\x80\x80\x80\x01", 9)),
std::make_tuple((1ull << 63) - 1, TString("\xff\xff\xff\xff\xff\xff\xff\xff\x7f", 9)),
std::make_tuple((1ull << 63), TString("\x80\x80\x80\x80\x80\x80\x80\x80\x80\x01", 10)),
// Boundary case.
std::make_tuple(static_cast<ui64>(-1), TString("\xff\xff\xff\xff\xff\xff\xff\xff\xff\x01", 10))
);
INSTANTIATE_TEST_SUITE_P(ValueParametrized, TWriteVarIntTest,
ValuesForVarIntTests);
INSTANTIATE_TEST_SUITE_P(ValueParametrized, TReadVarIntTest,
ValuesForVarIntTests);
////////////////////////////////////////////////////////////////////////////////
TEST(TVarInt32Test, RandomValues)
{
srand(100500); // Set seed
const int numberOfValues = 10000;
TStringStream stream;
for (int i = 0; i < numberOfValues; ++i) {
i32 expected = static_cast<i32>(RandomNumber<ui32>());
WriteVarInt32(&stream, expected);
i32 actual;
ReadVarInt32(&stream, &actual);
EXPECT_EQ(expected, actual)
<< "Encoded Variant: " << EscapeC(stream.Str());
}
}
////////////////////////////////////////////////////////////////////////////////
TEST(TVarInt64Test, RandomValues)
{
srand(100500); // Set seed
const int numberOfValues = 10000;
TStringStream stream;
for (int i = 0; i < numberOfValues; ++i) {
i64 expected = static_cast<i64>(RandomNumber<ui64>());
WriteVarInt64(&stream, expected);
i64 actual;
ReadVarInt64(&stream, &actual);
EXPECT_EQ(expected, actual)
<< "Encoded Variant: " << EscapeC(stream.Str());
}
}
////////////////////////////////////////////////////////////////////////////////
} // namespace
} // namespace NYT