[libc-commits] [libc] [libc] Move strfrom* test cases into each respective unit test. (PR #218474)
Alex Strelnikov via libc-commits
libc-commits at lists.llvm.org
Tue Aug 25 06:49:55 PDT 2026
https://github.com/strel-12 updated https://github.com/llvm/llvm-project/pull/218474
>From 8db19061fce0b565e2e0cce57626ca695a013314 Mon Sep 17 00:00:00 2001
From: Alex Strelnikov <strel at google.com>
Date: Fri, 21 Aug 2026 18:19:46 +0000
Subject: [PATCH 1/3] Move strfrom* test cases out of shared helper library.
---
libc/test/src/stdlib/CMakeLists.txt | 19 +-
libc/test/src/stdlib/StrfromTest.h | 523 -------------------------
libc/test/src/stdlib/strfromd_test.cpp | 230 ++++++++++-
libc/test/src/stdlib/strfromf_test.cpp | 117 +++++-
libc/test/src/stdlib/strfroml_test.cpp | 164 +++++++-
5 files changed, 511 insertions(+), 542 deletions(-)
delete mode 100644 libc/test/src/stdlib/StrfromTest.h
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<int>(sizeof(expected_str) - 1)); \
- EXPECT_STREQ(actual_str, expected_str);
-
-template <typename InputT>
-class StrfromTest : public LIBC_NAMESPACE::testing::ErrnoCheckingTest {
-
- static constexpr bool is_single_prec =
- LIBC_NAMESPACE::cpp::is_same<InputT, float>::value;
- static constexpr bool is_double_prec =
- LIBC_NAMESPACE::cpp::is_same<InputT, double>::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<InputT>(1234567890.0));
- ASSERT_STREQ_LEN(written, buff, "%1f");
- }
-
- void insufficentBufsize(FunctionT func) {
- char buff[20];
- int written;
-
- written = func(buff, 5, "%f", static_cast<InputT>(1234567890.0));
- EXPECT_EQ(written, 17);
- ASSERT_STREQ(buff, "1234");
-
- written = func(buff, 5, "%.5f", static_cast<InputT>(1.05));
- EXPECT_EQ(written, 7);
- ASSERT_STREQ(buff, "1.05");
-
- written = func(buff, 0, "%g", static_cast<InputT>(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<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");
- }
-
- // 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<InputType>; \
- 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..277a461bfd68f 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<int>(sizeof(expected_str) - 1)); \
+ EXPECT_STREQ(actual_str, expected_str);
+
+struct 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
+}
diff --git a/libc/test/src/stdlib/strfromf_test.cpp b/libc/test/src/stdlib/strfromf_test.cpp
index 8b987fd434ac5..bd05e63ecc6d6 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<int>(sizeof(expected_str) - 1)); \
+ EXPECT_STREQ(actual_str, expected_str);
+
+struct 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<float>::inf().get_val();
+ float nan = LIBC_NAMESPACE::fputil::FPBits<float>::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..e9f1ce09d89ad 100644
--- a/libc/test/src/stdlib/strfroml_test.cpp
+++ b/libc/test/src/stdlib/strfroml_test.cpp
@@ -6,8 +6,168 @@
//
//===----------------------------------------------------------------------===//
-#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<int>(sizeof(expected_str) - 1)); \
+ EXPECT_STREQ(actual_str, expected_str);
+
+struct 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) {
+ // Mark as maybe_unused to silence unused variable
+ // warning when long double is not 80-bit
+ [[maybe_unused]] char buff[100];
+ [[maybe_unused]] int result;
+
+#if defined(LIBC_TYPES_LONG_DOUBLE_IS_X86_FLOAT80)
+ 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) {
+ // Mark as maybe_unused to silence unused variable
+ // warning when long double is not 80-bit
+ [[maybe_unused]] char buff[100];
+ [[maybe_unused]] int result;
+
+#if defined(LIBC_TYPES_LONG_DOUBLE_IS_X86_FLOAT80)
+ 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
+}
>From c46b04e8e27b3514212d30d40b71824d83da6ffb Mon Sep 17 00:00:00 2001
From: Alex Strelnikov <strel at google.com>
Date: Mon, 24 Aug 2026 18:13:34 +0000
Subject: [PATCH 2/3] uncomment #if
---
libc/test/src/stdlib/strfromf_test.cpp | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/libc/test/src/stdlib/strfromf_test.cpp b/libc/test/src/stdlib/strfromf_test.cpp
index bd05e63ecc6d6..4462602266608 100644
--- a/libc/test/src/stdlib/strfromf_test.cpp
+++ b/libc/test/src/stdlib/strfromf_test.cpp
@@ -89,7 +89,7 @@ TEST_F(LlvmLibcStrfromfTest, InsufficientBufferSize) {
}
// TODO: fix https://github.com/llvm/llvm-project/issues/217708.
-// #if 0
+#if 0
TEST_F(LlvmLibcStrfromfTest, InfNanValues) {
char buff[15];
int result;
@@ -109,7 +109,7 @@ TEST_F(LlvmLibcStrfromfTest, InfNanValues) {
result = LIBC_NAMESPACE::strfromf(buff, 10, "%A", -nan);
EXPECT_STREQ_LEN(result, buff, "-NAN");
}
-// #endif
+#endif
// https://github.com/llvm/llvm-project/issues/166795
TEST_F(LlvmLibcStrfromfTest, ResultOverflow) {
>From 3400d26544c65a7a8c1a16629b872d41f76a1570 Mon Sep 17 00:00:00 2001
From: Alex Strelnikov <strel at google.com>
Date: Tue, 25 Aug 2026 13:48:24 +0000
Subject: [PATCH 3/3] Apply code-review changes.
---
libc/test/src/stdlib/strfromd_test.cpp | 2 +-
libc/test/src/stdlib/strfromf_test.cpp | 2 +-
libc/test/src/stdlib/strfroml_test.cpp | 18 +++++++-----------
3 files changed, 9 insertions(+), 13 deletions(-)
diff --git a/libc/test/src/stdlib/strfromd_test.cpp b/libc/test/src/stdlib/strfromd_test.cpp
index 277a461bfd68f..0f13b7cec8032 100644
--- a/libc/test/src/stdlib/strfromd_test.cpp
+++ b/libc/test/src/stdlib/strfromd_test.cpp
@@ -17,7 +17,7 @@
EXPECT_EQ(str_size_needed, static_cast<int>(sizeof(expected_str) - 1)); \
EXPECT_STREQ(actual_str, expected_str);
-struct LlvmLibcStrfromdTest : LIBC_NAMESPACE::testing::ErrnoCheckingTest {};
+using LlvmLibcStrfromdTest = LIBC_NAMESPACE::testing::ErrnoCheckingTest;
TEST_F(LlvmLibcStrfromdTest, DecimalFormat) {
char buff[500];
diff --git a/libc/test/src/stdlib/strfromf_test.cpp b/libc/test/src/stdlib/strfromf_test.cpp
index 4462602266608..5baeb119bf150 100644
--- a/libc/test/src/stdlib/strfromf_test.cpp
+++ b/libc/test/src/stdlib/strfromf_test.cpp
@@ -17,7 +17,7 @@
EXPECT_EQ(str_size_needed, static_cast<int>(sizeof(expected_str) - 1)); \
EXPECT_STREQ(actual_str, expected_str);
-struct LlvmLibcStrfromfTest : LIBC_NAMESPACE::testing::ErrnoCheckingTest {};
+using LlvmLibcStrfromfTest = LIBC_NAMESPACE::testing::ErrnoCheckingTest;
TEST_F(LlvmLibcStrfromfTest, DecimalFormat) {
char buff[70];
diff --git a/libc/test/src/stdlib/strfroml_test.cpp b/libc/test/src/stdlib/strfroml_test.cpp
index e9f1ce09d89ad..5d36f1d1cfcbb 100644
--- a/libc/test/src/stdlib/strfroml_test.cpp
+++ b/libc/test/src/stdlib/strfroml_test.cpp
@@ -17,7 +17,7 @@
EXPECT_EQ(str_size_needed, static_cast<int>(sizeof(expected_str) - 1)); \
EXPECT_STREQ(actual_str, expected_str);
-struct LlvmLibcStrfromlTest : LIBC_NAMESPACE::testing::ErrnoCheckingTest {};
+using LlvmLibcStrfromlTest = LIBC_NAMESPACE::testing::ErrnoCheckingTest;
TEST_F(LlvmLibcStrfromlTest, DecimalFormat) {
char buff[45];
@@ -82,12 +82,10 @@ TEST_F(LlvmLibcStrfromlTest, HexExponentFormat) {
}
TEST_F(LlvmLibcStrfromlTest, DecimalExponentFormat) {
- // Mark as maybe_unused to silence unused variable
- // warning when long double is not 80-bit
- [[maybe_unused]] char buff[100];
- [[maybe_unused]] int result;
-
#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");
@@ -101,12 +99,10 @@ TEST_F(LlvmLibcStrfromlTest, DecimalExponentFormat) {
}
TEST_F(LlvmLibcStrfromlTest, DecimalAutoFormat) {
- // Mark as maybe_unused to silence unused variable
- // warning when long double is not 80-bit
- [[maybe_unused]] char buff[100];
- [[maybe_unused]] int result;
-
#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");
More information about the libc-commits
mailing list