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/containers/containers_private.h"
17 #include "ecmascript/ecma_string.h"
18 #include "ecmascript/ecma_vm.h"
19 #include "ecmascript/global_env.h"
20 #include "ecmascript/js_api/js_api_list.h"
21 #include "ecmascript/js_api/js_api_list_iterator.h"
22 #include "ecmascript/js_function.h"
23 #include "ecmascript/js_handle.h"
24 #include "ecmascript/js_iterator.h"
25 #include "ecmascript/js_object-inl.h"
26 #include "ecmascript/js_tagged_value.h"
27 #include "ecmascript/object_factory.h"
28 #include "ecmascript/tagged_list.h"
29 #include "ecmascript/tests/test_helper.h"
30
31 using namespace panda;
32
33 using namespace panda::ecmascript;
34
35 using namespace panda::ecmascript::containers;
36
37 namespace panda::test {
38 class JSAPIListTest : public testing::Test {
39 public:
SetUpTestCase()40 static void SetUpTestCase()
41 {
42 GTEST_LOG_(INFO) << "SetUpTestCase";
43 }
44
TearDownTestCase()45 static void TearDownTestCase()
46 {
47 GTEST_LOG_(INFO) << "TearDownCase";
48 }
49
SetUp()50 void SetUp() override
51 {
52 TestHelper::CreateEcmaVMWithScope(instance, thread, scope);
53 }
54
TearDown()55 void TearDown() override
56 {
57 TestHelper::DestroyEcmaVMWithScope(instance, scope);
58 }
59
60 EcmaVM *instance {nullptr};
61 ecmascript::EcmaHandleScope *scope {nullptr};
62 JSThread *thread {nullptr};
63
64 protected:
CreateList()65 JSAPIList *CreateList()
66 {
67 ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
68 JSHandle<GlobalEnv> env = thread->GetEcmaVM()->GetGlobalEnv();
69
70 JSHandle<JSTaggedValue> globalObject = env->GetJSGlobalObject();
71 JSHandle<JSTaggedValue> key(factory->NewFromASCII("ArkPrivate"));
72 JSHandle<JSTaggedValue> value =
73 JSObject::GetProperty(thread, JSHandle<JSTaggedValue>(globalObject), key).GetValue();
74
75 auto objCallInfo = TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), 6);
76 objCallInfo->SetFunction(JSTaggedValue::Undefined());
77 objCallInfo->SetThis(value.GetTaggedValue());
78 objCallInfo->SetCallArg(0, JSTaggedValue(static_cast<int>(containers::ContainerTag::List)));
79
80 [[maybe_unused]] auto prev = TestHelper::SetupFrame(thread, objCallInfo);
81 JSTaggedValue result = containers::ContainersPrivate::Load(objCallInfo);
82 TestHelper::TearDownFrame(thread, prev);
83
84 JSHandle<JSTaggedValue> constructor(thread, result);
85 JSHandle<JSAPIList> list(factory->NewJSObjectByConstructor(JSHandle<JSFunction>(constructor), constructor));
86 JSTaggedValue singleList = TaggedSingleList::Create(thread);
87 list->SetSingleList(thread, singleList);
88 return *list;
89 }
90 };
91
HWTEST_F_L0(JSAPIListTest,listCreate)92 HWTEST_F_L0(JSAPIListTest, listCreate)
93 {
94 JSAPIList *list = CreateList();
95 EXPECT_TRUE(list != nullptr);
96 }
97
HWTEST_F_L0(JSAPIListTest,AddHasAndIsEmpty)98 HWTEST_F_L0(JSAPIListTest, AddHasAndIsEmpty)
99 {
100 constexpr int NODE_NUMBERS = 9;
101 ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
102 JSMutableHandle<JSTaggedValue> value(thread, JSTaggedValue::Undefined());
103
104 JSHandle<JSAPIList> toor(thread, CreateList());
105
106 EXPECT_TRUE(toor->IsEmpty());
107
108 std::string myValue("myvalue");
109 for (int i = 0; i < NODE_NUMBERS; i++) {
110 std::string ivalue = myValue + std::to_string(i);
111 value.Update(factory->NewFromStdString(ivalue).GetTaggedValue());
112 JSAPIList::Add(thread, toor, value);
113 }
114 EXPECT_EQ(toor->Length(), NODE_NUMBERS);
115 EXPECT_FALSE(toor->IsEmpty());
116
117 for (int i = 0; i < NODE_NUMBERS; i++) {
118 std::string ivalue = myValue + std::to_string(i);
119 value.Update(factory->NewFromStdString(ivalue).GetTaggedValue());
120
121 JSTaggedValue gValue = toor->Get(i);
122 EXPECT_EQ(gValue, value.GetTaggedValue());
123 }
124 JSTaggedValue gValue = toor->Get(10);
125 EXPECT_EQ(gValue, JSTaggedValue::Undefined());
126
127 std::string ivalue = myValue + std::to_string(1);
128 value.Update(factory->NewFromStdString(ivalue).GetTaggedValue());
129 EXPECT_TRUE(toor->Has(value.GetTaggedValue()));
130
131 toor->Dump();
132 }
133
HWTEST_F_L0(JSAPIListTest,InsertAndGetLastAndGetFirst)134 HWTEST_F_L0(JSAPIListTest, InsertAndGetLastAndGetFirst)
135 { // create jsMap
136 constexpr uint32_t NODE_NUMBERS = 9;
137 JSMutableHandle<JSTaggedValue> value(thread, JSTaggedValue::Undefined());
138
139 JSHandle<JSAPIList> toor(thread, CreateList());
140 EXPECT_EQ(toor->GetLast(), JSTaggedValue::Undefined());
141 EXPECT_EQ(toor->GetFirst(), JSTaggedValue::Undefined());
142 for (uint32_t i = 0; i < NODE_NUMBERS; i++) {
143 value.Update(JSTaggedValue(i + 1));
144 JSAPIList::Add(thread, toor, value);
145 }
146 EXPECT_EQ(toor->GetLast().GetInt(), 9);
147 EXPECT_EQ(toor->GetFirst().GetInt(), 1);
148
149 value.Update(JSTaggedValue(99));
150 int len = toor->Length();
151 toor->Insert(thread, toor, value, len);
152 EXPECT_EQ(toor->GetLast().GetInt(), 99);
153 EXPECT_EQ(toor->Length(), 10);
154
155 value.Update(JSTaggedValue(100));
156 toor->Insert(thread, toor, value, 0);
157 EXPECT_EQ(toor->GetFirst().GetInt(), 100);
158 EXPECT_EQ(toor->Length(), 11);
159
160 toor->Dump();
161
162 value.Update(JSTaggedValue(101));
163 toor->Insert(thread, toor, value, 5);
164 EXPECT_EQ(toor->Length(), 12);
165 toor->Dump();
166 EXPECT_EQ(toor->Get(5).GetInt(), 101);
167 }
168
HWTEST_F_L0(JSAPIListTest,GetIndexOfAndGetLastIndexOf)169 HWTEST_F_L0(JSAPIListTest, GetIndexOfAndGetLastIndexOf)
170 { // create jsMap
171 constexpr uint32_t NODE_NUMBERS = 9;
172 JSMutableHandle<JSTaggedValue> value(thread, JSTaggedValue::Undefined());
173
174 JSHandle<JSAPIList> toor(thread, CreateList());
175 EXPECT_EQ(toor->GetLast(), JSTaggedValue::Undefined());
176 EXPECT_EQ(toor->GetFirst(), JSTaggedValue::Undefined());
177 for (uint32_t i = 0; i < NODE_NUMBERS; i++) {
178 value.Update(JSTaggedValue(i + 1));
179 JSAPIList::Add(thread, toor, value);
180 }
181 EXPECT_EQ(toor->GetLast().GetInt(), 9);
182 EXPECT_EQ(toor->GetFirst().GetInt(), 1);
183
184 value.Update(JSTaggedValue(99));
185 int len = toor->Length();
186 toor->Insert(thread, toor, value, len);
187 EXPECT_EQ(toor->GetIndexOf(value.GetTaggedValue()).GetInt(), 9);
188 EXPECT_EQ(toor->GetLastIndexOf(value.GetTaggedValue()).GetInt(), 9);
189 EXPECT_EQ(toor->Length(), 10);
190
191 value.Update(JSTaggedValue(100));
192 toor->Insert(thread, toor, value, 0);
193 EXPECT_EQ(toor->GetIndexOf(value.GetTaggedValue()).GetInt(), 0);
194 EXPECT_EQ(toor->GetLastIndexOf(value.GetTaggedValue()).GetInt(), 0);
195 EXPECT_EQ(toor->Length(), 11);
196
197 value.Update(JSTaggedValue(101));
198 toor->Insert(thread, toor, value, 5);
199 EXPECT_EQ(toor->GetIndexOf(value.GetTaggedValue()).GetInt(), 5);
200 EXPECT_EQ(toor->GetLastIndexOf(value.GetTaggedValue()).GetInt(), 5);
201 EXPECT_EQ(toor->Length(), 12);
202
203 toor->Dump();
204 }
205
HWTEST_F_L0(JSAPIListTest,Remove)206 HWTEST_F_L0(JSAPIListTest, Remove)
207 { // create jsMap
208 constexpr uint32_t NODE_NUMBERS = 20;
209 JSMutableHandle<JSTaggedValue> value(thread, JSTaggedValue::Undefined());
210
211 JSHandle<JSAPIList> toor(thread, CreateList());
212 EXPECT_EQ(toor->GetLast(), JSTaggedValue::Undefined());
213 EXPECT_EQ(toor->GetFirst(), JSTaggedValue::Undefined());
214 for (uint32_t i = 0; i < NODE_NUMBERS; i++) {
215 value.Update(JSTaggedValue(i));
216 JSAPIList::Add(thread, toor, value);
217 }
218 EXPECT_EQ(toor->Length(), 20);
219 for (uint32_t i = 0; i < NODE_NUMBERS; i++) {
220 value.Update(JSTaggedValue(i));
221 JSTaggedValue gValue = toor->Get(i);
222 EXPECT_EQ(gValue, value.GetTaggedValue());
223 }
224
225 value.Update(JSTaggedValue(4));
226 EXPECT_EQ(JSAPIList::RemoveByIndex(thread, toor, 4), value.GetTaggedValue());
227 EXPECT_EQ(toor->Has(value.GetTaggedValue()), false);
228 EXPECT_EQ(toor->Length(), 19);
229
230 value.Update(JSTaggedValue(8));
231 EXPECT_EQ(toor->Remove(thread, value.GetTaggedValue()), JSTaggedValue::True());
232 EXPECT_EQ(toor->Has(value.GetTaggedValue()), false);
233 EXPECT_EQ(toor->Length(), 18);
234
235 toor->Dump();
236 }
237
HWTEST_F_L0(JSAPIListTest,Clear)238 HWTEST_F_L0(JSAPIListTest, Clear)
239 {
240 JSHandle<JSTaggedValue> value(thread, JSTaggedValue(1));
241 JSHandle<JSAPIList> list(thread, CreateList());
242 JSAPIList::Add(thread, list, value);
243
244 JSHandle<JSTaggedValue> value1(thread, JSTaggedValue(2));
245 JSAPIList::Insert(thread, list, value1, 0);
246
247 list->Clear(thread);
248
249 EXPECT_EQ(list->Length(), 0);
250 EXPECT_TRUE(list->GetFirst().IsUndefined());
251 }
252
HWTEST_F_L0(JSAPIListTest,Set)253 HWTEST_F_L0(JSAPIListTest, Set)
254 {
255 constexpr uint32_t NODE_NUMBERS = 20;
256 JSMutableHandle<JSTaggedValue> value(thread, JSTaggedValue::Undefined());
257
258 JSHandle<JSAPIList> toor(thread, CreateList());
259 EXPECT_EQ(toor->GetLast(), JSTaggedValue::Undefined());
260 EXPECT_EQ(toor->GetFirst(), JSTaggedValue::Undefined());
261 for (uint32_t i = 0; i < NODE_NUMBERS; i++) {
262 value.Update(JSTaggedValue(i));
263 JSAPIList::Add(thread, toor, value);
264 }
265 EXPECT_EQ(toor->Length(), 20);
266
267 for (uint32_t i = 0; i < NODE_NUMBERS; i++) {
268 value.Update(JSTaggedValue(i));
269 JSTaggedValue gValue = toor->Get(i);
270 EXPECT_EQ(gValue, value.GetTaggedValue());
271 }
272
273 for (uint32_t i = 0; i < NODE_NUMBERS; i++) {
274 value.Update(JSTaggedValue(i + 1));
275 JSAPIList::Set(thread, toor, i, value);
276 }
277
278 for (uint32_t i = 0; i < NODE_NUMBERS; i++) {
279 value.Update(JSTaggedValue(i + 1));
280 JSTaggedValue gValue = toor->Get(i);
281 EXPECT_EQ(gValue, value.GetTaggedValue());
282 }
283 }
284
HWTEST_F_L0(JSAPIListTest,GetOwnProperty)285 HWTEST_F_L0(JSAPIListTest, GetOwnProperty)
286 {
287 constexpr uint32_t DEFAULT_LENGTH = 8;
288 ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
289 JSMutableHandle<JSTaggedValue> value(thread, JSTaggedValue::Undefined());
290 JSHandle<JSAPIList> toor(thread, CreateList());
291
292 std::string listvalue("listvalue");
293 for (uint32_t i = 0; i < DEFAULT_LENGTH; i++) {
294 std::string ivalue = listvalue + std::to_string(i);
295 value.Update(factory->NewFromStdString(ivalue).GetTaggedValue());
296 JSAPIList::Add(thread, toor, value);
297 }
298 // test GetOwnProperty
299 int testInt = 1;
300 JSHandle<JSTaggedValue> listKey1(thread, JSTaggedValue(testInt));
301 EXPECT_TRUE(JSAPIList::GetOwnProperty(thread, toor, listKey1));
302 testInt = 20;
303 JSHandle<JSTaggedValue> listKey2(thread, JSTaggedValue(testInt));
304 EXPECT_FALSE(JSAPIList::GetOwnProperty(thread, toor, listKey2));
305 EXPECT_EXCEPTION();
306
307 // test GetOwnProperty exception
308 JSHandle<JSTaggedValue> undefined(thread, JSTaggedValue::Undefined());
309 EXPECT_FALSE(JSAPIList::GetOwnProperty(thread, toor, undefined));
310 EXPECT_EXCEPTION();
311 }
312
313 /**
314 * @tc.name: GetProperty
315 * @tc.desc:
316 * @tc.type: FUNC
317 * @tc.require:
318 */
HWTEST_F_L0(JSAPIListTest,GetProperty)319 HWTEST_F_L0(JSAPIListTest, GetProperty)
320 {
321 JSHandle<JSAPIList> toor(thread, CreateList());
322 uint32_t elementsNums = 8;
323 for (uint32_t i = 0; i < elementsNums; i++) {
324 JSHandle<JSTaggedValue> value(thread, JSTaggedValue(i));
325 JSAPIList::Add(thread, toor, value);
326 }
327 for (uint32_t i = 0; i < elementsNums; i++) {
328 JSHandle<JSTaggedValue> key(thread, JSTaggedValue(i));
329 OperationResult getPropertyRes = JSAPIList::GetProperty(thread, toor, key);
330 EXPECT_EQ(getPropertyRes.GetValue().GetTaggedValue(), JSTaggedValue(i));
331 }
332 }
333
334 /**
335 * @tc.name: SetProperty
336 * @tc.desc:
337 * @tc.type: FUNC
338 * @tc.require:
339 */
HWTEST_F_L0(JSAPIListTest,SetProperty)340 HWTEST_F_L0(JSAPIListTest, SetProperty)
341 {
342 JSHandle<JSAPIList> toor(thread, CreateList());
343 uint32_t elementsNums = 8;
344 for (uint32_t i = 0; i < elementsNums; i++) {
345 JSHandle<JSTaggedValue> value(thread, JSTaggedValue(i));
346 JSAPIList::Add(thread, toor, value);
347 }
348 for (uint32_t i = 0; i < elementsNums; i++) {
349 JSHandle<JSTaggedValue> key(thread, JSTaggedValue(i));
350 JSHandle<JSTaggedValue> value(thread, JSTaggedValue(i * 2)); // 2 : It means double
351 bool setPropertyRes = JSAPIList::SetProperty(thread, toor, key, value);
352 EXPECT_EQ(setPropertyRes, true);
353 }
354 JSHandle<JSTaggedValue> key(thread, JSTaggedValue(-1));
355 JSHandle<JSTaggedValue> value(thread, JSTaggedValue(-1));
356 EXPECT_FALSE(JSAPIList::SetProperty(thread, toor, key, value));
357 JSHandle<JSTaggedValue> key1(thread, JSTaggedValue(elementsNums));
358 EXPECT_FALSE(JSAPIList::SetProperty(thread, toor, key1, value));
359 }
360
361 /**
362 * @tc.name: GetSubList
363 * @tc.desc:
364 * @tc.type: FUNC
365 * @tc.require:
366 */
HWTEST_F_L0(JSAPIListTest,GetSubList)367 HWTEST_F_L0(JSAPIListTest, GetSubList)
368 {
369 JSHandle<JSAPIList> List(thread, CreateList());
370 uint32_t addElementNums = 256;
371 for (uint32_t i = 0; i < addElementNums; i++) {
372 JSHandle<JSTaggedValue> value(thread, JSTaggedValue(i));
373 JSAPIList::Add(thread, List, value);
374 }
375
376 // throw error test
377 uint32_t smallIndex = -1;
378 uint32_t bigIndex = List->Length() + 10;
379 uint32_t zeroIndex = 0;
380
381 // fromIndex < 0
382 JSAPIList::GetSubList(thread, List, smallIndex, zeroIndex);
383 EXPECT_EXCEPTION();
384
385 // fromIndex >= size
386 JSAPIList::GetSubList(thread, List, bigIndex, zeroIndex);
387 EXPECT_EXCEPTION();
388
389 // toIndex <= fromIndex
390 JSAPIList::GetSubList(thread, List, zeroIndex, zeroIndex);
391 EXPECT_EXCEPTION();
392
393 // toIndex < 0
394 JSAPIList::GetSubList(thread, List, zeroIndex, smallIndex);
395 EXPECT_EXCEPTION();
396
397 // toIndex > length
398 JSAPIList::GetSubList(thread, List, zeroIndex, bigIndex);
399 EXPECT_EXCEPTION();
400 }
401
HWTEST_F_L0(JSAPIListTest,OwnKeys)402 HWTEST_F_L0(JSAPIListTest, OwnKeys)
403 {
404 uint32_t elementsNums = 8;
405 JSHandle<JSAPIList> list(thread, CreateList());
406 for (uint32_t i = 0; i < elementsNums; i++) {
407 JSHandle<JSTaggedValue> value(thread, JSTaggedValue(i));
408 JSAPIList::Add(thread, list, value);
409 }
410 JSHandle<TaggedArray> keyArray = JSAPIList::OwnKeys(thread, list);
411 EXPECT_TRUE(keyArray->GetClass()->IsTaggedArray());
412 EXPECT_TRUE(keyArray->GetLength() == elementsNums);
413 for (uint32_t i = 0; i < elementsNums; i++) {
414 ASSERT_TRUE(EcmaStringAccessor::StringsAreEqual(*(base::NumberHelper::NumberToString(thread, JSTaggedValue(i))),
415 EcmaString::Cast(keyArray->Get(i).GetTaggedObject())));
416 }
417 }
418 } // namespace panda::test
419