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