Home | History | Annotate | Download | only in ime
      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   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 
    195 class 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 
    225 class 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 
    253 typedef ScopedObserver<InputMethod, InputMethodObserver>
    254     InputMethodScopedObserver;
    255 
    256 void 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 
    266 TEST_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 
    325 TEST_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 
    372 TEST_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