SDL: stdlib: Conditionally undef some SDL_strtox tests

From eb199176e68def985e7f1534eb6f2a6abe410c5d Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Carl=20=C3=85stholm?= <[EMAIL REDACTED]>
Date: Fri, 13 Sep 2024 18:09:16 +0200
Subject: [PATCH] stdlib: Conditionally undef some SDL_strtox tests

Some test cases have implementation-defined results,
so we should only test these when we know SDL's own
implementations of the functions are used.
---
 src/stdlib/SDL_string.c      | 21 ++++++++----
 test/testautomation_stdlib.c | 65 +++++++++++++++++++++++++++---------
 2 files changed, 64 insertions(+), 22 deletions(-)

diff --git a/src/stdlib/SDL_string.c b/src/stdlib/SDL_string.c
index a1d593e955315..a7cb691f7c572 100644
--- a/src/stdlib/SDL_string.c
+++ b/src/stdlib/SDL_string.c
@@ -389,8 +389,13 @@ static size_t SDL_ScanUnsignedLongLongInternal(const char *text, int count, int
         } while (count == 0 || (text - text_start) != count);
     }
     if (text == number_start) {
-        // no number was parsed, and thus no characters were consumed
-        text = text_start;
+        if (radix == 16 && text > text_start && (*(text - 1) == 'x' || *(text - 1) == 'X')) {
+            // the string was "0x"; consume the '0' but not the 'x'
+            --text;
+        } else {
+            // no number was parsed, and thus no characters were consumed
+            text = text_start;
+        }
     }
     if (overflow) {
         if (negative) {
@@ -478,8 +483,13 @@ static size_t SDL_ScanUnsignedLongLongInternalW(const wchar_t *text, int count,
         } while (count == 0 || (text - text_start) != count);
     }
     if (text == number_start) {
-        // no number was parsed, and thus no characters were consumed
-        text = text_start;
+        if (radix == 16 && text > text_start && (*(text - 1) == 'x' || *(text - 1) == 'X')) {
+            // the string was "0x"; consume the '0' but not the 'x'
+            --text;
+        } else {
+            // no number was parsed, and thus no characters were consumed
+            text = text_start;
+        }
     }
     if (overflow) {
         if (negative) {
@@ -656,8 +666,7 @@ static size_t SDL_ScanFloat(const char *text, double *valuep)
     if (text == number_start) {
         // no number was parsed, and thus no characters were consumed
         text = text_start;
-    }
-    if (negative) {
+    } else if (negative) {
         value = -value;
     }
     *valuep = value;
diff --git a/test/testautomation_stdlib.c b/test/testautomation_stdlib.c
index c500e00e1d47b..30702a867215b 100644
--- a/test/testautomation_stdlib.c
+++ b/test/testautomation_stdlib.c
@@ -4,6 +4,7 @@
 #include <SDL3/SDL.h>
 #include <SDL3/SDL_test.h>
 #include "testautomation_suites.h"
+#include "SDL_build_config.h"
 
 /* Test case functions */
 
@@ -1267,9 +1268,24 @@ static int SDLCALL stdlib_wcstol(void *arg)
     WCSTOL_TEST_CASE(L"00110011", 2, 51, 8);
     WCSTOL_TEST_CASE(L"-uvwxyz", 32, -991, 3);
     WCSTOL_TEST_CASE(L"ZzZzZzZzZzZzZ", 36, long_max, 13);
+
     WCSTOL_TEST_CASE(L"-0", 10, 0, 2);
     WCSTOL_TEST_CASE(L" - 1", 0, 0, 0); // invalid input
 
+#ifndef HAVE_WCSTOL
+    // implementation-defined
+    WCSTOL_TEST_CASE(L" +0x", 0, 0, 3);
+#endif
+
+    // values near the bounds of the type
+    if (sizeof(long) == 4) {
+        WCSTOL_TEST_CASE(L"2147483647", 10, 2147483647, 10);
+        WCSTOL_TEST_CASE(L"2147483648", 10, 2147483647, 10);
+        WCSTOL_TEST_CASE(L"-2147483648", 10, -2147483647L - 1, 11);
+        WCSTOL_TEST_CASE(L"-2147483649", 10, -2147483647L - 1, 11);
+        WCSTOL_TEST_CASE(L"-9999999999999999999999999999999999999999", 10, -2147483647L - 1, 41);
+    }
+
 #undef WCSTOL_TEST_CASE
 
     return TEST_COMPLETED;
@@ -1295,7 +1311,6 @@ static int SDLCALL stdlib_strtox(void *arg)
     STRTOX_TEST_CASE(SDL_strtoull, unsigned long long, "%llu", "+123abcxyz", 0, 123, 4);
     STRTOX_TEST_CASE(SDL_strtoull, unsigned long long, "%llu", "-123abcxyz", 0, -123, 4);
     STRTOX_TEST_CASE(SDL_strtoull, unsigned long long, "%llu", "9999999999999999999999999999999999999999abcxyz", 0, ullong_max, 40);
-    STRTOX_TEST_CASE(SDL_strtoull, unsigned long long, "%llu", "-9999999999999999999999999999999999999999abcxyz", 0, ullong_max, 41);
 
     // infer hexadecimal
     STRTOX_TEST_CASE(SDL_strtoull, unsigned long long, "%llu", "0x123abcxyz", 0, 0x123abc, 8);
@@ -1308,40 +1323,54 @@ static int SDLCALL stdlib_strtox(void *arg)
     STRTOX_TEST_CASE(SDL_strtoull, unsigned long long, "%llu", "00110011", 2, 51, 8);
     STRTOX_TEST_CASE(SDL_strtoull, unsigned long long, "%llu", "-uvwxyz", 32, -991, 3);
     STRTOX_TEST_CASE(SDL_strtoull, unsigned long long, "%llu", "ZzZzZzZzZzZzZzZzZzZzZzZzZ", 36, ullong_max, 25);
+
     STRTOX_TEST_CASE(SDL_strtoull, unsigned long long, "%llu", "-0", 10, 0, 2);
     STRTOX_TEST_CASE(SDL_strtoull, unsigned long long, "%llu", " - 1", 0, 0, 0); // invalid input
 
+#ifndef HAVE_STRTOULL
+    // implementation-defined
+    STRTOX_TEST_CASE(SDL_strtoull, unsigned long long, "%llu", " +0x", 0, 0, 3);
+#endif
+
     // We know that SDL_strtol, SDL_strtoul and SDL_strtoll share the same code path as SDL_strtoull under the hood,
     // so the most interesting test cases are those close to the bounds of the integer type.
 
     // For simplicity, we only run long/long long tests when they are 32-bit/64-bit, respectively.
+    // Suppressing warnings would be difficult otherwise.
     // Since the CI runs the tests against a variety of targets, this should be fine in practice.
 
-    // SDL_strtol (32-bit)
     if (sizeof(long) == 4) {
         STRTOX_TEST_CASE(SDL_strtol, long, "%ld", "2147483647", 10, 2147483647, 10);
         STRTOX_TEST_CASE(SDL_strtol, long, "%ld", "2147483648", 10, 2147483647, 10);
         STRTOX_TEST_CASE(SDL_strtol, long, "%ld", "-2147483648", 10, -2147483647L - 1, 11);
         STRTOX_TEST_CASE(SDL_strtol, long, "%ld", "-2147483649", 10, -2147483647L - 1, 11);
         STRTOX_TEST_CASE(SDL_strtol, long, "%ld", "-9999999999999999999999999999999999999999", 10, -2147483647L - 1, 41);
-    }
 
-    // SDL_strtoul (32-bit)
-    if (sizeof(unsigned long) == 4) {
         STRTOX_TEST_CASE(SDL_strtoul, unsigned long, "%lu", "4294967295", 10, 4294967295, 10);
         STRTOX_TEST_CASE(SDL_strtoul, unsigned long, "%lu", "4294967296", 10, 4294967295, 10);
         STRTOX_TEST_CASE(SDL_strtoul, unsigned long, "%lu", "-4294967295", 10, 1, 11);
+#ifndef HAVE_STRTOUL
+        // implementation-defined
         STRTOX_TEST_CASE(SDL_strtoul, unsigned long, "%lu", "-4294967296", 10, 4294967295, 11);
         STRTOX_TEST_CASE(SDL_strtoul, unsigned long, "%lu", "-9999999999999999999999999999999999999999", 10, 4294967295, 41);
+#endif
     }
 
-    // SDL_strtoll (64-bit)
     if (sizeof(long long) == 8) {
-        STRTOX_TEST_CASE(SDL_strtoll, long long, "%lld", "9223372036854775807", 10, 9223372036854775807, 19);
-        STRTOX_TEST_CASE(SDL_strtoll, long long, "%lld", "9223372036854775808", 10, 9223372036854775807, 19);
+        STRTOX_TEST_CASE(SDL_strtoll, long long, "%lld", "9223372036854775807", 10, 9223372036854775807LL, 19);
+        STRTOX_TEST_CASE(SDL_strtoll, long long, "%lld", "9223372036854775808", 10, 9223372036854775807LL, 19);
         STRTOX_TEST_CASE(SDL_strtoll, long long, "%lld", "-9223372036854775808", 10, -9223372036854775807LL - 1, 20);
         STRTOX_TEST_CASE(SDL_strtoll, long long, "%lld", "-9223372036854775809", 10, -9223372036854775807LL - 1, 20);
         STRTOX_TEST_CASE(SDL_strtoll, long long, "%lld", "-9999999999999999999999999999999999999999", 10, -9223372036854775807LL - 1, 41);
+
+        STRTOX_TEST_CASE(SDL_strtoull, unsigned long long, "%llu", "18446744073709551615", 10, 18446744073709551615ULL, 20);
+        STRTOX_TEST_CASE(SDL_strtoull, unsigned long long, "%llu", "18446744073709551616", 10, 18446744073709551615ULL, 20);
+        STRTOX_TEST_CASE(SDL_strtoull, unsigned long long, "%llu", "-18446744073709551615", 10, 1, 21);
+#ifndef HAVE_STRTOULL
+        // implementation-defined
+        STRTOX_TEST_CASE(SDL_strtoull, unsigned long long, "%llu", "-18446744073709551616", 10, 18446744073709551615ULL, 21);
+        STRTOX_TEST_CASE(SDL_strtoull, unsigned long long, "%llu", "-9999999999999999999999999999999999999999", 10, 18446744073709551615ULL, 41);
+#endif
     }
 
 #undef STRTOX_TEST_CASE
@@ -1351,21 +1380,25 @@ static int SDLCALL stdlib_strtox(void *arg)
 
 static int SDLCALL stdlib_strtod(void *arg)
 {
-#define STRTOD_TEST_CASE(str, expected_result, expected_endp_offset) do {                                   \
-        const char *s = str;                                                                                \
-        double r, expected_r = expected_result;                                                             \
-        char *ep, *expected_ep = (char *)s + expected_endp_offset;                                          \
-        r = SDL_strtod(s, &ep);                                                                             \
-        SDLTest_AssertPass("Call to SDL_strtod(" #str ", &endp)");                                          \
-        SDLTest_AssertCheck(r == expected_r, "Check result value, expected: %f, got: %f", expected_r, r);   \
-        SDLTest_AssertCheck(ep == expected_ep, "Check endp value, expected: %p, got: %p", expected_ep, ep); \
+#define STRTOD_TEST_CASE(str, expected_result, expected_endp_offset) do {                                                                              \
+        const char *s = str;                                                                                                                           \
+        double r, expected_r = expected_result;                                                                                                        \
+        char *ep, *expected_ep = (char *)s + expected_endp_offset;                                                                                     \
+        r = SDL_strtod(s, &ep);                                                                                                                        \
+        SDLTest_AssertPass("Call to SDL_strtod(" #str ", &endp)");                                                                                     \
+        SDLTest_AssertCheck(r == expected_r && (r != 0.0 || 1.0 / r == 1.0 / expected_r), "Check result value, expected: %f, got: %f", expected_r, r); \
+        SDLTest_AssertCheck(ep == expected_ep, "Check endp value, expected: %p, got: %p", expected_ep, ep);                                            \
     } while (0)
 
     STRTOD_TEST_CASE("\t  123.75abcxyz", 123.75, 9); // skip leading space
     STRTOD_TEST_CASE("+999.555", 999.555, 8);
     STRTOD_TEST_CASE("-999.555", -999.555, 8);
+
+#ifndef HAVE_STRTOD
+    // implementation-defined
     STRTOD_TEST_CASE("-0", -0.0, 2);
     STRTOD_TEST_CASE(" - 1", 0.0, 0); // invalid input
+#endif
 
 #undef STRTOD_TEST_CASE