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