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