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
17 #include "ecmascript/containers/containers_arraylist.h"
18 #include "ecmascript/containers/containers_private.h"
19 #include "ecmascript/ecma_runtime_call_info.h"
20 #include "ecmascript/global_env.h"
21 #include "ecmascript/js_api/js_api_arraylist.h"
22 #include "ecmascript/js_api/js_api_arraylist_iterator.h"
23 #include "ecmascript/js_handle.h"
24 #include "ecmascript/js_tagged_value-inl.h"
25 #include "ecmascript/js_thread.h"
26 #include "ecmascript/object_factory.h"
27 #include "ecmascript/tests/test_helper.h"
28 #include "ecmascript/containers/tests/containers_test_helper.h"
29
30 using namespace panda::ecmascript;
31 using namespace panda::ecmascript::containers;
32
33 namespace panda::test {
34 class ContainersArrayListTest : public testing::Test {
35 public:
SetUpTestCase()36 static void SetUpTestCase()
37 {
38 GTEST_LOG_(INFO) << "SetUpTestCase";
39 }
40
TearDownTestCase()41 static void TearDownTestCase()
42 {
43 GTEST_LOG_(INFO) << "TearDownCase";
44 }
45
SetUp()46 void SetUp() override
47 {
48 TestHelper::CreateEcmaVMWithScope(instance, thread, scope);
49 }
50
TearDown()51 void TearDown() override
52 {
53 TestHelper::DestroyEcmaVMWithScope(instance, scope);
54 }
55
56 EcmaVM *instance {nullptr};
57 EcmaHandleScope *scope {nullptr};
58 JSThread *thread {nullptr};
59
60 class TestClass : public base::BuiltinsBase {
61 public:
TestForEachFunc(EcmaRuntimeCallInfo * argv)62 static JSTaggedValue TestForEachFunc(EcmaRuntimeCallInfo *argv)
63 {
64 JSHandle<JSTaggedValue> value = GetCallArg(argv, 0);
65 JSHandle<JSTaggedValue> arrayList = GetCallArg(argv, 1);
66 if (!arrayList->IsUndefined()) {
67 if (value->IsNumber()) {
68 TaggedArray *elements = TaggedArray::Cast(JSAPIArrayList::Cast(arrayList.GetTaggedValue().
69 GetTaggedObject())->GetElements().GetTaggedObject());
70 JSTaggedValue result = elements->Get(value->GetInt());
71 EXPECT_EQ(result, value.GetTaggedValue());
72 }
73 }
74 return JSTaggedValue::True();
75 }
76 };
77 protected:
InitializeArrayListConstructor()78 JSTaggedValue InitializeArrayListConstructor()
79 {
80 ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
81 JSHandle<GlobalEnv> env = thread->GetEcmaVM()->GetGlobalEnv();
82 JSHandle<JSTaggedValue> globalObject = env->GetJSGlobalObject();
83 JSHandle<JSTaggedValue> key(factory->NewFromASCII("ArkPrivate"));
84 JSHandle<JSTaggedValue> value =
85 JSObject::GetProperty(thread, JSHandle<JSTaggedValue>(globalObject), key).GetValue();
86 auto objCallInfo =
87 TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), 6); // 6 means the value
88 objCallInfo->SetFunction(JSTaggedValue::Undefined());
89 objCallInfo->SetThis(value.GetTaggedValue());
90 objCallInfo->SetCallArg(
91 0, JSTaggedValue(static_cast<int>(ContainerTag::ArrayList))); // 0 means the argument
92 [[maybe_unused]] auto prev = TestHelper::SetupFrame(thread, objCallInfo);
93 JSTaggedValue result = ContainersPrivate::Load(objCallInfo);
94 TestHelper::TearDownFrame(thread, prev);
95
96 return result;
97 }
98
CreateJSAPIArrayList()99 JSHandle<JSAPIArrayList> CreateJSAPIArrayList()
100 {
101 JSHandle<JSFunction> newTarget(thread, InitializeArrayListConstructor());
102 auto objCallInfo =
103 TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), 4); // 4 means the value
104 objCallInfo->SetFunction(newTarget.GetTaggedValue());
105 objCallInfo->SetNewTarget(newTarget.GetTaggedValue());
106 objCallInfo->SetThis(JSTaggedValue::Undefined());
107
108 [[maybe_unused]] auto prev = TestHelper::SetupFrame(thread, objCallInfo);
109 JSTaggedValue result = ContainersArrayList::ArrayListConstructor(objCallInfo);
110 TestHelper::TearDownFrame(thread, prev);
111 JSHandle<JSAPIArrayList> ArrayList(thread, result);
112 return ArrayList;
113 }
114
ArrayListAdd(JSHandle<JSAPIArrayList> arrayList,JSTaggedValue value)115 JSTaggedValue ArrayListAdd(JSHandle<JSAPIArrayList> arrayList, JSTaggedValue value)
116 {
117 auto callInfo =
118 TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), 6); // 4 means the value
119 callInfo->SetFunction(JSTaggedValue::Undefined());
120 callInfo->SetThis(arrayList.GetTaggedValue());
121 callInfo->SetCallArg(0, value);
122
123 [[maybe_unused]] auto prev = TestHelper::SetupFrame(thread, callInfo);
124 JSTaggedValue result = ContainersArrayList::Add(callInfo);
125 TestHelper::TearDownFrame(thread, prev);
126 return result;
127 }
128
ArrayListRemoveByRange(JSHandle<JSAPIArrayList> arrayList,JSTaggedValue startIndex,JSTaggedValue endIndex)129 JSTaggedValue ArrayListRemoveByRange(JSHandle<JSAPIArrayList> arrayList, JSTaggedValue startIndex,
130 JSTaggedValue endIndex)
131 {
132 auto callInfo =
133 TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), 8); // 6 means the value
134 callInfo->SetFunction(JSTaggedValue::Undefined());
135 callInfo->SetThis(arrayList.GetTaggedValue());
136 callInfo->SetCallArg(0, startIndex);
137 callInfo->SetCallArg(1, endIndex);
138
139 [[maybe_unused]] auto prev = TestHelper::SetupFrame(thread, callInfo);
140 JSTaggedValue result = ContainersArrayList::RemoveByRange(callInfo);
141 TestHelper::TearDownFrame(thread, prev);
142 return result;
143 }
144
ArrayListSubArrayList(JSHandle<JSAPIArrayList> arrayList,JSTaggedValue startIndex,JSTaggedValue endIndex)145 JSTaggedValue ArrayListSubArrayList(JSHandle<JSAPIArrayList> arrayList, JSTaggedValue startIndex,
146 JSTaggedValue endIndex)
147 {
148 auto callInfo =
149 TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), 8); // 8 means the value
150 callInfo->SetFunction(JSTaggedValue::Undefined());
151 callInfo->SetThis(arrayList.GetTaggedValue());
152 callInfo->SetCallArg(0, startIndex);
153 callInfo->SetCallArg(1, endIndex);
154
155 [[maybe_unused]] auto prev = TestHelper::SetupFrame(thread, callInfo);
156 JSTaggedValue result = ContainersArrayList::SubArrayList(callInfo);
157 TestHelper::TearDownFrame(thread, prev);
158 return result;
159 }
160 };
161
HWTEST_F_L0(ContainersArrayListTest,ArrayListConstructor)162 HWTEST_F_L0(ContainersArrayListTest, ArrayListConstructor)
163 {
164 InitializeArrayListConstructor();
165 JSHandle<JSFunction> newTarget(thread, InitializeArrayListConstructor());
166 auto objCallInfo =
167 TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), 4); // 4 means the value
168 objCallInfo->SetFunction(newTarget.GetTaggedValue());
169 objCallInfo->SetNewTarget(newTarget.GetTaggedValue());
170 objCallInfo->SetThis(JSTaggedValue::Undefined());
171
172 [[maybe_unused]] auto prev = TestHelper::SetupFrame(thread, objCallInfo);
173 JSTaggedValue result = ContainersArrayList::ArrayListConstructor(objCallInfo);
174 TestHelper::TearDownFrame(thread, prev);
175
176 ASSERT_TRUE(result.IsJSAPIArrayList());
177 JSHandle<JSAPIArrayList> arrayList(thread, result);
178 JSTaggedValue resultProto = JSObject::GetPrototype(JSHandle<JSObject>::Cast(arrayList));
179 JSTaggedValue funcProto = newTarget->GetFunctionPrototype();
180 ASSERT_EQ(resultProto, funcProto);
181 int length = arrayList->GetLength().GetInt();
182 ASSERT_EQ(length, 0); // 0 means the value
183
184 // test ArrayListConstructor exception
185 objCallInfo->SetNewTarget(JSTaggedValue::Undefined());
186 CONTAINERS_API_EXCEPTION_TEST(ContainersArrayList, ArrayListConstructor, objCallInfo);
187 }
188
HWTEST_F_L0(ContainersArrayListTest,RemoveByRange)189 HWTEST_F_L0(ContainersArrayListTest, RemoveByRange)
190 {
191 constexpr uint32_t NODE_NUMBERS = 8;
192 JSHandle<JSAPIArrayList> arrayList = CreateJSAPIArrayList();
193 for (uint32_t i = 0; i < NODE_NUMBERS; i++) {
194 JSTaggedValue result = ArrayListAdd(arrayList, JSTaggedValue(i));
195 EXPECT_EQ(result, JSTaggedValue::True());
196 EXPECT_EQ(arrayList->GetSize(), static_cast<int>(i + 1));
197 }
198
199 // remove success
200 {
201 JSTaggedValue result = ArrayListRemoveByRange(arrayList, JSTaggedValue(1), JSTaggedValue(3));
202 EXPECT_EQ(result, JSTaggedValue::Undefined());
203 EXPECT_EQ(arrayList->GetSize(), static_cast<int>(NODE_NUMBERS - 2));
204 for (uint32_t i = 0; i < NODE_NUMBERS - 2; i++) {
205 if (i < 1) {
206 EXPECT_EQ(arrayList->Get(thread, i), JSTaggedValue(i));
207 } else {
208 EXPECT_EQ(arrayList->Get(thread, i), JSTaggedValue(i + 2));
209 }
210 }
211 }
212
213 // input startIndex type error
214 {
215 JSTaggedValue result = ArrayListRemoveByRange(arrayList, JSTaggedValue::Undefined(), JSTaggedValue(3));
216 EXPECT_TRUE(thread->HasPendingException());
217 EXPECT_EQ(result, JSTaggedValue::Exception());
218 thread->ClearException();
219 }
220
221 // input endIndex type error
222 {
223 JSTaggedValue result = ArrayListRemoveByRange(arrayList, JSTaggedValue(1), JSTaggedValue::Undefined());
224 EXPECT_TRUE(thread->HasPendingException());
225 EXPECT_EQ(result, JSTaggedValue::Exception());
226 thread->ClearException();
227 }
228 }
229
HWTEST_F_L0(ContainersArrayListTest,SubArrayList)230 HWTEST_F_L0(ContainersArrayListTest, SubArrayList)
231 {
232 constexpr uint32_t NODE_NUMBERS = 8;
233 JSHandle<JSAPIArrayList> arrayList = CreateJSAPIArrayList();
234 for (uint32_t i = 0; i < NODE_NUMBERS; i++) {
235 JSTaggedValue result = ArrayListAdd(arrayList, JSTaggedValue(i));
236 EXPECT_EQ(result, JSTaggedValue::True());
237 EXPECT_EQ(arrayList->GetSize(), static_cast<int>(i + 1));
238 }
239
240 // input startIndex type error
241 {
242 JSTaggedValue result = ArrayListSubArrayList(arrayList, JSTaggedValue::Undefined(), JSTaggedValue(2));
243 EXPECT_TRUE(thread->HasPendingException());
244 EXPECT_EQ(result, JSTaggedValue::Exception());
245 thread->ClearException();
246 }
247
248 // input endIndex type error
249 {
250 JSTaggedValue result = ArrayListSubArrayList(arrayList, JSTaggedValue(2), JSTaggedValue::Undefined());
251 EXPECT_TRUE(thread->HasPendingException());
252 EXPECT_EQ(result, JSTaggedValue::Exception());
253 thread->ClearException();
254 }
255
256 // success
257 {
258 JSTaggedValue newArrayList = ArrayListSubArrayList(arrayList, JSTaggedValue(1), JSTaggedValue(3));
259 JSHandle<TaggedArray> elements(thread, JSAPIArrayList::Cast(newArrayList.GetTaggedObject())->GetElements());
260 EXPECT_EQ(elements->GetLength(), static_cast<uint32_t>(2)); // length = 3 - 1
261 EXPECT_EQ(elements->Get(thread, 0), JSTaggedValue(1));
262 EXPECT_EQ(elements->Get(thread, 1), JSTaggedValue(2));
263 }
264 }
265
HWTEST_F_L0(ContainersArrayListTest,GetAndSet)266 HWTEST_F_L0(ContainersArrayListTest, GetAndSet)
267 {
268 constexpr uint32_t NODE_NUMBERS = 8;
269 JSHandle<JSAPIArrayList> arrayList = CreateJSAPIArrayList();
270 auto callInfo = TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), 8);
271 callInfo->SetFunction(JSTaggedValue::Undefined());
272 callInfo->SetThis(arrayList.GetTaggedValue());
273
274 for (uint32_t i = 0; i < NODE_NUMBERS; i++) {
275 callInfo->SetCallArg(0, JSTaggedValue(i));
276 [[maybe_unused]] auto prev = TestHelper::SetupFrame(thread, callInfo);
277 ContainersArrayList::Add(callInfo);
278 TestHelper::TearDownFrame(thread, prev);
279 }
280 for (uint32_t i = 0; i < NODE_NUMBERS; i++) {
281 callInfo->SetCallArg(0, JSTaggedValue(i));
282 [[maybe_unused]] auto prev = TestHelper::SetupFrame(thread, callInfo);
283 JSTaggedValue retult = ContainersArrayList::Get(callInfo);
284 TestHelper::TearDownFrame(thread, prev);
285 EXPECT_EQ(retult, JSTaggedValue(i));
286 }
287
288 for (uint32_t i = 0; i < NODE_NUMBERS; i++) {
289 callInfo->SetCallArg(0, JSTaggedValue(i));
290 callInfo->SetCallArg(1, JSTaggedValue(-i - 1));
291 [[maybe_unused]] auto prev = TestHelper::SetupFrame(thread, callInfo);
292 ContainersArrayList::Set(callInfo);
293 TestHelper::TearDownFrame(thread, prev);
294 }
295 for (uint32_t i = 0; i < NODE_NUMBERS; i++) {
296 callInfo->SetCallArg(0, JSTaggedValue(i));
297 [[maybe_unused]] auto prev = TestHelper::SetupFrame(thread, callInfo);
298 JSTaggedValue retult = ContainersArrayList::Get(callInfo);
299 TestHelper::TearDownFrame(thread, prev);
300 EXPECT_EQ(retult, JSTaggedValue(-i - 1));
301 }
302 }
303
HWTEST_F_L0(ContainersArrayListTest,ProxyOfGetSetAndGetSize)304 HWTEST_F_L0(ContainersArrayListTest, ProxyOfGetSetAndGetSize)
305 {
306 constexpr uint32_t NODE_NUMBERS = 8;
307 JSHandle<JSAPIArrayList> proxyArrayList = CreateJSAPIArrayList();
308 auto callInfo = TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), 8);
309 callInfo->SetFunction(JSTaggedValue::Undefined());
310 JSHandle<JSProxy> proxy = CreateJSProxyHandle(thread);
311 proxy->SetTarget(thread, proxyArrayList.GetTaggedValue());
312 callInfo->SetThis(proxy.GetTaggedValue());
313
314 // ArrayList proxy GetSize
315 for (uint32_t i = 0; i < NODE_NUMBERS; i++) {
316 callInfo->SetCallArg(0, JSTaggedValue(i));
317 [[maybe_unused]] auto prev = TestHelper::SetupFrame(thread, callInfo);
318 ContainersArrayList::Add(callInfo);
319 TestHelper::TearDownFrame(thread, prev);
320
321 [[maybe_unused]] auto prev1 = TestHelper::SetupFrame(thread, callInfo);
322 JSTaggedValue retult = ContainersArrayList::GetSize(callInfo);
323 TestHelper::TearDownFrame(thread, prev1);
324 EXPECT_EQ(retult, JSTaggedValue(i + 1));
325 }
326
327 // ArrayList proxy Set
328 for (uint32_t i = 0; i < NODE_NUMBERS; i++) {
329 callInfo->SetCallArg(0, JSTaggedValue(i));
330 callInfo->SetCallArg(1, JSTaggedValue(-i - 1));
331 [[maybe_unused]] auto prev = TestHelper::SetupFrame(thread, callInfo);
332 ContainersArrayList::Set(callInfo);
333 TestHelper::TearDownFrame(thread, prev);
334 }
335 // ArrayList proxy Get and verify
336 for (uint32_t i = 0; i < NODE_NUMBERS; i++) {
337 callInfo->SetCallArg(0, JSTaggedValue(i));
338 [[maybe_unused]] auto prev = TestHelper::SetupFrame(thread, callInfo);
339 JSTaggedValue retult = ContainersArrayList::Get(callInfo);
340 TestHelper::TearDownFrame(thread, prev);
341 EXPECT_EQ(retult, JSTaggedValue(-i - 1));
342 }
343 }
344
HWTEST_F_L0(ContainersArrayListTest,ExceptionReturn1)345 HWTEST_F_L0(ContainersArrayListTest, ExceptionReturn1)
346 {
347 CONTAINERS_API_TYPE_MISMATCH_EXCEPTION_TEST(ContainersArrayList, Insert);
348 CONTAINERS_API_TYPE_MISMATCH_EXCEPTION_TEST(ContainersArrayList, IncreaseCapacityTo);
349 CONTAINERS_API_TYPE_MISMATCH_EXCEPTION_TEST(ContainersArrayList, Add);
350 CONTAINERS_API_TYPE_MISMATCH_EXCEPTION_TEST(ContainersArrayList, Clear);
351 CONTAINERS_API_TYPE_MISMATCH_EXCEPTION_TEST(ContainersArrayList, Clone);
352 CONTAINERS_API_TYPE_MISMATCH_EXCEPTION_TEST(ContainersArrayList, Has);
353 CONTAINERS_API_TYPE_MISMATCH_EXCEPTION_TEST(ContainersArrayList, GetCapacity);
354 CONTAINERS_API_TYPE_MISMATCH_EXCEPTION_TEST(ContainersArrayList, TrimToCurrentLength);
355 CONTAINERS_API_TYPE_MISMATCH_EXCEPTION_TEST(ContainersArrayList, Get);
356
357 JSHandle<JSAPIArrayList> arrayList = CreateJSAPIArrayList();
358 {
359 auto callInfo = NewEmptyCallInfo(thread);
360 callInfo->SetThis(arrayList.GetTaggedValue());
361 CONTAINERS_API_EXCEPTION_TEST(ContainersArrayList, Insert, callInfo);
362 }
363 {
364 auto callInfo = NewEmptyCallInfo(thread);
365 callInfo->SetThis(arrayList.GetTaggedValue());
366 CONTAINERS_API_EXCEPTION_TEST(ContainersArrayList, IncreaseCapacityTo, callInfo);
367 }
368 }
369
HWTEST_F_L0(ContainersArrayListTest,ExceptionReturn2)370 HWTEST_F_L0(ContainersArrayListTest, ExceptionReturn2)
371 {
372 CONTAINERS_API_TYPE_MISMATCH_EXCEPTION_TEST(ContainersArrayList, RemoveByIndex);
373 CONTAINERS_API_TYPE_MISMATCH_EXCEPTION_TEST(ContainersArrayList, ReplaceAllElements);
374 CONTAINERS_API_TYPE_MISMATCH_EXCEPTION_TEST(ContainersArrayList, GetIndexOf);
375 CONTAINERS_API_TYPE_MISMATCH_EXCEPTION_TEST(ContainersArrayList, IsEmpty);
376 CONTAINERS_API_TYPE_MISMATCH_EXCEPTION_TEST(ContainersArrayList, GetLastIndexOf);
377 CONTAINERS_API_TYPE_MISMATCH_EXCEPTION_TEST(ContainersArrayList, Remove);
378 CONTAINERS_API_TYPE_MISMATCH_EXCEPTION_TEST(ContainersArrayList, RemoveByRange);
379
380 JSHandle<JSAPIArrayList> arrayList = CreateJSAPIArrayList();
381 {
382 auto callInfo = NewEmptyCallInfo(thread);
383 callInfo->SetThis(arrayList.GetTaggedValue());
384 CONTAINERS_API_EXCEPTION_TEST(ContainersArrayList, RemoveByIndex, callInfo);
385 }
386 {
387 auto callInfo = NewEmptyCallInfo(thread);
388 callInfo->SetThis(arrayList.GetTaggedValue());
389 CONTAINERS_API_EXCEPTION_TEST(ContainersArrayList, ReplaceAllElements, callInfo);
390 }
391 }
392
HWTEST_F_L0(ContainersArrayListTest,ExceptionReturn3)393 HWTEST_F_L0(ContainersArrayListTest, ExceptionReturn3)
394 {
395 CONTAINERS_API_TYPE_MISMATCH_EXCEPTION_TEST(ContainersArrayList, Sort);
396 CONTAINERS_API_TYPE_MISMATCH_EXCEPTION_TEST(ContainersArrayList, Set);
397 CONTAINERS_API_TYPE_MISMATCH_EXCEPTION_TEST(ContainersArrayList, SubArrayList);
398 CONTAINERS_API_TYPE_MISMATCH_EXCEPTION_TEST(ContainersArrayList, GetSize);
399 CONTAINERS_API_TYPE_MISMATCH_EXCEPTION_TEST(ContainersArrayList, ConvertToArray);
400 CONTAINERS_API_TYPE_MISMATCH_EXCEPTION_TEST(ContainersArrayList, ForEach);
401 CONTAINERS_API_TYPE_MISMATCH_EXCEPTION_TEST(ContainersArrayList, GetIteratorObj);
402
403 JSHandle<JSAPIArrayList> arrayList = CreateJSAPIArrayList();
404 {
405 auto callInfo = NewEmptyCallInfo(thread);
406 callInfo->SetThis(arrayList.GetTaggedValue());
407 CONTAINERS_API_EXCEPTION_TEST(ContainersArrayList, Sort, callInfo);
408 }
409 }
410 } // namespace panda::test
411