blob: 87e69c035a0a9a66a8abd8e8880a865db405f93c [file] [log] [blame]
henrik.lundin@webrtc.org1e3c5c22014-06-16 11:34:44 +00001/*
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
henrik.lundin@webrtc.org1e3c5c22014-06-16 11:34:44 +000013#include "testing/gtest/include/gtest/gtest.h"
henrik.lundin@webrtc.org18617cf2014-09-15 11:19:35 +000014#include "webrtc/base/checks.h"
henrik.lundin@webrtc.org1e3c5c22014-06-16 11:34:44 +000015#include "webrtc/base/thread.h"
16#include "webrtc/base/thread_checker.h"
17#include "webrtc/base/scoped_ptr.h"
18
19// Duplicated from base/threading/thread_checker.h so that we can be
20// good citizens there and undef the macro.
21#if !defined(NDEBUG) || defined(DCHECK_ALWAYS_ON)
22#define ENABLE_THREAD_CHECKER 1
23#else
24#define ENABLE_THREAD_CHECKER 0
25#endif
26
27namespace rtc {
28
29namespace {
30
31// Simple class to exercise the basics of ThreadChecker.
32// Both the destructor and DoStuff should verify that they were
33// called on the same thread as the constructor.
34class ThreadCheckerClass : public ThreadChecker {
35 public:
36 ThreadCheckerClass() {}
37
38 // Verifies that it was called on the same thread as the constructor.
39 void DoStuff() {
henrik.lundin@webrtc.org18617cf2014-09-15 11:19:35 +000040 DCHECK(CalledOnValidThread());
henrik.lundin@webrtc.org1e3c5c22014-06-16 11:34:44 +000041 }
42
43 void DetachFromThread() {
44 ThreadChecker::DetachFromThread();
45 }
46
47 static void MethodOnDifferentThreadImpl();
48 static void DetachThenCallFromDifferentThreadImpl();
49
50 private:
51 DISALLOW_COPY_AND_ASSIGN(ThreadCheckerClass);
52};
53
54// Calls ThreadCheckerClass::DoStuff on another thread.
55class CallDoStuffOnThread : public Thread {
56 public:
57 explicit CallDoStuffOnThread(ThreadCheckerClass* thread_checker_class)
58 : Thread(),
59 thread_checker_class_(thread_checker_class) {
60 SetName("call_do_stuff_on_thread", NULL);
61 }
62
63 virtual void Run() OVERRIDE {
64 thread_checker_class_->DoStuff();
65 }
66
67 // New method. Needed since Thread::Join is protected, and it is called by
68 // the TEST.
69 void Join() {
70 Thread::Join();
71 }
72
73 private:
74 ThreadCheckerClass* thread_checker_class_;
75
76 DISALLOW_COPY_AND_ASSIGN(CallDoStuffOnThread);
77};
78
79// Deletes ThreadCheckerClass on a different thread.
80class DeleteThreadCheckerClassOnThread : public Thread {
81 public:
82 explicit DeleteThreadCheckerClassOnThread(
83 ThreadCheckerClass* thread_checker_class)
84 : Thread(),
85 thread_checker_class_(thread_checker_class) {
86 SetName("delete_thread_checker_class_on_thread", NULL);
87 }
88
89 virtual void Run() OVERRIDE {
90 thread_checker_class_.reset();
91 }
92
93 // New method. Needed since Thread::Join is protected, and it is called by
94 // the TEST.
95 void Join() {
96 Thread::Join();
97 }
98
99 private:
100 scoped_ptr<ThreadCheckerClass> thread_checker_class_;
101
102 DISALLOW_COPY_AND_ASSIGN(DeleteThreadCheckerClassOnThread);
103};
104
105} // namespace
106
107TEST(ThreadCheckerTest, CallsAllowedOnSameThread) {
108 scoped_ptr<ThreadCheckerClass> thread_checker_class(
109 new ThreadCheckerClass);
110
111 // Verify that DoStuff doesn't assert.
112 thread_checker_class->DoStuff();
113
114 // Verify that the destructor doesn't assert.
115 thread_checker_class.reset();
116}
117
118TEST(ThreadCheckerTest, DestructorAllowedOnDifferentThread) {
119 scoped_ptr<ThreadCheckerClass> thread_checker_class(
120 new ThreadCheckerClass);
121
122 // Verify that the destructor doesn't assert
123 // when called on a different thread.
124 DeleteThreadCheckerClassOnThread delete_on_thread(
125 thread_checker_class.release());
126
127 delete_on_thread.Start();
128 delete_on_thread.Join();
129}
130
131TEST(ThreadCheckerTest, DetachFromThread) {
132 scoped_ptr<ThreadCheckerClass> thread_checker_class(
133 new ThreadCheckerClass);
134
135 // Verify that DoStuff doesn't assert when called on a different thread after
136 // a call to DetachFromThread.
137 thread_checker_class->DetachFromThread();
138 CallDoStuffOnThread call_on_thread(thread_checker_class.get());
139
140 call_on_thread.Start();
141 call_on_thread.Join();
142}
143
144#if GTEST_HAS_DEATH_TEST || !ENABLE_THREAD_CHECKER
145
146void ThreadCheckerClass::MethodOnDifferentThreadImpl() {
147 scoped_ptr<ThreadCheckerClass> thread_checker_class(
148 new ThreadCheckerClass);
149
150 // DoStuff should assert in debug builds only when called on a
151 // different thread.
152 CallDoStuffOnThread call_on_thread(thread_checker_class.get());
153
154 call_on_thread.Start();
155 call_on_thread.Join();
156}
157
158#if ENABLE_THREAD_CHECKER
henrike@webrtc.org78b2d562014-09-12 15:57:08 +0000159TEST(ThreadCheckerDeathTest,
160 DISABLED_MethodNotAllowedOnDifferentThreadInDebug) {
henrik.lundin@webrtc.org1e3c5c22014-06-16 11:34:44 +0000161 ASSERT_DEATH({
162 ThreadCheckerClass::MethodOnDifferentThreadImpl();
163 }, "");
164}
165#else
166TEST(ThreadCheckerTest, MethodAllowedOnDifferentThreadInRelease) {
167 ThreadCheckerClass::MethodOnDifferentThreadImpl();
168}
169#endif // ENABLE_THREAD_CHECKER
170
171void ThreadCheckerClass::DetachThenCallFromDifferentThreadImpl() {
172 scoped_ptr<ThreadCheckerClass> thread_checker_class(
173 new ThreadCheckerClass);
174
175 // DoStuff doesn't assert when called on a different thread
176 // after a call to DetachFromThread.
177 thread_checker_class->DetachFromThread();
178 CallDoStuffOnThread call_on_thread(thread_checker_class.get());
179
180 call_on_thread.Start();
181 call_on_thread.Join();
182
183 // DoStuff should assert in debug builds only after moving to
184 // another thread.
185 thread_checker_class->DoStuff();
186}
187
188#if ENABLE_THREAD_CHECKER
189TEST(ThreadCheckerDeathTest, DetachFromThreadInDebug) {
190 ASSERT_DEATH({
191 ThreadCheckerClass::DetachThenCallFromDifferentThreadImpl();
192 }, "");
193}
194#else
195TEST(ThreadCheckerTest, DetachFromThreadInRelease) {
196 ThreadCheckerClass::DetachThenCallFromDifferentThreadImpl();
197}
198#endif // ENABLE_THREAD_CHECKER
199
200#endif // GTEST_HAS_DEATH_TEST || !ENABLE_THREAD_CHECKER
201
202// Just in case we ever get lumped together with other compilation units.
203#undef ENABLE_THREAD_CHECKER
204
205} // namespace rtc