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