[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