1 /*
2 * Copyright (c) 2024 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 #include "ecmascript/ecma_vm.h"
16 #include "ecmascript/global_env.h"
17 #include "ecmascript/js_map.h"
18 #include "ecmascript/js_array.h"
19 #include "ecmascript/js_hclass.h"
20 #include "ecmascript/js_iterator.h"
21 #include "ecmascript/tests/test_helper.h"
22 #include "ecmascript/builtins/builtins_async_generator.h"
23 #include "ecmascript/builtins/builtins_shared_map.h"
24 #include "ecmascript/linked_hash_table.h"
25 #include "ecmascript/shared_objects/js_shared_map.h"
26 #include "ecmascript/shared_objects/js_shared_map_iterator.h"
27
28 using namespace panda::ecmascript;
29 using namespace panda::ecmascript::builtins;
30
31 namespace panda::test {
32 using BuiltinsSharedMap = ecmascript::builtins::BuiltinsSharedMap;
33
34 class BuiltinsSharedMapTest : public BaseTestWithScope<false> {
35 public:
36 class TestClass : public base::BuiltinsBase {
37 public:
TestFunc(EcmaRuntimeCallInfo * argv)38 static JSTaggedValue TestFunc(EcmaRuntimeCallInfo *argv)
39 {
40 int num = GetCallArg(argv, 0)->GetInt();
41 JSArray *jsArray = JSArray::Cast(GetThis(argv)->GetTaggedObject());
42 int length = jsArray->GetArrayLength() + num;
43 jsArray->SetArrayLength(argv->GetThread(), length);
44 return JSTaggedValue::Undefined();
45 }
46 };
47 };
48
CreateSBuiltinsMap(JSThread * thread)49 JSSharedMap *CreateSBuiltinsMap(JSThread *thread)
50 {
51 JSHandle<GlobalEnv> env = thread->GetEcmaVM()->GetGlobalEnv();
52 JSHandle<JSFunction> newTarget(env->GetSBuiltininMapFunction());
53 // 4 : test case
54 auto ecmaRuntimeCallInfo = TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue(*newTarget), 4);
55 ecmaRuntimeCallInfo->SetFunction(newTarget.GetTaggedValue());
56 ecmaRuntimeCallInfo->SetThis(JSTaggedValue::Undefined());
57
58 [[maybe_unused]] auto prev = TestHelper::SetupFrame(thread, ecmaRuntimeCallInfo);
59 JSTaggedValue result = BuiltinsSharedMap::Constructor(ecmaRuntimeCallInfo);
60 TestHelper::TearDownFrame(thread, prev);
61
62 EXPECT_TRUE(result.IsECMAObject());
63 JSSharedMap *jsSMap = JSSharedMap::Cast(reinterpret_cast<TaggedObject *>(result.GetRawData()));
64 return jsSMap;
65 }
66
67
HWTEST_F_L0(BuiltinsSharedMapTest,CreateAndGetSize)68 HWTEST_F_L0(BuiltinsSharedMapTest, CreateAndGetSize)
69 {
70 ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
71 JSHandle<GlobalEnv> env = thread->GetEcmaVM()->GetGlobalEnv();
72 JSHandle<JSFunction> newTarget(env->GetSBuiltininMapFunction());
73 JSHandle<JSSharedMap> map(thread, CreateSBuiltinsMap(thread));
74
75 auto ecmaRuntimeCallInfo = TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), 6);
76 ecmaRuntimeCallInfo->SetFunction(JSTaggedValue::Undefined());
77 ecmaRuntimeCallInfo->SetThis(map.GetTaggedValue());
78 ecmaRuntimeCallInfo->SetCallArg(0, JSTaggedValue::Undefined());
79
80 {
81 [[maybe_unused]] auto prev = TestHelper::SetupFrame(thread, ecmaRuntimeCallInfo);
82 JSTaggedValue result = BuiltinsSharedMap::GetSize(ecmaRuntimeCallInfo);
83 TestHelper::TearDownFrame(thread, prev);
84
85 EXPECT_EQ(result.GetRawData(), JSTaggedValue(0).GetRawData());
86 }
87 JSHandle<TaggedArray> array(factory->NewTaggedArray(5));
88 for (int i = 0; i < 5; i++) {
89 JSHandle<TaggedArray> internalArray(factory->NewTaggedArray(2));
90 internalArray->Set(thread, 0, JSTaggedValue(i));
91 internalArray->Set(thread, 1, JSTaggedValue(i));
92 auto arr = JSArray::CreateArrayFromList(thread, internalArray);
93 array->Set(thread, i, arr);
94 }
95 JSHandle<JSArray> values = JSArray::CreateArrayFromList(thread, array);
96 auto ecmaRuntimeCallInfo1 = TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), 6);
97 ecmaRuntimeCallInfo1->SetFunction(newTarget.GetTaggedValue());
98 ecmaRuntimeCallInfo1->SetThis(map.GetTaggedValue());
99 ecmaRuntimeCallInfo1->SetCallArg(0, values.GetTaggedValue());
100 ecmaRuntimeCallInfo1->SetNewTarget(newTarget.GetTaggedValue());
101 {
102 [[maybe_unused]] auto prev = TestHelper::SetupFrame(thread, ecmaRuntimeCallInfo1);
103 JSTaggedValue result1 = BuiltinsSharedMap::Constructor(ecmaRuntimeCallInfo1);
104 TestHelper::TearDownFrame(thread, prev);
105 JSHandle<JSSharedMap> map1(thread, JSSharedMap::Cast(reinterpret_cast<TaggedObject *>(result1.GetRawData())));
106 EXPECT_EQ(JSSharedMap::GetSize(thread, map1), 5);
107 }
108 }
109
110
HWTEST_F_L0(BuiltinsSharedMapTest,GetKeyTest001)111 HWTEST_F_L0(BuiltinsSharedMapTest, GetKeyTest001)
112 {
113 constexpr uint32_t NODE_NUMBERS = 8;
114 JSHandle<JSSharedMap> map(thread, CreateSBuiltinsMap(thread));
115 for (uint32_t i = 0; i < NODE_NUMBERS; i++) {
116 auto callInfo = TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), 8);
117 callInfo->SetFunction(JSTaggedValue::Undefined());
118 callInfo->SetThis(map.GetTaggedValue());
119 callInfo->SetCallArg(0, JSTaggedValue(i));
120 callInfo->SetCallArg(1, JSTaggedValue(i));
121
122 [[maybe_unused]] auto prev = TestHelper::SetupFrame(thread, callInfo);
123 JSTaggedValue result = BuiltinsSharedMap::Set(callInfo);
124 TestHelper::TearDownFrame(thread, prev);
125 EXPECT_TRUE(result.IsJSSharedMap());
126 JSHandle<JSSharedMap> jsSMap(thread, JSSharedMap::Cast(reinterpret_cast<TaggedObject *>(result.GetRawData())));
127 EXPECT_EQ(JSSharedMap::GetSize(thread, jsSMap), i + 1);
128 }
129 JSTaggedValue result = JSSharedMap::GetKey(thread, map, 0);
130 EXPECT_NE(result.GetRawData(), JSTaggedValue::Exception().GetRawData());
131 }
132
HWTEST_F_L0(BuiltinsSharedMapTest,GetValueTest001)133 HWTEST_F_L0(BuiltinsSharedMapTest, GetValueTest001)
134 {
135 constexpr uint32_t NODE_NUMBERS = 8;
136 JSHandle<JSSharedMap> map(thread, CreateSBuiltinsMap(thread));
137 for (uint32_t i = 0; i < NODE_NUMBERS; i++) {
138 auto callInfo = TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), 8);
139 callInfo->SetFunction(JSTaggedValue::Undefined());
140 callInfo->SetThis(map.GetTaggedValue());
141 callInfo->SetCallArg(0, JSTaggedValue(i));
142 callInfo->SetCallArg(1, JSTaggedValue(i));
143
144 [[maybe_unused]] auto prev = TestHelper::SetupFrame(thread, callInfo);
145 JSTaggedValue result = BuiltinsSharedMap::Set(callInfo);
146 TestHelper::TearDownFrame(thread, prev);
147 EXPECT_TRUE(result.IsJSSharedMap());
148 JSHandle<JSSharedMap> jsSMap(thread, JSSharedMap::Cast(reinterpret_cast<TaggedObject *>(result.GetRawData())));
149 EXPECT_EQ(JSSharedMap::GetSize(thread, jsSMap), i + 1);
150 }
151 JSTaggedValue result = JSSharedMap::GetValue(thread, map, 0);
152 EXPECT_NE(result.GetRawData(), JSTaggedValue::Exception().GetRawData());
153 }
154
HWTEST_F_L0(BuiltinsSharedMapTest,DeleteTest001)155 HWTEST_F_L0(BuiltinsSharedMapTest, DeleteTest001)
156 {
157 JSHandle<JSSharedMap> map(thread, CreateSBuiltinsMap(thread));
158 JSHandle<JSTaggedValue> key(thread, JSTaggedValue(10));
159 bool result = JSSharedMap::Delete(thread, map, key);
160 ASSERT_EQ(result, false);
161 }
162
163 enum class AlgorithmType {
164 SET,
165 FOR_EACH,
166 HAS,
167 };
168
MapAlgorithm(JSThread * thread,JSTaggedValue thisArg,std::vector<JSTaggedValue> & args,int32_t argLen,AlgorithmType type)169 JSTaggedValue MapAlgorithm(JSThread *thread, JSTaggedValue thisArg, std::vector<JSTaggedValue>& args,
170 int32_t argLen, AlgorithmType type)
171 {
172 auto ecmaRuntimeCallInfo = TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), argLen);
173 ecmaRuntimeCallInfo->SetFunction(JSTaggedValue::Undefined());
174 ecmaRuntimeCallInfo->SetThis(thisArg);
175 for (size_t i = 0; i < args.size(); i++) {
176 ecmaRuntimeCallInfo->SetCallArg(i, args[i]);
177 }
178 auto prev = TestHelper::SetupFrame(thread, ecmaRuntimeCallInfo);
179 JSTaggedValue result;
180 switch (type) {
181 case AlgorithmType::SET:
182 result = BuiltinsSharedMap::Set(ecmaRuntimeCallInfo);
183 break;
184 case AlgorithmType::FOR_EACH:
185 result = BuiltinsSharedMap::ForEach(ecmaRuntimeCallInfo);
186 break;
187 case AlgorithmType::HAS:
188 result = BuiltinsSharedMap::Has(ecmaRuntimeCallInfo);
189 break;
190 default:
191 break;
192 }
193 TestHelper::TearDownFrame(thread, prev);
194 return result;
195 }
196
HWTEST_F_L0(BuiltinsSharedMapTest,SetAndHas)197 HWTEST_F_L0(BuiltinsSharedMapTest, SetAndHas)
198 {
199 ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
200 // create jsSMap
201 JSHandle<JSSharedMap> map(thread, CreateSBuiltinsMap(thread));
202 JSHandle<JSTaggedValue> key(factory->NewFromASCII("key"));
203
204 auto ecmaRuntimeCallInfo = TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), 8);
205 ecmaRuntimeCallInfo->SetFunction(JSTaggedValue::Undefined());
206 ecmaRuntimeCallInfo->SetThis(map.GetTaggedValue());
207 ecmaRuntimeCallInfo->SetCallArg(0, key.GetTaggedValue());
208 ecmaRuntimeCallInfo->SetCallArg(1, JSTaggedValue(static_cast<int32_t>(1)));
209
210 // JSSharedMap *jsSMap;
211 {
212 [[maybe_unused]] auto prev = TestHelper::SetupFrame(thread, ecmaRuntimeCallInfo);
213 JSTaggedValue result1 = BuiltinsSharedMap::Has(ecmaRuntimeCallInfo);
214
215 EXPECT_EQ(result1.GetRawData(), JSTaggedValue::False().GetRawData());
216
217 // test Set()
218 JSTaggedValue result2 = BuiltinsSharedMap::Set(ecmaRuntimeCallInfo);
219
220 EXPECT_TRUE(result2.IsECMAObject());
221 JSHandle<JSSharedMap> jsSMap(thread, JSSharedMap::Cast(reinterpret_cast<TaggedObject *>(result2.GetRawData())));
222 EXPECT_EQ(JSSharedMap::GetSize(thread, jsSMap), 1);
223
224 std::vector<JSTaggedValue> args{key.GetTaggedValue(), JSTaggedValue(static_cast<int32_t>(1))}; // 1:value
225 auto result3 = MapAlgorithm(thread, jsSMap.GetTaggedValue(), args, 8, AlgorithmType::HAS); // 8: arg len
226 EXPECT_EQ(result3.GetRawData(), JSTaggedValue::True().GetRawData());
227 }
228 }
229
HWTEST_F_L0(BuiltinsSharedMapTest,ForEach)230 HWTEST_F_L0(BuiltinsSharedMapTest, ForEach)
231 {
232 // generate a map has 5 entries{key1:0,key2:1,key3:2,key4:3,key5:4}
233 ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
234 JSHandle<GlobalEnv> env = thread->GetEcmaVM()->GetGlobalEnv();
235 JSHandle<JSSharedMap> map(thread, CreateSBuiltinsMap(thread));
236 char keyArray[] = "key0";
237 for (uint32_t i = 0; i < 5; i++) {
238 keyArray[3] = '1' + i;
239 JSHandle<JSTaggedValue> key(factory->NewFromASCII(keyArray));
240 std::vector<JSTaggedValue> args{key.GetTaggedValue(), JSTaggedValue(static_cast<int32_t>(i))};
241 auto result1 = MapAlgorithm(thread, map.GetTaggedValue(), args, 8, AlgorithmType::SET);
242
243 EXPECT_TRUE(result1.IsECMAObject());
244 JSHandle<JSSharedMap> jsSMap(thread, JSSharedMap::Cast(reinterpret_cast<TaggedObject *>(result1.GetRawData())));
245 EXPECT_EQ(JSSharedMap::GetSize(thread, jsSMap), static_cast<int>(i) + 1);
246 }
247 JSHandle<JSArray> jsArray(JSArray::ArrayCreate(thread, JSTaggedNumber(0)));
248 JSHandle<JSFunction> func = factory->NewJSFunction(env, reinterpret_cast<void *>(TestClass::TestFunc));
249
250 std::vector<JSTaggedValue> args{func.GetTaggedValue(), jsArray.GetTaggedValue()};
251 auto result2 = MapAlgorithm(thread, map.GetTaggedValue(), args, 8, AlgorithmType::FOR_EACH);
252
253 EXPECT_EQ(result2.GetRawData(), JSTaggedValue::VALUE_UNDEFINED);
254 EXPECT_EQ(jsArray->GetArrayLength(), 10U);
255 }
256
HWTEST_F_L0(BuiltinsSharedMapTest,DeleteAndRemove)257 HWTEST_F_L0(BuiltinsSharedMapTest, DeleteAndRemove)
258 {
259 ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
260 // create jsSMap
261 JSHandle<JSSharedMap> map(thread, CreateSBuiltinsMap(thread));
262
263 // add 40 keys
264 char keyArray[] = "key0";
265 for (uint32_t i = 0; i < 40; i++) {
266 keyArray[3] = '1' + i;
267 JSHandle<JSTaggedValue> key(thread, factory->NewFromASCII(keyArray).GetTaggedValue());
268 std::vector<JSTaggedValue> args{key.GetTaggedValue(), JSTaggedValue(static_cast<int32_t>(i))};
269 auto result1 = MapAlgorithm(thread, map.GetTaggedValue(), args, 8, AlgorithmType::SET);
270
271 EXPECT_TRUE(result1.IsECMAObject());
272 JSHandle<JSSharedMap> jsSMap(thread, JSSharedMap::Cast(reinterpret_cast<TaggedObject *>(result1.GetRawData())));
273 EXPECT_EQ(JSSharedMap::GetSize(thread, jsSMap), static_cast<int>(i) + 1);
274 }
275 // whether jsSMap has delete key
276 keyArray[3] = '1' + 8;
277 JSHandle<JSTaggedValue> deleteKey(factory->NewFromASCII(keyArray));
278
279 auto ecmaRuntimeCallInfo1 = TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), 6);
280 ecmaRuntimeCallInfo1->SetFunction(JSTaggedValue::Undefined());
281 ecmaRuntimeCallInfo1->SetThis(map.GetTaggedValue());
282 ecmaRuntimeCallInfo1->SetCallArg(0, deleteKey.GetTaggedValue());
283
284 [[maybe_unused]] auto prev = TestHelper::SetupFrame(thread, ecmaRuntimeCallInfo1);
285 JSTaggedValue result2 = BuiltinsSharedMap::Has(ecmaRuntimeCallInfo1);
286 TestHelper::TearDownFrame(thread, prev);
287
288 EXPECT_EQ(result2.GetRawData(), JSTaggedValue::True().GetRawData());
289
290 // delete
291 [[maybe_unused]] auto prev1 = TestHelper::SetupFrame(thread, ecmaRuntimeCallInfo1);
292 JSTaggedValue result3 = BuiltinsSharedMap::Delete(ecmaRuntimeCallInfo1);
293 TestHelper::TearDownFrame(thread, prev1);
294 EXPECT_EQ(result3.GetRawData(), JSTaggedValue::True().GetRawData());
295
296 // check deleteKey is deleted
297 [[maybe_unused]] auto prev2 = TestHelper::SetupFrame(thread, ecmaRuntimeCallInfo1);
298 JSTaggedValue result4 = BuiltinsSharedMap::Has(ecmaRuntimeCallInfo1);
299 TestHelper::TearDownFrame(thread, prev2);
300 EXPECT_EQ(result4.GetRawData(), JSTaggedValue::False().GetRawData());
301 [[maybe_unused]] auto prev3 = TestHelper::SetupFrame(thread, ecmaRuntimeCallInfo1);
302 JSTaggedValue result5 = BuiltinsSharedMap::GetSize(ecmaRuntimeCallInfo1);
303 TestHelper::TearDownFrame(thread, prev3);
304 EXPECT_EQ(result5.GetRawData(), JSTaggedValue(39).GetRawData());
305
306 // clear
307 [[maybe_unused]] auto prev4 = TestHelper::SetupFrame(thread, ecmaRuntimeCallInfo1);
308 JSTaggedValue result6 = BuiltinsSharedMap::Clear(ecmaRuntimeCallInfo1);
309 TestHelper::TearDownFrame(thread, prev4);
310 EXPECT_EQ(result6.GetRawData(), JSTaggedValue::VALUE_UNDEFINED);
311 EXPECT_EQ(JSSharedMap::GetSize(thread, map), 0);
312 }
313
HWTEST_F_L0(BuiltinsSharedMapTest,NextInternalTest001)314 HWTEST_F_L0(BuiltinsSharedMapTest, NextInternalTest001)
315 {
316 JSTaggedValue result2 =
317 JSSharedMapIterator::NextInternal(thread, JSHandle<JSTaggedValue>(thread, JSTaggedValue::Undefined()));
318 EXPECT_EQ(result2.IsJSSharedSetIterator(), false);
319 }
320 }
321