• 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             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