Chromium Code Reviews| 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 |