1 // Copyright (c) 2012 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. 4 5 #include "base/bind_helpers.h" 6 #include "chrome/browser/extensions/extension_browsertest.h" 7 #include "chrome/browser/extensions/extension_test_message_listener.h" 8 #include "chrome/common/extensions/background_info.h" 9 #include "chromeos/dbus/dbus_thread_manager.h" 10 #include "chromeos/dbus/ibus/mock_ibus_client.h" 11 #include "chromeos/dbus/ibus/mock_ibus_engine_factory_service.h" 12 #include "chromeos/dbus/ibus/mock_ibus_engine_service.h" 13 #include "chromeos/dbus/mock_dbus_thread_manager_without_gmock.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 "dbus/mock_bus.h" 19 20 namespace chromeos { 21 namespace input_method { 22 namespace { 23 24 const char kIdentityIMEID[] = 25 "_ext_ime_iafoklpfplgfnoimmaejoeondnjnlcfpIdentityIME"; 26 const char kToUpperIMEID[] = 27 "_ext_ime_iafoklpfplgfnoimmaejoeondnjnlcfpToUpperIME"; 28 const char kAPIArgumentIMEID[] = 29 "_ext_ime_iafoklpfplgfnoimmaejoeondnjnlcfpAPIArgumentIME"; 30 31 const uint32 kAltKeyMask = 1 << 3; 32 const uint32 kCtrlKeyMask = 1 << 2; 33 const uint32 kShiftKeyMask = 1 << 0; 34 const uint32 kCapsLockMask = 1 << 1; 35 36 // InputMethod extension should work on 1)normal extension, 2)normal extension 37 // in incognito mode 3)component extension. 38 enum TestType { 39 kTestTypeNormal = 0, 40 kTestTypeIncognito = 1, 41 kTestTypeComponent = 2, 42 }; 43 44 void OnRegisterComponent(const IBusComponent& ibus_component, 45 const IBusClient::RegisterComponentCallback& callback, 46 const IBusClient::ErrorCallback& error_callback) { 47 callback.Run(); 48 } 49 50 class InputMethodEngineIBusBrowserTest 51 : public ExtensionBrowserTest, 52 public ::testing::WithParamInterface<TestType> { 53 public: 54 InputMethodEngineIBusBrowserTest() 55 : ExtensionBrowserTest(), 56 mock_dbus_thread_manager_(NULL) {} 57 virtual ~InputMethodEngineIBusBrowserTest() {} 58 59 virtual void SetUpInProcessBrowserTestFixture() OVERRIDE { 60 mock_dbus_thread_manager_ = new MockDBusThreadManagerWithoutGMock(); 61 DBusThreadManager::InitializeForTesting(mock_dbus_thread_manager_); 62 ExtensionBrowserTest::SetUpInProcessBrowserTestFixture(); 63 } 64 65 virtual void TearDownInProcessBrowserTestFixture() OVERRIDE { 66 DBusThreadManager::Shutdown(); 67 extension_ = NULL; 68 } 69 70 protected: 71 void LoadTestInputMethod() { 72 MockIBusClient* ibus_client = mock_dbus_thread_manager_->mock_ibus_client(); 73 ibus_client->set_register_component_handler( 74 base::Bind(&OnRegisterComponent)); 75 76 // This will load "chrome/test/data/extensions/input_ime" 77 ExtensionTestMessageListener ime_ready_listener("ReadyToUseImeEvent", 78 false); 79 extension_ = LoadExtensionWithType("input_ime", GetParam()); 80 ASSERT_TRUE(extension_); 81 ASSERT_TRUE(ime_ready_listener.WaitUntilSatisfied()); 82 83 // The reason why not EXPECT_EQ is that extension will be reloaded in the 84 // case of incognito mode switching. Thus registeration will be happend 85 // multiple times. Calling at least once per engine is sufficient for IBus 86 // component. Here, there is two engine, thus expectation is at least 4 87 // times. 88 EXPECT_LE(3, ibus_client->register_component_call_count()); 89 90 // Extension IMEs are not enabled by default. 91 std::vector<std::string> extension_ime_ids; 92 extension_ime_ids.push_back(kIdentityIMEID); 93 extension_ime_ids.push_back(kToUpperIMEID); 94 extension_ime_ids.push_back(kAPIArgumentIMEID); 95 InputMethodManager::Get()->SetEnabledExtensionImes(&extension_ime_ids); 96 97 InputMethodDescriptors extension_imes; 98 InputMethodManager::Get()->GetInputMethodExtensions(&extension_imes); 99 100 // Test IME has two input methods, thus InputMethodManager should have two 101 // extension IME. 102 // Note: Even extension is loaded by LoadExtensionAsComponent as above, the 103 // IME does not managed by ComponentExtensionIMEManager or it's id won't 104 // start with __comp__. The component extension IME is whitelisted and 105 // managed by ComponentExtensionIMEManager, but its framework is same as 106 // normal extension IME. 107 EXPECT_EQ(3U, extension_imes.size()); 108 } 109 110 const extensions::Extension* LoadExtensionWithType( 111 const std::string& extension_name, TestType type) { 112 switch (type) { 113 case kTestTypeNormal: 114 return LoadExtension(test_data_dir_.AppendASCII(extension_name)); 115 case kTestTypeIncognito: 116 return LoadExtensionIncognito( 117 test_data_dir_.AppendASCII(extension_name)); 118 case kTestTypeComponent: 119 return LoadExtensionAsComponent( 120 test_data_dir_.AppendASCII(extension_name)); 121 } 122 NOTREACHED(); 123 return NULL; 124 } 125 126 const extensions::Extension* extension_; 127 MockDBusThreadManagerWithoutGMock* mock_dbus_thread_manager_; 128 scoped_refptr<dbus::MockBus> mock_bus_; 129 }; 130 131 class KeyEventDoneCallback { 132 public: 133 explicit KeyEventDoneCallback(bool expected_argument) 134 : expected_argument_(expected_argument), 135 is_called_(false) {} 136 ~KeyEventDoneCallback() {} 137 138 void Run(bool consumed) { 139 if (consumed == expected_argument_) { 140 base::MessageLoop::current()->Quit(); 141 is_called_ = true; 142 } 143 } 144 145 void WaitUntilCalled() { 146 while (!is_called_) 147 content::RunMessageLoop(); 148 } 149 150 private: 151 bool expected_argument_; 152 bool is_called_; 153 154 DISALLOW_COPY_AND_ASSIGN(KeyEventDoneCallback); 155 }; 156 157 INSTANTIATE_TEST_CASE_P(InputMethodEngineIBusBrowserTest, 158 InputMethodEngineIBusBrowserTest, 159 ::testing::Values(kTestTypeNormal)); 160 INSTANTIATE_TEST_CASE_P(InputMethodEngineIBusIncognitoBrowserTest, 161 InputMethodEngineIBusBrowserTest, 162 ::testing::Values(kTestTypeIncognito)); 163 INSTANTIATE_TEST_CASE_P(InputMethodEngineIBusComponentExtensionBrowserTest, 164 InputMethodEngineIBusBrowserTest, 165 ::testing::Values(kTestTypeComponent)); 166 167 IN_PROC_BROWSER_TEST_P(InputMethodEngineIBusBrowserTest, 168 BasicScenarioTest) { 169 LoadTestInputMethod(); 170 171 MockIBusEngineFactoryService* factory_service = 172 mock_dbus_thread_manager_->mock_ibus_engine_factory_service(); 173 factory_service->CallCreateEngine(kIdentityIMEID); 174 175 MockIBusEngineService* engine_service = 176 mock_dbus_thread_manager_->mock_ibus_engine_service(); 177 IBusEngineHandlerInterface* engine_handler = engine_service->GetEngine(); 178 ASSERT_TRUE(engine_handler); 179 180 // onActivate event should be fired if Enable function is called. 181 ExtensionTestMessageListener activated_listener("onActivate", false); 182 engine_handler->Enable(); 183 ASSERT_TRUE(activated_listener.WaitUntilSatisfied()); 184 ASSERT_TRUE(activated_listener.was_satisfied()); 185 186 // onFocus event should be fired if FocusIn function is called. 187 ExtensionTestMessageListener focus_listener("onFocus", false);; 188 engine_handler->FocusIn(); 189 ASSERT_TRUE(focus_listener.WaitUntilSatisfied()); 190 ASSERT_TRUE(focus_listener.was_satisfied()); 191 192 // onKeyEvent should be fired if ProcessKeyEvent is called. 193 KeyEventDoneCallback callback(false); // EchoBackIME doesn't consume keys. 194 ExtensionTestMessageListener keyevent_listener("onKeyEvent", false); 195 engine_handler->ProcessKeyEvent(0x61, // KeySym for 'a'. 196 0x26, // KeyCode for 'a'. 197 0, // No modifiers. 198 base::Bind(&KeyEventDoneCallback::Run, 199 base::Unretained(&callback))); 200 ASSERT_TRUE(keyevent_listener.WaitUntilSatisfied()); 201 ASSERT_TRUE(keyevent_listener.was_satisfied()); 202 callback.WaitUntilCalled(); 203 204 // onSurroundingTextChange should be fired if SetSurroundingText is called. 205 ExtensionTestMessageListener surrounding_text_listener( 206 "onSurroundingTextChanged", false); 207 engine_handler->SetSurroundingText("text", // Surrounding text. 208 0, // focused position. 209 1); // anchor position. 210 ASSERT_TRUE(surrounding_text_listener.WaitUntilSatisfied()); 211 ASSERT_TRUE(surrounding_text_listener.was_satisfied()); 212 213 // onMenuItemActivated should be fired if PropertyActivate is called. 214 ExtensionTestMessageListener property_listener("onMenuItemActivated", false); 215 engine_handler->PropertyActivate("property_name", 216 ibus::IBUS_PROPERTY_STATE_CHECKED); 217 ASSERT_TRUE(property_listener.WaitUntilSatisfied()); 218 ASSERT_TRUE(property_listener.was_satisfied()); 219 220 // onReset should be fired if Reset is called. 221 ExtensionTestMessageListener reset_listener("onReset", false); 222 engine_handler->Reset(); 223 ASSERT_TRUE(reset_listener.WaitUntilSatisfied()); 224 ASSERT_TRUE(reset_listener.was_satisfied()); 225 226 // onBlur should be fired if FocusOut is called. 227 ExtensionTestMessageListener blur_listener("onBlur", false); 228 engine_handler->FocusOut(); 229 ASSERT_TRUE(blur_listener.WaitUntilSatisfied()); 230 ASSERT_TRUE(blur_listener.was_satisfied()); 231 232 // onDeactivated should be fired if Disable is called. 233 ExtensionTestMessageListener disabled_listener("onDeactivated", false); 234 engine_handler->Disable(); 235 ASSERT_TRUE(disabled_listener.WaitUntilSatisfied()); 236 ASSERT_TRUE(disabled_listener.was_satisfied()); 237 } 238 239 IN_PROC_BROWSER_TEST_P(InputMethodEngineIBusBrowserTest, 240 APIArgumentTest) { 241 LoadTestInputMethod(); 242 243 MockIBusEngineFactoryService* factory_service = 244 mock_dbus_thread_manager_->mock_ibus_engine_factory_service(); 245 factory_service->CallCreateEngine(kAPIArgumentIMEID); 246 247 MockIBusEngineService* engine_service = 248 mock_dbus_thread_manager_->mock_ibus_engine_service(); 249 IBusEngineHandlerInterface* engine_handler = engine_service->GetEngine(); 250 ASSERT_TRUE(engine_handler); 251 252 extensions::ExtensionHost* host = FindHostWithPath( 253 extensions::ExtensionSystem::Get(profile())->process_manager(), 254 extensions::BackgroundInfo::GetBackgroundURL(extension_).path(), 255 1); 256 257 engine_handler->Enable(); 258 engine_handler->FocusIn(); 259 260 { 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); 266 267 engine_handler->ProcessKeyEvent(0x61, // KeySym for 'a'. 268 0x26, // KeyCode for 'a'. 269 0, // No modifiers. 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(); 275 } 276 { 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); 282 283 engine_handler->ProcessKeyEvent(0x61, // KeySym for 'a'. 284 0x26, // KeyCode for 'a'. 285 kCtrlKeyMask, 286 base::Bind(&KeyEventDoneCallback::Run, 287 base::Unretained(&callback))); 288 ASSERT_TRUE(keyevent_listener.WaitUntilSatisfied()); 289 EXPECT_TRUE(keyevent_listener.was_satisfied()); 290 callback.WaitUntilCalled(); 291 } 292 { 293 SCOPED_TRACE("KeyDown, Ctrl:No, alt:Yes, Shift:No, Caps:No"); 294 KeyEventDoneCallback callback(false); 295 const std::string expected_value = 296 "onKeyEvent:keydown:a:KeyA:false:true:false:false"; 297 ExtensionTestMessageListener keyevent_listener(expected_value, false); 298 299 engine_handler->ProcessKeyEvent(0x61, // KeySym for 'a'. 300 0x26, // KeyCode for 'a'. 301 kAltKeyMask, 302 base::Bind(&KeyEventDoneCallback::Run, 303 base::Unretained(&callback))); 304 ASSERT_TRUE(keyevent_listener.WaitUntilSatisfied()); 305 EXPECT_TRUE(keyevent_listener.was_satisfied()); 306 callback.WaitUntilCalled(); 307 } 308 { 309 SCOPED_TRACE("KeyDown, Ctrl:No, alt:No, Shift:Yes, Caps:No"); 310 KeyEventDoneCallback callback(false); 311 const std::string expected_value = 312 "onKeyEvent:keydown:a:KeyA:false:false:true:false"; 313 ExtensionTestMessageListener keyevent_listener(expected_value, false); 314 315 engine_handler->ProcessKeyEvent(0x61, // KeySym for 'a'. 316 0x26, // KeyCode for 'a'. 317 kShiftKeyMask, 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(); 323 } 324 { 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); 330 331 engine_handler->ProcessKeyEvent(0x61, // KeySym for 'a'. 332 0x26, // KeyCode for 'a'. 333 kCapsLockMask, 334 base::Bind(&KeyEventDoneCallback::Run, 335 base::Unretained(&callback))); 336 ASSERT_TRUE(keyevent_listener.WaitUntilSatisfied()); 337 EXPECT_TRUE(keyevent_listener.was_satisfied()); 338 callback.WaitUntilCalled(); 339 } 340 { 341 SCOPED_TRACE("KeyDown, Ctrl:Yes, alt:Yes, Shift:No, Caps:No"); 342 KeyEventDoneCallback callback(false); 343 const std::string expected_value = 344 "onKeyEvent:keydown:a:KeyA:true:true:false:false"; 345 ExtensionTestMessageListener keyevent_listener(expected_value, false); 346 347 engine_handler->ProcessKeyEvent(0x61, // KeySym for 'a'. 348 0x26, // KeyCode for 'a'. 349 kAltKeyMask | kCtrlKeyMask, 350 base::Bind(&KeyEventDoneCallback::Run, 351 base::Unretained(&callback))); 352 ASSERT_TRUE(keyevent_listener.WaitUntilSatisfied()); 353 EXPECT_TRUE(keyevent_listener.was_satisfied()); 354 callback.WaitUntilCalled(); 355 } 356 { 357 SCOPED_TRACE("KeyDown, Ctrl:No, alt:No, Shift:Yes, Caps:Yes"); 358 KeyEventDoneCallback callback(false); 359 const std::string expected_value = 360 "onKeyEvent:keydown:a:KeyA:false:false:true:true"; 361 ExtensionTestMessageListener keyevent_listener(expected_value, false); 362 363 engine_handler->ProcessKeyEvent(0x61, // KeySym for 'a'. 364 0x26, // KeyCode for 'a'. 365 kShiftKeyMask | kCapsLockMask, 366 base::Bind(&KeyEventDoneCallback::Run, 367 base::Unretained(&callback))); 368 ASSERT_TRUE(keyevent_listener.WaitUntilSatisfied()); 369 EXPECT_TRUE(keyevent_listener.was_satisfied()); 370 callback.WaitUntilCalled(); 371 } 372 // TODO(nona): Add browser tests for other API as well. 373 { 374 SCOPED_TRACE("commitText test"); 375 const char commit_text_test_script[] = 376 "chrome.input.ime.commitText({" 377 " contextID: engineBridge.getFocusedContextID().contextID," 378 " text:'COMMIT_TEXT'" 379 "});"; 380 381 engine_service->Clear(); 382 ASSERT_TRUE(content::ExecuteScript(host->host_contents(), 383 commit_text_test_script)); 384 EXPECT_EQ(1, engine_service->commit_text_call_count()); 385 EXPECT_EQ("COMMIT_TEXT", engine_service->last_commit_text()); 386 } 387 { 388 SCOPED_TRACE("setComposition test"); 389 const char set_composition_test_script[] = 390 "chrome.input.ime.setComposition({" 391 " contextID: engineBridge.getFocusedContextID().contextID," 392 " text:'COMPOSITION_TEXT'," 393 " cursor:4," 394 " segments : [{" 395 " start: 0," 396 " end: 5," 397 " style: 'underline'" 398 " },{" 399 " start: 6," 400 " end: 10," 401 " style: 'doubleUnderline'" 402 " }]" 403 "});"; 404 405 engine_service->Clear(); 406 ASSERT_TRUE(content::ExecuteScript(host->host_contents(), 407 set_composition_test_script)); 408 EXPECT_EQ(1, engine_service->update_preedit_call_count()); 409 410 EXPECT_EQ(4U, engine_service->last_update_preedit_arg().cursor_pos); 411 EXPECT_TRUE(engine_service->last_update_preedit_arg().is_visible); 412 413 const IBusText& ibus_text = 414 engine_service->last_update_preedit_arg().ibus_text; 415 EXPECT_EQ("COMPOSITION_TEXT", ibus_text.text()); 416 const std::vector<IBusText::UnderlineAttribute>& underlines = 417 ibus_text.underline_attributes(); 418 419 ASSERT_EQ(2U, underlines.size()); 420 EXPECT_EQ(IBusText::IBUS_TEXT_UNDERLINE_SINGLE, underlines[0].type); 421 EXPECT_EQ(0U, underlines[0].start_index); 422 EXPECT_EQ(5U, underlines[0].end_index); 423 424 EXPECT_EQ(IBusText::IBUS_TEXT_UNDERLINE_DOUBLE, underlines[1].type); 425 EXPECT_EQ(6U, underlines[1].start_index); 426 EXPECT_EQ(10U, underlines[1].end_index); 427 } 428 { 429 SCOPED_TRACE("clearComposition test"); 430 const char commite_text_test_script[] = 431 "chrome.input.ime.clearComposition({" 432 " contextID: engineBridge.getFocusedContextID().contextID," 433 "});"; 434 435 engine_service->Clear(); 436 ASSERT_TRUE(content::ExecuteScript(host->host_contents(), 437 commite_text_test_script)); 438 EXPECT_EQ(1, engine_service->update_preedit_call_count()); 439 EXPECT_FALSE(engine_service->last_update_preedit_arg().is_visible); 440 const IBusText& ibus_text = 441 engine_service->last_update_preedit_arg().ibus_text; 442 EXPECT_TRUE(ibus_text.text().empty()); 443 } 444 { 445 SCOPED_TRACE("setCandidateWindowProperties:visibility test"); 446 const char set_candidate_window_properties_test_script[] = 447 "chrome.input.ime.setCandidateWindowProperties({" 448 " engineID: engineBridge.getActiveEngineID()," 449 " properties: {" 450 " visible: true," 451 " }" 452 "});"; 453 engine_service->Clear(); 454 ASSERT_TRUE(content::ExecuteScript( 455 host->host_contents(), 456 set_candidate_window_properties_test_script)); 457 EXPECT_EQ(1, engine_service->update_lookup_table_call_count()); 458 EXPECT_TRUE(engine_service->last_update_lookup_table_arg().is_visible); 459 } 460 { 461 SCOPED_TRACE("setCandidateWindowProperties:cursor_visibility test"); 462 const char set_candidate_window_properties_test_script[] = 463 "chrome.input.ime.setCandidateWindowProperties({" 464 " engineID: engineBridge.getActiveEngineID()," 465 " properties: {" 466 " cursorVisible: true," 467 " }" 468 "});"; 469 engine_service->Clear(); 470 ASSERT_TRUE(content::ExecuteScript( 471 host->host_contents(), 472 set_candidate_window_properties_test_script)); 473 EXPECT_EQ(1, engine_service->update_lookup_table_call_count()); 474 475 // window visibility is kept as before. 476 EXPECT_TRUE(engine_service->last_update_lookup_table_arg().is_visible); 477 478 const IBusLookupTable& table = 479 engine_service->last_update_lookup_table_arg().lookup_table; 480 EXPECT_TRUE(table.is_cursor_visible()); 481 } 482 { 483 SCOPED_TRACE("setCandidateWindowProperties:vertical test"); 484 const char set_candidate_window_properties_test_script[] = 485 "chrome.input.ime.setCandidateWindowProperties({" 486 " engineID: engineBridge.getActiveEngineID()," 487 " properties: {" 488 " vertical: true," 489 " }" 490 "});"; 491 engine_service->Clear(); 492 ASSERT_TRUE(content::ExecuteScript( 493 host->host_contents(), 494 set_candidate_window_properties_test_script)); 495 EXPECT_EQ(1, engine_service->update_lookup_table_call_count()); 496 497 // window visibility is kept as before. 498 EXPECT_TRUE(engine_service->last_update_lookup_table_arg().is_visible); 499 500 const IBusLookupTable& table = 501 engine_service->last_update_lookup_table_arg().lookup_table; 502 503 // cursor visibility is kept as before. 504 EXPECT_TRUE(table.is_cursor_visible()); 505 506 EXPECT_EQ(IBusLookupTable::VERTICAL, table.orientation()); 507 } 508 { 509 SCOPED_TRACE("setCandidateWindowProperties:pageSize test"); 510 const char set_candidate_window_properties_test_script[] = 511 "chrome.input.ime.setCandidateWindowProperties({" 512 " engineID: engineBridge.getActiveEngineID()," 513 " properties: {" 514 " pageSize: 7," 515 " }" 516 "});"; 517 engine_service->Clear(); 518 ASSERT_TRUE(content::ExecuteScript( 519 host->host_contents(), 520 set_candidate_window_properties_test_script)); 521 EXPECT_EQ(1, engine_service->update_lookup_table_call_count()); 522 523 // window visibility is kept as before. 524 EXPECT_TRUE(engine_service->last_update_lookup_table_arg().is_visible); 525 526 const IBusLookupTable& table = 527 engine_service->last_update_lookup_table_arg().lookup_table; 528 529 // cursor visibility is kept as before. 530 EXPECT_TRUE(table.is_cursor_visible()); 531 532 // oritantation is kept as before. 533 EXPECT_EQ(IBusLookupTable::VERTICAL, table.orientation()); 534 535 EXPECT_EQ(7U, table.page_size()); 536 } 537 { 538 SCOPED_TRACE("setCandidateWindowProperties:auxTextVisibility test"); 539 const char set_candidate_window_properties_test_script[] = 540 "chrome.input.ime.setCandidateWindowProperties({" 541 " engineID: engineBridge.getActiveEngineID()," 542 " properties: {" 543 " auxiliaryTextVisible: true" 544 " }" 545 "});"; 546 engine_service->Clear(); 547 ASSERT_TRUE(content::ExecuteScript( 548 host->host_contents(), 549 set_candidate_window_properties_test_script)); 550 EXPECT_EQ(1, engine_service->update_auxiliary_text_call_count()); 551 EXPECT_TRUE(engine_service->last_update_aux_text_arg().is_visible); 552 } 553 { 554 SCOPED_TRACE("setCandidateWindowProperties:auxText test"); 555 const char set_candidate_window_properties_test_script[] = 556 "chrome.input.ime.setCandidateWindowProperties({" 557 " engineID: engineBridge.getActiveEngineID()," 558 " properties: {" 559 " auxiliaryText: 'AUXILIARY_TEXT'" 560 " }" 561 "});"; 562 engine_service->Clear(); 563 ASSERT_TRUE(content::ExecuteScript( 564 host->host_contents(), 565 set_candidate_window_properties_test_script)); 566 EXPECT_EQ(1, engine_service->update_auxiliary_text_call_count()); 567 568 // aux text visibility is kept as before. 569 EXPECT_TRUE(engine_service->last_update_aux_text_arg().is_visible); 570 571 EXPECT_EQ("AUXILIARY_TEXT", 572 engine_service->last_update_aux_text_arg().ibus_text.text()); 573 } 574 { 575 SCOPED_TRACE("setCandidates test"); 576 const char set_candidates_test_script[] = 577 "chrome.input.ime.setCandidates({" 578 " contextID: engineBridge.getFocusedContextID().contextID," 579 " candidates: [{" 580 " candidate: 'CANDIDATE_1'," 581 " id: 1," 582 " },{" 583 " candidate: 'CANDIDATE_2'," 584 " id: 2," 585 " label: 'LABEL_2'," 586 " },{" 587 " candidate: 'CANDIDATE_3'," 588 " id: 3," 589 " label: 'LABEL_3'," 590 " annotation: 'ANNOTACTION_3'" 591 " },{" 592 " candidate: 'CANDIDATE_4'," 593 " id: 4," 594 " label: 'LABEL_4'," 595 " annotation: 'ANNOTACTION_4'," 596 " usage: {" 597 " title: 'TITLE_4'," 598 " body: 'BODY_4'" 599 " }" 600 " }]" 601 "});"; 602 engine_service->Clear(); 603 ASSERT_TRUE(content::ExecuteScript(host->host_contents(), 604 set_candidates_test_script)); 605 606 // window visibility is kept as before. 607 EXPECT_TRUE(engine_service->last_update_lookup_table_arg().is_visible); 608 609 const IBusLookupTable& table = 610 engine_service->last_update_lookup_table_arg().lookup_table; 611 612 // cursor visibility is kept as before. 613 EXPECT_TRUE(table.is_cursor_visible()); 614 615 // oritantation is kept as before. 616 EXPECT_EQ(IBusLookupTable::VERTICAL, table.orientation()); 617 618 // page size is kept as before. 619 EXPECT_EQ(7U, table.page_size()); 620 621 ASSERT_EQ(4U, table.candidates().size()); 622 623 EXPECT_EQ("CANDIDATE_1", table.candidates().at(0).value); 624 625 EXPECT_EQ("CANDIDATE_2", table.candidates().at(1).value); 626 EXPECT_EQ("LABEL_2", table.candidates().at(1).label); 627 628 EXPECT_EQ("CANDIDATE_3", table.candidates().at(2).value); 629 EXPECT_EQ("LABEL_3", table.candidates().at(2).label); 630 EXPECT_EQ("ANNOTACTION_3", table.candidates().at(2).annotation); 631 632 EXPECT_EQ("CANDIDATE_4", table.candidates().at(3).value); 633 EXPECT_EQ("LABEL_4", table.candidates().at(3).label); 634 EXPECT_EQ("ANNOTACTION_4", table.candidates().at(3).annotation); 635 EXPECT_EQ("TITLE_4", table.candidates().at(3).description_title); 636 EXPECT_EQ("BODY_4", table.candidates().at(3).description_body); 637 } 638 { 639 SCOPED_TRACE("setCursorPosition test"); 640 const char set_cursor_position_test_script[] = 641 "chrome.input.ime.setCursorPosition({" 642 " contextID: engineBridge.getFocusedContextID().contextID," 643 " candidateID: 2" 644 "});"; 645 engine_service->Clear(); 646 ASSERT_TRUE(content::ExecuteScript( 647 host->host_contents(), set_cursor_position_test_script)); 648 EXPECT_EQ(1, engine_service->update_lookup_table_call_count()); 649 650 // window visibility is kept as before. 651 EXPECT_TRUE(engine_service->last_update_lookup_table_arg().is_visible); 652 653 const IBusLookupTable& table = 654 engine_service->last_update_lookup_table_arg().lookup_table; 655 656 // cursor visibility is kept as before. 657 EXPECT_TRUE(table.is_cursor_visible()); 658 659 // oritantation is kept as before. 660 EXPECT_EQ(IBusLookupTable::VERTICAL, table.orientation()); 661 662 // page size is kept as before. 663 EXPECT_EQ(7U, table.page_size()); 664 665 // candidates are same as before. 666 ASSERT_EQ(4U, table.candidates().size()); 667 668 // Candidate ID == 2 is 1 in index. 669 EXPECT_EQ(1U, table.cursor_position()); 670 } 671 { 672 SCOPED_TRACE("setMenuItem test"); 673 const char set_menu_item_test_script[] = 674 "chrome.input.ime.setMenuItems({" 675 " engineID: engineBridge.getActiveEngineID()," 676 " items: [{" 677 " id: 'ID0'," 678 " },{" 679 " id: 'ID1'," 680 " label: 'LABEL1'," 681 " },{" 682 " id: 'ID2'," 683 " label: 'LABEL2'," 684 " style: 'radio'," 685 " },{" 686 " id: 'ID3'," 687 " label: 'LABEL3'," 688 " style: 'check'," 689 " visible: true," 690 " },{" 691 " id: 'ID4'," 692 " label: 'LABEL4'," 693 " style: 'separator'," 694 " visible: true," 695 " checked: true" 696 " }]" 697 "});"; 698 engine_service->Clear(); 699 ASSERT_TRUE(content::ExecuteScript( 700 host->host_contents(), set_menu_item_test_script)); 701 EXPECT_EQ(1, engine_service->register_properties_call_count()); 702 703 const IBusPropertyList& props = 704 engine_service->last_registered_properties(); 705 ASSERT_EQ(5U, props.size()); 706 707 EXPECT_EQ("ID0", props[0]->key()); 708 EXPECT_EQ("ID1", props[1]->key()); 709 EXPECT_EQ("ID2", props[2]->key()); 710 EXPECT_EQ("ID3", props[3]->key()); 711 EXPECT_EQ("ID4", props[4]->key()); 712 713 EXPECT_EQ("LABEL1", props[1]->label()); 714 EXPECT_EQ("LABEL2", props[2]->label()); 715 EXPECT_EQ("LABEL3", props[3]->label()); 716 EXPECT_EQ("LABEL4", props[4]->label()); 717 718 EXPECT_EQ(IBusProperty::IBUS_PROPERTY_TYPE_RADIO, props[2]->type()); 719 EXPECT_EQ(IBusProperty::IBUS_PROPERTY_TYPE_TOGGLE, props[3]->type()); 720 EXPECT_EQ(IBusProperty::IBUS_PROPERTY_TYPE_SEPARATOR, props[4]->type()); 721 722 EXPECT_TRUE(props[3]->visible()); 723 EXPECT_TRUE(props[4]->visible()); 724 725 EXPECT_TRUE(props[4]->checked()); 726 } 727 { 728 SCOPED_TRACE("deleteSurroundingText test"); 729 const char delete_surrounding_text_test_script[] = 730 "chrome.input.ime.deleteSurroundingText({" 731 " engineID: engineBridge.getActiveEngineID()," 732 " contextID: engineBridge.getFocusedContextID().contextID," 733 " offset: 5," 734 " length: 3" 735 "});"; 736 engine_service->Clear(); 737 ASSERT_TRUE(content::ExecuteScript( 738 host->host_contents(), delete_surrounding_text_test_script)); 739 740 EXPECT_EQ(1, engine_service->delete_surrounding_text_call_count()); 741 EXPECT_EQ(5, engine_service->last_delete_surrounding_text_arg().offset); 742 EXPECT_EQ(3U, engine_service->last_delete_surrounding_text_arg().length); 743 } 744 } 745 746 } // namespace 747 } // namespace input_method 748 } // namespace chromeos 749