Chromium Code Reviews| Index: remoting/host/mock_callback.h |
| diff --git a/remoting/host/mock_callback.h b/remoting/host/mock_callback.h |
| index ca3feb6d06a415f1853b363e7b089f8b0a03ad7a..4eb8cb032b1bbf26afb77813aaaa6481b4241c2e 100644 |
| --- a/remoting/host/mock_callback.h |
| +++ b/remoting/host/mock_callback.h |
| @@ -10,11 +10,33 @@ |
| #include "base/bind.h" |
| #include "base/bind_helpers.h" |
| #include "base/callback.h" |
| +#include "base/memory/ref_counted.h" |
| #include "testing/gmock/include/gmock/gmock.h" |
| namespace remoting { |
| +// MockCallback<Sig> can be used to mock Callback<Sig> from base/callback.h |
|
Lambros
2014/12/03 03:20:25
This basically looks fine, though I can't say I fu
|
| +// |
| +// Basic usage example: |
| +// |
| +// MockCallback<void(int)> mock_callback; |
| +// EXPECT_CALL(mock_callback, Run(123)).Times(2); |
| +// base::Callback<void(int)> callback = mock_callback.GetCallback(); |
| +// |
| +// // Use |callback| in the remainder of the test. |
| +// // GMock will enforce the expectations from above. |
| +// |
| +// HasRemainingCallbacks usage example: |
| +// |
| +// MockCallback<int()> mock_callback; |
| +// EXPECT_CALL(mock_callback, Run()).WillOnce(Return(123)); |
| +// HypotheticalFunctionUnderTest(mock_callback.GetCallback()); |
| +// EXPECT_FALSE(mock_callback.HasRemainingCallbacks()) |
| +// << "Verify that FunctionUnderTest didn't store the callback " |
|
Lambros
2014/12/03 03:20:25
This feels like it should be a code comment, not a
Łukasz Anforowicz
2014/12/03 17:54:22
Maybe. I think that having this message in the ou
|
| +// << "and therefore callers of FunctionUnderTest don't have to " |
| +// << "worry about lifetime of arguments bound to the callback"; |
| + |
| template <typename Sig> |
| class MockCallback; |
| @@ -23,16 +45,106 @@ class MockCallback<R()> { |
| public: |
| MOCK_CONST_METHOD0_T(Run, R()); |
| - MockCallback() { |
| + MockCallback() : mock_callback_tracker_(new MockCallbackTracker(this)) { |
| } |
| // Caller of GetCallback has to guarantee that the returned callback |
| // will not be run after |this| is destroyed. |
| base::Callback<R()> GetCallback() { |
| - return base::Bind(&MockCallback<R()>::Run, base::Unretained(this)); |
| + return base::Bind(&MockCallbackTracker::Run, mock_callback_tracker_); |
| + } |
| + |
| + // Returns |true| if callbacks returned by |GetCallback| have not been |
| + // destroyed yet. |
| + bool HasRemainingCallbacks() const { |
| + bool is_tracker_field_the_only_ref = mock_callback_tracker_->HasOneRef(); |
| + return !is_tracker_field_the_only_ref; |
| } |
| private: |
| + // MockCallbackTracker has 2 goals: |
| + // - Enable counting of callbacks for |HasRemainingCallbacks| method. |
| + // - Allow stack-allocated MockCallbacks to be short-lived, while |
| + // callbacks go through a long-lived MockCallbackTracker |
| + // (which in the future can enable better handling of callback- |
| + // -run-after-mock-callback-already-destroyed). |
| + class MockCallbackTracker |
| + : public base::RefCountedThreadSafe<MockCallbackTracker> { |
| + public: |
| + MockCallbackTracker(MockCallback* mock_callback) |
| + : mock_callback_(mock_callback) { |
| + } |
| + |
| + R Run() { |
| + // Forward to (gMock controlled) MockCallback::Run method. |
| + return mock_callback_->Run(); |
| + } |
| + |
| + private: |
| + // Ref-counting helpers. |
| + friend class base::RefCountedThreadSafe<MockCallbackTracker>; |
| + ~MockCallbackTracker() { |
| + } |
| + |
| + MockCallback<R()>* mock_callback_; |
| + }; |
| + |
| + scoped_refptr<MockCallbackTracker> mock_callback_tracker_; |
| + |
| + DISALLOW_COPY_AND_ASSIGN(MockCallback); |
| +}; |
| + |
| +template <typename R, typename A1> |
| +class MockCallback<R(A1)> { |
| + public: |
| + MOCK_CONST_METHOD1_T(Run, R(A1)); |
| + |
| + MockCallback() : mock_callback_tracker_(new MockCallbackTracker(this)) { |
| + } |
| + |
| + // Caller of GetCallback has to guarantee that the returned callback |
| + // will not be run after |this| is destroyed. |
| + base::Callback<R(A1)> GetCallback() { |
| + return base::Bind(&MockCallbackTracker::Run, mock_callback_tracker_); |
| + } |
| + |
| + // Returns |true| if callbacks returned by |GetCallback| have not been |
| + // destroyed yet. |
| + bool HasRemainingCallbacks() const { |
| + bool is_tracker_field_the_only_ref = mock_callback_tracker_->HasOneRef(); |
| + return !is_tracker_field_the_only_ref; |
| + } |
| + |
| + private: |
| + // MockCallbackTracker has 2 goals: |
| + // - Enable counting of callbacks for |HasRemainingCallbacks| method. |
| + // - Allow stack-allocated MockCallbacks to be short-lived, while |
| + // callbacks go through a long-lived MockCallbackTracker |
| + // (which in the future can enable better handling of callback- |
| + // -run-after-mock-callback-already-destroyed). |
| + class MockCallbackTracker |
| + : public base::RefCountedThreadSafe<MockCallbackTracker> { |
| + public: |
| + MockCallbackTracker(MockCallback* mock_callback) |
| + : mock_callback_(mock_callback) { |
| + } |
| + |
| + R Run(A1 a1) { |
| + // Forward to (gMock controlled) MockCallback::Run method. |
| + return mock_callback_->Run(a1); |
| + } |
| + |
| + private: |
| + // Ref-counting helpers. |
| + friend class base::RefCountedThreadSafe<MockCallbackTracker>; |
| + ~MockCallbackTracker() { |
| + } |
| + |
| + MockCallback<R(A1)>* mock_callback_; |
| + }; |
| + |
| + scoped_refptr<MockCallbackTracker> mock_callback_tracker_; |
| + |
| DISALLOW_COPY_AND_ASSIGN(MockCallback); |
| }; |