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_vector.h"
21 #include "ecmascript/js_api/js_api_vector_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/tests/test_helper.h"
29
30 using namespace panda;
31
32 using namespace panda::ecmascript;
33
34 using namespace panda::ecmascript::containers;
35
36 namespace panda::test {
37 class JSAPIVectorTest : public testing::Test {
38 public:
SetUpTestCase()39 static void SetUpTestCase()
40 {
41 GTEST_LOG_(INFO) << "SetUpTestCase";
42 }
43
TearDownTestCase()44 static void TearDownTestCase()
45 {
46 GTEST_LOG_(INFO) << "TearDownCase";
47 }
48
SetUp()49 void SetUp() override
50 {
51 TestHelper::CreateEcmaVMWithScope(instance, thread, scope);
52 }
53
TearDown()54 void TearDown() override
55 {
56 TestHelper::DestroyEcmaVMWithScope(instance, scope);
57 }
58
59 EcmaVM *instance {nullptr};
60 ecmascript::EcmaHandleScope *scope {nullptr};
61 JSThread *thread {nullptr};
62
63 protected:
CreateVector()64 JSAPIVector *CreateVector()
65 {
66 ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
67 JSHandle<GlobalEnv> env = thread->GetEcmaVM()->GetGlobalEnv();
68
69 JSHandle<JSTaggedValue> globalObject = env->GetJSGlobalObject();
70 JSHandle<JSTaggedValue> key(factory->NewFromASCII("ArkPrivate"));
71 JSHandle<JSTaggedValue> value =
72 JSObject::GetProperty(thread, JSHandle<JSTaggedValue>(globalObject), key).GetValue();
73
74 auto objCallInfo = TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), 6);
75 objCallInfo->SetFunction(JSTaggedValue::Undefined());
76 objCallInfo->SetThis(value.GetTaggedValue());
77 objCallInfo->SetCallArg(0, JSTaggedValue(static_cast<int>(containers::ContainerTag::Vector)));
78
79 [[maybe_unused]] auto prev = TestHelper::SetupFrame(thread, objCallInfo);
80 JSTaggedValue result = containers::ContainersPrivate::Load(objCallInfo);
81 TestHelper::TearDownFrame(thread, prev);
82
83 JSHandle<JSTaggedValue> constructor(thread, result);
84 JSHandle<JSAPIVector> vector(factory->NewJSObjectByConstructor(JSHandle<JSFunction>(constructor), constructor));
85 vector->SetLength(0);
86 return *vector;
87 }
88 };
89
HWTEST_F_L0(JSAPIVectorTest,vectorCreate)90 HWTEST_F_L0(JSAPIVectorTest, vectorCreate)
91 {
92 JSAPIVector *vector = CreateVector();
93 EXPECT_TRUE(vector != nullptr);
94 }
95
HWTEST_F_L0(JSAPIVectorTest,AddGetHas)96 HWTEST_F_L0(JSAPIVectorTest, AddGetHas)
97 {
98 constexpr uint32_t NODE_NUMBERS = 9;
99 ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
100 JSMutableHandle<JSTaggedValue> value(thread, JSTaggedValue::Undefined());
101
102 JSHandle<JSAPIVector> toor(thread, CreateVector());
103
104 // test Has of empty vector
105 value.Update(JSTaggedValue(NODE_NUMBERS));
106 EXPECT_FALSE(toor->Has(value.GetTaggedValue()));
107
108 std::string myValue("myvalue");
109 for (uint32_t i = 0; i < NODE_NUMBERS; i++) {
110 std::string ivalue = myValue + std::to_string(i);
111 value.Update(factory->NewFromStdString(ivalue).GetTaggedValue());
112 bool result = JSAPIVector::Add(thread, toor, value);
113 EXPECT_TRUE(result);
114 EXPECT_EQ(JSAPIVector::Get(thread, toor, i), value.GetTaggedValue());
115 EXPECT_TRUE(toor->Has(value.GetTaggedValue()));
116 }
117 value.Update(JSTaggedValue(NODE_NUMBERS));
118 EXPECT_FALSE(toor->Has(value.GetTaggedValue()));
119 EXPECT_EQ(static_cast<uint32_t>(toor->GetSize()), NODE_NUMBERS);
120
121 // test Get exception
122 JSAPIVector::Get(thread, toor, -1);
123 EXPECT_EXCEPTION();
124 JSAPIVector::Get(thread, toor, static_cast<int32_t>(NODE_NUMBERS));
125 EXPECT_EXCEPTION();
126
127 toor->Dump();
128 }
129
HWTEST_F_L0(JSAPIVectorTest,RemoveByIndexAndRemove)130 HWTEST_F_L0(JSAPIVectorTest, RemoveByIndexAndRemove)
131 {
132 constexpr uint32_t NODE_NUMBERS = 9;
133 ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
134 JSMutableHandle<JSTaggedValue> value(thread, JSTaggedValue::Undefined());
135
136 JSHandle<JSAPIVector> toor(thread, CreateVector());
137
138 std::string myValue("myvalue");
139 for (uint32_t i = 0; i < NODE_NUMBERS; i++) {
140 std::string ivalue = myValue + std::to_string(i);
141 value.Update(factory->NewFromStdString(ivalue).GetTaggedValue());
142 bool result = JSAPIVector::Add(thread, toor, value);
143 EXPECT_TRUE(result);
144 }
145
146 for (int32_t i = NODE_NUMBERS / 2; i > 0; i--) {
147 std::string ivalue = myValue + std::to_string(i);
148 value.Update(factory->NewFromStdString(ivalue).GetTaggedValue());
149 JSTaggedValue gValue = JSAPIVector::RemoveByIndex(thread, toor, i);
150 EXPECT_EQ(gValue, value.GetTaggedValue());
151 bool delResult = JSAPIVector::Remove(thread, toor, value);
152 EXPECT_FALSE(delResult);
153 }
154
155 // test RemoveByIndex exception
156 JSTaggedValue result = JSAPIVector::RemoveByIndex(thread, toor, -1);
157 EXPECT_EQ(result, JSTaggedValue::Exception());
158 EXPECT_EXCEPTION();
159 JSTaggedValue result1 = JSAPIVector::RemoveByIndex(thread, toor, NODE_NUMBERS);
160 EXPECT_EQ(result1, JSTaggedValue::Exception());
161 EXPECT_EXCEPTION();
162
163 toor->Dump();
164 }
165
HWTEST_F_L0(JSAPIVectorTest,ClearAndisEmpty)166 HWTEST_F_L0(JSAPIVectorTest, ClearAndisEmpty)
167 {
168 constexpr uint32_t NODE_NUMBERS = 9;
169 ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
170 JSMutableHandle<JSTaggedValue> value(thread, JSTaggedValue::Undefined());
171
172 JSHandle<JSAPIVector> toor(thread, CreateVector());
173
174 std::string myValue("myvalue");
175 for (uint32_t i = 0; i < NODE_NUMBERS; i++) {
176 std::string ivalue = myValue + std::to_string(i);
177 value.Update(factory->NewFromStdString(ivalue).GetTaggedValue());
178 bool result = JSAPIVector::Add(thread, toor, value);
179 EXPECT_TRUE(result);
180 EXPECT_EQ(toor->IsEmpty(), false);
181 }
182
183 JSAPIVector::Clear(thread, toor);
184 EXPECT_EQ(toor->IsEmpty(), true);
185
186 toor->Dump();
187 }
188
HWTEST_F_L0(JSAPIVectorTest,GetIndexOf)189 HWTEST_F_L0(JSAPIVectorTest, GetIndexOf)
190 {
191 constexpr uint32_t NODE_NUMBERS = 9;
192 ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
193 JSMutableHandle<JSTaggedValue> value(thread, JSTaggedValue::Undefined());
194
195 JSHandle<JSAPIVector> toor(thread, CreateVector());
196
197 std::string myValue("myvalue");
198 for (uint32_t i = 0; i < NODE_NUMBERS; i++) {
199 std::string ivalue = myValue + std::to_string(i);
200 value.Update(factory->NewFromStdString(ivalue).GetTaggedValue());
201 bool result = JSAPIVector::Add(thread, toor, value);
202 EXPECT_TRUE(result);
203 EXPECT_EQ(JSAPIVector::GetIndexOf(thread, toor, value), static_cast<int>(i));
204 }
205
206 toor->Dump();
207 }
208
HWTEST_F_L0(JSAPIVectorTest,GetOwnProperty)209 HWTEST_F_L0(JSAPIVectorTest, GetOwnProperty)
210 {
211 constexpr uint32_t DEFAULT_LENGTH = 8;
212 ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
213 JSMutableHandle<JSTaggedValue> value(thread, JSTaggedValue::Undefined());
214 JSHandle<JSAPIVector> toor(thread, CreateVector());
215
216 std::string vectorvalue("vectorvalue");
217 for (uint32_t i = 0; i < DEFAULT_LENGTH; i++) {
218 std::string ivalue = vectorvalue + std::to_string(i);
219 value.Update(factory->NewFromStdString(ivalue).GetTaggedValue());
220 JSAPIVector::Add(thread, toor, value);
221 }
222 // test GetOwnProperty
223 int testInt = 1;
224 JSHandle<JSTaggedValue> vectorKey1(thread, JSTaggedValue(testInt));
225 EXPECT_TRUE(JSAPIVector::GetOwnProperty(thread, toor, vectorKey1));
226 testInt = 20;
227 JSHandle<JSTaggedValue> vectorKey2(thread, JSTaggedValue(testInt));
228 EXPECT_FALSE(JSAPIVector::GetOwnProperty(thread, toor, vectorKey2));
229 EXPECT_EXCEPTION();
230
231 // test GetOwnProperty exception
232 JSHandle<JSTaggedValue> undefined(thread, JSTaggedValue::Undefined());
233 EXPECT_FALSE(JSAPIVector::GetOwnProperty(thread, toor, undefined));
234 EXPECT_EXCEPTION();
235 }
236
237 /**
238 * @tc.name: GetProperty
239 * @tc.desc:
240 * @tc.type: FUNC
241 * @tc.require:
242 */
HWTEST_F_L0(JSAPIVectorTest,GetProperty)243 HWTEST_F_L0(JSAPIVectorTest, GetProperty)
244 {
245 JSHandle<JSAPIVector> toor(thread, CreateVector());
246 uint32_t elementsNums = 8;
247 for (uint32_t i = 0; i < elementsNums; i++) {
248 JSHandle<JSTaggedValue> value(thread, JSTaggedValue(i));
249 JSAPIVector::Add(thread, toor, value);
250 }
251 for (uint32_t i = 0; i < elementsNums; i++) {
252 JSHandle<JSTaggedValue> key(thread, JSTaggedValue(i));
253 OperationResult getPropertyRes = JSAPIVector::GetProperty(thread, toor, key);
254 EXPECT_EQ(getPropertyRes.GetValue().GetTaggedValue(), JSTaggedValue(i));
255 }
256
257 // test GetProperty exception
258 JSHandle<JSTaggedValue> key1(thread, JSTaggedValue(-1));
259 JSAPIVector::GetProperty(thread, toor, key1);
260 EXPECT_EXCEPTION();
261 JSHandle<JSTaggedValue> key2(thread, JSTaggedValue(elementsNums));
262 JSAPIVector::GetProperty(thread, toor, key2);
263 EXPECT_EXCEPTION();
264 }
265
266 /**
267 * @tc.name: SetProperty
268 * @tc.desc:
269 * @tc.type: FUNC
270 * @tc.require:
271 */
HWTEST_F_L0(JSAPIVectorTest,SetProperty)272 HWTEST_F_L0(JSAPIVectorTest, SetProperty)
273 {
274 JSHandle<JSAPIVector> toor(thread, CreateVector());
275 uint32_t elementsNums = 8;
276 for (uint32_t i = 0; i < elementsNums; i++) {
277 JSHandle<JSTaggedValue> value(thread, JSTaggedValue(i));
278 JSAPIVector::Add(thread, toor, value);
279 }
280 for (uint32_t i = 0; i < elementsNums; i++) {
281 JSHandle<JSTaggedValue> key(thread, JSTaggedValue(i));
282 JSHandle<JSTaggedValue> value(thread, JSTaggedValue(i * 2)); // 2 : It means double
283 bool setPropertyRes = JSAPIVector::SetProperty(thread, toor, key, value);
284 EXPECT_EQ(setPropertyRes, true);
285 }
286 JSHandle<JSTaggedValue> key(thread, JSTaggedValue(-1));
287 JSHandle<JSTaggedValue> value(thread, JSTaggedValue(0));
288 EXPECT_FALSE(JSAPIVector::SetProperty(thread, toor, key, value));
289 JSHandle<JSTaggedValue> key1(thread, JSTaggedValue(elementsNums));
290 EXPECT_FALSE(JSAPIVector::SetProperty(thread, toor, key1, value));
291 }
292
293 /**
294 * @tc.name: TrimToCurrentLength
295 * @tc.desc:
296 * @tc.type: FUNC
297 * @tc.require:
298 */
HWTEST_F_L0(JSAPIVectorTest,IncreaseCapacityToTrimToCurrentLength)299 HWTEST_F_L0(JSAPIVectorTest, IncreaseCapacityToTrimToCurrentLength)
300 {
301 JSHandle<JSAPIVector> toor(thread, CreateVector());
302 uint32_t elementsNums = 20;
303 for (uint32_t i = 0; i < elementsNums; i++) {
304 JSHandle<JSTaggedValue> value(thread, JSTaggedValue(i));
305 JSAPIVector::Add(thread, toor, value);
306 }
307 JSAPIVector::IncreaseCapacityTo(thread, toor, 80);
308 JSHandle<TaggedArray> elementData(thread, toor->GetElements());
309 EXPECT_EQ(static_cast<int>(elementData->GetLength()), 80);
310 JSAPIVector::TrimToCurrentLength(thread, toor);
311 JSHandle<TaggedArray> newElementData(thread, toor->GetElements());
312 EXPECT_EQ(newElementData->GetLength(), elementsNums);
313
314 // test IncreaseCapacityTo exception
315 JSAPIVector::IncreaseCapacityTo(thread, toor, -1);
316 EXPECT_EXCEPTION();
317 }
318
319 /**
320 * @tc.name: Insert
321 * @tc.desc:
322 * @tc.type: FUNC
323 * @tc.require:
324 */
HWTEST_F_L0(JSAPIVectorTest,Insert)325 HWTEST_F_L0(JSAPIVectorTest, Insert)
326 {
327 JSHandle<JSAPIVector> toor(thread, CreateVector());
328 uint32_t elementsNums = 20;
329 for (uint32_t i = 0; i < elementsNums; i++) {
330 JSHandle<JSTaggedValue> value(thread, JSTaggedValue(i));
331 JSAPIVector::Insert(thread, toor, value, 0);
332 }
333
334 // check
335 for (uint32_t i = 0; i < elementsNums; i++) {
336 JSHandle<JSTaggedValue> value(thread, JSTaggedValue(i));
337 EXPECT_EQ(JSAPIVector::Get(
338 thread, toor, static_cast<int32_t>(i)), JSTaggedValue(elementsNums - i - 1));
339 }
340
341 // test Insert exception
342 JSHandle<JSTaggedValue> value(thread, JSTaggedValue(elementsNums));
343 JSAPIVector::Insert(thread, toor, value, -1);
344 EXPECT_EXCEPTION();
345
346 JSAPIVector::Insert(thread, toor, value, static_cast<int32_t>(elementsNums + 1));
347 EXPECT_EXCEPTION();
348 }
349
350 /**
351 * @tc.name: SetLength, GetIndexFrom, GetLastElement, GetLastIndexOf and GetLastIndexFrom
352 * @tc.desc:
353 * @tc.type: FUNC
354 * @tc.require:
355 */
HWTEST_F_L0(JSAPIVectorTest,SetLengthGetIndexFromGetLastElementGetLastIndexOf)356 HWTEST_F_L0(JSAPIVectorTest, SetLengthGetIndexFromGetLastElementGetLastIndexOf)
357 {
358 JSHandle<JSAPIVector> toor(thread, CreateVector());
359
360 // test GetLastElement of empty vector
361 EXPECT_EQ(toor->GetLastElement(), JSTaggedValue::Undefined());
362
363 // test GetLastIndexOf of empty vector
364 uint32_t elementsNums = 20;
365 JSHandle<JSTaggedValue> obj(thread, JSTaggedValue(elementsNums - 1));
366 EXPECT_EQ(JSAPIVector::GetLastIndexOf(thread, toor, obj), -1);
367
368 for (uint32_t i = 0; i < elementsNums; i++) {
369 JSHandle<JSTaggedValue> value(thread, JSTaggedValue(i));
370 JSAPIVector::Add(thread, toor, value);
371 }
372
373 // test GetIndexFrom
374 EXPECT_EQ(JSAPIVector::GetIndexFrom(thread, toor, obj, -1), static_cast<int32_t>(elementsNums - 1));
375
376 EXPECT_EQ(JSAPIVector::GetIndexFrom(thread, toor, obj, elementsNums), -1);
377 EXPECT_EXCEPTION();
378
379 // test GetLastElement
380 EXPECT_EQ(toor->GetLastElement(), JSTaggedValue(elementsNums - 1));
381
382 // test GetLastIndexOf
383 EXPECT_EQ(JSAPIVector::GetLastIndexOf(thread, toor, obj), static_cast<int32_t>(elementsNums - 1));
384
385 // test GetLastIndexFrom
386 EXPECT_EQ(JSAPIVector::GetLastIndexFrom(
387 thread, toor, obj, elementsNums - 1), static_cast<int32_t>(elementsNums - 1));
388
389 EXPECT_EQ(JSAPIVector::GetLastIndexFrom(thread, toor, obj, elementsNums), -1);
390 EXPECT_EXCEPTION();
391
392 JSHandle<JSTaggedValue> obj1(thread, JSTaggedValue(-elementsNums));
393 EXPECT_EQ(JSAPIVector::GetLastIndexFrom(thread, toor, obj1, -1), -1);
394
395 // test SetLength
396 JSAPIVector::SetLength(thread, toor, elementsNums * 3);
397 EXPECT_EQ(toor->GetLength(), static_cast<int32_t>(elementsNums * 3));
398 }
399
400 /**
401 * @tc.name: RemoveByRange
402 * @tc.desc:
403 * @tc.type: FUNC
404 * @tc.require:
405 */
HWTEST_F_L0(JSAPIVectorTest,ExceptionOfRemoveByRange)406 HWTEST_F_L0(JSAPIVectorTest, ExceptionOfRemoveByRange)
407 {
408 JSHandle<JSAPIVector> toor(thread, CreateVector());
409 uint32_t elementsNums = 20;
410 for (uint32_t i = 0; i < elementsNums; i++) {
411 JSHandle<JSTaggedValue> value(thread, JSTaggedValue(i));
412 JSAPIVector::Add(thread, toor, value);
413 }
414
415 // test RemoveByRange exception
416 // toIndex <= fromIndex
417 JSTaggedValue result1 = JSAPIVector::RemoveByRange(thread, toor, 0, 0);
418 EXPECT_EQ(result1, JSTaggedValue::Exception());
419 EXPECT_EXCEPTION();
420
421 // from < 0
422 JSTaggedValue result2 = JSAPIVector::RemoveByRange(thread, toor, -1, 0);
423 EXPECT_EQ(result2, JSTaggedValue::Exception());
424 EXPECT_EXCEPTION();
425
426 // fromIndex >= length
427 JSTaggedValue result3 = JSAPIVector::RemoveByRange(thread, toor, elementsNums, elementsNums * 2);
428 EXPECT_EQ(result3, JSTaggedValue::Exception());
429 EXPECT_EXCEPTION();
430 }
431
432 /**
433 * @tc.name: SubVector
434 * @tc.desc:
435 * @tc.type: FUNC
436 * @tc.require:
437 */
HWTEST_F_L0(JSAPIVectorTest,ExceptionOfSubVector)438 HWTEST_F_L0(JSAPIVectorTest, ExceptionOfSubVector)
439 {
440 JSHandle<JSAPIVector> toor(thread, CreateVector());
441 uint32_t elementsNums = 20;
442 for (uint32_t i = 0; i < elementsNums; i++) {
443 JSHandle<JSTaggedValue> value(thread, JSTaggedValue(i));
444 JSAPIVector::Add(thread, toor, value);
445 }
446
447 // test SubVector exception
448 // from < 0
449 JSAPIVector::SubVector(thread, toor, -1, 0);
450 EXPECT_EXCEPTION();
451
452 // toIndex < 0
453 JSAPIVector::SubVector(thread, toor, 0, -1);
454 EXPECT_EXCEPTION();
455
456 // fromIndex >= length
457 JSAPIVector::SubVector(thread, toor, elementsNums, 0);
458 EXPECT_EXCEPTION();
459
460 // ToIndex >= length
461 JSAPIVector::SubVector(thread, toor, 0, elementsNums);
462 EXPECT_EXCEPTION();
463
464 // toIndex <= fromIndex
465 JSAPIVector::SubVector(thread, toor, elementsNums - 1, 0);
466 EXPECT_EXCEPTION();
467 }
468
469 /**
470 * @tc.name: OwnKeys
471 * @tc.desc:
472 * @tc.type: FUNC
473 * @tc.require:
474 */
HWTEST_F_L0(JSAPIVectorTest,OwnKeys)475 HWTEST_F_L0(JSAPIVectorTest, OwnKeys)
476 {
477 JSHandle<JSAPIVector> toor(thread, CreateVector());
478 uint32_t elementsNums = 8;
479 for (uint32_t i = 0; i < elementsNums; i++) {
480 JSHandle<JSTaggedValue> value(thread, JSTaggedValue(i));
481 JSAPIVector::Add(thread, toor, value);
482 }
483 JSHandle<TaggedArray> keyArray = JSAPIVector::OwnKeys(thread, toor);
484 EXPECT_TRUE(keyArray->GetClass()->IsTaggedArray());
485 EXPECT_TRUE(keyArray->GetLength() == elementsNums);
486 for (uint32_t i = 0; i < elementsNums; i++) {
487 ASSERT_TRUE(EcmaStringAccessor::StringsAreEqual(
488 *(base::NumberHelper::NumberToString(thread, JSTaggedValue(i))),
489 EcmaString::Cast(keyArray->Get(i).GetTaggedObject())
490 ));
491 }
492 }
493
494 /**
495 * @tc.name: GetFirstElement
496 * @tc.desc:
497 * @tc.type: FUNC
498 * @tc.require:
499 */
HWTEST_F_L0(JSAPIVectorTest,GetFirstElement)500 HWTEST_F_L0(JSAPIVectorTest, GetFirstElement)
501 {
502 JSHandle<JSAPIVector> toor(thread, CreateVector());
503 EXPECT_EQ(JSAPIVector::GetFirstElement(toor), JSTaggedValue::Undefined());
504
505 uint32_t elementsNums = 8;
506 for (uint32_t i = 0; i < elementsNums; i++) {
507 JSHandle<JSTaggedValue> value(thread, JSTaggedValue(i));
508 JSAPIVector::Add(thread, toor, value);
509 }
510 EXPECT_EQ(JSAPIVector::GetFirstElement(toor), JSTaggedValue(0));
511 }
512 } // namespace panda::test
513