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 EXPECT_CALL( 181 autofill_client_, 182 UpdateAutofillPopupDataListValues(data_list_items, data_list_items)); 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 autofill_client_, 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 autofill_client_, 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(autofill_client_, ShowAutofillPopup(_, _, _, _, _, _, _)) 242 .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 EXPECT_CALL( 250 autofill_client_, 251 UpdateAutofillPopupDataListValues(data_list_items, data_list_items)); 252 253 external_delegate_->SetCurrentDataListValues(data_list_items, 254 data_list_items); 255 256 // The enums must be cast to ints to prevent compile errors on linux_rel. 257 EXPECT_CALL( 258 autofill_client_, 259 ShowAutofillPopup(_, 260 _, 261 _, 262 _, 263 _, 264 testing::ElementsAre( 265 static_cast<int>(POPUP_ITEM_ID_DATALIST_ENTRY), 266 static_cast<int>(POPUP_ITEM_ID_SEPARATOR), 267 kAutofillProfileId, 268 static_cast<int>(POPUP_ITEM_ID_SEPARATOR), 269 static_cast<int>(POPUP_ITEM_ID_AUTOFILL_OPTIONS)), 270 _)); 271 272 // Ensure the popup is displayed. 273 std::vector<base::string16> autofill_item; 274 autofill_item.push_back(base::string16()); 275 std::vector<int> autofill_ids; 276 autofill_ids.push_back(kAutofillProfileId); 277 external_delegate_->OnSuggestionsReturned(kQueryId, 278 autofill_item, 279 autofill_item, 280 autofill_item, 281 autofill_ids); 282 283 // This would normally get called from ShowAutofillPopup, but it is mocked so 284 // we need to call OnPopupShown ourselves. 285 external_delegate_->OnPopupShown(); 286 287 // Update the current data list and ensure the popup is updated. 288 data_list_items.push_back(base::string16()); 289 290 // The enums must be cast to ints to prevent compile errors on linux_rel. 291 EXPECT_CALL( 292 autofill_client_, 293 UpdateAutofillPopupDataListValues(data_list_items, data_list_items)); 294 295 external_delegate_->SetCurrentDataListValues(data_list_items, 296 data_list_items); 297} 298 299// Test that the Autofill popup is able to display warnings explaining why 300// Autofill is disabled for a website. 301// Regression test for http://crbug.com/247880 302TEST_F(AutofillExternalDelegateUnitTest, AutofillWarnings) { 303 IssueOnQuery(kQueryId); 304 305 // The enums must be cast to ints to prevent compile errors on linux_rel. 306 EXPECT_CALL( 307 autofill_client_, 308 ShowAutofillPopup( 309 _, 310 _, 311 _, 312 _, 313 _, 314 testing::ElementsAre(static_cast<int>(POPUP_ITEM_ID_WARNING_MESSAGE)), 315 _)); 316 317 // This should call ShowAutofillPopup. 318 std::vector<base::string16> autofill_item; 319 autofill_item.push_back(base::string16()); 320 std::vector<int> autofill_ids; 321 autofill_ids.push_back(POPUP_ITEM_ID_WARNING_MESSAGE); 322 external_delegate_->OnSuggestionsReturned(kQueryId, 323 autofill_item, 324 autofill_item, 325 autofill_item, 326 autofill_ids); 327} 328 329// Test that the Autofill popup doesn't display a warning explaining why 330// Autofill is disabled for a website when there are no Autofill suggestions. 331// Regression test for http://crbug.com/105636 332TEST_F(AutofillExternalDelegateUnitTest, NoAutofillWarningsWithoutSuggestions) { 333 const FormData form; 334 FormFieldData field; 335 field.is_focusable = true; 336 field.should_autocomplete = false; 337 const gfx::RectF element_bounds; 338 339 external_delegate_->OnQuery(kQueryId, form, field, element_bounds, true); 340 341 EXPECT_CALL(autofill_client_, ShowAutofillPopup(_, _, _, _, _, _, _)) 342 .Times(0); 343 EXPECT_CALL(autofill_client_, HideAutofillPopup()).Times(1); 344 345 // This should not call ShowAutofillPopup. 346 std::vector<base::string16> autofill_item; 347 autofill_item.push_back(base::string16()); 348 std::vector<int> autofill_ids; 349 autofill_ids.push_back(POPUP_ITEM_ID_AUTOCOMPLETE_ENTRY); 350 external_delegate_->OnSuggestionsReturned(kQueryId, 351 autofill_item, 352 autofill_item, 353 autofill_item, 354 autofill_ids); 355} 356 357// Test that the Autofill delegate doesn't try and fill a form with a 358// negative unique id. 359TEST_F(AutofillExternalDelegateUnitTest, ExternalDelegateInvalidUniqueId) { 360 // Ensure it doesn't try to preview the negative id. 361 EXPECT_CALL(*autofill_manager_, FillOrPreviewForm(_, _, _, _, _)).Times(0); 362 EXPECT_CALL(*autofill_driver_, RendererShouldClearPreviewedForm()).Times(1); 363 external_delegate_->DidSelectSuggestion(base::string16(), -1); 364 365 // Ensure it doesn't try to fill the form in with the negative id. 366 EXPECT_CALL(autofill_client_, HideAutofillPopup()); 367 EXPECT_CALL(*autofill_manager_, FillOrPreviewForm(_, _, _, _, _)).Times(0); 368 external_delegate_->DidAcceptSuggestion(base::string16(), -1); 369} 370 371// Test that the ClearPreview call is only sent if the form was being previewed 372// (i.e. it isn't autofilling a password). 373TEST_F(AutofillExternalDelegateUnitTest, ExternalDelegateClearPreviewedForm) { 374 // Ensure selecting a new password entries or Autofill entries will 375 // cause any previews to get cleared. 376 EXPECT_CALL(*autofill_driver_, RendererShouldClearPreviewedForm()).Times(1); 377 external_delegate_->DidSelectSuggestion(ASCIIToUTF16("baz foo"), 378 POPUP_ITEM_ID_PASSWORD_ENTRY); 379 EXPECT_CALL(*autofill_driver_, RendererShouldClearPreviewedForm()).Times(1); 380 EXPECT_CALL(*autofill_manager_, 381 FillOrPreviewForm( 382 AutofillDriver::FORM_DATA_ACTION_PREVIEW, _, _, _, _)); 383 external_delegate_->DidSelectSuggestion(ASCIIToUTF16("baz foo"), 1); 384 385 // Ensure selecting an autocomplete entry will cause any previews to 386 // get cleared. 387 EXPECT_CALL(*autofill_driver_, RendererShouldClearPreviewedForm()).Times(1); 388 EXPECT_CALL(*autofill_driver_, RendererShouldPreviewFieldWithValue( 389 ASCIIToUTF16("baz foo"))); 390 external_delegate_->DidSelectSuggestion(ASCIIToUTF16("baz foo"), 391 POPUP_ITEM_ID_AUTOCOMPLETE_ENTRY); 392} 393 394// Test that the popup is hidden once we are done editing the autofill field. 395TEST_F(AutofillExternalDelegateUnitTest, 396 ExternalDelegateHidePopupAfterEditing) { 397 EXPECT_CALL(autofill_client_, ShowAutofillPopup(_, _, _, _, _, _, _)); 398 autofill::GenerateTestAutofillPopup(external_delegate_.get()); 399 400 EXPECT_CALL(autofill_client_, HideAutofillPopup()); 401 external_delegate_->DidEndTextFieldEditing(); 402} 403 404// Test that the driver is directed to accept the data list after being notified 405// that the user accepted the data list suggestion. 406TEST_F(AutofillExternalDelegateUnitTest, ExternalDelegateAcceptSuggestion) { 407 EXPECT_CALL(autofill_client_, HideAutofillPopup()); 408 base::string16 dummy_string(ASCIIToUTF16("baz qux")); 409 EXPECT_CALL(*autofill_driver_, 410 RendererShouldAcceptDataListSuggestion(dummy_string)); 411 external_delegate_->DidAcceptSuggestion(dummy_string, 412 POPUP_ITEM_ID_DATALIST_ENTRY); 413} 414 415// Test that the driver is directed to clear the form after being notified that 416// the user accepted the suggestion to clear the form. 417TEST_F(AutofillExternalDelegateUnitTest, ExternalDelegateClearForm) { 418 EXPECT_CALL(autofill_client_, HideAutofillPopup()); 419 EXPECT_CALL(*autofill_driver_, RendererShouldClearFilledForm()); 420 421 external_delegate_->DidAcceptSuggestion(base::string16(), 422 POPUP_ITEM_ID_CLEAR_FORM); 423} 424 425TEST_F(AutofillExternalDelegateUnitTest, ExternalDelegateHideWarning) { 426 // Set up a field that shouldn't get autocompleted or display warnings. 427 const FormData form; 428 FormFieldData field; 429 field.is_focusable = true; 430 field.should_autocomplete = false; 431 const gfx::RectF element_bounds; 432 433 external_delegate_->OnQuery(kQueryId, form, field, element_bounds, false); 434 435 std::vector<base::string16> autofill_items; 436 autofill_items.push_back(base::string16()); 437 std::vector<int> autofill_ids; 438 autofill_ids.push_back(POPUP_ITEM_ID_AUTOCOMPLETE_ENTRY); 439 440 // Ensure the popup tries to hide itself, since it is not allowed to show 441 // anything. 442 EXPECT_CALL(autofill_client_, HideAutofillPopup()); 443 444 external_delegate_->OnSuggestionsReturned(kQueryId, 445 autofill_items, 446 autofill_items, 447 autofill_items, 448 autofill_ids); 449} 450 451TEST_F(AutofillExternalDelegateUnitTest, ExternalDelegateFillFieldWithValue) { 452 EXPECT_CALL(autofill_client_, HideAutofillPopup()); 453 base::string16 dummy_string(ASCIIToUTF16("baz foo")); 454 EXPECT_CALL(*autofill_driver_, 455 RendererShouldFillFieldWithValue(dummy_string)); 456 external_delegate_->DidAcceptSuggestion(dummy_string, 457 POPUP_ITEM_ID_AUTOCOMPLETE_ENTRY); 458} 459 460} // namespace autofill 461