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/non_thread_safe.h" 9#include "base/threading/simple_thread.h" 10#include "testing/gtest/include/gtest/gtest.h" 11 12namespace base { 13 14// Simple class to exersice the basics of NonThreadSafe. 15// Both the destructor and DoStuff should verify that they were 16// called on the same thread as the constructor. 17class NonThreadSafeClass : public NonThreadSafe { 18 public: 19 NonThreadSafeClass() {} 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 NonThreadSafe::DetachFromThread(); 28 } 29 30 static void MethodOnDifferentThreadImpl(); 31 static void DestructorOnDifferentThreadImpl(); 32 33 private: 34 DISALLOW_COPY_AND_ASSIGN(NonThreadSafeClass); 35}; 36 37// Calls NonThreadSafeClass::DoStuff on another thread. 38class CallDoStuffOnThread : public SimpleThread { 39 public: 40 CallDoStuffOnThread(NonThreadSafeClass* non_thread_safe_class) 41 : SimpleThread("call_do_stuff_on_thread"), 42 non_thread_safe_class_(non_thread_safe_class) { 43 } 44 45 virtual void Run() { 46 non_thread_safe_class_->DoStuff(); 47 } 48 49 private: 50 NonThreadSafeClass* non_thread_safe_class_; 51 52 DISALLOW_COPY_AND_ASSIGN(CallDoStuffOnThread); 53}; 54 55// Deletes NonThreadSafeClass on a different thread. 56class DeleteNonThreadSafeClassOnThread : public SimpleThread { 57 public: 58 DeleteNonThreadSafeClassOnThread(NonThreadSafeClass* non_thread_safe_class) 59 : SimpleThread("delete_non_thread_safe_class_on_thread"), 60 non_thread_safe_class_(non_thread_safe_class) { 61 } 62 63 virtual void Run() { 64 non_thread_safe_class_.reset(); 65 } 66 67 private: 68 scoped_ptr<NonThreadSafeClass> non_thread_safe_class_; 69 70 DISALLOW_COPY_AND_ASSIGN(DeleteNonThreadSafeClassOnThread); 71}; 72 73TEST(NonThreadSafeTest, CallsAllowedOnSameThread) { 74 scoped_ptr<NonThreadSafeClass> non_thread_safe_class( 75 new NonThreadSafeClass); 76 77 // Verify that DoStuff doesn't assert. 78 non_thread_safe_class->DoStuff(); 79 80 // Verify that the destructor doesn't assert. 81 non_thread_safe_class.reset(); 82} 83 84TEST(NonThreadSafeTest, DetachThenDestructOnDifferentThread) { 85 scoped_ptr<NonThreadSafeClass> non_thread_safe_class( 86 new NonThreadSafeClass); 87 88 // Verify that the destructor doesn't assert when called on a different thread 89 // after a detach. 90 non_thread_safe_class->DetachFromThread(); 91 DeleteNonThreadSafeClassOnThread delete_on_thread( 92 non_thread_safe_class.release()); 93 94 delete_on_thread.Start(); 95 delete_on_thread.Join(); 96} 97 98#if GTEST_HAS_DEATH_TEST || NDEBUG 99 100void NonThreadSafeClass::MethodOnDifferentThreadImpl() { 101 scoped_ptr<NonThreadSafeClass> non_thread_safe_class( 102 new NonThreadSafeClass); 103 104 // Verify that DoStuff asserts in debug builds only when called 105 // on a different thread. 106 CallDoStuffOnThread call_on_thread(non_thread_safe_class.get()); 107 108 call_on_thread.Start(); 109 call_on_thread.Join(); 110} 111 112#ifndef NDEBUG 113TEST(NonThreadSafeDeathTest, MethodNotAllowedOnDifferentThreadInDebug) { 114 ASSERT_DEBUG_DEATH({ 115 NonThreadSafeClass::MethodOnDifferentThreadImpl(); 116 }, ""); 117} 118#else 119TEST(NonThreadSafeTest, MethodAllowedOnDifferentThreadInRelease) { 120 NonThreadSafeClass::MethodOnDifferentThreadImpl(); 121} 122#endif // NDEBUG 123 124void NonThreadSafeClass::DestructorOnDifferentThreadImpl() { 125 scoped_ptr<NonThreadSafeClass> non_thread_safe_class( 126 new NonThreadSafeClass); 127 128 // Verify that the destructor asserts in debug builds only 129 // when called on a different thread. 130 DeleteNonThreadSafeClassOnThread delete_on_thread( 131 non_thread_safe_class.release()); 132 133 delete_on_thread.Start(); 134 delete_on_thread.Join(); 135} 136 137#ifndef NDEBUG 138TEST(NonThreadSafeDeathTest, DestructorNotAllowedOnDifferentThreadInDebug) { 139 ASSERT_DEBUG_DEATH({ 140 NonThreadSafeClass::DestructorOnDifferentThreadImpl(); 141 }, ""); 142} 143#else 144TEST(NonThreadSafeTest, DestructorAllowedOnDifferentThreadInRelease) { 145 NonThreadSafeClass::DestructorOnDifferentThreadImpl(); 146} 147#endif // NDEBUG 148 149#endif // GTEST_HAS_DEATH_TEST || NDEBUG 150 151} // namespace base 152