1 /*
2 * Copyright (c) 2022-2024 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/object_operator.h"
17 #include "ecmascript/ecma_string.h"
18 #include "ecmascript/global_env.h"
19 #include "ecmascript/global_dictionary-inl.h"
20 #include "ecmascript/js_array.h"
21 #include "ecmascript/js_object-inl.h"
22 #include "ecmascript/property_attributes.h"
23 #include "ecmascript/tagged_array.h"
24 #include "ecmascript/tagged_dictionary.h"
25 #include "ecmascript/tests/test_helper.h"
26
27 using namespace panda::ecmascript;
28
29 namespace panda::test {
30 class ObjectOperatorTest : public BaseTestWithScope<false> {
31 };
32
TestDefinedSetter(EcmaRuntimeCallInfo * argv)33 JSTaggedValue TestDefinedSetter([[maybe_unused]] EcmaRuntimeCallInfo *argv)
34 {
35 // 12 : test case
36 return JSTaggedValue(12);
37 }
38
JSObjectTestCreate(JSThread * thread)39 static JSFunction *JSObjectTestCreate(JSThread *thread)
40 {
41 JSHandle<GlobalEnv> globalEnv = thread->GetEcmaVM()->GetGlobalEnv();
42 return globalEnv->GetObjectFunction().GetObject<JSFunction>();
43 }
44
TestBoolSetter(JSThread * thread,const JSHandle<JSObject> & jsObject,const JSHandle<JSTaggedValue> & value,bool success)45 bool TestBoolSetter([[maybe_unused]] JSThread *thread,
46 [[maybe_unused]] const JSHandle<JSObject> &jsObject,
47 [[maybe_unused]] const JSHandle<JSTaggedValue> &value,
48 [[maybe_unused]] bool success)
49 {
50 return true;
51 }
52
HWTEST_F_L0(ObjectOperatorTest,ObjectOperator_Constructor1)53 HWTEST_F_L0(ObjectOperatorTest, ObjectOperator_Constructor1)
54 {
55 JSHandle<JSTaggedValue> handleKey(thread, JSTaggedValue(1));
56 OperatorType type = OperatorType::PROTOTYPE_CHAIN;
57 // ObjectOperator(thread, JSHandle<JSTaggedVale>(), type)
58 ObjectOperator objectOperator1(thread, handleKey, type);
59 EXPECT_TRUE(objectOperator1.IsOnPrototype());
60 EXPECT_TRUE(objectOperator1.GetReceiver()->IsJSGlobalObject());
61 EXPECT_FALSE(objectOperator1.GetHolder()->IsJSGlobalObject());
62 type = OperatorType::OWN;
63 ObjectOperator objectOperator2(thread, handleKey, type);
64 EXPECT_FALSE(objectOperator2.IsOnPrototype());
65 EXPECT_TRUE(objectOperator2.GetReceiver()->IsJSGlobalObject());
66 EXPECT_TRUE(objectOperator2.GetHolder()->IsJSGlobalObject());
67 }
68
HWTEST_F_L0(ObjectOperatorTest,ObjectOperator_Constructor2)69 HWTEST_F_L0(ObjectOperatorTest, ObjectOperator_Constructor2)
70 {
71 ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
72 JSHandle<JSTaggedValue> objFunc(thread, JSObjectTestCreate(thread));
73 JSHandle<JSObject> handleHolder = factory->NewJSObjectByConstructor(JSHandle<JSFunction>(objFunc), objFunc);
74 JSHandle<JSTaggedValue> handleKey(factory->NewFromASCII("key"));
75 OperatorType type = OperatorType::PROTOTYPE_CHAIN;
76 // ObjectOperator(thread, JSHandle<JSObject>(), JSHandle<JSTaggedVale>(), type)
77 ObjectOperator objectOperator1(thread, handleHolder, handleKey, type);
78 EXPECT_TRUE(objectOperator1.IsOnPrototype());
79 type = OperatorType::OWN;
80 ObjectOperator objectOperator2(thread, handleHolder, handleKey, type);
81 EXPECT_FALSE(objectOperator2.IsOnPrototype());
82 }
83
HWTEST_F_L0(ObjectOperatorTest,ObjectOperator_Constructor3)84 HWTEST_F_L0(ObjectOperatorTest, ObjectOperator_Constructor3)
85 {
86 ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
87 JSHandle<GlobalEnv> env = thread->GetEcmaVM()->GetGlobalEnv();
88 JSHandle<JSTaggedValue> symbolFunc = env->GetSymbolFunction();
89 JSHandle<JSTaggedValue> handleHolder(thread, symbolFunc.GetTaggedValue());
90 JSHandle<JSTaggedValue> handleReceiver(thread, symbolFunc.GetTaggedValue());
91 JSHandle<JSTaggedValue> handleKey(factory->NewFromASCII("key"));
92 OperatorType type = OperatorType::PROTOTYPE_CHAIN;
93 // ObjectOperator(thread, JSHandle<JSTaggedVale>(), JSHandle<JSTaggedVale>(), type)
94 ObjectOperator objectOperator1(thread, handleHolder, handleKey, type);
95 EXPECT_TRUE(objectOperator1.IsOnPrototype());
96 type = OperatorType::OWN;
97 ObjectOperator objectOperator2(thread, handleHolder, handleKey, type);
98 EXPECT_FALSE(objectOperator2.IsOnPrototype());
99 }
100
HWTEST_F_L0(ObjectOperatorTest,ObjectOperator_Constructor4)101 HWTEST_F_L0(ObjectOperatorTest, ObjectOperator_Constructor4)
102 {
103 JSHandle<GlobalEnv> env = thread->GetEcmaVM()->GetGlobalEnv();
104 JSHandle<JSTaggedValue> stringFunc = env->GetStringFunction();
105 JSHandle<JSTaggedValue> handleHolder(thread, stringFunc.GetTaggedValue());
106 JSHandle<JSTaggedValue> handleReceiver(thread, stringFunc.GetTaggedValue());
107 OperatorType type = OperatorType::PROTOTYPE_CHAIN;
108 // ObjectOperator(thread, JSHandle<JSTaggedVale>(), JSHandle<JSTaggedVale>(), type)
109 ObjectOperator objectOperator1(thread, handleHolder, handleReceiver, type);
110 EXPECT_TRUE(objectOperator1.IsOnPrototype());
111 type = OperatorType::OWN;
112 ObjectOperator objectOperator2(thread, handleHolder, handleReceiver, type);
113 EXPECT_FALSE(objectOperator2.IsOnPrototype());
114 }
115
HWTEST_F_L0(ObjectOperatorTest,ObjectOperator_Constructor5)116 HWTEST_F_L0(ObjectOperatorTest, ObjectOperator_Constructor5)
117 {
118 JSHandle<GlobalEnv> env = thread->GetEcmaVM()->GetGlobalEnv();
119 JSHandle<JSTaggedValue> boolFunc = env->GetBooleanFunction();
120 JSHandle<JSTaggedValue> handleHolder(thread, boolFunc.GetTaggedValue());
121 uint32_t index = 1;
122 OperatorType type = OperatorType::PROTOTYPE_CHAIN;
123 // ObjectOperator(thread, JSHandle<JSTaggedVale>(), index, type)
124 ObjectOperator objectOperator1(thread, handleHolder, index, type);
125 EXPECT_TRUE(objectOperator1.IsOnPrototype());
126 type = OperatorType::OWN;
127 ObjectOperator objectOperator2(thread, handleHolder, index, type);
128 EXPECT_FALSE(objectOperator2.IsOnPrototype());
129 }
130
HWTEST_F_L0(ObjectOperatorTest,ObjectOperator_Constructor6)131 HWTEST_F_L0(ObjectOperatorTest, ObjectOperator_Constructor6)
132 {
133 ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
134 JSHandle<GlobalEnv> env = thread->GetEcmaVM()->GetGlobalEnv();
135 JSHandle<JSTaggedValue> numFunc = env->GetNumberFunction();
136 JSHandle<JSTaggedValue> handleReceiver(thread, numFunc.GetTaggedValue());
137 JSHandle<JSTaggedValue> handleName(factory->NewFromASCII("name"));
138 OperatorType type = OperatorType::PROTOTYPE_CHAIN;
139 // ObjectOperator(thread, JSTaggedVale(), JSTaggedValue(), type)
140 ObjectOperator objectOperator1(thread, handleReceiver.GetTaggedValue(), handleName.GetTaggedValue(), type);
141 EXPECT_FALSE(objectOperator1.IsOnPrototype());
142 type = OperatorType::OWN;
143 ObjectOperator objectOperator2(thread, handleReceiver.GetTaggedValue(), handleName.GetTaggedValue(), type);
144 EXPECT_FALSE(objectOperator2.IsOnPrototype());
145 }
146
HWTEST_F_L0(ObjectOperatorTest,ObjectOperator_Constructor7)147 HWTEST_F_L0(ObjectOperatorTest, ObjectOperator_Constructor7)
148 {
149 JSHandle<JSTaggedValue> handleReceiver(thread, JSTaggedValue(1));
150 JSHandle<JSTaggedValue> handleName(thread, JSTaggedValue(2));
151 PropertyAttributes handleAttr(4);
152 // ObjectOperator(thread, JSTaggedVale(), JSTaggedValue(), PropertyAttributes())
153 ObjectOperator objectOperator(thread, handleReceiver.GetTaggedValue(), handleName.GetTaggedValue(), handleAttr);
154 EXPECT_EQ(objectOperator.GetReceiver()->GetInt(), 1);
155 EXPECT_EQ(objectOperator.GetAttr().GetPropertyMetaData(), 4);
156 EXPECT_EQ(objectOperator.GetKey()->GetInt(), 2);
157 }
158
HWTEST_F_L0(ObjectOperatorTest,UpdateDateValue_001)159 HWTEST_F_L0(ObjectOperatorTest, UpdateDateValue_001)
160 {
161 ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
162 JSHandle<JSTaggedValue> objFunc(thread, JSObjectTestCreate(thread));
163 JSHandle<JSTaggedValue> handleKey(factory->NewFromASCII("key"));
164 JSHandle<JSTaggedValue> handleKey2(thread, JSTaggedValue(2));
165 JSHandle<JSTaggedValue> handleKey3(thread, JSTaggedValue(102400));
166 JSHandle<JSTaggedValue> handleValue(thread, JSTaggedValue(4));
167 JSHandle<JSTaggedValue> handleValue1(thread, JSTaggedValue(5));
168 ObjectOperator objectOperator1(thread, handleValue);
169 objectOperator1.SetIndex(1);
170
171 // object is not DictionaryMode
172 JSHandle<JSObject> handleObject = factory->NewJSObjectByConstructor(JSHandle<JSFunction>(objFunc), objFunc);
173 for (int i = 0; i < 3; i++) {
174 JSHandle<JSTaggedValue> newKey(thread, JSTaggedValue(i));
175 JSObject::SetProperty(thread, JSHandle<JSTaggedValue>(handleObject), newKey, newKey);
176 }
177 EXPECT_TRUE(objectOperator1.UpdateDataValue(handleObject, handleValue, false));
178 auto *resultElements =TaggedArray::Cast(handleObject->GetElements().GetTaggedObject());
179 EXPECT_EQ(resultElements->Get(objectOperator1.GetIndex()).GetInt(), 4);
180
181 // object is DictionaryMode
182 JSObject::SetProperty(thread, JSHandle<JSTaggedValue>(handleObject), handleKey3, handleKey);
183 JSObject::DeleteProperty(thread, handleObject, handleKey3);
184 EXPECT_TRUE(objectOperator1.UpdateDataValue(handleObject, handleValue1, false));
185 auto *resultDict = NumberDictionary::Cast(handleObject->GetElements().GetTaggedObject());
186 EXPECT_EQ(resultDict->GetValue(objectOperator1.GetIndex()).GetInt(), 5);
187
188 // object value is InternalAccessor
189 JSHandle<AccessorData> handleAccessorData = factory->NewInternalAccessor(
190 reinterpret_cast<void*>(TestBoolSetter), nullptr);
191 JSHandle<JSTaggedValue> handleValue2(handleAccessorData);
192 ObjectOperator objectOperator2(thread, handleKey);
193 objectOperator2.SetValue(handleAccessorData.GetTaggedValue());
194 objectOperator2.SetIndex(1);
195 EXPECT_TRUE(objectOperator2.UpdateDataValue(handleObject, handleValue, true));
196 }
197
HWTEST_F_L0(ObjectOperatorTest,UpdateDataValue_002)198 HWTEST_F_L0(ObjectOperatorTest, UpdateDataValue_002)
199 {
200 ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
201 JSHandle<GlobalEnv> env = thread->GetEcmaVM()->GetGlobalEnv();
202 JSHandle<JSTaggedValue> objFunc(thread, JSObjectTestCreate(thread));
203 JSHandle<JSTaggedValue> handleKey(factory->NewFromASCII("key"));
204 JSHandle<JSTaggedValue> handleValue(thread, JSTaggedValue(100));
205 // object is JSGlobalObject
206 JSHandle<JSTaggedValue> globalObj = env->GetJSGlobalObject();
207 JSHandle<JSObject> handleGlobalObject(globalObj);
208
209 JSMutableHandle<GlobalDictionary> holderDict(thread, handleGlobalObject->GetProperties());
210 JSHandle<GlobalDictionary> handleDict = GlobalDictionary::Create(thread, 4); // numberofElements = 4
211 holderDict.Update(handleDict.GetTaggedValue());
212 JSHandle<PropertyBox> cellHandle = factory->NewPropertyBox(handleKey);
213 cellHandle->SetValue(thread, JSTaggedValue(4));
214 JSHandle<GlobalDictionary> handleProperties =
215 GlobalDictionary::PutIfAbsent(thread, holderDict, handleKey,
216 JSHandle<JSTaggedValue>(cellHandle), PropertyAttributes(4));
217 handleGlobalObject->SetProperties(thread, handleProperties.GetTaggedValue()); // Set Properties
218 int keyEntry = handleProperties->FindEntry(handleKey.GetTaggedValue());
219
220 ObjectOperator objectOperator(thread, handleGlobalObject, handleKey);
221 objectOperator.SetIndex(keyEntry);
222 EXPECT_TRUE(objectOperator.UpdateDataValue(handleGlobalObject, handleValue, false));
223 auto *resultDict = GlobalDictionary::Cast(handleGlobalObject->GetProperties().GetTaggedObject());
224 PropertyBox *resultCell = resultDict->GetBox(objectOperator.GetIndex());
225 EXPECT_EQ(resultCell->GetValue().GetInt(), 100);
226 }
227
HWTEST_F_L0(ObjectOperatorTest,UpdateDataValue_003)228 HWTEST_F_L0(ObjectOperatorTest, UpdateDataValue_003)
229 {
230 ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
231 JSHandle<JSTaggedValue> objFunc(thread, JSObjectTestCreate(thread));
232 JSHandle<JSTaggedValue> handleValue(thread, JSTaggedValue(4));
233 JSHandle<JSTaggedValue> handleValue1(thread, JSTaggedValue(3));
234 JSHandle<JSTaggedValue> handleKey(factory->NewFromASCII("key"));
235 JSHandle<EcmaString> handleKey1 = factory->NewFromASCII("value");
236 JSHandle<JSTaggedValue> handleKey2(factory->NewFromASCII("value1"));
237
238 ObjectOperator objectOperator(thread, handleKey);
239 objectOperator.SetIndex(1);
240 PropertyDescriptor handleDesc(thread);
241 PropertyAttributes handleAttr(handleDesc);
242 handleAttr.SetIsInlinedProps(true);
243 objectOperator.SetAttr(PropertyAttributes(handleDesc));
244
245 // object is not DictionaryMode
246 JSHandle<JSObject> handleObject = factory->NewJSObjectByConstructor(JSHandle<JSFunction>(objFunc), objFunc);
247 for (int i = 0; i < 10; i++) {
248 JSHandle<JSTaggedValue> newValue(thread, JSTaggedValue(i));
249 JSHandle<EcmaString> newString =
250 factory->ConcatFromString(handleKey1, JSTaggedValue::ToString(thread, newValue));
251 JSHandle<JSTaggedValue> newKey(thread, newString.GetTaggedValue());
252 JSObject::SetProperty(thread, JSHandle<JSTaggedValue>(handleObject), newKey, newValue);
253 }
254 EXPECT_TRUE(objectOperator.UpdateDataValue(handleObject, handleValue1, false));
255 EXPECT_EQ(handleObject->GetPropertyInlinedProps(objectOperator.GetIndex()).GetInt(), 3);
256
257 // object is DictionaryMode
258 JSObject::DeleteProperty(thread, handleObject, handleKey2);
259 EXPECT_TRUE(objectOperator.UpdateDataValue(handleObject, handleValue, false));
260 TaggedArray *resultElements2 = TaggedArray::Cast(handleObject->GetProperties().GetTaggedObject());
261 auto *resultDict = NumberDictionary::Cast(resultElements2);
262 EXPECT_EQ(resultDict->GetValue(objectOperator.GetIndex()).GetInt(), 4);
263 }
264 } // namespace panda::test