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_map_iterator.h"
17 #include "ecmascript/global_env.h"
18 #include "ecmascript/linked_hash_table.h"
19 #include "ecmascript/js_map.h"
20 #include "ecmascript/tests/test_helper.h"
21
22 using namespace panda;
23 using namespace panda::ecmascript;
24
25 namespace panda::test {
26 class JSMapIteratorTest : public testing::Test {
27 public:
SetUpTestCase()28 static void SetUpTestCase()
29 {
30 GTEST_LOG_(INFO) << "SetUpTestCase";
31 }
32
TearDownTestCase()33 static void TearDownTestCase()
34 {
35 GTEST_LOG_(INFO) << "TearDownCase";
36 }
37
SetUp()38 void SetUp() override
39 {
40 TestHelper::CreateEcmaVMWithScope(instance, thread, scope);
41 }
42
TearDown()43 void TearDown() override
44 {
45 TestHelper::DestroyEcmaVMWithScope(instance, scope);
46 }
47
48 EcmaVM *instance {nullptr};
49 EcmaHandleScope *scope {nullptr};
50 JSThread *thread {nullptr};
51 };
52
CreateJSMap(JSThread * thread)53 JSHandle<JSMap> CreateJSMap(JSThread *thread)
54 {
55 JSHandle<GlobalEnv> globaEnv = thread->GetEcmaVM()->GetGlobalEnv();
56 ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
57
58 JSHandle<JSTaggedValue> builtinsMapFunc = globaEnv->GetBuiltinsMapFunction();
59 JSHandle<JSMap> jsMap(factory->NewJSObjectByConstructor(JSHandle<JSFunction>(builtinsMapFunc), builtinsMapFunc));
60 JSHandle<JSTaggedValue> linkedHashMap(LinkedHashMap::Create(thread));
61 jsMap->SetLinkedMap(thread, linkedHashMap);
62 return jsMap;
63 }
64
65 /**
66 * @tc.name: CreateSetIterator
67 * @tc.desc: Call "CreateSetIterator" function create SetIterator,Check whether the the SetIterator is JSMapIterator
68 * through "IsJSMapIterator" function is within expectations.
69 * @tc.type: FUNC
70 * @tc.require:
71 */
HWTEST_F_L0(JSMapIteratorTest,CreateMapIterator)72 HWTEST_F_L0(JSMapIteratorTest, CreateMapIterator)
73 {
74 JSHandle<JSMap> jsMap = CreateJSMap(thread);
75
76 IterationKind iterKind = IterationKind::KEY;
77 JSHandle<JSTaggedValue> mapIteratorKey =
78 JSMapIterator::CreateMapIterator(thread, JSHandle<JSTaggedValue>::Cast(jsMap), iterKind);
79 EXPECT_TRUE(mapIteratorKey->IsJSMapIterator());
80
81 iterKind = IterationKind::VALUE;
82 JSHandle<JSTaggedValue> mapIteratorValue =
83 JSMapIterator::CreateMapIterator(thread, JSHandle<JSTaggedValue>::Cast(jsMap), iterKind);
84 EXPECT_TRUE(mapIteratorValue->IsJSMapIterator());
85
86 iterKind = IterationKind::KEY_AND_VALUE;
87 JSHandle<JSTaggedValue> mapIteratorKeyAndValue =
88 JSMapIterator::CreateMapIterator(thread, JSHandle<JSTaggedValue>::Cast(jsMap), iterKind);
89 EXPECT_TRUE(mapIteratorKeyAndValue->IsJSMapIterator());
90 }
91
92 /**
93 * @tc.name: SetIteratedMap
94 * @tc.desc: Create a JSMapIterator through calling "CreateMapIterator" function with the current thread. Check whether
95 * the returned value through calling "GetIteratedMap" function from the JSMapIterator is the same with the
96 * returned value through calling "GetLinkedMap" function. Call "SetIteratedMap" function change LinkedMap,
97 * Check whether the returned JSTaggedValue through calling "GetNextIndex" function from the JSMapIterator is
98 * the same with the changed value.
99 * source JSMap.
100 * @tc.type: FUNC
101 * @tc.require:
102 */
HWTEST_F_L0(JSMapIteratorTest,SetIteratedMap)103 HWTEST_F_L0(JSMapIteratorTest, SetIteratedMap)
104 {
105 IterationKind iterKind = IterationKind::KEY;
106 JSHandle<JSMap> jsMap1 = CreateJSMap(thread);
107 JSHandle<JSMap> jsMap2 = CreateJSMap(thread);
108 JSHandle<JSTaggedValue> mapIteratorVal =
109 JSMapIterator::CreateMapIterator(thread, JSHandle<JSTaggedValue>::Cast(jsMap1), iterKind);
110 JSHandle<JSMapIterator> jsMapIterator = JSHandle<JSMapIterator>::Cast(mapIteratorVal);
111
112 EXPECT_EQ(jsMap1->GetLinkedMap(), jsMapIterator->GetIteratedMap());
113 jsMapIterator->SetIteratedMap(thread, JSHandle<JSTaggedValue>(thread, jsMap2->GetLinkedMap()));
114 EXPECT_NE(jsMap1->GetLinkedMap(), jsMapIterator->GetIteratedMap());
115 EXPECT_EQ(jsMap2->GetLinkedMap(), jsMapIterator->GetIteratedMap());
116 }
117
118 /**
119 * @tc.name: SetNextIndex
120 * @tc.desc: Create a JSMapIterator through calling "CreateMapIterator" function with the current thread, Check
121 * whether the returned value through calling "GetNextIndex" function from the JSMapIterator is the same
122 * as JSTaggedValue(0) Call "SetNextIndex" to change NextIndex, Check whether the returned value through
123 * calling "GetNextIndex" function from the JSMapIterator is the same with the changed value.
124 * @tc.type: FUNC
125 * @tc.require:
126 */
HWTEST_F_L0(JSMapIteratorTest,SetNextIndex)127 HWTEST_F_L0(JSMapIteratorTest, SetNextIndex)
128 {
129 JSHandle<JSMap> jsMap = CreateJSMap(thread);
130 JSHandle<JSTaggedValue> mapValue(jsMap);
131 JSHandle<JSTaggedValue> mapIteratorVal =
132 JSMapIterator::CreateMapIterator(thread, mapValue, IterationKind::KEY);
133 JSHandle<JSMapIterator> mapIterator = JSHandle<JSMapIterator>::Cast(mapIteratorVal);
134
135 EXPECT_EQ(mapIterator->GetNextIndex(), 0U);
136 mapIterator->SetNextIndex(1);
137 EXPECT_EQ(mapIterator->GetNextIndex(), 1U);
138 }
139
140 /**
141 * @tc.name: SetIterationKind
142 * @tc.desc: Create a JSMapIterator through calling CreateMapIterator function with the current thread. Check whether
143 * the returned value through calling "GetIterationKind" function is the same with JSTaggedValue(0). Check
144 * whether the returned value through calling "GetIterationKind" function is within expectations after calling
145 * "SetIterationKind" with the current thread.
146 * @tc.type: FUNC
147 * @tc.require:
148 */
HWTEST_F_L0(JSMapIteratorTest,SetIterationKind)149 HWTEST_F_L0(JSMapIteratorTest, SetIterationKind)
150 {
151 JSHandle<JSMap> jsMap = CreateJSMap(thread);
152 JSHandle<JSTaggedValue> mapValue(jsMap);
153 JSHandle<JSTaggedValue> mapIteratorVal =
154 JSMapIterator::CreateMapIterator(thread, mapValue, IterationKind::KEY);
155 JSHandle<JSMapIterator> mapIterator = JSHandle<JSMapIterator>::Cast(mapIteratorVal);
156 EXPECT_EQ(mapIterator->GetIterationKind(), IterationKind::KEY);
157 mapIterator->SetIterationKind(IterationKind::VALUE);
158 EXPECT_EQ(mapIterator->GetIterationKind(), IterationKind::VALUE);
159 mapIterator->SetIterationKind(IterationKind::KEY_AND_VALUE);
160 EXPECT_EQ(mapIterator->GetIterationKind(), IterationKind::KEY_AND_VALUE);
161 }
162
163 /**
164 * @tc.name: Update
165 * @tc.desc: Call "NewJSMapIterator" function create MapIterator with emty IteratedMap, create other JSMap and add key
166 * to it,the old JSMap call "Rehash" function set new JSMap to the next table, then SetIterator call "Update"
167 * function upadate IteratedMap, check whether the IteratedMap is within expectations.
168 * @tc.type: FUNC
169 * @tc.require:
170 */
HWTEST_F_L0(JSMapIteratorTest,Update)171 HWTEST_F_L0(JSMapIteratorTest, Update)
172 {
173 ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
174 JSHandle<JSMap> jsMap1(thread, CreateJSMap(thread).GetTaggedValue());
175 JSHandle<JSMap> jsMap2(thread, CreateJSMap(thread).GetTaggedValue());
176
177 JSHandle<JSTaggedValue> keyHandle1(thread, JSTaggedValue(0));
178 JSHandle<JSTaggedValue> keyHandle2(thread, JSTaggedValue(1));
179 JSHandle<JSTaggedValue> keyHandle3(thread, JSTaggedValue(2)); // 2: means key and value
180 // add key and value to jsMap1
181 JSMap::Set(thread, jsMap1, keyHandle1, keyHandle1);
182 JSMap::Set(thread, jsMap1, keyHandle2, keyHandle2);
183 JSMap::Set(thread, jsMap1, keyHandle3, keyHandle3);
184
185 JSHandle<LinkedHashMap> mapHandle1(thread, LinkedHashMap::Cast(jsMap1->GetLinkedMap().GetTaggedObject()));
186 JSHandle<LinkedHashMap> mapHandle2(thread, LinkedHashMap::Cast(jsMap2->GetLinkedMap().GetTaggedObject()));
187 mapHandle1->Rehash(thread, *mapHandle2);
188 // create SetIterator with jsMap1
189 JSHandle<JSMapIterator> mapIterator = factory->NewJSMapIterator(jsMap1, IterationKind::KEY);
190 // update MapIterator
191 mapIterator->Update(thread);
192 LinkedHashMap *resultMap = LinkedHashMap::Cast(mapIterator->GetIteratedMap().GetTaggedObject());
193 EXPECT_TRUE(resultMap->Has(keyHandle1.GetTaggedValue()));
194 EXPECT_TRUE(resultMap->Has(keyHandle2.GetTaggedValue()));
195 EXPECT_TRUE(resultMap->Has(keyHandle3.GetTaggedValue()));
196 }
197
198 /**
199 * @tc.name: Next
200 * @tc.desc: Calling "Next" function get the next value from the MapIterator,Check whether the return value obtained
201 * by the function is the next value in the array element.
202 * @tc.type: FUNC
203 * @tc.require:
204 */
HWTEST_F_L0(JSMapIteratorTest,KEY_VALUE_Next)205 HWTEST_F_L0(JSMapIteratorTest, KEY_VALUE_Next)
206 {
207 JSHandle<JSMap> jsMap = CreateJSMap(thread);
208 int32_t iteratorLength = 5;
209 for (int32_t i = 0; i < iteratorLength; i++) {
210 JSMap::Set(thread, jsMap, JSHandle<JSTaggedValue>(thread, JSTaggedValue(i)),
211 JSHandle<JSTaggedValue>(thread, JSTaggedValue(i + 5))); // 5: means expected value
212 }
213 JSHandle<JSTaggedValue> mapValue(jsMap);
214 JSHandle<JSMapIterator> mapIterator(JSMapIterator::CreateMapIterator(thread, mapValue, IterationKind::KEY));
215 // 4: argv length
216 auto ecmaRuntimeCallInfo1 = TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), 4);
217 ecmaRuntimeCallInfo1->SetThis(mapIterator.GetTaggedValue());
218 ecmaRuntimeCallInfo1->SetFunction(JSTaggedValue::Undefined());
219 [[maybe_unused]] auto prev = TestHelper::SetupFrame(thread, ecmaRuntimeCallInfo1);
220 for (int32_t i = 0; i < 5; i++) {
221 JSHandle<JSTaggedValue> nextTagValResult(thread, JSMapIterator::Next(ecmaRuntimeCallInfo1));
222 EXPECT_EQ(JSIterator::IteratorValue(thread, nextTagValResult)->GetInt(), i);
223 }
224 TestHelper::TearDownFrame(thread, prev);
225 // change Iterationkind to VALUE
226 mapIterator->SetIterationKind(IterationKind::VALUE);
227 mapIterator->SetNextIndex(0);
228 // 4: argv length
229 auto ecmaRuntimeCallInfo2 = TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), 4);
230 ecmaRuntimeCallInfo2->SetThis(mapIterator.GetTaggedValue());
231 ecmaRuntimeCallInfo2->SetFunction(JSTaggedValue::Undefined());
232 prev = TestHelper::SetupFrame(thread, ecmaRuntimeCallInfo2);
233 for (int32_t i = 0; i < iteratorLength; i++) {
234 JSHandle<JSTaggedValue> nextTagValResult(thread, JSMapIterator::Next(ecmaRuntimeCallInfo2));
235 EXPECT_EQ(JSIterator::IteratorValue(thread, nextTagValResult)->GetInt(), i + 5); // 5: means expected value
236 }
237 TestHelper::TearDownFrame(thread, prev);
238 }
239
HWTEST_F_L0(JSMapIteratorTest,KEY_AND_VALUE_Next)240 HWTEST_F_L0(JSMapIteratorTest, KEY_AND_VALUE_Next)
241 {
242 JSHandle<JSMap> jsMap = CreateJSMap(thread);
243 int32_t iteratorLength = 5;
244 for (int32_t i = 0; i < iteratorLength; i++) {
245 JSMap::Set(thread, jsMap, JSHandle<JSTaggedValue>(thread, JSTaggedValue(i)),
246 JSHandle<JSTaggedValue>(thread, JSTaggedValue(i + 10))); // 10: means expected value
247 }
248 JSHandle<JSTaggedValue> mapValue(jsMap);
249 JSHandle<JSMapIterator> mapIterator(
250 JSMapIterator::CreateMapIterator(thread, mapValue, IterationKind::KEY_AND_VALUE));
251 // 4: argv length
252 auto ecmaRuntimeCallInfo = TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), 4);
253 ecmaRuntimeCallInfo->SetThis(mapIterator.GetTaggedValue());
254 ecmaRuntimeCallInfo->SetFunction(JSTaggedValue::Undefined());
255 [[maybe_unused]] auto prev = TestHelper::SetupFrame(thread, ecmaRuntimeCallInfo);
256 for (int32_t i = 0; i < iteratorLength; i++) {
257 JSHandle<JSTaggedValue> nextTagValResult(thread, JSMapIterator::Next(ecmaRuntimeCallInfo));
258 JSHandle<JSArray> iteratorVal(thread, JSIterator::IteratorValue(thread, nextTagValResult).GetTaggedValue());
259 JSHandle<TaggedArray> elementsIterVal(thread, iteratorVal->GetElements());
260 EXPECT_EQ(i, elementsIterVal->Get(thread, 0).GetInt());
261 EXPECT_EQ(i + 10, elementsIterVal->Get(thread, 1).GetInt()); // 10: means expected value
262 }
263 TestHelper::TearDownFrame(thread, prev);
264 }
265 } // namespace panda::test
266