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