1 /*
2 * Copyright (c) 2022 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/global_env.h"
17 #include "ecmascript/accessor_data.h"
18 #include "ecmascript/object_factory.h"
19 #include "ecmascript/object_operator.h"
20 #include "ecmascript/tests/test_helper.h"
21
22 using namespace panda::ecmascript;
23
24 namespace panda::test {
25 class AccessorDataTest : public testing::Test {
26 public:
SetUpTestCase()27 static void SetUpTestCase()
28 {
29 GTEST_LOG_(INFO) << "SetUpTestCase";
30 }
31
TearDownTestCase()32 static void TearDownTestCase()
33 {
34 GTEST_LOG_(INFO) << "TearDownCase";
35 }
36
SetUp()37 void SetUp() override
38 {
39 TestHelper::CreateEcmaVMWithScope(instance, thread, scope);
40 }
41
TearDown()42 void TearDown() override
43 {
44 TestHelper::DestroyEcmaVMWithScope(instance, scope);
45 }
46
47 EcmaVM *instance {nullptr};
48 EcmaHandleScope *scope {nullptr};
49 JSThread *thread {nullptr};
50 };
51
52 /**
53 * @tc.name: Cast
54 * @tc.desc: Convert an object of type TaggedObject to type AccessorData object.
55 * @tc.type: FUNC
56 * @tc.require:
57 */
HWTEST_F_L0(AccessorDataTest,AccessorData_Cast)58 HWTEST_F_L0(AccessorDataTest, AccessorData_Cast)
59 {
60 ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
61 JSHandle<JSTaggedValue> nullHandle(thread, JSTaggedValue::Null());
62
63 JSHandle<JSHClass> accClassHandle =
64 factory->NewEcmaHClass(JSObject::SIZE, JSType::ACCESSOR_DATA, nullHandle);
65 TaggedObject *accObject = factory->NewObject(accClassHandle);
66 AccessorData::Cast(accObject)->SetGetter(thread, JSTaggedValue::Undefined());
67 AccessorData::Cast(accObject)->SetSetter(thread, JSTaggedValue::Undefined());
68 EXPECT_TRUE(JSTaggedValue(accObject).IsAccessorData());
69 AccessorData *acc = AccessorData::Cast(accObject);
70 EXPECT_TRUE(JSTaggedValue(acc).IsAccessorData());
71
72 JSHandle<JSHClass> internalAccClassHandle =
73 factory->NewEcmaHClass(JSObject::SIZE, JSType::INTERNAL_ACCESSOR, nullHandle);
74 TaggedObject *internalAccObject = factory->NewObject(internalAccClassHandle);
75 EXPECT_TRUE(JSTaggedValue(internalAccObject).IsInternalAccessor());
76 AccessorData *internalAcc = AccessorData::Cast(internalAccObject);
77 EXPECT_TRUE(JSTaggedValue(internalAcc).IsInternalAccessor());
78 }
79
80 /**
81 * @tc.name: IsInternal
82 * @tc.desc: Judge whether the accessor is internal.
83 * @tc.type: FUNC
84 * @tc.require:
85 */
HWTEST_F_L0(AccessorDataTest,IsInternal)86 HWTEST_F_L0(AccessorDataTest, IsInternal)
87 {
88 ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
89 JSHandle<AccessorData> accHandle = factory->NewAccessorData();
90 EXPECT_EQ(accHandle->IsInternal(), false);
91
92 void *setter = nullptr;
93 void *getter = nullptr;
94 JSHandle<AccessorData> internalAccHancle = factory->NewInternalAccessor(setter, getter);
95 EXPECT_EQ(internalAccHancle->IsInternal(), true);
96
97 JSHandle<JSTaggedValue> nullHandle(thread, JSTaggedValue::Null());
98 JSHandle<JSHClass> accClass = factory->NewEcmaHClass(JSObject::SIZE, JSType::ACCESSOR_DATA, nullHandle);
99 TaggedObject *accObject = factory->NewObject(accClass);
100 AccessorData *acc = AccessorData::Cast(accObject);
101 acc->SetGetter(thread, JSTaggedValue::Undefined());
102 acc->SetSetter(thread, JSTaggedValue::Undefined());
103 EXPECT_EQ(acc->IsInternal(), false);
104
105 JSHandle<JSHClass> internalAccClass =
106 factory->NewEcmaHClass(JSObject::SIZE, JSType::INTERNAL_ACCESSOR, nullHandle);
107 TaggedObject *internalAccObject = factory->NewObject(internalAccClass);
108 AccessorData *internalAcc = AccessorData::Cast(internalAccObject);
109 EXPECT_EQ(internalAcc->IsInternal(), true);
110 }
111
112 /**
113 * @tc.name: HasSetter
114 * @tc.desc: Judge whether the accessor have a undefined type "Setter".
115 * @tc.type: FUNC
116 * @tc.require:
117 */
HWTEST_F_L0(AccessorDataTest,HasSetter)118 HWTEST_F_L0(AccessorDataTest, HasSetter)
119 {
120 JSHandle<GlobalEnv> globalEnv = thread->GetEcmaVM()->GetGlobalEnv();
121 ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
122 JSHandle<JSTaggedValue> normalFunction = globalEnv->GetNormalFunctionClass();
123
124 // 1.Create normal AccessorData object by NewAccessorData function.
125 JSHandle<AccessorData> accHandle = factory->NewAccessorData();
126 EXPECT_EQ(accHandle->HasSetter(), false);
127 accHandle->SetSetter(thread, JSTaggedValue::Undefined());
128 EXPECT_EQ(accHandle->HasSetter(), false);
129 accHandle->SetSetter(thread, normalFunction);
130 EXPECT_EQ(accHandle->HasSetter(), true);
131
132 // 2.Create internal AccessorData object by NewInternalAccessor function.
133 void *setter = nullptr;
134 void *getter = nullptr;
135 JSHandle<AccessorData> internalAccHandle = factory->NewInternalAccessor(setter, getter);
136 EXPECT_EQ(internalAccHandle->HasSetter(), false);
137 internalAccHandle->SetSetter(thread, JSTaggedValue::Undefined());
138 EXPECT_EQ(internalAccHandle->HasSetter(), false);
139 internalAccHandle->SetSetter(thread, normalFunction);
140 EXPECT_EQ(internalAccHandle->HasSetter(), true);
141
142 // 3.Create normal AccessorData object from dynamic class.
143 JSHandle<JSTaggedValue> nullHandle(thread, JSTaggedValue::Null());
144 JSHandle<JSHClass> accClass = factory->NewEcmaHClass(JSObject::SIZE, JSType::ACCESSOR_DATA, nullHandle);
145 TaggedObject *accObject = factory->NewObject(accClass);
146 AccessorData *acc = AccessorData::Cast(accObject);
147 acc->SetGetter(thread, JSTaggedValue::Undefined());
148 EXPECT_EQ(acc->HasSetter(), true);
149 acc->SetSetter(thread, JSTaggedValue::Undefined());
150 EXPECT_EQ(acc->HasSetter(), false);
151 acc->SetSetter(thread, normalFunction);
152 EXPECT_EQ(acc->HasSetter(), true);
153
154 // 4.Create internal AccessorData object from dynamic class.
155 JSHandle<JSHClass> internalAccClass =
156 factory->NewEcmaHClass(JSObject::SIZE, JSType::INTERNAL_ACCESSOR, nullHandle);
157 TaggedObject *internalAccObject = factory->NewObject(internalAccClass);
158 AccessorData *internalAcc = AccessorData::Cast(internalAccObject);
159 EXPECT_EQ(internalAcc->HasSetter(), true);
160 internalAcc->SetSetter(thread, JSTaggedValue::Undefined());
161 EXPECT_EQ(internalAcc->HasSetter(), false);
162 internalAcc->SetSetter(thread, normalFunction);
163 EXPECT_EQ(internalAcc->HasSetter(), true);
164 }
165
166 /**
167 * @tc.name: CallInternalSet/CallInternalGet
168 * @tc.desc: Call internal set & get function to set object prototype.
169 * @tc.type: FUNC
170 * @tc.require:
171 */
HWTEST_F_L0(AccessorDataTest,CallInternalSet)172 HWTEST_F_L0(AccessorDataTest, CallInternalSet)
173 {
174 ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
175 JSHandle<GlobalEnv> globalEnv = thread->GetEcmaVM()->GetGlobalEnv();
176
177 // Construct objects and specify specific prototypes.
178 JSFunction *func1 = globalEnv->GetObjectFunction().GetObject<JSFunction>();
179 Method::Cast(func1->GetMethod().GetTaggedObject())->SetFunctionKind(FunctionKind::BASE_CONSTRUCTOR);
180 JSHandle<JSFunction> funcTagVal1 =
181 factory->CloneJSFuction(JSHandle<JSFunction>(thread, func1));
182
183 // Call the CallInternalGet method to inspect prototype.
184 JSHandle<JSTaggedValue> nullPrototypeHandle(thread, JSTaggedValue::Null());
185 JSHandle<JSHClass> accClass1 =
186 factory->NewEcmaHClass(JSObject::SIZE, JSType::INTERNAL_ACCESSOR, nullPrototypeHandle);
187 JSHandle<AccessorData> accObject1(thread, factory->NewObject(accClass1));
188 accObject1->SetGetter(thread, JSTaggedValue::Undefined());
189 accObject1->SetSetter(thread, JSTaggedValue::Undefined());
190 JSHandle<JSNativePointer> prototypeGetterFuncNativePtrHandle =
191 factory->NewJSNativePointer(reinterpret_cast<void *>(JSFunction::PrototypeGetter), nullptr, nullptr, true);
192 accObject1->SetGetter(thread, prototypeGetterFuncNativePtrHandle);
193
194 JSTaggedValue valNullPrototype = accObject1->CallInternalGet(thread, JSHandle<JSObject>::Cast(funcTagVal1));
195 EXPECT_NE(valNullPrototype.GetRawData(), JSTaggedValue::Undefined().GetRawData());
196
197 // Call the CallInternalSet method to set new prototype.
198 JSHandle<JSTaggedValue> undefPrototypeHandle(thread, JSTaggedValue::Undefined());
199 JSHandle<JSNativePointer> prototypeSetterFuncNativePtrHandle =
200 factory->NewJSNativePointer(reinterpret_cast<void *>(JSFunction::PrototypeSetter), nullptr, nullptr, true);
201 accObject1->SetSetter(thread, prototypeSetterFuncNativePtrHandle);
202 bool res1 = accObject1->CallInternalSet(thread, JSHandle<JSObject>::Cast(funcTagVal1), undefPrototypeHandle);
203 EXPECT_TRUE(res1);
204
205 // Call the CallInternalGet method to check the changed prototype.
206 valNullPrototype = accObject1->CallInternalGet(thread, JSHandle<JSObject>::Cast(funcTagVal1));
207 EXPECT_EQ(valNullPrototype.GetRawData(), JSTaggedValue::Undefined().GetRawData());
208 }
209
210 /**
211 * @tc.name: Cast
212 * @tc.desc: Convert an object of type TaggedObject to type CompletionRecord object.
213 * @tc.type: FUNC
214 * @tc.require:
215 */
HWTEST_F_L0(AccessorDataTest,CompletionRecord_Cast)216 HWTEST_F_L0(AccessorDataTest, CompletionRecord_Cast)
217 {
218 ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
219 JSHandle<JSTaggedValue> nullHandle(thread, JSTaggedValue::Null());
220
221 JSHandle<JSHClass> comRecordClassHandle =
222 factory->NewEcmaHClass(JSObject::SIZE, JSType::COMPLETION_RECORD, nullHandle);
223 TaggedObject *comRecordObject = factory->NewObject(comRecordClassHandle);
224 EXPECT_TRUE(JSTaggedValue(comRecordObject).IsCompletionRecord());
225 CompletionRecord *comRecord = CompletionRecord::Cast(comRecordObject);
226 EXPECT_TRUE(JSTaggedValue(comRecord).IsCompletionRecord());
227 }
228
229 /**
230 * @tc.name: IsThrow
231 * @tc.desc: Judge whether the completion record is THROW type.
232 * @tc.type: FUNC
233 * @tc.require:
234 */
HWTEST_F_L0(AccessorDataTest,IsThrow)235 HWTEST_F_L0(AccessorDataTest, IsThrow)
236 {
237 ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
238 JSHandle<JSTaggedValue> exceptionHandle(thread, thread->GetException());
239
240 JSHandle<CompletionRecord> normalComRecHandle =
241 factory->NewCompletionRecord(CompletionRecordType::NORMAL, exceptionHandle);
242 EXPECT_TRUE(!normalComRecHandle->IsThrow());
243
244 JSHandle<CompletionRecord> throwComRecHandle =
245 factory->NewCompletionRecord(CompletionRecordType::THROW, exceptionHandle);
246 EXPECT_TRUE(throwComRecHandle->IsThrow());
247 }
248 } // namespace panda::test
249