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_api/js_api_plain_array.h"
17#include "ecmascript/containers/containers_private.h"
18#include "ecmascript/ecma_string.h"
19#include "ecmascript/ecma_vm.h"
20#include "ecmascript/global_env.h"
21#include "ecmascript/js_api/js_api_plain_array_iterator.h"
22#include "ecmascript/js_function.h"
23#include "ecmascript/js_handle.h"
24#include "ecmascript/js_iterator.h"
25#include "ecmascript/js_object-inl.h"
26#include "ecmascript/js_tagged_value.h"
27#include "ecmascript/object_factory.h"
28#include "ecmascript/tests/ecma_test_common.h"
29
30using namespace panda;
31
32using namespace panda::ecmascript;
33
34namespace panda::test {
35class JSAPIPlainArrayTest : public BaseTestWithScope<false> {
36protected:
37    JSAPIPlainArray *CreatePlainArray()
38    {
39        return EcmaContainerCommon::CreatePlainArray(thread);
40    }
41    JSHandle<JSAPIPlainArray> GetIndexOfKeyAndGeIndexOfValueGetArray(JSMutableHandle<JSTaggedValue>& value,
42        uint32_t numbers)
43    {
44        ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
45        JSMutableHandle<JSTaggedValue> key(thread, JSTaggedValue::Undefined());
46
47        JSHandle<JSAPIPlainArray> array(thread, CreatePlainArray());
48        EXPECT_TRUE(array->IsEmpty());
49        std::string myValue("myvalue");
50        for (uint32_t i = 0; i < numbers; i++) {
51            uint32_t ikey = 100 + i;
52            std::string ivalue = myValue + std::to_string(i);
53            key.Update(JSTaggedValue(ikey));
54            value.Update(factory->NewFromStdString(ivalue).GetTaggedValue());
55            JSAPIPlainArray::Add(thread, array, key, value);
56        }
57        EXPECT_EQ(array->GetSize(), static_cast<int>(numbers));
58        EXPECT_FALSE(array->IsEmpty());
59        return array;
60    }
61
62    JSHandle<JSAPIPlainArray> PropertyCommon(uint32_t elementsNums)
63    {
64        JSHandle<JSAPIPlainArray> plainArray(thread, CreatePlainArray());
65        for (uint32_t i = 0; i < elementsNums; i++) {
66            JSHandle<JSTaggedValue> key(thread, JSTaggedValue(i));
67            JSHandle<JSTaggedValue> value(thread, JSTaggedValue(i));
68            JSAPIPlainArray::Add(thread, plainArray, key, value);
69        }
70        return plainArray;
71    }
72};
73
74HWTEST_F_L0(JSAPIPlainArrayTest, PlainArrayCreate)
75{
76    JSAPIPlainArray *plainArray = CreatePlainArray();
77    EXPECT_TRUE(plainArray != nullptr);
78}
79
80HWTEST_F_L0(JSAPIPlainArrayTest, PA_AddAndGetKeyAtAndClear)
81{
82    constexpr uint32_t NODE_NUMBERS = 8; // 8 means the value
83    ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
84    JSMutableHandle<JSTaggedValue> key(thread, JSTaggedValue::Undefined());
85    JSMutableHandle<JSTaggedValue> value(thread, JSTaggedValue::Undefined());
86
87    // test JSAPIPlainArray
88    JSHandle<JSAPIPlainArray> array(thread, CreatePlainArray());
89    std::string myValue("myvalue");
90    for (uint32_t i = 0; i < NODE_NUMBERS; i = i + 2) {
91        uint32_t ikey = 100 + i;
92        std::string ivalue = myValue + std::to_string(i);
93
94        key.Update(JSTaggedValue(ikey));
95        value.Update(factory->NewFromStdString(ivalue).GetTaggedValue());
96
97        JSAPIPlainArray::Add(thread, array, key, value);
98    }
99    for (uint32_t i = 1; i < NODE_NUMBERS; i = i + 2) {
100        uint32_t ikey = 100 + i;
101        std::string ivalue = myValue + std::to_string(i);
102
103        key.Update(JSTaggedValue(ikey));
104        value.Update(factory->NewFromStdString(ivalue).GetTaggedValue());
105
106        JSAPIPlainArray::Add(thread, array, key, value);
107    }
108    EXPECT_EQ(array->GetSize(), static_cast<int>(NODE_NUMBERS));
109
110    for (uint32_t i = 0; i < NODE_NUMBERS; i++) {
111        uint32_t ikey = 100 + i;
112        std::string ivalue = myValue + std::to_string(i);
113        key.Update(JSTaggedValue(ikey));
114        value.Update(factory->NewFromStdString(ivalue).GetTaggedValue());
115
116        // test getKeyAt
117        JSTaggedValue gvalue = array->GetKeyAt(i);
118        EXPECT_EQ(gvalue, key.GetTaggedValue());
119    }
120    EXPECT_EQ(array->GetKeyAt(-1), JSTaggedValue::Undefined());
121    EXPECT_EQ(array->GetKeyAt(NODE_NUMBERS), JSTaggedValue::Undefined());
122    // test clear
123    array->Clear(thread);
124    EXPECT_EQ(array->GetSize(), 0); // 0 means the value
125}
126
127HWTEST_F_L0(JSAPIPlainArrayTest, PA_CloneAndHasAndGet)
128{
129    constexpr uint32_t NODE_NUMBERS = 8; // 8 means the value
130    ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
131    JSMutableHandle<JSTaggedValue> key(thread, JSTaggedValue::Undefined());
132    JSMutableHandle<JSTaggedValue> value(thread, JSTaggedValue::Undefined());
133
134    // test JSAPIPlainArray
135    JSHandle<JSAPIPlainArray> array(thread, CreatePlainArray());
136    std::string myValue("myvalue");
137    for (uint32_t i = 0; i < NODE_NUMBERS; i++) {
138        uint32_t ikey = 100 + i;
139        std::string ivalue = myValue + std::to_string(i);
140        key.Update(JSTaggedValue(ikey));
141        value.Update(factory->NewFromStdString(ivalue).GetTaggedValue());
142        JSAPIPlainArray::Add(thread, array, key, value);
143    }
144    EXPECT_EQ(array->GetSize(), static_cast<int>(NODE_NUMBERS));
145
146    // test clone
147    JSHandle<JSAPIPlainArray> newArray(thread, CreatePlainArray());
148    EXPECT_EQ(newArray->GetSize(), 0); // 0 means the value
149    newArray = JSAPIPlainArray::Clone(thread, array);
150    EXPECT_EQ(newArray->GetSize(), static_cast<int>(NODE_NUMBERS));
151
152    // test has
153    key.Update(JSTaggedValue(103)); // 103 means the value
154    int32_t lkey = 103;
155    bool result = array->Has(lkey);
156    EXPECT_TRUE(result);
157    EXPECT_FALSE(array->Has(lkey * 2));
158
159    // test get
160    myValue = std::string("myvalue3");
161    value.Update(factory->NewFromStdString(myValue).GetTaggedValue());
162    EXPECT_TRUE(JSTaggedValue::Equal(thread, JSHandle<JSTaggedValue>(thread, array->Get(key.GetTaggedValue())), value));
163}
164
165HWTEST_F_L0(JSAPIPlainArrayTest, PA_GetIndexOfKeyAndGeIndexOfValueAndIsEmptyAndRemoveRangeFrom)
166{
167    constexpr uint32_t NODE_NUMBERS = 8; // 8 means the value
168    JSMutableHandle<JSTaggedValue> value(thread, JSTaggedValue::Undefined());
169    auto array = GetIndexOfKeyAndGeIndexOfValueGetArray(value, NODE_NUMBERS);
170    value.Update(JSTaggedValue(103)); // 103 means the value
171    int32_t lvalue = 103;
172    JSTaggedValue value2 = array->GetIndexOfKey(lvalue);
173    EXPECT_EQ(value2.GetNumber(), 3); // 3 means the value
174    EXPECT_EQ(array->GetIndexOfKey(lvalue * 2), JSTaggedValue(-1));
175
176    std::string myValue = "myvalue2";
177    ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
178    value.Update(factory->NewFromStdString(myValue).GetTaggedValue());
179    JSTaggedValue value3 = array->GetIndexOfValue(value.GetTaggedValue());
180    EXPECT_EQ(value3.GetNumber(), 2); // 2 means the value
181    EXPECT_EQ(array->GetIndexOfValue(JSTaggedValue(0)), JSTaggedValue(-1));
182
183    value.Update(JSTaggedValue(1));
184    int32_t batchSize = 3; // 3 means the value
185    lvalue = 1;
186    value3 = array->RemoveRangeFrom(thread, lvalue, batchSize);
187    EXPECT_EQ(value3.GetNumber(), 3); // 3 means the value
188    EXPECT_EQ(array->GetSize(), static_cast<int>(NODE_NUMBERS - 3));
189
190    // test RemoveRangeFrom exception
191    array->RemoveRangeFrom(thread, lvalue, -1);
192}
193
194HWTEST_F_L0(JSAPIPlainArrayTest, PA_RemvoeAnrRemvoeAtAndSetValueAtAndGetValueAt)
195{
196    constexpr uint32_t NODE_NUMBERS = 8; // 8 means the value
197    JSMutableHandle<JSTaggedValue> value(thread, JSTaggedValue::Undefined());
198    auto array = GetIndexOfKeyAndGeIndexOfValueGetArray(value, NODE_NUMBERS);
199    // test Remove
200    std::string myValue = "myvalue2";
201    ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
202    value.Update(factory->NewFromStdString(myValue).GetTaggedValue());
203    JSTaggedValue taggedValue =
204        array->Remove(thread, JSTaggedValue(102)); // 102 means the value
205    EXPECT_TRUE(JSTaggedValue::Equal(thread, value, JSHandle<JSTaggedValue>(thread, taggedValue)));
206    EXPECT_EQ(array->Remove(thread, JSTaggedValue(-1)), JSTaggedValue::Undefined());
207    EXPECT_EQ(array->Remove(thread, JSTaggedValue(100 + NODE_NUMBERS)), JSTaggedValue::Undefined());
208
209    // test RemoveAt
210    myValue = "myvalue4";
211    value.Update(factory->NewFromStdString(myValue).GetTaggedValue());
212    taggedValue =
213        array->RemoveAt(thread, JSTaggedValue(3)); // 3 means the value
214    EXPECT_TRUE(JSTaggedValue::Equal(thread, value, JSHandle<JSTaggedValue>(thread, taggedValue)));
215    EXPECT_EQ(array->GetSize(), static_cast<int>(NODE_NUMBERS - 2));
216    EXPECT_EQ(array->RemoveAt(thread, JSTaggedValue(-1)), JSTaggedValue::Undefined());
217    EXPECT_EQ(array->RemoveAt(thread, JSTaggedValue(NODE_NUMBERS)), JSTaggedValue::Undefined());
218
219    // test SetValueAt
220    myValue = "myvalue14";
221    value.Update(factory->NewFromStdString(myValue).GetTaggedValue());
222    array->SetValueAt(thread, JSTaggedValue(3), value.GetTaggedValue()); // 3 means the value
223    int32_t lvalue = 3; // 3 means the value
224    taggedValue = array->GetValueAt(thread, lvalue);
225    EXPECT_TRUE(JSTaggedValue::Equal(thread, value, JSHandle<JSTaggedValue>(thread, taggedValue)));
226}
227
228HWTEST_F_L0(JSAPIPlainArrayTest, PA_GetOwnProperty)
229{
230    constexpr uint32_t DEFAULT_LENGTH = 8;
231    ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
232    JSHandle<JSAPIPlainArray> toor(thread, CreatePlainArray());
233    JSMutableHandle<JSTaggedValue> key(thread, JSTaggedValue::Undefined());
234    JSMutableHandle<JSTaggedValue> value(thread, JSTaggedValue::Undefined());
235
236    std::string plainArrayvalue("plainArrayvalue");
237    for (uint32_t i = 0; i < DEFAULT_LENGTH; i++) {
238        uint32_t ikey = 100 + i;
239        std::string ivalue = plainArrayvalue + std::to_string(i);
240        key.Update(JSTaggedValue(ikey));
241        value.Update(factory->NewFromStdString(ivalue).GetTaggedValue());
242        JSAPIPlainArray::Add(thread, toor, key, value);
243    }
244    // test GetOwnProperty
245    int testInt = 100 + 1;
246    JSHandle<JSTaggedValue> plainArrayKey1(thread, JSTaggedValue(testInt));
247    EXPECT_TRUE(JSAPIPlainArray::GetOwnProperty(thread, toor, plainArrayKey1));
248    testInt = 100 + 20;
249    JSHandle<JSTaggedValue> plainArrayKey2(thread, JSTaggedValue(testInt));
250    EXPECT_FALSE(JSAPIPlainArray::GetOwnProperty(thread, toor, plainArrayKey2));
251}
252
253HWTEST_F_L0(JSAPIPlainArrayTest, PA_ToString)
254{
255    constexpr uint32_t NODE_NUMBERS = 3; // 3 means the value
256    ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
257    JSMutableHandle<JSTaggedValue> key(thread, JSTaggedValue::Undefined());
258    JSMutableHandle<JSTaggedValue> value(thread, JSTaggedValue::Undefined());
259
260    // test JSAPIPlainArray
261    JSHandle<JSAPIPlainArray> array(thread, CreatePlainArray());
262    JSTaggedValue result1 = JSAPIPlainArray::ToString(thread, array);
263    JSHandle<EcmaString> resultHandle1(thread, result1);
264    JSHandle<EcmaString> det = thread->GetEcmaVM()->GetFactory()->NewFromASCII("");
265    ASSERT_EQ(EcmaStringAccessor::Compare(instance, resultHandle1, det), 0);
266    for (uint32_t i = 0; i < NODE_NUMBERS; i++) {
267        uint32_t ikey = i;
268        std::string ivalue = std::to_string(i);
269        key.Update(JSTaggedValue(ikey));
270        value.Update(factory->NewFromStdString(ivalue).GetTaggedValue());
271        JSAPIPlainArray::Add(thread, array, key, value);
272    }
273    JSHandle<EcmaString> str = thread->GetEcmaVM()->GetFactory()->NewFromASCII("0:0,1:1,2:2");
274    JSTaggedValue result = JSAPIPlainArray::ToString(thread, array);
275    JSHandle<EcmaString> resultHandle(thread, result);
276
277    ASSERT_EQ(EcmaStringAccessor::Compare(instance, resultHandle, str), 0);
278}
279
280/**
281 * @tc.name: GetProperty
282 * @tc.desc:
283 * @tc.type: FUNC
284 * @tc.require:
285 */
286HWTEST_F_L0(JSAPIPlainArrayTest, GetProperty)
287{
288    uint32_t elementsNums = 8;
289    auto plainArray = PropertyCommon(elementsNums);
290    for (uint32_t i = 0; i < elementsNums; i++) {
291        JSHandle<JSTaggedValue> key(thread, JSTaggedValue(i));
292        OperationResult getPropertyRes = JSAPIPlainArray::GetProperty(thread, plainArray, key);
293        EXPECT_EQ(getPropertyRes.GetValue().GetTaggedValue(), JSTaggedValue(i));
294    }
295}
296
297/**
298 * @tc.name: SetProperty
299 * @tc.desc:
300 * @tc.type: FUNC
301 * @tc.require:
302 */
303HWTEST_F_L0(JSAPIPlainArrayTest, SetProperty)
304{
305    uint32_t elementsNums = 8;
306    auto plainArray = PropertyCommon(elementsNums);
307    for (uint32_t i = 0; i < elementsNums; i++) {
308        JSHandle<JSTaggedValue> key(thread, JSTaggedValue(i));
309        JSHandle<JSTaggedValue> value(thread, JSTaggedValue(i * 2)); // 2 : It means double
310        bool setPropertyRes = JSAPIPlainArray::SetProperty(thread, plainArray, key, value);
311        EXPECT_EQ(setPropertyRes, true);
312    }
313    JSHandle<JSTaggedValue> key(thread, JSTaggedValue(-1));
314    JSHandle<JSTaggedValue> value(thread, JSTaggedValue(-1));
315    EXPECT_FALSE(JSAPIPlainArray::SetProperty(thread, plainArray, key, value));
316    JSHandle<JSTaggedValue> key1(thread, JSTaggedValue(elementsNums));
317    EXPECT_FALSE(JSAPIPlainArray::SetProperty(thread, plainArray, key1, value));
318    JSHandle<JSTaggedValue> key2(thread, JSTaggedValue(int64_t(-9007199254740992))); // Out-of-Bounds test
319    EXPECT_FALSE(JSAPIPlainArray::SetProperty(thread, plainArray, key1, value));
320}
321}  // namespace panda::test
322