/* * Copyright (c) 2021 Huawei Device Co., Ltd. * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "ecmascript/js_function.h" #include "ecmascript/base/builtins_base.h" #include "ecmascript/ecma_string.h" #include "ecmascript/ecma_vm.h" #include "ecmascript/global_env.h" #include "ecmascript/interpreter/interpreter.h" #include "ecmascript/js_handle.h" #include "ecmascript/js_hclass.h" #include "ecmascript/js_object-inl.h" #include "ecmascript/object_factory.h" #include "ecmascript/tagged_array-inl.h" #include "ecmascript/tests/test_helper.h" using namespace panda::ecmascript; using namespace panda::ecmascript::base; namespace panda::test { class JSFunctionTest : public BaseTestWithScope { }; JSFunction *JSObjectCreate(JSThread *thread) { EcmaVM *ecmaVM = thread->GetEcmaVM(); JSHandle globalEnv = ecmaVM->GetGlobalEnv(); return globalEnv->GetObjectFunction().GetObject(); } HWTEST_F_L0(JSFunctionTest, Create) { EcmaVM *ecmaVM = thread->GetEcmaVM(); JSHandle env = ecmaVM->GetGlobalEnv(); JSHandle funHandle = thread->GetEcmaVM()->GetFactory()->NewJSFunction(env); EXPECT_TRUE(*funHandle != nullptr); EXPECT_EQ(funHandle->GetProtoOrHClass(), JSTaggedValue::Hole()); JSHandle lexicalEnv = thread->GetEcmaVM()->GetFactory()->NewLexicalEnv(0); funHandle->SetLexicalEnv(thread, lexicalEnv.GetTaggedValue()); EXPECT_EQ(funHandle->GetLexicalEnv(), lexicalEnv.GetTaggedValue()); EXPECT_TRUE(*lexicalEnv != nullptr); } HWTEST_F_L0(JSFunctionTest, MakeConstructor) { EcmaVM *ecmaVM = thread->GetEcmaVM(); JSHandle env = ecmaVM->GetGlobalEnv(); JSHandle func = thread->GetEcmaVM()->GetFactory()->NewJSFunction(env, static_cast(nullptr), FunctionKind::BASE_CONSTRUCTOR); EXPECT_TRUE(*func != nullptr); JSHandle funcHandle(func); func->GetJSHClass()->SetExtensible(true); JSHandle nullHandle(thread, JSTaggedValue::Null()); JSHandle obj = JSObject::ObjectCreate(thread, nullHandle); JSHandle objValue(obj); JSFunction::MakeConstructor(thread, func, objValue); JSHandle constructorKey( thread->GetEcmaVM()->GetFactory()->NewFromASCII("constructor")); JSHandle protoKey(thread->GetEcmaVM()->GetFactory()->NewFromASCII("prototype")); JSTaggedValue proto = JSObject::GetProperty(thread, funcHandle, protoKey).GetValue().GetTaggedValue(); JSTaggedValue constructor = JSObject::GetProperty(thread, JSHandle(obj), constructorKey).GetValue().GetTaggedValue(); EXPECT_EQ(constructor, funcHandle.GetTaggedValue()); EXPECT_EQ(proto, obj.GetTaggedValue()); EXPECT_EQ(func->GetFunctionKind(), FunctionKind::BASE_CONSTRUCTOR); } HWTEST_F_L0(JSFunctionTest, OrdinaryHasInstance) { JSHandle objFun(thread, JSObjectCreate(thread)); JSHandle jsobject = thread->GetEcmaVM()->GetFactory()->NewJSObjectByConstructor(JSHandle(objFun), objFun); JSHandle obj(thread, jsobject.GetTaggedValue()); EXPECT_TRUE(*jsobject != nullptr); EcmaVM *ecmaVM = thread->GetEcmaVM(); JSHandle globalEnv = ecmaVM->GetGlobalEnv(); JSHandle constructor = globalEnv->GetObjectFunction(); EXPECT_TRUE(ecmascript::JSFunction::OrdinaryHasInstance(thread, constructor, obj)); } JSTaggedValue TestInvokeInternal(EcmaRuntimeCallInfo *argv) { if (argv->GetArgsNumber() == 1 && argv->GetCallArg(0).GetTaggedValue() == JSTaggedValue(1)) { return BuiltinsBase::GetTaggedBoolean(true); } else { return BuiltinsBase::GetTaggedBoolean(false); } } HWTEST_F_L0(JSFunctionTest, Invoke) { EcmaVM *ecmaVM = thread->GetEcmaVM(); JSHandle env = ecmaVM->GetGlobalEnv(); JSHandle hclass(thread, JSObjectCreate(thread)); JSHandle callee( thread->GetEcmaVM()->GetFactory()->NewJSObjectByConstructor(JSHandle::Cast(hclass), hclass)); EXPECT_TRUE(*callee != nullptr); char keyArray[] = "invoked"; JSHandle calleeKey(thread->GetEcmaVM()->GetFactory()->NewFromASCII(&keyArray[0])); JSHandle calleeFunc = thread->GetEcmaVM()->GetFactory()->NewJSFunction(env, reinterpret_cast(TestInvokeInternal)); calleeFunc->SetCallable(true); JSHandle calleeValue(calleeFunc); JSObject::SetProperty(thread, JSHandle(callee), calleeKey, calleeValue); JSHandle undefined = thread->GlobalConstants()->GetHandledUndefined(); EcmaRuntimeCallInfo *info = EcmaInterpreter::NewRuntimeCallInfo(thread, undefined, callee, undefined, 1); info->SetCallArg(JSTaggedValue(1)); JSTaggedValue res = JSFunction::Invoke(info, calleeKey); JSTaggedValue ruler = BuiltinsBase::GetTaggedBoolean(true); EXPECT_EQ(res.GetRawData(), ruler.GetRawData()); } HWTEST_F_L0(JSFunctionTest, SetSymbolFunctionName) { ObjectFactory *factory = thread->GetEcmaVM()->GetFactory(); JSHandle env = thread->GetEcmaVM()->GetGlobalEnv(); JSHandle jsFunction = factory->NewJSFunction(env); JSHandle symbol = factory->NewPublicSymbolWithChar("name"); JSHandle name = factory->NewFromASCII("[name]"); JSHandle prefix(thread, JSTaggedValue::Undefined()); JSFunction::SetFunctionName(thread, JSHandle(jsFunction), JSHandle(symbol), prefix); JSHandle functionName = JSFunctionBase::GetFunctionName(thread, JSHandle(jsFunction)); EXPECT_TRUE(functionName->IsString()); EXPECT_TRUE(EcmaStringAccessor::StringsAreEqual(*(JSHandle(functionName)), *name)); } } // namespace panda::test