| Index: base/sequence_checker_impl_unittest.cc
|
| diff --git a/base/sequence_checker_impl_unittest.cc b/base/sequence_checker_impl_unittest.cc
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..39e302003a4b4cc6af788aff49370775243e0f8e
|
| --- /dev/null
|
| +++ b/base/sequence_checker_impl_unittest.cc
|
| @@ -0,0 +1,218 @@
|
| +// Copyright (c) 2012 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/sequence_checker_impl.h"
|
| +
|
| +#include <cstddef>
|
| +
|
| +#include "base/bind.h"
|
| +#include "base/compiler_specific.h"
|
| +#include "base/location.h"
|
| +#include "base/memory/ref_counted.h"
|
| +#include "base/message_loop/message_loop.h"
|
| +#include "base/sequenced_task_runner.h"
|
| +#include "base/threading/thread.h"
|
| +#include "testing/gtest/include/gtest/gtest.h"
|
| +
|
| +namespace base {
|
| +
|
| +namespace {
|
| +
|
| +// Implementation of SequencedTaskRunner that lets us control what
|
| +// RunsTasksOnCurrentThread() returns.
|
| +class FakeTaskRunner : public SequencedTaskRunner {
|
| + public:
|
| + FakeTaskRunner() : runs_tasks_on_current_thread_(false) {}
|
| +
|
| + void SetRunsTasksOnCurrentThread(bool runs_tasks_on_current_thread) {
|
| + runs_tasks_on_current_thread_ = runs_tasks_on_current_thread;
|
| + }
|
| +
|
| + // SequencedTaskRunner implementation.
|
| + virtual bool PostDelayedTask(const tracked_objects::Location& from_here,
|
| + const Closure& task,
|
| + TimeDelta delay) OVERRIDE {
|
| + ADD_FAILURE();
|
| + return false;
|
| + }
|
| +
|
| + virtual bool PostNonNestableDelayedTask(
|
| + const tracked_objects::Location& from_here,
|
| + const Closure& task,
|
| + TimeDelta delay) OVERRIDE {
|
| + ADD_FAILURE();
|
| + return false;
|
| + }
|
| +
|
| + virtual bool RunsTasksOnCurrentThread() const OVERRIDE {
|
| + return runs_tasks_on_current_thread_;
|
| + }
|
| +
|
| + protected:
|
| + virtual ~FakeTaskRunner() {}
|
| +
|
| + private:
|
| + bool runs_tasks_on_current_thread_;
|
| +};
|
| +
|
| +class SequenceCheckerImplTest : public ::testing::Test {
|
| +};
|
| +
|
| +// Create a SequenceCheckerImpl with a SequencedTaskRunner and make
|
| +// sure that CalledOnValidSequence() returns what that SequencedTaskRunner
|
| +// returns for RunsTasksOnCurrentThread().
|
| +TEST_F(SequenceCheckerImplTest, CalledOnValidSequenceNonNull) {
|
| + const scoped_refptr<FakeTaskRunner> fake_sequenced_task_runner(
|
| + new FakeTaskRunner());
|
| +
|
| + const SequenceCheckerImpl sequence_checker_impl(fake_sequenced_task_runner);
|
| + EXPECT_FALSE(sequence_checker_impl.CalledOnValidSequence());
|
| +
|
| + fake_sequenced_task_runner->SetRunsTasksOnCurrentThread(true);
|
| + EXPECT_TRUE(sequence_checker_impl.CalledOnValidSequence());
|
| +
|
| + fake_sequenced_task_runner->SetRunsTasksOnCurrentThread(false);
|
| + EXPECT_FALSE(sequence_checker_impl.CalledOnValidSequence());
|
| +}
|
| +
|
| +void ExpectCalledOnValidSequence(
|
| + const tracked_objects::Location& location,
|
| + const SequenceCheckerImpl* sequence_checker_impl,
|
| + bool expected_value) {
|
| + EXPECT_EQ(expected_value, sequence_checker_impl->CalledOnValidSequence())
|
| + << location.ToString();
|
| +}
|
| +
|
| +// Create a SequenceCheckerImpl with no SequencedTaskRunner and make
|
| +// sure that CalledOnValidSequence() behaves like
|
| +// ThreadChecker::CalledOnValidThread().
|
| +TEST_F(SequenceCheckerImplTest, CalledOnValidSequenceNull) {
|
| + const SequenceCheckerImpl sequence_checker_impl(NULL);
|
| + EXPECT_TRUE(sequence_checker_impl.CalledOnValidSequence());
|
| +
|
| + {
|
| + Thread thread("thread 1");
|
| + ASSERT_TRUE(thread.Start());
|
| + thread.message_loop()->PostTask(
|
| + FROM_HERE, Bind(&ExpectCalledOnValidSequence,
|
| + FROM_HERE,
|
| + Unretained(&sequence_checker_impl),
|
| + false));
|
| + }
|
| +
|
| + EXPECT_TRUE(sequence_checker_impl.CalledOnValidSequence());
|
| +}
|
| +
|
| +// Create a SequenceCheckerImpl with a SequencedTaskRunner and switch
|
| +// it to another one. CalledOnValidSequence() should return what its
|
| +// underlying SequencedTaskRunner returns for
|
| +// RunsTasksOnCurrentThread().
|
| +TEST_F(SequenceCheckerImplTest, ChangeSequenceNonNull) {
|
| + const scoped_refptr<FakeTaskRunner> fake_sequenced_task_runner1(
|
| + new FakeTaskRunner());
|
| +
|
| + const scoped_refptr<FakeTaskRunner> fake_sequenced_task_runner2(
|
| + new FakeTaskRunner());
|
| +
|
| + SequenceCheckerImpl sequence_checker_impl(fake_sequenced_task_runner1);
|
| + EXPECT_FALSE(sequence_checker_impl.CalledOnValidSequence());
|
| +
|
| + fake_sequenced_task_runner2->SetRunsTasksOnCurrentThread(true);
|
| + EXPECT_FALSE(sequence_checker_impl.CalledOnValidSequence());
|
| +
|
| + sequence_checker_impl.ChangeSequence(fake_sequenced_task_runner2);
|
| + EXPECT_TRUE(sequence_checker_impl.CalledOnValidSequence());
|
| +
|
| + sequence_checker_impl.ChangeSequence(fake_sequenced_task_runner1);
|
| + EXPECT_FALSE(sequence_checker_impl.CalledOnValidSequence());
|
| +}
|
| +
|
| +// Create a SequenceCheckerImpl with a SequencedTaskRunner and switch
|
| +// it to a NULL one. CalledOnValidSequence() should then behave like
|
| +// ThreadChecker::CalledOnValidThread().
|
| +TEST_F(SequenceCheckerImplTest, ChangeSequenceNull) {
|
| + const scoped_refptr<FakeTaskRunner> fake_sequenced_task_runner(
|
| + new FakeTaskRunner());
|
| +
|
| + SequenceCheckerImpl sequence_checker_impl(fake_sequenced_task_runner);
|
| + EXPECT_FALSE(sequence_checker_impl.CalledOnValidSequence());
|
| +
|
| + sequence_checker_impl.ChangeSequence(NULL);
|
| + // Binds to current thread.
|
| + EXPECT_TRUE(sequence_checker_impl.CalledOnValidSequence());
|
| + {
|
| + Thread thread("thread 1");
|
| + ASSERT_TRUE(thread.Start());
|
| + thread.message_loop()->PostTask(
|
| + FROM_HERE, Bind(&ExpectCalledOnValidSequence,
|
| + FROM_HERE,
|
| + Unretained(&sequence_checker_impl),
|
| + false));
|
| + }
|
| +
|
| + EXPECT_TRUE(sequence_checker_impl.CalledOnValidSequence());
|
| +
|
| + sequence_checker_impl.ChangeSequence(NULL);
|
| + // Binds to worker thread.
|
| + {
|
| + Thread thread("thread 2");
|
| + ASSERT_TRUE(thread.Start());
|
| + thread.message_loop()->PostTask(
|
| + FROM_HERE, Bind(&ExpectCalledOnValidSequence,
|
| + FROM_HERE,
|
| + Unretained(&sequence_checker_impl),
|
| + true));
|
| + }
|
| + EXPECT_FALSE(sequence_checker_impl.CalledOnValidSequence());
|
| +}
|
| +
|
| +// Create a SequenceCheckerImpl with the current thread's task runner
|
| +// and switch it to other task runners. CalledOnValidSequence() should
|
| +// return true only when it's on the correct thread.
|
| +TEST_F(SequenceCheckerImplTest, MultipleThreads) {
|
| + MessageLoop loop;
|
| +
|
| + SequenceCheckerImpl sequence_checker_impl(loop.message_loop_proxy());
|
| + EXPECT_TRUE(sequence_checker_impl.CalledOnValidSequence());
|
| +
|
| + {
|
| + Thread thread("thread 1");
|
| + ASSERT_TRUE(thread.Start());
|
| + thread.message_loop()->PostTask(
|
| + FROM_HERE, Bind(&ExpectCalledOnValidSequence,
|
| + FROM_HERE,
|
| + Unretained(&sequence_checker_impl),
|
| + false));
|
| + thread.message_loop()->PostTask(
|
| + FROM_HERE, Bind(&SequenceCheckerImpl::ChangeSequence,
|
| + Unretained(&sequence_checker_impl),
|
| + thread.message_loop_proxy()));
|
| + thread.message_loop()->PostTask(
|
| + FROM_HERE, Bind(&ExpectCalledOnValidSequence,
|
| + FROM_HERE,
|
| + Unretained(&sequence_checker_impl),
|
| + true));
|
| + }
|
| +
|
| + EXPECT_FALSE(sequence_checker_impl.CalledOnValidSequence());
|
| +
|
| + sequence_checker_impl.ChangeSequence(loop.message_loop_proxy());
|
| + EXPECT_TRUE(sequence_checker_impl.CalledOnValidSequence());
|
| +
|
| + {
|
| + Thread thread("thread 2");
|
| + ASSERT_TRUE(thread.Start());
|
| + thread.message_loop()->PostTask(
|
| + FROM_HERE, Bind(&ExpectCalledOnValidSequence,
|
| + FROM_HERE,
|
| + Unretained(&sequence_checker_impl),
|
| + false));
|
| + }
|
| +
|
| + EXPECT_TRUE(sequence_checker_impl.CalledOnValidSequence());
|
| +}
|
| +
|
| +} // namespace
|
| +
|
| +} // namespace base
|
|
|