1 /* Copyright (C) 1998-2022 Free Software Foundation, Inc.
2    This file is part of the GNU C Library.
3 
4    The GNU C Library is free software; you can redistribute it and/or
5    modify it under the terms of the GNU Lesser General Public
6    License as published by the Free Software Foundation; either
7    version 2.1 of the License, or (at your option) any later version.
8 
9    The GNU C Library is distributed in the hope that it will be useful,
10    but WITHOUT ANY WARRANTY; without even the implied warranty of
11    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12    Lesser General Public License for more details.
13 
14    You should have received a copy of the GNU Lesser General Public
15    License along with the GNU C Library; if not, see
16    <https://www.gnu.org/licenses/>.  */
17 
18 /* This template provides testing for the *cvt family of functions,
19    which deal with double or long double types.  In order to use the
20    template, the following macros must be defined before inclusion of
21    this template:
22 
23      FLOAT: The floating-point type, i.e. double or long double.
24 
25      ECVT: Appropriate *ecvt function for FLOAT, i.e. ecvt or qecvt.
26      FCVT: Likewise for *fcvt, i.e. fcvt or qfcvt.
27      ECVT_R: Likewise for *ecvt_r, i.e. ecvt_r or qecvt_r.
28      FCVT_R: Likewise for *fcvt_r, i.e. fcvt_r or qfcvt_r.
29 
30      PRINTF_CONVERSION: The appropriate printf conversion specifier with
31      length modifier for FLOAT, i.e. "%f" or "%Lf".
32 
33      EXTRA_ECVT_TESTS: Additional tests for the ecvt or qecvt function
34      that are only relevant to a particular floating-point type and
35      cannot be represented generically.  */
36 
37 #ifndef _GNU_SOURCE
38 # define _GNU_SOURCE	1
39 #endif
40 
41 #include <math.h>
42 #include <stdio.h>
43 #include <stdlib.h>
44 #include <string.h>
45 
46 #include <support/check.h>
47 
48 #define NAME(x) NAMEX(x)
49 #define NAMEX(x) #x
50 
51 typedef struct
52 {
53   FLOAT value;
54   int ndigit;
55   int decpt;
56   char result[30];
57 } testcase;
58 
59 typedef char * ((*efcvt_func) (FLOAT, int, int *, int *));
60 
61 typedef int ((*efcvt_r_func) (FLOAT, int, int *, int *, char *, size_t));
62 
63 
64 static testcase ecvt_tests[] =
65 {
66   { 0.0, 0, 1, "" },
67   { 10.0, 0, 2, "" },
68   { 10.0, 1, 2, "1" },
69   { 10.0, 5, 2, "10000" },
70   { -12.0, 5, 2, "12000" },
71   { 0.2, 4, 0, "2000" },
72   { 0.02, 4, -1, "2000" },
73   { 5.5, 1, 1, "6" },
74   { 1.0, -1, 1, "" },
75   { 0.01, 2, -1, "10" },
76   { 100.0, -2, 3, "" },
77   { 100.0, -5, 3, "" },
78   { 100.0, -4, 3, "" },
79   { 100.01, -4, 3, "" },
80   { 123.01, -4, 3, "" },
81   { 126.71, -4, 3, "" },
82   { 0.0, 4, 1, "0000" },
83   EXTRA_ECVT_TESTS
84   /* -1.0 is end marker.  */
85   { -1.0, 0, 0, "" }
86 };
87 
88 static testcase fcvt_tests[] =
89 {
90   { 0.0, 0, 1, "0" },
91   { 10.0, 0, 2, "10" },
92   { 10.0, 1, 2, "100" },
93   { 10.0, 4, 2, "100000" },
94   { -12.0, 5, 2, "1200000" },
95   { 0.2, 4, 0, "2000" },
96   { 0.02, 4, -1, "200" },
97   { 5.5, 1, 1, "55" },
98   { 5.5, 0, 1, "6" },
99   { 0.01, 2, -1, "1" },
100   { 100.0, -2, 3, "100" },
101   { 100.0, -5, 3, "100" },
102   { 100.0, -4, 3, "100" },
103   { 100.01, -4, 3, "100" },
104   { 123.01, -4, 3, "100" },
105   { 126.71, -4, 3, "100" },
106   { 322.5, 16, 3, "3225000000000000000" },
107   /* -1.0 is end marker.  */
108   { -1.0, 0, 0, "" }
109 };
110 
111 static void
output_error(const char * name,FLOAT value,int ndigit,const char * exp_p,int exp_decpt,int exp_sign,char * res_p,int res_decpt,int res_sign)112 output_error (const char *name, FLOAT value, int ndigit,
113 	      const char *exp_p, int exp_decpt, int exp_sign,
114 	      char *res_p, int res_decpt, int res_sign)
115 {
116   printf ("%s returned wrong result for value: " PRINTF_CONVERSION
117 	  ", ndigits: %d\n",
118 	  name, value, ndigit);
119   printf ("Result was p: \"%s\", decpt: %d, sign: %d\n",
120 	  res_p, res_decpt, res_sign);
121   printf ("Should be  p: \"%s\", decpt: %d, sign: %d\n",
122 	  exp_p, exp_decpt, exp_sign);
123   support_record_failure ();
124 }
125 
126 
127 static void
output_r_error(const char * name,FLOAT value,int ndigit,const char * exp_p,int exp_decpt,int exp_sign,int exp_return,char * res_p,int res_decpt,int res_sign,int res_return)128 output_r_error (const char *name, FLOAT value, int ndigit,
129 		const char *exp_p, int exp_decpt, int exp_sign, int exp_return,
130 		char *res_p, int res_decpt, int res_sign, int res_return)
131 {
132   printf ("%s returned wrong result for value: " PRINTF_CONVERSION
133 	  ", ndigits: %d\n",
134 	  name, value, ndigit);
135   printf ("Result was buf: \"%s\", decpt: %d, sign: %d return value: %d\n",
136 	  res_p, res_decpt, res_sign, res_return);
137   printf ("Should be  buf: \"%s\", decpt: %d, sign: %d\n",
138 	  exp_p, exp_decpt, exp_sign);
139   support_record_failure ();
140 }
141 
142 static void
test(testcase tests[],efcvt_func efcvt,const char * name)143 test (testcase tests[], efcvt_func efcvt, const char *name)
144 {
145   int no = 0;
146   int decpt, sign;
147   char *p;
148 
149   while (tests[no].value != -1.0)
150     {
151       p = efcvt (tests[no].value, tests[no].ndigit, &decpt, &sign);
152       if (decpt != tests[no].decpt
153 	  || sign != (tests[no].value < 0)
154 	  || strcmp (p, tests[no].result) != 0)
155 	output_error (name, tests[no].value, tests[no].ndigit,
156 		      tests[no].result, tests[no].decpt,
157 		      (tests[no].value < 0),
158 		      p, decpt, sign);
159       ++no;
160     }
161 }
162 
163 static void
test_r(testcase tests[],efcvt_r_func efcvt_r,const char * name)164 test_r (testcase tests[], efcvt_r_func efcvt_r, const char *name)
165 {
166   int no = 0;
167   int decpt, sign, res;
168   char buf [1024];
169 
170 
171   while (tests[no].value != -1.0)
172     {
173       res = efcvt_r (tests[no].value, tests[no].ndigit, &decpt, &sign,
174 		     buf, sizeof (buf));
175       if (res != 0
176 	  || decpt != tests[no].decpt
177 	  || sign != (tests[no].value < 0)
178 	  || strcmp (buf, tests[no].result) != 0)
179 	output_r_error (name, tests[no].value, tests[no].ndigit,
180 			tests[no].result, tests[no].decpt, 0,
181 			(tests[no].value < 0),
182 			buf, decpt, sign, res);
183       ++no;
184     }
185 }
186 
187 static void
special(void)188 special (void)
189 {
190   int decpt, sign, res;
191   char *p;
192   char buf [1024];
193 
194   p = ECVT (NAN, 10, &decpt, &sign);
195   if (sign != 0 || strcmp (p, "nan") != 0)
196     output_error (NAME (ECVT), NAN, 10, "nan", 0, 0, p, decpt, sign);
197 
198   p = ECVT (INFINITY, 10, &decpt, &sign);
199   if (sign != 0 || strcmp (p, "inf") != 0)
200     output_error (NAME (ECVT), INFINITY, 10, "inf", 0, 0, p, decpt, sign);
201 
202   /* Simply make sure these calls with large NDIGITs don't crash.  */
203   (void) ECVT (123.456, 10000, &decpt, &sign);
204   (void) FCVT (123.456, 10000, &decpt, &sign);
205 
206   /* Some tests for the reentrant functions.  */
207   /* Use a too small buffer.  */
208   res = ECVT_R (123.456, 10, &decpt, &sign, buf, 1);
209   if (res == 0)
210     {
211       printf (NAME (ECVT_R) " with a too small buffer was succesful.\n");
212       support_record_failure ();
213     }
214   res = FCVT_R (123.456, 10, &decpt, &sign, buf, 1);
215   if (res == 0)
216     {
217       printf (NAME (FCVT_R) " with a too small buffer was succesful.\n");
218       support_record_failure ();
219     }
220 }
221 
222 
223 static int
do_test(void)224 do_test (void)
225 {
226   test (ecvt_tests, ECVT, NAME (ECVT));
227   test (fcvt_tests, FCVT, NAME (FCVT));
228   test_r (ecvt_tests, ECVT_R, NAME (ECVT_R));
229   test_r (fcvt_tests, FCVT_R, NAME (FCVT_R));
230   special ();
231 
232   return 0;
233 }
234 
235 #include <support/test-driver.c>
236