From 5fb172a50fc343ef642745b0ecb4b6a44d274b15 Mon Sep 17 00:00:00 2001 From: Dirk Engling Date: Sat, 24 Oct 2026 05:26:06 +0200 Subject: Add tests for the new ranged unsigned int scanner in ot_scan --- tests/runner.c | 1 + tests/t_scan.c | 162 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ tests/test.h | 1 + 3 files changed, 164 insertions(+) create mode 100644 tests/t_scan.c (limited to 'tests') diff --git a/tests/runner.c b/tests/runner.c index bf4fbde..370b92b 100644 --- a/tests/runner.c +++ b/tests/runner.c @@ -19,6 +19,7 @@ static const struct module modules[] = {{"scan_urlencoded_query", test_scan_urle {"ot_vector", test_vector}, {"ot_random", test_random}, {"ot_hex", test_hex}, + {"ot_scan", test_scan}, {"ot_accesslist", test_accesslist}, {NULL, NULL}}; diff --git a/tests/t_scan.c b/tests/t_scan.c new file mode 100644 index 0000000..89f1590 --- /dev/null +++ b/tests/t_scan.c @@ -0,0 +1,162 @@ +/* This software was written by Dirk Engling + It is considered beerware. Prost. Skol. Cheers or whatever. + + $id$ */ + +/* System */ +#include +#include + +/* Opentracker */ +#include "ot_scan.h" +#include "test.h" + +static void case_plain_numbers(void) { + uint64_t value; + + test_case("a decimal number is read and its length reported"); + CHECK_INT(scan_udec("0", &value, 65535), 1); + CHECK_INT(value, 0); + CHECK_INT(scan_udec("7", &value, 65535), 1); + CHECK_INT(value, 7); + CHECK_INT(scan_udec("6969", &value, 65535), 4); + CHECK_INT(value, 6969); + CHECK_INT(scan_udec("65535", &value, 65535), 5); + CHECK_INT(value, 65535); +} + +static void case_stops_at_non_digit(void) { + uint64_t value; + + test_case("scanning stops at the first character that is not a digit"); + CHECK_INT(scan_udec("6969:rest", &value, 65535), 4); + CHECK_INT(value, 6969); + CHECK_INT(scan_udec("128/8", &value, 65535), 3); + CHECK_INT(value, 128); + CHECK_INT(scan_udec("42\n", &value, 65535), 2); + CHECK_INT(value, 42); +} + +static void case_rejects_whitespace(void) { + uint64_t value = 0xdead; + + test_case("leading whitespace is not skipped"); + CHECK_INT(scan_udec(" 1", &value, 65535), 0); + CHECK_INT(scan_udec("\t1", &value, 65535), 0); + CHECK_INT(scan_udec("\n1", &value, 65535), 0); + CHECK_INT(value, 0xdead); +} + +static void case_rejects_sign(void) { + uint64_t value = 0xdead; + + test_case("a sign is not accepted"); + CHECK_INT(scan_udec("+1", &value, 65535), 0); + CHECK_INT(scan_udec("-1", &value, 65535), 0); + CHECK_INT(scan_udec("-0", &value, 65535), 0); + CHECK_INT(value, 0xdead); +} + +static void case_rejects_empty_and_junk(void) { + uint64_t value = 0xdead; + + test_case("a string with no leading digit yields nothing"); + CHECK_INT(scan_udec("", &value, 65535), 0); + CHECK_INT(scan_udec("x", &value, 65535), 0); + CHECK_INT(scan_udec(":80", &value, 65535), 0); + CHECK_INT(value, 0xdead); +} + +static void case_no_alternative_bases(void) { + uint64_t value; + + test_case("hexadecimal and octal notations are read as plain decimal"); + CHECK_INT(scan_udec("0x10", &value, 65535), 1); + CHECK_INT(value, 0); + CHECK_INT(scan_udec("010", &value, 65535), 3); + CHECK_INT(value, 10); +} + +static void case_refuses_out_of_range(void) { + uint64_t value = 0xdead; + + test_case("a value above max is refused, not truncated"); + CHECK_INT(scan_udec("65536", &value, 65535), 0); + CHECK_INT(scan_udec("99999", &value, 65535), 0); + CHECK_INT(scan_udec("129", &value, 128), 0); + CHECK_INT(value, 0xdead); + + test_case("the boundary itself is accepted"); + CHECK_INT(scan_udec("128", &value, 128), 3); + CHECK_INT(value, 128); +} + +static void case_sixty_four_bit_range(void) { + uint64_t value; + + test_case("the full unsigned 64 bit range is available"); + CHECK_INT(scan_udec("18446744073709551615", &value, UINT64_MAX), 20); + CHECK(value == UINT64_MAX); + + test_case("a number too large for 64 bits is refused"); + CHECK_INT(scan_udec("18446744073709551616", &value, UINT64_MAX), 0); + CHECK_INT(scan_udec("99999999999999999999999999", &value, UINT64_MAX), 0); +} + +static void case_leading_zeros_allowed(void) { + uint64_t value; + + test_case("leading zeros are accepted outside bencode"); + CHECK_INT(scan_udec("007", &value, 65535), 3); + CHECK_INT(value, 7); + CHECK_INT(scan_udec("0000", &value, 65535), 4); + CHECK_INT(value, 0); +} + +static void case_bencode_rejects_leading_zeros(void) { + uint64_t value = 0xdead; + + test_case("bencode refuses a leading zero on anything but zero"); + CHECK_INT(scan_udec_bencode("007", &value, 65535), 0); + CHECK_INT(scan_udec_bencode("0000", &value, 65535), 0); + CHECK_INT(scan_udec_bencode("01", &value, 65535), 0); + CHECK_INT(value, 0xdead); +} + +static void case_bencode_accepts_canonical(void) { + uint64_t value; + + test_case("bencode accepts a canonically written number"); + CHECK_INT(scan_udec_bencode("0", &value, 65535), 1); + CHECK_INT(value, 0); + CHECK_INT(scan_udec_bencode("0:", &value, 65535), 1); + CHECK_INT(value, 0); + CHECK_INT(scan_udec_bencode("160:", &value, 65535), 3); + CHECK_INT(value, 160); +} + +static void case_bencode_inherits_the_rest(void) { + uint64_t value = 0xdead; + + test_case("bencode is no laxer than the plain scanner"); + CHECK_INT(scan_udec_bencode(" 1", &value, 65535), 0); + CHECK_INT(scan_udec_bencode("-1", &value, 65535), 0); + CHECK_INT(scan_udec_bencode("+1", &value, 65535), 0); + CHECK_INT(scan_udec_bencode("65536", &value, 65535), 0); + CHECK_INT(value, 0xdead); +} + +void test_scan(void) { + case_plain_numbers(); + case_stops_at_non_digit(); + case_rejects_whitespace(); + case_rejects_sign(); + case_rejects_empty_and_junk(); + case_no_alternative_bases(); + case_refuses_out_of_range(); + case_sixty_four_bit_range(); + case_leading_zeros_allowed(); + case_bencode_rejects_leading_zeros(); + case_bencode_accepts_canonical(); + case_bencode_inherits_the_rest(); +} diff --git a/tests/test.h b/tests/test.h index 8be624b..f0f2360 100644 --- a/tests/test.h +++ b/tests/test.h @@ -82,5 +82,6 @@ void test_vector(void); void test_random(void); void test_hex(void); void test_accesslist(void); +void test_scan(void); #endif -- cgit v1.3