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
23 using namespace panda;
24 using namespace panda::ecmascript;
25
26 namespace panda::test {
27 class JSSetIteratorTest : public BaseTestWithScope<false> {
28 };
29
CreateJSSet(JSThread * thread)30 static 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 */
HWTEST_F_L0(JSSetIteratorTest,CreateSetIterator)48 HWTEST_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(thread, setIterator1->GetIteratedSet(thread), jsSet->GetLinkedSet(thread)),
59 true);
60 EXPECT_EQ(setIterator1->GetNextIndex(), 0U);
61 EXPECT_EQ(setIterator1->GetIterationKind(), IterationKind::KEY);
62
63 JSHandle<JSTaggedValue> setIteratorValue2 =
64 JSSetIterator::CreateSetIterator(thread, JSHandle<JSTaggedValue>(jsSet), IterationKind::VALUE);
65
66 EXPECT_EQ(setIteratorValue2->IsJSSetIterator(), true);
67 JSHandle<JSSetIterator> setIterator2(setIteratorValue2);
68 EXPECT_EQ(JSTaggedValue::SameValue(thread, setIterator2->GetIteratedSet(thread), jsSet->GetLinkedSet(thread)),
69 true);
70 EXPECT_EQ(setIterator2->GetNextIndex(), 0U);
71 EXPECT_EQ(setIterator2->GetIterationKind(), IterationKind::VALUE);
72 }
73
74 /**
75 * @tc.name: Update
76 * @tc.desc: Call "NewJSSetIterator" function create SetIterator with emty IteratedSet,create other JSSet and add key
77 * to it,the old JSSet call "Rehash" function set new JSSet to the next table, then SetIterator call "Update"
78 * function upadate IteratedSet,check whether the IteratedSet is within expectations.
79 * @tc.type: FUNC
80 * @tc.require:
81 */
HWTEST_F_L0(JSSetIteratorTest,Update)82 HWTEST_F_L0(JSSetIteratorTest, Update)
83 {
84 ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
85 JSHandle<JSSet> jsSet1(thread, CreateJSSet(thread));
86 JSHandle<JSSet> jsSet2(thread, CreateJSSet(thread));
87
88 JSHandle<JSTaggedValue> keyHandle1(factory->NewFromASCII("key1"));
89 JSHandle<JSTaggedValue> keyHandle2(factory->NewFromASCII("key2"));
90 JSHandle<JSTaggedValue> keyHandle3(factory->NewFromASCII("key3"));
91 // add key to jsSet2
92 JSSet::Add(thread, jsSet2, keyHandle1);
93 JSSet::Add(thread, jsSet2, keyHandle2);
94 JSSet::Add(thread, jsSet2, keyHandle3);
95
96 JSHandle<LinkedHashSet> setHandle1(thread, LinkedHashSet::Cast(jsSet1->GetLinkedSet(thread).GetTaggedObject()));
97 JSHandle<LinkedHashSet> setHandle2(thread, LinkedHashSet::Cast(jsSet2->GetLinkedSet(thread).GetTaggedObject()));
98 setHandle1->Rehash(thread, *setHandle2);
99 // create SetIterator with jsSet1
100 JSHandle<JSSetIterator> setIterator = factory->NewJSSetIterator(jsSet1, IterationKind::KEY);
101 // update SetIterator
102 setIterator->Update(thread);
103 LinkedHashSet *resultSet = LinkedHashSet::Cast(setIterator->GetIteratedSet(thread).GetTaggedObject());
104 EXPECT_TRUE(resultSet->Has(thread, keyHandle1.GetTaggedValue()));
105 EXPECT_TRUE(resultSet->Has(thread, keyHandle2.GetTaggedValue()));
106 EXPECT_TRUE(resultSet->Has(thread, keyHandle3.GetTaggedValue()));
107 }
108
NextCommon(JSThread * thread,JSHandle<JSSetIterator> & setIterator,IterationKind kind=IterationKind::KEY)109 EcmaRuntimeCallInfo* NextCommon(JSThread *thread, JSHandle<JSSetIterator>& setIterator,
110 IterationKind kind = IterationKind::KEY)
111 {
112 JSHandle<JSSet> jsSet(thread, CreateJSSet(thread));
113 EXPECT_TRUE(*jsSet != nullptr);
114
115 for (int i = 0; i < 3; i++) { // 3 : 3 default numberOfElements
116 JSHandle<JSTaggedValue> key(thread, JSTaggedValue(i));
117 JSSet::Add(thread, jsSet, key);
118 }
119 // set IterationKind(key or value)
120 JSHandle<JSTaggedValue> setIteratorValue =
121 JSSetIterator::CreateSetIterator(thread, JSHandle<JSTaggedValue>(jsSet), kind);
122 setIterator = JSHandle<JSSetIterator>(setIteratorValue);
123 std::vector<JSTaggedValue> args{JSTaggedValue::Undefined()};
124 auto ecmaRuntimeCallInfo =
125 TestHelper::CreateEcmaRuntimeCallInfo(thread, args, 6, setIteratorValue.GetTaggedValue());
126 return ecmaRuntimeCallInfo;
127 }
128 /**
129 * @tc.name: Next
130 * @tc.desc: get the next value in setiterator,Check whether the return value obtained by the function is
131 * the next value in the array element.
132 * @tc.type: FUNC
133 * @tc.require:
134 */
HWTEST_F_L0(JSSetIteratorTest,KEY_Next)135 HWTEST_F_L0(JSSetIteratorTest, KEY_Next)
136 {
137 JSHandle<JSSetIterator> setIterator;
138 auto ecmaRuntimeCallInfo = NextCommon(thread, setIterator);
139 [[maybe_unused]] auto prev = TestHelper::SetupFrame(thread, ecmaRuntimeCallInfo);
140
141 for (int i = 0; i <= 3; i++) { // 3 : 3 default numberOfElements
142 JSTaggedValue result = JSSetIterator::Next(ecmaRuntimeCallInfo);
143 JSHandle<JSTaggedValue> resultObj(thread, result);
144 if (i < 3) {
145 EXPECT_EQ(setIterator->GetNextIndex(), static_cast<uint32_t>(i + 1));
146 EXPECT_EQ(i, JSIterator::IteratorValue(thread, resultObj)->GetInt());
147 }
148 else {
149 EXPECT_EQ(JSIterator::IteratorValue(thread, resultObj).GetTaggedValue(), JSTaggedValue::Undefined());
150 }
151 }
152 TestHelper::TearDownFrame(thread, prev);
153 }
154
HWTEST_F_L0(JSSetIteratorTest,KEY_AND_VALUE_Next)155 HWTEST_F_L0(JSSetIteratorTest, KEY_AND_VALUE_Next)
156 {
157 JSHandle<JSTaggedValue> index0(thread, JSTaggedValue(0));
158 JSHandle<JSTaggedValue> index1(thread, JSTaggedValue(1));
159 JSHandle<JSSetIterator> setIterator;
160 auto ecmaRuntimeCallInfo = NextCommon(thread, setIterator, IterationKind::KEY_AND_VALUE);
161 [[maybe_unused]] auto prev = TestHelper::SetupFrame(thread, ecmaRuntimeCallInfo);
162
163 for (int i = 0; i <= 3; i++) { // 3 : 3 default numberOfElements
164 JSTaggedValue result = JSSetIterator::Next(ecmaRuntimeCallInfo);
165 JSHandle<JSTaggedValue> resultObj(thread, result);
166 if (i < 3) {
167 JSHandle<JSArray> arrayList(thread, JSIterator::IteratorValue(thread, resultObj).GetTaggedValue());
168 EXPECT_EQ(setIterator->GetNextIndex(), static_cast<uint32_t>(i+1));
169 EXPECT_EQ(JSArray::GetProperty(thread, JSHandle<JSTaggedValue>(arrayList), index0).GetValue()->GetInt(), i);
170 EXPECT_EQ(JSArray::GetProperty(thread, JSHandle<JSTaggedValue>(arrayList), index1).GetValue()->GetInt(), i);
171 }
172 else {
173 EXPECT_EQ(JSIterator::IteratorValue(thread, resultObj).GetTaggedValue(), JSTaggedValue::Undefined());
174 }
175 }
176 TestHelper::TearDownFrame(thread, prev);
177 }
178 } // namespace panda::test
179