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 "base/compiler_specific.h"
6#include "base/message_loop/message_loop.h"
7#include "base/strings/utf_string_conversions.h"
8#include "components/autofill/core/browser/popup_item_ids.h"
9#include "components/autofill/core/browser/test_autofill_client.h"
10#include "components/autofill/core/browser/test_autofill_driver.h"
11#include "components/password_manager/core/browser/password_autofill_manager.h"
12#include "components/password_manager/core/browser/stub_password_manager_client.h"
13#include "components/password_manager/core/browser/stub_password_manager_driver.h"
14#include "testing/gmock/include/gmock/gmock.h"
15#include "testing/gtest/include/gtest/gtest.h"
16#include "ui/gfx/geometry/rect_f.h"
17
18// The name of the username/password element in the form.
19const char kUsernameName[] = "username";
20const char kInvalidUsername[] = "no-username";
21const char kPasswordName[] = "password";
22
23const char kAliceUsername[] = "alice";
24const char kAlicePassword[] = "password";
25
26using testing::_;
27
28namespace autofill {
29class AutofillPopupDelegate;
30}
31
32namespace password_manager {
33
34namespace {
35
36class MockPasswordManagerDriver : public StubPasswordManagerDriver {
37 public:
38  MOCK_METHOD2(FillSuggestion,
39               void(const base::string16&, const base::string16&));
40  MOCK_METHOD2(PreviewSuggestion,
41               void(const base::string16&, const base::string16&));
42};
43
44class TestPasswordManagerClient : public StubPasswordManagerClient {
45 public:
46  virtual PasswordManagerDriver* GetDriver() OVERRIDE { return &driver_; }
47
48  MockPasswordManagerDriver* mock_driver() { return &driver_; }
49
50 private:
51  MockPasswordManagerDriver driver_;
52};
53
54class MockAutofillClient : public autofill::TestAutofillClient {
55 public:
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<autofill::AutofillPopupDelegate> delegate));
64  MOCK_METHOD0(HideAutofillPopup, void());
65};
66
67}  // namespace
68
69class PasswordAutofillManagerTest : public testing::Test {
70 protected:
71  PasswordAutofillManagerTest()
72      : test_username_(base::ASCIIToUTF16(kAliceUsername)),
73        test_password_(base::ASCIIToUTF16(kAlicePassword)) {}
74
75  virtual void SetUp() OVERRIDE {
76    // Add a preferred login and an additional login to the FillData.
77    username_field_.name = base::ASCIIToUTF16(kUsernameName);
78    username_field_.value = test_username_;
79    fill_data_.basic_data.fields.push_back(username_field_);
80
81    autofill::FormFieldData password_field;
82    password_field.name = base::ASCIIToUTF16(kPasswordName);
83    password_field.value = test_password_;
84    fill_data_.basic_data.fields.push_back(password_field);
85  }
86
87  void InitializePasswordAutofillManager(
88      PasswordManagerClient* client,
89      autofill::AutofillClient* autofill_client) {
90    password_autofill_manager_.reset(
91        new PasswordAutofillManager(client, autofill_client));
92    password_autofill_manager_->OnAddPasswordFormMapping(username_field_,
93                                                         fill_data_);
94  }
95
96 protected:
97  scoped_ptr<PasswordAutofillManager> password_autofill_manager_;
98
99  autofill::FormFieldData username_field_;
100  base::string16 test_username_;
101  base::string16 test_password_;
102
103 private:
104  autofill::PasswordFormFillData fill_data_;
105
106  // The TestAutofillDriver uses a SequencedWorkerPool which expects the
107  // existence of a MessageLoop.
108  base::MessageLoop message_loop_;
109};
110
111TEST_F(PasswordAutofillManagerTest, FillSuggestion) {
112  scoped_ptr<TestPasswordManagerClient> client(new TestPasswordManagerClient);
113  InitializePasswordAutofillManager(client.get(), NULL);
114
115  EXPECT_CALL(*client->mock_driver(),
116              FillSuggestion(test_username_, test_password_));
117  EXPECT_TRUE(password_autofill_manager_->FillSuggestionForTest(
118      username_field_, test_username_));
119  testing::Mock::VerifyAndClearExpectations(client->mock_driver());
120
121  EXPECT_CALL(*client->mock_driver(),
122              FillSuggestion(_, _)).Times(0);
123  EXPECT_FALSE(password_autofill_manager_->FillSuggestionForTest(
124      username_field_, base::ASCIIToUTF16(kInvalidUsername)));
125
126  autofill::FormFieldData invalid_username_field;
127  invalid_username_field.name = base::ASCIIToUTF16(kInvalidUsername);
128
129  EXPECT_FALSE(password_autofill_manager_->FillSuggestionForTest(
130      invalid_username_field, test_username_));
131
132  password_autofill_manager_->Reset();
133  EXPECT_FALSE(password_autofill_manager_->FillSuggestionForTest(
134      username_field_, test_username_));
135}
136
137TEST_F(PasswordAutofillManagerTest, PreviewSuggestion) {
138  scoped_ptr<TestPasswordManagerClient> client(new TestPasswordManagerClient);
139  InitializePasswordAutofillManager(client.get(), NULL);
140
141  EXPECT_CALL(*client->mock_driver(),
142              PreviewSuggestion(test_username_, test_password_));
143  EXPECT_TRUE(password_autofill_manager_->PreviewSuggestionForTest(
144      username_field_, test_username_));
145  testing::Mock::VerifyAndClearExpectations(client->mock_driver());
146
147  EXPECT_CALL(*client->mock_driver(), PreviewSuggestion(_, _)).Times(0);
148  EXPECT_FALSE(password_autofill_manager_->PreviewSuggestionForTest(
149      username_field_, base::ASCIIToUTF16(kInvalidUsername)));
150
151  autofill::FormFieldData invalid_username_field;
152  invalid_username_field.name = base::ASCIIToUTF16(kInvalidUsername);
153
154  EXPECT_FALSE(password_autofill_manager_->PreviewSuggestionForTest(
155      invalid_username_field, test_username_));
156
157  password_autofill_manager_->Reset();
158  EXPECT_FALSE(password_autofill_manager_->PreviewSuggestionForTest(
159      username_field_, test_username_));
160}
161
162// Test that the popup is marked as visible after recieving password
163// suggestions.
164TEST_F(PasswordAutofillManagerTest, ExternalDelegatePasswordSuggestions) {
165  scoped_ptr<TestPasswordManagerClient> client(new TestPasswordManagerClient);
166  scoped_ptr<MockAutofillClient> autofill_client(new MockAutofillClient);
167  InitializePasswordAutofillManager(client.get(), autofill_client.get());
168
169  gfx::RectF element_bounds;
170  std::vector<base::string16> suggestions;
171  suggestions.push_back(test_username_);
172  std::vector<base::string16> realms;
173  realms.push_back(base::ASCIIToUTF16("http://foo.com/"));
174
175  // The enums must be cast to ints to prevent compile errors on linux_rel.
176  EXPECT_CALL(*autofill_client,
177              ShowAutofillPopup(
178                  _,
179                  _,
180                  _,
181                  _,
182                  _,
183                  testing::ElementsAre(autofill::POPUP_ITEM_ID_PASSWORD_ENTRY),
184                  _));
185  password_autofill_manager_->OnShowPasswordSuggestions(
186      username_field_, element_bounds, suggestions, realms);
187
188  // Accepting a suggestion should trigger a call to hide the popup.
189  EXPECT_CALL(*autofill_client, HideAutofillPopup());
190  password_autofill_manager_->DidAcceptSuggestion(
191      suggestions[0], autofill::POPUP_ITEM_ID_PASSWORD_ENTRY);
192}
193
194}  // namespace password_manager
195