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