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