• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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:
MockAutofillDriver()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:
MockAutofillClient()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:
MockAutofillManager(AutofillDriver * driver,MockAutofillClient * client)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) {}
~MockAutofillManager()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:
SetUp()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 
TearDown()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|.
IssueOnQuery(int 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.
TEST_F(AutofillExternalDelegateUnitTest,TestExternalDelegateVirtualCalls)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.
TEST_F(AutofillExternalDelegateUnitTest,ExternalDelegateDataList)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.
TEST_F(AutofillExternalDelegateUnitTest,UpdateDataListWhileShowingPopup)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
TEST_F(AutofillExternalDelegateUnitTest,AutofillWarnings)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
TEST_F(AutofillExternalDelegateUnitTest,NoAutofillWarningsWithoutSuggestions)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.
TEST_F(AutofillExternalDelegateUnitTest,ExternalDelegateInvalidUniqueId)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).
TEST_F(AutofillExternalDelegateUnitTest,ExternalDelegateClearPreviewedForm)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.
TEST_F(AutofillExternalDelegateUnitTest,ExternalDelegateHidePopupAfterEditing)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.
TEST_F(AutofillExternalDelegateUnitTest,ExternalDelegateAcceptSuggestion)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.
TEST_F(AutofillExternalDelegateUnitTest,ExternalDelegateClearForm)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 
TEST_F(AutofillExternalDelegateUnitTest,ExternalDelegateHideWarning)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 
TEST_F(AutofillExternalDelegateUnitTest,ExternalDelegateFillFieldWithValue)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