--- a/tests/test_string.c Mon Dec 23 00:33:27 2024 +0100 +++ b/tests/test_string.c Mon Dec 23 00:34:05 2024 +0100 @@ -31,6 +31,9 @@ #include "cx/string.h" +#include <limits.h> +#include <errno.h> + #define ASSERT_ZERO_TERMINATED(str) CX_TEST_ASSERTM((str).ptr[(str).length] == '\0', \ #str " is not zero terminated") @@ -970,6 +973,159 @@ cx_strfree(&str); } +#define test_strtoint_impl(suffix, num, base, var, min, max) \ + do { \ + errno = 0; \ + int r = cx_strto##var(cx_str( #num), &var, base); \ + if ((min) <= (num##suffix) && (num##suffix) <= (max)) { \ + CX_TEST_ASSERTM(0 == r, "failed for "#num); \ + CX_TEST_ASSERT(0 == errno); \ + CX_TEST_ASSERT((num##suffix) == (0##suffix)+(var)); \ + } else { \ + CX_TEST_ASSERTM(0 != r, "out-of-range not detected for "#num " in variant "#var); \ + CX_TEST_ASSERT(ERANGE == errno); \ + } \ + } while (0) + +#define test_strtoint_rollout_signed_impl(num, base) \ + test_strtoint_impl(LL, num, base, s, SHRT_MIN, SHRT_MAX); \ + test_strtoint_impl(LL, num, base, i, INT_MIN, INT_MAX); \ + test_strtoint_impl(LL, num, base, l, LONG_MIN, LONG_MAX); \ + test_strtoint_impl(LL, num, base, ll, LLONG_MIN, LLONG_MAX); \ + test_strtoint_impl(LL, num, base, i8, INT8_MIN, INT8_MAX); \ + test_strtoint_impl(LL, num, base, i16, INT16_MIN, INT16_MAX); \ + test_strtoint_impl(LL, num, base, i32, INT32_MIN, INT32_MAX); \ + test_strtoint_impl(LL, num, base, i64, INT64_MIN, INT64_MAX); \ + test_strtoint_impl(LL, num, base, z, -SSIZE_MAX-1, SSIZE_MAX) + +#define test_strtoint_rollout_signed(num, base) \ + test_strtoint_rollout_signed_impl(num, base); \ + test_strtoint_rollout_signed_impl(-num, base) + +#define test_strtoint_rollout(num, base) \ + test_strtoint_impl(ULL, num, base, us, 0, USHRT_MAX); \ + test_strtoint_impl(ULL, num, base, u, 0, UINT_MAX); \ + test_strtoint_impl(ULL, num, base, ul, 0, ULONG_MAX); \ + test_strtoint_impl(ULL, num, base, ull, 0, ULLONG_MAX); \ + test_strtoint_impl(ULL, num, base, u8, 0, UINT8_MAX); \ + test_strtoint_impl(ULL, num, base, u16, 0, UINT16_MAX); \ + test_strtoint_impl(ULL, num, base, u32, 0, UINT32_MAX); \ + test_strtoint_impl(ULL, num, base, u64, 0, UINT64_MAX); \ + test_strtoint_impl(ULL, num, base, uz, 0, SIZE_MAX) + +CX_TEST(test_string_to_signed_integer) { + short s; + int i; + long l; + long long ll; + int8_t i8; + int16_t i16; + int32_t i32; + int64_t i64; + ssize_t z; + CX_TEST_DO { + // do some brute force tests with all ranges + test_strtoint_rollout_signed(47, 10); + test_strtoint_rollout_signed(210, 10); + test_strtoint_rollout_signed(5678, 10); + test_strtoint_rollout_signed(40678, 10); + test_strtoint_rollout_signed(1350266537, 10); + test_strtoint_rollout_signed(3350266537, 10); + test_strtoint_rollout_signed(473350266537, 10); + test_strtoint_rollout_signed(057, 8); + test_strtoint_rollout_signed(0322, 8); + test_strtoint_rollout_signed(013056, 8); + test_strtoint_rollout_signed(0117346, 8); + test_strtoint_rollout_signed(012036667251, 8); + test_strtoint_rollout_signed(030754201251, 8); + test_strtoint_rollout_signed(06706567757251, 8); + test_strtoint_rollout_signed(0767716340165362204025, 8); + test_strtoint_rollout_signed(0x65, 16); + test_strtoint_rollout_signed(0xf5, 16); + test_strtoint_rollout_signed(0xABC5, 16); + test_strtoint_rollout_signed(0xFBC5, 16); + test_strtoint_rollout_signed(0x6df9CE03, 16); + test_strtoint_rollout_signed(0xFdf9CE03, 16); + test_strtoint_rollout_signed(0x6df9CE03AbC90815, 16); + // TODO: roll out base 2 tests, but that needs C23 + + // do some special case tests + + // can fit only in unsigned long long + errno = 0; + CX_TEST_ASSERT(0 != cx_strtoll(cx_str("0x8df9CE03AbC90815"), &ll, 16)); + CX_TEST_ASSERT(errno == ERANGE); + + // TODO: implement more special cases + } +} + +CX_TEST(test_string_to_unsigned_integer) { + unsigned short us; + unsigned int u; + unsigned long ul; + unsigned long long ull; + uint8_t u8; + uint16_t u16; + uint32_t u32; + uint64_t u64; + size_t uz; + CX_TEST_DO { + // do some brute force tests with all ranges + test_strtoint_rollout(47, 10); + test_strtoint_rollout(210, 10); + test_strtoint_rollout(5678, 10); + test_strtoint_rollout(40678, 10); + test_strtoint_rollout(1350266537, 10); + test_strtoint_rollout(3350266537, 10); + test_strtoint_rollout(473350266537, 10); + test_strtoint_rollout(057, 8); + test_strtoint_rollout(0322, 8); + test_strtoint_rollout(013056, 8); + test_strtoint_rollout(0117346, 8); + test_strtoint_rollout(012036667251, 8); + test_strtoint_rollout(030754201251, 8); + test_strtoint_rollout(06706567757251, 8); + test_strtoint_rollout(01767716340165362204025, 8); + test_strtoint_rollout(0x65, 16); + test_strtoint_rollout(0xf5, 16); + test_strtoint_rollout(0xABC5, 16); + test_strtoint_rollout(0xFBC5, 16); + test_strtoint_rollout(0x6df9CE03, 16); + test_strtoint_rollout(0xFdf9CE03, 16); + test_strtoint_rollout(0x6df9CE03AbC90815, 16); + test_strtoint_rollout(0xfdf9CE03AbC90815, 16); + // TODO: roll out base 2 tests, but that needs C23 + + // do some special case tests + + // TODO: implement tests + } +} + +CX_TEST(test_string_to_float) { + float f; + CX_TEST_DO { + CX_TEST_ASSERT(0 == cx_strtof(cx_str("11.3"), &f)); + CX_TEST_ASSERT(11.3f == f); + } +} + +CX_TEST(test_string_to_double) { + double d; + CX_TEST_DO { + CX_TEST_ASSERT(0 == cx_strtod(cx_str("11.3"), &d)); + CX_TEST_ASSERT(11.3 == d); + } +} + +CX_TEST(test_string_to_float_german) { + float f; + CX_TEST_DO { + // TODO: implement + (void)f; + } +} CxTestSuite *cx_test_suite_string(void) { CxTestSuite *suite = cx_test_suite_new("string"); @@ -1006,3 +1162,15 @@ return suite; } + +CxTestSuite *cx_test_suite_string_to_number(void) { + CxTestSuite *suite = cx_test_suite_new("string to number"); + + cx_test_register(suite, test_string_to_signed_integer); + cx_test_register(suite, test_string_to_unsigned_integer); + cx_test_register(suite, test_string_to_float); + cx_test_register(suite, test_string_to_double); + cx_test_register(suite, test_string_to_float_german); + + return suite; +}