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/element_accessor.h"
17 #include "ecmascript/element_accessor-inl.h"
18 #include "ecmascript/js_stable_array.h"
19 #include "ecmascript/tests/test_helper.h"
20
21 using namespace panda;
22 using namespace panda::ecmascript;
23 constexpr uint32_t ARRAY_LENGTH_4 = 4;
24 constexpr int32_t INT_VALUE_0 = 0;
25 constexpr int32_t INT_VALUE_1 = 1;
26 constexpr int32_t INT_VALUE_2 = 2;
27 constexpr int32_t INT_VALUE_3 = 3;
28 constexpr int32_t INT_VALUE_666 = 666;
29
30 enum class StableArrayIndex {
31 STABLE_ARRAY_INDEX_0,
32 STABLE_ARRAY_INDEX_1,
33 STABLE_ARRAY_INDEX_2,
34 STABLE_ARRAY_INDEX_3
35 };
36
37 namespace panda::test {
38 class JSStableArrayTest : public BaseTestWithScope<false> {
39 public:
CallJoin(JSHandle<TaggedArray> handleTagArr,std::string & sep,int64_t lengthArr) const40 JSHandle<JSTaggedValue> CallJoin(JSHandle<TaggedArray> handleTagArr, std::string& sep, int64_t lengthArr) const
41 {
42 ObjectFactory* objFactory = thread->GetEcmaVM()->GetFactory();
43 JSHandle<JSArray> handleArr(JSArray::CreateArrayFromList(thread, handleTagArr));
44 auto ecmaRuntimeCallInfo = TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), 6);
45 ecmaRuntimeCallInfo->SetFunction(JSTaggedValue::Undefined());
46 ecmaRuntimeCallInfo->SetThis(JSTaggedValue::Undefined());
47 ecmaRuntimeCallInfo->SetCallArg(0,
48 JSHandle<JSTaggedValue>::Cast(objFactory->NewFromStdString(sep)).GetTaggedValue());
49 [[maybe_unused]] auto prev = TestHelper::SetupFrame(thread, ecmaRuntimeCallInfo);
50 JSHandle<JSTaggedValue> sepHandle = JSHandle<JSTaggedValue>::Cast(objFactory->NewFromStdString(sep));
51 JSHandle<EcmaString> sepStringHandle = JSTaggedValue::ToString(thread, sepHandle);
52 JSHandle<JSTaggedValue> handleTagValEcmaStrRet(thread,
53 JSStableArray::Join(thread, handleArr, sepStringHandle, lengthArr));
54 TestHelper::TearDownFrame(thread, prev);
55 return handleTagValEcmaStrRet;
56 }
57 };
58
59 /**
60 * @tc.name: Push
61 * @tc.desc: Change a JSArray through calling Push function with the JSArray and a EcmaRuntimeCallInfo, check whether
62 * the TaggedArray of the JSArray is within expectations.
63 * @tc.type: FUNC
64 * @tc.require:
65 */
HWTEST_F_L0(JSStableArrayTest,Push)66 HWTEST_F_L0(JSStableArrayTest, Push)
67 {
68 int32_t lengthArr = 99;
69 int32_t numElementsPush = 9;
70 JSHandle<JSTaggedValue> handleTagValArr = JSArray::ArrayCreate(thread, JSTaggedNumber(lengthArr));
71 JSHandle<JSArray> handleArr(handleTagValArr);
72
73 auto ecmaRuntimeCallInfo =
74 TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), 4 + 2 * numElementsPush);
75 ecmaRuntimeCallInfo->SetFunction(JSTaggedValue::Undefined());
76 ecmaRuntimeCallInfo->SetThis(JSTaggedValue::Undefined());
77 for (int32_t i = 0; i < numElementsPush; i++) {
78 ecmaRuntimeCallInfo->SetCallArg(i, JSTaggedValue(i));
79 }
80 [[maybe_unused]] auto prev = TestHelper::SetupFrame(thread, ecmaRuntimeCallInfo);
81 EXPECT_EQ(JSStableArray::Push(handleArr, ecmaRuntimeCallInfo),
82 JSTaggedValue(lengthArr + numElementsPush));
83 TestHelper::TearDownFrame(thread, prev);
84
85 JSHandle<JSObject> arrObjHandle(handleArr);
86 EXPECT_EQ(handleArr->GetArrayLength(), static_cast<size_t>(lengthArr + numElementsPush));
87 for (int32_t i = lengthArr; i < lengthArr + numElementsPush; i++) {
88 EXPECT_EQ(ElementAccessor::Get(arrObjHandle, i).GetNumber(), i - lengthArr);
89 }
90 }
91
92 /**
93 * @tc.name: Pop
94 * @tc.desc: Change a JSArray through calling Pop function with the JSArray and a EcmaRuntimeCallInfo, check whether
95 * the JSArray and the TaggedArray of the JSArray are within expectations.
96 * @tc.type: FUNC
97 * @tc.require:
98 */
HWTEST_F_L0(JSStableArrayTest,Pop)99 HWTEST_F_L0(JSStableArrayTest, Pop)
100 {
101 ObjectFactory *objFactory = thread->GetEcmaVM()->GetFactory();
102
103 int32_t lengthArr = 49;
104 JSHandle<TaggedArray> handleTagArr(objFactory->NewTaggedArray(lengthArr));
105 for (int i = 0; i < lengthArr; i++) {
106 handleTagArr->Set(thread, i, JSTaggedValue(i));
107 }
108 JSHandle<JSArray> handleArr(JSArray::CreateArrayFromList(thread, handleTagArr));
109
110 for (int32_t i = 1; i < 6; i++) {
111 auto ecmaRuntimeCallInfo = TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), 4);
112 ecmaRuntimeCallInfo->SetFunction(JSTaggedValue::Undefined());
113 ecmaRuntimeCallInfo->SetThis(JSTaggedValue::Undefined());
114 [[maybe_unused]] auto prev = TestHelper::SetupFrame(thread, ecmaRuntimeCallInfo);
115 EXPECT_EQ(JSStableArray::Pop(handleArr, ecmaRuntimeCallInfo), JSTaggedValue(lengthArr - i));
116 TestHelper::TearDownFrame(thread, prev);
117
118 EXPECT_EQ(handleArr->GetArrayLength(), static_cast<uint32_t>(lengthArr - i));
119 if (i != 5) {
120 EXPECT_EQ(handleTagArr->GetLength(), static_cast<uint32_t>(lengthArr));
121 EXPECT_EQ(handleTagArr->Get(lengthArr - i), JSTaggedValue::Hole());
122 } else {
123 EXPECT_EQ(handleTagArr->GetLength(), static_cast<uint32_t>(lengthArr - i));
124 }
125 }
126 }
127
128 /**
129 * @tc.name: Splice
130 * @tc.desc: Create a source TaggedArray, set value for the elements of the source TaggedArray, create an source Array
131 * through calling CreateArrayFromList function with the source TaggedArray, create a deleted Array through
132 * calling Splice function with the source Array, an EcmaRuntimeCallInfo that set Args from 2 as the
133 * delete-elements, the offsetStartInsert, the countInsert and the actualDeleteCount. Check whether the
134 * deleted Array and the source Array after change are within expectations.
135 * @tc.type: FUNC
136 * @tc.require:
137 */
HWTEST_F_L0(JSStableArrayTest,Splice)138 HWTEST_F_L0(JSStableArrayTest, Splice)
139 {
140 ObjectFactory *objFactory = thread->GetEcmaVM()->GetFactory();
141
142 int32_t lengthArr = 49;
143
144 JSHandle<JSTaggedValue> handleTagValInsertElement1(thread, JSTaggedValue(4000));
145 JSHandle<JSTaggedValue> handleTagValInsertElement2(thread, JSTaggedValue(4100));
146 JSHandle<TaggedArray> handleTagArr(objFactory->NewTaggedArray(lengthArr));
147 for (int i = 0; i < lengthArr; i++) {
148 handleTagArr->Set(thread, i, JSTaggedValue(i * 10));
149 }
150 JSHandle<JSArray> handleArr(JSArray::CreateArrayFromList(thread, handleTagArr));
151 double offsetStartInsert = 40;
152 double actualDeleteCount = 3;
153 double countInsert = 2;
154
155 auto ecmaRuntimeCallInfo = TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(),
156 4 + (2 + countInsert) * 2);
157 ecmaRuntimeCallInfo->SetFunction(JSTaggedValue::Undefined());
158 ecmaRuntimeCallInfo->SetThis(JSTaggedValue::Undefined());
159 ecmaRuntimeCallInfo->SetCallArg(2, handleTagValInsertElement1.GetTaggedValue());
160 ecmaRuntimeCallInfo->SetCallArg(3, handleTagValInsertElement2.GetTaggedValue());
161
162 [[maybe_unused]] auto prev = TestHelper::SetupFrame(thread, ecmaRuntimeCallInfo);
163 JSHandle<JSObject> thisObjHandle(handleArr);
164 JSTaggedValue newArray = JSArray::ArraySpeciesCreate(thread, thisObjHandle,
165 JSTaggedNumber(static_cast<double>(actualDeleteCount)));
166 JSHandle<JSObject> newArrayHandle(thread, newArray);
167 uint32_t len = JSHandle<JSArray>::Cast(thisObjHandle)->GetArrayLength();
168 JSHandle<JSTaggedValue> handleTagValArrCombinedOfDeletedElements(thread,
169 JSStableArray::Splice(JSHandle<JSArray>::Cast(thisObjHandle), ecmaRuntimeCallInfo, offsetStartInsert,
170 countInsert, actualDeleteCount, newArrayHandle, len));
171 TestHelper::TearDownFrame(thread, prev);
172 JSHandle<JSArray> handleArrCombinedOfDeletedElements(handleTagValArrCombinedOfDeletedElements);
173 EXPECT_EQ(handleArrCombinedOfDeletedElements->GetArrayLength(), actualDeleteCount);
174 JSHandle<JSObject> handleObjArrCombinedOfDeletedElements(handleTagValArrCombinedOfDeletedElements);
175 for (int32_t i = 0; i < actualDeleteCount; i++) {
176 EXPECT_EQ(ElementAccessor::Get(handleObjArrCombinedOfDeletedElements, i).GetNumber(),
177 (offsetStartInsert + i) * 10);
178 }
179
180 // Check the JSArray(in-out-parameter) changed through calling the Splice function.
181 EXPECT_EQ(handleArr->GetArrayLength(), lengthArr - actualDeleteCount + countInsert);
182 for (int32_t i = 0; i < offsetStartInsert; i++) {
183 EXPECT_EQ(handleTagArr->Get(i).GetNumber(), i * 10);
184 }
185 EXPECT_EQ(handleTagArr->Get(offsetStartInsert).GetNumber(),
186 handleTagValInsertElement1.GetTaggedValue().GetNumber());
187 EXPECT_EQ(handleTagArr->Get(offsetStartInsert + 1).GetNumber(),
188 handleTagValInsertElement2.GetTaggedValue().GetNumber());
189 for (int32_t i = offsetStartInsert + countInsert; i < lengthArr - actualDeleteCount + countInsert; i++) {
190 EXPECT_EQ(handleTagArr->Get(i).GetNumber(), (i + actualDeleteCount - countInsert) * 10);
191 }
192 }
193
194 /**
195 * @tc.name: Shift
196 * @tc.desc: Create a source Array, set value for the elements of the source Array, call the Shift function with the
197 * source Array 5 times, check whether the returned JSTaggedValue and the changed source Array are within
198 * expectations after each call to the Shift function.
199 * @tc.type: FUNC
200 * @tc.require:
201 */
HWTEST_F_L0(JSStableArrayTest,Shift)202 HWTEST_F_L0(JSStableArrayTest, Shift)
203 {
204 ObjectFactory *objFactory = thread->GetEcmaVM()->GetFactory();
205
206 int32_t lengthArr = 49;
207 JSHandle<TaggedArray> handleTagArr(objFactory->NewTaggedArray(lengthArr));
208 for (int i = 0; i < lengthArr; i++) {
209 handleTagArr->Set(thread, i, JSTaggedValue(i * 10));
210 }
211 JSHandle<JSArray> handleArr(JSArray::CreateArrayFromList(thread, handleTagArr));
212
213 for (int32_t i = 0; i < 5; i++) {
214 auto ecmaRuntimeCallInfo = TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), 4);
215 ecmaRuntimeCallInfo->SetFunction(JSTaggedValue::Undefined());
216 ecmaRuntimeCallInfo->SetThis(JSTaggedValue::Undefined());
217 [[maybe_unused]] auto prev = TestHelper::SetupFrame(thread, ecmaRuntimeCallInfo);
218 EXPECT_EQ(JSStableArray::Shift(handleArr, ecmaRuntimeCallInfo), JSTaggedValue(i * 10));
219 TestHelper::TearDownFrame(thread, prev);
220 EXPECT_EQ(handleArr->GetArrayLength(), static_cast<uint32_t>(lengthArr - (i + 1)));
221 EXPECT_EQ(handleTagArr->Get(0), JSTaggedValue((i + 1) * 10));
222 if (i != 4) {
223 EXPECT_EQ(handleTagArr->GetLength(), static_cast<uint32_t>(lengthArr));
224 EXPECT_EQ(handleTagArr->Get(lengthArr - (i + 1)), JSTaggedValue::Hole());
225 continue;
226 }
227 EXPECT_EQ(handleTagArr->GetLength(), static_cast<uint32_t>(lengthArr - (i + 1)));
228 }
229 }
230
231 /**
232 * @tc.name: Join_NumberElements_UndefinedSep
233 * @tc.desc: Create a source Array whose elements are Numbers and an EcmaRuntimeCallInfo, check whether the EcmaString
234 * returned through calling Join function with the source Array and the EcmaRuntimeCallInfo is within
235 * expectations.
236 * @tc.type: FUNC
237 * @tc.require:
238 */
HWTEST_F_L0(JSStableArrayTest,Join_NumberElements_UndefinedSep)239 HWTEST_F_L0(JSStableArrayTest, Join_NumberElements_UndefinedSep)
240 {
241 ObjectFactory *objFactory = thread->GetEcmaVM()->GetFactory();
242
243 int32_t lengthArr = 10;
244 JSHandle<TaggedArray> handleTagArr(objFactory->NewTaggedArray(lengthArr));
245 for (int i = 0; i < lengthArr; i++) {
246 handleTagArr->Set(thread, i, JSTaggedValue(i));
247 }
248 JSHandle<JSArray> handleArr(JSArray::CreateArrayFromList(thread, handleTagArr));
249 std::vector<JSTaggedValue> args{};
250 auto ecmaRuntimeCallInfo = TestHelper::CreateEcmaRuntimeCallInfo(thread, args, 4);
251 [[maybe_unused]] auto prev = TestHelper::SetupFrame(thread, ecmaRuntimeCallInfo);
252 JSHandle<JSTaggedValue> sepHandle = thread->GlobalConstants()->GetHandledCommaString();
253 JSHandle<EcmaString> sepStringHandle = JSTaggedValue::ToString(thread, sepHandle);
254 JSHandle<JSTaggedValue> handleTagValEcmaStrRet(thread,
255 JSStableArray::Join(thread, handleArr, sepStringHandle, lengthArr));
256 TestHelper::TearDownFrame(thread, prev);
257
258 JSHandle<EcmaString> handleEcmaStrRet(handleTagValEcmaStrRet);
259 EXPECT_STREQ(EcmaStringAccessor(handleEcmaStrRet).ToCString().c_str(), "0,1,2,3,4,5,6,7,8,9");
260 EXPECT_FALSE(EcmaStringAccessor(handleEcmaStrRet).IsTreeString());
261 }
262
263 /**
264 * @tc.name: Join_StringElements_UndefinedSep
265 * @tc.desc: Create a source Array whose elements are EcmaStrings and an EcmaRuntimeCallInfo, check whether the
266 * EcmaString returned through calling Join function with the source Array and the EcmaRuntimeCallInfo is
267 * within expectations.
268 * @tc.type: FUNC
269 * @tc.require:
270 */
HWTEST_F_L0(JSStableArrayTest,Join_StringElements_UndefinedSep)271 HWTEST_F_L0(JSStableArrayTest, Join_StringElements_UndefinedSep)
272 {
273 ObjectFactory *objFactory = thread->GetEcmaVM()->GetFactory();
274
275 int32_t lengthArr = 10;
276 JSHandle<TaggedArray> handleTagArr(objFactory->NewTaggedArray(lengthArr));
277 JSHandle<JSTaggedValue> handleTagValElementEcmaStr(objFactory->NewFromStdString("abc"));
278 for (int i = 0; i < lengthArr; i++) {
279 handleTagArr->Set(thread, i, handleTagValElementEcmaStr.GetTaggedValue());
280 }
281 JSHandle<JSArray> handleArr(JSArray::CreateArrayFromList(thread, handleTagArr));
282 std::vector<JSTaggedValue> args{};
283 auto ecmaRuntimeCallInfo = TestHelper::CreateEcmaRuntimeCallInfo(thread, args, 4);
284 [[maybe_unused]] auto prev = TestHelper::SetupFrame(thread, ecmaRuntimeCallInfo);
285 JSHandle<JSTaggedValue> sepHandle = thread->GlobalConstants()->GetHandledCommaString();
286 JSHandle<EcmaString> sepStringHandle = JSTaggedValue::ToString(thread, sepHandle);
287 JSHandle<JSTaggedValue> handleTagValEcmaStrRet(thread,
288 JSStableArray::Join(thread, handleArr, sepStringHandle, lengthArr));
289 TestHelper::TearDownFrame(thread, prev);
290
291 JSHandle<EcmaString> handleEcmaStrRet(handleTagValEcmaStrRet);
292 EXPECT_STREQ(EcmaStringAccessor(handleEcmaStrRet).ToCString().c_str(), "abc,abc,abc,abc,abc,abc,abc,abc,abc,abc");
293 EXPECT_FALSE(EcmaStringAccessor(handleEcmaStrRet).IsTreeString());
294 }
295
296 /**
297 * @tc.name: Join_NumberElements_DefinedSep
298 * @tc.desc: Create a source Array whose elements are Numbers and an EcmaRuntimeCallInfo, define the first arg of the
299 EcmaRuntimeCallInfo an EcmaString as the seperator, check whether the EcmaString returned through calling
300 Join function with the source Array and the EcmaRuntimeCallInfo is within expectations.
301 * @tc.type: FUNC
302 * @tc.require:
303 */
HWTEST_F_L0(JSStableArrayTest,Join_NumberElements_DefinedSep)304 HWTEST_F_L0(JSStableArrayTest, Join_NumberElements_DefinedSep)
305 {
306 ObjectFactory *objFactory = thread->GetEcmaVM()->GetFactory();
307
308 int32_t lengthArr = 10;
309 JSHandle<TaggedArray> handleTagArr(objFactory->NewTaggedArray(lengthArr));
310 for (int i = 0; i < lengthArr; i++) {
311 handleTagArr->Set(thread, i, JSTaggedValue(i));
312 }
313 JSHandle<JSArray> handleArr(JSArray::CreateArrayFromList(thread, handleTagArr));
314 std::vector<JSTaggedValue> args{JSHandle<JSTaggedValue>::Cast(objFactory->NewFromStdString("^")).GetTaggedValue()};
315 auto ecmaRuntimeCallInfo = TestHelper::CreateEcmaRuntimeCallInfo(thread, args, 6);
316 [[maybe_unused]] auto prev = TestHelper::SetupFrame(thread, ecmaRuntimeCallInfo);
317 JSHandle<JSTaggedValue> sepHandle = JSHandle<JSTaggedValue>::Cast(objFactory->NewFromStdString("^"));
318 JSHandle<EcmaString> sepStringHandle = JSTaggedValue::ToString(thread, sepHandle);
319 JSHandle<JSTaggedValue> handleTagValEcmaStrRet(thread,
320 JSStableArray::Join(thread, handleArr, sepStringHandle, lengthArr));
321 TestHelper::TearDownFrame(thread, prev);
322
323 JSHandle<EcmaString> handleEcmaStrRet(handleTagValEcmaStrRet);
324 EXPECT_STREQ(EcmaStringAccessor(handleEcmaStrRet).ToCString().c_str(), "0^1^2^3^4^5^6^7^8^9");
325 EXPECT_FALSE(EcmaStringAccessor(handleEcmaStrRet).IsTreeString());
326 }
327
328 /**
329 * @tc.name: Join_StringElements_DefinedSep
330 * @tc.desc: Create a source Array whose elements are EcmaStrings and an EcmaRuntimeCallInfo, define the first arg of
331 the EcmaRuntimeCallInfo an EcmaString as the seperator, check whether the EcmaString returned through
332 calling Join function with the source Array and the EcmaRuntimeCallInfo is within expectations.
333 * @tc.type: FUNC
334 * @tc.require:
335 */
HWTEST_F_L0(JSStableArrayTest,Join_StringElements_DefinedSep)336 HWTEST_F_L0(JSStableArrayTest, Join_StringElements_DefinedSep)
337 {
338 ObjectFactory *objFactory = thread->GetEcmaVM()->GetFactory();
339
340 int32_t lengthArr = 10;
341 JSHandle<TaggedArray> handleTagArr(objFactory->NewTaggedArray(lengthArr));
342 JSHandle<JSTaggedValue> handleTagValElementEcmaStr(objFactory->NewFromStdString("a"));
343 for (int i = 0; i < lengthArr; i++) {
344 handleTagArr->Set(thread, i, handleTagValElementEcmaStr.GetTaggedValue());
345 }
346 JSHandle<JSArray> handleArr(JSArray::CreateArrayFromList(thread, handleTagArr));
347 auto ecmaRuntimeCallInfo = TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), 6);
348 ecmaRuntimeCallInfo->SetFunction(JSTaggedValue::Undefined());
349 ecmaRuntimeCallInfo->SetThis(JSTaggedValue::Undefined());
350 ecmaRuntimeCallInfo->SetCallArg(0,
351 JSHandle<JSTaggedValue>::Cast(objFactory->NewFromStdString(" <> ")).GetTaggedValue());
352 [[maybe_unused]] auto prev = TestHelper::SetupFrame(thread, ecmaRuntimeCallInfo);
353 JSHandle<JSTaggedValue> sepHandle = JSHandle<JSTaggedValue>::Cast(objFactory->NewFromStdString(" <> "));
354 JSHandle<EcmaString> sepStringHandle = JSTaggedValue::ToString(thread, sepHandle);
355 JSHandle<JSTaggedValue> handleTagValEcmaStrRet(thread,
356 JSStableArray::Join(thread, handleArr, sepStringHandle, lengthArr));
357 TestHelper::TearDownFrame(thread, prev);
358
359 JSHandle<EcmaString> handleEcmaStrRet(handleTagValEcmaStrRet);
360 EXPECT_STREQ(EcmaStringAccessor(handleEcmaStrRet).ToCString().c_str(),
361 "a <> a <> a <> a <> a <> a <> a <> a <> a <> a");
362 EXPECT_FALSE(EcmaStringAccessor(handleEcmaStrRet).IsTreeString());
363 }
364
365 /**
366 * @tc.name: Join_StringElements_ManyTiny
367 * @tc.desc: Create a source Array whose elements are EcmaStrings and an EcmaRuntimeCallInfo, define the first arg of
368 the EcmaRuntimeCallInfo an EcmaString as the seperator, check whether the EcmaString returned through
369 calling Join function with the source Array and the EcmaRuntimeCallInfo is within expectations.
370 * @tc.type: FUNC
371 * @tc.require:
372 */
HWTEST_F_L0(JSStableArrayTest,Join_StringElements_ManyTiny)373 HWTEST_F_L0(JSStableArrayTest, Join_StringElements_ManyTiny)
374 {
375 int32_t lengthArr = 256;
376 std::string sep = "";
377 // tiny string join should not use tree string.
378 ObjectFactory* objFactory = thread->GetEcmaVM()->GetFactory();
379 JSHandle<TaggedArray> handleTagArr(objFactory->NewTaggedArray(lengthArr));
380 JSHandle<JSTaggedValue> handleTagValElementEcmaStr(objFactory->NewFromStdString("a"));
381 for (int i = 0; i < lengthArr; i++) {
382 handleTagArr->Set(thread, i, handleTagValElementEcmaStr.GetTaggedValue());
383 }
384 JSHandle<JSTaggedValue> handleTagValEcmaStrRet = CallJoin(handleTagArr, sep, lengthArr);
385 JSHandle<EcmaString> handleEcmaStrRet(handleTagValEcmaStrRet);
386 // 256 x a
387 EXPECT_STREQ(EcmaStringAccessor(handleEcmaStrRet).ToCString().c_str(),
388 "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
389 "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
390 "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
391 "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa");
392 EXPECT_FALSE(EcmaStringAccessor(handleEcmaStrRet).IsTreeString());
393 sep = ",";
394 handleTagValEcmaStrRet = CallJoin(handleTagArr, sep, lengthArr);
395 JSHandle<EcmaString> handleEcmaStrRet2(handleTagValEcmaStrRet);
396 EXPECT_STREQ(EcmaStringAccessor(handleEcmaStrRet2).ToCString().c_str(),
397 "a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,"
398 "a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,"
399 "a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,"
400 "a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,"
401 "a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,"
402 "a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,"
403 "a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,"
404 "a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a");
405 EXPECT_FALSE(EcmaStringAccessor(handleEcmaStrRet2).IsTreeString());
406 }
407
408 /**
409 * @tc.name: Join_StringElements_ManyTiny
410 * @tc.desc: Create a source Array whose elements are EcmaStrings and an EcmaRuntimeCallInfo, define the first arg of
411 the EcmaRuntimeCallInfo an EcmaString as the seperator, check whether the EcmaString returned through
412 calling Join function with the source Array and the EcmaRuntimeCallInfo is within expectations.
413 * @tc.type: FUNC
414 * @tc.require:
415 */
HWTEST_F_L0(JSStableArrayTest,Join_StringElements_LargeString)416 HWTEST_F_L0(JSStableArrayTest, Join_StringElements_LargeString)
417 {
418 int32_t lengthArr = 8;
419 std::string sep = "";
420 // large string should use tree string.
421 ObjectFactory* objFactory = thread->GetEcmaVM()->GetFactory();
422 JSHandle<TaggedArray> handleTagArr(objFactory->NewTaggedArray(lengthArr));
423 // 32 x a
424 JSHandle<JSTaggedValue>
425 handleTagValElementEcmaStr(objFactory->NewFromStdString("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"));
426 for (int i = 0; i < lengthArr; i++) {
427 handleTagArr->Set(thread, i, handleTagValElementEcmaStr.GetTaggedValue());
428 }
429 JSHandle<JSTaggedValue> handleTagValEcmaStrRet = CallJoin(handleTagArr, sep, lengthArr);
430 JSHandle<EcmaString> handleEcmaStrRet(handleTagValEcmaStrRet);
431 EXPECT_STREQ(EcmaStringAccessor(handleEcmaStrRet).ToCString().c_str(),
432 "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
433 "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
434 "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
435 "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa");
436 EXPECT_TRUE(EcmaStringAccessor(handleEcmaStrRet).IsTreeString());
437 }
438
439 /**
440 * @tc.name: Join_StringElements_ManyTiny
441 * @tc.desc: Create a source Array whose elements are EcmaStrings and an EcmaRuntimeCallInfo, define the first arg of
442 the EcmaRuntimeCallInfo an EcmaString as the seperator, check whether the EcmaString returned through
443 calling Join function with the source Array and the EcmaRuntimeCallInfo is within expectations.
444 * @tc.type: FUNC
445 * @tc.require:
446 */
HWTEST_F_L0(JSStableArrayTest,Join_StringElements_LargeString2)447 HWTEST_F_L0(JSStableArrayTest, Join_StringElements_LargeString2)
448 {
449 int32_t lengthArr = 4;
450 std::string sep = ",";
451 // large string should use tree string.
452 ObjectFactory* objFactory = thread->GetEcmaVM()->GetFactory();
453 JSHandle<TaggedArray> handleTagArr(objFactory->NewTaggedArray(lengthArr));
454 // 64 x a
455 JSHandle<JSTaggedValue> handleTagValElementEcmaStr(
456 objFactory->NewFromStdString("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"));
457 for (int i = 0; i < lengthArr; i++) {
458 handleTagArr->Set(thread, i, handleTagValElementEcmaStr.GetTaggedValue());
459 }
460 JSHandle<JSTaggedValue> handleTagValEcmaStrRet = CallJoin(handleTagArr, sep, lengthArr);
461
462 JSHandle<EcmaString> handleEcmaStrRet(handleTagValEcmaStrRet);
463 EXPECT_STREQ(EcmaStringAccessor(handleEcmaStrRet).ToCString().c_str(),
464 "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa,"
465 "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa,"
466 "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa,"
467 "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa");
468 EXPECT_TRUE(EcmaStringAccessor(handleEcmaStrRet).IsTreeString());
469 }
470
471 /**
472 * @tc.name: Join_StringElements_ManyTiny
473 * @tc.desc: Create a source Array whose elements are EcmaStrings and an EcmaRuntimeCallInfo, define the first arg of
474 the EcmaRuntimeCallInfo an EcmaString as the seperator, check whether the EcmaString returned through
475 calling Join function with the source Array and the EcmaRuntimeCallInfo is within expectations.
476 * @tc.type: FUNC
477 * @tc.require:
478 */
HWTEST_F_L0(JSStableArrayTest,Join_StringElements_LargeString3)479 HWTEST_F_L0(JSStableArrayTest, Join_StringElements_LargeString3)
480 {
481 int32_t lengthArr = 5;
482 std::string sep = ",";
483 // large string should use tree string.
484 ObjectFactory* objFactory = thread->GetEcmaVM()->GetFactory();
485 JSHandle<TaggedArray> handleTagArr(objFactory->NewTaggedArray(lengthArr));
486 // 64 x a
487 JSHandle<JSTaggedValue> handleTagValElementEcmaStr0(
488 objFactory->NewFromStdString("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"));
489 handleTagArr->Set(thread, 0, handleTagValElementEcmaStr0.GetTaggedValue());
490 JSHandle<JSTaggedValue> handleTagValElementEcmaStr1(
491 objFactory->NewFromStdString("bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb"));
492 handleTagArr->Set(thread, 1, handleTagValElementEcmaStr1.GetTaggedValue());
493 JSHandle<JSTaggedValue> handleTagValElementEcmaStr2(
494 objFactory->NewFromStdString("cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc"));
495 handleTagArr->Set(thread, 2, handleTagValElementEcmaStr2.GetTaggedValue());
496 JSHandle<JSTaggedValue> handleTagValElementEcmaStr3(
497 objFactory->NewFromStdString("dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd"));
498 handleTagArr->Set(thread, 3, handleTagValElementEcmaStr3.GetTaggedValue());
499 JSHandle<JSTaggedValue> handleTagValElementEcmaStr4(
500 objFactory->NewFromStdString("eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee"));
501 handleTagArr->Set(thread, 4, handleTagValElementEcmaStr4.GetTaggedValue());
502
503 JSHandle<JSTaggedValue> handleTagValEcmaStrRet = CallJoin(handleTagArr, sep, lengthArr);
504
505 JSHandle<EcmaString> handleEcmaStrRet(handleTagValEcmaStrRet);
506 EXPECT_STREQ(EcmaStringAccessor(handleEcmaStrRet).ToCString().c_str(),
507 "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa,"
508 "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb,"
509 "cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc,"
510 "dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd,"
511 "eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee");
512 EXPECT_TRUE(EcmaStringAccessor(handleEcmaStrRet).IsTreeString());
513 }
514
515 /**
516 * @tc.name: At
517 * @tc.desc: Create a source Array whose elements are Numbers and an EcmaRuntimeCallInfo, define the first arg of the
518 EcmaRuntimeCallInfo an number as the index, check whether the element returned through calling
519 At function with the source Array and the EcmaRuntimeCallInfo is within expectations.
520 * @tc.type: FUNC
521 * @tc.require:
522 */
HWTEST_F_L0(JSStableArrayTest,At_NUMBER_INDEX)523 HWTEST_F_L0(JSStableArrayTest, At_NUMBER_INDEX)
524 {
525 ObjectFactory *objFactory = thread->GetEcmaVM()->GetFactory();
526
527 int32_t lengthArr = 10;
528 JSHandle<TaggedArray> handleTagArr(objFactory->NewTaggedArray(lengthArr));
529 for (int i = 0; i < lengthArr; i++) {
530 handleTagArr->Set(thread, i, JSTaggedValue(i));
531 }
532 JSHandle<JSArray> handleArr(JSArray::CreateArrayFromList(thread, handleTagArr));
533 auto ecmaRuntimeCallInfo = TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), 6);
534 ecmaRuntimeCallInfo->SetFunction(JSTaggedValue::Undefined());
535 ecmaRuntimeCallInfo->SetThis(JSTaggedValue::Undefined());
536 ecmaRuntimeCallInfo->SetCallArg(0, JSTaggedValue(0));
537 [[maybe_unused]] auto prev = TestHelper::SetupFrame(thread, ecmaRuntimeCallInfo);
538
539 JSTaggedValue thisTagValue = JSStableArray::At(handleArr, ecmaRuntimeCallInfo);
540 TestHelper::TearDownFrame(thread, prev);
541
542 EXPECT_EQ(thisTagValue.GetNumber(), 0);
543
544 ecmaRuntimeCallInfo = TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), 6);
545 ecmaRuntimeCallInfo->SetFunction(JSTaggedValue::Undefined());
546 ecmaRuntimeCallInfo->SetThis(JSTaggedValue::Undefined());
547 ecmaRuntimeCallInfo->SetCallArg(0, JSTaggedValue(9));
548 prev = TestHelper::SetupFrame(thread, ecmaRuntimeCallInfo);
549
550 thisTagValue = JSStableArray::At(handleArr, ecmaRuntimeCallInfo);
551 TestHelper::TearDownFrame(thread, prev);
552
553 EXPECT_EQ(thisTagValue.GetNumber(), 9);
554
555 ecmaRuntimeCallInfo = TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), 6);
556 ecmaRuntimeCallInfo->SetFunction(JSTaggedValue::Undefined());
557 ecmaRuntimeCallInfo->SetThis(JSTaggedValue::Undefined());
558 ecmaRuntimeCallInfo->SetCallArg(0, JSTaggedValue(-1));
559 prev = TestHelper::SetupFrame(thread, ecmaRuntimeCallInfo);
560
561 thisTagValue = JSStableArray::At(handleArr, ecmaRuntimeCallInfo);
562 TestHelper::TearDownFrame(thread, prev);
563
564 EXPECT_EQ(thisTagValue.GetNumber(), 9);
565
566 ecmaRuntimeCallInfo = TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), 6);
567 ecmaRuntimeCallInfo->SetFunction(JSTaggedValue::Undefined());
568 ecmaRuntimeCallInfo->SetThis(JSTaggedValue::Undefined());
569 ecmaRuntimeCallInfo->SetCallArg(0, JSTaggedValue(10));
570 prev = TestHelper::SetupFrame(thread, ecmaRuntimeCallInfo);
571
572 thisTagValue = JSStableArray::At(handleArr, ecmaRuntimeCallInfo);
573 TestHelper::TearDownFrame(thread, prev);
574
575 EXPECT_EQ(thisTagValue, JSTaggedValue::Undefined());
576 }
577
578 /**
579 * @tc.name: With
580 * @tc.desc: Create a source Array whose elements are Numbers, define the first arg a thread,
581 * define the second arg as the source Array, define the third arg an number as the length of source Array
582 * define the forth arg an number as the index, define the fifth args an number as the value
583 * check whether the value returned through calling With function with the source Array
584 * and the args is within expectations.
585 * @tc.type: FUNC
586 * @tc.require:
587 */
HWTEST_F_L0(JSStableArrayTest,With)588 HWTEST_F_L0(JSStableArrayTest, With)
589 {
590 ObjectFactory *objFactory = thread->GetEcmaVM()->GetFactory();
591 int32_t lengthArr = ARRAY_LENGTH_4;
592 JSHandle<TaggedArray> handleTagArr(objFactory->NewTaggedArray(lengthArr));
593 for (int i = 0; i < lengthArr; i++) {
594 handleTagArr->Set(thread, i, JSTaggedValue(i));
595 }
596 JSHandle<JSArray> handleArr(JSArray::CreateArrayFromList(thread, handleTagArr));
597
598 int64_t arrayLength = ARRAY_LENGTH_4;
599 int64_t index = static_cast<int64_t>(StableArrayIndex::STABLE_ARRAY_INDEX_2);
600 JSTaggedValue resultArr = JSStableArray::With(thread, handleArr,
601 arrayLength, index,
602 JSHandle<JSTaggedValue>(thread, JSTaggedValue(INT_VALUE_666)));
603 JSHandle<JSTaggedValue> destTaggedValue(thread, resultArr);
604 JSHandle<JSArray> destArr(destTaggedValue);
605 JSHandle<TaggedArray> destTaggedArr(thread, TaggedArray::Cast(destArr->GetElements().GetTaggedObject()));
606 for (uint32_t i = 0; i < ARRAY_LENGTH_4; ++i) {
607 JSHandle<JSObject> arrObjHandle(handleArr);
608 EXPECT_EQ(ElementAccessor::Get(arrObjHandle, i).GetNumber(), i);
609 }
610 for (uint32_t i = 0; i < ARRAY_LENGTH_4; ++i) {
611 JSHandle<JSObject> arrObjHandle(destArr);
612 if (i == 2) {
613 EXPECT_EQ(ElementAccessor::Get(arrObjHandle, i).GetNumber(), INT_VALUE_666);
614 } else {
615 EXPECT_EQ(ElementAccessor::Get(arrObjHandle, i).GetNumber(), i);
616 }
617 }
618 }
619
620 /**
621 * @tc.name: ToReversed
622 * @tc.desc: Create a source Array whose elements are Numbers and an EcmaRuntimeCallInfo, check whether the
623 value returned through calling ToReversed function with the source Array is within expectations.
624 * @tc.type: FUNC
625 * @tc.require:
626 */
HWTEST_F_L0(JSStableArrayTest,ToReversed)627 HWTEST_F_L0(JSStableArrayTest, ToReversed)
628 {
629 ObjectFactory *objFactory = thread->GetEcmaVM()->GetFactory();
630 int32_t lengthArr = ARRAY_LENGTH_4;
631 JSHandle<TaggedArray> handleTagArr(objFactory->NewTaggedArray(lengthArr));
632 for (int i = 0; i < lengthArr; i++) {
633 handleTagArr->Set(thread, i, JSTaggedValue(i));
634 }
635 JSHandle<JSArray> handleArr(JSArray::CreateArrayFromList(thread, handleTagArr));
636 JSHandle<JSObject> handleArrObj(handleArr);
637 JSTaggedValue resultArr =
638 JSStableArray::ToReversed(thread, handleArr, ARRAY_LENGTH_4);
639 JSHandle<JSObject> dstArrObj(thread, resultArr);
640
641 EXPECT_EQ(ElementAccessor::Get(handleArrObj,
642 static_cast<uint32_t>(StableArrayIndex::STABLE_ARRAY_INDEX_0)).GetNumber(), INT_VALUE_0);
643 EXPECT_EQ(ElementAccessor::Get(handleArrObj,
644 static_cast<uint32_t>(StableArrayIndex::STABLE_ARRAY_INDEX_1)).GetNumber(), INT_VALUE_1);
645 EXPECT_EQ(ElementAccessor::Get(handleArrObj,
646 static_cast<uint32_t>(StableArrayIndex::STABLE_ARRAY_INDEX_2)).GetNumber(), INT_VALUE_2);
647 EXPECT_EQ(ElementAccessor::Get(handleArrObj,
648 static_cast<uint32_t>(StableArrayIndex::STABLE_ARRAY_INDEX_3)).GetNumber(), INT_VALUE_3);
649
650 EXPECT_EQ(ElementAccessor::Get(dstArrObj,
651 static_cast<uint32_t>(StableArrayIndex::STABLE_ARRAY_INDEX_0)).GetNumber(), INT_VALUE_3);
652 EXPECT_EQ(ElementAccessor::Get(dstArrObj,
653 static_cast<uint32_t>(StableArrayIndex::STABLE_ARRAY_INDEX_1)).GetNumber(), INT_VALUE_2);
654 EXPECT_EQ(ElementAccessor::Get(dstArrObj,
655 static_cast<uint32_t>(StableArrayIndex::STABLE_ARRAY_INDEX_2)).GetNumber(), INT_VALUE_1);
656 EXPECT_EQ(ElementAccessor::Get(dstArrObj,
657 static_cast<uint32_t>(StableArrayIndex::STABLE_ARRAY_INDEX_3)).GetNumber(), INT_VALUE_0);
658 }
659 } // namespace panda::test
660