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 |
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 (format: "%s returned wrong result for value: " PRINTF_CONVERSION |
117 | ", ndigits: %d\n" , |
118 | name, value, ndigit); |
119 | printf (format: "Result was p: \"%s\", decpt: %d, sign: %d\n" , |
120 | res_p, res_decpt, res_sign); |
121 | printf (format: "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 |
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 (format: "%s returned wrong result for value: " PRINTF_CONVERSION |
133 | ", ndigits: %d\n" , |
134 | name, value, ndigit); |
135 | printf (format: "Result was buf: \"%s\", decpt: %d, sign: %d return value: %d\n" , |
136 | res_p, res_decpt, res_sign, res_return); |
137 | printf (format: "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 |
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, value: tests[no].value, ndigit: tests[no].ndigit, |
156 | exp_p: tests[no].result, exp_decpt: tests[no].decpt, |
157 | exp_sign: (tests[no].value < 0), |
158 | res_p: p, res_decpt: decpt, res_sign: sign); |
159 | ++no; |
160 | } |
161 | } |
162 | |
163 | static void |
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, value: tests[no].value, ndigit: tests[no].ndigit, |
180 | exp_p: tests[no].result, exp_decpt: tests[no].decpt, exp_sign: 0, |
181 | exp_return: (tests[no].value < 0), |
182 | res_p: buf, res_decpt: decpt, res_sign: sign, res_return: res); |
183 | ++no; |
184 | } |
185 | } |
186 | |
187 | static void |
188 | special (void) |
189 | { |
190 | int decpt, sign, res; |
191 | char *p; |
192 | char buf [1024]; |
193 | |
194 | p = ECVT (NAN, ndigit: 10, decpt: &decpt, sign: &sign); |
195 | if (sign != 0 || strcmp (p, "nan" ) != 0) |
196 | output_error (NAME (ECVT), NAN, ndigit: 10, exp_p: "nan" , exp_decpt: 0, exp_sign: 0, res_p: p, res_decpt: decpt, res_sign: sign); |
197 | |
198 | p = ECVT (INFINITY, ndigit: 10, decpt: &decpt, sign: &sign); |
199 | if (sign != 0 || strcmp (p, "inf" ) != 0) |
200 | output_error (NAME (ECVT), INFINITY, ndigit: 10, exp_p: "inf" , exp_decpt: 0, exp_sign: 0, res_p: p, res_decpt: decpt, res_sign: sign); |
201 | |
202 | /* Simply make sure these calls with large NDIGITs don't crash. */ |
203 | (void) ECVT (value: 123.456, ndigit: 10000, decpt: &decpt, sign: &sign); |
204 | (void) FCVT (value: 123.456, ndigit: 10000, decpt: &decpt, sign: &sign); |
205 | |
206 | /* Some tests for the reentrant functions. */ |
207 | /* Use a too small buffer. */ |
208 | res = ECVT_R (value: 123.456, ndigit: 10, decpt: &decpt, sign: &sign, buf: buf, len: 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 (value: 123.456, ndigit: 10, decpt: &decpt, sign: &sign, buf: buf, len: 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 |
224 | do_test (void) |
225 | { |
226 | test (tests: ecvt_tests, ECVT, NAME (ECVT)); |
227 | test (tests: fcvt_tests, FCVT, NAME (FCVT)); |
228 | test_r (tests: ecvt_tests, ECVT_R, NAME (ECVT_R)); |
229 | test_r (tests: fcvt_tests, FCVT_R, NAME (FCVT_R)); |
230 | special (); |
231 | |
232 | return 0; |
233 | } |
234 | |
235 | #include <support/test-driver.c> |
236 | |