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 "chrome/browser/extensions/extension_test_message_listener.h"
12 #include "chromeos/ime/component_extension_ime_manager.h"
13 #include "chromeos/ime/composition_text.h"
14 #include "chromeos/ime/input_method_descriptor.h"
15 #include "chromeos/ime/input_method_manager.h"
16 #include "content/public/test/browser_test_utils.h"
17 #include "content/public/test/test_utils.h"
18 #include "extensions/browser/process_manager.h"
19 #include "extensions/common/manifest_handlers/background_info.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()->SetEnabledExtensionImes(&extension_ime_ids);
77 InputMethodDescriptors extension_imes;
78 InputMethodManager::Get()->GetInputMethodExtensions(&extension_imes);
80 // Test IME has two input methods, thus InputMethodManager should have two
82 // Note: Even extension is loaded by LoadExtensionAsComponent as above, the
83 // IME does not managed by ComponentExtensionIMEManager or it's id won't
84 // start with __comp__. The component extension IME is whitelisted and
85 // managed by ComponentExtensionIMEManager, but its framework is same as
86 // normal extension IME.
87 EXPECT_EQ(3U, extension_imes.size());
90 const extensions::Extension* LoadExtensionWithType(
91 const std::string& extension_name, TestType type) {
94 return LoadExtension(test_data_dir_.AppendASCII(extension_name));
95 case kTestTypeIncognito:
96 return LoadExtensionIncognito(
97 test_data_dir_.AppendASCII(extension_name));
98 case kTestTypeComponent:
99 return LoadExtensionAsComponent(
100 test_data_dir_.AppendASCII(extension_name));
106 const extensions::Extension* extension_;
109 class KeyEventDoneCallback {
111 explicit KeyEventDoneCallback(bool expected_argument)
112 : expected_argument_(expected_argument),
114 ~KeyEventDoneCallback() {}
116 void Run(bool consumed) {
117 if (consumed == expected_argument_) {
118 base::MessageLoop::current()->Quit();
123 void WaitUntilCalled() {
125 content::RunMessageLoop();
129 bool expected_argument_;
132 DISALLOW_COPY_AND_ASSIGN(KeyEventDoneCallback);
135 INSTANTIATE_TEST_CASE_P(InputMethodEngineBrowserTest,
136 InputMethodEngineBrowserTest,
137 ::testing::Values(kTestTypeNormal));
138 INSTANTIATE_TEST_CASE_P(InputMethodEngineIncognitoBrowserTest,
139 InputMethodEngineBrowserTest,
140 ::testing::Values(kTestTypeIncognito));
141 INSTANTIATE_TEST_CASE_P(InputMethodEngineComponentExtensionBrowserTest,
142 InputMethodEngineBrowserTest,
143 ::testing::Values(kTestTypeComponent));
145 IN_PROC_BROWSER_TEST_P(InputMethodEngineBrowserTest,
147 LoadTestInputMethod();
149 InputMethodManager::Get()->ChangeInputMethod(kIdentityIMEID);
151 scoped_ptr<MockIMEInputContextHandler> mock_input_context(
152 new MockIMEInputContextHandler());
153 scoped_ptr<MockIMECandidateWindowHandler> mock_candidate_window(
154 new MockIMECandidateWindowHandler());
156 IMEBridge::Get()->SetInputContextHandler(mock_input_context.get());
157 IMEBridge::Get()->SetCandidateWindowHandler(mock_candidate_window.get());
159 IMEEngineHandlerInterface* engine_handler =
160 IMEBridge::Get()->GetCurrentEngineHandler();
161 ASSERT_TRUE(engine_handler);
163 // onActivate event should be fired if Enable function is called.
164 ExtensionTestMessageListener activated_listener("onActivate", false);
165 engine_handler->Enable("IdentityIME");
166 ASSERT_TRUE(activated_listener.WaitUntilSatisfied());
167 ASSERT_TRUE(activated_listener.was_satisfied());
169 // onFocus event should be fired if FocusIn function is called.
170 ExtensionTestMessageListener focus_listener("onFocus:text", false);
171 IMEEngineHandlerInterface::InputContext context(ui::TEXT_INPUT_TYPE_TEXT,
172 ui::TEXT_INPUT_MODE_DEFAULT);
173 engine_handler->FocusIn(context);
174 ASSERT_TRUE(focus_listener.WaitUntilSatisfied());
175 ASSERT_TRUE(focus_listener.was_satisfied());
177 // onKeyEvent should be fired if ProcessKeyEvent is called.
178 KeyEventDoneCallback callback(false); // EchoBackIME doesn't consume keys.
179 ExtensionTestMessageListener keyevent_listener("onKeyEvent", false);
180 ui::KeyEvent key_event(ui::ET_KEY_PRESSED, ui::VKEY_A, ui::EF_NONE);
181 engine_handler->ProcessKeyEvent(key_event,
182 base::Bind(&KeyEventDoneCallback::Run,
183 base::Unretained(&callback)));
184 ASSERT_TRUE(keyevent_listener.WaitUntilSatisfied());
185 ASSERT_TRUE(keyevent_listener.was_satisfied());
186 callback.WaitUntilCalled();
188 // onSurroundingTextChange should be fired if SetSurroundingText is called.
189 ExtensionTestMessageListener surrounding_text_listener(
190 "onSurroundingTextChanged", false);
191 engine_handler->SetSurroundingText("text", // Surrounding text.
192 0, // focused position.
193 1); // anchor position.
194 ASSERT_TRUE(surrounding_text_listener.WaitUntilSatisfied());
195 ASSERT_TRUE(surrounding_text_listener.was_satisfied());
197 // onMenuItemActivated should be fired if PropertyActivate is called.
198 ExtensionTestMessageListener property_listener("onMenuItemActivated", false);
199 engine_handler->PropertyActivate("property_name");
200 ASSERT_TRUE(property_listener.WaitUntilSatisfied());
201 ASSERT_TRUE(property_listener.was_satisfied());
203 // onReset should be fired if Reset is called.
204 ExtensionTestMessageListener reset_listener("onReset", false);
205 engine_handler->Reset();
206 ASSERT_TRUE(reset_listener.WaitUntilSatisfied());
207 ASSERT_TRUE(reset_listener.was_satisfied());
209 // onBlur should be fired if FocusOut is called.
210 ExtensionTestMessageListener blur_listener("onBlur", false);
211 engine_handler->FocusOut();
212 ASSERT_TRUE(blur_listener.WaitUntilSatisfied());
213 ASSERT_TRUE(blur_listener.was_satisfied());
215 // onDeactivated should be fired if Disable is called.
216 ExtensionTestMessageListener disabled_listener("onDeactivated", false);
217 engine_handler->Disable();
218 ASSERT_TRUE(disabled_listener.WaitUntilSatisfied());
219 ASSERT_TRUE(disabled_listener.was_satisfied());
221 IMEBridge::Get()->SetInputContextHandler(NULL);
222 IMEBridge::Get()->SetCandidateWindowHandler(NULL);
225 IN_PROC_BROWSER_TEST_P(InputMethodEngineBrowserTest,
227 LoadTestInputMethod();
229 InputMethodManager::Get()->ChangeInputMethod(kAPIArgumentIMEID);
231 scoped_ptr<MockIMEInputContextHandler> mock_input_context(
232 new MockIMEInputContextHandler());
233 scoped_ptr<MockIMECandidateWindowHandler> mock_candidate_window(
234 new MockIMECandidateWindowHandler());
236 IMEBridge::Get()->SetInputContextHandler(mock_input_context.get());
237 IMEBridge::Get()->SetCandidateWindowHandler(mock_candidate_window.get());
239 IMEEngineHandlerInterface* engine_handler =
240 IMEBridge::Get()->GetCurrentEngineHandler();
241 ASSERT_TRUE(engine_handler);
243 extensions::ExtensionHost* host =
244 extensions::ExtensionSystem::Get(profile())
246 ->GetBackgroundHostForExtension(extension_->id());
249 engine_handler->Enable("APIArgumentIME");
250 IMEEngineHandlerInterface::InputContext context(ui::TEXT_INPUT_TYPE_TEXT,
251 ui::TEXT_INPUT_MODE_DEFAULT);
252 engine_handler->FocusIn(context);
255 SCOPED_TRACE("KeyDown, Ctrl:No, alt:No, Shift:No, Caps:No");
256 KeyEventDoneCallback callback(false);
257 const std::string expected_value =
258 "onKeyEvent::keydown:a:KeyA:false:false:false:false";
259 ExtensionTestMessageListener keyevent_listener(expected_value, false);
261 ui::KeyEvent key_event(
262 ui::ET_KEY_PRESSED, ui::VKEY_A, "KeyA", ui::EF_NONE);
263 engine_handler->ProcessKeyEvent(key_event,
264 base::Bind(&KeyEventDoneCallback::Run,
265 base::Unretained(&callback)));
266 ASSERT_TRUE(keyevent_listener.WaitUntilSatisfied());
267 EXPECT_TRUE(keyevent_listener.was_satisfied());
268 callback.WaitUntilCalled();
271 SCOPED_TRACE("KeyDown, Ctrl:Yes, alt:No, Shift:No, Caps:No");
272 KeyEventDoneCallback callback(false);
273 const std::string expected_value =
274 "onKeyEvent::keydown:a:KeyA:true:false:false:false";
275 ExtensionTestMessageListener keyevent_listener(expected_value, false);
277 ui::KeyEvent key_event(ui::ET_KEY_PRESSED,
280 ui::EF_CONTROL_DOWN);
281 engine_handler->ProcessKeyEvent(key_event,
282 base::Bind(&KeyEventDoneCallback::Run,
283 base::Unretained(&callback)));
284 ASSERT_TRUE(keyevent_listener.WaitUntilSatisfied());
285 EXPECT_TRUE(keyevent_listener.was_satisfied());
286 callback.WaitUntilCalled();
289 SCOPED_TRACE("KeyDown, Ctrl:No, alt:Yes, Shift:No, Caps:No");
290 KeyEventDoneCallback callback(false);
291 const std::string expected_value =
292 "onKeyEvent::keydown:a:KeyA:false:true:false:false";
293 ExtensionTestMessageListener keyevent_listener(expected_value, false);
295 ui::KeyEvent key_event(ui::ET_KEY_PRESSED,
299 engine_handler->ProcessKeyEvent(key_event,
300 base::Bind(&KeyEventDoneCallback::Run,
301 base::Unretained(&callback)));
302 ASSERT_TRUE(keyevent_listener.WaitUntilSatisfied());
303 EXPECT_TRUE(keyevent_listener.was_satisfied());
304 callback.WaitUntilCalled();
307 SCOPED_TRACE("KeyDown, Ctrl:No, alt:No, Shift:Yes, Caps:No");
308 KeyEventDoneCallback callback(false);
309 const std::string expected_value =
310 "onKeyEvent::keydown:A:KeyA:false:false:true:false";
311 ExtensionTestMessageListener keyevent_listener(expected_value, false);
313 ui::KeyEvent key_event(ui::ET_KEY_PRESSED,
317 engine_handler->ProcessKeyEvent(key_event,
318 base::Bind(&KeyEventDoneCallback::Run,
319 base::Unretained(&callback)));
320 ASSERT_TRUE(keyevent_listener.WaitUntilSatisfied());
321 EXPECT_TRUE(keyevent_listener.was_satisfied());
322 callback.WaitUntilCalled();
325 SCOPED_TRACE("KeyDown, Ctrl:No, alt:No, Shift:No, Caps:Yes");
326 KeyEventDoneCallback callback(false);
327 const std::string expected_value =
328 "onKeyEvent::keydown:A:KeyA:false:false:false:true";
329 ExtensionTestMessageListener keyevent_listener(expected_value, false);
331 ui::KeyEvent key_event(ui::ET_KEY_PRESSED,
334 ui::EF_CAPS_LOCK_DOWN);
335 engine_handler->ProcessKeyEvent(key_event,
336 base::Bind(&KeyEventDoneCallback::Run,
337 base::Unretained(&callback)));
338 ASSERT_TRUE(keyevent_listener.WaitUntilSatisfied());
339 EXPECT_TRUE(keyevent_listener.was_satisfied());
340 callback.WaitUntilCalled();
343 SCOPED_TRACE("KeyDown, Ctrl:Yes, alt:Yes, Shift:No, Caps:No");
344 KeyEventDoneCallback callback(false);
345 const std::string expected_value =
346 "onKeyEvent::keydown:a:KeyA:true:true:false:false";
347 ExtensionTestMessageListener keyevent_listener(expected_value, false);
349 ui::KeyEvent key_event(ui::ET_KEY_PRESSED,
352 ui::EF_ALT_DOWN | ui::EF_CONTROL_DOWN);
353 engine_handler->ProcessKeyEvent(key_event,
354 base::Bind(&KeyEventDoneCallback::Run,
355 base::Unretained(&callback)));
356 ASSERT_TRUE(keyevent_listener.WaitUntilSatisfied());
357 EXPECT_TRUE(keyevent_listener.was_satisfied());
358 callback.WaitUntilCalled();
361 SCOPED_TRACE("KeyDown, Ctrl:No, alt:No, Shift:Yes, Caps:Yes");
362 KeyEventDoneCallback callback(false);
363 const std::string expected_value =
364 "onKeyEvent::keydown:a:KeyA:false:false:true:true";
365 ExtensionTestMessageListener keyevent_listener(expected_value, false);
367 ui::KeyEvent key_event(ui::ET_KEY_PRESSED,
370 ui::EF_SHIFT_DOWN | ui::EF_CAPS_LOCK_DOWN);
371 engine_handler->ProcessKeyEvent(key_event,
372 base::Bind(&KeyEventDoneCallback::Run,
373 base::Unretained(&callback)));
374 ASSERT_TRUE(keyevent_listener.WaitUntilSatisfied());
375 EXPECT_TRUE(keyevent_listener.was_satisfied());
376 callback.WaitUntilCalled();
380 ui::KeyboardCode keycode;
383 } kMediaKeyCases[] = {
384 { ui::VKEY_BROWSER_BACK, "BrowserBack", "HistoryBack" },
385 { ui::VKEY_BROWSER_FORWARD, "BrowserForward", "HistoryForward" },
386 { ui::VKEY_BROWSER_REFRESH, "BrowserRefresh", "BrowserRefresh" },
387 { ui::VKEY_MEDIA_LAUNCH_APP2, "ChromeOSFullscreen", "ChromeOSFullscreen" },
388 { ui::VKEY_MEDIA_LAUNCH_APP1,
389 "ChromeOSSwitchWindow", "ChromeOSSwitchWindow" },
390 { ui::VKEY_BRIGHTNESS_DOWN, "BrightnessDown", "BrightnessDown" },
391 { ui::VKEY_BRIGHTNESS_UP, "BrightnessUp", "BrightnessUp" },
392 { ui::VKEY_VOLUME_MUTE, "VolumeMute", "AudioVolumeMute" },
393 { ui::VKEY_VOLUME_DOWN, "VolumeDown", "AudioVolumeDown" },
394 { ui::VKEY_VOLUME_UP, "VolumeUp", "AudioVolumeUp" },
395 { ui::VKEY_F1, "F1", "HistoryBack" },
396 { ui::VKEY_F2, "F2", "HistoryForward" },
397 { ui::VKEY_F3, "F3", "BrowserRefresh" },
398 { ui::VKEY_F4, "F4", "ChromeOSFullscreen" },
399 { ui::VKEY_F5, "F5", "ChromeOSSwitchWindow" },
400 { ui::VKEY_F6, "F6", "BrightnessDown" },
401 { ui::VKEY_F7, "F7", "BrightnessUp" },
402 { ui::VKEY_F8, "F8", "AudioVolumeMute" },
403 { ui::VKEY_F9, "F9", "AudioVolumeDown" },
404 { ui::VKEY_F10, "F10", "AudioVolumeUp" },
406 for (size_t i = 0; i < arraysize(kMediaKeyCases); ++i) {
407 SCOPED_TRACE(std::string("KeyDown, ") + kMediaKeyCases[i].code);
408 KeyEventDoneCallback callback(false);
409 const std::string expected_value =
410 base::StringPrintf("onKeyEvent::keydown:%s:%s:false:false:false:false",
411 kMediaKeyCases[i].key, kMediaKeyCases[i].code);
412 ExtensionTestMessageListener keyevent_listener(expected_value, false);
414 ui::KeyEvent key_event(ui::ET_KEY_PRESSED,
415 kMediaKeyCases[i].keycode,
416 kMediaKeyCases[i].code,
418 engine_handler->ProcessKeyEvent(key_event,
419 base::Bind(&KeyEventDoneCallback::Run,
420 base::Unretained(&callback)));
421 ASSERT_TRUE(keyevent_listener.WaitUntilSatisfied());
422 EXPECT_TRUE(keyevent_listener.was_satisfied());
423 callback.WaitUntilCalled();
425 // TODO(nona): Add browser tests for other API as well.
427 SCOPED_TRACE("commitText test");
428 mock_input_context->Reset();
429 mock_candidate_window->Reset();
431 const char commit_text_test_script[] =
432 "chrome.input.ime.commitText({"
433 " contextID: engineBridge.getFocusedContextID().contextID,"
434 " text:'COMMIT_TEXT'"
437 ASSERT_TRUE(content::ExecuteScript(host->host_contents(),
438 commit_text_test_script));
439 EXPECT_EQ(1, mock_input_context->commit_text_call_count());
440 EXPECT_EQ("COMMIT_TEXT", mock_input_context->last_commit_text());
443 SCOPED_TRACE("sendKeyEvents test");
444 mock_input_context->Reset();
445 mock_candidate_window->Reset();
447 const char send_key_events_test_script[] =
448 "chrome.input.ime.sendKeyEvents({"
449 " contextID: engineBridge.getFocusedContextID().contextID,"
463 ExtensionTestMessageListener keyevent_listener_down(
464 std::string("onKeyEvent:") + kExtensionID +
465 ":keydown:z:KeyZ:false:false:false:false",
467 ExtensionTestMessageListener keyevent_listener_up(
468 std::string("onKeyEvent:") + kExtensionID +
469 ":keyup:z:KeyZ:false:false:false:false",
472 ASSERT_TRUE(content::ExecuteScript(host->host_contents(),
473 send_key_events_test_script));
475 ASSERT_TRUE(keyevent_listener_down.WaitUntilSatisfied());
476 EXPECT_TRUE(keyevent_listener_down.was_satisfied());
477 ASSERT_TRUE(keyevent_listener_up.WaitUntilSatisfied());
478 EXPECT_TRUE(keyevent_listener_up.was_satisfied());
481 SCOPED_TRACE("sendKeyEvents test with keyCode");
482 mock_input_context->Reset();
483 mock_candidate_window->Reset();
485 const char send_key_events_test_script[] =
486 "chrome.input.ime.sendKeyEvents({"
487 " contextID: engineBridge.getFocusedContextID().contextID,"
503 ExtensionTestMessageListener keyevent_listener_down(
504 std::string("onKeyEvent:") + kExtensionID +
505 ":keydown:a:KeyQ:false:false:false:false",
507 ExtensionTestMessageListener keyevent_listener_up(
508 std::string("onKeyEvent:") + kExtensionID +
509 ":keyup:a:KeyQ:false:false:false:false",
512 ASSERT_TRUE(content::ExecuteScript(host->host_contents(),
513 send_key_events_test_script));
515 ASSERT_TRUE(keyevent_listener_down.WaitUntilSatisfied());
516 EXPECT_TRUE(keyevent_listener_down.was_satisfied());
517 ASSERT_TRUE(keyevent_listener_up.WaitUntilSatisfied());
518 EXPECT_TRUE(keyevent_listener_up.was_satisfied());
521 SCOPED_TRACE("setComposition test");
522 mock_input_context->Reset();
523 mock_candidate_window->Reset();
525 const char set_composition_test_script[] =
526 "chrome.input.ime.setComposition({"
527 " contextID: engineBridge.getFocusedContextID().contextID,"
528 " text:'COMPOSITION_TEXT',"
533 " style: 'underline'"
537 " style: 'doubleUnderline'"
541 ASSERT_TRUE(content::ExecuteScript(host->host_contents(),
542 set_composition_test_script));
543 EXPECT_EQ(1, mock_input_context->update_preedit_text_call_count());
546 mock_input_context->last_update_composition_arg().cursor_pos);
547 EXPECT_TRUE(mock_input_context->last_update_composition_arg().is_visible);
549 const CompositionText& composition_text =
550 mock_input_context->last_update_composition_arg().composition_text;
551 EXPECT_EQ(base::UTF8ToUTF16("COMPOSITION_TEXT"), composition_text.text());
552 const std::vector<CompositionText::UnderlineAttribute>& underlines =
553 composition_text.underline_attributes();
555 ASSERT_EQ(2U, underlines.size());
556 EXPECT_EQ(CompositionText::COMPOSITION_TEXT_UNDERLINE_SINGLE,
558 EXPECT_EQ(0U, underlines[0].start_index);
559 EXPECT_EQ(5U, underlines[0].end_index);
561 EXPECT_EQ(CompositionText::COMPOSITION_TEXT_UNDERLINE_DOUBLE,
563 EXPECT_EQ(6U, underlines[1].start_index);
564 EXPECT_EQ(10U, underlines[1].end_index);
567 SCOPED_TRACE("clearComposition test");
568 mock_input_context->Reset();
569 mock_candidate_window->Reset();
571 const char commite_text_test_script[] =
572 "chrome.input.ime.clearComposition({"
573 " contextID: engineBridge.getFocusedContextID().contextID,"
576 ASSERT_TRUE(content::ExecuteScript(host->host_contents(),
577 commite_text_test_script));
578 EXPECT_EQ(1, mock_input_context->update_preedit_text_call_count());
580 mock_input_context->last_update_composition_arg().is_visible);
581 const CompositionText& composition_text =
582 mock_input_context->last_update_composition_arg().composition_text;
583 EXPECT_TRUE(composition_text.text().empty());
586 SCOPED_TRACE("setCandidateWindowProperties:visibility test");
587 mock_input_context->Reset();
588 mock_candidate_window->Reset();
590 const char set_candidate_window_properties_test_script[] =
591 "chrome.input.ime.setCandidateWindowProperties({"
592 " engineID: engineBridge.getActiveEngineID(),"
597 ASSERT_TRUE(content::ExecuteScript(
598 host->host_contents(),
599 set_candidate_window_properties_test_script));
600 EXPECT_EQ(1, mock_candidate_window->update_lookup_table_call_count());
602 mock_candidate_window->last_update_lookup_table_arg().is_visible);
605 SCOPED_TRACE("setCandidateWindowProperties:cursor_visibility test");
606 mock_input_context->Reset();
607 mock_candidate_window->Reset();
609 const char set_candidate_window_properties_test_script[] =
610 "chrome.input.ime.setCandidateWindowProperties({"
611 " engineID: engineBridge.getActiveEngineID(),"
613 " cursorVisible: true,"
616 ASSERT_TRUE(content::ExecuteScript(
617 host->host_contents(),
618 set_candidate_window_properties_test_script));
619 EXPECT_EQ(1, mock_candidate_window->update_lookup_table_call_count());
621 // window visibility is kept as before.
623 mock_candidate_window->last_update_lookup_table_arg().is_visible);
625 const ui::CandidateWindow& table =
626 mock_candidate_window->last_update_lookup_table_arg().lookup_table;
627 EXPECT_TRUE(table.is_cursor_visible());
630 SCOPED_TRACE("setCandidateWindowProperties:vertical test");
631 mock_input_context->Reset();
632 mock_candidate_window->Reset();
634 const char set_candidate_window_properties_test_script[] =
635 "chrome.input.ime.setCandidateWindowProperties({"
636 " engineID: engineBridge.getActiveEngineID(),"
641 ASSERT_TRUE(content::ExecuteScript(
642 host->host_contents(),
643 set_candidate_window_properties_test_script));
644 EXPECT_EQ(1, mock_candidate_window->update_lookup_table_call_count());
646 // window visibility is kept as before.
648 mock_candidate_window->last_update_lookup_table_arg().is_visible);
650 const ui::CandidateWindow& table =
651 mock_candidate_window->last_update_lookup_table_arg().lookup_table;
653 // cursor visibility is kept as before.
654 EXPECT_TRUE(table.is_cursor_visible());
656 EXPECT_EQ(ui::CandidateWindow::VERTICAL, table.orientation());
659 SCOPED_TRACE("setCandidateWindowProperties:pageSize test");
660 mock_input_context->Reset();
661 mock_candidate_window->Reset();
663 const char set_candidate_window_properties_test_script[] =
664 "chrome.input.ime.setCandidateWindowProperties({"
665 " engineID: engineBridge.getActiveEngineID(),"
670 ASSERT_TRUE(content::ExecuteScript(
671 host->host_contents(),
672 set_candidate_window_properties_test_script));
673 EXPECT_EQ(1, mock_candidate_window->update_lookup_table_call_count());
675 // window visibility is kept as before.
677 mock_candidate_window->last_update_lookup_table_arg().is_visible);
679 const ui::CandidateWindow& table =
680 mock_candidate_window->last_update_lookup_table_arg().lookup_table;
682 // cursor visibility is kept as before.
683 EXPECT_TRUE(table.is_cursor_visible());
685 // oritantation is kept as before.
686 EXPECT_EQ(ui::CandidateWindow::VERTICAL, table.orientation());
688 EXPECT_EQ(7U, table.page_size());
691 SCOPED_TRACE("setCandidateWindowProperties:auxTextVisibility test");
692 mock_input_context->Reset();
693 mock_candidate_window->Reset();
695 const char set_candidate_window_properties_test_script[] =
696 "chrome.input.ime.setCandidateWindowProperties({"
697 " engineID: engineBridge.getActiveEngineID(),"
699 " auxiliaryTextVisible: true"
702 ASSERT_TRUE(content::ExecuteScript(
703 host->host_contents(),
704 set_candidate_window_properties_test_script));
705 EXPECT_EQ(1, mock_candidate_window->update_lookup_table_call_count());
707 const ui::CandidateWindow& table =
708 mock_candidate_window->last_update_lookup_table_arg().lookup_table;
709 EXPECT_TRUE(table.is_auxiliary_text_visible());
712 SCOPED_TRACE("setCandidateWindowProperties:auxText test");
713 mock_input_context->Reset();
714 mock_candidate_window->Reset();
716 const char set_candidate_window_properties_test_script[] =
717 "chrome.input.ime.setCandidateWindowProperties({"
718 " engineID: engineBridge.getActiveEngineID(),"
720 " auxiliaryText: 'AUXILIARY_TEXT'"
723 ASSERT_TRUE(content::ExecuteScript(
724 host->host_contents(),
725 set_candidate_window_properties_test_script));
726 EXPECT_EQ(1, mock_candidate_window->update_lookup_table_call_count());
728 // aux text visibility is kept as before.
729 const ui::CandidateWindow& table =
730 mock_candidate_window->last_update_lookup_table_arg().lookup_table;
731 EXPECT_TRUE(table.is_auxiliary_text_visible());
732 EXPECT_EQ("AUXILIARY_TEXT", table.auxiliary_text());
735 SCOPED_TRACE("setCandidates test");
736 mock_input_context->Reset();
737 mock_candidate_window->Reset();
739 const char set_candidates_test_script[] =
740 "chrome.input.ime.setCandidates({"
741 " contextID: engineBridge.getFocusedContextID().contextID,"
743 " candidate: 'CANDIDATE_1',"
746 " candidate: 'CANDIDATE_2',"
750 " candidate: 'CANDIDATE_3',"
753 " annotation: 'ANNOTACTION_3'"
755 " candidate: 'CANDIDATE_4',"
758 " annotation: 'ANNOTACTION_4',"
765 ASSERT_TRUE(content::ExecuteScript(host->host_contents(),
766 set_candidates_test_script));
768 // window visibility is kept as before.
770 mock_candidate_window->last_update_lookup_table_arg().is_visible);
772 const ui::CandidateWindow& table =
773 mock_candidate_window->last_update_lookup_table_arg().lookup_table;
775 // cursor visibility is kept as before.
776 EXPECT_TRUE(table.is_cursor_visible());
778 // oritantation is kept as before.
779 EXPECT_EQ(ui::CandidateWindow::VERTICAL, table.orientation());
781 // page size is kept as before.
782 EXPECT_EQ(7U, table.page_size());
784 ASSERT_EQ(4U, table.candidates().size());
786 EXPECT_EQ(base::UTF8ToUTF16("CANDIDATE_1"),
787 table.candidates().at(0).value);
789 EXPECT_EQ(base::UTF8ToUTF16("CANDIDATE_2"),
790 table.candidates().at(1).value);
791 EXPECT_EQ(base::UTF8ToUTF16("LABEL_2"), table.candidates().at(1).label);
793 EXPECT_EQ(base::UTF8ToUTF16("CANDIDATE_3"),
794 table.candidates().at(2).value);
795 EXPECT_EQ(base::UTF8ToUTF16("LABEL_3"), table.candidates().at(2).label);
796 EXPECT_EQ(base::UTF8ToUTF16("ANNOTACTION_3"),
797 table.candidates().at(2).annotation);
799 EXPECT_EQ(base::UTF8ToUTF16("CANDIDATE_4"),
800 table.candidates().at(3).value);
801 EXPECT_EQ(base::UTF8ToUTF16("LABEL_4"), table.candidates().at(3).label);
802 EXPECT_EQ(base::UTF8ToUTF16("ANNOTACTION_4"),
803 table.candidates().at(3).annotation);
804 EXPECT_EQ(base::UTF8ToUTF16("TITLE_4"),
805 table.candidates().at(3).description_title);
806 EXPECT_EQ(base::UTF8ToUTF16("BODY_4"),
807 table.candidates().at(3).description_body);
810 SCOPED_TRACE("setCursorPosition test");
811 mock_input_context->Reset();
812 mock_candidate_window->Reset();
814 const char set_cursor_position_test_script[] =
815 "chrome.input.ime.setCursorPosition({"
816 " contextID: engineBridge.getFocusedContextID().contextID,"
819 ASSERT_TRUE(content::ExecuteScript(
820 host->host_contents(), set_cursor_position_test_script));
821 EXPECT_EQ(1, mock_candidate_window->update_lookup_table_call_count());
823 // window visibility is kept as before.
825 mock_candidate_window->last_update_lookup_table_arg().is_visible);
827 const ui::CandidateWindow& table =
828 mock_candidate_window->last_update_lookup_table_arg().lookup_table;
830 // cursor visibility is kept as before.
831 EXPECT_TRUE(table.is_cursor_visible());
833 // oritantation is kept as before.
834 EXPECT_EQ(ui::CandidateWindow::VERTICAL, table.orientation());
836 // page size is kept as before.
837 EXPECT_EQ(7U, table.page_size());
839 // candidates are same as before.
840 ASSERT_EQ(4U, table.candidates().size());
842 // Candidate ID == 2 is 1 in index.
843 EXPECT_EQ(1U, table.cursor_position());
846 SCOPED_TRACE("setMenuItem test");
847 mock_input_context->Reset();
848 mock_candidate_window->Reset();
850 const char set_menu_item_test_script[] =
851 "chrome.input.ime.setMenuItems({"
852 " engineID: engineBridge.getActiveEngineID(),"
870 " style: 'separator',"
875 ASSERT_TRUE(content::ExecuteScript(
876 host->host_contents(), set_menu_item_test_script));
878 const ash::ime::InputMethodMenuItemList& props =
879 ash::ime::InputMethodMenuManager::GetInstance()->
880 GetCurrentInputMethodMenuItemList();
881 ASSERT_EQ(5U, props.size());
883 EXPECT_EQ("ID0", props[0].key);
884 EXPECT_EQ("ID1", props[1].key);
885 EXPECT_EQ("ID2", props[2].key);
886 EXPECT_EQ("ID3", props[3].key);
887 EXPECT_EQ("ID4", props[4].key);
889 EXPECT_EQ("LABEL1", props[1].label);
890 EXPECT_EQ("LABEL2", props[2].label);
891 EXPECT_EQ("LABEL3", props[3].label);
892 EXPECT_EQ("LABEL4", props[4].label);
894 EXPECT_TRUE(props[2].is_selection_item);
895 // TODO(nona): Add tests for style: ["toggle" and "separator"]
896 // and visible:, when implement them.
898 EXPECT_TRUE(props[4].is_selection_item_checked);
901 SCOPED_TRACE("deleteSurroundingText test");
902 mock_input_context->Reset();
903 mock_candidate_window->Reset();
905 const char delete_surrounding_text_test_script[] =
906 "chrome.input.ime.deleteSurroundingText({"
907 " engineID: engineBridge.getActiveEngineID(),"
908 " contextID: engineBridge.getFocusedContextID().contextID,"
912 ASSERT_TRUE(content::ExecuteScript(
913 host->host_contents(), delete_surrounding_text_test_script));
915 EXPECT_EQ(1, mock_input_context->delete_surrounding_text_call_count());
916 EXPECT_EQ(5, mock_input_context->last_delete_surrounding_text_arg().offset);
918 mock_input_context->last_delete_surrounding_text_arg().length);
921 SCOPED_TRACE("onFocus test");
922 mock_input_context->Reset();
923 mock_candidate_window->Reset();
926 ExtensionTestMessageListener focus_listener("onFocus:text", false);
927 IMEEngineHandlerInterface::InputContext context(
928 ui::TEXT_INPUT_TYPE_TEXT, ui::TEXT_INPUT_MODE_DEFAULT);
929 engine_handler->FocusIn(context);
930 ASSERT_TRUE(focus_listener.WaitUntilSatisfied());
931 ASSERT_TRUE(focus_listener.was_satisfied());
934 ExtensionTestMessageListener focus_listener("onFocus:search", false);
935 IMEEngineHandlerInterface::InputContext context(
936 ui::TEXT_INPUT_TYPE_SEARCH, ui::TEXT_INPUT_MODE_DEFAULT);
937 engine_handler->FocusIn(context);
938 ASSERT_TRUE(focus_listener.WaitUntilSatisfied());
939 ASSERT_TRUE(focus_listener.was_satisfied());
942 ExtensionTestMessageListener focus_listener("onFocus:tel", false);
943 IMEEngineHandlerInterface::InputContext context(
944 ui::TEXT_INPUT_TYPE_TELEPHONE, ui::TEXT_INPUT_MODE_DEFAULT);
945 engine_handler->FocusIn(context);
946 ASSERT_TRUE(focus_listener.WaitUntilSatisfied());
947 ASSERT_TRUE(focus_listener.was_satisfied());
950 ExtensionTestMessageListener focus_listener("onFocus:url", false);
951 IMEEngineHandlerInterface::InputContext context(
952 ui::TEXT_INPUT_TYPE_URL, ui::TEXT_INPUT_MODE_DEFAULT);
953 engine_handler->FocusIn(context);
954 ASSERT_TRUE(focus_listener.WaitUntilSatisfied());
955 ASSERT_TRUE(focus_listener.was_satisfied());
958 ExtensionTestMessageListener focus_listener("onFocus:email", false);
959 IMEEngineHandlerInterface::InputContext context(
960 ui::TEXT_INPUT_TYPE_EMAIL, ui::TEXT_INPUT_MODE_DEFAULT);
961 engine_handler->FocusIn(context);
962 ASSERT_TRUE(focus_listener.WaitUntilSatisfied());
963 ASSERT_TRUE(focus_listener.was_satisfied());
966 ExtensionTestMessageListener focus_listener("onFocus:number", false);
967 IMEEngineHandlerInterface::InputContext context(
968 ui::TEXT_INPUT_TYPE_NUMBER, ui::TEXT_INPUT_MODE_DEFAULT);
969 engine_handler->FocusIn(context);
970 ASSERT_TRUE(focus_listener.WaitUntilSatisfied());
971 ASSERT_TRUE(focus_listener.was_satisfied());
975 IMEBridge::Get()->SetInputContextHandler(NULL);
976 IMEBridge::Get()->SetCandidateWindowHandler(NULL);
980 } // namespace input_method
981 } // namespace chromeos