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_api/js_api_tree_map_iterator.h"
17 #include "ecmascript/containers/containers_private.h"
18 #include "ecmascript/global_env.h"
19 #include "ecmascript/js_api/js_api_tree_map.h"
20 #include "ecmascript/js_iterator.h"
21 #include "ecmascript/tagged_tree.h"
22 #include "ecmascript/tests/test_helper.h"
23
24 using namespace panda;
25 using namespace panda::ecmascript;
26
27 namespace panda::test {
28 class JSAPITreeMapIteratorTest : public testing::Test {
29 public:
SetUpTestCase()30 static void SetUpTestCase()
31 {
32 GTEST_LOG_(INFO) << "SetUpTestCase";
33 }
34
TearDownTestCase()35 static void TearDownTestCase()
36 {
37 GTEST_LOG_(INFO) << "TearDownCase";
38 }
39
SetUp()40 void SetUp() override
41 {
42 TestHelper::CreateEcmaVMWithScope(instance, thread, scope);
43 }
44
TearDown()45 void TearDown() override
46 {
47 TestHelper::DestroyEcmaVMWithScope(instance, scope);
48 }
49
50 EcmaVM *instance {nullptr};
51 ecmascript::EcmaHandleScope *scope {nullptr};
52 JSThread *thread {nullptr};
53
54 protected:
CreateTreeMap()55 JSHandle<JSAPITreeMap> CreateTreeMap()
56 {
57 ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
58 JSHandle<GlobalEnv> env = thread->GetEcmaVM()->GetGlobalEnv();
59
60 JSHandle<JSTaggedValue> globalObject = env->GetJSGlobalObject();
61 JSHandle<JSTaggedValue> key(factory->NewFromASCII("ArkPrivate"));
62 JSHandle<JSTaggedValue> value =
63 JSObject::GetProperty(thread, JSHandle<JSTaggedValue>(globalObject), key).GetValue();
64
65 auto ecmaRuntimeCallInfo = TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), 6);
66 ecmaRuntimeCallInfo->SetFunction(JSTaggedValue::Undefined());
67 ecmaRuntimeCallInfo->SetThis(value.GetTaggedValue());
68 ecmaRuntimeCallInfo->SetCallArg(0, JSTaggedValue(static_cast<int>(containers::ContainerTag::TreeMap)));
69
70 [[maybe_unused]] auto prev = TestHelper::SetupFrame(thread, ecmaRuntimeCallInfo);
71 JSTaggedValue result = containers::ContainersPrivate::Load(ecmaRuntimeCallInfo);
72 TestHelper::TearDownFrame(thread, prev);
73
74 JSHandle<JSTaggedValue> constructor(thread, result);
75 JSHandle<JSAPITreeMap> jsTreeMap(
76 factory->NewJSObjectByConstructor(JSHandle<JSFunction>(constructor), constructor));
77 JSTaggedValue internal = TaggedTreeMap::Create(thread);
78 jsTreeMap->SetTreeMap(thread, internal);
79 return jsTreeMap;
80 }
81 };
82
83 /**
84 * @tc.name: SetIterationKind
85 * @tc.desc: Call the "SetIterationKind" function, check whether the result returned through "GetIterationKind"
86 * function from the JSAPITreeMapIterator is within expectations.
87 * @tc.type: FUNC
88 * @tc.require:
89 */
HWTEST_F_L0(JSAPITreeMapIteratorTest,SetIterationKind)90 HWTEST_F_L0(JSAPITreeMapIteratorTest, SetIterationKind)
91 {
92 ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
93 JSHandle<JSAPITreeMap> jsTreeMap = CreateTreeMap();
94 EXPECT_TRUE(*jsTreeMap != nullptr);
95 JSHandle<JSAPITreeMapIterator> treeMapIterator =
96 factory->NewJSAPITreeMapIterator(jsTreeMap, IterationKind::KEY);
97 EXPECT_EQ(treeMapIterator->GetIterationKind(), IterationKind::KEY);
98 treeMapIterator->SetIterationKind(IterationKind::VALUE);
99 EXPECT_EQ(treeMapIterator->GetIterationKind(), IterationKind::VALUE);
100 treeMapIterator->SetIterationKind(IterationKind::KEY_AND_VALUE);
101 EXPECT_EQ(treeMapIterator->GetIterationKind(), IterationKind::KEY_AND_VALUE);
102 }
103
104 /**
105 * @tc.name: SetIteratedMap
106 * @tc.desc: Call the "SetIteratedMap" function, check whether the result returned through "GetIteratedMap"
107 * function from the JSAPITreeMapIterator is within expectations.
108 * @tc.type: FUNC
109 * @tc.require:
110 */
HWTEST_F_L0(JSAPITreeMapIteratorTest,SetIteratedMap)111 HWTEST_F_L0(JSAPITreeMapIteratorTest, SetIteratedMap)
112 {
113 constexpr uint32_t DEFAULT_LENGTH = 8;
114 ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
115 JSMutableHandle<JSTaggedValue> key(thread, JSTaggedValue::Undefined());
116 JSMutableHandle<JSTaggedValue> value(thread, JSTaggedValue::Undefined());
117 JSHandle<JSAPITreeMap> jsTreeMap = CreateTreeMap();
118 EXPECT_TRUE(*jsTreeMap != nullptr);
119 JSHandle<JSAPITreeMapIterator> treeMapIterator =
120 factory->NewJSAPITreeMapIterator(jsTreeMap, IterationKind::VALUE);
121
122 std::string mapKey("mapkey");
123 std::string mapValue("mapvalue");
124 for (uint32_t i = 0; i < DEFAULT_LENGTH; i++) {
125 std::string ikey = mapKey + std::to_string(i);
126 std::string ivalue = mapValue + std::to_string(i + 2U);
127 key.Update(factory->NewFromStdString(ikey).GetTaggedValue());
128 value.Update(factory->NewFromStdString(ivalue).GetTaggedValue());
129 JSAPITreeMap::Set(thread, jsTreeMap, key, value);
130 }
131 treeMapIterator->SetIteratedMap(thread, jsTreeMap.GetTaggedValue());
132 JSHandle<JSAPITreeMap> treeMapTo(thread, JSAPITreeMap::Cast(treeMapIterator->GetIteratedMap().GetTaggedObject()));
133 EXPECT_EQ(treeMapTo->GetSize(), static_cast<int>(DEFAULT_LENGTH));
134 for (uint32_t i = 0; i < DEFAULT_LENGTH; i++) {
135 std::string ikey = mapKey + std::to_string(i);
136 std::string ivalue = mapValue + std::to_string(i + 2U);
137 key.Update(factory->NewFromStdString(ikey).GetTaggedValue());
138 value.Update(factory->NewFromStdString(ivalue).GetTaggedValue());
139 JSTaggedValue result = JSAPITreeMap::Get(thread, treeMapTo, key);
140 EXPECT_EQ(result, value.GetTaggedValue());
141 }
142 }
143
144 /**
145 * @tc.name: SetNextIndex
146 * @tc.desc: Call the "SetNextIndex" function, check whether the result returned through "GetNextIndex"
147 * function from the JSAPITreeMapIterator is within expectations.
148 * @tc.type: FUNC
149 * @tc.require:
150 */
HWTEST_F_L0(JSAPITreeMapIteratorTest,SetNextIndex)151 HWTEST_F_L0(JSAPITreeMapIteratorTest, SetNextIndex)
152 {
153 constexpr uint32_t DEFAULT_LENGTH = 8;
154 ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
155 JSHandle<JSAPITreeMap> jsTreeMap = CreateTreeMap();
156 EXPECT_TRUE(*jsTreeMap != nullptr);
157 JSHandle<JSAPITreeMapIterator> treeMapIterator =
158 factory->NewJSAPITreeMapIterator(jsTreeMap, IterationKind::KEY_AND_VALUE);
159 EXPECT_EQ(treeMapIterator->GetNextIndex(), 0U);
160
161 for (uint32_t i = 0; i < DEFAULT_LENGTH; i++) {
162 treeMapIterator->SetNextIndex(i);
163 EXPECT_EQ(treeMapIterator->GetNextIndex(), i);
164 }
165 }
166
167 /**
168 * @tc.name: CreateTreeMapIterator
169 * @tc.desc: Create TreeMap iterator, check whether the result returned through "IsJSAPITreeMapIterator"
170 * function from the JSAPITreeMapIterator is within expectations.
171 * @tc.type: FUNC
172 * @tc.require:
173 */
HWTEST_F_L0(JSAPITreeMapIteratorTest,CreateTreeMapIterator)174 HWTEST_F_L0(JSAPITreeMapIteratorTest, CreateTreeMapIterator)
175 {
176 JSHandle<JSAPITreeMap> jsTreeMap = CreateTreeMap();
177 EXPECT_TRUE(*jsTreeMap != nullptr);
178 JSHandle<JSTaggedValue> treeMapVal(jsTreeMap);
179 // Create Iterator with KEY
180 JSHandle<JSTaggedValue> treeMapIterator =
181 JSAPITreeMapIterator::CreateTreeMapIterator(thread, treeMapVal, IterationKind::KEY);
182 EXPECT_TRUE(*treeMapIterator != nullptr);
183 EXPECT_TRUE(treeMapIterator->IsJSAPITreeMapIterator());
184 // Create Iterator with VALUE
185 treeMapIterator = JSAPITreeMapIterator::CreateTreeMapIterator(thread, treeMapVal, IterationKind::VALUE);
186 EXPECT_TRUE(*treeMapIterator != nullptr);
187 EXPECT_TRUE(treeMapIterator->IsJSAPITreeMapIterator());
188 // Create Iterator with KEY_AND_VALUE
189 treeMapIterator = JSAPITreeMapIterator::CreateTreeMapIterator(thread, treeMapVal, IterationKind::KEY_AND_VALUE);
190 EXPECT_TRUE(*treeMapIterator != nullptr);
191 EXPECT_TRUE(treeMapIterator->IsJSAPITreeMapIterator());
192 }
193
194 /**
195 * @tc.name: Next
196 * @tc.desc: Create an iterator of JSAPITreeMap,and then loop through the elements(key,value and keyAndvalue) of the
197 * iterator to check whether the elements through "Next" function are consistent.
198 * @tc.type: FUNC
199 * @tc.require:
200 */
HWTEST_F_L0(JSAPITreeMapIteratorTest,KEY_Next)201 HWTEST_F_L0(JSAPITreeMapIteratorTest, KEY_Next)
202 {
203 constexpr uint32_t DEFAULT_LENGTH = 8;
204 ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
205 JSMutableHandle<JSTaggedValue> key(thread, JSTaggedValue::Undefined());
206 JSMutableHandle<JSTaggedValue> value(thread, JSTaggedValue::Undefined());
207 JSHandle<JSTaggedValue> valueStr = thread->GlobalConstants()->GetHandledValueString();
208 JSHandle<JSAPITreeMap> jsTreeMap = CreateTreeMap();
209 std::string mapKey("mapkey");
210 std::string mapValue("mapvalue");
211 for (uint32_t i = 0; i < DEFAULT_LENGTH; i++) {
212 std::string ikey = mapKey + std::to_string(i);
213 std::string ivalue = mapValue + std::to_string(i);
214 key.Update(factory->NewFromStdString(ikey).GetTaggedValue());
215 value.Update(factory->NewFromStdString(ivalue).GetTaggedValue());
216 JSAPITreeMap::Set(thread, jsTreeMap, key, value);
217 }
218 // Create Iterator with KEY
219 JSHandle<JSAPITreeMapIterator> treeMapKeyIterator =
220 factory->NewJSAPITreeMapIterator(jsTreeMap, IterationKind::KEY);
221 // traversal iterator
222 for (uint32_t i = 0; i < DEFAULT_LENGTH; i++) {
223 auto ecmaRuntimeCallInfo = TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), 4);
224 ecmaRuntimeCallInfo->SetFunction(JSTaggedValue::Undefined());
225 ecmaRuntimeCallInfo->SetThis(treeMapKeyIterator.GetTaggedValue());
226
227 [[maybe_unused]] auto prev = TestHelper::SetupFrame(thread, ecmaRuntimeCallInfo);
228 JSTaggedValue result = JSAPITreeMapIterator::Next(ecmaRuntimeCallInfo);
229 TestHelper::TearDownFrame(thread, prev);
230
231 JSHandle<JSObject> resultObj(thread, result);
232 std::string resultKey = mapKey + std::to_string(i);
233 key.Update(factory->NewFromStdString(resultKey).GetTaggedValue());
234 EXPECT_EQ(JSTaggedValue::SameValue(
235 JSObject::GetProperty(thread, resultObj, valueStr).GetValue(), key), true);
236 EXPECT_EQ(treeMapKeyIterator->GetNextIndex(), (i + 1U));
237 }
238 }
239
HWTEST_F_L0(JSAPITreeMapIteratorTest,VALUE_Next)240 HWTEST_F_L0(JSAPITreeMapIteratorTest, VALUE_Next)
241 {
242 constexpr uint32_t DEFAULT_LENGTH = 8;
243 ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
244 JSMutableHandle<JSTaggedValue> key(thread, JSTaggedValue::Undefined());
245 JSMutableHandle<JSTaggedValue> value(thread, JSTaggedValue::Undefined());
246 JSHandle<JSTaggedValue> valueStr = thread->GlobalConstants()->GetHandledValueString();
247 JSHandle<JSAPITreeMap> jsTreeMap = CreateTreeMap();
248 std::string mapKey("mapkey");
249 std::string mapValue("mapvalue");
250 for (uint32_t i = 0; i < DEFAULT_LENGTH; i++) {
251 std::string ikey = mapKey + std::to_string(i);
252 std::string ivalue = mapValue + std::to_string(i + 1U);
253 key.Update(factory->NewFromStdString(ikey).GetTaggedValue());
254 value.Update(factory->NewFromStdString(ivalue).GetTaggedValue());
255 JSAPITreeMap::Set(thread, jsTreeMap, key, value);
256 }
257 // Create Iterator with VALUE
258 JSHandle<JSAPITreeMapIterator> treeMapKeyIterator =
259 factory->NewJSAPITreeMapIterator(jsTreeMap, IterationKind::VALUE);
260 // traversal iterator
261 for (uint32_t i = 0; i < DEFAULT_LENGTH; i++) {
262 auto ecmaRuntimeCallInfo = TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), 4);
263 ecmaRuntimeCallInfo->SetFunction(JSTaggedValue::Undefined());
264 ecmaRuntimeCallInfo->SetThis(treeMapKeyIterator.GetTaggedValue());
265
266 [[maybe_unused]] auto prev = TestHelper::SetupFrame(thread, ecmaRuntimeCallInfo);
267 JSTaggedValue result = JSAPITreeMapIterator::Next(ecmaRuntimeCallInfo);
268 TestHelper::TearDownFrame(thread, prev);
269
270 JSHandle<JSObject> resultObj(thread, result);
271 std::string resultKey = mapValue + std::to_string(i + 1U);
272 value.Update(factory->NewFromStdString(resultKey).GetTaggedValue());
273 EXPECT_EQ(JSTaggedValue::SameValue(
274 JSObject::GetProperty(thread, resultObj, valueStr).GetValue(), value), true);
275 EXPECT_EQ(treeMapKeyIterator->GetNextIndex(), (i + 1U));
276 }
277 }
278
HWTEST_F_L0(JSAPITreeMapIteratorTest,KEY_AND_VALUE_Next)279 HWTEST_F_L0(JSAPITreeMapIteratorTest, KEY_AND_VALUE_Next)
280 {
281 constexpr uint32_t DEFAULT_LENGTH = 8;
282 ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
283 JSMutableHandle<JSTaggedValue> key(thread, JSTaggedValue::Undefined());
284 JSMutableHandle<JSTaggedValue> value(thread, JSTaggedValue::Undefined());
285 JSHandle<JSTaggedValue> valueStr = thread->GlobalConstants()->GetHandledValueString();
286 JSHandle<JSAPITreeMap> jsTreeMap = CreateTreeMap();
287 std::string mapKey("mapkey");
288 std::string mapValue("mapvalue");
289 for (uint32_t i = 0; i < DEFAULT_LENGTH; i++) {
290 std::string ikey = mapKey + std::to_string(i + 1U);
291 std::string ivalue = mapValue + std::to_string(i + 2U);
292 key.Update(factory->NewFromStdString(ikey).GetTaggedValue());
293 value.Update(factory->NewFromStdString(ivalue).GetTaggedValue());
294 JSAPITreeMap::Set(thread, jsTreeMap, key, value);
295 }
296 // Create Iterator with KEY_AND_VALUE
297 JSHandle<JSAPITreeMapIterator> treeMapKeyIterator =
298 factory->NewJSAPITreeMapIterator(jsTreeMap, IterationKind::KEY_AND_VALUE);
299 // traversal iterator
300 for (uint32_t i = 0; i < DEFAULT_LENGTH; i++) {
301 auto ecmaRuntimeCallInfo = TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), 4);
302 ecmaRuntimeCallInfo->SetFunction(JSTaggedValue::Undefined());
303 ecmaRuntimeCallInfo->SetThis(treeMapKeyIterator.GetTaggedValue());
304
305 [[maybe_unused]] auto prev = TestHelper::SetupFrame(thread, ecmaRuntimeCallInfo);
306 JSTaggedValue result = JSAPITreeMapIterator::Next(ecmaRuntimeCallInfo);
307 TestHelper::TearDownFrame(thread, prev);
308
309 JSHandle<JSObject> resultObj(thread, result);
310 std::string resultKeyAndValue = mapKey + std::to_string(i + 1U);
311 value.Update(factory->NewFromStdString(resultKeyAndValue).GetTaggedValue());
312
313 JSHandle<JSTaggedValue> keyValueArr(JSObject::GetProperty(thread, resultObj, valueStr).GetValue());
314 for (int index = 0; index < 2; index++) {
315 JSHandle<JSTaggedValue> indexValue(thread, JSTaggedValue(index));
316 EXPECT_EQ(JSTaggedValue::SameValue(
317 JSObject::GetProperty(thread, keyValueArr, indexValue).GetValue(), value), true);
318 resultKeyAndValue = mapValue + std::to_string(i + 2U);
319 value.Update(factory->NewFromStdString(resultKeyAndValue).GetTaggedValue());
320 }
321 EXPECT_EQ(treeMapKeyIterator->GetNextIndex(), (i + 1U));
322 }
323 }
324
325 /**
326 * @tc.name: Next and CreateTreeMapIterator
327 * @tc.desc: test special return of Next and CreateTreeMapIterator,
328 * including throw exception and return undefined
329 * @tc.type: FUNC
330 * @tc.require:
331 */
HWTEST_F_L0(JSAPITreeMapIteratorTest,SpecailReturnOfNextCreateTreeMapIterator)332 HWTEST_F_L0(JSAPITreeMapIteratorTest, SpecailReturnOfNextCreateTreeMapIterator)
333 {
334 JSHandle<JSAPITreeMap> jsTreeMap = CreateTreeMap();
335 ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
336 JSHandle<JSAPITreeMapIterator> treeMapIterator = factory->NewJSAPITreeMapIterator(
337 jsTreeMap, IterationKind::KEY_AND_VALUE);
338 treeMapIterator->SetIteratedMap(thread, JSTaggedValue::Undefined());
339
340 // test Next exception
341 {
342 auto ecmaRuntimeCallInfo = TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), 4);
343 ecmaRuntimeCallInfo->SetFunction(JSTaggedValue::Undefined());
344 ecmaRuntimeCallInfo->SetThis(JSTaggedValue::Undefined());
345
346 [[maybe_unused]] auto prev = TestHelper::SetupFrame(thread, ecmaRuntimeCallInfo);
347 JSTaggedValue result = JSAPITreeMapIterator::Next(ecmaRuntimeCallInfo);
348 TestHelper::TearDownFrame(thread, prev);
349 EXPECT_EQ(result, JSTaggedValue::Exception());
350 EXPECT_EXCEPTION();
351 }
352
353 // test Next return undefined
354 {
355 auto ecmaRuntimeCallInfo = TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), 4);
356 ecmaRuntimeCallInfo->SetFunction(JSTaggedValue::Undefined());
357 ecmaRuntimeCallInfo->SetThis(treeMapIterator.GetTaggedValue());
358
359 [[maybe_unused]] auto prev = TestHelper::SetupFrame(thread, ecmaRuntimeCallInfo);
360 JSTaggedValue result = JSAPITreeMapIterator::Next(ecmaRuntimeCallInfo);
361 TestHelper::TearDownFrame(thread, prev);
362 EXPECT_EQ(result, thread->GlobalConstants()->GetUndefinedIterResult());
363 }
364
365 // test CreateTreeMapIterator exception
366 {
367 JSHandle<JSTaggedValue> undefined(thread, JSTaggedValue::Undefined());
368 JSHandle<JSTaggedValue> result =
369 JSAPITreeMapIterator::CreateTreeMapIterator(thread, undefined, IterationKind::KEY_AND_VALUE);
370 EXPECT_EQ(result.GetTaggedValue(), JSTaggedValue::Exception());
371 EXPECT_EXCEPTION();
372 }
373 }
374 } // namespace panda::ecmascript
375