diff options
Diffstat (limited to 'chromeos')
-rw-r--r-- | chromeos/chromeos.gyp | 7 | ||||
-rw-r--r-- | chromeos/dbus/ibus/ibus_input_context_client.cc | 431 | ||||
-rw-r--r-- | chromeos/dbus/ibus/ibus_input_context_client.h | 120 | ||||
-rw-r--r-- | chromeos/dbus/ibus/ibus_input_context_client_unittest.cc | 476 | ||||
-rw-r--r-- | chromeos/dbus/ibus/mock_ibus_input_context_client.cc | 13 | ||||
-rw-r--r-- | chromeos/dbus/ibus/mock_ibus_input_context_client.h | 49 |
6 files changed, 1096 insertions, 0 deletions
diff --git a/chromeos/chromeos.gyp b/chromeos/chromeos.gyp index 944aa4e..2b05ac1 100644 --- a/chromeos/chromeos.gyp +++ b/chromeos/chromeos.gyp @@ -76,6 +76,8 @@ 'dbus/ibus/ibus_object.h', 'dbus/ibus/ibus_text.cc', 'dbus/ibus/ibus_text.h', + 'dbus/ibus/ibus_input_context_client.cc', + 'dbus/ibus/ibus_input_context_client.h', 'dbus/image_burner_client.cc', 'dbus/image_burner_client.h', 'dbus/introspectable_client.cc', @@ -106,6 +108,8 @@ 'sources': [ 'dbus/ibus/mock_ibus_client.cc', 'dbus/ibus/mock_ibus_client.h', + 'dbus/ibus/mock_ibus_input_context_client.cc', + 'dbus/ibus/mock_ibus_input_context_client.h', 'dbus/mock_bluetooth_adapter_client.cc', 'dbus/mock_bluetooth_adapter_client.h', 'dbus/mock_bluetooth_device_client.cc', @@ -152,6 +156,8 @@ 'dbus/mock_speech_synthesizer_client.h', 'dbus/mock_update_engine_client.cc', 'dbus/mock_update_engine_client.h', + 'dbus/ibus/mock_ibus_input_context_client.cc', + 'dbus/ibus/mock_ibus_input_context_client.h', ], 'include_dirs': [ '..', @@ -183,6 +189,7 @@ 'dbus/ibus/ibus_client_unittest.cc', 'dbus/ibus/ibus_object_unittest.cc', 'dbus/ibus/ibus_text_unittest.cc', + 'dbus/ibus/ibus_input_context_client_unittest.cc', 'network/network_sms_handler_unittest.cc', ], 'include_dirs': [ diff --git a/chromeos/dbus/ibus/ibus_input_context_client.cc b/chromeos/dbus/ibus/ibus_input_context_client.cc new file mode 100644 index 0000000..10e7d6f --- /dev/null +++ b/chromeos/dbus/ibus/ibus_input_context_client.cc @@ -0,0 +1,431 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chromeos/dbus/ibus/ibus_input_context_client.h" + +#include <string> +#include "base/bind.h" +#include "base/callback.h" +#include "chromeos/dbus/ibus/ibus_constants.h" +#include "chromeos/dbus/ibus/ibus_text.h" +#include "dbus/bus.h" +#include "dbus/message.h" +#include "dbus/object_path.h" +#include "dbus/object_proxy.h" + +namespace chromeos { + +// TODO(nona): Remove after complete libibus removal. +using chromeos::ibus::IBusText; + +namespace { +const char kIBusInputContextInterface[] = "org.freedesktop.IBus.InputContext"; + +// Signal names. +const char kCommitTextSignal[] = "CommitText"; +const char kForwardKeyEventSignal[] = "ForwardKeyEvent"; +const char kHidePreeditTextSignal[] = "HidePreeditText"; +const char kShowPreeditTextSignal[] = "ShowPreeditText"; +const char kUpdatePreeditTextSignal[] = "UpdatePreeditText"; + +// Method names. +const char kFocusInMethod[] = "FocusIn"; +const char kFocusOutMethod[] = "FocusOut"; +const char kResetMethod[] = "Reset"; +const char kSetCapabilitiesMethod[] = "SetCapabilities"; +const char kSetCursorLocationMethod[] = "SetCursorLocation"; +const char kProcessKeyEventMethod[] = "ProcessKeyEvent"; + +// The IBusInputContextClient implementation. +class IBusInputContextClientImpl : public IBusInputContextClient { + public: + IBusInputContextClientImpl() + : proxy_(NULL), + weak_ptr_factory_(this) { + } + + virtual ~IBusInputContextClientImpl() {} + + public: + // IBusInputContextClient override. + virtual void Initialize(dbus::Bus* bus, + const dbus::ObjectPath& object_path) OVERRIDE { + if (proxy_ != NULL) { + LOG(ERROR) << "IBusInputContextClient is already initialized."; + return; + } + proxy_ = bus->GetObjectProxy(kIBusServiceName, object_path); + + ConnectSignals(); + } + + // IBusInputContextClient override. + virtual void ResetObjectProxy() OVERRIDE { + // Do not delete proxy here, proxy object is managed by dbus::Bus object. + proxy_ = NULL; + } + + // IBusInputContextClient override. + virtual bool IsConnected() const OVERRIDE { + return proxy_ != NULL; + } + + // IBusInputContextClient override. + virtual void SetCommitTextHandler( + const CommitTextHandler& commit_text_handler) OVERRIDE { + DCHECK(!commit_text_handler.is_null()); + commit_text_handler_ = commit_text_handler; + } + + // IBusInputContextClient override. + virtual void SetForwardKeyEventHandler( + const ForwardKeyEventHandler& forward_key_event_handler) OVERRIDE { + DCHECK(!forward_key_event_handler.is_null()); + forward_key_event_handler_ = forward_key_event_handler; + } + + // IBusInputContextClient override. + virtual void SetUpdatePreeditTextHandler( + const UpdatePreeditTextHandler& update_preedit_text_handler) OVERRIDE { + DCHECK(!update_preedit_text_handler.is_null()); + update_preedit_text_handler_ = update_preedit_text_handler; + } + + // IBusInputContextClient override. + virtual void SetShowPreeditTextHandler( + const ShowPreeditTextHandler& show_preedit_text_handler) OVERRIDE { + DCHECK(!show_preedit_text_handler.is_null()); + show_preedit_text_handler_ = show_preedit_text_handler; + } + + // IBusInputContextClient override. + virtual void SetHidePreeditTextHandler( + const HidePreeditTextHandler& hide_preedit_text_handler) OVERRIDE { + DCHECK(!hide_preedit_text_handler.is_null()); + hide_preedit_text_handler_ = hide_preedit_text_handler; + } + + // IBusInputContextClient override. + virtual void UnsetCommitTextHandler() OVERRIDE { + commit_text_handler_.Reset(); + } + + // IBusInputContextClient override. + virtual void UnsetForwardKeyEventHandler() OVERRIDE { + forward_key_event_handler_.Reset(); + } + + // IBusInputContextClient override. + virtual void UnsetUpdatePreeditTextHandler() OVERRIDE { + update_preedit_text_handler_.Reset(); + } + + // IBusInputContextClient override. + virtual void UnsetShowPreeditTextHandler() OVERRIDE { + show_preedit_text_handler_.Reset(); + } + + // IBusInputContextClient override. + virtual void UnsetHidePreeditTextHandler() OVERRIDE { + hide_preedit_text_handler_.Reset(); + } + + // IBusInputContextClient override. + virtual void SetCapabilities(uint32 capabilities) OVERRIDE { + dbus::MethodCall method_call(kIBusInputContextInterface, + kSetCapabilitiesMethod); + dbus::MessageWriter writer(&method_call); + writer.AppendUint32(capabilities); + proxy_->CallMethod(&method_call, + dbus::ObjectProxy::TIMEOUT_USE_DEFAULT, + base::Bind(&IBusInputContextClientImpl::DefaultCallback, + kSetCapabilitiesMethod)); + } + + // IBusInputContextClient override. + virtual void FocusIn() OVERRIDE { + dbus::MethodCall method_call(kIBusInputContextInterface, kFocusInMethod); + proxy_->CallMethod(&method_call, + dbus::ObjectProxy::TIMEOUT_USE_DEFAULT, + base::Bind(&IBusInputContextClientImpl::DefaultCallback, + kFocusInMethod)); + } + + // IBusInputContextClient override. + virtual void FocusOut() OVERRIDE { + dbus::MethodCall method_call(kIBusInputContextInterface, kFocusOutMethod); + proxy_->CallMethod(&method_call, + dbus::ObjectProxy::TIMEOUT_USE_DEFAULT, + base::Bind(&IBusInputContextClientImpl::DefaultCallback, + kFocusOutMethod)); + } + + // IBusInputContextClient override. + virtual void Reset() OVERRIDE { + dbus::MethodCall method_call(kIBusInputContextInterface, kResetMethod); + proxy_->CallMethod(&method_call, + dbus::ObjectProxy::TIMEOUT_USE_DEFAULT, + base::Bind(&IBusInputContextClientImpl::DefaultCallback, + kResetMethod)); + } + + // IBusInputContextClient override. + virtual void SetCursorLocation(int32 x, int32 y, int32 width, + int32 height) OVERRIDE { + dbus::MethodCall method_call(kIBusInputContextInterface, + kSetCursorLocationMethod); + dbus::MessageWriter writer(&method_call); + writer.AppendInt32(x); + writer.AppendInt32(y); + writer.AppendInt32(width); + writer.AppendInt32(height); + proxy_->CallMethod(&method_call, + dbus::ObjectProxy::TIMEOUT_USE_DEFAULT, + base::Bind(&IBusInputContextClientImpl::DefaultCallback, + kSetCursorLocationMethod)); + } + + // IBusInputContextClient override. + virtual void ProcessKeyEvent( + uint32 keyval, + uint32 keycode, + uint32 state, + const ProcessKeyEventCallback& callback) OVERRIDE { + dbus::MethodCall method_call(kIBusInputContextInterface, + kProcessKeyEventMethod); + dbus::MessageWriter writer(&method_call); + writer.AppendUint32(keyval); + writer.AppendUint32(keycode); + writer.AppendUint32(state); + proxy_->CallMethod( + &method_call, + dbus::ObjectProxy::TIMEOUT_USE_DEFAULT, + base::Bind(&IBusInputContextClientImpl::OnProcessKeyEvent, + callback)); + } + + private: + // Handles no response method call reply. + static void DefaultCallback(const std::string& method_name, + dbus::Response* response) { + if (!response) { + LOG(ERROR) << "Failed to call method: " << method_name; + return; + } + } + + // Handles ProcessKeyEvent method call reply. + static void OnProcessKeyEvent(const ProcessKeyEventCallback& callback, + dbus::Response* response) { + if (!response) { + LOG(ERROR) << "Cannot get input context: " << response->ToString(); + return; + } + dbus::MessageReader reader(response); + bool is_keyevent_used; + if (!reader.PopBool(&is_keyevent_used)) { + // The IBus message structure may be changed. + LOG(ERROR) << "Invalid response: " << response->ToString(); + return; + } + DCHECK(!callback.is_null()); + callback.Run(is_keyevent_used); + } + + // Handles CommitText signal. + void OnCommitText(dbus::Signal* signal) { + if (commit_text_handler_.is_null()) + return; + dbus::MessageReader reader(signal); + IBusText ibus_text; + if (!PopIBusText(&reader, &ibus_text)) { + // The IBus message structure may be changed. + LOG(ERROR) << "Invalid signal: " << signal->ToString(); + return; + } + commit_text_handler_.Run(ibus_text); + } + + // Handles ForwardKeyEvetn signal. + void OnForwardKeyEvent(dbus::Signal* signal) { + if (forward_key_event_handler_.is_null()) + return; + dbus::MessageReader reader(signal); + uint32 keyval = 0; + uint32 keycode = 0; + uint32 state = 0; + if (!reader.PopUint32(&keyval) || + !reader.PopUint32(&keycode) || + !reader.PopUint32(&state)) { + // The IBus message structure may be changed. + LOG(ERROR) << "Invalid signal: " << signal->ToString(); + return; + } + forward_key_event_handler_.Run(keyval, keycode, state); + } + + // Handles UpdatePreeditText signal. + void OnUpdatePreeditText(dbus::Signal* signal) { + if (update_preedit_text_handler_.is_null()) + return; + dbus::MessageReader reader(signal); + IBusText ibus_text; + uint32 cursor_pos = 0; + bool visible = true; + if (!PopIBusText(&reader, &ibus_text) || + !reader.PopUint32(&cursor_pos) || + !reader.PopBool(&visible)) { + // The IBus message structure may be changed. + LOG(ERROR) << "Invalid signal: " << signal->ToString(); + return; + } + update_preedit_text_handler_.Run(ibus_text, cursor_pos, visible); + } + + // Handles ShowPreeditText signal. + void OnShowPreeditText(dbus::Signal* signal) { + if (!show_preedit_text_handler_.is_null()) + show_preedit_text_handler_.Run(); + } + + // Handles HidePreeditText signal. + void OnHidePreeditText(dbus::Signal* signal) { + if (!hide_preedit_text_handler_.is_null()) + hide_preedit_text_handler_.Run(); + } + + // Connects signals to signal handlers. + void ConnectSignals() { + proxy_->ConnectToSignal( + kIBusInputContextInterface, + kCommitTextSignal, + base::Bind(&IBusInputContextClientImpl::OnCommitText, + weak_ptr_factory_.GetWeakPtr()), + base::Bind(&IBusInputContextClientImpl::OnSignalConnected, + weak_ptr_factory_.GetWeakPtr())); + + proxy_->ConnectToSignal( + kIBusInputContextInterface, + kForwardKeyEventSignal, + base::Bind(&IBusInputContextClientImpl::OnForwardKeyEvent, + weak_ptr_factory_.GetWeakPtr()), + base::Bind(&IBusInputContextClientImpl::OnSignalConnected, + weak_ptr_factory_.GetWeakPtr())); + + proxy_->ConnectToSignal( + kIBusInputContextInterface, + kUpdatePreeditTextSignal, + base::Bind(&IBusInputContextClientImpl::OnUpdatePreeditText, + weak_ptr_factory_.GetWeakPtr()), + base::Bind(&IBusInputContextClientImpl::OnSignalConnected, + weak_ptr_factory_.GetWeakPtr())); + + proxy_->ConnectToSignal( + kIBusInputContextInterface, + kShowPreeditTextSignal, + base::Bind(&IBusInputContextClientImpl::OnShowPreeditText, + weak_ptr_factory_.GetWeakPtr()), + base::Bind(&IBusInputContextClientImpl::OnSignalConnected, + weak_ptr_factory_.GetWeakPtr())); + + proxy_->ConnectToSignal( + kIBusInputContextInterface, + kHidePreeditTextSignal, + base::Bind(&IBusInputContextClientImpl::OnHidePreeditText, + weak_ptr_factory_.GetWeakPtr()), + base::Bind(&IBusInputContextClientImpl::OnSignalConnected, + weak_ptr_factory_.GetWeakPtr())); + } + + // Handles the result of signal connection setup. + void OnSignalConnected(const std::string& interface, + const std::string& signal, + bool succeeded) { + LOG_IF(ERROR, !succeeded) << "Connect to " << interface << " " + << signal << " failed."; + } + + dbus::ObjectProxy* proxy_; + + // Signal handlers. + CommitTextHandler commit_text_handler_; + ForwardKeyEventHandler forward_key_event_handler_; + HidePreeditTextHandler hide_preedit_text_handler_; + ShowPreeditTextHandler show_preedit_text_handler_; + UpdatePreeditTextHandler update_preedit_text_handler_; + + base::WeakPtrFactory<IBusInputContextClientImpl> weak_ptr_factory_; + + DISALLOW_COPY_AND_ASSIGN(IBusInputContextClientImpl); +}; + +// A stub implementation of IBusInputContextClient. +class IBusInputContextClientStubImpl : public IBusInputContextClient { + public: + IBusInputContextClientStubImpl() {} + + virtual ~IBusInputContextClientStubImpl() {} + + public: + // IBusInputContextClient override. + virtual void Initialize(dbus::Bus* bus, + const dbus::ObjectPath& object_path) OVERRIDE {} + // IBusInputContextClient override. + virtual void ResetObjectProxy() OVERRIDE {} + // IBusInputContextClient override. + virtual bool IsConnected() const OVERRIDE { + return true; + } + // IBusInputContextClient overrides. + virtual void SetCommitTextHandler( + const CommitTextHandler& commit_text_handler) OVERRIDE {} + virtual void SetForwardKeyEventHandler( + const ForwardKeyEventHandler& forward_key_event_handler) OVERRIDE {} + virtual void SetUpdatePreeditTextHandler( + const UpdatePreeditTextHandler& update_preedit_text_handler) OVERRIDE {} + virtual void SetShowPreeditTextHandler( + const ShowPreeditTextHandler& show_preedit_text_handler) OVERRIDE {} + virtual void SetHidePreeditTextHandler( + const HidePreeditTextHandler& hide_preedit_text_handler) OVERRIDE {} + virtual void UnsetCommitTextHandler() OVERRIDE {} + virtual void UnsetForwardKeyEventHandler() OVERRIDE {} + virtual void UnsetUpdatePreeditTextHandler() OVERRIDE {} + virtual void UnsetShowPreeditTextHandler() OVERRIDE {} + virtual void UnsetHidePreeditTextHandler() OVERRIDE {} + virtual void SetCapabilities(uint32 capability) OVERRIDE {} + virtual void FocusIn() OVERRIDE {} + virtual void FocusOut() OVERRIDE {} + virtual void Reset() OVERRIDE {} + virtual void SetCursorLocation(int32 x, int32 y, int32 w, int32 h) OVERRIDE {} + virtual void ProcessKeyEvent( + uint32 keyval, + uint32 keycode, + uint32 state, + const ProcessKeyEventCallback& callback) OVERRIDE { + callback.Run(false); + } + + private: + DISALLOW_COPY_AND_ASSIGN(IBusInputContextClientStubImpl); +}; + +} // namespace + +/////////////////////////////////////////////////////////////////////////////// +// IBusInputContextClient + +IBusInputContextClient::IBusInputContextClient() {} + +IBusInputContextClient::~IBusInputContextClient() {} + +// static +IBusInputContextClient* IBusInputContextClient::Create( + DBusClientImplementationType type) { + if (type == REAL_DBUS_CLIENT_IMPLEMENTATION) { + return new IBusInputContextClientImpl(); + } + DCHECK_EQ(STUB_DBUS_CLIENT_IMPLEMENTATION, type); + return new IBusInputContextClientStubImpl(); +} +} // namespace chromeos diff --git a/chromeos/dbus/ibus/ibus_input_context_client.h b/chromeos/dbus/ibus/ibus_input_context_client.h new file mode 100644 index 0000000..3b543f2 --- /dev/null +++ b/chromeos/dbus/ibus/ibus_input_context_client.h @@ -0,0 +1,120 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CHROMEOS_DBUS_IBUS_IBUS_INPUT_CONTEXT_CLIENT_H_ +#define CHROMEOS_DBUS_IBUS_IBUS_INPUT_CONTEXT_CLIENT_H_ +#pragma once + +#include "base/bind.h" +#include "base/callback.h" +#include "chromeos/chromeos_export.h" +#include "chromeos/dbus/dbus_client_implementation_type.h" +#include "dbus/object_path.h" + +namespace dbus { +class Bus; +} // namespace dbus + +namespace chromeos { + +// TODO(nona): Remove ibus namespace after complete libibus removal. +namespace ibus { +class IBusText; +} // namespace + +// A class to make the actual DBus calls for IBusInputContext service. +// The ibus-daemon creates object paths on demand, so the target object path is +// not determined before calling CreateInputContext. It is good to initialize +// this class at the callback from CreateInputContext in IBusClient. This class +// is managed by DBusThreadManager as singleton instance, so we can handle only +// one input context but it is enough for ChromeOS. +class CHROMEOS_EXPORT IBusInputContextClient { + public: + typedef base::Callback<void(const ibus::IBusText& text)> CommitTextHandler; + typedef base::Callback<void(uint32 keyval, uint32 keycode, uint32 state)> + ForwardKeyEventHandler; + typedef base::Callback<void(const ibus::IBusText& text, + uint32 cursor_pos, + bool visible)> + UpdatePreeditTextHandler; + typedef base::Callback<void()> ShowPreeditTextHandler; + typedef base::Callback<void()> HidePreeditTextHandler; + typedef base::Callback<void(bool is_keyevent_used)> ProcessKeyEventCallback; + + virtual ~IBusInputContextClient(); + + // Creates object proxy and connects signals. + virtual void Initialize(dbus::Bus* bus, + const dbus::ObjectPath& object_path) = 0; + + // Resets object proxy. If you want to use InputContext again, should call + // Initialize function again. + virtual void ResetObjectProxy() = 0; + + // Returns true if connected to target input context path, otherwise return + // false. + virtual bool IsConnected() const = 0; + + // Signal handler accessors. Setting function can be called multiple times. If + // you call setting function multiple times, previous callback will be + // overwritten. + // Sets CommitText signal handler. + virtual void SetCommitTextHandler( + const CommitTextHandler& commit_text_handler) = 0; + // Sets ForwardKeyEvent signal handler. + virtual void SetForwardKeyEventHandler( + const ForwardKeyEventHandler& forward_key_event_handler) = 0; + // Sets UpdatePreeditText signal handler. + virtual void SetUpdatePreeditTextHandler( + const UpdatePreeditTextHandler& update_preedit_text_handler) = 0; + // Sets ShowPreeditText signal handler. + virtual void SetShowPreeditTextHandler( + const ShowPreeditTextHandler& show_preedit_text_handler) = 0; + // Sets HidePreeditText signal handler. + virtual void SetHidePreeditTextHandler( + const HidePreeditTextHandler& hide_preedit_text_handler) = 0; + // Unsets CommitText signal handler. + virtual void UnsetCommitTextHandler() = 0; + // Unsets FowardKeyEvent signal handler. + virtual void UnsetForwardKeyEventHandler() = 0; + // Unsets UpdatePreeditText signal handler. + virtual void UnsetUpdatePreeditTextHandler() = 0; + // Unsets ShowPreeditText signal handler. + virtual void UnsetShowPreeditTextHandler() = 0; + // Unsets HidePreeditText signal handler. + virtual void UnsetHidePreeditTextHandler() = 0; + + // Invokes SetCapabilities method call. + virtual void SetCapabilities(uint32 capability) = 0; + // Invokes FocusIn method call. + virtual void FocusIn() = 0; + // Invokes FocusOut method call. + virtual void FocusOut() = 0; + // Invokes Reset method call. + virtual void Reset() = 0; + // Invokes SetCursorLocation method call. + virtual void SetCursorLocation(int32 x, int32 y, int32 width, + int32 height) = 0; + // Invokes ProcessKeyEvent method call. |callback| shold not be null-callback. + virtual void ProcessKeyEvent(uint32 keyval, + uint32 keycode, + uint32 state, + const ProcessKeyEventCallback& callback) = 0; + + // Factory function, creates a new instance and returns ownership. + // For normal usage, access the singleton via DBusThreadManager::Get(). + static CHROMEOS_EXPORT IBusInputContextClient* Create( + DBusClientImplementationType type); + + protected: + // Create() should be used instead. + IBusInputContextClient(); + + private: + DISALLOW_COPY_AND_ASSIGN(IBusInputContextClient); +}; + +} // namespace chromeos + +#endif // CHROMEOS_DBUS_IBUS_IBUS_INPUT_CONTEXT_CLIENT_H_ diff --git a/chromeos/dbus/ibus/ibus_input_context_client_unittest.cc b/chromeos/dbus/ibus/ibus_input_context_client_unittest.cc new file mode 100644 index 0000000..c4429b1 --- /dev/null +++ b/chromeos/dbus/ibus/ibus_input_context_client_unittest.cc @@ -0,0 +1,476 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chromeos/dbus/ibus/ibus_input_context_client.h" + +#include <map> +#include <string> +#include "base/message_loop.h" +#include "chromeos/dbus/ibus/ibus_text.h" +#include "dbus/message.h" +#include "dbus/mock_bus.h" +#include "dbus/mock_object_proxy.h" +#include "testing/gmock/include/gmock/gmock.h" +#include "testing/gtest/include/gtest/gtest.h" + +using ::testing::Invoke; +using ::testing::Return; +using ::testing::_; + +namespace chromeos { + +// TODO(nona): Remove after complete libibus removal. +using chromeos::ibus::IBusText; + +namespace { +const char kServiceName[] = "org.freedesktop.IBus"; +const char kInputContextInterface[] = "org.freedesktop.IBus.InputContext"; +const char kObjectPath[] = "/org/freedesktop/IBus/InputContext_1010"; + +// Signal names. +const char kCommitTextSignal[] = "CommitText"; +const char kForwardKeyEventSignal[] = "ForwardKeyEvent"; +const char kHidePreeditTextSignal[] = "HidePreeditText"; +const char kShowPreeditTextSignal[] = "ShowPreeditText"; +const char kUpdatePreeditTextSignal[] = "UpdatePreeditText"; + +// Method names. +const char kFocusInMethod[] = "FocusIn"; +const char kFocusOutMethod[] = "FocusOut"; +const char kResetMethod[] = "Reset"; +const char kSetCapabilitiesMethod[] = "SetCapabilities"; +const char kSetCursorLocationMethod[] = "SetCursorLocation"; +const char kProcessKeyEventMethod[] = "ProcessKeyEvent"; + +// Following variables are used in callback expectations. +const uint32 kCapabilities = 12345; +const int32 kCursorX = 30; +const int32 kCursorY = 31; +const int32 kCursorWidth = 32; +const int32 kCursorHeight = 33; +const uint32 kKeyval = 34; +const uint32 kKeycode = 35; +const uint32 kState = 36; +const bool kIsKeyHandled = false; + +class MockCommitTextHandler { + public: + MOCK_METHOD1(Run, void(const IBusText& text)); +}; + +class MockForwardKeyEventHandler { + public: + MOCK_METHOD3(Run, void(uint32 keyval, uint32 keycode, uint32 state)); +}; + +class MockHidePreeditTextHandler { + public: + MOCK_METHOD0(Run, void()); +}; + +class MockShowPreeditTextHandler { + public: + MOCK_METHOD0(Run, void()); +}; + +class MockUpdatePreeditTextHandler { + public: + MOCK_METHOD3(Run, void(const IBusText& text, uint32 cursor_pos, + bool visible)); +}; + +class MockProcessKeyEventHandler { + public: + MOCK_METHOD1(Run, void(bool is_key_handled)); +}; + +MATCHER_P(IBusTextEq, expected_text, "The expected IBusText does not match") { + // TODO(nona): Check attributes. + return (arg.text() == expected_text->text()); +} + +} // namespace + +class IBusInputContextClientTest : public testing::Test { + public: + IBusInputContextClientTest() : response_(NULL) {} + + virtual void SetUp() OVERRIDE { + // Create a mock bus. + dbus::Bus::Options options; + options.bus_type = dbus::Bus::SYSTEM; + mock_bus_ = new dbus::MockBus(options); + + // Create a mock proxy. + mock_proxy_ = new dbus::MockObjectProxy(mock_bus_.get(), + kServiceName, + dbus::ObjectPath(kObjectPath)); + + // Create a client. + client_.reset(IBusInputContextClient::Create( + REAL_DBUS_CLIENT_IMPLEMENTATION)); + + // Set an expectation so mock_bus's GetObjectProxy() for the given service + // name and the object path will return mock_proxy_. The GetObjectProxy + // function is called in Initialized function. + EXPECT_CALL(*mock_bus_, GetObjectProxy(kServiceName, + dbus::ObjectPath(kObjectPath))) + .WillOnce(Return(mock_proxy_.get())); + + // Set expectations so mock_proxy's ConnectToSignal will use + // OnConnectToSignal() to run the callback. The ConnectToSignal is called in + // Initialize function. + EXPECT_CALL(*mock_proxy_, ConnectToSignal( + kInputContextInterface, kCommitTextSignal, _, _)) + .WillRepeatedly( + Invoke(this, &IBusInputContextClientTest::OnConnectToSignal)); + EXPECT_CALL(*mock_proxy_, ConnectToSignal( + kInputContextInterface, kForwardKeyEventSignal, _, _)) + .WillRepeatedly( + Invoke(this, &IBusInputContextClientTest::OnConnectToSignal)); + EXPECT_CALL(*mock_proxy_, ConnectToSignal( + kInputContextInterface, kHidePreeditTextSignal, _, _)) + .WillRepeatedly( + Invoke(this, &IBusInputContextClientTest::OnConnectToSignal)); + EXPECT_CALL(*mock_proxy_, ConnectToSignal( + kInputContextInterface, kShowPreeditTextSignal, _, _)) + .WillRepeatedly( + Invoke(this, &IBusInputContextClientTest::OnConnectToSignal)); + EXPECT_CALL(*mock_proxy_, ConnectToSignal( + kInputContextInterface, kUpdatePreeditTextSignal, _, _)) + .WillRepeatedly( + Invoke(this, &IBusInputContextClientTest::OnConnectToSignal)); + + // Call Initialize to create object proxy and connect signals. + client_->Initialize(mock_bus_.get(), dbus::ObjectPath(kObjectPath)); + } + + virtual void TearDown() OVERRIDE { + EXPECT_TRUE(client_->IsConnected()); + client_->ResetObjectProxy(); + EXPECT_FALSE(client_->IsConnected()); + } + + // Handles FocusIn method call. + void OnFocusIn(dbus::MethodCall* method_call, + int timeout_ms, + const dbus::ObjectProxy::ResponseCallback& callback) { + EXPECT_EQ(kInputContextInterface, method_call->GetInterface()); + EXPECT_EQ(kFocusInMethod, method_call->GetMember()); + dbus::MessageReader reader(method_call); + EXPECT_FALSE(reader.HasMoreData()); + + message_loop_.PostTask(FROM_HERE, base::Bind(callback, response_)); + } + + // Handles FocusOut method call. + void OnFocusOut(dbus::MethodCall* method_call, + int timeout_ms, + const dbus::ObjectProxy::ResponseCallback& callback) { + EXPECT_EQ(kInputContextInterface, method_call->GetInterface()); + EXPECT_EQ(kFocusOutMethod, method_call->GetMember()); + dbus::MessageReader reader(method_call); + EXPECT_FALSE(reader.HasMoreData()); + + message_loop_.PostTask(FROM_HERE, base::Bind(callback, response_)); + } + + // Handles Reset method call. + void OnReset(dbus::MethodCall* method_call, + int timeout_ms, + const dbus::ObjectProxy::ResponseCallback& callback) { + EXPECT_EQ(kInputContextInterface, method_call->GetInterface()); + EXPECT_EQ(kResetMethod, method_call->GetMember()); + dbus::MessageReader reader(method_call); + EXPECT_FALSE(reader.HasMoreData()); + + message_loop_.PostTask(FROM_HERE, base::Bind(callback, response_)); + } + + // Handles SetCursorLocation method call. + void OnSetCursorLocation( + dbus::MethodCall* method_call, + int timeout_ms, + const dbus::ObjectProxy::ResponseCallback& callback) { + EXPECT_EQ(kInputContextInterface, method_call->GetInterface()); + EXPECT_EQ(kSetCursorLocationMethod, method_call->GetMember()); + dbus::MessageReader reader(method_call); + int32 x, y, width, height; + EXPECT_TRUE(reader.PopInt32(&x)); + EXPECT_TRUE(reader.PopInt32(&y)); + EXPECT_TRUE(reader.PopInt32(&width)); + EXPECT_TRUE(reader.PopInt32(&height)); + EXPECT_FALSE(reader.HasMoreData()); + + message_loop_.PostTask(FROM_HERE, base::Bind(callback, response_)); + } + + // Handles SetCapabilities method call. + void OnSetCapabilities(dbus::MethodCall* method_call, + int timeout_ms, + const dbus::ObjectProxy::ResponseCallback& callback) { + EXPECT_EQ(kInputContextInterface, method_call->GetInterface()); + EXPECT_EQ(kSetCapabilitiesMethod, method_call->GetMember()); + uint32 capabilities; + dbus::MessageReader reader(method_call); + EXPECT_TRUE(reader.PopUint32(&capabilities)); + EXPECT_EQ(kCapabilities, capabilities); + EXPECT_FALSE(reader.HasMoreData()); + + message_loop_.PostTask(FROM_HERE, base::Bind(callback, response_)); + } + + // Handles ProcessKeyEvent method call. + void OnProcessKeyEvent(dbus::MethodCall* method_call, + int timeout_ms, + const dbus::ObjectProxy::ResponseCallback& callback) { + EXPECT_EQ(kInputContextInterface, method_call->GetInterface()); + EXPECT_EQ(kProcessKeyEventMethod, method_call->GetMember()); + uint32 keyval, keycode, state; + dbus::MessageReader reader(method_call); + EXPECT_TRUE(reader.PopUint32(&keyval)); + EXPECT_TRUE(reader.PopUint32(&keycode)); + EXPECT_TRUE(reader.PopUint32(&state)); + EXPECT_FALSE(reader.HasMoreData()); + + message_loop_.PostTask(FROM_HERE, base::Bind(callback, response_)); + } + + protected: + // The client to be tested. + scoped_ptr<IBusInputContextClient> client_; + // The mock bus. + scoped_refptr<dbus::MockBus> mock_bus_; + // The mock object proxy. + scoped_refptr<dbus::MockObjectProxy> mock_proxy_; + // Response returned by mock methods. + dbus::Response* response_; + // A message loop to emulate asynchronous behavior. + MessageLoop message_loop_; + // The map from signal to signal handler. + std::map<std::string, dbus::ObjectProxy::SignalCallback> signal_callback_map_; + + private: + // Used to implement the mock proxy. + void OnConnectToSignal( + const std::string& interface_name, + const std::string& signal_name, + const dbus::ObjectProxy::SignalCallback& signal_callback, + const dbus::ObjectProxy::OnConnectedCallback& on_connected_callback) { + signal_callback_map_[signal_name] = signal_callback; + const bool success = true; + message_loop_.PostTask(FROM_HERE, base::Bind(on_connected_callback, + interface_name, + signal_name, + success)); + } +}; + +TEST_F(IBusInputContextClientTest, CommitTextHandler) { + const char kSampleText[] = "Sample Text"; + IBusText ibus_text; + ibus_text.set_text(kSampleText); + + // Set handler expectations. + MockCommitTextHandler handler; + EXPECT_CALL(handler, Run(IBusTextEq(&ibus_text))); + client_->SetCommitTextHandler(base::Bind(&MockCommitTextHandler::Run, + base::Unretained(&handler))); + message_loop_.RunAllPending(); + + // Emit signal. + dbus::Signal signal(kInputContextInterface, kCommitTextSignal); + dbus::MessageWriter writer(&signal); + AppendIBusText(ibus_text, &writer); + ASSERT_FALSE(signal_callback_map_[kCommitTextSignal].is_null()); + signal_callback_map_[kCommitTextSignal].Run(&signal); + + // Unset the handler so expect not calling handler. + client_->UnsetCommitTextHandler(); + signal_callback_map_[kCommitTextSignal].Run(&signal); +} + +TEST_F(IBusInputContextClientTest, ForwardKeyEventHandlerTest) { + // Set handler expectations. + MockForwardKeyEventHandler handler; + EXPECT_CALL(handler, Run(kKeyval, kKeycode, kState)); + client_->SetForwardKeyEventHandler( + base::Bind(&MockForwardKeyEventHandler::Run, + base::Unretained(&handler))); + message_loop_.RunAllPending(); + + // Emit signal. + dbus::Signal signal(kInputContextInterface, kForwardKeyEventSignal); + dbus::MessageWriter writer(&signal); + writer.AppendUint32(kKeyval); + writer.AppendUint32(kKeycode); + writer.AppendUint32(kState); + ASSERT_FALSE(signal_callback_map_[kForwardKeyEventSignal].is_null()); + signal_callback_map_[kForwardKeyEventSignal].Run(&signal); + + // Unset the handler so expect not calling handler. + client_->UnsetForwardKeyEventHandler(); + signal_callback_map_[kForwardKeyEventSignal].Run(&signal); +} + +TEST_F(IBusInputContextClientTest, HidePreeditTextHandlerTest) { + // Set handler expectations. + MockHidePreeditTextHandler handler; + EXPECT_CALL(handler, Run()); + client_->SetHidePreeditTextHandler( + base::Bind(&MockHidePreeditTextHandler::Run, + base::Unretained(&handler))); + message_loop_.RunAllPending(); + + // Emit signal. + dbus::Signal signal(kInputContextInterface, kHidePreeditTextSignal); + ASSERT_FALSE(signal_callback_map_[kHidePreeditTextSignal].is_null()); + signal_callback_map_[kHidePreeditTextSignal].Run(&signal); + + // Unset the handler so expect not calling handler. + client_->UnsetHidePreeditTextHandler(); + signal_callback_map_[kHidePreeditTextSignal].Run(&signal); +} + +TEST_F(IBusInputContextClientTest, ShowPreeditTextHandlerTest) { + // Set handler expectations. + MockShowPreeditTextHandler handler; + EXPECT_CALL(handler, Run()); + client_->SetShowPreeditTextHandler( + base::Bind(&MockShowPreeditTextHandler::Run, + base::Unretained(&handler))); + message_loop_.RunAllPending(); + + // Emit signal. + dbus::Signal signal(kInputContextInterface, kShowPreeditTextSignal); + ASSERT_FALSE(signal_callback_map_[kShowPreeditTextSignal].is_null()); + signal_callback_map_[kShowPreeditTextSignal].Run(&signal); + + // Unset the handler so expect not calling handler. + client_->UnsetShowPreeditTextHandler(); + signal_callback_map_[kShowPreeditTextSignal].Run(&signal); +} + +TEST_F(IBusInputContextClientTest, UpdatePreeditTextHandlerTest) { + const uint32 kCursorPos = 20; + const bool kVisible = false; + const char kSampleText[] = "Sample Text"; + IBusText ibus_text; + ibus_text.set_text(kSampleText); + + // Set handler expectations. + MockUpdatePreeditTextHandler handler; + EXPECT_CALL(handler, Run(IBusTextEq(&ibus_text), kCursorPos, kVisible)); + client_->SetUpdatePreeditTextHandler( + base::Bind(&MockUpdatePreeditTextHandler::Run, + base::Unretained(&handler))); + message_loop_.RunAllPending(); + + // Emit signal. + dbus::Signal signal(kInputContextInterface, kUpdatePreeditTextSignal); + dbus::MessageWriter writer(&signal); + AppendIBusText(ibus_text, &writer); + writer.AppendUint32(kCursorPos); + writer.AppendBool(kVisible); + ASSERT_FALSE(signal_callback_map_[kUpdatePreeditTextSignal].is_null()); + signal_callback_map_[kUpdatePreeditTextSignal].Run(&signal); + + // Unset the handler so expect not calling handler. + client_->UnsetUpdatePreeditTextHandler(); + signal_callback_map_[kUpdatePreeditTextSignal].Run(&signal); +} + +TEST_F(IBusInputContextClientTest, FocusInTest) { + // Set expectations. + EXPECT_CALL(*mock_proxy_, CallMethod(_, _, _)) + .WillOnce(Invoke(this, &IBusInputContextClientTest::OnFocusIn)); + // Create response. + scoped_ptr<dbus::Response> response(dbus::Response::CreateEmpty()); + response_ = response.get(); + + // Call FocusIn. + client_->FocusIn(); + // Run the message loop. + message_loop_.RunAllPending(); +} + +TEST_F(IBusInputContextClientTest, FocusOutTest) { + // Set expectations. + EXPECT_CALL(*mock_proxy_, CallMethod(_, _, _)) + .WillOnce(Invoke(this, &IBusInputContextClientTest::OnFocusOut)); + // Create response. + scoped_ptr<dbus::Response> response(dbus::Response::CreateEmpty()); + response_ = response.get(); + + // Call FocusOut. + client_->FocusOut(); + // Run the message loop. + message_loop_.RunAllPending(); +} + +TEST_F(IBusInputContextClientTest, ResetTest) { + // Set expectations. + EXPECT_CALL(*mock_proxy_, CallMethod(_, _, _)) + .WillOnce(Invoke(this, &IBusInputContextClientTest::OnReset)); + // Create response. + scoped_ptr<dbus::Response> response(dbus::Response::CreateEmpty()); + response_ = response.get(); + + // Call Reset. + client_->Reset(); + // Run the message loop. + message_loop_.RunAllPending(); +} + +TEST_F(IBusInputContextClientTest, SetCapabilitiesTest) { + // Set expectations. + EXPECT_CALL(*mock_proxy_, CallMethod(_, _, _)) + .WillOnce(Invoke(this, &IBusInputContextClientTest::OnSetCapabilities)); + // Create response. + scoped_ptr<dbus::Response> response(dbus::Response::CreateEmpty()); + response_ = response.get(); + + // Call SetCapabilities. + client_->SetCapabilities(kCapabilities); + // Run the message loop. + message_loop_.RunAllPending(); +} + +TEST_F(IBusInputContextClientTest, SetCursorLocationTest) { + // Set expectations. + EXPECT_CALL(*mock_proxy_, CallMethod(_, _, _)) + .WillOnce(Invoke(this, &IBusInputContextClientTest::OnSetCursorLocation)); + // Create response. + scoped_ptr<dbus::Response> response(dbus::Response::CreateEmpty()); + response_ = response.get(); + + // Call SetCursorLocation. + client_->SetCursorLocation(kCursorX, kCursorY, kCursorWidth, kCursorHeight); + // Run the message loop. + message_loop_.RunAllPending(); +} + +TEST_F(IBusInputContextClientTest, OnProcessKeyEvent) { + // Set expectations. + EXPECT_CALL(*mock_proxy_, CallMethod(_, _, _)) + .WillOnce(Invoke(this, &IBusInputContextClientTest::OnProcessKeyEvent)); + MockProcessKeyEventHandler callback; + EXPECT_CALL(callback, Run(kIsKeyHandled)); + // Create response. + scoped_ptr<dbus::Response> response(dbus::Response::CreateEmpty()); + dbus::MessageWriter writer(response.get()); + writer.AppendBool(kIsKeyHandled); + response_ = response.get(); + + // Call ProcessKeyEvent. + client_->ProcessKeyEvent(kKeyval, + kKeycode, + kState, + base::Bind(&MockProcessKeyEventHandler::Run, + base::Unretained(&callback))); + // Run the message loop. + message_loop_.RunAllPending(); +} + +} // namespace chromeos diff --git a/chromeos/dbus/ibus/mock_ibus_input_context_client.cc b/chromeos/dbus/ibus/mock_ibus_input_context_client.cc new file mode 100644 index 0000000..6b0eebf --- /dev/null +++ b/chromeos/dbus/ibus/mock_ibus_input_context_client.cc @@ -0,0 +1,13 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chromeos/dbus/ibus/mock_ibus_input_context_client.h" + +namespace chromeos { + +MockIBusInputContextClient::MockIBusInputContextClient() {} + +MockIBusInputContextClient::~MockIBusInputContextClient() {} + +} // namespace chromeos diff --git a/chromeos/dbus/ibus/mock_ibus_input_context_client.h b/chromeos/dbus/ibus/mock_ibus_input_context_client.h new file mode 100644 index 0000000..e3199b5 --- /dev/null +++ b/chromeos/dbus/ibus/mock_ibus_input_context_client.h @@ -0,0 +1,49 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CHROMEOS_DBUS_IBUS_MOCK_IBUS_INPUT_CONTEXT_CLIENT_H_ +#define CHROMEOS_DBUS_IBUS_MOCK_IBUS_INPUT_CONTEXT_CLIENT_H_ + +#include "chromeos/dbus/ibus/ibus_input_context_client.h" +#include "testing/gmock/include/gmock/gmock.h" + +namespace chromeos { +class MockIBusInputContextClient : public IBusInputContextClient { + public: + MockIBusInputContextClient(); + virtual ~MockIBusInputContextClient(); + + MOCK_METHOD2(Initialize, void(dbus::Bus* bus, + const dbus::ObjectPath& object_path)); + MOCK_METHOD0(ResetObjectProxy, void()); + MOCK_CONST_METHOD0(IsConnected, bool()); + MOCK_METHOD1(SetCommitTextHandler, + void(const CommitTextHandler& commit_text_handler)); + MOCK_METHOD1(SetForwardKeyEventHandler, + void(const ForwardKeyEventHandler& forward_key_event_handler)); + MOCK_METHOD1( + SetUpdatePreeditTextHandler, + void(const UpdatePreeditTextHandler& update_preedit_text_handler)); + MOCK_METHOD1(SetShowPreeditTextHandler, + void(const ShowPreeditTextHandler& show_preedit_text_handler)); + MOCK_METHOD1(SetHidePreeditTextHandler, + void(const HidePreeditTextHandler& hide_preedit_text_handler)); + MOCK_METHOD0(UnsetCommitTextHandler, void()); + MOCK_METHOD0(UnsetForwardKeyEventHandler, void()); + MOCK_METHOD0(UnsetUpdatePreeditTextHandler, void()); + MOCK_METHOD0(UnsetShowPreeditTextHandler, void()); + MOCK_METHOD0(UnsetHidePreeditTextHandler, void()); + MOCK_METHOD1(SetCapabilities, void(uint32 capabilities)); + MOCK_METHOD0(FocusIn, void()); + MOCK_METHOD0(FocusOut, void()); + MOCK_METHOD0(Reset, void()); + MOCK_METHOD4(SetCursorLocation, void(int32 x, int32 y, int32 w, int32 h)); + MOCK_METHOD4(ProcessKeyEvent, void(uint32 keyval, + uint32 keycode, + uint32 state, + const ProcessKeyEventCallback& callback)); +}; +} // namespace chromeos + +#endif // CHROMEOS_DBUS_IBUS_MOCK_IBUS_INPUT_CONTEXT_CLIENT_H_ |