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/input_method_base.h"
6
7#include "base/gtest_prod_util.h"
8#include "base/memory/scoped_ptr.h"
9#include "base/message_loop/message_loop.h"
10#include "base/run_loop.h"
11#include "base/scoped_observer.h"
12#include "testing/gtest/include/gtest/gtest.h"
13#include "ui/base/ime/dummy_text_input_client.h"
14#include "ui/base/ime/input_method_observer.h"
15#include "ui/base/ime/text_input_focus_manager.h"
16#include "ui/base/ui_base_switches_util.h"
17#include "ui/events/event.h"
18
19namespace ui {
20namespace {
21
22class ClientChangeVerifier {
23 public:
24  ClientChangeVerifier()
25     : previous_client_(NULL),
26       next_client_(NULL),
27       call_expected_(false),
28       on_will_change_focused_client_called_(false),
29       on_did_change_focused_client_called_(false),
30       on_text_input_state_changed_(false) {
31  }
32
33  // Expects that focused text input client will not be changed.
34  void ExpectClientDoesNotChange() {
35    previous_client_ = NULL;
36    next_client_ = NULL;
37    call_expected_ = false;
38    on_will_change_focused_client_called_ = false;
39    on_did_change_focused_client_called_ = false;
40    on_text_input_state_changed_ = false;
41  }
42
43  // Expects that focused text input client will be changed from
44  // |previous_client| to |next_client|.
45  void ExpectClientChange(TextInputClient* previous_client,
46                          TextInputClient* next_client) {
47    previous_client_ = previous_client;
48    next_client_ = next_client;
49    call_expected_ = true;
50    on_will_change_focused_client_called_ = false;
51    on_did_change_focused_client_called_ = false;
52    on_text_input_state_changed_ = false;
53  }
54
55  // Verifies the result satisfies the expectation or not.
56  void Verify() {
57    if (switches::IsTextInputFocusManagerEnabled()) {
58      EXPECT_FALSE(on_will_change_focused_client_called_);
59      EXPECT_FALSE(on_did_change_focused_client_called_);
60      EXPECT_FALSE(on_text_input_state_changed_);
61    } else {
62      EXPECT_EQ(call_expected_, on_will_change_focused_client_called_);
63      EXPECT_EQ(call_expected_, on_did_change_focused_client_called_);
64      EXPECT_EQ(call_expected_, on_text_input_state_changed_);
65    }
66  }
67
68  void OnWillChangeFocusedClient(TextInputClient* focused_before,
69                                 TextInputClient* focused) {
70    EXPECT_TRUE(call_expected_);
71
72    // Check arguments
73    EXPECT_EQ(previous_client_, focused_before);
74    EXPECT_EQ(next_client_, focused);
75
76    // Check call order
77    EXPECT_FALSE(on_will_change_focused_client_called_);
78    EXPECT_FALSE(on_did_change_focused_client_called_);
79    EXPECT_FALSE(on_text_input_state_changed_);
80
81    on_will_change_focused_client_called_ = true;
82  }
83
84  void OnDidChangeFocusedClient(TextInputClient* focused_before,
85                                TextInputClient* focused) {
86    EXPECT_TRUE(call_expected_);
87
88    // Check arguments
89    EXPECT_EQ(previous_client_, focused_before);
90    EXPECT_EQ(next_client_, focused);
91
92    // Check call order
93    EXPECT_TRUE(on_will_change_focused_client_called_);
94    EXPECT_FALSE(on_did_change_focused_client_called_);
95    EXPECT_FALSE(on_text_input_state_changed_);
96
97    on_did_change_focused_client_called_ = true;
98 }
99
100  void OnTextInputStateChanged(const TextInputClient* client) {
101    EXPECT_TRUE(call_expected_);
102
103    // Check arguments
104    EXPECT_EQ(next_client_, client);
105
106    // Check call order
107    EXPECT_TRUE(on_will_change_focused_client_called_);
108    EXPECT_TRUE(on_did_change_focused_client_called_);
109    EXPECT_FALSE(on_text_input_state_changed_);
110
111    on_text_input_state_changed_ = true;
112 }
113
114 private:
115  TextInputClient* previous_client_;
116  TextInputClient* next_client_;
117  bool call_expected_;
118  bool on_will_change_focused_client_called_;
119  bool on_did_change_focused_client_called_;
120  bool on_text_input_state_changed_;
121
122  DISALLOW_COPY_AND_ASSIGN(ClientChangeVerifier);
123};
124
125class InputMethodBaseTest : public testing::Test {
126 protected:
127  InputMethodBaseTest() {
128  }
129  virtual ~InputMethodBaseTest() {
130  }
131
132  virtual void SetUp() {
133    message_loop_.reset(new base::MessageLoopForUI);
134  }
135
136  virtual void TearDown() {
137    message_loop_.reset();
138  }
139
140 private:
141  scoped_ptr<base::MessageLoop> message_loop_;
142  DISALLOW_COPY_AND_ASSIGN(InputMethodBaseTest);
143};
144
145class MockInputMethodBase : public InputMethodBase {
146 public:
147  // Note: this class does not take the ownership of |verifier|.
148  MockInputMethodBase(ClientChangeVerifier* verifier) : verifier_(verifier) {
149  }
150  virtual ~MockInputMethodBase() {
151  }
152
153 private:
154  // Overriden from InputMethod.
155  virtual bool OnUntranslatedIMEMessage(
156      const base::NativeEvent& event,
157      InputMethod::NativeEventResult* result) OVERRIDE {
158    return false;
159  }
160  virtual bool DispatchKeyEvent(const ui::KeyEvent&) OVERRIDE {
161    return false;
162  }
163  virtual void OnCaretBoundsChanged(const TextInputClient* client) OVERRIDE {
164  }
165  virtual void CancelComposition(const TextInputClient* client) OVERRIDE {
166  }
167  virtual void OnInputLocaleChanged() OVERRIDE {
168  }
169  virtual std::string GetInputLocale() OVERRIDE{
170    return "";
171  }
172  virtual bool IsActive() OVERRIDE {
173    return false;
174  }
175  virtual bool IsCandidatePopupOpen() const OVERRIDE {
176    return false;
177  }
178  // Overriden from InputMethodBase.
179  virtual void OnWillChangeFocusedClient(TextInputClient* focused_before,
180                                         TextInputClient* focused) OVERRIDE {
181    verifier_->OnWillChangeFocusedClient(focused_before, focused);
182  }
183
184  virtual void OnDidChangeFocusedClient(TextInputClient* focused_before,
185                                        TextInputClient* focused) OVERRIDE {
186    verifier_->OnDidChangeFocusedClient(focused_before, focused);
187  }
188
189  ClientChangeVerifier* verifier_;
190
191  FRIEND_TEST_ALL_PREFIXES(InputMethodBaseTest, CandidateWindowEvents);
192  DISALLOW_COPY_AND_ASSIGN(MockInputMethodBase);
193};
194
195class MockInputMethodObserver : public InputMethodObserver {
196 public:
197  // Note: this class does not take the ownership of |verifier|.
198  explicit MockInputMethodObserver(ClientChangeVerifier* verifier)
199      : verifier_(verifier) {
200  }
201  virtual ~MockInputMethodObserver() {
202  }
203
204 private:
205  virtual void OnTextInputTypeChanged(const TextInputClient* client) OVERRIDE {
206  }
207  virtual void OnFocus() OVERRIDE {
208  }
209  virtual void OnBlur() OVERRIDE {
210  }
211  virtual void OnCaretBoundsChanged(const TextInputClient* client) OVERRIDE {
212  }
213  virtual void OnTextInputStateChanged(const TextInputClient* client) OVERRIDE {
214    verifier_->OnTextInputStateChanged(client);
215  }
216  virtual void OnShowImeIfNeeded() OVERRIDE {
217  }
218  virtual void OnInputMethodDestroyed(const InputMethod* client) OVERRIDE {
219  }
220
221  ClientChangeVerifier* verifier_;
222  DISALLOW_COPY_AND_ASSIGN(MockInputMethodObserver);
223};
224
225class MockTextInputClient : public DummyTextInputClient {
226 public:
227  MockTextInputClient()
228      : shown_event_count_(0), updated_event_count_(0), hidden_event_count_(0) {
229  }
230  virtual ~MockTextInputClient() {
231  }
232
233  virtual void OnCandidateWindowShown() OVERRIDE {
234    ++shown_event_count_;
235  }
236  virtual void OnCandidateWindowUpdated() OVERRIDE {
237    ++updated_event_count_;
238  }
239  virtual void OnCandidateWindowHidden() OVERRIDE {
240    ++hidden_event_count_;
241  }
242
243  int shown_event_count() const { return shown_event_count_; }
244  int updated_event_count() const { return updated_event_count_; }
245  int hidden_event_count() const { return hidden_event_count_; }
246
247 private:
248  int shown_event_count_;
249  int updated_event_count_;
250  int hidden_event_count_;
251};
252
253typedef ScopedObserver<InputMethod, InputMethodObserver>
254    InputMethodScopedObserver;
255
256void SetFocusedTextInputClient(InputMethod* input_method,
257                               TextInputClient* text_input_client) {
258  if (switches::IsTextInputFocusManagerEnabled()) {
259    TextInputFocusManager::GetInstance()->FocusTextInputClient(
260        text_input_client);
261  } else {
262    input_method->SetFocusedTextInputClient(text_input_client);
263  }
264}
265
266TEST_F(InputMethodBaseTest, SetFocusedTextInputClient) {
267  DummyTextInputClient text_input_client_1st;
268  DummyTextInputClient text_input_client_2nd;
269
270  ClientChangeVerifier verifier;
271  MockInputMethodBase input_method(&verifier);
272  MockInputMethodObserver input_method_observer(&verifier);
273  InputMethodScopedObserver scoped_observer(&input_method_observer);
274  scoped_observer.Add(&input_method);
275
276  // Assume that the top-level-widget gains focus.
277  input_method.OnFocus();
278
279  {
280    SCOPED_TRACE("Focus from NULL to 1st TextInputClient");
281
282    ASSERT_EQ(NULL, input_method.GetTextInputClient());
283    verifier.ExpectClientChange(NULL, &text_input_client_1st);
284    SetFocusedTextInputClient(&input_method, &text_input_client_1st);
285    EXPECT_EQ(&text_input_client_1st, input_method.GetTextInputClient());
286    verifier.Verify();
287  }
288
289  {
290    SCOPED_TRACE("Redundant focus events must be ignored");
291    verifier.ExpectClientDoesNotChange();
292    SetFocusedTextInputClient(&input_method, &text_input_client_1st);
293    verifier.Verify();
294  }
295
296  {
297    SCOPED_TRACE("Focus from 1st to 2nd TextInputClient");
298
299    ASSERT_EQ(&text_input_client_1st, input_method.GetTextInputClient());
300    verifier.ExpectClientChange(&text_input_client_1st,
301                                &text_input_client_2nd);
302    SetFocusedTextInputClient(&input_method, &text_input_client_2nd);
303    EXPECT_EQ(&text_input_client_2nd, input_method.GetTextInputClient());
304    verifier.Verify();
305  }
306
307  {
308    SCOPED_TRACE("Focus from 2nd TextInputClient to NULL");
309
310    ASSERT_EQ(&text_input_client_2nd, input_method.GetTextInputClient());
311    verifier.ExpectClientChange(&text_input_client_2nd, NULL);
312    SetFocusedTextInputClient(&input_method, NULL);
313    EXPECT_EQ(NULL, input_method.GetTextInputClient());
314    verifier.Verify();
315  }
316
317  {
318    SCOPED_TRACE("Redundant focus events must be ignored");
319    verifier.ExpectClientDoesNotChange();
320    SetFocusedTextInputClient(&input_method, NULL);
321    verifier.Verify();
322  }
323}
324
325TEST_F(InputMethodBaseTest, DetachTextInputClient) {
326  // DetachTextInputClient is not supported when IsTextInputFocusManagerEnabled.
327  if (switches::IsTextInputFocusManagerEnabled())
328    return;
329
330  DummyTextInputClient text_input_client;
331  DummyTextInputClient text_input_client_the_other;
332
333  ClientChangeVerifier verifier;
334  MockInputMethodBase input_method(&verifier);
335  MockInputMethodObserver input_method_observer(&verifier);
336  InputMethodScopedObserver scoped_observer(&input_method_observer);
337  scoped_observer.Add(&input_method);
338
339  // Assume that the top-level-widget gains focus.
340  input_method.OnFocus();
341
342  // Initialize for the next test.
343  {
344    verifier.ExpectClientChange(NULL, &text_input_client);
345    input_method.SetFocusedTextInputClient(&text_input_client);
346    verifier.Verify();
347  }
348
349  {
350    SCOPED_TRACE("DetachTextInputClient must be ignored for other clients");
351    ASSERT_EQ(&text_input_client, input_method.GetTextInputClient());
352    verifier.ExpectClientDoesNotChange();
353    input_method.DetachTextInputClient(&text_input_client_the_other);
354    EXPECT_EQ(&text_input_client, input_method.GetTextInputClient());
355    verifier.Verify();
356  }
357
358  {
359    SCOPED_TRACE("DetachTextInputClient must succeed even after the "
360                 "top-level loses the focus");
361
362    ASSERT_EQ(&text_input_client, input_method.GetTextInputClient());
363    input_method.OnBlur();
364    input_method.OnFocus();
365    verifier.ExpectClientChange(&text_input_client, NULL);
366    input_method.DetachTextInputClient(&text_input_client);
367    EXPECT_EQ(NULL, input_method.GetTextInputClient());
368    verifier.Verify();
369  }
370}
371
372TEST_F(InputMethodBaseTest, CandidateWindowEvents) {
373  MockTextInputClient text_input_client;
374
375  {
376    ClientChangeVerifier verifier;
377    MockInputMethodBase input_method_base(&verifier);
378    input_method_base.OnFocus();
379
380    verifier.ExpectClientChange(NULL, &text_input_client);
381    SetFocusedTextInputClient(&input_method_base, &text_input_client);
382
383    EXPECT_EQ(0, text_input_client.shown_event_count());
384    EXPECT_EQ(0, text_input_client.updated_event_count());
385    EXPECT_EQ(0, text_input_client.hidden_event_count());
386
387    input_method_base.OnCandidateWindowShown();
388    base::RunLoop().RunUntilIdle();
389
390    EXPECT_EQ(1, text_input_client.shown_event_count());
391    EXPECT_EQ(0, text_input_client.updated_event_count());
392    EXPECT_EQ(0, text_input_client.hidden_event_count());
393
394    input_method_base.OnCandidateWindowUpdated();
395    base::RunLoop().RunUntilIdle();
396
397    EXPECT_EQ(1, text_input_client.shown_event_count());
398    EXPECT_EQ(1, text_input_client.updated_event_count());
399    EXPECT_EQ(0, text_input_client.hidden_event_count());
400
401    input_method_base.OnCandidateWindowHidden();
402    base::RunLoop().RunUntilIdle();
403
404    EXPECT_EQ(1, text_input_client.shown_event_count());
405    EXPECT_EQ(1, text_input_client.updated_event_count());
406    EXPECT_EQ(1, text_input_client.hidden_event_count());
407
408    input_method_base.OnCandidateWindowShown();
409  }
410
411  // If InputMethod is deleted immediately after an event happens, but before
412  // its callback is invoked, the callback will be cancelled.
413  base::RunLoop().RunUntilIdle();
414  EXPECT_EQ(1, text_input_client.shown_event_count());
415  EXPECT_EQ(1, text_input_client.updated_event_count());
416  EXPECT_EQ(1, text_input_client.hidden_event_count());
417}
418
419}  // namespace
420}  // namespace ui
421