• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  *  Copyright (c) 2014 The WebRTC project authors. All Rights Reserved.
3  *
4  *  Use of this source code is governed by a BSD-style license
5  *  that can be found in the LICENSE file in the root of the source
6  *  tree. An additional intellectual property rights grant can be found
7  *  in the file PATENTS.  All contributing project authors may
8  *  be found in the AUTHORS file in the root of the source tree.
9  */
10 
11 // Borrowed from Chromium's src/base/threading/thread_checker_unittest.cc.
12 
13 #include "testing/gtest/include/gtest/gtest.h"
14 #include "webrtc/base/checks.h"
15 #include "webrtc/base/thread.h"
16 #include "webrtc/base/thread_checker.h"
17 #include "webrtc/base/scoped_ptr.h"
18 #include "webrtc/test/testsupport/gtest_disable.h"
19 
20 // Duplicated from base/threading/thread_checker.h so that we can be
21 // good citizens there and undef the macro.
22 #if !defined(NDEBUG) || defined(DCHECK_ALWAYS_ON)
23 #define ENABLE_THREAD_CHECKER 1
24 #else
25 #define ENABLE_THREAD_CHECKER 0
26 #endif
27 
28 namespace rtc {
29 
30 namespace {
31 
32 // Simple class to exercise the basics of ThreadChecker.
33 // Both the destructor and DoStuff should verify that they were
34 // called on the same thread as the constructor.
35 class ThreadCheckerClass : public ThreadChecker {
36  public:
ThreadCheckerClass()37   ThreadCheckerClass() {}
38 
39   // Verifies that it was called on the same thread as the constructor.
DoStuff()40   void DoStuff() {
41     DCHECK(CalledOnValidThread());
42   }
43 
DetachFromThread()44   void DetachFromThread() {
45     ThreadChecker::DetachFromThread();
46   }
47 
48   static void MethodOnDifferentThreadImpl();
49   static void DetachThenCallFromDifferentThreadImpl();
50 
51  private:
52   DISALLOW_COPY_AND_ASSIGN(ThreadCheckerClass);
53 };
54 
55 // Calls ThreadCheckerClass::DoStuff on another thread.
56 class CallDoStuffOnThread : public Thread {
57  public:
CallDoStuffOnThread(ThreadCheckerClass * thread_checker_class)58   explicit CallDoStuffOnThread(ThreadCheckerClass* thread_checker_class)
59       : Thread(),
60         thread_checker_class_(thread_checker_class) {
61     SetName("call_do_stuff_on_thread", NULL);
62   }
63 
Run()64   virtual void Run() OVERRIDE {
65     thread_checker_class_->DoStuff();
66   }
67 
68   // New method. Needed since Thread::Join is protected, and it is called by
69   // the TEST.
Join()70   void Join() {
71     Thread::Join();
72   }
73 
74  private:
75   ThreadCheckerClass* thread_checker_class_;
76 
77   DISALLOW_COPY_AND_ASSIGN(CallDoStuffOnThread);
78 };
79 
80 // Deletes ThreadCheckerClass on a different thread.
81 class DeleteThreadCheckerClassOnThread : public Thread {
82  public:
DeleteThreadCheckerClassOnThread(ThreadCheckerClass * thread_checker_class)83   explicit DeleteThreadCheckerClassOnThread(
84       ThreadCheckerClass* thread_checker_class)
85       : Thread(),
86         thread_checker_class_(thread_checker_class) {
87     SetName("delete_thread_checker_class_on_thread", NULL);
88   }
89 
Run()90   virtual void Run() OVERRIDE {
91     thread_checker_class_.reset();
92   }
93 
94   // New method. Needed since Thread::Join is protected, and it is called by
95   // the TEST.
Join()96   void Join() {
97     Thread::Join();
98   }
99 
100  private:
101   scoped_ptr<ThreadCheckerClass> thread_checker_class_;
102 
103   DISALLOW_COPY_AND_ASSIGN(DeleteThreadCheckerClassOnThread);
104 };
105 
106 }  // namespace
107 
TEST(ThreadCheckerTest,DISABLED_ON_MAC (CallsAllowedOnSameThread))108 TEST(ThreadCheckerTest, DISABLED_ON_MAC(CallsAllowedOnSameThread)) {
109   scoped_ptr<ThreadCheckerClass> thread_checker_class(
110       new ThreadCheckerClass);
111 
112   // Verify that DoStuff doesn't assert.
113   thread_checker_class->DoStuff();
114 
115   // Verify that the destructor doesn't assert.
116   thread_checker_class.reset();
117 }
118 
TEST(ThreadCheckerTest,DISABLED_ON_MAC (DestructorAllowedOnDifferentThread))119 TEST(ThreadCheckerTest, DISABLED_ON_MAC(DestructorAllowedOnDifferentThread)) {
120   scoped_ptr<ThreadCheckerClass> thread_checker_class(
121       new ThreadCheckerClass);
122 
123   // Verify that the destructor doesn't assert
124   // when called on a different thread.
125   DeleteThreadCheckerClassOnThread delete_on_thread(
126       thread_checker_class.release());
127 
128   delete_on_thread.Start();
129   delete_on_thread.Join();
130 }
131 
TEST(ThreadCheckerTest,DISABLED_ON_MAC (DetachFromThread))132 TEST(ThreadCheckerTest, DISABLED_ON_MAC(DetachFromThread)) {
133   scoped_ptr<ThreadCheckerClass> thread_checker_class(
134       new ThreadCheckerClass);
135 
136   // Verify that DoStuff doesn't assert when called on a different thread after
137   // a call to DetachFromThread.
138   thread_checker_class->DetachFromThread();
139   CallDoStuffOnThread call_on_thread(thread_checker_class.get());
140 
141   call_on_thread.Start();
142   call_on_thread.Join();
143 }
144 
145 #if GTEST_HAS_DEATH_TEST || !ENABLE_THREAD_CHECKER
146 
MethodOnDifferentThreadImpl()147 void ThreadCheckerClass::MethodOnDifferentThreadImpl() {
148   scoped_ptr<ThreadCheckerClass> thread_checker_class(
149       new ThreadCheckerClass);
150 
151   // DoStuff should assert in debug builds only when called on a
152   // different thread.
153   CallDoStuffOnThread call_on_thread(thread_checker_class.get());
154 
155   call_on_thread.Start();
156   call_on_thread.Join();
157 }
158 
159 #if ENABLE_THREAD_CHECKER
TEST(ThreadCheckerDeathTest,DISABLED_MethodNotAllowedOnDifferentThreadInDebug)160 TEST(ThreadCheckerDeathTest,
161      DISABLED_MethodNotAllowedOnDifferentThreadInDebug) {
162   ASSERT_DEATH({
163       ThreadCheckerClass::MethodOnDifferentThreadImpl();
164     }, "");
165 }
166 #else
TEST(ThreadCheckerTest,MethodAllowedOnDifferentThreadInRelease)167 TEST(ThreadCheckerTest, MethodAllowedOnDifferentThreadInRelease) {
168   ThreadCheckerClass::MethodOnDifferentThreadImpl();
169 }
170 #endif  // ENABLE_THREAD_CHECKER
171 
DetachThenCallFromDifferentThreadImpl()172 void ThreadCheckerClass::DetachThenCallFromDifferentThreadImpl() {
173   scoped_ptr<ThreadCheckerClass> thread_checker_class(
174       new ThreadCheckerClass);
175 
176   // DoStuff doesn't assert when called on a different thread
177   // after a call to DetachFromThread.
178   thread_checker_class->DetachFromThread();
179   CallDoStuffOnThread call_on_thread(thread_checker_class.get());
180 
181   call_on_thread.Start();
182   call_on_thread.Join();
183 
184   // DoStuff should assert in debug builds only after moving to
185   // another thread.
186   thread_checker_class->DoStuff();
187 }
188 
189 #if ENABLE_THREAD_CHECKER
TEST(ThreadCheckerDeathTest,DetachFromThreadInDebug)190 TEST(ThreadCheckerDeathTest, DetachFromThreadInDebug) {
191   ASSERT_DEATH({
192     ThreadCheckerClass::DetachThenCallFromDifferentThreadImpl();
193     }, "");
194 }
195 #else
TEST(ThreadCheckerTest,DetachFromThreadInRelease)196 TEST(ThreadCheckerTest, DetachFromThreadInRelease) {
197   ThreadCheckerClass::DetachThenCallFromDifferentThreadImpl();
198 }
199 #endif  // ENABLE_THREAD_CHECKER
200 
201 #endif  // GTEST_HAS_DEATH_TEST || !ENABLE_THREAD_CHECKER
202 
203 // Just in case we ever get lumped together with other compilation units.
204 #undef ENABLE_THREAD_CHECKER
205 
206 }  // namespace rtc
207