• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2018 The Chromium Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include "base/threading/sequence_bound.h"
6 
7 #include <functional>
8 #include <memory>
9 #include <utility>
10 
11 #include "base/memory/raw_ptr.h"
12 #include "base/memory/raw_ref.h"
13 #include "base/run_loop.h"
14 #include "base/sequence_checker.h"
15 #include "base/strings/stringprintf.h"
16 #include "base/synchronization/lock.h"
17 #include "base/task/sequenced_task_runner.h"
18 #include "base/task/thread_pool.h"
19 #include "base/test/bind.h"
20 #include "base/test/task_environment.h"
21 #include "build/build_config.h"
22 #include "testing/gmock/include/gmock/gmock.h"
23 #include "testing/gtest/include/gtest/gtest.h"
24 
25 namespace base {
26 
27 namespace {
28 
29 class EventLogger {
30  public:
31   EventLogger() = default;
32 
AddEvent(StringPiece event)33   void AddEvent(StringPiece event) {
34     AutoLock guard(lock_);
35     events_.push_back(std::string(event));
36   }
TakeEvents()37   std::vector<std::string> TakeEvents() {
38     AutoLock guard(lock_);
39     return std::exchange(events_, {});
40   }
41 
42  private:
43   Lock lock_;
44   std::vector<std::string> events_ GUARDED_BY(lock_);
45 };
46 
47 // Helpers for writing type tests against both `SequenceBound<T>` and
48 // `SequenceBound<std::unique_ptr<T>`. The tricky part here is that the
49 // constructor and emplace both need to accept variadic args; however,
50 // construction of the actual `T` depends on the storage strategy.  The
51 // `Wrapper` template provides this layer of indirection to construct the
52 // managed `T` while still passing through all the other remaining
53 // `SequenceBound` APIs.
54 struct DirectVariation {
55   static constexpr bool kManagingTaskRunnerConstructsT = true;
56 
57   template <typename T>
58   class Wrapper : public SequenceBound<T> {
59    public:
60     template <typename... Args>
Wrapper(scoped_refptr<SequencedTaskRunner> task_runner,Args &&...args)61     explicit Wrapper(scoped_refptr<SequencedTaskRunner> task_runner,
62                      Args&&... args)
63         : SequenceBound<T>(std::move(task_runner),
64                            std::forward<Args>(args)...) {}
65 
66     template <typename... Args>
WrappedEmplace(scoped_refptr<SequencedTaskRunner> task_runner,Args &&...args)67     void WrappedEmplace(scoped_refptr<SequencedTaskRunner> task_runner,
68                         Args&&... args) {
69       this->emplace(std::move(task_runner), std::forward<Args>(args)...);
70     }
71 
72     using SequenceBound<T>::SequenceBound;
73     using SequenceBound<T>::operator=;
74 
75    private:
76     using SequenceBound<T>::emplace;
77   };
78 };
79 
80 struct UniquePtrVariation {
81   static constexpr bool kManagingTaskRunnerConstructsT = false;
82 
83   template <typename T>
84   struct Wrapper : public SequenceBound<std::unique_ptr<T>> {
85    public:
86     template <typename... Args>
Wrapperbase::__anond9cde8c20111::UniquePtrVariation::Wrapper87     explicit Wrapper(scoped_refptr<SequencedTaskRunner> task_runner,
88                      Args&&... args)
89         : SequenceBound<std::unique_ptr<T>>(
90               std::move(task_runner),
91               std::make_unique<T>(std::forward<Args>(args)...)) {}
92 
93     template <typename... Args>
WrappedEmplacebase::__anond9cde8c20111::UniquePtrVariation::Wrapper94     void WrappedEmplace(scoped_refptr<SequencedTaskRunner> task_runner,
95                         Args&&... args) {
96       this->emplace(std::move(task_runner),
97                     std::make_unique<T>(std::forward<Args>(args)...));
98     }
99 
100     using SequenceBound<std::unique_ptr<T>>::SequenceBound;
101     using SequenceBound<std::unique_ptr<T>>::operator=;
102 
103    private:
104     using SequenceBound<std::unique_ptr<T>>::emplace;
105   };
106 };
107 
108 // Helper macros since using the name directly is otherwise quite unwieldy.
109 #define SEQUENCE_BOUND_T typename TypeParam::template Wrapper
110 // Try to catch tests that inadvertently use SequenceBound<T> directly instead
111 // of SEQUENCE_BOUND_T, as that bypasses the point of having a typed test.
112 #define SequenceBound PleaseUseSequenceBoundT
113 
114 template <typename Variation>
115 class SequenceBoundTest : public ::testing::Test {
116  public:
TearDown()117   void TearDown() override {
118     // Make sure that any objects owned by `SequenceBound` have been destroyed
119     // to avoid tripping leak detection.
120     task_environment_.RunUntilIdle();
121   }
122 
123   // Helper for tests that want to synchronize on a `SequenceBound` which has
124   // already been `Reset()`: a null `SequenceBound` has no `SequencedTaskRunner`
125   // associated with it, so the usual `FlushPostedTasksForTesting()` helper does
126   // not work.
FlushPostedTasks()127   void FlushPostedTasks() {
128     RunLoop run_loop;
129     background_task_runner_->PostTask(FROM_HERE, run_loop.QuitClosure());
130     run_loop.Run();
131   }
132 
133   test::TaskEnvironment task_environment_;
134 
135   // Task runner to use for SequenceBound's managed `T`.
136   scoped_refptr<SequencedTaskRunner> background_task_runner_ =
137       ThreadPool::CreateSequencedTaskRunner({});
138 
139   // Defined as part of the test fixture so that tests using `EventLogger` do
140   // not need to explicitly synchronize on `Reset() to avoid use-after-frees;
141   // instead, tests should rely on `TearDown()` to drain and run any
142   // already-posted cleanup tasks.
143   EventLogger logger_;
144 };
145 
146 using Variations = ::testing::Types<DirectVariation, UniquePtrVariation>;
147 TYPED_TEST_SUITE(SequenceBoundTest, Variations);
148 
149 class Base {
150  public:
Base(EventLogger & logger)151   explicit Base(EventLogger& logger) : logger_(logger) {
152     logger_->AddEvent("constructed Base");
153   }
~Base()154   virtual ~Base() { logger_->AddEvent("destroyed Base"); }
155 
156  protected:
GetLogger()157   EventLogger& GetLogger() { return *logger_; }
158 
159  private:
160   const raw_ref<EventLogger> logger_;
161 };
162 
163 class Derived : public Base {
164  public:
Derived(EventLogger & logger)165   explicit Derived(EventLogger& logger) : Base(logger) {
166     GetLogger().AddEvent("constructed Derived");
167   }
168 
~Derived()169   ~Derived() override { GetLogger().AddEvent("destroyed Derived"); }
170 
SetValue(int value)171   void SetValue(int value) {
172     GetLogger().AddEvent(StringPrintf("set Derived to %d", value));
173   }
174 };
175 
176 class Leftmost {
177  public:
Leftmost(EventLogger & logger)178   explicit Leftmost(EventLogger& logger) : logger_(logger) {
179     logger_->AddEvent("constructed Leftmost");
180   }
~Leftmost()181   virtual ~Leftmost() { logger_->AddEvent("destroyed Leftmost"); }
182 
SetValue(int value)183   void SetValue(int value) {
184     logger_->AddEvent(StringPrintf("set Leftmost to %d", value));
185   }
186 
187  private:
188   const raw_ref<EventLogger> logger_;
189 };
190 
191 class Rightmost : public Base {
192  public:
Rightmost(EventLogger & logger)193   explicit Rightmost(EventLogger& logger) : Base(logger) {
194     GetLogger().AddEvent("constructed Rightmost");
195   }
196 
~Rightmost()197   ~Rightmost() override { GetLogger().AddEvent("destroyed Rightmost"); }
198 
SetValue(int value)199   void SetValue(int value) {
200     GetLogger().AddEvent(StringPrintf("set Rightmost to %d", value));
201   }
202 };
203 
204 class MultiplyDerived : public Leftmost, public Rightmost {
205  public:
MultiplyDerived(EventLogger & logger)206   explicit MultiplyDerived(EventLogger& logger)
207       : Leftmost(logger), Rightmost(logger) {
208     GetLogger().AddEvent("constructed MultiplyDerived");
209   }
210 
~MultiplyDerived()211   ~MultiplyDerived() override {
212     GetLogger().AddEvent("destroyed MultiplyDerived");
213   }
214 };
215 
216 class BoxedValue {
217  public:
BoxedValue(int initial_value,EventLogger * logger=nullptr)218   explicit BoxedValue(int initial_value, EventLogger* logger = nullptr)
219       : logger_(logger), value_(initial_value) {
220     sequence_checker_.DetachFromSequence();
221     AddEventIfNeeded(StringPrintf("constructed BoxedValue = %d", value_));
222   }
223 
224   BoxedValue(const BoxedValue&) = delete;
225   BoxedValue& operator=(const BoxedValue&) = delete;
226 
~BoxedValue()227   ~BoxedValue() {
228     EXPECT_TRUE(sequence_checker_.CalledOnValidSequence());
229     AddEventIfNeeded(StringPrintf("destroyed BoxedValue = %d", value_));
230     if (destruction_callback_)
231       std::move(destruction_callback_).Run();
232   }
233 
set_destruction_callback(OnceClosure callback)234   void set_destruction_callback(OnceClosure callback) {
235     EXPECT_TRUE(sequence_checker_.CalledOnValidSequence());
236     destruction_callback_ = std::move(callback);
237   }
238 
value() const239   int value() const {
240     EXPECT_TRUE(sequence_checker_.CalledOnValidSequence());
241     AddEventIfNeeded(StringPrintf("accessed BoxedValue = %d", value_));
242     return value_;
243   }
set_value(int value)244   void set_value(int value) {
245     EXPECT_TRUE(sequence_checker_.CalledOnValidSequence());
246     AddEventIfNeeded(
247         StringPrintf("updated BoxedValue from %d to %d", value_, value));
248     value_ = value;
249   }
250 
251  private:
AddEventIfNeeded(StringPiece event) const252   void AddEventIfNeeded(StringPiece event) const {
253     if (logger_) {
254       logger_->AddEvent(event);
255     }
256   }
257 
258   SequenceChecker sequence_checker_;
259 
260   mutable raw_ptr<EventLogger> logger_ = nullptr;
261 
262   int value_ = 0;
263   OnceClosure destruction_callback_;
264 };
265 
266 // Smoke test that all interactions with the wrapped object are posted to the
267 // correct task runner.
268 class SequenceValidator {
269  public:
SequenceValidator(scoped_refptr<SequencedTaskRunner> task_runner,bool constructs_on_managing_task_runner)270   explicit SequenceValidator(scoped_refptr<SequencedTaskRunner> task_runner,
271                              bool constructs_on_managing_task_runner)
272       : task_runner_(std::move(task_runner)) {
273     if (constructs_on_managing_task_runner) {
274       EXPECT_TRUE(task_runner_->RunsTasksInCurrentSequence());
275     }
276   }
277 
~SequenceValidator()278   ~SequenceValidator() {
279     EXPECT_TRUE(task_runner_->RunsTasksInCurrentSequence());
280   }
281 
ReturnsVoid() const282   void ReturnsVoid() const {
283     EXPECT_TRUE(task_runner_->RunsTasksInCurrentSequence());
284   }
285 
ReturnsVoidMutable()286   void ReturnsVoidMutable() {
287     EXPECT_TRUE(task_runner_->RunsTasksInCurrentSequence());
288   }
289 
ReturnsInt() const290   int ReturnsInt() const {
291     EXPECT_TRUE(task_runner_->RunsTasksInCurrentSequence());
292     return 0;
293   }
294 
ReturnsIntMutable()295   int ReturnsIntMutable() {
296     EXPECT_TRUE(task_runner_->RunsTasksInCurrentSequence());
297     return 0;
298   }
299 
300  private:
301   scoped_refptr<SequencedTaskRunner> task_runner_;
302 };
303 
TYPED_TEST(SequenceBoundTest,SequenceValidation)304 TYPED_TEST(SequenceBoundTest, SequenceValidation) {
305   SEQUENCE_BOUND_T<SequenceValidator> validator(
306       this->background_task_runner_, this->background_task_runner_,
307       TypeParam::kManagingTaskRunnerConstructsT);
308   validator.AsyncCall(&SequenceValidator::ReturnsVoid);
309   validator.AsyncCall(&SequenceValidator::ReturnsVoidMutable);
310   validator.AsyncCall(&SequenceValidator::ReturnsInt).Then(BindOnce([](int) {
311   }));
312   validator.AsyncCall(&SequenceValidator::ReturnsIntMutable)
313       .Then(BindOnce([](int) {}));
314   validator.AsyncCall(IgnoreResult(&SequenceValidator::ReturnsInt));
315   validator.AsyncCall(IgnoreResult(&SequenceValidator::ReturnsIntMutable));
316   validator.WrappedEmplace(this->background_task_runner_,
317                            this->background_task_runner_,
318                            TypeParam::kManagingTaskRunnerConstructsT);
319   validator.PostTaskWithThisObject(BindLambdaForTesting(
320       [](const SequenceValidator& v) { v.ReturnsVoid(); }));
321   validator.PostTaskWithThisObject(BindLambdaForTesting(
322       [](SequenceValidator* v) { v->ReturnsVoidMutable(); }));
323   validator.Reset();
324   this->FlushPostedTasks();
325 }
326 
TYPED_TEST(SequenceBoundTest,Basic)327 TYPED_TEST(SequenceBoundTest, Basic) {
328   SEQUENCE_BOUND_T<BoxedValue> value(this->background_task_runner_, 0,
329                                      &this->logger_);
330   // Construction of `BoxedValue` may be posted to `background_task_runner_`,
331   // but the `SequenceBound` itself should immediately be treated as valid /
332   // non-null.
333   EXPECT_FALSE(value.is_null());
334   EXPECT_TRUE(value);
335   value.FlushPostedTasksForTesting();
336   EXPECT_THAT(this->logger_.TakeEvents(),
337               ::testing::ElementsAre("constructed BoxedValue = 0"));
338 
339   value.AsyncCall(&BoxedValue::set_value).WithArgs(66);
340   value.FlushPostedTasksForTesting();
341   EXPECT_THAT(this->logger_.TakeEvents(),
342               ::testing::ElementsAre("updated BoxedValue from 0 to 66"));
343 
344   // Destruction of `BoxedValue` may be posted to `background_task_runner_`, but
345   // the `SequenceBound` itself should immediately be treated as valid /
346   // non-null.
347   value.Reset();
348   EXPECT_TRUE(value.is_null());
349   EXPECT_FALSE(value);
350   this->FlushPostedTasks();
351   EXPECT_THAT(this->logger_.TakeEvents(),
352               ::testing::ElementsAre("destroyed BoxedValue = 66"));
353 }
354 
TYPED_TEST(SequenceBoundTest,ConstructAndImmediateAsyncCall)355 TYPED_TEST(SequenceBoundTest, ConstructAndImmediateAsyncCall) {
356   // Calling `AsyncCall` immediately after construction should always work.
357   SEQUENCE_BOUND_T<BoxedValue> value(this->background_task_runner_, 0,
358                                      &this->logger_);
359   value.AsyncCall(&BoxedValue::set_value).WithArgs(8);
360   value.FlushPostedTasksForTesting();
361   EXPECT_THAT(this->logger_.TakeEvents(),
362               ::testing::ElementsAre("constructed BoxedValue = 0",
363                                      "updated BoxedValue from 0 to 8"));
364 }
365 
TYPED_TEST(SequenceBoundTest,MoveConstruction)366 TYPED_TEST(SequenceBoundTest, MoveConstruction) {
367   // std::ref() is required here: internally, the async work is bound into the
368   // standard base callback infrastructure, which requires the explicit use of
369   // `std::cref()` and `std::ref()` when passing by reference.
370   SEQUENCE_BOUND_T<Derived> derived_old(this->background_task_runner_,
371                                         std::ref(this->logger_));
372   SEQUENCE_BOUND_T<Derived> derived_new = std::move(derived_old);
373   // NOLINTNEXTLINE(bugprone-use-after-move)
374   EXPECT_TRUE(derived_old.is_null());
375   EXPECT_FALSE(derived_new.is_null());
376   derived_new.Reset();
377   this->FlushPostedTasks();
378   EXPECT_THAT(this->logger_.TakeEvents(),
379               ::testing::ElementsAre("constructed Base", "constructed Derived",
380                                      "destroyed Derived", "destroyed Base"));
381 }
382 
TYPED_TEST(SequenceBoundTest,MoveConstructionUpcastsToBase)383 TYPED_TEST(SequenceBoundTest, MoveConstructionUpcastsToBase) {
384   SEQUENCE_BOUND_T<Derived> derived(this->background_task_runner_,
385                                     std::ref(this->logger_));
386   SEQUENCE_BOUND_T<Base> base = std::move(derived);
387   // NOLINTNEXTLINE(bugprone-use-after-move)
388   EXPECT_TRUE(derived.is_null());
389   EXPECT_FALSE(base.is_null());
390 
391   // The original `Derived` object is now owned by `SequencedBound<Base>`; make
392   // sure `~Derived()` still runs when it is reset.
393   base.Reset();
394   this->FlushPostedTasks();
395   EXPECT_THAT(this->logger_.TakeEvents(),
396               ::testing::ElementsAre("constructed Base", "constructed Derived",
397                                      "destroyed Derived", "destroyed Base"));
398 }
399 
400 // Classes with multiple-derived bases may need pointer adjustments when
401 // upcasting. These tests rely on sanitizers to catch potential mistakes.
TYPED_TEST(SequenceBoundTest,MoveConstructionUpcastsToLeftmost)402 TYPED_TEST(SequenceBoundTest, MoveConstructionUpcastsToLeftmost) {
403   SEQUENCE_BOUND_T<MultiplyDerived> multiply_derived(
404       this->background_task_runner_, std::ref(this->logger_));
405   SEQUENCE_BOUND_T<Leftmost> leftmost_base = std::move(multiply_derived);
406   // NOLINTNEXTLINE(bugprone-use-after-move)
407   EXPECT_TRUE(multiply_derived.is_null());
408   EXPECT_FALSE(leftmost_base.is_null());
409 
410   // The original `MultiplyDerived` object is now owned by
411   // `SequencedBound<Leftmost>`; make sure all the expected destructors
412   // still run when it is reset.
413   leftmost_base.Reset();
414   this->FlushPostedTasks();
415   EXPECT_THAT(
416       this->logger_.TakeEvents(),
417       ::testing::ElementsAre(
418           "constructed Leftmost", "constructed Base", "constructed Rightmost",
419           "constructed MultiplyDerived", "destroyed MultiplyDerived",
420           "destroyed Rightmost", "destroyed Base", "destroyed Leftmost"));
421 }
422 
TYPED_TEST(SequenceBoundTest,MoveConstructionUpcastsToRightmost)423 TYPED_TEST(SequenceBoundTest, MoveConstructionUpcastsToRightmost) {
424   SEQUENCE_BOUND_T<MultiplyDerived> multiply_derived(
425       this->background_task_runner_, std::ref(this->logger_));
426   SEQUENCE_BOUND_T<Rightmost> rightmost_base = std::move(multiply_derived);
427   // NOLINTNEXTLINE(bugprone-use-after-move)
428   EXPECT_TRUE(multiply_derived.is_null());
429   EXPECT_FALSE(rightmost_base.is_null());
430 
431   // The original `MultiplyDerived` object is now owned by
432   // `SequencedBound<Rightmost>`; make sure all the expected destructors
433   // still run when it is reset.
434   rightmost_base.Reset();
435   this->FlushPostedTasks();
436   EXPECT_THAT(
437       this->logger_.TakeEvents(),
438       ::testing::ElementsAre(
439           "constructed Leftmost", "constructed Base", "constructed Rightmost",
440           "constructed MultiplyDerived", "destroyed MultiplyDerived",
441           "destroyed Rightmost", "destroyed Base", "destroyed Leftmost"));
442 }
443 
TYPED_TEST(SequenceBoundTest,MoveAssignment)444 TYPED_TEST(SequenceBoundTest, MoveAssignment) {
445   SEQUENCE_BOUND_T<Derived> derived_old(this->background_task_runner_,
446                                         std::ref(this->logger_));
447   SEQUENCE_BOUND_T<Derived> derived_new;
448 
449   derived_new = std::move(derived_old);
450   // NOLINTNEXTLINE(bugprone-use-after-move)
451   EXPECT_TRUE(derived_old.is_null());
452   EXPECT_FALSE(derived_new.is_null());
453 
454   // Note that this explicitly avoids using `Reset()` as a basic test that
455   // assignment resets any previously-owned object.
456   derived_new = SEQUENCE_BOUND_T<Derived>();
457   this->FlushPostedTasks();
458   EXPECT_THAT(this->logger_.TakeEvents(),
459               ::testing::ElementsAre("constructed Base", "constructed Derived",
460                                      "destroyed Derived", "destroyed Base"));
461 }
462 
TYPED_TEST(SequenceBoundTest,MoveAssignmentUpcastsToBase)463 TYPED_TEST(SequenceBoundTest, MoveAssignmentUpcastsToBase) {
464   SEQUENCE_BOUND_T<Derived> derived(this->background_task_runner_,
465                                     std::ref(this->logger_));
466   SEQUENCE_BOUND_T<Base> base;
467 
468   base = std::move(derived);
469   // NOLINTNEXTLINE(bugprone-use-after-move)
470   EXPECT_TRUE(derived.is_null());
471   EXPECT_FALSE(base.is_null());
472 
473   // The original `Derived` object is now owned by `SequencedBound<Base>`; make
474   // sure `~Derived()` still runs when it is reset.
475   base.Reset();
476   this->FlushPostedTasks();
477   EXPECT_THAT(this->logger_.TakeEvents(),
478               ::testing::ElementsAre("constructed Base", "constructed Derived",
479                                      "destroyed Derived", "destroyed Base"));
480 }
481 
TYPED_TEST(SequenceBoundTest,MoveAssignmentUpcastsToLeftmost)482 TYPED_TEST(SequenceBoundTest, MoveAssignmentUpcastsToLeftmost) {
483   SEQUENCE_BOUND_T<MultiplyDerived> multiply_derived(
484       this->background_task_runner_, std::ref(this->logger_));
485   SEQUENCE_BOUND_T<Leftmost> leftmost_base;
486 
487   leftmost_base = std::move(multiply_derived);
488   // NOLINTNEXTLINE(bugprone-use-after-move)
489   EXPECT_TRUE(multiply_derived.is_null());
490   EXPECT_FALSE(leftmost_base.is_null());
491 
492   // The original `MultiplyDerived` object is now owned by
493   // `SequencedBound<Leftmost>`; make sure all the expected destructors
494   // still run when it is reset.
495   leftmost_base.Reset();
496   this->FlushPostedTasks();
497   EXPECT_THAT(
498       this->logger_.TakeEvents(),
499       ::testing::ElementsAre(
500           "constructed Leftmost", "constructed Base", "constructed Rightmost",
501           "constructed MultiplyDerived", "destroyed MultiplyDerived",
502           "destroyed Rightmost", "destroyed Base", "destroyed Leftmost"));
503 }
504 
TYPED_TEST(SequenceBoundTest,MoveAssignmentUpcastsToRightmost)505 TYPED_TEST(SequenceBoundTest, MoveAssignmentUpcastsToRightmost) {
506   SEQUENCE_BOUND_T<MultiplyDerived> multiply_derived(
507       this->background_task_runner_, std::ref(this->logger_));
508   SEQUENCE_BOUND_T<Rightmost> rightmost_base;
509 
510   rightmost_base = std::move(multiply_derived);
511   // NOLINTNEXTLINE(bugprone-use-after-move)
512   EXPECT_TRUE(multiply_derived.is_null());
513   EXPECT_FALSE(rightmost_base.is_null());
514 
515   // The original `MultiplyDerived` object is now owned by
516   // `SequencedBound<Rightmost>`; make sure all the expected destructors
517   // still run when it is reset.
518   rightmost_base.Reset();
519   this->FlushPostedTasks();
520   EXPECT_THAT(
521       this->logger_.TakeEvents(),
522       ::testing::ElementsAre(
523           "constructed Leftmost", "constructed Base", "constructed Rightmost",
524           "constructed MultiplyDerived", "destroyed MultiplyDerived",
525           "destroyed Rightmost", "destroyed Base", "destroyed Leftmost"));
526 }
527 
TYPED_TEST(SequenceBoundTest,AsyncCallLeftmost)528 TYPED_TEST(SequenceBoundTest, AsyncCallLeftmost) {
529   SEQUENCE_BOUND_T<MultiplyDerived> multiply_derived(
530       this->background_task_runner_, std::ref(this->logger_));
531   multiply_derived.AsyncCall(&Leftmost::SetValue).WithArgs(3);
532   multiply_derived.FlushPostedTasksForTesting();
533   EXPECT_THAT(this->logger_.TakeEvents(),
534               ::testing::ElementsAre("constructed Leftmost", "constructed Base",
535                                      "constructed Rightmost",
536                                      "constructed MultiplyDerived",
537                                      "set Leftmost to 3"));
538 }
539 
TYPED_TEST(SequenceBoundTest,AsyncCallRightmost)540 TYPED_TEST(SequenceBoundTest, AsyncCallRightmost) {
541   SEQUENCE_BOUND_T<MultiplyDerived> multiply_derived(
542       this->background_task_runner_, std::ref(this->logger_));
543   multiply_derived.AsyncCall(&Rightmost::SetValue).WithArgs(3);
544   multiply_derived.FlushPostedTasksForTesting();
545   EXPECT_THAT(this->logger_.TakeEvents(),
546               ::testing::ElementsAre("constructed Leftmost", "constructed Base",
547                                      "constructed Rightmost",
548                                      "constructed MultiplyDerived",
549                                      "set Rightmost to 3"));
550 }
551 
TYPED_TEST(SequenceBoundTest,MoveConstructionFromNull)552 TYPED_TEST(SequenceBoundTest, MoveConstructionFromNull) {
553   SEQUENCE_BOUND_T<BoxedValue> value1;
554   // Should not crash.
555   SEQUENCE_BOUND_T<BoxedValue> value2(std::move(value1));
556 }
557 
TYPED_TEST(SequenceBoundTest,MoveAssignmentFromNull)558 TYPED_TEST(SequenceBoundTest, MoveAssignmentFromNull) {
559   SEQUENCE_BOUND_T<BoxedValue> value1;
560   SEQUENCE_BOUND_T<BoxedValue> value2;
561   // Should not crash.
562   value2 = std::move(value1);
563 }
564 
TYPED_TEST(SequenceBoundTest,MoveAssignmentFromSelf)565 TYPED_TEST(SequenceBoundTest, MoveAssignmentFromSelf) {
566   SEQUENCE_BOUND_T<BoxedValue> value;
567   // Cheat to avoid clang self-move warning.
568   auto& value2 = value;
569   // Should not crash.
570   value2 = std::move(value);
571 }
572 
TYPED_TEST(SequenceBoundTest,ResetNullSequenceBound)573 TYPED_TEST(SequenceBoundTest, ResetNullSequenceBound) {
574   SEQUENCE_BOUND_T<BoxedValue> value;
575   // Should not crash.
576   value.Reset();
577 }
578 
TYPED_TEST(SequenceBoundTest,ConstructWithLvalue)579 TYPED_TEST(SequenceBoundTest, ConstructWithLvalue) {
580   int lvalue = 99;
581   SEQUENCE_BOUND_T<BoxedValue> value(this->background_task_runner_, lvalue,
582                                      &this->logger_);
583   value.FlushPostedTasksForTesting();
584   EXPECT_THAT(this->logger_.TakeEvents(),
585               ::testing::ElementsAre("constructed BoxedValue = 99"));
586 }
587 
TYPED_TEST(SequenceBoundTest,PostTaskWithThisObject)588 TYPED_TEST(SequenceBoundTest, PostTaskWithThisObject) {
589   constexpr int kTestValue1 = 42;
590   constexpr int kTestValue2 = 42;
591   SEQUENCE_BOUND_T<BoxedValue> value(this->background_task_runner_,
592                                      kTestValue1);
593   value.PostTaskWithThisObject(BindLambdaForTesting(
594       [&](const BoxedValue& v) { EXPECT_EQ(kTestValue1, v.value()); }));
595   value.PostTaskWithThisObject(
596       BindLambdaForTesting([&](BoxedValue* v) { v->set_value(kTestValue2); }));
597   value.PostTaskWithThisObject(BindLambdaForTesting(
598       [&](const BoxedValue& v) { EXPECT_EQ(kTestValue2, v.value()); }));
599   value.FlushPostedTasksForTesting();
600 }
601 
TYPED_TEST(SequenceBoundTest,SynchronouslyResetForTest)602 TYPED_TEST(SequenceBoundTest, SynchronouslyResetForTest) {
603   SEQUENCE_BOUND_T<BoxedValue> value(this->background_task_runner_, 0);
604 
605   bool destroyed = false;
606   value.AsyncCall(&BoxedValue::set_destruction_callback)
607       .WithArgs(BindLambdaForTesting([&] { destroyed = true; }));
608 
609   value.SynchronouslyResetForTest();
610   EXPECT_TRUE(destroyed);
611 }
612 
TYPED_TEST(SequenceBoundTest,FlushPostedTasksForTesting)613 TYPED_TEST(SequenceBoundTest, FlushPostedTasksForTesting) {
614   SEQUENCE_BOUND_T<BoxedValue> value(this->background_task_runner_, 0,
615                                      &this->logger_);
616 
617   value.AsyncCall(&BoxedValue::set_value).WithArgs(42);
618   value.FlushPostedTasksForTesting();
619 
620   EXPECT_THAT(this->logger_.TakeEvents(),
621               ::testing::ElementsAre("constructed BoxedValue = 0",
622                                      "updated BoxedValue from 0 to 42"));
623 }
624 
TYPED_TEST(SequenceBoundTest,SmallObject)625 TYPED_TEST(SequenceBoundTest, SmallObject) {
626   class EmptyClass {};
627   SEQUENCE_BOUND_T<EmptyClass> value(this->background_task_runner_);
628   // Test passes if SequenceBound constructor does not crash in AlignedAlloc().
629 }
630 
TYPED_TEST(SequenceBoundTest,SelfMoveAssign)631 TYPED_TEST(SequenceBoundTest, SelfMoveAssign) {
632   class EmptyClass {};
633   SEQUENCE_BOUND_T<EmptyClass> value(this->background_task_runner_);
634   EXPECT_FALSE(value.is_null());
635   // Clang has a warning for self-move, so be clever.
636   auto& actually_the_same_value = value;
637   value = std::move(actually_the_same_value);
638   // Note: in general, moved-from objects are in a valid but undefined state.
639   // This is merely a test that self-move doesn't result in something bad
640   // happening; this is not an assertion that self-move will always have this
641   // behavior.
642   EXPECT_TRUE(value.is_null());
643 }
644 
TYPED_TEST(SequenceBoundTest,Emplace)645 TYPED_TEST(SequenceBoundTest, Emplace) {
646   SEQUENCE_BOUND_T<BoxedValue> value;
647   EXPECT_TRUE(value.is_null());
648   value.WrappedEmplace(this->background_task_runner_, 8);
649   value.AsyncCall(&BoxedValue::value)
650       .Then(BindLambdaForTesting(
651           [&](int actual_value) { EXPECT_EQ(8, actual_value); }));
652   value.FlushPostedTasksForTesting();
653 }
654 
TYPED_TEST(SequenceBoundTest,EmplaceOverExisting)655 TYPED_TEST(SequenceBoundTest, EmplaceOverExisting) {
656   SEQUENCE_BOUND_T<BoxedValue> value(this->background_task_runner_, 8,
657                                      &this->logger_);
658   EXPECT_FALSE(value.is_null());
659   value.WrappedEmplace(this->background_task_runner_, 9, &this->logger_);
660   value.AsyncCall(&BoxedValue::value)
661       .Then(BindLambdaForTesting(
662           [&](int actual_value) { EXPECT_EQ(9, actual_value); }));
663   value.FlushPostedTasksForTesting();
664 
665   if constexpr (TypeParam::kManagingTaskRunnerConstructsT) {
666     // Both the replaced `BoxedValue` and the current `BoxedValue` should
667     // live on the same sequence: make sure the replaced `BoxedValue` was
668     // destroyed before the current `BoxedValue` was constructed.
669     EXPECT_THAT(this->logger_.TakeEvents(),
670                 ::testing::ElementsAre(
671                     "constructed BoxedValue = 8", "destroyed BoxedValue = 8",
672                     "constructed BoxedValue = 9", "accessed BoxedValue = 9"));
673   } else {
674     // When `SequenceBound` manages a `std::unique_ptr<T>`, `T` is constructed
675     // on the current sequence so construction of the new managed instance will
676     // happen before the previously-managed instance is destroyed on the
677     // managing task runner.
678     EXPECT_THAT(this->logger_.TakeEvents(),
679                 ::testing::ElementsAre(
680                     "constructed BoxedValue = 8", "constructed BoxedValue = 9",
681                     "destroyed BoxedValue = 8", "accessed BoxedValue = 9"));
682   }
683 }
684 
TYPED_TEST(SequenceBoundTest,EmplaceOverExistingWithTaskRunnerSwap)685 TYPED_TEST(SequenceBoundTest, EmplaceOverExistingWithTaskRunnerSwap) {
686   scoped_refptr<SequencedTaskRunner> another_task_runner =
687       ThreadPool::CreateSequencedTaskRunner({});
688   // No `EventLogger` here since destruction of the old `BoxedValue` and
689   // construction of the new `BoxedValue` take place on different sequences and
690   // can arbitrarily race.
691   SEQUENCE_BOUND_T<BoxedValue> value(another_task_runner, 8);
692   EXPECT_FALSE(value.is_null());
693   value.WrappedEmplace(this->background_task_runner_, 9);
694   {
695     value.PostTaskWithThisObject(BindLambdaForTesting(
696         [another_task_runner,
697          background_task_runner =
698              this->background_task_runner_](const BoxedValue& boxed_value) {
699           EXPECT_FALSE(another_task_runner->RunsTasksInCurrentSequence());
700           EXPECT_TRUE(background_task_runner->RunsTasksInCurrentSequence());
701           EXPECT_EQ(9, boxed_value.value());
702         }));
703     value.FlushPostedTasksForTesting();
704   }
705 }
706 
707 namespace {
708 
709 class NoArgsVoidReturn {
710  public:
Method()711   void Method() {
712     if (loop_) {
713       loop_->Quit();
714       loop_ = nullptr;
715     }
716   }
ConstMethod() const717   void ConstMethod() const {
718     if (loop_) {
719       loop_->Quit();
720       loop_ = nullptr;
721     }
722   }
723 
set_loop(RunLoop * loop)724   void set_loop(RunLoop* loop) { loop_ = loop; }
725 
726  private:
727   mutable raw_ptr<RunLoop> loop_ = nullptr;
728 };
729 
730 class NoArgsIntReturn {
731  public:
Method()732   int Method() { return 123; }
ConstMethod() const733   int ConstMethod() const { return 456; }
734 };
735 
736 class IntArgVoidReturn {
737  public:
IntArgVoidReturn(int * method_called_with,int * const_method_called_with)738   IntArgVoidReturn(int* method_called_with, int* const_method_called_with)
739       : method_called_with_(method_called_with),
740         const_method_called_with_(const_method_called_with) {}
741 
Method(int x)742   void Method(int x) {
743     *method_called_with_ = x;
744     method_called_with_ = nullptr;
745     if (loop_) {
746       loop_->Quit();
747       loop_ = nullptr;
748     }
749   }
ConstMethod(int x) const750   void ConstMethod(int x) const {
751     *const_method_called_with_ = x;
752     const_method_called_with_ = nullptr;
753     if (loop_) {
754       loop_->Quit();
755       loop_ = nullptr;
756     }
757   }
758 
set_loop(RunLoop * loop)759   void set_loop(RunLoop* loop) { loop_ = loop; }
760 
761  private:
762   raw_ptr<int> method_called_with_;
763   mutable raw_ptr<int> const_method_called_with_;
764   mutable raw_ptr<RunLoop> loop_ = nullptr;
765 };
766 
767 class IntArgIntReturn {
768  public:
Method(int x)769   int Method(int x) { return -x; }
ConstMethod(int x) const770   int ConstMethod(int x) const { return -x; }
771 };
772 
773 }  // namespace
774 
TYPED_TEST(SequenceBoundTest,AsyncCallNoArgsNoThen)775 TYPED_TEST(SequenceBoundTest, AsyncCallNoArgsNoThen) {
776   SEQUENCE_BOUND_T<NoArgsVoidReturn> s(this->background_task_runner_);
777 
778   {
779     RunLoop loop;
780     s.AsyncCall(&NoArgsVoidReturn::set_loop).WithArgs(&loop);
781     s.AsyncCall(&NoArgsVoidReturn::Method);
782     loop.Run();
783   }
784 
785   {
786     RunLoop loop;
787     s.AsyncCall(&NoArgsVoidReturn::set_loop).WithArgs(&loop);
788     s.AsyncCall(&NoArgsVoidReturn::ConstMethod);
789     loop.Run();
790   }
791 }
792 
TYPED_TEST(SequenceBoundTest,AsyncCallIntArgNoThen)793 TYPED_TEST(SequenceBoundTest, AsyncCallIntArgNoThen) {
794   int method_called_with = 0;
795   int const_method_called_with = 0;
796   SEQUENCE_BOUND_T<IntArgVoidReturn> s(this->background_task_runner_,
797                                        &method_called_with,
798                                        &const_method_called_with);
799 
800   {
801     RunLoop loop;
802     s.AsyncCall(&IntArgVoidReturn::set_loop).WithArgs(&loop);
803     s.AsyncCall(&IntArgVoidReturn::Method).WithArgs(123);
804     loop.Run();
805     EXPECT_EQ(123, method_called_with);
806   }
807 
808   {
809     RunLoop loop;
810     s.AsyncCall(&IntArgVoidReturn::set_loop).WithArgs(&loop);
811     s.AsyncCall(&IntArgVoidReturn::ConstMethod).WithArgs(456);
812     loop.Run();
813     EXPECT_EQ(456, const_method_called_with);
814   }
815 }
816 
TYPED_TEST(SequenceBoundTest,AsyncCallNoArgsVoidThen)817 TYPED_TEST(SequenceBoundTest, AsyncCallNoArgsVoidThen) {
818   SEQUENCE_BOUND_T<NoArgsVoidReturn> s(this->background_task_runner_);
819 
820   {
821     RunLoop loop;
822     s.AsyncCall(&NoArgsVoidReturn::Method).Then(BindLambdaForTesting([&]() {
823       loop.Quit();
824     }));
825     loop.Run();
826   }
827 
828   {
829     RunLoop loop;
830     s.AsyncCall(&NoArgsVoidReturn::ConstMethod)
831         .Then(BindLambdaForTesting([&]() { loop.Quit(); }));
832     loop.Run();
833   }
834 }
835 
TYPED_TEST(SequenceBoundTest,AsyncCallNoArgsIntThen)836 TYPED_TEST(SequenceBoundTest, AsyncCallNoArgsIntThen) {
837   SEQUENCE_BOUND_T<NoArgsIntReturn> s(this->background_task_runner_);
838 
839   {
840     RunLoop loop;
841     s.AsyncCall(&NoArgsIntReturn::Method)
842         .Then(BindLambdaForTesting([&](int result) {
843           EXPECT_EQ(123, result);
844           loop.Quit();
845         }));
846     loop.Run();
847   }
848 
849   {
850     RunLoop loop;
851     s.AsyncCall(&NoArgsIntReturn::ConstMethod)
852         .Then(BindLambdaForTesting([&](int result) {
853           EXPECT_EQ(456, result);
854           loop.Quit();
855         }));
856     loop.Run();
857   }
858 }
859 
TYPED_TEST(SequenceBoundTest,AsyncCallWithArgsVoidThen)860 TYPED_TEST(SequenceBoundTest, AsyncCallWithArgsVoidThen) {
861   int method_called_with = 0;
862   int const_method_called_with = 0;
863   SEQUENCE_BOUND_T<IntArgVoidReturn> s(this->background_task_runner_,
864                                        &method_called_with,
865                                        &const_method_called_with);
866 
867   {
868     RunLoop loop;
869     s.AsyncCall(&IntArgVoidReturn::Method)
870         .WithArgs(123)
871         .Then(BindLambdaForTesting([&] { loop.Quit(); }));
872     loop.Run();
873     EXPECT_EQ(123, method_called_with);
874   }
875 
876   {
877     RunLoop loop;
878     s.AsyncCall(&IntArgVoidReturn::ConstMethod)
879         .WithArgs(456)
880         .Then(BindLambdaForTesting([&] { loop.Quit(); }));
881     loop.Run();
882     EXPECT_EQ(456, const_method_called_with);
883   }
884 }
885 
TYPED_TEST(SequenceBoundTest,AsyncCallWithArgsIntThen)886 TYPED_TEST(SequenceBoundTest, AsyncCallWithArgsIntThen) {
887   SEQUENCE_BOUND_T<IntArgIntReturn> s(this->background_task_runner_);
888 
889   {
890     RunLoop loop;
891     s.AsyncCall(&IntArgIntReturn::Method)
892         .WithArgs(123)
893         .Then(BindLambdaForTesting([&](int result) {
894           EXPECT_EQ(-123, result);
895           loop.Quit();
896         }));
897     loop.Run();
898   }
899 
900   {
901     RunLoop loop;
902     s.AsyncCall(&IntArgIntReturn::ConstMethod)
903         .WithArgs(456)
904         .Then(BindLambdaForTesting([&](int result) {
905           EXPECT_EQ(-456, result);
906           loop.Quit();
907         }));
908     loop.Run();
909   }
910 }
911 
TYPED_TEST(SequenceBoundTest,AsyncCallIsConstQualified)912 TYPED_TEST(SequenceBoundTest, AsyncCallIsConstQualified) {
913   // Tests that both const and non-const methods may be called through a
914   // const-qualified SequenceBound.
915   const SEQUENCE_BOUND_T<NoArgsVoidReturn> s(this->background_task_runner_);
916   s.AsyncCall(&NoArgsVoidReturn::ConstMethod);
917   s.AsyncCall(&NoArgsVoidReturn::Method);
918 }
919 
920 class IgnoreResultTestHelperWithNoArgs {
921  public:
IgnoreResultTestHelperWithNoArgs(RunLoop * loop,bool * called)922   explicit IgnoreResultTestHelperWithNoArgs(RunLoop* loop, bool* called)
923       : loop_(loop), called_(called) {}
924 
ConstMethod() const925   int ConstMethod() const {
926     if (loop_) {
927       loop_->Quit();
928       loop_ = nullptr;
929     }
930     if (called_) {
931       *called_ = true;
932       called_ = nullptr;
933     }
934     return 0;
935   }
936 
Method()937   int Method() {
938     if (loop_) {
939       loop_->Quit();
940       loop_ = nullptr;
941     }
942     if (called_) {
943       *called_ = true;
944       called_ = nullptr;
945     }
946     return 0;
947   }
948 
949  private:
950   mutable raw_ptr<RunLoop> loop_ = nullptr;
951   mutable raw_ptr<bool> called_ = nullptr;
952 };
953 
TYPED_TEST(SequenceBoundTest,AsyncCallIgnoreResultNoArgs)954 TYPED_TEST(SequenceBoundTest, AsyncCallIgnoreResultNoArgs) {
955   {
956     RunLoop loop;
957     SEQUENCE_BOUND_T<IgnoreResultTestHelperWithNoArgs> s(
958         this->background_task_runner_, &loop, nullptr);
959     s.AsyncCall(IgnoreResult(&IgnoreResultTestHelperWithNoArgs::ConstMethod));
960     loop.Run();
961   }
962 
963   {
964     RunLoop loop;
965     SEQUENCE_BOUND_T<IgnoreResultTestHelperWithNoArgs> s(
966         this->background_task_runner_, &loop, nullptr);
967     s.AsyncCall(IgnoreResult(&IgnoreResultTestHelperWithNoArgs::Method));
968     loop.Run();
969   }
970 }
971 
TYPED_TEST(SequenceBoundTest,AsyncCallIgnoreResultThen)972 TYPED_TEST(SequenceBoundTest, AsyncCallIgnoreResultThen) {
973   {
974     RunLoop loop;
975     bool called = false;
976     SEQUENCE_BOUND_T<IgnoreResultTestHelperWithNoArgs> s(
977         this->background_task_runner_, nullptr, &called);
978     s.AsyncCall(IgnoreResult(&IgnoreResultTestHelperWithNoArgs::ConstMethod))
979         .Then(BindLambdaForTesting([&] { loop.Quit(); }));
980     loop.Run();
981     EXPECT_TRUE(called);
982   }
983 
984   {
985     RunLoop loop;
986     bool called = false;
987     SEQUENCE_BOUND_T<IgnoreResultTestHelperWithNoArgs> s(
988         this->background_task_runner_, nullptr, &called);
989     s.AsyncCall(IgnoreResult(&IgnoreResultTestHelperWithNoArgs::Method))
990         .Then(BindLambdaForTesting([&] { loop.Quit(); }));
991     loop.Run();
992     EXPECT_TRUE(called);
993   }
994 }
995 
996 class IgnoreResultTestHelperWithArgs {
997  public:
IgnoreResultTestHelperWithArgs(RunLoop * loop,int & value)998   IgnoreResultTestHelperWithArgs(RunLoop* loop, int& value)
999       : loop_(loop), value_(&value) {}
1000 
ConstMethod(int arg) const1001   int ConstMethod(int arg) const {
1002     if (value_) {
1003       *value_ = arg;
1004       value_ = nullptr;
1005     }
1006     if (loop_) {
1007       loop_->Quit();
1008       loop_ = nullptr;
1009     }
1010     return arg;
1011   }
1012 
Method(int arg)1013   int Method(int arg) {
1014     if (value_) {
1015       *value_ = arg;
1016       value_ = nullptr;
1017     }
1018     if (loop_) {
1019       loop_->Quit();
1020       loop_ = nullptr;
1021     }
1022     return arg;
1023   }
1024 
1025  private:
1026   mutable raw_ptr<RunLoop> loop_ = nullptr;
1027   mutable raw_ptr<int> value_;
1028 };
1029 
TYPED_TEST(SequenceBoundTest,AsyncCallIgnoreResultWithArgs)1030 TYPED_TEST(SequenceBoundTest, AsyncCallIgnoreResultWithArgs) {
1031   {
1032     RunLoop loop;
1033     int result = 0;
1034     SEQUENCE_BOUND_T<IgnoreResultTestHelperWithArgs> s(
1035         this->background_task_runner_, &loop, std::ref(result));
1036     s.AsyncCall(IgnoreResult(&IgnoreResultTestHelperWithArgs::ConstMethod))
1037         .WithArgs(60);
1038     loop.Run();
1039     EXPECT_EQ(60, result);
1040   }
1041 
1042   {
1043     RunLoop loop;
1044     int result = 0;
1045     SEQUENCE_BOUND_T<IgnoreResultTestHelperWithArgs> s(
1046         this->background_task_runner_, &loop, std::ref(result));
1047     s.AsyncCall(IgnoreResult(&IgnoreResultTestHelperWithArgs::Method))
1048         .WithArgs(06);
1049     loop.Run();
1050     EXPECT_EQ(06, result);
1051   }
1052 }
1053 
TYPED_TEST(SequenceBoundTest,AsyncCallIgnoreResultWithArgsThen)1054 TYPED_TEST(SequenceBoundTest, AsyncCallIgnoreResultWithArgsThen) {
1055   {
1056     RunLoop loop;
1057     int result = 0;
1058     SEQUENCE_BOUND_T<IgnoreResultTestHelperWithArgs> s(
1059         this->background_task_runner_, nullptr, std::ref(result));
1060     s.AsyncCall(IgnoreResult(&IgnoreResultTestHelperWithArgs::ConstMethod))
1061         .WithArgs(60)
1062         .Then(BindLambdaForTesting([&] { loop.Quit(); }));
1063     loop.Run();
1064     EXPECT_EQ(60, result);
1065   }
1066 
1067   {
1068     RunLoop loop;
1069     int result = 0;
1070     SEQUENCE_BOUND_T<IgnoreResultTestHelperWithArgs> s(
1071         this->background_task_runner_, nullptr, std::ref(result));
1072     s.AsyncCall(IgnoreResult(&IgnoreResultTestHelperWithArgs::Method))
1073         .WithArgs(06)
1074         .Then(BindLambdaForTesting([&] { loop.Quit(); }));
1075     loop.Run();
1076     EXPECT_EQ(06, result);
1077   }
1078 }
1079 
1080 // TODO(https://crbug.com/1382549): Maybe use the nocompile harness here instead
1081 // of being "clever"...
TYPED_TEST(SequenceBoundTest,NoCompileTests)1082 TYPED_TEST(SequenceBoundTest, NoCompileTests) {
1083   // TODO(https://crbug.com/1382549): Test calling WithArgs() on a method that
1084   // takes no arguments.
1085   //
1086   // Given:
1087   //   class C {
1088   //     void F();
1089   //   };
1090   //
1091   // Then:
1092   //   SequenceBound<C> s(...);
1093   //   s.AsyncCall(&C::F).WithArgs(...);
1094   //
1095   // should not compile.
1096   //
1097   // TODO(https://crbug.com/1382549): Test calling Then() before calling
1098   // WithArgs().
1099   //
1100   // Given:
1101   //   class C {
1102   //     void F(int);
1103   //   };
1104   //
1105   // Then:
1106   //   SequenceBound<C> s(...);
1107   //   s.AsyncCall(&C::F).Then(...).WithArgs(...);
1108   //
1109   // should not compile.
1110   //
1111   // TODO(https://crbug.com/1382549): Add no-compile tests for converting
1112   // between SequenceBound<T> and SequenceBound<std::unique_ptr<T>>.
1113 }
1114 #undef SequenceBound
1115 
1116 class SequenceBoundDeathTest : public ::testing::Test {
1117  protected:
TearDown()1118   void TearDown() override {
1119     // Make sure that any objects owned by `SequenceBound` have been destroyed
1120     // to avoid tripping leak detection.
1121     RunLoop run_loop;
1122     task_runner_->PostTask(FROM_HERE, run_loop.QuitClosure());
1123     run_loop.Run();
1124   }
1125 
1126   // Death tests use fork(), which can interact (very) poorly with threads.
1127   test::SingleThreadTaskEnvironment task_environment_;
1128   scoped_refptr<SequencedTaskRunner> task_runner_ =
1129       SequencedTaskRunner::GetCurrentDefault();
1130 };
1131 
TEST_F(SequenceBoundDeathTest,AsyncCallIntArgNoWithArgsShouldCheck)1132 TEST_F(SequenceBoundDeathTest, AsyncCallIntArgNoWithArgsShouldCheck) {
1133   SequenceBound<IntArgIntReturn> s(task_runner_);
1134   EXPECT_DEATH_IF_SUPPORTED(s.AsyncCall(&IntArgIntReturn::Method), "");
1135 }
1136 
TEST_F(SequenceBoundDeathTest,AsyncCallIntReturnNoThenShouldCheck)1137 TEST_F(SequenceBoundDeathTest, AsyncCallIntReturnNoThenShouldCheck) {
1138   {
1139     SequenceBound<NoArgsIntReturn> s(task_runner_);
1140     EXPECT_DEATH_IF_SUPPORTED(s.AsyncCall(&NoArgsIntReturn::Method), "");
1141   }
1142 
1143   {
1144     SequenceBound<IntArgIntReturn> s(task_runner_);
1145     EXPECT_DEATH_IF_SUPPORTED(s.AsyncCall(&IntArgIntReturn::Method).WithArgs(0),
1146                               "");
1147   }
1148 }
1149 
1150 }  // namespace
1151 
1152 }  // namespace base
1153