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