/* * Copyright (c) 2022 Huawei Device Co., Ltd. * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "ecmascript/global_dictionary-inl.h" #include "ecmascript/symbol_table.h" #include "ecmascript/property_attributes.h" #include "ecmascript/tests/test_helper.h" using namespace panda::ecmascript; namespace panda::test { class GlobalDictionaryTest : public BaseTestWithScope { }; /** * @tc.name: IsMatch * @tc.desc: Check whether two JSTaggedValue is equal through calling IsMatch function is within expectations. * @tc.type: FUNC * @tc.require: */ HWTEST_F_L0(GlobalDictionaryTest, IsMatch) { ObjectFactory *factory = thread->GetEcmaVM()->GetFactory(); JSHandle globalKey = factory->NewFromASCII("key"); JSTaggedValue globalOtherKey = globalKey.GetTaggedValue(); EXPECT_EQ(GlobalDictionary::IsMatch(thread, globalKey.GetTaggedValue(), globalOtherKey), true); EXPECT_EQ(GlobalDictionary::IsMatch(thread, globalKey.GetTaggedValue(), JSTaggedValue::Undefined()), false); } /** * @tc.name: Hash * @tc.desc: Check whether the hash size through calling Hash function is within expectations. * @tc.type: FUNC * @tc.require: */ HWTEST_F_L0(GlobalDictionaryTest, Hash) { ObjectFactory *factory = thread->GetEcmaVM()->GetFactory(); // test obj is string(uint8_t) uint8_t utf8ArrayName[4] = {0, 2, 5}; // The last element is "\0" uint32_t utf8ArrayNameLen = sizeof(utf8ArrayName) - 1; JSHandle nameStringUtf8Obj = factory->NewFromUtf8(utf8ArrayName, utf8ArrayNameLen); // 67 = (0 << 5 - 0 + 2) << 5 - 2 + 5 EXPECT_EQ(GlobalDictionary::Hash(thread, nameStringUtf8Obj.GetTaggedValue()), 67); // test obj is string(uint16_t) uint16_t utf16ArrayName[] = {0x1, 0x2, 0x1}; uint32_t utf16ArrayNameLen = sizeof(utf16ArrayName) / sizeof(utf16ArrayName[0]); JSHandle nameStringUtf16Obj = factory->NewFromUtf16(utf16ArrayName, utf16ArrayNameLen); // 1024 = (1 << 5 - 0 + 1) << 5 - 1 + 1 EXPECT_EQ(GlobalDictionary::Hash(thread, nameStringUtf16Obj.GetTaggedValue()), 1024); } /** * @tc.name: GetBoxAndValue * @tc.desc: Check whether the Box and Value through calling SetEntry function is within expectations. * @tc.type: FUNC * @tc.require: */ HWTEST_F_L0(GlobalDictionaryTest, GetBoxAndValue) { ObjectFactory *factory = thread->GetEcmaVM()->GetFactory(); JSHandle globalKey(factory->NewFromASCII("key")); JSHandle globalKey1(factory->NewFromASCII("value")); JSHandle handleValue(thread, JSTaggedValue(123)); JSHandle handleValue1(thread, JSTaggedValue(100)); JSHandle propertyBox(factory->NewPropertyBox(handleValue)); JSHandle propertyBox1(factory->NewPropertyBox(handleValue1)); PropertyAttributes attribute(1); // create GlobalDictionary JSHandle handleDict = GlobalDictionary::Create(thread, 4); EXPECT_TRUE(*handleDict != nullptr); handleDict->SetEntry(thread, 0, globalKey.GetTaggedValue(), propertyBox.GetTaggedValue(), attribute); // put value and cerate new dictionary JSHandle newDict = handleDict->PutIfAbsent(thread, handleDict, globalKey1, propertyBox1, attribute); EXPECT_TRUE(handleDict->GetBox(thread, 0) != nullptr); EXPECT_EQ(handleDict->GetValue(thread, 0).GetInt(), 123); EXPECT_TRUE(newDict->GetBox(thread, 0) != nullptr); EXPECT_EQ(newDict->GetValue(thread, 0).GetInt(), 123); EXPECT_TRUE(newDict->GetBox(thread, 1) != nullptr); EXPECT_EQ(newDict->GetValue(thread, 1).GetInt(), 100); } /** * @tc.name: GetAttributes * @tc.desc: Check whether the Attributes Get through calling SetAttributes function is within expectations. * @tc.type: FUNC * @tc.require: */ HWTEST_F_L0(GlobalDictionaryTest, GetAttributes) { // create GlobalDictionary int numberofElements = 4; JSHandle handleDict = GlobalDictionary::Create(thread, numberofElements); EXPECT_TRUE(*handleDict != nullptr); // set attributes call SetAttributes function for (int i = 0; i < numberofElements; i++) { handleDict->SetAttributes(thread, i, PropertyAttributes(i)); EXPECT_EQ(handleDict->GetAttributes(thread, i).GetPropertyMetaData(), i); } } /** * @tc.name: ClearEntry * @tc.desc: Create dictionary and set entry calling SetEntry function,Check whether Attributes is * the same as Attributes after calling the ClearEntry function. * @tc.type: FUNC * @tc.require: */ HWTEST_F_L0(GlobalDictionaryTest, ClearEntry) { // create GlobalDictionary int numberofElements = 16; JSHandle handleDict = GlobalDictionary::Create(thread, numberofElements); EXPECT_TRUE(*handleDict != nullptr); // set entry for (int i = 0; i < numberofElements; i++) { JSHandle handleValue(thread, JSTaggedValue(i)); JSHandle handleValueKey(JSTaggedValue::ToString(thread, handleValue)); handleDict->SetEntry(thread, i, handleValueKey.GetTaggedValue(), handleValue.GetTaggedValue(), PropertyAttributes(i)); } // check attributes in three EXPECT_EQ(handleDict->GetAttributes(thread, 3).GetPropertyMetaData(), 3); handleDict->ClearEntry(thread, 3); EXPECT_EQ(handleDict->GetAttributes(thread, 3).GetPropertyMetaData(), 0); } /** * @tc.name: UpdateValueAndAttributes * @tc.desc: Update value and Attributes through calling UpdateValueAndAttributes function. * @tc.type: FUNC * @tc.require: */ HWTEST_F_L0(GlobalDictionaryTest, UpdateValueAndAttributes) { ObjectFactory *factory = thread->GetEcmaVM()->GetFactory(); // create GlobalDictionary int numberofElements = 16; JSHandle handleDict = GlobalDictionary::Create(thread, numberofElements); EXPECT_TRUE(*handleDict != nullptr); // set entry for (int i = 0; i < numberofElements; i++) { JSHandle handleValue(thread, JSTaggedValue(i)); JSHandle propertyBox(factory->NewPropertyBox(handleValue)); JSHandle handleValueKey(JSTaggedValue::ToString(thread, handleValue)); handleDict->SetEntry(thread, i, handleValueKey.GetTaggedValue(), propertyBox.GetTaggedValue(), PropertyAttributes(i)); } // check attributes in five EXPECT_EQ(handleDict->GetAttributes(thread, 5).GetPropertyMetaData(), 5); EXPECT_EQ(handleDict->GetValue(thread, 5).GetInt(), 5); // Update value and attributes for (int i = 0; i < numberofElements; i++) { JSHandle handleValue(thread, JSTaggedValue(static_cast(i + 1))); JSHandle propertyBox(factory->NewPropertyBox(handleValue)); handleDict->UpdateValueAndAttributes(thread, i, propertyBox.GetTaggedValue(), PropertyAttributes(static_cast(i + 1))); } // check attributes in five EXPECT_EQ(handleDict->GetAttributes(thread, 5).GetPropertyMetaData(), 6); EXPECT_EQ(handleDict->GetValue(thread, 5).GetInt(), 6); } /** * @tc.name: GetAllKeys * @tc.desc: Get all Attributes from dictionary and store it in the TaggedArray. * @tc.type: FUNC * @tc.require: */ HWTEST_F_L0(GlobalDictionaryTest, GetAllKeys) { ObjectFactory *factory = thread->GetEcmaVM()->GetFactory(); // create GlobalDictionary int numberofElements = 16; std::vector nameKey = {"a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p"}; JSHandle handleDict = GlobalDictionary::Create(thread, numberofElements); EXPECT_TRUE(*handleDict != nullptr); JSMutableHandle dictHandle(thread, handleDict); for (int i = 0; i < numberofElements; i++) { JSHandle handleValue(thread, JSTaggedValue(i)); JSHandle handleNameKey(factory->NewFromASCII(nameKey[i])); PropertyAttributes metaData; // insert value JSHandle dict(GlobalDictionary::PutIfAbsent(thread, dictHandle, handleNameKey, handleValue, metaData)); dictHandle.Update(dict.GetTaggedValue()); } uint32_t offset = 7; // keyArray capacity must be enough for dictionary int arraySize = numberofElements + static_cast(offset); JSHandle keyArray = factory->NewTaggedArray(arraySize); dictHandle->GetAllKeys(thread, offset, *keyArray); // Skip the first seven positions for (uint32_t i = 0; i < offset; i++) { EXPECT_TRUE(keyArray->Get(thread, i).IsHole()); } // check key name JSHandle resultFirstKey(thread, keyArray->Get(thread, offset)); JSHandle resultLastKey(thread, keyArray->Get(thread, arraySize - 1)); EXPECT_EQ(nameKey[0], EcmaStringAccessor(resultFirstKey).ToCString(thread).c_str()); EXPECT_EQ(nameKey[15], EcmaStringAccessor(resultLastKey).ToCString(thread).c_str()); } /** * @tc.name: GetEnumAllKeys * @tc.desc: Get all Enumerable Attributes from dictionary and store it in the TaggedArray. * @tc.type: FUNC * @tc.require: */ HWTEST_F_L0(GlobalDictionaryTest, GetEnumAllKeys) { ObjectFactory *factory = thread->GetEcmaVM()->GetFactory(); // create GlobalDictionary int numberofElements = 16; std::vector nameKey = {"a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "q"}; JSHandle handleDict = GlobalDictionary::Create(thread, numberofElements); EXPECT_TRUE(*handleDict != nullptr); JSMutableHandle dictHandle(thread, handleDict); bool enumerable; for (int i = 0; i < numberofElements; i++) { JSHandle handleValue(thread, JSTaggedValue(i)); JSHandle handleNameKey(factory->NewFromASCII(nameKey[i])); PropertyAttributes metaData; enumerable = true; if (!(i % 2)) { enumerable = false; } metaData.SetEnumerable(enumerable); // insert value JSHandle dict(GlobalDictionary::PutIfAbsent(thread, dictHandle, handleNameKey, handleValue, metaData)); dictHandle.Update(dict.GetTaggedValue()); } uint32_t offset = 7; uint32_t keys = 0; // keyArray capacity must be enough for dictionary uint32_t arraySize = static_cast(numberofElements) + offset; JSHandle keyArray = factory->NewTaggedArray(arraySize); dictHandle->GetEnumAllKeys(thread, offset, *keyArray, &keys); EXPECT_EQ(keys, 8U); JSHandle resultFirstKey(thread, keyArray->Get(thread, offset)); JSHandle resultLastKey(thread, keyArray->Get(thread, offset + keys - 1U)); EXPECT_EQ(nameKey[1], EcmaStringAccessor(resultFirstKey).ToCString(thread).c_str()); EXPECT_EQ(nameKey[15], EcmaStringAccessor(resultLastKey).ToCString(thread).c_str()); } /** * @tc.name: CompKey * @tc.desc: The second element in the two structures is compared.If it is less than,return true. * @tc.type: FUNC * @tc.require: */ HWTEST_F_L0(GlobalDictionaryTest, CompKey) { std::pair a(JSTaggedValue(1), 1); std::pair b(JSTaggedValue(2), 2); std::pair c(JSTaggedValue(0), 0); EXPECT_TRUE(GlobalDictionary::CompKey(a, b)); EXPECT_TRUE(!GlobalDictionary::CompKey(a, c)); } /** * @tc.name: InvalidatePropertyBox * @tc.desc: Invalidate value which is Configurable in a dictionary. * @tc.type: FUNC * @tc.require: */ HWTEST_F_L0(GlobalDictionaryTest, InvalidatePropertyBox) { ObjectFactory *factory = thread->GetEcmaVM()->GetFactory(); // create GlobalDictionary int numberofElements = 16; std::vector nameKey = {"a", "b", "s", "t", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p"}; JSHandle handleDict = GlobalDictionary::Create(thread, numberofElements); EXPECT_TRUE(*handleDict != nullptr); int invalidatedSet = 3; int invalidatedPosition = 12; for (int i = 0; i < numberofElements; i++) { JSHandle handleKey(factory->NewFromASCII(nameKey[i])); JSHandle handleValue(thread, JSTaggedValue(i)); JSHandle propertyBox(factory->NewPropertyBox(handleValue)); PropertyAttributes metaData; if (i == invalidatedSet) { metaData.SetDictionaryOrder(invalidatedPosition); } else if (i == invalidatedPosition) { metaData.SetConfigurable(true); } handleDict->SetEntry(thread, i, handleKey.GetTaggedValue(), propertyBox.GetTaggedValue(), metaData); } // calling InvalidatePropertyBox function to Invalidate the PropertyBox PropertyAttributes newAttr(10); GlobalDictionary::InvalidatePropertyBox(thread, handleDict, invalidatedPosition); EXPECT_EQ(handleDict->GetAttributes(thread, invalidatedPosition).GetBoxType(), PropertyBoxType::MUTABLE); EXPECT_EQ(handleDict->GetAttributes(thread, invalidatedSet).GetDictionaryOrder(), invalidatedPosition); EXPECT_EQ(handleDict->GetValue(thread, invalidatedPosition).GetInt(), invalidatedPosition); } } // namespace panda::test