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..4e601b074236e883ade2c940bed98a3e8d032d09 |
--- /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.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 |