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.
5 #include "ui/base/ime/input_method_base.h"
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/events/event.h"
20 class ClientChangeVerifier
{
22 ClientChangeVerifier()
23 : previous_client_(NULL
),
25 call_expected_(false),
26 on_will_change_focused_client_called_(false),
27 on_did_change_focused_client_called_(false),
28 on_text_input_state_changed_(false) {
31 // Expects that focused text input client will not be changed.
32 void ExpectClientDoesNotChange() {
33 previous_client_
= NULL
;
35 call_expected_
= false;
36 on_will_change_focused_client_called_
= false;
37 on_did_change_focused_client_called_
= false;
38 on_text_input_state_changed_
= false;
41 // Expects that focused text input client will be changed from
42 // |previous_client| to |next_client|.
43 void ExpectClientChange(TextInputClient
* previous_client
,
44 TextInputClient
* next_client
) {
45 previous_client_
= previous_client
;
46 next_client_
= next_client
;
47 call_expected_
= true;
48 on_will_change_focused_client_called_
= false;
49 on_did_change_focused_client_called_
= false;
50 on_text_input_state_changed_
= false;
53 // Verifies the result satisfies the expectation or not.
55 EXPECT_EQ(call_expected_
, on_will_change_focused_client_called_
);
56 EXPECT_EQ(call_expected_
, on_did_change_focused_client_called_
);
57 EXPECT_EQ(call_expected_
, on_text_input_state_changed_
);
60 void OnWillChangeFocusedClient(TextInputClient
* focused_before
,
61 TextInputClient
* focused
) {
62 EXPECT_TRUE(call_expected_
);
65 EXPECT_EQ(previous_client_
, focused_before
);
66 EXPECT_EQ(next_client_
, focused
);
69 EXPECT_FALSE(on_will_change_focused_client_called_
);
70 EXPECT_FALSE(on_did_change_focused_client_called_
);
71 EXPECT_FALSE(on_text_input_state_changed_
);
73 on_will_change_focused_client_called_
= true;
76 void OnDidChangeFocusedClient(TextInputClient
* focused_before
,
77 TextInputClient
* focused
) {
78 EXPECT_TRUE(call_expected_
);
81 EXPECT_EQ(previous_client_
, focused_before
);
82 EXPECT_EQ(next_client_
, focused
);
85 EXPECT_TRUE(on_will_change_focused_client_called_
);
86 EXPECT_FALSE(on_did_change_focused_client_called_
);
87 EXPECT_FALSE(on_text_input_state_changed_
);
89 on_did_change_focused_client_called_
= true;
92 void OnTextInputStateChanged(const TextInputClient
* client
) {
93 EXPECT_TRUE(call_expected_
);
96 EXPECT_EQ(next_client_
, client
);
99 EXPECT_TRUE(on_will_change_focused_client_called_
);
100 EXPECT_TRUE(on_did_change_focused_client_called_
);
101 EXPECT_FALSE(on_text_input_state_changed_
);
103 on_text_input_state_changed_
= true;
107 TextInputClient
* previous_client_
;
108 TextInputClient
* next_client_
;
110 bool on_will_change_focused_client_called_
;
111 bool on_did_change_focused_client_called_
;
112 bool on_text_input_state_changed_
;
114 DISALLOW_COPY_AND_ASSIGN(ClientChangeVerifier
);
117 class InputMethodBaseTest
: public testing::Test
{
119 InputMethodBaseTest() {
121 virtual ~InputMethodBaseTest() {
124 virtual void SetUp() {
125 message_loop_
.reset(new base::MessageLoopForUI
);
128 virtual void TearDown() {
129 message_loop_
.reset();
133 scoped_ptr
<base::MessageLoop
> message_loop_
;
134 DISALLOW_COPY_AND_ASSIGN(InputMethodBaseTest
);
137 class MockInputMethodBase
: public InputMethodBase
{
139 // Note: this class does not take the ownership of |verifier|.
140 MockInputMethodBase(ClientChangeVerifier
* verifier
) : verifier_(verifier
) {
142 virtual ~MockInputMethodBase() {
146 // Overriden from InputMethod.
147 virtual bool OnUntranslatedIMEMessage(
148 const base::NativeEvent
& event
,
149 InputMethod::NativeEventResult
* result
) OVERRIDE
{
152 virtual bool DispatchKeyEvent(const ui::KeyEvent
&) OVERRIDE
{
155 virtual void OnCaretBoundsChanged(const TextInputClient
* client
) OVERRIDE
{
157 virtual void CancelComposition(const TextInputClient
* client
) OVERRIDE
{
159 virtual void OnInputLocaleChanged() OVERRIDE
{
161 virtual std::string
GetInputLocale() OVERRIDE
{
164 virtual bool IsActive() OVERRIDE
{
167 virtual bool IsCandidatePopupOpen() const OVERRIDE
{
170 // Overriden from InputMethodBase.
171 virtual void OnWillChangeFocusedClient(TextInputClient
* focused_before
,
172 TextInputClient
* focused
) OVERRIDE
{
173 verifier_
->OnWillChangeFocusedClient(focused_before
, focused
);
176 virtual void OnDidChangeFocusedClient(TextInputClient
* focused_before
,
177 TextInputClient
* focused
) OVERRIDE
{
178 verifier_
->OnDidChangeFocusedClient(focused_before
, focused
);
181 ClientChangeVerifier
* verifier_
;
183 FRIEND_TEST_ALL_PREFIXES(InputMethodBaseTest
, CandidateWindowEvents
);
184 DISALLOW_COPY_AND_ASSIGN(MockInputMethodBase
);
187 class MockInputMethodObserver
: public InputMethodObserver
{
189 // Note: this class does not take the ownership of |verifier|.
190 explicit MockInputMethodObserver(ClientChangeVerifier
* verifier
)
191 : verifier_(verifier
) {
193 virtual ~MockInputMethodObserver() {
197 virtual void OnTextInputTypeChanged(const TextInputClient
* client
) OVERRIDE
{
199 virtual void OnFocus() OVERRIDE
{
201 virtual void OnBlur() OVERRIDE
{
203 virtual void OnCaretBoundsChanged(const TextInputClient
* client
) OVERRIDE
{
205 virtual void OnTextInputStateChanged(const TextInputClient
* client
) OVERRIDE
{
206 verifier_
->OnTextInputStateChanged(client
);
208 virtual void OnShowImeIfNeeded() OVERRIDE
{
210 virtual void OnInputMethodDestroyed(const InputMethod
* client
) OVERRIDE
{
213 ClientChangeVerifier
* verifier_
;
214 DISALLOW_COPY_AND_ASSIGN(MockInputMethodObserver
);
217 class MockTextInputClient
: public DummyTextInputClient
{
219 MockTextInputClient()
220 : shown_event_count_(0), updated_event_count_(0), hidden_event_count_(0) {
222 virtual ~MockTextInputClient() {
225 virtual void OnCandidateWindowShown() OVERRIDE
{
226 ++shown_event_count_
;
228 virtual void OnCandidateWindowUpdated() OVERRIDE
{
229 ++updated_event_count_
;
231 virtual void OnCandidateWindowHidden() OVERRIDE
{
232 ++hidden_event_count_
;
235 int shown_event_count() const { return shown_event_count_
; }
236 int updated_event_count() const { return updated_event_count_
; }
237 int hidden_event_count() const { return hidden_event_count_
; }
240 int shown_event_count_
;
241 int updated_event_count_
;
242 int hidden_event_count_
;
245 typedef ScopedObserver
<InputMethod
, InputMethodObserver
>
246 InputMethodScopedObserver
;
248 TEST_F(InputMethodBaseTest
, SetFocusedTextInputClient
) {
249 DummyTextInputClient text_input_client_1st
;
250 DummyTextInputClient text_input_client_2nd
;
252 ClientChangeVerifier verifier
;
253 MockInputMethodBase
input_method(&verifier
);
254 MockInputMethodObserver
input_method_observer(&verifier
);
255 InputMethodScopedObserver
scoped_observer(&input_method_observer
);
256 scoped_observer
.Add(&input_method
);
258 // Assume that the top-level-widget gains focus.
259 input_method
.OnFocus();
262 SCOPED_TRACE("Focus from NULL to 1st TextInputClient");
264 ASSERT_EQ(NULL
, input_method
.GetTextInputClient());
265 verifier
.ExpectClientChange(NULL
, &text_input_client_1st
);
266 input_method
.SetFocusedTextInputClient(&text_input_client_1st
);
267 EXPECT_EQ(&text_input_client_1st
, input_method
.GetTextInputClient());
272 SCOPED_TRACE("Redundant focus events must be ignored");
273 verifier
.ExpectClientDoesNotChange();
274 input_method
.SetFocusedTextInputClient(&text_input_client_1st
);
279 SCOPED_TRACE("Focus from 1st to 2nd TextInputClient");
281 ASSERT_EQ(&text_input_client_1st
, input_method
.GetTextInputClient());
282 verifier
.ExpectClientChange(&text_input_client_1st
,
283 &text_input_client_2nd
);
284 input_method
.SetFocusedTextInputClient(&text_input_client_2nd
);
285 EXPECT_EQ(&text_input_client_2nd
, input_method
.GetTextInputClient());
290 SCOPED_TRACE("Focus from 2nd TextInputClient to NULL");
292 ASSERT_EQ(&text_input_client_2nd
, input_method
.GetTextInputClient());
293 verifier
.ExpectClientChange(&text_input_client_2nd
, NULL
);
294 input_method
.SetFocusedTextInputClient(NULL
);
295 EXPECT_EQ(NULL
, input_method
.GetTextInputClient());
300 SCOPED_TRACE("Redundant focus events must be ignored");
301 verifier
.ExpectClientDoesNotChange();
302 input_method
.SetFocusedTextInputClient(NULL
);
307 TEST_F(InputMethodBaseTest
, DetachTextInputClient
) {
308 DummyTextInputClient text_input_client
;
309 DummyTextInputClient text_input_client_the_other
;
311 ClientChangeVerifier verifier
;
312 MockInputMethodBase
input_method(&verifier
);
313 MockInputMethodObserver
input_method_observer(&verifier
);
314 InputMethodScopedObserver
scoped_observer(&input_method_observer
);
315 scoped_observer
.Add(&input_method
);
317 // Assume that the top-level-widget gains focus.
318 input_method
.OnFocus();
320 // Initialize for the next test.
322 verifier
.ExpectClientChange(NULL
, &text_input_client
);
323 input_method
.SetFocusedTextInputClient(&text_input_client
);
328 SCOPED_TRACE("DetachTextInputClient must be ignored for other clients");
329 ASSERT_EQ(&text_input_client
, input_method
.GetTextInputClient());
330 verifier
.ExpectClientDoesNotChange();
331 input_method
.DetachTextInputClient(&text_input_client_the_other
);
332 EXPECT_EQ(&text_input_client
, input_method
.GetTextInputClient());
337 SCOPED_TRACE("DetachTextInputClient must succeed even after the "
338 "top-level loses the focus");
340 ASSERT_EQ(&text_input_client
, input_method
.GetTextInputClient());
341 input_method
.OnBlur();
342 input_method
.OnFocus();
343 verifier
.ExpectClientChange(&text_input_client
, NULL
);
344 input_method
.DetachTextInputClient(&text_input_client
);
345 EXPECT_EQ(NULL
, input_method
.GetTextInputClient());
350 TEST_F(InputMethodBaseTest
, CandidateWindowEvents
) {
351 MockTextInputClient text_input_client
;
354 ClientChangeVerifier verifier
;
355 MockInputMethodBase
input_method_base(&verifier
);
356 input_method_base
.OnFocus();
358 verifier
.ExpectClientChange(NULL
, &text_input_client
);
359 input_method_base
.SetFocusedTextInputClient(&text_input_client
);
361 EXPECT_EQ(0, text_input_client
.shown_event_count());
362 EXPECT_EQ(0, text_input_client
.updated_event_count());
363 EXPECT_EQ(0, text_input_client
.hidden_event_count());
365 input_method_base
.OnCandidateWindowShown();
366 base::RunLoop().RunUntilIdle();
368 EXPECT_EQ(1, text_input_client
.shown_event_count());
369 EXPECT_EQ(0, text_input_client
.updated_event_count());
370 EXPECT_EQ(0, text_input_client
.hidden_event_count());
372 input_method_base
.OnCandidateWindowUpdated();
373 base::RunLoop().RunUntilIdle();
375 EXPECT_EQ(1, text_input_client
.shown_event_count());
376 EXPECT_EQ(1, text_input_client
.updated_event_count());
377 EXPECT_EQ(0, text_input_client
.hidden_event_count());
379 input_method_base
.OnCandidateWindowHidden();
380 base::RunLoop().RunUntilIdle();
382 EXPECT_EQ(1, text_input_client
.shown_event_count());
383 EXPECT_EQ(1, text_input_client
.updated_event_count());
384 EXPECT_EQ(1, text_input_client
.hidden_event_count());
386 input_method_base
.OnCandidateWindowShown();
389 // If InputMethod is deleted immediately after an event happens, but before
390 // its callback is invoked, the callback will be cancelled.
391 base::RunLoop().RunUntilIdle();
392 EXPECT_EQ(1, text_input_client
.shown_event_count());
393 EXPECT_EQ(1, text_input_client
.updated_event_count());
394 EXPECT_EQ(1, text_input_client
.hidden_event_count());