| OLD | NEW |
| (Empty) |
| 1 // Copyright 2014 The Chromium Authors. All rights reserved. | |
| 2 // Use of this source code is governed by a BSD-style license that can be | |
| 3 // found in the LICENSE file. | |
| 4 | |
| 5 #include "ui/base/ime/input_method_chromeos.h" | |
| 6 | |
| 7 #include <X11/Xlib.h> | |
| 8 #undef Bool | |
| 9 #undef FocusIn | |
| 10 #undef FocusOut | |
| 11 #undef None | |
| 12 | |
| 13 #include <cstring> | |
| 14 | |
| 15 #include "base/i18n/char_iterator.h" | |
| 16 #include "base/memory/scoped_ptr.h" | |
| 17 #include "base/strings/utf_string_conversions.h" | |
| 18 #include "chromeos/ime/composition_text.h" | |
| 19 #include "testing/gtest/include/gtest/gtest.h" | |
| 20 #include "ui/base/ime/chromeos/ime_bridge.h" | |
| 21 #include "ui/base/ime/chromeos/mock_ime_candidate_window_handler.h" | |
| 22 #include "ui/base/ime/chromeos/mock_ime_engine_handler.h" | |
| 23 #include "ui/base/ime/input_method_delegate.h" | |
| 24 #include "ui/base/ime/text_input_client.h" | |
| 25 #include "ui/base/ime/text_input_focus_manager.h" | |
| 26 #include "ui/base/ui_base_switches_util.h" | |
| 27 #include "ui/events/event.h" | |
| 28 #include "ui/events/test/events_test_utils_x11.h" | |
| 29 #include "ui/gfx/geometry/rect.h" | |
| 30 | |
| 31 using base::UTF8ToUTF16; | |
| 32 using base::UTF16ToUTF8; | |
| 33 | |
| 34 namespace ui { | |
| 35 namespace { | |
| 36 | |
| 37 const base::string16 kSampleText = base::UTF8ToUTF16( | |
| 38 "\xE3\x81\x82\xE3\x81\x84\xE3\x81\x86\xE3\x81\x88\xE3\x81\x8A"); | |
| 39 | |
| 40 typedef chromeos::IMEEngineHandlerInterface::KeyEventDoneCallback | |
| 41 KeyEventCallback; | |
| 42 | |
| 43 uint32 GetOffsetInUTF16( | |
| 44 const base::string16& utf16_string, uint32 utf8_offset) { | |
| 45 DCHECK_LT(utf8_offset, utf16_string.size()); | |
| 46 base::i18n::UTF16CharIterator char_iterator(&utf16_string); | |
| 47 for (size_t i = 0; i < utf8_offset; ++i) | |
| 48 char_iterator.Advance(); | |
| 49 return char_iterator.array_pos(); | |
| 50 } | |
| 51 | |
| 52 bool IsEqualXKeyEvent(const XEvent& e1, const XEvent& e2) { | |
| 53 if ((e1.type == KeyPress && e2.type == KeyPress) || | |
| 54 (e1.type == KeyRelease && e2.type == KeyRelease)) { | |
| 55 return !std::memcmp(&e1.xkey, &e2.xkey, sizeof(XKeyEvent)); | |
| 56 } | |
| 57 return false; | |
| 58 } | |
| 59 | |
| 60 enum KeyEventHandlerBehavior { | |
| 61 KEYEVENT_CONSUME, | |
| 62 KEYEVENT_NOT_CONSUME, | |
| 63 }; | |
| 64 | |
| 65 } // namespace | |
| 66 | |
| 67 | |
| 68 class TestableInputMethodChromeOS : public InputMethodChromeOS { | |
| 69 public: | |
| 70 explicit TestableInputMethodChromeOS(internal::InputMethodDelegate* delegate) | |
| 71 : InputMethodChromeOS(delegate), | |
| 72 process_key_event_post_ime_call_count_(0) { | |
| 73 } | |
| 74 | |
| 75 struct ProcessKeyEventPostIMEArgs { | |
| 76 ProcessKeyEventPostIMEArgs() : event(NULL), handled(false) {} | |
| 77 const ui::KeyEvent* event; | |
| 78 bool handled; | |
| 79 }; | |
| 80 | |
| 81 // Overridden from InputMethodChromeOS: | |
| 82 virtual void ProcessKeyEventPostIME(const ui::KeyEvent& key_event, | |
| 83 bool handled) override { | |
| 84 process_key_event_post_ime_args_.event = &key_event; | |
| 85 process_key_event_post_ime_args_.handled = handled; | |
| 86 ++process_key_event_post_ime_call_count_; | |
| 87 } | |
| 88 | |
| 89 void ResetCallCount() { | |
| 90 process_key_event_post_ime_call_count_ = 0; | |
| 91 } | |
| 92 | |
| 93 const ProcessKeyEventPostIMEArgs& process_key_event_post_ime_args() const { | |
| 94 return process_key_event_post_ime_args_; | |
| 95 } | |
| 96 | |
| 97 int process_key_event_post_ime_call_count() const { | |
| 98 return process_key_event_post_ime_call_count_; | |
| 99 } | |
| 100 | |
| 101 // Change access rights for testing. | |
| 102 using InputMethodChromeOS::ExtractCompositionText; | |
| 103 using InputMethodChromeOS::ResetContext; | |
| 104 | |
| 105 private: | |
| 106 ProcessKeyEventPostIMEArgs process_key_event_post_ime_args_; | |
| 107 int process_key_event_post_ime_call_count_; | |
| 108 }; | |
| 109 | |
| 110 class SynchronousKeyEventHandler { | |
| 111 public: | |
| 112 SynchronousKeyEventHandler(uint32 expected_keyval, | |
| 113 uint32 expected_keycode, | |
| 114 uint32 expected_state, | |
| 115 KeyEventHandlerBehavior behavior) | |
| 116 : expected_keyval_(expected_keyval), | |
| 117 expected_keycode_(expected_keycode), | |
| 118 expected_state_(expected_state), | |
| 119 behavior_(behavior) {} | |
| 120 | |
| 121 virtual ~SynchronousKeyEventHandler() {} | |
| 122 | |
| 123 void Run(uint32 keyval, | |
| 124 uint32 keycode, | |
| 125 uint32 state, | |
| 126 const KeyEventCallback& callback) { | |
| 127 EXPECT_EQ(expected_keyval_, keyval); | |
| 128 EXPECT_EQ(expected_keycode_, keycode); | |
| 129 EXPECT_EQ(expected_state_, state); | |
| 130 callback.Run(behavior_ == KEYEVENT_CONSUME); | |
| 131 } | |
| 132 | |
| 133 private: | |
| 134 const uint32 expected_keyval_; | |
| 135 const uint32 expected_keycode_; | |
| 136 const uint32 expected_state_; | |
| 137 const KeyEventHandlerBehavior behavior_; | |
| 138 | |
| 139 DISALLOW_COPY_AND_ASSIGN(SynchronousKeyEventHandler); | |
| 140 }; | |
| 141 | |
| 142 class AsynchronousKeyEventHandler { | |
| 143 public: | |
| 144 AsynchronousKeyEventHandler(uint32 expected_keyval, | |
| 145 uint32 expected_keycode, | |
| 146 uint32 expected_state) | |
| 147 : expected_keyval_(expected_keyval), | |
| 148 expected_keycode_(expected_keycode), | |
| 149 expected_state_(expected_state) {} | |
| 150 | |
| 151 virtual ~AsynchronousKeyEventHandler() {} | |
| 152 | |
| 153 void Run(uint32 keyval, | |
| 154 uint32 keycode, | |
| 155 uint32 state, | |
| 156 const KeyEventCallback& callback) { | |
| 157 EXPECT_EQ(expected_keyval_, keyval); | |
| 158 EXPECT_EQ(expected_keycode_, keycode); | |
| 159 EXPECT_EQ(expected_state_, state); | |
| 160 callback_ = callback; | |
| 161 } | |
| 162 | |
| 163 void RunCallback(KeyEventHandlerBehavior behavior) { | |
| 164 callback_.Run(behavior == KEYEVENT_CONSUME); | |
| 165 } | |
| 166 | |
| 167 private: | |
| 168 const uint32 expected_keyval_; | |
| 169 const uint32 expected_keycode_; | |
| 170 const uint32 expected_state_; | |
| 171 KeyEventCallback callback_; | |
| 172 | |
| 173 DISALLOW_COPY_AND_ASSIGN(AsynchronousKeyEventHandler); | |
| 174 }; | |
| 175 | |
| 176 class SetSurroundingTextVerifier { | |
| 177 public: | |
| 178 SetSurroundingTextVerifier(const std::string& expected_surrounding_text, | |
| 179 uint32 expected_cursor_position, | |
| 180 uint32 expected_anchor_position) | |
| 181 : expected_surrounding_text_(expected_surrounding_text), | |
| 182 expected_cursor_position_(expected_cursor_position), | |
| 183 expected_anchor_position_(expected_anchor_position) {} | |
| 184 | |
| 185 void Verify(const std::string& text, | |
| 186 uint32 cursor_pos, | |
| 187 uint32 anchor_pos) { | |
| 188 EXPECT_EQ(expected_surrounding_text_, text); | |
| 189 EXPECT_EQ(expected_cursor_position_, cursor_pos); | |
| 190 EXPECT_EQ(expected_anchor_position_, anchor_pos); | |
| 191 } | |
| 192 | |
| 193 private: | |
| 194 const std::string expected_surrounding_text_; | |
| 195 const uint32 expected_cursor_position_; | |
| 196 const uint32 expected_anchor_position_; | |
| 197 | |
| 198 DISALLOW_COPY_AND_ASSIGN(SetSurroundingTextVerifier); | |
| 199 }; | |
| 200 | |
| 201 class InputMethodChromeOSTest : public internal::InputMethodDelegate, | |
| 202 public testing::Test, | |
| 203 public TextInputClient { | |
| 204 public: | |
| 205 InputMethodChromeOSTest() | |
| 206 : dispatched_key_event_(ui::ET_UNKNOWN, ui::VKEY_UNKNOWN, ui::EF_NONE) { | |
| 207 ResetFlags(); | |
| 208 } | |
| 209 | |
| 210 virtual ~InputMethodChromeOSTest() { | |
| 211 } | |
| 212 | |
| 213 virtual void SetUp() override { | |
| 214 chromeos::IMEBridge::Initialize(); | |
| 215 | |
| 216 mock_ime_engine_handler_.reset( | |
| 217 new chromeos::MockIMEEngineHandler()); | |
| 218 chromeos::IMEBridge::Get()->SetCurrentEngineHandler( | |
| 219 mock_ime_engine_handler_.get()); | |
| 220 | |
| 221 mock_ime_candidate_window_handler_.reset( | |
| 222 new chromeos::MockIMECandidateWindowHandler()); | |
| 223 chromeos::IMEBridge::Get()->SetCandidateWindowHandler( | |
| 224 mock_ime_candidate_window_handler_.get()); | |
| 225 | |
| 226 ime_.reset(new TestableInputMethodChromeOS(this)); | |
| 227 if (switches::IsTextInputFocusManagerEnabled()) | |
| 228 TextInputFocusManager::GetInstance()->FocusTextInputClient(this); | |
| 229 else | |
| 230 ime_->SetFocusedTextInputClient(this); | |
| 231 } | |
| 232 | |
| 233 virtual void TearDown() override { | |
| 234 if (ime_.get()) { | |
| 235 if (switches::IsTextInputFocusManagerEnabled()) | |
| 236 TextInputFocusManager::GetInstance()->BlurTextInputClient(this); | |
| 237 else | |
| 238 ime_->SetFocusedTextInputClient(NULL); | |
| 239 } | |
| 240 ime_.reset(); | |
| 241 chromeos::IMEBridge::Get()->SetCurrentEngineHandler(NULL); | |
| 242 chromeos::IMEBridge::Get()->SetCandidateWindowHandler(NULL); | |
| 243 mock_ime_engine_handler_.reset(); | |
| 244 mock_ime_candidate_window_handler_.reset(); | |
| 245 chromeos::IMEBridge::Shutdown(); | |
| 246 } | |
| 247 | |
| 248 // Overridden from ui::internal::InputMethodDelegate: | |
| 249 virtual bool DispatchKeyEventPostIME(const ui::KeyEvent& event) override { | |
| 250 dispatched_key_event_ = event; | |
| 251 return false; | |
| 252 } | |
| 253 | |
| 254 // Overridden from ui::TextInputClient: | |
| 255 virtual void SetCompositionText( | |
| 256 const CompositionText& composition) override { | |
| 257 composition_text_ = composition; | |
| 258 } | |
| 259 virtual void ConfirmCompositionText() override { | |
| 260 confirmed_text_ = composition_text_; | |
| 261 composition_text_.Clear(); | |
| 262 } | |
| 263 virtual void ClearCompositionText() override { | |
| 264 composition_text_.Clear(); | |
| 265 } | |
| 266 virtual void InsertText(const base::string16& text) override { | |
| 267 inserted_text_ = text; | |
| 268 } | |
| 269 virtual void InsertChar(base::char16 ch, int flags) override { | |
| 270 inserted_char_ = ch; | |
| 271 inserted_char_flags_ = flags; | |
| 272 } | |
| 273 virtual gfx::NativeWindow GetAttachedWindow() const override { | |
| 274 return static_cast<gfx::NativeWindow>(NULL); | |
| 275 } | |
| 276 virtual TextInputType GetTextInputType() const override { | |
| 277 return input_type_; | |
| 278 } | |
| 279 virtual TextInputMode GetTextInputMode() const override { | |
| 280 return input_mode_; | |
| 281 } | |
| 282 virtual bool CanComposeInline() const override { | |
| 283 return can_compose_inline_; | |
| 284 } | |
| 285 virtual gfx::Rect GetCaretBounds() const override { | |
| 286 return caret_bounds_; | |
| 287 } | |
| 288 virtual bool GetCompositionCharacterBounds(uint32 index, | |
| 289 gfx::Rect* rect) const override { | |
| 290 return false; | |
| 291 } | |
| 292 virtual bool HasCompositionText() const override { | |
| 293 CompositionText empty; | |
| 294 return composition_text_ != empty; | |
| 295 } | |
| 296 virtual bool GetTextRange(gfx::Range* range) const override { | |
| 297 *range = text_range_; | |
| 298 return true; | |
| 299 } | |
| 300 virtual bool GetCompositionTextRange(gfx::Range* range) const override { | |
| 301 return false; | |
| 302 } | |
| 303 virtual bool GetSelectionRange(gfx::Range* range) const override { | |
| 304 *range = selection_range_; | |
| 305 return true; | |
| 306 } | |
| 307 | |
| 308 virtual bool SetSelectionRange(const gfx::Range& range) override { | |
| 309 return false; | |
| 310 } | |
| 311 virtual bool DeleteRange(const gfx::Range& range) override { return false; } | |
| 312 virtual bool GetTextFromRange(const gfx::Range& range, | |
| 313 base::string16* text) const override { | |
| 314 *text = surrounding_text_.substr(range.GetMin(), range.length()); | |
| 315 return true; | |
| 316 } | |
| 317 virtual void OnInputMethodChanged() override { | |
| 318 ++on_input_method_changed_call_count_; | |
| 319 } | |
| 320 virtual bool ChangeTextDirectionAndLayoutAlignment( | |
| 321 base::i18n::TextDirection direction) override { return false; } | |
| 322 virtual void ExtendSelectionAndDelete(size_t before, | |
| 323 size_t after) override {} | |
| 324 virtual void EnsureCaretInRect(const gfx::Rect& rect) override {} | |
| 325 virtual void OnCandidateWindowShown() override {} | |
| 326 virtual void OnCandidateWindowUpdated() override {} | |
| 327 virtual void OnCandidateWindowHidden() override {} | |
| 328 virtual bool IsEditingCommandEnabled(int command_id) override { | |
| 329 return false; | |
| 330 } | |
| 331 virtual void ExecuteEditingCommand(int command_id) override {} | |
| 332 | |
| 333 bool HasNativeEvent() const { | |
| 334 return dispatched_key_event_.HasNativeEvent(); | |
| 335 } | |
| 336 | |
| 337 void ResetFlags() { | |
| 338 dispatched_key_event_ = ui::KeyEvent(ui::ET_UNKNOWN, ui::VKEY_UNKNOWN, | |
| 339 ui::EF_NONE); | |
| 340 | |
| 341 composition_text_.Clear(); | |
| 342 confirmed_text_.Clear(); | |
| 343 inserted_text_.clear(); | |
| 344 inserted_char_ = 0; | |
| 345 inserted_char_flags_ = 0; | |
| 346 on_input_method_changed_call_count_ = 0; | |
| 347 | |
| 348 input_type_ = TEXT_INPUT_TYPE_NONE; | |
| 349 input_mode_ = TEXT_INPUT_MODE_DEFAULT; | |
| 350 can_compose_inline_ = true; | |
| 351 caret_bounds_ = gfx::Rect(); | |
| 352 } | |
| 353 | |
| 354 scoped_ptr<TestableInputMethodChromeOS> ime_; | |
| 355 | |
| 356 // Copy of the dispatched key event. | |
| 357 ui::KeyEvent dispatched_key_event_; | |
| 358 | |
| 359 // Variables for remembering the parameters that are passed to | |
| 360 // ui::TextInputClient functions. | |
| 361 CompositionText composition_text_; | |
| 362 CompositionText confirmed_text_; | |
| 363 base::string16 inserted_text_; | |
| 364 base::char16 inserted_char_; | |
| 365 unsigned int on_input_method_changed_call_count_; | |
| 366 int inserted_char_flags_; | |
| 367 | |
| 368 // Variables that will be returned from the ui::TextInputClient functions. | |
| 369 TextInputType input_type_; | |
| 370 TextInputMode input_mode_; | |
| 371 bool can_compose_inline_; | |
| 372 gfx::Rect caret_bounds_; | |
| 373 gfx::Range text_range_; | |
| 374 gfx::Range selection_range_; | |
| 375 base::string16 surrounding_text_; | |
| 376 | |
| 377 scoped_ptr<chromeos::MockIMEEngineHandler> mock_ime_engine_handler_; | |
| 378 scoped_ptr<chromeos::MockIMECandidateWindowHandler> | |
| 379 mock_ime_candidate_window_handler_; | |
| 380 | |
| 381 DISALLOW_COPY_AND_ASSIGN(InputMethodChromeOSTest); | |
| 382 }; | |
| 383 | |
| 384 // Tests public APIs in ui::InputMethod first. | |
| 385 | |
| 386 TEST_F(InputMethodChromeOSTest, GetInputLocale) { | |
| 387 // ui::InputMethodChromeOS does not support the API. | |
| 388 ime_->Init(true); | |
| 389 EXPECT_EQ("", ime_->GetInputLocale()); | |
| 390 } | |
| 391 | |
| 392 TEST_F(InputMethodChromeOSTest, IsActive) { | |
| 393 ime_->Init(true); | |
| 394 // ui::InputMethodChromeOS always returns true. | |
| 395 EXPECT_TRUE(ime_->IsActive()); | |
| 396 } | |
| 397 | |
| 398 TEST_F(InputMethodChromeOSTest, GetInputTextType) { | |
| 399 ime_->Init(true); | |
| 400 EXPECT_EQ(TEXT_INPUT_TYPE_NONE, ime_->GetTextInputType()); | |
| 401 input_type_ = TEXT_INPUT_TYPE_PASSWORD; | |
| 402 ime_->OnTextInputTypeChanged(this); | |
| 403 EXPECT_EQ(TEXT_INPUT_TYPE_PASSWORD, ime_->GetTextInputType()); | |
| 404 input_type_ = TEXT_INPUT_TYPE_TEXT; | |
| 405 ime_->OnTextInputTypeChanged(this); | |
| 406 EXPECT_EQ(TEXT_INPUT_TYPE_TEXT, ime_->GetTextInputType()); | |
| 407 } | |
| 408 | |
| 409 TEST_F(InputMethodChromeOSTest, CanComposeInline) { | |
| 410 ime_->Init(true); | |
| 411 EXPECT_TRUE(ime_->CanComposeInline()); | |
| 412 can_compose_inline_ = false; | |
| 413 ime_->OnTextInputTypeChanged(this); | |
| 414 EXPECT_FALSE(ime_->CanComposeInline()); | |
| 415 } | |
| 416 | |
| 417 TEST_F(InputMethodChromeOSTest, GetTextInputClient) { | |
| 418 ime_->Init(true); | |
| 419 EXPECT_EQ(this, ime_->GetTextInputClient()); | |
| 420 if (switches::IsTextInputFocusManagerEnabled()) | |
| 421 TextInputFocusManager::GetInstance()->BlurTextInputClient(this); | |
| 422 else | |
| 423 ime_->SetFocusedTextInputClient(NULL); | |
| 424 EXPECT_EQ(NULL, ime_->GetTextInputClient()); | |
| 425 } | |
| 426 | |
| 427 TEST_F(InputMethodChromeOSTest, GetInputTextType_WithoutFocusedClient) { | |
| 428 ime_->Init(true); | |
| 429 EXPECT_EQ(TEXT_INPUT_TYPE_NONE, ime_->GetTextInputType()); | |
| 430 if (switches::IsTextInputFocusManagerEnabled()) | |
| 431 TextInputFocusManager::GetInstance()->BlurTextInputClient(this); | |
| 432 else | |
| 433 ime_->SetFocusedTextInputClient(NULL); | |
| 434 input_type_ = TEXT_INPUT_TYPE_PASSWORD; | |
| 435 ime_->OnTextInputTypeChanged(this); | |
| 436 // The OnTextInputTypeChanged() call above should be ignored since |this| is | |
| 437 // not the current focused client. | |
| 438 EXPECT_EQ(TEXT_INPUT_TYPE_NONE, ime_->GetTextInputType()); | |
| 439 | |
| 440 if (switches::IsTextInputFocusManagerEnabled()) | |
| 441 TextInputFocusManager::GetInstance()->FocusTextInputClient(this); | |
| 442 else | |
| 443 ime_->SetFocusedTextInputClient(this); | |
| 444 ime_->OnTextInputTypeChanged(this); | |
| 445 EXPECT_EQ(TEXT_INPUT_TYPE_PASSWORD, ime_->GetTextInputType()); | |
| 446 } | |
| 447 | |
| 448 TEST_F(InputMethodChromeOSTest, GetInputTextType_WithoutFocusedWindow) { | |
| 449 ime_->Init(true); | |
| 450 EXPECT_EQ(TEXT_INPUT_TYPE_NONE, ime_->GetTextInputType()); | |
| 451 if (switches::IsTextInputFocusManagerEnabled()) | |
| 452 TextInputFocusManager::GetInstance()->BlurTextInputClient(this); | |
| 453 else | |
| 454 ime_->OnBlur(); | |
| 455 input_type_ = TEXT_INPUT_TYPE_PASSWORD; | |
| 456 ime_->OnTextInputTypeChanged(this); | |
| 457 // The OnTextInputTypeChanged() call above should be ignored since the top- | |
| 458 // level window which the ime_ is attached to is not currently focused. | |
| 459 EXPECT_EQ(TEXT_INPUT_TYPE_NONE, ime_->GetTextInputType()); | |
| 460 | |
| 461 if (switches::IsTextInputFocusManagerEnabled()) | |
| 462 TextInputFocusManager::GetInstance()->FocusTextInputClient(this); | |
| 463 else | |
| 464 ime_->OnFocus(); | |
| 465 ime_->OnTextInputTypeChanged(this); | |
| 466 EXPECT_EQ(TEXT_INPUT_TYPE_PASSWORD, ime_->GetTextInputType()); | |
| 467 } | |
| 468 | |
| 469 TEST_F(InputMethodChromeOSTest, GetInputTextType_WithoutFocusedWindow2) { | |
| 470 // We no longer support the case that |ime_->Init(false)| because no one | |
| 471 // actually uses it. | |
| 472 if (switches::IsTextInputFocusManagerEnabled()) | |
| 473 return; | |
| 474 | |
| 475 ime_->Init(false); // the top-level is initially unfocused. | |
| 476 EXPECT_EQ(TEXT_INPUT_TYPE_NONE, ime_->GetTextInputType()); | |
| 477 input_type_ = TEXT_INPUT_TYPE_PASSWORD; | |
| 478 ime_->OnTextInputTypeChanged(this); | |
| 479 EXPECT_EQ(TEXT_INPUT_TYPE_NONE, ime_->GetTextInputType()); | |
| 480 | |
| 481 ime_->OnFocus(); | |
| 482 ime_->OnTextInputTypeChanged(this); | |
| 483 EXPECT_EQ(TEXT_INPUT_TYPE_PASSWORD, ime_->GetTextInputType()); | |
| 484 } | |
| 485 | |
| 486 // Confirm that IBusClient::FocusIn is called on "connected" if input_type_ is | |
| 487 // TEXT. | |
| 488 TEST_F(InputMethodChromeOSTest, FocusIn_Text) { | |
| 489 ime_->Init(true); | |
| 490 // A context shouldn't be created since the daemon is not running. | |
| 491 EXPECT_EQ(0U, on_input_method_changed_call_count_); | |
| 492 // Click a text input form. | |
| 493 input_type_ = TEXT_INPUT_TYPE_TEXT; | |
| 494 ime_->OnTextInputTypeChanged(this); | |
| 495 // Since a form has focus, IBusClient::FocusIn() should be called. | |
| 496 EXPECT_EQ(1, mock_ime_engine_handler_->focus_in_call_count()); | |
| 497 EXPECT_EQ( | |
| 498 1, | |
| 499 mock_ime_candidate_window_handler_->set_cursor_bounds_call_count()); | |
| 500 // ui::TextInputClient::OnInputMethodChanged() should be called when | |
| 501 // ui::InputMethodChromeOS connects/disconnects to/from ibus-daemon and the | |
| 502 // current text input type is not NONE. | |
| 503 EXPECT_EQ(1U, on_input_method_changed_call_count_); | |
| 504 } | |
| 505 | |
| 506 // Confirm that InputMethodEngine::FocusIn is called on "connected" even if | |
| 507 // input_type_ is PASSWORD. | |
| 508 TEST_F(InputMethodChromeOSTest, FocusIn_Password) { | |
| 509 ime_->Init(true); | |
| 510 EXPECT_EQ(0U, on_input_method_changed_call_count_); | |
| 511 input_type_ = TEXT_INPUT_TYPE_PASSWORD; | |
| 512 ime_->OnTextInputTypeChanged(this); | |
| 513 // InputMethodEngine::FocusIn() should be called even for password field. | |
| 514 EXPECT_EQ(1, mock_ime_engine_handler_->focus_in_call_count()); | |
| 515 EXPECT_EQ(1U, on_input_method_changed_call_count_); | |
| 516 } | |
| 517 | |
| 518 // Confirm that IBusClient::FocusOut is called as expected. | |
| 519 TEST_F(InputMethodChromeOSTest, FocusOut_None) { | |
| 520 input_type_ = TEXT_INPUT_TYPE_TEXT; | |
| 521 ime_->Init(true); | |
| 522 EXPECT_EQ(1, mock_ime_engine_handler_->focus_in_call_count()); | |
| 523 EXPECT_EQ(0, mock_ime_engine_handler_->focus_out_call_count()); | |
| 524 input_type_ = TEXT_INPUT_TYPE_NONE; | |
| 525 ime_->OnTextInputTypeChanged(this); | |
| 526 EXPECT_EQ(1, mock_ime_engine_handler_->focus_in_call_count()); | |
| 527 EXPECT_EQ(1, mock_ime_engine_handler_->focus_out_call_count()); | |
| 528 } | |
| 529 | |
| 530 // Confirm that IBusClient::FocusOut is called as expected. | |
| 531 TEST_F(InputMethodChromeOSTest, FocusOut_Password) { | |
| 532 input_type_ = TEXT_INPUT_TYPE_TEXT; | |
| 533 ime_->Init(true); | |
| 534 EXPECT_EQ(1, mock_ime_engine_handler_->focus_in_call_count()); | |
| 535 EXPECT_EQ(0, mock_ime_engine_handler_->focus_out_call_count()); | |
| 536 input_type_ = TEXT_INPUT_TYPE_PASSWORD; | |
| 537 ime_->OnTextInputTypeChanged(this); | |
| 538 EXPECT_EQ(2, mock_ime_engine_handler_->focus_in_call_count()); | |
| 539 EXPECT_EQ(1, mock_ime_engine_handler_->focus_out_call_count()); | |
| 540 } | |
| 541 | |
| 542 // FocusIn/FocusOut scenario test | |
| 543 TEST_F(InputMethodChromeOSTest, Focus_Scenario) { | |
| 544 ime_->Init(true); | |
| 545 // Confirm that both FocusIn and FocusOut are NOT called. | |
| 546 EXPECT_EQ(0, mock_ime_engine_handler_->focus_in_call_count()); | |
| 547 EXPECT_EQ(0, mock_ime_engine_handler_->focus_out_call_count()); | |
| 548 EXPECT_EQ(TEXT_INPUT_TYPE_NONE, | |
| 549 mock_ime_engine_handler_->last_text_input_context().type); | |
| 550 EXPECT_EQ(TEXT_INPUT_MODE_DEFAULT, | |
| 551 mock_ime_engine_handler_->last_text_input_context().mode); | |
| 552 | |
| 553 input_type_ = TEXT_INPUT_TYPE_TEXT; | |
| 554 input_mode_ = TEXT_INPUT_MODE_LATIN; | |
| 555 ime_->OnTextInputTypeChanged(this); | |
| 556 // Confirm that only FocusIn is called, the TextInputType is TEXT and the | |
| 557 // TextInputMode is LATIN.. | |
| 558 EXPECT_EQ(1, mock_ime_engine_handler_->focus_in_call_count()); | |
| 559 EXPECT_EQ(0, mock_ime_engine_handler_->focus_out_call_count()); | |
| 560 EXPECT_EQ(TEXT_INPUT_TYPE_TEXT, | |
| 561 mock_ime_engine_handler_->last_text_input_context().type); | |
| 562 EXPECT_EQ(TEXT_INPUT_MODE_LATIN, | |
| 563 mock_ime_engine_handler_->last_text_input_context().mode); | |
| 564 | |
| 565 input_mode_ = TEXT_INPUT_MODE_KANA; | |
| 566 ime_->OnTextInputTypeChanged(this); | |
| 567 // Confirm that both FocusIn and FocusOut are called for mode change. | |
| 568 EXPECT_EQ(2, mock_ime_engine_handler_->focus_in_call_count()); | |
| 569 EXPECT_EQ(1, mock_ime_engine_handler_->focus_out_call_count()); | |
| 570 EXPECT_EQ(TEXT_INPUT_TYPE_TEXT, | |
| 571 mock_ime_engine_handler_->last_text_input_context().type); | |
| 572 EXPECT_EQ(TEXT_INPUT_MODE_KANA, | |
| 573 mock_ime_engine_handler_->last_text_input_context().mode); | |
| 574 | |
| 575 input_type_ = TEXT_INPUT_TYPE_URL; | |
| 576 ime_->OnTextInputTypeChanged(this); | |
| 577 // Confirm that both FocusIn and FocusOut are called and the TextInputType is | |
| 578 // changed to URL. | |
| 579 EXPECT_EQ(3, mock_ime_engine_handler_->focus_in_call_count()); | |
| 580 EXPECT_EQ(2, mock_ime_engine_handler_->focus_out_call_count()); | |
| 581 EXPECT_EQ(TEXT_INPUT_TYPE_URL, | |
| 582 mock_ime_engine_handler_->last_text_input_context().type); | |
| 583 EXPECT_EQ(TEXT_INPUT_MODE_KANA, | |
| 584 mock_ime_engine_handler_->last_text_input_context().mode); | |
| 585 | |
| 586 // When IsTextInputFocusManagerEnabled, InputMethod::SetFocusedTextInputClient | |
| 587 // is not supported and it's no-op. | |
| 588 if (switches::IsTextInputFocusManagerEnabled()) | |
| 589 return; | |
| 590 // Confirm that FocusOut is called when set focus to NULL client. | |
| 591 ime_->SetFocusedTextInputClient(NULL); | |
| 592 EXPECT_EQ(3, mock_ime_engine_handler_->focus_in_call_count()); | |
| 593 EXPECT_EQ(3, mock_ime_engine_handler_->focus_out_call_count()); | |
| 594 // Confirm that FocusIn is called when set focus to this client. | |
| 595 ime_->SetFocusedTextInputClient(this); | |
| 596 EXPECT_EQ(4, mock_ime_engine_handler_->focus_in_call_count()); | |
| 597 EXPECT_EQ(3, mock_ime_engine_handler_->focus_out_call_count()); | |
| 598 } | |
| 599 | |
| 600 // Test if the new |caret_bounds_| is correctly sent to ibus-daemon. | |
| 601 TEST_F(InputMethodChromeOSTest, OnCaretBoundsChanged) { | |
| 602 input_type_ = TEXT_INPUT_TYPE_TEXT; | |
| 603 ime_->Init(true); | |
| 604 EXPECT_EQ( | |
| 605 1, | |
| 606 mock_ime_candidate_window_handler_->set_cursor_bounds_call_count()); | |
| 607 caret_bounds_ = gfx::Rect(1, 2, 3, 4); | |
| 608 ime_->OnCaretBoundsChanged(this); | |
| 609 EXPECT_EQ( | |
| 610 2, | |
| 611 mock_ime_candidate_window_handler_->set_cursor_bounds_call_count()); | |
| 612 caret_bounds_ = gfx::Rect(0, 2, 3, 4); | |
| 613 ime_->OnCaretBoundsChanged(this); | |
| 614 EXPECT_EQ( | |
| 615 3, | |
| 616 mock_ime_candidate_window_handler_->set_cursor_bounds_call_count()); | |
| 617 caret_bounds_ = gfx::Rect(0, 2, 3, 4); // unchanged | |
| 618 ime_->OnCaretBoundsChanged(this); | |
| 619 // Current InputMethodChromeOS implementation performs the IPC | |
| 620 // regardless of the bounds are changed or not. | |
| 621 EXPECT_EQ( | |
| 622 4, | |
| 623 mock_ime_candidate_window_handler_->set_cursor_bounds_call_count()); | |
| 624 } | |
| 625 | |
| 626 TEST_F(InputMethodChromeOSTest, ExtractCompositionTextTest_NoAttribute) { | |
| 627 const base::string16 kSampleAsciiText = UTF8ToUTF16("Sample Text"); | |
| 628 const uint32 kCursorPos = 2UL; | |
| 629 | |
| 630 chromeos::CompositionText chromeos_composition_text; | |
| 631 chromeos_composition_text.set_text(kSampleAsciiText); | |
| 632 | |
| 633 CompositionText composition_text; | |
| 634 ime_->ExtractCompositionText( | |
| 635 chromeos_composition_text, kCursorPos, &composition_text); | |
| 636 EXPECT_EQ(kSampleAsciiText, composition_text.text); | |
| 637 // If there is no selection, |selection| represents cursor position. | |
| 638 EXPECT_EQ(kCursorPos, composition_text.selection.start()); | |
| 639 EXPECT_EQ(kCursorPos, composition_text.selection.end()); | |
| 640 // If there is no underline, |underlines| contains one underline and it is | |
| 641 // whole text underline. | |
| 642 ASSERT_EQ(1UL, composition_text.underlines.size()); | |
| 643 EXPECT_EQ(0UL, composition_text.underlines[0].start_offset); | |
| 644 EXPECT_EQ(kSampleAsciiText.size(), composition_text.underlines[0].end_offset); | |
| 645 EXPECT_FALSE(composition_text.underlines[0].thick); | |
| 646 } | |
| 647 | |
| 648 TEST_F(InputMethodChromeOSTest, ExtractCompositionTextTest_SingleUnderline) { | |
| 649 const uint32 kCursorPos = 2UL; | |
| 650 | |
| 651 // Set up chromeos composition text with one underline attribute. | |
| 652 chromeos::CompositionText chromeos_composition_text; | |
| 653 chromeos_composition_text.set_text(kSampleText); | |
| 654 chromeos::CompositionText::UnderlineAttribute underline; | |
| 655 underline.type = chromeos::CompositionText::COMPOSITION_TEXT_UNDERLINE_SINGLE; | |
| 656 underline.start_index = 1UL; | |
| 657 underline.end_index = 4UL; | |
| 658 chromeos_composition_text.mutable_underline_attributes()->push_back( | |
| 659 underline); | |
| 660 | |
| 661 CompositionText composition_text; | |
| 662 ime_->ExtractCompositionText( | |
| 663 chromeos_composition_text, kCursorPos, &composition_text); | |
| 664 EXPECT_EQ(kSampleText, composition_text.text); | |
| 665 // If there is no selection, |selection| represents cursor position. | |
| 666 EXPECT_EQ(kCursorPos, composition_text.selection.start()); | |
| 667 EXPECT_EQ(kCursorPos, composition_text.selection.end()); | |
| 668 ASSERT_EQ(1UL, composition_text.underlines.size()); | |
| 669 EXPECT_EQ(GetOffsetInUTF16(kSampleText, underline.start_index), | |
| 670 composition_text.underlines[0].start_offset); | |
| 671 EXPECT_EQ(GetOffsetInUTF16(kSampleText, underline.end_index), | |
| 672 composition_text.underlines[0].end_offset); | |
| 673 // Single underline represents as black thin line. | |
| 674 EXPECT_EQ(SK_ColorBLACK, composition_text.underlines[0].color); | |
| 675 EXPECT_FALSE(composition_text.underlines[0].thick); | |
| 676 EXPECT_EQ(static_cast<SkColor>(SK_ColorTRANSPARENT), | |
| 677 composition_text.underlines[0].background_color); | |
| 678 } | |
| 679 | |
| 680 TEST_F(InputMethodChromeOSTest, ExtractCompositionTextTest_DoubleUnderline) { | |
| 681 const uint32 kCursorPos = 2UL; | |
| 682 | |
| 683 // Set up chromeos composition text with one underline attribute. | |
| 684 chromeos::CompositionText chromeos_composition_text; | |
| 685 chromeos_composition_text.set_text(kSampleText); | |
| 686 chromeos::CompositionText::UnderlineAttribute underline; | |
| 687 underline.type = chromeos::CompositionText::COMPOSITION_TEXT_UNDERLINE_DOUBLE; | |
| 688 underline.start_index = 1UL; | |
| 689 underline.end_index = 4UL; | |
| 690 chromeos_composition_text.mutable_underline_attributes()->push_back( | |
| 691 underline); | |
| 692 | |
| 693 CompositionText composition_text; | |
| 694 ime_->ExtractCompositionText( | |
| 695 chromeos_composition_text, kCursorPos, &composition_text); | |
| 696 EXPECT_EQ(kSampleText, composition_text.text); | |
| 697 // If there is no selection, |selection| represents cursor position. | |
| 698 EXPECT_EQ(kCursorPos, composition_text.selection.start()); | |
| 699 EXPECT_EQ(kCursorPos, composition_text.selection.end()); | |
| 700 ASSERT_EQ(1UL, composition_text.underlines.size()); | |
| 701 EXPECT_EQ(GetOffsetInUTF16(kSampleText, underline.start_index), | |
| 702 composition_text.underlines[0].start_offset); | |
| 703 EXPECT_EQ(GetOffsetInUTF16(kSampleText, underline.end_index), | |
| 704 composition_text.underlines[0].end_offset); | |
| 705 // Double underline represents as black thick line. | |
| 706 EXPECT_EQ(SK_ColorBLACK, composition_text.underlines[0].color); | |
| 707 EXPECT_TRUE(composition_text.underlines[0].thick); | |
| 708 EXPECT_EQ(static_cast<SkColor>(SK_ColorTRANSPARENT), | |
| 709 composition_text.underlines[0].background_color); | |
| 710 } | |
| 711 | |
| 712 TEST_F(InputMethodChromeOSTest, ExtractCompositionTextTest_ErrorUnderline) { | |
| 713 const uint32 kCursorPos = 2UL; | |
| 714 | |
| 715 // Set up chromeos composition text with one underline attribute. | |
| 716 chromeos::CompositionText chromeos_composition_text; | |
| 717 chromeos_composition_text.set_text(kSampleText); | |
| 718 chromeos::CompositionText::UnderlineAttribute underline; | |
| 719 underline.type = chromeos::CompositionText::COMPOSITION_TEXT_UNDERLINE_ERROR; | |
| 720 underline.start_index = 1UL; | |
| 721 underline.end_index = 4UL; | |
| 722 chromeos_composition_text.mutable_underline_attributes()->push_back( | |
| 723 underline); | |
| 724 | |
| 725 CompositionText composition_text; | |
| 726 ime_->ExtractCompositionText( | |
| 727 chromeos_composition_text, kCursorPos, &composition_text); | |
| 728 EXPECT_EQ(kSampleText, composition_text.text); | |
| 729 EXPECT_EQ(kCursorPos, composition_text.selection.start()); | |
| 730 EXPECT_EQ(kCursorPos, composition_text.selection.end()); | |
| 731 ASSERT_EQ(1UL, composition_text.underlines.size()); | |
| 732 EXPECT_EQ(GetOffsetInUTF16(kSampleText, underline.start_index), | |
| 733 composition_text.underlines[0].start_offset); | |
| 734 EXPECT_EQ(GetOffsetInUTF16(kSampleText, underline.end_index), | |
| 735 composition_text.underlines[0].end_offset); | |
| 736 // Error underline represents as red thin line. | |
| 737 EXPECT_EQ(SK_ColorRED, composition_text.underlines[0].color); | |
| 738 EXPECT_FALSE(composition_text.underlines[0].thick); | |
| 739 } | |
| 740 | |
| 741 TEST_F(InputMethodChromeOSTest, ExtractCompositionTextTest_Selection) { | |
| 742 const uint32 kCursorPos = 2UL; | |
| 743 | |
| 744 // Set up chromeos composition text with one underline attribute. | |
| 745 chromeos::CompositionText chromeos_composition_text; | |
| 746 chromeos_composition_text.set_text(kSampleText); | |
| 747 chromeos_composition_text.set_selection_start(1UL); | |
| 748 chromeos_composition_text.set_selection_end(4UL); | |
| 749 | |
| 750 CompositionText composition_text; | |
| 751 ime_->ExtractCompositionText( | |
| 752 chromeos_composition_text, kCursorPos, &composition_text); | |
| 753 EXPECT_EQ(kSampleText, composition_text.text); | |
| 754 EXPECT_EQ(kCursorPos, composition_text.selection.start()); | |
| 755 EXPECT_EQ(kCursorPos, composition_text.selection.end()); | |
| 756 ASSERT_EQ(1UL, composition_text.underlines.size()); | |
| 757 EXPECT_EQ(GetOffsetInUTF16(kSampleText, | |
| 758 chromeos_composition_text.selection_start()), | |
| 759 composition_text.underlines[0].start_offset); | |
| 760 EXPECT_EQ(GetOffsetInUTF16(kSampleText, | |
| 761 chromeos_composition_text.selection_end()), | |
| 762 composition_text.underlines[0].end_offset); | |
| 763 EXPECT_EQ(SK_ColorBLACK, composition_text.underlines[0].color); | |
| 764 EXPECT_TRUE(composition_text.underlines[0].thick); | |
| 765 EXPECT_EQ(static_cast<SkColor>(SK_ColorTRANSPARENT), | |
| 766 composition_text.underlines[0].background_color); | |
| 767 } | |
| 768 | |
| 769 TEST_F(InputMethodChromeOSTest, | |
| 770 ExtractCompositionTextTest_SelectionStartWithCursor) { | |
| 771 const uint32 kCursorPos = 1UL; | |
| 772 | |
| 773 // Set up chromeos composition text with one underline attribute. | |
| 774 chromeos::CompositionText chromeos_composition_text; | |
| 775 chromeos_composition_text.set_text(kSampleText); | |
| 776 chromeos_composition_text.set_selection_start(kCursorPos); | |
| 777 chromeos_composition_text.set_selection_end(4UL); | |
| 778 | |
| 779 CompositionText composition_text; | |
| 780 ime_->ExtractCompositionText( | |
| 781 chromeos_composition_text, kCursorPos, &composition_text); | |
| 782 EXPECT_EQ(kSampleText, composition_text.text); | |
| 783 // If the cursor position is same as selection bounds, selection start | |
| 784 // position become opposit side of selection from cursor. | |
| 785 EXPECT_EQ(GetOffsetInUTF16(kSampleText, | |
| 786 chromeos_composition_text.selection_end()), | |
| 787 composition_text.selection.start()); | |
| 788 EXPECT_EQ(GetOffsetInUTF16(kSampleText, kCursorPos), | |
| 789 composition_text.selection.end()); | |
| 790 ASSERT_EQ(1UL, composition_text.underlines.size()); | |
| 791 EXPECT_EQ(GetOffsetInUTF16(kSampleText, | |
| 792 chromeos_composition_text.selection_start()), | |
| 793 composition_text.underlines[0].start_offset); | |
| 794 EXPECT_EQ(GetOffsetInUTF16(kSampleText, | |
| 795 chromeos_composition_text.selection_end()), | |
| 796 composition_text.underlines[0].end_offset); | |
| 797 EXPECT_EQ(SK_ColorBLACK, composition_text.underlines[0].color); | |
| 798 EXPECT_TRUE(composition_text.underlines[0].thick); | |
| 799 EXPECT_EQ(static_cast<SkColor>(SK_ColorTRANSPARENT), | |
| 800 composition_text.underlines[0].background_color); | |
| 801 } | |
| 802 | |
| 803 TEST_F(InputMethodChromeOSTest, | |
| 804 ExtractCompositionTextTest_SelectionEndWithCursor) { | |
| 805 const uint32 kCursorPos = 4UL; | |
| 806 | |
| 807 // Set up chromeos composition text with one underline attribute. | |
| 808 chromeos::CompositionText chromeos_composition_text; | |
| 809 chromeos_composition_text.set_text(kSampleText); | |
| 810 chromeos_composition_text.set_selection_start(1UL); | |
| 811 chromeos_composition_text.set_selection_end(kCursorPos); | |
| 812 | |
| 813 CompositionText composition_text; | |
| 814 ime_->ExtractCompositionText( | |
| 815 chromeos_composition_text, kCursorPos, &composition_text); | |
| 816 EXPECT_EQ(kSampleText, composition_text.text); | |
| 817 // If the cursor position is same as selection bounds, selection start | |
| 818 // position become opposit side of selection from cursor. | |
| 819 EXPECT_EQ(GetOffsetInUTF16(kSampleText, | |
| 820 chromeos_composition_text.selection_start()), | |
| 821 composition_text.selection.start()); | |
| 822 EXPECT_EQ(GetOffsetInUTF16(kSampleText, kCursorPos), | |
| 823 composition_text.selection.end()); | |
| 824 ASSERT_EQ(1UL, composition_text.underlines.size()); | |
| 825 EXPECT_EQ(GetOffsetInUTF16(kSampleText, | |
| 826 chromeos_composition_text.selection_start()), | |
| 827 composition_text.underlines[0].start_offset); | |
| 828 EXPECT_EQ(GetOffsetInUTF16(kSampleText, | |
| 829 chromeos_composition_text.selection_end()), | |
| 830 composition_text.underlines[0].end_offset); | |
| 831 EXPECT_EQ(SK_ColorBLACK, composition_text.underlines[0].color); | |
| 832 EXPECT_TRUE(composition_text.underlines[0].thick); | |
| 833 EXPECT_EQ(static_cast<SkColor>(SK_ColorTRANSPARENT), | |
| 834 composition_text.underlines[0].background_color); | |
| 835 } | |
| 836 | |
| 837 TEST_F(InputMethodChromeOSTest, SurroundingText_NoSelectionTest) { | |
| 838 ime_->Init(true); | |
| 839 // Click a text input form. | |
| 840 input_type_ = TEXT_INPUT_TYPE_TEXT; | |
| 841 ime_->OnTextInputTypeChanged(this); | |
| 842 | |
| 843 // Set the TextInputClient behaviors. | |
| 844 surrounding_text_ = UTF8ToUTF16("abcdef"); | |
| 845 text_range_ = gfx::Range(0, 6); | |
| 846 selection_range_ = gfx::Range(3, 3); | |
| 847 | |
| 848 // Set the verifier for SetSurroundingText mock call. | |
| 849 SetSurroundingTextVerifier verifier(UTF16ToUTF8(surrounding_text_), 3, 3); | |
| 850 | |
| 851 | |
| 852 ime_->OnCaretBoundsChanged(this); | |
| 853 | |
| 854 // Check the call count. | |
| 855 EXPECT_EQ(1, | |
| 856 mock_ime_engine_handler_->set_surrounding_text_call_count()); | |
| 857 EXPECT_EQ(UTF16ToUTF8(surrounding_text_), | |
| 858 mock_ime_engine_handler_->last_set_surrounding_text()); | |
| 859 EXPECT_EQ(3U, | |
| 860 mock_ime_engine_handler_->last_set_surrounding_cursor_pos()); | |
| 861 EXPECT_EQ(3U, | |
| 862 mock_ime_engine_handler_->last_set_surrounding_anchor_pos()); | |
| 863 } | |
| 864 | |
| 865 TEST_F(InputMethodChromeOSTest, SurroundingText_SelectionTest) { | |
| 866 ime_->Init(true); | |
| 867 // Click a text input form. | |
| 868 input_type_ = TEXT_INPUT_TYPE_TEXT; | |
| 869 ime_->OnTextInputTypeChanged(this); | |
| 870 | |
| 871 // Set the TextInputClient behaviors. | |
| 872 surrounding_text_ = UTF8ToUTF16("abcdef"); | |
| 873 text_range_ = gfx::Range(0, 6); | |
| 874 selection_range_ = gfx::Range(2, 5); | |
| 875 | |
| 876 // Set the verifier for SetSurroundingText mock call. | |
| 877 SetSurroundingTextVerifier verifier(UTF16ToUTF8(surrounding_text_), 2, 5); | |
| 878 | |
| 879 ime_->OnCaretBoundsChanged(this); | |
| 880 | |
| 881 // Check the call count. | |
| 882 EXPECT_EQ(1, | |
| 883 mock_ime_engine_handler_->set_surrounding_text_call_count()); | |
| 884 EXPECT_EQ(UTF16ToUTF8(surrounding_text_), | |
| 885 mock_ime_engine_handler_->last_set_surrounding_text()); | |
| 886 EXPECT_EQ(2U, | |
| 887 mock_ime_engine_handler_->last_set_surrounding_cursor_pos()); | |
| 888 EXPECT_EQ(5U, | |
| 889 mock_ime_engine_handler_->last_set_surrounding_anchor_pos()); | |
| 890 } | |
| 891 | |
| 892 TEST_F(InputMethodChromeOSTest, SurroundingText_PartialText) { | |
| 893 ime_->Init(true); | |
| 894 // Click a text input form. | |
| 895 input_type_ = TEXT_INPUT_TYPE_TEXT; | |
| 896 ime_->OnTextInputTypeChanged(this); | |
| 897 | |
| 898 // Set the TextInputClient behaviors. | |
| 899 surrounding_text_ = UTF8ToUTF16("abcdefghij"); | |
| 900 text_range_ = gfx::Range(5, 10); | |
| 901 selection_range_ = gfx::Range(7, 9); | |
| 902 | |
| 903 ime_->OnCaretBoundsChanged(this); | |
| 904 | |
| 905 // Check the call count. | |
| 906 EXPECT_EQ(1, | |
| 907 mock_ime_engine_handler_->set_surrounding_text_call_count()); | |
| 908 // Set the verifier for SetSurroundingText mock call. | |
| 909 // Here (2, 4) is selection range in expected surrounding text coordinates. | |
| 910 EXPECT_EQ("fghij", | |
| 911 mock_ime_engine_handler_->last_set_surrounding_text()); | |
| 912 EXPECT_EQ(2U, | |
| 913 mock_ime_engine_handler_->last_set_surrounding_cursor_pos()); | |
| 914 EXPECT_EQ(4U, | |
| 915 mock_ime_engine_handler_->last_set_surrounding_anchor_pos()); | |
| 916 } | |
| 917 | |
| 918 TEST_F(InputMethodChromeOSTest, SurroundingText_BecomeEmptyText) { | |
| 919 ime_->Init(true); | |
| 920 // Click a text input form. | |
| 921 input_type_ = TEXT_INPUT_TYPE_TEXT; | |
| 922 ime_->OnTextInputTypeChanged(this); | |
| 923 | |
| 924 // Set the TextInputClient behaviors. | |
| 925 // If the surrounding text becomes empty, text_range become (0, 0) and | |
| 926 // selection range become invalid. | |
| 927 surrounding_text_ = UTF8ToUTF16(""); | |
| 928 text_range_ = gfx::Range(0, 0); | |
| 929 selection_range_ = gfx::Range::InvalidRange(); | |
| 930 | |
| 931 ime_->OnCaretBoundsChanged(this); | |
| 932 | |
| 933 // Check the call count. | |
| 934 EXPECT_EQ(0, | |
| 935 mock_ime_engine_handler_->set_surrounding_text_call_count()); | |
| 936 | |
| 937 // Should not be called twice with same condition. | |
| 938 ime_->OnCaretBoundsChanged(this); | |
| 939 EXPECT_EQ(0, | |
| 940 mock_ime_engine_handler_->set_surrounding_text_call_count()); | |
| 941 } | |
| 942 | |
| 943 class InputMethodChromeOSKeyEventTest : public InputMethodChromeOSTest { | |
| 944 public: | |
| 945 InputMethodChromeOSKeyEventTest() {} | |
| 946 virtual ~InputMethodChromeOSKeyEventTest() {} | |
| 947 | |
| 948 virtual void SetUp() override { | |
| 949 InputMethodChromeOSTest::SetUp(); | |
| 950 ime_->Init(true); | |
| 951 } | |
| 952 | |
| 953 DISALLOW_COPY_AND_ASSIGN(InputMethodChromeOSKeyEventTest); | |
| 954 }; | |
| 955 | |
| 956 TEST_F(InputMethodChromeOSKeyEventTest, KeyEventDelayResponseTest) { | |
| 957 const int kFlags = ui::EF_SHIFT_DOWN; | |
| 958 ScopedXI2Event xevent; | |
| 959 xevent.InitKeyEvent(ui::ET_KEY_PRESSED, ui::VKEY_A, kFlags); | |
| 960 const ui::KeyEvent event(xevent); | |
| 961 | |
| 962 // Do key event. | |
| 963 input_type_ = TEXT_INPUT_TYPE_TEXT; | |
| 964 ime_->OnTextInputTypeChanged(this); | |
| 965 ime_->DispatchKeyEvent(event); | |
| 966 | |
| 967 // Check before state. | |
| 968 const ui::KeyEvent* key_event = | |
| 969 mock_ime_engine_handler_->last_processed_key_event(); | |
| 970 EXPECT_EQ(1, mock_ime_engine_handler_->process_key_event_call_count()); | |
| 971 EXPECT_EQ(ui::VKEY_A, key_event->key_code()); | |
| 972 EXPECT_EQ("KeyA", key_event->code()); | |
| 973 EXPECT_EQ(kFlags, key_event->flags()); | |
| 974 EXPECT_EQ(0, ime_->process_key_event_post_ime_call_count()); | |
| 975 | |
| 976 // Do callback. | |
| 977 mock_ime_engine_handler_->last_passed_callback().Run(true); | |
| 978 | |
| 979 // Check the results | |
| 980 EXPECT_EQ(1, ime_->process_key_event_post_ime_call_count()); | |
| 981 const ui::KeyEvent* stored_event = | |
| 982 ime_->process_key_event_post_ime_args().event; | |
| 983 EXPECT_TRUE(stored_event->HasNativeEvent()); | |
| 984 EXPECT_TRUE(IsEqualXKeyEvent(*xevent, *(stored_event->native_event()))); | |
| 985 EXPECT_TRUE(ime_->process_key_event_post_ime_args().handled); | |
| 986 } | |
| 987 | |
| 988 TEST_F(InputMethodChromeOSKeyEventTest, MultiKeyEventDelayResponseTest) { | |
| 989 // Preparation | |
| 990 input_type_ = TEXT_INPUT_TYPE_TEXT; | |
| 991 ime_->OnTextInputTypeChanged(this); | |
| 992 | |
| 993 const int kFlags = ui::EF_SHIFT_DOWN; | |
| 994 ScopedXI2Event xevent; | |
| 995 xevent.InitKeyEvent(ui::ET_KEY_PRESSED, ui::VKEY_B, kFlags); | |
| 996 const ui::KeyEvent event(xevent); | |
| 997 | |
| 998 // Do key event. | |
| 999 ime_->DispatchKeyEvent(event); | |
| 1000 const ui::KeyEvent* key_event = | |
| 1001 mock_ime_engine_handler_->last_processed_key_event(); | |
| 1002 EXPECT_EQ(ui::VKEY_B, key_event->key_code()); | |
| 1003 EXPECT_EQ("KeyB", key_event->code()); | |
| 1004 EXPECT_EQ(kFlags, key_event->flags()); | |
| 1005 | |
| 1006 KeyEventCallback first_callback = | |
| 1007 mock_ime_engine_handler_->last_passed_callback(); | |
| 1008 | |
| 1009 // Do key event again. | |
| 1010 ScopedXI2Event xevent2; | |
| 1011 xevent2.InitKeyEvent(ui::ET_KEY_PRESSED, ui::VKEY_C, kFlags); | |
| 1012 const ui::KeyEvent event2(xevent2); | |
| 1013 | |
| 1014 ime_->DispatchKeyEvent(event2); | |
| 1015 const ui::KeyEvent* key_event2 = | |
| 1016 mock_ime_engine_handler_->last_processed_key_event(); | |
| 1017 EXPECT_EQ(ui::VKEY_C, key_event2->key_code()); | |
| 1018 EXPECT_EQ("KeyC", key_event2->code()); | |
| 1019 EXPECT_EQ(kFlags, key_event2->flags()); | |
| 1020 | |
| 1021 // Check before state. | |
| 1022 EXPECT_EQ(2, | |
| 1023 mock_ime_engine_handler_->process_key_event_call_count()); | |
| 1024 EXPECT_EQ(0, ime_->process_key_event_post_ime_call_count()); | |
| 1025 | |
| 1026 // Do callback for first key event. | |
| 1027 first_callback.Run(true); | |
| 1028 | |
| 1029 // Check the results for first key event. | |
| 1030 EXPECT_EQ(1, ime_->process_key_event_post_ime_call_count()); | |
| 1031 const ui::KeyEvent* stored_event = | |
| 1032 ime_->process_key_event_post_ime_args().event; | |
| 1033 EXPECT_TRUE(stored_event->HasNativeEvent()); | |
| 1034 EXPECT_TRUE(IsEqualXKeyEvent(*xevent, *(stored_event->native_event()))); | |
| 1035 EXPECT_TRUE(ime_->process_key_event_post_ime_args().handled); | |
| 1036 | |
| 1037 // Do callback for second key event. | |
| 1038 mock_ime_engine_handler_->last_passed_callback().Run(false); | |
| 1039 | |
| 1040 // Check the results for second key event. | |
| 1041 EXPECT_EQ(2, ime_->process_key_event_post_ime_call_count()); | |
| 1042 stored_event = ime_->process_key_event_post_ime_args().event; | |
| 1043 EXPECT_TRUE(stored_event->HasNativeEvent()); | |
| 1044 EXPECT_TRUE(IsEqualXKeyEvent(*xevent2, *(stored_event->native_event()))); | |
| 1045 EXPECT_FALSE(ime_->process_key_event_post_ime_args().handled); | |
| 1046 } | |
| 1047 | |
| 1048 TEST_F(InputMethodChromeOSKeyEventTest, KeyEventDelayResponseResetTest) { | |
| 1049 ScopedXI2Event xevent; | |
| 1050 xevent.InitKeyEvent(ui::ET_KEY_PRESSED, ui::VKEY_A, ui::EF_SHIFT_DOWN); | |
| 1051 const ui::KeyEvent event(xevent); | |
| 1052 | |
| 1053 // Do key event. | |
| 1054 input_type_ = TEXT_INPUT_TYPE_TEXT; | |
| 1055 ime_->OnTextInputTypeChanged(this); | |
| 1056 ime_->DispatchKeyEvent(event); | |
| 1057 | |
| 1058 // Check before state. | |
| 1059 EXPECT_EQ(1, mock_ime_engine_handler_->process_key_event_call_count()); | |
| 1060 EXPECT_EQ(0, ime_->process_key_event_post_ime_call_count()); | |
| 1061 | |
| 1062 ime_->ResetContext(); | |
| 1063 | |
| 1064 // Do callback. | |
| 1065 mock_ime_engine_handler_->last_passed_callback().Run(true); | |
| 1066 | |
| 1067 EXPECT_EQ(0, ime_->process_key_event_post_ime_call_count()); | |
| 1068 } | |
| 1069 // TODO(nona): Introduce ProcessKeyEventPostIME tests(crbug.com/156593). | |
| 1070 | |
| 1071 } // namespace ui | |
| OLD | NEW |