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/js_function.h"
17 #include "ecmascript/base/builtins_base.h"
18 #include "ecmascript/ecma_string.h"
19 #include "ecmascript/ecma_vm.h"
20 #include "ecmascript/global_env.h"
21 #include "ecmascript/interpreter/interpreter.h"
22 #include "ecmascript/js_handle.h"
23 #include "ecmascript/js_hclass.h"
24 #include "ecmascript/js_object-inl.h"
25 #include "ecmascript/object_factory.h"
26 #include "ecmascript/tagged_array-inl.h"
27 #include "ecmascript/tests/test_helper.h"
28
29 using namespace panda::ecmascript;
30
31 using namespace panda::ecmascript::base;
32
33 namespace panda::test {
34 class JSFunctionTest : public testing::Test {
35 public:
SetUpTestCase()36 static void SetUpTestCase()
37 {
38 GTEST_LOG_(INFO) << "SetUpTestCase";
39 }
40
TearDownTestCase()41 static void TearDownTestCase()
42 {
43 GTEST_LOG_(INFO) << "TearDownCase";
44 }
45
SetUp()46 void SetUp() override
47 {
48 TestHelper::CreateEcmaVMWithScope(instance, thread, scope);
49 }
50
TearDown()51 void TearDown() override
52 {
53 TestHelper::DestroyEcmaVMWithScope(instance, scope);
54 }
55
56 EcmaVM *instance {nullptr};
57 ecmascript::EcmaHandleScope *scope {nullptr};
58 JSThread *thread {nullptr};
59 };
60
JSObjectCreate(JSThread * thread)61 JSFunction *JSObjectCreate(JSThread *thread)
62 {
63 EcmaVM *ecmaVM = thread->GetEcmaVM();
64 JSHandle<GlobalEnv> globalEnv = ecmaVM->GetGlobalEnv();
65 return globalEnv->GetObjectFunction().GetObject<JSFunction>();
66 }
67
HWTEST_F_L0(JSFunctionTest,Create)68 HWTEST_F_L0(JSFunctionTest, Create)
69 {
70 EcmaVM *ecmaVM = thread->GetEcmaVM();
71 JSHandle<GlobalEnv> env = ecmaVM->GetGlobalEnv();
72 JSHandle<JSFunction> funHandle = thread->GetEcmaVM()->GetFactory()->NewJSFunction(env);
73 EXPECT_TRUE(*funHandle != nullptr);
74 EXPECT_EQ(funHandle->GetProtoOrHClass(), JSTaggedValue::Hole());
75
76 JSHandle<LexicalEnv> lexicalEnv = thread->GetEcmaVM()->GetFactory()->NewLexicalEnv(0);
77 funHandle->SetLexicalEnv(thread, lexicalEnv.GetTaggedValue());
78 EXPECT_EQ(funHandle->GetLexicalEnv(), lexicalEnv.GetTaggedValue());
79 EXPECT_TRUE(*lexicalEnv != nullptr);
80 }
HWTEST_F_L0(JSFunctionTest,MakeConstructor)81 HWTEST_F_L0(JSFunctionTest, MakeConstructor)
82 {
83 EcmaVM *ecmaVM = thread->GetEcmaVM();
84 JSHandle<GlobalEnv> env = ecmaVM->GetGlobalEnv();
85 JSHandle<JSFunction> func = thread->GetEcmaVM()->GetFactory()->NewJSFunction(env, static_cast<void *>(nullptr),
86 FunctionKind::BASE_CONSTRUCTOR);
87 EXPECT_TRUE(*func != nullptr);
88 JSHandle<JSTaggedValue> funcHandle(func);
89 func->GetJSHClass()->SetExtensible(true);
90
91 JSHandle<JSObject> nullHandle(thread, JSTaggedValue::Null());
92 JSHandle<JSObject> obj = JSObject::ObjectCreate(thread, nullHandle);
93 JSHandle<JSTaggedValue> objValue(obj);
94
95 JSFunction::MakeConstructor(thread, func, objValue);
96
97 JSHandle<JSTaggedValue> constructorKey(
98 thread->GetEcmaVM()->GetFactory()->NewFromASCII("constructor"));
99
100 JSHandle<JSTaggedValue> protoKey(thread->GetEcmaVM()->GetFactory()->NewFromASCII("prototype"));
101 JSTaggedValue proto = JSObject::GetProperty(thread, funcHandle, protoKey).GetValue().GetTaggedValue();
102 JSTaggedValue constructor =
103 JSObject::GetProperty(thread, JSHandle<JSTaggedValue>(obj), constructorKey).GetValue().GetTaggedValue();
104 EXPECT_EQ(constructor, funcHandle.GetTaggedValue());
105 EXPECT_EQ(proto, obj.GetTaggedValue());
106 EXPECT_EQ(func->GetFunctionKind(), FunctionKind::BASE_CONSTRUCTOR);
107 }
108
HWTEST_F_L0(JSFunctionTest,OrdinaryHasInstance)109 HWTEST_F_L0(JSFunctionTest, OrdinaryHasInstance)
110 {
111 JSHandle<JSTaggedValue> objFun(thread, JSObjectCreate(thread));
112
113 JSHandle<JSObject> jsobject =
114 thread->GetEcmaVM()->GetFactory()->NewJSObjectByConstructor(JSHandle<JSFunction>(objFun), objFun);
115 JSHandle<JSTaggedValue> obj(thread, jsobject.GetTaggedValue());
116 EXPECT_TRUE(*jsobject != nullptr);
117
118 EcmaVM *ecmaVM = thread->GetEcmaVM();
119 JSHandle<GlobalEnv> globalEnv = ecmaVM->GetGlobalEnv();
120 JSHandle<JSTaggedValue> constructor = globalEnv->GetObjectFunction();
121 EXPECT_TRUE(ecmascript::JSFunction::OrdinaryHasInstance(thread, constructor, obj));
122 }
123
TestInvokeInternal(EcmaRuntimeCallInfo * argv)124 JSTaggedValue TestInvokeInternal(EcmaRuntimeCallInfo *argv)
125 {
126 if (argv->GetArgsNumber() == 1 && argv->GetCallArg(0).GetTaggedValue() == JSTaggedValue(1)) {
127 return BuiltinsBase::GetTaggedBoolean(true);
128 } else {
129 return BuiltinsBase::GetTaggedBoolean(false);
130 }
131 }
132
HWTEST_F_L0(JSFunctionTest,Invoke)133 HWTEST_F_L0(JSFunctionTest, Invoke)
134 {
135 EcmaVM *ecmaVM = thread->GetEcmaVM();
136 JSHandle<GlobalEnv> env = ecmaVM->GetGlobalEnv();
137 JSHandle<JSTaggedValue> hclass(thread, JSObjectCreate(thread));
138 JSHandle<JSTaggedValue> callee(
139 thread->GetEcmaVM()->GetFactory()->NewJSObjectByConstructor(JSHandle<JSFunction>::Cast(hclass), hclass));
140 EXPECT_TRUE(*callee != nullptr);
141
142 char keyArray[] = "invoked";
143 JSHandle<JSTaggedValue> calleeKey(thread->GetEcmaVM()->GetFactory()->NewFromASCII(&keyArray[0]));
144 JSHandle<JSFunction> calleeFunc =
145 thread->GetEcmaVM()->GetFactory()->NewJSFunction(env, reinterpret_cast<void *>(TestInvokeInternal));
146 calleeFunc->SetCallable(true);
147 JSHandle<JSTaggedValue> calleeValue(calleeFunc);
148 JSObject::SetProperty(thread, JSHandle<JSTaggedValue>(callee), calleeKey, calleeValue);
149 JSHandle<JSTaggedValue> undefined = thread->GlobalConstants()->GetHandledUndefined();
150 EcmaRuntimeCallInfo *info = EcmaInterpreter::NewRuntimeCallInfo(thread, undefined, callee, undefined, 1);
151 info->SetCallArg(JSTaggedValue(1));
152 JSTaggedValue res = JSFunction::Invoke(info, calleeKey);
153
154 JSTaggedValue ruler = BuiltinsBase::GetTaggedBoolean(true);
155 EXPECT_EQ(res.GetRawData(), ruler.GetRawData());
156 }
157
HWTEST_F_L0(JSFunctionTest,SetSymbolFunctionName)158 HWTEST_F_L0(JSFunctionTest, SetSymbolFunctionName)
159 {
160 ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
161 JSHandle<GlobalEnv> env = thread->GetEcmaVM()->GetGlobalEnv();
162 JSHandle<JSFunction> jsFunction = factory->NewJSFunction(env);
163 JSHandle<JSSymbol> symbol = factory->NewPublicSymbolWithChar("name");
164 JSHandle<EcmaString> name = factory->NewFromASCII("[name]");
165 JSHandle<JSTaggedValue> prefix(thread, JSTaggedValue::Undefined());
166 JSFunction::SetFunctionName(thread, JSHandle<JSFunctionBase>(jsFunction), JSHandle<JSTaggedValue>(symbol), prefix);
167 JSHandle<JSTaggedValue> functionName =
168 JSFunctionBase::GetFunctionName(thread, JSHandle<JSFunctionBase>(jsFunction));
169 EXPECT_TRUE(functionName->IsString());
170 EXPECT_TRUE(EcmaStringAccessor::StringsAreEqual(*(JSHandle<EcmaString>(functionName)), *name));
171 }
172 } // namespace panda::test
173