/Users/deen/code/yugabyte-db/src/yb/util/varint-test.cc
Line | Count | Source |
1 | | // Copyright (c) YugaByte, Inc. |
2 | | // |
3 | | // Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except |
4 | | // in compliance with the License. You may obtain a copy of the License at |
5 | | // |
6 | | // http://www.apache.org/licenses/LICENSE-2.0 |
7 | | // |
8 | | // Unless required by applicable law or agreed to in writing, software distributed under the License |
9 | | // is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express |
10 | | // or implied. See the License for the specific language governing permissions and limitations |
11 | | // under the License. |
12 | | // |
13 | | |
14 | | #include "yb/util/result.h" |
15 | | #include "yb/util/test_macros.h" |
16 | | #include "yb/util/test_util.h" |
17 | | #include "yb/util/varint.h" |
18 | | |
19 | | namespace yb { |
20 | | namespace util { |
21 | | |
22 | | const std::string kTooSmall = "-9223372036854775809"; |
23 | | const std::string kTooBig = "9223372036854775808"; |
24 | | |
25 | | class VarIntTest : public YBTest { |
26 | | protected: |
27 | 6 | void SetUp() override { |
28 | 6 | YBTest::SetUp(); |
29 | | |
30 | | // Should be ordered by value, since it is used in comparison tests. |
31 | 6 | std::vector<std::string> inputs = { |
32 | 6 | "-37618632178637216379216387", |
33 | 6 | kTooSmall, |
34 | 6 | std::to_string(std::numeric_limits<int64_t>::min()), |
35 | 6 | std::to_string(std::numeric_limits<int>::min() - 1LL), |
36 | 6 | std::to_string(std::numeric_limits<int>::min()), |
37 | 6 | "-129", |
38 | 6 | "-128", |
39 | 6 | "-127", |
40 | 6 | "-23", |
41 | 6 | "0", |
42 | 6 | "38", |
43 | 6 | std::to_string(std::numeric_limits<int>::max()), |
44 | 6 | std::to_string(std::numeric_limits<int>::max() + 1LL), |
45 | 6 | std::to_string(std::numeric_limits<int64_t>::max()), |
46 | 6 | kTooBig, |
47 | 6 | "8429024091289482183283928321", |
48 | 6 | }; |
49 | | |
50 | 6 | values_.reserve(inputs.size()); |
51 | | |
52 | 96 | for (const auto& input : inputs) { |
53 | 96 | values_.push_back(ASSERT_RESULT(VarInt::CreateFromString(input))); |
54 | 96 | } |
55 | 6 | } |
56 | | |
57 | 32 | std::string ToDebugString(const std::string& input) { |
58 | 32 | size_t num_bytes = input.size(); |
59 | 32 | string output = "[ "; |
60 | 210 | for (size_t i = 0; i < num_bytes; i++) { |
61 | 1.60k | for (size_t j = 0; j < 8; j++) { |
62 | 1.42k | output += '0' + static_cast<char>(input[i] >> (7 - j) & 1); |
63 | 1.42k | } |
64 | 178 | output += ' '; |
65 | 178 | } |
66 | 32 | output += ']'; |
67 | 32 | return output; |
68 | 32 | } |
69 | | |
70 | 4 | void CheckInt(int64_t val) { |
71 | 4 | VarInt varint(val); |
72 | 4 | auto converted = ASSERT_RESULT(varint.ToInt64()); |
73 | 4 | ASSERT_EQ(val, converted); |
74 | 4 | ASSERT_EQ(std::to_string(val), varint.ToString()); |
75 | 4 | } |
76 | | |
77 | | std::vector<VarInt> values_; |
78 | | }; |
79 | | |
80 | 1 | TEST_F(VarIntTest, TestTypeConversions) { |
81 | 1 | int64_t max = std::numeric_limits<int64_t>::max(); |
82 | 1 | int64_t min = std::numeric_limits<int64_t>::min(); |
83 | 1 | int64_t zero = 0; |
84 | 1 | int64_t negative = -380; |
85 | | |
86 | 1 | CheckInt(max); |
87 | 1 | CheckInt(min); |
88 | 1 | CheckInt(zero); |
89 | 1 | CheckInt(negative); |
90 | | |
91 | | // One more and less than largest value should overflow. |
92 | 1 | auto too_big = ASSERT_RESULT(VarInt::CreateFromString("9223372036854775808")); |
93 | 1 | ASSERT_FALSE(too_big.ToInt64().ok()); |
94 | 1 | auto very_big = ASSERT_RESULT(VarInt::CreateFromString("99999999999999999999999")); |
95 | 1 | ASSERT_FALSE(very_big.ToInt64().ok()); |
96 | 1 | auto too_small = ASSERT_RESULT(VarInt::CreateFromString("-9223372036854775809")); |
97 | 1 | ASSERT_FALSE(too_small.ToInt64().ok()); |
98 | 1 | auto very_small = ASSERT_RESULT(VarInt::CreateFromString("-99999999999999999999999")); |
99 | 1 | ASSERT_FALSE(very_small.ToInt64().ok()); |
100 | 1 | } |
101 | | |
102 | 1 | TEST_F(VarIntTest, TestComparison) { |
103 | 1 | std::vector<std::string> encoded; |
104 | 1 | encoded.reserve(values_.size()); |
105 | | |
106 | 16 | for (const auto& value : values_) { |
107 | 16 | encoded.push_back(value.EncodeToComparable()); |
108 | 16 | } |
109 | | |
110 | 17 | for (size_t i = 0; i != values_.size(); ++i) { |
111 | 272 | for (size_t j = 0; j != values_.size(); ++j) { |
112 | 256 | ASSERT_EQ(i < j, values_[i] < values_[j]); |
113 | 256 | ASSERT_EQ(i <= j, values_[i] <= values_[j]); |
114 | 256 | ASSERT_EQ(i == j, values_[i] == values_[j]); |
115 | 256 | ASSERT_EQ(i >= j, values_[i] >= values_[j]); |
116 | 256 | ASSERT_EQ(i > j, values_[i] > values_[j]); |
117 | | |
118 | 256 | ASSERT_EQ(i < j, encoded[i] < encoded[j]); |
119 | 256 | ASSERT_EQ(i <= j, encoded[i] <= encoded[j]); |
120 | 256 | ASSERT_EQ(i == j, encoded[i] == encoded[j]); |
121 | 256 | ASSERT_EQ(i >= j, encoded[i] >= encoded[j]); |
122 | 256 | ASSERT_EQ(i > j, encoded[i] > encoded[j]); |
123 | 256 | } |
124 | 16 | } |
125 | 1 | } |
126 | | |
127 | 1 | TEST_F(VarIntTest, TestArithmetic) { |
128 | 1 | ASSERT_EQ(VarInt(74), VarInt(28) + VarInt(46)); |
129 | 1 | ASSERT_EQ(VarInt(-113), VarInt(28) - VarInt(141)); |
130 | 1 | ASSERT_EQ(VarInt(0), VarInt(23) + VarInt(3) + VarInt(-26)); |
131 | 1 | ASSERT_EQ(VarInt(1), VarInt(23) + VarInt(3) + VarInt(-25)); |
132 | 1 | ASSERT_EQ(VarInt(-1), VarInt(23) + VarInt(3) + VarInt(-27)); |
133 | 1 | } |
134 | | |
135 | 1 | TEST_F(VarIntTest, ComparableEncodingWithReserve) { |
136 | 1 | constexpr int kNumReservedBits = 2; |
137 | 65.5k | for (int i = 0; i != 0xffff; ++i) { |
138 | 65.5k | SCOPED_TRACE(Format("i: $0", i)); |
139 | 65.5k | VarInt v(i); |
140 | 65.5k | auto encoded = v.EncodeToComparable(kNumReservedBits); |
141 | 65.5k | VarInt decoded; |
142 | 65.5k | size_t decoded_size = 0; |
143 | 65.5k | ASSERT_OK(decoded.DecodeFromComparable(encoded, &decoded_size, kNumReservedBits)); |
144 | 65.5k | ASSERT_EQ(v, decoded); |
145 | 65.5k | ASSERT_EQ(encoded.size(), decoded_size); |
146 | 65.5k | } |
147 | 1 | } |
148 | | |
149 | 1 | TEST_F(VarIntTest, TestComparableEncoding) { |
150 | 1 | std::vector<std::string> expected = { |
151 | 1 | "[ 00000000 00000111 11100000 11100001 11110001 11011101 00000001 00110000 " |
152 | 1 | "11011100 11111011 11101101 01011101 11111100 ]", // -37618632178637216379216387 |
153 | 1 | "[ 00000000 00111111 01111111 11111111 11111111 11111111 11111111 11111111 11111111 " |
154 | 1 | "11111110 ]", // kTooSmall, |
155 | 1 | "[ 00000000 00111111 01111111 11111111 11111111 11111111 11111111 11111111 11111111 " |
156 | 1 | "11111111 ]", // std::to_string(std::numeric_limits<int64_t>::min()), |
157 | 1 | "[ 00000111 01111111 11111111 11111111 11111110 ]", |
158 | | // std::to_string(std::numeric_limits<int>::min() - 1LL), |
159 | 1 | "[ 00000111 01111111 11111111 11111111 11111111 ]", |
160 | | // std::to_string(std::numeric_limits<int>::min()), |
161 | 1 | "[ 00111111 01111110 ]", // -129 |
162 | 1 | "[ 00111111 01111111 ]", // -128 |
163 | 1 | "[ 00111111 10000000 ]", // -127 |
164 | 1 | "[ 01101000 ]", // -23 |
165 | 1 | "[ 10000000 ]", // 0 |
166 | 1 | "[ 10100110 ]", // 38 |
167 | 1 | "[ 11111000 01111111 11111111 11111111 11111111 ]", |
168 | | // std::to_string(std::numeric_limits<int>::max()), |
169 | 1 | "[ 11111000 10000000 00000000 00000000 00000000 ]", |
170 | | // std::to_string(std::numeric_limits<int>::max() + 1LL), |
171 | 1 | "[ 11111111 11000000 01111111 11111111 11111111 11111111 11111111 11111111 11111111 " |
172 | 1 | "11111111 ]", // std::to_string(std::numeric_limits<int64_t>::max()), |
173 | 1 | "[ 11111111 11000000 10000000 00000000 00000000 00000000 00000000 00000000 00000000 " |
174 | 1 | "00000000 ]", // kTooBig, |
175 | 1 | "[ 11111111 11111100 00011011 00111100 01010011 01000111 10010101 11011111 " |
176 | 1 | "00011011 00001010 01111011 11111101 01101101 00000001 ]" // 8429024091289482183283928321 |
177 | 1 | }; |
178 | 1 | ASSERT_EQ(expected.size(), values_.size()); |
179 | 17 | for (size_t i = 0; i != values_.size(); ++i) { |
180 | 16 | SCOPED_TRACE(Format("Index: $0, value: $1", i, values_[i])); |
181 | 16 | auto encoded = values_[i].EncodeToComparable(); |
182 | 16 | EXPECT_EQ(expected[i], ToDebugString(encoded)); |
183 | 16 | VarInt decoded; |
184 | 16 | size_t size; |
185 | 16 | ASSERT_OK(decoded.DecodeFromComparable(encoded, &size)); |
186 | 16 | EXPECT_EQ(encoded.size(), size); |
187 | 16 | EXPECT_EQ(values_[i], decoded); |
188 | 16 | } |
189 | 1 | } |
190 | | |
191 | 1 | TEST_F(VarIntTest, TestTwosComplementEncoding) { |
192 | 1 | std::vector<std::string> expected = { |
193 | 1 | "[ 11100000 11100001 11110001 11011101 00000001 00110000 11011100 11111011 " |
194 | 1 | "11101101 01011101 11111101 ]", // -37618632178637216379216387 |
195 | 1 | "[ 11111111 01111111 11111111 11111111 11111111 11111111 11111111 11111111 11111111 ]", |
196 | | // kTooSmall |
197 | 1 | "[ 10000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 ]", |
198 | | // std::to_string(std::numeric_limits<int64_t>::min()) |
199 | 1 | "[ 11111111 01111111 11111111 11111111 11111111 ]", |
200 | | // std::to_string(std::numeric_limits<int>::min() - 1LL) |
201 | 1 | "[ 10000000 00000000 00000000 00000000 ]", // std::to_string(std::numeric_limits<int>::min()) |
202 | 1 | "[ 11111111 01111111 ]", // -129 |
203 | 1 | "[ 10000000 ]", // -128 |
204 | 1 | "[ 10000001 ]", // -127 |
205 | 1 | "[ 11101001 ]", // -23 |
206 | 1 | "[ 00000000 ]", // 0 |
207 | 1 | "[ 00100110 ]", // 38 |
208 | 1 | "[ 01111111 11111111 11111111 11111111 ]", // std::to_string(std::numeric_limits<int>::max()) |
209 | 1 | "[ 00000000 10000000 00000000 00000000 00000000 ]", |
210 | | // std::to_string(std::numeric_limits<int>::max() + 1LL) |
211 | 1 | "[ 01111111 11111111 11111111 11111111 11111111 11111111 11111111 11111111 ]", |
212 | | // std::to_string(std::numeric_limits<int64_t>::max()) |
213 | 1 | "[ 00000000 10000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 ]", |
214 | | // kTooBig |
215 | 1 | "[ 00011011 00111100 01010011 01000111 10010101 11011111 00011011 00001010 " |
216 | 1 | "01111011 11111101 01101101 00000001 ]" // 8429024091289482183283928321 |
217 | 1 | }; |
218 | 1 | ASSERT_EQ(expected.size(), values_.size()); |
219 | 17 | for (size_t i = 0; i != values_.size(); ++i) { |
220 | 16 | SCOPED_TRACE(Format("Index: $0, value: $1", i, values_[i])); |
221 | 16 | auto encoded = values_[i].EncodeToTwosComplement(); |
222 | 16 | EXPECT_EQ(expected[i], ToDebugString(encoded)); |
223 | 16 | VarInt decoded; |
224 | 16 | ASSERT_OK(decoded.DecodeFromTwosComplement(encoded)); |
225 | 16 | EXPECT_EQ(values_[i], decoded); |
226 | 16 | } |
227 | 1 | } |
228 | | |
229 | | } // namespace util |
230 | | } // namespace yb |