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/base/ime/text_input_focus_manager.h"
16 #include "ui/base/ui_base_switches_util.h"
17 #include "ui/events/event.h"
22 class ClientChangeVerifier
{
24 ClientChangeVerifier()
25 : previous_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) {
33 // Expects that focused text input client will not be changed.
34 void ExpectClientDoesNotChange() {
35 previous_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;
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;
55 // Verifies the result satisfies the expectation or not.
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_
);
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_
);
68 void OnWillChangeFocusedClient(TextInputClient
* focused_before
,
69 TextInputClient
* focused
) {
70 EXPECT_TRUE(call_expected_
);
73 EXPECT_EQ(previous_client_
, focused_before
);
74 EXPECT_EQ(next_client_
, focused
);
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_
);
81 on_will_change_focused_client_called_
= true;
84 void OnDidChangeFocusedClient(TextInputClient
* focused_before
,
85 TextInputClient
* focused
) {
86 EXPECT_TRUE(call_expected_
);
89 EXPECT_EQ(previous_client_
, focused_before
);
90 EXPECT_EQ(next_client_
, focused
);
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_
);
97 on_did_change_focused_client_called_
= true;
100 void OnTextInputStateChanged(const TextInputClient
* client
) {
101 EXPECT_TRUE(call_expected_
);
104 EXPECT_EQ(next_client_
, client
);
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_
);
111 on_text_input_state_changed_
= true;
115 TextInputClient
* previous_client_
;
116 TextInputClient
* next_client_
;
118 bool on_will_change_focused_client_called_
;
119 bool on_did_change_focused_client_called_
;
120 bool on_text_input_state_changed_
;
122 DISALLOW_COPY_AND_ASSIGN(ClientChangeVerifier
);
125 class InputMethodBaseTest
: public testing::Test
{
127 InputMethodBaseTest() {
129 ~InputMethodBaseTest() override
{}
131 void SetUp() override
{ message_loop_
.reset(new base::MessageLoopForUI
); }
133 void TearDown() override
{ message_loop_
.reset(); }
136 scoped_ptr
<base::MessageLoop
> message_loop_
;
137 DISALLOW_COPY_AND_ASSIGN(InputMethodBaseTest
);
140 class MockInputMethodBase
: public InputMethodBase
{
142 // Note: this class does not take the ownership of |verifier|.
143 MockInputMethodBase(ClientChangeVerifier
* verifier
) : verifier_(verifier
) {
145 ~MockInputMethodBase() override
{}
148 // Overriden from InputMethod.
149 bool OnUntranslatedIMEMessage(
150 const base::NativeEvent
& event
,
151 InputMethod::NativeEventResult
* result
) override
{
154 bool DispatchKeyEvent(const ui::KeyEvent
&) override
{ return false; }
155 void OnCaretBoundsChanged(const TextInputClient
* client
) override
{}
156 void CancelComposition(const TextInputClient
* client
) override
{}
157 void OnInputLocaleChanged() override
{}
158 std::string
GetInputLocale() override
{ return ""; }
159 bool IsActive() override
{ return false; }
160 bool IsCandidatePopupOpen() const override
{ return false; }
161 // Overriden from InputMethodBase.
162 void OnWillChangeFocusedClient(TextInputClient
* focused_before
,
163 TextInputClient
* focused
) override
{
164 verifier_
->OnWillChangeFocusedClient(focused_before
, focused
);
167 void OnDidChangeFocusedClient(TextInputClient
* focused_before
,
168 TextInputClient
* focused
) override
{
169 verifier_
->OnDidChangeFocusedClient(focused_before
, focused
);
172 ClientChangeVerifier
* verifier_
;
174 FRIEND_TEST_ALL_PREFIXES(InputMethodBaseTest
, CandidateWindowEvents
);
175 DISALLOW_COPY_AND_ASSIGN(MockInputMethodBase
);
178 class MockInputMethodObserver
: public InputMethodObserver
{
180 // Note: this class does not take the ownership of |verifier|.
181 explicit MockInputMethodObserver(ClientChangeVerifier
* verifier
)
182 : verifier_(verifier
) {
184 ~MockInputMethodObserver() override
{}
187 void OnTextInputTypeChanged(const TextInputClient
* client
) override
{}
188 void OnFocus() override
{}
189 void OnBlur() override
{}
190 void OnCaretBoundsChanged(const TextInputClient
* client
) override
{}
191 void OnTextInputStateChanged(const TextInputClient
* client
) override
{
192 verifier_
->OnTextInputStateChanged(client
);
194 void OnShowImeIfNeeded() override
{}
195 void OnInputMethodDestroyed(const InputMethod
* client
) override
{}
197 ClientChangeVerifier
* verifier_
;
198 DISALLOW_COPY_AND_ASSIGN(MockInputMethodObserver
);
201 class MockTextInputClient
: public DummyTextInputClient
{
203 MockTextInputClient()
204 : shown_event_count_(0), updated_event_count_(0), hidden_event_count_(0) {
206 ~MockTextInputClient() override
{}
208 void OnCandidateWindowShown() override
{ ++shown_event_count_
; }
209 void OnCandidateWindowUpdated() override
{ ++updated_event_count_
; }
210 void OnCandidateWindowHidden() override
{ ++hidden_event_count_
; }
212 int shown_event_count() const { return shown_event_count_
; }
213 int updated_event_count() const { return updated_event_count_
; }
214 int hidden_event_count() const { return hidden_event_count_
; }
217 int shown_event_count_
;
218 int updated_event_count_
;
219 int hidden_event_count_
;
222 typedef ScopedObserver
<InputMethod
, InputMethodObserver
>
223 InputMethodScopedObserver
;
225 void SetFocusedTextInputClient(InputMethod
* input_method
,
226 TextInputClient
* text_input_client
) {
227 if (switches::IsTextInputFocusManagerEnabled()) {
228 TextInputFocusManager::GetInstance()->FocusTextInputClient(
231 input_method
->SetFocusedTextInputClient(text_input_client
);
235 TEST_F(InputMethodBaseTest
, SetFocusedTextInputClient
) {
236 DummyTextInputClient text_input_client_1st
;
237 DummyTextInputClient text_input_client_2nd
;
239 ClientChangeVerifier verifier
;
240 MockInputMethodBase
input_method(&verifier
);
241 MockInputMethodObserver
input_method_observer(&verifier
);
242 InputMethodScopedObserver
scoped_observer(&input_method_observer
);
243 scoped_observer
.Add(&input_method
);
245 // Assume that the top-level-widget gains focus.
246 input_method
.OnFocus();
249 SCOPED_TRACE("Focus from NULL to 1st TextInputClient");
251 ASSERT_EQ(NULL
, input_method
.GetTextInputClient());
252 verifier
.ExpectClientChange(NULL
, &text_input_client_1st
);
253 SetFocusedTextInputClient(&input_method
, &text_input_client_1st
);
254 EXPECT_EQ(&text_input_client_1st
, input_method
.GetTextInputClient());
259 SCOPED_TRACE("Redundant focus events must be ignored");
260 verifier
.ExpectClientDoesNotChange();
261 SetFocusedTextInputClient(&input_method
, &text_input_client_1st
);
266 SCOPED_TRACE("Focus from 1st to 2nd TextInputClient");
268 ASSERT_EQ(&text_input_client_1st
, input_method
.GetTextInputClient());
269 verifier
.ExpectClientChange(&text_input_client_1st
,
270 &text_input_client_2nd
);
271 SetFocusedTextInputClient(&input_method
, &text_input_client_2nd
);
272 EXPECT_EQ(&text_input_client_2nd
, input_method
.GetTextInputClient());
277 SCOPED_TRACE("Focus from 2nd TextInputClient to NULL");
279 ASSERT_EQ(&text_input_client_2nd
, input_method
.GetTextInputClient());
280 verifier
.ExpectClientChange(&text_input_client_2nd
, NULL
);
281 SetFocusedTextInputClient(&input_method
, NULL
);
282 EXPECT_EQ(NULL
, input_method
.GetTextInputClient());
287 SCOPED_TRACE("Redundant focus events must be ignored");
288 verifier
.ExpectClientDoesNotChange();
289 SetFocusedTextInputClient(&input_method
, NULL
);
294 TEST_F(InputMethodBaseTest
, DetachTextInputClient
) {
295 // DetachTextInputClient is not supported when IsTextInputFocusManagerEnabled.
296 if (switches::IsTextInputFocusManagerEnabled())
299 DummyTextInputClient text_input_client
;
300 DummyTextInputClient text_input_client_the_other
;
302 ClientChangeVerifier verifier
;
303 MockInputMethodBase
input_method(&verifier
);
304 MockInputMethodObserver
input_method_observer(&verifier
);
305 InputMethodScopedObserver
scoped_observer(&input_method_observer
);
306 scoped_observer
.Add(&input_method
);
308 // Assume that the top-level-widget gains focus.
309 input_method
.OnFocus();
311 // Initialize for the next test.
313 verifier
.ExpectClientChange(NULL
, &text_input_client
);
314 input_method
.SetFocusedTextInputClient(&text_input_client
);
319 SCOPED_TRACE("DetachTextInputClient must be ignored for other clients");
320 ASSERT_EQ(&text_input_client
, input_method
.GetTextInputClient());
321 verifier
.ExpectClientDoesNotChange();
322 input_method
.DetachTextInputClient(&text_input_client_the_other
);
323 EXPECT_EQ(&text_input_client
, input_method
.GetTextInputClient());
328 SCOPED_TRACE("DetachTextInputClient must succeed even after the "
329 "top-level loses the focus");
331 ASSERT_EQ(&text_input_client
, input_method
.GetTextInputClient());
332 input_method
.OnBlur();
333 input_method
.OnFocus();
334 verifier
.ExpectClientChange(&text_input_client
, NULL
);
335 input_method
.DetachTextInputClient(&text_input_client
);
336 EXPECT_EQ(NULL
, input_method
.GetTextInputClient());
341 TEST_F(InputMethodBaseTest
, CandidateWindowEvents
) {
342 MockTextInputClient text_input_client
;
345 ClientChangeVerifier verifier
;
346 MockInputMethodBase
input_method_base(&verifier
);
347 input_method_base
.OnFocus();
349 verifier
.ExpectClientChange(NULL
, &text_input_client
);
350 SetFocusedTextInputClient(&input_method_base
, &text_input_client
);
352 EXPECT_EQ(0, text_input_client
.shown_event_count());
353 EXPECT_EQ(0, text_input_client
.updated_event_count());
354 EXPECT_EQ(0, text_input_client
.hidden_event_count());
356 input_method_base
.OnCandidateWindowShown();
357 base::RunLoop().RunUntilIdle();
359 EXPECT_EQ(1, text_input_client
.shown_event_count());
360 EXPECT_EQ(0, text_input_client
.updated_event_count());
361 EXPECT_EQ(0, text_input_client
.hidden_event_count());
363 input_method_base
.OnCandidateWindowUpdated();
364 base::RunLoop().RunUntilIdle();
366 EXPECT_EQ(1, text_input_client
.shown_event_count());
367 EXPECT_EQ(1, text_input_client
.updated_event_count());
368 EXPECT_EQ(0, text_input_client
.hidden_event_count());
370 input_method_base
.OnCandidateWindowHidden();
371 base::RunLoop().RunUntilIdle();
373 EXPECT_EQ(1, text_input_client
.shown_event_count());
374 EXPECT_EQ(1, text_input_client
.updated_event_count());
375 EXPECT_EQ(1, text_input_client
.hidden_event_count());
377 input_method_base
.OnCandidateWindowShown();
380 // If InputMethod is deleted immediately after an event happens, but before
381 // its callback is invoked, the callback will be cancelled.
382 base::RunLoop().RunUntilIdle();
383 EXPECT_EQ(1, text_input_client
.shown_event_count());
384 EXPECT_EQ(1, text_input_client
.updated_event_count());
385 EXPECT_EQ(1, text_input_client
.hidden_event_count());