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_vm.h"
18 #include "ecmascript/ecma_runtime_call_info.h"
19 #include "ecmascript/js_tagged_value.h"
20 #include "ecmascript/js_api/js_api_arraylist.h"
21 #include "ecmascript/global_env.h"
22 #include "ecmascript/object_factory.h"
23 #include "ecmascript/tests/test_helper.h"
24 #include "ecmascript/containers/containers_errors.h"
25
26 using namespace panda;
27 using namespace panda::ecmascript;
28
29 namespace panda::test {
30 class JSAPIArrayListTest : public testing::Test {
31 public:
SetUpTestCase()32 static void SetUpTestCase()
33 {
34 GTEST_LOG_(INFO) << "SetUpTestCase";
35 }
36
TearDownTestCase()37 static void TearDownTestCase()
38 {
39 GTEST_LOG_(INFO) << "TearDownCase";
40 }
41
SetUp()42 void SetUp() override
43 {
44 TestHelper::CreateEcmaVMWithScope(instance, thread, scope);
45 }
46
TearDown()47 void TearDown() override
48 {
49 TestHelper::DestroyEcmaVMWithScope(instance, scope);
50 }
51
52 EcmaVM *instance {nullptr};
53 EcmaHandleScope *scope {nullptr};
54 JSThread *thread {nullptr};
55
56 class TestClass : public base::BuiltinsBase {
57 public:
TestForEachAndReplaceAllFunc(EcmaRuntimeCallInfo * argv)58 static JSTaggedValue TestForEachAndReplaceAllFunc(EcmaRuntimeCallInfo *argv)
59 {
60 JSHandle<JSTaggedValue> value = GetCallArg(argv, 0);
61 JSHandle<JSTaggedValue> key = GetCallArg(argv, 1);
62 JSHandle<JSTaggedValue> arrayList = GetCallArg(argv, 2); // 2 means the secode arg
63 if (!arrayList->IsUndefined()) {
64 if (value->IsNumber()) {
65 TaggedArray *elements = TaggedArray::Cast(JSAPIArrayList::Cast(arrayList.GetTaggedValue().
66 GetTaggedObject())->GetElements().GetTaggedObject());
67 JSTaggedValue result = elements->Get(key->GetInt());
68 EXPECT_EQ(result, value.GetTaggedValue());
69 }
70 }
71 return JSTaggedValue::True();
72 }
73 };
74 protected:
CreateArrayList()75 JSAPIArrayList *CreateArrayList()
76 {
77 ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
78 JSHandle<GlobalEnv> env = thread->GetEcmaVM()->GetGlobalEnv();
79
80 JSHandle<JSTaggedValue> globalObject = env->GetJSGlobalObject();
81 JSHandle<JSTaggedValue> key(factory->NewFromASCII("ArkPrivate"));
82 JSHandle<JSTaggedValue> value =
83 JSObject::GetProperty(thread, JSHandle<JSTaggedValue>(globalObject), key).GetValue();
84
85 auto objCallInfo =
86 TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), 6); // 6 means the value
87 objCallInfo->SetFunction(JSTaggedValue::Undefined());
88 objCallInfo->SetThis(value.GetTaggedValue());
89 objCallInfo->SetCallArg(0, JSTaggedValue(static_cast<int>(containers::ContainerTag::ArrayList)));
90
91 [[maybe_unused]] auto prev = TestHelper::SetupFrame(thread, objCallInfo);
92 JSTaggedValue result = containers::ContainersPrivate::Load(objCallInfo);
93 TestHelper::TearDownFrame(thread, prev);
94
95 JSHandle<JSTaggedValue> constructor(thread, result);
96 JSHandle<JSAPIArrayList> arrayList(
97 factory->NewJSObjectByConstructor(JSHandle<JSFunction>(constructor), constructor));
98 JSHandle<TaggedArray> taggedArray = factory->NewTaggedArray(JSAPIArrayList::DEFAULT_CAPACITY_LENGTH);
99 arrayList->SetElements(thread, taggedArray);
100 return *arrayList;
101 }
102 };
103
HWTEST_F_L0(JSAPIArrayListTest,CreateArrayList)104 HWTEST_F_L0(JSAPIArrayListTest, CreateArrayList)
105 {
106 JSAPIArrayList *arrayList = CreateArrayList();
107 EXPECT_TRUE(arrayList != nullptr);
108 }
109
110 /**
111 * @tc.name: Add
112 * @tc.desc:
113 * @tc.type: FUNC
114 * @tc.require:
115 */
HWTEST_F_L0(JSAPIArrayListTest,Add)116 HWTEST_F_L0(JSAPIArrayListTest, Add)
117 {
118 uint32_t increasedLength = 5;
119 JSHandle<JSAPIArrayList> arrayList(thread, CreateArrayList());
120 for (uint32_t i = 0; i < increasedLength; i++) {
121 JSHandle<JSTaggedValue> value(thread, JSTaggedValue(i * 10));
122 JSAPIArrayList::Add(thread, arrayList, value);
123 }
124 JSHandle<TaggedArray> elements(thread, arrayList->GetElements());
125 for (uint32_t i = 0; i < increasedLength; i++) {
126 EXPECT_EQ(elements->Get(i), JSTaggedValue(i * 10));
127 }
128 }
129
130 /**
131 * @tc.name: Insert
132 * @tc.desc:
133 * @tc.type: FUNC
134 * @tc.require:
135 */
HWTEST_F_L0(JSAPIArrayListTest,Insert)136 HWTEST_F_L0(JSAPIArrayListTest, Insert)
137 {
138 uint32_t basicLength = 5;
139 JSHandle<JSAPIArrayList> arrayList(thread, CreateArrayList());
140 for (uint32_t i = 0; i < basicLength; i++) {
141 JSHandle<JSTaggedValue> value(thread, JSTaggedValue(i * 10));
142 JSAPIArrayList::Add(thread, arrayList, value);
143 }
144 uint32_t insertStartFrom = 2;
145 uint32_t insertNums = 3;
146 for (uint32_t i = 0; i < insertNums; i++) {
147 JSHandle<JSTaggedValue> insertValue(thread, JSTaggedValue(99 + i));
148 JSAPIArrayList::Insert(thread, arrayList, insertValue, insertStartFrom + i);
149 }
150 JSHandle<TaggedArray> elements(thread, arrayList->GetElements());
151 for (uint32_t i = 0; i < basicLength + insertNums; i++) {
152 if (i < insertStartFrom) {
153 EXPECT_EQ(elements->Get(i), JSTaggedValue(i * 10));
154 } else if (i >= insertStartFrom && i < insertStartFrom + insertNums) {
155 EXPECT_EQ(elements->Get(i), JSTaggedValue(99 + i - insertStartFrom));
156 } else if (i >= insertStartFrom + insertNums) {
157 EXPECT_EQ(elements->Get(i), JSTaggedValue((i - insertNums) * 10));
158 }
159 }
160
161 // throw error
162 // index < 0
163 JSHandle<JSTaggedValue> zeroValue(thread, JSTaggedValue(0));
164 JSAPIArrayList::Insert(thread, arrayList, zeroValue, -1);
165 EXPECT_EXCEPTION();
166
167 // index > length
168 int outOfRangeNumber = basicLength + insertNums + 10;
169 JSAPIArrayList::Insert(thread, arrayList, zeroValue, outOfRangeNumber);
170 EXPECT_EXCEPTION();
171 }
172
173 /**
174 * @tc.name: Clear & IsEmpty
175 * @tc.desc:
176 * @tc.type: FUNC
177 * @tc.require:
178 */
HWTEST_F_L0(JSAPIArrayListTest,Clear)179 HWTEST_F_L0(JSAPIArrayListTest, Clear)
180 {
181 JSHandle<JSAPIArrayList> arrayList(thread, CreateArrayList());
182 EXPECT_TRUE(JSAPIArrayList::IsEmpty(arrayList));
183 EXPECT_EQ(arrayList->GetLength(), JSTaggedValue(0));
184
185 JSHandle<JSTaggedValue> value(thread, JSTaggedValue(99));
186 JSAPIArrayList::Add(thread, arrayList, value);
187 EXPECT_FALSE(JSAPIArrayList::IsEmpty(arrayList));
188 EXPECT_EQ(arrayList->GetLength(), JSTaggedValue(1));
189
190 JSAPIArrayList::Clear(thread, arrayList);
191 EXPECT_TRUE(JSAPIArrayList::IsEmpty(arrayList));
192 EXPECT_EQ(arrayList->GetLength(), JSTaggedValue(0));
193 }
194
195 /**
196 * @tc.name: Clone
197 * @tc.desc:
198 * @tc.type: FUNC
199 * @tc.require:
200 */
HWTEST_F_L0(JSAPIArrayListTest,Clone)201 HWTEST_F_L0(JSAPIArrayListTest, Clone)
202 {
203 JSHandle<JSAPIArrayList> arrayList(thread, CreateArrayList());
204 uint32_t length = 10;
205 for (uint32_t i = 0; i < length; i++) {
206 JSHandle<JSTaggedValue> value(thread, JSTaggedValue(i));
207 JSAPIArrayList::Add(thread, arrayList, value);
208 }
209 JSHandle<JSAPIArrayList> newArrayList = JSAPIArrayList::Clone(thread, arrayList);
210 JSHandle<TaggedArray> elements(thread, arrayList->GetElements());
211 JSHandle<TaggedArray> newElements(thread, newArrayList->GetElements());
212 for (uint32_t i = 0; i < length; i++) {
213 EXPECT_EQ(elements->Get(i), JSTaggedValue(i));
214 EXPECT_EQ(newElements->Get(i), JSTaggedValue(i));
215 }
216 }
217
218 /**
219 * @tc.name: GetCapacity & IncreaseCapacityTo
220 * @tc.desc:
221 * @tc.type: FUNC
222 * @tc.require:
223 */
HWTEST_F_L0(JSAPIArrayListTest,GetCapacity_IncreaseCapacityTo)224 HWTEST_F_L0(JSAPIArrayListTest, GetCapacity_IncreaseCapacityTo)
225 {
226 JSHandle<JSAPIArrayList> arrayList(thread, CreateArrayList());
227 uint32_t oldCapacity = JSAPIArrayList::GetCapacity(thread, arrayList);
228 EXPECT_EQ(oldCapacity, JSAPIArrayList::DEFAULT_CAPACITY_LENGTH);
229
230 uint32_t addElementNums = 256;
231 uint32_t growCapacityTimes = 0;
232 uint32_t currentCapacity = JSAPIArrayList::DEFAULT_CAPACITY_LENGTH;
233 for (uint32_t i = 0; i < addElementNums; i++) {
234 JSAPIArrayList::Add(thread, arrayList, JSHandle<JSTaggedValue>(thread, JSTaggedValue::Undefined()));
235
236 // After capacity expansion, the capacity will be about 1.5 times that of the original.
237 currentCapacity = JSAPIArrayList::DEFAULT_CAPACITY_LENGTH;
238 for (uint32_t j = 0; j < growCapacityTimes; j++) {
239 currentCapacity = static_cast<uint32_t>(currentCapacity * 1.5);
240 }
241 EXPECT_EQ(JSAPIArrayList::GetCapacity(thread, arrayList), currentCapacity);
242
243 // When an element is added to the end of the current list, dynamic capacity expansion will be triggered.
244 if (i == (currentCapacity - 2U)) {
245 growCapacityTimes++;
246 }
247 }
248
249 // Expand capacity to a specified capacity value
250 uint32_t newCapacity = JSAPIArrayList::GetCapacity(thread, arrayList);
251 EXPECT_EQ(newCapacity, currentCapacity);
252
253 JSAPIArrayList::IncreaseCapacityTo(thread, arrayList, currentCapacity + 1230U);
254 newCapacity = JSAPIArrayList::GetCapacity(thread, arrayList);
255 EXPECT_EQ(newCapacity, currentCapacity + 1230U);
256 }
257
258 /**
259 * @tc.name: TrimToCurrentLength
260 * @tc.desc:
261 * @tc.type: FUNC
262 * @tc.require:
263 */
HWTEST_F_L0(JSAPIArrayListTest,TrimToCurrentLength)264 HWTEST_F_L0(JSAPIArrayListTest, TrimToCurrentLength)
265 {
266 JSHandle<JSAPIArrayList> arrayList(thread, CreateArrayList());
267
268 uint32_t addElementNums = 256;
269 uint32_t growCapacityTimes = 0;
270 uint32_t currentCapacity = JSAPIArrayList::DEFAULT_CAPACITY_LENGTH;
271 for (uint32_t i = 0; i < addElementNums; i++) {
272 JSAPIArrayList::Add(thread, arrayList, JSHandle<JSTaggedValue>(thread, JSTaggedValue::Undefined()));
273 currentCapacity = JSAPIArrayList::DEFAULT_CAPACITY_LENGTH;
274 for (uint32_t j = 0; j < growCapacityTimes; j++) {
275 currentCapacity = static_cast<uint32_t>(currentCapacity * 1.5);
276 }
277 EXPECT_EQ(JSAPIArrayList::GetCapacity(thread, arrayList), currentCapacity);
278 if (i == (currentCapacity - 2U)) {
279 growCapacityTimes++;
280 }
281 }
282 EXPECT_EQ(JSAPIArrayList::GetCapacity(thread, arrayList), currentCapacity);
283
284 // Cut the excess length to the actual number of elements
285 JSAPIArrayList::TrimToCurrentLength(thread, arrayList);
286 EXPECT_EQ(JSAPIArrayList::GetCapacity(thread, arrayList), addElementNums);
287 }
288
289 /**
290 * @tc.name: GetIndexOf & GetLastIndexOf
291 * @tc.desc:
292 * @tc.type: FUNC
293 * @tc.require:
294 */
HWTEST_F_L0(JSAPIArrayListTest,GetIndexOf_GetLastIndexOf)295 HWTEST_F_L0(JSAPIArrayListTest, GetIndexOf_GetLastIndexOf)
296 {
297 JSHandle<JSAPIArrayList> arrayList(thread, CreateArrayList());
298 uint32_t addElementNums = 100;
299 for (uint32_t i = 0; i < addElementNums; i++) {
300 JSHandle<JSTaggedValue> value(thread, JSTaggedValue(i));
301 JSAPIArrayList::Add(thread, arrayList, value);
302 }
303 for (uint32_t i = 0; i < JSAPIArrayList::GetCapacity(thread, arrayList); i++) {
304 if (i < addElementNums) {
305 int index =
306 JSAPIArrayList::GetIndexOf(thread, arrayList, JSHandle<JSTaggedValue>(thread, JSTaggedValue(i)));
307 EXPECT_EQ(index, static_cast<int>(i));
308 } else {
309 int index =
310 JSAPIArrayList::GetIndexOf(thread, arrayList, JSHandle<JSTaggedValue>(thread, JSTaggedValue(i)));
311 EXPECT_EQ(index, -1);
312 }
313 }
314
315 JSHandle<JSTaggedValue> value(thread, JSTaggedValue(99));
316 JSAPIArrayList::Add(thread, arrayList, value);
317 int firstIndex =
318 JSAPIArrayList::GetIndexOf(thread, arrayList, JSHandle<JSTaggedValue>(thread, JSTaggedValue(99)));
319 EXPECT_EQ(firstIndex, 99);
320
321 int lastIndex =
322 JSAPIArrayList::GetLastIndexOf(thread, arrayList, JSHandle<JSTaggedValue>(thread, JSTaggedValue(99)));
323 EXPECT_EQ(lastIndex, 99 + 1);
324 int lastIndex1 =
325 JSAPIArrayList::GetLastIndexOf(
326 thread, arrayList, JSHandle<JSTaggedValue>(thread, JSTaggedValue(addElementNums)));
327 EXPECT_EQ(lastIndex1, -1);
328 }
329
330 /**
331 * @tc.name: RemoveByIndex & Remove
332 * @tc.desc:
333 * @tc.type: FUNC
334 * @tc.require:
335 */
HWTEST_F_L0(JSAPIArrayListTest,RemoveByIndex_Remove)336 HWTEST_F_L0(JSAPIArrayListTest, RemoveByIndex_Remove)
337 {
338 JSHandle<JSAPIArrayList> arrayList(thread, CreateArrayList());
339 uint32_t addElementNums = 256;
340 uint32_t removeElementNums = 56;
341 for (uint32_t i = 0; i < addElementNums; i++) {
342 JSHandle<JSTaggedValue> value(thread, JSTaggedValue(i));
343 JSAPIArrayList::Add(thread, arrayList, value);
344 }
345
346 // RemoveByIndex
347 {
348 for (uint32_t i = 0; i < removeElementNums; i++) {
349 // Delete elements with indexes between [0, 55].
350 JSAPIArrayList::RemoveByIndex(thread, arrayList, 0);
351 }
352 JSHandle<TaggedArray> elements(thread, arrayList->GetElements());
353 for (uint32_t i = 0; i < addElementNums - removeElementNums; i++) {
354 // The value of the corresponding index [0, 199] is [56, 255].
355 EXPECT_EQ(elements->Get(i), JSTaggedValue(i + removeElementNums));
356 }
357 }
358
359 // Remove
360 {
361 for (uint32_t i = removeElementNums; i < 100; i++) {
362 JSHandle<JSTaggedValue> value(thread, JSTaggedValue(i));
363
364 // Delete 44 elements whose element values are in [56, 99].
365 JSAPIArrayList::Remove(thread, arrayList, value);
366 }
367 JSHandle<TaggedArray> elements(thread, arrayList->GetElements());
368 for (uint32_t i = 0; i < addElementNums - 100 - 1; i++) {
369
370 // The value of the corresponding index [0, 155] is [100, 255].
371 EXPECT_EQ(elements->Get(i), JSTaggedValue(i + 100));
372 }
373 JSHandle<JSTaggedValue> value(thread, JSTaggedValue(addElementNums));
374 bool result = JSAPIArrayList::Remove(thread, arrayList, value);
375 EXPECT_FALSE(result);
376 }
377 }
378
379 /**
380 * @tc.name: RemoveByRange
381 * @tc.desc:
382 * @tc.type: FUNC
383 * @tc.require:
384 */
HWTEST_F_L0(JSAPIArrayListTest,RemoveByRange)385 HWTEST_F_L0(JSAPIArrayListTest, RemoveByRange)
386 {
387 JSHandle<JSAPIArrayList> arrayList(thread, CreateArrayList());
388 uint32_t addElementNums = 150;
389 for (uint32_t i = 0; i < addElementNums; i++) {
390 JSHandle<JSTaggedValue> value(thread, JSTaggedValue(i));
391 JSAPIArrayList::Add(thread, arrayList, value);
392 }
393 // RemoveByRange
394 {
395 uint32_t formIndex = 50;
396 uint32_t toIndex = 100;
397 JSHandle<JSTaggedValue> fromIndexValue(thread, JSTaggedValue(formIndex));
398 JSHandle<JSTaggedValue> toIndexValue(thread, JSTaggedValue(toIndex));
399
400 // Remove the value between 50 and 100 of the index element.
401 JSAPIArrayList::RemoveByRange(thread, arrayList, fromIndexValue, toIndexValue);
402 uint32_t length = arrayList->GetLength().GetArrayLength();
403 JSHandle<TaggedArray> elements(thread, arrayList->GetElements());
404 for (uint32_t i = 0; i < length - (toIndex - formIndex); i++) {
405 // The value of the corresponding index [0, 100] is [0, 49] ∪ [100, 149].
406 if (i >= 0 && i < 50) {
407 EXPECT_EQ(elements->Get(i), JSTaggedValue(i));
408 } else if (i > 50) {
409 EXPECT_EQ(elements->Get(i), JSTaggedValue(i + 50));
410 }
411 }
412
413 // throw error test
414 uint32_t smallIndex = -1;
415 uint32_t bigIndex = arrayList->GetLength().GetArrayLength() + 10;
416 uint32_t zeroIndex = 0;
417 JSHandle<JSTaggedValue> smallIndexValue(thread, JSTaggedValue(smallIndex));
418 JSHandle<JSTaggedValue> bigIndexValue(thread, JSTaggedValue(bigIndex));
419 JSHandle<JSTaggedValue> zeroIndexValue(thread, JSTaggedValue(zeroIndex));
420
421 // startIndex < 0
422 JSAPIArrayList::RemoveByRange(thread, arrayList, smallIndexValue, zeroIndexValue);
423 EXPECT_EXCEPTION();
424
425 // startIndex >= size
426 JSAPIArrayList::RemoveByRange(thread, arrayList, bigIndexValue, zeroIndexValue);
427 EXPECT_EXCEPTION();
428
429 // endIndex <= startIndex
430 JSAPIArrayList::RemoveByRange(thread, arrayList, zeroIndexValue, zeroIndexValue);
431 EXPECT_EXCEPTION();
432
433 // endIndex < 0
434 JSAPIArrayList::RemoveByRange(thread, arrayList, zeroIndexValue, smallIndexValue);
435 EXPECT_EXCEPTION();
436
437 // endIndex > length
438 JSAPIArrayList::RemoveByRange(thread, arrayList, zeroIndexValue, bigIndexValue);
439 EXPECT_EXCEPTION();
440 }
441 }
442
443 /**
444 * @tc.name: ReplaceAllElements
445 * @tc.desc:
446 * @tc.type: FUNC
447 * @tc.require:
448 */
HWTEST_F_L0(JSAPIArrayListTest,ReplaceAllElements)449 HWTEST_F_L0(JSAPIArrayListTest, ReplaceAllElements)
450 {
451 ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
452 JSHandle<JSAPIArrayList> arrayList(thread, CreateArrayList());
453 JSHandle<GlobalEnv> env = thread->GetEcmaVM()->GetGlobalEnv();
454 JSHandle<JSFunction> func =
455 factory->NewJSFunction(env, reinterpret_cast<void *>(TestClass::TestForEachAndReplaceAllFunc));
456 auto callInfo = TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), 6);
457 callInfo->SetFunction(JSTaggedValue::Undefined());
458 callInfo->SetThis(arrayList.GetTaggedValue());
459 callInfo->SetCallArg(0, func.GetTaggedValue());
460
461 [[maybe_unused]] auto prev = TestHelper::SetupFrame(thread, callInfo);
462 JSHandle<JSTaggedValue> result(thread, JSAPIArrayList::ReplaceAllElements(thread,
463 callInfo->GetThis(), callInfo->GetFunction(), callInfo->GetCallArg(0)));
464 EXPECT_EQ(result.GetTaggedValue(), JSTaggedValue::Undefined());
465 TestHelper::TearDownFrame(thread, prev);
466
467 // Recheck the results after replace.
468 uint32_t length = arrayList->GetLength().GetArrayLength();
469 JSHandle<TaggedArray> elements(thread, arrayList->GetElements());
470 for (uint32_t i = 0; i < length; i++) {
471 EXPECT_EQ(elements->Get(i), JSTaggedValue(i));
472 }
473 }
474
475 /**
476 * @tc.name: SubArrayList
477 * @tc.desc:
478 * @tc.type: FUNC
479 * @tc.require:
480 */
HWTEST_F_L0(JSAPIArrayListTest,SubArrayList)481 HWTEST_F_L0(JSAPIArrayListTest, SubArrayList)
482 {
483 JSHandle<JSAPIArrayList> arrayList(thread, CreateArrayList());
484 uint32_t addElementNums = 256;
485 for (uint32_t i = 0; i < addElementNums; i++) {
486 JSHandle<JSTaggedValue> value(thread, JSTaggedValue(i));
487 JSAPIArrayList::Add(thread, arrayList, value);
488 }
489 uint32_t formIndex = 50;
490 uint32_t toIndex = 100;
491 JSHandle<JSTaggedValue> fromIndexValue(thread, JSTaggedValue(formIndex));
492 JSHandle<JSTaggedValue> toIndexValue(thread, JSTaggedValue(toIndex));
493 JSTaggedValue subArrayListValue =
494 JSAPIArrayList::SubArrayList(thread, arrayList, fromIndexValue, toIndexValue);
495 JSHandle<JSAPIArrayList> subArrayList(thread, subArrayListValue);
496 JSHandle<TaggedArray> subElements(thread, subArrayList->GetElements());
497 for (uint32_t i = 0; i < subArrayList->GetLength().GetArrayLength(); i++) {
498 // The element value interval of substring is [50, 100]
499 EXPECT_EQ(subElements->Get(i), JSTaggedValue(i + formIndex));
500 }
501
502 // throw error test
503 uint32_t smallIndex = -1;
504 uint32_t bigIndex = arrayList->GetLength().GetArrayLength() + 10;
505 uint32_t zeroIndex = 0;
506 JSHandle<JSTaggedValue> smallIndexValue(thread, JSTaggedValue(smallIndex));
507 JSHandle<JSTaggedValue> bigIndexValue(thread, JSTaggedValue(bigIndex));
508 JSHandle<JSTaggedValue> zeroIndexValue(thread, JSTaggedValue(zeroIndex));
509
510 // fromIndex < 0
511 JSAPIArrayList::SubArrayList(thread, arrayList, smallIndexValue, zeroIndexValue);
512 EXPECT_EXCEPTION();
513
514 // fromIndex > size
515 JSAPIArrayList::SubArrayList(thread, arrayList, bigIndexValue, zeroIndexValue);
516 EXPECT_EXCEPTION();
517
518 // toIndex <= fromIndex
519 JSAPIArrayList::SubArrayList(thread, arrayList, zeroIndexValue, zeroIndexValue);
520 EXPECT_EXCEPTION();
521
522 // toIndex < 0
523 JSAPIArrayList::SubArrayList(thread, arrayList, zeroIndexValue, smallIndexValue);
524 EXPECT_EXCEPTION();
525
526 // toIndex > length
527 JSAPIArrayList::SubArrayList(thread, arrayList, zeroIndexValue, bigIndexValue);
528 EXPECT_EXCEPTION();
529
530 // newLength == 0
531 uint32_t arrayLength = arrayList->GetLength().GetArrayLength();
532 JSHandle<JSTaggedValue> fromIndexValue0(thread, JSTaggedValue(arrayLength - 1));
533 JSHandle<JSTaggedValue> toIndexValue0(thread, JSTaggedValue(arrayLength));
534 JSTaggedValue newSubArrayListValue =
535 JSAPIArrayList::SubArrayList(thread, arrayList, fromIndexValue0, toIndexValue0);
536 JSHandle<JSAPIArrayList> newSubArrayList(thread, newSubArrayListValue);
537 int newLength = static_cast<int>(newSubArrayList->GetLength().GetArrayLength());
538 EXPECT_EQ(newLength, 1);
539 }
540
541 /**
542 * @tc.name: ForEach
543 * @tc.desc:
544 * @tc.type: FUNC
545 * @tc.require:
546 */
HWTEST_F_L0(JSAPIArrayListTest,ForEach)547 HWTEST_F_L0(JSAPIArrayListTest, ForEach)
548 {
549 ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
550 JSHandle<JSAPIArrayList> arrayList(thread, CreateArrayList());
551 JSHandle<GlobalEnv> env = thread->GetEcmaVM()->GetGlobalEnv();
552 JSHandle<JSFunction> func =
553 factory->NewJSFunction(env, reinterpret_cast<void *>(TestClass::TestForEachAndReplaceAllFunc));
554 auto callInfo = TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), 6);
555 callInfo->SetFunction(JSTaggedValue::Undefined());
556 callInfo->SetThis(arrayList.GetTaggedValue());
557 callInfo->SetCallArg(0, func.GetTaggedValue());
558
559 [[maybe_unused]] auto prev = TestHelper::SetupFrame(thread, callInfo);
560 JSHandle<JSTaggedValue> result(thread,
561 JSAPIArrayList::ForEach(thread, callInfo->GetThis(), callInfo->GetFunction(), callInfo->GetCallArg(0)));
562 EXPECT_EQ(result.GetTaggedValue(), JSTaggedValue::Undefined());
563 TestHelper::TearDownFrame(thread, prev);
564 }
565
566 /**
567 * @tc.name: GetIteratorObj
568 * @tc.desc:
569 * @tc.type: FUNC
570 * @tc.require:
571 */
HWTEST_F_L0(JSAPIArrayListTest,GetIteratorObj)572 HWTEST_F_L0(JSAPIArrayListTest, GetIteratorObj)
573 {
574 JSHandle<JSAPIArrayList> arrayList(thread, CreateArrayList());
575 JSHandle<JSTaggedValue> iteratorObj(thread, JSAPIArrayList::GetIteratorObj(thread, arrayList));
576 EXPECT_TRUE(iteratorObj->IsJSAPIArrayListIterator());
577 }
578
579 /**
580 * @tc.name: Get & Set & Has
581 * @tc.desc:
582 * @tc.type: FUNC
583 * @tc.require:
584 */
HWTEST_F_L0(JSAPIArrayListTest,Get_Set_Has)585 HWTEST_F_L0(JSAPIArrayListTest, Get_Set_Has)
586 {
587 JSHandle<JSAPIArrayList> arrayList(thread, CreateArrayList());
588
589 // test Has of empty arraylist
590 EXPECT_FALSE(arrayList->Has(JSTaggedValue(0)));
591
592 uint32_t elementsNum = 256;
593 for (uint32_t i = 0; i < elementsNum; i++) {
594 JSHandle<JSTaggedValue> value(thread, JSTaggedValue(i));
595 JSAPIArrayList::Add(thread, arrayList, value);
596 arrayList->Set(thread, i, JSTaggedValue(i * 10));
597
598 JSHandle<JSTaggedValue> getValue(thread, arrayList->Get(thread, i));
599 EXPECT_EQ(getValue.GetTaggedValue(), JSTaggedValue(i * 10));
600
601 bool isHas = arrayList->Has(JSTaggedValue(i * 10));
602 EXPECT_EQ(isHas, true);
603 EXPECT_FALSE(arrayList->Has(JSTaggedValue(-(i + 1))));
604 }
605
606 // test Get exception
607 JSTaggedValue result = arrayList->Get(thread, elementsNum);
608 EXPECT_EQ(result, JSTaggedValue::Exception());
609 EXPECT_EXCEPTION();
610
611 // test Set exception
612 JSTaggedValue result2 = arrayList->Set(thread, elementsNum, JSTaggedValue(elementsNum));
613 EXPECT_EQ(result2, JSTaggedValue::Exception());
614 EXPECT_EXCEPTION();
615 }
616
617 /**
618 * @tc.name: OwnKeys
619 * @tc.desc:
620 * @tc.type: FUNC
621 * @tc.require:
622 */
HWTEST_F_L0(JSAPIArrayListTest,OwnKeys)623 HWTEST_F_L0(JSAPIArrayListTest, OwnKeys)
624 {
625 JSHandle<JSAPIArrayList> arrayList(thread, CreateArrayList());
626 uint32_t elementsNum = 256;
627 for (uint32_t i = 0; i < elementsNum; i++) {
628 JSHandle<JSTaggedValue> value(thread, JSTaggedValue(i));
629 JSAPIArrayList::Add(thread, arrayList, value);
630 }
631 JSHandle<TaggedArray> keys = JSAPIArrayList::OwnKeys(thread, arrayList);
632 uint32_t length = arrayList->GetLength().GetArrayLength();
633 for (uint32_t i = 0; i < length; i++) {
634 ASSERT_TRUE(EcmaStringAccessor::StringsAreEqual(*(base::NumberHelper::NumberToString(thread, JSTaggedValue(i))),
635 EcmaString::Cast(keys->Get(i).GetTaggedObject())));
636 }
637 }
638
639 /**
640 * @tc.name: GetOwnProperty
641 * @tc.desc:
642 * @tc.type: FUNC
643 * @tc.require:
644 */
HWTEST_F_L0(JSAPIArrayListTest,GetOwnProperty)645 HWTEST_F_L0(JSAPIArrayListTest, GetOwnProperty)
646 {
647 JSHandle<JSAPIArrayList> arrayList(thread, CreateArrayList());
648 uint32_t elementsNums = 256;
649 for (uint32_t i = 0; i < elementsNums; i++) {
650 JSHandle<JSTaggedValue> value(thread, JSTaggedValue(i));
651 JSAPIArrayList::Add(thread, arrayList, value);
652 }
653 for (uint32_t i = 0; i < elementsNums; i++) {
654 JSHandle<JSTaggedValue> key(thread, JSTaggedValue(i));
655 bool getOwnPropertyRes = JSAPIArrayList::GetOwnProperty(thread, arrayList, key);
656 EXPECT_EQ(getOwnPropertyRes, true);
657 }
658
659 // test GetOwnProperty exception
660 JSHandle<JSTaggedValue> key(thread, JSTaggedValue(elementsNums * 2));
661 EXPECT_FALSE(JSAPIArrayList::GetOwnProperty(thread, arrayList, key));
662 EXPECT_EXCEPTION();
663
664 JSHandle<JSTaggedValue> undefined(thread, JSTaggedValue::Undefined());
665 EXPECT_FALSE(JSAPIArrayList::GetOwnProperty(thread, arrayList, undefined));
666 EXPECT_EXCEPTION();
667 }
668
669 /**
670 * @tc.name: GetProperty
671 * @tc.desc:
672 * @tc.type: FUNC
673 * @tc.require:
674 */
HWTEST_F_L0(JSAPIArrayListTest,GetProperty)675 HWTEST_F_L0(JSAPIArrayListTest, GetProperty)
676 {
677 JSHandle<JSAPIArrayList> arrayList(thread, CreateArrayList());
678 uint32_t elementsNums = 8;
679 for (uint32_t i = 0; i < elementsNums; i++) {
680 JSHandle<JSTaggedValue> value(thread, JSTaggedValue(i));
681 JSAPIArrayList::Add(thread, arrayList, value);
682 }
683 for (uint32_t i = 0; i < elementsNums; i++) {
684 JSHandle<JSTaggedValue> key(thread, JSTaggedValue(i));
685 OperationResult getPropertyRes = JSAPIArrayList::GetProperty(thread, arrayList, key);
686 EXPECT_EQ(getPropertyRes.GetValue().GetTaggedValue(), JSTaggedValue(i));
687 }
688 }
689
690 /**
691 * @tc.name: SetProperty
692 * @tc.desc:
693 * @tc.type: FUNC
694 * @tc.require:
695 */
HWTEST_F_L0(JSAPIArrayListTest,SetProperty)696 HWTEST_F_L0(JSAPIArrayListTest, SetProperty)
697 {
698 JSHandle<JSAPIArrayList> arrayList(thread, CreateArrayList());
699 uint32_t elementsNums = 8;
700 for (uint32_t i = 0; i < elementsNums; i++) {
701 JSHandle<JSTaggedValue> value(thread, JSTaggedValue(i));
702 JSAPIArrayList::Add(thread, arrayList, value);
703 }
704 for (uint32_t i = 0; i < elementsNums; i++) {
705 JSHandle<JSTaggedValue> key(thread, JSTaggedValue(i));
706 JSHandle<JSTaggedValue> value(thread, JSTaggedValue(i * 2)); // 2 : It means double
707 bool setPropertyRes = JSAPIArrayList::SetProperty(thread, arrayList, key, value);
708 EXPECT_EQ(setPropertyRes, true);
709 }
710 JSHandle<JSTaggedValue> key(thread, JSTaggedValue(-1));
711 JSHandle<JSTaggedValue> value(thread, JSTaggedValue(-1));
712 EXPECT_FALSE(JSAPIArrayList::SetProperty(thread, arrayList, key, value));
713 JSHandle<JSTaggedValue> key1(thread, JSTaggedValue(elementsNums));
714 EXPECT_FALSE(JSAPIArrayList::SetProperty(thread, arrayList, key1, value));
715 }
716 } // namespace panda::test
717