autofill_external_delegate_unittest.cc revision a1401311d1ab56c4ed0a474bd38c108f75cb0cd9
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_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 "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 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 76class 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_METHOD5(FillOrPreviewForm, 87 void(AutofillDriver::RendererFormDataAction action, 88 int query_id, 89 const FormData& form, 90 const FormFieldData& field, 91 int unique_id)); 92 93 private: 94 DISALLOW_COPY_AND_ASSIGN(MockAutofillManager); 95}; 96 97} // namespace 98 99class AutofillExternalDelegateUnitTest : public testing::Test { 100 protected: 101 virtual void SetUp() OVERRIDE { 102 autofill_driver_.reset(new MockAutofillDriver()); 103 autofill_manager_.reset( 104 new MockAutofillManager(autofill_driver_.get(), 105 &manager_delegate_)); 106 external_delegate_.reset( 107 new AutofillExternalDelegate( 108 autofill_manager_.get(), autofill_driver_.get())); 109 } 110 111 virtual void TearDown() OVERRIDE { 112 // Order of destruction is important as AutofillManager relies on 113 // PersonalDataManager to be around when it gets destroyed. 114 autofill_manager_.reset(); 115 external_delegate_.reset(); 116 autofill_driver_.reset(); 117 } 118 119 // Issue an OnQuery call with the given |query_id|. 120 void IssueOnQuery(int query_id) { 121 const FormData form; 122 FormFieldData field; 123 field.is_focusable = true; 124 field.should_autocomplete = true; 125 const gfx::RectF element_bounds; 126 127 external_delegate_->OnQuery(query_id, form, field, element_bounds, true); 128 } 129 130 MockAutofillManagerDelegate manager_delegate_; 131 scoped_ptr<MockAutofillDriver> autofill_driver_; 132 scoped_ptr<MockAutofillManager> autofill_manager_; 133 scoped_ptr<AutofillExternalDelegate> external_delegate_; 134 135 base::MessageLoop message_loop_; 136}; 137 138// Test that our external delegate called the virtual methods at the right time. 139TEST_F(AutofillExternalDelegateUnitTest, TestExternalDelegateVirtualCalls) { 140 IssueOnQuery(kQueryId); 141 142 // The enums must be cast to ints to prevent compile errors on linux_rel. 143 EXPECT_CALL( 144 manager_delegate_, 145 ShowAutofillPopup(_, 146 _, 147 _, 148 _, 149 _, 150 testing::ElementsAre( 151 kAutofillProfileId, 152 static_cast<int>(POPUP_ITEM_ID_SEPARATOR), 153 static_cast<int>(POPUP_ITEM_ID_AUTOFILL_OPTIONS)), 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 EXPECT_CALL(*autofill_manager_, 168 FillOrPreviewForm( 169 AutofillDriver::FORM_DATA_ACTION_FILL, _, _, _, _)); 170 EXPECT_CALL(manager_delegate_, HideAutofillPopup()); 171 172 // This should trigger a call to hide the popup since we've selected an 173 // option. 174 external_delegate_->DidAcceptSuggestion(autofill_item[0], autofill_ids[0]); 175} 176 177// Test that data list elements for a node will appear in the Autofill popup. 178TEST_F(AutofillExternalDelegateUnitTest, ExternalDelegateDataList) { 179 IssueOnQuery(kQueryId); 180 181 std::vector<base::string16> data_list_items; 182 data_list_items.push_back(base::string16()); 183 184 external_delegate_->SetCurrentDataListValues(data_list_items, 185 data_list_items); 186 187 // The enums must be cast to ints to prevent compile errors on linux_rel. 188 EXPECT_CALL( 189 manager_delegate_, 190 ShowAutofillPopup(_, 191 _, 192 _, 193 _, 194 _, 195 testing::ElementsAre( 196 static_cast<int>(POPUP_ITEM_ID_DATALIST_ENTRY), 197 static_cast<int>(POPUP_ITEM_ID_SEPARATOR), 198 kAutofillProfileId, 199 static_cast<int>(POPUP_ITEM_ID_SEPARATOR), 200 static_cast<int>(POPUP_ITEM_ID_AUTOFILL_OPTIONS)), 201 _)); 202 203 // This should call ShowAutofillPopup. 204 std::vector<base::string16> autofill_item; 205 autofill_item.push_back(base::string16()); 206 std::vector<int> autofill_ids; 207 autofill_ids.push_back(kAutofillProfileId); 208 external_delegate_->OnSuggestionsReturned(kQueryId, 209 autofill_item, 210 autofill_item, 211 autofill_item, 212 autofill_ids); 213 214 // Try calling OnSuggestionsReturned with no Autofill values and ensure 215 // the datalist items are still shown. 216 // The enum must be cast to an int to prevent compile errors on linux_rel. 217 EXPECT_CALL( 218 manager_delegate_, 219 ShowAutofillPopup( 220 _, 221 _, 222 _, 223 _, 224 _, 225 testing::ElementsAre(static_cast<int>(POPUP_ITEM_ID_DATALIST_ENTRY)), 226 _)); 227 228 autofill_item = std::vector<base::string16>(); 229 autofill_ids = std::vector<int>(); 230 external_delegate_->OnSuggestionsReturned(kQueryId, 231 autofill_item, 232 autofill_item, 233 autofill_item, 234 autofill_ids); 235} 236 237// Test that datalist values can get updated while a popup is showing. 238TEST_F(AutofillExternalDelegateUnitTest, UpdateDataListWhileShowingPopup) { 239 IssueOnQuery(kQueryId); 240 241 EXPECT_CALL(manager_delegate_, 242 ShowAutofillPopup(_, _, _, _, _, _, _)).Times(0); 243 244 // Make sure just setting the data list values doesn't cause the popup to 245 // appear. 246 std::vector<base::string16> data_list_items; 247 data_list_items.push_back(base::string16()); 248 249 external_delegate_->SetCurrentDataListValues(data_list_items, 250 data_list_items); 251 252 // The enums must be cast to ints to prevent compile errors on linux_rel. 253 EXPECT_CALL( 254 manager_delegate_, 255 ShowAutofillPopup(_, 256 _, 257 _, 258 _, 259 _, 260 testing::ElementsAre( 261 static_cast<int>(POPUP_ITEM_ID_DATALIST_ENTRY), 262 static_cast<int>(POPUP_ITEM_ID_SEPARATOR), 263 kAutofillProfileId, 264 static_cast<int>(POPUP_ITEM_ID_SEPARATOR), 265 static_cast<int>(POPUP_ITEM_ID_AUTOFILL_OPTIONS)), 266 _)); 267 268 // Ensure the popup is displayed. 269 std::vector<base::string16> autofill_item; 270 autofill_item.push_back(base::string16()); 271 std::vector<int> autofill_ids; 272 autofill_ids.push_back(kAutofillProfileId); 273 external_delegate_->OnSuggestionsReturned(kQueryId, 274 autofill_item, 275 autofill_item, 276 autofill_item, 277 autofill_ids); 278 279 // This would normally get called from ShowAutofillPopup, but it is mocked so 280 // we need to call OnPopupShown ourselves. 281 external_delegate_->OnPopupShown(); 282 283 // Update the current data list and ensure the popup is updated. 284 data_list_items.push_back(base::string16()); 285 286 // The enums must be cast to ints to prevent compile errors on linux_rel. 287 EXPECT_CALL(manager_delegate_, 288 UpdateAutofillPopupDataListValues(data_list_items, 289 data_list_items)); 290 291 external_delegate_->SetCurrentDataListValues(data_list_items, 292 data_list_items); 293} 294 295// Test that the Autofill popup is able to display warnings explaining why 296// Autofill is disabled for a website. 297// Regression test for http://crbug.com/247880 298TEST_F(AutofillExternalDelegateUnitTest, AutofillWarnings) { 299 IssueOnQuery(kQueryId); 300 301 // The enums must be cast to ints to prevent compile errors on linux_rel. 302 EXPECT_CALL( 303 manager_delegate_, 304 ShowAutofillPopup( 305 _, 306 _, 307 _, 308 _, 309 _, 310 testing::ElementsAre(static_cast<int>(POPUP_ITEM_ID_WARNING_MESSAGE)), 311 _)); 312 313 // This should call ShowAutofillPopup. 314 std::vector<base::string16> autofill_item; 315 autofill_item.push_back(base::string16()); 316 std::vector<int> autofill_ids; 317 autofill_ids.push_back(POPUP_ITEM_ID_WARNING_MESSAGE); 318 external_delegate_->OnSuggestionsReturned(kQueryId, 319 autofill_item, 320 autofill_item, 321 autofill_item, 322 autofill_ids); 323} 324 325// Test that the Autofill popup doesn't display a warning explaining why 326// Autofill is disabled for a website when there are no Autofill suggestions. 327// Regression test for http://crbug.com/105636 328TEST_F(AutofillExternalDelegateUnitTest, NoAutofillWarningsWithoutSuggestions) { 329 const FormData form; 330 FormFieldData field; 331 field.is_focusable = true; 332 field.should_autocomplete = false; 333 const gfx::RectF element_bounds; 334 335 external_delegate_->OnQuery(kQueryId, form, field, element_bounds, true); 336 337 EXPECT_CALL(manager_delegate_, 338 ShowAutofillPopup(_, _, _, _, _, _, _)).Times(0); 339 EXPECT_CALL(manager_delegate_, HideAutofillPopup()).Times(1); 340 341 // This should not call ShowAutofillPopup. 342 std::vector<base::string16> autofill_item; 343 autofill_item.push_back(base::string16()); 344 std::vector<int> autofill_ids; 345 autofill_ids.push_back(POPUP_ITEM_ID_AUTOCOMPLETE_ENTRY); 346 external_delegate_->OnSuggestionsReturned(kQueryId, 347 autofill_item, 348 autofill_item, 349 autofill_item, 350 autofill_ids); 351} 352 353// Test that the Autofill delegate doesn't try and fill a form with a 354// negative unique id. 355TEST_F(AutofillExternalDelegateUnitTest, ExternalDelegateInvalidUniqueId) { 356 // Ensure it doesn't try to preview the negative id. 357 EXPECT_CALL(*autofill_manager_, FillOrPreviewForm(_, _, _, _, _)).Times(0); 358 EXPECT_CALL(*autofill_driver_, RendererShouldClearPreviewedForm()).Times(1); 359 external_delegate_->DidSelectSuggestion(base::string16(), -1); 360 361 // Ensure it doesn't try to fill the form in with the negative id. 362 EXPECT_CALL(manager_delegate_, HideAutofillPopup()); 363 EXPECT_CALL(*autofill_manager_, FillOrPreviewForm(_, _, _, _, _)).Times(0); 364 external_delegate_->DidAcceptSuggestion(base::string16(), -1); 365} 366 367// Test that the ClearPreview call is only sent if the form was being previewed 368// (i.e. it isn't autofilling a password). 369TEST_F(AutofillExternalDelegateUnitTest, ExternalDelegateClearPreviewedForm) { 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(ASCIIToUTF16("baz foo"), 374 POPUP_ITEM_ID_PASSWORD_ENTRY); 375 EXPECT_CALL(*autofill_driver_, RendererShouldClearPreviewedForm()).Times(1); 376 EXPECT_CALL(*autofill_manager_, 377 FillOrPreviewForm( 378 AutofillDriver::FORM_DATA_ACTION_PREVIEW, _, _, _, _)); 379 external_delegate_->DidSelectSuggestion(ASCIIToUTF16("baz foo"), 1); 380 381 // Ensure selecting an autocomplete entry will cause any previews to 382 // get cleared. 383 EXPECT_CALL(*autofill_driver_, RendererShouldClearPreviewedForm()).Times(1); 384 EXPECT_CALL(*autofill_driver_, RendererShouldPreviewFieldWithValue( 385 ASCIIToUTF16("baz foo"))); 386 external_delegate_->DidSelectSuggestion(ASCIIToUTF16("baz foo"), 387 POPUP_ITEM_ID_AUTOCOMPLETE_ENTRY); 388} 389 390// Test that the popup is hidden once we are done editing the autofill field. 391TEST_F(AutofillExternalDelegateUnitTest, 392 ExternalDelegateHidePopupAfterEditing) { 393 EXPECT_CALL(manager_delegate_, ShowAutofillPopup(_, _, _, _, _, _, _)); 394 autofill::GenerateTestAutofillPopup(external_delegate_.get()); 395 396 EXPECT_CALL(manager_delegate_, HideAutofillPopup()); 397 external_delegate_->DidEndTextFieldEditing(); 398} 399 400// Test that the popup is marked as visible after recieving password 401// suggestions. 402TEST_F(AutofillExternalDelegateUnitTest, ExternalDelegatePasswordSuggestions) { 403 static const base::string16 kUsername = ASCIIToUTF16("username"); 404 static const base::string16 kSignonRealm = ASCIIToUTF16("http://foo.com/"); 405 std::vector<base::string16> suggestions; 406 suggestions.push_back(kUsername); 407 std::vector<base::string16> realms; 408 realms.push_back(kSignonRealm); 409 410 FormFieldData field; 411 field.is_focusable = true; 412 field.should_autocomplete = true; 413 const gfx::RectF element_bounds; 414 415 FormFieldData username_field_data; 416 username_field_data.value = kUsername; 417 PasswordFormFillData password_form_fill_data; 418 password_form_fill_data.basic_data.fields.push_back(username_field_data); 419 external_delegate_->AddPasswordFormMapping(field, password_form_fill_data); 420 421 // The enums must be cast to ints to prevent compile errors on linux_rel. 422 EXPECT_CALL( 423 manager_delegate_, 424 ShowAutofillPopup( 425 _, 426 _, 427 _, 428 _, 429 _, 430 testing::ElementsAre(static_cast<int>(POPUP_ITEM_ID_PASSWORD_ENTRY)), 431 _)); 432 433 external_delegate_->OnShowPasswordSuggestions(suggestions, 434 realms, 435 field, 436 element_bounds); 437 438 EXPECT_CALL(manager_delegate_, HideAutofillPopup()); 439 440 // This should trigger a call to hide the popup since 441 // we've selected an option. 442 external_delegate_->DidAcceptSuggestion(suggestions[0], 443 POPUP_ITEM_ID_PASSWORD_ENTRY); 444} 445 446// Test that the driver is directed to accept the data list after being notified 447// that the user accepted the data list suggestion. 448TEST_F(AutofillExternalDelegateUnitTest, ExternalDelegateAcceptSuggestion) { 449 EXPECT_CALL(manager_delegate_, HideAutofillPopup()); 450 base::string16 dummy_string(ASCIIToUTF16("baz qux")); 451 EXPECT_CALL(*autofill_driver_, 452 RendererShouldAcceptDataListSuggestion(dummy_string)); 453 external_delegate_->DidAcceptSuggestion(dummy_string, 454 POPUP_ITEM_ID_DATALIST_ENTRY); 455} 456 457// Test that the driver is directed to clear the form after being notified that 458// the user accepted the suggestion to clear the form. 459TEST_F(AutofillExternalDelegateUnitTest, ExternalDelegateClearForm) { 460 EXPECT_CALL(manager_delegate_, HideAutofillPopup()); 461 EXPECT_CALL(*autofill_driver_, RendererShouldClearFilledForm()); 462 463 external_delegate_->DidAcceptSuggestion(base::string16(), 464 POPUP_ITEM_ID_CLEAR_FORM); 465} 466 467TEST_F(AutofillExternalDelegateUnitTest, ExternalDelegateHideWarning) { 468 // Set up a field that shouldn't get autocompleted or display warnings. 469 const FormData form; 470 FormFieldData field; 471 field.is_focusable = true; 472 field.should_autocomplete = false; 473 const gfx::RectF element_bounds; 474 475 external_delegate_->OnQuery(kQueryId, form, field, element_bounds, false); 476 477 std::vector<base::string16> autofill_items; 478 autofill_items.push_back(base::string16()); 479 std::vector<int> autofill_ids; 480 autofill_ids.push_back(POPUP_ITEM_ID_AUTOCOMPLETE_ENTRY); 481 482 // Ensure the popup tries to hide itself, since it is not allowed to show 483 // anything. 484 EXPECT_CALL(manager_delegate_, HideAutofillPopup()); 485 486 external_delegate_->OnSuggestionsReturned(kQueryId, 487 autofill_items, 488 autofill_items, 489 autofill_items, 490 autofill_ids); 491} 492 493TEST_F(AutofillExternalDelegateUnitTest, ExternalDelegateFillFieldWithValue) { 494 EXPECT_CALL(manager_delegate_, HideAutofillPopup()); 495 base::string16 dummy_string(ASCIIToUTF16("baz foo")); 496 EXPECT_CALL(*autofill_driver_, 497 RendererShouldFillFieldWithValue(dummy_string)); 498 external_delegate_->DidAcceptSuggestion(dummy_string, 499 POPUP_ITEM_ID_AUTOCOMPLETE_ENTRY); 500} 501 502} // namespace autofill 503