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