1//===-- A template class for testing strfrom functions ----------*- C++ -*-===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8
9#include "src/__support/CPP/type_traits.h"
10#include "src/__support/FPUtil/FPBits.h"
11#include "test/UnitTest/Test.h"
12
13#define ASSERT_STREQ_LEN(actual_written, actual_str, expected_str) \
14 EXPECT_EQ(actual_written, static_cast<int>(sizeof(expected_str) - 1)); \
15 EXPECT_STREQ(actual_str, expected_str);
16
17template <typename InputT>
18class StrfromTest : public LIBC_NAMESPACE::testing::Test {
19
20 static constexpr bool is_single_prec =
21 LIBC_NAMESPACE::cpp::is_same<InputT, float>::value;
22 static constexpr bool is_double_prec =
23 LIBC_NAMESPACE::cpp::is_same<InputT, double>::value;
24
25 using FunctionT = int (*)(char *, size_t, const char *, InputT fp);
26
27public:
28 void floatDecimalFormat(FunctionT func) {
29 if constexpr (is_single_prec)
30 floatDecimalSinglePrec(func);
31 else if constexpr (is_double_prec)
32 floatDecimalDoublePrec(func);
33 else
34 floatDecimalLongDoublePrec(func);
35 }
36
37 void floatHexExpFormat(FunctionT func) {
38 if constexpr (is_single_prec)
39 floatHexExpSinglePrec(func);
40 else if constexpr (is_double_prec)
41 floatHexExpDoublePrec(func);
42 else
43 floatHexExpLongDoublePrec(func);
44 }
45
46 void floatDecimalExpFormat(FunctionT func) {
47 if constexpr (is_single_prec)
48 floatDecimalExpSinglePrec(func);
49 else if constexpr (is_double_prec)
50 floatDecimalExpDoublePrec(func);
51 else
52 floatDecimalExpLongDoublePrec(func);
53 }
54
55 void floatDecimalAutoFormat(FunctionT func) {
56 if constexpr (is_single_prec)
57 floatDecimalAutoSinglePrec(func);
58 else if constexpr (is_double_prec)
59 floatDecimalAutoDoublePrec(func);
60 else
61 floatDecimalAutoLongDoublePrec(func);
62 }
63
64 void improperFormatString(FunctionT func) {
65 char buff[100];
66 int written;
67 const bool is_long_double = !is_single_prec && !is_double_prec;
68
69 written = func(buff, 37, "A simple string with no conversions.", 1.0);
70 ASSERT_STREQ_LEN(written, buff, "A simple string with no conversions.");
71
72 written =
73 func(buff, 37,
74 "%A simple string with one conversion, should overwrite.", 1.0);
75 if (is_long_double) {
76#if defined(LIBC_TYPES_LONG_DOUBLE_IS_X86_FLOAT80)
77 ASSERT_STREQ_LEN(written, buff, "0X8P-3");
78#elif defined(LIBC_TYPES_LONG_DOUBLE_IS_FLOAT64)
79 ASSERT_STREQ_LEN(written, buff, "0X1P+0");
80#elif defined(LIBC_TYPES_LONG_DOUBLE_IS_FLOAT128)
81 ASSERT_STREQ_LEN(written, buff, "0X1P+0");
82#endif
83 } else {
84 // not long double
85 ASSERT_STREQ_LEN(written, buff, "0X1P+0");
86 }
87 written = func(buff, 74,
88 "A simple string with one conversion in %A "
89 "between, writes string as it is",
90 1.0);
91 ASSERT_STREQ_LEN(written, buff,
92 "A simple string with one conversion in %A between, "
93 "writes string as it is");
94
95 written = func(buff, 36, "A simple string with one conversion", 1.0);
96 ASSERT_STREQ_LEN(written, buff, "A simple string with one conversion");
97
98 written = func(buff, 20, "%1f", static_cast<InputT>(1234567890.0));
99 ASSERT_STREQ_LEN(written, buff, "%1f");
100 }
101
102 void insufficentBufsize(FunctionT func) {
103 char buff[20];
104 int written;
105
106 written = func(buff, 5, "%f", static_cast<InputT>(1234567890.0));
107 EXPECT_EQ(written, 17);
108 ASSERT_STREQ(buff, "1234");
109
110 written = func(buff, 5, "%.5f", static_cast<InputT>(1.05));
111 EXPECT_EQ(written, 7);
112 ASSERT_STREQ(buff, "1.05");
113
114 written = func(buff, 0, "%g", static_cast<InputT>(1.0));
115 EXPECT_EQ(written, 1);
116 ASSERT_STREQ(buff, "1.05"); // Make sure that buff has not changed
117 }
118
119 void infNanValues(FunctionT func) {
120 if constexpr (is_double_prec)
121 doublePrecInfNan(func);
122 else if constexpr (!is_single_prec)
123 longDoublePrecInfNan(func);
124 }
125
126 void floatDecimalSinglePrec(FunctionT func) {
127 char buff[70];
128 int written;
129
130 written = func(buff, 16, "%f", 1.0f);
131 ASSERT_STREQ_LEN(written, buff, "1.000000");
132
133 written = func(buff, 20, "%f", 1234567890.0f);
134 ASSERT_STREQ_LEN(written, buff, "1234567936.000000");
135
136 written = func(buff, 67, "%.3f", 1.0f);
137 ASSERT_STREQ_LEN(written, buff, "1.000");
138 }
139
140 void floatDecimalDoublePrec(FunctionT func) {
141 char buff[500];
142 int written;
143
144 written = func(buff, 99, "%f", 1.0);
145 ASSERT_STREQ_LEN(written, buff, "1.000000");
146
147 written = func(buff, 99, "%F", -1.0);
148 ASSERT_STREQ_LEN(written, buff, "-1.000000");
149
150 written = func(buff, 99, "%f", -1.234567);
151 ASSERT_STREQ_LEN(written, buff, "-1.234567");
152
153 written = func(buff, 99, "%f", 0.0);
154 ASSERT_STREQ_LEN(written, buff, "0.000000");
155
156 written = func(buff, 99, "%f", 1.5);
157 ASSERT_STREQ_LEN(written, buff, "1.500000");
158
159// Dyadic float is only accurate to ~50 digits, so skip this 300 digit test.
160// TODO: Create way to test just the first ~50 digits of a number.
161#ifndef LIBC_COPT_FLOAT_TO_STR_REDUCED_PRECISION
162 written = func(buff, 499, "%f", 1e300);
163 ASSERT_STREQ_LEN(written, buff,
164 "100000000000000005250476025520442024870446858110815915491"
165 "585411551180245"
166 "798890819578637137508044786404370444383288387817694252323"
167 "536043057564479"
168 "218478670698284838720092657580373783023379478809005936895"
169 "323497079994508"
170 "111903896764088007465274278014249457925878882005684283811"
171 "566947219638686"
172 "5459400540160.000000");
173#endif // DLIBC_COPT_FLOAT_TO_STR_REDUCED_PRECISION
174
175 written = func(buff, 99, "%f", 0.1);
176 ASSERT_STREQ_LEN(written, buff, "0.100000");
177
178 written = func(buff, 99, "%f", 1234567890123456789.0);
179 ASSERT_STREQ_LEN(written, buff, "1234567890123456768.000000");
180
181 written = func(buff, 99, "%f", 9999999999999.99);
182 ASSERT_STREQ_LEN(written, buff, "9999999999999.990234");
183
184 written = func(buff, 99, "%f", 0.1);
185 ASSERT_STREQ_LEN(written, buff, "0.100000");
186
187 written = func(buff, 99, "%f", 1234567890123456789.0);
188 ASSERT_STREQ_LEN(written, buff, "1234567890123456768.000000");
189
190 written = func(buff, 99, "%f", 9999999999999.99);
191 ASSERT_STREQ_LEN(written, buff, "9999999999999.990234");
192
193 // Precision Tests
194 written = func(buff, 100, "%.2f", 9999999999999.99);
195 ASSERT_STREQ_LEN(written, buff, "9999999999999.99");
196
197 written = func(buff, 100, "%.1f", 9999999999999.99);
198 ASSERT_STREQ_LEN(written, buff, "10000000000000.0");
199
200 written = func(buff, 100, "%.5f", 1.25);
201 ASSERT_STREQ_LEN(written, buff, "1.25000");
202
203 written = func(buff, 100, "%.0f", 1.25);
204 ASSERT_STREQ_LEN(written, buff, "1");
205
206 written = func(buff, 100, "%.20f", 1.234e-10);
207 ASSERT_STREQ_LEN(written, buff, "0.00000000012340000000");
208 }
209
210 void floatDecimalLongDoublePrec(FunctionT func) {
211 char buff[45];
212 int written;
213
214 written = func(buff, 40, "%f", 1.0L);
215 ASSERT_STREQ_LEN(written, buff, "1.000000");
216
217 written = func(buff, 10, "%.f", -2.5L);
218 ASSERT_STREQ_LEN(written, buff, "-2");
219 }
220
221 void floatHexExpSinglePrec(FunctionT func) {
222 char buff[25];
223 int written;
224
225 written = func(buff, 0, "%a", 1234567890.0f);
226 EXPECT_EQ(written, 14);
227
228 written = func(buff, 20, "%a", 1234567890.0f);
229 EXPECT_EQ(written, 14);
230 ASSERT_STREQ(buff, "0x1.26580cp+30");
231
232 written = func(buff, 20, "%A", 1234567890.0f);
233 EXPECT_EQ(written, 14);
234 ASSERT_STREQ(buff, "0X1.26580CP+30");
235 }
236
237 void floatHexExpDoublePrec(FunctionT func) {
238 char buff[60];
239 int written;
240
241 written = func(buff, 10, "%a", 1.0);
242 ASSERT_STREQ_LEN(written, buff, "0x1p+0");
243
244 written = func(buff, 10, "%A", -1.0);
245 ASSERT_STREQ_LEN(written, buff, "-0X1P+0");
246
247 written = func(buff, 30, "%a", -0x1.abcdef12345p0);
248 ASSERT_STREQ_LEN(written, buff, "-0x1.abcdef12345p+0");
249
250 written = func(buff, 50, "%A", 0x1.abcdef12345p0);
251 ASSERT_STREQ_LEN(written, buff, "0X1.ABCDEF12345P+0");
252
253 written = func(buff, 10, "%a", 0.0);
254 ASSERT_STREQ_LEN(written, buff, "0x0p+0");
255
256 written = func(buff, 40, "%a", 1.0e100);
257 ASSERT_STREQ_LEN(written, buff, "0x1.249ad2594c37dp+332");
258
259 written = func(buff, 30, "%a", 0.1);
260 ASSERT_STREQ_LEN(written, buff, "0x1.999999999999ap-4");
261 }
262
263 void floatHexExpLongDoublePrec(FunctionT func) {
264 char buff[55];
265 int written;
266
267 written = func(buff, 50, "%a", 0.1L);
268#if defined(LIBC_TYPES_LONG_DOUBLE_IS_X86_FLOAT80)
269 ASSERT_STREQ_LEN(written, buff, "0xc.ccccccccccccccdp-7");
270#elif defined(LIBC_TYPES_LONG_DOUBLE_IS_FLOAT64)
271 ASSERT_STREQ_LEN(written, buff, "0x1.999999999999ap-4");
272#elif defined(LIBC_TYPES_LONG_DOUBLE_IS_FLOAT128)
273 ASSERT_STREQ_LEN(written, buff, "0x1.999999999999999999999999999ap-4");
274#endif
275
276 written = func(buff, 20, "%.1a", 0.1L);
277#if defined(LIBC_TYPES_LONG_DOUBLE_IS_X86_FLOAT80)
278 ASSERT_STREQ_LEN(written, buff, "0xc.dp-7");
279#elif defined(LIBC_TYPES_LONG_DOUBLE_IS_FLOAT64)
280 ASSERT_STREQ_LEN(written, buff, "0x1.ap-4");
281#elif defined(LIBC_TYPES_LONG_DOUBLE_IS_FLOAT128)
282 ASSERT_STREQ_LEN(written, buff, "0x1.ap-4");
283#endif
284
285 written = func(buff, 50, "%a", 1.0e1000L);
286#if defined(LIBC_TYPES_LONG_DOUBLE_IS_X86_FLOAT80)
287 ASSERT_STREQ_LEN(written, buff, "0xf.38db1f9dd3dac05p+3318");
288#elif defined(LIBC_TYPES_LONG_DOUBLE_IS_FLOAT64)
289 ASSERT_STREQ_LEN(written, buff, "inf");
290#elif defined(LIBC_TYPES_LONG_DOUBLE_IS_FLOAT128)
291 ASSERT_STREQ_LEN(written, buff, "0x1.e71b63f3ba7b580af1a52d2a7379p+3321");
292#endif
293
294 written = func(buff, 50, "%a", 1.0e-1000L);
295#if defined(LIBC_TYPES_LONG_DOUBLE_IS_X86_FLOAT80)
296 ASSERT_STREQ_LEN(written, buff, "0x8.68a9188a89e1467p-3325");
297#elif defined(LIBC_TYPES_LONG_DOUBLE_IS_FLOAT64)
298 ASSERT_STREQ_LEN(written, buff, "0x0p+0");
299#elif defined(LIBC_TYPES_LONG_DOUBLE_IS_FLOAT128)
300 ASSERT_STREQ_LEN(written, buff, "0x1.0d152311513c28ce202627c06ec2p-3322");
301#endif
302
303 written = func(buff, 50, "%.1a", 0xf.fffffffffffffffp16380L);
304#if defined(LIBC_TYPES_LONG_DOUBLE_IS_X86_FLOAT80)
305 ASSERT_STREQ_LEN(written, buff, "0x1.0p+16384");
306#elif defined(LIBC_TYPES_LONG_DOUBLE_IS_FLOAT64)
307 ASSERT_STREQ_LEN(written, buff, "inf");
308#elif defined(LIBC_TYPES_LONG_DOUBLE_IS_FLOAT128)
309 ASSERT_STREQ_LEN(written, buff, "0x2.0p+16383");
310#endif
311 }
312
313 void floatDecimalExpSinglePrec(FunctionT func) {
314 char buff[25];
315 int written;
316
317 written = func(buff, 20, "%.9e", 1234567890.0f);
318 ASSERT_STREQ_LEN(written, buff, "1.234567936e+09");
319
320 written = func(buff, 20, "%.9E", 1234567890.0f);
321 ASSERT_STREQ_LEN(written, buff, "1.234567936E+09");
322 }
323
324 void floatDecimalExpDoublePrec(FunctionT func) {
325 char buff[101];
326 int written;
327
328 written = func(buff, 100, "%e", 1.0);
329 ASSERT_STREQ_LEN(written, buff, "1.000000e+00");
330
331 written = func(buff, 100, "%E", -1.0);
332 ASSERT_STREQ_LEN(written, buff, "-1.000000E+00");
333
334 written = func(buff, 100, "%e", -1.234567);
335 ASSERT_STREQ_LEN(written, buff, "-1.234567e+00");
336
337 written = func(buff, 100, "%e", 0.0);
338 ASSERT_STREQ_LEN(written, buff, "0.000000e+00");
339
340 written = func(buff, 100, "%e", 1.5);
341 ASSERT_STREQ_LEN(written, buff, "1.500000e+00");
342
343 written = func(buff, 100, "%e", 1e300);
344 ASSERT_STREQ_LEN(written, buff, "1.000000e+300");
345
346 written = func(buff, 100, "%e", 1234567890123456789.0);
347 ASSERT_STREQ_LEN(written, buff, "1.234568e+18");
348
349 // Precision Tests
350 written = func(buff, 100, "%.1e", 1.0);
351 ASSERT_STREQ_LEN(written, buff, "1.0e+00");
352
353 written = func(buff, 100, "%.1e", 1.99);
354 ASSERT_STREQ_LEN(written, buff, "2.0e+00");
355
356 written = func(buff, 100, "%.1e", 9.99);
357 ASSERT_STREQ_LEN(written, buff, "1.0e+01");
358 }
359
360 void floatDecimalExpLongDoublePrec(FunctionT func) {
361 // Mark as maybe_unused to silence unused variable
362 // warning when long double is not 80-bit
363 [[maybe_unused]] char buff[100];
364 [[maybe_unused]] int written;
365
366#if defined(LIBC_TYPES_LONG_DOUBLE_IS_X86_FLOAT80)
367 written = func(buff, 90, "%.9e", 1000000000500000000.1L);
368 ASSERT_STREQ_LEN(written, buff, "1.000000001e+18");
369
370 written = func(buff, 90, "%.9e", 1000000000500000000.0L);
371 ASSERT_STREQ_LEN(written, buff, "1.000000000e+18");
372
373 written = func(buff, 90, "%e", 0xf.fffffffffffffffp+16380L);
374 ASSERT_STREQ_LEN(written, buff, "1.189731e+4932");
375#endif // LIBC_TYPES_LONG_DOUBLE_IS_X86_FLOAT80
376 }
377
378 void floatDecimalAutoSinglePrec(FunctionT func) {
379 char buff[25];
380 int written;
381
382 written = func(buff, 20, "%.9g", 1234567890.0f);
383 ASSERT_STREQ_LEN(written, buff, "1.23456794e+09");
384
385 written = func(buff, 20, "%.9G", 1234567890.0f);
386 ASSERT_STREQ_LEN(written, buff, "1.23456794E+09");
387 }
388
389 void floatDecimalAutoDoublePrec(FunctionT func) {
390 char buff[120];
391 int written;
392
393 written = func(buff, 100, "%g", 1234567890123456789.0);
394 ASSERT_STREQ_LEN(written, buff, "1.23457e+18");
395
396 written = func(buff, 100, "%g", 9999990000000.00);
397 ASSERT_STREQ_LEN(written, buff, "9.99999e+12");
398
399 written = func(buff, 100, "%g", 9999999000000.00);
400 ASSERT_STREQ_LEN(written, buff, "1e+13");
401
402 written = func(buff, 100, "%g", 0xa.aaaaaaaaaaaaaabp-7);
403 ASSERT_STREQ_LEN(written, buff, "0.0833333");
404
405 written = func(buff, 100, "%g", 0.00001);
406 ASSERT_STREQ_LEN(written, buff, "1e-05");
407
408 // Precision Tests
409 written = func(buff, 100, "%.0g", 0.0);
410 ASSERT_STREQ_LEN(written, buff, "0");
411
412 written = func(buff, 100, "%.2g", 0.1);
413 ASSERT_STREQ_LEN(written, buff, "0.1");
414
415 written = func(buff, 100, "%.2g", 1.09);
416 ASSERT_STREQ_LEN(written, buff, "1.1");
417
418 written = func(buff, 100, "%.15g", 22.25);
419 ASSERT_STREQ_LEN(written, buff, "22.25");
420
421 written = func(buff, 100, "%.20g", 1.234e-10);
422 ASSERT_STREQ_LEN(written, buff, "1.2340000000000000814e-10");
423 }
424
425 void floatDecimalAutoLongDoublePrec(FunctionT func) {
426 // Mark as maybe_unused to silence unused variable
427 // warning when long double is not 80-bit
428 [[maybe_unused]] char buff[100];
429 [[maybe_unused]] int written;
430
431#if defined(LIBC_TYPES_LONG_DOUBLE_IS_X86_FLOAT80)
432 written = func(buff, 99, "%g", 0xf.fffffffffffffffp+16380L);
433 ASSERT_STREQ_LEN(written, buff, "1.18973e+4932");
434
435 written = func(buff, 99, "%g", 0xa.aaaaaaaaaaaaaabp-7L);
436 ASSERT_STREQ_LEN(written, buff, "0.0833333");
437
438 written = func(buff, 99, "%g", 9.99999999999e-100L);
439 ASSERT_STREQ_LEN(written, buff, "1e-99");
440#endif // LIBC_TYPES_LONG_DOUBLE_IS_X86_FLOAT80
441 }
442
443 void doublePrecInfNan(FunctionT func) {
444 char buff[15];
445 int written;
446
447 double inf = LIBC_NAMESPACE::fputil::FPBits<double>::inf().get_val();
448 double nan = LIBC_NAMESPACE::fputil::FPBits<double>::quiet_nan().get_val();
449
450 written = func(buff, 10, "%f", inf);
451 ASSERT_STREQ_LEN(written, buff, "inf");
452
453 written = func(buff, 10, "%A", -inf);
454 ASSERT_STREQ_LEN(written, buff, "-INF");
455
456 written = func(buff, 10, "%f", nan);
457 ASSERT_STREQ_LEN(written, buff, "nan");
458
459 written = func(buff, 10, "%A", -nan);
460 ASSERT_STREQ_LEN(written, buff, "-NAN");
461 }
462
463 void longDoublePrecInfNan(FunctionT func) {
464 char buff[15];
465 int written;
466
467 long double ld_inf =
468 LIBC_NAMESPACE::fputil::FPBits<long double>::inf().get_val();
469 long double ld_nan =
470 LIBC_NAMESPACE::fputil::FPBits<long double>::quiet_nan().get_val();
471
472 written = func(buff, 10, "%f", ld_inf);
473 ASSERT_STREQ_LEN(written, buff, "inf");
474
475 written = func(buff, 10, "%A", -ld_inf);
476 ASSERT_STREQ_LEN(written, buff, "-INF");
477
478 written = func(buff, 10, "%f", ld_nan);
479 ASSERT_STREQ_LEN(written, buff, "nan");
480
481 written = func(buff, 10, "%A", -ld_nan);
482 ASSERT_STREQ_LEN(written, buff, "-NAN");
483 }
484};
485
486#define STRFROM_TEST(InputType, name, func) \
487 using LlvmLibc##name##Test = StrfromTest<InputType>; \
488 TEST_F(LlvmLibc##name##Test, FloatDecimalFormat) { \
489 floatDecimalFormat(func); \
490 } \
491 TEST_F(LlvmLibc##name##Test, FloatHexExpFormat) { floatHexExpFormat(func); } \
492 TEST_F(LlvmLibc##name##Test, FloatDecimalAutoFormat) { \
493 floatDecimalAutoFormat(func); \
494 } \
495 TEST_F(LlvmLibc##name##Test, FloatDecimalExpFormat) { \
496 floatDecimalExpFormat(func); \
497 } \
498 TEST_F(LlvmLibc##name##Test, ImproperFormatString) { \
499 improperFormatString(func); \
500 } \
501 TEST_F(LlvmLibc##name##Test, InsufficientBufferSize) { \
502 insufficentBufsize(func); \
503 } \
504 TEST_F(LlvmLibc##name##Test, InfAndNanValues) { infNanValues(func); }
505

Provided by KDAB

Privacy Policy
Learn to use CMake with our Intro Training
Find out more

source code of libc/test/src/stdlib/StrfromTest.h