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_dictionary-inl.h" 17#include "ecmascript/symbol_table.h" 18#include "ecmascript/property_attributes.h" 19#include "ecmascript/tests/test_helper.h" 20 21using namespace panda::ecmascript; 22 23namespace panda::test { 24class GlobalDictionaryTest : public BaseTestWithScope<false> { 25}; 26 27/** 28 * @tc.name: IsMatch 29 * @tc.desc: Check whether two JSTaggedValue is equal through calling IsMatch function is within expectations. 30 * @tc.type: FUNC 31 * @tc.require: 32 */ 33HWTEST_F_L0(GlobalDictionaryTest, IsMatch) 34{ 35 ObjectFactory *factory = thread->GetEcmaVM()->GetFactory(); 36 37 JSHandle<EcmaString> globalKey = factory->NewFromASCII("key"); 38 JSTaggedValue globalOtherKey = globalKey.GetTaggedValue(); 39 40 EXPECT_EQ(GlobalDictionary::IsMatch(globalKey.GetTaggedValue(), globalOtherKey), true); 41 EXPECT_EQ(GlobalDictionary::IsMatch(globalKey.GetTaggedValue(), JSTaggedValue::Undefined()), false); 42} 43 44/** 45 * @tc.name: Hash 46 * @tc.desc: Check whether the hash size through calling Hash function is within expectations. 47 * @tc.type: FUNC 48 * @tc.require: 49 */ 50HWTEST_F_L0(GlobalDictionaryTest, Hash) 51{ 52 ObjectFactory *factory = thread->GetEcmaVM()->GetFactory(); 53 // test obj is jsSymbol 54 JSHandle<JSSymbol> jsSymbol = factory->NewJSSymbol(); 55 uint32_t hashField = static_cast<uint32_t>(GlobalDictionary::Hash(jsSymbol.GetTaggedValue())); 56 EXPECT_EQ(hashField, SymbolTable::Hash(jsSymbol.GetTaggedValue())); 57 58 // test obj is string(uint8_t) 59 uint8_t utf8ArrayName[4] = {0, 2, 5}; // The last element is "\0" 60 uint32_t utf8ArrayNameLen = sizeof(utf8ArrayName) - 1; 61 JSHandle<EcmaString> nameStringUtf8Obj = factory->NewFromUtf8(utf8ArrayName, utf8ArrayNameLen); 62 EXPECT_EQ(GlobalDictionary::Hash(nameStringUtf8Obj.GetTaggedValue()), 67); // 67 = (0 << 5 - 0 + 2) << 5 - 2 + 5 63 // test obj is string(uint16_t) 64 uint16_t utf16ArrayName[] = {0x1, 0x2, 0x1}; 65 uint32_t utf16ArrayNameLen = sizeof(utf16ArrayName) / sizeof(utf16ArrayName[0]); 66 JSHandle<EcmaString> nameStringUtf16Obj = factory->NewFromUtf16(utf16ArrayName, utf16ArrayNameLen); 67 // 1024 = (1 << 5 - 0 + 1) << 5 - 1 + 1 68 EXPECT_EQ(GlobalDictionary::Hash(nameStringUtf16Obj.GetTaggedValue()), 1024); 69} 70 71/** 72 * @tc.name: GetBoxAndValue 73 * @tc.desc: Check whether the Box and Value through calling SetEntry function is within expectations. 74 * @tc.type: FUNC 75 * @tc.require: 76 */ 77HWTEST_F_L0(GlobalDictionaryTest, GetBoxAndValue) 78{ 79 ObjectFactory *factory = thread->GetEcmaVM()->GetFactory(); 80 81 JSHandle<JSTaggedValue> globalKey(factory->NewFromASCII("key")); 82 JSHandle<JSTaggedValue> globalKey1(factory->NewFromASCII("value")); 83 JSHandle<JSTaggedValue> handleValue(thread, JSTaggedValue(123)); 84 JSHandle<JSTaggedValue> handleValue1(thread, JSTaggedValue(100)); 85 JSHandle<JSTaggedValue> propertyBox(factory->NewPropertyBox(handleValue)); 86 JSHandle<JSTaggedValue> propertyBox1(factory->NewPropertyBox(handleValue1)); 87 PropertyAttributes attribute(1); 88 // create GlobalDictionary 89 JSHandle<GlobalDictionary> handleDict = GlobalDictionary::Create(thread, 4); 90 EXPECT_TRUE(*handleDict != nullptr); 91 handleDict->SetEntry(thread, 0, globalKey.GetTaggedValue(), propertyBox.GetTaggedValue(), attribute); 92 // put value and cerate new dictionary 93 JSHandle<GlobalDictionary> newDict = 94 handleDict->PutIfAbsent(thread, handleDict, globalKey1, propertyBox1, attribute); 95 96 EXPECT_TRUE(handleDict->GetBox(0) != nullptr); 97 EXPECT_EQ(handleDict->GetValue(0).GetInt(), 123); 98 99 EXPECT_TRUE(newDict->GetBox(0) != nullptr); 100 EXPECT_EQ(newDict->GetValue(0).GetInt(), 123); 101 EXPECT_TRUE(newDict->GetBox(1) != nullptr); 102 EXPECT_EQ(newDict->GetValue(1).GetInt(), 100); 103} 104 105/** 106 * @tc.name: GetAttributes 107 * @tc.desc: Check whether the Attributes Get through calling SetAttributes function is within expectations. 108 * @tc.type: FUNC 109 * @tc.require: 110 */ 111HWTEST_F_L0(GlobalDictionaryTest, GetAttributes) 112{ 113 // create GlobalDictionary 114 int numberofElements = 4; 115 JSHandle<GlobalDictionary> handleDict = GlobalDictionary::Create(thread, numberofElements); 116 EXPECT_TRUE(*handleDict != nullptr); 117 // set attributes call SetAttributes function 118 for (int i = 0; i < numberofElements; i++) { 119 handleDict->SetAttributes(thread, i, PropertyAttributes(i)); 120 EXPECT_EQ(handleDict->GetAttributes(i).GetPropertyMetaData(), i); 121 } 122} 123 124/** 125 * @tc.name: ClearEntry 126 * @tc.desc: Create dictionary and set entry calling SetEntry function,Check whether Attributes is 127 * the same as Attributes after calling the ClearEntry function. 128 * @tc.type: FUNC 129 * @tc.require: 130 */ 131HWTEST_F_L0(GlobalDictionaryTest, ClearEntry) 132{ 133 // create GlobalDictionary 134 int numberofElements = 16; 135 JSHandle<GlobalDictionary> handleDict = GlobalDictionary::Create(thread, numberofElements); 136 EXPECT_TRUE(*handleDict != nullptr); 137 // set entry 138 for (int i = 0; i < numberofElements; i++) { 139 JSHandle<JSTaggedValue> handleValue(thread, JSTaggedValue(i)); 140 JSHandle<JSTaggedValue> handleValueKey(JSTaggedValue::ToString(thread, handleValue)); 141 handleDict->SetEntry(thread, i, handleValueKey.GetTaggedValue(), 142 handleValue.GetTaggedValue(), PropertyAttributes(i)); 143 } 144 // check attributes in three 145 EXPECT_EQ(handleDict->GetAttributes(3).GetPropertyMetaData(), 3); 146 handleDict->ClearEntry(thread, 3); 147 EXPECT_EQ(handleDict->GetAttributes(3).GetPropertyMetaData(), 0); 148} 149 150/** 151 * @tc.name: UpdateValueAndAttributes 152 * @tc.desc: Update value and Attributes through calling UpdateValueAndAttributes function. 153 * @tc.type: FUNC 154 * @tc.require: 155 */ 156HWTEST_F_L0(GlobalDictionaryTest, UpdateValueAndAttributes) 157{ 158 ObjectFactory *factory = thread->GetEcmaVM()->GetFactory(); 159 // create GlobalDictionary 160 int numberofElements = 16; 161 JSHandle<GlobalDictionary> handleDict = GlobalDictionary::Create(thread, numberofElements); 162 EXPECT_TRUE(*handleDict != nullptr); 163 // set entry 164 for (int i = 0; i < numberofElements; i++) { 165 JSHandle<JSTaggedValue> handleValue(thread, JSTaggedValue(i)); 166 JSHandle<JSTaggedValue> propertyBox(factory->NewPropertyBox(handleValue)); 167 JSHandle<JSTaggedValue> handleValueKey(JSTaggedValue::ToString(thread, handleValue)); 168 handleDict->SetEntry(thread, i, handleValueKey.GetTaggedValue(), 169 propertyBox.GetTaggedValue(), PropertyAttributes(i)); 170 } 171 // check attributes in five 172 EXPECT_EQ(handleDict->GetAttributes(5).GetPropertyMetaData(), 5); 173 EXPECT_EQ(handleDict->GetValue(5).GetInt(), 5); 174 // Update value and attributes 175 for (int i = 0; i < numberofElements; i++) { 176 JSHandle<JSTaggedValue> handleValue(thread, JSTaggedValue(static_cast<int>(i + 1))); 177 JSHandle<JSTaggedValue> propertyBox(factory->NewPropertyBox(handleValue)); 178 handleDict->UpdateValueAndAttributes(thread, i, propertyBox.GetTaggedValue(), 179 PropertyAttributes(static_cast<int>(i + 1))); 180 } 181 // check attributes in five 182 EXPECT_EQ(handleDict->GetAttributes(5).GetPropertyMetaData(), 6); 183 EXPECT_EQ(handleDict->GetValue(5).GetInt(), 6); 184} 185 186/** 187 * @tc.name: GetAllKeys 188 * @tc.desc: Get all Attributes from dictionary and store it in the TaggedArray. 189 * @tc.type: FUNC 190 * @tc.require: 191 */ 192HWTEST_F_L0(GlobalDictionaryTest, GetAllKeys) 193{ 194 ObjectFactory *factory = thread->GetEcmaVM()->GetFactory(); 195 // create GlobalDictionary 196 int numberofElements = 16; 197 std::vector<CString> nameKey = {"a", "b", "c", "d", "e", "f", 198 "g", "h", "i", "j", "k", "l", "m", "n", "o", "p"}; 199 JSHandle<GlobalDictionary> handleDict = GlobalDictionary::Create(thread, numberofElements); 200 EXPECT_TRUE(*handleDict != nullptr); 201 JSMutableHandle<GlobalDictionary> dictHandle(thread, handleDict); 202 for (int i = 0; i < numberofElements; i++) { 203 JSHandle<JSTaggedValue> handleValue(thread, JSTaggedValue(i)); 204 JSHandle<JSTaggedValue> handleNameKey(factory->NewFromASCII(nameKey[i])); 205 PropertyAttributes metaData; 206 // insert value 207 JSHandle<GlobalDictionary> dict(GlobalDictionary::PutIfAbsent(thread, dictHandle, 208 handleNameKey, handleValue, metaData)); 209 dictHandle.Update(dict.GetTaggedValue()); 210 } 211 uint32_t offset = 7; 212 // keyArray capacity must be enough for dictionary 213 int arraySize = numberofElements + static_cast<int>(offset); 214 JSHandle<TaggedArray> keyArray = factory->NewTaggedArray(arraySize); 215 dictHandle->GetAllKeys(thread, offset, *keyArray); 216 // Skip the first seven positions 217 for (uint32_t i = 0; i < offset; i++) { 218 EXPECT_TRUE(keyArray->Get(i).IsHole()); 219 } 220 // check key name 221 JSHandle<EcmaString> resultFirstKey(thread, keyArray->Get(offset)); 222 JSHandle<EcmaString> resultLastKey(thread, keyArray->Get(arraySize - 1)); 223 EXPECT_EQ(nameKey[0], EcmaStringAccessor(resultFirstKey).ToCString().c_str()); 224 EXPECT_EQ(nameKey[15], EcmaStringAccessor(resultLastKey).ToCString().c_str()); 225} 226 227/** 228 * @tc.name: GetEnumAllKeys 229 * @tc.desc: Get all Enumerable Attributes from dictionary and store it in the TaggedArray. 230 * @tc.type: FUNC 231 * @tc.require: 232 */ 233HWTEST_F_L0(GlobalDictionaryTest, GetEnumAllKeys) 234{ 235 ObjectFactory *factory = thread->GetEcmaVM()->GetFactory(); 236 // create GlobalDictionary 237 int numberofElements = 16; 238 std::vector<CString> nameKey = {"a", "b", "c", "d", "e", "f", 239 "g", "h", "i", "j", "k", "l", "m", "n", "o", "q"}; 240 JSHandle<GlobalDictionary> handleDict = GlobalDictionary::Create(thread, numberofElements); 241 EXPECT_TRUE(*handleDict != nullptr); 242 JSMutableHandle<GlobalDictionary> dictHandle(thread, handleDict); 243 bool enumerable; 244 for (int i = 0; i < numberofElements; i++) { 245 JSHandle<JSTaggedValue> handleValue(thread, JSTaggedValue(i)); 246 JSHandle<JSTaggedValue> handleNameKey(factory->NewFromASCII(nameKey[i])); 247 PropertyAttributes metaData; 248 enumerable = true; 249 if (!(i % 2)) { 250 enumerable = false; 251 } 252 metaData.SetEnumerable(enumerable); 253 // insert value 254 JSHandle<GlobalDictionary> dict(GlobalDictionary::PutIfAbsent(thread, dictHandle, 255 handleNameKey, handleValue, metaData)); 256 dictHandle.Update(dict.GetTaggedValue()); 257 } 258 uint32_t offset = 7; 259 uint32_t keys = 0; 260 // keyArray capacity must be enough for dictionary 261 uint32_t arraySize = static_cast<uint32_t>(numberofElements) + offset; 262 JSHandle<TaggedArray> keyArray = factory->NewTaggedArray(arraySize); 263 dictHandle->GetEnumAllKeys(thread, offset, *keyArray, &keys); 264 EXPECT_EQ(keys, 8U); 265 JSHandle<EcmaString> resultFirstKey(thread, keyArray->Get(offset)); 266 JSHandle<EcmaString> resultLastKey(thread, keyArray->Get(offset + keys - 1U)); 267 EXPECT_EQ(nameKey[1], EcmaStringAccessor(resultFirstKey).ToCString().c_str()); 268 EXPECT_EQ(nameKey[15], EcmaStringAccessor(resultLastKey).ToCString().c_str()); 269} 270 271/** 272 * @tc.name: CompKey 273 * @tc.desc: The second element in the two structures is compared.If it is less than,return true. 274 * @tc.type: FUNC 275 * @tc.require: 276 */ 277HWTEST_F_L0(GlobalDictionaryTest, CompKey) 278{ 279 std::pair<JSTaggedValue, uint32_t> a(JSTaggedValue(1), 1); 280 std::pair<JSTaggedValue, uint32_t> b(JSTaggedValue(2), 2); 281 std::pair<JSTaggedValue, uint32_t> c(JSTaggedValue(0), 0); 282 EXPECT_TRUE(GlobalDictionary::CompKey(a, b)); 283 EXPECT_TRUE(!GlobalDictionary::CompKey(a, c)); 284} 285 286/** 287 * @tc.name: InvalidatePropertyBox 288 * @tc.desc: Invalidate value which is Configurable in a dictionary. 289 * @tc.type: FUNC 290 * @tc.require: 291 */ 292HWTEST_F_L0(GlobalDictionaryTest, InvalidatePropertyBox) 293{ 294 ObjectFactory *factory = thread->GetEcmaVM()->GetFactory(); 295 // create GlobalDictionary 296 int numberofElements = 16; 297 std::vector<CString> nameKey = {"a", "b", "s", "t", "e", "f", 298 "g", "h", "i", "j", "k", "l", "m", "n", "o", "p"}; 299 JSHandle<GlobalDictionary> handleDict = GlobalDictionary::Create(thread, numberofElements); 300 EXPECT_TRUE(*handleDict != nullptr); 301 int invalidatedSet = 3; 302 int invalidatedPosition = 12; 303 for (int i = 0; i < numberofElements; i++) { 304 JSHandle<JSTaggedValue> handleKey(factory->NewFromASCII(nameKey[i])); 305 JSHandle<JSTaggedValue> handleValue(thread, JSTaggedValue(i)); 306 JSHandle<JSTaggedValue> propertyBox(factory->NewPropertyBox(handleValue)); 307 PropertyAttributes metaData; 308 if (i == invalidatedSet) { 309 metaData.SetDictionaryOrder(invalidatedPosition); 310 } 311 else if (i == invalidatedPosition) { 312 metaData.SetConfigurable(true); 313 } 314 handleDict->SetEntry(thread, i, handleKey.GetTaggedValue(), 315 propertyBox.GetTaggedValue(), metaData); 316 } 317 // calling InvalidatePropertyBox function to Invalidate the PropertyBox 318 PropertyAttributes newAttr(10); 319 GlobalDictionary::InvalidatePropertyBox(thread, handleDict, invalidatedPosition); 320 EXPECT_EQ(handleDict->GetAttributes(invalidatedPosition).GetBoxType(), PropertyBoxType::MUTABLE); 321 EXPECT_EQ(handleDict->GetAttributes(invalidatedSet).GetDictionaryOrder(), invalidatedPosition); 322 EXPECT_EQ(handleDict->GetValue(invalidatedPosition).GetInt(), invalidatedPosition); 323} 324} // namespace panda::test