|
1 | 1 |
|
2 | 2 | #include <test.hpp> |
3 | 3 |
|
| 4 | +namespace { |
| 5 | + |
| 6 | +struct checked_varint_decoder { |
| 7 | + static uint64_t decode(const char** data, const char* end) { |
| 8 | + return protozero::decode_varint(data, end); |
| 9 | + } |
| 10 | + |
| 11 | + static void skip(const char** data, const char* end) { |
| 12 | + protozero::skip_varint(data, end); |
| 13 | + } |
| 14 | +}; |
| 15 | + |
| 16 | +struct unchecked_varint_decoder { |
| 17 | + static uint64_t decode(const char** data, const char* end) { |
| 18 | + (void)end; |
| 19 | + return protozero::decode_varint_unchecked(data); |
| 20 | + } |
| 21 | + |
| 22 | + static void skip(const char** data, const char* end) { |
| 23 | + (void)end; |
| 24 | + protozero::skip_varint_unchecked(data); |
| 25 | + } |
| 26 | +}; |
| 27 | + |
| 28 | +} // namespace |
| 29 | + |
4 | 30 | TEST_CASE("max varint length") { |
5 | 31 | REQUIRE(protozero::max_varint_length == 10); |
6 | 32 | } |
@@ -248,6 +274,124 @@ TEST_CASE("call decode_varint_unchecked with every possible value of terminal va |
248 | 274 | } |
249 | 275 | } |
250 | 276 |
|
| 277 | +template <typename Decoder> |
| 278 | +void test_decode_various_lengths() { |
| 279 | + const std::vector<uint64_t> values{ |
| 280 | + 0, |
| 281 | + 127, |
| 282 | + 128, |
| 283 | + 16383, |
| 284 | + 16384, |
| 285 | + 2097151, |
| 286 | + 2097152, |
| 287 | + 0xffffffffULL, |
| 288 | + 0xffffffffffffffffULL, |
| 289 | + 1ULL << 40U, |
| 290 | + }; |
| 291 | + |
| 292 | + for (const auto value : values) { |
| 293 | + std::string buffer; |
| 294 | + protozero::add_varint_to_buffer(&buffer, value); |
| 295 | + const char* b = buffer.data(); |
| 296 | + const char* const end = buffer.data() + buffer.size(); |
| 297 | + REQUIRE(Decoder::decode(&b, end) == value); |
| 298 | + REQUIRE(b == end); |
| 299 | + } |
| 300 | +} |
| 301 | + |
| 302 | +TEST_CASE("decode_varint with varints of various lengths") { |
| 303 | + SECTION("checked") { |
| 304 | + test_decode_various_lengths<checked_varint_decoder>(); |
| 305 | + } |
| 306 | + |
| 307 | + SECTION("unchecked") { |
| 308 | + test_decode_various_lengths<unchecked_varint_decoder>(); |
| 309 | + } |
| 310 | +} |
| 311 | + |
| 312 | +template <typename Decoder> |
| 313 | +void test_skip_various_lengths() { |
| 314 | + const std::vector<uint64_t> values{ |
| 315 | + 0, |
| 316 | + 127, |
| 317 | + 128, |
| 318 | + 16383, |
| 319 | + 16384, |
| 320 | + 2097151, |
| 321 | + 2097152, |
| 322 | + 0xffffffffULL, |
| 323 | + 0xffffffffffffffffULL, |
| 324 | + 1ULL << 40U, |
| 325 | + }; |
| 326 | + |
| 327 | + for (const auto value : values) { |
| 328 | + std::string buffer; |
| 329 | + protozero::add_varint_to_buffer(&buffer, value); |
| 330 | + const char* b = buffer.data(); |
| 331 | + const char* const end = buffer.data() + buffer.size(); |
| 332 | + Decoder::skip(&b, end); |
| 333 | + REQUIRE(b == end); |
| 334 | + } |
| 335 | +} |
| 336 | + |
| 337 | +TEST_CASE("skip_varint with varints of various lengths") { |
| 338 | + SECTION("checked") { |
| 339 | + test_skip_various_lengths<checked_varint_decoder>(); |
| 340 | + } |
| 341 | + |
| 342 | + SECTION("unchecked") { |
| 343 | + test_skip_various_lengths<unchecked_varint_decoder>(); |
| 344 | + } |
| 345 | +} |
| 346 | + |
| 347 | +template <typename Decoder> |
| 348 | +void test_decode_multiple_varints_in_sequence() { |
| 349 | + std::string buffer; |
| 350 | + protozero::add_varint_to_buffer(&buffer, 5); |
| 351 | + protozero::add_varint_to_buffer(&buffer, 1); |
| 352 | + protozero::add_varint_to_buffer(&buffer, 300); |
| 353 | + |
| 354 | + const char* b = buffer.data(); |
| 355 | + const char* const end = buffer.data() + buffer.size(); |
| 356 | + REQUIRE(Decoder::decode(&b, end) == 5); |
| 357 | + REQUIRE(Decoder::decode(&b, end) == 1); |
| 358 | + REQUIRE(Decoder::decode(&b, end) == 300); |
| 359 | + REQUIRE(b == end); |
| 360 | +} |
| 361 | + |
| 362 | +TEST_CASE("decode multiple varints in sequence") { |
| 363 | + SECTION("checked") { |
| 364 | + test_decode_multiple_varints_in_sequence<checked_varint_decoder>(); |
| 365 | + } |
| 366 | + |
| 367 | + SECTION("unchecked") { |
| 368 | + test_decode_multiple_varints_in_sequence<unchecked_varint_decoder>(); |
| 369 | + } |
| 370 | +} |
| 371 | + |
| 372 | +template <typename Decoder> |
| 373 | +void test_overlong_varint_throws() { |
| 374 | + std::string buffer(10, static_cast<char>(0xffU)); |
| 375 | + const char* b = buffer.data(); |
| 376 | + const char* const end = buffer.data() + buffer.size(); |
| 377 | + REQUIRE_THROWS_AS(Decoder::decode(&b, end), protozero::varint_too_long_exception); |
| 378 | + REQUIRE(b == buffer.data()); |
| 379 | + |
| 380 | + b = buffer.data(); |
| 381 | + REQUIRE_THROWS_AS([&]() { Decoder::skip(&b, end); }(), protozero::varint_too_long_exception); |
| 382 | + REQUIRE(b == buffer.data()); |
| 383 | +} |
| 384 | + |
| 385 | +TEST_CASE("overlong varint throws varint_too_long_exception") { |
| 386 | + SECTION("checked") { |
| 387 | + test_overlong_varint_throws<checked_varint_decoder>(); |
| 388 | + } |
| 389 | + |
| 390 | + SECTION("unchecked") { |
| 391 | + test_overlong_varint_throws<unchecked_varint_decoder>(); |
| 392 | + } |
| 393 | +} |
| 394 | + |
251 | 395 | TEST_CASE("check lengths of varint") { |
252 | 396 | REQUIRE(protozero::length_of_varint(0) == 1); |
253 | 397 | REQUIRE(protozero::length_of_varint(127) == 1); |
|
0 commit comments