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/pending_job.h"
17
18 #include "ecmascript/base/builtins_base.h"
19 #include "ecmascript/global_env.h"
20 #include "ecmascript/js_promise.h"
21 #include "ecmascript/tagged_array.h"
22 #include "ecmascript/tests/test_helper.h"
23
24 using namespace panda::ecmascript;
25 using namespace panda::ecmascript::base;
26
27 namespace panda::test {
28 using PendingJob = ecmascript::job::PendingJob;
29 class PendingJobTest : public testing::Test {
30 public:
SetUpTestCase()31 static void SetUpTestCase()
32 {
33 GTEST_LOG_(INFO) << "SetUpTestCase";
34 }
35
TearDownTestCase()36 static void TearDownTestCase()
37 {
38 GTEST_LOG_(INFO) << "TearDownCase";
39 }
40
SetUp()41 void SetUp() override
42 {
43 TestHelper::CreateEcmaVMWithScope(instance, thread, scope);
44 }
45
TearDown()46 void TearDown() override
47 {
48 TestHelper::DestroyEcmaVMWithScope(instance, scope);
49 }
50
51 EcmaVM *instance {nullptr};
52 EcmaHandleScope *scope {nullptr};
53 JSThread *thread {nullptr};
54 };
55
56 /**
57 * @tc.name: GetJob
58 * @tc.desc: Check whether the result returned through "GetJob" function is within expectations.
59 * @tc.type: FUNC
60 * @tc.require:
61 */
HWTEST_F_L0(PendingJobTest,GetJob)62 HWTEST_F_L0(PendingJobTest, GetJob)
63 {
64 ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
65 JSHandle<GlobalEnv> env = thread->GetEcmaVM()->GetGlobalEnv();
66
67 JSHandle<TaggedArray> handleArgv = factory->NewTaggedArray(0);
68 JSHandle<JSFunction> handleFunc = factory->NewJSFunction(env);
69
70 JSHandle<JSTaggedValue> handlePendingJobVal(factory->NewPendingJob(handleFunc, handleArgv));
71 EXPECT_TRUE(handlePendingJobVal->IsPendingJob());
72 JSHandle<PendingJob> handlePendingJob(handlePendingJobVal);
73 EXPECT_TRUE(handlePendingJob->GetJob(thread).IsJSFunction());
74
75 JSHandle<JSFunction> handleNativeFunc(env->GetTypedArrayFunction());
76 handlePendingJob->SetJob(thread, handleNativeFunc.GetTaggedValue());
77 EXPECT_EQ(JSTaggedValue::SameValue(thread, handlePendingJob->GetJob(thread), handleNativeFunc.GetTaggedValue()),
78 true);
79 }
80
81 /**
82 * @tc.name: GetArguments
83 * @tc.desc: Check whether the result returned through "GetArguments" function is within expectations.
84 * @tc.type: FUNC
85 * @tc.require:
86 */
HWTEST_F_L0(PendingJobTest,GetArguments)87 HWTEST_F_L0(PendingJobTest, GetArguments)
88 {
89 ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
90 JSHandle<GlobalEnv> env = thread->GetEcmaVM()->GetGlobalEnv();
91
92 JSHandle<TaggedArray> handleArgv1 = factory->NewTaggedArray(0);
93 JSHandle<JSFunction> handleFunc = factory->NewJSFunction(env);
94
95 JSHandle<JSTaggedValue> handlePendingJobVal(factory->NewPendingJob(handleFunc, handleArgv1));
96 EXPECT_TRUE(handlePendingJobVal->IsPendingJob());
97 JSHandle<PendingJob> handlePendingJob(handlePendingJobVal);
98 EXPECT_TRUE(handlePendingJob->GetArguments(thread).IsTaggedArray());
99
100 JSHandle<TaggedArray> handleArgv2 = factory->NewTaggedArray(1);
101 handleArgv2->Set(thread, 0, JSTaggedValue(1));
102 handlePendingJob->SetArguments(thread, handleArgv2.GetTaggedValue());
103
104 JSHandle<TaggedArray> resultArray(thread, handlePendingJob->GetArguments(thread));
105 EXPECT_EQ(resultArray->GetLength(), 1U);
106 EXPECT_EQ(resultArray->Get(thread, 0).GetInt(), 1);
107 }
108
109 /**
110 * @tc.name: ExecutePendingJob_001
111 * @tc.desc: Get a function called PromiseReactionJob from env.According to the definition of function,define a
112 * TaggedArray object with length of two.set the required value and define a pendingjob object according
113 * to both.the pendingjob object call "ExecutePendingJob" function to execute the method of function and
114 * return the value of the method.
115 * @tc.type: FUNC
116 * @tc.require:
117 */
HWTEST_F_L0(PendingJobTest,ExecutePendingJob_001)118 HWTEST_F_L0(PendingJobTest, ExecutePendingJob_001)
119 {
120 ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
121 JSHandle<GlobalEnv> env = thread->GetEcmaVM()->GetGlobalEnv();
122 JSHandle<JSTaggedValue> promiseFunc = env->GetPromiseFunction();
123
124 JSHandle<PromiseCapability> capbility = JSPromise::NewPromiseCapability(thread, promiseFunc);
125 JSHandle<JSTaggedValue> reject(thread, capbility->GetReject(thread));
126
127 JSHandle<PromiseReaction> rejectReaction = factory->NewPromiseReaction();
128 rejectReaction->SetPromiseCapability(thread, capbility.GetTaggedValue());
129 rejectReaction->SetHandler(thread, reject.GetTaggedValue());
130
131 JSHandle<JSFunction> promiseReactionsJob(env->GetPromiseReactionJob());
132 JSHandle<TaggedArray> handleArgv = factory->NewTaggedArray(2);
133 handleArgv->Set(thread, 0, rejectReaction.GetTaggedValue());
134 handleArgv->Set(thread, 1, JSTaggedValue(44));
135
136 JSHandle<PendingJob> handlePendingJob = factory->NewPendingJob(promiseReactionsJob, handleArgv);
137 JSTaggedValue callResult = PendingJob::ExecutePendingJob(handlePendingJob, thread);
138 EXPECT_EQ(callResult, JSTaggedValue::Undefined());
139 JSHandle<JSPromise> jsPromise(thread, capbility->GetPromise(thread));
140 EXPECT_EQ(jsPromise->GetPromiseState(), PromiseState::REJECTED);
141 EXPECT_EQ(JSTaggedValue::SameValue(thread, jsPromise->GetPromiseResult(thread), JSTaggedValue(44)), true);
142 }
143
144 /**
145 * @tc.name: ExecutePendingJob_002
146 * @tc.desc: Get a function called PromiseReactionJob from env.According to the definition of function,define a
147 * TaggedArray object with length of two.set the required value and define a pendingjob object according
148 * to both.the pendingjob object call "ExecutePendingJob" function to execute the method of function and
149 * return the value of the method.
150 * @tc.type: FUNC
151 * @tc.require:
152 */
HWTEST_F_L0(PendingJobTest,ExecutePendingJob_002)153 HWTEST_F_L0(PendingJobTest, ExecutePendingJob_002)
154 {
155 ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
156 JSHandle<GlobalEnv> env = thread->GetEcmaVM()->GetGlobalEnv();
157 JSHandle<JSTaggedValue> promiseFunc = env->GetPromiseFunction();
158 JSHandle<JSTaggedValue> paramMsg(factory->NewFromASCII("resolve"));
159
160 JSHandle<PromiseCapability> capbility = JSPromise::NewPromiseCapability(thread, promiseFunc);
161 JSHandle<JSTaggedValue> resolve(thread, capbility->GetResolve(thread));
162
163 JSHandle<PromiseReaction> fulfillReaction = factory->NewPromiseReaction();
164 fulfillReaction->SetPromiseCapability(thread, capbility.GetTaggedValue());
165 fulfillReaction->SetHandler(thread, resolve.GetTaggedValue());
166
167 JSHandle<JSFunction> promiseReactionsJob(env->GetPromiseReactionJob());
168 JSHandle<TaggedArray> handleArgv = factory->NewTaggedArray(2);
169 handleArgv->Set(thread, 0, fulfillReaction.GetTaggedValue());
170 handleArgv->Set(thread, 1, paramMsg.GetTaggedValue());
171
172 JSHandle<PendingJob> handlePendingJob = factory->NewPendingJob(promiseReactionsJob, handleArgv);
173 JSTaggedValue callResult = PendingJob::ExecutePendingJob(handlePendingJob, thread);
174 EXPECT_EQ(callResult, JSTaggedValue::Undefined());
175 JSHandle<JSPromise> jsPromise(thread, capbility->GetPromise(thread));
176 EXPECT_EQ(jsPromise->GetPromiseState(), PromiseState::FULFILLED);
177 EXPECT_EQ(JSTaggedValue::SameValue(thread, jsPromise->GetPromiseResult(thread), paramMsg.GetTaggedValue()), true);
178 }
179
180 /**
181 * @tc.name: ExecutePendingJob_003
182 * @tc.desc: Get a function called PromiseReactionJob from env.According to the definition of function,define a
183 * TaggedArray object with length of two.set the required value and define a pendingjob object according
184 * to both.the pendingjob object call "ExecutePendingJob" function to execute the method of function and
185 * return the value of the method.
186 * @tc.type: FUNC
187 * @tc.require:
188 */
HWTEST_F_L0(PendingJobTest,ExecutePendingJob_003)189 HWTEST_F_L0(PendingJobTest, ExecutePendingJob_003)
190 {
191 ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
192 JSHandle<GlobalEnv> env = thread->GetEcmaVM()->GetGlobalEnv();
193 JSHandle<JSTaggedValue> promiseFunc = env->GetPromiseFunction();
194 JSHandle<JSTaggedValue> paramMsg(factory->NewFromASCII("Thrower"));
195
196 JSHandle<PromiseCapability> capbility = JSPromise::NewPromiseCapability(thread, promiseFunc);
197 JSHandle<PromiseReaction> rejectReaction = factory->NewPromiseReaction();
198 rejectReaction->SetPromiseCapability(thread, capbility.GetTaggedValue());
199 rejectReaction->SetHandler(thread, paramMsg.GetTaggedValue());
200
201 JSHandle<JSFunction> promiseReactionsJob(env->GetPromiseReactionJob());
202 JSHandle<TaggedArray> handleArgv = factory->NewTaggedArray(2);
203 handleArgv->Set(thread, 0, rejectReaction.GetTaggedValue());
204 handleArgv->Set(thread, 1, JSTaggedValue::Undefined());
205
206 JSHandle<PendingJob> handlePendingJob = factory->NewPendingJob(promiseReactionsJob, handleArgv);
207 JSTaggedValue callResult = PendingJob::ExecutePendingJob(handlePendingJob, thread);
208 EXPECT_EQ(callResult, JSTaggedValue::Undefined());
209 JSHandle<JSPromise> jsPromise(thread, capbility->GetPromise(thread));
210 EXPECT_EQ(jsPromise->GetPromiseState(), PromiseState::REJECTED);
211 EXPECT_EQ(JSTaggedValue::SameValue(thread, jsPromise->GetPromiseResult(thread), JSTaggedValue::Undefined()), true);
212 }
213
TestPromiseOnResolved(EcmaRuntimeCallInfo * argv)214 JSTaggedValue TestPromiseOnResolved(EcmaRuntimeCallInfo *argv)
215 {
216 auto thread = argv->GetThread();
217 auto factory = thread->GetEcmaVM()->GetFactory();
218 JSHandle<JSTaggedValue> result = BuiltinsBase::GetCallArg(argv, 0);
219 EXPECT_TRUE(result->IsPromiseReaction());
220 auto handlerMsg = factory->NewFromASCII("after_resolve");
221 JSHandle<PromiseReaction> reaction = JSHandle<PromiseReaction>::Cast(result);
222 JSHandle<JSTaggedValue> handler(argv->GetThread(), reaction->GetHandler(argv->GetThread()));
223 EXPECT_EQ(JSTaggedValue::SameValue(thread, handler.GetTaggedValue(), handlerMsg.GetTaggedValue()), true);
224 return JSTaggedValue::Undefined();
225 }
226
227 /**
228 * @tc.name: ExecutePendingJob_004
229 * @tc.desc: Create a function called TestPromiseOnResolved.According to the definition of function,define a TaggedArray
230 * object with length of two.set the required value and define a pendingjob object according to both.
231 * the pendingjob object call "ExecutePendingJob" function to execute the method of function and return the
232 * value of the method.
233 * @tc.type: FUNC
234 * @tc.require:
235 */
HWTEST_F_L0(PendingJobTest,ExecutePendingJob_004)236 HWTEST_F_L0(PendingJobTest, ExecutePendingJob_004)
237 {
238 ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
239 JSHandle<GlobalEnv> env = thread->GetEcmaVM()->GetGlobalEnv();
240 JSHandle<JSTaggedValue> promiseFunc = env->GetPromiseFunction();
241 JSHandle<JSTaggedValue> paramMsg(factory->NewFromASCII("after_resolve"));
242
243 JSHandle<PromiseCapability> capbility = JSPromise::NewPromiseCapability(thread, promiseFunc);
244 JSHandle<JSTaggedValue> resolve(thread, capbility->GetResolve(thread));
245
246 JSHandle<PromiseReaction> fulfillReaction = factory->NewPromiseReaction();
247 fulfillReaction->SetPromiseCapability(thread, capbility.GetTaggedValue());
248 fulfillReaction->SetHandler(thread, paramMsg.GetTaggedValue());
249
250 JSHandle<JSFunction> testPromiseResolved =
251 factory->NewJSFunction(env, reinterpret_cast<void *>(TestPromiseOnResolved));
252 JSHandle<TaggedArray> handleArgv = factory->NewTaggedArray(2);
253 handleArgv->Set(thread, 0, fulfillReaction.GetTaggedValue());
254 handleArgv->Set(thread, 1, JSTaggedValue::Undefined());
255
256 JSHandle<PendingJob> handlePendingJob = factory->NewPendingJob(testPromiseResolved, handleArgv);
257 JSTaggedValue callResult = PendingJob::ExecutePendingJob(handlePendingJob, thread);
258 EXPECT_EQ(callResult, JSTaggedValue::Undefined());
259 JSHandle<JSPromise> jsPromise(thread, capbility->GetPromise(thread));
260 EXPECT_EQ(jsPromise->GetPromiseState(), PromiseState::PENDING);
261 EXPECT_EQ(jsPromise->GetPromiseResult(thread).IsUndefined(), true);
262 }
263
TestPromiseResolveThenableJob(EcmaRuntimeCallInfo * argv)264 JSTaggedValue TestPromiseResolveThenableJob(EcmaRuntimeCallInfo *argv)
265 {
266 JSHandle<JSTaggedValue> result = BuiltinsBase::GetCallArg(argv, 0);
267 EXPECT_TRUE(result->IsJSFunction());
268 JSHandle<JSTaggedValue> undefined(argv->GetThread(), JSTaggedValue::Undefined());
269 EcmaRuntimeCallInfo *info =
270 EcmaInterpreter::NewRuntimeCallInfo(argv->GetThread(), result, undefined, undefined, 1);
271 info->SetCallArg(JSTaggedValue(44)); // 44 : 44 promise result
272 return JSFunction::Call(info);
273 }
274
275 /**
276 * @tc.name: ExecutePendingJob_005
277 * @tc.desc: Get a function called promiseresolvethenablejob from env. According to the definition of function,
278 * define a TaggedArray object with length of three.set the required value and define a pendingjob object
279 * according to both.The pendingjob object call "ExecutePendingJob" function to execute the method of function
280 * and return the value of the method.
281 * @tc.type: FUNC
282 * @tc.require:
283 */
HWTEST_F_L0(PendingJobTest,ExecutePendingJob_005)284 HWTEST_F_L0(PendingJobTest, ExecutePendingJob_005)
285 {
286 ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
287 JSHandle<GlobalEnv> env = thread->GetEcmaVM()->GetGlobalEnv();
288 JSHandle<JSTaggedValue> promiseFunc = env->GetPromiseFunction();
289 JSHandle<JSTaggedValue> paramMsg(thread, JSTaggedValue::Undefined());
290
291 JSHandle<JSPromise> jsPromise =
292 JSHandle<JSPromise>::Cast(factory->NewJSObjectByConstructor(JSHandle<JSFunction>(promiseFunc), promiseFunc));
293 JSHandle<JSFunction> testPromiseResolveThenableJob =
294 factory->NewJSFunction(env, reinterpret_cast<void *>(TestPromiseResolveThenableJob));
295
296 JSHandle<JSFunction> promiseResolveThenableJob(env->GetPromiseResolveThenableJob());
297 JSHandle<TaggedArray> handleArgv = factory->NewTaggedArray(3);
298 handleArgv->Set(thread, 0, jsPromise.GetTaggedValue());
299 handleArgv->Set(thread, 1, paramMsg.GetTaggedValue());
300 handleArgv->Set(thread, 2, testPromiseResolveThenableJob.GetTaggedValue());
301
302 JSHandle<PendingJob> handlePendingJob = factory->NewPendingJob(promiseResolveThenableJob, handleArgv);
303 JSTaggedValue callResult = PendingJob::ExecutePendingJob(handlePendingJob, thread);
304 EXPECT_EQ(callResult, JSTaggedValue::Undefined());
305
306 EXPECT_EQ(jsPromise->GetPromiseState(), PromiseState::FULFILLED);
307 EXPECT_EQ(JSTaggedValue::SameValue(thread, jsPromise->GetPromiseResult(thread), JSTaggedValue(44)), true);
308 }
309 } // namespace panda::test
310