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.
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"
26 namespace input_method {
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";
37 // InputMethod extension should work on 1)normal extension, 2)normal extension
38 // in incognito mode 3)component extension.
41 kTestTypeIncognito = 1,
42 kTestTypeComponent = 2,
45 class InputMethodEngineBrowserTest
46 : public ExtensionBrowserTest,
47 public ::testing::WithParamInterface<TestType> {
49 InputMethodEngineBrowserTest()
50 : ExtensionBrowserTest() {}
51 virtual ~InputMethodEngineBrowserTest() {}
53 virtual void SetUpInProcessBrowserTestFixture() OVERRIDE {
54 ExtensionBrowserTest::SetUpInProcessBrowserTestFixture();
57 virtual void TearDownInProcessBrowserTestFixture() OVERRIDE {
62 void LoadTestInputMethod() {
63 // This will load "chrome/test/data/extensions/input_ime"
64 ExtensionTestMessageListener ime_ready_listener("ReadyToUseImeEvent",
66 extension_ = LoadExtensionWithType("input_ime", GetParam());
67 ASSERT_TRUE(extension_);
68 ASSERT_TRUE(ime_ready_listener.WaitUntilSatisfied());
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(
78 InputMethodDescriptors extension_imes;
79 InputMethodManager::Get()->GetActiveIMEState()->GetInputMethodExtensions(
82 // Test IME has two input methods, thus InputMethodManager should have two
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());
92 const extensions::Extension* LoadExtensionWithType(
93 const std::string& extension_name, TestType type) {
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));
108 const extensions::Extension* extension_;
111 class KeyEventDoneCallback {
113 explicit KeyEventDoneCallback(bool expected_argument)
114 : expected_argument_(expected_argument),
116 ~KeyEventDoneCallback() {}
118 void Run(bool consumed) {
119 if (consumed == expected_argument_) {
120 base::MessageLoop::current()->Quit();
125 void WaitUntilCalled() {
127 content::RunMessageLoop();
131 bool expected_argument_;
134 DISALLOW_COPY_AND_ASSIGN(KeyEventDoneCallback);
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));
147 IN_PROC_BROWSER_TEST_P(InputMethodEngineBrowserTest,
149 LoadTestInputMethod();
151 InputMethodManager::Get()->GetActiveIMEState()->ChangeInputMethod(
152 kIdentityIMEID, false /* show_message */);
154 scoped_ptr<MockIMEInputContextHandler> mock_input_context(
155 new MockIMEInputContextHandler());
156 scoped_ptr<MockIMECandidateWindowHandler> mock_candidate_window(
157 new MockIMECandidateWindowHandler());
159 IMEBridge::Get()->SetInputContextHandler(mock_input_context.get());
160 IMEBridge::Get()->SetCandidateWindowHandler(mock_candidate_window.get());
162 IMEEngineHandlerInterface* engine_handler =
163 IMEBridge::Get()->GetCurrentEngineHandler();
164 ASSERT_TRUE(engine_handler);
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());
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());
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();
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());
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());
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());
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());
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());
224 IMEBridge::Get()->SetInputContextHandler(NULL);
225 IMEBridge::Get()->SetCandidateWindowHandler(NULL);
228 IN_PROC_BROWSER_TEST_P(InputMethodEngineBrowserTest,
230 LoadTestInputMethod();
232 InputMethodManager::Get()->GetActiveIMEState()->ChangeInputMethod(
233 kAPIArgumentIMEID, false /* show_message */);
235 scoped_ptr<MockIMEInputContextHandler> mock_input_context(
236 new MockIMEInputContextHandler());
237 scoped_ptr<MockIMECandidateWindowHandler> mock_candidate_window(
238 new MockIMECandidateWindowHandler());
240 IMEBridge::Get()->SetInputContextHandler(mock_input_context.get());
241 IMEBridge::Get()->SetCandidateWindowHandler(mock_candidate_window.get());
243 IMEEngineHandlerInterface* engine_handler =
244 IMEBridge::Get()->GetCurrentEngineHandler();
245 ASSERT_TRUE(engine_handler);
247 extensions::ExtensionHost* host =
248 extensions::ExtensionSystem::Get(profile())
250 ->GetBackgroundHostForExtension(extension_->id());
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);
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);
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();
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);
281 ui::KeyEvent key_event(ui::ET_KEY_PRESSED,
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();
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);
299 ui::KeyEvent key_event(ui::ET_KEY_PRESSED,
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();
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);
317 ui::KeyEvent key_event(ui::ET_KEY_PRESSED,
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();
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);
335 ui::KeyEvent key_event(ui::ET_KEY_PRESSED,
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();
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);
353 ui::KeyEvent key_event(ui::ET_KEY_PRESSED,
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();
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);
371 ui::KeyEvent key_event(ui::ET_KEY_PRESSED,
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();
384 ui::KeyboardCode keycode;
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" },
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);
418 ui::KeyEvent key_event(ui::ET_KEY_PRESSED,
419 kMediaKeyCases[i].keycode,
420 kMediaKeyCases[i].code,
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();
429 // TODO(nona): Add browser tests for other API as well.
431 SCOPED_TRACE("commitText test");
432 mock_input_context->Reset();
433 mock_candidate_window->Reset();
435 const char commit_text_test_script[] =
436 "chrome.input.ime.commitText({"
437 " contextID: engineBridge.getFocusedContextID().contextID,"
438 " text:'COMMIT_TEXT'"
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());
447 SCOPED_TRACE("sendKeyEvents test");
448 mock_input_context->Reset();
449 mock_candidate_window->Reset();
451 const char send_key_events_test_script[] =
452 "chrome.input.ime.sendKeyEvents({"
453 " contextID: engineBridge.getFocusedContextID().contextID,"
467 ExtensionTestMessageListener keyevent_listener_down(
468 std::string("onKeyEvent:") + kExtensionID +
469 ":keydown:z:KeyZ:false:false:false:false",
471 ExtensionTestMessageListener keyevent_listener_up(
472 std::string("onKeyEvent:") + kExtensionID +
473 ":keyup:z:KeyZ:false:false:false:false",
476 ASSERT_TRUE(content::ExecuteScript(host->host_contents(),
477 send_key_events_test_script));
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());
485 SCOPED_TRACE("sendKeyEvents test with keyCode");
486 mock_input_context->Reset();
487 mock_candidate_window->Reset();
489 const char send_key_events_test_script[] =
490 "chrome.input.ime.sendKeyEvents({"
491 " contextID: engineBridge.getFocusedContextID().contextID,"
507 ExtensionTestMessageListener keyevent_listener_down(
508 std::string("onKeyEvent:") + kExtensionID +
509 ":keydown:a:KeyQ:false:false:false:false",
511 ExtensionTestMessageListener keyevent_listener_up(
512 std::string("onKeyEvent:") + kExtensionID +
513 ":keyup:a:KeyQ:false:false:false:false",
516 ASSERT_TRUE(content::ExecuteScript(host->host_contents(),
517 send_key_events_test_script));
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());
525 SCOPED_TRACE("setComposition test");
526 mock_input_context->Reset();
527 mock_candidate_window->Reset();
529 const char set_composition_test_script[] =
530 "chrome.input.ime.setComposition({"
531 " contextID: engineBridge.getFocusedContextID().contextID,"
532 " text:'COMPOSITION_TEXT',"
537 " style: 'underline'"
541 " style: 'doubleUnderline'"
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());
550 mock_input_context->last_update_composition_arg().cursor_pos);
551 EXPECT_TRUE(mock_input_context->last_update_composition_arg().is_visible);
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();
559 ASSERT_EQ(2U, underlines.size());
560 EXPECT_EQ(CompositionText::COMPOSITION_TEXT_UNDERLINE_SINGLE,
562 EXPECT_EQ(0U, underlines[0].start_index);
563 EXPECT_EQ(5U, underlines[0].end_index);
565 EXPECT_EQ(CompositionText::COMPOSITION_TEXT_UNDERLINE_DOUBLE,
567 EXPECT_EQ(6U, underlines[1].start_index);
568 EXPECT_EQ(10U, underlines[1].end_index);
571 SCOPED_TRACE("clearComposition test");
572 mock_input_context->Reset();
573 mock_candidate_window->Reset();
575 const char commite_text_test_script[] =
576 "chrome.input.ime.clearComposition({"
577 " contextID: engineBridge.getFocusedContextID().contextID,"
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());
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());
590 SCOPED_TRACE("setCandidateWindowProperties:visibility test");
591 mock_input_context->Reset();
592 mock_candidate_window->Reset();
594 const char set_candidate_window_properties_test_script[] =
595 "chrome.input.ime.setCandidateWindowProperties({"
596 " engineID: engineBridge.getActiveEngineID(),"
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());
606 mock_candidate_window->last_update_lookup_table_arg().is_visible);
609 SCOPED_TRACE("setCandidateWindowProperties:cursor_visibility test");
610 mock_input_context->Reset();
611 mock_candidate_window->Reset();
613 const char set_candidate_window_properties_test_script[] =
614 "chrome.input.ime.setCandidateWindowProperties({"
615 " engineID: engineBridge.getActiveEngineID(),"
617 " cursorVisible: true,"
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());
625 // window visibility is kept as before.
627 mock_candidate_window->last_update_lookup_table_arg().is_visible);
629 const ui::CandidateWindow& table =
630 mock_candidate_window->last_update_lookup_table_arg().lookup_table;
631 EXPECT_TRUE(table.is_cursor_visible());
634 SCOPED_TRACE("setCandidateWindowProperties:vertical test");
635 mock_input_context->Reset();
636 mock_candidate_window->Reset();
638 const char set_candidate_window_properties_test_script[] =
639 "chrome.input.ime.setCandidateWindowProperties({"
640 " engineID: engineBridge.getActiveEngineID(),"
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());
650 // window visibility is kept as before.
652 mock_candidate_window->last_update_lookup_table_arg().is_visible);
654 const ui::CandidateWindow& table =
655 mock_candidate_window->last_update_lookup_table_arg().lookup_table;
657 // cursor visibility is kept as before.
658 EXPECT_TRUE(table.is_cursor_visible());
660 EXPECT_EQ(ui::CandidateWindow::VERTICAL, table.orientation());
663 SCOPED_TRACE("setCandidateWindowProperties:pageSize test");
664 mock_input_context->Reset();
665 mock_candidate_window->Reset();
667 const char set_candidate_window_properties_test_script[] =
668 "chrome.input.ime.setCandidateWindowProperties({"
669 " engineID: engineBridge.getActiveEngineID(),"
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());
679 // window visibility is kept as before.
681 mock_candidate_window->last_update_lookup_table_arg().is_visible);
683 const ui::CandidateWindow& table =
684 mock_candidate_window->last_update_lookup_table_arg().lookup_table;
686 // cursor visibility is kept as before.
687 EXPECT_TRUE(table.is_cursor_visible());
689 // oritantation is kept as before.
690 EXPECT_EQ(ui::CandidateWindow::VERTICAL, table.orientation());
692 EXPECT_EQ(7U, table.page_size());
695 SCOPED_TRACE("setCandidateWindowProperties:auxTextVisibility test");
696 mock_input_context->Reset();
697 mock_candidate_window->Reset();
699 const char set_candidate_window_properties_test_script[] =
700 "chrome.input.ime.setCandidateWindowProperties({"
701 " engineID: engineBridge.getActiveEngineID(),"
703 " auxiliaryTextVisible: true"
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());
711 const ui::CandidateWindow& table =
712 mock_candidate_window->last_update_lookup_table_arg().lookup_table;
713 EXPECT_TRUE(table.is_auxiliary_text_visible());
716 SCOPED_TRACE("setCandidateWindowProperties:auxText test");
717 mock_input_context->Reset();
718 mock_candidate_window->Reset();
720 const char set_candidate_window_properties_test_script[] =
721 "chrome.input.ime.setCandidateWindowProperties({"
722 " engineID: engineBridge.getActiveEngineID(),"
724 " auxiliaryText: 'AUXILIARY_TEXT'"
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());
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());
739 SCOPED_TRACE("setCandidates test");
740 mock_input_context->Reset();
741 mock_candidate_window->Reset();
743 const char set_candidates_test_script[] =
744 "chrome.input.ime.setCandidates({"
745 " contextID: engineBridge.getFocusedContextID().contextID,"
747 " candidate: 'CANDIDATE_1',"
750 " candidate: 'CANDIDATE_2',"
754 " candidate: 'CANDIDATE_3',"
757 " annotation: 'ANNOTACTION_3'"
759 " candidate: 'CANDIDATE_4',"
762 " annotation: 'ANNOTACTION_4',"
769 ASSERT_TRUE(content::ExecuteScript(host->host_contents(),
770 set_candidates_test_script));
772 // window visibility is kept as before.
774 mock_candidate_window->last_update_lookup_table_arg().is_visible);
776 const ui::CandidateWindow& table =
777 mock_candidate_window->last_update_lookup_table_arg().lookup_table;
779 // cursor visibility is kept as before.
780 EXPECT_TRUE(table.is_cursor_visible());
782 // oritantation is kept as before.
783 EXPECT_EQ(ui::CandidateWindow::VERTICAL, table.orientation());
785 // page size is kept as before.
786 EXPECT_EQ(7U, table.page_size());
788 ASSERT_EQ(4U, table.candidates().size());
790 EXPECT_EQ(base::UTF8ToUTF16("CANDIDATE_1"),
791 table.candidates().at(0).value);
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);
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);
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);
814 SCOPED_TRACE("setCursorPosition test");
815 mock_input_context->Reset();
816 mock_candidate_window->Reset();
818 const char set_cursor_position_test_script[] =
819 "chrome.input.ime.setCursorPosition({"
820 " contextID: engineBridge.getFocusedContextID().contextID,"
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());
827 // window visibility is kept as before.
829 mock_candidate_window->last_update_lookup_table_arg().is_visible);
831 const ui::CandidateWindow& table =
832 mock_candidate_window->last_update_lookup_table_arg().lookup_table;
834 // cursor visibility is kept as before.
835 EXPECT_TRUE(table.is_cursor_visible());
837 // oritantation is kept as before.
838 EXPECT_EQ(ui::CandidateWindow::VERTICAL, table.orientation());
840 // page size is kept as before.
841 EXPECT_EQ(7U, table.page_size());
843 // candidates are same as before.
844 ASSERT_EQ(4U, table.candidates().size());
846 // Candidate ID == 2 is 1 in index.
847 EXPECT_EQ(1U, table.cursor_position());
850 SCOPED_TRACE("setMenuItem test");
851 mock_input_context->Reset();
852 mock_candidate_window->Reset();
854 const char set_menu_item_test_script[] =
855 "chrome.input.ime.setMenuItems({"
856 " engineID: engineBridge.getActiveEngineID(),"
874 " style: 'separator',"
879 ASSERT_TRUE(content::ExecuteScript(
880 host->host_contents(), set_menu_item_test_script));
882 const ash::ime::InputMethodMenuItemList& props =
883 ash::ime::InputMethodMenuManager::GetInstance()->
884 GetCurrentInputMethodMenuItemList();
885 ASSERT_EQ(5U, props.size());
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);
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);
898 EXPECT_TRUE(props[2].is_selection_item);
899 // TODO(nona): Add tests for style: ["toggle" and "separator"]
900 // and visible:, when implement them.
902 EXPECT_TRUE(props[4].is_selection_item_checked);
905 SCOPED_TRACE("deleteSurroundingText test");
906 mock_input_context->Reset();
907 mock_candidate_window->Reset();
909 const char delete_surrounding_text_test_script[] =
910 "chrome.input.ime.deleteSurroundingText({"
911 " engineID: engineBridge.getActiveEngineID(),"
912 " contextID: engineBridge.getFocusedContextID().contextID,"
916 ASSERT_TRUE(content::ExecuteScript(
917 host->host_contents(), delete_surrounding_text_test_script));
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);
922 mock_input_context->last_delete_surrounding_text_arg().length);
925 SCOPED_TRACE("onFocus test");
926 mock_input_context->Reset();
927 mock_candidate_window->Reset();
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());
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());
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());
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());
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());
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());
979 IMEBridge::Get()->SetInputContextHandler(NULL);
980 IMEBridge::Get()->SetCandidateWindowHandler(NULL);
984 } // namespace input_method
985 } // namespace chromeos