/* * 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/template_map.h" #include "ecmascript/tagged_hash_table.h" #include "ecmascript/tests/test_helper.h" using namespace panda; using namespace panda::ecmascript; namespace panda::test { class TemplateMapTest : public testing::Test { public: static void SetUpTestCase() { GTEST_LOG_(INFO) << "SetUpTestCase"; } static void TearDownTestCase() { GTEST_LOG_(INFO) << "TearDownCase"; } void SetUp() override { TestHelper::CreateEcmaVMWithScope(instance, thread, scope); } void TearDown() override { TestHelper::DestroyEcmaVMWithScope(instance, scope); } EcmaVM *instance {nullptr}; ecmascript::EcmaHandleScope *scope {nullptr}; JSThread *thread {nullptr}; }; /* * @tc.name: CreateTemplateMap * @tc.desc: Create a TemplateMap through calling Create function with numberOfElements. Check whether the value * returned through the TemplateMap's calling Get/GetKey/GetValue function is within expectations.Check * whether the value returned through the TaggedArray's(transformed from the TemplateMap) calling GetLength * function is within expectations. * expectations. * @tc.type: FUNC * @tc.require: */ HWTEST_F_L0(TemplateMapTest, CreateTemplateMap) { int numElementsTempMap = 128; uint32_t tagArrExpectLength = TemplateMap::HashTable::TABLE_HEADER_SIZE + numElementsTempMap * TemplateMap::ENTRY_SIZE; JSHandle<TemplateMap> templateMap = TemplateMap::Create(thread, numElementsTempMap); JSHandle<TaggedArray> handleTagArr(templateMap); EXPECT_EQ(handleTagArr->GetLength(), tagArrExpectLength); EXPECT_EQ(templateMap->EntriesCount(), 0); EXPECT_EQ(templateMap->HoleEntriesCount(), 0); EXPECT_EQ(templateMap->Size(), numElementsTempMap); for (int32_t i = 0; i < numElementsTempMap; i++) { EXPECT_EQ(templateMap->GetKey(i), JSTaggedValue::Undefined()); EXPECT_EQ(templateMap->GetValue(i), JSTaggedValue::Undefined()); } } /* * @tc.name: Insert * @tc.desc: Create a TemplateMap, call Insert function with the TemplateMap, a key(JSArray) and a value. Check whether * the value(entry) returned through the TemplateMap's calling FindEntry function with the key(JSArray) is * within expectations. Check whether the value returned through the TemplateMap's calling GetKey/GetValue * function with the value(entry) is within expectations. * @tc.type: FUNC * @tc.require: */ HWTEST_F_L0(TemplateMapTest, Insert) { ObjectFactory *factory = thread->GetEcmaVM()->GetFactory(); JSHandle<TemplateMap> templateMap = TemplateMap::Create(thread); JSHandle<JSTaggedValue> tempMapKey(JSArray::ArrayCreate(thread, JSTaggedNumber(0))); JSHandle<JSTaggedValue> tempMapKey1(JSArray::ArrayCreate(thread, JSTaggedNumber(1))); JSHandle<JSTaggedValue> templateArrVal(factory->NewFromASCII("key")); JSHandle<JSTaggedValue> templateArrVal1(factory->NewFromASCII("key1")); TemplateMap::Insert(thread, templateMap, tempMapKey, templateArrVal); int keyEntry = templateMap->FindEntry(tempMapKey.GetTaggedValue()); EXPECT_EQ(templateMap->GetKey(keyEntry), tempMapKey.GetTaggedValue()); EXPECT_EQ(templateMap->GetValue(keyEntry), templateArrVal.GetTaggedValue()); TemplateMap::Insert(thread, templateMap, tempMapKey, templateArrVal1); int keyEntry1 = templateMap->FindEntry(tempMapKey.GetTaggedValue()); EXPECT_EQ(keyEntry, keyEntry1); EXPECT_EQ(templateMap->GetKey(keyEntry1), tempMapKey.GetTaggedValue()); EXPECT_EQ(templateMap->GetValue(keyEntry1), templateArrVal1.GetTaggedValue()); TemplateMap::Insert(thread, templateMap, tempMapKey1, templateArrVal1); int keyEntry2 = templateMap->FindEntry(tempMapKey1.GetTaggedValue()); EXPECT_NE(keyEntry1, keyEntry2); EXPECT_EQ(templateMap->GetKey(keyEntry2), tempMapKey1.GetTaggedValue()); EXPECT_EQ(templateMap->GetValue(keyEntry2), templateArrVal1.GetTaggedValue()); EXPECT_EQ(templateMap->GetValue(keyEntry), templateArrVal1.GetTaggedValue()); } /* * @tc.name: IncreaseEntries * @tc.desc: Create a TemplateMap, let it call IncreaseEntries function, check whether the value returned through * calling EntriesCount function is within expectations. * @tc.type: FUNC * @tc.require: */ HWTEST_F_L0(TemplateMapTest, IncreaseEntries) { int entriesCount = 8; JSHandle<TemplateMap> templateMap = TemplateMap::Create(thread); for (int32_t i = 0; i < entriesCount; i++) { templateMap->IncreaseEntries(thread); } EXPECT_EQ(templateMap->EntriesCount(), entriesCount); } /* * @tc.name: IncreaseHoleEntriesCount * @tc.desc: Create a TemplateMap, let it call IncreaseEntries function and IncreaseHoleEntriesCount function, check * whether the value returned through calling EntriesCount function and the value returned through calling * HoleEntriesCount function are within expectations. * @tc.type: FUNC * @tc.require: */ HWTEST_F_L0(TemplateMapTest, IncreaseHoleEntriesCount) { int entriesCount = 8; int holeEntriesCount = 3; JSHandle<TemplateMap> templateMap = TemplateMap::Create(thread); for (int32_t i = 0; i < entriesCount; i++) { templateMap->IncreaseEntries(thread); } templateMap->IncreaseHoleEntriesCount(thread, holeEntriesCount); EXPECT_EQ(templateMap->EntriesCount(), entriesCount - holeEntriesCount); EXPECT_EQ(templateMap->HoleEntriesCount(), holeEntriesCount); } /* * @tc.name: ComputeHashTableSize * @tc.desc: Check whether the value returned through a TemplateMap's calling ComputeHashTableSize function is within * expectations. * expectations. * @tc.type: FUNC * @tc.require: */ HWTEST_F_L0(TemplateMapTest, ComputeHashTableSize) { JSHandle<TemplateMap> templateMap = TemplateMap::Create(thread); uint32_t atLeastSize = 85; uint32_t atLeastSize1 = atLeastSize + 1; // 128: eighty-five is close to the seventh power of two EXPECT_EQ(templateMap->ComputeHashTableSize(atLeastSize), 128); // 256: eighty-six is close to the eighth power of two EXPECT_EQ(templateMap->ComputeHashTableSize(atLeastSize1), 256); uint32_t atLeastSize2 = 172; // 512: one hundred and seventy-two is close to the ninth power of two EXPECT_EQ(templateMap->ComputeHashTableSize(atLeastSize2), 512); } /* * @tc.name: IsNeedGrowHashTable * @tc.desc: Create a source TemplateMap, change it through calling IncreaseEntries/IncreaseHoleEntriesCount function. * Check whether the bool returned through the source TemplateMap's calling IsNeedGrowHashTable function is * within expectations. * expectations. * @tc.type: FUNC * @tc.require: */ HWTEST_F_L0(TemplateMapTest, IsNeedGrowHashTable) { // Test for the TemplateMap of which the size is 128 int intNumElementsTempMap = 128; JSHandle<TemplateMap> templateMap = TemplateMap::Create(thread, intNumElementsTempMap); int atLeastSize = 85; int entriesCount = 22; int addEntriesCount = atLeastSize - entriesCount; for (int32_t i = 0; i < entriesCount; i++) { templateMap->IncreaseEntries(thread); } EXPECT_FALSE(templateMap->IsNeedGrowHashTable(addEntriesCount)); EXPECT_TRUE(templateMap->IsNeedGrowHashTable(addEntriesCount + 1)); // Test for the TemplateMap of which the size is 256 intNumElementsTempMap = 256; JSHandle<TemplateMap> templateMap1 = TemplateMap::Create(thread, intNumElementsTempMap); atLeastSize = 170; entriesCount = 33; addEntriesCount = atLeastSize - entriesCount; for (int32_t i = 0; i < entriesCount; i++) { templateMap1->IncreaseEntries(thread); } EXPECT_FALSE(templateMap1->IsNeedGrowHashTable(addEntriesCount)); EXPECT_FALSE(templateMap1->IsNeedGrowHashTable(addEntriesCount + 1)); EXPECT_TRUE(templateMap1->IsNeedGrowHashTable(addEntriesCount + 2)); } /* * @tc.name: GrowHashTable * @tc.desc: Create a source TemplateMap, change it through calling IncreaseEntries function. Check whether the value * returned through the TemplateMap's(returned through calling GrowHashTable function) calling Size function * is within expectations. * expectations. * @tc.type: FUNC * @tc.require: */ HWTEST_F_L0(TemplateMapTest, GrowHashTable) { // Test for the TemplateMap of which the size is 128 int intNumElementsTempMap = 128; JSHandle<TemplateMap> templateMap = TemplateMap::Create(thread, intNumElementsTempMap); int atLeastSize = 85; int entriesCount = 55; int addEntriesCount = atLeastSize - entriesCount; for (int32_t i = 0; i < entriesCount; i++) { templateMap->IncreaseEntries(thread); } JSHandle<TemplateMap> templateMap1 = TemplateMap::GrowHashTable(thread, templateMap, addEntriesCount); EXPECT_EQ(templateMap1->Size(), intNumElementsTempMap); JSHandle<TemplateMap> templateMap2 = TemplateMap::GrowHashTable(thread, templateMap, addEntriesCount + 1); EXPECT_EQ(templateMap2->Size(), intNumElementsTempMap << 1); // Test for the TemplateMap of which the size is 256 intNumElementsTempMap = 256; JSHandle<TemplateMap> templateMap3 = TemplateMap::Create(thread, intNumElementsTempMap); atLeastSize = 170; entriesCount = 66; addEntriesCount = atLeastSize - entriesCount; for (int32_t i = 0; i < entriesCount; i++) { templateMap3->IncreaseEntries(thread); } JSHandle<TemplateMap> templateMap4 = TemplateMap::GrowHashTable(thread, templateMap3, addEntriesCount); EXPECT_EQ(templateMap4->Size(), intNumElementsTempMap); JSHandle<TemplateMap> templateMap5 = TemplateMap::GrowHashTable(thread, templateMap3, addEntriesCount + 1); EXPECT_EQ(templateMap5->Size(), intNumElementsTempMap); // 2: means needing to grow JSHandle<TemplateMap> templateMap6 = TemplateMap::GrowHashTable(thread, templateMap3, addEntriesCount + 2); // 2: means twice as much EXPECT_EQ(templateMap6->Size(), intNumElementsTempMap << 2); } /* * @tc.name: RecalculateTableSize * @tc.desc: Check whether the value returned through calling RecalculateTableSize function is within expectations. * @tc.type: FUNC * @tc.require: */ HWTEST_F_L0(TemplateMapTest, RecalculateTableSize) { int currentSize = 128, atLeastSize = 33; EXPECT_EQ(TemplateMap::RecalculateTableSize(currentSize, atLeastSize), currentSize); // 2: means half EXPECT_EQ(TemplateMap::RecalculateTableSize(currentSize, atLeastSize - 1), currentSize / 2); // 4: shift left by two digits currentSize = TemplateMap::MIN_SIZE * 4; for (int i = currentSize; i >= 0; i--) { EXPECT_EQ(TemplateMap::RecalculateTableSize(currentSize, i), currentSize); } } /* * @tc.name: GetAllKeys * @tc.desc: Create a source TemplateMap, change the source TemplateMap through calling Insert function some times. * Create a target TaggedArray, change the target TaggedArray through the changed source TemplateMap's calling * GetAllKeys function with the offset at which the copying of the elements start and the target TaggedArray * Check whether the target TaggedArray is within expectations. * @tc.type: FUNC * @tc.require: */ HWTEST_F_L0(TemplateMapTest, GetAllKeys) { ObjectFactory *factory = thread->GetEcmaVM()->GetFactory(); int numElements = 32; JSHandle<TemplateMap> templateMap = TemplateMap::Create(thread); // insert key and value for (int i = 0; i < numElements; i++) { JSHandle<JSTaggedValue> tempMapKey(JSArray::ArrayCreate(thread, JSTaggedNumber(i))); JSHandle<JSTaggedValue> tempMapValue(thread, JSTaggedValue(i)); templateMap = TemplateMap::Insert(thread, templateMap, tempMapKey, tempMapValue); } JSHandle<TaggedArray> storeKeyArray = factory->NewTaggedArray(55); // 55 : means the length of array templateMap->GetAllKeys(thread, 5, *storeKeyArray); // 5: means the index of array for (int32_t i = 0; i < numElements; i++) { EXPECT_NE(templateMap->GetKey(i), JSTaggedValue::Undefined()); // 5: get value from subscript five EXPECT_EQ(templateMap->GetKey(i), storeKeyArray->Get(i + 5)); } } /* * @tc.name: GetAllKeysIntoVector * @tc.desc: Create a source TemplateMap, change the source TemplateMap through calling Insert function some times. * Create a target std::vector<JSTaggedValue>,change the target std::vector<JSTaggedValue> through the changed * source TemplateMap's calling GetAllKeysIntoVector function with the target std::vector<JSTaggedValue>.Check * whether the target std::vector<JSTaggedValue> is within expectations. * @tc.type: FUNC * @tc.require: */ HWTEST_F_L0(TemplateMapTest, GetAllKeysIntoVector) { int numElements = 33; JSHandle<TemplateMap> templateMap = TemplateMap::Create(thread); // insert key and value for (int i = 0; i < numElements; i++) { JSHandle<JSTaggedValue> tempMapKey(JSArray::ArrayCreate(thread, JSTaggedNumber(i))); JSHandle<JSTaggedValue> tempMapValue(thread, JSTaggedValue(i)); templateMap = TemplateMap::Insert(thread, templateMap, tempMapKey, tempMapValue); } std::vector<JSTaggedValue> storeKeyVector = {}; templateMap->GetAllKeysIntoVector(storeKeyVector); for (int32_t i = 0; i < numElements; i++) { EXPECT_NE(templateMap->GetKey(i), JSTaggedValue::Undefined()); EXPECT_EQ(templateMap->GetKey(i), storeKeyVector[i]); } } /* * @tc.name: FindInsertIndex * @tc.desc: Create a source TemplateMap, change the source TemplateMap through calling Insert function some times. * Get the next InsertIndex through the changed source TemplateMap's calling FindInsertIndex function with the * hash of the Key which exists in the changed TemplateMap. Check whether the JSTaggedValue returned through * the changed source TemplateMap's calling GetKey function with the next InsertIndex is Undefined. * @tc.type: FUNC * @tc.require: */ HWTEST_F_L0(TemplateMapTest, FindInsertIndex) { int numElements = 33; JSHandle<TemplateMap> templateMap = TemplateMap::Create(thread); // insert key and value for (int i = 0; i < numElements; i++) { JSHandle<JSTaggedValue> tempMapKey(JSArray::ArrayCreate(thread, JSTaggedNumber(i))); JSHandle<JSTaggedValue> tempMapValue(thread, JSTaggedValue(i)); templateMap = TemplateMap::Insert(thread, templateMap, tempMapKey, tempMapValue); } for (int i = 0; i < numElements; i++) { JSHandle<JSTaggedValue> tempMapKey(JSArray::ArrayCreate(thread, JSTaggedNumber(i))); EXPECT_EQ(JSTaggedValue::Undefined(), templateMap->GetKey( templateMap->FindInsertIndex(TemplateMap::Hash(tempMapKey.GetTaggedValue())))); } } } // namespace panda::test