Coverage Report

Created: 2018-09-25 14:53

/src/mozilla-central/xpcom/tests/gtest/TestMozPromise.cpp
Line
Count
Source (jump to first uncovered line)
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 "gtest/gtest.h"
7
8
#include "base/message_loop.h"
9
10
#include "mozilla/TaskQueue.h"
11
#include "mozilla/MozPromise.h"
12
#include "mozilla/Unused.h"
13
14
#include "nsISupportsImpl.h"
15
#include "mozilla/SharedThreadPool.h"
16
#include "VideoUtils.h"
17
18
using namespace mozilla;
19
20
typedef MozPromise<int, double, false> TestPromise;
21
typedef TestPromise::ResolveOrRejectValue RRValue;
22
23
class MOZ_STACK_CLASS AutoTaskQueue
24
{
25
public:
26
  AutoTaskQueue()
27
    : mTaskQueue(new TaskQueue(GetMediaThreadPool(MediaThreadType::PLAYBACK)))
28
0
  {}
29
30
  ~AutoTaskQueue()
31
0
  {
32
0
    mTaskQueue->AwaitShutdownAndIdle();
33
0
  }
34
35
0
  TaskQueue* Queue() { return mTaskQueue; }
36
private:
37
  RefPtr<TaskQueue> mTaskQueue;
38
};
39
40
class DelayedResolveOrReject : public Runnable
41
{
42
public:
43
  DelayedResolveOrReject(TaskQueue* aTaskQueue,
44
                         TestPromise::Private* aPromise,
45
                         const TestPromise::ResolveOrRejectValue& aValue,
46
                         int aIterations)
47
    : mozilla::Runnable("DelayedResolveOrReject")
48
    , mTaskQueue(aTaskQueue)
49
    , mPromise(aPromise)
50
    , mValue(aValue)
51
    , mIterations(aIterations)
52
0
  {}
53
54
  NS_IMETHOD Run() override
55
0
  {
56
0
    MOZ_ASSERT(mTaskQueue->IsCurrentThreadIn());
57
0
    if (!mPromise) {
58
0
      // Canceled.
59
0
      return NS_OK;
60
0
    }
61
0
62
0
    if (--mIterations == 0) {
63
0
      mPromise->ResolveOrReject(mValue, __func__);
64
0
      return NS_OK;
65
0
    }
66
0
67
0
    nsCOMPtr<nsIRunnable> r = this;
68
0
    return mTaskQueue->Dispatch(r.forget());
69
0
  }
70
71
0
  void Cancel() {
72
0
    mPromise = nullptr;
73
0
  }
74
75
protected:
76
0
  ~DelayedResolveOrReject() {}
77
78
private:
79
  RefPtr<TaskQueue> mTaskQueue;
80
  RefPtr<TestPromise::Private> mPromise;
81
  TestPromise::ResolveOrRejectValue mValue;
82
  int mIterations;
83
};
84
85
template<typename FunctionType>
86
void
87
RunOnTaskQueue(TaskQueue* aQueue, FunctionType aFun)
88
0
{
89
0
  nsCOMPtr<nsIRunnable> r = NS_NewRunnableFunction("RunOnTaskQueue", aFun);
90
0
  Unused << aQueue->Dispatch(r.forget());
91
0
}
Unexecuted instantiation: Unified_cpp_xpcom_tests_gtest1.cpp:void RunOnTaskQueue<MozPromise_BasicResolve_Test::TestBody()::$_18>(mozilla::TaskQueue*, MozPromise_BasicResolve_Test::TestBody()::$_18)
Unexecuted instantiation: Unified_cpp_xpcom_tests_gtest1.cpp:void RunOnTaskQueue<MozPromise_BasicReject_Test::TestBody()::$_19>(mozilla::TaskQueue*, MozPromise_BasicReject_Test::TestBody()::$_19)
Unexecuted instantiation: Unified_cpp_xpcom_tests_gtest1.cpp:void RunOnTaskQueue<MozPromise_BasicResolveOrRejectResolved_Test::TestBody()::$_20>(mozilla::TaskQueue*, MozPromise_BasicResolveOrRejectResolved_Test::TestBody()::$_20)
Unexecuted instantiation: Unified_cpp_xpcom_tests_gtest1.cpp:void RunOnTaskQueue<MozPromise_BasicResolveOrRejectRejected_Test::TestBody()::$_21>(mozilla::TaskQueue*, MozPromise_BasicResolveOrRejectRejected_Test::TestBody()::$_21)
Unexecuted instantiation: Unified_cpp_xpcom_tests_gtest1.cpp:void RunOnTaskQueue<MozPromise_AsyncResolve_Test::TestBody()::$_22>(mozilla::TaskQueue*, MozPromise_AsyncResolve_Test::TestBody()::$_22)
Unexecuted instantiation: Unified_cpp_xpcom_tests_gtest1.cpp:void RunOnTaskQueue<MozPromise_CompletionPromises_Test::TestBody()::$_23>(mozilla::TaskQueue*, MozPromise_CompletionPromises_Test::TestBody()::$_23)
Unexecuted instantiation: Unified_cpp_xpcom_tests_gtest1.cpp:void RunOnTaskQueue<MozPromise_PromiseAllResolve_Test::TestBody()::$_24>(mozilla::TaskQueue*, MozPromise_PromiseAllResolve_Test::TestBody()::$_24)
Unexecuted instantiation: Unified_cpp_xpcom_tests_gtest1.cpp:void RunOnTaskQueue<MozPromise_PromiseAllReject_Test::TestBody()::$_25>(mozilla::TaskQueue*, MozPromise_PromiseAllReject_Test::TestBody()::$_25)
Unexecuted instantiation: Unified_cpp_xpcom_tests_gtest1.cpp:void RunOnTaskQueue<MozPromise_Chaining_Test::TestBody()::$_26>(mozilla::TaskQueue*, MozPromise_Chaining_Test::TestBody()::$_26)
Unexecuted instantiation: Unified_cpp_xpcom_tests_gtest1.cpp:void RunOnTaskQueue<MozPromise_HeterogeneousChaining_Test::TestBody()::$_30>(mozilla::TaskQueue*, MozPromise_HeterogeneousChaining_Test::TestBody()::$_30)
92
93
// std::function can't come soon enough. :-(
94
0
#define DO_FAIL []() { EXPECT_TRUE(false); return TestPromise::CreateAndReject(0, __func__); }
Unexecuted instantiation: Unified_cpp_xpcom_tests_gtest1.cpp:MozPromise_BasicResolve_Test::TestBody()::$_18::operator()() const::{lambda()#1}::operator()() const
Unexecuted instantiation: Unified_cpp_xpcom_tests_gtest1.cpp:MozPromise_BasicReject_Test::TestBody()::$_19::operator()() const::{lambda()#1}::operator()() const
Unexecuted instantiation: Unified_cpp_xpcom_tests_gtest1.cpp:MozPromise_AsyncResolve_Test::TestBody()::$_22::operator()() const::{lambda()#1}::operator()() const
Unexecuted instantiation: Unified_cpp_xpcom_tests_gtest1.cpp:MozPromise_CompletionPromises_Test::TestBody()::$_23::operator()() const::{lambda()#1}::operator()() const
Unexecuted instantiation: Unified_cpp_xpcom_tests_gtest1.cpp:MozPromise_CompletionPromises_Test::TestBody()::$_23::operator()() const::{lambda()#2}::operator()() const
Unexecuted instantiation: Unified_cpp_xpcom_tests_gtest1.cpp:MozPromise_CompletionPromises_Test::TestBody()::$_23::operator()() const::{lambda()#3}::operator()() const
Unexecuted instantiation: Unified_cpp_xpcom_tests_gtest1.cpp:MozPromise_CompletionPromises_Test::TestBody()::$_23::operator()() const::{lambda()#4}::operator()() const
Unexecuted instantiation: Unified_cpp_xpcom_tests_gtest1.cpp:MozPromise_CompletionPromises_Test::TestBody()::$_23::operator()() const::{lambda()#5}::operator()() const
Unexecuted instantiation: Unified_cpp_xpcom_tests_gtest1.cpp:MozPromise_Chaining_Test::TestBody()::$_26::operator()() const::{lambda()#2}::operator()() const
Unexecuted instantiation: Unified_cpp_xpcom_tests_gtest1.cpp:MozPromise_XPCOMEventTarget_Test::TestBody()::$_38::operator()() const
Unexecuted instantiation: Unified_cpp_xpcom_tests_gtest1.cpp:MozPromise_MessageLoopEventTarget_Test::TestBody()::$_40::operator()() const
95
96
TEST(MozPromise, BasicResolve)
97
0
{
98
0
  AutoTaskQueue atq;
99
0
  RefPtr<TaskQueue> queue = atq.Queue();
100
0
  RunOnTaskQueue(queue, [queue] () -> void {
101
0
    TestPromise::CreateAndResolve(42, __func__)->Then(queue, __func__,
102
0
      [queue] (int aResolveValue) -> void { EXPECT_EQ(aResolveValue, 42); queue->BeginShutdown(); },
103
0
      DO_FAIL);
104
0
  });
105
0
}
106
107
TEST(MozPromise, BasicReject)
108
0
{
109
0
  AutoTaskQueue atq;
110
0
  RefPtr<TaskQueue> queue = atq.Queue();
111
0
  RunOnTaskQueue(queue, [queue] () -> void {
112
0
    TestPromise::CreateAndReject(42.0, __func__)->Then(queue, __func__,
113
0
      DO_FAIL,
114
0
      [queue] (int aRejectValue) -> void { EXPECT_EQ(aRejectValue, 42.0); queue->BeginShutdown(); });
115
0
  });
116
0
}
117
118
TEST(MozPromise, BasicResolveOrRejectResolved)
119
0
{
120
0
  AutoTaskQueue atq;
121
0
  RefPtr<TaskQueue> queue = atq.Queue();
122
0
  RunOnTaskQueue(queue, [queue] () -> void {
123
0
    TestPromise::CreateAndResolve(42, __func__)->Then(queue, __func__,
124
0
      [queue] (const TestPromise::ResolveOrRejectValue& aValue) -> void
125
0
      {
126
0
        EXPECT_TRUE(aValue.IsResolve());
127
0
        EXPECT_FALSE(aValue.IsReject());
128
0
        EXPECT_FALSE(aValue.IsNothing());
129
0
        EXPECT_EQ(aValue.ResolveValue(), 42);
130
0
        queue->BeginShutdown();
131
0
      });
132
0
  });
133
0
}
134
135
TEST(MozPromise, BasicResolveOrRejectRejected)
136
0
{
137
0
  AutoTaskQueue atq;
138
0
  RefPtr<TaskQueue> queue = atq.Queue();
139
0
  RunOnTaskQueue(queue, [queue] () -> void {
140
0
    TestPromise::CreateAndReject(42.0, __func__)->Then(queue, __func__,
141
0
      [queue] (const TestPromise::ResolveOrRejectValue& aValue) -> void
142
0
      {
143
0
        EXPECT_TRUE(aValue.IsReject());
144
0
        EXPECT_FALSE(aValue.IsResolve());
145
0
        EXPECT_FALSE(aValue.IsNothing());
146
0
        EXPECT_EQ(aValue.RejectValue(), 42.0);
147
0
        queue->BeginShutdown();
148
0
      });
149
0
  });
150
0
}
151
152
TEST(MozPromise, AsyncResolve)
153
0
{
154
0
  AutoTaskQueue atq;
155
0
  RefPtr<TaskQueue> queue = atq.Queue();
156
0
  RunOnTaskQueue(queue, [queue] () -> void {
157
0
    RefPtr<TestPromise::Private> p = new TestPromise::Private(__func__);
158
0
159
0
    // Kick off three racing tasks, and make sure we get the one that finishes earliest.
160
0
    RefPtr<DelayedResolveOrReject> a = new DelayedResolveOrReject(queue, p, RRValue::MakeResolve(32), 10);
161
0
    RefPtr<DelayedResolveOrReject> b = new DelayedResolveOrReject(queue, p, RRValue::MakeResolve(42), 5);
162
0
    RefPtr<DelayedResolveOrReject> c = new DelayedResolveOrReject(queue, p, RRValue::MakeReject(32.0), 7);
163
0
164
0
    nsCOMPtr<nsIRunnable> ref = a.get();
165
0
    Unused << queue->Dispatch(ref.forget());
166
0
    ref = b.get();
167
0
    Unused << queue->Dispatch(ref.forget());
168
0
    ref = c.get();
169
0
    Unused << queue->Dispatch(ref.forget());
170
0
171
0
    p->Then(queue, __func__, [queue, a, b, c] (int aResolveValue) -> void {
172
0
      EXPECT_EQ(aResolveValue, 42);
173
0
      a->Cancel();
174
0
      b->Cancel();
175
0
      c->Cancel();
176
0
      queue->BeginShutdown();
177
0
    }, DO_FAIL);
178
0
  });
179
0
}
180
181
TEST(MozPromise, CompletionPromises)
182
0
{
183
0
  bool invokedPass = false;
184
0
  AutoTaskQueue atq;
185
0
  RefPtr<TaskQueue> queue = atq.Queue();
186
0
  RunOnTaskQueue(queue, [queue, &invokedPass] () -> void {
187
0
    TestPromise::CreateAndResolve(40, __func__)
188
0
    ->Then(queue, __func__,
189
0
      [] (int aVal) -> RefPtr<TestPromise> { return TestPromise::CreateAndResolve(aVal + 10, __func__); },
190
0
      DO_FAIL)
191
0
    ->Then(queue, __func__,
192
0
           [&invokedPass] (int aVal) {
193
0
             invokedPass = true;
194
0
             return TestPromise::CreateAndResolve(aVal, __func__);
195
0
           }, DO_FAIL)
196
0
    ->Then(queue, __func__,
197
0
      [queue] (int aVal) -> RefPtr<TestPromise> {
198
0
        RefPtr<TestPromise::Private> p = new TestPromise::Private(__func__);
199
0
        nsCOMPtr<nsIRunnable> resolver = new DelayedResolveOrReject(queue, p, RRValue::MakeResolve(aVal - 8), 10);
200
0
        Unused << queue->Dispatch(resolver.forget());
201
0
        return RefPtr<TestPromise>(p);
202
0
      },
203
0
      DO_FAIL)
204
0
    ->Then(queue, __func__,
205
0
      [] (int aVal) -> RefPtr<TestPromise> { return TestPromise::CreateAndReject(double(aVal - 42) + 42.0, __func__); },
206
0
      DO_FAIL)
207
0
    ->Then(queue, __func__,
208
0
      DO_FAIL,
209
0
      [queue, &invokedPass] (double aVal) -> void { EXPECT_EQ(aVal, 42.0); EXPECT_TRUE(invokedPass); queue->BeginShutdown(); });
210
0
  });
211
0
}
212
213
TEST(MozPromise, PromiseAllResolve)
214
0
{
215
0
  AutoTaskQueue atq;
216
0
  RefPtr<TaskQueue> queue = atq.Queue();
217
0
  RunOnTaskQueue(queue, [queue] () -> void {
218
0
219
0
    nsTArray<RefPtr<TestPromise>> promises;
220
0
    promises.AppendElement(TestPromise::CreateAndResolve(22, __func__));
221
0
    promises.AppendElement(TestPromise::CreateAndResolve(32, __func__));
222
0
    promises.AppendElement(TestPromise::CreateAndResolve(42, __func__));
223
0
224
0
    TestPromise::All(queue, promises)->Then(queue, __func__,
225
0
      [queue] (const nsTArray<int>& aResolveValues) -> void {
226
0
        EXPECT_EQ(aResolveValues.Length(), 3UL);
227
0
        EXPECT_EQ(aResolveValues[0], 22);
228
0
        EXPECT_EQ(aResolveValues[1], 32);
229
0
        EXPECT_EQ(aResolveValues[2], 42);
230
0
        queue->BeginShutdown();
231
0
      },
232
0
      []() { EXPECT_TRUE(false); }
233
0
    );
234
0
  });
235
0
}
236
237
TEST(MozPromise, PromiseAllReject)
238
0
{
239
0
  AutoTaskQueue atq;
240
0
  RefPtr<TaskQueue> queue = atq.Queue();
241
0
  RunOnTaskQueue(queue, [queue] () -> void {
242
0
243
0
    nsTArray<RefPtr<TestPromise>> promises;
244
0
    promises.AppendElement(TestPromise::CreateAndResolve(22, __func__));
245
0
    promises.AppendElement(TestPromise::CreateAndReject(32.0, __func__));
246
0
    promises.AppendElement(TestPromise::CreateAndResolve(42, __func__));
247
0
   // Ensure that more than one rejection doesn't cause a crash (bug #1207312)
248
0
    promises.AppendElement(TestPromise::CreateAndReject(52.0, __func__));
249
0
250
0
    TestPromise::All(queue, promises)->Then(queue, __func__,
251
0
      []() { EXPECT_TRUE(false); },
252
0
      [queue] (float aRejectValue) -> void {
253
0
        EXPECT_EQ(aRejectValue, 32.0);
254
0
        queue->BeginShutdown();
255
0
      }
256
0
    );
257
0
  });
258
0
}
259
260
// Test we don't hit the assertions in MozPromise when exercising promise
261
// chaining upon task queue shutdown.
262
TEST(MozPromise, Chaining)
263
0
{
264
0
  // We declare this variable before |atq| to ensure
265
0
  // the destructor is run after |holder.Disconnect()|.
266
0
  MozPromiseRequestHolder<TestPromise> holder;
267
0
268
0
  AutoTaskQueue atq;
269
0
  RefPtr<TaskQueue> queue = atq.Queue();
270
0
271
0
  RunOnTaskQueue(queue, [queue, &holder] () {
272
0
    auto p = TestPromise::CreateAndResolve(42, __func__);
273
0
    const size_t kIterations = 100;
274
0
    for (size_t i = 0; i < kIterations; ++i) {
275
0
      p = p->Then(queue, __func__,
276
0
        [] (int aVal) {
277
0
          EXPECT_EQ(aVal, 42);
278
0
          return TestPromise::CreateAndResolve(aVal, __func__);
279
0
        },
280
0
        [] (double aVal) {
281
0
          return TestPromise::CreateAndReject(aVal, __func__);
282
0
        }
283
0
      );
284
0
285
0
      if (i == kIterations / 2) {
286
0
        p->Then(queue, __func__,
287
0
          [queue, &holder] () {
288
0
            holder.Disconnect();
289
0
            queue->BeginShutdown();
290
0
          },
291
0
          DO_FAIL);
292
0
      }
293
0
    }
294
0
    // We will hit the assertion if we don't disconnect the leaf Request
295
0
    // in the promise chain.
296
0
    p->Then(queue, __func__, [] () {}, [] () {})->Track(holder);
297
0
  });
298
0
}
299
300
TEST(MozPromise, ResolveOrRejectValue)
301
0
{
302
0
  using MyPromise = MozPromise<UniquePtr<int>, bool, false>;
303
0
  using RRValue = MyPromise::ResolveOrRejectValue;
304
0
305
0
  RRValue val;
306
0
  EXPECT_TRUE(val.IsNothing());
307
0
  EXPECT_FALSE(val.IsResolve());
308
0
  EXPECT_FALSE(val.IsReject());
309
0
310
0
  val.SetResolve(MakeUnique<int>(87));
311
0
  EXPECT_FALSE(val.IsNothing());
312
0
  EXPECT_TRUE(val.IsResolve());
313
0
  EXPECT_FALSE(val.IsReject());
314
0
  EXPECT_EQ(87, *val.ResolveValue());
315
0
316
0
  // IsResolve() should remain true after std::move().
317
0
  UniquePtr<int> i = std::move(val.ResolveValue());
318
0
  EXPECT_EQ(87, *i);
319
0
  EXPECT_TRUE(val.IsResolve());
320
0
  EXPECT_EQ(val.ResolveValue().get(), nullptr);
321
0
}
322
323
TEST(MozPromise, MoveOnlyType)
324
0
{
325
0
  using MyPromise = MozPromise<UniquePtr<int>, bool, true>;
326
0
  using RRValue = MyPromise::ResolveOrRejectValue;
327
0
328
0
  AutoTaskQueue atq;
329
0
  RefPtr<TaskQueue> queue = atq.Queue();
330
0
331
0
  MyPromise::CreateAndResolve(MakeUnique<int>(87), __func__)
332
0
  ->Then(queue, __func__,
333
0
    [](UniquePtr<int> aVal) {
334
0
      EXPECT_EQ(87, *aVal);
335
0
    },
336
0
    []() { EXPECT_TRUE(false); });
337
0
338
0
  MyPromise::CreateAndResolve(MakeUnique<int>(87), __func__)
339
0
  ->Then(queue, __func__,
340
0
    [queue](RRValue&& aVal) {
341
0
      EXPECT_FALSE(aVal.IsNothing());
342
0
      EXPECT_TRUE(aVal.IsResolve());
343
0
      EXPECT_FALSE(aVal.IsReject());
344
0
      EXPECT_EQ(87, *aVal.ResolveValue());
345
0
346
0
      // std::move() shouldn't change the resolve/reject state of aVal.
347
0
      RRValue val = std::move(aVal);
348
0
      EXPECT_TRUE(aVal.IsResolve());
349
0
      EXPECT_EQ(nullptr, aVal.ResolveValue().get());
350
0
      EXPECT_EQ(87, *val.ResolveValue());
351
0
352
0
      queue->BeginShutdown();
353
0
    });
354
0
}
355
356
TEST(MozPromise, HeterogeneousChaining)
357
0
{
358
0
  using Promise1 = MozPromise<UniquePtr<char>, bool, true>;
359
0
  using Promise2 = MozPromise<UniquePtr<int>, bool, true>;
360
0
  using RRValue1 = Promise1::ResolveOrRejectValue;
361
0
  using RRValue2 = Promise2::ResolveOrRejectValue;
362
0
363
0
  MozPromiseRequestHolder<Promise2> holder;
364
0
365
0
  AutoTaskQueue atq;
366
0
  RefPtr<TaskQueue> queue = atq.Queue();
367
0
368
0
  RunOnTaskQueue(queue, [queue, &holder]() {
369
0
    Promise1::CreateAndResolve(MakeUnique<char>(0), __func__)
370
0
      ->Then(queue,
371
0
             __func__,
372
0
             [&holder]() {
373
0
               holder.Disconnect();
374
0
               return Promise2::CreateAndResolve(MakeUnique<int>(0), __func__);
375
0
             })
376
0
      ->Then(queue,
377
0
             __func__,
378
0
             []() {
379
0
               // Shouldn't be called for we've disconnected the request.
380
0
               EXPECT_FALSE(true);
381
0
             })
382
0
      ->Track(holder);
383
0
  });
384
0
385
0
  Promise1::CreateAndResolve(MakeUnique<char>(87), __func__)
386
0
    ->Then(queue,
387
0
           __func__,
388
0
           [](UniquePtr<char> aVal) {
389
0
             EXPECT_EQ(87, *aVal);
390
0
             return Promise2::CreateAndResolve(MakeUnique<int>(94), __func__);
391
0
           },
392
0
           []() {
393
0
             return Promise2::CreateAndResolve(MakeUnique<int>(95), __func__);
394
0
           })
395
0
    ->Then(queue,
396
0
           __func__,
397
0
           [](UniquePtr<int> aVal) { EXPECT_EQ(94, *aVal); },
398
0
           []() { EXPECT_FALSE(true); });
399
0
400
0
  Promise1::CreateAndResolve(MakeUnique<char>(87), __func__)
401
0
    ->Then(queue,
402
0
           __func__,
403
0
           [](RRValue1&& aVal) {
404
0
             EXPECT_EQ(87, *aVal.ResolveValue());
405
0
             return Promise2::CreateAndResolve(MakeUnique<int>(94), __func__);
406
0
           })
407
0
    ->Then(queue, __func__, [queue](RRValue2&& aVal) {
408
0
      EXPECT_EQ(94, *aVal.ResolveValue());
409
0
      queue->BeginShutdown();
410
0
    });
411
0
}
412
413
TEST(MozPromise, XPCOMEventTarget)
414
0
{
415
0
  TestPromise::CreateAndResolve(42, __func__)->Then(GetCurrentThreadSerialEventTarget(), __func__,
416
0
    [] (int aResolveValue) -> void { EXPECT_EQ(aResolveValue, 42); },
417
0
    DO_FAIL);
418
0
419
0
  // Spin the event loop.
420
0
  NS_ProcessPendingEvents(nullptr);
421
0
}
422
423
TEST(MozPromise, MessageLoopEventTarget)
424
0
{
425
0
  TestPromise::CreateAndResolve(42, __func__)->Then(MessageLoop::current()->SerialEventTarget(), __func__,
426
0
    [] (int aResolveValue) -> void { EXPECT_EQ(aResolveValue, 42); },
427
0
    DO_FAIL);
428
0
429
0
  // Spin the event loop.
430
0
  NS_ProcessPendingEvents(nullptr);
431
0
}
432
433
#undef DO_FAIL