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. 4 5 #include "chromeos/dbus/ibus/ibus_client.h" 6 7 #include "base/bind.h" 8 #include "base/message_loop/message_loop.h" 9 #include "base/values.h" 10 #include "chromeos/dbus/ibus/ibus_constants.h" 11 #include "dbus/message.h" 12 #include "dbus/mock_bus.h" 13 #include "dbus/mock_object_proxy.h" 14 #include "dbus/object_path.h" 15 #include "dbus/values_util.h" 16 #include "testing/gmock/include/gmock/gmock.h" 17 #include "testing/gtest/include/gtest/gtest.h" 18 19 using testing::Invoke; 20 using testing::Return; 21 using testing::_; 22 23 namespace chromeos { 24 25 namespace { 26 const char kClientName[] = "chrome"; 27 const char kEngineName[] = "engine"; 28 const bool kRestartFlag = true; 29 } // namespace 30 31 class MockCreateInputContextCallback { 32 public: 33 MOCK_METHOD1(Run, void(const dbus::ObjectPath& object_path)); 34 }; 35 36 class MockErrorCallback { 37 public: 38 MOCK_METHOD0(Run, void()); 39 }; 40 41 class IBusClientTest : public testing::Test { 42 public: 43 IBusClientTest() : response_(NULL) {} 44 45 // Handles CreateInputContext method call. 46 void OnCreateInputContext( 47 dbus::MethodCall* method_call, 48 int timeout_ms, 49 const dbus::ObjectProxy::ResponseCallback& callback, 50 const dbus::ObjectProxy::ErrorCallback& error_callback) { 51 dbus::MessageReader reader(method_call); 52 std::string client_name; 53 EXPECT_TRUE(reader.PopString(&client_name)); 54 EXPECT_EQ(kClientName, client_name); 55 EXPECT_FALSE(reader.HasMoreData()); 56 57 message_loop_.PostTask(FROM_HERE, base::Bind(callback, response_)); 58 } 59 60 // Handles fail case of CreateInputContext method call. 61 void OnCreateInputContextFail( 62 dbus::MethodCall* method_call, 63 int timeout_ms, 64 const dbus::ObjectProxy::ResponseCallback& callback, 65 const dbus::ObjectProxy::ErrorCallback& error_callback) { 66 dbus::MessageReader reader(method_call); 67 std::string client_name; 68 EXPECT_TRUE(reader.PopString(&client_name)); 69 EXPECT_EQ(kClientName, client_name); 70 EXPECT_FALSE(reader.HasMoreData()); 71 72 message_loop_.PostTask(FROM_HERE, base::Bind(error_callback, 73 error_response_)); 74 } 75 76 // Handles SetGlobalEngine method call. 77 void OnSetGlobalEngine( 78 dbus::MethodCall* method_call, 79 int timeout_ms, 80 const dbus::ObjectProxy::ResponseCallback& callback, 81 const dbus::ObjectProxy::ErrorCallback& error_callback) { 82 dbus::MessageReader reader(method_call); 83 std::string engine_name; 84 EXPECT_TRUE(reader.PopString(&engine_name)); 85 EXPECT_EQ(kEngineName, engine_name); 86 EXPECT_FALSE(reader.HasMoreData()); 87 message_loop_.PostTask(FROM_HERE, base::Bind(callback, response_)); 88 } 89 90 // Handles fail case of SetGlobalEngine method call. 91 void OnSetGlobalEngineFail( 92 dbus::MethodCall* method_call, 93 int timeout_ms, 94 const dbus::ObjectProxy::ResponseCallback& callback, 95 const dbus::ObjectProxy::ErrorCallback& error_callback) { 96 dbus::MessageReader reader(method_call); 97 std::string engine_name; 98 EXPECT_TRUE(reader.PopString(&engine_name)); 99 EXPECT_EQ(kEngineName, engine_name); 100 EXPECT_FALSE(reader.HasMoreData()); 101 message_loop_.PostTask(FROM_HERE, base::Bind(error_callback, 102 error_response_)); 103 } 104 105 // Handles Exit method call. 106 void OnExit(dbus::MethodCall* method_call, 107 int timeout_ms, 108 const dbus::ObjectProxy::ResponseCallback& callback, 109 const dbus::ObjectProxy::ErrorCallback& error_callback) { 110 dbus::MessageReader reader(method_call); 111 bool restart = false; 112 EXPECT_TRUE(reader.PopBool(&restart)); 113 EXPECT_EQ(kRestartFlag, restart); 114 EXPECT_FALSE(reader.HasMoreData()); 115 message_loop_.PostTask(FROM_HERE, base::Bind(callback, response_)); 116 } 117 118 // Handles fail case of Exit method call. 119 void OnExitFail(dbus::MethodCall* method_call, 120 int timeout_ms, 121 const dbus::ObjectProxy::ResponseCallback& callback, 122 const dbus::ObjectProxy::ErrorCallback& error_callback) { 123 dbus::MessageReader reader(method_call); 124 bool restart = false; 125 EXPECT_TRUE(reader.PopBool(&restart)); 126 EXPECT_EQ(kRestartFlag, restart); 127 EXPECT_FALSE(reader.HasMoreData()); 128 message_loop_.PostTask(FROM_HERE, base::Bind(error_callback, 129 error_response_)); 130 } 131 132 protected: 133 virtual void SetUp() OVERRIDE { 134 dbus::Bus::Options options; 135 mock_bus_ = new dbus::MockBus(options); 136 mock_proxy_ = new dbus::MockObjectProxy(mock_bus_.get(), 137 ibus::kServiceName, 138 dbus::ObjectPath( 139 ibus::bus::kServicePath)); 140 EXPECT_CALL(*mock_bus_.get(), 141 GetObjectProxy(ibus::kServiceName, 142 dbus::ObjectPath(ibus::bus::kServicePath))) 143 .WillOnce(Return(mock_proxy_.get())); 144 145 EXPECT_CALL(*mock_bus_.get(), ShutdownAndBlock()); 146 client_.reset( 147 IBusClient::Create(REAL_DBUS_CLIENT_IMPLEMENTATION, mock_bus_.get())); 148 } 149 150 virtual void TearDown() OVERRIDE { 151 mock_bus_->ShutdownAndBlock(); 152 } 153 154 // The IBus client to be tested. 155 scoped_ptr<IBusClient> client_; 156 157 // A message loop to emulate asynchronous behavior. 158 base::MessageLoop message_loop_; 159 scoped_refptr<dbus::MockBus> mock_bus_; 160 scoped_refptr<dbus::MockObjectProxy> mock_proxy_; 161 162 // Response returned by mock methods. 163 dbus::Response* response_; 164 dbus::ErrorResponse* error_response_; 165 }; 166 167 TEST_F(IBusClientTest, CreateInputContextTest) { 168 // Set expectations. 169 const dbus::ObjectPath kInputContextObjectPath = 170 dbus::ObjectPath("/some/object/path"); 171 EXPECT_CALL(*mock_proxy_.get(), CallMethodWithErrorCallback(_, _, _, _)) 172 .WillOnce(Invoke(this, &IBusClientTest::OnCreateInputContext)); 173 MockCreateInputContextCallback callback; 174 EXPECT_CALL(callback, Run(kInputContextObjectPath)); 175 MockErrorCallback error_callback; 176 EXPECT_CALL(error_callback, Run()).Times(0); 177 178 // Create response. 179 scoped_ptr<dbus::Response> response(dbus::Response::CreateEmpty()); 180 dbus::MessageWriter writer(response.get()); 181 writer.AppendObjectPath(kInputContextObjectPath); 182 response_ = response.get(); 183 184 // Call CreateInputContext. 185 client_->CreateInputContext( 186 kClientName, 187 base::Bind(&MockCreateInputContextCallback::Run, 188 base::Unretained(&callback)), 189 base::Bind(&MockErrorCallback::Run, 190 base::Unretained(&error_callback))); 191 192 // Run the message loop. 193 message_loop_.RunUntilIdle(); 194 } 195 196 TEST_F(IBusClientTest, CreateInputContext_NullResponseFail) { 197 // Set expectations. 198 EXPECT_CALL(*mock_proxy_.get(), CallMethodWithErrorCallback(_, _, _, _)) 199 .WillOnce(Invoke(this, &IBusClientTest::OnCreateInputContext)); 200 MockCreateInputContextCallback callback; 201 EXPECT_CALL(callback, Run(_)).Times(0); 202 MockErrorCallback error_callback; 203 EXPECT_CALL(error_callback, Run()); 204 205 // Set NULL response. 206 response_ = NULL; 207 208 // Call CreateInputContext. 209 client_->CreateInputContext( 210 kClientName, 211 base::Bind(&MockCreateInputContextCallback::Run, 212 base::Unretained(&callback)), 213 base::Bind(&MockErrorCallback::Run, 214 base::Unretained(&error_callback))); 215 216 // Run the message loop. 217 message_loop_.RunUntilIdle(); 218 } 219 220 TEST_F(IBusClientTest, CreateInputContext_InvalidResponseFail) { 221 // Set expectations. 222 EXPECT_CALL(*mock_proxy_.get(), CallMethodWithErrorCallback(_, _, _, _)) 223 .WillOnce(Invoke(this, &IBusClientTest::OnCreateInputContext)); 224 MockCreateInputContextCallback callback; 225 EXPECT_CALL(callback, Run(_)).Times(0); 226 MockErrorCallback error_callback; 227 EXPECT_CALL(error_callback, Run()); 228 229 // Create invalid(empty) response. 230 scoped_ptr<dbus::Response> response(dbus::Response::CreateEmpty()); 231 response_ = response.get(); 232 233 // Call CreateInputContext. 234 client_->CreateInputContext( 235 kClientName, 236 base::Bind(&MockCreateInputContextCallback::Run, 237 base::Unretained(&callback)), 238 base::Bind(&MockErrorCallback::Run, 239 base::Unretained(&error_callback))); 240 241 // Run the message loop. 242 message_loop_.RunUntilIdle(); 243 } 244 245 TEST_F(IBusClientTest, CreateInputContext_MethodCallFail) { 246 // Set expectations 247 EXPECT_CALL(*mock_proxy_.get(), CallMethodWithErrorCallback(_, _, _, _)) 248 .WillOnce(Invoke(this, &IBusClientTest::OnCreateInputContextFail)); 249 MockCreateInputContextCallback callback; 250 EXPECT_CALL(callback, Run(_)).Times(0); 251 MockErrorCallback error_callback; 252 EXPECT_CALL(error_callback, Run()); 253 254 // The error response is not used in CreateInputContext. 255 error_response_ = NULL; 256 257 // Call CreateInputContext. 258 client_->CreateInputContext( 259 kClientName, 260 base::Bind(&MockCreateInputContextCallback::Run, 261 base::Unretained(&callback)), 262 base::Bind(&MockErrorCallback::Run, 263 base::Unretained(&error_callback))); 264 265 // Run the message loop. 266 message_loop_.RunUntilIdle(); 267 } 268 269 TEST_F(IBusClientTest, SetGlobalEngineTest) { 270 // Set expectations 271 EXPECT_CALL(*mock_proxy_.get(), CallMethodWithErrorCallback(_, _, _, _)) 272 .WillOnce(Invoke(this, &IBusClientTest::OnSetGlobalEngine)); 273 MockErrorCallback error_callback; 274 EXPECT_CALL(error_callback, Run()).Times(0); 275 276 // Create empty response. 277 scoped_ptr<dbus::Response> response(dbus::Response::CreateEmpty()); 278 response_ = response.get(); 279 280 // The error response is not used in SetGLobalEngine. 281 error_response_ = NULL; 282 283 // Call CreateInputContext. 284 client_->SetGlobalEngine( 285 kEngineName, 286 base::Bind(&MockErrorCallback::Run, 287 base::Unretained(&error_callback))); 288 289 // Run the message loop. 290 message_loop_.RunUntilIdle(); 291 } 292 293 TEST_F(IBusClientTest, SetGlobalEngineTest_InvalidResponse) { 294 // Set expectations 295 EXPECT_CALL(*mock_proxy_.get(), CallMethodWithErrorCallback(_, _, _, _)) 296 .WillOnce(Invoke(this, &IBusClientTest::OnSetGlobalEngineFail)); 297 MockErrorCallback error_callback; 298 EXPECT_CALL(error_callback, Run()); 299 300 // Set invalid response. 301 response_ = NULL; 302 303 // The error response is not used in SetGLobalEngine. 304 error_response_ = NULL; 305 306 // Call CreateInputContext. 307 client_->SetGlobalEngine( 308 kEngineName, 309 base::Bind(&MockErrorCallback::Run, 310 base::Unretained(&error_callback))); 311 312 // Run the message loop. 313 message_loop_.RunUntilIdle(); 314 } 315 316 TEST_F(IBusClientTest, SetGlobalEngineTest_MethodCallFail) { 317 // Set expectations 318 EXPECT_CALL(*mock_proxy_.get(), CallMethodWithErrorCallback(_, _, _, _)) 319 .WillOnce(Invoke(this, &IBusClientTest::OnSetGlobalEngineFail)); 320 MockErrorCallback error_callback; 321 EXPECT_CALL(error_callback, Run()); 322 323 // Create empty response. 324 scoped_ptr<dbus::Response> response(dbus::Response::CreateEmpty()); 325 response_ = response.get(); 326 327 // The error response is not used in SetGLobalEngine. 328 error_response_ = NULL; 329 330 // Call CreateInputContext. 331 client_->SetGlobalEngine( 332 kEngineName, 333 base::Bind(&MockErrorCallback::Run, 334 base::Unretained(&error_callback))); 335 336 // Run the message loop. 337 message_loop_.RunUntilIdle(); 338 } 339 340 TEST_F(IBusClientTest, ExitTest) { 341 // Set expectations 342 EXPECT_CALL(*mock_proxy_.get(), CallMethodWithErrorCallback(_, _, _, _)) 343 .WillOnce(Invoke(this, &IBusClientTest::OnExit)); 344 MockErrorCallback error_callback; 345 EXPECT_CALL(error_callback, Run()).Times(0); 346 347 // Create empty response. 348 scoped_ptr<dbus::Response> response(dbus::Response::CreateEmpty()); 349 response_ = response.get(); 350 351 // The error response is not used in SetGLobalEngine. 352 error_response_ = NULL; 353 354 // Call CreateInputContext. 355 client_->Exit( 356 IBusClient::RESTART_IBUS_DAEMON, 357 base::Bind(&MockErrorCallback::Run, 358 base::Unretained(&error_callback))); 359 360 // Run the message loop. 361 message_loop_.RunUntilIdle(); 362 } 363 364 TEST_F(IBusClientTest, ExitTest_InvalidResponse) { 365 // Set expectations 366 EXPECT_CALL(*mock_proxy_.get(), CallMethodWithErrorCallback(_, _, _, _)) 367 .WillOnce(Invoke(this, &IBusClientTest::OnExit)); 368 MockErrorCallback error_callback; 369 EXPECT_CALL(error_callback, Run()); 370 371 // Set invalid response. 372 response_ = NULL; 373 374 // The error response is not used in SetGLobalEngine. 375 error_response_ = NULL; 376 377 // Call CreateInputContext. 378 client_->Exit( 379 IBusClient::RESTART_IBUS_DAEMON, 380 base::Bind(&MockErrorCallback::Run, 381 base::Unretained(&error_callback))); 382 383 // Run the message loop. 384 message_loop_.RunUntilIdle(); 385 } 386 387 TEST_F(IBusClientTest, ExitTest_MethodCallFail) { 388 // Set expectations 389 EXPECT_CALL(*mock_proxy_.get(), CallMethodWithErrorCallback(_, _, _, _)) 390 .WillOnce(Invoke(this, &IBusClientTest::OnExitFail)); 391 MockErrorCallback error_callback; 392 EXPECT_CALL(error_callback, Run()); 393 394 // Create empty response. 395 scoped_ptr<dbus::Response> response(dbus::Response::CreateEmpty()); 396 response_ = response.get(); 397 398 // The error response is not used in SetGLobalEngine. 399 error_response_ = NULL; 400 401 // Call CreateInputContext. 402 client_->Exit( 403 IBusClient::RESTART_IBUS_DAEMON, 404 base::Bind(&MockErrorCallback::Run, 405 base::Unretained(&error_callback))); 406 407 // Run the message loop. 408 message_loop_.RunUntilIdle(); 409 } 410 411 } // namespace chromeos 412