diff options
Diffstat (limited to 'chrome/browser')
-rw-r--r-- | chrome/browser/autofill/autofill_dialog_gtk.cc | 184 | ||||
-rw-r--r-- | chrome/browser/autofill/autofill_manager.cc | 8 | ||||
-rw-r--r-- | chrome/browser/autofill/autofill_profile.cc | 2 | ||||
-rw-r--r-- | chrome/browser/autofill/autofill_profile.h | 6 | ||||
-rw-r--r-- | chrome/browser/autofill/credit_card.cc | 90 | ||||
-rw-r--r-- | chrome/browser/autofill/credit_card.h | 42 | ||||
-rw-r--r-- | chrome/browser/autofill/personal_data_manager.cc | 203 | ||||
-rw-r--r-- | chrome/browser/autofill/personal_data_manager.h | 51 | ||||
-rw-r--r-- | chrome/browser/autofill/personal_data_manager_unittest.cc | 103 | ||||
-rw-r--r-- | chrome/browser/webdata/web_data_service.cc | 101 | ||||
-rw-r--r-- | chrome/browser/webdata/web_data_service.h | 51 | ||||
-rw-r--r-- | chrome/browser/webdata/web_database.cc | 176 | ||||
-rw-r--r-- | chrome/browser/webdata/web_database.h | 19 | ||||
-rw-r--r-- | chrome/browser/webdata/web_database_unittest.cc | 75 |
14 files changed, 963 insertions, 148 deletions
diff --git a/chrome/browser/autofill/autofill_dialog_gtk.cc b/chrome/browser/autofill/autofill_dialog_gtk.cc index 33a30a5..20f673d 100644 --- a/chrome/browser/autofill/autofill_dialog_gtk.cc +++ b/chrome/browser/autofill/autofill_dialog_gtk.cc @@ -57,6 +57,23 @@ typedef struct _AddressWidgets { GtkWidget* fax3; } AddressWidgets; +// All of these widgets are GtkEntrys except for default_profile, which is a +// GtkCheckButton, and billing/shipping_address are GtkComboBoxes. +typedef struct _CreditCardWidgets { + GtkWidget* label; + GtkWidget* default_creditcard; + GtkWidget* name_on_card; + GtkWidget* card_number; + GtkWidget* expiration_month; + GtkWidget* expiration_year; + GtkWidget* verification_code; + GtkWidget* billing_address; + GtkWidget* shipping_address; + GtkWidget* phone1; + GtkWidget* phone2; + GtkWidget* phone3; +} CreditCardWidgets; + // Adds an alignment around |widget| which indents the widget by |offset|. GtkWidget* IndentWidget(GtkWidget* widget, int offset) { GtkWidget* alignment = gtk_alignment_new(0, 0, 0, 0); @@ -267,11 +284,14 @@ class AutoFillDialog { // for either an address or a credit card. The expander will be expanded by // default if |expand| is true. GtkWidget* AddNewAddress(bool expand); - GtkWidget* AddNewCreditCard(); + GtkWidget* AddNewCreditCard(bool expand); // Adds a new address filled out with information from |profile|. void AddAddress(const AutoFillProfile& profile); + // Adds a new credit card filled out with information from |credit_card|. + void AddCreditCard(const CreditCard& credit_card); + // The list of current AutoFill profiles. std::vector<AutoFillProfile> profiles_; @@ -281,6 +301,9 @@ class AutoFillDialog { // The list of address widgets, used to modify the AutoFill profiles. std::vector<AddressWidgets> address_widgets_; + // The list of credit card widgets, used to modify the stored credit cards. + std::vector<CreditCardWidgets> credit_card_widgets_; + // The AutoFill dialog. GtkWidget* dialog_; @@ -306,11 +329,14 @@ AutoFillDialog::AutoFillDialog(AutoFillDialogObserver* observer, DCHECK(observer); // Copy the profiles. - std::vector<AutoFillProfile*>::const_iterator profile; - for (profile = profiles.begin(); profile != profiles.end(); ++profile) - profiles_.push_back(**profile); + for (std::vector<AutoFillProfile*>::const_iterator iter = profiles.begin(); + iter != profiles.end(); ++iter) + profiles_.push_back(**iter); - // TODO(jhawkins): Copy the credit cards. + // Copy the credit cards. + for (std::vector<CreditCard*>::const_iterator iter = credit_cards.begin(); + iter != credit_cards.end(); ++iter) + credit_cards_.push_back(**iter); dialog_ = gtk_dialog_new_with_buttons( l10n_util::GetStringUTF8(IDS_AUTOFILL_DIALOG_TITLE).c_str(), @@ -365,8 +391,8 @@ AutoFillDialog::AutoFillDialog(AutoFillDialogObserver* observer, G_CALLBACK(OnAddAddressClicked)); gtk_box_pack_start_defaults(GTK_BOX(outer_vbox), addresses_vbox_); - std::vector<AutoFillProfile>::const_iterator iter; - for (iter = profiles_.begin(); iter != profiles_.end(); ++iter) + for (std::vector<AutoFillProfile>::const_iterator iter = profiles_.begin(); + iter != profiles_.end(); ++iter) AddAddress(*iter); creditcards_vbox_ = InitGroup(IDS_AUTOFILL_CREDITCARDS_GROUP_NAME, @@ -374,7 +400,9 @@ AutoFillDialog::AutoFillDialog(AutoFillDialogObserver* observer, G_CALLBACK(OnAddCreditCardClicked)); gtk_box_pack_start_defaults(GTK_BOX(outer_vbox), creditcards_vbox_); - // TODO(jhawkins): Add credit cards from |credit_cards|. + for (std::vector<CreditCard>::const_iterator iter = credit_cards_.begin(); + iter != credit_cards_.end(); ++iter) + AddCreditCard(*iter); gtk_widget_show_all(dialog_); } @@ -432,19 +460,47 @@ static AutoFillProfile AutoFillProfileFromWidgetValues( return profile; } +static CreditCard CreditCardFromWidgetValues( + const CreditCardWidgets& widgets) { + // TODO(jhawkins): unique id? + CreditCard credit_card(GetEntryText(widgets.label), 0); + credit_card.SetInfo(AutoFillType(CREDIT_CARD_NAME), + GetEntryText(widgets.name_on_card)); + // TODO(jhawkins): Credit card type. + credit_card.SetInfo(AutoFillType(CREDIT_CARD_NUMBER), + GetEntryText(widgets.card_number)); + credit_card.SetInfo(AutoFillType(CREDIT_CARD_EXP_MONTH), + GetEntryText(widgets.expiration_month)); + credit_card.SetInfo(AutoFillType(CREDIT_CARD_EXP_4_DIGIT_YEAR), + GetEntryText(widgets.expiration_year)); + credit_card.SetInfo(AutoFillType(CREDIT_CARD_VERIFICATION_CODE), + GetEntryText(widgets.verification_code)); + // TODO(jhawkins): Billing/shipping addresses. + return credit_card; +} + // static void AutoFillDialog::OnResponse(GtkDialog* dialog, gint response_id, AutoFillDialog* autofill_dialog) { if (response_id == GTK_RESPONSE_APPLY || response_id == GTK_RESPONSE_OK) { autofill_dialog->profiles_.clear(); - std::vector<AddressWidgets>::const_iterator iter; - for (iter = autofill_dialog->address_widgets_.begin(); + for (std::vector<AddressWidgets>::const_iterator iter = + autofill_dialog->address_widgets_.begin(); iter != autofill_dialog->address_widgets_.end(); ++iter) { autofill_dialog->profiles_.push_back( AutoFillProfileFromWidgetValues(*iter)); } + autofill_dialog->credit_cards_.clear(); + for (std::vector<CreditCardWidgets>::const_iterator iter = + autofill_dialog->credit_card_widgets_.begin(); + iter != autofill_dialog->credit_card_widgets_.end(); + ++iter) { + autofill_dialog->credit_cards_.push_back( + CreditCardFromWidgetValues(*iter)); + } + autofill_dialog->observer_->OnAutoFillDialogApply( &autofill_dialog->profiles_, &autofill_dialog->credit_cards_); @@ -467,7 +523,7 @@ void AutoFillDialog::OnAddAddressClicked(GtkButton* button, // static void AutoFillDialog::OnAddCreditCardClicked(GtkButton* button, AutoFillDialog* dialog) { - GtkWidget* new_creditcard = dialog->AddNewCreditCard(); + GtkWidget* new_creditcard = dialog->AddNewCreditCard(true); gtk_box_pack_start(GTK_BOX(dialog->creditcards_vbox_), new_creditcard, FALSE, FALSE, 0); gtk_widget_show_all(new_creditcard); @@ -514,7 +570,39 @@ void AutoFillDialog::OnDeleteAddressClicked(GtkButton* button, // static void AutoFillDialog::OnDeleteCreditCardClicked(GtkButton* button, AutoFillDialog* dialog) { - // TODO(jhawkins): Remove the associated credit card. + GtkWidget* entry = GetButtonData(GTK_WIDGET(button)); + string16 label = GetEntryText(entry); + + // TODO(jhawkins): Base this on ID. + + // Remove the credit card. + for (std::vector<CreditCard>::iterator iter = dialog->credit_cards_.begin(); + iter != dialog->credit_cards_.end(); + ++iter) { + if (iter->Label() == label) { + dialog->credit_cards_.erase(iter); + break; + } + } + + // Remove the set of credit widgets. + for (std::vector<CreditCardWidgets>::iterator iter = + dialog->credit_card_widgets_.begin(); + iter != dialog->credit_card_widgets_.end(); + ++iter) { + if (iter->label == entry) { + dialog->credit_card_widgets_.erase(iter); + break; + } + } + + // Get back to the expander widget. + GtkWidget* expander = gtk_widget_get_ancestor(GTK_WIDGET(button), + GTK_TYPE_EXPANDER); + DCHECK(expander); + + // Destroying the widget will also remove it from the parent container. + gtk_widget_destroy(expander); } // static @@ -647,33 +735,38 @@ GtkWidget* AutoFillDialog::AddNewAddress(bool expand) { return address; } -GtkWidget* AutoFillDialog::AddNewCreditCard() { +GtkWidget* AutoFillDialog::AddNewCreditCard(bool expand) { + CreditCardWidgets widgets = {0}; GtkWidget* vbox; GtkWidget* credit_card = InitGroupContentArea(IDS_AUTOFILL_NEW_CREDITCARD, &vbox); + gtk_expander_set_expanded(GTK_EXPANDER(credit_card), expand); + GtkWidget* label_table = InitFormTable(1, 2); gtk_box_pack_start_defaults(GTK_BOX(vbox), label_table); - FormTableAddLabelEntry(label_table, 0, 0, 1, IDS_AUTOFILL_DIALOG_LABEL, - credit_card, G_CALLBACK(OnLabelChanged)); + widgets.label = FormTableAddLabelEntry(label_table, 0, 0, 1, + IDS_AUTOFILL_DIALOG_LABEL, credit_card, + G_CALLBACK(OnLabelChanged)); // TODO(jhawkins): If there's not a default profile, automatically check this // check button. - GtkWidget* default_check = gtk_check_button_new_with_label( + widgets.default_creditcard = gtk_check_button_new_with_label( l10n_util::GetStringUTF8(IDS_AUTOFILL_DIALOG_MAKE_DEFAULT).c_str()); - FormTableSetWidget(label_table, default_check, 0, 1, 1, true); + FormTableSetWidget(label_table, widgets.default_creditcard, 0, 1, 1, true); GtkWidget* name_cc_table = InitFormTable(2, 6); gtk_box_pack_start_defaults(GTK_BOX(vbox), name_cc_table); - FormTableAddExpandedEntry(name_cc_table, 0, 0, 3, - IDS_AUTOFILL_DIALOG_NAME_ON_CARD); - FormTableAddExpandedEntry(name_cc_table, 1, 0, 3, - IDS_AUTOFILL_DIALOG_CREDIT_CARD_NUMBER); - FormTableAddSizedEntry(name_cc_table, 1, 3, 2, 0); - FormTableAddSizedEntry(name_cc_table, 1, 4, 4, 0); - FormTableAddSizedEntry(name_cc_table, 1, 5, 5, IDS_AUTOFILL_DIALOG_CVC); + widgets.name_on_card = FormTableAddExpandedEntry( + name_cc_table, 0, 0, 3, IDS_AUTOFILL_DIALOG_NAME_ON_CARD); + widgets.card_number = FormTableAddExpandedEntry( + name_cc_table, 1, 0, 3, IDS_AUTOFILL_DIALOG_CREDIT_CARD_NUMBER); + widgets.expiration_month = FormTableAddSizedEntry(name_cc_table, 1, 3, 2, 0); + widgets.expiration_year = FormTableAddSizedEntry(name_cc_table, 1, 4, 4, 0); + widgets.verification_code = FormTableAddSizedEntry( + name_cc_table, 1, 5, 5, IDS_AUTOFILL_DIALOG_CVC); FormTableSetLabel(name_cc_table, 1, 3, 2, IDS_AUTOFILL_DIALOG_EXPIRATION_DATE); @@ -687,6 +780,7 @@ GtkWidget* AutoFillDialog::AddNewCreditCard() { IDS_AUTOFILL_DIALOG_BILLING_ADDRESS); GtkWidget* billing = gtk_combo_box_new_text(); + widgets.billing_address = billing; std::string combo_text = l10n_util::GetStringUTF8( IDS_AUTOFILL_DIALOG_CHOOSE_EXISTING_ADDRESS); gtk_combo_box_append_text(GTK_COMBO_BOX(billing), combo_text.c_str()); @@ -697,6 +791,7 @@ GtkWidget* AutoFillDialog::AddNewCreditCard() { IDS_AUTOFILL_DIALOG_SHIPPING_ADDRESS); GtkWidget* shipping = gtk_combo_box_new_text(); + widgets.shipping_address = shipping; combo_text = l10n_util::GetStringUTF8(IDS_AUTOFILL_DIALOG_SAME_AS_BILLING); gtk_combo_box_append_text(GTK_COMBO_BOX(shipping), combo_text.c_str()); gtk_combo_box_set_active(GTK_COMBO_BOX(shipping), 0); @@ -705,16 +800,21 @@ GtkWidget* AutoFillDialog::AddNewCreditCard() { GtkWidget* phone_table = InitFormTable(1, 4); gtk_box_pack_start_defaults(GTK_BOX(vbox), phone_table); - FormTableAddSizedEntry(phone_table, 0, 0, 4, IDS_AUTOFILL_DIALOG_PHONE); - FormTableAddSizedEntry(phone_table, 0, 1, 4, 0); - FormTableAddEntry(phone_table, 0, 2, 2, 0); + widgets.phone1 = FormTableAddSizedEntry( + phone_table, 0, 0, 4, IDS_AUTOFILL_DIALOG_PHONE); + widgets.phone2 = FormTableAddSizedEntry(phone_table, 0, 1, 4, 0); + widgets.phone3 = FormTableAddEntry(phone_table, 0, 2, 2, 0); GtkWidget* button = gtk_button_new_with_label( l10n_util::GetStringUTF8(IDS_AUTOFILL_DELETE_BUTTON).c_str()); + g_signal_connect(button, "clicked", + G_CALLBACK(OnDeleteCreditCardClicked), this); + SetButtonData(button, widgets.label); GtkWidget* alignment = gtk_alignment_new(0, 0, 0, 0); gtk_container_add(GTK_CONTAINER(alignment), button); gtk_box_pack_start_defaults(GTK_BOX(vbox), alignment); + credit_card_widgets_.push_back(widgets); return credit_card; } @@ -765,6 +865,36 @@ void AutoFillDialog::AddAddress(const AutoFillProfile& profile) { gtk_widget_show_all(address); } +void AutoFillDialog::AddCreditCard(const CreditCard& credit_card) { + GtkWidget* credit_card_widget = AddNewCreditCard(false); + gtk_expander_set_label(GTK_EXPANDER(credit_card_widget), + UTF16ToUTF8(credit_card.Label()).c_str()); + + // We just pushed the widgets to the back of the vector. + const CreditCardWidgets& widgets = credit_card_widgets_.back(); + SetEntryText(widgets.label, credit_card.Label()); + SetEntryText(widgets.name_on_card, + credit_card.GetFieldText(AutoFillType(CREDIT_CARD_NAME))); + /*SetEntryText(widgets.type, + credit_card.GetFieldText(AutoFillType(CREDIT_CARD_TYPE)));*/ + SetEntryText(widgets.card_number, + credit_card.GetFieldText(AutoFillType(CREDIT_CARD_NUMBER))); + SetEntryText(widgets.expiration_month, + credit_card.GetFieldText(AutoFillType(CREDIT_CARD_EXP_MONTH))); + SetEntryText( + widgets.expiration_year, + credit_card.GetFieldText(AutoFillType(CREDIT_CARD_EXP_4_DIGIT_YEAR))); + SetEntryText( + widgets.verification_code, + credit_card.GetFieldText(AutoFillType(CREDIT_CARD_VERIFICATION_CODE))); + + // TODO(jhawkins): Set the GtkComboBox widgets. + + gtk_box_pack_start(GTK_BOX(creditcards_vbox_), credit_card_widget, + FALSE, FALSE, 0); + gtk_widget_show_all(credit_card_widget); +} + /////////////////////////////////////////////////////////////////////////////// // Factory/finder method: diff --git a/chrome/browser/autofill/autofill_manager.cc b/chrome/browser/autofill/autofill_manager.cc index 2e067a9..a9f1f7f 100644 --- a/chrome/browser/autofill/autofill_manager.cc +++ b/chrome/browser/autofill/autofill_manager.cc @@ -64,7 +64,7 @@ void AutoFillManager::OnAutoFillDialogApply( std::vector<CreditCard>* credit_cards) { // Save the personal data. personal_data_->SetProfiles(profiles); - // TODO(jhawkins): Set the credit cards. + personal_data_->SetCreditCards(credit_cards); HandleSubmit(); } @@ -74,10 +74,8 @@ void AutoFillManager::OnPersonalDataLoaded() { // remove ourselves as observer. personal_data_->RemoveObserver(this); - // TODO(jhawkins): Actually send in the real credit cards from the personal - // data manager. - std::vector<CreditCard*> credit_cards; - ShowAutoFillDialog(this, personal_data_->profiles(), credit_cards); + ShowAutoFillDialog( + this, personal_data_->profiles(), personal_data_->credit_cards()); } void AutoFillManager::DeterminePossibleFieldTypes( diff --git a/chrome/browser/autofill/autofill_profile.cc b/chrome/browser/autofill/autofill_profile.cc index bfc4fef..cd0438d 100644 --- a/chrome/browser/autofill/autofill_profile.cc +++ b/chrome/browser/autofill/autofill_profile.cc @@ -188,7 +188,7 @@ Address* AutoFillProfile::GetHomeAddress() { // So we can compare AutoFillProfiles with EXPECT_EQ(). std::ostream& operator<<(std::ostream& os, const AutoFillProfile& profile) { return os - << UTF16ToASCII(profile.Label()) + << UTF16ToUTF8(profile.Label()) << " " << profile.unique_id() << " " diff --git a/chrome/browser/autofill/autofill_profile.h b/chrome/browser/autofill/autofill_profile.h index acc7527..6142721 100644 --- a/chrome/browser/autofill/autofill_profile.h +++ b/chrome/browser/autofill/autofill_profile.h @@ -21,7 +21,7 @@ typedef std::map<FieldTypeGroup, FormGroup*> FormGroupMap; class AutoFillProfile : public FormGroup { public: AutoFillProfile(const string16& label, int unique_id); - // For use in std containers. + // For use in STL containers. AutoFillProfile(); AutoFillProfile(const AutoFillProfile&); virtual ~AutoFillProfile(); @@ -47,16 +47,16 @@ class AutoFillProfile : public FormGroup { void set_use_billing_address(bool use); bool use_billing_address() const { return use_billing_address_; } + void set_unique_id(int id) { unique_id_ = id; } int unique_id() const { return unique_id_; } - // For use in std containers. + // For use in STL containers. void operator=(const AutoFillProfile&); // Used by tests. // TODO(jhawkins): Move these to private and add the test as a friend. bool operator==(const AutoFillProfile& profile) const; void set_label(const string16& label) { label_ = label; } - void set_unique_id(int id) { unique_id_ = id; } private: Address* GetBillingAddress(); diff --git a/chrome/browser/autofill/credit_card.cc b/chrome/browser/autofill/credit_card.cc index fb679a7..882a062 100644 --- a/chrome/browser/autofill/credit_card.cc +++ b/chrome/browser/autofill/credit_card.cc @@ -6,6 +6,7 @@ #include "base/basictypes.h" #include "base/string_util.h" +#include "base/utf_string_conversions.h" #include "chrome/browser/autofill/autofill_type.h" #include "chrome/browser/autofill/field_types.h" @@ -23,23 +24,16 @@ static const AutoFillFieldType kAutoFillCreditCardTypes[] = { static const int kAutoFillCreditCardLength = arraysize(kAutoFillCreditCardTypes); -CreditCard::CreditCard(const string16& label) +CreditCard::CreditCard(const string16& label, int unique_id) : expiration_month_(0), expiration_year_(0), - label_(label) { + label_(label), + unique_id_(unique_id) { } -CreditCard::CreditCard(const CreditCard& card) - : number_(card.number_), - name_on_card_(card.name_on_card_), - type_(card.type_), - verification_code_(card.verification_code_), - last_four_digits_(card.last_four_digits_), - expiration_month_(card.expiration_month_), - expiration_year_(card.expiration_year_), - label_(card.label_) { +CreditCard::CreditCard(const CreditCard& card) { + operator=(card); } - FormGroup* CreditCard::Clone() const { return new CreditCard(*this); } @@ -190,7 +184,8 @@ void CreditCard::SetInfo(const AutoFillType& type, const string16& value) { break; default: - DLOG(ERROR) << "Attempting to set unknown info-type"; + DLOG(ERROR) << "Attempting to set unknown info-type " + << type.field_type(); break; } } @@ -254,6 +249,48 @@ void CreditCard::set_expiration_year(int expiration_year) { expiration_year_ = expiration_year; } + +void CreditCard::operator=(const CreditCard& source) { + number_ = source.number_; + name_on_card_ = source.name_on_card_; + type_ = source.type_; + verification_code_ = source.verification_code_; + last_four_digits_ = source.last_four_digits_; + expiration_month_ = source.expiration_month_; + expiration_year_ = source.expiration_year_; + label_ = source.label_; + billing_address_ = source.billing_address_; + shipping_address_ = source.shipping_address_; + unique_id_ = source.unique_id_; +} + +bool CreditCard::operator==(const CreditCard& creditcard) const { + // The following CreditCard field types are the only types we store in the + // WebDB so far, so we're only concerned with matching these types in the + // profile. + const AutoFillFieldType types[] = { CREDIT_CARD_NAME, + CREDIT_CARD_TYPE, + CREDIT_CARD_NUMBER, + CREDIT_CARD_VERIFICATION_CODE, + CREDIT_CARD_EXP_MONTH, + CREDIT_CARD_EXP_4_DIGIT_YEAR }; + + if (label_ != creditcard.label_ || + unique_id_ != creditcard.unique_id_ || + billing_address_ != creditcard.billing_address_ || + shipping_address_ != creditcard.shipping_address_) { + return false; + } + + for (size_t index = 0; index < arraysize(types); ++index) { + if (GetFieldText(AutoFillType(types[index])) != + creditcard.GetFieldText(AutoFillType(types[index]))) + return false; + } + + return true; +} + bool CreditCard::FindInfoMatchesHelper(const AutoFillFieldType& field_type, const string16& info, string16* match) const { @@ -395,3 +432,30 @@ bool CreditCard::ConvertDate(const string16& date, int* num) const { return true; } + +// So we can compare CreditCards with EXPECT_EQ(). +std::ostream& operator<<(std::ostream& os, const CreditCard& creditcard) { + return os + << UTF16ToUTF8(creditcard.Label()) + << " " + << creditcard.unique_id() + << " " + << UTF16ToUTF8(creditcard.billing_address()) + << " " + << UTF16ToUTF8(creditcard.shipping_address()) + << " " + << UTF16ToUTF8(creditcard.GetFieldText(AutoFillType(CREDIT_CARD_NAME))) + << " " + << UTF16ToUTF8(creditcard.GetFieldText(AutoFillType(CREDIT_CARD_TYPE))) + << " " + << UTF16ToUTF8(creditcard.GetFieldText(AutoFillType(CREDIT_CARD_NUMBER))) + << " " + << UTF16ToUTF8(creditcard.GetFieldText( + AutoFillType(CREDIT_CARD_VERIFICATION_CODE))) + << " " + << UTF16ToUTF8(creditcard.GetFieldText( + AutoFillType(CREDIT_CARD_EXP_MONTH))) + << " " + << UTF16ToUTF8(creditcard.GetFieldText( + AutoFillType(CREDIT_CARD_EXP_4_DIGIT_YEAR))); +} diff --git a/chrome/browser/autofill/credit_card.h b/chrome/browser/autofill/credit_card.h index 7d3cbe9..3962c40 100644 --- a/chrome/browser/autofill/credit_card.h +++ b/chrome/browser/autofill/credit_card.h @@ -13,9 +13,9 @@ // A form group that stores credit card information. class CreditCard : public FormGroup { public: - explicit CreditCard(const string16& label); - // Used for STL. - explicit CreditCard(const CreditCard& card); + CreditCard(const string16& label, int unique_id); + // For use in STL containers. + CreditCard(const CreditCard& card); // FormGroup implementation: FormGroup* Clone() const; @@ -49,6 +49,9 @@ class CreditCard : public FormGroup { string16 last_four_digits() const { return last_four_digits_; } int expiration_month() const { return expiration_month_; } int expiration_year() const { return expiration_year_; } + string16 billing_address() const { return billing_address_; } + string16 shipping_address() const { return shipping_address_; } + int unique_id() const { return unique_id_; } void set_number(const string16& number) { number_ = number; } void set_name_on_card(const string16& name_on_card) { @@ -61,15 +64,31 @@ class CreditCard : public FormGroup { void set_last_four_digits(const string16& last_four_digits) { last_four_digits_ = last_four_digits; } + void set_unique_id(int id) { unique_id_ = id; } + + // The caller should verify that the corresponding AutoFillProfile exists. If + // the shipping address should be the same as the billing address, send in an + // empty string to set_shipping_address. + void set_billing_address(const string16& address) { + billing_address_ = address; + } + void set_shipping_address(const string16& address) { + shipping_address_ = address; + } // These setters verify that the month and year are within appropriate // ranges. void set_expiration_month(int expiration_month); void set_expiration_year(int expiration_year); - private: - void operator=(const CreditCard& card); + // For use in STL containers. + void operator=(const CreditCard&); + + // Used by tests. + bool operator==(const CreditCard& creditcard) const; + void set_label(const string16& label) { label_ = label; } + private: // A helper function for FindInfoMatches that only handles matching the info // with the requested field type. bool FindInfoMatchesHelper(const AutoFillFieldType& field_type, @@ -121,6 +140,19 @@ class CreditCard : public FormGroup { // This is the display name of the card set by the user, e.g., Amazon Visa. string16 label_; + + // The billing and shipping addresses. The are the labels of + // AutoFillProfiles that contain the corresponding address. If + // |shipping_address_| is empty, the billing address is used for the shipping + // address. + string16 billing_address_; + string16 shipping_address_; + + // The unique ID of this profile. + int unique_id_; }; +// So we can compare CreditCards with EXPECT_EQ(). +std::ostream& operator<<(std::ostream& os, const CreditCard& creditcard); + #endif // CHROME_BROWSER_AUTOFILL_CREDIT_CARD_H_ diff --git a/chrome/browser/autofill/personal_data_manager.cc b/chrome/browser/autofill/personal_data_manager.cc index e2b2150..0ed0cce 100644 --- a/chrome/browser/autofill/personal_data_manager.cc +++ b/chrome/browser/autofill/personal_data_manager.cc @@ -25,7 +25,8 @@ static const int kPhoneNumberLength = 7; static const int kPhoneCityCodeLength = 3; PersonalDataManager::~PersonalDataManager() { - CancelPendingQuery(); + CancelPendingQuery(&pending_profiles_query_); + CancelPendingQuery(&pending_creditcards_query_); } void PersonalDataManager::OnWebDataServiceRequestDone( @@ -35,24 +36,27 @@ void PersonalDataManager::OnWebDataServiceRequestDone( if (!result) return; - DCHECK(pending_query_handle_); - DCHECK(result->GetType() == AUTOFILL_PROFILES_RESULT); - pending_query_handle_ = 0; - - unique_ids_.clear(); - profiles_.reset(); - const WDResult<std::vector<AutoFillProfile*> >* r = - static_cast<const WDResult<std::vector<AutoFillProfile*> >*>(result); - std::vector<AutoFillProfile*> profiles = r->GetValue(); - for (std::vector<AutoFillProfile*>::iterator iter = profiles.begin(); - iter != profiles.end(); ++iter) { - unique_ids_.insert((*iter)->unique_id()); - profiles_.push_back(*iter); + DCHECK(pending_profiles_query_ || pending_creditcards_query_); + DCHECK(result->GetType() == AUTOFILL_PROFILES_RESULT || + result->GetType() == AUTOFILL_CREDITCARDS_RESULT); + + switch (result->GetType()) { + case AUTOFILL_PROFILES_RESULT: + ReceiveLoadedProfiles(h, result); + break; + case AUTOFILL_CREDITCARDS_RESULT: + ReceiveLoadedCreditCards(h, result); + break; + default: + NOTREACHED(); } - is_data_loaded_ = true; - if (observer_) - observer_->OnPersonalDataLoaded(); + // If both requests have responded, then all personal data is loaded. + if (pending_profiles_query_ == 0 && pending_creditcards_query_ == 0) { + is_data_loaded_ = true; + if (observer_) + observer_->OnPersonalDataLoaded(); + } } void PersonalDataManager::SetObserver(PersonalDataManager::Observer* observer) { @@ -75,9 +79,10 @@ bool PersonalDataManager::ImportFormData( // possible to import. int importable_fields = 0; int importable_credit_card_fields = 0; - imported_profile_.reset(new AutoFillProfile(string16(), - CreateNextUniqueID())); - imported_credit_card_.reset(new CreditCard(string16())); + imported_profile_.reset(new AutoFillProfile( + string16(), CreateNextUniqueID(&unique_profile_ids_))); + // TODO(jhawkins): Use a hash of the CC# instead of a list of unique IDs? + imported_credit_card_.reset(new CreditCard(string16(), 0)); bool billing_address_info = false; std::vector<FormStructure*>::const_iterator iter; @@ -161,28 +166,28 @@ void PersonalDataManager::SetProfiles(std::vector<AutoFillProfile>* profiles) { for (std::vector<AutoFillProfile>::iterator iter = profiles->begin(); iter != profiles->end(); ++iter) { if (iter->unique_id() != 0) - unique_ids_.erase(iter->unique_id()); + unique_profile_ids_.erase(iter->unique_id()); } // Any remaining IDs are not in the new profile list and should be removed // from the web database. - for (std::set<int>::iterator iter = unique_ids_.begin(); - iter != unique_ids_.end(); ++iter) { + for (std::set<int>::iterator iter = unique_profile_ids_.begin(); + iter != unique_profile_ids_.end(); ++iter) { wds->RemoveAutoFillProfile(*iter); } // Clear the unique IDs. The set of unique IDs is updated for each profile - // added to |profile_| below. - unique_ids_.clear(); + // added to |profiles_| below. + unique_profile_ids_.clear(); // Update the web database with the existing profiles. We need to handle - // these first so that |unique_ids_| is reset with the IDs of the existing - // profiles; otherwise, new profiles added before older profiles can take - // their unique ID. + // these first so that |unique_profile_ids_| is reset with the IDs of the + // existing profiles; otherwise, new profiles added before older profiles can + // take their unique ID. for (std::vector<AutoFillProfile>::iterator iter = profiles->begin(); iter != profiles->end(); ++iter) { if (iter->unique_id() != 0) { - unique_ids_.insert(iter->unique_id()); + unique_profile_ids_.insert(iter->unique_id()); wds->UpdateAutoFillProfile(*iter); } } @@ -190,10 +195,11 @@ void PersonalDataManager::SetProfiles(std::vector<AutoFillProfile>* profiles) { // Add the new profiles to the web database. for (std::vector<AutoFillProfile>::iterator iter = profiles->begin(); iter != profiles->end(); ++iter) { - // Profile was added by the AutoFill dialog, so we need to set the unique - // ID. This also means we need to add this profile to the web DB. + // The profile was added by the AutoFill dialog, so we need to set the + // unique ID. This also means we need to add this profile to the web + // database. if (iter->unique_id() == 0) { - iter->set_unique_id(CreateNextUniqueID()); + iter->set_unique_id(CreateNextUniqueID(&unique_profile_ids_)); wds->AddAutoFillProfile(*iter); } } @@ -205,6 +211,64 @@ void PersonalDataManager::SetProfiles(std::vector<AutoFillProfile>* profiles) { } } +void PersonalDataManager::SetCreditCards( + std::vector<CreditCard>* credit_cards) { + if (profile_->IsOffTheRecord()) + return; + + WebDataService* wds = profile_->GetWebDataService(Profile::EXPLICIT_ACCESS); + if (!wds) + return; + + // Remove the unique IDs of the new set of credit cards from the unique ID + // set. + for (std::vector<CreditCard>::iterator iter = credit_cards->begin(); + iter != credit_cards->end(); ++iter) { + if (iter->unique_id() != 0) + unique_creditcard_ids_.erase(iter->unique_id()); + } + + // Any remaining IDs are not in the new credit card list and should be removed + // from the web database. + for (std::set<int>::iterator iter = unique_creditcard_ids_.begin(); + iter != unique_creditcard_ids_.end(); ++iter) { + wds->RemoveCreditCard(*iter); + } + + // Clear the unique IDs. The set of unique IDs is updated for each credit + // card added to |credit_cards_| below. + unique_creditcard_ids_.clear(); + + // Update the web database with the existing credit cards. We need to handle + // these first so that |unique_creditcard_ids_| is reset with the IDs of the + // existing credit cards; otherwise, new credit cards added before older + // credit cards can take their unique ID. + for (std::vector<CreditCard>::iterator iter = credit_cards->begin(); + iter != credit_cards->end(); ++iter) { + if (iter->unique_id() != 0) { + unique_creditcard_ids_.insert(iter->unique_id()); + wds->UpdateCreditCard(*iter); + } + } + + // Add the new credit cards to the web database. + for (std::vector<CreditCard>::iterator iter = credit_cards->begin(); + iter != credit_cards->end(); ++iter) { + // The credit card was added by the AutoFill dialog, so we need to set the + // unique ID. This also means we need to add this credit card to the web + // database. + if (iter->unique_id() == 0) { + iter->set_unique_id(CreateNextUniqueID(&unique_creditcard_ids_)); + wds->AddCreditCard(*iter); + } + } + + credit_cards_.reset(); + for (std::vector<CreditCard>::iterator iter = credit_cards->begin(); + iter != credit_cards->end(); ++iter) { + credit_cards_.push_back(new CreditCard(*iter)); + } +} void PersonalDataManager::GetPossibleFieldTypes(const string16& text, FieldTypeSet* possible_types) { @@ -227,7 +291,7 @@ void PersonalDataManager::GetPossibleFieldTypes(const string16& text, profile->GetPossibleFieldTypes(clean_info, possible_types); } - for (ScopedVector<FormGroup>::iterator iter = credit_cards_.begin(); + for (ScopedVector<CreditCard>::iterator iter = credit_cards_.begin(); iter != credit_cards_.end(); ++iter) { const FormGroup* credit_card = *iter; if (!credit_card) { @@ -250,9 +314,11 @@ PersonalDataManager::PersonalDataManager(Profile* profile) : profile_(profile), is_initialized_(false), is_data_loaded_(false), - pending_query_handle_(0), + pending_profiles_query_(0), + pending_creditcards_query_(0), observer_(NULL) { LoadProfiles(); + LoadCreditCards(); } void PersonalDataManager::InitializeIfNeeded() { @@ -263,13 +329,13 @@ void PersonalDataManager::InitializeIfNeeded() { // TODO(jhawkins): Load data. } -int PersonalDataManager::CreateNextUniqueID() { +int PersonalDataManager::CreateNextUniqueID(std::set<int>* unique_ids) { // Profile IDs MUST start at 1 to allow 0 as an error value when reading // the ID from the WebDB (see LoadData()). int id = 1; - while (unique_ids_.count(id) != 0) + while (unique_ids->count(id) != 0) ++id; - unique_ids_.insert(id); + unique_ids->insert(id); return id; } @@ -307,20 +373,71 @@ void PersonalDataManager::LoadProfiles() { return; } - CancelPendingQuery(); + CancelPendingQuery(&pending_profiles_query_); + + pending_profiles_query_ = web_data_service->GetAutoFillProfiles(this); +} + +void PersonalDataManager::LoadCreditCards() { + WebDataService* web_data_service = + profile_->GetWebDataService(Profile::EXPLICIT_ACCESS); + if (!web_data_service) { + NOTREACHED(); + return; + } + + CancelPendingQuery(&pending_creditcards_query_); - pending_query_handle_ = web_data_service->GetAutoFillProfiles(this); + pending_creditcards_query_ = web_data_service->GetCreditCards(this); +} + +void PersonalDataManager::ReceiveLoadedProfiles(WebDataService::Handle h, + const WDTypedResult* result) { + DCHECK_EQ(pending_profiles_query_, h); + pending_profiles_query_ = 0; + + unique_profile_ids_.clear(); + profiles_.reset(); + + const WDResult<std::vector<AutoFillProfile*> >* r = + static_cast<const WDResult<std::vector<AutoFillProfile*> >*>(result); + + std::vector<AutoFillProfile*> profiles = r->GetValue(); + for (std::vector<AutoFillProfile*>::iterator iter = profiles.begin(); + iter != profiles.end(); ++iter) { + unique_profile_ids_.insert((*iter)->unique_id()); + profiles_.push_back(*iter); + } +} + +void PersonalDataManager::ReceiveLoadedCreditCards( + WebDataService::Handle h, const WDTypedResult* result) { + DCHECK_EQ(pending_creditcards_query_, h); + pending_creditcards_query_ = 0; + + unique_creditcard_ids_.clear(); + credit_cards_.reset(); + + const WDResult<std::vector<CreditCard*> >* r = + static_cast<const WDResult<std::vector<CreditCard*> >*>(result); + + std::vector<CreditCard*> credit_cards = r->GetValue(); + for (std::vector<CreditCard*>::iterator iter = credit_cards.begin(); + iter != credit_cards.end(); ++iter) { + unique_creditcard_ids_.insert((*iter)->unique_id()); + credit_cards_.push_back(*iter); + } } -void PersonalDataManager::CancelPendingQuery() { - if (pending_query_handle_) { +void PersonalDataManager::CancelPendingQuery(WebDataService::Handle* handle) { + if (*handle) { WebDataService* web_data_service = profile_->GetWebDataService(Profile::EXPLICIT_ACCESS); if (!web_data_service) { NOTREACHED(); return; } - web_data_service->CancelRequest(pending_query_handle_); + web_data_service->CancelRequest(*handle); } - pending_query_handle_ = 0; + *handle = 0; } diff --git a/chrome/browser/autofill/personal_data_manager.h b/chrome/browser/autofill/personal_data_manager.h index 5821a2a..4f6ed7b 100644 --- a/chrome/browser/autofill/personal_data_manager.h +++ b/chrome/browser/autofill/personal_data_manager.h @@ -58,9 +58,15 @@ class PersonalDataManager : public WebDataServiceConsumer { AutoFillManager* autofill_manager); // Sets |profiles_| to the contents of |profiles| and updates the web database - // by adding, updating and removing profiles. + // by adding, updating and removing profiles. Sets the unique ID of + // newly-added profiles. void SetProfiles(std::vector<AutoFillProfile>* profiles); + // Sets |credit_cards_| to the contents of |credit_cards| and updates the web + // database by adding, updating and removing credit cards. Sets the unique + // ID of newly-added profiles. + void SetCreditCards(std::vector<CreditCard>* credit_cards); + // Gets the possible field types for the given text, determined by matching // the text with all known personal information and returning matching types. void GetPossibleFieldTypes(const string16& text, @@ -72,9 +78,11 @@ class PersonalDataManager : public WebDataServiceConsumer { // Returns whether the personal data has been loaded from the web database. bool IsDataLoaded() const { return is_data_loaded_; } - // This PersonalDataManager owns these profiles. Their lifetime is until the - // web database is updated with new profile information. + // This PersonalDataManager owns these profiles and credit cards. Their + // lifetime is until the web database is updated with new profile and credit + // card information, respectively. const std::vector<AutoFillProfile*>& profiles() { return profiles_.get(); } + const std::vector<CreditCard*>& credit_cards() { return credit_cards_.get(); } private: // Make sure that only Profile and the PersonalDataManager tests can create an @@ -93,7 +101,7 @@ class PersonalDataManager : public WebDataServiceConsumer { void InitializeIfNeeded(); // This will create and reserve a new unique ID for a profile. - int CreateNextUniqueID(); + int CreateNextUniqueID(std::set<int>* unique_ids); // Parses value to extract the components of a phone number and adds them to // profile. @@ -108,8 +116,22 @@ class PersonalDataManager : public WebDataServiceConsumer { // Loads the saved profiles from the web database. void LoadProfiles(); - // Cancels a pending query to the web database. - void CancelPendingQuery(); + // Loads the saved credit cards from the web database. + void LoadCreditCards(); + + // Receives the loaded profiles from the web data service and stores them in + // |credit_cards_|. + void ReceiveLoadedProfiles(WebDataService::Handle h, + const WDTypedResult* result); + + // Receives the loaded credit cards from the web data service and stores them + // in |credit_cards_|. + void ReceiveLoadedCreditCards(WebDataService::Handle h, + const WDTypedResult* result); + + // Cancels a pending query to the web database. |handle| is a pointer to the + // query handle. + void CancelPendingQuery(WebDataService::Handle* handle); // The profile hosting this PersonalDataManager. Profile* profile_; @@ -120,14 +142,19 @@ class PersonalDataManager : public WebDataServiceConsumer { // True if personal data has been loaded from the web database. bool is_data_loaded_; - // The set of already created unique IDs, used to create a new unique ID. - std::set<int> unique_ids_; + // The set of already created unique profile IDs, used to create a new unique + // profile ID. + std::set<int> unique_profile_ids_; + + // The set of already created unique credit card IDs, used to create a new + // unique credit card ID. + std::set<int> unique_creditcard_ids_; // The loaded profiles. ScopedVector<AutoFillProfile> profiles_; // The loaded credit cards. - ScopedVector<FormGroup> credit_cards_; + ScopedVector<CreditCard> credit_cards_; // The profile that is imported from a web form by ImportFormData. scoped_ptr<AutoFillProfile> imported_profile_; @@ -141,8 +168,10 @@ class PersonalDataManager : public WebDataServiceConsumer { // When the manager makes a request from WebDataService, the database // is queried on another thread, we record the query handle until we - // get called back. - WebDataService::Handle pending_query_handle_; + // get called back. We store handles for both profile and credit card queries + // so they can be loaded at the same time. + WebDataService::Handle pending_profiles_query_; + WebDataService::Handle pending_creditcards_query_; // The observer. This can be NULL. Observer* observer_; diff --git a/chrome/browser/autofill/personal_data_manager_unittest.cc b/chrome/browser/autofill/personal_data_manager_unittest.cc index 5bcbb08..db7e070 100644 --- a/chrome/browser/autofill/personal_data_manager_unittest.cc +++ b/chrome/browser/autofill/personal_data_manager_unittest.cc @@ -82,6 +82,27 @@ class PersonalDataManagerTest : public testing::Test { profile->SetInfo(AutoFillType(PHONE_FAX_NUMBER), ASCIIToUTF16(fax)); } + static void SetCreditCardInfo(CreditCard* credit_card, + const char* label, const char* name_on_card, const char* type, + const char* card_number, const char* expiration_month, + const char* expiration_year, const char* verification_code, + const char* billing_address, const char* shipping_address) { + credit_card->set_label(ASCIIToUTF16(label)); + credit_card->SetInfo(AutoFillType(CREDIT_CARD_NAME), + ASCIIToUTF16(name_on_card)); + credit_card->SetInfo(AutoFillType(CREDIT_CARD_TYPE), ASCIIToUTF16(type)); + credit_card->SetInfo(AutoFillType(CREDIT_CARD_NUMBER), + ASCIIToUTF16(card_number)); + credit_card->SetInfo(AutoFillType(CREDIT_CARD_EXP_MONTH), + ASCIIToUTF16(expiration_month)); + credit_card->SetInfo(AutoFillType(CREDIT_CARD_EXP_4_DIGIT_YEAR), + ASCIIToUTF16(expiration_year)); + credit_card->SetInfo(AutoFillType(CREDIT_CARD_VERIFICATION_CODE), + ASCIIToUTF16(verification_code)); + credit_card->set_billing_address(ASCIIToUTF16(billing_address)); + credit_card->set_shipping_address(ASCIIToUTF16(shipping_address)); + } + MessageLoopForUI message_loop_; ChromeThread ui_thread_; ChromeThread db_thread_; @@ -92,7 +113,7 @@ class PersonalDataManagerTest : public testing::Test { PersonalDataLoadedObserverMock personal_data_observer_; }; -// TODO(jhawkins): Test SaveProfiles w/out a WebDataService in the profile. +// TODO(jhawkins): Test SetProfiles w/out a WebDataService in the profile. TEST_F(PersonalDataManagerTest, SetProfiles) { AutoFillProfile profile0(string16(), 0); SetProfileInfo(&profile0, "Billing", "Marion", "Mitchell", "Morrison", @@ -174,3 +195,83 @@ TEST_F(PersonalDataManagerTest, SetProfiles) { EXPECT_EQ(profile0, *results3.at(0)); EXPECT_EQ(profile2, *results3.at(1)); } + +// TODO(jhawkins): Test SetCreditCards w/out a WebDataService in the profile. +TEST_F(PersonalDataManagerTest, SetCreditCards) { + CreditCard creditcard0(string16(), 0); + SetCreditCardInfo(&creditcard0, "Corporate", "John Dillinger", "Visa", + "123456789012", "01", "2010", "123", "Chicago", "Indianapolis"); + + CreditCard creditcard1(string16(), 0); + SetCreditCardInfo(&creditcard1, "Personal", "Bonnie Parker", "Mastercard", + "098765432109", "12", "2012", "987", "Dallas", ""); + + CreditCard creditcard2(string16(), 0); + SetCreditCardInfo(&creditcard2, "Savings", "Clyde Barrow", "American Express", + "777666888555", "04", "2015", "445", "Home", "Farm"); + + // This will verify that the web database has been loaded and the notification + // sent out. + EXPECT_CALL(personal_data_observer_, + OnPersonalDataLoaded()).WillOnce(QuitUIMessageLoop()); + + // The message loop will exit when the mock observer is notified. + MessageLoop::current()->Run(); + + // Add the three test credit cards to the database. + std::vector<CreditCard> update; + update.push_back(creditcard0); + update.push_back(creditcard1); + personal_data_->SetCreditCards(&update); + + // The PersonalDataManager will update the unique IDs when saving the + // credit cards, so we have to update the expectations. + creditcard0.set_unique_id(update[0].unique_id()); + creditcard1.set_unique_id(update[1].unique_id()); + + const std::vector<CreditCard*>& results1 = personal_data_->credit_cards(); + ASSERT_EQ(2U, results1.size()); + EXPECT_EQ(creditcard0, *results1.at(0)); + EXPECT_EQ(creditcard1, *results1.at(1)); + + // Three operations in one: + // - Update creditcard0 + // - Remove creditcard1 + // - Add creditcard2 + creditcard0.SetInfo(AutoFillType(CREDIT_CARD_NAME), ASCIIToUTF16("Joe")); + update.clear(); + update.push_back(creditcard0); + update.push_back(creditcard2); + personal_data_->SetCreditCards(&update); + + // Set the expected unique ID for creditcard2. + creditcard2.set_unique_id(update[1].unique_id()); + + // CreditCard IDs are re-used, so the third credit card to be added will have + // a unique ID that matches the old unique ID of the removed creditcard1, even + // though that ID has already been used. + const std::vector<CreditCard*>& results2 = personal_data_->credit_cards(); + ASSERT_EQ(2U, results2.size()); + EXPECT_EQ(creditcard0, *results2.at(0)); + EXPECT_EQ(creditcard2, *results2.at(1)); + EXPECT_EQ(creditcard2.unique_id(), creditcard1.unique_id()); + + // Reset the PersonalDataManager. This tests that the personal data was saved + // to the web database, and that we can load the credit cards from the web + // database. + ResetPersonalDataManager(); + + // This will verify that the web database has been loaded and the notification + // sent out. + EXPECT_CALL(personal_data_observer_, + OnPersonalDataLoaded()).WillOnce(QuitUIMessageLoop()); + + // The message loop will exit when the PersonalDataLoadedObserver is notified. + MessageLoop::current()->Run(); + + // Verify that we've loaded the credit cards from the web database. + const std::vector<CreditCard*>& results3 = personal_data_->credit_cards(); + ASSERT_EQ(2U, results3.size()); + EXPECT_EQ(creditcard0, *results3.at(0)); + EXPECT_EQ(creditcard2, *results3.at(1)); +} diff --git a/chrome/browser/webdata/web_data_service.cc b/chrome/browser/webdata/web_data_service.cc index b630a91..197b859 100644 --- a/chrome/browser/webdata/web_data_service.cc +++ b/chrome/browser/webdata/web_data_service.cc @@ -8,6 +8,7 @@ #include "base/task.h" #include "base/thread.h" #include "chrome/browser/autofill/autofill_profile.h" +#include "chrome/browser/autofill/credit_card.h" #include "chrome/browser/webdata/autofill_change.h" #include "chrome/browser/webdata/autofill_entry.h" #include "chrome/browser/webdata/web_database.h" @@ -170,27 +171,56 @@ void WebDataService::RemoveAutoFillProfile(int profile_id) { request)); } -WebDataService::Handle WebDataService::GetAutoFillProfileForLabel( - const string16& label, WebDataServiceConsumer* consumer) { +WebDataService::Handle WebDataService::GetAutoFillProfiles( + WebDataServiceConsumer* consumer) { WebDataRequest* request = new WebDataRequest(this, GetNextRequestHandle(), consumer); RegisterRequest(request); ScheduleTask( NewRunnableMethod(this, - &WebDataService::GetAutoFillProfileForLabelImpl, - request, - label)); + &WebDataService::GetAutoFillProfilesImpl, + request)); return request->GetHandle(); } -WebDataService::Handle WebDataService::GetAutoFillProfiles( +void WebDataService::AddCreditCard(const CreditCard& creditcard) { + GenericRequest<CreditCard>* request = + new GenericRequest<CreditCard>( + this, GetNextRequestHandle(), NULL, creditcard); + RegisterRequest(request); + ScheduleTask(NewRunnableMethod(this, + &WebDataService::AddCreditCardImpl, + request)); +} + +void WebDataService::UpdateCreditCard(const CreditCard& creditcard) { + GenericRequest<CreditCard>* request = + new GenericRequest<CreditCard>( + this, GetNextRequestHandle(), NULL, creditcard); + RegisterRequest(request); + ScheduleTask(NewRunnableMethod(this, + &WebDataService::UpdateCreditCardImpl, + request)); +} + +void WebDataService::RemoveCreditCard(int creditcard_id) { + GenericRequest<int>* request = + new GenericRequest<int>( + this, GetNextRequestHandle(), NULL, creditcard_id); + RegisterRequest(request); + ScheduleTask(NewRunnableMethod(this, + &WebDataService::RemoveCreditCardImpl, + request)); +} + +WebDataService::Handle WebDataService::GetCreditCards( WebDataServiceConsumer* consumer) { WebDataRequest* request = new WebDataRequest(this, GetNextRequestHandle(), consumer); RegisterRequest(request); ScheduleTask( NewRunnableMethod(this, - &WebDataService::GetAutoFillProfilesImpl, + &WebDataService::GetCreditCardsImpl, request)); return request->GetHandle(); } @@ -768,27 +798,62 @@ void WebDataService::RemoveAutoFillProfileImpl( request->RequestComplete(); } -void WebDataService::GetAutoFillProfileForLabelImpl(WebDataRequest* request, - const string16& label) { +void WebDataService::GetAutoFillProfilesImpl(WebDataRequest* request) { InitializeDatabaseIfNecessary(); if (db_ && !request->IsCancelled()) { - AutoFillProfile* profile; - db_->GetAutoFillProfileForLabel(label, &profile); + std::vector<AutoFillProfile*> profiles; + db_->GetAutoFillProfiles(&profiles); request->SetResult( - new WDResult<AutoFillProfile>(AUTOFILL_PROFILE_RESULT, *profile)); - delete profile; + new WDResult<std::vector<AutoFillProfile*> >(AUTOFILL_PROFILES_RESULT, + profiles)); } request->RequestComplete(); } -void WebDataService::GetAutoFillProfilesImpl(WebDataRequest* request) { +void WebDataService::AddCreditCardImpl( + GenericRequest<CreditCard>* request) { InitializeDatabaseIfNecessary(); if (db_ && !request->IsCancelled()) { - std::vector<AutoFillProfile*> profiles; - db_->GetAutoFillProfiles(&profiles); + const CreditCard& creditcard = request->GetArgument(); + if (!db_->AddCreditCard(creditcard)) + NOTREACHED(); + ScheduleCommit(); + } + request->RequestComplete(); +} + +void WebDataService::UpdateCreditCardImpl( + GenericRequest<CreditCard>* request) { + InitializeDatabaseIfNecessary(); + if (db_ && !request->IsCancelled()) { + const CreditCard& creditcard = request->GetArgument(); + if (!db_->UpdateCreditCard(creditcard)) + NOTREACHED(); + ScheduleCommit(); + } + request->RequestComplete(); +} + +void WebDataService::RemoveCreditCardImpl( + GenericRequest<int>* request) { + InitializeDatabaseIfNecessary(); + if (db_ && !request->IsCancelled()) { + int creditcard_id = request->GetArgument(); + if (!db_->RemoveCreditCard(creditcard_id)) + NOTREACHED(); + ScheduleCommit(); + } + request->RequestComplete(); +} + +void WebDataService::GetCreditCardsImpl(WebDataRequest* request) { + InitializeDatabaseIfNecessary(); + if (db_ && !request->IsCancelled()) { + std::vector<CreditCard*> creditcards; + db_->GetCreditCards(&creditcards); request->SetResult( - new WDResult<std::vector<AutoFillProfile*> >(AUTOFILL_PROFILES_RESULT, - profiles)); + new WDResult<std::vector<CreditCard*> >(AUTOFILL_CREDITCARDS_RESULT, + creditcards)); } request->RequestComplete(); } diff --git a/chrome/browser/webdata/web_data_service.h b/chrome/browser/webdata/web_data_service.h index ff356e0..c81061d 100644 --- a/chrome/browser/webdata/web_data_service.h +++ b/chrome/browser/webdata/web_data_service.h @@ -19,6 +19,7 @@ class AutofillChange; class AutoFillProfile; +class CreditCard; #if defined(OS_WIN) struct IE7PasswordInfo; #endif @@ -54,18 +55,20 @@ struct PasswordForm; // Result types // typedef enum { - BOOL_RESULT = 1, // WDResult<bool> - KEYWORDS_RESULT, // WDResult<WDKeywordsResult> - INT64_RESULT, // WDResult<int64> - PASSWORD_RESULT, // WDResult<std::vector<PasswordForm*>> + BOOL_RESULT = 1, // WDResult<bool> + KEYWORDS_RESULT, // WDResult<WDKeywordsResult> + INT64_RESULT, // WDResult<int64> + PASSWORD_RESULT, // WDResult<std::vector<PasswordForm*>> #if defined(OS_WIN) - PASSWORD_IE7_RESULT, // WDResult<IE7PasswordInfo> + PASSWORD_IE7_RESULT, // WDResult<IE7PasswordInfo> #endif - WEB_APP_IMAGES, // WDResult<WDAppImagesResult> - AUTOFILL_VALUE_RESULT, // WDResult<std::vector<string16>> - AUTOFILL_CHANGES, // WDResult<std::vector<AutofillChange>> - AUTOFILL_PROFILE_RESULT, // WDResult<AutoFillProfile> - AUTOFILL_PROFILES_RESULT // WDResult<std::vector<AutoFillProfile*>> + WEB_APP_IMAGES, // WDResult<WDAppImagesResult> + AUTOFILL_VALUE_RESULT, // WDResult<std::vector<string16>> + AUTOFILL_CHANGES, // WDResult<std::vector<AutofillChange>> + AUTOFILL_PROFILE_RESULT, // WDResult<AutoFillProfile> + AUTOFILL_PROFILES_RESULT, // WDResult<std::vector<AutoFillProfile*>> + AUTOFILL_CREDITCARD_RESULT, // WDResult<CreditCard> + AUTOFILL_CREDITCARDS_RESULT // WDResult<std::vector<CreditCard*>> } WDResultType; typedef std::vector<AutofillChange> AutofillChangeList; @@ -418,18 +421,28 @@ class WebDataService // |profile_id| is the unique ID of the profile to remove. void RemoveAutoFillProfile(int profile_id); - // Initiates the request for an AutoFill profile with label |label|. The - // method OnWebDataServiceRequestDone of |consumer| gets called back when the - // request is finished, with the profile included in the argument |result|. - Handle GetAutoFillProfileForLabel(const string16& label, - WebDataServiceConsumer* consumer); - // Initiates the request for all AutoFill profiles. The method // OnWebDataServiceRequestDone of |consumer| gets called when the request is // finished, with the profiles included in the argument |result|. The // consumer owns the profiles. Handle GetAutoFillProfiles(WebDataServiceConsumer* consumer); + // Schedules a task to add credit card to the web database. + void AddCreditCard(const CreditCard& creditcard); + + // Schedules a task to update credit card in the web database. + void UpdateCreditCard(const CreditCard& creditcard); + + // Schedules a task to remove a credit card from the web database. + // |creditcard_id| is the unique ID of the credit card to remove. + void RemoveCreditCard(int creditcard_id); + + // Initiates the request for all credit cards. The method + // OnWebDataServiceRequestDone of |consumer| gets called when the request is + // finished, with the credit cards included in the argument |result|. The + // consumer owns the credit cards. + Handle GetCreditCards(WebDataServiceConsumer* consumer); + // Testing #ifdef UNIT_TEST void set_failed_init(bool value) { failed_init_ = value; } @@ -531,6 +544,12 @@ class WebDataService void GetAutoFillProfileForLabelImpl(WebDataRequest* request, const string16& label); void GetAutoFillProfilesImpl(WebDataRequest* request); + void AddCreditCardImpl(GenericRequest<CreditCard>* request); + void UpdateCreditCardImpl(GenericRequest<CreditCard>* request); + void RemoveCreditCardImpl(GenericRequest<int>* request); + void GetCreditCardForLabelImpl(WebDataRequest* request, + const string16& label); + void GetCreditCardsImpl(WebDataRequest* request); ////////////////////////////////////////////////////////////////////////////// // diff --git a/chrome/browser/webdata/web_database.cc b/chrome/browser/webdata/web_database.cc index 019c7d3..3bc0438 100644 --- a/chrome/browser/webdata/web_database.cc +++ b/chrome/browser/webdata/web_database.cc @@ -17,6 +17,7 @@ #include "base/utf_string_conversions.h" #include "chrome/browser/autofill/autofill_profile.h" #include "chrome/browser/autofill/autofill_type.h" +#include "chrome/browser/autofill/credit_card.h" #include "chrome/browser/diagnostics/sqlite_diagnostics.h" #include "chrome/browser/history/history_database.h" #include "chrome/browser/webdata/autofill_change.h" @@ -111,6 +112,22 @@ using webkit_glue::PasswordForm; // phone // fax // +// credit_cards This table contains credit card data added by the user +// with the AutoFill dialog. Most of the columns are +// standard entries in a credit card form. +// +// label The label of the credit card. Presented to the user +// when selecting credit cards. +// unique_id The unique ID of this credit card. +// name_on_card +// type +// card_number +// expiration_month +// expiration_year +// verification_code The CVC/CVV/CVV2 card security code. +// billing_address A foreign key into the autofill_profiles table. +// shipping_address A foreign key into the autofill_profiles table. +// // web_app_icons // url URL of the web app. // width Width of the image. @@ -198,7 +215,8 @@ sql::InitStatus WebDatabase::Init(const FilePath& db_name) { // Initialize the tables. if (!InitKeywordsTable() || !InitLoginsTable() || !InitWebAppIconsTable() || !InitWebAppsTable() || !InitAutofillTable() || - !InitAutofillDatesTable() || !InitAutoFillProfilesTable()) { + !InitAutofillDatesTable() || !InitAutoFillProfilesTable() || + !InitCreditCardsTable()) { LOG(WARNING) << "Unable to initialize the web database."; return sql::INIT_FAILURE; } @@ -445,6 +463,31 @@ bool WebDatabase::InitAutoFillProfilesTable() { return true; } +bool WebDatabase::InitCreditCardsTable() { + if (!db_.DoesTableExist("credit_cards")) { + if (!db_.Execute("CREATE TABLE credit_cards ( " + "label VARCHAR, " + "unique_id INTEGER PRIMARY KEY, " + "name_on_card VARCHAR, " + "type VARCHAR, " + "card_number VARCHAR, " + "expiration_month INTEGER, " + "expiration_year INTEGER, " + "verification_code VARCHAR, " + "billing_address VARCHAR, " + "shipping_address VARCHAR)")) { + NOTREACHED(); + return false; + } + if (!db_.Execute("CREATE INDEX credit_cards_label_index " + "ON credit_cards (label)")) { + NOTREACHED(); + return false; + } + } + return true; +} + bool WebDatabase::InitWebAppIconsTable() { if (!db_.DoesTableExist("web_app_icons")) { if (!db_.Execute("CREATE TABLE web_app_icons (" @@ -1331,6 +1374,137 @@ bool WebDatabase::RemoveAutoFillProfile(int profile_id) { return s.Run(); } +static void BindCreditCardToStatement(const CreditCard& creditcard, + sql::Statement* s) { + s->BindString(0, UTF16ToUTF8(creditcard.Label())); + s->BindInt(1, creditcard.unique_id()); + + string16 text = creditcard.GetFieldText(AutoFillType(CREDIT_CARD_NAME)); + s->BindString(2, UTF16ToUTF8(text)); + text = creditcard.GetFieldText(AutoFillType(CREDIT_CARD_TYPE)); + s->BindString(3, UTF16ToUTF8(text)); + text = creditcard.GetFieldText(AutoFillType(CREDIT_CARD_NUMBER)); + s->BindString(4, UTF16ToUTF8(text)); + text = creditcard.GetFieldText(AutoFillType(CREDIT_CARD_EXP_MONTH)); + s->BindString(5, UTF16ToUTF8(text)); + text = creditcard.GetFieldText(AutoFillType(CREDIT_CARD_EXP_4_DIGIT_YEAR)); + s->BindString(6, UTF16ToUTF8(text)); + text = creditcard.GetFieldText(AutoFillType(CREDIT_CARD_VERIFICATION_CODE)); + s->BindString(7, UTF16ToUTF8(text)); + s->BindString(8, UTF16ToUTF8(creditcard.billing_address())); + s->BindString(9, UTF16ToUTF8(creditcard.shipping_address())); +} + +bool WebDatabase::AddCreditCard(const CreditCard& creditcard) { + sql::Statement s(db_.GetUniqueStatement( + "INSERT INTO credit_cards" + "(label, unique_id, name_on_card, type, card_number, expiration_month," + " expiration_year, verification_code, billing_address, shipping_address)" + "VALUES (?,?,?,?,?,?,?,?,?,?)")); + if (!s) { + NOTREACHED() << "Statement prepare failed"; + return false; + } + + BindCreditCardToStatement(creditcard, &s); + + if (!s.Run()) { + NOTREACHED(); + return false; + } + + return s.Succeeded(); +} + +static CreditCard* CreditCardFromStatement(const sql::Statement& s) { + CreditCard* creditcard = new CreditCard( + ASCIIToUTF16(s.ColumnString(0)), s.ColumnInt(1)); + creditcard->SetInfo(AutoFillType(CREDIT_CARD_NAME), + ASCIIToUTF16(s.ColumnString(2))); + creditcard->SetInfo(AutoFillType(CREDIT_CARD_TYPE), + ASCIIToUTF16(s.ColumnString(3))); + creditcard->SetInfo(AutoFillType(CREDIT_CARD_NUMBER), + ASCIIToUTF16(s.ColumnString(4))); + creditcard->SetInfo(AutoFillType(CREDIT_CARD_EXP_MONTH), + ASCIIToUTF16(s.ColumnString(5))); + creditcard->SetInfo(AutoFillType(CREDIT_CARD_EXP_4_DIGIT_YEAR), + ASCIIToUTF16(s.ColumnString(6))); + creditcard->SetInfo(AutoFillType(CREDIT_CARD_VERIFICATION_CODE), + ASCIIToUTF16(s.ColumnString(7))); + creditcard->set_billing_address(ASCIIToUTF16(s.ColumnString(8))); + creditcard->set_shipping_address(ASCIIToUTF16(s.ColumnString(9))); + + return creditcard; +} + +bool WebDatabase::GetCreditCardForLabel(const string16& label, + CreditCard** creditcard) { + DCHECK(creditcard); + sql::Statement s(db_.GetUniqueStatement( + "SELECT * FROM credit_cards " + "WHERE label = ?")); + if (!s) { + NOTREACHED() << "Statement prepare failed"; + return false; + } + + s.BindString(0, UTF16ToUTF8(label)); + if (!s.Step()) + return false; + + *creditcard = CreditCardFromStatement(s); + + return s.Succeeded(); +} + +bool WebDatabase::GetCreditCards( + std::vector<CreditCard*>* creditcards) { + DCHECK(creditcards); + creditcards->clear(); + + sql::Statement s(db_.GetUniqueStatement("SELECT * FROM credit_cards")); + if (!s) { + NOTREACHED() << "Statement prepare failed"; + return false; + } + + while (s.Step()) + creditcards->push_back(CreditCardFromStatement(s)); + + return s.Succeeded(); +} + +bool WebDatabase::UpdateCreditCard(const CreditCard& creditcard) { + DCHECK(creditcard.unique_id()); + sql::Statement s(db_.GetUniqueStatement( + "UPDATE credit_cards " + "SET label=?, unique_id=?, name_on_card=?, type=?, card_number=?, " + " expiration_month=?, expiration_year=?, verification_code=?, " + " billing_address=?, shipping_address=? " + "WHERE unique_id=?")); + if (!s) { + NOTREACHED() << "Statement prepare failed"; + return false; + } + + BindCreditCardToStatement(creditcard, &s); + s.BindInt(10, creditcard.unique_id()); + return s.Run(); +} + +bool WebDatabase::RemoveCreditCard(int creditcard_id) { + DCHECK_NE(0, creditcard_id); + sql::Statement s(db_.GetUniqueStatement( + "DELETE FROM credit_cards WHERE unique_id = ?")); + if (!s) { + NOTREACHED() << "Statement prepare failed"; + return false; + } + + s.BindInt(0, creditcard_id); + return s.Run(); +} + bool WebDatabase::AddToCountOfFormElement(int64 pair_id, int delta, bool* was_removed) { diff --git a/chrome/browser/webdata/web_database.h b/chrome/browser/webdata/web_database.h index 2820beb1..d8179b1 100644 --- a/chrome/browser/webdata/web_database.h +++ b/chrome/browser/webdata/web_database.h @@ -17,6 +17,7 @@ class AutofillChange; class AutoFillProfile; +class CreditCard; class FilePath; namespace base { @@ -215,6 +216,23 @@ class WebDatabase { // Retrieves all profiles in the database. Caller owns the returned profiles. bool GetAutoFillProfiles(std::vector<AutoFillProfile*>* profiles); + // Records a single credit card in the credit_cards table. + bool AddCreditCard(const CreditCard& creditcard); + + // Updates the database values for the specified profile. + bool UpdateCreditCard(const CreditCard& profile); + + // Removes a row from the autofill_profiles table. |profile_id| is the + // unique ID of the profile to remove. + bool RemoveCreditCard(int profile_id); + + // Retrieves a profile with label |label|. The caller owns |profile|. + bool GetCreditCardForLabel(const string16& label, + CreditCard** profile); + + // Retrieves all profiles in the database. Caller owns the returned profiles. + bool GetCreditCards(std::vector<CreditCard*>* profiles); + ////////////////////////////////////////////////////////////////////////////// // // Web Apps @@ -255,6 +273,7 @@ class WebDatabase { bool InitAutofillTable(); bool InitAutofillDatesTable(); bool InitAutoFillProfilesTable(); + bool InitCreditCardsTable(); bool InitWebAppIconsTable(); bool InitWebAppsTable(); diff --git a/chrome/browser/webdata/web_database_unittest.cc b/chrome/browser/webdata/web_database_unittest.cc index c0f340d..1b950c8 100644 --- a/chrome/browser/webdata/web_database_unittest.cc +++ b/chrome/browser/webdata/web_database_unittest.cc @@ -13,6 +13,7 @@ #include "base/values.h" #include "chrome/browser/autofill/autofill_profile.h" #include "chrome/browser/autofill/autofill_type.h" +#include "chrome/browser/autofill/credit_card.h" #include "chrome/browser/search_engines/template_url.h" #include "chrome/browser/webdata/autofill_change.h" #include "chrome/browser/webdata/autofill_entry.h" @@ -900,8 +901,7 @@ TEST_F(WebDatabaseTest, AutoFillProfile) { // Get the 'Home' profile. AutoFillProfile* db_profile; - EXPECT_TRUE(db.GetAutoFillProfileForLabel(ASCIIToUTF16("Home"), - &db_profile)); + ASSERT_TRUE(db.GetAutoFillProfileForLabel(ASCIIToUTF16("Home"), &db_profile)); EXPECT_EQ(home_profile, *db_profile); delete db_profile; @@ -915,7 +915,7 @@ TEST_F(WebDatabaseTest, AutoFillProfile) { ASCIIToUTF16("suite 3")); EXPECT_TRUE(db.AddAutoFillProfile(billing_profile)); - EXPECT_TRUE(db.GetAutoFillProfileForLabel(ASCIIToUTF16("Billing"), + ASSERT_TRUE(db.GetAutoFillProfileForLabel(ASCIIToUTF16("Billing"), &db_profile)); EXPECT_EQ(billing_profile, *db_profile); delete db_profile; @@ -923,7 +923,7 @@ TEST_F(WebDatabaseTest, AutoFillProfile) { // Update the 'Billing' profile. billing_profile.SetInfo(AutoFillType(NAME_FIRST), ASCIIToUTF16("Jane")); EXPECT_TRUE(db.UpdateAutoFillProfile(billing_profile)); - EXPECT_TRUE(db.GetAutoFillProfileForLabel(ASCIIToUTF16("Billing"), + ASSERT_TRUE(db.GetAutoFillProfileForLabel(ASCIIToUTF16("Billing"), &db_profile)); EXPECT_EQ(billing_profile, *db_profile); delete db_profile; @@ -933,3 +933,70 @@ TEST_F(WebDatabaseTest, AutoFillProfile) { EXPECT_FALSE(db.GetAutoFillProfileForLabel(ASCIIToUTF16("Billing"), &db_profile)); } + +TEST_F(WebDatabaseTest, CreditCard) { + WebDatabase db; + + ASSERT_EQ(sql::INIT_OK, db.Init(file_)); + + // Add a 'Work' credit card. + CreditCard work_creditcard(ASCIIToUTF16("Work"), 13); + work_creditcard.SetInfo(AutoFillType(CREDIT_CARD_NAME), + ASCIIToUTF16("Jack Torrance")); + work_creditcard.SetInfo(AutoFillType(CREDIT_CARD_TYPE), + ASCIIToUTF16("Visa")); + work_creditcard.SetInfo(AutoFillType(CREDIT_CARD_NUMBER), + ASCIIToUTF16("1234567890123456")); + work_creditcard.SetInfo(AutoFillType(CREDIT_CARD_EXP_MONTH), + ASCIIToUTF16("04")); + work_creditcard.SetInfo(AutoFillType(CREDIT_CARD_EXP_4_DIGIT_YEAR), + ASCIIToUTF16("2013")); + work_creditcard.SetInfo(AutoFillType(CREDIT_CARD_VERIFICATION_CODE), + ASCIIToUTF16("987")); + work_creditcard.set_billing_address(ASCIIToUTF16("Overlook Hotel")); + work_creditcard.set_shipping_address(ASCIIToUTF16("Timberline Lodge")); + + EXPECT_TRUE(db.AddCreditCard(work_creditcard)); + + // Get the 'Work' credit card. + CreditCard* db_creditcard; + ASSERT_TRUE(db.GetCreditCardForLabel(ASCIIToUTF16("Work"), &db_creditcard)); + EXPECT_EQ(work_creditcard, *db_creditcard); + delete db_creditcard; + + // Add a 'Target' profile. + CreditCard target_creditcard(ASCIIToUTF16("Target"), 7); + target_creditcard.SetInfo(AutoFillType(CREDIT_CARD_NAME), + ASCIIToUTF16("Jack Torrance")); + target_creditcard.SetInfo(AutoFillType(CREDIT_CARD_TYPE), + ASCIIToUTF16("Mastercard")); + target_creditcard.SetInfo(AutoFillType(CREDIT_CARD_NUMBER), + ASCIIToUTF16("1111222233334444")); + target_creditcard.SetInfo(AutoFillType(CREDIT_CARD_EXP_MONTH), + ASCIIToUTF16("06")); + target_creditcard.SetInfo(AutoFillType(CREDIT_CARD_EXP_4_DIGIT_YEAR), + ASCIIToUTF16("2012")); + target_creditcard.SetInfo(AutoFillType(CREDIT_CARD_VERIFICATION_CODE), + ASCIIToUTF16("123")); + target_creditcard.set_billing_address(ASCIIToUTF16("Overlook Hotel")); + target_creditcard.set_shipping_address(string16()); + + EXPECT_TRUE(db.AddCreditCard(target_creditcard)); + ASSERT_TRUE(db.GetCreditCardForLabel(ASCIIToUTF16("Target"), + &db_creditcard)); + EXPECT_EQ(target_creditcard, *db_creditcard); + delete db_creditcard; + + // Update the 'Target' profile. + target_creditcard.SetInfo(AutoFillType(CREDIT_CARD_NAME), + ASCIIToUTF16("Charles Grady")); + EXPECT_TRUE(db.UpdateCreditCard(target_creditcard)); + ASSERT_TRUE(db.GetCreditCardForLabel(ASCIIToUTF16("Target"), &db_creditcard)); + EXPECT_EQ(target_creditcard, *db_creditcard); + delete db_creditcard; + + // Remove the 'Billing' profile. + EXPECT_TRUE(db.RemoveCreditCard(target_creditcard.unique_id())); + EXPECT_FALSE(db.GetCreditCardForLabel(ASCIIToUTF16("Target"), + &db_creditcard)); +} |