[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