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