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
51typedef struct
52{
53 FLOAT value;
54 int ndigit;
55 int decpt;
56 char result[30];
57} testcase;
58
59typedef char * ((*efcvt_func) (FLOAT, int, int *, int *));
60
61typedef int ((*efcvt_r_func) (FLOAT, int, int *, int *, char *, size_t));
62
63
64static 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
88static 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
111static void
112output_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
127static void
128output_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
142static void
143test (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
163static void
164test_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
187static void
188special (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
223static int
224do_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

source code of glibc/misc/tst-efgcvt-template.c