brintos

brintos / llvm-project-archived public Read only

0
0
Text · 18.0 KiB · 3dacfca Raw
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