1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* This Source Code Form is subject to the terms of the Mozilla Public
3 * License, v. 2.0. If a copy of the MPL was not distributed with this
4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
5
6 #include "VideoUtils.h"
7 #include "base/message_loop.h"
8 #include "gtest/gtest.h"
9 #include "mozilla/MozPromise.h"
10 #include "mozilla/SharedThreadPool.h"
11 #include "mozilla/TaskQueue.h"
12 #include "mozilla/Unused.h"
13 #include "nsISupportsImpl.h"
14
15 using namespace mozilla;
16
17 typedef MozPromise<int, double, false> TestPromise;
18 typedef MozPromise<int, double, true /* exclusive */> TestPromiseExcl;
19 typedef TestPromise::ResolveOrRejectValue RRValue;
20
21 class MOZ_STACK_CLASS AutoTaskQueue {
22 public:
AutoTaskQueue()23 AutoTaskQueue()
24 : mTaskQueue(
25 new TaskQueue(GetMediaThreadPool(MediaThreadType::SUPERVISOR),
26 "TestMozPromise AutoTaskQueue")) {}
27
~AutoTaskQueue()28 ~AutoTaskQueue() { mTaskQueue->AwaitShutdownAndIdle(); }
29
Queue()30 TaskQueue* Queue() { return mTaskQueue; }
31
32 private:
33 RefPtr<TaskQueue> mTaskQueue;
34 };
35
36 class DelayedResolveOrReject : public Runnable {
37 public:
DelayedResolveOrReject(TaskQueue * aTaskQueue,TestPromise::Private * aPromise,const TestPromise::ResolveOrRejectValue & aValue,int aIterations)38 DelayedResolveOrReject(TaskQueue* aTaskQueue, TestPromise::Private* aPromise,
39 const TestPromise::ResolveOrRejectValue& aValue,
40 int aIterations)
41 : mozilla::Runnable("DelayedResolveOrReject"),
42 mTaskQueue(aTaskQueue),
43 mPromise(aPromise),
44 mValue(aValue),
45 mIterations(aIterations) {}
46
Run()47 NS_IMETHOD Run() override {
48 MOZ_ASSERT(mTaskQueue->IsCurrentThreadIn());
49 if (!mPromise) {
50 // Canceled.
51 return NS_OK;
52 }
53
54 if (--mIterations == 0) {
55 mPromise->ResolveOrReject(mValue, __func__);
56 return NS_OK;
57 }
58
59 nsCOMPtr<nsIRunnable> r = this;
60 return mTaskQueue->Dispatch(r.forget());
61 }
62
Cancel()63 void Cancel() { mPromise = nullptr; }
64
65 protected:
66 ~DelayedResolveOrReject() = default;
67
68 private:
69 RefPtr<TaskQueue> mTaskQueue;
70 RefPtr<TestPromise::Private> mPromise;
71 TestPromise::ResolveOrRejectValue mValue;
72 int mIterations;
73 };
74
75 template <typename FunctionType>
RunOnTaskQueue(TaskQueue * aQueue,FunctionType aFun)76 void RunOnTaskQueue(TaskQueue* aQueue, FunctionType aFun) {
77 nsCOMPtr<nsIRunnable> r = NS_NewRunnableFunction("RunOnTaskQueue", aFun);
78 Unused << aQueue->Dispatch(r.forget());
79 }
80
81 // std::function can't come soon enough. :-(
82 #define DO_FAIL \
83 []() { \
84 EXPECT_TRUE(false); \
85 return TestPromise::CreateAndReject(0, __func__); \
86 }
87
TEST(MozPromise,BasicResolve)88 TEST(MozPromise, BasicResolve)
89 {
90 AutoTaskQueue atq;
91 RefPtr<TaskQueue> queue = atq.Queue();
92 RunOnTaskQueue(queue, [queue]() -> void {
93 TestPromise::CreateAndResolve(42, __func__)
94 ->Then(
95 queue, __func__,
96 [queue](int aResolveValue) -> void {
97 EXPECT_EQ(aResolveValue, 42);
98 queue->BeginShutdown();
99 },
100 DO_FAIL);
101 });
102 }
103
TEST(MozPromise,BasicReject)104 TEST(MozPromise, BasicReject)
105 {
106 AutoTaskQueue atq;
107 RefPtr<TaskQueue> queue = atq.Queue();
108 RunOnTaskQueue(queue, [queue]() -> void {
109 TestPromise::CreateAndReject(42.0, __func__)
110 ->Then(queue, __func__, DO_FAIL, [queue](int aRejectValue) -> void {
111 EXPECT_EQ(aRejectValue, 42.0);
112 queue->BeginShutdown();
113 });
114 });
115 }
116
TEST(MozPromise,BasicResolveOrRejectResolved)117 TEST(MozPromise, BasicResolveOrRejectResolved)
118 {
119 AutoTaskQueue atq;
120 RefPtr<TaskQueue> queue = atq.Queue();
121 RunOnTaskQueue(queue, [queue]() -> void {
122 TestPromise::CreateAndResolve(42, __func__)
123 ->Then(
124 queue, __func__,
125 [queue](const TestPromise::ResolveOrRejectValue& aValue) -> void {
126 EXPECT_TRUE(aValue.IsResolve());
127 EXPECT_FALSE(aValue.IsReject());
128 EXPECT_FALSE(aValue.IsNothing());
129 EXPECT_EQ(aValue.ResolveValue(), 42);
130 queue->BeginShutdown();
131 });
132 });
133 }
134
TEST(MozPromise,BasicResolveOrRejectRejected)135 TEST(MozPromise, BasicResolveOrRejectRejected)
136 {
137 AutoTaskQueue atq;
138 RefPtr<TaskQueue> queue = atq.Queue();
139 RunOnTaskQueue(queue, [queue]() -> void {
140 TestPromise::CreateAndReject(42.0, __func__)
141 ->Then(
142 queue, __func__,
143 [queue](const TestPromise::ResolveOrRejectValue& aValue) -> void {
144 EXPECT_TRUE(aValue.IsReject());
145 EXPECT_FALSE(aValue.IsResolve());
146 EXPECT_FALSE(aValue.IsNothing());
147 EXPECT_EQ(aValue.RejectValue(), 42.0);
148 queue->BeginShutdown();
149 });
150 });
151 }
152
TEST(MozPromise,AsyncResolve)153 TEST(MozPromise, AsyncResolve)
154 {
155 AutoTaskQueue atq;
156 RefPtr<TaskQueue> queue = atq.Queue();
157 RunOnTaskQueue(queue, [queue]() -> void {
158 RefPtr<TestPromise::Private> p = new TestPromise::Private(__func__);
159
160 // Kick off three racing tasks, and make sure we get the one that finishes
161 // earliest.
162 RefPtr<DelayedResolveOrReject> a =
163 new DelayedResolveOrReject(queue, p, RRValue::MakeResolve(32), 10);
164 RefPtr<DelayedResolveOrReject> b =
165 new DelayedResolveOrReject(queue, p, RRValue::MakeResolve(42), 5);
166 RefPtr<DelayedResolveOrReject> c =
167 new DelayedResolveOrReject(queue, p, RRValue::MakeReject(32.0), 7);
168
169 nsCOMPtr<nsIRunnable> ref = a.get();
170 Unused << queue->Dispatch(ref.forget());
171 ref = b.get();
172 Unused << queue->Dispatch(ref.forget());
173 ref = c.get();
174 Unused << queue->Dispatch(ref.forget());
175
176 p->Then(
177 queue, __func__,
178 [queue, a, b, c](int aResolveValue) -> void {
179 EXPECT_EQ(aResolveValue, 42);
180 a->Cancel();
181 b->Cancel();
182 c->Cancel();
183 queue->BeginShutdown();
184 },
185 DO_FAIL);
186 });
187 }
188
TEST(MozPromise,CompletionPromises)189 TEST(MozPromise, CompletionPromises)
190 {
191 bool invokedPass = false;
192 AutoTaskQueue atq;
193 RefPtr<TaskQueue> queue = atq.Queue();
194 RunOnTaskQueue(queue, [queue, &invokedPass]() -> void {
195 TestPromise::CreateAndResolve(40, __func__)
196 ->Then(
197 queue, __func__,
198 [](int aVal) -> RefPtr<TestPromise> {
199 return TestPromise::CreateAndResolve(aVal + 10, __func__);
200 },
201 DO_FAIL)
202 ->Then(
203 queue, __func__,
204 [&invokedPass](int aVal) {
205 invokedPass = true;
206 return TestPromise::CreateAndResolve(aVal, __func__);
207 },
208 DO_FAIL)
209 ->Then(
210 queue, __func__,
211 [queue](int aVal) -> RefPtr<TestPromise> {
212 RefPtr<TestPromise::Private> p =
213 new TestPromise::Private(__func__);
214 nsCOMPtr<nsIRunnable> resolver = new DelayedResolveOrReject(
215 queue, p, RRValue::MakeResolve(aVal - 8), 10);
216 Unused << queue->Dispatch(resolver.forget());
217 return RefPtr<TestPromise>(p);
218 },
219 DO_FAIL)
220 ->Then(
221 queue, __func__,
222 [](int aVal) -> RefPtr<TestPromise> {
223 return TestPromise::CreateAndReject(double(aVal - 42) + 42.0,
224 __func__);
225 },
226 DO_FAIL)
227 ->Then(queue, __func__, DO_FAIL,
228 [queue, &invokedPass](double aVal) -> void {
229 EXPECT_EQ(aVal, 42.0);
230 EXPECT_TRUE(invokedPass);
231 queue->BeginShutdown();
232 });
233 });
234 }
235
TEST(MozPromise,PromiseAllResolve)236 TEST(MozPromise, PromiseAllResolve)
237 {
238 AutoTaskQueue atq;
239 RefPtr<TaskQueue> queue = atq.Queue();
240 RunOnTaskQueue(queue, [queue]() -> void {
241 nsTArray<RefPtr<TestPromise>> promises;
242 promises.AppendElement(TestPromise::CreateAndResolve(22, __func__));
243 promises.AppendElement(TestPromise::CreateAndResolve(32, __func__));
244 promises.AppendElement(TestPromise::CreateAndResolve(42, __func__));
245
246 TestPromise::All(queue, promises)
247 ->Then(
248 queue, __func__,
249 [queue](const CopyableTArray<int>& aResolveValues) -> void {
250 EXPECT_EQ(aResolveValues.Length(), 3UL);
251 EXPECT_EQ(aResolveValues[0], 22);
252 EXPECT_EQ(aResolveValues[1], 32);
253 EXPECT_EQ(aResolveValues[2], 42);
254 queue->BeginShutdown();
255 },
256 []() { EXPECT_TRUE(false); });
257 });
258 }
259
TEST(MozPromise,PromiseAllResolveAsync)260 TEST(MozPromise, PromiseAllResolveAsync)
261 {
262 AutoTaskQueue atq;
263 RefPtr<TaskQueue> queue = atq.Queue();
264 RunOnTaskQueue(queue, [queue]() -> void {
265 nsTArray<RefPtr<TestPromise>> promises;
266 promises.AppendElement(InvokeAsync(queue, __func__, []() {
267 return TestPromise::CreateAndResolve(22, __func__);
268 }));
269 promises.AppendElement(InvokeAsync(queue, __func__, []() {
270 return TestPromise::CreateAndResolve(32, __func__);
271 }));
272 promises.AppendElement(InvokeAsync(queue, __func__, []() {
273 return TestPromise::CreateAndResolve(42, __func__);
274 }));
275
276 TestPromise::All(queue, promises)
277 ->Then(
278 queue, __func__,
279 [queue](const CopyableTArray<int>& aResolveValues) -> void {
280 EXPECT_EQ(aResolveValues.Length(), 3UL);
281 EXPECT_EQ(aResolveValues[0], 22);
282 EXPECT_EQ(aResolveValues[1], 32);
283 EXPECT_EQ(aResolveValues[2], 42);
284 queue->BeginShutdown();
285 },
286 []() { EXPECT_TRUE(false); });
287 });
288 }
289
TEST(MozPromise,PromiseAllReject)290 TEST(MozPromise, PromiseAllReject)
291 {
292 AutoTaskQueue atq;
293 RefPtr<TaskQueue> queue = atq.Queue();
294 RunOnTaskQueue(queue, [queue]() -> void {
295 nsTArray<RefPtr<TestPromise>> promises;
296 promises.AppendElement(TestPromise::CreateAndResolve(22, __func__));
297 promises.AppendElement(TestPromise::CreateAndReject(32.0, __func__));
298 promises.AppendElement(TestPromise::CreateAndResolve(42, __func__));
299 // Ensure that more than one rejection doesn't cause a crash (bug #1207312)
300 promises.AppendElement(TestPromise::CreateAndReject(52.0, __func__));
301
302 TestPromise::All(queue, promises)
303 ->Then(
304 queue, __func__, []() { EXPECT_TRUE(false); },
305 [queue](float aRejectValue) -> void {
306 EXPECT_EQ(aRejectValue, 32.0);
307 queue->BeginShutdown();
308 });
309 });
310 }
311
TEST(MozPromise,PromiseAllRejectAsync)312 TEST(MozPromise, PromiseAllRejectAsync)
313 {
314 AutoTaskQueue atq;
315 RefPtr<TaskQueue> queue = atq.Queue();
316 RunOnTaskQueue(queue, [queue]() -> void {
317 nsTArray<RefPtr<TestPromise>> promises;
318 promises.AppendElement(InvokeAsync(queue, __func__, []() {
319 return TestPromise::CreateAndResolve(22, __func__);
320 }));
321 promises.AppendElement(InvokeAsync(queue, __func__, []() {
322 return TestPromise::CreateAndReject(32.0, __func__);
323 }));
324 promises.AppendElement(InvokeAsync(queue, __func__, []() {
325 return TestPromise::CreateAndResolve(42, __func__);
326 }));
327 // Ensure that more than one rejection doesn't cause a crash (bug #1207312)
328 promises.AppendElement(InvokeAsync(queue, __func__, []() {
329 return TestPromise::CreateAndReject(52.0, __func__);
330 }));
331
332 TestPromise::All(queue, promises)
333 ->Then(
334 queue, __func__, []() { EXPECT_TRUE(false); },
335 [queue](float aRejectValue) -> void {
336 EXPECT_EQ(aRejectValue, 32.0);
337 queue->BeginShutdown();
338 });
339 });
340 }
341
TEST(MozPromise,PromiseAllSettled)342 TEST(MozPromise, PromiseAllSettled)
343 {
344 AutoTaskQueue atq;
345 RefPtr<TaskQueue> queue = atq.Queue();
346 RunOnTaskQueue(queue, [queue]() -> void {
347 nsTArray<RefPtr<TestPromise>> promises;
348 promises.AppendElement(TestPromise::CreateAndResolve(22, __func__));
349 promises.AppendElement(TestPromise::CreateAndReject(32.0, __func__));
350 promises.AppendElement(TestPromise::CreateAndResolve(42, __func__));
351 promises.AppendElement(TestPromise::CreateAndReject(52.0, __func__));
352
353 TestPromise::AllSettled(queue, promises)
354 ->Then(
355 queue, __func__,
356 [queue](const TestPromise::AllSettledPromiseType::ResolveValueType&
357 aResolveValues) -> void {
358 EXPECT_EQ(aResolveValues.Length(), 4UL);
359 EXPECT_TRUE(aResolveValues[0].IsResolve());
360 EXPECT_EQ(aResolveValues[0].ResolveValue(), 22);
361 EXPECT_FALSE(aResolveValues[1].IsResolve());
362 EXPECT_EQ(aResolveValues[1].RejectValue(), 32.0);
363 EXPECT_TRUE(aResolveValues[2].IsResolve());
364 EXPECT_EQ(aResolveValues[2].ResolveValue(), 42);
365 EXPECT_FALSE(aResolveValues[3].IsResolve());
366 EXPECT_EQ(aResolveValues[3].RejectValue(), 52.0);
367 queue->BeginShutdown();
368 },
369 []() { EXPECT_TRUE(false); });
370 });
371 }
372
TEST(MozPromise,PromiseAllSettledAsync)373 TEST(MozPromise, PromiseAllSettledAsync)
374 {
375 AutoTaskQueue atq;
376 RefPtr<TaskQueue> queue = atq.Queue();
377
378 RunOnTaskQueue(queue, [queue]() -> void {
379 nsTArray<RefPtr<TestPromise>> promises;
380 promises.AppendElement(InvokeAsync(queue, __func__, []() {
381 return TestPromise::CreateAndResolve(22, __func__);
382 }));
383 promises.AppendElement(InvokeAsync(queue, __func__, []() {
384 return TestPromise::CreateAndReject(32.0, __func__);
385 }));
386 promises.AppendElement(InvokeAsync(queue, __func__, []() {
387 return TestPromise::CreateAndResolve(42, __func__);
388 }));
389 promises.AppendElement(InvokeAsync(queue, __func__, []() {
390 return TestPromise::CreateAndReject(52.0, __func__);
391 }));
392
393 TestPromise::AllSettled(queue, promises)
394 ->Then(
395 queue, __func__,
396 [queue](const TestPromise::AllSettledPromiseType::ResolveValueType&
397 aResolveValues) -> void {
398 EXPECT_EQ(aResolveValues.Length(), 4UL);
399 EXPECT_TRUE(aResolveValues[0].IsResolve());
400 EXPECT_EQ(aResolveValues[0].ResolveValue(), 22);
401 EXPECT_FALSE(aResolveValues[1].IsResolve());
402 EXPECT_EQ(aResolveValues[1].RejectValue(), 32.0);
403 EXPECT_TRUE(aResolveValues[2].IsResolve());
404 EXPECT_EQ(aResolveValues[2].ResolveValue(), 42);
405 EXPECT_FALSE(aResolveValues[3].IsResolve());
406 EXPECT_EQ(aResolveValues[3].RejectValue(), 52.0);
407 queue->BeginShutdown();
408 },
409 []() { EXPECT_TRUE(false); });
410 });
411 }
412
413 // Test we don't hit the assertions in MozPromise when exercising promise
414 // chaining upon task queue shutdown.
TEST(MozPromise,Chaining)415 TEST(MozPromise, Chaining)
416 {
417 // We declare this variable before |atq| to ensure
418 // the destructor is run after |holder.Disconnect()|.
419 MozPromiseRequestHolder<TestPromise> holder;
420
421 AutoTaskQueue atq;
422 RefPtr<TaskQueue> queue = atq.Queue();
423
424 RunOnTaskQueue(queue, [queue, &holder]() {
425 auto p = TestPromise::CreateAndResolve(42, __func__);
426 const size_t kIterations = 100;
427 for (size_t i = 0; i < kIterations; ++i) {
428 p = p->Then(
429 queue, __func__,
430 [](int aVal) {
431 EXPECT_EQ(aVal, 42);
432 return TestPromise::CreateAndResolve(aVal, __func__);
433 },
434 [](double aVal) {
435 return TestPromise::CreateAndReject(aVal, __func__);
436 });
437
438 if (i == kIterations / 2) {
439 p->Then(
440 queue, __func__,
441 [queue, &holder]() {
442 holder.Disconnect();
443 queue->BeginShutdown();
444 },
445 DO_FAIL);
446 }
447 }
448 // We will hit the assertion if we don't disconnect the leaf Request
449 // in the promise chain.
450 p->Then(
451 queue, __func__, []() {}, []() {})
452 ->Track(holder);
453 });
454 }
455
TEST(MozPromise,ResolveOrRejectValue)456 TEST(MozPromise, ResolveOrRejectValue)
457 {
458 using MyPromise = MozPromise<UniquePtr<int>, bool, false>;
459 using RRValue = MyPromise::ResolveOrRejectValue;
460
461 RRValue val;
462 EXPECT_TRUE(val.IsNothing());
463 EXPECT_FALSE(val.IsResolve());
464 EXPECT_FALSE(val.IsReject());
465
466 val.SetResolve(MakeUnique<int>(87));
467 EXPECT_FALSE(val.IsNothing());
468 EXPECT_TRUE(val.IsResolve());
469 EXPECT_FALSE(val.IsReject());
470 EXPECT_EQ(87, *val.ResolveValue());
471
472 // IsResolve() should remain true after std::move().
473 UniquePtr<int> i = std::move(val.ResolveValue());
474 EXPECT_EQ(87, *i);
475 EXPECT_TRUE(val.IsResolve());
476 EXPECT_EQ(val.ResolveValue().get(), nullptr);
477 }
478
TEST(MozPromise,MoveOnlyType)479 TEST(MozPromise, MoveOnlyType)
480 {
481 using MyPromise = MozPromise<UniquePtr<int>, bool, true>;
482 using RRValue = MyPromise::ResolveOrRejectValue;
483
484 AutoTaskQueue atq;
485 RefPtr<TaskQueue> queue = atq.Queue();
486
487 MyPromise::CreateAndResolve(MakeUnique<int>(87), __func__)
488 ->Then(
489 queue, __func__, [](UniquePtr<int> aVal) { EXPECT_EQ(87, *aVal); },
490 []() { EXPECT_TRUE(false); });
491
492 MyPromise::CreateAndResolve(MakeUnique<int>(87), __func__)
493 ->Then(queue, __func__, [queue](RRValue&& aVal) {
494 EXPECT_FALSE(aVal.IsNothing());
495 EXPECT_TRUE(aVal.IsResolve());
496 EXPECT_FALSE(aVal.IsReject());
497 EXPECT_EQ(87, *aVal.ResolveValue());
498
499 // std::move() shouldn't change the resolve/reject state of aVal.
500 RRValue val = std::move(aVal);
501 EXPECT_TRUE(aVal.IsResolve());
502 EXPECT_EQ(nullptr, aVal.ResolveValue().get());
503 EXPECT_EQ(87, *val.ResolveValue());
504
505 queue->BeginShutdown();
506 });
507 }
508
TEST(MozPromise,HeterogeneousChaining)509 TEST(MozPromise, HeterogeneousChaining)
510 {
511 using Promise1 = MozPromise<UniquePtr<char>, bool, true>;
512 using Promise2 = MozPromise<UniquePtr<int>, bool, true>;
513 using RRValue1 = Promise1::ResolveOrRejectValue;
514 using RRValue2 = Promise2::ResolveOrRejectValue;
515
516 MozPromiseRequestHolder<Promise2> holder;
517
518 AutoTaskQueue atq;
519 RefPtr<TaskQueue> queue = atq.Queue();
520
521 RunOnTaskQueue(queue, [queue, &holder]() {
522 Promise1::CreateAndResolve(MakeUnique<char>(0), __func__)
523 ->Then(queue, __func__,
524 [&holder]() {
525 holder.Disconnect();
526 return Promise2::CreateAndResolve(MakeUnique<int>(0),
527 __func__);
528 })
529 ->Then(queue, __func__,
530 []() {
531 // Shouldn't be called for we've disconnected the request.
532 EXPECT_FALSE(true);
533 })
534 ->Track(holder);
535 });
536
537 Promise1::CreateAndResolve(MakeUnique<char>(87), __func__)
538 ->Then(
539 queue, __func__,
540 [](UniquePtr<char> aVal) {
541 EXPECT_EQ(87, *aVal);
542 return Promise2::CreateAndResolve(MakeUnique<int>(94), __func__);
543 },
544 []() {
545 return Promise2::CreateAndResolve(MakeUnique<int>(95), __func__);
546 })
547 ->Then(
548 queue, __func__, [](UniquePtr<int> aVal) { EXPECT_EQ(94, *aVal); },
549 []() { EXPECT_FALSE(true); });
550
551 Promise1::CreateAndResolve(MakeUnique<char>(87), __func__)
552 ->Then(queue, __func__,
553 [](RRValue1&& aVal) {
554 EXPECT_EQ(87, *aVal.ResolveValue());
555 return Promise2::CreateAndResolve(MakeUnique<int>(94), __func__);
556 })
557 ->Then(queue, __func__, [queue](RRValue2&& aVal) {
558 EXPECT_EQ(94, *aVal.ResolveValue());
559 queue->BeginShutdown();
560 });
561 }
562
TEST(MozPromise,XPCOMEventTarget)563 TEST(MozPromise, XPCOMEventTarget)
564 {
565 TestPromise::CreateAndResolve(42, __func__)
566 ->Then(
567 GetCurrentSerialEventTarget(), __func__,
568 [](int aResolveValue) -> void { EXPECT_EQ(aResolveValue, 42); },
569 DO_FAIL);
570
571 // Spin the event loop.
572 NS_ProcessPendingEvents(nullptr);
573 }
574
TEST(MozPromise,MessageLoopEventTarget)575 TEST(MozPromise, MessageLoopEventTarget)
576 {
577 TestPromise::CreateAndResolve(42, __func__)
578 ->Then(
579 MessageLoop::current()->SerialEventTarget(), __func__,
580 [](int aResolveValue) -> void { EXPECT_EQ(aResolveValue, 42); },
581 DO_FAIL);
582
583 // Spin the event loop.
584 NS_ProcessPendingEvents(nullptr);
585 }
586
TEST(MozPromise,ChainTo)587 TEST(MozPromise, ChainTo)
588 {
589 RefPtr<TestPromise> promise1 = TestPromise::CreateAndResolve(42, __func__);
590 RefPtr<TestPromise::Private> promise2 = new TestPromise::Private(__func__);
591 promise2->Then(
592 GetCurrentSerialEventTarget(), __func__,
593 [&](int aResolveValue) -> void { EXPECT_EQ(aResolveValue, 42); },
594 DO_FAIL);
595
596 promise1->ChainTo(promise2.forget(), __func__);
597
598 // Spin the event loop.
599 NS_ProcessPendingEvents(nullptr);
600 }
601
TEST(MozPromise,SynchronousTaskDispatch1)602 TEST(MozPromise, SynchronousTaskDispatch1)
603 {
604 bool value = false;
605 RefPtr<TestPromiseExcl::Private> promise =
606 new TestPromiseExcl::Private(__func__);
607 promise->UseSynchronousTaskDispatch(__func__);
608 promise->Resolve(42, __func__);
609 EXPECT_EQ(value, false);
610 promise->Then(
611 GetCurrentSerialEventTarget(), __func__,
612 [&](int aResolveValue) -> void {
613 EXPECT_EQ(aResolveValue, 42);
614 value = true;
615 },
616 DO_FAIL);
617 EXPECT_EQ(value, true);
618 }
619
TEST(MozPromise,SynchronousTaskDispatch2)620 TEST(MozPromise, SynchronousTaskDispatch2)
621 {
622 bool value = false;
623 RefPtr<TestPromiseExcl::Private> promise =
624 new TestPromiseExcl::Private(__func__);
625 promise->UseSynchronousTaskDispatch(__func__);
626 promise->Then(
627 GetCurrentSerialEventTarget(), __func__,
628 [&](int aResolveValue) -> void {
629 EXPECT_EQ(aResolveValue, 42);
630 value = true;
631 },
632 DO_FAIL);
633 EXPECT_EQ(value, false);
634 promise->Resolve(42, __func__);
635 EXPECT_EQ(value, true);
636 }
637
TEST(MozPromise,DirectTaskDispatch)638 TEST(MozPromise, DirectTaskDispatch)
639 {
640 bool value1 = false;
641 bool value2 = false;
642
643 // For direct task dispatch to be working, we must be within a
644 // nested event loop. So the test itself must be dispatched within
645 // a task.
646 GetCurrentSerialEventTarget()->Dispatch(NS_NewRunnableFunction("test", [&]() {
647 GetCurrentSerialEventTarget()->Dispatch(
648 NS_NewRunnableFunction("test", [&]() {
649 EXPECT_EQ(value1, true);
650 value2 = true;
651 }));
652
653 RefPtr<TestPromise::Private> promise = new TestPromise::Private(__func__);
654 promise->UseDirectTaskDispatch(__func__);
655 promise->Resolve(42, __func__);
656 EXPECT_EQ(value1, false);
657 promise->Then(
658 GetCurrentSerialEventTarget(), __func__,
659 [&](int aResolveValue) -> void {
660 EXPECT_EQ(aResolveValue, 42);
661 EXPECT_EQ(value2, false);
662 value1 = true;
663 },
664 DO_FAIL);
665 EXPECT_EQ(value1, false);
666 }));
667
668 // Spin the event loop.
669 NS_ProcessPendingEvents(nullptr);
670 }
671
TEST(MozPromise,ChainedDirectTaskDispatch)672 TEST(MozPromise, ChainedDirectTaskDispatch)
673 {
674 bool value1 = false;
675 bool value2 = false;
676
677 // For direct task dispatch to be working, we must be within a
678 // nested event loop. So the test itself must be dispatched within
679 // a task.
680 GetCurrentSerialEventTarget()->Dispatch(NS_NewRunnableFunction("test", [&]() {
681 GetCurrentSerialEventTarget()->Dispatch(
682 NS_NewRunnableFunction("test", [&]() {
683 EXPECT_EQ(value1, true);
684 value2 = true;
685 }));
686
687 RefPtr<TestPromise::Private> promise1 = new TestPromise::Private(__func__);
688 promise1->UseDirectTaskDispatch(__func__);
689 promise1->Resolve(42, __func__);
690 EXPECT_EQ(value1, false);
691 promise1
692 ->Then(
693 GetCurrentSerialEventTarget(), __func__,
694 [&](int aResolveValue) -> RefPtr<TestPromise> {
695 EXPECT_EQ(aResolveValue, 42);
696 EXPECT_EQ(value2, false);
697 RefPtr<TestPromise::Private> promise2 =
698 new TestPromise::Private(__func__);
699 promise2->UseDirectTaskDispatch(__func__);
700 promise2->Resolve(43, __func__);
701 return promise2;
702 },
703 DO_FAIL)
704 ->Then(
705 GetCurrentSerialEventTarget(), __func__,
706 [&](int aResolveValue) -> void {
707 EXPECT_EQ(aResolveValue, 43);
708 EXPECT_EQ(value2, false);
709 value1 = true;
710 },
711 DO_FAIL);
712 EXPECT_EQ(value1, false);
713 }));
714
715 // Spin the event loop.
716 NS_ProcessPendingEvents(nullptr);
717 }
718
TEST(MozPromise,ChainToDirectTaskDispatch)719 TEST(MozPromise, ChainToDirectTaskDispatch)
720 {
721 bool value1 = false;
722 bool value2 = false;
723
724 // For direct task dispatch to be working, we must be within a
725 // nested event loop. So the test itself must be dispatched within
726 // a task.
727 GetCurrentSerialEventTarget()->Dispatch(NS_NewRunnableFunction("test", [&]() {
728 GetCurrentSerialEventTarget()->Dispatch(
729 NS_NewRunnableFunction("test", [&]() {
730 EXPECT_EQ(value1, true);
731 value2 = true;
732 }));
733
734 RefPtr<TestPromise::Private> promise1 = new TestPromise::Private(__func__);
735 promise1->UseDirectTaskDispatch(__func__);
736
737 RefPtr<TestPromise::Private> promise2 = new TestPromise::Private(__func__);
738 promise2->Then(
739 GetCurrentSerialEventTarget(), __func__,
740 [&](int aResolveValue) -> void {
741 EXPECT_EQ(aResolveValue, 42);
742 EXPECT_EQ(value2, false);
743 value1 = true;
744 },
745 DO_FAIL);
746
747 promise1->ChainTo(promise2.forget(), __func__);
748 EXPECT_EQ(value1, false);
749 promise1->Resolve(42, __func__);
750 }));
751
752 // Spin the event loop.
753 NS_ProcessPendingEvents(nullptr);
754 }
755
756 #undef DO_FAIL
757