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.
5 #include "base/strings/string16.h"
6 #include "base/strings/string_util.h"
7 #include "base/strings/stringprintf.h"
8 #include "base/strings/utf_string_conversions.h"
9 #include "components/autofill/content/renderer/password_form_conversion_utils.h"
10 #include "components/autofill/core/common/password_form.h"
11 #include "content/public/test/render_view_test.h"
12 #include "testing/gmock/include/gmock/gmock.h"
13 #include "testing/gtest/include/gtest/gtest.h"
14 #include "third_party/WebKit/public/platform/WebVector.h"
15 #include "third_party/WebKit/public/web/WebDocument.h"
16 #include "third_party/WebKit/public/web/WebFormControlElement.h"
17 #include "third_party/WebKit/public/web/WebFormElement.h"
18 #include "third_party/WebKit/public/web/WebInputElement.h"
19 #include "third_party/WebKit/public/web/WebLocalFrame.h"
21 using blink::WebFormControlElement
;
22 using blink::WebFormElement
;
23 using blink::WebFrame
;
24 using blink::WebInputElement
;
25 using blink::WebVector
;
30 const char kTestFormActionURL
[] = "http://cnn.com";
32 // A builder to produce HTML code for a password form composed of the desired
33 // number and kinds of username and password fields.
34 class PasswordFormBuilder
{
36 // Creates a builder to start composing a new form. The form will have the
37 // specified |action| URL.
38 explicit PasswordFormBuilder(const char* action
) {
40 &html_
, "<FORM name=\"Test\" action=\"%s\" method=\"post\">", action
);
43 // Appends a new text-type field at the end of the form, having the specified
44 // |name_and_id|, |value|, and |autocomplete| attributes. The |autocomplete|
45 // argument can take two special values, namely:
46 // 1.) NULL, causing no autocomplete attribute to be added,
47 // 2.) "", causing an empty attribute (i.e. autocomplete="") to be added.
48 void AddUsernameField(const char* name_and_id
,
50 const char* autocomplete
) {
51 std::string
autocomplete_attribute(autocomplete
?
52 base::StringPrintf("autocomplete=\"%s\"", autocomplete
) : "");
55 "<INPUT type=\"text\" name=\"%s\" id=\"%s\" value=\"%s\" %s/>",
56 name_and_id
, name_and_id
, value
, autocomplete_attribute
.c_str());
59 // Appends a new password-type field at the end of the form, having the
60 // specified |name_and_id|, |value|, and |autocomplete| attributes. Special
61 // values for |autocomplete| are the same as in AddUsernameField.
62 void AddPasswordField(const char* name_and_id
,
64 const char* autocomplete
) {
65 std::string
autocomplete_attribute(autocomplete
?
66 base::StringPrintf("autocomplete=\"%s\"", autocomplete
): "");
69 "<INPUT type=\"password\" name=\"%s\" id=\"%s\" value=\"%s\" %s/>",
70 name_and_id
, name_and_id
, value
, autocomplete_attribute
.c_str());
73 // Appends a disabled text-type field at the end of the form.
74 void AddDisabledUsernameField() {
75 html_
+= "<INPUT type=\"text\" disabled/>";
78 // Appends a disabled password-type field at the end of the form.
79 void AddDisabledPasswordField() {
80 html_
+= "<INPUT type=\"password\" disabled/>";
83 // Appends a new submit-type field at the end of the form with the specified
84 // |name|. If |activated| is true, the test will emulate as if this button
85 // were used to submit the form.
86 void AddSubmitButton(const char* name
, bool activated
) {
89 "<INPUT type=\"submit\" name=\"%s\" value=\"Submit\" %s/>",
90 name
, activated
? "set-activated-submit" : "");
93 // Returns the HTML code for the form containing the fields that have been
95 std::string
ProduceHTML() const {
96 return html_
+ "</FORM>";
102 DISALLOW_COPY_AND_ASSIGN(PasswordFormBuilder
);
105 class PasswordFormConversionUtilsTest
: public content::RenderViewTest
{
107 PasswordFormConversionUtilsTest() : content::RenderViewTest() {}
108 virtual ~PasswordFormConversionUtilsTest() {}
111 // Loads the given |html|, retrieves the sole WebFormElement from it, and then
112 // calls CreatePasswordForm() to convert it into a |password_form|. Note that
113 // ASSERT() can only be used in void functions, this is why |password_form| is
114 // passed in as a pointer to a scoped_ptr.
115 void LoadHTMLAndConvertForm(const std::string
& html
,
116 scoped_ptr
<PasswordForm
>* password_form
) {
117 LoadHTML(html
.c_str());
119 WebFrame
* frame
= GetMainFrame();
120 ASSERT_NE(static_cast<WebFrame
*>(NULL
), frame
);
122 WebVector
<WebFormElement
> forms
;
123 frame
->document().forms(forms
);
124 ASSERT_EQ(1U, forms
.size());
126 WebVector
<WebFormControlElement
> control_elements
;
127 forms
[0].getFormControlElements(control_elements
);
128 for (size_t i
= 0; i
< control_elements
.size(); ++i
) {
129 WebInputElement
* input_element
= toWebInputElement(&control_elements
[i
]);
130 if (input_element
->hasAttribute("set-activated-submit"))
131 input_element
->setActivatedSubmit(true);
134 *password_form
= CreatePasswordForm(forms
[0]);
138 DISALLOW_COPY_AND_ASSIGN(PasswordFormConversionUtilsTest
);
143 TEST_F(PasswordFormConversionUtilsTest
, BasicFormAttributes
) {
144 PasswordFormBuilder
builder(kTestFormActionURL
);
145 builder
.AddUsernameField("username", "johnsmith", NULL
);
146 builder
.AddSubmitButton("inactive_submit", false);
147 builder
.AddSubmitButton("active_submit", true);
148 builder
.AddSubmitButton("inactive_submit2", false);
149 builder
.AddPasswordField("password", "secret", NULL
);
150 std::string html
= builder
.ProduceHTML();
152 scoped_ptr
<PasswordForm
> password_form
;
153 ASSERT_NO_FATAL_FAILURE(LoadHTMLAndConvertForm(html
, &password_form
));
154 ASSERT_TRUE(password_form
);
156 EXPECT_EQ("data:", password_form
->signon_realm
);
157 EXPECT_EQ(GURL(kTestFormActionURL
), password_form
->action
);
158 EXPECT_EQ(base::UTF8ToUTF16("active_submit"), password_form
->submit_element
);
159 EXPECT_EQ(base::UTF8ToUTF16("username"), password_form
->username_element
);
160 EXPECT_EQ(base::UTF8ToUTF16("johnsmith"), password_form
->username_value
);
161 EXPECT_EQ(base::UTF8ToUTF16("password"), password_form
->password_element
);
162 EXPECT_EQ(base::UTF8ToUTF16("secret"), password_form
->password_value
);
163 EXPECT_EQ(PasswordForm::SCHEME_HTML
, password_form
->scheme
);
164 EXPECT_FALSE(password_form
->ssl_valid
);
165 EXPECT_FALSE(password_form
->preferred
);
166 EXPECT_FALSE(password_form
->blacklisted_by_user
);
167 EXPECT_EQ(PasswordForm::TYPE_MANUAL
, password_form
->type
);
170 TEST_F(PasswordFormConversionUtilsTest
, DisabledFieldsAreIgnored
) {
171 PasswordFormBuilder
builder(kTestFormActionURL
);
172 builder
.AddUsernameField("username", "johnsmith", NULL
);
173 builder
.AddDisabledUsernameField();
174 builder
.AddDisabledPasswordField();
175 builder
.AddPasswordField("password", "secret", NULL
);
176 builder
.AddSubmitButton("submit", true);
177 std::string html
= builder
.ProduceHTML();
179 scoped_ptr
<PasswordForm
> password_form
;
180 ASSERT_NO_FATAL_FAILURE(LoadHTMLAndConvertForm(html
, &password_form
));
181 ASSERT_TRUE(password_form
);
182 EXPECT_EQ(base::UTF8ToUTF16("username"), password_form
->username_element
);
183 EXPECT_EQ(base::UTF8ToUTF16("johnsmith"), password_form
->username_value
);
184 EXPECT_EQ(base::UTF8ToUTF16("password"), password_form
->password_element
);
185 EXPECT_EQ(base::UTF8ToUTF16("secret"), password_form
->password_value
);
188 TEST_F(PasswordFormConversionUtilsTest
, IdentifyingUsernameFields
) {
189 // Each test case consists of a set of parameters to be plugged into the
190 // PasswordFormBuilder below, plus the corresponding expectations.
192 const char* autocomplete
[3];
193 const char* expected_username_element
;
194 const char* expected_username_value
;
195 const char* expected_other_possible_usernames
;
197 // When no elements are marked with autocomplete='username', the text-type
198 // input field before the first password element should get selected as
199 // the username, and the rest should be marked as alternatives.
200 {{NULL
, NULL
, NULL
}, "username2", "William", "John+Smith"},
201 // When a sole element is marked with autocomplete='username', it should
202 // be treated as the username for sure, with no other_possible_usernames.
203 {{"username", NULL
, NULL
}, "username1", "John", ""},
204 {{NULL
, "username", NULL
}, "username2", "William", ""},
205 {{NULL
, NULL
, "username"}, "username3", "Smith", ""},
206 // When >=2 elements have the attribute, the first should be selected as
207 // the username, and the rest should go to other_possible_usernames.
208 {{"username", "username", NULL
}, "username1", "John", "William"},
209 {{NULL
, "username", "username"}, "username2", "William", "Smith"},
210 {{"username", NULL
, "username"}, "username1", "John", "Smith"},
211 {{"username", "username", "username"}, "username1", "John",
213 // When there is an empty autocomplete attribute (i.e. autocomplete=""),
214 // it should have the same effect as having no attribute whatsoever.
215 {{"", "", ""}, "username2", "William", "John+Smith"},
216 {{"", "", "username"}, "username3", "Smith", ""},
217 {{"username", "", "username"}, "username1", "John", "Smith"},
218 // It should not matter if attribute values are upper or mixed case.
219 {{"USERNAME", NULL
, "uSeRNaMe"}, "username1", "John", "Smith"},
220 {{"uSeRNaMe", NULL
, "USERNAME"}, "username1", "John", "Smith"}};
222 for (size_t i
= 0; i
< arraysize(cases
); ++i
) {
223 for (size_t nonempty_username_fields
= 0; nonempty_username_fields
< 2;
224 ++nonempty_username_fields
) {
225 SCOPED_TRACE(testing::Message()
226 << "Iteration " << i
<< " "
227 << (nonempty_username_fields
? "nonempty" : "empty"));
229 // Repeat each test once with empty, and once with non-empty usernames.
230 // In the former case, no empty other_possible_usernames should be saved.
231 const char* names
[3];
232 if (nonempty_username_fields
) {
234 names
[1] = "William";
237 names
[0] = names
[1] = names
[2] = "";
240 PasswordFormBuilder
builder(kTestFormActionURL
);
241 builder
.AddUsernameField("username1", names
[0], cases
[i
].autocomplete
[0]);
242 builder
.AddUsernameField("username2", names
[1], cases
[i
].autocomplete
[1]);
243 builder
.AddPasswordField("password", "secret", NULL
);
244 builder
.AddUsernameField("username3", names
[2], cases
[i
].autocomplete
[2]);
245 builder
.AddPasswordField("password2", "othersecret", NULL
);
246 builder
.AddSubmitButton("submit", true);
247 std::string html
= builder
.ProduceHTML();
249 scoped_ptr
<PasswordForm
> password_form
;
250 ASSERT_NO_FATAL_FAILURE(LoadHTMLAndConvertForm(html
, &password_form
));
251 ASSERT_TRUE(password_form
);
253 EXPECT_EQ(base::UTF8ToUTF16(cases
[i
].expected_username_element
),
254 password_form
->username_element
);
256 if (nonempty_username_fields
) {
257 EXPECT_EQ(base::UTF8ToUTF16(cases
[i
].expected_username_value
),
258 password_form
->username_value
);
259 EXPECT_EQ(base::UTF8ToUTF16(cases
[i
].expected_other_possible_usernames
),
260 JoinString(password_form
->other_possible_usernames
, '+'));
262 EXPECT_TRUE(password_form
->username_value
.empty());
263 EXPECT_TRUE(password_form
->other_possible_usernames
.empty());
266 // Do a basic sanity check that we are still having a password field.
267 EXPECT_EQ(base::UTF8ToUTF16("password"), password_form
->password_element
);
268 EXPECT_EQ(base::UTF8ToUTF16("secret"), password_form
->password_value
);
273 TEST_F(PasswordFormConversionUtilsTest
, IdentifyingTwoPasswordFields
) {
274 // Each test case consists of a set of parameters to be plugged into the
275 // PasswordFormBuilder below, plus the corresponding expectations.
277 const char* password_values
[2];
278 const char* expected_password_element
;
279 const char* expected_password_value
;
280 const char* expected_new_password_element
;
281 const char* expected_new_password_value
;
283 // Twp non-empty fields with the same value should be treated as a new
284 // password field plus a confirmation field for the new password.
285 {{"alpha", "alpha"}, "", "", "password1", "alpha"},
286 // The same goes if the fields are yet empty: we speculate that we will
287 // identify them as new password fields once they are filled out, and we
288 // want to keep our abstract interpretation of the form less flaky.
289 {{"", ""}, "", "", "password1", ""},
290 // Two different values should be treated as a password change form, one
291 // that also asks for the current password, but only once for the new.
292 {{"alpha", ""}, "password1", "alpha", "password2", ""},
293 {{"", "beta"}, "password1", "", "password2", "beta"},
294 {{"alpha", "beta"}, "password1", "alpha", "password2", "beta"}};
296 for (size_t i
= 0; i
< arraysize(cases
); ++i
) {
297 SCOPED_TRACE(testing::Message() << "Iteration " << i
);
299 PasswordFormBuilder
builder(kTestFormActionURL
);
300 builder
.AddPasswordField("password1", cases
[i
].password_values
[0], NULL
);
301 builder
.AddUsernameField("username1", "William", NULL
);
302 builder
.AddPasswordField("password2", cases
[i
].password_values
[1], NULL
);
303 builder
.AddUsernameField("username2", "Smith", NULL
);
304 builder
.AddSubmitButton("submit", true);
305 std::string html
= builder
.ProduceHTML();
307 scoped_ptr
<PasswordForm
> password_form
;
308 ASSERT_NO_FATAL_FAILURE(LoadHTMLAndConvertForm(html
, &password_form
));
309 ASSERT_TRUE(password_form
);
311 EXPECT_EQ(base::UTF8ToUTF16(cases
[i
].expected_password_element
),
312 password_form
->password_element
);
313 EXPECT_EQ(base::UTF8ToUTF16(cases
[i
].expected_password_value
),
314 password_form
->password_value
);
315 EXPECT_EQ(base::UTF8ToUTF16(cases
[i
].expected_new_password_element
),
316 password_form
->new_password_element
);
317 EXPECT_EQ(base::UTF8ToUTF16(cases
[i
].expected_new_password_value
),
318 password_form
->new_password_value
);
320 // Do a basic sanity check that we are still selecting the right username.
321 EXPECT_EQ(base::UTF8ToUTF16("username1"), password_form
->username_element
);
322 EXPECT_EQ(base::UTF8ToUTF16("William"), password_form
->username_value
);
323 EXPECT_THAT(password_form
->other_possible_usernames
,
324 testing::ElementsAre(base::UTF8ToUTF16("Smith")));
328 TEST_F(PasswordFormConversionUtilsTest
, IdentifyingThreePasswordFields
) {
329 // Each test case consists of a set of parameters to be plugged into the
330 // PasswordFormBuilder below, plus the corresponding expectations.
332 const char* password_values
[3];
333 const char* expected_password_element
;
334 const char* expected_password_value
;
335 const char* expected_new_password_element
;
336 const char* expected_new_password_value
;
338 // Two fields with the same value, and one different: we should treat this
339 // as a password change form with confirmation for the new password. Note
340 // that we only recognize (current + new + new) and (new + new + current)
341 // without autocomplete attributes.
342 {{"alpha", "", ""}, "password1", "alpha", "password2", ""},
343 {{"", "beta", "beta"}, "password1", "", "password2", "beta"},
344 {{"alpha", "beta", "beta"}, "password1", "alpha", "password2", "beta"},
345 {{"beta", "beta", "alpha"}, "password3", "alpha", "password1", "beta"},
346 // If the fields are yet empty, we speculate that we will identify them as
347 // (current + new + new) once they are filled out, so we should classify
348 // them the same for now to keep our abstract interpretation less flaky.
349 {{"", "", ""}, "password1", "", "password2", ""}};
350 // Note: In all other cases, we give up and consider the form invalid.
351 // This is tested in InvalidFormDueToConfusingPasswordFields.
353 for (size_t i
= 0; i
< arraysize(cases
); ++i
) {
354 SCOPED_TRACE(testing::Message() << "Iteration " << i
);
356 PasswordFormBuilder
builder(kTestFormActionURL
);
357 builder
.AddPasswordField("password1", cases
[i
].password_values
[0], NULL
);
358 builder
.AddUsernameField("username1", "William", NULL
);
359 builder
.AddPasswordField("password2", cases
[i
].password_values
[1], NULL
);
360 builder
.AddUsernameField("username2", "Smith", NULL
);
361 builder
.AddPasswordField("password3", cases
[i
].password_values
[2], NULL
);
362 builder
.AddSubmitButton("submit", true);
363 std::string html
= builder
.ProduceHTML();
365 scoped_ptr
<PasswordForm
> password_form
;
366 ASSERT_NO_FATAL_FAILURE(LoadHTMLAndConvertForm(html
, &password_form
));
367 ASSERT_TRUE(password_form
);
369 EXPECT_EQ(base::UTF8ToUTF16(cases
[i
].expected_password_element
),
370 password_form
->password_element
);
371 EXPECT_EQ(base::UTF8ToUTF16(cases
[i
].expected_password_value
),
372 password_form
->password_value
);
373 EXPECT_EQ(base::UTF8ToUTF16(cases
[i
].expected_new_password_element
),
374 password_form
->new_password_element
);
375 EXPECT_EQ(base::UTF8ToUTF16(cases
[i
].expected_new_password_value
),
376 password_form
->new_password_value
);
378 // Do a basic sanity check that we are still selecting the right username.
379 EXPECT_EQ(base::UTF8ToUTF16("username1"), password_form
->username_element
);
380 EXPECT_EQ(base::UTF8ToUTF16("William"), password_form
->username_value
);
381 EXPECT_THAT(password_form
->other_possible_usernames
,
382 testing::ElementsAre(base::UTF8ToUTF16("Smith")));
386 TEST_F(PasswordFormConversionUtilsTest
,
387 IdentifyingPasswordFieldsWithAutocompleteAttributes
) {
388 // Each test case consists of a set of parameters to be plugged into the
389 // PasswordFormBuilder below, plus the corresponding expectations.
391 const char* autocomplete
[3];
392 const char* expected_password_element
;
393 const char* expected_password_value
;
394 const char* expected_new_password_element
;
395 const char* expected_new_password_value
;
397 // When there are elements marked with autocomplete='current-password',
398 // but no elements with 'new-password', we should treat the first of the
399 // former kind as the current password, and ignore all other password
400 // fields, assuming they are not intentionally not marked. They might be
401 // for other purposes, such as PINs, OTPs, and the like. Actual values in
402 // the password fields should be ignored in all cases below.
403 {{"current-password", NULL
, NULL
},
404 "password1", "alpha", "", ""},
405 {{NULL
, "current-password", NULL
},
406 "password2", "beta", "", ""},
407 {{NULL
, NULL
, "current-password"},
408 "password3", "gamma", "", ""},
409 {{NULL
, "current-password", "current-password"},
410 "password2", "beta", "", ""},
411 {{"current-password", NULL
, "current-password"},
412 "password1", "alpha", "", ""},
413 {{"current-password", "current-password", NULL
},
414 "password1", "alpha", "", ""},
415 {{"current-password", "current-password", "current-password"},
416 "password1", "alpha", "", ""},
417 // The same goes vice versa for autocomplete='new-password'.
418 {{"new-password", NULL
, NULL
},
419 "", "", "password1", "alpha"},
420 {{NULL
, "new-password", NULL
},
421 "", "", "password2", "beta"},
422 {{NULL
, NULL
, "new-password"},
423 "", "", "password3", "gamma"},
424 {{NULL
, "new-password", "new-password"},
425 "", "", "password2", "beta"},
426 {{"new-password", NULL
, "new-password"},
427 "", "", "password1", "alpha"},
428 {{"new-password", "new-password", NULL
},
429 "", "", "password1", "alpha"},
430 {{"new-password", "new-password", "new-password"},
431 "", "", "password1", "alpha"},
432 // When there is one element marked with autocomplete='current-password',
433 // and one with 'new-password', just comply, regardless of their order.
434 // Ignore the unmarked password field(s) for the same reason as above.
435 {{"current-password", "new-password", NULL
},
436 "password1", "alpha", "password2", "beta"},
437 {{"current-password", NULL
, "new-password"},
438 "password1", "alpha", "password3", "gamma"},
439 {{NULL
, "current-password", "new-password"},
440 "password2", "beta", "password3", "gamma"},
441 {{"new-password", "current-password", NULL
},
442 "password2", "beta", "password1", "alpha"},
443 {{"new-password", NULL
, "current-password"},
444 "password3", "gamma", "password1", "alpha"},
445 {{NULL
, "new-password", "current-password"},
446 "password3", "gamma", "password2", "beta"},
447 // In case of duplicated elements of either kind, go with the first one of
449 {{"current-password", "current-password", "new-password"},
450 "password1", "alpha", "password3", "gamma"},
451 {{"current-password", "new-password", "current-password"},
452 "password1", "alpha", "password2", "beta"},
453 {{"new-password", "current-password", "current-password"},
454 "password2", "beta", "password1", "alpha"},
455 {{"current-password", "new-password", "new-password"},
456 "password1", "alpha", "password2", "beta"},
457 {{"new-password", "current-password", "new-password"},
458 "password2", "beta", "password1", "alpha"},
459 {{"new-password", "new-password", "current-password"},
460 "password3", "gamma", "password1", "alpha"},
461 // When there is an empty autocomplete attribute (i.e. autocomplete=""),
462 // it should have the same effect as having no attribute whatsoever.
463 {{"current-password", "", ""},
464 "password1", "alpha", "", ""},
465 {{"", "", "new-password"},
466 "", "", "password3", "gamma"},
467 {{"", "new-password", ""},
468 "", "", "password2", "beta"},
469 {{"", "current-password", "current-password"},
470 "password2", "beta", "", ""},
471 {{"new-password", "", "new-password"},
472 "", "", "password1", "alpha"},
473 {{"new-password", "", "current-password"},
474 "password3", "gamma", "password1", "alpha"},
475 // It should not matter if attribute values are upper or mixed case.
476 {{NULL
, "current-password", NULL
},
477 "password2", "beta", "", ""},
478 {{NULL
, "CURRENT-PASSWORD", NULL
},
479 "password2", "beta", "", ""},
480 {{NULL
, "new-password", NULL
},
481 "", "", "password2", "beta"},
482 {{NULL
, "nEw-PaSsWoRd", NULL
},
483 "", "", "password2", "beta"}};
485 for (size_t i
= 0; i
< arraysize(cases
); ++i
) {
486 SCOPED_TRACE(testing::Message() << "Iteration " << i
);
488 PasswordFormBuilder
builder(kTestFormActionURL
);
489 builder
.AddPasswordField("pin1", "123456", NULL
);
490 builder
.AddPasswordField("pin2", "789101", NULL
);
491 builder
.AddPasswordField("password1", "alpha", cases
[i
].autocomplete
[0]);
492 builder
.AddUsernameField("username1", "William", NULL
);
493 builder
.AddPasswordField("password2", "beta", cases
[i
].autocomplete
[1]);
494 builder
.AddUsernameField("username2", "Smith", NULL
);
495 builder
.AddPasswordField("password3", "gamma", cases
[i
].autocomplete
[2]);
496 builder
.AddSubmitButton("submit", true);
497 std::string html
= builder
.ProduceHTML();
499 scoped_ptr
<PasswordForm
> password_form
;
500 ASSERT_NO_FATAL_FAILURE(LoadHTMLAndConvertForm(html
, &password_form
));
501 ASSERT_TRUE(password_form
);
503 // In the absence of username autocomplete attributes, the username should
504 // be the text input field before the first password element.
505 // No constellation of password autocomplete attributes should change that.
506 EXPECT_EQ(base::UTF8ToUTF16("username1"), password_form
->username_element
);
507 EXPECT_EQ(base::UTF8ToUTF16("William"), password_form
->username_value
);
508 EXPECT_THAT(password_form
->other_possible_usernames
,
509 testing::ElementsAre(base::UTF8ToUTF16("Smith")));
510 EXPECT_EQ(base::UTF8ToUTF16(cases
[i
].expected_password_element
),
511 password_form
->password_element
);
512 EXPECT_EQ(base::UTF8ToUTF16(cases
[i
].expected_password_value
),
513 password_form
->password_value
);
514 EXPECT_EQ(base::UTF8ToUTF16(cases
[i
].expected_new_password_element
),
515 password_form
->new_password_element
);
516 EXPECT_EQ(base::UTF8ToUTF16(cases
[i
].expected_new_password_value
),
517 password_form
->new_password_value
);
521 TEST_F(PasswordFormConversionUtilsTest
, InvalidFormDueToBadActionURL
) {
522 PasswordFormBuilder
builder("invalid_target");
523 builder
.AddUsernameField("username", "JohnSmith", NULL
);
524 builder
.AddSubmitButton("submit", true);
525 builder
.AddPasswordField("password", "secret", NULL
);
526 std::string html
= builder
.ProduceHTML();
528 scoped_ptr
<PasswordForm
> password_form
;
529 ASSERT_NO_FATAL_FAILURE(LoadHTMLAndConvertForm(html
, &password_form
));
530 EXPECT_FALSE(password_form
);
533 TEST_F(PasswordFormConversionUtilsTest
, InvalidFormDueToNoPasswordFields
) {
534 PasswordFormBuilder
builder(kTestFormActionURL
);
535 builder
.AddUsernameField("username1", "John", NULL
);
536 builder
.AddUsernameField("username2", "Smith", NULL
);
537 builder
.AddSubmitButton("submit", true);
538 std::string html
= builder
.ProduceHTML();
540 scoped_ptr
<PasswordForm
> password_form
;
541 ASSERT_NO_FATAL_FAILURE(LoadHTMLAndConvertForm(html
, &password_form
));
542 EXPECT_FALSE(password_form
);
545 TEST_F(PasswordFormConversionUtilsTest
,
546 InvalidFormsDueToConfusingPasswordFields
) {
547 // Each test case consists of a set of parameters to be plugged into the
548 // PasswordFormBuilder below.
549 const char* cases
[][3] = {
550 // No autocomplete attributes to guide us, and we see:
551 // * three password values that are all different,
552 // * three password values that are all the same;
553 // * three password values with the first and last matching.
554 // In any case, we should just give up on this form.
555 {"alpha", "beta", "gamma"},
556 {"alpha", "alpha", "alpha"},
557 {"alpha", "beta", "alpha"}};
559 for (size_t i
= 0; i
< arraysize(cases
); ++i
) {
560 SCOPED_TRACE(testing::Message() << "Iteration " << i
);
562 PasswordFormBuilder
builder(kTestFormActionURL
);
563 builder
.AddUsernameField("username1", "John", NULL
);
564 builder
.AddPasswordField("password1", cases
[i
][0], NULL
);
565 builder
.AddPasswordField("password2", cases
[i
][1], NULL
);
566 builder
.AddPasswordField("password3", cases
[i
][2], NULL
);
567 builder
.AddSubmitButton("submit", true);
568 std::string html
= builder
.ProduceHTML();
570 scoped_ptr
<PasswordForm
> password_form
;
571 ASSERT_NO_FATAL_FAILURE(LoadHTMLAndConvertForm(html
, &password_form
));
572 EXPECT_FALSE(password_form
);
576 TEST_F(PasswordFormConversionUtilsTest
,
577 InvalidFormDueToTooManyPasswordFieldsWithoutAutocompleteAttributes
) {
578 PasswordFormBuilder
builder(kTestFormActionURL
);
579 builder
.AddUsernameField("username1", "John", NULL
);
580 builder
.AddPasswordField("password1", "alpha", NULL
);
581 builder
.AddPasswordField("password2", "alpha", NULL
);
582 builder
.AddPasswordField("password3", "alpha", NULL
);
583 builder
.AddPasswordField("password4", "alpha", NULL
);
584 builder
.AddSubmitButton("submit", true);
585 std::string html
= builder
.ProduceHTML();
587 scoped_ptr
<PasswordForm
> password_form
;
588 ASSERT_NO_FATAL_FAILURE(LoadHTMLAndConvertForm(html
, &password_form
));
589 EXPECT_FALSE(password_form
);
592 } // namespace autofill