1/*
2 * Copyright (c) 2021 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/ecma_vm.h"
17#include "ecmascript/global_env.h"
18#include "ecmascript/js_handle.h"
19#include "ecmascript/js_object-inl.h"
20#include "ecmascript/js_tagged_value.h"
21#include "ecmascript/linked_hash_table.h"
22#include "ecmascript/linked_hash_table.h"
23#include "ecmascript/object_factory.h"
24#include "ecmascript/tagged_hash_table.h"
25#include "ecmascript/tests/test_helper.h"
26
27using namespace panda;
28
29using namespace panda::ecmascript;
30
31namespace panda::test {
32class LinkedHashTableTest : public BaseTestWithScope<false> {
33public:
34    JSHandle<GlobalEnv> GetGlobalEnv()
35    {
36        EcmaVM *ecma = thread->GetEcmaVM();
37        return ecma->GetGlobalEnv();
38    }
39};
40
41HWTEST_F_L0(LinkedHashTableTest, MapCreate)
42{
43    int numOfElement = 64;
44    JSHandle<LinkedHashMap> dict = LinkedHashMap::Create(thread, numOfElement);
45    EXPECT_TRUE(*dict != nullptr);
46}
47
48HWTEST_F_L0(LinkedHashTableTest, SetCreate)
49{
50    int numOfElement = 64;
51    JSHandle<LinkedHashSet> set = LinkedHashSet::Create(thread, numOfElement);
52    EXPECT_TRUE(*set != nullptr);
53}
54
55HWTEST_F_L0(LinkedHashTableTest, addKeyAndValue)
56{
57    ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
58    // mock object needed in test
59    int numOfElement = 64;
60    JSHandle<LinkedHashMap> dictHandle = LinkedHashMap::Create(thread, numOfElement);
61    EXPECT_TRUE(*dictHandle != nullptr);
62    JSHandle<JSTaggedValue> objFun = GetGlobalEnv()->GetObjectFunction();
63
64    char keyArray[] = "hello";
65    JSHandle<EcmaString> stringKey1 = factory->NewFromASCII(keyArray);
66    JSHandle<JSTaggedValue> key1(stringKey1);
67    JSHandle<JSTaggedValue> value1(factory->NewJSObjectByConstructor(JSHandle<JSFunction>(objFun), objFun));
68
69    char key2Array[] = "hello2";
70    JSHandle<EcmaString> stringKey2 = factory->NewFromASCII(key2Array);
71    JSHandle<JSTaggedValue> key2(stringKey2);
72    JSHandle<JSTaggedValue> value2(factory->NewJSObjectByConstructor(JSHandle<JSFunction>(objFun), objFun));
73
74    // test set()
75    dictHandle = LinkedHashMap::Set(thread, dictHandle, key1, value1);
76    EXPECT_EQ(dictHandle->NumberOfElements(), 1);
77
78    // test find()
79    int entry1 = dictHandle->FindElement(thread, key1.GetTaggedValue());
80    EXPECT_EQ(key1.GetTaggedValue(), dictHandle->GetKey(entry1));
81    EXPECT_EQ(value1.GetTaggedValue(), dictHandle->GetValue(entry1));
82
83    dictHandle = LinkedHashMap::Set(thread, dictHandle, key2, value2);
84    EXPECT_EQ(dictHandle->NumberOfElements(), 2);
85    // test remove()
86    dictHandle = LinkedHashMap::Delete(thread, dictHandle, key1);
87    EXPECT_EQ(-1, dictHandle->FindElement(thread, key1.GetTaggedValue()));
88    EXPECT_EQ(dictHandle->NumberOfElements(), 1);
89
90    JSHandle<JSTaggedValue> undefinedKey(thread, JSTaggedValue::Undefined());
91    dictHandle = LinkedHashMap::Set(thread, dictHandle, undefinedKey, value1);
92    int entry2 = dictHandle->FindElement(thread, undefinedKey.GetTaggedValue());
93    EXPECT_EQ(value1.GetTaggedValue(), dictHandle->GetValue(entry2));
94}
95
96HWTEST_F_L0(LinkedHashTableTest, SetaddKeyAndValue)
97{
98    ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
99    // mock object needed in test
100    int numOfElement = 64;
101    JSHandle<LinkedHashSet> setHandle = LinkedHashSet::Create(thread, numOfElement);
102    EXPECT_TRUE(*setHandle != nullptr);
103    JSHandle<JSTaggedValue> objFun = GetGlobalEnv()->GetObjectFunction();
104
105    char keyArray[] = "hello";
106    JSHandle<EcmaString> stringKey1 = factory->NewFromASCII(keyArray);
107    JSHandle<JSTaggedValue> key1(stringKey1);
108    JSHandle<JSTaggedValue> value1(factory->NewJSObjectByConstructor(JSHandle<JSFunction>(objFun), objFun));
109
110    char key2Array[] = "hello2";
111    JSHandle<EcmaString> stringKey2 = factory->NewFromASCII(key2Array);
112    JSHandle<JSTaggedValue> key2(stringKey2);
113    JSHandle<JSTaggedValue> value2(factory->NewJSObjectByConstructor(JSHandle<JSFunction>(objFun), objFun));
114
115    // test set()
116    setHandle = LinkedHashSet::Add(thread, setHandle, key1);
117    EXPECT_EQ(setHandle->NumberOfElements(), 1);
118
119    // test has()
120    EXPECT_TRUE(setHandle->Has(thread, key1.GetTaggedValue()));
121
122    setHandle = LinkedHashSet::Add(thread, setHandle, key2);
123    EXPECT_EQ(setHandle->NumberOfElements(), 2);
124    // test remove()
125    setHandle = LinkedHashSet::Delete(thread, setHandle, key1);
126    EXPECT_EQ(-1, setHandle->FindElement(thread, key1.GetTaggedValue()));
127    EXPECT_EQ(setHandle->NumberOfElements(), 1);
128
129    JSHandle<JSTaggedValue> undefinedKey(thread, JSTaggedValue::Undefined());
130    setHandle = LinkedHashSet::Add(thread, setHandle, undefinedKey);
131    EXPECT_TRUE(setHandle->Has(thread, undefinedKey.GetTaggedValue()));
132}
133
134HWTEST_F_L0(LinkedHashTableTest, GrowCapacity)
135{
136    ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
137    int numOfElement = 8;
138    JSHandle<LinkedHashMap> dictHandle = LinkedHashMap::Create(thread, numOfElement);
139    EXPECT_TRUE(*dictHandle != nullptr);
140    JSHandle<JSFunction> objFun(GetGlobalEnv()->GetObjectFunction());
141    char keyArray[7] = "hello";
142    for (int i = 0; i < 33; i++) {
143        keyArray[5] = '1' + static_cast<uint32_t>(i);
144        keyArray[6] = 0;
145        JSHandle<JSTaggedValue> key(factory->NewFromASCII(keyArray));
146        JSHandle<JSTaggedValue> value(thread, JSTaggedValue(i));
147
148        // test insert()
149        dictHandle = LinkedHashMap::Set(thread, dictHandle, key, value);
150        EXPECT_EQ(i, dictHandle->FindElement(thread, key.GetTaggedValue()));
151    }
152
153    // test order
154    for (int i = 0; i < 33; i++) {
155        keyArray[5] = '1' + static_cast<uint32_t>(i);
156        keyArray[6] = 0;
157        JSHandle<EcmaString> stringKey = factory->NewFromASCII(keyArray);
158        // test insert()
159        EXPECT_EQ(i, dictHandle->FindElement(thread, stringKey.GetTaggedValue()));
160    }
161    EXPECT_EQ(dictHandle->NumberOfElements(), 33);
162    EXPECT_EQ(dictHandle->Capacity(), 64);
163}
164
165HWTEST_F_L0(LinkedHashTableTest, SetGrowCapacity)
166{
167    ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
168    int numOfElement = 8;
169    JSHandle<LinkedHashSet> setHandle = LinkedHashSet::Create(thread, numOfElement);
170    EXPECT_TRUE(*setHandle != nullptr);
171    JSHandle<JSFunction> objFun(GetGlobalEnv()->GetObjectFunction());
172    // create key and values
173    char keyArray[7] = "hello";
174    for (int i = 0; i < 33; i++) {
175        keyArray[5] = '1' + static_cast<uint32_t>(i);
176        keyArray[6] = 0;
177        JSHandle<EcmaString> stringKey = factory->NewFromASCII(keyArray);
178        JSHandle<JSTaggedValue> key(stringKey);
179
180        // test insert()
181        setHandle = LinkedHashSet::Add(thread, setHandle, key);
182        EXPECT_EQ(i, setHandle->FindElement(thread, key.GetTaggedValue()));
183    }
184
185    // test order
186    for (int i = 0; i < 33; i++) {
187        keyArray[5] = '1' + static_cast<uint32_t>(i);
188        keyArray[6] = 0;
189        JSHandle<EcmaString> stringKey = factory->NewFromASCII(keyArray);
190        // test insert()
191        EXPECT_EQ(i, setHandle->FindElement(thread, stringKey.GetTaggedValue()));
192    }
193    EXPECT_EQ(setHandle->NumberOfElements(), 33);
194    EXPECT_EQ(setHandle->Capacity(), 64);
195}
196
197HWTEST_F_L0(LinkedHashTableTest, ShrinkCapacity)
198{
199    ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
200    int numOfElement = 64;
201    JSHandle<LinkedHashMap> dictHandle = LinkedHashMap::Create(thread, numOfElement);
202    EXPECT_TRUE(*dictHandle != nullptr);
203    JSHandle<JSFunction> objFun(GetGlobalEnv()->GetObjectFunction());
204    char keyArray[7] = "hello";
205    for (int i = 0; i < 10; i++) {
206        keyArray[5] = '1' + static_cast<uint32_t>(i);
207        keyArray[6] = 0;
208        JSHandle<JSTaggedValue> key(factory->NewFromASCII(keyArray));
209        JSHandle<JSTaggedValue> value(thread, JSTaggedValue(i));
210
211        // test insert()
212        dictHandle = LinkedHashMap::Set(thread, dictHandle, key, value);
213    }
214    keyArray[5] = '1' + 9;
215    JSHandle<JSTaggedValue> key(factory->NewFromASCII(keyArray));
216    dictHandle = LinkedHashMap::Delete(thread, dictHandle, key);
217    // test order
218    for (int i = 0; i < 9; i++) {
219        keyArray[5] = '1' + static_cast<uint32_t>(i);
220        keyArray[6] = 0;
221        JSHandle<EcmaString> stringKey = factory->NewFromASCII(keyArray);
222        // test insert()
223        EXPECT_EQ(i, dictHandle->FindElement(thread, stringKey.GetTaggedValue()));
224    }
225    EXPECT_EQ(dictHandle->NumberOfElements(), 9);
226    EXPECT_EQ(dictHandle->Capacity(), 16);
227}
228
229HWTEST_F_L0(LinkedHashTableTest, SetShrinkCapacity)
230{
231    ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
232    int numOfElement = 64;
233    JSHandle<LinkedHashSet> setHandle = LinkedHashSet::Create(thread, numOfElement);
234    EXPECT_TRUE(*setHandle != nullptr);
235    JSHandle<JSFunction> objFun(GetGlobalEnv()->GetObjectFunction());
236    // create key and values
237    char keyArray[7] = "hello";
238    for (int i = 0; i < 10; i++) {
239        keyArray[5] = '1' + static_cast<uint32_t>(i);
240        keyArray[6] = 0;
241        JSHandle<JSTaggedValue> key(factory->NewFromASCII(keyArray));
242
243        // test insert()
244        setHandle = LinkedHashSet::Add(thread, setHandle, key);
245    }
246    keyArray[5] = '1' + 9;
247    JSHandle<JSTaggedValue> keyHandle(factory->NewFromASCII(keyArray));
248    setHandle = LinkedHashSet::Delete(thread, setHandle, keyHandle);
249    // test order
250    for (int i = 0; i < 9; i++) {
251        keyArray[5] = '1' + static_cast<uint32_t>(i);
252        keyArray[6] = 0;
253        JSHandle<EcmaString> stringKey = factory->NewFromASCII(keyArray);
254        // test insert()
255        EXPECT_EQ(i, setHandle->FindElement(thread, stringKey.GetTaggedValue()));
256    }
257    EXPECT_EQ(setHandle->NumberOfElements(), 9);
258    EXPECT_EQ(setHandle->Capacity(), 16);
259}
260}  // namespace panda::test
261