diff options
author | estade@chromium.org <estade@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2012-11-13 08:18:46 +0000 |
---|---|---|
committer | estade@chromium.org <estade@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2012-11-13 08:18:46 +0000 |
commit | 64853b1bdaf54456b93379c38b3324b85402fc84 (patch) | |
tree | 5f813513ea121742c0a92b300592c3dea321572a | |
parent | 0e14413b74298b9baea7aa2f38d42e58ac7f2b5c (diff) | |
download | chromium_src-64853b1bdaf54456b93379c38b3324b85402fc84.zip chromium_src-64853b1bdaf54456b93379c38b3324b85402fc84.tar.gz chromium_src-64853b1bdaf54456b93379c38b3324b85402fc84.tar.bz2 |
Refactor autofill code somewhat.
This pulls form field filling functionality out of AutofillManager and into FormGroup and its subclasses. It also folds the SelectControlHandler file into FormGroup. There should be no functional changes.
Result: better encapsulation, slightly smaller AutofillManager. Code outside of AutofillManager can fill in forms, there are fewer ugly typecasts.
BUG=none
Review URL: https://chromiumcodereview.appspot.com/11360179
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@167326 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r-- | chrome/browser/autofill/autofill_manager.cc | 90 | ||||
-rw-r--r-- | chrome/browser/autofill/autofill_manager.h | 22 | ||||
-rw-r--r-- | chrome/browser/autofill/autofill_profile.cc | 264 | ||||
-rw-r--r-- | chrome/browser/autofill/autofill_profile.h | 81 | ||||
-rw-r--r-- | chrome/browser/autofill/autofill_profile_unittest.cc | 156 | ||||
-rw-r--r-- | chrome/browser/autofill/credit_card.cc | 44 | ||||
-rw-r--r-- | chrome/browser/autofill/credit_card.h | 5 | ||||
-rw-r--r-- | chrome/browser/autofill/credit_card_unittest.cc | 162 | ||||
-rw-r--r-- | chrome/browser/autofill/form_group.cc | 261 | ||||
-rw-r--r-- | chrome/browser/autofill/form_group.h | 16 | ||||
-rw-r--r-- | chrome/browser/autofill/personal_data_manager.cc | 4 | ||||
-rw-r--r-- | chrome/browser/autofill/select_control_handler.cc | 291 | ||||
-rw-r--r-- | chrome/browser/autofill/select_control_handler.h | 31 | ||||
-rw-r--r-- | chrome/browser/autofill/select_control_handler_unittest.cc | 293 | ||||
-rw-r--r-- | chrome/chrome_browser.gypi | 2 | ||||
-rw-r--r-- | chrome/chrome_tests_unit.gypi | 1 |
16 files changed, 840 insertions, 883 deletions
diff --git a/chrome/browser/autofill/autofill_manager.cc b/chrome/browser/autofill/autofill_manager.cc index 5e04f35..be99841 100644 --- a/chrome/browser/autofill/autofill_manager.cc +++ b/chrome/browser/autofill/autofill_manager.cc @@ -38,7 +38,6 @@ #include "chrome/browser/autofill/personal_data_manager_factory.h" #include "chrome/browser/autofill/phone_number.h" #include "chrome/browser/autofill/phone_number_i18n.h" -#include "chrome/browser/autofill/select_control_handler.h" #include "chrome/common/autofill_messages.h" #include "chrome/common/chrome_notification_types.h" #include "chrome/common/chrome_switches.h" @@ -614,11 +613,11 @@ void AutofillManager::OnFillAutofillFormData(int query_id, if (profile) { DCHECK_NE(AutofillType::CREDIT_CARD, AutofillType(field_type).group()); - FillFormField(*profile, *autofill_field, variant, &(*iter)); + profile->FillFormField(*autofill_field, variant, &(*iter)); } else { DCHECK_EQ(AutofillType::CREDIT_CARD, AutofillType(field_type).group()); - FillCreditCardFormField(*credit_card, field_type, &(*iter)); + credit_card->FillFormField(field_type, &(*iter)); } // Mark the cached field as autofilled, so that we can detect when a @@ -654,15 +653,15 @@ void AutofillManager::OnFillAutofillFormData(int query_id, // (b) part of the same logical unit, e.g. name or phone number, // then take the multi-profile "variant" into account. // Otherwise fill with the default (zeroth) variant. + size_t use_variant = 0; if (result.fields[i] == field || field_group_type == initiating_group_type) { - FillFormField(*profile, *cached_field, variant, &result.fields[i]); - } else { - FillFormField(*profile, *cached_field, 0, &result.fields[i]); + use_variant = variant; } + profile->FillFormField(*cached_field, use_variant, &result.fields[i]); } else { DCHECK_EQ(AutofillType::CREDIT_CARD, field_group_type); - FillCreditCardFormField(*credit_card, field_type, &result.fields[i]); + credit_card->FillFormField(field_type, &result.fields[i]); } // Mark the cached field as autofilled, so that we can detect when a user @@ -1250,83 +1249,6 @@ void AutofillManager::GetCreditCardSuggestions( } } -void AutofillManager::FillCreditCardFormField(const CreditCard& credit_card, - AutofillFieldType type, - FormFieldData* field) { - DCHECK_EQ(AutofillType::CREDIT_CARD, AutofillType(type).group()); - DCHECK(field); - - if (field->form_control_type == "select-one") { - autofill::FillSelectControl(credit_card, type, field); - } else if (field->form_control_type == "month") { - // HTML5 input="month" consists of year-month. - string16 year = - credit_card.GetCanonicalizedInfo(CREDIT_CARD_EXP_4_DIGIT_YEAR); - string16 month = credit_card.GetCanonicalizedInfo(CREDIT_CARD_EXP_MONTH); - if (!year.empty() && !month.empty()) { - // Fill the value only if |credit_card| includes both year and month - // information. - field->value = year + ASCIIToUTF16("-") + month; - } - } else { - field->value = credit_card.GetCanonicalizedInfo(type); - } -} - -void AutofillManager::FillFormField(const AutofillProfile& profile, - const AutofillField& cached_field, - size_t variant, - FormFieldData* field) { - AutofillFieldType type = cached_field.type(); - DCHECK_NE(AutofillType::CREDIT_CARD, AutofillType(type).group()); - DCHECK(field); - - if (type == PHONE_HOME_NUMBER) { - FillPhoneNumberField(profile, cached_field, variant, field); - } else { - if (field->form_control_type == "select-one") { - autofill::FillSelectControl(profile, type, field); - } else { - std::vector<string16> values; - profile.GetCanonicalizedMultiInfo(type, &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->value = values[variant]; - } - } -} - -void AutofillManager::FillPhoneNumberField(const AutofillProfile& profile, - const AutofillField& cached_field, - size_t variant, - FormFieldData* field) { - std::vector<string16> values; - profile.GetCanonicalizedMultiInfo(cached_field.type(), &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. - string16 number = values[variant]; - if (number.length() == - (PhoneNumber::kPrefixLength + PhoneNumber::kSuffixLength)) { - if (cached_field.phone_part() == AutofillField::PHONE_PREFIX || - field->max_length == PhoneNumber::kPrefixLength) { - number = number.substr(PhoneNumber::kPrefixOffset, - PhoneNumber::kPrefixLength); - } else if (cached_field.phone_part() == AutofillField::PHONE_SUFFIX || - field->max_length == PhoneNumber::kSuffixLength) { - number = number.substr(PhoneNumber::kSuffixOffset, - PhoneNumber::kSuffixLength); - } - } - - field->value = number; -} - void AutofillManager::ParseForms(const std::vector<FormData>& forms) { std::vector<FormStructure*> non_queryable_forms; for (std::vector<FormData>::const_iterator iter = forms.begin(); diff --git a/chrome/browser/autofill/autofill_manager.h b/chrome/browser/autofill/autofill_manager.h index 9261af2..ba11dbb 100644 --- a/chrome/browser/autofill/autofill_manager.h +++ b/chrome/browser/autofill/autofill_manager.h @@ -288,28 +288,6 @@ class AutofillManager : public content::WebContentsObserver, std::vector<string16>* icons, std::vector<int>* unique_ids) const; - // Set |field|'s value based on |type| and contents of the |credit_card|. - void FillCreditCardFormField(const CreditCard& credit_card, - AutofillFieldType type, - FormFieldData* field); - - // Set |field|'s value based on |cached_field|'s type and contents of the - // |profile|. The |variant| parameter specifies which value in a multi-valued - // profile. - void FillFormField(const AutofillProfile& profile, - const AutofillField& cached_field, - size_t variant, - FormFieldData* field); - - // Set |field|'s value for phone number based on contents of the |profile|. - // The |cached_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 AutofillProfile& profile, - const AutofillField& cached_field, - size_t variant, - FormFieldData* field); - // Parses the forms using heuristic matching and querying the Autofill server. void ParseForms(const std::vector<FormData>& forms); diff --git a/chrome/browser/autofill/autofill_profile.cc b/chrome/browser/autofill/autofill_profile.cc index 54c119a..fd54c4d 100644 --- a/chrome/browser/autofill/autofill_profile.cc +++ b/chrome/browser/autofill/autofill_profile.cc @@ -16,10 +16,13 @@ #include "base/string_util.h" #include "base/utf_string_conversions.h" #include "chrome/browser/autofill/address.h" +#include "chrome/browser/autofill/autofill_country.h" +#include "chrome/browser/autofill/autofill_field.h" #include "chrome/browser/autofill/autofill_type.h" #include "chrome/browser/autofill/contact_info.h" #include "chrome/browser/autofill/phone_number.h" #include "chrome/browser/autofill/phone_number_i18n.h" +#include "chrome/common/form_field_data.h" #include "grit/generated_resources.h" #include "ui/base/l10n/l10n_util.h" @@ -250,12 +253,6 @@ AutofillProfile& AutofillProfile::operator=(const AutofillProfile& profile) { return *this; } -void AutofillProfile::GetSupportedTypes(FieldTypeSet* supported_types) const { - FormGroupList info = FormGroups(); - for (FormGroupList::const_iterator it = info.begin(); it != info.end(); ++it) - (*it)->GetSupportedTypes(supported_types); -} - void AutofillProfile::GetMatchingTypes(const string16& text, FieldTypeSet* matching_types) const { FormGroupList info = FormGroups(); @@ -263,7 +260,6 @@ void AutofillProfile::GetMatchingTypes(const string16& text, (*it)->GetMatchingTypes(text, matching_types); } - string16 AutofillProfile::GetRawInfo(AutofillFieldType type) const { AutofillFieldType return_type = AutofillType::GetEquivalentFieldType(type); const FormGroup* form_group = FormGroupForType(return_type); @@ -338,31 +334,54 @@ void AutofillProfile::GetCanonicalizedMultiInfo( GetMultiInfoImpl(type, true, values); } -void AutofillProfile::GetMultiInfoImpl(AutofillFieldType type, - bool canonicalize, - std::vector<string16>* values) const { - switch (AutofillType(type).group()) { - case AutofillType::NAME: - CopyItemsToValues(type, name_, canonicalize, values); - break; - case AutofillType::EMAIL: - CopyItemsToValues(type, email_, canonicalize, values); - break; - case AutofillType::PHONE: - CopyItemsToValues(type, home_number_, canonicalize, values); - break; - default: - values->resize(1); - (*values)[0] = GetRawInfo(type); +void AutofillProfile::FillFormField(const AutofillField& field, + size_t variant, + FormFieldData* field_data) const { + AutofillFieldType type = field.type(); + DCHECK_NE(AutofillType::CREDIT_CARD, AutofillType(type).group()); + DCHECK(field_data); + + if (type == PHONE_HOME_NUMBER) { + FillPhoneNumberField(field, variant, field_data); + } else if (field_data->form_control_type == "select-one") { + FillSelectControl(type, field_data); + } else { + std::vector<string16> values; + GetCanonicalizedMultiInfo(type, &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]; } } -// static -bool AutofillProfile::SupportsMultiValue(AutofillFieldType type) { - AutofillType::FieldTypeGroup group = AutofillType(type).group(); - return group == AutofillType::NAME || - group == AutofillType::EMAIL || - group == AutofillType::PHONE; +void AutofillProfile::FillPhoneNumberField(const AutofillField& field, + size_t variant, + FormFieldData* field_data) const { + std::vector<string16> values; + GetCanonicalizedMultiInfo(field.type(), &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. + 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 string16 AutofillProfile::Label() const { @@ -377,69 +396,6 @@ void AutofillProfile::SetCountryCode(const std::string& country_code) { address_.set_country_code(country_code); } -// static -bool AutofillProfile::AdjustInferredLabels( - std::vector<AutofillProfile*>* profiles) { - const size_t kMinimalFieldsShown = 2; - - std::vector<string16> created_labels; - CreateInferredLabels(profiles, NULL, UNKNOWN_TYPE, kMinimalFieldsShown, - &created_labels); - DCHECK_EQ(profiles->size(), created_labels.size()); - - bool updated_labels = false; - for (size_t i = 0; i < profiles->size(); ++i) { - if ((*profiles)[i]->Label() != created_labels[i]) { - updated_labels = true; - (*profiles)[i]->label_ = created_labels[i]; - } - } - return updated_labels; -} - -// static -void AutofillProfile::CreateInferredLabels( - const std::vector<AutofillProfile*>* profiles, - const std::vector<AutofillFieldType>* suggested_fields, - AutofillFieldType excluded_field, - size_t minimal_fields_shown, - std::vector<string16>* created_labels) { - DCHECK(profiles); - DCHECK(created_labels); - - std::vector<AutofillFieldType> fields_to_use; - GetFieldsForDistinguishingProfiles(suggested_fields, excluded_field, - &fields_to_use); - - // Construct the default label for each profile. Also construct a map that - // associates each label with the profiles that have this label. This map is - // then used to detect which labels need further differentiating fields. - std::map<string16, std::list<size_t> > labels; - for (size_t i = 0; i < profiles->size(); ++i) { - string16 label = - (*profiles)[i]->ConstructInferredLabel(fields_to_use, - minimal_fields_shown); - labels[label].push_back(i); - } - - created_labels->resize(profiles->size()); - for (std::map<string16, std::list<size_t> >::const_iterator it = - labels.begin(); - it != labels.end(); ++it) { - if (it->second.size() == 1) { - // This label is unique, so use it without any further ado. - string16 label = it->first; - size_t profile_index = it->second.front(); - (*created_labels)[profile_index] = label; - } else { - // We have more than one profile with the same label, so add - // differentiating fields. - CreateDifferentiatingLabels(*profiles, it->second, fields_to_use, - minimal_fields_shown, created_labels); - } - } -} - bool AutofillProfile::IsEmpty() const { FieldTypeSet types; GetNonEmptyTypes(&types); @@ -496,8 +452,7 @@ bool AutofillProfile::operator!=(const AutofillProfile& profile) const { } const string16 AutofillProfile::PrimaryValue() const { - return GetRawInfo(ADDRESS_HOME_LINE1) + - GetRawInfo(ADDRESS_HOME_CITY); + return GetRawInfo(ADDRESS_HOME_LINE1) + GetRawInfo(ADDRESS_HOME_CITY); } bool AutofillProfile::IsSubsetOf(const AutofillProfile& profile) const { @@ -576,6 +531,124 @@ void AutofillProfile::OverwriteWithOrAddTo(const AutofillProfile& profile) { } } +// static +bool AutofillProfile::SupportsMultiValue(AutofillFieldType type) { + AutofillType::FieldTypeGroup group = AutofillType(type).group(); + return group == AutofillType::NAME || + group == AutofillType::EMAIL || + group == AutofillType::PHONE; +} + +// static +bool AutofillProfile::AdjustInferredLabels( + std::vector<AutofillProfile*>* profiles) { + const size_t kMinimalFieldsShown = 2; + + std::vector<string16> created_labels; + CreateInferredLabels(profiles, NULL, UNKNOWN_TYPE, kMinimalFieldsShown, + &created_labels); + DCHECK_EQ(profiles->size(), created_labels.size()); + + bool updated_labels = false; + for (size_t i = 0; i < profiles->size(); ++i) { + if ((*profiles)[i]->Label() != created_labels[i]) { + updated_labels = true; + (*profiles)[i]->label_ = created_labels[i]; + } + } + return updated_labels; +} + +// static +void AutofillProfile::CreateInferredLabels( + const std::vector<AutofillProfile*>* profiles, + const std::vector<AutofillFieldType>* suggested_fields, + AutofillFieldType excluded_field, + size_t minimal_fields_shown, + std::vector<string16>* created_labels) { + DCHECK(profiles); + DCHECK(created_labels); + + std::vector<AutofillFieldType> fields_to_use; + GetFieldsForDistinguishingProfiles(suggested_fields, excluded_field, + &fields_to_use); + + // Construct the default label for each profile. Also construct a map that + // associates each label with the profiles that have this label. This map is + // then used to detect which labels need further differentiating fields. + std::map<string16, std::list<size_t> > labels; + for (size_t i = 0; i < profiles->size(); ++i) { + string16 label = + (*profiles)[i]->ConstructInferredLabel(fields_to_use, + minimal_fields_shown); + labels[label].push_back(i); + } + + created_labels->resize(profiles->size()); + for (std::map<string16, std::list<size_t> >::const_iterator it = + labels.begin(); + it != labels.end(); ++it) { + if (it->second.size() == 1) { + // This label is unique, so use it without any further ado. + string16 label = it->first; + size_t profile_index = it->second.front(); + (*created_labels)[profile_index] = label; + } else { + // We have more than one profile with the same label, so add + // differentiating fields. + CreateDifferentiatingLabels(*profiles, it->second, fields_to_use, + minimal_fields_shown, created_labels); + } + } +} + +void AutofillProfile::GetSupportedTypes(FieldTypeSet* supported_types) const { + FormGroupList info = FormGroups(); + for (FormGroupList::const_iterator it = info.begin(); it != info.end(); ++it) + (*it)->GetSupportedTypes(supported_types); +} + +bool AutofillProfile::FillCountrySelectControl(FormFieldData* field_data) + const { + std::string country_code = CountryCode(); + std::string app_locale = AutofillCountry::ApplicationLocale(); + + 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. + string16 value = field_data->option_values[i]; + 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(AutofillFieldType type, + bool canonicalize, + std::vector<string16>* values) const { + switch (AutofillType(type).group()) { + case AutofillType::NAME: + CopyItemsToValues(type, name_, canonicalize, values); + break; + case AutofillType::EMAIL: + CopyItemsToValues(type, email_, canonicalize, values); + break; + case AutofillType::PHONE: + CopyItemsToValues(type, home_number_, canonicalize, values); + break; + default: + values->resize(1); + (*values)[0] = GetRawInfo(type); + } +} + void AutofillProfile::AddPhoneIfUnique(const string16& phone, std::vector<string16>* existing_phones) { DCHECK(existing_phones); @@ -706,7 +779,7 @@ const FormGroup* AutofillProfile::FormGroupForType( } FormGroup* AutofillProfile::MutableFormGroupForType(AutofillFieldType type) { - FormGroup* form_group = NULL; + FormGroup* form_group = NULL; switch (AutofillType(type).group()) { case AutofillType::NAME: form_group = &name_[0]; @@ -726,6 +799,7 @@ FormGroup* AutofillProfile::MutableFormGroupForType(AutofillFieldType type) { default: break; } + return form_group; } diff --git a/chrome/browser/autofill/autofill_profile.h b/chrome/browser/autofill/autofill_profile.h index 82d40f0..927a3c6 100644 --- a/chrome/browser/autofill/autofill_profile.h +++ b/chrome/browser/autofill/autofill_profile.h @@ -20,6 +20,9 @@ #include "chrome/browser/autofill/form_group.h" #include "chrome/browser/autofill/phone_number.h" +class AutofillField; +struct FormFieldData; + // A collection of FormGroups stored in a profile. AutofillProfile also // implements the FormGroup interface so that owners of this object can request // form information from the profile, and the profile will delegate the request @@ -53,8 +56,20 @@ class AutofillProfile : public FormGroup { void GetCanonicalizedMultiInfo(AutofillFieldType type, std::vector<string16>* values) const; - // Returns |true| if |type| accepts multi-values. - static bool SupportsMultiValue(AutofillFieldType type); + // Set |field_data|'s value based on |field|'s type and contents of the + // |this|. The |variant| parameter specifies which value to use from a + // multi-valued profile. + void FillFormField(const AutofillField& field, + size_t variant, + FormFieldData* field_data) 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, + 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 @@ -69,34 +84,6 @@ class AutofillProfile : public FormGroup { const std::string CountryCode() const; void SetCountryCode(const std::string& country_code); - // Adjusts the labels according to profile data. - // Labels contain minimal different combination of: - // 1. Full name. - // 2. Address. - // 3. E-mail. - // 4. Phone. - // 5. Company name. - // Profile labels are changed accordingly to these rules. - // Returns true if any of the profiles were updated. - // This function is useful if you want to adjust unique labels for all - // profiles. For non permanent situations (selection of profile, when user - // started typing in the field, for example) use CreateInferredLabels(). - static bool AdjustInferredLabels(std::vector<AutofillProfile*>* profiles); - - // Creates inferred labels for |profiles|, according to the rules above and - // stores them in |created_labels|. If |suggested_fields| is not NULL, the - // resulting label fields are drawn from |suggested_fields|, except excluding - // |excluded_field|. Otherwise, the label fields are drawn from a default set, - // and |excluded_field| is ignored; by convention, it should be of - // |UNKNOWN_TYPE| when |suggested_fields| is NULL. Each label includes at - // least |minimal_fields_shown| fields, if possible. - static void CreateInferredLabels( - const std::vector<AutofillProfile*>* profiles, - const std::vector<AutofillFieldType>* suggested_fields, - AutofillFieldType excluded_field, - size_t minimal_fields_shown, - std::vector<string16>* created_labels); - // Returns true if there are no values (field types) set. bool IsEmpty() const; @@ -125,10 +112,42 @@ class AutofillProfile : public FormGroup { // Profile. Or, for multi-valued fields append the new values. void OverwriteWithOrAddTo(const AutofillProfile& profile); + // Returns |true| if |type| accepts multi-values. + static bool SupportsMultiValue(AutofillFieldType type); + + // Adjusts the labels according to profile data. + // Labels contain minimal different combination of: + // 1. Full name. + // 2. Address. + // 3. E-mail. + // 4. Phone. + // 5. Company name. + // Profile labels are changed accordingly to these rules. + // Returns true if any of the profiles were updated. + // This function is useful if you want to adjust unique labels for all + // profiles. For non permanent situations (selection of profile, when user + // started typing in the field, for example) use CreateInferredLabels(). + static bool AdjustInferredLabels(std::vector<AutofillProfile*>* profiles); + + // Creates inferred labels for |profiles|, according to the rules above and + // stores them in |created_labels|. If |suggested_fields| is not NULL, the + // resulting label fields are drawn from |suggested_fields|, except excluding + // |excluded_field|. Otherwise, the label fields are drawn from a default set, + // and |excluded_field| is ignored; by convention, it should be of + // |UNKNOWN_TYPE| when |suggested_fields| is NULL. Each label includes at + // least |minimal_fields_shown| fields, if possible. + static void CreateInferredLabels( + const std::vector<AutofillProfile*>* profiles, + const std::vector<AutofillFieldType>* suggested_fields, + AutofillFieldType excluded_field, + size_t minimal_fields_shown, + std::vector<string16>* created_labels); + private: typedef std::vector<const FormGroup*> FormGroupList; - // FormGroup implementation. + // FormGroup: + virtual bool FillCountrySelectControl(FormFieldData* field) const OVERRIDE; virtual void GetSupportedTypes(FieldTypeSet* supported_types) const OVERRIDE; // Shared implementation for GetMultiInfo() and GetCanonicalizedMultiInfo(). diff --git a/chrome/browser/autofill/autofill_profile_unittest.cc b/chrome/browser/autofill/autofill_profile_unittest.cc index 51ed9ee..26f4de4 100644 --- a/chrome/browser/autofill/autofill_profile_unittest.cc +++ b/chrome/browser/autofill/autofill_profile_unittest.cc @@ -8,9 +8,11 @@ #include "base/memory/scoped_vector.h" #include "base/stl_util.h" #include "base/string16.h" +#include "base/stringprintf.h" #include "base/utf_string_conversions.h" #include "chrome/browser/autofill/autofill_common_test.h" #include "chrome/browser/autofill/autofill_profile.h" +#include "chrome/common/form_field_data.h" #include "grit/generated_resources.h" #include "testing/gtest/include/gtest/gtest.h" @@ -24,11 +26,9 @@ bool UpdateProfileLabel(AutofillProfile *profile) { } // namespace -typedef testing::Test AutofillProfileTest; - // Tests different possibilities for summary string generation. // Based on existence of first name, last name, and address line 1. -TEST_F(AutofillProfileTest, PreviewSummaryString) { +TEST(AutofillProfileTest, PreviewSummaryString) { // Case 0/null: "" AutofillProfile profile0; // Empty profile - nothing to update. @@ -139,7 +139,7 @@ TEST_F(AutofillProfileTest, PreviewSummaryString) { "Marion Mitchell Morrison, 123 Zoo St., marion@me.xyz"), summary7a); } -TEST_F(AutofillProfileTest, AdjustInferredLabels) { +TEST(AutofillProfileTest, AdjustInferredLabels) { std::vector<AutofillProfile*> profiles; profiles.push_back(new AutofillProfile); autofill_test::SetProfileInfo( @@ -296,7 +296,7 @@ TEST_F(AutofillProfileTest, AdjustInferredLabels) { STLDeleteContainerPointers(profiles.begin(), profiles.end()); } -TEST_F(AutofillProfileTest, CreateInferredLabels) { +TEST(AutofillProfileTest, CreateInferredLabels) { std::vector<AutofillProfile*> profiles; profiles.push_back(new AutofillProfile); autofill_test::SetProfileInfo(profiles[0], @@ -405,7 +405,7 @@ TEST_F(AutofillProfileTest, CreateInferredLabels) { // Test that we fall back to using the full name if there are no other // distinguishing fields, but only if it makes sense given the suggested fields. -TEST_F(AutofillProfileTest, CreateInferredLabelsFallsBackToFullName) { +TEST(AutofillProfileTest, CreateInferredLabelsFallsBackToFullName) { ScopedVector<AutofillProfile> profiles; profiles.push_back(new AutofillProfile); autofill_test::SetProfileInfo(profiles[0], @@ -439,7 +439,7 @@ TEST_F(AutofillProfileTest, CreateInferredLabelsFallsBackToFullName) { } // Test that we do not show duplicate fields in the labels. -TEST_F(AutofillProfileTest, CreateInferredLabelsNoDuplicatedFields) { +TEST(AutofillProfileTest, CreateInferredLabelsNoDuplicatedFields) { ScopedVector<AutofillProfile> profiles; profiles.push_back(new AutofillProfile); autofill_test::SetProfileInfo(profiles[0], @@ -465,7 +465,7 @@ TEST_F(AutofillProfileTest, CreateInferredLabelsNoDuplicatedFields) { } // Make sure that empty fields are not treated as distinguishing fields. -TEST_F(AutofillProfileTest, CreateInferredLabelsSkipsEmptyFields) { +TEST(AutofillProfileTest, CreateInferredLabelsSkipsEmptyFields) { ScopedVector<AutofillProfile> profiles; profiles.push_back(new AutofillProfile); autofill_test::SetProfileInfo(profiles[0], @@ -500,7 +500,7 @@ TEST_F(AutofillProfileTest, CreateInferredLabelsSkipsEmptyFields) { EXPECT_EQ(ASCIIToUTF16("John Doe, john.doe@example.com"), labels[2]); } -TEST_F(AutofillProfileTest, IsSubsetOf) { +TEST(AutofillProfileTest, IsSubsetOf) { scoped_ptr<AutofillProfile> a, b; // |a| is a subset of |b|. @@ -532,7 +532,7 @@ TEST_F(AutofillProfileTest, IsSubsetOf) { EXPECT_FALSE(a->IsSubsetOf(*b)); } -TEST_F(AutofillProfileTest, AssignmentOperator){ +TEST(AutofillProfileTest, AssignmentOperator) { AutofillProfile a, b; // Result of assignment should be logically equal to the original profile. @@ -548,7 +548,7 @@ TEST_F(AutofillProfileTest, AssignmentOperator){ EXPECT_TRUE(a == b); } -TEST_F(AutofillProfileTest, Copy) { +TEST(AutofillProfileTest, Copy) { AutofillProfile a; // Clone should be logically equal to the original. @@ -560,7 +560,7 @@ TEST_F(AutofillProfileTest, Copy) { EXPECT_TRUE(a == b); } -TEST_F(AutofillProfileTest, Compare) { +TEST(AutofillProfileTest, Compare) { AutofillProfile a, b; // Empty profiles are the same. @@ -580,7 +580,7 @@ TEST_F(AutofillProfileTest, Compare) { EXPECT_LT(0, b.Compare(a)); } -TEST_F(AutofillProfileTest, CountryCode) { +TEST(AutofillProfileTest, CountryCode) { AutofillProfile profile; EXPECT_EQ(std::string(), profile.CountryCode()); @@ -588,7 +588,7 @@ TEST_F(AutofillProfileTest, CountryCode) { EXPECT_EQ("US", profile.CountryCode()); } -TEST_F(AutofillProfileTest, MultiValueNames) { +TEST(AutofillProfileTest, MultiValueNames) { AutofillProfile p; const string16 kJohnDoe(ASCIIToUTF16("John Doe")); const string16 kJohnPDoe(ASCIIToUTF16("John P. Doe")); @@ -630,7 +630,7 @@ TEST_F(AutofillProfileTest, MultiValueNames) { EXPECT_EQ(string16(), p.GetRawInfo(NAME_FULL)); } -TEST_F(AutofillProfileTest, MultiValueEmails) { +TEST(AutofillProfileTest, MultiValueEmails) { AutofillProfile p; const string16 kJohnDoe(ASCIIToUTF16("john@doe.com")); const string16 kJohnPDoe(ASCIIToUTF16("john_p@doe.com")); @@ -672,7 +672,7 @@ TEST_F(AutofillProfileTest, MultiValueEmails) { EXPECT_EQ(string16(), p.GetRawInfo(EMAIL_ADDRESS)); } -TEST_F(AutofillProfileTest, MultiValuePhone) { +TEST(AutofillProfileTest, MultiValuePhone) { AutofillProfile p; const string16 kJohnDoe(ASCIIToUTF16("4151112222")); const string16 kJohnPDoe(ASCIIToUTF16("4151113333")); @@ -713,3 +713,127 @@ TEST_F(AutofillProfileTest, MultiValuePhone) { // Expect regular |GetInfo| returns empty value. EXPECT_EQ(string16(), p.GetRawInfo(PHONE_HOME_WHOLE_NUMBER)); } + +TEST(AutofillProfileTest, AddressCountryFull) { + const char* const kCountries[] = { + "Albania", "Canada" + }; + std::vector<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; + profile.SetRawInfo(ADDRESS_HOME_COUNTRY, ASCIIToUTF16("CA")); + profile.FillSelectControl(ADDRESS_HOME_COUNTRY, &field); + EXPECT_EQ(ASCIIToUTF16("Canada"), field.value); +} + +TEST(AutofillProfileTest, AddressCountryAbbrev) { + const char* const kCountries[] = { + "AL", "CA" + }; + std::vector<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; + profile.SetRawInfo(ADDRESS_HOME_COUNTRY, ASCIIToUTF16("Canada")); + profile.FillSelectControl(ADDRESS_HOME_COUNTRY, &field); + EXPECT_EQ(ASCIIToUTF16("CA"), field.value); +} + +TEST(AutofillProfileTest, AddressStateFull) { + const char* const kStates[] = { + "Alabama", "California" + }; + std::vector<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; + profile.SetRawInfo(ADDRESS_HOME_STATE, ASCIIToUTF16("CA")); + profile.FillSelectControl(ADDRESS_HOME_STATE, &field); + EXPECT_EQ(ASCIIToUTF16("California"), field.value); +} + +TEST(AutofillProfileTest, AddressStateAbbrev) { + const char* const kStates[] = { + "AL", "CA" + }; + std::vector<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; + profile.SetRawInfo(ADDRESS_HOME_STATE, ASCIIToUTF16("California")); + profile.FillSelectControl(ADDRESS_HOME_STATE, &field); + EXPECT_EQ(ASCIIToUTF16("CA"), field.value); +} + +TEST(AutofillProfileTest, FillByValue) { + const char* const kStates[] = { + "Alabama", "California" + }; + std::vector<string16> values(arraysize(kStates)); + std::vector<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; + profile.SetRawInfo(ADDRESS_HOME_STATE, ASCIIToUTF16("California")); + profile.FillSelectControl(ADDRESS_HOME_STATE, &field); + EXPECT_EQ(ASCIIToUTF16("California"), field.value); +} + +TEST(AutofillProfileTest, FillByContents) { + const char* const kStates[] = { + "Alabama", "California" + }; + std::vector<string16> values(arraysize(kStates)); + std::vector<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; + profile.SetRawInfo(ADDRESS_HOME_STATE, ASCIIToUTF16("California")); + profile.FillSelectControl(ADDRESS_HOME_STATE, &field); + EXPECT_EQ(ASCIIToUTF16("2"), field.value); +} diff --git a/chrome/browser/autofill/credit_card.cc b/chrome/browser/autofill/credit_card.cc index 2dfb47e..924bfc2 100644 --- a/chrome/browser/autofill/credit_card.cc +++ b/chrome/browser/autofill/credit_card.cc @@ -21,6 +21,7 @@ #include "chrome/browser/autofill/autofill_regexes.h" #include "chrome/browser/autofill/autofill_type.h" #include "chrome/browser/autofill/field_types.h" +#include "chrome/common/form_field_data.h" #include "grit/generated_resources.h" #include "ui/base/l10n/l10n_util.h" #include "unicode/dtfmtsym.h" @@ -232,17 +233,6 @@ CreditCard::CreditCard(const CreditCard& credit_card) : FormGroup() { CreditCard::~CreditCard() {} -void CreditCard::GetSupportedTypes(FieldTypeSet* supported_types) const { - supported_types->insert(CREDIT_CARD_NAME); - supported_types->insert(CREDIT_CARD_NUMBER); - supported_types->insert(CREDIT_CARD_TYPE); - supported_types->insert(CREDIT_CARD_EXP_MONTH); - supported_types->insert(CREDIT_CARD_EXP_2_DIGIT_YEAR); - supported_types->insert(CREDIT_CARD_EXP_4_DIGIT_YEAR); - supported_types->insert(CREDIT_CARD_EXP_DATE_2_DIGIT_YEAR); - supported_types->insert(CREDIT_CARD_EXP_DATE_4_DIGIT_YEAR); -} - string16 CreditCard::GetRawInfo(AutofillFieldType type) const { switch (type) { case CREDIT_CARD_NAME: @@ -458,6 +448,27 @@ bool CreditCard::UpdateFromImportedCard(const CreditCard& imported_card) { return true; } +void CreditCard::FillFormField(AutofillFieldType type, + FormFieldData* field) const { + DCHECK_EQ(AutofillType::CREDIT_CARD, AutofillType(type).group()); + DCHECK(field); + + if (field->form_control_type == "select-one") { + FillSelectControl(type, field); + } else if (field->form_control_type == "month") { + // HTML5 input="month" consists of year-month. + string16 year = GetCanonicalizedInfo(CREDIT_CARD_EXP_4_DIGIT_YEAR); + string16 month = GetCanonicalizedInfo(CREDIT_CARD_EXP_MONTH); + if (!year.empty() && !month.empty()) { + // Fill the value only if |this| includes both year and month + // information. + field->value = year + ASCIIToUTF16("-") + month; + } + } else { + field->value = GetCanonicalizedInfo(type); + } +} + 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 @@ -536,6 +547,17 @@ bool CreditCard::IsComplete() const { expiration_year_ != 0; } +void CreditCard::GetSupportedTypes(FieldTypeSet* supported_types) const { + supported_types->insert(CREDIT_CARD_NAME); + supported_types->insert(CREDIT_CARD_NUMBER); + supported_types->insert(CREDIT_CARD_TYPE); + supported_types->insert(CREDIT_CARD_EXP_MONTH); + supported_types->insert(CREDIT_CARD_EXP_2_DIGIT_YEAR); + supported_types->insert(CREDIT_CARD_EXP_4_DIGIT_YEAR); + supported_types->insert(CREDIT_CARD_EXP_DATE_2_DIGIT_YEAR); + supported_types->insert(CREDIT_CARD_EXP_DATE_4_DIGIT_YEAR); +} + string16 CreditCard::ExpirationMonthAsString() const { if (expiration_month_ == 0) return string16(); diff --git a/chrome/browser/autofill/credit_card.h b/chrome/browser/autofill/credit_card.h index 7514a8e..256a511 100644 --- a/chrome/browser/autofill/credit_card.h +++ b/chrome/browser/autofill/credit_card.h @@ -13,6 +13,8 @@ #include "chrome/browser/autofill/field_types.h" #include "chrome/browser/autofill/form_group.h" +struct FormFieldData; + // A form group that stores credit card information. class CreditCard : public FormGroup { public: @@ -59,6 +61,9 @@ class CreditCard : public FormGroup { bool UpdateFromImportedCard(const CreditCard& imported_card) WARN_UNUSED_RESULT; + // Set |field|'s value based on |type| and contents of |this|. + void FillFormField(AutofillFieldType type, FormFieldData* field) const; + // Comparison for Sync. Returns 0 if the credit card is the same as |this|, // or < 0, or > 0 if it is different. The implied ordering can be used for // culling duplicates. The ordering is based on collation order of the diff --git a/chrome/browser/autofill/credit_card_unittest.cc b/chrome/browser/autofill/credit_card_unittest.cc index 28d2bab..62e1f72 100644 --- a/chrome/browser/autofill/credit_card_unittest.cc +++ b/chrome/browser/autofill/credit_card_unittest.cc @@ -6,6 +6,7 @@ #include "base/utf_string_conversions.h" #include "chrome/browser/autofill/autofill_common_test.h" #include "chrome/browser/autofill/credit_card.h" +#include "chrome/common/form_field_data.h" #include "testing/gtest/include/gtest/gtest.h" namespace { @@ -153,7 +154,7 @@ TEST(CreditCardTest, InvalidMastercardNumber) { } // Verify that we preserve exactly what the user typed for credit card numbers. -TEST(CreditCardTest, SetInfoCreditCardNumber) { +TEST(CreditCardTest, SetRawInfoCreditCardNumber) { CreditCard card; autofill_test::SetCreditCardInfo(&card, "Bob Dylan", @@ -163,7 +164,7 @@ TEST(CreditCardTest, SetInfoCreditCardNumber) { } // Verify that we can handle both numeric and named months. -TEST(CreditCardTest, SetInfoExpirationMonth) { +TEST(CreditCardTest, SetRawInfoExpirationMonth) { CreditCard card; card.SetRawInfo(CREDIT_CARD_EXP_MONTH, ASCIIToUTF16("05")); @@ -198,3 +199,160 @@ TEST(CreditCardTest, CreditCardVerificationCode) { card.SetRawInfo(CREDIT_CARD_VERIFICATION_CODE, ASCIIToUTF16("999")); EXPECT_EQ(string16(), card.GetRawInfo(CREDIT_CARD_VERIFICATION_CODE)); } + + +TEST(CreditCardTest, CreditCardMonthExact) { + const char* const kMonthsNumeric[] = { + "01", "02", "03", "04", "05", "06", "07", "08", "09", "10", "11", "12", + }; + std::vector<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; + credit_card.SetRawInfo(CREDIT_CARD_EXP_MONTH, ASCIIToUTF16("01")); + credit_card.FillSelectControl(CREDIT_CARD_EXP_MONTH, &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<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; + credit_card.SetRawInfo(CREDIT_CARD_EXP_MONTH, ASCIIToUTF16("01")); + credit_card.FillSelectControl(CREDIT_CARD_EXP_MONTH, &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<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; + credit_card.SetRawInfo(CREDIT_CARD_EXP_MONTH, ASCIIToUTF16("01")); + credit_card.FillSelectControl(CREDIT_CARD_EXP_MONTH, &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<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; + credit_card.SetRawInfo(CREDIT_CARD_EXP_MONTH, ASCIIToUTF16("01")); + credit_card.FillSelectControl(CREDIT_CARD_EXP_MONTH, &field); + EXPECT_EQ(ASCIIToUTF16("1"), field.value); +} + +TEST(CreditCardTest, CreditCardTwoDigitYear) { + const char* const kYears[] = { + "12", "13", "14", "15", "16", "17", "18", "19" + }; + std::vector<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; + credit_card.SetRawInfo(CREDIT_CARD_EXP_4_DIGIT_YEAR, ASCIIToUTF16("2017")); + credit_card.FillSelectControl(CREDIT_CARD_EXP_4_DIGIT_YEAR, &field); + EXPECT_EQ(ASCIIToUTF16("17"), field.value); +} + +TEST(CreditCardTest, CreditCardTypeSelectControl) { + const char* const kCreditCardTypes[] = { + "Visa", "Master Card", "AmEx", "discover" + }; + std::vector<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; + credit_card.SetRawInfo(CREDIT_CARD_NUMBER, + ASCIIToUTF16("4111111111111111")); + credit_card.FillSelectControl(CREDIT_CARD_TYPE, &field); + EXPECT_EQ(ASCIIToUTF16("Visa"), field.value); + } + + { + // Filling should be able to handle intervening whitespace: + CreditCard credit_card; + credit_card.SetRawInfo(CREDIT_CARD_NUMBER, + ASCIIToUTF16("5105105105105100")); + credit_card.FillSelectControl(CREDIT_CARD_TYPE, &field); + EXPECT_EQ(ASCIIToUTF16("Master Card"), field.value); + } + + { + // American Express is sometimes abbreviated as AmEx: + CreditCard credit_card; + credit_card.SetRawInfo(CREDIT_CARD_NUMBER, ASCIIToUTF16("371449635398431")); + credit_card.FillSelectControl(CREDIT_CARD_TYPE, &field); + EXPECT_EQ(ASCIIToUTF16("AmEx"), field.value); + } + + { + // Case insensitivity: + CreditCard credit_card; + credit_card.SetRawInfo(CREDIT_CARD_NUMBER, + ASCIIToUTF16("6011111111111117")); + credit_card.FillSelectControl(CREDIT_CARD_TYPE, &field); + EXPECT_EQ(ASCIIToUTF16("discover"), field.value); + } +} diff --git a/chrome/browser/autofill/form_group.cc b/chrome/browser/autofill/form_group.cc index fcc8e95..49ebb88 100644 --- a/chrome/browser/autofill/form_group.cc +++ b/chrome/browser/autofill/form_group.cc @@ -2,12 +2,211 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include <algorithm> - #include "chrome/browser/autofill/form_group.h" +#include <algorithm> #include <iterator> +#include "base/basictypes.h" +#include "base/logging.h" +#include "base/string_number_conversions.h" +#include "base/utf_string_conversions.h" +#include "chrome/common/form_field_data.h" +#include "grit/generated_resources.h" +#include "ui/base/l10n/l10n_util.h" + +namespace { + +// TODO(jhawkins): Add more states/provinces. See http://crbug.com/45039. + +class State { + public: + const char* name; + const char* abbreviation; + + static const State all_states[]; + + static string16 Abbreviation(const string16& name); + static string16 FullName(const string16& abbreviation); +}; + +const State State::all_states[] = { + { "alabama", "al" }, + { "alaska", "ak" }, + { "arizona", "az" }, + { "arkansas", "ar" }, + { "california", "ca" }, + { "colorado", "co" }, + { "connecticut", "ct" }, + { "delaware", "de" }, + { "district of columbia", "dc" }, + { "florida", "fl" }, + { "georgia", "ga" }, + { "hawaii", "hi" }, + { "idaho", "id" }, + { "illinois", "il" }, + { "indiana", "in" }, + { "iowa", "ia" }, + { "kansas", "ks" }, + { "kentucky", "ky" }, + { "louisiana", "la" }, + { "maine", "me" }, + { "maryland", "md" }, + { "massachusetts", "ma" }, + { "michigan", "mi" }, + { "minnesota", "mv" }, + { "mississippi", "ms" }, + { "missouri", "mo" }, + { "montana", "mt" }, + { "nebraska", "ne" }, + { "nevada", "nv" }, + { "new hampshire", "nh" }, + { "new jersey", "nj" }, + { "new mexico", "nm" }, + { "new york", "ny" }, + { "north carolina", "nc" }, + { "north dakota", "nd" }, + { "ohio", "oh" }, + { "oklahoma", "ok" }, + { "oregon", "or" }, + { "pennsylvania", "pa" }, + { "puerto rico", "pr" }, + { "rhode island", "ri" }, + { "south carolina", "sc" }, + { "south dakota", "sd" }, + { "tennessee", "tn" }, + { "texas", "tx" }, + { "utah", "ut" }, + { "vermont", "vt" }, + { "virginia", "va" }, + { "washington", "wa" }, + { "west virginia", "wv" }, + { "wisconsin", "wi" }, + { "wyoming", "wy" }, + { NULL, NULL } +}; + +string16 State::Abbreviation(const string16& name) { + for (const State* state = all_states; state->name; ++state) { + if (LowerCaseEqualsASCII(name, state->name)) + return ASCIIToUTF16(state->abbreviation); + } + return string16(); +} + +string16 State::FullName(const string16& abbreviation) { + for (const State* state = all_states; state->name; ++state) { + if (LowerCaseEqualsASCII(abbreviation, state->abbreviation)) + return ASCIIToUTF16(state->name); + } + return string16(); +} + +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 string16& value, + FormFieldData* field) { + 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 string16& value, + FormFieldData* field) { + string16 abbrev, full; + if (value.size() < 4U) { + abbrev = value; + full = State::FullName(value); + } else { + abbrev = State::Abbreviation(value); + full = value; + } + + // Try the abbreviation name first. + if (!abbrev.empty() && SetSelectControlValue(abbrev, field)) + return true; + + if (full.empty()) + return false; + + return SetSelectControlValue(full, field); +} + +bool FillExpirationMonthSelectControl(const 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 string16& value, + FormFieldData* field) { + // Try stripping off spaces. + string16 value_stripped; + RemoveChars(StringToLowerASCII(value), kWhitespaceUTF16, &value_stripped); + + for (size_t i = 0; i < field->option_values.size(); ++i) { + string16 option_value_lowercase; + RemoveChars(StringToLowerASCII(field->option_values[i]), kWhitespaceUTF16, + &option_value_lowercase); + 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 + void FormGroup::GetMatchingTypes(const string16& text, FieldTypeSet* matching_types) const { if (text.empty()) { @@ -46,3 +245,61 @@ bool FormGroup::SetCanonicalizedInfo(AutofillFieldType type, SetRawInfo(type, value); return true; } + +void FormGroup::FillSelectControl(AutofillFieldType type, + FormFieldData* field) const { + DCHECK(field); + DCHECK_EQ("select-one", field->form_control_type); + DCHECK_EQ(field->option_values.size(), field->option_contents.size()); + + string16 field_text = GetCanonicalizedInfo(type); + string16 field_text_lower = StringToLowerASCII(field_text); + if (field_text.empty()) + return; + + 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; + } + + if (type == ADDRESS_HOME_STATE || type == ADDRESS_BILLING_STATE) { + FillStateSelectControl(field_text, field); + } else if (type == ADDRESS_HOME_COUNTRY || type == ADDRESS_BILLING_COUNTRY) { + FillCountrySelectControl(field); + } else if (type == CREDIT_CARD_EXP_MONTH) { + FillExpirationMonthSelectControl(field_text, field); + } else if (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(CREDIT_CARD_EXP_2_DIGIT_YEAR, field); + } else if (type == CREDIT_CARD_TYPE) { + FillCreditCardTypeSelectControl(field_text, field); + } +} + +bool FormGroup::FillCountrySelectControl(FormFieldData* field_data) const { + return false; +} + +// static +bool FormGroup::IsValidState(const string16& value) { + return !State::Abbreviation(value).empty() || !State::FullName(value).empty(); +} diff --git a/chrome/browser/autofill/form_group.h b/chrome/browser/autofill/form_group.h index b250773..e84cff2 100644 --- a/chrome/browser/autofill/form_group.h +++ b/chrome/browser/autofill/form_group.h @@ -11,6 +11,8 @@ #include "base/string_util.h" #include "chrome/browser/autofill/field_types.h" +struct FormFieldData; + // This class is an interface for collections of form fields, grouped by type. // The information in objects of this class is managed by the // PersonalDataManager. @@ -47,6 +49,16 @@ class FormGroup { virtual bool SetCanonicalizedInfo(AutofillFieldType type, const string16& value); + // Fills in select control with data matching |type| from |this|. + // Public for testing purposes. + void FillSelectControl(AutofillFieldType type, + FormFieldData* field_data) const; + + // Returns true if |value| is a valid US state name or abbreviation. It is + // case insensitive. Valid for US states only. + // TODO(estade): this is a crappy place for this function. + static bool IsValidState(const string16& value); + protected: // AutofillProfile needs to call into GetSupportedTypes() for objects of // non-AutofillProfile type, for which mere inheritance is insufficient. @@ -55,6 +67,10 @@ class FormGroup { // Returns a set of AutofillFieldTypes for which this FormGroup can store // data. This method is additive on |supported_types|. virtual void GetSupportedTypes(FieldTypeSet* supported_types) const = 0; + + // Fills in a select control for a country from data in |this|. Returns true + // for success. + virtual bool FillCountrySelectControl(FormFieldData* field_data) const; }; #endif // CHROME_BROWSER_AUTOFILL_FORM_GROUP_H_ diff --git a/chrome/browser/autofill/personal_data_manager.cc b/chrome/browser/autofill/personal_data_manager.cc index 8e7c62e..580521d 100644 --- a/chrome/browser/autofill/personal_data_manager.cc +++ b/chrome/browser/autofill/personal_data_manager.cc @@ -18,11 +18,11 @@ #include "chrome/browser/autofill/autofill_field.h" #include "chrome/browser/autofill/autofill_metrics.h" #include "chrome/browser/autofill/autofill_regexes.h" +#include "chrome/browser/autofill/form_group.h" #include "chrome/browser/autofill/form_structure.h" #include "chrome/browser/autofill/personal_data_manager_observer.h" #include "chrome/browser/autofill/phone_number.h" #include "chrome/browser/autofill/phone_number_i18n.h" -#include "chrome/browser/autofill/select_control_handler.h" #include "chrome/common/chrome_notification_types.h" #include "chrome/common/pref_names.h" #include "content/public/browser/browser_context.h" @@ -603,7 +603,7 @@ bool PersonalDataManager::IsValidLearnableProfile( // Reject profiles with invalid US state information. string16 state = profile.GetRawInfo(ADDRESS_HOME_STATE); if (profile.CountryCode() == "US" && - !state.empty() && !autofill::IsValidState(state)) { + !state.empty() && !FormGroup::IsValidState(state)) { return false; } diff --git a/chrome/browser/autofill/select_control_handler.cc b/chrome/browser/autofill/select_control_handler.cc deleted file mode 100644 index 9712d0f..0000000 --- a/chrome/browser/autofill/select_control_handler.cc +++ /dev/null @@ -1,291 +0,0 @@ -// 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 "chrome/browser/autofill/select_control_handler.h" - -#include <string> - -#include "base/basictypes.h" -#include "base/logging.h" -#include "base/string_number_conversions.h" -#include "base/utf_string_conversions.h" -#include "chrome/browser/autofill/autofill_country.h" -#include "chrome/browser/autofill/autofill_profile.h" -#include "chrome/browser/autofill/form_group.h" -#include "chrome/common/form_field_data.h" -#include "grit/generated_resources.h" -#include "ui/base/l10n/l10n_util.h" - -namespace { - -// TODO(jhawkins): Add more states/provinces. See http://crbug.com/45039. - -class State { - public: - const char* name; - const char* abbreviation; - - static const State all_states[]; - - static string16 Abbreviation(const string16& name); - static string16 FullName(const string16& abbreviation); -}; - -const State State::all_states[] = { - { "alabama", "al" }, - { "alaska", "ak" }, - { "arizona", "az" }, - { "arkansas", "ar" }, - { "california", "ca" }, - { "colorado", "co" }, - { "connecticut", "ct" }, - { "delaware", "de" }, - { "district of columbia", "dc" }, - { "florida", "fl" }, - { "georgia", "ga" }, - { "hawaii", "hi" }, - { "idaho", "id" }, - { "illinois", "il" }, - { "indiana", "in" }, - { "iowa", "ia" }, - { "kansas", "ks" }, - { "kentucky", "ky" }, - { "louisiana", "la" }, - { "maine", "me" }, - { "maryland", "md" }, - { "massachusetts", "ma" }, - { "michigan", "mi" }, - { "minnesota", "mv" }, - { "mississippi", "ms" }, - { "missouri", "mo" }, - { "montana", "mt" }, - { "nebraska", "ne" }, - { "nevada", "nv" }, - { "new hampshire", "nh" }, - { "new jersey", "nj" }, - { "new mexico", "nm" }, - { "new york", "ny" }, - { "north carolina", "nc" }, - { "north dakota", "nd" }, - { "ohio", "oh" }, - { "oklahoma", "ok" }, - { "oregon", "or" }, - { "pennsylvania", "pa" }, - { "puerto rico", "pr" }, - { "rhode island", "ri" }, - { "south carolina", "sc" }, - { "south dakota", "sd" }, - { "tennessee", "tn" }, - { "texas", "tx" }, - { "utah", "ut" }, - { "vermont", "vt" }, - { "virginia", "va" }, - { "washington", "wa" }, - { "west Virginia", "wv" }, - { "wisconsin", "wi" }, - { "wyoming", "wy" }, - { NULL, NULL } -}; - -string16 State::Abbreviation(const string16& name) { - for (const State *s = all_states ; s->name ; ++s) - if (LowerCaseEqualsASCII(name, s->name)) - return ASCIIToUTF16(s->abbreviation); - return string16(); -} - -string16 State::FullName(const string16& abbreviation) { - for (const State *s = all_states ; s->name ; ++s) - if (LowerCaseEqualsASCII(abbreviation, s->abbreviation)) - return ASCIIToUTF16(s->name); - return string16(); -} - -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 string16& value, - FormFieldData* field) { - 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 string16& value, - FormFieldData* field) { - string16 abbrev, full; - if (value.size() < 4U) { - abbrev = value; - full = State::FullName(value); - } else { - abbrev = State::Abbreviation(value); - full = value; - } - - // Try the abbreviation name first. - if (!abbrev.empty() && SetSelectControlValue(abbrev, field)) - return true; - - if (full.empty()) - return false; - - return SetSelectControlValue(full, field); -} - -bool FillCountrySelectControl(const FormGroup& form_group, - FormFieldData* field) { - const AutofillProfile& profile = - static_cast<const AutofillProfile&>(form_group); - std::string country_code = profile.CountryCode(); - std::string app_locale = AutofillCountry::ApplicationLocale(); - - DCHECK_EQ(field->option_values.size(), field->option_contents.size()); - for (size_t i = 0; i < field->option_values.size(); ++i) { - // Canonicalize each <option> value to a country code, and compare to the - // target country code. - string16 value = field->option_values[i]; - string16 contents = field->option_contents[i]; - if (country_code == AutofillCountry::GetCountryCode(value, app_locale) || - country_code == AutofillCountry::GetCountryCode(contents, app_locale)) { - field->value = value; - return true; - } - } - - return false; -} - -bool FillExpirationMonthSelectControl(const 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 string16& value, - FormFieldData* field) { - // Try stripping off spaces. - string16 value_stripped; - RemoveChars(StringToLowerASCII(value), kWhitespaceUTF16, &value_stripped); - - for (size_t i = 0; i < field->option_values.size(); ++i) { - string16 option_value_lowercase; - RemoveChars(StringToLowerASCII(field->option_values[i]), kWhitespaceUTF16, - &option_value_lowercase); - 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 - -namespace autofill { - -void FillSelectControl(const FormGroup& form_group, - AutofillFieldType type, - FormFieldData* field) { - DCHECK(field); - DCHECK_EQ("select-one", field->form_control_type); - DCHECK_EQ(field->option_values.size(), field->option_contents.size()); - - string16 field_text = form_group.GetCanonicalizedInfo(type); - string16 field_text_lower = StringToLowerASCII(field_text); - if (field_text.empty()) - return; - - 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; - } - - if (type == ADDRESS_HOME_STATE || type == ADDRESS_BILLING_STATE) { - FillStateSelectControl(field_text, field); - } else if (type == ADDRESS_HOME_COUNTRY || type == ADDRESS_BILLING_COUNTRY) { - FillCountrySelectControl(form_group, field); - } else if (type == CREDIT_CARD_EXP_MONTH) { - FillExpirationMonthSelectControl(field_text, field); - } else if (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(form_group, CREDIT_CARD_EXP_2_DIGIT_YEAR, field); - } else if (type == CREDIT_CARD_TYPE) { - FillCreditCardTypeSelectControl(field_text, field); - } - - return; -} - -bool IsValidState(const string16& value) { - return !State::Abbreviation(value).empty() || !State::FullName(value).empty(); -} - -} // namespace autofill diff --git a/chrome/browser/autofill/select_control_handler.h b/chrome/browser/autofill/select_control_handler.h deleted file mode 100644 index 34f4076..0000000 --- a/chrome/browser/autofill/select_control_handler.h +++ /dev/null @@ -1,31 +0,0 @@ -// 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. - -#ifndef CHROME_BROWSER_AUTOFILL_SELECT_CONTROL_HANDLER_H_ -#define CHROME_BROWSER_AUTOFILL_SELECT_CONTROL_HANDLER_H_ - -#include "chrome/browser/autofill/field_types.h" -#include "base/string16.h" - -class FormGroup; - -struct FormFieldData; - -namespace autofill { - -// Fills a select-one control with the appropriate value from |form_group|. -// Finds the matching value for field types that we know contain different -// variations of a value, e.g., (tx, TX, Texas) or credit card expiration -// months, e.g., (04, April). -void FillSelectControl(const FormGroup& form_group, - AutofillFieldType type, - FormFieldData* field); - -// Returns true if |value| is a valid US state name or abbreviation. It is case -// insensitive. Valid for US states only. -bool IsValidState(const string16& value); - -} // namespace autofill - -#endif // CHROME_BROWSER_AUTOFILL_SELECT_CONTROL_HANDLER_H_ diff --git a/chrome/browser/autofill/select_control_handler_unittest.cc b/chrome/browser/autofill/select_control_handler_unittest.cc deleted file mode 100644 index 3b91748..0000000 --- a/chrome/browser/autofill/select_control_handler_unittest.cc +++ /dev/null @@ -1,293 +0,0 @@ -// 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/stringprintf.h" -#include "base/utf_string_conversions.h" -#include "chrome/browser/autofill/autofill_profile.h" -#include "chrome/browser/autofill/autofill_type.h" -#include "chrome/browser/autofill/credit_card.h" -#include "chrome/browser/autofill/select_control_handler.h" -#include "chrome/common/form_field_data.h" -#include "testing/gtest/include/gtest/gtest.h" - -TEST(SelectControlHandlerTest, CreditCardMonthExact) { - const char* const kMonthsNumeric[] = { - "01", "02", "03", "04", "05", "06", "07", "08", "09", "10", "11", "12", - }; - std::vector<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; - credit_card.SetRawInfo(CREDIT_CARD_EXP_MONTH, ASCIIToUTF16("01")); - autofill::FillSelectControl(credit_card, CREDIT_CARD_EXP_MONTH, &field); - EXPECT_EQ(ASCIIToUTF16("01"), field.value); -} - -TEST(SelectControlHandlerTest, CreditCardMonthAbbreviated) { - const char* const kMonthsAbbreviated[] = { - "Jan", "Feb", "Mar", "Apr", "May", "Jun", - "Jul", "Aug", "Sep", "Oct", "Nov", "Dec", - }; - std::vector<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; - credit_card.SetRawInfo(CREDIT_CARD_EXP_MONTH, ASCIIToUTF16("01")); - autofill::FillSelectControl(credit_card, CREDIT_CARD_EXP_MONTH, &field); - EXPECT_EQ(ASCIIToUTF16("Jan"), field.value); -} - -TEST(SelectControlHandlerTest, CreditCardMonthFull) { - const char* const kMonthsFull[] = { - "January", "February", "March", "April", "May", "June", - "July", "August", "September", "October", "November", "December", - }; - std::vector<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; - credit_card.SetRawInfo(CREDIT_CARD_EXP_MONTH, ASCIIToUTF16("01")); - autofill::FillSelectControl(credit_card, CREDIT_CARD_EXP_MONTH, &field); - EXPECT_EQ(ASCIIToUTF16("January"), field.value); -} - -TEST(SelectControlHandlerTest, CreditCardMonthNumeric) { - const char* const kMonthsNumeric[] = { - "1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12", - }; - std::vector<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; - credit_card.SetRawInfo(CREDIT_CARD_EXP_MONTH, ASCIIToUTF16("01")); - autofill::FillSelectControl(credit_card, CREDIT_CARD_EXP_MONTH, &field); - EXPECT_EQ(ASCIIToUTF16("1"), field.value); -} - -TEST(SelectControlHandlerTest, CreditCardTwoDigitYear) { - const char* const kYears[] = { - "12", "13", "14", "15", "16", "17", "18", "19" - }; - std::vector<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; - credit_card.SetRawInfo(CREDIT_CARD_EXP_4_DIGIT_YEAR, ASCIIToUTF16("2017")); - autofill::FillSelectControl(credit_card, CREDIT_CARD_EXP_4_DIGIT_YEAR, - &field); - EXPECT_EQ(ASCIIToUTF16("17"), field.value); -} - -TEST(SelectControlHandlerTest, CreditCardType) { - const char* const kCreditCardTypes[] = { - "Visa", "Master Card", "AmEx", "discover" - }; - std::vector<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; - credit_card.SetRawInfo(CREDIT_CARD_NUMBER, - ASCIIToUTF16("4111111111111111")); - autofill::FillSelectControl(credit_card, CREDIT_CARD_TYPE, &field); - EXPECT_EQ(ASCIIToUTF16("Visa"), field.value); - } - - { - // Filling should be able to handle intervening whitespace: - CreditCard credit_card; - credit_card.SetRawInfo(CREDIT_CARD_NUMBER, - ASCIIToUTF16("5105105105105100")); - autofill::FillSelectControl(credit_card, CREDIT_CARD_TYPE, &field); - EXPECT_EQ(ASCIIToUTF16("Master Card"), field.value); - } - - { - // American Express is sometimes abbreviated as AmEx: - CreditCard credit_card; - credit_card.SetRawInfo(CREDIT_CARD_NUMBER, ASCIIToUTF16("371449635398431")); - autofill::FillSelectControl(credit_card, CREDIT_CARD_TYPE, &field); - EXPECT_EQ(ASCIIToUTF16("AmEx"), field.value); - } - - { - // Case insensitivity: - CreditCard credit_card; - credit_card.SetRawInfo(CREDIT_CARD_NUMBER, - ASCIIToUTF16("6011111111111117")); - autofill::FillSelectControl(credit_card, CREDIT_CARD_TYPE, &field); - EXPECT_EQ(ASCIIToUTF16("discover"), field.value); - } -} - -TEST(SelectControlHandlerTest, AddressCountryFull) { - const char* const kCountries[] = { - "Albania", "Canada" - }; - std::vector<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; - profile.SetRawInfo(ADDRESS_HOME_COUNTRY, ASCIIToUTF16("CA")); - autofill::FillSelectControl(profile, ADDRESS_HOME_COUNTRY, &field); - EXPECT_EQ(ASCIIToUTF16("Canada"), field.value); -} - -TEST(SelectControlHandlerTest, AddressCountryAbbrev) { - const char* const kCountries[] = { - "AL", "CA" - }; - std::vector<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; - profile.SetRawInfo(ADDRESS_HOME_COUNTRY, ASCIIToUTF16("Canada")); - autofill::FillSelectControl(profile, ADDRESS_HOME_COUNTRY, &field); - EXPECT_EQ(ASCIIToUTF16("CA"), field.value); -} - -TEST(SelectControlHandlerTest, AddressStateFull) { - const char* const kStates[] = { - "Alabama", "California" - }; - std::vector<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; - profile.SetRawInfo(ADDRESS_HOME_STATE, ASCIIToUTF16("CA")); - autofill::FillSelectControl(profile, ADDRESS_HOME_STATE, &field); - EXPECT_EQ(ASCIIToUTF16("California"), field.value); -} - -TEST(SelectControlHandlerTest, AddressStateAbbrev) { - const char* const kStates[] = { - "AL", "CA" - }; - std::vector<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; - profile.SetRawInfo(ADDRESS_HOME_STATE, ASCIIToUTF16("California")); - autofill::FillSelectControl(profile, ADDRESS_HOME_STATE, &field); - EXPECT_EQ(ASCIIToUTF16("CA"), field.value); -} - -TEST(SelectControlHandlerTest, FillByValue) { - const char* const kStates[] = { - "Alabama", "California" - }; - std::vector<string16> values(arraysize(kStates)); - std::vector<string16> contents(arraysize(kStates)); - for (size_t i = 0; i < arraysize(kStates); ++i) { - values[i] = ASCIIToUTF16(kStates[i]); - contents[i] = ASCIIToUTF16(base::StringPrintf("%d", static_cast<int>(i))); - } - - FormFieldData field; - field.form_control_type = "select-one"; - field.option_values = values; - field.option_contents = contents; - - AutofillProfile profile; - profile.SetRawInfo(ADDRESS_HOME_STATE, ASCIIToUTF16("California")); - autofill::FillSelectControl(profile, ADDRESS_HOME_STATE, &field); - EXPECT_EQ(ASCIIToUTF16("California"), field.value); -} - -TEST(SelectControlHandlerTest, FillByContents) { - const char* const kStates[] = { - "Alabama", "California" - }; - std::vector<string16> values(arraysize(kStates)); - std::vector<string16> contents(arraysize(kStates)); - for (size_t i = 0; i < arraysize(kStates); ++i) { - values[i] = ASCIIToUTF16(base::StringPrintf("%d", static_cast<int>(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; - profile.SetRawInfo(ADDRESS_HOME_STATE, ASCIIToUTF16("California")); - autofill::FillSelectControl(profile, ADDRESS_HOME_STATE, &field); - EXPECT_EQ(ASCIIToUTF16("2"), field.value); -} diff --git a/chrome/chrome_browser.gypi b/chrome/chrome_browser.gypi index e2f6eb3..356ce8a 100644 --- a/chrome/chrome_browser.gypi +++ b/chrome/chrome_browser.gypi @@ -252,8 +252,6 @@ 'browser/autofill/phone_number.h', 'browser/autofill/phone_number_i18n.cc', 'browser/autofill/phone_number_i18n.h', - 'browser/autofill/select_control_handler.cc', - 'browser/autofill/select_control_handler.h', 'browser/auto_launch_trial.cc', 'browser/auto_launch_trial.h', 'browser/automation/automation_browser_tracker.cc', diff --git a/chrome/chrome_tests_unit.gypi b/chrome/chrome_tests_unit.gypi index 27602b1..b32a17e 100644 --- a/chrome/chrome_tests_unit.gypi +++ b/chrome/chrome_tests_unit.gypi @@ -459,7 +459,6 @@ 'browser/autofill/phone_field_unittest.cc', 'browser/autofill/phone_number_unittest.cc', 'browser/autofill/phone_number_i18n_unittest.cc', - 'browser/autofill/select_control_handler_unittest.cc', 'browser/automation/automation_provider_unittest.cc', 'browser/automation/automation_tab_helper_unittest.cc', 'browser/background/background_application_list_model_unittest.cc', |