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