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/base/ime/text_input_flags.h"
24 #include "ui/events/event.h"
27 namespace input_method {
30 const char kIdentityIMEID[] =
31 "_ext_ime_iafoklpfplgfnoimmaejoeondnjnlcfpIdentityIME";
32 const char kToUpperIMEID[] =
33 "_ext_ime_iafoklpfplgfnoimmaejoeondnjnlcfpToUpperIME";
34 const char kAPIArgumentIMEID[] =
35 "_ext_ime_iafoklpfplgfnoimmaejoeondnjnlcfpAPIArgumentIME";
36 const char kExtensionID[] = "iafoklpfplgfnoimmaejoeondnjnlcfp";
38 // InputMethod extension should work on 1)normal extension, 2)normal extension
39 // in incognito mode 3)component extension.
42 kTestTypeIncognito = 1,
43 kTestTypeComponent = 2,
46 class InputMethodEngineBrowserTest
47 : public ExtensionBrowserTest,
48 public ::testing::WithParamInterface<TestType> {
50 InputMethodEngineBrowserTest()
51 : ExtensionBrowserTest() {}
52 virtual ~InputMethodEngineBrowserTest() {}
54 virtual void SetUpInProcessBrowserTestFixture() override {
55 ExtensionBrowserTest::SetUpInProcessBrowserTestFixture();
58 virtual void TearDownInProcessBrowserTestFixture() override {
63 void LoadTestInputMethod() {
64 // This will load "chrome/test/data/extensions/input_ime"
65 ExtensionTestMessageListener ime_ready_listener("ReadyToUseImeEvent",
67 extension_ = LoadExtensionWithType("input_ime", GetParam());
68 ASSERT_TRUE(extension_);
69 ASSERT_TRUE(ime_ready_listener.WaitUntilSatisfied());
71 // Extension IMEs are not enabled by default.
72 std::vector<std::string> extension_ime_ids;
73 extension_ime_ids.push_back(kIdentityIMEID);
74 extension_ime_ids.push_back(kToUpperIMEID);
75 extension_ime_ids.push_back(kAPIArgumentIMEID);
76 InputMethodManager::Get()->GetActiveIMEState()->SetEnabledExtensionImes(
79 InputMethodDescriptors extension_imes;
80 InputMethodManager::Get()->GetActiveIMEState()->GetInputMethodExtensions(
83 // Test IME has two input methods, thus InputMethodManager should have two
85 // Note: Even extension is loaded by LoadExtensionAsComponent as above, the
86 // IME does not managed by ComponentExtensionIMEManager or it's id won't
87 // start with __comp__. The component extension IME is whitelisted and
88 // managed by ComponentExtensionIMEManager, but its framework is same as
89 // normal extension IME.
90 EXPECT_EQ(3U, extension_imes.size());
93 const extensions::Extension* LoadExtensionWithType(
94 const std::string& extension_name, TestType type) {
97 return LoadExtension(test_data_dir_.AppendASCII(extension_name));
98 case kTestTypeIncognito:
99 return LoadExtensionIncognito(
100 test_data_dir_.AppendASCII(extension_name));
101 case kTestTypeComponent:
102 return LoadExtensionAsComponent(
103 test_data_dir_.AppendASCII(extension_name));
109 const extensions::Extension* extension_;
112 class KeyEventDoneCallback {
114 explicit KeyEventDoneCallback(bool expected_argument)
115 : expected_argument_(expected_argument),
117 ~KeyEventDoneCallback() {}
119 void Run(bool consumed) {
120 if (consumed == expected_argument_) {
121 base::MessageLoop::current()->Quit();
126 void WaitUntilCalled() {
128 content::RunMessageLoop();
132 bool expected_argument_;
135 DISALLOW_COPY_AND_ASSIGN(KeyEventDoneCallback);
138 INSTANTIATE_TEST_CASE_P(InputMethodEngineBrowserTest,
139 InputMethodEngineBrowserTest,
140 ::testing::Values(kTestTypeNormal));
141 INSTANTIATE_TEST_CASE_P(InputMethodEngineIncognitoBrowserTest,
142 InputMethodEngineBrowserTest,
143 ::testing::Values(kTestTypeIncognito));
144 INSTANTIATE_TEST_CASE_P(InputMethodEngineComponentExtensionBrowserTest,
145 InputMethodEngineBrowserTest,
146 ::testing::Values(kTestTypeComponent));
148 IN_PROC_BROWSER_TEST_P(InputMethodEngineBrowserTest,
150 LoadTestInputMethod();
152 InputMethodManager::Get()->GetActiveIMEState()->ChangeInputMethod(
153 kIdentityIMEID, false /* show_message */);
155 scoped_ptr<MockIMEInputContextHandler> mock_input_context(
156 new MockIMEInputContextHandler());
157 scoped_ptr<MockIMECandidateWindowHandler> mock_candidate_window(
158 new MockIMECandidateWindowHandler());
160 IMEBridge::Get()->SetInputContextHandler(mock_input_context.get());
161 IMEBridge::Get()->SetCandidateWindowHandler(mock_candidate_window.get());
163 IMEEngineHandlerInterface* engine_handler =
164 IMEBridge::Get()->GetCurrentEngineHandler();
165 ASSERT_TRUE(engine_handler);
167 // onActivate event should be fired if Enable function is called.
168 ExtensionTestMessageListener activated_listener("onActivate", false);
169 engine_handler->Enable("IdentityIME");
170 ASSERT_TRUE(activated_listener.WaitUntilSatisfied());
171 ASSERT_TRUE(activated_listener.was_satisfied());
173 // onFocus event should be fired if FocusIn function is called.
174 ExtensionTestMessageListener focus_listener("onFocus:text", false);
175 IMEEngineHandlerInterface::InputContext context(ui::TEXT_INPUT_TYPE_TEXT,
176 ui::TEXT_INPUT_MODE_DEFAULT,
177 ui::TEXT_INPUT_FLAG_NONE);
178 engine_handler->FocusIn(context);
179 ASSERT_TRUE(focus_listener.WaitUntilSatisfied());
180 ASSERT_TRUE(focus_listener.was_satisfied());
182 // onKeyEvent should be fired if ProcessKeyEvent is called.
183 KeyEventDoneCallback callback(false); // EchoBackIME doesn't consume keys.
184 ExtensionTestMessageListener keyevent_listener("onKeyEvent", false);
185 ui::KeyEvent key_event(ui::ET_KEY_PRESSED, ui::VKEY_A, ui::EF_NONE);
186 engine_handler->ProcessKeyEvent(key_event,
187 base::Bind(&KeyEventDoneCallback::Run,
188 base::Unretained(&callback)));
189 ASSERT_TRUE(keyevent_listener.WaitUntilSatisfied());
190 ASSERT_TRUE(keyevent_listener.was_satisfied());
191 callback.WaitUntilCalled();
193 // onSurroundingTextChange should be fired if SetSurroundingText is called.
194 ExtensionTestMessageListener surrounding_text_listener(
195 "onSurroundingTextChanged", false);
196 engine_handler->SetSurroundingText("text", // Surrounding text.
197 0, // focused position.
198 1); // anchor position.
199 ASSERT_TRUE(surrounding_text_listener.WaitUntilSatisfied());
200 ASSERT_TRUE(surrounding_text_listener.was_satisfied());
202 // onMenuItemActivated should be fired if PropertyActivate is called.
203 ExtensionTestMessageListener property_listener("onMenuItemActivated", false);
204 engine_handler->PropertyActivate("property_name");
205 ASSERT_TRUE(property_listener.WaitUntilSatisfied());
206 ASSERT_TRUE(property_listener.was_satisfied());
208 // onReset should be fired if Reset is called.
209 ExtensionTestMessageListener reset_listener("onReset", false);
210 engine_handler->Reset();
211 ASSERT_TRUE(reset_listener.WaitUntilSatisfied());
212 ASSERT_TRUE(reset_listener.was_satisfied());
214 // onBlur should be fired if FocusOut is called.
215 ExtensionTestMessageListener blur_listener("onBlur", false);
216 engine_handler->FocusOut();
217 ASSERT_TRUE(blur_listener.WaitUntilSatisfied());
218 ASSERT_TRUE(blur_listener.was_satisfied());
220 // onDeactivated should be fired if Disable is called.
221 ExtensionTestMessageListener disabled_listener("onDeactivated", false);
222 engine_handler->Disable();
223 ASSERT_TRUE(disabled_listener.WaitUntilSatisfied());
224 ASSERT_TRUE(disabled_listener.was_satisfied());
226 IMEBridge::Get()->SetInputContextHandler(NULL);
227 IMEBridge::Get()->SetCandidateWindowHandler(NULL);
230 IN_PROC_BROWSER_TEST_P(InputMethodEngineBrowserTest,
232 LoadTestInputMethod();
234 InputMethodManager::Get()->GetActiveIMEState()->ChangeInputMethod(
235 kAPIArgumentIMEID, false /* show_message */);
237 scoped_ptr<MockIMEInputContextHandler> mock_input_context(
238 new MockIMEInputContextHandler());
239 scoped_ptr<MockIMECandidateWindowHandler> mock_candidate_window(
240 new MockIMECandidateWindowHandler());
242 IMEBridge::Get()->SetInputContextHandler(mock_input_context.get());
243 IMEBridge::Get()->SetCandidateWindowHandler(mock_candidate_window.get());
245 IMEEngineHandlerInterface* engine_handler =
246 IMEBridge::Get()->GetCurrentEngineHandler();
247 ASSERT_TRUE(engine_handler);
249 extensions::ExtensionHost* host =
250 extensions::ProcessManager::Get(profile())
251 ->GetBackgroundHostForExtension(extension_->id());
254 engine_handler->Enable("APIArgumentIME");
255 IMEEngineHandlerInterface::InputContext context(ui::TEXT_INPUT_TYPE_TEXT,
256 ui::TEXT_INPUT_MODE_DEFAULT,
257 ui::TEXT_INPUT_FLAG_NONE);
258 engine_handler->FocusIn(context);
261 SCOPED_TRACE("KeyDown, Ctrl:No, alt:No, Shift:No, Caps:No");
262 KeyEventDoneCallback callback(false);
263 const std::string expected_value =
264 "onKeyEvent::keydown:a:KeyA:false:false:false:false";
265 ExtensionTestMessageListener keyevent_listener(expected_value, false);
267 ui::KeyEvent key_event(
268 ui::ET_KEY_PRESSED, ui::VKEY_A, "KeyA", ui::EF_NONE);
269 engine_handler->ProcessKeyEvent(key_event,
270 base::Bind(&KeyEventDoneCallback::Run,
271 base::Unretained(&callback)));
272 ASSERT_TRUE(keyevent_listener.WaitUntilSatisfied());
273 EXPECT_TRUE(keyevent_listener.was_satisfied());
274 callback.WaitUntilCalled();
277 SCOPED_TRACE("KeyDown, Ctrl:Yes, alt:No, Shift:No, Caps:No");
278 KeyEventDoneCallback callback(false);
279 const std::string expected_value =
280 "onKeyEvent::keydown:a:KeyA:true:false:false:false";
281 ExtensionTestMessageListener keyevent_listener(expected_value, false);
283 ui::KeyEvent key_event(ui::ET_KEY_PRESSED,
286 ui::EF_CONTROL_DOWN);
287 engine_handler->ProcessKeyEvent(key_event,
288 base::Bind(&KeyEventDoneCallback::Run,
289 base::Unretained(&callback)));
290 ASSERT_TRUE(keyevent_listener.WaitUntilSatisfied());
291 EXPECT_TRUE(keyevent_listener.was_satisfied());
292 callback.WaitUntilCalled();
295 SCOPED_TRACE("KeyDown, Ctrl:No, alt:Yes, Shift:No, Caps:No");
296 KeyEventDoneCallback callback(false);
297 const std::string expected_value =
298 "onKeyEvent::keydown:a:KeyA:false:true:false:false";
299 ExtensionTestMessageListener keyevent_listener(expected_value, false);
301 ui::KeyEvent key_event(ui::ET_KEY_PRESSED,
305 engine_handler->ProcessKeyEvent(key_event,
306 base::Bind(&KeyEventDoneCallback::Run,
307 base::Unretained(&callback)));
308 ASSERT_TRUE(keyevent_listener.WaitUntilSatisfied());
309 EXPECT_TRUE(keyevent_listener.was_satisfied());
310 callback.WaitUntilCalled();
313 SCOPED_TRACE("KeyDown, Ctrl:No, alt:No, Shift:Yes, Caps:No");
314 KeyEventDoneCallback callback(false);
315 const std::string expected_value =
316 "onKeyEvent::keydown:A:KeyA:false:false:true:false";
317 ExtensionTestMessageListener keyevent_listener(expected_value, false);
319 ui::KeyEvent key_event(ui::ET_KEY_PRESSED,
323 engine_handler->ProcessKeyEvent(key_event,
324 base::Bind(&KeyEventDoneCallback::Run,
325 base::Unretained(&callback)));
326 ASSERT_TRUE(keyevent_listener.WaitUntilSatisfied());
327 EXPECT_TRUE(keyevent_listener.was_satisfied());
328 callback.WaitUntilCalled();
331 SCOPED_TRACE("KeyDown, Ctrl:No, alt:No, Shift:No, Caps:Yes");
332 KeyEventDoneCallback callback(false);
333 const std::string expected_value =
334 "onKeyEvent::keydown:A:KeyA:false:false:false:true";
335 ExtensionTestMessageListener keyevent_listener(expected_value, false);
337 ui::KeyEvent key_event(ui::ET_KEY_PRESSED,
340 ui::EF_CAPS_LOCK_DOWN);
341 engine_handler->ProcessKeyEvent(key_event,
342 base::Bind(&KeyEventDoneCallback::Run,
343 base::Unretained(&callback)));
344 ASSERT_TRUE(keyevent_listener.WaitUntilSatisfied());
345 EXPECT_TRUE(keyevent_listener.was_satisfied());
346 callback.WaitUntilCalled();
349 SCOPED_TRACE("KeyDown, Ctrl:Yes, alt:Yes, Shift:No, Caps:No");
350 KeyEventDoneCallback callback(false);
351 const std::string expected_value =
352 "onKeyEvent::keydown:a:KeyA:true:true:false:false";
353 ExtensionTestMessageListener keyevent_listener(expected_value, false);
355 ui::KeyEvent key_event(ui::ET_KEY_PRESSED,
358 ui::EF_ALT_DOWN | ui::EF_CONTROL_DOWN);
359 engine_handler->ProcessKeyEvent(key_event,
360 base::Bind(&KeyEventDoneCallback::Run,
361 base::Unretained(&callback)));
362 ASSERT_TRUE(keyevent_listener.WaitUntilSatisfied());
363 EXPECT_TRUE(keyevent_listener.was_satisfied());
364 callback.WaitUntilCalled();
367 SCOPED_TRACE("KeyDown, Ctrl:No, alt:No, Shift:Yes, Caps:Yes");
368 KeyEventDoneCallback callback(false);
369 const std::string expected_value =
370 "onKeyEvent::keydown:a:KeyA:false:false:true:true";
371 ExtensionTestMessageListener keyevent_listener(expected_value, false);
373 ui::KeyEvent key_event(ui::ET_KEY_PRESSED,
376 ui::EF_SHIFT_DOWN | ui::EF_CAPS_LOCK_DOWN);
377 engine_handler->ProcessKeyEvent(key_event,
378 base::Bind(&KeyEventDoneCallback::Run,
379 base::Unretained(&callback)));
380 ASSERT_TRUE(keyevent_listener.WaitUntilSatisfied());
381 EXPECT_TRUE(keyevent_listener.was_satisfied());
382 callback.WaitUntilCalled();
386 ui::KeyboardCode keycode;
389 } kMediaKeyCases[] = {
390 { ui::VKEY_BROWSER_BACK, "BrowserBack", "HistoryBack" },
391 { ui::VKEY_BROWSER_FORWARD, "BrowserForward", "HistoryForward" },
392 { ui::VKEY_BROWSER_REFRESH, "BrowserRefresh", "BrowserRefresh" },
393 { ui::VKEY_MEDIA_LAUNCH_APP2, "ChromeOSFullscreen", "ChromeOSFullscreen" },
394 { ui::VKEY_MEDIA_LAUNCH_APP1,
395 "ChromeOSSwitchWindow", "ChromeOSSwitchWindow" },
396 { ui::VKEY_BRIGHTNESS_DOWN, "BrightnessDown", "BrightnessDown" },
397 { ui::VKEY_BRIGHTNESS_UP, "BrightnessUp", "BrightnessUp" },
398 { ui::VKEY_VOLUME_MUTE, "VolumeMute", "AudioVolumeMute" },
399 { ui::VKEY_VOLUME_DOWN, "VolumeDown", "AudioVolumeDown" },
400 { ui::VKEY_VOLUME_UP, "VolumeUp", "AudioVolumeUp" },
401 { ui::VKEY_F1, "F1", "HistoryBack" },
402 { ui::VKEY_F2, "F2", "HistoryForward" },
403 { ui::VKEY_F3, "F3", "BrowserRefresh" },
404 { ui::VKEY_F4, "F4", "ChromeOSFullscreen" },
405 { ui::VKEY_F5, "F5", "ChromeOSSwitchWindow" },
406 { ui::VKEY_F6, "F6", "BrightnessDown" },
407 { ui::VKEY_F7, "F7", "BrightnessUp" },
408 { ui::VKEY_F8, "F8", "AudioVolumeMute" },
409 { ui::VKEY_F9, "F9", "AudioVolumeDown" },
410 { ui::VKEY_F10, "F10", "AudioVolumeUp" },
412 for (size_t i = 0; i < arraysize(kMediaKeyCases); ++i) {
413 SCOPED_TRACE(std::string("KeyDown, ") + kMediaKeyCases[i].code);
414 KeyEventDoneCallback callback(false);
415 const std::string expected_value =
416 base::StringPrintf("onKeyEvent::keydown:%s:%s:false:false:false:false",
417 kMediaKeyCases[i].key, kMediaKeyCases[i].code);
418 ExtensionTestMessageListener keyevent_listener(expected_value, false);
420 ui::KeyEvent key_event(ui::ET_KEY_PRESSED,
421 kMediaKeyCases[i].keycode,
422 kMediaKeyCases[i].code,
424 engine_handler->ProcessKeyEvent(key_event,
425 base::Bind(&KeyEventDoneCallback::Run,
426 base::Unretained(&callback)));
427 ASSERT_TRUE(keyevent_listener.WaitUntilSatisfied());
428 EXPECT_TRUE(keyevent_listener.was_satisfied());
429 callback.WaitUntilCalled();
431 // TODO(nona): Add browser tests for other API as well.
433 SCOPED_TRACE("commitText test");
434 mock_input_context->Reset();
435 mock_candidate_window->Reset();
437 const char commit_text_test_script[] =
438 "chrome.input.ime.commitText({"
439 " contextID: engineBridge.getFocusedContextID().contextID,"
440 " text:'COMMIT_TEXT'"
443 ASSERT_TRUE(content::ExecuteScript(host->host_contents(),
444 commit_text_test_script));
445 EXPECT_EQ(1, mock_input_context->commit_text_call_count());
446 EXPECT_EQ("COMMIT_TEXT", mock_input_context->last_commit_text());
449 SCOPED_TRACE("sendKeyEvents test");
450 mock_input_context->Reset();
451 mock_candidate_window->Reset();
453 const char send_key_events_test_script[] =
454 "chrome.input.ime.sendKeyEvents({"
455 " contextID: engineBridge.getFocusedContextID().contextID,"
469 ExtensionTestMessageListener keyevent_listener_down(
470 std::string("onKeyEvent:") + kExtensionID +
471 ":keydown:z:KeyZ:false:false:false:false",
473 ExtensionTestMessageListener keyevent_listener_up(
474 std::string("onKeyEvent:") + kExtensionID +
475 ":keyup:z:KeyZ:false:false:false:false",
478 ASSERT_TRUE(content::ExecuteScript(host->host_contents(),
479 send_key_events_test_script));
481 ASSERT_TRUE(keyevent_listener_down.WaitUntilSatisfied());
482 EXPECT_TRUE(keyevent_listener_down.was_satisfied());
483 ASSERT_TRUE(keyevent_listener_up.WaitUntilSatisfied());
484 EXPECT_TRUE(keyevent_listener_up.was_satisfied());
487 SCOPED_TRACE("sendKeyEvents test with keyCode");
488 mock_input_context->Reset();
489 mock_candidate_window->Reset();
491 const char send_key_events_test_script[] =
492 "chrome.input.ime.sendKeyEvents({"
493 " contextID: engineBridge.getFocusedContextID().contextID,"
509 ExtensionTestMessageListener keyevent_listener_down(
510 std::string("onKeyEvent:") + kExtensionID +
511 ":keydown:a:KeyQ:false:false:false:false",
513 ExtensionTestMessageListener keyevent_listener_up(
514 std::string("onKeyEvent:") + kExtensionID +
515 ":keyup:a:KeyQ:false:false:false:false",
518 ASSERT_TRUE(content::ExecuteScript(host->host_contents(),
519 send_key_events_test_script));
521 ASSERT_TRUE(keyevent_listener_down.WaitUntilSatisfied());
522 EXPECT_TRUE(keyevent_listener_down.was_satisfied());
523 ASSERT_TRUE(keyevent_listener_up.WaitUntilSatisfied());
524 EXPECT_TRUE(keyevent_listener_up.was_satisfied());
527 SCOPED_TRACE("setComposition test");
528 mock_input_context->Reset();
529 mock_candidate_window->Reset();
531 const char set_composition_test_script[] =
532 "chrome.input.ime.setComposition({"
533 " contextID: engineBridge.getFocusedContextID().contextID,"
534 " text:'COMPOSITION_TEXT',"
539 " style: 'underline'"
543 " style: 'doubleUnderline'"
547 ASSERT_TRUE(content::ExecuteScript(host->host_contents(),
548 set_composition_test_script));
549 EXPECT_EQ(1, mock_input_context->update_preedit_text_call_count());
552 mock_input_context->last_update_composition_arg().cursor_pos);
553 EXPECT_TRUE(mock_input_context->last_update_composition_arg().is_visible);
555 const CompositionText& composition_text =
556 mock_input_context->last_update_composition_arg().composition_text;
557 EXPECT_EQ(base::UTF8ToUTF16("COMPOSITION_TEXT"), composition_text.text());
558 const std::vector<CompositionText::UnderlineAttribute>& underlines =
559 composition_text.underline_attributes();
561 ASSERT_EQ(2U, underlines.size());
562 EXPECT_EQ(CompositionText::COMPOSITION_TEXT_UNDERLINE_SINGLE,
564 EXPECT_EQ(0U, underlines[0].start_index);
565 EXPECT_EQ(5U, underlines[0].end_index);
567 EXPECT_EQ(CompositionText::COMPOSITION_TEXT_UNDERLINE_DOUBLE,
569 EXPECT_EQ(6U, underlines[1].start_index);
570 EXPECT_EQ(10U, underlines[1].end_index);
573 SCOPED_TRACE("clearComposition test");
574 mock_input_context->Reset();
575 mock_candidate_window->Reset();
577 const char commite_text_test_script[] =
578 "chrome.input.ime.clearComposition({"
579 " contextID: engineBridge.getFocusedContextID().contextID,"
582 ASSERT_TRUE(content::ExecuteScript(host->host_contents(),
583 commite_text_test_script));
584 EXPECT_EQ(1, mock_input_context->update_preedit_text_call_count());
586 mock_input_context->last_update_composition_arg().is_visible);
587 const CompositionText& composition_text =
588 mock_input_context->last_update_composition_arg().composition_text;
589 EXPECT_TRUE(composition_text.text().empty());
592 SCOPED_TRACE("setCandidateWindowProperties:visibility test");
593 mock_input_context->Reset();
594 mock_candidate_window->Reset();
596 const char set_candidate_window_properties_test_script[] =
597 "chrome.input.ime.setCandidateWindowProperties({"
598 " engineID: engineBridge.getActiveEngineID(),"
603 ASSERT_TRUE(content::ExecuteScript(
604 host->host_contents(),
605 set_candidate_window_properties_test_script));
606 EXPECT_EQ(1, mock_candidate_window->update_lookup_table_call_count());
608 mock_candidate_window->last_update_lookup_table_arg().is_visible);
611 SCOPED_TRACE("setCandidateWindowProperties:cursor_visibility test");
612 mock_input_context->Reset();
613 mock_candidate_window->Reset();
615 const char set_candidate_window_properties_test_script[] =
616 "chrome.input.ime.setCandidateWindowProperties({"
617 " engineID: engineBridge.getActiveEngineID(),"
619 " cursorVisible: true,"
622 ASSERT_TRUE(content::ExecuteScript(
623 host->host_contents(),
624 set_candidate_window_properties_test_script));
625 EXPECT_EQ(1, mock_candidate_window->update_lookup_table_call_count());
627 // window visibility is kept as before.
629 mock_candidate_window->last_update_lookup_table_arg().is_visible);
631 const ui::CandidateWindow& table =
632 mock_candidate_window->last_update_lookup_table_arg().lookup_table;
633 EXPECT_TRUE(table.is_cursor_visible());
636 SCOPED_TRACE("setCandidateWindowProperties:vertical test");
637 mock_input_context->Reset();
638 mock_candidate_window->Reset();
640 const char set_candidate_window_properties_test_script[] =
641 "chrome.input.ime.setCandidateWindowProperties({"
642 " engineID: engineBridge.getActiveEngineID(),"
647 ASSERT_TRUE(content::ExecuteScript(
648 host->host_contents(),
649 set_candidate_window_properties_test_script));
650 EXPECT_EQ(1, mock_candidate_window->update_lookup_table_call_count());
652 // window visibility is kept as before.
654 mock_candidate_window->last_update_lookup_table_arg().is_visible);
656 const ui::CandidateWindow& table =
657 mock_candidate_window->last_update_lookup_table_arg().lookup_table;
659 // cursor visibility is kept as before.
660 EXPECT_TRUE(table.is_cursor_visible());
662 EXPECT_EQ(ui::CandidateWindow::VERTICAL, table.orientation());
665 SCOPED_TRACE("setCandidateWindowProperties:pageSize test");
666 mock_input_context->Reset();
667 mock_candidate_window->Reset();
669 const char set_candidate_window_properties_test_script[] =
670 "chrome.input.ime.setCandidateWindowProperties({"
671 " engineID: engineBridge.getActiveEngineID(),"
676 ASSERT_TRUE(content::ExecuteScript(
677 host->host_contents(),
678 set_candidate_window_properties_test_script));
679 EXPECT_EQ(1, mock_candidate_window->update_lookup_table_call_count());
681 // window visibility is kept as before.
683 mock_candidate_window->last_update_lookup_table_arg().is_visible);
685 const ui::CandidateWindow& table =
686 mock_candidate_window->last_update_lookup_table_arg().lookup_table;
688 // cursor visibility is kept as before.
689 EXPECT_TRUE(table.is_cursor_visible());
691 // oritantation is kept as before.
692 EXPECT_EQ(ui::CandidateWindow::VERTICAL, table.orientation());
694 EXPECT_EQ(7U, table.page_size());
697 SCOPED_TRACE("setCandidateWindowProperties:auxTextVisibility test");
698 mock_input_context->Reset();
699 mock_candidate_window->Reset();
701 const char set_candidate_window_properties_test_script[] =
702 "chrome.input.ime.setCandidateWindowProperties({"
703 " engineID: engineBridge.getActiveEngineID(),"
705 " auxiliaryTextVisible: true"
708 ASSERT_TRUE(content::ExecuteScript(
709 host->host_contents(),
710 set_candidate_window_properties_test_script));
711 EXPECT_EQ(1, mock_candidate_window->update_lookup_table_call_count());
713 const ui::CandidateWindow& table =
714 mock_candidate_window->last_update_lookup_table_arg().lookup_table;
715 EXPECT_TRUE(table.is_auxiliary_text_visible());
718 SCOPED_TRACE("setCandidateWindowProperties:auxText test");
719 mock_input_context->Reset();
720 mock_candidate_window->Reset();
722 const char set_candidate_window_properties_test_script[] =
723 "chrome.input.ime.setCandidateWindowProperties({"
724 " engineID: engineBridge.getActiveEngineID(),"
726 " auxiliaryText: 'AUXILIARY_TEXT'"
729 ASSERT_TRUE(content::ExecuteScript(
730 host->host_contents(),
731 set_candidate_window_properties_test_script));
732 EXPECT_EQ(1, mock_candidate_window->update_lookup_table_call_count());
734 // aux text visibility is kept as before.
735 const ui::CandidateWindow& table =
736 mock_candidate_window->last_update_lookup_table_arg().lookup_table;
737 EXPECT_TRUE(table.is_auxiliary_text_visible());
738 EXPECT_EQ("AUXILIARY_TEXT", table.auxiliary_text());
741 SCOPED_TRACE("setCandidates test");
742 mock_input_context->Reset();
743 mock_candidate_window->Reset();
745 const char set_candidates_test_script[] =
746 "chrome.input.ime.setCandidates({"
747 " contextID: engineBridge.getFocusedContextID().contextID,"
749 " candidate: 'CANDIDATE_1',"
752 " candidate: 'CANDIDATE_2',"
756 " candidate: 'CANDIDATE_3',"
759 " annotation: 'ANNOTACTION_3'"
761 " candidate: 'CANDIDATE_4',"
764 " annotation: 'ANNOTACTION_4',"
771 ASSERT_TRUE(content::ExecuteScript(host->host_contents(),
772 set_candidates_test_script));
774 // window visibility is kept as before.
776 mock_candidate_window->last_update_lookup_table_arg().is_visible);
778 const ui::CandidateWindow& table =
779 mock_candidate_window->last_update_lookup_table_arg().lookup_table;
781 // cursor visibility is kept as before.
782 EXPECT_TRUE(table.is_cursor_visible());
784 // oritantation is kept as before.
785 EXPECT_EQ(ui::CandidateWindow::VERTICAL, table.orientation());
787 // page size is kept as before.
788 EXPECT_EQ(7U, table.page_size());
790 ASSERT_EQ(4U, table.candidates().size());
792 EXPECT_EQ(base::UTF8ToUTF16("CANDIDATE_1"),
793 table.candidates().at(0).value);
795 EXPECT_EQ(base::UTF8ToUTF16("CANDIDATE_2"),
796 table.candidates().at(1).value);
797 EXPECT_EQ(base::UTF8ToUTF16("LABEL_2"), table.candidates().at(1).label);
799 EXPECT_EQ(base::UTF8ToUTF16("CANDIDATE_3"),
800 table.candidates().at(2).value);
801 EXPECT_EQ(base::UTF8ToUTF16("LABEL_3"), table.candidates().at(2).label);
802 EXPECT_EQ(base::UTF8ToUTF16("ANNOTACTION_3"),
803 table.candidates().at(2).annotation);
805 EXPECT_EQ(base::UTF8ToUTF16("CANDIDATE_4"),
806 table.candidates().at(3).value);
807 EXPECT_EQ(base::UTF8ToUTF16("LABEL_4"), table.candidates().at(3).label);
808 EXPECT_EQ(base::UTF8ToUTF16("ANNOTACTION_4"),
809 table.candidates().at(3).annotation);
810 EXPECT_EQ(base::UTF8ToUTF16("TITLE_4"),
811 table.candidates().at(3).description_title);
812 EXPECT_EQ(base::UTF8ToUTF16("BODY_4"),
813 table.candidates().at(3).description_body);
816 SCOPED_TRACE("setCursorPosition test");
817 mock_input_context->Reset();
818 mock_candidate_window->Reset();
820 const char set_cursor_position_test_script[] =
821 "chrome.input.ime.setCursorPosition({"
822 " contextID: engineBridge.getFocusedContextID().contextID,"
825 ASSERT_TRUE(content::ExecuteScript(
826 host->host_contents(), set_cursor_position_test_script));
827 EXPECT_EQ(1, mock_candidate_window->update_lookup_table_call_count());
829 // window visibility is kept as before.
831 mock_candidate_window->last_update_lookup_table_arg().is_visible);
833 const ui::CandidateWindow& table =
834 mock_candidate_window->last_update_lookup_table_arg().lookup_table;
836 // cursor visibility is kept as before.
837 EXPECT_TRUE(table.is_cursor_visible());
839 // oritantation is kept as before.
840 EXPECT_EQ(ui::CandidateWindow::VERTICAL, table.orientation());
842 // page size is kept as before.
843 EXPECT_EQ(7U, table.page_size());
845 // candidates are same as before.
846 ASSERT_EQ(4U, table.candidates().size());
848 // Candidate ID == 2 is 1 in index.
849 EXPECT_EQ(1U, table.cursor_position());
852 SCOPED_TRACE("setMenuItem test");
853 mock_input_context->Reset();
854 mock_candidate_window->Reset();
856 const char set_menu_item_test_script[] =
857 "chrome.input.ime.setMenuItems({"
858 " engineID: engineBridge.getActiveEngineID(),"
876 " style: 'separator',"
881 ASSERT_TRUE(content::ExecuteScript(
882 host->host_contents(), set_menu_item_test_script));
884 const ash::ime::InputMethodMenuItemList& props =
885 ash::ime::InputMethodMenuManager::GetInstance()->
886 GetCurrentInputMethodMenuItemList();
887 ASSERT_EQ(5U, props.size());
889 EXPECT_EQ("ID0", props[0].key);
890 EXPECT_EQ("ID1", props[1].key);
891 EXPECT_EQ("ID2", props[2].key);
892 EXPECT_EQ("ID3", props[3].key);
893 EXPECT_EQ("ID4", props[4].key);
895 EXPECT_EQ("LABEL1", props[1].label);
896 EXPECT_EQ("LABEL2", props[2].label);
897 EXPECT_EQ("LABEL3", props[3].label);
898 EXPECT_EQ("LABEL4", props[4].label);
900 EXPECT_TRUE(props[2].is_selection_item);
901 // TODO(nona): Add tests for style: ["toggle" and "separator"]
902 // and visible:, when implement them.
904 EXPECT_TRUE(props[4].is_selection_item_checked);
907 SCOPED_TRACE("deleteSurroundingText test");
908 mock_input_context->Reset();
909 mock_candidate_window->Reset();
911 const char delete_surrounding_text_test_script[] =
912 "chrome.input.ime.deleteSurroundingText({"
913 " engineID: engineBridge.getActiveEngineID(),"
914 " contextID: engineBridge.getFocusedContextID().contextID,"
918 ASSERT_TRUE(content::ExecuteScript(
919 host->host_contents(), delete_surrounding_text_test_script));
921 EXPECT_EQ(1, mock_input_context->delete_surrounding_text_call_count());
922 EXPECT_EQ(5, mock_input_context->last_delete_surrounding_text_arg().offset);
924 mock_input_context->last_delete_surrounding_text_arg().length);
927 SCOPED_TRACE("onFocus test");
928 mock_input_context->Reset();
929 mock_candidate_window->Reset();
932 ExtensionTestMessageListener focus_listener("onFocus:text", false);
933 IMEEngineHandlerInterface::InputContext context(
934 ui::TEXT_INPUT_TYPE_TEXT, ui::TEXT_INPUT_MODE_DEFAULT,
935 ui::TEXT_INPUT_FLAG_NONE);
936 engine_handler->FocusIn(context);
937 ASSERT_TRUE(focus_listener.WaitUntilSatisfied());
938 ASSERT_TRUE(focus_listener.was_satisfied());
941 ExtensionTestMessageListener focus_listener("onFocus:search", false);
942 IMEEngineHandlerInterface::InputContext context(
943 ui::TEXT_INPUT_TYPE_SEARCH, ui::TEXT_INPUT_MODE_DEFAULT,
944 ui::TEXT_INPUT_FLAG_NONE);
945 engine_handler->FocusIn(context);
946 ASSERT_TRUE(focus_listener.WaitUntilSatisfied());
947 ASSERT_TRUE(focus_listener.was_satisfied());
950 ExtensionTestMessageListener focus_listener("onFocus:tel", false);
951 IMEEngineHandlerInterface::InputContext context(
952 ui::TEXT_INPUT_TYPE_TELEPHONE, ui::TEXT_INPUT_MODE_DEFAULT,
953 ui::TEXT_INPUT_FLAG_NONE);
954 engine_handler->FocusIn(context);
955 ASSERT_TRUE(focus_listener.WaitUntilSatisfied());
956 ASSERT_TRUE(focus_listener.was_satisfied());
959 ExtensionTestMessageListener focus_listener("onFocus:url", false);
960 IMEEngineHandlerInterface::InputContext context(
961 ui::TEXT_INPUT_TYPE_URL, ui::TEXT_INPUT_MODE_DEFAULT,
962 ui::TEXT_INPUT_FLAG_NONE);
963 engine_handler->FocusIn(context);
964 ASSERT_TRUE(focus_listener.WaitUntilSatisfied());
965 ASSERT_TRUE(focus_listener.was_satisfied());
968 ExtensionTestMessageListener focus_listener("onFocus:email", false);
969 IMEEngineHandlerInterface::InputContext context(
970 ui::TEXT_INPUT_TYPE_EMAIL, ui::TEXT_INPUT_MODE_DEFAULT,
971 ui::TEXT_INPUT_FLAG_NONE);
972 engine_handler->FocusIn(context);
973 ASSERT_TRUE(focus_listener.WaitUntilSatisfied());
974 ASSERT_TRUE(focus_listener.was_satisfied());
977 ExtensionTestMessageListener focus_listener("onFocus:number", false);
978 IMEEngineHandlerInterface::InputContext context(
979 ui::TEXT_INPUT_TYPE_NUMBER, ui::TEXT_INPUT_MODE_DEFAULT,
980 ui::TEXT_INPUT_FLAG_NONE);
981 engine_handler->FocusIn(context);
982 ASSERT_TRUE(focus_listener.WaitUntilSatisfied());
983 ASSERT_TRUE(focus_listener.was_satisfied());
987 IMEBridge::Get()->SetInputContextHandler(NULL);
988 IMEBridge::Get()->SetCandidateWindowHandler(NULL);
992 } // namespace input_method
993 } // namespace chromeos