• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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