summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--chrome/browser/autofill/autofill_manager.cc294
-rw-r--r--chrome/browser/autofill/autofill_manager.h24
-rw-r--r--chrome/browser/autofill/autofill_manager_unittest.cc347
-rw-r--r--chrome/browser/autofill/credit_card.cc9
-rw-r--r--chrome/browser/autofill/credit_card.h2
-rw-r--r--chrome/browser/autofill/form_structure.cc41
-rw-r--r--chrome/browser/autofill/form_structure.h8
7 files changed, 519 insertions, 206 deletions
diff --git a/chrome/browser/autofill/autofill_manager.cc b/chrome/browser/autofill/autofill_manager.cc
index 6754c2a..15b5ba8 100644
--- a/chrome/browser/autofill/autofill_manager.cc
+++ b/chrome/browser/autofill/autofill_manager.cc
@@ -6,7 +6,8 @@
#include <string>
-#include "base/command_line.h"
+#include "base/basictypes.h"
+#include "base/string16.h"
#include "chrome/browser/autofill/autofill_dialog.h"
#include "chrome/browser/autofill/autofill_infobar_delegate.h"
#include "chrome/browser/autofill/form_structure.h"
@@ -35,6 +36,8 @@ const int kAutoFillPhoneNumberPrefixCount = 3;
const int kAutoFillPhoneNumberSuffixOffset = 3;
const int kAutoFillPhoneNumberSuffixCount = 4;
+const string16::value_type kLabelSeparator[] = {';',' ',0};
+
} // namespace
// TODO(jhawkins): Maybe this should be in a grd file?
@@ -130,37 +133,48 @@ bool AutoFillManager::GetAutoFillSuggestions(int query_id,
personal_data_->credit_cards().empty())
return false;
- AutoFillField* form_field = NULL;
- for (std::vector<FormStructure*>::iterator form = form_structures_.begin();
- form != form_structures_.end(); ++form) {
+ // Loops through the cached FormStructures looking for the FormStructure that
+ // contains |field| and the associated AutoFillFieldType.
+ FormStructure* form = NULL;
+ AutoFillField* autofill_field = NULL;
+ for (std::vector<FormStructure*>::iterator form_iter =
+ form_structures_.begin();
+ form_iter != form_structures_.end(); ++form_iter) {
+ form = *form_iter;
+
// Don't send suggestions for forms that aren't auto-fillable.
- if (!(*form)->IsAutoFillable())
+ if (!form->IsAutoFillable())
continue;
- for (std::vector<AutoFillField*>::const_iterator iter = (*form)->begin();
- iter != (*form)->end(); ++iter) {
+ for (std::vector<AutoFillField*>::const_iterator iter = form->begin();
+ iter != form->end(); ++iter) {
// The field list is terminated with a NULL AutoFillField, so don't try to
// dereference it.
if (!*iter)
break;
if ((**iter) == field) {
- form_field = *iter;
+ autofill_field = *iter;
break;
}
}
}
- if (form_field == NULL)
+ if (autofill_field == NULL)
return false;
std::vector<string16> values;
std::vector<string16> labels;
+ AutoFillType type(autofill_field->type());
- if (AutoFillType(form_field->type()).group() != AutoFillType::CREDIT_CARD)
- GetProfileSuggestions(field, form_field->type(), &values, &labels);
+ if (type.group() == AutoFillType::CREDIT_CARD)
+ GetCreditCardSuggestions(form, field, type, &values, &labels);
+ else if (type.group() == AutoFillType::ADDRESS_BILLING)
+ GetBillingProfileSuggestions(field, type, &values, &labels);
else
- GetCreditCardSuggestions(field, form_field->type(), &values, &labels);
+ GetProfileSuggestions(form, field, type, &values, &labels);
+
+ DCHECK_EQ(values.size(), labels.size());
// No suggestions.
if (values.empty())
@@ -170,6 +184,7 @@ bool AutoFillManager::GetAutoFillSuggestions(int query_id,
return true;
}
+// TODO(jhawkins): Remove the |value| parameter.
bool AutoFillManager::FillAutoFillFormData(int query_id,
const FormData& form,
const string16& value,
@@ -183,35 +198,66 @@ bool AutoFillManager::FillAutoFillFormData(int query_id,
const std::vector<AutoFillProfile*>& profiles = personal_data_->profiles();
const std::vector<CreditCard*>& credit_cards = personal_data_->credit_cards();
+
+ // No data to return if the profiles are empty.
if (profiles.empty() && credit_cards.empty())
return false;
- // Find profile that matches the |value| and |label| in question.
+ // Find the FormStructure that corresponds to |form|.
+ FormData result = form;
+ FormStructure* form_structure = NULL;
+ for (std::vector<FormStructure*>::const_iterator iter =
+ form_structures_.begin();
+ iter != form_structures_.end(); ++iter) {
+ if (**iter == form) {
+ form_structure = *iter;
+ break;
+ }
+ }
+
+ if (!form_structure)
+ return false;
+
+ // No data to return if there are no auto-fillable fields.
+ if (!form_structure->autofill_count())
+ return false;
+
+ // |cc_digits| will contain the last four digits of a credit card number only
+ // if the form has billing fields.
+ string16 profile_label = label;
+ string16 cc_digits;
+
+ // If the form has billing fields, |label| will contain at least one "; "
+ // followed by the last four digits of a credit card number.
+ if (form_structure->HasBillingFields()) {
+ // We must search for the last "; " as it's possible the profile label
+ // proper can contain this sequence of characters.
+ size_t index = label.find_last_of(kLabelSeparator);
+ if (index != string16::npos) {
+ profile_label = label.substr(0, index - 1);
+
+ size_t cc_index = index + 1;
+ cc_digits = label.substr(cc_index);
+ }
+ }
+
+ // Find the profile that matches the |profile_label|.
const AutoFillProfile* profile = NULL;
for (std::vector<AutoFillProfile*>::const_iterator iter = profiles.begin();
iter != profiles.end(); ++iter) {
- if ((*iter)->Label() != label)
- continue;
-
- FieldTypeSet field_types;
- (*iter)->GetPossibleFieldTypes(value, &field_types);
- for (FieldTypeSet::const_iterator type = field_types.begin();
- type != field_types.end(); ++type) {
- if ((*iter)->GetFieldText(AutoFillType(*type)) == value) {
- profile = *iter;
- break;
- }
+ if ((*iter)->Label() == profile_label) {
+ profile = *iter;
}
}
- // Only look for credit card info if we're not filling profile.
+ // Don't look for a matching credit card if we fully-matched the profile using
+ // the entire label.
const CreditCard* credit_card = NULL;
- if (!profile) {
+ if (!cc_digits.empty()) {
+ // Find the credit card that matches the |cc_label|.
for (std::vector<CreditCard*>::const_iterator iter = credit_cards.begin();
iter != credit_cards.end(); ++iter) {
- // Labels are unique, so we only need to verify the label for the credit
- // card.
- if ((*iter)->Label() == label) {
+ if ((*iter)->LastFourDigits() == cc_digits) {
credit_card = *iter;
break;
}
@@ -221,56 +267,44 @@ bool AutoFillManager::FillAutoFillFormData(int query_id,
if (!profile && !credit_card)
return false;
- // We fill either the profile or the credit card, not both.
- DCHECK((profile && !credit_card) || (!profile && credit_card));
+ // The list of fields in |form_structure| and |result.fields| often match
+ // directly and we can fill these corresponding fields; however, when the
+ // |form_structure| and |result.fields| do not match directly we search
+ // ahead in the |form_structure| for the matching field.
+ // See unit tests: AutoFillManagerTest.FormChangesRemoveField and
+ // AutoFillManagerTest.FormChangesAddField for usage.
+ for (size_t i = 0, j = 0;
+ i < form_structure->field_count() && j < result.fields.size();
+ j++) {
+ size_t k = i;
+
+ // Search forward in the |form_structure| for a corresponding field.
+ while (k < form_structure->field_count() &&
+ *form_structure->field(k) != result.fields[j]) {
+ k++;
+ }
- FormData result = form;
- for (std::vector<FormStructure*>::const_iterator iter =
- form_structures_.begin();
- iter != form_structures_.end(); ++iter) {
- const FormStructure* form_structure = *iter;
- if (*form_structure != form)
+ // If we've found a match then fill the |result| field with the found
+ // field in the |form_structure|.
+ if (k >= form_structure->field_count())
continue;
- // The list of fields in |form_structure| and |result.fields| often match
- // directly and we can fill these corresponding fields; however, when the
- // |form_structure| and |result.fields| do not match directly we search
- // ahead in the |form_structure| for the matching field.
- // See unit tests: AutoFillManagerTest.FormChangesRemoveField and
- // AutoFillManagerTest.FormChangesAddField for usage.
- for (size_t i = 0, j = 0;
- i < form_structure->field_count() && j < result.fields.size();
- j++) {
- size_t k = i;
-
- // Search forward in the |form_structure| for a corresponding field.
- while (k < form_structure->field_count() &&
- *form_structure->field(k) != result.fields[j]) {
- k++;
- }
-
- // If we've found a match then fill the |result| field with the found
- // field in the |form_structure|.
- if (k >= form_structure->field_count())
- continue;
-
- const AutoFillField* field = form_structure->field(k);
- AutoFillType autofill_type(field->type());
- if (credit_card &&
- autofill_type.group() == AutoFillType::CREDIT_CARD) {
- result.fields[i].set_value(
- credit_card->GetFieldText(autofill_type));
- } else if (credit_card &&
- autofill_type.group() == AutoFillType::ADDRESS_BILLING) {
- FillBillingFormField(credit_card, autofill_type, &result.fields[j]);
- } else if (profile) {
- FillFormField(profile, autofill_type, &result.fields[j]);
- }
-
- // We found a matching field in the |form_structure| so we
- // proceed to the next |result| field, and the next |form_structure|.
- ++i;
+ const AutoFillField* field = form_structure->field(k);
+ AutoFillType autofill_type(field->type());
+ if (credit_card &&
+ autofill_type.group() == AutoFillType::CREDIT_CARD) {
+ result.fields[i].set_value(
+ credit_card->GetFieldText(autofill_type));
+ } else if (credit_card &&
+ autofill_type.group() == AutoFillType::ADDRESS_BILLING) {
+ FillBillingFormField(credit_card, autofill_type, &result.fields[j]);
+ } else if (profile) {
+ FillFormField(profile, autofill_type, &result.fields[j]);
}
+
+ // We found a matching field in the |form_structure| so we
+ // proceed to the next |result| field, and the next |form_structure|.
+ ++i;
}
host->AutoFillFormDataFilled(query_id, result);
@@ -400,8 +434,9 @@ AutoFillManager::AutoFillManager(TabContents* tab_contents,
DCHECK(tab_contents);
}
-void AutoFillManager::GetProfileSuggestions(const FormField& field,
- AutoFillFieldType type,
+void AutoFillManager::GetProfileSuggestions(FormStructure* form,
+ const FormField& field,
+ AutoFillType type,
std::vector<string16>* values,
std::vector<string16>* labels) {
const std::vector<AutoFillProfile*>& profiles = personal_data_->profiles();
@@ -410,37 +445,110 @@ void AutoFillManager::GetProfileSuggestions(const FormField& field,
AutoFillProfile* profile = *iter;
// The value of the stored data for this field type in the |profile|.
- string16 profile_field_value = profile->GetFieldText(AutoFillType(type));
+ string16 profile_field_value = profile->GetFieldText(type);
if (!profile_field_value.empty() &&
StartsWith(profile_field_value, field.value(), false)) {
- values->push_back(profile_field_value);
- labels->push_back(profile->Label());
+ if (!form->HasBillingFields()) {
+ values->push_back(profile_field_value);
+ labels->push_back(profile->Label());
+ } else {
+ for (std::vector<CreditCard*>::const_iterator cc =
+ personal_data_->credit_cards().begin();
+ cc != personal_data_->credit_cards().end(); ++cc) {
+ values->push_back(profile_field_value);
+
+ string16 label = profile->Label() + kLabelSeparator +
+ (*cc)->LastFourDigits();
+ labels->push_back(label);
+ }
+ }
+ }
+ }
+}
+
+void AutoFillManager::GetBillingProfileSuggestions(
+ const FormField& field,
+ AutoFillType type,
+ std::vector<string16>* values,
+ std::vector<string16>* labels) {
+ std::vector<CreditCard*> matching_creditcards;
+ std::vector<AutoFillProfile*> matching_profiles;
+ std::vector<string16> cc_values;
+ std::vector<string16> cc_labels;
+
+ for (std::vector<CreditCard*>::const_iterator cc =
+ personal_data_->credit_cards().begin();
+ cc != personal_data_->credit_cards().end(); ++cc) {
+ string16 label = (*cc)->billing_address();
+ AutoFillProfile* billing_profile = NULL;
+
+ // The value of the stored data for this field type in the |profile|.
+ string16 profile_field_value;
+
+ for (std::vector<AutoFillProfile*>::const_iterator iter =
+ personal_data_->profiles().begin();
+ iter != personal_data_->profiles().end(); ++iter) {
+ AutoFillProfile* profile = *iter;
+
+ // This assumes that labels are unique.
+ if (profile->Label() == label &&
+ !profile->GetFieldText(type).empty() &&
+ StartsWith(profile->GetFieldText(type), field.value(), false)) {
+ billing_profile = profile;
+ break;
+ }
+ }
+
+ if (!billing_profile)
+ continue;
+
+ for (std::vector<AutoFillProfile*>::const_iterator iter =
+ personal_data_->profiles().begin();
+ iter != personal_data_->profiles().end(); ++iter) {
+ values->push_back(billing_profile->GetFieldText(type));
+
+ string16 label = (*iter)->Label() +
+ ASCIIToUTF16("; ") +
+ (*cc)->LastFourDigits();
+ labels->push_back(label);
}
}
}
-void AutoFillManager::GetCreditCardSuggestions(const FormField& field,
- AutoFillFieldType type,
+void AutoFillManager::GetCreditCardSuggestions(FormStructure* form,
+ const FormField& field,
+ AutoFillType type,
std::vector<string16>* values,
std::vector<string16>* labels) {
- // TODO(jhawkins): Only return suggestions for the credit card number until
- // the AutoFill dropdown is redesigned to show a credit card icon.
- if (type != CREDIT_CARD_NUMBER)
- return;
-
- const std::vector<CreditCard*>& credit_cards = personal_data_->credit_cards();
- for (std::vector<CreditCard*>::const_iterator iter = credit_cards.begin();
- iter != credit_cards.end(); ++iter) {
+ for (std::vector<CreditCard*>::const_iterator iter =
+ personal_data_->credit_cards().begin();
+ iter != personal_data_->credit_cards().end(); ++iter) {
CreditCard* credit_card = *iter;
// The value of the stored data for this field type in the |credit_card|.
string16 creditcard_field_value =
- credit_card->GetFieldText(AutoFillType(type));
+ credit_card->GetFieldText(type);
if (!creditcard_field_value.empty() &&
StartsWith(creditcard_field_value, field.value(), false)) {
- values->push_back(credit_card->ObfuscatedNumber());
- labels->push_back(credit_card->Label());
+ if (type.field_type() == CREDIT_CARD_NUMBER)
+ creditcard_field_value = credit_card->ObfuscatedNumber();
+
+ if (!form->HasNonBillingFields()) {
+ values->push_back(creditcard_field_value);
+ labels->push_back(credit_card->Label());
+ } else {
+ for (std::vector<AutoFillProfile*>::const_iterator iter =
+ personal_data_->profiles().begin();
+ iter != personal_data_->profiles().end(); ++iter) {
+ values->push_back(creditcard_field_value);
+
+ string16 label = (*iter)->Label() +
+ ASCIIToUTF16("; ") +
+ credit_card->LastFourDigits();
+ labels->push_back(label);
+ }
+ }
}
}
}
diff --git a/chrome/browser/autofill/autofill_manager.h b/chrome/browser/autofill/autofill_manager.h
index 31c03d2..46ee0f5 100644
--- a/chrome/browser/autofill/autofill_manager.h
+++ b/chrome/browser/autofill/autofill_manager.h
@@ -100,23 +100,35 @@ class AutoFillManager : public RenderViewHostDelegate::AutoFill,
private:
// Returns a list of values from the stored profiles that match |type| and the
- // value of |field| and returns the labels of the matching profiles.
- void GetProfileSuggestions(const webkit_glue::FormField& field,
- AutoFillFieldType type,
+ // value of |field| and returns the labels of the matching profiles. |labels|
+ // is filled with the Profile label and possibly the last four digits of a
+ // corresponding credit card: 'Home; 1258' - Home is the Profile label and
+ // 1258 is the last four digits of the credit card.
+ void GetProfileSuggestions(FormStructure* form,
+ const webkit_glue::FormField& field,
+ AutoFillType type,
std::vector<string16>* values,
std::vector<string16>* labels);
+ // Same as GetProfileSuggestions, but the list of stored profiles is limited
+ // to the linked billing addresses from the list of credit cards.
+ void GetBillingProfileSuggestions(const webkit_glue::FormField& field,
+ AutoFillType type,
+ std::vector<string16>* values,
+ std::vector<string16>* labels);
+
// Returns a list of values from the stored credit cards that match |type| and
// the value of |field| and returns the labels of the matching credit cards.
- void GetCreditCardSuggestions(const webkit_glue::FormField& field,
- AutoFillFieldType type,
+ void GetCreditCardSuggestions(FormStructure* form,
+ const webkit_glue::FormField& field,
+ AutoFillType type,
std::vector<string16>* values,
std::vector<string16>* labels);
// Set |field| argument's value based on |type| and contents of the
// |credit_card|. The |type| field is expected to have main group type of
// ADDRESS_BILLING. The address information is retrieved from the billing
- // profile asscociated with the |credit_card|, if there is one set.
+ // profile associated with the |credit_card|, if there is one set.
void FillBillingFormField(const CreditCard* credit_card,
AutoFillType type,
webkit_glue::FormField* field);
diff --git a/chrome/browser/autofill/autofill_manager_unittest.cc b/chrome/browser/autofill/autofill_manager_unittest.cc
index 33ac34c..2435b93 100644
--- a/chrome/browser/autofill/autofill_manager_unittest.cc
+++ b/chrome/browser/autofill/autofill_manager_unittest.cc
@@ -49,6 +49,16 @@ class TestPersonalDataManager : public PersonalDataManager {
return NULL;
}
+ void AddSemicolonAutoFillProfile() {
+ AutoFillProfile* profile = new AutoFillProfile;
+ autofill_unittest::SetProfileInfo(profile, "Home; 8765", "Joe", "", "Ely",
+ "flatlander@gmail.com", "MCA",
+ "916 16th St.", "Apt. 6", "Lubbock",
+ "Texas", "79401", "USA",
+ "12345678901", "");
+ web_profiles_->push_back(profile);
+ }
+
private:
void CreateTestAutoFillProfiles(ScopedVector<AutoFillProfile>* profiles) {
AutoFillProfile* profile = new AutoFillProfile;
@@ -105,6 +115,10 @@ class TestAutoFillManager : public AutoFillManager {
return test_personal_data_->GetLabeledProfile(label);
}
+ void AddSemicolonAutoFillProfile() {
+ test_personal_data_->AddSemicolonAutoFillProfile();
+ }
+
private:
scoped_refptr<TestPersonalDataManager> test_personal_data_;
@@ -149,14 +163,6 @@ void CreateTestFormData(FormData* form) {
form->fields.push_back(field);
CreateTestFormField("Email", "email", "", "text", &field);
form->fields.push_back(field);
- CreateTestFormField("Name on Card", "nameoncard", "", "text", &field);
- form->fields.push_back(field);
- CreateTestFormField("Card Number", "cardnumber", "", "text", &field);
- form->fields.push_back(field);
- CreateTestFormField("Expiration Date", "ccmonth", "", "text", &field);
- form->fields.push_back(field);
- CreateTestFormField("", "ccyear", "", "text", &field);
- form->fields.push_back(field);
}
void CreateTestFormDataBilling(FormData* form) {
@@ -243,6 +249,10 @@ class AutoFillManagerTest : public RenderViewHostTestHarness {
return true;
}
+ void AddSemicolonAutoFillProfile() {
+ autofill_manager_->AddSemicolonAutoFillProfile();
+ }
+
protected:
scoped_ptr<TestAutoFillManager> autofill_manager_;
@@ -312,7 +322,7 @@ TEST_F(AutoFillManagerTest, GetProfileSuggestionsMatchCharacter) {
TEST_F(AutoFillManagerTest, GetCreditCardSuggestionsEmptyValue) {
FormData form;
- CreateTestFormData(&form);
+ CreateTestFormDataBilling(&form);
// Set up our FormStructures.
std::vector<FormData> forms;
@@ -333,17 +343,25 @@ TEST_F(AutoFillManagerTest, GetCreditCardSuggestionsEmptyValue) {
std::vector<string16> labels;
EXPECT_TRUE(GetAutoFillSuggestionsMessage(&page_id, &values, &labels));
EXPECT_EQ(kPageID, page_id);
- ASSERT_EQ(2U, values.size());
+ ASSERT_EQ(6U, values.size());
EXPECT_EQ(ASCIIToUTF16("************3456"), values[0]);
- EXPECT_EQ(ASCIIToUTF16("************8765"), values[1]);
- ASSERT_EQ(2U, labels.size());
- EXPECT_EQ(ASCIIToUTF16("First"), labels[0]);
- EXPECT_EQ(ASCIIToUTF16("Second"), labels[1]);
+ EXPECT_EQ(ASCIIToUTF16("************3456"), values[1]);
+ EXPECT_EQ(ASCIIToUTF16("************3456"), values[2]);
+ EXPECT_EQ(ASCIIToUTF16("************8765"), values[3]);
+ EXPECT_EQ(ASCIIToUTF16("************8765"), values[4]);
+ EXPECT_EQ(ASCIIToUTF16("************8765"), values[5]);
+ ASSERT_EQ(6U, labels.size());
+ EXPECT_EQ(ASCIIToUTF16("Home; 3456"), labels[0]);
+ EXPECT_EQ(ASCIIToUTF16("Work; 3456"), labels[1]);
+ EXPECT_EQ(ASCIIToUTF16("Empty; 3456"), labels[2]);
+ EXPECT_EQ(ASCIIToUTF16("Home; 8765"), labels[3]);
+ EXPECT_EQ(ASCIIToUTF16("Work; 8765"), labels[4]);
+ EXPECT_EQ(ASCIIToUTF16("Empty; 8765"), labels[5]);
}
TEST_F(AutoFillManagerTest, GetCreditCardSuggestionsMatchCharacter) {
FormData form;
- CreateTestFormData(&form);
+ CreateTestFormDataBilling(&form);
// Set up our FormStructures.
std::vector<FormData> forms;
@@ -364,15 +382,19 @@ TEST_F(AutoFillManagerTest, GetCreditCardSuggestionsMatchCharacter) {
std::vector<string16> labels;
EXPECT_TRUE(GetAutoFillSuggestionsMessage(&page_id, &values, &labels));
EXPECT_EQ(kPageID, page_id);
- ASSERT_EQ(1U, values.size());
+ ASSERT_EQ(3U, values.size());
EXPECT_EQ(ASCIIToUTF16("************3456"), values[0]);
- ASSERT_EQ(1U, labels.size());
- EXPECT_EQ(ASCIIToUTF16("First"), labels[0]);
+ EXPECT_EQ(ASCIIToUTF16("************3456"), values[1]);
+ EXPECT_EQ(ASCIIToUTF16("************3456"), values[2]);
+ ASSERT_EQ(3U, labels.size());
+ EXPECT_EQ(ASCIIToUTF16("Home; 3456"), labels[0]);
+ EXPECT_EQ(ASCIIToUTF16("Work; 3456"), labels[1]);
+ EXPECT_EQ(ASCIIToUTF16("Empty; 3456"), labels[2]);
}
TEST_F(AutoFillManagerTest, GetCreditCardSuggestionsNonCCNumber) {
FormData form;
- CreateTestFormData(&form);
+ CreateTestFormDataBilling(&form);
// Set up our FormStructures.
std::vector<FormData> forms;
@@ -384,24 +406,145 @@ TEST_F(AutoFillManagerTest, GetCreditCardSuggestionsNonCCNumber) {
const int kPageID = 1;
webkit_glue::FormField field;
+ CreateTestFormField("Name on Card", "nameoncard", "", "text", &field);
+ EXPECT_TRUE(autofill_manager_->GetAutoFillSuggestions(kPageID, field));
+
+ // Test that we sent the right message to the renderer.
int page_id = 0;
std::vector<string16> values;
std::vector<string16> labels;
- CreateTestFormField("Name on Card", "nameoncard", "", "text", &field);
- EXPECT_FALSE(autofill_manager_->GetAutoFillSuggestions(kPageID, field));
- EXPECT_FALSE(GetAutoFillSuggestionsMessage(&page_id, &values, &labels));
+ EXPECT_TRUE(GetAutoFillSuggestionsMessage(&page_id, &values, &labels));
+ EXPECT_EQ(kPageID, page_id);
+ ASSERT_EQ(6U, values.size());
+ EXPECT_EQ(ASCIIToUTF16("Elvis Presley"), values[0]);
+ EXPECT_EQ(ASCIIToUTF16("Elvis Presley"), values[1]);
+ EXPECT_EQ(ASCIIToUTF16("Elvis Presley"), values[2]);
+ EXPECT_EQ(ASCIIToUTF16("Buddy Holly"), values[3]);
+ EXPECT_EQ(ASCIIToUTF16("Buddy Holly"), values[4]);
+ EXPECT_EQ(ASCIIToUTF16("Buddy Holly"), values[5]);
+ ASSERT_EQ(6U, labels.size());
+ EXPECT_EQ(ASCIIToUTF16("Home; 3456"), labels[0]);
+ EXPECT_EQ(ASCIIToUTF16("Work; 3456"), labels[1]);
+ EXPECT_EQ(ASCIIToUTF16("Empty; 3456"), labels[2]);
+ EXPECT_EQ(ASCIIToUTF16("Home; 8765"), labels[3]);
+ EXPECT_EQ(ASCIIToUTF16("Work; 8765"), labels[4]);
+ EXPECT_EQ(ASCIIToUTF16("Empty; 8765"), labels[5]);
+}
- CreateTestFormField("Expiration Date", "ccmonth", "", "text", &field);
- EXPECT_FALSE(autofill_manager_->GetAutoFillSuggestions(kPageID, field));
- EXPECT_FALSE(GetAutoFillSuggestionsMessage(&page_id, &values, &labels));
+TEST_F(AutoFillManagerTest, GetCreditCardSuggestionsSemicolon) {
+ AddSemicolonAutoFillProfile();
- CreateTestFormField("", "ccyear", "", "text", &field);
- EXPECT_FALSE(autofill_manager_->GetAutoFillSuggestions(kPageID, field));
- EXPECT_FALSE(GetAutoFillSuggestionsMessage(&page_id, &values, &labels));
+ FormData form;
+ CreateTestFormDataBilling(&form);
+
+ // Set up our FormStructures.
+ std::vector<FormData> forms;
+ forms.push_back(form);
+ autofill_manager_->FormsSeen(forms);
+
+ // The page ID sent to the AutoFillManager from the RenderView, used to send
+ // an IPC message back to the renderer.
+ const int kPageID = 1;
+
+ webkit_glue::FormField field;
+ CreateTestFormField("Name on Card", "nameoncard", "", "text", &field);
+ EXPECT_TRUE(autofill_manager_->GetAutoFillSuggestions(kPageID, field));
+
+ // Test that we sent the right message to the renderer.
+ int page_id = 0;
+ std::vector<string16> values;
+ std::vector<string16> labels;
+ EXPECT_TRUE(GetAutoFillSuggestionsMessage(&page_id, &values, &labels));
+ EXPECT_EQ(kPageID, page_id);
+ ASSERT_EQ(8U, values.size());
+ EXPECT_EQ(ASCIIToUTF16("Elvis Presley"), values[0]);
+ EXPECT_EQ(ASCIIToUTF16("Elvis Presley"), values[1]);
+ EXPECT_EQ(ASCIIToUTF16("Elvis Presley"), values[2]);
+ EXPECT_EQ(ASCIIToUTF16("Elvis Presley"), values[3]);
+ EXPECT_EQ(ASCIIToUTF16("Buddy Holly"), values[4]);
+ EXPECT_EQ(ASCIIToUTF16("Buddy Holly"), values[5]);
+ EXPECT_EQ(ASCIIToUTF16("Buddy Holly"), values[6]);
+ EXPECT_EQ(ASCIIToUTF16("Buddy Holly"), values[7]);
+ ASSERT_EQ(8U, labels.size());
+ EXPECT_EQ(ASCIIToUTF16("Home; 3456"), labels[0]);
+ EXPECT_EQ(ASCIIToUTF16("Work; 3456"), labels[1]);
+ EXPECT_EQ(ASCIIToUTF16("Empty; 3456"), labels[2]);
+ EXPECT_EQ(ASCIIToUTF16("Home; 8765; 3456"), labels[3]);
+ EXPECT_EQ(ASCIIToUTF16("Home; 8765"), labels[4]);
+ EXPECT_EQ(ASCIIToUTF16("Work; 8765"), labels[5]);
+ EXPECT_EQ(ASCIIToUTF16("Empty; 8765"), labels[6]);
+ EXPECT_EQ(ASCIIToUTF16("Home; 8765; 8765"), labels[7]);
}
TEST_F(AutoFillManagerTest, FillCreditCardForm) {
FormData form;
+ CreateTestFormDataBilling(&form);
+
+ // Set up our FormStructures.
+ std::vector<FormData> forms;
+ forms.push_back(form);
+ autofill_manager_->FormsSeen(forms);
+
+ // The page ID sent to the AutoFillManager from the RenderView, used to send
+ // an IPC message back to the renderer.
+ const int kPageID = 1;
+ EXPECT_TRUE(
+ autofill_manager_->FillAutoFillFormData(kPageID,
+ form,
+ string16(),
+ ASCIIToUTF16("Home; 3456")));
+
+ int page_id = 0;
+ FormData results;
+ EXPECT_TRUE(GetAutoFillFormDataFilledMessage(&page_id, &results));
+ EXPECT_EQ(ASCIIToUTF16("MyForm"), results.name);
+ EXPECT_EQ(ASCIIToUTF16("POST"), results.method);
+ EXPECT_EQ(GURL("http://myform.com/form.html"), results.origin);
+ EXPECT_EQ(GURL("http://myform.com/submit.html"), results.action);
+ ASSERT_EQ(15U, results.fields.size());
+
+ webkit_glue::FormField field;
+ CreateTestFormField("First Name", "firstname", "Elvis", "text", &field);
+ EXPECT_TRUE(field.StrictlyEqualsHack(results.fields[0]));
+ CreateTestFormField("Middle Name", "middlename", "Aaron", "text", &field);
+ EXPECT_TRUE(field.StrictlyEqualsHack(results.fields[1]));
+ CreateTestFormField("Last Name", "lastname", "Presley", "text", &field);
+ EXPECT_TRUE(field.StrictlyEqualsHack(results.fields[2]));
+ CreateTestFormField("Address Line 1", "billingAddr1",
+ "3734 Elvis Presley Blvd.", "text", &field);
+ EXPECT_TRUE(field.StrictlyEqualsHack(results.fields[3]));
+ CreateTestFormField(
+ "Address Line 2", "billingAddr2", "Apt. 10", "text", &field);
+ EXPECT_TRUE(field.StrictlyEqualsHack(results.fields[4]));
+ CreateTestFormField("City", "billingCity", "Memphis", "text", &field);
+ EXPECT_TRUE(field.StrictlyEqualsHack(results.fields[5]));
+ CreateTestFormField("State", "billingState", "Tennessee", "text", &field);
+ EXPECT_TRUE(field.StrictlyEqualsHack(results.fields[6]));
+ CreateTestFormField("Postal Code", "billingZipcode", "38116", "text", &field);
+ EXPECT_TRUE(field.StrictlyEqualsHack(results.fields[7]));
+ CreateTestFormField("Country", "billingCountry", "USA", "text", &field);
+ EXPECT_TRUE(field.StrictlyEqualsHack(results.fields[8]));
+ CreateTestFormField(
+ "Phone Number", "phonenumber", "12345678901", "text", &field);
+ EXPECT_TRUE(field.StrictlyEqualsHack(results.fields[9]));
+ CreateTestFormField("Email", "email", "theking@gmail.com", "text", &field);
+ EXPECT_TRUE(field.StrictlyEqualsHack(results.fields[10]));
+ CreateTestFormField(
+ "Name on Card", "nameoncard", "Elvis Presley", "text", &field);
+ EXPECT_TRUE(field.StrictlyEqualsHack(results.fields[11]));
+ CreateTestFormField(
+ "Card Number", "cardnumber", "1234567890123456", "text", &field);
+ EXPECT_TRUE(field.StrictlyEqualsHack(results.fields[12]));
+ CreateTestFormField("Expiration Date", "ccmonth", "04", "text", &field);
+ EXPECT_TRUE(field.StrictlyEqualsHack(results.fields[13]));
+ CreateTestFormField("", "ccyear", "2012", "text", &field);
+ EXPECT_TRUE(field.StrictlyEqualsHack(results.fields[14]));
+}
+
+TEST_F(AutoFillManagerTest, FillNonBillingFormSemicolon) {
+ AddSemicolonAutoFillProfile();
+
+ FormData form;
CreateTestFormData(&form);
// Set up our FormStructures.
@@ -415,8 +558,62 @@ TEST_F(AutoFillManagerTest, FillCreditCardForm) {
EXPECT_TRUE(
autofill_manager_->FillAutoFillFormData(kPageID,
form,
- ASCIIToUTF16("cardnumber"),
- ASCIIToUTF16("First")));
+ string16(),
+ ASCIIToUTF16("Home; 8765")));
+
+ int page_id = 0;
+ FormData results;
+ EXPECT_TRUE(GetAutoFillFormDataFilledMessage(&page_id, &results));
+ EXPECT_EQ(ASCIIToUTF16("MyForm"), results.name);
+ EXPECT_EQ(ASCIIToUTF16("POST"), results.method);
+ EXPECT_EQ(GURL("http://myform.com/form.html"), results.origin);
+ EXPECT_EQ(GURL("http://myform.com/submit.html"), results.action);
+ ASSERT_EQ(11U, results.fields.size());
+
+ webkit_glue::FormField field;
+ CreateTestFormField("First Name", "firstname", "Joe", "text", &field);
+ EXPECT_TRUE(field.StrictlyEqualsHack(results.fields[0]));
+ CreateTestFormField("Middle Name", "middlename", "", "text", &field);
+ EXPECT_TRUE(field.StrictlyEqualsHack(results.fields[1]));
+ CreateTestFormField("Last Name", "lastname", "Ely", "text", &field);
+ EXPECT_TRUE(field.StrictlyEqualsHack(results.fields[2]));
+ CreateTestFormField(
+ "Address Line 1", "addr1", "916 16th St.", "text", &field);
+ EXPECT_TRUE(field.StrictlyEqualsHack(results.fields[3]));
+ CreateTestFormField(
+ "Address Line 2", "addr2", "Apt. 6", "text", &field);
+ EXPECT_TRUE(field.StrictlyEqualsHack(results.fields[4]));
+ CreateTestFormField("City", "city", "Lubbock", "text", &field);
+ EXPECT_TRUE(field.StrictlyEqualsHack(results.fields[5]));
+ CreateTestFormField("State", "state", "Texas", "text", &field);
+ EXPECT_TRUE(field.StrictlyEqualsHack(results.fields[6]));
+ CreateTestFormField("Postal Code", "zipcode", "79401", "text", &field);
+ EXPECT_TRUE(field.StrictlyEqualsHack(results.fields[7]));
+ CreateTestFormField("Country", "country", "USA", "text", &field);
+ EXPECT_TRUE(field.StrictlyEqualsHack(results.fields[8]));
+ CreateTestFormField(
+ "Phone Number", "phonenumber", "12345678901", "text", &field);
+ EXPECT_TRUE(field.StrictlyEqualsHack(results.fields[9]));
+ CreateTestFormField("Email", "email", "flatlander@gmail.com", "text", &field);
+ EXPECT_TRUE(field.StrictlyEqualsHack(results.fields[10]));
+}
+
+TEST_F(AutoFillManagerTest, FillBillFormSemicolon) {
+ AddSemicolonAutoFillProfile();
+
+ FormData form;
+ CreateTestFormDataBilling(&form);
+
+ // Set up our FormStructures.
+ std::vector<FormData> forms;
+ forms.push_back(form);
+ autofill_manager_->FormsSeen(forms);
+
+ // The page ID sent to the AutoFillManager from the RenderView, used to send
+ // an IPC message back to the renderer.
+ const int kPageID = 1;
+ EXPECT_TRUE(autofill_manager_->FillAutoFillFormData(
+ kPageID, form, string16(), ASCIIToUTF16("Home; 8765; 3456")));
int page_id = 0;
FormData results;
@@ -428,27 +625,30 @@ TEST_F(AutoFillManagerTest, FillCreditCardForm) {
ASSERT_EQ(15U, results.fields.size());
webkit_glue::FormField field;
- CreateTestFormField("First Name", "firstname", "", "text", &field);
+ CreateTestFormField("First Name", "firstname", "Joe", "text", &field);
EXPECT_TRUE(field.StrictlyEqualsHack(results.fields[0]));
CreateTestFormField("Middle Name", "middlename", "", "text", &field);
EXPECT_TRUE(field.StrictlyEqualsHack(results.fields[1]));
- CreateTestFormField("Last Name", "lastname", "", "text", &field);
+ CreateTestFormField("Last Name", "lastname", "Ely", "text", &field);
EXPECT_TRUE(field.StrictlyEqualsHack(results.fields[2]));
- CreateTestFormField("Address Line 1", "addr1", "", "text", &field);
+ CreateTestFormField("Address Line 1", "billingAddr1",
+ "3734 Elvis Presley Blvd.", "text", &field);
EXPECT_TRUE(field.StrictlyEqualsHack(results.fields[3]));
- CreateTestFormField("Address Line 2", "addr2", "", "text", &field);
+ CreateTestFormField(
+ "Address Line 2", "billingAddr2", "Apt. 10", "text", &field);
EXPECT_TRUE(field.StrictlyEqualsHack(results.fields[4]));
- CreateTestFormField("City", "city", "", "text", &field);
+ CreateTestFormField("City", "billingCity", "Memphis", "text", &field);
EXPECT_TRUE(field.StrictlyEqualsHack(results.fields[5]));
- CreateTestFormField("State", "state", "", "text", &field);
+ CreateTestFormField("State", "billingState", "Tennessee", "text", &field);
EXPECT_TRUE(field.StrictlyEqualsHack(results.fields[6]));
- CreateTestFormField("Postal Code", "zipcode", "", "text", &field);
+ CreateTestFormField("Postal Code", "billingZipcode", "38116", "text", &field);
EXPECT_TRUE(field.StrictlyEqualsHack(results.fields[7]));
- CreateTestFormField("Country", "country", "", "text", &field);
+ CreateTestFormField("Country", "billingCountry", "USA", "text", &field);
EXPECT_TRUE(field.StrictlyEqualsHack(results.fields[8]));
- CreateTestFormField("Phone Number", "phonenumber", "", "text", &field);
+ CreateTestFormField(
+ "Phone Number", "phonenumber", "12345678901", "text", &field);
EXPECT_TRUE(field.StrictlyEqualsHack(results.fields[9]));
- CreateTestFormField("Email", "email", "", "text", &field);
+ CreateTestFormField("Email", "email", "flatlander@gmail.com", "text", &field);
EXPECT_TRUE(field.StrictlyEqualsHack(results.fields[10]));
CreateTestFormField(
"Name on Card", "nameoncard", "Elvis Presley", "text", &field);
@@ -527,73 +727,6 @@ TEST_F(AutoFillManagerTest, FillPhoneNumberTest) {
work_profile->SetInfo(phone_type, saved_phone);
}
-TEST_F(AutoFillManagerTest, FillCreditCardFormWithBilling) {
- FormData form;
- CreateTestFormDataBilling(&form);
-
- // Set up our FormStructures.
- std::vector<FormData> forms;
- forms.push_back(form);
- autofill_manager_->FormsSeen(forms);
-
- // The page ID sent to the AutoFillManager from the RenderView, used to send
- // an IPC message back to the renderer.
- const int kPageID = 1;
- EXPECT_TRUE(
- autofill_manager_->FillAutoFillFormData(kPageID,
- form,
- ASCIIToUTF16("cardnumber"),
- ASCIIToUTF16("First")));
-
- int page_id = 0;
- FormData results;
- EXPECT_TRUE(GetAutoFillFormDataFilledMessage(&page_id, &results));
- EXPECT_EQ(ASCIIToUTF16("MyForm"), results.name);
- EXPECT_EQ(ASCIIToUTF16("POST"), results.method);
- EXPECT_EQ(GURL("http://myform.com/form.html"), results.origin);
- EXPECT_EQ(GURL("http://myform.com/submit.html"), results.action);
- ASSERT_EQ(15U, results.fields.size());
-
- webkit_glue::FormField field;
- CreateTestFormField("First Name", "firstname", "", "text", &field);
- EXPECT_TRUE(field.StrictlyEqualsHack(results.fields[0]));
- CreateTestFormField("Middle Name", "middlename", "", "text", &field);
- EXPECT_TRUE(field.StrictlyEqualsHack(results.fields[1]));
- CreateTestFormField("Last Name", "lastname", "", "text", &field);
- EXPECT_TRUE(field.StrictlyEqualsHack(results.fields[2]));
- CreateTestFormField(
- "Address Line 1", "billingAddr1", "3734 Elvis Presley Blvd.", "text",
- &field);
- EXPECT_TRUE(field.StrictlyEqualsHack(results.fields[3]));
- CreateTestFormField(
- "Address Line 2", "billingAddr2", "Apt. 10", "text", &field);
- EXPECT_TRUE(field.StrictlyEqualsHack(results.fields[4]));
- CreateTestFormField("City", "billingCity", "Memphis", "text", &field);
- EXPECT_TRUE(field.StrictlyEqualsHack(results.fields[5]));
- CreateTestFormField("State", "billingState", "Tennessee", "text", &field);
- EXPECT_TRUE(field.StrictlyEqualsHack(results.fields[6]));
- CreateTestFormField("Postal Code", "billingZipcode", "38116", "text", &field);
- EXPECT_TRUE(field.StrictlyEqualsHack(results.fields[7]));
- CreateTestFormField("Country", "billingCountry", "USA", "text", &field);
- EXPECT_TRUE(field.StrictlyEqualsHack(results.fields[8]));
- CreateTestFormField(
- "Phone Number", "phonenumber", "", "text", &field);
- EXPECT_TRUE(field.StrictlyEqualsHack(results.fields[9]));
- CreateTestFormField(
- "Email", "email", "", "text", &field);
- EXPECT_TRUE(field.StrictlyEqualsHack(results.fields[10]));
- CreateTestFormField(
- "Name on Card", "nameoncard", "Elvis Presley", "text", &field);
- EXPECT_TRUE(field.StrictlyEqualsHack(results.fields[11]));
- CreateTestFormField(
- "Card Number", "cardnumber", "1234567890123456", "text", &field);
- EXPECT_TRUE(field.StrictlyEqualsHack(results.fields[12]));
- CreateTestFormField("Expiration Date", "ccmonth", "04", "text", &field);
- EXPECT_TRUE(field.StrictlyEqualsHack(results.fields[13]));
- CreateTestFormField("", "ccyear", "2012", "text", &field);
- EXPECT_TRUE(field.StrictlyEqualsHack(results.fields[14]));
-}
-
TEST_F(AutoFillManagerTest, FormChangesRemoveField) {
FormData form;
form.name = ASCIIToUTF16("MyForm");
diff --git a/chrome/browser/autofill/credit_card.cc b/chrome/browser/autofill/credit_card.cc
index 7f41b5e..f694cda 100644
--- a/chrome/browser/autofill/credit_card.cc
+++ b/chrome/browser/autofill/credit_card.cc
@@ -236,6 +236,15 @@ string16 CreditCard::PreviewSummary() const {
return preview;
}
+string16 CreditCard::LastFourDigits() const {
+ static const size_t kNumLastDigits = 4;
+
+ if (number().size() < kNumLastDigits)
+ return string16();
+
+ return number().substr(number().size() - kNumLastDigits, kNumLastDigits);
+}
+
void CreditCard::operator=(const CreditCard& source) {
number_ = source.number_;
name_on_card_ = source.name_on_card_;
diff --git a/chrome/browser/autofill/credit_card.h b/chrome/browser/autofill/credit_card.h
index 50bfa3a..00e5f39 100644
--- a/chrome/browser/autofill/credit_card.h
+++ b/chrome/browser/autofill/credit_card.h
@@ -34,6 +34,8 @@ class CreditCard : public FormGroup {
string16 ObfuscatedNumber() const;
// Credit card preview summary, for example: ******1234, Exp: 01/2020
string16 PreviewSummary() const;
+ // The last four digits of the credit card number.
+ string16 LastFourDigits() const;
const string16& billing_address() const { return billing_address_; }
const string16& shipping_address() const { return shipping_address_; }
diff --git a/chrome/browser/autofill/form_structure.cc b/chrome/browser/autofill/form_structure.cc
index 75ea94b..1a6a973 100644
--- a/chrome/browser/autofill/form_structure.cc
+++ b/chrome/browser/autofill/form_structure.cc
@@ -245,6 +245,47 @@ bool FormStructure::HasAutoFillableValues() const {
if (field && !field->IsEmpty() && field->IsFieldFillable())
return true;
}
+
+ return false;
+}
+
+// TODO(jhawkins): Cache this result.
+bool FormStructure::HasBillingFields() const {
+ for (std::vector<AutoFillField*>::const_iterator iter = begin();
+ iter != end(); ++iter) {
+ if (!*iter)
+ return false;
+
+ AutoFillField* field = *iter;
+ if (!field)
+ continue;
+
+ AutoFillType type(field->type());
+ if (type.group() == AutoFillType::ADDRESS_BILLING ||
+ type.group() == AutoFillType::CREDIT_CARD)
+ return true;
+ }
+
+ return false;
+}
+
+// TODO(jhawkins): Cache this result.
+bool FormStructure::HasNonBillingFields() const {
+ for (std::vector<AutoFillField*>::const_iterator iter = begin();
+ iter != end(); ++iter) {
+ if (!*iter)
+ return false;
+
+ AutoFillField* field = *iter;
+ if (!field)
+ continue;
+
+ AutoFillType type(field->type());
+ if (type.group() != AutoFillType::ADDRESS_BILLING &&
+ type.group() != AutoFillType::CREDIT_CARD)
+ return true;
+ }
+
return false;
}
diff --git a/chrome/browser/autofill/form_structure.h b/chrome/browser/autofill/form_structure.h
index a0740a0..6537bd4 100644
--- a/chrome/browser/autofill/form_structure.h
+++ b/chrome/browser/autofill/form_structure.h
@@ -66,6 +66,14 @@ class FormStructure {
// is not empty.
bool HasAutoFillableValues() const;
+ // Returns true if at least one of the form fields is a billing field, which
+ // includes billing address fields and credit card fields.
+ bool HasBillingFields() const;
+
+ // Returns true if at least one of the form fields is a non-billing field,
+ // which includes billing address fields and credit card fields.
+ bool HasNonBillingFields() const;
+
// Resets |autofill_count_| and counts the number of auto-fillable fields.
// This is used when we receive server data for form fields. At that time,
// we may have more known fields than just the number of fields we matched