Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(177)

Side by Side Diff: components/autofill/content/renderer/password_form_conversion_utils_browsertest.cc

Issue 372683003: Clean up PasswordFormConversionUtilsTest and add some missing tests. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Rebase. Created 6 years, 5 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « components/autofill/content/renderer/password_form_conversion_utils.cc ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright 2013 The Chromium Authors. All rights reserved. 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 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "base/strings/string16.h" 5 #include "base/strings/string16.h"
6 #include "base/strings/string_util.h" 6 #include "base/strings/string_util.h"
7 #include "base/strings/stringprintf.h" 7 #include "base/strings/stringprintf.h"
8 #include "base/strings/utf_string_conversions.h" 8 #include "base/strings/utf_string_conversions.h"
9 #include "components/autofill/content/renderer/password_form_conversion_utils.h" 9 #include "components/autofill/content/renderer/password_form_conversion_utils.h"
10 #include "components/autofill/core/common/password_form.h" 10 #include "components/autofill/core/common/password_form.h"
11 #include "content/public/test/render_view_test.h" 11 #include "content/public/test/render_view_test.h"
12 #include "testing/gmock/include/gmock/gmock.h"
12 #include "testing/gtest/include/gtest/gtest.h" 13 #include "testing/gtest/include/gtest/gtest.h"
13 #include "third_party/WebKit/public/platform/WebVector.h" 14 #include "third_party/WebKit/public/platform/WebVector.h"
14 #include "third_party/WebKit/public/web/WebDocument.h" 15 #include "third_party/WebKit/public/web/WebDocument.h"
16 #include "third_party/WebKit/public/web/WebFormControlElement.h"
15 #include "third_party/WebKit/public/web/WebFormElement.h" 17 #include "third_party/WebKit/public/web/WebFormElement.h"
18 #include "third_party/WebKit/public/web/WebInputElement.h"
16 #include "third_party/WebKit/public/web/WebLocalFrame.h" 19 #include "third_party/WebKit/public/web/WebLocalFrame.h"
17 20
21 using blink::WebFormControlElement;
18 using blink::WebFormElement; 22 using blink::WebFormElement;
19 using blink::WebFrame; 23 using blink::WebFrame;
24 using blink::WebInputElement;
20 using blink::WebVector; 25 using blink::WebVector;
21 26
22 namespace autofill { 27 namespace autofill {
23 namespace { 28 namespace {
24 29
25 const char kTestFormActionURL[] = "http://cnn.com"; 30 const char kTestFormActionURL[] = "http://cnn.com";
26 31
27 // A builder to produce HTML code for a password form composed of the desired 32 // A builder to produce HTML code for a password form composed of the desired
28 // number and kinds of username and password fields. 33 // number and kinds of username and password fields.
29 class PasswordFormBuilder { 34 class PasswordFormBuilder {
(...skipping 28 matching lines...) Expand all
58 const char* value, 63 const char* value,
59 const char* autocomplete) { 64 const char* autocomplete) {
60 std::string autocomplete_attribute(autocomplete ? 65 std::string autocomplete_attribute(autocomplete ?
61 base::StringPrintf("autocomplete=\"%s\"", autocomplete): ""); 66 base::StringPrintf("autocomplete=\"%s\"", autocomplete): "");
62 base::StringAppendF( 67 base::StringAppendF(
63 &html_, 68 &html_,
64 "<INPUT type=\"password\" name=\"%s\" id=\"%s\" value=\"%s\" %s/>", 69 "<INPUT type=\"password\" name=\"%s\" id=\"%s\" value=\"%s\" %s/>",
65 name_and_id, name_and_id, value, autocomplete_attribute.c_str()); 70 name_and_id, name_and_id, value, autocomplete_attribute.c_str());
66 } 71 }
67 72
68 // Appends a new submit-type field at the end of the form. 73 // Appends a disabled text-type field at the end of the form.
69 void AddSubmitButton() { 74 void AddDisabledUsernameField() {
70 html_ += "<INPUT type=\"submit\" name=\"submit\" value=\"Submit\"/>"; 75 html_ += "<INPUT type=\"text\" disabled/>";
76 }
77
78 // Appends a disabled password-type field at the end of the form.
79 void AddDisabledPasswordField() {
80 html_ += "<INPUT type=\"password\" disabled/>";
81 }
82
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" : "");
71 } 91 }
72 92
73 // Returns the HTML code for the form containing the fields that have been 93 // Returns the HTML code for the form containing the fields that have been
74 // added so far. 94 // added so far.
75 std::string ProduceHTML() const { 95 std::string ProduceHTML() const {
76 return html_ + "</FORM>"; 96 return html_ + "</FORM>";
77 } 97 }
78 98
79 private: 99 private:
80 std::string html_; 100 std::string html_;
(...skipping 15 matching lines...) Expand all
96 scoped_ptr<PasswordForm>* password_form) { 116 scoped_ptr<PasswordForm>* password_form) {
97 LoadHTML(html.c_str()); 117 LoadHTML(html.c_str());
98 118
99 WebFrame* frame = GetMainFrame(); 119 WebFrame* frame = GetMainFrame();
100 ASSERT_NE(static_cast<WebFrame*>(NULL), frame); 120 ASSERT_NE(static_cast<WebFrame*>(NULL), frame);
101 121
102 WebVector<WebFormElement> forms; 122 WebVector<WebFormElement> forms;
103 frame->document().forms(forms); 123 frame->document().forms(forms);
104 ASSERT_EQ(1U, forms.size()); 124 ASSERT_EQ(1U, forms.size());
105 125
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);
132 }
133
106 *password_form = CreatePasswordForm(forms[0]); 134 *password_form = CreatePasswordForm(forms[0]);
107 } 135 }
108 136
109 private: 137 private:
110 DISALLOW_COPY_AND_ASSIGN(PasswordFormConversionUtilsTest); 138 DISALLOW_COPY_AND_ASSIGN(PasswordFormConversionUtilsTest);
111 }; 139 };
112 140
113 } // namespace 141 } // namespace
114 142
115 TEST_F(PasswordFormConversionUtilsTest, ValidWebFormElementToPasswordForm) { 143 TEST_F(PasswordFormConversionUtilsTest, BasicFormAttributes) {
116 PasswordFormBuilder builder(kTestFormActionURL); 144 PasswordFormBuilder builder(kTestFormActionURL);
117 builder.AddUsernameField("username", "johnsmith", NULL); 145 builder.AddUsernameField("username", "johnsmith", NULL);
118 builder.AddSubmitButton(); 146 builder.AddSubmitButton("inactive_submit", false);
147 builder.AddSubmitButton("active_submit", true);
148 builder.AddSubmitButton("inactive_submit2", false);
119 builder.AddPasswordField("password", "secret", NULL); 149 builder.AddPasswordField("password", "secret", NULL);
120 std::string html = builder.ProduceHTML(); 150 std::string html = builder.ProduceHTML();
121 151
122 scoped_ptr<PasswordForm> password_form; 152 scoped_ptr<PasswordForm> password_form;
123 ASSERT_NO_FATAL_FAILURE(LoadHTMLAndConvertForm(html, &password_form)); 153 ASSERT_NO_FATAL_FAILURE(LoadHTMLAndConvertForm(html, &password_form));
124 ASSERT_NE(static_cast<PasswordForm*>(NULL), password_form.get()); 154 ASSERT_TRUE(password_form);
125 155
126 EXPECT_EQ("data:", password_form->signon_realm); 156 EXPECT_EQ("data:", password_form->signon_realm);
127 EXPECT_EQ(GURL(kTestFormActionURL), password_form->action); 157 EXPECT_EQ(GURL(kTestFormActionURL), password_form->action);
158 EXPECT_EQ(base::UTF8ToUTF16("active_submit"), password_form->submit_element);
128 EXPECT_EQ(base::UTF8ToUTF16("username"), password_form->username_element); 159 EXPECT_EQ(base::UTF8ToUTF16("username"), password_form->username_element);
129 EXPECT_EQ(base::UTF8ToUTF16("johnsmith"), password_form->username_value); 160 EXPECT_EQ(base::UTF8ToUTF16("johnsmith"), password_form->username_value);
130 EXPECT_EQ(base::UTF8ToUTF16("password"), password_form->password_element); 161 EXPECT_EQ(base::UTF8ToUTF16("password"), password_form->password_element);
131 EXPECT_EQ(base::UTF8ToUTF16("secret"), password_form->password_value); 162 EXPECT_EQ(base::UTF8ToUTF16("secret"), password_form->password_value);
132 EXPECT_EQ(PasswordForm::SCHEME_HTML, password_form->scheme); 163 EXPECT_EQ(PasswordForm::SCHEME_HTML, password_form->scheme);
133 EXPECT_FALSE(password_form->ssl_valid); 164 EXPECT_FALSE(password_form->ssl_valid);
134 EXPECT_FALSE(password_form->preferred); 165 EXPECT_FALSE(password_form->preferred);
135 EXPECT_FALSE(password_form->blacklisted_by_user); 166 EXPECT_FALSE(password_form->blacklisted_by_user);
136 EXPECT_EQ(PasswordForm::TYPE_MANUAL, password_form->type); 167 EXPECT_EQ(PasswordForm::TYPE_MANUAL, password_form->type);
168 EXPECT_FALSE(password_form->use_additional_authentication);
137 } 169 }
138 170
139 TEST_F(PasswordFormConversionUtilsTest, InvalidWebFormElementToPasswordForm) { 171 TEST_F(PasswordFormConversionUtilsTest, DisabledFieldsAreIgnored) {
140 PasswordFormBuilder builder("invalid_target"); 172 PasswordFormBuilder builder(kTestFormActionURL);
141 builder.AddUsernameField("username", "johnsmith", NULL); 173 builder.AddUsernameField("username", "johnsmith", NULL);
142 builder.AddSubmitButton(); 174 builder.AddDisabledUsernameField();
175 builder.AddDisabledPasswordField();
143 builder.AddPasswordField("password", "secret", NULL); 176 builder.AddPasswordField("password", "secret", NULL);
177 builder.AddSubmitButton("submit", true);
144 std::string html = builder.ProduceHTML(); 178 std::string html = builder.ProduceHTML();
145 179
146 scoped_ptr<PasswordForm> password_form; 180 scoped_ptr<PasswordForm> password_form;
147 ASSERT_NO_FATAL_FAILURE(LoadHTMLAndConvertForm(html, &password_form)); 181 ASSERT_NO_FATAL_FAILURE(LoadHTMLAndConvertForm(html, &password_form));
148 ASSERT_EQ(static_cast<PasswordForm*>(NULL), password_form.get()); 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);
149 } 187 }
150 188
151 TEST_F(PasswordFormConversionUtilsTest, 189 TEST_F(PasswordFormConversionUtilsTest, IdentifyingUsernameFields) {
152 WebFormWithMultipleUseNameAndPassWordFieldsToPasswordForm) {
153 PasswordFormBuilder builder(kTestFormActionURL);
154 builder.AddUsernameField("username1", "John", NULL);
155 builder.AddPasswordField("password1", "oldsecret", NULL);
156 builder.AddUsernameField("username2", "William", NULL);
157 builder.AddPasswordField("password2", "secret", NULL);
158 builder.AddUsernameField("username3", "Smith", NULL);
159 builder.AddPasswordField("password3", "secret", NULL);
160 builder.AddSubmitButton();
161 std::string html = builder.ProduceHTML();
162
163 scoped_ptr<PasswordForm> password_form;
164 ASSERT_NO_FATAL_FAILURE(LoadHTMLAndConvertForm(html, &password_form));
165 ASSERT_NE(static_cast<PasswordForm*>(NULL), password_form.get());
166
167 EXPECT_EQ("data:", password_form->signon_realm);
168 EXPECT_EQ(GURL(kTestFormActionURL), password_form->action);
169 EXPECT_EQ(base::UTF8ToUTF16("username1"), password_form->username_element);
170 EXPECT_EQ(base::UTF8ToUTF16("John"), password_form->username_value);
171 EXPECT_EQ(base::UTF8ToUTF16("password1"),
172 password_form->password_element);
173 EXPECT_EQ(base::UTF8ToUTF16("oldsecret"), password_form->password_value);
174 EXPECT_EQ(base::UTF8ToUTF16("password2"),
175 password_form->new_password_element);
176 EXPECT_EQ(base::UTF8ToUTF16("secret"), password_form->new_password_value);
177 ASSERT_EQ(2u, password_form->other_possible_usernames.size());
178 EXPECT_EQ(base::UTF8ToUTF16("William"),
179 password_form->other_possible_usernames[0]);
180 EXPECT_EQ(base::UTF8ToUTF16("Smith"),
181 password_form->other_possible_usernames[1]);
182 EXPECT_EQ(PasswordForm::SCHEME_HTML, password_form->scheme);
183 EXPECT_FALSE(password_form->ssl_valid);
184 EXPECT_FALSE(password_form->preferred);
185 EXPECT_FALSE(password_form->blacklisted_by_user);
186 EXPECT_EQ(PasswordForm::TYPE_MANUAL, password_form->type);
187 }
188
189 TEST_F(PasswordFormConversionUtilsTest,
190 WebFormwithThreeDifferentPasswordsToPasswordForm) {
191 PasswordFormBuilder builder(kTestFormActionURL);
192 builder.AddUsernameField("username1", "John", NULL);
193 builder.AddPasswordField("password1", "alpha", NULL);
194 builder.AddPasswordField("password2", "beta", NULL);
195 builder.AddPasswordField("password3", "gamma", NULL);
196 builder.AddSubmitButton();
197 std::string html = builder.ProduceHTML();
198
199 scoped_ptr<PasswordForm> password_form;
200 ASSERT_NO_FATAL_FAILURE(LoadHTMLAndConvertForm(html, &password_form));
201 ASSERT_EQ(static_cast<PasswordForm*>(NULL), password_form.get());
202 }
203
204 TEST_F(PasswordFormConversionUtilsTest,
205 UsernameFieldsWithAutocompleteAttributes) {
206 // Each test case consists of a set of parameters to be plugged into the 190 // Each test case consists of a set of parameters to be plugged into the
207 // PasswordFormBuilder below, plus the corresponding expectations. 191 // PasswordFormBuilder below, plus the corresponding expectations.
208 struct TestCase { 192 struct TestCase {
209 const char* autocomplete[3]; 193 const char* autocomplete[3];
210 const char* expected_username_element; 194 const char* expected_username_element;
211 const char* expected_username_value; 195 const char* expected_username_value;
212 const char* expected_other_possible_usernames; 196 const char* expected_other_possible_usernames;
213 } cases[] = { 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"},
214 // When a sole element is marked with autocomplete='username', it should 202 // When a sole element is marked with autocomplete='username', it should
215 // be treated as the username for sure, with no other_possible_usernames. 203 // be treated as the username for sure, with no other_possible_usernames.
216 {{"username", NULL, NULL}, "username1", "John", ""}, 204 {{"username", NULL, NULL}, "username1", "John", ""},
217 {{NULL, "username", NULL}, "username2", "William", ""}, 205 {{NULL, "username", NULL}, "username2", "William", ""},
218 {{NULL, NULL, "username"}, "username3", "Smith", ""}, 206 {{NULL, NULL, "username"}, "username3", "Smith", ""},
219 // When >=2 elements have the attribute, the first should be selected as 207 // When >=2 elements have the attribute, the first should be selected as
220 // the username, and the rest should go to other_possible_usernames. 208 // the username, and the rest should go to other_possible_usernames.
221 {{"username", "username", NULL}, "username1", "John", "William"}, 209 {{"username", "username", NULL}, "username1", "John", "William"},
222 {{NULL, "username", "username"}, "username2", "William", "Smith"}, 210 {{NULL, "username", "username"}, "username2", "William", "Smith"},
223 {{"username", NULL, "username"}, "username1", "John", "Smith"}, 211 {{"username", NULL, "username"}, "username1", "John", "Smith"},
224 {{"username", "username", "username"}, "username1", "John", 212 {{"username", "username", "username"}, "username1", "John",
225 "William+Smith"}, 213 "William+Smith"},
226 // When there is an empty autocomplete attribute (i.e. autocomplete=""), 214 // When there is an empty autocomplete attribute (i.e. autocomplete=""),
227 // it should have the same effect as having no attribute whatsoever. 215 // it should have the same effect as having no attribute whatsoever.
228 {{"", "", ""}, "username2", "William", "John+Smith"}, 216 {{"", "", ""}, "username2", "William", "John+Smith"},
229 {{"", "", "username"}, "username3", "Smith", ""}, 217 {{"", "", "username"}, "username3", "Smith", ""},
230 {{"username", "", "username"}, "username1", "John", "Smith"}, 218 {{"username", "", "username"}, "username1", "John", "Smith"},
231 // It should not matter if attribute values are upper or mixed case. 219 // It should not matter if attribute values are upper or mixed case.
232 {{"USERNAME", NULL, "uSeRNaMe"}, "username1", "John", "Smith"}, 220 {{"USERNAME", NULL, "uSeRNaMe"}, "username1", "John", "Smith"},
233 {{"uSeRNaMe", NULL, "USERNAME"}, "username1", "John", "Smith"}}; 221 {{"uSeRNaMe", NULL, "USERNAME"}, "username1", "John", "Smith"}};
234 222
235 for (size_t i = 0; i < ARRAYSIZE_UNSAFE(cases); ++i) { 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"));
229
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] = "";
239 }
240
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();
249
250 scoped_ptr<PasswordForm> password_form;
251 ASSERT_NO_FATAL_FAILURE(LoadHTMLAndConvertForm(html, &password_form));
252 ASSERT_TRUE(password_form);
253
254 EXPECT_EQ(base::UTF8ToUTF16(cases[i].expected_username_element),
255 password_form->username_element);
256
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());
265 }
266
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);
270 }
271 }
272 }
273
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"}};
296
297 for (size_t i = 0; i < ARRAYSIZE_UNSAFE(cases); ++i) {
236 SCOPED_TRACE(testing::Message() << "Iteration " << i); 298 SCOPED_TRACE(testing::Message() << "Iteration " << i);
237 299
238 PasswordFormBuilder builder(kTestFormActionURL); 300 PasswordFormBuilder builder(kTestFormActionURL);
239 builder.AddUsernameField("username1", "John", cases[i].autocomplete[0]); 301 builder.AddPasswordField("password1", cases[i].password_values[0], NULL);
240 builder.AddUsernameField("username2", "William", cases[i].autocomplete[1]); 302 builder.AddUsernameField("username1", "William", NULL);
241 builder.AddPasswordField("password", "secret", NULL); 303 builder.AddPasswordField("password2", cases[i].password_values[1], NULL);
242 builder.AddUsernameField("username3", "Smith", cases[i].autocomplete[2]); 304 builder.AddUsernameField("username2", "Smith", NULL);
243 builder.AddSubmitButton(); 305 builder.AddSubmitButton("submit", true);
244 std::string html = builder.ProduceHTML(); 306 std::string html = builder.ProduceHTML();
245 307
246 scoped_ptr<PasswordForm> password_form; 308 scoped_ptr<PasswordForm> password_form;
247 ASSERT_NO_FATAL_FAILURE(LoadHTMLAndConvertForm(html, &password_form)); 309 ASSERT_NO_FATAL_FAILURE(LoadHTMLAndConvertForm(html, &password_form));
248 ASSERT_NE(static_cast<PasswordForm*>(NULL), password_form.get()); 310 ASSERT_TRUE(password_form);
249 311
250 EXPECT_EQ(base::UTF8ToUTF16(cases[i].expected_username_element), 312 EXPECT_EQ(base::UTF8ToUTF16(cases[i].expected_password_element),
251 password_form->username_element); 313 password_form->password_element);
252 EXPECT_EQ(base::UTF8ToUTF16(cases[i].expected_username_value), 314 EXPECT_EQ(base::UTF8ToUTF16(cases[i].expected_password_value),
253 password_form->username_value); 315 password_form->password_value);
254 EXPECT_EQ(base::UTF8ToUTF16("password"), password_form->password_element); 316 EXPECT_EQ(base::UTF8ToUTF16(cases[i].expected_new_password_element),
255 EXPECT_EQ(base::UTF8ToUTF16("secret"), password_form->password_value); 317 password_form->new_password_element);
256 EXPECT_EQ(base::UTF8ToUTF16(cases[i].expected_other_possible_usernames), 318 EXPECT_EQ(base::UTF8ToUTF16(cases[i].expected_new_password_value),
257 JoinString(password_form->other_possible_usernames, '+')); 319 password_form->new_password_value);
320
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")));
326 }
327 }
328
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.
353
354 for (size_t i = 0; i < ARRAYSIZE_UNSAFE(cases); ++i) {
355 SCOPED_TRACE(testing::Message() << "Iteration " << i);
356
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();
365
366 scoped_ptr<PasswordForm> password_form;
367 ASSERT_NO_FATAL_FAILURE(LoadHTMLAndConvertForm(html, &password_form));
368 ASSERT_TRUE(password_form);
369
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);
378
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")));
258 } 384 }
259 } 385 }
260 386
261 TEST_F(PasswordFormConversionUtilsTest, 387 TEST_F(PasswordFormConversionUtilsTest,
262 PasswordFieldsWithAutocompleteAttributes) { 388 IdentifyingPasswordFieldsWithAutocompleteAttributes) {
263 // Each test case consists of a set of parameters to be plugged into the 389 // Each test case consists of a set of parameters to be plugged into the
264 // PasswordFormBuilder below, plus the corresponding expectations. 390 // PasswordFormBuilder below, plus the corresponding expectations.
265 struct TestCase { 391 struct TestCase {
266 const char* autocomplete[3]; 392 const char* autocomplete[3];
267 const char* expected_password_element; 393 const char* expected_password_element;
268 const char* expected_password_value; 394 const char* expected_password_value;
269 const char* expected_new_password_element; 395 const char* expected_new_password_element;
270 const char* expected_new_password_value; 396 const char* expected_new_password_value;
271 } cases[] = { 397 } cases[] = {
272 // When there are elements marked with autocomplete='current-password', 398 // When there are elements marked with autocomplete='current-password',
(...skipping 81 matching lines...) Expand 10 before | Expand all | Expand 10 after
354 "password2", "beta", "", ""}, 480 "password2", "beta", "", ""},
355 {{NULL, "new-password", NULL}, 481 {{NULL, "new-password", NULL},
356 "", "", "password2", "beta"}, 482 "", "", "password2", "beta"},
357 {{NULL, "nEw-PaSsWoRd", NULL}, 483 {{NULL, "nEw-PaSsWoRd", NULL},
358 "", "", "password2", "beta"}}; 484 "", "", "password2", "beta"}};
359 485
360 for (size_t i = 0; i < ARRAYSIZE_UNSAFE(cases); ++i) { 486 for (size_t i = 0; i < ARRAYSIZE_UNSAFE(cases); ++i) {
361 SCOPED_TRACE(testing::Message() << "Iteration " << i); 487 SCOPED_TRACE(testing::Message() << "Iteration " << i);
362 488
363 PasswordFormBuilder builder(kTestFormActionURL); 489 PasswordFormBuilder builder(kTestFormActionURL);
490 builder.AddPasswordField("pin1", "123456", NULL);
491 builder.AddPasswordField("pin2", "789101", NULL);
364 builder.AddPasswordField("password1", "alpha", cases[i].autocomplete[0]); 492 builder.AddPasswordField("password1", "alpha", cases[i].autocomplete[0]);
365 builder.AddUsernameField("username1", "William", NULL); 493 builder.AddUsernameField("username1", "William", NULL);
366 builder.AddPasswordField("password2", "beta", cases[i].autocomplete[1]); 494 builder.AddPasswordField("password2", "beta", cases[i].autocomplete[1]);
367 builder.AddUsernameField("username2", "Smith", NULL); 495 builder.AddUsernameField("username2", "Smith", NULL);
368 builder.AddPasswordField("password3", "gamma", cases[i].autocomplete[2]); 496 builder.AddPasswordField("password3", "gamma", cases[i].autocomplete[2]);
369 builder.AddSubmitButton(); 497 builder.AddSubmitButton("submit", true);
370 std::string html = builder.ProduceHTML(); 498 std::string html = builder.ProduceHTML();
371 499
372 scoped_ptr<PasswordForm> password_form; 500 scoped_ptr<PasswordForm> password_form;
373 ASSERT_NO_FATAL_FAILURE(LoadHTMLAndConvertForm(html, &password_form)); 501 ASSERT_NO_FATAL_FAILURE(LoadHTMLAndConvertForm(html, &password_form));
374 ASSERT_NE(static_cast<PasswordForm*>(NULL), password_form.get()); 502 ASSERT_TRUE(password_form);
375 503
376 // Any constellation of password autocomplete attributes should have no 504 // In the absence of username autocomplete attributes, the username should
377 // effect on that the first text-type input field before a password field 505 // be the text input field before the first password element.
378 // should be selected as the username. 506 // No constellation of password autocomplete attributes should change that.
379 EXPECT_EQ(base::UTF8ToUTF16("username1"), password_form->username_element); 507 EXPECT_EQ(base::UTF8ToUTF16("username1"), password_form->username_element);
380 EXPECT_EQ(base::UTF8ToUTF16("William"), password_form->username_value); 508 EXPECT_EQ(base::UTF8ToUTF16("William"), password_form->username_value);
509 EXPECT_THAT(password_form->other_possible_usernames,
510 testing::ElementsAre(base::UTF8ToUTF16("Smith")));
381 EXPECT_EQ(base::UTF8ToUTF16(cases[i].expected_password_element), 511 EXPECT_EQ(base::UTF8ToUTF16(cases[i].expected_password_element),
382 password_form->password_element); 512 password_form->password_element);
383 EXPECT_EQ(base::UTF8ToUTF16(cases[i].expected_password_value), 513 EXPECT_EQ(base::UTF8ToUTF16(cases[i].expected_password_value),
384 password_form->password_value); 514 password_form->password_value);
385 EXPECT_EQ(base::UTF8ToUTF16(cases[i].expected_new_password_element), 515 EXPECT_EQ(base::UTF8ToUTF16(cases[i].expected_new_password_element),
386 password_form->new_password_element); 516 password_form->new_password_element);
387 EXPECT_EQ(base::UTF8ToUTF16(cases[i].expected_new_password_value), 517 EXPECT_EQ(base::UTF8ToUTF16(cases[i].expected_new_password_value),
388 password_form->new_password_value); 518 password_form->new_password_value);
389 ASSERT_EQ(1u, password_form->other_possible_usernames.size());
390 EXPECT_EQ(base::UTF8ToUTF16("Smith"),
391 password_form->other_possible_usernames[0]);
392 } 519 }
393 } 520 }
394 521
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();
528
529 scoped_ptr<PasswordForm> password_form;
530 ASSERT_NO_FATAL_FAILURE(LoadHTMLAndConvertForm(html, &password_form));
531 EXPECT_FALSE(password_form);
532 }
533
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();
540
541 scoped_ptr<PasswordForm> password_form;
542 ASSERT_NO_FATAL_FAILURE(LoadHTMLAndConvertForm(html, &password_form));
543 EXPECT_FALSE(password_form);
544 }
545
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"}};
559
560 for (size_t i = 0; i < ARRAYSIZE_UNSAFE(cases); ++i) {
561 SCOPED_TRACE(testing::Message() << "Iteration " << i);
562
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();
570
571 scoped_ptr<PasswordForm> password_form;
572 ASSERT_NO_FATAL_FAILURE(LoadHTMLAndConvertForm(html, &password_form));
573 EXPECT_FALSE(password_form);
574 }
575 }
576
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();
587
588 scoped_ptr<PasswordForm> password_form;
589 ASSERT_NO_FATAL_FAILURE(LoadHTMLAndConvertForm(html, &password_form));
590 EXPECT_FALSE(password_form);
591 }
592
395 } // namespace autofill 593 } // namespace autofill
OLDNEW
« no previous file with comments | « components/autofill/content/renderer/password_form_conversion_utils.cc ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698