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 BaseTestWithScope<false> {
35 };
36
JSObjectCreate(JSThread * thread)37 JSFunction *JSObjectCreate(JSThread *thread)
38 {
39 EcmaVM *ecmaVM = thread->GetEcmaVM();
40 JSHandle<GlobalEnv> globalEnv = ecmaVM->GetGlobalEnv();
41 return globalEnv->GetObjectFunction().GetObject<JSFunction>();
42 }
43
HWTEST_F_L0(JSFunctionTest,Create)44 HWTEST_F_L0(JSFunctionTest, Create)
45 {
46 EcmaVM *ecmaVM = thread->GetEcmaVM();
47 JSHandle<GlobalEnv> env = ecmaVM->GetGlobalEnv();
48 JSHandle<JSFunction> funHandle = thread->GetEcmaVM()->GetFactory()->NewJSFunction(env);
49 EXPECT_TRUE(*funHandle != nullptr);
50 EXPECT_EQ(funHandle->GetProtoOrHClass(thread), JSTaggedValue::Hole());
51
52 JSHandle<LexicalEnv> lexicalEnv = thread->GetEcmaVM()->GetFactory()->NewLexicalEnv(0);
53 funHandle->SetLexicalEnv(thread, lexicalEnv.GetTaggedValue());
54 EXPECT_EQ(funHandle->GetLexicalEnv(thread), lexicalEnv.GetTaggedValue());
55 EXPECT_TRUE(*lexicalEnv != nullptr);
56 }
HWTEST_F_L0(JSFunctionTest,MakeConstructor)57 HWTEST_F_L0(JSFunctionTest, MakeConstructor)
58 {
59 EcmaVM *ecmaVM = thread->GetEcmaVM();
60 JSHandle<GlobalEnv> env = ecmaVM->GetGlobalEnv();
61 JSHandle<JSFunction> func = thread->GetEcmaVM()->GetFactory()->NewJSFunction(env, static_cast<void *>(nullptr),
62 FunctionKind::BASE_CONSTRUCTOR);
63 EXPECT_TRUE(*func != nullptr);
64 JSHandle<JSTaggedValue> funcHandle(func);
65 func->GetJSHClass()->SetExtensible(true);
66
67 JSHandle<JSObject> nullHandle(thread, JSTaggedValue::Null());
68 JSHandle<JSObject> obj = JSObject::ObjectCreate(thread, nullHandle);
69 JSHandle<JSTaggedValue> objValue(obj);
70
71 JSFunction::MakeConstructor(thread, func, objValue);
72
73 JSHandle<JSTaggedValue> constructorKey(
74 thread->GetEcmaVM()->GetFactory()->NewFromASCII("constructor"));
75
76 JSHandle<JSTaggedValue> protoKey(thread->GetEcmaVM()->GetFactory()->NewFromASCII("prototype"));
77 JSTaggedValue proto = JSObject::GetProperty(thread, funcHandle, protoKey).GetValue().GetTaggedValue();
78 JSTaggedValue constructor =
79 JSObject::GetProperty(thread, JSHandle<JSTaggedValue>(obj), constructorKey).GetValue().GetTaggedValue();
80 EXPECT_EQ(constructor, funcHandle.GetTaggedValue());
81 EXPECT_EQ(proto, obj.GetTaggedValue());
82 EXPECT_EQ(func->GetFunctionKind(thread), FunctionKind::BASE_CONSTRUCTOR);
83 }
84
HWTEST_F_L0(JSFunctionTest,OrdinaryHasInstance)85 HWTEST_F_L0(JSFunctionTest, OrdinaryHasInstance)
86 {
87 JSHandle<JSTaggedValue> objFun(thread, JSObjectCreate(thread));
88
89 JSHandle<JSObject> jsobject =
90 thread->GetEcmaVM()->GetFactory()->NewJSObjectByConstructor(JSHandle<JSFunction>(objFun), objFun);
91 JSHandle<JSTaggedValue> obj(thread, jsobject.GetTaggedValue());
92 EXPECT_TRUE(*jsobject != nullptr);
93
94 EcmaVM *ecmaVM = thread->GetEcmaVM();
95 JSHandle<GlobalEnv> globalEnv = ecmaVM->GetGlobalEnv();
96 JSHandle<JSTaggedValue> constructor = globalEnv->GetObjectFunction();
97 EXPECT_TRUE(ecmascript::JSFunction::OrdinaryHasInstance(thread, constructor, obj));
98 }
99
TestInvokeInternal(EcmaRuntimeCallInfo * argv)100 JSTaggedValue TestInvokeInternal(EcmaRuntimeCallInfo *argv)
101 {
102 if (argv->GetArgsNumber() == 1 && argv->GetCallArg(0).GetTaggedValue() == JSTaggedValue(1)) {
103 return BuiltinsBase::GetTaggedBoolean(true);
104 } else {
105 return BuiltinsBase::GetTaggedBoolean(false);
106 }
107 }
108
HWTEST_F_L0(JSFunctionTest,Invoke)109 HWTEST_F_L0(JSFunctionTest, Invoke)
110 {
111 EcmaVM *ecmaVM = thread->GetEcmaVM();
112 JSHandle<GlobalEnv> env = ecmaVM->GetGlobalEnv();
113 JSHandle<JSTaggedValue> hclass(thread, JSObjectCreate(thread));
114 JSHandle<JSTaggedValue> callee(
115 thread->GetEcmaVM()->GetFactory()->NewJSObjectByConstructor(JSHandle<JSFunction>::Cast(hclass), hclass));
116 EXPECT_TRUE(*callee != nullptr);
117
118 char keyArray[] = "invoked";
119 JSHandle<JSTaggedValue> calleeKey(thread->GetEcmaVM()->GetFactory()->NewFromASCII(&keyArray[0]));
120 JSHandle<JSFunction> calleeFunc =
121 thread->GetEcmaVM()->GetFactory()->NewJSFunction(env, reinterpret_cast<void *>(TestInvokeInternal));
122 calleeFunc->SetCallable(true);
123 JSHandle<JSTaggedValue> calleeValue(calleeFunc);
124 JSObject::SetProperty(thread, JSHandle<JSTaggedValue>(callee), calleeKey, calleeValue);
125 JSHandle<JSTaggedValue> undefined = thread->GlobalConstants()->GetHandledUndefined();
126 EcmaRuntimeCallInfo *info = EcmaInterpreter::NewRuntimeCallInfo(thread, undefined, callee, undefined, 1);
127 info->SetCallArg(JSTaggedValue(1));
128 JSTaggedValue res = JSFunction::Invoke(info, calleeKey);
129
130 JSTaggedValue ruler = BuiltinsBase::GetTaggedBoolean(true);
131 EXPECT_EQ(res.GetRawData(), ruler.GetRawData());
132 }
133
HWTEST_F_L0(JSFunctionTest,SetSymbolFunctionName)134 HWTEST_F_L0(JSFunctionTest, SetSymbolFunctionName)
135 {
136 ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
137 JSHandle<GlobalEnv> env = thread->GetEcmaVM()->GetGlobalEnv();
138 JSHandle<JSFunction> jsFunction = factory->NewJSFunction(env);
139 JSHandle<JSSymbol> symbol = factory->NewPublicSymbolWithChar("name");
140 JSHandle<EcmaString> name = factory->NewFromASCII("[name]");
141 JSHandle<JSTaggedValue> prefix(thread, JSTaggedValue::Undefined());
142 JSFunction::SetFunctionName(thread, JSHandle<JSFunctionBase>(jsFunction), JSHandle<JSTaggedValue>(symbol), prefix);
143 JSHandle<JSTaggedValue> functionName =
144 JSFunctionBase::GetFunctionName(thread, JSHandle<JSFunctionBase>(jsFunction));
145 EXPECT_TRUE(functionName->IsString());
146 EXPECT_TRUE(EcmaStringAccessor::StringsAreEqual(thread, *(JSHandle<EcmaString>(functionName)), *name));
147 }
148 } // namespace panda::test
149