/* * 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_set_iterator.h" #include "ecmascript/global_env.h" #include "ecmascript/js_array.h" #include "ecmascript/js_set.h" #include "ecmascript/linked_hash_table.h" #include "ecmascript/tests/test_helper.h" using namespace panda; using namespace panda::ecmascript; namespace panda::test { class JSSetIteratorTest : 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}; }; static JSSet *CreateJSSet(JSThread *thread) { ObjectFactory *factory = thread->GetEcmaVM()->GetFactory(); JSHandle env = thread->GetEcmaVM()->GetGlobalEnv(); JSHandle constructor = env->GetBuiltinsSetFunction(); JSHandle set = JSHandle::Cast(factory->NewJSObjectByConstructor(JSHandle(constructor), constructor)); JSHandle hashSet = LinkedHashSet::Create(thread); set->SetLinkedSet(thread, hashSet); return JSSet::Cast(set.GetTaggedValue().GetTaggedObject()); } /** * @tc.name: CreateSetIterator * @tc.desc: Call "CreateSetIterator" function create SetIterator,Check whether the the attribute setting of SetIterator * through "GetNextIndex" and "GetIterationKind" function is within expectations. * @tc.type: FUNC * @tc.require: */ HWTEST_F_L0(JSSetIteratorTest, CreateSetIterator) { JSHandle jsSet(thread, CreateJSSet(thread)); EXPECT_TRUE(*jsSet != nullptr); JSHandle setIteratorValue1 = JSSetIterator::CreateSetIterator(thread, JSHandle(jsSet), IterationKind::KEY); EXPECT_EQ(setIteratorValue1->IsJSSetIterator(), true); JSHandle setIterator1(setIteratorValue1); EXPECT_EQ(JSTaggedValue::SameValue(setIterator1->GetIteratedSet(), jsSet->GetLinkedSet()), true); EXPECT_EQ(setIterator1->GetNextIndex(), 0U); EXPECT_EQ(setIterator1->GetIterationKind(), IterationKind::KEY); JSHandle setIteratorValue2 = JSSetIterator::CreateSetIterator(thread, JSHandle(jsSet), IterationKind::VALUE); EXPECT_EQ(setIteratorValue2->IsJSSetIterator(), true); JSHandle setIterator2(setIteratorValue2); EXPECT_EQ(JSTaggedValue::SameValue(setIterator2->GetIteratedSet(), jsSet->GetLinkedSet()), true); EXPECT_EQ(setIterator2->GetNextIndex(), 0U); EXPECT_EQ(setIterator2->GetIterationKind(), IterationKind::VALUE); } /** * @tc.name: Update * @tc.desc: Call "NewJSSetIterator" function create SetIterator with emty IteratedSet,create other JSSet and add key * to it,the old JSSet call "Rehash" function set new JSSet to the next table, then SetIterator call "Update" * function upadate IteratedSet,check whether the IteratedSet is within expectations. * @tc.type: FUNC * @tc.require: */ HWTEST_F_L0(JSSetIteratorTest, Update) { ObjectFactory *factory = thread->GetEcmaVM()->GetFactory(); JSHandle jsSet1(thread, CreateJSSet(thread)); JSHandle jsSet2(thread, CreateJSSet(thread)); JSHandle keyHandle1(factory->NewFromASCII("key1")); JSHandle keyHandle2(factory->NewFromASCII("key2")); JSHandle keyHandle3(factory->NewFromASCII("key3")); // add key to jsSet2 JSSet::Add(thread, jsSet2, keyHandle1); JSSet::Add(thread, jsSet2, keyHandle2); JSSet::Add(thread, jsSet2, keyHandle3); JSHandle setHandle1(thread, LinkedHashSet::Cast(jsSet1->GetLinkedSet().GetTaggedObject())); JSHandle setHandle2(thread, LinkedHashSet::Cast(jsSet2->GetLinkedSet().GetTaggedObject())); setHandle1->Rehash(thread, *setHandle2); // create SetIterator with jsSet1 JSHandle setIterator = factory->NewJSSetIterator(jsSet1, IterationKind::KEY); // update SetIterator setIterator->Update(thread); LinkedHashSet *resultSet = LinkedHashSet::Cast(setIterator->GetIteratedSet().GetTaggedObject()); EXPECT_TRUE(resultSet->Has(thread, keyHandle1.GetTaggedValue())); EXPECT_TRUE(resultSet->Has(thread, keyHandle2.GetTaggedValue())); EXPECT_TRUE(resultSet->Has(thread, keyHandle3.GetTaggedValue())); } /** * @tc.name: Next * @tc.desc: get the next value in setiterator,Check whether the return value obtained by the function is * the next value in the array element. * @tc.type: FUNC * @tc.require: */ HWTEST_F_L0(JSSetIteratorTest, KEY_Next) { JSHandle jsSet(thread, CreateJSSet(thread)); EXPECT_TRUE(*jsSet != nullptr); for (int i = 0; i < 3; i++) { // 3 : 3 default numberOfElements JSHandle key(thread, JSTaggedValue(i)); JSSet::Add(thread, jsSet, key); } // set IterationKind(key or value) JSHandle setIteratorValue = JSSetIterator::CreateSetIterator(thread, JSHandle(jsSet), IterationKind::KEY); JSHandle setIterator(setIteratorValue); auto ecmaRuntimeCallInfo = TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), 6); ecmaRuntimeCallInfo->SetFunction(JSTaggedValue::Undefined()); ecmaRuntimeCallInfo->SetThis(setIteratorValue.GetTaggedValue()); ecmaRuntimeCallInfo->SetCallArg(0, JSTaggedValue::Undefined()); [[maybe_unused]] auto prev = TestHelper::SetupFrame(thread, ecmaRuntimeCallInfo); for (int i = 0; i <= 3; i++) { // 3 : 3 default numberOfElements JSTaggedValue result = JSSetIterator::Next(ecmaRuntimeCallInfo); JSHandle resultObj(thread, result); if (i < 3) { EXPECT_EQ(setIterator->GetNextIndex(), static_cast(i + 1)); EXPECT_EQ(i, JSIterator::IteratorValue(thread, resultObj)->GetInt()); } else { EXPECT_EQ(JSIterator::IteratorValue(thread, resultObj).GetTaggedValue(), JSTaggedValue::Undefined()); } } TestHelper::TearDownFrame(thread, prev); } HWTEST_F_L0(JSSetIteratorTest, KEY_AND_VALUE_Next) { JSHandle jsSet(thread, CreateJSSet(thread)); EXPECT_TRUE(*jsSet != nullptr); JSHandle index0(thread, JSTaggedValue(0)); JSHandle index1(thread, JSTaggedValue(1)); for (int i = 0; i < 3; i++) { // default numberOfElements JSHandle key(thread, JSTaggedValue(i)); JSSet::Add(thread, jsSet, key); } // set IterationKind(key and value) JSHandle setIteratorValue = JSSetIterator::CreateSetIterator(thread, JSHandle(jsSet), IterationKind::KEY_AND_VALUE); JSHandle setIterator(setIteratorValue); auto ecmaRuntimeCallInfo = TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), 6); ecmaRuntimeCallInfo->SetFunction(JSTaggedValue::Undefined()); ecmaRuntimeCallInfo->SetThis(setIteratorValue.GetTaggedValue()); ecmaRuntimeCallInfo->SetCallArg(0, JSTaggedValue::Undefined()); [[maybe_unused]] auto prev = TestHelper::SetupFrame(thread, ecmaRuntimeCallInfo); for (int i = 0; i <= 3; i++) { // 3 : 3 default numberOfElements JSTaggedValue result = JSSetIterator::Next(ecmaRuntimeCallInfo); JSHandle resultObj(thread, result); if (i < 3) { JSHandle arrayList(thread, JSIterator::IteratorValue(thread, resultObj).GetTaggedValue()); EXPECT_EQ(setIterator->GetNextIndex(), static_cast(i+1)); EXPECT_EQ(JSArray::GetProperty(thread, JSHandle(arrayList), index0).GetValue()->GetInt(), i); EXPECT_EQ(JSArray::GetProperty(thread, JSHandle(arrayList), index1).GetValue()->GetInt(), i); } else { EXPECT_EQ(JSIterator::IteratorValue(thread, resultObj).GetTaggedValue(), JSTaggedValue::Undefined()); } } TestHelper::TearDownFrame(thread, prev); } } // namespace panda::test