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