Chromium Code Reviews| Index: base/threading/thread_checker_unittest.cc |
| diff --git a/base/threading/thread_checker_unittest.cc b/base/threading/thread_checker_unittest.cc |
| index bc5b1e473a5fdc21ee01496a1e19f3fd66bde7c6..dedf5db07be4898861b884503375e0086c747580 100644 |
| --- a/base/threading/thread_checker_unittest.cc |
| +++ b/base/threading/thread_checker_unittest.cc |
| @@ -2,180 +2,162 @@ |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| -#include "base/threading/thread_checker.h" |
| - |
| #include <memory> |
| -#include "base/logging.h" |
| +#include "base/bind.h" |
| +#include "base/bind_helpers.h" |
| #include "base/macros.h" |
| +#include "base/memory/ref_counted.h" |
| +#include "base/sequence_token.h" |
| +#include "base/test/test_simple_task_runner.h" |
| #include "base/threading/simple_thread.h" |
| +#include "base/threading/thread_checker_impl.h" |
| +#include "base/threading/thread_task_runner_handle.h" |
| #include "testing/gtest/include/gtest/gtest.h" |
| -// Duplicated from base/threading/thread_checker.h so that we can be |
| -// good citizens there and undef the macro. |
| -#if !defined(NDEBUG) || defined(DCHECK_ALWAYS_ON) |
| -#define ENABLE_THREAD_CHECKER 1 |
| -#else |
| -#define ENABLE_THREAD_CHECKER 0 |
| -#endif |
| - |
| namespace base { |
| - |
| namespace { |
| -// Simple class to exercise the basics of ThreadChecker. |
| -// Both the destructor and DoStuff should verify that they were |
| -// called on the same thread as the constructor. |
| -class ThreadCheckerClass : public ThreadChecker { |
| +// Runs a callback on another thread. |
| +class RunCallbackThread : public SimpleThread { |
| public: |
| - ThreadCheckerClass() {} |
| - |
| - // Verifies that it was called on the same thread as the constructor. |
| - void DoStuff() { |
| - DCHECK(CalledOnValidThread()); |
| + explicit RunCallbackThread(const Closure& callback) |
| + : SimpleThread("RunCallbackThread"), callback_(callback) { |
| + Start(); |
| + Join(); |
| } |
| - void DetachFromThread() { |
| - ThreadChecker::DetachFromThread(); |
| - } |
| - |
| - static void MethodOnDifferentThreadImpl(); |
| - static void DetachThenCallFromDifferentThreadImpl(); |
| - |
| private: |
| - DISALLOW_COPY_AND_ASSIGN(ThreadCheckerClass); |
| -}; |
| - |
| -// Calls ThreadCheckerClass::DoStuff on another thread. |
| -class CallDoStuffOnThread : public base::SimpleThread { |
| - public: |
| - explicit CallDoStuffOnThread(ThreadCheckerClass* thread_checker_class) |
| - : SimpleThread("call_do_stuff_on_thread"), |
| - thread_checker_class_(thread_checker_class) { |
| - } |
| + // SimpleThread: |
| + void Run() override { callback_.Run(); } |
| - void Run() override { thread_checker_class_->DoStuff(); } |
| + const Closure callback_; |
| - private: |
| - ThreadCheckerClass* thread_checker_class_; |
| - |
| - DISALLOW_COPY_AND_ASSIGN(CallDoStuffOnThread); |
| + DISALLOW_COPY_AND_ASSIGN(RunCallbackThread); |
| }; |
| -// Deletes ThreadCheckerClass on a different thread. |
| -class DeleteThreadCheckerClassOnThread : public base::SimpleThread { |
| - public: |
| - explicit DeleteThreadCheckerClassOnThread( |
| - ThreadCheckerClass* thread_checker_class) |
| - : SimpleThread("delete_thread_checker_class_on_thread"), |
| - thread_checker_class_(thread_checker_class) { |
| - } |
| - |
| - void Run() override { thread_checker_class_.reset(); } |
| +void ExpectCalledOnValidThread(ThreadCheckerImpl* thread_checker) { |
| + ASSERT_TRUE(thread_checker); |
| - private: |
| - std::unique_ptr<ThreadCheckerClass> thread_checker_class_; |
| + // This should bind |thread_checker| to the current thread if it wasn't |
| + // already bound to a thread. |
| + EXPECT_TRUE(thread_checker->CalledOnValidThread()); |
| - DISALLOW_COPY_AND_ASSIGN(DeleteThreadCheckerClassOnThread); |
| -}; |
| + // Since |thread_checker| is now bound to the current thread, another call to |
| + // CalledOnValidThread() should return true. |
| + EXPECT_TRUE(thread_checker->CalledOnValidThread()); |
| +} |
| -} // namespace |
| +void ExpectNotCalledOnValidThread(ThreadCheckerImpl* thread_checker) { |
| + ASSERT_TRUE(thread_checker); |
| + EXPECT_FALSE(thread_checker->CalledOnValidThread()); |
| +} |
| -TEST(ThreadCheckerTest, CallsAllowedOnSameThread) { |
| - std::unique_ptr<ThreadCheckerClass> thread_checker_class( |
| - new ThreadCheckerClass); |
| +void ExpectNotCalledOnValidThreadWithSequenceTokenAndThreadTaskRunnerHandle( |
| + ThreadCheckerImpl* thread_checker, |
| + internal::SequenceToken sequence_token) { |
| + ThreadTaskRunnerHandle thread_task_runner_handle( |
| + make_scoped_refptr(new TestSimpleTaskRunner)); |
| + internal::ScopedSetCurrentSequenceToken scoped_set_current_sequence_token( |
| + sequence_token); |
| + ExpectNotCalledOnValidThread(thread_checker); |
| +} |
| - // Verify that DoStuff doesn't assert. |
| - thread_checker_class->DoStuff(); |
| +} // namespace |
| - // Verify that the destructor doesn't assert. |
| - thread_checker_class.reset(); |
| +TEST(ThreadCheckerTest, CallsAllowedSameThreadNoSequenceToken) { |
| + ThreadCheckerImpl thread_checker; |
| + EXPECT_TRUE(thread_checker.CalledOnValidThread()); |
| } |
| -TEST(ThreadCheckerTest, DestructorAllowedOnDifferentThread) { |
| - std::unique_ptr<ThreadCheckerClass> thread_checker_class( |
| - new ThreadCheckerClass); |
| +TEST(ThreadCheckerTest, |
| + CallsAllowedSameThreadSameSequenceTokenWithThreadTaskRunnerHandle) { |
| + ThreadTaskRunnerHandle thread_task_runner_handle( |
| + make_scoped_refptr(new TestSimpleTaskRunner)); |
| + internal::ScopedSetCurrentSequenceToken scoped_set_current_sequence_token( |
| + internal::SequenceToken::Create()); |
| + ThreadCheckerImpl thread_checker; |
| + EXPECT_TRUE(thread_checker.CalledOnValidThread()); |
| +} |
| - // Verify that the destructor doesn't assert |
| - // when called on a different thread. |
| - DeleteThreadCheckerClassOnThread delete_on_thread( |
| - thread_checker_class.release()); |
| +TEST(ThreadCheckerTest, |
| + CallsDisallowedSameThreadSameSequenceTokenNoThreadTaskRunnerHandle) { |
| + internal::ScopedSetCurrentSequenceToken scoped_set_current_sequence_token( |
| + internal::SequenceToken::Create()); |
| + ThreadCheckerImpl thread_checker; |
| + EXPECT_FALSE(thread_checker.CalledOnValidThread()); |
| +} |
| - delete_on_thread.Start(); |
| - delete_on_thread.Join(); |
| +TEST(ThreadCheckerTest, CallsDisallowedOnDifferentThreadsNoSequenceToken) { |
| + ThreadCheckerImpl thread_checker; |
| + RunCallbackThread thread( |
| + Bind(&ExpectNotCalledOnValidThread, Unretained(&thread_checker))); |
| } |
| -TEST(ThreadCheckerTest, DetachFromThread) { |
| - std::unique_ptr<ThreadCheckerClass> thread_checker_class( |
| - new ThreadCheckerClass); |
| +TEST(ThreadCheckerTest, CallsDisallowedOnDifferentThreadsSameSequenceToken) { |
| + ThreadTaskRunnerHandle thread_task_runner_handle( |
| + make_scoped_refptr(new TestSimpleTaskRunner)); |
| + const internal::SequenceToken sequence_token( |
| + internal::SequenceToken::Create()); |
| - // Verify that DoStuff doesn't assert when called on a different thread after |
| - // a call to DetachFromThread. |
| - thread_checker_class->DetachFromThread(); |
| - CallDoStuffOnThread call_on_thread(thread_checker_class.get()); |
| + internal::ScopedSetCurrentSequenceToken scoped_set_current_sequence_token( |
| + sequence_token); |
| + ThreadCheckerImpl thread_checker; |
|
gab
2016/07/21 21:14:24
EXPECT_TRUE on this thread to drive essence of tes
fdoray
2016/07/25 13:24:28
Done.
|
| - call_on_thread.Start(); |
| - call_on_thread.Join(); |
| + RunCallbackThread thread(Bind( |
| + &ExpectNotCalledOnValidThreadWithSequenceTokenAndThreadTaskRunnerHandle, |
| + Unretained(&thread_checker), sequence_token)); |
| } |
| -#if GTEST_HAS_DEATH_TEST || !ENABLE_THREAD_CHECKER |
| +TEST(ThreadCheckerTest, CallsDisallowedSameThreadDifferentSequenceToken) { |
| + std::unique_ptr<ThreadCheckerImpl> thread_checker; |
| -void ThreadCheckerClass::MethodOnDifferentThreadImpl() { |
| - std::unique_ptr<ThreadCheckerClass> thread_checker_class( |
| - new ThreadCheckerClass); |
| + ThreadTaskRunnerHandle thread_task_runner_handle( |
| + make_scoped_refptr(new TestSimpleTaskRunner)); |
| - // DoStuff should assert in debug builds only when called on a |
| - // different thread. |
| - CallDoStuffOnThread call_on_thread(thread_checker_class.get()); |
| + { |
| + internal::ScopedSetCurrentSequenceToken scoped_set_current_sequence_token( |
| + internal::SequenceToken::Create()); |
| + thread_checker.reset(new ThreadCheckerImpl); |
| + } |
| - call_on_thread.Start(); |
| - call_on_thread.Join(); |
| -} |
| + { |
| + // Different SequenceToken. |
| + internal::ScopedSetCurrentSequenceToken scoped_set_current_sequence_token( |
| + internal::SequenceToken::Create()); |
| + EXPECT_FALSE(thread_checker->CalledOnValidThread()); |
| + } |
| -#if ENABLE_THREAD_CHECKER |
| -TEST(ThreadCheckerDeathTest, MethodNotAllowedOnDifferentThreadInDebug) { |
| - ASSERT_DEATH({ |
| - ThreadCheckerClass::MethodOnDifferentThreadImpl(); |
| - }, ""); |
| + // No SequenceToken. |
| + EXPECT_FALSE(thread_checker->CalledOnValidThread()); |
| } |
| -#else |
| -TEST(ThreadCheckerTest, MethodAllowedOnDifferentThreadInRelease) { |
| - ThreadCheckerClass::MethodOnDifferentThreadImpl(); |
| -} |
| -#endif // ENABLE_THREAD_CHECKER |
| - |
| -void ThreadCheckerClass::DetachThenCallFromDifferentThreadImpl() { |
| - std::unique_ptr<ThreadCheckerClass> thread_checker_class( |
| - new ThreadCheckerClass); |
| - // DoStuff doesn't assert when called on a different thread |
| - // after a call to DetachFromThread. |
| - thread_checker_class->DetachFromThread(); |
| - CallDoStuffOnThread call_on_thread(thread_checker_class.get()); |
| +TEST(ThreadCheckerTest, DetachFromThread) { |
| + ThreadCheckerImpl thread_checker; |
| + thread_checker.DetachFromThread(); |
| - call_on_thread.Start(); |
| - call_on_thread.Join(); |
| + // Verify that CalledOnValidThread() returns true when called on a different |
| + // thread after a call to DetachFromThread(). |
| + RunCallbackThread thread( |
| + Bind(&ExpectCalledOnValidThread, Unretained(&thread_checker))); |
| - // DoStuff should assert in debug builds only after moving to |
| - // another thread. |
| - thread_checker_class->DoStuff(); |
| + EXPECT_FALSE(thread_checker.CalledOnValidThread()); |
| } |
| -#if ENABLE_THREAD_CHECKER |
| -TEST(ThreadCheckerDeathTest, DetachFromThreadInDebug) { |
| - ASSERT_DEATH({ |
| - ThreadCheckerClass::DetachThenCallFromDifferentThreadImpl(); |
| - }, ""); |
| -} |
| -#else |
| -TEST(ThreadCheckerTest, DetachFromThreadInRelease) { |
| - ThreadCheckerClass::DetachThenCallFromDifferentThreadImpl(); |
| -} |
| -#endif // ENABLE_THREAD_CHECKER |
| +TEST(ThreadCheckerTest, DetachFromThreadWithSequenceToken) { |
| + ThreadTaskRunnerHandle thread_task_runner_handle( |
| + make_scoped_refptr(new TestSimpleTaskRunner)); |
| + internal::ScopedSetCurrentSequenceToken scoped_set_current_sequence_token( |
| + internal::SequenceToken::Create()); |
| + ThreadCheckerImpl thread_checker; |
| + thread_checker.DetachFromThread(); |
| -#endif // GTEST_HAS_DEATH_TEST || !ENABLE_THREAD_CHECKER |
| + // Verify that CalledOnValidThread() returns true when called on a different |
| + // thread after a call to DetachFromThread(). |
| + RunCallbackThread thread( |
| + Bind(&ExpectCalledOnValidThread, Unretained(&thread_checker))); |
| -// Just in case we ever get lumped together with other compilation units. |
| -#undef ENABLE_THREAD_CHECKER |
| + EXPECT_FALSE(thread_checker.CalledOnValidThread()); |
| +} |
| } // namespace base |