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/builtins/builtins_promise.h"
17
18#include "ecmascript/builtins/builtins_array.h"
19#include "ecmascript/ecma_string.h"
20#include "ecmascript/ecma_vm.h"
21#include "ecmascript/global_env.h"
22#include "ecmascript/jobs/micro_job_queue.h"
23#include "ecmascript/js_array.h"
24#include "ecmascript/js_promise.h"
25#include "ecmascript/js_tagged_value-inl.h"
26#include "ecmascript/js_tagged_value.h"
27#include "ecmascript/js_thread.h"
28#include "ecmascript/object_factory.h"
29#include "ecmascript/tests/test_helper.h"
30
31using namespace panda::ecmascript;
32using namespace panda::ecmascript::builtins;
33
34namespace panda::test {
35using BuiltinsBase = panda::ecmascript::base::BuiltinsBase;
36using JSArray = panda::ecmascript::JSArray;
37
38class BuiltinsPromiseTest : public BaseTestWithScope<false> {
39};
40
41// native function for race2 then_on_rejected()
42JSTaggedValue TestPromiseRaceThenOnRejectd(EcmaRuntimeCallInfo *argv)
43{
44    JSHandle<JSTaggedValue> result = BuiltinsBase::GetCallArg(argv, 0);
45    // 12345 : test case
46    EXPECT_EQ(JSTaggedValue::SameValue(result.GetTaggedValue(), JSTaggedValue(12345)), true);
47    return JSTaggedValue::Undefined();
48}
49
50// native function for all then_on_resolved()
51JSTaggedValue TestPromiseAllThenOnResolved(EcmaRuntimeCallInfo *argv)
52{
53    JSHandle<JSTaggedValue> array = BuiltinsBase::GetCallArg(argv, 0);
54    JSHandle<JSObject> objectArray = JSHandle<JSObject>::Cast(array);
55    [[maybe_unused]] PropertyDescriptor desc(argv->GetThread());
56    [[maybe_unused]] bool result1 = JSObject::GetOwnProperty(
57        argv->GetThread(), objectArray, JSHandle<JSTaggedValue>(argv->GetThread(), JSTaggedValue(0)), desc);
58    EXPECT_TRUE(result1);
59    JSHandle<JSTaggedValue> value1 = desc.GetValue();
60    // 111 : test case
61    EXPECT_EQ(JSTaggedValue::SameValue(value1.GetTaggedValue(), JSTaggedValue(111)), true);
62    [[maybe_unused]] bool result2 = JSObject::GetOwnProperty(
63        argv->GetThread(), objectArray, JSHandle<JSTaggedValue>(argv->GetThread(), JSTaggedValue(1)), desc);
64    EXPECT_TRUE(result2);
65    JSHandle<JSTaggedValue> value2 = desc.GetValue();
66    // 222 : test case
67    EXPECT_EQ(JSTaggedValue::SameValue(value2.GetTaggedValue(), JSTaggedValue(222)), true);
68    return JSTaggedValue::Undefined();
69}
70
71// native function for catch catch_on_rejected()
72JSTaggedValue TestPromiseCatch(EcmaRuntimeCallInfo *argv)
73{
74    JSHandle<JSTaggedValue> result = BuiltinsBase::GetCallArg(argv, 0);
75    // 3 : test case
76    EXPECT_EQ(JSTaggedValue::SameValue(result.GetTaggedValue(), JSTaggedValue(3)), true);
77    return JSTaggedValue::Undefined();
78}
79
80// native function for then then_on_resolved()
81JSTaggedValue TestPromiseThenOnResolved(EcmaRuntimeCallInfo *argv)
82{
83    auto factory = argv->GetThread()->GetEcmaVM()->GetFactory();
84    JSHandle<JSTaggedValue> result = BuiltinsBase::GetCallArg(argv, 0);
85    auto expect = factory->NewFromASCII("resolve");
86    EXPECT_EQ(JSTaggedValue::SameValue(result.GetTaggedValue(), expect.GetTaggedValue()), true);
87    return JSTaggedValue::Undefined();
88}
89
90// native function for then then_on_rejected()
91JSTaggedValue TestPromiseThenOnRejected(EcmaRuntimeCallInfo *argv)
92{
93    auto factory = argv->GetThread()->GetEcmaVM()->GetFactory();
94    JSHandle<JSTaggedValue> result = BuiltinsBase::GetCallArg(argv, 0);
95    auto expect = factory->NewFromASCII("reject");
96    EXPECT_EQ(JSTaggedValue::SameValue(result.GetTaggedValue(), expect.GetTaggedValue()), true);
97    return JSTaggedValue::Undefined();
98}
99
100enum class AlgorithmType {
101    REJECT,
102    RESOLVE,
103    RACE,
104    ALL,
105};
106
107JSTaggedValue PromiseAlgorithm(JSThread *thread, JSHandle<JSFunction>& promise, JSTaggedValue arg,
108    AlgorithmType type)
109{
110    auto ecmaRuntimeCallInfo = TestHelper::CreateEcmaRuntimeCallInfo(thread,  JSTaggedValue(*promise), 6);
111    ecmaRuntimeCallInfo->SetFunction(promise.GetTaggedValue());
112    ecmaRuntimeCallInfo->SetThis(promise.GetTaggedValue());
113    ecmaRuntimeCallInfo->SetCallArg(0, arg);
114
115    auto prev = TestHelper::SetupFrame(thread, ecmaRuntimeCallInfo);
116    JSTaggedValue result;
117    switch (type) {
118        case AlgorithmType::REJECT:
119            result = BuiltinsPromise::Reject(ecmaRuntimeCallInfo);
120            break;
121        case AlgorithmType::RESOLVE:
122            result = BuiltinsPromise::Resolve(ecmaRuntimeCallInfo);
123            break;
124        case AlgorithmType::RACE:
125            result = BuiltinsPromise::Race(ecmaRuntimeCallInfo);
126            break;
127        case AlgorithmType::ALL:
128            result = BuiltinsPromise::All(ecmaRuntimeCallInfo);
129            break;
130        default:
131            break;
132    }
133
134    TestHelper::TearDownFrame(thread, prev);
135    return result;
136}
137
138JSTaggedValue ThanAlgorithm(JSThread *thread, JSHandle<JSPromise>& promise, JSTaggedValue arg1,
139    JSTaggedValue arg2)
140{
141    auto ecmaRuntimeCallInfo = TestHelper::CreateEcmaRuntimeCallInfo(thread,  promise.GetTaggedValue(), 8);
142    ecmaRuntimeCallInfo->SetFunction(promise.GetTaggedValue());
143    ecmaRuntimeCallInfo->SetThis(promise.GetTaggedValue());
144    ecmaRuntimeCallInfo->SetCallArg(0, arg1);
145    ecmaRuntimeCallInfo->SetCallArg(1, arg2);
146    auto prev = TestHelper::SetupFrame(thread, ecmaRuntimeCallInfo);
147    auto result = BuiltinsPromise::Then(ecmaRuntimeCallInfo);
148    TestHelper::TearDownFrame(thread, prev);
149    return result;
150}
151/*
152 * @tc.name: Reject1
153 * @tc.desc: The reject method receives a number.
154 * @tc.type: FUNC
155 */
156HWTEST_F_L0(BuiltinsPromiseTest, Reject1)
157{
158    JSHandle<GlobalEnv> env = instance->GetGlobalEnv();
159
160    JSHandle<JSFunction> promise = JSHandle<JSFunction>::Cast(env->GetPromiseFunction());
161    JSHandle<JSTaggedValue> paramMsg(thread, JSTaggedValue(3));
162
163    // /**
164    //  * @tc.steps: var p1 = Promise.reject(3).
165    //  */
166
167    auto result = PromiseAlgorithm(thread, promise, paramMsg.GetTaggedValue(), AlgorithmType::REJECT);
168    JSHandle<JSPromise> rejectPromise(thread, result);
169    EXPECT_EQ(rejectPromise->GetPromiseState(), PromiseState::REJECTED);
170    EXPECT_EQ(JSTaggedValue::SameValue(rejectPromise->GetPromiseResult(), JSTaggedValue(3)), true);
171}
172
173/*
174 * @tc.name: Reject2
175 * @tc.desc: The reject method receives a promise object.
176 * @tc.type: FUNC
177 */
178HWTEST_F_L0(BuiltinsPromiseTest, Reject2)
179{
180    ObjectFactory *factory = instance->GetFactory();
181    JSHandle<GlobalEnv> env = instance->GetGlobalEnv();
182
183    // constructor promise1
184    JSHandle<JSFunction> promise = JSHandle<JSFunction>::Cast(env->GetPromiseFunction());
185    JSHandle<JSTaggedValue> paramMsg1 =
186        JSHandle<JSTaggedValue>::Cast(factory->NewFromASCII("Promise reject"));
187
188    /**
189     * @tc.steps: step1. var p1 = Promise.reject("Promise reject")
190     */
191    auto result = PromiseAlgorithm(thread, promise, paramMsg1.GetTaggedValue(), AlgorithmType::REJECT);
192    JSHandle<JSPromise> promise1(thread, result);
193    EXPECT_EQ(promise1->GetPromiseState(), PromiseState::REJECTED);
194    EXPECT_EQ(JSTaggedValue::SameValue(promise1->GetPromiseResult(), paramMsg1.GetTaggedValue()), true);
195
196    /**
197     * @tc.steps: step2. var p2 = Promise.reject(p1)
198     */
199    auto result1 = PromiseAlgorithm(thread, promise, promise1.GetTaggedValue(), AlgorithmType::REJECT);
200    JSHandle<JSPromise> promise2(thread, result1);
201    EXPECT_NE(*promise1, *promise2);
202    EXPECT_EQ(promise2->GetPromiseState(), PromiseState::REJECTED);
203    EXPECT_EQ(
204        JSTaggedValue::SameValue(promise2->GetPromiseResult(), JSTaggedValue(promise1.GetTaggedValue().GetRawData())),
205        true);
206}
207
208/*
209 * @tc.name: Resolve1
210 * @tc.desc: The resolve method receives a number.
211 * @tc.type: FUNC
212 */
213HWTEST_F_L0(BuiltinsPromiseTest, Resolve1)
214{
215    JSHandle<GlobalEnv> env = instance->GetGlobalEnv();
216
217    JSHandle<JSFunction> promise = JSHandle<JSFunction>::Cast(env->GetPromiseFunction());
218    JSHandle<JSTaggedValue> paramMsg(thread, JSTaggedValue(5));
219
220    /**
221     * @tc.steps: step1. var p1 = Promise.resolve(12345)
222     */
223    auto result = PromiseAlgorithm(thread, promise, paramMsg.GetTaggedValue(), AlgorithmType::RESOLVE);
224    JSHandle<JSPromise> rejectPromise(thread, result);
225    EXPECT_EQ(rejectPromise->GetPromiseState(), PromiseState::FULFILLED);
226    EXPECT_EQ(JSTaggedValue::SameValue(rejectPromise->GetPromiseResult(), JSTaggedValue(5)), true);
227}
228
229/*
230 * @tc.name: Resolve2
231 * @tc.desc: The resolve method receives a promise object.
232 * @tc.type: FUNC
233 */
234HWTEST_F_L0(BuiltinsPromiseTest, Resolve2)
235{
236    ObjectFactory *factory = instance->GetFactory();
237    JSHandle<GlobalEnv> env = instance->GetGlobalEnv();
238
239    // constructor promise1
240    JSHandle<JSFunction> promise = JSHandle<JSFunction>::Cast(env->GetPromiseFunction());
241    JSHandle<JSTaggedValue> paramMsg1 =
242        JSHandle<JSTaggedValue>::Cast(factory->NewFromASCII("Promise reject"));
243
244    /**
245     * @tc.steps: step1. var p1 = Promise.reject("Promise reject")
246     */
247    auto result = PromiseAlgorithm(thread, promise, paramMsg1.GetTaggedValue(), AlgorithmType::REJECT);
248    JSHandle<JSPromise> promise1(thread, result);
249    EXPECT_EQ(promise1->GetPromiseState(), PromiseState::REJECTED);
250    EXPECT_EQ(JSTaggedValue::SameValue(promise1->GetPromiseResult(), paramMsg1.GetTaggedValue()), true);
251
252    // promise1 Enter Reject() as a parameter.
253    /**
254     * @tc.steps: step2. var p2 = Promise.resolve(p1)
255     */
256    auto result1 = PromiseAlgorithm(thread, promise, promise1.GetTaggedValue(), AlgorithmType::RESOLVE);
257    JSHandle<JSPromise> promise2(thread, result1);
258    EXPECT_EQ(*promise1, *promise2);
259    EXPECT_EQ(promise2->GetPromiseState(), PromiseState::REJECTED);
260    EXPECT_EQ(JSTaggedValue::SameValue(promise2->GetPromiseResult(), paramMsg1.GetTaggedValue()), true);
261}
262
263/*
264 * @tc.name: Race1
265 * @tc.desc: The race method receives an array.
266 * @tc.type: FUNC
267 */
268HWTEST_F_L0(BuiltinsPromiseTest, Race1)
269{
270    JSHandle<GlobalEnv> env = instance->GetGlobalEnv();
271
272    JSHandle<JSFunction> promise = JSHandle<JSFunction>::Cast(env->GetPromiseFunction());
273    JSHandle<JSTaggedValue> paramMsg1(thread, JSTaggedValue(12345));
274
275    /**
276     * @tc.steps: step1. var p1 = Promise.reject(12345)
277     */
278    auto result1 = PromiseAlgorithm(thread, promise, paramMsg1.GetTaggedValue(), AlgorithmType::REJECT);
279    JSHandle<JSPromise> rejectPromise(thread, result1);
280    EXPECT_EQ(rejectPromise->GetPromiseState(), PromiseState::REJECTED);
281    EXPECT_EQ(JSTaggedValue::SameValue(rejectPromise->GetPromiseResult(), JSTaggedValue(12345)), true);
282
283    /**
284     * @tc.steps: step2. var p2 = Promise.resolve(6789)
285     */
286    JSHandle<JSTaggedValue> paramMsg2(thread, JSTaggedValue(6789));
287    auto result2 = PromiseAlgorithm(thread, promise, paramMsg2.GetTaggedValue(), AlgorithmType::RESOLVE);
288    JSHandle<JSPromise> resolvePromise(thread, result2);
289    EXPECT_EQ(resolvePromise->GetPromiseState(), PromiseState::FULFILLED);
290    EXPECT_EQ(JSTaggedValue::SameValue(resolvePromise->GetPromiseResult(), JSTaggedValue(6789)), true);
291    /**
292     * @tc.steps: step3. Construct an array with two elements p1 and p2. array = [p1. p2]
293     */
294    JSHandle<JSObject> array(JSArray::ArrayCreate(thread, JSTaggedNumber(2)));
295    PropertyDescriptor desc(thread, JSHandle<JSTaggedValue>::Cast(rejectPromise));
296    JSArray::DefineOwnProperty(thread, array, JSHandle<JSTaggedValue>(thread, JSTaggedValue(0)), desc);
297
298    PropertyDescriptor desc1(thread, JSHandle<JSTaggedValue>::Cast(resolvePromise));
299    JSArray::DefineOwnProperty(thread, array, JSHandle<JSTaggedValue>(thread, JSTaggedValue(1)), desc1);
300
301    /**
302     * @tc.steps: step4. var p3 = Promise.race([p1,p2]);
303     */
304    auto result4 = PromiseAlgorithm(thread, promise, array.GetTaggedValue(), AlgorithmType::RACE);
305    JSHandle<JSPromise> racePromise(thread, result4);
306    EXPECT_EQ(racePromise->GetPromiseState(), PromiseState::PENDING);
307    EXPECT_EQ(racePromise->GetPromiseResult().IsUndefined(), true);
308}
309
310/*
311 * @tc.name: Race2
312 * @tc.desc: The Race method receives an array, uses the Then method to save the task in the task queue, and outputs
313 * the execution result of the queue.
314 * @tc.type: FUNC
315 */
316HWTEST_F_L0(BuiltinsPromiseTest, Race2)
317{
318    ObjectFactory *factory = instance->GetFactory();
319    JSHandle<GlobalEnv> env = instance->GetGlobalEnv();
320
321    JSHandle<JSFunction> promise = JSHandle<JSFunction>::Cast(env->GetPromiseFunction());
322    JSHandle<JSTaggedValue> paramMsg1(thread, JSTaggedValue(12345));
323    JSHandle<JSTaggedValue> paramMsg2(thread, JSTaggedValue(6789));
324
325    /**
326     * @tc.steps: step1. var p1 = Promise.reject(12345)
327     */
328    auto result1 = PromiseAlgorithm(thread, promise, paramMsg1.GetTaggedValue(), AlgorithmType::REJECT);
329    JSHandle<JSPromise> rejectPromise(thread, result1);
330    EXPECT_EQ(rejectPromise->GetPromiseState(), PromiseState::REJECTED);
331    EXPECT_EQ(JSTaggedValue::SameValue(rejectPromise->GetPromiseResult(), JSTaggedValue(12345)), true);
332
333    /**
334     * @tc.steps: step2. var p2 = Promise.resolve(6789)
335     */
336    auto result2 = PromiseAlgorithm(thread, promise, paramMsg2.GetTaggedValue(), AlgorithmType::RESOLVE);
337    JSHandle<JSPromise> resolvePromise(thread, result2);
338    EXPECT_EQ(resolvePromise->GetPromiseState(), PromiseState::FULFILLED);
339    EXPECT_EQ(JSTaggedValue::SameValue(resolvePromise->GetPromiseResult(), JSTaggedValue(6789)), true);
340
341    /**
342     * @tc.steps: step3. Construct an array with two elements p1 and p2. array = [p1. p2]
343     */
344    JSHandle<JSObject> array(JSArray::ArrayCreate(thread, JSTaggedNumber(2)));
345    PropertyDescriptor desc(thread, JSHandle<JSTaggedValue>::Cast(rejectPromise));
346    JSArray::DefineOwnProperty(thread, array, JSHandle<JSTaggedValue>(thread, JSTaggedValue(0)), desc);
347
348    PropertyDescriptor desc1(thread, JSHandle<JSTaggedValue>::Cast(resolvePromise));
349    JSArray::DefineOwnProperty(thread, array, JSHandle<JSTaggedValue>(thread, JSTaggedValue(1)), desc1);
350
351    /**
352     * @tc.steps: step4. var p3 = Promise.race([p1,p2]);
353     */
354    auto result3 = PromiseAlgorithm(thread, promise, array.GetTaggedValue(), AlgorithmType::RACE);
355    JSHandle<JSPromise> racePromise(thread, result3);
356    EXPECT_EQ(racePromise->GetPromiseState(), PromiseState::PENDING);
357    EXPECT_EQ(racePromise->GetPromiseResult().IsUndefined(), true);
358
359    /**
360     * @tc.steps: step5. p3.then((resolve)=>{print(resolve)}, (reject)=>{print(reject)})
361     */
362    JSHandle<JSFunction> raceThenOnRejected =
363        factory->NewJSFunction(env, reinterpret_cast<void *>(TestPromiseRaceThenOnRejectd));
364    auto thenResult = ThanAlgorithm(thread, racePromise, JSTaggedValue::Undefined(),
365                                    raceThenOnRejected.GetTaggedValue());
366    JSHandle<JSPromise> thenPromise(thread, thenResult);
367
368    EXPECT_EQ(thenPromise->GetPromiseState(), PromiseState::PENDING);
369    EXPECT_TRUE(thenPromise->GetPromiseResult().IsUndefined());
370
371    /**
372     * @tc.steps: step6. execute promise queue
373     */
374    auto microJobQueue = instance->GetJSThread()->GetCurrentEcmaContext()->GetMicroJobQueue();
375    if (!thread->HasPendingException()) {
376        job::MicroJobQueue::ExecutePendingJob(thread, microJobQueue);
377    }
378}
379
380/*
381 * @tc.name: All
382 * @tc.desc: The All method receives an array, uses the Then method to save the task in the task queue, and outputs the
383 * execution result of the queue.
384 * @tc.type: FUNC
385 */
386HWTEST_F_L0(BuiltinsPromiseTest, All)
387{
388    ObjectFactory *factory = instance->GetFactory();
389    JSHandle<GlobalEnv> env = instance->GetGlobalEnv();
390
391    JSHandle<JSFunction> promise = JSHandle<JSFunction>::Cast(env->GetPromiseFunction());
392    JSHandle<JSTaggedValue> paramMsg1(thread, JSTaggedValue(111));
393    JSHandle<JSTaggedValue> paramMsg2(thread, JSTaggedValue(222));
394
395    /**
396     * @tc.steps: step1. var p1 = Promise.resolve(111)
397     */
398    auto result1 = PromiseAlgorithm(thread, promise, paramMsg1.GetTaggedValue(), AlgorithmType::RESOLVE);
399    JSHandle<JSPromise> resolvePromise1(thread, result1);
400    EXPECT_EQ(resolvePromise1->GetPromiseState(), PromiseState::FULFILLED);
401    EXPECT_EQ(JSTaggedValue::SameValue(resolvePromise1->GetPromiseResult(), JSTaggedValue(111)), true);
402
403    /**
404     * @tc.steps: step2. var p2 = Promise.resolve(222)
405     */
406    auto result2 = PromiseAlgorithm(thread, promise, paramMsg2.GetTaggedValue(), AlgorithmType::RESOLVE);
407    JSHandle<JSPromise> resolvePromise2(thread, result2);
408    EXPECT_EQ(resolvePromise2->GetPromiseState(), PromiseState::FULFILLED);
409    EXPECT_EQ(JSTaggedValue::SameValue(resolvePromise2->GetPromiseResult(), JSTaggedValue(222)), true);
410
411    /**
412     * @tc.steps: step3. Construct an array with two elements p1 and p2. array = [p1. p2]
413     */
414    JSHandle<JSObject> array(JSArray::ArrayCreate(thread, JSTaggedNumber(2)));
415    PropertyDescriptor desc(thread, JSHandle<JSTaggedValue>::Cast(resolvePromise1));
416    JSArray::DefineOwnProperty(thread, array, JSHandle<JSTaggedValue>(thread, JSTaggedValue(0)), desc);
417
418    PropertyDescriptor desc1(thread, JSHandle<JSTaggedValue>::Cast(resolvePromise2));
419    JSArray::DefineOwnProperty(thread, array, JSHandle<JSTaggedValue>(thread, JSTaggedValue(1)), desc1);
420
421    /**
422     * @tc.steps: step4. var p3 = Promise.all([p1,p2]);
423     */
424    auto result4 = PromiseAlgorithm(thread, promise, array.GetTaggedValue(), AlgorithmType::ALL);
425    JSHandle<JSPromise> allPromise(thread, result4);
426    EXPECT_EQ(allPromise->GetPromiseState(), PromiseState::PENDING);
427    EXPECT_EQ(allPromise->GetPromiseResult().IsUndefined(), true);
428
429    /**
430     * @tc.steps: step5. p3.then((resolve)=>{print(resolve)}, (reject)=>{print(reject)});
431     */
432    JSHandle<JSFunction> nativeFuncRaceThenOnResolved =
433        factory->NewJSFunction(env, reinterpret_cast<void *>(TestPromiseAllThenOnResolved));
434    auto thenResult = ThanAlgorithm(thread, allPromise, nativeFuncRaceThenOnResolved.GetTaggedValue(),
435                                    nativeFuncRaceThenOnResolved.GetTaggedValue());
436    JSHandle<JSPromise> thenPromise(thread, thenResult);
437
438    EXPECT_EQ(thenPromise->GetPromiseState(), PromiseState::PENDING);
439    EXPECT_TRUE(thenPromise->GetPromiseResult().IsUndefined());
440
441    /**
442     * @tc.steps: step6. execute promise queue
443     */
444    auto microJobQueue = instance->GetJSThread()->GetCurrentEcmaContext()->GetMicroJobQueue();
445    if (!thread->HasPendingException()) {
446        job::MicroJobQueue::ExecutePendingJob(thread, microJobQueue);
447    }
448}
449
450/*
451 * @tc.name: Catch
452 * @tc.desc: test Catch() method
453 * @tc.type: FUNC
454 */
455HWTEST_F_L0(BuiltinsPromiseTest, Catch)
456{
457    auto env = instance->GetGlobalEnv();
458    auto factory = instance->GetFactory();
459
460    JSHandle<JSFunction> promise = JSHandle<JSFunction>::Cast(env->GetPromiseFunction());
461    JSHandle<JSTaggedValue> paramMsg1(thread, JSTaggedValue(3));
462
463    /**
464     * @tc.steps: step1. var p1 = Promise.reject(3)
465     */
466    auto result = PromiseAlgorithm(thread, promise, paramMsg1.GetTaggedValue(), AlgorithmType::REJECT);
467    JSHandle<JSPromise> rejectPromise(thread, result);
468    EXPECT_EQ(rejectPromise->GetPromiseState(), PromiseState::REJECTED);
469    EXPECT_EQ(JSTaggedValue::SameValue(rejectPromise->GetPromiseResult(), JSTaggedValue(3)), true);
470
471    /**
472     * @tc.steps: step2. p1 invokes catch()
473     */
474    JSHandle<JSFunction> testPromiseCatch = factory->NewJSFunction(env, reinterpret_cast<void *>(TestPromiseCatch));
475    auto ecmaRuntimeCallInfo2 = TestHelper::CreateEcmaRuntimeCallInfo(thread, rejectPromise.GetTaggedValue(), 6);
476    ecmaRuntimeCallInfo2->SetFunction(rejectPromise.GetTaggedValue());
477    ecmaRuntimeCallInfo2->SetThis(rejectPromise.GetTaggedValue());
478    ecmaRuntimeCallInfo2->SetCallArg(0, testPromiseCatch.GetTaggedValue());
479
480    [[maybe_unused]] auto prevCatch = TestHelper::SetupFrame(thread, ecmaRuntimeCallInfo2);
481    JSTaggedValue catchResult = BuiltinsPromise::Catch(ecmaRuntimeCallInfo2);
482    JSHandle<JSPromise> catchPromise(thread, catchResult);
483
484    EXPECT_EQ(catchPromise->GetPromiseState(), PromiseState::PENDING);
485    EXPECT_EQ(catchPromise->GetPromiseResult().IsUndefined(), true);
486    TestHelper::TearDownFrame(thread, prevCatch);
487
488    /**
489     * @tc.steps: step3. execute promise queue
490     */
491    auto microJobQueue = instance->GetJSThread()->GetCurrentEcmaContext()->GetMicroJobQueue();
492    if (!thread->HasPendingException()) {
493        job::MicroJobQueue::ExecutePendingJob(thread, microJobQueue);
494    }
495}
496
497/*
498 * @tc.name: ThenResolve
499 * @tc.desc: Testing the Then() function with the Resolve() function
500 * @tc.type: FUNC
501 */
502HWTEST_F_L0(BuiltinsPromiseTest, ThenResolve)
503{
504    auto env = instance->GetGlobalEnv();
505    auto factory = instance->GetFactory();
506
507    JSHandle<JSFunction> promise = JSHandle<JSFunction>::Cast(env->GetPromiseFunction());
508    JSHandle<JSTaggedValue> paramMsg = JSHandle<JSTaggedValue>::Cast(factory->NewFromASCII("resolve"));
509
510    /**
511     * @tc.steps: step1. var p1 = Promise.resolve("resolve")
512     */
513    auto result = PromiseAlgorithm(thread, promise, paramMsg.GetTaggedValue(), AlgorithmType::RESOLVE);
514    JSHandle<JSPromise> resolvePromise(thread, result);
515    EXPECT_EQ(resolvePromise->GetPromiseState(), PromiseState::FULFILLED);
516    EXPECT_EQ(JSTaggedValue::SameValue(resolvePromise->GetPromiseResult(), paramMsg.GetTaggedValue()), true);
517
518    /**
519     * @tc.steps: step2. p1 invokes then()
520     */
521    JSHandle<JSFunction> testPromiseThenOnResolved =
522        factory->NewJSFunction(env, reinterpret_cast<void *>(TestPromiseThenOnResolved));
523    auto thenResult = ThanAlgorithm(thread, resolvePromise, testPromiseThenOnResolved.GetTaggedValue(),
524                                    JSTaggedValue::Undefined());
525    JSHandle<JSPromise> thenPromise(thread, thenResult);
526
527    EXPECT_EQ(thenPromise->GetPromiseState(), PromiseState::PENDING);
528    EXPECT_EQ(thenPromise->GetPromiseResult().IsUndefined(), true);
529
530    /**
531     * @tc.steps: step3.  execute promise queue
532     */
533    auto microJobQueue = instance->GetJSThread()->GetCurrentEcmaContext()->GetMicroJobQueue();
534    if (!thread->HasPendingException()) {
535        job::MicroJobQueue::ExecutePendingJob(thread, microJobQueue);
536    }
537}
538
539/*
540 * @tc.name: ThenReject
541 * @tc.desc: Testing the Then() function with the Reject() function
542 * @tc.type: FUNC
543 */
544HWTEST_F_L0(BuiltinsPromiseTest, ThenReject)
545{
546    auto env = instance->GetGlobalEnv();
547    auto factory = instance->GetFactory();
548
549    JSHandle<JSFunction> promise = JSHandle<JSFunction>::Cast(env->GetPromiseFunction());
550    JSHandle<JSTaggedValue> paramMsg = JSHandle<JSTaggedValue>::Cast(factory->NewFromASCII("reject"));
551
552    /**
553     * @tc.steps: step1. var p1 = Promise.Reject(5)
554     */
555    auto result = PromiseAlgorithm(thread, promise, paramMsg.GetTaggedValue(), AlgorithmType::REJECT);
556    JSHandle<JSPromise> rejectPromise(thread, result);
557    EXPECT_EQ(rejectPromise->GetPromiseState(), PromiseState::REJECTED);
558    EXPECT_EQ(JSTaggedValue::SameValue(rejectPromise->GetPromiseResult(), paramMsg.GetTaggedValue()), true);
559
560    /**
561     * @tc.steps: step1. p1 invokes then()
562     */
563    JSHandle<JSFunction> testPromiseThenOnRejected =
564        factory->NewJSFunction(env, reinterpret_cast<void *>(TestPromiseThenOnRejected));
565    auto thenResult = ThanAlgorithm(thread, rejectPromise, testPromiseThenOnRejected.GetTaggedValue(),
566                                    testPromiseThenOnRejected.GetTaggedValue());
567    JSHandle<JSPromise> thenPromise(thread, thenResult);
568    EXPECT_EQ(thenPromise->GetPromiseState(), PromiseState::PENDING);
569    EXPECT_EQ(thenPromise->GetPromiseResult().IsUndefined(), true);
570    /**
571     * @tc.steps: step3.  execute promise queue
572     */
573    auto microJobQueue = instance->GetJSThread()->GetCurrentEcmaContext()->GetMicroJobQueue();
574    if (!thread->HasPendingException()) {
575        job::MicroJobQueue::ExecutePendingJob(thread, microJobQueue);
576    }
577}
578}  // namespace panda::test
579