tests/test_string.c

changeset 1500
d20037235c9c
parent 1426
3a89b31f0724
--- a/tests/test_string.c	Thu Nov 20 18:51:00 2025 +0100
+++ b/tests/test_string.c	Thu Nov 20 20:06:20 2025 +0100
@@ -43,6 +43,8 @@
     cxstring s2 = cx_strn("abcd", 2);
     cxmutstr s3 = cx_mutstr((char *) "1234");
     cxmutstr s4 = cx_mutstrn((char *) "abcd", 2);
+    cxstring snull = cx_str(NULL);
+    cxmutstr mnull = cx_mutstr(NULL);
     CX_TEST_DO {
         CX_TEST_ASSERT(s1.length == 4);
         CX_TEST_ASSERT(strncmp(s1.ptr, "1234", 4) == 0);
@@ -52,6 +54,12 @@
         CX_TEST_ASSERT(strncmp(s3.ptr, "1234", 4) == 0);
         CX_TEST_ASSERT(s4.length == 2);
         CX_TEST_ASSERT(strncmp(s4.ptr, "ab", 2) == 0);
+        CX_TEST_ASSERT(0 == snull.length);
+        CX_TEST_ASSERT(NULL == snull.ptr);
+        CX_TEST_ASSERT(0 == mnull.length);
+        CX_TEST_ASSERT(NULL == mnull.ptr);
+        CX_TEST_ASSERT(0 == cx_strcmp(snull, ""));
+        CX_TEST_ASSERT(0 == cx_strcmp(mnull, ""));
     }
 }
 
@@ -89,6 +97,9 @@
         CX_TEST_ASSERT(str.ptr == NULL);
         CX_TEST_ASSERT(str.length == 0);
         CX_TEST_ASSERT(cx_testing_allocator_verify(&talloc));
+        // check that this does not explode
+        cx_strfree(NULL);
+        cx_strfree_a(alloc, NULL);
     }
     cx_testing_allocator_destroy(&talloc);
 }
@@ -393,6 +404,17 @@
         CX_TEST_ASSERT(0 == cx_strcmp(cx_strcast(t6), cx_str("Hello, World!")));
         ASSERT_ZERO_TERMINATED(t6);
         cx_strfree(&t6);
+
+        // test overflow with fake strings
+        char *fakestr = NULL;
+        cxstring a = cx_strn(fakestr, SIZE_MAX / 3 - 10);
+        cxstring b = cx_strn(fakestr, SIZE_MAX / 3 - 5);
+        cxstring c = cx_strn(fakestr, SIZE_MAX / 3 + 20);
+        errno = 0;
+        cxmutstr z = cx_strcat(3, a, b, c);
+        CX_TEST_ASSERT(errno == EOVERFLOW);
+        CX_TEST_ASSERT(z.ptr == NULL);
+        CX_TEST_ASSERT(z.length == 0);
     }
     cx_testing_allocator_destroy(&talloc);
 }
@@ -753,6 +775,9 @@
     cxmutstr replan10 = cx_strreplacen(astr, cx_str("a"), cx_str("x"), 10);
     const char *an10expected = "xxxxxxxxxx";
 
+    cxmutstr norepl = cx_strreplace(cx_strn("hello world", 11), cx_str("worlds"), cx_str("test"));
+    const char *noreplexpect = "hello world";
+
     CX_TEST_DO {
         cxmutstr repl1_a = cx_strreplace_a(alloc, csstr, cx_str("AB"), cx_str("*"));
         const char *expeced1_a = "test * ab TEST xyz";
@@ -789,6 +814,8 @@
         CX_TEST_ASSERT(0 == strcmp(repl1_a.ptr, expeced1_a));
         ASSERT_ZERO_TERMINATED(repl2_a);
         CX_TEST_ASSERT(0 == strcmp(repl2_a.ptr, expected2_a));
+        ASSERT_ZERO_TERMINATED(norepl);
+        CX_TEST_ASSERT(0 == strcmp(norepl.ptr, noreplexpect));
 
         cx_strfree_a(alloc, &repl1_a);
         cx_strfree_a(alloc, &repl2_a);
@@ -807,6 +834,7 @@
     cx_strfree(&replan4);
     cx_strfree(&replan9);
     cx_strfree(&replan10);
+    cx_strfree(&norepl);
     cx_testing_allocator_destroy(&talloc);
 }
 
@@ -1107,6 +1135,49 @@
         CX_TEST_ASSERT(0 != cx_strtoll(cx_str("0x8df9CE03AbC90815"), &ll, 16));
         CX_TEST_ASSERT(errno == ERANGE);
 
+        // negative overflow (we only test for 64 bit long long)
+#if LLONG_MAX == 9223372036854775807ll
+        errno = 0;
+        CX_TEST_ASSERT(0 == cx_strtoll(cx_str("-9223372036854775808"), &ll, 10));
+        CX_TEST_ASSERT(ll == LLONG_MIN);
+        CX_TEST_ASSERT(errno == 0);
+        CX_TEST_ASSERT(0 != cx_strtoll(cx_str("-9223372036854775809"), &ll, 10));
+        CX_TEST_ASSERT(errno == ERANGE);
+#endif
+
+        // edge case: empty and NULL string
+        errno = 0;
+        CX_TEST_ASSERT(0 != cx_strtoll(cx_str(""), &ll, 16));
+        CX_TEST_ASSERT(errno == EINVAL);
+        errno = 0;
+        CX_TEST_ASSERT(0 != cx_strtoll(cx_str(NULL), &ll, 16));
+        CX_TEST_ASSERT(errno == EINVAL);
+
+        // edge case: unsupported base
+        errno = 0;
+        CX_TEST_ASSERT(0 != cx_strtoll(cx_str("7"), &ll, 12));
+        CX_TEST_ASSERT(errno == EINVAL);
+
+        // edge case: incorrect sign characters
+        errno = 0;
+        CX_TEST_ASSERT(0 != cx_strtoll(cx_str("-"), &ll, 10));
+        CX_TEST_ASSERT(errno == EINVAL);
+        errno = 0;
+        CX_TEST_ASSERT(0 != cx_strtoll(cx_str("+"), &ll, 10));
+        CX_TEST_ASSERT(errno == EINVAL);
+        errno = 0;
+        CX_TEST_ASSERT(0 != cx_strtoll(cx_str("-+15"), &ll, 10));
+        CX_TEST_ASSERT(errno == EINVAL);
+        errno = 0;
+        CX_TEST_ASSERT(0 != cx_strtoll(cx_str("--15"), &ll, 10));
+        CX_TEST_ASSERT(errno == EINVAL);
+        errno = 0;
+        CX_TEST_ASSERT(0 != cx_strtoll(cx_str("+-15"), &ll, 10));
+        CX_TEST_ASSERT(errno == EINVAL);
+        errno = 0;
+        CX_TEST_ASSERT(0 != cx_strtoll(cx_str("++15"), &ll, 10));
+        CX_TEST_ASSERT(errno == EINVAL);
+
         // edge case: only the sign bit is set
         errno = 0;
         CX_TEST_ASSERT(0 != cx_strtoi16(cx_str("0x8000"), &i16, 16));
@@ -1163,6 +1234,7 @@
     size_t z;
     CX_TEST_DO {
         // do some brute force tests with all ranges
+        test_strtoint_rollout(0, 10);
         test_strtoint_rollout(47, 10);
         test_strtoint_rollout(210, 10);
         test_strtoint_rollout(5678, 10);
@@ -1170,6 +1242,7 @@
         test_strtoint_rollout(1350266537, 10);
         test_strtoint_rollout(3350266537, 10);
         test_strtoint_rollout(473350266537, 10);
+        test_strtoint_rollout(0, 8);
         test_strtoint_rollout(057, 8);
         test_strtoint_rollout(0322, 8);
         test_strtoint_rollout(013056, 8);
@@ -1178,6 +1251,8 @@
         test_strtoint_rollout(030754201251, 8);
         test_strtoint_rollout(06706567757251, 8);
         test_strtoint_rollout(01767716340165362204025, 8);
+        test_strtoint_rollout(0x0, 16);
+        test_strtoint_rollout(0, 16);
         test_strtoint_rollout(0x65, 16);
         test_strtoint_rollout(0xf5, 16);
         test_strtoint_rollout(0xABC5, 16);
@@ -1187,6 +1262,8 @@
         test_strtoint_rollout(0x6df9CE03AbC90815, 16);
         test_strtoint_rollout(0xfdf9CE03AbC90815, 16);
 #if __STDC_VERSION__ >= 202300L
+        test_strtoint_rollout(0b0, 2);
+        test_strtoint_rollout(0, 2);
         test_strtoint_rollout(0b01000010100100101110101001110101, 2);
         test_strtoint_rollout(0b00011010101100001111111001010100, 2);
         test_strtoint_rollout(0b10110001001001010001010111010011, 2);
@@ -1218,6 +1295,36 @@
         CX_TEST_ASSERT(0 == cx_strtou8_lc(cx_str("1010 1011"), &u8, 2, " "));
         CX_TEST_ASSERT(errno == 0);
         CX_TEST_ASSERT(u8 == 0xAB);
+
+        // edge case: empty and NULL string
+        errno = 0;
+        CX_TEST_ASSERT(0 != cx_strtoull(cx_str(""), &ull, 16));
+        CX_TEST_ASSERT(errno == EINVAL);
+        errno = 0;
+        CX_TEST_ASSERT(0 != cx_strtoull(cx_str(NULL), &ull, 16));
+        CX_TEST_ASSERT(errno == EINVAL);
+
+        // edge case: unsupported base
+        errno = 0;
+        CX_TEST_ASSERT(0 != cx_strtoull(cx_str("7"), &ull, 12));
+        CX_TEST_ASSERT(errno == EINVAL);
+
+        // edge case: prefix only
+        errno = 0;
+        CX_TEST_ASSERT(0 != cx_strtoull(cx_str("0b"), &ull, 2));
+        CX_TEST_ASSERT(errno == EINVAL);
+        errno = 0;
+        CX_TEST_ASSERT(0 != cx_strtoull(cx_str("b"), &ull, 2));
+        CX_TEST_ASSERT(errno == EINVAL);
+        errno = 0;
+        CX_TEST_ASSERT(0 != cx_strtoull(cx_str("0x"), &ull, 16));
+        CX_TEST_ASSERT(errno == EINVAL);
+        errno = 0;
+        CX_TEST_ASSERT(0 != cx_strtoull(cx_str("x"), &ull, 16));
+        CX_TEST_ASSERT(errno == EINVAL);
+        errno = 0;
+        CX_TEST_ASSERT(0 != cx_strtoull(cx_str("#"), &ull, 16));
+        CX_TEST_ASSERT(errno == EINVAL);
     }
 }
 
@@ -1275,6 +1382,12 @@
         CX_TEST_ASSERT(0 == cx_strtod(cx_str("11.3"), &d));
         CX_TEST_ASSERT(0 == cx_vcmp_double(11.3, d));
 
+        CX_TEST_ASSERT(0 == cx_strtod(cx_str("13."), &d));
+        CX_TEST_ASSERT(0 == cx_vcmp_double(13.0, d));
+
+        CX_TEST_ASSERT(0 == cx_strtod(cx_str("47"), &d));
+        CX_TEST_ASSERT(0 == cx_vcmp_double(47.0, d));
+
         CX_TEST_ASSERT(0 == cx_strtod(cx_str("-13.37"), &d));
         CX_TEST_ASSERT(0 == cx_vcmp_double(-13.37, d));
 
@@ -1290,6 +1403,53 @@
         CX_TEST_ASSERT(0 == cx_strtod_lc(cx_str("138,339.4"), &d, ',', "."));
         CX_TEST_ASSERT(0 == cx_vcmp_double(138.3394, d));
 
+        CX_TEST_ASSERT(0 == cx_strtod_lc(cx_str("13.37e04.7"), &d, ',', "."));
+        CX_TEST_ASSERT(0 == cx_vcmp_double(1337e47, d));
+
+        d = 47.11;
+        errno = 0;
+        CX_TEST_ASSERT(0 != cx_strtod(cx_str(""), &d));
+        CX_TEST_ASSERT(errno == EINVAL);
+        CX_TEST_ASSERT(d == 47.11);
+        errno = 0;
+        CX_TEST_ASSERT(0 != cx_strtod(cx_str(NULL), &d));
+        CX_TEST_ASSERT(errno == EINVAL);
+        CX_TEST_ASSERT(d == 47.11);
+        errno = 0;
+        CX_TEST_ASSERT(0 != cx_strtod(cx_str("+"), &d));
+        CX_TEST_ASSERT(errno == EINVAL);
+        CX_TEST_ASSERT(d == 47.11);
+        errno = 0;
+        CX_TEST_ASSERT(0 != cx_strtod(cx_str("-"), &d));
+        CX_TEST_ASSERT(errno == EINVAL);
+        CX_TEST_ASSERT(d == 47.11);
+        errno = 0;
+        CX_TEST_ASSERT(0 != cx_strtod(cx_str("+-5"), &d));
+        CX_TEST_ASSERT(errno == EINVAL);
+        CX_TEST_ASSERT(d == 47.11);
+        errno = 0;
+        CX_TEST_ASSERT(0 != cx_strtod(cx_str("-+5"), &d));
+        CX_TEST_ASSERT(errno == EINVAL);
+        CX_TEST_ASSERT(d == 47.11);
+        errno = 0;
+        CX_TEST_ASSERT(0 != cx_strtod(cx_str("++5"), &d));
+        CX_TEST_ASSERT(errno == EINVAL);
+        CX_TEST_ASSERT(d == 47.11);
+        errno = 0;
+        CX_TEST_ASSERT(0 != cx_strtod(cx_str("--5"), &d));
+        CX_TEST_ASSERT(errno == EINVAL);
+        CX_TEST_ASSERT(d == 47.11);
+
+        errno = 0;
+        CX_TEST_ASSERT(0 != cx_strtod_lc(cx_str("."), &d, '.', "'"));
+        CX_TEST_ASSERT(errno == EINVAL);
+        CX_TEST_ASSERT(d == 47.11);
+
+        errno = 0;
+        CX_TEST_ASSERT(0 != cx_strtod(cx_str("19e0x5"), &d));
+        CX_TEST_ASSERT(errno == EINVAL);
+        CX_TEST_ASSERT(d == 47.11);
+
         // TODO: test and improve support for big numbers, precision, and out-of-range detection
     }
 }

mercurial