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