| //===-- Unittests for strfroml --------------------------------------------===// | |
| // | |
| // 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/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" | |
| #define EXPECT_STREQ_LEN(str_size_needed, actual_str, expected_str) \ | |
| EXPECT_EQ(str_size_needed, static_cast<int>(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<long double>::inf().get_val(); | |
| long double nan = | |
| LIBC_NAMESPACE::fputil::FPBits<long double>::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 | |
| } |