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