/*
 * Copyright (c) 2021 Huawei Device Co., Ltd.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include "ecmascript/builtins/builtins_bigint.h"

#include "ecmascript/global_env.h"
#include "ecmascript/js_bigint.h"
#include "ecmascript/js_primitive_ref.h"
#include "ecmascript/tests/test_helper.h"

using namespace panda::ecmascript;
using namespace panda::ecmascript::builtins;

namespace panda::test {
using BigInt = ecmascript::BigInt;
class BuiltinsBigIntTest : public testing::Test {
public:
    static void SetUpTestCase()
    {
        GTEST_LOG_(INFO) << "SetUpTestCase";
    }

    static void TearDownTestCase()
    {
        GTEST_LOG_(INFO) << "TearDownCase";
    }

    void SetUp() override
    {
        JSRuntimeOptions options;
#if PANDA_TARGET_LINUX
        // for consistency requirement, use ohos_icu4j/data as icu-data-path
        options.SetIcuDataPath(ICU_PATH);
#endif
        options.SetEnableForceGC(true);
        instance = JSNApi::CreateEcmaVM(options);
        instance->SetEnableForceGC(true);
        ASSERT_TRUE(instance != nullptr) << "Cannot create EcmaVM";
        thread = instance->GetJSThread();
        scope = new EcmaHandleScope(thread);
    }

    void TearDown() override
    {
        TestHelper::DestroyEcmaVMWithScope(instance, scope);
    }

    EcmaVM *instance {nullptr};
    EcmaHandleScope *scope {nullptr};
    JSThread *thread {nullptr};
};

// new BigInt(123)
HWTEST_F_L0(BuiltinsBigIntTest, BigIntConstructor_001)
{
    JSHandle<JSTaggedValue> numericValue(thread, JSTaggedValue(123));
    auto ecmaRuntimeCallInfo = TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), 6);
    ecmaRuntimeCallInfo->SetFunction(JSTaggedValue::Undefined());
    ecmaRuntimeCallInfo->SetThis(JSTaggedValue::Undefined());
    ecmaRuntimeCallInfo->SetCallArg(0, numericValue.GetTaggedValue());

    [[maybe_unused]] auto prev = TestHelper::SetupFrame(thread, ecmaRuntimeCallInfo);
    JSTaggedValue result = BuiltinsBigInt::BigIntConstructor(ecmaRuntimeCallInfo);
    TestHelper::TearDownFrame(thread, prev);

    EXPECT_TRUE(result.IsBigInt());
}

// new BigInt("456")
HWTEST_F_L0(BuiltinsBigIntTest, BigIntConstructor_002)
{
    ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
    JSHandle<JSTaggedValue> numericValue(factory->NewFromASCII("456"));

    auto ecmaRuntimeCallInfo = TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), 6);
    ecmaRuntimeCallInfo->SetFunction(JSTaggedValue::Undefined());
    ecmaRuntimeCallInfo->SetThis(JSTaggedValue::Undefined());
    ecmaRuntimeCallInfo->SetCallArg(0, numericValue.GetTaggedValue());

    [[maybe_unused]] auto prev = TestHelper::SetupFrame(thread, ecmaRuntimeCallInfo);
    JSTaggedValue result = BuiltinsBigInt::BigIntConstructor(ecmaRuntimeCallInfo);
    TestHelper::TearDownFrame(thread, prev);

    EXPECT_TRUE(result.IsBigInt());
}

// AsIntN(64, (2 ^ 63 - 1))
HWTEST_F_L0(BuiltinsBigIntTest, AsIntN_001)
{
    ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
    JSHandle<JSTaggedValue> numericValue(factory->NewFromASCII("9223372036854775807"));
    int bit = 64; // 64-bit

    auto ecmaRuntimeCallInfo = TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), 8);
    ecmaRuntimeCallInfo->SetFunction(JSTaggedValue::Undefined());
    ecmaRuntimeCallInfo->SetThis(JSTaggedValue::Undefined());
    ecmaRuntimeCallInfo->SetCallArg(0, JSTaggedValue(static_cast<int>(bit)));
    ecmaRuntimeCallInfo->SetCallArg(1, numericValue.GetTaggedValue());

    [[maybe_unused]] auto prev = TestHelper::SetupFrame(thread, ecmaRuntimeCallInfo);
    JSTaggedValue result = BuiltinsBigInt::AsIntN(ecmaRuntimeCallInfo);
    TestHelper::TearDownFrame(thread, prev);

    EXPECT_TRUE(result.IsBigInt());
    JSHandle<BigInt> bigIntHandle(thread, result);
    JSHandle<EcmaString> resultStr = BigInt::ToString(thread, bigIntHandle);
    JSHandle<EcmaString> str = factory->NewFromASCII("9223372036854775807");
    EXPECT_EQ(EcmaStringAccessor::Compare(instance, resultStr, str), 0);
}

// AsIntN(64, (2 ^ 63))
HWTEST_F_L0(BuiltinsBigIntTest, AsIntN_002)
{
    ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
    JSHandle<JSTaggedValue> numericValue(factory->NewFromASCII("9223372036854775808"));
    int bit = 64; // 64-bit

    auto ecmaRuntimeCallInfo = TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), 8);
    ecmaRuntimeCallInfo->SetFunction(JSTaggedValue::Undefined());
    ecmaRuntimeCallInfo->SetThis(JSTaggedValue::Undefined());
    ecmaRuntimeCallInfo->SetCallArg(0, JSTaggedValue(static_cast<int>(bit)));
    ecmaRuntimeCallInfo->SetCallArg(1, numericValue.GetTaggedValue());

    [[maybe_unused]] auto prev = TestHelper::SetupFrame(thread, ecmaRuntimeCallInfo);
    JSTaggedValue result = BuiltinsBigInt::AsIntN(ecmaRuntimeCallInfo);
    TestHelper::TearDownFrame(thread, prev);

    EXPECT_TRUE(result.IsBigInt());
    JSHandle<BigInt> bigIntHandle(thread, result);
    JSHandle<EcmaString> resultStr = BigInt::ToString(thread, bigIntHandle);
    JSHandle<EcmaString> str = factory->NewFromASCII("-9223372036854775808");
    EXPECT_EQ(EcmaStringAccessor::Compare(instance, resultStr, str), 0);
}

// AsUintN(64, (2 ^ 64 - 1))
HWTEST_F_L0(BuiltinsBigIntTest, AsUintN_001)
{
    ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
    JSHandle<JSTaggedValue> numericValue(factory->NewFromASCII("18446744073709551615"));
    int bit = 64; // 64-bit

    auto ecmaRuntimeCallInfo = TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), 8);
    ecmaRuntimeCallInfo->SetFunction(JSTaggedValue::Undefined());
    ecmaRuntimeCallInfo->SetThis(JSTaggedValue::Undefined());
    ecmaRuntimeCallInfo->SetCallArg(0, JSTaggedValue(static_cast<int>(bit)));
    ecmaRuntimeCallInfo->SetCallArg(1, numericValue.GetTaggedValue());

    [[maybe_unused]] auto prev = TestHelper::SetupFrame(thread, ecmaRuntimeCallInfo);
    JSTaggedValue result = BuiltinsBigInt::AsUintN(ecmaRuntimeCallInfo);
    TestHelper::TearDownFrame(thread, prev);

    EXPECT_TRUE(result.IsBigInt());
    JSHandle<BigInt> bigIntHandle(thread, result);
    JSHandle<EcmaString> resultStr = BigInt::ToString(thread, bigIntHandle);
    JSHandle<EcmaString> str = factory->NewFromASCII("18446744073709551615");
    EXPECT_EQ(EcmaStringAccessor::Compare(instance, resultStr, str), 0);
}

// AsUintN(64, (2 ^ 64))
HWTEST_F_L0(BuiltinsBigIntTest, AsUintN_002)
{
    ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
    JSHandle<JSTaggedValue> numericValue(factory->NewFromASCII("18446744073709551616"));
    int bit = 64; // 64-bit

    auto ecmaRuntimeCallInfo = TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), 8);
    ecmaRuntimeCallInfo->SetFunction(JSTaggedValue::Undefined());
    ecmaRuntimeCallInfo->SetThis(JSTaggedValue::Undefined());
    ecmaRuntimeCallInfo->SetCallArg(0, JSTaggedValue(static_cast<int>(bit)));
    ecmaRuntimeCallInfo->SetCallArg(1, numericValue.GetTaggedValue());

    [[maybe_unused]] auto prev = TestHelper::SetupFrame(thread, ecmaRuntimeCallInfo);
    JSTaggedValue result = BuiltinsBigInt::AsUintN(ecmaRuntimeCallInfo);
    TestHelper::TearDownFrame(thread, prev);

    EXPECT_TRUE(result.IsBigInt());
    JSHandle<BigInt> bigIntHandle(thread, result);
    JSHandle<EcmaString> resultStr = BigInt::ToString(thread, bigIntHandle);
    JSHandle<EcmaString> str = factory->NewFromASCII("0");
    EXPECT_EQ(EcmaStringAccessor::Compare(instance, resultStr, str), 0);
}

// using locale
HWTEST_F_L0(BuiltinsBigIntTest, ToLocaleString_001)
{
    ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
    JSHandle<JSTaggedValue> numericValue(factory->NewFromASCII("123456789123456789"));

    auto ecmaRuntimeCallInfo1 = TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), 6);
    ecmaRuntimeCallInfo1->SetFunction(JSTaggedValue::Undefined());
    ecmaRuntimeCallInfo1->SetThis(JSTaggedValue::Undefined());
    ecmaRuntimeCallInfo1->SetCallArg(0, numericValue.GetTaggedValue());

    [[maybe_unused]] auto prev = TestHelper::SetupFrame(thread, ecmaRuntimeCallInfo1);
    JSTaggedValue result1 = BuiltinsBigInt::BigIntConstructor(ecmaRuntimeCallInfo1);
    TestHelper::TearDownFrame(thread, prev);

    JSHandle<BigInt> bigIntHandle(thread, result1);
    JSHandle<JSTaggedValue> locale(factory->NewFromASCII("de-DE"));

    auto ecmaRuntimeCallInfo2 = TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), 8);
    ecmaRuntimeCallInfo2->SetFunction(JSTaggedValue::Undefined());
    ecmaRuntimeCallInfo2->SetThis(bigIntHandle.GetTaggedValue());
    ecmaRuntimeCallInfo2->SetCallArg(0, locale.GetTaggedValue());
    ecmaRuntimeCallInfo2->SetCallArg(1, JSTaggedValue::Undefined());

    prev = TestHelper::SetupFrame(thread, ecmaRuntimeCallInfo2);
    JSTaggedValue result2 = BuiltinsBigInt::ToLocaleString(ecmaRuntimeCallInfo2);
    TestHelper::TearDownFrame(thread, prev);

    EXPECT_TRUE(result2.IsString());
    JSHandle<EcmaString> ecmaStrHandle(thread, result2);
    JSHandle<EcmaString> resultStr(factory->NewFromASCII("123.456.789.123.456.789"));
    EXPECT_EQ(EcmaStringAccessor::Compare(instance, ecmaStrHandle, resultStr), 0);
}

// using locale and options
HWTEST_F_L0(BuiltinsBigIntTest, ToLocaleString_002)
{
    ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
    JSHandle<GlobalEnv> env = thread->GetEcmaVM()->GetGlobalEnv();
    JSHandle<JSTaggedValue> objFun = env->GetObjectFunction();
    JSHandle<JSObject> optionsObj = factory->NewJSObjectByConstructor(JSHandle<JSFunction>(objFun), objFun);
    JSHandle<JSTaggedValue> numericValue(factory->NewFromASCII("123456789123456789"));
    JSHandle<JSTaggedValue> formatStyle = thread->GlobalConstants()->GetHandledStyleString();
    JSHandle<JSTaggedValue> styleKey(factory->NewFromASCII("currency"));
    JSHandle<JSTaggedValue> styleValue(factory->NewFromASCII("EUR"));

    auto ecmaRuntimeCallInfo1 = TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), 6);
    ecmaRuntimeCallInfo1->SetFunction(JSTaggedValue::Undefined());
    ecmaRuntimeCallInfo1->SetThis(JSTaggedValue::Undefined());
    ecmaRuntimeCallInfo1->SetCallArg(0, numericValue.GetTaggedValue());

    [[maybe_unused]] auto prev = TestHelper::SetupFrame(thread, ecmaRuntimeCallInfo1);
    JSTaggedValue result1 = BuiltinsBigInt::BigIntConstructor(ecmaRuntimeCallInfo1);
    TestHelper::TearDownFrame(thread, prev);

    JSHandle<BigInt> bigIntHandle(thread, result1);
    JSHandle<JSTaggedValue> locale(factory->NewFromASCII("de-DE"));
    JSObject::SetProperty(thread, optionsObj, formatStyle, styleKey);
    JSObject::SetProperty(thread, optionsObj, styleKey, styleValue);

    auto ecmaRuntimeCallInfo2 = TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), 8);
    ecmaRuntimeCallInfo2->SetFunction(JSTaggedValue::Undefined());
    ecmaRuntimeCallInfo2->SetThis(bigIntHandle.GetTaggedValue());
    ecmaRuntimeCallInfo2->SetCallArg(0, locale.GetTaggedValue());
    ecmaRuntimeCallInfo2->SetCallArg(1, optionsObj.GetTaggedValue());

    prev = TestHelper::SetupFrame(thread, ecmaRuntimeCallInfo2);
    JSTaggedValue result2 = BuiltinsBigInt::ToLocaleString(ecmaRuntimeCallInfo2);
    TestHelper::TearDownFrame(thread, prev);

    EXPECT_TRUE(result2.IsString());
    JSHandle<EcmaString> ecmaStrHandle(thread, result2);
    EXPECT_STREQ("123.456.789.123.456.789,00 €", EcmaStringAccessor(ecmaStrHandle).ToCString().c_str());
}

// 17.ToStirng()
HWTEST_F_L0(BuiltinsBigIntTest, ToString_001)
{
    ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
    JSHandle<JSTaggedValue> numericValue(factory->NewFromASCII("17"));

    auto ecmaRuntimeCallInfo1 = TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), 6);
    ecmaRuntimeCallInfo1->SetFunction(JSTaggedValue::Undefined());
    ecmaRuntimeCallInfo1->SetThis(JSTaggedValue::Undefined());
    ecmaRuntimeCallInfo1->SetCallArg(0, numericValue.GetTaggedValue());

    [[maybe_unused]] auto prev = TestHelper::SetupFrame(thread, ecmaRuntimeCallInfo1);
    JSTaggedValue result1 = BuiltinsBigInt::BigIntConstructor(ecmaRuntimeCallInfo1);
    TestHelper::TearDownFrame(thread, prev);

    JSHandle<BigInt> bigIntHandle(thread, result1);
    auto ecmaRuntimeCallInfo2 = TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), 6);
    ecmaRuntimeCallInfo2->SetFunction(JSTaggedValue::Undefined());
    ecmaRuntimeCallInfo2->SetThis(bigIntHandle.GetTaggedValue());
    ecmaRuntimeCallInfo2->SetCallArg(0, JSTaggedValue::Undefined());

    prev = TestHelper::SetupFrame(thread, ecmaRuntimeCallInfo2);
    JSTaggedValue result2 = BuiltinsBigInt::ToString(ecmaRuntimeCallInfo2);
    TestHelper::TearDownFrame(thread, prev);

    EXPECT_TRUE(result2.IsString());
    JSHandle<EcmaString> ecmaStrHandle(thread, result2);
    EXPECT_STREQ("17", EcmaStringAccessor(ecmaStrHandle).ToCString().c_str());
}

// -0.ToStirng()
HWTEST_F_L0(BuiltinsBigIntTest, ToString_002)
{
    ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
    JSHandle<JSTaggedValue> numericValue(factory->NewFromASCII("-0"));

    auto ecmaRuntimeCallInfo1 = TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), 6);
    ecmaRuntimeCallInfo1->SetFunction(JSTaggedValue::Undefined());
    ecmaRuntimeCallInfo1->SetThis(JSTaggedValue::Undefined());
    ecmaRuntimeCallInfo1->SetCallArg(0, numericValue.GetTaggedValue());

    [[maybe_unused]] auto prev = TestHelper::SetupFrame(thread, ecmaRuntimeCallInfo1);
    JSTaggedValue result1 = BuiltinsBigInt::BigIntConstructor(ecmaRuntimeCallInfo1);
    TestHelper::TearDownFrame(thread, prev);

    JSHandle<BigInt> bigIntHandle(thread, result1);
    auto ecmaRuntimeCallInfo2 = TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), 6);
    ecmaRuntimeCallInfo2->SetFunction(JSTaggedValue::Undefined());
    ecmaRuntimeCallInfo2->SetThis(bigIntHandle.GetTaggedValue());
    ecmaRuntimeCallInfo2->SetCallArg(0, JSTaggedValue::Undefined());

    prev = TestHelper::SetupFrame(thread, ecmaRuntimeCallInfo2);
    JSTaggedValue result2 = BuiltinsBigInt::ToString(ecmaRuntimeCallInfo2);
    TestHelper::TearDownFrame(thread, prev);

    EXPECT_TRUE(result2.IsString());
    JSHandle<EcmaString> ecmaStrHandle(thread, result2);
    EXPECT_STREQ("0", EcmaStringAccessor(ecmaStrHandle).ToCString().c_str());
}

// -10.ToStirng(2)
HWTEST_F_L0(BuiltinsBigIntTest, ToString_003)
{
    ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
    JSHandle<JSTaggedValue> numericValue(factory->NewFromASCII("-10"));

    auto ecmaRuntimeCallInfo1 = TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), 6);
    ecmaRuntimeCallInfo1->SetFunction(JSTaggedValue::Undefined());
    ecmaRuntimeCallInfo1->SetThis(JSTaggedValue::Undefined());
    ecmaRuntimeCallInfo1->SetCallArg(0, numericValue.GetTaggedValue());

    [[maybe_unused]] auto prev = TestHelper::SetupFrame(thread, ecmaRuntimeCallInfo1);
    JSTaggedValue result1 = BuiltinsBigInt::BigIntConstructor(ecmaRuntimeCallInfo1);
    TestHelper::TearDownFrame(thread, prev);

    JSHandle<BigInt> bigIntHandle(thread, result1);
    JSHandle<JSTaggedValue> radix(thread, JSTaggedValue(2));
    auto ecmaRuntimeCallInfo2 = TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), 6);
    ecmaRuntimeCallInfo2->SetFunction(JSTaggedValue::Undefined());
    ecmaRuntimeCallInfo2->SetThis(bigIntHandle.GetTaggedValue());
    ecmaRuntimeCallInfo2->SetCallArg(0, radix.GetTaggedValue());

    prev = TestHelper::SetupFrame(thread, ecmaRuntimeCallInfo2);
    JSTaggedValue result2 = BuiltinsBigInt::ToString(ecmaRuntimeCallInfo2);
    TestHelper::TearDownFrame(thread, prev);

    EXPECT_TRUE(result2.IsString());
    JSHandle<EcmaString> ecmaStrHandle(thread, result2);
    EXPECT_STREQ("-1010", EcmaStringAccessor(ecmaStrHandle).ToCString().c_str());
}

// 254.ToStirng(16)
HWTEST_F_L0(BuiltinsBigIntTest, ToString_004)
{
    ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
    JSHandle<JSTaggedValue> numericValue(factory->NewFromASCII("254"));

    auto ecmaRuntimeCallInfo1 = TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), 6);
    ecmaRuntimeCallInfo1->SetFunction(JSTaggedValue::Undefined());
    ecmaRuntimeCallInfo1->SetThis(JSTaggedValue::Undefined());
    ecmaRuntimeCallInfo1->SetCallArg(0, numericValue.GetTaggedValue());

    [[maybe_unused]] auto prev = TestHelper::SetupFrame(thread, ecmaRuntimeCallInfo1);
    JSTaggedValue result1 = BuiltinsBigInt::BigIntConstructor(ecmaRuntimeCallInfo1);
    TestHelper::TearDownFrame(thread, prev);

    JSHandle<BigInt> bigIntHandle(thread, result1);
    JSHandle<JSTaggedValue> radix(thread, JSTaggedValue(16));
    auto ecmaRuntimeCallInfo2 = TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), 6);
    ecmaRuntimeCallInfo2->SetFunction(JSTaggedValue::Undefined());
    ecmaRuntimeCallInfo2->SetThis(bigIntHandle.GetTaggedValue());
    ecmaRuntimeCallInfo2->SetCallArg(0, radix.GetTaggedValue());

    prev = TestHelper::SetupFrame(thread, ecmaRuntimeCallInfo2);
    JSTaggedValue result2 = BuiltinsBigInt::ToString(ecmaRuntimeCallInfo2);
    TestHelper::TearDownFrame(thread, prev);

    EXPECT_TRUE(result2.IsString());
    JSHandle<EcmaString> ecmaStrHandle(thread, result2);
    EXPECT_STREQ("fe", EcmaStringAccessor(ecmaStrHandle).ToCString().c_str());
}

// BigInt.ValueOf
HWTEST_F_L0(BuiltinsBigIntTest, ValueOf_001)
{
    ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
    JSHandle<JSTaggedValue> numericValue(factory->NewFromASCII("-65536"));

    auto ecmaRuntimeCallInfo = TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), 6);
    ecmaRuntimeCallInfo->SetFunction(JSTaggedValue::Undefined());
    ecmaRuntimeCallInfo->SetThis(JSTaggedValue::Undefined());
    ecmaRuntimeCallInfo->SetCallArg(0, numericValue.GetTaggedValue());

    [[maybe_unused]] auto prev = TestHelper::SetupFrame(thread, ecmaRuntimeCallInfo);
    JSTaggedValue result1 = BuiltinsBigInt::BigIntConstructor(ecmaRuntimeCallInfo);
    TestHelper::TearDownFrame(thread, prev);

    JSHandle<BigInt> bigIntHandle(thread, result1);
    auto ecmaRuntimeCallInfo2 = TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), 4);
    ecmaRuntimeCallInfo2->SetFunction(JSTaggedValue::Undefined());
    ecmaRuntimeCallInfo2->SetThis(bigIntHandle.GetTaggedValue());

    prev = TestHelper::SetupFrame(thread, ecmaRuntimeCallInfo2);
    JSTaggedValue result2 = BuiltinsBigInt::ValueOf(ecmaRuntimeCallInfo2);
    TestHelper::TearDownFrame(thread, prev);

    EXPECT_EQ(BigInt::SameValue(result1, result2), true);
}

// Object.ValueOf
HWTEST_F_L0(BuiltinsBigIntTest, ValueOf_002)
{
    ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
    JSHandle<JSTaggedValue> numericValue(factory->NewFromASCII("65535"));

    auto ecmaRuntimeCallInfo = TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), 6);
    ecmaRuntimeCallInfo->SetFunction(JSTaggedValue::Undefined());
    ecmaRuntimeCallInfo->SetThis(JSTaggedValue::Undefined());
    ecmaRuntimeCallInfo->SetCallArg(0, numericValue.GetTaggedValue());

    [[maybe_unused]] auto prev = TestHelper::SetupFrame(thread, ecmaRuntimeCallInfo);
    JSTaggedValue result1 = BuiltinsBigInt::BigIntConstructor(ecmaRuntimeCallInfo);
    TestHelper::TearDownFrame(thread, prev);

    JSHandle<BigInt> bigIntHandle(thread, result1);
    JSHandle<JSTaggedValue> bigIntObj(bigIntHandle);

    JSHandle<JSPrimitiveRef> jsPrimitiveRef = factory->NewJSPrimitiveRef(PrimitiveType::PRIMITIVE_BIGINT, bigIntObj);
    auto ecmaRuntimeCallInfo2 = TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), 4);
    ecmaRuntimeCallInfo2->SetFunction(JSTaggedValue::Undefined());
    ecmaRuntimeCallInfo2->SetThis(jsPrimitiveRef.GetTaggedValue());

    prev = TestHelper::SetupFrame(thread, ecmaRuntimeCallInfo2);
    JSTaggedValue result2 = BuiltinsBigInt::ValueOf(ecmaRuntimeCallInfo2);
    TestHelper::TearDownFrame(thread, prev);

    EXPECT_EQ(BigInt::SameValue(bigIntHandle.GetTaggedValue(), result2), true);
}

// testcases of NumberToBigint()
HWTEST_F_L0(BuiltinsBigIntTest, NumberToBigint)
{
    JSHandle<JSTaggedValue> number(thread, JSTaggedValue::Undefined());
    JSHandle<JSTaggedValue> bigint(thread, JSTaggedValue::Undefined());

    number = JSHandle<JSTaggedValue>(thread, JSTaggedValue(base::MAX_VALUE));
    bigint = JSHandle<JSTaggedValue>(thread, BigInt::NumberToBigInt(thread, number));
    ASSERT_TRUE(bigint->IsBigInt());
    bool compareRes = JSTaggedValue::Equal(thread, number, bigint);
    ASSERT_TRUE(compareRes);

    number = JSHandle<JSTaggedValue>(thread, JSTaggedValue(-base::MAX_VALUE));
    bigint = JSHandle<JSTaggedValue>(thread, BigInt::NumberToBigInt(thread, number));
    ASSERT_TRUE(bigint->IsBigInt());
    compareRes = JSTaggedValue::Equal(thread, number, bigint);
    ASSERT_TRUE(JSHandle<BigInt>::Cast(bigint)->GetSign());
    ASSERT_TRUE(compareRes);

    number = JSHandle<JSTaggedValue>(thread, JSTaggedValue(-0xffffffff));
    bigint = JSHandle<JSTaggedValue>(thread, BigInt::NumberToBigInt(thread, number));
    ASSERT_TRUE(bigint->IsBigInt());
    compareRes = JSTaggedValue::Equal(thread, number, bigint);
    ASSERT_TRUE(compareRes);

    number = JSHandle<JSTaggedValue>(thread, JSTaggedValue(0));
    bigint = JSHandle<JSTaggedValue>(thread, BigInt::NumberToBigInt(thread, number));
    ASSERT_TRUE(bigint->IsBigInt());
    compareRes = JSTaggedValue::Equal(thread, number, bigint);
    ASSERT_TRUE(compareRes);

    number = JSHandle<JSTaggedValue>(thread, JSTaggedValue(std::numeric_limits<double>::infinity()));
    bigint = JSHandle<JSTaggedValue>(thread, BigInt::NumberToBigInt(thread, number));
    ASSERT_TRUE(bigint->IsException());
    thread->ClearException();
}

// testcases of BigintToNumber()
HWTEST_F_L0(BuiltinsBigIntTest, BigintToNumber)
{
    ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
    JSHandle<JSTaggedValue> bigint(thread, JSTaggedValue::Undefined());
    JSTaggedNumber number(0);

    JSHandle<JSTaggedValue> parma(factory->NewFromASCII("0xffff"));
    bigint = JSHandle<JSTaggedValue>(thread, JSTaggedValue::ToBigInt(thread, parma));
    ASSERT_TRUE(bigint->IsBigInt());
    number = BigInt::BigIntToNumber(JSHandle<BigInt>::Cast(bigint));
    ASSERT_EQ(number.GetNumber(), static_cast<double>(0xffff));

    parma = JSHandle<JSTaggedValue>(
        factory->NewFromASCII("0xfffffffffffff8000000000000000000000000000000000000000000000000000"
                              "0000000000000000000000000000000000000000000000000000000000000000000"
                              "0000000000000000000000000000000000000000000000000000000000000000000"
                              "000000000000000000000000000000000000000000000000000000000"));
    bigint = JSHandle<JSTaggedValue>(thread, JSTaggedValue::ToBigInt(thread, parma));
    ASSERT_TRUE(bigint->IsBigInt());
    number = BigInt::BigIntToNumber(JSHandle<BigInt>::Cast(bigint));
    ASSERT_EQ(number.GetNumber(), base::MAX_VALUE);

    parma = JSHandle<JSTaggedValue>(thread, JSTaggedValue::False());
    bigint = JSHandle<JSTaggedValue>(thread, JSTaggedValue::ToBigInt(thread, parma));
    ASSERT_TRUE(bigint->IsBigInt());
    ASSERT_TRUE(JSHandle<BigInt>::Cast(bigint)->IsZero());
    number = BigInt::BigIntToNumber(JSHandle<BigInt>::Cast(bigint));
    ASSERT_EQ(number.GetNumber(), 0.0);

    parma = JSHandle<JSTaggedValue>(thread, JSTaggedValue(base::MAX_VALUE));
    bigint = JSHandle<JSTaggedValue>(thread, BigInt::NumberToBigInt(thread, parma));
    ASSERT_TRUE(bigint->IsBigInt());
    number = BigInt::BigIntToNumber(JSHandle<BigInt>::Cast(bigint));
    ASSERT_EQ(number.GetNumber(), base::MAX_VALUE);

    parma = JSHandle<JSTaggedValue>(thread, JSTaggedValue(-base::MAX_VALUE));
    bigint = JSHandle<JSTaggedValue>(thread, BigInt::NumberToBigInt(thread, parma));
    ASSERT_TRUE(bigint->IsBigInt());
    number = BigInt::BigIntToNumber(JSHandle<BigInt>::Cast(bigint));
    ASSERT_EQ(number.GetNumber(), -base::MAX_VALUE);

    parma = JSHandle<JSTaggedValue>(thread, JSTaggedValue(-0xffffffff));
    bigint = JSHandle<JSTaggedValue>(thread, BigInt::NumberToBigInt(thread, parma));
    ASSERT_TRUE(bigint->IsBigInt());
    number = BigInt::BigIntToNumber(JSHandle<BigInt>::Cast(bigint));
    ASSERT_EQ(number.GetNumber(), -0xffffffff);
}

// testcases of StringToBigInt(EcmaString)
HWTEST_F_L0(BuiltinsBigIntTest, StringToBigInt)
{
    ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
    JSHandle<JSTaggedValue> bigint;
    JSHandle<EcmaString> str;
    JSHandle<JSTaggedValue> parma;

    // hex string
    parma = JSHandle<JSTaggedValue>(factory->NewFromASCII("0xffff"));
    bigint = JSHandle<JSTaggedValue>(thread, base::NumberHelper::StringToBigInt(thread, parma));
    ASSERT_TRUE(bigint->IsBigInt());
    str = BigInt::ToString(thread, JSHandle<BigInt>::Cast(bigint), BigInt::HEXADECIMAL);
    parma = JSHandle<JSTaggedValue>(factory->NewFromASCII("ffff"));
    ASSERT_EQ(EcmaStringAccessor::Compare(instance, str, JSHandle<EcmaString>(parma)), 0);

    parma = JSHandle<JSTaggedValue>(factory->NewFromASCII("0XFFFF"));
    bigint = JSHandle<JSTaggedValue>(thread, base::NumberHelper::StringToBigInt(thread, parma));
    ASSERT_TRUE(bigint->IsBigInt());
    str = BigInt::ToString(thread, JSHandle<BigInt>::Cast(bigint), BigInt::HEXADECIMAL);
    parma = JSHandle<JSTaggedValue>(factory->NewFromASCII("ffff"));
    ASSERT_EQ(EcmaStringAccessor::Compare(instance, str, JSHandle<EcmaString>(parma)), 0);

    // binary string
    parma = JSHandle<JSTaggedValue>(factory->NewFromASCII("0b11111111"));
    bigint = JSHandle<JSTaggedValue>(thread, base::NumberHelper::StringToBigInt(thread, parma));
    ASSERT_TRUE(bigint->IsBigInt());
    str = BigInt::ToString(thread, JSHandle<BigInt>::Cast(bigint), BigInt::BINARY);
    parma = JSHandle<JSTaggedValue>(factory->NewFromASCII("11111111"));
    ASSERT_EQ(EcmaStringAccessor::Compare(instance, str, JSHandle<EcmaString>(parma)), 0);

    parma = JSHandle<JSTaggedValue>(factory->NewFromASCII("0B11111111"));
    bigint = JSHandle<JSTaggedValue>(thread, base::NumberHelper::StringToBigInt(thread, parma));
    ASSERT_TRUE(bigint->IsBigInt());
    str = BigInt::ToString(thread, JSHandle<BigInt>::Cast(bigint), BigInt::BINARY);
    parma = JSHandle<JSTaggedValue>(factory->NewFromASCII("11111111"));
    ASSERT_EQ(EcmaStringAccessor::Compare(instance, str, JSHandle<EcmaString>(parma)), 0);

    // octal string
    parma = JSHandle<JSTaggedValue>(factory->NewFromASCII("0o123456"));
    bigint = JSHandle<JSTaggedValue>(thread, base::NumberHelper::StringToBigInt(thread, parma));
    ASSERT_TRUE(bigint->IsBigInt());
    str = BigInt::ToString(thread, JSHandle<BigInt>::Cast(bigint), BigInt::OCTAL);
    parma = JSHandle<JSTaggedValue>(factory->NewFromASCII("123456"));
    ASSERT_EQ(EcmaStringAccessor::Compare(instance, str, JSHandle<EcmaString>(parma)), 0);

    parma = JSHandle<JSTaggedValue>(factory->NewFromASCII("0O123456"));
    bigint = JSHandle<JSTaggedValue>(thread, base::NumberHelper::StringToBigInt(thread, parma));
    ASSERT_TRUE(bigint->IsBigInt());
    str = BigInt::ToString(thread, JSHandle<BigInt>::Cast(bigint), BigInt::OCTAL);
    parma = JSHandle<JSTaggedValue>(factory->NewFromASCII("123456"));
    ASSERT_EQ(EcmaStringAccessor::Compare(instance, str, JSHandle<EcmaString>(parma)), 0);

    // decimal string
    parma = JSHandle<JSTaggedValue>(factory->NewFromASCII("999999999"));
    bigint = JSHandle<JSTaggedValue>(thread, base::NumberHelper::StringToBigInt(thread, parma));
    ASSERT_TRUE(bigint->IsBigInt());
    str = BigInt::ToString(thread, JSHandle<BigInt>::Cast(bigint));
    ASSERT_EQ(EcmaStringAccessor::Compare(instance, str, JSHandle<EcmaString>(parma)), 0);

    // string has space
    parma = JSHandle<JSTaggedValue>(factory->NewFromASCII("  123  "));
    bigint = JSHandle<JSTaggedValue>(thread, base::NumberHelper::StringToBigInt(thread, parma));
    ASSERT_TRUE(bigint->IsBigInt());
    JSHandle<JSTaggedValue> number(thread, JSTaggedValue(static_cast<double>(123)));
    bool compareRes = JSTaggedValue::Equal(thread, bigint, number);
    ASSERT_TRUE(compareRes);

    parma = JSHandle<JSTaggedValue>(factory->NewFromASCII("123   "));
    bigint = JSHandle<JSTaggedValue>(thread, base::NumberHelper::StringToBigInt(thread, parma));
    ASSERT_TRUE(bigint->IsBigInt());
    number = JSHandle<JSTaggedValue>(thread, JSTaggedValue(static_cast<double>(123)));
    compareRes = JSTaggedValue::Equal(thread, bigint, number);
    ASSERT_TRUE(compareRes);

    parma = JSHandle<JSTaggedValue>(factory->NewFromASCII("   123"));
    bigint = JSHandle<JSTaggedValue>(thread, base::NumberHelper::StringToBigInt(thread, parma));
    ASSERT_TRUE(bigint->IsBigInt());
    number = JSHandle<JSTaggedValue>(thread, JSTaggedValue(static_cast<double>(123)));
    compareRes = JSTaggedValue::Equal(thread, bigint, number);
    ASSERT_TRUE(compareRes);

    parma = JSHandle<JSTaggedValue>(factory->NewFromASCII(""));
    bigint = JSHandle<JSTaggedValue>(thread, base::NumberHelper::StringToBigInt(thread, parma));
    ASSERT_TRUE(bigint->IsBigInt());
    ASSERT_TRUE(JSHandle<BigInt>::Cast(bigint)->IsZero());

    parma = JSHandle<JSTaggedValue>(factory->NewFromASCII("    "));
    bigint = JSHandle<JSTaggedValue>(thread, base::NumberHelper::StringToBigInt(thread, parma));
    ASSERT_TRUE(bigint->IsBigInt());
    ASSERT_TRUE(JSHandle<BigInt>::Cast(bigint)->IsZero());
}
}  // namespace panda::test