tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

testBigInt.cpp (24257B)


      1 /* This Source Code Form is subject to the terms of the Mozilla Public
      2 * License, v. 2.0. If a copy of the MPL was not distributed with this
      3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
      4 
      5 #include "mozilla/FloatingPoint.h"  // mozilla::NumberIsInt32
      6 #include "mozilla/Range.h"          // mozilla::Range
      7 #include "mozilla/Span.h"           // mozilla::MakeStringSpan
      8 
      9 #include <stdint.h>
     10 
     11 #include "js/BigInt.h"  // JS::{,Number,String,SimpleString}ToBigInt, JS::ToBig{I,Ui}nt64
     12 #include "js/CharacterEncoding.h"  // JS::Const{Latin1,TwoByte}Chars
     13 #include "js/Conversions.h"        // JS::ToString
     14 #include "js/ErrorReport.h"        // JS::ErrorReportBuilder, JSEXN_SYNTAXERR
     15 #include "js/Exception.h"  // JS::StealPendingExceptionStack, JS_IsExceptionPending
     16 #include "js/friend/ErrorMessages.h"  // JSMSG_*
     17 #include "js/RootingAPI.h"            // JS::Rooted
     18 #include "js/String.h"                // JS_StringEqualsLiteral
     19 #include "js/Value.h"                 // JS::FalseValue, JS::Value
     20 
     21 #include "jsapi-tests/tests.h"
     22 #include "util/Text.h"  // js::InflateString
     23 
     24 struct JS_PUBLIC_API JSContext;
     25 class JS_PUBLIC_API JSString;
     26 
     27 namespace JS {
     28 
     29 class JS_PUBLIC_API BigInt;
     30 
     31 }  // namespace JS
     32 
     33 BEGIN_TEST(testToBigInt64) {
     34  JS::Rooted<JS::Value> v(cx);
     35 
     36  EVAL("0n", &v);
     37  CHECK(v.isBigInt());
     38  CHECK(JS::ToBigInt64(v.toBigInt()) == 0);
     39 
     40  EVAL("9223372036854775807n", &v);
     41  CHECK(v.isBigInt());
     42  CHECK(JS::ToBigInt64(v.toBigInt()) == 9223372036854775807L);
     43 
     44  EVAL("-9223372036854775808n", &v);
     45  CHECK(v.isBigInt());
     46  CHECK(JS::ToBigInt64(v.toBigInt()) == -9223372036854775807L - 1L);
     47 
     48  return true;
     49 }
     50 END_TEST(testToBigInt64)
     51 
     52 BEGIN_TEST(testToBigUint64) {
     53  JS::Rooted<JS::Value> v(cx);
     54 
     55  EVAL("0n", &v);
     56  CHECK(v.isBigInt());
     57  CHECK(JS::ToBigUint64(v.toBigInt()) == 0);
     58 
     59  EVAL("18446744073709551615n", &v);
     60  CHECK(v.isBigInt());
     61  CHECK(JS::ToBigUint64(v.toBigInt()) == 18446744073709551615UL);
     62 
     63  return true;
     64 }
     65 END_TEST(testToBigUint64)
     66 
     67 #define GENERATE_INTTYPE_TEST(bits)             \
     68  BEGIN_TEST(testNumberToBigInt_Int##bits) {    \
     69    int##bits##_t i = INT##bits##_MIN;          \
     70    JS::BigInt* bi = JS::NumberToBigInt(cx, i); \
     71    CHECK(bi);                                  \
     72    CHECK(JS::ToBigInt64(bi) == i);             \
     73                                                \
     74    i = INT##bits##_MAX;                        \
     75    bi = JS::NumberToBigInt(cx, i);             \
     76    CHECK(bi);                                  \
     77    CHECK(JS::ToBigInt64(bi) == i);             \
     78                                                \
     79    uint##bits##_t u = 0;                       \
     80    bi = JS::NumberToBigInt(cx, u);             \
     81    CHECK(bi);                                  \
     82    CHECK(JS::ToBigUint64(bi) == 0);            \
     83                                                \
     84    u = UINT##bits##_MAX;                       \
     85    bi = JS::NumberToBigInt(cx, u);             \
     86    CHECK(bi);                                  \
     87    CHECK(JS::ToBigUint64(bi) == u);            \
     88                                                \
     89    return true;                                \
     90  }                                             \
     91  END_TEST(testNumberToBigInt_Int##bits)
     92 
     93 GENERATE_INTTYPE_TEST(8);
     94 GENERATE_INTTYPE_TEST(16);
     95 GENERATE_INTTYPE_TEST(32);
     96 GENERATE_INTTYPE_TEST(64);
     97 
     98 #undef GENERATE_INTTYPE_TEST
     99 
    100 #define GENERATE_SIGNED_VALUE_TEST(type, tag, val) \
    101  BEGIN_TEST(testNumberToBigInt_##type##_##tag) {  \
    102    type v = val;                                  \
    103    JS::BigInt* bi = JS::NumberToBigInt(cx, v);    \
    104    CHECK(bi);                                     \
    105    CHECK(JS::ToBigInt64(bi) == (val));            \
    106    return true;                                   \
    107  }                                                \
    108  END_TEST(testNumberToBigInt_##type##_##tag)
    109 
    110 #define GENERATE_UNSIGNED_VALUE_TEST(type, tag, val) \
    111  BEGIN_TEST(testNumberToBigInt_##type##_##tag) {    \
    112    type v = val;                                    \
    113    JS::BigInt* bi = JS::NumberToBigInt(cx, v);      \
    114    CHECK(bi);                                       \
    115    CHECK(JS::ToBigUint64(bi) == (val));             \
    116    return true;                                     \
    117  }                                                  \
    118  END_TEST(testNumberToBigInt_##type##_##tag)
    119 
    120 GENERATE_SIGNED_VALUE_TEST(int, zero, 0);
    121 GENERATE_SIGNED_VALUE_TEST(int, aValue, -42);
    122 GENERATE_UNSIGNED_VALUE_TEST(unsigned, zero, 0);
    123 GENERATE_UNSIGNED_VALUE_TEST(unsigned, aValue, 42);
    124 GENERATE_SIGNED_VALUE_TEST(long, zero, 0);
    125 GENERATE_SIGNED_VALUE_TEST(long, aValue, -42);
    126 GENERATE_UNSIGNED_VALUE_TEST(uintptr_t, zero, 0);
    127 GENERATE_UNSIGNED_VALUE_TEST(uintptr_t, aValue, 42);
    128 GENERATE_UNSIGNED_VALUE_TEST(size_t, zero, 0);
    129 GENERATE_UNSIGNED_VALUE_TEST(size_t, aValue, 42);
    130 GENERATE_SIGNED_VALUE_TEST(double, zero, 0);
    131 GENERATE_SIGNED_VALUE_TEST(double, aValue, -42);
    132 
    133 #undef GENERATE_SIGNED_VALUE_TEST
    134 #undef GENERATE_UNSIGNED_VALUE_TEST
    135 
    136 BEGIN_TEST(testNumberToBigInt_bool) {
    137  JS::BigInt* bi = JS::NumberToBigInt(cx, true);
    138  CHECK(bi);
    139  CHECK(JS::ToBigUint64(bi) == 1);
    140 
    141  bi = JS::NumberToBigInt(cx, false);
    142  CHECK(bi);
    143  CHECK(JS::ToBigUint64(bi) == 0);
    144 
    145  return true;
    146 }
    147 END_TEST(testNumberToBigInt_bool)
    148 
    149 BEGIN_TEST(testNumberToBigInt_NonIntegerValueFails) {
    150  JS::BigInt* bi = JS::NumberToBigInt(cx, 3.1416);
    151  CHECK_NULL(bi);
    152  CHECK(JS_IsExceptionPending(cx));
    153  JS_ClearPendingException(cx);
    154  return true;
    155 }
    156 END_TEST(testNumberToBigInt_NonIntegerValueFails)
    157 
    158 BEGIN_TEST(testStringToBigInt_FromTwoByteStringSpan) {
    159  mozilla::Range<const char16_t> input{
    160      mozilla::MakeStringSpan(u"18446744073709551616")};
    161  JS::BigInt* bi = JS::StringToBigInt(cx, input);
    162  CHECK(bi);
    163  JS::Rooted<JS::Value> val(cx, JS::BigIntValue(bi));
    164  JS::Rooted<JSString*> str(cx, JS::ToString(cx, val));
    165  CHECK(str);
    166  bool match;
    167  CHECK(JS_StringEqualsLiteral(cx, str, "18446744073709551616", &match));
    168  CHECK(match);
    169  return true;
    170 }
    171 END_TEST(testStringToBigInt_FromTwoByteStringSpan)
    172 
    173 BEGIN_TEST(testStringToBigInt_FromLatin1Range) {
    174  const JS::Latin1Char string[] = "12345 and some junk at the end";
    175  JS::ConstLatin1Chars range(string, 5);
    176  JS::BigInt* bi = JS::StringToBigInt(cx, range);
    177  CHECK(bi);
    178  CHECK(JS::ToBigInt64(bi) == 12345);
    179  return true;
    180 }
    181 END_TEST(testStringToBigInt_FromLatin1Range)
    182 
    183 BEGIN_TEST(testStringToBigInt_FromTwoByteRange) {
    184  const char16_t string[] = u"12345 and some junk at the end";
    185  JS::ConstTwoByteChars range(string, 5);
    186  JS::BigInt* bi = JS::StringToBigInt(cx, range);
    187  CHECK(bi);
    188  CHECK(JS::ToBigInt64(bi) == 12345);
    189  return true;
    190 }
    191 END_TEST(testStringToBigInt_FromTwoByteRange)
    192 
    193 BEGIN_TEST(testStringToBigInt_AcceptedInput) {
    194  CHECK(Allowed(u"", 0));
    195  CHECK(Allowed(u"\n", 0));
    196  CHECK(Allowed(u" ", 0));
    197  CHECK(Allowed(u"0\n", 0));
    198  CHECK(Allowed(u"0 ", 0));
    199  CHECK(Allowed(u"\n1", 1));
    200  CHECK(Allowed(u" 1", 1));
    201  CHECK(Allowed(u"\n2 ", 2));
    202  CHECK(Allowed(u" 2\n", 2));
    203  CHECK(Allowed(u"0b11", 3));
    204  CHECK(Allowed(u"0x17", 23));
    205  CHECK(Allowed(u"-5", -5));
    206  CHECK(Allowed(u"+5", 5));
    207  CHECK(Allowed(u"-0", 0));
    208 
    209  CHECK(Fails(u"!!!!!!111one1111one1!1!1!!"));
    210  CHECK(Fails(u"3.1416"));
    211  CHECK(Fails(u"6.022e23"));
    212  CHECK(Fails(u"1e3"));
    213  CHECK(Fails(u".25"));
    214  CHECK(Fails(u".25e2"));
    215  CHECK(Fails(u"1_000_000"));
    216  CHECK(Fails(u"3n"));
    217  CHECK(Fails(u"-0x3"));
    218  CHECK(Fails(u"Infinity"));
    219 
    220  return true;
    221 }
    222 
    223 template <size_t N>
    224 inline bool Allowed(const char16_t (&str)[N], int64_t expected) {
    225  JS::BigInt* bi = JS::StringToBigInt(cx, mozilla::MakeStringSpan(str));
    226  CHECK(bi);
    227  CHECK(JS::ToBigInt64(bi) == expected);
    228  return true;
    229 }
    230 
    231 template <size_t N>
    232 inline bool Fails(const char16_t (&str)[N]) {
    233  JS::BigInt* bi = JS::StringToBigInt(cx, mozilla::MakeStringSpan(str));
    234  CHECK_NULL(bi);
    235  CHECK(JS_IsExceptionPending(cx));
    236 
    237  JS::ExceptionStack exnStack(cx);
    238  CHECK(JS::StealPendingExceptionStack(cx, &exnStack));
    239 
    240  JS::ErrorReportBuilder report(cx);
    241  CHECK(report.init(cx, exnStack, JS::ErrorReportBuilder::NoSideEffects));
    242  CHECK(report.report()->exnType == JSEXN_SYNTAXERR);
    243  CHECK(report.report()->errorNumber == JSMSG_BIGINT_INVALID_SYNTAX);
    244 
    245  CHECK(!JS_IsExceptionPending(cx));
    246 
    247  return true;
    248 }
    249 END_TEST(testStringToBigInt_AcceptedInput)
    250 
    251 BEGIN_TEST(testSimpleStringToBigInt_AcceptedInput) {
    252  CHECK(Allowed("12345", 10, 12345));
    253  CHECK(Allowed("+12345", 10, 12345));
    254  CHECK(Allowed("-12345", 10, -12345));
    255  CHECK(Allowed("775", 8, 0775));
    256  CHECK(Allowed("+775", 8, 0775));
    257  CHECK(Allowed("-775", 8, -0775));
    258  CHECK(Allowed("cAfE", 16, 0xCAFE));
    259  CHECK(Allowed("+cAfE", 16, +0xCAFE));
    260  CHECK(Allowed("-cAfE", 16, -0xCAFE));
    261  CHECK(Allowed("-0", 10, 0));
    262 
    263  CHECK(Fails("", 10));
    264  CHECK(Fails("\n", 10));
    265  CHECK(Fails(" ", 10));
    266  CHECK(Fails("0\n", 10));
    267  CHECK(Fails("0 ", 10));
    268  CHECK(Fails("\n1", 10));
    269  CHECK(Fails(" 1", 10));
    270  CHECK(Fails("\n2 ", 10));
    271  CHECK(Fails(" 2\n", 10));
    272  CHECK(Fails("0b11", 2));
    273  CHECK(Fails("0x17", 16));
    274  CHECK(Fails("!!!!!!111one1111one1!1!1!!", 10));
    275  CHECK(Fails("3.1416", 10));
    276  CHECK(Fails("6.022e23", 10));
    277  CHECK(Fails("1e3", 10));
    278  CHECK(Fails(".25", 10));
    279  CHECK(Fails(".25e2", 10));
    280  CHECK(Fails("1_000_000", 10));
    281  CHECK(Fails("3n", 10));
    282  CHECK(Fails("-0x3", 10));
    283  CHECK(Fails("Infinity", 10));
    284  CHECK(Fails("555", 4));
    285  CHECK(Fails("fff", 15));
    286 
    287  return true;
    288 }
    289 
    290 template <size_t N>
    291 inline bool Allowed(const char (&str)[N], unsigned radix, int64_t expected) {
    292  JS::BigInt* bi = JS::SimpleStringToBigInt(cx, {str, N - 1}, radix);
    293  CHECK(bi);
    294  CHECK(JS::ToBigInt64(bi) == expected);
    295  return true;
    296 }
    297 
    298 template <size_t N>
    299 inline bool Fails(const char (&str)[N], unsigned radix) {
    300  JS::BigInt* bi = JS::SimpleStringToBigInt(cx, {str, N - 1}, radix);
    301  CHECK_NULL(bi);
    302  CHECK(JS_IsExceptionPending(cx));
    303 
    304  JS::ExceptionStack exnStack(cx);
    305  CHECK(JS::StealPendingExceptionStack(cx, &exnStack));
    306 
    307  JS::ErrorReportBuilder report(cx);
    308  CHECK(report.init(cx, exnStack, JS::ErrorReportBuilder::NoSideEffects));
    309  CHECK(report.report()->exnType == JSEXN_SYNTAXERR);
    310  CHECK(report.report()->errorNumber == JSMSG_BIGINT_INVALID_SYNTAX);
    311 
    312  CHECK(!JS_IsExceptionPending(cx));
    313 
    314  return true;
    315 }
    316 END_TEST(testSimpleStringToBigInt_AcceptedInput)
    317 
    318 BEGIN_TEST(testSimpleStringToBigInt_AllPossibleDigits) {
    319  const char allPossible[] =
    320      "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890";
    321  JS::BigInt* bi =
    322      JS::SimpleStringToBigInt(cx, mozilla::MakeStringSpan(allPossible), 36);
    323  CHECK(bi);
    324  JS::Rooted<JS::Value> val(cx, JS::BigIntValue(bi));
    325  JS::Rooted<JSString*> str(cx, JS::ToString(cx, val));
    326  CHECK(str);
    327 
    328  // Answer calculated using Python:
    329  // int('abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890', 36)
    330  // Do not trust online base-36 calculators for values > UINT32_MAX!
    331  bool match;
    332  CHECK(
    333      JS_StringEqualsLiteral(cx, str,
    334                             "8870050151210747660007771095260505028056221996735"
    335                             "67534007158336222790086855213834764150805438340",
    336                             &match));
    337  CHECK(match);
    338  return true;
    339 }
    340 END_TEST(testSimpleStringToBigInt_AllPossibleDigits)
    341 
    342 BEGIN_TEST(testSimpleStringToBigInt_RadixOutOfRange) {
    343  CHECK(RadixOutOfRange(1));
    344  CHECK(RadixOutOfRange(37));
    345  return true;
    346 }
    347 
    348 inline bool RadixOutOfRange(unsigned radix) {
    349  JS::BigInt* bi =
    350      JS::SimpleStringToBigInt(cx, mozilla::MakeStringSpan("1"), radix);
    351  CHECK_NULL(bi);
    352  CHECK(JS_IsExceptionPending(cx));
    353 
    354  JS::ExceptionStack exnStack(cx);
    355  CHECK(JS::StealPendingExceptionStack(cx, &exnStack));
    356 
    357  JS::ErrorReportBuilder report(cx);
    358  CHECK(report.init(cx, exnStack, JS::ErrorReportBuilder::NoSideEffects));
    359  CHECK(report.report()->exnType == JSEXN_RANGEERR);
    360  CHECK(report.report()->errorNumber == JSMSG_BAD_RADIX);
    361 
    362  CHECK(!JS_IsExceptionPending(cx));
    363 
    364  return true;
    365 }
    366 END_TEST(testSimpleStringToBigInt_RadixOutOfRange)
    367 
    368 BEGIN_TEST(testToBigInt_Undefined) {
    369  JS::Rooted<JS::Value> v(cx, JS::UndefinedValue());
    370  JS::BigInt* bi = JS::ToBigInt(cx, v);
    371  CHECK_NULL(bi);
    372  CHECK(JS_IsExceptionPending(cx));
    373  JS_ClearPendingException(cx);
    374  return true;
    375 }
    376 END_TEST(testToBigInt_Undefined)
    377 
    378 BEGIN_TEST(testToBigInt_Null) {
    379  JS::Rooted<JS::Value> v(cx, JS::NullValue());
    380  JS::BigInt* bi = JS::ToBigInt(cx, v);
    381  CHECK_NULL(bi);
    382  CHECK(JS_IsExceptionPending(cx));
    383  JS_ClearPendingException(cx);
    384  return true;
    385 }
    386 END_TEST(testToBigInt_Null)
    387 
    388 BEGIN_TEST(testToBigInt_Boolean) {
    389  JS::Rooted<JS::Value> v(cx, JS::TrueValue());
    390  JS::BigInt* bi = JS::ToBigInt(cx, v);
    391  CHECK(bi);
    392  CHECK(JS::ToBigInt64(bi) == 1);
    393 
    394  v = JS::FalseValue();
    395  bi = JS::ToBigInt(cx, v);
    396  CHECK(bi);
    397  CHECK(JS::ToBigInt64(bi) == 0);
    398 
    399  return true;
    400 }
    401 END_TEST(testToBigInt_Boolean)
    402 
    403 BEGIN_TEST(testToBigInt_BigInt) {
    404  JS::Rooted<JS::Value> v(cx);
    405  EVAL("42n", &v);
    406  JS::BigInt* bi = JS::ToBigInt(cx, v);
    407  CHECK(bi);
    408  CHECK(JS::ToBigInt64(bi) == 42);
    409  return true;
    410 }
    411 END_TEST(testToBigInt_BigInt)
    412 
    413 BEGIN_TEST(testToBigInt_Number) {
    414  JS::Rooted<JS::Value> v(cx, JS::Int32Value(42));
    415  JS::BigInt* bi = JS::ToBigInt(cx, v);
    416  CHECK_NULL(bi);
    417  CHECK(JS_IsExceptionPending(cx));
    418  JS_ClearPendingException(cx);
    419  return true;
    420 }
    421 END_TEST(testToBigInt_Number)
    422 
    423 BEGIN_TEST(testToBigInt_String) {
    424  JS::Rooted<JS::Value> v(cx);
    425  EVAL("'42'", &v);
    426  JS::BigInt* bi = JS::ToBigInt(cx, v);
    427  CHECK(bi);
    428  CHECK(JS::ToBigInt64(bi) == 42);
    429  return true;
    430 }
    431 END_TEST(testToBigInt_String)
    432 
    433 BEGIN_TEST(testToBigInt_Symbol) {
    434  JS::Rooted<JS::Value> v(cx);
    435  EVAL("Symbol.toStringTag", &v);
    436  JS::BigInt* bi = JS::ToBigInt(cx, v);
    437  CHECK_NULL(bi);
    438  CHECK(JS_IsExceptionPending(cx));
    439  JS_ClearPendingException(cx);
    440  return true;
    441 }
    442 END_TEST(testToBigInt_Symbol)
    443 
    444 BEGIN_TEST(testBigIntToNumber) {
    445  JS::BigInt* bi = JS::NumberToBigInt(cx, 0);
    446  CHECK(bi);
    447  int32_t result;
    448  CHECK(mozilla::NumberIsInt32(JS::BigIntToNumber(bi), &result));
    449  CHECK_EQUAL(result, 0);
    450 
    451  bi = JS::NumberToBigInt(cx, 100);
    452  CHECK(bi);
    453  CHECK(JS::BigIntToNumber(bi) == 100);
    454 
    455  bi = JS::NumberToBigInt(cx, -100);
    456  CHECK(bi);
    457  CHECK(JS::BigIntToNumber(bi) == -100);
    458 
    459  JS::Rooted<JS::Value> v(cx);
    460 
    461  EVAL("18446744073709551615n", &v);
    462  CHECK(v.isBigInt());
    463  double numberValue = JS::BigIntToNumber(v.toBigInt());
    464  EVAL("Number(18446744073709551615n)", &v);
    465  CHECK(v.isNumber());
    466  CHECK(numberValue == v.toNumber());
    467 
    468  EVAL((std::string(500, '9') + "n").c_str(), &v);
    469  CHECK(v.isBigInt());
    470  CHECK(JS::BigIntToNumber(v.toBigInt()) == INFINITY);
    471 
    472  return true;
    473 }
    474 END_TEST(testBigIntToNumber)
    475 
    476 BEGIN_TEST(testBigIntIsNegative) {
    477  JS::BigInt* bi = JS::NumberToBigInt(cx, 0);
    478  CHECK(bi);
    479  CHECK(!JS::BigIntIsNegative(bi));
    480 
    481  bi = JS::NumberToBigInt(cx, 100);
    482  CHECK(bi);
    483  CHECK(!JS::BigIntIsNegative(bi));
    484 
    485  bi = JS::NumberToBigInt(cx, -100);
    486  CHECK(bi);
    487  CHECK(JS::BigIntIsNegative(bi));
    488 
    489  return true;
    490 }
    491 END_TEST(testBigIntIsNegative)
    492 
    493 #define GENERATE_INTTYPE_TEST(bits)              \
    494  BEGIN_TEST(testBigIntFits_Int##bits) {         \
    495    int64_t in = INT##bits##_MIN;                \
    496    JS::BigInt* bi = JS::NumberToBigInt(cx, in); \
    497    CHECK(bi);                                   \
    498    int##bits##_t i;                             \
    499    CHECK(JS::BigIntFits(bi, &i));               \
    500    CHECK_EQUAL(i, in);                          \
    501                                                 \
    502    in = int64_t(INT##bits##_MIN) - 1;           \
    503    bi = JS::NumberToBigInt(cx, in);             \
    504    CHECK(bi);                                   \
    505    CHECK(!JS::BigIntFits(bi, &i));              \
    506                                                 \
    507    in = INT64_MIN;                              \
    508    bi = JS::NumberToBigInt(cx, in);             \
    509    CHECK(bi);                                   \
    510    CHECK(!JS::BigIntFits(bi, &i));              \
    511                                                 \
    512    in = INT##bits##_MAX;                        \
    513    bi = JS::NumberToBigInt(cx, in);             \
    514    CHECK(bi);                                   \
    515    CHECK(JS::BigIntFits(bi, &i));               \
    516    CHECK_EQUAL(i, in);                          \
    517                                                 \
    518    in = int64_t(INT##bits##_MAX) + 1;           \
    519    bi = JS::NumberToBigInt(cx, in);             \
    520    CHECK(bi);                                   \
    521    CHECK(!JS::BigIntFits(bi, &i));              \
    522                                                 \
    523    in = INT64_MAX;                              \
    524    bi = JS::NumberToBigInt(cx, in);             \
    525    CHECK(bi);                                   \
    526    CHECK(!JS::BigIntFits(bi, &i));              \
    527                                                 \
    528    uint64_t uin = 0;                            \
    529    bi = JS::NumberToBigInt(cx, uin);            \
    530    CHECK(bi);                                   \
    531    uint##bits##_t u;                            \
    532    CHECK(JS::BigIntFits(bi, &u));               \
    533    CHECK_EQUAL(u, uin);                         \
    534                                                 \
    535    uin = UINT##bits##_MAX;                      \
    536    bi = JS::NumberToBigInt(cx, uin);            \
    537    CHECK(bi);                                   \
    538    CHECK(JS::BigIntFits(bi, &u));               \
    539    CHECK_EQUAL(u, uin);                         \
    540                                                 \
    541    uin = uint64_t(UINT##bits##_MAX) + 1;        \
    542    bi = JS::NumberToBigInt(cx, uin);            \
    543    CHECK(bi);                                   \
    544    CHECK(!JS::BigIntFits(bi, &u));              \
    545                                                 \
    546    uin = UINT64_MAX;                            \
    547    bi = JS::NumberToBigInt(cx, uin);            \
    548    CHECK(bi);                                   \
    549    CHECK(!JS::BigIntFits(bi, &u));              \
    550                                                 \
    551    return true;                                 \
    552  }                                              \
    553  END_TEST(testBigIntFits_Int##bits)
    554 
    555 GENERATE_INTTYPE_TEST(8);
    556 GENERATE_INTTYPE_TEST(16);
    557 GENERATE_INTTYPE_TEST(32);
    558 
    559 #undef GENERATE_INTTYPE_TEST
    560 
    561 BEGIN_TEST(testBigIntFits_Int64) {
    562  int64_t in = INT64_MIN;
    563  JS::BigInt* bi = JS::NumberToBigInt(cx, in);
    564  CHECK(bi);
    565  int64_t i;
    566  CHECK(JS::BigIntFits(bi, &i));
    567  CHECK_EQUAL(i, in);
    568 
    569  in = INT64_MAX;
    570  bi = JS::NumberToBigInt(cx, in);
    571  CHECK(bi);
    572  CHECK(JS::BigIntFits(bi, &i));
    573  CHECK_EQUAL(i, in);
    574 
    575  JS::RootedValue v(cx);
    576 
    577  EVAL((std::string(500, '9') + "n").c_str(), &v);
    578  CHECK(v.isBigInt());
    579  CHECK(!JS::BigIntFits(v.toBigInt(), &i));
    580 
    581  EVAL(("-" + std::string(500, '9') + "n").c_str(), &v);
    582  CHECK(v.isBigInt());
    583  CHECK(!JS::BigIntFits(v.toBigInt(), &i));
    584 
    585  return true;
    586 }
    587 END_TEST(testBigIntFits_Int64)
    588 
    589 BEGIN_TEST(testBigIntFits_Uint64) {
    590  uint64_t uin = 0;
    591  JS::BigInt* bi = JS::NumberToBigInt(cx, uin);
    592  CHECK(bi);
    593  uint64_t u;
    594  CHECK(JS::BigIntFits(bi, &u));
    595  CHECK_EQUAL(u, uin);
    596 
    597  uin = UINT64_MAX;
    598  bi = JS::NumberToBigInt(cx, uin);
    599  CHECK(bi);
    600  CHECK(JS::BigIntFits(bi, &u));
    601  CHECK_EQUAL(u, uin);
    602 
    603  JS::RootedValue v(cx);
    604 
    605  EVAL((std::string(500, '9') + "n").c_str(), &v);
    606  CHECK(v.isBigInt());
    607  CHECK(!JS::BigIntFits(v.toBigInt(), &u));
    608 
    609  return true;
    610 }
    611 END_TEST(testBigIntFits_Uint64)
    612 
    613 #define GENERATE_SIGNED_VALUE_TEST(type, tag, val) \
    614  BEGIN_TEST(testBigIntFits_##type##_##tag) {      \
    615    int64_t v = val;                               \
    616    JS::BigInt* bi = JS::NumberToBigInt(cx, v);    \
    617    CHECK(bi);                                     \
    618    type result;                                   \
    619    CHECK(JS::BigIntFits(bi, &result));            \
    620    CHECK_EQUAL(v, result);                        \
    621    return true;                                   \
    622  }                                                \
    623  END_TEST(testBigIntFits_##type##_##tag)
    624 
    625 #define GENERATE_UNSIGNED_VALUE_TEST(type, tag, val) \
    626  BEGIN_TEST(testBigIntFits_##type##_##tag) {        \
    627    uint64_t v = val;                                \
    628    JS::BigInt* bi = JS::NumberToBigInt(cx, v);      \
    629    CHECK(bi);                                       \
    630    type result;                                     \
    631    CHECK(JS::BigIntFits(bi, &result));              \
    632    CHECK_EQUAL(v, result);                          \
    633    return true;                                     \
    634  }                                                  \
    635  END_TEST(testBigIntFits_##type##_##tag)
    636 
    637 GENERATE_SIGNED_VALUE_TEST(int, zero, 0);
    638 GENERATE_SIGNED_VALUE_TEST(int, aValue, -42);
    639 GENERATE_UNSIGNED_VALUE_TEST(unsigned, zero, 0);
    640 GENERATE_UNSIGNED_VALUE_TEST(unsigned, aValue, 42);
    641 GENERATE_SIGNED_VALUE_TEST(long, zero, 0);
    642 GENERATE_SIGNED_VALUE_TEST(long, aValue, -42);
    643 GENERATE_UNSIGNED_VALUE_TEST(uintptr_t, zero, 0);
    644 GENERATE_UNSIGNED_VALUE_TEST(uintptr_t, aValue, 42);
    645 GENERATE_UNSIGNED_VALUE_TEST(size_t, zero, 0);
    646 GENERATE_UNSIGNED_VALUE_TEST(size_t, aValue, 42);
    647 
    648 #undef GENERATE_SIGNED_VALUE_TEST
    649 #undef GENERATE_UNSIGNED_VALUE_TEST
    650 
    651 BEGIN_TEST(testBigIntFitsNumber) {
    652  JS::BigInt* bi = JS::NumberToBigInt(cx, 0);
    653  CHECK(bi);
    654  double num;
    655  CHECK(JS::BigIntFitsNumber(bi, &num));
    656  int32_t result;
    657  CHECK(mozilla::NumberIsInt32(num, &result));
    658  CHECK_EQUAL(result, 0);
    659 
    660  bi = JS::NumberToBigInt(cx, 100);
    661  CHECK(bi);
    662  CHECK(JS::BigIntFitsNumber(bi, &num));
    663  CHECK(num == 100);
    664 
    665  bi = JS::NumberToBigInt(cx, -100);
    666  CHECK(bi);
    667  CHECK(JS::BigIntFitsNumber(bi, &num));
    668  CHECK(num == -100);
    669 
    670  JS::Rooted<JS::Value> v(cx);
    671 
    672  EVAL("BigInt(Number.MAX_SAFE_INTEGER)", &v);
    673  CHECK(v.isBigInt());
    674  CHECK(JS::BigIntFitsNumber(v.toBigInt(), &num));
    675 
    676  EVAL("BigInt(Number.MIN_SAFE_INTEGER)", &v);
    677  CHECK(v.isBigInt());
    678  CHECK(JS::BigIntFitsNumber(v.toBigInt(), &num));
    679 
    680  EVAL("BigInt(Number.MAX_SAFE_INTEGER) + 1n", &v);
    681  CHECK(v.isBigInt());
    682  CHECK(!JS::BigIntFitsNumber(v.toBigInt(), &num));
    683 
    684  EVAL("BigInt(Number.MIN_SAFE_INTEGER) - 1n", &v);
    685  CHECK(v.isBigInt());
    686  CHECK(!JS::BigIntFitsNumber(v.toBigInt(), &num));
    687 
    688  EVAL((std::string(500, '9') + "n").c_str(), &v);
    689  CHECK(v.isBigInt());
    690  CHECK(!JS::BigIntFitsNumber(v.toBigInt(), &num));
    691 
    692  EVAL(("-" + std::string(500, '9') + "n").c_str(), &v);
    693  CHECK(v.isBigInt());
    694  CHECK(!JS::BigIntFitsNumber(v.toBigInt(), &num));
    695 
    696  return true;
    697 }
    698 END_TEST(testBigIntFitsNumber)
    699 
    700 BEGIN_TEST(testBigIntToString) {
    701  CHECK(Convert(12345, 10, "12345"));
    702  CHECK(Convert(-12345, 10, "-12345"));
    703  CHECK(Convert(0775, 8, "775"));
    704  CHECK(Convert(-0775, 8, "-775"));
    705  CHECK(Convert(0xCAFE, 16, "cafe"));
    706  CHECK(Convert(-0xCAFE, 16, "-cafe"));
    707 
    708  return true;
    709 }
    710 
    711 template <size_t N>
    712 inline bool Convert(int64_t input, uint8_t radix, const char (&expected)[N]) {
    713  JS::Rooted<JS::BigInt*> bi(cx, JS::NumberToBigInt(cx, input));
    714  CHECK(bi);
    715  JS::Rooted<JSString*> str(cx, JS::BigIntToString(cx, bi, radix));
    716  CHECK(str);
    717 
    718  bool match;
    719  CHECK(JS_StringEqualsLiteral(cx, str, expected, &match));
    720  CHECK(match);
    721 
    722  return true;
    723 }
    724 END_TEST(testBigIntToString)
    725 
    726 BEGIN_TEST(testBigIntToString_AllPossibleDigits) {
    727  const char allPossible[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890";
    728  JS::Rooted<JS::BigInt*> bi(
    729      cx,
    730      JS::SimpleStringToBigInt(cx, mozilla::MakeStringSpan(allPossible), 36));
    731  CHECK(bi);
    732  JS::Rooted<JSString*> str(cx, JS::BigIntToString(cx, bi, 36));
    733  CHECK(str);
    734 
    735  bool match;
    736  CHECK(JS_StringEqualsLiteral(cx, str, "abcdefghijklmnopqrstuvwxyz1234567890",
    737                               &match));
    738  CHECK(match);
    739  return true;
    740 }
    741 END_TEST(testBigIntToString_AllPossibleDigits)
    742 
    743 BEGIN_TEST(testBigIntToString_RadixOutOfRange) {
    744  CHECK(RadixOutOfRange(1));
    745  CHECK(RadixOutOfRange(37));
    746  return true;
    747 }
    748 
    749 inline bool RadixOutOfRange(uint8_t radix) {
    750  JS::Rooted<JS::BigInt*> bi(cx, JS::NumberToBigInt(cx, 1));
    751  CHECK(bi);
    752  JSString* s = JS::BigIntToString(cx, bi, radix);
    753  CHECK_NULL(s);
    754  CHECK(JS_IsExceptionPending(cx));
    755 
    756  JS::ExceptionStack exnStack(cx);
    757  CHECK(JS::StealPendingExceptionStack(cx, &exnStack));
    758 
    759  JS::ErrorReportBuilder report(cx);
    760  CHECK(report.init(cx, exnStack, JS::ErrorReportBuilder::NoSideEffects));
    761  CHECK(report.report()->exnType == JSEXN_RANGEERR);
    762  CHECK(report.report()->errorNumber == JSMSG_BAD_RADIX);
    763 
    764  CHECK(!JS_IsExceptionPending(cx));
    765 
    766  return true;
    767 }
    768 END_TEST(testBigIntToString_RadixOutOfRange)