[libcxx-commits] [libcxx] [libc++] Refactor the <charconv> tests (PR #227611)

via libcxx-commits libcxx-commits at lists.llvm.org
Wed Sep 30 02:00:53 PDT 2026


llvmorg-github-actions[bot] wrote:


<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-libcxx

Author: Nikolas Klauser (philnik777)

<details>
<summary>Changes</summary>



---

Patch is 119.59 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/227611.diff


7 Files Affected:

- (modified) libcxx/test/std/utilities/charconv/charconv.from.chars/floating_point.pass.cpp (+930-932) 
- (removed) libcxx/test/std/utilities/charconv/charconv.from.chars/integral.bool.verify.cpp (-32) 
- (modified) libcxx/test/std/utilities/charconv/charconv.from.chars/integral.pass.cpp (+22-6) 
- (modified) libcxx/test/std/utilities/charconv/charconv.from.chars/integral.roundtrip.pass.cpp (+84-58) 
- (removed) libcxx/test/std/utilities/charconv/charconv.to.chars/integral.bool.verify.cpp (-32) 
- (modified) libcxx/test/std/utilities/charconv/charconv.to.chars/integral.pass.cpp (+367-232) 
- (modified) libcxx/test/support/charconv_test_helpers.h (+6-265) 


``````````diff
diff --git a/libcxx/test/std/utilities/charconv/charconv.from.chars/floating_point.pass.cpp b/libcxx/test/std/utilities/charconv/charconv.from.chars/floating_point.pass.cpp
index a02c7ac466f04..fa223785d758d 100644
--- a/libcxx/test/std/utilities/charconv/charconv.from.chars/floating_point.pass.cpp
+++ b/libcxx/test/std/utilities/charconv/charconv.from.chars/floating_point.pass.cpp
@@ -17,6 +17,7 @@
 //                              double& value, chars_format fmt = chars_format::general)
 
 #include <array>
+#include <cassert>
 #include <charconv>
 #include <cmath>
 #include <cstring>
@@ -24,8 +25,8 @@
 #include <stdexcept>
 #include <system_error>
 
-#include "charconv_test_helpers.h"
 #include "test_macros.h"
+#include "type_algorithms.h"
 
 template <class F>
 void test_infinity(std::chars_format fmt) {
@@ -326,1193 +327,1183 @@ void test_fmt_independent(std::chars_format fmt) {
 }
 
 template <class F>
-struct test_basics {
-  void operator()() {
-    for (auto fmt : {std::chars_format::scientific,
-                     std::chars_format::fixed,
-                     /*std::chars_format::hex,*/ std::chars_format::general})
-      test_fmt_independent<F>(fmt);
-  }
-};
+void test_basics() {
+  for (auto fmt : {std::chars_format::scientific,
+                   std::chars_format::fixed,
+                   /*std::chars_format::hex,*/ std::chars_format::general})
+    test_fmt_independent<F>(fmt);
+}
 
 template <class F>
-struct test_fixed {
-  void operator()() {
-    std::from_chars_result r;
-    F x = 0.25;
+void test_fixed() {
+  std::from_chars_result r;
+  F x = 0.25;
 
-    // *** Failures
+  // *** Failures
 
-    { // Starts with invalid character
-      std::array s = {' ', '1'};
-      for (auto c : "abcdefghijklmnopqrstuvwxyz"
-                    "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
-                    "`~!@#$%^&*()_=[]{}\\|;:'\",/<>? \t\v\r\n") {
-        s[0] = c;
-        r    = std::from_chars(s.data(), s.data() + s.size(), x, std::chars_format::fixed);
+  { // Starts with invalid character
+    std::array s = {' ', '1'};
+    for (auto c : "abcdefghijklmnopqrstuvwxyz"
+                  "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
+                  "`~!@#$%^&*()_=[]{}\\|;:'\",/<>? \t\v\r\n") {
+      s[0] = c;
+      r    = std::from_chars(s.data(), s.data() + s.size(), x, std::chars_format::fixed);
 
-        assert(r.ec == std::errc::invalid_argument);
-        assert(r.ptr == s.data());
-        assert(x == F(0.25));
-      }
+      assert(r.ec == std::errc::invalid_argument);
+      assert(r.ptr == s.data());
+      assert(x == F(0.25));
     }
+  }
 
-    // *** Success
+  // *** Success
 
-    { // number followed by non-numeric values
-      const char* s = "001x";
+  { // number followed by non-numeric values
+    const char* s = "001x";
 
-      // the expected form of the subject sequence is a nonempty sequence of
-      // decimal digits optionally containing a decimal-point character, then
-      // an optional exponent part as defined in 6.4.4.3, excluding any digit
-      // separators (6.4.4.2); (C23 7.24.1.5)
-      r = std::from_chars(s, s + std::strlen(s), x, std::chars_format::fixed);
-      assert(r.ec == std::errc{});
-      assert(r.ptr == s + 3);
-      assert(x == F(1.0));
-    }
-    { // no leading digit
-      const char* s = ".5";
+    // the expected form of the subject sequence is a nonempty sequence of
+    // decimal digits optionally containing a decimal-point character, then
+    // an optional exponent part as defined in 6.4.4.3, excluding any digit
+    // separators (6.4.4.2); (C23 7.24.1.5)
+    r = std::from_chars(s, s + std::strlen(s), x, std::chars_format::fixed);
+    assert(r.ec == std::errc{});
+    assert(r.ptr == s + 3);
+    assert(x == F(1.0));
+  }
+  { // no leading digit
+    const char* s = ".5";
+
+    // the expected form of the subject sequence is a nonempty sequence of
+    // decimal digits optionally containing a decimal-point character, then
+    // an optional exponent part as defined in 6.4.4.3, excluding any digit
+    // separators (6.4.4.2); (C23 7.24.1.5)
+    r = std::from_chars(s, s + std::strlen(s), x, std::chars_format::fixed);
+    assert(r.ec == std::errc{});
+    assert(r.ptr == s + 2);
+    assert(x == F(0.5));
+  }
+  { // negative sign and no leading digit
+    const char* s = "-.5";
+
+    // the expected form of the subject sequence is a nonempty sequence of
+    // decimal digits optionally containing a decimal-point character, then
+    // an optional exponent part as defined in 6.4.4.3, excluding any digit
+    // separators (6.4.4.2); (C23 7.24.1.5)
+    r = std::from_chars(s, s + std::strlen(s), x, std::chars_format::fixed);
+    assert(r.ec == std::errc{});
+    assert(r.ptr == s + 3);
+    assert(x == F(-0.5));
+  }
 
-      // the expected form of the subject sequence is a nonempty sequence of
-      // decimal digits optionally containing a decimal-point character, then
-      // an optional exponent part as defined in 6.4.4.3, excluding any digit
-      // separators (6.4.4.2); (C23 7.24.1.5)
-      r = std::from_chars(s, s + std::strlen(s), x, std::chars_format::fixed);
-      assert(r.ec == std::errc{});
-      assert(r.ptr == s + 2);
-      assert(x == F(0.5));
-    }
-    { // negative sign and no leading digit
-      const char* s = "-.5";
+  { // double decimal point
+    const char* s = "1.25.78";
 
-      // the expected form of the subject sequence is a nonempty sequence of
-      // decimal digits optionally containing a decimal-point character, then
-      // an optional exponent part as defined in 6.4.4.3, excluding any digit
-      // separators (6.4.4.2); (C23 7.24.1.5)
-      r = std::from_chars(s, s + std::strlen(s), x, std::chars_format::fixed);
-      assert(r.ec == std::errc{});
-      assert(r.ptr == s + 3);
-      assert(x == F(-0.5));
-    }
+    // This number is halfway between two float values.
+    r = std::from_chars(s, s + std::strlen(s), x, std::chars_format::fixed);
+    assert(r.ec == std::errc{});
+    assert(r.ptr == s + 4);
+    assert(x == F(1.25));
+  }
+  { // exponent no sign
+    const char* s = "1.5e10";
+    r             = std::from_chars(s, s + std::strlen(s), x, std::chars_format::fixed);
+
+    assert(r.ec == std::errc{});
+    assert(r.ptr == s + 3);
+    assert(x == F(1.5));
+  }
+  { // exponent capitalized no sign
+    const char* s = "1.5E10";
+    r             = std::from_chars(s, s + std::strlen(s), x, std::chars_format::fixed);
+
+    assert(r.ec == std::errc{});
+    assert(r.ptr == s + 3);
+    assert(x == F(1.5));
+  }
+  { // exponent + sign
+    const char* s = "1.5e+10";
+    r             = std::from_chars(s, s + std::strlen(s), x, std::chars_format::fixed);
+
+    assert(r.ec == std::errc{});
+    assert(r.ptr == s + 3);
+    assert(x == F(1.5));
+  }
+  { // exponent - sign
+    const char* s = "1.5e-10";
+    r             = std::from_chars(s, s + std::strlen(s), x, std::chars_format::fixed);
+
+    assert(r.ec == std::errc{});
+    assert(r.ptr == s + 3);
+    assert(x == F(1.5));
+  }
+  { // Exponent no number
+    const char* s = "1.5e";
 
-    { // double decimal point
-      const char* s = "1.25.78";
+    r = std::from_chars(s, s + std::strlen(s), x, std::chars_format::fixed);
+    assert(r.ec == std::errc{});
+    assert(r.ptr == s + 3);
+    assert(x == F(1.5));
+  }
+  { // Exponent sign no number
+    {
+      const char* s = "1.5e+";
 
-      // This number is halfway between two float values.
       r = std::from_chars(s, s + std::strlen(s), x, std::chars_format::fixed);
       assert(r.ec == std::errc{});
-      assert(r.ptr == s + 4);
-      assert(x == F(1.25));
+      assert(r.ptr == s + 3);
+      assert(x == F(1.5));
     }
-    { // exponent no sign
-      const char* s = "1.5e10";
-      r             = std::from_chars(s, s + std::strlen(s), x, std::chars_format::fixed);
+    {
+      const char* s = "1.5e-";
 
+      r = std::from_chars(s, s + std::strlen(s), x, std::chars_format::fixed);
       assert(r.ec == std::errc{});
       assert(r.ptr == s + 3);
       assert(x == F(1.5));
     }
-    { // exponent capitalized no sign
-      const char* s = "1.5E10";
-      r             = std::from_chars(s, s + std::strlen(s), x, std::chars_format::fixed);
+  }
+  { // Exponent with whitespace
+    {
+      const char* s = "1.5e +1";
 
+      r = std::from_chars(s, s + std::strlen(s), x, std::chars_format::fixed);
       assert(r.ec == std::errc{});
       assert(r.ptr == s + 3);
       assert(x == F(1.5));
     }
-    { // exponent + sign
-      const char* s = "1.5e+10";
-      r             = std::from_chars(s, s + std::strlen(s), x, std::chars_format::fixed);
+    {
+      const char* s = "1.5e+ 1";
 
+      r = std::from_chars(s, s + std::strlen(s), x, std::chars_format::fixed);
       assert(r.ec == std::errc{});
       assert(r.ptr == s + 3);
       assert(x == F(1.5));
     }
-    { // exponent - sign
-      const char* s = "1.5e-10";
-      r             = std::from_chars(s, s + std::strlen(s), x, std::chars_format::fixed);
+    {
+      const char* s = "1.5e -1";
 
+      r = std::from_chars(s, s + std::strlen(s), x, std::chars_format::fixed);
       assert(r.ec == std::errc{});
       assert(r.ptr == s + 3);
       assert(x == F(1.5));
     }
-    { // Exponent no number
-      const char* s = "1.5e";
+    {
+      const char* s = "1.5e- 1";
 
       r = std::from_chars(s, s + std::strlen(s), x, std::chars_format::fixed);
       assert(r.ec == std::errc{});
       assert(r.ptr == s + 3);
       assert(x == F(1.5));
     }
-    { // Exponent sign no number
-      {
-        const char* s = "1.5e+";
-
-        r = std::from_chars(s, s + std::strlen(s), x, std::chars_format::fixed);
-        assert(r.ec == std::errc{});
-        assert(r.ptr == s + 3);
-        assert(x == F(1.5));
-      }
-      {
-        const char* s = "1.5e-";
-
-        r = std::from_chars(s, s + std::strlen(s), x, std::chars_format::fixed);
-        assert(r.ec == std::errc{});
-        assert(r.ptr == s + 3);
-        assert(x == F(1.5));
-      }
-    }
-    { // Exponent with whitespace
-      {
-        const char* s = "1.5e +1";
-
-        r = std::from_chars(s, s + std::strlen(s), x, std::chars_format::fixed);
-        assert(r.ec == std::errc{});
-        assert(r.ptr == s + 3);
-        assert(x == F(1.5));
-      }
-      {
-        const char* s = "1.5e+ 1";
-
-        r = std::from_chars(s, s + std::strlen(s), x, std::chars_format::fixed);
-        assert(r.ec == std::errc{});
-        assert(r.ptr == s + 3);
-        assert(x == F(1.5));
-      }
-      {
-        const char* s = "1.5e -1";
-
-        r = std::from_chars(s, s + std::strlen(s), x, std::chars_format::fixed);
-        assert(r.ec == std::errc{});
-        assert(r.ptr == s + 3);
-        assert(x == F(1.5));
-      }
-      {
-        const char* s = "1.5e- 1";
-
-        r = std::from_chars(s, s + std::strlen(s), x, std::chars_format::fixed);
-        assert(r.ec == std::errc{});
-        assert(r.ptr == s + 3);
-        assert(x == F(1.5));
-      }
-    }
-    { // double exponent
-      const char* s = "1.25e0e12";
-      r             = std::from_chars(s, s + std::strlen(s), x, std::chars_format::fixed);
+  }
+  { // double exponent
+    const char* s = "1.25e0e12";
+    r             = std::from_chars(s, s + std::strlen(s), x, std::chars_format::fixed);
 
+    assert(r.ec == std::errc{});
+    assert(r.ptr == s + 4);
+    assert(x == F(1.25));
+  }
+  { // Exponent double sign
+    {
+      const char* s = "1.25e++12";
+
+      r = std::from_chars(s, s + std::strlen(s), x, std::chars_format::fixed);
       assert(r.ec == std::errc{});
       assert(r.ptr == s + 4);
       assert(x == F(1.25));
     }
-    { // Exponent double sign
-      {
-        const char* s = "1.25e++12";
-
-        r = std::from_chars(s, s + std::strlen(s), x, std::chars_format::fixed);
-        assert(r.ec == std::errc{});
-        assert(r.ptr == s + 4);
-        assert(x == F(1.25));
-      }
-      {
-        const char* s = "1.25e+-12";
-
-        r = std::from_chars(s, s + std::strlen(s), x, std::chars_format::fixed);
-        assert(r.ec == std::errc{});
-        assert(r.ptr == s + 4);
-        assert(x == F(1.25));
-      }
-      {
-        const char* s = "1.25e-+12";
-
-        r = std::from_chars(s, s + std::strlen(s), x, std::chars_format::fixed);
-        assert(r.ec == std::errc{});
-        assert(r.ptr == s + 4);
-        assert(x == F(1.25));
-      }
-      {
-        const char* s = "1.25e--12";
-
-        r = std::from_chars(s, s + std::strlen(s), x, std::chars_format::fixed);
-        assert(r.ec == std::errc{});
-        assert(r.ptr == s + 4);
-        assert(x == F(1.25));
-      }
-    }
-    { // exponent hex prefix
-      const char* s = "1.25e0x12";
+    {
+      const char* s = "1.25e+-12";
 
       r = std::from_chars(s, s + std::strlen(s), x, std::chars_format::fixed);
       assert(r.ec == std::errc{});
       assert(r.ptr == s + 4);
       assert(x == F(1.25));
     }
-    { // This number is halfway between two float values.
-      const char* s = "20040229";
+    {
+      const char* s = "1.25e-+12";
 
       r = std::from_chars(s, s + std::strlen(s), x, std::chars_format::fixed);
       assert(r.ec == std::errc{});
-      assert(r.ptr == s + 8);
-      assert(x == F(20040229));
+      assert(r.ptr == s + 4);
+      assert(x == F(1.25));
     }
-    { // Shifting mantissa exponent and no exponent
-      const char* s = "123.456";
+    {
+      const char* s = "1.25e--12";
 
       r = std::from_chars(s, s + std::strlen(s), x, std::chars_format::fixed);
       assert(r.ec == std::errc{});
-      assert(r.ptr == s + 7);
-      assert(x == F(1.23456e2));
+      assert(r.ptr == s + 4);
+      assert(x == F(1.25));
     }
-    { // Shifting mantissa exponent and an exponent
-      const char* s = "123.456e3";
-      r             = std::from_chars(s, s + std::strlen(s), x, std::chars_format::fixed);
+  }
+  { // exponent hex prefix
+    const char* s = "1.25e0x12";
 
+    r = std::from_chars(s, s + std::strlen(s), x, std::chars_format::fixed);
+    assert(r.ec == std::errc{});
+    assert(r.ptr == s + 4);
+    assert(x == F(1.25));
+  }
+  { // This number is halfway between two float values.
+    const char* s = "20040229";
+
+    r = std::from_chars(s, s + std::strlen(s), x, std::chars_format::fixed);
+    assert(r.ec == std::errc{});
+    assert(r.ptr == s + 8);
+    assert(x == F(20040229));
+  }
+  { // Shifting mantissa exponent and no exponent
+    const char* s = "123.456";
+
+    r = std::from_chars(s, s + std::strlen(s), x, std::chars_format::fixed);
+    assert(r.ec == std::errc{});
+    assert(r.ptr == s + 7);
+    assert(x == F(1.23456e2));
+  }
+  { // Shifting mantissa exponent and an exponent
+    const char* s = "123.456e3";
+    r             = std::from_chars(s, s + std::strlen(s), x, std::chars_format::fixed);
+
+    assert(r.ec == std::errc{});
+    assert(r.ptr == s + 7);
+    assert(x == F(123.456));
+  }
+  { // Mantissa overflow
+    {
+      const char* s = "0.111111111111111111111111111111111111111111";
+
+      r = std::from_chars(s, s + std::strlen(s), x, std::chars_format::fixed);
       assert(r.ec == std::errc{});
-      assert(r.ptr == s + 7);
-      assert(x == F(123.456));
-    }
-    { // Mantissa overflow
-      {
-        const char* s = "0.111111111111111111111111111111111111111111";
-
-        r = std::from_chars(s, s + std::strlen(s), x, std::chars_format::fixed);
-        assert(r.ec == std::errc{});
-        assert(r.ptr == s + std::strlen(s));
-        assert(x == F(0.111111111111111111111111111111111111111111));
-      }
-      {
-        const char* s = "111111111111.111111111111111111111111111111111111111111";
-
-        r = std::from_chars(s, s + std::strlen(s), x, std::chars_format::fixed);
-        assert(r.ec == std::errc{});
-        assert(r.ptr == s + std::strlen(s));
-        assert(x == F(111111111111.111111111111111111111111111111111111111111));
-      }
-    }
-    { // Negative value
-      const char* s = "-0.25";
+      assert(r.ptr == s + std::strlen(s));
+      assert(x == F(0.111111111111111111111111111111111111111111));
+    }
+    {
+      const char* s = "111111111111.111111111111111111111111111111111111111111";
 
       r = std::from_chars(s, s + std::strlen(s), x, std::chars_format::fixed);
       assert(r.ec == std::errc{});
       assert(r.ptr == s + std::strlen(s));
-      assert(x == F(-0.25));
+      assert(x == F(111111111111.111111111111111111111111111111111111111111));
     }
   }
-};
+  { // Negative value
+    const char* s = "-0.25";
+
+    r = std::from_chars(s, s + std::strlen(s), x, std::chars_format::fixed);
+    assert(r.ec == std::errc{});
+    assert(r.ptr == s + std::strlen(s));
+    assert(x == F(-0.25));
+  }
+}
 
 template <class F>
-struct test_scientific {
-  void operator()() {
-    std::from_chars_result r;
-    F x = 0.25;
+void test_scientific() {
+  std::from_chars_result r;
+  F x = 0.25;
 
-    // *** Failures
+  // *** Failures
 
-    { // Starts with invalid character
-      std::array s = {' ', '1', 'e', '0'};
-      for (auto c : "abcdefghijklmnopqrstuvwxyz"
-                    "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
-                    "`~!@#$%^&*()_=[]{}\\|;:'\",/<>? \t\v\r\n") {
-        s[0] = c;
-        r    = std::from_chars(s.data(), s.data() + s.size(), x, std::chars_format::scientific);
+  { // Starts with invalid character
+    std::array s = {' ', '1', 'e', '0'};
+    for (auto c : "abcdefghijklmnopqrstuvwxyz"
+                  "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
+                  "`~!@#$%^&*()_=[]{}\\|;:'\",/<>? \t\v\r\n") {
+      s[0] = c;
+      r    = std::from_chars(s.data(), s.data() + s.size(), x, std::chars_format::scientific);
 
-        assert(r.ec == std::errc::invalid_argument);
-        assert(r.ptr == s.data());
-        assert(x == F(0.25));
-      }
+      assert(r.ec == std::errc::invalid_argument);
+      assert(r.ptr == s.data());
+      assert(x == F(0.25));
     }
-    { // No exponent
-      const char* s = "1.23";
-      r             = std::from_chars(s, s + strlen(s), x, std::chars_format::scientific);
+  }
+  { // No exponent
+    const char* s = "1.23";
+    r             = std::from_chars(s, s + strlen(s), x, std::chars_format::scientific);
 
+    assert(r.ec == std::errc::invalid_argument);
+    assert(r.ptr == s);
+    assert(x == F(0.25));
+  }
+  { // Exponent no number
+    const char* s = "1.23e";
+    r             = std::from_chars(s, s + strlen(s), x, std::chars_format::scientific);
+
+    assert(r.ec == std::errc::invalid_argument);
+    assert(r.ptr == s);
+    assert(x == F(0.25));
+  }
+  { // Exponent sign no number
+    {
+      const char* s = "1.5e+";
+
+      r = std::from_chars(s, s + std::strlen(s), x, std::chars_format::scientific);
       assert(r.ec == std::errc::invalid_argument);
       assert(r.ptr == s);
       assert(x == F(0.25));
     }
-    { // Exponent no number
-      const char* s = "1.23e";
-      r             = std::from_chars(s, s + strlen(s), x, std::chars_format::scientific);
+    {
+      const char* s = "1.5e-";
 
+      r = std::from_chars(s, s + std::strlen(s), x, std::chars_format::scientific);
       assert(r.ec == std::errc::invalid_argument);
       assert(r.ptr == s);
       assert(x == F(0.25));
     }
-    { // Exponent sign no number
-      {
-        const char* s = "1.5e+";
-
-        r = std::from_chars(s, s + std::strlen(s), x, std::chars_format::scientific);
-        assert(r.ec == std::errc::invalid_argument);
-        assert(r.ptr == s);
-        assert(x == F(0.25));
-      }
-      {
-        const char* s = "1.5e-";
-
-        r = std::from_chars(s, s + std::strlen(s), x, std::chars_format::scientific);
-        assert(r.ec == std::errc::invalid_argument);
-        assert(r.ptr == s);
-        assert(x == F(0.25));
-      }
-    }
-    { // Exponent with whitespace
-      {
-        const char* s = "1.5e +1";
-
-        r = std::from_chars(s, s + std::strlen(s), x, std::chars_format::scientific);
-        assert(r.ec == std::errc::invalid_argument);
-        assert(r.ptr == s);
-        assert(x == F(0.25));
-      }
-      {
-        const char* s = "1.5e+ 1";
-
-        r = std::from_chars(s, s + std::strlen(s), x, std::chars_format::scientific);
-        assert(r.ec == std::errc::invalid_argument);
-        assert(r.ptr == s);
-        assert(x == F(0.25));
-  ...
[truncated]

``````````

</details>


https://github.com/llvm/llvm-project/pull/227611


More information about the libcxx-commits mailing list