diff --git a/libc/test/src/stdlib/CMakeLists.txt b/libc/test/src/stdlib/CMakeLists.txt index 7c9f770a4b02b..11e8f2e1bb634 100644 --- a/libc/test/src/stdlib/CMakeLists.txt +++ b/libc/test/src/stdlib/CMakeLists.txt @@ -180,16 +180,6 @@ if(LIBC_CONF_PRINTF_FLOAT_TO_STR_USE_DYADIC_FLOAT OR libc_set_definition(strfrom_test_copts "LIBC_COPT_FLOAT_TO_STR_REDUCED_PRECISION") endif() -add_header_library( - strfrom_test_support - HDRS - StrfromTest.h - DEPENDS - libc.src.__support.CPP.type_traits - libc.src.__support.FPUtil.fp_bits - libc.src.__support.macros.properties.architectures -) - add_libc_test( strfromf_test SUITE @@ -197,7 +187,8 @@ add_libc_test( SRCS strfromf_test.cpp DEPENDS - .strfrom_test_support + libc.src.__support.FPUtil.fp_bits + libc.src.__support.macros.properties.architectures libc.src.stdlib.strfromf COMPILE_OPTIONS ${strfrom_test_copts} @@ -210,7 +201,8 @@ add_libc_test( SRCS strfromd_test.cpp DEPENDS - .strfrom_test_support + libc.src.__support.FPUtil.fp_bits + libc.src.__support.macros.properties.architectures libc.src.stdlib.strfromd COMPILE_OPTIONS ${strfrom_test_copts} @@ -223,7 +215,8 @@ add_libc_test( SRCS strfroml_test.cpp DEPENDS - .strfrom_test_support + libc.src.__support.FPUtil.fp_bits + libc.src.__support.macros.properties.architectures libc.src.stdlib.strfroml COMPILE_OPTIONS ${strfrom_test_copts} diff --git a/libc/test/src/stdlib/StrfromTest.h b/libc/test/src/stdlib/StrfromTest.h deleted file mode 100644 index 3dacfca9e89f9..0000000000000 --- a/libc/test/src/stdlib/StrfromTest.h +++ /dev/null @@ -1,523 +0,0 @@ -//===-- A template class for testing strfrom functions ----------*- C++ -*-===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// - -#include "src/__support/CPP/type_traits.h" -#include "src/__support/FPUtil/FPBits.h" -#include "src/__support/macros/properties/architectures.h" -#include "test/UnitTest/ErrnoCheckingTest.h" -#include "test/UnitTest/ErrnoSetterMatcher.h" -#include "test/UnitTest/Test.h" - -#define ASSERT_STREQ_LEN(actual_written, actual_str, expected_str) \ - EXPECT_EQ(actual_written, static_cast(sizeof(expected_str) - 1)); \ - EXPECT_STREQ(actual_str, expected_str); - -template -class StrfromTest : public LIBC_NAMESPACE::testing::ErrnoCheckingTest { - - static constexpr bool is_single_prec = - LIBC_NAMESPACE::cpp::is_same::value; - static constexpr bool is_double_prec = - LIBC_NAMESPACE::cpp::is_same::value; - - using FunctionT = int (*)(char *, size_t, const char *, InputT fp); - -public: - void floatDecimalFormat(FunctionT func) { - if constexpr (is_single_prec) - floatDecimalSinglePrec(func); - else if constexpr (is_double_prec) - floatDecimalDoublePrec(func); - else - floatDecimalLongDoublePrec(func); - } - - void floatHexExpFormat(FunctionT func) { - if constexpr (is_single_prec) - floatHexExpSinglePrec(func); - else if constexpr (is_double_prec) - floatHexExpDoublePrec(func); - else - floatHexExpLongDoublePrec(func); - } - - void floatDecimalExpFormat(FunctionT func) { - if constexpr (is_single_prec) - floatDecimalExpSinglePrec(func); - else if constexpr (is_double_prec) - floatDecimalExpDoublePrec(func); - else - floatDecimalExpLongDoublePrec(func); - } - - void floatDecimalAutoFormat(FunctionT func) { - if constexpr (is_single_prec) - floatDecimalAutoSinglePrec(func); - else if constexpr (is_double_prec) - floatDecimalAutoDoublePrec(func); - else - floatDecimalAutoLongDoublePrec(func); - } - - void improperFormatString(FunctionT func) { - char buff[100]; - int written; - const bool is_long_double = !is_single_prec && !is_double_prec; - - written = func(buff, 37, "A simple string with no conversions.", 1.0); - ASSERT_STREQ_LEN(written, buff, "A simple string with no conversions."); - - written = - func(buff, 37, - "%A simple string with one conversion, should overwrite.", 1.0); - if (is_long_double) { -#if defined(LIBC_TYPES_LONG_DOUBLE_IS_X86_FLOAT80) - ASSERT_STREQ_LEN(written, buff, "0X8P-3"); -#elif defined(LIBC_TYPES_LONG_DOUBLE_IS_FLOAT64) - ASSERT_STREQ_LEN(written, buff, "0X1P+0"); -#elif defined(LIBC_TYPES_LONG_DOUBLE_IS_FLOAT128) - ASSERT_STREQ_LEN(written, buff, "0X1P+0"); -#endif - } else { - // not long double - ASSERT_STREQ_LEN(written, buff, "0X1P+0"); - } - written = func(buff, 74, - "A simple string with one conversion in %A " - "between, writes string as it is", - 1.0); - ASSERT_STREQ_LEN(written, buff, - "A simple string with one conversion in %A between, " - "writes string as it is"); - - written = func(buff, 36, "A simple string with one conversion", 1.0); - ASSERT_STREQ_LEN(written, buff, "A simple string with one conversion"); - - written = func(buff, 20, "%1f", static_cast(1234567890.0)); - ASSERT_STREQ_LEN(written, buff, "%1f"); - } - - void insufficentBufsize(FunctionT func) { - char buff[20]; - int written; - - written = func(buff, 5, "%f", static_cast(1234567890.0)); - EXPECT_EQ(written, 17); - ASSERT_STREQ(buff, "1234"); - - written = func(buff, 5, "%.5f", static_cast(1.05)); - EXPECT_EQ(written, 7); - ASSERT_STREQ(buff, "1.05"); - - written = func(buff, 0, "%g", static_cast(1.0)); - EXPECT_EQ(written, 1); - ASSERT_STREQ(buff, "1.05"); // Make sure that buff has not changed - } - - void infNanValues(FunctionT func) { - if constexpr (is_double_prec) - doublePrecInfNan(func); - else if constexpr (!is_single_prec) - longDoublePrecInfNan(func); - } - - void floatDecimalSinglePrec(FunctionT func) { - char buff[70]; - int written; - - written = func(buff, 16, "%f", 1.0f); - ASSERT_STREQ_LEN(written, buff, "1.000000"); - - written = func(buff, 20, "%f", 1234567890.0f); - ASSERT_STREQ_LEN(written, buff, "1234567936.000000"); - - written = func(buff, 67, "%.3f", 1.0f); - ASSERT_STREQ_LEN(written, buff, "1.000"); - } - - void floatDecimalDoublePrec(FunctionT func) { - char buff[500]; - int written; - - written = func(buff, 99, "%f", 1.0); - ASSERT_STREQ_LEN(written, buff, "1.000000"); - - written = func(buff, 99, "%F", -1.0); - ASSERT_STREQ_LEN(written, buff, "-1.000000"); - - written = func(buff, 99, "%f", -1.234567); - ASSERT_STREQ_LEN(written, buff, "-1.234567"); - - written = func(buff, 99, "%f", 0.0); - ASSERT_STREQ_LEN(written, buff, "0.000000"); - - written = func(buff, 99, "%f", 1.5); - ASSERT_STREQ_LEN(written, buff, "1.500000"); - -// Dyadic float is only accurate to ~50 digits, so skip this 300 digit test. -// TODO: Create way to test just the first ~50 digits of a number. -#ifndef LIBC_COPT_FLOAT_TO_STR_REDUCED_PRECISION - written = func(buff, 499, "%f", 1e300); - ASSERT_STREQ_LEN(written, buff, - "100000000000000005250476025520442024870446858110815915491" - "585411551180245" - "798890819578637137508044786404370444383288387817694252323" - "536043057564479" - "218478670698284838720092657580373783023379478809005936895" - "323497079994508" - "111903896764088007465274278014249457925878882005684283811" - "566947219638686" - "5459400540160.000000"); -#endif // DLIBC_COPT_FLOAT_TO_STR_REDUCED_PRECISION - - written = func(buff, 99, "%f", 0.1); - ASSERT_STREQ_LEN(written, buff, "0.100000"); - - written = func(buff, 99, "%f", 1234567890123456789.0); - ASSERT_STREQ_LEN(written, buff, "1234567890123456768.000000"); - - written = func(buff, 99, "%f", 9999999999999.99); - ASSERT_STREQ_LEN(written, buff, "9999999999999.990234"); - - written = func(buff, 99, "%f", 0.1); - ASSERT_STREQ_LEN(written, buff, "0.100000"); - - written = func(buff, 99, "%f", 1234567890123456789.0); - ASSERT_STREQ_LEN(written, buff, "1234567890123456768.000000"); - - written = func(buff, 99, "%f", 9999999999999.99); - ASSERT_STREQ_LEN(written, buff, "9999999999999.990234"); - - // Precision Tests - written = func(buff, 100, "%.2f", 9999999999999.99); - ASSERT_STREQ_LEN(written, buff, "9999999999999.99"); - - written = func(buff, 100, "%.1f", 9999999999999.99); - ASSERT_STREQ_LEN(written, buff, "10000000000000.0"); - - written = func(buff, 100, "%.5f", 1.25); - ASSERT_STREQ_LEN(written, buff, "1.25000"); - - written = func(buff, 100, "%.0f", 1.25); - ASSERT_STREQ_LEN(written, buff, "1"); - - written = func(buff, 100, "%.20f", 1.234e-10); - ASSERT_STREQ_LEN(written, buff, "0.00000000012340000000"); - } - - void floatDecimalLongDoublePrec(FunctionT func) { - char buff[45]; - int written; - - written = func(buff, 40, "%f", 1.0L); - ASSERT_STREQ_LEN(written, buff, "1.000000"); - - written = func(buff, 10, "%.f", -2.5L); - ASSERT_STREQ_LEN(written, buff, "-2"); - } - - void floatHexExpSinglePrec(FunctionT func) { - char buff[25]; - int written; - - written = func(buff, 0, "%a", 1234567890.0f); - EXPECT_EQ(written, 14); - - written = func(buff, 20, "%a", 1234567890.0f); - EXPECT_EQ(written, 14); - ASSERT_STREQ(buff, "0x1.26580cp+30"); - - written = func(buff, 20, "%A", 1234567890.0f); - EXPECT_EQ(written, 14); - ASSERT_STREQ(buff, "0X1.26580CP+30"); - } - - void floatHexExpDoublePrec(FunctionT func) { - char buff[60]; - int written; - - written = func(buff, 10, "%a", 1.0); - ASSERT_STREQ_LEN(written, buff, "0x1p+0"); - - written = func(buff, 10, "%A", -1.0); - ASSERT_STREQ_LEN(written, buff, "-0X1P+0"); - - written = func(buff, 30, "%a", -0x1.abcdef12345p0); - ASSERT_STREQ_LEN(written, buff, "-0x1.abcdef12345p+0"); - - written = func(buff, 50, "%A", 0x1.abcdef12345p0); - ASSERT_STREQ_LEN(written, buff, "0X1.ABCDEF12345P+0"); - - written = func(buff, 10, "%a", 0.0); - ASSERT_STREQ_LEN(written, buff, "0x0p+0"); - - written = func(buff, 40, "%a", 1.0e100); - ASSERT_STREQ_LEN(written, buff, "0x1.249ad2594c37dp+332"); - - written = func(buff, 30, "%a", 0.1); - ASSERT_STREQ_LEN(written, buff, "0x1.999999999999ap-4"); - } - - void floatHexExpLongDoublePrec(FunctionT func) { - char buff[55]; - int written; - - written = func(buff, 50, "%a", 0.1L); -#if defined(LIBC_TYPES_LONG_DOUBLE_IS_X86_FLOAT80) - ASSERT_STREQ_LEN(written, buff, "0xc.ccccccccccccccdp-7"); -#elif defined(LIBC_TYPES_LONG_DOUBLE_IS_FLOAT64) - ASSERT_STREQ_LEN(written, buff, "0x1.999999999999ap-4"); -#elif defined(LIBC_TYPES_LONG_DOUBLE_IS_FLOAT128) - ASSERT_STREQ_LEN(written, buff, "0x1.999999999999999999999999999ap-4"); -#endif - - written = func(buff, 20, "%.1a", 0.1L); -#if defined(LIBC_TYPES_LONG_DOUBLE_IS_X86_FLOAT80) - ASSERT_STREQ_LEN(written, buff, "0xc.dp-7"); -#elif defined(LIBC_TYPES_LONG_DOUBLE_IS_FLOAT64) - ASSERT_STREQ_LEN(written, buff, "0x1.ap-4"); -#elif defined(LIBC_TYPES_LONG_DOUBLE_IS_FLOAT128) - ASSERT_STREQ_LEN(written, buff, "0x1.ap-4"); -#endif - - written = func(buff, 50, "%a", 1.0e1000L); -#if defined(LIBC_TYPES_LONG_DOUBLE_IS_X86_FLOAT80) - ASSERT_STREQ_LEN(written, buff, "0xf.38db1f9dd3dac05p+3318"); -#elif defined(LIBC_TYPES_LONG_DOUBLE_IS_FLOAT64) - ASSERT_STREQ_LEN(written, buff, "inf"); -#elif defined(LIBC_TYPES_LONG_DOUBLE_IS_FLOAT128) - ASSERT_STREQ_LEN(written, buff, "0x1.e71b63f3ba7b580af1a52d2a7379p+3321"); -#endif - - written = func(buff, 50, "%a", 1.0e-1000L); -#if defined(LIBC_TYPES_LONG_DOUBLE_IS_X86_FLOAT80) - ASSERT_STREQ_LEN(written, buff, "0x8.68a9188a89e1467p-3325"); -#elif defined(LIBC_TYPES_LONG_DOUBLE_IS_FLOAT64) - ASSERT_STREQ_LEN(written, buff, "0x0p+0"); -#elif defined(LIBC_TYPES_LONG_DOUBLE_IS_FLOAT128) - ASSERT_STREQ_LEN(written, buff, "0x1.0d152311513c28ce202627c06ec2p-3322"); -#endif - - written = func(buff, 50, "%.1a", 0xf.fffffffffffffffp16380L); -#if defined(LIBC_TYPES_LONG_DOUBLE_IS_X86_FLOAT80) - ASSERT_STREQ_LEN(written, buff, "0x1.0p+16384"); -#elif defined(LIBC_TYPES_LONG_DOUBLE_IS_FLOAT64) - ASSERT_STREQ_LEN(written, buff, "inf"); -#elif defined(LIBC_TYPES_LONG_DOUBLE_IS_FLOAT128) - ASSERT_STREQ_LEN(written, buff, "0x2.0p+16383"); -#endif - } - - void floatDecimalExpSinglePrec(FunctionT func) { - char buff[25]; - int written; - - written = func(buff, 20, "%.9e", 1234567890.0f); - ASSERT_STREQ_LEN(written, buff, "1.234567936e+09"); - - written = func(buff, 20, "%.9E", 1234567890.0f); - ASSERT_STREQ_LEN(written, buff, "1.234567936E+09"); - } - - void floatDecimalExpDoublePrec(FunctionT func) { - char buff[101]; - int written; - - written = func(buff, 100, "%e", 1.0); - ASSERT_STREQ_LEN(written, buff, "1.000000e+00"); - - written = func(buff, 100, "%E", -1.0); - ASSERT_STREQ_LEN(written, buff, "-1.000000E+00"); - - written = func(buff, 100, "%e", -1.234567); - ASSERT_STREQ_LEN(written, buff, "-1.234567e+00"); - - written = func(buff, 100, "%e", 0.0); - ASSERT_STREQ_LEN(written, buff, "0.000000e+00"); - - written = func(buff, 100, "%e", 1.5); - ASSERT_STREQ_LEN(written, buff, "1.500000e+00"); - - written = func(buff, 100, "%e", 1e300); - ASSERT_STREQ_LEN(written, buff, "1.000000e+300"); - - written = func(buff, 100, "%e", 1234567890123456789.0); - ASSERT_STREQ_LEN(written, buff, "1.234568e+18"); - - // Precision Tests - written = func(buff, 100, "%.1e", 1.0); - ASSERT_STREQ_LEN(written, buff, "1.0e+00"); - - written = func(buff, 100, "%.1e", 1.99); - ASSERT_STREQ_LEN(written, buff, "2.0e+00"); - - written = func(buff, 100, "%.1e", 9.99); - ASSERT_STREQ_LEN(written, buff, "1.0e+01"); - } - - void floatDecimalExpLongDoublePrec([[maybe_unused]] FunctionT func) { - // Mark as maybe_unused to silence unused variable - // warning when long double is not 80-bit - [[maybe_unused]] char buff[100]; - [[maybe_unused]] int written; - -#if defined(LIBC_TYPES_LONG_DOUBLE_IS_X86_FLOAT80) - written = func(buff, 90, "%.9e", 1000000000500000000.1L); - ASSERT_STREQ_LEN(written, buff, "1.000000001e+18"); - - written = func(buff, 90, "%.9e", 1000000000500000000.0L); - ASSERT_STREQ_LEN(written, buff, "1.000000000e+18"); - - written = func(buff, 90, "%e", 0xf.fffffffffffffffp+16380L); - ASSERT_STREQ_LEN(written, buff, "1.189731e+4932"); -#endif // LIBC_TYPES_LONG_DOUBLE_IS_X86_FLOAT80 - } - - void floatDecimalAutoSinglePrec(FunctionT func) { - char buff[25]; - int written; - - written = func(buff, 20, "%.9g", 1234567890.0f); - ASSERT_STREQ_LEN(written, buff, "1.23456794e+09"); - - written = func(buff, 20, "%.9G", 1234567890.0f); - ASSERT_STREQ_LEN(written, buff, "1.23456794E+09"); - } - - void floatDecimalAutoDoublePrec(FunctionT func) { - char buff[120]; - int written; - - written = func(buff, 100, "%g", 1234567890123456789.0); - ASSERT_STREQ_LEN(written, buff, "1.23457e+18"); - - written = func(buff, 100, "%g", 9999990000000.00); - ASSERT_STREQ_LEN(written, buff, "9.99999e+12"); - - written = func(buff, 100, "%g", 9999999000000.00); - ASSERT_STREQ_LEN(written, buff, "1e+13"); - - written = func(buff, 100, "%g", 0xa.aaaaaaaaaaaaaabp-7); - ASSERT_STREQ_LEN(written, buff, "0.0833333"); - - written = func(buff, 100, "%g", 0.00001); - ASSERT_STREQ_LEN(written, buff, "1e-05"); - - // Precision Tests - written = func(buff, 100, "%.0g", 0.0); - ASSERT_STREQ_LEN(written, buff, "0"); - - written = func(buff, 100, "%.2g", 0.1); - ASSERT_STREQ_LEN(written, buff, "0.1"); - - written = func(buff, 100, "%.2g", 1.09); - ASSERT_STREQ_LEN(written, buff, "1.1"); - - written = func(buff, 100, "%.15g", 22.25); - ASSERT_STREQ_LEN(written, buff, "22.25"); - - written = func(buff, 100, "%.20g", 1.234e-10); - ASSERT_STREQ_LEN(written, buff, "1.2340000000000000814e-10"); - } - - void floatDecimalAutoLongDoublePrec([[maybe_unused]] FunctionT func) { - // Mark as maybe_unused to silence unused variable - // warning when long double is not 80-bit - [[maybe_unused]] char buff[100]; - [[maybe_unused]] int written; - -#if defined(LIBC_TYPES_LONG_DOUBLE_IS_X86_FLOAT80) - written = func(buff, 99, "%g", 0xf.fffffffffffffffp+16380L); - ASSERT_STREQ_LEN(written, buff, "1.18973e+4932"); - - written = func(buff, 99, "%g", 0xa.aaaaaaaaaaaaaabp-7L); - ASSERT_STREQ_LEN(written, buff, "0.0833333"); - - written = func(buff, 99, "%g", 9.99999999999e-100L); - ASSERT_STREQ_LEN(written, buff, "1e-99"); -#endif // LIBC_TYPES_LONG_DOUBLE_IS_X86_FLOAT80 - } - - void doublePrecInfNan(FunctionT func) { - char buff[15]; - int written; - - double inf = LIBC_NAMESPACE::fputil::FPBits::inf().get_val(); - double nan = LIBC_NAMESPACE::fputil::FPBits::quiet_nan().get_val(); - - written = func(buff, 10, "%f", inf); - ASSERT_STREQ_LEN(written, buff, "inf"); - - written = func(buff, 10, "%A", -inf); - ASSERT_STREQ_LEN(written, buff, "-INF"); - - written = func(buff, 10, "%f", nan); - ASSERT_STREQ_LEN(written, buff, "nan"); - - written = func(buff, 10, "%A", -nan); - ASSERT_STREQ_LEN(written, buff, "-NAN"); - } - - void longDoublePrecInfNan(FunctionT func) { - char buff[15]; - int written; - - long double ld_inf = - LIBC_NAMESPACE::fputil::FPBits::inf().get_val(); - long double ld_nan = - LIBC_NAMESPACE::fputil::FPBits::quiet_nan().get_val(); - - written = func(buff, 10, "%f", ld_inf); - ASSERT_STREQ_LEN(written, buff, "inf"); - - written = func(buff, 10, "%A", -ld_inf); - ASSERT_STREQ_LEN(written, buff, "-INF"); - - written = func(buff, 10, "%f", ld_nan); - ASSERT_STREQ_LEN(written, buff, "nan"); - - written = func(buff, 10, "%A", -ld_nan); - ASSERT_STREQ_LEN(written, buff, "-NAN"); - } - - // https://github.com/llvm/llvm-project/issues/166795 - void charsWrittenOverflow(FunctionT func) { -#ifndef LIBC_TARGET_ARCH_IS_RISCV32 - char buff[100]; - // Trigger an overflow in the return value of strfrom by writing more than - // INT_MAX bytes. - int result = func(buff, sizeof(buff), "%.2147483647f", 1.0f); - - EXPECT_LT(result, 0); - ASSERT_ERRNO_FAILURE(); -#endif - } -}; - -#define STRFROM_TEST(InputType, name, func) \ - using LlvmLibc##name##Test = StrfromTest; \ - TEST_F(LlvmLibc##name##Test, FloatDecimalFormat) { \ - floatDecimalFormat(func); \ - } \ - TEST_F(LlvmLibc##name##Test, FloatHexExpFormat) { floatHexExpFormat(func); } \ - TEST_F(LlvmLibc##name##Test, FloatDecimalAutoFormat) { \ - floatDecimalAutoFormat(func); \ - } \ - TEST_F(LlvmLibc##name##Test, FloatDecimalExpFormat) { \ - floatDecimalExpFormat(func); \ - } \ - TEST_F(LlvmLibc##name##Test, ImproperFormatString) { \ - improperFormatString(func); \ - } \ - TEST_F(LlvmLibc##name##Test, InsufficientBufferSize) { \ - insufficentBufsize(func); \ - } \ - TEST_F(LlvmLibc##name##Test, InfAndNanValues) { infNanValues(func); } \ - TEST_F(LlvmLibc##name##Test, CharsWrittenOverflow) { \ - charsWrittenOverflow(func); \ - } diff --git a/libc/test/src/stdlib/strfromd_test.cpp b/libc/test/src/stdlib/strfromd_test.cpp index 55724d7e902b5..0f13b7cec8032 100644 --- a/libc/test/src/stdlib/strfromd_test.cpp +++ b/libc/test/src/stdlib/strfromd_test.cpp @@ -6,8 +6,234 @@ // //===----------------------------------------------------------------------===// -#include "StrfromTest.h" +#include "src/__support/FPUtil/FPBits.h" +#include "src/__support/macros/properties/architectures.h" #include "src/stdlib/strfromd.h" +#include "test/UnitTest/ErrnoCheckingTest.h" +#include "test/UnitTest/ErrnoSetterMatcher.h" #include "test/UnitTest/Test.h" -STRFROM_TEST(double, Strfromd, LIBC_NAMESPACE::strfromd) +#define EXPECT_STREQ_LEN(str_size_needed, actual_str, expected_str) \ + EXPECT_EQ(str_size_needed, static_cast(sizeof(expected_str) - 1)); \ + EXPECT_STREQ(actual_str, expected_str); + +using LlvmLibcStrfromdTest = LIBC_NAMESPACE::testing::ErrnoCheckingTest; + +TEST_F(LlvmLibcStrfromdTest, DecimalFormat) { + char buff[500]; + int result; + + result = LIBC_NAMESPACE::strfromd(buff, 99, "%f", 1.0); + EXPECT_STREQ_LEN(result, buff, "1.000000"); + + result = LIBC_NAMESPACE::strfromd(buff, 99, "%F", -1.0); + EXPECT_STREQ_LEN(result, buff, "-1.000000"); + + result = LIBC_NAMESPACE::strfromd(buff, 99, "%f", -1.234567); + EXPECT_STREQ_LEN(result, buff, "-1.234567"); + + result = LIBC_NAMESPACE::strfromd(buff, 99, "%f", 0.0); + EXPECT_STREQ_LEN(result, buff, "0.000000"); + + result = LIBC_NAMESPACE::strfromd(buff, 99, "%f", 1.5); + EXPECT_STREQ_LEN(result, buff, "1.500000"); + +// Dyadic float is only accurate to ~50 digits, so skip this 300 digit test. +// TODO: Create way to test just the first ~50 digits of a number. +#ifndef LIBC_COPT_FLOAT_TO_STR_REDUCED_PRECISION + result = LIBC_NAMESPACE::strfromd(buff, 499, "%f", 1e300); + EXPECT_STREQ_LEN(result, buff, + "100000000000000005250476025520442024870446858110815915491" + "585411551180245" + "798890819578637137508044786404370444383288387817694252323" + "536043057564479" + "218478670698284838720092657580373783023379478809005936895" + "323497079994508" + "111903896764088007465274278014249457925878882005684283811" + "566947219638686" + "5459400540160.000000"); +#endif // DLIBC_COPT_FLOAT_TO_STR_REDUCED_PRECISION + + result = LIBC_NAMESPACE::strfromd(buff, 99, "%f", 0.1); + EXPECT_STREQ_LEN(result, buff, "0.100000"); + + result = LIBC_NAMESPACE::strfromd(buff, 99, "%f", 1234567890123456789.0); + EXPECT_STREQ_LEN(result, buff, "1234567890123456768.000000"); + + result = LIBC_NAMESPACE::strfromd(buff, 99, "%f", 9999999999999.99); + EXPECT_STREQ_LEN(result, buff, "9999999999999.990234"); + + result = LIBC_NAMESPACE::strfromd(buff, 99, "%f", 0.1); + EXPECT_STREQ_LEN(result, buff, "0.100000"); + + result = LIBC_NAMESPACE::strfromd(buff, 99, "%f", 1234567890123456789.0); + EXPECT_STREQ_LEN(result, buff, "1234567890123456768.000000"); + + result = LIBC_NAMESPACE::strfromd(buff, 99, "%f", 9999999999999.99); + EXPECT_STREQ_LEN(result, buff, "9999999999999.990234"); + + // Precision Tests + result = LIBC_NAMESPACE::strfromd(buff, 100, "%.2f", 9999999999999.99); + EXPECT_STREQ_LEN(result, buff, "9999999999999.99"); + + result = LIBC_NAMESPACE::strfromd(buff, 100, "%.1f", 9999999999999.99); + EXPECT_STREQ_LEN(result, buff, "10000000000000.0"); + + result = LIBC_NAMESPACE::strfromd(buff, 100, "%.5f", 1.25); + EXPECT_STREQ_LEN(result, buff, "1.25000"); + + result = LIBC_NAMESPACE::strfromd(buff, 100, "%.0f", 1.25); + EXPECT_STREQ_LEN(result, buff, "1"); + + result = LIBC_NAMESPACE::strfromd(buff, 100, "%.20f", 1.234e-10); + EXPECT_STREQ_LEN(result, buff, "0.00000000012340000000"); +} + +TEST_F(LlvmLibcStrfromdTest, HexExponentFormat) { + char buff[60]; + int result; + + result = LIBC_NAMESPACE::strfromd(buff, 10, "%a", 1.0); + EXPECT_STREQ_LEN(result, buff, "0x1p+0"); + + result = LIBC_NAMESPACE::strfromd(buff, 10, "%A", -1.0); + EXPECT_STREQ_LEN(result, buff, "-0X1P+0"); + + result = LIBC_NAMESPACE::strfromd(buff, 30, "%a", -0x1.abcdef12345p0); + EXPECT_STREQ_LEN(result, buff, "-0x1.abcdef12345p+0"); + + result = LIBC_NAMESPACE::strfromd(buff, 50, "%A", 0x1.abcdef12345p0); + EXPECT_STREQ_LEN(result, buff, "0X1.ABCDEF12345P+0"); + + result = LIBC_NAMESPACE::strfromd(buff, 10, "%a", 0.0); + EXPECT_STREQ_LEN(result, buff, "0x0p+0"); + + result = LIBC_NAMESPACE::strfromd(buff, 40, "%a", 1.0e100); + EXPECT_STREQ_LEN(result, buff, "0x1.249ad2594c37dp+332"); + + result = LIBC_NAMESPACE::strfromd(buff, 30, "%a", 0.1); + EXPECT_STREQ_LEN(result, buff, "0x1.999999999999ap-4"); +} + +TEST_F(LlvmLibcStrfromdTest, DecimalExponentFormat) { + char buff[101]; + int result; + + result = LIBC_NAMESPACE::strfromd(buff, 100, "%e", 1.0); + EXPECT_STREQ_LEN(result, buff, "1.000000e+00"); + + result = LIBC_NAMESPACE::strfromd(buff, 100, "%E", -1.0); + EXPECT_STREQ_LEN(result, buff, "-1.000000E+00"); + + result = LIBC_NAMESPACE::strfromd(buff, 100, "%e", -1.234567); + EXPECT_STREQ_LEN(result, buff, "-1.234567e+00"); + + result = LIBC_NAMESPACE::strfromd(buff, 100, "%e", 0.0); + EXPECT_STREQ_LEN(result, buff, "0.000000e+00"); + + result = LIBC_NAMESPACE::strfromd(buff, 100, "%e", 1.5); + EXPECT_STREQ_LEN(result, buff, "1.500000e+00"); + + result = LIBC_NAMESPACE::strfromd(buff, 100, "%e", 1e300); + EXPECT_STREQ_LEN(result, buff, "1.000000e+300"); + + result = LIBC_NAMESPACE::strfromd(buff, 100, "%e", 1234567890123456789.0); + EXPECT_STREQ_LEN(result, buff, "1.234568e+18"); + + // Precision Tests + result = LIBC_NAMESPACE::strfromd(buff, 100, "%.1e", 1.0); + EXPECT_STREQ_LEN(result, buff, "1.0e+00"); + + result = LIBC_NAMESPACE::strfromd(buff, 100, "%.1e", 1.99); + EXPECT_STREQ_LEN(result, buff, "2.0e+00"); + + result = LIBC_NAMESPACE::strfromd(buff, 100, "%.1e", 9.99); + EXPECT_STREQ_LEN(result, buff, "1.0e+01"); +} + +TEST_F(LlvmLibcStrfromdTest, DecimalAutoFormat) { + char buff[120]; + int result; + + result = LIBC_NAMESPACE::strfromd(buff, 100, "%g", 1234567890123456789.0); + EXPECT_STREQ_LEN(result, buff, "1.23457e+18"); + + result = LIBC_NAMESPACE::strfromd(buff, 100, "%g", 9999990000000.00); + EXPECT_STREQ_LEN(result, buff, "9.99999e+12"); + + result = LIBC_NAMESPACE::strfromd(buff, 100, "%g", 9999999000000.00); + EXPECT_STREQ_LEN(result, buff, "1e+13"); + + result = LIBC_NAMESPACE::strfromd(buff, 100, "%g", 0xa.aaaaaaaaaaaaaabp-7); + EXPECT_STREQ_LEN(result, buff, "0.0833333"); + + result = LIBC_NAMESPACE::strfromd(buff, 100, "%g", 0.00001); + EXPECT_STREQ_LEN(result, buff, "1e-05"); + + // Precision Tests + result = LIBC_NAMESPACE::strfromd(buff, 100, "%.0g", 0.0); + EXPECT_STREQ_LEN(result, buff, "0"); + + result = LIBC_NAMESPACE::strfromd(buff, 100, "%.2g", 0.1); + EXPECT_STREQ_LEN(result, buff, "0.1"); + + result = LIBC_NAMESPACE::strfromd(buff, 100, "%.2g", 1.09); + EXPECT_STREQ_LEN(result, buff, "1.1"); + + result = LIBC_NAMESPACE::strfromd(buff, 100, "%.15g", 22.25); + EXPECT_STREQ_LEN(result, buff, "22.25"); + + result = LIBC_NAMESPACE::strfromd(buff, 100, "%.20g", 1.234e-10); + EXPECT_STREQ_LEN(result, buff, "1.2340000000000000814e-10"); +} + +TEST_F(LlvmLibcStrfromdTest, InsufficientBufferSize) { + char buff[20]; + int result; + + result = LIBC_NAMESPACE::strfromd(buff, 5, "%f", 1234567890.0); + EXPECT_EQ(result, 17); + ASSERT_STREQ(buff, "1234"); + + result = LIBC_NAMESPACE::strfromd(buff, 5, "%.5f", 1.05); + EXPECT_EQ(result, 7); + ASSERT_STREQ(buff, "1.05"); + + result = LIBC_NAMESPACE::strfromd(buff, 0, "%g", 1.0); + EXPECT_EQ(result, 1); + ASSERT_STREQ(buff, "1.05"); // Make sure that buff has not changed +} + +TEST_F(LlvmLibcStrfromdTest, InfNanValues) { + char buff[15]; + int result; + + double inf = LIBC_NAMESPACE::fputil::FPBits::inf().get_val(); + double nan = LIBC_NAMESPACE::fputil::FPBits::quiet_nan().get_val(); + + result = LIBC_NAMESPACE::strfromd(buff, 10, "%f", inf); + EXPECT_STREQ_LEN(result, buff, "inf"); + + result = LIBC_NAMESPACE::strfromd(buff, 10, "%A", -inf); + EXPECT_STREQ_LEN(result, buff, "-INF"); + + result = LIBC_NAMESPACE::strfromd(buff, 10, "%f", nan); + EXPECT_STREQ_LEN(result, buff, "nan"); + + result = LIBC_NAMESPACE::strfromd(buff, 10, "%A", -nan); + EXPECT_STREQ_LEN(result, buff, "-NAN"); +} + +// https://github.com/llvm/llvm-project/issues/166795 +TEST_F(LlvmLibcStrfromdTest, ResultOverflow) { +#ifndef LIBC_TARGET_ARCH_IS_RISCV32 + char buff[100]; + // Trigger an overflow in the return value of strfromd by writing more than + // INT_MAX bytes. + int result = + LIBC_NAMESPACE::strfromd(buff, sizeof(buff), "%.2147483647f", 1.0); + + EXPECT_LT(result, 0); + ASSERT_ERRNO_FAILURE(); +#endif +} diff --git a/libc/test/src/stdlib/strfromf_test.cpp b/libc/test/src/stdlib/strfromf_test.cpp index 8b987fd434ac5..5baeb119bf150 100644 --- a/libc/test/src/stdlib/strfromf_test.cpp +++ b/libc/test/src/stdlib/strfromf_test.cpp @@ -6,8 +6,121 @@ // //===----------------------------------------------------------------------===// -#include "StrfromTest.h" +#include "src/__support/FPUtil/FPBits.h" +#include "src/__support/macros/properties/architectures.h" #include "src/stdlib/strfromf.h" +#include "test/UnitTest/ErrnoCheckingTest.h" +#include "test/UnitTest/ErrnoSetterMatcher.h" #include "test/UnitTest/Test.h" -STRFROM_TEST(float, StrFromf, LIBC_NAMESPACE::strfromf) +#define EXPECT_STREQ_LEN(str_size_needed, actual_str, expected_str) \ + EXPECT_EQ(str_size_needed, static_cast(sizeof(expected_str) - 1)); \ + EXPECT_STREQ(actual_str, expected_str); + +using LlvmLibcStrfromfTest = LIBC_NAMESPACE::testing::ErrnoCheckingTest; + +TEST_F(LlvmLibcStrfromfTest, DecimalFormat) { + char buff[70]; + int result; + + result = LIBC_NAMESPACE::strfromf(buff, 16, "%f", 1.0f); + EXPECT_STREQ_LEN(result, buff, "1.000000"); + + result = LIBC_NAMESPACE::strfromf(buff, 20, "%f", 1234567890.0f); + EXPECT_STREQ_LEN(result, buff, "1234567936.000000"); + + result = LIBC_NAMESPACE::strfromf(buff, 67, "%.3f", 1.0f); + EXPECT_STREQ_LEN(result, buff, "1.000"); +} + +TEST_F(LlvmLibcStrfromfTest, HexExponentFormat) { + char buff[25]; + int result; + + result = LIBC_NAMESPACE::strfromf(buff, 0, "%a", 1234567890.0f); + EXPECT_EQ(result, 14); + + result = LIBC_NAMESPACE::strfromf(buff, 20, "%a", 1234567890.0f); + EXPECT_EQ(result, 14); + ASSERT_STREQ(buff, "0x1.26580cp+30"); + + result = LIBC_NAMESPACE::strfromf(buff, 20, "%A", 1234567890.0f); + EXPECT_EQ(result, 14); + ASSERT_STREQ(buff, "0X1.26580CP+30"); +} + +TEST_F(LlvmLibcStrfromfTest, DecimalExponentFormat) { + char buff[25]; + int result; + + result = LIBC_NAMESPACE::strfromf(buff, 20, "%.9e", 1234567890.0f); + EXPECT_STREQ_LEN(result, buff, "1.234567936e+09"); + + result = LIBC_NAMESPACE::strfromf(buff, 20, "%.9E", 1234567890.0f); + EXPECT_STREQ_LEN(result, buff, "1.234567936E+09"); +} + +TEST_F(LlvmLibcStrfromfTest, DecimalAutoFormat) { + char buff[25]; + int result; + + result = LIBC_NAMESPACE::strfromf(buff, 20, "%.9g", 1234567890.0f); + EXPECT_STREQ_LEN(result, buff, "1.23456794e+09"); + + result = LIBC_NAMESPACE::strfromf(buff, 20, "%.9G", 1234567890.0f); + EXPECT_STREQ_LEN(result, buff, "1.23456794E+09"); +} + +TEST_F(LlvmLibcStrfromfTest, InsufficientBufferSize) { + char buff[20]; + int result; + + result = LIBC_NAMESPACE::strfromf(buff, 5, "%f", 1234567890.0f); + EXPECT_EQ(result, 17); + ASSERT_STREQ(buff, "1234"); + + result = LIBC_NAMESPACE::strfromf(buff, 5, "%.5f", 1.05f); + EXPECT_EQ(result, 7); + ASSERT_STREQ(buff, "1.05"); + + result = LIBC_NAMESPACE::strfromf(buff, 0, "%g", 1.0f); + EXPECT_EQ(result, 1); + ASSERT_STREQ(buff, "1.05"); // Make sure that buff has not changed +} + +// TODO: fix https://github.com/llvm/llvm-project/issues/217708. +#if 0 +TEST_F(LlvmLibcStrfromfTest, InfNanValues) { + char buff[15]; + int result; + + float inf = LIBC_NAMESPACE::fputil::FPBits::inf().get_val(); + float nan = LIBC_NAMESPACE::fputil::FPBits::quiet_nan().get_val(); + + result = LIBC_NAMESPACE::strfromf(buff, 10, "%f", inf); + EXPECT_STREQ_LEN(result, buff, "inf"); + + result = LIBC_NAMESPACE::strfromf(buff, 10, "%A", -inf); + EXPECT_STREQ_LEN(result, buff, "-INF"); + + result = LIBC_NAMESPACE::strfromf(buff, 10, "%f", nan); + EXPECT_STREQ_LEN(result, buff, "nan"); + + result = LIBC_NAMESPACE::strfromf(buff, 10, "%A", -nan); + EXPECT_STREQ_LEN(result, buff, "-NAN"); +} +#endif + +// https://github.com/llvm/llvm-project/issues/166795 +TEST_F(LlvmLibcStrfromfTest, ResultOverflow) { +#ifndef LIBC_TARGET_ARCH_IS_RISCV32 + char buff[100]; + // Trigger an overflow in the return value of strfromf by writing more than + // INT_MAX bytes. + int result = + LIBC_NAMESPACE::strfromf(buff, sizeof(buff), "%.2147483647f", 1.0f); + + EXPECT_LT(result, 0); + ASSERT_ERRNO_FAILURE(); +#endif +} diff --git a/libc/test/src/stdlib/strfroml_test.cpp b/libc/test/src/stdlib/strfroml_test.cpp index cf472a39a5bf8..5d36f1d1cfcbb 100644 --- a/libc/test/src/stdlib/strfroml_test.cpp +++ b/libc/test/src/stdlib/strfroml_test.cpp @@ -6,8 +6,164 @@ // //===----------------------------------------------------------------------===// -#include "StrfromTest.h" +#include "src/__support/FPUtil/FPBits.h" +#include "src/__support/macros/properties/architectures.h" #include "src/stdlib/strfroml.h" +#include "test/UnitTest/ErrnoCheckingTest.h" +#include "test/UnitTest/ErrnoSetterMatcher.h" #include "test/UnitTest/Test.h" -STRFROM_TEST(long double, Strfroml, LIBC_NAMESPACE::strfroml) +#define EXPECT_STREQ_LEN(str_size_needed, actual_str, expected_str) \ + EXPECT_EQ(str_size_needed, static_cast(sizeof(expected_str) - 1)); \ + EXPECT_STREQ(actual_str, expected_str); + +using LlvmLibcStrfromlTest = LIBC_NAMESPACE::testing::ErrnoCheckingTest; + +TEST_F(LlvmLibcStrfromlTest, DecimalFormat) { + char buff[45]; + int result; + + result = LIBC_NAMESPACE::strfroml(buff, 40, "%f", 1.0L); + EXPECT_STREQ_LEN(result, buff, "1.000000"); + + result = LIBC_NAMESPACE::strfroml(buff, 10, "%.f", -2.5L); + EXPECT_STREQ_LEN(result, buff, "-2"); +} + +TEST_F(LlvmLibcStrfromlTest, HexExponentFormat) { + char buff[55]; + int result; + + result = LIBC_NAMESPACE::strfroml(buff, 50, "%a", 0.1L); +#if defined(LIBC_TYPES_LONG_DOUBLE_IS_X86_FLOAT80) + EXPECT_STREQ_LEN(result, buff, "0xc.ccccccccccccccdp-7"); +#elif defined(LIBC_TYPES_LONG_DOUBLE_IS_FLOAT64) + EXPECT_STREQ_LEN(result, buff, "0x1.999999999999ap-4"); +#elif defined(LIBC_TYPES_LONG_DOUBLE_IS_FLOAT128) + EXPECT_STREQ_LEN(result, buff, "0x1.999999999999999999999999999ap-4"); +#endif + + result = LIBC_NAMESPACE::strfroml(buff, 20, "%.1a", 0.1L); +#if defined(LIBC_TYPES_LONG_DOUBLE_IS_X86_FLOAT80) + EXPECT_STREQ_LEN(result, buff, "0xc.dp-7"); +#elif defined(LIBC_TYPES_LONG_DOUBLE_IS_FLOAT64) + EXPECT_STREQ_LEN(result, buff, "0x1.ap-4"); +#elif defined(LIBC_TYPES_LONG_DOUBLE_IS_FLOAT128) + EXPECT_STREQ_LEN(result, buff, "0x1.ap-4"); +#endif + + result = LIBC_NAMESPACE::strfroml(buff, 50, "%a", 1.0e1000L); +#if defined(LIBC_TYPES_LONG_DOUBLE_IS_X86_FLOAT80) + EXPECT_STREQ_LEN(result, buff, "0xf.38db1f9dd3dac05p+3318"); +#elif defined(LIBC_TYPES_LONG_DOUBLE_IS_FLOAT64) + EXPECT_STREQ_LEN(result, buff, "inf"); +#elif defined(LIBC_TYPES_LONG_DOUBLE_IS_FLOAT128) + EXPECT_STREQ_LEN(result, buff, "0x1.e71b63f3ba7b580af1a52d2a7379p+3321"); +#endif + + result = LIBC_NAMESPACE::strfroml(buff, 50, "%a", 1.0e-1000L); +#if defined(LIBC_TYPES_LONG_DOUBLE_IS_X86_FLOAT80) + EXPECT_STREQ_LEN(result, buff, "0x8.68a9188a89e1467p-3325"); +#elif defined(LIBC_TYPES_LONG_DOUBLE_IS_FLOAT64) + EXPECT_STREQ_LEN(result, buff, "0x0p+0"); +#elif defined(LIBC_TYPES_LONG_DOUBLE_IS_FLOAT128) + EXPECT_STREQ_LEN(result, buff, "0x1.0d152311513c28ce202627c06ec2p-3322"); +#endif + + result = + LIBC_NAMESPACE::strfroml(buff, 50, "%.1a", 0xf.fffffffffffffffp16380L); +#if defined(LIBC_TYPES_LONG_DOUBLE_IS_X86_FLOAT80) + EXPECT_STREQ_LEN(result, buff, "0x1.0p+16384"); +#elif defined(LIBC_TYPES_LONG_DOUBLE_IS_FLOAT64) + EXPECT_STREQ_LEN(result, buff, "inf"); +#elif defined(LIBC_TYPES_LONG_DOUBLE_IS_FLOAT128) + EXPECT_STREQ_LEN(result, buff, "0x2.0p+16383"); +#endif +} + +TEST_F(LlvmLibcStrfromlTest, DecimalExponentFormat) { +#if defined(LIBC_TYPES_LONG_DOUBLE_IS_X86_FLOAT80) + char buff[100]; + int result; + + result = LIBC_NAMESPACE::strfroml(buff, 90, "%.9e", 1000000000500000000.1L); + EXPECT_STREQ_LEN(result, buff, "1.000000001e+18"); + + result = LIBC_NAMESPACE::strfroml(buff, 90, "%.9e", 1000000000500000000.0L); + EXPECT_STREQ_LEN(result, buff, "1.000000000e+18"); + + result = + LIBC_NAMESPACE::strfroml(buff, 90, "%e", 0xf.fffffffffffffffp+16380L); + EXPECT_STREQ_LEN(result, buff, "1.189731e+4932"); +#endif // LIBC_TYPES_LONG_DOUBLE_IS_X86_FLOAT80 +} + +TEST_F(LlvmLibcStrfromlTest, DecimalAutoFormat) { +#if defined(LIBC_TYPES_LONG_DOUBLE_IS_X86_FLOAT80) + char buff[100]; + int result; + + result = + LIBC_NAMESPACE::strfroml(buff, 99, "%g", 0xf.fffffffffffffffp+16380L); + EXPECT_STREQ_LEN(result, buff, "1.18973e+4932"); + + result = LIBC_NAMESPACE::strfroml(buff, 99, "%g", 0xa.aaaaaaaaaaaaaabp-7L); + EXPECT_STREQ_LEN(result, buff, "0.0833333"); + + result = LIBC_NAMESPACE::strfroml(buff, 99, "%g", 9.99999999999e-100L); + EXPECT_STREQ_LEN(result, buff, "1e-99"); +#endif // LIBC_TYPES_LONG_DOUBLE_IS_X86_FLOAT80 +} + +TEST_F(LlvmLibcStrfromlTest, InsufficientBufferSize) { + char buff[20]; + int result; + + result = LIBC_NAMESPACE::strfroml(buff, 5, "%f", 1234567890.0l); + EXPECT_EQ(result, 17); + ASSERT_STREQ(buff, "1234"); + + result = LIBC_NAMESPACE::strfroml(buff, 5, "%.5f", 1.05l); + EXPECT_EQ(result, 7); + ASSERT_STREQ(buff, "1.05"); + + result = LIBC_NAMESPACE::strfroml(buff, 0, "%g", 1.0l); + EXPECT_EQ(result, 1); + ASSERT_STREQ(buff, "1.05"); // Make sure that buff has not changed +} + +TEST_F(LlvmLibcStrfromlTest, InfNanValues) { + char buff[15]; + int result; + + long double inf = + LIBC_NAMESPACE::fputil::FPBits::inf().get_val(); + long double nan = + LIBC_NAMESPACE::fputil::FPBits::quiet_nan().get_val(); + + result = LIBC_NAMESPACE::strfroml(buff, 10, "%f", inf); + EXPECT_STREQ_LEN(result, buff, "inf"); + + result = LIBC_NAMESPACE::strfroml(buff, 10, "%A", -inf); + EXPECT_STREQ_LEN(result, buff, "-INF"); + + result = LIBC_NAMESPACE::strfroml(buff, 10, "%f", nan); + EXPECT_STREQ_LEN(result, buff, "nan"); + + result = LIBC_NAMESPACE::strfroml(buff, 10, "%A", -nan); + EXPECT_STREQ_LEN(result, buff, "-NAN"); +} + +// https://github.com/llvm/llvm-project/issues/166795 +TEST_F(LlvmLibcStrfromlTest, ResultOverflow) { +#ifndef LIBC_TARGET_ARCH_IS_RISCV32 + char buff[100]; + // Trigger an overflow in the return value of strfroml by writing more than + // INT_MAX bytes. + int result = + LIBC_NAMESPACE::strfroml(buff, sizeof(buff), "%.2147483647f", 1.0); + + EXPECT_LT(result, 0); + ASSERT_ERRNO_FAILURE(); +#endif +}