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 ~InputMethodBaseTest() override
{}
123 void SetUp() override
{ message_loop_
.reset(new base::MessageLoopForUI
); }
125 void TearDown() override
{ message_loop_
.reset(); }
128 scoped_ptr
<base::MessageLoop
> message_loop_
;
129 DISALLOW_COPY_AND_ASSIGN(InputMethodBaseTest
);
132 class MockInputMethodBase
: public InputMethodBase
{
134 // Note: this class does not take the ownership of |verifier|.
135 MockInputMethodBase(ClientChangeVerifier
* verifier
) : verifier_(verifier
) {
137 ~MockInputMethodBase() override
{}
140 // Overriden from InputMethod.
141 bool OnUntranslatedIMEMessage(
142 const base::NativeEvent
& event
,
143 InputMethod::NativeEventResult
* result
) override
{
146 void DispatchKeyEvent(ui::KeyEvent
*) override
{}
147 void OnCaretBoundsChanged(const TextInputClient
* client
) override
{}
148 void CancelComposition(const TextInputClient
* client
) override
{}
149 void OnInputLocaleChanged() override
{}
150 std::string
GetInputLocale() override
{ return ""; }
151 bool IsCandidatePopupOpen() const override
{ return false; }
152 // Overriden from InputMethodBase.
153 void OnWillChangeFocusedClient(TextInputClient
* focused_before
,
154 TextInputClient
* focused
) override
{
155 verifier_
->OnWillChangeFocusedClient(focused_before
, focused
);
158 void OnDidChangeFocusedClient(TextInputClient
* focused_before
,
159 TextInputClient
* focused
) override
{
160 verifier_
->OnDidChangeFocusedClient(focused_before
, focused
);
163 ClientChangeVerifier
* verifier_
;
165 FRIEND_TEST_ALL_PREFIXES(InputMethodBaseTest
, CandidateWindowEvents
);
166 DISALLOW_COPY_AND_ASSIGN(MockInputMethodBase
);
169 class MockInputMethodObserver
: public InputMethodObserver
{
171 // Note: this class does not take the ownership of |verifier|.
172 explicit MockInputMethodObserver(ClientChangeVerifier
* verifier
)
173 : verifier_(verifier
) {
175 ~MockInputMethodObserver() override
{}
178 void OnTextInputTypeChanged(const TextInputClient
* client
) override
{}
179 void OnFocus() override
{}
180 void OnBlur() override
{}
181 void OnCaretBoundsChanged(const TextInputClient
* client
) override
{}
182 void OnTextInputStateChanged(const TextInputClient
* client
) override
{
183 verifier_
->OnTextInputStateChanged(client
);
185 void OnShowImeIfNeeded() override
{}
186 void OnInputMethodDestroyed(const InputMethod
* client
) override
{}
188 ClientChangeVerifier
* verifier_
;
189 DISALLOW_COPY_AND_ASSIGN(MockInputMethodObserver
);
192 typedef ScopedObserver
<InputMethod
, InputMethodObserver
>
193 InputMethodScopedObserver
;
195 void SetFocusedTextInputClient(InputMethod
* input_method
,
196 TextInputClient
* text_input_client
) {
197 input_method
->SetFocusedTextInputClient(text_input_client
);
200 TEST_F(InputMethodBaseTest
, SetFocusedTextInputClient
) {
201 DummyTextInputClient text_input_client_1st
;
202 DummyTextInputClient text_input_client_2nd
;
204 ClientChangeVerifier verifier
;
205 MockInputMethodBase
input_method(&verifier
);
206 MockInputMethodObserver
input_method_observer(&verifier
);
207 InputMethodScopedObserver
scoped_observer(&input_method_observer
);
208 scoped_observer
.Add(&input_method
);
210 // Assume that the top-level-widget gains focus.
211 input_method
.OnFocus();
214 SCOPED_TRACE("Focus from NULL to 1st TextInputClient");
216 ASSERT_EQ(NULL
, input_method
.GetTextInputClient());
217 verifier
.ExpectClientChange(NULL
, &text_input_client_1st
);
218 SetFocusedTextInputClient(&input_method
, &text_input_client_1st
);
219 EXPECT_EQ(&text_input_client_1st
, input_method
.GetTextInputClient());
224 SCOPED_TRACE("Redundant focus events must be ignored");
225 verifier
.ExpectClientDoesNotChange();
226 SetFocusedTextInputClient(&input_method
, &text_input_client_1st
);
231 SCOPED_TRACE("Focus from 1st to 2nd TextInputClient");
233 ASSERT_EQ(&text_input_client_1st
, input_method
.GetTextInputClient());
234 verifier
.ExpectClientChange(&text_input_client_1st
,
235 &text_input_client_2nd
);
236 SetFocusedTextInputClient(&input_method
, &text_input_client_2nd
);
237 EXPECT_EQ(&text_input_client_2nd
, input_method
.GetTextInputClient());
242 SCOPED_TRACE("Focus from 2nd TextInputClient to NULL");
244 ASSERT_EQ(&text_input_client_2nd
, input_method
.GetTextInputClient());
245 verifier
.ExpectClientChange(&text_input_client_2nd
, NULL
);
246 SetFocusedTextInputClient(&input_method
, NULL
);
247 EXPECT_EQ(NULL
, input_method
.GetTextInputClient());
252 SCOPED_TRACE("Redundant focus events must be ignored");
253 verifier
.ExpectClientDoesNotChange();
254 SetFocusedTextInputClient(&input_method
, NULL
);
259 TEST_F(InputMethodBaseTest
, DetachTextInputClient
) {
260 DummyTextInputClient text_input_client
;
261 DummyTextInputClient text_input_client_the_other
;
263 ClientChangeVerifier verifier
;
264 MockInputMethodBase
input_method(&verifier
);
265 MockInputMethodObserver
input_method_observer(&verifier
);
266 InputMethodScopedObserver
scoped_observer(&input_method_observer
);
267 scoped_observer
.Add(&input_method
);
269 // Assume that the top-level-widget gains focus.
270 input_method
.OnFocus();
272 // Initialize for the next test.
274 verifier
.ExpectClientChange(NULL
, &text_input_client
);
275 input_method
.SetFocusedTextInputClient(&text_input_client
);
280 SCOPED_TRACE("DetachTextInputClient must be ignored for other clients");
281 ASSERT_EQ(&text_input_client
, input_method
.GetTextInputClient());
282 verifier
.ExpectClientDoesNotChange();
283 input_method
.DetachTextInputClient(&text_input_client_the_other
);
284 EXPECT_EQ(&text_input_client
, input_method
.GetTextInputClient());
289 SCOPED_TRACE("DetachTextInputClient must succeed even after the "
290 "top-level loses the focus");
292 ASSERT_EQ(&text_input_client
, input_method
.GetTextInputClient());
293 input_method
.OnBlur();
294 input_method
.OnFocus();
295 verifier
.ExpectClientChange(&text_input_client
, NULL
);
296 input_method
.DetachTextInputClient(&text_input_client
);
297 EXPECT_EQ(NULL
, input_method
.GetTextInputClient());