• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2022-2024 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/js_map_iterator.h"
17 #include "ecmascript/global_env.h"
18 #include "ecmascript/linked_hash_table.h"
19 #include "ecmascript/js_array.h"
20 #include "ecmascript/js_map.h"
21 #include "ecmascript/tests/test_helper.h"
22 
23 using namespace panda;
24 using namespace panda::ecmascript;
25 
26 namespace panda::test {
27 class JSMapIteratorTest : public BaseTestWithScope<false> {
28 };
29 
CreateJSMap(JSThread * thread)30 JSHandle<JSMap> CreateJSMap(JSThread *thread)
31 {
32     JSHandle<GlobalEnv> globaEnv = thread->GetEcmaVM()->GetGlobalEnv();
33     ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
34 
35     JSHandle<JSTaggedValue> builtinsMapFunc = globaEnv->GetBuiltinsMapFunction();
36     JSHandle<JSMap> jsMap(factory->NewJSObjectByConstructor(JSHandle<JSFunction>(builtinsMapFunc), builtinsMapFunc));
37     JSHandle<JSTaggedValue> linkedHashMap(LinkedHashMap::Create(thread));
38     jsMap->SetLinkedMap(thread, linkedHashMap);
39     return jsMap;
40 }
41 
42 /**
43  * @tc.name: CreateSetIterator
44  * @tc.desc: Call "CreateSetIterator" function create SetIterator,Check whether the the SetIterator is JSMapIterator
45  *           through "IsJSMapIterator" function is within expectations.
46  * @tc.type: FUNC
47  * @tc.require:
48  */
HWTEST_F_L0(JSMapIteratorTest,CreateMapIterator)49 HWTEST_F_L0(JSMapIteratorTest, CreateMapIterator)
50 {
51     JSHandle<JSMap> jsMap = CreateJSMap(thread);
52 
53     IterationKind iterKind = IterationKind::KEY;
54     JSHandle<JSTaggedValue> mapIteratorKey =
55         JSMapIterator::CreateMapIterator(thread, JSHandle<JSTaggedValue>::Cast(jsMap), iterKind);
56     EXPECT_TRUE(mapIteratorKey->IsJSMapIterator());
57 
58     iterKind = IterationKind::VALUE;
59     JSHandle<JSTaggedValue> mapIteratorValue =
60         JSMapIterator::CreateMapIterator(thread, JSHandle<JSTaggedValue>::Cast(jsMap), iterKind);
61     EXPECT_TRUE(mapIteratorValue->IsJSMapIterator());
62 
63     iterKind = IterationKind::KEY_AND_VALUE;
64     JSHandle<JSTaggedValue> mapIteratorKeyAndValue =
65         JSMapIterator::CreateMapIterator(thread, JSHandle<JSTaggedValue>::Cast(jsMap), iterKind);
66     EXPECT_TRUE(mapIteratorKeyAndValue->IsJSMapIterator());
67 }
68 
69 /**
70  * @tc.name: SetIteratedMap
71  * @tc.desc: Create a JSMapIterator through calling "CreateMapIterator" function with the current thread. Check whether
72  *           the returned value through calling "GetIteratedMap" function from the JSMapIterator is the same with the
73  *           returned value through calling "GetLinkedMap" function. Call "SetIteratedMap" function change LinkedMap,
74  *           Check whether the returned JSTaggedValue through calling "GetNextIndex" function from the JSMapIterator is
75  *           the same with the changed value.
76  * source JSMap.
77  * @tc.type: FUNC
78  * @tc.require:
79  */
HWTEST_F_L0(JSMapIteratorTest,SetIteratedMap)80 HWTEST_F_L0(JSMapIteratorTest, SetIteratedMap)
81 {
82     IterationKind iterKind = IterationKind::KEY;
83     JSHandle<JSMap> jsMap1 = CreateJSMap(thread);
84     JSHandle<JSMap> jsMap2 = CreateJSMap(thread);
85     JSHandle<JSTaggedValue> mapIteratorVal =
86         JSMapIterator::CreateMapIterator(thread, JSHandle<JSTaggedValue>::Cast(jsMap1), iterKind);
87     JSHandle<JSMapIterator> jsMapIterator = JSHandle<JSMapIterator>::Cast(mapIteratorVal);
88 
89     EXPECT_EQ(jsMap1->GetLinkedMap(thread), jsMapIterator->GetIteratedMap(thread));
90     jsMapIterator->SetIteratedMap(thread, JSHandle<JSTaggedValue>(thread, jsMap2->GetLinkedMap(thread)));
91     EXPECT_NE(jsMap1->GetLinkedMap(thread), jsMapIterator->GetIteratedMap(thread));
92     EXPECT_EQ(jsMap2->GetLinkedMap(thread), jsMapIterator->GetIteratedMap(thread));
93 }
94 
95 /**
96  * @tc.name: SetNextIndex
97  * @tc.desc: Create a JSMapIterator through calling "CreateMapIterator" function with the current thread, Check
98  *           whether the returned value through calling "GetNextIndex" function from the JSMapIterator is the same
99  *           as JSTaggedValue(0) Call "SetNextIndex" to change NextIndex, Check whether the returned value through
100  *           calling "GetNextIndex" function from the JSMapIterator is the same with the changed value.
101  * @tc.type: FUNC
102  * @tc.require:
103  */
HWTEST_F_L0(JSMapIteratorTest,SetNextIndex)104 HWTEST_F_L0(JSMapIteratorTest, SetNextIndex)
105 {
106     JSHandle<JSMap> jsMap = CreateJSMap(thread);
107     JSHandle<JSTaggedValue> mapValue(jsMap);
108     JSHandle<JSTaggedValue> mapIteratorVal =
109         JSMapIterator::CreateMapIterator(thread, mapValue, IterationKind::KEY);
110     JSHandle<JSMapIterator> mapIterator = JSHandle<JSMapIterator>::Cast(mapIteratorVal);
111 
112     EXPECT_EQ(mapIterator->GetNextIndex(), 0U);
113     mapIterator->SetNextIndex(1);
114     EXPECT_EQ(mapIterator->GetNextIndex(), 1U);
115 }
116 
117 /**
118  * @tc.name: SetIterationKind
119  * @tc.desc: Create a JSMapIterator through calling CreateMapIterator function with the current thread. Check whether
120  *           the returned value through calling "GetIterationKind" function is the same with JSTaggedValue(0). Check
121  *           whether the returned value through calling "GetIterationKind" function is within expectations after calling
122  *           "SetIterationKind" with the current thread.
123  * @tc.type: FUNC
124  * @tc.require:
125  */
HWTEST_F_L0(JSMapIteratorTest,SetIterationKind)126 HWTEST_F_L0(JSMapIteratorTest, SetIterationKind)
127 {
128     JSHandle<JSMap> jsMap = CreateJSMap(thread);
129     JSHandle<JSTaggedValue> mapValue(jsMap);
130     JSHandle<JSTaggedValue> mapIteratorVal =
131         JSMapIterator::CreateMapIterator(thread, mapValue, IterationKind::KEY);
132     JSHandle<JSMapIterator> mapIterator = JSHandle<JSMapIterator>::Cast(mapIteratorVal);
133     EXPECT_EQ(mapIterator->GetIterationKind(), IterationKind::KEY);
134     mapIterator->SetIterationKind(IterationKind::VALUE);
135     EXPECT_EQ(mapIterator->GetIterationKind(), IterationKind::VALUE);
136     mapIterator->SetIterationKind(IterationKind::KEY_AND_VALUE);
137     EXPECT_EQ(mapIterator->GetIterationKind(), IterationKind::KEY_AND_VALUE);
138 }
139 
140 /**
141  * @tc.name: Update
142  * @tc.desc: Call "NewJSMapIterator" function create MapIterator with emty IteratedMap, create other JSMap and add key
143  *           to it,the old JSMap call "Rehash" function set new JSMap to the next table, then SetIterator call "Update"
144  *           function upadate IteratedMap, check whether the IteratedMap is within expectations.
145  * @tc.type: FUNC
146  * @tc.require:
147  */
HWTEST_F_L0(JSMapIteratorTest,Update)148 HWTEST_F_L0(JSMapIteratorTest, Update)
149 {
150     ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
151     JSHandle<JSMap> jsMap1(thread, CreateJSMap(thread).GetTaggedValue());
152     JSHandle<JSMap> jsMap2(thread, CreateJSMap(thread).GetTaggedValue());
153 
154     JSHandle<JSTaggedValue> keyHandle1(thread, JSTaggedValue(0));
155     JSHandle<JSTaggedValue> keyHandle2(thread, JSTaggedValue(1));
156     JSHandle<JSTaggedValue> keyHandle3(thread, JSTaggedValue(2));  // 2: means key and value
157     // add key and value to jsMap1
158     JSMap::Set(thread, jsMap1, keyHandle1, keyHandle1);
159     JSMap::Set(thread, jsMap1, keyHandle2, keyHandle2);
160     JSMap::Set(thread, jsMap1, keyHandle3, keyHandle3);
161 
162     JSHandle<LinkedHashMap> mapHandle1(thread, LinkedHashMap::Cast(jsMap1->GetLinkedMap(thread).GetTaggedObject()));
163     JSHandle<LinkedHashMap> mapHandle2(thread, LinkedHashMap::Cast(jsMap2->GetLinkedMap(thread).GetTaggedObject()));
164     mapHandle1->Rehash(thread, *mapHandle2);
165     // create SetIterator with jsMap1
166     JSHandle<JSMapIterator> mapIterator = factory->NewJSMapIterator(jsMap1, IterationKind::KEY);
167     // update MapIterator
168     mapIterator->Update(thread);
169     LinkedHashMap *resultMap = LinkedHashMap::Cast(mapIterator->GetIteratedMap(thread).GetTaggedObject());
170     EXPECT_TRUE(resultMap->Has(thread, keyHandle1.GetTaggedValue()));
171     EXPECT_TRUE(resultMap->Has(thread, keyHandle2.GetTaggedValue()));
172     EXPECT_TRUE(resultMap->Has(thread, keyHandle3.GetTaggedValue()));
173 }
174 
175 /**
176  * @tc.name: Next
177  * @tc.desc: Calling "Next" function get the next value from the MapIterator,Check whether the return value obtained
178  *           by the function is the next value in the array element.
179  * @tc.type: FUNC
180  * @tc.require:
181  */
HWTEST_F_L0(JSMapIteratorTest,KEY_VALUE_Next)182 HWTEST_F_L0(JSMapIteratorTest, KEY_VALUE_Next)
183 {
184     JSHandle<JSMap> jsMap = CreateJSMap(thread);
185     int32_t iteratorLength = 5;
186     for (int32_t i = 0; i < iteratorLength; i++) {
187         JSMap::Set(thread, jsMap, JSHandle<JSTaggedValue>(thread, JSTaggedValue(i)),
188             JSHandle<JSTaggedValue>(thread, JSTaggedValue(i + 5)));  // 5: means expected value
189     }
190     JSHandle<JSTaggedValue> mapValue(jsMap);
191     JSHandle<JSMapIterator> mapIterator(JSMapIterator::CreateMapIterator(thread, mapValue, IterationKind::KEY));
192     // 4: argv length
193     auto ecmaRuntimeCallInfo1 = TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), 4);
194     ecmaRuntimeCallInfo1->SetThis(mapIterator.GetTaggedValue());
195     ecmaRuntimeCallInfo1->SetFunction(JSTaggedValue::Undefined());
196     [[maybe_unused]] auto prev = TestHelper::SetupFrame(thread, ecmaRuntimeCallInfo1);
197     for (int32_t i = 0; i < 5; i++) {
198         JSHandle<JSTaggedValue> nextTagValResult(thread, JSMapIterator::Next(ecmaRuntimeCallInfo1));
199         EXPECT_EQ(JSIterator::IteratorValue(thread, nextTagValResult)->GetInt(), i);
200     }
201     TestHelper::TearDownFrame(thread, prev);
202     // change Iterationkind to VALUE
203     mapIterator->SetIterationKind(IterationKind::VALUE);
204     mapIterator->SetNextIndex(0);
205     // 4: argv length
206     auto ecmaRuntimeCallInfo2 = TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), 4);
207     ecmaRuntimeCallInfo2->SetThis(mapIterator.GetTaggedValue());
208     ecmaRuntimeCallInfo2->SetFunction(JSTaggedValue::Undefined());
209     prev = TestHelper::SetupFrame(thread, ecmaRuntimeCallInfo2);
210     for (int32_t i = 0; i < iteratorLength; i++) {
211         JSHandle<JSTaggedValue> nextTagValResult(thread, JSMapIterator::Next(ecmaRuntimeCallInfo2));
212         EXPECT_EQ(JSIterator::IteratorValue(thread, nextTagValResult)->GetInt(), i + 5);  // 5: means expected value
213     }
214     TestHelper::TearDownFrame(thread, prev);
215 }
216 
HWTEST_F_L0(JSMapIteratorTest,KEY_AND_VALUE_Next)217 HWTEST_F_L0(JSMapIteratorTest, KEY_AND_VALUE_Next)
218 {
219     JSHandle<JSMap> jsMap = CreateJSMap(thread);
220     int32_t iteratorLength = 5;
221     for (int32_t i = 0; i < iteratorLength; i++) {
222         JSMap::Set(thread, jsMap, JSHandle<JSTaggedValue>(thread, JSTaggedValue(i)),
223             JSHandle<JSTaggedValue>(thread, JSTaggedValue(i + 10)));   // 10: means expected value
224     }
225     JSHandle<JSTaggedValue> mapValue(jsMap);
226     JSHandle<JSMapIterator> mapIterator(
227         JSMapIterator::CreateMapIterator(thread, mapValue, IterationKind::KEY_AND_VALUE));
228     // 4: argv length
229     auto ecmaRuntimeCallInfo = TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), 4);
230     ecmaRuntimeCallInfo->SetThis(mapIterator.GetTaggedValue());
231     ecmaRuntimeCallInfo->SetFunction(JSTaggedValue::Undefined());
232     [[maybe_unused]] auto prev = TestHelper::SetupFrame(thread, ecmaRuntimeCallInfo);
233     for (int32_t i = 0; i < iteratorLength; i++) {
234         JSHandle<JSTaggedValue> nextTagValResult(thread, JSMapIterator::Next(ecmaRuntimeCallInfo));
235         JSHandle<JSArray> iteratorVal(thread, JSIterator::IteratorValue(thread, nextTagValResult).GetTaggedValue());
236         JSHandle<TaggedArray> elementsIterVal(thread, iteratorVal->GetElements(thread));
237         EXPECT_EQ(i, elementsIterVal->Get(thread, 0).GetInt());
238         EXPECT_EQ(i + 10, elementsIterVal->Get(thread, 1).GetInt());  // 10: means expected value
239     }
240     TestHelper::TearDownFrame(thread, prev);
241 }
242 }  // namespace panda::test
243