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 --- Makefile | 10 ++-- tests/runner.c | 1 + tests/t_scan.c | 162 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ tests/test.h | 1 + 4 files changed, 169 insertions(+), 5 deletions(-) create mode 100644 tests/t_scan.c diff --git a/Makefile b/Makefile index e96269f..591ddb0 100644 --- a/Makefile +++ b/Makefile @@ -68,9 +68,9 @@ CFLAGS+=-I$(LIBOWFAT_HEADERS) -DGIT_VERSION=$(GIT_VERSION) -Wall -pipe -pthread LDFLAGS+=-L$(LIBOWFAT_LIBRARY) -lowfat -pthread BINARY =opentracker -HEADERS=trackerlogic.h scan_urlencoded_query.h ot_hex.h ot_mutex.h ot_random.h ot_stats.h ot_vector.h ot_clean.h ot_udp.h ot_iovec.h ot_fullscrape.h ot_accesslist.h ot_http.h ot_livesync.h ot_rijndael.h -SOURCES=opentracker.c trackerlogic.c scan_urlencoded_query.c ot_hex.c ot_mutex.c ot_random.c ot_stats.c ot_vector.c ot_clean.c ot_udp.c ot_iovec.c ot_fullscrape.c ot_accesslist.c ot_http.c ot_livesync.c ot_rijndael.c -SOURCES_proxy=proxy.c ot_vector.c ot_mutex.c ot_random.c +HEADERS=trackerlogic.h scan_urlencoded_query.h ot_hex.h ot_scan.h ot_mutex.h ot_random.h ot_stats.h ot_vector.h ot_clean.h ot_udp.h ot_iovec.h ot_fullscrape.h ot_accesslist.h ot_http.h ot_livesync.h ot_rijndael.h +SOURCES=opentracker.c trackerlogic.c scan_urlencoded_query.c ot_hex.c ot_scan.c ot_mutex.c ot_random.c ot_stats.c ot_vector.c ot_clean.c ot_udp.c ot_iovec.c ot_fullscrape.c ot_accesslist.c ot_http.c ot_livesync.c ot_rijndael.c +SOURCES_proxy=proxy.c ot_vector.c ot_mutex.c ot_random.c ot_scan.c OBJECTS = $(SOURCES:%.c=%.o) OBJECTS_debug = $(SOURCES:%.c=%.debug.o) @@ -105,8 +105,8 @@ proxy.debug: $(OBJECTS_proxy_debug) $(HEADERS) # has to. tests/stubs.c supplies the few symbols those modules reference but # the tests never reach. TESTBIN=tests/runner -TEST_SOURCES=tests/runner.c tests/test.c tests/stubs.c tests/t_scan_urlencoded_query.c tests/t_iovec.c tests/t_vector.c tests/t_random.c tests/t_hex.c tests/t_accesslist.c -TEST_UNITS=scan_urlencoded_query.c ot_iovec.c ot_vector.c ot_random.c ot_hex.c ot_accesslist.c +TEST_SOURCES=tests/runner.c tests/test.c tests/stubs.c tests/t_scan_urlencoded_query.c tests/t_iovec.c tests/t_vector.c tests/t_random.c tests/t_hex.c tests/t_accesslist.c tests/t_scan.c +TEST_UNITS=scan_urlencoded_query.c ot_iovec.c ot_vector.c ot_random.c ot_hex.c ot_scan.c ot_accesslist.c TEST_HEADERS=tests/test.h $(HEADERS) # Tests reach code that sits behind feature flags, so the units under test are # built with those features enabled. A test binary is not a production binary. 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