1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #include "base/basictypes.h" 6 #include "base/logging.h" 7 #include "base/memory/scoped_ptr.h" 8 #include "base/threading/thread_checker.h" 9 #include "base/threading/simple_thread.h" 10 #include "testing/gtest/include/gtest/gtest.h" 11 12 namespace base { 13 14 // Simple class to exercise the basics of ThreadChecker. 15 // Both the destructor and DoStuff should verify that they were 16 // called on the same thread as the constructor. 17 class ThreadCheckerClass : public ThreadChecker { 18 public: 19 ThreadCheckerClass() {} 20 21 // Verifies that it was called on the same thread as the constructor. 22 void DoStuff() { 23 CHECK(CalledOnValidThread()); 24 } 25 26 void DetachFromThread() { 27 ThreadChecker::DetachFromThread(); 28 } 29 30 static void MethodOnDifferentThreadImpl(); 31 static void DetachThenCallFromDifferentThreadImpl(); 32 33 private: 34 DISALLOW_COPY_AND_ASSIGN(ThreadCheckerClass); 35 }; 36 37 // Calls ThreadCheckerClass::DoStuff on another thread. 38 class CallDoStuffOnThread : public base::SimpleThread { 39 public: 40 CallDoStuffOnThread(ThreadCheckerClass* thread_checker_class) 41 : SimpleThread("call_do_stuff_on_thread"), 42 thread_checker_class_(thread_checker_class) { 43 } 44 45 virtual void Run() { 46 thread_checker_class_->DoStuff(); 47 } 48 49 private: 50 ThreadCheckerClass* thread_checker_class_; 51 52 DISALLOW_COPY_AND_ASSIGN(CallDoStuffOnThread); 53 }; 54 55 // Deletes ThreadCheckerClass on a different thread. 56 class DeleteThreadCheckerClassOnThread : public base::SimpleThread { 57 public: 58 DeleteThreadCheckerClassOnThread(ThreadCheckerClass* thread_checker_class) 59 : SimpleThread("delete_thread_checker_class_on_thread"), 60 thread_checker_class_(thread_checker_class) { 61 } 62 63 virtual void Run() { 64 thread_checker_class_.reset(); 65 } 66 67 private: 68 scoped_ptr<ThreadCheckerClass> thread_checker_class_; 69 70 DISALLOW_COPY_AND_ASSIGN(DeleteThreadCheckerClassOnThread); 71 }; 72 73 TEST(ThreadCheckerTest, CallsAllowedOnSameThread) { 74 scoped_ptr<ThreadCheckerClass> thread_checker_class( 75 new ThreadCheckerClass); 76 77 // Verify that DoStuff doesn't assert. 78 thread_checker_class->DoStuff(); 79 80 // Verify that the destructor doesn't assert. 81 thread_checker_class.reset(); 82 } 83 84 TEST(ThreadCheckerTest, DestructorAllowedOnDifferentThread) { 85 scoped_ptr<ThreadCheckerClass> thread_checker_class( 86 new ThreadCheckerClass); 87 88 // Verify that the destructor doesn't assert 89 // when called on a different thread. 90 DeleteThreadCheckerClassOnThread delete_on_thread( 91 thread_checker_class.release()); 92 93 delete_on_thread.Start(); 94 delete_on_thread.Join(); 95 } 96 97 TEST(ThreadCheckerTest, DetachFromThread) { 98 scoped_ptr<ThreadCheckerClass> thread_checker_class( 99 new ThreadCheckerClass); 100 101 // Verify that DoStuff doesn't assert when called on a different thread after 102 // a call to DetachFromThread. 103 thread_checker_class->DetachFromThread(); 104 CallDoStuffOnThread call_on_thread(thread_checker_class.get()); 105 106 call_on_thread.Start(); 107 call_on_thread.Join(); 108 } 109 110 #if GTEST_HAS_DEATH_TEST || NDEBUG 111 112 void ThreadCheckerClass::MethodOnDifferentThreadImpl() { 113 scoped_ptr<ThreadCheckerClass> thread_checker_class( 114 new ThreadCheckerClass); 115 116 // DoStuff should assert in debug builds only when called on a 117 // different thread. 118 CallDoStuffOnThread call_on_thread(thread_checker_class.get()); 119 120 call_on_thread.Start(); 121 call_on_thread.Join(); 122 } 123 124 #ifndef NDEBUG 125 TEST(ThreadCheckerDeathTest, MethodNotAllowedOnDifferentThreadInDebug) { 126 ASSERT_DEBUG_DEATH({ 127 ThreadCheckerClass::MethodOnDifferentThreadImpl(); 128 }, ""); 129 } 130 #else 131 TEST(ThreadCheckerTest, MethodAllowedOnDifferentThreadInRelease) { 132 ThreadCheckerClass::MethodOnDifferentThreadImpl(); 133 } 134 #endif // NDEBUG 135 136 void ThreadCheckerClass::DetachThenCallFromDifferentThreadImpl() { 137 scoped_ptr<ThreadCheckerClass> thread_checker_class( 138 new ThreadCheckerClass); 139 140 // DoStuff doesn't assert when called on a different thread 141 // after a call to DetachFromThread. 142 thread_checker_class->DetachFromThread(); 143 CallDoStuffOnThread call_on_thread(thread_checker_class.get()); 144 145 call_on_thread.Start(); 146 call_on_thread.Join(); 147 148 // DoStuff should assert in debug builds only after moving to 149 // another thread. 150 thread_checker_class->DoStuff(); 151 } 152 153 #ifndef NDEBUG 154 TEST(ThreadCheckerDeathTest, DetachFromThreadInDebug) { 155 ASSERT_DEBUG_DEATH({ 156 ThreadCheckerClass::DetachThenCallFromDifferentThreadImpl(); 157 }, ""); 158 } 159 #else 160 TEST(ThreadCheckerTest, DetachFromThreadInRelease) { 161 ThreadCheckerClass::DetachThenCallFromDifferentThreadImpl(); 162 } 163 #endif // NDEBUG 164 165 #endif // GTEST_HAS_DEATH_TEST || NDEBUG 166 167 } // namespace base 168