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