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_deque.h"
17 #include "ecmascript/containers/containers_private.h"
18 #include "ecmascript/ecma_runtime_call_info.h"
19 #include "ecmascript/global_env.h"
20 #include "ecmascript/js_api/js_api_deque.h"
21 #include "ecmascript/js_api/js_api_deque_iterator.h"
22 #include "ecmascript/js_handle.h"
23 #include "ecmascript/js_tagged_value-inl.h"
24 #include "ecmascript/js_thread.h"
25 #include "ecmascript/object_factory.h"
26 #include "ecmascript/tests/test_helper.h"
27 #include "ecmascript/containers/tests/containers_test_helper.h"
28
29 using namespace panda::ecmascript;
30 using namespace panda::ecmascript::containers;
31
32 namespace panda::test {
33 class ContainersDequeTest : public testing::Test {
34 public:
SetUpTestCase()35 static void SetUpTestCase()
36 {
37 GTEST_LOG_(INFO) << "SetUpTestCase";
38 }
39
TearDownTestCase()40 static void TearDownTestCase()
41 {
42 GTEST_LOG_(INFO) << "TearDownCase";
43 }
44
SetUp()45 void SetUp() override
46 {
47 TestHelper::CreateEcmaVMWithScope(instance, thread, scope);
48 }
49
TearDown()50 void TearDown() override
51 {
52 TestHelper::DestroyEcmaVMWithScope(instance, scope);
53 }
54
55 EcmaVM *instance {nullptr};
56 EcmaHandleScope *scope {nullptr};
57 JSThread *thread {nullptr};
58
59 class TestClass : public base::BuiltinsBase {
60 public:
TestForEachFunc(EcmaRuntimeCallInfo * argv)61 static JSTaggedValue TestForEachFunc(EcmaRuntimeCallInfo *argv)
62 {
63 JSHandle<JSTaggedValue> value = GetCallArg(argv, 0);
64 JSHandle<JSTaggedValue> key = GetCallArg(argv, 1);
65 JSHandle<JSTaggedValue> deque = GetCallArg(argv, 2); // 2 means the secode arg
66 if (!deque->IsUndefined()) {
67 if (value->IsNumber()) {
68 TaggedArray *elements = TaggedArray::Cast(JSAPIDeque::Cast(deque.GetTaggedValue().
69 GetTaggedObject())->GetElements().GetTaggedObject());
70 JSTaggedValue result = elements->Get(key->GetInt());
71 EXPECT_EQ(result, value.GetTaggedValue());
72 }
73 }
74 return JSTaggedValue::True();
75 }
76 };
77 protected:
InitializeDequeConstructor()78 JSTaggedValue InitializeDequeConstructor()
79 {
80 ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
81 JSHandle<GlobalEnv> env = thread->GetEcmaVM()->GetGlobalEnv();
82
83 JSHandle<JSTaggedValue> globalObject = env->GetJSGlobalObject();
84 JSHandle<JSTaggedValue> key(factory->NewFromASCII("ArkPrivate"));
85 JSHandle<JSTaggedValue> value =
86 JSObject::GetProperty(thread, JSHandle<JSTaggedValue>(globalObject), key).GetValue();
87
88 auto objCallInfo = TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), 6);
89 objCallInfo->SetFunction(JSTaggedValue::Undefined());
90 objCallInfo->SetThis(value.GetTaggedValue());
91 objCallInfo->SetCallArg(0, JSTaggedValue(static_cast<int>(ContainerTag::Deque)));
92 [[maybe_unused]] auto prev = TestHelper::SetupFrame(thread, objCallInfo);
93 JSTaggedValue result = ContainersPrivate::Load(objCallInfo);
94 TestHelper::TearDownFrame(thread, prev);
95
96 return result;
97 }
98
CreateJSAPIDeque(JSTaggedValue compare=JSTaggedValue::Undefined ())99 JSHandle<JSAPIDeque> CreateJSAPIDeque(JSTaggedValue compare = JSTaggedValue::Undefined())
100 {
101 JSHandle<JSTaggedValue> compareHandle(thread, compare);
102 JSHandle<JSFunction> newTarget(thread, InitializeDequeConstructor());
103 auto objCallInfo = TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), 6);
104 objCallInfo->SetFunction(newTarget.GetTaggedValue());
105 objCallInfo->SetNewTarget(newTarget.GetTaggedValue());
106 objCallInfo->SetThis(JSTaggedValue::Undefined());
107 objCallInfo->SetCallArg(0, compareHandle.GetTaggedValue());
108
109 [[maybe_unused]] auto prev = TestHelper::SetupFrame(thread, objCallInfo);
110 JSTaggedValue result = ContainersDeque::DequeConstructor(objCallInfo);
111 TestHelper::TearDownFrame(thread, prev);
112 JSHandle<JSAPIDeque> deque(thread, result);
113 return deque;
114 }
115 };
116
HWTEST_F_L0(ContainersDequeTest,DequeConstructor)117 HWTEST_F_L0(ContainersDequeTest, DequeConstructor)
118 {
119 InitializeDequeConstructor();
120 JSHandle<JSFunction> newTarget(thread, InitializeDequeConstructor());
121
122 auto objCallInfo = TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), 4);
123 objCallInfo->SetFunction(newTarget.GetTaggedValue());
124 objCallInfo->SetNewTarget(newTarget.GetTaggedValue());
125 objCallInfo->SetThis(JSTaggedValue::Undefined());
126
127 [[maybe_unused]] auto prev = TestHelper::SetupFrame(thread, objCallInfo);
128 JSTaggedValue result = ContainersDeque::DequeConstructor(objCallInfo);
129 TestHelper::TearDownFrame(thread, prev);
130
131 ASSERT_TRUE(result.IsJSAPIDeque());
132 JSHandle<JSAPIDeque> deque(thread, result);
133 JSTaggedValue resultProto = JSTaggedValue::GetPrototype(thread, JSHandle<JSTaggedValue>(deque));
134 JSTaggedValue funcProto = newTarget->GetFunctionPrototype();
135 ASSERT_EQ(resultProto, funcProto);
136
137 // test DequeConstructor exception
138 objCallInfo->SetNewTarget(JSTaggedValue::Undefined());
139 CONTAINERS_API_EXCEPTION_TEST(ContainersDeque, DequeConstructor, objCallInfo);
140 }
141
HWTEST_F_L0(ContainersDequeTest,InsertFrontAndGetFirst)142 HWTEST_F_L0(ContainersDequeTest, InsertFrontAndGetFirst)
143 {
144 constexpr uint32_t NODE_NUMBERS = 8;
145 JSHandle<JSAPIDeque> deque = CreateJSAPIDeque();
146 for (uint32_t i = 0; i < NODE_NUMBERS; i++) {
147 auto callInfo = TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), 8);
148 callInfo->SetFunction(JSTaggedValue::Undefined());
149 callInfo->SetThis(deque.GetTaggedValue());
150 callInfo->SetCallArg(0, JSTaggedValue(i));
151
152 [[maybe_unused]] auto prev = TestHelper::SetupFrame(thread, callInfo);
153 JSTaggedValue result = ContainersDeque::InsertFront(callInfo);
154 TestHelper::TearDownFrame(thread, prev);
155 EXPECT_EQ(result, JSTaggedValue::True());
156 EXPECT_EQ(ContainersDeque::GetFirst(callInfo), JSTaggedValue(i));
157 }
158 }
159
HWTEST_F_L0(ContainersDequeTest,InsertEndAndGetLast)160 HWTEST_F_L0(ContainersDequeTest, InsertEndAndGetLast)
161 {
162 constexpr uint32_t NODE_NUMBERS = 8;
163 JSHandle<JSAPIDeque> deque = CreateJSAPIDeque();
164 for (uint32_t i = 0; i < NODE_NUMBERS; i++) {
165 auto callInfo = TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), 8);
166 callInfo->SetFunction(JSTaggedValue::Undefined());
167 callInfo->SetThis(deque.GetTaggedValue());
168 callInfo->SetCallArg(0, JSTaggedValue(i));
169
170 [[maybe_unused]] auto prev = TestHelper::SetupFrame(thread, callInfo);
171 JSTaggedValue result = ContainersDeque::InsertEnd(callInfo);
172 TestHelper::TearDownFrame(thread, prev);
173 EXPECT_EQ(result, JSTaggedValue::True());
174 EXPECT_EQ(ContainersDeque::GetLast(callInfo), JSTaggedValue(i));
175 }
176 }
177
HWTEST_F_L0(ContainersDequeTest,Has)178 HWTEST_F_L0(ContainersDequeTest, Has)
179 {
180 constexpr uint32_t NODE_NUMBERS = 8;
181 JSHandle<JSAPIDeque> deque = CreateJSAPIDeque();
182 for (uint32_t i = 0; i < NODE_NUMBERS; i++) {
183 auto callInfo = TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), 8);
184 callInfo->SetFunction(JSTaggedValue::Undefined());
185 callInfo->SetThis(deque.GetTaggedValue());
186 callInfo->SetCallArg(0, JSTaggedValue(i));
187
188 [[maybe_unused]] auto prev = TestHelper::SetupFrame(thread, callInfo);
189 ContainersDeque::InsertEnd(callInfo);
190 TestHelper::TearDownFrame(thread, prev);
191 }
192
193 int num = 7;
194 for (uint32_t i = 0; i < NODE_NUMBERS; i++) {
195 auto callInfo = TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), 6);
196 callInfo->SetFunction(JSTaggedValue::Undefined());
197 callInfo->SetThis(deque.GetTaggedValue());
198 callInfo->SetCallArg(0, JSTaggedValue(i));
199
200 [[maybe_unused]] auto prev = TestHelper::SetupFrame(thread, callInfo);
201 JSTaggedValue result = ContainersDeque::Has(callInfo);
202 TestHelper::TearDownFrame(thread, prev);
203 EXPECT_EQ(result, JSTaggedValue::True());
204 }
205 num = 7;
206 for (uint32_t i = 0; i < NODE_NUMBERS; i++) {
207 auto callInfo = TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), 6);
208 callInfo->SetFunction(JSTaggedValue::Undefined());
209 callInfo->SetThis(deque.GetTaggedValue());
210 callInfo->SetCallArg(0, JSTaggedValue(i + 8));
211
212 [[maybe_unused]] auto prev = TestHelper::SetupFrame(thread, callInfo);
213 JSTaggedValue result = ContainersDeque::Has(callInfo);
214 TestHelper::TearDownFrame(thread, prev);
215 EXPECT_EQ(result, JSTaggedValue::False());
216 }
217 }
218
HWTEST_F_L0(ContainersDequeTest,PopFirst)219 HWTEST_F_L0(ContainersDequeTest, PopFirst)
220 {
221 constexpr uint32_t NODE_NUMBERS = 8;
222 JSHandle<JSAPIDeque> deque = CreateJSAPIDeque();
223 for (uint32_t i = 0; i < NODE_NUMBERS; i++) {
224 auto callInfo = TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), 8);
225 callInfo->SetFunction(JSTaggedValue::Undefined());
226 callInfo->SetThis(deque.GetTaggedValue());
227 callInfo->SetCallArg(0, JSTaggedValue(i));
228
229 [[maybe_unused]] auto prev = TestHelper::SetupFrame(thread, callInfo);
230 ContainersDeque::InsertFront(callInfo);
231 TestHelper::TearDownFrame(thread, prev);
232 EXPECT_EQ(ContainersDeque::PopFirst(callInfo), JSTaggedValue(i));
233 }
234 }
235
HWTEST_F_L0(ContainersDequeTest,PopLast)236 HWTEST_F_L0(ContainersDequeTest, PopLast)
237 {
238 constexpr uint32_t NODE_NUMBERS = 8;
239 JSHandle<JSAPIDeque> deque = CreateJSAPIDeque();
240 for (uint32_t i = 0; i < NODE_NUMBERS; i++) {
241 auto callInfo = TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), 8);
242 callInfo->SetFunction(JSTaggedValue::Undefined());
243 callInfo->SetThis(deque.GetTaggedValue());
244 callInfo->SetCallArg(0, JSTaggedValue(i));
245
246 [[maybe_unused]] auto prev = TestHelper::SetupFrame(thread, callInfo);
247 ContainersDeque::InsertEnd(callInfo);
248 TestHelper::TearDownFrame(thread, prev);
249 EXPECT_EQ(ContainersDeque::PopLast(callInfo), JSTaggedValue(i));
250 }
251 }
252
HWTEST_F_L0(ContainersDequeTest,ForEach)253 HWTEST_F_L0(ContainersDequeTest, ForEach)
254 {
255 constexpr uint32_t NODE_NUMBERS = 8;
256 JSHandle<JSAPIDeque> deque = CreateJSAPIDeque();
257 for (uint32_t i = 0; i < NODE_NUMBERS; i++) {
258 auto callInfo = TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), 8);
259 callInfo->SetFunction(JSTaggedValue::Undefined());
260 callInfo->SetThis(deque.GetTaggedValue());
261 callInfo->SetCallArg(0, JSTaggedValue(i));
262
263 [[maybe_unused]] auto prev = TestHelper::SetupFrame(thread, callInfo);
264 ContainersDeque::InsertEnd(callInfo);
265 TestHelper::TearDownFrame(thread, prev);
266 }
267 ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
268 JSHandle<JSAPIDeque> dlist = CreateJSAPIDeque();
269 {
270 JSHandle<GlobalEnv> env = thread->GetEcmaVM()->GetGlobalEnv();
271 JSHandle<JSFunction> func = factory->NewJSFunction(env, reinterpret_cast<void *>(TestClass::TestForEachFunc));
272 auto callInfo = TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), 8);
273 callInfo->SetFunction(JSTaggedValue::Undefined());
274 callInfo->SetThis(deque.GetTaggedValue());
275 callInfo->SetCallArg(0, func.GetTaggedValue());
276 callInfo->SetCallArg(1, dlist.GetTaggedValue());
277
278 [[maybe_unused]] auto prev = TestHelper::SetupFrame(thread, callInfo);
279 ContainersDeque::ForEach(callInfo);
280 TestHelper::TearDownFrame(thread, prev);
281 }
282 }
283
HWTEST_F_L0(ContainersDequeTest,ProxyOfGetSize)284 HWTEST_F_L0(ContainersDequeTest, ProxyOfGetSize)
285 {
286 constexpr uint32_t NODE_NUMBERS = 10;
287 JSHandle<JSAPIDeque> deque = CreateJSAPIDeque();
288 auto callInfo = TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), 8);
289 callInfo->SetFunction(JSTaggedValue::Undefined());
290 JSHandle<JSProxy> proxy = CreateJSProxyHandle(thread);
291 proxy->SetTarget(thread, deque.GetTaggedValue());
292 callInfo->SetThis(proxy.GetTaggedValue());
293
294 for (uint32_t i = 0; i < NODE_NUMBERS; i++) {
295 callInfo->SetCallArg(0, JSTaggedValue(i));
296 callInfo->SetCallArg(1, JSTaggedValue(i + 1));
297 [[maybe_unused]] auto prev = TestHelper::SetupFrame(thread, callInfo);
298 ContainersDeque::InsertFront(callInfo);
299 TestHelper::TearDownFrame(thread, prev);
300
301 [[maybe_unused]] auto prev1 = TestHelper::SetupFrame(thread, callInfo);
302 JSTaggedValue retult = ContainersDeque::GetSize(callInfo);
303 TestHelper::TearDownFrame(thread, prev1);
304 EXPECT_EQ(retult, JSTaggedValue(i + 1));
305 }
306 }
307
HWTEST_F_L0(ContainersDequeTest,ExceptionReturn)308 HWTEST_F_L0(ContainersDequeTest, ExceptionReturn)
309 {
310 CONTAINERS_API_TYPE_MISMATCH_EXCEPTION_TEST(ContainersDeque, InsertFront);
311 CONTAINERS_API_TYPE_MISMATCH_EXCEPTION_TEST(ContainersDeque, InsertEnd);
312 CONTAINERS_API_TYPE_MISMATCH_EXCEPTION_TEST(ContainersDeque, GetFirst);
313 CONTAINERS_API_TYPE_MISMATCH_EXCEPTION_TEST(ContainersDeque, GetLast);
314 CONTAINERS_API_TYPE_MISMATCH_EXCEPTION_TEST(ContainersDeque, Has);
315 CONTAINERS_API_TYPE_MISMATCH_EXCEPTION_TEST(ContainersDeque, PopFirst);
316 CONTAINERS_API_TYPE_MISMATCH_EXCEPTION_TEST(ContainersDeque, PopLast);
317 CONTAINERS_API_TYPE_MISMATCH_EXCEPTION_TEST(ContainersDeque, ForEach);
318 CONTAINERS_API_TYPE_MISMATCH_EXCEPTION_TEST(ContainersDeque, GetIteratorObj);
319 CONTAINERS_API_TYPE_MISMATCH_EXCEPTION_TEST(ContainersDeque, GetSize);
320 }
321 } // namespace panda::test
322