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_api/js_api_tree_set_iterator.h"
17 #include "ecmascript/containers/containers_private.h"
18 #include "ecmascript/global_env.h"
19 #include "ecmascript/js_api/js_api_tree_set.h"
20 #include "ecmascript/js_iterator.h"
21 #include "ecmascript/tagged_tree.h"
22 #include "ecmascript/tests/test_helper.h"
23
24 using namespace panda;
25 using namespace panda::ecmascript;
26
27 namespace panda::test {
28 class JSAPITreeSetIteratorTest : public testing::Test {
29 public:
SetUpTestCase()30 static void SetUpTestCase()
31 {
32 GTEST_LOG_(INFO) << "SetUpTestCase";
33 }
34
TearDownTestCase()35 static void TearDownTestCase()
36 {
37 GTEST_LOG_(INFO) << "TearDownCase";
38 }
39
SetUp()40 void SetUp() override
41 {
42 TestHelper::CreateEcmaVMWithScope(instance, thread, scope);
43 }
44
TearDown()45 void TearDown() override
46 {
47 TestHelper::DestroyEcmaVMWithScope(instance, scope);
48 }
49
50 EcmaVM *instance {nullptr};
51 ecmascript::EcmaHandleScope *scope {nullptr};
52 JSThread *thread {nullptr};
53
54 protected:
CreateTreeSet()55 JSHandle<JSAPITreeSet> CreateTreeSet()
56 {
57 ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
58 JSHandle<GlobalEnv> env = thread->GetEcmaVM()->GetGlobalEnv();
59
60 JSHandle<JSTaggedValue> globalObject = env->GetJSGlobalObject();
61 JSHandle<JSTaggedValue> key(factory->NewFromASCII("ArkPrivate"));
62 JSHandle<JSTaggedValue> value =
63 JSObject::GetProperty(thread, JSHandle<JSTaggedValue>(globalObject), key).GetValue();
64
65 auto objCallInfo = TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), 6);
66 objCallInfo->SetFunction(JSTaggedValue::Undefined());
67 objCallInfo->SetThis(value.GetTaggedValue());
68 objCallInfo->SetCallArg(0, JSTaggedValue(static_cast<int>(containers::ContainerTag::TreeSet)));
69
70 [[maybe_unused]] auto prev = TestHelper::SetupFrame(thread, objCallInfo);
71 JSTaggedValue result = containers::ContainersPrivate::Load(objCallInfo);
72 TestHelper::TearDownFrame(thread, prev);
73
74 JSHandle<JSTaggedValue> constructor(thread, result);
75 JSHandle<JSAPITreeSet> jsSet(factory->NewJSObjectByConstructor(JSHandle<JSFunction>(constructor), constructor));
76 JSTaggedValue internal = TaggedTreeSet::Create(thread);
77 jsSet->SetTreeSet(thread, internal);
78 return jsSet;
79 }
80 };
81
82 /**
83 * @tc.name: SetIterationKind
84 * @tc.desc: Call the "SetIterationKind" function, check whether the result returned through "GetIterationKind"
85 * function from the JSAPITreeSetIterator is within expectations.
86 * @tc.type: FUNC
87 * @tc.require:
88 */
HWTEST_F_L0(JSAPITreeSetIteratorTest,SetIterationKind)89 HWTEST_F_L0(JSAPITreeSetIteratorTest, SetIterationKind)
90 {
91 ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
92 JSHandle<JSAPITreeSet> jsTreeSet = CreateTreeSet();
93 EXPECT_TRUE(*jsTreeSet != nullptr);
94 JSHandle<JSAPITreeSetIterator> treeSetIterator =
95 factory->NewJSAPITreeSetIterator(jsTreeSet, IterationKind::KEY);
96 EXPECT_EQ(treeSetIterator->GetIterationKind(), IterationKind::KEY);
97 treeSetIterator->SetIterationKind(IterationKind::VALUE);
98 EXPECT_EQ(treeSetIterator->GetIterationKind(), IterationKind::VALUE);
99 treeSetIterator->SetIterationKind(IterationKind::KEY_AND_VALUE);
100 EXPECT_EQ(treeSetIterator->GetIterationKind(), IterationKind::KEY_AND_VALUE);
101 }
102
103 /**
104 * @tc.name: SetIteratedSet
105 * @tc.desc: Call the "SetIteratedSet" function, check whether the result returned through "GetIteratedSet"
106 * function from the JSAPITreeSetIterator is within expectations.
107 * @tc.type: FUNC
108 * @tc.require:
109 */
HWTEST_F_L0(JSAPITreeSetIteratorTest,SetIteratedSet)110 HWTEST_F_L0(JSAPITreeSetIteratorTest, SetIteratedSet)
111 {
112 constexpr uint32_t DEFAULT_LENGTH = 8;
113 ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
114 JSMutableHandle<JSTaggedValue> key(thread, JSTaggedValue::Undefined());
115 JSHandle<JSAPITreeSet> jsTreeSet = CreateTreeSet();
116 EXPECT_TRUE(*jsTreeSet != nullptr);
117 JSHandle<JSAPITreeSetIterator> treeSetIterator =
118 factory->NewJSAPITreeSetIterator(jsTreeSet, IterationKind::VALUE);
119
120 std::string setKey("setkey");
121 for (uint32_t i = 0; i < DEFAULT_LENGTH; i++) {
122 std::string ikey = setKey + std::to_string(i);
123 key.Update(factory->NewFromStdString(ikey).GetTaggedValue());
124 JSAPITreeSet::Add(thread, jsTreeSet, key);
125 }
126 treeSetIterator->SetIteratedSet(thread, jsTreeSet.GetTaggedValue());
127 JSHandle<JSAPITreeSet> treeSetTo(thread, JSAPITreeSet::Cast(treeSetIterator->GetIteratedSet().GetTaggedObject()));
128 EXPECT_EQ(treeSetTo->GetSize(), static_cast<int>(DEFAULT_LENGTH));
129 for (uint32_t i = 0; i < DEFAULT_LENGTH; i++) {
130 std::string ikey = setKey + std::to_string(i);
131 key.Update(factory->NewFromStdString(ikey).GetTaggedValue());
132 EXPECT_TRUE(JSAPITreeSet::Has(thread, jsTreeSet, key));
133 }
134 }
135
136 /**
137 * @tc.name: SetNextIndex
138 * @tc.desc: Call the "SetNextIndex" function, check whether the result returned through "GetNextIndex"
139 * function from the JSAPITreeSetIterator is within expectations.
140 * @tc.type: FUNC
141 * @tc.require:
142 */
HWTEST_F_L0(JSAPITreeSetIteratorTest,SetNextIndex)143 HWTEST_F_L0(JSAPITreeSetIteratorTest, SetNextIndex)
144 {
145 constexpr uint32_t DEFAULT_LENGTH = 8;
146 ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
147 JSHandle<JSAPITreeSet> jsTreeSet = CreateTreeSet();
148 EXPECT_TRUE(*jsTreeSet != nullptr);
149 JSHandle<JSAPITreeSetIterator> treeSetIterator =
150 factory->NewJSAPITreeSetIterator(jsTreeSet, IterationKind::KEY_AND_VALUE);
151 EXPECT_EQ(treeSetIterator->GetNextIndex(), 0U);
152
153 for (uint32_t i = 0; i < DEFAULT_LENGTH; i++) {
154 treeSetIterator->SetNextIndex(i);
155 EXPECT_EQ(treeSetIterator->GetNextIndex(), i);
156 }
157 }
158
159 /**
160 * @tc.name: CreateTreeSetIterator
161 * @tc.desc: Create TreeSet iterator, check whether the result returned through "IsJSAPITreeSetIterator"
162 * function from the JSAPITreeSetIterator is within expectations.
163 * @tc.type: FUNC
164 * @tc.require:
165 */
HWTEST_F_L0(JSAPITreeSetIteratorTest,CreateTreeSetIterator)166 HWTEST_F_L0(JSAPITreeSetIteratorTest, CreateTreeSetIterator)
167 {
168 JSHandle<JSAPITreeSet> jsTreeSet = CreateTreeSet();
169 EXPECT_TRUE(*jsTreeSet != nullptr);
170 JSHandle<JSTaggedValue> treeSetVal(jsTreeSet);
171 // Create Iterator with KEY
172 JSHandle<JSTaggedValue> treeSetIterator =
173 JSAPITreeSetIterator::CreateTreeSetIterator(thread, treeSetVal, IterationKind::KEY);
174 EXPECT_TRUE(*treeSetIterator != nullptr);
175 EXPECT_TRUE(treeSetIterator->IsJSAPITreeSetIterator());
176 // Create Iterator with VALUE
177 treeSetIterator = JSAPITreeSetIterator::CreateTreeSetIterator(thread, treeSetVal, IterationKind::VALUE);
178 EXPECT_TRUE(*treeSetIterator != nullptr);
179 EXPECT_TRUE(treeSetIterator->IsJSAPITreeSetIterator());
180 // Create Iterator with KEY_AND_VALUE
181 treeSetIterator = JSAPITreeSetIterator::CreateTreeSetIterator(thread, treeSetVal, IterationKind::KEY_AND_VALUE);
182 EXPECT_TRUE(*treeSetIterator != nullptr);
183 EXPECT_TRUE(treeSetIterator->IsJSAPITreeSetIterator());
184 }
185
186 /**
187 * @tc.name: Next
188 * @tc.desc: Create an iterator of JSAPITreeSet,and then loop through the elements(key and keyAndvalue) of the
189 * iterator to check whether the elements through "Next" function are consistent.
190 * @tc.type: FUNC
191 * @tc.require:
192 */
HWTEST_F_L0(JSAPITreeSetIteratorTest,KEY_Next)193 HWTEST_F_L0(JSAPITreeSetIteratorTest, KEY_Next)
194 {
195 constexpr uint32_t DEFAULT_LENGTH = 8;
196 ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
197 JSMutableHandle<JSTaggedValue> key(thread, JSTaggedValue::Undefined());
198 JSHandle<JSTaggedValue> valueStr = thread->GlobalConstants()->GetHandledValueString();
199 JSHandle<JSAPITreeSet> jsTreeSet = CreateTreeSet();
200 std::string setKey("setkey");
201 for (uint32_t i = 0; i < DEFAULT_LENGTH; i++) {
202 std::string ikey = setKey + std::to_string(i);
203 key.Update(factory->NewFromStdString(ikey).GetTaggedValue());
204 JSAPITreeSet::Add(thread, jsTreeSet, key);
205 }
206 // Create Iterator with KEY or VALUE
207 JSHandle<JSAPITreeSetIterator> treeSetIterator =
208 factory->NewJSAPITreeSetIterator(jsTreeSet, IterationKind::KEY);
209 // traversal iterator
210 for (uint32_t i = 0; i < DEFAULT_LENGTH; i++) {
211 auto ecmaRuntimeCallInfo = TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), 4);
212 ecmaRuntimeCallInfo->SetFunction(JSTaggedValue::Undefined());
213 ecmaRuntimeCallInfo->SetThis(treeSetIterator.GetTaggedValue());
214
215 [[maybe_unused]] auto prev = TestHelper::SetupFrame(thread, ecmaRuntimeCallInfo);
216 JSTaggedValue result = JSAPITreeSetIterator::Next(ecmaRuntimeCallInfo);
217 TestHelper::TearDownFrame(thread, prev);
218
219 JSHandle<JSObject> resultObj(thread, result);
220 std::string resultKey = setKey + std::to_string(i);
221 key.Update(factory->NewFromStdString(resultKey).GetTaggedValue());
222 EXPECT_EQ(JSTaggedValue::SameValue(
223 JSObject::GetProperty(thread, resultObj, valueStr).GetValue(), key), true);
224 EXPECT_EQ(treeSetIterator->GetNextIndex(), (i + 1U));
225 }
226 }
227
228 /**
229 * @tc.name: Next
230 * @tc.desc: test special return of Next, including throw exception and return undefined
231 * @tc.type: FUNC
232 * @tc.require:
233 */
HWTEST_F_L0(JSAPITreeSetIteratorTest,SpecialReturnOfNext)234 HWTEST_F_L0(JSAPITreeSetIteratorTest, SpecialReturnOfNext)
235 {
236 JSHandle<JSAPITreeSet> jsTreeSet = CreateTreeSet();
237 ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
238 JSHandle<JSAPITreeSetIterator> treeSetIterator = factory->NewJSAPITreeSetIterator(jsTreeSet, IterationKind::KEY);
239 treeSetIterator->SetIteratedSet(thread, JSTaggedValue::Undefined());
240
241 // test Next exception
242 {
243 auto ecmaRuntimeCallInfo = TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), 4);
244 ecmaRuntimeCallInfo->SetFunction(JSTaggedValue::Undefined());
245 ecmaRuntimeCallInfo->SetThis(JSTaggedValue::Undefined());
246
247 [[maybe_unused]] auto prev = TestHelper::SetupFrame(thread, ecmaRuntimeCallInfo);
248 JSTaggedValue result = JSAPITreeSetIterator::Next(ecmaRuntimeCallInfo);
249 TestHelper::TearDownFrame(thread, prev);
250 EXPECT_EQ(result, JSTaggedValue::Exception());
251 EXPECT_EXCEPTION();
252 }
253
254 // test Next return undefined
255 {
256 auto ecmaRuntimeCallInfo = TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), 4);
257 ecmaRuntimeCallInfo->SetFunction(JSTaggedValue::Undefined());
258 ecmaRuntimeCallInfo->SetThis(treeSetIterator.GetTaggedValue());
259
260 [[maybe_unused]] auto prev = TestHelper::SetupFrame(thread, ecmaRuntimeCallInfo);
261 JSTaggedValue result = JSAPITreeSetIterator::Next(ecmaRuntimeCallInfo);
262 TestHelper::TearDownFrame(thread, prev);
263 EXPECT_EQ(result, thread->GlobalConstants()->GetUndefinedIterResult());
264 }
265 }
266
HWTEST_F_L0(JSAPITreeSetIteratorTest,KEY_AND_VALUE_Next)267 HWTEST_F_L0(JSAPITreeSetIteratorTest, KEY_AND_VALUE_Next)
268 {
269 constexpr uint32_t DEFAULT_LENGTH = 8;
270 ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
271 JSMutableHandle<JSTaggedValue> key(thread, JSTaggedValue::Undefined());
272 JSHandle<JSTaggedValue> valueStr = thread->GlobalConstants()->GetHandledValueString();
273 JSHandle<JSAPITreeSet> jsTreeSet = CreateTreeSet();
274 std::string setKey("setkey");
275 for (uint32_t i = 0; i < DEFAULT_LENGTH; i++) {
276 std::string ikey = setKey + std::to_string(i + 1U);
277 key.Update(factory->NewFromStdString(ikey).GetTaggedValue());
278 JSAPITreeSet::Add(thread, jsTreeSet, key);
279 }
280 // Create Iterator with KEY_AND_VALUE
281 JSHandle<JSAPITreeSetIterator> treeSetIterator =
282 factory->NewJSAPITreeSetIterator(jsTreeSet, IterationKind::KEY_AND_VALUE);
283 // traversal iterator
284 for (uint32_t i = 0; i < DEFAULT_LENGTH; i++) {
285 auto ecmaRuntimeCallInfo = TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), 4);
286 ecmaRuntimeCallInfo->SetFunction(JSTaggedValue::Undefined());
287 ecmaRuntimeCallInfo->SetThis(treeSetIterator.GetTaggedValue());
288
289 [[maybe_unused]] auto prev = TestHelper::SetupFrame(thread, ecmaRuntimeCallInfo);
290 JSTaggedValue result = JSAPITreeSetIterator::Next(ecmaRuntimeCallInfo);
291 TestHelper::TearDownFrame(thread, prev);
292
293 JSHandle<JSObject> resultObj(thread, result);
294 std::string resultKeyAndValue = setKey + std::to_string(i + 1U);
295 key.Update(factory->NewFromStdString(resultKeyAndValue).GetTaggedValue());
296
297 JSHandle<JSTaggedValue> keyValueArr(JSObject::GetProperty(thread, resultObj, valueStr).GetValue());
298 for (int index = 0; index < 2; index++) {
299 JSHandle<JSTaggedValue> indexValue(thread, JSTaggedValue(index));
300 EXPECT_EQ(JSTaggedValue::SameValue(
301 JSObject::GetProperty(thread, keyValueArr, indexValue).GetValue(), key), true);
302 }
303 EXPECT_EQ(treeSetIterator->GetNextIndex(), (i + 1U));
304 }
305 }
306 } // namespace panda::ecmascript
307