autofill_external_delegate_unittest.cc revision f8ee788a64d60abd8f2d742a5fdedde054ecd910
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 23using base::ASCIIToUTF16; 24using testing::_; 25 26namespace autofill { 27 28namespace { 29 30// A constant value to use as the Autofill query ID. 31const int kQueryId = 5; 32 33// A constant value to use as an Autofill profile ID. 34const int kAutofillProfileId = 1; 35 36class 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 52class 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 75class 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 96class 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. 135TEST_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. 174TEST_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. 234TEST_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 294TEST_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 324TEST_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. 351TEST_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). 365TEST_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. 387TEST_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. 398TEST_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. 409TEST_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 417TEST_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 443TEST_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