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/template_map.h"
17 #include "ecmascript/tagged_hash_table.h"
18 #include "ecmascript/tests/test_helper.h"
19
20 using namespace panda;
21 using namespace panda::ecmascript;
22
23 namespace panda::test {
24 class TemplateMapTest : public testing::Test {
25 public:
SetUpTestCase()26 static void SetUpTestCase()
27 {
28 GTEST_LOG_(INFO) << "SetUpTestCase";
29 }
30
TearDownTestCase()31 static void TearDownTestCase()
32 {
33 GTEST_LOG_(INFO) << "TearDownCase";
34 }
35
SetUp()36 void SetUp() override
37 {
38 TestHelper::CreateEcmaVMWithScope(instance, thread, scope);
39 }
40
TearDown()41 void TearDown() override
42 {
43 TestHelper::DestroyEcmaVMWithScope(instance, scope);
44 }
45
46 EcmaVM *instance {nullptr};
47 ecmascript::EcmaHandleScope *scope {nullptr};
48 JSThread *thread {nullptr};
49 };
50
51 /*
52 * @tc.name: CreateTemplateMap
53 * @tc.desc: Create a TemplateMap through calling Create function with numberOfElements. Check whether the value
54 * returned through the TemplateMap's calling Get/GetKey/GetValue function is within expectations.Check
55 * whether the value returned through the TaggedArray's(transformed from the TemplateMap) calling GetLength
56 * function is within expectations.
57 * expectations.
58 * @tc.type: FUNC
59 * @tc.require:
60 */
HWTEST_F_L0(TemplateMapTest,CreateTemplateMap)61 HWTEST_F_L0(TemplateMapTest, CreateTemplateMap)
62 {
63 int numElementsTempMap = 128;
64 uint32_t tagArrExpectLength = TemplateMap::HashTable::TABLE_HEADER_SIZE +
65 numElementsTempMap * TemplateMap::ENTRY_SIZE;
66
67 JSHandle<TemplateMap> templateMap = TemplateMap::Create(thread, numElementsTempMap);
68 JSHandle<TaggedArray> handleTagArr(templateMap);
69
70 EXPECT_EQ(handleTagArr->GetLength(), tagArrExpectLength);
71 EXPECT_EQ(templateMap->EntriesCount(), 0);
72 EXPECT_EQ(templateMap->HoleEntriesCount(), 0);
73 EXPECT_EQ(templateMap->Size(), numElementsTempMap);
74 for (int32_t i = 0; i < numElementsTempMap; i++) {
75 EXPECT_EQ(templateMap->GetKey(i), JSTaggedValue::Undefined());
76 EXPECT_EQ(templateMap->GetValue(i), JSTaggedValue::Undefined());
77 }
78 }
79
80 /*
81 * @tc.name: Insert
82 * @tc.desc: Create a TemplateMap, call Insert function with the TemplateMap, a key(JSArray) and a value. Check whether
83 * the value(entry) returned through the TemplateMap's calling FindEntry function with the key(JSArray) is
84 * within expectations. Check whether the value returned through the TemplateMap's calling GetKey/GetValue
85 * function with the value(entry) is within expectations.
86 * @tc.type: FUNC
87 * @tc.require:
88 */
HWTEST_F_L0(TemplateMapTest,Insert)89 HWTEST_F_L0(TemplateMapTest, Insert)
90 {
91 ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
92 JSHandle<TemplateMap> templateMap = TemplateMap::Create(thread);
93
94 JSHandle<JSTaggedValue> tempMapKey(JSArray::ArrayCreate(thread, JSTaggedNumber(0)));
95 JSHandle<JSTaggedValue> tempMapKey1(JSArray::ArrayCreate(thread, JSTaggedNumber(1)));
96 JSHandle<JSTaggedValue> templateArrVal(factory->NewFromASCII("key"));
97 JSHandle<JSTaggedValue> templateArrVal1(factory->NewFromASCII("key1"));
98
99 TemplateMap::Insert(thread, templateMap, tempMapKey, templateArrVal);
100 int keyEntry = templateMap->FindEntry(tempMapKey.GetTaggedValue());
101 EXPECT_EQ(templateMap->GetKey(keyEntry), tempMapKey.GetTaggedValue());
102 EXPECT_EQ(templateMap->GetValue(keyEntry), templateArrVal.GetTaggedValue());
103
104 TemplateMap::Insert(thread, templateMap, tempMapKey, templateArrVal1);
105 int keyEntry1 = templateMap->FindEntry(tempMapKey.GetTaggedValue());
106 EXPECT_EQ(keyEntry, keyEntry1);
107 EXPECT_EQ(templateMap->GetKey(keyEntry1), tempMapKey.GetTaggedValue());
108 EXPECT_EQ(templateMap->GetValue(keyEntry1), templateArrVal1.GetTaggedValue());
109
110 TemplateMap::Insert(thread, templateMap, tempMapKey1, templateArrVal1);
111 int keyEntry2 = templateMap->FindEntry(tempMapKey1.GetTaggedValue());
112 EXPECT_NE(keyEntry1, keyEntry2);
113 EXPECT_EQ(templateMap->GetKey(keyEntry2), tempMapKey1.GetTaggedValue());
114 EXPECT_EQ(templateMap->GetValue(keyEntry2), templateArrVal1.GetTaggedValue());
115 EXPECT_EQ(templateMap->GetValue(keyEntry), templateArrVal1.GetTaggedValue());
116 }
117
118 /*
119 * @tc.name: IncreaseEntries
120 * @tc.desc: Create a TemplateMap, let it call IncreaseEntries function, check whether the value returned through
121 * calling EntriesCount function is within expectations.
122 * @tc.type: FUNC
123 * @tc.require:
124 */
125
HWTEST_F_L0(TemplateMapTest,IncreaseEntries)126 HWTEST_F_L0(TemplateMapTest, IncreaseEntries)
127 {
128 int entriesCount = 8;
129 JSHandle<TemplateMap> templateMap = TemplateMap::Create(thread);
130 for (int32_t i = 0; i < entriesCount; i++) {
131 templateMap->IncreaseEntries(thread);
132 }
133 EXPECT_EQ(templateMap->EntriesCount(), entriesCount);
134 }
135
136 /*
137 * @tc.name: IncreaseHoleEntriesCount
138 * @tc.desc: Create a TemplateMap, let it call IncreaseEntries function and IncreaseHoleEntriesCount function, check
139 * whether the value returned through calling EntriesCount function and the value returned through calling
140 * HoleEntriesCount function are within expectations.
141 * @tc.type: FUNC
142 * @tc.require:
143 */
HWTEST_F_L0(TemplateMapTest,IncreaseHoleEntriesCount)144 HWTEST_F_L0(TemplateMapTest, IncreaseHoleEntriesCount)
145 {
146 int entriesCount = 8;
147 int holeEntriesCount = 3;
148 JSHandle<TemplateMap> templateMap = TemplateMap::Create(thread);
149 for (int32_t i = 0; i < entriesCount; i++) {
150 templateMap->IncreaseEntries(thread);
151 }
152 templateMap->IncreaseHoleEntriesCount(thread, holeEntriesCount);
153
154 EXPECT_EQ(templateMap->EntriesCount(), entriesCount - holeEntriesCount);
155 EXPECT_EQ(templateMap->HoleEntriesCount(), holeEntriesCount);
156 }
157
158 /*
159 * @tc.name: ComputeHashTableSize
160 * @tc.desc: Check whether the value returned through a TemplateMap's calling ComputeHashTableSize function is within
161 * expectations.
162 * expectations.
163 * @tc.type: FUNC
164 * @tc.require:
165 */
HWTEST_F_L0(TemplateMapTest,ComputeHashTableSize)166 HWTEST_F_L0(TemplateMapTest, ComputeHashTableSize)
167 {
168 JSHandle<TemplateMap> templateMap = TemplateMap::Create(thread);
169
170 uint32_t atLeastSize = 85;
171 uint32_t atLeastSize1 = atLeastSize + 1;
172 // 128: eighty-five is close to the seventh power of two
173 EXPECT_EQ(templateMap->ComputeHashTableSize(atLeastSize), 128);
174 // 256: eighty-six is close to the eighth power of two
175 EXPECT_EQ(templateMap->ComputeHashTableSize(atLeastSize1), 256);
176 uint32_t atLeastSize2 = 172;
177 // 512: one hundred and seventy-two is close to the ninth power of two
178 EXPECT_EQ(templateMap->ComputeHashTableSize(atLeastSize2), 512);
179 }
180
181 /*
182 * @tc.name: IsNeedGrowHashTable
183 * @tc.desc: Create a source TemplateMap, change it through calling IncreaseEntries/IncreaseHoleEntriesCount function.
184 * Check whether the bool returned through the source TemplateMap's calling IsNeedGrowHashTable function is
185 * within expectations.
186 * expectations.
187 * @tc.type: FUNC
188 * @tc.require:
189 */
HWTEST_F_L0(TemplateMapTest,IsNeedGrowHashTable)190 HWTEST_F_L0(TemplateMapTest, IsNeedGrowHashTable)
191 {
192 // Test for the TemplateMap of which the size is 128
193 int intNumElementsTempMap = 128;
194 JSHandle<TemplateMap> templateMap = TemplateMap::Create(thread, intNumElementsTempMap);
195 int atLeastSize = 85;
196 int entriesCount = 22;
197 int addEntriesCount = atLeastSize - entriesCount;
198 for (int32_t i = 0; i < entriesCount; i++) {
199 templateMap->IncreaseEntries(thread);
200 }
201 EXPECT_FALSE(templateMap->IsNeedGrowHashTable(addEntriesCount));
202 EXPECT_TRUE(templateMap->IsNeedGrowHashTable(addEntriesCount + 1));
203 // Test for the TemplateMap of which the size is 256
204 intNumElementsTempMap = 256;
205 JSHandle<TemplateMap> templateMap1 = TemplateMap::Create(thread, intNumElementsTempMap);
206 atLeastSize = 170;
207 entriesCount = 33;
208 addEntriesCount = atLeastSize - entriesCount;
209 for (int32_t i = 0; i < entriesCount; i++) {
210 templateMap1->IncreaseEntries(thread);
211 }
212 EXPECT_FALSE(templateMap1->IsNeedGrowHashTable(addEntriesCount));
213 EXPECT_FALSE(templateMap1->IsNeedGrowHashTable(addEntriesCount + 1));
214 EXPECT_TRUE(templateMap1->IsNeedGrowHashTable(addEntriesCount + 2));
215 }
216
217 /*
218 * @tc.name: GrowHashTable
219 * @tc.desc: Create a source TemplateMap, change it through calling IncreaseEntries function. Check whether the value
220 * returned through the TemplateMap's(returned through calling GrowHashTable function) calling Size function
221 * is within expectations.
222 * expectations.
223 * @tc.type: FUNC
224 * @tc.require:
225 */
HWTEST_F_L0(TemplateMapTest,GrowHashTable)226 HWTEST_F_L0(TemplateMapTest, GrowHashTable)
227 {
228 // Test for the TemplateMap of which the size is 128
229 int intNumElementsTempMap = 128;
230 JSHandle<TemplateMap> templateMap = TemplateMap::Create(thread, intNumElementsTempMap);
231 int atLeastSize = 85;
232 int entriesCount = 55;
233 int addEntriesCount = atLeastSize - entriesCount;
234 for (int32_t i = 0; i < entriesCount; i++) {
235 templateMap->IncreaseEntries(thread);
236 }
237 JSHandle<TemplateMap> templateMap1 = TemplateMap::GrowHashTable(thread, templateMap, addEntriesCount);
238 EXPECT_EQ(templateMap1->Size(), intNumElementsTempMap);
239
240 JSHandle<TemplateMap> templateMap2 = TemplateMap::GrowHashTable(thread, templateMap, addEntriesCount + 1);
241 EXPECT_EQ(templateMap2->Size(), intNumElementsTempMap << 1);
242 // Test for the TemplateMap of which the size is 256
243 intNumElementsTempMap = 256;
244 JSHandle<TemplateMap> templateMap3 = TemplateMap::Create(thread, intNumElementsTempMap);
245 atLeastSize = 170;
246 entriesCount = 66;
247 addEntriesCount = atLeastSize - entriesCount;
248 for (int32_t i = 0; i < entriesCount; i++) {
249 templateMap3->IncreaseEntries(thread);
250 }
251 JSHandle<TemplateMap> templateMap4 = TemplateMap::GrowHashTable(thread, templateMap3, addEntriesCount);
252 EXPECT_EQ(templateMap4->Size(), intNumElementsTempMap);
253
254 JSHandle<TemplateMap> templateMap5 = TemplateMap::GrowHashTable(thread, templateMap3, addEntriesCount + 1);
255 EXPECT_EQ(templateMap5->Size(), intNumElementsTempMap);
256 // 2: means needing to grow
257 JSHandle<TemplateMap> templateMap6 = TemplateMap::GrowHashTable(thread, templateMap3, addEntriesCount + 2);
258 // 2: means twice as much
259 EXPECT_EQ(templateMap6->Size(), intNumElementsTempMap << 2);
260 }
261
262 /*
263 * @tc.name: RecalculateTableSize
264 * @tc.desc: Check whether the value returned through calling RecalculateTableSize function is within expectations.
265 * @tc.type: FUNC
266 * @tc.require:
267 */
HWTEST_F_L0(TemplateMapTest,RecalculateTableSize)268 HWTEST_F_L0(TemplateMapTest, RecalculateTableSize)
269 {
270 int currentSize = 128, atLeastSize = 33;
271 EXPECT_EQ(TemplateMap::RecalculateTableSize(currentSize, atLeastSize), currentSize);
272 // 2: means half
273 EXPECT_EQ(TemplateMap::RecalculateTableSize(currentSize, atLeastSize - 1), currentSize / 2);
274 // 4: shift left by two digits
275 currentSize = TemplateMap::MIN_SIZE * 4;
276 for (int i = currentSize; i >= 0; i--) {
277 EXPECT_EQ(TemplateMap::RecalculateTableSize(currentSize, i), currentSize);
278 }
279 }
280
281 /*
282 * @tc.name: GetAllKeys
283 * @tc.desc: Create a source TemplateMap, change the source TemplateMap through calling Insert function some times.
284 * Create a target TaggedArray, change the target TaggedArray through the changed source TemplateMap's calling
285 * GetAllKeys function with the offset at which the copying of the elements start and the target TaggedArray
286 * Check whether the target TaggedArray is within expectations.
287 * @tc.type: FUNC
288 * @tc.require:
289 */
HWTEST_F_L0(TemplateMapTest,GetAllKeys)290 HWTEST_F_L0(TemplateMapTest, GetAllKeys)
291 {
292 ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
293 int numElements = 32;
294 JSHandle<TemplateMap> templateMap = TemplateMap::Create(thread);
295 // insert key and value
296 for (int i = 0; i < numElements; i++) {
297 JSHandle<JSTaggedValue> tempMapKey(JSArray::ArrayCreate(thread, JSTaggedNumber(i)));
298 JSHandle<JSTaggedValue> tempMapValue(thread, JSTaggedValue(i));
299 templateMap = TemplateMap::Insert(thread, templateMap, tempMapKey, tempMapValue);
300 }
301
302 JSHandle<TaggedArray> storeKeyArray = factory->NewTaggedArray(55); // 55 : means the length of array
303 templateMap->GetAllKeys(thread, 5, *storeKeyArray); // 5: means the index of array
304 for (int32_t i = 0; i < numElements; i++) {
305 EXPECT_NE(templateMap->GetKey(i), JSTaggedValue::Undefined());
306 // 5: get value from subscript five
307 EXPECT_EQ(templateMap->GetKey(i), storeKeyArray->Get(i + 5));
308 }
309 }
310
311 /*
312 * @tc.name: GetAllKeysIntoVector
313 * @tc.desc: Create a source TemplateMap, change the source TemplateMap through calling Insert function some times.
314 * Create a target std::vector<JSTaggedValue>,change the target std::vector<JSTaggedValue> through the changed
315 * source TemplateMap's calling GetAllKeysIntoVector function with the target std::vector<JSTaggedValue>.Check
316 * whether the target std::vector<JSTaggedValue> is within expectations.
317 * @tc.type: FUNC
318 * @tc.require:
319 */
HWTEST_F_L0(TemplateMapTest,GetAllKeysIntoVector)320 HWTEST_F_L0(TemplateMapTest, GetAllKeysIntoVector)
321 {
322 int numElements = 33;
323 JSHandle<TemplateMap> templateMap = TemplateMap::Create(thread);
324 // insert key and value
325 for (int i = 0; i < numElements; i++) {
326 JSHandle<JSTaggedValue> tempMapKey(JSArray::ArrayCreate(thread, JSTaggedNumber(i)));
327 JSHandle<JSTaggedValue> tempMapValue(thread, JSTaggedValue(i));
328 templateMap = TemplateMap::Insert(thread, templateMap, tempMapKey, tempMapValue);
329 }
330 std::vector<JSTaggedValue> storeKeyVector = {};
331 templateMap->GetAllKeysIntoVector(storeKeyVector);
332 for (int32_t i = 0; i < numElements; i++) {
333 EXPECT_NE(templateMap->GetKey(i), JSTaggedValue::Undefined());
334 EXPECT_EQ(templateMap->GetKey(i), storeKeyVector[i]);
335 }
336 }
337
338 /*
339 * @tc.name: FindInsertIndex
340 * @tc.desc: Create a source TemplateMap, change the source TemplateMap through calling Insert function some times.
341 * Get the next InsertIndex through the changed source TemplateMap's calling FindInsertIndex function with the
342 * hash of the Key which exists in the changed TemplateMap. Check whether the JSTaggedValue returned through
343 * the changed source TemplateMap's calling GetKey function with the next InsertIndex is Undefined.
344 * @tc.type: FUNC
345 * @tc.require:
346 */
HWTEST_F_L0(TemplateMapTest,FindInsertIndex)347 HWTEST_F_L0(TemplateMapTest, FindInsertIndex)
348 {
349 int numElements = 33;
350 JSHandle<TemplateMap> templateMap = TemplateMap::Create(thread);
351 // insert key and value
352 for (int i = 0; i < numElements; i++) {
353 JSHandle<JSTaggedValue> tempMapKey(JSArray::ArrayCreate(thread, JSTaggedNumber(i)));
354 JSHandle<JSTaggedValue> tempMapValue(thread, JSTaggedValue(i));
355 templateMap = TemplateMap::Insert(thread, templateMap, tempMapKey, tempMapValue);
356 }
357
358 for (int i = 0; i < numElements; i++) {
359 JSHandle<JSTaggedValue> tempMapKey(JSArray::ArrayCreate(thread, JSTaggedNumber(i)));
360 EXPECT_EQ(JSTaggedValue::Undefined(), templateMap->GetKey(
361 templateMap->FindInsertIndex(TemplateMap::Hash(tempMapKey.GetTaggedValue()))));
362 }
363 }
364 } // namespace panda::test
365