diff options
Diffstat (limited to 'js/src/jsapi-tests/testDecimalNumber.cpp')
-rw-r--r-- | js/src/jsapi-tests/testDecimalNumber.cpp | 289 |
1 files changed, 289 insertions, 0 deletions
diff --git a/js/src/jsapi-tests/testDecimalNumber.cpp b/js/src/jsapi-tests/testDecimalNumber.cpp new file mode 100644 index 0000000000..c63051523d --- /dev/null +++ b/js/src/jsapi-tests/testDecimalNumber.cpp @@ -0,0 +1,289 @@ +/* -*- 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/Span.h" + +#include <string_view> + +#include "builtin/intl/DecimalNumber.h" +#include "jsapi-tests/tests.h" + +using namespace js::intl; + +static mozilla::Maybe<js::intl::DecimalNumber> DecimalFrom( + std::string_view sv) { + auto span = mozilla::Span(reinterpret_cast<const JS::Latin1Char*>(sv.data()), + sv.length()); + return DecimalNumber::from(span); +} + +BEGIN_TEST(test_DecimalNumberParse) { + struct TestData { + std::string_view string; + bool success; + bool zero; + bool negative; + bool exponentTooLarge; + int32_t exponent; + size_t significandStart; + size_t significandEnd; + } tests[] = { + // "Infinity" and "NaN" aren't accepted. + {"Infinity", false}, + {"+Infinity", false}, + {"-Infinity", false}, + {"NaN", false}, + {"+NaN", false}, + {"-NaN", false}, + + // Non-decimal strings aren't accepted. + {"0xbad", false}, + {"0Xbad", false}, + {"0o0", false}, + {"0O0", false}, + {"0b0", false}, + {"0B0", false}, + + // Doesn't start with sign, digit, or decimal point. + {"e0", false}, + {"Hello", false}, + + // Incomplete number strings. + + // 1. Missing digit after sign. + {"+", false}, + {"+ ", false}, + {"+e0", false}, + {"-", false}, + {"- ", false}, + {"-e0", false}, + + // 2. Missing digit when starting with decimal point. + {".", false}, + {". ", false}, + {".e0", false}, + {"+.", false}, + {"+. ", false}, + {"+.e0", false}, + {"-.", false}, + {"-. ", false}, + {"-.e0", false}, + + // 3. Missing digit after exponent. + {"1e", false}, + {"1e ", false}, + {"1e+", false}, + {"1e+ ", false}, + {"1e-", false}, + {"1e- ", false}, + + // Empty and whitespace-only strings parse as zero. + {"", true, true, false, false, 0, 0, 0}, + {" ", true, true, false, false, 0, 0, 0}, + {" \t ", true, true, false, false, 0, 0, 0}, + + // Positive zero. + {"0", true, true, false, false, 0, 0, 0}, + {"0000", true, true, false, false, 0, 0, 0}, + {"0.0", true, true, false, false, 0, 0, 0}, + {"0.", true, true, false, false, 0, 0, 0}, + {".0", true, true, false, false, 0, 0, 0}, + {"0e0", true, true, false, false, 0, 0, 0}, + {"0e+1", true, true, false, false, 0, 0, 0}, + {"0e-1", true, true, false, false, 0, 0, 0}, + + {"+0", true, true, false, false, 0, 0, 0}, + {"+0000", true, true, false, false, 0, 0, 0}, + {"+0.0", true, true, false, false, 0, 0, 0}, + {"+0.", true, true, false, false, 0, 0, 0}, + {"+.0", true, true, false, false, 0, 0, 0}, + {"+0e0", true, true, false, false, 0, 0, 0}, + {"+0e+1", true, true, false, false, 0, 0, 0}, + {"+0e-1", true, true, false, false, 0, 0, 0}, + + // Negative zero. + {"-0", true, true, true, false, 0, 0, 0}, + {"-0000", true, true, true, false, 0, 0, 0}, + {"-0.0", true, true, true, false, 0, 0, 0}, + {"-0.", true, true, true, false, 0, 0, 0}, + {"-.0", true, true, true, false, 0, 0, 0}, + {"-0e0", true, true, true, false, 0, 0, 0}, + {"-0e+1", true, true, true, false, 0, 0, 0}, + {"-0e-1", true, true, true, false, 0, 0, 0}, + + // Integer numbers. + {"1", true, false, false, false, 1, 0, 1}, + {"10", true, false, false, false, 2, 0, 2}, + {"123", true, false, false, false, 3, 0, 3}, + {"123456789012345678901234567890", true, false, false, false, 30, 0, 30}, + {"1e100", true, false, false, false, 101, 0, 1}, + {"123e39", true, false, false, false, 42, 0, 3}, + + {"+1", true, false, false, false, 1, 1, 2}, + {"+10", true, false, false, false, 2, 1, 3}, + {"+123", true, false, false, false, 3, 1, 4}, + {"+123456789012345678901234567890", true, false, false, false, 30, 1, 31}, + {"+1e100", true, false, false, false, 101, 1, 2}, + {"+123e39", true, false, false, false, 42, 1, 4}, + + {"-1", true, false, true, false, 1, 1, 2}, + {"-10", true, false, true, false, 2, 1, 3}, + {"-123", true, false, true, false, 3, 1, 4}, + {"-123456789012345678901234567890", true, false, true, false, 30, 1, 31}, + {"-1e100", true, false, true, false, 101, 1, 2}, + {"-123e39", true, false, true, false, 42, 1, 4}, + + // Fractional numbers. + {"0.1", true, false, false, false, 0, 2, 3}, + {"0.01", true, false, false, false, -1, 3, 4}, + {"0.001", true, false, false, false, -2, 4, 5}, + {"1.001", true, false, false, false, 1, 0, 5}, + + {".1", true, false, false, false, 0, 1, 2}, + {".01", true, false, false, false, -1, 2, 3}, + {".001", true, false, false, false, -2, 3, 4}, + + {"+.1", true, false, false, false, 0, 2, 3}, + {"+.01", true, false, false, false, -1, 3, 4}, + {"+.001", true, false, false, false, -2, 4, 5}, + + {"-.1", true, false, true, false, 0, 2, 3}, + {"-.01", true, false, true, false, -1, 3, 4}, + {"-.001", true, false, true, false, -2, 4, 5}, + + // Fractional number with exponent part. + {".1e0", true, false, false, false, 0, 1, 2}, + {".01e0", true, false, false, false, -1, 2, 3}, + {".001e0", true, false, false, false, -2, 3, 4}, + + {".1e1", true, false, false, false, 1, 1, 2}, + {".01e1", true, false, false, false, 0, 2, 3}, + {".001e1", true, false, false, false, -1, 3, 4}, + + {".1e-1", true, false, false, false, -1, 1, 2}, + {".01e-1", true, false, false, false, -2, 2, 3}, + {".001e-1", true, false, false, false, -3, 3, 4}, + + {"1.1e0", true, false, false, false, 1, 0, 3}, + {"1.01e0", true, false, false, false, 1, 0, 4}, + {"1.001e0", true, false, false, false, 1, 0, 5}, + + {"1.1e1", true, false, false, false, 2, 0, 3}, + {"1.01e1", true, false, false, false, 2, 0, 4}, + {"1.001e1", true, false, false, false, 2, 0, 5}, + + {"1.1e-1", true, false, false, false, 0, 0, 3}, + {"1.01e-1", true, false, false, false, 0, 0, 4}, + {"1.001e-1", true, false, false, false, 0, 0, 5}, + + // Exponent too large. + // + // The exponent is limited to: |abs(exp) < 2147483648|. + {".1e2147483647", true, false, false, false, 2147483647, 1, 2}, + {".1e-2147483647", true, false, false, false, -2147483647, 1, 2}, + {"1e2147483646", true, false, false, false, 2147483647, 0, 1}, + {".01e-2147483646", true, false, false, false, -2147483647, 2, 3}, + {"1e2147483647", true, false, false, true, 0, 0, 1}, + {".1e2147483648", true, false, false, true, 0, 1, 2}, + {".1e-2147483648", true, false, false, true, 0, 1, 2}, + {".01e-2147483647", true, false, false, true, 0, 2, 3}, + }; + + for (const auto& test : tests) { + if (auto decimal = DecimalFrom(test.string)) { + CHECK(test.success); + CHECK_EQUAL(decimal->isZero(), test.zero); + CHECK_EQUAL(decimal->isNegative(), test.negative); + CHECK_EQUAL(decimal->exponentTooLarge(), test.exponentTooLarge); + CHECK_EQUAL(decimal->exponent(), test.exponent); + CHECK_EQUAL(decimal->significandStart(), test.significandStart); + CHECK_EQUAL(decimal->significandEnd(), test.significandEnd); + } else { + CHECK(!test.success); + } + } + + return true; +} +END_TEST(test_DecimalNumberParse) + +static int32_t NormalizeResult(int32_t r) { return r < 0 ? -1 : r > 0 ? 1 : 0; } + +BEGIN_TEST(test_DecimalNumberCompareTo) { + struct TestData { + std::string_view left; + std::string_view right; + int32_t result; + } tests[] = { + // Compare zeros. + {"0", "0", 0}, + {"-0", "-0", 0}, + {"-0", "+0", -1}, + {"+0", "-0", 1}, + + // Compare with different signs. + {"-1", "+1", -1}, + {"+1", "-1", 1}, + + // Compare zero against non-zero. + {"0", "+1", -1}, + {"0", "-1", 1}, + {"+1", "0", 1}, + {"-1", "0", -1}, + + // Compare with different exponent. + {"1", "0.1", 1}, + {"1e2", "1000", -1}, + {"-1", "-0.1", -1}, + {"-1e2", "-1000", 1}, + + // Compare with same exponent. + {"1", "2", -1}, + {"1", "1", 0}, + {"2", "1", 1}, + + // ToString(1e10) is "10000000000". + {"1e10", "10000000000", 0}, + {"1e10", "10000000001", -1}, + {"-1e10", "-10000000001", 1}, + + // ToString(1e30) is "1e+30". + {"1e30", "1000000000000000000000000000000", 0}, + {"1e30", "1000000000000000000000000000001", -1}, + {"-1e30", "-1000000000000000000000000000001", 1}, + + // ToString(1e-5) is "0.00001". + {"1e-5", "0.00001", 0}, + {"1e-5", "0.00002", -1}, + {"-1e-5", "-0.00002", 1}, + + // ToString(1e-10) is "1e-10". + {"1e-10", "0.0000000001", 0}, + {"1e-10", "0.0000000002", -1}, + {"-1e-10", "-0.0000000002", 1}, + + // Additional tests with exponent forms. + {"1.23e5", "123000", 0}, + {".123e-3", "0.000123", 0}, + {".123e+5", "12300", 0}, + {".00123e5", "123", 0}, + }; + + for (const auto& test : tests) { + auto left = DecimalFrom(test.left); + CHECK(left); + + auto right = DecimalFrom(test.right); + CHECK(right); + + int32_t result = left->compareTo(*right); + CHECK_EQUAL(NormalizeResult(result), test.result); + } + + return true; +} +END_TEST(test_DecimalNumberCompareTo) |