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/tagged_dictionary.h"
17 #include "ecmascript/ecma_string_table.h"
18 #include "ecmascript/global_env.h"
19 #include "ecmascript/tests/test_helper.h"
20
21 using namespace panda;
22 using namespace panda::ecmascript;
23
24 namespace panda::test {
25 class TaggedDictionaryTest : public BaseTestWithScope<false> {
26 };
27
GetGlobalEnv(JSThread * thread)28 static JSHandle<GlobalEnv> GetGlobalEnv(JSThread *thread)
29 {
30 EcmaVM *ecma = thread->GetEcmaVM();
31 return ecma->GetGlobalEnv();
32 }
33
34 /**
35 * @tc.name: CreateNameDictionary
36 * @tc.desc: Call "NameDictionary::Create" function Create a name dictionary.then, check whether the dictionary
37 * is created successfully.
38 * @tc.type: FUNC
39 * @tc.require:
40 */
HWTEST_F_L0(TaggedDictionaryTest,CreateNameDictionary)41 HWTEST_F_L0(TaggedDictionaryTest, CreateNameDictionary)
42 {
43 int numOfElement = 64;
44 JSHandle<NameDictionary> nameDict = NameDictionary::Create(thread, numOfElement);
45 EXPECT_TRUE(*nameDict != nullptr);
46 }
47
48 /**
49 * @tc.name: NameDictionary_addKeyAndValue
50 * @tc.desc: Create a name dictionary, set a key value pair to the dictionary.The key is a string type, call the
51 * "PutIfAbsent" function to add the key and value to the dictionary then,check whether the key is found in
52 * the dictionary.
53 * @tc.type: FUNC
54 * @tc.require:
55 */
HWTEST_F_L0(TaggedDictionaryTest,NameDictionary_addKeyAndValue)56 HWTEST_F_L0(TaggedDictionaryTest, NameDictionary_addKeyAndValue)
57 {
58 // mock object needed in test
59 int numOfElement = 64;
60 ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
61 JSHandle<NameDictionary> dictJShandle(NameDictionary::Create(thread, numOfElement));
62 EXPECT_TRUE(*dictJShandle != nullptr);
63 JSMutableHandle<NameDictionary> dictHandle(thread, dictJShandle);
64 JSHandle<JSTaggedValue> objFun = GetGlobalEnv(thread)->GetObjectFunction();
65
66 // create key and values
67 char keyArray[] = "hello";
68 JSHandle<EcmaString> stringKey1 = thread->GetEcmaVM()->GetFactory()->NewFromASCII(keyArray);
69 JSHandle<JSTaggedValue> key1(stringKey1);
70 JSHandle<JSTaggedValue> value1(factory->NewJSObjectByConstructor(JSHandle<JSFunction>(objFun), objFun));
71 PropertyAttributes metaData1;
72
73 char key2Array[] = "hello2";
74 JSHandle<EcmaString> stringKey2 = thread->GetEcmaVM()->GetFactory()->NewFromASCII(key2Array);
75 JSHandle<JSTaggedValue> key2(stringKey2);
76 JSHandle<JSTaggedValue> value2(factory->NewJSObjectByConstructor(JSHandle<JSFunction>(objFun), objFun));
77 PropertyAttributes metaData2;
78
79 // test insert()
80 JSHandle<NameDictionary> dict(NameDictionary::PutIfAbsent(thread, dictHandle, key1, value1, metaData1));
81 dictHandle.Update(dict.GetTaggedValue());
82 EXPECT_EQ(dict->EntriesCount(), 1);
83
84 // test find() and lookup()
85 int entry1 = dict->FindEntry(key1.GetTaggedValue());
86 EXPECT_EQ(key1.GetTaggedValue(), JSTaggedValue(dict->GetKey(entry1).GetRawData()));
87 EXPECT_EQ(value1.GetTaggedValue(), JSTaggedValue(dict->GetValue(entry1).GetRawData()));
88
89 JSHandle<NameDictionary> dict2(NameDictionary::PutIfAbsent(thread, dictHandle, key2, value2, metaData2));
90 EXPECT_EQ(dict2->EntriesCount(), 2);
91 // test remove()
92 dict = NameDictionary::Remove(thread, dictHandle, entry1);
93 EXPECT_EQ(-1, dict->FindEntry(key1.GetTaggedValue()));
94 EXPECT_EQ(dict->EntriesCount(), 1);
95 }
96
97 /**
98 * @tc.name: NameDictionary_GrowCapacity
99 * @tc.desc: Create a name dictionary, set a key value pair to the dictionary.The key is a string type, call the
100 * "PutIfAbsent" function to glow the capacity of the dictionary,then check whether the key number and size
101 * of the dictionary have become bigger.
102 * @tc.type: FUNC
103 * @tc.require:
104 */
HWTEST_F_L0(TaggedDictionaryTest,NameDictionary_GrowCapacity)105 HWTEST_F_L0(TaggedDictionaryTest, NameDictionary_GrowCapacity)
106 {
107 int numOfElement = 8;
108 JSHandle<NameDictionary> dictHandle(NameDictionary::Create(thread, numOfElement));
109 EXPECT_TRUE(*dictHandle != nullptr);
110 // create key and values
111 char keyArray[7] = "hello";
112 for (int i = 0; i < 9; i++) {
113 JSHandle<NameDictionary> tempHandle = dictHandle;
114 keyArray[5] = '1' + static_cast<uint32_t>(i);
115 keyArray[6] = 0;
116 JSHandle<EcmaString> stringKey = thread->GetEcmaVM()->GetFactory()->NewFromASCII(keyArray);
117 JSHandle<JSTaggedValue> key(stringKey);
118 JSHandle<JSTaggedValue> keyHandle(key);
119 JSHandle<JSTaggedValue> valueHandle(thread, JSTaggedValue(i));
120 PropertyAttributes metaData;
121 // test insert()
122 dictHandle = NameDictionary::PutIfAbsent(thread, tempHandle, keyHandle, valueHandle, metaData);
123 }
124 EXPECT_EQ(dictHandle->EntriesCount(), 9);
125 EXPECT_EQ(dictHandle->Size(), 16);
126 }
127
128 /**
129 * @tc.name: NameDictionary_ShrinkCapacity
130 * @tc.desc: Create a name dictionary, set a key value pair to the dictionary.The key is a string type, call the
131 * "Remove" function to shrink the capacity of the dictionary,then check whether the key number and size of
132 * the dictionary have become smaller.
133 * @tc.type: FUNC
134 * @tc.require:
135 */
HWTEST_F_L0(TaggedDictionaryTest,NameDictionary_ShrinkCapacity)136 HWTEST_F_L0(TaggedDictionaryTest, NameDictionary_ShrinkCapacity)
137 {
138 int numOfElement = 64;
139 JSMutableHandle<NameDictionary> dictHandle(thread, NameDictionary::Create(thread, numOfElement));
140 EXPECT_TRUE(*dictHandle != nullptr);
141 // create key and values
142 uint8_t keyArray[7] = "hello";
143
144 auto stringTable = thread->GetEcmaVM()->GetEcmaStringTable();
145 for (int i = 0; i < 10; i++) {
146 keyArray[5] = '0' + static_cast<uint32_t>(i);
147 keyArray[6] = 0;
148 JSHandle<JSTaggedValue> key(thread,
149 stringTable->GetOrInternString(instance, keyArray, utf::Mutf8Size(keyArray), true));
150 JSHandle<JSTaggedValue> value(thread, JSTaggedValue(i));
151 PropertyAttributes metaData;
152 // test insert()
153 JSHandle<NameDictionary> newDict = NameDictionary::PutIfAbsent(thread, dictHandle, key, value, metaData);
154 dictHandle.Update(newDict.GetTaggedValue());
155 }
156
157 keyArray[5] = '2';
158 keyArray[6] = 0;
159 JSHandle<JSTaggedValue> arrayHandle(
160 thread, stringTable->GetOrInternString(instance, keyArray, utf::Mutf8Size(keyArray), true));
161 int entry = dictHandle->FindEntry(arrayHandle.GetTaggedValue());
162 EXPECT_NE(entry, -1);
163
164 JSHandle<NameDictionary> newDict1 = NameDictionary::Remove(thread, dictHandle, entry);
165 dictHandle.Update(newDict1.GetTaggedValue());
166 EXPECT_EQ(dictHandle->EntriesCount(), 9);
167 EXPECT_EQ(dictHandle->Size(), 16);
168 }
169
170 /**
171 * @tc.name: CreateNumberDictionary
172 * @tc.desc: Call "NumberDictionary::Create" function Create a number dictionary.then, check whether the dictionary
173 * is created successfully.
174 * @tc.type: FUNC
175 * @tc.require:
176 */
HWTEST_F_L0(TaggedDictionaryTest,CreateNumberDictionary)177 HWTEST_F_L0(TaggedDictionaryTest, CreateNumberDictionary)
178 {
179 int numOfElement = 64;
180 JSHandle<NumberDictionary> numberDict = NumberDictionary::Create(thread, numOfElement);
181 EXPECT_TRUE(*numberDict != nullptr);
182 }
183
184 /**
185 * @tc.name: NumberDictionary_addKeyAndValue
186 * @tc.desc: Create a number dictionary, set a key value pair to the dictionary.The key is a numeric type, call the
187 * "PutIfAbsent" function to add the key and value to the dictionary then,check whether the key is found in
188 * the dictionary.
189 * @tc.type: FUNC
190 * @tc.require:
191 */
HWTEST_F_L0(TaggedDictionaryTest,NumberDictionary_addKeyAndValue)192 HWTEST_F_L0(TaggedDictionaryTest, NumberDictionary_addKeyAndValue)
193 {
194 int numOfElement = 64;
195 ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
196 JSHandle<NumberDictionary> dictJShandle = NumberDictionary::Create(thread, numOfElement);
197 EXPECT_TRUE(*dictJShandle != nullptr);
198 JSMutableHandle<NumberDictionary> dictHandle(thread, dictJShandle);
199 JSHandle<JSTaggedValue> objFun = GetGlobalEnv(thread)->GetObjectFunction();
200
201 // create key and values
202 JSHandle<JSTaggedValue> key1(thread, JSTaggedValue(1));
203 JSHandle<JSTaggedValue> value1(factory->NewJSObjectByConstructor(JSHandle<JSFunction>(objFun), objFun));
204 PropertyAttributes metaData1;
205
206 JSHandle<JSTaggedValue> key2(thread, JSTaggedValue(2)); // 2: number key
207 JSHandle<JSTaggedValue> value2(factory->NewJSObjectByConstructor(JSHandle<JSFunction>(objFun), objFun));
208 PropertyAttributes metaData2;
209
210 // add key and values
211 JSHandle<NumberDictionary> dict = NumberDictionary::PutIfAbsent(thread, dictHandle, key1, value1, metaData1);
212 dictHandle.Update(dict.GetTaggedValue());
213 EXPECT_EQ(dict->EntriesCount(), 1);
214
215 // test find() and lookup()
216 int entry1 = dict->FindEntry(key1.GetTaggedValue());
217 EXPECT_EQ(key1.GetTaggedValue(), JSTaggedValue(dict->GetKey(entry1).GetRawData()));
218 EXPECT_EQ(value1.GetTaggedValue(), JSTaggedValue(dict->GetValue(entry1).GetRawData()));
219
220 JSHandle<NumberDictionary> dict2 = NumberDictionary::PutIfAbsent(thread, dictHandle, key2, value2, metaData2);
221 EXPECT_EQ(dict2->EntriesCount(), 2);
222 // test remove()
223 dict = NumberDictionary::Remove(thread, dictHandle, entry1);
224 EXPECT_EQ(-1, dict->FindEntry(key1.GetTaggedValue()));
225 EXPECT_EQ(dict->EntriesCount(), 1);
226 }
227
228 /**
229 * @tc.name: NumberDictionary_GetAllKey
230 * @tc.desc: Create a number dictionary, set a key value pair to the dictionary.The key is a numeric type, call the
231 * "GetAllKeys" function to get the key of the dictionary to the taggedarray,then check whether the length
232 * of the array is equal to the number of keys, and whether the array value is equal to the key value.
233 * @tc.type: FUNC
234 * @tc.require:
235 */
HWTEST_F_L0(TaggedDictionaryTest,NumberDictionary_GetAllKey)236 HWTEST_F_L0(TaggedDictionaryTest, NumberDictionary_GetAllKey)
237 {
238 int numOfElement = 64;
239 int keyNumbers = 10;
240 ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
241 JSHandle<NumberDictionary> dictHandle = NumberDictionary::Create(thread, numOfElement);
242 EXPECT_TRUE(*dictHandle != nullptr);
243 JSHandle<TaggedArray> storeKeyArray = factory->NewTaggedArray(keyNumbers);
244 // create key and values
245 for (int i = keyNumbers - 2; i >= 0; i--) {
246 JSHandle<NumberDictionary> tempHandle = dictHandle;
247 JSHandle<JSTaggedValue> keyHandle(thread, JSTaggedValue(i));
248 JSHandle<JSTaggedValue> valueHandle(JSTaggedValue::ToString(thread, keyHandle));
249 PropertyAttributes metaData;
250 dictHandle = NumberDictionary::PutIfAbsent(thread, tempHandle, keyHandle, valueHandle, metaData);
251 }
252 // get key
253 NumberDictionary::GetAllKeys(thread, dictHandle, 1, storeKeyArray); // 1: store to the second position of the array
254 for (int i = 1; i < keyNumbers; i++) {
255 JSHandle<JSTaggedValue> numberKey(thread, JSTaggedValue(i-1));
256 JSHandle<EcmaString> stringKey(JSTaggedValue::ToString(thread, numberKey));
257 EXPECT_EQ(storeKeyArray->Get(i), stringKey.GetTaggedValue());
258 }
259 EXPECT_TRUE(storeKeyArray->Get(0).IsHole());
260 }
261
262 /**
263 * @tc.name: NumberDictionary_GrowCapacity
264 * @tc.desc: Create a number dictionary, set a key value pair to the dictionary.The key is a numeric type, call the
265 * "PutIfAbsent" function to glow the capacity of the dictionary,then check whether the key number and size
266 * of the dictionary have become bigger.
267 * @tc.type: FUNC
268 * @tc.require:
269 */
HWTEST_F_L0(TaggedDictionaryTest,NumberDictionary_GrowCapacity)270 HWTEST_F_L0(TaggedDictionaryTest, NumberDictionary_GrowCapacity)
271 {
272 int numOfElement = 8;
273 JSHandle<NumberDictionary> dictHandle = NumberDictionary::Create(thread, numOfElement);
274 EXPECT_TRUE(*dictHandle != nullptr);
275 // create key and values
276 for (int i = 0; i < 9; i++) {
277 JSHandle<NumberDictionary> tempHandle = dictHandle;
278 JSHandle<JSTaggedValue> keyHandle(thread, JSTaggedValue(i));
279 JSHandle<JSTaggedValue> valueHandle(JSTaggedValue::ToString(thread, keyHandle));
280 PropertyAttributes metaData;
281 // test insert()
282 dictHandle = NumberDictionary::PutIfAbsent(thread, tempHandle, keyHandle, valueHandle, metaData);
283 }
284 EXPECT_EQ(dictHandle->EntriesCount(), 9);
285 EXPECT_EQ(dictHandle->Size(), 16);
286 }
287
288 /**
289 * @tc.name: NumberDictionary_ShrinkCapacity
290 * @tc.desc: Create a number dictionary, set a key value pair to the dictionary.The key is a numeric type, call the
291 * "Remove" function to shrink the capacity of the dictionary,then check whether the key number and size of
292 * the dictionary have become smaller.
293 * @tc.type: FUNC
294 * @tc.require:
295 */
HWTEST_F_L0(TaggedDictionaryTest,NumberDictionary_ShrinkCapacity)296 HWTEST_F_L0(TaggedDictionaryTest, NumberDictionary_ShrinkCapacity)
297 {
298 int numOfElement = 64;
299 JSMutableHandle<NumberDictionary> dictHandle(thread, NumberDictionary::Create(thread, numOfElement));
300 EXPECT_TRUE(*dictHandle != nullptr);
301 // create key and values
302 for (int i = 0; i < 10; i++) {
303 JSHandle<JSTaggedValue> keyHandle(thread, JSTaggedValue(i));
304 JSHandle<JSTaggedValue> valueHandle(JSTaggedValue::ToString(thread, keyHandle));
305 PropertyAttributes metaData;
306 JSHandle<NumberDictionary> newDict =
307 NumberDictionary::PutIfAbsent(thread, dictHandle, keyHandle, valueHandle, metaData);
308 dictHandle.Update(newDict.GetTaggedValue());
309 }
310
311 JSHandle<JSTaggedValue> arrayHandle(thread, JSTaggedValue(9));
312 int entry = dictHandle->FindEntry(arrayHandle.GetTaggedValue());
313 EXPECT_NE(entry, -1);
314
315 JSHandle<NumberDictionary> newDict1 = NumberDictionary::Remove(thread, dictHandle, entry);
316 dictHandle.Update(newDict1.GetTaggedValue());
317 EXPECT_EQ(dictHandle->EntriesCount(), 9);
318 EXPECT_EQ(dictHandle->Size(), 16);
319 }
320
321 /**
322 * @tc.name: NumberDictionary_IsMatch
323 * @tc.desc: Call the "IsMatch" function to determine whether the key in the dictionary is equal to the defined key.
324 * If it is equal, return true, otherwise return false.
325 * @tc.type: FUNC
326 * @tc.require:
327 */
HWTEST_F_L0(TaggedDictionaryTest,NumberDictionary_IsMatch)328 HWTEST_F_L0(TaggedDictionaryTest, NumberDictionary_IsMatch)
329 {
330 JSTaggedValue numberKey1(0);
331 JSTaggedValue numberKey2(1);
332 bool result = false;
333 // key must be integer
334 result = NumberDictionary::IsMatch(numberKey1, numberKey2);
335 EXPECT_TRUE(!result);
336
337 result = NumberDictionary::IsMatch(numberKey1, numberKey1);
338 EXPECT_TRUE(result);
339 }
340 } // namespace panda::test
341