diff options
author | isherman@chromium.org <isherman@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2013-10-23 07:08:26 +0000 |
---|---|---|
committer | isherman@chromium.org <isherman@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2013-10-23 07:08:26 +0000 |
commit | e001d11bebcb4739282c4bf365fe53a5fb847424 (patch) | |
tree | b660f5fc5c79447c0fadbb145ef07147e79965b3 /components | |
parent | d6d06a3517f9549488826a9f5faac5cdb678e992 (diff) | |
download | chromium_src-e001d11bebcb4739282c4bf365fe53a5fb847424.zip chromium_src-e001d11bebcb4739282c4bf365fe53a5fb847424.tar.gz chromium_src-e001d11bebcb4739282c4bf365fe53a5fb847424.tar.bz2 |
[Autofill] Refactor FillFormField to be shared between local Autofill and Wallet.
BUG=263705
TEST=unit_tests
R=estade@chromium.org
Review URL: https://codereview.chromium.org/26320010
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@230359 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'components')
17 files changed, 655 insertions, 662 deletions
diff --git a/components/autofill/core/browser/autofill_data_model.cc b/components/autofill/core/browser/autofill_data_model.cc index 2d1edcf..48b818d 100644 --- a/components/autofill/core/browser/autofill_data_model.cc +++ b/components/autofill/core/browser/autofill_data_model.cc @@ -4,119 +4,10 @@ #include "components/autofill/core/browser/autofill_data_model.h" -#include "base/basictypes.h" -#include "base/logging.h" -#include "base/strings/string_number_conversions.h" -#include "base/strings/string_util.h" -#include "base/strings/utf_string_conversions.h" -#include "components/autofill/core/browser/autofill_country.h" -#include "components/autofill/core/browser/autofill_field.h" #include "components/autofill/core/browser/autofill_type.h" -#include "components/autofill/core/browser/state_names.h" -#include "components/autofill/core/browser/validation.h" -#include "components/autofill/core/common/form_field_data.h" -#include "grit/component_strings.h" -#include "ui/base/l10n/l10n_util.h" #include "url/gurl.h" namespace autofill { -namespace { - -const char* const kMonthsAbbreviated[] = { - NULL, // Padding so index 1 = month 1 = January. - "Jan", "Feb", "Mar", "Apr", "May", "Jun", - "Jul", "Aug", "Sep", "Oct", "Nov", "Dec", -}; - -const char* const kMonthsFull[] = { - NULL, // Padding so index 1 = month 1 = January. - "January", "February", "March", "April", "May", "June", - "July", "August", "September", "October", "November", "December", -}; - -const char* const kMonthsNumeric[] = { - NULL, // Padding so index 1 = month 1 = January. - "1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12", -}; - -// Returns true if the value was successfully set, meaning |value| was found in -// the list of select options in |field|. -bool SetSelectControlValue(const base::string16& value, - FormFieldData* field) { - base::string16 value_lowercase = StringToLowerASCII(value); - - DCHECK_EQ(field->option_values.size(), field->option_contents.size()); - for (size_t i = 0; i < field->option_values.size(); ++i) { - if (value_lowercase == StringToLowerASCII(field->option_values[i]) || - value_lowercase == StringToLowerASCII(field->option_contents[i])) { - field->value = field->option_values[i]; - return true; - } - } - - return false; -} - -bool FillStateSelectControl(const base::string16& value, - FormFieldData* field) { - base::string16 full, abbreviation; - state_names::GetNameAndAbbreviation(value, &full, &abbreviation); - - // Try the abbreviation first. - if (!abbreviation.empty() && SetSelectControlValue(abbreviation, field)) - return true; - - return !full.empty() && SetSelectControlValue(full, field); -} - -bool FillExpirationMonthSelectControl(const base::string16& value, - FormFieldData* field) { - int index = 0; - if (!base::StringToInt(value, &index) || - index <= 0 || - static_cast<size_t>(index) >= arraysize(kMonthsFull)) - return false; - - bool filled = - SetSelectControlValue(ASCIIToUTF16(kMonthsAbbreviated[index]), field) || - SetSelectControlValue(ASCIIToUTF16(kMonthsFull[index]), field) || - SetSelectControlValue(ASCIIToUTF16(kMonthsNumeric[index]), field); - return filled; -} - -// Try to fill a credit card type |value| (Visa, MasterCard, etc.) into the -// given |field|. -bool FillCreditCardTypeSelectControl(const base::string16& value, - FormFieldData* field) { - // Try stripping off spaces. - base::string16 value_stripped; - RemoveChars(StringToLowerASCII(value), kWhitespaceUTF16, &value_stripped); - - for (size_t i = 0; i < field->option_values.size(); ++i) { - base::string16 option_value_lowercase; - RemoveChars(StringToLowerASCII(field->option_values[i]), kWhitespaceUTF16, - &option_value_lowercase); - base::string16 option_contents_lowercase; - RemoveChars(StringToLowerASCII(field->option_contents[i]), kWhitespaceUTF16, - &option_contents_lowercase); - - // Perform a case-insensitive comparison; but fill the form with the - // original text, not the lowercased version. - if (value_stripped == option_value_lowercase || - value_stripped == option_contents_lowercase) { - field->value = field->option_values[i]; - return true; - } - } - - // For American Express, also try filling as "AmEx". - if (value == l10n_util::GetStringUTF16(IDS_AUTOFILL_CC_AMEX)) - return FillCreditCardTypeSelectControl(ASCIIToUTF16("AmEx"), field); - - return false; -} - -} // namespace AutofillDataModel::AutofillDataModel(const std::string& guid, const std::string& origin) @@ -124,62 +15,11 @@ AutofillDataModel::AutofillDataModel(const std::string& guid, origin_(origin) {} AutofillDataModel::~AutofillDataModel() {} -void AutofillDataModel::FillSelectControl(const AutofillType& type, - const std::string& app_locale, - FormFieldData* field) const { - DCHECK(field); - DCHECK_EQ("select-one", field->form_control_type); - DCHECK_EQ(field->option_values.size(), field->option_contents.size()); - - base::string16 field_text = GetInfo(type, app_locale); - base::string16 field_text_lower = StringToLowerASCII(field_text); - if (field_text.empty()) - return; - - base::string16 value; - for (size_t i = 0; i < field->option_values.size(); ++i) { - if (field_text == field->option_values[i] || - field_text == field->option_contents[i]) { - // An exact match, use it. - value = field->option_values[i]; - break; - } - - if (field_text_lower == StringToLowerASCII(field->option_values[i]) || - field_text_lower == StringToLowerASCII(field->option_contents[i])) { - // A match, but not in the same case. Save it in case an exact match is - // not found. - value = field->option_values[i]; - } - } - - if (!value.empty()) { - field->value = value; - return; - } - - ServerFieldType storable_type = type.GetStorableType(); - if (storable_type == ADDRESS_HOME_STATE) { - FillStateSelectControl(field_text, field); - } else if (storable_type == ADDRESS_HOME_COUNTRY) { - FillCountrySelectControl(app_locale, field); - } else if (storable_type == CREDIT_CARD_EXP_MONTH) { - FillExpirationMonthSelectControl(field_text, field); - } else if (storable_type == CREDIT_CARD_EXP_4_DIGIT_YEAR) { - // Attempt to fill the year as a 2-digit year. This compensates for the - // fact that our heuristics do not always correctly detect when a website - // requests a 2-digit rather than a 4-digit year. - FillSelectControl(AutofillType(CREDIT_CARD_EXP_2_DIGIT_YEAR), app_locale, - field); - } else if (storable_type == CREDIT_CARD_TYPE) { - FillCreditCardTypeSelectControl(field_text, field); - } -} - -bool AutofillDataModel::FillCountrySelectControl( - const std::string& app_locale, - FormFieldData* field_data) const { - return false; +base::string16 AutofillDataModel::GetInfoForVariant( + const AutofillType& type, + size_t variant, + const std::string& app_locale) const { + return GetInfo(type, app_locale); } bool AutofillDataModel::IsVerified() const { diff --git a/components/autofill/core/browser/autofill_data_model.h b/components/autofill/core/browser/autofill_data_model.h index 0f2cd33..04499f3 100644 --- a/components/autofill/core/browser/autofill_data_model.h +++ b/components/autofill/core/browser/autofill_data_model.h @@ -7,13 +7,12 @@ #include <string> -#include "components/autofill/core/browser/field_types.h" +#include "base/strings/string16.h" #include "components/autofill/core/browser/form_group.h" namespace autofill { -class AutofillField; -struct FormFieldData; +class AutofillType; // This class is an interface for the primary data models that back Autofill. // The information in objects of this class is managed by the @@ -23,18 +22,13 @@ class AutofillDataModel : public FormGroup { AutofillDataModel(const std::string& guid, const std::string& origin); virtual ~AutofillDataModel(); - // Set |field_data|'s value based on |field| and contents of |this| (using - // data variant |variant|). - virtual void FillFormField(const AutofillField& field, - size_t variant, - const std::string& app_locale, - FormFieldData* field_data) const = 0; - - // Fills in select control with data matching |type| from |this|. - // Public for testing purposes. - void FillSelectControl(const AutofillType& type, - const std::string& app_locale, - FormFieldData* field_data) const; + // Returns the string that should be auto-filled into a text field given the + // |type| of that field, localized to the given |app_locale| if appropriate. + // If the data model supports multiple values for the given |type|, returns + // the |variant|th value for the |type|. + virtual base::string16 GetInfoForVariant(const AutofillType& type, + size_t variant, + const std::string& app_locale) const; // Returns true if the data in this model was entered directly by the user, // rather than automatically aggregated. @@ -46,12 +40,6 @@ class AutofillDataModel : public FormGroup { std::string origin() const { return origin_; } void set_origin(const std::string& origin) { origin_ = origin; } - protected: - // Fills in a select control for a country from data in |this|. Returns true - // for success. - virtual bool FillCountrySelectControl(const std::string& app_locale, - FormFieldData* field_data) const; - private: // A globally unique ID for this object. std::string guid_; diff --git a/components/autofill/core/browser/autofill_data_model_unittest.cc b/components/autofill/core/browser/autofill_data_model_unittest.cc index 8004df4..8540ecf 100644 --- a/components/autofill/core/browser/autofill_data_model_unittest.cc +++ b/components/autofill/core/browser/autofill_data_model_unittest.cc @@ -26,10 +26,6 @@ class TestAutofillDataModel : public AutofillDataModel { const base::string16& value) OVERRIDE {} virtual void GetSupportedTypes( ServerFieldTypeSet* supported_types) const OVERRIDE {} - virtual void FillFormField(const AutofillField& field, - size_t variant, - const std::string& app_locale, - FormFieldData* field_data) const OVERRIDE {} DISALLOW_COPY_AND_ASSIGN(TestAutofillDataModel); }; diff --git a/components/autofill/core/browser/autofill_field.cc b/components/autofill/core/browser/autofill_field.cc index 4bcb118..56f7204 100644 --- a/components/autofill/core/browser/autofill_field.cc +++ b/components/autofill/core/browser/autofill_field.cc @@ -7,12 +7,278 @@ #include "base/logging.h" #include "base/sha1.h" #include "base/strings/string_number_conversions.h" +#include "base/strings/string_split.h" +#include "base/strings/string_util.h" #include "base/strings/utf_string_conversions.h" +#include "components/autofill/core/browser/autofill_country.h" #include "components/autofill/core/browser/autofill_type.h" +#include "components/autofill/core/browser/phone_number.h" +#include "components/autofill/core/browser/state_names.h" +#include "grit/component_strings.h" +#include "ui/base/l10n/l10n_util.h" +using base::StringToInt; + +namespace autofill { namespace { -static std::string Hash32Bit(const std::string& str) { +const char* const kMonthsAbbreviated[] = { + NULL, // Padding so index 1 = month 1 = January. + "Jan", "Feb", "Mar", "Apr", "May", "Jun", + "Jul", "Aug", "Sep", "Oct", "Nov", "Dec", +}; + +const char* const kMonthsFull[] = { + NULL, // Padding so index 1 = month 1 = January. + "January", "February", "March", "April", "May", "June", + "July", "August", "September", "October", "November", "December", +}; + +// Returns true if the value was successfully set, meaning |value| was found in +// the list of select options in |field|. +bool SetSelectControlValue(const base::string16& value, + FormFieldData* field) { + base::string16 value_lowercase = StringToLowerASCII(value); + + DCHECK_EQ(field->option_values.size(), field->option_contents.size()); + base::string16 best_match; + for (size_t i = 0; i < field->option_values.size(); ++i) { + if (value == field->option_values[i] || + value == field->option_contents[i]) { + // An exact match, use it. + best_match = field->option_values[i]; + break; + } + + if (value_lowercase == StringToLowerASCII(field->option_values[i]) || + value_lowercase == StringToLowerASCII(field->option_contents[i])) { + // A match, but not in the same case. Save it in case an exact match is + // not found. + best_match = field->option_values[i]; + } + } + + if (best_match.empty()) + return false; + + field->value = best_match; + return true; +} + + +// Try to fill a numeric |value| into the given |field|. +bool FillNumericSelectControl(int value, + FormFieldData* field) { + DCHECK_EQ(field->option_values.size(), field->option_contents.size()); + for (size_t i = 0; i < field->option_values.size(); ++i) { + int option; + if ((StringToInt(field->option_values[i], &option) && option == value) || + (StringToInt(field->option_contents[i], &option) && option == value)) { + field->value = field->option_values[i]; + return true; + } + } + + return false; +} + +bool FillStateSelectControl(const base::string16& value, + FormFieldData* field) { + base::string16 full, abbreviation; + state_names::GetNameAndAbbreviation(value, &full, &abbreviation); + + // Try the abbreviation first. + if (!abbreviation.empty() && SetSelectControlValue(abbreviation, field)) + return true; + + return !full.empty() && SetSelectControlValue(full, field); +} + +bool FillCountrySelectControl(const base::string16& value, + const std::string& app_locale, + FormFieldData* field_data) { + std::string country_code = AutofillCountry::GetCountryCode(value, app_locale); + if (country_code.empty()) + return false; + + DCHECK_EQ(field_data->option_values.size(), + field_data->option_contents.size()); + for (size_t i = 0; i < field_data->option_values.size(); ++i) { + // Canonicalize each <option> value to a country code, and compare to the + // target country code. + base::string16 value = field_data->option_values[i]; + base::string16 contents = field_data->option_contents[i]; + if (country_code == AutofillCountry::GetCountryCode(value, app_locale) || + country_code == AutofillCountry::GetCountryCode(contents, app_locale)) { + field_data->value = value; + return true; + } + } + + return false; +} + +bool FillExpirationMonthSelectControl(const base::string16& value, + FormFieldData* field) { + int index = 0; + if (!StringToInt(value, &index) || + index <= 0 || + static_cast<size_t>(index) >= arraysize(kMonthsFull)) + return false; + + bool filled = + SetSelectControlValue(ASCIIToUTF16(kMonthsAbbreviated[index]), field) || + SetSelectControlValue(ASCIIToUTF16(kMonthsFull[index]), field) || + FillNumericSelectControl(index, field); + return filled; +} + +// Returns true if the last two digits in |year| match those in |str|. +bool LastTwoDigitsMatch(const base::string16& year, + const base::string16& str) { + int year_int; + int str_int; + if (!StringToInt(year, &year_int) || !StringToInt(str, &str_int)) + return false; + + return (year_int % 100) == (str_int % 100); +} + +// Try to fill a year |value| into the given |field| by comparing the last two +// digits of the year to the field's options. +bool FillYearSelectControl(const base::string16& value, + FormFieldData* field) { + if (value.size() != 2U && value.size() != 4U) + return false; + + DCHECK_EQ(field->option_values.size(), field->option_contents.size()); + for (size_t i = 0; i < field->option_values.size(); ++i) { + if (LastTwoDigitsMatch(value, field->option_values[i]) || + LastTwoDigitsMatch(value, field->option_contents[i])) { + field->value = field->option_values[i]; + return true; + } + } + + return false; +} + +// Try to fill a credit card type |value| (Visa, MasterCard, etc.) into the +// given |field|. +bool FillCreditCardTypeSelectControl(const base::string16& value, + FormFieldData* field) { + // Try stripping off spaces. + base::string16 value_stripped; + RemoveChars(StringToLowerASCII(value), kWhitespaceUTF16, &value_stripped); + + for (size_t i = 0; i < field->option_values.size(); ++i) { + base::string16 option_value_lowercase; + RemoveChars(StringToLowerASCII(field->option_values[i]), kWhitespaceUTF16, + &option_value_lowercase); + base::string16 option_contents_lowercase; + RemoveChars(StringToLowerASCII(field->option_contents[i]), kWhitespaceUTF16, + &option_contents_lowercase); + + // Perform a case-insensitive comparison; but fill the form with the + // original text, not the lowercased version. + if (value_stripped == option_value_lowercase || + value_stripped == option_contents_lowercase) { + field->value = field->option_values[i]; + return true; + } + } + + // For American Express, also try filling as "AmEx". + if (value == l10n_util::GetStringUTF16(IDS_AUTOFILL_CC_AMEX)) + return FillCreditCardTypeSelectControl(ASCIIToUTF16("AmEx"), field); + + return false; +} + +// Set |field_data|'s value to |number|, or possibly an appropriate substring of +// |number|. The |field| specifies the type of the phone and whether this is a +// phone prefix or suffix. +void FillPhoneNumberField(const AutofillField& field, + const base::string16& number, + FormFieldData* field_data) { + // Check to see if the size field matches the "prefix" or "suffix" sizes and + // fill accordingly. + base::string16 value = number; + if (number.length() == + PhoneNumber::kPrefixLength + PhoneNumber::kSuffixLength) { + if (field.phone_part() == AutofillField::PHONE_PREFIX || + field_data->max_length == PhoneNumber::kPrefixLength) { + value = number.substr(PhoneNumber::kPrefixOffset, + PhoneNumber::kPrefixLength); + } else if (field.phone_part() == AutofillField::PHONE_SUFFIX || + field_data->max_length == PhoneNumber::kSuffixLength) { + value = number.substr(PhoneNumber::kSuffixOffset, + PhoneNumber::kSuffixLength); + } + } + + field_data->value = value; +} + +// Fills in the select control |field| with |value|. If an exact match is not +// found, falls back to alternate filling strategies based on the |type|. +void FillSelectControl(const AutofillType& type, + const base::string16& value, + const std::string& app_locale, + FormFieldData* field) { + DCHECK_EQ("select-one", field->form_control_type); + + // Guard against corrupted values passed over IPC. + if (field->option_values.size() != field->option_contents.size()) + return; + + if (value.empty()) + return; + + // First, search for exact matches. + if (SetSelectControlValue(value, field)) + return; + + // If that fails, try specific fallbacks based on the field type. + ServerFieldType storable_type = type.GetStorableType(); + if (storable_type == ADDRESS_HOME_STATE) { + FillStateSelectControl(value, field); + } else if (storable_type == ADDRESS_HOME_COUNTRY) { + FillCountrySelectControl(value, app_locale, field); + } else if (storable_type == CREDIT_CARD_EXP_MONTH) { + FillExpirationMonthSelectControl(value, field); + } else if (storable_type == CREDIT_CARD_EXP_2_DIGIT_YEAR || + storable_type == CREDIT_CARD_EXP_4_DIGIT_YEAR) { + FillYearSelectControl(value, field); + } else if (storable_type == CREDIT_CARD_TYPE) { + FillCreditCardTypeSelectControl(value, field); + } +} + +// Fills in the month control |field| with |value|. |value| should be a date +// formatted as MM/YYYY. If it isn't, filling will fail. +bool FillMonthControl(const base::string16& value, FormFieldData* field) { + // Autofill formats a combined date as month/year. + std::vector<base::string16> pieces; + base::SplitString(value, char16('/'), &pieces); + if (pieces.size() != 2) + return false; + + // HTML5 input="month" is formatted as year-month. + base::string16 month = pieces[0]; + base::string16 year = pieces[1]; + if ((month.size() != 1 && month.size() != 2) || year.size() != 4) + return false; + + // HTML5 input="month" expects zero-padded months. + if (month.size() == 1) + month = ASCIIToUTF16("0") + month; + + field->value = year + ASCIIToUTF16("-") + month; + return true; +} + +std::string Hash32Bit(const std::string& str) { std::string hash_bin = base::SHA1HashString(str); DCHECK_EQ(20U, hash_bin.length()); @@ -26,8 +292,6 @@ static std::string Hash32Bit(const std::string& str) { } // namespace -namespace autofill { - AutofillField::AutofillField() : server_type_(NO_SERVER_DATA), heuristic_type_(UNKNOWN_TYPE), @@ -74,9 +338,11 @@ void AutofillField::SetHtmlType(HtmlFieldType type, HtmlFieldMode mode) { html_mode_ = mode; if (type == HTML_TYPE_TEL_LOCAL_PREFIX) - phone_part_ = AutofillField::PHONE_PREFIX; + phone_part_ = PHONE_PREFIX; else if (type == HTML_TYPE_TEL_LOCAL_SUFFIX) - phone_part_ = AutofillField::PHONE_SUFFIX; + phone_part_ = PHONE_SUFFIX; + else + phone_part_ = IGNORED; } AutofillType AutofillField::Type() const { @@ -103,4 +369,21 @@ bool AutofillField::IsFieldFillable() const { return !Type().IsUnknown(); } +// static +void AutofillField::FillFormField(const AutofillField& field, + const base::string16& value, + const std::string& app_locale, + FormFieldData* field_data) { + AutofillType type = field.Type(); + + if (type.GetStorableType() == PHONE_HOME_NUMBER) + FillPhoneNumberField(field, value, field_data); + else if (field_data->form_control_type == "select-one") + FillSelectControl(type, value, app_locale, field_data); + else if (field_data->form_control_type == "month") + FillMonthControl(value, field_data); + else + field_data->value = value; +} + } // namespace autofill diff --git a/components/autofill/core/browser/autofill_field.h b/components/autofill/core/browser/autofill_field.h index 6f57484..38aeaea 100644 --- a/components/autofill/core/browser/autofill_field.h +++ b/components/autofill/core/browser/autofill_field.h @@ -65,6 +65,14 @@ class AutofillField : public FormFieldData { void set_default_value(const std::string& value) { default_value_ = value; } const std::string& default_value() const { return default_value_; } + // Set |field_data|'s value to |value|. Uses |field| and |app_locale| as + // hints when filling exceptional cases like phone number values and <select> + // fields. + static void FillFormField(const AutofillField& field, + const base::string16& value, + const std::string& app_locale, + FormFieldData* field_data); + private: // The unique name of this field, generated by Autofill. base::string16 unique_name_; diff --git a/components/autofill/core/browser/autofill_field_unittest.cc b/components/autofill/core/browser/autofill_field_unittest.cc index 3c26302..b7daedae 100644 --- a/components/autofill/core/browser/autofill_field_unittest.cc +++ b/components/autofill/core/browser/autofill_field_unittest.cc @@ -2,7 +2,9 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +#include "base/format_macros.h" #include "base/strings/string_util.h" +#include "base/strings/stringprintf.h" #include "base/strings/utf_string_conversions.h" #include "components/autofill/core/browser/autofill_field.h" #include "components/autofill/core/browser/autofill_type.h" @@ -12,6 +14,22 @@ namespace autofill { namespace { +// Returns a FormFieldData object corresponding to a <select> field populated +// with the given |options|. +FormFieldData GenerateSelectFieldWithOptions(const char* const* options, + size_t options_size) { + std::vector<base::string16> options16(options_size); + for (size_t i = 0; i < options_size; ++i) { + options16[i] = ASCIIToUTF16(options[i]); + } + + FormFieldData form_field; + form_field.form_control_type = "select-one"; + form_field.option_values = options16; + form_field.option_contents = options16; + return form_field; +} + TEST(AutofillFieldTest, Type) { AutofillField field; ASSERT_EQ(NO_SERVER_DATA, field.server_type()); @@ -95,5 +113,241 @@ TEST(AutofillFieldTest, IsFieldFillable) { EXPECT_TRUE(field.IsFieldFillable()); } +TEST(AutofillFieldTest, FillPhoneNumber) { + AutofillField field; + field.SetHtmlType(HTML_TYPE_TEL_LOCAL_PREFIX, HtmlFieldMode()); + + // Fill with a non-phone number; should fill normally. + AutofillField::FillFormField(field, ASCIIToUTF16("Oh hai"), "en-US", &field); + EXPECT_EQ(ASCIIToUTF16("Oh hai"), field.value); + + // Fill with a phone number; should fill just the prefix. + AutofillField::FillFormField(field, ASCIIToUTF16("5551234"), "en-US", &field); + EXPECT_EQ(ASCIIToUTF16("555"), field.value); + + // Now reset the type, and set a max-length instead. + field.SetHtmlType(HTML_TYPE_UNKNOWN, HtmlFieldMode()); + field.set_heuristic_type(PHONE_HOME_NUMBER); + field.max_length = 4; + + // Fill with a phone-number; should fill just the suffix. + AutofillField::FillFormField(field, ASCIIToUTF16("5551234"), "en-US", &field); + EXPECT_EQ(ASCIIToUTF16("1234"), field.value); +} + +TEST(AutofillFieldTest, FillSelectControlByValue) { + const char* const kOptions[] = { + "Eenie", "Meenie", "Miney", "Mo", + }; + AutofillField field( + GenerateSelectFieldWithOptions(kOptions, arraysize(kOptions)), + base::string16()); + + // Set semantically empty contents for each option, so that only the values + // can be used for matching. + for (size_t i = 0; i < field.option_contents.size(); ++i) { + field.option_contents[i] = ASCIIToUTF16(base::StringPrintf("%" PRIuS, i)); + } + + AutofillField::FillFormField(field, ASCIIToUTF16("Meenie"), "en-US", + &field); + EXPECT_EQ(ASCIIToUTF16("Meenie"), field.value); +} + +TEST(AutofillFieldTest, FillSelectControlByContents) { + const char* const kOptions[] = { + "Eenie", "Meenie", "Miney", "Mo", + }; + AutofillField field( + GenerateSelectFieldWithOptions(kOptions, arraysize(kOptions)), + base::string16()); + + // Set semantically empty values for each option, so that only the contents + // can be used for matching. + for (size_t i = 0; i < field.option_values.size(); ++i) { + field.option_values[i] = ASCIIToUTF16(base::StringPrintf("%" PRIuS, i)); + } + + AutofillField::FillFormField(field, ASCIIToUTF16("Miney"), "en-US", + &field); + EXPECT_EQ(ASCIIToUTF16("2"), field.value); // Corresponds to "Miney". +} + +TEST(AutofillFieldTest, FillSelectControlWithFullCountryNames) { + const char* const kCountries[] = { + "Albania", "Canada" + }; + AutofillField field( + GenerateSelectFieldWithOptions(kCountries, arraysize(kCountries)), + base::string16()); + field.set_heuristic_type(ADDRESS_HOME_COUNTRY); + + AutofillField::FillFormField(field, ASCIIToUTF16("CA"), "en-US", &field); + EXPECT_EQ(ASCIIToUTF16("Canada"), field.value); +} + +TEST(AutofillFieldTest, FillSelectControlWithAbbreviatedCountryNames) { + const char* const kCountries[] = { + "AL", "CA" + }; + AutofillField field( + GenerateSelectFieldWithOptions(kCountries, arraysize(kCountries)), + base::string16()); + field.set_heuristic_type(ADDRESS_HOME_COUNTRY); + + AutofillField::FillFormField(field, ASCIIToUTF16("Canada"), "en-US", &field); + EXPECT_EQ(ASCIIToUTF16("CA"), field.value); +} + +TEST(AutofillFieldTest, FillSelectControlWithFullStateNames) { + const char* const kStates[] = { + "Alabama", "California" + }; + AutofillField field( + GenerateSelectFieldWithOptions(kStates, arraysize(kStates)), + base::string16()); + field.set_heuristic_type(ADDRESS_HOME_STATE); + + AutofillField::FillFormField(field, ASCIIToUTF16("CA"), "en-US", &field); + EXPECT_EQ(ASCIIToUTF16("California"), field.value); +} + +TEST(AutofillFieldTest, FillSelectControlWithWithAbbreviateStateNames) { + const char* const kStates[] = { + "AL", "CA" + }; + AutofillField field( + GenerateSelectFieldWithOptions(kStates, arraysize(kStates)), + base::string16()); + field.set_heuristic_type(ADDRESS_HOME_STATE); + + AutofillField::FillFormField(field, ASCIIToUTF16("California"), "en-US", + &field); + EXPECT_EQ(ASCIIToUTF16("CA"), field.value); +} + +TEST(AutofillFieldTest, FillSelectControlWithNumericMonth) { + const char* const kMonthsNumeric[] = { + "01", "02", "03", "04", "05", "06", "07", "08", "09", "10", "11", "12", + }; + AutofillField field( + GenerateSelectFieldWithOptions(kMonthsNumeric, arraysize(kMonthsNumeric)), + base::string16()); + field.set_heuristic_type(CREDIT_CARD_EXP_MONTH); + + // Try with a leading zero. + AutofillField::FillFormField(field, ASCIIToUTF16("03"), "en-US", &field); + EXPECT_EQ(ASCIIToUTF16("03"), field.value); + + // Try without a leading zero. + AutofillField::FillFormField(field, ASCIIToUTF16("4"), "en-US", &field); + EXPECT_EQ(ASCIIToUTF16("04"), field.value); + + // Try a two-digit month. + AutofillField::FillFormField(field, ASCIIToUTF16("11"), "en-US", &field); + EXPECT_EQ(ASCIIToUTF16("11"), field.value); +} + +TEST(AutofillFieldTest, FillSelectControlWithAbbreviatedMonthName) { + const char* const kMonthsAbbreviated[] = { + "Jan", "Feb", "Mar", "Apr", "May", "Jun", + "Jul", "Aug", "Sep", "Oct", "Nov", "Dec", + }; + AutofillField field( + GenerateSelectFieldWithOptions( + kMonthsAbbreviated, arraysize(kMonthsAbbreviated)), + base::string16()); + field.set_heuristic_type(CREDIT_CARD_EXP_MONTH); + + AutofillField::FillFormField(field, ASCIIToUTF16("04"), "en-US", &field); + EXPECT_EQ(ASCIIToUTF16("Apr"), field.value); +} + +TEST(AutofillFieldTest, FillSelectControlWithFullMonthName) { + const char* const kMonthsFull[] = { + "January", "February", "March", "April", "May", "June", + "July", "August", "September", "October", "November", "December", + }; + AutofillField field( + GenerateSelectFieldWithOptions(kMonthsFull, arraysize(kMonthsFull)), + base::string16()); + field.set_heuristic_type(CREDIT_CARD_EXP_MONTH); + + AutofillField::FillFormField(field, ASCIIToUTF16("04"), "en-US", &field); + EXPECT_EQ(ASCIIToUTF16("April"), field.value); +} + +TEST(AutofillFieldTest, FillSelectControlWithNumericMonthSansLeadingZero) { + const char* const kMonthsNumeric[] = { + "1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12", + }; + AutofillField field( + GenerateSelectFieldWithOptions(kMonthsNumeric, arraysize(kMonthsNumeric)), + base::string16()); + field.set_heuristic_type(CREDIT_CARD_EXP_MONTH); + + AutofillField::FillFormField(field, ASCIIToUTF16("04"), "en-US", &field); + EXPECT_EQ(ASCIIToUTF16("4"), field.value); +} + +TEST(AutofillFieldTest, FillSelectControlWithTwoDigitCreditCardYear) { + const char* const kYears[] = { + "12", "13", "14", "15", "16", "17", "18", "19" + }; + AutofillField field(GenerateSelectFieldWithOptions(kYears, arraysize(kYears)), + base::string16()); + field.set_heuristic_type(CREDIT_CARD_EXP_2_DIGIT_YEAR); + + AutofillField::FillFormField(field, ASCIIToUTF16("2017"), "en-US", &field); + EXPECT_EQ(ASCIIToUTF16("17"), field.value); +} + +TEST(AutofillFieldTest, FillSelectControlWithCreditCardType) { + const char* const kCreditCardTypes[] = { + "Visa", "Master Card", "AmEx", "discover" + }; + AutofillField field( + GenerateSelectFieldWithOptions( + kCreditCardTypes, arraysize(kCreditCardTypes)), + base::string16()); + field.set_heuristic_type(CREDIT_CARD_TYPE); + + // Normal case: + AutofillField::FillFormField(field, ASCIIToUTF16("Visa"), "en-US", &field); + EXPECT_EQ(ASCIIToUTF16("Visa"), field.value); + + // Filling should be able to handle intervening whitespace: + AutofillField::FillFormField(field, ASCIIToUTF16("MasterCard"), "en-US", + &field); + EXPECT_EQ(ASCIIToUTF16("Master Card"), field.value); + + // American Express is sometimes abbreviated as AmEx: + AutofillField::FillFormField(field, ASCIIToUTF16("American Express"), "en-US", + &field); + EXPECT_EQ(ASCIIToUTF16("AmEx"), field.value); + + // Case insensitivity: + AutofillField::FillFormField(field, ASCIIToUTF16("Discover"), "en-US", + &field); + EXPECT_EQ(ASCIIToUTF16("discover"), field.value); +} + +TEST(AutofillFieldTest, FillMonthControl) { + AutofillField field; + field.form_control_type = "month"; + + // Try a month with two digits. + AutofillField::FillFormField(field, ASCIIToUTF16("12/2017"), "en-US", &field); + EXPECT_EQ(ASCIIToUTF16("2017-12"), field.value); + + // Try a month with a leading zero. + AutofillField::FillFormField(field, ASCIIToUTF16("03/2019"), "en-US", &field); + EXPECT_EQ(ASCIIToUTF16("2019-03"), field.value); + + // Try a month without a leading zero. + AutofillField::FillFormField(field, ASCIIToUTF16("4/2018"), "en-US", &field); + EXPECT_EQ(ASCIIToUTF16("2018-04"), field.value); +} + } // namespace } // namespace autofill diff --git a/components/autofill/core/browser/autofill_manager.cc b/components/autofill/core/browser/autofill_manager.cc index d6d55df..4c76295 100644 --- a/components/autofill/core/browser/autofill_manager.cc +++ b/components/autofill/core/browser/autofill_manager.cc @@ -483,8 +483,10 @@ void AutofillManager::OnFillAutofillFormData(int query_id, for (std::vector<FormFieldData>::iterator iter = result.fields.begin(); iter != result.fields.end(); ++iter) { if ((*iter) == field) { - data_model->FillFormField( - *autofill_field, variant, app_locale_, &(*iter)); + base::string16 value = data_model->GetInfoForVariant( + autofill_field->Type(), variant, app_locale_); + AutofillField::FillFormField(*autofill_field, value, app_locale_, + &(*iter)); // Mark the cached field as autofilled, so that we can detect when a // user edits an autofilled field (for metrics). autofill_field->is_autofilled = true; @@ -518,10 +520,10 @@ void AutofillManager::OnFillAutofillFormData(int query_id, field_group_type == initiating_group_type) { use_variant = variant; } - data_model->FillFormField(*cached_field, - use_variant, - app_locale_, - &result.fields[i]); + base::string16 value = data_model->GetInfoForVariant( + cached_field->Type(), use_variant, app_locale_); + AutofillField::FillFormField(*cached_field, value, app_locale_, + &result.fields[i]); // Mark the cached field as autofilled, so that we can detect when a user // edits an autofilled field (for metrics). form_structure->field(i)->is_autofilled = true; diff --git a/components/autofill/core/browser/autofill_profile.cc b/components/autofill/core/browser/autofill_profile.cc index 735549f..53a056f 100644 --- a/components/autofill/core/browser/autofill_profile.cc +++ b/components/autofill/core/browser/autofill_profile.cc @@ -309,6 +309,22 @@ bool AutofillProfile::SetInfo(const AutofillType& type, form_group->SetInfo(type, CollapseWhitespace(value, false), app_locale); } +base::string16 AutofillProfile::GetInfoForVariant( + const AutofillType& type, + size_t variant, + const std::string& app_locale) const { + std::vector<base::string16> values; + GetMultiInfo(type, app_locale, &values); + + if (variant >= values.size()) { + // If the variant is unavailable, bail. This case is reachable, for + // example if Sync updates a profile during the filling process. + return base::string16(); + } + + return values[variant]; +} + void AutofillProfile::SetRawMultiInfo( ServerFieldType type, const std::vector<base::string16>& values) { @@ -352,58 +368,6 @@ void AutofillProfile::GetMultiInfo(const AutofillType& type, GetMultiInfoImpl(type, app_locale, values); } -void AutofillProfile::FillFormField(const AutofillField& field, - size_t variant, - const std::string& app_locale, - FormFieldData* field_data) const { - AutofillType type = field.Type(); - DCHECK_NE(CREDIT_CARD, type.group()); - DCHECK(field_data); - - if (type.GetStorableType() == PHONE_HOME_NUMBER) { - FillPhoneNumberField(field, variant, app_locale, field_data); - } else if (field_data->form_control_type == "select-one") { - FillSelectControl(type, app_locale, field_data); - } else { - std::vector<base::string16> values; - GetMultiInfo(type, app_locale, &values); - if (variant >= values.size()) { - // If the variant is unavailable, bail. This case is reachable, for - // example if Sync updates a profile during the filling process. - return; - } - - field_data->value = values[variant]; - } -} - -void AutofillProfile::FillPhoneNumberField(const AutofillField& field, - size_t variant, - const std::string& app_locale, - FormFieldData* field_data) const { - std::vector<base::string16> values; - GetMultiInfo(field.Type(), app_locale, &values); - DCHECK(variant < values.size()); - - // If we are filling a phone number, check to see if the size field - // matches the "prefix" or "suffix" sizes and fill accordingly. - base::string16 number = values[variant]; - if (number.length() == - PhoneNumber::kPrefixLength + PhoneNumber::kSuffixLength) { - if (field.phone_part() == AutofillField::PHONE_PREFIX || - field_data->max_length == PhoneNumber::kPrefixLength) { - number = number.substr(PhoneNumber::kPrefixOffset, - PhoneNumber::kPrefixLength); - } else if (field.phone_part() == AutofillField::PHONE_SUFFIX || - field_data->max_length == PhoneNumber::kSuffixLength) { - number = number.substr(PhoneNumber::kSuffixOffset, - PhoneNumber::kSuffixLength); - } - } - - field_data->value = number; -} - const base::string16 AutofillProfile::Label() const { return label_; } @@ -661,28 +625,6 @@ void AutofillProfile::GetSupportedTypes( (*it)->GetSupportedTypes(supported_types); } -bool AutofillProfile::FillCountrySelectControl( - const std::string& app_locale, - FormFieldData* field_data) const { - std::string country_code = UTF16ToASCII(GetRawInfo(ADDRESS_HOME_COUNTRY)); - - DCHECK_EQ(field_data->option_values.size(), - field_data->option_contents.size()); - for (size_t i = 0; i < field_data->option_values.size(); ++i) { - // Canonicalize each <option> value to a country code, and compare to the - // target country code. - base::string16 value = field_data->option_values[i]; - base::string16 contents = field_data->option_contents[i]; - if (country_code == AutofillCountry::GetCountryCode(value, app_locale) || - country_code == AutofillCountry::GetCountryCode(contents, app_locale)) { - field_data->value = value; - return true; - } - } - - return false; -} - void AutofillProfile::GetMultiInfoImpl( const AutofillType& type, const std::string& app_locale, diff --git a/components/autofill/core/browser/autofill_profile.h b/components/autofill/core/browser/autofill_profile.h index 5a3f65c..0611fd3 100644 --- a/components/autofill/core/browser/autofill_profile.h +++ b/components/autofill/core/browser/autofill_profile.h @@ -54,10 +54,10 @@ class AutofillProfile : public AutofillDataModel { const std::string& app_locale) OVERRIDE; // AutofillDataModel: - virtual void FillFormField(const AutofillField& field, - size_t variant, - const std::string& app_locale, - FormFieldData* field_data) const OVERRIDE; + virtual base::string16 GetInfoForVariant( + const AutofillType& type, + size_t variant, + const std::string& app_locale) const OVERRIDE; // Multi-value equivalents to |GetInfo| and |SetInfo|. void SetRawMultiInfo(ServerFieldType type, @@ -68,15 +68,6 @@ class AutofillProfile : public AutofillDataModel { const std::string& app_locale, std::vector<base::string16>* values) const; - // Set |field_data|'s value for phone number based on contents of |this|. - // The |field| specifies the type of the phone and whether this is a - // phone prefix or suffix. The |variant| parameter specifies which value in a - // multi-valued profile. - void FillPhoneNumberField(const AutofillField& field, - size_t variant, - const std::string& app_locale, - FormFieldData* field_data) const; - // The user-visible label of the profile, generated in relation to other // profiles. Shows at least 2 fields that differentiate profile from other // profiles. See AdjustInferredLabels() further down for more description. @@ -153,8 +144,6 @@ class AutofillProfile : public AutofillDataModel { typedef std::vector<const FormGroup*> FormGroupList; // FormGroup: - virtual bool FillCountrySelectControl(const std::string& app_locale, - FormFieldData* field) const OVERRIDE; virtual void GetSupportedTypes( ServerFieldTypeSet* supported_types) const OVERRIDE; diff --git a/components/autofill/core/browser/autofill_profile_unittest.cc b/components/autofill/core/browser/autofill_profile_unittest.cc index f67c536..e652fdf 100644 --- a/components/autofill/core/browser/autofill_profile_unittest.cc +++ b/components/autofill/core/browser/autofill_profile_unittest.cc @@ -8,7 +8,6 @@ #include "base/memory/scoped_vector.h" #include "base/stl_util.h" #include "base/strings/string16.h" -#include "base/strings/stringprintf.h" #include "base/strings/utf_string_conversions.h" #include "components/autofill/core/browser/autofill_common_test.h" #include "components/autofill/core/browser/autofill_profile.h" @@ -772,132 +771,6 @@ TEST(AutofillProfileTest, MultiValuePhone) { EXPECT_EQ(base::string16(), p.GetRawInfo(PHONE_HOME_WHOLE_NUMBER)); } -TEST(AutofillProfileTest, AddressCountryFull) { - const char* const kCountries[] = { - "Albania", "Canada" - }; - std::vector<base::string16> options(arraysize(kCountries)); - for (size_t i = 0; i < arraysize(kCountries); ++i) { - options[i] = ASCIIToUTF16(kCountries[i]); - } - - FormFieldData field; - field.form_control_type = "select-one"; - field.option_values = options; - field.option_contents = options; - - AutofillProfile profile(base::GenerateGUID(), "https://www.example.com/"); - profile.SetRawInfo(ADDRESS_HOME_COUNTRY, ASCIIToUTF16("CA")); - profile.FillSelectControl( - AutofillType(ADDRESS_HOME_COUNTRY), "en-US", &field); - EXPECT_EQ(ASCIIToUTF16("Canada"), field.value); -} - -TEST(AutofillProfileTest, AddressCountryAbbrev) { - const char* const kCountries[] = { - "AL", "CA" - }; - std::vector<base::string16> options(arraysize(kCountries)); - for (size_t i = 0; i < arraysize(kCountries); ++i) { - options[i] = ASCIIToUTF16(kCountries[i]); - } - - FormFieldData field; - field.form_control_type = "select-one"; - field.option_values = options; - field.option_contents = options; - - AutofillProfile profile(base::GenerateGUID(), "https://www.example.com/"); - profile.SetRawInfo(ADDRESS_HOME_COUNTRY, ASCIIToUTF16("CA")); - profile.FillSelectControl( - AutofillType(ADDRESS_HOME_COUNTRY), "en-US", &field); - EXPECT_EQ(ASCIIToUTF16("CA"), field.value); -} - -TEST(AutofillProfileTest, AddressStateFull) { - const char* const kStates[] = { - "Alabama", "California" - }; - std::vector<base::string16> options(arraysize(kStates)); - for (size_t i = 0; i < arraysize(kStates); ++i) { - options[i] = ASCIIToUTF16(kStates[i]); - } - - FormFieldData field; - field.form_control_type = "select-one"; - field.option_values = options; - field.option_contents = options; - - AutofillProfile profile(base::GenerateGUID(), "https://www.example.com/"); - profile.SetRawInfo(ADDRESS_HOME_STATE, ASCIIToUTF16("CA")); - profile.FillSelectControl(AutofillType(ADDRESS_HOME_STATE), "en-US", &field); - EXPECT_EQ(ASCIIToUTF16("California"), field.value); -} - -TEST(AutofillProfileTest, AddressStateAbbrev) { - const char* const kStates[] = { - "AL", "CA" - }; - std::vector<base::string16> options(arraysize(kStates)); - for (size_t i = 0; i < arraysize(kStates); ++i) { - options[i] = ASCIIToUTF16(kStates[i]); - } - - FormFieldData field; - field.form_control_type = "select-one"; - field.option_values = options; - field.option_contents = options; - - AutofillProfile profile(base::GenerateGUID(), "https://www.example.com/"); - profile.SetRawInfo(ADDRESS_HOME_STATE, ASCIIToUTF16("California")); - profile.FillSelectControl(AutofillType(ADDRESS_HOME_STATE), "en-US", &field); - EXPECT_EQ(ASCIIToUTF16("CA"), field.value); -} - -TEST(AutofillProfileTest, FillByValue) { - const char* const kStates[] = { - "Alabama", "California" - }; - std::vector<base::string16> values(arraysize(kStates)); - std::vector<base::string16> contents(arraysize(kStates)); - for (unsigned int i = 0; i < arraysize(kStates); ++i) { - values[i] = ASCIIToUTF16(kStates[i]); - contents[i] = ASCIIToUTF16(base::StringPrintf("%u", i)); - } - - FormFieldData field; - field.form_control_type = "select-one"; - field.option_values = values; - field.option_contents = contents; - - AutofillProfile profile(base::GenerateGUID(), "https://www.example.com/"); - profile.SetRawInfo(ADDRESS_HOME_STATE, ASCIIToUTF16("California")); - profile.FillSelectControl(AutofillType(ADDRESS_HOME_STATE), "en-US", &field); - EXPECT_EQ(ASCIIToUTF16("California"), field.value); -} - -TEST(AutofillProfileTest, FillByContents) { - const char* const kStates[] = { - "Alabama", "California" - }; - std::vector<base::string16> values(arraysize(kStates)); - std::vector<base::string16> contents(arraysize(kStates)); - for (unsigned int i = 0; i < arraysize(kStates); ++i) { - values[i] = ASCIIToUTF16(base::StringPrintf("%u", i + 1)); - contents[i] = ASCIIToUTF16(kStates[i]); - } - - FormFieldData field; - field.form_control_type = "select-one"; - field.option_values = values; - field.option_contents = contents; - - AutofillProfile profile(base::GenerateGUID(), "https://www.example.com/"); - profile.SetRawInfo(ADDRESS_HOME_STATE, ASCIIToUTF16("California")); - profile.FillSelectControl(AutofillType(ADDRESS_HOME_STATE), "en-US", &field); - EXPECT_EQ(ASCIIToUTF16("2"), field.value); -} - TEST(AutofillProfileTest, IsPresentButInvalid) { AutofillProfile profile(base::GenerateGUID(), "https://www.example.com/"); EXPECT_FALSE(profile.IsPresentButInvalid(ADDRESS_HOME_STATE)); diff --git a/components/autofill/core/browser/credit_card.cc b/components/autofill/core/browser/credit_card.cc index a3e3044..9617798 100644 --- a/components/autofill/core/browser/credit_card.cc +++ b/components/autofill/core/browser/credit_card.cc @@ -534,31 +534,6 @@ bool CreditCard::UpdateFromImportedCard(const CreditCard& imported_card, return true; } -void CreditCard::FillFormField(const AutofillField& field, - size_t /*variant*/, - const std::string& app_locale, - FormFieldData* field_data) const { - DCHECK_EQ(CREDIT_CARD, field.Type().group()); - DCHECK(field_data); - - if (field_data->form_control_type == "select-one") { - FillSelectControl(field.Type(), app_locale, field_data); - } else if (field_data->form_control_type == "month") { - // HTML5 input="month" consists of year-month. - base::string16 year = - GetInfo(AutofillType(CREDIT_CARD_EXP_4_DIGIT_YEAR), app_locale); - base::string16 month = - GetInfo(AutofillType(CREDIT_CARD_EXP_MONTH), app_locale); - if (!year.empty() && !month.empty()) { - // Fill the value only if |this| includes both year and month - // information. - field_data->value = year + ASCIIToUTF16("-") + month; - } - } else { - field_data->value = GetInfo(field.Type(), app_locale); - } -} - int CreditCard::Compare(const CreditCard& credit_card) const { // The following CreditCard field types are the only types we store in the // WebDB so far, so we're only concerned with matching these types in the diff --git a/components/autofill/core/browser/credit_card.h b/components/autofill/core/browser/credit_card.h index d5bf1a0..4c92e62 100644 --- a/components/autofill/core/browser/credit_card.h +++ b/components/autofill/core/browser/credit_card.h @@ -59,12 +59,6 @@ class CreditCard : public AutofillDataModel { const base::string16& value, const std::string& app_locale) OVERRIDE; - // AutofillDataModel: - virtual void FillFormField(const AutofillField& field, - size_t variant, - const std::string& app_locale, - FormFieldData* field_data) const OVERRIDE; - // Credit card preview summary, for example: ******1234, Exp: 01/2020 const base::string16 Label() const; diff --git a/components/autofill/core/browser/credit_card_field.cc b/components/autofill/core/browser/credit_card_field.cc index bba804c..f9012ca 100644 --- a/components/autofill/core/browser/credit_card_field.cc +++ b/components/autofill/core/browser/credit_card_field.cc @@ -95,7 +95,7 @@ FormField* CreditCardField::Parse(AutofillScanner* scanner) { } if (LowerCaseEqualsASCII(scanner->Cursor()->form_control_type, "month")) { - credit_card_field->expiration_month_ = scanner->Cursor(); + credit_card_field->expiration_date_ = scanner->Cursor(); scanner->Advance(); } else { // First try to parse split month/year expiration fields. @@ -170,10 +170,7 @@ FormField* CreditCardField::Parse(AutofillScanner* scanner) { if ((credit_card_field->number_ || credit_card_field->verification_) && (credit_card_field->expiration_date_ || (credit_card_field->expiration_month_ && - (credit_card_field->expiration_year_ || - (LowerCaseEqualsASCII( - credit_card_field->expiration_month_->form_control_type, - "month")))))) { + credit_card_field->expiration_year_))) { return credit_card_field.release(); } diff --git a/components/autofill/core/browser/credit_card_field.h b/components/autofill/core/browser/credit_card_field.h index 119e1ab..bf45e7e 100644 --- a/components/autofill/core/browser/credit_card_field.h +++ b/components/autofill/core/browser/credit_card_field.h @@ -27,15 +27,7 @@ class CreditCardField : public FormField { virtual bool ClassifyField(ServerFieldTypeMap* map) const OVERRIDE; private: - FRIEND_TEST_ALL_PREFIXES(CreditCardFieldTest, ParseMiniumCreditCard); - FRIEND_TEST_ALL_PREFIXES(CreditCardFieldTest, ParseFullCreditCard); - FRIEND_TEST_ALL_PREFIXES(CreditCardFieldTest, ParseCreditCardType); - FRIEND_TEST_ALL_PREFIXES(CreditCardFieldTest, ParseExpMonthYear); - FRIEND_TEST_ALL_PREFIXES(CreditCardFieldTest, ParseExpMonthYear2); - FRIEND_TEST_ALL_PREFIXES(CreditCardFieldTest, ParseExpField); - FRIEND_TEST_ALL_PREFIXES(CreditCardFieldTest, ParseExpField2DigitYear); - FRIEND_TEST_ALL_PREFIXES(CreditCardFieldTest, - ParseCreditCardHolderNameWithCCFullName); + friend class CreditCardFieldTest; CreditCardField(); diff --git a/components/autofill/core/browser/credit_card_field_unittest.cc b/components/autofill/core/browser/credit_card_field_unittest.cc index 9f60a1d..073e5d7 100644 --- a/components/autofill/core/browser/credit_card_field_unittest.cc +++ b/components/autofill/core/browser/credit_card_field_unittest.cc @@ -16,15 +16,25 @@ namespace autofill { class CreditCardFieldTest : public testing::Test { public: CreditCardFieldTest() {} + virtual ~CreditCardFieldTest() {} protected: ScopedVector<const AutofillField> list_; - scoped_ptr<CreditCardField> field_; + scoped_ptr<const CreditCardField> field_; ServerFieldTypeMap field_type_map_; - // Downcast for tests. - static CreditCardField* Parse(AutofillScanner* scanner) { - return static_cast<CreditCardField*>(CreditCardField::Parse(scanner)); + // Parses the contents of |list_| as a form, and stores the result into + // |field_|. + void Parse() { + AutofillScanner scanner(list_.get()); + field_.reset( + static_cast<const CreditCardField*>(CreditCardField::Parse(&scanner))); + } + + // Associates fields with their corresponding types, based on the previous + // call to Parse(). + bool ClassifyField() { + return field_->ClassifyField(&field_type_map_); } private: @@ -32,15 +42,13 @@ class CreditCardFieldTest : public testing::Test { }; TEST_F(CreditCardFieldTest, Empty) { - AutofillScanner scanner(list_.get()); - field_.reset(Parse(&scanner)); + Parse(); ASSERT_EQ(static_cast<CreditCardField*>(NULL), field_.get()); } TEST_F(CreditCardFieldTest, NonParse) { list_.push_back(new AutofillField); - AutofillScanner scanner(list_.get()); - field_.reset(Parse(&scanner)); + Parse(); ASSERT_EQ(static_cast<CreditCardField*>(NULL), field_.get()); } @@ -56,8 +64,7 @@ TEST_F(CreditCardFieldTest, ParseCreditCardNoNumber) { field.name = ASCIIToUTF16("ccyear"); list_.push_back(new AutofillField(field, ASCIIToUTF16("year2"))); - AutofillScanner scanner(list_.get()); - field_.reset(Parse(&scanner)); + Parse(); ASSERT_EQ(static_cast<CreditCardField*>(NULL), field_.get()); } @@ -69,8 +76,7 @@ TEST_F(CreditCardFieldTest, ParseCreditCardNoDate) { field.name = ASCIIToUTF16("card_number"); list_.push_back(new AutofillField(field, ASCIIToUTF16("number1"))); - AutofillScanner scanner(list_.get()); - field_.reset(Parse(&scanner)); + Parse(); ASSERT_EQ(static_cast<CreditCardField*>(NULL), field_.get()); } @@ -90,10 +96,9 @@ TEST_F(CreditCardFieldTest, ParseMiniumCreditCard) { field.name = ASCIIToUTF16("ccyear"); list_.push_back(new AutofillField(field, ASCIIToUTF16("year3"))); - AutofillScanner scanner(list_.get()); - field_.reset(Parse(&scanner)); + Parse(); ASSERT_NE(static_cast<CreditCardField*>(NULL), field_.get()); - ASSERT_TRUE(field_->ClassifyField(&field_type_map_)); + EXPECT_TRUE(ClassifyField()); ASSERT_TRUE( field_type_map_.find(ASCIIToUTF16("number1")) != field_type_map_.end()); EXPECT_EQ(CREDIT_CARD_NUMBER, field_type_map_[ASCIIToUTF16("number1")]); @@ -134,10 +139,9 @@ TEST_F(CreditCardFieldTest, ParseFullCreditCard) { field.name = ASCIIToUTF16("verification"); list_.push_back(new AutofillField(field, ASCIIToUTF16("cvc"))); - AutofillScanner scanner(list_.get()); - field_.reset(Parse(&scanner)); + Parse(); ASSERT_NE(static_cast<CreditCardField*>(NULL), field_.get()); - ASSERT_TRUE(field_->ClassifyField(&field_type_map_)); + EXPECT_TRUE(ClassifyField()); ASSERT_TRUE( field_type_map_.find(ASCIIToUTF16("type")) != field_type_map_.end()); EXPECT_EQ(CREDIT_CARD_TYPE, field_type_map_[ASCIIToUTF16("type")]); @@ -180,10 +184,9 @@ TEST_F(CreditCardFieldTest, ParseExpMonthYear) { field.name = ASCIIToUTF16("ExpDate"); list_.push_back(new AutofillField(field, ASCIIToUTF16("year4"))); - AutofillScanner scanner(list_.get()); - field_.reset(Parse(&scanner)); + Parse(); ASSERT_NE(static_cast<CreditCardField*>(NULL), field_.get()); - ASSERT_TRUE(field_->ClassifyField(&field_type_map_)); + EXPECT_TRUE(ClassifyField()); ASSERT_TRUE( field_type_map_.find(ASCIIToUTF16("name1")) != field_type_map_.end()); EXPECT_EQ(CREDIT_CARD_NAME, field_type_map_[ASCIIToUTF16("name1")]); @@ -219,10 +222,9 @@ TEST_F(CreditCardFieldTest, ParseExpMonthYear2) { field.name = ASCIIToUTF16("ExpDate"); list_.push_back(new AutofillField(field, ASCIIToUTF16("year4"))); - AutofillScanner scanner(list_.get()); - field_.reset(Parse(&scanner)); + Parse(); ASSERT_NE(static_cast<CreditCardField*>(NULL), field_.get()); - ASSERT_TRUE(field_->ClassifyField(&field_type_map_)); + EXPECT_TRUE(ClassifyField()); ASSERT_TRUE( field_type_map_.find(ASCIIToUTF16("name1")) != field_type_map_.end()); EXPECT_EQ(CREDIT_CARD_NAME, field_type_map_[ASCIIToUTF16("name1")]); @@ -254,10 +256,9 @@ TEST_F(CreditCardFieldTest, ParseExpField) { field.name = ASCIIToUTF16("cc_exp"); list_.push_back(new AutofillField(field, ASCIIToUTF16("exp3"))); - AutofillScanner scanner(list_.get()); - field_.reset(Parse(&scanner)); + Parse(); ASSERT_NE(static_cast<CreditCardField*>(NULL), field_.get()); - ASSERT_TRUE(field_->ClassifyField(&field_type_map_)); + EXPECT_TRUE(ClassifyField()); ASSERT_TRUE( field_type_map_.find(ASCIIToUTF16("name1")) != field_type_map_.end()); EXPECT_EQ(CREDIT_CARD_NAME, field_type_map_[ASCIIToUTF16("name1")]); @@ -286,10 +287,9 @@ TEST_F(CreditCardFieldTest, ParseExpField2DigitYear) { field.name = ASCIIToUTF16("cc_exp"); list_.push_back(new AutofillField(field, ASCIIToUTF16("exp3"))); - AutofillScanner scanner(list_.get()); - field_.reset(Parse(&scanner)); + Parse(); ASSERT_NE(static_cast<CreditCardField*>(NULL), field_.get()); - ASSERT_TRUE(field_->ClassifyField(&field_type_map_)); + EXPECT_TRUE(ClassifyField()); ASSERT_TRUE( field_type_map_.find(ASCIIToUTF16("name1")) != field_type_map_.end()); EXPECT_EQ(CREDIT_CARD_NAME, field_type_map_[ASCIIToUTF16("name1")]); @@ -310,13 +310,39 @@ TEST_F(CreditCardFieldTest, ParseCreditCardHolderNameWithCCFullName) { field.name = ASCIIToUTF16("ccfullname"); list_.push_back(new AutofillField(field, ASCIIToUTF16("name1"))); - AutofillScanner scanner(list_.get()); - field_.reset(Parse(&scanner)); + Parse(); ASSERT_NE(static_cast<CreditCardField*>(NULL), field_.get()); - ASSERT_TRUE(field_->ClassifyField(&field_type_map_)); + EXPECT_TRUE(ClassifyField()); ASSERT_TRUE( field_type_map_.find(ASCIIToUTF16("name1")) != field_type_map_.end()); EXPECT_EQ(CREDIT_CARD_NAME, field_type_map_[ASCIIToUTF16("name1")]); } +// Verifies that <input type="month"> controls are able to be parsed correctly. +TEST_F(CreditCardFieldTest, ParseMonthControl) { + FormFieldData field; + + field.form_control_type = "text"; + field.label = ASCIIToUTF16("Card number:"); + field.name = ASCIIToUTF16("ccnumber"); + list_.push_back(new AutofillField(field, ASCIIToUTF16("number1"))); + + field.form_control_type = "month"; + field.label = ASCIIToUTF16("Expiration date:"); + field.name = ASCIIToUTF16("ccexp"); + list_.push_back(new AutofillField(field, ASCIIToUTF16("date2"))); + + Parse(); + ASSERT_NE(static_cast<CreditCardField*>(NULL), field_.get()); + EXPECT_TRUE(ClassifyField()); + ASSERT_TRUE( + field_type_map_.find(ASCIIToUTF16("number1")) != field_type_map_.end()); + EXPECT_EQ(CREDIT_CARD_NUMBER, + field_type_map_[ASCIIToUTF16("number1")]); + ASSERT_TRUE( + field_type_map_.find(ASCIIToUTF16("date2")) != field_type_map_.end()); + EXPECT_EQ(CREDIT_CARD_EXP_DATE_4_DIGIT_YEAR, + field_type_map_[ASCIIToUTF16("date2")]); +} + } // namespace autofill diff --git a/components/autofill/core/browser/credit_card_unittest.cc b/components/autofill/core/browser/credit_card_unittest.cc index 837d729..ee3b7d9 100644 --- a/components/autofill/core/browser/credit_card_unittest.cc +++ b/components/autofill/core/browser/credit_card_unittest.cc @@ -360,172 +360,6 @@ TEST(CreditCardTest, CreditCardVerificationCode) { } -TEST(CreditCardTest, CreditCardMonthExact) { - const char* const kMonthsNumeric[] = { - "01", "02", "03", "04", "05", "06", "07", "08", "09", "10", "11", "12", - }; - std::vector<base::string16> options(arraysize(kMonthsNumeric)); - for (size_t i = 0; i < arraysize(kMonthsNumeric); ++i) { - options[i] = ASCIIToUTF16(kMonthsNumeric[i]); - } - - FormFieldData field; - field.form_control_type = "select-one"; - field.option_values = options; - field.option_contents = options; - - CreditCard credit_card(base::GenerateGUID(), "https://www.example.com/"); - credit_card.SetRawInfo(CREDIT_CARD_EXP_MONTH, ASCIIToUTF16("01")); - credit_card.FillSelectControl( - AutofillType(CREDIT_CARD_EXP_MONTH), "en-US", &field); - EXPECT_EQ(ASCIIToUTF16("01"), field.value); -} - -TEST(CreditCardTest, CreditCardMonthAbbreviated) { - const char* const kMonthsAbbreviated[] = { - "Jan", "Feb", "Mar", "Apr", "May", "Jun", - "Jul", "Aug", "Sep", "Oct", "Nov", "Dec", - }; - std::vector<base::string16> options(arraysize(kMonthsAbbreviated)); - for (size_t i = 0; i < arraysize(kMonthsAbbreviated); ++i) { - options[i] = ASCIIToUTF16(kMonthsAbbreviated[i]); - } - - FormFieldData field; - field.form_control_type = "select-one"; - field.option_values = options; - field.option_contents = options; - - CreditCard credit_card(base::GenerateGUID(), "https://www.example.com/"); - credit_card.SetRawInfo(CREDIT_CARD_EXP_MONTH, ASCIIToUTF16("01")); - credit_card.FillSelectControl( - AutofillType(CREDIT_CARD_EXP_MONTH), "en-US", &field); - EXPECT_EQ(ASCIIToUTF16("Jan"), field.value); -} - -TEST(CreditCardTest, CreditCardMonthFull) { - const char* const kMonthsFull[] = { - "January", "February", "March", "April", "May", "June", - "July", "August", "September", "October", "November", "December", - }; - std::vector<base::string16> options(arraysize(kMonthsFull)); - for (size_t i = 0; i < arraysize(kMonthsFull); ++i) { - options[i] = ASCIIToUTF16(kMonthsFull[i]); - } - - FormFieldData field; - field.form_control_type = "select-one"; - field.option_values = options; - field.option_contents = options; - - CreditCard credit_card(base::GenerateGUID(), "https://www.example.com/"); - credit_card.SetRawInfo(CREDIT_CARD_EXP_MONTH, ASCIIToUTF16("01")); - credit_card.FillSelectControl( - AutofillType(CREDIT_CARD_EXP_MONTH), "en-US", &field); - EXPECT_EQ(ASCIIToUTF16("January"), field.value); -} - -TEST(CreditCardTest, CreditCardMonthNumeric) { - const char* const kMonthsNumeric[] = { - "1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12", - }; - std::vector<base::string16> options(arraysize(kMonthsNumeric)); - for (size_t i = 0; i < arraysize(kMonthsNumeric); ++i) { - options[i] = ASCIIToUTF16(kMonthsNumeric[i]); - } - - FormFieldData field; - field.form_control_type = "select-one"; - field.option_values = options; - field.option_contents = options; - - CreditCard credit_card(base::GenerateGUID(), "https://www.example.com/"); - credit_card.SetRawInfo(CREDIT_CARD_EXP_MONTH, ASCIIToUTF16("01")); - credit_card.FillSelectControl( - AutofillType(CREDIT_CARD_EXP_MONTH), "en-US", &field); - EXPECT_EQ(ASCIIToUTF16("1"), field.value); -} - -TEST(CreditCardTest, CreditCardTwoDigitYear) { - const char* const kYears[] = { - "12", "13", "14", "15", "16", "17", "18", "19" - }; - std::vector<base::string16> options(arraysize(kYears)); - for (size_t i = 0; i < arraysize(kYears); ++i) { - options[i] = ASCIIToUTF16(kYears[i]); - } - - FormFieldData field; - field.form_control_type = "select-one"; - field.option_values = options; - field.option_contents = options; - - CreditCard credit_card(base::GenerateGUID(), "https://www.example.com/"); - credit_card.SetRawInfo(CREDIT_CARD_EXP_4_DIGIT_YEAR, ASCIIToUTF16("2017")); - credit_card.FillSelectControl( - AutofillType(CREDIT_CARD_EXP_4_DIGIT_YEAR), "en-US", &field); - EXPECT_EQ(ASCIIToUTF16("17"), field.value); - EXPECT_EQ(2017, credit_card.expiration_year()); -} - -TEST(CreditCardTest, CreditCardTypeSelectControl) { - const char* const kCreditCardTypes[] = { - "Visa", "Master Card", "AmEx", "discover" - }; - std::vector<base::string16> options(arraysize(kCreditCardTypes)); - for (size_t i = 0; i < arraysize(kCreditCardTypes); ++i) { - options[i] = ASCIIToUTF16(kCreditCardTypes[i]); - } - - FormFieldData field; - field.form_control_type = "select-one"; - field.option_values = options; - field.option_contents = options; - - // Credit card types are inferred from the numbers, so we use test numbers for - // each card type. Test card numbers are drawn from - // http://www.paypalobjects.com/en_US/vhelp/paypalmanager_help/credit_card_numbers.htm - - { - // Normal case: - CreditCard credit_card(base::GenerateGUID(), "https://www.example.com/"); - credit_card.SetRawInfo(CREDIT_CARD_NUMBER, - ASCIIToUTF16("4111111111111111")); - credit_card.FillSelectControl( - AutofillType(CREDIT_CARD_TYPE), "en-US", &field); - EXPECT_EQ(ASCIIToUTF16("Visa"), field.value); - } - - { - // Filling should be able to handle intervening whitespace: - CreditCard credit_card(base::GenerateGUID(), "https://www.example.com/"); - credit_card.SetRawInfo(CREDIT_CARD_NUMBER, - ASCIIToUTF16("5105105105105100")); - credit_card.FillSelectControl( - AutofillType(CREDIT_CARD_TYPE), "en-US", &field); - EXPECT_EQ(ASCIIToUTF16("Master Card"), field.value); - } - - { - // American Express is sometimes abbreviated as AmEx: - CreditCard credit_card(base::GenerateGUID(), "https://www.example.com/"); - credit_card.SetRawInfo(CREDIT_CARD_NUMBER, ASCIIToUTF16("371449635398431")); - credit_card.FillSelectControl( - AutofillType(CREDIT_CARD_TYPE), "en-US", &field); - EXPECT_EQ(ASCIIToUTF16("AmEx"), field.value); - } - - { - // Case insensitivity: - CreditCard credit_card(base::GenerateGUID(), "https://www.example.com/"); - credit_card.SetRawInfo(CREDIT_CARD_NUMBER, - ASCIIToUTF16("6011111111111117")); - credit_card.FillSelectControl( - AutofillType(CREDIT_CARD_TYPE), "en-US", &field); - EXPECT_EQ(ASCIIToUTF16("discover"), field.value); - } -} - TEST(CreditCardTest, GetCreditCardType) { struct { std::string card_number; diff --git a/components/autofill/core/browser/personal_data_manager.cc b/components/autofill/core/browser/personal_data_manager.cc index 5c9c80c..9298047 100644 --- a/components/autofill/core/browser/personal_data_manager.cc +++ b/components/autofill/core/browser/personal_data_manager.cc @@ -291,7 +291,7 @@ bool PersonalDataManager::ImportFormData( if (group == CREDIT_CARD) { if (LowerCaseEqualsASCII(field->form_control_type, "month")) { - DCHECK_EQ(CREDIT_CARD_EXP_MONTH, server_field_type); + DCHECK_EQ(CREDIT_CARD_EXP_DATE_4_DIGIT_YEAR, server_field_type); local_imported_credit_card->SetInfoForMonthInputType(value); } else { local_imported_credit_card->SetInfo(field_type, value, app_locale_); |