Home | History | Annotate | Download | only in ime
      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
   1072