xref: /aosp_15_r20/external/cronet/base/threading/sequence_bound_unittest.cc (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
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::__anon5d5b4e930111::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::__anon5d5b4e930111::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)
832         .Then(BindLambdaForTesting([&]() { loop.Quit(); }));
833     loop.Run();
834   }
835 }
836 
TYPED_TEST(SequenceBoundTest,AsyncCallNoArgsIntThen)837 TYPED_TEST(SequenceBoundTest, AsyncCallNoArgsIntThen) {
838   SEQUENCE_BOUND_T<NoArgsIntReturn> s(this->background_task_runner_);
839 
840   {
841     RunLoop loop;
842     s.AsyncCall(&NoArgsIntReturn::Method)
843         .Then(BindLambdaForTesting([&](int result) {
844           EXPECT_EQ(123, result);
845           loop.Quit();
846         }));
847     loop.Run();
848   }
849 
850   {
851     RunLoop loop;
852     s.AsyncCall(&NoArgsIntReturn::ConstMethod)
853         .Then(BindLambdaForTesting([&](int result) {
854           EXPECT_EQ(456, result);
855           loop.Quit();
856         }));
857     loop.Run();
858   }
859 }
860 
TYPED_TEST(SequenceBoundTest,AsyncCallWithArgsVoidThen)861 TYPED_TEST(SequenceBoundTest, AsyncCallWithArgsVoidThen) {
862   int method_called_with = 0;
863   int const_method_called_with = 0;
864   SEQUENCE_BOUND_T<IntArgVoidReturn> s(this->background_task_runner_,
865                                        &method_called_with,
866                                        &const_method_called_with);
867 
868   {
869     RunLoop loop;
870     s.AsyncCall(&IntArgVoidReturn::Method)
871         .WithArgs(123)
872         .Then(BindLambdaForTesting([&] { loop.Quit(); }));
873     loop.Run();
874     EXPECT_EQ(123, method_called_with);
875   }
876 
877   {
878     RunLoop loop;
879     s.AsyncCall(&IntArgVoidReturn::ConstMethod)
880         .WithArgs(456)
881         .Then(BindLambdaForTesting([&] { loop.Quit(); }));
882     loop.Run();
883     EXPECT_EQ(456, const_method_called_with);
884   }
885 }
886 
TYPED_TEST(SequenceBoundTest,AsyncCallWithArgsIntThen)887 TYPED_TEST(SequenceBoundTest, AsyncCallWithArgsIntThen) {
888   SEQUENCE_BOUND_T<IntArgIntReturn> s(this->background_task_runner_);
889 
890   {
891     RunLoop loop;
892     s.AsyncCall(&IntArgIntReturn::Method)
893         .WithArgs(123)
894         .Then(BindLambdaForTesting([&](int result) {
895           EXPECT_EQ(-123, result);
896           loop.Quit();
897         }));
898     loop.Run();
899   }
900 
901   {
902     RunLoop loop;
903     s.AsyncCall(&IntArgIntReturn::ConstMethod)
904         .WithArgs(456)
905         .Then(BindLambdaForTesting([&](int result) {
906           EXPECT_EQ(-456, result);
907           loop.Quit();
908         }));
909     loop.Run();
910   }
911 }
912 
TYPED_TEST(SequenceBoundTest,AsyncCallIsConstQualified)913 TYPED_TEST(SequenceBoundTest, AsyncCallIsConstQualified) {
914   // Tests that both const and non-const methods may be called through a
915   // const-qualified SequenceBound.
916   const SEQUENCE_BOUND_T<NoArgsVoidReturn> s(this->background_task_runner_);
917   s.AsyncCall(&NoArgsVoidReturn::ConstMethod);
918   s.AsyncCall(&NoArgsVoidReturn::Method);
919 }
920 
921 class IgnoreResultTestHelperWithNoArgs {
922  public:
IgnoreResultTestHelperWithNoArgs(RunLoop * loop,bool * called)923   explicit IgnoreResultTestHelperWithNoArgs(RunLoop* loop, bool* called)
924       : loop_(loop), called_(called) {}
925 
ConstMethod() const926   int ConstMethod() const {
927     if (loop_) {
928       loop_->Quit();
929       loop_ = nullptr;
930     }
931     if (called_) {
932       *called_ = true;
933       called_ = nullptr;
934     }
935     return 0;
936   }
937 
Method()938   int Method() {
939     if (loop_) {
940       loop_->Quit();
941       loop_ = nullptr;
942     }
943     if (called_) {
944       *called_ = true;
945       called_ = nullptr;
946     }
947     return 0;
948   }
949 
950  private:
951   mutable raw_ptr<RunLoop> loop_ = nullptr;
952   mutable raw_ptr<bool> called_ = nullptr;
953 };
954 
TYPED_TEST(SequenceBoundTest,AsyncCallIgnoreResultNoArgs)955 TYPED_TEST(SequenceBoundTest, AsyncCallIgnoreResultNoArgs) {
956   {
957     RunLoop loop;
958     SEQUENCE_BOUND_T<IgnoreResultTestHelperWithNoArgs> s(
959         this->background_task_runner_, &loop, nullptr);
960     s.AsyncCall(IgnoreResult(&IgnoreResultTestHelperWithNoArgs::ConstMethod));
961     loop.Run();
962   }
963 
964   {
965     RunLoop loop;
966     SEQUENCE_BOUND_T<IgnoreResultTestHelperWithNoArgs> s(
967         this->background_task_runner_, &loop, nullptr);
968     s.AsyncCall(IgnoreResult(&IgnoreResultTestHelperWithNoArgs::Method));
969     loop.Run();
970   }
971 }
972 
TYPED_TEST(SequenceBoundTest,AsyncCallIgnoreResultThen)973 TYPED_TEST(SequenceBoundTest, AsyncCallIgnoreResultThen) {
974   {
975     RunLoop loop;
976     bool called = false;
977     SEQUENCE_BOUND_T<IgnoreResultTestHelperWithNoArgs> s(
978         this->background_task_runner_, nullptr, &called);
979     s.AsyncCall(IgnoreResult(&IgnoreResultTestHelperWithNoArgs::ConstMethod))
980         .Then(BindLambdaForTesting([&] { loop.Quit(); }));
981     loop.Run();
982     EXPECT_TRUE(called);
983   }
984 
985   {
986     RunLoop loop;
987     bool called = false;
988     SEQUENCE_BOUND_T<IgnoreResultTestHelperWithNoArgs> s(
989         this->background_task_runner_, nullptr, &called);
990     s.AsyncCall(IgnoreResult(&IgnoreResultTestHelperWithNoArgs::Method))
991         .Then(BindLambdaForTesting([&] { loop.Quit(); }));
992     loop.Run();
993     EXPECT_TRUE(called);
994   }
995 }
996 
997 class IgnoreResultTestHelperWithArgs {
998  public:
IgnoreResultTestHelperWithArgs(RunLoop * loop,int & value)999   IgnoreResultTestHelperWithArgs(RunLoop* loop, int& value)
1000       : loop_(loop), value_(&value) {}
1001 
ConstMethod(int arg) const1002   int ConstMethod(int arg) const {
1003     if (value_) {
1004       *value_ = arg;
1005       value_ = nullptr;
1006     }
1007     if (loop_) {
1008       loop_->Quit();
1009       loop_ = nullptr;
1010     }
1011     return arg;
1012   }
1013 
Method(int arg)1014   int Method(int arg) {
1015     if (value_) {
1016       *value_ = arg;
1017       value_ = nullptr;
1018     }
1019     if (loop_) {
1020       loop_->Quit();
1021       loop_ = nullptr;
1022     }
1023     return arg;
1024   }
1025 
1026  private:
1027   mutable raw_ptr<RunLoop> loop_ = nullptr;
1028   mutable raw_ptr<int> value_;
1029 };
1030 
TYPED_TEST(SequenceBoundTest,AsyncCallIgnoreResultWithArgs)1031 TYPED_TEST(SequenceBoundTest, AsyncCallIgnoreResultWithArgs) {
1032   {
1033     RunLoop loop;
1034     int result = 0;
1035     SEQUENCE_BOUND_T<IgnoreResultTestHelperWithArgs> s(
1036         this->background_task_runner_, &loop, std::ref(result));
1037     s.AsyncCall(IgnoreResult(&IgnoreResultTestHelperWithArgs::ConstMethod))
1038         .WithArgs(60);
1039     loop.Run();
1040     EXPECT_EQ(60, result);
1041   }
1042 
1043   {
1044     RunLoop loop;
1045     int result = 0;
1046     SEQUENCE_BOUND_T<IgnoreResultTestHelperWithArgs> s(
1047         this->background_task_runner_, &loop, std::ref(result));
1048     s.AsyncCall(IgnoreResult(&IgnoreResultTestHelperWithArgs::Method))
1049         .WithArgs(06);
1050     loop.Run();
1051     EXPECT_EQ(06, result);
1052   }
1053 }
1054 
TYPED_TEST(SequenceBoundTest,AsyncCallIgnoreResultWithArgsThen)1055 TYPED_TEST(SequenceBoundTest, AsyncCallIgnoreResultWithArgsThen) {
1056   {
1057     RunLoop loop;
1058     int result = 0;
1059     SEQUENCE_BOUND_T<IgnoreResultTestHelperWithArgs> s(
1060         this->background_task_runner_, nullptr, std::ref(result));
1061     s.AsyncCall(IgnoreResult(&IgnoreResultTestHelperWithArgs::ConstMethod))
1062         .WithArgs(60)
1063         .Then(BindLambdaForTesting([&] { loop.Quit(); }));
1064     loop.Run();
1065     EXPECT_EQ(60, result);
1066   }
1067 
1068   {
1069     RunLoop loop;
1070     int result = 0;
1071     SEQUENCE_BOUND_T<IgnoreResultTestHelperWithArgs> s(
1072         this->background_task_runner_, nullptr, std::ref(result));
1073     s.AsyncCall(IgnoreResult(&IgnoreResultTestHelperWithArgs::Method))
1074         .WithArgs(06)
1075         .Then(BindLambdaForTesting([&] { loop.Quit(); }));
1076     loop.Run();
1077     EXPECT_EQ(06, result);
1078   }
1079 }
1080 
1081 // TODO(https://crbug.com/1382549): Maybe use the nocompile harness here instead
1082 // of being "clever"...
TYPED_TEST(SequenceBoundTest,NoCompileTests)1083 TYPED_TEST(SequenceBoundTest, NoCompileTests) {
1084   // TODO(https://crbug.com/1382549): Test calling WithArgs() on a method that
1085   // takes no arguments.
1086   //
1087   // Given:
1088   //   class C {
1089   //     void F();
1090   //   };
1091   //
1092   // Then:
1093   //   SequenceBound<C> s(...);
1094   //   s.AsyncCall(&C::F).WithArgs(...);
1095   //
1096   // should not compile.
1097   //
1098   // TODO(https://crbug.com/1382549): Test calling Then() before calling
1099   // WithArgs().
1100   //
1101   // Given:
1102   //   class C {
1103   //     void F(int);
1104   //   };
1105   //
1106   // Then:
1107   //   SequenceBound<C> s(...);
1108   //   s.AsyncCall(&C::F).Then(...).WithArgs(...);
1109   //
1110   // should not compile.
1111   //
1112   // TODO(https://crbug.com/1382549): Add no-compile tests for converting
1113   // between SequenceBound<T> and SequenceBound<std::unique_ptr<T>>.
1114 }
1115 #undef SequenceBound
1116 
1117 class SequenceBoundDeathTest : public ::testing::Test {
1118  protected:
TearDown()1119   void TearDown() override {
1120     // Make sure that any objects owned by `SequenceBound` have been destroyed
1121     // to avoid tripping leak detection.
1122     RunLoop run_loop;
1123     task_runner_->PostTask(FROM_HERE, run_loop.QuitClosure());
1124     run_loop.Run();
1125   }
1126 
1127   // Death tests use fork(), which can interact (very) poorly with threads.
1128   test::SingleThreadTaskEnvironment task_environment_;
1129   scoped_refptr<SequencedTaskRunner> task_runner_ =
1130       SequencedTaskRunner::GetCurrentDefault();
1131 };
1132 
TEST_F(SequenceBoundDeathTest,AsyncCallIntArgNoWithArgsShouldCheck)1133 TEST_F(SequenceBoundDeathTest, AsyncCallIntArgNoWithArgsShouldCheck) {
1134   SequenceBound<IntArgIntReturn> s(task_runner_);
1135   EXPECT_DEATH_IF_SUPPORTED(s.AsyncCall(&IntArgIntReturn::Method), "");
1136 }
1137 
TEST_F(SequenceBoundDeathTest,AsyncCallIntReturnNoThenShouldCheck)1138 TEST_F(SequenceBoundDeathTest, AsyncCallIntReturnNoThenShouldCheck) {
1139   {
1140     SequenceBound<NoArgsIntReturn> s(task_runner_);
1141     EXPECT_DEATH_IF_SUPPORTED(s.AsyncCall(&NoArgsIntReturn::Method), "");
1142   }
1143 
1144   {
1145     SequenceBound<IntArgIntReturn> s(task_runner_);
1146     EXPECT_DEATH_IF_SUPPORTED(s.AsyncCall(&IntArgIntReturn::Method).WithArgs(0),
1147                               "");
1148   }
1149 }
1150 
1151 }  // namespace
1152 
1153 }  // namespace base
1154