/* 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_uint("0", &value, 65535), 1); CHECK_INT(value, 0); CHECK_INT(scan_uint("7", &value, 65535), 1); CHECK_INT(value, 7); CHECK_INT(scan_uint("6969", &value, 65535), 4); CHECK_INT(value, 6969); CHECK_INT(scan_uint("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_uint("6969:rest", &value, 65535), 4); CHECK_INT(value, 6969); CHECK_INT(scan_uint("128/8", &value, 65535), 3); CHECK_INT(value, 128); CHECK_INT(scan_uint("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_uint(" 1", &value, 65535), 0); CHECK_INT(scan_uint("\t1", &value, 65535), 0); CHECK_INT(scan_uint("\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_uint("+1", &value, 65535), 0); CHECK_INT(scan_uint("-1", &value, 65535), 0); CHECK_INT(scan_uint("-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_uint("", &value, 65535), 0); CHECK_INT(scan_uint("x", &value, 65535), 0); CHECK_INT(scan_uint(":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_uint("0x10", &value, 65535), 1); CHECK_INT(value, 0); CHECK_INT(scan_uint("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_uint("65536", &value, 65535), 0); CHECK_INT(scan_uint("99999", &value, 65535), 0); CHECK_INT(scan_uint("129", &value, 128), 0); CHECK_INT(value, 0xdead); test_case("the boundary itself is accepted"); CHECK_INT(scan_uint("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_uint("18446744073709551615", &value, UINT64_MAX), 20); CHECK(value == UINT64_MAX); test_case("a number too large for 64 bits is refused"); CHECK_INT(scan_uint("18446744073709551616", &value, UINT64_MAX), 0); CHECK_INT(scan_uint("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_uint("007", &value, 65535), 3); CHECK_INT(value, 7); CHECK_INT(scan_uint("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_uint_bencode("007", &value, 65535), 0); CHECK_INT(scan_uint_bencode("0000", &value, 65535), 0); CHECK_INT(scan_uint_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_uint_bencode("0", &value, 65535), 1); CHECK_INT(value, 0); CHECK_INT(scan_uint_bencode("0:", &value, 65535), 1); CHECK_INT(value, 0); CHECK_INT(scan_uint_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_uint_bencode(" 1", &value, 65535), 0); CHECK_INT(scan_uint_bencode("-1", &value, 65535), 0); CHECK_INT(scan_uint_bencode("+1", &value, 65535), 0); CHECK_INT(scan_uint_bencode("65536", &value, 65535), 0); CHECK_INT(value, 0xdead); } /* ------------------------------------------- fixed width signed integers */ /* A value lifted out of a query string arrives as a pointer and a length with nothing terminating it, and the whole of it has to be the number. */ static void case_int_whole_field(void) { int64_t value = 0; test_case("the whole field is read, sign and all"); CHECK_INT(scan_int("123", 3, &value), 0); CHECK_INT(value, 123); CHECK_INT(scan_int("-45", 3, &value), 0); CHECK_INT(value, -45); test_case("and only as far as the length given"); CHECK_INT(scan_int("12345", 3, &value), 0); CHECK_INT(value, 123); } static void case_int_rejects_the_rest(void) { int64_t value = 4711; test_case("anything that is not all digits is refused"); CHECK_INT(scan_int("12a", 3, &value), -1); CHECK_INT(scan_int("", 0, &value), -1); CHECK_INT(scan_int("-", 1, &value), -1); CHECK_INT(scan_int(" 12", 3, &value), -1); CHECK_INT(scan_int("+12", 3, &value), -1); test_case("and a refused field leaves the number alone"); CHECK_INT(value, 4711); } static void case_int_overflow(void) { int64_t value = 0; test_case("a field too long to fit is refused rather than wrapped"); CHECK_INT(scan_int("9223372036854775807", 19, &value), 0); CHECK_INT(value, INT64_MAX); CHECK_INT(scan_int("9223372036854775808", 19, &value), -1); CHECK_INT(scan_int("99999999999999999999", 20, &value), -1); test_case("including the negative side"); CHECK_INT(scan_int("-9223372036854775807", 20, &value), 0); CHECK_INT(value, -INT64_MAX); } void test_scan(void) { case_int_whole_field(); case_int_rejects_the_rest(); case_int_overflow(); 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(); }