OLD | NEW |
| (Empty) |
1 // Copyright (c) 2012 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/message_loop/message_loop.h" | |
8 #include "base/strings/string_util.h" | |
9 #include "base/strings/utf_string_conversions.h" | |
10 #include "chrome/common/url_constants.h" | |
11 #include "chrome/test/base/chrome_render_view_host_test_harness.h" | |
12 #include "chrome/test/base/testing_pref_service_syncable.h" | |
13 #include "chrome/test/base/testing_profile.h" | |
14 #include "components/password_manager/core/browser/mock_password_store.h" | |
15 #include "components/password_manager/core/browser/password_manager.h" | |
16 #include "components/password_manager/core/browser/password_manager_client.h" | |
17 #include "components/password_manager/core/browser/password_manager_driver.h" | |
18 #include "components/password_manager/core/browser/password_store.h" | |
19 #include "components/password_manager/core/common/password_manager_pref_names.h" | |
20 #include "testing/gmock/include/gmock/gmock.h" | |
21 #include "testing/gtest/include/gtest/gtest.h" | |
22 | |
23 class PasswordGenerationManager; | |
24 | |
25 using autofill::PasswordForm; | |
26 using base::ASCIIToUTF16; | |
27 using testing::_; | |
28 using testing::AnyNumber; | |
29 using testing::DoAll; | |
30 using testing::Exactly; | |
31 using testing::Return; | |
32 using testing::WithArg; | |
33 | |
34 namespace autofill { | |
35 class AutofillManager; | |
36 } | |
37 | |
38 namespace { | |
39 | |
40 class MockPasswordManagerClient : public PasswordManagerClient { | |
41 public: | |
42 MOCK_METHOD1(PromptUserToSavePassword, void(PasswordFormManager*)); | |
43 MOCK_METHOD0(GetProfile, Profile*()); | |
44 MOCK_METHOD0(GetPasswordStore, PasswordStore*()); | |
45 MOCK_METHOD0(GetPrefs, PrefService*()); | |
46 MOCK_METHOD0(GetDriver, PasswordManagerDriver*()); | |
47 MOCK_METHOD1(GetProbabilityForExperiment, | |
48 base::FieldTrial::Probability(const std::string&)); | |
49 | |
50 // The following is required because GMock does not support move-only | |
51 // parameters. | |
52 MOCK_METHOD1(AuthenticateAutofillAndFillFormPtr, | |
53 void(autofill::PasswordFormFillData* fill_data)); | |
54 virtual void AuthenticateAutofillAndFillForm( | |
55 scoped_ptr<autofill::PasswordFormFillData> fill_data) OVERRIDE { | |
56 return AuthenticateAutofillAndFillFormPtr(fill_data.release()); | |
57 } | |
58 }; | |
59 | |
60 class MockPasswordManagerDriver : public PasswordManagerDriver { | |
61 public: | |
62 MOCK_METHOD1(FillPasswordForm, void(const autofill::PasswordFormFillData&)); | |
63 MOCK_METHOD0(DidLastPageLoadEncounterSSLErrors, bool()); | |
64 MOCK_METHOD0(IsOffTheRecord, bool()); | |
65 MOCK_METHOD0(GetPasswordGenerationManager, PasswordGenerationManager*()); | |
66 MOCK_METHOD0(GetPasswordManager, PasswordManager*()); | |
67 MOCK_METHOD0(GetAutofillManager, autofill::AutofillManager*()); | |
68 MOCK_METHOD1(AllowPasswordGenerationForForm, void(autofill::PasswordForm*)); | |
69 MOCK_METHOD1(AccountCreationFormsFound, | |
70 void(const std::vector<autofill::FormData>&)); | |
71 }; | |
72 | |
73 ACTION_P(InvokeConsumer, forms) { | |
74 arg0->OnGetPasswordStoreResults(forms); | |
75 } | |
76 | |
77 ACTION_P(SaveToScopedPtr, scoped) { | |
78 scoped->reset(arg0); | |
79 } | |
80 | |
81 class TestPasswordManager : public PasswordManager { | |
82 public: | |
83 explicit TestPasswordManager(PasswordManagerClient* client) | |
84 : PasswordManager(client) {} | |
85 virtual ~TestPasswordManager() {} | |
86 | |
87 virtual void OnPasswordFormSubmitted(const PasswordForm& form) OVERRIDE { | |
88 PasswordManager::OnPasswordFormSubmitted(form); | |
89 } | |
90 | |
91 private: | |
92 DISALLOW_COPY_AND_ASSIGN(TestPasswordManager); | |
93 }; | |
94 | |
95 } // namespace | |
96 | |
97 class PasswordManagerTest : public ChromeRenderViewHostTestHarness { | |
98 protected: | |
99 virtual void SetUp() { | |
100 ChromeRenderViewHostTestHarness::SetUp(); | |
101 store_ = new MockPasswordStore; | |
102 CHECK(store_->Init()); | |
103 | |
104 EXPECT_CALL(client_, GetPasswordStore()).WillRepeatedly(Return(store_)); | |
105 EXPECT_CALL(client_, GetPrefs()) | |
106 .WillRepeatedly(Return(profile()->GetTestingPrefService())); | |
107 EXPECT_CALL(client_, GetDriver()).WillRepeatedly(Return(&driver_)); | |
108 | |
109 manager_.reset(new TestPasswordManager(&client_)); | |
110 | |
111 EXPECT_CALL(driver_, DidLastPageLoadEncounterSSLErrors()) | |
112 .WillRepeatedly(Return(false)); | |
113 EXPECT_CALL(driver_, IsOffTheRecord()).WillRepeatedly(Return(false)); | |
114 EXPECT_CALL(driver_, GetPasswordGenerationManager()) | |
115 .WillRepeatedly(Return(static_cast<PasswordGenerationManager*>(NULL))); | |
116 EXPECT_CALL(driver_, GetPasswordManager()) | |
117 .WillRepeatedly(Return(manager_.get())); | |
118 EXPECT_CALL(driver_, AllowPasswordGenerationForForm(_)).Times(AnyNumber()); | |
119 | |
120 EXPECT_CALL(*store_, ReportMetricsImpl()).Times(AnyNumber()); | |
121 } | |
122 | |
123 virtual void TearDown() { | |
124 store_->Shutdown(); | |
125 store_ = NULL; | |
126 | |
127 // Destroy the PasswordManager before tearing down the Profile to avoid | |
128 // crashes due to prefs accesses. | |
129 manager_.reset(); | |
130 ChromeRenderViewHostTestHarness::TearDown(); | |
131 } | |
132 | |
133 PasswordForm MakeSimpleForm() { | |
134 PasswordForm form; | |
135 form.origin = GURL("http://www.google.com/a/LoginAuth"); | |
136 form.action = GURL("http://www.google.com/a/Login"); | |
137 form.username_element = ASCIIToUTF16("Email"); | |
138 form.password_element = ASCIIToUTF16("Passwd"); | |
139 form.username_value = ASCIIToUTF16("google"); | |
140 form.password_value = ASCIIToUTF16("password"); | |
141 // Default to true so we only need to add tests in autocomplete=off cases. | |
142 form.password_autocomplete_set = true; | |
143 form.submit_element = ASCIIToUTF16("signIn"); | |
144 form.signon_realm = "http://www.google.com"; | |
145 return form; | |
146 } | |
147 | |
148 // Reproduction of the form present on twitter's login page. | |
149 PasswordForm MakeTwitterLoginForm() { | |
150 PasswordForm form; | |
151 form.origin = GURL("https://twitter.com/"); | |
152 form.action = GURL("https://twitter.com/sessions"); | |
153 form.username_element = ASCIIToUTF16("Email"); | |
154 form.password_element = ASCIIToUTF16("Passwd"); | |
155 form.username_value = ASCIIToUTF16("twitter"); | |
156 form.password_value = ASCIIToUTF16("password"); | |
157 form.password_autocomplete_set = true; | |
158 form.submit_element = ASCIIToUTF16("signIn"); | |
159 form.signon_realm = "https://twitter.com"; | |
160 return form; | |
161 } | |
162 | |
163 // Reproduction of the form present on twitter's failed login page. | |
164 PasswordForm MakeTwitterFailedLoginForm() { | |
165 PasswordForm form; | |
166 form.origin = | |
167 GURL("https://twitter.com/login/error?redirect_after_login"); | |
168 form.action = GURL("https://twitter.com/sessions"); | |
169 form.username_element = ASCIIToUTF16("EmailField"); | |
170 form.password_element = ASCIIToUTF16("PasswdField"); | |
171 form.username_value = ASCIIToUTF16("twitter"); | |
172 form.password_value = ASCIIToUTF16("password"); | |
173 form.password_autocomplete_set = true; | |
174 form.submit_element = ASCIIToUTF16("signIn"); | |
175 form.signon_realm = "https://twitter.com"; | |
176 return form; | |
177 } | |
178 | |
179 bool FormsAreEqual(const autofill::PasswordForm& lhs, | |
180 const autofill::PasswordForm& rhs) { | |
181 if (lhs.origin != rhs.origin) | |
182 return false; | |
183 if (lhs.action != rhs.action) | |
184 return false; | |
185 if (lhs.username_element != rhs.username_element) | |
186 return false; | |
187 if (lhs.password_element != rhs.password_element) | |
188 return false; | |
189 if (lhs.username_value != rhs.username_value) | |
190 return false; | |
191 if (lhs.password_value != rhs.password_value) | |
192 return false; | |
193 if (lhs.password_autocomplete_set != rhs.password_autocomplete_set) | |
194 return false; | |
195 if (lhs.submit_element != rhs.submit_element) | |
196 return false; | |
197 if (lhs.signon_realm != rhs.signon_realm) | |
198 return false; | |
199 return true; | |
200 } | |
201 | |
202 TestPasswordManager* manager() { return manager_.get(); } | |
203 | |
204 void OnPasswordFormSubmitted(const autofill::PasswordForm& form) { | |
205 manager()->OnPasswordFormSubmitted(form); | |
206 } | |
207 | |
208 PasswordManager::PasswordSubmittedCallback SubmissionCallback() { | |
209 return base::Bind(&PasswordManagerTest::FormSubmitted, | |
210 base::Unretained(this)); | |
211 } | |
212 | |
213 void FormSubmitted(const autofill::PasswordForm& form) { | |
214 submitted_form_ = form; | |
215 } | |
216 | |
217 scoped_refptr<MockPasswordStore> store_; | |
218 MockPasswordManagerClient client_; | |
219 MockPasswordManagerDriver driver_; | |
220 scoped_ptr<TestPasswordManager> manager_; | |
221 PasswordForm submitted_form_; | |
222 }; | |
223 | |
224 MATCHER_P(FormMatches, form, "") { | |
225 return form.signon_realm == arg.signon_realm && | |
226 form.origin == arg.origin && | |
227 form.action == arg.action && | |
228 form.username_element == arg.username_element && | |
229 form.password_element == arg.password_element && | |
230 form.password_autocomplete_set == | |
231 arg.password_autocomplete_set && | |
232 form.submit_element == arg.submit_element; | |
233 } | |
234 | |
235 TEST_F(PasswordManagerTest, FormSubmitEmptyStore) { | |
236 // Test that observing a newly submitted form shows the save password bar. | |
237 std::vector<PasswordForm*> result; // Empty password store. | |
238 EXPECT_CALL(driver_, FillPasswordForm(_)).Times(Exactly(0)); | |
239 EXPECT_CALL(*store_.get(), GetLogins(_, _, _)) | |
240 .WillOnce(DoAll(WithArg<2>(InvokeConsumer(result)), Return())); | |
241 std::vector<PasswordForm> observed; | |
242 PasswordForm form(MakeSimpleForm()); | |
243 observed.push_back(form); | |
244 manager()->OnPasswordFormsParsed(observed); // The initial load. | |
245 manager()->OnPasswordFormsRendered(observed); // The initial layout. | |
246 | |
247 // And the form submit contract is to call ProvisionallySavePassword. | |
248 manager()->ProvisionallySavePassword(form); | |
249 | |
250 scoped_ptr<PasswordFormManager> form_to_save; | |
251 EXPECT_CALL(client_, PromptUserToSavePassword(_)) | |
252 .WillOnce(WithArg<0>(SaveToScopedPtr(&form_to_save))); | |
253 | |
254 // Now the password manager waits for the navigation to complete. | |
255 observed.clear(); | |
256 manager()->OnPasswordFormsParsed(observed); // The post-navigation load. | |
257 manager()->OnPasswordFormsRendered(observed); // The post-navigation layout. | |
258 | |
259 ASSERT_TRUE(form_to_save.get()); | |
260 EXPECT_CALL(*store_.get(), AddLogin(FormMatches(form))); | |
261 | |
262 // Simulate saving the form, as if the info bar was accepted. | |
263 form_to_save->Save(); | |
264 } | |
265 | |
266 TEST_F(PasswordManagerTest, GeneratedPasswordFormSubmitEmptyStore) { | |
267 // This test is the same FormSubmitEmptyStore, except that it simulates the | |
268 // user generating the password through the browser. | |
269 std::vector<PasswordForm*> result; // Empty password store. | |
270 EXPECT_CALL(driver_, FillPasswordForm(_)).Times(Exactly(0)); | |
271 EXPECT_CALL(*store_.get(), GetLogins(_, _, _)) | |
272 .WillOnce(DoAll(WithArg<2>(InvokeConsumer(result)), Return())); | |
273 std::vector<PasswordForm> observed; | |
274 PasswordForm form(MakeSimpleForm()); | |
275 observed.push_back(form); | |
276 manager()->OnPasswordFormsParsed(observed); // The initial load. | |
277 manager()->OnPasswordFormsRendered(observed); // The initial layout. | |
278 | |
279 // Simulate the user generating the password and submitting the form. | |
280 manager()->SetFormHasGeneratedPassword(form); | |
281 manager()->ProvisionallySavePassword(form); | |
282 | |
283 // The user should not be presented with an infobar as they have already given | |
284 // consent by using the generated password. The form should be saved once | |
285 // navigation occurs. | |
286 EXPECT_CALL(client_, PromptUserToSavePassword(_)).Times(Exactly(0)); | |
287 EXPECT_CALL(*store_.get(), AddLogin(FormMatches(form))); | |
288 | |
289 // Now the password manager waits for the navigation to complete. | |
290 observed.clear(); | |
291 manager()->OnPasswordFormsParsed(observed); // The post-navigation load. | |
292 manager()->OnPasswordFormsRendered(observed); // The post-navigation layout. | |
293 } | |
294 | |
295 TEST_F(PasswordManagerTest, FormSubmitNoGoodMatch) { | |
296 // Same as above, except with an existing form for the same signon realm, | |
297 // but different origin. Detailed cases like this are covered by | |
298 // PasswordFormManagerTest. | |
299 std::vector<PasswordForm*> result; | |
300 PasswordForm* existing_different = new PasswordForm(MakeSimpleForm()); | |
301 existing_different->username_value = ASCIIToUTF16("google2"); | |
302 result.push_back(existing_different); | |
303 EXPECT_CALL(driver_, FillPasswordForm(_)); | |
304 EXPECT_CALL(*store_.get(), GetLogins(_, _, _)) | |
305 .WillOnce(DoAll(WithArg<2>(InvokeConsumer(result)), Return())); | |
306 | |
307 std::vector<PasswordForm> observed; | |
308 PasswordForm form(MakeSimpleForm()); | |
309 observed.push_back(form); | |
310 manager()->OnPasswordFormsParsed(observed); // The initial load. | |
311 manager()->OnPasswordFormsRendered(observed); // The initial layout. | |
312 manager()->ProvisionallySavePassword(form); | |
313 | |
314 // We still expect an add, since we didn't have a good match. | |
315 scoped_ptr<PasswordFormManager> form_to_save; | |
316 EXPECT_CALL(client_, PromptUserToSavePassword(_)) | |
317 .WillOnce(WithArg<0>(SaveToScopedPtr(&form_to_save))); | |
318 | |
319 // Now the password manager waits for the navigation to complete. | |
320 observed.clear(); | |
321 manager()->OnPasswordFormsParsed(observed); // The post-navigation load. | |
322 manager()->OnPasswordFormsRendered(observed); // The post-navigation layout. | |
323 | |
324 ASSERT_TRUE(form_to_save.get()); | |
325 EXPECT_CALL(*store_.get(), AddLogin(FormMatches(form))); | |
326 | |
327 // Simulate saving the form. | |
328 form_to_save->Save(); | |
329 } | |
330 | |
331 TEST_F(PasswordManagerTest, FormSeenThenLeftPage) { | |
332 std::vector<PasswordForm*> result; // Empty password store. | |
333 EXPECT_CALL(driver_, FillPasswordForm(_)).Times(Exactly(0)); | |
334 EXPECT_CALL(*store_.get(), GetLogins(_, _, _)) | |
335 .WillOnce(DoAll(WithArg<2>(InvokeConsumer(result)), Return())); | |
336 std::vector<PasswordForm> observed; | |
337 PasswordForm form(MakeSimpleForm()); | |
338 observed.push_back(form); | |
339 manager()->OnPasswordFormsParsed(observed); // The initial load. | |
340 manager()->OnPasswordFormsRendered(observed); // The initial layout. | |
341 | |
342 // No message from the renderer that a password was submitted. No | |
343 // expected calls. | |
344 EXPECT_CALL(client_, PromptUserToSavePassword(_)).Times(0); | |
345 observed.clear(); | |
346 manager()->OnPasswordFormsParsed(observed); // The post-navigation load. | |
347 manager()->OnPasswordFormsRendered(observed); // The post-navigation layout. | |
348 } | |
349 | |
350 TEST_F(PasswordManagerTest, FormSubmitAfterNavigateInPage) { | |
351 // Test that navigating in the page does not prevent us from showing the save | |
352 // password infobar. | |
353 std::vector<PasswordForm*> result; // Empty password store. | |
354 EXPECT_CALL(driver_, FillPasswordForm(_)).Times(Exactly(0)); | |
355 EXPECT_CALL(*store_.get(), GetLogins(_, _, _)) | |
356 .WillOnce(DoAll(WithArg<2>(InvokeConsumer(result)), Return())); | |
357 std::vector<PasswordForm> observed; | |
358 PasswordForm form(MakeSimpleForm()); | |
359 observed.push_back(form); | |
360 manager()->OnPasswordFormsParsed(observed); // The initial load. | |
361 manager()->OnPasswordFormsRendered(observed); // The initial layout. | |
362 | |
363 // Simulate navigating in the page. | |
364 manager()->DidNavigateMainFrame(true); | |
365 | |
366 // Simulate submitting the password. | |
367 OnPasswordFormSubmitted(form); | |
368 | |
369 // Now the password manager waits for the navigation to complete. | |
370 scoped_ptr<PasswordFormManager> form_to_save; | |
371 EXPECT_CALL(client_, PromptUserToSavePassword(_)) | |
372 .WillOnce(WithArg<0>(SaveToScopedPtr(&form_to_save))); | |
373 | |
374 observed.clear(); | |
375 manager()->OnPasswordFormsParsed(observed); // The post-navigation load. | |
376 manager()->OnPasswordFormsRendered(observed); // The post-navigation layout. | |
377 | |
378 ASSERT_FALSE(NULL == form_to_save.get()); | |
379 EXPECT_CALL(*store_.get(), AddLogin(FormMatches(form))); | |
380 | |
381 // Simulate saving the form, as if the info bar was accepted. | |
382 form_to_save->Save(); | |
383 } | |
384 | |
385 // This test verifies a fix for http://crbug.com/236673 | |
386 TEST_F(PasswordManagerTest, FormSubmitWithFormOnPreviousPage) { | |
387 std::vector<PasswordForm*> result; // Empty password store. | |
388 EXPECT_CALL(driver_, FillPasswordForm(_)).Times(Exactly(0)); | |
389 EXPECT_CALL(*store_.get(), GetLogins(_, _, _)) | |
390 .WillRepeatedly(DoAll(WithArg<2>(InvokeConsumer(result)), Return())); | |
391 PasswordForm first_form(MakeSimpleForm()); | |
392 first_form.origin = GURL("http://www.nytimes.com/"); | |
393 first_form.action = GURL("https://myaccount.nytimes.com/auth/login"); | |
394 first_form.signon_realm = "http://www.nytimes.com/"; | |
395 PasswordForm second_form(MakeSimpleForm()); | |
396 second_form.origin = GURL("https://myaccount.nytimes.com/auth/login"); | |
397 second_form.action = GURL("https://myaccount.nytimes.com/auth/login"); | |
398 second_form.signon_realm = "https://myaccount.nytimes.com/"; | |
399 | |
400 // Pretend that the form is hidden on the first page. | |
401 std::vector<PasswordForm> observed; | |
402 observed.push_back(first_form); | |
403 manager()->OnPasswordFormsParsed(observed); | |
404 observed.clear(); | |
405 manager()->OnPasswordFormsRendered(observed); | |
406 | |
407 // Now navigate to a second page. | |
408 manager()->DidNavigateMainFrame(false); | |
409 | |
410 // This page contains a form with the same markup, but on a different | |
411 // URL. | |
412 observed.push_back(second_form); | |
413 manager()->OnPasswordFormsParsed(observed); | |
414 manager()->OnPasswordFormsRendered(observed); | |
415 | |
416 // Now submit this form | |
417 OnPasswordFormSubmitted(second_form); | |
418 | |
419 // Navigation after form submit. | |
420 scoped_ptr<PasswordFormManager> form_to_save; | |
421 EXPECT_CALL(client_, PromptUserToSavePassword(_)) | |
422 .WillOnce(WithArg<0>(SaveToScopedPtr(&form_to_save))); | |
423 observed.clear(); | |
424 manager()->OnPasswordFormsParsed(observed); | |
425 manager()->OnPasswordFormsRendered(observed); | |
426 | |
427 // Make sure that the saved form matches the second form, not the first. | |
428 ASSERT_TRUE(form_to_save.get()); | |
429 EXPECT_CALL(*store_.get(), AddLogin(FormMatches(second_form))); | |
430 | |
431 // Simulate saving the form, as if the info bar was accepted. | |
432 form_to_save->Save(); | |
433 } | |
434 | |
435 TEST_F(PasswordManagerTest, FormSubmitFailedLogin) { | |
436 std::vector<PasswordForm*> result; // Empty password store. | |
437 EXPECT_CALL(driver_, FillPasswordForm(_)).Times(Exactly(0)); | |
438 EXPECT_CALL(*store_.get(), GetLogins(_, _, _)) | |
439 .WillRepeatedly(DoAll(WithArg<2>(InvokeConsumer(result)), Return())); | |
440 std::vector<PasswordForm> observed; | |
441 PasswordForm form(MakeSimpleForm()); | |
442 observed.push_back(form); | |
443 manager()->OnPasswordFormsParsed(observed); // The initial load. | |
444 manager()->OnPasswordFormsRendered(observed); // The initial layout. | |
445 | |
446 manager()->ProvisionallySavePassword(form); | |
447 | |
448 // The form reappears, and is visible in the layout: | |
449 // No expected calls to the PasswordStore... | |
450 manager()->OnPasswordFormsParsed(observed); | |
451 manager()->OnPasswordFormsRendered(observed); | |
452 } | |
453 | |
454 TEST_F(PasswordManagerTest, FormSubmitInvisibleLogin) { | |
455 // Tests fix of issue 28911: if the login form reappears on the subsequent | |
456 // page, but is invisible, it shouldn't count as a failed login. | |
457 std::vector<PasswordForm*> result; // Empty password store. | |
458 EXPECT_CALL(driver_, FillPasswordForm(_)).Times(Exactly(0)); | |
459 EXPECT_CALL(*store_.get(), GetLogins(_, _, _)) | |
460 .WillRepeatedly(DoAll(WithArg<2>(InvokeConsumer(result)), Return())); | |
461 std::vector<PasswordForm> observed; | |
462 PasswordForm form(MakeSimpleForm()); | |
463 observed.push_back(form); | |
464 manager()->OnPasswordFormsParsed(observed); // The initial load. | |
465 manager()->OnPasswordFormsRendered(observed); // The initial layout. | |
466 | |
467 manager()->ProvisionallySavePassword(form); | |
468 | |
469 // Expect info bar to appear: | |
470 scoped_ptr<PasswordFormManager> form_to_save; | |
471 EXPECT_CALL(client_, PromptUserToSavePassword(_)) | |
472 .WillOnce(WithArg<0>(SaveToScopedPtr(&form_to_save))); | |
473 | |
474 // The form reappears, but is not visible in the layout: | |
475 manager()->OnPasswordFormsParsed(observed); | |
476 observed.clear(); | |
477 manager()->OnPasswordFormsRendered(observed); | |
478 | |
479 ASSERT_TRUE(form_to_save.get()); | |
480 EXPECT_CALL(*store_.get(), AddLogin(FormMatches(form))); | |
481 | |
482 // Simulate saving the form. | |
483 form_to_save->Save(); | |
484 } | |
485 | |
486 TEST_F(PasswordManagerTest, InitiallyInvisibleForm) { | |
487 // Make sure an invisible login form still gets autofilled. | |
488 std::vector<PasswordForm*> result; | |
489 PasswordForm* existing = new PasswordForm(MakeSimpleForm()); | |
490 result.push_back(existing); | |
491 EXPECT_CALL(driver_, FillPasswordForm(_)); | |
492 EXPECT_CALL(*store_.get(), GetLogins(_, _, _)) | |
493 .WillRepeatedly(DoAll(WithArg<2>(InvokeConsumer(result)), Return())); | |
494 std::vector<PasswordForm> observed; | |
495 PasswordForm form(MakeSimpleForm()); | |
496 observed.push_back(form); | |
497 manager()->OnPasswordFormsParsed(observed); // The initial load. | |
498 observed.clear(); | |
499 manager()->OnPasswordFormsRendered(observed); // The initial layout. | |
500 | |
501 manager()->OnPasswordFormsParsed(observed); // The post-navigation load. | |
502 manager()->OnPasswordFormsRendered(observed); // The post-navigation layout. | |
503 } | |
504 | |
505 TEST_F(PasswordManagerTest, SavingDependsOnManagerEnabledPreference) { | |
506 // Test that saving passwords depends on the password manager enabled | |
507 // preference. | |
508 TestingPrefServiceSyncable* prefService = profile()->GetTestingPrefService(); | |
509 prefService->SetUserPref(prefs::kPasswordManagerEnabled, | |
510 base::Value::CreateBooleanValue(true)); | |
511 EXPECT_TRUE(manager()->IsSavingEnabled()); | |
512 prefService->SetUserPref(prefs::kPasswordManagerEnabled, | |
513 base::Value::CreateBooleanValue(false)); | |
514 EXPECT_FALSE(manager()->IsSavingEnabled()); | |
515 } | |
516 | |
517 TEST_F(PasswordManagerTest, FillPasswordsOnDisabledManager) { | |
518 // Test fix for issue 158296: Passwords must be filled even if the password | |
519 // manager is disabled. | |
520 std::vector<PasswordForm*> result; | |
521 PasswordForm* existing = new PasswordForm(MakeSimpleForm()); | |
522 result.push_back(existing); | |
523 TestingPrefServiceSyncable* prefService = profile()->GetTestingPrefService(); | |
524 prefService->SetUserPref(prefs::kPasswordManagerEnabled, | |
525 base::Value::CreateBooleanValue(false)); | |
526 EXPECT_CALL(driver_, FillPasswordForm(_)); | |
527 EXPECT_CALL(*store_.get(), | |
528 GetLogins(_, testing::Eq(PasswordStore::DISALLOW_PROMPT), _)) | |
529 .WillRepeatedly(DoAll(WithArg<2>(InvokeConsumer(result)), Return())); | |
530 std::vector<PasswordForm> observed; | |
531 PasswordForm form(MakeSimpleForm()); | |
532 observed.push_back(form); | |
533 manager()->OnPasswordFormsParsed(observed); | |
534 } | |
535 | |
536 TEST_F(PasswordManagerTest, FormSavedWithAutocompleteOff) { | |
537 // Test password form with non-generated password will be saved even if | |
538 // autocomplete=off. | |
539 std::vector<PasswordForm*> result; // Empty password store. | |
540 EXPECT_CALL(driver_, FillPasswordForm(_)).Times(Exactly(0)); | |
541 EXPECT_CALL(*store_.get(), GetLogins(_, _, _)) | |
542 .WillOnce(DoAll(WithArg<2>(InvokeConsumer(result)), Return())); | |
543 std::vector<PasswordForm> observed; | |
544 PasswordForm form(MakeSimpleForm()); | |
545 form.password_autocomplete_set = false; | |
546 observed.push_back(form); | |
547 manager()->OnPasswordFormsParsed(observed); // The initial load. | |
548 manager()->OnPasswordFormsRendered(observed); // The initial layout. | |
549 | |
550 // And the form submit contract is to call ProvisionallySavePassword. | |
551 manager()->ProvisionallySavePassword(form); | |
552 | |
553 // Password form should be saved. | |
554 scoped_ptr<PasswordFormManager> form_to_save; | |
555 EXPECT_CALL(client_, PromptUserToSavePassword(_)).Times(Exactly(1)).WillOnce( | |
556 WithArg<0>(SaveToScopedPtr(&form_to_save))); | |
557 EXPECT_CALL(*store_.get(), AddLogin(FormMatches(form))).Times(Exactly(0)); | |
558 | |
559 // Now the password manager waits for the navigation to complete. | |
560 observed.clear(); | |
561 manager()->OnPasswordFormsParsed(observed); // The post-navigation load. | |
562 manager()->OnPasswordFormsRendered(observed); // The post-navigation layout. | |
563 | |
564 ASSERT_TRUE(form_to_save.get()); | |
565 } | |
566 | |
567 TEST_F(PasswordManagerTest, GeneratedPasswordFormSavedAutocompleteOff) { | |
568 // Test password form with generated password will still be saved if | |
569 // autocomplete=off. | |
570 std::vector<PasswordForm*> result; // Empty password store. | |
571 EXPECT_CALL(driver_, FillPasswordForm(_)).Times(Exactly(0)); | |
572 EXPECT_CALL(*store_.get(), GetLogins(_, _, _)) | |
573 .WillOnce(DoAll(WithArg<2>(InvokeConsumer(result)), Return())); | |
574 std::vector<PasswordForm> observed; | |
575 PasswordForm form(MakeSimpleForm()); | |
576 form.password_autocomplete_set = false; | |
577 observed.push_back(form); | |
578 manager()->OnPasswordFormsParsed(observed); // The initial load. | |
579 manager()->OnPasswordFormsRendered(observed); // The initial layout. | |
580 | |
581 // Simulate the user generating the password and submitting the form. | |
582 manager()->SetFormHasGeneratedPassword(form); | |
583 manager()->ProvisionallySavePassword(form); | |
584 | |
585 // The user should not be presented with an infobar as they have already given | |
586 // consent by using the generated password. The form should be saved once | |
587 // navigation occurs. | |
588 EXPECT_CALL(client_, PromptUserToSavePassword(_)).Times(Exactly(0)); | |
589 EXPECT_CALL(*store_.get(), AddLogin(FormMatches(form))); | |
590 | |
591 // Now the password manager waits for the navigation to complete. | |
592 observed.clear(); | |
593 manager()->OnPasswordFormsParsed(observed); // The post-navigation load. | |
594 manager()->OnPasswordFormsRendered(observed); // The post-navigation layout. | |
595 } | |
596 | |
597 TEST_F(PasswordManagerTest, SubmissionCallbackTest) { | |
598 manager()->AddSubmissionCallback(SubmissionCallback()); | |
599 PasswordForm form = MakeSimpleForm(); | |
600 OnPasswordFormSubmitted(form); | |
601 EXPECT_TRUE(FormsAreEqual(form, submitted_form_)); | |
602 } | |
603 | |
604 TEST_F(PasswordManagerTest, PasswordFormReappearance) { | |
605 // Test the heuristic to know if a password form reappears. | |
606 // We assume that if we send our credentials and there | |
607 // is at least one visible password form in the next page that | |
608 // means that our previous login attempt failed. | |
609 std::vector<PasswordForm*> result; // Empty password store. | |
610 EXPECT_CALL(driver_, FillPasswordForm(_)).Times(0); | |
611 EXPECT_CALL(*store_.get(), GetLogins(_, _, _)) | |
612 .WillRepeatedly(DoAll(WithArg<2>(InvokeConsumer(result)), Return())); | |
613 std::vector<PasswordForm> observed; | |
614 PasswordForm login_form(MakeTwitterLoginForm()); | |
615 observed.push_back(login_form); | |
616 manager()->OnPasswordFormsParsed(observed); // The initial load. | |
617 manager()->OnPasswordFormsRendered(observed); // The initial layout. | |
618 | |
619 manager()->ProvisionallySavePassword(login_form); | |
620 | |
621 PasswordForm failed_login_form(MakeTwitterFailedLoginForm()); | |
622 observed.clear(); | |
623 observed.push_back(failed_login_form); | |
624 // A PasswordForm appears, and is visible in the layout: | |
625 // No expected calls to the PasswordStore... | |
626 manager()->OnPasswordFormsParsed(observed); | |
627 manager()->OnPasswordFormsRendered(observed); | |
628 } | |
OLD | NEW |