Quellcodebibliothek Statistik Leitseite products/sources/formale Sprachen/C/Firefox/js/src/jsapi-tests/   (Browser von der Mozilla Stiftung Version 136.0.1©)  Datei vom 10.2.2025 mit Größe 23 kB image not shown  

Quelle  testBigInt.cpp   Sprache: C

 
/* 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::NumberIsInt32
#include "mozilla/Range.h"          // mozilla::Range
#include "mozilla/Span.h"           // mozilla::MakeStringSpan

#include <stdint.h>

#include "js/BigInt.h"  // JS::{,Number,String,SimpleString}ToBigInt, JS::ToBig{I,Ui}nt64
#include "js/CharacterEncoding.h"  // JS::Const{Latin1,TwoByte}Chars
#include "js/Conversions.h"        // JS::ToString
#include "js/ErrorReport.h"        // JS::ErrorReportBuilder, JSEXN_SYNTAXERR
#include "js/Exception.h"  // JS::StealPendingExceptionStack, JS_IsExceptionPending
#include "js/friend/ErrorMessages.h"  // JSMSG_*
#include "js/RootingAPI.h"            // JS::Rooted
#include "js/String.h"                // JS_StringEqualsLiteral
#include "js/Value.h"                 // JS::FalseValue, JS::Value

#include "jsapi-tests/tests.h"
#include "util/Text.h"  // js::InflateString

struct JS_PUBLIC_API JSContext;
class JS_PUBLIC_API JSString;

namespace JS {

class JS_PUBLIC_API BigInt;

}  // namespace JS

BEGIN_TEST(testToBigInt64) {
  JS::Rooted<JS::Value> v(cx);

  EVAL("0n", &v);
  CHECK(v.isBigInt());
  CHECK(JS::ToBigInt64(v.toBigInt()) == 0);

  EVAL("9223372036854775807n", &v);
  CHECK(v.isBigInt());
  CHECK(JS::ToBigInt64(v.toBigInt()) == 9223372036854775807L);

  EVAL("-9223372036854775808n", &v);
  CHECK(v.isBigInt());
  CHECK(JS::ToBigInt64(v.toBigInt()) == -9223372036854775807L - 1L);

  return true;
}
END_TEST(testToBigInt64)

BEGIN_TEST(testToBigUint64) {
  JS::Rooted<JS::Value> v(cx);

  EVAL("0n", &v);
  CHECK(v.isBigInt());
  CHECK(JS::ToBigUint64(v.toBigInt()) == 0);

  EVAL("18446744073709551615n", &v);
  CHECK(v.isBigInt());
  CHECK(JS::ToBigUint64(v.toBigInt()) == 18446744073709551615UL);

  return true;
}
END_TEST(testToBigUint64)

#define GENERATE_INTTYPE_TEST(bits)             \
  BEGIN_TEST(testNumberToBigInt_Int##bits) {    \
    int##bits##_t i = INT##bits##_MIN;          \
    JS::BigInt* bi = JS::NumberToBigInt(cx, i); \
    CHECK(bi);                                  \
    CHECK(JS::ToBigInt64(bi) == i);             \
                                                \
    i = INT##bits##_MAX;                        \
    bi = JS::NumberToBigInt(cx, i);             \
    CHECK(bi);                                  \
    CHECK(JS::ToBigInt64(bi) == i);             \
                                                \
    uint##bits##_t u = 0;                       \
    bi = JS::NumberToBigInt(cx, u);             \
    CHECK(bi);                                  \
    CHECK(JS::ToBigUint64(bi) == 0);            \
                                                \
    u = UINT##bits##_MAX;                       \
    bi = JS::NumberToBigInt(cx, u);             \
    CHECK(bi);                                  \
    CHECK(JS::ToBigUint64(bi) == u);            \
                                                \
    return true;                                \
  }                                             \
  END_TEST(testNumberToBigInt_Int##bits)

GENERATE_INTTYPE_TEST(8);
GENERATE_INTTYPE_TEST(16);
GENERATE_INTTYPE_TEST(32);
GENERATE_INTTYPE_TEST(64);

#undef GENERATE_INTTYPE_TEST

#define GENERATE_SIGNED_VALUE_TEST(type, tag, val) \
  BEGIN_TEST(testNumberToBigInt_##type##_##tag) {  \
    type v = val;                                  \
    JS::BigInt* bi = JS::NumberToBigInt(cx, v);    \
    CHECK(bi);                                     \
    CHECK(JS::ToBigInt64(bi) == (val));            \
    return true;                                   \
  }                                                \
  END_TEST(testNumberToBigInt_##type##_##tag)

#define GENERATE_UNSIGNED_VALUE_TEST(type, tag, val) \
  BEGIN_TEST(testNumberToBigInt_##type##_##tag) {    \
    type v = val;                                    \
    JS::BigInt* bi = JS::NumberToBigInt(cx, v);      \
    CHECK(bi);                                       \
    CHECK(JS::ToBigUint64(bi) == (val));             \
    return true;                                     \
  }                                                  \
  END_TEST(testNumberToBigInt_##type##_##tag)

GENERATE_SIGNED_VALUE_TEST(int, zero, 0);
GENERATE_SIGNED_VALUE_TEST(int, aValue, -42);
GENERATE_UNSIGNED_VALUE_TEST(unsigned, zero, 0);
GENERATE_UNSIGNED_VALUE_TEST(unsigned, aValue, 42);
GENERATE_SIGNED_VALUE_TEST(long, zero, 0);
GENERATE_SIGNED_VALUE_TEST(long, aValue, -42);
GENERATE_UNSIGNED_VALUE_TEST(uintptr_t, zero, 0);
GENERATE_UNSIGNED_VALUE_TEST(uintptr_t, aValue, 42);
GENERATE_UNSIGNED_VALUE_TEST(size_t, zero, 0);
GENERATE_UNSIGNED_VALUE_TEST(size_t, aValue, 42);
GENERATE_SIGNED_VALUE_TEST(double, zero, 0);
GENERATE_SIGNED_VALUE_TEST(double, aValue, -42);

#undef GENERATE_SIGNED_VALUE_TEST
#undef GENERATE_UNSIGNED_VALUE_TEST

BEGIN_TEST(testNumberToBigInt_bool) {
  JS::BigInt* bi = JS::NumberToBigInt(cx, true);
  CHECK(bi);
  CHECK(JS::ToBigUint64(bi) == 1);

  bi = JS::NumberToBigInt(cx, false);
  CHECK(bi);
  CHECK(JS::ToBigUint64(bi) == 0);

  return true;
}
END_TEST(testNumberToBigInt_bool)

BEGIN_TEST(testNumberToBigInt_NonIntegerValueFails) {
  JS::BigInt* bi = JS::NumberToBigInt(cx, 3.1416);
  CHECK_NULL(bi);
  CHECK(JS_IsExceptionPending(cx));
  JS_ClearPendingException(cx);
  return true;
}
END_TEST(testNumberToBigInt_NonIntegerValueFails)

BEGIN_TEST(testStringToBigInt_FromTwoByteStringSpan) {
  mozilla::Range<const char16_t> input{
      mozilla::MakeStringSpan(u"18446744073709551616")};
  JS::BigInt* bi = JS::StringToBigInt(cx, input);
  CHECK(bi);
  JS::Rooted<JS::Value> val(cx, JS::BigIntValue(bi));
  JS::Rooted<JSString*> str(cx, JS::ToString(cx, val));
  CHECK(str);
  bool match;
  CHECK(JS_StringEqualsLiteral(cx, str, "18446744073709551616", &match));
  CHECK(match);
  return true;
}
END_TEST(testStringToBigInt_FromTwoByteStringSpan)

BEGIN_TEST(testStringToBigInt_FromLatin1Range) {
  const JS::Latin1Char string[] = "12345 and some junk at the end";
  JS::ConstLatin1Chars range(string, 5);
  JS::BigInt* bi = JS::StringToBigInt(cx, range);
  CHECK(bi);
  CHECK(JS::ToBigInt64(bi) == 12345);
  return true;
}
END_TEST(testStringToBigInt_FromLatin1Range)

BEGIN_TEST(testStringToBigInt_FromTwoByteRange) {
  const char16_t string[] = u"12345 and some junk at the end";
  JS::ConstTwoByteChars range(string, 5);
  JS::BigInt* bi = JS::StringToBigInt(cx, range);
  CHECK(bi);
  CHECK(JS::ToBigInt64(bi) == 12345);
  return true;
}
END_TEST(testStringToBigInt_FromTwoByteRange)

BEGIN_TEST(testStringToBigInt_AcceptedInput) {
  CHECK(Allowed(u"", 0));
  CHECK(Allowed(u"\n", 0));
  CHECK(Allowed(u" ", 0));
  CHECK(Allowed(u"0\n", 0));
  CHECK(Allowed(u"0 ", 0));
  CHECK(Allowed(u"\n1", 1));
  CHECK(Allowed(u" 1", 1));
  CHECK(Allowed(u"\n2 ", 2));
  CHECK(Allowed(u" 2\n", 2));
  CHECK(Allowed(u"0b11", 3));
  CHECK(Allowed(u"0x17", 23));
  CHECK(Allowed(u"-5", -5));
  CHECK(Allowed(u"+5", 5));
  CHECK(Allowed(u"-0", 0));

  CHECK(Fails(u"!!!!!!111one1111one1!1!1!!"));
  CHECK(Fails(u"3.1416"));
  CHECK(Fails(u"6.022e23"));
  CHECK(Fails(u"1e3"));
  CHECK(Fails(u".25"));
  CHECK(Fails(u".25e2"));
  CHECK(Fails(u"1_000_000"));
  CHECK(Fails(u"3n"));
  CHECK(Fails(u"-0x3"));
  CHECK(Fails(u"Infinity"));

  return true;
}

template <size_t N>
inline bool Allowed(const char16_t (&str)[N], int64_t expected) {
  JS::BigInt* bi = JS::StringToBigInt(cx, mozilla::MakeStringSpan(str));
  CHECK(bi);
  CHECK(JS::ToBigInt64(bi) == expected);
  return true;
}

template <size_t N>
inline bool Fails(const char16_t (&str)[N]) {
  JS::BigInt* bi = JS::StringToBigInt(cx, mozilla::MakeStringSpan(str));
  CHECK_NULL(bi);
  CHECK(JS_IsExceptionPending(cx));

  JS::ExceptionStack exnStack(cx);
  CHECK(JS::StealPendingExceptionStack(cx, &exnStack));

  JS::ErrorReportBuilder report(cx);
  CHECK(report.init(cx, exnStack, JS::ErrorReportBuilder::NoSideEffects));
  CHECK(report.report()->exnType == JSEXN_SYNTAXERR);
  CHECK(report.report()->errorNumber == JSMSG_BIGINT_INVALID_SYNTAX);

  CHECK(!JS_IsExceptionPending(cx));

  return true;
}
END_TEST(testStringToBigInt_AcceptedInput)

BEGIN_TEST(testSimpleStringToBigInt_AcceptedInput) {
  CHECK(Allowed("12345", 10, 12345));
  CHECK(Allowed("+12345", 10, 12345));
  CHECK(Allowed("-12345", 10, -12345));
  CHECK(Allowed("775", 8, 0775));
  CHECK(Allowed("+775", 8, 0775));
  CHECK(Allowed("-775", 8, -0775));
  CHECK(Allowed("cAfE", 16, 0xCAFE));
  CHECK(Allowed("+cAfE", 16, +0xCAFE));
  CHECK(Allowed("-cAfE", 16, -0xCAFE));
  CHECK(Allowed("-0", 10, 0));

  CHECK(Fails("", 10));
  CHECK(Fails("\n", 10));
  CHECK(Fails(" ", 10));
  CHECK(Fails("0\n", 10));
  CHECK(Fails("0 ", 10));
  CHECK(Fails("\n1", 10));
  CHECK(Fails(" 1", 10));
  CHECK(Fails("\n2 ", 10));
  CHECK(Fails(" 2\n", 10));
  CHECK(Fails("0b11", 2));
  CHECK(Fails("0x17", 16));
  CHECK(Fails("!!!!!!111one1111one1!1!1!!", 10));
  CHECK(Fails("3.1416", 10));
  CHECK(Fails("6.022e23", 10));
  CHECK(Fails("1e3", 10));
  CHECK(Fails(".25", 10));
  CHECK(Fails(".25e2", 10));
  CHECK(Fails("1_000_000", 10));
  CHECK(Fails("3n", 10));
  CHECK(Fails("-0x3", 10));
  CHECK(Fails("Infinity", 10));
  CHECK(Fails("555", 4));
  CHECK(Fails("fff", 15));

  return true;
}

template <size_t N>
inline bool Allowed(const char (&str)[N], unsigned radix, int64_t expected) {
  JS::BigInt* bi = JS::SimpleStringToBigInt(cx, {str, N - 1}, radix);
  CHECK(bi);
  CHECK(JS::ToBigInt64(bi) == expected);
  return true;
}

template <size_t N>
inline bool Fails(const char (&str)[N], unsigned radix) {
  JS::BigInt* bi = JS::SimpleStringToBigInt(cx, {str, N - 1}, radix);
  CHECK_NULL(bi);
  CHECK(JS_IsExceptionPending(cx));

  JS::ExceptionStack exnStack(cx);
  CHECK(JS::StealPendingExceptionStack(cx, &exnStack));

  JS::ErrorReportBuilder report(cx);
  CHECK(report.init(cx, exnStack, JS::ErrorReportBuilder::NoSideEffects));
  CHECK(report.report()->exnType == JSEXN_SYNTAXERR);
  CHECK(report.report()->errorNumber == JSMSG_BIGINT_INVALID_SYNTAX);

  CHECK(!JS_IsExceptionPending(cx));

  return true;
}
END_TEST(testSimpleStringToBigInt_AcceptedInput)

BEGIN_TEST(testSimpleStringToBigInt_AllPossibleDigits) {
  const char allPossible[] =
      "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890";
  JS::BigInt* bi =
      JS::SimpleStringToBigInt(cx, mozilla::MakeStringSpan(allPossible), 36);
  CHECK(bi);
  JS::Rooted<JS::Value> val(cx, JS::BigIntValue(bi));
  JS::Rooted<JSString*> str(cx, JS::ToString(cx, val));
  CHECK(str);

  // Answer calculated using Python:
  // int('abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890', 36)
  // Do not trust online base-36 calculators for values > UINT32_MAX!
  bool match;
  CHECK(
      JS_StringEqualsLiteral(cx, str,
                             "8870050151210747660007771095260505028056221996735"
                             "67534007158336222790086855213834764150805438340",
                             &match));
  CHECK(match);
  return true;
}
END_TEST(testSimpleStringToBigInt_AllPossibleDigits)

BEGIN_TEST(testSimpleStringToBigInt_RadixOutOfRange) {
  CHECK(RadixOutOfRange(1));
  CHECK(RadixOutOfRange(37));
  return true;
}

inline bool RadixOutOfRange(unsigned radix) {
  JS::BigInt* bi =
      JS::SimpleStringToBigInt(cx, mozilla::MakeStringSpan("1"), radix);
  CHECK_NULL(bi);
  CHECK(JS_IsExceptionPending(cx));

  JS::ExceptionStack exnStack(cx);
  CHECK(JS::StealPendingExceptionStack(cx, &exnStack));

  JS::ErrorReportBuilder report(cx);
  CHECK(report.init(cx, exnStack, JS::ErrorReportBuilder::NoSideEffects));
  CHECK(report.report()->exnType == JSEXN_RANGEERR);
  CHECK(report.report()->errorNumber == JSMSG_BAD_RADIX);

  CHECK(!JS_IsExceptionPending(cx));

  return true;
}
END_TEST(testSimpleStringToBigInt_RadixOutOfRange)

BEGIN_TEST(testToBigInt_Undefined) {
  JS::Rooted<JS::Value> v(cx, JS::UndefinedValue());
  JS::BigInt* bi = JS::ToBigInt(cx, v);
  CHECK_NULL(bi);
  CHECK(JS_IsExceptionPending(cx));
  JS_ClearPendingException(cx);
  return true;
}
END_TEST(testToBigInt_Undefined)

BEGIN_TEST(testToBigInt_Null) {
  JS::Rooted<JS::Value> v(cx, JS::NullValue());
  JS::BigInt* bi = JS::ToBigInt(cx, v);
  CHECK_NULL(bi);
  CHECK(JS_IsExceptionPending(cx));
  JS_ClearPendingException(cx);
  return true;
}
END_TEST(testToBigInt_Null)

BEGIN_TEST(testToBigInt_Boolean) {
  JS::Rooted<JS::Value> v(cx, JS::TrueValue());
  JS::BigInt* bi = JS::ToBigInt(cx, v);
  CHECK(bi);
  CHECK(JS::ToBigInt64(bi) == 1);

  v = JS::FalseValue();
  bi = JS::ToBigInt(cx, v);
  CHECK(bi);
  CHECK(JS::ToBigInt64(bi) == 0);

  return true;
}
END_TEST(testToBigInt_Boolean)

BEGIN_TEST(testToBigInt_BigInt) {
  JS::Rooted<JS::Value> v(cx);
  EVAL("42n", &v);
  JS::BigInt* bi = JS::ToBigInt(cx, v);
  CHECK(bi);
  CHECK(JS::ToBigInt64(bi) == 42);
  return true;
}
END_TEST(testToBigInt_BigInt)

BEGIN_TEST(testToBigInt_Number) {
  JS::Rooted<JS::Value> v(cx, JS::Int32Value(42));
  JS::BigInt* bi = JS::ToBigInt(cx, v);
  CHECK_NULL(bi);
  CHECK(JS_IsExceptionPending(cx));
  JS_ClearPendingException(cx);
  return true;
}
END_TEST(testToBigInt_Number)

BEGIN_TEST(testToBigInt_String) {
  JS::Rooted<JS::Value> v(cx);
  EVAL("'42'", &v);
  JS::BigInt* bi = JS::ToBigInt(cx, v);
  CHECK(bi);
  CHECK(JS::ToBigInt64(bi) == 42);
  return true;
}
END_TEST(testToBigInt_String)

BEGIN_TEST(testToBigInt_Symbol) {
  JS::Rooted<JS::Value> v(cx);
  EVAL("Symbol.toStringTag", &v);
  JS::BigInt* bi = JS::ToBigInt(cx, v);
  CHECK_NULL(bi);
  CHECK(JS_IsExceptionPending(cx));
  JS_ClearPendingException(cx);
  return true;
}
END_TEST(testToBigInt_Symbol)

BEGIN_TEST(testBigIntToNumber) {
  JS::BigInt* bi = JS::NumberToBigInt(cx, 0);
  CHECK(bi);
  int32_t result;
  CHECK(mozilla::NumberIsInt32(JS::BigIntToNumber(bi), &result));
  CHECK_EQUAL(result, 0);

  bi = JS::NumberToBigInt(cx, 100);
  CHECK(bi);
  CHECK(JS::BigIntToNumber(bi) == 100);

  bi = JS::NumberToBigInt(cx, -100);
  CHECK(bi);
  CHECK(JS::BigIntToNumber(bi) == -100);

  JS::Rooted<JS::Value> v(cx);

  EVAL("18446744073709551615n", &v);
  CHECK(v.isBigInt());
  double numberValue = JS::BigIntToNumber(v.toBigInt());
  EVAL("Number(18446744073709551615n)", &v);
  CHECK(v.isNumber());
  CHECK(numberValue == v.toNumber());

  EVAL((std::string(500, '9') + "n").c_str(), &v);
  CHECK(v.isBigInt());
  CHECK(JS::BigIntToNumber(v.toBigInt()) == INFINITY);

  return true;
}
END_TEST(testBigIntToNumber)

BEGIN_TEST(testBigIntIsNegative) {
  JS::BigInt* bi = JS::NumberToBigInt(cx, 0);
  CHECK(bi);
  CHECK(!JS::BigIntIsNegative(bi));

  bi = JS::NumberToBigInt(cx, 100);
  CHECK(bi);
  CHECK(!JS::BigIntIsNegative(bi));

  bi = JS::NumberToBigInt(cx, -100);
  CHECK(bi);
  CHECK(JS::BigIntIsNegative(bi));

  return true;
}
END_TEST(testBigIntIsNegative)

#define GENERATE_INTTYPE_TEST(bits)              \
  BEGIN_TEST(testBigIntFits_Int##bits) {         \
    int64_t in = INT##bits##_MIN;                \
    JS::BigInt* bi = JS::NumberToBigInt(cx, in); \
    CHECK(bi);                                   \
    int##bits##_t i;                             \
    CHECK(JS::BigIntFits(bi, &i));               \
    CHECK_EQUAL(i, in);                          \
                                                 \
    in = int64_t(INT##bits##_MIN) - 1;           \
    bi = JS::NumberToBigInt(cx, in);             \
    CHECK(bi);                                   \
    CHECK(!JS::BigIntFits(bi, &i));              \
                                                 \
    in = INT64_MIN;                              \
    bi = JS::NumberToBigInt(cx, in);             \
    CHECK(bi);                                   \
    CHECK(!JS::BigIntFits(bi, &i));              \
                                                 \
    in = INT##bits##_MAX;                        \
    bi = JS::NumberToBigInt(cx, in);             \
    CHECK(bi);                                   \
    CHECK(JS::BigIntFits(bi, &i));               \
    CHECK_EQUAL(i, in);                          \
                                                 \
    in = int64_t(INT##bits##_MAX) + 1;           \
    bi = JS::NumberToBigInt(cx, in);             \
    CHECK(bi);                                   \
    CHECK(!JS::BigIntFits(bi, &i));              \
                                                 \
    in = INT64_MAX;                              \
    bi = JS::NumberToBigInt(cx, in);             \
    CHECK(bi);                                   \
    CHECK(!JS::BigIntFits(bi, &i));              \
                                                 \
    uint64_t uin = 0;                            \
    bi = JS::NumberToBigInt(cx, uin);            \
    CHECK(bi);                                   \
    uint##bits##_t u;                            \
    CHECK(JS::BigIntFits(bi, &u));               \
    CHECK_EQUAL(u, uin);                         \
                                                 \
    uin = UINT##bits##_MAX;                      \
    bi = JS::NumberToBigInt(cx, uin);            \
    CHECK(bi);                                   \
    CHECK(JS::BigIntFits(bi, &u));               \
    CHECK_EQUAL(u, uin);                         \
                                                 \
    uin = uint64_t(UINT##bits##_MAX) + 1;        \
    bi = JS::NumberToBigInt(cx, uin);            \
    CHECK(bi);                                   \
    CHECK(!JS::BigIntFits(bi, &u));              \
                                                 \
    uin = UINT64_MAX;                            \
    bi = JS::NumberToBigInt(cx, uin);            \
    CHECK(bi);                                   \
    CHECK(!JS::BigIntFits(bi, &u));              \
                                                 \
    return true;                                 \
  }                                              \
  END_TEST(testBigIntFits_Int##bits)

GENERATE_INTTYPE_TEST(8);
GENERATE_INTTYPE_TEST(16);
GENERATE_INTTYPE_TEST(32);

#undef GENERATE_INTTYPE_TEST

BEGIN_TEST(testBigIntFits_Int64) {
  int64_t in = INT64_MIN;
  JS::BigInt* bi = JS::NumberToBigInt(cx, in);
  CHECK(bi);
  int64_t i;
  CHECK(JS::BigIntFits(bi, &i));
  CHECK_EQUAL(i, in);

  in = INT64_MAX;
  bi = JS::NumberToBigInt(cx, in);
  CHECK(bi);
  CHECK(JS::BigIntFits(bi, &i));
  CHECK_EQUAL(i, in);

  JS::RootedValue v(cx);

  EVAL((std::string(500, '9') + "n").c_str(), &v);
  CHECK(v.isBigInt());
  CHECK(!JS::BigIntFits(v.toBigInt(), &i));

  EVAL(("-" + std::string(500, '9') + "n").c_str(), &v);
  CHECK(v.isBigInt());
  CHECK(!JS::BigIntFits(v.toBigInt(), &i));

  return true;
}
END_TEST(testBigIntFits_Int64)

BEGIN_TEST(testBigIntFits_Uint64) {
  uint64_t uin = 0;
  JS::BigInt* bi = JS::NumberToBigInt(cx, uin);
  CHECK(bi);
  uint64_t u;
  CHECK(JS::BigIntFits(bi, &u));
  CHECK_EQUAL(u, uin);

  uin = UINT64_MAX;
  bi = JS::NumberToBigInt(cx, uin);
  CHECK(bi);
  CHECK(JS::BigIntFits(bi, &u));
  CHECK_EQUAL(u, uin);

  JS::RootedValue v(cx);

  EVAL((std::string(500, '9') + "n").c_str(), &v);
  CHECK(v.isBigInt());
  CHECK(!JS::BigIntFits(v.toBigInt(), &u));

  return true;
}
END_TEST(testBigIntFits_Uint64)

#define GENERATE_SIGNED_VALUE_TEST(type, tag, val) \
  BEGIN_TEST(testBigIntFits_##type##_##tag) {      \
    int64_t v = val;                               \
    JS::BigInt* bi = JS::NumberToBigInt(cx, v);    \
    CHECK(bi);                                     \
    type result;                                   \
    CHECK(JS::BigIntFits(bi, &result));            \
    CHECK_EQUAL(v, result);                        \
    return true;                                   \
  }                                                \
  END_TEST(testBigIntFits_##type##_##tag)

#define GENERATE_UNSIGNED_VALUE_TEST(type, tag, val) \
  BEGIN_TEST(testBigIntFits_##type##_##tag) {        \
    uint64_t v = val;                                \
    JS::BigInt* bi = JS::NumberToBigInt(cx, v);      \
    CHECK(bi);                                       \
    type result;                                     \
    CHECK(JS::BigIntFits(bi, &result));              \
    CHECK_EQUAL(v, result);                          \
    return true;                                     \
  }                                                  \
  END_TEST(testBigIntFits_##type##_##tag)

GENERATE_SIGNED_VALUE_TEST(int, zero, 0);
GENERATE_SIGNED_VALUE_TEST(int, aValue, -42);
GENERATE_UNSIGNED_VALUE_TEST(unsigned, zero, 0);
GENERATE_UNSIGNED_VALUE_TEST(unsigned, aValue, 42);
GENERATE_SIGNED_VALUE_TEST(long, zero, 0);
GENERATE_SIGNED_VALUE_TEST(long, aValue, -42);
GENERATE_UNSIGNED_VALUE_TEST(uintptr_t, zero, 0);
GENERATE_UNSIGNED_VALUE_TEST(uintptr_t, aValue, 42);
GENERATE_UNSIGNED_VALUE_TEST(size_t, zero, 0);
GENERATE_UNSIGNED_VALUE_TEST(size_t, aValue, 42);

#undef GENERATE_SIGNED_VALUE_TEST
#undef GENERATE_UNSIGNED_VALUE_TEST

BEGIN_TEST(testBigIntFitsNumber) {
  JS::BigInt* bi = JS::NumberToBigInt(cx, 0);
  CHECK(bi);
  double num;
  CHECK(JS::BigIntFitsNumber(bi, &num));
  int32_t result;
  CHECK(mozilla::NumberIsInt32(num, &result));
  CHECK_EQUAL(result, 0);

  bi = JS::NumberToBigInt(cx, 100);
  CHECK(bi);
  CHECK(JS::BigIntFitsNumber(bi, &num));
  CHECK(num == 100);

  bi = JS::NumberToBigInt(cx, -100);
  CHECK(bi);
  CHECK(JS::BigIntFitsNumber(bi, &num));
  CHECK(num == -100);

  JS::Rooted<JS::Value> v(cx);

  EVAL("BigInt(Number.MAX_SAFE_INTEGER)", &v);
  CHECK(v.isBigInt());
  CHECK(JS::BigIntFitsNumber(v.toBigInt(), &num));

  EVAL("BigInt(Number.MIN_SAFE_INTEGER)", &v);
  CHECK(v.isBigInt());
  CHECK(JS::BigIntFitsNumber(v.toBigInt(), &num));

  EVAL("BigInt(Number.MAX_SAFE_INTEGER) + 1n", &v);
  CHECK(v.isBigInt());
  CHECK(!JS::BigIntFitsNumber(v.toBigInt(), &num));

  EVAL("BigInt(Number.MIN_SAFE_INTEGER) - 1n", &v);
  CHECK(v.isBigInt());
  CHECK(!JS::BigIntFitsNumber(v.toBigInt(), &num));

  EVAL((std::string(500, '9') + "n").c_str(), &v);
  CHECK(v.isBigInt());
  CHECK(!JS::BigIntFitsNumber(v.toBigInt(), &num));

  EVAL(("-" + std::string(500, '9') + "n").c_str(), &v);
  CHECK(v.isBigInt());
  CHECK(!JS::BigIntFitsNumber(v.toBigInt(), &num));

  return true;
}
END_TEST(testBigIntFitsNumber)

BEGIN_TEST(testBigIntToString) {
  CHECK(Convert(12345, 10, "12345"));
  CHECK(Convert(-12345, 10, "-12345"));
  CHECK(Convert(0775, 8, "775"));
  CHECK(Convert(-0775, 8, "-775"));
  CHECK(Convert(0xCAFE, 16, "cafe"));
  CHECK(Convert(-0xCAFE, 16, "-cafe"));

  return true;
}

template <size_t N>
inline bool Convert(int64_t input, uint8_t radix, const char (&expected)[N]) {
  JS::Rooted<JS::BigInt*> bi(cx, JS::NumberToBigInt(cx, input));
  CHECK(bi);
  JS::Rooted<JSString*> str(cx, JS::BigIntToString(cx, bi, radix));
  CHECK(str);

  bool match;
  CHECK(JS_StringEqualsLiteral(cx, str, expected, &match));
  CHECK(match);

  return true;
}
END_TEST(testBigIntToString)

BEGIN_TEST(testBigIntToString_AllPossibleDigits) {
  const char allPossible[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890";
  JS::Rooted<JS::BigInt*> bi(
      cx,
      JS::SimpleStringToBigInt(cx, mozilla::MakeStringSpan(allPossible), 36));
  CHECK(bi);
  JS::Rooted<JSString*> str(cx, JS::BigIntToString(cx, bi, 36));
  CHECK(str);

  bool match;
  CHECK(JS_StringEqualsLiteral(cx, str, "abcdefghijklmnopqrstuvwxyz1234567890",
                               &match));
  CHECK(match);
  return true;
}
END_TEST(testBigIntToString_AllPossibleDigits)

BEGIN_TEST(testBigIntToString_RadixOutOfRange) {
  CHECK(RadixOutOfRange(1));
  CHECK(RadixOutOfRange(37));
  return true;
}

inline bool RadixOutOfRange(uint8_t radix) {
  JS::Rooted<JS::BigInt*> bi(cx, JS::NumberToBigInt(cx, 1));
  CHECK(bi);
  JSString* s = JS::BigIntToString(cx, bi, radix);
  CHECK_NULL(s);
  CHECK(JS_IsExceptionPending(cx));

  JS::ExceptionStack exnStack(cx);
  CHECK(JS::StealPendingExceptionStack(cx, &exnStack));

  JS::ErrorReportBuilder report(cx);
  CHECK(report.init(cx, exnStack, JS::ErrorReportBuilder::NoSideEffects));
  CHECK(report.report()->exnType == JSEXN_RANGEERR);
  CHECK(report.report()->errorNumber == JSMSG_BAD_RADIX);

  CHECK(!JS_IsExceptionPending(cx));

  return true;
}
END_TEST(testBigIntToString_RadixOutOfRange)

96%


¤ Dauer der Verarbeitung: 0.11 Sekunden  ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

Beweissystem der NASA

Beweissystem Isabelle

NIST Cobol Testsuite

Cephes Mathematical Library

Wiener Entwicklungsmethode

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung ist noch experimentell.