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/symbol_table.h"
17#include "ecmascript/ecma_string.h"
18#include "ecmascript/js_symbol.h"
19#include "ecmascript/object_factory.h"
20#include "ecmascript/js_tagged_value.h"
21#include "ecmascript/tagged_array-inl.h"
22#include "ecmascript/tests/test_helper.h"
23
24using namespace panda::ecmascript;
25
26namespace panda::test {
27class SymbolTableTest : public BaseTestWithScope<false> {
28};
29
30HWTEST_F_L0(SymbolTableTest, GetKeyIndex)
31{
32    int entry = 0;
33    EXPECT_EQ(SymbolTable::GetKeyIndex(entry), 3);
34}
35
36HWTEST_F_L0(SymbolTableTest, GetValueIndex)
37{
38    int entry = 0;
39    EXPECT_EQ(SymbolTable::GetValueIndex(entry), 4);
40}
41
42HWTEST_F_L0(SymbolTableTest, GetEntryIndex)
43{
44    int entry = 0;
45    EXPECT_EQ(SymbolTable::GetEntryIndex(entry), 3);
46}
47
48HWTEST_F_L0(SymbolTableTest, GetEntrySize)
49{
50    EXPECT_EQ(SymbolTable::GetEntrySize(), 2);
51}
52
53/*
54 * Feature: SymbolTableTest
55 * Function: IsMatch
56 * SubFunction: StringsAreEqual
57 * FunctionPoints: Is Match
58 * CaseDescription: Judge whether two string variables are equal. If they are equal,
59 *                  it returns true, otherwise it returns false.
60 */
61HWTEST_F_L0(SymbolTableTest, IsMatch)
62{
63    ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
64
65    JSHandle<EcmaString> symbolTableString = factory->NewFromASCII("name");
66    JSTaggedValue symbolTableOther = symbolTableString.GetTaggedValue();
67
68    JSTaggedValue symbolTableName1 = JSTaggedValue::Hole();
69    EXPECT_EQ(SymbolTable::IsMatch(symbolTableName1, symbolTableOther), false);
70
71    JSTaggedValue symbolTableName2 = JSTaggedValue::Undefined();
72    EXPECT_EQ(SymbolTable::IsMatch(symbolTableName2, symbolTableOther), false);
73
74    JSTaggedValue symbolTableName3 = symbolTableString.GetTaggedValue();
75    EXPECT_EQ(SymbolTable::IsMatch(symbolTableName3, symbolTableOther), true);
76}
77
78/*
79 * Feature: SymbolTableTest
80 * Function: Hash_Utf8
81 * SubFunction: GetHashCode
82 * FunctionPoints: Hash
83 * CaseDescription: The hash code is obtained by passing in a character string array or an uint8_t
84 *                  type array through a specific calculation formula.
85 */
86HWTEST_F_L0(SymbolTableTest, Hash_Utf8)
87{
88    ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
89    // test obj is not string
90    JSHandle<JSTaggedValue> jsObJect(factory->NewEmptyJSObject());
91    EXPECT_EQ(SymbolTable::Hash(jsObJect.GetTaggedValue()), JSSymbol::ComputeHash());
92
93    uint8_t utf8ArrayName1[4] = {1, 2, 3}; // The last element is "\0"
94    uint32_t utf8ArrayNameLen1 = sizeof(utf8ArrayName1) - 1;
95    JSHandle<EcmaString> nameStringUtf8Obj1 = factory->NewFromUtf8(utf8ArrayName1, utf8ArrayNameLen1);
96    EXPECT_EQ(SymbolTable::Hash(nameStringUtf8Obj1.GetTaggedValue()), 1026U); // 1026 = (1 << 5 - 1 + 2) << 5 - 2 + 3
97
98    uint8_t utf8ArrayName2[] = "key";
99    uint32_t utf8ArrayNameLen2 = sizeof(utf8ArrayName2) - 1;
100    JSHandle<EcmaString> nameStringUtf8Obj2 = factory->NewFromUtf8(utf8ArrayName2, utf8ArrayNameLen2);
101    EXPECT_EQ(SymbolTable::Hash(nameStringUtf8Obj2.GetTaggedValue()), 106079U);
102}
103
104/*
105 * Feature: SymbolTableTest
106 * Function: Hash_Utf16
107 * SubFunction: GetHashCode
108 * FunctionPoints: Hash
109 * CaseDescription: The hash code is obtained by passing in a character string array or an uint16_t
110 *                  type array through a specific calculation formula.
111 */
112HWTEST_F_L0(SymbolTableTest, Hash_Utf16)
113{
114    ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
115
116    uint16_t utf16ArrayName1[] = {1, 2, 3};
117    uint32_t utf16ArrayNameLen1 = sizeof(utf16ArrayName1) / sizeof(utf16ArrayName1[0]);
118    JSHandle<EcmaString> nameStringUtf16Obj1 = factory->NewFromUtf16(utf16ArrayName1, utf16ArrayNameLen1);
119    EXPECT_EQ(SymbolTable::Hash(nameStringUtf16Obj1.GetTaggedValue()), 1026U); // 1026 = (1 << 5 - 1 + 2) << 5 - 2 + 3
120
121    uint16_t utf16ArrayName2[] = {0, 1, 2};
122    uint32_t utf16ArrayNameLen2 = sizeof(utf16ArrayName2) / sizeof(utf16ArrayName2[0]);
123    JSHandle<EcmaString> nameStringUtf16Obj2 = factory->NewFromUtf16(utf16ArrayName2, utf16ArrayNameLen2);
124    EXPECT_EQ(SymbolTable::Hash(nameStringUtf16Obj2.GetTaggedValue()), 33U); // 33 = (0 << 5 - 0 + 1) << 5 - 1 + 2
125}
126
127/*
128 * Feature: SymbolTableTest
129 * Function: Create
130 * SubFunction: *Value
131 * FunctionPoints: Create
132 * CaseDescription: A pointer variable of symboltable type is obtained by changing the function,
133 *                  If it is created successfully, the pointer variable is not equal to null,
134 *                  The prerequisite for creation is that compressedstringsenabled must be true.
135 */
136HWTEST_F_L0(SymbolTableTest, Create)
137{
138    int numberOfElements = SymbolTable::DEFAULT_ELEMENTS_NUMBER;
139
140    JSHandle<SymbolTable> symbolTable = SymbolTable::Create(thread, numberOfElements);
141    EXPECT_TRUE(*symbolTable != nullptr);
142}
143
144/*
145 * Feature: SymbolTableTest
146 * Function: ContainsKey
147 * SubFunction: Getkey
148 * FunctionPoints: Contains Key
149 * CaseDescription: Judge whether the key value can be found in the key value in your own created symbol
150 *                  table.If you do not have a key value, you will return false.
151 */
152HWTEST_F_L0(SymbolTableTest, ContainsKey)
153{
154    ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
155    JSHandle<EcmaString> symbolTableStringKey1 = factory->NewFromASCII("key");
156    JSHandle<EcmaString> symbolTableStringKey2 = factory->NewFromASCII("key1");
157    JSHandle<EcmaString> symbolTableStringKey3 = factory->NewFromASCII("value");
158
159    int numberOfElements = 2;
160    JSHandle<SymbolTable> symbolTable = SymbolTable::Create(thread, numberOfElements);
161    EXPECT_EQ(symbolTable->ContainsKey(symbolTableStringKey1.GetTaggedValue()), false);
162
163    symbolTable->SetKey(thread, 1, JSTaggedValue::Hole());
164    EXPECT_EQ(symbolTable->ContainsKey(symbolTableStringKey1.GetTaggedValue()), false);
165
166    symbolTable->SetKey(thread, 1, JSTaggedValue::Undefined());
167    EXPECT_EQ(symbolTable->ContainsKey(symbolTableStringKey1.GetTaggedValue()), false);
168
169    symbolTable->SetKey(thread, 1, symbolTableStringKey1.GetTaggedValue());
170    EXPECT_EQ(symbolTable->ContainsKey(symbolTableStringKey1.GetTaggedValue()), true);
171
172    // the key value has numbers
173    symbolTable->SetKey(thread, 1, symbolTableStringKey2.GetTaggedValue());
174    EXPECT_EQ(symbolTable->ContainsKey(symbolTableStringKey2.GetTaggedValue()), false);
175
176    symbolTable->SetKey(thread, 1, symbolTableStringKey3.GetTaggedValue());
177    EXPECT_EQ(symbolTable->ContainsKey(symbolTableStringKey3.GetTaggedValue()), true);
178}
179
180/*
181 * Feature: SymbolTableTest
182 * Function: GetSymbol
183 * SubFunction: GetValue
184 * FunctionPoints: Get Symbol
185 * CaseDescription: This function obtains the value in the key of symbol table pointer variable created
186 *                  by the create function. If the pointer variable has no value set, it returns false.
187 */
188HWTEST_F_L0(SymbolTableTest, GetSymbol)
189{
190    ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
191    int numberOfElements = 2;
192
193    JSHandle<EcmaString> symbolTableStringKey = factory->NewFromASCII("key");
194    JSHandle<SymbolTable> symbolTable = SymbolTable::Create(thread, numberOfElements);
195
196    symbolTable->SetKey(thread, 1, symbolTableStringKey.GetTaggedValue());
197    EXPECT_EQ(symbolTable->GetSymbol(symbolTableStringKey.GetTaggedValue()), JSTaggedValue::Undefined());
198
199    symbolTable->SetValue(thread, 0, JSTaggedValue(1));
200    EXPECT_EQ(symbolTable->GetSymbol(symbolTableStringKey.GetTaggedValue()), JSTaggedValue::Undefined());
201
202    symbolTable->SetValue(thread, 1, JSTaggedValue(1));
203    EXPECT_EQ(symbolTable->GetSymbol(symbolTableStringKey.GetTaggedValue()).GetInt(), 1);
204}
205
206/*
207 * Feature: SymbolTableTest
208 * Function: FindSymbol
209 * SubFunction: GetKey
210 * FunctionPoints: Find Symbol
211 * CaseDescription: This function compares the key value in the symboltable pointer variable created by the create
212 *                  function with the description value in the jssymbol type variable. If they are equal, it indicates
213 *                  that the find symbol is successful, and the return value is the key value. Before creating the
214 *                  symboltable pointer, perform the NewFromASCII operation to obtain the array length.
215 */
216HWTEST_F_L0(SymbolTableTest, FindSymbol)
217{
218    ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
219    JSHandle<JSTaggedValue> symbolTableStringKey1(factory->NewFromASCII("key"));
220    JSHandle<JSTaggedValue> symbolTableStringKey2(factory->NewFromASCII("key1"));
221
222    int numberOfElements = 2;
223    JSHandle<JSSymbol> handleSymbol = factory->NewJSSymbol();
224    JSHandle<SymbolTable> symbolTable = SymbolTable::Create(thread, numberOfElements);
225
226    JSTaggedValue resultValue1 = symbolTable->FindSymbol(handleSymbol.GetTaggedValue());
227    EXPECT_EQ(JSTaggedValue::SameValue(resultValue1, JSTaggedValue::Undefined()), true);
228
229    handleSymbol->SetDescription(thread, symbolTableStringKey1.GetTaggedValue());
230    JSTaggedValue resultValue2 = symbolTable->FindSymbol(handleSymbol.GetTaggedValue());
231    EXPECT_EQ(JSTaggedValue::SameValue(resultValue2, JSTaggedValue::Undefined()), true);
232
233    symbolTable->SetKey(thread, 1, symbolTableStringKey1.GetTaggedValue());
234    JSTaggedValue resultValue3 = symbolTable->FindSymbol(handleSymbol.GetTaggedValue());
235    EXPECT_EQ(resultValue3.GetRawData() == symbolTableStringKey1.GetTaggedValue().GetRawData(), true);
236
237    symbolTable->SetKey(thread, 1, symbolTableStringKey2.GetTaggedValue());
238    JSTaggedValue resultValue4 = symbolTable->FindSymbol(handleSymbol.GetTaggedValue());
239    EXPECT_EQ(JSTaggedValue::SameValue(resultValue4, JSTaggedValue::Undefined()), true);
240}
241}  // namespace panda::test
242