1 //===-- Unittests for strtod ---------------------------------------------===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 
9 #include "src/__support/FPUtil/FPBits.h"
10 #include "src/stdlib/strtod.h"
11 
12 #include "utils/UnitTest/Test.h"
13 
14 #include <errno.h>
15 #include <limits.h>
16 #include <stddef.h>
17 
18 class LlvmLibcStrToDTest : public __llvm_libc::testing::Test {
19 public:
20   void runTest(const char *inputString, const ptrdiff_t expectedStrLen,
21                const uint64_t expectedRawData, const int expectedErrno = 0) {
22     // expectedRawData is the expected double result as a uint64_t, organized
23     // according to IEEE754:
24     //
25     // +-- 1 Sign Bit                        +-- 52 Mantissa bits
26     // |                                     |
27     // |           +-------------------------+------------------------+
28     // |           |                                                  |
29     // SEEEEEEEEEEEMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM
30     //  |         |
31     //  +----+----+
32     //       |
33     //       +-- 11 Exponent Bits
34     //
35     //  This is so that the result can be compared in parts.
36     char *strEnd = nullptr;
37 
38     __llvm_libc::fputil::FPBits<double> expectedFP =
39         __llvm_libc::fputil::FPBits<double>(expectedRawData);
40 
41     errno = 0;
42     double result = __llvm_libc::strtod(inputString, &strEnd);
43 
44     __llvm_libc::fputil::FPBits<double> actualFP =
45         __llvm_libc::fputil::FPBits<double>(result);
46 
47     EXPECT_EQ(strEnd - inputString, expectedStrLen);
48 
49     EXPECT_EQ(actualFP.bits, expectedFP.bits);
50     EXPECT_EQ(actualFP.get_sign(), expectedFP.get_sign());
51     EXPECT_EQ(actualFP.get_exponent(), expectedFP.get_exponent());
52     EXPECT_EQ(actualFP.get_mantissa(), expectedFP.get_mantissa());
53     EXPECT_EQ(errno, expectedErrno);
54   }
55 };
56 
57 TEST_F(LlvmLibcStrToDTest, SimpleTest) {
58   runTest("123", 3, uint64_t(0x405ec00000000000));
59 
60   // This should fail on Eisel-Lemire, forcing a fallback to simple decimal
61   // conversion.
62   runTest("12345678901234549760", 20, uint64_t(0x43e56a95319d63d8));
63 
64   // Found while looking for difficult test cases here:
65   // https://github.com/nigeltao/parse-number-fxx-test-data/blob/main/more-test-cases/golang-org-issue-36657.txt
66   runTest("1090544144181609348835077142190", 31, uint64_t(0x462b8779f2474dfb));
67 
68   runTest("0x123", 5, uint64_t(0x4072300000000000));
69 }
70 
71 // These are tests that have caused problems in the past.
72 TEST_F(LlvmLibcStrToDTest, SpecificFailures) {
73   runTest("3E70000000000000", 16, uint64_t(0x7FF0000000000000), ERANGE);
74   runTest("358416272e-33", 13, uint64_t(0x3adbbb2a68c9d0b9));
75   runTest("2.16656806400000023841857910156251e9", 36,
76           uint64_t(0x41e0246690000001));
77   runTest("27949676547093071875", 20, uint64_t(0x43f83e132bc608c9));
78 }
79 
80 TEST_F(LlvmLibcStrToDTest, FuzzFailures) {
81   runTest("-\xff\xff\xff\xff\xff\xff\xff\x01", 0, uint64_t(0));
82   runTest("-.????", 0, uint64_t(0));
83   runTest("44444444444444444444444444444444444444444444444444A44444444444444444"
84           "44444444444*\x99\xff\xff\xff\xff",
85           50, uint64_t(0x4a3e68fdd0e0b2d8));
86   runTest("-NNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNKNNNNNNNNNNNNNNNNNN?"
87           "NNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNN?",
88           0, uint64_t(0));
89   runTest("0x.666E40", 9, uint64_t(0x3fd99b9000000000));
90 }
91