Merge Chromium + Blink git repositories
[chromium-blink-merge.git] / chrome / browser / chromeos / input_method / input_method_engine_browsertests.cc
blobbe373fb8b928ccf6ce716f62217c84603a9417d9
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 "base/bind_helpers.h"
6 #include "base/strings/stringprintf.h"
7 #include "base/strings/utf_string_conversions.h"
8 #include "chrome/browser/extensions/extension_browsertest.h"
9 #include "content/public/test/browser_test_utils.h"
10 #include "content/public/test/test_utils.h"
11 #include "extensions/browser/process_manager.h"
12 #include "extensions/common/manifest_handlers/background_info.h"
13 #include "extensions/test/extension_test_message_listener.h"
14 #include "ui/base/ime/chromeos/component_extension_ime_manager.h"
15 #include "ui/base/ime/chromeos/composition_text_chromeos.h"
16 #include "ui/base/ime/chromeos/extension_ime_util.h"
17 #include "ui/base/ime/chromeos/ime_bridge.h"
18 #include "ui/base/ime/chromeos/input_method_descriptor.h"
19 #include "ui/base/ime/chromeos/input_method_manager.h"
20 #include "ui/base/ime/chromeos/mock_ime_candidate_window_handler.h"
21 #include "ui/base/ime/chromeos/mock_ime_input_context_handler.h"
22 #include "ui/base/ime/text_input_flags.h"
23 #include "ui/chromeos/ime/input_method_menu_item.h"
24 #include "ui/chromeos/ime/input_method_menu_manager.h"
25 #include "ui/events/event.h"
26 #include "ui/events/keycodes/dom/dom_code.h"
27 #include "ui/events/keycodes/dom/keycode_converter.h"
29 namespace chromeos {
30 namespace input_method {
31 namespace {
33 const char kIdentityIMEID[] =
34 "_ext_ime_iafoklpfplgfnoimmaejoeondnjnlcfpIdentityIME";
35 const char kToUpperIMEID[] =
36 "_ext_ime_iafoklpfplgfnoimmaejoeondnjnlcfpToUpperIME";
37 const char kAPIArgumentIMEID[] =
38 "_ext_ime_iafoklpfplgfnoimmaejoeondnjnlcfpAPIArgumentIME";
39 const char kExtensionID[] = "iafoklpfplgfnoimmaejoeondnjnlcfp";
41 // InputMethod extension should work on 1)normal extension, 2)normal extension
42 // in incognito mode 3)component extension.
43 enum TestType {
44 kTestTypeNormal = 0,
45 kTestTypeIncognito = 1,
46 kTestTypeComponent = 2,
49 class InputMethodEngineBrowserTest
50 : public ExtensionBrowserTest,
51 public ::testing::WithParamInterface<TestType> {
52 public:
53 InputMethodEngineBrowserTest()
54 : ExtensionBrowserTest() {}
55 virtual ~InputMethodEngineBrowserTest() {}
57 void SetUpInProcessBrowserTestFixture() override {
58 ExtensionBrowserTest::SetUpInProcessBrowserTestFixture();
61 void TearDownInProcessBrowserTestFixture() override { extension_ = NULL; }
63 protected:
64 void LoadTestInputMethod() {
65 // This will load "chrome/test/data/extensions/input_ime"
66 ExtensionTestMessageListener ime_ready_listener("ReadyToUseImeEvent",
67 false);
68 extension_ = LoadExtensionWithType("input_ime", GetParam());
69 ASSERT_TRUE(extension_);
70 ASSERT_TRUE(ime_ready_listener.WaitUntilSatisfied());
72 // Extension IMEs are not enabled by default.
73 std::vector<std::string> extension_ime_ids;
74 extension_ime_ids.push_back(kIdentityIMEID);
75 extension_ime_ids.push_back(kToUpperIMEID);
76 extension_ime_ids.push_back(kAPIArgumentIMEID);
77 InputMethodManager::Get()->GetActiveIMEState()->SetEnabledExtensionImes(
78 &extension_ime_ids);
80 InputMethodDescriptors extension_imes;
81 InputMethodManager::Get()->GetActiveIMEState()->GetInputMethodExtensions(
82 &extension_imes);
84 // Test IME has two input methods, thus InputMethodManager should have two
85 // extension IME.
86 // Note: Even extension is loaded by LoadExtensionAsComponent as above, the
87 // IME does not managed by ComponentExtensionIMEManager or it's id won't
88 // start with __comp__. The component extension IME is whitelisted and
89 // managed by ComponentExtensionIMEManager, but its framework is same as
90 // normal extension IME.
91 EXPECT_EQ(3U, extension_imes.size());
94 const extensions::Extension* LoadExtensionWithType(
95 const std::string& extension_name, TestType type) {
96 switch (type) {
97 case kTestTypeNormal:
98 return LoadExtension(test_data_dir_.AppendASCII(extension_name));
99 case kTestTypeIncognito:
100 return LoadExtensionIncognito(
101 test_data_dir_.AppendASCII(extension_name));
102 case kTestTypeComponent:
103 return LoadExtensionAsComponent(
104 test_data_dir_.AppendASCII(extension_name));
106 NOTREACHED();
107 return NULL;
110 const extensions::Extension* extension_;
113 class KeyEventDoneCallback {
114 public:
115 explicit KeyEventDoneCallback(bool expected_argument)
116 : expected_argument_(expected_argument),
117 is_called_(false) {}
118 ~KeyEventDoneCallback() {}
120 void Run(bool consumed) {
121 if (consumed == expected_argument_) {
122 base::MessageLoop::current()->Quit();
123 is_called_ = true;
127 void WaitUntilCalled() {
128 while (!is_called_)
129 content::RunMessageLoop();
132 private:
133 bool expected_argument_;
134 bool is_called_;
136 DISALLOW_COPY_AND_ASSIGN(KeyEventDoneCallback);
139 INSTANTIATE_TEST_CASE_P(InputMethodEngineBrowserTest,
140 InputMethodEngineBrowserTest,
141 ::testing::Values(kTestTypeNormal));
142 INSTANTIATE_TEST_CASE_P(InputMethodEngineIncognitoBrowserTest,
143 InputMethodEngineBrowserTest,
144 ::testing::Values(kTestTypeIncognito));
145 INSTANTIATE_TEST_CASE_P(InputMethodEngineComponentExtensionBrowserTest,
146 InputMethodEngineBrowserTest,
147 ::testing::Values(kTestTypeComponent));
149 IN_PROC_BROWSER_TEST_P(InputMethodEngineBrowserTest,
150 BasicScenarioTest) {
151 LoadTestInputMethod();
153 InputMethodManager::Get()->GetActiveIMEState()->ChangeInputMethod(
154 kIdentityIMEID, false /* show_message */);
156 scoped_ptr<MockIMEInputContextHandler> mock_input_context(
157 new MockIMEInputContextHandler());
158 scoped_ptr<MockIMECandidateWindowHandler> mock_candidate_window(
159 new MockIMECandidateWindowHandler());
161 IMEBridge::Get()->SetInputContextHandler(mock_input_context.get());
162 IMEBridge::Get()->SetCandidateWindowHandler(mock_candidate_window.get());
164 IMEEngineHandlerInterface* engine_handler =
165 IMEBridge::Get()->GetCurrentEngineHandler();
166 ASSERT_TRUE(engine_handler);
168 // onActivate event should be fired if Enable function is called.
169 ExtensionTestMessageListener activated_listener("onActivate", false);
170 engine_handler->Enable("IdentityIME");
171 ASSERT_TRUE(activated_listener.WaitUntilSatisfied());
172 ASSERT_TRUE(activated_listener.was_satisfied());
174 // onFocus event should be fired if FocusIn function is called.
175 ExtensionTestMessageListener focus_listener("onFocus:text", false);
176 IMEEngineHandlerInterface::InputContext context(ui::TEXT_INPUT_TYPE_TEXT,
177 ui::TEXT_INPUT_MODE_DEFAULT,
178 ui::TEXT_INPUT_FLAG_NONE);
179 engine_handler->FocusIn(context);
180 ASSERT_TRUE(focus_listener.WaitUntilSatisfied());
181 ASSERT_TRUE(focus_listener.was_satisfied());
183 // onKeyEvent should be fired if ProcessKeyEvent is called.
184 KeyEventDoneCallback callback(false); // EchoBackIME doesn't consume keys.
185 ExtensionTestMessageListener keyevent_listener("onKeyEvent", false);
186 ui::KeyEvent key_event(ui::ET_KEY_PRESSED, ui::VKEY_A, ui::EF_NONE);
187 engine_handler->ProcessKeyEvent(key_event,
188 base::Bind(&KeyEventDoneCallback::Run,
189 base::Unretained(&callback)));
190 ASSERT_TRUE(keyevent_listener.WaitUntilSatisfied());
191 ASSERT_TRUE(keyevent_listener.was_satisfied());
192 callback.WaitUntilCalled();
194 // onSurroundingTextChange should be fired if SetSurroundingText is called.
195 ExtensionTestMessageListener surrounding_text_listener(
196 "onSurroundingTextChanged", false);
197 engine_handler->SetSurroundingText("text", // Surrounding text.
198 0, // focused position.
199 1, // anchor position.
200 0); // offset position.
201 ASSERT_TRUE(surrounding_text_listener.WaitUntilSatisfied());
202 ASSERT_TRUE(surrounding_text_listener.was_satisfied());
204 // onMenuItemActivated should be fired if PropertyActivate is called.
205 ExtensionTestMessageListener property_listener("onMenuItemActivated", false);
206 engine_handler->PropertyActivate("property_name");
207 ASSERT_TRUE(property_listener.WaitUntilSatisfied());
208 ASSERT_TRUE(property_listener.was_satisfied());
210 // onReset should be fired if Reset is called.
211 ExtensionTestMessageListener reset_listener("onReset", false);
212 engine_handler->Reset();
213 ASSERT_TRUE(reset_listener.WaitUntilSatisfied());
214 ASSERT_TRUE(reset_listener.was_satisfied());
216 // onBlur should be fired if FocusOut is called.
217 ExtensionTestMessageListener blur_listener("onBlur", false);
218 engine_handler->FocusOut();
219 ASSERT_TRUE(blur_listener.WaitUntilSatisfied());
220 ASSERT_TRUE(blur_listener.was_satisfied());
222 // onDeactivated should be fired if Disable is called.
223 ExtensionTestMessageListener disabled_listener("onDeactivated", false);
224 engine_handler->Disable();
225 ASSERT_TRUE(disabled_listener.WaitUntilSatisfied());
226 ASSERT_TRUE(disabled_listener.was_satisfied());
228 IMEBridge::Get()->SetInputContextHandler(NULL);
229 IMEBridge::Get()->SetCandidateWindowHandler(NULL);
232 IN_PROC_BROWSER_TEST_P(InputMethodEngineBrowserTest,
233 APIArgumentTest) {
234 LoadTestInputMethod();
236 InputMethodManager::Get()->GetActiveIMEState()->ChangeInputMethod(
237 kAPIArgumentIMEID, false /* show_message */);
239 scoped_ptr<MockIMEInputContextHandler> mock_input_context(
240 new MockIMEInputContextHandler());
241 scoped_ptr<MockIMECandidateWindowHandler> mock_candidate_window(
242 new MockIMECandidateWindowHandler());
244 IMEBridge::Get()->SetInputContextHandler(mock_input_context.get());
245 IMEBridge::Get()->SetCandidateWindowHandler(mock_candidate_window.get());
247 IMEEngineHandlerInterface* engine_handler =
248 IMEBridge::Get()->GetCurrentEngineHandler();
249 ASSERT_TRUE(engine_handler);
251 extensions::ExtensionHost* host =
252 extensions::ProcessManager::Get(profile())
253 ->GetBackgroundHostForExtension(extension_->id());
254 ASSERT_TRUE(host);
256 engine_handler->Enable("APIArgumentIME");
257 IMEEngineHandlerInterface::InputContext context(ui::TEXT_INPUT_TYPE_TEXT,
258 ui::TEXT_INPUT_MODE_DEFAULT,
259 ui::TEXT_INPUT_FLAG_NONE);
260 engine_handler->FocusIn(context);
263 SCOPED_TRACE("KeyDown, Ctrl:No, alt:No, Shift:No, Caps:No");
264 KeyEventDoneCallback callback(false);
265 const std::string expected_value =
266 "onKeyEvent::keydown:a:KeyA:false:false:false:false";
267 ExtensionTestMessageListener keyevent_listener(expected_value, false);
269 ui::KeyEvent key_event(
270 ui::ET_KEY_PRESSED, ui::VKEY_A, ui::DomCode::KEY_A, ui::EF_NONE);
271 engine_handler->ProcessKeyEvent(key_event,
272 base::Bind(&KeyEventDoneCallback::Run,
273 base::Unretained(&callback)));
274 ASSERT_TRUE(keyevent_listener.WaitUntilSatisfied());
275 EXPECT_TRUE(keyevent_listener.was_satisfied());
276 callback.WaitUntilCalled();
279 SCOPED_TRACE("KeyDown, Ctrl:Yes, alt:No, Shift:No, Caps:No");
280 KeyEventDoneCallback callback(false);
281 const std::string expected_value =
282 "onKeyEvent::keydown:a:KeyA:true:false:false:false";
283 ExtensionTestMessageListener keyevent_listener(expected_value, false);
285 ui::KeyEvent key_event(ui::ET_KEY_PRESSED,
286 ui::VKEY_A,
287 ui::DomCode::KEY_A,
288 ui::EF_CONTROL_DOWN);
289 engine_handler->ProcessKeyEvent(key_event,
290 base::Bind(&KeyEventDoneCallback::Run,
291 base::Unretained(&callback)));
292 ASSERT_TRUE(keyevent_listener.WaitUntilSatisfied());
293 EXPECT_TRUE(keyevent_listener.was_satisfied());
294 callback.WaitUntilCalled();
297 SCOPED_TRACE("KeyDown, Ctrl:No, alt:Yes, Shift:No, Caps:No");
298 KeyEventDoneCallback callback(false);
299 const std::string expected_value =
300 "onKeyEvent::keydown:a:KeyA:false:true:false:false";
301 ExtensionTestMessageListener keyevent_listener(expected_value, false);
303 ui::KeyEvent key_event(ui::ET_KEY_PRESSED,
304 ui::VKEY_A,
305 ui::DomCode::KEY_A,
306 ui::EF_ALT_DOWN);
307 engine_handler->ProcessKeyEvent(key_event,
308 base::Bind(&KeyEventDoneCallback::Run,
309 base::Unretained(&callback)));
310 ASSERT_TRUE(keyevent_listener.WaitUntilSatisfied());
311 EXPECT_TRUE(keyevent_listener.was_satisfied());
312 callback.WaitUntilCalled();
315 SCOPED_TRACE("KeyDown, Ctrl:No, alt:No, Shift:Yes, Caps:No");
316 KeyEventDoneCallback callback(false);
317 const std::string expected_value =
318 "onKeyEvent::keydown:A:KeyA:false:false:true:false";
319 ExtensionTestMessageListener keyevent_listener(expected_value, false);
321 ui::KeyEvent key_event(ui::ET_KEY_PRESSED,
322 ui::VKEY_A,
323 ui::DomCode::KEY_A,
324 ui::EF_SHIFT_DOWN);
325 engine_handler->ProcessKeyEvent(key_event,
326 base::Bind(&KeyEventDoneCallback::Run,
327 base::Unretained(&callback)));
328 ASSERT_TRUE(keyevent_listener.WaitUntilSatisfied());
329 EXPECT_TRUE(keyevent_listener.was_satisfied());
330 callback.WaitUntilCalled();
333 SCOPED_TRACE("KeyDown, Ctrl:No, alt:No, Shift:No, Caps:Yes");
334 KeyEventDoneCallback callback(false);
335 const std::string expected_value =
336 "onKeyEvent::keydown:A:KeyA:false:false:false:true";
337 ExtensionTestMessageListener keyevent_listener(expected_value, false);
339 ui::KeyEvent key_event(ui::ET_KEY_PRESSED,
340 ui::VKEY_A,
341 ui::DomCode::KEY_A,
342 ui::EF_CAPS_LOCK_DOWN);
343 engine_handler->ProcessKeyEvent(key_event,
344 base::Bind(&KeyEventDoneCallback::Run,
345 base::Unretained(&callback)));
346 ASSERT_TRUE(keyevent_listener.WaitUntilSatisfied());
347 EXPECT_TRUE(keyevent_listener.was_satisfied());
348 callback.WaitUntilCalled();
351 SCOPED_TRACE("KeyDown, Ctrl:Yes, alt:Yes, Shift:No, Caps:No");
352 KeyEventDoneCallback callback(false);
353 const std::string expected_value =
354 "onKeyEvent::keydown:a:KeyA:true:true:false:false";
355 ExtensionTestMessageListener keyevent_listener(expected_value, false);
357 ui::KeyEvent key_event(ui::ET_KEY_PRESSED,
358 ui::VKEY_A,
359 ui::DomCode::KEY_A,
360 ui::EF_ALT_DOWN | ui::EF_CONTROL_DOWN);
361 engine_handler->ProcessKeyEvent(key_event,
362 base::Bind(&KeyEventDoneCallback::Run,
363 base::Unretained(&callback)));
364 ASSERT_TRUE(keyevent_listener.WaitUntilSatisfied());
365 EXPECT_TRUE(keyevent_listener.was_satisfied());
366 callback.WaitUntilCalled();
369 SCOPED_TRACE("KeyDown, Ctrl:No, alt:No, Shift:Yes, Caps:Yes");
370 KeyEventDoneCallback callback(false);
371 const std::string expected_value =
372 "onKeyEvent::keydown:a:KeyA:false:false:true:true";
373 ExtensionTestMessageListener keyevent_listener(expected_value, false);
375 ui::KeyEvent key_event(ui::ET_KEY_PRESSED,
376 ui::VKEY_A,
377 ui::DomCode::KEY_A,
378 ui::EF_SHIFT_DOWN | ui::EF_CAPS_LOCK_DOWN);
379 engine_handler->ProcessKeyEvent(key_event,
380 base::Bind(&KeyEventDoneCallback::Run,
381 base::Unretained(&callback)));
382 ASSERT_TRUE(keyevent_listener.WaitUntilSatisfied());
383 EXPECT_TRUE(keyevent_listener.was_satisfied());
384 callback.WaitUntilCalled();
386 // Media keys cases.
387 const struct {
388 ui::KeyboardCode keycode;
389 const char* code;
390 const char* key;
391 } kMediaKeyCases[] = {
392 { ui::VKEY_BROWSER_BACK, "BrowserBack", "HistoryBack" },
393 { ui::VKEY_BROWSER_FORWARD, "BrowserForward", "HistoryForward" },
394 { ui::VKEY_BROWSER_REFRESH, "BrowserRefresh", "BrowserRefresh" },
395 { ui::VKEY_MEDIA_LAUNCH_APP2, "ChromeOSFullscreen", "ChromeOSFullscreen" },
396 { ui::VKEY_MEDIA_LAUNCH_APP1,
397 "ChromeOSSwitchWindow", "ChromeOSSwitchWindow" },
398 { ui::VKEY_BRIGHTNESS_DOWN, "BrightnessDown", "BrightnessDown" },
399 { ui::VKEY_BRIGHTNESS_UP, "BrightnessUp", "BrightnessUp" },
400 { ui::VKEY_VOLUME_MUTE, "VolumeMute", "AudioVolumeMute" },
401 { ui::VKEY_VOLUME_DOWN, "VolumeDown", "AudioVolumeDown" },
402 { ui::VKEY_VOLUME_UP, "VolumeUp", "AudioVolumeUp" },
403 { ui::VKEY_F1, "F1", "HistoryBack" },
404 { ui::VKEY_F2, "F2", "HistoryForward" },
405 { ui::VKEY_F3, "F3", "BrowserRefresh" },
406 { ui::VKEY_F4, "F4", "ChromeOSFullscreen" },
407 { ui::VKEY_F5, "F5", "ChromeOSSwitchWindow" },
408 { ui::VKEY_F6, "F6", "BrightnessDown" },
409 { ui::VKEY_F7, "F7", "BrightnessUp" },
410 { ui::VKEY_F8, "F8", "AudioVolumeMute" },
411 { ui::VKEY_F9, "F9", "AudioVolumeDown" },
412 { ui::VKEY_F10, "F10", "AudioVolumeUp" },
414 for (size_t i = 0; i < arraysize(kMediaKeyCases); ++i) {
415 SCOPED_TRACE(std::string("KeyDown, ") + kMediaKeyCases[i].code);
416 KeyEventDoneCallback callback(false);
417 const std::string expected_value =
418 base::StringPrintf("onKeyEvent::keydown:%s:%s:false:false:false:false",
419 kMediaKeyCases[i].key, kMediaKeyCases[i].code);
420 ExtensionTestMessageListener keyevent_listener(expected_value, false);
422 ui::KeyEvent key_event(
423 ui::ET_KEY_PRESSED,
424 kMediaKeyCases[i].keycode,
425 ui::KeycodeConverter::CodeStringToDomCode(kMediaKeyCases[i].code),
426 ui::EF_NONE);
427 engine_handler->ProcessKeyEvent(key_event,
428 base::Bind(&KeyEventDoneCallback::Run,
429 base::Unretained(&callback)));
430 ASSERT_TRUE(keyevent_listener.WaitUntilSatisfied());
431 EXPECT_TRUE(keyevent_listener.was_satisfied());
432 callback.WaitUntilCalled();
434 // TODO(nona): Add browser tests for other API as well.
436 SCOPED_TRACE("commitText test");
437 mock_input_context->Reset();
438 mock_candidate_window->Reset();
440 const char commit_text_test_script[] =
441 "chrome.input.ime.commitText({"
442 " contextID: engineBridge.getFocusedContextID().contextID,"
443 " text:'COMMIT_TEXT'"
444 "});";
446 ASSERT_TRUE(content::ExecuteScript(host->host_contents(),
447 commit_text_test_script));
448 EXPECT_EQ(1, mock_input_context->commit_text_call_count());
449 EXPECT_EQ("COMMIT_TEXT", mock_input_context->last_commit_text());
452 SCOPED_TRACE("sendKeyEvents test");
453 mock_input_context->Reset();
454 mock_candidate_window->Reset();
456 const char send_key_events_test_script[] =
457 "chrome.input.ime.sendKeyEvents({"
458 " contextID: engineBridge.getFocusedContextID().contextID,"
459 " keyData : [{"
460 " type : 'keydown',"
461 " requestId : '0',"
462 " key : 'z',"
463 " code : 'KeyZ',"
464 " },{"
465 " type : 'keyup',"
466 " requestId : '1',"
467 " key : 'z',"
468 " code : 'KeyZ',"
469 " }]"
470 "});";
472 ExtensionTestMessageListener keyevent_listener_down(
473 std::string("onKeyEvent:") + kExtensionID +
474 ":keydown:z:KeyZ:false:false:false:false",
475 false);
476 ExtensionTestMessageListener keyevent_listener_up(
477 std::string("onKeyEvent:") + kExtensionID +
478 ":keyup:z:KeyZ:false:false:false:false",
479 false);
481 ASSERT_TRUE(content::ExecuteScript(host->host_contents(),
482 send_key_events_test_script));
484 ASSERT_TRUE(keyevent_listener_down.WaitUntilSatisfied());
485 EXPECT_TRUE(keyevent_listener_down.was_satisfied());
486 ASSERT_TRUE(keyevent_listener_up.WaitUntilSatisfied());
487 EXPECT_TRUE(keyevent_listener_up.was_satisfied());
490 SCOPED_TRACE("sendKeyEvents test with keyCode");
491 mock_input_context->Reset();
492 mock_candidate_window->Reset();
494 const char send_key_events_test_script[] =
495 "chrome.input.ime.sendKeyEvents({"
496 " contextID: engineBridge.getFocusedContextID().contextID,"
497 " keyData : [{"
498 " type : 'keydown',"
499 " requestId : '2',"
500 " key : 'a',"
501 " code : 'KeyQ',"
502 " keyCode : 0x41,"
503 " },{"
504 " type : 'keyup',"
505 " requestId : '3',"
506 " key : 'a',"
507 " code : 'KeyQ',"
508 " keyCode : 0x41,"
509 " }]"
510 "});";
512 ExtensionTestMessageListener keyevent_listener_down(
513 std::string("onKeyEvent:") + kExtensionID +
514 ":keydown:a:KeyQ:false:false:false:false",
515 false);
516 ExtensionTestMessageListener keyevent_listener_up(
517 std::string("onKeyEvent:") + kExtensionID +
518 ":keyup:a:KeyQ:false:false:false:false",
519 false);
521 ASSERT_TRUE(content::ExecuteScript(host->host_contents(),
522 send_key_events_test_script));
524 ASSERT_TRUE(keyevent_listener_down.WaitUntilSatisfied());
525 EXPECT_TRUE(keyevent_listener_down.was_satisfied());
526 ASSERT_TRUE(keyevent_listener_up.WaitUntilSatisfied());
527 EXPECT_TRUE(keyevent_listener_up.was_satisfied());
530 SCOPED_TRACE("setComposition test");
531 mock_input_context->Reset();
532 mock_candidate_window->Reset();
534 const char set_composition_test_script[] =
535 "chrome.input.ime.setComposition({"
536 " contextID: engineBridge.getFocusedContextID().contextID,"
537 " text:'COMPOSITION_TEXT',"
538 " cursor:4,"
539 " segments : [{"
540 " start: 0,"
541 " end: 5,"
542 " style: 'underline'"
543 " },{"
544 " start: 6,"
545 " end: 10,"
546 " style: 'doubleUnderline'"
547 " }]"
548 "});";
550 ASSERT_TRUE(content::ExecuteScript(host->host_contents(),
551 set_composition_test_script));
552 EXPECT_EQ(1, mock_input_context->update_preedit_text_call_count());
554 EXPECT_EQ(4U,
555 mock_input_context->last_update_composition_arg().cursor_pos);
556 EXPECT_TRUE(mock_input_context->last_update_composition_arg().is_visible);
558 const CompositionText& composition_text =
559 mock_input_context->last_update_composition_arg().composition_text;
560 EXPECT_EQ(base::UTF8ToUTF16("COMPOSITION_TEXT"), composition_text.text());
561 const std::vector<CompositionText::UnderlineAttribute>& underlines =
562 composition_text.underline_attributes();
564 ASSERT_EQ(2U, underlines.size());
565 EXPECT_EQ(CompositionText::COMPOSITION_TEXT_UNDERLINE_SINGLE,
566 underlines[0].type);
567 EXPECT_EQ(0U, underlines[0].start_index);
568 EXPECT_EQ(5U, underlines[0].end_index);
570 EXPECT_EQ(CompositionText::COMPOSITION_TEXT_UNDERLINE_DOUBLE,
571 underlines[1].type);
572 EXPECT_EQ(6U, underlines[1].start_index);
573 EXPECT_EQ(10U, underlines[1].end_index);
576 SCOPED_TRACE("clearComposition test");
577 mock_input_context->Reset();
578 mock_candidate_window->Reset();
580 const char commite_text_test_script[] =
581 "chrome.input.ime.clearComposition({"
582 " contextID: engineBridge.getFocusedContextID().contextID,"
583 "});";
585 ASSERT_TRUE(content::ExecuteScript(host->host_contents(),
586 commite_text_test_script));
587 EXPECT_EQ(1, mock_input_context->update_preedit_text_call_count());
588 EXPECT_FALSE(
589 mock_input_context->last_update_composition_arg().is_visible);
590 const CompositionText& composition_text =
591 mock_input_context->last_update_composition_arg().composition_text;
592 EXPECT_TRUE(composition_text.text().empty());
595 SCOPED_TRACE("setCandidateWindowProperties:visibility test");
596 mock_input_context->Reset();
597 mock_candidate_window->Reset();
599 const char set_candidate_window_properties_test_script[] =
600 "chrome.input.ime.setCandidateWindowProperties({"
601 " engineID: engineBridge.getActiveEngineID(),"
602 " properties: {"
603 " visible: true,"
604 " }"
605 "});";
606 ASSERT_TRUE(content::ExecuteScript(
607 host->host_contents(),
608 set_candidate_window_properties_test_script));
609 EXPECT_EQ(1, mock_candidate_window->update_lookup_table_call_count());
610 EXPECT_TRUE(
611 mock_candidate_window->last_update_lookup_table_arg().is_visible);
614 SCOPED_TRACE("setCandidateWindowProperties:cursor_visibility test");
615 mock_input_context->Reset();
616 mock_candidate_window->Reset();
618 const char set_candidate_window_properties_test_script[] =
619 "chrome.input.ime.setCandidateWindowProperties({"
620 " engineID: engineBridge.getActiveEngineID(),"
621 " properties: {"
622 " cursorVisible: true,"
623 " }"
624 "});";
625 ASSERT_TRUE(content::ExecuteScript(
626 host->host_contents(),
627 set_candidate_window_properties_test_script));
628 EXPECT_EQ(1, mock_candidate_window->update_lookup_table_call_count());
630 // window visibility is kept as before.
631 EXPECT_TRUE(
632 mock_candidate_window->last_update_lookup_table_arg().is_visible);
634 const ui::CandidateWindow& table =
635 mock_candidate_window->last_update_lookup_table_arg().lookup_table;
636 EXPECT_TRUE(table.is_cursor_visible());
639 SCOPED_TRACE("setCandidateWindowProperties:vertical test");
640 mock_input_context->Reset();
641 mock_candidate_window->Reset();
643 const char set_candidate_window_properties_test_script[] =
644 "chrome.input.ime.setCandidateWindowProperties({"
645 " engineID: engineBridge.getActiveEngineID(),"
646 " properties: {"
647 " vertical: true,"
648 " }"
649 "});";
650 ASSERT_TRUE(content::ExecuteScript(
651 host->host_contents(),
652 set_candidate_window_properties_test_script));
653 EXPECT_EQ(1, mock_candidate_window->update_lookup_table_call_count());
655 // window visibility is kept as before.
656 EXPECT_TRUE(
657 mock_candidate_window->last_update_lookup_table_arg().is_visible);
659 const ui::CandidateWindow& table =
660 mock_candidate_window->last_update_lookup_table_arg().lookup_table;
662 // cursor visibility is kept as before.
663 EXPECT_TRUE(table.is_cursor_visible());
665 EXPECT_EQ(ui::CandidateWindow::VERTICAL, table.orientation());
668 SCOPED_TRACE("setCandidateWindowProperties:pageSize test");
669 mock_input_context->Reset();
670 mock_candidate_window->Reset();
672 const char set_candidate_window_properties_test_script[] =
673 "chrome.input.ime.setCandidateWindowProperties({"
674 " engineID: engineBridge.getActiveEngineID(),"
675 " properties: {"
676 " pageSize: 7,"
677 " }"
678 "});";
679 ASSERT_TRUE(content::ExecuteScript(
680 host->host_contents(),
681 set_candidate_window_properties_test_script));
682 EXPECT_EQ(1, mock_candidate_window->update_lookup_table_call_count());
684 // window visibility is kept as before.
685 EXPECT_TRUE(
686 mock_candidate_window->last_update_lookup_table_arg().is_visible);
688 const ui::CandidateWindow& table =
689 mock_candidate_window->last_update_lookup_table_arg().lookup_table;
691 // cursor visibility is kept as before.
692 EXPECT_TRUE(table.is_cursor_visible());
694 // oritantation is kept as before.
695 EXPECT_EQ(ui::CandidateWindow::VERTICAL, table.orientation());
697 EXPECT_EQ(7U, table.page_size());
700 SCOPED_TRACE("setCandidateWindowProperties:auxTextVisibility test");
701 mock_input_context->Reset();
702 mock_candidate_window->Reset();
704 const char set_candidate_window_properties_test_script[] =
705 "chrome.input.ime.setCandidateWindowProperties({"
706 " engineID: engineBridge.getActiveEngineID(),"
707 " properties: {"
708 " auxiliaryTextVisible: true"
709 " }"
710 "});";
711 ASSERT_TRUE(content::ExecuteScript(
712 host->host_contents(),
713 set_candidate_window_properties_test_script));
714 EXPECT_EQ(1, mock_candidate_window->update_lookup_table_call_count());
716 const ui::CandidateWindow& table =
717 mock_candidate_window->last_update_lookup_table_arg().lookup_table;
718 EXPECT_TRUE(table.is_auxiliary_text_visible());
721 SCOPED_TRACE("setCandidateWindowProperties:auxText test");
722 mock_input_context->Reset();
723 mock_candidate_window->Reset();
725 const char set_candidate_window_properties_test_script[] =
726 "chrome.input.ime.setCandidateWindowProperties({"
727 " engineID: engineBridge.getActiveEngineID(),"
728 " properties: {"
729 " auxiliaryText: 'AUXILIARY_TEXT'"
730 " }"
731 "});";
732 ASSERT_TRUE(content::ExecuteScript(
733 host->host_contents(),
734 set_candidate_window_properties_test_script));
735 EXPECT_EQ(1, mock_candidate_window->update_lookup_table_call_count());
737 // aux text visibility is kept as before.
738 const ui::CandidateWindow& table =
739 mock_candidate_window->last_update_lookup_table_arg().lookup_table;
740 EXPECT_TRUE(table.is_auxiliary_text_visible());
741 EXPECT_EQ("AUXILIARY_TEXT", table.auxiliary_text());
744 SCOPED_TRACE("setCandidates test");
745 mock_input_context->Reset();
746 mock_candidate_window->Reset();
748 const char set_candidates_test_script[] =
749 "chrome.input.ime.setCandidates({"
750 " contextID: engineBridge.getFocusedContextID().contextID,"
751 " candidates: [{"
752 " candidate: 'CANDIDATE_1',"
753 " id: 1,"
754 " },{"
755 " candidate: 'CANDIDATE_2',"
756 " id: 2,"
757 " label: 'LABEL_2',"
758 " },{"
759 " candidate: 'CANDIDATE_3',"
760 " id: 3,"
761 " label: 'LABEL_3',"
762 " annotation: 'ANNOTACTION_3'"
763 " },{"
764 " candidate: 'CANDIDATE_4',"
765 " id: 4,"
766 " label: 'LABEL_4',"
767 " annotation: 'ANNOTACTION_4',"
768 " usage: {"
769 " title: 'TITLE_4',"
770 " body: 'BODY_4'"
771 " }"
772 " }]"
773 "});";
774 ASSERT_TRUE(content::ExecuteScript(host->host_contents(),
775 set_candidates_test_script));
777 // window visibility is kept as before.
778 EXPECT_TRUE(
779 mock_candidate_window->last_update_lookup_table_arg().is_visible);
781 const ui::CandidateWindow& table =
782 mock_candidate_window->last_update_lookup_table_arg().lookup_table;
784 // cursor visibility is kept as before.
785 EXPECT_TRUE(table.is_cursor_visible());
787 // oritantation is kept as before.
788 EXPECT_EQ(ui::CandidateWindow::VERTICAL, table.orientation());
790 // page size is kept as before.
791 EXPECT_EQ(7U, table.page_size());
793 ASSERT_EQ(4U, table.candidates().size());
795 EXPECT_EQ(base::UTF8ToUTF16("CANDIDATE_1"),
796 table.candidates().at(0).value);
798 EXPECT_EQ(base::UTF8ToUTF16("CANDIDATE_2"),
799 table.candidates().at(1).value);
800 EXPECT_EQ(base::UTF8ToUTF16("LABEL_2"), table.candidates().at(1).label);
802 EXPECT_EQ(base::UTF8ToUTF16("CANDIDATE_3"),
803 table.candidates().at(2).value);
804 EXPECT_EQ(base::UTF8ToUTF16("LABEL_3"), table.candidates().at(2).label);
805 EXPECT_EQ(base::UTF8ToUTF16("ANNOTACTION_3"),
806 table.candidates().at(2).annotation);
808 EXPECT_EQ(base::UTF8ToUTF16("CANDIDATE_4"),
809 table.candidates().at(3).value);
810 EXPECT_EQ(base::UTF8ToUTF16("LABEL_4"), table.candidates().at(3).label);
811 EXPECT_EQ(base::UTF8ToUTF16("ANNOTACTION_4"),
812 table.candidates().at(3).annotation);
813 EXPECT_EQ(base::UTF8ToUTF16("TITLE_4"),
814 table.candidates().at(3).description_title);
815 EXPECT_EQ(base::UTF8ToUTF16("BODY_4"),
816 table.candidates().at(3).description_body);
819 SCOPED_TRACE("setCursorPosition test");
820 mock_input_context->Reset();
821 mock_candidate_window->Reset();
823 const char set_cursor_position_test_script[] =
824 "chrome.input.ime.setCursorPosition({"
825 " contextID: engineBridge.getFocusedContextID().contextID,"
826 " candidateID: 2"
827 "});";
828 ASSERT_TRUE(content::ExecuteScript(
829 host->host_contents(), set_cursor_position_test_script));
830 EXPECT_EQ(1, mock_candidate_window->update_lookup_table_call_count());
832 // window visibility is kept as before.
833 EXPECT_TRUE(
834 mock_candidate_window->last_update_lookup_table_arg().is_visible);
836 const ui::CandidateWindow& table =
837 mock_candidate_window->last_update_lookup_table_arg().lookup_table;
839 // cursor visibility is kept as before.
840 EXPECT_TRUE(table.is_cursor_visible());
842 // oritantation is kept as before.
843 EXPECT_EQ(ui::CandidateWindow::VERTICAL, table.orientation());
845 // page size is kept as before.
846 EXPECT_EQ(7U, table.page_size());
848 // candidates are same as before.
849 ASSERT_EQ(4U, table.candidates().size());
851 // Candidate ID == 2 is 1 in index.
852 EXPECT_EQ(1U, table.cursor_position());
855 SCOPED_TRACE("setMenuItem test");
856 mock_input_context->Reset();
857 mock_candidate_window->Reset();
859 const char set_menu_item_test_script[] =
860 "chrome.input.ime.setMenuItems({"
861 " engineID: engineBridge.getActiveEngineID(),"
862 " items: [{"
863 " id: 'ID0',"
864 " },{"
865 " id: 'ID1',"
866 " label: 'LABEL1',"
867 " },{"
868 " id: 'ID2',"
869 " label: 'LABEL2',"
870 " style: 'radio',"
871 " },{"
872 " id: 'ID3',"
873 " label: 'LABEL3',"
874 " style: 'check',"
875 " visible: true,"
876 " },{"
877 " id: 'ID4',"
878 " label: 'LABEL4',"
879 " style: 'separator',"
880 " visible: true,"
881 " checked: true"
882 " }]"
883 "});";
884 ASSERT_TRUE(content::ExecuteScript(
885 host->host_contents(), set_menu_item_test_script));
887 const ui::ime::InputMethodMenuItemList& props =
888 ui::ime::InputMethodMenuManager::GetInstance()->
889 GetCurrentInputMethodMenuItemList();
890 ASSERT_EQ(5U, props.size());
892 EXPECT_EQ("ID0", props[0].key);
893 EXPECT_EQ("ID1", props[1].key);
894 EXPECT_EQ("ID2", props[2].key);
895 EXPECT_EQ("ID3", props[3].key);
896 EXPECT_EQ("ID4", props[4].key);
898 EXPECT_EQ("LABEL1", props[1].label);
899 EXPECT_EQ("LABEL2", props[2].label);
900 EXPECT_EQ("LABEL3", props[3].label);
901 EXPECT_EQ("LABEL4", props[4].label);
903 EXPECT_TRUE(props[2].is_selection_item);
904 // TODO(nona): Add tests for style: ["toggle" and "separator"]
905 // and visible:, when implement them.
907 EXPECT_TRUE(props[4].is_selection_item_checked);
910 SCOPED_TRACE("deleteSurroundingText test");
911 mock_input_context->Reset();
912 mock_candidate_window->Reset();
914 const char delete_surrounding_text_test_script[] =
915 "chrome.input.ime.deleteSurroundingText({"
916 " engineID: engineBridge.getActiveEngineID(),"
917 " contextID: engineBridge.getFocusedContextID().contextID,"
918 " offset: 5,"
919 " length: 3"
920 "});";
921 ASSERT_TRUE(content::ExecuteScript(
922 host->host_contents(), delete_surrounding_text_test_script));
924 EXPECT_EQ(1, mock_input_context->delete_surrounding_text_call_count());
925 EXPECT_EQ(5, mock_input_context->last_delete_surrounding_text_arg().offset);
926 EXPECT_EQ(3U,
927 mock_input_context->last_delete_surrounding_text_arg().length);
930 SCOPED_TRACE("onFocus test");
931 mock_input_context->Reset();
932 mock_candidate_window->Reset();
935 ExtensionTestMessageListener focus_listener("onFocus:text", false);
936 IMEEngineHandlerInterface::InputContext context(
937 ui::TEXT_INPUT_TYPE_TEXT, ui::TEXT_INPUT_MODE_DEFAULT,
938 ui::TEXT_INPUT_FLAG_NONE);
939 engine_handler->FocusIn(context);
940 ASSERT_TRUE(focus_listener.WaitUntilSatisfied());
941 ASSERT_TRUE(focus_listener.was_satisfied());
944 ExtensionTestMessageListener focus_listener("onFocus:search", false);
945 IMEEngineHandlerInterface::InputContext context(
946 ui::TEXT_INPUT_TYPE_SEARCH, ui::TEXT_INPUT_MODE_DEFAULT,
947 ui::TEXT_INPUT_FLAG_NONE);
948 engine_handler->FocusIn(context);
949 ASSERT_TRUE(focus_listener.WaitUntilSatisfied());
950 ASSERT_TRUE(focus_listener.was_satisfied());
953 ExtensionTestMessageListener focus_listener("onFocus:tel", false);
954 IMEEngineHandlerInterface::InputContext context(
955 ui::TEXT_INPUT_TYPE_TELEPHONE, ui::TEXT_INPUT_MODE_DEFAULT,
956 ui::TEXT_INPUT_FLAG_NONE);
957 engine_handler->FocusIn(context);
958 ASSERT_TRUE(focus_listener.WaitUntilSatisfied());
959 ASSERT_TRUE(focus_listener.was_satisfied());
962 ExtensionTestMessageListener focus_listener("onFocus:url", false);
963 IMEEngineHandlerInterface::InputContext context(
964 ui::TEXT_INPUT_TYPE_URL, ui::TEXT_INPUT_MODE_DEFAULT,
965 ui::TEXT_INPUT_FLAG_NONE);
966 engine_handler->FocusIn(context);
967 ASSERT_TRUE(focus_listener.WaitUntilSatisfied());
968 ASSERT_TRUE(focus_listener.was_satisfied());
971 ExtensionTestMessageListener focus_listener("onFocus:email", false);
972 IMEEngineHandlerInterface::InputContext context(
973 ui::TEXT_INPUT_TYPE_EMAIL, ui::TEXT_INPUT_MODE_DEFAULT,
974 ui::TEXT_INPUT_FLAG_NONE);
975 engine_handler->FocusIn(context);
976 ASSERT_TRUE(focus_listener.WaitUntilSatisfied());
977 ASSERT_TRUE(focus_listener.was_satisfied());
980 ExtensionTestMessageListener focus_listener("onFocus:number", false);
981 IMEEngineHandlerInterface::InputContext context(
982 ui::TEXT_INPUT_TYPE_NUMBER, ui::TEXT_INPUT_MODE_DEFAULT,
983 ui::TEXT_INPUT_FLAG_NONE);
984 engine_handler->FocusIn(context);
985 ASSERT_TRUE(focus_listener.WaitUntilSatisfied());
986 ASSERT_TRUE(focus_listener.was_satisfied());
990 SCOPED_TRACE("changeInputMethod with uncommited text test");
991 // For http://crbug.com/529999.
993 mock_input_context->Reset();
994 mock_candidate_window->Reset();
996 EXPECT_TRUE(mock_input_context->last_commit_text().empty());
998 const char set_composition_test_script[] =
999 "chrome.input.ime.setComposition({"
1000 " contextID: engineBridge.getFocusedContextID().contextID,"
1001 " text:'us',"
1002 " cursor:2,"
1003 " segments : [{"
1004 " start: 0,"
1005 " end: 1,"
1006 " style: 'underline'"
1007 " }]"
1008 "});";
1010 ASSERT_TRUE(content::ExecuteScript(host->host_contents(),
1011 set_composition_test_script));
1012 EXPECT_EQ(2U, mock_input_context->last_update_composition_arg().cursor_pos);
1013 EXPECT_TRUE(mock_input_context->last_update_composition_arg().is_visible);
1015 const CompositionText& composition_text =
1016 mock_input_context->last_update_composition_arg().composition_text;
1017 EXPECT_EQ(base::UTF8ToUTF16("us"), composition_text.text());
1018 const std::vector<CompositionText::UnderlineAttribute>& underlines =
1019 composition_text.underline_attributes();
1021 ASSERT_EQ(1U, underlines.size());
1022 EXPECT_EQ(CompositionText::COMPOSITION_TEXT_UNDERLINE_SINGLE,
1023 underlines[0].type);
1024 EXPECT_EQ(0U, underlines[0].start_index);
1025 EXPECT_EQ(1U, underlines[0].end_index);
1026 EXPECT_TRUE(mock_input_context->last_commit_text().empty());
1028 InputMethodManager::Get()->GetActiveIMEState()->ChangeInputMethod(
1029 kIdentityIMEID, false /* show_message */);
1030 EXPECT_EQ("us", mock_input_context->last_commit_text());
1032 InputMethodManager::Get()->GetActiveIMEState()->ChangeInputMethod(
1033 extension_ime_util::GetInputMethodIDByEngineID("zh-t-i0-pinyin"),
1034 false /* show_message */);
1035 EXPECT_EQ("", mock_input_context->last_commit_text());
1037 InputMethodManager::Get()->GetActiveIMEState()->ChangeInputMethod(
1038 extension_ime_util::GetInputMethodIDByEngineID("xkb:us::eng"),
1039 false /* show_message */);
1040 EXPECT_EQ("", mock_input_context->last_commit_text());
1043 IMEBridge::Get()->SetInputContextHandler(NULL);
1044 IMEBridge::Get()->SetCandidateWindowHandler(NULL);
1047 } // namespace
1048 } // namespace input_method
1049 } // namespace chromeos