input_method_manager_impl_unittest.cc revision 68043e1e95eeb07d5cae7aca370b26518b0867d6
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 "chrome/browser/chromeos/input_method/input_method_manager_impl.h" 6 7#include <algorithm> 8 9#include "base/basictypes.h" 10#include "base/bind.h" 11#include "base/bind_helpers.h" 12#include "base/compiler_specific.h" 13#include "base/logging.h" 14#include "base/memory/scoped_ptr.h" 15#include "base/message_loop/message_loop.h" 16#include "chrome/browser/chromeos/input_method/mock_candidate_window_controller.h" 17#include "chrome/browser/chromeos/input_method/mock_ibus_controller.h" 18#include "chromeos/dbus/ibus/mock_ibus_client.h" 19#include "chromeos/dbus/mock_dbus_thread_manager_without_gmock.h" 20#include "chromeos/ime/extension_ime_util.h" 21#include "chromeos/ime/fake_input_method_delegate.h" 22#include "chromeos/ime/mock_component_extension_ime_manager_delegate.h" 23#include "chromeos/ime/mock_ibus_daemon_controller.h" 24#include "chromeos/ime/mock_ime_engine_handler.h" 25#include "chromeos/ime/mock_xkeyboard.h" 26#include "testing/gtest/include/gtest/gtest.h" 27#include "ui/base/accelerators/accelerator.h" 28#include "ui/events/keycodes/keyboard_codes.h" 29 30namespace chromeos { 31 32namespace input_method { 33namespace { 34 35const char nacl_mozc_us_id[] = 36 "_comp_ime_fpfbhcjppmaeaijcidgiibchfbnhbeljnacl_mozc_us"; 37const char nacl_mozc_jp_id[] = 38 "_comp_ime_fpfbhcjppmaeaijcidgiibchfbnhbeljnacl_mozc_jp"; 39 40// Returns true if |descriptors| contain |target|. 41bool Contain(const InputMethodDescriptors& descriptors, 42 const InputMethodDescriptor& target) { 43 for (size_t i = 0; i < descriptors.size(); ++i) { 44 if (descriptors[i].id() == target.id()) 45 return true; 46 } 47 return false; 48} 49 50class InputMethodManagerImplTest : public testing::Test { 51 public: 52 InputMethodManagerImplTest() 53 : delegate_(NULL), 54 controller_(NULL), 55 candidate_window_controller_(NULL), 56 xkeyboard_(NULL) { 57 } 58 virtual ~InputMethodManagerImplTest() {} 59 60 virtual void SetUp() OVERRIDE { 61 mock_ibus_daemon_controller_ = new chromeos::MockIBusDaemonController(); 62 chromeos::IBusDaemonController::InitializeForTesting( 63 mock_ibus_daemon_controller_); 64 mock_dbus_thread_manager_ = 65 new chromeos::MockDBusThreadManagerWithoutGMock(); 66 chromeos::DBusThreadManager::InitializeForTesting( 67 mock_dbus_thread_manager_); 68 delegate_ = new FakeInputMethodDelegate(); 69 manager_.reset(new InputMethodManagerImpl( 70 scoped_ptr<InputMethodDelegate>(delegate_))); 71 controller_ = new MockIBusController; 72 manager_->SetIBusControllerForTesting(controller_); 73 candidate_window_controller_ = new MockCandidateWindowController; 74 manager_->SetCandidateWindowControllerForTesting( 75 candidate_window_controller_); 76 xkeyboard_ = new MockXKeyboard; 77 manager_->SetXKeyboardForTesting(xkeyboard_); 78 mock_engine_handler_.reset(new MockIMEEngineHandler()); 79 IBusBridge::Initialize(); 80 IBusBridge::Get()->SetEngineHandler(mock_engine_handler_.get()); 81 82 ime_list_.clear(); 83 84 ComponentExtensionIME ext1; 85 ext1.id = "fpfbhcjppmaeaijcidgiibchfbnhbelj"; 86 ext1.description = "ext1_description"; 87 ext1.path = base::FilePath("ext1_file_path"); 88 89 ComponentExtensionEngine ext1_engine1; 90 ext1_engine1.engine_id = "nacl_mozc_us"; 91 ext1_engine1.display_name = "ext1_engine_1_display_name"; 92 ext1_engine1.language_codes.push_back("ja"); 93 ext1_engine1.layouts.push_back("us"); 94 ext1.engines.push_back(ext1_engine1); 95 96 ComponentExtensionEngine ext1_engine2; 97 ext1_engine2.engine_id = "nacl_mozc_jp"; 98 ext1_engine2.display_name = "ext1_engine_1_display_name"; 99 ext1_engine2.language_codes.push_back("ja"); 100 ext1_engine2.layouts.push_back("jp"); 101 ext1.engines.push_back(ext1_engine2); 102 103 ime_list_.push_back(ext1); 104 105 ComponentExtensionIME ext2; 106 ext2.id = "nmblnjkfdkabgdofidlkienfnnbjhnab"; 107 ext2.description = "ext2_description"; 108 ext2.path = base::FilePath("ext2_file_path"); 109 110 ComponentExtensionEngine ext2_engine1; 111 ext2_engine1.engine_id = "ext2_engine1_engine_id"; 112 ext2_engine1.display_name = "ext2_engine_1_display_name"; 113 ext2_engine1.language_codes.push_back("en"); 114 ext2_engine1.layouts.push_back("us"); 115 ext2.engines.push_back(ext2_engine1); 116 117 ComponentExtensionEngine ext2_engine2; 118 ext2_engine2.engine_id = "ext2_engine2_engine_id"; 119 ext2_engine2.display_name = "ext2_engine_2_display_name"; 120 ext2_engine2.language_codes.push_back("en"); 121 ext2_engine2.layouts.push_back("us(dvorak)"); 122 ext2.engines.push_back(ext2_engine2); 123 124 ime_list_.push_back(ext2); 125 126 mock_ibus_daemon_controller_->EmulateConnect(); 127 } 128 129 virtual void TearDown() OVERRIDE { 130 mock_ibus_daemon_controller_->EmulateDisconnect(); 131 delegate_ = NULL; 132 controller_ = NULL; 133 candidate_window_controller_ = NULL; 134 xkeyboard_ = NULL; 135 manager_.reset(); 136 IBusBridge::Get()->SetEngineHandler(NULL); 137 IBusBridge::Shutdown(); 138 chromeos::DBusThreadManager::Shutdown(); 139 chromeos::IBusDaemonController::Shutdown(); 140 } 141 142 protected: 143 // Helper function to initialize component extension stuff for testing. 144 void InitComponentExtension() { 145 mock_delegate_ = new MockComponentExtIMEManagerDelegate(); 146 mock_delegate_->set_ime_list(ime_list_); 147 scoped_ptr<ComponentExtensionIMEManagerDelegate> delegate(mock_delegate_); 148 manager_->InitializeComponentExtensionForTesting(delegate.Pass()); 149 } 150 151 // Helper function to initialize IBus bus connection for testing. Do not use 152 // ibus related mocks before calling this function. 153 void InitIBusBus() { 154 mock_dbus_thread_manager_->InitIBusBus("dummy address", 155 base::Bind(&base::DoNothing)); 156 mock_ibus_client_ = mock_dbus_thread_manager_->mock_ibus_client(); 157 mock_ibus_daemon_controller_->EmulateConnect(); 158 } 159 160 scoped_ptr<InputMethodManagerImpl> manager_; 161 FakeInputMethodDelegate* delegate_; 162 MockIBusController* controller_; 163 MockCandidateWindowController* candidate_window_controller_; 164 MockIBusDaemonController* mock_ibus_daemon_controller_; 165 scoped_ptr<MockIMEEngineHandler> mock_engine_handler_; 166 MockIBusClient* mock_ibus_client_; 167 MockDBusThreadManagerWithoutGMock* mock_dbus_thread_manager_; 168 MockXKeyboard* xkeyboard_; 169 base::MessageLoop message_loop_; 170 MockComponentExtIMEManagerDelegate* mock_delegate_; 171 std::vector<ComponentExtensionIME> ime_list_; 172 173 private: 174 DISALLOW_COPY_AND_ASSIGN(InputMethodManagerImplTest); 175}; 176 177class TestableComponentExtensionIMEManager 178 : public ComponentExtensionIMEManager { 179 public: 180 using ComponentExtensionIMEManager::GetComponentExtensionIMEId; 181}; 182 183class TestObserver : public InputMethodManager::Observer { 184 public: 185 TestObserver() 186 : input_method_changed_count_(0), 187 input_method_property_changed_count_(0), 188 last_show_message_(false) { 189 } 190 virtual ~TestObserver() {} 191 192 virtual void InputMethodChanged(InputMethodManager* manager, 193 bool show_message) OVERRIDE { 194 ++input_method_changed_count_; 195 last_show_message_ = show_message; 196 } 197 virtual void InputMethodPropertyChanged( 198 InputMethodManager* manager) OVERRIDE { 199 ++input_method_property_changed_count_; 200 } 201 202 int input_method_changed_count_; 203 int input_method_property_changed_count_; 204 bool last_show_message_; 205 206 private: 207 DISALLOW_COPY_AND_ASSIGN(TestObserver); 208}; 209 210class TestCandidateWindowObserver 211 : public InputMethodManager::CandidateWindowObserver { 212 public: 213 TestCandidateWindowObserver() 214 : candidate_window_opened_count_(0), 215 candidate_window_closed_count_(0) { 216 } 217 virtual ~TestCandidateWindowObserver() {} 218 219 virtual void CandidateWindowOpened(InputMethodManager* manager) OVERRIDE { 220 ++candidate_window_opened_count_; 221 } 222 virtual void CandidateWindowClosed(InputMethodManager* manager) OVERRIDE { 223 ++candidate_window_closed_count_; 224 } 225 226 int candidate_window_opened_count_; 227 int candidate_window_closed_count_; 228 229 private: 230 DISALLOW_COPY_AND_ASSIGN(TestCandidateWindowObserver); 231}; 232 233} // namespace 234 235TEST_F(InputMethodManagerImplTest, TestGetXKeyboard) { 236 EXPECT_TRUE(manager_->GetXKeyboard()); 237 EXPECT_EQ(xkeyboard_, manager_->GetXKeyboard()); 238} 239 240TEST_F(InputMethodManagerImplTest, TestCandidateWindowObserver) { 241 TestCandidateWindowObserver observer; 242 candidate_window_controller_->NotifyCandidateWindowOpened(); // nop 243 candidate_window_controller_->NotifyCandidateWindowClosed(); // nop 244 manager_->AddCandidateWindowObserver(&observer); 245 candidate_window_controller_->NotifyCandidateWindowOpened(); 246 EXPECT_EQ(1, observer.candidate_window_opened_count_); 247 candidate_window_controller_->NotifyCandidateWindowClosed(); 248 EXPECT_EQ(1, observer.candidate_window_closed_count_); 249 candidate_window_controller_->NotifyCandidateWindowOpened(); 250 EXPECT_EQ(2, observer.candidate_window_opened_count_); 251 candidate_window_controller_->NotifyCandidateWindowClosed(); 252 EXPECT_EQ(2, observer.candidate_window_closed_count_); 253 manager_->RemoveCandidateWindowObserver(&observer); 254} 255 256TEST_F(InputMethodManagerImplTest, TestObserver) { 257 // For http://crbug.com/19655#c11 - (3). browser_state_monitor_unittest.cc is 258 // also for the scenario. 259 TestObserver observer; 260 InitComponentExtension(); 261 InitIBusBus(); 262 manager_->AddObserver(&observer); 263 EXPECT_EQ(0, observer.input_method_changed_count_); 264 manager_->EnableLayouts("en-US", "xkb:us::eng"); 265 EXPECT_EQ(1, observer.input_method_changed_count_); 266 EXPECT_EQ(1, observer.input_method_property_changed_count_); 267 manager_->ChangeInputMethod("xkb:us:dvorak:eng"); 268 EXPECT_FALSE(observer.last_show_message_); 269 EXPECT_EQ(2, observer.input_method_changed_count_); 270 EXPECT_EQ(2, observer.input_method_property_changed_count_); 271 manager_->ChangeInputMethod("xkb:us:dvorak:eng"); 272 EXPECT_FALSE(observer.last_show_message_); 273 // The observer is always notified even when the same input method ID is 274 // passed to ChangeInputMethod() more than twice. 275 EXPECT_EQ(3, observer.input_method_changed_count_); 276 EXPECT_EQ(3, observer.input_method_property_changed_count_); 277 278 controller_->NotifyPropertyChangedForTesting(); 279 EXPECT_EQ(4, observer.input_method_property_changed_count_); 280 controller_->NotifyPropertyChangedForTesting(); 281 EXPECT_EQ(5, observer.input_method_property_changed_count_); 282 manager_->RemoveObserver(&observer); 283} 284 285TEST_F(InputMethodManagerImplTest, TestGetSupportedInputMethods) { 286 InitComponentExtension(); 287 InitIBusBus(); 288 scoped_ptr<InputMethodDescriptors> methods( 289 manager_->GetSupportedInputMethods()); 290 ASSERT_TRUE(methods.get()); 291 // Try to find random 4-5 layuts and IMEs to make sure the returned list is 292 // correct. 293 const InputMethodDescriptor* id_to_find = 294 manager_->GetInputMethodUtil()->GetInputMethodDescriptorFromId( 295 nacl_mozc_us_id); 296 id_to_find = manager_->GetInputMethodUtil()->GetInputMethodDescriptorFromId( 297 "xkb:us::eng"); 298 EXPECT_TRUE(Contain(*methods.get(), *id_to_find)); 299 id_to_find = manager_->GetInputMethodUtil()->GetInputMethodDescriptorFromId( 300 "xkb:us:dvorak:eng"); 301 EXPECT_TRUE(Contain(*methods.get(), *id_to_find)); 302 id_to_find = manager_->GetInputMethodUtil()->GetInputMethodDescriptorFromId( 303 "xkb:fr::fra"); 304 EXPECT_TRUE(Contain(*methods.get(), *id_to_find)); 305} 306 307TEST_F(InputMethodManagerImplTest, TestEnableLayouts) { 308 // Currently 5 keyboard layouts are supported for en-US, and 1 for ja. See 309 // ibus_input_method.txt. 310 InitComponentExtension(); 311 InitIBusBus(); 312 manager_->EnableLayouts("en-US", ""); 313 EXPECT_EQ(5U, manager_->GetNumActiveInputMethods()); 314 for (size_t i = 0; i < manager_->GetActiveInputMethodIds().size(); ++i) 315 LOG(ERROR) << manager_->GetActiveInputMethodIds().at(i); 316 // For http://crbug.com/19655#c11 - (2) 317 EXPECT_EQ(0, mock_ibus_daemon_controller_->start_count()); 318 319 // For http://crbug.com/19655#c11 - (5) 320 // The hardware keyboard layout "xkb:us::eng" is always active, hence 2U. 321 manager_->EnableLayouts("ja", ""); // Japanese 322 EXPECT_EQ(2U, manager_->GetNumActiveInputMethods()); 323 EXPECT_EQ(0, mock_ibus_daemon_controller_->start_count()); 324} 325 326TEST_F(InputMethodManagerImplTest, TestEnableLayoutsNonUsHardwareKeyboard) { 327 // The physical layout is French. 328 delegate_->set_hardware_keyboard_layout("xkb:fr::fra"); 329 manager_->EnableLayouts("en-US", ""); 330 EXPECT_EQ(6U, manager_->GetNumActiveInputMethods()); // 5 + French 331 // The physical layout is Japanese. 332 delegate_->set_hardware_keyboard_layout("xkb:jp::jpn"); 333 manager_->EnableLayouts("ja", ""); 334 // "xkb:us::eng" is not needed, hence 1. 335 EXPECT_EQ(1U, manager_->GetNumActiveInputMethods()); 336} 337 338TEST_F(InputMethodManagerImplTest, TestActiveInputMethods) { 339 manager_->EnableLayouts("ja", ""); // Japanese 340 EXPECT_EQ(2U, manager_->GetNumActiveInputMethods()); 341 scoped_ptr<InputMethodDescriptors> methods( 342 manager_->GetActiveInputMethods()); 343 ASSERT_TRUE(methods.get()); 344 EXPECT_EQ(2U, methods->size()); 345 const InputMethodDescriptor* id_to_find = 346 manager_->GetInputMethodUtil()->GetInputMethodDescriptorFromId( 347 "xkb:us::eng"); 348 EXPECT_TRUE(Contain(*methods.get(), *id_to_find)); 349 id_to_find = manager_->GetInputMethodUtil()->GetInputMethodDescriptorFromId( 350 "xkb:jp::jpn"); 351 EXPECT_TRUE(Contain(*methods.get(), *id_to_find)); 352} 353 354TEST_F(InputMethodManagerImplTest, TestEnableTwoLayouts) { 355 // For http://crbug.com/19655#c11 - (8), step 6. 356 TestObserver observer; 357 manager_->AddObserver(&observer); 358 InitComponentExtension(); 359 InitIBusBus(); 360 manager_->SetState(InputMethodManager::STATE_BROWSER_SCREEN); 361 std::vector<std::string> ids; 362 ids.push_back("xkb:us:dvorak:eng"); 363 ids.push_back("xkb:us:colemak:eng"); 364 EXPECT_TRUE(manager_->EnableInputMethods(ids)); 365 EXPECT_EQ(2U, manager_->GetNumActiveInputMethods()); 366 // Since all the IDs added avobe are keyboard layouts, Start() should not be 367 // called. 368 EXPECT_EQ(0, mock_ibus_daemon_controller_->start_count()); 369 EXPECT_EQ(1, observer.input_method_changed_count_); 370 EXPECT_EQ(ids[0], manager_->GetCurrentInputMethod().id()); 371 EXPECT_EQ("us(dvorak)", xkeyboard_->last_layout_); 372 // Disable Dvorak. 373 ids.erase(ids.begin()); 374 EXPECT_TRUE(manager_->EnableInputMethods(ids)); 375 EXPECT_EQ(1U, manager_->GetNumActiveInputMethods()); 376 EXPECT_EQ(2, observer.input_method_changed_count_); 377 EXPECT_EQ(ids[0], // colemak 378 manager_->GetCurrentInputMethod().id()); 379 EXPECT_EQ("us(colemak)", xkeyboard_->last_layout_); 380 manager_->RemoveObserver(&observer); 381} 382 383TEST_F(InputMethodManagerImplTest, TestEnableThreeLayouts) { 384 // For http://crbug.com/19655#c11 - (9). 385 TestObserver observer; 386 manager_->AddObserver(&observer); 387 InitComponentExtension(); 388 InitIBusBus(); 389 manager_->SetState(InputMethodManager::STATE_BROWSER_SCREEN); 390 std::vector<std::string> ids; 391 ids.push_back("xkb:us::eng"); 392 ids.push_back("xkb:us:dvorak:eng"); 393 ids.push_back("xkb:us:colemak:eng"); 394 EXPECT_TRUE(manager_->EnableInputMethods(ids)); 395 EXPECT_EQ(3U, manager_->GetNumActiveInputMethods()); 396 EXPECT_EQ(1, observer.input_method_changed_count_); 397 EXPECT_EQ(ids[0], manager_->GetCurrentInputMethod().id()); 398 EXPECT_EQ("us", xkeyboard_->last_layout_); 399 // Switch to Dvorak. 400 manager_->SwitchToNextInputMethod(); 401 EXPECT_EQ(2, observer.input_method_changed_count_); 402 EXPECT_EQ(ids[1], manager_->GetCurrentInputMethod().id()); 403 EXPECT_EQ("us(dvorak)", xkeyboard_->last_layout_); 404 // Disable Dvorak. 405 ids.erase(ids.begin() + 1); 406 EXPECT_TRUE(manager_->EnableInputMethods(ids)); 407 EXPECT_EQ(2U, manager_->GetNumActiveInputMethods()); 408 EXPECT_EQ(3, observer.input_method_changed_count_); 409 EXPECT_EQ(ids[0], // US Qwerty 410 manager_->GetCurrentInputMethod().id()); 411 EXPECT_EQ("us", xkeyboard_->last_layout_); 412 manager_->RemoveObserver(&observer); 413} 414 415TEST_F(InputMethodManagerImplTest, TestEnableLayoutAndIme) { 416 // For http://crbug.com/19655#c11 - (10). 417 TestObserver observer; 418 manager_->AddObserver(&observer); 419 InitComponentExtension(); 420 InitIBusBus(); 421 manager_->SetState(InputMethodManager::STATE_BROWSER_SCREEN); 422 std::vector<std::string> ids; 423 ids.push_back("xkb:us:dvorak:eng"); 424 ids.push_back(nacl_mozc_us_id); 425 EXPECT_TRUE(manager_->EnableInputMethods(ids)); 426 EXPECT_EQ(1, mock_ibus_daemon_controller_->start_count()); 427 EXPECT_EQ(1, observer.input_method_changed_count_); 428 EXPECT_EQ(ids[0], manager_->GetCurrentInputMethod().id()); 429 EXPECT_EQ("us(dvorak)", xkeyboard_->last_layout_); 430 // Switch to Mozc 431 manager_->SwitchToNextInputMethod(); 432 EXPECT_EQ(2, observer.input_method_changed_count_); 433 EXPECT_EQ(ids[1], manager_->GetCurrentInputMethod().id()); 434 EXPECT_EQ("us", xkeyboard_->last_layout_); 435 // Disable Mozc. 436 ids.erase(ids.begin() + 1); 437 EXPECT_TRUE(manager_->EnableInputMethods(ids)); 438 EXPECT_EQ(1U, manager_->GetNumActiveInputMethods()); 439 EXPECT_EQ(ids[0], manager_->GetCurrentInputMethod().id()); 440 EXPECT_EQ("us(dvorak)", xkeyboard_->last_layout_); 441 // Currently, to work around a crash issue at crosbug.com/27051, 442 // controller_->Stop(); is NOT called when all IMEs are disabled 443 // or on shutdown. 444 EXPECT_EQ(0, mock_ibus_daemon_controller_->stop_count()); 445 446 manager_->SetState(InputMethodManager::STATE_TERMINATING); 447 EXPECT_EQ(0, mock_ibus_daemon_controller_->stop_count()); 448 manager_->RemoveObserver(&observer); 449} 450 451TEST_F(InputMethodManagerImplTest, TestEnableLayoutAndIme2) { 452 // For http://crbug.com/19655#c11 - (11). 453 TestObserver observer; 454 manager_->AddObserver(&observer); 455 InitComponentExtension(); 456 InitIBusBus(); 457 manager_->SetState(InputMethodManager::STATE_BROWSER_SCREEN); 458 std::vector<std::string> ids; 459 ids.push_back("xkb:us:dvorak:eng"); 460 ids.push_back(nacl_mozc_us_id); 461 EXPECT_TRUE(manager_->EnableInputMethods(ids)); 462 EXPECT_EQ(1, mock_ibus_daemon_controller_->start_count()); 463 EXPECT_EQ(1, observer.input_method_changed_count_); 464 EXPECT_EQ(ids[0], manager_->GetCurrentInputMethod().id()); 465 EXPECT_EQ("us(dvorak)", xkeyboard_->last_layout_); 466 467 // Disable Dvorak. 468 ids.erase(ids.begin()); 469 EXPECT_TRUE(manager_->EnableInputMethods(ids)); 470 EXPECT_EQ(1U, manager_->GetNumActiveInputMethods()); 471 EXPECT_EQ(ids[0], // Mozc 472 manager_->GetCurrentInputMethod().id()); 473 EXPECT_EQ("us", xkeyboard_->last_layout_); 474 manager_->RemoveObserver(&observer); 475} 476 477TEST_F(InputMethodManagerImplTest, TestEnableImes) { 478 TestObserver observer; 479 manager_->AddObserver(&observer); 480 InitComponentExtension(); 481 InitIBusBus(); 482 manager_->SetState(InputMethodManager::STATE_BROWSER_SCREEN); 483 std::vector<std::string> ids; 484 ids.push_back("_comp_ime_nmblnjkfdkabgdofidlkienfnnbjhnabext2_engine1_engine_id"); 485 ids.push_back("mozc-dv"); 486 EXPECT_TRUE(manager_->EnableInputMethods(ids)); 487 EXPECT_EQ(1, mock_ibus_daemon_controller_->start_count()); 488 EXPECT_EQ(1, observer.input_method_changed_count_); 489 EXPECT_EQ(ids[0], manager_->GetCurrentInputMethod().id()); 490 EXPECT_EQ("us", xkeyboard_->last_layout_); 491 manager_->RemoveObserver(&observer); 492} 493 494TEST_F(InputMethodManagerImplTest, TestEnableUnknownIds) { 495 TestObserver observer; 496 manager_->AddObserver(&observer); 497 manager_->SetState(InputMethodManager::STATE_BROWSER_SCREEN); 498 std::vector<std::string> ids; 499 ids.push_back("xkb:tl::tlh"); // Klingon, which is not supported. 500 ids.push_back("unknown-super-cool-ime"); 501 EXPECT_FALSE(manager_->EnableInputMethods(ids)); 502 503 // TODO(yusukes): Should we fall back to the hardware keyboard layout in this 504 // case? 505 EXPECT_EQ(0, observer.input_method_changed_count_); 506 507 manager_->RemoveObserver(&observer); 508} 509 510TEST_F(InputMethodManagerImplTest, TestEnableLayoutsThenLock) { 511 // For http://crbug.com/19655#c11 - (14). 512 TestObserver observer; 513 manager_->AddObserver(&observer); 514 InitComponentExtension(); 515 InitIBusBus(); 516 manager_->SetState(InputMethodManager::STATE_BROWSER_SCREEN); 517 std::vector<std::string> ids; 518 ids.push_back("xkb:us::eng"); 519 ids.push_back("xkb:us:dvorak:eng"); 520 EXPECT_TRUE(manager_->EnableInputMethods(ids)); 521 EXPECT_EQ(2U, manager_->GetNumActiveInputMethods()); 522 EXPECT_EQ(1, observer.input_method_changed_count_); 523 EXPECT_EQ(ids[0], manager_->GetCurrentInputMethod().id()); 524 EXPECT_EQ("us", xkeyboard_->last_layout_); 525 526 // Switch to Dvorak. 527 manager_->SwitchToNextInputMethod(); 528 EXPECT_EQ(2, observer.input_method_changed_count_); 529 EXPECT_EQ(ids[1], manager_->GetCurrentInputMethod().id()); 530 EXPECT_EQ("us(dvorak)", xkeyboard_->last_layout_); 531 532 // Lock screen 533 manager_->SetState(InputMethodManager::STATE_LOCK_SCREEN); 534 EXPECT_EQ(2U, manager_->GetNumActiveInputMethods()); 535 EXPECT_EQ(ids[1], // still Dvorak 536 manager_->GetCurrentInputMethod().id()); 537 EXPECT_EQ("us(dvorak)", xkeyboard_->last_layout_); 538 // Switch back to Qwerty. 539 manager_->SwitchToNextInputMethod(); 540 EXPECT_EQ(ids[0], manager_->GetCurrentInputMethod().id()); 541 EXPECT_EQ("us", xkeyboard_->last_layout_); 542 543 // Unlock screen. The original state, Dvorak, is restored. 544 manager_->SetState(InputMethodManager::STATE_BROWSER_SCREEN); 545 EXPECT_EQ(2U, manager_->GetNumActiveInputMethods()); 546 EXPECT_EQ(ids[1], manager_->GetCurrentInputMethod().id()); 547 EXPECT_EQ("us(dvorak)", xkeyboard_->last_layout_); 548 549 manager_->RemoveObserver(&observer); 550} 551 552TEST_F(InputMethodManagerImplTest, SwithchInputMethodTest) { 553 // For http://crbug.com/19655#c11 - (15). 554 TestObserver observer; 555 manager_->AddObserver(&observer); 556 InitComponentExtension(); 557 InitIBusBus(); 558 manager_->SetState(InputMethodManager::STATE_BROWSER_SCREEN); 559 std::vector<std::string> ids; 560 ids.push_back("xkb:us:dvorak:eng"); 561 ids.push_back("_comp_ime_nmblnjkfdkabgdofidlkienfnnbjhnabext2_engine2_engine_id"); 562 ids.push_back("_comp_ime_nmblnjkfdkabgdofidlkienfnnbjhnabext2_engine1_engine_id"); 563 EXPECT_TRUE(manager_->EnableInputMethods(ids)); 564 EXPECT_EQ(3U, manager_->GetNumActiveInputMethods()); 565 EXPECT_EQ(1, observer.input_method_changed_count_); 566 EXPECT_EQ(ids[0], manager_->GetCurrentInputMethod().id()); 567 EXPECT_EQ("us(dvorak)", xkeyboard_->last_layout_); 568 569 // Switch to Mozc. 570 manager_->SwitchToNextInputMethod(); 571 EXPECT_EQ(2, observer.input_method_changed_count_); 572 EXPECT_EQ(ids[1], manager_->GetCurrentInputMethod().id()); 573 EXPECT_EQ("us(dvorak)", xkeyboard_->last_layout_); 574 575 // Lock screen 576 manager_->SetState(InputMethodManager::STATE_LOCK_SCREEN); 577 EXPECT_EQ(2U, manager_->GetNumActiveInputMethods()); // Qwerty+Dvorak. 578 EXPECT_EQ("xkb:us:dvorak:eng", 579 manager_->GetCurrentInputMethod().id()); 580 EXPECT_EQ("us(dvorak)", xkeyboard_->last_layout_); 581 // controller_->Stop() should never be called when the screen is locked even 582 // after crosbug.com/27051 is fixed. 583 EXPECT_EQ(0, mock_ibus_daemon_controller_->stop_count()); 584 manager_->SwitchToNextInputMethod(); 585 EXPECT_EQ("xkb:us::eng", // The hardware keyboard layout. 586 manager_->GetCurrentInputMethod().id()); 587 EXPECT_EQ("us", xkeyboard_->last_layout_); 588 589 // Unlock screen. The original state, pinyin-dv, is restored. 590 manager_->SetState(InputMethodManager::STATE_BROWSER_SCREEN); 591 EXPECT_EQ(3U, manager_->GetNumActiveInputMethods()); // Dvorak and 2 IMEs. 592 EXPECT_EQ(ids[1], manager_->GetCurrentInputMethod().id()); 593 EXPECT_EQ("us(dvorak)", xkeyboard_->last_layout_); 594 595 manager_->RemoveObserver(&observer); 596} 597 598TEST_F(InputMethodManagerImplTest, TestXkbSetting) { 599 // For http://crbug.com/19655#c11 - (8), step 7-11. 600 InitComponentExtension(); 601 InitIBusBus(); 602 manager_->SetState(InputMethodManager::STATE_BROWSER_SCREEN); 603 std::vector<std::string> ids; 604 ids.push_back("xkb:us:dvorak:eng"); 605 ids.push_back("xkb:us:colemak:eng"); 606 ids.push_back(nacl_mozc_jp_id); 607 ids.push_back(nacl_mozc_us_id); 608 EXPECT_TRUE(manager_->EnableInputMethods(ids)); 609 EXPECT_EQ(4U, manager_->GetNumActiveInputMethods()); 610 EXPECT_EQ(1, xkeyboard_->set_current_keyboard_layout_by_name_count_); 611 // See input_methods.txt for an expected XKB layout name. 612 EXPECT_EQ("us(dvorak)", xkeyboard_->last_layout_); 613 manager_->SwitchToNextInputMethod(); 614 EXPECT_EQ(2, xkeyboard_->set_current_keyboard_layout_by_name_count_); 615 EXPECT_EQ("us(colemak)", xkeyboard_->last_layout_); 616 manager_->SwitchToNextInputMethod(); 617 EXPECT_EQ(3, xkeyboard_->set_current_keyboard_layout_by_name_count_); 618 EXPECT_EQ("jp", xkeyboard_->last_layout_); 619 manager_->SwitchToNextInputMethod(); 620 EXPECT_EQ(4, xkeyboard_->set_current_keyboard_layout_by_name_count_); 621 EXPECT_EQ("us", xkeyboard_->last_layout_); 622 manager_->SwitchToNextInputMethod(); 623 EXPECT_EQ(5, xkeyboard_->set_current_keyboard_layout_by_name_count_); 624 EXPECT_EQ("us(dvorak)", xkeyboard_->last_layout_); 625 // Disable Dvorak. 626 ids.erase(ids.begin()); 627 EXPECT_TRUE(manager_->EnableInputMethods(ids)); 628 EXPECT_EQ(3U, manager_->GetNumActiveInputMethods()); 629 EXPECT_EQ(6, xkeyboard_->set_current_keyboard_layout_by_name_count_); 630 EXPECT_EQ("us(colemak)", xkeyboard_->last_layout_); 631} 632 633TEST_F(InputMethodManagerImplTest, TestActivateInputMethodProperty) { 634 manager_->ActivateInputMethodProperty("key"); 635 EXPECT_EQ(1, controller_->activate_input_method_property_count_); 636 EXPECT_EQ("key", controller_->activate_input_method_property_key_); 637 manager_->ActivateInputMethodProperty("key2"); 638 EXPECT_EQ(2, controller_->activate_input_method_property_count_); 639 EXPECT_EQ("key2", controller_->activate_input_method_property_key_); 640} 641 642TEST_F(InputMethodManagerImplTest, TestGetCurrentInputMethodProperties) { 643 InitComponentExtension(); 644 InitIBusBus(); 645 EXPECT_TRUE(manager_->GetCurrentInputMethodProperties().empty()); 646 647 manager_->SetState(InputMethodManager::STATE_BROWSER_SCREEN); 648 std::vector<std::string> ids; 649 ids.push_back("xkb:us::eng"); 650 ids.push_back(nacl_mozc_us_id); 651 EXPECT_TRUE(manager_->EnableInputMethods(ids)); 652 EXPECT_EQ(2U, manager_->GetNumActiveInputMethods()); 653 EXPECT_TRUE(manager_->GetCurrentInputMethodProperties().empty()); 654 manager_->ChangeInputMethod(nacl_mozc_us_id); 655 656 InputMethodPropertyList current_property_list; 657 current_property_list.push_back(InputMethodProperty("key", 658 "label", 659 false, 660 false)); 661 controller_->SetCurrentPropertiesForTesting(current_property_list); 662 controller_->NotifyPropertyChangedForTesting(); 663 664 ASSERT_EQ(1U, manager_->GetCurrentInputMethodProperties().size()); 665 EXPECT_EQ("key", manager_->GetCurrentInputMethodProperties().at(0).key); 666 667 manager_->ChangeInputMethod("xkb:us::eng"); 668 EXPECT_TRUE(manager_->GetCurrentInputMethodProperties().empty()); 669 670 // Delayed asynchronous property update signal from the Mozc IME. 671 controller_->NotifyPropertyChangedForTesting(); 672 // When XKB layout is in use, GetCurrentInputMethodProperties() should always 673 // return an empty list. 674 EXPECT_TRUE(manager_->GetCurrentInputMethodProperties().empty()); 675} 676 677TEST_F(InputMethodManagerImplTest, TestGetCurrentInputMethodPropertiesTwoImes) { 678 InitComponentExtension(); 679 InitIBusBus(); 680 EXPECT_TRUE(manager_->GetCurrentInputMethodProperties().empty()); 681 682 manager_->SetState(InputMethodManager::STATE_BROWSER_SCREEN); 683 std::vector<std::string> ids; 684 ids.push_back(nacl_mozc_us_id); // Japanese 685 ids.push_back("_comp_ime_nmblnjkfdkabgdofidlkienfnnbjhnabext2_engine1_engine_id"); // T-Chinese 686 EXPECT_TRUE(manager_->EnableInputMethods(ids)); 687 EXPECT_EQ(2U, manager_->GetNumActiveInputMethods()); 688 EXPECT_TRUE(manager_->GetCurrentInputMethodProperties().empty()); 689 690 InputMethodPropertyList current_property_list; 691 current_property_list.push_back(InputMethodProperty("key-mozc", 692 "label", 693 false, 694 false)); 695 controller_->SetCurrentPropertiesForTesting(current_property_list); 696 controller_->NotifyPropertyChangedForTesting(); 697 698 ASSERT_EQ(1U, manager_->GetCurrentInputMethodProperties().size()); 699 EXPECT_EQ("key-mozc", manager_->GetCurrentInputMethodProperties().at(0).key); 700 701 manager_->ChangeInputMethod("_comp_ime_nmblnjkfdkabgdofidlkienfnnbjhnabext2_engine1_engine_id"); 702 // Since the IME is changed, the property for mozc Japanese should be hidden. 703 EXPECT_TRUE(manager_->GetCurrentInputMethodProperties().empty()); 704 705 // Asynchronous property update signal from mozc-chewing. 706 current_property_list.clear(); 707 current_property_list.push_back(InputMethodProperty("key-chewing", 708 "label", 709 false, 710 false)); 711 controller_->SetCurrentPropertiesForTesting(current_property_list); 712 controller_->NotifyPropertyChangedForTesting(); 713 ASSERT_EQ(1U, manager_->GetCurrentInputMethodProperties().size()); 714 EXPECT_EQ("key-chewing", 715 manager_->GetCurrentInputMethodProperties().at(0).key); 716} 717 718TEST_F(InputMethodManagerImplTest, TestNextInputMethod) { 719 TestObserver observer; 720 manager_->AddObserver(&observer); 721 InitComponentExtension(); 722 InitIBusBus(); 723 // For http://crbug.com/19655#c11 - (1) 724 manager_->EnableLayouts("en-US", "xkb:us::eng"); 725 EXPECT_EQ(5U, manager_->GetNumActiveInputMethods()); 726 EXPECT_EQ("xkb:us::eng", manager_->GetCurrentInputMethod().id()); 727 EXPECT_EQ("us", xkeyboard_->last_layout_); 728 manager_->SwitchToNextInputMethod(); 729 EXPECT_TRUE(observer.last_show_message_); 730 EXPECT_EQ("xkb:us:intl:eng", manager_->GetCurrentInputMethod().id()); 731 EXPECT_EQ("us(intl)", xkeyboard_->last_layout_); 732 manager_->SwitchToNextInputMethod(); 733 EXPECT_TRUE(observer.last_show_message_); 734 EXPECT_EQ("xkb:us:altgr-intl:eng", manager_->GetCurrentInputMethod().id()); 735 EXPECT_EQ("us(altgr-intl)", xkeyboard_->last_layout_); 736 manager_->SwitchToNextInputMethod(); 737 EXPECT_TRUE(observer.last_show_message_); 738 EXPECT_EQ("xkb:us:dvorak:eng", manager_->GetCurrentInputMethod().id()); 739 EXPECT_EQ("us(dvorak)", xkeyboard_->last_layout_); 740 manager_->SwitchToNextInputMethod(); 741 EXPECT_TRUE(observer.last_show_message_); 742 EXPECT_EQ("xkb:us:colemak:eng", manager_->GetCurrentInputMethod().id()); 743 EXPECT_EQ("us(colemak)", xkeyboard_->last_layout_); 744 manager_->SwitchToNextInputMethod(); 745 EXPECT_TRUE(observer.last_show_message_); 746 EXPECT_EQ("xkb:us::eng", manager_->GetCurrentInputMethod().id()); 747 EXPECT_EQ("us", xkeyboard_->last_layout_); 748 749 manager_->RemoveObserver(&observer); 750} 751 752TEST_F(InputMethodManagerImplTest, TestPreviousInputMethod) { 753 TestObserver observer; 754 manager_->AddObserver(&observer); 755 InitComponentExtension(); 756 InitIBusBus(); 757 758 ui::Accelerator keydown_accelerator(ui::VKEY_SPACE, ui::EF_CONTROL_DOWN); 759 keydown_accelerator.set_type(ui::ET_KEY_PRESSED); 760 ui::Accelerator keyup_accelerator(ui::VKEY_SPACE, ui::EF_CONTROL_DOWN); 761 keyup_accelerator.set_type(ui::ET_KEY_RELEASED); 762 763 manager_->EnableLayouts("en-US", "xkb:us::eng"); 764 EXPECT_EQ(5U, manager_->GetNumActiveInputMethods()); 765 EXPECT_EQ("xkb:us::eng", manager_->GetCurrentInputMethod().id()); 766 EXPECT_EQ("us", xkeyboard_->last_layout_); 767 EXPECT_TRUE(manager_->SwitchToNextInputMethod()); 768 EXPECT_TRUE(observer.last_show_message_); 769 EXPECT_EQ("xkb:us:intl:eng", manager_->GetCurrentInputMethod().id()); 770 EXPECT_EQ("us(intl)", xkeyboard_->last_layout_); 771 EXPECT_TRUE(manager_->SwitchToPreviousInputMethod(keydown_accelerator)); 772 EXPECT_TRUE(manager_->SwitchToPreviousInputMethod(keyup_accelerator)); 773 EXPECT_TRUE(observer.last_show_message_); 774 EXPECT_EQ("xkb:us::eng", manager_->GetCurrentInputMethod().id()); 775 EXPECT_EQ("us", xkeyboard_->last_layout_); 776 EXPECT_TRUE(manager_->SwitchToPreviousInputMethod(keydown_accelerator)); 777 EXPECT_TRUE(manager_->SwitchToPreviousInputMethod(keyup_accelerator)); 778 EXPECT_TRUE(observer.last_show_message_); 779 EXPECT_EQ("xkb:us:intl:eng", manager_->GetCurrentInputMethod().id()); 780 EXPECT_EQ("us(intl)", xkeyboard_->last_layout_); 781 EXPECT_TRUE(manager_->SwitchToPreviousInputMethod(keydown_accelerator)); 782 EXPECT_TRUE(manager_->SwitchToPreviousInputMethod(keyup_accelerator)); 783 EXPECT_TRUE(observer.last_show_message_); 784 EXPECT_EQ("xkb:us::eng", manager_->GetCurrentInputMethod().id()); 785 EXPECT_EQ("us", xkeyboard_->last_layout_); 786 EXPECT_TRUE(manager_->SwitchToNextInputMethod()); 787 EXPECT_TRUE(observer.last_show_message_); 788 EXPECT_EQ("xkb:us:intl:eng", manager_->GetCurrentInputMethod().id()); 789 EXPECT_EQ("us(intl)", xkeyboard_->last_layout_); 790 EXPECT_TRUE(manager_->SwitchToNextInputMethod()); 791 EXPECT_TRUE(observer.last_show_message_); 792 EXPECT_EQ("xkb:us:altgr-intl:eng", manager_->GetCurrentInputMethod().id()); 793 EXPECT_EQ("us(altgr-intl)", xkeyboard_->last_layout_); 794 EXPECT_TRUE(manager_->SwitchToPreviousInputMethod(keydown_accelerator)); 795 EXPECT_TRUE(manager_->SwitchToPreviousInputMethod(keyup_accelerator)); 796 EXPECT_TRUE(observer.last_show_message_); 797 EXPECT_EQ("xkb:us:intl:eng", manager_->GetCurrentInputMethod().id()); 798 EXPECT_EQ("us(intl)", xkeyboard_->last_layout_); 799 EXPECT_TRUE(manager_->SwitchToPreviousInputMethod(keydown_accelerator)); 800 EXPECT_TRUE(manager_->SwitchToPreviousInputMethod(keyup_accelerator)); 801 EXPECT_TRUE(observer.last_show_message_); 802 EXPECT_EQ("xkb:us:altgr-intl:eng", manager_->GetCurrentInputMethod().id()); 803 EXPECT_EQ("us(altgr-intl)", xkeyboard_->last_layout_); 804 805 manager_->RemoveObserver(&observer); 806} 807 808TEST_F(InputMethodManagerImplTest, 809 TestSwitchToPreviousInputMethodForOneActiveInputMethod) { 810 TestObserver observer; 811 manager_->AddObserver(&observer); 812 InitComponentExtension(); 813 InitIBusBus(); 814 815 ui::Accelerator keydown_accelerator(ui::VKEY_SPACE, ui::EF_CONTROL_DOWN); 816 keydown_accelerator.set_type(ui::ET_KEY_PRESSED); 817 ui::Accelerator keyup_accelerator(ui::VKEY_SPACE, ui::EF_CONTROL_DOWN); 818 keyup_accelerator.set_type(ui::ET_KEY_RELEASED); 819 820 std::vector<std::string> ids; 821 ids.push_back("xkb:us:dvorak:eng"); 822 EXPECT_TRUE(manager_->EnableInputMethods(ids)); 823 EXPECT_EQ(1U, manager_->GetNumActiveInputMethods()); 824 825 // Ctrl+Space accelerator should not be consumed if there is only one active 826 // input method. 827 EXPECT_FALSE(manager_->SwitchToPreviousInputMethod(keydown_accelerator)); 828 EXPECT_FALSE(manager_->SwitchToPreviousInputMethod(keyup_accelerator)); 829 830 manager_->RemoveObserver(&observer); 831} 832 833TEST_F(InputMethodManagerImplTest, TestSwitchInputMethodWithUsLayouts) { 834 TestObserver observer; 835 manager_->AddObserver(&observer); 836 InitComponentExtension(); 837 InitIBusBus(); 838 manager_->EnableLayouts("en-US", "xkb:us::eng"); 839 EXPECT_EQ(5U, manager_->GetNumActiveInputMethods()); 840 EXPECT_EQ("xkb:us::eng", manager_->GetCurrentInputMethod().id()); 841 EXPECT_EQ("us", xkeyboard_->last_layout_); 842 843 // Henkan, Muhenkan, ZenkakuHankaku should be ignored when no Japanese IMEs 844 // and keyboards are enabled. 845 EXPECT_FALSE(manager_->SwitchInputMethod( 846 ui::Accelerator(ui::VKEY_CONVERT, ui::EF_NONE))); 847 EXPECT_FALSE(observer.last_show_message_); 848 EXPECT_EQ("xkb:us::eng", manager_->GetCurrentInputMethod().id()); 849 EXPECT_EQ("us", xkeyboard_->last_layout_); 850 EXPECT_FALSE(manager_->SwitchInputMethod( 851 ui::Accelerator(ui::VKEY_NONCONVERT, ui::EF_NONE))); 852 EXPECT_EQ("xkb:us::eng", manager_->GetCurrentInputMethod().id()); 853 EXPECT_EQ("us", xkeyboard_->last_layout_); 854 EXPECT_FALSE(manager_->SwitchInputMethod( 855 ui::Accelerator(ui::VKEY_DBE_SBCSCHAR, ui::EF_NONE))); 856 EXPECT_EQ("xkb:us::eng", manager_->GetCurrentInputMethod().id()); 857 EXPECT_EQ("us", xkeyboard_->last_layout_); 858 EXPECT_FALSE(manager_->SwitchInputMethod( 859 ui::Accelerator(ui::VKEY_DBE_DBCSCHAR, ui::EF_NONE))); 860 EXPECT_EQ("xkb:us::eng", manager_->GetCurrentInputMethod().id()); 861 EXPECT_EQ("us", xkeyboard_->last_layout_); 862 863 manager_->RemoveObserver(&observer); 864} 865 866TEST_F(InputMethodManagerImplTest, TestSwitchInputMethodWithJpLayout) { 867 // Enable "xkb:jp::jpn" and press Muhenkan/ZenkakuHankaku. 868 InitComponentExtension(); 869 InitIBusBus(); 870 871 ui::Accelerator keydown_accelerator(ui::VKEY_SPACE, ui::EF_CONTROL_DOWN); 872 keydown_accelerator.set_type(ui::ET_KEY_PRESSED); 873 ui::Accelerator keyup_accelerator(ui::VKEY_SPACE, ui::EF_CONTROL_DOWN); 874 keyup_accelerator.set_type(ui::ET_KEY_RELEASED); 875 876 manager_->EnableLayouts("ja", "xkb:us::eng"); 877 EXPECT_EQ(2U, manager_->GetNumActiveInputMethods()); 878 EXPECT_EQ("xkb:us::eng", manager_->GetCurrentInputMethod().id()); 879 EXPECT_EQ("us", xkeyboard_->last_layout_); 880 EXPECT_TRUE(manager_->SwitchInputMethod( 881 ui::Accelerator(ui::VKEY_NONCONVERT, ui::EF_NONE))); 882 EXPECT_EQ("xkb:jp::jpn", manager_->GetCurrentInputMethod().id()); 883 EXPECT_EQ("jp", xkeyboard_->last_layout_); 884 EXPECT_TRUE(manager_->SwitchToPreviousInputMethod(keydown_accelerator)); 885 EXPECT_TRUE(manager_->SwitchToPreviousInputMethod(keyup_accelerator)); 886 EXPECT_EQ("xkb:us::eng", manager_->GetCurrentInputMethod().id()); 887 EXPECT_EQ("us", xkeyboard_->last_layout_); 888 EXPECT_TRUE(manager_->SwitchInputMethod( 889 ui::Accelerator(ui::VKEY_DBE_SBCSCHAR, ui::EF_NONE))); 890 EXPECT_EQ("xkb:jp::jpn", manager_->GetCurrentInputMethod().id()); 891 EXPECT_EQ("jp", xkeyboard_->last_layout_); 892 EXPECT_TRUE(manager_->SwitchToPreviousInputMethod(keydown_accelerator)); 893 EXPECT_TRUE(manager_->SwitchToPreviousInputMethod(keyup_accelerator)); 894 EXPECT_EQ("xkb:us::eng", manager_->GetCurrentInputMethod().id()); 895 EXPECT_EQ("us", xkeyboard_->last_layout_); 896 EXPECT_TRUE(manager_->SwitchInputMethod( 897 ui::Accelerator(ui::VKEY_DBE_DBCSCHAR, ui::EF_NONE))); 898 EXPECT_EQ("xkb:jp::jpn", manager_->GetCurrentInputMethod().id()); 899 EXPECT_EQ("jp", xkeyboard_->last_layout_); 900} 901 902TEST_F(InputMethodManagerImplTest, TestSwitchInputMethodWithJpIme) { 903 InitComponentExtension(); 904 InitIBusBus(); 905 manager_->SetState(InputMethodManager::STATE_BROWSER_SCREEN); 906 std::vector<std::string> ids; 907 ids.push_back("xkb:jp::jpn"); 908 ids.push_back(nacl_mozc_jp_id); 909 EXPECT_TRUE(manager_->EnableInputMethods(ids)); 910 EXPECT_EQ("xkb:jp::jpn", manager_->GetCurrentInputMethod().id()); 911 EXPECT_EQ("jp", xkeyboard_->last_layout_); 912 EXPECT_TRUE(manager_->SwitchInputMethod( 913 ui::Accelerator(ui::VKEY_DBE_DBCSCHAR, ui::EF_NONE))); 914 EXPECT_EQ(nacl_mozc_jp_id, manager_->GetCurrentInputMethod().id()); 915 EXPECT_EQ("jp", xkeyboard_->last_layout_); 916 EXPECT_TRUE(manager_->SwitchInputMethod( 917 ui::Accelerator(ui::VKEY_DBE_DBCSCHAR, ui::EF_NONE))); 918 EXPECT_EQ("xkb:jp::jpn", manager_->GetCurrentInputMethod().id()); 919 EXPECT_EQ("jp", xkeyboard_->last_layout_); 920 EXPECT_TRUE(manager_->SwitchInputMethod( 921 ui::Accelerator(ui::VKEY_CONVERT, ui::EF_NONE))); 922 EXPECT_EQ(nacl_mozc_jp_id, manager_->GetCurrentInputMethod().id()); 923 EXPECT_EQ("jp", xkeyboard_->last_layout_); 924 EXPECT_TRUE(manager_->SwitchInputMethod( 925 ui::Accelerator(ui::VKEY_CONVERT, ui::EF_NONE))); 926 EXPECT_EQ(nacl_mozc_jp_id, manager_->GetCurrentInputMethod().id()); 927 EXPECT_EQ("jp", xkeyboard_->last_layout_); 928 EXPECT_TRUE(manager_->SwitchInputMethod( 929 ui::Accelerator(ui::VKEY_NONCONVERT, ui::EF_NONE))); 930 EXPECT_EQ("xkb:jp::jpn", manager_->GetCurrentInputMethod().id()); 931 EXPECT_EQ("jp", xkeyboard_->last_layout_); 932 EXPECT_TRUE(manager_->SwitchInputMethod( 933 ui::Accelerator(ui::VKEY_NONCONVERT, ui::EF_NONE))); 934 EXPECT_EQ("xkb:jp::jpn", manager_->GetCurrentInputMethod().id()); 935 EXPECT_EQ("jp", xkeyboard_->last_layout_); 936 937 // Add Dvorak. 938 ids.push_back("xkb:us:dvorak:eng"); 939 EXPECT_TRUE(manager_->EnableInputMethods(ids)); 940 EXPECT_EQ("xkb:jp::jpn", manager_->GetCurrentInputMethod().id()); 941 EXPECT_EQ("jp", xkeyboard_->last_layout_); 942 EXPECT_TRUE(manager_->SwitchInputMethod( 943 ui::Accelerator(ui::VKEY_DBE_SBCSCHAR, ui::EF_NONE))); 944 EXPECT_EQ(nacl_mozc_jp_id, manager_->GetCurrentInputMethod().id()); 945 EXPECT_EQ("jp", xkeyboard_->last_layout_); 946 EXPECT_TRUE(manager_->SwitchInputMethod( 947 ui::Accelerator(ui::VKEY_DBE_SBCSCHAR, ui::EF_NONE))); 948 EXPECT_EQ("xkb:jp::jpn", manager_->GetCurrentInputMethod().id()); 949 EXPECT_EQ("jp", xkeyboard_->last_layout_); 950} 951 952TEST_F(InputMethodManagerImplTest, TestAddRemoveExtensionInputMethods) { 953 TestObserver observer; 954 manager_->AddObserver(&observer); 955 InitComponentExtension(); 956 InitIBusBus(); 957 manager_->SetState(InputMethodManager::STATE_BROWSER_SCREEN); 958 std::vector<std::string> ids; 959 ids.push_back("xkb:us:dvorak:eng"); 960 EXPECT_TRUE(manager_->EnableInputMethods(ids)); 961 EXPECT_EQ(1U, manager_->GetNumActiveInputMethods()); 962 EXPECT_EQ(0, mock_ibus_daemon_controller_->start_count()); 963 EXPECT_EQ(1, observer.input_method_changed_count_); 964 EXPECT_EQ(ids[0], 965 manager_->GetCurrentInputMethod().id()); 966 EXPECT_EQ("us(dvorak)", xkeyboard_->last_layout_); 967 968 // Add two Extension IMEs. 969 std::vector<std::string> layouts; 970 layouts.push_back("us"); 971 std::vector<std::string> languages; 972 languages.push_back("en-US"); 973 manager_->AddInputMethodExtension( 974 extension_ime_util::GetInputMethodID("deadbeef", "engine_id"), 975 "deadbeef input method", 976 layouts, 977 languages, 978 GURL(), 979 NULL); 980 981 // Extension IMEs are not enabled by default. 982 EXPECT_EQ(1U, manager_->GetNumActiveInputMethods()); 983 984 std::vector<std::string> extension_ime_ids; 985 extension_ime_ids.push_back( 986 extension_ime_util::GetInputMethodID("deadbeef", "engine_id")); 987 manager_->SetEnabledExtensionImes(&extension_ime_ids); 988 EXPECT_EQ(2U, manager_->GetNumActiveInputMethods()); 989 990 // should be started. 991 EXPECT_EQ(1, mock_ibus_daemon_controller_->start_count()); 992 { 993 scoped_ptr<InputMethodDescriptors> methods( 994 manager_->GetActiveInputMethods()); 995 ASSERT_EQ(2U, methods->size()); 996 EXPECT_EQ(extension_ime_util::GetInputMethodID("deadbeef", "engine_id"), 997 // Ext IMEs should be at the end of the list. 998 methods->at(1).id()); 999 } 1000 manager_->AddInputMethodExtension( 1001 extension_ime_util::GetInputMethodID("cafebabe", "engine_id"), 1002 "cafebabe input method", 1003 layouts, 1004 languages, 1005 GURL(), 1006 NULL); 1007 EXPECT_EQ(2U, manager_->GetNumActiveInputMethods()); 1008 1009 extension_ime_ids.push_back( 1010 extension_ime_util::GetInputMethodID("cafebabe", "engine_id")); 1011 manager_->SetEnabledExtensionImes(&extension_ime_ids); 1012 EXPECT_EQ(3U, manager_->GetNumActiveInputMethods()); 1013 { 1014 scoped_ptr<InputMethodDescriptors> methods( 1015 manager_->GetActiveInputMethods()); 1016 ASSERT_EQ(3U, methods->size()); 1017 EXPECT_EQ(extension_ime_util::GetInputMethodID("deadbeef", "engine_id"), 1018 // Ext IMEs should be at the end of the list. 1019 methods->at(1).id()); 1020 } 1021 1022 // Remove them. 1023 manager_->RemoveInputMethodExtension( 1024 extension_ime_util::GetInputMethodID("deadbeef", "engine_id")); 1025 EXPECT_EQ(2U, manager_->GetNumActiveInputMethods()); 1026 manager_->RemoveInputMethodExtension( 1027 extension_ime_util::GetInputMethodID("cafebabe", "engine_id")); 1028 EXPECT_EQ(1U, manager_->GetNumActiveInputMethods()); 1029 // Currently, to work around a crash issue at crosbug.com/27051, 1030 // controller_->Stop(); is NOT called when all (extension) IMEs are disabled. 1031 EXPECT_EQ(0, mock_ibus_daemon_controller_->stop_count()); 1032 1033 manager_->RemoveObserver(&observer); 1034} 1035 1036TEST_F(InputMethodManagerImplTest, TestAddExtensionInputThenLockScreen) { 1037 TestObserver observer; 1038 InitComponentExtension(); 1039 InitIBusBus(); 1040 manager_->AddObserver(&observer); 1041 manager_->SetState(InputMethodManager::STATE_BROWSER_SCREEN); 1042 std::vector<std::string> ids; 1043 ids.push_back("xkb:us::eng"); 1044 EXPECT_TRUE(manager_->EnableInputMethods(ids)); 1045 EXPECT_EQ(1U, manager_->GetNumActiveInputMethods()); 1046 EXPECT_EQ(1, observer.input_method_changed_count_); 1047 EXPECT_EQ(ids[0], manager_->GetCurrentInputMethod().id()); 1048 EXPECT_EQ("us", xkeyboard_->last_layout_); 1049 1050 // Add an Extension IME. 1051 std::vector<std::string> layouts; 1052 layouts.push_back("us(dvorak)"); 1053 std::vector<std::string> languages; 1054 languages.push_back("en-US"); 1055 manager_->AddInputMethodExtension( 1056 extension_ime_util::GetInputMethodID("deadbeef", "engine_id"), 1057 "deadbeef input method", 1058 layouts, 1059 languages, 1060 GURL(), 1061 NULL); 1062 // Extension IME is not enabled by default. 1063 EXPECT_EQ(1U, manager_->GetNumActiveInputMethods()); 1064 EXPECT_EQ(1, observer.input_method_changed_count_); 1065 1066 std::vector<std::string> extension_ime_ids; 1067 extension_ime_ids.push_back( 1068 extension_ime_util::GetInputMethodID("deadbeef", "engine_id")); 1069 manager_->SetEnabledExtensionImes(&extension_ime_ids); 1070 EXPECT_EQ(2U, manager_->GetNumActiveInputMethods()); 1071 1072 // Switch to the IME. 1073 manager_->SwitchToNextInputMethod(); 1074 EXPECT_EQ(3, observer.input_method_changed_count_); 1075 EXPECT_EQ(extension_ime_util::GetInputMethodID("deadbeef", "engine_id"), 1076 manager_->GetCurrentInputMethod().id()); 1077 EXPECT_EQ("us(dvorak)", xkeyboard_->last_layout_); 1078 1079 // Lock the screen. This is for crosbug.com/27049. 1080 manager_->SetState(InputMethodManager::STATE_LOCK_SCREEN); 1081 EXPECT_EQ(1U, manager_->GetNumActiveInputMethods()); // Qwerty. No Ext. IME 1082 EXPECT_EQ("xkb:us::eng", 1083 manager_->GetCurrentInputMethod().id()); 1084 EXPECT_EQ("us", xkeyboard_->last_layout_); 1085 EXPECT_EQ(0, mock_ibus_daemon_controller_->stop_count()); 1086 1087 // Unlock the screen. 1088 manager_->SetState(InputMethodManager::STATE_BROWSER_SCREEN); 1089 EXPECT_EQ(2U, manager_->GetNumActiveInputMethods()); 1090 EXPECT_EQ(extension_ime_util::GetInputMethodID("deadbeef", "engine_id"), 1091 manager_->GetCurrentInputMethod().id()); 1092 EXPECT_EQ("us(dvorak)", xkeyboard_->last_layout_); 1093 { 1094 // This is for crosbug.com/27052. 1095 scoped_ptr<InputMethodDescriptors> methods( 1096 manager_->GetActiveInputMethods()); 1097 ASSERT_EQ(2U, methods->size()); 1098 EXPECT_EQ(extension_ime_util::GetInputMethodID("deadbeef", "engine_id"), 1099 // Ext. IMEs should be at the end of the list. 1100 methods->at(1).id()); 1101 } 1102 manager_->RemoveObserver(&observer); 1103} 1104 1105TEST_F(InputMethodManagerImplTest, TestReset) { 1106 InitComponentExtension(); 1107 InitIBusBus(); 1108 manager_->SetState(InputMethodManager::STATE_BROWSER_SCREEN); 1109 std::vector<std::string> ids; 1110 ids.push_back("xkb:us::eng"); 1111 ids.push_back(nacl_mozc_us_id); 1112 EXPECT_TRUE(manager_->EnableInputMethods(ids)); 1113 EXPECT_EQ(2U, manager_->GetNumActiveInputMethods()); 1114 EXPECT_EQ(0, mock_engine_handler_->reset_call_count()); 1115 manager_->ChangeInputMethod(nacl_mozc_us_id); 1116 EXPECT_EQ(1, mock_ibus_client_->set_global_engine_call_count()); 1117 EXPECT_EQ(nacl_mozc_us_id, mock_ibus_client_->latest_global_engine_name()); 1118 EXPECT_EQ(0, mock_engine_handler_->reset_call_count()); 1119 manager_->ChangeInputMethod("xkb:us::eng"); 1120 EXPECT_EQ(1, mock_ibus_client_->set_global_engine_call_count()); 1121 EXPECT_EQ(nacl_mozc_us_id, mock_ibus_client_->latest_global_engine_name()); 1122 EXPECT_EQ(0, mock_engine_handler_->reset_call_count()); 1123} 1124 1125TEST_F(InputMethodManagerImplTest, 1126 ChangeInputMethodBeforeComponentExtensionInitialization_OneIME) { 1127 manager_->SetState(InputMethodManager::STATE_BROWSER_SCREEN); 1128 std::vector<std::string> ids; 1129 ids.push_back(nacl_mozc_us_id); 1130 EXPECT_TRUE(manager_->EnableInputMethods(ids)); 1131 EXPECT_EQ(1U, manager_->GetNumActiveInputMethods()); 1132 manager_->ChangeInputMethod(nacl_mozc_us_id); 1133 1134 InitIBusBus(); 1135 InitComponentExtension(); 1136 EXPECT_EQ(1, mock_ibus_client_->set_global_engine_call_count()); 1137 EXPECT_EQ(nacl_mozc_us_id, mock_ibus_client_->latest_global_engine_name()); 1138} 1139 1140TEST_F(InputMethodManagerImplTest, 1141 ChangeInputMethodBeforeComponentExtensionInitialization_TwoIME) { 1142 manager_->SetState(InputMethodManager::STATE_BROWSER_SCREEN); 1143 std::vector<std::string> ids; 1144 ids.push_back(nacl_mozc_us_id); 1145 ids.push_back(nacl_mozc_jp_id); 1146 EXPECT_TRUE(manager_->EnableInputMethods(ids)); 1147 EXPECT_EQ(2U, manager_->GetNumActiveInputMethods()); 1148 manager_->ChangeInputMethod(nacl_mozc_us_id); 1149 manager_->ChangeInputMethod(nacl_mozc_jp_id); 1150 1151 InitComponentExtension(); 1152 InitIBusBus(); 1153 EXPECT_EQ(1, mock_ibus_client_->set_global_engine_call_count()); 1154 EXPECT_EQ(nacl_mozc_jp_id, mock_ibus_client_->latest_global_engine_name()); 1155} 1156 1157TEST_F(InputMethodManagerImplTest, 1158 ChangeInputMethodBeforeComponentExtensionInitialization_CompOneIME) { 1159 manager_->SetState(InputMethodManager::STATE_BROWSER_SCREEN); 1160 const std::string ext_id = 1161 TestableComponentExtensionIMEManager::GetComponentExtensionIMEId( 1162 ime_list_[0].id, 1163 ime_list_[0].engines[0].engine_id); 1164 std::vector<std::string> ids; 1165 ids.push_back(ext_id); 1166 EXPECT_TRUE(manager_->EnableInputMethods(ids)); 1167 EXPECT_EQ(1U, manager_->GetNumActiveInputMethods()); 1168 manager_->ChangeInputMethod(ext_id); 1169 1170 InitComponentExtension(); 1171 InitIBusBus(); 1172 EXPECT_EQ(1, mock_ibus_client_->set_global_engine_call_count()); 1173 EXPECT_EQ(ext_id, mock_ibus_client_->latest_global_engine_name()); 1174} 1175 1176TEST_F(InputMethodManagerImplTest, 1177 ChangeInputMethodBeforeComponentExtensionInitialization_CompTwoIME) { 1178 manager_->SetState(InputMethodManager::STATE_BROWSER_SCREEN); 1179 const std::string ext_id1 = 1180 TestableComponentExtensionIMEManager::GetComponentExtensionIMEId( 1181 ime_list_[0].id, 1182 ime_list_[0].engines[0].engine_id); 1183 const std::string ext_id2 = 1184 TestableComponentExtensionIMEManager::GetComponentExtensionIMEId( 1185 ime_list_[1].id, 1186 ime_list_[1].engines[0].engine_id); 1187 std::vector<std::string> ids; 1188 ids.push_back(ext_id1); 1189 ids.push_back(ext_id2); 1190 EXPECT_TRUE(manager_->EnableInputMethods(ids)); 1191 EXPECT_EQ(2U, manager_->GetNumActiveInputMethods()); 1192 manager_->ChangeInputMethod(ext_id1); 1193 manager_->ChangeInputMethod(ext_id2); 1194 1195 InitComponentExtension(); 1196 InitIBusBus(); 1197 EXPECT_EQ(1, mock_ibus_client_->set_global_engine_call_count()); 1198 EXPECT_EQ(ext_id2, mock_ibus_client_->latest_global_engine_name()); 1199} 1200 1201TEST_F(InputMethodManagerImplTest, 1202 ChangeInputMethod_ComponenteExtensionOneIME) { 1203 InitComponentExtension(); 1204 InitIBusBus(); 1205 manager_->SetState(InputMethodManager::STATE_BROWSER_SCREEN); 1206 const std::string ext_id = 1207 TestableComponentExtensionIMEManager::GetComponentExtensionIMEId( 1208 ime_list_[0].id, 1209 ime_list_[0].engines[0].engine_id); 1210 std::vector<std::string> ids; 1211 ids.push_back(ext_id); 1212 EXPECT_TRUE(manager_->EnableInputMethods(ids)); 1213 EXPECT_EQ(1U, manager_->GetNumActiveInputMethods()); 1214 EXPECT_EQ(1, mock_ibus_client_->set_global_engine_call_count()); 1215 EXPECT_EQ(ext_id, mock_ibus_client_->latest_global_engine_name()); 1216} 1217 1218TEST_F(InputMethodManagerImplTest, 1219 ChangeInputMethod_ComponenteExtensionTwoIME) { 1220 InitComponentExtension(); 1221 InitIBusBus(); 1222 manager_->SetState(InputMethodManager::STATE_BROWSER_SCREEN); 1223 const std::string ext_id1 = 1224 TestableComponentExtensionIMEManager::GetComponentExtensionIMEId( 1225 ime_list_[0].id, 1226 ime_list_[0].engines[0].engine_id); 1227 const std::string ext_id2 = 1228 TestableComponentExtensionIMEManager::GetComponentExtensionIMEId( 1229 ime_list_[1].id, 1230 ime_list_[1].engines[0].engine_id); 1231 std::vector<std::string> ids; 1232 ids.push_back(ext_id1); 1233 ids.push_back(ext_id2); 1234 EXPECT_TRUE(manager_->EnableInputMethods(ids)); 1235 EXPECT_EQ(2U, manager_->GetNumActiveInputMethods()); 1236 EXPECT_EQ(1, mock_ibus_client_->set_global_engine_call_count()); 1237 EXPECT_EQ(ext_id1, mock_ibus_client_->latest_global_engine_name()); 1238 manager_->ChangeInputMethod(ext_id2); 1239 EXPECT_EQ(2, mock_ibus_client_->set_global_engine_call_count()); 1240 EXPECT_EQ(ext_id2, mock_ibus_client_->latest_global_engine_name()); 1241} 1242 1243TEST_F(InputMethodManagerImplTest, 1244 MigrateOldInputMethodTest) { 1245 std::vector<std::string> input_method_ids; 1246 input_method_ids.push_back("mozc"); 1247 input_method_ids.push_back("mozc-jp"); 1248 input_method_ids.push_back("xkb:us::eng"); 1249 input_method_ids.push_back(nacl_mozc_us_id); 1250 1251 manager_->MigrateOldInputMethods(&input_method_ids); 1252 1253 ASSERT_EQ(4U, input_method_ids.size()); 1254 EXPECT_EQ(input_method_ids.end(), 1255 std::find(input_method_ids.begin(), input_method_ids.end(), 1256 "mozc")); 1257 EXPECT_EQ(input_method_ids.end(), 1258 std::find(input_method_ids.begin(), input_method_ids.end(), 1259 "mozc-jp")); 1260 EXPECT_NE(input_method_ids.end(), 1261 std::find(input_method_ids.begin(), input_method_ids.end(), 1262 "xkb:us::eng")); 1263 EXPECT_NE(input_method_ids.end(), 1264 std::find(input_method_ids.begin(), input_method_ids.end(), 1265 nacl_mozc_us_id)); 1266 1267} 1268 1269TEST_F(InputMethodManagerImplTest, 1270 AsyncComponentExtentionInitializeBeforeIBusDaemonConnection) { 1271 const std::string xkb_id = "xkb:cz::cze"; 1272 const std::string ime_id = nacl_mozc_us_id; 1273 const std::string fallback_id = "xkb:us::eng"; 1274 std::vector<std::string> ids; 1275 ids.push_back(xkb_id); 1276 ids.push_back(ime_id); 1277 EXPECT_TRUE(manager_->EnableInputMethods(ids)); 1278 1279 // If component extension IME is not initialized, even XKB layout cannot be 1280 // enabled. 1281 manager_->ChangeInputMethod(xkb_id); 1282 EXPECT_EQ(fallback_id, manager_->GetCurrentInputMethod().id()); 1283 1284 // After component extension IME is initialized, previous input method should 1285 // be automatically enabled. 1286 InitComponentExtension(); 1287 EXPECT_EQ(xkb_id, manager_->GetCurrentInputMethod().id()); 1288 1289 // However input method should not be enabled before establishment of 1290 // connection with ibus-daemon. 1291 manager_->ChangeInputMethod(ime_id); 1292 // TODO(nona): Write expectation, GetCurrentInputMethod returns |ime_id| even 1293 // the actual input method is not changed. 1294 1295 // After connection with ibus-daemon is established, previous specified input 1296 // method should be enabled automatically. 1297 InitIBusBus(); 1298 EXPECT_EQ(ime_id, manager_->GetCurrentInputMethod().id()); 1299} 1300 1301TEST_F(InputMethodManagerImplTest, 1302 AsyncComponentExtentionInitializeAfterIBusDaemonConnection) { 1303 const std::string xkb_id = "xkb:cz::cze"; 1304 const std::string ime_id = nacl_mozc_us_id; 1305 const std::string fallback_id = "xkb:us::eng"; 1306 std::vector<std::string> ids; 1307 ids.push_back(xkb_id); 1308 ids.push_back(ime_id); 1309 EXPECT_TRUE(manager_->EnableInputMethods(ids)); 1310 1311 // If component extension IME is not initialized, even XKB layout cannot be 1312 // enabled. 1313 manager_->ChangeInputMethod(xkb_id); 1314 EXPECT_EQ(fallback_id, manager_->GetCurrentInputMethod().id()); 1315 1316 // Even after connection with ibus-daemon is established, ChangeInputMethod do 1317 // nothing without component extension IME initialization. 1318 InitIBusBus(); 1319 EXPECT_EQ(fallback_id, manager_->GetCurrentInputMethod().id()); 1320 1321 // After component extension IME is initialized, previous specified input 1322 // method should be automatically enabled. 1323 InitComponentExtension(); 1324 EXPECT_EQ(xkb_id, manager_->GetCurrentInputMethod().id()); 1325} 1326 1327} // namespace input_method 1328} // namespace chromeos 1329