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
12 namespace 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.
17 class NonThreadSafeClass : public NonThreadSafe {
18 public:
NonThreadSafeClass()19 NonThreadSafeClass() {}
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 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.
38 class CallDoStuffOnThread : public SimpleThread {
39 public:
CallDoStuffOnThread(NonThreadSafeClass * non_thread_safe_class)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
Run()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.
56 class DeleteNonThreadSafeClassOnThread : public SimpleThread {
57 public:
DeleteNonThreadSafeClassOnThread(NonThreadSafeClass * non_thread_safe_class)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
Run()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
TEST(NonThreadSafeTest,CallsAllowedOnSameThread)73 TEST(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
TEST(NonThreadSafeTest,DetachThenDestructOnDifferentThread)84 TEST(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
MethodOnDifferentThreadImpl()100 void 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
TEST(NonThreadSafeDeathTest,MethodNotAllowedOnDifferentThreadInDebug)113 TEST(NonThreadSafeDeathTest, MethodNotAllowedOnDifferentThreadInDebug) {
114 ASSERT_DEBUG_DEATH({
115 NonThreadSafeClass::MethodOnDifferentThreadImpl();
116 }, "");
117 }
118 #else
TEST(NonThreadSafeTest,MethodAllowedOnDifferentThreadInRelease)119 TEST(NonThreadSafeTest, MethodAllowedOnDifferentThreadInRelease) {
120 NonThreadSafeClass::MethodOnDifferentThreadImpl();
121 }
122 #endif // NDEBUG
123
DestructorOnDifferentThreadImpl()124 void 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
TEST(NonThreadSafeDeathTest,DestructorNotAllowedOnDifferentThreadInDebug)138 TEST(NonThreadSafeDeathTest, DestructorNotAllowedOnDifferentThreadInDebug) {
139 ASSERT_DEBUG_DEATH({
140 NonThreadSafeClass::DestructorOnDifferentThreadImpl();
141 }, "");
142 }
143 #else
TEST(NonThreadSafeTest,DestructorAllowedOnDifferentThreadInRelease)144 TEST(NonThreadSafeTest, DestructorAllowedOnDifferentThreadInRelease) {
145 NonThreadSafeClass::DestructorOnDifferentThreadImpl();
146 }
147 #endif // NDEBUG
148
149 #endif // GTEST_HAS_DEATH_TEST || NDEBUG
150
151 } // namespace base
152