OLD | NEW |
---|---|
1 // Copyright 2014 The Chromium Authors. All rights reserved. | 1 // Copyright 2014 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #ifndef REMOTING_HOST_MOCK_CALLBACK_H_ | 5 #ifndef REMOTING_HOST_MOCK_CALLBACK_H_ |
6 #define REMOTING_HOST_MOCK_CALLBACK_H_ | 6 #define REMOTING_HOST_MOCK_CALLBACK_H_ |
7 | 7 |
8 // TODO(lukasza): If possible, move this header file to base/mock_callback.h | 8 // TODO(lukasza): If possible, move this header file to base/mock_callback.h |
9 | 9 |
10 #include "base/bind.h" | 10 #include "base/bind.h" |
11 #include "base/bind_helpers.h" | 11 #include "base/bind_helpers.h" |
12 #include "base/callback.h" | 12 #include "base/callback.h" |
13 #include "base/memory/ref_counted.h" | |
14 #include "base/synchronization/lock.h" | |
13 | 15 |
14 #include "testing/gmock/include/gmock/gmock.h" | 16 #include "testing/gmock/include/gmock/gmock.h" |
15 | 17 |
16 namespace remoting { | 18 namespace remoting { |
17 | 19 |
20 // MockCallback<Sig> can be used to mock Callback<Sig> from base/callback.h | |
21 // | |
22 // Basic usage example: | |
23 // | |
24 // MockCallback<void(int)> mock_callback; | |
25 // EXPECT_CALL(mock_callback, Run(123)).Times(2); | |
26 // base::Callback<void(int)> callback = mock_callback.GetCallback(); | |
Wez
2014/12/03 19:45:49
Is it important that GetCallback() is only called
Łukasz Anforowicz
2014/12/03 22:00:44
Sort of. EXPECT_CALL is not thread-safe wrt Callb
| |
27 // | |
28 // // Use |callback| in the remainder of the test. | |
29 // // GMock will enforce the expectations from above. | |
30 // | |
31 // HasRemainingCallbacks usage example: | |
Wez
2014/12/03 19:45:49
HasRemainingCallbacks has not been introduced yet,
Łukasz Anforowicz
2014/12/03 22:00:44
Good point. I am not sure about this
- Some tests
| |
32 // | |
33 // MockCallback<int()> mock_callback; | |
34 // EXPECT_CALL(mock_callback, Run()).WillOnce(Return(123)); | |
35 // HypotheticalFunctionUnderTest(mock_callback.GetCallback()); | |
36 // EXPECT_FALSE(mock_callback.HasRemainingCallbacks()) | |
37 // << "Verify that FunctionUnderTest didn't store the callback " | |
38 // << "and therefore callers of FunctionUnderTest don't have to " | |
39 // << "worry about lifetime of arguments bound to the callback"; | |
Wez
2014/12/03 19:45:49
You need to be very clear on the threading semanti
Łukasz Anforowicz
2014/12/03 22:00:44
I don't understand:
- HasRemainingCallbacks is thr
| |
40 // | |
41 // Thread safety notes: | |
42 // | |
43 // Calling Run on a Callback returned from MockCallback::GetCallback | |
44 // - Is *not* thread-safe wrt setting default actions and expectations (via | |
45 // ON_CALL and EXPECT_CALL gMock macros). | |
Wez
2014/12/03 19:45:49
This is not very clear; you mean that the call exp
Łukasz Anforowicz
2014/12/03 22:00:44
One cannot call EXPECT_CALL and Run in parallel.
| |
46 // - Is thread-safe wrt other Run calls and destroying MockCallback. | |
Wez
2014/12/03 19:45:49
What are the semantics if a callback still exists
Łukasz Anforowicz
2014/12/03 22:00:44
This is documented in "What happens when Callback:
| |
47 // | |
48 // This is similar to the guarantees described at | |
49 // https://code.google.com/p/googlemock/wiki/CookBook#Using_Google_Mock_and_Th reads | |
50 // except that the guarantees hold on all platforms. | |
51 // | |
52 // What happens when Callback::Run is called after MockCallback is destroyed: | |
Wez
2014/12/03 19:45:49
This contradicts the GetCallback comment, though.
Łukasz Anforowicz
2014/12/03 22:00:44
Acknowledged.
| |
53 // | |
54 // - gTest EXPECT failure will be triggered | |
55 // - gMock's default return value will be returned - see: | |
56 // https://code.google.com/p/googlemock/wiki/CookBook#Setting_the_Default_Va lue_for_a_Return_Type | |
57 | |
58 // Implementation notes: | |
59 // | |
60 // WeakPtr-like code | |
61 // ----------------- | |
62 // | |
63 // Relationship between MockCallback and MockCallbackTracker is similar | |
64 // to the relationship between WeakPtrFactory<T> and WeakPtr<T>. We don't | |
65 // use WeakPtrFactory<T> and WeakPtr<T>, because: | |
Wez
2014/12/03 19:45:49
This comment is very confusing; it's not clear wha
| |
66 // - WeakPtrs can only bind to methods without return values | |
67 // (enforced by a static assert in bind_internal.h:402). | |
68 // - WeakPtr impose task-specific, thread-safety-restrictions that are | |
69 // not present in Callback that MockCallback is mocking. | |
70 // - For MockCallback we don't necessarily want the behavior where Callbacks | |
71 // bound to WeakPtr are translated into no-ops, before the bound function | |
72 // gets to execute. In MockCallback case we want the test to have control of | |
73 // what happens in this case (i.e. gtest EXPECT, rather than a no-op; | |
74 // note that we cannot use gtest ASSERT for non-void-returning Run method). | |
75 | |
18 template <typename Sig> | 76 template <typename Sig> |
19 class MockCallback; | 77 class MockCallback; |
20 | 78 |
21 template <typename R> | 79 template <typename R> |
22 class MockCallback<R()> { | 80 class MockCallback<R()> { |
Wez
2014/12/03 19:45:49
It looks like you should be able to put most of th
Łukasz Anforowicz
2014/12/03 22:00:44
Ack - I'll try this out.
| |
23 public: | 81 public: |
24 MOCK_CONST_METHOD0_T(Run, R()); | 82 MOCK_CONST_METHOD0_T(Run, R()); |
25 | 83 |
26 MockCallback() { | 84 MockCallback() : mock_callback_tracker_(new MockCallbackTracker(this)) {} |
27 } | 85 |
86 ~MockCallback() { mock_callback_tracker_->MarkMockCallbackAsDead(); } | |
28 | 87 |
29 // Caller of GetCallback has to guarantee that the returned callback | 88 // Caller of GetCallback has to guarantee that the returned callback |
30 // will not be run after |this| is destroyed. | 89 // will not be run after |this| is destroyed. |
31 base::Callback<R()> GetCallback() { | 90 base::Callback<R()> GetCallback() const { |
32 return base::Bind(&MockCallback<R()>::Run, base::Unretained(this)); | 91 return base::Bind(&MockCallbackTracker::Run, mock_callback_tracker_); |
92 } | |
93 | |
94 // Returns |true| if callbacks returned by |GetCallback| have not been | |
95 // destroyed yet. | |
96 bool HasRemainingCallbacks() const { | |
97 bool is_tracker_field_the_only_ref = mock_callback_tracker_->HasOneRef(); | |
98 return !is_tracker_field_the_only_ref; | |
33 } | 99 } |
34 | 100 |
35 private: | 101 private: |
102 class MockCallbackTracker | |
103 : public base::RefCountedThreadSafe<MockCallbackTracker> { | |
104 public: | |
105 MockCallbackTracker(MockCallback* mock_callback) | |
106 : mock_callback_(mock_callback), is_mock_callback_alive_(true) {} | |
107 | |
108 R Run() { | |
109 base::AutoLock auto_lock(lock_); | |
110 EXPECT_TRUE(is_mock_callback_alive_) | |
111 << "MockCallback should be alive when Callback::Run happens."; | |
112 return is_mock_callback_alive_ ? mock_callback_->Run() | |
113 : testing::DefaultValue<R>::Get(); | |
114 } | |
115 | |
116 void MarkMockCallbackAsDead() { | |
117 base::AutoLock auto_lock(lock_); | |
118 is_mock_callback_alive_ = false; | |
119 mock_callback_ = nullptr; | |
120 } | |
121 | |
122 private: | |
123 // Ref-counting helpers. | |
124 friend class base::RefCountedThreadSafe<MockCallbackTracker>; | |
125 ~MockCallbackTracker() {} | |
126 | |
127 MockCallback<R()>* mock_callback_; | |
128 base::Lock lock_; | |
129 bool is_mock_callback_alive_; | |
130 }; | |
131 | |
132 scoped_refptr<MockCallbackTracker> mock_callback_tracker_; | |
133 | |
36 DISALLOW_COPY_AND_ASSIGN(MockCallback); | 134 DISALLOW_COPY_AND_ASSIGN(MockCallback); |
37 }; | 135 }; |
38 | 136 |
137 template <typename R, typename A1> | |
138 class MockCallback<R(A1)> { | |
139 public: | |
140 MOCK_CONST_METHOD1_T(Run, R(A1)); | |
141 | |
142 MockCallback() : mock_callback_tracker_(new MockCallbackTracker(this)) {} | |
143 | |
144 ~MockCallback() { mock_callback_tracker_->MarkMockCallbackAsDead(); } | |
145 | |
146 // Caller of GetCallback has to guarantee that the returned callback | |
147 // will not be run after |this| is destroyed. | |
148 base::Callback<R(A1)> GetCallback() const { | |
149 return base::Bind(&MockCallbackTracker::Run, mock_callback_tracker_); | |
150 } | |
151 | |
152 // Returns |true| if callbacks returned by |GetCallback| have not been | |
153 // destroyed yet. | |
154 bool HasRemainingCallbacks() const { | |
155 bool is_tracker_field_the_only_ref = mock_callback_tracker_->HasOneRef(); | |
156 return !is_tracker_field_the_only_ref; | |
157 } | |
158 | |
159 private: | |
160 class MockCallbackTracker | |
161 : public base::RefCountedThreadSafe<MockCallbackTracker> { | |
162 public: | |
163 MockCallbackTracker(MockCallback* mock_callback) | |
164 : mock_callback_(mock_callback), is_mock_callback_alive_(true) {} | |
165 | |
166 R Run(A1 a1) { | |
167 base::AutoLock auto_lock(lock_); | |
168 EXPECT_TRUE(is_mock_callback_alive_) | |
169 << "MockCallback should be alive when Callback::Run happens."; | |
170 return is_mock_callback_alive_ ? mock_callback_->Run(a1) | |
171 : testing::DefaultValue<R>::Get(); | |
172 } | |
173 | |
174 void MarkMockCallbackAsDead() { | |
175 base::AutoLock auto_lock(lock_); | |
176 is_mock_callback_alive_ = false; | |
177 mock_callback_ = nullptr; | |
178 } | |
179 | |
180 private: | |
181 // Ref-counting helpers. | |
182 friend class base::RefCountedThreadSafe<MockCallbackTracker>; | |
183 ~MockCallbackTracker() {} | |
184 | |
185 MockCallback<R(A1)>* mock_callback_; | |
186 base::Lock lock_; | |
187 bool is_mock_callback_alive_; | |
188 }; | |
189 | |
190 scoped_refptr<MockCallbackTracker> mock_callback_tracker_; | |
191 | |
192 DISALLOW_COPY_AND_ASSIGN(MockCallback); | |
193 }; | |
194 | |
39 typedef MockCallback<void(void)> MockClosure; | 195 typedef MockCallback<void(void)> MockClosure; |
40 | 196 |
41 } // namespace remoting | 197 } // namespace remoting |
42 | 198 |
43 #endif // REMOTING_HOST_MOCK_CALLBACK_H_ | 199 #endif // REMOTING_HOST_MOCK_CALLBACK_H_ |
OLD | NEW |