[PATCH v2] Make __strtod_internal tests type-generic
DJ Delorie
dj@redhat.com
Tue Aug 27 02:59:28 GMT 2024
A few typos but otherwise OK. One of the test looks locale-dependent
but "it worked before".
Reviewed-by: DJ Delorie <dj@redhat.com>
Joseph Myers <josmyers@redhat.com> writes:
> diff --git a/stdlib/tst-strtod1i.c b/stdlib/tst-strtod1i.c
> index 9d6bb760fb..dec1ef37c1 100644
> --- a/stdlib/tst-strtod1i.c
> +++ b/stdlib/tst-strtod1i.c
> @@ -25,60 +25,91 @@
> #include <string.h>
> #include <math.h>
>
> -/* Perform a few tests in a locale with thousands separators. */
> -static int
> -do_test (void)
> -{
> - static const struct
> - {
> - const char *loc;
> - const char *str;
> - double exp;
> - ptrdiff_t nread;
> - } tests[] =
> - {
> - { "de_DE.UTF-8", "1,5", 1.5, 3 },
> - { "de_DE.UTF-8", "1.5", 1.0, 1 },
> - { "de_DE.UTF-8", "1.500", 1500.0, 5 },
> - { "de_DE.UTF-8", "36.893.488.147.419.103.232", 0x1.0p65, 26 }
> - };
> -#define ntests (sizeof (tests) / sizeof (tests[0]))
> - size_t n;
> - int result = 0;
> - for (n = 0; n < ntests; ++n)
> - {
> - double d;
> - char *endp;
Moved lower, ok.
> +#include "tst-strtod.h"
Ok.
> +/* This tests internal interfaces, which are only defined for types
> + with distinct ABIs, so diable testing for types without distinct
> + ABIs. */
spelling: s/diable/disable/ ?
> +#undef IF_FLOAT32
> +#define IF_FLOAT32(x)
> +#undef IF_FLOAT64
> +#define IF_FLOAT64(x)
> +#undef IF_FLOAT32X
> +#define IF_FLOAT32X(x)
> +#undef IF_FLOAT64X
> +#define IF_FLOAT64X(x)
> +#if !__HAVE_DISTINCT_FLOAT128
> +# undef IF_FLOAT128
> +# define IF_FLOAT128(x)
> +#endif
Ok.
> - if (setlocale (LC_ALL, tests[n].loc) == NULL)
> - {
> - printf ("cannot set locale %s\n", tests[n].loc);
> - result = 1;
> - continue;
> - }
Moved, ok
> +#define ntests (sizeof (tests) / sizeof (tests[0]))
Ok as it's only used when tests is defined.
> - d = __strtod_internal (tests[n].str, &endp, 1);
> - if (d != tests[n].exp)
> - {
> - printf ("strtod(\"%s\") returns %g and not %g\n",
> - tests[n].str, d, tests[n].exp);
> - result = 1;
> - }
> - else if (endp - tests[n].str != tests[n].nread)
> - {
> - printf ("strtod(\"%s\") read %td bytes and not %td\n",
> - tests[n].str, endp - tests[n].str, tests[n].nread);
> - result = 1;
> - }
> - }
Moved, ok
> +/* Perform a few tests in a locale with thousands separators. */
> +#define TEST_STRTOD(FSUF, FTYPE, FTOSTR, LSUF, CSUF) \
FSUF = function suffix
LSUF = literal suffix?
CSUF = copysign suffix
> +static int \
> +test_strto ## FSUF (void) \
> +{ \
> + static const struct \
> + { \
> + const char *loc; \
> + const char *str; \
> + FTYPE exp; \
> + ptrdiff_t nread; \
> + } tests[] = \
> + { \
> + { "de_DE.UTF-8", "1,5", 1.5 ## LSUF, 3 }, \
> + { "de_DE.UTF-8", "1.5", 1.0 ## LSUF, 1 }, \
> + { "de_DE.UTF-8", "1.500", 1500.0 ## LSUF, 5 }, \
> + { "de_DE.UTF-8", "36.893.488.147.419.103.232", 0x1.0p65 ## LSUF, 26 } \
> + }; \
> + size_t n; \
> + int result = 0; \
> + \
> + puts ("\nLocale tests"); \
> + \
> + for (n = 0; n < ntests; ++n) \
> + { \
> + FTYPE d; \
> + char *endp; \
> + \
> + if (setlocale (LC_ALL, tests[n].loc) == NULL) \
> + { \
> + printf ("cannot set locale %s\n", tests[n].loc); \
> + result = 1; \
> + continue; \
> + } \
> + \
> + d = __strto ## FSUF ## _internal (tests[n].str, &endp, 1); \
> + if (d != tests[n].exp) \
> + { \
> + char buf1[FSTRLENMAX], buf2[FSTRLENMAX]; \
> + FTOSTR (buf1, sizeof (buf1), "%g", d); \
> + FTOSTR (buf2, sizeof (buf2), "%g", tests[n].exp); \
Don't we need "%lg" here for long double? Ah, the function itself
defines the "l" part. Ok.
> + printf ("strto" # FSUF "(\"%s\") returns %s and not %s\n", \
> + tests[n].str, buf1, buf2); \
> + result = 1; \
> + } \
> + else if (endp - tests[n].str != tests[n].nread) \
> + { \
> + printf ("strto" # FSUF "(\"%s\") read %td bytes and not %td\n", \
> + tests[n].str, endp - tests[n].str, tests[n].nread); \
> + result = 1; \
> + } \
> + } \
Ok.
> + if (result == 0) \
> + puts ("all OK"); \
> + \
> + return result ? EXIT_FAILURE : EXIT_SUCCESS; \
> +}
Ok.
> - if (result == 0)
> - puts ("all OK");
> +GEN_TEST_STRTOD_FOREACH (TEST_STRTOD)
Invokes TEST_STRTOD three times, creating three functions, ok
> - return result ? EXIT_FAILURE : EXIT_SUCCESS;
> +static int
> +do_test (void)
> +{
> + return STRTOD_TEST_FOREACH (test_strto);
> }
Same, but alls those three functions. Ok.
> #include <support/test-driver.c>
> diff --git a/stdlib/tst-strtod3.c b/stdlib/tst-strtod3.c
> index 23abec1896..fc4efd44d1 100644
> --- a/stdlib/tst-strtod3.c
> +++ b/stdlib/tst-strtod3.c
> @@ -3,19 +3,73 @@
> #include <stdlib.h>
> #include <string.h>
>
> -static const struct
> -{
> - const char *in;
> - const char *out;
> - double expected;
> -} tests[] =
> - {
> - { "000,,,e1", ",,,e1", 0.0 },
> - { "000e1", "", 0.0 },
> - { "000,1e1", ",1e1", 0.0 }
> - };
> -#define NTESTS (sizeof (tests) / sizeof (tests[0]))
> +#include "tst-strtod.h"
> +
> +/* This tests internal interfaces, which are only defined for types
> + with distinct ABIs, so diable testing for types without distinct
Again, s/diable/disable/
> + ABIs. */
> +#undef IF_FLOAT32
> +#define IF_FLOAT32(x)
> +#undef IF_FLOAT64
> +#define IF_FLOAT64(x)
> +#undef IF_FLOAT32X
> +#define IF_FLOAT32X(x)
> +#undef IF_FLOAT64X
> +#define IF_FLOAT64X(x)
> +#if !__HAVE_DISTINCT_FLOAT128
> +# undef IF_FLOAT128
> +# define IF_FLOAT128(x)
> +#endif
Ok.
> +#define TEST_STRTOD(FSUF, FTYPE, FTOSTR, LSUF, CSUF) \
> +static const struct \
> +{ \
> + const char *in; \
> + const char *out; \
> + FTYPE expected; \
> +} tests_strto ## FSUF[] = \
> + { \
> + { "000,,,e1", ",,,e1", 0.0 ## LSUF }, \
> + { "000e1", "", 0.0 ## LSUF }, \
> + { "000,1e1", ",1e1", 0.0 ## LSUF } \
> + }; \
I'm curious how this isn't locale-dependent, but it's not new code
so... it worked before? ok ;-)
> +static int \
> +test_strto ## FSUF (void) \
> +{ \
> + int status = 0; \
> + \
> + for (int i = 0; \
> + i < sizeof (tests_strto ## FSUF) / sizeof (tests_strto ## FSUF[0]); \
> + ++i) \
> + { \
> + char *ep; \
> + FTYPE r = __strto ## FSUF ## _internal (tests_strto ## FSUF[i].in, \
> + &ep, 1); \
> + \
> + if (strcmp (ep, tests_strto ## FSUF[i].out) != 0) \
> + { \
> + printf ("%d: got rest string \"%s\", expected \"%s\"\n", \
> + i, ep, tests_strto ## FSUF[i].out); \
> + status = 1; \
> + } \
> + \
> + if (r != tests_strto ## FSUF[i].expected) \
> + { \
> + char buf1[FSTRLENMAX], buf2[FSTRLENMAX]; \
> + FTOSTR (buf1, sizeof (buf1), "%g", r); \
> + FTOSTR (buf2, sizeof (buf2), "%g", \
> + tests_strto ## FSUF[i].expected); \
> + printf ("%d: got wrong results %s, expected %s\n", \
> + i, buf1, buf2); \
> + status = 1; \
> + } \
> + } \
> + \
> + return status; \
> +}
> +
Ok.
> +GEN_TEST_STRTOD_FOREACH (TEST_STRTOD)
Ok.
> static int
> do_test (void)
> @@ -26,29 +80,7 @@ do_test (void)
> return 1;
> }
>
> - int status = 0;
> -
> - for (int i = 0; i < NTESTS; ++i)
> - {
> - char *ep;
> - double r = __strtod_internal (tests[i].in, &ep, 1);
> -
> - if (strcmp (ep, tests[i].out) != 0)
> - {
> - printf ("%d: got rest string \"%s\", expected \"%s\"\n",
> - i, ep, tests[i].out);
> - status = 1;
> - }
> -
> - if (r != tests[i].expected)
> - {
> - printf ("%d: got wrong results %g, expected %g\n",
> - i, r, tests[i].expected);
> - status = 1;
> - }
> - }
> -
> - return status;
> + return STRTOD_TEST_FOREACH (test_strto);
> }
Ok.
> diff --git a/stdlib/tst-strtod4.c b/stdlib/tst-strtod4.c
> index 6cc4e843c7..d4e569e8fc 100644
> --- a/stdlib/tst-strtod4.c
> +++ b/stdlib/tst-strtod4.c
> @@ -3,22 +3,76 @@
> #include <stdlib.h>
> #include <string.h>
>
> +#include "tst-strtod.h"
> +
> +/* This tests internal interfaces, which are only defined for types
> + with distinct ABIs, so diable testing for types without distinct
> + ABIs. */
> +#undef IF_FLOAT32
> +#define IF_FLOAT32(x)
> +#undef IF_FLOAT64
> +#define IF_FLOAT64(x)
> +#undef IF_FLOAT32X
> +#define IF_FLOAT32X(x)
> +#undef IF_FLOAT64X
> +#define IF_FLOAT64X(x)
> +#if !__HAVE_DISTINCT_FLOAT128
> +# undef IF_FLOAT128
> +# define IF_FLOAT128(x)
> +#endif
> +
Ok.
> #define NNBSP "\xe2\x80\xaf"
>
> -static const struct
> -{
> - const char *in;
> - const char *out;
> - double expected;
> -} tests[] =
> - {
> - { "000"NNBSP"000"NNBSP"000", "", 0.0 },
> - { "1"NNBSP"000"NNBSP"000,5x", "x", 1000000.5 },
> - /* Bug 30964 */
> - { "10"NNBSP NNBSP"200", NNBSP NNBSP"200", 10.0 }
> - };
> -#define NTESTS (sizeof (tests) / sizeof (tests[0]))
> +#define TEST_STRTOD(FSUF, FTYPE, FTOSTR, LSUF, CSUF) \
> +static const struct \
> +{ \
> + const char *in; \
> + const char *out; \
> + FTYPE expected; \
> +} tests_strto ## FSUF[] = \
> + { \
> + { "000"NNBSP"000"NNBSP"000", "", 0.0 ## LSUF }, \
> + { "1"NNBSP"000"NNBSP"000,5x", "x", 1000000.5 ## LSUF }, \
> + /* Bug 30964 */ \
> + { "10"NNBSP NNBSP"200", NNBSP NNBSP"200", 10.0 ## LSUF } \
> + }; \
> + \
Ok.
> +static int \
> +test_strto ## FSUF (void) \
> +{ \
> + int status = 0; \
> + \
> + for (int i = 0; \
> + i < sizeof (tests_strto ## FSUF) / sizeof (tests_strto ## FSUF[0]); \
> + ++i) \
> + { \
> + char *ep; \
> + FTYPE r = __strto ## FSUF ## _internal (tests_strto ## FSUF[i].in, \
> + &ep, 1); \
> + \
> + if (strcmp (ep, tests_strto ## FSUF[i].out) != 0) \
> + { \
> + printf ("%d: got rest string \"%s\", expected \"%s\"\n", \
> + i, ep, tests_strto ## FSUF[i].out); \
> + status = 1; \
> + } \
> + \
> + if (r != tests_strto ## FSUF[i].expected) \
> + { \
> + char buf1[FSTRLENMAX], buf2[FSTRLENMAX]; \
> + FTOSTR (buf1, sizeof (buf1), "%g", r); \
> + FTOSTR (buf2, sizeof (buf2), "%g", \
> + tests_strto ## FSUF[i].expected); \
> + printf ("%d: got wrong results %s, expected %s\n", \
> + i, buf1, buf2); \
> + status = 1; \
> + } \
> + } \
> + \
> + return status; \
> +}
Ok.
> +GEN_TEST_STRTOD_FOREACH (TEST_STRTOD)
Ok.
> static int
> do_test (void)
> @@ -29,29 +83,7 @@ do_test (void)
> return 1;
> }
>
> - int status = 0;
> -
> - for (int i = 0; i < NTESTS; ++i)
> - {
> - char *ep;
> - double r = __strtod_internal (tests[i].in, &ep, 1);
> -
> - if (strcmp (ep, tests[i].out) != 0)
> - {
> - printf ("%d: got rest string \"%s\", expected \"%s\"\n",
> - i, ep, tests[i].out);
> - status = 1;
> - }
> -
> - if (r != tests[i].expected)
> - {
> - printf ("%d: got wrong results %g, expected %g\n",
> - i, r, tests[i].expected);
> - status = 1;
> - }
> - }
> -
> - return status;
> + return STRTOD_TEST_FOREACH (test_strto);
> }
Ok.
> diff --git a/stdlib/tst-strtod5i.c b/stdlib/tst-strtod5i.c
> index ee54e3404c..aaae486884 100644
> --- a/stdlib/tst-strtod5i.c
> +++ b/stdlib/tst-strtod5i.c
> @@ -16,52 +16,112 @@
> License along with the GNU C Library; if not, see
> <https://www.gnu.org/licenses/>. */
>
> +/* Defining _LIBC_TEST ensures long double math functions are
> + declared in the headers. */
> +#define _LIBC_TEST 1
> #include <locale.h>
> #include <stdio.h>
> #include <stdlib.h>
> #include <string.h>
> #include <math.h>
>
> +#include "tst-strtod.h"
> +
> +/* This tests internal interfaces, which are only defined for types
> + with distinct ABIs, so diable testing for types without distinct
> + ABIs. */
> +#undef IF_FLOAT32
> +#define IF_FLOAT32(x)
> +#undef IF_FLOAT64
> +#define IF_FLOAT64(x)
> +#undef IF_FLOAT32X
> +#define IF_FLOAT32X(x)
> +#undef IF_FLOAT64X
> +#define IF_FLOAT64X(x)
> +#if !__HAVE_DISTINCT_FLOAT128
> +# undef IF_FLOAT128
> +# define IF_FLOAT128(x)
> +#endif
> +
Ok.
> #define NNBSP "\xe2\x80\xaf"
>
> -static const struct
> -{
> - const char *in;
> - int group;
> - double expected;
> -} tests[] =
> - {
> - { "0", 0, 0.0 },
> - { "000", 0, 0.0 },
> - { "-0", 0, -0.0 },
> - { "-000", 0, -0.0 },
> - { "0,", 0, 0.0 },
> - { "-0,", 0, -0.0 },
> - { "0,0", 0, 0.0 },
> - { "-0,0", 0, -0.0 },
> - { "0e-10", 0, 0.0 },
> - { "-0e-10", 0, -0.0 },
> - { "0,e-10", 0, 0.0 },
> - { "-0,e-10", 0, -0.0 },
> - { "0,0e-10", 0, 0.0 },
> - { "-0,0e-10", 0, -0.0 },
> - { "0e-1000000", 0, 0.0 },
> - { "-0e-1000000", 0, -0.0 },
> - { "0,0e-1000000", 0, 0.0 },
> - { "-0,0e-1000000", 0, -0.0 },
> - { "0", 1, 0.0 },
> - { "000", 1, 0.0 },
> - { "-0", 1, -0.0 },
> - { "-000", 1, -0.0 },
> - { "0e-10", 1, 0.0 },
> - { "-0e-10", 1, -0.0 },
> - { "0e-1000000", 1, 0.0 },
> - { "-0e-1000000", 1, -0.0 },
> - { "000"NNBSP"000"NNBSP"000", 1, 0.0 },
> - { "-000"NNBSP"000"NNBSP"000", 1, -0.0 }
> - };
> -#define NTESTS (sizeof (tests) / sizeof (tests[0]))
> +#define TEST_STRTOD(FSUF, FTYPE, FTOSTR, LSUF, CSUF) \
> +static const struct \
> +{ \
> + const char *in; \
> + int group; \
> + FTYPE expected; \
> +} tests_strto ## FSUF[] = \
> + { \
> + { "0", 0, 0.0 ## LSUF }, \
> + { "000", 0, 0.0 ## LSUF }, \
> + { "-0", 0, -0.0 ## LSUF }, \
> + { "-000", 0, -0.0 ## LSUF }, \
> + { "0,", 0, 0.0 ## LSUF }, \
> + { "-0,", 0, -0.0 ## LSUF }, \
> + { "0,0", 0, 0.0 ## LSUF }, \
> + { "-0,0", 0, -0.0 ## LSUF }, \
> + { "0e-10", 0, 0.0 ## LSUF }, \
> + { "-0e-10", 0, -0.0 ## LSUF }, \
> + { "0,e-10", 0, 0.0 ## LSUF }, \
> + { "-0,e-10", 0, -0.0 ## LSUF }, \
> + { "0,0e-10", 0, 0.0 ## LSUF }, \
> + { "-0,0e-10", 0, -0.0 ## LSUF }, \
> + { "0e-1000000", 0, 0.0 ## LSUF }, \
> + { "-0e-1000000", 0, -0.0 ## LSUF }, \
> + { "0,0e-1000000", 0, 0.0 ## LSUF }, \
> + { "-0,0e-1000000", 0, -0.0 ## LSUF }, \
> + { "0", 1, 0.0 ## LSUF }, \
> + { "000", 1, 0.0 ## LSUF }, \
> + { "-0", 1, -0.0 ## LSUF }, \
> + { "-000", 1, -0.0 ## LSUF }, \
> + { "0e-10", 1, 0.0 ## LSUF }, \
> + { "-0e-10", 1, -0.0 ## LSUF }, \
> + { "0e-1000000", 1, 0.0 ## LSUF }, \
> + { "-0e-1000000", 1, -0.0 ## LSUF }, \
> + { "000"NNBSP"000"NNBSP"000", 1, 0.0 ## LSUF }, \
> + { "-000"NNBSP"000"NNBSP"000", 1, -0.0 ## LSUF } \
> + }; \
> + \
Ok.
> +static int \
> +test_strto ## FSUF (void) \
> +{ \
> + int status = 0; \
> + \
> + for (int i = 0; \
> + i < sizeof (tests_strto ## FSUF) / sizeof (tests_strto ## FSUF[0]); \
> + ++i) \
> + { \
> + char *ep; \
> + FTYPE r = __strto ## FSUF ## _internal (tests_strto ## FSUF[i].in, \
> + &ep, \
> + tests_strto ## FSUF[i].group); \
> + \
> + if (*ep != '\0') \
> + { \
> + printf ("%d: got rest string \"%s\", expected \"\"\n", i, ep); \
> + status = 1; \
> + } \
> + \
> + if (r != tests_strto ## FSUF[i].expected \
> + || (copysign ## CSUF (10.0 ## LSUF, r) \
> + != copysign ## CSUF (10.0 ## LSUF, \
> + tests_strto ## FSUF[i].expected))) \
> + { \
> + char buf1[FSTRLENMAX], buf2[FSTRLENMAX]; \
> + FTOSTR (buf1, sizeof (buf1), "%g", r); \
> + FTOSTR (buf2, sizeof (buf2), "%g", \
> + tests_strto ## FSUF[i].expected); \
> + printf ("%d: got wrong results %s, expected %s\n", \
> + i, buf1, buf2); \
> + status = 1; \
> + } \
> + } \
> + \
> + return status; \
> +}
>
> +GEN_TEST_STRTOD_FOREACH (TEST_STRTOD)
Ok.
> static int
> do_test (void)
> @@ -72,29 +132,7 @@ do_test (void)
> return 1;
> }
>
> - int status = 0;
> -
> - for (int i = 0; i < NTESTS; ++i)
> - {
> - char *ep;
> - double r = __strtod_internal (tests[i].in, &ep, tests[i].group);
> -
> - if (*ep != '\0')
> - {
> - printf ("%d: got rest string \"%s\", expected \"\"\n", i, ep);
> - status = 1;
> - }
> -
> - if (r != tests[i].expected
> - || copysign (10.0, r) != copysign (10.0, tests[i].expected))
> - {
> - printf ("%d: got wrong results %g, expected %g\n",
> - i, r, tests[i].expected);
> - status = 1;
> - }
> - }
> -
> - return status;
> + return STRTOD_TEST_FOREACH (test_strto);
> }
>
> #include <support/test-driver.c>
Ok.
More information about the Libc-alpha
mailing list