Add diagnostics_writer.cc to the list of files allowed to printf.
[chromium-blink-merge.git] / components / autofill / content / renderer / password_form_conversion_utils_browsertest.cc
blobaf70d2258c7e783fbc751450f9d8cc4ae5708311
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;
27 namespace autofill {
28 namespace {
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 {
35 public:
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) {
39 base::StringAppendF(
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,
49 const char* value,
50 const char* autocomplete) {
51 std::string autocomplete_attribute(autocomplete ?
52 base::StringPrintf("autocomplete=\"%s\"", autocomplete) : "");
53 base::StringAppendF(
54 &html_,
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,
63 const char* value,
64 const char* autocomplete) {
65 std::string autocomplete_attribute(autocomplete ?
66 base::StringPrintf("autocomplete=\"%s\"", autocomplete): "");
67 base::StringAppendF(
68 &html_,
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) {
87 base::StringAppendF(
88 &html_,
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
94 // added so far.
95 std::string ProduceHTML() const {
96 return html_ + "</FORM>";
99 private:
100 std::string html_;
102 DISALLOW_COPY_AND_ASSIGN(PasswordFormBuilder);
105 class PasswordFormConversionUtilsTest : public content::RenderViewTest {
106 public:
107 PasswordFormConversionUtilsTest() : content::RenderViewTest() {}
108 virtual ~PasswordFormConversionUtilsTest() {}
110 protected:
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]);
137 private:
138 DISALLOW_COPY_AND_ASSIGN(PasswordFormConversionUtilsTest);
141 } // namespace
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);
168 EXPECT_FALSE(password_form->use_additional_authentication);
171 TEST_F(PasswordFormConversionUtilsTest, DisabledFieldsAreIgnored) {
172 PasswordFormBuilder builder(kTestFormActionURL);
173 builder.AddUsernameField("username", "johnsmith", NULL);
174 builder.AddDisabledUsernameField();
175 builder.AddDisabledPasswordField();
176 builder.AddPasswordField("password", "secret", NULL);
177 builder.AddSubmitButton("submit", true);
178 std::string html = builder.ProduceHTML();
180 scoped_ptr<PasswordForm> password_form;
181 ASSERT_NO_FATAL_FAILURE(LoadHTMLAndConvertForm(html, &password_form));
182 ASSERT_TRUE(password_form);
183 EXPECT_EQ(base::UTF8ToUTF16("username"), password_form->username_element);
184 EXPECT_EQ(base::UTF8ToUTF16("johnsmith"), password_form->username_value);
185 EXPECT_EQ(base::UTF8ToUTF16("password"), password_form->password_element);
186 EXPECT_EQ(base::UTF8ToUTF16("secret"), password_form->password_value);
189 TEST_F(PasswordFormConversionUtilsTest, IdentifyingUsernameFields) {
190 // Each test case consists of a set of parameters to be plugged into the
191 // PasswordFormBuilder below, plus the corresponding expectations.
192 struct TestCase {
193 const char* autocomplete[3];
194 const char* expected_username_element;
195 const char* expected_username_value;
196 const char* expected_other_possible_usernames;
197 } cases[] = {
198 // When no elements are marked with autocomplete='username', the text-type
199 // input field before the first password element should get selected as
200 // the username, and the rest should be marked as alternatives.
201 {{NULL, NULL, NULL}, "username2", "William", "John+Smith"},
202 // When a sole element is marked with autocomplete='username', it should
203 // be treated as the username for sure, with no other_possible_usernames.
204 {{"username", NULL, NULL}, "username1", "John", ""},
205 {{NULL, "username", NULL}, "username2", "William", ""},
206 {{NULL, NULL, "username"}, "username3", "Smith", ""},
207 // When >=2 elements have the attribute, the first should be selected as
208 // the username, and the rest should go to other_possible_usernames.
209 {{"username", "username", NULL}, "username1", "John", "William"},
210 {{NULL, "username", "username"}, "username2", "William", "Smith"},
211 {{"username", NULL, "username"}, "username1", "John", "Smith"},
212 {{"username", "username", "username"}, "username1", "John",
213 "William+Smith"},
214 // When there is an empty autocomplete attribute (i.e. autocomplete=""),
215 // it should have the same effect as having no attribute whatsoever.
216 {{"", "", ""}, "username2", "William", "John+Smith"},
217 {{"", "", "username"}, "username3", "Smith", ""},
218 {{"username", "", "username"}, "username1", "John", "Smith"},
219 // It should not matter if attribute values are upper or mixed case.
220 {{"USERNAME", NULL, "uSeRNaMe"}, "username1", "John", "Smith"},
221 {{"uSeRNaMe", NULL, "USERNAME"}, "username1", "John", "Smith"}};
223 for (size_t i = 0; i < ARRAYSIZE_UNSAFE(cases); ++i) {
224 for (size_t nonempty_username_fields = 0; nonempty_username_fields < 2;
225 ++nonempty_username_fields) {
226 SCOPED_TRACE(testing::Message()
227 << "Iteration " << i << " "
228 << (nonempty_username_fields ? "nonempty" : "empty"));
230 // Repeat each test once with empty, and once with non-empty usernames.
231 // In the former case, no empty other_possible_usernames should be saved.
232 const char* names[3];
233 if (nonempty_username_fields) {
234 names[0] = "John";
235 names[1] = "William";
236 names[2] = "Smith";
237 } else {
238 names[0] = names[1] = names[2] = "";
241 PasswordFormBuilder builder(kTestFormActionURL);
242 builder.AddUsernameField("username1", names[0], cases[i].autocomplete[0]);
243 builder.AddUsernameField("username2", names[1], cases[i].autocomplete[1]);
244 builder.AddPasswordField("password", "secret", NULL);
245 builder.AddUsernameField("username3", names[2], cases[i].autocomplete[2]);
246 builder.AddPasswordField("password2", "othersecret", NULL);
247 builder.AddSubmitButton("submit", true);
248 std::string html = builder.ProduceHTML();
250 scoped_ptr<PasswordForm> password_form;
251 ASSERT_NO_FATAL_FAILURE(LoadHTMLAndConvertForm(html, &password_form));
252 ASSERT_TRUE(password_form);
254 EXPECT_EQ(base::UTF8ToUTF16(cases[i].expected_username_element),
255 password_form->username_element);
257 if (nonempty_username_fields) {
258 EXPECT_EQ(base::UTF8ToUTF16(cases[i].expected_username_value),
259 password_form->username_value);
260 EXPECT_EQ(base::UTF8ToUTF16(cases[i].expected_other_possible_usernames),
261 JoinString(password_form->other_possible_usernames, '+'));
262 } else {
263 EXPECT_TRUE(password_form->username_value.empty());
264 EXPECT_TRUE(password_form->other_possible_usernames.empty());
267 // Do a basic sanity check that we are still having a password field.
268 EXPECT_EQ(base::UTF8ToUTF16("password"), password_form->password_element);
269 EXPECT_EQ(base::UTF8ToUTF16("secret"), password_form->password_value);
274 TEST_F(PasswordFormConversionUtilsTest, IdentifyingTwoPasswordFields) {
275 // Each test case consists of a set of parameters to be plugged into the
276 // PasswordFormBuilder below, plus the corresponding expectations.
277 struct TestCase {
278 const char* password_values[2];
279 const char* expected_password_element;
280 const char* expected_password_value;
281 const char* expected_new_password_element;
282 const char* expected_new_password_value;
283 } cases[] = {
284 // Twp non-empty fields with the same value should be treated as a new
285 // password field plus a confirmation field for the new password.
286 {{"alpha", "alpha"}, "", "", "password1", "alpha"},
287 // The same goes if the fields are yet empty: we speculate that we will
288 // identify them as new password fields once they are filled out, and we
289 // want to keep our abstract interpretation of the form less flaky.
290 {{"", ""}, "", "", "password1", ""},
291 // Two different values should be treated as a password change form, one
292 // that also asks for the current password, but only once for the new.
293 {{"alpha", ""}, "password1", "alpha", "password2", ""},
294 {{"", "beta"}, "password1", "", "password2", "beta"},
295 {{"alpha", "beta"}, "password1", "alpha", "password2", "beta"}};
297 for (size_t i = 0; i < ARRAYSIZE_UNSAFE(cases); ++i) {
298 SCOPED_TRACE(testing::Message() << "Iteration " << i);
300 PasswordFormBuilder builder(kTestFormActionURL);
301 builder.AddPasswordField("password1", cases[i].password_values[0], NULL);
302 builder.AddUsernameField("username1", "William", NULL);
303 builder.AddPasswordField("password2", cases[i].password_values[1], NULL);
304 builder.AddUsernameField("username2", "Smith", NULL);
305 builder.AddSubmitButton("submit", true);
306 std::string html = builder.ProduceHTML();
308 scoped_ptr<PasswordForm> password_form;
309 ASSERT_NO_FATAL_FAILURE(LoadHTMLAndConvertForm(html, &password_form));
310 ASSERT_TRUE(password_form);
312 EXPECT_EQ(base::UTF8ToUTF16(cases[i].expected_password_element),
313 password_form->password_element);
314 EXPECT_EQ(base::UTF8ToUTF16(cases[i].expected_password_value),
315 password_form->password_value);
316 EXPECT_EQ(base::UTF8ToUTF16(cases[i].expected_new_password_element),
317 password_form->new_password_element);
318 EXPECT_EQ(base::UTF8ToUTF16(cases[i].expected_new_password_value),
319 password_form->new_password_value);
321 // Do a basic sanity check that we are still selecting the right username.
322 EXPECT_EQ(base::UTF8ToUTF16("username1"), password_form->username_element);
323 EXPECT_EQ(base::UTF8ToUTF16("William"), password_form->username_value);
324 EXPECT_THAT(password_form->other_possible_usernames,
325 testing::ElementsAre(base::UTF8ToUTF16("Smith")));
329 TEST_F(PasswordFormConversionUtilsTest, IdentifyingThreePasswordFields) {
330 // Each test case consists of a set of parameters to be plugged into the
331 // PasswordFormBuilder below, plus the corresponding expectations.
332 struct TestCase {
333 const char* password_values[3];
334 const char* expected_password_element;
335 const char* expected_password_value;
336 const char* expected_new_password_element;
337 const char* expected_new_password_value;
338 } cases[] = {
339 // Two fields with the same value, and one different: we should treat this
340 // as a password change form with confirmation for the new password. Note
341 // that we only recognize (current + new + new) and (new + new + current)
342 // without autocomplete attributes.
343 {{"alpha", "", ""}, "password1", "alpha", "password2", ""},
344 {{"", "beta", "beta"}, "password1", "", "password2", "beta"},
345 {{"alpha", "beta", "beta"}, "password1", "alpha", "password2", "beta"},
346 {{"beta", "beta", "alpha"}, "password3", "alpha", "password1", "beta"},
347 // If the fields are yet empty, we speculate that we will identify them as
348 // (current + new + new) once they are filled out, so we should classify
349 // them the same for now to keep our abstract interpretation less flaky.
350 {{"", "", ""}, "password1", "", "password2", ""}};
351 // Note: In all other cases, we give up and consider the form invalid.
352 // This is tested in InvalidFormDueToConfusingPasswordFields.
354 for (size_t i = 0; i < ARRAYSIZE_UNSAFE(cases); ++i) {
355 SCOPED_TRACE(testing::Message() << "Iteration " << i);
357 PasswordFormBuilder builder(kTestFormActionURL);
358 builder.AddPasswordField("password1", cases[i].password_values[0], NULL);
359 builder.AddUsernameField("username1", "William", NULL);
360 builder.AddPasswordField("password2", cases[i].password_values[1], NULL);
361 builder.AddUsernameField("username2", "Smith", NULL);
362 builder.AddPasswordField("password3", cases[i].password_values[2], NULL);
363 builder.AddSubmitButton("submit", true);
364 std::string html = builder.ProduceHTML();
366 scoped_ptr<PasswordForm> password_form;
367 ASSERT_NO_FATAL_FAILURE(LoadHTMLAndConvertForm(html, &password_form));
368 ASSERT_TRUE(password_form);
370 EXPECT_EQ(base::UTF8ToUTF16(cases[i].expected_password_element),
371 password_form->password_element);
372 EXPECT_EQ(base::UTF8ToUTF16(cases[i].expected_password_value),
373 password_form->password_value);
374 EXPECT_EQ(base::UTF8ToUTF16(cases[i].expected_new_password_element),
375 password_form->new_password_element);
376 EXPECT_EQ(base::UTF8ToUTF16(cases[i].expected_new_password_value),
377 password_form->new_password_value);
379 // Do a basic sanity check that we are still selecting the right username.
380 EXPECT_EQ(base::UTF8ToUTF16("username1"), password_form->username_element);
381 EXPECT_EQ(base::UTF8ToUTF16("William"), password_form->username_value);
382 EXPECT_THAT(password_form->other_possible_usernames,
383 testing::ElementsAre(base::UTF8ToUTF16("Smith")));
387 TEST_F(PasswordFormConversionUtilsTest,
388 IdentifyingPasswordFieldsWithAutocompleteAttributes) {
389 // Each test case consists of a set of parameters to be plugged into the
390 // PasswordFormBuilder below, plus the corresponding expectations.
391 struct TestCase {
392 const char* autocomplete[3];
393 const char* expected_password_element;
394 const char* expected_password_value;
395 const char* expected_new_password_element;
396 const char* expected_new_password_value;
397 } cases[] = {
398 // When there are elements marked with autocomplete='current-password',
399 // but no elements with 'new-password', we should treat the first of the
400 // former kind as the current password, and ignore all other password
401 // fields, assuming they are not intentionally not marked. They might be
402 // for other purposes, such as PINs, OTPs, and the like. Actual values in
403 // the password fields should be ignored in all cases below.
404 {{"current-password", NULL, NULL},
405 "password1", "alpha", "", ""},
406 {{NULL, "current-password", NULL},
407 "password2", "beta", "", ""},
408 {{NULL, NULL, "current-password"},
409 "password3", "gamma", "", ""},
410 {{NULL, "current-password", "current-password"},
411 "password2", "beta", "", ""},
412 {{"current-password", NULL, "current-password"},
413 "password1", "alpha", "", ""},
414 {{"current-password", "current-password", NULL},
415 "password1", "alpha", "", ""},
416 {{"current-password", "current-password", "current-password"},
417 "password1", "alpha", "", ""},
418 // The same goes vice versa for autocomplete='new-password'.
419 {{"new-password", NULL, NULL},
420 "", "", "password1", "alpha"},
421 {{NULL, "new-password", NULL},
422 "", "", "password2", "beta"},
423 {{NULL, NULL, "new-password"},
424 "", "", "password3", "gamma"},
425 {{NULL, "new-password", "new-password"},
426 "", "", "password2", "beta"},
427 {{"new-password", NULL, "new-password"},
428 "", "", "password1", "alpha"},
429 {{"new-password", "new-password", NULL},
430 "", "", "password1", "alpha"},
431 {{"new-password", "new-password", "new-password"},
432 "", "", "password1", "alpha"},
433 // When there is one element marked with autocomplete='current-password',
434 // and one with 'new-password', just comply, regardless of their order.
435 // Ignore the unmarked password field(s) for the same reason as above.
436 {{"current-password", "new-password", NULL},
437 "password1", "alpha", "password2", "beta"},
438 {{"current-password", NULL, "new-password"},
439 "password1", "alpha", "password3", "gamma"},
440 {{NULL, "current-password", "new-password"},
441 "password2", "beta", "password3", "gamma"},
442 {{"new-password", "current-password", NULL},
443 "password2", "beta", "password1", "alpha"},
444 {{"new-password", NULL, "current-password"},
445 "password3", "gamma", "password1", "alpha"},
446 {{NULL, "new-password", "current-password"},
447 "password3", "gamma", "password2", "beta"},
448 // In case of duplicated elements of either kind, go with the first one of
449 // its kind.
450 {{"current-password", "current-password", "new-password"},
451 "password1", "alpha", "password3", "gamma"},
452 {{"current-password", "new-password", "current-password"},
453 "password1", "alpha", "password2", "beta"},
454 {{"new-password", "current-password", "current-password"},
455 "password2", "beta", "password1", "alpha"},
456 {{"current-password", "new-password", "new-password"},
457 "password1", "alpha", "password2", "beta"},
458 {{"new-password", "current-password", "new-password"},
459 "password2", "beta", "password1", "alpha"},
460 {{"new-password", "new-password", "current-password"},
461 "password3", "gamma", "password1", "alpha"},
462 // When there is an empty autocomplete attribute (i.e. autocomplete=""),
463 // it should have the same effect as having no attribute whatsoever.
464 {{"current-password", "", ""},
465 "password1", "alpha", "", ""},
466 {{"", "", "new-password"},
467 "", "", "password3", "gamma"},
468 {{"", "new-password", ""},
469 "", "", "password2", "beta"},
470 {{"", "current-password", "current-password"},
471 "password2", "beta", "", ""},
472 {{"new-password", "", "new-password"},
473 "", "", "password1", "alpha"},
474 {{"new-password", "", "current-password"},
475 "password3", "gamma", "password1", "alpha"},
476 // It should not matter if attribute values are upper or mixed case.
477 {{NULL, "current-password", NULL},
478 "password2", "beta", "", ""},
479 {{NULL, "CURRENT-PASSWORD", NULL},
480 "password2", "beta", "", ""},
481 {{NULL, "new-password", NULL},
482 "", "", "password2", "beta"},
483 {{NULL, "nEw-PaSsWoRd", NULL},
484 "", "", "password2", "beta"}};
486 for (size_t i = 0; i < ARRAYSIZE_UNSAFE(cases); ++i) {
487 SCOPED_TRACE(testing::Message() << "Iteration " << i);
489 PasswordFormBuilder builder(kTestFormActionURL);
490 builder.AddPasswordField("pin1", "123456", NULL);
491 builder.AddPasswordField("pin2", "789101", NULL);
492 builder.AddPasswordField("password1", "alpha", cases[i].autocomplete[0]);
493 builder.AddUsernameField("username1", "William", NULL);
494 builder.AddPasswordField("password2", "beta", cases[i].autocomplete[1]);
495 builder.AddUsernameField("username2", "Smith", NULL);
496 builder.AddPasswordField("password3", "gamma", cases[i].autocomplete[2]);
497 builder.AddSubmitButton("submit", true);
498 std::string html = builder.ProduceHTML();
500 scoped_ptr<PasswordForm> password_form;
501 ASSERT_NO_FATAL_FAILURE(LoadHTMLAndConvertForm(html, &password_form));
502 ASSERT_TRUE(password_form);
504 // In the absence of username autocomplete attributes, the username should
505 // be the text input field before the first password element.
506 // No constellation of password autocomplete attributes should change that.
507 EXPECT_EQ(base::UTF8ToUTF16("username1"), password_form->username_element);
508 EXPECT_EQ(base::UTF8ToUTF16("William"), password_form->username_value);
509 EXPECT_THAT(password_form->other_possible_usernames,
510 testing::ElementsAre(base::UTF8ToUTF16("Smith")));
511 EXPECT_EQ(base::UTF8ToUTF16(cases[i].expected_password_element),
512 password_form->password_element);
513 EXPECT_EQ(base::UTF8ToUTF16(cases[i].expected_password_value),
514 password_form->password_value);
515 EXPECT_EQ(base::UTF8ToUTF16(cases[i].expected_new_password_element),
516 password_form->new_password_element);
517 EXPECT_EQ(base::UTF8ToUTF16(cases[i].expected_new_password_value),
518 password_form->new_password_value);
522 TEST_F(PasswordFormConversionUtilsTest, InvalidFormDueToBadActionURL) {
523 PasswordFormBuilder builder("invalid_target");
524 builder.AddUsernameField("username", "JohnSmith", NULL);
525 builder.AddSubmitButton("submit", true);
526 builder.AddPasswordField("password", "secret", NULL);
527 std::string html = builder.ProduceHTML();
529 scoped_ptr<PasswordForm> password_form;
530 ASSERT_NO_FATAL_FAILURE(LoadHTMLAndConvertForm(html, &password_form));
531 EXPECT_FALSE(password_form);
534 TEST_F(PasswordFormConversionUtilsTest, InvalidFormDueToNoPasswordFields) {
535 PasswordFormBuilder builder(kTestFormActionURL);
536 builder.AddUsernameField("username1", "John", NULL);
537 builder.AddUsernameField("username2", "Smith", NULL);
538 builder.AddSubmitButton("submit", true);
539 std::string html = builder.ProduceHTML();
541 scoped_ptr<PasswordForm> password_form;
542 ASSERT_NO_FATAL_FAILURE(LoadHTMLAndConvertForm(html, &password_form));
543 EXPECT_FALSE(password_form);
546 TEST_F(PasswordFormConversionUtilsTest,
547 InvalidFormsDueToConfusingPasswordFields) {
548 // Each test case consists of a set of parameters to be plugged into the
549 // PasswordFormBuilder below.
550 const char* cases[][3] = {
551 // No autocomplete attributes to guide us, and we see:
552 // * three password values that are all different,
553 // * three password values that are all the same;
554 // * three password values with the first and last matching.
555 // In any case, we should just give up on this form.
556 {"alpha", "beta", "gamma"},
557 {"alpha", "alpha", "alpha"},
558 {"alpha", "beta", "alpha"}};
560 for (size_t i = 0; i < ARRAYSIZE_UNSAFE(cases); ++i) {
561 SCOPED_TRACE(testing::Message() << "Iteration " << i);
563 PasswordFormBuilder builder(kTestFormActionURL);
564 builder.AddUsernameField("username1", "John", NULL);
565 builder.AddPasswordField("password1", cases[i][0], NULL);
566 builder.AddPasswordField("password2", cases[i][1], NULL);
567 builder.AddPasswordField("password3", cases[i][2], NULL);
568 builder.AddSubmitButton("submit", true);
569 std::string html = builder.ProduceHTML();
571 scoped_ptr<PasswordForm> password_form;
572 ASSERT_NO_FATAL_FAILURE(LoadHTMLAndConvertForm(html, &password_form));
573 EXPECT_FALSE(password_form);
577 TEST_F(PasswordFormConversionUtilsTest,
578 InvalidFormDueToTooManyPasswordFieldsWithoutAutocompleteAttributes) {
579 PasswordFormBuilder builder(kTestFormActionURL);
580 builder.AddUsernameField("username1", "John", NULL);
581 builder.AddPasswordField("password1", "alpha", NULL);
582 builder.AddPasswordField("password2", "alpha", NULL);
583 builder.AddPasswordField("password3", "alpha", NULL);
584 builder.AddPasswordField("password4", "alpha", NULL);
585 builder.AddSubmitButton("submit", true);
586 std::string html = builder.ProduceHTML();
588 scoped_ptr<PasswordForm> password_form;
589 ASSERT_NO_FATAL_FAILURE(LoadHTMLAndConvertForm(html, &password_form));
590 EXPECT_FALSE(password_form);
593 } // namespace autofill