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