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