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/js_stable_array.h"
17 #include "ecmascript/tests/test_helper.h"
18
19 using namespace panda;
20 using namespace panda::ecmascript;
21
22 namespace panda::test {
23 class JSStableArrayTest : public testing::Test {
24 public:
SetUpTestCase()25 static void SetUpTestCase()
26 {
27 GTEST_LOG_(INFO) << "SetUpTestCase";
28 }
29
TearDownTestCase()30 static void TearDownTestCase()
31 {
32 GTEST_LOG_(INFO) << "TearDownCase";
33 }
34
SetUp()35 void SetUp() override
36 {
37 TestHelper::CreateEcmaVMWithScope(instance, thread, scope);
38 }
39
TearDown()40 void TearDown() override
41 {
42 TestHelper::DestroyEcmaVMWithScope(instance, scope);
43 }
44
45 EcmaVM *instance {nullptr};
46 EcmaHandleScope *scope {nullptr};
47 JSThread *thread {nullptr};
48 };
49
50 /**
51 * @tc.name: Push
52 * @tc.desc: Change a JSArray through calling Push function with the JSArray and a EcmaRuntimeCallInfo, check whether
53 * the TaggedArray of the JSArray is within expectations.
54 * @tc.type: FUNC
55 * @tc.require:
56 */
HWTEST_F_L0(JSStableArrayTest,Push)57 HWTEST_F_L0(JSStableArrayTest, Push)
58 {
59 int32_t lengthArr = 99;
60 int32_t numElementsPush = 9;
61 JSHandle<JSTaggedValue> handleTagValArr = JSArray::ArrayCreate(thread, JSTaggedNumber(lengthArr));
62 JSHandle<JSArray> handleArr(handleTagValArr);
63
64 auto ecmaRuntimeCallInfo =
65 TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), 4 + 2 * numElementsPush);
66 ecmaRuntimeCallInfo->SetFunction(JSTaggedValue::Undefined());
67 ecmaRuntimeCallInfo->SetThis(JSTaggedValue::Undefined());
68 for (int32_t i = 0; i < numElementsPush; i++) {
69 ecmaRuntimeCallInfo->SetCallArg(i, JSTaggedValue(i));
70 }
71 [[maybe_unused]] auto prev = TestHelper::SetupFrame(thread, ecmaRuntimeCallInfo);
72 EXPECT_EQ(JSStableArray::Push(handleArr, ecmaRuntimeCallInfo),
73 JSTaggedValue(lengthArr + numElementsPush));
74 TestHelper::TearDownFrame(thread, prev);
75
76 JSHandle<TaggedArray> handleTagArr(thread, TaggedArray::Cast(handleArr->GetElements().GetTaggedObject()));
77 EXPECT_EQ(handleArr->GetArrayLength(), static_cast<size_t>(lengthArr + numElementsPush));
78 for (int32_t i = lengthArr; i < lengthArr + numElementsPush; i++) {
79 EXPECT_EQ(handleTagArr->Get(i).GetNumber(), i - lengthArr);
80 }
81 }
82
83 /**
84 * @tc.name: Pop
85 * @tc.desc: Change a JSArray through calling Pop function with the JSArray and a EcmaRuntimeCallInfo, check whether
86 * the JSArray and the TaggedArray of the JSArray are within expectations.
87 * @tc.type: FUNC
88 * @tc.require:
89 */
HWTEST_F_L0(JSStableArrayTest,Pop)90 HWTEST_F_L0(JSStableArrayTest, Pop)
91 {
92 ObjectFactory *objFactory = thread->GetEcmaVM()->GetFactory();
93
94 int32_t lengthArr = 49;
95 JSHandle<TaggedArray> handleTagArr(objFactory->NewTaggedArray(lengthArr));
96 for (int i = 0; i < lengthArr; i++) {
97 handleTagArr->Set(thread, i, JSTaggedValue(i));
98 }
99 JSHandle<JSArray> handleArr(JSArray::CreateArrayFromList(thread, handleTagArr));
100
101 for (int32_t i = 1; i < 6; i++) {
102 auto ecmaRuntimeCallInfo = TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), 4);
103 ecmaRuntimeCallInfo->SetFunction(JSTaggedValue::Undefined());
104 ecmaRuntimeCallInfo->SetThis(JSTaggedValue::Undefined());
105 [[maybe_unused]] auto prev = TestHelper::SetupFrame(thread, ecmaRuntimeCallInfo);
106 EXPECT_EQ(JSStableArray::Pop(handleArr, ecmaRuntimeCallInfo), JSTaggedValue(lengthArr - i));
107 TestHelper::TearDownFrame(thread, prev);
108
109 EXPECT_EQ(handleArr->GetArrayLength(), static_cast<uint32_t>(lengthArr - i));
110 if (i != 5) {
111 EXPECT_EQ(handleTagArr->GetLength(), static_cast<uint32_t>(lengthArr));
112 EXPECT_EQ(handleTagArr->Get(lengthArr - i), JSTaggedValue::Hole());
113 } else {
114 EXPECT_EQ(handleTagArr->GetLength(), static_cast<uint32_t>(lengthArr - i));
115 }
116 }
117 }
118
119 /**
120 * @tc.name: Splice
121 * @tc.desc: Create a source TaggedArray, set value for the elements of the source TaggedArray, create an source Array
122 * through calling CreateArrayFromList function with the source TaggedArray, create a deleted Array through
123 * calling Splice function with the source Array, an EcmaRuntimeCallInfo that set Args from 2 as the
124 * delete-elements, the offsetStartInsert, the countInsert and the actualDeleteCount. Check whether the
125 * deleted Array and the source Array after change are within expectations.
126 * @tc.type: FUNC
127 * @tc.require:
128 */
HWTEST_F_L0(JSStableArrayTest,Splice)129 HWTEST_F_L0(JSStableArrayTest, Splice)
130 {
131 ObjectFactory *objFactory = thread->GetEcmaVM()->GetFactory();
132
133 int32_t lengthArr = 49;
134
135 JSHandle<JSTaggedValue> handleTagValInsertElement1(thread, JSTaggedValue(4000));
136 JSHandle<JSTaggedValue> handleTagValInsertElement2(thread, JSTaggedValue(4100));
137 JSHandle<TaggedArray> handleTagArr(objFactory->NewTaggedArray(lengthArr));
138 for (int i = 0; i < lengthArr; i++) {
139 handleTagArr->Set(thread, i, JSTaggedValue(i * 10));
140 }
141 JSHandle<JSArray> handleArr(JSArray::CreateArrayFromList(thread, handleTagArr));
142 double offsetStartInsert = 40;
143 double actualDeleteCount = 3;
144 double countInsert = 2;
145
146 auto ecmaRuntimeCallInfo = TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(),
147 4 + (2 + countInsert) * 2);
148 ecmaRuntimeCallInfo->SetFunction(JSTaggedValue::Undefined());
149 ecmaRuntimeCallInfo->SetThis(JSTaggedValue::Undefined());
150 ecmaRuntimeCallInfo->SetCallArg(2, handleTagValInsertElement1.GetTaggedValue());
151 ecmaRuntimeCallInfo->SetCallArg(3, handleTagValInsertElement2.GetTaggedValue());
152
153 [[maybe_unused]] auto prev = TestHelper::SetupFrame(thread, ecmaRuntimeCallInfo);
154 JSHandle<JSTaggedValue> handleTagValArrCombinedOfDeletedElements(thread,
155 JSStableArray::Splice(handleArr, ecmaRuntimeCallInfo, offsetStartInsert, countInsert,
156 actualDeleteCount));
157 TestHelper::TearDownFrame(thread, prev);
158 JSHandle<JSArray> handleArrCombinedOfDeletedElements(handleTagValArrCombinedOfDeletedElements);
159 EXPECT_EQ(handleArrCombinedOfDeletedElements->GetArrayLength(), actualDeleteCount);
160 JSHandle<JSObject> handleObjArrCombinedOfDeletedElements(handleTagValArrCombinedOfDeletedElements);
161 JSHandle<JSTaggedValue> handleTagValTagArrCombinedOfDeletedElements(thread,
162 handleObjArrCombinedOfDeletedElements->GetElements());
163 JSHandle<TaggedArray> handleTagArrCombinedOfDeletedElements(handleTagValTagArrCombinedOfDeletedElements);
164 for (int32_t i = 0; i < actualDeleteCount; i++) {
165 EXPECT_EQ(handleTagArrCombinedOfDeletedElements->Get(i).GetNumber(), (offsetStartInsert + i) * 10);
166 }
167
168 // Check the JSArray(in-out-parameter) changed through calling the Splice function.
169 EXPECT_EQ(handleArr->GetArrayLength(), lengthArr - actualDeleteCount + countInsert);
170 for (int32_t i = 0; i < offsetStartInsert; i++) {
171 EXPECT_EQ(handleTagArr->Get(i).GetNumber(), i * 10);
172 }
173 EXPECT_EQ(handleTagArr->Get(offsetStartInsert).GetNumber(),
174 handleTagValInsertElement1.GetTaggedValue().GetNumber());
175 EXPECT_EQ(handleTagArr->Get(offsetStartInsert + 1).GetNumber(),
176 handleTagValInsertElement2.GetTaggedValue().GetNumber());
177 for (int32_t i = offsetStartInsert + countInsert; i < lengthArr - actualDeleteCount + countInsert; i++) {
178 EXPECT_EQ(handleTagArr->Get(i).GetNumber(), (i + actualDeleteCount - countInsert) * 10);
179 }
180 }
181
182 /**
183 * @tc.name: Shift
184 * @tc.desc: Create a source Array, set value for the elements of the source Array, call the Shift function with the
185 * source Array 5 times, check whether the returned JSTaggedValue and the changed source Array are within
186 * expectations after each call to the Shift function.
187 * @tc.type: FUNC
188 * @tc.require:
189 */
HWTEST_F_L0(JSStableArrayTest,Shift)190 HWTEST_F_L0(JSStableArrayTest, Shift)
191 {
192 ObjectFactory *objFactory = thread->GetEcmaVM()->GetFactory();
193
194 int32_t lengthArr = 49;
195 JSHandle<TaggedArray> handleTagArr(objFactory->NewTaggedArray(lengthArr));
196 for (int i = 0; i < lengthArr; i++) {
197 handleTagArr->Set(thread, i, JSTaggedValue(i * 10));
198 }
199 JSHandle<JSArray> handleArr(JSArray::CreateArrayFromList(thread, handleTagArr));
200
201 for (int32_t i = 0; i < 5; i++) {
202 auto ecmaRuntimeCallInfo = TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), 4);
203 ecmaRuntimeCallInfo->SetFunction(JSTaggedValue::Undefined());
204 ecmaRuntimeCallInfo->SetThis(JSTaggedValue::Undefined());
205 [[maybe_unused]] auto prev = TestHelper::SetupFrame(thread, ecmaRuntimeCallInfo);
206 EXPECT_EQ(JSStableArray::Shift(handleArr, ecmaRuntimeCallInfo), JSTaggedValue(i * 10));
207 TestHelper::TearDownFrame(thread, prev);
208 EXPECT_EQ(handleArr->GetArrayLength(), static_cast<uint32_t>(lengthArr - (i + 1)));
209 EXPECT_EQ(handleTagArr->Get(0), JSTaggedValue((i + 1) * 10));
210 if (i != 4) {
211 EXPECT_EQ(handleTagArr->GetLength(), static_cast<uint32_t>(lengthArr));
212 EXPECT_EQ(handleTagArr->Get(lengthArr - (i + 1)), JSTaggedValue::Hole());
213 continue;
214 }
215 EXPECT_EQ(handleTagArr->GetLength(), static_cast<uint32_t>(lengthArr - (i + 1)));
216 }
217 }
218
219 /**
220 * @tc.name: Join_NumberElements_UndefinedSep
221 * @tc.desc: Create a source Array whose elements are Numbers and an EcmaRuntimeCallInfo, check whether the EcmaString
222 * returned through calling Join function with the source Array and the EcmaRuntimeCallInfo is within
223 * expectations.
224 * @tc.type: FUNC
225 * @tc.require:
226 */
HWTEST_F_L0(JSStableArrayTest,Join_NumberElements_UndefinedSep)227 HWTEST_F_L0(JSStableArrayTest, Join_NumberElements_UndefinedSep)
228 {
229 ObjectFactory *objFactory = thread->GetEcmaVM()->GetFactory();
230
231 int32_t lengthArr = 10;
232 JSHandle<TaggedArray> handleTagArr(objFactory->NewTaggedArray(lengthArr));
233 for (int i = 0; i < lengthArr; i++) {
234 handleTagArr->Set(thread, i, JSTaggedValue(i));
235 }
236 JSHandle<JSArray> handleArr(JSArray::CreateArrayFromList(thread, handleTagArr));
237 auto ecmaRuntimeCallInfo = TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), 4);
238 ecmaRuntimeCallInfo->SetFunction(JSTaggedValue::Undefined());
239 ecmaRuntimeCallInfo->SetThis(JSTaggedValue::Undefined());
240 [[maybe_unused]] auto prev = TestHelper::SetupFrame(thread, ecmaRuntimeCallInfo);
241 JSHandle<JSTaggedValue> handleTagValEcmaStrRet(thread,
242 JSStableArray::Join(handleArr, ecmaRuntimeCallInfo));
243 TestHelper::TearDownFrame(thread, prev);
244
245 JSHandle<EcmaString> handleEcmaStrRet(handleTagValEcmaStrRet);
246 EXPECT_STREQ(EcmaStringAccessor(handleEcmaStrRet).ToCString().c_str(), "0,1,2,3,4,5,6,7,8,9");
247 }
248
249 /**
250 * @tc.name: Join_StringElements_UndefinedSep
251 * @tc.desc: Create a source Array whose elements are EcmaStrings and an EcmaRuntimeCallInfo, check whether the
252 * EcmaString returned through calling Join function with the source Array and the EcmaRuntimeCallInfo is
253 * within expectations.
254 * @tc.type: FUNC
255 * @tc.require:
256 */
HWTEST_F_L0(JSStableArrayTest,Join_StringElements_UndefinedSep)257 HWTEST_F_L0(JSStableArrayTest, Join_StringElements_UndefinedSep)
258 {
259 ObjectFactory *objFactory = thread->GetEcmaVM()->GetFactory();
260
261 int32_t lengthArr = 10;
262 JSHandle<TaggedArray> handleTagArr(objFactory->NewTaggedArray(lengthArr));
263 JSHandle<JSTaggedValue> handleTagValElementEcmaStr(objFactory->NewFromStdString("abc"));
264 for (int i = 0; i < lengthArr; i++) {
265 handleTagArr->Set(thread, i, handleTagValElementEcmaStr.GetTaggedValue());
266 }
267 JSHandle<JSArray> handleArr(JSArray::CreateArrayFromList(thread, handleTagArr));
268 auto ecmaRuntimeCallInfo = TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), 4);
269 ecmaRuntimeCallInfo->SetFunction(JSTaggedValue::Undefined());
270 ecmaRuntimeCallInfo->SetThis(JSTaggedValue::Undefined());
271 [[maybe_unused]] auto prev = TestHelper::SetupFrame(thread, ecmaRuntimeCallInfo);
272 JSHandle<JSTaggedValue> handleTagValEcmaStrRet(thread,
273 JSStableArray::Join(handleArr, ecmaRuntimeCallInfo));
274 TestHelper::TearDownFrame(thread, prev);
275
276 JSHandle<EcmaString> handleEcmaStrRet(handleTagValEcmaStrRet);
277 EXPECT_STREQ(EcmaStringAccessor(handleEcmaStrRet).ToCString().c_str(), "abc,abc,abc,abc,abc,abc,abc,abc,abc,abc");
278 }
279
280 /**
281 * @tc.name: Join_NumberElements_DefinedSep
282 * @tc.desc: Create a source Array whose elements are Numbers and an EcmaRuntimeCallInfo, define the first arg of the
283 EcmaRuntimeCallInfo an EcmaString as the seperator, check whether the EcmaString returned through calling
284 Join function with the source Array and the EcmaRuntimeCallInfo is within expectations.
285 * @tc.type: FUNC
286 * @tc.require:
287 */
HWTEST_F_L0(JSStableArrayTest,Join_NumberElements_DefinedSep)288 HWTEST_F_L0(JSStableArrayTest, Join_NumberElements_DefinedSep)
289 {
290 ObjectFactory *objFactory = thread->GetEcmaVM()->GetFactory();
291
292 int32_t lengthArr = 10;
293 JSHandle<TaggedArray> handleTagArr(objFactory->NewTaggedArray(lengthArr));
294 for (int i = 0; i < lengthArr; i++) {
295 handleTagArr->Set(thread, i, JSTaggedValue(i));
296 }
297 JSHandle<JSArray> handleArr(JSArray::CreateArrayFromList(thread, handleTagArr));
298 auto ecmaRuntimeCallInfo = TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), 6);
299 ecmaRuntimeCallInfo->SetFunction(JSTaggedValue::Undefined());
300 ecmaRuntimeCallInfo->SetThis(JSTaggedValue::Undefined());
301 ecmaRuntimeCallInfo->SetCallArg(0,
302 JSHandle<JSTaggedValue>::Cast(objFactory->NewFromStdString("^")).GetTaggedValue());
303 [[maybe_unused]] auto prev = TestHelper::SetupFrame(thread, ecmaRuntimeCallInfo);
304 JSHandle<JSTaggedValue> handleTagValEcmaStrRet(thread,
305 JSStableArray::Join(handleArr, ecmaRuntimeCallInfo));
306 TestHelper::TearDownFrame(thread, prev);
307
308 JSHandle<EcmaString> handleEcmaStrRet(handleTagValEcmaStrRet);
309 EXPECT_STREQ(EcmaStringAccessor(handleEcmaStrRet).ToCString().c_str(), "0^1^2^3^4^5^6^7^8^9");
310 }
311
312 /**
313 * @tc.name: Join_StringElements_DefinedSep
314 * @tc.desc: Create a source Array whose elements are EcmaStrings and an EcmaRuntimeCallInfo, define the first arg of
315 the EcmaRuntimeCallInfo an EcmaString as the seperator, check whether the EcmaString returned through
316 calling Join function with the source Array and the EcmaRuntimeCallInfo is within expectations.
317 * @tc.type: FUNC
318 * @tc.require:
319 */
HWTEST_F_L0(JSStableArrayTest,Join_StringElements_DefinedSep)320 HWTEST_F_L0(JSStableArrayTest, Join_StringElements_DefinedSep)
321 {
322 ObjectFactory *objFactory = thread->GetEcmaVM()->GetFactory();
323
324 int32_t lengthArr = 10;
325 JSHandle<TaggedArray> handleTagArr(objFactory->NewTaggedArray(lengthArr));
326 JSHandle<JSTaggedValue> handleTagValElementEcmaStr(objFactory->NewFromStdString("a"));
327 for (int i = 0; i < lengthArr; i++) {
328 handleTagArr->Set(thread, i, handleTagValElementEcmaStr.GetTaggedValue());
329 }
330 JSHandle<JSArray> handleArr(JSArray::CreateArrayFromList(thread, handleTagArr));
331 auto ecmaRuntimeCallInfo = TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), 6);
332 ecmaRuntimeCallInfo->SetFunction(JSTaggedValue::Undefined());
333 ecmaRuntimeCallInfo->SetThis(JSTaggedValue::Undefined());
334 ecmaRuntimeCallInfo->SetCallArg(0,
335 JSHandle<JSTaggedValue>::Cast(objFactory->NewFromStdString(" <> ")).GetTaggedValue());
336 [[maybe_unused]] auto prev = TestHelper::SetupFrame(thread, ecmaRuntimeCallInfo);
337 JSHandle<JSTaggedValue> handleTagValEcmaStrRet(thread,
338 JSStableArray::Join(handleArr, ecmaRuntimeCallInfo));
339 TestHelper::TearDownFrame(thread, prev);
340
341 JSHandle<EcmaString> handleEcmaStrRet(handleTagValEcmaStrRet);
342 EXPECT_STREQ(EcmaStringAccessor(handleEcmaStrRet).ToCString().c_str(),
343 "a <> a <> a <> a <> a <> a <> a <> a <> a <> a");
344 }
345 } // namespace panda::test