123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830 |
- // Copyright 2018 The Chromium Authors. All rights reserved.
- // Use of this source code is governed by a BSD-style license that can be
- // found in the LICENSE file.
- #include "base/threading/sequence_bound.h"
- #include <functional>
- #include <utility>
- #include "base/memory/raw_ptr.h"
- #include "base/run_loop.h"
- #include "base/test/bind.h"
- #include "base/test/task_environment.h"
- #include "base/threading/sequenced_task_runner_handle.h"
- #include "build/build_config.h"
- #include "testing/gtest/include/gtest/gtest.h"
- namespace base {
- class SequenceBoundTest : public ::testing::Test {
- public:
- // Helpful values that our test classes use.
- enum Value {
- kInitialValue = 0,
- kDifferentValue = 1,
- // Values used by the Derived class.
- kDerivedCtorValue = 111,
- kDerivedDtorValue = 222,
- // Values used by the Other class.
- kOtherCtorValue = 333,
- kOtherDtorValue = 444,
- };
- void TearDown() override {
- // Make sure that any objects owned by `SequenceBound` have been destroyed
- // to avoid tripping leak detection.
- RunLoop run_loop;
- task_runner_->PostTask(FROM_HERE, run_loop.QuitClosure());
- run_loop.Run();
- }
- // Do-nothing base class, just so we can test assignment of derived classes.
- // It introduces a virtual destructor, so that casting derived classes to
- // Base should still use the appropriate (virtual) destructor.
- class Base {
- public:
- virtual ~Base() {}
- };
- // Handy class to set an int ptr to different values, to verify that things
- // are being run properly.
- class Derived : public Base {
- public:
- Derived(Value* ptr) : ptr_(ptr) { *ptr_ = kDerivedCtorValue; }
- ~Derived() override { *ptr_ = kDerivedDtorValue; }
- void SetValue(Value value) { *ptr_ = value; }
- raw_ptr<Value> ptr_;
- };
- // Another base class, which sets ints to different values.
- class Other {
- public:
- Other(Value* ptr) : ptr_(ptr) { *ptr = kOtherCtorValue; }
- virtual ~Other() { *ptr_ = kOtherDtorValue; }
- void SetValue(Value value) { *ptr_ = value; }
- raw_ptr<Value> ptr_;
- };
- class MultiplyDerived : public Other, public Derived {
- public:
- MultiplyDerived(Value* ptr1, Value* ptr2) : Other(ptr1), Derived(ptr2) {}
- };
- // TODO(dcheng): This isn't used, but upcasting to a virtual base class is
- // unsafe and is currently unchecked! Add these safety checks back in.
- struct VirtuallyDerived : public virtual Base {};
- base::test::TaskEnvironment task_environment_;
- scoped_refptr<base::SequencedTaskRunner> task_runner_ =
- base::SequencedTaskRunnerHandle::Get();
- Value value_ = kInitialValue;
- };
- class BoxedValue {
- public:
- explicit BoxedValue(int initial_value) : value_(initial_value) {}
- BoxedValue(const BoxedValue&) = delete;
- BoxedValue& operator=(const BoxedValue&) = delete;
- ~BoxedValue() {
- if (destruction_callback_)
- std::move(destruction_callback_).Run();
- }
- void set_destruction_callback(base::OnceClosure callback) {
- destruction_callback_ = std::move(callback);
- }
- int value() const { return value_; }
- void set_value(int value) { value_ = value; }
- private:
- int value_ = 0;
- base::OnceClosure destruction_callback_;
- };
- #if BUILDFLAG(IS_IOS) && !TARGET_OS_SIMULATOR
- #define MAYBE_ConstructAsyncCallReset FLAKY_ConstructAsyncCallReset
- #else
- #define MAYBE_ConstructAsyncCallReset ConstructAsyncCallReset
- #endif
- // https://crbug.com/899779 tracks test flakiness on iOS.
- TEST_F(SequenceBoundTest, MAYBE_ConstructAsyncCallReset) {
- auto derived = SequenceBound<Derived>(task_runner_, &value_);
- EXPECT_FALSE(derived.is_null());
- EXPECT_TRUE(derived);
- // Nothing should happen until we run the message loop.
- EXPECT_EQ(value_, kInitialValue);
- base::RunLoop().RunUntilIdle();
- EXPECT_EQ(value_, kDerivedCtorValue);
- // Post now that the object has been constructed.
- derived.AsyncCall(&Derived::SetValue).WithArgs(kDifferentValue);
- EXPECT_EQ(value_, kDerivedCtorValue);
- base::RunLoop().RunUntilIdle();
- EXPECT_EQ(value_, kDifferentValue);
- // Reset it, and make sure that destruction is posted. The owner should
- // report that it is null immediately.
- derived.Reset();
- EXPECT_TRUE(derived.is_null());
- EXPECT_FALSE(derived);
- EXPECT_EQ(value_, kDifferentValue);
- base::RunLoop().RunUntilIdle();
- EXPECT_EQ(value_, kDerivedDtorValue);
- }
- TEST_F(SequenceBoundTest, PostBeforeConstruction) {
- // Construct an object and post a message to it, before construction has been
- // run on |task_runner_|.
- auto derived = SequenceBound<Derived>(task_runner_, &value_);
- derived.AsyncCall(&Derived::SetValue).WithArgs(kDifferentValue);
- EXPECT_EQ(value_, kInitialValue);
- // Both construction and SetValue should run.
- base::RunLoop().RunUntilIdle();
- EXPECT_EQ(value_, kDifferentValue);
- }
- TEST_F(SequenceBoundTest, MoveConstructionFromSameClass) {
- // Verify that we can move-construct with the same class.
- auto derived_old = SequenceBound<Derived>(task_runner_, &value_);
- auto derived_new = std::move(derived_old);
- EXPECT_TRUE(derived_old.is_null());
- EXPECT_FALSE(derived_new.is_null());
- base::RunLoop().RunUntilIdle();
- EXPECT_EQ(value_, kDerivedCtorValue);
- // Verify that |derived_new| owns the object now, and that the virtual
- // destructor is called.
- derived_new.Reset();
- EXPECT_EQ(value_, kDerivedCtorValue);
- base::RunLoop().RunUntilIdle();
- EXPECT_EQ(value_, kDerivedDtorValue);
- }
- TEST_F(SequenceBoundTest, MoveConstructionFromDerivedClass) {
- // Verify that we can move-construct to a base class from a derived class.
- auto derived = SequenceBound<Derived>(task_runner_, &value_);
- SequenceBound<Base> base(std::move(derived));
- EXPECT_TRUE(derived.is_null());
- EXPECT_FALSE(base.is_null());
- base::RunLoop().RunUntilIdle();
- EXPECT_EQ(value_, kDerivedCtorValue);
- // Verify that |base| owns the object now, and that destruction still destroys
- // Derived properly.
- base.Reset();
- EXPECT_EQ(value_, kDerivedCtorValue);
- base::RunLoop().RunUntilIdle();
- EXPECT_EQ(value_, kDerivedDtorValue);
- }
- TEST_F(SequenceBoundTest, MultiplyDerivedDestructionWorksLeftSuper) {
- // Verify that everything works when we're casting around in ways that might
- // change the address. We cast to the left side of MultiplyDerived and then
- // reset the owner. ASAN will catch free() errors.
- Value value2 = kInitialValue;
- auto mderived =
- SequenceBound<MultiplyDerived>(task_runner_, &value_, &value2);
- base::RunLoop().RunUntilIdle();
- EXPECT_EQ(value_, kOtherCtorValue);
- EXPECT_EQ(value2, kDerivedCtorValue);
- SequenceBound<Other> other = std::move(mderived);
- other.Reset();
- base::RunLoop().RunUntilIdle();
- // Both destructors should have run.
- EXPECT_EQ(value_, kOtherDtorValue);
- EXPECT_EQ(value2, kDerivedDtorValue);
- }
- TEST_F(SequenceBoundTest, MultiplyDerivedDestructionWorksRightSuper) {
- // Verify that everything works when we're casting around in ways that might
- // change the address. We cast to the right side of MultiplyDerived and then
- // reset the owner. ASAN will catch free() errors.
- Value value2 = kInitialValue;
- auto mderived =
- SequenceBound<MultiplyDerived>(task_runner_, &value_, &value2);
- base::RunLoop().RunUntilIdle();
- EXPECT_EQ(value_, kOtherCtorValue);
- EXPECT_EQ(value2, kDerivedCtorValue);
- SequenceBound<Base> base = std::move(mderived);
- base.Reset();
- base::RunLoop().RunUntilIdle();
- // Both destructors should have run.
- EXPECT_EQ(value_, kOtherDtorValue);
- EXPECT_EQ(value2, kDerivedDtorValue);
- }
- TEST_F(SequenceBoundTest, MoveAssignmentFromSameClass) {
- // Test move-assignment using the same classes.
- auto derived_old = SequenceBound<Derived>(task_runner_, &value_);
- SequenceBound<Derived> derived_new;
- derived_new = std::move(derived_old);
- EXPECT_TRUE(derived_old.is_null());
- EXPECT_FALSE(derived_new.is_null());
- base::RunLoop().RunUntilIdle();
- EXPECT_EQ(value_, kDerivedCtorValue);
- // Verify that |derived_new| owns the object now. Also verifies that move
- // assignment from the same class deletes the outgoing object.
- derived_new = SequenceBound<Derived>();
- EXPECT_EQ(value_, kDerivedCtorValue);
- base::RunLoop().RunUntilIdle();
- EXPECT_EQ(value_, kDerivedDtorValue);
- }
- TEST_F(SequenceBoundTest, MoveAssignmentFromDerivedClass) {
- // Move-assignment from a derived class to a base class.
- auto derived = SequenceBound<Derived>(task_runner_, &value_);
- SequenceBound<Base> base;
- base = std::move(derived);
- EXPECT_TRUE(derived.is_null());
- EXPECT_FALSE(base.is_null());
- base::RunLoop().RunUntilIdle();
- EXPECT_EQ(value_, kDerivedCtorValue);
- // Verify that |base| owns the object now, and that destruction still destroys
- // Derived properly.
- base.Reset();
- EXPECT_EQ(value_, kDerivedCtorValue);
- base::RunLoop().RunUntilIdle();
- EXPECT_EQ(value_, kDerivedDtorValue);
- }
- TEST_F(SequenceBoundTest, MoveAssignmentFromDerivedClassDestroysOldObject) {
- // Verify that move-assignment from a derived class runs the dtor of the
- // outgoing object.
- auto derived = SequenceBound<Derived>(task_runner_, &value_);
- Value value1 = kInitialValue;
- Value value2 = kInitialValue;
- auto mderived =
- SequenceBound<MultiplyDerived>(task_runner_, &value1, &value2);
- base::RunLoop().RunUntilIdle();
- EXPECT_EQ(value_, kDerivedCtorValue);
- // Assign |mderived|, and verify that the original object in |derived| is
- // destroyed properly.
- derived = std::move(mderived);
- base::RunLoop().RunUntilIdle();
- EXPECT_EQ(value_, kDerivedDtorValue);
- // Delete |derived|, since it has pointers to local vars.
- derived.Reset();
- base::RunLoop().RunUntilIdle();
- }
- TEST_F(SequenceBoundTest, MultiplyDerivedPostToLeftBaseClass) {
- // Cast and call methods on the left base class.
- Value value1 = kInitialValue;
- Value value2 = kInitialValue;
- auto mderived =
- SequenceBound<MultiplyDerived>(task_runner_, &value1, &value2);
- // Cast to Other, the left base.
- SequenceBound<Other> other(std::move(mderived));
- other.AsyncCall(&Other::SetValue).WithArgs(kDifferentValue);
- base::RunLoop().RunUntilIdle();
- EXPECT_EQ(value1, kDifferentValue);
- EXPECT_EQ(value2, kDerivedCtorValue);
- other.Reset();
- base::RunLoop().RunUntilIdle();
- }
- TEST_F(SequenceBoundTest, MultiplyDerivedPostToRightBaseClass) {
- // Cast and call methods on the right base class.
- Value value1 = kInitialValue;
- Value value2 = kInitialValue;
- auto mderived =
- SequenceBound<MultiplyDerived>(task_runner_, &value1, &value2);
- SequenceBound<Derived> derived(std::move(mderived));
- derived.AsyncCall(&Derived::SetValue).WithArgs(kDifferentValue);
- base::RunLoop().RunUntilIdle();
- EXPECT_EQ(value1, kOtherCtorValue);
- EXPECT_EQ(value2, kDifferentValue);
- derived.Reset();
- base::RunLoop().RunUntilIdle();
- }
- TEST_F(SequenceBoundTest, MoveConstructionFromNullWorks) {
- // Verify that this doesn't crash.
- SequenceBound<Derived> derived1;
- SequenceBound<Derived> derived2(std::move(derived1));
- }
- TEST_F(SequenceBoundTest, MoveAssignmentFromNullWorks) {
- // Verify that this doesn't crash.
- SequenceBound<Derived> derived1;
- SequenceBound<Derived> derived2;
- derived2 = std::move(derived1);
- }
- TEST_F(SequenceBoundTest, ResetOnNullObjectWorks) {
- // Verify that this doesn't crash.
- SequenceBound<Derived> derived;
- derived.Reset();
- }
- TEST_F(SequenceBoundTest, LvalueConstructionParameter) {
- // Note here that |value_ptr| is an lvalue, while |&value| would be an rvalue.
- Value value = kInitialValue;
- Value* value_ptr = &value;
- SequenceBound<Derived> derived(task_runner_, value_ptr);
- {
- derived.AsyncCall(&Derived::SetValue).WithArgs(kDifferentValue);
- base::RunLoop run_loop;
- task_runner_->PostTask(FROM_HERE, run_loop.QuitClosure());
- run_loop.Run();
- EXPECT_EQ(value, kDifferentValue);
- }
- {
- derived.Reset();
- base::RunLoop run_loop;
- task_runner_->PostTask(FROM_HERE, run_loop.QuitClosure());
- run_loop.Run();
- EXPECT_EQ(value, kDerivedDtorValue);
- }
- }
- TEST_F(SequenceBoundTest, PostTaskWithThisObject) {
- constexpr int kTestValue1 = 42;
- constexpr int kTestValue2 = 42;
- base::SequenceBound<BoxedValue> value(task_runner_, kTestValue1);
- base::RunLoop loop;
- value.PostTaskWithThisObject(base::BindLambdaForTesting(
- [&](const BoxedValue& v) { EXPECT_EQ(kTestValue1, v.value()); }));
- value.PostTaskWithThisObject(base::BindLambdaForTesting(
- [&](BoxedValue* v) { v->set_value(kTestValue2); }));
- value.PostTaskWithThisObject(
- base::BindLambdaForTesting([&](const BoxedValue& v) {
- EXPECT_EQ(kTestValue2, v.value());
- loop.Quit();
- }));
- loop.Run();
- }
- TEST_F(SequenceBoundTest, SynchronouslyResetForTest) {
- base::SequenceBound<BoxedValue> value(task_runner_, 0);
- bool destroyed = false;
- value.AsyncCall(&BoxedValue::set_destruction_callback)
- .WithArgs(base::BindLambdaForTesting([&] { destroyed = true; }));
- value.SynchronouslyResetForTest();
- EXPECT_TRUE(destroyed);
- }
- TEST_F(SequenceBoundTest, SmallObject) {
- class EmptyClass {};
- SequenceBound<EmptyClass> value(task_runner_);
- // Test passes if SequenceBound constructor does not crash in AlignedAlloc().
- }
- TEST_F(SequenceBoundTest, SelfMoveAssign) {
- class EmptyClass {};
- SequenceBound<EmptyClass> value(task_runner_);
- EXPECT_FALSE(value.is_null());
- // Clang has a warning for self-move, so be clever.
- auto& actually_the_same_value = value;
- value = std::move(actually_the_same_value);
- // Note: in general, moved-from objects are in a valid but undefined state.
- // This is merely a test that self-move doesn't result in something bad
- // happening; this is not an assertion that self-move will always have this
- // behavior.
- EXPECT_TRUE(value.is_null());
- }
- namespace {
- class NoArgsVoidReturn {
- public:
- void Method() {
- if (loop_)
- loop_->Quit();
- }
- void ConstMethod() const {
- if (loop_)
- loop_->Quit();
- }
- void set_loop(RunLoop* loop) { loop_ = loop; }
- private:
- RunLoop* loop_ = nullptr;
- };
- class NoArgsIntReturn {
- public:
- int Method() { return 123; }
- int ConstMethod() const { return 456; }
- };
- class IntArgVoidReturn {
- public:
- IntArgVoidReturn(int* method_called_with, int* const_method_called_with)
- : method_called_with_(method_called_with),
- const_method_called_with_(const_method_called_with) {}
- void Method(int x) {
- *method_called_with_ = x;
- if (loop_)
- loop_->Quit();
- }
- void ConstMethod(int x) const {
- *const_method_called_with_ = x;
- if (loop_)
- loop_->Quit();
- }
- void set_loop(RunLoop* loop) { loop_ = loop; }
- private:
- const raw_ptr<int> method_called_with_;
- const raw_ptr<int> const_method_called_with_;
- raw_ptr<RunLoop> loop_ = nullptr;
- };
- class IntArgIntReturn {
- public:
- int Method(int x) { return -x; }
- int ConstMethod(int x) const { return -x; }
- };
- } // namespace
- TEST_F(SequenceBoundTest, AsyncCallNoArgsNoThen) {
- SequenceBound<NoArgsVoidReturn> s(task_runner_);
- {
- RunLoop loop;
- s.AsyncCall(&NoArgsVoidReturn::set_loop).WithArgs(&loop);
- s.AsyncCall(&NoArgsVoidReturn::Method);
- loop.Run();
- }
- {
- RunLoop loop;
- s.AsyncCall(&NoArgsVoidReturn::set_loop).WithArgs(&loop);
- s.AsyncCall(&NoArgsVoidReturn::ConstMethod);
- loop.Run();
- }
- }
- TEST_F(SequenceBoundTest, AsyncCallIntArgNoThen) {
- int method_called_with = 0;
- int const_method_called_with = 0;
- SequenceBound<IntArgVoidReturn> s(task_runner_, &method_called_with,
- &const_method_called_with);
- {
- RunLoop loop;
- s.AsyncCall(&IntArgVoidReturn::set_loop).WithArgs(&loop);
- s.AsyncCall(&IntArgVoidReturn::Method).WithArgs(123);
- loop.Run();
- EXPECT_EQ(123, method_called_with);
- }
- {
- RunLoop loop;
- s.AsyncCall(&IntArgVoidReturn::set_loop).WithArgs(&loop);
- s.AsyncCall(&IntArgVoidReturn::ConstMethod).WithArgs(456);
- loop.Run();
- EXPECT_EQ(456, const_method_called_with);
- }
- }
- TEST_F(SequenceBoundTest, AsyncCallNoArgsVoidThen) {
- SequenceBound<NoArgsVoidReturn> s(task_runner_);
- {
- RunLoop loop;
- s.AsyncCall(&NoArgsVoidReturn::Method).Then(BindLambdaForTesting([&]() {
- loop.Quit();
- }));
- loop.Run();
- }
- {
- RunLoop loop;
- s.AsyncCall(&NoArgsVoidReturn::ConstMethod)
- .Then(BindLambdaForTesting([&]() { loop.Quit(); }));
- loop.Run();
- }
- }
- TEST_F(SequenceBoundTest, AsyncCallNoArgsIntThen) {
- SequenceBound<NoArgsIntReturn> s(task_runner_);
- {
- RunLoop loop;
- s.AsyncCall(&NoArgsIntReturn::Method)
- .Then(BindLambdaForTesting([&](int result) {
- EXPECT_EQ(123, result);
- loop.Quit();
- }));
- loop.Run();
- }
- {
- RunLoop loop;
- s.AsyncCall(&NoArgsIntReturn::ConstMethod)
- .Then(BindLambdaForTesting([&](int result) {
- EXPECT_EQ(456, result);
- loop.Quit();
- }));
- loop.Run();
- }
- }
- TEST_F(SequenceBoundTest, AsyncCallWithArgsVoidThen) {
- int method_called_with = 0;
- int const_method_called_with = 0;
- SequenceBound<IntArgVoidReturn> s(task_runner_, &method_called_with,
- &const_method_called_with);
- {
- RunLoop loop;
- s.AsyncCall(&IntArgVoidReturn::Method)
- .WithArgs(123)
- .Then(BindLambdaForTesting([&] { loop.Quit(); }));
- loop.Run();
- EXPECT_EQ(123, method_called_with);
- }
- {
- RunLoop loop;
- s.AsyncCall(&IntArgVoidReturn::ConstMethod)
- .WithArgs(456)
- .Then(BindLambdaForTesting([&] { loop.Quit(); }));
- loop.Run();
- EXPECT_EQ(456, const_method_called_with);
- }
- }
- TEST_F(SequenceBoundTest, AsyncCallWithArgsIntThen) {
- SequenceBound<IntArgIntReturn> s(task_runner_);
- {
- RunLoop loop;
- s.AsyncCall(&IntArgIntReturn::Method)
- .WithArgs(123)
- .Then(BindLambdaForTesting([&](int result) {
- EXPECT_EQ(-123, result);
- loop.Quit();
- }));
- loop.Run();
- }
- {
- RunLoop loop;
- s.AsyncCall(&IntArgIntReturn::ConstMethod)
- .WithArgs(456)
- .Then(BindLambdaForTesting([&](int result) {
- EXPECT_EQ(-456, result);
- loop.Quit();
- }));
- loop.Run();
- }
- }
- TEST_F(SequenceBoundTest, AsyncCallIsConstQualified) {
- // Tests that both const and non-const methods may be called through a
- // const-qualified SequenceBound.
- const SequenceBound<NoArgsVoidReturn> s(task_runner_);
- s.AsyncCall(&NoArgsVoidReturn::ConstMethod);
- s.AsyncCall(&NoArgsVoidReturn::Method);
- }
- class IgnoreResultTestHelperWithNoArgs {
- public:
- explicit IgnoreResultTestHelperWithNoArgs(RunLoop* loop, bool* called)
- : loop_(loop), called_(called) {}
- int ConstMethod() const {
- if (loop_) {
- loop_->Quit();
- }
- if (called_) {
- *called_ = true;
- }
- return 0;
- }
- int Method() {
- if (loop_) {
- loop_->Quit();
- }
- if (called_) {
- *called_ = true;
- }
- return 0;
- }
- private:
- const raw_ptr<RunLoop> loop_ = nullptr;
- const raw_ptr<bool> called_ = nullptr;
- };
- TEST_F(SequenceBoundTest, AsyncCallIgnoreResultNoArgs) {
- {
- RunLoop loop;
- SequenceBound<IgnoreResultTestHelperWithNoArgs> s(task_runner_, &loop,
- nullptr);
- s.AsyncCall(IgnoreResult(&IgnoreResultTestHelperWithNoArgs::ConstMethod));
- loop.Run();
- }
- {
- RunLoop loop;
- SequenceBound<IgnoreResultTestHelperWithNoArgs> s(task_runner_, &loop,
- nullptr);
- s.AsyncCall(IgnoreResult(&IgnoreResultTestHelperWithNoArgs::Method));
- loop.Run();
- }
- }
- TEST_F(SequenceBoundTest, AsyncCallIgnoreResultThen) {
- {
- RunLoop loop;
- bool called = false;
- SequenceBound<IgnoreResultTestHelperWithNoArgs> s(task_runner_, nullptr,
- &called);
- s.AsyncCall(IgnoreResult(&IgnoreResultTestHelperWithNoArgs::ConstMethod))
- .Then(BindLambdaForTesting([&] { loop.Quit(); }));
- loop.Run();
- EXPECT_TRUE(called);
- }
- {
- RunLoop loop;
- bool called = false;
- SequenceBound<IgnoreResultTestHelperWithNoArgs> s(task_runner_, nullptr,
- &called);
- s.AsyncCall(IgnoreResult(&IgnoreResultTestHelperWithNoArgs::Method))
- .Then(BindLambdaForTesting([&] { loop.Quit(); }));
- loop.Run();
- EXPECT_TRUE(called);
- }
- }
- class IgnoreResultTestHelperWithArgs {
- public:
- IgnoreResultTestHelperWithArgs(RunLoop* loop, int& value)
- : loop_(loop), value_(value) {}
- int ConstMethod(int arg) const {
- value_ = arg;
- if (loop_) {
- loop_->Quit();
- }
- return arg;
- }
- int Method(int arg) {
- value_ = arg;
- if (loop_) {
- loop_->Quit();
- }
- return arg;
- }
- private:
- const raw_ptr<RunLoop> loop_ = nullptr;
- int& value_;
- };
- TEST_F(SequenceBoundTest, AsyncCallIgnoreResultWithArgs) {
- {
- RunLoop loop;
- int result = 0;
- SequenceBound<IgnoreResultTestHelperWithArgs> s(task_runner_, &loop,
- std::ref(result));
- s.AsyncCall(IgnoreResult(&IgnoreResultTestHelperWithArgs::ConstMethod))
- .WithArgs(60);
- loop.Run();
- EXPECT_EQ(60, result);
- }
- {
- RunLoop loop;
- int result = 0;
- SequenceBound<IgnoreResultTestHelperWithArgs> s(task_runner_, &loop,
- std::ref(result));
- s.AsyncCall(IgnoreResult(&IgnoreResultTestHelperWithArgs::Method))
- .WithArgs(06);
- loop.Run();
- EXPECT_EQ(06, result);
- }
- }
- TEST_F(SequenceBoundTest, AsyncCallIgnoreResultWithArgsThen) {
- {
- RunLoop loop;
- int result = 0;
- SequenceBound<IgnoreResultTestHelperWithArgs> s(task_runner_, nullptr,
- std::ref(result));
- s.AsyncCall(IgnoreResult(&IgnoreResultTestHelperWithArgs::ConstMethod))
- .WithArgs(60)
- .Then(BindLambdaForTesting([&] { loop.Quit(); }));
- loop.Run();
- EXPECT_EQ(60, result);
- }
- {
- RunLoop loop;
- int result = 0;
- SequenceBound<IgnoreResultTestHelperWithArgs> s(task_runner_, nullptr,
- std::ref(result));
- s.AsyncCall(IgnoreResult(&IgnoreResultTestHelperWithArgs::Method))
- .WithArgs(06)
- .Then(BindLambdaForTesting([&] { loop.Quit(); }));
- loop.Run();
- EXPECT_EQ(06, result);
- }
- }
- // TODO(dcheng): Maybe use the nocompile harness here instead of being
- // "clever"...
- TEST_F(SequenceBoundTest, NoCompileTests) {
- // TODO(dcheng): Test calling WithArgs() on a method that takes no arguments.
- // Given:
- // class C {
- // void F();
- // };
- //
- // Then:
- // SequenceBound<C> s(...);
- // s.AsyncCall(&C::F).WithArgs(...);
- //
- // should not compile.
- //
- // TODO(dcheng): Test calling Then() before calling WithArgs().
- // Given:
- // class C {
- // void F(int);
- // };
- //
- // Then:
- // SequenceBound<C> s(...);
- // s.AsyncCall(&C::F).Then(...).WithArgs(...);
- //
- // should not compile.
- //
- }
- class SequenceBoundDeathTest : public ::testing::Test {
- protected:
- void TearDown() override {
- // Make sure that any objects owned by `SequenceBound` have been destroyed
- // to avoid tripping leak detection.
- RunLoop run_loop;
- task_runner_->PostTask(FROM_HERE, run_loop.QuitClosure());
- run_loop.Run();
- }
- // Death tests use fork(), which can interact (very) poorly with threads.
- test::SingleThreadTaskEnvironment task_environment_;
- scoped_refptr<SequencedTaskRunner> task_runner_ =
- base::SequencedTaskRunnerHandle::Get();
- };
- TEST_F(SequenceBoundDeathTest, AsyncCallIntArgNoWithArgsShouldCheck) {
- SequenceBound<IntArgIntReturn> s(task_runner_);
- EXPECT_DEATH_IF_SUPPORTED(s.AsyncCall(&IntArgIntReturn::Method), "");
- }
- TEST_F(SequenceBoundDeathTest, AsyncCallIntReturnNoThenShouldCheck) {
- {
- SequenceBound<NoArgsIntReturn> s(task_runner_);
- EXPECT_DEATH_IF_SUPPORTED(s.AsyncCall(&NoArgsIntReturn::Method), "");
- }
- {
- SequenceBound<IntArgIntReturn> s(task_runner_);
- EXPECT_DEATH_IF_SUPPORTED(s.AsyncCall(&IntArgIntReturn::Method).WithArgs(0),
- "");
- }
- }
- } // namespace base
|