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