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
30 using namespace panda;
31
32 using namespace panda::ecmascript;
33
34 namespace panda::test {
35 class JSAPIPlainArrayTest : public BaseTestWithScope<false> {
36 protected:
CreatePlainArray()37 JSAPIPlainArray *CreatePlainArray()
38 {
39 return EcmaContainerCommon::CreatePlainArray(thread);
40 }
GetIndexOfKeyAndGeIndexOfValueGetArray(JSMutableHandle<JSTaggedValue> & value,uint32_t numbers)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
PropertyCommon(uint32_t elementsNums)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
HWTEST_F_L0(JSAPIPlainArrayTest,PlainArrayCreate)74 HWTEST_F_L0(JSAPIPlainArrayTest, PlainArrayCreate)
75 {
76 JSAPIPlainArray *plainArray = CreatePlainArray();
77 EXPECT_TRUE(plainArray != nullptr);
78 }
79
HWTEST_F_L0(JSAPIPlainArrayTest,PA_AddAndGetKeyAtAndClear)80 HWTEST_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
HWTEST_F_L0(JSAPIPlainArrayTest,PA_CloneAndHasAndGet)127 HWTEST_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
HWTEST_F_L0(JSAPIPlainArrayTest,PA_GetIndexOfKeyAndGeIndexOfValueAndIsEmptyAndRemoveRangeFrom)165 HWTEST_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
HWTEST_F_L0(JSAPIPlainArrayTest,PA_RemvoeAnrRemvoeAtAndSetValueAtAndGetValueAt)194 HWTEST_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
HWTEST_F_L0(JSAPIPlainArrayTest,PA_GetOwnProperty)228 HWTEST_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
HWTEST_F_L0(JSAPIPlainArrayTest,PA_ToString)253 HWTEST_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 */
HWTEST_F_L0(JSAPIPlainArrayTest,GetProperty)286 HWTEST_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 */
HWTEST_F_L0(JSAPIPlainArrayTest,SetProperty)303 HWTEST_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