blob: 0f13b7cec8032bb3ce0feee8adfa4c33896f3884 [file]
//===-- Unittests for strfromd --------------------------------------------===//
//
// 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/strfromd.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 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<double>::inf().get_val();
double nan = LIBC_NAMESPACE::fputil::FPBits<double>::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
}