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