autofill_external_delegate_unittest.cc revision 0f1bc08d4cfcc34181b0b5cbf065c40f687bf740
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
24using testing::_;
25using WebKit::WebAutofillClient;
26
27namespace autofill {
28
29namespace {
30
31// A constant value to use as the Autofill query ID.
32const int kQueryId = 5;
33
34// A constant value to use as an Autofill profile ID.
35const int kAutofillProfileId = 1;
36
37class 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
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_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
98class 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.
142TEST_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.
181TEST_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.
236TEST_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 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(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
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(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
321TEST_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.
348TEST_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).
366TEST_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.
383TEST_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.
394TEST_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.
438TEST_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
447TEST_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