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 #include "ecmascript/ecma_string.h"
18 #include "ecmascript/ecma_vm.h"
19 #include "ecmascript/global_env.h"
20 #include "ecmascript/js_array.h"
21 #include "ecmascript/js_handle.h"
22 #include "ecmascript/js_hclass.h"
23 #include "ecmascript/js_object-inl.h"
24 #include "ecmascript/js_set_iterator.h"
25 #include "ecmascript/js_tagged_value.h"
26 #include "ecmascript/js_thread.h"
27
28 #include "ecmascript/js_weak_container.h"
29 #include "ecmascript/object_factory.h"
30 #include "ecmascript/tests/test_helper.h"
31 #include "utils/bit_utils.h"
32
33 using namespace panda::ecmascript;
34 using namespace panda::ecmascript::builtins;
35
36 namespace panda::test {
37 using BuiltinsWeakSet = ecmascript::builtins::BuiltinsWeakSet;
38 using JSWeakSet = ecmascript::JSWeakSet;
39
40 class BuiltinsWeakSetTest : public testing::Test {
41 public:
SetUpTestCase()42 static void SetUpTestCase()
43 {
44 GTEST_LOG_(INFO) << "SetUpTestCase";
45 }
46
TearDownTestCase()47 static void TearDownTestCase()
48 {
49 GTEST_LOG_(INFO) << "TearDownCase";
50 }
51
SetUp()52 void SetUp() override
53 {
54 TestHelper::CreateEcmaVMWithScope(instance, thread, scope);
55 }
56
TearDown()57 void TearDown() override
58 {
59 TestHelper::DestroyEcmaVMWithScope(instance, scope);
60 }
61
62 PandaVM *instance {nullptr};
63 EcmaHandleScope *scope {nullptr};
64 JSThread *thread {nullptr};
65 };
66
JSObjectTestCreate(JSThread * thread)67 static JSObject *JSObjectTestCreate(JSThread *thread)
68 {
69 [[maybe_unused]] EcmaHandleScope scope(thread);
70 EcmaVM *ecmaVM = thread->GetEcmaVM();
71 JSHandle<GlobalEnv> globalEnv = ecmaVM->GetGlobalEnv();
72 JSHandle<JSTaggedValue> jsFunc = globalEnv->GetObjectFunction();
73 JSHandle<JSObject> newObj =
74 thread->GetEcmaVM()->GetFactory()->NewJSObjectByConstructor(JSHandle<JSFunction>(jsFunc), jsFunc);
75 return *newObj;
76 }
77
CreateBuiltinsWeakSet(JSThread * thread)78 JSWeakSet *CreateBuiltinsWeakSet(JSThread *thread)
79 {
80 JSHandle<GlobalEnv> env = thread->GetEcmaVM()->GetGlobalEnv();
81 JSHandle<JSFunction> newTarget(env->GetBuiltinsWeakSetFunction());
82
83 // 4 : test case
84 auto ecmaRuntimeCallInfo = TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue(*newTarget), 4);
85 ecmaRuntimeCallInfo->SetFunction(newTarget.GetTaggedValue());
86 ecmaRuntimeCallInfo->SetThis(JSTaggedValue::Undefined());
87 [[maybe_unused]] auto prev = TestHelper::SetupFrame(thread, ecmaRuntimeCallInfo.get());
88 JSTaggedValue result = BuiltinsWeakSet::WeakSetConstructor(ecmaRuntimeCallInfo.get());
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.get());
116
117 JSTaggedValue result1 = BuiltinsWeakSet::WeakSetConstructor(ecmaRuntimeCallInfo.get());
118 JSHandle<JSWeakSet> weakSetResult(thread,
119 JSWeakSet::Cast(reinterpret_cast<TaggedObject *>(result1.GetRawData())));
120 EXPECT_EQ(weakSetResult->GetSize(), 5);
121 }
122
HWTEST_F_L0(BuiltinsWeakSetTest,AddAndHas)123 HWTEST_F_L0(BuiltinsWeakSetTest, AddAndHas)
124 {
125 // create jsWeakSet
126 JSHandle<JSWeakSet> weakSet(thread, CreateBuiltinsWeakSet(thread));
127 JSHandle<JSTaggedValue> key(thread, JSObjectTestCreate(thread));
128 auto ecmaRuntimeCallInfo = TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), 6);
129 ecmaRuntimeCallInfo->SetFunction(JSTaggedValue::Undefined());
130 ecmaRuntimeCallInfo->SetThis(weakSet.GetTaggedValue());
131 ecmaRuntimeCallInfo->SetCallArg(0, key.GetTaggedValue());
132
133 JSWeakSet *jsWeakSet;
134 {
135 [[maybe_unused]] auto prev = TestHelper::SetupFrame(thread, ecmaRuntimeCallInfo.get());
136 JSTaggedValue result1 = BuiltinsWeakSet::Has(ecmaRuntimeCallInfo.get());
137
138 EXPECT_EQ(result1.GetRawData(), JSTaggedValue::False().GetRawData());
139
140 // test Add()
141 JSTaggedValue result2 = BuiltinsWeakSet::Add(ecmaRuntimeCallInfo.get());
142 EXPECT_TRUE(result2.IsECMAObject());
143 jsWeakSet = JSWeakSet::Cast(reinterpret_cast<TaggedObject *>(result2.GetRawData()));
144 EXPECT_EQ(jsWeakSet->GetSize(), 1);
145 }
146
147 // test Has()
148 auto ecmaRuntimeCallInfo1 = TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), 6);
149 ecmaRuntimeCallInfo1->SetFunction(JSTaggedValue::Undefined());
150 ecmaRuntimeCallInfo1->SetThis(JSTaggedValue(jsWeakSet));
151 ecmaRuntimeCallInfo1->SetCallArg(0, key.GetTaggedValue());
152 {
153 [[maybe_unused]] auto prev = TestHelper::SetupFrame(thread, ecmaRuntimeCallInfo1.get());
154 JSTaggedValue result3 = BuiltinsWeakSet::Has(ecmaRuntimeCallInfo1.get());
155
156 EXPECT_EQ(result3.GetRawData(), JSTaggedValue::True().GetRawData());
157 }
158 }
159
HWTEST_F_L0(BuiltinsWeakSetTest,DeleteAndRemove)160 HWTEST_F_L0(BuiltinsWeakSetTest, DeleteAndRemove)
161 {
162 // create jsSet
163 JSHandle<JSWeakSet> weakSet(thread, CreateBuiltinsWeakSet(thread));
164
165 // add 40 keys
166 JSTaggedValue lastKey(JSTaggedValue::Undefined());
167 for (int i = 0; i < 40; i++) {
168 JSHandle<JSTaggedValue> key(thread, JSObjectTestCreate(thread));
169
170 auto ecmaRuntimeCallInfo = TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), 6);
171 ecmaRuntimeCallInfo->SetFunction(JSTaggedValue::Undefined());
172 ecmaRuntimeCallInfo->SetThis(weakSet.GetTaggedValue());
173 ecmaRuntimeCallInfo->SetCallArg(0, key.GetTaggedValue());
174
175 [[maybe_unused]] auto prev = TestHelper::SetupFrame(thread, ecmaRuntimeCallInfo.get());
176 JSTaggedValue result1 = BuiltinsWeakSet::Add(ecmaRuntimeCallInfo.get());
177
178 EXPECT_TRUE(result1.IsECMAObject());
179 JSWeakSet *jsWeakSet = JSWeakSet::Cast(reinterpret_cast<TaggedObject *>(result1.GetRawData()));
180 EXPECT_EQ(jsWeakSet->GetSize(), i + 1);
181 lastKey = key.GetTaggedValue();
182 }
183 // whether jsWeakSet has delete lastKey
184
185 auto ecmaRuntimeCallInfo1 = TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), 6);
186 ecmaRuntimeCallInfo1->SetFunction(JSTaggedValue::Undefined());
187 ecmaRuntimeCallInfo1->SetThis(weakSet.GetTaggedValue());
188 ecmaRuntimeCallInfo1->SetCallArg(0, lastKey);
189
190 [[maybe_unused]] auto prev = TestHelper::SetupFrame(thread, ecmaRuntimeCallInfo1.get());
191 JSTaggedValue result2 = BuiltinsWeakSet::Has(ecmaRuntimeCallInfo1.get());
192
193 EXPECT_EQ(result2.GetRawData(), JSTaggedValue::True().GetRawData());
194
195 // delete
196 JSTaggedValue result3 = BuiltinsWeakSet::Delete(ecmaRuntimeCallInfo1.get());
197
198 EXPECT_EQ(result3.GetRawData(), JSTaggedValue::True().GetRawData());
199
200 // check deleteKey is deleted
201 JSTaggedValue result4 = BuiltinsWeakSet::Has(ecmaRuntimeCallInfo1.get());
202
203 EXPECT_EQ(result4.GetRawData(), JSTaggedValue::False().GetRawData());
204 }
205 } // namespace panda::test
206