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_string.h"
17 #include "ecmascript/ecma_vm.h"
18 #include "ecmascript/global_env.h"
19 #include "ecmascript/js_function.h"
20 #include "ecmascript/js_handle.h"
21 #include "ecmascript/js_iterator.h"
22 #include "ecmascript/js_map.h"
23 #include "ecmascript/js_map_iterator.h"
24 #include "ecmascript/js_object-inl.h"
25 #include "ecmascript/js_tagged_value.h"
26 #include "ecmascript/linked_hash_table.h"
27 #include "ecmascript/object_factory.h"
28 #include "ecmascript/tagged_hash_table.h"
29 #include "ecmascript/tests/test_helper.h"
30
31 using namespace panda;
32
33 using namespace panda::ecmascript;
34
35 namespace panda::test {
36 class JSMapTest : public BaseTestWithScope<false> {
37 protected:
CreateMap()38 JSMap *CreateMap()
39 {
40 ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
41 JSHandle<GlobalEnv> env = thread->GetEcmaVM()->GetGlobalEnv();
42 JSHandle<JSTaggedValue> constructor = env->GetBuiltinsMapFunction();
43 JSHandle<JSMap> map =
44 JSHandle<JSMap>::Cast(factory->NewJSObjectByConstructor(JSHandle<JSFunction>(constructor), constructor));
45 JSHandle<LinkedHashMap> hashMap = LinkedHashMap::Create(thread);
46 map->SetLinkedMap(thread, hashMap);
47 return *map;
48 }
49 };
50
HWTEST_F_L0(JSMapTest,MapCreate)51 HWTEST_F_L0(JSMapTest, MapCreate)
52 {
53 JSMap *map = CreateMap();
54 EXPECT_TRUE(map != nullptr);
55 }
56
HWTEST_F_L0(JSMapTest,AddAndHas)57 HWTEST_F_L0(JSMapTest, AddAndHas)
58 {
59 ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
60 // create jsMap
61 JSHandle<JSMap> map(thread, CreateMap());
62
63 JSHandle<JSTaggedValue> key(factory->NewFromASCII("key"));
64 JSHandle<JSTaggedValue> value(thread, JSTaggedValue(1));
65 JSMap::Set(thread, map, key, value);
66 EXPECT_TRUE(map->Has(thread, key.GetTaggedValue()));
67 }
68
HWTEST_F_L0(JSMapTest,DeleteAndGet)69 HWTEST_F_L0(JSMapTest, DeleteAndGet)
70 {
71 ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
72 // create jsMap
73 JSHandle<JSMap> map(thread, CreateMap());
74
75 // add 40 keys
76 char keyArray[] = "key0";
77 for (uint32_t i = 0; i < 40; i++) {
78 keyArray[3] = '1' + i;
79 JSHandle<JSTaggedValue> key(factory->NewFromASCII(keyArray));
80 JSHandle<JSTaggedValue> value(thread, JSTaggedValue(i));
81 JSMap::Set(thread, map, key, value);
82 EXPECT_TRUE(map->Has(thread, key.GetTaggedValue()));
83 }
84 EXPECT_EQ(map->GetSize(thread), 40);
85 // whether jsMap has delete key
86 keyArray[3] = '1' + 8;
87 JSHandle<JSTaggedValue> deleteKey(factory->NewFromASCII(keyArray));
88 EXPECT_EQ(map->GetValue(thread, 8), JSTaggedValue(8));
89 JSMap::Delete(thread, map, deleteKey);
90 EXPECT_FALSE(map->Has(thread, deleteKey.GetTaggedValue()));
91 EXPECT_EQ(map->GetSize(thread), 39);
92 }
93
HWTEST_F_L0(JSMapTest,DeleteAndGet2)94 HWTEST_F_L0(JSMapTest, DeleteAndGet2)
95 {
96 ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
97 // create jsMap
98 JSHandle<JSMap> map(thread, CreateMap());
99 JSHandle<JSTaggedValue> mapvalue(map);
100 JSHandle<TaggedArray> taggedArray = factory->NewTaggedArray(10);
101 int pointArr[10];
102 for (uint32_t i = 0; i < 10; i++) {
103 JSHandle<JSObject> obj = factory->NewEmptyJSObject(0);
104 auto *nativePointer = pointArr + i;
105 JSHandle<JSNativePointer> pointer = factory->NewJSNativePointer(nativePointer);
106 Barriers::SetObject<true>(thread, *obj, ECMAObject::HASH_OFFSET, pointer.GetTaggedValue().GetRawData());
107 taggedArray->Set(thread, i, obj);
108 }
109 thread->GetEcmaVM()->CollectGarbage(TriggerGCType::FULL_GC);
110 JSHandle<JSTaggedValue> setfunc =
111 JSObject::GetProperty(thread, mapvalue, thread->GlobalConstants()->GetHandledSetString()).GetValue();
112 JSHandle<JSTaggedValue> getfunc = thread->GetGlobalEnv()->GetMapGet();
113 JSHandle<JSTaggedValue> deletefunc = thread->GetGlobalEnv()->GetMapDelete();
114
115 for (int i = 0; i < 10; i++) {
116 JSHandle<JSTaggedValue> key(thread, taggedArray->Get(thread, i));
117 JSHandle<JSTaggedValue> value(thread, JSTaggedValue(i));
118 auto ecmaRuntimeCallInfo = TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), 8);
119 ecmaRuntimeCallInfo->SetFunction(setfunc.GetTaggedValue());
120 ecmaRuntimeCallInfo->SetThis(map.GetTaggedValue());
121 ecmaRuntimeCallInfo->SetCallArg(key.GetTaggedValue(), value.GetTaggedValue());
122 auto prev = TestHelper::SetupFrame(thread, ecmaRuntimeCallInfo);
123 JSFunction::Call(ecmaRuntimeCallInfo);
124 TestHelper::TearDownFrame(thread, prev);
125 JSTaggedValue hashField =
126 JSTaggedValue(Barriers::GetTaggedValue(thread, key->GetTaggedObject(), ECMAObject::HASH_OFFSET));
127 EXPECT_TRUE(hashField.IsTaggedArray());
128 }
129 thread->GetEcmaVM()->CollectGarbage(TriggerGCType::FULL_GC);
130 for (int i = 0; i < 10; i++) {
131 JSHandle<JSTaggedValue> key(thread, taggedArray->Get(thread, i));
132 auto ecmaRuntimeCallInfo = TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), 6);
133 ecmaRuntimeCallInfo->SetFunction(getfunc.GetTaggedValue());
134 ecmaRuntimeCallInfo->SetThis(map.GetTaggedValue());
135 ecmaRuntimeCallInfo->SetCallArg(key.GetTaggedValue());
136 auto prev = TestHelper::SetupFrame(thread, ecmaRuntimeCallInfo);
137 auto res = JSFunction::Call(ecmaRuntimeCallInfo);
138 EXPECT_TRUE(res.GetInt() == i);
139 TestHelper::TearDownFrame(thread, prev);
140 JSTaggedValue hashField =
141 JSTaggedValue(Barriers::GetTaggedValue(thread, key->GetTaggedObject(), ECMAObject::HASH_OFFSET));
142 EXPECT_TRUE(hashField.IsTaggedArray());
143 }
144 thread->GetEcmaVM()->CollectGarbage(TriggerGCType::FULL_GC);
145 for (int i = 0; i < 10; i++) {
146 JSHandle<JSTaggedValue> key(thread, taggedArray->Get(thread, i));
147 auto ecmaRuntimeCallInfo = TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), 6);
148 ecmaRuntimeCallInfo->SetFunction(deletefunc.GetTaggedValue());
149 ecmaRuntimeCallInfo->SetThis(map.GetTaggedValue());
150 ecmaRuntimeCallInfo->SetCallArg(key.GetTaggedValue());
151 auto prev = TestHelper::SetupFrame(thread, ecmaRuntimeCallInfo);
152 auto res = JSFunction::Call(ecmaRuntimeCallInfo);
153 EXPECT_TRUE(res.IsTrue());
154 TestHelper::TearDownFrame(thread, prev);
155 JSTaggedValue hashField =
156 JSTaggedValue(Barriers::GetTaggedValue(thread, key->GetTaggedObject(), ECMAObject::HASH_OFFSET));
157 EXPECT_TRUE(hashField.IsTaggedArray());
158 }
159 }
160
HWTEST_F_L0(JSMapTest,Iterator)161 HWTEST_F_L0(JSMapTest, Iterator)
162 {
163 ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
164
165 JSHandle<JSMap> map(thread, CreateMap());
166 for (int i = 0; i < 5; i++) {
167 JSHandle<JSTaggedValue> key(thread, JSTaggedValue(i));
168 JSHandle<JSTaggedValue> value(thread, JSTaggedValue(i + 10));
169 JSMap::Set(thread, map, key, value);
170 }
171
172 JSHandle<JSTaggedValue> keyIter(factory->NewJSMapIterator(map, IterationKind::KEY));
173 JSHandle<JSTaggedValue> valueIter(factory->NewJSMapIterator(map, IterationKind::VALUE));
174 JSHandle<JSTaggedValue> iter(factory->NewJSMapIterator(map, IterationKind::KEY_AND_VALUE));
175
176 JSHandle<JSTaggedValue> indexKey(thread, JSTaggedValue(0));
177 JSHandle<JSTaggedValue> elementKey(thread, JSTaggedValue(1));
178
179 JSHandle<JSTaggedValue> keyResult0 = JSIterator::IteratorStep(thread, keyIter);
180 JSHandle<JSTaggedValue> valueResult0 = JSIterator::IteratorStep(thread, valueIter);
181 JSHandle<JSTaggedValue> result0 = JSIterator::IteratorStep(thread, iter);
182
183 EXPECT_EQ(0, JSIterator::IteratorValue(thread, keyResult0)->GetInt());
184 EXPECT_EQ(10, JSIterator::IteratorValue(thread, valueResult0)->GetInt());
185 JSHandle<JSTaggedValue> result0Handle = JSIterator::IteratorValue(thread, result0);
186 EXPECT_EQ(0, JSObject::GetProperty(thread, result0Handle, indexKey).GetValue()->GetInt());
187 EXPECT_EQ(10, JSObject::GetProperty(thread, result0Handle, elementKey).GetValue()->GetInt());
188
189 JSHandle<JSTaggedValue> keyResult1 = JSIterator::IteratorStep(thread, keyIter);
190 EXPECT_EQ(1, JSIterator::IteratorValue(thread, keyResult1)->GetInt());
191 for (int i = 0; i < 3; i++) {
192 JSHandle<JSTaggedValue> key(thread, JSTaggedValue(i));
193 JSMap::Delete(thread, map, key);
194 }
195 JSHandle<JSTaggedValue> keyResult2 = JSIterator::IteratorStep(thread, keyIter);
196 EXPECT_EQ(3, JSIterator::IteratorValue(thread, keyResult2)->GetInt());
197 JSHandle<JSTaggedValue> keyResult3 = JSIterator::IteratorStep(thread, keyIter);
198 EXPECT_EQ(4, JSIterator::IteratorValue(thread, keyResult3)->GetInt());
199 JSHandle<JSTaggedValue> key(thread, JSTaggedValue(5));
200 JSMap::Set(thread, map, key, key);
201 JSHandle<JSTaggedValue> keyResult4 = JSIterator::IteratorStep(thread, keyIter);
202
203 EXPECT_EQ(5, JSIterator::IteratorValue(thread, keyResult4)->GetInt());
204 JSHandle<JSTaggedValue> keyResult5 = JSIterator::IteratorStep(thread, keyIter);
205 EXPECT_EQ(JSTaggedValue::False(), keyResult5.GetTaggedValue());
206 }
207 } // namespace panda::test
208