/* * Copyright (c) 2022 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/global_env.h" #include "ecmascript/accessor_data.h" #include "ecmascript/object_factory.h" #include "ecmascript/object_operator.h" #include "ecmascript/tests/test_helper.h" using namespace panda::ecmascript; namespace panda::test { class AccessorDataTest : public testing::Test { public: static void SetUpTestCase() { GTEST_LOG_(INFO) << "SetUpTestCase"; } static void TearDownTestCase() { GTEST_LOG_(INFO) << "TearDownCase"; } void SetUp() override { TestHelper::CreateEcmaVMWithScope(instance, thread, scope); } void TearDown() override { TestHelper::DestroyEcmaVMWithScope(instance, scope); } EcmaVM *instance {nullptr}; EcmaHandleScope *scope {nullptr}; JSThread *thread {nullptr}; }; /** * @tc.name: Cast * @tc.desc: Convert an object of type TaggedObject to type AccessorData object. * @tc.type: FUNC * @tc.require: */ HWTEST_F_L0(AccessorDataTest, AccessorData_Cast) { ObjectFactory *factory = thread->GetEcmaVM()->GetFactory(); JSHandle nullHandle(thread, JSTaggedValue::Null()); JSHandle accClassHandle = factory->NewEcmaHClass(JSObject::SIZE, JSType::ACCESSOR_DATA, nullHandle); TaggedObject *accObject = factory->NewObject(accClassHandle); AccessorData::Cast(accObject)->SetGetter(thread, JSTaggedValue::Undefined()); AccessorData::Cast(accObject)->SetSetter(thread, JSTaggedValue::Undefined()); EXPECT_TRUE(JSTaggedValue(accObject).IsAccessorData()); AccessorData *acc = AccessorData::Cast(accObject); EXPECT_TRUE(JSTaggedValue(acc).IsAccessorData()); JSHandle internalAccClassHandle = factory->NewEcmaHClass(JSObject::SIZE, JSType::INTERNAL_ACCESSOR, nullHandle); TaggedObject *internalAccObject = factory->NewObject(internalAccClassHandle); EXPECT_TRUE(JSTaggedValue(internalAccObject).IsInternalAccessor()); AccessorData *internalAcc = AccessorData::Cast(internalAccObject); EXPECT_TRUE(JSTaggedValue(internalAcc).IsInternalAccessor()); } /** * @tc.name: IsInternal * @tc.desc: Judge whether the accessor is internal. * @tc.type: FUNC * @tc.require: */ HWTEST_F_L0(AccessorDataTest, IsInternal) { ObjectFactory *factory = thread->GetEcmaVM()->GetFactory(); JSHandle accHandle = factory->NewAccessorData(); EXPECT_EQ(accHandle->IsInternal(), false); void *setter = nullptr; void *getter = nullptr; JSHandle internalAccHancle = factory->NewInternalAccessor(setter, getter); EXPECT_EQ(internalAccHancle->IsInternal(), true); JSHandle nullHandle(thread, JSTaggedValue::Null()); JSHandle accClass = factory->NewEcmaHClass(JSObject::SIZE, JSType::ACCESSOR_DATA, nullHandle); TaggedObject *accObject = factory->NewObject(accClass); AccessorData *acc = AccessorData::Cast(accObject); acc->SetGetter(thread, JSTaggedValue::Undefined()); acc->SetSetter(thread, JSTaggedValue::Undefined()); EXPECT_EQ(acc->IsInternal(), false); JSHandle internalAccClass = factory->NewEcmaHClass(JSObject::SIZE, JSType::INTERNAL_ACCESSOR, nullHandle); TaggedObject *internalAccObject = factory->NewObject(internalAccClass); AccessorData *internalAcc = AccessorData::Cast(internalAccObject); EXPECT_EQ(internalAcc->IsInternal(), true); } /** * @tc.name: HasSetter * @tc.desc: Judge whether the accessor have a undefined type "Setter". * @tc.type: FUNC * @tc.require: */ HWTEST_F_L0(AccessorDataTest, HasSetter) { JSHandle globalEnv = thread->GetEcmaVM()->GetGlobalEnv(); ObjectFactory *factory = thread->GetEcmaVM()->GetFactory(); JSHandle normalFunction = globalEnv->GetNormalFunctionClass(); // 1.Create normal AccessorData object by NewAccessorData function. JSHandle accHandle = factory->NewAccessorData(); EXPECT_EQ(accHandle->HasSetter(), false); accHandle->SetSetter(thread, JSTaggedValue::Undefined()); EXPECT_EQ(accHandle->HasSetter(), false); accHandle->SetSetter(thread, normalFunction); EXPECT_EQ(accHandle->HasSetter(), true); // 2.Create internal AccessorData object by NewInternalAccessor function. void *setter = nullptr; void *getter = nullptr; JSHandle internalAccHandle = factory->NewInternalAccessor(setter, getter); EXPECT_EQ(internalAccHandle->HasSetter(), false); internalAccHandle->SetSetter(thread, JSTaggedValue::Undefined()); EXPECT_EQ(internalAccHandle->HasSetter(), false); internalAccHandle->SetSetter(thread, normalFunction); EXPECT_EQ(internalAccHandle->HasSetter(), true); // 3.Create normal AccessorData object from dynamic class. JSHandle nullHandle(thread, JSTaggedValue::Null()); JSHandle accClass = factory->NewEcmaHClass(JSObject::SIZE, JSType::ACCESSOR_DATA, nullHandle); TaggedObject *accObject = factory->NewObject(accClass); AccessorData *acc = AccessorData::Cast(accObject); acc->SetGetter(thread, JSTaggedValue::Undefined()); EXPECT_EQ(acc->HasSetter(), true); acc->SetSetter(thread, JSTaggedValue::Undefined()); EXPECT_EQ(acc->HasSetter(), false); acc->SetSetter(thread, normalFunction); EXPECT_EQ(acc->HasSetter(), true); // 4.Create internal AccessorData object from dynamic class. JSHandle internalAccClass = factory->NewEcmaHClass(JSObject::SIZE, JSType::INTERNAL_ACCESSOR, nullHandle); TaggedObject *internalAccObject = factory->NewObject(internalAccClass); AccessorData *internalAcc = AccessorData::Cast(internalAccObject); EXPECT_EQ(internalAcc->HasSetter(), true); internalAcc->SetSetter(thread, JSTaggedValue::Undefined()); EXPECT_EQ(internalAcc->HasSetter(), false); internalAcc->SetSetter(thread, normalFunction); EXPECT_EQ(internalAcc->HasSetter(), true); } /** * @tc.name: CallInternalSet/CallInternalGet * @tc.desc: Call internal set & get function to set object prototype. * @tc.type: FUNC * @tc.require: */ HWTEST_F_L0(AccessorDataTest, CallInternalSet) { ObjectFactory *factory = thread->GetEcmaVM()->GetFactory(); JSHandle globalEnv = thread->GetEcmaVM()->GetGlobalEnv(); // Construct objects and specify specific prototypes. JSFunction *func1 = globalEnv->GetObjectFunction().GetObject(); Method::Cast(func1->GetMethod().GetTaggedObject())->SetFunctionKind(FunctionKind::BASE_CONSTRUCTOR); JSHandle funcTagVal1 = factory->CloneJSFuction(JSHandle(thread, func1)); // Call the CallInternalGet method to inspect prototype. JSHandle nullPrototypeHandle(thread, JSTaggedValue::Null()); JSHandle accClass1 = factory->NewEcmaHClass(JSObject::SIZE, JSType::INTERNAL_ACCESSOR, nullPrototypeHandle); JSHandle accObject1(thread, factory->NewObject(accClass1)); accObject1->SetGetter(thread, JSTaggedValue::Undefined()); accObject1->SetSetter(thread, JSTaggedValue::Undefined()); JSHandle prototypeGetterFuncNativePtrHandle = factory->NewJSNativePointer(reinterpret_cast(JSFunction::PrototypeGetter), nullptr, nullptr, true); accObject1->SetGetter(thread, prototypeGetterFuncNativePtrHandle); JSTaggedValue valNullPrototype = accObject1->CallInternalGet(thread, JSHandle::Cast(funcTagVal1)); EXPECT_NE(valNullPrototype.GetRawData(), JSTaggedValue::Undefined().GetRawData()); // Call the CallInternalSet method to set new prototype. JSHandle undefPrototypeHandle(thread, JSTaggedValue::Undefined()); JSHandle prototypeSetterFuncNativePtrHandle = factory->NewJSNativePointer(reinterpret_cast(JSFunction::PrototypeSetter), nullptr, nullptr, true); accObject1->SetSetter(thread, prototypeSetterFuncNativePtrHandle); bool res1 = accObject1->CallInternalSet(thread, JSHandle::Cast(funcTagVal1), undefPrototypeHandle); EXPECT_TRUE(res1); // Call the CallInternalGet method to check the changed prototype. valNullPrototype = accObject1->CallInternalGet(thread, JSHandle::Cast(funcTagVal1)); EXPECT_EQ(valNullPrototype.GetRawData(), JSTaggedValue::Undefined().GetRawData()); } /** * @tc.name: Cast * @tc.desc: Convert an object of type TaggedObject to type CompletionRecord object. * @tc.type: FUNC * @tc.require: */ HWTEST_F_L0(AccessorDataTest, CompletionRecord_Cast) { ObjectFactory *factory = thread->GetEcmaVM()->GetFactory(); JSHandle nullHandle(thread, JSTaggedValue::Null()); JSHandle comRecordClassHandle = factory->NewEcmaHClass(JSObject::SIZE, JSType::COMPLETION_RECORD, nullHandle); TaggedObject *comRecordObject = factory->NewObject(comRecordClassHandle); EXPECT_TRUE(JSTaggedValue(comRecordObject).IsCompletionRecord()); CompletionRecord *comRecord = CompletionRecord::Cast(comRecordObject); EXPECT_TRUE(JSTaggedValue(comRecord).IsCompletionRecord()); } /** * @tc.name: IsThrow * @tc.desc: Judge whether the completion record is THROW type. * @tc.type: FUNC * @tc.require: */ HWTEST_F_L0(AccessorDataTest, IsThrow) { ObjectFactory *factory = thread->GetEcmaVM()->GetFactory(); JSHandle exceptionHandle(thread, thread->GetException()); JSHandle normalComRecHandle = factory->NewCompletionRecord(CompletionRecordType::NORMAL, exceptionHandle); EXPECT_TRUE(!normalComRecHandle->IsThrow()); JSHandle throwComRecHandle = factory->NewCompletionRecord(CompletionRecordType::THROW, exceptionHandle); EXPECT_TRUE(throwComRecHandle->IsThrow()); } } // namespace panda::test