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)