// Copyright (c) 2011 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #include "base/memory/scoped_ptr.h" #include "base/string_util.h" #include "base/utf_string_conversions.h" #include "chrome/browser/autofill/form_structure.h" #include "googleurl/src/gurl.h" #include "testing/gtest/include/gtest/gtest.h" #include "third_party/WebKit/Source/WebKit/chromium/public/WebInputElement.h" #include "webkit/glue/form_data.h" #include "webkit/glue/form_field.h" using webkit_glue::FormData; using WebKit::WebInputElement; namespace webkit_glue { std::ostream& operator<<(std::ostream& os, const FormData& form) { os << UTF16ToUTF8(form.name) << " " << UTF16ToUTF8(form.method) << " " << form.origin.spec() << " " << form.action.spec() << " "; for (std::vector<webkit_glue::FormField>::const_iterator iter = form.fields.begin(); iter != form.fields.end(); ++iter) { os << *iter << " "; } return os; } } // namespace webkit_glue class FormStructureTest { public: static std::string Hash64Bit(const std::string& str) { return FormStructure::Hash64Bit(str); } }; namespace { TEST(FormStructureTest, FieldCount) { FormData form; form.method = ASCIIToUTF16("post"); form.fields.push_back(webkit_glue::FormField(ASCIIToUTF16("username"), ASCIIToUTF16("username"), string16(), ASCIIToUTF16("text"), 0, false)); form.fields.push_back(webkit_glue::FormField(ASCIIToUTF16("password"), ASCIIToUTF16("password"), string16(), ASCIIToUTF16("password"), 0, false)); form.fields.push_back(webkit_glue::FormField(string16(), ASCIIToUTF16("Submit"), string16(), ASCIIToUTF16("submit"), 0, false)); FormStructure form_structure(form); // All fields are counted. EXPECT_EQ(3U, form_structure.field_count()); } TEST(FormStructureTest, AutofillCount) { FormData form; form.method = ASCIIToUTF16("post"); form.fields.push_back(webkit_glue::FormField(ASCIIToUTF16("username"), ASCIIToUTF16("username"), string16(), ASCIIToUTF16("text"), 0, false)); form.fields.push_back(webkit_glue::FormField(ASCIIToUTF16("password"), ASCIIToUTF16("password"), string16(), ASCIIToUTF16("password"), 0, false)); form.fields.push_back(webkit_glue::FormField(ASCIIToUTF16("state"), ASCIIToUTF16("state"), string16(), ASCIIToUTF16("select-one"), 0, false)); form.fields.push_back(webkit_glue::FormField(string16(), ASCIIToUTF16("Submit"), string16(), ASCIIToUTF16("submit"), 0, false)); FormStructure form_structure(form); form_structure.DetermineHeuristicTypes(); // Only text and select fields that are heuristically matched are counted. EXPECT_EQ(1U, form_structure.autofill_count()); } TEST(FormStructureTest, SourceURL) { FormData form; form.origin = GURL("http://www.foo.com/"); form.method = ASCIIToUTF16("post"); FormStructure form_structure(form); EXPECT_EQ(form.origin, form_structure.source_url()); } TEST(FormStructureTest, IsAutofillable) { scoped_ptr<FormStructure> form_structure; FormData form; // We need at least three text fields to be auto-fillable. form.method = ASCIIToUTF16("post"); form.fields.push_back(webkit_glue::FormField(ASCIIToUTF16("username"), ASCIIToUTF16("username"), string16(), ASCIIToUTF16("text"), 0, false)); form.fields.push_back(webkit_glue::FormField(ASCIIToUTF16("password"), ASCIIToUTF16("password"), string16(), ASCIIToUTF16("password"), 0, false)); form.fields.push_back(webkit_glue::FormField(string16(), ASCIIToUTF16("Submit"), string16(), ASCIIToUTF16("submit"), 0, false)); form_structure.reset(new FormStructure(form)); form_structure->DetermineHeuristicTypes(); EXPECT_FALSE(form_structure->IsAutofillable(true)); // We now have three text fields, but only two auto-fillable fields. form.fields.push_back(webkit_glue::FormField(ASCIIToUTF16("First Name"), ASCIIToUTF16("firstname"), string16(), ASCIIToUTF16("text"), 0, false)); form.fields.push_back(webkit_glue::FormField(ASCIIToUTF16("Last Name"), ASCIIToUTF16("lastname"), string16(), ASCIIToUTF16("text"), 0, false)); form_structure.reset(new FormStructure(form)); form_structure->DetermineHeuristicTypes(); EXPECT_FALSE(form_structure->IsAutofillable(true)); // We now have three auto-fillable fields. form.fields.push_back(webkit_glue::FormField(ASCIIToUTF16("Email"), ASCIIToUTF16("email"), string16(), ASCIIToUTF16("text"), 0, false)); form_structure.reset(new FormStructure(form)); form_structure->DetermineHeuristicTypes(); EXPECT_TRUE(form_structure->IsAutofillable(true)); // The method must be 'post', though we can intentionally ignore this // criterion for the sake of providing a helpful warning message to the user. form.method = ASCIIToUTF16("get"); form_structure.reset(new FormStructure(form)); form_structure->DetermineHeuristicTypes(); EXPECT_FALSE(form_structure->IsAutofillable(true)); EXPECT_TRUE(form_structure->IsAutofillable(false)); // The target cannot include http(s)://*/search... form.method = ASCIIToUTF16("post"); form.action = GURL("http://google.com/search?q=hello"); form_structure.reset(new FormStructure(form)); form_structure->DetermineHeuristicTypes(); EXPECT_FALSE(form_structure->IsAutofillable(true)); // But search can be in the URL. form.action = GURL("http://search.com/?q=hello"); form_structure.reset(new FormStructure(form)); form_structure->DetermineHeuristicTypes(); EXPECT_TRUE(form_structure->IsAutofillable(true)); } TEST(FormStructureTest, HeuristicsContactInfo) { scoped_ptr<FormStructure> form_structure; FormData form; form.method = ASCIIToUTF16("post"); form.fields.push_back(webkit_glue::FormField(ASCIIToUTF16("First Name"), ASCIIToUTF16("firstname"), string16(), ASCIIToUTF16("text"), 0, false)); form.fields.push_back(webkit_glue::FormField(ASCIIToUTF16("Last Name"), ASCIIToUTF16("lastname"), string16(), ASCIIToUTF16("text"), 0, false)); form.fields.push_back(webkit_glue::FormField(ASCIIToUTF16("EMail"), ASCIIToUTF16("email"), string16(), ASCIIToUTF16("text"), 0, false)); form.fields.push_back(webkit_glue::FormField(ASCIIToUTF16("Phone"), ASCIIToUTF16("phone"), string16(), ASCIIToUTF16("text"), 0, false)); form.fields.push_back(webkit_glue::FormField(ASCIIToUTF16("Fax"), ASCIIToUTF16("fax"), string16(), ASCIIToUTF16("text"), 0, false)); form.fields.push_back(webkit_glue::FormField(ASCIIToUTF16("Address"), ASCIIToUTF16("address"), string16(), ASCIIToUTF16("text"), 0, false)); form.fields.push_back(webkit_glue::FormField(ASCIIToUTF16("City"), ASCIIToUTF16("city"), string16(), ASCIIToUTF16("text"), 0, false)); form.fields.push_back(webkit_glue::FormField(ASCIIToUTF16("Zip code"), ASCIIToUTF16("zipcode"), string16(), ASCIIToUTF16("text"), 0, false)); form.fields.push_back(webkit_glue::FormField(string16(), ASCIIToUTF16("Submit"), string16(), ASCIIToUTF16("submit"), 0, false)); form_structure.reset(new FormStructure(form)); form_structure->DetermineHeuristicTypes(); EXPECT_TRUE(form_structure->IsAutofillable(true)); // Expect the correct number of fields. ASSERT_EQ(9U, form_structure->field_count()); ASSERT_EQ(8U, form_structure->autofill_count()); // First name. EXPECT_EQ(NAME_FIRST, form_structure->field(0)->heuristic_type()); // Last name. EXPECT_EQ(NAME_LAST, form_structure->field(1)->heuristic_type()); // Email. EXPECT_EQ(EMAIL_ADDRESS, form_structure->field(2)->heuristic_type()); // Phone. EXPECT_EQ(PHONE_HOME_WHOLE_NUMBER, form_structure->field(3)->heuristic_type()); // Fax. EXPECT_EQ(PHONE_FAX_WHOLE_NUMBER, form_structure->field(4)->heuristic_type()); // Address. EXPECT_EQ(ADDRESS_HOME_LINE1, form_structure->field(5)->heuristic_type()); // City. EXPECT_EQ(ADDRESS_HOME_CITY, form_structure->field(6)->heuristic_type()); // Zip. EXPECT_EQ(ADDRESS_HOME_ZIP, form_structure->field(7)->heuristic_type()); // Submit. EXPECT_EQ(UNKNOWN_TYPE, form_structure->field(8)->heuristic_type()); } TEST(FormStructureTest, HeuristicsSample8) { scoped_ptr<FormStructure> form_structure; FormData form; form.method = ASCIIToUTF16("post"); form.fields.push_back( webkit_glue::FormField(ASCIIToUTF16("Your First Name:"), ASCIIToUTF16("bill.first"), string16(), ASCIIToUTF16("text"), 0, false)); form.fields.push_back( webkit_glue::FormField(ASCIIToUTF16("Your Last Name:"), ASCIIToUTF16("bill.last"), string16(), ASCIIToUTF16("text"), 0, false)); form.fields.push_back( webkit_glue::FormField(ASCIIToUTF16("Street Address Line 1:"), ASCIIToUTF16("bill.street1"), string16(), ASCIIToUTF16("text"), 0, false)); form.fields.push_back( webkit_glue::FormField(ASCIIToUTF16("Street Address Line 2:"), ASCIIToUTF16("bill.street2"), string16(), ASCIIToUTF16("text"), 0, false)); form.fields.push_back( webkit_glue::FormField(ASCIIToUTF16("City:"), ASCIIToUTF16("bill.city"), string16(), ASCIIToUTF16("text"), 0, false)); form.fields.push_back( webkit_glue::FormField(ASCIIToUTF16("State (U.S.):"), ASCIIToUTF16("bill.state"), string16(), ASCIIToUTF16("text"), 0, false)); form.fields.push_back( webkit_glue::FormField(ASCIIToUTF16("Zip/Postal Code:"), ASCIIToUTF16("BillTo.PostalCode"), string16(), ASCIIToUTF16("text"), 0, false)); form.fields.push_back( webkit_glue::FormField(ASCIIToUTF16("Country:"), ASCIIToUTF16("bill.country"), string16(), ASCIIToUTF16("text"), 0, false)); form.fields.push_back( webkit_glue::FormField(ASCIIToUTF16("Phone Number:"), ASCIIToUTF16("BillTo.Phone"), string16(), ASCIIToUTF16("text"), 0, false)); form.fields.push_back( webkit_glue::FormField(string16(), ASCIIToUTF16("Submit"), string16(), ASCIIToUTF16("submit"), 0, false)); form_structure.reset(new FormStructure(form)); form_structure->DetermineHeuristicTypes(); EXPECT_TRUE(form_structure->IsAutofillable(true)); ASSERT_EQ(10U, form_structure->field_count()); ASSERT_EQ(9U, form_structure->autofill_count()); // First name. EXPECT_EQ(NAME_FIRST, form_structure->field(0)->heuristic_type()); // Last name. EXPECT_EQ(NAME_LAST, form_structure->field(1)->heuristic_type()); // Address. EXPECT_EQ(ADDRESS_BILLING_LINE1, form_structure->field(2)->heuristic_type()); // Address. EXPECT_EQ(ADDRESS_BILLING_LINE2, form_structure->field(3)->heuristic_type()); // City. EXPECT_EQ(ADDRESS_BILLING_CITY, form_structure->field(4)->heuristic_type()); // State. EXPECT_EQ(ADDRESS_BILLING_STATE, form_structure->field(5)->heuristic_type()); // Zip. EXPECT_EQ(ADDRESS_BILLING_ZIP, form_structure->field(6)->heuristic_type()); // Country. EXPECT_EQ(ADDRESS_BILLING_COUNTRY, form_structure->field(7)->heuristic_type()); // Phone. EXPECT_EQ(PHONE_HOME_WHOLE_NUMBER, form_structure->field(8)->heuristic_type()); // Submit. EXPECT_EQ(UNKNOWN_TYPE, form_structure->field(9)->heuristic_type()); } TEST(FormStructureTest, HeuristicsSample6) { scoped_ptr<FormStructure> form_structure; FormData form; form.method = ASCIIToUTF16("post"); form.fields.push_back( webkit_glue::FormField(ASCIIToUTF16("E-mail address"), ASCIIToUTF16("email"), string16(), ASCIIToUTF16("text"), 0, false)); form.fields.push_back( webkit_glue::FormField(ASCIIToUTF16("Full name"), ASCIIToUTF16("name"), string16(), ASCIIToUTF16("text"), 0, false)); form.fields.push_back( webkit_glue::FormField(ASCIIToUTF16("Company"), ASCIIToUTF16("company"), string16(), ASCIIToUTF16("text"), 0, false)); form.fields.push_back( webkit_glue::FormField(ASCIIToUTF16("Address"), ASCIIToUTF16("address"), string16(), ASCIIToUTF16("text"), 0, false)); form.fields.push_back( webkit_glue::FormField(ASCIIToUTF16("City"), ASCIIToUTF16("city"), string16(), ASCIIToUTF16("text"), 0, false)); // TODO(jhawkins): Add state select control. form.fields.push_back( webkit_glue::FormField(ASCIIToUTF16("Zip Code"), ASCIIToUTF16("Home.PostalCode"), string16(), ASCIIToUTF16("text"), 0, false)); // TODO(jhawkins): Phone number. form.fields.push_back( webkit_glue::FormField(string16(), ASCIIToUTF16("Submit"), ASCIIToUTF16("continue"), ASCIIToUTF16("submit"), 0, false)); form_structure.reset(new FormStructure(form)); form_structure->DetermineHeuristicTypes(); EXPECT_TRUE(form_structure->IsAutofillable(true)); ASSERT_EQ(7U, form_structure->field_count()); ASSERT_EQ(6U, form_structure->autofill_count()); // Email. EXPECT_EQ(EMAIL_ADDRESS, form_structure->field(0)->heuristic_type()); // Full name. EXPECT_EQ(NAME_FULL, form_structure->field(1)->heuristic_type()); // Company EXPECT_EQ(COMPANY_NAME, form_structure->field(2)->heuristic_type()); // Address. EXPECT_EQ(ADDRESS_HOME_LINE1, form_structure->field(3)->heuristic_type()); // City. EXPECT_EQ(ADDRESS_HOME_CITY, form_structure->field(4)->heuristic_type()); // Zip. EXPECT_EQ(ADDRESS_HOME_ZIP, form_structure->field(5)->heuristic_type()); // Submit. EXPECT_EQ(UNKNOWN_TYPE, form_structure->field(6)->heuristic_type()); } // Tests a sequence of FormFields where only labels are supplied to heuristics // for matching. This works because FormField labels are matched in the case // that input element ids (or |name| fields) are missing. TEST(FormStructureTest, HeuristicsLabelsOnly) { scoped_ptr<FormStructure> form_structure; FormData form; form.method = ASCIIToUTF16("post"); form.fields.push_back(webkit_glue::FormField(ASCIIToUTF16("First Name"), string16(), string16(), ASCIIToUTF16("text"), 0, false)); form.fields.push_back(webkit_glue::FormField(ASCIIToUTF16("Last Name"), string16(), string16(), ASCIIToUTF16("text"), 0, false)); form.fields.push_back(webkit_glue::FormField(ASCIIToUTF16("EMail"), string16(), string16(), ASCIIToUTF16("text"), 0, false)); form.fields.push_back(webkit_glue::FormField(ASCIIToUTF16("Phone"), string16(), string16(), ASCIIToUTF16("text"), 0, false)); form.fields.push_back(webkit_glue::FormField(ASCIIToUTF16("Fax"), string16(), string16(), ASCIIToUTF16("text"), 0, false)); form.fields.push_back(webkit_glue::FormField(ASCIIToUTF16("Address"), string16(), string16(), ASCIIToUTF16("text"), 0, false)); form.fields.push_back(webkit_glue::FormField(ASCIIToUTF16("Address"), string16(), string16(), ASCIIToUTF16("text"), 0, false)); form.fields.push_back(webkit_glue::FormField(ASCIIToUTF16("Zip code"), string16(), string16(), ASCIIToUTF16("text"), 0, false)); form.fields.push_back(webkit_glue::FormField(string16(), ASCIIToUTF16("Submit"), string16(), ASCIIToUTF16("submit"), 0, false)); form_structure.reset(new FormStructure(form)); form_structure->DetermineHeuristicTypes(); EXPECT_TRUE(form_structure->IsAutofillable(true)); ASSERT_EQ(9U, form_structure->field_count()); ASSERT_EQ(8U, form_structure->autofill_count()); // First name. EXPECT_EQ(NAME_FIRST, form_structure->field(0)->heuristic_type()); // Last name. EXPECT_EQ(NAME_LAST, form_structure->field(1)->heuristic_type()); // Email. EXPECT_EQ(EMAIL_ADDRESS, form_structure->field(2)->heuristic_type()); // Phone. EXPECT_EQ(PHONE_HOME_WHOLE_NUMBER, form_structure->field(3)->heuristic_type()); // Fax. EXPECT_EQ(PHONE_FAX_WHOLE_NUMBER, form_structure->field(4)->heuristic_type()); // Address. EXPECT_EQ(ADDRESS_HOME_LINE1, form_structure->field(5)->heuristic_type()); // Address Line 2. EXPECT_EQ(ADDRESS_HOME_LINE2, form_structure->field(6)->heuristic_type()); // Zip. EXPECT_EQ(ADDRESS_HOME_ZIP, form_structure->field(7)->heuristic_type()); // Submit. EXPECT_EQ(UNKNOWN_TYPE, form_structure->field(8)->heuristic_type()); } TEST(FormStructureTest, HeuristicsCreditCardInfo) { scoped_ptr<FormStructure> form_structure; FormData form; form.method = ASCIIToUTF16("post"); form.fields.push_back(webkit_glue::FormField(ASCIIToUTF16("Name on Card"), ASCIIToUTF16("name on card"), string16(), ASCIIToUTF16("text"), 0, false)); form.fields.push_back(webkit_glue::FormField(ASCIIToUTF16("Card Number"), ASCIIToUTF16("card_number"), string16(), ASCIIToUTF16("text"), 0, false)); form.fields.push_back(webkit_glue::FormField(ASCIIToUTF16("Exp Month"), ASCIIToUTF16("ccmonth"), string16(), ASCIIToUTF16("text"), 0, false)); form.fields.push_back(webkit_glue::FormField(ASCIIToUTF16("Exp Year"), ASCIIToUTF16("ccyear"), string16(), ASCIIToUTF16("text"), 0, false)); form.fields.push_back(webkit_glue::FormField(ASCIIToUTF16("Verification"), ASCIIToUTF16("verification"), string16(), ASCIIToUTF16("text"), 0, false)); form.fields.push_back(webkit_glue::FormField(string16(), ASCIIToUTF16("Submit"), string16(), ASCIIToUTF16("submit"), 0, false)); form_structure.reset(new FormStructure(form)); form_structure->DetermineHeuristicTypes(); EXPECT_TRUE(form_structure->IsAutofillable(true)); ASSERT_EQ(6U, form_structure->field_count()); ASSERT_EQ(4U, form_structure->autofill_count()); // Credit card name. EXPECT_EQ(CREDIT_CARD_NAME, form_structure->field(0)->heuristic_type()); // Credit card number. EXPECT_EQ(CREDIT_CARD_NUMBER, form_structure->field(1)->heuristic_type()); // Credit card expiration month. EXPECT_EQ(CREDIT_CARD_EXP_MONTH, form_structure->field(2)->heuristic_type()); // Credit card expiration year. EXPECT_EQ(CREDIT_CARD_EXP_4_DIGIT_YEAR, form_structure->field(3)->heuristic_type()); // We don't determine CVV. EXPECT_EQ(UNKNOWN_TYPE, form_structure->field(4)->heuristic_type()); // Submit. EXPECT_EQ(UNKNOWN_TYPE, form_structure->field(5)->heuristic_type()); } TEST(FormStructureTest, HeuristicsCreditCardInfoWithUnknownCardField) { scoped_ptr<FormStructure> form_structure; FormData form; form.method = ASCIIToUTF16("post"); form.fields.push_back(webkit_glue::FormField(ASCIIToUTF16("Name on Card"), ASCIIToUTF16("name on card"), string16(), ASCIIToUTF16("text"), 0, false)); // This is not a field we know how to process. But we should skip over it // and process the other fields in the card block. form.fields.push_back(webkit_glue::FormField(ASCIIToUTF16("Card Type"), ASCIIToUTF16("card_type"), string16(), ASCIIToUTF16("text"), 0, false)); form.fields.push_back(webkit_glue::FormField(ASCIIToUTF16("Card Number"), ASCIIToUTF16("card_number"), string16(), ASCIIToUTF16("text"), 0, false)); form.fields.push_back(webkit_glue::FormField(ASCIIToUTF16("Exp Month"), ASCIIToUTF16("ccmonth"), string16(), ASCIIToUTF16("text"), 0, false)); form.fields.push_back(webkit_glue::FormField(ASCIIToUTF16("Exp Year"), ASCIIToUTF16("ccyear"), string16(), ASCIIToUTF16("text"), 0, false)); form.fields.push_back(webkit_glue::FormField(ASCIIToUTF16("Verification"), ASCIIToUTF16("verification"), string16(), ASCIIToUTF16("text"), 0, false)); form.fields.push_back(webkit_glue::FormField(string16(), ASCIIToUTF16("Submit"), string16(), ASCIIToUTF16("submit"), 0, false)); form_structure.reset(new FormStructure(form)); form_structure->DetermineHeuristicTypes(); EXPECT_TRUE(form_structure->IsAutofillable(true)); ASSERT_EQ(7U, form_structure->field_count()); ASSERT_EQ(4U, form_structure->autofill_count()); // Credit card name. EXPECT_EQ(CREDIT_CARD_NAME, form_structure->field(0)->heuristic_type()); // Credit card type. This is an unknown type but related to the credit card. EXPECT_EQ(UNKNOWN_TYPE, form_structure->field(1)->heuristic_type()); // Credit card number. EXPECT_EQ(CREDIT_CARD_NUMBER, form_structure->field(2)->heuristic_type()); // Credit card expiration month. EXPECT_EQ(CREDIT_CARD_EXP_MONTH, form_structure->field(3)->heuristic_type()); // Credit card expiration year. EXPECT_EQ(CREDIT_CARD_EXP_4_DIGIT_YEAR, form_structure->field(4)->heuristic_type()); // We don't determine CVV. EXPECT_EQ(UNKNOWN_TYPE, form_structure->field(5)->heuristic_type()); // Submit. EXPECT_EQ(UNKNOWN_TYPE, form_structure->field(6)->heuristic_type()); } TEST(FormStructureTest, ThreeAddressLines) { scoped_ptr<FormStructure> form_structure; FormData form; form.method = ASCIIToUTF16("post"); form.fields.push_back( webkit_glue::FormField(ASCIIToUTF16("Address Line1"), ASCIIToUTF16("Address"), string16(), ASCIIToUTF16("text"), 0, false)); form.fields.push_back( webkit_glue::FormField(ASCIIToUTF16("Address Line2"), ASCIIToUTF16("Address"), string16(), ASCIIToUTF16("text"), 0, false)); form.fields.push_back( webkit_glue::FormField(ASCIIToUTF16("Address Line3"), ASCIIToUTF16("Address"), string16(), ASCIIToUTF16("text"), 0, false)); form.fields.push_back( webkit_glue::FormField(ASCIIToUTF16("City"), ASCIIToUTF16("city"), string16(), ASCIIToUTF16("text"), 0, false)); form_structure.reset(new FormStructure(form)); form_structure->DetermineHeuristicTypes(); EXPECT_TRUE(form_structure->IsAutofillable(true)); ASSERT_EQ(4U, form_structure->field_count()); ASSERT_EQ(3U, form_structure->autofill_count()); // Address Line 1. EXPECT_EQ(ADDRESS_HOME_LINE1, form_structure->field(0)->heuristic_type()); // Address Line 2. EXPECT_EQ(ADDRESS_HOME_LINE2, form_structure->field(1)->heuristic_type()); // Address Line 3. EXPECT_EQ(UNKNOWN_TYPE, form_structure->field(2)->heuristic_type()); // City. EXPECT_EQ(ADDRESS_HOME_CITY, form_structure->field(3)->heuristic_type()); } // This test verifies that "addressLine1" and "addressLine2" matches heuristics. // This occured in https://www.gorillaclothing.com/. http://crbug.com/52126. TEST(FormStructureTest, BillingAndShippingAddresses) { scoped_ptr<FormStructure> form_structure; FormData form; form.method = ASCIIToUTF16("post"); form.fields.push_back( webkit_glue::FormField(ASCIIToUTF16("Address Line1"), ASCIIToUTF16("shipping.address.addressLine1"), string16(), ASCIIToUTF16("text"), 0, false)); form.fields.push_back( webkit_glue::FormField(ASCIIToUTF16("Address Line2"), ASCIIToUTF16("shipping.address.addressLine2"), string16(), ASCIIToUTF16("text"), 0, false)); form.fields.push_back( webkit_glue::FormField(ASCIIToUTF16("Address Line1"), ASCIIToUTF16("billing.address.addressLine1"), string16(), ASCIIToUTF16("text"), 0, false)); form.fields.push_back( webkit_glue::FormField(ASCIIToUTF16("Address Line2"), ASCIIToUTF16("billing.address.addressLine2"), string16(), ASCIIToUTF16("text"), 0, false)); form_structure.reset(new FormStructure(form)); form_structure->DetermineHeuristicTypes(); EXPECT_TRUE(form_structure->IsAutofillable(true)); ASSERT_EQ(4U, form_structure->field_count()); ASSERT_EQ(4U, form_structure->autofill_count()); // Address Line 1. EXPECT_EQ(ADDRESS_HOME_LINE1, form_structure->field(0)->heuristic_type()); // Address Line 2. EXPECT_EQ(ADDRESS_HOME_LINE2, form_structure->field(1)->heuristic_type()); // Address Line 1. EXPECT_EQ(ADDRESS_BILLING_LINE1, form_structure->field(2)->heuristic_type()); // Address Line 2. EXPECT_EQ(ADDRESS_BILLING_LINE2, form_structure->field(3)->heuristic_type()); } // This example comes from expedia.com where they use a "Suite" label to // indicate a suite or apartment number. We interpret this as address line 2. // And the following "Street address second line" we interpret as address line // 3 and discard. // See http://crbug.com/48197 for details. TEST(FormStructureTest, ThreeAddressLinesExpedia) { scoped_ptr<FormStructure> form_structure; FormData form; form.method = ASCIIToUTF16("post"); form.fields.push_back( webkit_glue::FormField(ASCIIToUTF16("Street:"), ASCIIToUTF16("FOPIH_RgWebCC_0_IHAddress_ads1"), string16(), ASCIIToUTF16("text"), 0, false)); form.fields.push_back( webkit_glue::FormField(ASCIIToUTF16("Suite or Apt:"), ASCIIToUTF16("FOPIH_RgWebCC_0_IHAddress_adap"), string16(), ASCIIToUTF16("text"), 0, false)); form.fields.push_back( webkit_glue::FormField(ASCIIToUTF16("Street address second line"), ASCIIToUTF16("FOPIH_RgWebCC_0_IHAddress_ads2"), string16(), ASCIIToUTF16("text"), 0, false)); form.fields.push_back( webkit_glue::FormField(ASCIIToUTF16("City:"), ASCIIToUTF16("FOPIH_RgWebCC_0_IHAddress_adct"), string16(), ASCIIToUTF16("text"), 0, false)); form_structure.reset(new FormStructure(form)); form_structure->DetermineHeuristicTypes(); EXPECT_TRUE(form_structure->IsAutofillable(true)); ASSERT_EQ(4U, form_structure->field_count()); ASSERT_EQ(3U, form_structure->autofill_count()); // Address Line 1. EXPECT_EQ(ADDRESS_HOME_LINE1, form_structure->field(0)->heuristic_type()); // Suite / Apt. EXPECT_EQ(ADDRESS_HOME_LINE2, form_structure->field(1)->heuristic_type()); // Address Line 3. EXPECT_EQ(UNKNOWN_TYPE, form_structure->field(2)->heuristic_type()); // City. EXPECT_EQ(ADDRESS_HOME_CITY, form_structure->field(3)->heuristic_type()); } // This example comes from ebay.com where the word "suite" appears in the label // and the name "address2" clearly indicates that this is the address line 2. // See http://crbug.com/48197 for details. TEST(FormStructureTest, TwoAddressLinesEbay) { scoped_ptr<FormStructure> form_structure; FormData form; form.method = ASCIIToUTF16("post"); form.fields.push_back( webkit_glue::FormField(ASCIIToUTF16("Address Line1"), ASCIIToUTF16("address1"), string16(), ASCIIToUTF16("text"), 0, false)); form.fields.push_back( webkit_glue::FormField(ASCIIToUTF16("Floor number, suite number, etc"), ASCIIToUTF16("address2"), string16(), ASCIIToUTF16("text"), 0, false)); form.fields.push_back( webkit_glue::FormField(ASCIIToUTF16("City"), ASCIIToUTF16("city"), string16(), ASCIIToUTF16("text"), 0, false)); form_structure.reset(new FormStructure(form)); form_structure->DetermineHeuristicTypes(); EXPECT_TRUE(form_structure->IsAutofillable(true)); ASSERT_EQ(3U, form_structure->field_count()); ASSERT_EQ(3U, form_structure->autofill_count()); // Address Line 1. EXPECT_EQ(ADDRESS_HOME_LINE1, form_structure->field(0)->heuristic_type()); // Address Line 2. EXPECT_EQ(ADDRESS_HOME_LINE2, form_structure->field(1)->heuristic_type()); // City. EXPECT_EQ(ADDRESS_HOME_CITY, form_structure->field(2)->heuristic_type()); } TEST(FormStructureTest, HeuristicsStateWithProvince) { scoped_ptr<FormStructure> form_structure; FormData form; form.method = ASCIIToUTF16("post"); form.fields.push_back( webkit_glue::FormField(ASCIIToUTF16("Address Line1"), ASCIIToUTF16("Address"), string16(), ASCIIToUTF16("text"), 0, false)); form.fields.push_back( webkit_glue::FormField(ASCIIToUTF16("Address Line2"), ASCIIToUTF16("Address"), string16(), ASCIIToUTF16("text"), 0, false)); form.fields.push_back( webkit_glue::FormField(ASCIIToUTF16("State/Province/Region"), ASCIIToUTF16("State"), string16(), ASCIIToUTF16("text"), 0, false)); form_structure.reset(new FormStructure(form)); form_structure->DetermineHeuristicTypes(); EXPECT_TRUE(form_structure->IsAutofillable(true)); ASSERT_EQ(3U, form_structure->field_count()); ASSERT_EQ(3U, form_structure->autofill_count()); // Address Line 1. EXPECT_EQ(ADDRESS_HOME_LINE1, form_structure->field(0)->heuristic_type()); // Address Line 2. EXPECT_EQ(ADDRESS_HOME_LINE2, form_structure->field(1)->heuristic_type()); // State. EXPECT_EQ(ADDRESS_HOME_STATE, form_structure->field(2)->heuristic_type()); } // This example comes from lego.com's checkout page. TEST(FormStructureTest, HeuristicsWithBilling) { scoped_ptr<FormStructure> form_structure; FormData form; form.method = ASCIIToUTF16("post"); form.fields.push_back( webkit_glue::FormField(ASCIIToUTF16("First Name*:"), ASCIIToUTF16("editBillingAddress$firstNameBox"), string16(), ASCIIToUTF16("text"), 0, false)); form.fields.push_back( webkit_glue::FormField(ASCIIToUTF16("Last Name*:"), ASCIIToUTF16("editBillingAddress$lastNameBox"), string16(), ASCIIToUTF16("text"), 0, false)); form.fields.push_back( webkit_glue::FormField(ASCIIToUTF16("Company Name:"), ASCIIToUTF16("editBillingAddress$companyBox"), string16(), ASCIIToUTF16("text"), 0, false)); form.fields.push_back( webkit_glue::FormField(ASCIIToUTF16("Address*:"), ASCIIToUTF16("editBillingAddress$addressLine1Box"), string16(), ASCIIToUTF16("text"), 0, false)); form.fields.push_back( webkit_glue::FormField(ASCIIToUTF16("Apt/Suite :"), ASCIIToUTF16("editBillingAddress$addressLine2Box"), string16(), ASCIIToUTF16("text"), 0, false)); form.fields.push_back( webkit_glue::FormField(ASCIIToUTF16("City*:"), ASCIIToUTF16("editBillingAddress$cityBox"), string16(), ASCIIToUTF16("text"), 0, false)); form.fields.push_back( webkit_glue::FormField(ASCIIToUTF16("State/Province*:"), ASCIIToUTF16("editBillingAddress$stateDropDown"), string16(), ASCIIToUTF16("text"), 0, false)); form.fields.push_back( webkit_glue::FormField(ASCIIToUTF16("Country*:"), ASCIIToUTF16("editBillingAddress$countryDropDown"), string16(), ASCIIToUTF16("text"), 0, false)); form.fields.push_back( webkit_glue::FormField(ASCIIToUTF16("Postal Code*:"), ASCIIToUTF16("editBillingAddress$zipCodeBox"), string16(), ASCIIToUTF16("text"), 0, false)); form.fields.push_back( webkit_glue::FormField(ASCIIToUTF16("Phone*:"), ASCIIToUTF16("editBillingAddress$phoneBox"), string16(), ASCIIToUTF16("text"), 0, false)); form.fields.push_back( webkit_glue::FormField(ASCIIToUTF16("Email Address*:"), ASCIIToUTF16("email$emailBox"), string16(), ASCIIToUTF16("text"), 0, false)); form_structure.reset(new FormStructure(form)); form_structure->DetermineHeuristicTypes(); EXPECT_TRUE(form_structure->IsAutofillable(true)); ASSERT_EQ(11U, form_structure->field_count()); ASSERT_EQ(11U, form_structure->autofill_count()); EXPECT_EQ(NAME_FIRST, form_structure->field(0)->heuristic_type()); EXPECT_EQ(NAME_LAST, form_structure->field(1)->heuristic_type()); EXPECT_EQ(COMPANY_NAME, form_structure->field(2)->heuristic_type()); EXPECT_EQ(ADDRESS_BILLING_LINE1, form_structure->field(3)->heuristic_type()); EXPECT_EQ(ADDRESS_BILLING_LINE2, form_structure->field(4)->heuristic_type()); EXPECT_EQ(ADDRESS_BILLING_CITY, form_structure->field(5)->heuristic_type()); EXPECT_EQ(ADDRESS_BILLING_STATE, form_structure->field(6)->heuristic_type()); EXPECT_EQ(ADDRESS_BILLING_COUNTRY, form_structure->field(7)->heuristic_type()); EXPECT_EQ(ADDRESS_BILLING_ZIP, form_structure->field(8)->heuristic_type()); EXPECT_EQ(PHONE_HOME_WHOLE_NUMBER, form_structure->field(9)->heuristic_type()); EXPECT_EQ(EMAIL_ADDRESS, form_structure->field(10)->heuristic_type()); } TEST(FormStructureTest, ThreePartPhoneNumber) { scoped_ptr<FormStructure> form_structure; FormData form; form.method = ASCIIToUTF16("post"); form.fields.push_back( webkit_glue::FormField(ASCIIToUTF16("Phone:"), ASCIIToUTF16("dayphone1"), string16(), ASCIIToUTF16("text"), 0, false)); form.fields.push_back( webkit_glue::FormField(ASCIIToUTF16("-"), ASCIIToUTF16("dayphone2"), string16(), ASCIIToUTF16("text"), 3, // Size of prefix is 3. false)); form.fields.push_back( webkit_glue::FormField(ASCIIToUTF16("-"), ASCIIToUTF16("dayphone3"), string16(), ASCIIToUTF16("text"), 4, // Size of suffix is 4. If unlimited size is // passed, phone will be parsed as // <country code> - <area code> - <phone>. false)); form.fields.push_back( webkit_glue::FormField(ASCIIToUTF16("ext.:"), ASCIIToUTF16("dayphone4"), string16(), ASCIIToUTF16("text"), 0, false)); form_structure.reset(new FormStructure(form)); form_structure->DetermineHeuristicTypes(); EXPECT_TRUE(form_structure->IsAutofillable(true)); ASSERT_EQ(4U, form_structure->field_count()); ASSERT_EQ(3U, form_structure->autofill_count()); // Area code. EXPECT_EQ(PHONE_HOME_CITY_CODE, form_structure->field(0)->heuristic_type()); // Phone number suffix. EXPECT_EQ(PHONE_HOME_NUMBER, form_structure->field(1)->heuristic_type()); // Phone number suffix. EXPECT_EQ(PHONE_HOME_NUMBER, form_structure->field(2)->heuristic_type()); // Unknown. EXPECT_EQ(UNKNOWN_TYPE, form_structure->field(3)->heuristic_type()); } TEST(FormStructureTest, HeuristicsInfernoCC) { scoped_ptr<FormStructure> form_structure; FormData form; form.method = ASCIIToUTF16("post"); form.fields.push_back(webkit_glue::FormField(ASCIIToUTF16("Name on Card"), ASCIIToUTF16("name_on_card"), string16(), ASCIIToUTF16("text"), 0, false)); form.fields.push_back(webkit_glue::FormField(ASCIIToUTF16("Address"), ASCIIToUTF16("billing_address"), string16(), ASCIIToUTF16("text"), 0, false)); form.fields.push_back(webkit_glue::FormField(ASCIIToUTF16("Card Number"), ASCIIToUTF16("card_number"), string16(), ASCIIToUTF16("text"), 0, false)); form.fields.push_back(webkit_glue::FormField(ASCIIToUTF16("Expiration Date"), ASCIIToUTF16("expiration_month"), string16(), ASCIIToUTF16("text"), 0, false)); form.fields.push_back(webkit_glue::FormField(ASCIIToUTF16("Expiration Year"), ASCIIToUTF16("expiration_year"), string16(), ASCIIToUTF16("text"), 0, false)); form_structure.reset(new FormStructure(form)); form_structure->DetermineHeuristicTypes(); EXPECT_TRUE(form_structure->IsAutofillable(true)); // Expect the correct number of fields. ASSERT_EQ(5U, form_structure->field_count()); ASSERT_EQ(5U, form_structure->autofill_count()); // Name on Card. EXPECT_EQ(CREDIT_CARD_NAME, form_structure->field(0)->heuristic_type()); // Address. EXPECT_EQ(ADDRESS_BILLING_LINE1, form_structure->field(1)->heuristic_type()); // Card Number. EXPECT_EQ(CREDIT_CARD_NUMBER, form_structure->field(2)->heuristic_type()); // Expiration Date. EXPECT_EQ(CREDIT_CARD_EXP_MONTH, form_structure->field(3)->heuristic_type()); // Expiration Year. EXPECT_EQ(CREDIT_CARD_EXP_4_DIGIT_YEAR, form_structure->field(4)->heuristic_type()); } TEST(FormStructureTest, CVCCodeClash) { scoped_ptr<FormStructure> form_structure; FormData form; form.method = ASCIIToUTF16("post"); form.fields.push_back(webkit_glue::FormField(ASCIIToUTF16("Card number"), ASCIIToUTF16("ccnumber"), string16(), ASCIIToUTF16("text"), 0, false)); form.fields.push_back(webkit_glue::FormField(ASCIIToUTF16("First name"), ASCIIToUTF16("first_name"), string16(), ASCIIToUTF16("text"), 0, false)); form.fields.push_back(webkit_glue::FormField(ASCIIToUTF16("Last name"), ASCIIToUTF16("last_name"), string16(), ASCIIToUTF16("text"), 0, false)); form.fields.push_back(webkit_glue::FormField(ASCIIToUTF16("Expiration date"), ASCIIToUTF16("ccexpiresmonth"), string16(), ASCIIToUTF16("text"), 0, false)); form.fields.push_back(webkit_glue::FormField(ASCIIToUTF16(""), ASCIIToUTF16("ccexpiresyear"), string16(), ASCIIToUTF16("text"), 0, false)); form.fields.push_back(webkit_glue::FormField(ASCIIToUTF16("cvc number"), ASCIIToUTF16("csc"), string16(), ASCIIToUTF16("text"), 0, false)); form_structure.reset(new FormStructure(form)); form_structure->DetermineHeuristicTypes(); EXPECT_TRUE(form_structure->IsAutofillable(true)); // Expect the correct number of fields. ASSERT_EQ(6U, form_structure->field_count()); ASSERT_EQ(4U, form_structure->autofill_count()); // Card Number. EXPECT_EQ(CREDIT_CARD_NUMBER, form_structure->field(0)->heuristic_type()); // First name, taken as name on card. EXPECT_EQ(CREDIT_CARD_NAME, form_structure->field(1)->heuristic_type()); // Last name is not merged. EXPECT_EQ(UNKNOWN_TYPE, form_structure->field(2)->heuristic_type()); // Expiration Date. EXPECT_EQ(CREDIT_CARD_EXP_MONTH, form_structure->field(3)->heuristic_type()); // Expiration Year. EXPECT_EQ(CREDIT_CARD_EXP_4_DIGIT_YEAR, form_structure->field(4)->heuristic_type()); // CVC code should not match. EXPECT_EQ(UNKNOWN_TYPE, form_structure->field(5)->heuristic_type()); } TEST(FormStructureTest, EncodeQueryRequest) { FormData form; form.method = ASCIIToUTF16("post"); form.fields.push_back(webkit_glue::FormField(ASCIIToUTF16("Name on Card"), ASCIIToUTF16("name_on_card"), string16(), ASCIIToUTF16("text"), 0, false)); form.fields.push_back(webkit_glue::FormField(ASCIIToUTF16("Address"), ASCIIToUTF16("billing_address"), string16(), ASCIIToUTF16("text"), 0, false)); form.fields.push_back(webkit_glue::FormField(ASCIIToUTF16("Card Number"), ASCIIToUTF16("card_number"), string16(), ASCIIToUTF16("text"), 0, false)); form.fields.push_back(webkit_glue::FormField(ASCIIToUTF16("Expiration Date"), ASCIIToUTF16("expiration_month"), string16(), ASCIIToUTF16("text"), 0, false)); form.fields.push_back(webkit_glue::FormField(ASCIIToUTF16("Expiration Year"), ASCIIToUTF16("expiration_year"), string16(), ASCIIToUTF16("text"), 0, false)); ScopedVector<FormStructure> forms; forms.push_back(new FormStructure(form)); std::vector<std::string> encoded_signatures; std::string encoded_xml; const char * const kSignature1 = "11337937696949187602"; const char * const kResponse1 = "<\?xml version=\"1.0\" encoding=\"UTF-8\"\?><autofillquery " "clientversion=\"6.1.1715.1442/en (GGLL)\" accepts=\"e\"><form " "signature=\"11337937696949187602\"><field signature=\"412125936\"/>" "<field signature=\"1917667676\"/><field signature=\"2226358947\"/>" "<field signature=\"747221617\"/><field signature=\"4108155786\"/></form>" "</autofillquery>"; ASSERT_TRUE(FormStructure::EncodeQueryRequest(forms, &encoded_signatures, &encoded_xml)); ASSERT_EQ(1U, encoded_signatures.size()); EXPECT_EQ(kSignature1, encoded_signatures[0]); EXPECT_EQ(kResponse1, encoded_xml); // Add the same form, only one will be encoded, so EncodeQueryRequest() should // return the same data. forms.push_back(new FormStructure(form)); ASSERT_TRUE(FormStructure::EncodeQueryRequest(forms, &encoded_signatures, &encoded_xml)); ASSERT_EQ(1U, encoded_signatures.size()); EXPECT_EQ(kSignature1, encoded_signatures[0]); EXPECT_EQ(kResponse1, encoded_xml); // Add 5 address fields - this should be still a valid form. for (size_t i = 0; i < 5; ++i) { form.fields.push_back( webkit_glue::FormField(ASCIIToUTF16("Address"), ASCIIToUTF16("address"), string16(), ASCIIToUTF16("text"), 0, false)); } forms.push_back(new FormStructure(form)); ASSERT_TRUE(FormStructure::EncodeQueryRequest(forms, &encoded_signatures, &encoded_xml)); ASSERT_EQ(2U, encoded_signatures.size()); EXPECT_EQ(kSignature1, encoded_signatures[0]); const char * const kSignature2 = "8308881815906226214"; EXPECT_EQ(kSignature2, encoded_signatures[1]); const char * const kResponse2 = "<\?xml version=\"1.0\" encoding=\"UTF-8\"\?><autofillquery " "clientversion=\"6.1.1715.1442/en (GGLL)\" accepts=\"e\"><form " "signature=\"11337937696949187602\"><field signature=\"412125936\"/>" "<field signature=\"1917667676\"/><field signature=\"2226358947\"/>" "<field signature=\"747221617\"/><field signature=\"4108155786\"/></form>" "<form signature=\"8308881815906226214\"><field signature=\"412125936\"/>" "<field signature=\"1917667676\"/><field signature=\"2226358947\"/>" "<field signature=\"747221617\"/><field signature=\"4108155786\"/><field " "signature=\"509334676\"/><field signature=\"509334676\"/><field " "signature=\"509334676\"/><field signature=\"509334676\"/><field " "signature=\"509334676\"/></form></autofillquery>"; EXPECT_EQ(kResponse2, encoded_xml); // Add 50 address fields - the form is not valid anymore, but previous ones // are. The result should be the same as in previous test. for (size_t i = 0; i < 50; ++i) { form.fields.push_back( webkit_glue::FormField(ASCIIToUTF16("Address"), ASCIIToUTF16("address"), string16(), ASCIIToUTF16("text"), 0, false)); } forms.push_back(new FormStructure(form)); ASSERT_TRUE(FormStructure::EncodeQueryRequest(forms, &encoded_signatures, &encoded_xml)); ASSERT_EQ(2U, encoded_signatures.size()); EXPECT_EQ(kSignature1, encoded_signatures[0]); EXPECT_EQ(kSignature2, encoded_signatures[1]); EXPECT_EQ(kResponse2, encoded_xml); // Check that we fail if there are only bad form(s). ScopedVector<FormStructure> bad_forms; bad_forms.push_back(new FormStructure(form)); EXPECT_FALSE(FormStructure::EncodeQueryRequest(bad_forms, &encoded_signatures, &encoded_xml)); EXPECT_EQ(0U, encoded_signatures.size()); EXPECT_EQ("", encoded_xml); } TEST(FormStructureTest, EncodeUploadRequest) { scoped_ptr<FormStructure> form_structure; std::vector<FieldTypeSet> possible_field_types; FormData form; form.method = ASCIIToUTF16("post"); form_structure.reset(new FormStructure(form)); form_structure->DetermineHeuristicTypes(); form.fields.push_back(webkit_glue::FormField(ASCIIToUTF16("First Name"), ASCIIToUTF16("firstname"), string16(), ASCIIToUTF16("text"), 0, false)); possible_field_types.push_back(FieldTypeSet()); possible_field_types.back().insert(NAME_FIRST); form.fields.push_back(webkit_glue::FormField(ASCIIToUTF16("Last Name"), ASCIIToUTF16("lastname"), string16(), ASCIIToUTF16("text"), 0, false)); possible_field_types.push_back(FieldTypeSet()); possible_field_types.back().insert(NAME_LAST); form.fields.push_back(webkit_glue::FormField(ASCIIToUTF16("EMail"), ASCIIToUTF16("email"), string16(), ASCIIToUTF16("email"), 0, false)); possible_field_types.push_back(FieldTypeSet()); possible_field_types.back().insert(EMAIL_ADDRESS); form.fields.push_back(webkit_glue::FormField(ASCIIToUTF16("Phone"), ASCIIToUTF16("phone"), string16(), ASCIIToUTF16("number"), 0, false)); possible_field_types.push_back(FieldTypeSet()); possible_field_types.back().insert(PHONE_HOME_WHOLE_NUMBER); form.fields.push_back(webkit_glue::FormField(ASCIIToUTF16("Country"), ASCIIToUTF16("country"), string16(), ASCIIToUTF16("select-one"), 0, false)); possible_field_types.push_back(FieldTypeSet()); possible_field_types.back().insert(ADDRESS_HOME_COUNTRY); form.fields.push_back(webkit_glue::FormField(ASCIIToUTF16("Fax"), ASCIIToUTF16("fax"), string16(), ASCIIToUTF16("tel"), 0, false)); possible_field_types.push_back(FieldTypeSet()); possible_field_types.back().insert(PHONE_FAX_WHOLE_NUMBER); form_structure.reset(new FormStructure(form)); ASSERT_EQ(form_structure->field_count(), possible_field_types.size()); for (size_t i = 0; i < form_structure->field_count(); ++i) form_structure->set_possible_types(i, possible_field_types[i]); std::string encoded_xml; EXPECT_TRUE(form_structure->EncodeUploadRequest(false, &encoded_xml)); EXPECT_EQ("<\?xml version=\"1.0\" encoding=\"UTF-8\"\?>" "<autofillupload clientversion=\"6.1.1715.1442/en (GGLL)\" " "formsignature=\"7641728017676399335\" autofillused=\"false\" " "datapresent=\"1442008008\">" "<field signature=\"3763331450\" autofilltype=\"3\"/>" "<field signature=\"3494530716\" autofilltype=\"5\"/>" "<field signature=\"1029417091\" autofilltype=\"9\"/>" "<field signature=\"466116101\" autofilltype=\"14\"/>" "<field signature=\"2799270304\" autofilltype=\"36\"/>" "<field signature=\"1876771436\" autofilltype=\"24\"/>" "</autofillupload>", encoded_xml); EXPECT_TRUE(form_structure->EncodeUploadRequest(true, &encoded_xml)); EXPECT_EQ("<\?xml version=\"1.0\" encoding=\"UTF-8\"\?>" "<autofillupload clientversion=\"6.1.1715.1442/en (GGLL)\" " "formsignature=\"7641728017676399335\" autofillused=\"true\" " "datapresent=\"1442008008\">" "<field signature=\"3763331450\" autofilltype=\"3\"/>" "<field signature=\"3494530716\" autofilltype=\"5\"/>" "<field signature=\"1029417091\" autofilltype=\"9\"/>" "<field signature=\"466116101\" autofilltype=\"14\"/>" "<field signature=\"2799270304\" autofilltype=\"36\"/>" "<field signature=\"1876771436\" autofilltype=\"24\"/>" "</autofillupload>", encoded_xml); // Add 2 address fields - this should be still a valid form. for (size_t i = 0; i < 2; ++i) { form.fields.push_back(webkit_glue::FormField(ASCIIToUTF16("Address"), ASCIIToUTF16("address"), string16(), ASCIIToUTF16("text"), 0, false)); possible_field_types.push_back(FieldTypeSet()); possible_field_types.back().insert(ADDRESS_HOME_LINE1); possible_field_types.back().insert(ADDRESS_HOME_LINE2); possible_field_types.back().insert(ADDRESS_BILLING_LINE1); possible_field_types.back().insert(ADDRESS_BILLING_LINE2); } form_structure.reset(new FormStructure(form)); ASSERT_EQ(form_structure->field_count(), possible_field_types.size()); for (size_t i = 0; i < form_structure->field_count(); ++i) form_structure->set_possible_types(i, possible_field_types[i]); EXPECT_TRUE(form_structure->EncodeUploadRequest(false, &encoded_xml)); EXPECT_EQ("<\?xml version=\"1.0\" encoding=\"UTF-8\"\?>" "<autofillupload clientversion=\"6.1.1715.1442/en (GGLL)\" " "formsignature=\"12226592129574322128\" autofillused=\"false\" " "datapresent=\"144200830e\">" "<field signature=\"3763331450\" autofilltype=\"3\"/>" "<field signature=\"3494530716\" autofilltype=\"5\"/>" "<field signature=\"1029417091\" autofilltype=\"9\"/>" "<field signature=\"466116101\" autofilltype=\"14\"/>" "<field signature=\"2799270304\" autofilltype=\"36\"/>" "<field signature=\"1876771436\" autofilltype=\"24\"/>" "<field signature=\"509334676\" autofilltype=\"30\"/>" "<field signature=\"509334676\" autofilltype=\"31\"/>" "<field signature=\"509334676\" autofilltype=\"37\"/>" "<field signature=\"509334676\" autofilltype=\"38\"/>" "<field signature=\"509334676\" autofilltype=\"30\"/>" "<field signature=\"509334676\" autofilltype=\"31\"/>" "<field signature=\"509334676\" autofilltype=\"37\"/>" "<field signature=\"509334676\" autofilltype=\"38\"/>" "</autofillupload>", encoded_xml); // Add 50 address fields - now the form is invalid, as it has too many fields. for (size_t i = 0; i < 50; ++i) { form.fields.push_back(webkit_glue::FormField(ASCIIToUTF16("Address"), ASCIIToUTF16("address"), string16(), ASCIIToUTF16("text"), 0, false)); possible_field_types.push_back(FieldTypeSet()); possible_field_types.back().insert(ADDRESS_HOME_LINE1); possible_field_types.back().insert(ADDRESS_HOME_LINE2); possible_field_types.back().insert(ADDRESS_BILLING_LINE1); possible_field_types.back().insert(ADDRESS_BILLING_LINE2); } form_structure.reset(new FormStructure(form)); ASSERT_EQ(form_structure->field_count(), possible_field_types.size()); for (size_t i = 0; i < form_structure->field_count(); ++i) form_structure->set_possible_types(i, possible_field_types[i]); EXPECT_FALSE(form_structure->EncodeUploadRequest(false, &encoded_xml)); EXPECT_EQ("", encoded_xml); } TEST(FormStructureTest, CheckDataPresence) { // Checks bits set in the datapresence field: for each type in the form // relevant bit in datapresence has to be set. scoped_ptr<FormStructure> form_structure; std::vector<FieldTypeSet> possible_field_types; FormData form; form.method = ASCIIToUTF16("post"); form.fields.push_back(webkit_glue::FormField(ASCIIToUTF16("First Name"), ASCIIToUTF16("first"), string16(), ASCIIToUTF16("text"), 0, false)); possible_field_types.push_back(FieldTypeSet()); possible_field_types.back().insert(NAME_FIRST); form.fields.push_back(webkit_glue::FormField(ASCIIToUTF16("Last Name"), ASCIIToUTF16("last"), string16(), ASCIIToUTF16("text"), 0, false)); possible_field_types.push_back(FieldTypeSet()); possible_field_types.back().insert(NAME_LAST); form.fields.push_back(webkit_glue::FormField(ASCIIToUTF16("email"), ASCIIToUTF16("email"), string16(), ASCIIToUTF16("text"), 0, false)); possible_field_types.push_back(FieldTypeSet()); possible_field_types.back().insert(EMAIL_ADDRESS); form_structure.reset(new FormStructure(form)); for (size_t i = 0; i < form_structure->field_count(); ++i) form_structure->set_possible_types(i, possible_field_types[i]); std::string encoded_xml; EXPECT_TRUE(form_structure->EncodeUploadRequest(false, &encoded_xml)); EXPECT_EQ("<\?xml version=\"1.0\" encoding=\"UTF-8\"\?><autofillupload " "clientversion=\"6.1.1715.1442/en (GGLL)\" formsignature=\"" "6402244543831589061\" autofillused=\"false\" " "datapresent=\"1440\"><field signature=\"1089846351\" ", encoded_xml.substr(0, 200)); form.fields.push_back(webkit_glue::FormField(ASCIIToUTF16("Address"), ASCIIToUTF16("address"), string16(), ASCIIToUTF16("text"), 0, false)); possible_field_types.push_back(FieldTypeSet()); possible_field_types.back().insert(ADDRESS_HOME_LINE1); form_structure.reset(new FormStructure(form)); for (size_t i = 0; i < form_structure->field_count(); ++i) form_structure->set_possible_types(i, possible_field_types[i]); EXPECT_TRUE(form_structure->EncodeUploadRequest(false, &encoded_xml)); EXPECT_EQ("<\?xml version=\"1.0\" encoding=\"UTF-8\"\?><autofillupload " "clientversion=\"6.1.1715.1442/en (GGLL)\" formsignature=\"" "11817937699000629499\" autofillused=\"false\" " "datapresent=\"14400002\"><field signature=\"1089846", encoded_xml.substr(0, 200)); form.fields.push_back(webkit_glue::FormField(ASCIIToUTF16("F4"), ASCIIToUTF16("f4"), string16(), ASCIIToUTF16("text"), 0, false)); possible_field_types.push_back(FieldTypeSet()); possible_field_types.back().insert(CREDIT_CARD_TYPE); form_structure.reset(new FormStructure(form)); for (size_t i = 0; i < form_structure->field_count(); ++i) form_structure->set_possible_types(i, possible_field_types[i]); EXPECT_TRUE(form_structure->EncodeUploadRequest(false, &encoded_xml)); EXPECT_EQ("<\?xml version=\"1.0\" encoding=\"UTF-8\"\?><autofillupload " "clientversion=\"6.1.1715.1442/en (GGLL)\" formsignature=\"" "15126663683491865216\" autofillused=\"false\" " "datapresent=\"1440000200000020\"><field signature=", encoded_xml.substr(0, 200)); } TEST(FormStructureTest, CheckMultipleTypes) { // Check that multiple types for the field are processed correctly, both in // datapresence and in actual field data. scoped_ptr<FormStructure> form_structure; std::vector<FieldTypeSet> possible_field_types; FormData form; form.method = ASCIIToUTF16("post"); form.fields.push_back(webkit_glue::FormField(ASCIIToUTF16("email"), ASCIIToUTF16("email"), string16(), ASCIIToUTF16("text"), 0, false)); possible_field_types.push_back(FieldTypeSet()); possible_field_types.back().insert(EMAIL_ADDRESS); form.fields.push_back(webkit_glue::FormField(ASCIIToUTF16("First Name"), ASCIIToUTF16("first"), string16(), ASCIIToUTF16("text"), 0, false)); possible_field_types.push_back(FieldTypeSet()); possible_field_types.back().insert(NAME_FIRST); form.fields.push_back(webkit_glue::FormField(ASCIIToUTF16("Last Name"), ASCIIToUTF16("last"), string16(), ASCIIToUTF16("text"), 0, false)); possible_field_types.push_back(FieldTypeSet()); possible_field_types.back().insert(NAME_LAST); form.fields.push_back(webkit_glue::FormField(ASCIIToUTF16("Address"), ASCIIToUTF16("address"), string16(), ASCIIToUTF16("text"), 0, false)); possible_field_types.push_back(FieldTypeSet()); possible_field_types.back().insert(ADDRESS_HOME_LINE1); form_structure.reset(new FormStructure(form)); for (size_t i = 0; i < form_structure->field_count(); ++i) form_structure->set_possible_types(i, possible_field_types[i]); std::string encoded_xml; // Now we matched both fields singularly. EXPECT_TRUE(form_structure->EncodeUploadRequest(false, &encoded_xml)); // datapresent==14400002==00010100010000000000000000000010b set bits are: // #3 == NAME_FIRST // #5 == NAME_LAST // #9 == EMAIL_ADDRESS // #30 == ADDRESS_HOME_LINE1 EXPECT_EQ("<\?xml version=\"1.0\" encoding=\"UTF-8\"\?><autofillupload " "clientversion=\"6.1.1715.1442/en (GGLL)\" formsignature=\"" "18062476096658145866\" autofillused=\"false\" datapresent=" "\"14400002\"><field signature=\"420638584\" autofilltype=" "\"9\"/><field signature=\"1089846351\" autofilltype=\"3\"/><field " "signature=\"2404144663\" autofilltype=\"5\"/><field signature=" "\"509334676\" autofilltype=\"30\"/></autofillupload>", encoded_xml); // Match third field as both first and last. possible_field_types[2].insert(NAME_FIRST); form_structure->set_possible_types(2, possible_field_types[2]); EXPECT_TRUE(form_structure->EncodeUploadRequest(false, &encoded_xml)); // datapresent==14400002==00010100010000000000000000000010b set bits are: // #3 == NAME_FIRST // #5 == NAME_LAST // #9 == EMAIL_ADDRESS // #30 == ADDRESS_HOME_LINE1 EXPECT_EQ("<\?xml version=\"1.0\" encoding=\"UTF-8\"\?><autofillupload " "clientversion=\"6.1.1715.1442/en (GGLL)\" formsignature=\"" "18062476096658145866\" autofillused=\"false\" datapresent=" "\"14400002\"><field signature=\"420638584\" autofilltype=" "\"9\"/><field signature=\"1089846351\" autofilltype=\"3\"/><field " "signature=\"2404144663\" autofilltype=\"3\"/><field " "signature=\"2404144663\" autofilltype=\"5\"/><field signature=" "\"509334676\" autofilltype=\"30\"/></autofillupload>", encoded_xml); possible_field_types[3].insert(ADDRESS_BILLING_LINE1); form_structure->set_possible_types( form_structure->field_count() - 1, possible_field_types[form_structure->field_count() - 1]); EXPECT_TRUE(form_structure->EncodeUploadRequest(false, &encoded_xml)); // datapresent==1440000204==0001010001000000000000000000001000000100b set bits // are: // #3 == NAME_FIRST // #5 == NAME_LAST // #9 == EMAIL_ADDRESS // #30 == ADDRESS_HOME_LINE1 // #37 == ADDRESS_BILLING_LINE1 EXPECT_EQ("<\?xml version=\"1.0\" encoding=\"UTF-8\"\?><autofillupload " "clientversion=\"6.1.1715.1442/en (GGLL)\" formsignature=\"" "18062476096658145866\" autofillused=\"false\" datapresent=" "\"1440000204\"><field signature=\"420638584\" autofilltype=" "\"9\"/><field signature=\"1089846351\" autofilltype=\"3\"/><field " "signature=\"2404144663\" autofilltype=\"3\"/><field " "signature=\"2404144663\" autofilltype=\"5\"/><field signature=" "\"509334676\" autofilltype=\"30\"/><field signature=\"509334676\" " "autofilltype=\"37\"/></autofillupload>", encoded_xml); possible_field_types[3].clear(); possible_field_types[3].insert(ADDRESS_HOME_LINE1); possible_field_types[3].insert(ADDRESS_BILLING_LINE2); form_structure->set_possible_types( form_structure->field_count() - 1, possible_field_types[form_structure->field_count() - 1]); EXPECT_TRUE(form_structure->EncodeUploadRequest(false, &encoded_xml)); // datapresent==1440000202==0001010001000000000000000000001000000010b set bits // are: // #3 == NAME_FIRST // #5 == NAME_LAST // #9 == EMAIL_ADDRESS // #30 == ADDRESS_HOME_LINE1 // #38 == ADDRESS_BILLING_LINE2 EXPECT_EQ("<\?xml version=\"1.0\" encoding=\"UTF-8\"\?><autofillupload " "clientversion=\"6.1.1715.1442/en (GGLL)\" formsignature=\"" "18062476096658145866\" autofillused=\"false\" datapresent=" "\"1440000202\"><field signature=\"420638584\" autofilltype=" "\"9\"/><field signature=\"1089846351\" autofilltype=\"3\"/><field " "signature=\"2404144663\" autofilltype=\"3\"/><field " "signature=\"2404144663\" autofilltype=\"5\"/><field signature=" "\"509334676\" autofilltype=\"30\"/><field signature=\"509334676\" " "autofilltype=\"38\"/></autofillupload>", encoded_xml); } TEST(FormStructureTest, CheckFormSignature) { // Check that form signature is created correctly. scoped_ptr<FormStructure> form_structure; FormData form; form.method = ASCIIToUTF16("post"); form.fields.push_back(webkit_glue::FormField(ASCIIToUTF16("email"), ASCIIToUTF16("email"), string16(), ASCIIToUTF16("text"), 0, false)); form.fields.push_back(webkit_glue::FormField(ASCIIToUTF16("First Name"), ASCIIToUTF16("first"), string16(), ASCIIToUTF16("text"), 0, false)); form_structure.reset(new FormStructure(form)); EXPECT_EQ(FormStructureTest::Hash64Bit( std::string("://&&email&first")), form_structure->FormSignature()); form.origin = GURL(std::string("http://www.facebook.com")); form_structure.reset(new FormStructure(form)); EXPECT_EQ(FormStructureTest::Hash64Bit( std::string("http://www.facebook.com&&email&first")), form_structure->FormSignature()); form.action = GURL(std::string("https://login.facebook.com/path")); form_structure.reset(new FormStructure(form)); EXPECT_EQ(FormStructureTest::Hash64Bit( std::string("https://login.facebook.com&&email&first")), form_structure->FormSignature()); form.name = ASCIIToUTF16("login_form"); form_structure.reset(new FormStructure(form)); EXPECT_EQ(FormStructureTest::Hash64Bit( std::string("https://login.facebook.com&login_form&email&first")), form_structure->FormSignature()); } } // namespace