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