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> handleValue(thread, JSTaggedValue(4));
166 JSHandle<JSTaggedValue> handleValue1(thread, JSTaggedValue(5));
167 ObjectOperator objectOperator1(thread, handleValue);
168 objectOperator1.SetIndex(1);
169
170 // object is not DictionaryMode
171 JSHandle<JSObject> handleObject = factory->NewJSObjectByConstructor(JSHandle<JSFunction>(objFunc), objFunc);
172 for (int i = 0; i < 3; i++) {
173 JSHandle<JSTaggedValue> newKey(thread, JSTaggedValue(i));
174 JSObject::SetProperty(thread, JSHandle<JSTaggedValue>(handleObject), newKey, newKey);
175 }
176 EXPECT_TRUE(objectOperator1.UpdateDataValue(handleObject, handleValue, false));
177 auto *resultElements =TaggedArray::Cast(handleObject->GetElements().GetTaggedObject());
178 EXPECT_EQ(resultElements->Get(objectOperator1.GetIndex()).GetInt(), 4);
179
180 // object is DictionaryMode
181 JSObject::DeleteProperty(thread, handleObject, handleKey2);
182 EXPECT_TRUE(objectOperator1.UpdateDataValue(handleObject, handleValue1, false));
183 auto *resultDict = NumberDictionary::Cast(handleObject->GetElements().GetTaggedObject());
184 EXPECT_EQ(resultDict->GetValue(objectOperator1.GetIndex()).GetInt(), 5);
185
186 // object value is InternalAccessor
187 JSHandle<AccessorData> handleAccessorData = factory->NewInternalAccessor(
188 reinterpret_cast<void*>(TestBoolSetter), nullptr);
189 JSHandle<JSTaggedValue> handleValue2(handleAccessorData);
190 ObjectOperator objectOperator2(thread, handleKey);
191 objectOperator2.SetValue(handleAccessorData.GetTaggedValue());
192 objectOperator2.SetIndex(1);
193 EXPECT_TRUE(objectOperator2.UpdateDataValue(handleObject, handleValue, true));
194 }
195
HWTEST_F_L0(ObjectOperatorTest,UpdateDataValue_002)196 HWTEST_F_L0(ObjectOperatorTest, UpdateDataValue_002)
197 {
198 ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
199 JSHandle<GlobalEnv> env = thread->GetEcmaVM()->GetGlobalEnv();
200 JSHandle<JSTaggedValue> objFunc(thread, JSObjectTestCreate(thread));
201 JSHandle<JSTaggedValue> handleKey(factory->NewFromASCII("key"));
202 JSHandle<JSTaggedValue> handleValue(thread, JSTaggedValue(100));
203 // object is JSGlobalObject
204 JSHandle<JSTaggedValue> globalObj = env->GetJSGlobalObject();
205 JSHandle<JSObject> handleGlobalObject(globalObj);
206
207 JSMutableHandle<GlobalDictionary> holderDict(thread, handleGlobalObject->GetProperties());
208 JSHandle<GlobalDictionary> handleDict = GlobalDictionary::Create(thread, 4); // numberofElements = 4
209 holderDict.Update(handleDict.GetTaggedValue());
210 JSHandle<PropertyBox> cellHandle = factory->NewPropertyBox(handleKey);
211 cellHandle->SetValue(thread, JSTaggedValue(4));
212 JSHandle<GlobalDictionary> handleProperties =
213 GlobalDictionary::PutIfAbsent(thread, holderDict, handleKey,
214 JSHandle<JSTaggedValue>(cellHandle), PropertyAttributes(4));
215 handleGlobalObject->SetProperties(thread, handleProperties.GetTaggedValue()); // Set Properties
216 int keyEntry = handleProperties->FindEntry(handleKey.GetTaggedValue());
217
218 ObjectOperator objectOperator(thread, handleGlobalObject, handleKey);
219 objectOperator.SetIndex(keyEntry);
220 EXPECT_TRUE(objectOperator.UpdateDataValue(handleGlobalObject, handleValue, false));
221 auto *resultDict = GlobalDictionary::Cast(handleGlobalObject->GetProperties().GetTaggedObject());
222 PropertyBox *resultCell = resultDict->GetBox(objectOperator.GetIndex());
223 EXPECT_EQ(resultCell->GetValue().GetInt(), 100);
224 }
225
HWTEST_F_L0(ObjectOperatorTest,UpdateDataValue_003)226 HWTEST_F_L0(ObjectOperatorTest, UpdateDataValue_003)
227 {
228 ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
229 JSHandle<JSTaggedValue> objFunc(thread, JSObjectTestCreate(thread));
230 JSHandle<JSTaggedValue> handleValue(thread, JSTaggedValue(4));
231 JSHandle<JSTaggedValue> handleValue1(thread, JSTaggedValue(3));
232 JSHandle<JSTaggedValue> handleKey(factory->NewFromASCII("key"));
233 JSHandle<EcmaString> handleKey1 = factory->NewFromASCII("value");
234 JSHandle<JSTaggedValue> handleKey2(factory->NewFromASCII("value1"));
235
236 ObjectOperator objectOperator(thread, handleKey);
237 objectOperator.SetIndex(1);
238 PropertyDescriptor handleDesc(thread);
239 PropertyAttributes handleAttr(handleDesc);
240 handleAttr.SetIsInlinedProps(true);
241 objectOperator.SetAttr(PropertyAttributes(handleDesc));
242
243 // object is not DictionaryMode
244 JSHandle<JSObject> handleObject = factory->NewJSObjectByConstructor(JSHandle<JSFunction>(objFunc), objFunc);
245 for (int i = 0; i < 10; i++) {
246 JSHandle<JSTaggedValue> newValue(thread, JSTaggedValue(i));
247 JSHandle<EcmaString> newString =
248 factory->ConcatFromString(handleKey1, JSTaggedValue::ToString(thread, newValue));
249 JSHandle<JSTaggedValue> newKey(thread, newString.GetTaggedValue());
250 JSObject::SetProperty(thread, JSHandle<JSTaggedValue>(handleObject), newKey, newValue);
251 }
252 EXPECT_TRUE(objectOperator.UpdateDataValue(handleObject, handleValue1, false));
253 EXPECT_EQ(handleObject->GetPropertyInlinedProps(objectOperator.GetIndex()).GetInt(), 3);
254
255 // object is DictionaryMode
256 JSObject::DeleteProperty(thread, handleObject, handleKey2);
257 EXPECT_TRUE(objectOperator.UpdateDataValue(handleObject, handleValue, false));
258 TaggedArray *resultElements2 = TaggedArray::Cast(handleObject->GetProperties().GetTaggedObject());
259 auto *resultDict = NumberDictionary::Cast(resultElements2);
260 EXPECT_EQ(resultDict->GetValue(objectOperator.GetIndex()).GetInt(), 4);
261 }
262 } // namespace panda::test