1/* 2 * Copyright (c) 2022 Huawei Device Co., Ltd. 3 * Licensed under the Apache License, Version 2.0 (the "License"); 4 * you may not use this file except in compliance with the License. 5 * You may obtain a copy of the License at 6 * 7 * http://www.apache.org/licenses/LICENSE-2.0 8 * 9 * Unless required by applicable law or agreed to in writing, software 10 * distributed under the License is distributed on an "AS IS" BASIS, 11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 * See the License for the specific language governing permissions and 13 * limitations under the License. 14 */ 15 16#include "ecmascript/js_set_iterator.h" 17#include "ecmascript/global_env.h" 18#include "ecmascript/js_array.h" 19#include "ecmascript/js_set.h" 20#include "ecmascript/linked_hash_table.h" 21#include "ecmascript/tests/ecma_test_common.h" 22 23using namespace panda; 24using namespace panda::ecmascript; 25 26namespace panda::test { 27class JSSetIteratorTest : public BaseTestWithScope<false> { 28}; 29 30static JSSet *CreateJSSet(JSThread *thread) 31{ 32 ObjectFactory *factory = thread->GetEcmaVM()->GetFactory(); 33 JSHandle<JSTaggedValue> constructor = thread->GetEcmaVM()->GetGlobalEnv()->GetBuiltinsSetFunction(); 34 JSHandle<JSSet> set = 35 JSHandle<JSSet>::Cast(factory->NewJSObjectByConstructor(JSHandle<JSFunction>(constructor), constructor)); 36 JSHandle<LinkedHashSet> hashSet = LinkedHashSet::Create(thread); 37 set->SetLinkedSet(thread, hashSet); 38 return JSSet::Cast(set.GetTaggedValue().GetTaggedObject()); 39} 40 41/** 42 * @tc.name: CreateSetIterator 43 * @tc.desc: Call "CreateSetIterator" function create SetIterator,Check whether the the attribute setting of SetIterator 44 * through "GetNextIndex" and "GetIterationKind" function is within expectations. 45 * @tc.type: FUNC 46 * @tc.require: 47 */ 48HWTEST_F_L0(JSSetIteratorTest, CreateSetIterator) 49{ 50 JSHandle<JSSet> jsSet(thread, CreateJSSet(thread)); 51 EXPECT_TRUE(*jsSet != nullptr); 52 53 JSHandle<JSTaggedValue> setIteratorValue1 = 54 JSSetIterator::CreateSetIterator(thread, JSHandle<JSTaggedValue>(jsSet), IterationKind::KEY); 55 56 EXPECT_EQ(setIteratorValue1->IsJSSetIterator(), true); 57 JSHandle<JSSetIterator> setIterator1(setIteratorValue1); 58 EXPECT_EQ(JSTaggedValue::SameValue(setIterator1->GetIteratedSet(), jsSet->GetLinkedSet()), true); 59 EXPECT_EQ(setIterator1->GetNextIndex(), 0U); 60 EXPECT_EQ(setIterator1->GetIterationKind(), IterationKind::KEY); 61 62 JSHandle<JSTaggedValue> setIteratorValue2 = 63 JSSetIterator::CreateSetIterator(thread, JSHandle<JSTaggedValue>(jsSet), IterationKind::VALUE); 64 65 EXPECT_EQ(setIteratorValue2->IsJSSetIterator(), true); 66 JSHandle<JSSetIterator> setIterator2(setIteratorValue2); 67 EXPECT_EQ(JSTaggedValue::SameValue(setIterator2->GetIteratedSet(), jsSet->GetLinkedSet()), true); 68 EXPECT_EQ(setIterator2->GetNextIndex(), 0U); 69 EXPECT_EQ(setIterator2->GetIterationKind(), IterationKind::VALUE); 70} 71 72/** 73 * @tc.name: Update 74 * @tc.desc: Call "NewJSSetIterator" function create SetIterator with emty IteratedSet,create other JSSet and add key 75 * to it,the old JSSet call "Rehash" function set new JSSet to the next table, then SetIterator call "Update" 76 * function upadate IteratedSet,check whether the IteratedSet is within expectations. 77 * @tc.type: FUNC 78 * @tc.require: 79 */ 80HWTEST_F_L0(JSSetIteratorTest, Update) 81{ 82 ObjectFactory *factory = thread->GetEcmaVM()->GetFactory(); 83 JSHandle<JSSet> jsSet1(thread, CreateJSSet(thread)); 84 JSHandle<JSSet> jsSet2(thread, CreateJSSet(thread)); 85 86 JSHandle<JSTaggedValue> keyHandle1(factory->NewFromASCII("key1")); 87 JSHandle<JSTaggedValue> keyHandle2(factory->NewFromASCII("key2")); 88 JSHandle<JSTaggedValue> keyHandle3(factory->NewFromASCII("key3")); 89 // add key to jsSet2 90 JSSet::Add(thread, jsSet2, keyHandle1); 91 JSSet::Add(thread, jsSet2, keyHandle2); 92 JSSet::Add(thread, jsSet2, keyHandle3); 93 94 JSHandle<LinkedHashSet> setHandle1(thread, LinkedHashSet::Cast(jsSet1->GetLinkedSet().GetTaggedObject())); 95 JSHandle<LinkedHashSet> setHandle2(thread, LinkedHashSet::Cast(jsSet2->GetLinkedSet().GetTaggedObject())); 96 setHandle1->Rehash(thread, *setHandle2); 97 // create SetIterator with jsSet1 98 JSHandle<JSSetIterator> setIterator = factory->NewJSSetIterator(jsSet1, IterationKind::KEY); 99 // update SetIterator 100 setIterator->Update(thread); 101 LinkedHashSet *resultSet = LinkedHashSet::Cast(setIterator->GetIteratedSet().GetTaggedObject()); 102 EXPECT_TRUE(resultSet->Has(thread, keyHandle1.GetTaggedValue())); 103 EXPECT_TRUE(resultSet->Has(thread, keyHandle2.GetTaggedValue())); 104 EXPECT_TRUE(resultSet->Has(thread, keyHandle3.GetTaggedValue())); 105} 106 107EcmaRuntimeCallInfo* NextCommon(JSThread *thread, JSHandle<JSSetIterator>& setIterator, 108 IterationKind kind = IterationKind::KEY) 109{ 110 JSHandle<JSSet> jsSet(thread, CreateJSSet(thread)); 111 EXPECT_TRUE(*jsSet != nullptr); 112 113 for (int i = 0; i < 3; i++) { // 3 : 3 default numberOfElements 114 JSHandle<JSTaggedValue> key(thread, JSTaggedValue(i)); 115 JSSet::Add(thread, jsSet, key); 116 } 117 // set IterationKind(key or value) 118 JSHandle<JSTaggedValue> setIteratorValue = 119 JSSetIterator::CreateSetIterator(thread, JSHandle<JSTaggedValue>(jsSet), kind); 120 setIterator = JSHandle<JSSetIterator>(setIteratorValue); 121 std::vector<JSTaggedValue> args{JSTaggedValue::Undefined()}; 122 auto ecmaRuntimeCallInfo = 123 TestHelper::CreateEcmaRuntimeCallInfo(thread, args, 6, setIteratorValue.GetTaggedValue()); 124 return ecmaRuntimeCallInfo; 125} 126/** 127 * @tc.name: Next 128 * @tc.desc: get the next value in setiterator,Check whether the return value obtained by the function is 129 * the next value in the array element. 130 * @tc.type: FUNC 131 * @tc.require: 132 */ 133HWTEST_F_L0(JSSetIteratorTest, KEY_Next) 134{ 135 JSHandle<JSSetIterator> setIterator; 136 auto ecmaRuntimeCallInfo = NextCommon(thread, setIterator); 137 [[maybe_unused]] auto prev = TestHelper::SetupFrame(thread, ecmaRuntimeCallInfo); 138 139 for (int i = 0; i <= 3; i++) { // 3 : 3 default numberOfElements 140 JSTaggedValue result = JSSetIterator::Next(ecmaRuntimeCallInfo); 141 JSHandle<JSTaggedValue> resultObj(thread, result); 142 if (i < 3) { 143 EXPECT_EQ(setIterator->GetNextIndex(), static_cast<uint32_t>(i + 1)); 144 EXPECT_EQ(i, JSIterator::IteratorValue(thread, resultObj)->GetInt()); 145 } 146 else { 147 EXPECT_EQ(JSIterator::IteratorValue(thread, resultObj).GetTaggedValue(), JSTaggedValue::Undefined()); 148 } 149 } 150 TestHelper::TearDownFrame(thread, prev); 151} 152 153HWTEST_F_L0(JSSetIteratorTest, KEY_AND_VALUE_Next) 154{ 155 JSHandle<JSTaggedValue> index0(thread, JSTaggedValue(0)); 156 JSHandle<JSTaggedValue> index1(thread, JSTaggedValue(1)); 157 JSHandle<JSSetIterator> setIterator; 158 auto ecmaRuntimeCallInfo = NextCommon(thread, setIterator, IterationKind::KEY_AND_VALUE); 159 [[maybe_unused]] auto prev = TestHelper::SetupFrame(thread, ecmaRuntimeCallInfo); 160 161 for (int i = 0; i <= 3; i++) { // 3 : 3 default numberOfElements 162 JSTaggedValue result = JSSetIterator::Next(ecmaRuntimeCallInfo); 163 JSHandle<JSTaggedValue> resultObj(thread, result); 164 if (i < 3) { 165 JSHandle<JSArray> arrayList(thread, JSIterator::IteratorValue(thread, resultObj).GetTaggedValue()); 166 EXPECT_EQ(setIterator->GetNextIndex(), static_cast<uint32_t>(i+1)); 167 EXPECT_EQ(JSArray::GetProperty(thread, JSHandle<JSTaggedValue>(arrayList), index0).GetValue()->GetInt(), i); 168 EXPECT_EQ(JSArray::GetProperty(thread, JSHandle<JSTaggedValue>(arrayList), index1).GetValue()->GetInt(), i); 169 } 170 else { 171 EXPECT_EQ(JSIterator::IteratorValue(thread, resultObj).GetTaggedValue(), JSTaggedValue::Undefined()); 172 } 173 } 174 TestHelper::TearDownFrame(thread, prev); 175} 176} // namespace panda::test 177