• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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:
ThreadCheckerClass()19   ThreadCheckerClass() {}
20 
21   // Verifies that it was called on the same thread as the constructor.
DoStuff()22   void DoStuff() {
23     CHECK(CalledOnValidThread());
24   }
25 
DetachFromThread()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:
CallDoStuffOnThread(ThreadCheckerClass * thread_checker_class)40   CallDoStuffOnThread(ThreadCheckerClass* thread_checker_class)
41       : SimpleThread("call_do_stuff_on_thread"),
42         thread_checker_class_(thread_checker_class) {
43   }
44 
Run()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:
DeleteThreadCheckerClassOnThread(ThreadCheckerClass * thread_checker_class)58   DeleteThreadCheckerClassOnThread(ThreadCheckerClass* thread_checker_class)
59       : SimpleThread("delete_thread_checker_class_on_thread"),
60         thread_checker_class_(thread_checker_class) {
61   }
62 
Run()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 
TEST(ThreadCheckerTest,CallsAllowedOnSameThread)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 
TEST(ThreadCheckerTest,DestructorAllowedOnDifferentThread)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 
TEST(ThreadCheckerTest,DetachFromThread)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 
MethodOnDifferentThreadImpl()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
TEST(ThreadCheckerDeathTest,MethodNotAllowedOnDifferentThreadInDebug)125 TEST(ThreadCheckerDeathTest, MethodNotAllowedOnDifferentThreadInDebug) {
126   ASSERT_DEBUG_DEATH({
127       ThreadCheckerClass::MethodOnDifferentThreadImpl();
128     }, "");
129 }
130 #else
TEST(ThreadCheckerTest,MethodAllowedOnDifferentThreadInRelease)131 TEST(ThreadCheckerTest, MethodAllowedOnDifferentThreadInRelease) {
132   ThreadCheckerClass::MethodOnDifferentThreadImpl();
133 }
134 #endif  // NDEBUG
135 
DetachThenCallFromDifferentThreadImpl()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
TEST(ThreadCheckerDeathTest,DetachFromThreadInDebug)154 TEST(ThreadCheckerDeathTest, DetachFromThreadInDebug) {
155   ASSERT_DEBUG_DEATH({
156     ThreadCheckerClass::DetachThenCallFromDifferentThreadImpl();
157     }, "");
158 }
159 #else
TEST(ThreadCheckerTest,DetachFromThreadInRelease)160 TEST(ThreadCheckerTest, DetachFromThreadInRelease) {
161   ThreadCheckerClass::DetachThenCallFromDifferentThreadImpl();
162 }
163 #endif  // NDEBUG
164 
165 #endif  // GTEST_HAS_DEATH_TEST || NDEBUG
166 
167 }  // namespace base
168