| // 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 <X11/Xlib.h> |
| #undef Bool |
| #undef FocusIn |
| #undef FocusOut |
| #undef None |
| |
| #include <cstring> |
| |
| #include "base/i18n/char_iterator.h" |
| #include "base/memory/scoped_ptr.h" |
| #include "base/strings/utf_string_conversions.h" |
| #include "chromeos/dbus/dbus_thread_manager.h" |
| #include "chromeos/dbus/ibus/ibus_text.h" |
| #include "chromeos/dbus/ibus/mock_ibus_client.h" |
| #include "chromeos/dbus/ibus/mock_ibus_input_context_client.h" |
| #include "chromeos/dbus/mock_dbus_thread_manager_without_gmock.h" |
| #include "chromeos/ime/mock_ibus_daemon_controller.h" |
| #include "testing/gtest/include/gtest/gtest.h" |
| #include "ui/base/ime/input_method_delegate.h" |
| #include "ui/base/ime/input_method_ibus.h" |
| #include "ui/base/ime/text_input_client.h" |
| #include "ui/gfx/rect.h" |
| |
| namespace ui { |
| namespace { |
| const int kCreateInputContextMaxTrialCount = 10; |
| const uint32 kTestIBusKeyVal1 = 97; |
| const uint32 kTestIBusKeyVal2 = 30; |
| const uint32 kTestIBusKeyVal3 = 0; |
| const uint32 kTestIBusKeyCode1 = 98; |
| const uint32 kTestIBusKeyCode2 = 48; |
| const uint32 kTestIBusKeyCode3 = 1; |
| const uint32 kTestIBusState1 = 99; |
| const uint32 kTestIBusState2 = 46; |
| const uint32 kTestIBusState3 = 8; |
| |
| uint32 GetOffsetInUTF16(const std::string& utf8_string, uint32 utf8_offset) { |
| string16 utf16_string = UTF8ToUTF16(utf8_string); |
| DCHECK_LT(utf8_offset, utf16_string.size()); |
| base::i18n::UTF16CharIterator char_iterator(&utf16_string); |
| for (size_t i = 0; i < utf8_offset; ++i) |
| char_iterator.Advance(); |
| return char_iterator.array_pos(); |
| } |
| |
| bool IsEqualXKeyEvent(const XEvent& e1, const XEvent& e2) { |
| if ((e1.type == KeyPress && e2.type == KeyPress) || |
| (e1.type == KeyRelease && e2.type == KeyRelease)) { |
| return !std::memcmp(&e1.xkey, &e2.xkey, sizeof(XKeyEvent)); |
| } |
| return false; |
| } |
| |
| enum KeyEventHandlerBehavior { |
| KEYEVENT_CONSUME, |
| KEYEVENT_NOT_CONSUME, |
| KEYEVENT_ERROR, |
| }; |
| |
| } // namespace |
| |
| |
| using chromeos::IBusInputContextClient; |
| |
| class TestableInputMethodIBus : public InputMethodIBus { |
| public: |
| explicit TestableInputMethodIBus(internal::InputMethodDelegate* delegate) |
| : InputMethodIBus(delegate), |
| process_key_event_post_ime_call_count_(0) { |
| } |
| |
| struct ProcessKeyEventPostIMEArgs { |
| ProcessKeyEventPostIMEArgs() : handled(false) { |
| std::memset(&event, 0, sizeof(XEvent)); |
| } |
| XEvent event; |
| bool handled; |
| }; |
| |
| struct IBusKeyEventFromNativeKeyEventResult { |
| IBusKeyEventFromNativeKeyEventResult() : keyval(0), keycode(0), state(0) {} |
| uint32 keyval; |
| uint32 keycode; |
| uint32 state; |
| }; |
| |
| // InputMethodIBus override. |
| virtual void ProcessKeyEventPostIME(const base::NativeEvent& native_key_event, |
| uint32 ibus_state, |
| bool handled) OVERRIDE { |
| process_key_event_post_ime_args_.event = *native_key_event; |
| process_key_event_post_ime_args_.handled = handled; |
| ++process_key_event_post_ime_call_count_; |
| } |
| |
| // We can't call X11 related function without display in unit test, so |
| // override with mock function. |
| virtual void IBusKeyEventFromNativeKeyEvent( |
| const base::NativeEvent& native_event, |
| uint32* ibus_keyval, |
| uint32* ibus_keycode, |
| uint32* ibus_state) OVERRIDE { |
| EXPECT_TRUE(native_event); |
| EXPECT_TRUE(ibus_keyval); |
| EXPECT_TRUE(ibus_keycode); |
| EXPECT_TRUE(ibus_state); |
| *ibus_keyval = ibus_key_event_from_native_key_event_result_.keyval; |
| *ibus_keycode = ibus_key_event_from_native_key_event_result_.keycode; |
| *ibus_state = ibus_key_event_from_native_key_event_result_.state; |
| } |
| |
| void ResetCallCount() { |
| process_key_event_post_ime_call_count_ = 0; |
| } |
| |
| const ProcessKeyEventPostIMEArgs& process_key_event_post_ime_args() const { |
| return process_key_event_post_ime_args_; |
| } |
| |
| int process_key_event_post_ime_call_count() const { |
| return process_key_event_post_ime_call_count_; |
| } |
| |
| IBusKeyEventFromNativeKeyEventResult* |
| mutable_ibus_key_event_from_native_key_event_result() { |
| return &ibus_key_event_from_native_key_event_result_; |
| } |
| |
| // Change access rights for testing. |
| using InputMethodIBus::ExtractCompositionText; |
| using InputMethodIBus::ResetContext; |
| |
| private: |
| ProcessKeyEventPostIMEArgs process_key_event_post_ime_args_; |
| int process_key_event_post_ime_call_count_; |
| |
| IBusKeyEventFromNativeKeyEventResult |
| ibus_key_event_from_native_key_event_result_; |
| }; |
| |
| class CreateInputContextSuccessHandler { |
| public: |
| explicit CreateInputContextSuccessHandler(const dbus::ObjectPath& object_path) |
| : object_path_(object_path) { |
| } |
| |
| void Run(const std::string& client_name, |
| const chromeos::IBusClient::CreateInputContextCallback& callback, |
| const chromeos::IBusClient::ErrorCallback& error_callback) { |
| EXPECT_EQ("chrome", client_name); |
| callback.Run(object_path_); |
| } |
| |
| private: |
| dbus::ObjectPath object_path_; |
| |
| DISALLOW_COPY_AND_ASSIGN(CreateInputContextSuccessHandler); |
| }; |
| |
| class CreateInputContextFailHandler { |
| public: |
| CreateInputContextFailHandler() {} |
| void Run(const std::string& client_name, |
| const chromeos::IBusClient::CreateInputContextCallback& callback, |
| const chromeos::IBusClient::ErrorCallback& error_callback) { |
| error_callback.Run(); |
| } |
| |
| private: |
| DISALLOW_COPY_AND_ASSIGN(CreateInputContextFailHandler); |
| }; |
| |
| class CreateInputContextNoResponseHandler { |
| public: |
| CreateInputContextNoResponseHandler() {} |
| void Run(const std::string& client_name, |
| const chromeos::IBusClient::CreateInputContextCallback& callback, |
| const chromeos::IBusClient::ErrorCallback& error_callback) { |
| } |
| |
| private: |
| DISALLOW_COPY_AND_ASSIGN(CreateInputContextNoResponseHandler); |
| }; |
| |
| class CreateInputContextDelayHandler { |
| public: |
| explicit CreateInputContextDelayHandler(const dbus::ObjectPath& object_path) |
| : object_path_(object_path) { |
| } |
| |
| void Run(const std::string& client_name, |
| const chromeos::IBusClient::CreateInputContextCallback& callback, |
| const chromeos::IBusClient::ErrorCallback& error_callback) { |
| callback_ = callback; |
| error_callback_ = error_callback; |
| } |
| |
| void RunCallback(bool success) { |
| if (success) |
| callback_.Run(object_path_); |
| else |
| error_callback_.Run(); |
| } |
| |
| private: |
| dbus::ObjectPath object_path_; |
| chromeos::IBusClient::CreateInputContextCallback callback_; |
| chromeos::IBusClient::ErrorCallback error_callback_; |
| |
| DISALLOW_COPY_AND_ASSIGN(CreateInputContextDelayHandler); |
| }; |
| |
| class SynchronousKeyEventHandler { |
| public: |
| SynchronousKeyEventHandler(uint32 expected_keyval, |
| uint32 expected_keycode, |
| uint32 expected_state, |
| KeyEventHandlerBehavior behavior) |
| : expected_keyval_(expected_keyval), |
| expected_keycode_(expected_keycode), |
| expected_state_(expected_state), |
| behavior_(behavior) {} |
| |
| virtual ~SynchronousKeyEventHandler() {} |
| |
| void Run(uint32 keyval, |
| uint32 keycode, |
| uint32 state, |
| const IBusInputContextClient::ProcessKeyEventCallback& callback, |
| const IBusInputContextClient::ErrorCallback& error_callback) { |
| EXPECT_EQ(expected_keyval_, keyval); |
| EXPECT_EQ(expected_keycode_, keycode); |
| EXPECT_EQ(expected_state_, state); |
| if (behavior_ == KEYEVENT_ERROR) |
| error_callback.Run(); |
| else |
| callback.Run(behavior_ == KEYEVENT_CONSUME); |
| } |
| |
| private: |
| const uint32 expected_keyval_; |
| const uint32 expected_keycode_; |
| const uint32 expected_state_; |
| const KeyEventHandlerBehavior behavior_; |
| |
| DISALLOW_COPY_AND_ASSIGN(SynchronousKeyEventHandler); |
| }; |
| |
| class AsynchronousKeyEventHandler { |
| public: |
| AsynchronousKeyEventHandler(uint32 expected_keyval, |
| uint32 expected_keycode, |
| uint32 expected_state) |
| : expected_keyval_(expected_keyval), |
| expected_keycode_(expected_keycode), |
| expected_state_(expected_state) {} |
| |
| virtual ~AsynchronousKeyEventHandler() {} |
| |
| void Run(uint32 keyval, |
| uint32 keycode, |
| uint32 state, |
| const IBusInputContextClient::ProcessKeyEventCallback& callback, |
| const IBusInputContextClient::ErrorCallback& error_callback) { |
| EXPECT_EQ(expected_keyval_, keyval); |
| EXPECT_EQ(expected_keycode_, keycode); |
| EXPECT_EQ(expected_state_, state); |
| callback_ = callback; |
| error_callback_ = error_callback; |
| } |
| |
| void RunCallback(KeyEventHandlerBehavior behavior) { |
| if (behavior == KEYEVENT_ERROR) |
| error_callback_.Run(); |
| else |
| callback_.Run(behavior == KEYEVENT_CONSUME); |
| } |
| |
| private: |
| const uint32 expected_keyval_; |
| const uint32 expected_keycode_; |
| const uint32 expected_state_; |
| IBusInputContextClient::ProcessKeyEventCallback callback_; |
| IBusInputContextClient::ErrorCallback error_callback_; |
| |
| DISALLOW_COPY_AND_ASSIGN(AsynchronousKeyEventHandler); |
| }; |
| |
| class SetSurroundingTextVerifier { |
| public: |
| SetSurroundingTextVerifier(const std::string& expected_surrounding_text, |
| uint32 expected_cursor_position, |
| uint32 expected_anchor_position) |
| : expected_surrounding_text_(expected_surrounding_text), |
| expected_cursor_position_(expected_cursor_position), |
| expected_anchor_position_(expected_anchor_position) {} |
| |
| void Verify(const std::string& text, |
| uint32 cursor_pos, |
| uint32 anchor_pos) { |
| EXPECT_EQ(expected_surrounding_text_, text); |
| EXPECT_EQ(expected_cursor_position_, cursor_pos); |
| EXPECT_EQ(expected_anchor_position_, anchor_pos); |
| } |
| |
| private: |
| const std::string expected_surrounding_text_; |
| const uint32 expected_cursor_position_; |
| const uint32 expected_anchor_position_; |
| |
| DISALLOW_COPY_AND_ASSIGN(SetSurroundingTextVerifier); |
| }; |
| |
| class InputMethodIBusTest : public internal::InputMethodDelegate, |
| public testing::Test, |
| public TextInputClient { |
| public: |
| InputMethodIBusTest() { |
| ResetFlags(); |
| } |
| |
| virtual ~InputMethodIBusTest() { |
| } |
| |
| // testing::Test overrides: |
| virtual void SetUp() OVERRIDE { |
| // |thread_manager_| will be released by DBusThreadManager::Shutdown |
| // function in TearDown function. |
| // Current MockIBusInputContext is strongly depend on gmock, but gmock is |
| // banned in ui/*. So just use stab implementation for testing. |
| mock_dbus_thread_manager_ = |
| new chromeos::MockDBusThreadManagerWithoutGMock(); |
| chromeos::DBusThreadManager::InitializeForTesting( |
| mock_dbus_thread_manager_); |
| mock_ibus_daemon_controller_ = new chromeos::MockIBusDaemonController(); |
| chromeos::IBusDaemonController::InitializeForTesting( |
| mock_ibus_daemon_controller_); |
| |
| ime_.reset(new TestableInputMethodIBus(this)); |
| ime_->SetFocusedTextInputClient(this); |
| } |
| |
| virtual void TearDown() OVERRIDE { |
| if (ime_.get()) |
| ime_->SetFocusedTextInputClient(NULL); |
| ime_.reset(); |
| chromeos::DBusThreadManager::Shutdown(); |
| chromeos::IBusDaemonController::Shutdown(); |
| } |
| |
| // Helper function to initialize IBus connection for testing. |
| void InitIBusBus() { |
| mock_dbus_thread_manager_->InitIBusBus("dummy address", |
| base::Bind(&base::DoNothing)); |
| mock_ibus_client_ = mock_dbus_thread_manager_->mock_ibus_client(); |
| mock_ibus_input_context_client_ = |
| mock_dbus_thread_manager_->mock_ibus_input_context_client(); |
| |
| } |
| |
| // ui::internal::InputMethodDelegate overrides: |
| virtual bool DispatchKeyEventPostIME( |
| const base::NativeEvent& native_key_event) OVERRIDE { |
| dispatched_native_event_ = native_key_event; |
| return false; |
| } |
| virtual bool DispatchFabricatedKeyEventPostIME(ui::EventType type, |
| ui::KeyboardCode key_code, |
| int flags) OVERRIDE { |
| dispatched_fabricated_event_type_ = type; |
| dispatched_fabricated_event_key_code_ = key_code; |
| dispatched_fabricated_event_flags_ = flags; |
| return false; |
| } |
| |
| // ui::TextInputClient overrides: |
| virtual void SetCompositionText( |
| const CompositionText& composition) OVERRIDE { |
| composition_text_ = composition; |
| } |
| virtual void ConfirmCompositionText() OVERRIDE { |
| confirmed_text_ = composition_text_; |
| composition_text_.Clear(); |
| } |
| virtual void ClearCompositionText() OVERRIDE { |
| composition_text_.Clear(); |
| } |
| virtual void InsertText(const string16& text) OVERRIDE { |
| inserted_text_ = text; |
| } |
| virtual void InsertChar(char16 ch, int flags) OVERRIDE { |
| inserted_char_ = ch; |
| inserted_char_flags_ = flags; |
| } |
| virtual gfx::NativeWindow GetAttachedWindow() const OVERRIDE { |
| return static_cast<gfx::NativeWindow>(NULL); |
| } |
| virtual TextInputType GetTextInputType() const OVERRIDE { |
| return input_type_; |
| } |
| virtual TextInputMode GetTextInputMode() const OVERRIDE { |
| return TEXT_INPUT_MODE_DEFAULT; |
| } |
| virtual bool CanComposeInline() const OVERRIDE { |
| return can_compose_inline_; |
| } |
| virtual gfx::Rect GetCaretBounds() OVERRIDE { |
| return caret_bounds_; |
| } |
| virtual bool GetCompositionCharacterBounds(uint32 index, |
| gfx::Rect* rect) OVERRIDE { |
| return false; |
| } |
| virtual bool HasCompositionText() OVERRIDE { |
| CompositionText empty; |
| return composition_text_ != empty; |
| } |
| virtual bool GetTextRange(Range* range) OVERRIDE { |
| *range = text_range_; |
| return true; |
| } |
| virtual bool GetCompositionTextRange(Range* range) OVERRIDE { return false; } |
| virtual bool GetSelectionRange(Range* range) OVERRIDE { |
| *range = selection_range_; |
| return true; |
| } |
| |
| virtual bool SetSelectionRange(const Range& range) OVERRIDE { return false; } |
| virtual bool DeleteRange(const Range& range) OVERRIDE { return false; } |
| virtual bool GetTextFromRange(const Range& range, string16* text) OVERRIDE { |
| *text = surrounding_text_.substr(range.GetMin(), range.length()); |
| return true; |
| } |
| virtual void OnInputMethodChanged() OVERRIDE { |
| ++on_input_method_changed_call_count_; |
| } |
| virtual bool ChangeTextDirectionAndLayoutAlignment( |
| base::i18n::TextDirection direction) OVERRIDE { return false; } |
| virtual void ExtendSelectionAndDelete(size_t before, |
| size_t after) OVERRIDE { } |
| virtual void EnsureCaretInRect(const gfx::Rect& rect) OVERRIDE { } |
| |
| bool HasNativeEvent() const { |
| base::NativeEvent empty; |
| std::memset(&empty, 0, sizeof(empty)); |
| return !!std::memcmp(&dispatched_native_event_, |
| &empty, |
| sizeof(dispatched_native_event_)); |
| } |
| |
| void ResetFlags() { |
| std::memset(&dispatched_native_event_, 0, sizeof(dispatched_native_event_)); |
| DCHECK(!HasNativeEvent()); |
| dispatched_fabricated_event_type_ = ET_UNKNOWN; |
| dispatched_fabricated_event_key_code_ = VKEY_UNKNOWN; |
| dispatched_fabricated_event_flags_ = 0; |
| |
| composition_text_.Clear(); |
| confirmed_text_.Clear(); |
| inserted_text_.clear(); |
| inserted_char_ = 0; |
| inserted_char_flags_ = 0; |
| on_input_method_changed_call_count_ = 0; |
| |
| input_type_ = TEXT_INPUT_TYPE_NONE; |
| can_compose_inline_ = true; |
| caret_bounds_ = gfx::Rect(); |
| } |
| |
| void SetCreateContextSuccessHandler() { |
| CreateInputContextSuccessHandler create_input_context_handler( |
| dbus::ObjectPath("InputContext_1")); |
| mock_ibus_client_->set_create_input_context_handler(base::Bind( |
| &CreateInputContextSuccessHandler::Run, |
| base::Unretained(&create_input_context_handler))); |
| } |
| |
| scoped_ptr<TestableInputMethodIBus> ime_; |
| |
| // Variables for remembering the parameters that are passed to |
| // ui::internal::InputMethodDelegate functions. |
| base::NativeEvent dispatched_native_event_; |
| ui::EventType dispatched_fabricated_event_type_; |
| ui::KeyboardCode dispatched_fabricated_event_key_code_; |
| int dispatched_fabricated_event_flags_; |
| |
| // Variables for remembering the parameters that are passed to |
| // ui::TextInputClient functions. |
| CompositionText composition_text_; |
| CompositionText confirmed_text_; |
| string16 inserted_text_; |
| char16 inserted_char_; |
| unsigned int on_input_method_changed_call_count_; |
| int inserted_char_flags_; |
| |
| // Variables that will be returned from the ui::TextInputClient functions. |
| TextInputType input_type_; |
| bool can_compose_inline_; |
| gfx::Rect caret_bounds_; |
| ui::Range text_range_; |
| ui::Range selection_range_; |
| string16 surrounding_text_; |
| |
| // Variables for mock dbus connections. |
| chromeos::MockDBusThreadManagerWithoutGMock* mock_dbus_thread_manager_; |
| chromeos::MockIBusClient* mock_ibus_client_; |
| chromeos::MockIBusInputContextClient* mock_ibus_input_context_client_; |
| chromeos::MockIBusDaemonController* mock_ibus_daemon_controller_; |
| |
| DISALLOW_COPY_AND_ASSIGN(InputMethodIBusTest); |
| }; |
| |
| // Tests public APIs in ui::InputMethod first. |
| |
| TEST_F(InputMethodIBusTest, GetInputLocale) { |
| // ui::InputMethodIBus does not support the API. |
| ime_->Init(true); |
| EXPECT_EQ("", ime_->GetInputLocale()); |
| } |
| |
| TEST_F(InputMethodIBusTest, GetInputTextDirection) { |
| // ui::InputMethodIBus does not support the API. |
| ime_->Init(true); |
| EXPECT_EQ(base::i18n::UNKNOWN_DIRECTION, ime_->GetInputTextDirection()); |
| } |
| |
| TEST_F(InputMethodIBusTest, IsActive) { |
| ime_->Init(true); |
| // ui::InputMethodIBus always returns true. |
| EXPECT_TRUE(ime_->IsActive()); |
| } |
| |
| TEST_F(InputMethodIBusTest, GetInputTextType) { |
| ime_->Init(true); |
| EXPECT_EQ(TEXT_INPUT_TYPE_NONE, ime_->GetTextInputType()); |
| input_type_ = TEXT_INPUT_TYPE_PASSWORD; |
| ime_->OnTextInputTypeChanged(this); |
| EXPECT_EQ(TEXT_INPUT_TYPE_PASSWORD, ime_->GetTextInputType()); |
| input_type_ = TEXT_INPUT_TYPE_TEXT; |
| ime_->OnTextInputTypeChanged(this); |
| EXPECT_EQ(TEXT_INPUT_TYPE_TEXT, ime_->GetTextInputType()); |
| } |
| |
| TEST_F(InputMethodIBusTest, CanComposeInline) { |
| ime_->Init(true); |
| EXPECT_TRUE(ime_->CanComposeInline()); |
| can_compose_inline_ = false; |
| ime_->OnTextInputTypeChanged(this); |
| EXPECT_FALSE(ime_->CanComposeInline()); |
| } |
| |
| TEST_F(InputMethodIBusTest, GetTextInputClient) { |
| ime_->Init(true); |
| EXPECT_EQ(this, ime_->GetTextInputClient()); |
| ime_->SetFocusedTextInputClient(NULL); |
| EXPECT_EQ(NULL, ime_->GetTextInputClient()); |
| } |
| |
| TEST_F(InputMethodIBusTest, GetInputTextType_WithoutFocusedClient) { |
| ime_->Init(true); |
| EXPECT_EQ(TEXT_INPUT_TYPE_NONE, ime_->GetTextInputType()); |
| ime_->SetFocusedTextInputClient(NULL); |
| input_type_ = TEXT_INPUT_TYPE_PASSWORD; |
| ime_->OnTextInputTypeChanged(this); |
| // The OnTextInputTypeChanged() call above should be ignored since |this| is |
| // not the current focused client. |
| EXPECT_EQ(TEXT_INPUT_TYPE_NONE, ime_->GetTextInputType()); |
| |
| ime_->SetFocusedTextInputClient(this); |
| ime_->OnTextInputTypeChanged(this); |
| EXPECT_EQ(TEXT_INPUT_TYPE_PASSWORD, ime_->GetTextInputType()); |
| } |
| |
| TEST_F(InputMethodIBusTest, GetInputTextType_WithoutFocusedWindow) { |
| ime_->Init(true); |
| EXPECT_EQ(TEXT_INPUT_TYPE_NONE, ime_->GetTextInputType()); |
| ime_->OnBlur(); |
| input_type_ = TEXT_INPUT_TYPE_PASSWORD; |
| ime_->OnTextInputTypeChanged(this); |
| // The OnTextInputTypeChanged() call above should be ignored since the top- |
| // level window which the ime_ is attached to is not currently focused. |
| EXPECT_EQ(TEXT_INPUT_TYPE_NONE, ime_->GetTextInputType()); |
| |
| ime_->OnFocus(); |
| ime_->OnTextInputTypeChanged(this); |
| EXPECT_EQ(TEXT_INPUT_TYPE_PASSWORD, ime_->GetTextInputType()); |
| } |
| |
| TEST_F(InputMethodIBusTest, GetInputTextType_WithoutFocusedWindow2) { |
| ime_->Init(false); // the top-level is initially unfocused. |
| EXPECT_EQ(TEXT_INPUT_TYPE_NONE, ime_->GetTextInputType()); |
| input_type_ = TEXT_INPUT_TYPE_PASSWORD; |
| ime_->OnTextInputTypeChanged(this); |
| EXPECT_EQ(TEXT_INPUT_TYPE_NONE, ime_->GetTextInputType()); |
| |
| ime_->OnFocus(); |
| ime_->OnTextInputTypeChanged(this); |
| EXPECT_EQ(TEXT_INPUT_TYPE_PASSWORD, ime_->GetTextInputType()); |
| } |
| |
| // Then, tests internal behavior of ui::InputMethodIBus, especially if the input |
| // method implementation calls ui::internal::IBusClient APIs as expected. |
| |
| // Start ibus-daemon first, then create ui::InputMethodIBus. Check if a new |
| // input context is created. |
| TEST_F(InputMethodIBusTest, InitiallyConnected) { |
| InitIBusBus(); |
| SetCreateContextSuccessHandler(); |
| ime_->Init(true); |
| // An input context should be created immediately since is_connected_ is true. |
| EXPECT_EQ(1, mock_ibus_client_->create_input_context_call_count()); |
| EXPECT_EQ(1, mock_ibus_input_context_client_->set_capabilities_call_count()); |
| // However, since the current text input type is 'NONE' (the default), FocusIn |
| // shouldn't be called. |
| EXPECT_EQ(0, mock_ibus_input_context_client_->focus_in_call_count()); |
| EXPECT_TRUE(mock_ibus_input_context_client_->IsObjectProxyReady()); |
| } |
| |
| // Create ui::InputMethodIBus, then start ibus-daemon. |
| TEST_F(InputMethodIBusTest, InitiallyDisconnected) { |
| ime_->Init(true); |
| // Start the daemon. |
| InitIBusBus(); |
| SetCreateContextSuccessHandler(); |
| mock_ibus_daemon_controller_->EmulateConnect(); |
| // A context should be created upon the signal delivery. |
| EXPECT_EQ(1, mock_ibus_client_->create_input_context_call_count()); |
| EXPECT_EQ(1, mock_ibus_input_context_client_->set_capabilities_call_count()); |
| EXPECT_EQ(0, mock_ibus_input_context_client_->focus_in_call_count()); |
| EXPECT_TRUE(mock_ibus_input_context_client_->IsObjectProxyReady()); |
| } |
| |
| // Confirm that ui::InputMethodIBus does not crash on "disconnected" signal |
| // delivery. |
| TEST_F(InputMethodIBusTest, Disconnect) { |
| InitIBusBus(); |
| SetCreateContextSuccessHandler(); |
| ime_->Init(true); |
| EXPECT_EQ(1, mock_ibus_client_->create_input_context_call_count()); |
| // Currently we can't shutdown IBusBus connection except in |
| // DBusThreadManager's shutting down. So set ibus_bus_ as NULL to emulate |
| // dynamical shutting down. |
| mock_dbus_thread_manager_->set_ibus_bus(NULL); |
| mock_ibus_daemon_controller_->EmulateDisconnect(); |
| EXPECT_FALSE(mock_ibus_input_context_client_->IsObjectProxyReady()); |
| } |
| |
| // Confirm that ui::InputMethodIBus re-creates an input context when ibus-daemon |
| // restarts. |
| TEST_F(InputMethodIBusTest, DisconnectThenReconnect) { |
| InitIBusBus(); |
| SetCreateContextSuccessHandler(); |
| ime_->Init(true); |
| EXPECT_EQ(1, mock_ibus_client_->create_input_context_call_count()); |
| EXPECT_EQ(1, mock_ibus_input_context_client_->set_capabilities_call_count()); |
| EXPECT_EQ(0, |
| mock_ibus_input_context_client_->reset_object_proxy_call_caount()); |
| mock_dbus_thread_manager_->set_ibus_bus(NULL); |
| mock_ibus_daemon_controller_->EmulateDisconnect(); |
| EXPECT_FALSE(mock_ibus_input_context_client_->IsObjectProxyReady()); |
| mock_ibus_daemon_controller_->EmulateDisconnect(); |
| InitIBusBus(); |
| SetCreateContextSuccessHandler(); |
| mock_ibus_daemon_controller_->EmulateConnect(); |
| // Check if the old context is deleted. |
| EXPECT_EQ(0, |
| mock_ibus_input_context_client_->reset_object_proxy_call_caount()); |
| // Check if a new context is created. |
| EXPECT_EQ(1, mock_ibus_client_->create_input_context_call_count()); |
| EXPECT_EQ(1, mock_ibus_input_context_client_->set_capabilities_call_count()); |
| EXPECT_TRUE(mock_ibus_input_context_client_->IsObjectProxyReady()); |
| } |
| |
| // Confirm that ui::InputMethodIBus does not crash even if NULL context is |
| // passed. |
| // TODO(yusukes): Currently, ui::InputMethodIBus does not try to create ic once |
| // it fails (unless ibus sends the "connected" signal to Chrome again). It might |
| // be better to add some retry logic. Will revisit later. |
| TEST_F(InputMethodIBusTest, CreateContextFail) { |
| InitIBusBus(); |
| CreateInputContextFailHandler create_input_context_handler; |
| mock_ibus_client_->set_create_input_context_handler(base::Bind( |
| &CreateInputContextFailHandler::Run, |
| base::Unretained(&create_input_context_handler))); |
| ime_->Init(true); |
| // InputMethodIBus tries several times if the CreateInputContext method call |
| // is failed. |
| EXPECT_EQ(kCreateInputContextMaxTrialCount, |
| mock_ibus_client_->create_input_context_call_count()); |
| // |set_capabilities_call_count()| should be zero since a context is not |
| // created yet. |
| EXPECT_EQ(0, mock_ibus_input_context_client_->set_capabilities_call_count()); |
| EXPECT_FALSE(mock_ibus_input_context_client_->IsObjectProxyReady()); |
| } |
| |
| // Confirm that ui::InputMethodIBus does not crash even if ibus-daemon does not |
| // respond. |
| TEST_F(InputMethodIBusTest, CreateContextNoResp) { |
| InitIBusBus(); |
| CreateInputContextNoResponseHandler create_input_context_handler; |
| mock_ibus_client_->set_create_input_context_handler(base::Bind( |
| &CreateInputContextNoResponseHandler::Run, |
| base::Unretained(&create_input_context_handler))); |
| ime_->Init(true); |
| EXPECT_EQ(1, mock_ibus_client_->create_input_context_call_count()); |
| EXPECT_EQ(0, mock_ibus_input_context_client_->set_capabilities_call_count()); |
| EXPECT_FALSE(mock_ibus_input_context_client_->IsObjectProxyReady()); |
| } |
| |
| // Confirm that ui::InputMethodIBus does not crash even if ibus-daemon responds |
| // after ui::InputMethodIBus is deleted. |
| TEST_F(InputMethodIBusTest, CreateContextFailDelayed) { |
| InitIBusBus(); |
| CreateInputContextDelayHandler create_input_context_handler( |
| dbus::ObjectPath("Sample object path")); |
| mock_ibus_client_->set_create_input_context_handler(base::Bind( |
| &CreateInputContextDelayHandler::Run, |
| base::Unretained(&create_input_context_handler))); |
| ime_->Init(true); |
| EXPECT_EQ(1, mock_ibus_client_->create_input_context_call_count()); |
| EXPECT_EQ(0, mock_ibus_input_context_client_->set_capabilities_call_count()); |
| EXPECT_FALSE(mock_ibus_input_context_client_->IsObjectProxyReady()); |
| |
| ime_->SetFocusedTextInputClient(NULL); |
| ime_.reset(); |
| EXPECT_FALSE(mock_ibus_input_context_client_->IsObjectProxyReady()); |
| |
| create_input_context_handler.RunCallback(false); |
| EXPECT_EQ(1, mock_ibus_client_->create_input_context_call_count()); |
| EXPECT_EQ(0, mock_ibus_input_context_client_->set_capabilities_call_count()); |
| EXPECT_FALSE(mock_ibus_input_context_client_->IsObjectProxyReady()); |
| } |
| |
| // Confirm that ui::InputMethodIBus does not crash even if ibus-daemon responds |
| // after ui::InputMethodIBus is deleted. |
| TEST_F(InputMethodIBusTest, CreateContextSuccessDelayed) { |
| InitIBusBus(); |
| CreateInputContextDelayHandler create_input_context_handler( |
| dbus::ObjectPath("Sample object path")); |
| mock_ibus_client_->set_create_input_context_handler(base::Bind( |
| &CreateInputContextDelayHandler::Run, |
| base::Unretained(&create_input_context_handler))); |
| ime_->Init(true); |
| EXPECT_EQ(1, mock_ibus_client_->create_input_context_call_count()); |
| EXPECT_EQ(0, mock_ibus_input_context_client_->set_capabilities_call_count()); |
| EXPECT_FALSE(mock_ibus_input_context_client_->IsObjectProxyReady()); |
| |
| ime_->SetFocusedTextInputClient(NULL); |
| ime_.reset(); |
| EXPECT_FALSE(mock_ibus_input_context_client_->IsObjectProxyReady()); |
| |
| create_input_context_handler.RunCallback(true); |
| EXPECT_EQ(1, mock_ibus_client_->create_input_context_call_count()); |
| EXPECT_EQ(0, mock_ibus_input_context_client_->set_capabilities_call_count()); |
| EXPECT_FALSE(mock_ibus_input_context_client_->IsObjectProxyReady()); |
| } |
| |
| // Confirm that ui::InputMethodIBus does not crash even if ibus-daemon responds |
| // after disconnected from ibus-daemon. |
| TEST_F(InputMethodIBusTest, CreateContextSuccessDelayedAfterDisconnection) { |
| InitIBusBus(); |
| CreateInputContextDelayHandler create_input_context_handler( |
| dbus::ObjectPath("Sample object path")); |
| mock_ibus_client_->set_create_input_context_handler(base::Bind( |
| &CreateInputContextDelayHandler::Run, |
| base::Unretained(&create_input_context_handler))); |
| ime_->Init(true); |
| EXPECT_EQ(1, mock_ibus_client_->create_input_context_call_count()); |
| EXPECT_EQ(0, mock_ibus_input_context_client_->set_capabilities_call_count()); |
| EXPECT_FALSE(mock_ibus_input_context_client_->IsObjectProxyReady()); |
| |
| mock_ibus_daemon_controller_->EmulateDisconnect(); |
| EXPECT_FALSE(mock_ibus_input_context_client_->IsObjectProxyReady()); |
| |
| create_input_context_handler.RunCallback(true); |
| EXPECT_EQ(1, mock_ibus_client_->create_input_context_call_count()); |
| EXPECT_EQ(0, mock_ibus_input_context_client_->set_capabilities_call_count()); |
| EXPECT_FALSE(mock_ibus_input_context_client_->IsObjectProxyReady()); |
| } |
| |
| // Confirm that ui::InputMethodIBus does not crash even if ibus-daemon responds |
| // after disconnected from ibus-daemon. |
| TEST_F(InputMethodIBusTest, CreateContextFailDelayedAfterDisconnection) { |
| InitIBusBus(); |
| CreateInputContextDelayHandler create_input_context_handler( |
| dbus::ObjectPath("Sample object path")); |
| mock_ibus_client_->set_create_input_context_handler(base::Bind( |
| &CreateInputContextDelayHandler::Run, |
| base::Unretained(&create_input_context_handler))); |
| ime_->Init(true); |
| EXPECT_EQ(1, mock_ibus_client_->create_input_context_call_count()); |
| EXPECT_EQ(0, mock_ibus_input_context_client_->set_capabilities_call_count()); |
| EXPECT_FALSE(mock_ibus_input_context_client_->IsObjectProxyReady()); |
| |
| mock_ibus_daemon_controller_->EmulateDisconnect(); |
| EXPECT_FALSE(mock_ibus_input_context_client_->IsObjectProxyReady()); |
| |
| create_input_context_handler.RunCallback(false); |
| EXPECT_EQ(1, mock_ibus_client_->create_input_context_call_count()); |
| EXPECT_EQ(0, mock_ibus_input_context_client_->set_capabilities_call_count()); |
| EXPECT_FALSE(mock_ibus_input_context_client_->IsObjectProxyReady()); |
| } |
| |
| // Confirm that IBusClient::FocusIn is called on "connected" if input_type_ is |
| // TEXT. |
| TEST_F(InputMethodIBusTest, FocusIn_Text) { |
| ime_->Init(true); |
| // A context shouldn't be created since the daemon is not running. |
| EXPECT_EQ(0U, on_input_method_changed_call_count_); |
| // Click a text input form. |
| input_type_ = TEXT_INPUT_TYPE_TEXT; |
| ime_->OnTextInputTypeChanged(this); |
| // Start the daemon. |
| InitIBusBus(); |
| SetCreateContextSuccessHandler(); |
| mock_ibus_daemon_controller_->EmulateConnect(); |
| // A context should be created upon the signal delivery. |
| EXPECT_EQ(1, mock_ibus_client_->create_input_context_call_count()); |
| // Since a form has focus, IBusClient::FocusIn() should be called. |
| EXPECT_EQ(1, mock_ibus_input_context_client_->focus_in_call_count()); |
| EXPECT_EQ(1, |
| mock_ibus_input_context_client_->set_cursor_location_call_count()); |
| // ui::TextInputClient::OnInputMethodChanged() should be called when |
| // ui::InputMethodIBus connects/disconnects to/from ibus-daemon and the |
| // current text input type is not NONE. |
| EXPECT_EQ(1U, on_input_method_changed_call_count_); |
| } |
| |
| // Confirm that IBusClient::FocusIn is NOT called on "connected" if input_type_ |
| // is PASSWORD. |
| TEST_F(InputMethodIBusTest, FocusIn_Password) { |
| ime_->Init(true); |
| EXPECT_EQ(0U, on_input_method_changed_call_count_); |
| input_type_ = TEXT_INPUT_TYPE_PASSWORD; |
| ime_->OnTextInputTypeChanged(this); |
| InitIBusBus(); |
| SetCreateContextSuccessHandler(); |
| mock_ibus_daemon_controller_->EmulateConnect(); |
| EXPECT_EQ(1, mock_ibus_client_->create_input_context_call_count()); |
| // Since a form has focus, IBusClient::FocusIn() should NOT be called. |
| EXPECT_EQ(0, mock_ibus_input_context_client_->focus_in_call_count()); |
| EXPECT_EQ(1U, on_input_method_changed_call_count_); |
| } |
| |
| // Confirm that IBusClient::FocusOut is called as expected. |
| TEST_F(InputMethodIBusTest, FocusOut_None) { |
| input_type_ = TEXT_INPUT_TYPE_TEXT; |
| InitIBusBus(); |
| SetCreateContextSuccessHandler(); |
| ime_->Init(true); |
| EXPECT_EQ(1, mock_ibus_client_->create_input_context_call_count()); |
| EXPECT_EQ(1, mock_ibus_input_context_client_->focus_in_call_count()); |
| EXPECT_EQ(0, mock_ibus_input_context_client_->focus_out_call_count()); |
| input_type_ = TEXT_INPUT_TYPE_NONE; |
| ime_->OnTextInputTypeChanged(this); |
| EXPECT_EQ(1, mock_ibus_input_context_client_->focus_in_call_count()); |
| EXPECT_EQ(1, mock_ibus_input_context_client_->focus_out_call_count()); |
| } |
| |
| // Confirm that IBusClient::FocusOut is called as expected. |
| TEST_F(InputMethodIBusTest, FocusOut_Password) { |
| input_type_ = TEXT_INPUT_TYPE_TEXT; |
| InitIBusBus(); |
| SetCreateContextSuccessHandler(); |
| ime_->Init(true); |
| EXPECT_EQ(1, mock_ibus_client_->create_input_context_call_count()); |
| EXPECT_EQ(1, mock_ibus_input_context_client_->focus_in_call_count()); |
| EXPECT_EQ(0, mock_ibus_input_context_client_->focus_out_call_count()); |
| input_type_ = TEXT_INPUT_TYPE_PASSWORD; |
| ime_->OnTextInputTypeChanged(this); |
| EXPECT_EQ(1, mock_ibus_input_context_client_->focus_in_call_count()); |
| EXPECT_EQ(1, mock_ibus_input_context_client_->focus_out_call_count()); |
| } |
| |
| // Confirm that IBusClient::FocusOut is NOT called. |
| TEST_F(InputMethodIBusTest, FocusOut_Url) { |
| input_type_ = TEXT_INPUT_TYPE_TEXT; |
| InitIBusBus(); |
| SetCreateContextSuccessHandler(); |
| ime_->Init(true); |
| EXPECT_EQ(1, mock_ibus_client_->create_input_context_call_count()); |
| EXPECT_EQ(1, mock_ibus_input_context_client_->focus_in_call_count()); |
| EXPECT_EQ(0, mock_ibus_input_context_client_->focus_out_call_count()); |
| input_type_ = TEXT_INPUT_TYPE_URL; |
| ime_->OnTextInputTypeChanged(this); |
| EXPECT_EQ(1, mock_ibus_input_context_client_->focus_in_call_count()); |
| EXPECT_EQ(0, mock_ibus_input_context_client_->focus_out_call_count()); |
| } |
| |
| // Test if the new |caret_bounds_| is correctly sent to ibus-daemon. |
| TEST_F(InputMethodIBusTest, OnCaretBoundsChanged) { |
| InitIBusBus(); |
| SetCreateContextSuccessHandler(); |
| input_type_ = TEXT_INPUT_TYPE_TEXT; |
| ime_->Init(true); |
| EXPECT_EQ(0, |
| mock_ibus_input_context_client_->set_cursor_location_call_count()); |
| caret_bounds_ = gfx::Rect(1, 2, 3, 4); |
| ime_->OnCaretBoundsChanged(this); |
| EXPECT_EQ(1, |
| mock_ibus_input_context_client_->set_cursor_location_call_count()); |
| caret_bounds_ = gfx::Rect(0, 2, 3, 4); |
| ime_->OnCaretBoundsChanged(this); |
| EXPECT_EQ(2, |
| mock_ibus_input_context_client_->set_cursor_location_call_count()); |
| caret_bounds_ = gfx::Rect(0, 2, 3, 4); // unchanged |
| ime_->OnCaretBoundsChanged(this); |
| // Current InputMethodIBus implementation performs the IPC regardless of the |
| // bounds are changed or not. |
| EXPECT_EQ(3, |
| mock_ibus_input_context_client_->set_cursor_location_call_count()); |
| } |
| |
| TEST_F(InputMethodIBusTest, ExtractCompositionTextTest_NoAttribute) { |
| const char kSampleText[] = "Sample Text"; |
| const uint32 kCursorPos = 2UL; |
| |
| const string16 utf16_string = UTF8ToUTF16(kSampleText); |
| chromeos::IBusText ibus_text; |
| ibus_text.set_text(kSampleText); |
| |
| CompositionText composition_text; |
| ime_->ExtractCompositionText(ibus_text, kCursorPos, &composition_text); |
| EXPECT_EQ(UTF8ToUTF16(kSampleText), composition_text.text); |
| // If there is no selection, |selection| represents cursor position. |
| EXPECT_EQ(kCursorPos, composition_text.selection.start()); |
| EXPECT_EQ(kCursorPos, composition_text.selection.end()); |
| // If there is no underline, |underlines| contains one underline and it is |
| // whole text underline. |
| ASSERT_EQ(1UL, composition_text.underlines.size()); |
| EXPECT_EQ(0UL, composition_text.underlines[0].start_offset); |
| EXPECT_EQ(utf16_string.size(), composition_text.underlines[0].end_offset); |
| EXPECT_FALSE(composition_text.underlines[0].thick); |
| } |
| |
| TEST_F(InputMethodIBusTest, ExtractCompositionTextTest_SingleUnderline) { |
| const char kSampleText[] = "\xE3\x81\x82\xE3\x81\x84\xE3\x81\x86" |
| "\xE3\x81\x88\xE3\x81\x8A"; |
| const uint32 kCursorPos = 2UL; |
| |
| // Set up ibus text with one underline attribute. |
| chromeos::IBusText ibus_text; |
| ibus_text.set_text(kSampleText); |
| chromeos::IBusText::UnderlineAttribute underline; |
| underline.type = chromeos::IBusText::IBUS_TEXT_UNDERLINE_SINGLE; |
| underline.start_index = 1UL; |
| underline.end_index = 4UL; |
| ibus_text.mutable_underline_attributes()->push_back(underline); |
| |
| CompositionText composition_text; |
| ime_->ExtractCompositionText(ibus_text, kCursorPos, &composition_text); |
| EXPECT_EQ(UTF8ToUTF16(kSampleText), composition_text.text); |
| // If there is no selection, |selection| represents cursor position. |
| EXPECT_EQ(kCursorPos, composition_text.selection.start()); |
| EXPECT_EQ(kCursorPos, composition_text.selection.end()); |
| ASSERT_EQ(1UL, composition_text.underlines.size()); |
| EXPECT_EQ(GetOffsetInUTF16(kSampleText, underline.start_index), |
| composition_text.underlines[0].start_offset); |
| EXPECT_EQ(GetOffsetInUTF16(kSampleText, underline.end_index), |
| composition_text.underlines[0].end_offset); |
| // Single underline represents as black thin line. |
| EXPECT_EQ(SK_ColorBLACK, composition_text.underlines[0].color); |
| EXPECT_FALSE(composition_text.underlines[0].thick); |
| } |
| |
| TEST_F(InputMethodIBusTest, ExtractCompositionTextTest_DoubleUnderline) { |
| const char kSampleText[] = "\xE3\x81\x82\xE3\x81\x84\xE3\x81\x86" |
| "\xE3\x81\x88\xE3\x81\x8A"; |
| const uint32 kCursorPos = 2UL; |
| |
| // Set up ibus text with one underline attribute. |
| chromeos::IBusText ibus_text; |
| ibus_text.set_text(kSampleText); |
| chromeos::IBusText::UnderlineAttribute underline; |
| underline.type = chromeos::IBusText::IBUS_TEXT_UNDERLINE_DOUBLE; |
| underline.start_index = 1UL; |
| underline.end_index = 4UL; |
| ibus_text.mutable_underline_attributes()->push_back(underline); |
| |
| CompositionText composition_text; |
| ime_->ExtractCompositionText(ibus_text, kCursorPos, &composition_text); |
| EXPECT_EQ(UTF8ToUTF16(kSampleText), composition_text.text); |
| // If there is no selection, |selection| represents cursor position. |
| EXPECT_EQ(kCursorPos, composition_text.selection.start()); |
| EXPECT_EQ(kCursorPos, composition_text.selection.end()); |
| ASSERT_EQ(1UL, composition_text.underlines.size()); |
| EXPECT_EQ(GetOffsetInUTF16(kSampleText, underline.start_index), |
| composition_text.underlines[0].start_offset); |
| EXPECT_EQ(GetOffsetInUTF16(kSampleText, underline.end_index), |
| composition_text.underlines[0].end_offset); |
| // Double underline represents as black thick line. |
| EXPECT_EQ(SK_ColorBLACK, composition_text.underlines[0].color); |
| EXPECT_TRUE(composition_text.underlines[0].thick); |
| } |
| |
| TEST_F(InputMethodIBusTest, ExtractCompositionTextTest_ErrorUnderline) { |
| const char kSampleText[] = "\xE3\x81\x82\xE3\x81\x84\xE3\x81\x86" |
| "\xE3\x81\x88\xE3\x81\x8A"; |
| const uint32 kCursorPos = 2UL; |
| |
| // Set up ibus text with one underline attribute. |
| chromeos::IBusText ibus_text; |
| ibus_text.set_text(kSampleText); |
| chromeos::IBusText::UnderlineAttribute underline; |
| underline.type = chromeos::IBusText::IBUS_TEXT_UNDERLINE_ERROR; |
| underline.start_index = 1UL; |
| underline.end_index = 4UL; |
| ibus_text.mutable_underline_attributes()->push_back(underline); |
| |
| CompositionText composition_text; |
| ime_->ExtractCompositionText(ibus_text, kCursorPos, &composition_text); |
| EXPECT_EQ(UTF8ToUTF16(kSampleText), composition_text.text); |
| EXPECT_EQ(kCursorPos, composition_text.selection.start()); |
| EXPECT_EQ(kCursorPos, composition_text.selection.end()); |
| ASSERT_EQ(1UL, composition_text.underlines.size()); |
| EXPECT_EQ(GetOffsetInUTF16(kSampleText, underline.start_index), |
| composition_text.underlines[0].start_offset); |
| EXPECT_EQ(GetOffsetInUTF16(kSampleText, underline.end_index), |
| composition_text.underlines[0].end_offset); |
| // Error underline represents as red thin line. |
| EXPECT_EQ(SK_ColorRED, composition_text.underlines[0].color); |
| EXPECT_FALSE(composition_text.underlines[0].thick); |
| } |
| |
| TEST_F(InputMethodIBusTest, ExtractCompositionTextTest_Selection) { |
| const char kSampleText[] = "\xE3\x81\x82\xE3\x81\x84\xE3\x81\x86" |
| "\xE3\x81\x88\xE3\x81\x8A"; |
| const uint32 kCursorPos = 2UL; |
| |
| // Set up ibus text with one underline attribute. |
| chromeos::IBusText ibus_text; |
| ibus_text.set_text(kSampleText); |
| chromeos::IBusText::SelectionAttribute selection; |
| selection.start_index = 1UL; |
| selection.end_index = 4UL; |
| ibus_text.mutable_selection_attributes()->push_back(selection); |
| |
| CompositionText composition_text; |
| ime_->ExtractCompositionText(ibus_text, kCursorPos, &composition_text); |
| EXPECT_EQ(UTF8ToUTF16(kSampleText), composition_text.text); |
| EXPECT_EQ(kCursorPos, composition_text.selection.start()); |
| EXPECT_EQ(kCursorPos, composition_text.selection.end()); |
| ASSERT_EQ(1UL, composition_text.underlines.size()); |
| EXPECT_EQ(GetOffsetInUTF16(kSampleText, selection.start_index), |
| composition_text.underlines[0].start_offset); |
| EXPECT_EQ(GetOffsetInUTF16(kSampleText, selection.end_index), |
| composition_text.underlines[0].end_offset); |
| EXPECT_EQ(SK_ColorBLACK, composition_text.underlines[0].color); |
| EXPECT_TRUE(composition_text.underlines[0].thick); |
| } |
| |
| TEST_F(InputMethodIBusTest, |
| ExtractCompositionTextTest_SelectionStartWithCursor) { |
| const char kSampleText[] = "\xE3\x81\x82\xE3\x81\x84\xE3\x81\x86" |
| "\xE3\x81\x88\xE3\x81\x8A"; |
| const uint32 kCursorPos = 1UL; |
| |
| // Set up ibus text with one underline attribute. |
| chromeos::IBusText ibus_text; |
| ibus_text.set_text(kSampleText); |
| chromeos::IBusText::SelectionAttribute selection; |
| selection.start_index = kCursorPos; |
| selection.end_index = 4UL; |
| ibus_text.mutable_selection_attributes()->push_back(selection); |
| |
| CompositionText composition_text; |
| ime_->ExtractCompositionText(ibus_text, kCursorPos, &composition_text); |
| EXPECT_EQ(UTF8ToUTF16(kSampleText), composition_text.text); |
| // If the cursor position is same as selection bounds, selection start |
| // position become opposit side of selection from cursor. |
| EXPECT_EQ(GetOffsetInUTF16(kSampleText, selection.end_index), |
| composition_text.selection.start()); |
| EXPECT_EQ(GetOffsetInUTF16(kSampleText, kCursorPos), |
| composition_text.selection.end()); |
| ASSERT_EQ(1UL, composition_text.underlines.size()); |
| EXPECT_EQ(GetOffsetInUTF16(kSampleText, selection.start_index), |
| composition_text.underlines[0].start_offset); |
| EXPECT_EQ(GetOffsetInUTF16(kSampleText, selection.end_index), |
| composition_text.underlines[0].end_offset); |
| EXPECT_EQ(SK_ColorBLACK, composition_text.underlines[0].color); |
| EXPECT_TRUE(composition_text.underlines[0].thick); |
| } |
| |
| TEST_F(InputMethodIBusTest, ExtractCompositionTextTest_SelectionEndWithCursor) { |
| const char kSampleText[] = "\xE3\x81\x82\xE3\x81\x84\xE3\x81\x86" |
| "\xE3\x81\x88\xE3\x81\x8A"; |
| const uint32 kCursorPos = 4UL; |
| |
| // Set up ibus text with one underline attribute. |
| chromeos::IBusText ibus_text; |
| ibus_text.set_text(kSampleText); |
| chromeos::IBusText::SelectionAttribute selection; |
| selection.start_index = 1UL; |
| selection.end_index = kCursorPos; |
| ibus_text.mutable_selection_attributes()->push_back(selection); |
| |
| CompositionText composition_text; |
| ime_->ExtractCompositionText(ibus_text, kCursorPos, &composition_text); |
| EXPECT_EQ(UTF8ToUTF16(kSampleText), composition_text.text); |
| // If the cursor position is same as selection bounds, selection start |
| // position become opposit side of selection from cursor. |
| EXPECT_EQ(GetOffsetInUTF16(kSampleText, selection.start_index), |
| composition_text.selection.start()); |
| EXPECT_EQ(GetOffsetInUTF16(kSampleText, kCursorPos), |
| composition_text.selection.end()); |
| ASSERT_EQ(1UL, composition_text.underlines.size()); |
| EXPECT_EQ(GetOffsetInUTF16(kSampleText, selection.start_index), |
| composition_text.underlines[0].start_offset); |
| EXPECT_EQ(GetOffsetInUTF16(kSampleText, selection.end_index), |
| composition_text.underlines[0].end_offset); |
| EXPECT_EQ(SK_ColorBLACK, composition_text.underlines[0].color); |
| EXPECT_TRUE(composition_text.underlines[0].thick); |
| } |
| |
| TEST_F(InputMethodIBusTest, SurroundingText_NoSelectionTest) { |
| ime_->Init(true); |
| // Click a text input form. |
| input_type_ = TEXT_INPUT_TYPE_TEXT; |
| ime_->OnTextInputTypeChanged(this); |
| // Start the daemon. |
| InitIBusBus(); |
| SetCreateContextSuccessHandler(); |
| mock_ibus_daemon_controller_->EmulateConnect(); |
| |
| // Set the TextInputClient behaviors. |
| surrounding_text_ = UTF8ToUTF16("abcdef"); |
| text_range_ = ui::Range(0, 6); |
| selection_range_ = ui::Range(3, 3); |
| |
| // Set the verifier for SetSurroundingText mock call. |
| SetSurroundingTextVerifier verifier(UTF16ToUTF8(surrounding_text_), 3, 3); |
| |
| |
| mock_ibus_input_context_client_->set_set_surrounding_text_handler( |
| base::Bind(&SetSurroundingTextVerifier::Verify, |
| base::Unretained(&verifier))); |
| ime_->OnCaretBoundsChanged(this); |
| |
| // Check the call count. |
| EXPECT_EQ(1, |
| mock_ibus_input_context_client_->set_surrounding_text_call_count()); |
| } |
| |
| TEST_F(InputMethodIBusTest, SurroundingText_SelectionTest) { |
| ime_->Init(true); |
| // Click a text input form. |
| input_type_ = TEXT_INPUT_TYPE_TEXT; |
| ime_->OnTextInputTypeChanged(this); |
| // Start the daemon. |
| InitIBusBus(); |
| SetCreateContextSuccessHandler(); |
| mock_ibus_daemon_controller_->EmulateConnect(); |
| |
| // Set the TextInputClient behaviors. |
| surrounding_text_ = UTF8ToUTF16("abcdef"); |
| text_range_ = ui::Range(0, 6); |
| selection_range_ = ui::Range(2, 5); |
| |
| // Set the verifier for SetSurroundingText mock call. |
| SetSurroundingTextVerifier verifier(UTF16ToUTF8(surrounding_text_), 2, 5); |
| |
| mock_ibus_input_context_client_->set_set_surrounding_text_handler( |
| base::Bind(&SetSurroundingTextVerifier::Verify, |
| base::Unretained(&verifier))); |
| ime_->OnCaretBoundsChanged(this); |
| |
| // Check the call count. |
| EXPECT_EQ(1, |
| mock_ibus_input_context_client_->set_surrounding_text_call_count()); |
| } |
| |
| TEST_F(InputMethodIBusTest, SurroundingText_PartialText) { |
| ime_->Init(true); |
| // Click a text input form. |
| input_type_ = TEXT_INPUT_TYPE_TEXT; |
| ime_->OnTextInputTypeChanged(this); |
| // Start the daemon. |
| InitIBusBus(); |
| SetCreateContextSuccessHandler(); |
| mock_ibus_daemon_controller_->EmulateConnect(); |
| |
| // Set the TextInputClient behaviors. |
| surrounding_text_ = UTF8ToUTF16("abcdefghij"); |
| text_range_ = ui::Range(5, 10); |
| selection_range_ = ui::Range(7, 9); |
| |
| // Set the verifier for SetSurroundingText mock call. |
| // Here (2, 4) is selection range in expected surrounding text coordinates. |
| SetSurroundingTextVerifier verifier("fghij", 2, 4); |
| |
| mock_ibus_input_context_client_->set_set_surrounding_text_handler( |
| base::Bind(&SetSurroundingTextVerifier::Verify, |
| base::Unretained(&verifier))); |
| ime_->OnCaretBoundsChanged(this); |
| |
| // Check the call count. |
| EXPECT_EQ(1, |
| mock_ibus_input_context_client_->set_surrounding_text_call_count()); |
| } |
| |
| TEST_F(InputMethodIBusTest, SurroundingText_BecomeEmptyText) { |
| ime_->Init(true); |
| // Click a text input form. |
| input_type_ = TEXT_INPUT_TYPE_TEXT; |
| ime_->OnTextInputTypeChanged(this); |
| // Start the daemon. |
| InitIBusBus(); |
| SetCreateContextSuccessHandler(); |
| mock_ibus_daemon_controller_->EmulateConnect(); |
| |
| // Set the TextInputClient behaviors. |
| // If the surrounding text becomes empty, text_range become (0, 0) and |
| // selection range become invalid. |
| surrounding_text_ = UTF8ToUTF16(""); |
| text_range_ = ui::Range(0, 0); |
| selection_range_ = ui::Range::InvalidRange(); |
| |
| // Set the verifier for SetSurroundingText mock call. |
| SetSurroundingTextVerifier verifier("", 0, 0); |
| |
| mock_ibus_input_context_client_->set_set_surrounding_text_handler( |
| base::Bind(&SetSurroundingTextVerifier::Verify, |
| base::Unretained(&verifier))); |
| ime_->OnCaretBoundsChanged(this); |
| |
| // Check the call count. |
| EXPECT_EQ(0, |
| mock_ibus_input_context_client_->set_surrounding_text_call_count()); |
| |
| // Should not be called twice with same condition. |
| ime_->OnCaretBoundsChanged(this); |
| EXPECT_EQ(0, |
| mock_ibus_input_context_client_->set_surrounding_text_call_count()); |
| } |
| |
| class InputMethodIBusKeyEventTest : public InputMethodIBusTest { |
| public: |
| InputMethodIBusKeyEventTest() {} |
| virtual ~InputMethodIBusKeyEventTest() {} |
| |
| virtual void SetUp() OVERRIDE { |
| InputMethodIBusTest::SetUp(); |
| InitIBusBus(); |
| SetCreateContextSuccessHandler(); |
| ime_->Init(true); |
| mock_ibus_daemon_controller_->EmulateConnect(); |
| mock_ibus_input_context_client_->SetIsXKBLayout(false); |
| } |
| |
| DISALLOW_COPY_AND_ASSIGN(InputMethodIBusKeyEventTest); |
| }; |
| |
| TEST_F(InputMethodIBusKeyEventTest, KeyEventConsumeTest) { |
| XEvent event = {}; |
| event.xkey.type = KeyPress; |
| |
| // Set up IBusKeyEventFromNativeKeyEvent result. |
| ime_->mutable_ibus_key_event_from_native_key_event_result()->keyval |
| = kTestIBusKeyVal1; |
| ime_->mutable_ibus_key_event_from_native_key_event_result()->keycode |
| = kTestIBusKeyCode1; |
| ime_->mutable_ibus_key_event_from_native_key_event_result()->state |
| = kTestIBusState1; |
| |
| // Set up ProcessKeyEvent handler. |
| SynchronousKeyEventHandler success_consume_handler(kTestIBusKeyVal1, |
| kTestIBusKeyCode1, |
| kTestIBusState1, |
| KEYEVENT_CONSUME); |
| mock_ibus_input_context_client_->set_process_key_event_handler( |
| base::Bind(&SynchronousKeyEventHandler::Run, |
| base::Unretained(&success_consume_handler))); |
| |
| // Do key event. |
| input_type_ = TEXT_INPUT_TYPE_TEXT; |
| ime_->OnTextInputTypeChanged(this); |
| ime_->DispatchKeyEvent(&event); |
| |
| // Check result |
| EXPECT_EQ(1, |
| mock_ibus_input_context_client_->process_key_event_call_count()); |
| EXPECT_EQ(1, ime_->process_key_event_post_ime_call_count()); |
| EXPECT_TRUE(IsEqualXKeyEvent(event, |
| ime_->process_key_event_post_ime_args().event)); |
| EXPECT_TRUE(ime_->process_key_event_post_ime_args().handled); |
| } |
| |
| TEST_F(InputMethodIBusKeyEventTest, KeyEventNotConsumeTest) { |
| XEvent event = {}; |
| event.xkey.type = KeyPress; |
| |
| // Set up IBusKeyEventFromNativeKeyEvent result. |
| ime_->mutable_ibus_key_event_from_native_key_event_result()->keyval |
| = kTestIBusKeyVal1; |
| ime_->mutable_ibus_key_event_from_native_key_event_result()->keycode |
| = kTestIBusKeyCode1; |
| ime_->mutable_ibus_key_event_from_native_key_event_result()->state |
| = kTestIBusState1; |
| |
| // Set up ProcessKeyEvent handler. |
| SynchronousKeyEventHandler success_nonconsume_handler(kTestIBusKeyVal1, |
| kTestIBusKeyCode1, |
| kTestIBusState1, |
| KEYEVENT_NOT_CONSUME); |
| mock_ibus_input_context_client_->set_process_key_event_handler( |
| base::Bind(&SynchronousKeyEventHandler::Run, |
| base::Unretained(&success_nonconsume_handler))); |
| |
| // Do key event. |
| input_type_ = TEXT_INPUT_TYPE_TEXT; |
| ime_->OnTextInputTypeChanged(this); |
| ime_->DispatchKeyEvent(&event); |
| |
| EXPECT_EQ(1, |
| mock_ibus_input_context_client_->process_key_event_call_count()); |
| EXPECT_EQ(1, ime_->process_key_event_post_ime_call_count()); |
| EXPECT_TRUE(IsEqualXKeyEvent(event, |
| ime_->process_key_event_post_ime_args().event)); |
| EXPECT_FALSE(ime_->process_key_event_post_ime_args().handled); |
| } |
| |
| TEST_F(InputMethodIBusKeyEventTest, KeyEventFailTest) { |
| XEvent event = {}; |
| event.xkey.type = KeyPress; |
| |
| // Set up IBusKeyEventFromNativeKeyEvent result. |
| ime_->mutable_ibus_key_event_from_native_key_event_result()->keyval |
| = kTestIBusKeyVal1; |
| ime_->mutable_ibus_key_event_from_native_key_event_result()->keycode |
| = kTestIBusKeyCode1; |
| ime_->mutable_ibus_key_event_from_native_key_event_result()->state |
| = kTestIBusState1; |
| |
| // Set up ProcessKeyEvent handler. |
| SynchronousKeyEventHandler fail_handler(kTestIBusKeyVal1, |
| kTestIBusKeyCode1, |
| kTestIBusState1, |
| KEYEVENT_ERROR); |
| mock_ibus_input_context_client_->set_process_key_event_handler( |
| base::Bind(&SynchronousKeyEventHandler::Run, |
| base::Unretained(&fail_handler))); |
| |
| // Do key event. |
| input_type_ = TEXT_INPUT_TYPE_TEXT; |
| ime_->OnTextInputTypeChanged(this); |
| ime_->DispatchKeyEvent(&event); |
| |
| // Check result |
| EXPECT_EQ(1, |
| mock_ibus_input_context_client_->process_key_event_call_count()); |
| EXPECT_EQ(1, ime_->process_key_event_post_ime_call_count()); |
| // If some error is happend, key should not be consumed. |
| EXPECT_FALSE(ime_->process_key_event_post_ime_args().handled); |
| } |
| |
| TEST_F(InputMethodIBusKeyEventTest, KeyEventDelayResponseSuccessTest) { |
| XEvent event = {}; |
| event.xkey.type = KeyPress; |
| |
| // Set up IBusKeyEventFromNativeKeyEvent result. |
| ime_->mutable_ibus_key_event_from_native_key_event_result()->keyval |
| = kTestIBusKeyVal1; |
| ime_->mutable_ibus_key_event_from_native_key_event_result()->keycode |
| = kTestIBusKeyCode1; |
| ime_->mutable_ibus_key_event_from_native_key_event_result()->state |
| = kTestIBusState1; |
| |
| // Set up ProcessKeyEvent handler. |
| AsynchronousKeyEventHandler success_consume_handler(kTestIBusKeyVal1, |
| kTestIBusKeyCode1, |
| kTestIBusState1); |
| mock_ibus_input_context_client_->set_process_key_event_handler( |
| base::Bind(&AsynchronousKeyEventHandler::Run, |
| base::Unretained(&success_consume_handler))); |
| |
| // Do key event. |
| input_type_ = TEXT_INPUT_TYPE_TEXT; |
| ime_->OnTextInputTypeChanged(this); |
| ime_->DispatchKeyEvent(&event); |
| |
| // Check before state. |
| EXPECT_EQ(1, |
| mock_ibus_input_context_client_->process_key_event_call_count()); |
| EXPECT_EQ(0, ime_->process_key_event_post_ime_call_count()); |
| |
| // Do callback. |
| success_consume_handler.RunCallback(KEYEVENT_CONSUME); |
| |
| // Check the results |
| EXPECT_EQ(1, ime_->process_key_event_post_ime_call_count()); |
| EXPECT_TRUE(IsEqualXKeyEvent(event, |
| ime_->process_key_event_post_ime_args().event)); |
| EXPECT_TRUE(ime_->process_key_event_post_ime_args().handled); |
| } |
| |
| TEST_F(InputMethodIBusKeyEventTest, KeyEventDelayResponseFailTest) { |
| XEvent event = {}; |
| event.xkey.type = KeyPress; |
| |
| // Set up IBusKeyEventFromNativeKeyEvent result. |
| ime_->mutable_ibus_key_event_from_native_key_event_result()->keyval |
| = kTestIBusKeyVal1; |
| ime_->mutable_ibus_key_event_from_native_key_event_result()->keycode |
| = kTestIBusKeyCode1; |
| ime_->mutable_ibus_key_event_from_native_key_event_result()->state |
| = kTestIBusState1; |
| |
| // Set up ProcessKeyEvent handler. |
| AsynchronousKeyEventHandler fail_handler(kTestIBusKeyVal1, kTestIBusKeyCode1, |
| kTestIBusState1); |
| mock_ibus_input_context_client_->set_process_key_event_handler( |
| base::Bind(&AsynchronousKeyEventHandler::Run, |
| base::Unretained(&fail_handler))); |
| |
| // Do key event. |
| input_type_ = TEXT_INPUT_TYPE_TEXT; |
| ime_->OnTextInputTypeChanged(this); |
| ime_->DispatchKeyEvent(&event); |
| |
| // Check before state. |
| EXPECT_EQ(1, |
| mock_ibus_input_context_client_->process_key_event_call_count()); |
| EXPECT_EQ(0, ime_->process_key_event_post_ime_call_count()); |
| |
| // Do callback. |
| fail_handler.RunCallback(KEYEVENT_ERROR); |
| |
| // Check the results |
| EXPECT_EQ(1, ime_->process_key_event_post_ime_call_count()); |
| EXPECT_TRUE(IsEqualXKeyEvent(event, |
| ime_->process_key_event_post_ime_args().event)); |
| EXPECT_FALSE(ime_->process_key_event_post_ime_args().handled); |
| } |
| |
| TEST_F(InputMethodIBusKeyEventTest, MultiKeyEventDelayResponseSuccessTest) { |
| // Preparation |
| input_type_ = TEXT_INPUT_TYPE_TEXT; |
| ime_->OnTextInputTypeChanged(this); |
| |
| XEvent event = {}; |
| event.xkey.type = KeyPress; |
| |
| // Set up IBusKeyEventFromNativeKeyEvent result for first key event. |
| ime_->mutable_ibus_key_event_from_native_key_event_result()->keyval |
| = kTestIBusKeyVal1; |
| ime_->mutable_ibus_key_event_from_native_key_event_result()->keycode |
| = kTestIBusKeyCode1; |
| ime_->mutable_ibus_key_event_from_native_key_event_result()->state |
| = kTestIBusState1; |
| |
| // Set up ProcessKeyEvent handler. |
| AsynchronousKeyEventHandler handler1(kTestIBusKeyVal1, kTestIBusKeyCode1, |
| kTestIBusState1); |
| mock_ibus_input_context_client_->set_process_key_event_handler( |
| base::Bind(&AsynchronousKeyEventHandler::Run, |
| base::Unretained(&handler1))); |
| |
| // Do key event. |
| ime_->DispatchKeyEvent(&event); |
| |
| // Set up IBusKeyEventFromNativeKeyEvent result for second key event. |
| ime_->mutable_ibus_key_event_from_native_key_event_result()->keyval |
| = kTestIBusKeyVal2; |
| ime_->mutable_ibus_key_event_from_native_key_event_result()->keycode |
| = kTestIBusKeyCode2; |
| ime_->mutable_ibus_key_event_from_native_key_event_result()->state |
| = kTestIBusState2; |
| |
| // Set up yet another ProcessKeyEvent handler. |
| AsynchronousKeyEventHandler handler2(kTestIBusKeyVal2, kTestIBusKeyCode2, |
| kTestIBusState2); |
| mock_ibus_input_context_client_->set_process_key_event_handler( |
| base::Bind(&AsynchronousKeyEventHandler::Run, |
| base::Unretained(&handler2))); |
| |
| // Do key event again. |
| ime_->DispatchKeyEvent(&event); |
| |
| // Check before state. |
| EXPECT_EQ(2, |
| mock_ibus_input_context_client_->process_key_event_call_count()); |
| EXPECT_EQ(0, ime_->process_key_event_post_ime_call_count()); |
| |
| // Do callback for first key event. |
| handler1.RunCallback(KEYEVENT_CONSUME); |
| |
| // Check the results for first key event. |
| EXPECT_EQ(1, ime_->process_key_event_post_ime_call_count()); |
| EXPECT_TRUE(IsEqualXKeyEvent(event, |
| ime_->process_key_event_post_ime_args().event)); |
| EXPECT_TRUE(ime_->process_key_event_post_ime_args().handled); |
| |
| // Do callback for second key event. |
| handler2.RunCallback(KEYEVENT_NOT_CONSUME); |
| |
| // Check the results for second key event. |
| EXPECT_EQ(2, ime_->process_key_event_post_ime_call_count()); |
| EXPECT_TRUE(IsEqualXKeyEvent(event, |
| ime_->process_key_event_post_ime_args().event)); |
| EXPECT_FALSE(ime_->process_key_event_post_ime_args().handled); |
| } |
| |
| TEST_F(InputMethodIBusKeyEventTest, MultiKeyEventDelayResponseFailTest) { |
| // Preparation |
| input_type_ = TEXT_INPUT_TYPE_TEXT; |
| ime_->OnTextInputTypeChanged(this); |
| |
| XEvent event = {}; |
| event.xkey.type = KeyPress; |
| |
| // Set up IBusKeyEventFromNativeKeyEvent result for first key event. |
| ime_->mutable_ibus_key_event_from_native_key_event_result()->keyval |
| = kTestIBusKeyVal1; |
| ime_->mutable_ibus_key_event_from_native_key_event_result()->keycode |
| = kTestIBusKeyCode1; |
| ime_->mutable_ibus_key_event_from_native_key_event_result()->state |
| = kTestIBusState1; |
| |
| // Set up ProcessKeyEvent handler. |
| AsynchronousKeyEventHandler handler1(kTestIBusKeyVal1, kTestIBusKeyCode1, |
| kTestIBusState1); |
| mock_ibus_input_context_client_->set_process_key_event_handler( |
| base::Bind(&AsynchronousKeyEventHandler::Run, |
| base::Unretained(&handler1))); |
| |
| // Do key event. |
| ime_->DispatchKeyEvent(&event); |
| |
| // Set up IBusKeyEventFromNativeKeyEvent result for second key event. |
| ime_->mutable_ibus_key_event_from_native_key_event_result()->keyval |
| = kTestIBusKeyVal2; |
| ime_->mutable_ibus_key_event_from_native_key_event_result()->keycode |
| = kTestIBusKeyCode2; |
| ime_->mutable_ibus_key_event_from_native_key_event_result()->state |
| = kTestIBusState2; |
| |
| // Set up yet another ProcessKeyEvent handler. |
| AsynchronousKeyEventHandler handler2(kTestIBusKeyVal2, kTestIBusKeyCode2, |
| kTestIBusState2); |
| mock_ibus_input_context_client_->set_process_key_event_handler( |
| base::Bind(&AsynchronousKeyEventHandler::Run, |
| base::Unretained(&handler2))); |
| |
| // Do key event again. |
| ime_->DispatchKeyEvent(&event); |
| |
| // Check before state. |
| EXPECT_EQ(2, |
| mock_ibus_input_context_client_->process_key_event_call_count()); |
| EXPECT_EQ(0, ime_->process_key_event_post_ime_call_count()); |
| |
| // Do callback for first key event. |
| handler1.RunCallback(KEYEVENT_ERROR); |
| |
| // Check the results for first key event. |
| EXPECT_EQ(1, ime_->process_key_event_post_ime_call_count()); |
| EXPECT_TRUE(IsEqualXKeyEvent(event, |
| ime_->process_key_event_post_ime_args().event)); |
| EXPECT_FALSE(ime_->process_key_event_post_ime_args().handled); |
| |
| // Do callback for second key event. |
| handler2.RunCallback(KEYEVENT_ERROR); |
| |
| // Check the results for second key event. |
| EXPECT_EQ(2, ime_->process_key_event_post_ime_call_count()); |
| EXPECT_TRUE(IsEqualXKeyEvent(event, |
| ime_->process_key_event_post_ime_args().event)); |
| EXPECT_FALSE(ime_->process_key_event_post_ime_args().handled); |
| } |
| |
| TEST_F(InputMethodIBusKeyEventTest, |
| MultiKeyEventDelayResponseSuccessFailMixTest) { |
| // Preparation |
| input_type_ = TEXT_INPUT_TYPE_TEXT; |
| ime_->OnTextInputTypeChanged(this); |
| |
| XEvent event = {}; |
| event.xkey.type = KeyPress; |
| |
| // Set up IBusKeyEventFromNativeKeyEvent result for first key event. |
| ime_->mutable_ibus_key_event_from_native_key_event_result()->keyval |
| = kTestIBusKeyVal1; |
| ime_->mutable_ibus_key_event_from_native_key_event_result()->keycode |
| = kTestIBusKeyCode1; |
| ime_->mutable_ibus_key_event_from_native_key_event_result()->state |
| = kTestIBusState1; |
| |
| // Set up ProcessKeyEvent handler. |
| AsynchronousKeyEventHandler handler1(kTestIBusKeyVal1, kTestIBusKeyCode1, |
| kTestIBusState1); |
| mock_ibus_input_context_client_->set_process_key_event_handler( |
| base::Bind(&AsynchronousKeyEventHandler::Run, |
| base::Unretained(&handler1))); |
| |
| // Do key event. |
| ime_->DispatchKeyEvent(&event); |
| |
| // Set up IBusKeyEventFromNativeKeyEvent result for second key event. |
| ime_->mutable_ibus_key_event_from_native_key_event_result()->keyval |
| = kTestIBusKeyVal2; |
| ime_->mutable_ibus_key_event_from_native_key_event_result()->keycode |
| = kTestIBusKeyCode2; |
| ime_->mutable_ibus_key_event_from_native_key_event_result()->state |
| = kTestIBusState2; |
| |
| // Set up yet another ProcessKeyEvent handler. |
| AsynchronousKeyEventHandler handler2(kTestIBusKeyVal2, kTestIBusKeyCode2, |
| kTestIBusState2); |
| mock_ibus_input_context_client_->set_process_key_event_handler( |
| base::Bind(&AsynchronousKeyEventHandler::Run, |
| base::Unretained(&handler2))); |
| |
| // Do key event again. |
| ime_->DispatchKeyEvent(&event); |
| |
| // Set up IBusKeyEventFromNativeKeyEvent result for second key event. |
| ime_->mutable_ibus_key_event_from_native_key_event_result()->keyval |
| = kTestIBusKeyVal3; |
| ime_->mutable_ibus_key_event_from_native_key_event_result()->keycode |
| = kTestIBusKeyCode3; |
| ime_->mutable_ibus_key_event_from_native_key_event_result()->state |
| = kTestIBusState3; |
| |
| // Set up yet another ProcessKeyEvent handler. |
| AsynchronousKeyEventHandler handler3(kTestIBusKeyVal3, kTestIBusKeyCode3, |
| kTestIBusState3); |
| mock_ibus_input_context_client_->set_process_key_event_handler( |
| base::Bind(&AsynchronousKeyEventHandler::Run, |
| base::Unretained(&handler3))); |
| |
| // Do key event again. |
| ime_->DispatchKeyEvent(&event); |
| |
| // Check before state. |
| EXPECT_EQ(3, |
| mock_ibus_input_context_client_->process_key_event_call_count()); |
| EXPECT_EQ(0, ime_->process_key_event_post_ime_call_count()); |
| |
| // Do callback for first key event. |
| handler1.RunCallback(KEYEVENT_CONSUME); |
| |
| // Check the results for first key event. |
| EXPECT_EQ(1, ime_->process_key_event_post_ime_call_count()); |
| EXPECT_TRUE(IsEqualXKeyEvent(event, |
| ime_->process_key_event_post_ime_args().event)); |
| EXPECT_TRUE(ime_->process_key_event_post_ime_args().handled); |
| |
| // Do callback for second key event. |
| handler2.RunCallback(KEYEVENT_ERROR); |
| |
| // Check the results for second key event. |
| EXPECT_EQ(2, ime_->process_key_event_post_ime_call_count()); |
| EXPECT_TRUE(IsEqualXKeyEvent(event, |
| ime_->process_key_event_post_ime_args().event)); |
| EXPECT_FALSE(ime_->process_key_event_post_ime_args().handled); |
| |
| // Do callback for first key event. |
| handler3.RunCallback(KEYEVENT_CONSUME); |
| |
| // Check the results for first key event. |
| EXPECT_EQ(3, ime_->process_key_event_post_ime_call_count()); |
| EXPECT_TRUE(IsEqualXKeyEvent(event, |
| ime_->process_key_event_post_ime_args().event)); |
| EXPECT_TRUE(ime_->process_key_event_post_ime_args().handled); |
| } |
| |
| TEST_F(InputMethodIBusKeyEventTest, KeyEventDelayResponseResetTest) { |
| XEvent event = {}; |
| event.xkey.type = KeyPress; |
| |
| // Set up IBusKeyEventFromNativeKeyEvent result. |
| ime_->mutable_ibus_key_event_from_native_key_event_result()->keyval |
| = kTestIBusKeyVal1; |
| ime_->mutable_ibus_key_event_from_native_key_event_result()->keycode |
| = kTestIBusKeyCode1; |
| ime_->mutable_ibus_key_event_from_native_key_event_result()->state |
| = kTestIBusState1; |
| |
| // Set up ProcessKeyEvent handler. |
| AsynchronousKeyEventHandler success_consume_handler(kTestIBusKeyVal1, |
| kTestIBusKeyCode1, |
| kTestIBusState1); |
| mock_ibus_input_context_client_->set_process_key_event_handler( |
| base::Bind(&AsynchronousKeyEventHandler::Run, |
| base::Unretained(&success_consume_handler))); |
| |
| // Do key event. |
| input_type_ = TEXT_INPUT_TYPE_TEXT; |
| ime_->OnTextInputTypeChanged(this); |
| ime_->DispatchKeyEvent(&event); |
| |
| // Check before state. |
| EXPECT_EQ(1, |
| mock_ibus_input_context_client_->process_key_event_call_count()); |
| EXPECT_EQ(0, ime_->process_key_event_post_ime_call_count()); |
| |
| ime_->ResetContext(); |
| |
| // Do callback. |
| success_consume_handler.RunCallback(KEYEVENT_CONSUME); |
| |
| EXPECT_EQ(0, ime_->process_key_event_post_ime_call_count()); |
| } |
| |
| // TODO(nona): Introduce ProcessKeyEventPostIME tests(crbug.com/156593). |
| |
| } // namespace ui |