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