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 BaseTestWithScope<false> {
43 };
44
JSObjectTestCreate(JSThread *thread)45 static JSObject *JSObjectTestCreate(JSThread *thread)
46 {
47 EcmaVM *ecmaVM = thread->GetEcmaVM();
48 ObjectFactory *factory = ecmaVM->GetFactory();
49 [[maybe_unused]] EcmaHandleScope scope(thread);
50 JSHandle<GlobalEnv> globalEnv = ecmaVM->GetGlobalEnv();
51 JSHandle<JSTaggedValue> jsFunc = globalEnv->GetObjectFunction();
52 return *factory->NewJSObjectByConstructor(JSHandle<JSFunction>(jsFunc), jsFunc);
53 }
54
CreateBuiltinsWeakMap(JSThread *thread)55 JSWeakMap *CreateBuiltinsWeakMap(JSThread *thread)
56 {
57 JSHandle<GlobalEnv> env = thread->GetEcmaVM()->GetGlobalEnv();
58 JSHandle<JSFunction> newTarget(env->GetBuiltinsWeakMapFunction());
59 // 4 : test case
60 auto ecmaRuntimeCallInfo = TestHelper::CreateEcmaRuntimeCallInfo(thread, newTarget.GetTaggedValue(), 4);
61 ecmaRuntimeCallInfo->SetFunction(newTarget.GetTaggedValue());
62 ecmaRuntimeCallInfo->SetThis(JSTaggedValue::Undefined());
63
64 [[maybe_unused]] auto prev = TestHelper::SetupFrame(thread, ecmaRuntimeCallInfo);
65 JSTaggedValue result = BuiltinsWeakMap::WeakMapConstructor(ecmaRuntimeCallInfo);
66 TestHelper::TearDownFrame(thread, prev);
67
68 EXPECT_TRUE(result.IsECMAObject());
69 return JSWeakMap::Cast(reinterpret_cast<TaggedObject *>(result.GetRawData()));
70 }
71
72 // new Map("abrupt").toString()
HWTEST_F_L0(BuiltinsWeakMapTest, CreateAndGetSize)73 HWTEST_F_L0(BuiltinsWeakMapTest, CreateAndGetSize)
74 {
75 ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
76 JSHandle<GlobalEnv> env = thread->GetEcmaVM()->GetGlobalEnv();
77 JSHandle<JSFunction> newTarget(env->GetBuiltinsWeakMapFunction());
78 JSHandle<JSWeakMap> map(thread, CreateBuiltinsWeakMap(thread));
79
80 JSHandle<TaggedArray> array(factory->NewTaggedArray(1));
81 JSHandle<TaggedArray> internalArray(factory->NewTaggedArray(2));
82 JSTaggedValue value(JSObjectTestCreate(thread));
83 internalArray->Set(thread, 0, value);
84 internalArray->Set(thread, 1, JSTaggedValue(0));
85 auto result = JSArray::CreateArrayFromList(thread, internalArray);
86 array->Set(thread, 0, result);
87
88 JSHandle<JSArray> values = JSArray::CreateArrayFromList(thread, array);
89
90 auto ecmaRuntimeCallInfo = TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), 6);
91 ecmaRuntimeCallInfo->SetFunction(newTarget.GetTaggedValue());
92 ecmaRuntimeCallInfo->SetThis(map.GetTaggedValue());
93 ecmaRuntimeCallInfo->SetCallArg(0, values.GetTaggedValue());
94 ecmaRuntimeCallInfo->SetNewTarget(newTarget.GetTaggedValue());
95
96 [[maybe_unused]] auto prev = TestHelper::SetupFrame(thread, ecmaRuntimeCallInfo);
97
98 JSTaggedValue result1 = BuiltinsWeakMap::WeakMapConstructor(ecmaRuntimeCallInfo);
99 JSHandle<JSWeakMap> weakMap(thread, JSWeakMap::Cast(reinterpret_cast<TaggedObject *>(result1.GetRawData())));
100 EXPECT_EQ(weakMap->GetSize(), 1);
101 }
102
HWTEST_F_L0(BuiltinsWeakMapTest, SetAndHas)103 HWTEST_F_L0(BuiltinsWeakMapTest, SetAndHas)
104 {
105 // create jsWeakMap
106 JSHandle<JSWeakMap> weakMap(thread, CreateBuiltinsWeakMap(thread));
107 JSHandle<JSTaggedValue> key(thread, JSObjectTestCreate(thread));
108
109 auto ecmaRuntimeCallInfo = TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), 8);
110 ecmaRuntimeCallInfo->SetFunction(JSTaggedValue::Undefined());
111 ecmaRuntimeCallInfo->SetThis(weakMap.GetTaggedValue());
112 ecmaRuntimeCallInfo->SetCallArg(0, key.GetTaggedValue());
113 ecmaRuntimeCallInfo->SetCallArg(1, JSTaggedValue(static_cast<int32_t>(1)));
114
115 {
116 [[maybe_unused]] auto prev = TestHelper::SetupFrame(thread, ecmaRuntimeCallInfo);
117 JSTaggedValue result1 = BuiltinsWeakMap::Has(ecmaRuntimeCallInfo);
118 TestHelper::TearDownFrame(thread, prev);
119
120 EXPECT_EQ(result1.GetRawData(), JSTaggedValue::False().GetRawData());
121 }
122
123 // test Set()
124 JSTaggedValue result2 = BuiltinsWeakMap::Set(ecmaRuntimeCallInfo);
125 EXPECT_TRUE(result2.IsECMAObject());
126 JSWeakMap *jsWeakMap = JSWeakMap::Cast(reinterpret_cast<TaggedObject *>(result2.GetRawData()));
127 EXPECT_EQ(jsWeakMap->GetSize(), 1);
128
129 // test Has()
130 auto ecmaRuntimeCallInfo1 = TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), 8);
131 ecmaRuntimeCallInfo1->SetFunction(JSTaggedValue::Undefined());
132 ecmaRuntimeCallInfo1->SetCallArg(0, key.GetTaggedValue());
133 ecmaRuntimeCallInfo1->SetCallArg(1, JSTaggedValue(static_cast<int32_t>(1)));
134 ecmaRuntimeCallInfo1->SetThis(JSTaggedValue(jsWeakMap));
135 {
136 [[maybe_unused]] auto prev = TestHelper::SetupFrame(thread, ecmaRuntimeCallInfo1);
137 JSTaggedValue result3 = BuiltinsWeakMap::Has(ecmaRuntimeCallInfo1);
138 TestHelper::TearDownFrame(thread, prev);
139
140 EXPECT_EQ(result3.GetRawData(), JSTaggedValue::True().GetRawData());
141 }
142 }
143
KeySetCommon(JSThread* thread, JSHandle<JSWeakMap>& weakMap, JSHandle<JSTaggedValue>& key, int32_t val)144 void KeySetCommon(JSThread* thread, JSHandle<JSWeakMap>& weakMap, JSHandle<JSTaggedValue>& key, int32_t val)
145 {
146 auto ecmaRuntimeCallInfo = TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), 8);
147 ecmaRuntimeCallInfo->SetFunction(JSTaggedValue::Undefined());
148 ecmaRuntimeCallInfo->SetThis(weakMap.GetTaggedValue());
149 ecmaRuntimeCallInfo->SetCallArg(0, key.GetTaggedValue());
150 ecmaRuntimeCallInfo->SetCallArg(1, JSTaggedValue(val));
151
152 [[maybe_unused]] auto prev = TestHelper::SetupFrame(thread, ecmaRuntimeCallInfo);
153 JSTaggedValue result1 = BuiltinsWeakMap::Set(ecmaRuntimeCallInfo);
154 TestHelper::TearDownFrame(thread, prev);
155
156 EXPECT_TRUE(result1.IsECMAObject());
157 JSWeakMap *jsWeakMap = JSWeakMap::Cast(reinterpret_cast<TaggedObject *>(result1.GetRawData()));
158 EXPECT_EQ(jsWeakMap->GetSize(), static_cast<int>(val) + 1);
159 }
160
HWTEST_F_L0(BuiltinsWeakMapTest, DeleteAndRemove)161 HWTEST_F_L0(BuiltinsWeakMapTest, DeleteAndRemove)
162 {
163 // create jsWeakMap
164 JSHandle<JSWeakMap> weakMap(thread, CreateBuiltinsWeakMap(thread));
165
166 // add 40 keys
167 JSTaggedValue lastKey(JSTaggedValue::Undefined());
168 for (int i = 0; i < 40; i++) {
169 JSHandle<JSTaggedValue> key(thread, JSObjectTestCreate(thread));
170 KeySetCommon(thread, weakMap, key, static_cast<int32_t>(i));
171 lastKey = key.GetTaggedValue();
172 }
173
174 // whether jsWeakMap has delete lastKey
175
176 auto ecmaRuntimeCallInfo1 = TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), 6);
177 ecmaRuntimeCallInfo1->SetFunction(JSTaggedValue::Undefined());
178 ecmaRuntimeCallInfo1->SetThis(weakMap.GetTaggedValue());
179 ecmaRuntimeCallInfo1->SetCallArg(0, lastKey);
180
181 [[maybe_unused]] auto prev = TestHelper::SetupFrame(thread, ecmaRuntimeCallInfo1);
182 JSTaggedValue result2 = BuiltinsWeakMap::Has(ecmaRuntimeCallInfo1);
183 TestHelper::TearDownFrame(thread, prev);
184
185 EXPECT_EQ(result2.GetRawData(), JSTaggedValue::True().GetRawData());
186
187 // delete
188 JSTaggedValue result3 = BuiltinsWeakMap::Delete(ecmaRuntimeCallInfo1);
189
190 EXPECT_EQ(result3.GetRawData(), JSTaggedValue::True().GetRawData());
191
192 // check deleteKey is deleted
193 JSTaggedValue result4 = BuiltinsWeakMap::Has(ecmaRuntimeCallInfo1);
194
195 EXPECT_EQ(result4.GetRawData(), JSTaggedValue::False().GetRawData());
196 }
197
HWTEST_F_L0(BuiltinsWeakMapTest, SymbolKey)198 HWTEST_F_L0(BuiltinsWeakMapTest, SymbolKey)
199 {
200 // create jsWeakMap
201 JSHandle<JSWeakMap> weakMap(thread, CreateBuiltinsWeakMap(thread));
202
203 // add 2 symbol keys
204 JSTaggedValue lastKey(JSTaggedValue::Undefined());
205 for (int i = 0; i < 2; i++) {
206 JSHandle<JSSymbol> symbolKey = thread->GetEcmaVM()->GetFactory()->NewJSSymbol();
207 JSHandle<JSTaggedValue> key(symbolKey);
208 KeySetCommon(thread, weakMap, key, static_cast<int32_t>(i));
209 lastKey = key.GetTaggedValue();
210 }
211
212 // check whether jsWeakMap can get and delete lastKey
213
214 auto ecmaRuntimeCallInfo1 =
215 TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), 6); // 6 means 1 call arg
216 ecmaRuntimeCallInfo1->SetFunction(JSTaggedValue::Undefined());
217 ecmaRuntimeCallInfo1->SetThis(weakMap.GetTaggedValue());
218 ecmaRuntimeCallInfo1->SetCallArg(0, lastKey);
219
220 [[maybe_unused]] auto prev = TestHelper::SetupFrame(thread, ecmaRuntimeCallInfo1);
221 // get
222 JSTaggedValue result2 = BuiltinsWeakMap::Get(ecmaRuntimeCallInfo1);
223 TestHelper::TearDownFrame(thread, prev);
224 EXPECT_EQ(result2, JSTaggedValue(1));
225
226 // delete
227 JSTaggedValue result3 = BuiltinsWeakMap::Delete(ecmaRuntimeCallInfo1);
228 EXPECT_EQ(result3.GetRawData(), JSTaggedValue::True().GetRawData());
229
230 // check deleteKey is deleted
231 JSTaggedValue result4 = BuiltinsWeakMap::Has(ecmaRuntimeCallInfo1);
232 EXPECT_EQ(result4.GetRawData(), JSTaggedValue::False().GetRawData());
233 }
234 } // namespace panda::test
235