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