summaryrefslogtreecommitdiffstats
path: root/chrome/browser
diff options
context:
space:
mode:
authordhollowa@chromium.org <dhollowa@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2011-03-28 22:54:03 +0000
committerdhollowa@chromium.org <dhollowa@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2011-03-28 22:54:03 +0000
commit791c8c7d6aa25a182970d4c3a3c50dc88f527171 (patch)
tree31bcfb23927126d630af52f388b8540d8ed5bfc5 /chrome/browser
parent1561fd6740aedcdb6cf47703fef0de9d292c38b2 (diff)
downloadchromium_src-791c8c7d6aa25a182970d4c3a3c50dc88f527171.zip
chromium_src-791c8c7d6aa25a182970d4c3a3c50dc88f527171.tar.gz
chromium_src-791c8c7d6aa25a182970d4c3a3c50dc88f527171.tar.bz2
Autofill extend profiles to include multi-valued fields, part 3.
Adds new GetMultiInfo/SetMultiInfo methods to the AutofillProfile class and propagates the multi-valued data down through to the WebDatabase layer. Single-valued mechanisms are still in place. Some of these will be removed once Sync is updated. BUG=65625 TEST=WebDatabaseTest.*:AutofillProfileTest.* Review URL: http://codereview.chromium.org/6726042 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@79629 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome/browser')
-rw-r--r--chrome/browser/autofill/address.h2
-rw-r--r--chrome/browser/autofill/autofill_profile.cc226
-rw-r--r--chrome/browser/autofill/autofill_profile.h30
-rw-r--r--chrome/browser/autofill/autofill_profile_unittest.cc176
-rw-r--r--chrome/browser/autofill/contact_info.h6
-rw-r--r--chrome/browser/autofill/fax_number.h2
-rw-r--r--chrome/browser/autofill/home_phone_number.h2
-rw-r--r--chrome/browser/webdata/web_data_service.cc2
-rw-r--r--chrome/browser/webdata/web_database.cc324
-rw-r--r--chrome/browser/webdata/web_database.h4
-rw-r--r--chrome/browser/webdata/web_database_unittest.cc285
11 files changed, 818 insertions, 241 deletions
diff --git a/chrome/browser/autofill/address.h b/chrome/browser/autofill/address.h
index d030049..de6ac46 100644
--- a/chrome/browser/autofill/address.h
+++ b/chrome/browser/autofill/address.h
@@ -17,7 +17,7 @@
class Address : public FormGroup {
public:
Address();
- explicit Address(const Address& address);
+ Address(const Address& address);
virtual ~Address();
Address& operator=(const Address& address);
diff --git a/chrome/browser/autofill/autofill_profile.cc b/chrome/browser/autofill/autofill_profile.cc
index b8f29a1..cc0ab01 100644
--- a/chrome/browser/autofill/autofill_profile.cc
+++ b/chrome/browser/autofill/autofill_profile.cc
@@ -98,19 +98,58 @@ void GetFieldsForDistinguishingProfiles(
}
}
+// A helper function for string streaming. Concatenates multi-valued entries
+// stored for a given |type| into a single string. This string is returned.
+const string16 MultiString(const AutofillProfile& p, AutofillFieldType type) {
+ std::vector<string16> values;
+ p.GetMultiInfo(type, &values);
+ string16 accumulate;
+ for (size_t i = 0; i < values.size(); ++i) {
+ if (i > 0)
+ accumulate += ASCIIToUTF16(" ");
+ accumulate += values[i];
+ }
+ return accumulate;
+}
+
+template <class T>
+void CopyValuesToItems(AutofillFieldType type,
+ const std::vector<string16>& values,
+ std::vector<T>* form_group_items) {
+ form_group_items->resize(values.size());
+ for (size_t i = 0; i < form_group_items->size(); ++i)
+ (*form_group_items)[i].SetInfo(type, CollapseWhitespace(values[i], false));
+ // Must have at least one (possibly empty) element.
+ if (form_group_items->empty())
+ form_group_items->resize(1);
+}
+
+template <class T>
+void CopyItemsToValues(AutofillFieldType type,
+ const std::vector<T>& form_group_items,
+ std::vector<string16>* values) {
+ values->resize(form_group_items.size());
+ for (size_t i = 0; i < values->size(); ++i)
+ (*values)[i] = form_group_items[i].GetInfo(type);
+}
+
} // namespace
AutofillProfile::AutofillProfile(const std::string& guid)
- : guid_(guid) {
+ : guid_(guid), name_(1), email_(1), home_number_(1), fax_number_(1) {
}
AutofillProfile::AutofillProfile()
- : guid_(guid::GenerateGUID()) {
+ : guid_(guid::GenerateGUID()),
+ name_(1),
+ email_(1),
+ home_number_(1),
+ fax_number_(1) {
}
-AutofillProfile::AutofillProfile(const AutofillProfile& source)
+AutofillProfile::AutofillProfile(const AutofillProfile& profile)
: FormGroup() {
- operator=(source);
+ operator=(profile);
}
AutofillProfile::~AutofillProfile() {
@@ -136,14 +175,14 @@ AutofillProfile& AutofillProfile::operator=(const AutofillProfile& profile) {
void AutofillProfile::GetPossibleFieldTypes(
const string16& text,
FieldTypeSet* possible_types) const {
- FormGroupList info = info_list();
+ FormGroupList info = FormGroups();
for (FormGroupList::const_iterator it = info.begin(); it != info.end(); ++it)
(*it)->GetPossibleFieldTypes(text, possible_types);
}
void AutofillProfile::GetAvailableFieldTypes(
FieldTypeSet* available_types) const {
- FormGroupList info = info_list();
+ FormGroupList info = FormGroups();
for (FormGroupList::const_iterator it = info.begin(); it != info.end(); ++it)
(*it)->GetAvailableFieldTypes(available_types);
}
@@ -161,35 +200,73 @@ void AutofillProfile::FindInfoMatches(
// If the field_type is unknown, then match against all field types.
if (type == UNKNOWN_TYPE) {
- FormGroupList info = info_list();
+ FormGroupList info = FormGroups();
for (FormGroupList::const_iterator it = info.begin();
it != info.end(); ++it)
(*it)->FindInfoMatches(type, clean_info, matched_text);
} else {
- FormGroupMap info = info_map();
- FormGroupMap::const_iterator it = info.find(AutofillType(type).group());
- if (it != info.end())
- it->second->FindInfoMatches(type, clean_info, matched_text);
+ const FormGroup* form_group = FormGroupForType(type);
+ if (form_group)
+ form_group->FindInfoMatches(type, clean_info, matched_text);
}
}
string16 AutofillProfile::GetInfo(AutofillFieldType type) const {
AutofillFieldType return_type = AutofillType::GetEquivalentFieldType(type);
-
- FormGroupMap info = info_map();
- FormGroupMap::const_iterator it =
- info.find(AutofillType(return_type).group());
- if (it == info.end())
+ const FormGroup* form_group = FormGroupForType(return_type);
+ if (!form_group)
return string16();
- return it->second->GetInfo(return_type);
+ return form_group->GetInfo(return_type);
}
void AutofillProfile::SetInfo(AutofillFieldType type, const string16& value) {
- MutableFormGroupMap info = mutable_info_map();
- MutableFormGroupMap::iterator it = info.find(AutofillType(type).group());
- if (it != info.end())
- it->second->SetInfo(type, CollapseWhitespace(value, false));
+ FormGroup* form_group = MutableFormGroupForType(type);
+ if (form_group)
+ form_group->SetInfo(type, CollapseWhitespace(value, false));
+}
+
+void AutofillProfile::SetMultiInfo(AutofillFieldType type,
+ const std::vector<string16>& values) {
+ switch (AutofillType(type).group()) {
+ case AutofillType::NAME:
+ CopyValuesToItems(type, values, &name_);
+ break;
+ case AutofillType::EMAIL:
+ CopyValuesToItems(type, values, &email_);
+ break;
+ case AutofillType::PHONE_HOME:
+ CopyValuesToItems(type, values, &home_number_);
+ break;
+ case AutofillType::PHONE_FAX:
+ CopyValuesToItems(type, values, &fax_number_);
+ break;
+ default:
+ NOTREACHED() << "Attempt to set multiple values on single-valued field.";
+ break;
+ }
+}
+
+void AutofillProfile::GetMultiInfo(AutofillFieldType type,
+ std::vector<string16>* values) const {
+ switch (AutofillType(type).group()) {
+ case AutofillType::NAME:
+ CopyItemsToValues(type, name_, values);
+ break;
+ case AutofillType::EMAIL:
+ CopyItemsToValues(type, email_, values);
+ break;
+ case AutofillType::PHONE_HOME:
+ CopyItemsToValues(type, home_number_, values);
+ break;
+ case AutofillType::PHONE_FAX:
+ CopyItemsToValues(type, fax_number_, values);
+ break;
+ default:
+ NOTREACHED()
+ << "Attempt to get multiple values from a single-valued field.";
+ break;
+ }
}
const string16 AutofillProfile::Label() const {
@@ -300,6 +377,48 @@ int AutofillProfile::Compare(const AutofillProfile& profile) const {
return 0;
}
+int AutofillProfile::CompareMulti(const AutofillProfile& profile) const {
+ const AutofillFieldType single_value_types[] = { COMPANY_NAME,
+ ADDRESS_HOME_LINE1,
+ ADDRESS_HOME_LINE2,
+ ADDRESS_HOME_CITY,
+ ADDRESS_HOME_STATE,
+ ADDRESS_HOME_ZIP,
+ ADDRESS_HOME_COUNTRY };
+
+ for (size_t i = 0; i < arraysize(single_value_types); ++i) {
+ int comparison = GetInfo(single_value_types[i]).compare(
+ profile.GetInfo(single_value_types[i]));
+ if (comparison != 0)
+ return comparison;
+ }
+
+ const AutofillFieldType multi_value_types[] = { NAME_FIRST,
+ NAME_MIDDLE,
+ NAME_LAST,
+ EMAIL_ADDRESS,
+ PHONE_HOME_NUMBER,
+ PHONE_FAX_NUMBER };
+
+ for (size_t i = 0; i < arraysize(multi_value_types); ++i) {
+ std::vector<string16> values_a;
+ std::vector<string16> values_b;
+ GetMultiInfo(multi_value_types[i], &values_a);
+ profile.GetMultiInfo(multi_value_types[i], &values_b);
+ if (values_a.size() < values_b.size())
+ return -1;
+ if (values_a.size() > values_b.size())
+ return 1;
+ for (size_t j = 0; j < values_a.size(); ++j) {
+ int comparison = values_a[j].compare(values_b[j]);
+ if (comparison != 0)
+ return comparison;
+ }
+ }
+
+ return 0;
+}
+
bool AutofillProfile::operator==(const AutofillProfile& profile) const {
return guid_ == profile.guid_ && Compare(profile) == 0;
}
@@ -422,36 +541,47 @@ void AutofillProfile::CreateDifferentiatingLabels(
}
}
-AutofillProfile::FormGroupList AutofillProfile::info_list() const {
+AutofillProfile::FormGroupList AutofillProfile::FormGroups() const {
FormGroupList v(6);
- v[0] = &name_;
- v[1] = &email_;
+ v[0] = &name_[0];
+ v[1] = &email_[0];
v[2] = &company_;
- v[3] = &home_number_;
- v[4] = &fax_number_;
+ v[3] = &home_number_[0];
+ v[4] = &fax_number_[0];
v[5] = &address_;
return v;
}
-AutofillProfile::FormGroupMap AutofillProfile::info_map() const {
- FormGroupMap m;
- m[AutofillType::NAME] = &name_;
- m[AutofillType::EMAIL] = &email_;
- m[AutofillType::COMPANY] = &company_;
- m[AutofillType::PHONE_HOME] = &home_number_;
- m[AutofillType::PHONE_FAX] = &fax_number_;
- m[AutofillType::ADDRESS_HOME] = &address_;
- return m;
+const FormGroup* AutofillProfile::FormGroupForType(
+ AutofillFieldType type) const {
+ return const_cast<AutofillProfile*>(this)->MutableFormGroupForType(type);
}
-AutofillProfile::MutableFormGroupMap AutofillProfile::mutable_info_map() {
- FormGroupMap m_const = info_map();
- MutableFormGroupMap m;
- for (FormGroupMap::const_iterator it = m_const.begin();
- it != m_const.end(); ++it) {
- m[it->first] = const_cast<FormGroup*>(it->second);
+FormGroup* AutofillProfile::MutableFormGroupForType(AutofillFieldType type) {
+ FormGroup* form_group = NULL;
+ switch (AutofillType(type).group()) {
+ case AutofillType::NAME:
+ form_group = &name_[0];
+ break;
+ case AutofillType::EMAIL:
+ form_group = &email_[0];
+ break;
+ case AutofillType::COMPANY:
+ form_group = &company_;
+ break;
+ case AutofillType::PHONE_HOME:
+ form_group = &home_number_[0];
+ break;
+ case AutofillType::PHONE_FAX:
+ form_group = &fax_number_[0];
+ break;
+ case AutofillType::ADDRESS_HOME:
+ form_group = &address_;
+ break;
+ default:
+ break;
}
- return m;
+ return form_group;
}
// So we can compare AutofillProfiles with EXPECT_EQ().
@@ -461,13 +591,13 @@ std::ostream& operator<<(std::ostream& os, const AutofillProfile& profile) {
<< " "
<< profile.guid()
<< " "
- << UTF16ToUTF8(profile.GetInfo(NAME_FIRST))
+ << UTF16ToUTF8(MultiString(profile, NAME_FIRST))
<< " "
- << UTF16ToUTF8(profile.GetInfo(NAME_MIDDLE))
+ << UTF16ToUTF8(MultiString(profile, NAME_MIDDLE))
<< " "
- << UTF16ToUTF8(profile.GetInfo(NAME_LAST))
+ << UTF16ToUTF8(MultiString(profile, NAME_LAST))
<< " "
- << UTF16ToUTF8(profile.GetInfo(EMAIL_ADDRESS))
+ << UTF16ToUTF8(MultiString(profile, EMAIL_ADDRESS))
<< " "
<< UTF16ToUTF8(profile.GetInfo(COMPANY_NAME))
<< " "
@@ -483,7 +613,7 @@ std::ostream& operator<<(std::ostream& os, const AutofillProfile& profile) {
<< " "
<< UTF16ToUTF8(profile.GetInfo(ADDRESS_HOME_COUNTRY))
<< " "
- << UTF16ToUTF8(profile.GetInfo(PHONE_HOME_WHOLE_NUMBER))
+ << UTF16ToUTF8(MultiString(profile, PHONE_HOME_WHOLE_NUMBER))
<< " "
- << UTF16ToUTF8(profile.GetInfo(PHONE_FAX_WHOLE_NUMBER));
+ << UTF16ToUTF8(MultiString(profile, PHONE_FAX_WHOLE_NUMBER));
}
diff --git a/chrome/browser/autofill/autofill_profile.h b/chrome/browser/autofill/autofill_profile.h
index 7b8b50f..11e8bce 100644
--- a/chrome/browser/autofill/autofill_profile.h
+++ b/chrome/browser/autofill/autofill_profile.h
@@ -27,7 +27,7 @@ class AutofillProfile : public FormGroup {
// For use in STL containers.
AutofillProfile();
- AutofillProfile(const AutofillProfile&);
+ AutofillProfile(const AutofillProfile& profile);
virtual ~AutofillProfile();
AutofillProfile& operator=(const AutofillProfile& profile);
@@ -45,6 +45,12 @@ class AutofillProfile : public FormGroup {
virtual string16 GetInfo(AutofillFieldType type) const;
virtual void SetInfo(AutofillFieldType type, const string16& value);
+ // Multi-value equivalents to |GetInfo| and |SetInfo|.
+ void SetMultiInfo(AutofillFieldType type,
+ const std::vector<string16>& values);
+ void GetMultiInfo(AutofillFieldType type,
+ std::vector<string16>* values) const;
+
// The user-visible label of the profile, generated in relation to other
// profiles. Shows at least 2 fields that differentiate profile from other
// profiles. See AdjustInferredLabels() further down for more description.
@@ -95,9 +101,15 @@ class AutofillProfile : public FormGroup {
// culling duplicates. The ordering is based on collation order of the
// textual contents of the fields.
// GUIDs are not compared, only the values of the contents themselves.
+ // DEPRECATED: Use |CompareMulti| instead. |Compare| does not compare
+ // multi-valued items.
int Compare(const AutofillProfile& profile) const;
+ // Comparison for Sync. Same as |Compare| but includes multi-valued fields.
+ int CompareMulti(const AutofillProfile& profile) const;
+
// Equality operators compare GUIDs and the contents in the comparison.
+ // TODO(dhollowa): This needs to be made multi-profile once Sync updates.
bool operator==(const AutofillProfile& profile) const;
virtual bool operator!=(const AutofillProfile& profile) const;
@@ -108,8 +120,6 @@ class AutofillProfile : public FormGroup {
private:
typedef std::vector<const FormGroup*> FormGroupList;
- typedef std::map<FieldTypeGroup, const FormGroup*> FormGroupMap;
- typedef std::map<FieldTypeGroup, FormGroup*> MutableFormGroupMap;
// Builds inferred label from the first |num_fields_to_include| non-empty
// fields in |label_fields|. Uses as many fields as possible if there are not
@@ -132,9 +142,9 @@ class AutofillProfile : public FormGroup {
// Utilities for listing and lookup of the data members that constitute
// user-visible profile information.
- FormGroupList info_list() const;
- FormGroupMap info_map() const;
- MutableFormGroupMap mutable_info_map();
+ FormGroupList FormGroups() const;
+ const FormGroup* FormGroupForType(AutofillFieldType type) const;
+ FormGroup* MutableFormGroupForType(AutofillFieldType type);
// The label presented to the user when selecting a profile.
string16 label_;
@@ -143,11 +153,11 @@ class AutofillProfile : public FormGroup {
std::string guid_;
// Personal information for this profile.
- NameInfo name_;
- EmailInfo email_;
+ std::vector<NameInfo> name_;
+ std::vector<EmailInfo> email_;
CompanyInfo company_;
- HomePhoneNumber home_number_;
- FaxNumber fax_number_;
+ std::vector<HomePhoneNumber> home_number_;
+ std::vector<FaxNumber> fax_number_;
Address address_;
};
diff --git a/chrome/browser/autofill/autofill_profile_unittest.cc b/chrome/browser/autofill/autofill_profile_unittest.cc
index 5f5d214..28b5f84 100644
--- a/chrome/browser/autofill/autofill_profile_unittest.cc
+++ b/chrome/browser/autofill/autofill_profile_unittest.cc
@@ -642,3 +642,179 @@ TEST(AutofillProfileTest, CountryCode) {
profile.SetCountryCode("US");
EXPECT_EQ("US", profile.CountryCode());
}
+
+TEST(AutofillProfileTest, MultiValueNames) {
+ AutofillProfile p;
+ const string16 kJohnDoe(ASCIIToUTF16("John Doe"));
+ const string16 kJohnPDoe(ASCIIToUTF16("John P. Doe"));
+ std::vector<string16> set_values;
+ set_values.push_back(kJohnDoe);
+ set_values.push_back(kJohnPDoe);
+ p.SetMultiInfo(NAME_FULL, set_values);
+
+ // Expect regular |GetInfo| returns the first element.
+ EXPECT_EQ(kJohnDoe, p.GetInfo(NAME_FULL));
+
+ // Ensure that we get out what we put in.
+ std::vector<string16> get_values;
+ p.GetMultiInfo(NAME_FULL, &get_values);
+ ASSERT_EQ(2UL, get_values.size());
+ EXPECT_EQ(kJohnDoe, get_values[0]);
+ EXPECT_EQ(kJohnPDoe, get_values[1]);
+
+ // Update the values.
+ AutofillProfile p2 = p;
+ EXPECT_EQ(0, p.Compare(p2));
+ EXPECT_EQ(0, p.CompareMulti(p2));
+ const string16 kNoOne(ASCIIToUTF16("No One"));
+ set_values[1] = kNoOne;
+ p.SetMultiInfo(NAME_FULL, set_values);
+ p.GetMultiInfo(NAME_FULL, &get_values);
+ ASSERT_EQ(2UL, get_values.size());
+ EXPECT_EQ(kJohnDoe, get_values[0]);
+ EXPECT_EQ(kNoOne, get_values[1]);
+ EXPECT_EQ(0, p.Compare(p2));
+ EXPECT_NE(0, p.CompareMulti(p2));
+
+ // Delete values.
+ set_values.clear();
+ p.SetMultiInfo(NAME_FULL, set_values);
+ p.GetMultiInfo(NAME_FULL, &get_values);
+ ASSERT_EQ(1UL, get_values.size());
+ EXPECT_EQ(string16(), get_values[0]);
+
+ // Expect regular |GetInfo| returns empty value.
+ EXPECT_EQ(string16(), p.GetInfo(NAME_FULL));
+}
+
+TEST(AutofillProfileTest, MultiValueEmails) {
+ AutofillProfile p;
+ const string16 kJohnDoe(ASCIIToUTF16("john@doe.com"));
+ const string16 kJohnPDoe(ASCIIToUTF16("john_p@doe.com"));
+ std::vector<string16> set_values;
+ set_values.push_back(kJohnDoe);
+ set_values.push_back(kJohnPDoe);
+ p.SetMultiInfo(EMAIL_ADDRESS, set_values);
+
+ // Expect regular |GetInfo| returns the first element.
+ EXPECT_EQ(kJohnDoe, p.GetInfo(EMAIL_ADDRESS));
+
+ // Ensure that we get out what we put in.
+ std::vector<string16> get_values;
+ p.GetMultiInfo(EMAIL_ADDRESS, &get_values);
+ ASSERT_EQ(2UL, get_values.size());
+ EXPECT_EQ(kJohnDoe, get_values[0]);
+ EXPECT_EQ(kJohnPDoe, get_values[1]);
+
+ // Update the values.
+ AutofillProfile p2 = p;
+ EXPECT_EQ(0, p.Compare(p2));
+ EXPECT_EQ(0, p.CompareMulti(p2));
+ const string16 kNoOne(ASCIIToUTF16("no@one.com"));
+ set_values[1] = kNoOne;
+ p.SetMultiInfo(EMAIL_ADDRESS, set_values);
+ p.GetMultiInfo(EMAIL_ADDRESS, &get_values);
+ ASSERT_EQ(2UL, get_values.size());
+ EXPECT_EQ(kJohnDoe, get_values[0]);
+ EXPECT_EQ(kNoOne, get_values[1]);
+ EXPECT_EQ(0, p.Compare(p2));
+ EXPECT_NE(0, p.CompareMulti(p2));
+
+ // Delete values.
+ set_values.clear();
+ p.SetMultiInfo(EMAIL_ADDRESS, set_values);
+ p.GetMultiInfo(EMAIL_ADDRESS, &get_values);
+ ASSERT_EQ(1UL, get_values.size());
+ EXPECT_EQ(string16(), get_values[0]);
+
+ // Expect regular |GetInfo| returns empty value.
+ EXPECT_EQ(string16(), p.GetInfo(EMAIL_ADDRESS));
+}
+
+TEST(AutofillProfileTest, MultiValuePhone) {
+ AutofillProfile p;
+ const string16 kJohnDoe(ASCIIToUTF16("4151112222"));
+ const string16 kJohnPDoe(ASCIIToUTF16("4151113333"));
+ std::vector<string16> set_values;
+ set_values.push_back(kJohnDoe);
+ set_values.push_back(kJohnPDoe);
+ p.SetMultiInfo(PHONE_HOME_WHOLE_NUMBER, set_values);
+
+ // Expect regular |GetInfo| returns the first element.
+ EXPECT_EQ(kJohnDoe, p.GetInfo(PHONE_HOME_WHOLE_NUMBER));
+
+ // Ensure that we get out what we put in.
+ std::vector<string16> get_values;
+ p.GetMultiInfo(PHONE_HOME_WHOLE_NUMBER, &get_values);
+ ASSERT_EQ(2UL, get_values.size());
+ EXPECT_EQ(kJohnDoe, get_values[0]);
+ EXPECT_EQ(kJohnPDoe, get_values[1]);
+
+ // Update the values.
+ AutofillProfile p2 = p;
+ EXPECT_EQ(0, p.Compare(p2));
+ EXPECT_EQ(0, p.CompareMulti(p2));
+ const string16 kNoOne(ASCIIToUTF16("4151110000"));
+ set_values[1] = kNoOne;
+ p.SetMultiInfo(PHONE_HOME_WHOLE_NUMBER, set_values);
+ p.GetMultiInfo(PHONE_HOME_WHOLE_NUMBER, &get_values);
+ ASSERT_EQ(2UL, get_values.size());
+ EXPECT_EQ(kJohnDoe, get_values[0]);
+ EXPECT_EQ(kNoOne, get_values[1]);
+ EXPECT_EQ(0, p.Compare(p2));
+ EXPECT_NE(0, p.CompareMulti(p2));
+
+ // Delete values.
+ set_values.clear();
+ p.SetMultiInfo(PHONE_HOME_WHOLE_NUMBER, set_values);
+ p.GetMultiInfo(PHONE_HOME_WHOLE_NUMBER, &get_values);
+ ASSERT_EQ(1UL, get_values.size());
+ EXPECT_EQ(string16(), get_values[0]);
+
+ // Expect regular |GetInfo| returns empty value.
+ EXPECT_EQ(string16(), p.GetInfo(PHONE_HOME_WHOLE_NUMBER));
+}
+
+TEST(AutofillProfileTest, MultiValueFax) {
+ AutofillProfile p;
+ const string16 kJohnDoe(ASCIIToUTF16("4151112222"));
+ const string16 kJohnPDoe(ASCIIToUTF16("4151113333"));
+ std::vector<string16> set_values;
+ set_values.push_back(kJohnDoe);
+ set_values.push_back(kJohnPDoe);
+ p.SetMultiInfo(PHONE_FAX_WHOLE_NUMBER, set_values);
+
+ // Expect regular |GetInfo| returns the first element.
+ EXPECT_EQ(kJohnDoe, p.GetInfo(PHONE_FAX_WHOLE_NUMBER));
+
+ // Ensure that we get out what we put in.
+ std::vector<string16> get_values;
+ p.GetMultiInfo(PHONE_FAX_WHOLE_NUMBER, &get_values);
+ ASSERT_EQ(2UL, get_values.size());
+ EXPECT_EQ(kJohnDoe, get_values[0]);
+ EXPECT_EQ(kJohnPDoe, get_values[1]);
+
+ // Update the values.
+ AutofillProfile p2 = p;
+ EXPECT_EQ(0, p.Compare(p2));
+ EXPECT_EQ(0, p.CompareMulti(p2));
+ const string16 kNoOne(ASCIIToUTF16("4151110000"));
+ set_values[1] = kNoOne;
+ p.SetMultiInfo(PHONE_FAX_WHOLE_NUMBER, set_values);
+ p.GetMultiInfo(PHONE_FAX_WHOLE_NUMBER, &get_values);
+ ASSERT_EQ(2UL, get_values.size());
+ EXPECT_EQ(kJohnDoe, get_values[0]);
+ EXPECT_EQ(kNoOne, get_values[1]);
+ EXPECT_EQ(0, p.Compare(p2));
+ EXPECT_NE(0, p.CompareMulti(p2));
+
+ // Delete values.
+ set_values.clear();
+ p.SetMultiInfo(PHONE_FAX_WHOLE_NUMBER, set_values);
+ p.GetMultiInfo(PHONE_FAX_WHOLE_NUMBER, &get_values);
+ ASSERT_EQ(1UL, get_values.size());
+ EXPECT_EQ(string16(), get_values[0]);
+
+ // Expect regular |GetInfo| returns empty value.
+ EXPECT_EQ(string16(), p.GetInfo(PHONE_FAX_WHOLE_NUMBER));
+}
diff --git a/chrome/browser/autofill/contact_info.h b/chrome/browser/autofill/contact_info.h
index d01e20c..52755aa 100644
--- a/chrome/browser/autofill/contact_info.h
+++ b/chrome/browser/autofill/contact_info.h
@@ -16,7 +16,7 @@
class NameInfo : public FormGroup {
public:
NameInfo();
- explicit NameInfo(const NameInfo& info);
+ NameInfo(const NameInfo& info);
virtual ~NameInfo();
NameInfo& operator=(const NameInfo& info);
@@ -105,7 +105,7 @@ class NameInfo : public FormGroup {
class EmailInfo : public FormGroup {
public:
EmailInfo();
- explicit EmailInfo(const EmailInfo& info);
+ EmailInfo(const EmailInfo& info);
virtual ~EmailInfo();
EmailInfo& operator=(const EmailInfo& info);
@@ -127,7 +127,7 @@ class EmailInfo : public FormGroup {
class CompanyInfo : public FormGroup {
public:
CompanyInfo();
- explicit CompanyInfo(const CompanyInfo& info);
+ CompanyInfo(const CompanyInfo& info);
virtual ~CompanyInfo();
CompanyInfo& operator=(const CompanyInfo& info);
diff --git a/chrome/browser/autofill/fax_number.h b/chrome/browser/autofill/fax_number.h
index 3fdc59e..8c2eda7 100644
--- a/chrome/browser/autofill/fax_number.h
+++ b/chrome/browser/autofill/fax_number.h
@@ -13,7 +13,7 @@ class FormGroup;
class FaxNumber : public PhoneNumber {
public:
FaxNumber();
- explicit FaxNumber(const FaxNumber& fax);
+ FaxNumber(const FaxNumber& fax);
virtual ~FaxNumber();
FaxNumber& operator=(const FaxNumber& fax);
diff --git a/chrome/browser/autofill/home_phone_number.h b/chrome/browser/autofill/home_phone_number.h
index a9e0d145..8c3a10b 100644
--- a/chrome/browser/autofill/home_phone_number.h
+++ b/chrome/browser/autofill/home_phone_number.h
@@ -13,7 +13,7 @@ class FormGroup;
class HomePhoneNumber : public PhoneNumber {
public:
HomePhoneNumber();
- explicit HomePhoneNumber(const HomePhoneNumber& phone);
+ HomePhoneNumber(const HomePhoneNumber& phone);
virtual ~HomePhoneNumber();
HomePhoneNumber& operator=(const HomePhoneNumber& phone);
diff --git a/chrome/browser/webdata/web_data_service.cc b/chrome/browser/webdata/web_data_service.cc
index a610cf2..e334a03 100644
--- a/chrome/browser/webdata/web_data_service.cc
+++ b/chrome/browser/webdata/web_data_service.cc
@@ -1040,7 +1040,7 @@ void WebDataService::UpdateAutofillProfileImpl(
}
scoped_ptr<AutofillProfile> scoped_profile(original_profile);
- if (!db_->UpdateAutofillProfile(profile)) {
+ if (!db_->UpdateAutofillProfileMulti(profile)) {
NOTREACHED();
return;
}
diff --git a/chrome/browser/webdata/web_database.cc b/chrome/browser/webdata/web_database.cc
index 5b2488e..ea6b6ec 100644
--- a/chrome/browser/webdata/web_database.cc
+++ b/chrome/browser/webdata/web_database.cc
@@ -330,38 +330,96 @@ AutofillProfile* AutofillProfileFromStatement(const sql::Statement& s) {
return profile;
}
-void AddAutofillProfileNameFromStatement(const sql::Statement& s,
+bool AddAutofillProfileNamesToProfile(sql::Connection* db,
AutofillProfile* profile) {
- DCHECK_EQ(profile->guid(), s.ColumnString(0));
- DCHECK(guid::IsValidGUID(profile->guid()));
+ sql::Statement s(db->GetUniqueStatement(
+ "SELECT guid, first_name, middle_name, last_name "
+ "FROM autofill_profile_names "
+ "WHERE guid=?"));
+ if (!s) {
+ NOTREACHED() << "Statement prepare failed";
+ return false;
+ }
+ s.BindString(0, profile->guid());
- profile->SetInfo(NAME_FIRST, s.ColumnString16(1));
- profile->SetInfo(NAME_MIDDLE, s.ColumnString16(2));
- profile->SetInfo(NAME_LAST, s.ColumnString16(3));
+ std::vector<string16> first_names;
+ std::vector<string16> middle_names;
+ std::vector<string16> last_names;
+ while (s.Step()) {
+ DCHECK_EQ(profile->guid(), s.ColumnString(0));
+ first_names.push_back(s.ColumnString16(1));
+ middle_names.push_back(s.ColumnString16(2));
+ last_names.push_back(s.ColumnString16(3));
+ }
+ profile->SetMultiInfo(NAME_FIRST, first_names);
+ profile->SetMultiInfo(NAME_MIDDLE, middle_names);
+ profile->SetMultiInfo(NAME_LAST, last_names);
+ return true;
}
-void AddAutofillProfileEmailFromStatement(const sql::Statement& s,
+bool AddAutofillProfileEmailsToProfile(sql::Connection* db,
AutofillProfile* profile) {
- DCHECK_EQ(profile->guid(), s.ColumnString(0));
- DCHECK(guid::IsValidGUID(profile->guid()));
+ sql::Statement s(db->GetUniqueStatement(
+ "SELECT guid, email "
+ "FROM autofill_profile_emails "
+ "WHERE guid=?"));
+ if (!s) {
+ NOTREACHED() << "Statement prepare failed";
+ return false;
+ }
+ s.BindString(0, profile->guid());
- profile->SetInfo(EMAIL_ADDRESS, s.ColumnString16(1));
+ std::vector<string16> emails;
+ while (s.Step()) {
+ DCHECK_EQ(profile->guid(), s.ColumnString(0));
+ emails.push_back(s.ColumnString16(1));
+ }
+ profile->SetMultiInfo(EMAIL_ADDRESS, emails);
+ return true;
}
-void AddAutofillProfilePhoneFromStatement(const sql::Statement& s,
+bool AddAutofillProfilePhonesToProfile(sql::Connection* db,
AutofillProfile* profile) {
- DCHECK_EQ(profile->guid(), s.ColumnString(0));
- DCHECK(guid::IsValidGUID(profile->guid()));
- DCHECK_EQ(kAutofillPhoneNumber, s.ColumnInt(1));
- profile->SetInfo(PHONE_HOME_WHOLE_NUMBER, s.ColumnString16(2));
+ sql::Statement s(db->GetUniqueStatement(
+ "SELECT guid, type, number "
+ "FROM autofill_profile_phones "
+ "WHERE guid=? AND type=?"));
+ if (!s) {
+ NOTREACHED() << "Statement prepare failed";
+ return false;
+ }
+ s.BindString(0, profile->guid());
+ s.BindInt(1, kAutofillPhoneNumber);
+
+ std::vector<string16> numbers;
+ while (s.Step()) {
+ DCHECK_EQ(profile->guid(), s.ColumnString(0));
+ numbers.push_back(s.ColumnString16(2));
+ }
+ profile->SetMultiInfo(PHONE_HOME_WHOLE_NUMBER, numbers);
+ return true;
}
-void AddAutofillProfileFaxFromStatement(const sql::Statement& s,
- AutofillProfile* profile) {
- DCHECK_EQ(profile->guid(), s.ColumnString(0));
- DCHECK(guid::IsValidGUID(profile->guid()));
- DCHECK_EQ(kAutofillFaxNumber, s.ColumnInt(1));
- profile->SetInfo(PHONE_FAX_WHOLE_NUMBER, s.ColumnString16(2));
+bool AddAutofillProfileFaxesToProfile(sql::Connection* db,
+ AutofillProfile* profile) {
+ sql::Statement s(db->GetUniqueStatement(
+ "SELECT guid, type, number "
+ "FROM autofill_profile_phones "
+ "WHERE guid=? AND type=?"));
+ if (!s) {
+ NOTREACHED() << "Statement prepare failed";
+ return false;
+ }
+ s.BindString(0, profile->guid());
+ s.BindInt(1, kAutofillFaxNumber);
+
+ std::vector<string16> numbers;
+ while (s.Step()) {
+ DCHECK_EQ(profile->guid(), s.ColumnString(0));
+ numbers.push_back(s.ColumnString16(2));
+ }
+ profile->SetMultiInfo(PHONE_FAX_WHOLE_NUMBER, numbers);
+ return true;
}
void BindCreditCardToStatement(const CreditCard& credit_card,
@@ -408,33 +466,18 @@ CreditCard* CreditCardFromStatement(const sql::Statement& s) {
return credit_card;
}
-bool AutofillProfileHasName(const AutofillProfile& profile) {
- return !profile.GetInfo(NAME_FIRST).empty() ||
- !profile.GetInfo(NAME_MIDDLE).empty() ||
- !profile.GetInfo(NAME_MIDDLE).empty();
-}
-
-bool AddAutofillProfileName(const std::string& guid,
- const AutofillProfile& profile,
- sql::Connection* db) {
- if (!AutofillProfileHasName(profile))
- return true;
-
- // Check for duplicate.
- sql::Statement s_find(db->GetUniqueStatement(
- "SELECT guid, first_name, middle_name, last_name "
- "FROM autofill_profile_names "
- "WHERE guid=? AND first_name=? AND middle_name=? AND last_name=?"));
- if (!s_find) {
- NOTREACHED();
- return false;
- }
- s_find.BindString(0, guid);
- s_find.BindString16(1, profile.GetInfo(NAME_FIRST));
- s_find.BindString16(2, profile.GetInfo(NAME_MIDDLE));
- s_find.BindString16(3, profile.GetInfo(NAME_LAST));
-
- if (!s_find.Step()) {
+bool AddAutofillProfileNames(const AutofillProfile& profile,
+ sql::Connection* db) {
+ std::vector<string16> first_names;
+ profile.GetMultiInfo(NAME_FIRST, &first_names);
+ std::vector<string16> middle_names;
+ profile.GetMultiInfo(NAME_MIDDLE, &middle_names);
+ std::vector<string16> last_names;
+ profile.GetMultiInfo(NAME_LAST, &last_names);
+ DCHECK_EQ(first_names.size(), middle_names.size());
+ DCHECK_EQ(middle_names.size(), last_names.size());
+
+ for (size_t i = 0; i < first_names.size(); ++i) {
// Add the new name.
sql::Statement s(db->GetUniqueStatement(
"INSERT INTO autofill_profile_names"
@@ -444,10 +487,10 @@ bool AddAutofillProfileName(const std::string& guid,
NOTREACHED();
return false;
}
- s.BindString(0, guid);
- s.BindString16(1, profile.GetInfo(NAME_FIRST));
- s.BindString16(2, profile.GetInfo(NAME_MIDDLE));
- s.BindString16(3, profile.GetInfo(NAME_LAST));
+ s.BindString(0, profile.guid());
+ s.BindString16(1, first_names[i]);
+ s.BindString16(2, middle_names[i]);
+ s.BindString16(3, last_names[i]);
if (!s.Run()) {
NOTREACHED();
@@ -457,25 +500,13 @@ bool AddAutofillProfileName(const std::string& guid,
return true;
}
-bool AddAutofillProfileEmail(const std::string& guid,
- const AutofillProfile& profile,
- sql::Connection* db) {
- if (profile.GetInfo(EMAIL_ADDRESS).empty())
- return true;
-
- // Check for duplicate.
- sql::Statement s_find(db->GetUniqueStatement(
- "SELECT guid, email "
- "FROM autofill_profile_emails "
- "WHERE guid=? AND email=?"));
- if (!s_find) {
- NOTREACHED();
- return false;
- }
- s_find.BindString(0, guid);
- s_find.BindString16(1, profile.GetInfo(EMAIL_ADDRESS));
+bool AddAutofillProfileEmails(const AutofillProfile& profile,
+ sql::Connection* db) {
+ std::vector<string16> emails;
+ profile.GetMultiInfo(EMAIL_ADDRESS, &emails);
- if (!s_find.Step()) {
+ for (size_t i = 0; i < emails.size(); ++i) {
+ // Add the new email.
sql::Statement s(db->GetUniqueStatement(
"INSERT INTO autofill_profile_emails"
" (guid, email) "
@@ -484,8 +515,8 @@ bool AddAutofillProfileEmail(const std::string& guid,
NOTREACHED();
return false;
}
- s.BindString(0, guid);
- s.BindString16(1, profile.GetInfo(EMAIL_ADDRESS));
+ s.BindString(0, profile.guid());
+ s.BindString16(1, emails[i]);
if (!s.Run()) {
NOTREACHED();
@@ -495,10 +526,9 @@ bool AddAutofillProfileEmail(const std::string& guid,
return true;
}
-bool AddAutofillProfilePhone(const std::string& guid,
- const AutofillProfile& profile,
- AutofillPhoneType phone_type,
- sql::Connection* db) {
+bool AddAutofillProfilePhones(const AutofillProfile& profile,
+ AutofillPhoneType phone_type,
+ sql::Connection* db) {
AutofillFieldType field_type;
if (phone_type == kAutofillPhoneNumber) {
field_type = PHONE_HOME_WHOLE_NUMBER;
@@ -509,34 +539,22 @@ bool AddAutofillProfilePhone(const std::string& guid,
return false;
}
- if (profile.GetInfo(field_type).empty())
- return true;
+ std::vector<string16> numbers;
+ profile.GetMultiInfo(field_type, &numbers);
- // Check for duplicate.
- sql::Statement s_find(db->GetUniqueStatement(
- "SELECT guid, type, number "
- "FROM autofill_profile_phones "
- "WHERE guid=? AND type=? AND number=?"));
- if (!s_find) {
- NOTREACHED();
- return false;
- }
- s_find.BindString(0, guid);
- s_find.BindInt(1, phone_type);
- s_find.BindString16(2, profile.GetInfo(field_type));
-
- if (!s_find.Step()) {
+ for (size_t i = 0; i < numbers.size(); ++i) {
+ // Add the new number.
sql::Statement s(db->GetUniqueStatement(
"INSERT INTO autofill_profile_phones"
" (guid, type, number) "
"VALUES (?,?,?)"));
if (!s) {
NOTREACHED();
- return sql::INIT_FAILURE;
+ return false;
}
- s.BindString(0, guid);
+ s.BindString(0, profile.guid());
s.BindInt(1, phone_type);
- s.BindString16(2, profile.GetInfo(field_type));
+ s.BindString16(2, numbers[i]);
if (!s.Run()) {
NOTREACHED();
@@ -546,19 +564,18 @@ bool AddAutofillProfilePhone(const std::string& guid,
return true;
}
-bool AddAutofillProfilePieces(const std::string& guid,
- const AutofillProfile& profile,
+bool AddAutofillProfilePieces(const AutofillProfile& profile,
sql::Connection* db) {
- if (!AddAutofillProfileName(guid, profile, db))
+ if (!AddAutofillProfileNames(profile, db))
return false;
- if (!AddAutofillProfileEmail(guid, profile, db))
+ if (!AddAutofillProfileEmails(profile, db))
return false;
- if (!AddAutofillProfilePhone(guid, profile, kAutofillPhoneNumber, db))
+ if (!AddAutofillProfilePhones(profile, kAutofillPhoneNumber, db))
return false;
- if (!AddAutofillProfilePhone(guid, profile, kAutofillFaxNumber, db))
+ if (!AddAutofillProfilePhones(profile, kAutofillFaxNumber, db))
return false;
return true;
@@ -1894,7 +1911,7 @@ bool WebDatabase::AddAutofillProfile(const AutofillProfile& profile) {
if (!s.Succeeded())
return false;
- return AddAutofillProfilePieces(profile.guid(), profile, &db_);
+ return AddAutofillProfilePieces(profile, &db_);
}
bool WebDatabase::GetAutofillProfile(const std::string& guid,
@@ -1921,66 +1938,16 @@ bool WebDatabase::GetAutofillProfile(const std::string& guid,
scoped_ptr<AutofillProfile> p(AutofillProfileFromStatement(s));
// Get associated name info.
- sql::Statement s2(db_.GetUniqueStatement(
- "SELECT guid, first_name, middle_name, last_name "
- "FROM autofill_profile_names "
- "WHERE guid=?"));
- if (!s2) {
- NOTREACHED() << "Statement prepare failed";
- return false;
- }
- s2.BindString(0, guid);
-
- if (s2.Step()) {
- AddAutofillProfileNameFromStatement(s2, p.get());
- }
+ AddAutofillProfileNamesToProfile(&db_, p.get());
// Get associated email info.
- sql::Statement s3(db_.GetUniqueStatement(
- "SELECT guid, email "
- "FROM autofill_profile_emails "
- "WHERE guid=?"));
- if (!s3) {
- NOTREACHED() << "Statement prepare failed";
- return false;
- }
- s3.BindString(0, guid);
-
- if (s3.Step()) {
- AddAutofillProfileEmailFromStatement(s3, p.get());
- }
+ AddAutofillProfileEmailsToProfile(&db_, p.get());
// Get associated phone info.
- sql::Statement s4(db_.GetUniqueStatement(
- "SELECT guid, type, number "
- "FROM autofill_profile_phones "
- "WHERE guid=? AND type=?"));
- if (!s4) {
- NOTREACHED() << "Statement prepare failed";
- return false;
- }
- s4.BindString(0, guid);
- s4.BindInt(1, kAutofillPhoneNumber);
-
- if (s4.Step()) {
- AddAutofillProfilePhoneFromStatement(s4, p.get());
- }
+ AddAutofillProfilePhonesToProfile(&db_, p.get());
// Get associated fax info.
- sql::Statement s5(db_.GetUniqueStatement(
- "SELECT guid, type, number "
- "FROM autofill_profile_phones "
- "WHERE guid=? AND type=?"));
- if (!s5) {
- NOTREACHED() << "Statement prepare failed";
- return false;
- }
- s5.BindString(0, guid);
- s5.BindInt(1, kAutofillFaxNumber);
-
- if (s5.Step()) {
- AddAutofillProfileFaxFromStatement(s5, p.get());
- }
+ AddAutofillProfileFaxesToProfile(&db_, p.get());
*profile = p.release();
return true;
@@ -2024,7 +1991,46 @@ bool WebDatabase::UpdateAutofillProfile(const AutofillProfile& profile) {
// Preserve appropriate modification dates by not updating unchanged profiles.
scoped_ptr<AutofillProfile> old_profile(tmp_profile);
- if (*old_profile == profile)
+ if (old_profile->Compare(profile) == 0)
+ return true;
+
+ AutofillProfile new_profile(profile);
+ std::vector<string16> values;
+
+ old_profile->GetMultiInfo(NAME_FULL, &values);
+ values[0] = new_profile.GetInfo(NAME_FULL);
+ new_profile.SetMultiInfo(NAME_FULL, values);
+
+ old_profile->GetMultiInfo(EMAIL_ADDRESS, &values);
+ values[0] = new_profile.GetInfo(EMAIL_ADDRESS);
+ new_profile.SetMultiInfo(EMAIL_ADDRESS, values);
+
+ old_profile->GetMultiInfo(PHONE_HOME_WHOLE_NUMBER, &values);
+ values[0] = new_profile.GetInfo(PHONE_HOME_WHOLE_NUMBER);
+ new_profile.SetMultiInfo(PHONE_HOME_WHOLE_NUMBER, values);
+
+ old_profile->GetMultiInfo(PHONE_FAX_WHOLE_NUMBER, &values);
+ values[0] = new_profile.GetInfo(PHONE_FAX_WHOLE_NUMBER);
+ new_profile.SetMultiInfo(PHONE_FAX_WHOLE_NUMBER, values);
+
+ return UpdateAutofillProfileMulti(new_profile);
+}
+
+bool WebDatabase::UpdateAutofillProfileMulti(const AutofillProfile& profile) {
+ DCHECK(guid::IsValidGUID(profile.guid()));
+
+ // Don't update anything until the trash has been emptied. There may be
+ // pending modifications to process.
+ if (!IsAutofillProfilesTrashEmpty())
+ return true;
+
+ AutofillProfile* tmp_profile = NULL;
+ if (!GetAutofillProfile(profile.guid(), &tmp_profile))
+ return false;
+
+ // Preserve appropriate modification dates by not updating unchanged profiles.
+ scoped_ptr<AutofillProfile> old_profile(tmp_profile);
+ if (old_profile->CompareMulti(profile) == 0)
return true;
sql::Statement s(db_.GetUniqueStatement(
@@ -2049,7 +2055,7 @@ bool WebDatabase::UpdateAutofillProfile(const AutofillProfile& profile) {
if (!RemoveAutofillProfilePieces(profile.guid(), &db_))
return false;
- return AddAutofillProfilePieces(profile.guid(), profile, &db_);
+ return AddAutofillProfilePieces(profile, &db_);
}
bool WebDatabase::RemoveAutofillProfile(const std::string& guid) {
@@ -3103,7 +3109,7 @@ sql::InitStatus WebDatabase::MigrateOldVersionsAsNeeded(){
}
// Add the other bits: names, emails, and phone/fax.
- if (!AddAutofillProfilePieces(profile.guid(), profile, &db_)) {
+ if (!AddAutofillProfilePieces(profile, &db_)) {
NOTREACHED();
return sql::INIT_FAILURE;
}
diff --git a/chrome/browser/webdata/web_database.h b/chrome/browser/webdata/web_database.h
index f5aeaa4..71138cd 100644
--- a/chrome/browser/webdata/web_database.h
+++ b/chrome/browser/webdata/web_database.h
@@ -225,8 +225,12 @@ class WebDatabase {
virtual bool AddAutofillProfile(const AutofillProfile& profile);
// Updates the database values for the specified profile.
+ // DEPRECATED: Use |UpdateAutofillProfileMulti| instead.
virtual bool UpdateAutofillProfile(const AutofillProfile& profile);
+ // Updates the database values for the specified profile. Mulit-value aware.
+ virtual bool UpdateAutofillProfileMulti(const AutofillProfile& profile);
+
// Removes a row from the autofill_profiles table. |guid| is the identifier
// of the profile to remove.
virtual bool RemoveAutofillProfile(const std::string& guid);
diff --git a/chrome/browser/webdata/web_database_unittest.cc b/chrome/browser/webdata/web_database_unittest.cc
index f8cbc6e..0601954 100644
--- a/chrome/browser/webdata/web_database_unittest.cc
+++ b/chrome/browser/webdata/web_database_unittest.cc
@@ -1464,7 +1464,7 @@ TEST_F(WebDatabaseTest, AutofillProfile) {
// Update the 'Billing' profile, name only.
billing_profile.SetInfo(NAME_FIRST, ASCIIToUTF16("Jane"));
Time pre_modification_time = Time::Now();
- EXPECT_TRUE(db.UpdateAutofillProfile(billing_profile));
+ EXPECT_TRUE(db.UpdateAutofillProfileMulti(billing_profile));
Time post_modification_time = Time::Now();
ASSERT_TRUE(db.GetAutofillProfile(billing_profile.guid(), &db_profile));
EXPECT_EQ(billing_profile, *db_profile);
@@ -1495,7 +1495,7 @@ TEST_F(WebDatabaseTest, AutofillProfile) {
billing_profile.SetInfo(PHONE_HOME_WHOLE_NUMBER, ASCIIToUTF16("18181230000"));
billing_profile.SetInfo(PHONE_FAX_WHOLE_NUMBER, ASCIIToUTF16("1915240000"));
Time pre_modification_time_2 = Time::Now();
- EXPECT_TRUE(db.UpdateAutofillProfile(billing_profile));
+ EXPECT_TRUE(db.UpdateAutofillProfileMulti(billing_profile));
Time post_modification_time_2 = Time::Now();
ASSERT_TRUE(db.GetAutofillProfile(billing_profile.guid(), &db_profile));
EXPECT_EQ(billing_profile, *db_profile);
@@ -1516,6 +1516,208 @@ TEST_F(WebDatabaseTest, AutofillProfile) {
EXPECT_FALSE(db.GetAutofillProfile(billing_profile.guid(), &db_profile));
}
+TEST_F(WebDatabaseTest, AutofillProfileMultiValueNames) {
+ WebDatabase db;
+ ASSERT_EQ(sql::INIT_OK, db.Init(file_));
+
+ AutofillProfile p;
+ const string16 kJohnDoe(ASCIIToUTF16("John Doe"));
+ const string16 kJohnPDoe(ASCIIToUTF16("John P. Doe"));
+ std::vector<string16> set_values;
+ set_values.push_back(kJohnDoe);
+ set_values.push_back(kJohnPDoe);
+ p.SetMultiInfo(NAME_FULL, set_values);
+
+ EXPECT_TRUE(db.AddAutofillProfile(p));
+
+ AutofillProfile* db_profile;
+ ASSERT_TRUE(db.GetAutofillProfile(p.guid(), &db_profile));
+ EXPECT_EQ(p, *db_profile);
+ EXPECT_EQ(0, p.CompareMulti(*db_profile));
+ delete db_profile;
+
+ // Update the values.
+ const string16 kNoOne(ASCIIToUTF16("No One"));
+ set_values[1] = kNoOne;
+ p.SetMultiInfo(NAME_FULL, set_values);
+ EXPECT_TRUE(db.UpdateAutofillProfileMulti(p));
+ ASSERT_TRUE(db.GetAutofillProfile(p.guid(), &db_profile));
+ EXPECT_EQ(p, *db_profile);
+ EXPECT_EQ(0, p.CompareMulti(*db_profile));
+ delete db_profile;
+
+ // Delete values.
+ set_values.clear();
+ p.SetMultiInfo(NAME_FULL, set_values);
+ EXPECT_TRUE(db.UpdateAutofillProfileMulti(p));
+ ASSERT_TRUE(db.GetAutofillProfile(p.guid(), &db_profile));
+ EXPECT_EQ(p, *db_profile);
+ EXPECT_EQ(0, p.CompareMulti(*db_profile));
+ EXPECT_EQ(string16(), db_profile->GetInfo(NAME_FULL));
+ delete db_profile;
+}
+
+TEST_F(WebDatabaseTest, AutofillProfileSingleValue) {
+ WebDatabase db;
+ ASSERT_EQ(sql::INIT_OK, db.Init(file_));
+
+ AutofillProfile p;
+ const string16 kJohnDoe(ASCIIToUTF16("John Doe"));
+ const string16 kJohnPDoe(ASCIIToUTF16("John P. Doe"));
+ std::vector<string16> set_values;
+ set_values.push_back(kJohnDoe);
+ set_values.push_back(kJohnPDoe);
+ p.SetMultiInfo(NAME_FULL, set_values);
+
+ EXPECT_TRUE(db.AddAutofillProfile(p));
+
+ AutofillProfile* db_profile;
+ ASSERT_TRUE(db.GetAutofillProfile(p.guid(), &db_profile));
+ EXPECT_EQ(p, *db_profile);
+ EXPECT_EQ(0, p.CompareMulti(*db_profile));
+ delete db_profile;
+
+ // Update the values. This update is the "single value" update, it should
+ // not perturb the multi-values following the zeroth entry. This simulates
+ // the Sync use-case until Sync can be changed to be multi-value aware.
+ const string16 kNoOne(ASCIIToUTF16("No One"));
+ set_values.resize(1);
+ set_values[0] = kNoOne;
+ p.SetMultiInfo(NAME_FULL, set_values);
+ EXPECT_TRUE(db.UpdateAutofillProfile(p));
+ ASSERT_TRUE(db.GetAutofillProfile(p.guid(), &db_profile));
+ EXPECT_EQ(p, *db_profile);
+ EXPECT_NE(0, p.CompareMulti(*db_profile));
+ db_profile->GetMultiInfo(NAME_FULL, &set_values);
+ ASSERT_EQ(2UL, set_values.size());
+ EXPECT_EQ(kNoOne, set_values[0]);
+ EXPECT_EQ(kJohnPDoe, set_values[1]);
+ delete db_profile;
+}
+
+TEST_F(WebDatabaseTest, AutofillProfileMultiValueEmails) {
+ WebDatabase db;
+ ASSERT_EQ(sql::INIT_OK, db.Init(file_));
+
+ AutofillProfile p;
+ const string16 kJohnDoe(ASCIIToUTF16("john@doe.com"));
+ const string16 kJohnPDoe(ASCIIToUTF16("john_p@doe.com"));
+ std::vector<string16> set_values;
+ set_values.push_back(kJohnDoe);
+ set_values.push_back(kJohnPDoe);
+ p.SetMultiInfo(EMAIL_ADDRESS, set_values);
+
+ EXPECT_TRUE(db.AddAutofillProfile(p));
+
+ AutofillProfile* db_profile;
+ ASSERT_TRUE(db.GetAutofillProfile(p.guid(), &db_profile));
+ EXPECT_EQ(p, *db_profile);
+ EXPECT_EQ(0, p.CompareMulti(*db_profile));
+ delete db_profile;
+
+ // Update the values.
+ const string16 kNoOne(ASCIIToUTF16("no@one.com"));
+ set_values[1] = kNoOne;
+ p.SetMultiInfo(EMAIL_ADDRESS, set_values);
+ EXPECT_TRUE(db.UpdateAutofillProfileMulti(p));
+ ASSERT_TRUE(db.GetAutofillProfile(p.guid(), &db_profile));
+ EXPECT_EQ(p, *db_profile);
+ EXPECT_EQ(0, p.CompareMulti(*db_profile));
+ delete db_profile;
+
+ // Delete values.
+ set_values.clear();
+ p.SetMultiInfo(EMAIL_ADDRESS, set_values);
+ EXPECT_TRUE(db.UpdateAutofillProfileMulti(p));
+ ASSERT_TRUE(db.GetAutofillProfile(p.guid(), &db_profile));
+ EXPECT_EQ(p, *db_profile);
+ EXPECT_EQ(0, p.CompareMulti(*db_profile));
+ EXPECT_EQ(string16(), db_profile->GetInfo(EMAIL_ADDRESS));
+ delete db_profile;
+}
+
+TEST_F(WebDatabaseTest, AutofillProfileMultiValuePhone) {
+ WebDatabase db;
+ ASSERT_EQ(sql::INIT_OK, db.Init(file_));
+
+ AutofillProfile p;
+ const string16 kJohnDoe(ASCIIToUTF16("4151112222"));
+ const string16 kJohnPDoe(ASCIIToUTF16("4151113333"));
+ std::vector<string16> set_values;
+ set_values.push_back(kJohnDoe);
+ set_values.push_back(kJohnPDoe);
+ p.SetMultiInfo(PHONE_HOME_WHOLE_NUMBER, set_values);
+
+ EXPECT_TRUE(db.AddAutofillProfile(p));
+
+ AutofillProfile* db_profile;
+ ASSERT_TRUE(db.GetAutofillProfile(p.guid(), &db_profile));
+ EXPECT_EQ(p, *db_profile);
+ EXPECT_EQ(0, p.CompareMulti(*db_profile));
+ delete db_profile;
+
+ // Update the values.
+ const string16 kNoOne(ASCIIToUTF16("4151110000"));
+ set_values[1] = kNoOne;
+ p.SetMultiInfo(PHONE_HOME_WHOLE_NUMBER, set_values);
+ EXPECT_TRUE(db.UpdateAutofillProfileMulti(p));
+ ASSERT_TRUE(db.GetAutofillProfile(p.guid(), &db_profile));
+ EXPECT_EQ(p, *db_profile);
+ EXPECT_EQ(0, p.CompareMulti(*db_profile));
+ delete db_profile;
+
+ // Delete values.
+ set_values.clear();
+ p.SetMultiInfo(PHONE_HOME_WHOLE_NUMBER, set_values);
+ EXPECT_TRUE(db.UpdateAutofillProfileMulti(p));
+ ASSERT_TRUE(db.GetAutofillProfile(p.guid(), &db_profile));
+ EXPECT_EQ(p, *db_profile);
+ EXPECT_EQ(0, p.CompareMulti(*db_profile));
+ EXPECT_EQ(string16(), db_profile->GetInfo(EMAIL_ADDRESS));
+ delete db_profile;
+}
+
+TEST_F(WebDatabaseTest, AutofillProfileMultiValueFax) {
+ WebDatabase db;
+ ASSERT_EQ(sql::INIT_OK, db.Init(file_));
+
+ AutofillProfile p;
+ const string16 kJohnDoe(ASCIIToUTF16("4151112222"));
+ const string16 kJohnPDoe(ASCIIToUTF16("4151113333"));
+ std::vector<string16> set_values;
+ set_values.push_back(kJohnDoe);
+ set_values.push_back(kJohnPDoe);
+ p.SetMultiInfo(PHONE_FAX_WHOLE_NUMBER, set_values);
+
+ EXPECT_TRUE(db.AddAutofillProfile(p));
+
+ AutofillProfile* db_profile;
+ ASSERT_TRUE(db.GetAutofillProfile(p.guid(), &db_profile));
+ EXPECT_EQ(p, *db_profile);
+ EXPECT_EQ(0, p.CompareMulti(*db_profile));
+ delete db_profile;
+
+ // Update the values.
+ const string16 kNoOne(ASCIIToUTF16("4151110000"));
+ set_values[1] = kNoOne;
+ p.SetMultiInfo(PHONE_FAX_WHOLE_NUMBER, set_values);
+ EXPECT_TRUE(db.UpdateAutofillProfileMulti(p));
+ ASSERT_TRUE(db.GetAutofillProfile(p.guid(), &db_profile));
+ EXPECT_EQ(p, *db_profile);
+ EXPECT_EQ(0, p.CompareMulti(*db_profile));
+ delete db_profile;
+
+ // Delete values.
+ set_values.clear();
+ p.SetMultiInfo(PHONE_FAX_WHOLE_NUMBER, set_values);
+ EXPECT_TRUE(db.UpdateAutofillProfileMulti(p));
+ ASSERT_TRUE(db.GetAutofillProfile(p.guid(), &db_profile));
+ EXPECT_EQ(p, *db_profile);
+ EXPECT_EQ(0, p.CompareMulti(*db_profile));
+ EXPECT_EQ(string16(), db_profile->GetInfo(EMAIL_ADDRESS));
+ delete db_profile;
+}
+
TEST_F(WebDatabaseTest, AutofillProfileTrash) {
WebDatabase db;
@@ -1576,12 +1778,12 @@ TEST_F(WebDatabaseTest, AutofillProfileTrashInteraction) {
ASSERT_NE(static_cast<AutofillProfile*>(NULL), added_profile);
delete added_profile;
- // Mark this profile as in the trash. This stops |UpdateAutofillProfile| from
- // updating it. In normal operation a profile should not be both in the trash
- // and in the profiles table simultaneously.
+ // Mark this profile as in the trash. This stops |UpdateAutofillProfileMulti|
+ // from updating it. In normal operation a profile should not be both in the
+ // trash and in the profiles table simultaneously.
EXPECT_TRUE(db.AddAutofillGUIDToTrash(profile.guid()));
profile.SetInfo(NAME_FIRST, ASCIIToUTF16("Jane"));
- EXPECT_TRUE(db.UpdateAutofillProfile(profile));
+ EXPECT_TRUE(db.UpdateAutofillProfileMulti(profile));
AutofillProfile* updated_profile = NULL;
EXPECT_TRUE(db.GetAutofillProfile(profile.guid(), &updated_profile));
ASSERT_NE(static_cast<AutofillProfile*>(NULL), added_profile);
@@ -1734,7 +1936,7 @@ TEST_F(WebDatabaseTest, UpdateAutofillProfile) {
// Now, update the profile and save the update to the database.
// The modification date should change to reflect the update.
profile.SetInfo(EMAIL_ADDRESS, ASCIIToUTF16("js@smith.xyz"));
- db.UpdateAutofillProfile(profile);
+ db.UpdateAutofillProfileMulti(profile);
// Get the profile.
ASSERT_TRUE(db.GetAutofillProfile(profile.guid(), &tmp_profile));
@@ -1755,9 +1957,9 @@ TEST_F(WebDatabaseTest, UpdateAutofillProfile) {
s_mock_modification_date.BindInt64(0, mock_modification_date);
ASSERT_TRUE(s_mock_modification_date.Run());
- // Finally, call into |UpdateAutofillProfile()| without changing the profile.
- // The modification date should not change.
- db.UpdateAutofillProfile(profile);
+ // Finally, call into |UpdateAutofillProfileMulti()| without changing the
+ // profile. The modification date should not change.
+ db.UpdateAutofillProfileMulti(profile);
// Get the profile.
ASSERT_TRUE(db.GetAutofillProfile(profile.guid(), &tmp_profile));
@@ -3095,7 +3297,12 @@ TEST_F(WebDatabaseMigrationTest, MigrateVersion32ToCurrent) {
// Alfred E Newman.
// Gets culled during migration from 35 to 36 due to incomplete address.
- // Note no name for 3 Main St.
+ // 3 Main St.
+ ASSERT_TRUE(s2.Step());
+ EXPECT_EQ("9E5FE298-62C7-83DF-6293-381BC589183F", s2.ColumnString(0));
+ EXPECT_EQ(ASCIIToUTF16(""), s2.ColumnString16(1));
+ EXPECT_EQ(ASCIIToUTF16(""), s2.ColumnString16(2));
+ EXPECT_EQ(ASCIIToUTF16(""), s2.ColumnString16(3));
// Should be all.
EXPECT_FALSE(s2.Step());
@@ -3115,13 +3322,23 @@ TEST_F(WebDatabaseMigrationTest, MigrateVersion32ToCurrent) {
EXPECT_EQ("589636FD-9037-3053-200C-80ABC97D7344", s3.ColumnString(0));
EXPECT_EQ(ASCIIToUTF16("john@doe.com"), s3.ColumnString16(1));
- // Note no email for 2 Main Street.
- // Note no email for 2 Main St.
+ // 2 Main Street.
+ ASSERT_TRUE(s3.Step());
+ EXPECT_EQ("4C74A9D8-7EEE-423E-F9C2-E7FA70ED1396", s3.ColumnString(0));
+ EXPECT_EQ(ASCIIToUTF16(""), s3.ColumnString16(1));
+
+ // 2 Main St.
+ ASSERT_TRUE(s3.Step());
+ EXPECT_EQ("722DF5C4-F74A-294A-46F0-31FFDED0D635", s3.ColumnString(0));
+ EXPECT_EQ(ASCIIToUTF16(""), s3.ColumnString16(1));
// Alfred E Newman.
// Gets culled during migration from 35 to 36 due to incomplete address.
- // Note no email for 3 Main St.
+ // 3 Main St.
+ ASSERT_TRUE(s3.Step());
+ EXPECT_EQ("9E5FE298-62C7-83DF-6293-381BC589183F", s3.ColumnString(0));
+ EXPECT_EQ(ASCIIToUTF16(""), s3.ColumnString16(1));
// Should be all.
EXPECT_FALSE(s3.Step());
@@ -3155,10 +3372,44 @@ TEST_F(WebDatabaseMigrationTest, MigrateVersion32ToCurrent) {
EXPECT_EQ(1, s4.ColumnInt(1)); // 1 means fax.
EXPECT_EQ(ASCIIToUTF16("4153334444"), s4.ColumnString16(2));
- // Note no phone or fax for 2 Main Street.
- // Note no phone or fax for 2 Main St.
+ // 2 Main Street phone.
+ ASSERT_TRUE(s4.Step());
+ EXPECT_EQ("4C74A9D8-7EEE-423E-F9C2-E7FA70ED1396", s4.ColumnString(0));
+ EXPECT_EQ(0, s4.ColumnInt(1)); // 0 means phone.
+ EXPECT_EQ(ASCIIToUTF16(""), s4.ColumnString16(2));
+
+ // 2 Main Street fax.
+ ASSERT_TRUE(s4.Step());
+ EXPECT_EQ("4C74A9D8-7EEE-423E-F9C2-E7FA70ED1396", s4.ColumnString(0));
+ EXPECT_EQ(1, s4.ColumnInt(1)); // 1 means fax.
+ EXPECT_EQ(ASCIIToUTF16(""), s4.ColumnString16(2));
+
+ // 2 Main St phone.
+ ASSERT_TRUE(s4.Step());
+ EXPECT_EQ("722DF5C4-F74A-294A-46F0-31FFDED0D635", s4.ColumnString(0));
+ EXPECT_EQ(0, s4.ColumnInt(1)); // 0 means phone.
+ EXPECT_EQ(ASCIIToUTF16(""), s4.ColumnString16(2));
+
+ // 2 Main St fax.
+ ASSERT_TRUE(s4.Step());
+ EXPECT_EQ("722DF5C4-F74A-294A-46F0-31FFDED0D635", s4.ColumnString(0));
+ EXPECT_EQ(1, s4.ColumnInt(1)); // 1 means fax.
+ EXPECT_EQ(ASCIIToUTF16(""), s4.ColumnString16(2));
+
// Note no phone or fax for Alfred E Newman.
- // Note no phone or fax for 3 Main St.
+
+ // 3 Main St phone.
+ ASSERT_TRUE(s4.Step());
+ EXPECT_EQ("9E5FE298-62C7-83DF-6293-381BC589183F", s4.ColumnString(0));
+ EXPECT_EQ(0, s4.ColumnInt(1)); // 0 means phone.
+ EXPECT_EQ(ASCIIToUTF16(""), s4.ColumnString16(2));
+
+ // 2 Main St fax.
+ ASSERT_TRUE(s4.Step());
+ EXPECT_EQ("9E5FE298-62C7-83DF-6293-381BC589183F", s4.ColumnString(0));
+ EXPECT_EQ(1, s4.ColumnInt(1)); // 1 means fax.
+ EXPECT_EQ(ASCIIToUTF16(""), s4.ColumnString16(2));
+
// Should be all.
EXPECT_FALSE(s4.Step());