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/base/builtins_base.h"
17 #include "ecmascript/builtins/builtins_weak_map.h"
18 #include "ecmascript/ecma_runtime_call_info.h"
19 #include "ecmascript/ecma_string.h"
20 #include "ecmascript/ecma_vm.h"
21 #include "ecmascript/global_env.h"
22 #include "ecmascript/js_array.h"
23 #include "ecmascript/js_handle.h"
24 #include "ecmascript/js_hclass.h"
25 #include "ecmascript/js_map_iterator.h"
26 #include "ecmascript/js_object-inl.h"
27 #include "ecmascript/js_tagged_value.h"
28 #include "ecmascript/js_thread.h"
29 #include "ecmascript/js_weak_container.h"
30 #include "ecmascript/object_factory.h"
31 #include "ecmascript/tagged_array-inl.h"
32 #include "ecmascript/tests/test_helper.h"
33 #include "utils/bit_utils.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 testing::Test {
43 public:
SetUpTestCase()44 static void SetUpTestCase()
45 {
46 GTEST_LOG_(INFO) << "SetUpTestCase";
47 }
48
TearDownTestCase()49 static void TearDownTestCase()
50 {
51 GTEST_LOG_(INFO) << "TearDownCase";
52 }
53
SetUp()54 void SetUp() override
55 {
56 TestHelper::CreateEcmaVMWithScope(instance, thread, scope);
57 }
58
TearDown()59 void TearDown() override
60 {
61 TestHelper::DestroyEcmaVMWithScope(instance, scope);
62 }
63
64 PandaVM *instance {nullptr};
65 EcmaHandleScope *scope {nullptr};
66 JSThread *thread {nullptr};
67 };
68
JSObjectTestCreate(JSThread * thread)69 static JSObject *JSObjectTestCreate(JSThread *thread)
70 {
71 EcmaVM *ecmaVM = thread->GetEcmaVM();
72 ObjectFactory *factory = ecmaVM->GetFactory();
73 [[maybe_unused]] EcmaHandleScope scope(thread);
74 JSHandle<GlobalEnv> globalEnv = ecmaVM->GetGlobalEnv();
75 JSHandle<JSTaggedValue> jsFunc = globalEnv->GetObjectFunction();
76 return *factory->NewJSObjectByConstructor(JSHandle<JSFunction>(jsFunc), jsFunc);
77 }
78
CreateBuiltinsWeakMap(JSThread * thread)79 JSWeakMap *CreateBuiltinsWeakMap(JSThread *thread)
80 {
81 JSHandle<GlobalEnv> env = thread->GetEcmaVM()->GetGlobalEnv();
82 JSHandle<JSFunction> newTarget(env->GetBuiltinsWeakMapFunction());
83 // 4 : test case
84 auto ecmaRuntimeCallInfo = TestHelper::CreateEcmaRuntimeCallInfo(thread, newTarget.GetTaggedValue(), 4);
85 ecmaRuntimeCallInfo->SetFunction(newTarget.GetTaggedValue());
86 ecmaRuntimeCallInfo->SetThis(JSTaggedValue::Undefined());
87
88 [[maybe_unused]] auto prev = TestHelper::SetupFrame(thread, ecmaRuntimeCallInfo.get());
89 JSTaggedValue result = BuiltinsWeakMap::WeakMapConstructor(ecmaRuntimeCallInfo.get());
90
91 EXPECT_TRUE(result.IsECMAObject());
92 return JSWeakMap::Cast(reinterpret_cast<TaggedObject *>(result.GetRawData()));
93 }
94
95 // new Map("abrupt").toString()
HWTEST_F_L0(BuiltinsWeakMapTest,CreateAndGetSize)96 HWTEST_F_L0(BuiltinsWeakMapTest, CreateAndGetSize)
97 {
98 ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
99 JSHandle<GlobalEnv> env = thread->GetEcmaVM()->GetGlobalEnv();
100 JSHandle<JSFunction> newTarget(env->GetBuiltinsWeakMapFunction());
101 JSHandle<JSWeakMap> map(thread, CreateBuiltinsWeakMap(thread));
102
103 JSHandle<TaggedArray> array(factory->NewTaggedArray(1));
104 JSHandle<TaggedArray> internal_array(factory->NewTaggedArray(2));
105 JSTaggedValue value(JSObjectTestCreate(thread));
106 internal_array->Set(thread, 0, value);
107 internal_array->Set(thread, 1, JSTaggedValue(0));
108 auto result = JSArray::CreateArrayFromList(thread, internal_array);
109 array->Set(thread, 0, result);
110
111 JSHandle<JSArray> values = JSArray::CreateArrayFromList(thread, array);
112
113 auto ecmaRuntimeCallInfo = TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), 6);
114 ecmaRuntimeCallInfo->SetFunction(newTarget.GetTaggedValue());
115 ecmaRuntimeCallInfo->SetThis(map.GetTaggedValue());
116 ecmaRuntimeCallInfo->SetCallArg(0, values.GetTaggedValue());
117 ecmaRuntimeCallInfo->SetNewTarget(newTarget.GetTaggedValue());
118
119 [[maybe_unused]] auto prev = TestHelper::SetupFrame(thread, ecmaRuntimeCallInfo.get());
120
121 JSTaggedValue result1 = BuiltinsWeakMap::WeakMapConstructor(ecmaRuntimeCallInfo.get());
122 JSHandle<JSWeakMap> weakMap(thread, JSWeakMap::Cast(reinterpret_cast<TaggedObject *>(result1.GetRawData())));
123 EXPECT_EQ(weakMap->GetSize(), 1);
124 }
125
HWTEST_F_L0(BuiltinsWeakMapTest,SetAndHas)126 HWTEST_F_L0(BuiltinsWeakMapTest, SetAndHas)
127 {
128 // create jsWeakMap
129 JSHandle<JSWeakMap> weakMap(thread, CreateBuiltinsWeakMap(thread));
130 JSHandle<JSTaggedValue> key(thread, JSObjectTestCreate(thread));
131
132 auto ecmaRuntimeCallInfo = TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), 8);
133 ecmaRuntimeCallInfo->SetFunction(JSTaggedValue::Undefined());
134 ecmaRuntimeCallInfo->SetThis(weakMap.GetTaggedValue());
135 ecmaRuntimeCallInfo->SetCallArg(0, key.GetTaggedValue());
136 ecmaRuntimeCallInfo->SetCallArg(1, JSTaggedValue(static_cast<int32_t>(1)));
137
138 {
139 [[maybe_unused]] auto prev = TestHelper::SetupFrame(thread, ecmaRuntimeCallInfo.get());
140 JSTaggedValue result1 = BuiltinsWeakMap::Has(ecmaRuntimeCallInfo.get());
141
142 EXPECT_EQ(result1.GetRawData(), JSTaggedValue::False().GetRawData());
143 }
144
145 // test Set()
146 JSTaggedValue result2 = BuiltinsWeakMap::Set(ecmaRuntimeCallInfo.get());
147 EXPECT_TRUE(result2.IsECMAObject());
148 JSWeakMap *jsWeakMap = JSWeakMap::Cast(reinterpret_cast<TaggedObject *>(result2.GetRawData()));
149 EXPECT_EQ(jsWeakMap->GetSize(), 1);
150
151 // test Has()
152 auto ecmaRuntimeCallInfo1 = TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), 8);
153 ecmaRuntimeCallInfo1->SetFunction(JSTaggedValue::Undefined());
154 ecmaRuntimeCallInfo1->SetCallArg(0, key.GetTaggedValue());
155 ecmaRuntimeCallInfo1->SetCallArg(1, JSTaggedValue(static_cast<int32_t>(1)));
156 ecmaRuntimeCallInfo1->SetThis(JSTaggedValue(jsWeakMap));
157 {
158 [[maybe_unused]] auto prev = TestHelper::SetupFrame(thread, ecmaRuntimeCallInfo1.get());
159 JSTaggedValue result3 = BuiltinsWeakMap::Has(ecmaRuntimeCallInfo1.get());
160
161 EXPECT_EQ(result3.GetRawData(), JSTaggedValue::True().GetRawData());
162 }
163 }
164
HWTEST_F_L0(BuiltinsWeakMapTest,DeleteAndRemove)165 HWTEST_F_L0(BuiltinsWeakMapTest, DeleteAndRemove)
166 {
167 // create jsWeakMap
168 JSHandle<JSWeakMap> weakMap(thread, CreateBuiltinsWeakMap(thread));
169
170 // add 40 keys
171 JSTaggedValue lastKey(JSTaggedValue::Undefined());
172 for (int i = 0; i < 40; i++) {
173 JSHandle<JSTaggedValue> key(thread, JSObjectTestCreate(thread));
174 auto ecmaRuntimeCallInfo = TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), 8);
175 ecmaRuntimeCallInfo->SetFunction(JSTaggedValue::Undefined());
176 ecmaRuntimeCallInfo->SetThis(weakMap.GetTaggedValue());
177 ecmaRuntimeCallInfo->SetCallArg(0, key.GetTaggedValue());
178 ecmaRuntimeCallInfo->SetCallArg(1, JSTaggedValue(static_cast<int32_t>(i)));
179
180 [[maybe_unused]] auto prev = TestHelper::SetupFrame(thread, ecmaRuntimeCallInfo.get());
181 JSTaggedValue result1 = BuiltinsWeakMap::Set(ecmaRuntimeCallInfo.get());
182
183 EXPECT_TRUE(result1.IsECMAObject());
184 JSWeakMap *jsWeakMap = JSWeakMap::Cast(reinterpret_cast<TaggedObject *>(result1.GetRawData()));
185 EXPECT_EQ(jsWeakMap->GetSize(), i + 1);
186 lastKey = key.GetTaggedValue();
187 }
188
189 // whether jsWeakMap has delete lastKey
190
191 auto ecmaRuntimeCallInfo1 = TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), 6);
192 ecmaRuntimeCallInfo1->SetFunction(JSTaggedValue::Undefined());
193 ecmaRuntimeCallInfo1->SetThis(weakMap.GetTaggedValue());
194 ecmaRuntimeCallInfo1->SetCallArg(0, lastKey);
195
196 [[maybe_unused]] auto prev = TestHelper::SetupFrame(thread, ecmaRuntimeCallInfo1.get());
197 JSTaggedValue result2 = BuiltinsWeakMap::Has(ecmaRuntimeCallInfo1.get());
198
199 EXPECT_EQ(result2.GetRawData(), JSTaggedValue::True().GetRawData());
200
201 // delete
202 JSTaggedValue result3 = BuiltinsWeakMap::Delete(ecmaRuntimeCallInfo1.get());
203
204 EXPECT_EQ(result3.GetRawData(), JSTaggedValue::True().GetRawData());
205
206 // check deleteKey is deleted
207 JSTaggedValue result4 = BuiltinsWeakMap::Has(ecmaRuntimeCallInfo1.get());
208
209 EXPECT_EQ(result4.GetRawData(), JSTaggedValue::False().GetRawData());
210 }
211 } // namespace panda::test
212