1 /*
2 * Copyright (c) 2021 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/jobs/micro_job_queue.h"
17
18 #include "ecmascript/jobs/pending_job.h"
19 #include "ecmascript/global_env.h"
20 #include "ecmascript/js_promise.h"
21 #include "ecmascript/tagged_queue.h"
22 #include "ecmascript/tests/test_helper.h"
23
24 using namespace panda::ecmascript;
25
26 namespace panda::test {
27 using MicroJobQueue = ecmascript::job::MicroJobQueue;
28 using PendingJob = ecmascript::job::PendingJob;
29 using QueueType = job::QueueType;
30 class MicroJobQueueTest : public testing::Test {
31 public:
SetUpTestCase()32 static void SetUpTestCase()
33 {
34 GTEST_LOG_(INFO) << "SetUpTestCase";
35 }
36
TearDownTestCase()37 static void TearDownTestCase()
38 {
39 GTEST_LOG_(INFO) << "TearDownCase";
40 }
41
SetUp()42 void SetUp() override
43 {
44 TestHelper::CreateEcmaVMWithScope(instance, thread, scope);
45 }
46
TearDown()47 void TearDown() override
48 {
49 TestHelper::DestroyEcmaVMWithScope(instance, scope);
50 }
51
52 EcmaVM *instance {nullptr};
53 EcmaHandleScope *scope {nullptr};
54 JSThread *thread {nullptr};
55 };
56
57 /**
58 * @tc.name: GetJobQueue
59 * @tc.desc: Check whether the result returned through "GetPromiseJobQueue" and "GetScriptJobQueue" function
60 * is within expectations.
61 * @tc.type: FUNC
62 * @tc.require:
63 */
HWTEST_F_L0(MicroJobQueueTest,GetJobQueue)64 HWTEST_F_L0(MicroJobQueueTest, GetJobQueue)
65 {
66 ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
67 uint32_t capacity = 4;
68 JSHandle<JSTaggedValue> handleValue(thread, JSTaggedValue(123));
69
70 JSHandle<TaggedQueue> handlePromiseQueue = factory->NewTaggedQueue(capacity);
71 TaggedQueue::PushFixedQueue(thread, handlePromiseQueue, handleValue);
72 JSHandle<TaggedQueue> handleScriptQueue = factory->NewTaggedQueue(capacity - 1);
73
74 JSHandle<MicroJobQueue> handleMicroJobQueue = factory->NewMicroJobQueue();
75 EXPECT_TRUE(*handleMicroJobQueue != nullptr);
76
77 handleMicroJobQueue->SetPromiseJobQueue(thread, handlePromiseQueue.GetTaggedValue());
78 handleMicroJobQueue->SetScriptJobQueue(thread, handleScriptQueue.GetTaggedValue());
79
80 JSHandle<TaggedQueue> promiseQueue(thread, handleMicroJobQueue->GetPromiseJobQueue());
81 JSHandle<TaggedQueue> scriptQueue(thread, handleMicroJobQueue->GetScriptJobQueue());
82
83 EXPECT_EQ(promiseQueue->Size(), 1U);
84 EXPECT_EQ(scriptQueue->Size(), 0U);
85
86 EXPECT_EQ(promiseQueue->Back().GetInt(), 123);
87 EXPECT_TRUE(scriptQueue->Back().IsHole());
88 }
89
90 /**
91 * @tc.name: EnqueuePromiseJob
92 * @tc.desc: Get a JobQueue called MicroJobQueue from vm.define a function and TaggedArray object,call EnqueuePromiseJob
93 * function to enter the "function" and TaggedArray object into the promise job queueof the MicroJobQueue,then
94 * check whether the object out of the queue is the same as the object in the queue.
95 * @tc.type: FUNC
96 * @tc.require:
97 */
HWTEST_F_L0(MicroJobQueueTest,EnqueuePromiseJob)98 HWTEST_F_L0(MicroJobQueueTest, EnqueuePromiseJob)
99 {
100 ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
101 JSHandle<GlobalEnv> globalEnv = thread->GetEcmaVM()->GetGlobalEnv();
102 JSHandle<MicroJobQueue> handleMicrojob = thread->GetEcmaVM()->GetMicroJobQueue();
103 JSHandle<TaggedQueue> originalPromiseQueue(thread, handleMicrojob->GetPromiseJobQueue());
104 JSHandle<JSTaggedValue> scriptQueue(thread, handleMicrojob->GetScriptJobQueue());
105
106 JSHandle<TaggedArray> arguments = factory->NewTaggedArray(2);
107 arguments->Set(thread, 0, JSTaggedValue::Undefined());
108 arguments->Set(thread, 1, JSTaggedValue::Undefined());
109 JSHandle<JSFunction> promiseReactionsJob(globalEnv->GetPromiseReactionJob());
110
111 QueueType type = QueueType::QUEUE_PROMISE;
112 MicroJobQueue::EnqueueJob(thread, handleMicrojob, type, promiseReactionsJob, arguments);
113
114 JSHandle<TaggedQueue> promiseQueue(thread, handleMicrojob->GetPromiseJobQueue());
115 EXPECT_EQ(JSTaggedValue::SameValue(promiseQueue.GetTaggedValue(), originalPromiseQueue.GetTaggedValue()), false);
116 EXPECT_EQ(JSTaggedValue::SameValue(handleMicrojob->GetScriptJobQueue(), scriptQueue.GetTaggedValue()), true);
117
118 JSTaggedValue result = promiseQueue->Pop(thread);
119 EXPECT_TRUE(result.IsPendingJob());
120
121 JSHandle<PendingJob> pendingJob(thread, result);
122 EXPECT_EQ(JSTaggedValue::SameValue(pendingJob->GetJob(), promiseReactionsJob.GetTaggedValue()), true);
123 EXPECT_EQ(JSTaggedValue::SameValue(pendingJob->GetArguments(), arguments.GetTaggedValue()), true);
124 }
125
126 /**
127 * @tc.name: EnqueuePromiseJob
128 * @tc.desc: Get a JobQueue called MicroJobQueue from vm.define a function and TaggedArray object,call EnqueuePromiseJob
129 * function to enter the "function" and TaggedArray object into the script job queue of the MicroJobQueue,then
130 * check whether the object out of the queue is the same as the object in the queue.
131 * @tc.type: FUNC
132 * @tc.require:
133 */
HWTEST_F_L0(MicroJobQueueTest,EnqueueScriptJob)134 HWTEST_F_L0(MicroJobQueueTest, EnqueueScriptJob)
135 {
136 ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
137 JSHandle<GlobalEnv> globalEnv = thread->GetEcmaVM()->GetGlobalEnv();
138 JSHandle<MicroJobQueue> handleMicrojob = thread->GetEcmaVM()->GetMicroJobQueue();
139 JSHandle<JSTaggedValue> promiseQueue(thread, handleMicrojob->GetPromiseJobQueue());
140 JSHandle<TaggedQueue> originalScriptQueue(thread, handleMicrojob->GetScriptJobQueue());
141
142 JSHandle<TaggedArray> arguments1 = factory->NewTaggedArray(2);
143 JSHandle<JSFunction> promiseReactionsJob(globalEnv->GetPromiseReactionJob());
144
145 QueueType type = QueueType::QUEUE_SCRIPT;
146 MicroJobQueue::EnqueueJob(thread, handleMicrojob, type, promiseReactionsJob, arguments1);
147
148 JSHandle<JSFunction> promiseResolveThenableJob(globalEnv->GetPromiseResolveThenableJob());
149 JSHandle<TaggedArray> arguments2 = factory->NewTaggedArray(2);
150 arguments2->Set(thread, 0, JSTaggedValue(134));
151 arguments2->Set(thread, 1, JSTaggedValue::Undefined());
152 MicroJobQueue::EnqueueJob(thread, handleMicrojob, type, promiseResolveThenableJob, arguments2);
153
154 JSHandle<TaggedQueue> scriptQueue(thread, handleMicrojob->GetScriptJobQueue());
155 EXPECT_EQ(JSTaggedValue::SameValue(scriptQueue.GetTaggedValue(), originalScriptQueue.GetTaggedValue()), false);
156 EXPECT_EQ(JSTaggedValue::SameValue(handleMicrojob->GetPromiseJobQueue(), promiseQueue.GetTaggedValue()), true);
157
158 JSTaggedValue result1 = scriptQueue->Pop(thread);
159 EXPECT_TRUE(result1.IsPendingJob());
160 // FIFO
161 JSHandle<PendingJob> pendingJob1(thread, result1);
162 EXPECT_EQ(JSTaggedValue::SameValue(pendingJob1->GetJob(), promiseReactionsJob.GetTaggedValue()), true);
163 EXPECT_EQ(JSTaggedValue::SameValue(pendingJob1->GetArguments(), arguments1.GetTaggedValue()), true);
164
165 JSTaggedValue result2 = scriptQueue->Pop(thread);
166 EXPECT_TRUE(result2.IsPendingJob());
167 JSHandle<PendingJob> pendingJob2(thread, result2);
168 EXPECT_EQ(JSTaggedValue::SameValue(pendingJob2->GetJob(), promiseResolveThenableJob.GetTaggedValue()), true);
169 EXPECT_EQ(JSTaggedValue::SameValue(pendingJob2->GetArguments(), arguments2.GetTaggedValue()), true);
170 }
171
172 /**
173 * @tc.name: ExecutePendingJob_001
174 * @tc.desc: Get a JobQueue called MicroJobQueue from vm and get a function called PromiseReactionJob from env.
175 * According to the definition of function,define a TaggedArray object with length of two.set the required
176 * value and enter "function" and TaggedArray object into the promise job queue.Calling "ExecutePendingJob"
177 * function to execute the method of function and return the value of the method.
178 * @tc.type: FUNC
179 * @tc.require:
180 */
HWTEST_F_L0(MicroJobQueueTest,ExecutePendingJob_001)181 HWTEST_F_L0(MicroJobQueueTest, ExecutePendingJob_001)
182 {
183 ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
184 auto env = thread->GetEcmaVM()->GetGlobalEnv();
185 JSHandle<JSFunction> promiseReactionsJob(env->GetPromiseReactionJob());
186 JSHandle<MicroJobQueue> handleMicrojob = thread->GetEcmaVM()->GetMicroJobQueue();
187
188 JSHandle<JSTaggedValue> promiseFunc = env->GetPromiseFunction();
189 JSHandle<PromiseCapability> capbility = JSPromise::NewPromiseCapability(thread, promiseFunc);
190 JSHandle<JSTaggedValue> resolve(thread, capbility->GetResolve());
191
192 JSHandle<PromiseReaction> fulfillReaction = factory->NewPromiseReaction();
193 fulfillReaction->SetPromiseCapability(thread, capbility.GetTaggedValue());
194 fulfillReaction->SetHandler(thread, resolve.GetTaggedValue());
195
196 JSHandle<TaggedArray> arguments = factory->NewTaggedArray(2);
197 arguments->Set(thread, 0, fulfillReaction.GetTaggedValue());
198 arguments->Set(thread, 1, JSTaggedValue::Undefined());
199 MicroJobQueue::EnqueueJob(thread, handleMicrojob, QueueType::QUEUE_PROMISE, promiseReactionsJob, arguments);
200
201 JSHandle<PromiseReaction> rejectReaction = factory->NewPromiseReaction();
202 rejectReaction->SetPromiseCapability(thread, capbility.GetTaggedValue());
203 rejectReaction->SetHandler(thread, resolve.GetTaggedValue());
204
205 // get into the promise queue and execute PendingJob
206 if (!thread->HasPendingException()) {
207 MicroJobQueue::ExecutePendingJob(thread, handleMicrojob);
208 }
209 JSHandle<JSPromise> jsPromise(thread, capbility->GetPromise());
210 EXPECT_EQ(jsPromise->GetPromiseState(), PromiseState::FULFILLED);
211 EXPECT_EQ(JSTaggedValue::SameValue(jsPromise->GetPromiseResult(), JSTaggedValue::Undefined()), true);
212 }
213
214 /**
215 * @tc.name: ExecutePendingJob_002
216 * @tc.desc: Get a JobQueue called MicroJobQueue from vm and get a function called PromiseReactionJob from env.
217 * According to the definition of function,define a TaggedArray object with length of two.set the required
218 * value and enter the "function" and TaggedArray object into the script job queue and promise job queue.
219 * Calling "ExecutePendingJob" function to execute the method of Two queue function and return the value
220 * of the method.
221 * @tc.type: FUNC
222 * @tc.require:
223 */
HWTEST_F_L0(MicroJobQueueTest,ExecutePendingJob_002)224 HWTEST_F_L0(MicroJobQueueTest, ExecutePendingJob_002)
225 {
226 ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
227 auto env = thread->GetEcmaVM()->GetGlobalEnv();
228 JSHandle<JSFunction> promiseReactionsJob(env->GetPromiseReactionJob());
229 JSHandle<MicroJobQueue> handleMicrojob = thread->GetEcmaVM()->GetMicroJobQueue();
230
231 JSHandle<JSTaggedValue> promiseFunc = env->GetPromiseFunction();
232 JSHandle<PromiseCapability> capbility1 = JSPromise::NewPromiseCapability(thread, promiseFunc);
233 JSHandle<JSTaggedValue> resolve(thread, capbility1->GetResolve());
234
235 JSHandle<PromiseReaction> fulfillReaction = factory->NewPromiseReaction();
236 fulfillReaction->SetPromiseCapability(thread, capbility1.GetTaggedValue());
237 fulfillReaction->SetHandler(thread, resolve.GetTaggedValue());
238
239 JSHandle<TaggedArray> arguments1 = factory->NewTaggedArray(2);
240 arguments1->Set(thread, 0, fulfillReaction.GetTaggedValue());
241 arguments1->Set(thread, 1, JSTaggedValue::Undefined());
242 MicroJobQueue::EnqueueJob(thread, handleMicrojob, QueueType::QUEUE_PROMISE, promiseReactionsJob, arguments1);
243
244 JSHandle<PromiseCapability> capbility2 = JSPromise::NewPromiseCapability(thread, promiseFunc);
245 JSHandle<JSTaggedValue> reject(thread, capbility2->GetReject());
246 JSHandle<PromiseReaction> rejectReaction = factory->NewPromiseReaction();
247 rejectReaction->SetPromiseCapability(thread, capbility2.GetTaggedValue());
248 rejectReaction->SetHandler(thread, reject.GetTaggedValue());
249
250 JSHandle<TaggedArray> arguments2 = factory->NewTaggedArray(2);
251 arguments2->Set(thread, 0, rejectReaction.GetTaggedValue());
252 arguments2->Set(thread, 1, JSTaggedValue(32));
253 MicroJobQueue::EnqueueJob(thread, handleMicrojob, QueueType::QUEUE_SCRIPT, promiseReactionsJob, arguments2);
254
255 // get into the promise queue and execute PendingJob
256 if (!thread->HasPendingException()) {
257 MicroJobQueue::ExecutePendingJob(thread, handleMicrojob);
258 }
259 JSHandle<JSPromise> resolvePromise(thread, capbility1->GetPromise());
260 EXPECT_EQ(resolvePromise->GetPromiseState(), PromiseState::FULFILLED);
261 EXPECT_EQ(JSTaggedValue::SameValue(resolvePromise->GetPromiseResult(), JSTaggedValue::Undefined()), true);
262
263 JSHandle<JSPromise> rejectPromise(thread, capbility2->GetPromise());
264 EXPECT_EQ(rejectPromise->GetPromiseState(), PromiseState::REJECTED);
265 EXPECT_EQ(JSTaggedValue::SameValue(rejectPromise->GetPromiseResult(), JSTaggedValue(32)), true);
266 }
267 } // namespace panda::test