| OLD | NEW |
| 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" |
| (...skipping 21 matching lines...) Expand all Loading... |
| 32 // specified |action| URL. | 32 // specified |action| URL. |
| 33 explicit PasswordFormBuilder(const char* action) { | 33 explicit PasswordFormBuilder(const char* action) { |
| 34 base::StringAppendF( | 34 base::StringAppendF( |
| 35 &html_, "<FORM name=\"Test\" action=\"%s\" method=\"post\">", action); | 35 &html_, "<FORM name=\"Test\" action=\"%s\" method=\"post\">", action); |
| 36 } | 36 } |
| 37 | 37 |
| 38 // Appends a new text-type field at the end of the form, having the specified | 38 // Appends a new text-type field at the end of the form, having the specified |
| 39 // |name_and_id|, |value|, and |autocomplete| attributes. The |autocomplete| | 39 // |name_and_id|, |value|, and |autocomplete| attributes. The |autocomplete| |
| 40 // argument can take two special values, namely: | 40 // argument can take two special values, namely: |
| 41 // 1.) NULL, causing no autocomplete attribute to be added, | 41 // 1.) NULL, causing no autocomplete attribute to be added, |
| 42 // 2.) "", causing an empty attribute (i.e. autocomplete='') to be added. | 42 // 2.) "", causing an empty attribute (i.e. autocomplete="") to be added. |
| 43 void AddUsernameField(const char* name_and_id, | 43 void AddUsernameField(const char* name_and_id, |
| 44 const char* value, | 44 const char* value, |
| 45 const char* autocomplete) { | 45 const char* autocomplete) { |
| 46 std::string autocomplete_attribute(autocomplete != NULL ? | 46 std::string autocomplete_attribute(autocomplete ? |
| 47 base::StringPrintf("autocomplete=\"%s\"", autocomplete) : ""); | 47 base::StringPrintf("autocomplete=\"%s\"", autocomplete) : ""); |
| 48 base::StringAppendF( | 48 base::StringAppendF( |
| 49 &html_, | 49 &html_, |
| 50 "<INPUT type=\"text\" name=\"%s\" id=\"%s\" value=\"%s\" %s/>", | 50 "<INPUT type=\"text\" name=\"%s\" id=\"%s\" value=\"%s\" %s/>", |
| 51 name_and_id, name_and_id, value, autocomplete_attribute.c_str()); | 51 name_and_id, name_and_id, value, autocomplete_attribute.c_str()); |
| 52 } | 52 } |
| 53 | 53 |
| 54 // Appends a new password-type field at the end of the form, having the | 54 // Appends a new password-type field at the end of the form, having the |
| 55 // specified |name_and_id| and |value| attributes. | 55 // specified |name_and_id|, |value|, and |autocomplete| attributes. Special |
| 56 void AddPasswordField(const char* name_and_id, const char* value) { | 56 // values for |autocomplete| are the same as in AddUsernameField. |
| 57 void AddPasswordField(const char* name_and_id, |
| 58 const char* value, |
| 59 const char* autocomplete) { |
| 60 std::string autocomplete_attribute(autocomplete ? |
| 61 base::StringPrintf("autocomplete=\"%s\"", autocomplete): ""); |
| 57 base::StringAppendF( | 62 base::StringAppendF( |
| 58 &html_, | 63 &html_, |
| 59 "<INPUT type=\"password\" name=\"%s\" id=\"%s\" value=\"%s\"/>", | 64 "<INPUT type=\"password\" name=\"%s\" id=\"%s\" value=\"%s\" %s/>", |
| 60 name_and_id, name_and_id, value); | 65 name_and_id, name_and_id, value, autocomplete_attribute.c_str()); |
| 61 } | 66 } |
| 62 | 67 |
| 63 // Appends a new submit-type field at the end of the form. | 68 // Appends a new submit-type field at the end of the form. |
| 64 void AddSubmitButton() { | 69 void AddSubmitButton() { |
| 65 html_ += "<INPUT type=\"submit\" name=\"submit\" value=\"Submit\"/>"; | 70 html_ += "<INPUT type=\"submit\" name=\"submit\" value=\"Submit\"/>"; |
| 66 } | 71 } |
| 67 | 72 |
| 68 // Returns the HTML code for the form containing the fields that have been | 73 // Returns the HTML code for the form containing the fields that have been |
| 69 // added so far. | 74 // added so far. |
| 70 std::string ProduceHTML() const { | 75 std::string ProduceHTML() const { |
| (...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 104 private: | 109 private: |
| 105 DISALLOW_COPY_AND_ASSIGN(PasswordFormConversionUtilsTest); | 110 DISALLOW_COPY_AND_ASSIGN(PasswordFormConversionUtilsTest); |
| 106 }; | 111 }; |
| 107 | 112 |
| 108 } // namespace | 113 } // namespace |
| 109 | 114 |
| 110 TEST_F(PasswordFormConversionUtilsTest, ValidWebFormElementToPasswordForm) { | 115 TEST_F(PasswordFormConversionUtilsTest, ValidWebFormElementToPasswordForm) { |
| 111 PasswordFormBuilder builder(kTestFormActionURL); | 116 PasswordFormBuilder builder(kTestFormActionURL); |
| 112 builder.AddUsernameField("username", "johnsmith", NULL); | 117 builder.AddUsernameField("username", "johnsmith", NULL); |
| 113 builder.AddSubmitButton(); | 118 builder.AddSubmitButton(); |
| 114 builder.AddPasswordField("password", "secret"); | 119 builder.AddPasswordField("password", "secret", NULL); |
| 115 std::string html = builder.ProduceHTML(); | 120 std::string html = builder.ProduceHTML(); |
| 116 | 121 |
| 117 scoped_ptr<PasswordForm> password_form; | 122 scoped_ptr<PasswordForm> password_form; |
| 118 ASSERT_NO_FATAL_FAILURE(LoadHTMLAndConvertForm(html, &password_form)); | 123 ASSERT_NO_FATAL_FAILURE(LoadHTMLAndConvertForm(html, &password_form)); |
| 119 ASSERT_NE(static_cast<PasswordForm*>(NULL), password_form.get()); | 124 ASSERT_NE(static_cast<PasswordForm*>(NULL), password_form.get()); |
| 120 | 125 |
| 121 EXPECT_EQ("data:", password_form->signon_realm); | 126 EXPECT_EQ("data:", password_form->signon_realm); |
| 122 EXPECT_EQ(GURL(kTestFormActionURL), password_form->action); | 127 EXPECT_EQ(GURL(kTestFormActionURL), password_form->action); |
| 123 EXPECT_EQ(base::UTF8ToUTF16("username"), password_form->username_element); | 128 EXPECT_EQ(base::UTF8ToUTF16("username"), password_form->username_element); |
| 124 EXPECT_EQ(base::UTF8ToUTF16("johnsmith"), password_form->username_value); | 129 EXPECT_EQ(base::UTF8ToUTF16("johnsmith"), password_form->username_value); |
| 125 EXPECT_EQ(base::UTF8ToUTF16("password"), password_form->password_element); | 130 EXPECT_EQ(base::UTF8ToUTF16("password"), password_form->password_element); |
| 126 EXPECT_EQ(base::UTF8ToUTF16("secret"), password_form->password_value); | 131 EXPECT_EQ(base::UTF8ToUTF16("secret"), password_form->password_value); |
| 127 EXPECT_EQ(PasswordForm::SCHEME_HTML, password_form->scheme); | 132 EXPECT_EQ(PasswordForm::SCHEME_HTML, password_form->scheme); |
| 128 EXPECT_FALSE(password_form->ssl_valid); | 133 EXPECT_FALSE(password_form->ssl_valid); |
| 129 EXPECT_FALSE(password_form->preferred); | 134 EXPECT_FALSE(password_form->preferred); |
| 130 EXPECT_FALSE(password_form->blacklisted_by_user); | 135 EXPECT_FALSE(password_form->blacklisted_by_user); |
| 131 EXPECT_EQ(PasswordForm::TYPE_MANUAL, password_form->type); | 136 EXPECT_EQ(PasswordForm::TYPE_MANUAL, password_form->type); |
| 132 } | 137 } |
| 133 | 138 |
| 134 TEST_F(PasswordFormConversionUtilsTest, InvalidWebFormElementToPasswordForm) { | 139 TEST_F(PasswordFormConversionUtilsTest, InvalidWebFormElementToPasswordForm) { |
| 135 PasswordFormBuilder builder("invalid_target"); | 140 PasswordFormBuilder builder("invalid_target"); |
| 136 builder.AddUsernameField("username", "johnsmith", NULL); | 141 builder.AddUsernameField("username", "johnsmith", NULL); |
| 137 builder.AddSubmitButton(); | 142 builder.AddSubmitButton(); |
| 138 builder.AddPasswordField("password", "secret"); | 143 builder.AddPasswordField("password", "secret", NULL); |
| 139 std::string html = builder.ProduceHTML(); | 144 std::string html = builder.ProduceHTML(); |
| 140 | 145 |
| 141 scoped_ptr<PasswordForm> password_form; | 146 scoped_ptr<PasswordForm> password_form; |
| 142 ASSERT_NO_FATAL_FAILURE(LoadHTMLAndConvertForm(html, &password_form)); | 147 ASSERT_NO_FATAL_FAILURE(LoadHTMLAndConvertForm(html, &password_form)); |
| 143 ASSERT_EQ(static_cast<PasswordForm*>(NULL), password_form.get()); | 148 ASSERT_EQ(static_cast<PasswordForm*>(NULL), password_form.get()); |
| 144 } | 149 } |
| 145 | 150 |
| 146 TEST_F(PasswordFormConversionUtilsTest, | 151 TEST_F(PasswordFormConversionUtilsTest, |
| 147 WebFormWithMultipleUseNameAndPassWordFieldsToPasswordForm) { | 152 WebFormWithMultipleUseNameAndPassWordFieldsToPasswordForm) { |
| 148 PasswordFormBuilder builder(kTestFormActionURL); | 153 PasswordFormBuilder builder(kTestFormActionURL); |
| 149 builder.AddUsernameField("username1", "John", NULL); | 154 builder.AddUsernameField("username1", "John", NULL); |
| 150 builder.AddPasswordField("password1", "oldsecret"); | 155 builder.AddPasswordField("password1", "oldsecret", NULL); |
| 151 builder.AddUsernameField("username2", "William", NULL); | 156 builder.AddUsernameField("username2", "William", NULL); |
| 152 builder.AddPasswordField("password2", "secret"); | 157 builder.AddPasswordField("password2", "secret", NULL); |
| 153 builder.AddUsernameField("username3", "Smith", NULL); | 158 builder.AddUsernameField("username3", "Smith", NULL); |
| 154 builder.AddPasswordField("password3", "secret"); | 159 builder.AddPasswordField("password3", "secret", NULL); |
| 155 builder.AddSubmitButton(); | 160 builder.AddSubmitButton(); |
| 156 std::string html = builder.ProduceHTML(); | 161 std::string html = builder.ProduceHTML(); |
| 157 | 162 |
| 158 scoped_ptr<PasswordForm> password_form; | 163 scoped_ptr<PasswordForm> password_form; |
| 159 ASSERT_NO_FATAL_FAILURE(LoadHTMLAndConvertForm(html, &password_form)); | 164 ASSERT_NO_FATAL_FAILURE(LoadHTMLAndConvertForm(html, &password_form)); |
| 160 ASSERT_NE(static_cast<PasswordForm*>(NULL), password_form.get()); | 165 ASSERT_NE(static_cast<PasswordForm*>(NULL), password_form.get()); |
| 161 | 166 |
| 162 EXPECT_EQ("data:", password_form->signon_realm); | 167 EXPECT_EQ("data:", password_form->signon_realm); |
| 163 EXPECT_EQ(GURL(kTestFormActionURL), password_form->action); | 168 EXPECT_EQ(GURL(kTestFormActionURL), password_form->action); |
| 164 EXPECT_EQ(base::UTF8ToUTF16("username1"), password_form->username_element); | 169 EXPECT_EQ(base::UTF8ToUTF16("username1"), password_form->username_element); |
| (...skipping 13 matching lines...) Expand all Loading... |
| 178 EXPECT_FALSE(password_form->ssl_valid); | 183 EXPECT_FALSE(password_form->ssl_valid); |
| 179 EXPECT_FALSE(password_form->preferred); | 184 EXPECT_FALSE(password_form->preferred); |
| 180 EXPECT_FALSE(password_form->blacklisted_by_user); | 185 EXPECT_FALSE(password_form->blacklisted_by_user); |
| 181 EXPECT_EQ(PasswordForm::TYPE_MANUAL, password_form->type); | 186 EXPECT_EQ(PasswordForm::TYPE_MANUAL, password_form->type); |
| 182 } | 187 } |
| 183 | 188 |
| 184 TEST_F(PasswordFormConversionUtilsTest, | 189 TEST_F(PasswordFormConversionUtilsTest, |
| 185 WebFormwithThreeDifferentPasswordsToPasswordForm) { | 190 WebFormwithThreeDifferentPasswordsToPasswordForm) { |
| 186 PasswordFormBuilder builder(kTestFormActionURL); | 191 PasswordFormBuilder builder(kTestFormActionURL); |
| 187 builder.AddUsernameField("username1", "John", NULL); | 192 builder.AddUsernameField("username1", "John", NULL); |
| 188 builder.AddPasswordField("password1", "alpha"); | 193 builder.AddPasswordField("password1", "alpha", NULL); |
| 189 builder.AddPasswordField("password2", "beta"); | 194 builder.AddPasswordField("password2", "beta", NULL); |
| 190 builder.AddPasswordField("password3", "gamma"); | 195 builder.AddPasswordField("password3", "gamma", NULL); |
| 191 builder.AddSubmitButton(); | 196 builder.AddSubmitButton(); |
| 192 std::string html = builder.ProduceHTML(); | 197 std::string html = builder.ProduceHTML(); |
| 193 | 198 |
| 194 scoped_ptr<PasswordForm> password_form; | 199 scoped_ptr<PasswordForm> password_form; |
| 195 ASSERT_NO_FATAL_FAILURE(LoadHTMLAndConvertForm(html, &password_form)); | 200 ASSERT_NO_FATAL_FAILURE(LoadHTMLAndConvertForm(html, &password_form)); |
| 196 ASSERT_EQ(static_cast<PasswordForm*>(NULL), password_form.get()); | 201 ASSERT_EQ(static_cast<PasswordForm*>(NULL), password_form.get()); |
| 197 } | 202 } |
| 198 | 203 |
| 199 TEST_F(PasswordFormConversionUtilsTest, | 204 TEST_F(PasswordFormConversionUtilsTest, |
| 200 UsernameFieldsWithAutocompleteAttributes) { | 205 UsernameFieldsWithAutocompleteAttributes) { |
| (...skipping 10 matching lines...) Expand all Loading... |
| 211 {{"username", NULL, NULL}, "username1", "John", ""}, | 216 {{"username", NULL, NULL}, "username1", "John", ""}, |
| 212 {{NULL, "username", NULL}, "username2", "William", ""}, | 217 {{NULL, "username", NULL}, "username2", "William", ""}, |
| 213 {{NULL, NULL, "username"}, "username3", "Smith", ""}, | 218 {{NULL, NULL, "username"}, "username3", "Smith", ""}, |
| 214 // When >=2 elements have the attribute, the first should be selected as | 219 // When >=2 elements have the attribute, the first should be selected as |
| 215 // the username, and the rest should go to other_possible_usernames. | 220 // the username, and the rest should go to other_possible_usernames. |
| 216 {{"username", "username", NULL}, "username1", "John", "William"}, | 221 {{"username", "username", NULL}, "username1", "John", "William"}, |
| 217 {{NULL, "username", "username"}, "username2", "William", "Smith"}, | 222 {{NULL, "username", "username"}, "username2", "William", "Smith"}, |
| 218 {{"username", NULL, "username"}, "username1", "John", "Smith"}, | 223 {{"username", NULL, "username"}, "username1", "John", "Smith"}, |
| 219 {{"username", "username", "username"}, "username1", "John", | 224 {{"username", "username", "username"}, "username1", "John", |
| 220 "William+Smith"}, | 225 "William+Smith"}, |
| 221 // When there is an empty autocomplete attribute (i.e. autocomplete=''), | 226 // When there is an empty autocomplete attribute (i.e. autocomplete=""), |
| 222 // it should have the same effect as having no attribute whatsoever. | 227 // it should have the same effect as having no attribute whatsoever. |
| 223 {{"", "", ""}, "username2", "William", "John+Smith"}, | 228 {{"", "", ""}, "username2", "William", "John+Smith"}, |
| 224 {{"", "", "username"}, "username3", "Smith", ""}, | 229 {{"", "", "username"}, "username3", "Smith", ""}, |
| 225 {{"username", "", "username"}, "username1", "John", "Smith"}, | 230 {{"username", "", "username"}, "username1", "John", "Smith"}, |
| 226 // Whether attribute values are upper or mixed case, it should not matter. | 231 // It should not matter if attribute values are upper or mixed case. |
| 227 {{"USERNAME", NULL, "uSeRNaMe"}, "username1", "John", "Smith"}, | 232 {{"USERNAME", NULL, "uSeRNaMe"}, "username1", "John", "Smith"}, |
| 228 {{"uSeRNaMe", NULL, "USERNAME"}, "username1", "John", "Smith"}}; | 233 {{"uSeRNaMe", NULL, "USERNAME"}, "username1", "John", "Smith"}}; |
| 229 | 234 |
| 230 for (size_t i = 0; i < ARRAYSIZE_UNSAFE(cases); ++i) { | 235 for (size_t i = 0; i < ARRAYSIZE_UNSAFE(cases); ++i) { |
| 231 SCOPED_TRACE(testing::Message() << "Iteration " << i); | 236 SCOPED_TRACE(testing::Message() << "Iteration " << i); |
| 232 | 237 |
| 233 PasswordFormBuilder builder(kTestFormActionURL); | 238 PasswordFormBuilder builder(kTestFormActionURL); |
| 234 builder.AddUsernameField("username1", "John", cases[i].autocomplete[0]); | 239 builder.AddUsernameField("username1", "John", cases[i].autocomplete[0]); |
| 235 builder.AddUsernameField("username2", "William", cases[i].autocomplete[1]); | 240 builder.AddUsernameField("username2", "William", cases[i].autocomplete[1]); |
| 236 builder.AddPasswordField("password", "secret"); | 241 builder.AddPasswordField("password", "secret", NULL); |
| 237 builder.AddUsernameField("username3", "Smith", cases[i].autocomplete[2]); | 242 builder.AddUsernameField("username3", "Smith", cases[i].autocomplete[2]); |
| 238 builder.AddSubmitButton(); | 243 builder.AddSubmitButton(); |
| 239 std::string html = builder.ProduceHTML(); | 244 std::string html = builder.ProduceHTML(); |
| 240 | 245 |
| 241 scoped_ptr<PasswordForm> password_form; | 246 scoped_ptr<PasswordForm> password_form; |
| 242 ASSERT_NO_FATAL_FAILURE(LoadHTMLAndConvertForm(html, &password_form)); | 247 ASSERT_NO_FATAL_FAILURE(LoadHTMLAndConvertForm(html, &password_form)); |
| 243 ASSERT_NE(static_cast<PasswordForm*>(NULL), password_form.get()); | 248 ASSERT_NE(static_cast<PasswordForm*>(NULL), password_form.get()); |
| 244 | 249 |
| 245 EXPECT_EQ(base::UTF8ToUTF16(cases[i].expected_username_element), | 250 EXPECT_EQ(base::UTF8ToUTF16(cases[i].expected_username_element), |
| 246 password_form->username_element); | 251 password_form->username_element); |
| 247 EXPECT_EQ(base::UTF8ToUTF16(cases[i].expected_username_value), | 252 EXPECT_EQ(base::UTF8ToUTF16(cases[i].expected_username_value), |
| 248 password_form->username_value); | 253 password_form->username_value); |
| 249 EXPECT_EQ(base::UTF8ToUTF16("password"), password_form->password_element); | 254 EXPECT_EQ(base::UTF8ToUTF16("password"), password_form->password_element); |
| 250 EXPECT_EQ(base::UTF8ToUTF16("secret"), password_form->password_value); | 255 EXPECT_EQ(base::UTF8ToUTF16("secret"), password_form->password_value); |
| 251 EXPECT_EQ(base::UTF8ToUTF16(cases[i].expected_other_possible_usernames), | 256 EXPECT_EQ(base::UTF8ToUTF16(cases[i].expected_other_possible_usernames), |
| 252 JoinString(password_form->other_possible_usernames, '+')); | 257 JoinString(password_form->other_possible_usernames, '+')); |
| 253 } | 258 } |
| 254 } | 259 } |
| 255 | 260 |
| 261 TEST_F(PasswordFormConversionUtilsTest, |
| 262 PasswordFieldsWithAutocompleteAttributes) { |
| 263 // Each test case consists of a set of parameters to be plugged into the |
| 264 // PasswordFormBuilder below, plus the corresponding expectations. |
| 265 struct TestCase { |
| 266 const char* autocomplete[3]; |
| 267 const char* expected_password_element; |
| 268 const char* expected_password_value; |
| 269 const char* expected_new_password_element; |
| 270 const char* expected_new_password_value; |
| 271 } cases[] = { |
| 272 // When there are elements marked with autocomplete='current-password', |
| 273 // but no elements with 'new-password', we should treat the first of the |
| 274 // former kind as the current password, and ignore all other password |
| 275 // fields, assuming they are not intentionally not marked. They might be |
| 276 // for other purposes, such as PINs, OTPs, and the like. Actual values in |
| 277 // the password fields should be ignored in all cases below. |
| 278 {{"current-password", NULL, NULL}, "password1", "alpha", "", ""}, |
| 279 {{NULL, "current-password", NULL}, "password2", "beta", "", ""}, |
| 280 {{NULL, NULL, "current-password"}, "password3", "gamma", "", ""}, |
| 281 {{NULL, "current-password", "current-password"}, |
| 282 "password2", "beta", "", ""}, |
| 283 {{"current-password", NULL, "current-password"}, |
| 284 "password1", "alpha", "", ""}, |
| 285 {{"current-password", "current-password", NULL}, |
| 286 "password1", "alpha", "", ""}, |
| 287 {{"current-password", "current-password", "current-password"}, |
| 288 "password1", "alpha", "", ""}, |
| 289 // The same goes vice versa for autocomplete='new-password'. |
| 290 {{"new-password", NULL, NULL}, "", "", "password1", "alpha"}, |
| 291 {{NULL, "new-password", NULL}, "", "", "password2", "beta"}, |
| 292 {{NULL, NULL, "new-password"}, "", "", "password3", "gamma"}, |
| 293 {{NULL, "new-password", "new-password"}, "", "", "password2", "beta"}, |
| 294 {{"new-password", NULL, "new-password"}, "", "", "password1", "alpha"}, |
| 295 {{"new-password", "new-password", NULL}, "", "", "password1", "alpha"}, |
| 296 {{"new-password", "new-password", "new-password"}, |
| 297 "", "", "password1", "alpha"}, |
| 298 // When there is one element marked with autocomplete='current-password', |
| 299 // and one with 'new-password', just comply, regardless of their order. |
| 300 // Ignore the unmarked password field(s) for the same reason as above. |
| 301 {{"current-password", "new-password", NULL}, |
| 302 "password1", "alpha", "password2", "beta"}, |
| 303 {{"current-password", NULL, "new-password"}, |
| 304 "password1", "alpha", "password3", "gamma"}, |
| 305 {{NULL, "current-password", "new-password"}, |
| 306 "password2", "beta", "password3", "gamma"}, |
| 307 {{"new-password", "current-password", NULL}, |
| 308 "password2", "beta", "password1", "alpha"}, |
| 309 {{"new-password", NULL, "current-password"}, |
| 310 "password3", "gamma", "password1", "alpha"}, |
| 311 {{NULL, "new-password", "current-password"}, |
| 312 "password3", "gamma", "password2", "beta"}, |
| 313 // In case of duplicated elements of either kind, go with the first one of |
| 314 // its kind. |
| 315 {{"current-password", "current-password", "new-password"}, |
| 316 "password1", "alpha", "password3", "gamma"}, |
| 317 {{"current-password", "new-password", "current-password"}, |
| 318 "password1", "alpha", "password2", "beta"}, |
| 319 {{"new-password", "current-password", "current-password"}, |
| 320 "password2", "beta", "password1", "alpha"}, |
| 321 {{"current-password", "new-password", "new-password"}, |
| 322 "password1", "alpha", "password2", "beta"}, |
| 323 {{"new-password", "current-password", "new-password"}, |
| 324 "password2", "beta", "password1", "alpha"}, |
| 325 {{"new-password", "new-password", "current-password"}, |
| 326 "password3", "gamma", "password1", "alpha"}, |
| 327 // When there is an empty autocomplete attribute (i.e. autocomplete=""), |
| 328 // it should have the same effect as having no attribute whatsoever. |
| 329 {{"current-password", "", ""}, |
| 330 "password1", "alpha", "", ""}, |
| 331 {{"", "", "new-password"}, |
| 332 "", "", "password3", "gamma"}, |
| 333 {{"", "new-password", ""}, |
| 334 "", "", "password2", "beta"}, |
| 335 {{"", "current-password", "current-password"}, |
| 336 "password2", "beta", "", ""}, |
| 337 {{"new-password", "", "new-password"}, "", "", "password1", "alpha"}, |
| 338 {{"new-password", "", "current-password"}, |
| 339 "password3", "gamma", "password1", "alpha"}, |
| 340 // It should not matter if attribute values are upper or mixed case. |
| 341 {{NULL, "current-password", NULL}, |
| 342 "password2", "beta", "", ""}, |
| 343 {{NULL, "CURRENT-PASSWORD", NULL}, |
| 344 "password2", "beta", "", ""}, |
| 345 {{NULL, "new-password", NULL}, |
| 346 "", "", "password2", "beta"}, |
| 347 {{NULL, "nEw-PaSsWoRd", NULL}, |
| 348 "", "", "password2", "beta"}}; |
| 349 |
| 350 for (size_t i = 0; i < ARRAYSIZE_UNSAFE(cases); ++i) { |
| 351 SCOPED_TRACE(testing::Message() << "Iteration " << i); |
| 352 |
| 353 PasswordFormBuilder builder(kTestFormActionURL); |
| 354 builder.AddPasswordField("password1", "alpha", cases[i].autocomplete[0]); |
| 355 builder.AddUsernameField("username1", "William", NULL); |
| 356 builder.AddPasswordField("password2", "beta", cases[i].autocomplete[1]); |
| 357 builder.AddUsernameField("username2", "Smith", NULL); |
| 358 builder.AddPasswordField("password3", "gamma", cases[i].autocomplete[2]); |
| 359 builder.AddSubmitButton(); |
| 360 std::string html = builder.ProduceHTML(); |
| 361 |
| 362 scoped_ptr<PasswordForm> password_form; |
| 363 ASSERT_NO_FATAL_FAILURE(LoadHTMLAndConvertForm(html, &password_form)); |
| 364 ASSERT_NE(static_cast<PasswordForm*>(NULL), password_form.get()); |
| 365 |
| 366 // Any constellation of password autocomplete attributes should have no |
| 367 // effect on that the first text-type input field before a password field |
| 368 // should be selected as the username. |
| 369 // TODO(engedy): Double-check whether this is the intended behavior. |
| 370 EXPECT_EQ(base::UTF8ToUTF16("username1"), password_form->username_element); |
| 371 EXPECT_EQ(base::UTF8ToUTF16("William"), password_form->username_value); |
| 372 EXPECT_EQ(base::UTF8ToUTF16(cases[i].expected_password_element), |
| 373 password_form->password_element); |
| 374 EXPECT_EQ(base::UTF8ToUTF16(cases[i].expected_password_value), |
| 375 password_form->password_value); |
| 376 EXPECT_EQ(base::UTF8ToUTF16(cases[i].expected_new_password_element), |
| 377 password_form->new_password_element); |
| 378 EXPECT_EQ(base::UTF8ToUTF16(cases[i].expected_new_password_value), |
| 379 password_form->new_password_value); |
| 380 ASSERT_EQ(1u, password_form->other_possible_usernames.size()); |
| 381 EXPECT_EQ(base::UTF8ToUTF16("Smith"), |
| 382 password_form->other_possible_usernames[0]); |
| 383 } |
| 384 } |
| 385 |
| 256 } // namespace autofill | 386 } // namespace autofill |
| OLD | NEW |