/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- * vim: set ts=8 sts=2 et sw=2 tw=80: */ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #include "mozilla/FloatingPoint.h" // mozilla::{PositiveInfinity,UnspecifiedNaN} #include // size_t #include // memcmp, memset #include "js/Conversions.h" // JS::NumberToString, JS::MaximumNumberToStringLength #include "jsapi-tests/tests.h" // BEGIN_TEST, CHECK_EQUAL, END_TEST #include "util/Text.h" // js_strlen #define REST(x) x, (js_strlen(x)), __LINE__ static const struct NumberToStringTest { double number; const char* expected; size_t expectedLength; size_t lineno; } numberToStringTests[] = { {5e-324, REST("5e-324")}, // 2**-1074 {9.5367431640625e-7, REST("9.5367431640625e-7")}, // 2**-20 {0.0000010984284297360395, REST("0.0000010984284297360395")}, {0.0000019073486328125, REST("0.0000019073486328125")}, // 2**-19 {0.000003814697265625, REST("0.000003814697265625")}, // 2**-18 {0.0000057220458984375, REST("0.0000057220458984375")}, // 2**-18 + 2**-19 {0.000244140625, REST("0.000244140625")}, // 2**-12 {0.125, REST("0.125")}, {0.25, REST("0.25")}, {0.5, REST("0.5")}, {1, REST("1")}, {1.5, REST("1.5")}, {2, REST("2")}, {9, REST("9")}, {10, REST("10")}, {15, REST("15")}, {16, REST("16")}, {389427, REST("389427")}, {1073741823, REST("1073741823")}, {1073741824, REST("1073741824")}, {1073741825, REST("1073741825")}, {2147483647, REST("2147483647")}, {2147483648, REST("2147483648")}, {2147483649, REST("2147483649")}, {4294967294, REST("4294967294")}, {4294967295, REST("4294967295")}, {4294967296, REST("4294967296")}, {999999999999999900000.0, REST("999999999999999900000")}, {999999999999999900000.0 + 65535, REST("999999999999999900000")}, {999999999999999900000.0 + 65536, REST("1e+21")}, {1.7976931348623157e+308, REST("1.7976931348623157e+308")}, // MAX_VALUE }; static constexpr char PoisonChar = 0x37; struct StorageForNumberToString { char out[JS::MaximumNumberToStringLength]; char overflow; } storage; BEGIN_TEST(testNumberToString) { StorageForNumberToString storage; if (!testNormalValues(false, storage)) { return false; } if (!testNormalValues(true, storage)) { return false; } NumberToStringTest zeroTest = {0.0, REST("0")}; if (!testOne(zeroTest, false, storage)) { return false; } NumberToStringTest negativeZeroTest = {-0.0, REST("0")}; if (!testOne(negativeZeroTest, false, storage)) { return false; } NumberToStringTest infTest = {mozilla::PositiveInfinity(), REST("Infinity")}; if (!testOne(infTest, false, storage)) { return false; } if (!testOne(infTest, true, storage)) { return false; } NumberToStringTest nanTest = {mozilla::UnspecifiedNaN(), REST("NaN")}; return testOne(nanTest, false, storage); } bool testNormalValues(bool hasMinusSign, StorageForNumberToString& storage) { for (const auto& test : numberToStringTests) { if (!testOne(test, hasMinusSign, storage)) { return false; } } return true; } bool testOne(const NumberToStringTest& test, bool hasMinusSign, StorageForNumberToString& storage) { memset(&storage, PoisonChar, sizeof(storage)); JS::NumberToString(hasMinusSign ? -test.number : test.number, storage.out); CHECK_EQUAL(storage.overflow, PoisonChar); const char* start = storage.out; if (hasMinusSign) { CHECK_EQUAL(start[0], '-'); start++; } if (!checkEqual(memcmp(start, test.expected, test.expectedLength), 0, start, test.expected, __FILE__, test.lineno)) { return false; } char actualTerminator[] = {start[test.expectedLength], '\0'}; return checkEqual(actualTerminator[0], '\0', actualTerminator, "'\\0'", __FILE__, test.lineno); } END_TEST(testNumberToString) #undef REST