• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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