Home | History | Annotate | Download | only in browser
      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 <vector>
      6 
      7 #include "base/compiler_specific.h"
      8 #include "base/message_loop/message_loop.h"
      9 #include "base/strings/string16.h"
     10 #include "base/strings/utf_string_conversions.h"
     11 #include "components/autofill/core/browser/autofill_manager.h"
     12 #include "components/autofill/core/browser/popup_item_ids.h"
     13 #include "components/autofill/core/browser/test_autofill_client.h"
     14 #include "components/autofill/core/browser/test_autofill_driver.h"
     15 #include "components/autofill/core/browser/test_autofill_external_delegate.h"
     16 #include "components/autofill/core/common/form_data.h"
     17 #include "components/autofill/core/common/form_field_data.h"
     18 #include "components/autofill/core/common/password_form_fill_data.h"
     19 #include "testing/gmock/include/gmock/gmock.h"
     20 #include "testing/gtest/include/gtest/gtest.h"
     21 #include "ui/gfx/rect.h"
     22 
     23 using base::ASCIIToUTF16;
     24 using testing::_;
     25 
     26 namespace autofill {
     27 
     28 namespace {
     29 
     30 // A constant value to use as the Autofill query ID.
     31 const int kQueryId = 5;
     32 
     33 // A constant value to use as an Autofill profile ID.
     34 const int kAutofillProfileId = 1;
     35 
     36 class MockAutofillDriver : public TestAutofillDriver {
     37  public:
     38   MockAutofillDriver() {}
     39   // Mock methods to enable testability.
     40   MOCK_METHOD1(RendererShouldAcceptDataListSuggestion,
     41                void(const base::string16&));
     42   MOCK_METHOD0(RendererShouldClearFilledForm, void());
     43   MOCK_METHOD0(RendererShouldClearPreviewedForm, void());
     44   MOCK_METHOD1(RendererShouldFillFieldWithValue, void(const base::string16&));
     45   MOCK_METHOD1(RendererShouldPreviewFieldWithValue,
     46                void(const base::string16&));
     47 
     48  private:
     49   DISALLOW_COPY_AND_ASSIGN(MockAutofillDriver);
     50 };
     51 
     52 class MockAutofillClient : public autofill::TestAutofillClient {
     53  public:
     54   MockAutofillClient() {}
     55 
     56   MOCK_METHOD7(ShowAutofillPopup,
     57                void(const gfx::RectF& element_bounds,
     58                     base::i18n::TextDirection text_direction,
     59                     const std::vector<base::string16>& values,
     60                     const std::vector<base::string16>& labels,
     61                     const std::vector<base::string16>& icons,
     62                     const std::vector<int>& identifiers,
     63                     base::WeakPtr<AutofillPopupDelegate> delegate));
     64 
     65   MOCK_METHOD2(UpdateAutofillPopupDataListValues,
     66                void(const std::vector<base::string16>& values,
     67                     const std::vector<base::string16>& lables));
     68 
     69   MOCK_METHOD0(HideAutofillPopup, void());
     70 
     71  private:
     72   DISALLOW_COPY_AND_ASSIGN(MockAutofillClient);
     73 };
     74 
     75 class MockAutofillManager : public AutofillManager {
     76  public:
     77   MockAutofillManager(AutofillDriver* driver, MockAutofillClient* client)
     78       // Force to use the constructor designated for unit test, but we don't
     79       // really need personal_data in this test so we pass a NULL pointer.
     80       : AutofillManager(driver, client, NULL) {}
     81   virtual ~MockAutofillManager() {}
     82 
     83   MOCK_METHOD5(FillOrPreviewForm,
     84                void(AutofillDriver::RendererFormDataAction action,
     85                     int query_id,
     86                     const FormData& form,
     87                     const FormFieldData& field,
     88                     int unique_id));
     89 
     90  private:
     91   DISALLOW_COPY_AND_ASSIGN(MockAutofillManager);
     92 };
     93 
     94 }  // namespace
     95 
     96 class AutofillExternalDelegateUnitTest : public testing::Test {
     97  protected:
     98   virtual void SetUp() OVERRIDE {
     99     autofill_driver_.reset(new MockAutofillDriver());
    100     autofill_manager_.reset(
    101         new MockAutofillManager(autofill_driver_.get(), &autofill_client_));
    102     external_delegate_.reset(
    103         new AutofillExternalDelegate(
    104             autofill_manager_.get(), autofill_driver_.get()));
    105   }
    106 
    107   virtual void TearDown() OVERRIDE {
    108     // Order of destruction is important as AutofillManager relies on
    109     // PersonalDataManager to be around when it gets destroyed.
    110     autofill_manager_.reset();
    111     external_delegate_.reset();
    112     autofill_driver_.reset();
    113   }
    114 
    115   // Issue an OnQuery call with the given |query_id|.
    116   void IssueOnQuery(int query_id) {
    117     const FormData form;
    118     FormFieldData field;
    119     field.is_focusable = true;
    120     field.should_autocomplete = true;
    121     const gfx::RectF element_bounds;
    122 
    123     external_delegate_->OnQuery(query_id, form, field, element_bounds, true);
    124   }
    125 
    126   MockAutofillClient autofill_client_;
    127   scoped_ptr<MockAutofillDriver> autofill_driver_;
    128   scoped_ptr<MockAutofillManager> autofill_manager_;
    129   scoped_ptr<AutofillExternalDelegate> external_delegate_;
    130 
    131   base::MessageLoop message_loop_;
    132 };
    133 
    134 // Test that our external delegate called the virtual methods at the right time.
    135 TEST_F(AutofillExternalDelegateUnitTest, TestExternalDelegateVirtualCalls) {
    136   IssueOnQuery(kQueryId);
    137 
    138   // The enums must be cast to ints to prevent compile errors on linux_rel.
    139   EXPECT_CALL(
    140       autofill_client_,
    141       ShowAutofillPopup(_,
    142                         _,
    143                         _,
    144                         _,
    145                         _,
    146                         testing::ElementsAre(
    147                             kAutofillProfileId,
    148                             static_cast<int>(POPUP_ITEM_ID_SEPARATOR),
    149                             static_cast<int>(POPUP_ITEM_ID_AUTOFILL_OPTIONS)),
    150                         _));
    151 
    152   // This should call ShowAutofillPopup.
    153   std::vector<base::string16> autofill_item;
    154   autofill_item.push_back(base::string16());
    155   std::vector<int> autofill_ids;
    156   autofill_ids.push_back(kAutofillProfileId);
    157   external_delegate_->OnSuggestionsReturned(kQueryId,
    158                                             autofill_item,
    159                                             autofill_item,
    160                                             autofill_item,
    161                                             autofill_ids);
    162 
    163   EXPECT_CALL(*autofill_manager_,
    164               FillOrPreviewForm(
    165                   AutofillDriver::FORM_DATA_ACTION_FILL, _, _, _, _));
    166   EXPECT_CALL(autofill_client_, HideAutofillPopup());
    167 
    168   // This should trigger a call to hide the popup since we've selected an
    169   // option.
    170   external_delegate_->DidAcceptSuggestion(autofill_item[0], autofill_ids[0]);
    171 }
    172 
    173 // Test that data list elements for a node will appear in the Autofill popup.
    174 TEST_F(AutofillExternalDelegateUnitTest, ExternalDelegateDataList) {
    175   IssueOnQuery(kQueryId);
    176 
    177   std::vector<base::string16> data_list_items;
    178   data_list_items.push_back(base::string16());
    179 
    180   external_delegate_->SetCurrentDataListValues(data_list_items,
    181                                                data_list_items);
    182 
    183   // The enums must be cast to ints to prevent compile errors on linux_rel.
    184   EXPECT_CALL(
    185       autofill_client_,
    186       ShowAutofillPopup(_,
    187                         _,
    188                         _,
    189                         _,
    190                         _,
    191                         testing::ElementsAre(
    192                             static_cast<int>(POPUP_ITEM_ID_DATALIST_ENTRY),
    193                             static_cast<int>(POPUP_ITEM_ID_SEPARATOR),
    194                             kAutofillProfileId,
    195                             static_cast<int>(POPUP_ITEM_ID_SEPARATOR),
    196                             static_cast<int>(POPUP_ITEM_ID_AUTOFILL_OPTIONS)),
    197                         _));
    198 
    199   // This should call ShowAutofillPopup.
    200   std::vector<base::string16> autofill_item;
    201   autofill_item.push_back(base::string16());
    202   std::vector<int> autofill_ids;
    203   autofill_ids.push_back(kAutofillProfileId);
    204   external_delegate_->OnSuggestionsReturned(kQueryId,
    205                                             autofill_item,
    206                                             autofill_item,
    207                                             autofill_item,
    208                                             autofill_ids);
    209 
    210   // Try calling OnSuggestionsReturned with no Autofill values and ensure
    211   // the datalist items are still shown.
    212   // The enum must be cast to an int to prevent compile errors on linux_rel.
    213   EXPECT_CALL(
    214       autofill_client_,
    215       ShowAutofillPopup(
    216           _,
    217           _,
    218           _,
    219           _,
    220           _,
    221           testing::ElementsAre(static_cast<int>(POPUP_ITEM_ID_DATALIST_ENTRY)),
    222           _));
    223 
    224   autofill_item = std::vector<base::string16>();
    225   autofill_ids = std::vector<int>();
    226   external_delegate_->OnSuggestionsReturned(kQueryId,
    227                                             autofill_item,
    228                                             autofill_item,
    229                                             autofill_item,
    230                                             autofill_ids);
    231 }
    232 
    233 // Test that datalist values can get updated while a popup is showing.
    234 TEST_F(AutofillExternalDelegateUnitTest, UpdateDataListWhileShowingPopup) {
    235   IssueOnQuery(kQueryId);
    236 
    237   EXPECT_CALL(autofill_client_, ShowAutofillPopup(_, _, _, _, _, _, _))
    238       .Times(0);
    239 
    240   // Make sure just setting the data list values doesn't cause the popup to
    241   // appear.
    242   std::vector<base::string16> data_list_items;
    243   data_list_items.push_back(base::string16());
    244 
    245   external_delegate_->SetCurrentDataListValues(data_list_items,
    246                                                data_list_items);
    247 
    248   // The enums must be cast to ints to prevent compile errors on linux_rel.
    249   EXPECT_CALL(
    250       autofill_client_,
    251       ShowAutofillPopup(_,
    252                         _,
    253                         _,
    254                         _,
    255                         _,
    256                         testing::ElementsAre(
    257                             static_cast<int>(POPUP_ITEM_ID_DATALIST_ENTRY),
    258                             static_cast<int>(POPUP_ITEM_ID_SEPARATOR),
    259                             kAutofillProfileId,
    260                             static_cast<int>(POPUP_ITEM_ID_SEPARATOR),
    261                             static_cast<int>(POPUP_ITEM_ID_AUTOFILL_OPTIONS)),
    262                         _));
    263 
    264   // Ensure the popup is displayed.
    265   std::vector<base::string16> autofill_item;
    266   autofill_item.push_back(base::string16());
    267   std::vector<int> autofill_ids;
    268   autofill_ids.push_back(kAutofillProfileId);
    269   external_delegate_->OnSuggestionsReturned(kQueryId,
    270                                             autofill_item,
    271                                             autofill_item,
    272                                             autofill_item,
    273                                             autofill_ids);
    274 
    275   // This would normally get called from ShowAutofillPopup, but it is mocked so
    276   // we need to call OnPopupShown ourselves.
    277   external_delegate_->OnPopupShown();
    278 
    279   // Update the current data list and ensure the popup is updated.
    280   data_list_items.push_back(base::string16());
    281 
    282   // The enums must be cast to ints to prevent compile errors on linux_rel.
    283   EXPECT_CALL(
    284       autofill_client_,
    285       UpdateAutofillPopupDataListValues(data_list_items, data_list_items));
    286 
    287   external_delegate_->SetCurrentDataListValues(data_list_items,
    288                                                data_list_items);
    289 }
    290 
    291 // Test that the Autofill popup is able to display warnings explaining why
    292 // Autofill is disabled for a website.
    293 // Regression test for http://crbug.com/247880
    294 TEST_F(AutofillExternalDelegateUnitTest, AutofillWarnings) {
    295   IssueOnQuery(kQueryId);
    296 
    297   // The enums must be cast to ints to prevent compile errors on linux_rel.
    298   EXPECT_CALL(
    299       autofill_client_,
    300       ShowAutofillPopup(
    301           _,
    302           _,
    303           _,
    304           _,
    305           _,
    306           testing::ElementsAre(static_cast<int>(POPUP_ITEM_ID_WARNING_MESSAGE)),
    307           _));
    308 
    309   // This should call ShowAutofillPopup.
    310   std::vector<base::string16> autofill_item;
    311   autofill_item.push_back(base::string16());
    312   std::vector<int> autofill_ids;
    313   autofill_ids.push_back(POPUP_ITEM_ID_WARNING_MESSAGE);
    314   external_delegate_->OnSuggestionsReturned(kQueryId,
    315                                             autofill_item,
    316                                             autofill_item,
    317                                             autofill_item,
    318                                             autofill_ids);
    319 }
    320 
    321 // Test that the Autofill popup doesn't display a warning explaining why
    322 // Autofill is disabled for a website when there are no Autofill suggestions.
    323 // Regression test for http://crbug.com/105636
    324 TEST_F(AutofillExternalDelegateUnitTest, NoAutofillWarningsWithoutSuggestions) {
    325   const FormData form;
    326   FormFieldData field;
    327   field.is_focusable = true;
    328   field.should_autocomplete = false;
    329   const gfx::RectF element_bounds;
    330 
    331   external_delegate_->OnQuery(kQueryId, form, field, element_bounds, true);
    332 
    333   EXPECT_CALL(autofill_client_, ShowAutofillPopup(_, _, _, _, _, _, _))
    334       .Times(0);
    335   EXPECT_CALL(autofill_client_, HideAutofillPopup()).Times(1);
    336 
    337   // This should not call ShowAutofillPopup.
    338   std::vector<base::string16> autofill_item;
    339   autofill_item.push_back(base::string16());
    340   std::vector<int> autofill_ids;
    341   autofill_ids.push_back(POPUP_ITEM_ID_AUTOCOMPLETE_ENTRY);
    342   external_delegate_->OnSuggestionsReturned(kQueryId,
    343                                             autofill_item,
    344                                             autofill_item,
    345                                             autofill_item,
    346                                             autofill_ids);
    347 }
    348 
    349 // Test that the Autofill delegate doesn't try and fill a form with a
    350 // negative unique id.
    351 TEST_F(AutofillExternalDelegateUnitTest, ExternalDelegateInvalidUniqueId) {
    352   // Ensure it doesn't try to preview the negative id.
    353   EXPECT_CALL(*autofill_manager_, FillOrPreviewForm(_, _, _, _, _)).Times(0);
    354   EXPECT_CALL(*autofill_driver_, RendererShouldClearPreviewedForm()).Times(1);
    355   external_delegate_->DidSelectSuggestion(base::string16(), -1);
    356 
    357   // Ensure it doesn't try to fill the form in with the negative id.
    358   EXPECT_CALL(autofill_client_, HideAutofillPopup());
    359   EXPECT_CALL(*autofill_manager_, FillOrPreviewForm(_, _, _, _, _)).Times(0);
    360   external_delegate_->DidAcceptSuggestion(base::string16(), -1);
    361 }
    362 
    363 // Test that the ClearPreview call is only sent if the form was being previewed
    364 // (i.e. it isn't autofilling a password).
    365 TEST_F(AutofillExternalDelegateUnitTest, ExternalDelegateClearPreviewedForm) {
    366   // Ensure selecting a new password entries or Autofill entries will
    367   // cause any previews to get cleared.
    368   EXPECT_CALL(*autofill_driver_, RendererShouldClearPreviewedForm()).Times(1);
    369   external_delegate_->DidSelectSuggestion(ASCIIToUTF16("baz foo"),
    370                                           POPUP_ITEM_ID_PASSWORD_ENTRY);
    371   EXPECT_CALL(*autofill_driver_, RendererShouldClearPreviewedForm()).Times(1);
    372   EXPECT_CALL(*autofill_manager_,
    373               FillOrPreviewForm(
    374                   AutofillDriver::FORM_DATA_ACTION_PREVIEW, _, _, _, _));
    375   external_delegate_->DidSelectSuggestion(ASCIIToUTF16("baz foo"), 1);
    376 
    377   // Ensure selecting an autocomplete entry will cause any previews to
    378   // get cleared.
    379   EXPECT_CALL(*autofill_driver_, RendererShouldClearPreviewedForm()).Times(1);
    380   EXPECT_CALL(*autofill_driver_, RendererShouldPreviewFieldWithValue(
    381                                      ASCIIToUTF16("baz foo")));
    382   external_delegate_->DidSelectSuggestion(ASCIIToUTF16("baz foo"),
    383                                           POPUP_ITEM_ID_AUTOCOMPLETE_ENTRY);
    384 }
    385 
    386 // Test that the popup is hidden once we are done editing the autofill field.
    387 TEST_F(AutofillExternalDelegateUnitTest,
    388        ExternalDelegateHidePopupAfterEditing) {
    389   EXPECT_CALL(autofill_client_, ShowAutofillPopup(_, _, _, _, _, _, _));
    390   autofill::GenerateTestAutofillPopup(external_delegate_.get());
    391 
    392   EXPECT_CALL(autofill_client_, HideAutofillPopup());
    393   external_delegate_->DidEndTextFieldEditing();
    394 }
    395 
    396 // Test that the driver is directed to accept the data list after being notified
    397 // that the user accepted the data list suggestion.
    398 TEST_F(AutofillExternalDelegateUnitTest, ExternalDelegateAcceptSuggestion) {
    399   EXPECT_CALL(autofill_client_, HideAutofillPopup());
    400   base::string16 dummy_string(ASCIIToUTF16("baz qux"));
    401   EXPECT_CALL(*autofill_driver_,
    402               RendererShouldAcceptDataListSuggestion(dummy_string));
    403   external_delegate_->DidAcceptSuggestion(dummy_string,
    404                                           POPUP_ITEM_ID_DATALIST_ENTRY);
    405 }
    406 
    407 // Test that the driver is directed to clear the form after being notified that
    408 // the user accepted the suggestion to clear the form.
    409 TEST_F(AutofillExternalDelegateUnitTest, ExternalDelegateClearForm) {
    410   EXPECT_CALL(autofill_client_, HideAutofillPopup());
    411   EXPECT_CALL(*autofill_driver_, RendererShouldClearFilledForm());
    412 
    413   external_delegate_->DidAcceptSuggestion(base::string16(),
    414                                           POPUP_ITEM_ID_CLEAR_FORM);
    415 }
    416 
    417 TEST_F(AutofillExternalDelegateUnitTest, ExternalDelegateHideWarning) {
    418   // Set up a field that shouldn't get autocompleted or display warnings.
    419   const FormData form;
    420   FormFieldData field;
    421   field.is_focusable = true;
    422   field.should_autocomplete = false;
    423   const gfx::RectF element_bounds;
    424 
    425   external_delegate_->OnQuery(kQueryId, form, field, element_bounds, false);
    426 
    427   std::vector<base::string16> autofill_items;
    428   autofill_items.push_back(base::string16());
    429   std::vector<int> autofill_ids;
    430   autofill_ids.push_back(POPUP_ITEM_ID_AUTOCOMPLETE_ENTRY);
    431 
    432   // Ensure the popup tries to hide itself, since it is not allowed to show
    433   // anything.
    434   EXPECT_CALL(autofill_client_, HideAutofillPopup());
    435 
    436   external_delegate_->OnSuggestionsReturned(kQueryId,
    437                                             autofill_items,
    438                                             autofill_items,
    439                                             autofill_items,
    440                                             autofill_ids);
    441 }
    442 
    443 TEST_F(AutofillExternalDelegateUnitTest, ExternalDelegateFillFieldWithValue) {
    444   EXPECT_CALL(autofill_client_, HideAutofillPopup());
    445   base::string16 dummy_string(ASCIIToUTF16("baz foo"));
    446   EXPECT_CALL(*autofill_driver_,
    447               RendererShouldFillFieldWithValue(dummy_string));
    448   external_delegate_->DidAcceptSuggestion(dummy_string,
    449                                           POPUP_ITEM_ID_AUTOCOMPLETE_ENTRY);
    450 }
    451 
    452 }  // namespace autofill
    453