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