1 /*
2 * Copyright (c) 2021 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/builtins/builtins_weak_map.h"
17
18 #include "ecmascript/base/builtins_base.h"
19 #include "ecmascript/ecma_runtime_call_info.h"
20 #include "ecmascript/ecma_string.h"
21 #include "ecmascript/ecma_vm.h"
22 #include "ecmascript/global_env.h"
23 #include "ecmascript/js_array.h"
24 #include "ecmascript/js_handle.h"
25 #include "ecmascript/js_hclass.h"
26 #include "ecmascript/js_map_iterator.h"
27 #include "ecmascript/js_object-inl.h"
28 #include "ecmascript/js_tagged_value.h"
29 #include "ecmascript/js_thread.h"
30 #include "ecmascript/js_weak_container.h"
31 #include "ecmascript/object_factory.h"
32 #include "ecmascript/tagged_array-inl.h"
33 #include "ecmascript/tests/test_helper.h"
34
35 using namespace panda::ecmascript;
36 using namespace panda::ecmascript::builtins;
37
38 namespace panda::test {
39 using BuiltinsWeakMap = ecmascript::builtins::BuiltinsWeakMap;
40 using JSWeakMap = ecmascript::JSWeakMap;
41
42 class BuiltinsWeakMapTest : public testing::Test {
43 public:
SetUpTestCase()44 static void SetUpTestCase()
45 {
46 GTEST_LOG_(INFO) << "SetUpTestCase";
47 }
48
TearDownTestCase()49 static void TearDownTestCase()
50 {
51 GTEST_LOG_(INFO) << "TearDownCase";
52 }
53
SetUp()54 void SetUp() override
55 {
56 TestHelper::CreateEcmaVMWithScope(instance, thread, scope);
57 }
58
TearDown()59 void TearDown() override
60 {
61 TestHelper::DestroyEcmaVMWithScope(instance, scope);
62 }
63
64 EcmaVM *instance {nullptr};
65 EcmaHandleScope *scope {nullptr};
66 JSThread *thread {nullptr};
67 };
68
JSObjectTestCreate(JSThread * thread)69 static JSObject *JSObjectTestCreate(JSThread *thread)
70 {
71 EcmaVM *ecmaVM = thread->GetEcmaVM();
72 ObjectFactory *factory = ecmaVM->GetFactory();
73 [[maybe_unused]] EcmaHandleScope scope(thread);
74 JSHandle<GlobalEnv> globalEnv = ecmaVM->GetGlobalEnv();
75 JSHandle<JSTaggedValue> jsFunc = globalEnv->GetObjectFunction();
76 return *factory->NewJSObjectByConstructor(JSHandle<JSFunction>(jsFunc), jsFunc);
77 }
78
CreateBuiltinsWeakMap(JSThread * thread)79 JSWeakMap *CreateBuiltinsWeakMap(JSThread *thread)
80 {
81 JSHandle<GlobalEnv> env = thread->GetEcmaVM()->GetGlobalEnv();
82 JSHandle<JSFunction> newTarget(env->GetBuiltinsWeakMapFunction());
83 // 4 : test case
84 auto ecmaRuntimeCallInfo = TestHelper::CreateEcmaRuntimeCallInfo(thread, newTarget.GetTaggedValue(), 4);
85 ecmaRuntimeCallInfo->SetFunction(newTarget.GetTaggedValue());
86 ecmaRuntimeCallInfo->SetThis(JSTaggedValue::Undefined());
87
88 [[maybe_unused]] auto prev = TestHelper::SetupFrame(thread, ecmaRuntimeCallInfo);
89 JSTaggedValue result = BuiltinsWeakMap::WeakMapConstructor(ecmaRuntimeCallInfo);
90 TestHelper::TearDownFrame(thread, prev);
91
92 EXPECT_TRUE(result.IsECMAObject());
93 return JSWeakMap::Cast(reinterpret_cast<TaggedObject *>(result.GetRawData()));
94 }
95
96 // new Map("abrupt").toString()
HWTEST_F_L0(BuiltinsWeakMapTest,CreateAndGetSize)97 HWTEST_F_L0(BuiltinsWeakMapTest, CreateAndGetSize)
98 {
99 ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
100 JSHandle<GlobalEnv> env = thread->GetEcmaVM()->GetGlobalEnv();
101 JSHandle<JSFunction> newTarget(env->GetBuiltinsWeakMapFunction());
102 JSHandle<JSWeakMap> map(thread, CreateBuiltinsWeakMap(thread));
103
104 JSHandle<TaggedArray> array(factory->NewTaggedArray(1));
105 JSHandle<TaggedArray> internalArray(factory->NewTaggedArray(2));
106 JSTaggedValue value(JSObjectTestCreate(thread));
107 internalArray->Set(thread, 0, value);
108 internalArray->Set(thread, 1, JSTaggedValue(0));
109 auto result = JSArray::CreateArrayFromList(thread, internalArray);
110 array->Set(thread, 0, result);
111
112 JSHandle<JSArray> values = JSArray::CreateArrayFromList(thread, array);
113
114 auto ecmaRuntimeCallInfo = TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), 6);
115 ecmaRuntimeCallInfo->SetFunction(newTarget.GetTaggedValue());
116 ecmaRuntimeCallInfo->SetThis(map.GetTaggedValue());
117 ecmaRuntimeCallInfo->SetCallArg(0, values.GetTaggedValue());
118 ecmaRuntimeCallInfo->SetNewTarget(newTarget.GetTaggedValue());
119
120 [[maybe_unused]] auto prev = TestHelper::SetupFrame(thread, ecmaRuntimeCallInfo);
121
122 JSTaggedValue result1 = BuiltinsWeakMap::WeakMapConstructor(ecmaRuntimeCallInfo);
123 JSHandle<JSWeakMap> weakMap(thread, JSWeakMap::Cast(reinterpret_cast<TaggedObject *>(result1.GetRawData())));
124 EXPECT_EQ(weakMap->GetSize(), 1);
125 }
126
HWTEST_F_L0(BuiltinsWeakMapTest,SetAndHas)127 HWTEST_F_L0(BuiltinsWeakMapTest, SetAndHas)
128 {
129 // create jsWeakMap
130 JSHandle<JSWeakMap> weakMap(thread, CreateBuiltinsWeakMap(thread));
131 JSHandle<JSTaggedValue> key(thread, JSObjectTestCreate(thread));
132
133 auto ecmaRuntimeCallInfo = TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), 8);
134 ecmaRuntimeCallInfo->SetFunction(JSTaggedValue::Undefined());
135 ecmaRuntimeCallInfo->SetThis(weakMap.GetTaggedValue());
136 ecmaRuntimeCallInfo->SetCallArg(0, key.GetTaggedValue());
137 ecmaRuntimeCallInfo->SetCallArg(1, JSTaggedValue(static_cast<int32_t>(1)));
138
139 {
140 [[maybe_unused]] auto prev = TestHelper::SetupFrame(thread, ecmaRuntimeCallInfo);
141 JSTaggedValue result1 = BuiltinsWeakMap::Has(ecmaRuntimeCallInfo);
142 TestHelper::TearDownFrame(thread, prev);
143
144 EXPECT_EQ(result1.GetRawData(), JSTaggedValue::False().GetRawData());
145 }
146
147 // test Set()
148 JSTaggedValue result2 = BuiltinsWeakMap::Set(ecmaRuntimeCallInfo);
149 EXPECT_TRUE(result2.IsECMAObject());
150 JSWeakMap *jsWeakMap = JSWeakMap::Cast(reinterpret_cast<TaggedObject *>(result2.GetRawData()));
151 EXPECT_EQ(jsWeakMap->GetSize(), 1);
152
153 // test Has()
154 auto ecmaRuntimeCallInfo1 = TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), 8);
155 ecmaRuntimeCallInfo1->SetFunction(JSTaggedValue::Undefined());
156 ecmaRuntimeCallInfo1->SetCallArg(0, key.GetTaggedValue());
157 ecmaRuntimeCallInfo1->SetCallArg(1, JSTaggedValue(static_cast<int32_t>(1)));
158 ecmaRuntimeCallInfo1->SetThis(JSTaggedValue(jsWeakMap));
159 {
160 [[maybe_unused]] auto prev = TestHelper::SetupFrame(thread, ecmaRuntimeCallInfo1);
161 JSTaggedValue result3 = BuiltinsWeakMap::Has(ecmaRuntimeCallInfo1);
162 TestHelper::TearDownFrame(thread, prev);
163
164 EXPECT_EQ(result3.GetRawData(), JSTaggedValue::True().GetRawData());
165 }
166 }
167
HWTEST_F_L0(BuiltinsWeakMapTest,DeleteAndRemove)168 HWTEST_F_L0(BuiltinsWeakMapTest, DeleteAndRemove)
169 {
170 // create jsWeakMap
171 JSHandle<JSWeakMap> weakMap(thread, CreateBuiltinsWeakMap(thread));
172
173 // add 40 keys
174 JSTaggedValue lastKey(JSTaggedValue::Undefined());
175 for (int i = 0; i < 40; i++) {
176 JSHandle<JSTaggedValue> key(thread, JSObjectTestCreate(thread));
177 auto ecmaRuntimeCallInfo = TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), 8);
178 ecmaRuntimeCallInfo->SetFunction(JSTaggedValue::Undefined());
179 ecmaRuntimeCallInfo->SetThis(weakMap.GetTaggedValue());
180 ecmaRuntimeCallInfo->SetCallArg(0, key.GetTaggedValue());
181 ecmaRuntimeCallInfo->SetCallArg(1, JSTaggedValue(static_cast<int32_t>(i)));
182
183 [[maybe_unused]] auto prev = TestHelper::SetupFrame(thread, ecmaRuntimeCallInfo);
184 JSTaggedValue result1 = BuiltinsWeakMap::Set(ecmaRuntimeCallInfo);
185 TestHelper::TearDownFrame(thread, prev);
186
187 EXPECT_TRUE(result1.IsECMAObject());
188 JSWeakMap *jsWeakMap = JSWeakMap::Cast(reinterpret_cast<TaggedObject *>(result1.GetRawData()));
189 EXPECT_EQ(jsWeakMap->GetSize(), static_cast<int>(i) + 1);
190 lastKey = key.GetTaggedValue();
191 }
192
193 // whether jsWeakMap has delete lastKey
194
195 auto ecmaRuntimeCallInfo1 = TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), 6);
196 ecmaRuntimeCallInfo1->SetFunction(JSTaggedValue::Undefined());
197 ecmaRuntimeCallInfo1->SetThis(weakMap.GetTaggedValue());
198 ecmaRuntimeCallInfo1->SetCallArg(0, lastKey);
199
200 [[maybe_unused]] auto prev = TestHelper::SetupFrame(thread, ecmaRuntimeCallInfo1);
201 JSTaggedValue result2 = BuiltinsWeakMap::Has(ecmaRuntimeCallInfo1);
202 TestHelper::TearDownFrame(thread, prev);
203
204 EXPECT_EQ(result2.GetRawData(), JSTaggedValue::True().GetRawData());
205
206 // delete
207 JSTaggedValue result3 = BuiltinsWeakMap::Delete(ecmaRuntimeCallInfo1);
208
209 EXPECT_EQ(result3.GetRawData(), JSTaggedValue::True().GetRawData());
210
211 // check deleteKey is deleted
212 JSTaggedValue result4 = BuiltinsWeakMap::Has(ecmaRuntimeCallInfo1);
213
214 EXPECT_EQ(result4.GetRawData(), JSTaggedValue::False().GetRawData());
215 }
216
HWTEST_F_L0(BuiltinsWeakMapTest,SymbolKey)217 HWTEST_F_L0(BuiltinsWeakMapTest, SymbolKey)
218 {
219 // create jsWeakMap
220 JSHandle<JSWeakMap> weakMap(thread, CreateBuiltinsWeakMap(thread));
221
222 // add 2 symbol keys
223 JSTaggedValue lastKey(JSTaggedValue::Undefined());
224 for (int i = 0; i < 2; i++) {
225 JSHandle<JSSymbol> symbolKey = thread->GetEcmaVM()->GetFactory()->NewJSSymbol();
226 JSHandle<JSTaggedValue> key(symbolKey);
227 auto ecmaRuntimeCallInfo =
228 TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), 8); // 8 means 2 call args
229 ecmaRuntimeCallInfo->SetFunction(JSTaggedValue::Undefined());
230 ecmaRuntimeCallInfo->SetThis(weakMap.GetTaggedValue());
231 ecmaRuntimeCallInfo->SetCallArg(0, key.GetTaggedValue());
232 ecmaRuntimeCallInfo->SetCallArg(1, JSTaggedValue(static_cast<int32_t>(i)));
233
234 [[maybe_unused]] auto prev = TestHelper::SetupFrame(thread, ecmaRuntimeCallInfo);
235 // set
236 JSTaggedValue result1 = BuiltinsWeakMap::Set(ecmaRuntimeCallInfo);
237 TestHelper::TearDownFrame(thread, prev);
238
239 EXPECT_TRUE(result1.IsECMAObject());
240 JSWeakMap *jsWeakMap = JSWeakMap::Cast(reinterpret_cast<TaggedObject *>(result1.GetRawData()));
241 EXPECT_EQ(jsWeakMap->GetSize(), static_cast<int>(i) + 1);
242 lastKey = key.GetTaggedValue();
243 }
244
245 // check whether jsWeakMap can get and delete lastKey
246
247 auto ecmaRuntimeCallInfo1 =
248 TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), 6); // 6 means 1 call arg
249 ecmaRuntimeCallInfo1->SetFunction(JSTaggedValue::Undefined());
250 ecmaRuntimeCallInfo1->SetThis(weakMap.GetTaggedValue());
251 ecmaRuntimeCallInfo1->SetCallArg(0, lastKey);
252
253 [[maybe_unused]] auto prev = TestHelper::SetupFrame(thread, ecmaRuntimeCallInfo1);
254 // get
255 JSTaggedValue result2 = BuiltinsWeakMap::Get(ecmaRuntimeCallInfo1);
256 TestHelper::TearDownFrame(thread, prev);
257 EXPECT_EQ(result2, JSTaggedValue(1));
258
259 // delete
260 JSTaggedValue result3 = BuiltinsWeakMap::Delete(ecmaRuntimeCallInfo1);
261 EXPECT_EQ(result3.GetRawData(), JSTaggedValue::True().GetRawData());
262
263 // check deleteKey is deleted
264 JSTaggedValue result4 = BuiltinsWeakMap::Has(ecmaRuntimeCallInfo1);
265 EXPECT_EQ(result4.GetRawData(), JSTaggedValue::False().GetRawData());
266 }
267 } // namespace panda::test
268