1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
6 #include "base/logging.h"
7 #include "base/memory/ref_counted.h"
8 #include "base/memory/scoped_ptr.h"
9 #include "base/message_loop/message_loop.h"
10 #include "base/run_loop.h"
11 #include "dbus/message.h"
12 #include "dbus/mock_bus.h"
13 #include "dbus/mock_exported_object.h"
14 #include "dbus/mock_object_proxy.h"
15 #include "dbus/object_path.h"
16 #include "dbus/scoped_dbus_error.h"
17 #include "testing/gmock/include/gmock/gmock.h"
18 #include "testing/gtest/include/gtest/gtest.h"
21 using ::testing::Invoke
;
22 using ::testing::Return
;
23 using ::testing::Unused
;
27 class MockTest
: public testing::Test
{
32 virtual void SetUp() {
35 options
.bus_type
= Bus::SYSTEM
;
36 mock_bus_
= new MockBus(options
);
38 // Create a mock proxy.
39 mock_proxy_
= new MockObjectProxy(
41 "org.chromium.TestService",
42 ObjectPath("/org/chromium/TestObject"));
44 // Set an expectation so mock_proxy's CallMethodAndBlock() will use
45 // CreateMockProxyResponse() to return responses.
46 EXPECT_CALL(*mock_proxy_
.get(), MockCallMethodAndBlock(_
, _
))
47 .WillRepeatedly(Invoke(this, &MockTest::CreateMockProxyResponse
));
48 EXPECT_CALL(*mock_proxy_
.get(),
49 MockCallMethodAndBlockWithErrorDetails(_
, _
, _
))
51 Invoke(this, &MockTest::CreateMockProxyResponseWithErrorDetails
));
53 // Set an expectation so mock_proxy's CallMethod() will use
54 // HandleMockProxyResponseWithMessageLoop() to return responses.
55 EXPECT_CALL(*mock_proxy_
.get(), CallMethod(_
, _
, _
)).WillRepeatedly(
56 Invoke(this, &MockTest::HandleMockProxyResponseWithMessageLoop
));
58 // Set an expectation so mock_bus's GetObjectProxy() for the given
59 // service name and the object path will return mock_proxy_.
60 EXPECT_CALL(*mock_bus_
.get(),
61 GetObjectProxy("org.chromium.TestService",
62 ObjectPath("/org/chromium/TestObject")))
63 .WillOnce(Return(mock_proxy_
.get()));
65 // ShutdownAndBlock() will be called in TearDown().
66 EXPECT_CALL(*mock_bus_
.get(), ShutdownAndBlock()).WillOnce(Return());
69 virtual void TearDown() {
70 mock_bus_
->ShutdownAndBlock();
73 // Called when the response is received.
74 void OnResponse(Response
* response
) {
75 // |response| will be deleted on exit of the function. Copy the
76 // payload to |response_string_|.
78 MessageReader
reader(response
);
79 ASSERT_TRUE(reader
.PopString(&response_string_
));
85 std::string response_string_
;
86 base::MessageLoop message_loop_
;
87 scoped_ptr
<base::RunLoop
> run_loop_
;
88 scoped_refptr
<MockBus
> mock_bus_
;
89 scoped_refptr
<MockObjectProxy
> mock_proxy_
;
92 // Returns a response for the given method call. Used to implement
93 // CallMethodAndBlock() for |mock_proxy_|.
94 Response
* CreateMockProxyResponse(MethodCall
* method_call
,
96 if (method_call
->GetInterface() == "org.chromium.TestInterface" &&
97 method_call
->GetMember() == "Echo") {
98 MessageReader
reader(method_call
);
99 std::string text_message
;
100 if (reader
.PopString(&text_message
)) {
101 scoped_ptr
<Response
> response
= Response::CreateEmpty();
102 MessageWriter
writer(response
.get());
103 writer
.AppendString(text_message
);
104 return response
.release();
108 LOG(ERROR
) << "Unexpected method call: " << method_call
->ToString();
112 Response
* CreateMockProxyResponseWithErrorDetails(
113 MethodCall
* method_call
, int timeout_ms
, ScopedDBusError
* error
) {
114 dbus_set_error(error
->get(), DBUS_ERROR_NOT_SUPPORTED
, "Not implemented");
118 // Creates a response and runs the given response callback in the
119 // message loop with the response. Used to implement for |mock_proxy_|.
120 void HandleMockProxyResponseWithMessageLoop(
121 MethodCall
* method_call
,
123 ObjectProxy::ResponseCallback response_callback
) {
124 Response
* response
= CreateMockProxyResponse(method_call
, timeout_ms
);
125 message_loop_
.PostTask(FROM_HERE
,
126 base::Bind(&MockTest::RunResponseCallback
,
127 base::Unretained(this),
132 // Runs the given response callback with the given response.
133 void RunResponseCallback(
134 ObjectProxy::ResponseCallback response_callback
,
135 Response
* response
) {
136 response_callback
.Run(response
);
141 // This test demonstrates how to mock a synchronous method call using the
143 TEST_F(MockTest
, CallMethodAndBlock
) {
144 const char kHello
[] = "Hello";
145 // Get an object proxy from the mock bus.
146 ObjectProxy
* proxy
= mock_bus_
->GetObjectProxy(
147 "org.chromium.TestService",
148 ObjectPath("/org/chromium/TestObject"));
150 // Create a method call.
151 MethodCall
method_call("org.chromium.TestInterface", "Echo");
152 MessageWriter
writer(&method_call
);
153 writer
.AppendString(kHello
);
156 scoped_ptr
<Response
> response(
157 proxy
->CallMethodAndBlock(&method_call
,
158 ObjectProxy::TIMEOUT_USE_DEFAULT
));
160 // Check the response.
161 ASSERT_TRUE(response
.get());
162 MessageReader
reader(response
.get());
163 std::string text_message
;
164 ASSERT_TRUE(reader
.PopString(&text_message
));
165 // The text message should be echo'ed back.
166 EXPECT_EQ(kHello
, text_message
);
169 TEST_F(MockTest
, CallMethodAndBlockWithErrorDetails
) {
170 // Get an object proxy from the mock bus.
171 ObjectProxy
* proxy
= mock_bus_
->GetObjectProxy(
172 "org.chromium.TestService",
173 ObjectPath("/org/chromium/TestObject"));
175 // Create a method call.
176 MethodCall
method_call("org.chromium.TestInterface", "Echo");
178 ScopedDBusError error
;
180 scoped_ptr
<Response
> response(
181 proxy
->CallMethodAndBlockWithErrorDetails(
182 &method_call
, ObjectProxy::TIMEOUT_USE_DEFAULT
, &error
));
184 // Check the response.
185 ASSERT_FALSE(response
.get());
186 ASSERT_TRUE(error
.is_set());
187 EXPECT_STREQ(DBUS_ERROR_NOT_SUPPORTED
, error
.name());
188 EXPECT_STREQ("Not implemented", error
.message());
191 // This test demonstrates how to mock an asynchronous method call using the
193 TEST_F(MockTest
, CallMethod
) {
194 const char kHello
[] = "hello";
196 // Get an object proxy from the mock bus.
197 ObjectProxy
* proxy
= mock_bus_
->GetObjectProxy(
198 "org.chromium.TestService",
199 ObjectPath("/org/chromium/TestObject"));
201 // Create a method call.
202 MethodCall
method_call("org.chromium.TestInterface", "Echo");
203 MessageWriter
writer(&method_call
);
204 writer
.AppendString(kHello
);
207 run_loop_
.reset(new base::RunLoop
);
208 proxy
->CallMethod(&method_call
,
209 ObjectProxy::TIMEOUT_USE_DEFAULT
,
210 base::Bind(&MockTest::OnResponse
,
211 base::Unretained(this)));
212 // Run the message loop to let OnResponse be called.
215 EXPECT_EQ(kHello
, response_string_
);