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