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 12namespace 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. 17class 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. 38class 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. 56class 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 73TEST(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 84TEST(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 97TEST(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 112void 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 125TEST(ThreadCheckerDeathTest, MethodNotAllowedOnDifferentThreadInDebug) { 126 ASSERT_DEBUG_DEATH({ 127 ThreadCheckerClass::MethodOnDifferentThreadImpl(); 128 }, ""); 129} 130#else 131TEST(ThreadCheckerTest, MethodAllowedOnDifferentThreadInRelease) { 132 ThreadCheckerClass::MethodOnDifferentThreadImpl(); 133} 134#endif // NDEBUG 135 136void 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 154TEST(ThreadCheckerDeathTest, DetachFromThreadInDebug) { 155 ASSERT_DEBUG_DEATH({ 156 ThreadCheckerClass::DetachThenCallFromDifferentThreadImpl(); 157 }, ""); 158} 159#else 160TEST(ThreadCheckerTest, DetachFromThreadInRelease) { 161 ThreadCheckerClass::DetachThenCallFromDifferentThreadImpl(); 162} 163#endif // NDEBUG 164 165#endif // GTEST_HAS_DEATH_TEST || NDEBUG 166 167} // namespace base 168