764426b8df9467b1444c28e00864d0914cb04dd1
[platform/framework/web/crosswalk.git] / src / chrome / browser / chromeos / input_method / input_method_engine_browsertests.cc
1 // Copyright 2013 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 "ash/ime/input_method_menu_item.h"
6 #include "ash/ime/input_method_menu_manager.h"
7 #include "base/bind_helpers.h"
8 #include "base/strings/stringprintf.h"
9 #include "base/strings/utf_string_conversions.h"
10 #include "chrome/browser/extensions/extension_browsertest.h"
11 #include "chrome/browser/extensions/extension_test_message_listener.h"
12 #include "chromeos/ime/component_extension_ime_manager.h"
13 #include "chromeos/ime/composition_text.h"
14 #include "chromeos/ime/input_method_descriptor.h"
15 #include "chromeos/ime/input_method_manager.h"
16 #include "content/public/test/browser_test_utils.h"
17 #include "content/public/test/test_utils.h"
18 #include "extensions/browser/process_manager.h"
19 #include "extensions/common/manifest_handlers/background_info.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_input_context_handler.h"
23 #include "ui/events/event.h"
24
25 namespace chromeos {
26 namespace input_method {
27 namespace {
28
29 const char kIdentityIMEID[] =
30     "_ext_ime_iafoklpfplgfnoimmaejoeondnjnlcfpIdentityIME";
31 const char kToUpperIMEID[] =
32     "_ext_ime_iafoklpfplgfnoimmaejoeondnjnlcfpToUpperIME";
33 const char kAPIArgumentIMEID[] =
34     "_ext_ime_iafoklpfplgfnoimmaejoeondnjnlcfpAPIArgumentIME";
35 const char kExtensionID[] = "iafoklpfplgfnoimmaejoeondnjnlcfp";
36
37 // InputMethod extension should work on 1)normal extension, 2)normal extension
38 // in incognito mode 3)component extension.
39 enum TestType {
40   kTestTypeNormal = 0,
41   kTestTypeIncognito = 1,
42   kTestTypeComponent = 2,
43 };
44
45 class InputMethodEngineBrowserTest
46     : public ExtensionBrowserTest,
47       public ::testing::WithParamInterface<TestType> {
48  public:
49   InputMethodEngineBrowserTest()
50       : ExtensionBrowserTest() {}
51   virtual ~InputMethodEngineBrowserTest() {}
52
53   virtual void SetUpInProcessBrowserTestFixture() OVERRIDE {
54     ExtensionBrowserTest::SetUpInProcessBrowserTestFixture();
55   }
56
57   virtual void TearDownInProcessBrowserTestFixture() OVERRIDE {
58     extension_ = NULL;
59   }
60
61  protected:
62   void LoadTestInputMethod() {
63     // This will load "chrome/test/data/extensions/input_ime"
64     ExtensionTestMessageListener ime_ready_listener("ReadyToUseImeEvent",
65                                                     false);
66     extension_ = LoadExtensionWithType("input_ime", GetParam());
67     ASSERT_TRUE(extension_);
68     ASSERT_TRUE(ime_ready_listener.WaitUntilSatisfied());
69
70     // Extension IMEs are not enabled by default.
71     std::vector<std::string> extension_ime_ids;
72     extension_ime_ids.push_back(kIdentityIMEID);
73     extension_ime_ids.push_back(kToUpperIMEID);
74     extension_ime_ids.push_back(kAPIArgumentIMEID);
75     InputMethodManager::Get()->SetEnabledExtensionImes(&extension_ime_ids);
76
77     InputMethodDescriptors extension_imes;
78     InputMethodManager::Get()->GetInputMethodExtensions(&extension_imes);
79
80     // Test IME has two input methods, thus InputMethodManager should have two
81     // extension IME.
82     // Note: Even extension is loaded by LoadExtensionAsComponent as above, the
83     // IME does not managed by ComponentExtensionIMEManager or it's id won't
84     // start with __comp__. The component extension IME is whitelisted and
85     // managed by ComponentExtensionIMEManager, but its framework is same as
86     // normal extension IME.
87     EXPECT_EQ(3U, extension_imes.size());
88   }
89
90   const extensions::Extension* LoadExtensionWithType(
91       const std::string& extension_name, TestType type) {
92     switch (type) {
93       case kTestTypeNormal:
94         return LoadExtension(test_data_dir_.AppendASCII(extension_name));
95       case kTestTypeIncognito:
96         return LoadExtensionIncognito(
97             test_data_dir_.AppendASCII(extension_name));
98       case kTestTypeComponent:
99         return LoadExtensionAsComponent(
100             test_data_dir_.AppendASCII(extension_name));
101     }
102     NOTREACHED();
103     return NULL;
104   }
105
106   const extensions::Extension* extension_;
107 };
108
109 class KeyEventDoneCallback {
110  public:
111   explicit KeyEventDoneCallback(bool expected_argument)
112       : expected_argument_(expected_argument),
113         is_called_(false) {}
114   ~KeyEventDoneCallback() {}
115
116   void Run(bool consumed) {
117     if (consumed == expected_argument_) {
118       base::MessageLoop::current()->Quit();
119       is_called_ = true;
120     }
121   }
122
123   void WaitUntilCalled() {
124     while (!is_called_)
125       content::RunMessageLoop();
126   }
127
128  private:
129   bool expected_argument_;
130   bool is_called_;
131
132   DISALLOW_COPY_AND_ASSIGN(KeyEventDoneCallback);
133 };
134
135 INSTANTIATE_TEST_CASE_P(InputMethodEngineBrowserTest,
136                         InputMethodEngineBrowserTest,
137                         ::testing::Values(kTestTypeNormal));
138 INSTANTIATE_TEST_CASE_P(InputMethodEngineIncognitoBrowserTest,
139                         InputMethodEngineBrowserTest,
140                         ::testing::Values(kTestTypeIncognito));
141 INSTANTIATE_TEST_CASE_P(InputMethodEngineComponentExtensionBrowserTest,
142                         InputMethodEngineBrowserTest,
143                         ::testing::Values(kTestTypeComponent));
144
145 IN_PROC_BROWSER_TEST_P(InputMethodEngineBrowserTest,
146                        BasicScenarioTest) {
147   LoadTestInputMethod();
148
149   InputMethodManager::Get()->ChangeInputMethod(kIdentityIMEID);
150
151   scoped_ptr<MockIMEInputContextHandler> mock_input_context(
152       new MockIMEInputContextHandler());
153   scoped_ptr<MockIMECandidateWindowHandler> mock_candidate_window(
154       new MockIMECandidateWindowHandler());
155
156   IMEBridge::Get()->SetInputContextHandler(mock_input_context.get());
157   IMEBridge::Get()->SetCandidateWindowHandler(mock_candidate_window.get());
158
159   IMEEngineHandlerInterface* engine_handler =
160       IMEBridge::Get()->GetCurrentEngineHandler();
161   ASSERT_TRUE(engine_handler);
162
163   // onActivate event should be fired if Enable function is called.
164   ExtensionTestMessageListener activated_listener("onActivate", false);
165   engine_handler->Enable("IdentityIME");
166   ASSERT_TRUE(activated_listener.WaitUntilSatisfied());
167   ASSERT_TRUE(activated_listener.was_satisfied());
168
169   // onFocus event should be fired if FocusIn function is called.
170   ExtensionTestMessageListener focus_listener("onFocus:text", false);
171   IMEEngineHandlerInterface::InputContext context(ui::TEXT_INPUT_TYPE_TEXT,
172                                                   ui::TEXT_INPUT_MODE_DEFAULT);
173   engine_handler->FocusIn(context);
174   ASSERT_TRUE(focus_listener.WaitUntilSatisfied());
175   ASSERT_TRUE(focus_listener.was_satisfied());
176
177   // onKeyEvent should be fired if ProcessKeyEvent is called.
178   KeyEventDoneCallback callback(false);  // EchoBackIME doesn't consume keys.
179   ExtensionTestMessageListener keyevent_listener("onKeyEvent", false);
180   ui::KeyEvent key_event(ui::ET_KEY_PRESSED, ui::VKEY_A, ui::EF_NONE);
181   engine_handler->ProcessKeyEvent(key_event,
182                                   base::Bind(&KeyEventDoneCallback::Run,
183                                              base::Unretained(&callback)));
184   ASSERT_TRUE(keyevent_listener.WaitUntilSatisfied());
185   ASSERT_TRUE(keyevent_listener.was_satisfied());
186   callback.WaitUntilCalled();
187
188   // onSurroundingTextChange should be fired if SetSurroundingText is called.
189   ExtensionTestMessageListener surrounding_text_listener(
190       "onSurroundingTextChanged", false);
191   engine_handler->SetSurroundingText("text",  // Surrounding text.
192                                      0,  // focused position.
193                                      1);  // anchor position.
194   ASSERT_TRUE(surrounding_text_listener.WaitUntilSatisfied());
195   ASSERT_TRUE(surrounding_text_listener.was_satisfied());
196
197   // onMenuItemActivated should be fired if PropertyActivate is called.
198   ExtensionTestMessageListener property_listener("onMenuItemActivated", false);
199   engine_handler->PropertyActivate("property_name");
200   ASSERT_TRUE(property_listener.WaitUntilSatisfied());
201   ASSERT_TRUE(property_listener.was_satisfied());
202
203   // onReset should be fired if Reset is called.
204   ExtensionTestMessageListener reset_listener("onReset", false);
205   engine_handler->Reset();
206   ASSERT_TRUE(reset_listener.WaitUntilSatisfied());
207   ASSERT_TRUE(reset_listener.was_satisfied());
208
209   // onBlur should be fired if FocusOut is called.
210   ExtensionTestMessageListener blur_listener("onBlur", false);
211   engine_handler->FocusOut();
212   ASSERT_TRUE(blur_listener.WaitUntilSatisfied());
213   ASSERT_TRUE(blur_listener.was_satisfied());
214
215   // onDeactivated should be fired if Disable is called.
216   ExtensionTestMessageListener disabled_listener("onDeactivated", false);
217   engine_handler->Disable();
218   ASSERT_TRUE(disabled_listener.WaitUntilSatisfied());
219   ASSERT_TRUE(disabled_listener.was_satisfied());
220
221   IMEBridge::Get()->SetInputContextHandler(NULL);
222   IMEBridge::Get()->SetCandidateWindowHandler(NULL);
223 }
224
225 IN_PROC_BROWSER_TEST_P(InputMethodEngineBrowserTest,
226                        APIArgumentTest) {
227   LoadTestInputMethod();
228
229   InputMethodManager::Get()->ChangeInputMethod(kAPIArgumentIMEID);
230
231   scoped_ptr<MockIMEInputContextHandler> mock_input_context(
232       new MockIMEInputContextHandler());
233   scoped_ptr<MockIMECandidateWindowHandler> mock_candidate_window(
234       new MockIMECandidateWindowHandler());
235
236   IMEBridge::Get()->SetInputContextHandler(mock_input_context.get());
237   IMEBridge::Get()->SetCandidateWindowHandler(mock_candidate_window.get());
238
239   IMEEngineHandlerInterface* engine_handler =
240       IMEBridge::Get()->GetCurrentEngineHandler();
241   ASSERT_TRUE(engine_handler);
242
243   extensions::ExtensionHost* host =
244       extensions::ExtensionSystem::Get(profile())
245           ->process_manager()
246           ->GetBackgroundHostForExtension(extension_->id());
247   ASSERT_TRUE(host);
248
249   engine_handler->Enable("APIArgumentIME");
250   IMEEngineHandlerInterface::InputContext context(ui::TEXT_INPUT_TYPE_TEXT,
251                                                   ui::TEXT_INPUT_MODE_DEFAULT);
252   engine_handler->FocusIn(context);
253
254   {
255     SCOPED_TRACE("KeyDown, Ctrl:No, alt:No, Shift:No, Caps:No");
256     KeyEventDoneCallback callback(false);
257     const std::string expected_value =
258         "onKeyEvent::keydown:a:KeyA:false:false:false:false";
259     ExtensionTestMessageListener keyevent_listener(expected_value, false);
260
261     ui::KeyEvent key_event(
262         ui::ET_KEY_PRESSED, ui::VKEY_A, "KeyA", ui::EF_NONE);
263     engine_handler->ProcessKeyEvent(key_event,
264                                     base::Bind(&KeyEventDoneCallback::Run,
265                                                base::Unretained(&callback)));
266     ASSERT_TRUE(keyevent_listener.WaitUntilSatisfied());
267     EXPECT_TRUE(keyevent_listener.was_satisfied());
268     callback.WaitUntilCalled();
269   }
270   {
271     SCOPED_TRACE("KeyDown, Ctrl:Yes, alt:No, Shift:No, Caps:No");
272     KeyEventDoneCallback callback(false);
273     const std::string expected_value =
274         "onKeyEvent::keydown:a:KeyA:true:false:false:false";
275     ExtensionTestMessageListener keyevent_listener(expected_value, false);
276
277     ui::KeyEvent key_event(ui::ET_KEY_PRESSED,
278                            ui::VKEY_A,
279                            "KeyA",
280                            ui::EF_CONTROL_DOWN);
281     engine_handler->ProcessKeyEvent(key_event,
282                                     base::Bind(&KeyEventDoneCallback::Run,
283                                                base::Unretained(&callback)));
284     ASSERT_TRUE(keyevent_listener.WaitUntilSatisfied());
285     EXPECT_TRUE(keyevent_listener.was_satisfied());
286     callback.WaitUntilCalled();
287   }
288   {
289     SCOPED_TRACE("KeyDown, Ctrl:No, alt:Yes, Shift:No, Caps:No");
290     KeyEventDoneCallback callback(false);
291     const std::string expected_value =
292         "onKeyEvent::keydown:a:KeyA:false:true:false:false";
293     ExtensionTestMessageListener keyevent_listener(expected_value, false);
294
295     ui::KeyEvent key_event(ui::ET_KEY_PRESSED,
296                            ui::VKEY_A,
297                            "KeyA",
298                            ui::EF_ALT_DOWN);
299     engine_handler->ProcessKeyEvent(key_event,
300                                     base::Bind(&KeyEventDoneCallback::Run,
301                                                base::Unretained(&callback)));
302     ASSERT_TRUE(keyevent_listener.WaitUntilSatisfied());
303     EXPECT_TRUE(keyevent_listener.was_satisfied());
304     callback.WaitUntilCalled();
305   }
306   {
307     SCOPED_TRACE("KeyDown, Ctrl:No, alt:No, Shift:Yes, Caps:No");
308     KeyEventDoneCallback callback(false);
309     const std::string expected_value =
310         "onKeyEvent::keydown:A:KeyA:false:false:true:false";
311     ExtensionTestMessageListener keyevent_listener(expected_value, false);
312
313     ui::KeyEvent key_event(ui::ET_KEY_PRESSED,
314                            ui::VKEY_A,
315                            "KeyA",
316                            ui::EF_SHIFT_DOWN);
317     engine_handler->ProcessKeyEvent(key_event,
318                                     base::Bind(&KeyEventDoneCallback::Run,
319                                                base::Unretained(&callback)));
320     ASSERT_TRUE(keyevent_listener.WaitUntilSatisfied());
321     EXPECT_TRUE(keyevent_listener.was_satisfied());
322     callback.WaitUntilCalled();
323   }
324   {
325     SCOPED_TRACE("KeyDown, Ctrl:No, alt:No, Shift:No, Caps:Yes");
326     KeyEventDoneCallback callback(false);
327     const std::string expected_value =
328         "onKeyEvent::keydown:A:KeyA:false:false:false:true";
329     ExtensionTestMessageListener keyevent_listener(expected_value, false);
330
331     ui::KeyEvent key_event(ui::ET_KEY_PRESSED,
332                            ui::VKEY_A,
333                            "KeyA",
334                            ui::EF_CAPS_LOCK_DOWN);
335     engine_handler->ProcessKeyEvent(key_event,
336                                     base::Bind(&KeyEventDoneCallback::Run,
337                                                base::Unretained(&callback)));
338     ASSERT_TRUE(keyevent_listener.WaitUntilSatisfied());
339     EXPECT_TRUE(keyevent_listener.was_satisfied());
340     callback.WaitUntilCalled();
341   }
342   {
343     SCOPED_TRACE("KeyDown, Ctrl:Yes, alt:Yes, Shift:No, Caps:No");
344     KeyEventDoneCallback callback(false);
345     const std::string expected_value =
346         "onKeyEvent::keydown:a:KeyA:true:true:false:false";
347     ExtensionTestMessageListener keyevent_listener(expected_value, false);
348
349     ui::KeyEvent key_event(ui::ET_KEY_PRESSED,
350                            ui::VKEY_A,
351                            "KeyA",
352                            ui::EF_ALT_DOWN | ui::EF_CONTROL_DOWN);
353     engine_handler->ProcessKeyEvent(key_event,
354                                     base::Bind(&KeyEventDoneCallback::Run,
355                                                base::Unretained(&callback)));
356     ASSERT_TRUE(keyevent_listener.WaitUntilSatisfied());
357     EXPECT_TRUE(keyevent_listener.was_satisfied());
358     callback.WaitUntilCalled();
359   }
360   {
361     SCOPED_TRACE("KeyDown, Ctrl:No, alt:No, Shift:Yes, Caps:Yes");
362     KeyEventDoneCallback callback(false);
363     const std::string expected_value =
364         "onKeyEvent::keydown:a:KeyA:false:false:true:true";
365     ExtensionTestMessageListener keyevent_listener(expected_value, false);
366
367     ui::KeyEvent key_event(ui::ET_KEY_PRESSED,
368                            ui::VKEY_A,
369                            "KeyA",
370                            ui::EF_SHIFT_DOWN | ui::EF_CAPS_LOCK_DOWN);
371     engine_handler->ProcessKeyEvent(key_event,
372                                     base::Bind(&KeyEventDoneCallback::Run,
373                                                base::Unretained(&callback)));
374     ASSERT_TRUE(keyevent_listener.WaitUntilSatisfied());
375     EXPECT_TRUE(keyevent_listener.was_satisfied());
376     callback.WaitUntilCalled();
377   }
378   // Media keys cases.
379   const struct {
380     ui::KeyboardCode keycode;
381     const char* code;
382     const char* key;
383   } kMediaKeyCases[] = {
384     { ui::VKEY_BROWSER_BACK, "BrowserBack", "HistoryBack" },
385     { ui::VKEY_BROWSER_FORWARD, "BrowserForward", "HistoryForward" },
386     { ui::VKEY_BROWSER_REFRESH, "BrowserRefresh", "BrowserRefresh" },
387     { ui::VKEY_MEDIA_LAUNCH_APP2, "ChromeOSFullscreen", "ChromeOSFullscreen" },
388     { ui::VKEY_MEDIA_LAUNCH_APP1,
389       "ChromeOSSwitchWindow", "ChromeOSSwitchWindow" },
390     { ui::VKEY_BRIGHTNESS_DOWN, "BrightnessDown", "BrightnessDown" },
391     { ui::VKEY_BRIGHTNESS_UP, "BrightnessUp", "BrightnessUp" },
392     { ui::VKEY_VOLUME_MUTE, "VolumeMute", "AudioVolumeMute" },
393     { ui::VKEY_VOLUME_DOWN, "VolumeDown", "AudioVolumeDown" },
394     { ui::VKEY_VOLUME_UP, "VolumeUp", "AudioVolumeUp" },
395     { ui::VKEY_F1, "F1", "HistoryBack" },
396     { ui::VKEY_F2, "F2", "HistoryForward" },
397     { ui::VKEY_F3, "F3", "BrowserRefresh" },
398     { ui::VKEY_F4, "F4", "ChromeOSFullscreen" },
399     { ui::VKEY_F5, "F5", "ChromeOSSwitchWindow" },
400     { ui::VKEY_F6, "F6", "BrightnessDown" },
401     { ui::VKEY_F7, "F7", "BrightnessUp" },
402     { ui::VKEY_F8, "F8", "AudioVolumeMute" },
403     { ui::VKEY_F9, "F9", "AudioVolumeDown" },
404     { ui::VKEY_F10, "F10", "AudioVolumeUp" },
405   };
406   for (size_t i = 0; i < arraysize(kMediaKeyCases); ++i) {
407     SCOPED_TRACE(std::string("KeyDown, ") + kMediaKeyCases[i].code);
408     KeyEventDoneCallback callback(false);
409     const std::string expected_value =
410         base::StringPrintf("onKeyEvent::keydown:%s:%s:false:false:false:false",
411                            kMediaKeyCases[i].key, kMediaKeyCases[i].code);
412     ExtensionTestMessageListener keyevent_listener(expected_value, false);
413
414     ui::KeyEvent key_event(ui::ET_KEY_PRESSED,
415                            kMediaKeyCases[i].keycode,
416                            kMediaKeyCases[i].code,
417                            ui::EF_NONE);
418     engine_handler->ProcessKeyEvent(key_event,
419                                     base::Bind(&KeyEventDoneCallback::Run,
420                                                base::Unretained(&callback)));
421     ASSERT_TRUE(keyevent_listener.WaitUntilSatisfied());
422     EXPECT_TRUE(keyevent_listener.was_satisfied());
423     callback.WaitUntilCalled();
424   }
425   // TODO(nona): Add browser tests for other API as well.
426   {
427     SCOPED_TRACE("commitText test");
428     mock_input_context->Reset();
429     mock_candidate_window->Reset();
430
431     const char commit_text_test_script[] =
432         "chrome.input.ime.commitText({"
433         "  contextID: engineBridge.getFocusedContextID().contextID,"
434         "  text:'COMMIT_TEXT'"
435         "});";
436
437     ASSERT_TRUE(content::ExecuteScript(host->host_contents(),
438                                        commit_text_test_script));
439     EXPECT_EQ(1, mock_input_context->commit_text_call_count());
440     EXPECT_EQ("COMMIT_TEXT", mock_input_context->last_commit_text());
441   }
442   {
443     SCOPED_TRACE("sendKeyEvents test");
444     mock_input_context->Reset();
445     mock_candidate_window->Reset();
446
447     const char send_key_events_test_script[] =
448         "chrome.input.ime.sendKeyEvents({"
449         "  contextID: engineBridge.getFocusedContextID().contextID,"
450         "  keyData : [{"
451         "    type : 'keydown',"
452         "    requestId : '0',"
453         "    key : 'z',"
454         "    code : 'KeyZ',"
455         "  },{"
456         "    type : 'keyup',"
457         "    requestId : '1',"
458         "    key : 'z',"
459         "    code : 'KeyZ',"
460         "  }]"
461         "});";
462
463     ExtensionTestMessageListener keyevent_listener_down(
464         std::string("onKeyEvent:") + kExtensionID +
465         ":keydown:z:KeyZ:false:false:false:false",
466         false);
467     ExtensionTestMessageListener keyevent_listener_up(
468         std::string("onKeyEvent:") + kExtensionID +
469         ":keyup:z:KeyZ:false:false:false:false",
470         false);
471
472     ASSERT_TRUE(content::ExecuteScript(host->host_contents(),
473                                        send_key_events_test_script));
474
475     ASSERT_TRUE(keyevent_listener_down.WaitUntilSatisfied());
476     EXPECT_TRUE(keyevent_listener_down.was_satisfied());
477     ASSERT_TRUE(keyevent_listener_up.WaitUntilSatisfied());
478     EXPECT_TRUE(keyevent_listener_up.was_satisfied());
479   }
480   {
481     SCOPED_TRACE("sendKeyEvents test with keyCode");
482     mock_input_context->Reset();
483     mock_candidate_window->Reset();
484
485     const char send_key_events_test_script[] =
486         "chrome.input.ime.sendKeyEvents({"
487         "  contextID: engineBridge.getFocusedContextID().contextID,"
488         "  keyData : [{"
489         "    type : 'keydown',"
490         "    requestId : '2',"
491         "    key : 'a',"
492         "    code : 'KeyQ',"
493         "    keyCode : 0x41,"
494         "  },{"
495         "    type : 'keyup',"
496         "    requestId : '3',"
497         "    key : 'a',"
498         "    code : 'KeyQ',"
499         "    keyCode : 0x41,"
500         "  }]"
501         "});";
502
503     ExtensionTestMessageListener keyevent_listener_down(
504         std::string("onKeyEvent:") + kExtensionID +
505         ":keydown:a:KeyQ:false:false:false:false",
506         false);
507     ExtensionTestMessageListener keyevent_listener_up(
508         std::string("onKeyEvent:") + kExtensionID +
509         ":keyup:a:KeyQ:false:false:false:false",
510         false);
511
512     ASSERT_TRUE(content::ExecuteScript(host->host_contents(),
513                                        send_key_events_test_script));
514
515     ASSERT_TRUE(keyevent_listener_down.WaitUntilSatisfied());
516     EXPECT_TRUE(keyevent_listener_down.was_satisfied());
517     ASSERT_TRUE(keyevent_listener_up.WaitUntilSatisfied());
518     EXPECT_TRUE(keyevent_listener_up.was_satisfied());
519   }
520   {
521     SCOPED_TRACE("setComposition test");
522     mock_input_context->Reset();
523     mock_candidate_window->Reset();
524
525     const char set_composition_test_script[] =
526         "chrome.input.ime.setComposition({"
527         "  contextID: engineBridge.getFocusedContextID().contextID,"
528         "  text:'COMPOSITION_TEXT',"
529         "  cursor:4,"
530         "  segments : [{"
531         "    start: 0,"
532         "    end: 5,"
533         "    style: 'underline'"
534         "  },{"
535         "    start: 6,"
536         "    end: 10,"
537         "    style: 'doubleUnderline'"
538         "  }]"
539         "});";
540
541     ASSERT_TRUE(content::ExecuteScript(host->host_contents(),
542                                        set_composition_test_script));
543     EXPECT_EQ(1, mock_input_context->update_preedit_text_call_count());
544
545     EXPECT_EQ(4U,
546               mock_input_context->last_update_composition_arg().cursor_pos);
547     EXPECT_TRUE(mock_input_context->last_update_composition_arg().is_visible);
548
549     const CompositionText& composition_text =
550         mock_input_context->last_update_composition_arg().composition_text;
551     EXPECT_EQ(base::UTF8ToUTF16("COMPOSITION_TEXT"), composition_text.text());
552     const std::vector<CompositionText::UnderlineAttribute>& underlines =
553         composition_text.underline_attributes();
554
555     ASSERT_EQ(2U, underlines.size());
556     EXPECT_EQ(CompositionText::COMPOSITION_TEXT_UNDERLINE_SINGLE,
557               underlines[0].type);
558     EXPECT_EQ(0U, underlines[0].start_index);
559     EXPECT_EQ(5U, underlines[0].end_index);
560
561     EXPECT_EQ(CompositionText::COMPOSITION_TEXT_UNDERLINE_DOUBLE,
562               underlines[1].type);
563     EXPECT_EQ(6U, underlines[1].start_index);
564     EXPECT_EQ(10U, underlines[1].end_index);
565   }
566   {
567     SCOPED_TRACE("clearComposition test");
568     mock_input_context->Reset();
569     mock_candidate_window->Reset();
570
571     const char commite_text_test_script[] =
572         "chrome.input.ime.clearComposition({"
573         "  contextID: engineBridge.getFocusedContextID().contextID,"
574         "});";
575
576     ASSERT_TRUE(content::ExecuteScript(host->host_contents(),
577                                        commite_text_test_script));
578     EXPECT_EQ(1, mock_input_context->update_preedit_text_call_count());
579     EXPECT_FALSE(
580         mock_input_context->last_update_composition_arg().is_visible);
581     const CompositionText& composition_text =
582         mock_input_context->last_update_composition_arg().composition_text;
583     EXPECT_TRUE(composition_text.text().empty());
584   }
585   {
586     SCOPED_TRACE("setCandidateWindowProperties:visibility test");
587     mock_input_context->Reset();
588     mock_candidate_window->Reset();
589
590     const char set_candidate_window_properties_test_script[] =
591         "chrome.input.ime.setCandidateWindowProperties({"
592         "  engineID: engineBridge.getActiveEngineID(),"
593         "  properties: {"
594         "    visible: true,"
595         "  }"
596         "});";
597     ASSERT_TRUE(content::ExecuteScript(
598         host->host_contents(),
599         set_candidate_window_properties_test_script));
600     EXPECT_EQ(1, mock_candidate_window->update_lookup_table_call_count());
601     EXPECT_TRUE(
602         mock_candidate_window->last_update_lookup_table_arg().is_visible);
603   }
604   {
605     SCOPED_TRACE("setCandidateWindowProperties:cursor_visibility test");
606     mock_input_context->Reset();
607     mock_candidate_window->Reset();
608
609     const char set_candidate_window_properties_test_script[] =
610         "chrome.input.ime.setCandidateWindowProperties({"
611         "  engineID: engineBridge.getActiveEngineID(),"
612         "  properties: {"
613         "    cursorVisible: true,"
614         "  }"
615         "});";
616     ASSERT_TRUE(content::ExecuteScript(
617         host->host_contents(),
618         set_candidate_window_properties_test_script));
619     EXPECT_EQ(1, mock_candidate_window->update_lookup_table_call_count());
620
621     // window visibility is kept as before.
622     EXPECT_TRUE(
623         mock_candidate_window->last_update_lookup_table_arg().is_visible);
624
625     const ui::CandidateWindow& table =
626         mock_candidate_window->last_update_lookup_table_arg().lookup_table;
627     EXPECT_TRUE(table.is_cursor_visible());
628   }
629   {
630     SCOPED_TRACE("setCandidateWindowProperties:vertical test");
631     mock_input_context->Reset();
632     mock_candidate_window->Reset();
633
634     const char set_candidate_window_properties_test_script[] =
635         "chrome.input.ime.setCandidateWindowProperties({"
636         "  engineID: engineBridge.getActiveEngineID(),"
637         "  properties: {"
638         "    vertical: true,"
639         "  }"
640         "});";
641     ASSERT_TRUE(content::ExecuteScript(
642         host->host_contents(),
643         set_candidate_window_properties_test_script));
644     EXPECT_EQ(1, mock_candidate_window->update_lookup_table_call_count());
645
646     // window visibility is kept as before.
647     EXPECT_TRUE(
648         mock_candidate_window->last_update_lookup_table_arg().is_visible);
649
650     const ui::CandidateWindow& table =
651         mock_candidate_window->last_update_lookup_table_arg().lookup_table;
652
653     // cursor visibility is kept as before.
654     EXPECT_TRUE(table.is_cursor_visible());
655
656     EXPECT_EQ(ui::CandidateWindow::VERTICAL, table.orientation());
657   }
658   {
659     SCOPED_TRACE("setCandidateWindowProperties:pageSize test");
660     mock_input_context->Reset();
661     mock_candidate_window->Reset();
662
663     const char set_candidate_window_properties_test_script[] =
664         "chrome.input.ime.setCandidateWindowProperties({"
665         "  engineID: engineBridge.getActiveEngineID(),"
666         "  properties: {"
667         "    pageSize: 7,"
668         "  }"
669         "});";
670     ASSERT_TRUE(content::ExecuteScript(
671         host->host_contents(),
672         set_candidate_window_properties_test_script));
673     EXPECT_EQ(1, mock_candidate_window->update_lookup_table_call_count());
674
675     // window visibility is kept as before.
676     EXPECT_TRUE(
677         mock_candidate_window->last_update_lookup_table_arg().is_visible);
678
679     const ui::CandidateWindow& table =
680         mock_candidate_window->last_update_lookup_table_arg().lookup_table;
681
682     // cursor visibility is kept as before.
683     EXPECT_TRUE(table.is_cursor_visible());
684
685     // oritantation is kept as before.
686     EXPECT_EQ(ui::CandidateWindow::VERTICAL, table.orientation());
687
688     EXPECT_EQ(7U, table.page_size());
689   }
690   {
691     SCOPED_TRACE("setCandidateWindowProperties:auxTextVisibility test");
692     mock_input_context->Reset();
693     mock_candidate_window->Reset();
694
695     const char set_candidate_window_properties_test_script[] =
696         "chrome.input.ime.setCandidateWindowProperties({"
697         "  engineID: engineBridge.getActiveEngineID(),"
698         "  properties: {"
699         "    auxiliaryTextVisible: true"
700         "  }"
701         "});";
702     ASSERT_TRUE(content::ExecuteScript(
703         host->host_contents(),
704         set_candidate_window_properties_test_script));
705     EXPECT_EQ(1, mock_candidate_window->update_lookup_table_call_count());
706
707     const ui::CandidateWindow& table =
708         mock_candidate_window->last_update_lookup_table_arg().lookup_table;
709     EXPECT_TRUE(table.is_auxiliary_text_visible());
710   }
711   {
712     SCOPED_TRACE("setCandidateWindowProperties:auxText test");
713     mock_input_context->Reset();
714     mock_candidate_window->Reset();
715
716     const char set_candidate_window_properties_test_script[] =
717         "chrome.input.ime.setCandidateWindowProperties({"
718         "  engineID: engineBridge.getActiveEngineID(),"
719         "  properties: {"
720         "    auxiliaryText: 'AUXILIARY_TEXT'"
721         "  }"
722         "});";
723     ASSERT_TRUE(content::ExecuteScript(
724         host->host_contents(),
725         set_candidate_window_properties_test_script));
726     EXPECT_EQ(1, mock_candidate_window->update_lookup_table_call_count());
727
728     // aux text visibility is kept as before.
729     const ui::CandidateWindow& table =
730         mock_candidate_window->last_update_lookup_table_arg().lookup_table;
731     EXPECT_TRUE(table.is_auxiliary_text_visible());
732     EXPECT_EQ("AUXILIARY_TEXT", table.auxiliary_text());
733   }
734   {
735     SCOPED_TRACE("setCandidates test");
736     mock_input_context->Reset();
737     mock_candidate_window->Reset();
738
739     const char set_candidates_test_script[] =
740         "chrome.input.ime.setCandidates({"
741         "  contextID: engineBridge.getFocusedContextID().contextID,"
742         "  candidates: [{"
743         "    candidate: 'CANDIDATE_1',"
744         "    id: 1,"
745         "    },{"
746         "    candidate: 'CANDIDATE_2',"
747         "    id: 2,"
748         "    label: 'LABEL_2',"
749         "    },{"
750         "    candidate: 'CANDIDATE_3',"
751         "    id: 3,"
752         "    label: 'LABEL_3',"
753         "    annotation: 'ANNOTACTION_3'"
754         "    },{"
755         "    candidate: 'CANDIDATE_4',"
756         "    id: 4,"
757         "    label: 'LABEL_4',"
758         "    annotation: 'ANNOTACTION_4',"
759         "    usage: {"
760         "      title: 'TITLE_4',"
761         "      body: 'BODY_4'"
762         "    }"
763         "  }]"
764         "});";
765     ASSERT_TRUE(content::ExecuteScript(host->host_contents(),
766                                        set_candidates_test_script));
767
768     // window visibility is kept as before.
769     EXPECT_TRUE(
770         mock_candidate_window->last_update_lookup_table_arg().is_visible);
771
772     const ui::CandidateWindow& table =
773         mock_candidate_window->last_update_lookup_table_arg().lookup_table;
774
775     // cursor visibility is kept as before.
776     EXPECT_TRUE(table.is_cursor_visible());
777
778     // oritantation is kept as before.
779     EXPECT_EQ(ui::CandidateWindow::VERTICAL, table.orientation());
780
781     // page size is kept as before.
782     EXPECT_EQ(7U, table.page_size());
783
784     ASSERT_EQ(4U, table.candidates().size());
785
786     EXPECT_EQ(base::UTF8ToUTF16("CANDIDATE_1"),
787               table.candidates().at(0).value);
788
789     EXPECT_EQ(base::UTF8ToUTF16("CANDIDATE_2"),
790               table.candidates().at(1).value);
791     EXPECT_EQ(base::UTF8ToUTF16("LABEL_2"), table.candidates().at(1).label);
792
793     EXPECT_EQ(base::UTF8ToUTF16("CANDIDATE_3"),
794               table.candidates().at(2).value);
795     EXPECT_EQ(base::UTF8ToUTF16("LABEL_3"), table.candidates().at(2).label);
796     EXPECT_EQ(base::UTF8ToUTF16("ANNOTACTION_3"),
797               table.candidates().at(2).annotation);
798
799     EXPECT_EQ(base::UTF8ToUTF16("CANDIDATE_4"),
800               table.candidates().at(3).value);
801     EXPECT_EQ(base::UTF8ToUTF16("LABEL_4"), table.candidates().at(3).label);
802     EXPECT_EQ(base::UTF8ToUTF16("ANNOTACTION_4"),
803               table.candidates().at(3).annotation);
804     EXPECT_EQ(base::UTF8ToUTF16("TITLE_4"),
805               table.candidates().at(3).description_title);
806     EXPECT_EQ(base::UTF8ToUTF16("BODY_4"),
807               table.candidates().at(3).description_body);
808   }
809   {
810     SCOPED_TRACE("setCursorPosition test");
811     mock_input_context->Reset();
812     mock_candidate_window->Reset();
813
814     const char set_cursor_position_test_script[] =
815         "chrome.input.ime.setCursorPosition({"
816         "  contextID: engineBridge.getFocusedContextID().contextID,"
817         "  candidateID: 2"
818         "});";
819     ASSERT_TRUE(content::ExecuteScript(
820         host->host_contents(), set_cursor_position_test_script));
821     EXPECT_EQ(1, mock_candidate_window->update_lookup_table_call_count());
822
823     // window visibility is kept as before.
824     EXPECT_TRUE(
825         mock_candidate_window->last_update_lookup_table_arg().is_visible);
826
827     const ui::CandidateWindow& table =
828         mock_candidate_window->last_update_lookup_table_arg().lookup_table;
829
830     // cursor visibility is kept as before.
831     EXPECT_TRUE(table.is_cursor_visible());
832
833     // oritantation is kept as before.
834     EXPECT_EQ(ui::CandidateWindow::VERTICAL, table.orientation());
835
836     // page size is kept as before.
837     EXPECT_EQ(7U, table.page_size());
838
839     // candidates are same as before.
840     ASSERT_EQ(4U, table.candidates().size());
841
842     // Candidate ID == 2 is 1 in index.
843     EXPECT_EQ(1U, table.cursor_position());
844   }
845   {
846     SCOPED_TRACE("setMenuItem test");
847     mock_input_context->Reset();
848     mock_candidate_window->Reset();
849
850     const char set_menu_item_test_script[] =
851         "chrome.input.ime.setMenuItems({"
852         "  engineID: engineBridge.getActiveEngineID(),"
853         "  items: [{"
854         "    id: 'ID0',"
855         "  },{"
856         "    id: 'ID1',"
857         "    label: 'LABEL1',"
858         "  },{"
859         "    id: 'ID2',"
860         "    label: 'LABEL2',"
861         "    style: 'radio',"
862         "  },{"
863         "    id: 'ID3',"
864         "    label: 'LABEL3',"
865         "    style: 'check',"
866         "    visible: true,"
867         "  },{"
868         "    id: 'ID4',"
869         "    label: 'LABEL4',"
870         "    style: 'separator',"
871         "    visible: true,"
872         "    checked: true"
873         "  }]"
874         "});";
875     ASSERT_TRUE(content::ExecuteScript(
876         host->host_contents(), set_menu_item_test_script));
877
878     const ash::ime::InputMethodMenuItemList& props =
879         ash::ime::InputMethodMenuManager::GetInstance()->
880         GetCurrentInputMethodMenuItemList();
881     ASSERT_EQ(5U, props.size());
882
883     EXPECT_EQ("ID0", props[0].key);
884     EXPECT_EQ("ID1", props[1].key);
885     EXPECT_EQ("ID2", props[2].key);
886     EXPECT_EQ("ID3", props[3].key);
887     EXPECT_EQ("ID4", props[4].key);
888
889     EXPECT_EQ("LABEL1", props[1].label);
890     EXPECT_EQ("LABEL2", props[2].label);
891     EXPECT_EQ("LABEL3", props[3].label);
892     EXPECT_EQ("LABEL4", props[4].label);
893
894     EXPECT_TRUE(props[2].is_selection_item);
895     // TODO(nona): Add tests for style: ["toggle" and "separator"]
896     // and visible:, when implement them.
897
898     EXPECT_TRUE(props[4].is_selection_item_checked);
899   }
900   {
901     SCOPED_TRACE("deleteSurroundingText test");
902     mock_input_context->Reset();
903     mock_candidate_window->Reset();
904
905     const char delete_surrounding_text_test_script[] =
906         "chrome.input.ime.deleteSurroundingText({"
907         "  engineID: engineBridge.getActiveEngineID(),"
908         "  contextID: engineBridge.getFocusedContextID().contextID,"
909         "  offset: 5,"
910         "  length: 3"
911         "});";
912     ASSERT_TRUE(content::ExecuteScript(
913         host->host_contents(), delete_surrounding_text_test_script));
914
915     EXPECT_EQ(1, mock_input_context->delete_surrounding_text_call_count());
916     EXPECT_EQ(5, mock_input_context->last_delete_surrounding_text_arg().offset);
917     EXPECT_EQ(3U,
918               mock_input_context->last_delete_surrounding_text_arg().length);
919   }
920   {
921     SCOPED_TRACE("onFocus test");
922     mock_input_context->Reset();
923     mock_candidate_window->Reset();
924
925     {
926       ExtensionTestMessageListener focus_listener("onFocus:text", false);
927       IMEEngineHandlerInterface::InputContext context(
928           ui::TEXT_INPUT_TYPE_TEXT, ui::TEXT_INPUT_MODE_DEFAULT);
929       engine_handler->FocusIn(context);
930       ASSERT_TRUE(focus_listener.WaitUntilSatisfied());
931       ASSERT_TRUE(focus_listener.was_satisfied());
932     }
933     {
934       ExtensionTestMessageListener focus_listener("onFocus:search", false);
935       IMEEngineHandlerInterface::InputContext context(
936           ui::TEXT_INPUT_TYPE_SEARCH, ui::TEXT_INPUT_MODE_DEFAULT);
937       engine_handler->FocusIn(context);
938       ASSERT_TRUE(focus_listener.WaitUntilSatisfied());
939       ASSERT_TRUE(focus_listener.was_satisfied());
940     }
941     {
942       ExtensionTestMessageListener focus_listener("onFocus:tel", false);
943       IMEEngineHandlerInterface::InputContext context(
944           ui::TEXT_INPUT_TYPE_TELEPHONE, ui::TEXT_INPUT_MODE_DEFAULT);
945       engine_handler->FocusIn(context);
946       ASSERT_TRUE(focus_listener.WaitUntilSatisfied());
947       ASSERT_TRUE(focus_listener.was_satisfied());
948     }
949     {
950       ExtensionTestMessageListener focus_listener("onFocus:url", false);
951       IMEEngineHandlerInterface::InputContext context(
952           ui::TEXT_INPUT_TYPE_URL, ui::TEXT_INPUT_MODE_DEFAULT);
953       engine_handler->FocusIn(context);
954       ASSERT_TRUE(focus_listener.WaitUntilSatisfied());
955       ASSERT_TRUE(focus_listener.was_satisfied());
956     }
957     {
958       ExtensionTestMessageListener focus_listener("onFocus:email", false);
959       IMEEngineHandlerInterface::InputContext context(
960           ui::TEXT_INPUT_TYPE_EMAIL, ui::TEXT_INPUT_MODE_DEFAULT);
961       engine_handler->FocusIn(context);
962       ASSERT_TRUE(focus_listener.WaitUntilSatisfied());
963       ASSERT_TRUE(focus_listener.was_satisfied());
964     }
965     {
966       ExtensionTestMessageListener focus_listener("onFocus:number", false);
967       IMEEngineHandlerInterface::InputContext context(
968           ui::TEXT_INPUT_TYPE_NUMBER, ui::TEXT_INPUT_MODE_DEFAULT);
969       engine_handler->FocusIn(context);
970       ASSERT_TRUE(focus_listener.WaitUntilSatisfied());
971       ASSERT_TRUE(focus_listener.was_satisfied());
972     }
973   }
974
975   IMEBridge::Get()->SetInputContextHandler(NULL);
976   IMEBridge::Get()->SetCandidateWindowHandler(NULL);
977 }
978
979 }  // namespace
980 }  // namespace input_method
981 }  // namespace chromeos