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.h"
16 #include "ui/base/ime/chromeos/ime_bridge.h"
17 #include "ui/base/ime/chromeos/input_method_descriptor.h"
18 #include "ui/base/ime/chromeos/input_method_manager.h"
19 #include "ui/base/ime/chromeos/mock_ime_candidate_window_handler.h"
20 #include "ui/base/ime/chromeos/mock_ime_input_context_handler.h"
21 #include "ui/base/ime/text_input_flags.h"
22 #include "ui/chromeos/ime/input_method_menu_item.h"
23 #include "ui/chromeos/ime/input_method_menu_manager.h"
24 #include "ui/events/event.h"
25 #include "ui/events/keycodes/dom3/dom_code.h"
26 #include "ui/events/keycodes/dom4/keycode_converter.h"
29 namespace input_method
{
32 const char kIdentityIMEID
[] =
33 "_ext_ime_iafoklpfplgfnoimmaejoeondnjnlcfpIdentityIME";
34 const char kToUpperIMEID
[] =
35 "_ext_ime_iafoklpfplgfnoimmaejoeondnjnlcfpToUpperIME";
36 const char kAPIArgumentIMEID
[] =
37 "_ext_ime_iafoklpfplgfnoimmaejoeondnjnlcfpAPIArgumentIME";
38 const char kExtensionID
[] = "iafoklpfplgfnoimmaejoeondnjnlcfp";
40 // InputMethod extension should work on 1)normal extension, 2)normal extension
41 // in incognito mode 3)component extension.
44 kTestTypeIncognito
= 1,
45 kTestTypeComponent
= 2,
48 class InputMethodEngineBrowserTest
49 : public ExtensionBrowserTest
,
50 public ::testing::WithParamInterface
<TestType
> {
52 InputMethodEngineBrowserTest()
53 : ExtensionBrowserTest() {}
54 virtual ~InputMethodEngineBrowserTest() {}
56 void SetUpInProcessBrowserTestFixture() override
{
57 ExtensionBrowserTest::SetUpInProcessBrowserTestFixture();
60 void TearDownInProcessBrowserTestFixture() override
{ extension_
= NULL
; }
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
, ui::DomCode::KEY_A
, 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(
422 kMediaKeyCases
[i
].keycode
,
423 ui::KeycodeConverter::CodeStringToDomCode(kMediaKeyCases
[i
].code
),
425 engine_handler
->ProcessKeyEvent(key_event
,
426 base::Bind(&KeyEventDoneCallback::Run
,
427 base::Unretained(&callback
)));
428 ASSERT_TRUE(keyevent_listener
.WaitUntilSatisfied());
429 EXPECT_TRUE(keyevent_listener
.was_satisfied());
430 callback
.WaitUntilCalled();
432 // TODO(nona): Add browser tests for other API as well.
434 SCOPED_TRACE("commitText test");
435 mock_input_context
->Reset();
436 mock_candidate_window
->Reset();
438 const char commit_text_test_script
[] =
439 "chrome.input.ime.commitText({"
440 " contextID: engineBridge.getFocusedContextID().contextID,"
441 " text:'COMMIT_TEXT'"
444 ASSERT_TRUE(content::ExecuteScript(host
->host_contents(),
445 commit_text_test_script
));
446 EXPECT_EQ(1, mock_input_context
->commit_text_call_count());
447 EXPECT_EQ("COMMIT_TEXT", mock_input_context
->last_commit_text());
450 SCOPED_TRACE("sendKeyEvents test");
451 mock_input_context
->Reset();
452 mock_candidate_window
->Reset();
454 const char send_key_events_test_script
[] =
455 "chrome.input.ime.sendKeyEvents({"
456 " contextID: engineBridge.getFocusedContextID().contextID,"
470 ExtensionTestMessageListener
keyevent_listener_down(
471 std::string("onKeyEvent:") + kExtensionID
+
472 ":keydown:z:KeyZ:false:false:false:false",
474 ExtensionTestMessageListener
keyevent_listener_up(
475 std::string("onKeyEvent:") + kExtensionID
+
476 ":keyup:z:KeyZ:false:false:false:false",
479 ASSERT_TRUE(content::ExecuteScript(host
->host_contents(),
480 send_key_events_test_script
));
482 ASSERT_TRUE(keyevent_listener_down
.WaitUntilSatisfied());
483 EXPECT_TRUE(keyevent_listener_down
.was_satisfied());
484 ASSERT_TRUE(keyevent_listener_up
.WaitUntilSatisfied());
485 EXPECT_TRUE(keyevent_listener_up
.was_satisfied());
488 SCOPED_TRACE("sendKeyEvents test with keyCode");
489 mock_input_context
->Reset();
490 mock_candidate_window
->Reset();
492 const char send_key_events_test_script
[] =
493 "chrome.input.ime.sendKeyEvents({"
494 " contextID: engineBridge.getFocusedContextID().contextID,"
510 ExtensionTestMessageListener
keyevent_listener_down(
511 std::string("onKeyEvent:") + kExtensionID
+
512 ":keydown:a:KeyQ:false:false:false:false",
514 ExtensionTestMessageListener
keyevent_listener_up(
515 std::string("onKeyEvent:") + kExtensionID
+
516 ":keyup:a:KeyQ:false:false:false:false",
519 ASSERT_TRUE(content::ExecuteScript(host
->host_contents(),
520 send_key_events_test_script
));
522 ASSERT_TRUE(keyevent_listener_down
.WaitUntilSatisfied());
523 EXPECT_TRUE(keyevent_listener_down
.was_satisfied());
524 ASSERT_TRUE(keyevent_listener_up
.WaitUntilSatisfied());
525 EXPECT_TRUE(keyevent_listener_up
.was_satisfied());
528 SCOPED_TRACE("setComposition test");
529 mock_input_context
->Reset();
530 mock_candidate_window
->Reset();
532 const char set_composition_test_script
[] =
533 "chrome.input.ime.setComposition({"
534 " contextID: engineBridge.getFocusedContextID().contextID,"
535 " text:'COMPOSITION_TEXT',"
540 " style: 'underline'"
544 " style: 'doubleUnderline'"
548 ASSERT_TRUE(content::ExecuteScript(host
->host_contents(),
549 set_composition_test_script
));
550 EXPECT_EQ(1, mock_input_context
->update_preedit_text_call_count());
553 mock_input_context
->last_update_composition_arg().cursor_pos
);
554 EXPECT_TRUE(mock_input_context
->last_update_composition_arg().is_visible
);
556 const CompositionText
& composition_text
=
557 mock_input_context
->last_update_composition_arg().composition_text
;
558 EXPECT_EQ(base::UTF8ToUTF16("COMPOSITION_TEXT"), composition_text
.text());
559 const std::vector
<CompositionText::UnderlineAttribute
>& underlines
=
560 composition_text
.underline_attributes();
562 ASSERT_EQ(2U, underlines
.size());
563 EXPECT_EQ(CompositionText::COMPOSITION_TEXT_UNDERLINE_SINGLE
,
565 EXPECT_EQ(0U, underlines
[0].start_index
);
566 EXPECT_EQ(5U, underlines
[0].end_index
);
568 EXPECT_EQ(CompositionText::COMPOSITION_TEXT_UNDERLINE_DOUBLE
,
570 EXPECT_EQ(6U, underlines
[1].start_index
);
571 EXPECT_EQ(10U, underlines
[1].end_index
);
574 SCOPED_TRACE("clearComposition test");
575 mock_input_context
->Reset();
576 mock_candidate_window
->Reset();
578 const char commite_text_test_script
[] =
579 "chrome.input.ime.clearComposition({"
580 " contextID: engineBridge.getFocusedContextID().contextID,"
583 ASSERT_TRUE(content::ExecuteScript(host
->host_contents(),
584 commite_text_test_script
));
585 EXPECT_EQ(1, mock_input_context
->update_preedit_text_call_count());
587 mock_input_context
->last_update_composition_arg().is_visible
);
588 const CompositionText
& composition_text
=
589 mock_input_context
->last_update_composition_arg().composition_text
;
590 EXPECT_TRUE(composition_text
.text().empty());
593 SCOPED_TRACE("setCandidateWindowProperties:visibility test");
594 mock_input_context
->Reset();
595 mock_candidate_window
->Reset();
597 const char set_candidate_window_properties_test_script
[] =
598 "chrome.input.ime.setCandidateWindowProperties({"
599 " engineID: engineBridge.getActiveEngineID(),"
604 ASSERT_TRUE(content::ExecuteScript(
605 host
->host_contents(),
606 set_candidate_window_properties_test_script
));
607 EXPECT_EQ(1, mock_candidate_window
->update_lookup_table_call_count());
609 mock_candidate_window
->last_update_lookup_table_arg().is_visible
);
612 SCOPED_TRACE("setCandidateWindowProperties:cursor_visibility test");
613 mock_input_context
->Reset();
614 mock_candidate_window
->Reset();
616 const char set_candidate_window_properties_test_script
[] =
617 "chrome.input.ime.setCandidateWindowProperties({"
618 " engineID: engineBridge.getActiveEngineID(),"
620 " cursorVisible: true,"
623 ASSERT_TRUE(content::ExecuteScript(
624 host
->host_contents(),
625 set_candidate_window_properties_test_script
));
626 EXPECT_EQ(1, mock_candidate_window
->update_lookup_table_call_count());
628 // window visibility is kept as before.
630 mock_candidate_window
->last_update_lookup_table_arg().is_visible
);
632 const ui::CandidateWindow
& table
=
633 mock_candidate_window
->last_update_lookup_table_arg().lookup_table
;
634 EXPECT_TRUE(table
.is_cursor_visible());
637 SCOPED_TRACE("setCandidateWindowProperties:vertical test");
638 mock_input_context
->Reset();
639 mock_candidate_window
->Reset();
641 const char set_candidate_window_properties_test_script
[] =
642 "chrome.input.ime.setCandidateWindowProperties({"
643 " engineID: engineBridge.getActiveEngineID(),"
648 ASSERT_TRUE(content::ExecuteScript(
649 host
->host_contents(),
650 set_candidate_window_properties_test_script
));
651 EXPECT_EQ(1, mock_candidate_window
->update_lookup_table_call_count());
653 // window visibility is kept as before.
655 mock_candidate_window
->last_update_lookup_table_arg().is_visible
);
657 const ui::CandidateWindow
& table
=
658 mock_candidate_window
->last_update_lookup_table_arg().lookup_table
;
660 // cursor visibility is kept as before.
661 EXPECT_TRUE(table
.is_cursor_visible());
663 EXPECT_EQ(ui::CandidateWindow::VERTICAL
, table
.orientation());
666 SCOPED_TRACE("setCandidateWindowProperties:pageSize test");
667 mock_input_context
->Reset();
668 mock_candidate_window
->Reset();
670 const char set_candidate_window_properties_test_script
[] =
671 "chrome.input.ime.setCandidateWindowProperties({"
672 " engineID: engineBridge.getActiveEngineID(),"
677 ASSERT_TRUE(content::ExecuteScript(
678 host
->host_contents(),
679 set_candidate_window_properties_test_script
));
680 EXPECT_EQ(1, mock_candidate_window
->update_lookup_table_call_count());
682 // window visibility is kept as before.
684 mock_candidate_window
->last_update_lookup_table_arg().is_visible
);
686 const ui::CandidateWindow
& table
=
687 mock_candidate_window
->last_update_lookup_table_arg().lookup_table
;
689 // cursor visibility is kept as before.
690 EXPECT_TRUE(table
.is_cursor_visible());
692 // oritantation is kept as before.
693 EXPECT_EQ(ui::CandidateWindow::VERTICAL
, table
.orientation());
695 EXPECT_EQ(7U, table
.page_size());
698 SCOPED_TRACE("setCandidateWindowProperties:auxTextVisibility test");
699 mock_input_context
->Reset();
700 mock_candidate_window
->Reset();
702 const char set_candidate_window_properties_test_script
[] =
703 "chrome.input.ime.setCandidateWindowProperties({"
704 " engineID: engineBridge.getActiveEngineID(),"
706 " auxiliaryTextVisible: true"
709 ASSERT_TRUE(content::ExecuteScript(
710 host
->host_contents(),
711 set_candidate_window_properties_test_script
));
712 EXPECT_EQ(1, mock_candidate_window
->update_lookup_table_call_count());
714 const ui::CandidateWindow
& table
=
715 mock_candidate_window
->last_update_lookup_table_arg().lookup_table
;
716 EXPECT_TRUE(table
.is_auxiliary_text_visible());
719 SCOPED_TRACE("setCandidateWindowProperties:auxText test");
720 mock_input_context
->Reset();
721 mock_candidate_window
->Reset();
723 const char set_candidate_window_properties_test_script
[] =
724 "chrome.input.ime.setCandidateWindowProperties({"
725 " engineID: engineBridge.getActiveEngineID(),"
727 " auxiliaryText: 'AUXILIARY_TEXT'"
730 ASSERT_TRUE(content::ExecuteScript(
731 host
->host_contents(),
732 set_candidate_window_properties_test_script
));
733 EXPECT_EQ(1, mock_candidate_window
->update_lookup_table_call_count());
735 // aux text visibility is kept as before.
736 const ui::CandidateWindow
& table
=
737 mock_candidate_window
->last_update_lookup_table_arg().lookup_table
;
738 EXPECT_TRUE(table
.is_auxiliary_text_visible());
739 EXPECT_EQ("AUXILIARY_TEXT", table
.auxiliary_text());
742 SCOPED_TRACE("setCandidates test");
743 mock_input_context
->Reset();
744 mock_candidate_window
->Reset();
746 const char set_candidates_test_script
[] =
747 "chrome.input.ime.setCandidates({"
748 " contextID: engineBridge.getFocusedContextID().contextID,"
750 " candidate: 'CANDIDATE_1',"
753 " candidate: 'CANDIDATE_2',"
757 " candidate: 'CANDIDATE_3',"
760 " annotation: 'ANNOTACTION_3'"
762 " candidate: 'CANDIDATE_4',"
765 " annotation: 'ANNOTACTION_4',"
772 ASSERT_TRUE(content::ExecuteScript(host
->host_contents(),
773 set_candidates_test_script
));
775 // window visibility is kept as before.
777 mock_candidate_window
->last_update_lookup_table_arg().is_visible
);
779 const ui::CandidateWindow
& table
=
780 mock_candidate_window
->last_update_lookup_table_arg().lookup_table
;
782 // cursor visibility is kept as before.
783 EXPECT_TRUE(table
.is_cursor_visible());
785 // oritantation is kept as before.
786 EXPECT_EQ(ui::CandidateWindow::VERTICAL
, table
.orientation());
788 // page size is kept as before.
789 EXPECT_EQ(7U, table
.page_size());
791 ASSERT_EQ(4U, table
.candidates().size());
793 EXPECT_EQ(base::UTF8ToUTF16("CANDIDATE_1"),
794 table
.candidates().at(0).value
);
796 EXPECT_EQ(base::UTF8ToUTF16("CANDIDATE_2"),
797 table
.candidates().at(1).value
);
798 EXPECT_EQ(base::UTF8ToUTF16("LABEL_2"), table
.candidates().at(1).label
);
800 EXPECT_EQ(base::UTF8ToUTF16("CANDIDATE_3"),
801 table
.candidates().at(2).value
);
802 EXPECT_EQ(base::UTF8ToUTF16("LABEL_3"), table
.candidates().at(2).label
);
803 EXPECT_EQ(base::UTF8ToUTF16("ANNOTACTION_3"),
804 table
.candidates().at(2).annotation
);
806 EXPECT_EQ(base::UTF8ToUTF16("CANDIDATE_4"),
807 table
.candidates().at(3).value
);
808 EXPECT_EQ(base::UTF8ToUTF16("LABEL_4"), table
.candidates().at(3).label
);
809 EXPECT_EQ(base::UTF8ToUTF16("ANNOTACTION_4"),
810 table
.candidates().at(3).annotation
);
811 EXPECT_EQ(base::UTF8ToUTF16("TITLE_4"),
812 table
.candidates().at(3).description_title
);
813 EXPECT_EQ(base::UTF8ToUTF16("BODY_4"),
814 table
.candidates().at(3).description_body
);
817 SCOPED_TRACE("setCursorPosition test");
818 mock_input_context
->Reset();
819 mock_candidate_window
->Reset();
821 const char set_cursor_position_test_script
[] =
822 "chrome.input.ime.setCursorPosition({"
823 " contextID: engineBridge.getFocusedContextID().contextID,"
826 ASSERT_TRUE(content::ExecuteScript(
827 host
->host_contents(), set_cursor_position_test_script
));
828 EXPECT_EQ(1, mock_candidate_window
->update_lookup_table_call_count());
830 // window visibility is kept as before.
832 mock_candidate_window
->last_update_lookup_table_arg().is_visible
);
834 const ui::CandidateWindow
& table
=
835 mock_candidate_window
->last_update_lookup_table_arg().lookup_table
;
837 // cursor visibility is kept as before.
838 EXPECT_TRUE(table
.is_cursor_visible());
840 // oritantation is kept as before.
841 EXPECT_EQ(ui::CandidateWindow::VERTICAL
, table
.orientation());
843 // page size is kept as before.
844 EXPECT_EQ(7U, table
.page_size());
846 // candidates are same as before.
847 ASSERT_EQ(4U, table
.candidates().size());
849 // Candidate ID == 2 is 1 in index.
850 EXPECT_EQ(1U, table
.cursor_position());
853 SCOPED_TRACE("setMenuItem test");
854 mock_input_context
->Reset();
855 mock_candidate_window
->Reset();
857 const char set_menu_item_test_script
[] =
858 "chrome.input.ime.setMenuItems({"
859 " engineID: engineBridge.getActiveEngineID(),"
877 " style: 'separator',"
882 ASSERT_TRUE(content::ExecuteScript(
883 host
->host_contents(), set_menu_item_test_script
));
885 const ui::ime::InputMethodMenuItemList
& props
=
886 ui::ime::InputMethodMenuManager::GetInstance()->
887 GetCurrentInputMethodMenuItemList();
888 ASSERT_EQ(5U, props
.size());
890 EXPECT_EQ("ID0", props
[0].key
);
891 EXPECT_EQ("ID1", props
[1].key
);
892 EXPECT_EQ("ID2", props
[2].key
);
893 EXPECT_EQ("ID3", props
[3].key
);
894 EXPECT_EQ("ID4", props
[4].key
);
896 EXPECT_EQ("LABEL1", props
[1].label
);
897 EXPECT_EQ("LABEL2", props
[2].label
);
898 EXPECT_EQ("LABEL3", props
[3].label
);
899 EXPECT_EQ("LABEL4", props
[4].label
);
901 EXPECT_TRUE(props
[2].is_selection_item
);
902 // TODO(nona): Add tests for style: ["toggle" and "separator"]
903 // and visible:, when implement them.
905 EXPECT_TRUE(props
[4].is_selection_item_checked
);
908 SCOPED_TRACE("deleteSurroundingText test");
909 mock_input_context
->Reset();
910 mock_candidate_window
->Reset();
912 const char delete_surrounding_text_test_script
[] =
913 "chrome.input.ime.deleteSurroundingText({"
914 " engineID: engineBridge.getActiveEngineID(),"
915 " contextID: engineBridge.getFocusedContextID().contextID,"
919 ASSERT_TRUE(content::ExecuteScript(
920 host
->host_contents(), delete_surrounding_text_test_script
));
922 EXPECT_EQ(1, mock_input_context
->delete_surrounding_text_call_count());
923 EXPECT_EQ(5, mock_input_context
->last_delete_surrounding_text_arg().offset
);
925 mock_input_context
->last_delete_surrounding_text_arg().length
);
928 SCOPED_TRACE("onFocus test");
929 mock_input_context
->Reset();
930 mock_candidate_window
->Reset();
933 ExtensionTestMessageListener
focus_listener("onFocus:text", false);
934 IMEEngineHandlerInterface::InputContext
context(
935 ui::TEXT_INPUT_TYPE_TEXT
, ui::TEXT_INPUT_MODE_DEFAULT
,
936 ui::TEXT_INPUT_FLAG_NONE
);
937 engine_handler
->FocusIn(context
);
938 ASSERT_TRUE(focus_listener
.WaitUntilSatisfied());
939 ASSERT_TRUE(focus_listener
.was_satisfied());
942 ExtensionTestMessageListener
focus_listener("onFocus:search", false);
943 IMEEngineHandlerInterface::InputContext
context(
944 ui::TEXT_INPUT_TYPE_SEARCH
, ui::TEXT_INPUT_MODE_DEFAULT
,
945 ui::TEXT_INPUT_FLAG_NONE
);
946 engine_handler
->FocusIn(context
);
947 ASSERT_TRUE(focus_listener
.WaitUntilSatisfied());
948 ASSERT_TRUE(focus_listener
.was_satisfied());
951 ExtensionTestMessageListener
focus_listener("onFocus:tel", false);
952 IMEEngineHandlerInterface::InputContext
context(
953 ui::TEXT_INPUT_TYPE_TELEPHONE
, ui::TEXT_INPUT_MODE_DEFAULT
,
954 ui::TEXT_INPUT_FLAG_NONE
);
955 engine_handler
->FocusIn(context
);
956 ASSERT_TRUE(focus_listener
.WaitUntilSatisfied());
957 ASSERT_TRUE(focus_listener
.was_satisfied());
960 ExtensionTestMessageListener
focus_listener("onFocus:url", false);
961 IMEEngineHandlerInterface::InputContext
context(
962 ui::TEXT_INPUT_TYPE_URL
, ui::TEXT_INPUT_MODE_DEFAULT
,
963 ui::TEXT_INPUT_FLAG_NONE
);
964 engine_handler
->FocusIn(context
);
965 ASSERT_TRUE(focus_listener
.WaitUntilSatisfied());
966 ASSERT_TRUE(focus_listener
.was_satisfied());
969 ExtensionTestMessageListener
focus_listener("onFocus:email", false);
970 IMEEngineHandlerInterface::InputContext
context(
971 ui::TEXT_INPUT_TYPE_EMAIL
, ui::TEXT_INPUT_MODE_DEFAULT
,
972 ui::TEXT_INPUT_FLAG_NONE
);
973 engine_handler
->FocusIn(context
);
974 ASSERT_TRUE(focus_listener
.WaitUntilSatisfied());
975 ASSERT_TRUE(focus_listener
.was_satisfied());
978 ExtensionTestMessageListener
focus_listener("onFocus:number", false);
979 IMEEngineHandlerInterface::InputContext
context(
980 ui::TEXT_INPUT_TYPE_NUMBER
, ui::TEXT_INPUT_MODE_DEFAULT
,
981 ui::TEXT_INPUT_FLAG_NONE
);
982 engine_handler
->FocusIn(context
);
983 ASSERT_TRUE(focus_listener
.WaitUntilSatisfied());
984 ASSERT_TRUE(focus_listener
.was_satisfied());
988 IMEBridge::Get()->SetInputContextHandler(NULL
);
989 IMEBridge::Get()->SetCandidateWindowHandler(NULL
);
993 } // namespace input_method
994 } // namespace chromeos