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