| OLD | NEW |
| (Empty) |
| 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 | |
| 19 namespace ui { | |
| 20 namespace { | |
| 21 | |
| 22 class 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 | |
| 125 class 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 | |
| 145 class MockInputMethodBase : public InputMethodBase { | |
| 146 public: | |
| 147 // Note: this class does not take the ownership of |verifier|. | |
| 148 MockInputMethodBase(ClientChangeVerifier* verifier) : verifier_(verifier) { | |
| 149 } | |
| 150 ~MockInputMethodBase() override {} | |
| 151 | |
| 152 private: | |
| 153 // Overriden from InputMethod. | |
| 154 bool OnUntranslatedIMEMessage( | |
| 155 const base::NativeEvent& event, | |
| 156 InputMethod::NativeEventResult* result) override { | |
| 157 return false; | |
| 158 } | |
| 159 bool DispatchKeyEvent(const ui::KeyEvent&) override { return false; } | |
| 160 void OnCaretBoundsChanged(const TextInputClient* client) override {} | |
| 161 void CancelComposition(const TextInputClient* client) override {} | |
| 162 void OnInputLocaleChanged() override {} | |
| 163 std::string GetInputLocale() override { return ""; } | |
| 164 bool IsActive() override { return false; } | |
| 165 bool IsCandidatePopupOpen() const override { return false; } | |
| 166 // Overriden from InputMethodBase. | |
| 167 void OnWillChangeFocusedClient(TextInputClient* focused_before, | |
| 168 TextInputClient* focused) override { | |
| 169 verifier_->OnWillChangeFocusedClient(focused_before, focused); | |
| 170 } | |
| 171 | |
| 172 void OnDidChangeFocusedClient(TextInputClient* focused_before, | |
| 173 TextInputClient* focused) override { | |
| 174 verifier_->OnDidChangeFocusedClient(focused_before, focused); | |
| 175 } | |
| 176 | |
| 177 ClientChangeVerifier* verifier_; | |
| 178 | |
| 179 FRIEND_TEST_ALL_PREFIXES(InputMethodBaseTest, CandidateWindowEvents); | |
| 180 DISALLOW_COPY_AND_ASSIGN(MockInputMethodBase); | |
| 181 }; | |
| 182 | |
| 183 class MockInputMethodObserver : public InputMethodObserver { | |
| 184 public: | |
| 185 // Note: this class does not take the ownership of |verifier|. | |
| 186 explicit MockInputMethodObserver(ClientChangeVerifier* verifier) | |
| 187 : verifier_(verifier) { | |
| 188 } | |
| 189 ~MockInputMethodObserver() override {} | |
| 190 | |
| 191 private: | |
| 192 void OnTextInputTypeChanged(const TextInputClient* client) override {} | |
| 193 void OnFocus() override {} | |
| 194 void OnBlur() override {} | |
| 195 void OnCaretBoundsChanged(const TextInputClient* client) override {} | |
| 196 void OnTextInputStateChanged(const TextInputClient* client) override { | |
| 197 verifier_->OnTextInputStateChanged(client); | |
| 198 } | |
| 199 void OnShowImeIfNeeded() override {} | |
| 200 void OnInputMethodDestroyed(const InputMethod* client) override {} | |
| 201 | |
| 202 ClientChangeVerifier* verifier_; | |
| 203 DISALLOW_COPY_AND_ASSIGN(MockInputMethodObserver); | |
| 204 }; | |
| 205 | |
| 206 class MockTextInputClient : public DummyTextInputClient { | |
| 207 public: | |
| 208 MockTextInputClient() | |
| 209 : shown_event_count_(0), updated_event_count_(0), hidden_event_count_(0) { | |
| 210 } | |
| 211 ~MockTextInputClient() override {} | |
| 212 | |
| 213 void OnCandidateWindowShown() override { ++shown_event_count_; } | |
| 214 void OnCandidateWindowUpdated() override { ++updated_event_count_; } | |
| 215 void OnCandidateWindowHidden() override { ++hidden_event_count_; } | |
| 216 | |
| 217 int shown_event_count() const { return shown_event_count_; } | |
| 218 int updated_event_count() const { return updated_event_count_; } | |
| 219 int hidden_event_count() const { return hidden_event_count_; } | |
| 220 | |
| 221 private: | |
| 222 int shown_event_count_; | |
| 223 int updated_event_count_; | |
| 224 int hidden_event_count_; | |
| 225 }; | |
| 226 | |
| 227 typedef ScopedObserver<InputMethod, InputMethodObserver> | |
| 228 InputMethodScopedObserver; | |
| 229 | |
| 230 void SetFocusedTextInputClient(InputMethod* input_method, | |
| 231 TextInputClient* text_input_client) { | |
| 232 if (switches::IsTextInputFocusManagerEnabled()) { | |
| 233 TextInputFocusManager::GetInstance()->FocusTextInputClient( | |
| 234 text_input_client); | |
| 235 } else { | |
| 236 input_method->SetFocusedTextInputClient(text_input_client); | |
| 237 } | |
| 238 } | |
| 239 | |
| 240 TEST_F(InputMethodBaseTest, SetFocusedTextInputClient) { | |
| 241 DummyTextInputClient text_input_client_1st; | |
| 242 DummyTextInputClient text_input_client_2nd; | |
| 243 | |
| 244 ClientChangeVerifier verifier; | |
| 245 MockInputMethodBase input_method(&verifier); | |
| 246 MockInputMethodObserver input_method_observer(&verifier); | |
| 247 InputMethodScopedObserver scoped_observer(&input_method_observer); | |
| 248 scoped_observer.Add(&input_method); | |
| 249 | |
| 250 // Assume that the top-level-widget gains focus. | |
| 251 input_method.OnFocus(); | |
| 252 | |
| 253 { | |
| 254 SCOPED_TRACE("Focus from NULL to 1st TextInputClient"); | |
| 255 | |
| 256 ASSERT_EQ(NULL, input_method.GetTextInputClient()); | |
| 257 verifier.ExpectClientChange(NULL, &text_input_client_1st); | |
| 258 SetFocusedTextInputClient(&input_method, &text_input_client_1st); | |
| 259 EXPECT_EQ(&text_input_client_1st, input_method.GetTextInputClient()); | |
| 260 verifier.Verify(); | |
| 261 } | |
| 262 | |
| 263 { | |
| 264 SCOPED_TRACE("Redundant focus events must be ignored"); | |
| 265 verifier.ExpectClientDoesNotChange(); | |
| 266 SetFocusedTextInputClient(&input_method, &text_input_client_1st); | |
| 267 verifier.Verify(); | |
| 268 } | |
| 269 | |
| 270 { | |
| 271 SCOPED_TRACE("Focus from 1st to 2nd TextInputClient"); | |
| 272 | |
| 273 ASSERT_EQ(&text_input_client_1st, input_method.GetTextInputClient()); | |
| 274 verifier.ExpectClientChange(&text_input_client_1st, | |
| 275 &text_input_client_2nd); | |
| 276 SetFocusedTextInputClient(&input_method, &text_input_client_2nd); | |
| 277 EXPECT_EQ(&text_input_client_2nd, input_method.GetTextInputClient()); | |
| 278 verifier.Verify(); | |
| 279 } | |
| 280 | |
| 281 { | |
| 282 SCOPED_TRACE("Focus from 2nd TextInputClient to NULL"); | |
| 283 | |
| 284 ASSERT_EQ(&text_input_client_2nd, input_method.GetTextInputClient()); | |
| 285 verifier.ExpectClientChange(&text_input_client_2nd, NULL); | |
| 286 SetFocusedTextInputClient(&input_method, NULL); | |
| 287 EXPECT_EQ(NULL, input_method.GetTextInputClient()); | |
| 288 verifier.Verify(); | |
| 289 } | |
| 290 | |
| 291 { | |
| 292 SCOPED_TRACE("Redundant focus events must be ignored"); | |
| 293 verifier.ExpectClientDoesNotChange(); | |
| 294 SetFocusedTextInputClient(&input_method, NULL); | |
| 295 verifier.Verify(); | |
| 296 } | |
| 297 } | |
| 298 | |
| 299 TEST_F(InputMethodBaseTest, DetachTextInputClient) { | |
| 300 // DetachTextInputClient is not supported when IsTextInputFocusManagerEnabled. | |
| 301 if (switches::IsTextInputFocusManagerEnabled()) | |
| 302 return; | |
| 303 | |
| 304 DummyTextInputClient text_input_client; | |
| 305 DummyTextInputClient text_input_client_the_other; | |
| 306 | |
| 307 ClientChangeVerifier verifier; | |
| 308 MockInputMethodBase input_method(&verifier); | |
| 309 MockInputMethodObserver input_method_observer(&verifier); | |
| 310 InputMethodScopedObserver scoped_observer(&input_method_observer); | |
| 311 scoped_observer.Add(&input_method); | |
| 312 | |
| 313 // Assume that the top-level-widget gains focus. | |
| 314 input_method.OnFocus(); | |
| 315 | |
| 316 // Initialize for the next test. | |
| 317 { | |
| 318 verifier.ExpectClientChange(NULL, &text_input_client); | |
| 319 input_method.SetFocusedTextInputClient(&text_input_client); | |
| 320 verifier.Verify(); | |
| 321 } | |
| 322 | |
| 323 { | |
| 324 SCOPED_TRACE("DetachTextInputClient must be ignored for other clients"); | |
| 325 ASSERT_EQ(&text_input_client, input_method.GetTextInputClient()); | |
| 326 verifier.ExpectClientDoesNotChange(); | |
| 327 input_method.DetachTextInputClient(&text_input_client_the_other); | |
| 328 EXPECT_EQ(&text_input_client, input_method.GetTextInputClient()); | |
| 329 verifier.Verify(); | |
| 330 } | |
| 331 | |
| 332 { | |
| 333 SCOPED_TRACE("DetachTextInputClient must succeed even after the " | |
| 334 "top-level loses the focus"); | |
| 335 | |
| 336 ASSERT_EQ(&text_input_client, input_method.GetTextInputClient()); | |
| 337 input_method.OnBlur(); | |
| 338 input_method.OnFocus(); | |
| 339 verifier.ExpectClientChange(&text_input_client, NULL); | |
| 340 input_method.DetachTextInputClient(&text_input_client); | |
| 341 EXPECT_EQ(NULL, input_method.GetTextInputClient()); | |
| 342 verifier.Verify(); | |
| 343 } | |
| 344 } | |
| 345 | |
| 346 TEST_F(InputMethodBaseTest, CandidateWindowEvents) { | |
| 347 MockTextInputClient text_input_client; | |
| 348 | |
| 349 { | |
| 350 ClientChangeVerifier verifier; | |
| 351 MockInputMethodBase input_method_base(&verifier); | |
| 352 input_method_base.OnFocus(); | |
| 353 | |
| 354 verifier.ExpectClientChange(NULL, &text_input_client); | |
| 355 SetFocusedTextInputClient(&input_method_base, &text_input_client); | |
| 356 | |
| 357 EXPECT_EQ(0, text_input_client.shown_event_count()); | |
| 358 EXPECT_EQ(0, text_input_client.updated_event_count()); | |
| 359 EXPECT_EQ(0, text_input_client.hidden_event_count()); | |
| 360 | |
| 361 input_method_base.OnCandidateWindowShown(); | |
| 362 base::RunLoop().RunUntilIdle(); | |
| 363 | |
| 364 EXPECT_EQ(1, text_input_client.shown_event_count()); | |
| 365 EXPECT_EQ(0, text_input_client.updated_event_count()); | |
| 366 EXPECT_EQ(0, text_input_client.hidden_event_count()); | |
| 367 | |
| 368 input_method_base.OnCandidateWindowUpdated(); | |
| 369 base::RunLoop().RunUntilIdle(); | |
| 370 | |
| 371 EXPECT_EQ(1, text_input_client.shown_event_count()); | |
| 372 EXPECT_EQ(1, text_input_client.updated_event_count()); | |
| 373 EXPECT_EQ(0, text_input_client.hidden_event_count()); | |
| 374 | |
| 375 input_method_base.OnCandidateWindowHidden(); | |
| 376 base::RunLoop().RunUntilIdle(); | |
| 377 | |
| 378 EXPECT_EQ(1, text_input_client.shown_event_count()); | |
| 379 EXPECT_EQ(1, text_input_client.updated_event_count()); | |
| 380 EXPECT_EQ(1, text_input_client.hidden_event_count()); | |
| 381 | |
| 382 input_method_base.OnCandidateWindowShown(); | |
| 383 } | |
| 384 | |
| 385 // If InputMethod is deleted immediately after an event happens, but before | |
| 386 // its callback is invoked, the callback will be cancelled. | |
| 387 base::RunLoop().RunUntilIdle(); | |
| 388 EXPECT_EQ(1, text_input_client.shown_event_count()); | |
| 389 EXPECT_EQ(1, text_input_client.updated_event_count()); | |
| 390 EXPECT_EQ(1, text_input_client.hidden_event_count()); | |
| 391 } | |
| 392 | |
| 393 } // namespace | |
| 394 } // namespace ui | |
| OLD | NEW |