Skip to content

[libc] Add inf/nan tests for strfrom*() functions #86663

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Mar 28, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions libc/test/src/stdlib/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -174,6 +174,7 @@ add_header_library(
StrfromTest.h
DEPENDS
libc.src.__support.CPP.type_traits
libc.src.__support.FPUtil.fp_bits
)

add_libc_test(
Expand Down
79 changes: 72 additions & 7 deletions libc/test/src/stdlib/StrfromTest.h
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
//===----------------------------------------------------------------------===//

#include "src/__support/CPP/type_traits.h"
#include "src/__support/FPUtil/FPBits.h"
#include "test/UnitTest/Test.h"

#define ASSERT_STREQ_LEN(actual_written, actual_str, expected_str) \
Expand Down Expand Up @@ -71,8 +72,18 @@ class StrfromTest : public LIBC_NAMESPACE::testing::Test {
written =
func(buff, 37,
"%A simple string with one conversion, should overwrite.", 1.0);
ASSERT_STREQ_LEN(written, buff, is_long_double ? "0X8P-3" : "0X1P+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",
Expand Down Expand Up @@ -105,6 +116,13 @@ class StrfromTest : public LIBC_NAMESPACE::testing::Test {
ASSERT_STREQ(buff, "1.05"); // Make sure that buff has not changed
}

void infNanValues(FunctionT func) {
if (is_double_prec)
doublePrecInfNan(func);
else if (!is_single_prec)
longDoublePrecInfNan(func);
}

void floatDecimalSinglePrec(FunctionT func) {
char buff[70];
int written;
Expand Down Expand Up @@ -336,8 +354,10 @@ class StrfromTest : public LIBC_NAMESPACE::testing::Test {
}

void floatDecimalExpLongDoublePrec(FunctionT func) {
char buff[100];
int written;
// 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);
Expand Down Expand Up @@ -399,8 +419,10 @@ class StrfromTest : public LIBC_NAMESPACE::testing::Test {
}

void floatDecimalAutoLongDoublePrec(FunctionT func) {
char buff[100];
int written;
// 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);
Expand All @@ -413,6 +435,48 @@ class StrfromTest : public LIBC_NAMESPACE::testing::Test {
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<double>::inf().get_val();
double nan = LIBC_NAMESPACE::fputil::FPBits<double>::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<long double>::inf().get_val();
long double ld_nan =
LIBC_NAMESPACE::fputil::FPBits<long double>::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");
}
};

#define STRFROM_TEST(InputType, name, func) \
Expand All @@ -432,4 +496,5 @@ class StrfromTest : public LIBC_NAMESPACE::testing::Test {
} \
TEST_F(LlvmLibc##name##Test, InsufficientBufferSize) { \
insufficentBufsize(func); \
}
} \
TEST_F(LlvmLibc##name##Test, InfAndNanValues) { infNanValues(func); }