/* * Copyright (c) 2022 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/js_api_plain_array.h" #include "ecmascript/containers/containers_private.h" #include "ecmascript/ecma_string.h" #include "ecmascript/ecma_vm.h" #include "ecmascript/global_env.h" #include "ecmascript/js_api_plain_array_iterator.h" #include "ecmascript/js_function.h" #include "ecmascript/js_handle.h" #include "ecmascript/js_iterator.h" #include "ecmascript/js_object-inl.h" #include "ecmascript/js_tagged_value.h" #include "ecmascript/object_factory.h" #include "ecmascript/tests/test_helper.h" using namespace panda; using namespace panda::ecmascript; namespace panda::test { class JSAPIPlainArrayTest : public testing::Test { public: static void SetUpTestCase() { GTEST_LOG_(INFO) << "SetUpTestCase"; } static void TearDownTestCase() { GTEST_LOG_(INFO) << "TearDownCase"; } void SetUp() override { TestHelper::CreateEcmaVMWithScope(instance, thread, scope); } void TearDown() override { TestHelper::DestroyEcmaVMWithScope(instance, scope); } EcmaVM *instance {nullptr}; ecmascript::EcmaHandleScope *scope {nullptr}; JSThread *thread {nullptr}; protected: JSAPIPlainArray *CreatePlainArray() { ObjectFactory *factory = thread->GetEcmaVM()->GetFactory(); JSHandle env = thread->GetEcmaVM()->GetGlobalEnv(); JSHandle globalObject = env->GetJSGlobalObject(); JSHandle key(factory->NewFromASCII("ArkPrivate")); JSHandle value = JSObject::GetProperty(thread, JSHandle(globalObject), key).GetValue(); auto objCallInfo = TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), 6); // 6 means the value objCallInfo->SetFunction(JSTaggedValue::Undefined()); objCallInfo->SetThis(value.GetTaggedValue()); objCallInfo->SetCallArg(0, JSTaggedValue(static_cast(containers::ContainerTag::PlainArray))); [[maybe_unused]] auto prev = TestHelper::SetupFrame(thread, objCallInfo.get()); JSTaggedValue result = containers::ContainersPrivate::Load(objCallInfo.get()); TestHelper::TearDownFrame(thread, prev); JSHandle constructor(thread, result); JSHandle plainArray( factory->NewJSObjectByConstructor(JSHandle(constructor), constructor)); JSHandle keyArray = JSHandle(factory->NewTaggedArray(8)); // 8 means the value JSHandle valueArray = JSHandle(factory->NewTaggedArray(8)); // 8 means the value plainArray->SetKeys(thread, keyArray); plainArray->SetValues(thread, valueArray); return *plainArray; } }; HWTEST_F_L0(JSAPIPlainArrayTest, PlainArrayCreate) { JSAPIPlainArray *plainArray = CreatePlainArray(); EXPECT_TRUE(plainArray != nullptr); } HWTEST_F_L0(JSAPIPlainArrayTest, PA_AddAndGetKeyAtAndClear) { constexpr uint32_t NODE_NUMBERS = 8; // 8 means the value ObjectFactory *factory = thread->GetEcmaVM()->GetFactory(); JSMutableHandle key(thread, JSTaggedValue::Undefined()); JSMutableHandle value(thread, JSTaggedValue::Undefined()); // test JSAPIPlainArray JSHandle array(thread, CreatePlainArray()); std::string myValue("myvalue"); for (uint32_t i = 0; i < NODE_NUMBERS; i++) { uint32_t ikey = 100 + i; std::string ivalue = myValue + std::to_string(i); key.Update(JSTaggedValue(ikey)); value.Update(factory->NewFromStdString(ivalue).GetTaggedValue()); JSAPIPlainArray::Add(thread, array, key, value); } EXPECT_EQ(array->GetSize(), static_cast(NODE_NUMBERS)); for (uint32_t i = 0; i < NODE_NUMBERS; i++) { uint32_t ikey = 100 + i; std::string ivalue = myValue + std::to_string(i); key.Update(JSTaggedValue(ikey)); value.Update(factory->NewFromStdString(ivalue).GetTaggedValue()); // test getKeyAt JSTaggedValue gvalue = array->GetKeyAt(i); EXPECT_EQ(gvalue, key.GetTaggedValue()); } // test clear array->Clear(thread); EXPECT_EQ(array->GetSize(), 0); // 0 means the value } HWTEST_F_L0(JSAPIPlainArrayTest, PA_CloneAndHasAndGet) { constexpr uint32_t NODE_NUMBERS = 8; // 8 means the value ObjectFactory *factory = thread->GetEcmaVM()->GetFactory(); JSMutableHandle key(thread, JSTaggedValue::Undefined()); JSMutableHandle value(thread, JSTaggedValue::Undefined()); // test JSAPIPlainArray JSHandle array(thread, CreatePlainArray()); std::string myValue("myvalue"); for (uint32_t i = 0; i < NODE_NUMBERS; i++) { uint32_t ikey = 100 + i; std::string ivalue = myValue + std::to_string(i); key.Update(JSTaggedValue(ikey)); value.Update(factory->NewFromStdString(ivalue).GetTaggedValue()); JSAPIPlainArray::Add(thread, array, key, value); } EXPECT_EQ(array->GetSize(), static_cast(NODE_NUMBERS)); // test clone JSHandle newArray(thread, CreatePlainArray()); EXPECT_EQ(newArray->GetSize(), 0); // 0 means the value newArray = JSAPIPlainArray::Clone(thread, array); EXPECT_EQ(newArray->GetSize(), static_cast(NODE_NUMBERS)); // test has key.Update(JSTaggedValue(103)); // 103 means the value int32_t lkey = 103; bool result = array->Has(lkey); EXPECT_TRUE(result); // test get myValue = std::string("myvalue3"); value.Update(factory->NewFromStdString(myValue).GetTaggedValue()); EXPECT_TRUE(JSTaggedValue::Equal(thread, JSHandle(thread, array->Get(key.GetTaggedValue())), value)); } HWTEST_F_L0(JSAPIPlainArrayTest, PA_GetIndexOfKeyAndGeIndexOfValueAndIsEmptyAndRemoveRangeFrom) { constexpr uint32_t NODE_NUMBERS = 8; // 8 means the value ObjectFactory *factory = thread->GetEcmaVM()->GetFactory(); JSMutableHandle key(thread, JSTaggedValue::Undefined()); JSMutableHandle value(thread, JSTaggedValue::Undefined()); JSHandle array(thread, CreatePlainArray()); EXPECT_TRUE(array->IsEmpty()); std::string myValue("myvalue"); for (uint32_t i = 0; i < NODE_NUMBERS; i++) { uint32_t ikey = 100 + i; std::string ivalue = myValue + std::to_string(i); key.Update(JSTaggedValue(ikey)); value.Update(factory->NewFromStdString(ivalue).GetTaggedValue()); JSAPIPlainArray::Add(thread, array, key, value); } EXPECT_EQ(array->GetSize(), static_cast(NODE_NUMBERS)); EXPECT_FALSE(array->IsEmpty()); value.Update(JSTaggedValue(103)); // 103 means the value int32_t lvalue = 103; JSTaggedValue value2 = array->GetIndexOfKey(lvalue); EXPECT_EQ(value2.GetNumber(), 3); // 3 means the value myValue = "myvalue2"; value.Update(factory->NewFromStdString(myValue).GetTaggedValue()); JSTaggedValue value3 = array->GetIndexOfValue(value.GetTaggedValue()); EXPECT_EQ(value3.GetNumber(), 2); // 2 means the value value.Update(JSTaggedValue(1)); int32_t batchSize = 3; // 3 means the value lvalue = 1; value3 = array->RemoveRangeFrom(thread, lvalue, batchSize); EXPECT_EQ(value3.GetNumber(), 3); // 3 means the value EXPECT_EQ(array->GetSize(), static_cast(NODE_NUMBERS - 3)); } HWTEST_F_L0(JSAPIPlainArrayTest, PA_RemvoeAnrRemvoeAtAndSetValueAtAndGetValueAt) { constexpr uint32_t NODE_NUMBERS = 8; // 8 means the value ObjectFactory *factory = thread->GetEcmaVM()->GetFactory(); JSMutableHandle key(thread, JSTaggedValue::Undefined()); JSMutableHandle value(thread, JSTaggedValue::Undefined()); JSHandle array(thread, CreatePlainArray()); EXPECT_TRUE(array->IsEmpty()); std::string myValue("myvalue"); for (uint32_t i = 0; i < NODE_NUMBERS; i++) { uint32_t ikey = 100 + i; std::string ivalue = myValue + std::to_string(i); key.Update(JSTaggedValue(ikey)); value.Update(factory->NewFromStdString(ivalue).GetTaggedValue()); JSAPIPlainArray::Add(thread, array, key, value); } EXPECT_EQ(array->GetSize(), static_cast(NODE_NUMBERS)); EXPECT_FALSE(array->IsEmpty()); // test Remove myValue = "myvalue2"; value.Update(factory->NewFromStdString(myValue).GetTaggedValue()); JSTaggedValue taggedValue = array->Remove(thread, JSTaggedValue(102)); // 102 means the value EXPECT_TRUE(JSTaggedValue::Equal(thread, value, JSHandle(thread, taggedValue))); // test RemoveAt myValue = "myvalue4"; value.Update(factory->NewFromStdString(myValue).GetTaggedValue()); taggedValue = array->RemoveAt(thread, JSTaggedValue(3)); // 3 means the value EXPECT_TRUE(JSTaggedValue::Equal(thread, value, JSHandle(thread, taggedValue))); EXPECT_EQ(array->GetSize(), static_cast(NODE_NUMBERS - 2)); // test SetValueAt myValue = "myvalue14"; value.Update(factory->NewFromStdString(myValue).GetTaggedValue()); array->SetValueAt(thread, JSTaggedValue(3), value.GetTaggedValue()); // 3 means the value int32_t lvalue = 3; // 3 means the value taggedValue = array->GetValueAt(lvalue); EXPECT_TRUE(JSTaggedValue::Equal(thread, value, JSHandle(thread, taggedValue))); } HWTEST_F_L0(JSAPIPlainArrayTest, PA_GetOwnProperty) { constexpr uint32_t DEFAULT_LENGTH = 8; ObjectFactory *factory = thread->GetEcmaVM()->GetFactory(); JSHandle toor(thread, CreatePlainArray()); JSMutableHandle key(thread, JSTaggedValue::Undefined()); JSMutableHandle value(thread, JSTaggedValue::Undefined()); std::string plainArrayvalue("plainArrayvalue"); for (uint32_t i = 0; i < DEFAULT_LENGTH; i++) { uint32_t ikey = 100 + i; std::string ivalue = plainArrayvalue + std::to_string(i); key.Update(JSTaggedValue(ikey)); value.Update(factory->NewFromStdString(ivalue).GetTaggedValue()); JSAPIPlainArray::Add(thread, toor, key, value); } // test GetOwnProperty int testInt = 100 + 1; JSHandle plainArrayKey1(thread, JSTaggedValue(testInt)); EXPECT_TRUE(JSAPIPlainArray::GetOwnProperty(thread, toor, plainArrayKey1)); testInt = 100 + 20; JSHandle plainArrayKey2(thread, JSTaggedValue(testInt)); EXPECT_FALSE(JSAPIPlainArray::GetOwnProperty(thread, toor, plainArrayKey2)); } HWTEST_F_L0(JSAPIPlainArrayTest, PA_ToString) { constexpr uint32_t NODE_NUMBERS = 3; // 3 means the value ObjectFactory *factory = thread->GetEcmaVM()->GetFactory(); JSMutableHandle key(thread, JSTaggedValue::Undefined()); JSMutableHandle value(thread, JSTaggedValue::Undefined()); // test JSAPIPlainArray JSHandle array(thread, CreatePlainArray()); JSTaggedValue result1 = JSAPIPlainArray::ToString(thread, array); JSHandle resultHandle1(thread, result1); [[maybe_unused]] auto *res1 = EcmaString::Cast(resultHandle1.GetTaggedValue().GetTaggedObject()); JSHandle det = thread->GetEcmaVM()->GetFactory()->NewFromASCII(""); ASSERT_EQ(res1->Compare(*det), 0); for (uint32_t i = 0; i < NODE_NUMBERS; i++) { uint32_t ikey = i; std::string ivalue = std::to_string(i); key.Update(JSTaggedValue(ikey)); value.Update(factory->NewFromStdString(ivalue).GetTaggedValue()); JSAPIPlainArray::Add(thread, array, key, value); } JSHandle str = thread->GetEcmaVM()->GetFactory()->NewFromASCII("0:0,1:1,2:2"); JSTaggedValue result = JSAPIPlainArray::ToString(thread, array); JSHandle resultHandle(thread, result); [[maybe_unused]] auto *res = EcmaString::Cast(resultHandle.GetTaggedValue().GetTaggedObject()); ASSERT_EQ(res->Compare(*str), 0); } } // namespace panda::test