// Copyright (c) 2010 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/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/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 { 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::const_iterator iter = form.fields.begin(); iter != form.fields.end(); ++iter) { os << *iter << " "; } return os; } TEST(FormStructureTest, FieldCount) { FormData form; form.method = ASCIIToUTF16("post"); form.fields.push_back(webkit_glue::FormField(ASCIIToUTF16("username"), ASCIIToUTF16("username"), string16(), ASCIIToUTF16("text"), 0)); form.fields.push_back(webkit_glue::FormField(ASCIIToUTF16("password"), ASCIIToUTF16("password"), string16(), ASCIIToUTF16("password"), 0)); form.fields.push_back(webkit_glue::FormField(string16(), ASCIIToUTF16("Submit"), string16(), ASCIIToUTF16("submit"), 0)); 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)); form.fields.push_back(webkit_glue::FormField(ASCIIToUTF16("password"), ASCIIToUTF16("password"), string16(), ASCIIToUTF16("password"), 0)); form.fields.push_back(webkit_glue::FormField(ASCIIToUTF16("state"), ASCIIToUTF16("state"), string16(), ASCIIToUTF16("select-one"), 0)); form.fields.push_back(webkit_glue::FormField(string16(), ASCIIToUTF16("Submit"), string16(), ASCIIToUTF16("submit"), 0)); FormStructure form_structure(form); // Only text and select fields that are heuristically matched are counted. EXPECT_EQ(1U, form_structure.autofill_count()); } TEST(FormStructureTest, ConvertToFormData) { FormData form; form.method = ASCIIToUTF16("post"); form.user_submitted = true; form.fields.push_back(webkit_glue::FormField(ASCIIToUTF16("username"), ASCIIToUTF16("username"), string16(), ASCIIToUTF16("text"), 0)); form.fields.push_back(webkit_glue::FormField(ASCIIToUTF16("password"), ASCIIToUTF16("password"), string16(), ASCIIToUTF16("password"), 0)); form.fields.push_back(webkit_glue::FormField(ASCIIToUTF16("state"), ASCIIToUTF16("state"), string16(), ASCIIToUTF16("select"), 0)); form.fields.push_back(webkit_glue::FormField(string16(), ASCIIToUTF16("Submit"), string16(), ASCIIToUTF16("submit"), 0)); FormStructure form_structure(form); FormData converted = form_structure.ConvertToFormData(); EXPECT_EQ(form, converted); } TEST(FormStructureTest, HasAutoFillableValues) { scoped_ptr form_structure; FormData form; form.method = ASCIIToUTF16("post"); // Non text/select fields are not used when saving auto fill data. form.fields.push_back(webkit_glue::FormField(string16(), ASCIIToUTF16("Submit1"), string16(), ASCIIToUTF16("submit"), 0)); form.fields.push_back(webkit_glue::FormField(string16(), ASCIIToUTF16("Submit2"), ASCIIToUTF16("dummy value"), ASCIIToUTF16("submit"), 0)); form_structure.reset(new FormStructure(form)); EXPECT_FALSE(form_structure->HasAutoFillableValues()); // Empty text/select fields are also not used when saving auto fill data. form.fields.push_back(webkit_glue::FormField(ASCIIToUTF16("Email"), ASCIIToUTF16("email"), string16(), ASCIIToUTF16("text"), 0)); form.fields.push_back(webkit_glue::FormField(ASCIIToUTF16("state"), ASCIIToUTF16("state"), string16(), ASCIIToUTF16("select-one"), 0)); form_structure.reset(new FormStructure(form)); EXPECT_FALSE(form_structure->HasAutoFillableValues()); // Non-empty fields can be saved in auto fill profile. form.fields.push_back(webkit_glue::FormField(ASCIIToUTF16("First Name"), ASCIIToUTF16("firstname"), ASCIIToUTF16("John"), ASCIIToUTF16("text"), 0)); form.fields.push_back(webkit_glue::FormField(ASCIIToUTF16("Last Name"), ASCIIToUTF16("lastname"), ASCIIToUTF16("Dear"), ASCIIToUTF16("text"), 0)); form_structure.reset(new FormStructure(form)); EXPECT_TRUE(form_structure->HasAutoFillableValues()); // The fields must be recognized heuristically by AutoFill in addition to // being text or select and non-empty. form.fields.clear(); form.fields.push_back(webkit_glue::FormField(string16(), ASCIIToUTF16("Field1"), string16(), ASCIIToUTF16("text"), 0)); form.fields.push_back(webkit_glue::FormField(string16(), ASCIIToUTF16("Field2"), ASCIIToUTF16("dummy value"), ASCIIToUTF16("text"), 0)); form_structure.reset(new FormStructure(form)); EXPECT_FALSE(form_structure->HasAutoFillableValues()); // Add a field that we match heuristically, verify that this form has // auto-fillable values. form.fields.push_back(webkit_glue::FormField(ASCIIToUTF16("Full Name"), ASCIIToUTF16("fullname"), ASCIIToUTF16("John Dear"), ASCIIToUTF16("text"), 0)); form_structure.reset(new FormStructure(form)); EXPECT_TRUE(form_structure->HasAutoFillableValues()); } TEST(FormStructureTest, IsAutoFillable) { scoped_ptr 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)); form.fields.push_back(webkit_glue::FormField(ASCIIToUTF16("password"), ASCIIToUTF16("password"), string16(), ASCIIToUTF16("password"), 0)); form.fields.push_back(webkit_glue::FormField(string16(), ASCIIToUTF16("Submit"), string16(), ASCIIToUTF16("submit"), 0)); form_structure.reset(new FormStructure(form)); EXPECT_FALSE(form_structure->IsAutoFillable()); // 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)); form.fields.push_back(webkit_glue::FormField(ASCIIToUTF16("Last Name"), ASCIIToUTF16("lastname"), string16(), ASCIIToUTF16("text"), 0)); form_structure.reset(new FormStructure(form)); EXPECT_FALSE(form_structure->IsAutoFillable()); // We now have three auto-fillable fields. form.fields.push_back(webkit_glue::FormField(ASCIIToUTF16("Email"), ASCIIToUTF16("email"), string16(), ASCIIToUTF16("text"), 0)); form_structure.reset(new FormStructure(form)); EXPECT_TRUE(form_structure->IsAutoFillable()); // The method must be 'post'. form.method = ASCIIToUTF16("get"); form_structure.reset(new FormStructure(form)); EXPECT_FALSE(form_structure->IsAutoFillable()); // 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)); EXPECT_FALSE(form_structure->IsAutoFillable()); // But search can be in the URL. form.action = GURL("http://search.com/?q=hello"); form_structure.reset(new FormStructure(form)); EXPECT_TRUE(form_structure->IsAutoFillable()); } TEST(FormStructureTest, HeuristicsContactInfo) { scoped_ptr form_structure; FormData form; form.method = ASCIIToUTF16("post"); form.fields.push_back(webkit_glue::FormField(ASCIIToUTF16("First Name"), ASCIIToUTF16("firstname"), string16(), ASCIIToUTF16("text"), 0)); form.fields.push_back(webkit_glue::FormField(ASCIIToUTF16("Last Name"), ASCIIToUTF16("lastname"), string16(), ASCIIToUTF16("text"), 0)); form.fields.push_back(webkit_glue::FormField(ASCIIToUTF16("EMail"), ASCIIToUTF16("email"), string16(), ASCIIToUTF16("text"), 0)); form.fields.push_back(webkit_glue::FormField(ASCIIToUTF16("Phone"), ASCIIToUTF16("phone"), string16(), ASCIIToUTF16("text"), 0)); form.fields.push_back(webkit_glue::FormField(ASCIIToUTF16("Fax"), ASCIIToUTF16("fax"), string16(), ASCIIToUTF16("text"), 0)); form.fields.push_back(webkit_glue::FormField(ASCIIToUTF16("Address"), ASCIIToUTF16("address"), string16(), ASCIIToUTF16("text"), 0)); form.fields.push_back(webkit_glue::FormField(ASCIIToUTF16("City"), ASCIIToUTF16("city"), string16(), ASCIIToUTF16("text"), 0)); form.fields.push_back(webkit_glue::FormField(ASCIIToUTF16("Zip code"), ASCIIToUTF16("zipcode"), string16(), ASCIIToUTF16("text"), 0)); form.fields.push_back(webkit_glue::FormField(string16(), ASCIIToUTF16("Submit"), string16(), ASCIIToUTF16("submit"), 0)); form_structure.reset(new FormStructure(form)); EXPECT_TRUE(form_structure->IsAutoFillable()); // 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 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)); form.fields.push_back( webkit_glue::FormField(ASCIIToUTF16("Your Last Name:"), ASCIIToUTF16("bill.last"), string16(), ASCIIToUTF16("text"), 0)); form.fields.push_back( webkit_glue::FormField(ASCIIToUTF16("Street Address Line 1:"), ASCIIToUTF16("bill.street1"), string16(), ASCIIToUTF16("text"), 0)); form.fields.push_back( webkit_glue::FormField(ASCIIToUTF16("Street Address Line 2:"), ASCIIToUTF16("bill.street2"), string16(), ASCIIToUTF16("text"), 0)); form.fields.push_back( webkit_glue::FormField(ASCIIToUTF16("City:"), ASCIIToUTF16("bill.city"), string16(), ASCIIToUTF16("text"), 0)); form.fields.push_back( webkit_glue::FormField(ASCIIToUTF16("State (U.S.):"), ASCIIToUTF16("bill.state"), string16(), ASCIIToUTF16("text"), 0)); form.fields.push_back( webkit_glue::FormField(ASCIIToUTF16("Zip/Postal Code:"), ASCIIToUTF16("BillTo.PostalCode"), string16(), ASCIIToUTF16("text"), 0)); form.fields.push_back( webkit_glue::FormField(ASCIIToUTF16("Country:"), ASCIIToUTF16("bill.country"), string16(), ASCIIToUTF16("text"), 0)); form.fields.push_back( webkit_glue::FormField(ASCIIToUTF16("Phone Number:"), ASCIIToUTF16("BillTo.Phone"), string16(), ASCIIToUTF16("text"), 0)); form.fields.push_back( webkit_glue::FormField(string16(), ASCIIToUTF16("Submit"), string16(), ASCIIToUTF16("submit"), 0)); form_structure.reset(new FormStructure(form)); EXPECT_TRUE(form_structure->IsAutoFillable()); 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 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)); form.fields.push_back( webkit_glue::FormField(ASCIIToUTF16("Full name"), ASCIIToUTF16("name"), string16(), ASCIIToUTF16("text"), 0)); form.fields.push_back( webkit_glue::FormField(ASCIIToUTF16("Company"), ASCIIToUTF16("company"), string16(), ASCIIToUTF16("text"), 0)); form.fields.push_back( webkit_glue::FormField(ASCIIToUTF16("Address"), ASCIIToUTF16("address"), string16(), ASCIIToUTF16("text"), 0)); form.fields.push_back( webkit_glue::FormField(ASCIIToUTF16("City"), ASCIIToUTF16("city"), string16(), ASCIIToUTF16("text"), 0)); // TODO(jhawkins): Add state select control. form.fields.push_back( webkit_glue::FormField(ASCIIToUTF16("Zip Code"), ASCIIToUTF16("Home.PostalCode"), string16(), ASCIIToUTF16("text"), 0)); // TODO(jhawkins): Phone number. form.fields.push_back( webkit_glue::FormField(string16(), ASCIIToUTF16("Submit"), ASCIIToUTF16("continue"), ASCIIToUTF16("submit"), 0)); form_structure.reset(new FormStructure(form)); EXPECT_TRUE(form_structure->IsAutoFillable()); 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 form_structure; FormData form; form.method = ASCIIToUTF16("post"); form.fields.push_back(webkit_glue::FormField(ASCIIToUTF16("First Name"), string16(), string16(), ASCIIToUTF16("text"), 0)); form.fields.push_back(webkit_glue::FormField(ASCIIToUTF16("Last Name"), string16(), string16(), ASCIIToUTF16("text"), 0)); form.fields.push_back(webkit_glue::FormField(ASCIIToUTF16("EMail"), string16(), string16(), ASCIIToUTF16("text"), 0)); form.fields.push_back(webkit_glue::FormField(ASCIIToUTF16("Phone"), string16(), string16(), ASCIIToUTF16("text"), 0)); form.fields.push_back(webkit_glue::FormField(ASCIIToUTF16("Fax"), string16(), string16(), ASCIIToUTF16("text"), 0)); form.fields.push_back(webkit_glue::FormField(ASCIIToUTF16("Address"), string16(), string16(), ASCIIToUTF16("text"), 0)); form.fields.push_back(webkit_glue::FormField(ASCIIToUTF16("Address"), string16(), string16(), ASCIIToUTF16("text"), 0)); form.fields.push_back(webkit_glue::FormField(ASCIIToUTF16("Zip code"), string16(), string16(), ASCIIToUTF16("text"), 0)); form.fields.push_back(webkit_glue::FormField(string16(), ASCIIToUTF16("Submit"), string16(), ASCIIToUTF16("submit"), 0)); form_structure.reset(new FormStructure(form)); EXPECT_TRUE(form_structure->IsAutoFillable()); 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 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)); form.fields.push_back(webkit_glue::FormField(ASCIIToUTF16("Card Number"), ASCIIToUTF16("card_number"), string16(), ASCIIToUTF16("text"), 0)); form.fields.push_back(webkit_glue::FormField(ASCIIToUTF16("Exp Month"), ASCIIToUTF16("ccmonth"), string16(), ASCIIToUTF16("text"), 0)); form.fields.push_back(webkit_glue::FormField(ASCIIToUTF16("Exp Year"), ASCIIToUTF16("ccyear"), string16(), ASCIIToUTF16("text"), 0)); form.fields.push_back(webkit_glue::FormField(ASCIIToUTF16("Verification"), ASCIIToUTF16("verification"), string16(), ASCIIToUTF16("text"), 0)); form.fields.push_back(webkit_glue::FormField(string16(), ASCIIToUTF16("Submit"), string16(), ASCIIToUTF16("submit"), 0)); form_structure.reset(new FormStructure(form)); EXPECT_TRUE(form_structure->IsAutoFillable()); 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 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)); // 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)); form.fields.push_back(webkit_glue::FormField(ASCIIToUTF16("Card Number"), ASCIIToUTF16("card_number"), string16(), ASCIIToUTF16("text"), 0)); form.fields.push_back(webkit_glue::FormField(ASCIIToUTF16("Exp Month"), ASCIIToUTF16("ccmonth"), string16(), ASCIIToUTF16("text"), 0)); form.fields.push_back(webkit_glue::FormField(ASCIIToUTF16("Exp Year"), ASCIIToUTF16("ccyear"), string16(), ASCIIToUTF16("text"), 0)); form.fields.push_back(webkit_glue::FormField(ASCIIToUTF16("Verification"), ASCIIToUTF16("verification"), string16(), ASCIIToUTF16("text"), 0)); form.fields.push_back(webkit_glue::FormField(string16(), ASCIIToUTF16("Submit"), string16(), ASCIIToUTF16("submit"), 0)); form_structure.reset(new FormStructure(form)); EXPECT_TRUE(form_structure->IsAutoFillable()); 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 form_structure; FormData form; form.method = ASCIIToUTF16("post"); form.fields.push_back( webkit_glue::FormField(ASCIIToUTF16("Address Line1"), ASCIIToUTF16("Address"), string16(), ASCIIToUTF16("text"), 0)); form.fields.push_back( webkit_glue::FormField(ASCIIToUTF16("Address Line2"), ASCIIToUTF16("Address"), string16(), ASCIIToUTF16("text"), 0)); form.fields.push_back( webkit_glue::FormField(ASCIIToUTF16("Address Line3"), ASCIIToUTF16("Address"), string16(), ASCIIToUTF16("text"), 0)); form.fields.push_back( webkit_glue::FormField(ASCIIToUTF16("City"), ASCIIToUTF16("city"), string16(), ASCIIToUTF16("text"), 0)); form_structure.reset(new FormStructure(form)); EXPECT_TRUE(form_structure->IsAutoFillable()); 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()); } TEST(FormStructureTest, HeuristicsStateWithProvince) { scoped_ptr form_structure; FormData form; form.method = ASCIIToUTF16("post"); form.fields.push_back( webkit_glue::FormField(ASCIIToUTF16("Address Line1"), ASCIIToUTF16("Address"), string16(), ASCIIToUTF16("text"), 0)); form.fields.push_back( webkit_glue::FormField(ASCIIToUTF16("Address Line2"), ASCIIToUTF16("Address"), string16(), ASCIIToUTF16("text"), 0)); form.fields.push_back( webkit_glue::FormField(ASCIIToUTF16("State/Province/Region"), ASCIIToUTF16("State"), string16(), ASCIIToUTF16("text"), 0)); form_structure.reset(new FormStructure(form)); EXPECT_TRUE(form_structure->IsAutoFillable()); 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 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)); form.fields.push_back( webkit_glue::FormField(ASCIIToUTF16("Last Name*:"), ASCIIToUTF16("editBillingAddress$lastNameBox"), string16(), ASCIIToUTF16("text"), 0)); form.fields.push_back( webkit_glue::FormField(ASCIIToUTF16("Company Name:"), ASCIIToUTF16("editBillingAddress$companyBox"), string16(), ASCIIToUTF16("text"), 0)); form.fields.push_back( webkit_glue::FormField(ASCIIToUTF16("Address*:"), ASCIIToUTF16("editBillingAddress$addressLine1Box"), string16(), ASCIIToUTF16("text"), 0)); form.fields.push_back( webkit_glue::FormField(ASCIIToUTF16("Apt/Suite :"), ASCIIToUTF16("editBillingAddress$addressLine2Box"), string16(), ASCIIToUTF16("text"), 0)); form.fields.push_back( webkit_glue::FormField(ASCIIToUTF16("City*:"), ASCIIToUTF16("editBillingAddress$cityBox"), string16(), ASCIIToUTF16("text"), 0)); form.fields.push_back( webkit_glue::FormField(ASCIIToUTF16("State/Province*:"), ASCIIToUTF16("editBillingAddress$stateDropDown"), string16(), ASCIIToUTF16("text"), 0)); form.fields.push_back( webkit_glue::FormField(ASCIIToUTF16("Country*:"), ASCIIToUTF16("editBillingAddress$countryDropDown"), string16(), ASCIIToUTF16("text"), 0)); form.fields.push_back( webkit_glue::FormField(ASCIIToUTF16("Postal Code*:"), ASCIIToUTF16("editBillingAddress$zipCodeBox"), string16(), ASCIIToUTF16("text"), 0)); form.fields.push_back( webkit_glue::FormField(ASCIIToUTF16("Phone*:"), ASCIIToUTF16("editBillingAddress$phoneBox"), string16(), ASCIIToUTF16("text"), 0)); form.fields.push_back( webkit_glue::FormField(ASCIIToUTF16("Email Address*:"), ASCIIToUTF16("email$emailBox"), string16(), ASCIIToUTF16("text"), 0)); form_structure.reset(new FormStructure(form)); EXPECT_TRUE(form_structure->IsAutoFillable()); ASSERT_EQ(11U, form_structure->field_count()); ASSERT_EQ(10U, 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()); // Note: We'd expect this to match ADDRESS_BILLING_LINE2, but due to toolbar // heuristics for other pages we skip fields with label including "suite". EXPECT_EQ(UNKNOWN_TYPE, 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 form_structure; FormData form; form.method = ASCIIToUTF16("post"); form.fields.push_back( webkit_glue::FormField(ASCIIToUTF16("Phone:"), ASCIIToUTF16("dayphone1"), string16(), ASCIIToUTF16("text"), 0)); form.fields.push_back( webkit_glue::FormField(ASCIIToUTF16("-"), ASCIIToUTF16("dayphone2"), string16(), ASCIIToUTF16("text"), 0)); form.fields.push_back( webkit_glue::FormField(ASCIIToUTF16("-"), ASCIIToUTF16("dayphone3"), string16(), ASCIIToUTF16("text"), 0)); form.fields.push_back( webkit_glue::FormField(ASCIIToUTF16("ext.:"), ASCIIToUTF16("dayphone4"), string16(), ASCIIToUTF16("text"), 0)); form_structure.reset(new FormStructure(form)); EXPECT_TRUE(form_structure->IsAutoFillable()); 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()); } } // namespace