| Index: media/base/bind_to_current_loop_unittest.cc
|
| diff --git a/media/base/bind_to_current_loop_unittest.cc b/media/base/bind_to_current_loop_unittest.cc
|
| index 23030856675d69052dc3f37aab8eacd08c8614b1..4f69455150fbcbaa5209882c0da9fb0c3047b9df 100644
|
| --- a/media/base/bind_to_current_loop_unittest.cc
|
| +++ b/media/base/bind_to_current_loop_unittest.cc
|
| @@ -4,8 +4,12 @@
|
|
|
| #include "media/base/bind_to_current_loop.h"
|
|
|
| +#include "base/barrier_closure.h"
|
| #include "base/message_loop/message_loop.h"
|
| +#include "base/run_loop.h"
|
| #include "base/synchronization/waitable_event.h"
|
| +#include "base/thread_task_runner_handle.h"
|
| +#include "base/threading/thread.h"
|
| #include "testing/gtest/include/gtest/gtest.h"
|
|
|
| namespace media {
|
| @@ -165,4 +169,124 @@ TEST_F(BindToCurrentLoopTest, Integers) {
|
| EXPECT_EQ(b, -1);
|
| }
|
|
|
| +namespace {
|
| +
|
| +void ExpectRunOn(scoped_refptr<base::SingleThreadTaskRunner> loop,
|
| + const base::Closure& done_closure) {
|
| + EXPECT_TRUE(loop->BelongsToCurrentThread());
|
| + done_closure.Run();
|
| +}
|
| +
|
| +} // namespace
|
| +
|
| +TEST_F(BindToCurrentLoopTest, CalledOnOriginalThread) {
|
| + scoped_refptr<base::SingleThreadTaskRunner> origin_loop =
|
| + base::ThreadTaskRunnerHandle::Get();
|
| + ASSERT_TRUE(origin_loop->BelongsToCurrentThread());
|
| +
|
| + base::Thread thread("Other thread");
|
| + ASSERT_TRUE(thread.Start());
|
| + scoped_refptr<base::SingleThreadTaskRunner> thread_loop =
|
| + thread.task_runner();
|
| + ASSERT_FALSE(thread_loop->BelongsToCurrentThread());
|
| +
|
| + base::RunLoop run_loop;
|
| + base::Closure barrier_closure =
|
| + base::BarrierClosure(2, BindToCurrentLoop(run_loop.QuitClosure()));
|
| +
|
| + base::Closure thread_cb = base::Bind(
|
| + &ExpectRunOn, thread_loop, barrier_closure);
|
| + base::Closure origin_cb = BindToCurrentLoop(base::Bind(
|
| + &ExpectRunOn, origin_loop, barrier_closure));
|
| +
|
| + thread_loop->PostTask(FROM_HERE, thread_cb);
|
| + thread_loop->PostTask(FROM_HERE, origin_cb);
|
| +
|
| + run_loop.Run();
|
| +
|
| + thread.Stop();
|
| +}
|
| +
|
| +namespace {
|
| +
|
| +class ExpectDeletedOnOrigin {
|
| + public:
|
| + ExpectDeletedOnOrigin(
|
| + scoped_refptr<base::SingleThreadTaskRunner> origin_loop,
|
| + const base::Closure& deleted_closure)
|
| + : origin_loop_(origin_loop),
|
| + deleted_closure_(deleted_closure) {}
|
| +
|
| + ~ExpectDeletedOnOrigin() {
|
| + EXPECT_TRUE(origin_loop_->BelongsToCurrentThread());
|
| + deleted_closure_.Run();
|
| + }
|
| +
|
| + scoped_refptr<base::SingleThreadTaskRunner> origin_loop_;
|
| + base::Closure deleted_closure_;
|
| +};
|
| +
|
| +class RefCountedExpectDeletedOnOrigin
|
| + : public ExpectDeletedOnOrigin,
|
| + public base::RefCountedThreadSafe<RefCountedExpectDeletedOnOrigin> {
|
| + public:
|
| + RefCountedExpectDeletedOnOrigin(
|
| + scoped_refptr<base::SingleThreadTaskRunner> origin_loop,
|
| + const base::Closure& deleted_closure)
|
| + : ExpectDeletedOnOrigin(origin_loop, deleted_closure) {}
|
| +
|
| + private:
|
| + friend class base::RefCountedThreadSafe<RefCountedExpectDeletedOnOrigin>;
|
| + ~RefCountedExpectDeletedOnOrigin() {}
|
| +};
|
| +
|
| +void CallbackWithParamsToDelete(
|
| + ExpectDeletedOnOrigin* unused_owned,
|
| + scoped_ptr<ExpectDeletedOnOrigin> unused_passed,
|
| + scoped_refptr<RefCountedExpectDeletedOnOrigin> unused_ref_counted) {}
|
| +
|
| +} // namespace
|
| +
|
| +TEST_F(BindToCurrentLoopTest, CallbackDeletedOnOriginalThread) {
|
| + scoped_refptr<base::SingleThreadTaskRunner> origin_loop =
|
| + base::ThreadTaskRunnerHandle::Get();
|
| +
|
| + base::Thread thread("Other thread");
|
| + ASSERT_TRUE(thread.Start());
|
| + scoped_refptr<base::SingleThreadTaskRunner> thread_loop =
|
| + thread.task_runner();
|
| +
|
| + base::RunLoop run_loop;
|
| + base::Closure barrier_closure =
|
| + base::BarrierClosure(3, BindToCurrentLoop(run_loop.QuitClosure()));
|
| +
|
| + base::Closure* origin_cb_ptr;
|
| + {
|
| + ExpectDeletedOnOrigin* new_delete_on_origin =
|
| + new ExpectDeletedOnOrigin(origin_loop, barrier_closure);
|
| + scoped_ptr<ExpectDeletedOnOrigin> scoped_delete_on_origin(
|
| + new ExpectDeletedOnOrigin(origin_loop, barrier_closure));
|
| + scoped_refptr<RefCountedExpectDeletedOnOrigin> counted_delete_on_origin =
|
| + new RefCountedExpectDeletedOnOrigin(origin_loop, barrier_closure);
|
| + origin_cb_ptr = new base::Closure(BindToCurrentLoop(base::Bind(
|
| + &CallbackWithParamsToDelete,
|
| + base::Owned(new_delete_on_origin),
|
| + base::Passed(&scoped_delete_on_origin),
|
| + counted_delete_on_origin)));
|
| + }
|
| +
|
| + // Delete the callback returned by BindToCurrentLoop on the other thread. This
|
| + // must cause the wrapped callback that was passed in to BindToCurrentLoop to
|
| + // be deleted on the origin thread (where BindToCurrentLoop was invoked), and
|
| + // hence the parameters of that wrapped callback must also be deleted on the
|
| + // origin thread.
|
| + thread_loop->DeleteSoon(FROM_HERE, origin_cb_ptr);
|
| +
|
| + // If this test times out, that means one of the ExpectDeletedOnOrigin or
|
| + // RefCountedExpectDeletedOnOrigin objects failed to be deleted (bad).
|
| + run_loop.Run();
|
| +
|
| + thread.Stop();
|
| +}
|
| +
|
| } // namespace media
|
|
|