[v9,3/3] Add tests for strfrom functions

Message ID 1476803310-2259-1-git-send-email-gftg@linux.vnet.ibm.com
State Superseded
Headers

Commit Message

Gabriel F T Gomes Oct. 18, 2016, 3:08 p.m. UTC
  From: Rajalakshmi Srinivasaraghavan <raji@linux.vnet.ibm.com>

Tested for x86_64, ppc64, ppc64le and s390.

-- 8< --
2016-10-18  Rajalakshmi Srinivasaraghavan  <raji@linux.vnet.ibm.com>

	* stdlib/Makefile (tests): Add tst-strfrom and tst-strfrom-locale.
	* stdlib/tst-strfrom.h: New file.
	* stdlib/tst-strfrom.c: New file.
	* stdlib/tst-strfrom-locale.c: New file.
---
 stdlib/Makefile             |   4 +-
 stdlib/tst-strfrom-locale.c | 115 ++++++++++++++++++++++++++++++++++++++++
 stdlib/tst-strfrom.c        | 116 ++++++++++++++++++++++++++++++++++++++++
 stdlib/tst-strfrom.h        | 126 ++++++++++++++++++++++++++++++++++++++++++++
 4 files changed, 360 insertions(+), 1 deletion(-)
 create mode 100644 stdlib/tst-strfrom-locale.c
 create mode 100644 stdlib/tst-strfrom.c
 create mode 100644 stdlib/tst-strfrom.h
  

Comments

Joseph Myers Oct. 20, 2016, 4:55 p.m. UTC | #1
On Tue, 18 Oct 2016, Gabriel F. T. Gomes wrote:

> +/* Hexadecimal tests.  */
> +static const struct htests htest[] = {
> +  {"%a", { "0x1,ffp+6", "0x3,fep+5", "0x7,fcp+4", "0xf,f8p+3" },
> +   {0x1.ffp+6, 0x1.ffp+6, 0x1.ffp+6}},
> +  {"%a", { "0x1,88p+4", "0x3,1p+3", "0x6,2p+2", "0xc,4p+1" },
> +   {0x1.88p+4, 0x1.88p+4, 0x1.88p+4}},
> +  {"%A", { "-0X1,88P+5", "-0X3,1P+4", "-0X6,2P+3", "-0XC,4P+2" },
> +   {-0x1.88p+5, -0x1.88p+5, -0x1.88p+5}},
> +  {"%a", { "0x1,44p+10", "0x2,88p+9", "0x5,1p+8", "0xa,2p+7"},
> +   {0x1.44p+10, 0x1.44p+10, 0x1.44p+10}},
> +  {"%a", { "0x1p-10", "0x2p-11", "0x4p-12", "0x8p-13"},
> +   {0x0.0040p+0, 0x0.0040p+0, 0x0.0040p+0}},
> +  {"%a", { "0x1,4p+3", "0x2,8p+2", "0x5p+1", "0xap+0"},
> +   {10.0, 10.0, 10.0}}
> +};

These still aren't type-generic.

> +/* Hexadecimal tests.  */
> +static const struct htests htest[] = {
> +  {"%a", { "0x1.ffp+6", "0x3.fep+5", "0x7.fcp+4", "0xf.f8p+3" },
> +   {0x1.ffp+6, 0x1.ffp+6, 0x1.ffp+6}},
> +  {"%a", { "0x1.88p+4", "0x3.1p+3", "0x6.2p+2", "0xc.4p+1" },
> +   {0x1.88p+4, 0x1.88p+4, 0x1.88p+4}},
> +  {"%A", { "-0X1.88P+5", "-0X3.1P+4", "-0X6.2P+3", "-0XC.4P+2" },
> +   {-0x1.88p+5, -0x1.88p+5, -0x1.88p+5}},
> +  {"%a", { "0x1.44p+10", "0x2.88p+9", "0x5.1p+8", "0xa.2p+7"},
> +   {0x1.44p+10, 0x1.44p+10, 0x1.44p+10}},
> +  {"%a", { "0x1p-10", "0x2p-11", "0x4p-12", "0x8p-13"},
> +   {0x0.0040p+0, 0x0.0040p+0, 0x0.0040p+0}},
> +  {"%a", { "0x1.4p+3", "0x2.8p+2", "0x5p+1", "0xap+0"},
> +   {10.0, 10.0, 10.0}}

Likewise.

> +#define TEST(s, fmt, size, rc, f, d, ld)	\
> +  {						\
> +    s, fmt, size, rc,  { ENTRY (f, d, ld) }	\
> +  }

You should have one argument to TEST that is the constant used for all 
types (and that then gets the appropriate suffix added to it for each 
type).  It should not be necessary to update the tables of tests at all 
when adding a new floating-point type (in general, the idea of making such 
tests type-generic is so that as little as possible needs to change to 
make them test a new type; ideally only the definitions of 
GEN_TEST_STRTOD_FOREACH and STRTOD_TEST_FOREACH).  The only obvious 
differences I see between the constants in your tests for different types 
is that some have more precision in the constants for double and long 
double, but it's fine to have the extra digits in the float constant even 
if they aren't significant to its value.

That is, the definition should look something like

{ s, fmt, size, rc, { GEN_TEST_STRTOD_FOREACH (SOMETHING, f) } }

where SOMETHING expands to concatenate its 7th argument (the 
floating-point number) with its 5th (the constant suffix) (followed by a 
comma).  Then I think you can get rid of the ENTRY and CHOOSE macros.

(tst-strtod-round is different because it involves data for every 
floating-point *format*, which then needs mapping to the supported types.)
  

Patch

diff --git a/stdlib/Makefile b/stdlib/Makefile
index 3cacb8b..3cce9d9 100644
--- a/stdlib/Makefile
+++ b/stdlib/Makefile
@@ -79,7 +79,7 @@  tests		:= tst-strtol tst-strtod testmb testrand testsort testdiv   \
 		   tst-setcontext3 tst-tls-atexit-nodelete		    \
 		   tst-strtol-locale tst-strtod-nan-locale tst-strfmon_l    \
 		   tst-quick_exit tst-thread-quick_exit tst-width	    \
-		   tst-width-stdint
+		   tst-width-stdint tst-strfrom tst-strfrom-locale
 tests-static	:= tst-secure-getenv
 ifeq ($(have-cxx-thread_local),yes)
 CFLAGS-tst-quick_exit.o = -std=c++11
@@ -158,6 +158,8 @@  $(objpfx)tst-strtod5.out: $(gen-locales)
 $(objpfx)tst-strtol-locale.out: $(gen-locales)
 $(objpfx)tst-strtod-nan-locale.out: $(gen-locales)
 $(objpfx)tst-strfmon_l.out: $(gen-locales)
+$(objpfx)tst-strfrom.out: $(gen-locales)
+$(objpfx)tst-strfrom-locale.out: $(gen-locales)
 endif
 
 # Testdir has to be named stdlib and needs to be writable
diff --git a/stdlib/tst-strfrom-locale.c b/stdlib/tst-strfrom-locale.c
new file mode 100644
index 0000000..e30f43e
--- /dev/null
+++ b/stdlib/tst-strfrom-locale.c
@@ -0,0 +1,115 @@ 
+/* Tests for strfromf, strfromd, strfroml functions.
+   Copyright (C) 2016 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <http://www.gnu.org/licenses/>.  */
+
+#include "tst-strfrom.h"
+
+static const struct test tests[] = {
+  TEST ("12,345000", "%f", 50, 9,
+	12.345, 12.345, 12.345),
+  TEST ("9,999", "%.3f", 50, 5,
+	9.999, 9.999, 9.999),
+  TEST ("0,125000", "%f", 50, 8,
+	.125, .125, .125),
+  TEST ("0,000000", "%f", 50, 8,
+	.0, .0, .0),
+  TEST ("0", "%g", 50, 1,
+	.0, .0, .0),
+  TEST ("9,900000", "%f", 50, 8,
+	9.9, 9.9, 9.9),
+  TEST ("9,1", "%.5f", 4, 7,
+	9.123456, 9.123456, 9.123456),
+  TEST ("9,91235", "%g", 50, 7,
+	9.9123456, 9.91234567812345678, 9.91234567812345678),
+  TEST ("79,8765", "%G", 50, 7,
+	79.876543, 79.8765432111, 79.8765432111),
+  TEST ("79,9", "%.3g", 50, 4,
+	79.876543, 79.8765432111, 79.8765432111),
+  TEST ("1,000000e+38", "%e", 50, 12,
+	1e+38, 1e+38, 1e+38),
+  TEST ("1,000000e+38", "%e", 50, 12,
+	1e38, 1e38, 1e38),
+  TEST ("-1,000000e-37", "%e", 50, 13,
+	-1e-37, -1e-37, -1e-37),
+  TEST ("1,000000e-37", "%e", 50, 12,
+	0.00000001e-29, 0.00000001e-29, 0.00000001e-29),
+  TEST ("1,000000e-37", "%e", 50, 12,
+	1.000000e-37, 1.000000e-37, 1.000000e-37),
+  TEST ("5,900000e-16", "%e", 50, 12,
+	5.9e-16, 5.9e-16, 5.9e-16),
+  TEST ("1,234500e+20", "%e", 50, 12,
+	12.345e19, 12.345e19, 12.345e19),
+  TEST ("1,000000e+05", "%e", 50, 12,
+	1e5, 1e5, 1e5),
+  TEST ("-NAN", "%G", 50, 4,
+	-NAN_, -NAN_, -NAN_),
+  TEST ("-inf", "%g", 50, 4,
+	-INF, -INF, -INF),
+  TEST ("inf", "%g", 50, 3,
+	INF, INF, INF)
+   };
+/* Tests with buffer size small.  */
+static const struct test stest[] = {
+  TEST ("1234", "%g", 5, 7,
+	12345.345, 12345.345, 12345.345),
+  TEST ("0,12", "%f", 5, 8,
+	.125, .125, .125),
+  TEST ("9,99", "%.3f", 5, 5,
+	9.999, 9.999, 9.999),
+  TEST ("100", "%g", 5, 3,
+	1e2, 1e2, 1e2)
+};
+/* Hexadecimal tests.  */
+static const struct htests htest[] = {
+  {"%a", { "0x1,ffp+6", "0x3,fep+5", "0x7,fcp+4", "0xf,f8p+3" },
+   {0x1.ffp+6, 0x1.ffp+6, 0x1.ffp+6}},
+  {"%a", { "0x1,88p+4", "0x3,1p+3", "0x6,2p+2", "0xc,4p+1" },
+   {0x1.88p+4, 0x1.88p+4, 0x1.88p+4}},
+  {"%A", { "-0X1,88P+5", "-0X3,1P+4", "-0X6,2P+3", "-0XC,4P+2" },
+   {-0x1.88p+5, -0x1.88p+5, -0x1.88p+5}},
+  {"%a", { "0x1,44p+10", "0x2,88p+9", "0x5,1p+8", "0xa,2p+7"},
+   {0x1.44p+10, 0x1.44p+10, 0x1.44p+10}},
+  {"%a", { "0x1p-10", "0x2p-11", "0x4p-12", "0x8p-13"},
+   {0x0.0040p+0, 0x0.0040p+0, 0x0.0040p+0}},
+  {"%a", { "0x1,4p+3", "0x2,8p+2", "0x5p+1", "0xap+0"},
+   {10.0, 10.0, 10.0}}
+};
+GEN_TEST_STRTOD_FOREACH (TEST_STRFROM)
+
+static int
+test_locale (const char *locale)
+{
+  printf ("Testing in locale: %s\n", locale);
+  if (setlocale (LC_ALL, locale) == NULL)
+    {
+      printf ("Cannot set locale %s\n", locale);
+    }
+  return STRTOD_TEST_FOREACH (test_);
+}
+
+static int
+do_test (void)
+{
+  int result = 0;
+  result += test_locale ("de_DE.UTF-8");
+  result += test_locale ("tr_TR.ISO-8859-9");
+  result += test_locale ("tr_TR.UTF-8");
+  return result;
+}
+
+#define TEST_FUNCTION do_test ()
+#include "../test-skeleton.c"
diff --git a/stdlib/tst-strfrom.c b/stdlib/tst-strfrom.c
new file mode 100644
index 0000000..686bede
--- /dev/null
+++ b/stdlib/tst-strfrom.c
@@ -0,0 +1,116 @@ 
+/* Tests for strfromf, strfromd, strfroml functions.
+   Copyright (C) 2016 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <http://www.gnu.org/licenses/>.  */
+
+#include "tst-strfrom.h"
+
+static const struct test tests[] = {
+  TEST ("12.345000", "%f", 50, 9,
+	12.345, 12.345, 12.345),
+  TEST ("9.999", "%.3f", 50, 5,
+	9.999, 9.999, 9.999),
+  TEST ("0.125000", "%f", 50, 8,
+	.125, .125, .125),
+  TEST ("0.000000", "%f", 50, 8,
+	.0, .0, .0),
+  TEST ("0", "%g", 50, 1,
+	.0, .0, .0),
+  TEST ("9.900000", "%f", 50, 8,
+	9.9, 9.9, 9.9),
+  TEST ("9.1", "%.5f", 4, 7,
+	9.123456, 9.123456, 9.123456),
+  TEST ("9.91235", "%g", 50, 7,
+	9.9123456, 9.91234567812345678, 9.91234567812345678),
+  TEST ("79.8765", "%G", 50, 7,
+	79.876543, 79.8765432111, 79.8765432111),
+  TEST ("79.9", "%.3g", 50, 4,
+	79.876543, 79.8765432111, 79.8765432111),
+  TEST ("1.000000e+38", "%e", 50, 12,
+	1e+38, 1e+38, 1e+38),
+  TEST ("1.000000e+38", "%e", 50, 12,
+	1e38, 1e38, 1e38),
+  TEST ("-1.000000e-37", "%e", 50, 13,
+	-1e-37, -1e-37, -1e-37),
+  TEST ("1.000000e-37", "%e", 50, 12,
+	0.00000001e-29, 0.00000001e-29, 0.00000001e-29),
+  TEST ("1.000000e-37", "%e", 50, 12,
+	1.000000e-37, 1.000000e-37, 1.000000e-37),
+  TEST ("5.900000e-16", "%e", 50, 12,
+	5.9e-16, 5.9e-16, 5.9e-16),
+  TEST ("1.234500e+20", "%e", 50, 12,
+	12.345e19, 12.345e19, 12.345e19),
+  TEST ("1.000000e+05", "%e", 50, 12,
+	1e5, 1e5, 1e5),
+  TEST ("-NAN", "%G", 50, 4,
+	-NAN_, -NAN_, -NAN_),
+  TEST ("-inf", "%g", 50, 4,
+	-INF, -INF, -INF),
+  TEST ("inf", "%g", 50, 3,
+	INF, INF, INF)
+   };
+
+/* Tests with buffer size small.  */
+static const struct test stest[] = {
+  TEST ("1234", "%g", 5, 7,
+	12345.345, 12345.345, 12345.345),
+  TEST ("0.12", "%f", 5, 8,
+	.125, .125, .125),
+  TEST ("9.99", "%.3f", 5, 5,
+	9.999, 9.999, 9.999),
+  TEST ("100", "%g", 5, 3,
+	1e2, 1e2, 1e2)
+};
+/* Hexadecimal tests.  */
+static const struct htests htest[] = {
+  {"%a", { "0x1.ffp+6", "0x3.fep+5", "0x7.fcp+4", "0xf.f8p+3" },
+   {0x1.ffp+6, 0x1.ffp+6, 0x1.ffp+6}},
+  {"%a", { "0x1.88p+4", "0x3.1p+3", "0x6.2p+2", "0xc.4p+1" },
+   {0x1.88p+4, 0x1.88p+4, 0x1.88p+4}},
+  {"%A", { "-0X1.88P+5", "-0X3.1P+4", "-0X6.2P+3", "-0XC.4P+2" },
+   {-0x1.88p+5, -0x1.88p+5, -0x1.88p+5}},
+  {"%a", { "0x1.44p+10", "0x2.88p+9", "0x5.1p+8", "0xa.2p+7"},
+   {0x1.44p+10, 0x1.44p+10, 0x1.44p+10}},
+  {"%a", { "0x1p-10", "0x2p-11", "0x4p-12", "0x8p-13"},
+   {0x0.0040p+0, 0x0.0040p+0, 0x0.0040p+0}},
+  {"%a", { "0x1.4p+3", "0x2.8p+2", "0x5p+1", "0xap+0"},
+   {10.0, 10.0, 10.0}}
+};
+GEN_TEST_STRTOD_FOREACH (TEST_STRFROM)
+
+static int
+test_locale (const char *locale)
+{
+  printf ("Testing in locale: %s\n", locale);
+  if (setlocale (LC_ALL, locale) == NULL)
+    {
+      printf ("Cannot set locale %s\n", locale);
+    }
+  return STRTOD_TEST_FOREACH (test_);
+}
+
+static int
+do_test (void)
+{
+  int result = 0;
+  result += test_locale ("C");
+  result += test_locale ("en_US.ISO-8859-1");
+  result += test_locale ("en_US.UTF-8");
+  return result;
+}
+
+#define TEST_FUNCTION do_test ()
+#include "../test-skeleton.c"
diff --git a/stdlib/tst-strfrom.h b/stdlib/tst-strfrom.h
new file mode 100644
index 0000000..f0acd94
--- /dev/null
+++ b/stdlib/tst-strfrom.h
@@ -0,0 +1,126 @@ 
+/* Tests for strfromf, strfromd, strfroml functions.
+   Copyright (C) 2016 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <http://www.gnu.org/licenses/>.  */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <float.h>
+#include <math.h>
+#include <locale.h>
+
+#include "tst-strtod.h"
+
+#define _CONCAT(a, b) a ## b
+#define CONCAT(a, b) _CONCAT (a, b)
+
+/* Generator to create an FTYPE member variabled named FSUF
+ *    used to populate struct member variables.  */
+#define FTYPE_MEMBER(FSUF, FTYPE, FTOSTR, LSUF, CSUF)  \
+       FTYPE FSUF;
+
+#define STRUCT_FOREACH_FLOAT_FTYPE GEN_TEST_STRTOD_FOREACH (FTYPE_MEMBER)
+
+/* Add type specific choosing macros below.  */
+#define CHOOSE_f(f,...) f
+#define CHOOSE_d(f,d,...) d
+#define CHOOSE_ld(f,d,ld...) ld
+
+/* Selector for expected result field of a given type.  */
+#define _ENTRY(FSUF, FTYPE, FTOSTR, LSUF, CSUF, ...)  \
+  CONCAT (CHOOSE_ ## FSUF (__VA_ARGS__), LSUF),
+#define ENTRY(...) \
+  GEN_TEST_STRTOD_FOREACH (_ENTRY, __VA_ARGS__)
+
+/* This is hacky way around the seemingly unavoidable macro
+ * expansion of the INFINITY or HUGE_VAL like macros in the
+ * above.  It is assumed the compiler will implicitly convert
+ * the infinity correctly.  */
+#define INF INFINITY + 0.0
+#define NAN_ NAN + 0.0
+
+struct test_input
+{
+  STRUCT_FOREACH_FLOAT_FTYPE
+};
+struct test {
+  const char *s;
+  const char *fmt;
+  int size;
+  int rc;
+  struct test_input t;
+};
+
+#define TEST(s, fmt, size, rc, f, d, ld)	\
+  {						\
+    s, fmt, size, rc,  { ENTRY (f, d, ld) }	\
+  }
+/* Hexadecimal tests.  */
+struct htests
+{
+  const char *fmt;
+  const char *exp[4];
+  struct test_input t;
+};
+
+#define TEST_STRFROM(FSUF, FTYPE, FTOSTR, LSUF, CSUF)			\
+static int								\
+test_ ## FSUF (void)							\
+{									\
+  char buf[50], sbuf[5];						\
+  int status = 0;							\
+  int i, rc = 0, rc1 = 0;						\
+  for (i = 0; i < sizeof (stest) / sizeof (stest[0]); i++)		\
+    {									\
+      rc = FTOSTR (sbuf, stest[i].size, stest[i].fmt, stest[i].t.FSUF);	\
+      rc1 = (strcmp (sbuf, stest[i].s) != 0) || (rc != stest[i].rc);	\
+      if (rc1)								\
+	{								\
+	  printf (#FTOSTR ": got %s (%d), expected %s (%d)\n",		\
+		  sbuf, rc, stest[i].s, stest[i].rc);			\
+	  status++;							\
+	}								\
+    }									\
+  for (i = 0; i < sizeof (tests) / sizeof (tests[0]); i++)		\
+    {									\
+      rc = FTOSTR (buf, tests[i].size, tests[i].fmt, tests[i].t.FSUF);	\
+      rc1 = (strcmp (buf, tests[i].s) != 0) || (rc != tests[i].rc);	\
+      if (rc1)								\
+	{								\
+	  printf (#FTOSTR ": got %s (%d), expected %s (%d)\n",		\
+		  buf, rc, tests[i].s, tests[i].rc);			\
+	  status++;							\
+	}								\
+    }									\
+  for (i = 0; i < sizeof (htest) / sizeof (htest[0]); i++)		\
+    {									\
+      rc = FTOSTR (buf, 50, htest[i].fmt, htest[i].t.FSUF);		\
+      if (strcmp (buf, htest[i].exp[0]) == 0 ||				\
+	  strcmp (buf, htest[i].exp[1]) == 0 ||				\
+	  strcmp (buf, htest[i].exp[2]) == 0 ||				\
+	  strcmp (buf, htest[i].exp[3]) == 0)				\
+	continue;							\
+      else								\
+	{								\
+	  printf (#FTOSTR ": got %s (%d), expected %s or %s or %s "	\
+		  "or %s\n", buf, rc, htest[i].exp[0], htest[i].exp[1],	\
+		  htest[i].exp[2], htest[i].exp[3]);			\
+	  status++;							\
+	}								\
+    }									\
+  return status;							\
+}