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