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_ref.h"
17
18#include "ecmascript/base/builtins_base.h"
19#include "ecmascript/ecma_vm.h"
20#include "ecmascript/ecma_runtime_call_info.h"
21#include "ecmascript/global_env.h"
22#include "ecmascript/jobs/micro_job_queue.h"
23#include "ecmascript/js_weak_ref.h"
24#include "ecmascript/js_array.h"
25#include "ecmascript/js_handle.h"
26#include "ecmascript/js_hclass.h"
27#include "ecmascript/js_object-inl.h"
28#include "ecmascript/js_tagged_value.h"
29#include "ecmascript/js_thread.h"
30#include "ecmascript/object_factory.h"
31#include "ecmascript/tests/test_helper.h"
32#include "ecmascript/tagged_array-inl.h"
33
34
35using namespace panda::ecmascript;
36using namespace panda::ecmascript::builtins;
37using BuiltinsBase = panda::ecmascript::base::BuiltinsBase;
38
39namespace panda::test {
40using BuiltinsWeakRef = ecmascript::builtins::BuiltinsWeakRef;
41
42class BuiltinsWeakRefTest : public BaseTestWithScope<false> {
43};
44
45JSTaggedValue CreateWeakRefConstructor(JSThread *thread, JSTaggedValue target)
46{
47    JSHandle<GlobalEnv> env = thread->GetEcmaVM()->GetGlobalEnv();
48    JSHandle<JSObject> globalObject(thread, env->GetGlobalObject());
49    JSHandle<JSFunction> weakRef(env->GetBuiltinsWeakRefFunction());
50
51    auto ecmaRuntimeCallInfo = TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue(*weakRef), 6);
52    ecmaRuntimeCallInfo->SetFunction(weakRef.GetTaggedValue());
53    ecmaRuntimeCallInfo->SetThis(globalObject.GetTaggedValue());
54    ecmaRuntimeCallInfo->SetCallArg(0, target);
55
56    [[maybe_unused]] auto prev = TestHelper::SetupFrame(thread, ecmaRuntimeCallInfo);
57    JSTaggedValue result = BuiltinsWeakRef::WeakRefConstructor(ecmaRuntimeCallInfo);
58    TestHelper::TearDownFrame(thread, prev);
59    return result;
60}
61
62// new WeakRef(target)
63HWTEST_F_L0(BuiltinsWeakRefTest, WeakRefConstructor)
64{
65    JSHandle<GlobalEnv> env = thread->GetEcmaVM()->GetGlobalEnv();
66    ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
67    JSHandle<JSTaggedValue> objectFunc(env->GetObjectFunction());
68
69    JSHandle<JSObject> target(factory->NewJSObjectByConstructor(JSHandle<JSFunction>(objectFunc), objectFunc));
70
71    JSHandle<JSFunction> weakRef(env->GetBuiltinsWeakRefFunction());
72    JSHandle<JSObject> globalObject(thread, env->GetGlobalObject());
73
74    auto ecmaRuntimeCallInfo = TestHelper::CreateEcmaRuntimeCallInfo(thread, weakRef.GetTaggedValue(), 6);
75    ecmaRuntimeCallInfo->SetFunction(weakRef.GetTaggedValue());
76    ecmaRuntimeCallInfo->SetThis(globalObject.GetTaggedValue());
77    ecmaRuntimeCallInfo->SetCallArg(0, target.GetTaggedValue());
78
79    [[maybe_unused]] auto prev = TestHelper::SetupFrame(thread, ecmaRuntimeCallInfo);
80    JSTaggedValue result = BuiltinsWeakRef::WeakRefConstructor(ecmaRuntimeCallInfo);
81
82    ASSERT_TRUE(result.IsECMAObject());
83}
84
85// weakRef.Deref()
86HWTEST_F_L0(BuiltinsWeakRefTest, Deref1)
87{
88    JSHandle<GlobalEnv> env = thread->GetEcmaVM()->GetGlobalEnv();
89    ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
90    JSHandle<JSTaggedValue> objectFunc(env->GetObjectFunction());
91
92    JSHandle<JSObject> target(factory->NewJSObjectByConstructor(JSHandle<JSFunction>(objectFunc), objectFunc));
93    JSTaggedValue result = CreateWeakRefConstructor(thread, target.GetTaggedValue());
94    JSHandle<JSWeakRef> jsWeakRef(thread, JSWeakRef::Cast(reinterpret_cast<TaggedObject *>(result.GetRawData())));
95    auto ecmaRuntimeCallInfo = TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), 4);
96    ecmaRuntimeCallInfo->SetFunction(JSTaggedValue::Undefined());
97    ecmaRuntimeCallInfo->SetThis(jsWeakRef.GetTaggedValue());
98
99    [[maybe_unused]] auto prev = TestHelper::SetupFrame(thread, ecmaRuntimeCallInfo);
100    TestHelper::TearDownFrame(thread, prev);
101    JSTaggedValue result1 = BuiltinsWeakRef::Deref(ecmaRuntimeCallInfo);
102    ASSERT_EQ(result1, target.GetTaggedValue());
103}
104
105// weakRef.Deref()
106HWTEST_F_L0(BuiltinsWeakRefTest, Deref2)
107{
108    JSHandle<GlobalEnv> env = thread->GetEcmaVM()->GetGlobalEnv();
109    ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
110    JSHandle<JSTaggedValue> objectFunc(env->GetObjectFunction());
111    JSHandle<JSTaggedValue> formatStyle = thread->GlobalConstants()->GetHandledStyleString();
112    JSHandle<JSTaggedValue> styleKey(factory->NewFromASCII("currency"));
113    JSHandle<JSTaggedValue> styleValue(factory->NewFromASCII("EUR"));
114    JSHandle<JSObject> target(factory->NewJSObjectByConstructor(JSHandle<JSFunction>(objectFunc), objectFunc));
115    JSObject::SetProperty(thread, target, formatStyle, styleKey);
116    JSObject::SetProperty(thread, target, styleKey, styleValue);
117
118    JSTaggedValue result = CreateWeakRefConstructor(thread, target.GetTaggedValue());
119    JSHandle<JSWeakRef> jsWeakRef(thread, JSWeakRef::Cast(reinterpret_cast<TaggedObject *>(result.GetRawData())));
120    auto ecmaRuntimeCallInfo = TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), 4);
121    ecmaRuntimeCallInfo->SetFunction(JSTaggedValue::Undefined());
122    ecmaRuntimeCallInfo->SetThis(jsWeakRef.GetTaggedValue());
123
124    [[maybe_unused]] auto prev = TestHelper::SetupFrame(thread, ecmaRuntimeCallInfo);
125    TestHelper::TearDownFrame(thread, prev);
126    JSTaggedValue result1 = BuiltinsWeakRef::Deref(ecmaRuntimeCallInfo);
127    ASSERT_EQ(result1, target.GetTaggedValue());
128
129    JSObject::SetProperty(thread, target, styleKey, styleValue);
130    ASSERT_EQ(result1, target.GetTaggedValue());
131}
132
133// weakRef.Deref()
134HWTEST_F_L0(BuiltinsWeakRefTest, Deref3)
135{
136    EcmaVM *vm = thread->GetEcmaVM();
137    JSHandle<GlobalEnv> env = thread->GetEcmaVM()->GetGlobalEnv();
138    ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
139    JSHandle<JSTaggedValue> objectFunc(env->GetObjectFunction());
140
141    JSTaggedValue target =
142	    factory->NewJSObjectByConstructor(JSHandle<JSFunction>(objectFunc), objectFunc).GetTaggedValue();
143    JSTaggedValue result = CreateWeakRefConstructor(thread, target);
144    JSHandle<JSWeakRef> jsWeakRef(thread, JSWeakRef::Cast(reinterpret_cast<TaggedObject *>(result.GetRawData())));
145    JSTaggedValue result2 = JSTaggedValue::Undefined();
146
147    {
148        [[maybe_unused]] EcmaHandleScope handleScope(thread);
149        auto obj =
150	        factory->NewJSObjectByConstructor(JSHandle<JSFunction>(objectFunc), objectFunc);
151        target = obj.GetTaggedValue();
152        auto ecmaRuntimeCallInfo1 = TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), 4);
153        ecmaRuntimeCallInfo1->SetFunction(JSTaggedValue::Undefined());
154        ecmaRuntimeCallInfo1->SetThis(jsWeakRef.GetTaggedValue());
155
156        [[maybe_unused]] auto prev1 = TestHelper::SetupFrame(thread, ecmaRuntimeCallInfo1);
157        result2 = BuiltinsWeakRef::Deref(ecmaRuntimeCallInfo1);
158        TestHelper::TearDownFrame(thread, prev1);
159    }
160    vm->CollectGarbage(TriggerGCType::FULL_GC);
161    if (!thread->HasPendingException()) {
162        job::MicroJobQueue::ExecutePendingJob(thread, vm->GetJSThread()->GetCurrentEcmaContext()->GetMicroJobQueue());
163    }
164    vm->SetEnableForceGC(true);
165    ASSERT_TRUE(!result2.IsUndefined());
166}
167
168// symbol target
169HWTEST_F_L0(BuiltinsWeakRefTest, SymbolTarget)
170{
171    JSHandle<GlobalEnv> env = thread->GetEcmaVM()->GetGlobalEnv();
172    JSHandle<JSSymbol> symbolTarget = thread->GetEcmaVM()->GetFactory()->NewJSSymbol();
173    JSHandle<JSTaggedValue> target(symbolTarget);
174
175    JSHandle<JSFunction> weakRef(env->GetBuiltinsWeakRefFunction());
176
177    auto ecmaRuntimeCallInfo1 =
178        TestHelper::CreateEcmaRuntimeCallInfo(thread, weakRef.GetTaggedValue(), 6); // 6 means 1 call arg
179    ecmaRuntimeCallInfo1->SetFunction(weakRef.GetTaggedValue());
180    ecmaRuntimeCallInfo1->SetThis(JSTaggedValue::Undefined());
181    ecmaRuntimeCallInfo1->SetCallArg(0, target.GetTaggedValue());
182
183    // constructor
184    [[maybe_unused]] auto prev1 = TestHelper::SetupFrame(thread, ecmaRuntimeCallInfo1);
185    JSTaggedValue result1 = BuiltinsWeakRef::WeakRefConstructor(ecmaRuntimeCallInfo1);
186    TestHelper::TearDownFrame(thread, prev1);
187    ASSERT_TRUE(result1.IsECMAObject());
188
189    JSHandle<JSWeakRef> jsWeakRef(thread, JSWeakRef::Cast(reinterpret_cast<TaggedObject *>(result1.GetRawData())));
190    auto ecmaRuntimeCallInfo2 =
191        TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), 4); // 4 means 0 call arg
192    ecmaRuntimeCallInfo2->SetFunction(JSTaggedValue::Undefined());
193    ecmaRuntimeCallInfo2->SetThis(jsWeakRef.GetTaggedValue());
194
195    // weakRef.Deref()
196    [[maybe_unused]] auto prev2 = TestHelper::SetupFrame(thread, ecmaRuntimeCallInfo2);
197    JSTaggedValue result2 = BuiltinsWeakRef::Deref(ecmaRuntimeCallInfo2);
198    TestHelper::TearDownFrame(thread, prev2);
199    ASSERT_EQ(result2, target.GetTaggedValue());
200}
201}  // namespace panda::test
202