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
32using namespace panda::ecmascript;
33using namespace panda::ecmascript::builtins;
34
35namespace panda::test {
36using BuiltinsWeakSet = ecmascript::builtins::BuiltinsWeakSet;
37using JSWeakSet = ecmascript::JSWeakSet;
38
39class BuiltinsWeakSetTest : public BaseTestWithScope<false> {
40};
41
42static 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
53JSWeakSet *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
71HWTEST_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
100HWTEST_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
139void 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
157void 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
181HWTEST_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
199HWTEST_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