diff options
Diffstat (limited to 'chrome/browser')
-rw-r--r-- | chrome/browser/autofill/address.h | 2 | ||||
-rw-r--r-- | chrome/browser/autofill/autofill_profile.cc | 226 | ||||
-rw-r--r-- | chrome/browser/autofill/autofill_profile.h | 30 | ||||
-rw-r--r-- | chrome/browser/autofill/autofill_profile_unittest.cc | 176 | ||||
-rw-r--r-- | chrome/browser/autofill/contact_info.h | 6 | ||||
-rw-r--r-- | chrome/browser/autofill/fax_number.h | 2 | ||||
-rw-r--r-- | chrome/browser/autofill/home_phone_number.h | 2 | ||||
-rw-r--r-- | chrome/browser/webdata/web_data_service.cc | 2 | ||||
-rw-r--r-- | chrome/browser/webdata/web_database.cc | 324 | ||||
-rw-r--r-- | chrome/browser/webdata/web_database.h | 4 | ||||
-rw-r--r-- | chrome/browser/webdata/web_database_unittest.cc | 285 |
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()); |