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