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