• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2013 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 "ui/base/ime/remote_input_method_win.h"
6 
7 #include <InputScope.h>
8 
9 #include <vector>
10 
11 #include "base/memory/scoped_ptr.h"
12 #include "base/scoped_observer.h"
13 #include "base/strings/string16.h"
14 #include "testing/gtest/include/gtest/gtest.h"
15 #include "ui/base/ime/composition_text.h"
16 #include "ui/base/ime/dummy_text_input_client.h"
17 #include "ui/base/ime/input_method.h"
18 #include "ui/base/ime/input_method_delegate.h"
19 #include "ui/base/ime/input_method_observer.h"
20 #include "ui/base/ime/remote_input_method_delegate_win.h"
21 #include "ui/events/event.h"
22 
23 namespace ui {
24 namespace {
25 
26 class MockTextInputClient : public DummyTextInputClient {
27  public:
MockTextInputClient()28   MockTextInputClient()
29       : text_input_type_(TEXT_INPUT_TYPE_NONE),
30         text_input_mode_(TEXT_INPUT_MODE_DEFAULT),
31         call_count_set_composition_text_(0),
32         call_count_insert_char_(0),
33         call_count_insert_text_(0) {
34   }
35 
call_count_set_composition_text() const36   size_t call_count_set_composition_text() const {
37     return call_count_set_composition_text_;
38   }
inserted_text() const39   const base::string16& inserted_text() const {
40     return inserted_text_;
41   }
call_count_insert_char() const42   size_t call_count_insert_char() const {
43     return call_count_insert_char_;
44   }
call_count_insert_text() const45   size_t call_count_insert_text() const {
46     return call_count_insert_text_;
47   }
Reset()48   void Reset() {
49     text_input_type_ = TEXT_INPUT_TYPE_NONE;
50     text_input_mode_ = TEXT_INPUT_MODE_DEFAULT;
51     call_count_set_composition_text_ = 0;
52     inserted_text_.clear();
53     call_count_insert_char_ = 0;
54     call_count_insert_text_ = 0;
55     caret_bounds_ = gfx::Rect();
56     composition_character_bounds_.clear();
57   }
set_text_input_type(ui::TextInputType type)58   void set_text_input_type(ui::TextInputType type) {
59     text_input_type_ = type;
60   }
set_text_input_mode(ui::TextInputMode mode)61   void set_text_input_mode(ui::TextInputMode mode) {
62     text_input_mode_ = mode;
63   }
set_caret_bounds(const gfx::Rect & caret_bounds)64   void set_caret_bounds(const gfx::Rect& caret_bounds) {
65     caret_bounds_ = caret_bounds;
66   }
set_composition_character_bounds(const std::vector<gfx::Rect> & composition_character_bounds)67   void set_composition_character_bounds(
68       const std::vector<gfx::Rect>& composition_character_bounds) {
69     composition_character_bounds_ = composition_character_bounds;
70   }
71 
72  private:
73   // Overriden from DummyTextInputClient.
SetCompositionText(const ui::CompositionText & composition)74   virtual void SetCompositionText(
75       const ui::CompositionText& composition) OVERRIDE {
76     ++call_count_set_composition_text_;
77   }
InsertChar(char16 ch,int flags)78   virtual void InsertChar(char16 ch, int flags) OVERRIDE{
79     inserted_text_.append(1, ch);
80     ++call_count_insert_char_;
81   }
InsertText(const string16 & text)82   virtual void InsertText(const string16& text) OVERRIDE{
83     inserted_text_.append(text);
84     ++call_count_insert_text_;
85   }
GetTextInputType() const86   virtual ui::TextInputType GetTextInputType() const OVERRIDE {
87     return text_input_type_;
88   }
GetTextInputMode() const89   virtual ui::TextInputMode GetTextInputMode() const OVERRIDE {
90     return text_input_mode_;
91   }
GetCaretBounds() const92   virtual gfx::Rect GetCaretBounds() const {
93     return caret_bounds_;
94   }
GetCompositionCharacterBounds(uint32 index,gfx::Rect * rect) const95   virtual bool GetCompositionCharacterBounds(uint32 index,
96                                              gfx::Rect* rect) const OVERRIDE {
97     if (!rect || composition_character_bounds_.size() <= index)
98       return false;
99     *rect = composition_character_bounds_[index];
100     return true;
101   }
HasCompositionText() const102   virtual bool HasCompositionText() const OVERRIDE {
103     return !composition_character_bounds_.empty();
104   }
105 
106   ui::TextInputType text_input_type_;
107   ui::TextInputMode text_input_mode_;
108   gfx::Rect caret_bounds_;
109   std::vector<gfx::Rect> composition_character_bounds_;
110   base::string16 inserted_text_;
111   size_t call_count_set_composition_text_;
112   size_t call_count_insert_char_;
113   size_t call_count_insert_text_;
114   DISALLOW_COPY_AND_ASSIGN(MockTextInputClient);
115 };
116 
117 class MockInputMethodDelegate : public internal::InputMethodDelegate {
118  public:
MockInputMethodDelegate()119   MockInputMethodDelegate() {}
120 
fabricated_key_events() const121   const std::vector<ui::KeyboardCode>& fabricated_key_events() const {
122     return fabricated_key_events_;
123   }
Reset()124   void Reset() {
125     fabricated_key_events_.clear();
126   }
127 
128  private:
DispatchKeyEventPostIME(const base::NativeEvent & native_key_event)129   virtual bool DispatchKeyEventPostIME(
130       const base::NativeEvent& native_key_event) OVERRIDE {
131     EXPECT_TRUE(false) << "Not reach here";
132     return true;
133   }
DispatchFabricatedKeyEventPostIME(ui::EventType type,ui::KeyboardCode key_code,int flags)134   virtual bool DispatchFabricatedKeyEventPostIME(ui::EventType type,
135                                                  ui::KeyboardCode key_code,
136                                                  int flags) OVERRIDE {
137     fabricated_key_events_.push_back(key_code);
138     return true;
139   }
140 
141   std::vector<ui::KeyboardCode> fabricated_key_events_;
142   DISALLOW_COPY_AND_ASSIGN(MockInputMethodDelegate);
143 };
144 
145 class MockRemoteInputMethodDelegateWin
146     : public internal::RemoteInputMethodDelegateWin {
147  public:
MockRemoteInputMethodDelegateWin()148   MockRemoteInputMethodDelegateWin()
149       : cancel_composition_called_(false),
150         text_input_client_updated_called_(false) {
151   }
152 
cancel_composition_called() const153   bool cancel_composition_called() const {
154     return cancel_composition_called_;
155   }
text_input_client_updated_called() const156   bool text_input_client_updated_called() const {
157     return text_input_client_updated_called_;
158   }
input_scopes() const159   const std::vector<int32>& input_scopes() const {
160     return input_scopes_;
161   }
composition_character_bounds() const162   const std::vector<gfx::Rect>& composition_character_bounds() const {
163     return composition_character_bounds_;
164   }
Reset()165   void Reset() {
166     cancel_composition_called_ = false;
167     text_input_client_updated_called_ = false;
168     input_scopes_.clear();
169     composition_character_bounds_.clear();
170   }
171 
172  private:
CancelComposition()173   virtual void CancelComposition() OVERRIDE {
174     cancel_composition_called_ = true;
175   }
176 
OnTextInputClientUpdated(const std::vector<int32> & input_scopes,const std::vector<gfx::Rect> & composition_character_bounds)177   virtual void OnTextInputClientUpdated(
178       const std::vector<int32>& input_scopes,
179       const std::vector<gfx::Rect>& composition_character_bounds) OVERRIDE {
180     text_input_client_updated_called_ = true;
181     input_scopes_ = input_scopes;
182     composition_character_bounds_ = composition_character_bounds;
183   }
184 
185   bool cancel_composition_called_;
186   bool text_input_client_updated_called_;
187   std::vector<int32> input_scopes_;
188   std::vector<gfx::Rect> composition_character_bounds_;
189   DISALLOW_COPY_AND_ASSIGN(MockRemoteInputMethodDelegateWin);
190 };
191 
192 class MockInputMethodObserver : public InputMethodObserver {
193  public:
MockInputMethodObserver()194   MockInputMethodObserver()
195       : on_text_input_state_changed_(0),
196         on_input_method_destroyed_changed_(0) {
197   }
~MockInputMethodObserver()198   virtual ~MockInputMethodObserver() {
199   }
Reset()200   void Reset() {
201     on_text_input_state_changed_ = 0;
202     on_input_method_destroyed_changed_ = 0;
203   }
on_text_input_state_changed() const204   size_t on_text_input_state_changed() const {
205     return on_text_input_state_changed_;
206   }
on_input_method_destroyed_changed() const207   size_t on_input_method_destroyed_changed() const {
208     return on_input_method_destroyed_changed_;
209   }
210 
211  private:
212   // Overriden from InputMethodObserver.
OnTextInputTypeChanged(const TextInputClient * client)213   virtual void OnTextInputTypeChanged(const TextInputClient* client) OVERRIDE {
214   }
OnFocus()215   virtual void OnFocus() OVERRIDE {
216   }
OnBlur()217   virtual void OnBlur() OVERRIDE {
218   }
OnCaretBoundsChanged(const TextInputClient * client)219   virtual void OnCaretBoundsChanged(const TextInputClient* client) OVERRIDE {
220   }
OnTextInputStateChanged(const TextInputClient * client)221   virtual void OnTextInputStateChanged(const TextInputClient* client) OVERRIDE {
222     ++on_text_input_state_changed_;
223   }
OnInputMethodDestroyed(const InputMethod * client)224   virtual void OnInputMethodDestroyed(const InputMethod* client) OVERRIDE {
225     ++on_input_method_destroyed_changed_;
226   }
227 
228   size_t on_text_input_state_changed_;
229   size_t on_input_method_destroyed_changed_;
230   DISALLOW_COPY_AND_ASSIGN(MockInputMethodObserver);
231 };
232 
233 typedef ScopedObserver<InputMethod, InputMethodObserver>
234     InputMethodScopedObserver;
235 
TEST(RemoteInputMethodWinTest,RemoteInputMethodPrivateWin)236 TEST(RemoteInputMethodWinTest, RemoteInputMethodPrivateWin) {
237   InputMethod* other_ptr = static_cast<InputMethod*>(NULL) + 1;
238 
239   // Use typed NULL to make EXPECT_NE happy until nullptr becomes available.
240   RemoteInputMethodPrivateWin* kNull =
241       static_cast<RemoteInputMethodPrivateWin*>(NULL);
242   EXPECT_EQ(kNull, RemoteInputMethodPrivateWin::Get(other_ptr));
243 
244   MockInputMethodDelegate delegate_;
245   scoped_ptr<InputMethod> input_method(CreateRemoteInputMethodWin(&delegate_));
246   EXPECT_NE(kNull, RemoteInputMethodPrivateWin::Get(input_method.get()));
247 
248   InputMethod* dangling_ptr = input_method.get();
249   input_method.reset(NULL);
250   EXPECT_EQ(kNull, RemoteInputMethodPrivateWin::Get(dangling_ptr));
251 }
252 
TEST(RemoteInputMethodWinTest,OnInputSourceChanged)253 TEST(RemoteInputMethodWinTest, OnInputSourceChanged) {
254   MockInputMethodDelegate delegate_;
255   scoped_ptr<InputMethod> input_method(CreateRemoteInputMethodWin(&delegate_));
256   RemoteInputMethodPrivateWin* private_ptr =
257       RemoteInputMethodPrivateWin::Get(input_method.get());
258   ASSERT_TRUE(private_ptr != NULL);
259 
260   private_ptr->OnInputSourceChanged(
261       MAKELANGID(LANG_JAPANESE, SUBLANG_JAPANESE_JAPAN), true);
262   EXPECT_EQ("ja-JP", input_method->GetInputLocale());
263   EXPECT_EQ(base::i18n::LEFT_TO_RIGHT,
264            input_method->GetInputTextDirection());
265 
266   private_ptr->OnInputSourceChanged(
267       MAKELANGID(LANG_ARABIC, SUBLANG_ARABIC_QATAR), true);
268   EXPECT_EQ("ar-QA", input_method->GetInputLocale());
269   EXPECT_EQ(base::i18n::RIGHT_TO_LEFT,
270             input_method->GetInputTextDirection());
271 }
272 
TEST(RemoteInputMethodWinTest,OnCandidatePopupChanged)273 TEST(RemoteInputMethodWinTest, OnCandidatePopupChanged) {
274   MockInputMethodDelegate delegate_;
275   scoped_ptr<InputMethod> input_method(CreateRemoteInputMethodWin(&delegate_));
276   RemoteInputMethodPrivateWin* private_ptr =
277       RemoteInputMethodPrivateWin::Get(input_method.get());
278   ASSERT_TRUE(private_ptr != NULL);
279 
280   // Initial value
281   EXPECT_FALSE(input_method->IsCandidatePopupOpen());
282 
283   private_ptr->OnCandidatePopupChanged(true);
284   EXPECT_TRUE(input_method->IsCandidatePopupOpen());
285 
286   private_ptr->OnCandidatePopupChanged(false);
287   EXPECT_FALSE(input_method->IsCandidatePopupOpen());
288 }
289 
TEST(RemoteInputMethodWinTest,CancelComposition)290 TEST(RemoteInputMethodWinTest, CancelComposition) {
291   MockInputMethodDelegate delegate_;
292   MockTextInputClient mock_text_input_client;
293   scoped_ptr<InputMethod> input_method(CreateRemoteInputMethodWin(&delegate_));
294 
295   // This must not cause a crash.
296   input_method->CancelComposition(&mock_text_input_client);
297 
298   RemoteInputMethodPrivateWin* private_ptr =
299       RemoteInputMethodPrivateWin::Get(input_method.get());
300   ASSERT_TRUE(private_ptr != NULL);
301   MockRemoteInputMethodDelegateWin mock_remote_delegate;
302   private_ptr->SetRemoteDelegate(&mock_remote_delegate);
303 
304   input_method->CancelComposition(&mock_text_input_client);
305   EXPECT_FALSE(mock_remote_delegate.cancel_composition_called());
306 
307   input_method->SetFocusedTextInputClient(&mock_text_input_client);
308   input_method->CancelComposition(&mock_text_input_client);
309   EXPECT_TRUE(mock_remote_delegate.cancel_composition_called());
310 }
311 
TEST(RemoteInputMethodWinTest,SetFocusedTextInputClient)312 TEST(RemoteInputMethodWinTest, SetFocusedTextInputClient) {
313   MockInputMethodDelegate delegate_;
314   MockTextInputClient mock_text_input_client;
315   scoped_ptr<InputMethod> input_method(CreateRemoteInputMethodWin(&delegate_));
316 
317   mock_text_input_client.set_caret_bounds(gfx::Rect(10, 0, 10, 20));
318   mock_text_input_client.set_text_input_type(ui::TEXT_INPUT_TYPE_URL);
319   input_method->SetFocusedTextInputClient(&mock_text_input_client);
320 
321   RemoteInputMethodPrivateWin* private_ptr =
322       RemoteInputMethodPrivateWin::Get(input_method.get());
323   ASSERT_TRUE(private_ptr != NULL);
324   MockRemoteInputMethodDelegateWin mock_remote_delegate;
325   private_ptr->SetRemoteDelegate(&mock_remote_delegate);
326 
327   // Initial state must be synced.
328   EXPECT_TRUE(mock_remote_delegate.text_input_client_updated_called());
329   ASSERT_EQ(1, mock_remote_delegate.composition_character_bounds().size());
330   EXPECT_EQ(gfx::Rect(10, 0, 10, 20),
331             mock_remote_delegate.composition_character_bounds()[0]);
332   ASSERT_EQ(1, mock_remote_delegate.input_scopes().size());
333   EXPECT_EQ(IS_URL, mock_remote_delegate.input_scopes()[0]);
334 
335   // State must be cleared by SetFocusedTextInputClient(NULL).
336   mock_remote_delegate.Reset();
337   input_method->SetFocusedTextInputClient(NULL);
338   EXPECT_TRUE(mock_remote_delegate.text_input_client_updated_called());
339   EXPECT_TRUE(mock_remote_delegate.composition_character_bounds().empty());
340   EXPECT_TRUE(mock_remote_delegate.input_scopes().empty());
341 }
342 
TEST(RemoteInputMethodWinTest,DetachTextInputClient)343 TEST(RemoteInputMethodWinTest, DetachTextInputClient) {
344   MockInputMethodDelegate delegate_;
345   MockTextInputClient mock_text_input_client;
346   scoped_ptr<InputMethod> input_method(CreateRemoteInputMethodWin(&delegate_));
347 
348   mock_text_input_client.set_caret_bounds(gfx::Rect(10, 0, 10, 20));
349   mock_text_input_client.set_text_input_type(ui::TEXT_INPUT_TYPE_URL);
350   input_method->SetFocusedTextInputClient(&mock_text_input_client);
351 
352   RemoteInputMethodPrivateWin* private_ptr =
353       RemoteInputMethodPrivateWin::Get(input_method.get());
354   ASSERT_TRUE(private_ptr != NULL);
355   MockRemoteInputMethodDelegateWin mock_remote_delegate;
356   private_ptr->SetRemoteDelegate(&mock_remote_delegate);
357 
358   // Initial state must be synced.
359   EXPECT_TRUE(mock_remote_delegate.text_input_client_updated_called());
360   ASSERT_EQ(1, mock_remote_delegate.composition_character_bounds().size());
361   EXPECT_EQ(gfx::Rect(10, 0, 10, 20),
362     mock_remote_delegate.composition_character_bounds()[0]);
363   ASSERT_EQ(1, mock_remote_delegate.input_scopes().size());
364   EXPECT_EQ(IS_URL, mock_remote_delegate.input_scopes()[0]);
365 
366   // State must be cleared by DetachTextInputClient
367   mock_remote_delegate.Reset();
368   input_method->DetachTextInputClient(&mock_text_input_client);
369   EXPECT_TRUE(mock_remote_delegate.text_input_client_updated_called());
370   EXPECT_TRUE(mock_remote_delegate.composition_character_bounds().empty());
371   EXPECT_TRUE(mock_remote_delegate.input_scopes().empty());
372 }
373 
TEST(RemoteInputMethodWinTest,OnCaretBoundsChanged)374 TEST(RemoteInputMethodWinTest, OnCaretBoundsChanged) {
375   MockInputMethodDelegate delegate_;
376   MockTextInputClient mock_text_input_client;
377   scoped_ptr<InputMethod> input_method(CreateRemoteInputMethodWin(&delegate_));
378 
379   // This must not cause a crash.
380   input_method->OnCaretBoundsChanged(&mock_text_input_client);
381 
382   mock_text_input_client.set_caret_bounds(gfx::Rect(10, 0, 10, 20));
383   input_method->SetFocusedTextInputClient(&mock_text_input_client);
384 
385   RemoteInputMethodPrivateWin* private_ptr =
386       RemoteInputMethodPrivateWin::Get(input_method.get());
387   ASSERT_TRUE(private_ptr != NULL);
388   MockRemoteInputMethodDelegateWin mock_remote_delegate;
389   private_ptr->SetRemoteDelegate(&mock_remote_delegate);
390 
391   // Initial state must be synced.
392   EXPECT_TRUE(mock_remote_delegate.text_input_client_updated_called());
393   ASSERT_EQ(1, mock_remote_delegate.composition_character_bounds().size());
394   EXPECT_EQ(gfx::Rect(10, 0, 10, 20),
395       mock_remote_delegate.composition_character_bounds()[0]);
396 
397   // Redundant OnCaretBoundsChanged must be ignored.
398   mock_remote_delegate.Reset();
399   input_method->OnCaretBoundsChanged(&mock_text_input_client);
400   EXPECT_FALSE(mock_remote_delegate.text_input_client_updated_called());
401 
402   // Check OnCaretBoundsChanged is handled. (w/o composition)
403   mock_remote_delegate.Reset();
404   mock_text_input_client.Reset();
405   mock_text_input_client.set_caret_bounds(gfx::Rect(10, 20, 30, 40));
406   input_method->OnCaretBoundsChanged(&mock_text_input_client);
407   EXPECT_TRUE(mock_remote_delegate.text_input_client_updated_called());
408   ASSERT_EQ(1, mock_remote_delegate.composition_character_bounds().size());
409   EXPECT_EQ(gfx::Rect(10, 20, 30, 40),
410       mock_remote_delegate.composition_character_bounds()[0]);
411 
412   // Check OnCaretBoundsChanged is handled. (w/ composition)
413   {
414     mock_remote_delegate.Reset();
415     mock_text_input_client.Reset();
416 
417     std::vector<gfx::Rect> bounds;
418     bounds.push_back(gfx::Rect(10, 20, 30, 40));
419     bounds.push_back(gfx::Rect(40, 30, 20, 10));
420     mock_text_input_client.set_composition_character_bounds(bounds);
421     input_method->OnCaretBoundsChanged(&mock_text_input_client);
422     EXPECT_TRUE(mock_remote_delegate.text_input_client_updated_called());
423     EXPECT_EQ(bounds, mock_remote_delegate.composition_character_bounds());
424   }
425 }
426 
TEST(RemoteInputMethodWinTest,OnTextInputTypeChanged)427 TEST(RemoteInputMethodWinTest, OnTextInputTypeChanged) {
428   MockInputMethodDelegate delegate_;
429   MockTextInputClient mock_text_input_client;
430   scoped_ptr<InputMethod> input_method(CreateRemoteInputMethodWin(&delegate_));
431 
432   // This must not cause a crash.
433   input_method->OnCaretBoundsChanged(&mock_text_input_client);
434 
435   mock_text_input_client.set_text_input_type(ui::TEXT_INPUT_TYPE_URL);
436   input_method->SetFocusedTextInputClient(&mock_text_input_client);
437 
438   RemoteInputMethodPrivateWin* private_ptr =
439       RemoteInputMethodPrivateWin::Get(input_method.get());
440   ASSERT_TRUE(private_ptr != NULL);
441   MockRemoteInputMethodDelegateWin mock_remote_delegate;
442   private_ptr->SetRemoteDelegate(&mock_remote_delegate);
443 
444   // Initial state must be synced.
445   EXPECT_TRUE(mock_remote_delegate.text_input_client_updated_called());
446   ASSERT_EQ(1, mock_remote_delegate.input_scopes().size());
447   EXPECT_EQ(IS_URL, mock_remote_delegate.input_scopes()[0]);
448 
449   // Check TEXT_INPUT_TYPE_NONE is handled.
450   mock_remote_delegate.Reset();
451   mock_text_input_client.Reset();
452   mock_text_input_client.set_text_input_type(ui::TEXT_INPUT_TYPE_NONE);
453   mock_text_input_client.set_text_input_mode(ui::TEXT_INPUT_MODE_KATAKANA);
454   input_method->OnTextInputTypeChanged(&mock_text_input_client);
455   EXPECT_TRUE(mock_remote_delegate.text_input_client_updated_called());
456   EXPECT_TRUE(mock_remote_delegate.input_scopes().empty());
457 
458   // Redundant OnTextInputTypeChanged must be ignored.
459   mock_remote_delegate.Reset();
460   input_method->OnTextInputTypeChanged(&mock_text_input_client);
461   EXPECT_FALSE(mock_remote_delegate.text_input_client_updated_called());
462 
463   mock_remote_delegate.Reset();
464   mock_text_input_client.Reset();
465   mock_text_input_client.set_caret_bounds(gfx::Rect(10, 20, 30, 40));
466   input_method->OnCaretBoundsChanged(&mock_text_input_client);
467 }
468 
TEST(RemoteInputMethodWinTest,DispatchKeyEvent_NativeKeyEvent)469 TEST(RemoteInputMethodWinTest, DispatchKeyEvent_NativeKeyEvent) {
470   // Basically RemoteInputMethodWin does not handle native keydown event.
471 
472   MockInputMethodDelegate delegate_;
473   MockTextInputClient mock_text_input_client;
474   scoped_ptr<InputMethod> input_method(CreateRemoteInputMethodWin(&delegate_));
475 
476   const MSG wm_keydown = { NULL, WM_KEYDOWN, ui::VKEY_A };
477   ui::KeyEvent native_keydown(wm_keydown, false);
478 
479   // This must not cause a crash.
480   EXPECT_FALSE(input_method->DispatchKeyEvent(native_keydown));
481   EXPECT_TRUE(mock_text_input_client.inserted_text().empty());
482   EXPECT_TRUE(delegate_.fabricated_key_events().empty());
483   delegate_.Reset();
484   mock_text_input_client.Reset();
485 
486   RemoteInputMethodPrivateWin* private_ptr =
487       RemoteInputMethodPrivateWin::Get(input_method.get());
488   ASSERT_TRUE(private_ptr != NULL);
489   MockRemoteInputMethodDelegateWin mock_remote_delegate;
490   private_ptr->SetRemoteDelegate(&mock_remote_delegate);
491 
492   // TextInputClient is not focused yet here.
493 
494   EXPECT_FALSE(input_method->DispatchKeyEvent(native_keydown));
495   EXPECT_TRUE(mock_text_input_client.inserted_text().empty());
496   EXPECT_TRUE(delegate_.fabricated_key_events().empty());
497   delegate_.Reset();
498   mock_text_input_client.Reset();
499 
500   input_method->SetFocusedTextInputClient(&mock_text_input_client);
501 
502   // TextInputClient is now focused here.
503 
504   EXPECT_FALSE(input_method->DispatchKeyEvent(native_keydown));
505   EXPECT_TRUE(mock_text_input_client.inserted_text().empty());
506   EXPECT_TRUE(delegate_.fabricated_key_events().empty());
507   delegate_.Reset();
508   mock_text_input_client.Reset();
509 }
510 
TEST(RemoteInputMethodWinTest,DispatchKeyEvent_NativeCharEvent)511 TEST(RemoteInputMethodWinTest, DispatchKeyEvent_NativeCharEvent) {
512   // RemoteInputMethodWin handles native char event if possible.
513 
514   MockInputMethodDelegate delegate_;
515   MockTextInputClient mock_text_input_client;
516   scoped_ptr<InputMethod> input_method(CreateRemoteInputMethodWin(&delegate_));
517 
518   const MSG wm_char = { NULL, WM_CHAR, 'A', 0 };
519   ui::KeyEvent native_char(wm_char, true);
520 
521   // This must not cause a crash.
522   EXPECT_FALSE(input_method->DispatchKeyEvent(native_char));
523   EXPECT_TRUE(mock_text_input_client.inserted_text().empty());
524   EXPECT_TRUE(delegate_.fabricated_key_events().empty());
525   delegate_.Reset();
526   mock_text_input_client.Reset();
527 
528   RemoteInputMethodPrivateWin* private_ptr =
529       RemoteInputMethodPrivateWin::Get(input_method.get());
530   ASSERT_TRUE(private_ptr != NULL);
531   MockRemoteInputMethodDelegateWin mock_remote_delegate;
532   private_ptr->SetRemoteDelegate(&mock_remote_delegate);
533 
534   // TextInputClient is not focused yet here.
535 
536   EXPECT_FALSE(input_method->DispatchKeyEvent(native_char));
537   EXPECT_TRUE(mock_text_input_client.inserted_text().empty());
538   EXPECT_TRUE(delegate_.fabricated_key_events().empty());
539   delegate_.Reset();
540   mock_text_input_client.Reset();
541 
542   input_method->SetFocusedTextInputClient(&mock_text_input_client);
543 
544   // TextInputClient is now focused here.
545 
546   EXPECT_TRUE(input_method->DispatchKeyEvent(native_char));
547   EXPECT_EQ(L"A", mock_text_input_client.inserted_text());
548   EXPECT_TRUE(delegate_.fabricated_key_events().empty());
549   delegate_.Reset();
550   mock_text_input_client.Reset();
551 }
552 
TEST(RemoteInputMethodWinTest,DispatchKeyEvent_FabricatedKeyDown)553 TEST(RemoteInputMethodWinTest, DispatchKeyEvent_FabricatedKeyDown) {
554   // Fabricated non-char event will be delegated to
555   // InputMethodDelegate::DispatchFabricatedKeyEventPostIME as long as the
556   // delegate is installed.
557 
558   MockInputMethodDelegate delegate_;
559   MockTextInputClient mock_text_input_client;
560   scoped_ptr<InputMethod> input_method(CreateRemoteInputMethodWin(&delegate_));
561 
562   ui::KeyEvent fabricated_keydown(ui::ET_KEY_PRESSED, ui::VKEY_A, 0, false);
563   fabricated_keydown.set_character(L'A');
564 
565   // This must not cause a crash.
566   EXPECT_TRUE(input_method->DispatchKeyEvent(fabricated_keydown));
567   EXPECT_TRUE(mock_text_input_client.inserted_text().empty());
568   ASSERT_EQ(1, delegate_.fabricated_key_events().size());
569   EXPECT_EQ(L'A', delegate_.fabricated_key_events()[0]);
570   delegate_.Reset();
571   mock_text_input_client.Reset();
572 
573   RemoteInputMethodPrivateWin* private_ptr =
574       RemoteInputMethodPrivateWin::Get(input_method.get());
575   ASSERT_TRUE(private_ptr != NULL);
576   MockRemoteInputMethodDelegateWin mock_remote_delegate;
577   private_ptr->SetRemoteDelegate(&mock_remote_delegate);
578 
579   // TextInputClient is not focused yet here.
580 
581   EXPECT_TRUE(input_method->DispatchKeyEvent(fabricated_keydown));
582   EXPECT_TRUE(mock_text_input_client.inserted_text().empty());
583   ASSERT_EQ(1, delegate_.fabricated_key_events().size());
584   EXPECT_EQ(L'A', delegate_.fabricated_key_events()[0]);
585   delegate_.Reset();
586   mock_text_input_client.Reset();
587 
588   input_method->SetFocusedTextInputClient(&mock_text_input_client);
589   // TextInputClient is now focused here.
590 
591   EXPECT_TRUE(input_method->DispatchKeyEvent(fabricated_keydown));
592   EXPECT_TRUE(mock_text_input_client.inserted_text().empty());
593   ASSERT_EQ(1, delegate_.fabricated_key_events().size());
594   EXPECT_EQ(L'A', delegate_.fabricated_key_events()[0]);
595   delegate_.Reset();
596   mock_text_input_client.Reset();
597 
598   input_method->SetDelegate(NULL);
599   // RemoteInputMethodDelegateWin is no longer set here.
600 
601   EXPECT_FALSE(input_method->DispatchKeyEvent(fabricated_keydown));
602   EXPECT_TRUE(mock_text_input_client.inserted_text().empty());
603 }
604 
TEST(RemoteInputMethodWinTest,DispatchKeyEvent_FabricatedChar)605 TEST(RemoteInputMethodWinTest, DispatchKeyEvent_FabricatedChar) {
606   // Note: RemoteInputMethodWin::DispatchKeyEvent should always return true
607   // for fabricated character events.
608 
609   MockInputMethodDelegate delegate_;
610   MockTextInputClient mock_text_input_client;
611   scoped_ptr<InputMethod> input_method(CreateRemoteInputMethodWin(&delegate_));
612 
613   ui::KeyEvent fabricated_char(ui::ET_KEY_PRESSED, ui::VKEY_A, 0, true);
614   fabricated_char.set_character(L'A');
615 
616   // This must not cause a crash.
617   EXPECT_TRUE(input_method->DispatchKeyEvent(fabricated_char));
618   EXPECT_TRUE(mock_text_input_client.inserted_text().empty());
619   EXPECT_TRUE(delegate_.fabricated_key_events().empty());
620   delegate_.Reset();
621   mock_text_input_client.Reset();
622 
623   RemoteInputMethodPrivateWin* private_ptr =
624       RemoteInputMethodPrivateWin::Get(input_method.get());
625   ASSERT_TRUE(private_ptr != NULL);
626   MockRemoteInputMethodDelegateWin mock_remote_delegate;
627   private_ptr->SetRemoteDelegate(&mock_remote_delegate);
628 
629   // TextInputClient is not focused yet here.
630 
631   EXPECT_TRUE(input_method->DispatchKeyEvent(fabricated_char));
632   EXPECT_TRUE(mock_text_input_client.inserted_text().empty());
633   EXPECT_TRUE(delegate_.fabricated_key_events().empty());
634   delegate_.Reset();
635   mock_text_input_client.Reset();
636 
637   input_method->SetFocusedTextInputClient(&mock_text_input_client);
638 
639   // TextInputClient is now focused here.
640 
641   EXPECT_TRUE(input_method->DispatchKeyEvent(fabricated_char));
642   EXPECT_EQ(L"A", mock_text_input_client.inserted_text());
643   EXPECT_TRUE(delegate_.fabricated_key_events().empty());
644   delegate_.Reset();
645   mock_text_input_client.Reset();
646 }
647 
TEST(RemoteInputMethodWinTest,OnCompositionChanged)648 TEST(RemoteInputMethodWinTest, OnCompositionChanged) {
649   MockInputMethodDelegate delegate_;
650   MockTextInputClient mock_text_input_client;
651   scoped_ptr<InputMethod> input_method(CreateRemoteInputMethodWin(&delegate_));
652 
653   RemoteInputMethodPrivateWin* private_ptr =
654       RemoteInputMethodPrivateWin::Get(input_method.get());
655   ASSERT_TRUE(private_ptr != NULL);
656   MockRemoteInputMethodDelegateWin mock_remote_delegate;
657   private_ptr->SetRemoteDelegate(&mock_remote_delegate);
658 
659   CompositionText composition_text;
660 
661   // TextInputClient is not focused yet here.
662 
663   private_ptr->OnCompositionChanged(composition_text);
664   EXPECT_EQ(0, mock_text_input_client.call_count_set_composition_text());
665   delegate_.Reset();
666   mock_text_input_client.Reset();
667 
668   input_method->SetFocusedTextInputClient(&mock_text_input_client);
669 
670   // TextInputClient is now focused here.
671 
672   private_ptr->OnCompositionChanged(composition_text);
673   EXPECT_EQ(1, mock_text_input_client.call_count_set_composition_text());
674   delegate_.Reset();
675   mock_text_input_client.Reset();
676 }
677 
TEST(RemoteInputMethodWinTest,OnTextCommitted)678 TEST(RemoteInputMethodWinTest, OnTextCommitted) {
679   MockInputMethodDelegate delegate_;
680   MockTextInputClient mock_text_input_client;
681   scoped_ptr<InputMethod> input_method(CreateRemoteInputMethodWin(&delegate_));
682 
683   RemoteInputMethodPrivateWin* private_ptr =
684       RemoteInputMethodPrivateWin::Get(input_method.get());
685   ASSERT_TRUE(private_ptr != NULL);
686   MockRemoteInputMethodDelegateWin mock_remote_delegate;
687   private_ptr->SetRemoteDelegate(&mock_remote_delegate);
688 
689   base::string16 committed_text = L"Hello";
690 
691   // TextInputClient is not focused yet here.
692 
693   mock_text_input_client.set_text_input_type(TEXT_INPUT_TYPE_TEXT);
694   private_ptr->OnTextCommitted(committed_text);
695   EXPECT_EQ(0, mock_text_input_client.call_count_insert_char());
696   EXPECT_EQ(0, mock_text_input_client.call_count_insert_text());
697   EXPECT_EQ(L"", mock_text_input_client.inserted_text());
698   delegate_.Reset();
699   mock_text_input_client.Reset();
700 
701   input_method->SetFocusedTextInputClient(&mock_text_input_client);
702 
703   // TextInputClient is now focused here.
704 
705   mock_text_input_client.set_text_input_type(TEXT_INPUT_TYPE_TEXT);
706   private_ptr->OnTextCommitted(committed_text);
707   EXPECT_EQ(0, mock_text_input_client.call_count_insert_char());
708   EXPECT_EQ(1, mock_text_input_client.call_count_insert_text());
709   EXPECT_EQ(committed_text, mock_text_input_client.inserted_text());
710   delegate_.Reset();
711   mock_text_input_client.Reset();
712 
713   // When TextInputType is TEXT_INPUT_TYPE_NONE, TextInputClient::InsertText
714   // should not be used.
715   mock_text_input_client.set_text_input_type(TEXT_INPUT_TYPE_NONE);
716   private_ptr->OnTextCommitted(committed_text);
717   EXPECT_EQ(committed_text.size(),
718             mock_text_input_client.call_count_insert_char());
719   EXPECT_EQ(0, mock_text_input_client.call_count_insert_text());
720   EXPECT_EQ(committed_text, mock_text_input_client.inserted_text());
721   delegate_.Reset();
722   mock_text_input_client.Reset();
723 }
724 
TEST(RemoteInputMethodWinTest,OnTextInputStateChanged_Observer)725 TEST(RemoteInputMethodWinTest, OnTextInputStateChanged_Observer) {
726   DummyTextInputClient text_input_client;
727   DummyTextInputClient text_input_client_the_other;
728 
729   MockInputMethodObserver input_method_observer;
730   MockInputMethodDelegate delegate_;
731   scoped_ptr<InputMethod> input_method(CreateRemoteInputMethodWin(&delegate_));
732   InputMethodScopedObserver scoped_observer(&input_method_observer);
733   scoped_observer.Add(input_method.get());
734 
735   input_method->SetFocusedTextInputClient(&text_input_client);
736   ASSERT_EQ(&text_input_client, input_method->GetTextInputClient());
737   EXPECT_EQ(1u, input_method_observer.on_text_input_state_changed());
738   input_method_observer.Reset();
739 
740   input_method->SetFocusedTextInputClient(&text_input_client);
741   ASSERT_EQ(&text_input_client, input_method->GetTextInputClient());
742   EXPECT_EQ(0u, input_method_observer.on_text_input_state_changed());
743   input_method_observer.Reset();
744 
745   input_method->SetFocusedTextInputClient(&text_input_client_the_other);
746   ASSERT_EQ(&text_input_client_the_other, input_method->GetTextInputClient());
747   EXPECT_EQ(1u, input_method_observer.on_text_input_state_changed());
748   input_method_observer.Reset();
749 
750   input_method->DetachTextInputClient(&text_input_client_the_other);
751   ASSERT_TRUE(input_method->GetTextInputClient() == NULL);
752   EXPECT_EQ(1u, input_method_observer.on_text_input_state_changed());
753   input_method_observer.Reset();
754 }
755 
TEST(RemoteInputMethodWinTest,OnInputMethodDestroyed_Observer)756 TEST(RemoteInputMethodWinTest, OnInputMethodDestroyed_Observer) {
757   DummyTextInputClient text_input_client;
758   DummyTextInputClient text_input_client_the_other;
759 
760   MockInputMethodObserver input_method_observer;
761   InputMethodScopedObserver scoped_observer(&input_method_observer);
762 
763   MockInputMethodDelegate delegate_;
764   scoped_ptr<InputMethod> input_method(CreateRemoteInputMethodWin(&delegate_));
765   input_method->AddObserver(&input_method_observer);
766 
767   EXPECT_EQ(0u, input_method_observer.on_input_method_destroyed_changed());
768   input_method.reset();
769   EXPECT_EQ(1u, input_method_observer.on_input_method_destroyed_changed());
770 }
771 
772 }  // namespace
773 }  // namespace ui
774