blob: e68fe3ecd11a57098864bedbc9c63b40f3b8ee19 [file] [log] [blame]
// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chrome/browser/chromeos/input_method/input_method_manager_impl.h"
#include <algorithm>
#include "base/basictypes.h"
#include "base/compiler_specific.h"
#include "base/logging.h"
#include "base/memory/scoped_ptr.h"
#include "base/message_loop/message_loop.h"
#include "chrome/browser/chromeos/input_method/mock_candidate_window_controller.h"
#include "chrome/browser/chromeos/input_method/mock_ibus_controller.h"
#include "chromeos/dbus/ibus/mock_ibus_client.h"
#include "chromeos/dbus/ibus/mock_ibus_input_context_client.h"
#include "chromeos/dbus/mock_dbus_thread_manager_without_gmock.h"
#include "chromeos/ime/extension_ime_util.h"
#include "chromeos/ime/fake_input_method_delegate.h"
#include "chromeos/ime/mock_component_extension_ime_manager_delegate.h"
#include "chromeos/ime/mock_ibus_daemon_controller.h"
#include "chromeos/ime/mock_xkeyboard.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "ui/base/accelerators/accelerator.h"
#include "ui/base/keycodes/keyboard_codes.h"
namespace chromeos {
namespace input_method {
namespace {
const char nacl_mozc_us_id[] =
"_comp_ime_fpfbhcjppmaeaijcidgiibchfbnhbeljnacl_mozc_us";
const char nacl_mozc_jp_id[] =
"_comp_ime_fpfbhcjppmaeaijcidgiibchfbnhbeljnacl_mozc_jp";
// Returns true if |descriptors| contain |target|.
bool Contain(const InputMethodDescriptors& descriptors,
const InputMethodDescriptor& target) {
for (size_t i = 0; i < descriptors.size(); ++i) {
if (descriptors[i].id() == target.id())
return true;
}
return false;
}
class InputMethodManagerImplTest : public testing::Test {
public:
InputMethodManagerImplTest()
: delegate_(NULL),
controller_(NULL),
candidate_window_controller_(NULL),
xkeyboard_(NULL) {
}
virtual ~InputMethodManagerImplTest() {}
virtual void SetUp() OVERRIDE {
mock_ibus_daemon_controller_ = new chromeos::MockIBusDaemonController();
chromeos::IBusDaemonController::InitializeForTesting(
mock_ibus_daemon_controller_);
mock_dbus_thread_manager_ =
new chromeos::MockDBusThreadManagerWithoutGMock();
chromeos::DBusThreadManager::InitializeForTesting(
mock_dbus_thread_manager_);
delegate_ = new FakeInputMethodDelegate();
manager_.reset(new InputMethodManagerImpl(
scoped_ptr<InputMethodDelegate>(delegate_)));
controller_ = new MockIBusController;
manager_->SetIBusControllerForTesting(controller_);
candidate_window_controller_ = new MockCandidateWindowController;
manager_->SetCandidateWindowControllerForTesting(
candidate_window_controller_);
xkeyboard_ = new MockXKeyboard;
manager_->SetXKeyboardForTesting(xkeyboard_);
ime_list_.clear();
ComponentExtensionIME ext1;
ext1.id = "fpfbhcjppmaeaijcidgiibchfbnhbelj";
ext1.description = "ext1_description";
ext1.path = base::FilePath("ext1_file_path");
ComponentExtensionEngine ext1_engine1;
ext1_engine1.engine_id = "nacl_mozc_us";
ext1_engine1.display_name = "ext1_engine_1_display_name";
ext1_engine1.language_codes.push_back("ja");
ext1_engine1.layouts.push_back("us");
ext1.engines.push_back(ext1_engine1);
ComponentExtensionEngine ext1_engine2;
ext1_engine2.engine_id = "nacl_mozc_jp";
ext1_engine2.display_name = "ext1_engine_1_display_name";
ext1_engine2.language_codes.push_back("ja");
ext1_engine2.layouts.push_back("jp");
ext1.engines.push_back(ext1_engine2);
ime_list_.push_back(ext1);
ComponentExtensionIME ext2;
ext2.id = "nmblnjkfdkabgdofidlkienfnnbjhnab";
ext2.description = "ext2_description";
ext2.path = base::FilePath("ext2_file_path");
ComponentExtensionEngine ext2_engine1;
ext2_engine1.engine_id = "ext2_engine1_engine_id";
ext2_engine1.display_name = "ext2_engine_1_display_name";
ext2_engine1.language_codes.push_back("en");
ext2_engine1.layouts.push_back("us");
ext2.engines.push_back(ext2_engine1);
ComponentExtensionEngine ext2_engine2;
ext2_engine2.engine_id = "ext2_engine2_engine_id";
ext2_engine2.display_name = "ext2_engine_2_display_name";
ext2_engine2.language_codes.push_back("en");
ext2_engine2.layouts.push_back("us(dvorak)");
ext2.engines.push_back(ext2_engine2);
ime_list_.push_back(ext2);
mock_ibus_daemon_controller_->EmulateConnect();
}
virtual void TearDown() OVERRIDE {
mock_ibus_daemon_controller_->EmulateDisconnect();
delegate_ = NULL;
controller_ = NULL;
candidate_window_controller_ = NULL;
xkeyboard_ = NULL;
manager_.reset();
chromeos::DBusThreadManager::Shutdown();
chromeos::IBusDaemonController::Shutdown();
}
protected:
// Helper function to initialize component extension stuff for testing.
void InitComponentExtension() {
mock_delegate_ = new MockComponentExtIMEManagerDelegate();
mock_delegate_->set_ime_list(ime_list_);
scoped_ptr<ComponentExtensionIMEManagerDelegate> delegate(mock_delegate_);
manager_->InitializeComponentExtensionForTesting(delegate.Pass());
}
// Helper function to initialize IBus bus connection for testing. Do not use
// ibus related mocks before calling this function.
void InitIBusBus() {
mock_dbus_thread_manager_->InitIBusBus("dummy address",
base::Bind(&base::DoNothing));
mock_ibus_client_ = mock_dbus_thread_manager_->mock_ibus_client();
mock_ibus_input_context_client_ =
mock_dbus_thread_manager_->mock_ibus_input_context_client();
mock_ibus_daemon_controller_->EmulateConnect();
}
scoped_ptr<InputMethodManagerImpl> manager_;
FakeInputMethodDelegate* delegate_;
MockIBusController* controller_;
MockCandidateWindowController* candidate_window_controller_;
MockIBusDaemonController* mock_ibus_daemon_controller_;
MockIBusInputContextClient* mock_ibus_input_context_client_;
MockIBusClient* mock_ibus_client_;
MockDBusThreadManagerWithoutGMock* mock_dbus_thread_manager_;
MockXKeyboard* xkeyboard_;
base::MessageLoop message_loop_;
MockComponentExtIMEManagerDelegate* mock_delegate_;
std::vector<ComponentExtensionIME> ime_list_;
private:
DISALLOW_COPY_AND_ASSIGN(InputMethodManagerImplTest);
};
class TestableComponentExtensionIMEManager
: public ComponentExtensionIMEManager {
public:
using ComponentExtensionIMEManager::GetComponentExtensionIMEId;
};
class TestObserver : public InputMethodManager::Observer {
public:
TestObserver()
: input_method_changed_count_(0),
input_method_property_changed_count_(0),
last_show_message_(false) {
}
virtual ~TestObserver() {}
virtual void InputMethodChanged(InputMethodManager* manager,
bool show_message) OVERRIDE {
++input_method_changed_count_;
last_show_message_ = show_message;
}
virtual void InputMethodPropertyChanged(
InputMethodManager* manager) OVERRIDE {
++input_method_property_changed_count_;
}
int input_method_changed_count_;
int input_method_property_changed_count_;
bool last_show_message_;
private:
DISALLOW_COPY_AND_ASSIGN(TestObserver);
};
class TestCandidateWindowObserver
: public InputMethodManager::CandidateWindowObserver {
public:
TestCandidateWindowObserver()
: candidate_window_opened_count_(0),
candidate_window_closed_count_(0) {
}
virtual ~TestCandidateWindowObserver() {}
virtual void CandidateWindowOpened(InputMethodManager* manager) OVERRIDE {
++candidate_window_opened_count_;
}
virtual void CandidateWindowClosed(InputMethodManager* manager) OVERRIDE {
++candidate_window_closed_count_;
}
int candidate_window_opened_count_;
int candidate_window_closed_count_;
private:
DISALLOW_COPY_AND_ASSIGN(TestCandidateWindowObserver);
};
} // namespace
TEST_F(InputMethodManagerImplTest, TestGetXKeyboard) {
EXPECT_TRUE(manager_->GetXKeyboard());
EXPECT_EQ(xkeyboard_, manager_->GetXKeyboard());
}
TEST_F(InputMethodManagerImplTest, TestCandidateWindowObserver) {
TestCandidateWindowObserver observer;
candidate_window_controller_->NotifyCandidateWindowOpened(); // nop
candidate_window_controller_->NotifyCandidateWindowClosed(); // nop
manager_->AddCandidateWindowObserver(&observer);
candidate_window_controller_->NotifyCandidateWindowOpened();
EXPECT_EQ(1, observer.candidate_window_opened_count_);
candidate_window_controller_->NotifyCandidateWindowClosed();
EXPECT_EQ(1, observer.candidate_window_closed_count_);
candidate_window_controller_->NotifyCandidateWindowOpened();
EXPECT_EQ(2, observer.candidate_window_opened_count_);
candidate_window_controller_->NotifyCandidateWindowClosed();
EXPECT_EQ(2, observer.candidate_window_closed_count_);
manager_->RemoveCandidateWindowObserver(&observer);
}
TEST_F(InputMethodManagerImplTest, TestObserver) {
// For http://crbug.com/19655#c11 - (3). browser_state_monitor_unittest.cc is
// also for the scenario.
TestObserver observer;
InitComponentExtension();
InitIBusBus();
manager_->AddObserver(&observer);
EXPECT_EQ(0, observer.input_method_changed_count_);
manager_->EnableLayouts("en-US", "xkb:us::eng");
EXPECT_EQ(1, observer.input_method_changed_count_);
EXPECT_EQ(1, observer.input_method_property_changed_count_);
manager_->ChangeInputMethod("xkb:us:dvorak:eng");
EXPECT_FALSE(observer.last_show_message_);
EXPECT_EQ(2, observer.input_method_changed_count_);
EXPECT_EQ(2, observer.input_method_property_changed_count_);
manager_->ChangeInputMethod("xkb:us:dvorak:eng");
EXPECT_FALSE(observer.last_show_message_);
// The observer is always notified even when the same input method ID is
// passed to ChangeInputMethod() more than twice.
EXPECT_EQ(3, observer.input_method_changed_count_);
EXPECT_EQ(3, observer.input_method_property_changed_count_);
controller_->NotifyPropertyChangedForTesting();
EXPECT_EQ(4, observer.input_method_property_changed_count_);
controller_->NotifyPropertyChangedForTesting();
EXPECT_EQ(5, observer.input_method_property_changed_count_);
manager_->RemoveObserver(&observer);
}
TEST_F(InputMethodManagerImplTest, TestGetSupportedInputMethods) {
InitComponentExtension();
InitIBusBus();
scoped_ptr<InputMethodDescriptors> methods(
manager_->GetSupportedInputMethods());
ASSERT_TRUE(methods.get());
// Try to find random 4-5 layuts and IMEs to make sure the returned list is
// correct.
const InputMethodDescriptor* id_to_find =
manager_->GetInputMethodUtil()->GetInputMethodDescriptorFromId(
nacl_mozc_us_id);
id_to_find = manager_->GetInputMethodUtil()->GetInputMethodDescriptorFromId(
"xkb:us::eng");
EXPECT_TRUE(Contain(*methods.get(), *id_to_find));
id_to_find = manager_->GetInputMethodUtil()->GetInputMethodDescriptorFromId(
"xkb:us:dvorak:eng");
EXPECT_TRUE(Contain(*methods.get(), *id_to_find));
id_to_find = manager_->GetInputMethodUtil()->GetInputMethodDescriptorFromId(
"xkb:fr::fra");
EXPECT_TRUE(Contain(*methods.get(), *id_to_find));
}
TEST_F(InputMethodManagerImplTest, TestEnableLayouts) {
// Currently 5 keyboard layouts are supported for en-US, and 1 for ja. See
// ibus_input_method.txt.
InitComponentExtension();
InitIBusBus();
manager_->EnableLayouts("en-US", "");
EXPECT_EQ(5U, manager_->GetNumActiveInputMethods());
for (size_t i = 0; i < manager_->GetActiveInputMethodIds().size(); ++i)
LOG(ERROR) << manager_->GetActiveInputMethodIds().at(i);
// For http://crbug.com/19655#c11 - (2)
EXPECT_EQ(0, mock_ibus_daemon_controller_->start_count());
// For http://crbug.com/19655#c11 - (5)
// The hardware keyboard layout "xkb:us::eng" is always active, hence 2U.
manager_->EnableLayouts("ja", ""); // Japanese
EXPECT_EQ(2U, manager_->GetNumActiveInputMethods());
EXPECT_EQ(0, mock_ibus_daemon_controller_->start_count());
}
TEST_F(InputMethodManagerImplTest, TestEnableLayoutsNonUsHardwareKeyboard) {
// The physical layout is French.
delegate_->set_hardware_keyboard_layout("xkb:fr::fra");
manager_->EnableLayouts("en-US", "");
EXPECT_EQ(6U, manager_->GetNumActiveInputMethods()); // 5 + French
// The physical layout is Japanese.
delegate_->set_hardware_keyboard_layout("xkb:jp::jpn");
manager_->EnableLayouts("ja", "");
// "xkb:us::eng" is not needed, hence 1.
EXPECT_EQ(1U, manager_->GetNumActiveInputMethods());
}
TEST_F(InputMethodManagerImplTest, TestActiveInputMethods) {
manager_->EnableLayouts("ja", ""); // Japanese
EXPECT_EQ(2U, manager_->GetNumActiveInputMethods());
scoped_ptr<InputMethodDescriptors> methods(
manager_->GetActiveInputMethods());
ASSERT_TRUE(methods.get());
EXPECT_EQ(2U, methods->size());
const InputMethodDescriptor* id_to_find =
manager_->GetInputMethodUtil()->GetInputMethodDescriptorFromId(
"xkb:us::eng");
EXPECT_TRUE(Contain(*methods.get(), *id_to_find));
id_to_find = manager_->GetInputMethodUtil()->GetInputMethodDescriptorFromId(
"xkb:jp::jpn");
EXPECT_TRUE(Contain(*methods.get(), *id_to_find));
}
TEST_F(InputMethodManagerImplTest, TestEnableTwoLayouts) {
// For http://crbug.com/19655#c11 - (8), step 6.
TestObserver observer;
manager_->AddObserver(&observer);
InitComponentExtension();
InitIBusBus();
manager_->SetState(InputMethodManager::STATE_BROWSER_SCREEN);
std::vector<std::string> ids;
ids.push_back("xkb:us:dvorak:eng");
ids.push_back("xkb:us:colemak:eng");
EXPECT_TRUE(manager_->EnableInputMethods(ids));
EXPECT_EQ(2U, manager_->GetNumActiveInputMethods());
// Since all the IDs added avobe are keyboard layouts, Start() should not be
// called.
EXPECT_EQ(0, mock_ibus_daemon_controller_->start_count());
EXPECT_EQ(1, observer.input_method_changed_count_);
EXPECT_EQ(ids[0], manager_->GetCurrentInputMethod().id());
EXPECT_EQ("us(dvorak)", xkeyboard_->last_layout_);
// Disable Dvorak.
ids.erase(ids.begin());
EXPECT_TRUE(manager_->EnableInputMethods(ids));
EXPECT_EQ(1U, manager_->GetNumActiveInputMethods());
EXPECT_EQ(2, observer.input_method_changed_count_);
EXPECT_EQ(ids[0], // colemak
manager_->GetCurrentInputMethod().id());
EXPECT_EQ("us(colemak)", xkeyboard_->last_layout_);
manager_->RemoveObserver(&observer);
}
TEST_F(InputMethodManagerImplTest, TestEnableThreeLayouts) {
// For http://crbug.com/19655#c11 - (9).
TestObserver observer;
manager_->AddObserver(&observer);
InitComponentExtension();
InitIBusBus();
manager_->SetState(InputMethodManager::STATE_BROWSER_SCREEN);
std::vector<std::string> ids;
ids.push_back("xkb:us::eng");
ids.push_back("xkb:us:dvorak:eng");
ids.push_back("xkb:us:colemak:eng");
EXPECT_TRUE(manager_->EnableInputMethods(ids));
EXPECT_EQ(3U, manager_->GetNumActiveInputMethods());
EXPECT_EQ(1, observer.input_method_changed_count_);
EXPECT_EQ(ids[0], manager_->GetCurrentInputMethod().id());
EXPECT_EQ("us", xkeyboard_->last_layout_);
// Switch to Dvorak.
manager_->SwitchToNextInputMethod();
EXPECT_EQ(2, observer.input_method_changed_count_);
EXPECT_EQ(ids[1], manager_->GetCurrentInputMethod().id());
EXPECT_EQ("us(dvorak)", xkeyboard_->last_layout_);
// Disable Dvorak.
ids.erase(ids.begin() + 1);
EXPECT_TRUE(manager_->EnableInputMethods(ids));
EXPECT_EQ(2U, manager_->GetNumActiveInputMethods());
EXPECT_EQ(3, observer.input_method_changed_count_);
EXPECT_EQ(ids[0], // US Qwerty
manager_->GetCurrentInputMethod().id());
EXPECT_EQ("us", xkeyboard_->last_layout_);
manager_->RemoveObserver(&observer);
}
TEST_F(InputMethodManagerImplTest, TestEnableLayoutAndIme) {
// For http://crbug.com/19655#c11 - (10).
TestObserver observer;
manager_->AddObserver(&observer);
InitComponentExtension();
InitIBusBus();
manager_->SetState(InputMethodManager::STATE_BROWSER_SCREEN);
std::vector<std::string> ids;
ids.push_back("xkb:us:dvorak:eng");
ids.push_back(nacl_mozc_us_id);
EXPECT_TRUE(manager_->EnableInputMethods(ids));
EXPECT_EQ(1, mock_ibus_daemon_controller_->start_count());
EXPECT_EQ(1, observer.input_method_changed_count_);
EXPECT_EQ(ids[0], manager_->GetCurrentInputMethod().id());
EXPECT_EQ("us(dvorak)", xkeyboard_->last_layout_);
// Switch to Mozc
manager_->SwitchToNextInputMethod();
EXPECT_EQ(2, observer.input_method_changed_count_);
EXPECT_EQ(ids[1], manager_->GetCurrentInputMethod().id());
EXPECT_EQ("us", xkeyboard_->last_layout_);
// Disable Mozc.
ids.erase(ids.begin() + 1);
EXPECT_TRUE(manager_->EnableInputMethods(ids));
EXPECT_EQ(1U, manager_->GetNumActiveInputMethods());
EXPECT_EQ(ids[0], manager_->GetCurrentInputMethod().id());
EXPECT_EQ("us(dvorak)", xkeyboard_->last_layout_);
// Currently, to work around a crash issue at crosbug.com/27051,
// controller_->Stop(); is NOT called when all IMEs are disabled
// or on shutdown.
EXPECT_EQ(0, mock_ibus_daemon_controller_->stop_count());
manager_->SetState(InputMethodManager::STATE_TERMINATING);
EXPECT_EQ(0, mock_ibus_daemon_controller_->stop_count());
manager_->RemoveObserver(&observer);
}
TEST_F(InputMethodManagerImplTest, TestEnableLayoutAndIme2) {
// For http://crbug.com/19655#c11 - (11).
TestObserver observer;
manager_->AddObserver(&observer);
InitComponentExtension();
InitIBusBus();
manager_->SetState(InputMethodManager::STATE_BROWSER_SCREEN);
std::vector<std::string> ids;
ids.push_back("xkb:us:dvorak:eng");
ids.push_back(nacl_mozc_us_id);
EXPECT_TRUE(manager_->EnableInputMethods(ids));
EXPECT_EQ(1, mock_ibus_daemon_controller_->start_count());
EXPECT_EQ(1, observer.input_method_changed_count_);
EXPECT_EQ(ids[0], manager_->GetCurrentInputMethod().id());
EXPECT_EQ("us(dvorak)", xkeyboard_->last_layout_);
// Disable Dvorak.
ids.erase(ids.begin());
EXPECT_TRUE(manager_->EnableInputMethods(ids));
EXPECT_EQ(1U, manager_->GetNumActiveInputMethods());
EXPECT_EQ(ids[0], // Mozc
manager_->GetCurrentInputMethod().id());
EXPECT_EQ("us", xkeyboard_->last_layout_);
manager_->RemoveObserver(&observer);
}
TEST_F(InputMethodManagerImplTest, TestEnableImes) {
TestObserver observer;
manager_->AddObserver(&observer);
InitComponentExtension();
InitIBusBus();
manager_->SetState(InputMethodManager::STATE_BROWSER_SCREEN);
std::vector<std::string> ids;
ids.push_back("_comp_ime_nmblnjkfdkabgdofidlkienfnnbjhnabext2_engine1_engine_id");
ids.push_back("mozc-dv");
EXPECT_TRUE(manager_->EnableInputMethods(ids));
EXPECT_EQ(1, mock_ibus_daemon_controller_->start_count());
EXPECT_EQ(1, observer.input_method_changed_count_);
EXPECT_EQ(ids[0], manager_->GetCurrentInputMethod().id());
EXPECT_EQ("us", xkeyboard_->last_layout_);
manager_->RemoveObserver(&observer);
}
TEST_F(InputMethodManagerImplTest, TestEnableUnknownIds) {
TestObserver observer;
manager_->AddObserver(&observer);
manager_->SetState(InputMethodManager::STATE_BROWSER_SCREEN);
std::vector<std::string> ids;
ids.push_back("xkb:tl::tlh"); // Klingon, which is not supported.
ids.push_back("unknown-super-cool-ime");
EXPECT_FALSE(manager_->EnableInputMethods(ids));
// TODO(yusukes): Should we fall back to the hardware keyboard layout in this
// case?
EXPECT_EQ(0, observer.input_method_changed_count_);
manager_->RemoveObserver(&observer);
}
TEST_F(InputMethodManagerImplTest, TestEnableLayoutsThenLock) {
// For http://crbug.com/19655#c11 - (14).
TestObserver observer;
manager_->AddObserver(&observer);
InitComponentExtension();
InitIBusBus();
manager_->SetState(InputMethodManager::STATE_BROWSER_SCREEN);
std::vector<std::string> ids;
ids.push_back("xkb:us::eng");
ids.push_back("xkb:us:dvorak:eng");
EXPECT_TRUE(manager_->EnableInputMethods(ids));
EXPECT_EQ(2U, manager_->GetNumActiveInputMethods());
EXPECT_EQ(1, observer.input_method_changed_count_);
EXPECT_EQ(ids[0], manager_->GetCurrentInputMethod().id());
EXPECT_EQ("us", xkeyboard_->last_layout_);
// Switch to Dvorak.
manager_->SwitchToNextInputMethod();
EXPECT_EQ(2, observer.input_method_changed_count_);
EXPECT_EQ(ids[1], manager_->GetCurrentInputMethod().id());
EXPECT_EQ("us(dvorak)", xkeyboard_->last_layout_);
// Lock screen
manager_->SetState(InputMethodManager::STATE_LOCK_SCREEN);
EXPECT_EQ(2U, manager_->GetNumActiveInputMethods());
EXPECT_EQ(ids[1], // still Dvorak
manager_->GetCurrentInputMethod().id());
EXPECT_EQ("us(dvorak)", xkeyboard_->last_layout_);
// Switch back to Qwerty.
manager_->SwitchToNextInputMethod();
EXPECT_EQ(ids[0], manager_->GetCurrentInputMethod().id());
EXPECT_EQ("us", xkeyboard_->last_layout_);
// Unlock screen. The original state, Dvorak, is restored.
manager_->SetState(InputMethodManager::STATE_BROWSER_SCREEN);
EXPECT_EQ(2U, manager_->GetNumActiveInputMethods());
EXPECT_EQ(ids[1], manager_->GetCurrentInputMethod().id());
EXPECT_EQ("us(dvorak)", xkeyboard_->last_layout_);
manager_->RemoveObserver(&observer);
}
TEST_F(InputMethodManagerImplTest, SwithchInputMethodTest) {
// For http://crbug.com/19655#c11 - (15).
TestObserver observer;
manager_->AddObserver(&observer);
InitComponentExtension();
InitIBusBus();
manager_->SetState(InputMethodManager::STATE_BROWSER_SCREEN);
std::vector<std::string> ids;
ids.push_back("xkb:us:dvorak:eng");
ids.push_back("_comp_ime_nmblnjkfdkabgdofidlkienfnnbjhnabext2_engine2_engine_id");
ids.push_back("_comp_ime_nmblnjkfdkabgdofidlkienfnnbjhnabext2_engine1_engine_id");
EXPECT_TRUE(manager_->EnableInputMethods(ids));
EXPECT_EQ(3U, manager_->GetNumActiveInputMethods());
EXPECT_EQ(1, observer.input_method_changed_count_);
EXPECT_EQ(ids[0], manager_->GetCurrentInputMethod().id());
EXPECT_EQ("us(dvorak)", xkeyboard_->last_layout_);
// Switch to Mozc.
manager_->SwitchToNextInputMethod();
EXPECT_EQ(2, observer.input_method_changed_count_);
EXPECT_EQ(ids[1], manager_->GetCurrentInputMethod().id());
EXPECT_EQ("us(dvorak)", xkeyboard_->last_layout_);
// Lock screen
manager_->SetState(InputMethodManager::STATE_LOCK_SCREEN);
EXPECT_EQ(2U, manager_->GetNumActiveInputMethods()); // Qwerty+Dvorak.
EXPECT_EQ("xkb:us:dvorak:eng",
manager_->GetCurrentInputMethod().id());
EXPECT_EQ("us(dvorak)", xkeyboard_->last_layout_);
// controller_->Stop() should never be called when the screen is locked even
// after crosbug.com/27051 is fixed.
EXPECT_EQ(0, mock_ibus_daemon_controller_->stop_count());
manager_->SwitchToNextInputMethod();
EXPECT_EQ("xkb:us::eng", // The hardware keyboard layout.
manager_->GetCurrentInputMethod().id());
EXPECT_EQ("us", xkeyboard_->last_layout_);
// Unlock screen. The original state, pinyin-dv, is restored.
manager_->SetState(InputMethodManager::STATE_BROWSER_SCREEN);
EXPECT_EQ(3U, manager_->GetNumActiveInputMethods()); // Dvorak and 2 IMEs.
EXPECT_EQ(ids[1], manager_->GetCurrentInputMethod().id());
EXPECT_EQ("us(dvorak)", xkeyboard_->last_layout_);
manager_->RemoveObserver(&observer);
}
TEST_F(InputMethodManagerImplTest, TestXkbSetting) {
// For http://crbug.com/19655#c11 - (8), step 7-11.
InitComponentExtension();
InitIBusBus();
manager_->SetState(InputMethodManager::STATE_BROWSER_SCREEN);
std::vector<std::string> ids;
ids.push_back("xkb:us:dvorak:eng");
ids.push_back("xkb:us:colemak:eng");
ids.push_back(nacl_mozc_jp_id);
ids.push_back(nacl_mozc_us_id);
EXPECT_TRUE(manager_->EnableInputMethods(ids));
EXPECT_EQ(4U, manager_->GetNumActiveInputMethods());
EXPECT_EQ(1, xkeyboard_->set_current_keyboard_layout_by_name_count_);
// See input_methods.txt for an expected XKB layout name.
EXPECT_EQ("us(dvorak)", xkeyboard_->last_layout_);
manager_->SwitchToNextInputMethod();
EXPECT_EQ(2, xkeyboard_->set_current_keyboard_layout_by_name_count_);
EXPECT_EQ("us(colemak)", xkeyboard_->last_layout_);
manager_->SwitchToNextInputMethod();
EXPECT_EQ(3, xkeyboard_->set_current_keyboard_layout_by_name_count_);
EXPECT_EQ("jp", xkeyboard_->last_layout_);
manager_->SwitchToNextInputMethod();
EXPECT_EQ(4, xkeyboard_->set_current_keyboard_layout_by_name_count_);
EXPECT_EQ("us", xkeyboard_->last_layout_);
manager_->SwitchToNextInputMethod();
EXPECT_EQ(5, xkeyboard_->set_current_keyboard_layout_by_name_count_);
EXPECT_EQ("us(dvorak)", xkeyboard_->last_layout_);
// Disable Dvorak.
ids.erase(ids.begin());
EXPECT_TRUE(manager_->EnableInputMethods(ids));
EXPECT_EQ(3U, manager_->GetNumActiveInputMethods());
EXPECT_EQ(6, xkeyboard_->set_current_keyboard_layout_by_name_count_);
EXPECT_EQ("us(colemak)", xkeyboard_->last_layout_);
}
TEST_F(InputMethodManagerImplTest, TestActivateInputMethodProperty) {
manager_->ActivateInputMethodProperty("key");
EXPECT_EQ(1, controller_->activate_input_method_property_count_);
EXPECT_EQ("key", controller_->activate_input_method_property_key_);
manager_->ActivateInputMethodProperty("key2");
EXPECT_EQ(2, controller_->activate_input_method_property_count_);
EXPECT_EQ("key2", controller_->activate_input_method_property_key_);
}
TEST_F(InputMethodManagerImplTest, TestGetCurrentInputMethodProperties) {
InitComponentExtension();
InitIBusBus();
EXPECT_TRUE(manager_->GetCurrentInputMethodProperties().empty());
manager_->SetState(InputMethodManager::STATE_BROWSER_SCREEN);
std::vector<std::string> ids;
ids.push_back("xkb:us::eng");
ids.push_back(nacl_mozc_us_id);
EXPECT_TRUE(manager_->EnableInputMethods(ids));
EXPECT_EQ(2U, manager_->GetNumActiveInputMethods());
EXPECT_TRUE(manager_->GetCurrentInputMethodProperties().empty());
manager_->ChangeInputMethod(nacl_mozc_us_id);
InputMethodPropertyList current_property_list;
current_property_list.push_back(InputMethodProperty("key",
"label",
false,
false));
controller_->SetCurrentPropertiesForTesting(current_property_list);
controller_->NotifyPropertyChangedForTesting();
ASSERT_EQ(1U, manager_->GetCurrentInputMethodProperties().size());
EXPECT_EQ("key", manager_->GetCurrentInputMethodProperties().at(0).key);
manager_->ChangeInputMethod("xkb:us::eng");
EXPECT_TRUE(manager_->GetCurrentInputMethodProperties().empty());
// Delayed asynchronous property update signal from the Mozc IME.
controller_->NotifyPropertyChangedForTesting();
// When XKB layout is in use, GetCurrentInputMethodProperties() should always
// return an empty list.
EXPECT_TRUE(manager_->GetCurrentInputMethodProperties().empty());
}
TEST_F(InputMethodManagerImplTest, TestGetCurrentInputMethodPropertiesTwoImes) {
InitComponentExtension();
InitIBusBus();
EXPECT_TRUE(manager_->GetCurrentInputMethodProperties().empty());
manager_->SetState(InputMethodManager::STATE_BROWSER_SCREEN);
std::vector<std::string> ids;
ids.push_back(nacl_mozc_us_id); // Japanese
ids.push_back("_comp_ime_nmblnjkfdkabgdofidlkienfnnbjhnabext2_engine1_engine_id"); // T-Chinese
EXPECT_TRUE(manager_->EnableInputMethods(ids));
EXPECT_EQ(2U, manager_->GetNumActiveInputMethods());
EXPECT_TRUE(manager_->GetCurrentInputMethodProperties().empty());
InputMethodPropertyList current_property_list;
current_property_list.push_back(InputMethodProperty("key-mozc",
"label",
false,
false));
controller_->SetCurrentPropertiesForTesting(current_property_list);
controller_->NotifyPropertyChangedForTesting();
ASSERT_EQ(1U, manager_->GetCurrentInputMethodProperties().size());
EXPECT_EQ("key-mozc", manager_->GetCurrentInputMethodProperties().at(0).key);
manager_->ChangeInputMethod("_comp_ime_nmblnjkfdkabgdofidlkienfnnbjhnabext2_engine1_engine_id");
// Since the IME is changed, the property for mozc Japanese should be hidden.
EXPECT_TRUE(manager_->GetCurrentInputMethodProperties().empty());
// Asynchronous property update signal from mozc-chewing.
current_property_list.clear();
current_property_list.push_back(InputMethodProperty("key-chewing",
"label",
false,
false));
controller_->SetCurrentPropertiesForTesting(current_property_list);
controller_->NotifyPropertyChangedForTesting();
ASSERT_EQ(1U, manager_->GetCurrentInputMethodProperties().size());
EXPECT_EQ("key-chewing",
manager_->GetCurrentInputMethodProperties().at(0).key);
}
TEST_F(InputMethodManagerImplTest, TestNextInputMethod) {
TestObserver observer;
manager_->AddObserver(&observer);
InitComponentExtension();
InitIBusBus();
// For http://crbug.com/19655#c11 - (1)
manager_->EnableLayouts("en-US", "xkb:us::eng");
EXPECT_EQ(5U, manager_->GetNumActiveInputMethods());
EXPECT_EQ("xkb:us::eng", manager_->GetCurrentInputMethod().id());
EXPECT_EQ("us", xkeyboard_->last_layout_);
manager_->SwitchToNextInputMethod();
EXPECT_TRUE(observer.last_show_message_);
EXPECT_EQ("xkb:us:intl:eng", manager_->GetCurrentInputMethod().id());
EXPECT_EQ("us(intl)", xkeyboard_->last_layout_);
manager_->SwitchToNextInputMethod();
EXPECT_TRUE(observer.last_show_message_);
EXPECT_EQ("xkb:us:altgr-intl:eng", manager_->GetCurrentInputMethod().id());
EXPECT_EQ("us(altgr-intl)", xkeyboard_->last_layout_);
manager_->SwitchToNextInputMethod();
EXPECT_TRUE(observer.last_show_message_);
EXPECT_EQ("xkb:us:dvorak:eng", manager_->GetCurrentInputMethod().id());
EXPECT_EQ("us(dvorak)", xkeyboard_->last_layout_);
manager_->SwitchToNextInputMethod();
EXPECT_TRUE(observer.last_show_message_);
EXPECT_EQ("xkb:us:colemak:eng", manager_->GetCurrentInputMethod().id());
EXPECT_EQ("us(colemak)", xkeyboard_->last_layout_);
manager_->SwitchToNextInputMethod();
EXPECT_TRUE(observer.last_show_message_);
EXPECT_EQ("xkb:us::eng", manager_->GetCurrentInputMethod().id());
EXPECT_EQ("us", xkeyboard_->last_layout_);
manager_->RemoveObserver(&observer);
}
TEST_F(InputMethodManagerImplTest, TestPreviousInputMethod) {
TestObserver observer;
manager_->AddObserver(&observer);
InitComponentExtension();
InitIBusBus();
ui::Accelerator keydown_accelerator(ui::VKEY_SPACE, ui::EF_CONTROL_DOWN);
keydown_accelerator.set_type(ui::ET_KEY_PRESSED);
ui::Accelerator keyup_accelerator(ui::VKEY_SPACE, ui::EF_CONTROL_DOWN);
keyup_accelerator.set_type(ui::ET_KEY_RELEASED);
manager_->EnableLayouts("en-US", "xkb:us::eng");
EXPECT_EQ(5U, manager_->GetNumActiveInputMethods());
EXPECT_EQ("xkb:us::eng", manager_->GetCurrentInputMethod().id());
EXPECT_EQ("us", xkeyboard_->last_layout_);
EXPECT_TRUE(manager_->SwitchToNextInputMethod());
EXPECT_TRUE(observer.last_show_message_);
EXPECT_EQ("xkb:us:intl:eng", manager_->GetCurrentInputMethod().id());
EXPECT_EQ("us(intl)", xkeyboard_->last_layout_);
EXPECT_TRUE(manager_->SwitchToPreviousInputMethod(keydown_accelerator));
EXPECT_TRUE(manager_->SwitchToPreviousInputMethod(keyup_accelerator));
EXPECT_TRUE(observer.last_show_message_);
EXPECT_EQ("xkb:us::eng", manager_->GetCurrentInputMethod().id());
EXPECT_EQ("us", xkeyboard_->last_layout_);
EXPECT_TRUE(manager_->SwitchToPreviousInputMethod(keydown_accelerator));
EXPECT_TRUE(manager_->SwitchToPreviousInputMethod(keyup_accelerator));
EXPECT_TRUE(observer.last_show_message_);
EXPECT_EQ("xkb:us:intl:eng", manager_->GetCurrentInputMethod().id());
EXPECT_EQ("us(intl)", xkeyboard_->last_layout_);
EXPECT_TRUE(manager_->SwitchToPreviousInputMethod(keydown_accelerator));
EXPECT_TRUE(manager_->SwitchToPreviousInputMethod(keyup_accelerator));
EXPECT_TRUE(observer.last_show_message_);
EXPECT_EQ("xkb:us::eng", manager_->GetCurrentInputMethod().id());
EXPECT_EQ("us", xkeyboard_->last_layout_);
EXPECT_TRUE(manager_->SwitchToNextInputMethod());
EXPECT_TRUE(observer.last_show_message_);
EXPECT_EQ("xkb:us:intl:eng", manager_->GetCurrentInputMethod().id());
EXPECT_EQ("us(intl)", xkeyboard_->last_layout_);
EXPECT_TRUE(manager_->SwitchToNextInputMethod());
EXPECT_TRUE(observer.last_show_message_);
EXPECT_EQ("xkb:us:altgr-intl:eng", manager_->GetCurrentInputMethod().id());
EXPECT_EQ("us(altgr-intl)", xkeyboard_->last_layout_);
EXPECT_TRUE(manager_->SwitchToPreviousInputMethod(keydown_accelerator));
EXPECT_TRUE(manager_->SwitchToPreviousInputMethod(keyup_accelerator));
EXPECT_TRUE(observer.last_show_message_);
EXPECT_EQ("xkb:us:intl:eng", manager_->GetCurrentInputMethod().id());
EXPECT_EQ("us(intl)", xkeyboard_->last_layout_);
EXPECT_TRUE(manager_->SwitchToPreviousInputMethod(keydown_accelerator));
EXPECT_TRUE(manager_->SwitchToPreviousInputMethod(keyup_accelerator));
EXPECT_TRUE(observer.last_show_message_);
EXPECT_EQ("xkb:us:altgr-intl:eng", manager_->GetCurrentInputMethod().id());
EXPECT_EQ("us(altgr-intl)", xkeyboard_->last_layout_);
manager_->RemoveObserver(&observer);
}
TEST_F(InputMethodManagerImplTest,
TestSwitchToPreviousInputMethodForOneActiveInputMethod) {
TestObserver observer;
manager_->AddObserver(&observer);
InitComponentExtension();
InitIBusBus();
ui::Accelerator keydown_accelerator(ui::VKEY_SPACE, ui::EF_CONTROL_DOWN);
keydown_accelerator.set_type(ui::ET_KEY_PRESSED);
ui::Accelerator keyup_accelerator(ui::VKEY_SPACE, ui::EF_CONTROL_DOWN);
keyup_accelerator.set_type(ui::ET_KEY_RELEASED);
std::vector<std::string> ids;
ids.push_back("xkb:us:dvorak:eng");
EXPECT_TRUE(manager_->EnableInputMethods(ids));
EXPECT_EQ(1U, manager_->GetNumActiveInputMethods());
// Ctrl+Space accelerator should not be consumed if there is only one active
// input method.
EXPECT_FALSE(manager_->SwitchToPreviousInputMethod(keydown_accelerator));
EXPECT_FALSE(manager_->SwitchToPreviousInputMethod(keyup_accelerator));
manager_->RemoveObserver(&observer);
}
TEST_F(InputMethodManagerImplTest, TestSwitchInputMethodWithUsLayouts) {
TestObserver observer;
manager_->AddObserver(&observer);
InitComponentExtension();
InitIBusBus();
manager_->EnableLayouts("en-US", "xkb:us::eng");
EXPECT_EQ(5U, manager_->GetNumActiveInputMethods());
EXPECT_EQ("xkb:us::eng", manager_->GetCurrentInputMethod().id());
EXPECT_EQ("us", xkeyboard_->last_layout_);
// Henkan, Muhenkan, ZenkakuHankaku should be ignored when no Japanese IMEs
// and keyboards are enabled.
EXPECT_FALSE(manager_->SwitchInputMethod(
ui::Accelerator(ui::VKEY_CONVERT, ui::EF_NONE)));
EXPECT_FALSE(observer.last_show_message_);
EXPECT_EQ("xkb:us::eng", manager_->GetCurrentInputMethod().id());
EXPECT_EQ("us", xkeyboard_->last_layout_);
EXPECT_FALSE(manager_->SwitchInputMethod(
ui::Accelerator(ui::VKEY_NONCONVERT, ui::EF_NONE)));
EXPECT_EQ("xkb:us::eng", manager_->GetCurrentInputMethod().id());
EXPECT_EQ("us", xkeyboard_->last_layout_);
EXPECT_FALSE(manager_->SwitchInputMethod(
ui::Accelerator(ui::VKEY_DBE_SBCSCHAR, ui::EF_NONE)));
EXPECT_EQ("xkb:us::eng", manager_->GetCurrentInputMethod().id());
EXPECT_EQ("us", xkeyboard_->last_layout_);
EXPECT_FALSE(manager_->SwitchInputMethod(
ui::Accelerator(ui::VKEY_DBE_DBCSCHAR, ui::EF_NONE)));
EXPECT_EQ("xkb:us::eng", manager_->GetCurrentInputMethod().id());
EXPECT_EQ("us", xkeyboard_->last_layout_);
manager_->RemoveObserver(&observer);
}
TEST_F(InputMethodManagerImplTest, TestSwitchInputMethodWithJpLayout) {
// Enable "xkb:jp::jpn" and press Muhenkan/ZenkakuHankaku.
InitComponentExtension();
InitIBusBus();
ui::Accelerator keydown_accelerator(ui::VKEY_SPACE, ui::EF_CONTROL_DOWN);
keydown_accelerator.set_type(ui::ET_KEY_PRESSED);
ui::Accelerator keyup_accelerator(ui::VKEY_SPACE, ui::EF_CONTROL_DOWN);
keyup_accelerator.set_type(ui::ET_KEY_RELEASED);
manager_->EnableLayouts("ja", "xkb:us::eng");
EXPECT_EQ(2U, manager_->GetNumActiveInputMethods());
EXPECT_EQ("xkb:us::eng", manager_->GetCurrentInputMethod().id());
EXPECT_EQ("us", xkeyboard_->last_layout_);
EXPECT_TRUE(manager_->SwitchInputMethod(
ui::Accelerator(ui::VKEY_NONCONVERT, ui::EF_NONE)));
EXPECT_EQ("xkb:jp::jpn", manager_->GetCurrentInputMethod().id());
EXPECT_EQ("jp", xkeyboard_->last_layout_);
EXPECT_TRUE(manager_->SwitchToPreviousInputMethod(keydown_accelerator));
EXPECT_TRUE(manager_->SwitchToPreviousInputMethod(keyup_accelerator));
EXPECT_EQ("xkb:us::eng", manager_->GetCurrentInputMethod().id());
EXPECT_EQ("us", xkeyboard_->last_layout_);
EXPECT_TRUE(manager_->SwitchInputMethod(
ui::Accelerator(ui::VKEY_DBE_SBCSCHAR, ui::EF_NONE)));
EXPECT_EQ("xkb:jp::jpn", manager_->GetCurrentInputMethod().id());
EXPECT_EQ("jp", xkeyboard_->last_layout_);
EXPECT_TRUE(manager_->SwitchToPreviousInputMethod(keydown_accelerator));
EXPECT_TRUE(manager_->SwitchToPreviousInputMethod(keyup_accelerator));
EXPECT_EQ("xkb:us::eng", manager_->GetCurrentInputMethod().id());
EXPECT_EQ("us", xkeyboard_->last_layout_);
EXPECT_TRUE(manager_->SwitchInputMethod(
ui::Accelerator(ui::VKEY_DBE_DBCSCHAR, ui::EF_NONE)));
EXPECT_EQ("xkb:jp::jpn", manager_->GetCurrentInputMethod().id());
EXPECT_EQ("jp", xkeyboard_->last_layout_);
}
TEST_F(InputMethodManagerImplTest, TestSwitchInputMethodWithJpIme) {
InitComponentExtension();
InitIBusBus();
manager_->SetState(InputMethodManager::STATE_BROWSER_SCREEN);
std::vector<std::string> ids;
ids.push_back("xkb:jp::jpn");
ids.push_back(nacl_mozc_jp_id);
EXPECT_TRUE(manager_->EnableInputMethods(ids));
EXPECT_EQ("xkb:jp::jpn", manager_->GetCurrentInputMethod().id());
EXPECT_EQ("jp", xkeyboard_->last_layout_);
EXPECT_TRUE(manager_->SwitchInputMethod(
ui::Accelerator(ui::VKEY_DBE_DBCSCHAR, ui::EF_NONE)));
EXPECT_EQ(nacl_mozc_jp_id, manager_->GetCurrentInputMethod().id());
EXPECT_EQ("jp", xkeyboard_->last_layout_);
EXPECT_TRUE(manager_->SwitchInputMethod(
ui::Accelerator(ui::VKEY_DBE_DBCSCHAR, ui::EF_NONE)));
EXPECT_EQ("xkb:jp::jpn", manager_->GetCurrentInputMethod().id());
EXPECT_EQ("jp", xkeyboard_->last_layout_);
EXPECT_TRUE(manager_->SwitchInputMethod(
ui::Accelerator(ui::VKEY_CONVERT, ui::EF_NONE)));
EXPECT_EQ(nacl_mozc_jp_id, manager_->GetCurrentInputMethod().id());
EXPECT_EQ("jp", xkeyboard_->last_layout_);
EXPECT_TRUE(manager_->SwitchInputMethod(
ui::Accelerator(ui::VKEY_CONVERT, ui::EF_NONE)));
EXPECT_EQ(nacl_mozc_jp_id, manager_->GetCurrentInputMethod().id());
EXPECT_EQ("jp", xkeyboard_->last_layout_);
EXPECT_TRUE(manager_->SwitchInputMethod(
ui::Accelerator(ui::VKEY_NONCONVERT, ui::EF_NONE)));
EXPECT_EQ("xkb:jp::jpn", manager_->GetCurrentInputMethod().id());
EXPECT_EQ("jp", xkeyboard_->last_layout_);
EXPECT_TRUE(manager_->SwitchInputMethod(
ui::Accelerator(ui::VKEY_NONCONVERT, ui::EF_NONE)));
EXPECT_EQ("xkb:jp::jpn", manager_->GetCurrentInputMethod().id());
EXPECT_EQ("jp", xkeyboard_->last_layout_);
// Add Dvorak.
ids.push_back("xkb:us:dvorak:eng");
EXPECT_TRUE(manager_->EnableInputMethods(ids));
EXPECT_EQ("xkb:jp::jpn", manager_->GetCurrentInputMethod().id());
EXPECT_EQ("jp", xkeyboard_->last_layout_);
EXPECT_TRUE(manager_->SwitchInputMethod(
ui::Accelerator(ui::VKEY_DBE_SBCSCHAR, ui::EF_NONE)));
EXPECT_EQ(nacl_mozc_jp_id, manager_->GetCurrentInputMethod().id());
EXPECT_EQ("jp", xkeyboard_->last_layout_);
EXPECT_TRUE(manager_->SwitchInputMethod(
ui::Accelerator(ui::VKEY_DBE_SBCSCHAR, ui::EF_NONE)));
EXPECT_EQ("xkb:jp::jpn", manager_->GetCurrentInputMethod().id());
EXPECT_EQ("jp", xkeyboard_->last_layout_);
}
TEST_F(InputMethodManagerImplTest, TestAddRemoveExtensionInputMethods) {
TestObserver observer;
manager_->AddObserver(&observer);
InitComponentExtension();
InitIBusBus();
manager_->SetState(InputMethodManager::STATE_BROWSER_SCREEN);
std::vector<std::string> ids;
ids.push_back("xkb:us:dvorak:eng");
EXPECT_TRUE(manager_->EnableInputMethods(ids));
EXPECT_EQ(1U, manager_->GetNumActiveInputMethods());
EXPECT_EQ(0, mock_ibus_daemon_controller_->start_count());
EXPECT_EQ(1, observer.input_method_changed_count_);
EXPECT_EQ(ids[0],
manager_->GetCurrentInputMethod().id());
EXPECT_EQ("us(dvorak)", xkeyboard_->last_layout_);
// Add two Extension IMEs.
std::vector<std::string> layouts;
layouts.push_back("us");
std::vector<std::string> languages;
languages.push_back("en-US");
manager_->AddInputMethodExtension(
extension_ime_util::GetInputMethodID("deadbeef", "engine_id"),
"deadbeef input method",
layouts,
languages,
GURL(),
NULL);
// Extension IMEs are not enabled by default.
EXPECT_EQ(1U, manager_->GetNumActiveInputMethods());
std::vector<std::string> extension_ime_ids;
extension_ime_ids.push_back(
extension_ime_util::GetInputMethodID("deadbeef", "engine_id"));
manager_->SetEnabledExtensionImes(&extension_ime_ids);
EXPECT_EQ(2U, manager_->GetNumActiveInputMethods());
// should be started.
EXPECT_EQ(1, mock_ibus_daemon_controller_->start_count());
{
scoped_ptr<InputMethodDescriptors> methods(
manager_->GetActiveInputMethods());
ASSERT_EQ(2U, methods->size());
EXPECT_EQ(extension_ime_util::GetInputMethodID("deadbeef", "engine_id"),
// Ext IMEs should be at the end of the list.
methods->at(1).id());
}
manager_->AddInputMethodExtension(
extension_ime_util::GetInputMethodID("cafebabe", "engine_id"),
"cafebabe input method",
layouts,
languages,
GURL(),
NULL);
EXPECT_EQ(2U, manager_->GetNumActiveInputMethods());
extension_ime_ids.push_back(
extension_ime_util::GetInputMethodID("cafebabe", "engine_id"));
manager_->SetEnabledExtensionImes(&extension_ime_ids);
EXPECT_EQ(3U, manager_->GetNumActiveInputMethods());
{
scoped_ptr<InputMethodDescriptors> methods(
manager_->GetActiveInputMethods());
ASSERT_EQ(3U, methods->size());
EXPECT_EQ(extension_ime_util::GetInputMethodID("deadbeef", "engine_id"),
// Ext IMEs should be at the end of the list.
methods->at(1).id());
}
// Remove them.
manager_->RemoveInputMethodExtension(
extension_ime_util::GetInputMethodID("deadbeef", "engine_id"));
EXPECT_EQ(2U, manager_->GetNumActiveInputMethods());
manager_->RemoveInputMethodExtension(
extension_ime_util::GetInputMethodID("cafebabe", "engine_id"));
EXPECT_EQ(1U, manager_->GetNumActiveInputMethods());
// Currently, to work around a crash issue at crosbug.com/27051,
// controller_->Stop(); is NOT called when all (extension) IMEs are disabled.
EXPECT_EQ(0, mock_ibus_daemon_controller_->stop_count());
manager_->RemoveObserver(&observer);
}
TEST_F(InputMethodManagerImplTest, TestAddExtensionInputThenLockScreen) {
TestObserver observer;
InitComponentExtension();
InitIBusBus();
manager_->AddObserver(&observer);
manager_->SetState(InputMethodManager::STATE_BROWSER_SCREEN);
std::vector<std::string> ids;
ids.push_back("xkb:us::eng");
EXPECT_TRUE(manager_->EnableInputMethods(ids));
EXPECT_EQ(1U, manager_->GetNumActiveInputMethods());
EXPECT_EQ(1, observer.input_method_changed_count_);
EXPECT_EQ(ids[0], manager_->GetCurrentInputMethod().id());
EXPECT_EQ("us", xkeyboard_->last_layout_);
// Add an Extension IME.
std::vector<std::string> layouts;
layouts.push_back("us(dvorak)");
std::vector<std::string> languages;
languages.push_back("en-US");
manager_->AddInputMethodExtension(
extension_ime_util::GetInputMethodID("deadbeef", "engine_id"),
"deadbeef input method",
layouts,
languages,
GURL(),
NULL);
// Extension IME is not enabled by default.
EXPECT_EQ(1U, manager_->GetNumActiveInputMethods());
EXPECT_EQ(1, observer.input_method_changed_count_);
std::vector<std::string> extension_ime_ids;
extension_ime_ids.push_back(
extension_ime_util::GetInputMethodID("deadbeef", "engine_id"));
manager_->SetEnabledExtensionImes(&extension_ime_ids);
EXPECT_EQ(2U, manager_->GetNumActiveInputMethods());
// Switch to the IME.
manager_->SwitchToNextInputMethod();
EXPECT_EQ(3, observer.input_method_changed_count_);
EXPECT_EQ(extension_ime_util::GetInputMethodID("deadbeef", "engine_id"),
manager_->GetCurrentInputMethod().id());
EXPECT_EQ("us(dvorak)", xkeyboard_->last_layout_);
// Lock the screen. This is for crosbug.com/27049.
manager_->SetState(InputMethodManager::STATE_LOCK_SCREEN);
EXPECT_EQ(1U, manager_->GetNumActiveInputMethods()); // Qwerty. No Ext. IME
EXPECT_EQ("xkb:us::eng",
manager_->GetCurrentInputMethod().id());
EXPECT_EQ("us", xkeyboard_->last_layout_);
EXPECT_EQ(0, mock_ibus_daemon_controller_->stop_count());
// Unlock the screen.
manager_->SetState(InputMethodManager::STATE_BROWSER_SCREEN);
EXPECT_EQ(2U, manager_->GetNumActiveInputMethods());
EXPECT_EQ(extension_ime_util::GetInputMethodID("deadbeef", "engine_id"),
manager_->GetCurrentInputMethod().id());
EXPECT_EQ("us(dvorak)", xkeyboard_->last_layout_);
{
// This is for crosbug.com/27052.
scoped_ptr<InputMethodDescriptors> methods(
manager_->GetActiveInputMethods());
ASSERT_EQ(2U, methods->size());
EXPECT_EQ(extension_ime_util::GetInputMethodID("deadbeef", "engine_id"),
// Ext. IMEs should be at the end of the list.
methods->at(1).id());
}
manager_->RemoveObserver(&observer);
}
TEST_F(InputMethodManagerImplTest, TestReset) {
InitComponentExtension();
InitIBusBus();
manager_->SetState(InputMethodManager::STATE_BROWSER_SCREEN);
std::vector<std::string> ids;
ids.push_back("xkb:us::eng");
ids.push_back(nacl_mozc_us_id);
EXPECT_TRUE(manager_->EnableInputMethods(ids));
EXPECT_EQ(2U, manager_->GetNumActiveInputMethods());
EXPECT_EQ(1, mock_ibus_input_context_client_->reset_call_count());
manager_->ChangeInputMethod(nacl_mozc_us_id);
EXPECT_EQ(1, mock_ibus_client_->set_global_engine_call_count());
EXPECT_EQ(nacl_mozc_us_id, mock_ibus_client_->latest_global_engine_name());
EXPECT_EQ(1, mock_ibus_input_context_client_->reset_call_count());
manager_->ChangeInputMethod("xkb:us::eng");
EXPECT_EQ(2, mock_ibus_client_->set_global_engine_call_count());
EXPECT_EQ(nacl_mozc_us_id, mock_ibus_client_->latest_global_engine_name());
EXPECT_EQ(1, mock_ibus_input_context_client_->reset_call_count());
}
TEST_F(InputMethodManagerImplTest,
ChangeInputMethodBeforeComponentExtensionInitialization_OneIME) {
manager_->SetState(InputMethodManager::STATE_BROWSER_SCREEN);
std::vector<std::string> ids;
ids.push_back(nacl_mozc_us_id);
EXPECT_TRUE(manager_->EnableInputMethods(ids));
EXPECT_EQ(1U, manager_->GetNumActiveInputMethods());
manager_->ChangeInputMethod(nacl_mozc_us_id);
InitIBusBus();
InitComponentExtension();
EXPECT_EQ(1, mock_ibus_client_->set_global_engine_call_count());
EXPECT_EQ(nacl_mozc_us_id, mock_ibus_client_->latest_global_engine_name());
}
TEST_F(InputMethodManagerImplTest,
ChangeInputMethodBeforeComponentExtensionInitialization_TwoIME) {
manager_->SetState(InputMethodManager::STATE_BROWSER_SCREEN);
std::vector<std::string> ids;
ids.push_back(nacl_mozc_us_id);
ids.push_back(nacl_mozc_jp_id);
EXPECT_TRUE(manager_->EnableInputMethods(ids));
EXPECT_EQ(2U, manager_->GetNumActiveInputMethods());
manager_->ChangeInputMethod(nacl_mozc_us_id);
manager_->ChangeInputMethod(nacl_mozc_jp_id);
InitComponentExtension();
InitIBusBus();
EXPECT_EQ(1, mock_ibus_client_->set_global_engine_call_count());
EXPECT_EQ(nacl_mozc_jp_id, mock_ibus_client_->latest_global_engine_name());
}
TEST_F(InputMethodManagerImplTest,
ChangeInputMethodBeforeComponentExtensionInitialization_CompOneIME) {
manager_->SetState(InputMethodManager::STATE_BROWSER_SCREEN);
const std::string ext_id =
TestableComponentExtensionIMEManager::GetComponentExtensionIMEId(
ime_list_[0].id,
ime_list_[0].engines[0].engine_id);
std::vector<std::string> ids;
ids.push_back(ext_id);
EXPECT_TRUE(manager_->EnableInputMethods(ids));
EXPECT_EQ(1U, manager_->GetNumActiveInputMethods());
manager_->ChangeInputMethod(ext_id);
InitComponentExtension();
InitIBusBus();
EXPECT_EQ(1, mock_ibus_client_->set_global_engine_call_count());
EXPECT_EQ(ext_id, mock_ibus_client_->latest_global_engine_name());
}
TEST_F(InputMethodManagerImplTest,
ChangeInputMethodBeforeComponentExtensionInitialization_CompTwoIME) {
manager_->SetState(InputMethodManager::STATE_BROWSER_SCREEN);
const std::string ext_id1 =
TestableComponentExtensionIMEManager::GetComponentExtensionIMEId(
ime_list_[0].id,
ime_list_[0].engines[0].engine_id);
const std::string ext_id2 =
TestableComponentExtensionIMEManager::GetComponentExtensionIMEId(
ime_list_[1].id,
ime_list_[1].engines[0].engine_id);
std::vector<std::string> ids;
ids.push_back(ext_id1);
ids.push_back(ext_id2);
EXPECT_TRUE(manager_->EnableInputMethods(ids));
EXPECT_EQ(2U, manager_->GetNumActiveInputMethods());
manager_->ChangeInputMethod(ext_id1);
manager_->ChangeInputMethod(ext_id2);
InitComponentExtension();
InitIBusBus();
EXPECT_EQ(1, mock_ibus_client_->set_global_engine_call_count());
EXPECT_EQ(ext_id2, mock_ibus_client_->latest_global_engine_name());
}
TEST_F(InputMethodManagerImplTest,
ChangeInputMethod_ComponenteExtensionOneIME) {
InitComponentExtension();
InitIBusBus();
manager_->SetState(InputMethodManager::STATE_BROWSER_SCREEN);
const std::string ext_id =
TestableComponentExtensionIMEManager::GetComponentExtensionIMEId(
ime_list_[0].id,
ime_list_[0].engines[0].engine_id);
std::vector<std::string> ids;
ids.push_back(ext_id);
EXPECT_TRUE(manager_->EnableInputMethods(ids));
EXPECT_EQ(1U, manager_->GetNumActiveInputMethods());
EXPECT_EQ(1, mock_ibus_client_->set_global_engine_call_count());
EXPECT_EQ(ext_id, mock_ibus_client_->latest_global_engine_name());
}
TEST_F(InputMethodManagerImplTest,
ChangeInputMethod_ComponenteExtensionTwoIME) {
InitComponentExtension();
InitIBusBus();
manager_->SetState(InputMethodManager::STATE_BROWSER_SCREEN);
const std::string ext_id1 =
TestableComponentExtensionIMEManager::GetComponentExtensionIMEId(
ime_list_[0].id,
ime_list_[0].engines[0].engine_id);
const std::string ext_id2 =
TestableComponentExtensionIMEManager::GetComponentExtensionIMEId(
ime_list_[1].id,
ime_list_[1].engines[0].engine_id);
std::vector<std::string> ids;
ids.push_back(ext_id1);
ids.push_back(ext_id2);
EXPECT_TRUE(manager_->EnableInputMethods(ids));
EXPECT_EQ(2U, manager_->GetNumActiveInputMethods());
EXPECT_EQ(1, mock_ibus_client_->set_global_engine_call_count());
EXPECT_EQ(ext_id1, mock_ibus_client_->latest_global_engine_name());
manager_->ChangeInputMethod(ext_id2);
EXPECT_EQ(2, mock_ibus_client_->set_global_engine_call_count());
EXPECT_EQ(ext_id2, mock_ibus_client_->latest_global_engine_name());
}
TEST_F(InputMethodManagerImplTest,
MigrateOldInputMethodTest) {
std::vector<std::string> input_method_ids;
input_method_ids.push_back("mozc");
input_method_ids.push_back("mozc-jp");
input_method_ids.push_back("xkb:us::eng");
input_method_ids.push_back(nacl_mozc_us_id);
manager_->MigrateOldInputMethods(&input_method_ids);
ASSERT_EQ(4U, input_method_ids.size());
EXPECT_EQ(input_method_ids.end(),
std::find(input_method_ids.begin(), input_method_ids.end(),
"mozc"));
EXPECT_EQ(input_method_ids.end(),
std::find(input_method_ids.begin(), input_method_ids.end(),
"mozc-jp"));
EXPECT_NE(input_method_ids.end(),
std::find(input_method_ids.begin(), input_method_ids.end(),
"xkb:us::eng"));
EXPECT_NE(input_method_ids.end(),
std::find(input_method_ids.begin(), input_method_ids.end(),
nacl_mozc_us_id));
}
TEST_F(InputMethodManagerImplTest,
AsyncComponentExtentionInitializeBeforeIBusDaemonConnection) {
const std::string xkb_id = "xkb:cz::cze";
const std::string ime_id = nacl_mozc_us_id;
const std::string fallback_id = "xkb:us::eng";
std::vector<std::string> ids;
ids.push_back(xkb_id);
ids.push_back(ime_id);
EXPECT_TRUE(manager_->EnableInputMethods(ids));
// If component extension IME is not initialized, even XKB layout cannot be
// enabled.
manager_->ChangeInputMethod(xkb_id);
EXPECT_EQ(fallback_id, manager_->GetCurrentInputMethod().id());
// After component extension IME is initialized, previous input method should
// be automatically enabled.
InitComponentExtension();
EXPECT_EQ(xkb_id, manager_->GetCurrentInputMethod().id());
// However input method should not be enabled before establishment of
// connection with ibus-daemon.
manager_->ChangeInputMethod(ime_id);
// TODO(nona): Write expectation, GetCurrentInputMethod returns |ime_id| even
// the actual input method is not changed.
// After connection with ibus-daemon is established, previous specified input
// method should be enabled automatically.
InitIBusBus();
EXPECT_EQ(ime_id, manager_->GetCurrentInputMethod().id());
}
TEST_F(InputMethodManagerImplTest,
AsyncComponentExtentionInitializeAfterIBusDaemonConnection) {
const std::string xkb_id = "xkb:cz::cze";
const std::string ime_id = nacl_mozc_us_id;
const std::string fallback_id = "xkb:us::eng";
std::vector<std::string> ids;
ids.push_back(xkb_id);
ids.push_back(ime_id);
EXPECT_TRUE(manager_->EnableInputMethods(ids));
// If component extension IME is not initialized, even XKB layout cannot be
// enabled.
manager_->ChangeInputMethod(xkb_id);
EXPECT_EQ(fallback_id, manager_->GetCurrentInputMethod().id());
// Even after connection with ibus-daemon is established, ChangeInputMethod do
// nothing without component extension IME initialization.
InitIBusBus();
EXPECT_EQ(fallback_id, manager_->GetCurrentInputMethod().id());
// After component extension IME is initialized, previous specified input
// method should be automatically enabled.
InitComponentExtension();
EXPECT_EQ(xkb_id, manager_->GetCurrentInputMethod().id());
}
} // namespace input_method
} // namespace chromeos