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