This makes the hexadecimal section of the long double std::to_chars
testcase more robust by avoiding false-negative FAILs due to printf
using a different leading hex digit than us, and by additionally
verifying the correctness of the hexadecimal form via round-tripping
through std::from_chars.

Tested on x86, x86_64, powerpc64be, powerpc64le and aarch64.  Does this
look OK for trunk?

libstdc++-v3/ChangeLog:

        PR libstdc++/98384
        * testsuite/20_util/to_chars/long_double.cc: Include <optional>.
        (test01): Simplify verifying the nearby values by using a
        2-iteration loop and a dedicated output buffer to check that the
        nearby values are different.  Factor out the printf-based
        verification into a local function, and check that the leading
        hex digits agree before comparing with the output of printf.
        Also verify the output by round-tripping it through from_chars.
---
 .../testsuite/20_util/to_chars/long_double.cc | 73 ++++++++++++-------
 1 file changed, 47 insertions(+), 26 deletions(-)

diff --git a/libstdc++-v3/testsuite/20_util/to_chars/long_double.cc 
b/libstdc++-v3/testsuite/20_util/to_chars/long_double.cc
index 4f72cb65400..34cc03034cc 100644
--- a/libstdc++-v3/testsuite/20_util/to_chars/long_double.cc
+++ b/libstdc++-v3/testsuite/20_util/to_chars/long_double.cc
@@ -26,6 +26,7 @@
 #include <cmath>
 #include <cstring>
 #include <iterator>
+#include <optional>
 #include <limits>
 
 #include <testsuite_hooks.h>
@@ -50,6 +51,38 @@ namespace detail
 void
 test01()
 {
+  // Verifies correctness of the hexadecimal form [BEGIN,END) for VALUE by
+  // round-tripping it through from_chars (if available).
+  auto verify_via_from_chars = [] (char *begin, char *end, long double value) {
+#if __cpp_lib_to_chars >= 201611L || _GLIBCXX_HAVE_USELOCALE
+    long double roundtrip;
+    auto result = from_chars(begin, end, roundtrip, chars_format::hex);
+    VERIFY( result.ec == errc{} );
+    VERIFY( result.ptr == end );
+    VERIFY( roundtrip == value );
+#endif
+  };
+
+  // Verifies correctness of the null-terminated hexadecimal form at BEGIN
+  // for VALUE and PRECISION by comparing it with the output of printf's %La
+  // conversion specifier.
+  auto verify_via_printf = [] (char *begin, long double value,
+                              optional<int> precision = nullopt) {
+    char printf_buffer[1024] = {};
+    if (precision.has_value())
+      sprintf(printf_buffer, "%.*La", precision.value(), value);
+    else
+      sprintf(printf_buffer, "%La", value);
+
+    // Only compare with the output of printf if the leading hex digits agree.
+    // If the leading hex digit of our form doesn't agree with that of printf,
+    // then the two forms may still be equivalent (e.g. 1.1p+0 vs 8.8p-3), so 
we
+    // don't want a FAIL in this case.  But if the leading hex digits do agree,
+    // then we do expect the two forms to be the same.
+    if (printf_buffer[strlen("0x")] == begin[0])
+      VERIFY( !strcmp(begin, printf_buffer+strlen("0x")) );
+  };
+
   const long double hex_testcases[]
     = { detail::nextdownl(numeric_limits<long double>::max()),
        detail::nextupl(numeric_limits<long double>::min()),
@@ -92,38 +125,27 @@ test01()
        if (testcase == 0.0L || isinf(testcase))
          continue;
 
-       char to_chars_buffer[1024], printf_buffer[1024];
-       memset(to_chars_buffer, '\0', sizeof(to_chars_buffer));
-       memset(printf_buffer, '\0', sizeof(printf_buffer));
-
+       char to_chars_buffer[1024] = {};
        auto result = to_chars(begin(to_chars_buffer), end(to_chars_buffer),
                               testcase, chars_format::hex);
        VERIFY( result.ec == errc{} );
        *result.ptr = '\0';
-       sprintf(printf_buffer, "%La", testcase);
-       VERIFY( !strcmp(to_chars_buffer, printf_buffer+strlen("0x")) );
+       verify_via_from_chars(begin(to_chars_buffer), result.ptr, testcase);
+       verify_via_printf(to_chars_buffer, testcase);
 
+       // Verify the nearby values, and also check they have a different
+       // shortest form.
+       for (long double nearby
+            : { detail::nextdownl(testcase), detail::nextupl(testcase) })
          {
-           // Verify that the nearby values have a different shortest form.
-           testcase = detail::nextdownl(testcase);
-           result = to_chars(begin(to_chars_buffer), end(to_chars_buffer),
-                             testcase, chars_format::hex);
-           VERIFY( result.ec == errc{} );
-           *result.ptr = '\0';
-           VERIFY( strcmp(to_chars_buffer, printf_buffer+strlen("0x")) != 0);
-           sprintf(printf_buffer, "%La", testcase);
-           VERIFY( !strcmp(to_chars_buffer, printf_buffer+strlen("0x")) );
-
-           testcase = detail::nextupl(detail::nextupl(testcase));
-           result = to_chars(begin(to_chars_buffer), end(to_chars_buffer),
-                             testcase, chars_format::hex);
+           char nearby_buffer[1024] = {};
+           result = to_chars(begin(nearby_buffer), end(nearby_buffer),
+                             nearby, chars_format::hex);
            VERIFY( result.ec == errc{} );
            *result.ptr = '\0';
-           VERIFY( strcmp(to_chars_buffer, printf_buffer+strlen("0x")) != 0);
-           sprintf(printf_buffer, "%La", testcase);
-           VERIFY( !strcmp(to_chars_buffer, printf_buffer+strlen("0x")) );
-
-           testcase = detail::nextdownl(testcase);
+           VERIFY( strcmp(nearby_buffer, to_chars_buffer) != 0);
+           verify_via_from_chars(begin(nearby_buffer), result.ptr, nearby);
+           verify_via_printf(nearby_buffer, nearby);
          }
 
        for (int precision = -1; precision < 50; precision++)
@@ -132,8 +154,7 @@ test01()
                              testcase, chars_format::hex, precision);
            VERIFY( result.ec == errc{} );
            *result.ptr = '\0';
-           sprintf(printf_buffer, "%.*La", precision, testcase);
-           VERIFY( !strcmp(to_chars_buffer, printf_buffer+strlen("0x")) );
+           verify_via_printf(to_chars_buffer, testcase, precision);
          }
       }
 }
-- 
2.30.1.559.g2283e0e9af

Reply via email to