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 27using namespace panda::ecmascript; 28 29namespace panda::test { 30class ObjectOperatorTest : public BaseTestWithScope<false> { 31}; 32 33JSTaggedValue TestDefinedSetter([[maybe_unused]] EcmaRuntimeCallInfo *argv) 34{ 35 // 12 : test case 36 return JSTaggedValue(12); 37} 38 39static JSFunction *JSObjectTestCreate(JSThread *thread) 40{ 41 JSHandle<GlobalEnv> globalEnv = thread->GetEcmaVM()->GetGlobalEnv(); 42 return globalEnv->GetObjectFunction().GetObject<JSFunction>(); 43} 44 45bool 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 53HWTEST_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 69HWTEST_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 84HWTEST_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 101HWTEST_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 116HWTEST_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 131HWTEST_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 147HWTEST_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 159HWTEST_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 196HWTEST_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 226HWTEST_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