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