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/containers/containers_private.h"
17 #include "ecmascript/js_api/js_api_queue_iterator.h"
18 #include "ecmascript/js_api/js_api_queue.h"
19 #include "ecmascript/global_env.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 JSAPIQueueIteratorTest : 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 ecmascript::EcmaHandleScope *scope {nullptr};
50 JSThread *thread {nullptr};
51
52 protected:
CreateQueue(int capacaty=JSAPIQueue::DEFAULT_CAPACITY_LENGTH)53 JSHandle<JSAPIQueue> CreateQueue(int capacaty = JSAPIQueue::DEFAULT_CAPACITY_LENGTH)
54 {
55 ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
56 JSHandle<GlobalEnv> env = thread->GetEcmaVM()->GetGlobalEnv();
57
58 JSHandle<JSTaggedValue> globalObject = env->GetJSGlobalObject();
59 JSHandle<JSTaggedValue> key(factory->NewFromASCII("ArkPrivate"));
60 JSHandle<JSTaggedValue> value =
61 JSObject::GetProperty(thread, JSHandle<JSTaggedValue>(globalObject), key).GetValue();
62
63 auto ecmaRuntimeCallInfo = TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), 6);
64 ecmaRuntimeCallInfo->SetFunction(JSTaggedValue::Undefined());
65 ecmaRuntimeCallInfo->SetThis(value.GetTaggedValue());
66 ecmaRuntimeCallInfo->SetCallArg(0, JSTaggedValue(static_cast<int>(containers::ContainerTag::Queue)));
67
68 [[maybe_unused]] auto prev = TestHelper::SetupFrame(thread, ecmaRuntimeCallInfo);
69 JSTaggedValue result = containers::ContainersPrivate::Load(ecmaRuntimeCallInfo);
70 TestHelper::TearDownFrame(thread, prev);
71
72 JSHandle<JSTaggedValue> constructor(thread, result);
73 JSHandle<JSAPIQueue> jsQueue(factory->NewJSObjectByConstructor(JSHandle<JSFunction>(constructor), constructor));
74 JSHandle<TaggedArray> newElements = factory->NewTaggedArray(capacaty);
75 jsQueue->SetElements(thread, newElements);
76 jsQueue->SetLength(thread, JSTaggedValue(0));
77 jsQueue->SetFront(0);
78 jsQueue->SetTail(0);
79 return jsQueue;
80 }
81 };
82
83 /**
84 * @tc.name: Next
85 * @tc.desc: Create an iterator of JSAPIQueue,and then loop through the elements of the iterator to check whether
86 * the elements are consistent through Next function.
87 * @tc.type: FUNC
88 * @tc.require:
89 */
HWTEST_F_L0(JSAPIQueueIteratorTest,Next)90 HWTEST_F_L0(JSAPIQueueIteratorTest, Next)
91 {
92 constexpr uint32_t DEFAULT_LENGTH = 8;
93 ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
94 JSHandle<JSAPIQueue> jsQueue = CreateQueue();
95 EXPECT_TRUE(*jsQueue != nullptr);
96 JSMutableHandle<JSTaggedValue> value(thread, JSTaggedValue::Undefined());
97 JSHandle<JSTaggedValue> valueStr = thread->GlobalConstants()->GetHandledValueString();
98 // insert value
99 std::string queueValue("keyvalue");
100 for (uint32_t i = 0; i < DEFAULT_LENGTH; i++) {
101 std::string ivalue = queueValue + std::to_string(i);
102 value.Update(factory->NewFromStdString(ivalue).GetTaggedValue());
103 JSAPIQueue::Add(thread, jsQueue, value);
104 }
105 JSHandle<JSAPIQueueIterator> queueIterator = factory->NewJSAPIQueueIterator(jsQueue);
106 for (uint32_t i = 0; i <= DEFAULT_LENGTH; i++) {
107 auto ecmaRuntimeCallInfo = TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), 4);
108 ecmaRuntimeCallInfo->SetFunction(JSTaggedValue::Undefined());
109 ecmaRuntimeCallInfo->SetThis(queueIterator.GetTaggedValue());
110
111 [[maybe_unused]] auto prev = TestHelper::SetupFrame(thread, ecmaRuntimeCallInfo);
112 JSTaggedValue result = JSAPIQueueIterator::Next(ecmaRuntimeCallInfo);
113 TestHelper::TearDownFrame(thread, prev);
114
115 JSHandle<JSObject> resultObj(thread, result);
116 std::string resultValue = queueValue + std::to_string(i);
117 if (i <= DEFAULT_LENGTH - 1U) {
118 value.Update(factory->NewFromStdString(resultValue).GetTaggedValue());
119 EXPECT_EQ(queueIterator->GetNextIndex(), i + 1U);
120 EXPECT_EQ(JSTaggedValue::SameValue(
121 JSObject::GetProperty(thread, resultObj, valueStr).GetValue(), value), true);
122 }
123 else {
124 EXPECT_TRUE(queueIterator->GetIteratedQueue().IsUndefined());
125 EXPECT_TRUE(JSObject::GetProperty(thread, resultObj, valueStr).GetValue()->IsUndefined());
126 }
127 }
128 }
129
130 /**
131 * @tc.name: Next
132 * @tc.desc: test special return of Next, including throw exception and return undefined
133 * @tc.type: FUNC
134 * @tc.require:
135 */
HWTEST_F_L0(JSAPIQueueIteratorTest,SpecialReturnOfNext)136 HWTEST_F_L0(JSAPIQueueIteratorTest, SpecialReturnOfNext)
137 {
138 JSHandle<JSAPIQueue> jsQueue = CreateQueue();
139 ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
140 JSHandle<JSAPIQueueIterator> queueIterator = factory->NewJSAPIQueueIterator(jsQueue);
141 queueIterator->SetIteratedQueue(thread, JSTaggedValue::Undefined());
142
143 // test Next exception
144 {
145 auto ecmaRuntimeCallInfo = TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), 4);
146 ecmaRuntimeCallInfo->SetFunction(JSTaggedValue::Undefined());
147 ecmaRuntimeCallInfo->SetThis(JSTaggedValue::Undefined());
148
149 [[maybe_unused]] auto prev = TestHelper::SetupFrame(thread, ecmaRuntimeCallInfo);
150 JSTaggedValue result = JSAPIQueueIterator::Next(ecmaRuntimeCallInfo);
151 TestHelper::TearDownFrame(thread, prev);
152 EXPECT_EQ(result, JSTaggedValue::Exception());
153 EXPECT_EXCEPTION();
154 }
155
156 // test Next return undefined
157 {
158 auto ecmaRuntimeCallInfo = TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), 4);
159 ecmaRuntimeCallInfo->SetFunction(JSTaggedValue::Undefined());
160 ecmaRuntimeCallInfo->SetThis(queueIterator.GetTaggedValue());
161
162 [[maybe_unused]] auto prev = TestHelper::SetupFrame(thread, ecmaRuntimeCallInfo);
163 JSTaggedValue result = JSAPIQueueIterator::Next(ecmaRuntimeCallInfo);
164 TestHelper::TearDownFrame(thread, prev);
165 EXPECT_EQ(result, thread->GlobalConstants()->GetUndefinedIterResult());
166 }
167 }
168
169
170 /**
171 * @tc.name: SetIteratedQueue
172 * @tc.desc: Call the "SetIteratedQueue" function, check whether the result returned through "GetIteratedQueue"
173 * function from the JSAPIQueueIterator is within expectations.
174 * @tc.type: FUNC
175 * @tc.require:
176 */
HWTEST_F_L0(JSAPIQueueIteratorTest,SetIteratedQueue)177 HWTEST_F_L0(JSAPIQueueIteratorTest, SetIteratedQueue)
178 {
179 constexpr uint32_t DEFAULT_LENGTH = 8;
180 ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
181 JSHandle<JSAPIQueue> jsQueue1 = CreateQueue();
182 JSHandle<JSAPIQueue> jsQueue2 = CreateQueue();
183 EXPECT_TRUE(*jsQueue1 != nullptr);
184 EXPECT_TRUE(*jsQueue2 != nullptr);
185 JSMutableHandle<JSTaggedValue> value(thread, JSTaggedValue::Undefined());
186 // insert value
187 std::string queueValue("keyvalue");
188 for (uint32_t i = 0; i < DEFAULT_LENGTH; i++) {
189 std::string ivalue = queueValue + std::to_string(i);
190 value.Update(factory->NewFromStdString(ivalue).GetTaggedValue());
191 JSAPIQueue::Add(thread, jsQueue1, value);
192 }
193
194 for (uint32_t i = 0; i < DEFAULT_LENGTH; i++) {
195 std::string ivalue = queueValue + std::to_string(i + 1U);
196 value.Update(factory->NewFromStdString(ivalue).GetTaggedValue());
197 JSAPIQueue::Add(thread, jsQueue2, value);
198 }
199 JSHandle<JSAPIQueueIterator> queueIterator = factory->NewJSAPIQueueIterator(jsQueue1);
200 EXPECT_EQ(queueIterator->GetIteratedQueue(), jsQueue1.GetTaggedValue());
201
202 queueIterator->SetIteratedQueue(thread, jsQueue2.GetTaggedValue());
203 EXPECT_EQ(queueIterator->GetIteratedQueue(), jsQueue2.GetTaggedValue());
204 }
205
206 /**
207 * @tc.name: SetNextIndex
208 * @tc.desc: Call the "SetNextIndex" function, check whether the result returned through "GetNextIndex"
209 * function from the JSAPIQueueIterator is within expectations.
210 * @tc.type: FUNC
211 * @tc.require:
212 */
HWTEST_F_L0(JSAPIQueueIteratorTest,SetNextIndex)213 HWTEST_F_L0(JSAPIQueueIteratorTest, SetNextIndex)
214 {
215 constexpr uint32_t DEFAULT_LENGTH = 8;
216 ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
217 JSHandle<JSAPIQueue> jsQueue = CreateQueue();
218 EXPECT_TRUE(*jsQueue != nullptr);
219 JSMutableHandle<JSTaggedValue> value(thread, JSTaggedValue::Undefined());
220 // insert value
221 std::string queueValue("keyvalue");
222 for (uint32_t i = 0; i < DEFAULT_LENGTH; i++) {
223 std::string ivalue = queueValue + std::to_string(i);
224 value.Update(factory->NewFromStdString(ivalue).GetTaggedValue());
225 JSAPIQueue::Add(thread, jsQueue, value);
226 }
227 JSHandle<JSAPIQueueIterator> queueIterator = factory->NewJSAPIQueueIterator(jsQueue);
228 for (uint32_t i = 0; i < DEFAULT_LENGTH; i++) {
229 queueIterator->SetNextIndex(i);
230 EXPECT_EQ(queueIterator->GetNextIndex(), i);
231 }
232 }
233 } // namespace panda::test
234