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/test_helper.h"
29
30 using namespace panda;
31
32 using namespace panda::ecmascript;
33
34 namespace panda::test {
35 class JSAPIPlainArrayTest : public testing::Test {
36 public:
SetUpTestCase()37 static void SetUpTestCase()
38 {
39 GTEST_LOG_(INFO) << "SetUpTestCase";
40 }
41
TearDownTestCase()42 static void TearDownTestCase()
43 {
44 GTEST_LOG_(INFO) << "TearDownCase";
45 }
46
SetUp()47 void SetUp() override
48 {
49 TestHelper::CreateEcmaVMWithScope(instance, thread, scope);
50 }
51
TearDown()52 void TearDown() override
53 {
54 TestHelper::DestroyEcmaVMWithScope(instance, scope);
55 }
56
57 EcmaVM *instance {nullptr};
58 ecmascript::EcmaHandleScope *scope {nullptr};
59 JSThread *thread {nullptr};
60
61 protected:
CreatePlainArray()62 JSAPIPlainArray *CreatePlainArray()
63 {
64 ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
65 JSHandle<GlobalEnv> env = thread->GetEcmaVM()->GetGlobalEnv();
66
67 JSHandle<JSTaggedValue> globalObject = env->GetJSGlobalObject();
68 JSHandle<JSTaggedValue> key(factory->NewFromASCII("ArkPrivate"));
69 JSHandle<JSTaggedValue> value =
70 JSObject::GetProperty(thread, JSHandle<JSTaggedValue>(globalObject), key).GetValue();
71
72 auto objCallInfo =
73 TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), 6); // 6 means the value
74 objCallInfo->SetFunction(JSTaggedValue::Undefined());
75 objCallInfo->SetThis(value.GetTaggedValue());
76 objCallInfo->SetCallArg(0, JSTaggedValue(static_cast<int>(containers::ContainerTag::PlainArray)));
77
78 [[maybe_unused]] auto prev = TestHelper::SetupFrame(thread, objCallInfo);
79 JSTaggedValue result = containers::ContainersPrivate::Load(objCallInfo);
80 TestHelper::TearDownFrame(thread, prev);
81
82 JSHandle<JSTaggedValue> constructor(thread, result);
83 JSHandle<JSAPIPlainArray> plainArray(
84 factory->NewJSObjectByConstructor(JSHandle<JSFunction>(constructor), constructor));
85 JSHandle<JSTaggedValue> keyArray = JSHandle<JSTaggedValue>(factory->NewTaggedArray(8)); // 8 means the value
86 JSHandle<JSTaggedValue> valueArray = JSHandle<JSTaggedValue>(factory->NewTaggedArray(8)); // 8 means the value
87 plainArray->SetKeys(thread, keyArray);
88 plainArray->SetValues(thread, valueArray);
89 return *plainArray;
90 }
91 };
92
HWTEST_F_L0(JSAPIPlainArrayTest,PlainArrayCreate)93 HWTEST_F_L0(JSAPIPlainArrayTest, PlainArrayCreate)
94 {
95 JSAPIPlainArray *plainArray = CreatePlainArray();
96 EXPECT_TRUE(plainArray != nullptr);
97 }
98
HWTEST_F_L0(JSAPIPlainArrayTest,PA_AddAndGetKeyAtAndClear)99 HWTEST_F_L0(JSAPIPlainArrayTest, PA_AddAndGetKeyAtAndClear)
100 {
101 constexpr uint32_t NODE_NUMBERS = 8; // 8 means the value
102 ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
103 JSMutableHandle<JSTaggedValue> key(thread, JSTaggedValue::Undefined());
104 JSMutableHandle<JSTaggedValue> value(thread, JSTaggedValue::Undefined());
105
106 // test JSAPIPlainArray
107 JSHandle<JSAPIPlainArray> array(thread, CreatePlainArray());
108 std::string myValue("myvalue");
109 for (uint32_t i = 0; i < NODE_NUMBERS; i = i + 2) {
110 uint32_t ikey = 100 + i;
111 std::string ivalue = myValue + std::to_string(i);
112
113 key.Update(JSTaggedValue(ikey));
114 value.Update(factory->NewFromStdString(ivalue).GetTaggedValue());
115
116 JSAPIPlainArray::Add(thread, array, key, value);
117 }
118 for (uint32_t i = 1; i < NODE_NUMBERS; i = i + 2) {
119 uint32_t ikey = 100 + i;
120 std::string ivalue = myValue + std::to_string(i);
121
122 key.Update(JSTaggedValue(ikey));
123 value.Update(factory->NewFromStdString(ivalue).GetTaggedValue());
124
125 JSAPIPlainArray::Add(thread, array, key, value);
126 }
127 EXPECT_EQ(array->GetSize(), static_cast<int>(NODE_NUMBERS));
128
129 for (uint32_t i = 0; i < NODE_NUMBERS; i++) {
130 uint32_t ikey = 100 + i;
131 std::string ivalue = myValue + std::to_string(i);
132 key.Update(JSTaggedValue(ikey));
133 value.Update(factory->NewFromStdString(ivalue).GetTaggedValue());
134
135 // test getKeyAt
136 JSTaggedValue gvalue = array->GetKeyAt(i);
137 EXPECT_EQ(gvalue, key.GetTaggedValue());
138 }
139 EXPECT_EQ(array->GetKeyAt(-1), JSTaggedValue::Undefined());
140 EXPECT_EQ(array->GetKeyAt(NODE_NUMBERS), JSTaggedValue::Undefined());
141 // test clear
142 array->Clear(thread);
143 EXPECT_EQ(array->GetSize(), 0); // 0 means the value
144 }
145
HWTEST_F_L0(JSAPIPlainArrayTest,PA_CloneAndHasAndGet)146 HWTEST_F_L0(JSAPIPlainArrayTest, PA_CloneAndHasAndGet)
147 {
148 constexpr uint32_t NODE_NUMBERS = 8; // 8 means the value
149 ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
150 JSMutableHandle<JSTaggedValue> key(thread, JSTaggedValue::Undefined());
151 JSMutableHandle<JSTaggedValue> value(thread, JSTaggedValue::Undefined());
152
153 // test JSAPIPlainArray
154 JSHandle<JSAPIPlainArray> array(thread, CreatePlainArray());
155 std::string myValue("myvalue");
156 for (uint32_t i = 0; i < NODE_NUMBERS; i++) {
157 uint32_t ikey = 100 + i;
158 std::string ivalue = myValue + std::to_string(i);
159 key.Update(JSTaggedValue(ikey));
160 value.Update(factory->NewFromStdString(ivalue).GetTaggedValue());
161 JSAPIPlainArray::Add(thread, array, key, value);
162 }
163 EXPECT_EQ(array->GetSize(), static_cast<int>(NODE_NUMBERS));
164
165 // test clone
166 JSHandle<JSAPIPlainArray> newArray(thread, CreatePlainArray());
167 EXPECT_EQ(newArray->GetSize(), 0); // 0 means the value
168 newArray = JSAPIPlainArray::Clone(thread, array);
169 EXPECT_EQ(newArray->GetSize(), static_cast<int>(NODE_NUMBERS));
170
171 // test has
172 key.Update(JSTaggedValue(103)); // 103 means the value
173 int32_t lkey = 103;
174 bool result = array->Has(lkey);
175 EXPECT_TRUE(result);
176 EXPECT_FALSE(array->Has(lkey * 2));
177
178 // test get
179 myValue = std::string("myvalue3");
180 value.Update(factory->NewFromStdString(myValue).GetTaggedValue());
181 EXPECT_TRUE(JSTaggedValue::Equal(thread, JSHandle<JSTaggedValue>(thread, array->Get(key.GetTaggedValue())), value));
182 }
183
HWTEST_F_L0(JSAPIPlainArrayTest,PA_GetIndexOfKeyAndGeIndexOfValueAndIsEmptyAndRemoveRangeFrom)184 HWTEST_F_L0(JSAPIPlainArrayTest, PA_GetIndexOfKeyAndGeIndexOfValueAndIsEmptyAndRemoveRangeFrom)
185 {
186 constexpr uint32_t NODE_NUMBERS = 8; // 8 means the value
187 ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
188 JSMutableHandle<JSTaggedValue> key(thread, JSTaggedValue::Undefined());
189 JSMutableHandle<JSTaggedValue> value(thread, JSTaggedValue::Undefined());
190
191 JSHandle<JSAPIPlainArray> array(thread, CreatePlainArray());
192 EXPECT_TRUE(array->IsEmpty());
193 std::string myValue("myvalue");
194 for (uint32_t i = 0; i < NODE_NUMBERS; i++) {
195 uint32_t ikey = 100 + i;
196 std::string ivalue = myValue + std::to_string(i);
197 key.Update(JSTaggedValue(ikey));
198 value.Update(factory->NewFromStdString(ivalue).GetTaggedValue());
199 JSAPIPlainArray::Add(thread, array, key, value);
200 }
201 EXPECT_EQ(array->GetSize(), static_cast<int>(NODE_NUMBERS));
202 EXPECT_FALSE(array->IsEmpty());
203
204 value.Update(JSTaggedValue(103)); // 103 means the value
205 int32_t lvalue = 103;
206 JSTaggedValue value2 = array->GetIndexOfKey(lvalue);
207 EXPECT_EQ(value2.GetNumber(), 3); // 3 means the value
208 EXPECT_EQ(array->GetIndexOfKey(lvalue * 2), JSTaggedValue(-1));
209
210 myValue = "myvalue2";
211 value.Update(factory->NewFromStdString(myValue).GetTaggedValue());
212 JSTaggedValue value3 = array->GetIndexOfValue(value.GetTaggedValue());
213 EXPECT_EQ(value3.GetNumber(), 2); // 2 means the value
214 EXPECT_EQ(array->GetIndexOfValue(JSTaggedValue(0)), JSTaggedValue(-1));
215
216 value.Update(JSTaggedValue(1));
217 int32_t batchSize = 3; // 3 means the value
218 lvalue = 1;
219 value3 = array->RemoveRangeFrom(thread, lvalue, batchSize);
220 EXPECT_EQ(value3.GetNumber(), 3); // 3 means the value
221 EXPECT_EQ(array->GetSize(), static_cast<int>(NODE_NUMBERS - 3));
222
223 // test RemoveRangeFrom exception
224 array->RemoveRangeFrom(thread, lvalue, -1);
225 }
226
HWTEST_F_L0(JSAPIPlainArrayTest,PA_RemvoeAnrRemvoeAtAndSetValueAtAndGetValueAt)227 HWTEST_F_L0(JSAPIPlainArrayTest, PA_RemvoeAnrRemvoeAtAndSetValueAtAndGetValueAt)
228 {
229 constexpr uint32_t NODE_NUMBERS = 8; // 8 means the value
230 ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
231 JSMutableHandle<JSTaggedValue> key(thread, JSTaggedValue::Undefined());
232 JSMutableHandle<JSTaggedValue> value(thread, JSTaggedValue::Undefined());
233
234 JSHandle<JSAPIPlainArray> array(thread, CreatePlainArray());
235 EXPECT_TRUE(array->IsEmpty());
236 std::string myValue("myvalue");
237 for (uint32_t i = 0; i < NODE_NUMBERS; i++) {
238 uint32_t ikey = 100 + i;
239 std::string ivalue = myValue + std::to_string(i);
240 key.Update(JSTaggedValue(ikey));
241 value.Update(factory->NewFromStdString(ivalue).GetTaggedValue());
242 JSAPIPlainArray::Add(thread, array, key, value);
243 }
244 EXPECT_EQ(array->GetSize(), static_cast<int>(NODE_NUMBERS));
245 EXPECT_FALSE(array->IsEmpty());
246
247 // test Remove
248 myValue = "myvalue2";
249 value.Update(factory->NewFromStdString(myValue).GetTaggedValue());
250 JSTaggedValue taggedValue =
251 array->Remove(thread, JSTaggedValue(102)); // 102 means the value
252 EXPECT_TRUE(JSTaggedValue::Equal(thread, value, JSHandle<JSTaggedValue>(thread, taggedValue)));
253 EXPECT_EQ(array->Remove(thread, JSTaggedValue(-1)), JSTaggedValue::Undefined());
254 EXPECT_EQ(array->Remove(thread, JSTaggedValue(100 + NODE_NUMBERS)), JSTaggedValue::Undefined());
255
256 // test RemoveAt
257 myValue = "myvalue4";
258 value.Update(factory->NewFromStdString(myValue).GetTaggedValue());
259 taggedValue =
260 array->RemoveAt(thread, JSTaggedValue(3)); // 3 means the value
261 EXPECT_TRUE(JSTaggedValue::Equal(thread, value, JSHandle<JSTaggedValue>(thread, taggedValue)));
262 EXPECT_EQ(array->GetSize(), static_cast<int>(NODE_NUMBERS - 2));
263 EXPECT_EQ(array->RemoveAt(thread, JSTaggedValue(-1)), JSTaggedValue::Undefined());
264 EXPECT_EQ(array->RemoveAt(thread, JSTaggedValue(NODE_NUMBERS)), JSTaggedValue::Undefined());
265
266 // test SetValueAt
267 myValue = "myvalue14";
268 value.Update(factory->NewFromStdString(myValue).GetTaggedValue());
269 array->SetValueAt(thread, JSTaggedValue(3), value.GetTaggedValue()); // 3 means the value
270 int32_t lvalue = 3; // 3 means the value
271 taggedValue = array->GetValueAt(thread, lvalue);
272 EXPECT_TRUE(JSTaggedValue::Equal(thread, value, JSHandle<JSTaggedValue>(thread, taggedValue)));
273 }
274
HWTEST_F_L0(JSAPIPlainArrayTest,PA_GetOwnProperty)275 HWTEST_F_L0(JSAPIPlainArrayTest, PA_GetOwnProperty)
276 {
277 constexpr uint32_t DEFAULT_LENGTH = 8;
278 ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
279 JSHandle<JSAPIPlainArray> toor(thread, CreatePlainArray());
280 JSMutableHandle<JSTaggedValue> key(thread, JSTaggedValue::Undefined());
281 JSMutableHandle<JSTaggedValue> value(thread, JSTaggedValue::Undefined());
282
283 std::string plainArrayvalue("plainArrayvalue");
284 for (uint32_t i = 0; i < DEFAULT_LENGTH; i++) {
285 uint32_t ikey = 100 + i;
286 std::string ivalue = plainArrayvalue + std::to_string(i);
287 key.Update(JSTaggedValue(ikey));
288 value.Update(factory->NewFromStdString(ivalue).GetTaggedValue());
289 JSAPIPlainArray::Add(thread, toor, key, value);
290 }
291 // test GetOwnProperty
292 int testInt = 100 + 1;
293 JSHandle<JSTaggedValue> plainArrayKey1(thread, JSTaggedValue(testInt));
294 EXPECT_TRUE(JSAPIPlainArray::GetOwnProperty(thread, toor, plainArrayKey1));
295 testInt = 100 + 20;
296 JSHandle<JSTaggedValue> plainArrayKey2(thread, JSTaggedValue(testInt));
297 EXPECT_FALSE(JSAPIPlainArray::GetOwnProperty(thread, toor, plainArrayKey2));
298 }
299
HWTEST_F_L0(JSAPIPlainArrayTest,PA_ToString)300 HWTEST_F_L0(JSAPIPlainArrayTest, PA_ToString)
301 {
302 constexpr uint32_t NODE_NUMBERS = 3; // 3 means the value
303 ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
304 JSMutableHandle<JSTaggedValue> key(thread, JSTaggedValue::Undefined());
305 JSMutableHandle<JSTaggedValue> value(thread, JSTaggedValue::Undefined());
306
307 // test JSAPIPlainArray
308 JSHandle<JSAPIPlainArray> array(thread, CreatePlainArray());
309 JSTaggedValue result1 = JSAPIPlainArray::ToString(thread, array);
310 JSHandle<EcmaString> resultHandle1(thread, result1);
311 JSHandle<EcmaString> det = thread->GetEcmaVM()->GetFactory()->NewFromASCII("");
312 ASSERT_EQ(EcmaStringAccessor::Compare(instance, resultHandle1, det), 0);
313 for (uint32_t i = 0; i < NODE_NUMBERS; i++) {
314 uint32_t ikey = i;
315 std::string ivalue = std::to_string(i);
316 key.Update(JSTaggedValue(ikey));
317 value.Update(factory->NewFromStdString(ivalue).GetTaggedValue());
318 JSAPIPlainArray::Add(thread, array, key, value);
319 }
320 JSHandle<EcmaString> str = thread->GetEcmaVM()->GetFactory()->NewFromASCII("0:0,1:1,2:2");
321 JSTaggedValue result = JSAPIPlainArray::ToString(thread, array);
322 JSHandle<EcmaString> resultHandle(thread, result);
323
324 ASSERT_EQ(EcmaStringAccessor::Compare(instance, resultHandle, str), 0);
325 }
326
327 /**
328 * @tc.name: GetProperty
329 * @tc.desc:
330 * @tc.type: FUNC
331 * @tc.require:
332 */
HWTEST_F_L0(JSAPIPlainArrayTest,GetProperty)333 HWTEST_F_L0(JSAPIPlainArrayTest, GetProperty)
334 {
335 JSHandle<JSAPIPlainArray> plainArray(thread, CreatePlainArray());
336 uint32_t elementsNums = 8;
337 for (uint32_t i = 0; i < elementsNums; i++) {
338 JSHandle<JSTaggedValue> key(thread, JSTaggedValue(i));
339 JSHandle<JSTaggedValue> value(thread, JSTaggedValue(i));
340 JSAPIPlainArray::Add(thread, plainArray, key, value);
341 }
342 for (uint32_t i = 0; i < elementsNums; i++) {
343 JSHandle<JSTaggedValue> key(thread, JSTaggedValue(i));
344 OperationResult getPropertyRes = JSAPIPlainArray::GetProperty(thread, plainArray, key);
345 EXPECT_EQ(getPropertyRes.GetValue().GetTaggedValue(), JSTaggedValue(i));
346 }
347 }
348
349 /**
350 * @tc.name: SetProperty
351 * @tc.desc:
352 * @tc.type: FUNC
353 * @tc.require:
354 */
HWTEST_F_L0(JSAPIPlainArrayTest,SetProperty)355 HWTEST_F_L0(JSAPIPlainArrayTest, SetProperty)
356 {
357 JSHandle<JSAPIPlainArray> plainArray(thread, CreatePlainArray());
358 uint32_t elementsNums = 8;
359 for (uint32_t i = 0; i < elementsNums; i++) {
360 JSHandle<JSTaggedValue> key(thread, JSTaggedValue(i));
361 JSHandle<JSTaggedValue> value(thread, JSTaggedValue(i));
362 JSAPIPlainArray::Add(thread, plainArray, key, value);
363 }
364 for (uint32_t i = 0; i < elementsNums; i++) {
365 JSHandle<JSTaggedValue> key(thread, JSTaggedValue(i));
366 JSHandle<JSTaggedValue> value(thread, JSTaggedValue(i * 2)); // 2 : It means double
367 bool setPropertyRes = JSAPIPlainArray::SetProperty(thread, plainArray, key, value);
368 EXPECT_EQ(setPropertyRes, true);
369 }
370 JSHandle<JSTaggedValue> key(thread, JSTaggedValue(-1));
371 JSHandle<JSTaggedValue> value(thread, JSTaggedValue(-1));
372 EXPECT_FALSE(JSAPIPlainArray::SetProperty(thread, plainArray, key, value));
373 JSHandle<JSTaggedValue> key1(thread, JSTaggedValue(elementsNums));
374 EXPECT_FALSE(JSAPIPlainArray::SetProperty(thread, plainArray, key1, value));
375 }
376 } // namespace panda::test
377