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