Commit 6a8caa9c authored by engedy@chromium.org's avatar engedy@chromium.org

Clean up PasswordFormConversionUtilsTest and add some missing tests.

BUG=375333

Review URL: https://codereview.chromium.org/372683003

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@282400 0039d316-1c4b-4281-b951-d872f2087c98
parent cfab30ca
...@@ -22,10 +22,6 @@ using blink::WebVector; ...@@ -22,10 +22,6 @@ using blink::WebVector;
namespace autofill { namespace autofill {
namespace { namespace {
// Maximum number of password fields we will observe before throwing our
// hands in the air and giving up with a given form.
static const size_t kMaxPasswords = 3;
// Checks in a case-insensitive way if the autocomplete attribute for the given // Checks in a case-insensitive way if the autocomplete attribute for the given
// |element| is present and has the specified |value_in_lowercase|. // |element| is present and has the specified |value_in_lowercase|.
bool HasAutocompleteAttributeValue(const WebInputElement& element, bool HasAutocompleteAttributeValue(const WebInputElement& element,
...@@ -132,8 +128,7 @@ void GetPasswordForm(const WebFormElement& form, PasswordForm* password_form) { ...@@ -132,8 +128,7 @@ void GetPasswordForm(const WebFormElement& form, PasswordForm* password_form) {
if (!input_element || !input_element->isEnabled()) if (!input_element || !input_element->isEnabled())
continue; continue;
if ((passwords.size() < kMaxPasswords) && if (input_element->isPasswordField()) {
input_element->isPasswordField()) {
passwords.push_back(*input_element); passwords.push_back(*input_element);
// If we have not yet considered any element to be the username so far, // If we have not yet considered any element to be the username so far,
// provisionally select the input element just before the first password // provisionally select the input element just before the first password
......
...@@ -9,14 +9,19 @@ ...@@ -9,14 +9,19 @@
#include "components/autofill/content/renderer/password_form_conversion_utils.h" #include "components/autofill/content/renderer/password_form_conversion_utils.h"
#include "components/autofill/core/common/password_form.h" #include "components/autofill/core/common/password_form.h"
#include "content/public/test/render_view_test.h" #include "content/public/test/render_view_test.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h" #include "testing/gtest/include/gtest/gtest.h"
#include "third_party/WebKit/public/platform/WebVector.h" #include "third_party/WebKit/public/platform/WebVector.h"
#include "third_party/WebKit/public/web/WebDocument.h" #include "third_party/WebKit/public/web/WebDocument.h"
#include "third_party/WebKit/public/web/WebFormControlElement.h"
#include "third_party/WebKit/public/web/WebFormElement.h" #include "third_party/WebKit/public/web/WebFormElement.h"
#include "third_party/WebKit/public/web/WebInputElement.h"
#include "third_party/WebKit/public/web/WebLocalFrame.h" #include "third_party/WebKit/public/web/WebLocalFrame.h"
using blink::WebFormControlElement;
using blink::WebFormElement; using blink::WebFormElement;
using blink::WebFrame; using blink::WebFrame;
using blink::WebInputElement;
using blink::WebVector; using blink::WebVector;
namespace autofill { namespace autofill {
...@@ -65,9 +70,24 @@ class PasswordFormBuilder { ...@@ -65,9 +70,24 @@ class PasswordFormBuilder {
name_and_id, name_and_id, value, autocomplete_attribute.c_str()); name_and_id, name_and_id, value, autocomplete_attribute.c_str());
} }
// Appends a new submit-type field at the end of the form. // Appends a disabled text-type field at the end of the form.
void AddSubmitButton() { void AddDisabledUsernameField() {
html_ += "<INPUT type=\"submit\" name=\"submit\" value=\"Submit\"/>"; html_ += "<INPUT type=\"text\" disabled/>";
}
// Appends a disabled password-type field at the end of the form.
void AddDisabledPasswordField() {
html_ += "<INPUT type=\"password\" disabled/>";
}
// Appends a new submit-type field at the end of the form with the specified
// |name|. If |activated| is true, the test will emulate as if this button
// were used to submit the form.
void AddSubmitButton(const char* name, bool activated) {
base::StringAppendF(
&html_,
"<INPUT type=\"submit\" name=\"%s\" value=\"Submit\" %s/>",
name, activated ? "set-activated-submit" : "");
} }
// Returns the HTML code for the form containing the fields that have been // Returns the HTML code for the form containing the fields that have been
...@@ -103,6 +123,14 @@ class PasswordFormConversionUtilsTest : public content::RenderViewTest { ...@@ -103,6 +123,14 @@ class PasswordFormConversionUtilsTest : public content::RenderViewTest {
frame->document().forms(forms); frame->document().forms(forms);
ASSERT_EQ(1U, forms.size()); ASSERT_EQ(1U, forms.size());
WebVector<WebFormControlElement> control_elements;
forms[0].getFormControlElements(control_elements);
for (size_t i = 0; i < control_elements.size(); ++i) {
WebInputElement* input_element = toWebInputElement(&control_elements[i]);
if (input_element->hasAttribute("set-activated-submit"))
input_element->setActivatedSubmit(true);
}
*password_form = CreatePasswordForm(forms[0]); *password_form = CreatePasswordForm(forms[0]);
} }
...@@ -112,19 +140,22 @@ class PasswordFormConversionUtilsTest : public content::RenderViewTest { ...@@ -112,19 +140,22 @@ class PasswordFormConversionUtilsTest : public content::RenderViewTest {
} // namespace } // namespace
TEST_F(PasswordFormConversionUtilsTest, ValidWebFormElementToPasswordForm) { TEST_F(PasswordFormConversionUtilsTest, BasicFormAttributes) {
PasswordFormBuilder builder(kTestFormActionURL); PasswordFormBuilder builder(kTestFormActionURL);
builder.AddUsernameField("username", "johnsmith", NULL); builder.AddUsernameField("username", "johnsmith", NULL);
builder.AddSubmitButton(); builder.AddSubmitButton("inactive_submit", false);
builder.AddSubmitButton("active_submit", true);
builder.AddSubmitButton("inactive_submit2", false);
builder.AddPasswordField("password", "secret", NULL); builder.AddPasswordField("password", "secret", NULL);
std::string html = builder.ProduceHTML(); std::string html = builder.ProduceHTML();
scoped_ptr<PasswordForm> password_form; scoped_ptr<PasswordForm> password_form;
ASSERT_NO_FATAL_FAILURE(LoadHTMLAndConvertForm(html, &password_form)); ASSERT_NO_FATAL_FAILURE(LoadHTMLAndConvertForm(html, &password_form));
ASSERT_NE(static_cast<PasswordForm*>(NULL), password_form.get()); ASSERT_TRUE(password_form);
EXPECT_EQ("data:", password_form->signon_realm); EXPECT_EQ("data:", password_form->signon_realm);
EXPECT_EQ(GURL(kTestFormActionURL), password_form->action); EXPECT_EQ(GURL(kTestFormActionURL), password_form->action);
EXPECT_EQ(base::UTF8ToUTF16("active_submit"), password_form->submit_element);
EXPECT_EQ(base::UTF8ToUTF16("username"), password_form->username_element); EXPECT_EQ(base::UTF8ToUTF16("username"), password_form->username_element);
EXPECT_EQ(base::UTF8ToUTF16("johnsmith"), password_form->username_value); EXPECT_EQ(base::UTF8ToUTF16("johnsmith"), password_form->username_value);
EXPECT_EQ(base::UTF8ToUTF16("password"), password_form->password_element); EXPECT_EQ(base::UTF8ToUTF16("password"), password_form->password_element);
...@@ -134,75 +165,28 @@ TEST_F(PasswordFormConversionUtilsTest, ValidWebFormElementToPasswordForm) { ...@@ -134,75 +165,28 @@ TEST_F(PasswordFormConversionUtilsTest, ValidWebFormElementToPasswordForm) {
EXPECT_FALSE(password_form->preferred); EXPECT_FALSE(password_form->preferred);
EXPECT_FALSE(password_form->blacklisted_by_user); EXPECT_FALSE(password_form->blacklisted_by_user);
EXPECT_EQ(PasswordForm::TYPE_MANUAL, password_form->type); EXPECT_EQ(PasswordForm::TYPE_MANUAL, password_form->type);
EXPECT_FALSE(password_form->use_additional_authentication);
} }
TEST_F(PasswordFormConversionUtilsTest, InvalidWebFormElementToPasswordForm) { TEST_F(PasswordFormConversionUtilsTest, DisabledFieldsAreIgnored) {
PasswordFormBuilder builder("invalid_target"); PasswordFormBuilder builder(kTestFormActionURL);
builder.AddUsernameField("username", "johnsmith", NULL); builder.AddUsernameField("username", "johnsmith", NULL);
builder.AddSubmitButton(); builder.AddDisabledUsernameField();
builder.AddDisabledPasswordField();
builder.AddPasswordField("password", "secret", NULL); builder.AddPasswordField("password", "secret", NULL);
builder.AddSubmitButton("submit", true);
std::string html = builder.ProduceHTML(); std::string html = builder.ProduceHTML();
scoped_ptr<PasswordForm> password_form; scoped_ptr<PasswordForm> password_form;
ASSERT_NO_FATAL_FAILURE(LoadHTMLAndConvertForm(html, &password_form)); ASSERT_NO_FATAL_FAILURE(LoadHTMLAndConvertForm(html, &password_form));
ASSERT_EQ(static_cast<PasswordForm*>(NULL), password_form.get()); ASSERT_TRUE(password_form);
} EXPECT_EQ(base::UTF8ToUTF16("username"), password_form->username_element);
EXPECT_EQ(base::UTF8ToUTF16("johnsmith"), password_form->username_value);
TEST_F(PasswordFormConversionUtilsTest, EXPECT_EQ(base::UTF8ToUTF16("password"), password_form->password_element);
WebFormWithMultipleUseNameAndPassWordFieldsToPasswordForm) { EXPECT_EQ(base::UTF8ToUTF16("secret"), password_form->password_value);
PasswordFormBuilder builder(kTestFormActionURL);
builder.AddUsernameField("username1", "John", NULL);
builder.AddPasswordField("password1", "oldsecret", NULL);
builder.AddUsernameField("username2", "William", NULL);
builder.AddPasswordField("password2", "secret", NULL);
builder.AddUsernameField("username3", "Smith", NULL);
builder.AddPasswordField("password3", "secret", NULL);
builder.AddSubmitButton();
std::string html = builder.ProduceHTML();
scoped_ptr<PasswordForm> password_form;
ASSERT_NO_FATAL_FAILURE(LoadHTMLAndConvertForm(html, &password_form));
ASSERT_NE(static_cast<PasswordForm*>(NULL), password_form.get());
EXPECT_EQ("data:", password_form->signon_realm);
EXPECT_EQ(GURL(kTestFormActionURL), password_form->action);
EXPECT_EQ(base::UTF8ToUTF16("username1"), password_form->username_element);
EXPECT_EQ(base::UTF8ToUTF16("John"), password_form->username_value);
EXPECT_EQ(base::UTF8ToUTF16("password1"),
password_form->password_element);
EXPECT_EQ(base::UTF8ToUTF16("oldsecret"), password_form->password_value);
EXPECT_EQ(base::UTF8ToUTF16("password2"),
password_form->new_password_element);
EXPECT_EQ(base::UTF8ToUTF16("secret"), password_form->new_password_value);
ASSERT_EQ(2u, password_form->other_possible_usernames.size());
EXPECT_EQ(base::UTF8ToUTF16("William"),
password_form->other_possible_usernames[0]);
EXPECT_EQ(base::UTF8ToUTF16("Smith"),
password_form->other_possible_usernames[1]);
EXPECT_EQ(PasswordForm::SCHEME_HTML, password_form->scheme);
EXPECT_FALSE(password_form->ssl_valid);
EXPECT_FALSE(password_form->preferred);
EXPECT_FALSE(password_form->blacklisted_by_user);
EXPECT_EQ(PasswordForm::TYPE_MANUAL, password_form->type);
}
TEST_F(PasswordFormConversionUtilsTest,
WebFormwithThreeDifferentPasswordsToPasswordForm) {
PasswordFormBuilder builder(kTestFormActionURL);
builder.AddUsernameField("username1", "John", NULL);
builder.AddPasswordField("password1", "alpha", NULL);
builder.AddPasswordField("password2", "beta", NULL);
builder.AddPasswordField("password3", "gamma", NULL);
builder.AddSubmitButton();
std::string html = builder.ProduceHTML();
scoped_ptr<PasswordForm> password_form;
ASSERT_NO_FATAL_FAILURE(LoadHTMLAndConvertForm(html, &password_form));
ASSERT_EQ(static_cast<PasswordForm*>(NULL), password_form.get());
} }
TEST_F(PasswordFormConversionUtilsTest, TEST_F(PasswordFormConversionUtilsTest, IdentifyingUsernameFields) {
UsernameFieldsWithAutocompleteAttributes) {
// Each test case consists of a set of parameters to be plugged into the // Each test case consists of a set of parameters to be plugged into the
// PasswordFormBuilder below, plus the corresponding expectations. // PasswordFormBuilder below, plus the corresponding expectations.
struct TestCase { struct TestCase {
...@@ -211,6 +195,10 @@ TEST_F(PasswordFormConversionUtilsTest, ...@@ -211,6 +195,10 @@ TEST_F(PasswordFormConversionUtilsTest,
const char* expected_username_value; const char* expected_username_value;
const char* expected_other_possible_usernames; const char* expected_other_possible_usernames;
} cases[] = { } cases[] = {
// When no elements are marked with autocomplete='username', the text-type
// input field before the first password element should get selected as
// the username, and the rest should be marked as alternatives.
{{NULL, NULL, NULL}, "username2", "William", "John+Smith"},
// When a sole element is marked with autocomplete='username', it should // When a sole element is marked with autocomplete='username', it should
// be treated as the username for sure, with no other_possible_usernames. // be treated as the username for sure, with no other_possible_usernames.
{{"username", NULL, NULL}, "username1", "John", ""}, {{"username", NULL, NULL}, "username1", "John", ""},
...@@ -233,33 +221,171 @@ TEST_F(PasswordFormConversionUtilsTest, ...@@ -233,33 +221,171 @@ TEST_F(PasswordFormConversionUtilsTest,
{{"uSeRNaMe", NULL, "USERNAME"}, "username1", "John", "Smith"}}; {{"uSeRNaMe", NULL, "USERNAME"}, "username1", "John", "Smith"}};
for (size_t i = 0; i < ARRAYSIZE_UNSAFE(cases); ++i) { for (size_t i = 0; i < ARRAYSIZE_UNSAFE(cases); ++i) {
SCOPED_TRACE(testing::Message() << "Iteration " << i); for (size_t nonempty_username_fields = 0; nonempty_username_fields < 2;
++nonempty_username_fields) {
SCOPED_TRACE(testing::Message()
<< "Iteration " << i << " "
<< (nonempty_username_fields ? "nonempty" : "empty"));
// Repeat each test once with empty, and once with non-empty usernames.
// In the former case, no empty other_possible_usernames should be saved.
const char* names[3];
if (nonempty_username_fields) {
names[0] = "John";
names[1] = "William";
names[2] = "Smith";
} else {
names[0] = names[1] = names[2] = "";
}
PasswordFormBuilder builder(kTestFormActionURL); PasswordFormBuilder builder(kTestFormActionURL);
builder.AddUsernameField("username1", "John", cases[i].autocomplete[0]); builder.AddUsernameField("username1", names[0], cases[i].autocomplete[0]);
builder.AddUsernameField("username2", "William", cases[i].autocomplete[1]); builder.AddUsernameField("username2", names[1], cases[i].autocomplete[1]);
builder.AddPasswordField("password", "secret", NULL); builder.AddPasswordField("password", "secret", NULL);
builder.AddUsernameField("username3", "Smith", cases[i].autocomplete[2]); builder.AddUsernameField("username3", names[2], cases[i].autocomplete[2]);
builder.AddSubmitButton(); builder.AddPasswordField("password2", "othersecret", NULL);
builder.AddSubmitButton("submit", true);
std::string html = builder.ProduceHTML(); std::string html = builder.ProduceHTML();
scoped_ptr<PasswordForm> password_form; scoped_ptr<PasswordForm> password_form;
ASSERT_NO_FATAL_FAILURE(LoadHTMLAndConvertForm(html, &password_form)); ASSERT_NO_FATAL_FAILURE(LoadHTMLAndConvertForm(html, &password_form));
ASSERT_NE(static_cast<PasswordForm*>(NULL), password_form.get()); ASSERT_TRUE(password_form);
EXPECT_EQ(base::UTF8ToUTF16(cases[i].expected_username_element), EXPECT_EQ(base::UTF8ToUTF16(cases[i].expected_username_element),
password_form->username_element); password_form->username_element);
if (nonempty_username_fields) {
EXPECT_EQ(base::UTF8ToUTF16(cases[i].expected_username_value), EXPECT_EQ(base::UTF8ToUTF16(cases[i].expected_username_value),
password_form->username_value); password_form->username_value);
EXPECT_EQ(base::UTF8ToUTF16("password"), password_form->password_element);
EXPECT_EQ(base::UTF8ToUTF16("secret"), password_form->password_value);
EXPECT_EQ(base::UTF8ToUTF16(cases[i].expected_other_possible_usernames), EXPECT_EQ(base::UTF8ToUTF16(cases[i].expected_other_possible_usernames),
JoinString(password_form->other_possible_usernames, '+')); JoinString(password_form->other_possible_usernames, '+'));
} else {
EXPECT_TRUE(password_form->username_value.empty());
EXPECT_TRUE(password_form->other_possible_usernames.empty());
}
// Do a basic sanity check that we are still having a password field.
EXPECT_EQ(base::UTF8ToUTF16("password"), password_form->password_element);
EXPECT_EQ(base::UTF8ToUTF16("secret"), password_form->password_value);
}
}
}
TEST_F(PasswordFormConversionUtilsTest, IdentifyingTwoPasswordFields) {
// Each test case consists of a set of parameters to be plugged into the
// PasswordFormBuilder below, plus the corresponding expectations.
struct TestCase {
const char* password_values[2];
const char* expected_password_element;
const char* expected_password_value;
const char* expected_new_password_element;
const char* expected_new_password_value;
} cases[] = {
// Twp non-empty fields with the same value should be treated as a new
// password field plus a confirmation field for the new password.
{{"alpha", "alpha"}, "", "", "password1", "alpha"},
// The same goes if the fields are yet empty: we speculate that we will
// identify them as new password fields once they are filled out, and we
// want to keep our abstract interpretation of the form less flaky.
{{"", ""}, "", "", "password1", ""},
// Two different values should be treated as a password change form, one
// that also asks for the current password, but only once for the new.
{{"alpha", ""}, "password1", "alpha", "password2", ""},
{{"", "beta"}, "password1", "", "password2", "beta"},
{{"alpha", "beta"}, "password1", "alpha", "password2", "beta"}};
for (size_t i = 0; i < ARRAYSIZE_UNSAFE(cases); ++i) {
SCOPED_TRACE(testing::Message() << "Iteration " << i);
PasswordFormBuilder builder(kTestFormActionURL);
builder.AddPasswordField("password1", cases[i].password_values[0], NULL);
builder.AddUsernameField("username1", "William", NULL);
builder.AddPasswordField("password2", cases[i].password_values[1], NULL);
builder.AddUsernameField("username2", "Smith", NULL);
builder.AddSubmitButton("submit", true);
std::string html = builder.ProduceHTML();
scoped_ptr<PasswordForm> password_form;
ASSERT_NO_FATAL_FAILURE(LoadHTMLAndConvertForm(html, &password_form));
ASSERT_TRUE(password_form);
EXPECT_EQ(base::UTF8ToUTF16(cases[i].expected_password_element),
password_form->password_element);
EXPECT_EQ(base::UTF8ToUTF16(cases[i].expected_password_value),
password_form->password_value);
EXPECT_EQ(base::UTF8ToUTF16(cases[i].expected_new_password_element),
password_form->new_password_element);
EXPECT_EQ(base::UTF8ToUTF16(cases[i].expected_new_password_value),
password_form->new_password_value);
// Do a basic sanity check that we are still selecting the right username.
EXPECT_EQ(base::UTF8ToUTF16("username1"), password_form->username_element);
EXPECT_EQ(base::UTF8ToUTF16("William"), password_form->username_value);
EXPECT_THAT(password_form->other_possible_usernames,
testing::ElementsAre(base::UTF8ToUTF16("Smith")));
}
}
TEST_F(PasswordFormConversionUtilsTest, IdentifyingThreePasswordFields) {
// Each test case consists of a set of parameters to be plugged into the
// PasswordFormBuilder below, plus the corresponding expectations.
struct TestCase {
const char* password_values[3];
const char* expected_password_element;
const char* expected_password_value;
const char* expected_new_password_element;
const char* expected_new_password_value;
} cases[] = {
// Two fields with the same value, and one different: we should treat this
// as a password change form with confirmation for the new password. Note
// that we only recognize (current + new + new) and (new + new + current)
// without autocomplete attributes.
{{"alpha", "", ""}, "password1", "alpha", "password2", ""},
{{"", "beta", "beta"}, "password1", "", "password2", "beta"},
{{"alpha", "beta", "beta"}, "password1", "alpha", "password2", "beta"},
{{"beta", "beta", "alpha"}, "password3", "alpha", "password1", "beta"},
// If the fields are yet empty, we speculate that we will identify them as
// (current + new + new) once they are filled out, so we should classify
// them the same for now to keep our abstract interpretation less flaky.
{{"", "", ""}, "password1", "", "password2", ""}};
// Note: In all other cases, we give up and consider the form invalid.
// This is tested in InvalidFormDueToConfusingPasswordFields.
for (size_t i = 0; i < ARRAYSIZE_UNSAFE(cases); ++i) {
SCOPED_TRACE(testing::Message() << "Iteration " << i);
PasswordFormBuilder builder(kTestFormActionURL);
builder.AddPasswordField("password1", cases[i].password_values[0], NULL);
builder.AddUsernameField("username1", "William", NULL);
builder.AddPasswordField("password2", cases[i].password_values[1], NULL);
builder.AddUsernameField("username2", "Smith", NULL);
builder.AddPasswordField("password3", cases[i].password_values[2], NULL);
builder.AddSubmitButton("submit", true);
std::string html = builder.ProduceHTML();
scoped_ptr<PasswordForm> password_form;
ASSERT_NO_FATAL_FAILURE(LoadHTMLAndConvertForm(html, &password_form));
ASSERT_TRUE(password_form);
EXPECT_EQ(base::UTF8ToUTF16(cases[i].expected_password_element),
password_form->password_element);
EXPECT_EQ(base::UTF8ToUTF16(cases[i].expected_password_value),
password_form->password_value);
EXPECT_EQ(base::UTF8ToUTF16(cases[i].expected_new_password_element),
password_form->new_password_element);
EXPECT_EQ(base::UTF8ToUTF16(cases[i].expected_new_password_value),
password_form->new_password_value);
// Do a basic sanity check that we are still selecting the right username.
EXPECT_EQ(base::UTF8ToUTF16("username1"), password_form->username_element);
EXPECT_EQ(base::UTF8ToUTF16("William"), password_form->username_value);
EXPECT_THAT(password_form->other_possible_usernames,
testing::ElementsAre(base::UTF8ToUTF16("Smith")));
} }
} }
TEST_F(PasswordFormConversionUtilsTest, TEST_F(PasswordFormConversionUtilsTest,
PasswordFieldsWithAutocompleteAttributes) { IdentifyingPasswordFieldsWithAutocompleteAttributes) {
// Each test case consists of a set of parameters to be plugged into the // Each test case consists of a set of parameters to be plugged into the
// PasswordFormBuilder below, plus the corresponding expectations. // PasswordFormBuilder below, plus the corresponding expectations.
struct TestCase { struct TestCase {
...@@ -361,23 +487,27 @@ TEST_F(PasswordFormConversionUtilsTest, ...@@ -361,23 +487,27 @@ TEST_F(PasswordFormConversionUtilsTest,
SCOPED_TRACE(testing::Message() << "Iteration " << i); SCOPED_TRACE(testing::Message() << "Iteration " << i);
PasswordFormBuilder builder(kTestFormActionURL); PasswordFormBuilder builder(kTestFormActionURL);
builder.AddPasswordField("pin1", "123456", NULL);
builder.AddPasswordField("pin2", "789101", NULL);
builder.AddPasswordField("password1", "alpha", cases[i].autocomplete[0]); builder.AddPasswordField("password1", "alpha", cases[i].autocomplete[0]);
builder.AddUsernameField("username1", "William", NULL); builder.AddUsernameField("username1", "William", NULL);
builder.AddPasswordField("password2", "beta", cases[i].autocomplete[1]); builder.AddPasswordField("password2", "beta", cases[i].autocomplete[1]);
builder.AddUsernameField("username2", "Smith", NULL); builder.AddUsernameField("username2", "Smith", NULL);
builder.AddPasswordField("password3", "gamma", cases[i].autocomplete[2]); builder.AddPasswordField("password3", "gamma", cases[i].autocomplete[2]);
builder.AddSubmitButton(); builder.AddSubmitButton("submit", true);
std::string html = builder.ProduceHTML(); std::string html = builder.ProduceHTML();
scoped_ptr<PasswordForm> password_form; scoped_ptr<PasswordForm> password_form;
ASSERT_NO_FATAL_FAILURE(LoadHTMLAndConvertForm(html, &password_form)); ASSERT_NO_FATAL_FAILURE(LoadHTMLAndConvertForm(html, &password_form));
ASSERT_NE(static_cast<PasswordForm*>(NULL), password_form.get()); ASSERT_TRUE(password_form);
// Any constellation of password autocomplete attributes should have no // In the absence of username autocomplete attributes, the username should
// effect on that the first text-type input field before a password field // be the text input field before the first password element.
// should be selected as the username. // No constellation of password autocomplete attributes should change that.
EXPECT_EQ(base::UTF8ToUTF16("username1"), password_form->username_element); EXPECT_EQ(base::UTF8ToUTF16("username1"), password_form->username_element);
EXPECT_EQ(base::UTF8ToUTF16("William"), password_form->username_value); EXPECT_EQ(base::UTF8ToUTF16("William"), password_form->username_value);
EXPECT_THAT(password_form->other_possible_usernames,
testing::ElementsAre(base::UTF8ToUTF16("Smith")));
EXPECT_EQ(base::UTF8ToUTF16(cases[i].expected_password_element), EXPECT_EQ(base::UTF8ToUTF16(cases[i].expected_password_element),
password_form->password_element); password_form->password_element);
EXPECT_EQ(base::UTF8ToUTF16(cases[i].expected_password_value), EXPECT_EQ(base::UTF8ToUTF16(cases[i].expected_password_value),
...@@ -386,10 +516,78 @@ TEST_F(PasswordFormConversionUtilsTest, ...@@ -386,10 +516,78 @@ TEST_F(PasswordFormConversionUtilsTest,
password_form->new_password_element); password_form->new_password_element);
EXPECT_EQ(base::UTF8ToUTF16(cases[i].expected_new_password_value), EXPECT_EQ(base::UTF8ToUTF16(cases[i].expected_new_password_value),
password_form->new_password_value); password_form->new_password_value);
ASSERT_EQ(1u, password_form->other_possible_usernames.size());
EXPECT_EQ(base::UTF8ToUTF16("Smith"),
password_form->other_possible_usernames[0]);
} }
} }
TEST_F(PasswordFormConversionUtilsTest, InvalidFormDueToBadActionURL) {
PasswordFormBuilder builder("invalid_target");
builder.AddUsernameField("username", "JohnSmith", NULL);
builder.AddSubmitButton("submit", true);
builder.AddPasswordField("password", "secret", NULL);
std::string html = builder.ProduceHTML();
scoped_ptr<PasswordForm> password_form;
ASSERT_NO_FATAL_FAILURE(LoadHTMLAndConvertForm(html, &password_form));
EXPECT_FALSE(password_form);
}
TEST_F(PasswordFormConversionUtilsTest, InvalidFormDueToNoPasswordFields) {
PasswordFormBuilder builder(kTestFormActionURL);
builder.AddUsernameField("username1", "John", NULL);
builder.AddUsernameField("username2", "Smith", NULL);
builder.AddSubmitButton("submit", true);
std::string html = builder.ProduceHTML();
scoped_ptr<PasswordForm> password_form;
ASSERT_NO_FATAL_FAILURE(LoadHTMLAndConvertForm(html, &password_form));
EXPECT_FALSE(password_form);
}
TEST_F(PasswordFormConversionUtilsTest,
InvalidFormsDueToConfusingPasswordFields) {
// Each test case consists of a set of parameters to be plugged into the
// PasswordFormBuilder below.
const char* cases[][3] = {
// No autocomplete attributes to guide us, and we see:
// * three password values that are all different,
// * three password values that are all the same;
// * three password values with the first and last matching.
// In any case, we should just give up on this form.
{"alpha", "beta", "gamma"},
{"alpha", "alpha", "alpha"},
{"alpha", "beta", "alpha"}};
for (size_t i = 0; i < ARRAYSIZE_UNSAFE(cases); ++i) {
SCOPED_TRACE(testing::Message() << "Iteration " << i);
PasswordFormBuilder builder(kTestFormActionURL);
builder.AddUsernameField("username1", "John", NULL);
builder.AddPasswordField("password1", cases[i][0], NULL);
builder.AddPasswordField("password2", cases[i][1], NULL);
builder.AddPasswordField("password3", cases[i][2], NULL);
builder.AddSubmitButton("submit", true);
std::string html = builder.ProduceHTML();
scoped_ptr<PasswordForm> password_form;
ASSERT_NO_FATAL_FAILURE(LoadHTMLAndConvertForm(html, &password_form));
EXPECT_FALSE(password_form);
}
}
TEST_F(PasswordFormConversionUtilsTest,
InvalidFormDueToTooManyPasswordFieldsWithoutAutocompleteAttributes) {
PasswordFormBuilder builder(kTestFormActionURL);
builder.AddUsernameField("username1", "John", NULL);
builder.AddPasswordField("password1", "alpha", NULL);
builder.AddPasswordField("password2", "alpha", NULL);
builder.AddPasswordField("password3", "alpha", NULL);
builder.AddPasswordField("password4", "alpha", NULL);
builder.AddSubmitButton("submit", true);
std::string html = builder.ProduceHTML();
scoped_ptr<PasswordForm> password_form;
ASSERT_NO_FATAL_FAILURE(LoadHTMLAndConvertForm(html, &password_form));
EXPECT_FALSE(password_form);
}
} // namespace autofill } // namespace autofill
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment