diff options
author | Allan Sandfeld Jensen <allan.jensen@qt.io> | 2019-05-24 11:40:17 +0200 |
---|---|---|
committer | Allan Sandfeld Jensen <allan.jensen@qt.io> | 2019-05-24 12:42:11 +0000 |
commit | 5d87695f37678f96492b258bbab36486c59866b4 (patch) | |
tree | be9783bbaf04fb930c4d74ca9c00b5e7954c8bc6 /chromium/components/autofill/core/browser | |
parent | 6c11fb357ec39bf087b8b632e2b1e375aef1b38b (diff) | |
download | qtwebengine-chromium-5d87695f37678f96492b258bbab36486c59866b4.tar.gz |
BASELINE: Update Chromium to 75.0.3770.56
Change-Id: I86d2007fd27a45d5797eee06f4c9369b8b50ac4f
Reviewed-by: Alexandru Croitor <alexandru.croitor@qt.io>
Diffstat (limited to 'chromium/components/autofill/core/browser')
221 files changed, 7785 insertions, 4608 deletions
diff --git a/chromium/components/autofill/core/browser/BUILD.gn b/chromium/components/autofill/core/browser/BUILD.gn index fea04db6961..8b751bc708a 100644 --- a/chromium/components/autofill/core/browser/BUILD.gn +++ b/chromium/components/autofill/core/browser/BUILD.gn @@ -11,11 +11,14 @@ jumbo_static_library("browser") { sources = [ "accessory_sheet_data.cc", "accessory_sheet_data.h", - "account_info_getter.h", "address.cc", "address.h", "address_combobox_model.cc", "address_combobox_model.h", + "address_contact_form_label_formatter.cc", + "address_contact_form_label_formatter.h", + "address_email_form_label_formatter.cc", + "address_email_form_label_formatter.h", "address_field.cc", "address_field.h", "address_form_label_formatter.cc", @@ -27,6 +30,8 @@ jumbo_static_library("browser") { "address_normalizer.h", "address_normalizer_impl.cc", "address_normalizer_impl.h", + "address_phone_form_label_formatter.cc", + "address_phone_form_label_formatter.h", "address_rewriter.cc", "address_rewriter.h", "address_rewriter_rules.cc", @@ -88,12 +93,6 @@ jumbo_static_library("browser") { "autofill_subject.h", "autofill_type.cc", "autofill_type.h", - "autofill_wallet_data_type_controller.cc", - "autofill_wallet_data_type_controller.h", - "autofill_wallet_model_type_controller.cc", - "autofill_wallet_model_type_controller.h", - "card_unmask_delegate.cc", - "card_unmask_delegate.h", "contact_form_label_formatter.cc", "contact_form_label_formatter.h", "contact_info.cc", @@ -108,10 +107,6 @@ jumbo_static_library("browser") { "credit_card.h", "credit_card_field.cc", "credit_card_field.h", - "credit_card_save_manager.cc", - "credit_card_save_manager.h", - "credit_card_save_strike_database.cc", - "credit_card_save_strike_database.h", "email_field.cc", "email_field.h", "field_candidates.cc", @@ -133,14 +128,6 @@ jumbo_static_library("browser") { "label_formatter.h", "label_formatter_utils.cc", "label_formatter_utils.h", - "legacy_strike_database.cc", - "legacy_strike_database.h", - "legal_message_line.cc", - "legal_message_line.h", - "local_card_migration_manager.cc", - "local_card_migration_manager.h", - "local_card_migration_strike_database.cc", - "local_card_migration_strike_database.h", "metrics/address_form_event_logger.cc", "metrics/address_form_event_logger.h", "metrics/credit_card_form_event_logger.cc", @@ -150,13 +137,27 @@ jumbo_static_library("browser") { "metrics/form_events.h", "name_field.cc", "name_field.h", - "password_requirements_spec_fetcher.h", - "password_requirements_spec_fetcher_impl.cc", - "password_requirements_spec_fetcher_impl.h", - "password_requirements_spec_printer.cc", - "password_requirements_spec_printer.h", + "payments/account_info_getter.h", + "payments/autofill_wallet_data_type_controller.cc", + "payments/autofill_wallet_data_type_controller.h", + "payments/autofill_wallet_model_type_controller.cc", + "payments/autofill_wallet_model_type_controller.h", + "payments/card_unmask_delegate.cc", + "payments/card_unmask_delegate.h", + "payments/credit_card_save_manager.cc", + "payments/credit_card_save_manager.h", + "payments/credit_card_save_strike_database.cc", + "payments/credit_card_save_strike_database.h", "payments/full_card_request.cc", "payments/full_card_request.h", + "payments/legacy_strike_database.cc", + "payments/legacy_strike_database.h", + "payments/legal_message_line.cc", + "payments/legal_message_line.h", + "payments/local_card_migration_manager.cc", + "payments/local_card_migration_manager.h", + "payments/local_card_migration_strike_database.cc", + "payments/local_card_migration_strike_database.h", "payments/payments_client.cc", "payments/payments_client.h", "payments/payments_customer_data.h", @@ -165,6 +166,13 @@ jumbo_static_library("browser") { "payments/payments_service_url.h", "payments/payments_util.cc", "payments/payments_util.h", + "payments/risk_data_loader.h", + "payments/strike_database.cc", + "payments/strike_database.h", + "payments/strike_database_integrator_base.cc", + "payments/strike_database_integrator_base.h", + "payments/strike_database_integrator_test_strike_database.cc", + "payments/strike_database_integrator_test_strike_database.h", "personal_data_manager.cc", "personal_data_manager.h", "personal_data_manager_observer.h", @@ -187,17 +195,10 @@ jumbo_static_library("browser") { "region_data_loader.h", "region_data_loader_impl.cc", "region_data_loader_impl.h", - "risk_data_loader.h", "search_field.cc", "search_field.h", "state_names.cc", "state_names.h", - "strike_database.cc", - "strike_database.h", - "strike_database_integrator_base.cc", - "strike_database_integrator_base.h", - "strike_database_integrator_test_strike_database.cc", - "strike_database_integrator_test_strike_database.h", "subkey_requester.cc", "subkey_requester.h", "suggestion.cc", @@ -209,10 +210,10 @@ jumbo_static_library("browser") { "test_data_creator.h", "travel_field.cc", "travel_field.h", - "ui/card_unmask_prompt_controller.h", - "ui/card_unmask_prompt_controller_impl.cc", - "ui/card_unmask_prompt_controller_impl.h", - "ui/card_unmask_prompt_view.h", + "ui/payments/card_unmask_prompt_controller.h", + "ui/payments/card_unmask_prompt_controller_impl.cc", + "ui/payments/card_unmask_prompt_controller_impl.h", + "ui/payments/card_unmask_prompt_view.h", "validation.cc", "validation.h", "webdata/autocomplete_sync_bridge.cc", @@ -246,10 +247,11 @@ jumbo_static_library("browser") { "webdata/autofill_wallet_sync_bridge.h", "webdata/autofill_wallet_syncable_service.cc", "webdata/autofill_wallet_syncable_service.h", - "webdata/autofill_webdata.h", "webdata/autofill_webdata_backend.h", "webdata/autofill_webdata_backend_impl.cc", "webdata/autofill_webdata_backend_impl.h", + "webdata/autofill_webdata_backend_util.cc", + "webdata/autofill_webdata_backend_util.h", "webdata/autofill_webdata_service.cc", "webdata/autofill_webdata_service.h", "webdata/autofill_webdata_service_observer.h", @@ -268,23 +270,23 @@ jumbo_static_library("browser") { sources += [ "autofill_assistant.cc", "autofill_assistant.h", - "autofill_credit_card_filling_infobar_delegate_mobile.cc", - "autofill_credit_card_filling_infobar_delegate_mobile.h", - "autofill_save_card_infobar_delegate_mobile.cc", - "autofill_save_card_infobar_delegate_mobile.h", - "autofill_save_card_infobar_mobile.h", - "ui/card_expiration_date_fix_flow_view_delegate_mobile.cc", - "ui/card_expiration_date_fix_flow_view_delegate_mobile.h", - "ui/card_name_fix_flow_view_delegate_mobile.cc", - "ui/card_name_fix_flow_view_delegate_mobile.h", + "payments/autofill_credit_card_filling_infobar_delegate_mobile.cc", + "payments/autofill_credit_card_filling_infobar_delegate_mobile.h", + "payments/autofill_save_card_infobar_delegate_mobile.cc", + "payments/autofill_save_card_infobar_delegate_mobile.h", + "payments/autofill_save_card_infobar_mobile.h", + "ui/payments/card_expiration_date_fix_flow_view_delegate_mobile.cc", + "ui/payments/card_expiration_date_fix_flow_view_delegate_mobile.h", + "ui/payments/card_name_fix_flow_view_delegate_mobile.cc", + "ui/payments/card_name_fix_flow_view_delegate_mobile.h", ] } if (!is_android) { sources += [ - "ui/local_card_migration_bubble_controller.h", - "ui/local_card_migration_dialog_controller.h", - "ui/save_card_bubble_controller.h", + "ui/payments/local_card_migration_bubble_controller.h", + "ui/payments/local_card_migration_dialog_controller.h", + "ui/payments/save_card_bubble_controller.h", ] } @@ -312,8 +314,6 @@ jumbo_static_library("browser") { "//third_party/libaddressinput", ] deps = [ - ":password_generator", - ":password_generator_fips181", "proto:legacy_proto_bridge", "//base", "//base:i18n", @@ -378,8 +378,18 @@ jumbo_static_library("test_support") { "data_driven_test.h", "mock_autocomplete_history_manager.cc", "mock_autocomplete_history_manager.h", + "payments/test_credit_card_save_manager.cc", + "payments/test_credit_card_save_manager.h", + "payments/test_credit_card_save_strike_database.cc", + "payments/test_credit_card_save_strike_database.h", + "payments/test_legacy_strike_database.cc", + "payments/test_legacy_strike_database.h", + "payments/test_local_card_migration_manager.cc", + "payments/test_local_card_migration_manager.h", "payments/test_payments_client.cc", "payments/test_payments_client.h", + "payments/test_strike_database.cc", + "payments/test_strike_database.h", "suggestion_test_helpers.h", "test_address_normalizer.cc", "test_address_normalizer.h", @@ -403,25 +413,15 @@ jumbo_static_library("test_support") { "test_autofill_profile_validator_delayed.h", "test_autofill_provider.cc", "test_autofill_provider.h", - "test_credit_card_save_manager.cc", - "test_credit_card_save_manager.h", - "test_credit_card_save_strike_database.cc", - "test_credit_card_save_strike_database.h", "test_event_waiter.h", "test_form_data_importer.cc", "test_form_data_importer.h", "test_form_structure.cc", "test_form_structure.h", - "test_legacy_strike_database.cc", - "test_legacy_strike_database.h", - "test_local_card_migration_manager.cc", - "test_local_card_migration_manager.h", "test_personal_data_manager.cc", "test_personal_data_manager.h", "test_region_data_loader.cc", "test_region_data_loader.h", - "test_strike_database.cc", - "test_strike_database.h", "webdata/autofill_sync_bridge_test_util.cc", "webdata/autofill_sync_bridge_test_util.h", "webdata/mock_autofill_webdata_backend.cc", @@ -459,30 +459,6 @@ jumbo_static_library("test_support") { ] } -static_library("password_generator") { - sources = [ - "password_generator.cc", - "password_generator.h", - ] - public_deps = [ - "//components/autofill/core/browser/proto", - ] - deps = [ - "//base", - ] -} - -static_library("password_generator_fips181") { - sources = [ - "password_generator_fips181.cc", - "password_generator_fips181.h", - ] - deps = [ - "//base", - "//third_party/fips181", - ] -} - bundle_data("unit_tests_bundle_data") { sources = [ "//components/test/data/autofill/merge/input/ambiguous.in", @@ -535,30 +511,28 @@ source_set("unit_tests") { "autofill_profile_validator_unittest.cc", "autofill_subject_unittest.cc", "autofill_type_unittest.cc", - "autofill_wallet_data_type_controller_unittest.cc", "contact_info_unittest.cc", "country_combobox_model_unittest.cc", "country_names_unittest.cc", "credit_card_field_unittest.cc", - "credit_card_save_manager_unittest.cc", "credit_card_unittest.cc", "field_candidates_unittest.cc", "field_filler_unittest.cc", "form_data_importer_unittest.cc", "form_field_unittest.cc", "form_structure_unittest.cc", - "label_formatter_utils_unittest.cc", - "legacy_strike_database_unittest.cc", - "legal_message_line_unittest.cc", - "local_card_migration_manager_unittest.cc", "name_field_unittest.cc", - "password_generator_fips181_unittest.cc", - "password_generator_unittest.cc", - "password_requirements_spec_fetcher_unittest.cc", + "payments/autofill_wallet_data_type_controller_unittest.cc", + "payments/credit_card_save_manager_unittest.cc", "payments/full_card_request_unittest.cc", + "payments/legacy_strike_database_unittest.cc", + "payments/legal_message_line_unittest.cc", + "payments/local_card_migration_manager_unittest.cc", "payments/payments_client_unittest.cc", "payments/payments_service_url_unittest.cc", "payments/payments_util_unittest.cc", + "payments/strike_database_integrator_test_strike_database_unittest.cc", + "payments/strike_database_unittest.cc", "personal_data_manager_unittest.cc", "phone_field_unittest.cc", "phone_number_i18n_unittest.cc", @@ -569,11 +543,9 @@ source_set("unit_tests") { "rationalization_util_unittest.cc", "region_combobox_model_unittest.cc", "search_field_unittest.cc", - "strike_database_integrator_test_strike_database_unittest.cc", - "strike_database_unittest.cc", "subkey_requester_unittest.cc", "suggestion_selection_unittest.cc", - "ui/card_unmask_prompt_controller_impl_unittest.cc", + "ui/payments/card_unmask_prompt_controller_impl_unittest.cc", "validation_unittest.cc", "webdata/autocomplete_sync_bridge_unittest.cc", "webdata/autofill_profile_sync_bridge_unittest.cc", @@ -600,12 +572,22 @@ source_set("unit_tests") { ] } + if (!is_ios && !is_android) { + sources += [ + "address_contact_form_label_formatter_unittest.cc", + "address_email_form_label_formatter_unittest.cc", + "address_form_label_formatter_unittest.cc", + "address_phone_form_label_formatter_unittest.cc", + "contact_form_label_formatter_unittest.cc", + "label_formatter_unittest.cc", + "label_formatter_utils_unittest.cc", + ] + } + defines = [ "CHROME_VERSION_MAJOR=" + chrome_version_major ] deps = [ ":browser", - ":password_generator", - ":password_generator_fips181", ":test_support", ":unit_tests_bundle_data", "proto:legacy_proto_bridge", @@ -665,15 +647,6 @@ fuzzer_test("form_structure_fuzzer") { dict = "form_structure_fuzzer.dict" } -fuzzer_test("password_generator_fips181_fuzzer") { - sources = [ - "password_generator_fips181_fuzzer.cc", - ] - deps = [ - ":password_generator_fips181", - ] -} - if (use_libfuzzer) { fuzzer_test("form_structure_process_query_response_fuzzer") { sources = [ @@ -688,17 +661,6 @@ if (use_libfuzzer) { "//third_party/libprotobuf-mutator", ] } - - fuzzer_test("password_generator_proto_fuzzer") { - sources = [ - "password_generator_proto_fuzzer.cc", - ] - deps = [ - ":password_generator", - "//components/autofill/core/browser/proto", - "//third_party/libprotobuf-mutator", - ] - } } fuzzer_test("autofill_phone_number_i18n_fuzzer") { diff --git a/chromium/components/autofill/core/browser/DEPS b/chromium/components/autofill/core/browser/DEPS index 3536f9f5ce0..55b6c82a628 100644 --- a/chromium/components/autofill/core/browser/DEPS +++ b/chromium/components/autofill/core/browser/DEPS @@ -32,7 +32,6 @@ include_rules = [ "+services/network/public", "+services/network/test", "+sql", - "+third_party/fips181", "+third_party/libaddressinput", # For address i18n. "+third_party/libphonenumber", # For phone number i18n. "+third_party/re2", diff --git a/chromium/components/autofill/core/browser/OWNERS b/chromium/components/autofill/core/browser/OWNERS index 013fa313149..c23e8389686 100644 --- a/chromium/components/autofill/core/browser/OWNERS +++ b/chromium/components/autofill/core/browser/OWNERS @@ -1 +1,4 @@ parastoog@google.com + +per-file *type_controller*=jkrcal@chromium.org +per-file *type_controller*=file://components/sync/OWNERS diff --git a/chromium/components/autofill/core/browser/address_contact_form_label_formatter.cc b/chromium/components/autofill/core/browser/address_contact_form_label_formatter.cc new file mode 100644 index 00000000000..32b1a9de7be --- /dev/null +++ b/chromium/components/autofill/core/browser/address_contact_form_label_formatter.cc @@ -0,0 +1,61 @@ +// Copyright 2019 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "components/autofill/core/browser/address_contact_form_label_formatter.h" + +#include "components/autofill/core/browser/label_formatter_utils.h" + +namespace autofill { + +AddressContactFormLabelFormatter::AddressContactFormLabelFormatter( + const std::string& app_locale, + ServerFieldType focused_field_type, + uint32_t groups, + const std::vector<ServerFieldType>& field_types, + bool show_phone, + bool show_email) + : LabelFormatter(app_locale, focused_field_type, groups, field_types), + form_has_street_address_(HasStreetAddress(field_types_for_labels())), + show_phone_(show_phone), + show_email_(show_email) {} + +AddressContactFormLabelFormatter::~AddressContactFormLabelFormatter() {} + +// Note that the order in which parts of the label are added--name, street +// address, phone, and email--ensures that the label is formatted correctly for +// |focused_group|, |focused_field_type_|, and this kind of formatter. +base::string16 AddressContactFormLabelFormatter::GetLabelForProfile( + const AutofillProfile& profile, + FieldTypeGroup focused_group) const { + std::vector<base::string16> label_parts; + + bool street_address_is_focused = focused_group == ADDRESS_HOME && + IsStreetAddressPart(focused_field_type()); + bool non_street_address_is_focused = + focused_group == ADDRESS_HOME && + !IsStreetAddressPart(focused_field_type()); + + if (focused_group != NAME && !non_street_address_is_focused) { + AddLabelPartIfNotEmpty(GetLabelName(profile, app_locale()), &label_parts); + } + + if (!street_address_is_focused) { + AddLabelPartIfNotEmpty( + GetLabelAddress(form_has_street_address_, profile, app_locale(), + field_types_for_labels()), + &label_parts); + } + + if (focused_group != PHONE_HOME && show_phone_) { + AddLabelPartIfNotEmpty(GetLabelPhone(profile, app_locale()), &label_parts); + } + + if (focused_group != EMAIL && show_email_) { + AddLabelPartIfNotEmpty(GetLabelEmail(profile, app_locale()), &label_parts); + } + + return ConstructLabelLine(label_parts); +} + +} // namespace autofill diff --git a/chromium/components/autofill/core/browser/address_contact_form_label_formatter.h b/chromium/components/autofill/core/browser/address_contact_form_label_formatter.h new file mode 100644 index 00000000000..eb851cab460 --- /dev/null +++ b/chromium/components/autofill/core/browser/address_contact_form_label_formatter.h @@ -0,0 +1,52 @@ +// Copyright 2019 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef COMPONENTS_AUTOFILL_CORE_BROWSER_ADDRESS_CONTACT_FORM_LABEL_FORMATTER_H_ +#define COMPONENTS_AUTOFILL_CORE_BROWSER_ADDRESS_CONTACT_FORM_LABEL_FORMATTER_H_ + +#include <string> +#include <vector> + +#include "base/strings/string16.h" +#include "components/autofill/core/browser/autofill_profile.h" +#include "components/autofill/core/browser/field_types.h" +#include "components/autofill/core/browser/label_formatter.h" + +namespace autofill { + +// A LabelFormatter that creates Suggestions' disambiguating labels for forms +// with name, address, email, and phone fields. +class AddressContactFormLabelFormatter : public LabelFormatter { + public: + AddressContactFormLabelFormatter( + const std::string& app_locale, + ServerFieldType focused_field_type, + uint32_t groups, + const std::vector<ServerFieldType>& field_types, + bool show_phone, + bool show_email); + + ~AddressContactFormLabelFormatter() override; + + base::string16 GetLabelForProfile( + const AutofillProfile& profile, + FieldTypeGroup focused_group) const override; + + private: + // True if this formatter's associated form has a street address field. A + // form may have an address-related field, e.g. zip code, without having a + // street address field. If a form does not include a street address field, + // street addresses should not appear in labels. + bool form_has_street_address_; + + // True if phone numbers should be included in labels. + bool show_phone_; + + // True if email addresses should be included in labels. + bool show_email_; +}; + +} // namespace autofill + +#endif // COMPONENTS_AUTOFILL_CORE_BROWSER_ADDRESS_CONTACT_FORM_LABEL_FORMATTER_H_ diff --git a/chromium/components/autofill/core/browser/address_contact_form_label_formatter_unittest.cc b/chromium/components/autofill/core/browser/address_contact_form_label_formatter_unittest.cc new file mode 100644 index 00000000000..b9508f2c02e --- /dev/null +++ b/chromium/components/autofill/core/browser/address_contact_form_label_formatter_unittest.cc @@ -0,0 +1,510 @@ +// Copyright 2019 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "components/autofill/core/browser/address_contact_form_label_formatter.h" + +#include <memory> +#include <string> +#include <vector> + +#include "base/guid.h" +#include "base/strings/string16.h" +#include "base/strings/utf_string_conversions.h" +#include "components/autofill/core/browser/autofill_profile.h" +#include "components/autofill/core/browser/autofill_test_utils.h" +#include "components/autofill/core/browser/field_types.h" +#include "components/autofill/core/browser/label_formatter_utils.h" +#include "testing/gmock/include/gmock/gmock.h" +#include "testing/gtest/include/gtest/gtest.h" + +using testing::ElementsAre; + +namespace autofill { +namespace { + +std::vector<ServerFieldType> GetFieldTypes() { + return {NO_SERVER_DATA, + NAME_BILLING_FULL, + EMAIL_ADDRESS, + ADDRESS_BILLING_LINE1, + ADDRESS_BILLING_LINE2, + ADDRESS_BILLING_DEPENDENT_LOCALITY, + ADDRESS_BILLING_CITY, + ADDRESS_BILLING_STATE, + ADDRESS_BILLING_ZIP, + ADDRESS_BILLING_COUNTRY, + PHONE_BILLING_WHOLE_NUMBER}; +} + +TEST(AddressContactFormLabelFormatterTest, GetLabelsWithMissingProfiles) { + const std::vector<AutofillProfile*> profiles{}; + const std::unique_ptr<LabelFormatter> formatter = LabelFormatter::Create( + "en-US", NAME_BILLING_FULL, GetFieldTypes(), profiles); + EXPECT_TRUE(formatter->GetLabels(profiles).empty()); +} + +TEST(AddressContactFormLabelFormatterTest, + GetLabelsForUSProfilesAndFocusedName) { + AutofillProfile profile1 = + AutofillProfile(base::GenerateGUID(), test::kEmptyOrigin); + test::SetProfileInfo(&profile1, "Sarah", "", "Revere", "sarah.revere@aol.com", + "", "19 North Sq", "", "Boston", "MA", "02113", "US", + "16175232338"); + + AutofillProfile profile2 = + AutofillProfile(base::GenerateGUID(), test::kEmptyOrigin); + test::SetProfileInfo(&profile2, "Jackie", "L", "Kennedy", "", "", + "151 Irving Ave", "", "Hyannis", "MA", "02601", "US", + "6175141600"); + + AutofillProfile profile3 = + AutofillProfile(base::GenerateGUID(), test::kEmptyOrigin); + test::SetProfileInfo(&profile3, "Paul", "", "Revere", "paul1775@gmail.com", + "", "19 North Sq", "", "Boston", "MA", "02113", "US", + ""); + + AutofillProfile profile4 = + AutofillProfile(base::GenerateGUID(), test::kEmptyOrigin); + test::SetProfileInfo(&profile4, "Deborah", "", "Katabi", "deborah@mit.edu", + "", "", "", "", "", "", "US", "6173240000"); + + AutofillProfile profile5 = + AutofillProfile(base::GenerateGUID(), test::kEmptyOrigin); + test::SetProfileInfo(&profile5, "", "", "", "", "", "Old North Church", + "193 Salem St", "Boston", "MA", "02113", "US", ""); + + AutofillProfile profile6 = + AutofillProfile(base::GenerateGUID(), test::kEmptyOrigin); + test::SetProfileInfo(&profile6, "", "", "", "", "", "", "", "", "", "", "US", + ""); + + const std::vector<AutofillProfile*> profiles{&profile1, &profile2, &profile3, + &profile4, &profile5, &profile6}; + const std::unique_ptr<LabelFormatter> formatter = LabelFormatter::Create( + "en-US", NAME_BILLING_FULL, GetFieldTypes(), profiles); + + EXPECT_THAT( + formatter->GetLabels(profiles), + ElementsAre( + ConstructLabelLine({base::ASCIIToUTF16("19 North Sq"), + base::ASCIIToUTF16("(617) 523-2338"), + base::ASCIIToUTF16("sarah.revere@aol.com")}), + ConstructLabelLine({base::ASCIIToUTF16("151 Irving Ave"), + base::ASCIIToUTF16("(617) 514-1600")}), + ConstructLabelLine({base::ASCIIToUTF16("19 North Sq"), + base::ASCIIToUTF16("paul1775@gmail.com")}), + ConstructLabelLine({base::ASCIIToUTF16("(617) 324-0000"), + base::ASCIIToUTF16("deborah@mit.edu")}), + base::ASCIIToUTF16("Old North Church, 193 Salem St"), + base::string16())); +} + +TEST(AddressContactFormLabelFormatterTest, + GetLabelsForUSProfilesAndFocusedStreetAddress) { + AutofillProfile profile1 = + AutofillProfile(base::GenerateGUID(), test::kEmptyOrigin); + test::SetProfileInfo(&profile1, "Sarah", "", "Revere", "sarah.revere@aol.com", + "", "19 North Sq", "", "Boston", "MA", "02113", "US", + "16175232338"); + + AutofillProfile profile2 = + AutofillProfile(base::GenerateGUID(), test::kEmptyOrigin); + test::SetProfileInfo(&profile2, "Jackie", "L", "Kennedy", "", "", + "151 Irving Ave", "", "Hyannis", "MA", "02601", "US", + "6175141600"); + + AutofillProfile profile3 = + AutofillProfile(base::GenerateGUID(), test::kEmptyOrigin); + test::SetProfileInfo(&profile3, "Paul", "", "Revere", "paul1775@gmail.com", + "", "19 North Sq", "", "Boston", "MA", "02113", "US", + ""); + + AutofillProfile profile4 = + AutofillProfile(base::GenerateGUID(), test::kEmptyOrigin); + test::SetProfileInfo(&profile4, "Deborah", "", "Katabi", "deborah@mit.edu", + "", "", "", "", "", "", "US", "6173240000"); + + AutofillProfile profile5 = + AutofillProfile(base::GenerateGUID(), test::kEmptyOrigin); + test::SetProfileInfo(&profile5, "", "", "", "", "", "Old North Church", + "193 Salem St", "Boston", "MA", "02113", "US", ""); + + AutofillProfile profile6 = + AutofillProfile(base::GenerateGUID(), test::kEmptyOrigin); + test::SetProfileInfo(&profile6, "", "", "", "", "", "", "", "", "", "", "US", + ""); + + const std::vector<AutofillProfile*> profiles{&profile1, &profile2, &profile3, + &profile4, &profile5, &profile6}; + const std::unique_ptr<LabelFormatter> formatter = LabelFormatter::Create( + "en-US", ADDRESS_BILLING_LINE1, GetFieldTypes(), profiles); + + EXPECT_THAT( + formatter->GetLabels(profiles), + ElementsAre( + ConstructLabelLine({base::ASCIIToUTF16("Sarah Revere"), + base::ASCIIToUTF16("(617) 523-2338"), + base::ASCIIToUTF16("sarah.revere@aol.com")}), + ConstructLabelLine({base::ASCIIToUTF16("Jackie L Kennedy"), + base::ASCIIToUTF16("(617) 514-1600")}), + ConstructLabelLine({base::ASCIIToUTF16("Paul Revere"), + base::ASCIIToUTF16("paul1775@gmail.com")}), + ConstructLabelLine({base::ASCIIToUTF16("Deborah Katabi"), + base::ASCIIToUTF16("(617) 324-0000"), + base::ASCIIToUTF16("deborah@mit.edu")}), + base::ASCIIToUTF16(""), base::string16())); +} + +TEST(AddressContactFormLabelFormatterTest, + GetLabelsForUSProfilesAndFocusedNonStreetAddress) { + AutofillProfile profile1 = + AutofillProfile(base::GenerateGUID(), test::kEmptyOrigin); + test::SetProfileInfo(&profile1, "Sarah", "", "Revere", "sarah.revere@aol.com", + "", "19 North Sq", "", "Boston", "MA", "02113", "US", + "16175232338"); + + AutofillProfile profile2 = + AutofillProfile(base::GenerateGUID(), test::kEmptyOrigin); + test::SetProfileInfo(&profile2, "Jackie", "L", "Kennedy", "", "", + "151 Irving Ave", "", "Hyannis", "MA", "02601", "US", + "6175141600"); + + AutofillProfile profile3 = + AutofillProfile(base::GenerateGUID(), test::kEmptyOrigin); + test::SetProfileInfo(&profile3, "Paul", "", "Revere", "paul1775@gmail.com", + "", "19 North Sq", "", "Boston", "MA", "02113", "US", + ""); + + AutofillProfile profile4 = + AutofillProfile(base::GenerateGUID(), test::kEmptyOrigin); + test::SetProfileInfo(&profile4, "Deborah", "", "Katabi", "deborah@mit.edu", + "", "", "", "", "", "", "US", "6173240000"); + + AutofillProfile profile5 = + AutofillProfile(base::GenerateGUID(), test::kEmptyOrigin); + test::SetProfileInfo(&profile5, "", "", "", "", "", "Old North Church", + "193 Salem St", "Boston", "MA", "02113", "US", ""); + + AutofillProfile profile6 = + AutofillProfile(base::GenerateGUID(), test::kEmptyOrigin); + test::SetProfileInfo(&profile6, "", "", "", "", "", "", "", "", "", "", "US", + ""); + + const std::vector<AutofillProfile*> profiles{&profile1, &profile2, &profile3, + &profile4, &profile5, &profile6}; + const std::unique_ptr<LabelFormatter> formatter = LabelFormatter::Create( + "en-US", ADDRESS_BILLING_CITY, GetFieldTypes(), profiles); + + EXPECT_THAT( + formatter->GetLabels(profiles), + ElementsAre( + ConstructLabelLine({base::ASCIIToUTF16("19 North Sq"), + base::ASCIIToUTF16("(617) 523-2338"), + base::ASCIIToUTF16("sarah.revere@aol.com")}), + ConstructLabelLine({base::ASCIIToUTF16("151 Irving Ave"), + base::ASCIIToUTF16("(617) 514-1600")}), + ConstructLabelLine({base::ASCIIToUTF16("19 North Sq"), + base::ASCIIToUTF16("paul1775@gmail.com")}), + ConstructLabelLine({base::ASCIIToUTF16("(617) 324-0000"), + base::ASCIIToUTF16("deborah@mit.edu")}), + base::ASCIIToUTF16("Old North Church, 193 Salem St"), + base::string16())); +} + +TEST(AddressContactFormLabelFormatterTest, + GetLabelsForUSProfilesAndFocusedEmail) { + AutofillProfile profile1 = + AutofillProfile(base::GenerateGUID(), test::kEmptyOrigin); + test::SetProfileInfo(&profile1, "Sarah", "", "Revere", "sarah.revere@aol.com", + "", "19 North Sq", "", "Boston", "MA", "02113", "US", + "16175232338"); + + AutofillProfile profile2 = + AutofillProfile(base::GenerateGUID(), test::kEmptyOrigin); + test::SetProfileInfo(&profile2, "Jackie", "L", "Kennedy", "", "", + "151 Irving Ave", "", "Hyannis", "MA", "02601", "US", + "6175141600"); + + AutofillProfile profile3 = + AutofillProfile(base::GenerateGUID(), test::kEmptyOrigin); + test::SetProfileInfo(&profile3, "Paul", "", "Revere", "paul1775@gmail.com", + "", "19 North Sq", "", "Boston", "MA", "02113", "US", + ""); + + AutofillProfile profile4 = + AutofillProfile(base::GenerateGUID(), test::kEmptyOrigin); + test::SetProfileInfo(&profile4, "Deborah", "", "Katabi", "deborah@mit.edu", + "", "", "", "", "", "", "US", "6173240000"); + + AutofillProfile profile5 = + AutofillProfile(base::GenerateGUID(), test::kEmptyOrigin); + test::SetProfileInfo(&profile5, "", "", "", "", "", "Old North Church", + "193 Salem St", "Boston", "MA", "02113", "US", ""); + + AutofillProfile profile6 = + AutofillProfile(base::GenerateGUID(), test::kEmptyOrigin); + test::SetProfileInfo(&profile6, "", "", "", "", "", "", "", "", "", "", "US", + ""); + + const std::vector<AutofillProfile*> profiles{&profile1, &profile2, &profile3, + &profile4, &profile5, &profile6}; + const std::unique_ptr<LabelFormatter> formatter = + LabelFormatter::Create("en-US", EMAIL_ADDRESS, GetFieldTypes(), profiles); + + EXPECT_THAT( + formatter->GetLabels(profiles), + ElementsAre(ConstructLabelLine({base::ASCIIToUTF16("Sarah Revere"), + base::ASCIIToUTF16("19 North Sq"), + base::ASCIIToUTF16("(617) 523-2338")}), + ConstructLabelLine({base::ASCIIToUTF16("Jackie L Kennedy"), + base::ASCIIToUTF16("151 Irving Ave"), + base::ASCIIToUTF16("(617) 514-1600")}), + ConstructLabelLine({base::ASCIIToUTF16("Paul Revere"), + base::ASCIIToUTF16("19 North Sq")}), + ConstructLabelLine({base::ASCIIToUTF16("Deborah Katabi"), + base::ASCIIToUTF16("(617) 324-0000")}), + base::ASCIIToUTF16("Old North Church, 193 Salem St"), + base::string16())); +} + +TEST(AddressContactFormLabelFormatterTest, + GetLabelsForUSProfilesAndFocusedPhone) { + AutofillProfile profile1 = + AutofillProfile(base::GenerateGUID(), test::kEmptyOrigin); + test::SetProfileInfo(&profile1, "Sarah", "", "Revere", "sarah.revere@aol.com", + "", "19 North Sq", "", "Boston", "MA", "02113", "US", + "16175232338"); + + AutofillProfile profile2 = + AutofillProfile(base::GenerateGUID(), test::kEmptyOrigin); + test::SetProfileInfo(&profile2, "Jackie", "L", "Kennedy", "", "", + "151 Irving Ave", "", "Hyannis", "MA", "02601", "US", + "6175141600"); + + AutofillProfile profile3 = + AutofillProfile(base::GenerateGUID(), test::kEmptyOrigin); + test::SetProfileInfo(&profile3, "Paul", "", "Revere", "paul1775@gmail.com", + "", "19 North Sq", "", "Boston", "MA", "02113", "US", + ""); + + AutofillProfile profile4 = + AutofillProfile(base::GenerateGUID(), test::kEmptyOrigin); + test::SetProfileInfo(&profile4, "Deborah", "", "Katabi", "deborah@mit.edu", + "", "", "", "", "", "", "US", "6173240000"); + + AutofillProfile profile5 = + AutofillProfile(base::GenerateGUID(), test::kEmptyOrigin); + test::SetProfileInfo(&profile5, "", "", "", "", "", "Old North Church", + "193 Salem St", "Boston", "MA", "02113", "US", ""); + + AutofillProfile profile6 = + AutofillProfile(base::GenerateGUID(), test::kEmptyOrigin); + test::SetProfileInfo(&profile6, "", "", "", "", "", "", "", "", "", "", "US", + ""); + + const std::vector<AutofillProfile*> profiles{&profile1, &profile2, &profile3, + &profile4, &profile5, &profile6}; + const std::unique_ptr<LabelFormatter> formatter = LabelFormatter::Create( + "en-US", PHONE_BILLING_WHOLE_NUMBER, GetFieldTypes(), profiles); + + EXPECT_THAT( + formatter->GetLabels(profiles), + ElementsAre( + ConstructLabelLine({base::ASCIIToUTF16("Sarah Revere"), + base::ASCIIToUTF16("19 North Sq"), + base::ASCIIToUTF16("sarah.revere@aol.com")}), + ConstructLabelLine({base::ASCIIToUTF16("Jackie L Kennedy"), + base::ASCIIToUTF16("151 Irving Ave")}), + ConstructLabelLine({base::ASCIIToUTF16("Paul Revere"), + base::ASCIIToUTF16("19 North Sq"), + base::ASCIIToUTF16("paul1775@gmail.com")}), + ConstructLabelLine({base::ASCIIToUTF16("Deborah Katabi"), + base::ASCIIToUTF16("deborah@mit.edu")}), + base::ASCIIToUTF16("Old North Church, 193 Salem St"), + base::string16())); +} + +TEST(AddressContactFormLabelFormatterTest, + GetLabelsForBRProfilesAndFocusedName) { + AutofillProfile profile1 = + AutofillProfile(base::GenerateGUID(), test::kEmptyOrigin); + test::SetProfileInfo(&profile1, "Tarsila", "do", "Amaral", "tarsila@aol.com", + "", "Av. Pedro Álvares Cabral, 1301", "", "Vila Mariana", + "São Paulo", " SP ", " 04094-050 ", "BR", + "+55 11 2648-0254"); + + AutofillProfile profile2 = + AutofillProfile(base::GenerateGUID(), test::kEmptyOrigin); + test::SetProfileInfo(&profile2, "Artur", "", "Avila", "aavila@uol.com.br", "", + "Estr. Dona Castorina, 110", "", "Jardim Botânico", + "Rio de Janeiro", "RJ", "22460-320", "BR", + "21987650000"); + + const std::vector<AutofillProfile*> profiles{&profile1, &profile2}; + const std::unique_ptr<LabelFormatter> formatter = LabelFormatter::Create( + "pt-BR", NAME_BILLING_FULL, GetFieldTypes(), profiles); + + EXPECT_THAT( + formatter->GetLabels(profiles), + ElementsAre( + ConstructLabelLine( + {base::UTF8ToUTF16("Av. Pedro Álvares Cabral, 1301"), + base::ASCIIToUTF16("(11) 2648-0254"), + base::ASCIIToUTF16("tarsila@aol.com")}), + ConstructLabelLine({base::UTF8ToUTF16("Estr. Dona Castorina, 110"), + base::ASCIIToUTF16("(21) 98765-0000"), + base::ASCIIToUTF16("aavila@uol.com.br")}))); +} + +TEST(AddressContactFormLabelFormatterTest, + GetLabelsForBRProfilesAndFocusedStreetAddress) { + AutofillProfile profile1 = + AutofillProfile(base::GenerateGUID(), test::kEmptyOrigin); + test::SetProfileInfo(&profile1, "Tarsila", "do", "Amaral", "tarsila@aol.com", + "", "Av. Pedro Álvares Cabral, 1301", "", "Vila Mariana", + "São Paulo", " SP ", " 04094-050 ", "BR", + "+55 11 2648-0254"); + + AutofillProfile profile2 = + AutofillProfile(base::GenerateGUID(), test::kEmptyOrigin); + test::SetProfileInfo(&profile2, "Artur", "", "Avila", "aavila@uol.com.br", "", + "Estr. Dona Castorina, 110", "", "Jardim Botânico", + "Rio de Janeiro", "RJ", "22460-320", "BR", + "21987650000"); + + const std::vector<AutofillProfile*> profiles{&profile1, &profile2}; + const std::unique_ptr<LabelFormatter> formatter = LabelFormatter::Create( + "pt-BR", ADDRESS_BILLING_LINE1, GetFieldTypes(), profiles); + + EXPECT_THAT( + formatter->GetLabels(profiles), + ElementsAre( + ConstructLabelLine({base::ASCIIToUTF16("Tarsila do Amaral"), + base::ASCIIToUTF16("(11) 2648-0254"), + base::ASCIIToUTF16("tarsila@aol.com")}), + ConstructLabelLine({base::ASCIIToUTF16("Artur Avila"), + base::ASCIIToUTF16("(21) 98765-0000"), + base::ASCIIToUTF16("aavila@uol.com.br")}))); +} + +TEST(AddressContactFormLabelFormatterTest, + GetLabelsForBRProfilesAndFocusedNonStreetAddress) { + AutofillProfile profile1 = + AutofillProfile(base::GenerateGUID(), test::kEmptyOrigin); + test::SetProfileInfo(&profile1, "Tarsila", "do", "Amaral", "tarsila@aol.com", + "", "Av. Pedro Álvares Cabral, 1301", "", "Vila Mariana", + "São Paulo", " SP ", " 04094-050 ", "BR", + "+55 11 2648-0254"); + + AutofillProfile profile2 = + AutofillProfile(base::GenerateGUID(), test::kEmptyOrigin); + test::SetProfileInfo(&profile2, "Artur", "", "Avila", "aavila@uol.com.br", "", + "Estr. Dona Castorina, 110", "", "Jardim Botânico", + "Rio de Janeiro", "RJ", "22460-320", "BR", + "21987650000"); + + const std::vector<AutofillProfile*> profiles{&profile1, &profile2}; + const std::unique_ptr<LabelFormatter> formatter = LabelFormatter::Create( + "pt-BR", ADDRESS_BILLING_ZIP, GetFieldTypes(), profiles); + + EXPECT_THAT( + formatter->GetLabels(profiles), + ElementsAre( + ConstructLabelLine( + {base::UTF8ToUTF16("Av. Pedro Álvares Cabral, 1301"), + base::ASCIIToUTF16("(11) 2648-0254"), + base::ASCIIToUTF16("tarsila@aol.com")}), + ConstructLabelLine({base::ASCIIToUTF16("Estr. Dona Castorina, 110"), + base::ASCIIToUTF16("(21) 98765-0000"), + base::ASCIIToUTF16("aavila@uol.com.br")}))); +} + +TEST(AddressContactFormLabelFormatterTest, + GetLabelsForBRProfilesAndFocusedEmail) { + AutofillProfile profile1 = + AutofillProfile(base::GenerateGUID(), test::kEmptyOrigin); + test::SetProfileInfo(&profile1, "Tarsila", "do", "Amaral", "tarsila@aol.com", + "", "Av. Pedro Álvares Cabral, 1301", "", "Vila Mariana", + "São Paulo", " SP ", " 04094-050 ", "BR", + "+55 11 2648-0254"); + + AutofillProfile profile2 = + AutofillProfile(base::GenerateGUID(), test::kEmptyOrigin); + test::SetProfileInfo(&profile2, "Artur", "", "Avila", "aavila@uol.com.br", "", + "Estr. Dona Castorina, 110", "", "Jardim Botânico", + "Rio de Janeiro", "RJ", "22460-320", "BR", + "21987650000"); + + const std::vector<AutofillProfile*> profiles{&profile1, &profile2}; + const std::unique_ptr<LabelFormatter> formatter = + LabelFormatter::Create("pt-BR", EMAIL_ADDRESS, GetFieldTypes(), profiles); + + EXPECT_THAT( + formatter->GetLabels(profiles), + ElementsAre( + ConstructLabelLine( + {base::ASCIIToUTF16("Tarsila do Amaral"), + base::UTF8ToUTF16("Av. Pedro Álvares Cabral, 1301"), + base::ASCIIToUTF16("(11) 2648-0254")}), + ConstructLabelLine({base::ASCIIToUTF16("Artur Avila"), + base::UTF8ToUTF16("Estr. Dona Castorina, 110"), + base::ASCIIToUTF16("(21) 98765-0000")}))); +} + +TEST(AddressContactFormLabelFormatterTest, + GetLabelsForBRProfilesAndFocusedPhone) { + AutofillProfile profile1 = + AutofillProfile(base::GenerateGUID(), test::kEmptyOrigin); + test::SetProfileInfo(&profile1, "Tarsila", "do", "Amaral", "tarsila@aol.com", + "", "Av. Pedro Álvares Cabral, 1301", "", "Vila Mariana", + "São Paulo", " SP ", " 04094-050 ", "BR", + "+55 11 2648-0254"); + + AutofillProfile profile2 = + AutofillProfile(base::GenerateGUID(), test::kEmptyOrigin); + test::SetProfileInfo(&profile2, "Artur", "", "Avila", "aavila@uol.com.br", "", + "Estr. Dona Castorina, 110", "", "Jardim Botânico", + "Rio de Janeiro", "RJ", "22460-320", "BR", + "21987650000"); + + const std::vector<AutofillProfile*> profiles{&profile1, &profile2}; + const std::unique_ptr<LabelFormatter> formatter = LabelFormatter::Create( + "pt-BR", PHONE_BILLING_WHOLE_NUMBER, GetFieldTypes(), profiles); + + EXPECT_THAT( + formatter->GetLabels(profiles), + ElementsAre( + ConstructLabelLine( + {base::ASCIIToUTF16("Tarsila do Amaral"), + base::UTF8ToUTF16("Av. Pedro Álvares Cabral, 1301"), + base::ASCIIToUTF16("tarsila@aol.com")}), + ConstructLabelLine({base::ASCIIToUTF16("Artur Avila"), + base::UTF8ToUTF16("Estr. Dona Castorina, 110"), + base::ASCIIToUTF16("aavila@uol.com.br")}))); +} + +TEST(AddressContactFormLabelFormatterTest, + GetLabelsForFormWithPartialAddressFields) { + AutofillProfile profile = + AutofillProfile(base::GenerateGUID(), test::kEmptyOrigin); + test::SetProfileInfo(&profile, "Sarah", "", "Revere", "sarah.revere@aol.com", + "", "19 North Sq", "", "Boston", "MA", "02113", "US", + "16175232338"); + + const std::vector<AutofillProfile*> profiles{&profile}; + const std::unique_ptr<LabelFormatter> formatter = + LabelFormatter::Create("en-US", EMAIL_ADDRESS, + {NAME_BILLING_FULL, EMAIL_ADDRESS, + ADDRESS_BILLING_ZIP, PHONE_BILLING_WHOLE_NUMBER}, + profiles); + + // Checks that only address fields in the form are shown in the label. + EXPECT_THAT( + formatter->GetLabels(profiles), + ElementsAre(ConstructLabelLine( + {base::ASCIIToUTF16("Sarah Revere"), base::ASCIIToUTF16("02113")}))); +} + +} // namespace +} // namespace autofill diff --git a/chromium/components/autofill/core/browser/address_email_form_label_formatter.cc b/chromium/components/autofill/core/browser/address_email_form_label_formatter.cc new file mode 100644 index 00000000000..675bf30ade1 --- /dev/null +++ b/chromium/components/autofill/core/browser/address_email_form_label_formatter.cc @@ -0,0 +1,61 @@ +// Copyright 2019 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "components/autofill/core/browser/address_email_form_label_formatter.h" + +#include "components/autofill/core/browser/label_formatter_utils.h" + +namespace autofill { + +AddressEmailFormLabelFormatter::AddressEmailFormLabelFormatter( + const std::string& app_locale, + ServerFieldType focused_field_type, + uint32_t groups, + const std::vector<ServerFieldType>& field_types) + : LabelFormatter(app_locale, focused_field_type, groups, field_types), + form_has_street_address_(HasStreetAddress(field_types_for_labels())) {} + +AddressEmailFormLabelFormatter::~AddressEmailFormLabelFormatter() {} + +base::string16 AddressEmailFormLabelFormatter::GetLabelForProfile( + const AutofillProfile& profile, + FieldTypeGroup focused_group) const { + return focused_group == ADDRESS_HOME && + !IsStreetAddressPart(focused_field_type()) + ? GetLabelForProfileOnFocusedNonStreetAddress( + form_has_street_address_, profile, app_locale(), + field_types_for_labels(), + GetLabelEmail(profile, app_locale())) + : GetLabelForProfileOnFocusedNameEmailOrStreetAddress( + profile, focused_group); +} + +// Note that the order--name, address, and email--in which parts of the label +// are added ensures that the label is formatted correctly for |focused_group|, +// |focused_field_type_| and for this kind of formatter. +base::string16 AddressEmailFormLabelFormatter:: + GetLabelForProfileOnFocusedNameEmailOrStreetAddress( + const AutofillProfile& profile, + FieldTypeGroup focused_group) const { + std::vector<base::string16> label_parts; + + if (focused_group != NAME) { + AddLabelPartIfNotEmpty(GetLabelName(profile, app_locale()), &label_parts); + } + + if (focused_group != ADDRESS_HOME) { + AddLabelPartIfNotEmpty( + GetLabelAddress(form_has_street_address_, profile, app_locale(), + field_types_for_labels()), + &label_parts); + } + + if (focused_group != EMAIL) { + AddLabelPartIfNotEmpty(GetLabelEmail(profile, app_locale()), &label_parts); + } + + return ConstructLabelLine(label_parts); +} + +} // namespace autofill diff --git a/chromium/components/autofill/core/browser/address_email_form_label_formatter.h b/chromium/components/autofill/core/browser/address_email_form_label_formatter.h new file mode 100644 index 00000000000..5c44dba5cdf --- /dev/null +++ b/chromium/components/autofill/core/browser/address_email_form_label_formatter.h @@ -0,0 +1,52 @@ +// Copyright 2019 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef COMPONENTS_AUTOFILL_CORE_BROWSER_ADDRESS_EMAIL_FORM_LABEL_FORMATTER_H_ +#define COMPONENTS_AUTOFILL_CORE_BROWSER_ADDRESS_EMAIL_FORM_LABEL_FORMATTER_H_ + +#include <string> +#include <vector> + +#include "base/strings/string16.h" +#include "components/autofill/core/browser/autofill_profile.h" +#include "components/autofill/core/browser/field_types.h" +#include "components/autofill/core/browser/label_formatter.h" + +namespace autofill { + +// A LabelFormatter that creates Suggestions' disambiguating labels for forms +// with name, address, and email fields and without phone fields. +class AddressEmailFormLabelFormatter : public LabelFormatter { + public: + AddressEmailFormLabelFormatter( + const std::string& app_locale, + ServerFieldType focused_field_type, + uint32_t groups, + const std::vector<ServerFieldType>& field_types); + + ~AddressEmailFormLabelFormatter() override; + + base::string16 GetLabelForProfile( + const AutofillProfile& profile, + FieldTypeGroup focused_group) const override; + + private: + // Returns a label to show the user when |focused_field_type_| is a type + // other than a non-street-address field type. For example, + // |focused_field_type_| could be last name, home street address, or email + // address. + base::string16 GetLabelForProfileOnFocusedNameEmailOrStreetAddress( + const AutofillProfile& profile, + FieldTypeGroup focused_group) const; + + // True if this formatter's associated form has a street address field. A + // form may have an address-related field, e.g. zip code, without having a + // street address field. If a form does not include a street address field, + // street addresses should not appear in labels. + bool form_has_street_address_; +}; + +} // namespace autofill + +#endif // COMPONENTS_AUTOFILL_CORE_BROWSER_ADDRESS_EMAIL_FORM_LABEL_FORMATTER_H_ diff --git a/chromium/components/autofill/core/browser/address_email_form_label_formatter_unittest.cc b/chromium/components/autofill/core/browser/address_email_form_label_formatter_unittest.cc new file mode 100644 index 00000000000..34e2a2bab92 --- /dev/null +++ b/chromium/components/autofill/core/browser/address_email_form_label_formatter_unittest.cc @@ -0,0 +1,332 @@ +// Copyright 2019 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "components/autofill/core/browser/address_email_form_label_formatter.h" + +#include <memory> +#include <string> +#include <vector> + +#include "base/guid.h" +#include "base/strings/string16.h" +#include "base/strings/utf_string_conversions.h" +#include "components/autofill/core/browser/autofill_profile.h" +#include "components/autofill/core/browser/autofill_test_utils.h" +#include "components/autofill/core/browser/field_types.h" +#include "components/autofill/core/browser/label_formatter_utils.h" +#include "testing/gmock/include/gmock/gmock.h" +#include "testing/gtest/include/gtest/gtest.h" + +using testing::ElementsAre; + +namespace autofill { +namespace { + +std::vector<ServerFieldType> GetFieldTypes() { + return {NAME_FULL, + EMAIL_ADDRESS, + ADDRESS_BILLING_LINE1, + ADDRESS_BILLING_LINE2, + ADDRESS_BILLING_CITY, + ADDRESS_BILLING_STATE, + ADDRESS_BILLING_DEPENDENT_LOCALITY, + ADDRESS_BILLING_ZIP, + ADDRESS_BILLING_COUNTRY}; +} + +TEST(AddressEmailFormLabelFormatterTest, GetLabelsWithMissingProfiles) { + const std::vector<AutofillProfile*> profiles{}; + const std::unique_ptr<LabelFormatter> formatter = LabelFormatter::Create( + "en-US", NAME_BILLING_FULL, GetFieldTypes(), profiles); + EXPECT_TRUE(formatter->GetLabels(profiles).empty()); +} + +TEST(AddressEmailFormLabelFormatterTest, GetLabelsForUSProfilesAndFocusedName) { + AutofillProfile profile1 = + AutofillProfile(base::GenerateGUID(), test::kEmptyOrigin); + test::SetProfileInfo(&profile1, "John", "F", "Kennedy", "jfk@gmail.com", "", + "333 Washington St", "", "Brookline", "MA", "02445", + "US", "16177302000"); + + AutofillProfile profile2 = + AutofillProfile(base::GenerateGUID(), test::kEmptyOrigin); + test::SetProfileInfo(&profile2, "Jackie", "", "Kennedy", "", "", + "151 Irving Ave", "", "Hyannis", "MA", "02601", "US", + ""); + + AutofillProfile profile3 = + AutofillProfile(base::GenerateGUID(), test::kEmptyOrigin); + test::SetProfileInfo(&profile3, "Paul", "", "Revere", "paul1775@gmail.com", + "", "", "", "", "", "", "US", ""); + + AutofillProfile profile4 = + AutofillProfile(base::GenerateGUID(), test::kEmptyOrigin); + test::SetProfileInfo(&profile4, "John", "", "Adams", "", "", "", "", "Quincy", + "MA", "02169", "US", ""); + + const std::vector<AutofillProfile*> profiles{&profile1, &profile2, &profile3, + &profile4}; + const std::unique_ptr<LabelFormatter> formatter = LabelFormatter::Create( + "en-US", NAME_BILLING_FULL, GetFieldTypes(), profiles); + + EXPECT_THAT( + formatter->GetLabels(profiles), + ElementsAre(ConstructLabelLine({base::ASCIIToUTF16("333 Washington St"), + base::ASCIIToUTF16("jfk@gmail.com")}), + base::ASCIIToUTF16("151 Irving Ave"), + base::ASCIIToUTF16("paul1775@gmail.com"), base::string16())); +} + +TEST(AddressEmailFormLabelFormatterTest, + GetLabelsForUSProfilesAndFocusedStreetAddress) { + AutofillProfile profile1 = + AutofillProfile(base::GenerateGUID(), test::kEmptyOrigin); + test::SetProfileInfo(&profile1, "John", "F", "Kennedy", "jfk@gmail.com", "", + "333 Washington St", "", "Brookline", "MA", "02445", + "US", "16177302000"); + + AutofillProfile profile2 = + AutofillProfile(base::GenerateGUID(), test::kEmptyOrigin); + test::SetProfileInfo(&profile2, "Jackie", "", "Kennedy", "", "", + "151 Irving Ave", "", "Hyannis", "MA", "02601", "US", + ""); + + AutofillProfile profile3 = + AutofillProfile(base::GenerateGUID(), test::kEmptyOrigin); + test::SetProfileInfo(&profile3, "", "", "", "paul1775@gmail.com", "", "", "", + "", "", "", "US", ""); + + AutofillProfile profile4 = + AutofillProfile(base::GenerateGUID(), test::kEmptyOrigin); + test::SetProfileInfo(&profile4, "", "", "", "", "", "141 Franklin St", "", + "Quincy", "MA", "02169", "US", ""); + + const std::vector<AutofillProfile*> profiles{&profile1, &profile2, &profile3, + &profile4}; + const std::unique_ptr<LabelFormatter> formatter = LabelFormatter::Create( + "en-US", ADDRESS_BILLING_LINE1, GetFieldTypes(), profiles); + + EXPECT_THAT( + formatter->GetLabels(profiles), + ElementsAre(ConstructLabelLine({base::ASCIIToUTF16("John F Kennedy"), + base::ASCIIToUTF16("jfk@gmail.com")}), + base::ASCIIToUTF16("Jackie Kennedy"), + base::ASCIIToUTF16("paul1775@gmail.com"), base::string16())); +} + +TEST(AddressEmailFormLabelFormatterTest, + GetLabelsForUSProfilesAndFocusedNonStreetAddress) { + AutofillProfile profile1 = + AutofillProfile(base::GenerateGUID(), test::kEmptyOrigin); + test::SetProfileInfo(&profile1, "John", "F", "Kennedy", "jfk@gmail.com", "", + "333 Washington St", "", "Brookline", "MA", "02445", + "US", "16177302000"); + + AutofillProfile profile2 = + AutofillProfile(base::GenerateGUID(), test::kEmptyOrigin); + test::SetProfileInfo(&profile2, "Jackie", "", "Kennedy", "", "", + "151 Irving Ave", "", "Hyannis", "MA", "02601", "US", + ""); + + AutofillProfile profile3 = + AutofillProfile(base::GenerateGUID(), test::kEmptyOrigin); + test::SetProfileInfo(&profile3, "", "", "", "paul1775@gmail.com", "", "", "", + "", "", "", "US", ""); + + AutofillProfile profile4 = + AutofillProfile(base::GenerateGUID(), test::kEmptyOrigin); + test::SetProfileInfo(&profile4, "", "", "", "", "", "", "", "Quincy", "MA", + "02169", "US", ""); + + const std::vector<AutofillProfile*> profiles{&profile1, &profile2, &profile3, + &profile4}; + const std::unique_ptr<LabelFormatter> formatter = LabelFormatter::Create( + "en-US", ADDRESS_BILLING_ZIP, GetFieldTypes(), profiles); + + EXPECT_THAT( + formatter->GetLabels(profiles), + ElementsAre(ConstructLabelLine({base::ASCIIToUTF16("333 Washington St"), + base::ASCIIToUTF16("jfk@gmail.com")}), + base::ASCIIToUTF16("151 Irving Ave"), + base::ASCIIToUTF16("paul1775@gmail.com"), base::string16())); +} + +TEST(AddressEmailFormLabelFormatterTest, + GetLabelsForUSProfilesAndFocusedEmail) { + AutofillProfile profile1 = + AutofillProfile(base::GenerateGUID(), test::kEmptyOrigin); + test::SetProfileInfo(&profile1, "John", "F", "Kennedy", "jfk@gmail.com", "", + "333 Washington St", "", "Brookline", "MA", "02445", + "US", "16177302000"); + + AutofillProfile profile2 = + AutofillProfile(base::GenerateGUID(), test::kEmptyOrigin); + test::SetProfileInfo(&profile2, "Jackie", "", "Kennedy", "jackie@outlook.com", + "", "", "", "Hyannis", "MA", "02601", "US", ""); + + AutofillProfile profile3 = + AutofillProfile(base::GenerateGUID(), test::kEmptyOrigin); + test::SetProfileInfo(&profile3, "", "", "", "paul1775@gmail.com", "", "", "", + "", "", "", "US", ""); + + AutofillProfile profile4 = + AutofillProfile(base::GenerateGUID(), test::kEmptyOrigin); + test::SetProfileInfo(&profile4, "", "", "", "", "", "141 Franklin St", "", + "Quincy", "MA", "02169", "US", ""); + + const std::vector<AutofillProfile*> profiles{&profile1, &profile2, &profile3, + &profile4}; + const std::unique_ptr<LabelFormatter> formatter = + LabelFormatter::Create("en-US", EMAIL_ADDRESS, GetFieldTypes(), profiles); + + EXPECT_THAT( + formatter->GetLabels(profiles), + ElementsAre(ConstructLabelLine({base::ASCIIToUTF16("John F Kennedy"), + base::ASCIIToUTF16("333 Washington St")}), + base::ASCIIToUTF16("Jackie Kennedy"), base::string16(), + base::ASCIIToUTF16("141 Franklin St"))); +} + +TEST(AddressEmailFormLabelFormatterTest, GetLabelsForBRProfilesAndFocusedName) { + AutofillProfile profile1 = + AutofillProfile(base::GenerateGUID(), test::kEmptyOrigin); + test::SetProfileInfo(&profile1, "Tarsila", "do", "Amaral", "tarsila@aol.com", + "", "Av. Pedro Álvares Cabral, 1301", "", "Vila Mariana", + "São Paulo", "SP", "04094-050", "BR", + "+55 11 2648-0254"); + + AutofillProfile profile2 = + AutofillProfile(base::GenerateGUID(), test::kEmptyOrigin); + test::SetProfileInfo(&profile2, "Artur", "", "Avila", "aavila@uol.com.br", "", + "Estr. Dona Castorina, 110", "", "Jardim Botânico", + "Rio de Janeiro", "RJ", "22460-320", "BR", + "21987650000"); + + const std::vector<AutofillProfile*> profiles{&profile1, &profile2}; + const std::unique_ptr<LabelFormatter> formatter = LabelFormatter::Create( + "pt-BR", NAME_BILLING_FULL, GetFieldTypes(), profiles); + + EXPECT_THAT( + formatter->GetLabels(profiles), + ElementsAre( + ConstructLabelLine( + {base::UTF8ToUTF16("Av. Pedro Álvares Cabral, 1301"), + base::ASCIIToUTF16("tarsila@aol.com")}), + ConstructLabelLine({base::ASCIIToUTF16("Estr. Dona Castorina, 110"), + base::ASCIIToUTF16("aavila@uol.com.br")}))); +} + +TEST(AddressEmailFormLabelFormatterTest, + GetLabelsForBRProfilesAndFocusedStreetAddress) { + AutofillProfile profile1 = + AutofillProfile(base::GenerateGUID(), test::kEmptyOrigin); + test::SetProfileInfo(&profile1, "Tarsila", "do", "Amaral", "tarsila@aol.com", + "", "Av. Pedro Álvares Cabral, 1301", "", "Vila Mariana", + "São Paulo", "SP", "04094-050", "BR", + "+55 11 2648-0254"); + + AutofillProfile profile2 = + AutofillProfile(base::GenerateGUID(), test::kEmptyOrigin); + test::SetProfileInfo(&profile2, "Artur", "", "Avila", "aavila@uol.com.br", "", + "Estr. Dona Castorina, 110", "", "Jardim Botânico", + "Rio de Janeiro", "RJ", "22460-320", "BR", + "21987650000"); + + const std::vector<AutofillProfile*> profiles{&profile1, &profile2}; + const std::unique_ptr<LabelFormatter> formatter = LabelFormatter::Create( + "pt-BR", ADDRESS_BILLING_LINE1, GetFieldTypes(), profiles); + + EXPECT_THAT( + formatter->GetLabels(profiles), + ElementsAre( + ConstructLabelLine({base::ASCIIToUTF16("Tarsila do Amaral"), + base::ASCIIToUTF16("tarsila@aol.com")}), + ConstructLabelLine({base::ASCIIToUTF16("Artur Avila"), + base::ASCIIToUTF16("aavila@uol.com.br")}))); +} + +TEST(AddressEmailFormLabelFormatterTest, + GetLabelsForBRProfilesAndFocusedNonStreetAddress) { + AutofillProfile profile1 = + AutofillProfile(base::GenerateGUID(), test::kEmptyOrigin); + test::SetProfileInfo(&profile1, "Tarsila", "do", "Amaral", "tarsila@aol.com", + "", "Av. Pedro Álvares Cabral, 1301", "", "Vila Mariana", + "São Paulo", "SP", "04094-050", "BR", + "+55 11 2648-0254"); + + AutofillProfile profile2 = + AutofillProfile(base::GenerateGUID(), test::kEmptyOrigin); + test::SetProfileInfo(&profile2, "Artur", "", "Avila", "aavila@uol.com.br", "", + "Estr. Dona Castorina, 110", "", "Jardim Botânico", + "Rio de Janeiro", "RJ", "22460-320", "BR", + "21987650000"); + + const std::vector<AutofillProfile*> profiles{&profile1, &profile2}; + const std::unique_ptr<LabelFormatter> formatter = LabelFormatter::Create( + "pt-BR", ADDRESS_BILLING_DEPENDENT_LOCALITY, GetFieldTypes(), profiles); + + EXPECT_THAT( + formatter->GetLabels(profiles), + ElementsAre( + ConstructLabelLine( + {base::UTF8ToUTF16("Av. Pedro Álvares Cabral, 1301"), + base::ASCIIToUTF16("tarsila@aol.com")}), + ConstructLabelLine({base::ASCIIToUTF16("Estr. Dona Castorina, 110"), + base::ASCIIToUTF16("aavila@uol.com.br")}))); +} + +TEST(AddressEmailFormLabelFormatterTest, + GetLabelsForBRProfilesAndFocusedEmail) { + AutofillProfile profile1 = + AutofillProfile(base::GenerateGUID(), test::kEmptyOrigin); + test::SetProfileInfo(&profile1, "Tarsila", "do", "Amaral", "tarsila@aol.com", + "", "Av. Pedro Álvares Cabral, 1301", "", "Vila Mariana", + "São Paulo", "SP", "04094-050", "BR", + "+55 11 2648-0254"); + + AutofillProfile profile2 = + AutofillProfile(base::GenerateGUID(), test::kEmptyOrigin); + test::SetProfileInfo(&profile2, "Artur", "", "Avila", "aavila@uol.com.br", "", + "Estr. Dona Castorina, 110", "", "Jardim Botânico", + "Rio de Janeiro", "RJ", "22460-320", "BR", + "21987650000"); + + const std::vector<AutofillProfile*> profiles{&profile1, &profile2}; + const std::unique_ptr<LabelFormatter> formatter = + LabelFormatter::Create("pt-BR", EMAIL_ADDRESS, GetFieldTypes(), profiles); + + EXPECT_THAT( + formatter->GetLabels(profiles), + ElementsAre(ConstructLabelLine( + {base::ASCIIToUTF16("Tarsila do Amaral"), + base::UTF8ToUTF16("Av. Pedro Álvares Cabral, 1301")}), + ConstructLabelLine( + {base::ASCIIToUTF16("Artur Avila"), + base::ASCIIToUTF16("Estr. Dona Castorina, 110")}))); +} + +TEST(AddressEmailFormLabelFormatterTest, + GetLabelsForFormWithAddressFieldsMinusStreetAddress) { + AutofillProfile profile = + AutofillProfile(base::GenerateGUID(), test::kEmptyOrigin); + test::SetProfileInfo(&profile, "John", "F", "Kennedy", "jfk@gmail.com", "", + "333 Washington St", "", "Brookline", "MA", "02445", + "US", "16177302000"); + + const std::vector<AutofillProfile*> profiles{&profile}; + const std::unique_ptr<LabelFormatter> formatter = + LabelFormatter::Create("en-US", EMAIL_ADDRESS, + {NAME_BILLING_FULL, EMAIL_ADDRESS, + ADDRESS_BILLING_CITY, ADDRESS_BILLING_STATE}, + profiles); + + // Checks that only address fields in the form are shown in the label. + EXPECT_THAT( + formatter->GetLabels(profiles), + ElementsAre(ConstructLabelLine({base::ASCIIToUTF16("John F Kennedy"), + base::ASCIIToUTF16("Brookline, MA")}))); +} + +} // namespace +} // namespace autofill diff --git a/chromium/components/autofill/core/browser/address_form_label_formatter.cc b/chromium/components/autofill/core/browser/address_form_label_formatter.cc index 604dd7882da..ec88eda9bf5 100644 --- a/chromium/components/autofill/core/browser/address_form_label_formatter.cc +++ b/chromium/components/autofill/core/browser/address_form_label_formatter.cc @@ -4,28 +4,35 @@ #include "components/autofill/core/browser/address_form_label_formatter.h" +#include "components/autofill/core/browser/label_formatter_utils.h" + namespace autofill { AddressFormLabelFormatter::AddressFormLabelFormatter( const std::string& app_locale, ServerFieldType focused_field_type, + uint32_t groups, const std::vector<ServerFieldType>& field_types) - : LabelFormatter(app_locale, focused_field_type, field_types) { - for (const ServerFieldType& type : field_types) { - if (type != focused_field_type && type != ADDRESS_HOME_COUNTRY && - type != ADDRESS_BILLING_COUNTRY) { - field_types_for_labels_.push_back(type); - } - } -} + : LabelFormatter(app_locale, focused_field_type, groups, field_types), + form_has_street_address_(HasStreetAddress(field_types_for_labels())) {} AddressFormLabelFormatter::~AddressFormLabelFormatter() {} -std::vector<base::string16> AddressFormLabelFormatter::GetLabels( - const std::vector<AutofillProfile*>& profiles) const { - // TODO(crbug.com/936168): Implement GetLabels(). - std::vector<base::string16> labels; - return labels; +base::string16 AddressFormLabelFormatter::GetLabelForProfile( + const AutofillProfile& profile, + FieldTypeGroup focused_group) const { + if (focused_group != ADDRESS_HOME) { + return GetLabelNationalAddress(profile, app_locale(), + field_types_for_labels()); + } else { + std::vector<base::string16> label_parts; + AddLabelPartIfNotEmpty(GetLabelName(profile, app_locale()), &label_parts); + AddLabelPartIfNotEmpty(GetLabelForFocusedAddress( + focused_field_type(), form_has_street_address_, + profile, app_locale(), field_types_for_labels()), + &label_parts); + return ConstructLabelLine(label_parts); + } } } // namespace autofill diff --git a/chromium/components/autofill/core/browser/address_form_label_formatter.h b/chromium/components/autofill/core/browser/address_form_label_formatter.h index 1f0c4850a3d..e4a97dcd759 100644 --- a/chromium/components/autofill/core/browser/address_form_label_formatter.h +++ b/chromium/components/autofill/core/browser/address_form_label_formatter.h @@ -21,17 +21,21 @@ class AddressFormLabelFormatter : public LabelFormatter { public: AddressFormLabelFormatter(const std::string& app_locale, ServerFieldType focused_field_type, + uint32_t groups, const std::vector<ServerFieldType>& field_types); ~AddressFormLabelFormatter() override; - std::vector<base::string16> GetLabels( - const std::vector<AutofillProfile*>& profiles) const override; + base::string16 GetLabelForProfile( + const AutofillProfile& profile, + FieldTypeGroup focused_group) const override; private: - // A collection of field types that can be used to make labels. This - // collection excludes the focused_field_type_ and address countries. - std::vector<ServerFieldType> field_types_for_labels_; + // True if this formatter's associated form has a street address field. A + // form may have an address-related field, e.g. zip code, without having a + // street address field. If a form does not include a street address field, + // street addresses should not appear in labels. + bool form_has_street_address_; }; } // namespace autofill diff --git a/chromium/components/autofill/core/browser/address_form_label_formatter_unittest.cc b/chromium/components/autofill/core/browser/address_form_label_formatter_unittest.cc new file mode 100644 index 00000000000..4f7a554bf19 --- /dev/null +++ b/chromium/components/autofill/core/browser/address_form_label_formatter_unittest.cc @@ -0,0 +1,191 @@ +// Copyright 2019 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "components/autofill/core/browser/address_form_label_formatter.h" + +#include <vector> + +#include "base/guid.h" +#include "base/strings/string16.h" +#include "base/strings/utf_string_conversions.h" +#include "components/autofill/core/browser/autofill_profile.h" +#include "components/autofill/core/browser/autofill_test_utils.h" +#include "components/autofill/core/browser/field_types.h" +#include "components/autofill/core/browser/label_formatter_utils.h" +#include "testing/gmock/include/gmock/gmock.h" +#include "testing/gtest/include/gtest/gtest.h" + +using testing::ElementsAre; + +namespace autofill { +namespace { + +std::vector<ServerFieldType> GetFieldTypes() { + return {NO_SERVER_DATA, NAME_FIRST, + NAME_LAST, ADDRESS_HOME_LINE1, + ADDRESS_HOME_LINE2, ADDRESS_HOME_DEPENDENT_LOCALITY, + ADDRESS_HOME_CITY, ADDRESS_HOME_STATE, + ADDRESS_HOME_ZIP, ADDRESS_HOME_COUNTRY}; +} + +TEST(AddressFormLabelFormatterTest, GetLabelsWithMissingProfiles) { + const std::vector<AutofillProfile*> profiles{}; + const std::unique_ptr<LabelFormatter> formatter = + LabelFormatter::Create("en-US", NAME_FIRST, GetFieldTypes(), profiles); + EXPECT_TRUE(formatter->GetLabels(profiles).empty()); +} + +TEST(AddressFormLabelFormatterTest, + GetLabelsForUSProfilesAndFocusedStreetAddress) { + AutofillProfile profile1 = + AutofillProfile(base::GenerateGUID(), test::kEmptyOrigin); + test::SetProfileInfo(&profile1, "John", "F", "Kennedy", "jfk@gmail.com", "", + "333 Washington St", "", "Brookline", "MA", "02445", + "US", "16177302000"); + + AutofillProfile profile2 = + AutofillProfile(base::GenerateGUID(), test::kEmptyOrigin); + test::SetProfileInfo(&profile2, "", "", "", "jackie@outlook.com", "", + "151 Irving Ave", "", "Hyannis", "MA", "", "US", + "5087717796"); + + AutofillProfile profile3 = + AutofillProfile(base::GenerateGUID(), test::kEmptyOrigin); + test::SetProfileInfo(&profile3, "Paul", "", "Revere", "paul1775@gmail.com", + "", "", "", "", "", "", "US", ""); + + AutofillProfile profile4 = + AutofillProfile(base::GenerateGUID(), test::kEmptyOrigin); + test::SetProfileInfo(&profile4, "", "", "", "", "", "", "", "", "", "", "US", + ""); + + const std::vector<AutofillProfile*> profiles{&profile1, &profile2, &profile3, + &profile4}; + const std::unique_ptr<LabelFormatter> formatter = LabelFormatter::Create( + "en-US", ADDRESS_HOME_LINE1, GetFieldTypes(), profiles); + + EXPECT_THAT(formatter->GetLabels(profiles), + ElementsAre(ConstructLabelLine( + {base::ASCIIToUTF16("John F Kennedy"), + base::ASCIIToUTF16("Brookline, MA 02445")}), + base::ASCIIToUTF16("Hyannis, MA"), + base::ASCIIToUTF16("Paul Revere"), base::string16())); +} + +TEST(AddressFormLabelFormatterTest, + GetLabelsForUSProfilesAndFocusedNonStreetAddress) { + AutofillProfile profile1 = + AutofillProfile(base::GenerateGUID(), test::kEmptyOrigin); + test::SetProfileInfo(&profile1, "John", "F", "Kennedy", "jfk@gmail.com", "", + "333 Washington St", "", "Brookline", "MA", "02445", + "US", "16177302000"); + + AutofillProfile profile2 = + AutofillProfile(base::GenerateGUID(), test::kEmptyOrigin); + test::SetProfileInfo(&profile2, "", "", "", "jackie@outlook.com", "", + "151 Irving Ave", "", "Hyannis", "MA", "", "US", + "5087717796"); + + AutofillProfile profile3 = + AutofillProfile(base::GenerateGUID(), test::kEmptyOrigin); + test::SetProfileInfo(&profile3, "Paul", "", "Revere", "paul1775@gmail.com", + "", "", "", "", "", "", "US", ""); + + AutofillProfile profile4 = + AutofillProfile(base::GenerateGUID(), test::kEmptyOrigin); + test::SetProfileInfo(&profile4, "", "", "", "", "", "", "", "", "", "", "US", + ""); + + const std::vector<AutofillProfile*> profiles{&profile1, &profile2, &profile3, + &profile4}; + const std::unique_ptr<LabelFormatter> formatter = LabelFormatter::Create( + "en-US", ADDRESS_HOME_CITY, GetFieldTypes(), profiles); + + EXPECT_THAT( + formatter->GetLabels(profiles), + ElementsAre(ConstructLabelLine({base::ASCIIToUTF16("John F Kennedy"), + base::ASCIIToUTF16("333 Washington St")}), + base::ASCIIToUTF16("151 Irving Ave"), + base::ASCIIToUTF16("Paul Revere"), base::string16())); +} + +TEST(AddressFormLabelFormatterTest, GetLabelsForUSProfilesAndFocusedName) { + AutofillProfile profile1 = + AutofillProfile(base::GenerateGUID(), test::kEmptyOrigin); + test::SetProfileInfo(&profile1, "John", "F", "Kennedy", "jfk@gmail.com", "", + "333 Washington St", "", "Brookline", "MA", "02445", + "US", "16177302000"); + + AutofillProfile profile2 = + AutofillProfile(base::GenerateGUID(), test::kEmptyOrigin); + test::SetProfileInfo(&profile2, "Jackie", "", "Kennedy", "jackie@outlook.com", + "", "151 Irving Ave", "", "Hyannis", "MA", "02601", "US", + "5087717796"); + + const std::vector<AutofillProfile*> profiles{&profile1, &profile2}; + const std::unique_ptr<LabelFormatter> formatter = + LabelFormatter::Create("en-US", NAME_FIRST, GetFieldTypes(), profiles); + + EXPECT_THAT( + formatter->GetLabels(profiles), + ElementsAre(base::ASCIIToUTF16("333 Washington St, Brookline, MA 02445"), + base::ASCIIToUTF16("151 Irving Ave, Hyannis, MA 02601"))); +} + +TEST(AddressFormLabelFormatterTest, + GetLabelsForBRProfilesAndFocusedStreetAddress) { + AutofillProfile profile = + AutofillProfile(base::GenerateGUID(), test::kEmptyOrigin); + test::SetProfileInfo(&profile, "Tarsila", "do", "Amaral", "tarsila@aol.com", + "", "Av. Pedro Álvares Cabral, 1301", "", "Vila Mariana", + "São Paulo", "SP", "04094-050", "BR", ""); + + const std::vector<AutofillProfile*> profiles{&profile}; + const std::unique_ptr<LabelFormatter> formatter = LabelFormatter::Create( + "pt-BR", ADDRESS_HOME_LINE1, GetFieldTypes(), profiles); + + EXPECT_THAT( + formatter->GetLabels(profiles), + ElementsAre(ConstructLabelLine( + {base::ASCIIToUTF16("Tarsila do Amaral"), + base::UTF8ToUTF16("Vila Mariana, São Paulo-SP, 04094-050")}))); +} + +TEST(AddressFormLabelFormatterTest, + GetLabelsForBRProfilesAndFocusedNonStreetAddress) { + AutofillProfile profile = + AutofillProfile(base::GenerateGUID(), test::kEmptyOrigin); + test::SetProfileInfo(&profile, "Tarsila", "do", "Amaral", "tarsila@aol.com", + "", "Av. Pedro Álvares Cabral, 1301", "", "Vila Mariana", + "São Paulo", "SP", "04094-050", "BR", ""); + + const std::vector<AutofillProfile*> profiles{&profile}; + const std::unique_ptr<LabelFormatter> formatter = LabelFormatter::Create( + "pt-BR", ADDRESS_HOME_ZIP, GetFieldTypes(), profiles); + + EXPECT_THAT(formatter->GetLabels(profiles), + ElementsAre(ConstructLabelLine( + {base::ASCIIToUTF16("Tarsila do Amaral"), + base::UTF8ToUTF16("Av. Pedro Álvares Cabral, 1301")}))); +} + +TEST(AddressFormLabelFormatterTest, GetLabelsForBRProfilesAndFocusedName) { + AutofillProfile profile = + AutofillProfile(base::GenerateGUID(), test::kEmptyOrigin); + test::SetProfileInfo(&profile, "Tarsila", "do", "Amaral", "tarsila@aol.com", + "", "Av. Pedro Álvares Cabral, 1301", "", "Vila Mariana", + "São Paulo", "SP", "04094-050", "BR", ""); + + const std::vector<AutofillProfile*> profiles{&profile}; + const std::unique_ptr<LabelFormatter> formatter = + LabelFormatter::Create("pt-BR", NAME_FIRST, GetFieldTypes(), profiles); + + EXPECT_THAT(formatter->GetLabels(profiles), + ElementsAre(base::UTF8ToUTF16( + "Av. Pedro Álvares Cabral, 1301, Vila Mariana, São " + "Paulo-SP, 04094-050"))); +} + +} // namespace +} // namespace autofill diff --git a/chromium/components/autofill/core/browser/address_phone_form_label_formatter.cc b/chromium/components/autofill/core/browser/address_phone_form_label_formatter.cc new file mode 100644 index 00000000000..97e374b27d9 --- /dev/null +++ b/chromium/components/autofill/core/browser/address_phone_form_label_formatter.cc @@ -0,0 +1,60 @@ +// Copyright 2019 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "components/autofill/core/browser/address_phone_form_label_formatter.h" + +#include "components/autofill/core/browser/label_formatter_utils.h" + +namespace autofill { + +AddressPhoneFormLabelFormatter::AddressPhoneFormLabelFormatter( + const std::string& app_locale, + ServerFieldType focused_field_type, + uint32_t groups, + const std::vector<ServerFieldType>& field_types) + : LabelFormatter(app_locale, focused_field_type, groups, field_types), + form_has_street_address_(HasStreetAddress(field_types_for_labels())) {} + +AddressPhoneFormLabelFormatter::~AddressPhoneFormLabelFormatter() {} + +base::string16 AddressPhoneFormLabelFormatter::GetLabelForProfile( + const AutofillProfile& profile, + FieldTypeGroup focused_group) const { + return focused_group == ADDRESS_HOME && + !IsStreetAddressPart(focused_field_type()) + ? GetLabelForProfileOnFocusedNonStreetAddress( + form_has_street_address_, profile, app_locale(), + field_types_for_labels(), + GetLabelPhone(profile, app_locale())) + : GetLabelForProfileOnFocusedNamePhoneOrStreetAddress( + profile, focused_group); +} + +// Note that the order--name, phone, and address--in which parts of the label +// are added ensures that the label is formatted correctly for |focused_group|, +// |focused_field_type_| and for this kind of formatter. +base::string16 AddressPhoneFormLabelFormatter:: + GetLabelForProfileOnFocusedNamePhoneOrStreetAddress( + const AutofillProfile& profile, + FieldTypeGroup focused_group) const { + std::vector<base::string16> label_parts; + if (focused_group != NAME) { + AddLabelPartIfNotEmpty(GetLabelName(profile, app_locale()), &label_parts); + } + + if (focused_group != PHONE_HOME) { + AddLabelPartIfNotEmpty(GetLabelPhone(profile, app_locale()), &label_parts); + } + + if (focused_group != ADDRESS_HOME) { + AddLabelPartIfNotEmpty( + GetLabelAddress(form_has_street_address_, profile, app_locale(), + field_types_for_labels()), + &label_parts); + } + + return ConstructLabelLine(label_parts); +} + +} // namespace autofill diff --git a/chromium/components/autofill/core/browser/address_phone_form_label_formatter.h b/chromium/components/autofill/core/browser/address_phone_form_label_formatter.h new file mode 100644 index 00000000000..231ca9e5084 --- /dev/null +++ b/chromium/components/autofill/core/browser/address_phone_form_label_formatter.h @@ -0,0 +1,51 @@ +// Copyright 2019 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef COMPONENTS_AUTOFILL_CORE_BROWSER_ADDRESS_PHONE_FORM_LABEL_FORMATTER_H_ +#define COMPONENTS_AUTOFILL_CORE_BROWSER_ADDRESS_PHONE_FORM_LABEL_FORMATTER_H_ + +#include <string> +#include <vector> + +#include "base/strings/string16.h" +#include "components/autofill/core/browser/autofill_profile.h" +#include "components/autofill/core/browser/field_types.h" +#include "components/autofill/core/browser/label_formatter.h" + +namespace autofill { + +// A LabelFormatter that creates Suggestions' disambiguating labels for forms +// with name, address, and phone fields and without email fields. +class AddressPhoneFormLabelFormatter : public LabelFormatter { + public: + AddressPhoneFormLabelFormatter( + const std::string& app_locale, + ServerFieldType focused_field_type, + uint32_t groups, + const std::vector<ServerFieldType>& field_types); + + ~AddressPhoneFormLabelFormatter() override; + + base::string16 GetLabelForProfile( + const AutofillProfile& profile, + FieldTypeGroup focused_group) const override; + + private: + // Returns a label to show the user when |focused_field_type_| is a type + // other than a non-street-address field type. For example, + // |focused_field_type_| could be first name, address line 1, or phone number. + base::string16 GetLabelForProfileOnFocusedNamePhoneOrStreetAddress( + const AutofillProfile& profile, + FieldTypeGroup focused_group) const; + + // True if this formatter's associated form has a street address field. A + // form may have an address-related field, e.g. zip code, without having a + // street address field. If a form does not include a street address field, + // street addresses should not appear in labels. + bool form_has_street_address_; +}; + +} // namespace autofill + +#endif // COMPONENTS_AUTOFILL_CORE_BROWSER_ADDRESS_PHONE_FORM_LABEL_FORMATTER_H_ diff --git a/chromium/components/autofill/core/browser/address_phone_form_label_formatter_unittest.cc b/chromium/components/autofill/core/browser/address_phone_form_label_formatter_unittest.cc new file mode 100644 index 00000000000..caf0e181a09 --- /dev/null +++ b/chromium/components/autofill/core/browser/address_phone_form_label_formatter_unittest.cc @@ -0,0 +1,325 @@ +// Copyright 2019 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "components/autofill/core/browser/address_phone_form_label_formatter.h" + +#include <memory> +#include <string> +#include <vector> + +#include "base/guid.h" +#include "base/strings/string16.h" +#include "base/strings/utf_string_conversions.h" +#include "components/autofill/core/browser/autofill_profile.h" +#include "components/autofill/core/browser/autofill_test_utils.h" +#include "components/autofill/core/browser/field_types.h" +#include "components/autofill/core/browser/label_formatter_utils.h" +#include "testing/gmock/include/gmock/gmock.h" +#include "testing/gtest/include/gtest/gtest.h" + +using testing::ElementsAre; + +namespace autofill { +namespace { + +std::vector<ServerFieldType> GetFieldTypes() { + return {NO_SERVER_DATA, NAME_FULL, PHONE_HOME_WHOLE_NUMBER, + ADDRESS_HOME_LINE1, ADDRESS_HOME_LINE2, ADDRESS_HOME_CITY, + ADDRESS_HOME_STATE, ADDRESS_HOME_ZIP, ADDRESS_HOME_COUNTRY}; +} + +TEST(AddressPhoneFormLabelFormatterTest, GetLabelsWithMissingProfiles) { + const std::vector<AutofillProfile*> profiles{}; + const std::unique_ptr<LabelFormatter> formatter = + LabelFormatter::Create("en-US", NAME_FULL, GetFieldTypes(), profiles); + EXPECT_TRUE(formatter->GetLabels(profiles).empty()); +} + +TEST(AddressPhoneFormLabelFormatterTest, GetLabelsForUSProfilesAndFocusedName) { + AutofillProfile profile1 = + AutofillProfile(base::GenerateGUID(), test::kEmptyOrigin); + test::SetProfileInfo(&profile1, "John", "F", "Kennedy", "jfk@gmail.com", "", + "333 Washington St", "", "Brookline", "MA", "02445", + "US", "16177302000"); + + AutofillProfile profile2 = + AutofillProfile(base::GenerateGUID(), test::kEmptyOrigin); + test::SetProfileInfo(&profile2, "Jackie", "", "Kennedy", "", "", + "151 Irving Ave", "", "Hyannis", "MA", "02601", "US", + ""); + + AutofillProfile profile3 = + AutofillProfile(base::GenerateGUID(), test::kEmptyOrigin); + test::SetProfileInfo(&profile3, "Paul", "", "Revere", "", "", "", "", "", "", + "", "US", "6175232338"); + + AutofillProfile profile4 = + AutofillProfile(base::GenerateGUID(), test::kEmptyOrigin); + test::SetProfileInfo(&profile4, "John", "", "Adams", "", "", "", "", "", "", + "", "US", ""); + + const std::vector<AutofillProfile*> profiles{&profile1, &profile2, &profile3, + &profile4}; + const std::unique_ptr<LabelFormatter> formatter = + LabelFormatter::Create("en-US", NAME_FULL, GetFieldTypes(), profiles); + + EXPECT_THAT( + formatter->GetLabels(profiles), + ElementsAre(ConstructLabelLine({base::ASCIIToUTF16("(617) 730-2000"), + base::ASCIIToUTF16("333 Washington St")}), + base::ASCIIToUTF16("151 Irving Ave"), + base::ASCIIToUTF16("(617) 523-2338"), base::string16())); +} + +TEST(AddressPhoneFormLabelFormatterTest, + GetLabelsForUSProfilesAndFocusedStreetAddress) { + AutofillProfile profile1 = + AutofillProfile(base::GenerateGUID(), test::kEmptyOrigin); + test::SetProfileInfo(&profile1, "John", "F", "Kennedy", "jfk@gmail.com", "", + "333 Washington St", "", "Brookline", "MA", "02445", + "US", "16177302000"); + + AutofillProfile profile2 = + AutofillProfile(base::GenerateGUID(), test::kEmptyOrigin); + test::SetProfileInfo(&profile2, "Jackie", "", "Kennedy", "", "", + "151 Irving Ave", "", "Hyannis", "MA", "02601", "US", + ""); + + AutofillProfile profile3 = + AutofillProfile(base::GenerateGUID(), test::kEmptyOrigin); + test::SetProfileInfo(&profile3, "", "", "", "", "", "", "", "", "", "", "US", + "6175232338"); + + AutofillProfile profile4 = + AutofillProfile(base::GenerateGUID(), test::kEmptyOrigin); + test::SetProfileInfo(&profile4, "", "", "", "", "", "141 Franklin St", "", + "Quincy", "MA", "02169", "US", ""); + + const std::vector<AutofillProfile*> profiles{&profile1, &profile2, &profile3, + &profile4}; + const std::unique_ptr<LabelFormatter> formatter = LabelFormatter::Create( + "en-US", ADDRESS_HOME_LINE1, GetFieldTypes(), profiles); + + EXPECT_THAT( + formatter->GetLabels(profiles), + ElementsAre(ConstructLabelLine({base::ASCIIToUTF16("John F Kennedy"), + base::ASCIIToUTF16("(617) 730-2000")}), + base::ASCIIToUTF16("Jackie Kennedy"), + base::ASCIIToUTF16("(617) 523-2338"), base::string16())); +} + +TEST(AddressPhoneFormLabelFormatterTest, + GetLabelsForUSProfilesAndFocusedNonStreetAddress) { + AutofillProfile profile1 = + AutofillProfile(base::GenerateGUID(), test::kEmptyOrigin); + test::SetProfileInfo(&profile1, "John", "F", "Kennedy", "jfk@gmail.com", "", + "333 Washington St", "", "Brookline", "MA", "02445", + "US", "16177302000"); + + AutofillProfile profile2 = + AutofillProfile(base::GenerateGUID(), test::kEmptyOrigin); + test::SetProfileInfo(&profile2, "Jackie", "", "Kennedy", "", "", + "151 Irving Ave", "", "Hyannis", "MA", "02601", "US", + ""); + + AutofillProfile profile3 = + AutofillProfile(base::GenerateGUID(), test::kEmptyOrigin); + test::SetProfileInfo(&profile3, "", "", "", "", "", "", "", "", "", "", "US", + "6175232338"); + + AutofillProfile profile4 = + AutofillProfile(base::GenerateGUID(), test::kEmptyOrigin); + test::SetProfileInfo(&profile4, "", "", "", "", "", "", "", "Quincy", "MA", + "02169", "US", ""); + + const std::vector<AutofillProfile*> profiles{&profile1, &profile2, &profile3, + &profile4}; + const std::unique_ptr<LabelFormatter> formatter = LabelFormatter::Create( + "en-US", ADDRESS_HOME_CITY, GetFieldTypes(), profiles); + + EXPECT_THAT( + formatter->GetLabels(profiles), + ElementsAre(ConstructLabelLine({base::ASCIIToUTF16("333 Washington St"), + base::ASCIIToUTF16("(617) 730-2000")}), + base::ASCIIToUTF16("151 Irving Ave"), + base::ASCIIToUTF16("(617) 523-2338"), base::string16())); +} + +TEST(AddressPhoneFormLabelFormatterTest, + GetLabelsForUSProfilesAndFocusedPhone) { + AutofillProfile profile1 = + AutofillProfile(base::GenerateGUID(), test::kEmptyOrigin); + test::SetProfileInfo(&profile1, "John", "F", "Kennedy", "jfk@gmail.com", "", + "333 Washington St", "", "Brookline", "MA", "02445", + "US", "16177302000"); + + AutofillProfile profile2 = + AutofillProfile(base::GenerateGUID(), test::kEmptyOrigin); + test::SetProfileInfo(&profile2, "Jackie", "", "Kennedy", "", "", "", "", "", + "", "", "US", ""); + + AutofillProfile profile3 = + AutofillProfile(base::GenerateGUID(), test::kEmptyOrigin); + test::SetProfileInfo(&profile3, "", "", "", "", "", "Paul Revere House", + "19 North Square", "Boston", "MA", "02113", "US", + "6175232338"); + + AutofillProfile profile4 = + AutofillProfile(base::GenerateGUID(), test::kEmptyOrigin); + test::SetProfileInfo(&profile4, "", "", "", "", "", "", "", "", "", "", "US", + ""); + + const std::vector<AutofillProfile*> profiles{&profile1, &profile2, &profile3, + &profile4}; + const std::unique_ptr<LabelFormatter> formatter = LabelFormatter::Create( + "en-US", PHONE_HOME_WHOLE_NUMBER, GetFieldTypes(), profiles); + + EXPECT_THAT( + formatter->GetLabels(profiles), + ElementsAre(ConstructLabelLine({base::ASCIIToUTF16("John F Kennedy"), + base::ASCIIToUTF16("333 Washington St")}), + base::ASCIIToUTF16("Jackie Kennedy"), + base::ASCIIToUTF16("Paul Revere House, 19 North Square"), + base::string16())); +} + +TEST(AddressPhoneFormLabelFormatterTest, GetLabelsForBRProfilesAndFocusedName) { + AutofillProfile profile1 = + AutofillProfile(base::GenerateGUID(), test::kEmptyOrigin); + test::SetProfileInfo(&profile1, "Tarsila", "do", "Amaral", "tarsila@aol.com", + "", "Av. Pedro Álvares Cabral, 1301", "", "Vila Mariana", + "São Paulo", "SP", "04094-050", "BR", + "+55 11 2648-0254"); + + AutofillProfile profile2 = + AutofillProfile(base::GenerateGUID(), test::kEmptyOrigin); + test::SetProfileInfo(&profile2, "Artur", "", "Avila", "aavila@uol.com.br", "", + "Estr. Dona Castorina, 110", "", "Jardim Botânico", + "Rio de Janeiro", "RJ", "22460-320", "BR", + "21987650000"); + + const std::vector<AutofillProfile*> profiles{&profile1, &profile2}; + const std::unique_ptr<LabelFormatter> formatter = + LabelFormatter::Create("pt-BR", NAME_FULL, GetFieldTypes(), profiles); + + EXPECT_THAT( + formatter->GetLabels(profiles), + ElementsAre(ConstructLabelLine( + {base::ASCIIToUTF16("(11) 2648-0254"), + base::UTF8ToUTF16("Av. Pedro Álvares Cabral, 1301")}), + ConstructLabelLine( + {base::ASCIIToUTF16("(21) 98765-0000"), + base::ASCIIToUTF16("Estr. Dona Castorina, 110")}))); +} + +TEST(AddressPhoneFormLabelFormatterTest, + GetLabelsForBRProfilesAndFocusedStreetAddress) { + AutofillProfile profile1 = + AutofillProfile(base::GenerateGUID(), test::kEmptyOrigin); + test::SetProfileInfo(&profile1, "Tarsila", "do", "Amaral", "tarsila@aol.com", + "", "Av. Pedro Álvares Cabral, 1301", "", "Vila Mariana", + "São Paulo", "SP", "04094-050", "BR", + "+55 11 2648-0254"); + + AutofillProfile profile2 = + AutofillProfile(base::GenerateGUID(), test::kEmptyOrigin); + test::SetProfileInfo(&profile2, "Artur", "", "Avila", "aavila@uol.com.br", "", + "Estr. Dona Castorina, 110", "", "Jardim Botânico", + "Rio de Janeiro", "RJ", "22460-320", "BR", + "21987650000"); + + const std::vector<AutofillProfile*> profiles{&profile1, &profile2}; + const std::unique_ptr<LabelFormatter> formatter = LabelFormatter::Create( + "pt-BR", ADDRESS_HOME_LINE1, GetFieldTypes(), profiles); + + EXPECT_THAT( + formatter->GetLabels(profiles), + ElementsAre(ConstructLabelLine({base::ASCIIToUTF16("Tarsila do Amaral"), + base::ASCIIToUTF16("(11) 2648-0254")}), + ConstructLabelLine({base::ASCIIToUTF16("Artur Avila"), + base::ASCIIToUTF16("(21) 98765-0000")}))); +} + +TEST(AddressPhoneFormLabelFormatterTest, + GetLabelsForBRProfilesAndFocusedNonStreetAddress) { + AutofillProfile profile1 = + AutofillProfile(base::GenerateGUID(), test::kEmptyOrigin); + test::SetProfileInfo(&profile1, "Tarsila", "do", "Amaral", "tarsila@aol.com", + "", "Av. Pedro Álvares Cabral, 1301", "", "Vila Mariana", + "São Paulo", "SP", "04094-050", "BR", + "+55 11 2648-0254"); + + AutofillProfile profile2 = + AutofillProfile(base::GenerateGUID(), test::kEmptyOrigin); + test::SetProfileInfo(&profile2, "Artur", "", "Avila", "aavila@uol.com.br", "", + "Estr. Dona Castorina, 110", "", "Jardim Botânico", + "Rio de Janeiro", "RJ", "22460-320", "BR", + "21987650000"); + + const std::vector<AutofillProfile*> profiles{&profile1, &profile2}; + const std::unique_ptr<LabelFormatter> formatter = LabelFormatter::Create( + "pt-BR", ADDRESS_HOME_ZIP, GetFieldTypes(), profiles); + + EXPECT_THAT( + formatter->GetLabels(profiles), + ElementsAre( + ConstructLabelLine( + {base::UTF8ToUTF16("Av. Pedro Álvares Cabral, 1301"), + base::ASCIIToUTF16("(11) 2648-0254")}), + ConstructLabelLine({base::ASCIIToUTF16("Estr. Dona Castorina, 110"), + base::ASCIIToUTF16("(21) 98765-0000")}))); +} + +TEST(AddressPhoneFormLabelFormatterTest, + GetLabelsForBRProfilesAndFocusedPhone) { + AutofillProfile profile1 = + AutofillProfile(base::GenerateGUID(), test::kEmptyOrigin); + test::SetProfileInfo(&profile1, "Tarsila", "do", "Amaral", "tarsila@aol.com", + "", "Av. Pedro Álvares Cabral, 1301", "", "Vila Mariana", + "São Paulo", "SP", "04094-050", "BR", + "+55 11 2648-0254"); + + AutofillProfile profile2 = + AutofillProfile(base::GenerateGUID(), test::kEmptyOrigin); + test::SetProfileInfo(&profile2, "Artur", "", "Avila", "aavila@uol.com.br", "", + "Estr. Dona Castorina, 110", "", "Jardim Botânico", + "Rio de Janeiro", "RJ", "22460-320", "BR", + "21987650000"); + + const std::vector<AutofillProfile*> profiles{&profile1, &profile2}; + const std::unique_ptr<LabelFormatter> formatter = LabelFormatter::Create( + "pt-BR", PHONE_HOME_WHOLE_NUMBER, GetFieldTypes(), profiles); + + EXPECT_THAT( + formatter->GetLabels(profiles), + ElementsAre(ConstructLabelLine( + {base::ASCIIToUTF16("Tarsila do Amaral"), + base::UTF8ToUTF16("Av. Pedro Álvares Cabral, 1301")}), + ConstructLabelLine( + {base::ASCIIToUTF16("Artur Avila"), + base::ASCIIToUTF16("Estr. Dona Castorina, 110")}))); +} + +TEST(AddressPhoneFormLabelFormatterTest, + GetLabelsForFormWithAddressFieldsMinusStreetAddress) { + AutofillProfile profile = + AutofillProfile(base::GenerateGUID(), test::kEmptyOrigin); + test::SetProfileInfo(&profile, "John", "F", "Kennedy", "jfk@gmail.com", "", + "333 Washington St", "", "Brookline", "MA", "02445", + "US", "16177302000"); + + const std::vector<AutofillProfile*> profiles{&profile}; + const std::unique_ptr<LabelFormatter> formatter = LabelFormatter::Create( + "en-US", PHONE_HOME_WHOLE_NUMBER, + {NAME_FULL, PHONE_HOME_WHOLE_NUMBER, ADDRESS_HOME_ZIP}, profiles); + + // Checks that only address fields in the form are shown in the label. + EXPECT_THAT( + formatter->GetLabels(profiles), + ElementsAre(ConstructLabelLine({base::ASCIIToUTF16("John F Kennedy"), + base::ASCIIToUTF16("02445")}))); +} + +} // namespace +} // namespace autofill
\ No newline at end of file diff --git a/chromium/components/autofill/core/browser/autocomplete_history_manager.cc b/chromium/components/autofill/core/browser/autocomplete_history_manager.cc index 8eae19020de..f484db2d6cb 100644 --- a/chromium/components/autofill/core/browser/autocomplete_history_manager.cc +++ b/chromium/components/autofill/core/browser/autocomplete_history_manager.cc @@ -122,6 +122,11 @@ void AutocompleteHistoryManager::Init( pref_service_ = pref_service; is_off_the_record_ = is_off_the_record; + if (!profile_database_) { + // In some tests, there are no dbs. + return; + } + // No need to run the retention policy in OTR. if (!is_off_the_record_ && base::FeatureList::IsEnabled( diff --git a/chromium/components/autofill/core/browser/autocomplete_history_manager_unittest.cc b/chromium/components/autofill/core/browser/autocomplete_history_manager_unittest.cc index 249abd01d70..4c662e11e9f 100644 --- a/chromium/components/autofill/core/browser/autocomplete_history_manager_unittest.cc +++ b/chromium/components/autofill/core/browser/autocomplete_history_manager_unittest.cc @@ -164,7 +164,7 @@ class AutocompleteHistoryManagerTest : public testing::Test { TEST_F(AutocompleteHistoryManagerTest, CreditCardNumberValue) { FormData form; form.name = ASCIIToUTF16("MyForm"); - form.origin = GURL("http://myform.com/form.html"); + form.url = GURL("http://myform.com/form.html"); form.action = GURL("http://myform.com/submit.html"); // Valid Visa credit card number pulled from the paypal help site. @@ -186,7 +186,7 @@ TEST_F(AutocompleteHistoryManagerTest, CreditCardNumberValue) { TEST_F(AutocompleteHistoryManagerTest, NonCreditCardNumberValue) { FormData form; form.name = ASCIIToUTF16("MyForm"); - form.origin = GURL("http://myform.com/form.html"); + form.url = GURL("http://myform.com/form.html"); form.action = GURL("http://myform.com/submit.html"); // Invalid credit card number. @@ -206,7 +206,7 @@ TEST_F(AutocompleteHistoryManagerTest, NonCreditCardNumberValue) { TEST_F(AutocompleteHistoryManagerTest, SSNValue) { FormData form; form.name = ASCIIToUTF16("MyForm"); - form.origin = GURL("http://myform.com/form.html"); + form.url = GURL("http://myform.com/form.html"); form.action = GURL("http://myform.com/submit.html"); FormFieldData ssn; @@ -225,7 +225,7 @@ TEST_F(AutocompleteHistoryManagerTest, SSNValue) { TEST_F(AutocompleteHistoryManagerTest, SearchField) { FormData form; form.name = ASCIIToUTF16("MyForm"); - form.origin = GURL("http://myform.com/form.html"); + form.url = GURL("http://myform.com/form.html"); form.action = GURL("http://myform.com/submit.html"); // Search field. @@ -244,7 +244,7 @@ TEST_F(AutocompleteHistoryManagerTest, SearchField) { TEST_F(AutocompleteHistoryManagerTest, AutocompleteFeatureOff) { FormData form; form.name = ASCIIToUTF16("MyForm"); - form.origin = GURL("http://myform.com/form.html"); + form.url = GURL("http://myform.com/form.html"); form.action = GURL("http://myform.com/submit.html"); // Search field. @@ -267,7 +267,7 @@ TEST_F(AutocompleteHistoryManagerTest, AutocompleteFeatureOff) { TEST_F(AutocompleteHistoryManagerTest, FieldWithAutocompleteOff) { FormData form; form.name = ASCIIToUTF16("MyForm"); - form.origin = GURL("http://myform.com/form.html"); + form.url = GURL("http://myform.com/form.html"); form.action = GURL("http://myform.com/submit.html"); // Field specifying autocomplete="off". @@ -290,7 +290,7 @@ TEST_F(AutocompleteHistoryManagerTest, Incognito) { /*is_off_the_record_=*/true); FormData form; form.name = ASCIIToUTF16("MyForm"); - form.origin = GURL("http://myform.com/form.html"); + form.url = GURL("http://myform.com/form.html"); form.action = GURL("http://myform.com/submit.html"); // Search field. @@ -311,7 +311,7 @@ TEST_F(AutocompleteHistoryManagerTest, Incognito) { TEST_F(AutocompleteHistoryManagerTest, NonFocusableField) { FormData form; form.name = ASCIIToUTF16("MyForm"); - form.origin = GURL("http://myform.com/form.html"); + form.url = GURL("http://myform.com/form.html"); form.action = GURL("http://myform.com/submit.html"); // Unfocusable field. @@ -333,7 +333,7 @@ TEST_F(AutocompleteHistoryManagerTest, NonFocusableField) { TEST_F(AutocompleteHistoryManagerTest, PresentationField) { FormData form; form.name = ASCIIToUTF16("MyForm"); - form.origin = GURL("http://myform.com/form.html"); + form.url = GURL("http://myform.com/form.html"); form.action = GURL("http://myform.com/submit.html"); // Presentation field. @@ -400,6 +400,21 @@ TEST_F(AutocompleteHistoryManagerTest, /*is_off_the_record=*/false); } +// Tests that the Init function will not crash even if we don't have a DB. +TEST_F(AutocompleteHistoryManagerTest, Init_NullDB_NoCrash) { + // Enable the feature, and set the major version. + scoped_features.InitAndEnableFeature( + features::kAutocompleteRetentionPolicyEnabled); + prefs_->SetInteger(prefs::kAutocompleteLastVersionRetentionPolicy, + CHROME_VERSION_MAJOR - 1); + + EXPECT_CALL(*web_data_service_, + RemoveExpiredAutocompleteEntries(autocomplete_manager_.get())) + .Times(0); + autocomplete_manager_->Init(nullptr, prefs_.get(), + /*is_off_the_record=*/false); +} + // Tests that the Init function will not trigger the Autocomplete Retention // Policy when running in a major version that was already cleaned. TEST_F(AutocompleteHistoryManagerTest, @@ -872,7 +887,7 @@ TEST_F(AutocompleteHistoryManagerTest, TEST_F(AutocompleteHistoryManagerTest, NoAutocompleteSuggestionsForTextarea) { FormData form; form.name = ASCIIToUTF16("MyForm"); - form.origin = GURL("http://myform.com/form.html"); + form.url = GURL("http://myform.com/form.html"); form.action = GURL("http://myform.com/submit.html"); FormFieldData field; diff --git a/chromium/components/autofill/core/browser/autofill_assistant_unittest.cc b/chromium/components/autofill/core/browser/autofill_assistant_unittest.cc index 958759bc688..365e2f8ea55 100644 --- a/chromium/components/autofill/core/browser/autofill_assistant_unittest.cc +++ b/chromium/components/autofill/core/browser/autofill_assistant_unittest.cc @@ -18,9 +18,9 @@ #include "components/autofill/core/browser/credit_card.h" #include "components/autofill/core/browser/form_structure.h" #include "components/autofill/core/browser/mock_autocomplete_history_manager.h" +#include "components/autofill/core/browser/payments/test_credit_card_save_manager.h" #include "components/autofill/core/browser/test_autofill_client.h" #include "components/autofill/core/browser/test_autofill_driver.h" -#include "components/autofill/core/browser/test_credit_card_save_manager.h" #include "components/autofill/core/browser/test_personal_data_manager.h" #include "components/autofill/core/common/autofill_constants.h" #include "components/autofill/core/common/autofill_features.h" @@ -70,9 +70,9 @@ class AutofillAssistantTest : public testing::Test { void SetUp() { payments::TestPaymentsClient* payments_client = - new payments::TestPaymentsClient( - autofill_driver_.GetURLLoaderFactory(), autofill_client_.GetPrefs(), - autofill_client_.GetIdentityManager(), &pdm_); + new payments::TestPaymentsClient(autofill_driver_.GetURLLoaderFactory(), + autofill_client_.GetIdentityManager(), + &pdm_); autofill_client_.set_test_payments_client( std::unique_ptr<payments::TestPaymentsClient>(payments_client)); TestCreditCardSaveManager* credit_card_save_manager = @@ -101,7 +101,7 @@ class AutofillAssistantTest : public testing::Test { // Returns a valid credit card form. FormData CreateValidCreditCardFormData() { FormData form; - form.origin = GURL("https://myform.com"); + form.url = GURL("https://myform.com"); form.action = GURL("https://myform.com/submit"); FormFieldData field; @@ -202,7 +202,7 @@ TEST_F(AutofillAssistantTest, CanShowCreditCardAssist_FeatureOn_NotSecure) { // Cannot be shown if the context is not secure. FormData form = CreateValidCreditCardFormData(); - form.origin = GURL("http://myform.com"); + form.url = GURL("http://myform.com"); form.action = GURL("http://myform.com/submit"); auto form_structure = std::make_unique<FormStructure>(form); form_structure->DetermineHeuristicTypes(); diff --git a/chromium/components/autofill/core/browser/autofill_client.h b/chromium/components/autofill/core/browser/autofill_client.h index 0341ce2c565..a60e5f6b0d9 100644 --- a/chromium/components/autofill/core/browser/autofill_client.h +++ b/chromium/components/autofill/core/browser/autofill_client.h @@ -15,7 +15,7 @@ #include "base/strings/string16.h" #include "base/values.h" #include "build/build_config.h" -#include "components/autofill/core/browser/risk_data_loader.h" +#include "components/autofill/core/browser/payments/risk_data_loader.h" #include "components/security_state/core/security_state.h" #include "services/metrics/public/cpp/ukm_source_id.h" #include "ui/base/window_open_disposition.h" @@ -125,6 +125,11 @@ class AutofillClient : public RiskDataLoader { // Used for options of upload prompt. struct SaveCreditCardOptions { + SaveCreditCardOptions& with_from_dynamic_change_form(bool b) { + from_dynamic_change_form = b; + return *this; + } + SaveCreditCardOptions& with_has_non_focusable_field(bool b) { has_non_focusable_field = b; return *this; @@ -146,6 +151,7 @@ class AutofillClient : public RiskDataLoader { return *this; } + bool from_dynamic_change_form = false; bool has_non_focusable_field = false; bool should_request_name_from_user = false; bool should_request_expiration_date_from_user = false; diff --git a/chromium/components/autofill/core/browser/autofill_data_model.cc b/chromium/components/autofill/core/browser/autofill_data_model.cc index 59f83e57b3e..7858c3dfd5b 100644 --- a/chromium/components/autofill/core/browser/autofill_data_model.cc +++ b/chromium/components/autofill/core/browser/autofill_data_model.cc @@ -44,7 +44,8 @@ bool AutofillDataModel::HasGreaterFrecencyThan( double other_score = other->GetFrecencyScore(comparison_time); // Ties are broken by MRU, then by GUID comparison. - if (score != other_score) + const double kEpsilon = 0.00001; + if (std::fabs(score - other_score) > kEpsilon) return score > other_score; if (use_date_ != other->use_date_) @@ -77,7 +78,7 @@ double AutofillDataModel::GetFrecencyScore(base::Time time) const { } bool AutofillDataModel::IsDeletable() const { - return use_date_ < AutofillClock::Now() - kDisusedDataModelDeletionTimeDelta; + return IsAutofillEntryWithUseDateDeletable(use_date_); } AutofillDataModel::ValidityState AutofillDataModel::GetValidityState( diff --git a/chromium/components/autofill/core/browser/autofill_data_model.h b/chromium/components/autofill/core/browser/autofill_data_model.h index 07fd92b828d..76909201239 100644 --- a/chromium/components/autofill/core/browser/autofill_data_model.h +++ b/chromium/components/autofill/core/browser/autofill_data_model.h @@ -103,6 +103,12 @@ class AutofillDataModel : public FormGroup { // the subject of user interaction (usually, when it's used to fill a form). void RecordUse(); + // Returns a score based on both the recency (relative to |time|) and + // frequency for the model. The score is a negative number where a higher + // value is more relevant. |time| is passed as a parameter to ensure + // consistent results. + double GetFrecencyScore(base::Time time) const; + private: // A globally unique ID for this object. std::string guid_; @@ -125,12 +131,6 @@ class AutofillDataModel : public FormGroup { // The last time data in the model was modified, rounded in seconds. Any // change should use set_previous_modification_date() base::Time modification_date_; - - // Returns a score based on both the recency (relative to |time|) and - // frequency for the model. The score is a negative number where a higher - // value is more relevant. |time| is passed as a parameter to ensure - // consistent results. - double GetFrecencyScore(base::Time time) const; }; } // namespace autofill diff --git a/chromium/components/autofill/core/browser/autofill_data_util.cc b/chromium/components/autofill/core/browser/autofill_data_util.cc index 542571769a6..5b530a04942 100644 --- a/chromium/components/autofill/core/browser/autofill_data_util.cc +++ b/chromium/components/autofill/core/browser/autofill_data_util.cc @@ -15,6 +15,7 @@ #include "base/strings/utf_string_conversions.h" #include "components/autofill/core/browser/autofill_country.h" #include "components/autofill/core/browser/autofill_profile.h" +#include "components/autofill/core/browser/autofill_type.h" #include "components/autofill/core/browser/credit_card.h" #include "components/autofill/core/browser/field_types.h" #include "components/autofill/core/browser/webdata/autofill_table.h" @@ -26,7 +27,13 @@ namespace autofill { namespace data_util { +using bit_field_type_groups::kAddress; +using bit_field_type_groups::kEmail; +using bit_field_type_groups::kName; +using bit_field_type_groups::kPhone; + namespace { + // Mappings from Chrome card networks to Payment Request API basic card payment // spec networks and icons. Note that "generic" is not in the spec. // https://w3c.github.io/webpayments-methods-card/#method-id @@ -242,6 +249,47 @@ bool SplitCJKName(const std::vector<base::StringPiece16>& name_tokens, } // namespace +bool ContainsName(uint32_t groups) { + return groups & kName; +} + +bool ContainsAddress(uint32_t groups) { + return groups & kAddress; +} + +bool ContainsEmail(uint32_t groups) { + return groups & kEmail; +} + +bool ContainsPhone(uint32_t groups) { + return groups & kPhone; +} + +uint32_t DetermineGroups(const std::vector<ServerFieldType>& types) { + uint32_t group_bitmask = 0; + for (const ServerFieldType& type : types) { + const FieldTypeGroup group = + AutofillType(AutofillType(type).GetStorableType()).group(); + switch (group) { + case autofill::NAME: + group_bitmask |= kName; + break; + case autofill::ADDRESS_HOME: + group_bitmask |= kAddress; + break; + case autofill::EMAIL: + group_bitmask |= kEmail; + break; + case autofill::PHONE_HOME: + group_bitmask |= kPhone; + break; + default: + break; + } + } + return group_bitmask; +} + std::string TruncateUTF8(const std::string& data) { std::string trimmed_value; base::TruncateUTF8ToByteSize(data, AutofillTable::kMaxDataLength, diff --git a/chromium/components/autofill/core/browser/autofill_data_util.h b/chromium/components/autofill/core/browser/autofill_data_util.h index ee3ede76fc8..ba8f55f0fdc 100644 --- a/chromium/components/autofill/core/browser/autofill_data_util.h +++ b/chromium/components/autofill/core/browser/autofill_data_util.h @@ -6,6 +6,7 @@ #define COMPONENTS_AUTOFILL_CORE_BROWSER_AUTOFILL_DATA_UTIL_H_ #include <string> +#include <vector> #include "base/strings/string16.h" #include "base/strings/string_piece_forward.h" @@ -23,6 +24,39 @@ struct NameParts { base::string16 family; }; +namespace bit_field_type_groups { + +// Bits for FieldTypeGroup options. +// The form has a field associated with the NAME_HOME or NAME_BILLING +// FieldTypeGroups. +constexpr uint32_t kName = 1 << 0; +// The form has a field associated with the ADDRESS_HOME or ADDRESS_BILLING +// FieldTypeGroups. +constexpr uint32_t kAddress = 1 << 1; +// The form has a field associated with the EMAIL FieldTypeGroup. +constexpr uint32_t kEmail = 1 << 2; +// The form has a field associated with the PHONE_HOME or PHONE_BILLING +// FieldTypeGroups. +constexpr uint32_t kPhone = 1 << 3; + +} // namespace bit_field_type_groups + +// Returns true if kName is set in |groups|. +bool ContainsName(uint32_t groups); + +// Returns true if kAddress is set in |groups|. +bool ContainsAddress(uint32_t groups); + +// Returns true if kEmail is set in |groups|. +bool ContainsEmail(uint32_t groups); + +// Returns true if kPhone is set in |groups|. +bool ContainsPhone(uint32_t groups); + +// Returns a bitmask indicating whether the NAME, ADDRESS_HOME, EMAIL, and +// PHONE_HOME FieldTypeGroups are associated with the given |field_types|. +uint32_t DetermineGroups(const std::vector<ServerFieldType>& types); + // Truncates a string to the nearest UTF-8 character that will leave // the string less than or equal to the specified byte size. std::string TruncateUTF8(const std::string& data); diff --git a/chromium/components/autofill/core/browser/autofill_download_manager_unittest.cc b/chromium/components/autofill/core/browser/autofill_download_manager_unittest.cc index 9e23fc158a4..b6c34b64afe 100644 --- a/chromium/components/autofill/core/browser/autofill_download_manager_unittest.cc +++ b/chromium/components/autofill/core/browser/autofill_download_manager_unittest.cc @@ -1525,7 +1525,7 @@ TEST_P(AutofillQueryTest, ExpiredCacheInResponse) { TEST_P(AutofillQueryTest, RichMetadata_Enabled) { // Initialize a form. Note that this state is post-parse. FormData form; - form.origin = GURL("https://origin.com"); + form.url = GURL("https://origin.com"); form.action = GURL("https://origin.com/submit-me"); form.id_attribute = UTF8ToUTF16("form-id-attribute"); form.name_attribute = UTF8ToUTF16("form-name-attribute"); @@ -1625,7 +1625,7 @@ TEST_P(AutofillQueryTest, RichMetadata_Enabled) { TEST_P(AutofillQueryTest, RichMetadata_Disabled) { // Initialize a form. Note that this state is post-parse. FormData form; - form.origin = GURL("https://origin.com"); + form.url = GURL("https://origin.com"); form.action = GURL("https://origin.com/submit-me"); form.id_attribute = UTF8ToUTF16("form-id-attribute"); form.name_attribute = UTF8ToUTF16("form-name-attribute"); @@ -1715,7 +1715,7 @@ TEST_P(AutofillUploadTest, RichMetadata) { local_feature.InitAndEnableFeature(features::kAutofillMetadataUploads); FormData form; - form.origin = GURL("https://origin.com"); + form.url = GURL("https://origin.com"); form.action = GURL("https://origin.com/submit-me"); form.id_attribute = UTF8ToUTF16("form-id_attribute"); form.name_attribute = UTF8ToUTF16("form-id_attribute"); diff --git a/chromium/components/autofill/core/browser/autofill_experiments.cc b/chromium/components/autofill/core/browser/autofill_experiments.cc index ffc1f9c2c89..15d85bf9bed 100644 --- a/chromium/components/autofill/core/browser/autofill_experiments.cc +++ b/chromium/components/autofill/core/browser/autofill_experiments.cc @@ -12,8 +12,12 @@ #include "base/strings/string_util.h" #include "base/strings/utf_string_conversions.h" #include "build/build_config.h" +#include "components/autofill/core/browser/autofill_metrics.h" +#include "components/autofill/core/browser/payments/payments_util.h" +#include "components/autofill/core/browser/personal_data_manager.h" #include "components/autofill/core/browser/suggestion.h" #include "components/autofill/core/common/autofill_features.h" +#include "components/autofill/core/common/autofill_payments_features.h" #include "components/autofill/core/common/autofill_prefs.h" #include "components/autofill/core/common/autofill_switches.h" #include "components/prefs/pref_service.h" @@ -29,22 +33,31 @@ namespace autofill { -#if defined(OS_LINUX) || defined(OS_MACOSX) || defined(OS_WIN) -const base::Feature kAutofillDropdownLayoutExperiment{ - "AutofillDropdownLayout", base::FEATURE_DISABLED_BY_DEFAULT}; -const char kAutofillDropdownLayoutParameterName[] = "variant"; -const char kAutofillDropdownLayoutParameterLeadingIcon[] = "leading-icon"; -const char kAutofillDropdownLayoutParameterTrailingIcon[] = "trailing-icon"; -const char kAutofillDropdownLayoutParameterTwoLinesLeadingIcon[] = - "two-lines-leading-icon"; -#endif // defined(OS_LINUX) || defined(OS_MACOSX) || defined(OS_WIN) - bool IsCreditCardUploadEnabled(const PrefService* pref_service, const syncer::SyncService* sync_service, - const std::string& user_email) { - if (!sync_service || sync_service->GetAuthError().IsPersistentError() || - !sync_service->GetActiveDataTypes().Has(syncer::AUTOFILL_WALLET_DATA)) { + const std::string& user_email, + const AutofillSyncSigninState sync_state) { + if (!sync_service) { // If credit card sync is not active, we're not offering to upload cards. + AutofillMetrics::LogCardUploadEnabledMetric( + AutofillMetrics::CardUploadEnabledMetric::SYNC_SERVICE_NULL, + sync_state); + return false; + } + + if (sync_service->GetAuthError().IsPersistentError()) { + AutofillMetrics::LogCardUploadEnabledMetric( + AutofillMetrics::CardUploadEnabledMetric:: + SYNC_SERVICE_PERSISTENT_AUTH_ERROR, + sync_state); + return false; + } + + if (!sync_service->GetActiveDataTypes().Has(syncer::AUTOFILL_WALLET_DATA)) { + AutofillMetrics::LogCardUploadEnabledMetric( + AutofillMetrics::CardUploadEnabledMetric:: + SYNC_SERVICE_MISSING_AUTOFILL_WALLET_DATA_ACTIVE_TYPE, + sync_state); return false; } @@ -52,6 +65,10 @@ bool IsCreditCardUploadEnabled(const PrefService* pref_service, if (!sync_service->GetActiveDataTypes().Has(syncer::AUTOFILL_PROFILE)) { // In full sync mode, we only allow card upload when addresses are also // active, because we upload potential billing addresses with the card. + AutofillMetrics::LogCardUploadEnabledMetric( + AutofillMetrics::CardUploadEnabledMetric:: + SYNC_SERVICE_MISSING_AUTOFILL_PROFILE_ACTIVE_TYPE, + sync_state); return false; } } else { @@ -63,6 +80,10 @@ bool IsCreditCardUploadEnabled(const PrefService* pref_service, features::kAutofillEnableAccountWalletStorageUpload)) { // We're not enabling uploads in the account wallet mode, so suppress // the upload prompt. + AutofillMetrics::LogCardUploadEnabledMetric( + AutofillMetrics::CardUploadEnabledMetric:: + ACCOUNT_WALLET_STORAGE_UPLOAD_DISABLED, + sync_state); return false; } } @@ -71,21 +92,37 @@ bool IsCreditCardUploadEnabled(const PrefService* pref_service, // Users who have enabled a passphrase have chosen to not make their sync // information accessible to Google. Since upload makes credit card data // available to other Google systems, disable it for passphrase users. - if (sync_service->GetUserSettings()->IsUsingSecondaryPassphrase()) + if (sync_service->GetUserSettings()->IsUsingSecondaryPassphrase()) { + AutofillMetrics::LogCardUploadEnabledMetric( + AutofillMetrics::CardUploadEnabledMetric:: + USING_SECONDARY_SYNC_PASSPHRASE, + sync_state); return false; + } // Don't offer upload for users that are only syncing locally, since they // won't receive the cards back from Google Payments. - if (sync_service->IsLocalSyncEnabled()) + if (sync_service->IsLocalSyncEnabled()) { + AutofillMetrics::LogCardUploadEnabledMetric( + AutofillMetrics::CardUploadEnabledMetric::LOCAL_SYNC_ENABLED, + sync_state); return false; + } // Check Payments integration user setting. - if (!prefs::IsPaymentsIntegrationEnabled(pref_service)) + if (!prefs::IsPaymentsIntegrationEnabled(pref_service)) { + AutofillMetrics::LogCardUploadEnabledMetric( + AutofillMetrics::CardUploadEnabledMetric::PAYMENTS_INTEGRATION_DISABLED, + sync_state); return false; + } // Check that the user is logged into a supported domain. - if (user_email.empty()) + if (user_email.empty()) { + AutofillMetrics::LogCardUploadEnabledMetric( + AutofillMetrics::CardUploadEnabledMetric::EMAIL_EMPTY, sync_state); return false; + } std::string domain = gaia::ExtractDomainName(user_email); // If the "allow all email domains" flag is off, restrict credit card upload @@ -98,10 +135,64 @@ bool IsCreditCardUploadEnabled(const PrefService* pref_service, !(domain == "googlemail.com" || domain == "gmail.com" || domain == "google.com" || domain == "chromium.org" || domain == "example.com")) { + AutofillMetrics::LogCardUploadEnabledMetric( + AutofillMetrics::CardUploadEnabledMetric::EMAIL_DOMAIN_NOT_SUPPORTED, + sync_state); return false; } - return base::FeatureList::IsEnabled(features::kAutofillUpstream); + if (!base::FeatureList::IsEnabled(features::kAutofillUpstream)) { + AutofillMetrics::LogCardUploadEnabledMetric( + AutofillMetrics::CardUploadEnabledMetric::AUTOFILL_UPSTREAM_DISABLED, + sync_state); + return false; + } + + AutofillMetrics::LogCardUploadEnabledMetric( + AutofillMetrics::CardUploadEnabledMetric::CARD_UPLOAD_ENABLED, + sync_state); + return true; +} + +bool IsCreditCardMigrationEnabled(PersonalDataManager* personal_data_manager, + PrefService* pref_service, + syncer::SyncService* sync_service, + bool is_test_mode) { + // Confirm that experiment flags are enabled. + if (features::GetLocalCardMigrationExperimentalFlag() == + features::LocalCardMigrationExperimentalFlag::kMigrationDisabled) { + return false; + } + + // If |is_test_mode| is set, assume we are in a browsertest and + // credit card upload should be enabled by default to fix flaky + // local card migration browsertests. + if (!is_test_mode && + !IsCreditCardUploadEnabled( + pref_service, sync_service, + personal_data_manager->GetAccountInfoForPaymentsServer().email, + personal_data_manager->GetSyncSigninState())) { + return false; + } + + if (!autofill::payments::HasGooglePaymentsAccount(personal_data_manager)) + return false; + + switch (personal_data_manager->GetSyncSigninState()) { + case AutofillSyncSigninState::kSignedOut: + case AutofillSyncSigninState::kSignedIn: + case AutofillSyncSigninState::kSyncPaused: + return false; + case AutofillSyncSigninState::kSignedInAndWalletSyncTransportEnabled: + return base::FeatureList::IsEnabled( + features::kAutofillEnableLocalCardMigrationForNonSyncUser); + case AutofillSyncSigninState::kSignedInAndSyncFeatureEnabled: + return true; + case AutofillSyncSigninState::kNumSyncStates: + break; + } + NOTREACHED(); + return false; } bool IsInAutofillSuggestionsDisabledExperiment() { @@ -110,14 +201,6 @@ bool IsInAutofillSuggestionsDisabledExperiment() { return group_name == "Disabled"; } -bool IsAutofillCreditCardAssistEnabled() { -#if !defined(OS_ANDROID) && !defined(OS_IOS) - return false; -#else - return base::FeatureList::IsEnabled(features::kAutofillCreditCardAssist); -#endif -} - features::LocalCardMigrationExperimentalFlag GetLocalCardMigrationExperimentalFlag() { if (!base::FeatureList::IsEnabled( @@ -182,30 +265,4 @@ bool ShouldUseActiveSignedInAccount() { features::kAutofillGetPaymentsIdentityFromSync); } -#if defined(OS_LINUX) || defined(OS_MACOSX) || defined(OS_WIN) -ForcedPopupLayoutState GetForcedPopupLayoutState() { - if (!base::FeatureList::IsEnabled( - autofill::kAutofillDropdownLayoutExperiment)) - return ForcedPopupLayoutState::kDefault; - - std::string param = base::GetFieldTrialParamValueByFeature( - kAutofillDropdownLayoutExperiment, kAutofillDropdownLayoutParameterName); - - if (param == kAutofillDropdownLayoutParameterLeadingIcon) { - return ForcedPopupLayoutState::kLeadingIcon; - } else if (param == kAutofillDropdownLayoutParameterTrailingIcon) { - return ForcedPopupLayoutState::kTrailingIcon; - } else if (param == - autofill::kAutofillDropdownLayoutParameterTwoLinesLeadingIcon) { - return ForcedPopupLayoutState::kTwoLinesLeadingIcon; - } else if (param.empty()) { - return ForcedPopupLayoutState::kDefault; - } - - // Unknown parameter value. - NOTREACHED(); - return ForcedPopupLayoutState::kDefault; -} -#endif // defined(OS_LINUX) || defined(OS_MACOSX) || defined(OS_WIN) - } // namespace autofill diff --git a/chromium/components/autofill/core/browser/autofill_experiments.h b/chromium/components/autofill/core/browser/autofill_experiments.h index d4247999259..c4a32743e09 100644 --- a/chromium/components/autofill/core/browser/autofill_experiments.h +++ b/chromium/components/autofill/core/browser/autofill_experiments.h @@ -9,34 +9,31 @@ #include "base/strings/string16.h" #include "build/build_config.h" +#include "components/autofill/core/browser/sync_utils.h" class PrefService; -namespace base { -struct Feature; -} - namespace syncer { class SyncService; } namespace autofill { -// Parameterized Features (grouped with parameter name and options) -#if defined(OS_LINUX) || defined(OS_MACOSX) || defined(OS_WIN) -extern const base::Feature kAutofillDropdownLayoutExperiment; -extern const char kAutofillDropdownLayoutParameterName[]; -extern const char kAutofillDropdownLayoutParameterLeadingIcon[]; -extern const char kAutofillDropdownLayoutParameterTrailingIcon[]; -extern const char kAutofillDropdownLayoutParameterTwoLinesLeadingIcon[]; -#endif // defined(OS_LINUX) || defined(OS_MACOSX) || defined(OS_WIN) +class PersonalDataManager; // Returns true if uploading credit cards to Wallet servers is enabled. This // requires the appropriate flags and user settings to be true and the user to // be a member of a supported domain. bool IsCreditCardUploadEnabled(const PrefService* pref_service, const syncer::SyncService* sync_service, - const std::string& user_email); + const std::string& user_email, + const AutofillSyncSigninState sync_state); + +// Returns true if autofill local card migration flow is enabled. +bool IsCreditCardMigrationEnabled(PersonalDataManager* personal_data_manager, + PrefService* pref_service, + syncer::SyncService* sync_service, + bool is_test_mode); // Returns true if autofill suggestions are disabled via experiment. The // disabled experiment isn't the same as disabling autofill completely since we @@ -44,9 +41,6 @@ bool IsCreditCardUploadEnabled(const PrefService* pref_service, // disables providing suggestions. bool IsInAutofillSuggestionsDisabledExperiment(); -// Returns whether the Autofill credit card assist infobar should be shown. -bool IsAutofillCreditCardAssistEnabled(); - // Returns whether locally saving card when credit card upload succeeds should // be disabled. bool IsAutofillNoLocalSaveOnUploadSuccessExperimentEnabled(); @@ -59,22 +53,6 @@ bool OfferStoreUnmaskedCards(bool is_off_the_record); // Returns whether the account of the active signed-in user should be used. bool ShouldUseActiveSignedInAccount(); -#if defined(OS_LINUX) || defined(OS_MACOSX) || defined(OS_WIN) -enum class ForcedPopupLayoutState { - kDefault, // No popup layout forced by experiment. - kLeadingIcon, // Experiment forces leading (left in LTR) icon layout. - kTrailingIcon, // Experiment forces trailing (right in LTR) icon layout. - kTwoLinesLeadingIcon, // Experiment forces leading (left in LTR) icon layout. - // with two lines display. -}; - -// Returns kDefault if no experimental behavior is enabled for -// kAutofillDropdownLayoutExperiment; returns kLeftIcon or kRightIcon -// if the experiment param matches kAutofillDropdownLayoutParameterLeadingIcon -// or kAutofillDropdownLayoutParameterTrailingIcon, respectively. -ForcedPopupLayoutState GetForcedPopupLayoutState(); -#endif // defined(OS_LINUX) || defined(OS_MACOSX) || defined(OS_WIN) - } // namespace autofill #endif // COMPONENTS_AUTOFILL_CORE_BROWSER_AUTOFILL_EXPERIMENTS_H_ diff --git a/chromium/components/autofill/core/browser/autofill_experiments_unittest.cc b/chromium/components/autofill/core/browser/autofill_experiments_unittest.cc index a23650fba78..b8ff2be732b 100644 --- a/chromium/components/autofill/core/browser/autofill_experiments_unittest.cc +++ b/chromium/components/autofill/core/browser/autofill_experiments_unittest.cc @@ -4,8 +4,11 @@ #include "components/autofill/core/browser/autofill_experiments.h" +#include "base/test/metrics/histogram_tester.h" #include "base/test/scoped_feature_list.h" +#include "components/autofill/core/browser/autofill_metrics.h" #include "components/autofill/core/common/autofill_features.h" +#include "components/autofill/core/common/autofill_payments_features.h" #include "components/autofill/core/common/autofill_prefs.h" #include "components/prefs/pref_registry_simple.h" #include "components/prefs/testing_pref_service.h" @@ -25,71 +28,147 @@ class AutofillExperimentsTest : public testing::Test { prefs::kAutofillWalletImportEnabled, true); } - bool IsCreditCardUploadEnabled() { - return IsCreditCardUploadEnabled("john.smith@gmail.com"); + bool IsCreditCardUploadEnabled(const AutofillSyncSigninState sync_state) { + return IsCreditCardUploadEnabled("john.smith@gmail.com", sync_state); } - bool IsCreditCardUploadEnabled(const std::string& user_email) { + bool IsCreditCardUploadEnabled(const std::string& user_email, + const AutofillSyncSigninState sync_state) { return autofill::IsCreditCardUploadEnabled(&pref_service_, &sync_service_, - user_email); + user_email, sync_state); } base::test::ScopedFeatureList scoped_feature_list_; TestingPrefServiceSimple pref_service_; syncer::TestSyncService sync_service_; + base::HistogramTester histogram_tester; }; -TEST_F(AutofillExperimentsTest, DenyUpload_FeatureEnabled) { +// Testing each scenario, followed by logging the metrics for various +// success and failure scenario of IsCreditCardUploadEnabled(). Every scenario +// should also be associated with logging of a metric so it's easy to analyze +// the results. +TEST_F(AutofillExperimentsTest, IsCardUploadEnabled_FeatureEnabled) { scoped_feature_list_.InitAndEnableFeature(features::kAutofillUpstream); - EXPECT_TRUE(IsCreditCardUploadEnabled()); + EXPECT_TRUE(IsCreditCardUploadEnabled( + AutofillSyncSigninState::kSignedInAndSyncFeatureEnabled)); + histogram_tester.ExpectUniqueSample( + "Autofill.CardUploadEnabled", + AutofillMetrics::CardUploadEnabledMetric::CARD_UPLOAD_ENABLED, 1); + histogram_tester.ExpectUniqueSample( + "Autofill.CardUploadEnabled.SignedInAndSyncFeatureEnabled", + AutofillMetrics::CardUploadEnabledMetric::CARD_UPLOAD_ENABLED, 1); } -TEST_F(AutofillExperimentsTest, DenyUpload_FeatureDisabled) { +TEST_F(AutofillExperimentsTest, IsCardUploadEnabled_FeatureDisabled) { scoped_feature_list_.InitAndDisableFeature(features::kAutofillUpstream); - EXPECT_FALSE(IsCreditCardUploadEnabled()); + EXPECT_FALSE(IsCreditCardUploadEnabled( + AutofillSyncSigninState::kSignedInAndSyncFeatureEnabled)); + histogram_tester.ExpectUniqueSample( + "Autofill.CardUploadEnabled", + AutofillMetrics::CardUploadEnabledMetric::AUTOFILL_UPSTREAM_DISABLED, 1); + histogram_tester.ExpectUniqueSample( + "Autofill.CardUploadEnabled.SignedInAndSyncFeatureEnabled", + AutofillMetrics::CardUploadEnabledMetric::AUTOFILL_UPSTREAM_DISABLED, 1); } -TEST_F(AutofillExperimentsTest, DenyUpload_AuthError) { +TEST_F(AutofillExperimentsTest, IsCardUploadEnabled_AuthError) { scoped_feature_list_.InitAndEnableFeature(features::kAutofillUpstream); sync_service_.SetAuthError( GoogleServiceAuthError(GoogleServiceAuthError::INVALID_GAIA_CREDENTIALS)); - EXPECT_FALSE(IsCreditCardUploadEnabled()); + EXPECT_FALSE(IsCreditCardUploadEnabled(AutofillSyncSigninState::kSyncPaused)); + histogram_tester.ExpectUniqueSample("Autofill.CardUploadEnabled", + AutofillMetrics::CardUploadEnabledMetric:: + SYNC_SERVICE_PERSISTENT_AUTH_ERROR, + 1); + histogram_tester.ExpectUniqueSample("Autofill.CardUploadEnabled.SyncPaused", + AutofillMetrics::CardUploadEnabledMetric:: + SYNC_SERVICE_PERSISTENT_AUTH_ERROR, + 1); } -TEST_F(AutofillExperimentsTest, DenyUpload_SyncDoesNotHaveWalletDataType) { +TEST_F(AutofillExperimentsTest, + IsCardUploadEnabled_SyncDoesNotHaveAutofillWalletDataActiveType) { scoped_feature_list_.InitAndEnableFeature(features::kAutofillUpstream); sync_service_.SetActiveDataTypes(syncer::ModelTypeSet()); - EXPECT_FALSE(IsCreditCardUploadEnabled()); + EXPECT_FALSE(IsCreditCardUploadEnabled( + AutofillSyncSigninState::kSignedInAndSyncFeatureEnabled)); + histogram_tester.ExpectUniqueSample( + "Autofill.CardUploadEnabled", + AutofillMetrics::CardUploadEnabledMetric:: + SYNC_SERVICE_MISSING_AUTOFILL_WALLET_DATA_ACTIVE_TYPE, + 1); + histogram_tester.ExpectUniqueSample( + "Autofill.CardUploadEnabled.SignedInAndSyncFeatureEnabled", + AutofillMetrics::CardUploadEnabledMetric:: + SYNC_SERVICE_MISSING_AUTOFILL_WALLET_DATA_ACTIVE_TYPE, + 1); } TEST_F(AutofillExperimentsTest, - DenyUpload_FullSyncDoesNotHaveAutofillProfileActiveDataType) { + IsCardUploadEnabled_SyncDoesNotHaveAutofillProfileActiveType) { scoped_feature_list_.InitAndEnableFeature(features::kAutofillUpstream); sync_service_.SetActiveDataTypes( syncer::ModelTypeSet(syncer::AUTOFILL_WALLET_DATA)); - EXPECT_FALSE(IsCreditCardUploadEnabled()); + EXPECT_FALSE(IsCreditCardUploadEnabled( + AutofillSyncSigninState::kSignedInAndSyncFeatureEnabled)); + histogram_tester.ExpectUniqueSample( + "Autofill.CardUploadEnabled", + AutofillMetrics::CardUploadEnabledMetric:: + SYNC_SERVICE_MISSING_AUTOFILL_PROFILE_ACTIVE_TYPE, + 1); + histogram_tester.ExpectUniqueSample( + "Autofill.CardUploadEnabled.SignedInAndSyncFeatureEnabled", + AutofillMetrics::CardUploadEnabledMetric:: + SYNC_SERVICE_MISSING_AUTOFILL_PROFILE_ACTIVE_TYPE, + 1); } TEST_F(AutofillExperimentsTest, - DenyUpload_SyncServiceUsingSecondaryPassphrase) { + IsCardUploadEnabled_SyncServiceUsingSecondaryPassphrase) { scoped_feature_list_.InitAndEnableFeature(features::kAutofillUpstream); sync_service_.SetIsUsingSecondaryPassphrase(true); - EXPECT_FALSE(IsCreditCardUploadEnabled()); + EXPECT_FALSE(IsCreditCardUploadEnabled( + AutofillSyncSigninState::kSignedInAndSyncFeatureEnabled)); + histogram_tester.ExpectUniqueSample( + "Autofill.CardUploadEnabled", + AutofillMetrics::CardUploadEnabledMetric::USING_SECONDARY_SYNC_PASSPHRASE, + 1); + histogram_tester.ExpectUniqueSample( + "Autofill.CardUploadEnabled.SignedInAndSyncFeatureEnabled", + AutofillMetrics::CardUploadEnabledMetric::USING_SECONDARY_SYNC_PASSPHRASE, + 1); } TEST_F(AutofillExperimentsTest, - DenyUpload_AutofillWalletImportEnabledPrefIsDisabled) { + IsCardUploadEnabled_AutofillWalletImportEnabledPrefIsDisabled) { scoped_feature_list_.InitAndEnableFeature(features::kAutofillUpstream); prefs::SetPaymentsIntegrationEnabled(&pref_service_, false); - EXPECT_FALSE(IsCreditCardUploadEnabled()); + EXPECT_FALSE(IsCreditCardUploadEnabled( + AutofillSyncSigninState::kSignedInAndSyncFeatureEnabled)); + histogram_tester.ExpectUniqueSample( + "Autofill.CardUploadEnabled", + AutofillMetrics::CardUploadEnabledMetric::PAYMENTS_INTEGRATION_DISABLED, + 1); + histogram_tester.ExpectUniqueSample( + "Autofill.CardUploadEnabled.SignedInAndSyncFeatureEnabled", + AutofillMetrics::CardUploadEnabledMetric::PAYMENTS_INTEGRATION_DISABLED, + 1); } -TEST_F(AutofillExperimentsTest, DenyUpload_EmptyUserEmail) { +TEST_F(AutofillExperimentsTest, IsCardUploadEnabled_EmptyUserEmail) { scoped_feature_list_.InitAndEnableFeature(features::kAutofillUpstream); - EXPECT_FALSE(IsCreditCardUploadEnabled("")); + EXPECT_FALSE(IsCreditCardUploadEnabled( + "", AutofillSyncSigninState::kSignedInAndSyncFeatureEnabled)); + histogram_tester.ExpectUniqueSample( + "Autofill.CardUploadEnabled", + AutofillMetrics::CardUploadEnabledMetric::EMAIL_EMPTY, 1); + histogram_tester.ExpectUniqueSample( + "Autofill.CardUploadEnabled.SignedInAndSyncFeatureEnabled", + AutofillMetrics::CardUploadEnabledMetric::EMAIL_EMPTY, 1); } -TEST_F(AutofillExperimentsTest, AllowUpload_TransportModeOnly) { +TEST_F(AutofillExperimentsTest, IsCardUploadEnabled_TransportModeOnly) { scoped_feature_list_.InitWithFeatures( /*enable_features=*/{features::kAutofillUpstream, features::kAutofillEnableAccountWalletStorage}, @@ -98,11 +177,19 @@ TEST_F(AutofillExperimentsTest, AllowUpload_TransportModeOnly) { // (if allowed). sync_service_.SetIsAuthenticatedAccountPrimary(false); - EXPECT_TRUE(IsCreditCardUploadEnabled("john.smith@gmail.com")); + EXPECT_TRUE(IsCreditCardUploadEnabled( + "john.smith@gmail.com", + AutofillSyncSigninState::kSignedInAndSyncFeatureEnabled)); + histogram_tester.ExpectUniqueSample( + "Autofill.CardUploadEnabled", + AutofillMetrics::CardUploadEnabledMetric::CARD_UPLOAD_ENABLED, 1); + histogram_tester.ExpectUniqueSample( + "Autofill.CardUploadEnabled.SignedInAndSyncFeatureEnabled", + AutofillMetrics::CardUploadEnabledMetric::CARD_UPLOAD_ENABLED, 1); } TEST_F(AutofillExperimentsTest, - DenyUpload_TransportSyncDoesNotHaveUploadEnabled) { + IsCardUploadEnabled_TransportSyncDoesNotHaveUploadEnabled) { scoped_feature_list_.InitWithFeatures( /*enable_features=*/{features::kAutofillUpstream, features::kAutofillEnableAccountWalletStorage}, @@ -112,11 +199,23 @@ TEST_F(AutofillExperimentsTest, // (if allowed). sync_service_.SetIsAuthenticatedAccountPrimary(false); - EXPECT_FALSE(IsCreditCardUploadEnabled()); + EXPECT_FALSE(IsCreditCardUploadEnabled( + AutofillSyncSigninState::kSignedInAndSyncFeatureEnabled)); + histogram_tester.ExpectUniqueSample( + "Autofill.CardUploadEnabled", + AutofillMetrics::CardUploadEnabledMetric:: + ACCOUNT_WALLET_STORAGE_UPLOAD_DISABLED, + 1); + histogram_tester.ExpectUniqueSample( + "Autofill.CardUploadEnabled.SignedInAndSyncFeatureEnabled", + AutofillMetrics::CardUploadEnabledMetric:: + ACCOUNT_WALLET_STORAGE_UPLOAD_DISABLED, + 1); } -TEST_F(AutofillExperimentsTest, - AllowUpload_TransportSyncDoesNotHaveAutofillProfileActiveDataType) { +TEST_F( + AutofillExperimentsTest, + IsCardUploadEnabled_TransportSyncDoesNotHaveAutofillProfileActiveDataType) { scoped_feature_list_.InitWithFeatures( /*enable_features=*/{features::kAutofillUpstream, features::kAutofillEnableAccountWalletStorage}, @@ -130,35 +229,85 @@ TEST_F(AutofillExperimentsTest, sync_service_.SetActiveDataTypes( syncer::ModelTypeSet(syncer::AUTOFILL_WALLET_DATA)); - EXPECT_TRUE(IsCreditCardUploadEnabled()); + EXPECT_TRUE(IsCreditCardUploadEnabled( + AutofillSyncSigninState::kSignedInAndSyncFeatureEnabled)); + histogram_tester.ExpectUniqueSample( + "Autofill.CardUploadEnabled", + AutofillMetrics::CardUploadEnabledMetric::CARD_UPLOAD_ENABLED, 1); + histogram_tester.ExpectUniqueSample( + "Autofill.CardUploadEnabled.SignedInAndSyncFeatureEnabled", + AutofillMetrics::CardUploadEnabledMetric::CARD_UPLOAD_ENABLED, 1); } -TEST_F(AutofillExperimentsTest, AllowUpload_UserEmailWithGoogleDomain) { +TEST_F(AutofillExperimentsTest, IsCardUploadEnabled_UserEmailWithGoogleDomain) { scoped_feature_list_.InitAndEnableFeature(features::kAutofillUpstream); - EXPECT_TRUE(IsCreditCardUploadEnabled("john.smith@gmail.com")); - EXPECT_TRUE(IsCreditCardUploadEnabled("googler@google.com")); - EXPECT_TRUE(IsCreditCardUploadEnabled("old.school@googlemail.com")); - EXPECT_TRUE(IsCreditCardUploadEnabled("code.committer@chromium.org")); + EXPECT_TRUE(IsCreditCardUploadEnabled( + "john.smith@gmail.com", + AutofillSyncSigninState::kSignedInAndSyncFeatureEnabled)); + EXPECT_TRUE(IsCreditCardUploadEnabled( + "googler@google.com", + AutofillSyncSigninState::kSignedInAndSyncFeatureEnabled)); + EXPECT_TRUE(IsCreditCardUploadEnabled( + "old.school@googlemail.com", + AutofillSyncSigninState::kSignedInAndSyncFeatureEnabled)); + EXPECT_TRUE(IsCreditCardUploadEnabled( + "code.committer@chromium.org", + AutofillSyncSigninState::kSignedInAndSyncFeatureEnabled)); + histogram_tester.ExpectUniqueSample( + "Autofill.CardUploadEnabled", + AutofillMetrics::CardUploadEnabledMetric::CARD_UPLOAD_ENABLED, 4); + histogram_tester.ExpectUniqueSample( + "Autofill.CardUploadEnabled.SignedInAndSyncFeatureEnabled", + AutofillMetrics::CardUploadEnabledMetric::CARD_UPLOAD_ENABLED, 4); } -TEST_F(AutofillExperimentsTest, DenyUpload_UserEmailWithNonGoogleDomain) { +TEST_F(AutofillExperimentsTest, + IsCardUploadEnabled_UserEmailWithNonGoogleDomain) { scoped_feature_list_.InitAndEnableFeature(features::kAutofillUpstream); - EXPECT_FALSE(IsCreditCardUploadEnabled("cool.user@hotmail.com")); - EXPECT_FALSE(IsCreditCardUploadEnabled("john.smith@johnsmith.com")); - EXPECT_FALSE(IsCreditCardUploadEnabled("fake.googler@google.net")); - EXPECT_FALSE(IsCreditCardUploadEnabled("fake.committer@chromium.com")); + EXPECT_FALSE(IsCreditCardUploadEnabled( + "cool.user@hotmail.com", + AutofillSyncSigninState::kSignedInAndSyncFeatureEnabled)); + EXPECT_FALSE(IsCreditCardUploadEnabled( + "john.smith@johnsmith.com", + AutofillSyncSigninState::kSignedInAndSyncFeatureEnabled)); + EXPECT_FALSE(IsCreditCardUploadEnabled( + "fake.googler@google.net", + AutofillSyncSigninState::kSignedInAndSyncFeatureEnabled)); + EXPECT_FALSE(IsCreditCardUploadEnabled( + "fake.committer@chromium.com", + AutofillSyncSigninState::kSignedInAndSyncFeatureEnabled)); + histogram_tester.ExpectUniqueSample( + "Autofill.CardUploadEnabled", + AutofillMetrics::CardUploadEnabledMetric::EMAIL_DOMAIN_NOT_SUPPORTED, 4); + histogram_tester.ExpectUniqueSample( + "Autofill.CardUploadEnabled.SignedInAndSyncFeatureEnabled", + AutofillMetrics::CardUploadEnabledMetric::EMAIL_DOMAIN_NOT_SUPPORTED, 4); } TEST_F(AutofillExperimentsTest, - AllowUpload_UserEmailWithNonGoogleDomainIfExperimentEnabled) { + IsCardUploadEnabled_UserEmailWithNonGoogleDomainIfExperimentEnabled) { scoped_feature_list_.InitWithFeatures( {features::kAutofillUpstream, features::kAutofillUpstreamAllowAllEmailDomains}, {}); - EXPECT_TRUE(IsCreditCardUploadEnabled("cool.user@hotmail.com")); - EXPECT_TRUE(IsCreditCardUploadEnabled("john.smith@johnsmith.com")); - EXPECT_TRUE(IsCreditCardUploadEnabled("fake.googler@google.net")); - EXPECT_TRUE(IsCreditCardUploadEnabled("fake.committer@chromium.com")); + EXPECT_TRUE(IsCreditCardUploadEnabled( + "cool.user@hotmail.com", + AutofillSyncSigninState::kSignedInAndSyncFeatureEnabled)); + EXPECT_TRUE(IsCreditCardUploadEnabled( + "john.smith@johnsmith.com", + AutofillSyncSigninState::kSignedInAndSyncFeatureEnabled)); + EXPECT_TRUE(IsCreditCardUploadEnabled( + "fake.googler@google.net", + AutofillSyncSigninState::kSignedInAndSyncFeatureEnabled)); + EXPECT_TRUE(IsCreditCardUploadEnabled( + "fake.committer@chromium.com", + AutofillSyncSigninState::kSignedInAndSyncFeatureEnabled)); + histogram_tester.ExpectUniqueSample( + "Autofill.CardUploadEnabled", + AutofillMetrics::CardUploadEnabledMetric::CARD_UPLOAD_ENABLED, 4); + histogram_tester.ExpectUniqueSample( + "Autofill.CardUploadEnabled.SignedInAndSyncFeatureEnabled", + AutofillMetrics::CardUploadEnabledMetric::CARD_UPLOAD_ENABLED, 4); } } // namespace autofill diff --git a/chromium/components/autofill/core/browser/autofill_external_delegate.cc b/chromium/components/autofill/core/browser/autofill_external_delegate.cc index 0024f2d615f..4b631efce6e 100644 --- a/chromium/components/autofill/core/browser/autofill_external_delegate.cc +++ b/chromium/components/autofill/core/browser/autofill_external_delegate.cc @@ -22,7 +22,7 @@ #include "components/autofill/core/browser/autofill_manager.h" #include "components/autofill/core/browser/autofill_metrics.h" #include "components/autofill/core/browser/popup_item_ids.h" -#include "components/autofill/core/common/autofill_features.h" +#include "components/autofill/core/common/autofill_payments_features.h" #include "components/autofill/core/common/autofill_util.h" #include "components/signin/core/browser/signin_metrics.h" #include "components/strings/grit/components_strings.h" @@ -207,6 +207,7 @@ void AutofillExternalDelegate::DidAcceptSuggestion(const base::string16& value, manager_->ShowAutofillSettings(popup_type_ == PopupType::kCreditCards); } else if (identifier == POPUP_ITEM_ID_CLEAR_FORM) { // User selected 'Clear form'. + AutofillMetrics::LogAutofillFormCleared(); driver_->RendererShouldClearFilledSection(); } else if (identifier == POPUP_ITEM_ID_PASSWORD_ENTRY || identifier == POPUP_ITEM_ID_USERNAME_ENTRY) { diff --git a/chromium/components/autofill/core/browser/autofill_external_delegate_unittest.cc b/chromium/components/autofill/core/browser/autofill_external_delegate_unittest.cc index 3e7d77e2a14..8974bfedfb1 100644 --- a/chromium/components/autofill/core/browser/autofill_external_delegate_unittest.cc +++ b/chromium/components/autofill/core/browser/autofill_external_delegate_unittest.cc @@ -25,6 +25,7 @@ #include "components/autofill/core/browser/test_autofill_client.h" #include "components/autofill/core/browser/test_autofill_driver.h" #include "components/autofill/core/common/autofill_features.h" +#include "components/autofill/core/common/autofill_payments_features.h" #include "components/autofill/core/common/autofill_switches.h" #include "components/autofill/core/common/form_data.h" #include "components/autofill/core/common/form_field_data.h" diff --git a/chromium/components/autofill/core/browser/autofill_handler.cc b/chromium/components/autofill/core/browser/autofill_handler.cc index a495cefa853..f0af93bb2fa 100644 --- a/chromium/components/autofill/core/browser/autofill_handler.cc +++ b/chromium/components/autofill/core/browser/autofill_handler.cc @@ -7,6 +7,7 @@ #include "base/containers/adapters.h" #include "components/autofill/core/browser/form_structure.h" #include "components/autofill/core/common/autofill_data_validation.h" +#include "components/autofill/core/common/autofill_payments_features.h" #include "components/autofill/core/common/signatures_util.h" #include "ui/gfx/geometry/rect_f.h" @@ -79,8 +80,29 @@ void AutofillHandler::OnFormsSeen(const std::vector<FormData>& forms, std::set<FormSignature> new_form_signatures; for (const FormData& form : forms) { const auto parse_form_start_time = TimeTicks::Now(); + FormStructure* cached_form_structure = nullptr; FormStructure* form_structure = nullptr; - if (!ParseForm(form, /*cached_form=*/nullptr, &form_structure)) + // Try to find the FormStructure that corresponds to |form| if the form + // contains credit card fields only. + // |cached_form_structure| may still be nullptr after this call. + if (base::FeatureList::IsEnabled(features::kAutofillImportDynamicForms)) { + ignore_result(FindCachedForm(form, &cached_form_structure)); + bool only_contains_credit_card_fields = true; + if (cached_form_structure) { + for (const FormType& form_type : + cached_form_structure->GetFormTypes()) { + if (form_type != CREDIT_CARD_FORM) { + only_contains_credit_card_fields = false; + break; + } + } + } + if (!only_contains_credit_card_fields) { + cached_form_structure = nullptr; + } + } + + if (!ParseForm(form, cached_form_structure, &form_structure)) continue; DCHECK(form_structure); new_form_signatures.insert(form_structure->form_signature()); @@ -261,8 +283,14 @@ bool AutofillHandler::ParseForm(const FormData& form, // We need to keep the server data if available. We need to use them while // determining the heuristics. form_structure->RetrieveFromCache(*cached_form, - /*apply_is_autofilled=*/true, + /*should_keep_cached_value=*/true, /*only_server_and_autofill_state=*/true); + if (observer_for_testing_) + observer_for_testing_->OnFormParsed(); + + if (form_structure.get()->value_from_dynamic_change_form()) { + value_from_dynamic_change_form_ = true; + } } form_structure->DetermineHeuristicTypes(); diff --git a/chromium/components/autofill/core/browser/autofill_handler.h b/chromium/components/autofill/core/browser/autofill_handler.h index 16f06b44368..b1744e84b57 100644 --- a/chromium/components/autofill/core/browser/autofill_handler.h +++ b/chromium/components/autofill/core/browser/autofill_handler.h @@ -37,6 +37,13 @@ class AutofillHandler { DISABLE_AUTOFILL_DOWNLOAD_MANAGER, }; + // An observer class used by browsertests that gets notified whenever + // particular actions occur. + class ObserverForTest { + public: + virtual void OnFormParsed() = 0; + }; + using FormStructureMap = std::map<FormSignature, std::unique_ptr<FormStructure>>; @@ -126,6 +133,10 @@ class AutofillHandler { // Returns the number of forms this Autofill handler is aware of. size_t NumFormsDetected() const { return form_structures_.size(); } + void SetEventObserverForTesting(ObserverForTest* observer) { + observer_for_testing_ = observer; + } + // Returns the present form structures seen by Autofill handler. const FormStructureMap& form_structures() const { return form_structures_; } @@ -190,6 +201,8 @@ class AutofillHandler { const FormStructure* cached_form, FormStructure** parsed_form_structure); + bool value_from_dynamic_change_form_ = false; + AutofillDriver* driver() { return driver_; } FormStructureMap* mutable_form_structures() { return &form_structures_; } @@ -202,6 +215,9 @@ class AutofillHandler { // Our copy of the form data. FormStructureMap form_structures_; + // Will be not null only for |SaveCardBubbleViewsFullFormBrowserTest|. + ObserverForTest* observer_for_testing_ = nullptr; + DISALLOW_COPY_AND_ASSIGN(AutofillHandler); }; diff --git a/chromium/components/autofill/core/browser/autofill_manager.cc b/chromium/components/autofill/core/browser/autofill_manager.cc index dcc247b97d0..94a84dc98ea 100644 --- a/chromium/components/autofill/core/browser/autofill_manager.cc +++ b/chromium/components/autofill/core/browser/autofill_manager.cc @@ -65,6 +65,7 @@ #include "components/autofill/core/common/autofill_constants.h" #include "components/autofill/core/common/autofill_data_validation.h" #include "components/autofill/core/common/autofill_features.h" +#include "components/autofill/core/common/autofill_payments_features.h" #include "components/autofill/core/common/autofill_prefs.h" #include "components/autofill/core/common/autofill_switches.h" #include "components/autofill/core/common/autofill_util.h" @@ -736,8 +737,7 @@ void AutofillManager::FillOrPreviewProfileForm( profile, *form_structure, *autofill_field, sync_state_); // Set up the information needed for an eventual refill of this form. - if (base::FeatureList::IsEnabled(features::kAutofillDynamicForms) && - !form_structure->GetIdentifierForRefill().empty()) { + if (!form_structure->GetIdentifierForRefill().empty()) { auto& entry = filling_contexts_map_[form_structure->GetIdentifierForRefill()]; auto filling_context = std::make_unique<FillingContext>(); @@ -1402,7 +1402,6 @@ void AutofillManager::FillOrPreviewDataModelForm( if (itr != filling_contexts_map_.end()) filling_context = itr->second.get(); bool could_attempt_refill = - base::FeatureList::IsEnabled(features::kAutofillDynamicForms) && filling_context != nullptr && !filling_context->attempted_refill && !is_refill && !is_credit_card; @@ -1512,8 +1511,12 @@ std::unique_ptr<FormStructure> AutofillManager::ValidateSubmittedForm( auto submitted_form = std::make_unique<FormStructure>(form); submitted_form->RetrieveFromCache(*cached_submitted_form, - /*apply_is_autofilled=*/false, + /*should_keep_cached_value=*/false, /*only_server_and_autofill_state=*/false); + if (value_from_dynamic_change_form_) { + submitted_form->set_value_from_dynamic_change_form(true); + } + return submitted_form; } @@ -2014,9 +2017,6 @@ void AutofillManager::FillFieldWithValue(AutofillField* autofill_field, } bool AutofillManager::ShouldTriggerRefill(const FormStructure& form_structure) { - if (!base::FeatureList::IsEnabled(features::kAutofillDynamicForms)) - return false; - // Should not refill if a form with the same name has not been filled before. auto itr = filling_contexts_map_.find(form_structure.GetIdentifierForRefill()); diff --git a/chromium/components/autofill/core/browser/autofill_manager.h b/chromium/components/autofill/core/browser/autofill_manager.h index e9871cd2c89..c6aee10ea77 100644 --- a/chromium/components/autofill/core/browser/autofill_manager.h +++ b/chromium/components/autofill/core/browser/autofill_manager.h @@ -26,11 +26,11 @@ #include "components/autofill/core/browser/autofill_driver.h" #include "components/autofill/core/browser/autofill_handler.h" #include "components/autofill/core/browser/autofill_metrics.h" -#include "components/autofill/core/browser/card_unmask_delegate.h" #include "components/autofill/core/browser/field_filler.h" #include "components/autofill/core/browser/form_types.h" #include "components/autofill/core/browser/metrics/address_form_event_logger.h" #include "components/autofill/core/browser/metrics/credit_card_form_event_logger.h" +#include "components/autofill/core/browser/payments/card_unmask_delegate.h" #include "components/autofill/core/browser/payments/full_card_request.h" #include "components/autofill/core/browser/personal_data_manager.h" #include "components/autofill/core/browser/popup_types.h" diff --git a/chromium/components/autofill/core/browser/autofill_manager_unittest.cc b/chromium/components/autofill/core/browser/autofill_manager_unittest.cc index 20c8ed86951..b5488cb9d16 100644 --- a/chromium/components/autofill/core/browser/autofill_manager_unittest.cc +++ b/chromium/components/autofill/core/browser/autofill_manager_unittest.cc @@ -36,6 +36,7 @@ #include "components/autofill/core/browser/credit_card.h" #include "components/autofill/core/browser/metrics/form_events.h" #include "components/autofill/core/browser/mock_autocomplete_history_manager.h" +#include "components/autofill/core/browser/payments/test_credit_card_save_manager.h" #include "components/autofill/core/browser/payments/test_payments_client.h" #include "components/autofill/core/browser/personal_data_manager.h" #include "components/autofill/core/browser/popup_item_ids.h" @@ -46,7 +47,6 @@ #include "components/autofill/core/browser/test_autofill_driver.h" #include "components/autofill/core/browser/test_autofill_external_delegate.h" #include "components/autofill/core/browser/test_autofill_manager.h" -#include "components/autofill/core/browser/test_credit_card_save_manager.h" #include "components/autofill/core/browser/test_form_data_importer.h" #include "components/autofill/core/browser/test_form_structure.h" #include "components/autofill/core/browser/test_personal_data_manager.h" @@ -54,6 +54,7 @@ #include "components/autofill/core/browser/webdata/autofill_webdata_service.h" #include "components/autofill/core/common/autofill_clock.h" #include "components/autofill/core/common/autofill_features.h" +#include "components/autofill/core/common/autofill_payments_features.h" #include "components/autofill/core/common/autofill_prefs.h" #include "components/autofill/core/common/autofill_switches.h" #include "components/autofill/core/common/autofill_util.h" @@ -175,10 +176,10 @@ void ExpectFilledForm(int page_id, EXPECT_EQ(expected_page_id, page_id); EXPECT_EQ(ASCIIToUTF16("MyForm"), filled_form.name); if (has_credit_card_fields) { - EXPECT_EQ(GURL("https://myform.com/form.html"), filled_form.origin); + EXPECT_EQ(GURL("https://myform.com/form.html"), filled_form.url); EXPECT_EQ(GURL("https://myform.com/submit.html"), filled_form.action); } else { - EXPECT_EQ(GURL("http://myform.com/form.html"), filled_form.origin); + EXPECT_EQ(GURL("http://myform.com/form.html"), filled_form.url); EXPECT_EQ(GURL("http://myform.com/submit.html"), filled_form.action); } @@ -314,8 +315,7 @@ class AutofillManagerTest : public testing::Test { payments::TestPaymentsClient* payments_client = new payments::TestPaymentsClient( autofill_driver_->GetURLLoaderFactory(), - autofill_client_.GetPrefs(), autofill_client_.GetIdentityManager(), - &personal_data_); + autofill_client_.GetIdentityManager(), &personal_data_); autofill_client_.set_test_payments_client( std::unique_ptr<payments::TestPaymentsClient>(payments_client)); TestCreditCardSaveManager* credit_card_save_manager = @@ -485,10 +485,10 @@ class AutofillManagerTest : public testing::Test { bool use_month_type) { form->name = ASCIIToUTF16("MyForm"); if (is_https) { - form->origin = GURL("https://myform.com/form.html"); + form->url = GURL("https://myform.com/form.html"); form->action = GURL("https://myform.com/submit.html"); } else { - form->origin = GURL("http://myform.com/form.html"); + form->url = GURL("http://myform.com/form.html"); form->action = GURL("http://myform.com/submit.html"); } @@ -687,7 +687,7 @@ TEST_F(AutofillManagerTest, OnFormsSeen_DifferentFormStructures) { // Different form structure. FormData form2; form2.name = ASCIIToUTF16("MyForm"); - form2.origin = GURL("https://myform.com/form.html"); + form2.url = GURL("https://myform.com/form.html"); form2.action = GURL("https://myform.com/submit.html"); FormFieldData field; test::CreateTestFormField("First Name", "firstname", "", "text", &field); @@ -717,7 +717,7 @@ TEST_F(AutofillManagerTest, OnFormsSeen_SendAutofillTypePredictionsToRenderer) { FormFieldData field; test::CreateTestFormField("Querty", "qwerty", "", "text", &field); form2.name = ASCIIToUTF16("NonQueryable"); - form2.origin = form1.origin; + form2.url = form1.url; form2.action = GURL("https://myform.com/submit.html"); form2.fields.push_back(field); @@ -736,7 +736,7 @@ TEST_F(AutofillManagerTest, GetProfileSuggestions_UnrecognizedAttribute) { // Set up our form data. FormData form; form.name = ASCIIToUTF16("MyForm"); - form.origin = GURL("https://myform.com/form.html"); + form.url = GURL("https://myform.com/form.html"); form.action = GURL("https://myform.com/submit.html"); FormFieldData field; // Set a valid autocomplete attribute for the first name. @@ -782,7 +782,7 @@ TEST_F(AutofillManagerTest, // Set up our form data. FormData form; form.name = ASCIIToUTF16("MyForm"); - form.origin = GURL("https://myform.com/form.html"); + form.url = GURL("https://myform.com/form.html"); form.action = GURL("https://myform.com/submit.html"); FormFieldData field; test::CreateTestFormField("First Name", "firstname", "", "text", &field); @@ -816,7 +816,7 @@ TEST_F(AutofillManagerTest, // Set up our form data. FormData form; form.name = ASCIIToUTF16("MyForm"); - form.origin = GURL("https://myform.com/form.html"); + form.url = GURL("https://myform.com/form.html"); form.action = GURL("https://myform.com/submit.html"); FormFieldData field; test::CreateTestFormField("First Name", "firstname", "", "text", &field); @@ -851,7 +851,7 @@ TEST_F(AutofillManagerTest, // Set up our form data. FormData form; form.name = ASCIIToUTF16("MyForm"); - form.origin = GURL("https://myform.com/form.html"); + form.url = GURL("https://myform.com/form.html"); form.action = GURL("https://myform.com/submit.html"); FormFieldData field; test::CreateTestFormField("First Name", "firstname", "", "text", &field); @@ -889,7 +889,7 @@ TEST_F(AutofillManagerTest, // Set up our form data. FormData form; form.name = ASCIIToUTF16("MyForm"); - form.origin = GURL("https://myform.com/form.html"); + form.url = GURL("https://myform.com/form.html"); form.action = GURL("https://myform.com/submit.html"); FormFieldData field; test::CreateTestFormField("First Name", "firstname", "", "text", &field); @@ -924,7 +924,7 @@ TEST_F(AutofillManagerTest, // Set up our form data. FormData form; form.name = ASCIIToUTF16("MyForm"); - form.origin = GURL("https://myform.com/form.html"); + form.url = GURL("https://myform.com/form.html"); form.action = GURL("https://myform.com/submit.html"); FormFieldData field; test::CreateTestFormField("First Name", "firstname", "", "text", &field); @@ -1075,7 +1075,7 @@ TEST_F(AutofillManagerTest, GetProfileSuggestions_UnknownFields) { // Set up our form data. FormData form; form.name = ASCIIToUTF16("MyForm"); - form.origin = GURL("http://myform.com/form.html"); + form.url = GURL("http://myform.com/form.html"); form.action = GURL("http://myform.com/submit.html"); FormFieldData field; @@ -1716,7 +1716,7 @@ TEST_F(AutofillManagerTest, GetProfileSuggestions_ForPhonePrefixOrSuffix) { // Set up our form data. FormData form; form.name = ASCIIToUTF16("MyForm"); - form.origin = GURL("http://myform.com/form.html"); + form.url = GURL("http://myform.com/form.html"); form.action = GURL("http://myform.com/submit.html"); struct { @@ -2039,7 +2039,7 @@ TEST_F(AutofillManagerTest, FillCreditCardForm_SplitName) { // Set up our form data. FormData form; form.name = ASCIIToUTF16("MyForm"); - form.origin = GURL("https://myform.com/form.html"); + form.url = GURL("https://myform.com/form.html"); form.action = GURL("https://myform.com/submit.html"); FormFieldData field; @@ -2109,7 +2109,7 @@ TEST_F(AutofillManagerTest, FillAddressAndCreditCardForm) { TEST_F(AutofillManagerTest, FillAddressForm_UnrecognizedAttribute) { FormData address_form; address_form.name = ASCIIToUTF16("MyForm"); - address_form.origin = GURL("https://myform.com/form.html"); + address_form.url = GURL("https://myform.com/form.html"); address_form.action = GURL("https://myform.com/submit.html"); FormFieldData field; // Set a valid autocomplete attribute for the first name. @@ -2155,7 +2155,7 @@ TEST_F(AutofillManagerTest, FillAddressForm_AutocompleteOffRespected) { FormData address_form; address_form.name = ASCIIToUTF16("MyForm"); - address_form.origin = GURL("https://myform.com/form.html"); + address_form.url = GURL("https://myform.com/form.html"); address_form.action = GURL("https://myform.com/submit.html"); FormFieldData field; test::CreateTestFormField("First name", "firstname", "", "text", &field); @@ -2213,7 +2213,7 @@ TEST_F(AutofillManagerTest, FillAddressForm_AutocompleteOffRespected) { TEST_F(AutofillManagerTest, FillAddressForm_AutocompleteOffNotRespected) { FormData address_form; address_form.name = ASCIIToUTF16("MyForm"); - address_form.origin = GURL("https://myform.com/form.html"); + address_form.url = GURL("https://myform.com/form.html"); address_form.action = GURL("https://myform.com/submit.html"); FormFieldData field; test::CreateTestFormField("First name", "firstname", "", "text", &field); @@ -2249,11 +2249,62 @@ TEST_F(AutofillManagerTest, FillAddressForm_AutocompleteOffNotRespected) { "text", response_data.fields[3]); } +// Test that if a company is of a format of a birthyear and the relevant feature +// is enabled, we would not fill it. +TEST_F(AutofillManagerTest, FillAddressForm_CompanyBirthyear) { + base::test::ScopedFeatureList scoped_feature_list; + scoped_feature_list.InitAndEnableFeature( + features::kAutofillRejectCompanyBirthyear); + + // Set up our form data. + FormData address_form; + address_form.name = ASCIIToUTF16("MyForm"); + address_form.url = GURL("https://myform.com/form.html"); + address_form.action = GURL("https://myform.com/submit.html"); + + FormFieldData field; + test::CreateTestFormField("First name", "firstname", "", "text", &field); + address_form.fields.push_back(field); + test::CreateTestFormField("Middle name", "middle", "", "text", &field); + address_form.fields.push_back(field); + test::CreateTestFormField("Last name", "lastname", "", "text", &field); + address_form.fields.push_back(field); + test::CreateTestFormField("Company", "company", "", "text", &field); + address_form.fields.push_back(field); + + std::vector<FormData> address_forms(1, address_form); + FormsSeen(address_forms); + + AutofillProfile profile; + const char guid[] = "00000000-0000-0000-0000-000000000123"; + test::SetProfileInfo(&profile, "Elvis", "Aaron", "Presley", + "theking@gmail.com", "1987", "3734 Elvis Presley Blvd.", + "Apt. 10", "Memphis", "Tennessee", "38116", "US", + "12345678901"); + profile.set_guid(guid); + personal_data_.AddProfile(profile); + + int response_page_id = 0; + FormData response_data; + FillAutofillFormDataAndSaveResults( + kDefaultPageID, address_form, *address_form.fields.begin(), + MakeFrontendID(std::string(), guid), &response_page_id, &response_data); + + // All the fields should be filled except the company. + ExpectFilledField("First name", "firstname", "Elvis", "text", + response_data.fields[0]); + ExpectFilledField("Middle name", "middle", "Aaron", "text", + response_data.fields[1]); + ExpectFilledField("Last name", "lastname", "Presley", "text", + response_data.fields[2]); + ExpectFilledField("Company", "company", "", "text", response_data.fields[3]); +} + // Test that a field with a value equal to it's placeholder attribute is filled. TEST_F(AutofillManagerTest, FillAddressForm_PlaceholderEqualsValue) { FormData address_form; address_form.name = ASCIIToUTF16("MyForm"); - address_form.origin = GURL("https://myform.com/form.html"); + address_form.url = GURL("https://myform.com/form.html"); address_form.action = GURL("https://myform.com/submit.html"); FormFieldData field; // Set the same placeholder and value for each field. @@ -2295,7 +2346,7 @@ TEST_F(AutofillManagerTest, FillCreditCardForm_UnrecognizedAttribute) { // Set up the form data. FormData form; form.name = ASCIIToUTF16("MyForm"); - form.origin = GURL("https://myform.com/form.html"); + form.url = GURL("https://myform.com/form.html"); form.action = GURL("https://myform.com/submit.html"); FormFieldData field; @@ -2372,7 +2423,7 @@ TEST_F(AutofillManagerTest, FillCreditCardForm_ExpiredCard) { // Set up the form data. FormData form; form.name = ASCIIToUTF16("MyForm"); - form.origin = GURL("https://myform.com/form.html"); + form.url = GURL("https://myform.com/form.html"); form.action = GURL("https://myform.com/submit.html"); // Create a credit card form. @@ -2426,7 +2477,7 @@ TEST_F(AutofillManagerTest, FillFormWithNonFocusableFields) { // Create a form with both focusable and non-focusable fields. FormData form; form.name = ASCIIToUTF16("MyForm"); - form.origin = GURL("https://myform.com/form.html"); + form.url = GURL("https://myform.com/form.html"); form.action = GURL("https://myform.com/submit.html"); FormFieldData field; @@ -2553,7 +2604,7 @@ TEST_F(AutofillManagerTest, FillFormWithAuthorSpecifiedSections) { // The billing section includes both address and credit card fields. FormData form; form.name = ASCIIToUTF16("MyForm"); - form.origin = GURL("https://myform.com/form.html"); + form.url = GURL("https://myform.com/form.html"); form.action = GURL("https://myform.com/submit.html"); FormFieldData field; @@ -2616,7 +2667,7 @@ TEST_F(AutofillManagerTest, FillFormWithAuthorSpecifiedSections) { SCOPED_TRACE("Unnamed section"); EXPECT_EQ(kDefaultPageID, response_page_id); EXPECT_EQ(ASCIIToUTF16("MyForm"), response_data.name); - EXPECT_EQ(GURL("https://myform.com/form.html"), response_data.origin); + EXPECT_EQ(GURL("https://myform.com/form.html"), response_data.url); EXPECT_EQ(GURL("https://myform.com/submit.html"), response_data.action); ASSERT_EQ(11U, response_data.fields.size()); @@ -2647,7 +2698,7 @@ TEST_F(AutofillManagerTest, FillFormWithAuthorSpecifiedSections) { SCOPED_TRACE("Billing address"); EXPECT_EQ(kPageID2, response_page_id); EXPECT_EQ(ASCIIToUTF16("MyForm"), response_data.name); - EXPECT_EQ(GURL("https://myform.com/form.html"), response_data.origin); + EXPECT_EQ(GURL("https://myform.com/form.html"), response_data.url); EXPECT_EQ(GURL("https://myform.com/submit.html"), response_data.action); ASSERT_EQ(11U, response_data.fields.size()); @@ -2677,7 +2728,7 @@ TEST_F(AutofillManagerTest, FillFormWithAuthorSpecifiedSections) { SCOPED_TRACE("Credit card"); EXPECT_EQ(kPageID3, response_page_id); EXPECT_EQ(ASCIIToUTF16("MyForm"), response_data.name); - EXPECT_EQ(GURL("https://myform.com/form.html"), response_data.origin); + EXPECT_EQ(GURL("https://myform.com/form.html"), response_data.url); EXPECT_EQ(GURL("https://myform.com/submit.html"), response_data.action); ASSERT_EQ(11U, response_data.fields.size()); @@ -2839,7 +2890,7 @@ TEST_F(AutofillManagerTest, FillPhoneNumber) { // parts. In the other form, rely on the autocomplete type attribute. FormData form_with_us_number_max_length; form_with_us_number_max_length.name = ASCIIToUTF16("MyMaxlengthPhoneForm"); - form_with_us_number_max_length.origin = + form_with_us_number_max_length.url = GURL("http://myform.com/phone_form.html"); form_with_us_number_max_length.action = GURL("http://myform.com/phone_submit.html"); @@ -2968,7 +3019,7 @@ TEST_F(AutofillManagerTest, FillFirstPhoneNumber_ComponentizedNumbers) { // Verify only the first complete number is filled when there are multiple // componentized number fields. FormData form_with_multiple_componentized_phone_fields; - form_with_multiple_componentized_phone_fields.origin = + form_with_multiple_componentized_phone_fields.url = GURL("http://www.foo.com/"); FormFieldData field; @@ -3035,7 +3086,7 @@ TEST_F(AutofillManagerTest, FillFirstPhoneNumber_WholeNumbers) { std::string guid(work_profile->guid()); FormData form_with_multiple_whole_number_fields; - form_with_multiple_whole_number_fields.origin = GURL("http://www.foo.com/"); + form_with_multiple_whole_number_fields.url = GURL("http://www.foo.com/"); FormFieldData field; // Default is zero, have to set to a number autofill can process. @@ -3089,7 +3140,7 @@ TEST_F(AutofillManagerTest, FillFirstPhoneNumber_FillPartsOnceOnly) { // Verify only the first complete number is filled when there are multiple // componentized number fields. FormData form_with_multiple_componentized_phone_fields; - form_with_multiple_componentized_phone_fields.origin = + form_with_multiple_componentized_phone_fields.url = GURL("http://www.foo.com/"); FormFieldData field; @@ -3162,7 +3213,7 @@ TEST_F(AutofillManagerTest, std::string guid(work_profile->guid()); FormData form_with_misclassified_extension; - form_with_misclassified_extension.origin = GURL("http://www.foo.com/"); + form_with_misclassified_extension.url = GURL("http://www.foo.com/"); FormFieldData field; // Default is zero, have to set to a number autofill can process. @@ -3223,7 +3274,7 @@ TEST_F(AutofillManagerTest, FillFirstPhoneNumber_BestEfforFilling) { std::string guid(work_profile->guid()); FormData form_with_no_complete_number; - form_with_no_complete_number.origin = GURL("http://www.foo.com/"); + form_with_no_complete_number.url = GURL("http://www.foo.com/"); FormFieldData field; // Default is zero, have to set to a number autofill can process. @@ -3281,7 +3332,7 @@ TEST_F(AutofillManagerTest, FillFirstPhoneNumber_FocusOnSecondPhoneNumber) { std::string guid(work_profile->guid()); FormData form_with_multiple_whole_number_fields; - form_with_multiple_whole_number_fields.origin = GURL("http://www.foo.com/"); + form_with_multiple_whole_number_fields.url = GURL("http://www.foo.com/"); FormFieldData field; // Default is zero, have to set to a number autofill can process. @@ -3336,7 +3387,7 @@ TEST_F(AutofillManagerTest, FillFirstPhoneNumber_HiddenFieldShouldNotCount) { std::string guid(work_profile->guid()); FormData form_with_multiple_whole_number_fields; - form_with_multiple_whole_number_fields.origin = GURL("http://www.foo.com/"); + form_with_multiple_whole_number_fields.url = GURL("http://www.foo.com/"); FormFieldData field; // Default is zero, have to set to a number autofill can process. @@ -3386,7 +3437,7 @@ TEST_F(AutofillManagerTest, FillFirstPhoneNumber_HiddenFieldShouldNotCount) { TEST_F(AutofillManagerTest, FormWithHiddenOrPresentationalSelects) { FormData form; form.name = ASCIIToUTF16("MyForm"); - form.origin = GURL("http://myform.com/form.html"); + form.url = GURL("http://myform.com/form.html"); form.action = GURL("http://myform.com/submit.html"); FormFieldData field; @@ -3462,7 +3513,7 @@ TEST_F(AutofillManagerTest, std::string guid(work_profile->guid()); FormData form_with_multiple_sections; - form_with_multiple_sections.origin = GURL("http://www.foo.com/"); + form_with_multiple_sections.url = GURL("http://www.foo.com/"); FormFieldData field; // Default is zero, have to set to a number autofill can process. @@ -3607,7 +3658,7 @@ TEST_F(AutofillManagerTest, FormChangesAddField) { TEST_F(AutofillManagerTest, FormChangesVisibilityOfFields) { // Set up our form data. FormData form; - form.origin = GURL("http://www.foo.com/"); + form.url = GURL("http://www.foo.com/"); FormFieldData field; @@ -3973,7 +4024,7 @@ TEST_F(AutofillManagerTest, OnLoadedServerPredictions) { // Similarly, a second form. FormData form2; form2.name = ASCIIToUTF16("MyForm"); - form2.origin = GURL("http://myform.com/form.html"); + form2.url = GURL("http://myform.com/form.html"); form2.action = GURL("http://myform.com/submit.html"); FormFieldData field; @@ -4047,7 +4098,7 @@ TEST_F(AutofillManagerTest, OnLoadedServerPredictionsFromApi) { // First form on the page. FormData form; form.name = ASCIIToUTF16("MyForm"); - form.origin = GURL("http://myform.com/form.html"); + form.url = GURL("http://myform.com/form.html"); form.action = GURL("http://myform.com/submit.html"); FormFieldData field; test::CreateTestFormField(/*label=*/"City", /*name=*/"city", @@ -4070,7 +4121,7 @@ TEST_F(AutofillManagerTest, OnLoadedServerPredictionsFromApi) { // Second form on the page. FormData form2; form2.name = ASCIIToUTF16("MyForm2"); - form2.origin = GURL("http://myform.com/form.html"); + form2.url = GURL("http://myform.com/form.html"); form2.action = GURL("http://myform.com/submit.html"); test::CreateTestFormField("Last Name", "lastname", "", "text", &field); form2.fields.push_back(field); @@ -4184,7 +4235,7 @@ TEST_F(AutofillManagerTest, OnLoadedServerPredictions_ResetManager) { TEST_F(AutofillManagerTest, DetermineHeuristicsWithOverallPrediction) { // Set up our form data. FormData form; - form.origin = GURL("https://www.myform.com"); + form.url = GURL("https://www.myform.com"); FormFieldData field; test::CreateTestFormField("First Name", "firstname", "", "text", &field); form.fields.push_back(field); @@ -4578,7 +4629,7 @@ TEST_P(ProfileMatchingTypesTest, DeterminePossibleFieldTypesForUpload) { FormData form; form.name = ASCIIToUTF16("MyForm"); - form.origin = GURL("http://myform.com/form.html"); + form.url = GURL("http://myform.com/form.html"); form.action = GURL("http://myform.com/submit.html"); FormFieldData field; @@ -4626,7 +4677,7 @@ INSTANTIATE_TEST_SUITE_P( TEST_F(AutofillManagerTest, DeterminePossibleFieldTypesForUpload_IsTriggered) { FormData form; form.name = ASCIIToUTF16("MyForm"); - form.origin = GURL("http://myform.com/form.html"); + form.url = GURL("http://myform.com/form.html"); form.action = GURL("http://myform.com/submit.html"); std::vector<ServerFieldTypeSet> expected_types; @@ -4728,7 +4779,7 @@ TEST_F(AutofillManagerTest, DeterminePossibleFieldTypesWithMultipleValidities) { for (const std::vector<TestFieldData>& test_fields : test_cases) { FormData form; form.name = ASCIIToUTF16("MyForm"); - form.origin = GURL("http://myform.com/form.html"); + form.url = GURL("http://myform.com/form.html"); form.action = GURL("http://myform.com/submit.html"); // Create the form fields specified in the test case. @@ -4917,7 +4968,7 @@ TEST_F(AutofillManagerTest, DisambiguateUploadTypes) { for (const std::vector<TestFieldData>& test_fields : test_cases) { FormData form; form.name = ASCIIToUTF16("MyForm"); - form.origin = GURL("http://myform.com/form.html"); + form.url = GURL("http://myform.com/form.html"); form.action = GURL("http://myform.com/submit.html"); // Create the form fields specified in the test case. @@ -4999,7 +5050,7 @@ TEST_F(AutofillManagerTest, OnTextFieldDidChangeAndUnfocus_Upload) { // Set up our form data (it's already filled out with user data). FormData form; form.name = ASCIIToUTF16("MyForm"); - form.origin = GURL("http://myform.com/form.html"); + form.url = GURL("http://myform.com/form.html"); form.action = GURL("http://myform.com/submit.html"); std::vector<ServerFieldTypeSet> expected_types; @@ -5049,7 +5100,7 @@ TEST_F(AutofillManagerTest, OnTextFieldDidChangeAndNavigation_Upload) { // Set up our form data (it's already filled out with user data). FormData form; form.name = ASCIIToUTF16("MyForm"); - form.origin = GURL("http://myform.com/form.html"); + form.url = GURL("http://myform.com/form.html"); form.action = GURL("http://myform.com/submit.html"); std::vector<ServerFieldTypeSet> expected_types; @@ -5099,7 +5150,7 @@ TEST_F(AutofillManagerTest, OnDidFillAutofillFormDataAndUnfocus_Upload) { // Set up our form data (empty). FormData form; form.name = ASCIIToUTF16("MyForm"); - form.origin = GURL("http://myform.com/form.html"); + form.url = GURL("http://myform.com/form.html"); form.action = GURL("http://myform.com/submit.html"); std::vector<ServerFieldTypeSet> expected_types; @@ -5148,7 +5199,7 @@ TEST_F(AutofillManagerTest, GetCreditCardSuggestions_UnrecognizedAttribute) { // Set up the form data. FormData form; form.name = ASCIIToUTF16("MyForm"); - form.origin = GURL("https://myform.com/form.html"); + form.url = GURL("https://myform.com/form.html"); form.action = GURL("https://myform.com/submit.html"); FormFieldData field; @@ -5186,7 +5237,7 @@ TEST_F(AutofillManagerTest, // Set up our form data with credit card number split across fields. FormData form; form.name = ASCIIToUTF16("MyForm"); - form.origin = GURL("https://myform.com/form.html"); + form.url = GURL("https://myform.com/form.html"); form.action = GURL("https://myform.com/submit.html"); FormFieldData name_field; @@ -5245,7 +5296,7 @@ TEST_F(AutofillManagerTest, DontSaveCvcInAutocompleteHistory) { FormData form; form.name = ASCIIToUTF16("MyForm"); - form.origin = GURL("http://myform.com/form.html"); + form.url = GURL("http://myform.com/form.html"); form.action = GURL("http://myform.com/submit.html"); struct { @@ -5617,9 +5668,9 @@ TEST_F(AutofillManagerTest, // Set up our form data. FormData form; CreateTestCreditCardFormData(&form, false, false); - form.origin = GURL("http://myform.com/form.html"); + form.url = GURL("http://myform.com/form.html"); form.action = GURL("https://myform.com/submit.html"); - autofill_client_.set_form_origin(form.origin); + autofill_client_.set_form_origin(form.url); std::vector<FormData> forms(1, form); FormsSeen(forms); @@ -5648,7 +5699,7 @@ TEST_F(AutofillManagerTest, // Set up our form data. FormData form; CreateTestCreditCardFormData(&form, false, false); - form.origin = GURL("https://myform.com/form.html"); + form.url = GURL("https://myform.com/form.html"); form.action = GURL("http://myform.com/submit.html"); std::vector<FormData> forms(1, form); FormsSeen(forms); @@ -5738,7 +5789,7 @@ TEST_F(AutofillManagerTest, ShouldUploadForm) { // scenarios. FormData form; form.name = ASCIIToUTF16("TestForm"); - form.origin = GURL("http://example.com/form.html"); + form.url = GURL("http://example.com/form.html"); form.action = GURL("http://example.com/submit.html"); // Empty Form. @@ -5856,7 +5907,7 @@ TEST_F(AutofillManagerTest, // Set up an address form. FormData mixed_form; mixed_form.name = ASCIIToUTF16("MyForm"); - mixed_form.origin = GURL("https://myform.com/form.html"); + mixed_form.url = GURL("https://myform.com/form.html"); mixed_form.action = GURL("https://myform.com/submit.html"); FormFieldData field; test::CreateTestFormField("First name", "firstname", "", "text", &field); @@ -5894,7 +5945,7 @@ TEST_F(AutofillManagerTest, // Set up an address form. FormData mixed_form; mixed_form.name = ASCIIToUTF16("MyForm"); - mixed_form.origin = GURL("https://myform.com/form.html"); + mixed_form.url = GURL("https://myform.com/form.html"); mixed_form.action = GURL("https://myform.com/submit.html"); FormFieldData field; test::CreateTestFormField("First name", "firstname", "", "text", &field); @@ -5932,7 +5983,7 @@ TEST_F(AutofillManagerTest, // Set up a credit card form. FormData mixed_form; mixed_form.name = ASCIIToUTF16("MyForm"); - mixed_form.origin = GURL("https://myform.com/form.html"); + mixed_form.url = GURL("https://myform.com/form.html"); mixed_form.action = GURL("https://myform.com/submit.html"); FormFieldData field; test::CreateTestFormField("Name on Card", "nameoncard", "", "text", &field); @@ -5962,7 +6013,7 @@ TEST_F(AutofillManagerTest, DisplaySuggestionsForUpdatedServerTypedForm) { // Create a form with unknown heuristic fields. FormData form; form.name = ASCIIToUTF16("MyForm"); - form.origin = GURL("http://myform.com/form.html"); + form.url = GURL("http://myform.com/form.html"); form.action = GURL("http://myform.com/submit.html"); FormFieldData field; @@ -6021,7 +6072,7 @@ TEST_F(AutofillManagerTest, DisplaySuggestionsForUpdatedServerTypedForm) { TEST_F(AutofillManagerTest, FormWithLongOptionValuesIsAcceptable) { FormData form; form.name = ASCIIToUTF16("MyForm"); - form.origin = GURL("http://myform.com/form.html"); + form.url = GURL("http://myform.com/form.html"); form.action = GURL("http://myform.com/submit.html"); FormFieldData field; @@ -6067,7 +6118,7 @@ TEST_F(AutofillManagerTest, SmallForm_Upload_NoHeuristicsOrQuery) { // Set up the form. FormData form; - form.origin = GURL("http://myform.com/form.html"); + form.url = GURL("http://myform.com/form.html"); form.action = GURL("http://myform.com/submit.html"); FormFieldData field; test::CreateTestFormField("Unknown", "unknown", "", "text", &field); @@ -6242,6 +6293,270 @@ TEST_F(AutofillManagerTest, DidShowSuggestions_LogAutofillAddressShownMetric) { HasSubstr("Autofill.FormEvents.CreditCard")))); } +TEST_F(AutofillManagerTest, DidShowSuggestions_LogByType_AddressOnly) { + // Create a form with name and address fields. + FormData form; + form.name = ASCIIToUTF16("MyForm"); + form.button_titles = {std::make_pair( + ASCIIToUTF16("Submit"), ButtonTitleType::BUTTON_ELEMENT_SUBMIT_TYPE)}; + form.url = GURL("http://myform.com/form.html"); + form.action = GURL("http://myform.com/submit.html"); + form.main_frame_origin = + url::Origin::Create(GURL("https://myform_root.com/form.html")); + form.submission_event = SubmissionIndicatorEvent::SAME_DOCUMENT_NAVIGATION; + + FormFieldData field; + test::CreateTestFormField("First Name", "firstname", "", "text", &field); + form.fields.push_back(field); + test::CreateTestFormField("Last Name", "lastname", "", "text", &field); + form.fields.push_back(field); + test::CreateTestFormField("Address Line 1", "addr1", "", "text", &field); + form.fields.push_back(field); + + base::HistogramTester histogram_tester; + autofill_manager_->DidShowSuggestions(/*has_autofill_suggestions=*/true, form, + form.fields[0]); + histogram_tester.ExpectBucketCount("Autofill.FormEvents.Address.AddressOnly", + FORM_EVENT_SUGGESTIONS_SHOWN, 1); + histogram_tester.ExpectBucketCount("Autofill.FormEvents.Address.AddressOnly", + FORM_EVENT_SUGGESTIONS_SHOWN_ONCE, 1); + + // Logging is not done for other types of address forms. + const std::string histograms = histogram_tester.GetAllHistogramsRecorded(); + EXPECT_THAT(histograms, + Not(AnyOf("Autofill.FormEvents.Address.AddressPlusContact", + "Autofill.FormEvents.Address.AddressPlusEmail", + "Autofill.FormEvents.Address.AddressPlusEmailPlusPhone", + "Autofill.FormEvents.Address.AddressPlusPhone", + "Autofill.FormEvents.Address.ContactOnly", + "Autofill.FormEvents.Address.Other"))); +} + +TEST_F(AutofillManagerTest, DidShowSuggestions_LogByType_ContactOnly) { + // Create a form with name and contact fields. + FormData form; + form.name = ASCIIToUTF16("MyForm"); + form.button_titles = {std::make_pair( + ASCIIToUTF16("Submit"), ButtonTitleType::BUTTON_ELEMENT_SUBMIT_TYPE)}; + form.url = GURL("http://myform.com/form.html"); + form.action = GURL("http://myform.com/submit.html"); + form.main_frame_origin = + url::Origin::Create(GURL("https://myform_root.com/form.html")); + form.submission_event = SubmissionIndicatorEvent::SAME_DOCUMENT_NAVIGATION; + + FormFieldData field; + test::CreateTestFormField("First Name", "firstname", "", "text", &field); + form.fields.push_back(field); + test::CreateTestFormField("Last Name", "lastname", "", "text", &field); + form.fields.push_back(field); + test::CreateTestFormField("Email", "email", "", "email", &field); + form.fields.push_back(field); + + base::HistogramTester histogram_tester; + autofill_manager_->DidShowSuggestions(/*has_autofill_suggestions=*/true, form, + form.fields[0]); + histogram_tester.ExpectBucketCount("Autofill.FormEvents.Address.ContactOnly", + FORM_EVENT_SUGGESTIONS_SHOWN, 1); + histogram_tester.ExpectBucketCount("Autofill.FormEvents.Address.ContactOnly", + FORM_EVENT_SUGGESTIONS_SHOWN_ONCE, 1); + + // Logging is not done for other types of address forms. + const std::string histograms = histogram_tester.GetAllHistogramsRecorded(); + EXPECT_THAT(histograms, + Not(AnyOf("Autofill.FormEvents.Address.AddressPlusContact", + "Autofill.FormEvents.Address.AddressPlusEmail", + "Autofill.FormEvents.Address.AddressPlusEmailPlusPhone", + "Autofill.FormEvents.Address.AddressPlusPhone", + "Autofill.FormEvents.Address.AddressOnly", + "Autofill.FormEvents.Address.Other"))); +} + +TEST_F(AutofillManagerTest, DidShowSuggestions_LogByType_Other) { + // Create a form with name fields. + FormData form; + form.name = ASCIIToUTF16("MyForm"); + form.button_titles = {std::make_pair( + ASCIIToUTF16("Submit"), ButtonTitleType::BUTTON_ELEMENT_SUBMIT_TYPE)}; + form.url = GURL("http://myform.com/form.html"); + form.action = GURL("http://myform.com/submit.html"); + form.main_frame_origin = + url::Origin::Create(GURL("https://myform_root.com/form.html")); + form.submission_event = SubmissionIndicatorEvent::SAME_DOCUMENT_NAVIGATION; + + FormFieldData field; + test::CreateTestFormField("First Name", "firstname", "", "text", &field); + form.fields.push_back(field); + test::CreateTestFormField("Middle Name", "middlename", "", "text", &field); + form.fields.push_back(field); + test::CreateTestFormField("Last Name", "lastname", "", "text", &field); + form.fields.push_back(field); + + base::HistogramTester histogram_tester; + autofill_manager_->DidShowSuggestions(/*has_autofill_suggestions=*/true, form, + form.fields[0]); + histogram_tester.ExpectBucketCount("Autofill.FormEvents.Address.Other", + FORM_EVENT_SUGGESTIONS_SHOWN, 1); + histogram_tester.ExpectBucketCount("Autofill.FormEvents.Address.Other", + FORM_EVENT_SUGGESTIONS_SHOWN_ONCE, 1); + + // Logging is not done for other types of address forms. + const std::string histograms = histogram_tester.GetAllHistogramsRecorded(); + EXPECT_THAT(histograms, + Not(AnyOf("Autofill.FormEvents.Address.AddressPlusContact", + "Autofill.FormEvents.Address.AddressPlusEmail", + "Autofill.FormEvents.Address.AddressPlusEmailPlusPhone", + "Autofill.FormEvents.Address.AddressPlusPhone", + "Autofill.FormEvents.Address.AddressOnly", + "Autofill.FormEvents.Address.ContactOnly"))); +} + +TEST_F(AutofillManagerTest, DidShowSuggestions_LogByType_AddressPlusEmail) { + // Create a form with name fields. + FormData form; + form.name = ASCIIToUTF16("MyForm"); + form.button_titles = {std::make_pair( + ASCIIToUTF16("Submit"), ButtonTitleType::BUTTON_ELEMENT_SUBMIT_TYPE)}; + form.url = GURL("http://myform.com/form.html"); + form.action = GURL("http://myform.com/submit.html"); + form.main_frame_origin = + url::Origin::Create(GURL("https://myform_root.com/form.html")); + form.submission_event = SubmissionIndicatorEvent::SAME_DOCUMENT_NAVIGATION; + + FormFieldData field; + test::CreateTestFormField("First Name", "firstname", "", "text", &field); + form.fields.push_back(field); + test::CreateTestFormField("Last Name", "lastname", "", "text", &field); + form.fields.push_back(field); + test::CreateTestFormField("Address Line 1", "addr1", "", "text", &field); + form.fields.push_back(field); + test::CreateTestFormField("Email", "email", "", "email", &field); + form.fields.push_back(field); + + base::HistogramTester histogram_tester; + autofill_manager_->DidShowSuggestions(/*has_autofill_suggestions=*/true, form, + form.fields[0]); + histogram_tester.ExpectBucketCount( + "Autofill.FormEvents.Address.AddressPlusEmail", + FORM_EVENT_SUGGESTIONS_SHOWN, 1); + histogram_tester.ExpectBucketCount( + "Autofill.FormEvents.Address.AddressPlusEmail", + FORM_EVENT_SUGGESTIONS_SHOWN_ONCE, 1); + histogram_tester.ExpectBucketCount( + "Autofill.FormEvents.Address.AddressPlusContact", + FORM_EVENT_SUGGESTIONS_SHOWN, 1); + histogram_tester.ExpectBucketCount( + "Autofill.FormEvents.Address.AddressPlusContact", + FORM_EVENT_SUGGESTIONS_SHOWN_ONCE, 1); + + // Logging is not done for other types of address forms. + const std::string histograms = histogram_tester.GetAllHistogramsRecorded(); + EXPECT_THAT(histograms, + Not(AnyOf("Autofill.FormEvents.Address.AddressPlusEmailPlusPhone", + "Autofill.FormEvents.Address.AddressPlusPhone", + "Autofill.FormEvents.Address.AddressOnly", + "Autofill.FormEvents.Address.ContactOnly", + "Autofill.FormEvents.Address.Other"))); +} + +TEST_F(AutofillManagerTest, DidShowSuggestions_LogByType_AddressPlusPhone) { + // Create a form with name fields. + FormData form; + form.name = ASCIIToUTF16("MyForm"); + form.button_titles = {std::make_pair( + ASCIIToUTF16("Submit"), ButtonTitleType::BUTTON_ELEMENT_SUBMIT_TYPE)}; + form.url = GURL("http://myform.com/form.html"); + form.action = GURL("http://myform.com/submit.html"); + form.main_frame_origin = + url::Origin::Create(GURL("https://myform_root.com/form.html")); + form.submission_event = SubmissionIndicatorEvent::SAME_DOCUMENT_NAVIGATION; + + FormFieldData field; + test::CreateTestFormField("First Name", "firstname", "", "text", &field); + form.fields.push_back(field); + test::CreateTestFormField("Last Name", "lastname", "", "text", &field); + form.fields.push_back(field); + test::CreateTestFormField("Address Line 1", "addr1", "", "text", &field); + form.fields.push_back(field); + test::CreateTestFormField("Phone Number", "phonenumber", "", "tel", &field); + form.fields.push_back(field); + + base::HistogramTester histogram_tester; + autofill_manager_->DidShowSuggestions(/*has_autofill_suggestions=*/true, form, + form.fields[0]); + histogram_tester.ExpectBucketCount( + "Autofill.FormEvents.Address.AddressPlusPhone", + FORM_EVENT_SUGGESTIONS_SHOWN, 1); + histogram_tester.ExpectBucketCount( + "Autofill.FormEvents.Address.AddressPlusPhone", + FORM_EVENT_SUGGESTIONS_SHOWN_ONCE, 1); + histogram_tester.ExpectBucketCount( + "Autofill.FormEvents.Address.AddressPlusContact", + FORM_EVENT_SUGGESTIONS_SHOWN, 1); + histogram_tester.ExpectBucketCount( + "Autofill.FormEvents.Address.AddressPlusContact", + FORM_EVENT_SUGGESTIONS_SHOWN_ONCE, 1); + + // Logging is not done for other types of address forms. + const std::string histograms = histogram_tester.GetAllHistogramsRecorded(); + EXPECT_THAT(histograms, + Not(AnyOf("Autofill.FormEvents.Address.AddressPlusEmailPlusPhone", + "Autofill.FormEvents.Address.AddressPlusEmail", + "Autofill.FormEvents.Address.AddressOnly", + "Autofill.FormEvents.Address.ContactOnly", + "Autofill.FormEvents.Address.Other"))); +} + +TEST_F(AutofillManagerTest, + DidShowSuggestions_LogByType_AddressPlusEmailPlusPhone) { + // Create a form with name fields. + FormData form; + form.name = ASCIIToUTF16("MyForm"); + form.button_titles = {std::make_pair( + ASCIIToUTF16("Submit"), ButtonTitleType::BUTTON_ELEMENT_SUBMIT_TYPE)}; + form.url = GURL("http://myform.com/form.html"); + form.action = GURL("http://myform.com/submit.html"); + form.main_frame_origin = + url::Origin::Create(GURL("https://myform_root.com/form.html")); + form.submission_event = SubmissionIndicatorEvent::SAME_DOCUMENT_NAVIGATION; + + FormFieldData field; + test::CreateTestFormField("First Name", "firstname", "", "text", &field); + form.fields.push_back(field); + test::CreateTestFormField("Last Name", "lastname", "", "text", &field); + form.fields.push_back(field); + test::CreateTestFormField("Address Line 1", "addr1", "", "text", &field); + form.fields.push_back(field); + test::CreateTestFormField("Phone Number", "phonenumber", "", "tel", &field); + form.fields.push_back(field); + test::CreateTestFormField("Email", "email", "", "email", &field); + form.fields.push_back(field); + + base::HistogramTester histogram_tester; + autofill_manager_->DidShowSuggestions(/*has_autofill_suggestions=*/true, form, + form.fields[0]); + histogram_tester.ExpectBucketCount( + "Autofill.FormEvents.Address.AddressPlusEmailPlusPhone", + FORM_EVENT_SUGGESTIONS_SHOWN, 1); + histogram_tester.ExpectBucketCount( + "Autofill.FormEvents.Address.AddressPlusEmailPlusPhone", + FORM_EVENT_SUGGESTIONS_SHOWN_ONCE, 1); + histogram_tester.ExpectBucketCount( + "Autofill.FormEvents.Address.AddressPlusContact", + FORM_EVENT_SUGGESTIONS_SHOWN, 1); + histogram_tester.ExpectBucketCount( + "Autofill.FormEvents.Address.AddressPlusContact", + FORM_EVENT_SUGGESTIONS_SHOWN_ONCE, 1); + + // Logging is not done for other types of address forms. + const std::string histograms = histogram_tester.GetAllHistogramsRecorded(); + EXPECT_THAT(histograms, + Not(AnyOf("Autofill.FormEvents.Address.AddressPlusPhone", + "Autofill.FormEvents.Address.AddressPlusEmail", + "Autofill.FormEvents.Address.AddressOnly", + "Autofill.FormEvents.Address.ContactOnly", + "Autofill.FormEvents.Address.Other"))); +} + TEST_F(AutofillManagerTest, DidShowSuggestions_LogAutofillCreditCardShownMetric) { FormData form; @@ -6392,7 +6707,7 @@ class OnFocusOnFormFieldTest : public AutofillManagerTest, TEST_P(OnFocusOnFormFieldTest, AddressSuggestions) { FormData form; form.name = ASCIIToUTF16("MyForm"); - form.origin = GURL("https://myform.com/form.html"); + form.url = GURL("https://myform.com/form.html"); form.action = GURL("https://myform.com/submit.html"); FormFieldData field; // Set a valid autocomplete attribute for the first name. @@ -6423,7 +6738,7 @@ TEST_P(OnFocusOnFormFieldTest, AddressSuggestions_AutocompleteOffNotRespected) { FormData form; form.name = ASCIIToUTF16("MyForm"); - form.origin = GURL("https://myform.com/form.html"); + form.url = GURL("https://myform.com/form.html"); form.action = GURL("https://myform.com/submit.html"); FormFieldData field; // Set a valid autocomplete attribute for the first name. @@ -6451,7 +6766,7 @@ TEST_P(OnFocusOnFormFieldTest, AddressSuggestions_AutocompleteOffRespected) { FormData form; form.name = ASCIIToUTF16("MyForm"); - form.origin = GURL("https://myform.com/form.html"); + form.url = GURL("https://myform.com/form.html"); form.action = GURL("https://myform.com/submit.html"); FormFieldData field; // Set a valid autocomplete attribute for the first name. diff --git a/chromium/components/autofill/core/browser/autofill_merge_unittest.cc b/chromium/components/autofill/core/browser/autofill_merge_unittest.cc index bd1bbb316a7..86ac1dcbbf1 100644 --- a/chromium/components/autofill/core/browser/autofill_merge_unittest.cc +++ b/chromium/components/autofill/core/browser/autofill_merge_unittest.cc @@ -229,7 +229,7 @@ void AutofillMergeTest::MergeProfiles(const std::string& profiles, // Create a test form. FormData form; form.name = base::ASCIIToUTF16("MyTestForm"); - form.origin = GURL("https://www.example.com/origin.html"); + form.url = GURL("https://www.example.com/origin.html"); form.action = GURL("https://www.example.com/action.html"); // Parse the input line by line. diff --git a/chromium/components/autofill/core/browser/autofill_metadata.cc b/chromium/components/autofill/core/browser/autofill_metadata.cc index 99527207f77..cb2686f98f5 100644 --- a/chromium/components/autofill/core/browser/autofill_metadata.cc +++ b/chromium/components/autofill/core/browser/autofill_metadata.cc @@ -4,6 +4,9 @@ #include "components/autofill/core/browser/autofill_metadata.h" +#include "components/autofill/core/common/autofill_clock.h" +#include "components/autofill/core/common/autofill_constants.h" + namespace autofill { bool AutofillMetadata::operator==(const AutofillMetadata& metadata) const { @@ -17,6 +20,10 @@ bool AutofillMetadata::operator!=(const AutofillMetadata& metadata) const { return !(*this == metadata); } +bool AutofillMetadata::IsDeletable() const { + return IsAutofillEntryWithUseDateDeletable(use_date); +} + std::ostream& operator<<(std::ostream& os, const AutofillMetadata& metadata) { return os << metadata.id << " " << metadata.use_count << " " << metadata.use_date << " " << metadata.has_converted << " " diff --git a/chromium/components/autofill/core/browser/autofill_metadata.h b/chromium/components/autofill/core/browser/autofill_metadata.h index 3fbc2e12a26..e8b62f16704 100644 --- a/chromium/components/autofill/core/browser/autofill_metadata.h +++ b/chromium/components/autofill/core/browser/autofill_metadata.h @@ -21,6 +21,10 @@ struct AutofillMetadata { bool operator==(const AutofillMetadata&) const; bool operator!=(const AutofillMetadata&) const; + // Returns whether the metadata is deletable: if it has not been used for + // longer than |kDisusedAddressDeletionTimeDelta|. + bool IsDeletable() const; + // The ID for the model. This should be the guid for local data and server_id // for the server data. std::string id; diff --git a/chromium/components/autofill/core/browser/autofill_metrics.cc b/chromium/components/autofill/core/browser/autofill_metrics.cc index b88ad9a0269..3afc5c867ca 100644 --- a/chromium/components/autofill/core/browser/autofill_metrics.cc +++ b/chromium/components/autofill/core/browser/autofill_metrics.cc @@ -684,6 +684,12 @@ void AutofillMetrics::LogCreditCardInfoBarMetric( metric, NUM_INFO_BAR_METRICS); } + if (options.from_dynamic_change_form) { + base::UmaHistogramEnumeration( + "Autofill.CreditCardInfoBar" + destination + ".FromDynamicChangeForm", + metric, NUM_INFO_BAR_METRICS); + } + if (options.has_non_focusable_field) { base::UmaHistogramEnumeration( "Autofill.CreditCardInfoBar" + destination + ".FromNonFocusableForm", @@ -746,6 +752,11 @@ void AutofillMetrics::LogSaveCardPromptMetric( metric_with_destination_and_show + ".FromNonFocusableForm", metric, NUM_SAVE_CARD_PROMPT_METRICS); } + if (options.from_dynamic_change_form) { + base::UmaHistogramEnumeration( + metric_with_destination_and_show + ".FromDynamicChangeForm", metric, + NUM_SAVE_CARD_PROMPT_METRICS); + } base::UmaHistogramEnumeration( metric_with_destination_and_show + PreviousSaveCreditCardPromptUserDecisionToString( @@ -1450,6 +1461,11 @@ void AutofillMetrics::LogAutofillSuggestionAcceptedIndex(int index) { } // static +void AutofillMetrics::LogAutofillFormCleared() { + base::RecordAction(base::UserMetricsAction("Autofill_ClearedForm")); +} + +// static void AutofillMetrics::LogNumberOfEditedAutofilledFields( size_t num_edited_autofilled_fields, bool observed_submission) { @@ -1871,6 +1887,17 @@ void AutofillMetrics::LogWalletSyncTransportCardsOptIn(bool is_opted_in) { "Autofill.HadUserOptedIn_To_WalletSyncTransportServerCards", is_opted_in); } +void AutofillMetrics::LogCardUploadEnabledMetric( + CardUploadEnabledMetric metric_value, + AutofillSyncSigninState sync_state) { + const std::string parent_metric = std::string("Autofill.CardUploadEnabled"); + base::UmaHistogramEnumeration(parent_metric, metric_value); + + const std::string child_metric = + parent_metric + GetMetricsSyncStateSuffix(sync_state); + base::UmaHistogramEnumeration(child_metric, metric_value); +} + // static const char* AutofillMetrics::GetMetricsSyncStateSuffix( AutofillSyncSigninState sync_state) { @@ -1881,8 +1908,10 @@ const char* AutofillMetrics::GetMetricsSyncStateSuffix( return ".SignedIn"; case AutofillSyncSigninState::kSignedInAndWalletSyncTransportEnabled: return ".SignedInAndWalletSyncTransportEnabled"; - case AutofillSyncSigninState::kSignedInAndSyncFeature: - return ".SignedInAndSyncFeature"; + case AutofillSyncSigninState::kSignedInAndSyncFeatureEnabled: + return ".SignedInAndSyncFeatureEnabled"; + case AutofillSyncSigninState::kSyncPaused: + return ".SyncPaused"; case AutofillSyncSigninState::kNumSyncStates: return ".Unknown"; } diff --git a/chromium/components/autofill/core/browser/autofill_metrics.h b/chromium/components/autofill/core/browser/autofill_metrics.h index 39c231415ae..3688ad1beff 100644 --- a/chromium/components/autofill/core/browser/autofill_metrics.h +++ b/chromium/components/autofill/core/browser/autofill_metrics.h @@ -116,6 +116,9 @@ class AutofillMetrics { UPLOAD_OFFERED_FROM_NON_FOCUSABLE_FIELD = 1 << 15, // The card does not satisfy any of the ranges of supported BIN ranges. UPLOAD_NOT_OFFERED_UNSUPPORTED_BIN_RANGE = 1 << 16, + // All the required conditions were satisfied even though the form is + // dynamic changed. + UPLOAD_OFFERED_FROM_DYNAMIC_CHANGE_FORM = 1 << 17, // Update |kNumCardUploadDecisionMetrics| when adding new enum here. }; @@ -746,7 +749,7 @@ class AutofillMetrics { NUM_WALLET_REQUIRED_ACTIONS }; - // For mesuring how wallet addresses are converted to local profiles. + // For measuring how wallet addresses are converted to local profiles. enum WalletAddressConversionType : int { // The converted wallet address was merged into an existing local profile. CONVERTED_ADDRESS_MERGED, @@ -755,9 +758,27 @@ class AutofillMetrics { NUM_CONVERTED_ADDRESS_CONVERSION_TYPES }; - // To record whether or not the upload event was sent, + // To record whether the upload event was sent. enum class UploadEventStatus { kNotSent, kSent, kMaxValue = kSent }; + // Log all the scenarios that contribute to the decision of whether card + // upload is enabled or not. + enum class CardUploadEnabledMetric { + SYNC_SERVICE_NULL = 0, + SYNC_SERVICE_PERSISTENT_AUTH_ERROR = 1, + SYNC_SERVICE_MISSING_AUTOFILL_WALLET_DATA_ACTIVE_TYPE = 2, + SYNC_SERVICE_MISSING_AUTOFILL_PROFILE_ACTIVE_TYPE = 3, + ACCOUNT_WALLET_STORAGE_UPLOAD_DISABLED = 4, + USING_SECONDARY_SYNC_PASSPHRASE = 5, + LOCAL_SYNC_ENABLED = 6, + PAYMENTS_INTEGRATION_DISABLED = 7, + EMAIL_EMPTY = 8, + EMAIL_DOMAIN_NOT_SUPPORTED = 9, + AUTOFILL_UPSTREAM_DISABLED = 10, + CARD_UPLOAD_ENABLED = 11, + kMaxValue = CARD_UPLOAD_ENABLED, + }; + // Utility to log URL keyed form interaction events. class FormInteractionsUkmLogger { public: @@ -1109,6 +1130,9 @@ class AutofillMetrics { // Log the index of the selected Autofill suggestion in the popup. static void LogAutofillSuggestionAcceptedIndex(int index); + // Logs that the user cleared the form. + static void LogAutofillFormCleared(); + // Log the number of days since an Autocomplete suggestion was last used. static void LogAutocompleteDaysSinceLastUse(size_t days); @@ -1231,13 +1255,18 @@ class AutofillMetrics { // server cards to be shown. static void LogWalletSyncTransportCardsOptIn(bool is_opted_in); + // Records the reason for why (or why not) card upload was enabled for the + // user. + static void LogCardUploadEnabledMetric(CardUploadEnabledMetric metric, + AutofillSyncSigninState sync_state); + static const char* GetMetricsSyncStateSuffix( AutofillSyncSigninState sync_state); private: static void Log(AutocompleteEvent event); - static const int kNumCardUploadDecisionMetrics = 17; + static const int kNumCardUploadDecisionMetrics = 18; DISALLOW_IMPLICIT_CONSTRUCTORS(AutofillMetrics); }; diff --git a/chromium/components/autofill/core/browser/autofill_metrics_unittest.cc b/chromium/components/autofill/core/browser/autofill_metrics_unittest.cc index 87afa30900e..8a6bdb8ab63 100644 --- a/chromium/components/autofill/core/browser/autofill_metrics_unittest.cc +++ b/chromium/components/autofill/core/browser/autofill_metrics_unittest.cc @@ -27,6 +27,7 @@ #include "components/autofill/core/browser/metrics/credit_card_form_event_logger.h" #include "components/autofill/core/browser/metrics/form_events.h" #include "components/autofill/core/browser/mock_autocomplete_history_manager.h" +#include "components/autofill/core/browser/payments/test_credit_card_save_manager.h" #include "components/autofill/core/browser/payments/test_payments_client.h" #include "components/autofill/core/browser/personal_data_manager.h" #include "components/autofill/core/browser/popup_item_ids.h" @@ -34,7 +35,6 @@ #include "components/autofill/core/browser/test_autofill_client.h" #include "components/autofill/core/browser/test_autofill_driver.h" #include "components/autofill/core/browser/test_autofill_manager.h" -#include "components/autofill/core/browser/test_credit_card_save_manager.h" #include "components/autofill/core/browser/test_form_data_importer.h" #include "components/autofill/core/browser/test_form_structure.h" #include "components/autofill/core/browser/test_personal_data_manager.h" @@ -84,8 +84,8 @@ using UkmFieldTypeValidationType = ukm::builders::Autofill_FieldTypeValidation; using UkmFieldFillStatusType = ukm::builders::Autofill_FieldFillStatus; using UkmFormEventType = ukm::builders::Autofill_FormEvent; -using ExpectedUkmMetrics = - std::vector<std::vector<std::pair<const char*, int64_t>>>; +using ExpectedUkmMetricsRecord = std::vector<std::pair<const char*, int64_t>>; +using ExpectedUkmMetrics = std::vector<ExpectedUkmMetricsRecord>; const char* kTestGuid = "00000000-0000-0000-0000-000000000001"; @@ -309,9 +309,9 @@ void AutofillMetricsTest::SetUp() { std::make_unique<MockAutocompleteHistoryManager>(); payments::TestPaymentsClient* payments_client = - new payments::TestPaymentsClient( - autofill_driver_->GetURLLoaderFactory(), autofill_client_.GetPrefs(), - autofill_client_.GetIdentityManager(), personal_data_.get()); + new payments::TestPaymentsClient(autofill_driver_->GetURLLoaderFactory(), + autofill_client_.GetIdentityManager(), + personal_data_.get()); autofill_client_.set_test_payments_client( std::unique_ptr<payments::TestPaymentsClient>(payments_client)); TestCreditCardSaveManager* credit_card_save_manager = @@ -501,7 +501,7 @@ TEST_F(AutofillMetricsTest, QualityMetrics) { // Set up our form data. FormData form; form.name = ASCIIToUTF16("TestForm"); - form.origin = GURL("http://example.com/form.html"); + form.url = GURL("http://example.com/form.html"); form.action = GURL("http://example.com/submit.html"); form.main_frame_origin = url::Origin::Create(autofill_client_.form_origin()); @@ -688,7 +688,7 @@ TEST_F(AutofillMetricsTest, // Set up our form data. FormData form; form.name = ASCIIToUTF16("TestForm"); - form.origin = GURL("http://example.com/form.html"); + form.url = GURL("http://example.com/form.html"); form.action = GURL("http://example.com/submit.html"); std::vector<ServerFieldType> heuristic_types, server_types; @@ -768,7 +768,7 @@ TEST_F(AutofillMetricsTest, // Set up our form data. FormData form; form.name = ASCIIToUTF16("TestForm"); - form.origin = GURL("http://example.com/form.html"); + form.url = GURL("http://example.com/form.html"); form.action = GURL("http://example.com/submit.html"); std::vector<ServerFieldType> heuristic_types, server_types; @@ -835,7 +835,7 @@ TEST_F(AutofillMetricsTest, LogHiddenRepresentationalFieldSkipDecision) { // Set up our form data. FormData form; form.name = ASCIIToUTF16("TestForm"); - form.origin = GURL("http://example.com/form.html"); + form.url = GURL("http://example.com/form.html"); form.action = GURL("http://example.com/submit.html"); form.main_frame_origin = url::Origin::Create(autofill_client_.form_origin()); @@ -977,7 +977,7 @@ TEST_F(AutofillMetricsTest, LogRepeatedAddressTypeRationalized) { // Set up our form data. FormData form; form.name = ASCIIToUTF16("TestForm"); - form.origin = GURL("http://example.com/form.html"); + form.url = GURL("http://example.com/form.html"); form.action = GURL("http://example.com/submit.html"); form.main_frame_origin = url::Origin::Create(autofill_client_.form_origin()); @@ -1084,7 +1084,7 @@ TEST_F(AutofillMetricsTest, LogRepeatedStateCountryTypeRationalized) { // Set up our form data. FormData form; form.name = ASCIIToUTF16("TestForm"); - form.origin = GURL("http://example.com/form.html"); + form.url = GURL("http://example.com/form.html"); form.action = GURL("http://example.com/submit.html"); form.main_frame_origin = url::Origin::Create(autofill_client_.form_origin()); @@ -1221,7 +1221,7 @@ TEST_F(AutofillMetricsTest, // Set up our form data. FormData form; form.name = ASCIIToUTF16("TestForm"); - form.origin = GURL("http://example.com/form.html"); + form.url = GURL("http://example.com/form.html"); form.action = GURL("http://example.com/submit.html"); std::vector<ServerFieldType> heuristic_types, server_types; @@ -1287,7 +1287,7 @@ TEST_F(AutofillMetricsTest, // Set up our form data. FormData form; form.name = ASCIIToUTF16("TestForm"); - form.origin = GURL("http://example.com/form.html"); + form.url = GURL("http://example.com/form.html"); form.action = GURL("http://example.com/submit.html"); std::vector<ServerFieldType> heuristic_types, server_types; @@ -1588,7 +1588,7 @@ TEST_P(QualityMetricsTest, Classification) { // Set up our form data. FormData form; form.name = ASCIIToUTF16("TestForm"); - form.origin = GURL("http://example.com/form.html"); + form.url = GURL("http://example.com/form.html"); form.action = GURL("http://example.com/submit.html"); form.main_frame_origin = url::Origin::Create(autofill_client_.form_origin()); @@ -1763,7 +1763,7 @@ TEST_F(AutofillMetricsTest, TimingMetrics) { FormData form; form.name = ASCIIToUTF16("TestForm"); - form.origin = GURL("http://example.com/form.html"); + form.url = GURL("http://example.com/form.html"); form.action = GURL("http://example.com/submit.html"); form.main_frame_origin = url::Origin::Create(GURL("http://example_root.com/form.html")); @@ -1804,7 +1804,7 @@ TEST_F(AutofillMetricsTest, QualityMetrics_NoSubmission) { // Set up our form data. FormData form; form.name = ASCIIToUTF16("TestForm"); - form.origin = GURL("http://example.com/form.html"); + form.url = GURL("http://example.com/form.html"); form.action = GURL("http://example.com/submit.html"); form.main_frame_origin = url::Origin::Create(autofill_client_.form_origin()); @@ -1990,7 +1990,7 @@ TEST_F(AutofillMetricsTest, QualityMetrics_NoSubmission) { TEST_F(AutofillMetricsTest, QualityMetrics_BasedOnAutocomplete) { FormData form; form.name = ASCIIToUTF16("MyForm"); - form.origin = GURL("http://myform.com/form.html"); + form.url = GURL("http://myform.com/form.html"); form.action = GURL("http://myform.com/submit.html"); form.main_frame_origin = url::Origin::Create(GURL("http://example_root.com/form.html")); @@ -2105,7 +2105,7 @@ TEST_F(AutofillMetricsTest, UpiVirtualPaymentAddress) { // Set up our form data. FormData form; form.name = ASCIIToUTF16("TestForm"); - form.origin = GURL("http://example.com/form.html"); + form.url = GURL("http://example.com/form.html"); form.action = GURL("http://example.com/submit.html"); form.main_frame_origin = url::Origin::Create(GURL("http://example_root.com/form.html")); @@ -2164,7 +2164,7 @@ TEST_F(AutofillMetricsTest, PredictedMetricsWithAutocomplete) { FormData form; FormFieldData field; form.name = ASCIIToUTF16("TestForm"); - form.origin = GURL("http://example.com/form.html"); + form.url = GURL("http://example.com/form.html"); form.action = GURL("http://example.com/submit.html"); form.main_frame_origin = url::Origin::Create(GURL("http://example_root.com/form.html")); @@ -2241,7 +2241,7 @@ TEST_F(AutofillMetricsTest, SaneMetricsWithCacheMismatch) { // Set up our form data. FormData form; form.name = ASCIIToUTF16("TestForm"); - form.origin = GURL("http://example.com/form.html"); + form.url = GURL("http://example.com/form.html"); form.action = GURL("http://example.com/submit.html"); form.main_frame_origin = url::Origin::Create(GURL("http://example_root.com/form.html")); @@ -2340,7 +2340,7 @@ TEST_F(AutofillMetricsTest, StoredProfileCountAutofillableFormSubmission) { // Construct a fillable form. FormData form; form.name = ASCIIToUTF16("TestForm"); - form.origin = GURL("http://example.com/form.html"); + form.url = GURL("http://example.com/form.html"); form.action = GURL("http://example.com/submit.html"); form.main_frame_origin = url::Origin::Create(GURL("http://example_root.com/form.html")); @@ -2376,7 +2376,7 @@ TEST_F(AutofillMetricsTest, StoredProfileCountNonAutofillableFormSubmission) { // Construct a non-fillable form. FormData form; form.name = ASCIIToUTF16("TestForm"); - form.origin = GURL("http://example.com/form.html"); + form.url = GURL("http://example.com/form.html"); form.action = GURL("http://example.com/submit.html"); form.main_frame_origin = url::Origin::Create(GURL("http://example_root.com/form.html")); @@ -2408,7 +2408,7 @@ TEST_F(AutofillMetricsTest, NumberOfEditedAutofilledFields) { // Construct a fillable form. FormData form; form.name = ASCIIToUTF16("TestForm"); - form.origin = GURL("http://example.com/form.html"); + form.url = GURL("http://example.com/form.html"); form.action = GURL("http://example.com/submit.html"); form.main_frame_origin = url::Origin::Create(GURL("http://example_root.com/form.html")); @@ -2462,7 +2462,7 @@ TEST_F(AutofillMetricsTest, NumberOfEditedAutofilledFields_NoSubmission) { // Construct a fillable form. FormData form; form.name = ASCIIToUTF16("TestForm"); - form.origin = GURL("http://example.com/form.html"); + form.url = GURL("http://example.com/form.html"); form.action = GURL("http://example.com/submit.html"); form.main_frame_origin = url::Origin::Create(autofill_client_.form_origin()); @@ -2511,7 +2511,7 @@ TEST_F(AutofillMetricsTest, DeveloperEngagement) { // Start with a non-fillable form. FormData form; form.name = ASCIIToUTF16("TestForm"); - form.origin = GURL("http://example.com/form.html"); + form.url = GURL("http://example.com/form.html"); form.action = GURL("http://example.com/submit.html"); form.main_frame_origin = url::Origin::Create(autofill_client_.form_origin()); @@ -2615,7 +2615,7 @@ TEST_F(AutofillMetricsTest, // Start with a non-fillable form. FormData form; form.name = ASCIIToUTF16("TestForm"); - form.origin = GURL("http://example.com/form.html"); + form.url = GURL("http://example.com/form.html"); form.action = GURL("http://example.com/submit.html"); form.main_frame_origin = url::Origin::Create(autofill_client_.form_origin()); @@ -2661,7 +2661,7 @@ TEST_F(AutofillMetricsTest, UkmDeveloperEngagement_LogFillableFormParsedWithTypeHints) { FormData form; form.name = ASCIIToUTF16("TestForm"); - form.origin = GURL("http://example.com/form.html"); + form.url = GURL("http://example.com/form.html"); form.action = GURL("http://example.com/submit.html"); form.main_frame_origin = url::Origin::Create(autofill_client_.form_origin()); @@ -2718,7 +2718,7 @@ TEST_F(AutofillMetricsTest, UkmDeveloperEngagement_LogUpiVpaTypeHint) { {}); FormData form; form.name = ASCIIToUTF16("TestForm"); - form.origin = GURL("http://example.com/form.html"); + form.url = GURL("http://example.com/form.html"); form.action = GURL("http://example.com/submit.html"); form.main_frame_origin = url::Origin::Create(autofill_client_.form_origin()); @@ -2919,7 +2919,7 @@ TEST_F(AutofillMetricsTest, AddressSuggestionsCount) { // Set up our form data. FormData form; form.name = ASCIIToUTF16("TestForm"); - form.origin = GURL("http://example.com/form.html"); + form.url = GURL("http://example.com/form.html"); form.action = GURL("http://example.com/submit.html"); form.main_frame_origin = url::Origin::Create(autofill_client_.form_origin()); @@ -2991,7 +2991,7 @@ TEST_P(AutofillMetricsCompanyTest, CompanyNameSuggestions) { // Set up our form data. FormData form; form.name = ASCIIToUTF16("TestForm"); - form.origin = GURL("http://example.com/form.html"); + form.url = GURL("http://example.com/form.html"); form.action = GURL("http://example.com/submit.html"); form.main_frame_origin = url::Origin::Create(autofill_client_.form_origin()); @@ -3035,7 +3035,7 @@ TEST_F(AutofillMetricsTest, CreditCardCheckoutFlowUserActions) { // Set up our form data. FormData form; form.name = ASCIIToUTF16("TestForm"); - form.origin = GURL("http://example.com/form.html"); + form.url = GURL("http://example.com/form.html"); form.action = GURL("http://example.com/submit.html"); form.main_frame_origin = url::Origin::Create(autofill_client_.form_origin()); @@ -3095,6 +3095,48 @@ TEST_F(AutofillMetricsTest, CreditCardCheckoutFlowUserActions) { user_action_tester.GetActionCount("Autofill_SelectedSuggestion")); } + // Simulate showing a credit card suggestion polled from "Credit card number" + // field along with a "Clear form" footer suggestion. + { + base::UserActionTester user_action_tester; + autofill_manager_->DidShowSuggestions(true /* is_new_popup */, form, + form.fields[1]); + EXPECT_EQ(1, user_action_tester.GetActionCount( + "Autofill_ShowedCreditCardSuggestions")); + } + + // Simulate selecting a "Clear form" suggestion. + { + base::UserActionTester user_action_tester; + std::string guid("10000000-0000-0000-0000-000000000001"); // local card + external_delegate_->OnQuery(0, form, form.fields.front(), gfx::RectF()); + external_delegate_->DidAcceptSuggestion(base::string16(), + POPUP_ITEM_ID_CLEAR_FORM, 0); + EXPECT_EQ(1, user_action_tester.GetActionCount("Autofill_ClearedForm")); + } + + // Simulate showing a credit card suggestion polled from "Credit card number" + // field, this time to submit the form. + { + base::UserActionTester user_action_tester; + autofill_manager_->DidShowSuggestions(true /* is_new_popup */, form, + form.fields[1]); + EXPECT_EQ(1, user_action_tester.GetActionCount( + "Autofill_ShowedCreditCardSuggestions")); + } + + // Simulate selecting a credit card suggestions. + { + base::UserActionTester user_action_tester; + std::string guid("10000000-0000-0000-0000-000000000001"); // local card + external_delegate_->OnQuery(0, form, form.fields.front(), gfx::RectF()); + external_delegate_->DidAcceptSuggestion( + ASCIIToUTF16("Test"), + autofill_manager_->MakeFrontendID(guid, std::string()), 0); + EXPECT_EQ(1, + user_action_tester.GetActionCount("Autofill_SelectedSuggestion")); + } + // Simulate filling a credit card suggestion. { base::UserActionTester user_action_tester; @@ -3119,43 +3161,53 @@ TEST_F(AutofillMetricsTest, CreditCardCheckoutFlowUserActions) { "Autofill_FormSubmitted_NonFillable")); } - VerifyUkm( - test_ukm_recorder_, form, UkmSuggestionsShownType::kEntryName, - {{{UkmSuggestionFilledType::kMillisecondsSinceFormParsedName, 0}, - {UkmTextFieldDidChangeType::kHeuristicTypeName, CREDIT_CARD_NAME_FULL}, - {UkmTextFieldDidChangeType::kHtmlFieldTypeName, HTML_TYPE_UNSPECIFIED}, - {UkmTextFieldDidChangeType::kServerTypeName, CREDIT_CARD_NAME_FULL}, - {UkmSuggestionsShownType::kFieldSignatureName, - Collapse(CalculateFieldSignatureForField(form.fields[0]))}, - {UkmSuggestionsShownType::kFormSignatureName, - Collapse(CalculateFormSignature(form))}}, - {{UkmSuggestionFilledType::kMillisecondsSinceFormParsedName, 0}, - {UkmTextFieldDidChangeType::kHeuristicTypeName, CREDIT_CARD_NUMBER}, - {UkmTextFieldDidChangeType::kHtmlFieldTypeName, HTML_TYPE_UNSPECIFIED}, - {UkmTextFieldDidChangeType::kServerTypeName, CREDIT_CARD_NUMBER}, - {UkmSuggestionsShownType::kFieldSignatureName, - Collapse(CalculateFieldSignatureForField(form.fields[1]))}, - {UkmSuggestionsShownType::kFormSignatureName, - Collapse(CalculateFormSignature(form))}}}); - // Expect 2 |FORM_EVENT_LOCAL_SUGGESTION_FILLED| events. First, from - // call to |external_delegate_->DidAcceptSuggestion|. Second, from call to - // |autofill_manager_->FillOrPreviewForm|. - VerifyUkm( - test_ukm_recorder_, form, UkmSuggestionFilledType::kEntryName, - {{{UkmSuggestionFilledType::kRecordTypeName, CreditCard::LOCAL_CARD}, - {UkmSuggestionFilledType::kMillisecondsSinceFormParsedName, 0}, - {UkmSuggestionFilledType::kIsForCreditCardName, true}, - {UkmSuggestionFilledType::kFieldSignatureName, - Collapse(CalculateFieldSignatureForField(form.fields.front()))}, - {UkmSuggestionFilledType::kFormSignatureName, - Collapse(CalculateFormSignature(form))}}, - {{UkmSuggestionFilledType::kRecordTypeName, CreditCard::LOCAL_CARD}, - {UkmSuggestionFilledType::kMillisecondsSinceFormParsedName, 0}, - {UkmSuggestionFilledType::kIsForCreditCardName, true}, - {UkmSuggestionFilledType::kFieldSignatureName, - Collapse(CalculateFieldSignatureForField(form.fields.front()))}, - {UkmSuggestionFilledType::kFormSignatureName, - Collapse(CalculateFormSignature(form))}}}); + // Expect one record for a click on the cardholder name field and one record + // for each of the 3 clicks on the card number field. + ExpectedUkmMetricsRecord name_field_record{ + {UkmSuggestionFilledType::kMillisecondsSinceFormParsedName, 0}, + {UkmTextFieldDidChangeType::kHeuristicTypeName, CREDIT_CARD_NAME_FULL}, + {UkmTextFieldDidChangeType::kHtmlFieldTypeName, HTML_TYPE_UNSPECIFIED}, + {UkmTextFieldDidChangeType::kServerTypeName, CREDIT_CARD_NAME_FULL}, + {UkmSuggestionsShownType::kFieldSignatureName, + Collapse(CalculateFieldSignatureForField(form.fields[0]))}, + {UkmSuggestionsShownType::kFormSignatureName, + Collapse(CalculateFormSignature(form))}}; + ExpectedUkmMetricsRecord number_field_record{ + {UkmSuggestionFilledType::kMillisecondsSinceFormParsedName, 0}, + {UkmTextFieldDidChangeType::kHeuristicTypeName, CREDIT_CARD_NUMBER}, + {UkmTextFieldDidChangeType::kHtmlFieldTypeName, HTML_TYPE_UNSPECIFIED}, + {UkmTextFieldDidChangeType::kServerTypeName, CREDIT_CARD_NUMBER}, + {UkmSuggestionsShownType::kFieldSignatureName, + Collapse(CalculateFieldSignatureForField(form.fields[1]))}, + {UkmSuggestionsShownType::kFormSignatureName, + Collapse(CalculateFormSignature(form))}}; + VerifyUkm(test_ukm_recorder_, form, UkmSuggestionsShownType::kEntryName, + {name_field_record, number_field_record, number_field_record, + number_field_record}); + + // Expect 3 |FORM_EVENT_LOCAL_SUGGESTION_FILLED| events. First, from + // call to |external_delegate_->DidAcceptSuggestion|. Second and third, from + // ExpectedUkmMetrics |autofill_manager_->FillOrPreviewForm|. + ExpectedUkmMetricsRecord from_did_accept_suggestion{ + {UkmSuggestionFilledType::kRecordTypeName, CreditCard::LOCAL_CARD}, + {UkmSuggestionFilledType::kMillisecondsSinceFormParsedName, 0}, + {UkmSuggestionFilledType::kIsForCreditCardName, true}, + {UkmSuggestionFilledType::kFieldSignatureName, + Collapse(CalculateFieldSignatureForField(form.fields.front()))}, + {UkmSuggestionFilledType::kFormSignatureName, + Collapse(CalculateFormSignature(form))}}; + ExpectedUkmMetricsRecord from_fill_or_preview_form{ + {UkmSuggestionFilledType::kRecordTypeName, CreditCard::LOCAL_CARD}, + {UkmSuggestionFilledType::kMillisecondsSinceFormParsedName, 0}, + {UkmSuggestionFilledType::kIsForCreditCardName, true}, + {UkmSuggestionFilledType::kFieldSignatureName, + Collapse(CalculateFieldSignatureForField(form.fields.front()))}, + {UkmSuggestionFilledType::kFormSignatureName, + Collapse(CalculateFormSignature(form))}}; + VerifyUkm(test_ukm_recorder_, form, UkmSuggestionFilledType::kEntryName, + {from_did_accept_suggestion, from_fill_or_preview_form, + from_fill_or_preview_form}); + // Expect |NON_FILLABLE_FORM_OR_NEW_DATA| in |AutofillFormSubmittedState| // because |field.value| is empty in |DeterminePossibleFieldTypesForUpload|. VerifySubmitFormUkm(test_ukm_recorder_, form, @@ -3168,7 +3220,7 @@ TEST_F(AutofillMetricsTest, CreditCardCheckoutFlowUserActions) { TEST_F(AutofillMetricsTest, UpiVpaUkmTest) { FormData form; form.name = ASCIIToUTF16("TestForm"); - form.origin = GURL("http://example.com/form.html"); + form.url = GURL("http://example.com/form.html"); form.action = GURL("http://example.com/submit.html"); form.main_frame_origin = url::Origin::Create(autofill_client_.form_origin()); FormFieldData field; @@ -3199,7 +3251,7 @@ TEST_F(AutofillMetricsTest, ProfileCheckoutFlowUserActions) { // Set up our form data. FormData form; form.name = ASCIIToUTF16("TestForm"); - form.origin = GURL("http://example.com/form.html"); + form.url = GURL("http://example.com/form.html"); form.action = GURL("http://example.com/submit.html"); form.main_frame_origin = url::Origin::Create(autofill_client_.form_origin()); @@ -3338,7 +3390,7 @@ TEST_F(AutofillMetricsTest, PolledCreditCardSuggestions_DebounceLogs) { // Set up the form data. FormData form; form.name = ASCIIToUTF16("TestForm"); - form.origin = GURL("http://www.foo.com/"); + form.url = GURL("http://www.foo.com/"); FormFieldData field; std::vector<ServerFieldType> field_types; @@ -3398,7 +3450,7 @@ TEST_F(AutofillMetricsTest, QueriedCreditCardFormIsSecure) { // Set up the form data. FormData form; form.name = ASCIIToUTF16("TestForm"); - form.origin = GURL("http://example.com/form.html"); + form.url = GURL("http://example.com/form.html"); form.action = GURL("http://example.com/submit.html"); form.main_frame_origin = url::Origin::Create(autofill_client_.form_origin()); @@ -3416,7 +3468,7 @@ TEST_F(AutofillMetricsTest, QueriedCreditCardFormIsSecure) { { // Simulate having seen this insecure form on page load. - form.origin = GURL("http://example.com/form.html"); + form.url = GURL("http://example.com/form.html"); form.action = GURL("http://example.com/submit.html"); form.main_frame_origin = url::Origin::Create(autofill_client_.form_origin()); @@ -3435,7 +3487,7 @@ TEST_F(AutofillMetricsTest, QueriedCreditCardFormIsSecure) { { // Simulate having seen this secure form on page load. autofill_manager_->Reset(); - form.origin = GURL("https://example.com/form.html"); + form.url = GURL("https://example.com/form.html"); form.action = GURL("https://example.com/submit.html"); form.main_frame_origin = url::Origin::Create(autofill_client_.form_origin()); @@ -3459,7 +3511,7 @@ TEST_F(AutofillMetricsTest, PolledProfileSuggestions_DebounceLogs) { // Set up the form data. FormData form; form.name = ASCIIToUTF16("TestForm"); - form.origin = GURL("http://example.com/form.html"); + form.url = GURL("http://example.com/form.html"); form.action = GURL("http://example.com/submit.html"); form.main_frame_origin = url::Origin::Create(autofill_client_.form_origin()); @@ -3516,7 +3568,7 @@ TEST_P(AutofillMetricsIFrameTest, CreditCardParsedFormEvents) { // Set up our form data. FormData form; form.name = ASCIIToUTF16("TestForm"); - form.origin = GURL("http://example.com/form.html"); + form.url = GURL("http://example.com/form.html"); form.action = GURL("http://example.com/submit.html"); form.main_frame_origin = url::Origin::Create(autofill_client_.form_origin()); @@ -3548,7 +3600,7 @@ TEST_P(AutofillMetricsIFrameTest, CreditCardInteractedFormEvents) { // Set up our form data. FormData form; form.name = ASCIIToUTF16("TestForm"); - form.origin = GURL("http://example.com/form.html"); + form.url = GURL("http://example.com/form.html"); form.action = GURL("http://example.com/submit.html"); form.main_frame_origin = url::Origin::Create(autofill_client_.form_origin()); @@ -3604,7 +3656,7 @@ TEST_P(AutofillMetricsIFrameTest, CreditCardPopupSuppressedFormEvents) { // Set up our form data. FormData form; form.name = ASCIIToUTF16("TestForm"); - form.origin = GURL("http://example.com/form.html"); + form.url = GURL("http://example.com/form.html"); form.action = GURL("http://example.com/submit.html"); form.main_frame_origin = url::Origin::Create(autofill_client_.form_origin()); @@ -3662,7 +3714,7 @@ TEST_P(AutofillMetricsIFrameTest, CreditCardShownFormEvents) { // Set up our form data. FormData form; form.name = ASCIIToUTF16("TestForm"); - form.origin = GURL("http://example.com/form.html"); + form.url = GURL("http://example.com/form.html"); form.action = GURL("http://example.com/submit.html"); form.main_frame_origin = url::Origin::Create(autofill_client_.form_origin()); @@ -3867,7 +3919,7 @@ TEST_P(AutofillMetricsIFrameTest, CreditCardSelectedFormEvents) { // Set up our form data. FormData form; form.name = ASCIIToUTF16("TestForm"); - form.origin = GURL("http://example.com/form.html"); + form.url = GURL("http://example.com/form.html"); form.action = GURL("http://example.com/submit.html"); form.main_frame_origin = url::Origin::Create(autofill_client_.form_origin()); @@ -3948,7 +4000,7 @@ TEST_P(AutofillMetricsIFrameTest, CreditCardFilledFormEvents) { // Set up our form data. FormData form; form.name = ASCIIToUTF16("TestForm"); - form.origin = GURL("http://example.com/form.html"); + form.url = GURL("http://example.com/form.html"); form.action = GURL("http://example.com/submit.html"); form.main_frame_origin = url::Origin::Create(autofill_client_.form_origin()); @@ -4189,7 +4241,7 @@ TEST_F(AutofillMetricsTest, CreditCardGetRealPanDuration) { // Set up our form data. FormData form; form.name = ASCIIToUTF16("TestForm"); - form.origin = GURL("http://example.com/form.html"); + form.url = GURL("http://example.com/form.html"); form.action = GURL("http://example.com/submit.html"); form.main_frame_origin = url::Origin::Create(autofill_client_.form_origin()); @@ -4260,7 +4312,7 @@ TEST_F(AutofillMetricsTest, // Set up our form data. FormData form; form.name = ASCIIToUTF16("TestForm"); - form.origin = GURL("http://example.com/form.html"); + form.url = GURL("http://example.com/form.html"); form.action = GURL("http://example.com/submit.html"); form.main_frame_origin = url::Origin::Create(autofill_client_.form_origin()); @@ -4302,7 +4354,7 @@ TEST_P(AutofillMetricsIFrameTest, // Set up our form data. FormData form; form.name = ASCIIToUTF16("TestForm"); - form.origin = GURL("http://example.com/form.html"); + form.url = GURL("http://example.com/form.html"); form.action = GURL("http://example.com/submit.html"); FormFieldData field; @@ -4348,7 +4400,7 @@ TEST_P(AutofillMetricsIFrameTest, // Set up our form data. FormData form; form.name = ASCIIToUTF16("TestForm"); - form.origin = GURL("http://example.com/form.html"); + form.url = GURL("http://example.com/form.html"); form.action = GURL("http://example.com/submit.html"); FormFieldData field; @@ -4395,7 +4447,7 @@ TEST_P(AutofillMetricsIFrameTest, // Set up our form data. FormData form; form.name = ASCIIToUTF16("TestForm"); - form.origin = GURL("http://example.com/form.html"); + form.url = GURL("http://example.com/form.html"); form.action = GURL("http://example.com/submit.html"); form.main_frame_origin = url::Origin::Create(autofill_client_.form_origin()); @@ -4443,7 +4495,7 @@ TEST_P(AutofillMetricsIFrameTest, // Set up our form data. FormData form; form.name = ASCIIToUTF16("TestForm"); - form.origin = GURL("http://example.com/form.html"); + form.url = GURL("http://example.com/form.html"); form.action = GURL("http://example.com/submit.html"); form.main_frame_origin = url::Origin::Create(autofill_client_.form_origin()); @@ -4491,7 +4543,7 @@ TEST_P(AutofillMetricsIFrameTest, // Set up our form data. FormData form; form.name = ASCIIToUTF16("TestForm"); - form.origin = GURL("http://example.com/form.html"); + form.url = GURL("http://example.com/form.html"); form.action = GURL("http://example.com/submit.html"); form.main_frame_origin = url::Origin::Create(autofill_client_.form_origin()); @@ -4555,7 +4607,7 @@ TEST_F(AutofillMetricsTest, ShouldNotLogFormEventNoCardForAddressForm) { // Set up our form data. FormData form; form.name = ASCIIToUTF16("TestForm"); - form.origin = GURL("http://example.com/form.html"); + form.url = GURL("http://example.com/form.html"); form.action = GURL("http://example.com/submit.html"); form.main_frame_origin = url::Origin::Create(autofill_client_.form_origin()); @@ -4596,7 +4648,7 @@ TEST_P(AutofillMetricsIFrameTest, CreditCardSubmittedFormEvents) { // Set up our form data. FormData form; form.name = ASCIIToUTF16("TestForm"); - form.origin = GURL("http://example.com/form.html"); + form.url = GURL("http://example.com/form.html"); form.action = GURL("http://example.com/submit.html"); form.main_frame_origin = url::Origin::Create(autofill_client_.form_origin()); @@ -5097,7 +5149,7 @@ TEST_P(AutofillMetricsIFrameTest, CreditCardWillSubmitFormEvents) { // Set up our form data. FormData form; form.name = ASCIIToUTF16("TestForm"); - form.origin = GURL("http://example.com/form.html"); + form.url = GURL("http://example.com/form.html"); form.action = GURL("http://example.com/submit.html"); form.main_frame_origin = url::Origin::Create(autofill_client_.form_origin()); @@ -5419,7 +5471,7 @@ TEST_F(AutofillMetricsTest, MixedParsedFormEvents) { // Set up our form data. FormData form; form.name = ASCIIToUTF16("TestForm"); - form.origin = GURL("http://example.com/form.html"); + form.url = GURL("http://example.com/form.html"); form.action = GURL("http://example.com/submit.html"); form.main_frame_origin = url::Origin::Create(autofill_client_.form_origin()); @@ -5462,7 +5514,7 @@ TEST_F(AutofillMetricsTest, AddressParsedFormEvents) { // Set up our form data. FormData form; form.name = ASCIIToUTF16("TestForm"); - form.origin = GURL("http://example.com/form.html"); + form.url = GURL("http://example.com/form.html"); form.action = GURL("http://example.com/submit.html"); form.main_frame_origin = url::Origin::Create(autofill_client_.form_origin()); @@ -5504,7 +5556,7 @@ TEST_F(AutofillMetricsTest, AddressInteractedFormEvents) { // Set up our form data. FormData form; form.name = ASCIIToUTF16("TestForm"); - form.origin = GURL("http://example.com/form.html"); + form.url = GURL("http://example.com/form.html"); form.action = GURL("http://example.com/submit.html"); form.main_frame_origin = url::Origin::Create(autofill_client_.form_origin()); @@ -5580,7 +5632,7 @@ TEST_F(AutofillMetricsTest, AddressSuppressedFormEvents) { // Set up our form data. FormData form; form.name = ASCIIToUTF16("TestForm"); - form.origin = GURL("http://example.com/form.html"); + form.url = GURL("http://example.com/form.html"); form.action = GURL("http://example.com/submit.html"); form.main_frame_origin = url::Origin::Create(autofill_client_.form_origin()); @@ -5673,7 +5725,7 @@ TEST_F(AutofillMetricsTest, AddressShownFormEvents) { // Set up our form data. FormData form; form.name = ASCIIToUTF16("TestForm"); - form.origin = GURL("http://example.com/form.html"); + form.url = GURL("http://example.com/form.html"); form.action = GURL("http://example.com/submit.html"); form.main_frame_origin = url::Origin::Create(autofill_client_.form_origin()); @@ -5799,7 +5851,7 @@ TEST_F(AutofillMetricsTest, AddressFilledFormEvents) { // Set up our form data. FormData form; form.name = ASCIIToUTF16("TestForm"); - form.origin = GURL("http://example.com/form.html"); + form.url = GURL("http://example.com/form.html"); form.action = GURL("http://example.com/submit.html"); form.main_frame_origin = url::Origin::Create(autofill_client_.form_origin()); @@ -5918,7 +5970,7 @@ TEST_F(AutofillMetricsTest, AddressSubmittedFormEvents) { // Set up our form data. FormData form; form.name = ASCIIToUTF16("TestForm"); - form.origin = GURL("http://example.com/form.html"); + form.url = GURL("http://example.com/form.html"); form.action = GURL("http://example.com/submit.html"); form.main_frame_origin = url::Origin::Create(autofill_client_.form_origin()); @@ -6132,7 +6184,7 @@ TEST_F(AutofillMetricsTest, AddressWillSubmitFormEvents) { // Set up our form data. FormData form; form.name = ASCIIToUTF16("TestForm"); - form.origin = GURL("http://example.com/form.html"); + form.url = GURL("http://example.com/form.html"); form.action = GURL("http://example.com/submit.html"); form.main_frame_origin = url::Origin::Create(autofill_client_.form_origin()); @@ -6320,7 +6372,7 @@ TEST_F(AutofillMetricsTest, CreditCardFormEventsAreSegmented) { // Set up our form data. FormData form; form.name = ASCIIToUTF16("TestForm"); - form.origin = GURL("http://example.com/form.html"); + form.url = GURL("http://example.com/form.html"); form.action = GURL("http://example.com/submit.html"); form.main_frame_origin = url::Origin::Create(autofill_client_.form_origin()); @@ -6431,7 +6483,7 @@ TEST_F(AutofillMetricsTest, AddressFormEventsAreSegmented) { // Set up our form data. FormData form; form.name = ASCIIToUTF16("TestForm"); - form.origin = GURL("http://example.com/form.html"); + form.url = GURL("http://example.com/form.html"); form.action = GURL("http://example.com/submit.html"); form.main_frame_origin = url::Origin::Create(autofill_client_.form_origin()); @@ -6519,7 +6571,7 @@ TEST_F(AutofillMetricsTest, AutofillFormSubmittedState) { // Start with a form with insufficiently many fields. FormData form; form.name = ASCIIToUTF16("TestForm"); - form.origin = GURL("http://example.com/form.html"); + form.url = GURL("http://example.com/form.html"); form.action = GURL("http://example.com/submit.html"); form.main_frame_origin = url::Origin::Create(autofill_client_.form_origin()); @@ -6821,7 +6873,7 @@ TEST_F( AutofillFormSubmittedState_DoNotCountUnfilledFieldsWithOnlyFillWhenFocused) { FormData form; form.name = ASCIIToUTF16("TestForm"); - form.origin = GURL("http://example.com/form.html"); + form.url = GURL("http://example.com/form.html"); form.action = GURL("http://example.com/submit.html"); form.main_frame_origin = url::Origin::Create(autofill_client_.form_origin()); @@ -6952,7 +7004,7 @@ TEST_F(AutofillMetricsTest, UserHappinessFormInteraction_EmptyForm) { // Load a fillable form. FormData form; form.name = ASCIIToUTF16("TestForm"); - form.origin = GURL("http://example.com/form.html"); + form.url = GURL("http://example.com/form.html"); form.action = GURL("http://example.com/submit.html"); form.main_frame_origin = url::Origin::Create(autofill_client_.form_origin()); @@ -6978,7 +7030,7 @@ TEST_F(AutofillMetricsTest, UserHappinessFormInteraction_CreditCardForm) { // Load a fillable form. FormData form; form.name = ASCIIToUTF16("TestForm"); - form.origin = GURL("https://example.com/form.html"); + form.url = GURL("https://example.com/form.html"); form.action = GURL("https://example.com/submit.html"); form.main_frame_origin = url::Origin::Create(autofill_client_.form_origin()); @@ -7147,7 +7199,7 @@ TEST_F(AutofillMetricsTest, UserHappinessFormInteraction_AddressForm) { // Load a fillable form. FormData form; form.name = ASCIIToUTF16("TestForm"); - form.origin = GURL("http://example.com/form.html"); + form.url = GURL("http://example.com/form.html"); form.action = GURL("http://example.com/submit.html"); form.main_frame_origin = url::Origin::Create(autofill_client_.form_origin()); @@ -7395,7 +7447,7 @@ TEST_F(AutofillMetricsTest, FormFillDuration) { // Load a fillable form. FormData form; form.name = ASCIIToUTF16("TestForm"); - form.origin = GURL("http://example.com/form.html"); + form.url = GURL("http://example.com/form.html"); form.action = GURL("http://example.com/submit.html"); form.main_frame_origin = url::Origin::Create(autofill_client_.form_origin()); @@ -7800,7 +7852,7 @@ TEST_F(AutofillMetricsTest, ProfileActionOnFormSubmitted) { // Load a fillable form. FormData form; form.name = ASCIIToUTF16("TestForm"); - form.origin = GURL("http://example.com/form.html"); + form.url = GURL("http://example.com/form.html"); form.action = GURL("http://example.com/submit.html"); form.main_frame_origin = url::Origin::Create(autofill_client_.form_origin()); @@ -7925,7 +7977,7 @@ class AutofillMetricsParseQueryResponseTest : public testing::Test { public: void SetUp() override { FormData form; - form.origin = GURL("http://foo.com"); + form.url = GURL("http://foo.com"); form.main_frame_origin = url::Origin::Create(GURL("http://foo_root.com")); FormFieldData field; field.form_control_type = "text"; @@ -8049,7 +8101,7 @@ TEST_F(AutofillMetricsTest, NonsecureCreditCardForm) { // Set up our form data. FormData form; form.name = ASCIIToUTF16("TestForm"); - form.origin = GURL("http://example.com/form.html"); + form.url = GURL("http://example.com/form.html"); form.action = GURL("http://example.com/submit.html"); GURL frame_origin("http://example_root.com/form.html"); form.main_frame_origin = url::Origin::Create(frame_origin); @@ -8107,7 +8159,7 @@ TEST_F(AutofillMetricsTest, // Set up our form data. FormData form; form.name = ASCIIToUTF16("TestForm"); - form.origin = GURL("https://example.com/form.html"); + form.url = GURL("https://example.com/form.html"); form.action = GURL("http://example.com/submit.html"); form.main_frame_origin = url::Origin::Create(GURL("http://example_root.com/form.html")); @@ -8234,7 +8286,7 @@ TEST_F(AutofillMetricsTest, MAYBE_AutofillSuggestionShownTest) { false /* include_full_server_credit_card */); FormData form; form.name = ASCIIToUTF16("TestForm"); - form.origin = GURL("http://example_cc.com/form.html"); + form.url = GURL("http://example_cc.com/form.html"); form.action = GURL("http://example_cc.com/submit.html"); form.main_frame_origin = url::Origin::Create(autofill_client_.form_origin()); @@ -8267,14 +8319,13 @@ TEST_F(AutofillMetricsTest, MAYBE_AutofillSuggestionShownTest) { } TEST_F(AutofillMetricsTest, DynamicFormMetrics) { - scoped_feature_list_.InitWithFeatures( - {features::kAutofillDynamicForms}, - {features::kAutofillRestrictUnownedFieldsToFormlessCheckout}); + scoped_feature_list_.InitAndDisableFeature( + features::kAutofillRestrictUnownedFieldsToFormlessCheckout); // Set up our form data. FormData form; form.name = ASCIIToUTF16("TestForm"); - form.origin = GURL("http://example.com/form.html"); + form.url = GURL("http://example.com/form.html"); form.action = GURL("http://example.com/submit.html"); FormFieldData field; std::vector<ServerFieldType> field_types; @@ -8396,7 +8447,7 @@ TEST_F(AutofillMetricsTest, LogUserHappinessBySecurityLevel_FromFormEvents) { // Load a fillable form. FormData form; form.name = ASCIIToUTF16("TestForm"); - form.origin = GURL("http://example.com/form.html"); + form.url = GURL("http://example.com/form.html"); form.action = GURL("http://example.com/submit.html"); form.main_frame_origin = url::Origin::Create(autofill_client_.form_origin()); @@ -8639,9 +8690,10 @@ TEST_F(AutofillMetricsTest, LogSaveCardPromptMetric_BySyncState) { /*is_reshow=*/true, AutofillClient::SaveCreditCardOptions(), /*previous_save_credit_card_prompt_user_decision=*/0, security_state::SecurityLevel::SECURE, - SyncSigninState::kSignedInAndSyncFeature); + SyncSigninState::kSignedInAndSyncFeatureEnabled); histogram_tester.ExpectBucketCount( - "Autofill.SaveCreditCardPrompt.Local.Reshows.SignedInAndSyncFeature", + "Autofill.SaveCreditCardPrompt.Local.Reshows." + "SignedInAndSyncFeatureEnabled", AutofillMetrics::SAVE_CARD_PROMPT_SHOWN, 1); } } diff --git a/chromium/components/autofill/core/browser/autofill_profile.cc b/chromium/components/autofill/core/browser/autofill_profile.cc index dd8c59b8f7a..2260617f9a6 100644 --- a/chromium/components/autofill/core/browser/autofill_profile.cc +++ b/chromium/components/autofill/core/browser/autofill_profile.cc @@ -12,11 +12,11 @@ #include <set> #include "base/guid.h" +#include "base/hash/sha1.h" #include "base/i18n/case_conversion.h" #include "base/i18n/char_iterator.h" #include "base/logging.h" #include "base/metrics/histogram_macros.h" -#include "base/sha1.h" #include "base/stl_util.h" #include "base/strings/string_number_conversions.h" #include "base/strings/string_util.h" @@ -228,6 +228,7 @@ ServerFieldType NormalizeTypeForValidityCheck(ServerFieldType type) { AutofillProfile::AutofillProfile(const std::string& guid, const std::string& origin) : AutofillDataModel(guid, origin), + company_(this), phone_number_(this), record_type_(LOCAL_PROFILE), has_converted_(false), @@ -235,6 +236,7 @@ AutofillProfile::AutofillProfile(const std::string& guid, AutofillProfile::AutofillProfile(RecordType type, const std::string& server_id) : AutofillDataModel(base::GenerateGUID(), std::string()), + company_(this), phone_number_(this), server_id_(server_id), record_type_(type), @@ -245,6 +247,7 @@ AutofillProfile::AutofillProfile(RecordType type, const std::string& server_id) AutofillProfile::AutofillProfile() : AutofillDataModel(base::GenerateGUID(), std::string()), + company_(this), phone_number_(this), record_type_(LOCAL_PROFILE), has_converted_(false), @@ -252,6 +255,7 @@ AutofillProfile::AutofillProfile() AutofillProfile::AutofillProfile(const AutofillProfile& profile) : AutofillDataModel(std::string(), std::string()), + company_(this), phone_number_(this), weak_ptr_factory_(this) { operator=(profile); @@ -277,6 +281,7 @@ AutofillProfile& AutofillProfile::operator=(const AutofillProfile& profile) { name_ = profile.name_; email_ = profile.email_; company_ = profile.company_; + company_.set_profile(this); phone_number_ = profile.phone_number_; phone_number_.set_profile(this); @@ -444,12 +449,6 @@ int AutofillProfile::Compare(const AutofillProfile& profile) const { return 0; } -bool AutofillProfile::EqualsSansOrigin(const AutofillProfile& profile) const { - return guid() == profile.guid() && - language_code() == profile.language_code() && - Compare(profile) == 0; -} - bool AutofillProfile::EqualsForSyncPurposes(const AutofillProfile& profile) const { return use_count() == profile.use_count() && @@ -565,7 +564,7 @@ bool AutofillProfile::MergeDataFrom(const AutofillProfile& profile, NameInfo name; EmailInfo email; - CompanyInfo company; + CompanyInfo company(this); PhoneNumber phone_number(this); Address address; @@ -665,16 +664,6 @@ bool AutofillProfile::SaveAdditionalInfo(const AutofillProfile& profile, } // static -bool AutofillProfile::SupportsMultiValue(ServerFieldType type) { - FieldTypeGroup group = AutofillType(type).group(); - return group == NAME || - group == NAME_BILLING || - group == EMAIL || - group == PHONE_HOME || - group == PHONE_BILLING; -} - -// static void AutofillProfile::CreateDifferentiatingLabels( const std::vector<AutofillProfile*>& profiles, const std::string& app_locale, @@ -832,12 +821,24 @@ bool AutofillProfile::HasGreaterFrescocencyThan( base::Time comparison_time, bool use_client_validation, bool use_server_validation) const { + double score = GetFrecencyScore(comparison_time); + double other_score = other->GetFrecencyScore(comparison_time); + + const double kEpsilon = 0.001; + if (std::fabs(score - other_score) > kEpsilon) + return score > other_score; + bool is_valid = (!use_client_validation || IsValidByClient()) && (!use_server_validation || IsValidByServer()); bool other_is_valid = (!use_client_validation || other->IsValidByClient()) && (!use_server_validation || other->IsValidByServer()); - if (is_valid == other_is_valid) - return HasGreaterFrecencyThan(other, comparison_time); + + if (is_valid == other_is_valid) { + if (use_date() != other->use_date()) + return use_date() > other->use_date(); + return guid() > other->guid(); + } + if (is_valid && !other_is_valid) return true; return false; diff --git a/chromium/components/autofill/core/browser/autofill_profile.h b/chromium/components/autofill/core/browser/autofill_profile.h index bf1c5494762..17126388e74 100644 --- a/chromium/components/autofill/core/browser/autofill_profile.h +++ b/chromium/components/autofill/core/browser/autofill_profile.h @@ -100,9 +100,6 @@ class AutofillProfile : public AutofillDataModel { // themselves. int Compare(const AutofillProfile& profile) const; - // Same as operator==, but ignores differences in origin. - bool EqualsSansOrigin(const AutofillProfile& profile) const; - // Same as operator==, but ignores differences in guid and cares about // differences in usage stats. bool EqualsForSyncPurposes(const AutofillProfile& profile) const; @@ -149,9 +146,6 @@ class AutofillProfile : public AutofillDataModel { bool SaveAdditionalInfo(const AutofillProfile& profile, const std::string& app_locale); - // Returns |true| if |type| accepts multi-values. - static bool SupportsMultiValue(ServerFieldType type); - // Creates a differentiating label for each of the |profiles|. // Labels consist of the minimal differentiating combination of: // 1. Full name. @@ -208,9 +202,8 @@ class AutofillProfile : public AutofillDataModel { // Returns true if the current profile has greater frescocency than the // |other|. Frescocency is a combination of validation score and frecency to // determine the relevance of the profile. Frescocency is a total order: it - // puts all the valid profiles before the invalid ones, and uses frecency - // (another total order) in case of tie. Please see - // AutofillDataModel::HasGreaterFrecencyThan. + // puts all the valid profiles before the invalid ones in case of frecency + // tie. Please see AutofillDataModel::HasGreaterFrecencyThan. bool HasGreaterFrescocencyThan(const AutofillProfile* other, base::Time comparison_time, bool use_client_validation, diff --git a/chromium/components/autofill/core/browser/autofill_profile_comparator_unittest.cc b/chromium/components/autofill/core/browser/autofill_profile_comparator_unittest.cc index 36da4fdf765..0fac04009e1 100644 --- a/chromium/components/autofill/core/browser/autofill_profile_comparator_unittest.cc +++ b/chromium/components/autofill/core/browser/autofill_profile_comparator_unittest.cc @@ -6,11 +6,13 @@ #include "base/guid.h" #include "base/strings/utf_string_conversions.h" +#include "base/test/scoped_feature_list.h" #include "components/autofill/core/browser/autofill_profile.h" #include "components/autofill/core/browser/autofill_test_utils.h" #include "components/autofill/core/browser/contact_info.h" #include "components/autofill/core/browser/country_names.h" #include "components/autofill/core/browser/field_types.h" +#include "components/autofill/core/common/autofill_features.h" #include "testing/gtest/include/gtest/gtest.h" // Field Type Constants @@ -758,9 +760,16 @@ TEST_F(AutofillProfileComparatorTest, MergeEmailAddresses) { } TEST_F(AutofillProfileComparatorTest, MergeCompanyNames) { + base::test::ScopedFeatureList scoped_features; + scoped_features.InitWithFeatures( + /*enabled_features=*/{autofill::features:: + kAutofillRejectCompanyBirthyear}, + /*disabled_features=*/{}); + static const char kCompanyA[] = "Some Company"; static const char kCompanyB[] = "SÔMÈ ÇÖMPÁÑÝ"; static const char kCompanyC[] = "SÔMÈ ÇÖMPÁÑÝ A.G."; + static const char kCompanyD[] = "1987"; CompanyInfo company_a; company_a.SetRawInfo(COMPANY_NAME, UTF8ToUTF16(kCompanyA)); @@ -781,15 +790,31 @@ TEST_F(AutofillProfileComparatorTest, MergeCompanyNames) { AutofillProfile profile_c = CreateProfileWithCompanyName(kCompanyC); profile_c.set_use_date(profile_a.use_date() - base::TimeDelta::FromDays(1)); + // Company Name D is in the format of a birthyear, invalid and non-verified. + CompanyInfo company_d; + company_d.SetRawInfo(COMPANY_NAME, UTF8ToUTF16(kCompanyD)); + AutofillProfile profile_d = CreateProfileWithCompanyName(kCompanyD); + profile_a.set_use_date(base::Time::Now()); + MergeCompanyNamesAndExpect(profile_a, profile_a, company_a); MergeCompanyNamesAndExpect(profile_a, profile_b, company_b); MergeCompanyNamesAndExpect(profile_a, profile_c, company_c); + MergeCompanyNamesAndExpect(profile_a, profile_d, company_a); + MergeCompanyNamesAndExpect(profile_b, profile_a, company_b); MergeCompanyNamesAndExpect(profile_b, profile_b, company_b); MergeCompanyNamesAndExpect(profile_b, profile_c, company_c); + MergeCompanyNamesAndExpect(profile_b, profile_d, company_b); + MergeCompanyNamesAndExpect(profile_c, profile_a, company_c); MergeCompanyNamesAndExpect(profile_c, profile_b, company_c); MergeCompanyNamesAndExpect(profile_c, profile_c, company_c); + MergeCompanyNamesAndExpect(profile_c, profile_d, company_c); + + MergeCompanyNamesAndExpect(profile_d, profile_a, company_a); + MergeCompanyNamesAndExpect(profile_d, profile_b, company_b); + MergeCompanyNamesAndExpect(profile_d, profile_c, company_c); + MergeCompanyNamesAndExpect(profile_d, profile_d, company_d); } TEST_F(AutofillProfileComparatorTest, MergePhoneNumbers_NA) { diff --git a/chromium/components/autofill/core/browser/autofill_profile_unittest.cc b/chromium/components/autofill/core/browser/autofill_profile_unittest.cc index 539a255e776..46f955119e1 100644 --- a/chromium/components/autofill/core/browser/autofill_profile_unittest.cc +++ b/chromium/components/autofill/core/browser/autofill_profile_unittest.cc @@ -1943,7 +1943,7 @@ TEST_P(HasGreaterFrescocencyTest, HasGreaterFrescocency) { test_case.server_validity_state_b, AutofillDataModel::SERVER); - base::Time now = base::Time::Now(); + const base::Time now = base::Time::Now(); if (test_case.expectation == EQUAL) { EXPECT_EQ(profile_a.HasGreaterFrecencyThan(&profile_b, now), @@ -1963,6 +1963,36 @@ TEST_P(HasGreaterFrescocencyTest, HasGreaterFrescocency) { test_case.use_server_validation)); } +// Validity is only checked in case of tie in frecency. Frecency has greater +// priority than validity in frescocency. +TEST_P(HasGreaterFrescocencyTest, PriorityCheck) { + AutofillProfile profile_invalid("00000000-0000-0000-0000-000000000001", ""); + AutofillProfile profile_valid("00000000-0000-0000-0000-000000000002", ""); + + profile_invalid.SetValidityState(EMAIL_ADDRESS, AutofillDataModel::INVALID, + AutofillDataModel::CLIENT); + profile_valid.SetValidityState(ADDRESS_HOME_ZIP, AutofillDataModel::INVALID, + AutofillDataModel::SERVER); + + profile_valid.SetValidityState(ADDRESS_HOME_CITY, AutofillDataModel::VALID, + AutofillDataModel::CLIENT); + profile_valid.SetValidityState(PHONE_HOME_NUMBER, AutofillDataModel::VALID, + AutofillDataModel::SERVER); + + profile_invalid.set_use_count(100); + profile_valid.set_use_count(10); + + const base::Time now = base::Time::Now(); + const base::Time past = now - base::TimeDelta::FromDays(1); + + profile_invalid.set_use_date(now); + profile_valid.set_use_date(past); + + EXPECT_TRUE(profile_invalid.HasGreaterFrecencyThan(&profile_valid, now)); + EXPECT_TRUE(profile_invalid.HasGreaterFrescocencyThan(&profile_valid, now, + true, true)); +} + INSTANTIATE_TEST_SUITE_P( AutofillProfileTest, HasGreaterFrescocencyTest, diff --git a/chromium/components/autofill/core/browser/autofill_test_utils.cc b/chromium/components/autofill/core/browser/autofill_test_utils.cc index ffab385a580..9c3e280433b 100644 --- a/chromium/components/autofill/core/browser/autofill_test_utils.cc +++ b/chromium/components/autofill/core/browser/autofill_test_utils.cc @@ -115,7 +115,7 @@ void CreateTestAddressFormData(FormData* form, ASCIIToUTF16("MyForm") + ASCIIToUTF16(unique_id ? unique_id : ""); form->button_titles = {std::make_pair( ASCIIToUTF16("Submit"), ButtonTitleType::BUTTON_ELEMENT_SUBMIT_TYPE)}; - form->origin = GURL("http://myform.com/form.html"); + form->url = GURL("http://myform.com/form.html"); form->action = GURL("http://myform.com/submit.html"); form->main_frame_origin = url::Origin::Create(GURL("https://myform_root.com/form.html")); @@ -185,7 +185,7 @@ void CreateTestPersonalInformationFormData(FormData* form, const char* unique_id) { form->name = ASCIIToUTF16("MyForm") + ASCIIToUTF16(unique_id ? unique_id : ""); - form->origin = GURL("http://myform.com/form.html"); + form->url = GURL("http://myform.com/form.html"); form->action = GURL("http://myform.com/submit.html"); form->main_frame_origin = url::Origin::Create(GURL("https://myform_root.com/form.html")); @@ -210,12 +210,12 @@ void CreateTestCreditCardFormData(FormData* form, form->name = ASCIIToUTF16("MyForm") + ASCIIToUTF16(unique_id ? unique_id : ""); if (is_https) { - form->origin = GURL("https://myform.com/form.html"); + form->url = GURL("https://myform.com/form.html"); form->action = GURL("https://myform.com/submit.html"); form->main_frame_origin = url::Origin::Create(GURL("https://myform_root.com/form.html")); } else { - form->origin = GURL("http://myform.com/form.html"); + form->url = GURL("http://myform.com/form.html"); form->action = GURL("http://myform.com/submit.html"); form->main_frame_origin = url::Origin::Create(GURL("http://myform_root.com/form.html")); @@ -337,12 +337,6 @@ AutofillProfile GetVerifiedProfile() { return profile; } -AutofillProfile GetVerifiedProfile2() { - AutofillProfile profile(GetFullProfile2()); - profile.set_origin(kSettingsOrigin); - return profile; -} - AutofillProfile GetServerProfile() { AutofillProfile profile(AutofillProfile::SERVER_PROFILE, "id1"); // Note: server profiles don't have email addresses and only have full names. diff --git a/chromium/components/autofill/core/browser/autofill_test_utils.h b/chromium/components/autofill/core/browser/autofill_test_utils.h index 02eb5847a07..9b74aabc9b7 100644 --- a/chromium/components/autofill/core/browser/autofill_test_utils.h +++ b/chromium/components/autofill/core/browser/autofill_test_utils.h @@ -112,9 +112,6 @@ AutofillProfile GetIncompleteProfile2(); // Returns a verified profile full of dummy info. AutofillProfile GetVerifiedProfile(); -// Returns a verified profile full of dummy info, different to the above. -AutofillProfile GetVerifiedProfile2(); - // Returns a server profile full of dummy info. AutofillProfile GetServerProfile(); @@ -127,12 +124,6 @@ CreditCard GetCreditCard(); // Returns a credit card full of dummy info, different to the above. CreditCard GetCreditCard2(); -// Returns a verified credit card full of dummy info. -CreditCard GetVerifiedCreditCard(); - -// Returns a verified credit card full of dummy info, different to the above. -CreditCard GetVerifiedCreditCard2(); - // Returns a masked server card full of dummy info. CreditCard GetMaskedServerCard(); CreditCard GetMaskedServerCardAmex(); diff --git a/chromium/components/autofill/core/browser/autofill_type.cc b/chromium/components/autofill/core/browser/autofill_type.cc index 62bb3c04655..e873833612a 100644 --- a/chromium/components/autofill/core/browser/autofill_type.cc +++ b/chromium/components/autofill/core/browser/autofill_type.cc @@ -777,10 +777,10 @@ std::string AutofillType::ServerFieldTypeToString(ServerFieldType type) { return "SEARCH_TERM"; case PRICE: return "PRICE"; - + case NOT_PASSWORD: + return "NOT_PASSWORD"; case AMBIGUOUS_TYPE: return "AMBIGUOUS_TYPE"; - case MAX_VALID_FIELD_TYPE: return std::string(); } diff --git a/chromium/components/autofill/core/browser/contact_form_label_formatter.cc b/chromium/components/autofill/core/browser/contact_form_label_formatter.cc index 47701675865..48feb02b774 100644 --- a/chromium/components/autofill/core/browser/contact_form_label_formatter.cc +++ b/chromium/components/autofill/core/browser/contact_form_label_formatter.cc @@ -4,33 +4,54 @@ #include "components/autofill/core/browser/contact_form_label_formatter.h" +#include "components/autofill/core/browser/autofill_data_util.h" +#include "components/autofill/core/browser/label_formatter_utils.h" + namespace autofill { ContactFormLabelFormatter::ContactFormLabelFormatter( const std::string& app_locale, ServerFieldType focused_field_type, - const std::vector<ServerFieldType>& field_types, - const std::set<FieldTypeGroup>& field_type_groups) - : LabelFormatter(app_locale, focused_field_type, field_types), - field_type_groups_(field_type_groups), - filtered_field_type_groups_(field_type_groups) { - for (const ServerFieldType& type : field_types) { - if (type != focused_field_type) { - field_types_for_labels_.push_back(type); - } + uint32_t groups, + const std::vector<ServerFieldType>& field_types) + : LabelFormatter(app_locale, focused_field_type, groups, field_types) {} + +ContactFormLabelFormatter::~ContactFormLabelFormatter() {} + +// Note that the order--name, phone, and email--in which parts of the label +// are possibly added ensures that the label is formatted correctly for +// |focused_group| and for this kind of formatter. +base::string16 ContactFormLabelFormatter::GetLabelForProfile( + const AutofillProfile& profile, + FieldTypeGroup focused_group) const { + std::vector<base::string16> label_parts; + if (focused_group != NAME) { + AddLabelPartIfNotEmpty(GetLabelName(profile, app_locale()), &label_parts); + } + + if (focused_group != PHONE_HOME) { + AddLabelPartIfNotEmpty(MaybeGetPhone(profile), &label_parts); } - const FieldTypeGroup group = - AutofillType(AutofillType(focused_field_type).GetStorableType()).group(); - filtered_field_type_groups_.erase(group); + + if (focused_group != EMAIL) { + AddLabelPartIfNotEmpty(MaybeGetEmail(profile), &label_parts); + } + + return ConstructLabelLine(label_parts); } -ContactFormLabelFormatter::~ContactFormLabelFormatter() {} +base::string16 ContactFormLabelFormatter::MaybeGetEmail( + const AutofillProfile& profile) const { + return data_util::ContainsEmail(groups()) + ? GetLabelEmail(profile, app_locale()) + : base::string16(); +} -std::vector<base::string16> ContactFormLabelFormatter::GetLabels( - const std::vector<AutofillProfile*>& profiles) const { - // TODO(crbug.com/936168): Implement GetLabels(). - std::vector<base::string16> labels; - return labels; +base::string16 ContactFormLabelFormatter::MaybeGetPhone( + const AutofillProfile& profile) const { + return data_util::ContainsPhone(groups()) + ? GetLabelPhone(profile, app_locale()) + : base::string16(); } } // namespace autofill diff --git a/chromium/components/autofill/core/browser/contact_form_label_formatter.h b/chromium/components/autofill/core/browser/contact_form_label_formatter.h index 38684976af4..be4eb1cab56 100644 --- a/chromium/components/autofill/core/browser/contact_form_label_formatter.h +++ b/chromium/components/autofill/core/browser/contact_form_label_formatter.h @@ -5,7 +5,6 @@ #ifndef COMPONENTS_AUTOFILL_CORE_BROWSER_CONTACT_FORM_LABEL_FORMATTER_H_ #define COMPONENTS_AUTOFILL_CORE_BROWSER_CONTACT_FORM_LABEL_FORMATTER_H_ -#include <set> #include <string> #include <vector> @@ -22,26 +21,23 @@ class ContactFormLabelFormatter : public LabelFormatter { public: ContactFormLabelFormatter(const std::string& app_locale, ServerFieldType focused_field_type, - const std::vector<ServerFieldType>& field_types, - const std::set<FieldTypeGroup>& field_type_groups); + uint32_t groups, + const std::vector<ServerFieldType>& field_types); ~ContactFormLabelFormatter() override; - std::vector<base::string16> GetLabels( - const std::vector<AutofillProfile*>& profiles) const override; + base::string16 GetLabelForProfile( + const AutofillProfile& profile, + FieldTypeGroup focused_group) const override; private: - // A collection of field types that can be used to make labels. This - // collection excludes the focused_field_type_. - std::vector<ServerFieldType> field_types_for_labels_; + // Returns |profile|'s email address if |profile| has a valid email address + // and if this formatter's associated form has an email field. + base::string16 MaybeGetEmail(const AutofillProfile& profile) const; - // A collection of meaningful FieldTypeGroups in the form with which the user - // is interacting. - std::set<FieldTypeGroup> field_type_groups_; - - // A collection of meaningful FieldTypeGroups in the form with which the user - // is interacting minus the focused field's corresponding FieldTypeGroup. - std::set<FieldTypeGroup> filtered_field_type_groups_; + // Returns |profile|'s phone number if |profile| has a phone number and if + // this formatter's associated form has a phone field. + base::string16 MaybeGetPhone(const AutofillProfile& profile) const; }; } // namespace autofill diff --git a/chromium/components/autofill/core/browser/contact_form_label_formatter_unittest.cc b/chromium/components/autofill/core/browser/contact_form_label_formatter_unittest.cc new file mode 100644 index 00000000000..d9f18e37bfc --- /dev/null +++ b/chromium/components/autofill/core/browser/contact_form_label_formatter_unittest.cc @@ -0,0 +1,306 @@ +// Copyright 2019 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "components/autofill/core/browser/contact_form_label_formatter.h" + +#include <memory> +#include <string> +#include <vector> + +#include "base/guid.h" +#include "base/strings/string16.h" +#include "base/strings/utf_string_conversions.h" +#include "components/autofill/core/browser/autofill_profile.h" +#include "components/autofill/core/browser/autofill_test_utils.h" +#include "components/autofill/core/browser/field_types.h" +#include "components/autofill/core/browser/label_formatter_utils.h" +#include "testing/gmock/include/gmock/gmock.h" +#include "testing/gtest/include/gtest/gtest.h" + +using testing::ElementsAre; + +namespace autofill { +namespace { + +std::vector<ServerFieldType> GetNamePhoneAndEmailFieldTypes() { + return {NAME_FIRST, NAME_LAST, PHONE_HOME_WHOLE_NUMBER, EMAIL_ADDRESS}; +} + +TEST(ContactFormLabelFormatterTest, GetLabelsWithMissingProfiles) { + const std::vector<AutofillProfile*> profiles{}; + const std::unique_ptr<LabelFormatter> formatter = LabelFormatter::Create( + "en-US", NAME_FIRST, GetNamePhoneAndEmailFieldTypes(), profiles); + EXPECT_TRUE(formatter->GetLabels(profiles).empty()); +} + +TEST(ContactFormLabelFormatterTest, GetLabelsForUSProfilesAndFocusedName) { + AutofillProfile profile1 = + AutofillProfile(base::GenerateGUID(), test::kEmptyOrigin); + test::SetProfileInfo(&profile1, "John", "F", "Kennedy", "jfk@gmail.com", "", + "333 Washington St", "", "Brookline", "MA", "02445", + "US", "16177302000"); + + AutofillProfile profile2 = + AutofillProfile(base::GenerateGUID(), test::kEmptyOrigin); + test::SetProfileInfo(&profile2, "Jackie", "", "Kennedy", "jackie@outlook.com", + "", "151 Irving Ave", "", "Hyannis", "MA", "02601", "US", + ""); + + AutofillProfile profile3 = + AutofillProfile(base::GenerateGUID(), test::kEmptyOrigin); + test::SetProfileInfo(&profile3, "Paul", "", "Revere", "", "", "19 N Square", + "", "Boston", "MA", "02113", "US", "+1 (617) 523-2338"); + + AutofillProfile profile4 = + AutofillProfile(base::GenerateGUID(), test::kEmptyOrigin); + test::SetProfileInfo(&profile4, "John", "", "Adams", "", "", + "141 Franklin St.", "", "Quincy", "MA", "02169", "US", + ""); + + const std::vector<AutofillProfile*> profiles{&profile1, &profile2, &profile3, + &profile4}; + const std::unique_ptr<LabelFormatter> formatter = LabelFormatter::Create( + "en-US", NAME_LAST, GetNamePhoneAndEmailFieldTypes(), profiles); + + EXPECT_THAT( + formatter->GetLabels(profiles), + ElementsAre(ConstructLabelLine({base::ASCIIToUTF16("(617) 730-2000"), + base::ASCIIToUTF16("jfk@gmail.com")}), + base::ASCIIToUTF16("jackie@outlook.com"), + base::ASCIIToUTF16("(617) 523-2338"), base::string16())); +} + +TEST(ContactFormLabelFormatterTest, GetLabelsForUSProfilesAndFocusedEmail) { + AutofillProfile profile1 = + AutofillProfile(base::GenerateGUID(), test::kEmptyOrigin); + test::SetProfileInfo(&profile1, "John", "F", "Kennedy", "jfk@gmail.com", "", + "333 Washington St", "", "Brookline", "MA", "02445", + "US", "16177302000"); + + AutofillProfile profile2 = + AutofillProfile(base::GenerateGUID(), test::kEmptyOrigin); + test::SetProfileInfo(&profile2, "Jackie", "", "Kennedy", "jackie@outlook.com", + "", "151 Irving Ave", "", "Hyannis", "MA", "02601", "US", + ""); + + AutofillProfile profile3 = + AutofillProfile(base::GenerateGUID(), test::kEmptyOrigin); + test::SetProfileInfo(&profile3, "Paul", "", "Revere", "", "", "19 N Square", + "", "Boston", "MA", "02113", "US", "+1 (617) 523-2338"); + + AutofillProfile profile4 = + AutofillProfile(base::GenerateGUID(), test::kEmptyOrigin); + test::SetProfileInfo(&profile4, "", "", "", "", "", "141 Franklin St.", "", + "Quincy", "MA", "02169", "US", ""); + + const std::vector<AutofillProfile*> profiles{&profile1, &profile2, &profile3, + &profile4}; + const std::unique_ptr<LabelFormatter> formatter = LabelFormatter::Create( + "en-US", EMAIL_ADDRESS, GetNamePhoneAndEmailFieldTypes(), profiles); + + EXPECT_THAT( + formatter->GetLabels(profiles), + ElementsAre(ConstructLabelLine({base::ASCIIToUTF16("John F Kennedy"), + base::ASCIIToUTF16("(617) 730-2000")}), + base::ASCIIToUTF16("Jackie Kennedy"), + ConstructLabelLine({base::ASCIIToUTF16("Paul Revere"), + base::ASCIIToUTF16("(617) 523-2338")}), + base::string16())); +} + +TEST(ContactFormLabelFormatterTest, GetLabelsForUSProfilesAndFocusedPhone) { + AutofillProfile profile1 = + AutofillProfile(base::GenerateGUID(), test::kEmptyOrigin); + test::SetProfileInfo(&profile1, "John", "F", "Kennedy", "jfk@gmail.com", "", + "333 Washington St", "", "Brookline", "MA", "02445", + "US", "16177302000"); + + AutofillProfile profile2 = + AutofillProfile(base::GenerateGUID(), test::kEmptyOrigin); + test::SetProfileInfo(&profile2, "Jackie", "", "Kennedy", "jackie@outlook.com", + "", "151 Irving Ave", "", "Hyannis", "MA", "02601", "US", + ""); + + AutofillProfile profile3 = + AutofillProfile(base::GenerateGUID(), test::kEmptyOrigin); + test::SetProfileInfo(&profile3, "Paul", "", "Revere", "", "", "19 N Square", + "", "Boston", "MA", "02113", "US", "+1 (617) 523-2338"); + + AutofillProfile profile4 = + AutofillProfile(base::GenerateGUID(), test::kEmptyOrigin); + test::SetProfileInfo(&profile4, "", "", "", "", "", "141 Franklin St.", "", + "Quincy", "MA", "02169", "US", ""); + + const std::vector<AutofillProfile*> profiles{&profile1, &profile2, &profile3, + &profile4}; + const std::unique_ptr<LabelFormatter> formatter = + LabelFormatter::Create("en-US", PHONE_HOME_WHOLE_NUMBER, + GetNamePhoneAndEmailFieldTypes(), profiles); + + EXPECT_THAT( + formatter->GetLabels(profiles), + ElementsAre( + ConstructLabelLine({base::ASCIIToUTF16("John F Kennedy"), + base::ASCIIToUTF16("jfk@gmail.com")}), + ConstructLabelLine({base::ASCIIToUTF16("Jackie Kennedy"), + base::ASCIIToUTF16("jackie@outlook.com")}), + base::ASCIIToUTF16("Paul Revere"), base::string16())); +} + +TEST(ContactFormLabelFormatterTest, GetLabelsForBRProfilesAndFocusedName) { + AutofillProfile profile1 = + AutofillProfile(base::GenerateGUID(), test::kEmptyOrigin); + test::SetProfileInfo(&profile1, "Tarsila", "do", "Amaral", "tarsila@aol.com", + "", "Av. Pedro Álvares Cabral, 1301", "", "Vila Mariana", + "São Paulo", "SP", "04094-050", "BR", + "+55 11 2648-0254"); + + AutofillProfile profile2 = + AutofillProfile(base::GenerateGUID(), test::kEmptyOrigin); + test::SetProfileInfo(&profile2, "Artur", "", "Avila", "aavila@uol.com.br", "", + "Estr. Dona Castorina, 110", "", "Jardim Botânico", + "Rio de Janeiro", "RJ", "22460-320", "BR", + "21987650000"); + + const std::vector<AutofillProfile*> profiles{&profile1, &profile2}; + const std::unique_ptr<LabelFormatter> formatter = LabelFormatter::Create( + "pt-BR", NAME_LAST, GetNamePhoneAndEmailFieldTypes(), profiles); + + EXPECT_THAT( + formatter->GetLabels(profiles), + ElementsAre( + ConstructLabelLine({base::ASCIIToUTF16("(11) 2648-0254"), + base::ASCIIToUTF16("tarsila@aol.com")}), + ConstructLabelLine({base::ASCIIToUTF16("(21) 98765-0000"), + base::ASCIIToUTF16("aavila@uol.com.br")}))); +} + +TEST(ContactFormLabelFormatterTest, GetLabelsForBRProfilesAndFocusedEmail) { + AutofillProfile profile1 = + AutofillProfile(base::GenerateGUID(), test::kEmptyOrigin); + test::SetProfileInfo(&profile1, "Tarsila", "do", "Amaral", "tarsila@aol.com", + "", "Av. Pedro Álvares Cabral, 1301", "", "Vila Mariana", + "São Paulo", "SP", "04094-050", "BR", + "+55 11 2648-0254"); + + AutofillProfile profile2 = + AutofillProfile(base::GenerateGUID(), test::kEmptyOrigin); + test::SetProfileInfo(&profile2, "Artur", "", "Avila", "aavila@uol.com.br", "", + "Estr. Dona Castorina, 110", "", "Jardim Botânico", + "Rio de Janeiro", "RJ", "22460-320", "BR", + "21987650000"); + + const std::vector<AutofillProfile*> profiles{&profile1, &profile2}; + const std::unique_ptr<LabelFormatter> formatter = LabelFormatter::Create( + "pt-BR", EMAIL_ADDRESS, GetNamePhoneAndEmailFieldTypes(), profiles); + + EXPECT_THAT( + formatter->GetLabels(profiles), + ElementsAre(ConstructLabelLine({base::ASCIIToUTF16("Tarsila do Amaral"), + base::ASCIIToUTF16("(11) 2648-0254")}), + ConstructLabelLine({base::ASCIIToUTF16("Artur Avila"), + base::ASCIIToUTF16("(21) 98765-0000")}))); +} + +TEST(ContactFormLabelFormatterTest, GetLabelsForBRProfilesAndFocusedPhone) { + AutofillProfile profile1 = + AutofillProfile(base::GenerateGUID(), test::kEmptyOrigin); + test::SetProfileInfo(&profile1, "Tarsila", "do", "Amaral", "tarsila@aol.com", + "", "Av. Pedro Álvares Cabral, 1301", "", "Vila Mariana", + "São Paulo", "SP", "04094-050", "BR", + "+55 11 2648-0254"); + + AutofillProfile profile2 = + AutofillProfile(base::GenerateGUID(), test::kEmptyOrigin); + test::SetProfileInfo(&profile2, "Artur", "", "Avila", "aavila@uol.com.br", "", + "Estr. Dona Castorina, 110", "", "Jardim Botânico", + "Rio de Janeiro", "RJ", "22460-320", "BR", + "21987650000"); + + const std::vector<AutofillProfile*> profiles{&profile1, &profile2}; + const std::unique_ptr<LabelFormatter> formatter = + LabelFormatter::Create("pt-BR", PHONE_HOME_WHOLE_NUMBER, + GetNamePhoneAndEmailFieldTypes(), profiles); + + EXPECT_THAT( + formatter->GetLabels(profiles), + ElementsAre( + ConstructLabelLine({base::ASCIIToUTF16("Tarsila do Amaral"), + base::ASCIIToUTF16("tarsila@aol.com")}), + ConstructLabelLine({base::ASCIIToUTF16("Artur Avila"), + base::ASCIIToUTF16("aavila@uol.com.br")}))); +} + +TEST(ContactFormLabelFormatterTest, GetLabelsForNameAndPhoneWithFocusedName) { + AutofillProfile profile = + AutofillProfile(base::GenerateGUID(), test::kEmptyOrigin); + test::SetProfileInfo(&profile, "John", "F", "Kennedy", "jfk@gmail.com", "", + "333 Washington St", "", "Brookline", "MA", "02445", + "US", "16177302000"); + + const std::vector<AutofillProfile*> profiles{&profile}; + const std::unique_ptr<LabelFormatter> formatter = LabelFormatter::Create( + "en-US", NAME_LAST, {NAME_FIRST, NAME_LAST, PHONE_HOME_WHOLE_NUMBER}, + profiles); + + // Checks that the email address is excluded when the form does not contain an + // email field. + EXPECT_THAT(formatter->GetLabels(profiles), + ElementsAre(base::ASCIIToUTF16("(617) 730-2000"))); +} + +TEST(ContactFormLabelFormatterTest, GetLabelsForNameAndPhoneWithFocusedPhone) { + AutofillProfile profile = + AutofillProfile(base::GenerateGUID(), test::kEmptyOrigin); + test::SetProfileInfo(&profile, "John", "F", "Kennedy", "jfk@gmail.com", "", + "333 Washington St", "", "Brookline", "MA", "02445", + "US", "16177302000"); + + const std::vector<AutofillProfile*> profiles{&profile}; + const std::unique_ptr<LabelFormatter> formatter = LabelFormatter::Create( + "en-US", PHONE_HOME_WHOLE_NUMBER, + {NAME_FIRST, NAME_LAST, PHONE_HOME_WHOLE_NUMBER}, profiles); + + // Checks that the email address is excluded when the form does not contain an + // email field. + EXPECT_THAT(formatter->GetLabels(profiles), + ElementsAre(base::ASCIIToUTF16("John F Kennedy"))); +} + +TEST(ContactFormLabelFormatterTest, GetLabelsForNameAndEmailWithFocusedName) { + AutofillProfile profile = + AutofillProfile(base::GenerateGUID(), test::kEmptyOrigin); + test::SetProfileInfo(&profile, "John", "F", "Kennedy", "jfk@gmail.com", "", + "333 Washington St", "", "Brookline", "MA", "02445", + "US", "16177302000"); + + const std::vector<AutofillProfile*> profiles{&profile}; + const std::unique_ptr<LabelFormatter> formatter = LabelFormatter::Create( + "en-US", NAME_LAST, {NAME_FIRST, NAME_LAST, EMAIL_ADDRESS}, profiles); + + // Checks that the phone number is excluded when the form does not contain a + // phone field. + EXPECT_THAT(formatter->GetLabels(profiles), + ElementsAre(base::ASCIIToUTF16("jfk@gmail.com"))); +} + +TEST(ContactFormLabelFormatterTest, GetLabelsForNameAndEmailWithFocusedEmail) { + AutofillProfile profile = + AutofillProfile(base::GenerateGUID(), test::kEmptyOrigin); + test::SetProfileInfo(&profile, "John", "F", "Kennedy", "jfk@gmail.com", "", + "333 Washington St", "", "Brookline", "MA", "02445", + "US", "16177302000"); + + const std::vector<AutofillProfile*> profiles{&profile}; + const std::unique_ptr<LabelFormatter> formatter = LabelFormatter::Create( + "en-US", EMAIL_ADDRESS, {NAME_FIRST, NAME_LAST, EMAIL_ADDRESS}, profiles); + + // Checks that the phone number is excluded when the form does not contain a + // phone field. + EXPECT_THAT(formatter->GetLabels(profiles), + ElementsAre(base::ASCIIToUTF16("John F Kennedy"))); +} + +} // namespace +} // namespace autofill
\ No newline at end of file diff --git a/chromium/components/autofill/core/browser/contact_info.cc b/chromium/components/autofill/core/browser/contact_info.cc index c2d5104c2eb..3f8dc709edc 100644 --- a/chromium/components/autofill/core/browser/contact_info.cc +++ b/chromium/components/autofill/core/browser/contact_info.cc @@ -13,9 +13,11 @@ #include "base/strings/string_util.h" #include "base/strings/utf_string_conversions.h" #include "components/autofill/core/browser/autofill_data_util.h" +#include "components/autofill/core/browser/autofill_profile.h" #include "components/autofill/core/browser/autofill_type.h" #include "components/autofill/core/common/autofill_features.h" #include "components/autofill/core/common/autofill_l10n_util.h" +#include "components/autofill/core/common/autofill_regexes.h" namespace autofill { @@ -218,6 +220,8 @@ void EmailInfo::SetRawInfo(ServerFieldType type, const base::string16& value) { CompanyInfo::CompanyInfo() {} +CompanyInfo::CompanyInfo(const AutofillProfile* profile) : profile_(profile) {} + CompanyInfo::CompanyInfo(const CompanyInfo& info) { *this = info; } @@ -228,12 +232,13 @@ CompanyInfo& CompanyInfo::operator=(const CompanyInfo& info) { if (this == &info) return *this; - company_name_ = info.company_name_; + company_name_ = info.GetRawInfo(COMPANY_NAME); return *this; } bool CompanyInfo::operator==(const CompanyInfo& other) const { - return this == &other || company_name_ == other.company_name_; + return this == &other || + GetRawInfo(COMPANY_NAME) == other.GetRawInfo(COMPANY_NAME); } void CompanyInfo::GetSupportedTypes(ServerFieldTypeSet* supported_types) const { @@ -241,7 +246,7 @@ void CompanyInfo::GetSupportedTypes(ServerFieldTypeSet* supported_types) const { } base::string16 CompanyInfo::GetRawInfo(ServerFieldType type) const { - return company_name_; + return IsValidOrVerified(company_name_) ? company_name_ : base::string16(); } void CompanyInfo::SetRawInfo(ServerFieldType type, @@ -250,4 +255,16 @@ void CompanyInfo::SetRawInfo(ServerFieldType type, company_name_ = value; } +bool CompanyInfo::IsValidOrVerified(const base::string16& value) const { + if (!base::FeatureList::IsEnabled( + autofill::features::kAutofillRejectCompanyBirthyear)) + return true; + + if (profile_ && profile_->IsVerified()) + return true; + + // Companies that are of the format of a four digit birth year are not valid. + return !MatchesPattern(value, base::UTF8ToUTF16("^(19|20)\\d{2}$")); +} + } // namespace autofill diff --git a/chromium/components/autofill/core/browser/contact_info.h b/chromium/components/autofill/core/browser/contact_info.h index 3c5e451a73c..3bb79c4121c 100644 --- a/chromium/components/autofill/core/browser/contact_info.h +++ b/chromium/components/autofill/core/browser/contact_info.h @@ -13,6 +13,8 @@ namespace autofill { +class AutofillProfile; + // A form group that stores name information. class NameInfo : public FormGroup { public: @@ -91,6 +93,7 @@ class CompanyInfo : public FormGroup { public: CompanyInfo(); CompanyInfo(const CompanyInfo& info); + explicit CompanyInfo(const AutofillProfile* profile); ~CompanyInfo() override; CompanyInfo& operator=(const CompanyInfo& info); @@ -100,12 +103,15 @@ class CompanyInfo : public FormGroup { // FormGroup: base::string16 GetRawInfo(ServerFieldType type) const override; void SetRawInfo(ServerFieldType type, const base::string16& value) override; + void set_profile(const AutofillProfile* profile) { profile_ = profile; } private: // FormGroup: void GetSupportedTypes(ServerFieldTypeSet* supported_types) const override; + bool IsValidOrVerified(const base::string16& value) const; base::string16 company_name_; + const AutofillProfile* profile_ = nullptr; }; } // namespace autofill diff --git a/chromium/components/autofill/core/browser/contact_info_unittest.cc b/chromium/components/autofill/core/browser/contact_info_unittest.cc index 3f2502fa654..cac7c92e4b6 100644 --- a/chromium/components/autofill/core/browser/contact_info_unittest.cc +++ b/chromium/components/autofill/core/browser/contact_info_unittest.cc @@ -11,8 +11,11 @@ #include "base/strings/string_util.h" #include "base/strings/stringprintf.h" #include "base/strings/utf_string_conversions.h" +#include "base/test/scoped_feature_list.h" +#include "components/autofill/core/browser/autofill_profile.h" #include "components/autofill/core/browser/autofill_type.h" #include "components/autofill/core/browser/field_types.h" +#include "components/autofill/core/common/autofill_features.h" #include "testing/gtest/include/gtest/gtest.h" using base::ASCIIToUTF16; @@ -397,4 +400,96 @@ INSTANTIATE_TEST_SUITE_P( NamePartsAreEmptyTestCase{"", "Mitchell", "", "", false}, NamePartsAreEmptyTestCase{"", "", "Morrison", "", false})); +TEST(CompanyTest, CompanyNameYear) { + base::test::ScopedFeatureList scoped_features; + scoped_features.InitWithFeatures( + /*enabled_features=*/{features::kAutofillRejectCompanyBirthyear}, + /*disabled_features=*/{}); + + AutofillProfile profile; + CompanyInfo company(&profile); + ASSERT_FALSE(profile.IsVerified()); + + company.SetRawInfo(COMPANY_NAME, UTF8ToUTF16("Google")); + EXPECT_EQ(UTF8ToUTF16("Google"), company.GetRawInfo(COMPANY_NAME)); + + company.SetRawInfo(COMPANY_NAME, UTF8ToUTF16("1987")); + EXPECT_EQ(UTF8ToUTF16(""), company.GetRawInfo(COMPANY_NAME)); + + company.SetRawInfo(COMPANY_NAME, UTF8ToUTF16("It was 1987.")); + EXPECT_EQ(UTF8ToUTF16("It was 1987."), company.GetRawInfo(COMPANY_NAME)); + + company.SetRawInfo(COMPANY_NAME, UTF8ToUTF16("1987 was the year.")); + EXPECT_EQ(UTF8ToUTF16("1987 was the year."), + company.GetRawInfo(COMPANY_NAME)); + + company.SetRawInfo(COMPANY_NAME, UTF8ToUTF16("Yes, 1987 was the year.")); + EXPECT_EQ(UTF8ToUTF16("Yes, 1987 was the year."), + company.GetRawInfo(COMPANY_NAME)); + + company.SetRawInfo(COMPANY_NAME, UTF8ToUTF16("2019")); + EXPECT_EQ(UTF8ToUTF16(""), company.GetRawInfo(COMPANY_NAME)); + + company.SetRawInfo(COMPANY_NAME, UTF8ToUTF16("1818")); + EXPECT_EQ(UTF8ToUTF16("1818"), company.GetRawInfo(COMPANY_NAME)); + + company.SetRawInfo(COMPANY_NAME, UTF8ToUTF16("2345")); + EXPECT_EQ(UTF8ToUTF16("2345"), company.GetRawInfo(COMPANY_NAME)); + + profile.set_origin("Not empty"); + ASSERT_TRUE(profile.IsVerified()); + + company.SetRawInfo(COMPANY_NAME, UTF8ToUTF16("Google")); + EXPECT_EQ(UTF8ToUTF16("Google"), company.GetRawInfo(COMPANY_NAME)); + + company.SetRawInfo(COMPANY_NAME, UTF8ToUTF16("1987")); + EXPECT_EQ(UTF8ToUTF16("1987"), company.GetRawInfo(COMPANY_NAME)); + + company.SetRawInfo(COMPANY_NAME, UTF8ToUTF16("2019")); + EXPECT_EQ(UTF8ToUTF16("2019"), company.GetRawInfo(COMPANY_NAME)); + + company.SetRawInfo(COMPANY_NAME, UTF8ToUTF16("1818")); + EXPECT_EQ(UTF8ToUTF16("1818"), company.GetRawInfo(COMPANY_NAME)); + + company.SetRawInfo(COMPANY_NAME, UTF8ToUTF16("2345")); + EXPECT_EQ(UTF8ToUTF16("2345"), company.GetRawInfo(COMPANY_NAME)); +} + +TEST(CompanyTest, CompanyNameYearCopy) { + base::test::ScopedFeatureList scoped_features; + scoped_features.InitWithFeatures( + /*enabled_features=*/{features::kAutofillRejectCompanyBirthyear}, + /*disabled_features=*/{}); + + AutofillProfile profile; + ASSERT_FALSE(profile.IsVerified()); + + CompanyInfo company_google(&profile); + CompanyInfo company_year(&profile); + + company_google.SetRawInfo(COMPANY_NAME, UTF8ToUTF16("Google")); + company_year.SetRawInfo(COMPANY_NAME, UTF8ToUTF16("1987")); + + company_google = company_year; + EXPECT_EQ(UTF8ToUTF16(""), company_google.GetRawInfo(COMPANY_NAME)); +} + +TEST(CompanyTest, CompanyNameYearIsEqual) { + base::test::ScopedFeatureList scoped_features; + scoped_features.InitWithFeatures( + /*enabled_features=*/{features::kAutofillRejectCompanyBirthyear}, + /*disabled_features=*/{}); + + AutofillProfile profile; + ASSERT_FALSE(profile.IsVerified()); + + CompanyInfo company_old(&profile); + CompanyInfo company_young(&profile); + + company_old.SetRawInfo(COMPANY_NAME, UTF8ToUTF16("2019")); + company_young.SetRawInfo(COMPANY_NAME, UTF8ToUTF16("1987")); + + EXPECT_EQ(company_old, company_young); +} + } // namespace autofill diff --git a/chromium/components/autofill/core/browser/field_types.h b/chromium/components/autofill/core/browser/field_types.h index c10fd8df61d..022575a16da 100644 --- a/chromium/components/autofill/core/browser/field_types.h +++ b/chromium/components/autofill/core/browser/field_types.h @@ -172,9 +172,12 @@ enum ServerFieldType { // Price fields are detected, but not filled. PRICE = 98, + // Password-type fields which are not actual passwords. + NOT_PASSWORD = 99, + // No new types can be added without a corresponding change to the Autofill // server. - MAX_VALID_FIELD_TYPE = 99, + MAX_VALID_FIELD_TYPE = 100, }; // The list of all HTML autocomplete field type hints supported by Chrome. diff --git a/chromium/components/autofill/core/browser/form_data_importer.cc b/chromium/components/autofill/core/browser/form_data_importer.cc index 15e57a10910..93a16220a75 100644 --- a/chromium/components/autofill/core/browser/form_data_importer.cc +++ b/chromium/components/autofill/core/browser/form_data_importer.cc @@ -31,6 +31,7 @@ #include "components/autofill/core/browser/phone_number_i18n.h" #include "components/autofill/core/browser/validation.h" #include "components/autofill/core/common/autofill_features.h" +#include "components/autofill/core/common/autofill_payments_features.h" #include "components/autofill/core/common/autofill_util.h" namespace autofill { @@ -133,6 +134,11 @@ void FormDataImporter::ImportFormData(const FormStructure& submitted_form, ImportedCreditCardRecordType::NO_CARD) { return; } + // Do not offer upload save for google domain. + if (net::HasGoogleHost(submitted_form.main_frame_origin().GetURL()) && + is_credit_card_upstream_enabled) { + return; + } // A credit card was successfully imported, but it's possible it is already a // local or server card. First, check to see if we should offer local card // migration in this case, as local cards could go either way. @@ -177,7 +183,8 @@ void FormDataImporter::ImportFormData(const FormStructure& submitted_form, imported_credit_card_record_type_ == ImportedCreditCardRecordType::NEW_CARD); credit_card_save_manager_->AttemptToOfferCardUploadSave( - submitted_form, has_non_focusable_field_, *imported_credit_card, + submitted_form, from_dynamic_change_form_, has_non_focusable_field_, + *imported_credit_card, /*uploading_local_card=*/imported_credit_card_record_type_ == ImportedCreditCardRecordType::LOCAL_CARD); } else { @@ -185,7 +192,8 @@ void FormDataImporter::ImportFormData(const FormStructure& submitted_form, DCHECK(imported_credit_card_record_type_ == ImportedCreditCardRecordType::NEW_CARD); credit_card_save_manager_->AttemptToOfferCardLocalSave( - has_non_focusable_field_, *imported_credit_card); + from_dynamic_change_form_, has_non_focusable_field_, + *imported_credit_card); } } @@ -508,6 +516,8 @@ CreditCard FormDataImporter::ExtractCreditCardFromForm( if (field_type.group() != CREDIT_CARD) continue; + if (form.value_from_dynamic_change_form()) + from_dynamic_change_form_ = true; if (!field->is_focusable) has_non_focusable_field_ = true; diff --git a/chromium/components/autofill/core/browser/form_data_importer.h b/chromium/components/autofill/core/browser/form_data_importer.h index a195d96cc86..9678400c066 100644 --- a/chromium/components/autofill/core/browser/form_data_importer.h +++ b/chromium/components/autofill/core/browser/form_data_importer.h @@ -13,9 +13,9 @@ #include "build/build_config.h" #include "components/autofill/core/browser/autofill_client.h" -#include "components/autofill/core/browser/credit_card_save_manager.h" #include "components/autofill/core/browser/form_structure.h" -#include "components/autofill/core/browser/local_card_migration_manager.h" +#include "components/autofill/core/browser/payments/credit_card_save_manager.h" +#include "components/autofill/core/browser/payments/local_card_migration_manager.h" #include "components/autofill/core/browser/payments/payments_client.h" #include "components/autofill/core/browser/personal_data_manager.h" @@ -120,6 +120,9 @@ class FormDataImporter { CreditCard ExtractCreditCardFromForm(const FormStructure& form, bool* hasDuplicateFieldType); + // Whether a dynamic change form is imported. + bool from_dynamic_change_form_ = false; + // Whether the form imported has non-focusable fields after user entered // information into it. bool has_non_focusable_field_ = false; diff --git a/chromium/components/autofill/core/browser/form_data_importer_unittest.cc b/chromium/components/autofill/core/browser/form_data_importer_unittest.cc index 00280a55dde..e1d3e18b03a 100644 --- a/chromium/components/autofill/core/browser/form_data_importer_unittest.cc +++ b/chromium/components/autofill/core/browser/form_data_importer_unittest.cc @@ -38,6 +38,7 @@ #include "components/autofill/core/browser/webdata/autofill_webdata_service.h" #include "components/autofill/core/common/autofill_constants.h" #include "components/autofill/core/common/autofill_features.h" +#include "components/autofill/core/common/autofill_payments_features.h" #include "components/autofill/core/common/autofill_prefs.h" #include "components/autofill/core/common/autofill_switches.h" #include "components/autofill/core/common/autofill_util.h" @@ -287,7 +288,7 @@ class FormDataImporterTest : public FormDataImporterTestBase, TEST_F(FormDataImporterTest, ImportAddressProfiles) { FormData form; - form.origin = GURL("https://wwww.foo.com"); + form.url = GURL("https://wwww.foo.com"); FormFieldData field; test::CreateTestFormField("First name:", "first_name", "George", "text", @@ -325,7 +326,7 @@ TEST_F(FormDataImporterTest, ImportAddressProfiles) { TEST_F(FormDataImporterTest, ImportAddressProfiles_BadEmail) { FormData form; - form.origin = GURL("https://wwww.foo.com"); + form.url = GURL("https://wwww.foo.com"); FormFieldData field; test::CreateTestFormField("First name:", "first_name", "George", "text", @@ -355,7 +356,7 @@ TEST_F(FormDataImporterTest, ImportAddressProfiles_BadEmail) { // Tests that a 'confirm email' field does not block profile import. TEST_F(FormDataImporterTest, ImportAddressProfiles_TwoEmails) { FormData form; - form.origin = GURL("https://wwww.foo.com"); + form.url = GURL("https://wwww.foo.com"); FormFieldData field; test::CreateTestFormField("Name:", "name", "George Washington", "text", @@ -386,7 +387,7 @@ TEST_F(FormDataImporterTest, ImportAddressProfiles_TwoEmails) { // Tests two email fields containing different values blocks profile import. TEST_F(FormDataImporterTest, ImportAddressProfiles_TwoDifferentEmails) { FormData form; - form.origin = GURL("https://wwww.foo.com"); + form.url = GURL("https://wwww.foo.com"); FormFieldData field; test::CreateTestFormField("Name:", "name", "George Washington", "text", @@ -417,7 +418,7 @@ TEST_F(FormDataImporterTest, ImportAddressProfiles_TwoDifferentEmails) { // Tests that not enough filled fields will result in not importing an address. TEST_F(FormDataImporterTest, ImportAddressProfiles_NotEnoughFilledFields) { FormData form; - form.origin = GURL("https://wwww.foo.com"); + form.url = GURL("https://wwww.foo.com"); FormFieldData field; test::CreateTestFormField("First name:", "first_name", "George", "text", @@ -441,7 +442,7 @@ TEST_F(FormDataImporterTest, ImportAddressProfiles_MinimumAddressUSA) { // United States addresses must specifiy one address line, a city, state and // zip code. FormData form; - form.origin = GURL("https://wwww.foo.com"); + form.url = GURL("https://wwww.foo.com"); FormFieldData field; test::CreateTestFormField("Name:", "name", "Barack Obama", "text", &field); @@ -468,7 +469,7 @@ TEST_F(FormDataImporterTest, ImportAddressProfiles_MinimumAddressGB) { // British addresses do not require a state/province as the county is usually // not requested on forms. FormData form; - form.origin = GURL("https://wwww.foo.com"); + form.url = GURL("https://wwww.foo.com"); FormFieldData field; test::CreateTestFormField("Name:", "name", "David Cameron", "text", &field); @@ -495,7 +496,7 @@ TEST_F(FormDataImporterTest, ImportAddressProfiles_MinimumAddressGI) { // Gibraltar has the most minimal set of requirements for a valid address. // There are no cities or provinces and no postal/zip code system. FormData form; - form.origin = GURL("https://wwww.foo.com"); + form.url = GURL("https://wwww.foo.com"); FormFieldData field; test::CreateTestFormField("Name:", "name", "Sir Adrian Johns", "text", @@ -516,7 +517,7 @@ TEST_F(FormDataImporterTest, ImportAddressProfiles_MinimumAddressGI) { TEST_F(FormDataImporterTest, ImportAddressProfiles_PhoneNumberSplitAcrossMultipleFields) { FormData form; - form.origin = GURL("https://wwww.foo.com"); + form.url = GURL("https://wwww.foo.com"); FormFieldData field; test::CreateTestFormField("First name:", "first_name", "George", "text", @@ -562,7 +563,7 @@ TEST_F(FormDataImporterTest, TEST_F(FormDataImporterTest, ImportAddressProfiles_MultilineAddress) { FormData form; - form.origin = GURL("https://wwww.foo.com"); + form.url = GURL("https://wwww.foo.com"); FormFieldData field; test::CreateTestFormField("First name:", "first_name", "George", "text", @@ -603,7 +604,7 @@ TEST_F(FormDataImporterTest, ImportAddressProfiles_MultilineAddress) { TEST_F(FormDataImporterTest, ImportAddressProfiles_TwoValidProfilesDifferentForms) { FormData form1; - form1.origin = GURL("https://wwww.foo.com"); + form1.url = GURL("https://wwww.foo.com"); FormFieldData field; test::CreateTestFormField("First name:", "first_name", "George", "text", @@ -641,7 +642,7 @@ TEST_F(FormDataImporterTest, // Now create a completely different profile. FormData form2; - form2.origin = GURL("https://wwww.foo.com"); + form2.url = GURL("https://wwww.foo.com"); test::CreateTestFormField("First name:", "first_name", "John", "text", &field); @@ -677,7 +678,7 @@ TEST_F(FormDataImporterTest, TEST_F(FormDataImporterTest, ImportAddressProfiles_TwoValidProfilesSameForm) { FormData form; - form.origin = GURL("https://wwww.foo.com"); + form.url = GURL("https://wwww.foo.com"); FormFieldData field; test::CreateTestFormField("First name:", "first_name", "George", "text", @@ -745,7 +746,7 @@ TEST_F(FormDataImporterTest, ImportAddressProfiles_TwoValidProfilesSameForm) { TEST_F(FormDataImporterTest, ImportAddressProfiles_OneValidProfileSameForm_PartsHidden) { FormData form; - form.origin = GURL("https://wwww.foo.com"); + form.url = GURL("https://wwww.foo.com"); FormFieldData field; test::CreateTestFormField("First name:", "first_name", "George", "text", @@ -814,7 +815,7 @@ TEST_F(FormDataImporterTest, // A maximum of two address profiles are imported per form. TEST_F(FormDataImporterTest, ImportAddressProfiles_ThreeValidProfilesSameForm) { FormData form; - form.origin = GURL("https://wwww.foo.com"); + form.url = GURL("https://wwww.foo.com"); FormFieldData field; test::CreateTestFormField("First name:", "first_name", "George", "text", @@ -901,7 +902,7 @@ TEST_F(FormDataImporterTest, ImportAddressProfiles_ThreeValidProfilesSameForm) { TEST_F(FormDataImporterTest, ImportAddressProfiles_SameProfileWithConflict) { FormData form1; - form1.origin = GURL("https://wwww.foo.com"); + form1.url = GURL("https://wwww.foo.com"); FormFieldData field; test::CreateTestFormField("First name:", "first_name", "George", "text", @@ -944,7 +945,7 @@ TEST_F(FormDataImporterTest, ImportAddressProfiles_SameProfileWithConflict) { // Now create an updated profile. FormData form2; - form2.origin = GURL("https://wwww.foo.com"); + form2.url = GURL("https://wwww.foo.com"); test::CreateTestFormField("First name:", "first_name", "George", "text", &field); @@ -992,7 +993,7 @@ TEST_F(FormDataImporterTest, ImportAddressProfiles_SameProfileWithConflict) { TEST_F(FormDataImporterTest, ImportAddressProfiles_MissingInfoInOld) { FormData form1; - form1.origin = GURL("https://wwww.foo.com"); + form1.url = GURL("https://wwww.foo.com"); FormFieldData field; test::CreateTestFormField("First name:", "first_name", "George", "text", @@ -1026,7 +1027,7 @@ TEST_F(FormDataImporterTest, ImportAddressProfiles_MissingInfoInOld) { // Submit a form with new data for the first profile. FormData form2; - form2.origin = GURL("https://wwww.foo.com"); + form2.url = GURL("https://wwww.foo.com"); test::CreateTestFormField("First name:", "first_name", "George", "text", &field); @@ -1066,7 +1067,7 @@ TEST_F(FormDataImporterTest, ImportAddressProfiles_MissingInfoInOld) { TEST_F(FormDataImporterTest, ImportAddressProfiles_MissingInfoInNew) { FormData form1; - form1.origin = GURL("https://wwww.foo.com"); + form1.url = GURL("https://wwww.foo.com"); FormFieldData field; test::CreateTestFormField("First name:", "first_name", "George", "text", @@ -1107,7 +1108,7 @@ TEST_F(FormDataImporterTest, ImportAddressProfiles_MissingInfoInNew) { // Submit a form with new data for the first profile. FormData form2; - form2.origin = GURL("https://wwww.foo.com"); + form2.url = GURL("https://wwww.foo.com"); test::CreateTestFormField("First name:", "first_name", "George", "text", &field); @@ -1144,7 +1145,7 @@ TEST_F(FormDataImporterTest, ImportAddressProfiles_MissingInfoInNew) { TEST_F(FormDataImporterTest, ImportAddressProfiles_InsufficientAddress) { FormData form1; - form1.origin = GURL("https://wwww.foo.com"); + form1.url = GURL("https://wwww.foo.com"); FormFieldData field; test::CreateTestFormField("First name:", "first_name", "George", "text", @@ -1199,7 +1200,7 @@ TEST_F(FormDataImporterTest, // Simulate a form submission with conflicting info. FormData form; - form.origin = GURL("https://wwww.foo.com"); + form.url = GURL("https://wwww.foo.com"); FormFieldData field; test::CreateTestFormField("First name:", "first_name", "Marion Mitchell", @@ -1253,7 +1254,7 @@ TEST_F(FormDataImporterTest, // Tests that no profile is inferred if the country is not recognized. TEST_F(FormDataImporterTest, ImportAddressProfiles_UnrecognizedCountry) { FormData form; - form.origin = GURL("https://wwww.foo.com"); + form.url = GURL("https://wwww.foo.com"); FormFieldData field; test::CreateTestFormField("First name:", "first_name", "George", "text", @@ -1294,7 +1295,7 @@ TEST_F(FormDataImporterTest, ImportAddressProfiles_UnrecognizedCountry) { TEST_F(FormDataImporterTest, ImportAddressProfiles_CompleteComposedCountryName) { FormData form; - form.origin = GURL("https://wwww.foo.com"); + form.url = GURL("https://wwww.foo.com"); FormFieldData field; test::CreateTestFormField("First name:", "first_name", "George", "text", @@ -1340,7 +1341,7 @@ TEST_F(FormDataImporterTest, TEST_F(FormDataImporterTest, ImportAddressProfiles_IncompleteComposedCountryName) { FormData form; - form.origin = GURL("https://wwww.foo.com"); + form.url = GURL("https://wwww.foo.com"); FormFieldData field; test::CreateTestFormField("First name:", "first_name", "George", "text", @@ -1384,7 +1385,7 @@ TEST_F(FormDataImporterTest, TEST_F(FormDataImporterTest, ImportCreditCard_Valid) { // Add a single valid credit card form. FormData form; - form.origin = GURL("https://wwww.foo.com"); + form.url = GURL("https://wwww.foo.com"); AddFullCreditCardForm(&form, "Biggie Smalls", "4111-1111-1111-1111", "01", "2999"); @@ -1414,7 +1415,7 @@ TEST_F(FormDataImporterTest, ImportCreditCard_Valid) { // Tests that an invalid credit card number is not extracted. TEST_F(FormDataImporterTest, ImportCreditCard_InvalidCardNumber) { FormData form; - form.origin = GURL("https://wwww.foo.com"); + form.url = GURL("https://wwww.foo.com"); AddFullCreditCardForm(&form, "Jim Johansen", "1000000000000000", "02", "2999"); @@ -1439,7 +1440,7 @@ TEST_F(FormDataImporterTest, ImportCreditCard_InvalidCardNumber) { // Tests that an invalid credit card expiration is not extracted. TEST_F(FormDataImporterTest, ImportCreditCard_InvalidExpiryDate) { FormData form; - form.origin = GURL("https://wwww.foo.com"); + form.url = GURL("https://wwww.foo.com"); AddFullCreditCardForm(&form, "Smalls Biggie", "4111-1111-1111-1111", "0", "2999"); @@ -1467,7 +1468,7 @@ TEST_F(FormDataImporterTest, scoped_feature_list_.InitAndEnableFeature( features::kAutofillUpstreamEditableExpirationDate); FormData form; - form.origin = GURL("https://wwww.foo.com"); + form.url = GURL("https://wwww.foo.com"); AddFullCreditCardForm(&form, "Smalls Biggie", "4111-1111-1111-1111", "", ""); @@ -1488,7 +1489,7 @@ TEST_F(FormDataImporterTest, scoped_feature_list_.InitAndEnableFeature( features::kAutofillUpstreamEditableExpirationDate); FormData form; - form.origin = GURL("https://wwww.foo.com"); + form.url = GURL("https://wwww.foo.com"); AddFullCreditCardForm(&form, "Smalls Biggie", "4111-1111-1111-1111", "01", "2000"); @@ -1508,7 +1509,7 @@ TEST_F(FormDataImporterTest, TEST_F(FormDataImporterTest, ImportCreditCard_MonthSelectInvalidText) { // Add a single valid credit card form with an invalid option value. FormData form; - form.origin = GURL("https://wwww.foo.com"); + form.url = GURL("https://wwww.foo.com"); AddFullCreditCardForm(&form, "Biggie Smalls", "4111-1111-1111-1111", "Feb (2)", "2999"); @@ -1551,7 +1552,7 @@ TEST_F(FormDataImporterTest, ImportCreditCard_MonthSelectInvalidText) { TEST_F(FormDataImporterTest, ImportCreditCard_TwoValidCards) { // Start with a single valid credit card form. FormData form1; - form1.origin = GURL("https://wwww.foo.com"); + form1.url = GURL("https://wwww.foo.com"); AddFullCreditCardForm(&form1, "Biggie Smalls", "4111-1111-1111-1111", "01", "2999"); @@ -1575,7 +1576,7 @@ TEST_F(FormDataImporterTest, ImportCreditCard_TwoValidCards) { // Add a second different valid credit card. FormData form2; - form2.origin = GURL("https://wwww.foo.com"); + form2.url = GURL("https://wwww.foo.com"); AddFullCreditCardForm(&form2, "", "5500 0000 0000 0004", "02", "2999"); @@ -1601,7 +1602,7 @@ TEST_F(FormDataImporterTest, ImportCreditCard_TwoValidCards) { // This form has the expiration year as one field with MM/YY. TEST_F(FormDataImporterTest, ImportCreditCard_Month2DigitYearCombination) { FormData form; - form.origin = GURL("https://wwww.foo.com"); + form.url = GURL("https://wwww.foo.com"); FormFieldData field; test::CreateTestFormField("Name on card:", "name_on_card", "John MMYY", @@ -1622,7 +1623,7 @@ TEST_F(FormDataImporterTest, ImportCreditCard_Month2DigitYearCombination) { // This form has the expiration year as one field with MM/YYYY. TEST_F(FormDataImporterTest, ImportCreditCard_Month4DigitYearCombination) { FormData form; - form.origin = GURL("https://wwww.foo.com"); + form.url = GURL("https://wwww.foo.com"); FormFieldData field; test::CreateTestFormField("Name on card:", "name_on_card", "John MMYYYY", @@ -1643,7 +1644,7 @@ TEST_F(FormDataImporterTest, ImportCreditCard_Month4DigitYearCombination) { // This form has the expiration year as one field with M/YYYY. TEST_F(FormDataImporterTest, ImportCreditCard_1DigitMonth4DigitYear) { FormData form; - form.origin = GURL("https://wwww.foo.com"); + form.url = GURL("https://wwww.foo.com"); FormFieldData field; test::CreateTestFormField("Name on card:", "name_on_card", "John MYYYY", @@ -1663,7 +1664,7 @@ TEST_F(FormDataImporterTest, ImportCreditCard_1DigitMonth4DigitYear) { // This form has the expiration year as a 2-digit field. TEST_F(FormDataImporterTest, ImportCreditCard_2DigitYear) { FormData form; - form.origin = GURL("https://wwww.foo.com"); + form.url = GURL("https://wwww.foo.com"); FormFieldData field; test::CreateTestFormField("Name on card:", "name_on_card", "John Smith", @@ -1701,7 +1702,7 @@ TEST_F(FormDataImporterTest, // Type the same data as the masked card into a form. FormData form; - form.origin = GURL("https://wwww.foo.com"); + form.url = GURL("https://wwww.foo.com"); AddFullCreditCardForm(&form, "John Dillinger", "4111111111111111", "01", "2999"); @@ -1733,7 +1734,7 @@ TEST_F(FormDataImporterTest, ImportCreditCard_DuplicateServerCards_FullCard) { // Type the same data as the unmasked card into a form. FormData form; - form.origin = GURL("https://wwww.foo.com"); + form.url = GURL("https://wwww.foo.com"); AddFullCreditCardForm(&form, "Clyde Barrow", "378282246310005", "04", "2999"); @@ -1749,7 +1750,7 @@ TEST_F(FormDataImporterTest, ImportCreditCard_DuplicateServerCards_FullCard) { TEST_F(FormDataImporterTest, ImportCreditCard_SameCreditCardWithConflict) { // Start with a single valid credit card form. FormData form1; - form1.origin = GURL("https://wwww.foo.com"); + form1.url = GURL("https://wwww.foo.com"); AddFullCreditCardForm(&form1, "Biggie Smalls", "4111-1111-1111-1111", "01", "2998"); @@ -1774,7 +1775,7 @@ TEST_F(FormDataImporterTest, ImportCreditCard_SameCreditCardWithConflict) { // Add a second different valid credit card where the year is different but // the credit card number matches. FormData form2; - form2.origin = GURL("https://wwww.foo.com"); + form2.url = GURL("https://wwww.foo.com"); AddFullCreditCardForm(&form2, "Biggie Smalls", "4111 1111 1111 1111", "01", /* different year */ "2999"); @@ -1801,7 +1802,7 @@ TEST_F(FormDataImporterTest, ImportCreditCard_SameCreditCardWithConflict) { TEST_F(FormDataImporterTest, ImportCreditCard_ShouldReturnLocalCard) { // Start with a single valid credit card form. FormData form1; - form1.origin = GURL("https://wwww.foo.com"); + form1.url = GURL("https://wwww.foo.com"); AddFullCreditCardForm(&form1, "Biggie Smalls", "4111-1111-1111-1111", "01", "2998"); @@ -1826,7 +1827,7 @@ TEST_F(FormDataImporterTest, ImportCreditCard_ShouldReturnLocalCard) { // Add a second different valid credit card where the year is different but // the credit card number matches. FormData form2; - form2.origin = GURL("https://wwww.foo.com"); + form2.url = GURL("https://wwww.foo.com"); AddFullCreditCardForm(&form2, "Biggie Smalls", "4111 1111 1111 1111", "01", /* different year */ "2999"); @@ -1856,7 +1857,7 @@ TEST_F(FormDataImporterTest, ImportCreditCard_ShouldReturnLocalCard) { TEST_F(FormDataImporterTest, ImportCreditCard_EmptyCardWithConflict) { // Start with a single valid credit card form. FormData form1; - form1.origin = GURL("https://wwww.foo.com"); + form1.url = GURL("https://wwww.foo.com"); AddFullCreditCardForm(&form1, "Biggie Smalls", "4111-1111-1111-1111", "01", "2998"); @@ -1881,7 +1882,7 @@ TEST_F(FormDataImporterTest, ImportCreditCard_EmptyCardWithConflict) { // Add a second credit card with no number. FormData form2; - form2.origin = GURL("https://wwww.foo.com"); + form2.url = GURL("https://wwww.foo.com"); AddFullCreditCardForm(&form2, "Biggie Smalls", /* no number */ nullptr, "01", "2999"); @@ -1910,7 +1911,7 @@ TEST_F(FormDataImporterTest, ImportCreditCard_EmptyCardWithConflict) { TEST_F(FormDataImporterTest, ImportCreditCard_MissingInfoInNew) { // Start with a single valid credit card form. FormData form1; - form1.origin = GURL("https://wwww.foo.com"); + form1.url = GURL("https://wwww.foo.com"); AddFullCreditCardForm(&form1, "Biggie Smalls", "4111-1111-1111-1111", "01", "2999"); @@ -1935,7 +1936,7 @@ TEST_F(FormDataImporterTest, ImportCreditCard_MissingInfoInNew) { // Add a second different valid credit card where the name is missing but // the credit card number matches. FormData form2; - form2.origin = GURL("https://wwww.foo.com"); + form2.url = GURL("https://wwww.foo.com"); AddFullCreditCardForm(&form2, /* missing name */ nullptr, "4111-1111-1111-1111", "01", "2999"); @@ -1961,7 +1962,7 @@ TEST_F(FormDataImporterTest, ImportCreditCard_MissingInfoInNew) { // Add a third credit card where the expiration date is missing. FormData form3; - form3.origin = GURL("https://wwww.foo.com"); + form3.url = GURL("https://wwww.foo.com"); AddFullCreditCardForm(&form3, "Johnny McEnroe", "5555555555554444", /* no month */ nullptr, @@ -2006,7 +2007,7 @@ TEST_F(FormDataImporterTest, ImportCreditCard_MissingInfoInOld) { // Add a second different valid credit card where the year is different but // the credit card number matches. FormData form; - form.origin = GURL("https://wwww.foo.com"); + form.url = GURL("https://wwww.foo.com"); AddFullCreditCardForm(&form, "Biggie Smalls", "4111-1111-1111-1111", "01", /* different year */ "2999"); @@ -2049,7 +2050,7 @@ TEST_F(FormDataImporterTest, ImportCreditCard_SameCardWithSeparators) { // Import the same card info, but with different separators in the number. FormData form; - form.origin = GURL("https://wwww.foo.com"); + form.url = GURL("https://wwww.foo.com"); AddFullCreditCardForm(&form, "Biggie Smalls", "4111-1111-1111-1111", "01", "2999"); @@ -2091,7 +2092,7 @@ TEST_F(FormDataImporterTest, // Simulate a form submission with conflicting expiration year. FormData form; - form.origin = GURL("https://wwww.foo.com"); + form.url = GURL("https://wwww.foo.com"); AddFullCreditCardForm(&form, "Biggie Smalls", "4111 1111 1111 1111", "01", /* different year */ "2999"); @@ -2131,7 +2132,7 @@ TEST_F(FormDataImporterTest, // Simulate a form submission with the same card. FormData form; - form.origin = GURL("https://wwww.foo.com"); + form.url = GURL("https://wwww.foo.com"); AddFullCreditCardForm(&form, "Biggie Smalls", "4111 1111 1111 1111", "01", "2999"); @@ -2153,7 +2154,7 @@ TEST_F(FormDataImporterTest, // |imported_credit_card_record_type_| should be reset. // Simulate a form submission with a new card. FormData form2; - form2.origin = GURL("https://wwww.foo.com"); + form2.url = GURL("https://wwww.foo.com"); AddFullCreditCardForm(&form2, "Biggie Smalls", "4012888888881881", "01", "2999"); @@ -2176,7 +2177,7 @@ TEST_F(FormDataImporterTest, // |imported_credit_card_record_type_| should still be reset even if // ImportCreditCard is not called. Simulate a form submission with no card. FormData form3; - form3.origin = GURL("https://wwww.foo.com"); + form3.url = GURL("https://wwww.foo.com"); FormFieldData field; test::CreateTestFormField("First name:", "first_name", "George", "text", @@ -2215,7 +2216,7 @@ TEST_F(FormDataImporterTest, ImportFormData_ImportCreditCardRecordType_NewCard) { // Simulate a form submission with a new credit card. FormData form; - form.origin = GURL("https://wwww.foo.com"); + form.url = GURL("https://wwww.foo.com"); AddFullCreditCardForm(&form, "Biggie Smalls", "4111 1111 1111 1111", "01", "2999"); @@ -2252,7 +2253,7 @@ TEST_F(FormDataImporterTest, // Simulate a form submission with the same card. FormData form; - form.origin = GURL("https://wwww.foo.com"); + form.url = GURL("https://wwww.foo.com"); AddFullCreditCardForm(&form, "Biggie Smalls", "4111 1111 1111 1111", "01", "2999"); @@ -2289,7 +2290,7 @@ TEST_F(FormDataImporterTest, // Simulate a form submission with the same masked server card. FormData form; - form.origin = GURL("https://wwww.foo.com"); + form.url = GURL("https://wwww.foo.com"); AddFullCreditCardForm(&form, "Biggie Smalls", "4111 1111 1111 1111", "01", "2999"); @@ -2325,7 +2326,7 @@ TEST_F(FormDataImporterTest, // Simulate a form submission with the same full server card. FormData form; - form.origin = GURL("https://wwww.foo.com"); + form.url = GURL("https://wwww.foo.com"); AddFullCreditCardForm(&form, "Biggie Smalls", "378282246310005", "04", "2999"); @@ -2348,7 +2349,7 @@ TEST_F(FormDataImporterTest, ImportFormData_ImportCreditCardRecordType_NoCard_InvalidCardNumber) { // Simulate a form submission using a credit card with an invalid card number. FormData form; - form.origin = GURL("https://wwww.foo.com"); + form.url = GURL("https://wwww.foo.com"); AddFullCreditCardForm(&form, "Biggie Smalls", "4111 1111 1111 1112", "01", "2999"); @@ -2372,7 +2373,7 @@ TEST_F(FormDataImporterTest, ImportFormData_ImportCreditCardRecordType_NoCard_ExpiredCard) { // Simulate a form submission with an expired credit card. FormData form; - form.origin = GURL("https://wwww.foo.com"); + form.url = GURL("https://wwww.foo.com"); AddFullCreditCardForm(&form, "Biggie Smalls", "4111 1111 1111 1111", "01", "1999"); @@ -2396,7 +2397,7 @@ TEST_F(FormDataImporterTest, ImportFormData_ImportCreditCardRecordType_NoCard_NoCardOnForm) { // Simulate a form submission with no credit card on form. FormData form; - form.origin = GURL("https://wwww.foo.com"); + form.url = GURL("https://wwww.foo.com"); FormFieldData field; test::CreateTestFormField("First name:", "first_name", "George", "text", @@ -2438,7 +2439,7 @@ TEST_F(FormDataImporterTest, // address and the credit card. TEST_F(FormDataImporterTest, ImportFormData_OneAddressOneCreditCard) { FormData form; - form.origin = GURL("https://wwww.foo.com"); + form.url = GURL("https://wwww.foo.com"); FormFieldData field; // Address section. @@ -2503,7 +2504,7 @@ TEST_F(FormDataImporterTest, ImportFormData_OneAddressOneCreditCard) { // import the address but does import the credit card. TEST_F(FormDataImporterTest, ImportFormData_TwoAddressesOneCreditCard) { FormData form; - form.origin = GURL("https://wwww.foo.com"); + form.url = GURL("https://wwww.foo.com"); FormFieldData field; // Address section 1. @@ -2583,7 +2584,7 @@ TEST_F(FormDataImporterTest, ImportFormData_TwoAddressesOneCreditCard) { // the credit card if addresses are disabled. TEST_F(FormDataImporterTest, ImportFormData_AddressesDisabledOneCreditCard) { FormData form; - form.origin = GURL("https://wwww.foo.com"); + form.url = GURL("https://wwww.foo.com"); FormFieldData field; // Address section. @@ -2639,7 +2640,7 @@ TEST_F(FormDataImporterTest, ImportFormData_AddressesDisabledOneCreditCard) { // the address if credit cards are disabled. TEST_F(FormDataImporterTest, ImportFormData_OneAddressCreditCardDisabled) { FormData form; - form.origin = GURL("https://wwww.foo.com"); + form.url = GURL("https://wwww.foo.com"); FormFieldData field; // Address section. @@ -2699,7 +2700,7 @@ TEST_F(FormDataImporterTest, ImportFormData_OneAddressCreditCardDisabled) { // if both addressed and credit cards are disabled. TEST_F(FormDataImporterTest, ImportFormData_AddressCreditCardDisabled) { FormData form; - form.origin = GURL("https://wwww.foo.com"); + form.url = GURL("https://wwww.foo.com"); FormFieldData field; // Address section. @@ -2769,7 +2770,7 @@ TEST_F(FormDataImporterTest, DontDuplicateMaskedServerCard) { // A valid credit card form. A user re-enters one of their masked cards. // We should not offer to save locally. FormData form; - form.origin = GURL("https://wwww.foo.com"); + form.url = GURL("https://wwww.foo.com"); FormFieldData field; test::CreateTestFormField("Name on card:", "name_on_card", "John Dillinger", @@ -2800,7 +2801,7 @@ TEST_F(FormDataImporterTest, ImportFormData_HiddenCreditCardFormAfterEntered) { features::kAutofillImportNonFocusableCreditCardForms); FormData form; - form.origin = GURL("https://wwww.foo.com"); + form.url = GURL("https://wwww.foo.com"); FormFieldData field; @@ -2854,7 +2855,7 @@ TEST_F(FormDataImporterTest, features::kAutofillImportNonFocusableCreditCardForms); FormData form; - form.origin = GURL("https://wwww.foo.com"); + form.url = GURL("https://wwww.foo.com"); FormFieldData field; @@ -2913,7 +2914,7 @@ TEST_F(FormDataImporterTest, DontDuplicateFullServerCard) { // here, either. Since it's unmasked, we know for certain that it's the same // card. FormData form; - form.origin = GURL("https://wwww.foo.com"); + form.url = GURL("https://wwww.foo.com"); FormFieldData field; test::CreateTestFormField("Name on card:", "name_on_card", "Clyde Barrow", @@ -2957,7 +2958,7 @@ TEST_F(FormDataImporterTest, // A user fills/enters the card's information on a checkout form. Ensure that // an expiration date match is recorded. FormData form; - form.origin = GURL("https://wwww.foo.com"); + form.url = GURL("https://wwww.foo.com"); FormFieldData field; test::CreateTestFormField("Name on card:", "name_on_card", "Clyde Barrow", @@ -3009,7 +3010,7 @@ TEST_F(FormDataImporterTest, // A user fills/enters the card's information on a checkout form with an empty // expiration date. FormData form; - form.origin = GURL("https://wwww.foo.com"); + form.url = GURL("https://wwww.foo.com"); FormFieldData field; test::CreateTestFormField("Name on card:", "name_on_card", "Clyde Barrow", @@ -3057,7 +3058,7 @@ TEST_F(FormDataImporterTest, // A user fills/enters the card's information on a checkout form with an empty // expiration date. FormData form; - form.origin = GURL("https://wwww.foo.com"); + form.url = GURL("https://wwww.foo.com"); FormFieldData field; test::CreateTestFormField("Name on card:", "name_on_card", "Clyde Barrow", @@ -3106,7 +3107,7 @@ TEST_F( // A user fills/enters the card's information on a checkout form with an empty // expiration date. FormData form; - form.origin = GURL("https://wwww.foo.com"); + form.url = GURL("https://wwww.foo.com"); FormFieldData field; test::CreateTestFormField("Name on card:", "name_on_card", "Clyde Barrow", @@ -3151,7 +3152,7 @@ TEST_F(FormDataImporterTest, // the expiration date of the card. Ensure that an expiration date mismatch // is recorded. FormData form; - form.origin = GURL("https://wwww.foo.com"); + form.url = GURL("https://wwww.foo.com"); FormFieldData field; test::CreateTestFormField("Name on card:", "name_on_card", "Clyde Barrow", @@ -3200,7 +3201,7 @@ TEST_F(FormDataImporterTest, // A user fills/enters the card's information on a checkout form. Ensure that // an expiration date match is recorded. FormData form; - form.origin = GURL("https://wwww.foo.com"); + form.url = GURL("https://wwww.foo.com"); FormFieldData field; test::CreateTestFormField("Name on card:", "name_on_card", "Clyde Barrow", @@ -3250,7 +3251,7 @@ TEST_F(FormDataImporterTest, // the expiration date of the card. Ensure that an expiration date mismatch // is recorded. FormData form; - form.origin = GURL("https://wwww.foo.com"); + form.url = GURL("https://wwww.foo.com"); FormFieldData field; test::CreateTestFormField("Name on card:", "name_on_card", "Clyde Barrow", diff --git a/chromium/components/autofill/core/browser/form_structure.cc b/chromium/components/autofill/core/browser/form_structure.cc index 07adcce22f2..c2af03ad09d 100644 --- a/chromium/components/autofill/core/browser/form_structure.cc +++ b/chromium/components/autofill/core/browser/form_structure.cc @@ -9,6 +9,8 @@ #include <algorithm> #include <map> #include <memory> +#include <unordered_map> +#include <unordered_set> #include <utility> #include <vector> @@ -37,6 +39,7 @@ #include "components/autofill/core/browser/validation.h" #include "components/autofill/core/common/autofill_constants.h" #include "components/autofill/core/common/autofill_features.h" +#include "components/autofill/core/common/autofill_payments_features.h" #include "components/autofill/core/common/autofill_regex_constants.h" #include "components/autofill/core/common/autofill_regexes.h" #include "components/autofill/core/common/autofill_util.h" @@ -339,6 +342,7 @@ bool AllTypesCaptured(const FormStructure& form, void EncodePasswordAttributesVote( const std::pair<PasswordAttribute, bool>& password_attributes_vote, const size_t password_length_vote, + const int password_symbol_vote, AutofillUploadContents* upload) { switch (password_attributes_vote.first) { case PasswordAttribute::kHasLowercaseLetter: @@ -354,6 +358,8 @@ void EncodePasswordAttributesVote( break; case PasswordAttribute::kHasSpecialSymbol: upload->set_password_has_special_symbol(password_attributes_vote.second); + if (password_attributes_vote.second) + upload->set_password_special_symbol(password_symbol_vote); break; case PasswordAttribute::kPasswordAttributesCount: NOTREACHED(); @@ -460,6 +466,22 @@ void EncodeFieldMetadataForQuery(const FormFieldData& field, base::UTF16ToUTF8(field.placeholder)); } +// Creates the type relationship rules map. The keys represent the type that has +// rules, and the value represents the list of required types for the given +// key. In order to respect the rule, only one of the required types is needed. +// For example, for Autofill to support fields of type +// "PHONE_HOME_COUNTRY_CODE", there would need to be at least one other field +// of type "PHONE_HOME_NUMBER" or "PHONE_HOME_CITY_AND_NUMBER". +const std::unordered_map<ServerFieldType, ServerFieldTypeSet>& +GetTypeRelationshipMap() { + // Initialized and cached on first use. + static const auto* const rules = + new std::unordered_map<ServerFieldType, ServerFieldTypeSet>( + {{PHONE_HOME_COUNTRY_CODE, + {PHONE_HOME_NUMBER, PHONE_HOME_CITY_AND_NUMBER}}}); + return *rules; +} + } // namespace FormStructure::FormStructure(const FormData& form) @@ -468,7 +490,7 @@ FormStructure::FormStructure(const FormData& form) form_name_(form.name), button_titles_(form.button_titles), submission_event_(SubmissionIndicatorEvent::NONE), - source_url_(form.origin), + source_url_(form.url), target_url_(form.action), main_frame_origin_(form.main_frame_origin), autofill_count_(0), @@ -484,6 +506,7 @@ FormStructure::FormStructure(const FormData& form) all_fields_are_passwords_(!form.fields.empty()), form_parsed_timestamp_(base::TimeTicks::Now()), passwords_were_revealed_(false), + password_symbol_vote_(0), developer_engagement_metrics_(0) { // Copy the form fields. std::map<base::string16, size_t> unique_names; @@ -591,7 +614,8 @@ bool FormStructure::EncodeUploadRequest( if (password_attributes_vote_) { EncodePasswordAttributesVote(*password_attributes_vote_, - password_length_vote_, upload); + password_length_vote_, password_symbol_vote_, + upload); } if (IsAutofillFieldMetadataEnabled()) { @@ -775,7 +799,7 @@ std::vector<FormDataPredictions> FormStructure::GetFieldTypePredictions( for (const FormStructure* form_structure : form_structures) { FormDataPredictions form; form.data.name = form_structure->form_name_; - form.data.origin = form_structure->source_url_; + form.data.url = form_structure->source_url_; form.data.action = form_structure->target_url_; form.data.main_frame_origin = form_structure->main_frame_origin_; form.data.is_form_tag = form_structure->is_form_tag_; @@ -900,7 +924,7 @@ bool FormStructure::ShouldBeUploaded() const { void FormStructure::RetrieveFromCache( const FormStructure& cached_form, - const bool apply_is_autofilled, + const bool should_keep_cached_value, const bool only_server_and_autofill_state) { // Map from field signatures to cached fields. std::map<base::string16, const AutofillField*> cached_fields; @@ -921,14 +945,23 @@ void FormStructure::RetrieveFromCache( field->set_only_fill_when_focused( cached_field->second->only_fill_when_focused()); } - if (apply_is_autofilled) { + if (should_keep_cached_value) { field->is_autofilled = cached_field->second->is_autofilled; } - if (field->form_control_type != "select-one" && - field->value == cached_field->second->value) { - // From the perspective of learning user data, text fields containing - // default values are equivalent to empty fields. - field->value = base::string16(); + if (field->form_control_type != "select-one") { + bool is_credit_card_field = + AutofillType(cached_field->second->Type().GetStorableType()) + .group() == CREDIT_CARD; + if (should_keep_cached_value && is_credit_card_field && + base::FeatureList::IsEnabled( + features::kAutofillImportDynamicForms)) { + field->value = cached_field->second->value; + value_from_dynamic_change_form_ = true; + } else if (field->value == cached_field->second->value) { + // From the perspective of learning user data, text fields containing + // default values are equivalent to empty fields. + field->value = base::string16(); + } } field->set_server_type(cached_field->second->server_type()); field->set_previously_autofilled( @@ -1221,24 +1254,6 @@ std::set<base::string16> FormStructure::PossibleValues(ServerFieldType type) { return values; } -base::string16 FormStructure::GetUniqueValue(HtmlFieldType type) const { - base::string16 value; - for (const auto& field : fields_) { - if (field->html_type() != type) - continue; - - // More than one value found; abort rather than choosing one arbitrarily. - if (!value.empty() && !field->value.empty()) { - value.clear(); - break; - } - - value = field->value; - } - - return value; -} - const AutofillField* FormStructure::field(size_t index) const { if (index >= fields_.size()) { NOTREACHED(); @@ -1264,7 +1279,7 @@ size_t FormStructure::active_field_count() const { FormData FormStructure::ToFormData() const { FormData data; data.name = form_name_; - data.origin = source_url_; + data.url = source_url_; data.action = target_url_; data.main_frame_origin = main_frame_origin_; @@ -1277,7 +1292,7 @@ FormData FormStructure::ToFormData() const { bool FormStructure::operator==(const FormData& form) const { // TODO(jhawkins): Is this enough to differentiate a form? - if (form_name_ == form.name && source_url_ == form.origin && + if (form_name_ == form.name && source_url_ == form.url && target_url_ == form.action) { return true; } @@ -1719,8 +1734,16 @@ void FormStructure::RationalizeRepeatedFields( void FormStructure::RationalizeFieldTypePredictions() { RationalizeCreditCardFieldPredictions(); for (const auto& field : fields_) { - field->SetTypeTo(field->Type()); + if (base::FeatureList::IsEnabled(features::kAutofillOffNoServerData) && + !field->should_autocomplete && field->server_type() == NO_SERVER_DATA) { + // When the field has autocomplete off, and the server returned no + // prediction, then assume Autofill is not useful for the current field. + field->SetTypeTo(AutofillType(UNKNOWN_TYPE)); + } else { + field->SetTypeTo(field->Type()); + } } + RationalizeTypeRelationships(); } void FormStructure::EncodeFormForQuery( @@ -2031,4 +2054,38 @@ void FormStructure::set_randomized_encoder( randomized_encoder_ = std::move(encoder); } +void FormStructure::RationalizeTypeRelationships() { + // Create a local set of all the types for faster lookup. + std::unordered_set<ServerFieldType> types; + for (const auto& field : fields_) { + types.insert(field->Type().GetStorableType()); + } + + const auto& type_relationship_rules = GetTypeRelationshipMap(); + + for (const auto& field : fields_) { + ServerFieldType field_type = field->Type().GetStorableType(); + const auto& ruleset_iterator = type_relationship_rules.find(field_type); + if (ruleset_iterator != type_relationship_rules.end()) { + // We have relationship rules for this type. Verify that at least one of + // the required related type is present. + bool found = false; + for (ServerFieldType required_type : ruleset_iterator->second) { + if (types.find(required_type) != types.end()) { + // Found a required type, we can break as we only need one required + // type to respect the rule. + found = true; + break; + } + } + + if (!found) { + // No required type was found, the current field failed the relationship + // requirements for its type. Disabling Autofill for this field. + field->SetTypeTo(AutofillType(UNKNOWN_TYPE)); + } + } + } +} + } // namespace autofill diff --git a/chromium/components/autofill/core/browser/form_structure.h b/chromium/components/autofill/core/browser/form_structure.h index 414345d7744..df85abceb14 100644 --- a/chromium/components/autofill/core/browser/form_structure.h +++ b/chromium/components/autofill/core/browser/form_structure.h @@ -11,6 +11,7 @@ #include <memory> #include <set> #include <string> +#include <utility> #include <vector> #include "base/gtest_prod_util.h" @@ -147,7 +148,7 @@ class FormStructure { // Sets the field types to be those set for |cached_form|. void RetrieveFromCache(const FormStructure& cached_form, - const bool apply_is_autofilled, + const bool should_keep_cached_value, const bool only_server_and_autofill_state); // Logs quality metrics for |this|, which should be a user-submitted form. @@ -194,10 +195,6 @@ class FormStructure { // All returned values are standardized to upper case. std::set<base::string16> PossibleValues(ServerFieldType type); - // Gets the form's current value for |type|. For example, it may return - // the contents of a text input or the currently selected <option>. - base::string16 GetUniqueValue(HtmlFieldType type) const; - // Rationalize phone number fields in a given section, that is only fill // the fields that are considered composing a first complete phone number. void RationalizePhoneNumbersInSection(std::string section); @@ -305,11 +302,26 @@ class FormStructure { } #endif + void set_password_symbol_vote(int noisified_symbol) { + DCHECK(password_attributes_vote_.has_value()) + << "password_symbol_vote_| doesn't make sense if " + "|password_attributes_vote_| has no value."; + password_symbol_vote_ = noisified_symbol; + } + +#if defined(UNIT_TEST) + int get_password_symbol_vote_for_testing() { + DCHECK(password_attributes_vote_.has_value()) + << "|password_symbol_vote_| doesn't make sense if " + "|password_attributes_vote_| has no value"; + return password_symbol_vote_; + } +#endif + SubmissionSource submission_source() const { return submission_source_; } void set_submission_source(SubmissionSource submission_source) { submission_source_ = submission_source; } - bool operator==(const FormData& form) const; bool operator!=(const FormData& form) const; @@ -331,6 +343,14 @@ class FormStructure { page_language_ = std::move(language); } + bool value_from_dynamic_change_form() const { + return value_from_dynamic_change_form_; + } + + void set_value_from_dynamic_change_form(bool v) { + value_from_dynamic_change_form_ = v; + } + private: friend class AutofillMergeTest; friend class FormStructureTest; @@ -438,6 +458,10 @@ class FormStructure { // Tunes the fields with identical predictions. void RationalizeRepeatedFields(AutofillMetrics::FormInteractionsUkmLogger*); + // Filters out fields that don't meet the relationship ruleset for their type + // defined in |type_relationships_rules_|. + void RationalizeTypeRelationships(); + // A helper function to review the predictions and do appropriate adjustments // when it considers necessary. void RationalizeFieldTypePredictions(); @@ -568,6 +592,12 @@ class FormStructure { // character). base::Optional<std::pair<PasswordAttribute, bool>> password_attributes_vote_; + // If |password_attribute_vote_| contains (kHasSpecialSymbol, true), this + // field contains nosified information about a special symbol in a + // user-created password stored as ASCII code. The default value of 0 + // indicates that no symbol was set. + int password_symbol_vote_; + // Noisified password length for crowdsourcing. If |password_attributes_vote_| // has no value, |password_length_vote_| should be ignored. size_t password_length_vote_; @@ -587,6 +617,8 @@ class FormStructure { // form/field metadata. bool is_rich_query_enabled_ = false; + bool value_from_dynamic_change_form_ = false; + DISALLOW_COPY_AND_ASSIGN(FormStructure); }; diff --git a/chromium/components/autofill/core/browser/form_structure_unittest.cc b/chromium/components/autofill/core/browser/form_structure_unittest.cc index cdc3cd526ad..cff3806b32f 100644 --- a/chromium/components/autofill/core/browser/form_structure_unittest.cc +++ b/chromium/components/autofill/core/browser/form_structure_unittest.cc @@ -143,10 +143,14 @@ class FormStructureTest : public testing::Test { scoped_refptr<base::FieldTrial> field_trial_; }; +class ParameterizedFormStructureTest + : public FormStructureTest, + public testing::WithParamInterface<bool> {}; + TEST_F(FormStructureTest, FieldCount) { std::unique_ptr<FormStructure> form_structure; FormData form; - form.origin = GURL("http://www.foo.com/"); + form.url = GURL("http://www.foo.com/"); FormFieldData field; field.label = ASCIIToUTF16("username"); @@ -179,7 +183,7 @@ TEST_F(FormStructureTest, FieldCount) { TEST_F(FormStructureTest, AutofillCount) { std::unique_ptr<FormStructure> form_structure; FormData form; - form.origin = GURL("http://www.foo.com/"); + form.url = GURL("http://www.foo.com/"); FormFieldData field; field.label = ASCIIToUTF16("username"); @@ -232,15 +236,15 @@ TEST_F(FormStructureTest, AutofillCount) { TEST_F(FormStructureTest, SourceURL) { FormData form; - form.origin = GURL("http://www.foo.com/"); + form.url = GURL("http://www.foo.com/"); FormStructure form_structure(form); - EXPECT_EQ(form.origin, form_structure.source_url()); + EXPECT_EQ(form.url, form_structure.source_url()); } TEST_F(FormStructureTest, IsAutofillable) { FormData form; - form.origin = GURL("http://www.foo.com/"); + form.url = GURL("http://www.foo.com/"); FormFieldData field; // Start with a username field. It should be picked up by the password but @@ -308,7 +312,7 @@ TEST_F(FormStructureTest, IsAutofillable) { TEST_F(FormStructureTest, ShouldBeParsed) { FormData form; - form.origin = GURL("http://www.foo.com/"); + form.url = GURL("http://www.foo.com/"); // Start with a single checkable field. FormFieldData checkable_field; @@ -426,7 +430,7 @@ TEST_F(FormStructureTest, ShouldBeParsed_BadScheme) { form.fields.push_back(field); // Baseline, HTTP should work. - form.origin = GURL("http://wwww.foo.com/myform"); + form.url = GURL("http://wwww.foo.com/myform"); form_structure = std::make_unique<FormStructure>(form); form_structure->ParseFieldTypesFromAutocompleteAttributes(); EXPECT_TRUE(form_structure->ShouldBeParsed()); @@ -435,7 +439,7 @@ TEST_F(FormStructureTest, ShouldBeParsed_BadScheme) { EXPECT_TRUE(form_structure->ShouldBeUploaded()); // Baseline, HTTPS should work. - form.origin = GURL("https://wwww.foo.com/myform"); + form.url = GURL("https://wwww.foo.com/myform"); form_structure = std::make_unique<FormStructure>(form); form_structure->ParseFieldTypesFromAutocompleteAttributes(); EXPECT_TRUE(form_structure->ShouldBeParsed()); @@ -444,7 +448,7 @@ TEST_F(FormStructureTest, ShouldBeParsed_BadScheme) { EXPECT_TRUE(form_structure->ShouldBeUploaded()); // Chrome internal urls shouldn't be parsed. - form.origin = GURL("chrome://settings"); + form.url = GURL("chrome://settings"); form_structure = std::make_unique<FormStructure>(form); form_structure->ParseFieldTypesFromAutocompleteAttributes(); EXPECT_FALSE(form_structure->ShouldBeParsed()); @@ -453,7 +457,7 @@ TEST_F(FormStructureTest, ShouldBeParsed_BadScheme) { EXPECT_FALSE(form_structure->ShouldBeUploaded()); // FTP urls shouldn't be parsed. - form.origin = GURL("ftp://ftp.foo.com/form.html"); + form.url = GURL("ftp://ftp.foo.com/form.html"); form_structure = std::make_unique<FormStructure>(form); form_structure->ParseFieldTypesFromAutocompleteAttributes(); EXPECT_FALSE(form_structure->ShouldBeParsed()); @@ -462,7 +466,7 @@ TEST_F(FormStructureTest, ShouldBeParsed_BadScheme) { EXPECT_FALSE(form_structure->ShouldBeUploaded()); // Blob urls shouldn't be parsed. - form.origin = GURL("blob://blob.foo.com/form.html"); + form.url = GURL("blob://blob.foo.com/form.html"); form_structure = std::make_unique<FormStructure>(form); form_structure->ParseFieldTypesFromAutocompleteAttributes(); EXPECT_FALSE(form_structure->ShouldBeParsed()); @@ -471,7 +475,7 @@ TEST_F(FormStructureTest, ShouldBeParsed_BadScheme) { EXPECT_FALSE(form_structure->ShouldBeUploaded()); // About urls shouldn't be parsed. - form.origin = GURL("about://about.foo.com/form.html"); + form.url = GURL("about://about.foo.com/form.html"); form_structure = std::make_unique<FormStructure>(form); form_structure->ParseFieldTypesFromAutocompleteAttributes(); EXPECT_FALSE(form_structure->ShouldBeParsed()); @@ -485,7 +489,7 @@ TEST_F(FormStructureTest, ShouldBeParsed_BadScheme) { TEST_F(FormStructureTest, ShouldBeParsed_TwoFields_HasAutocomplete) { std::unique_ptr<FormStructure> form_structure; FormData form; - form.origin = GURL("http://www.foo.com/"); + form.url = GURL("http://www.foo.com/"); FormFieldData field; field.label = ASCIIToUTF16("Name"); @@ -510,7 +514,7 @@ TEST_F(FormStructureTest, ShouldBeParsed_TwoFields_HasAutocomplete) { TEST_F(FormStructureTest, DetermineHeuristicTypes_AutocompleteFalse) { std::unique_ptr<FormStructure> form_structure; FormData form; - form.origin = GURL("http://www.foo.com/"); + form.url = GURL("http://www.foo.com/"); FormFieldData field; field.label = ASCIIToUTF16("Name"); @@ -544,7 +548,7 @@ TEST_F(FormStructureTest, DetermineHeuristicTypes_AutocompleteFalse) { TEST_F(FormStructureTest, HeuristicsContactInfo) { std::unique_ptr<FormStructure> form_structure; FormData form; - form.origin = GURL("http://www.foo.com/"); + form.url = GURL("http://www.foo.com/"); FormFieldData field; field.form_control_type = "text"; @@ -619,7 +623,7 @@ TEST_F(FormStructureTest, HeuristicsContactInfo) { TEST_F(FormStructureTest, HeuristicsAutocompleteAttribute) { std::unique_ptr<FormStructure> form_structure; FormData form; - form.origin = GURL("http://www.foo.com/"); + form.url = GURL("http://www.foo.com/"); FormFieldData field; field.form_control_type = "text"; @@ -671,7 +675,7 @@ TEST_F(FormStructureTest, Heuristics_FormlessNonCheckoutForm) { features::kAutofillRestrictUnownedFieldsToFormlessCheckout); std::unique_ptr<FormStructure> form_structure; FormData form; - form.origin = GURL("http://www.foo.com/"); + form.url = GURL("http://www.foo.com/"); FormFieldData field; field.form_control_type = "text"; @@ -724,7 +728,7 @@ TEST_F(FormStructureTest, Heuristics_FormlessNonCheckoutForm) { // that the common prefix is stripped out before running heuristics. TEST_F(FormStructureTest, StripCommonNamePrefix) { FormData form; - form.origin = GURL("http://www.foo.com/"); + form.url = GURL("http://www.foo.com/"); FormFieldData field; field.form_control_type = "text"; @@ -775,7 +779,7 @@ TEST_F(FormStructureTest, StripCommonNamePrefix) { // stripped from the name before running the heuristics. TEST_F(FormStructureTest, StripCommonNamePrefix_SmallPrefix) { FormData form; - form.origin = GURL("http://www.foo.com/"); + form.url = GURL("http://www.foo.com/"); FormFieldData field; field.form_control_type = "text"; @@ -811,7 +815,7 @@ TEST_F(FormStructureTest, StripCommonNamePrefix_SmallPrefix) { TEST_F(FormStructureTest, IsCompleteCreditCardForm_Minimal) { std::unique_ptr<FormStructure> form_structure; FormData form; - form.origin = GURL("http://www.foo.com/"); + form.url = GURL("http://www.foo.com/"); FormFieldData field; field.form_control_type = "text"; @@ -838,7 +842,7 @@ TEST_F(FormStructureTest, IsCompleteCreditCardForm_Minimal) { TEST_F(FormStructureTest, IsCompleteCreditCardForm_Full) { std::unique_ptr<FormStructure> form_structure; FormData form; - form.origin = GURL("http://www.foo.com/"); + form.url = GURL("http://www.foo.com/"); FormFieldData field; field.form_control_type = "text"; @@ -878,7 +882,7 @@ TEST_F(FormStructureTest, IsCompleteCreditCardForm_Full) { TEST_F(FormStructureTest, IsCompleteCreditCardForm_OnlyCCNumber) { std::unique_ptr<FormStructure> form_structure; FormData form; - form.origin = GURL("http://www.foo.com/"); + form.url = GURL("http://www.foo.com/"); FormFieldData field; field.form_control_type = "text"; @@ -897,7 +901,7 @@ TEST_F(FormStructureTest, IsCompleteCreditCardForm_OnlyCCNumber) { TEST_F(FormStructureTest, IsCompleteCreditCardForm_AddressForm) { std::unique_ptr<FormStructure> form_structure; FormData form; - form.origin = GURL("http://www.foo.com/"); + form.url = GURL("http://www.foo.com/"); FormFieldData field; field.form_control_type = "text"; @@ -940,7 +944,7 @@ TEST_F(FormStructureTest, IsCompleteCreditCardForm_AddressForm) { TEST_F(FormStructureTest, HeuristicsAutocompleteAttributePhoneTypes) { std::unique_ptr<FormStructure> form_structure; FormData form; - form.origin = GURL("http://www.foo.com/"); + form.url = GURL("http://www.foo.com/"); FormFieldData field; field.form_control_type = "text"; @@ -984,7 +988,7 @@ TEST_F(FormStructureTest, HeuristicsAndServerPredictions_BigForm_NoAutocompleteAttribute) { std::unique_ptr<FormStructure> form_structure; FormData form; - form.origin = GURL("http://www.foo.com/"); + form.url = GURL("http://www.foo.com/"); FormFieldData field; field.form_control_type = "text"; @@ -1021,7 +1025,7 @@ TEST_F(FormStructureTest, HeuristicsAndServerPredictions_ValidAutocompleteAttribute) { std::unique_ptr<FormStructure> form_structure; FormData form; - form.origin = GURL("http://www.foo.com/"); + form.url = GURL("http://www.foo.com/"); FormFieldData field; field.form_control_type = "text"; @@ -1062,7 +1066,7 @@ TEST_F(FormStructureTest, HeuristicsAndServerPredictions_UnrecognizedAutocompleteAttribute) { std::unique_ptr<FormStructure> form_structure; FormData form; - form.origin = GURL("http://www.foo.com/"); + form.url = GURL("http://www.foo.com/"); FormFieldData field; field.form_control_type = "text"; @@ -1105,7 +1109,7 @@ TEST_F(FormStructureTest, TEST_F(FormStructureTest, HeuristicsAndServerPredictions_SmallForm_NoAutocompleteAttribute) { FormData form; - form.origin = GURL("http://www.foo.com/"); + form.url = GURL("http://www.foo.com/"); FormFieldData field; field.form_control_type = "text"; @@ -1179,7 +1183,7 @@ TEST_F(FormStructureTest, TEST_F(FormStructureTest, HeuristicsAndServerPredictions_SmallForm_ValidAutocompleteAttribute) { FormData form; - form.origin = GURL("http://www.foo.com/"); + form.url = GURL("http://www.foo.com/"); FormFieldData field; field.form_control_type = "text"; @@ -1266,7 +1270,7 @@ TEST_F(FormStructureTest, // considered autofillable though. TEST_F(FormStructureTest, PasswordFormShouldBeQueried) { FormData form; - form.origin = GURL("http://www.foo.com/"); + form.url = GURL("http://www.foo.com/"); // Start with a regular contact form. FormFieldData field; @@ -1301,7 +1305,7 @@ TEST_F(FormStructureTest, PasswordFormShouldBeQueried) { // attribute. TEST_F(FormStructureTest, HeuristicsAutocompleteAttributeWithSections) { FormData form; - form.origin = GURL("http://www.foo.com/"); + form.url = GURL("http://www.foo.com/"); FormFieldData field; field.form_control_type = "text"; @@ -1366,7 +1370,7 @@ TEST_F(FormStructureTest, HeuristicsAutocompleteAttributeWithSections) { TEST_F(FormStructureTest, HeuristicsAutocompleteAttributeWithSectionsDegenerate) { FormData form; - form.origin = GURL("http://www.foo.com/"); + form.url = GURL("http://www.foo.com/"); FormFieldData field; field.form_control_type = "text"; @@ -1410,7 +1414,7 @@ TEST_F(FormStructureTest, // |autocomplete| attribute. TEST_F(FormStructureTest, HeuristicsAutocompleteAttributeWithSectionsRepeated) { FormData form; - form.origin = GURL("http://www.foo.com/"); + form.url = GURL("http://www.foo.com/"); FormFieldData field; field.form_control_type = "text"; @@ -1440,7 +1444,7 @@ TEST_F(FormStructureTest, HeuristicsAutocompleteAttributeWithSectionsRepeated) { // local heuristics. TEST_F(FormStructureTest, HeuristicsDontOverrideAutocompleteAttributeSections) { FormData form; - form.origin = GURL("http://www.foo.com/"); + form.url = GURL("http://www.foo.com/"); FormFieldData field; field.form_control_type = "text"; @@ -1476,7 +1480,7 @@ TEST_F(FormStructureTest, HeuristicsDontOverrideAutocompleteAttributeSections) { TEST_F(FormStructureTest, HeuristicsSample8) { std::unique_ptr<FormStructure> form_structure; FormData form; - form.origin = GURL("http://www.foo.com/"); + form.url = GURL("http://www.foo.com/"); FormFieldData field; field.form_control_type = "text"; @@ -1554,7 +1558,7 @@ TEST_F(FormStructureTest, HeuristicsSample8) { TEST_F(FormStructureTest, HeuristicsSample6) { std::unique_ptr<FormStructure> form_structure; FormData form; - form.origin = GURL("http://www.foo.com/"); + form.url = GURL("http://www.foo.com/"); FormFieldData field; field.form_control_type = "text"; @@ -1617,7 +1621,7 @@ TEST_F(FormStructureTest, HeuristicsSample6) { TEST_F(FormStructureTest, HeuristicsLabelsOnly) { std::unique_ptr<FormStructure> form_structure; FormData form; - form.origin = GURL("http://www.foo.com/"); + form.url = GURL("http://www.foo.com/"); FormFieldData field; field.form_control_type = "text"; @@ -1683,7 +1687,7 @@ TEST_F(FormStructureTest, HeuristicsLabelsOnly) { TEST_F(FormStructureTest, HeuristicsCreditCardInfo) { std::unique_ptr<FormStructure> form_structure; FormData form; - form.origin = GURL("http://www.foo.com/"); + form.url = GURL("http://www.foo.com/"); FormFieldData field; field.form_control_type = "text"; @@ -1738,7 +1742,7 @@ TEST_F(FormStructureTest, HeuristicsCreditCardInfo) { TEST_F(FormStructureTest, HeuristicsCreditCardInfoWithUnknownCardField) { std::unique_ptr<FormStructure> form_structure; FormData form; - form.origin = GURL("http://www.foo.com/"); + form.url = GURL("http://www.foo.com/"); FormFieldData field; field.form_control_type = "text"; @@ -1801,7 +1805,7 @@ TEST_F(FormStructureTest, HeuristicsCreditCardInfoWithUnknownCardField) { TEST_F(FormStructureTest, ThreeAddressLines) { std::unique_ptr<FormStructure> form_structure; FormData form; - form.origin = GURL("http://www.foo.com/"); + form.url = GURL("http://www.foo.com/"); FormFieldData field; field.form_control_type = "text"; @@ -1842,7 +1846,7 @@ TEST_F(FormStructureTest, ThreeAddressLines) { TEST_F(FormStructureTest, SurplusAddressLinesIgnored) { std::unique_ptr<FormStructure> form_structure; FormData form; - form.origin = GURL("http://www.foo.com/"); + form.url = GURL("http://www.foo.com/"); FormFieldData field; field.form_control_type = "text"; @@ -1886,7 +1890,7 @@ TEST_F(FormStructureTest, SurplusAddressLinesIgnored) { TEST_F(FormStructureTest, ThreeAddressLinesExpedia) { std::unique_ptr<FormStructure> form_structure; FormData form; - form.origin = GURL("http://www.foo.com/"); + form.url = GURL("http://www.foo.com/"); FormFieldData field; field.form_control_type = "text"; @@ -1929,7 +1933,7 @@ TEST_F(FormStructureTest, ThreeAddressLinesExpedia) { TEST_F(FormStructureTest, TwoAddressLinesEbay) { std::unique_ptr<FormStructure> form_structure; FormData form; - form.origin = GURL("http://www.foo.com/"); + form.url = GURL("http://www.foo.com/"); FormFieldData field; field.form_control_type = "text"; @@ -1963,7 +1967,7 @@ TEST_F(FormStructureTest, TwoAddressLinesEbay) { TEST_F(FormStructureTest, HeuristicsStateWithProvince) { std::unique_ptr<FormStructure> form_structure; FormData form; - form.origin = GURL("http://www.foo.com/"); + form.url = GURL("http://www.foo.com/"); FormFieldData field; field.form_control_type = "text"; @@ -1998,7 +2002,7 @@ TEST_F(FormStructureTest, HeuristicsStateWithProvince) { TEST_F(FormStructureTest, HeuristicsWithBilling) { std::unique_ptr<FormStructure> form_structure; FormData form; - form.origin = GURL("http://www.foo.com/"); + form.url = GURL("http://www.foo.com/"); FormFieldData field; field.form_control_type = "text"; @@ -2070,7 +2074,7 @@ TEST_F(FormStructureTest, HeuristicsWithBilling) { TEST_F(FormStructureTest, ThreePartPhoneNumber) { std::unique_ptr<FormStructure> form_structure; FormData form; - form.origin = GURL("http://www.foo.com/"); + form.url = GURL("http://www.foo.com/"); FormFieldData field; field.form_control_type = "text"; @@ -2116,7 +2120,7 @@ TEST_F(FormStructureTest, ThreePartPhoneNumber) { TEST_F(FormStructureTest, HeuristicsInfernoCC) { std::unique_ptr<FormStructure> form_structure; FormData form; - form.origin = GURL("http://www.foo.com/"); + form.url = GURL("http://www.foo.com/"); FormFieldData field; field.form_control_type = "text"; @@ -2167,7 +2171,7 @@ TEST_F(FormStructureTest, HeuristicsInfernoCC) { TEST_F(FormStructureTest, HeuristicsInferCCNames_NamesNotFirst) { std::unique_ptr<FormStructure> form_structure; FormData form; - form.origin = GURL("http://www.foo.com/"); + form.url = GURL("http://www.foo.com/"); FormFieldData field; field.form_control_type = "text"; @@ -2226,7 +2230,7 @@ TEST_F(FormStructureTest, HeuristicsInferCCNames_NamesNotFirst) { TEST_F(FormStructureTest, HeuristicsInferCCNames_NamesFirst) { std::unique_ptr<FormStructure> form_structure; FormData form; - form.origin = GURL("http://www.foo.com/"); + form.url = GURL("http://www.foo.com/"); FormFieldData field; field.form_control_type = "text"; @@ -2281,7 +2285,7 @@ TEST_F(FormStructureTest, HeuristicsInferCCNames_NamesFirst) { TEST_F(FormStructureTest, EncodeQueryRequest) { FormData form; - form.origin = GURL("http://www.foo.com/"); + form.url = GURL("http://www.foo.com/"); FormFieldData field; field.form_control_type = "text"; @@ -2443,7 +2447,7 @@ TEST_F(FormStructureTest, EncodeUploadRequest_WithMatchingValidities) { std::vector<ServerFieldTypeSet> possible_field_types; std::vector<ServerFieldTypeValidityStatesMap> possible_field_types_validities; FormData form; - form.origin = GURL("http://www.foo.com/"); + form.url = GURL("http://www.foo.com/"); form.is_form_tag = true; form_structure = std::make_unique<FormStructure>(form); @@ -2638,7 +2642,7 @@ TEST_F(FormStructureTest, EncodeUploadRequest_WithNonMatchingValidities) { std::vector<ServerFieldTypeSet> possible_field_types; std::vector<ServerFieldTypeValidityStatesMap> possible_field_types_validities; FormData form; - form.origin = GURL("http://www.foo.com/"); + form.url = GURL("http://www.foo.com/"); form_structure = std::make_unique<FormStructure>(form); form_structure->DetermineHeuristicTypes(); @@ -2766,7 +2770,7 @@ TEST_F(FormStructureTest, EncodeUploadRequest_WithMultipleValidities) { std::vector<ServerFieldTypeSet> possible_field_types; std::vector<ServerFieldTypeValidityStatesMap> possible_field_types_validities; FormData form; - form.origin = GURL("http://www.foo.com/"); + form.url = GURL("http://www.foo.com/"); form.is_form_tag = true; form_structure = std::make_unique<FormStructure>(form); @@ -2895,7 +2899,7 @@ TEST_F(FormStructureTest, EncodeUploadRequest) { std::vector<ServerFieldTypeSet> possible_field_types; std::vector<ServerFieldTypeValidityStatesMap> possible_field_types_validities; FormData form; - form.origin = GURL("http://www.foo.com/"); + form.url = GURL("http://www.foo.com/"); form.is_form_tag = true; form_structure = std::make_unique<FormStructure>(form); @@ -3108,7 +3112,7 @@ TEST_F(FormStructureTest, std::vector<ServerFieldTypeSet> possible_field_types; std::vector<ServerFieldTypeValidityStatesMap> possible_field_types_validities; FormData form; - form.origin = GURL("http://www.foo.com/"); + form.url = GURL("http://www.foo.com/"); form.is_form_tag = true; form_structure = std::make_unique<FormStructure>(form); @@ -3234,7 +3238,7 @@ TEST_F(FormStructureTest, EncodeUploadRequest_WithAutocomplete) { std::vector<ServerFieldTypeSet> possible_field_types; std::vector<ServerFieldTypeValidityStatesMap> possible_field_types_validities; FormData form; - form.origin = GURL("http://www.foo.com/"); + form.url = GURL("http://www.foo.com/"); form.is_form_tag = true; form_structure = std::make_unique<FormStructure>(form); @@ -3318,7 +3322,7 @@ TEST_F(FormStructureTest, EncodeUploadRequestWithPropertiesMask) { std::vector<ServerFieldTypeSet> possible_field_types; std::vector<ServerFieldTypeValidityStatesMap> possible_field_types_validities; FormData form; - form.origin = GURL("http://www.foo.com/"); + form.url = GURL("http://www.foo.com/"); form.is_form_tag = true; form_structure = std::make_unique<FormStructure>(form); @@ -3418,7 +3422,7 @@ TEST_F(FormStructureTest, EncodeUploadRequest_ObservedSubmissionFalse) { std::vector<ServerFieldTypeSet> possible_field_types; std::vector<ServerFieldTypeValidityStatesMap> possible_field_types_validities; FormData form; - form.origin = GURL("http://www.foo.com/"); + form.url = GURL("http://www.foo.com/"); form.is_form_tag = true; form_structure = std::make_unique<FormStructure>(form); @@ -3501,7 +3505,7 @@ TEST_F(FormStructureTest, EncodeUploadRequest_WithLabels) { std::vector<ServerFieldTypeSet> possible_field_types; std::vector<ServerFieldTypeValidityStatesMap> possible_field_types_validities; FormData form; - form.origin = GURL("http://www.foo.com/"); + form.url = GURL("http://www.foo.com/"); form.is_form_tag = true; form_structure = std::make_unique<FormStructure>(form); @@ -3575,7 +3579,7 @@ TEST_F(FormStructureTest, EncodeUploadRequest_WithCssClassesAndIds) { std::vector<ServerFieldTypeSet> possible_field_types; std::vector<ServerFieldTypeValidityStatesMap> possible_field_types_validities; FormData form; - form.origin = GURL("http://www.foo.com/"); + form.url = GURL("http://www.foo.com/"); form.is_form_tag = true; FormFieldData field; @@ -3657,7 +3661,7 @@ TEST_F(FormStructureTest, EncodeUploadRequest_WithFormName) { std::vector<ServerFieldTypeSet> possible_field_types; std::vector<ServerFieldTypeValidityStatesMap> possible_field_types_validities; FormData form; - form.origin = GURL("http://www.foo.com/"); + form.url = GURL("http://www.foo.com/"); form.is_form_tag = true; // Setting the form name which we expect to see in the upload. @@ -3734,7 +3738,7 @@ TEST_F(FormStructureTest, EncodeUploadRequestPartialMetadata) { std::vector<ServerFieldTypeSet> possible_field_types; std::vector<ServerFieldTypeValidityStatesMap> possible_field_types_validities; FormData form; - form.origin = GURL("http://www.foo.com/"); + form.url = GURL("http://www.foo.com/"); form.is_form_tag = true; form_structure = std::make_unique<FormStructure>(form); @@ -3819,7 +3823,7 @@ TEST_F(FormStructureTest, EncodeUploadRequest_DisabledMetadataTrial) { std::vector<ServerFieldTypeSet> possible_field_types; std::vector<ServerFieldTypeValidityStatesMap> possible_field_types_validities; FormData form; - form.origin = GURL("http://www.foo.com/"); + form.url = GURL("http://www.foo.com/"); form.is_form_tag = true; form_structure = std::make_unique<FormStructure>(form); @@ -3908,7 +3912,7 @@ TEST_F(FormStructureTest, EncodeUploadRequest_DisabledMetadataTrial) { // |available_types|. TEST_F(FormStructureTest, CheckDataPresence) { FormData form; - form.origin = GURL("http://www.foo.com/"); + form.url = GURL("http://www.foo.com/"); form.is_form_tag = true; FormFieldData field; @@ -4188,7 +4192,7 @@ TEST_F(FormStructureTest, CheckMultipleTypes) { std::vector<ServerFieldTypeSet> possible_field_types; std::vector<ServerFieldTypeValidityStatesMap> possible_field_types_validities; FormData form; - form.origin = GURL("http://www.foo.com/"); + form.url = GURL("http://www.foo.com/"); form.is_form_tag = false; FormFieldData field; @@ -4331,7 +4335,7 @@ TEST_F(FormStructureTest, CheckMultipleTypes) { TEST_F(FormStructureTest, EncodeUploadRequest_PasswordsRevealed) { FormData form; - form.origin = GURL("http://www.foo.com/"); + form.url = GURL("http://www.foo.com/"); // Add 3 fields, to make the form uploadable. FormFieldData field; @@ -4362,7 +4366,7 @@ TEST_F(FormStructureTest, EncodeUploadRequest_IsFormTag) { SCOPED_TRACE(testing::Message() << "is_form_tag=" << is_form_tag); FormData form; - form.origin = GURL("http://www.foo.com/"); + form.url = GURL("http://www.foo.com/"); FormFieldData field; field.name = ASCIIToUTF16("email"); form.fields.push_back(field); @@ -4397,7 +4401,7 @@ TEST_F(FormStructureTest, EncodeUploadRequest_RichMetadata) { }; FormData form; - form.origin = GURL("http://www.foo.com/"); + form.url = GURL("http://www.foo.com/"); for (const auto& f : kFieldMetadata) { FormFieldData field; field.id_attribute = ASCIIToUTF16(f.id); @@ -4499,7 +4503,7 @@ TEST_F(FormStructureTest, CheckFormSignature) { EXPECT_EQ(FormStructureTest::Hash64Bit(std::string("://&&email&first")), form_structure->FormSignatureAsStr()); - form.origin = GURL(std::string("http://www.facebook.com")); + form.url = GURL(std::string("http://www.facebook.com")); form_structure = std::make_unique<FormStructure>(form); EXPECT_EQ(FormStructureTest::Hash64Bit( std::string("http://www.facebook.com&&email&first")), @@ -4542,8 +4546,8 @@ TEST_F(FormStructureTest, CheckFormSignature) { TEST_F(FormStructureTest, ToFormData) { FormData form; form.name = ASCIIToUTF16("the-name"); - form.origin = GURL("http://cool.com"); - form.action = form.origin.Resolve("/login"); + form.url = GURL("http://cool.com"); + form.action = form.url.Resolve("/login"); FormFieldData field; field.label = ASCIIToUTF16("username"); @@ -4567,8 +4571,8 @@ TEST_F(FormStructureTest, ToFormData) { TEST_F(FormStructureTest, SkipFieldTest) { FormData form; form.name = ASCIIToUTF16("the-name"); - form.origin = GURL("http://cool.com"); - form.action = form.origin.Resolve("/login"); + form.url = GURL("http://cool.com"); + form.action = form.url.Resolve("/login"); FormFieldData field; field.label = ASCIIToUTF16("username"); @@ -4621,8 +4625,8 @@ TEST_F(FormStructureTest, SkipFieldTest) { TEST_F(FormStructureTest, EncodeQueryRequest_WithLabels) { FormData form; form.name = ASCIIToUTF16("the-name"); - form.origin = GURL("http://cool.com"); - form.action = form.origin.Resolve("/login"); + form.url = GURL("http://cool.com"); + form.action = form.url.Resolve("/login"); FormFieldData field; // No label on the first field. @@ -4671,8 +4675,8 @@ TEST_F(FormStructureTest, EncodeQueryRequest_WithLabels) { TEST_F(FormStructureTest, EncodeQueryRequest_WithLongLabels) { FormData form; form.name = ASCIIToUTF16("the-name"); - form.origin = GURL("http://cool.com"); - form.action = form.origin.Resolve("/login"); + form.url = GURL("http://cool.com"); + form.action = form.url.Resolve("/login"); FormFieldData field; // No label on the first field. @@ -4727,8 +4731,8 @@ TEST_F(FormStructureTest, EncodeQueryRequest_WithLongLabels) { TEST_F(FormStructureTest, EncodeQueryRequest_MissingNames) { FormData form; // No name set for the form. - form.origin = GURL("http://cool.com"); - form.action = form.origin.Resolve("/login"); + form.url = GURL("http://cool.com"); + form.action = form.url.Resolve("/login"); FormFieldData field; field.label = ASCIIToUTF16("username"); @@ -4780,8 +4784,8 @@ TEST_F(FormStructureTest, EncodeQueryRequest_DisabledMetadataTrial) { FormData form; // No name set for the form. - form.origin = GURL("http://cool.com"); - form.action = form.origin.Resolve("/login"); + form.url = GURL("http://cool.com"); + form.action = form.url.Resolve("/login"); FormFieldData field; field.label = ASCIIToUTF16("username"); @@ -4827,7 +4831,7 @@ TEST_F(FormStructureTest, EncodeQueryRequest_DisabledMetadataTrial) { TEST_F(FormStructureTest, PossibleValues) { FormData form_data; - form_data.origin = GURL("http://www.foo.com/"); + form_data.url = GURL("http://www.foo.com/"); FormFieldData field; field.autocomplete_attribute = "billing country"; @@ -4871,7 +4875,7 @@ TEST_F(FormStructureTest, PossibleValues) { TEST_F(FormStructureTest, ParseQueryResponse_UnknownType) { FormData form_data; FormFieldData field; - form_data.origin = GURL("http://foo.com"); + form_data.url = GURL("http://foo.com"); field.form_control_type = "text"; field.label = ASCIIToUTF16("First Name"); @@ -4926,7 +4930,7 @@ TEST_F(FormStructureTest, ParseQueryResponse_UnknownType) { // proto. TEST_F(FormStructureTest, ParseQueryResponse) { FormData form; - form.origin = GURL("http://foo.com"); + form.url = GURL("http://foo.com"); FormFieldData field; field.form_control_type = "text"; @@ -4998,7 +5002,7 @@ TEST_F(FormStructureTest, ParseQueryResponse) { TEST_F(FormStructureTest, ParseApiQueryResponse) { // Make form 1 data. FormData form; - form.origin = GURL("http://foo.com"); + form.url = GURL("http://foo.com"); FormFieldData field; field.form_control_type = "text"; @@ -5087,7 +5091,7 @@ TEST_F(FormStructureTest, ParseApiQueryResponse) { TEST_F(FormStructureTest, ParseApiQueryResponseWhenCannotParseProtoFromString) { // Make form 1 data. FormData form; - form.origin = GURL("http://foo.com"); + form.url = GURL("http://foo.com"); FormFieldData field; field.form_control_type = "email"; field.label = ASCIIToUTF16("emailaddress"); @@ -5115,7 +5119,7 @@ TEST_F(FormStructureTest, ParseApiQueryResponseWhenCannotParseProtoFromString) { TEST_F(FormStructureTest, ParseApiQueryResponseWhenPayloadNotBase64) { // Make form 1 data. FormData form; - form.origin = GURL("http://foo.com"); + form.url = GURL("http://foo.com"); FormFieldData field; field.form_control_type = "email"; field.label = ASCIIToUTF16("emailaddress"); @@ -5154,7 +5158,7 @@ TEST_F(FormStructureTest, ParseApiQueryResponseWhenPayloadNotBase64) { TEST_F(FormStructureTest, ParseQueryResponse_AuthorDefinedTypes) { FormData form; - form.origin = GURL("http://foo.com"); + form.url = GURL("http://foo.com"); FormFieldData field; field.label = ASCIIToUTF16("email"); @@ -5194,7 +5198,7 @@ TEST_F(FormStructureTest, ParseQueryResponse_AuthorDefinedTypes) { TEST_F(FormStructureTest, ParseQueryResponse_RationalizeLoneField) { FormData form; - form.origin = GURL("http://foo.com"); + form.url = GURL("http://foo.com"); FormFieldData field; field.form_control_type = "text"; @@ -5240,7 +5244,7 @@ TEST_F(FormStructureTest, ParseQueryResponse_RationalizeLoneField) { TEST_F(FormStructureTest, ParseQueryResponse_RationalizeCCName) { FormData form; - form.origin = GURL("http://foo.com"); + form.url = GURL("http://foo.com"); FormFieldData field; field.form_control_type = "text"; @@ -5279,7 +5283,7 @@ TEST_F(FormStructureTest, ParseQueryResponse_RationalizeCCName) { TEST_F(FormStructureTest, ParseQueryResponse_RationalizeMultiMonth_1) { FormData form; - form.origin = GURL("http://foo.com"); + form.url = GURL("http://foo.com"); FormFieldData field; field.form_control_type = "text"; @@ -5335,7 +5339,7 @@ TEST_F(FormStructureTest, ParseQueryResponse_RationalizeMultiMonth_1) { TEST_F(FormStructureTest, ParseQueryResponse_RationalizeMultiMonth_2) { FormData form; - form.origin = GURL("http://foo.com"); + form.url = GURL("http://foo.com"); FormFieldData field; field.form_control_type = "text"; @@ -5424,7 +5428,7 @@ TEST_F(FormStructureTest, FindLongestCommonPrefix) { TEST_F(FormStructureTest, RationalizePhoneNumber_RunsOncePerSection) { FormData form; - form.origin = GURL("http://foo.com"); + form.url = GURL("http://foo.com"); FormFieldData field; field.form_control_type = "text"; field.max_length = 10000; @@ -5479,7 +5483,7 @@ TEST_F(FormStructureTest, RationalizePhoneNumber_RunsOncePerSection) { // ADDRESS_HOME_STREET_ADDRESS is not modified by the address rationalization. TEST_F(FormStructureTest, RationalizeRepeatedFields_OneAddress) { FormData form; - form.origin = GURL("http://foo.com"); + form.url = GURL("http://foo.com"); FormFieldData field; field.form_control_type = "text"; field.max_length = 10000; @@ -5525,7 +5529,7 @@ TEST_F(FormStructureTest, RationalizeRepeatedFields_OneAddress) { // ADDRESS_HOME_LINE1 and ADDRESS_HOME_LINE2 instead. TEST_F(FormStructureTest, RationalizeRepreatedFields_TwoAddresses) { FormData form; - form.origin = GURL("http://foo.com"); + form.url = GURL("http://foo.com"); FormFieldData field; field.form_control_type = "text"; field.max_length = 10000; @@ -5577,7 +5581,7 @@ TEST_F(FormStructureTest, RationalizeRepreatedFields_TwoAddresses) { // ADDRESS_HOME_LINE1, ADDRESS_HOME_LINE2 and ADDRESS_HOME_LINE3 instead. TEST_F(FormStructureTest, RationalizeRepreatedFields_ThreeAddresses) { FormData form; - form.origin = GURL("http://foo.com"); + form.url = GURL("http://foo.com"); FormFieldData field; field.form_control_type = "text"; field.max_length = 10000; @@ -5637,7 +5641,7 @@ TEST_F(FormStructureTest, RationalizeRepreatedFields_ThreeAddresses) { // sections according to the heuristics. TEST_F(FormStructureTest, RationalizeRepreatedFields_FourAddresses) { FormData form; - form.origin = GURL("http://foo.com"); + form.url = GURL("http://foo.com"); FormFieldData field; field.form_control_type = "text"; field.max_length = 10000; @@ -5706,7 +5710,7 @@ TEST_F(FormStructureTest, RationalizeRepreatedFields_FourAddresses) { // ADDRESS_HOME_STREET_ADDRESS is not modified by the address rationalization. TEST_F(FormStructureTest, RationalizeRepreatedFields_OneAddressEachSection) { FormData form; - form.origin = GURL("http://foo.com"); + form.url = GURL("http://foo.com"); FormFieldData field; field.form_control_type = "text"; field.max_length = 10000; @@ -5784,7 +5788,7 @@ TEST_F( FormStructureTest, RationalizeRepreatedFields_SectionTwoAddress_SectionThreeAddress_SectionFourAddresses) { FormData form; - form.origin = GURL("http://foo.com"); + form.url = GURL("http://foo.com"); FormFieldData field; field.form_control_type = "text"; field.max_length = 10000; @@ -5937,7 +5941,7 @@ TEST_F( TEST_F(FormStructureTest, RationalizeRepreatedFields_MultipleSectionsByHeuristics_OneAddressEach) { FormData form; - form.origin = GURL("http://foo.com"); + form.url = GURL("http://foo.com"); FormFieldData field; field.form_control_type = "text"; field.max_length = 10000; @@ -6010,7 +6014,7 @@ TEST_F( FormStructureTest, RationalizeRepreatedFields_MultipleSectionsByHeuristics_TwoAddress_ThreeAddress) { FormData form; - form.origin = GURL("http://foo.com"); + form.url = GURL("http://foo.com"); FormFieldData field; field.form_control_type = "text"; field.max_length = 10000; @@ -6099,7 +6103,7 @@ TEST_F( TEST_F(FormStructureTest, RationalizeRepreatedFields_StateCountry_NoRationalization) { FormData form; - form.origin = GURL("http://foo.com"); + form.url = GURL("http://foo.com"); FormFieldData field; field.form_control_type = "text"; field.max_length = 10000; @@ -6194,7 +6198,7 @@ TEST_F(FormStructureTest, TEST_F(FormStructureTest, RationalizeRepreatedFields_CountryStateNoHeuristics) { FormData form; - form.origin = GURL("http://foo.com"); + form.url = GURL("http://foo.com"); FormFieldData field; field.form_control_type = "text"; field.max_length = 10000; @@ -6325,7 +6329,7 @@ TEST_F(FormStructureTest, RationalizeRepreatedFields_CountryStateNoHeuristics) { TEST_F(FormStructureTest, RationalizeRepreatedFields_StateCountryWithHeuristics) { FormData form; - form.origin = GURL("http://foo.com"); + form.url = GURL("http://foo.com"); FormFieldData field; field.form_control_type = "text"; field.max_length = 10000; @@ -6456,7 +6460,7 @@ TEST_F(FormStructureTest, TEST_F(FormStructureTest, RationalizeRepreatedFields_FirstFieldRationalized) { FormData form; - form.origin = GURL("http://foo.com"); + form.url = GURL("http://foo.com"); FormFieldData field; field.form_control_type = "text"; field.max_length = 10000; @@ -6517,7 +6521,7 @@ TEST_F(FormStructureTest, RationalizeRepreatedFields_FirstFieldRationalized) { TEST_F(FormStructureTest, RationalizeRepreatedFields_LastFieldRationalized) { FormData form; - form.origin = GURL("http://foo.com"); + form.url = GURL("http://foo.com"); FormFieldData field; field.form_control_type = "text"; field.max_length = 10000; @@ -6584,9 +6588,227 @@ TEST_F(FormStructureTest, RationalizeRepreatedFields_LastFieldRationalized) { EXPECT_EQ(ADDRESS_HOME_STATE, forms[0]->field(5)->Type().GetStorableType()); } +INSTANTIATE_TEST_SUITE_P(, ParameterizedFormStructureTest, testing::Bool()); + +// Tests that, when the flag is off, we will not set the predicted type to +// unknown for fields that have no server data and autocomplete off, and when +// the flag is ON, we will overwrite the predicted type. +TEST_P(ParameterizedFormStructureTest, + NoServerData_AutocompleteOff_FlagDisabled_NoOverwrite) { + base::test::ScopedFeatureList scoped_features; + + bool flag_enabled = GetParam(); + scoped_features.InitWithFeatureState(features::kAutofillOffNoServerData, + flag_enabled); + + FormData form; + form.url = GURL("http://foo.com"); + FormFieldData field; + field.form_control_type = "text"; + field.max_length = 10000; + field.should_autocomplete = false; + + // Autocomplete Off, with server data. + field.label = ASCIIToUTF16("First Name"); + field.name = ASCIIToUTF16("firstName"); + form.fields.push_back(field); + + // Autocomplete Off, without server data. + field.label = ASCIIToUTF16("Last Name"); + field.name = ASCIIToUTF16("lastName"); + form.fields.push_back(field); + + // Autocomplete On, with server data. + field.should_autocomplete = true; + field.label = ASCIIToUTF16("Address"); + field.name = ASCIIToUTF16("address"); + form.fields.push_back(field); + + // Autocomplete On, without server data. + field.label = ASCIIToUTF16("Country"); + field.name = ASCIIToUTF16("country"); + form.fields.push_back(field); + + AutofillQueryResponseContents response; + response.add_field()->set_overall_type_prediction(NAME_FIRST); + response.add_field()->set_overall_type_prediction(NO_SERVER_DATA); + response.add_field()->set_overall_type_prediction(NO_SERVER_DATA); + response.add_field()->set_overall_type_prediction(NO_SERVER_DATA); + + std::string response_string; + ASSERT_TRUE(response.SerializeToString(&response_string)); + + FormStructure form_structure(form); + + // Will identify the sections based on the heuristics types. + form_structure.DetermineHeuristicTypes(); + + std::vector<FormStructure*> forms; + forms.push_back(&form_structure); + + // Will call RationalizeFieldTypePredictions + FormStructure::ParseQueryResponse(response_string, forms, nullptr); + + ASSERT_EQ(1U, forms.size()); + ASSERT_EQ(4U, forms[0]->field_count()); + + // Only NAME_LAST should be affected by the flag. + EXPECT_EQ(flag_enabled ? UNKNOWN_TYPE : NAME_LAST, + forms[0]->field(1)->Type().GetStorableType()); + + EXPECT_EQ(NAME_FIRST, forms[0]->field(0)->Type().GetStorableType()); + EXPECT_EQ(ADDRESS_HOME_LINE1, forms[0]->field(2)->Type().GetStorableType()); + EXPECT_EQ(ADDRESS_HOME_COUNTRY, forms[0]->field(3)->Type().GetStorableType()); +} + +struct RationalizationTypeRelationshipsTestParams { + ServerFieldType server_type; + ServerFieldType required_type; +}; +class RationalizationFieldTypeFilterTest + : public FormStructureTest, + public testing::WithParamInterface<ServerFieldType> {}; +class RationalizationFieldTypeRelationshipsTest + : public FormStructureTest, + public testing::WithParamInterface< + RationalizationTypeRelationshipsTestParams> {}; + +INSTANTIATE_TEST_SUITE_P(, + RationalizationFieldTypeFilterTest, + testing::Values(PHONE_HOME_COUNTRY_CODE)); + +INSTANTIATE_TEST_SUITE_P(, + RationalizationFieldTypeRelationshipsTest, + testing::Values( + RationalizationTypeRelationshipsTestParams{ + PHONE_HOME_COUNTRY_CODE, PHONE_HOME_NUMBER}, + RationalizationTypeRelationshipsTestParams{ + PHONE_HOME_COUNTRY_CODE, + PHONE_HOME_CITY_AND_NUMBER})); + +// Tests that the rationalization logic will filter out fields of type |param| +// when there is no other required type. +TEST_P(RationalizationFieldTypeFilterTest, Rationalization_Rules_Filter_Out) { + ServerFieldType filtered_off_field = GetParam(); + + FormData form; + form.url = GURL("http://foo.com"); + FormFieldData field; + field.form_control_type = "text"; + field.max_length = 10000; + field.should_autocomplete = true; + + // Just adding >=3 random fields to trigger rationalization. + field.label = ASCIIToUTF16("First Name"); + field.name = ASCIIToUTF16("firstName"); + form.fields.push_back(field); + field.label = ASCIIToUTF16("Last Name"); + field.name = ASCIIToUTF16("lastName"); + form.fields.push_back(field); + field.label = ASCIIToUTF16("Address"); + field.name = ASCIIToUTF16("address"); + form.fields.push_back(field); + + field.label = ASCIIToUTF16("Something under test"); + field.name = ASCIIToUTF16("tested-thing"); + form.fields.push_back(field); + + AutofillQueryResponseContents response; + response.add_field()->set_overall_type_prediction(NAME_FIRST); + response.add_field()->set_overall_type_prediction(NAME_LAST); + response.add_field()->set_overall_type_prediction(ADDRESS_HOME_LINE1); + response.add_field()->set_overall_type_prediction(filtered_off_field); + + std::string response_string; + ASSERT_TRUE(response.SerializeToString(&response_string)); + + FormStructure form_structure(form); + + // Will identify the sections based on the heuristics types. + form_structure.DetermineHeuristicTypes(); + + std::vector<FormStructure*> forms; + forms.push_back(&form_structure); + + // Will call RationalizeFieldTypePredictions + FormStructure::ParseQueryResponse(response_string, forms, nullptr); + + ASSERT_EQ(1U, forms.size()); + ASSERT_EQ(4U, forms[0]->field_count()); + + EXPECT_EQ(NAME_FIRST, forms[0]->field(0)->Type().GetStorableType()); + EXPECT_EQ(NAME_LAST, forms[0]->field(1)->Type().GetStorableType()); + EXPECT_EQ(ADDRESS_HOME_LINE1, forms[0]->field(2)->Type().GetStorableType()); + + // Last field's type should have been overwritten to expected. + EXPECT_EQ(UNKNOWN_TYPE, forms[0]->field(3)->Type().GetStorableType()); +} + +// Tests that the rationalization logic will not filter out fields of type +// |param| when there is another field with a required type. +TEST_P(RationalizationFieldTypeRelationshipsTest, + Rationalization_Rules_Relationships) { + RationalizationTypeRelationshipsTestParams test_params = GetParam(); + + FormData form; + form.url = GURL("http://foo.com"); + FormFieldData field; + field.form_control_type = "text"; + field.max_length = 10000; + field.should_autocomplete = true; + + // Just adding >=3 random fields to trigger rationalization. + field.label = ASCIIToUTF16("First Name"); + field.name = ASCIIToUTF16("firstName"); + form.fields.push_back(field); + field.label = ASCIIToUTF16("Last Name"); + field.name = ASCIIToUTF16("lastName"); + form.fields.push_back(field); + + field.label = ASCIIToUTF16("Some field with required type"); + field.name = ASCIIToUTF16("some-name"); + form.fields.push_back(field); + + field.label = ASCIIToUTF16("Something under test"); + field.name = ASCIIToUTF16("tested-thing"); + form.fields.push_back(field); + + AutofillQueryResponseContents response; + response.add_field()->set_overall_type_prediction(NAME_FIRST); + response.add_field()->set_overall_type_prediction(NAME_LAST); + response.add_field()->set_overall_type_prediction(test_params.required_type); + response.add_field()->set_overall_type_prediction(test_params.server_type); + + std::string response_string; + ASSERT_TRUE(response.SerializeToString(&response_string)); + + FormStructure form_structure(form); + + // Will identify the sections based on the heuristics types. + form_structure.DetermineHeuristicTypes(); + + std::vector<FormStructure*> forms; + forms.push_back(&form_structure); + + // Will call RationalizeFieldTypePredictions + FormStructure::ParseQueryResponse(response_string, forms, nullptr); + + ASSERT_EQ(1U, forms.size()); + ASSERT_EQ(4U, forms[0]->field_count()); + + EXPECT_EQ(NAME_FIRST, forms[0]->field(0)->Type().GetStorableType()); + EXPECT_EQ(NAME_LAST, forms[0]->field(1)->Type().GetStorableType()); + EXPECT_EQ(test_params.required_type, + forms[0]->field(2)->Type().GetStorableType()); + + // Last field's type should have been overwritten to expected. + EXPECT_EQ(test_params.server_type, + forms[0]->field(3)->Type().GetStorableType()); +} + TEST_F(FormStructureTest, AllowBigForms) { FormData form; - form.origin = GURL("http://foo.com"); + form.url = GURL("http://foo.com"); FormFieldData field; // Check that the form with 250 fields are processed correctly. for (size_t i = 0; i < 250; ++i) { diff --git a/chromium/components/autofill/core/browser/label_formatter.cc b/chromium/components/autofill/core/browser/label_formatter.cc index 32426dd7790..5fa3b42d195 100644 --- a/chromium/components/autofill/core/browser/label_formatter.cc +++ b/chromium/components/autofill/core/browser/label_formatter.cc @@ -4,14 +4,107 @@ #include "components/autofill/core/browser/label_formatter.h" +#include <algorithm> +#include <iterator> +#include <set> + +#include "components/autofill/core/browser/address_contact_form_label_formatter.h" +#include "components/autofill/core/browser/address_email_form_label_formatter.h" +#include "components/autofill/core/browser/address_form_label_formatter.h" +#include "components/autofill/core/browser/address_phone_form_label_formatter.h" +#include "components/autofill/core/browser/autofill_data_util.h" +#include "components/autofill/core/browser/autofill_metrics.h" +#include "components/autofill/core/browser/contact_form_label_formatter.h" +#include "components/autofill/core/browser/label_formatter_utils.h" + namespace autofill { +using data_util::bit_field_type_groups::kAddress; +using data_util::bit_field_type_groups::kEmail; +using data_util::bit_field_type_groups::kName; +using data_util::bit_field_type_groups::kPhone; + LabelFormatter::LabelFormatter(const std::string& app_locale, ServerFieldType focused_field_type, + uint32_t groups, const std::vector<ServerFieldType>& field_types) : app_locale_(app_locale), focused_field_type_(focused_field_type), - field_types_(field_types) {} + groups_(groups) { + const FieldTypeGroup focused_group = GetFocusedNonBillingGroup(); + std::set<FieldTypeGroup> groups_for_labels{NAME, ADDRESS_HOME, EMAIL, + PHONE_HOME}; + + // If a user is focused on an address field, then parts of the address may be + // shown in the label. For example, if the user is focusing on a street + // address field, then it may be helpful to show the city in the label. + // Otherwise, the focused field should not appear in the label. + if (focused_group != ADDRESS_HOME) { + groups_for_labels.erase(focused_group); + } + + // Countries are excluded to prevent them from appearing in labels with + // national addresses. + auto can_be_shown_in_label = + [&groups_for_labels](ServerFieldType type) -> bool { + return groups_for_labels.find( + AutofillType(AutofillType(type).GetStorableType()).group()) != + groups_for_labels.end() && + type != ADDRESS_HOME_COUNTRY && type != ADDRESS_BILLING_COUNTRY; + }; + + std::copy_if(field_types.begin(), field_types.end(), + std::back_inserter(field_types_for_labels_), + can_be_shown_in_label); +} + LabelFormatter::~LabelFormatter() = default; +std::vector<base::string16> LabelFormatter::GetLabels( + const std::vector<AutofillProfile*>& profiles) const { + std::vector<base::string16> labels; + for (const AutofillProfile* profile : profiles) { + labels.push_back(GetLabelForProfile(*profile, GetFocusedNonBillingGroup())); + } + return labels; +} + +FieldTypeGroup LabelFormatter::GetFocusedNonBillingGroup() const { + return AutofillType(AutofillType(focused_field_type_).GetStorableType()) + .group(); +} + +// static +std::unique_ptr<LabelFormatter> LabelFormatter::Create( + const std::string& app_locale, + ServerFieldType focused_field_type, + const std::vector<ServerFieldType>& field_types, + const std::vector<AutofillProfile*>& profiles) { + const uint32_t groups = data_util::DetermineGroups(field_types); + + switch (groups) { + case kName | kAddress | kEmail | kPhone: + return std::make_unique<AddressContactFormLabelFormatter>( + app_locale, focused_field_type, groups, field_types, + !HaveSamePhoneNumbers(profiles, app_locale), + !HaveSameEmailAddresses(profiles, app_locale)); + case kName | kAddress | kPhone: + return std::make_unique<AddressPhoneFormLabelFormatter>( + app_locale, focused_field_type, groups, field_types); + case kName | kAddress | kEmail: + return std::make_unique<AddressEmailFormLabelFormatter>( + app_locale, focused_field_type, groups, field_types); + case kName | kAddress: + return std::make_unique<AddressFormLabelFormatter>( + app_locale, focused_field_type, groups, field_types); + case kName | kEmail | kPhone: + case kName | kEmail: + case kName | kPhone: + return std::make_unique<ContactFormLabelFormatter>( + app_locale, focused_field_type, groups, field_types); + default: + return nullptr; + } +} + } // namespace autofill diff --git a/chromium/components/autofill/core/browser/label_formatter.h b/chromium/components/autofill/core/browser/label_formatter.h index d436401044d..48172fcbff1 100644 --- a/chromium/components/autofill/core/browser/label_formatter.h +++ b/chromium/components/autofill/core/browser/label_formatter.h @@ -5,6 +5,7 @@ #ifndef COMPONENTS_AUTOFILL_CORE_BROWSER_LABEL_FORMATTER_H_ #define COMPONENTS_AUTOFILL_CORE_BROWSER_LABEL_FORMATTER_H_ +#include <memory> #include <string> #include <vector> @@ -19,33 +20,67 @@ class LabelFormatter { public: LabelFormatter(const std::string& app_locale, ServerFieldType focused_field_type, + uint32_t groups, const std::vector<ServerFieldType>& field_types); virtual ~LabelFormatter(); - // Returns a collection of |labels| formed by extracting useful disambiguating - // information from a collection of |profiles|. - virtual std::vector<base::string16> GetLabels( - const std::vector<AutofillProfile*>& profiles) const = 0; + // Returns the bitmask indicating which FieldTypeGroups are represented in + // this formatter's associated form. + uint32_t groups() const { return groups_; } + + // Returns a collection of labels formed by extracting useful disambiguating + // information from a collection of |profiles_|. + std::vector<base::string16> GetLabels( + const std::vector<AutofillProfile*>& profiles) const; + + // Creates a form-specific LabelFormatter according to |field_types|. This + // formatter has the ability to build labels with disambiguating information + // from the given |profiles|. + static std::unique_ptr<LabelFormatter> Create( + const std::string& app_locale, + ServerFieldType focused_field_type, + const std::vector<ServerFieldType>& field_types, + const std::vector<AutofillProfile*>& profiles); protected: + // Returns a label to show the user. The elements of the label and their + // ordering depend on the kind of LabelFormatter, the data in |profile|, + // |focused_group|, and |focused_field_type_|. + virtual base::string16 GetLabelForProfile( + const AutofillProfile& profile, + FieldTypeGroup focused_group) const = 0; + + // Returns the FieldTypeGroup with which |focused_field_type_| is associated. + // Billing field types are mapped to their corresponding home address field + // types. For example, if focused_field_type_ is ADDRESS_BILLING_ZIP, then + // the resulting FieldTypeGroup is ADDRESS_HOME instead of ADDRESS_BILLING. + FieldTypeGroup GetFocusedNonBillingGroup() const; + const std::string& app_locale() const { return app_locale_; } + ServerFieldType focused_field_type() const { return focused_field_type_; } - const std::vector<ServerFieldType>& field_types() const { - return field_types_; + + const std::vector<ServerFieldType>& field_types_for_labels() const { + return field_types_for_labels_; } private: // The locale for which to generate labels. This reflects the language and - // country for which the application is translated, e.g. en_AU for Austalian + // country for which the application is translated, e.g. en-AU for Australian // English. std::string app_locale_; - // The field on which the user is currently focused. + // The type of field on which the user is focused, e.g. NAME_FIRST. ServerFieldType focused_field_type_; - // A collection of meaningful field types in the form with which the user is - // interacting. - std::vector<ServerFieldType> field_types_; + // The bitmask indicating which FieldTypeGroups are represented in this + // formatter's associated form. + uint32_t groups_; + + // The collection of field types that can be used to make labels. It includes + // only types related to names, addresses, email addresses, and phone + // numbers. It excludes types related to countries. + std::vector<ServerFieldType> field_types_for_labels_; }; } // namespace autofill diff --git a/chromium/components/autofill/core/browser/label_formatter_unittest.cc b/chromium/components/autofill/core/browser/label_formatter_unittest.cc new file mode 100644 index 00000000000..fc66da066d7 --- /dev/null +++ b/chromium/components/autofill/core/browser/label_formatter_unittest.cc @@ -0,0 +1,24 @@ +// Copyright 2019 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "components/autofill/core/browser/label_formatter.h" + +#include <vector> + +#include "components/autofill/core/browser/autofill_profile.h" +#include "components/autofill/core/browser/field_types.h" +#include "testing/gtest/include/gtest/gtest.h" + +namespace autofill { +namespace { + +TEST(LabelFormatterTest, CreateWithMissingFieldTypes) { + EXPECT_EQ(LabelFormatter::Create("en-US", NAME_FIRST, + std::vector<ServerFieldType>(), + std::vector<AutofillProfile*>()), + nullptr); +} + +} // namespace +} // namespace autofill
\ No newline at end of file diff --git a/chromium/components/autofill/core/browser/label_formatter_utils.cc b/chromium/components/autofill/core/browser/label_formatter_utils.cc index 53d8eab8836..42bd1a109e6 100644 --- a/chromium/components/autofill/core/browser/label_formatter_utils.cc +++ b/chromium/components/autofill/core/browser/label_formatter_utils.cc @@ -4,112 +4,236 @@ #include "components/autofill/core/browser/label_formatter_utils.h" +#include <algorithm> +#include <iterator> #include <memory> -#include <set> +#include "base/strings/string_util.h" #include "base/strings/utf_string_conversions.h" -#include "components/autofill/core/browser/address_form_label_formatter.h" +#include "components/autofill/core/browser/address_i18n.h" #include "components/autofill/core/browser/autofill_data_util.h" -#include "components/autofill/core/browser/contact_form_label_formatter.h" +#include "components/autofill/core/browser/phone_number_i18n.h" #include "components/autofill/core/browser/validation.h" +#include "components/grit/components_scaled_resources.h" +#include "components/strings/grit/components_strings.h" +#include "third_party/libaddressinput/src/cpp/include/libaddressinput/address_data.h" +#include "third_party/libaddressinput/src/cpp/include/libaddressinput/address_formatter.h" +#include "ui/base/l10n/l10n_util.h" namespace autofill { -namespace { -bool ContainsName(uint32_t groups) { - return groups & label_formatter_groups::kName; +const int kStreetAddressFieldTypes[] = { + ADDRESS_HOME_LINE1, ADDRESS_HOME_LINE2, + ADDRESS_HOME_APT_NUM, ADDRESS_BILLING_LINE1, + ADDRESS_BILLING_LINE2, ADDRESS_BILLING_APT_NUM, + ADDRESS_HOME_STREET_ADDRESS, ADDRESS_BILLING_STREET_ADDRESS, + ADDRESS_HOME_LINE3, ADDRESS_BILLING_LINE3}; + +bool IsStreetAddressPart(ServerFieldType type) { + return std::find(std::begin(kStreetAddressFieldTypes), + std::end(kStreetAddressFieldTypes), + type) != std::end(kStreetAddressFieldTypes); } -bool ContainsAddress(uint32_t groups) { - return groups & label_formatter_groups::kAddress; +bool HasStreetAddress(const std::vector<ServerFieldType>& types) { + return std::any_of(types.begin(), types.end(), IsStreetAddressPart); } -bool ContainsEmail(uint32_t groups) { - return groups & label_formatter_groups::kEmail; +std::vector<ServerFieldType> ExtractSpecifiedAddressFieldTypes( + bool extract_street_address_types, + const std::vector<ServerFieldType>& types) { + auto should_be_extracted = + [&extract_street_address_types](ServerFieldType type) -> bool { + return AutofillType(AutofillType(type).GetStorableType()).group() == + ADDRESS_HOME && + (extract_street_address_types ? IsStreetAddressPart(type) + : !IsStreetAddressPart(type)); + }; + + std::vector<ServerFieldType> extracted_address_types; + std::copy_if(types.begin(), types.end(), + std::back_inserter(extracted_address_types), + should_be_extracted); + + return extracted_address_types; } -bool ContainsPhone(uint32_t groups) { - return groups & label_formatter_groups::kPhone; +std::vector<ServerFieldType> ExtractAddressFieldTypes( + const std::vector<ServerFieldType>& types) { + std::vector<ServerFieldType> only_address_types; + + // Note that GetStorableType maps billing fields to their corresponding non- + // billing fields, e.g. ADDRESS_HOME_ZIP is mapped to ADDRESS_BILLING_ZIP. + std::copy_if( + types.begin(), types.end(), std::back_inserter(only_address_types), + [](ServerFieldType type) { + return AutofillType(AutofillType(type).GetStorableType()).group() == + ADDRESS_HOME; + }); + return only_address_types; } -std::set<FieldTypeGroup> GetFieldTypeGroups(uint32_t groups) { - std::set<FieldTypeGroup> field_type_groups; - if (ContainsName(groups)) { - field_type_groups.insert(NAME); - } - if (ContainsAddress(groups)) { - field_type_groups.insert(ADDRESS_HOME); - } - if (ContainsEmail(groups)) { - field_type_groups.insert(EMAIL); +void AddLabelPartIfNotEmpty(const base::string16& part, + std::vector<base::string16>* parts) { + if (!part.empty()) { + parts->push_back(part); } - if (ContainsPhone(groups)) { - field_type_groups.insert(PHONE_HOME); - } - return field_type_groups; } -} // namespace +base::string16 ConstructLabelLine(const std::vector<base::string16>& parts) { + return base::JoinString(parts, l10n_util::GetStringUTF16( + IDS_AUTOFILL_SUGGESTION_LABEL_SEPARATOR)); +} -std::vector<ServerFieldType> FilterFieldTypes( - const std::vector<ServerFieldType>& field_types) { - std::vector<ServerFieldType> filtered_field_types; - for (const ServerFieldType& field_type : field_types) { - const FieldTypeGroup group = - AutofillType(AutofillType(field_type).GetStorableType()).group(); - if (group == NAME || group == ADDRESS_HOME || group == EMAIL || - group == PHONE_HOME) { - filtered_field_types.push_back(field_type); - } - } - return filtered_field_types; -} - -uint32_t DetermineGroups(const std::vector<ServerFieldType>& field_types) { - uint32_t group_bitmask = 0; - for (const ServerFieldType& type : field_types) { - const FieldTypeGroup group = - AutofillType(AutofillType(type).GetStorableType()).group(); - switch (group) { - case autofill::NAME: - group_bitmask |= label_formatter_groups::kName; - break; - case autofill::ADDRESS_HOME: - group_bitmask |= label_formatter_groups::kAddress; - break; - case autofill::EMAIL: - group_bitmask |= label_formatter_groups::kEmail; - break; - case autofill::PHONE_HOME: - group_bitmask |= label_formatter_groups::kPhone; - break; - default: - break; - } +AutofillProfile MakeTrimmedProfile(const AutofillProfile& profile, + const std::string& app_locale, + const std::vector<ServerFieldType>& types) { + AutofillProfile trimmed_profile(profile.guid(), profile.origin()); + trimmed_profile.set_language_code(profile.language_code()); + + const AutofillType country_code_type(HTML_TYPE_COUNTRY_CODE, HTML_MODE_NONE); + const base::string16 country_code = + profile.GetInfo(country_code_type, app_locale); + trimmed_profile.SetInfo(country_code_type, country_code, app_locale); + + for (const ServerFieldType& type : types) { + trimmed_profile.SetInfo(type, profile.GetInfo(type, app_locale), + app_locale); } - return group_bitmask; + return trimmed_profile; } -std::unique_ptr<LabelFormatter> Create( - const std::string& app_locale, +base::string16 GetLabelName(const AutofillProfile& profile, + const std::string& app_locale) { + return profile.GetInfo(AutofillType(NAME_FULL), app_locale); +} + +base::string16 GetLabelForFocusedAddress( ServerFieldType focused_field_type, - const std::vector<ServerFieldType>& field_types) { - const uint32_t groups = DetermineGroups(field_types); + bool form_has_street_address, + const AutofillProfile& profile, + const std::string& app_locale, + const std::vector<ServerFieldType>& types) { + return GetLabelAddress( + form_has_street_address && !IsStreetAddressPart(focused_field_type), + profile, app_locale, types); +} - if (!ContainsName(groups)) { - return nullptr; - } - if (ContainsAddress(groups) && !ContainsEmail(groups) && - !ContainsPhone(groups)) { - return std::make_unique<AddressFormLabelFormatter>( - app_locale, focused_field_type, FilterFieldTypes(field_types)); +base::string16 GetLabelAddress(bool use_street_address, + const AutofillProfile& profile, + const std::string& app_locale, + const std::vector<ServerFieldType>& types) { + return use_street_address + ? GetLabelStreetAddress( + profile, app_locale, + ExtractSpecifiedAddressFieldTypes(use_street_address, types)) + : GetLabelNationalAddress(profile, app_locale, + ExtractSpecifiedAddressFieldTypes( + use_street_address, types)); +} + +base::string16 GetLabelNationalAddress( + const AutofillProfile& profile, + const std::string& app_locale, + const std::vector<ServerFieldType>& types) { + std::unique_ptr<::i18n::addressinput::AddressData> address_data = + i18n::CreateAddressDataFromAutofillProfile( + MakeTrimmedProfile(profile, app_locale, types), app_locale); + + std::string address_line; + ::i18n::addressinput::GetFormattedNationalAddressLine(*address_data, + &address_line); + return base::UTF8ToUTF16(address_line); +} + +base::string16 GetLabelStreetAddress( + const AutofillProfile& profile, + const std::string& app_locale, + const std::vector<ServerFieldType>& types) { + std::unique_ptr<::i18n::addressinput::AddressData> address_data = + i18n::CreateAddressDataFromAutofillProfile( + MakeTrimmedProfile(profile, app_locale, types), app_locale); + + std::string address_line; + ::i18n::addressinput::GetStreetAddressLinesAsSingleLine(*address_data, + &address_line); + return base::UTF8ToUTF16(address_line); +} + +base::string16 GetLabelForProfileOnFocusedNonStreetAddress( + bool form_has_street_address, + const AutofillProfile& profile, + const std::string& app_locale, + const std::vector<ServerFieldType>& types, + const base::string16& contact_info) { + std::vector<base::string16> label_parts; + AddLabelPartIfNotEmpty( + GetLabelAddress(form_has_street_address, profile, app_locale, types), + &label_parts); + AddLabelPartIfNotEmpty(contact_info, &label_parts); + return ConstructLabelLine(label_parts); +} + +base::string16 GetLabelEmail(const AutofillProfile& profile, + const std::string& app_locale) { + const base::string16 email = + profile.GetInfo(AutofillType(EMAIL_ADDRESS), app_locale); + return IsValidEmailAddress(email) ? email : base::string16(); +} + +base::string16 GetLabelPhone(const AutofillProfile& profile, + const std::string& app_locale) { + const std::string unformatted_phone = base::UTF16ToUTF8( + profile.GetInfo(AutofillType(PHONE_HOME_WHOLE_NUMBER), app_locale)); + return unformatted_phone.empty() + ? base::string16() + : base::UTF8ToUTF16(i18n::FormatPhoneNationallyForDisplay( + unformatted_phone, + data_util::GetCountryCodeWithFallback(profile, app_locale))); +} + +bool HaveSameEmailAddresses(const std::vector<AutofillProfile*>& profiles, + const std::string& app_locale) { + bool first_email_found = false; + base::string16 first_email; + + for (const AutofillProfile* profile : profiles) { + base::string16 email_from_profile = GetLabelEmail(*profile, app_locale); + + if (!first_email_found) { + // Store the first email address whether it's empty or not because we + // consider "" and "hao.le@aol.com" to be different email addresses. + first_email_found = true; + first_email = email_from_profile; + } else if (email_from_profile != first_email) { + return false; + } } - if (ContainsEmail(groups) || ContainsPhone(groups)) { - return std::make_unique<ContactFormLabelFormatter>( - app_locale, focused_field_type, FilterFieldTypes(field_types), - GetFieldTypeGroups(groups)); + return true; +} + +bool HaveSamePhoneNumbers(const std::vector<AutofillProfile*>& profiles, + const std::string& app_locale) { + bool first_phone_found = false; + base::string16 first_phone; + + for (const AutofillProfile* profile : profiles) { + base::string16 phone_from_profile = GetLabelPhone(*profile, app_locale); + + if (!first_phone_found) { + // Store the first phone number whether it's empty or not because we + // consider "" and "(514) 873-1100" to be different phone numbers. + first_phone_found = true; + first_phone = phone_from_profile; + } else if (!(first_phone.empty() && phone_from_profile.empty()) && + !i18n::PhoneNumbersMatch(first_phone, phone_from_profile, + base::UTF16ToASCII(profile->GetInfo( + ADDRESS_HOME_COUNTRY, app_locale)), + app_locale)) { + return false; + } } - return nullptr; + return true; } } // namespace autofill diff --git a/chromium/components/autofill/core/browser/label_formatter_utils.h b/chromium/components/autofill/core/browser/label_formatter_utils.h index 80b21942c39..c12d58958d7 100644 --- a/chromium/components/autofill/core/browser/label_formatter_utils.h +++ b/chromium/components/autofill/core/browser/label_formatter_utils.h @@ -5,53 +5,146 @@ #ifndef COMPONENTS_AUTOFILL_CORE_BROWSER_LABEL_FORMATTER_UTILS_H_ #define COMPONENTS_AUTOFILL_CORE_BROWSER_LABEL_FORMATTER_UTILS_H_ -#include <memory> -#include <set> #include <string> #include <vector> +#include "base/strings/string16.h" +#include "components/autofill/core/browser/autofill_profile.h" #include "components/autofill/core/browser/field_types.h" -#include "components/autofill/core/browser/label_formatter.h" namespace autofill { -namespace label_formatter_groups { - -// Bits for FieldTypeGroup options. -// The form contains at least one field associated with the NAME_HOME or -// NAME_BILLING FieldTypeGroups. -constexpr uint32_t kName = 1 << 0; -// The form contains at least one field associated with the ADDRESS_HOME or -// ADDRESS_BILLING FieldTypeGroups. -constexpr uint32_t kAddress = 1 << 1; -// The form contains at least one field associated with the EMAIL -// FieldTypeGroup. -constexpr uint32_t kEmail = 1 << 2; -// The form contains at least one field associated with the PHONE_HOME or -// PHONE_BILLING FieldTypeGroup. -constexpr uint32_t kPhone = 1 << 3; - -} // namespace label_formatter_groups - -// Returns a subset of meaningful ServerFieldTypes found in |field_types|. -// ServerFieldTypes like NO_SERVER_DATA and UNKNOWN_TYPE are frequently found in -// the collection of types sent from the frontend. Other types, e.g. -// COMPANY_NAME and PHONE_FAX_WHOLE_NUMBER, are also sometimes present. These -// types are not useful to LabelFormatters, so only types related to names, -// addresses, emails, and phone numbers are in the results. -std::vector<ServerFieldType> FilterFieldTypes( - const std::vector<ServerFieldType>& field_types); + +// Returns true if kName is set in |groups|. +bool ContainsName(uint32_t groups); + +// Returns true if kAddress is set in |groups|. +bool ContainsAddress(uint32_t groups); + +// Returns true if kEmail is set in |groups|. +bool ContainsEmail(uint32_t groups); + +// Returns true if kPhone is set in |groups|. +bool ContainsPhone(uint32_t groups); // Returns a bitmask indicating whether the NAME, ADDRESS_HOME, EMAIL, and // PHONE_HOME FieldTypeGroups are associated with the given |field_types|. -uint32_t DetermineGroups(const std::vector<ServerFieldType>& field_types); +uint32_t DetermineGroups(const std::vector<ServerFieldType>& types); -// Creates a form-specific LabelFormatter according to |field_types|. If the -// given |field_types| do not correspond to a LabelFormatter, then nullptr will -// be returned. -std::unique_ptr<LabelFormatter> Create( - const std::string& app_locale, +// Returns true if |type| is a component of a street address. +bool IsStreetAddressPart(ServerFieldType type); + +// Returns true if |types| has a street-address-related field. +bool HasStreetAddress(const std::vector<ServerFieldType>& types); + +// Returns a vector of only street-address-related field types in |types| if +// |extract_street_address_types| is true, e.g. ADDRESS_HOME_LINE1. +// +// Returns a vector of only non-street-address-related field types in |types| +// if |extract_street_address_types| is false, e.g. ADDRESS_BILLING_ZIP. +std::vector<ServerFieldType> ExtractSpecifiedAddressFieldTypes( + bool extract_street_address_types, + const std::vector<ServerFieldType>& types); + +// Returns a collection of the types in |types| that belong to the +// ADDRESS_HOME or ADDRESS_BILLING FieldTypeGroups. +std::vector<ServerFieldType> ExtractAddressFieldTypes( + const std::vector<ServerFieldType>& types); + +// Adds |part| to |parts| if |part| is not an empty string. +void AddLabelPartIfNotEmpty(const base::string16& part, + std::vector<base::string16>* parts); + +// Returns the text to show to the user. If there is more than one element in +// |parts|, then a separator, |IDS_AUTOFILL_SUGGESTION_LABEL_SEPARATOR|, is +// inserted between them. +base::string16 ConstructLabelLine(const std::vector<base::string16>& parts); + +// Returns a pared down copy of |profile|. The copy has the same guid, origin, +// country and language codes, and |field_types| as |profile|. +AutofillProfile MakeTrimmedProfile(const AutofillProfile& profile, + const std::string& app_locale, + const std::vector<ServerFieldType>& types); + +// Returns the full name associated with |profile|. +base::string16 GetLabelName(const AutofillProfile& profile, + const std::string& app_locale); + +// Returns either street-address data or non-street-address data found in +// |profile|. If |focused_field_type| is a street address field, then returns +// non-street-address data, e.g. Lowell, MA 01852. +// +// If the focused type is not a street address field and if +// |form_has_street_address| is true, then returns street-address data, e.g. 375 +// Merrimack St. +// +// If the focused type is not a street address field and if the form does not +// have a street address, then returns the parts of the address in the form +// other than the focused field. For example, if a user focuses on a city +// field and if the state and zip code can be in the label, then MA 01852 is +// returned. If there are no other non-street-address fields or if the data is +// not present in |profile|, then an empty string is returned. +base::string16 GetLabelForFocusedAddress( ServerFieldType focused_field_type, - const std::vector<ServerFieldType>& field_types); + bool form_has_street_address, + const AutofillProfile& profile, + const std::string& app_locale, + const std::vector<ServerFieldType>& types); + +// If |form_has_street_address_| is true and if |profile| is associated with a +// street address, then returns the street address, e.g. 24 Beacon St. +// +// If |form_has_street_address_| is false and |profile| is associated with +// address fields other than street addresses, then returns the non-street- +// address-related data corresponding to |types|. +base::string16 GetLabelAddress(bool use_street_address, + const AutofillProfile& profile, + const std::string& app_locale, + const std::vector<ServerFieldType>& types); + +// Returns the national address associated with |profile|, e.g. +// 24 Beacon St., Boston, MA 02133. +base::string16 GetLabelNationalAddress( + const AutofillProfile& profile, + const std::string& app_locale, + const std::vector<ServerFieldType>& types); + +// Returns the street address associated with |profile|, e.g. 24 Beacon St. +base::string16 GetLabelStreetAddress(const AutofillProfile& profile, + const std::string& app_locale, + const std::vector<ServerFieldType>& types); + +// Returns a label to show the user when |focused_field_type_| is not part of +// a street address. For example, city and postal code are non-street-address +// field types. +base::string16 GetLabelForProfileOnFocusedNonStreetAddress( + bool form_has_street_address, + const AutofillProfile& profile, + const std::string& app_locale, + const std::vector<ServerFieldType>& types, + const base::string16& contact_info); + +// Returns the email address associated with |profile|, if any; otherwise, +// returns an empty string. +base::string16 GetLabelEmail(const AutofillProfile& profile, + const std::string& app_locale); + +// Returns the phone number associated with |profile|, if any; otherwise, +// returns an empty string. Phone numbers are given in |profile|'s country's +// national format, if possible. +base::string16 GetLabelPhone(const AutofillProfile& profile, + const std::string& app_locale); + +// Returns true if all |profiles| have the same email address. Note that the +// absence of an email address and an actual email address, e.g. +// joe.bray@aol.com, are considered different email addresses. +bool HaveSameEmailAddresses(const std::vector<AutofillProfile*>& profiles, + const std::string& app_locale); + +// Returns true if all |profiles| have the same phone number after +// normalization. Note that the absence of a phone number and an actual phone +// number, e.g. (401) 847-8720, are considered different phone numbers. +bool HaveSamePhoneNumbers(const std::vector<AutofillProfile*>& profiles, + const std::string& app_locale); } // namespace autofill diff --git a/chromium/components/autofill/core/browser/label_formatter_utils_unittest.cc b/chromium/components/autofill/core/browser/label_formatter_utils_unittest.cc index 660cb0263d3..237ec3c5f36 100644 --- a/chromium/components/autofill/core/browser/label_formatter_utils_unittest.cc +++ b/chromium/components/autofill/core/browser/label_formatter_utils_unittest.cc @@ -4,43 +4,25 @@ #include "components/autofill/core/browser/label_formatter_utils.h" +#include "base/guid.h" +#include "base/strings/string16.h" +#include "base/strings/string_util.h" +#include "base/strings/utf_string_conversions.h" +#include "components/autofill/core/browser/autofill_data_util.h" +#include "components/autofill/core/browser/autofill_profile.h" +#include "components/autofill/core/browser/autofill_test_utils.h" +#include "components/grit/components_scaled_resources.h" +#include "components/strings/grit/components_strings.h" #include "testing/gtest/include/gtest/gtest.h" +#include "ui/base/l10n/l10n_util.h" namespace autofill { - namespace { -using label_formatter_groups::kAddress; -using label_formatter_groups::kEmail; -using label_formatter_groups::kName; -using label_formatter_groups::kPhone; - -} // namespace - -TEST(LabelFormatterUtilsTest, FilterFieldTypesNoFiltering) { - const std::vector<ServerFieldType> field_types{ - NAME_LAST, NAME_BILLING_LAST, ADDRESS_HOME_ZIP, - ADDRESS_BILLING_ZIP, EMAIL_ADDRESS, PHONE_HOME_NUMBER, - PHONE_BILLING_NUMBER}; - const std::vector<ServerFieldType> filtered_field_types = - FilterFieldTypes(field_types); - EXPECT_EQ(field_types, filtered_field_types); -} -TEST(LabelFormatterUtilsTest, FilterFieldTypesFilterCompany) { - const std::vector<ServerFieldType> field_types{NAME_LAST, COMPANY_NAME}; - const std::vector<ServerFieldType> expected_filtered_field_types{NAME_LAST}; - const std::vector<ServerFieldType> filtered_field_types = - FilterFieldTypes(field_types); - EXPECT_EQ(expected_filtered_field_types, filtered_field_types); -} - -TEST(LabelFormatterUtilsTest, FilterFieldTypesForNoGivenFieldTypes) { - const std::vector<ServerFieldType> field_types = - std::vector<ServerFieldType>(); - const std::vector<ServerFieldType> filtered_field_types = - FilterFieldTypes(field_types); - EXPECT_EQ(field_types, filtered_field_types); -} +using data_util::bit_field_type_groups::kAddress; +using data_util::bit_field_type_groups::kEmail; +using data_util::bit_field_type_groups::kName; +using data_util::bit_field_type_groups::kPhone; TEST(LabelFormatterUtilsTest, DetermineGroupsForHomeNameAndAddress) { const std::vector<ServerFieldType> field_types{ @@ -48,7 +30,7 @@ TEST(LabelFormatterUtilsTest, DetermineGroupsForHomeNameAndAddress) { ADDRESS_HOME_CITY, ADDRESS_HOME_STATE, ADDRESS_HOME_ZIP}; const uint32_t expected_group_bitmask = kName | kAddress; - const uint32_t group_bitmask = DetermineGroups(field_types); + const uint32_t group_bitmask = data_util::DetermineGroups(field_types); EXPECT_EQ(expected_group_bitmask, group_bitmask); } @@ -58,7 +40,7 @@ TEST(LabelFormatterUtilsTest, DetermineGroupsForBillingNameAndAddress) { ADDRESS_BILLING_STATE, ADDRESS_BILLING_ZIP}; const uint32_t expected_group_bitmask = kName | kAddress; - const uint32_t group_bitmask = DetermineGroups(field_types); + const uint32_t group_bitmask = data_util::DetermineGroups(field_types); EXPECT_EQ(expected_group_bitmask, group_bitmask); } @@ -67,7 +49,7 @@ TEST(LabelFormatterUtilsTest, DetermineGroupsForHomeNamePhoneAndEmail) { NAME_FULL, PHONE_HOME_CITY_AND_NUMBER, EMAIL_ADDRESS}; const uint32_t expected_group_bitmask = kName | kPhone | kEmail; - const uint32_t group_bitmask = DetermineGroups(field_types); + const uint32_t group_bitmask = data_util::DetermineGroups(field_types); EXPECT_EQ(expected_group_bitmask, group_bitmask); } @@ -76,7 +58,7 @@ TEST(LabelFormatterUtilsTest, DetermineGroupsForBillingNamePhoneAndEmail) { NAME_BILLING_FULL, PHONE_BILLING_WHOLE_NUMBER, EMAIL_ADDRESS}; const uint32_t expected_group_bitmask = kName | kPhone | kEmail; - const uint32_t group_bitmask = DetermineGroups(field_types); + const uint32_t group_bitmask = data_util::DetermineGroups(field_types); EXPECT_EQ(expected_group_bitmask, group_bitmask); } @@ -85,7 +67,7 @@ TEST(LabelFormatterUtilsTest, DetermineGroupsForUnknownServerFieldType) { ADDRESS_HOME_ZIP}; const uint32_t expected_group_bitmask = kName | kAddress; - const uint32_t group_bitmask = DetermineGroups(field_types); + const uint32_t group_bitmask = data_util::DetermineGroups(field_types); EXPECT_EQ(expected_group_bitmask, group_bitmask); } @@ -93,8 +75,171 @@ TEST(LabelFormatterUtilsTest, DetermineGroupsForNoServerFieldTypes) { const std::vector<ServerFieldType> field_types = std::vector<ServerFieldType>(); const uint32_t expected_group_bitmask = 0; - const uint32_t group_bitmask = DetermineGroups(field_types); + const uint32_t group_bitmask = data_util::DetermineGroups(field_types); EXPECT_EQ(expected_group_bitmask, group_bitmask); } -} // namespace autofill
\ No newline at end of file +TEST(LabelFormatterUtilsTest, ConstructLabelLine) { + EXPECT_EQ(base::string16(), ConstructLabelLine({})); + + base::string16 name = base::ASCIIToUTF16("Blaise Pascal"); + base::string16 phone = base::ASCIIToUTF16("01 53 01 82 00"); + base::string16 email = base::ASCIIToUTF16("b.pascal@orange.fr"); + + base::string16 separator = + l10n_util::GetStringUTF16(IDS_AUTOFILL_SUGGESTION_LABEL_SEPARATOR); + + EXPECT_EQ(name, ConstructLabelLine({name})); + EXPECT_EQ(base::JoinString({name, separator, phone, separator, email}, + base::string16()), + ConstructLabelLine({name, phone, email})); +} + +TEST(LabelFormatterUtilsTest, + HaveSameEmailAddressesWithOneProfileAndNoEmailAddress) { + AutofillProfile profile = + AutofillProfile(base::GenerateGUID(), test::kEmptyOrigin); + test::SetProfileInfo(&profile, "Maria", "Margaretha", "Kirch", + "mmkirch@gmx.de", "", "", "", "", "", "", "DE", ""); + EXPECT_TRUE(HaveSameEmailAddresses({&profile}, "de")); +} + +TEST(LabelFormatterUtilsTest, + HaveSameEmailAddressesWithOneProfileAndEmailAddress) { + AutofillProfile profile = + AutofillProfile(base::GenerateGUID(), test::kEmptyOrigin); + test::SetProfileInfo(&profile, "Maria", "Margaretha", "Kirch", "", "", "", "", + "", "", "", "DE", ""); + EXPECT_TRUE(HaveSameEmailAddresses({&profile}, "de")); +} + +TEST(LabelFormatterUtilsTest, + HaveSameEmailAddressesWithProfilesAndNoEmailAddresses) { + AutofillProfile profile1 = + AutofillProfile(base::GenerateGUID(), test::kEmptyOrigin); + test::SetProfileInfo(&profile1, "Maria", "Margaretha", "Kirch", "", "", "", + "", "", "", "", "DE", ""); + AutofillProfile profile2 = + AutofillProfile(base::GenerateGUID(), test::kEmptyOrigin); + test::SetProfileInfo(&profile2, "Maria", "Margaretha", "Winckelmann", "", "", + "", "", "", "", "", "DE", ""); + EXPECT_TRUE(HaveSameEmailAddresses({&profile1, &profile2}, "de")); +} + +TEST(LabelFormatterUtilsTest, + HaveSameEmailAddressesWithProfilesAndSameEmailAddresses) { + AutofillProfile profile1 = + AutofillProfile(base::GenerateGUID(), test::kEmptyOrigin); + test::SetProfileInfo(&profile1, "Maria", "Margaretha", "Kirch", + "mmkirch@gmx.de", "", "", "", "", "", "", "DE", ""); + AutofillProfile profile2 = + AutofillProfile(base::GenerateGUID(), test::kEmptyOrigin); + test::SetProfileInfo(&profile2, "Maria", "Margaretha", "Winckelmann", + "mmkirch@gmx.de", "", "", "", "", "", "", "DE", ""); + EXPECT_TRUE(HaveSameEmailAddresses({&profile1, &profile2}, "de")); +} + +TEST(LabelFormatterUtilsTest, + HaveSameEmailAddressesWithProfilesAndDifferentNonEmptyEmailAddresses) { + AutofillProfile profile1 = + AutofillProfile(base::GenerateGUID(), test::kEmptyOrigin); + test::SetProfileInfo(&profile1, "Maria", "Margaretha", "Kirch", + "mmkirch@gmx.de", "", "", "", "", "", "", "DE", ""); + AutofillProfile profile2 = + AutofillProfile(base::GenerateGUID(), test::kEmptyOrigin); + test::SetProfileInfo(&profile2, "Maria", "Margaretha", "Winckelmann", + "mmw@gmail.com", "", "", "", "", "", "", "DE", ""); + EXPECT_FALSE(HaveSameEmailAddresses({&profile1, &profile2}, "de")); +} + +TEST(LabelFormatterUtilsTest, + HaveSameEmailAddressesWithProfilesAndNonEmptyAndEmptyEmailAddresses) { + AutofillProfile profile1 = + AutofillProfile(base::GenerateGUID(), test::kEmptyOrigin); + test::SetProfileInfo(&profile1, "Maria", "Margaretha", "Kirch", + "mmkirch@gmx.de", "", "", "", "", "", "", "DE", ""); + AutofillProfile profile2 = + AutofillProfile(base::GenerateGUID(), test::kEmptyOrigin); + test::SetProfileInfo(&profile2, "Maria", "Margaretha", "Winckelmann", "", "", + "", "", "", "", "", "DE", ""); + EXPECT_FALSE(HaveSameEmailAddresses({&profile1, &profile2}, "de")); + EXPECT_FALSE(HaveSameEmailAddresses({&profile2, &profile1}, "de")); +} + +TEST(LabelFormatterUtilsTest, + HaveSamePhoneNumbersWithOneProfileAndNoPhoneNumber) { + AutofillProfile profile = + AutofillProfile(base::GenerateGUID(), test::kEmptyOrigin); + test::SetProfileInfo(&profile, "Maria", "Margaretha", "Kirch", "", "", "", "", + "", "", "", "DE", ""); + EXPECT_TRUE(HaveSamePhoneNumbers({&profile}, "de")); +} + +TEST(LabelFormatterUtilsTest, + HaveSamePhoneNumbersWithOneProfileAndPhoneNumber) { + AutofillProfile profile = + AutofillProfile(base::GenerateGUID(), test::kEmptyOrigin); + test::SetProfileInfo(&profile, "Maria", "Margaretha", "Kirch", "", "", "", "", + "", "", "", "DE", "+49 30 4504-2823"); + EXPECT_TRUE(HaveSamePhoneNumbers({&profile}, "de")); +} + +TEST(LabelFormatterUtilsTest, + HaveSamePhoneNumbersWithProfilesAndNoPhoneNumber) { + AutofillProfile profile1 = + AutofillProfile(base::GenerateGUID(), test::kEmptyOrigin); + test::SetProfileInfo(&profile1, "Maria", "Margaretha", "Kirch", "", "", "", + "", "", "", "", "DE", ""); + AutofillProfile profile2 = + AutofillProfile(base::GenerateGUID(), test::kEmptyOrigin); + test::SetProfileInfo(&profile2, "Maria", "Margaretha", "Winckelmann", "", "", + "", "", "", "", "", "DE", ""); + EXPECT_TRUE(HaveSamePhoneNumbers({&profile1, &profile2}, "de")); +} + +TEST(LabelFormatterUtilsTest, + HaveSamePhoneNumbersWithProfilesAndSamePhoneNumbers) { + AutofillProfile profile1 = + AutofillProfile(base::GenerateGUID(), test::kEmptyOrigin); + test::SetProfileInfo(&profile1, "Maria", "Margaretha", "Kirch", "", "", "", + "", "", "", "", "DE", "+49 30 4504-2823"); + AutofillProfile profile2 = + AutofillProfile(base::GenerateGUID(), test::kEmptyOrigin); + test::SetProfileInfo(&profile2, "Maria", "Margaretha", "Winckelmann", "", "", + "", "", "", "", "", "DE", "4903045042823"); + AutofillProfile profile3 = + AutofillProfile(base::GenerateGUID(), test::kEmptyOrigin); + test::SetProfileInfo(&profile3, "Maria", "Margaretha", "Winckelmann", "", "", + "", "", "", "", "", "DE", "03045042823"); + EXPECT_TRUE(HaveSamePhoneNumbers({&profile1, &profile2, &profile3}, "de")); +} + +TEST(LabelFormatterUtilsTest, + HaveSamePhoneNumbersWithProfilesAndDifferentNonEmptyPhoneNumbers) { + AutofillProfile profile1 = + AutofillProfile(base::GenerateGUID(), test::kEmptyOrigin); + test::SetProfileInfo(&profile1, "Maria", "Margaretha", "Kirch", "", "", "", + "", "", "", "", "DE", "+49 30 4504-2823"); + AutofillProfile profile2 = + AutofillProfile(base::GenerateGUID(), test::kEmptyOrigin); + test::SetProfileInfo(&profile2, "Maria", "Margaretha", "Winckelmann", "", "", + "", "", "", "", "", "DE", "+49 221 22123828"); + EXPECT_FALSE(HaveSamePhoneNumbers({&profile1, &profile2}, "de")); +} + +TEST(LabelFormatterUtilsTest, + HaveSamePhoneNumbersWithProfilesAndNonEmptyAndEmptyPhoneNumbers) { + AutofillProfile profile1 = + AutofillProfile(base::GenerateGUID(), test::kEmptyOrigin); + test::SetProfileInfo(&profile1, "Maria", "Margaretha", "Kirch", "", "", "", + "", "", "", "", "DE", "+49 30 4504-2823"); + AutofillProfile profile2 = + AutofillProfile(base::GenerateGUID(), test::kEmptyOrigin); + test::SetProfileInfo(&profile2, "Maria", "Margaretha", "Winckelmann", "", "", + "", "", "", "", "", "DE", ""); + EXPECT_FALSE(HaveSamePhoneNumbers({&profile1, &profile2}, "de")); + EXPECT_FALSE(HaveSamePhoneNumbers({&profile2, &profile1}, "de")); +} + +} // namespace +} // namespace autofill diff --git a/chromium/components/autofill/core/browser/metrics/address_form_event_logger.cc b/chromium/components/autofill/core/browser/metrics/address_form_event_logger.cc index 06674d12c2d..129918d6774 100644 --- a/chromium/components/autofill/core/browser/metrics/address_form_event_logger.cc +++ b/chromium/components/autofill/core/browser/metrics/address_form_event_logger.cc @@ -4,14 +4,47 @@ #include "components/autofill/core/browser/metrics/address_form_event_logger.h" +#include <algorithm> +#include <iterator> +#include <memory> +#include <vector> + +#include "base/metrics/histogram_functions.h" #include "base/metrics/user_metrics.h" #include "base/metrics/user_metrics_action.h" -#include "components/autofill/core/browser/autofill_data_model.h" -#include "components/autofill/core/browser/autofill_metrics.h" -#include "components/autofill/core/browser/autofill_profile.h" -#include "components/autofill/core/browser/metrics/form_events.h" +#include "components/autofill/core/browser/autofill_data_util.h" +#include "components/autofill/core/browser/autofill_type.h" +#include "components/autofill/core/browser/field_types.h" namespace autofill { +namespace { + +using data_util::bit_field_type_groups::kAddress; +using data_util::bit_field_type_groups::kEmail; +using data_util::bit_field_type_groups::kName; +using data_util::bit_field_type_groups::kPhone; + +// Returns the histogram suffix corresponding to the given |bitmask|. +std::string GetSuffixForFormType(uint32_t bitmask) { + switch (bitmask) { + case kName | kAddress | kEmail | kPhone: + return ".AddressPlusEmailPlusPhone"; + case kName | kAddress | kPhone: + return ".AddressPlusPhone"; + case kName | kAddress | kEmail: + return ".AddressPlusEmail"; + case kName | kAddress: + return ".AddressOnly"; + case kName | kEmail | kPhone: + case kName | kEmail: + case kName | kPhone: + return ".ContactOnly"; + default: + return ".Other"; + } +} + +} // namespace AddressFormEventLogger::AddressFormEventLogger( bool is_in_main_frame, @@ -74,6 +107,26 @@ void AddressFormEventLogger::OnSubsequentRefillAttempt( Log(FORM_EVENT_DYNAMIC_CHANGE_AFTER_REFILL, form); } +void AddressFormEventLogger::OnLog(const std::string& name, + FormEvent event, + const FormStructure& form) const { + std::vector<ServerFieldType> types; + std::transform( + form.begin(), form.end(), std::back_inserter(types), + [&](const std::unique_ptr<AutofillField>& field) -> ServerFieldType { + return field->Type().GetStorableType(); + }); + + uint32_t groups = data_util::DetermineGroups(types); + base::UmaHistogramEnumeration(name + GetSuffixForFormType(groups), event, + NUM_FORM_EVENTS); + if (data_util::ContainsName(groups) && data_util::ContainsAddress(groups) && + (data_util::ContainsPhone(groups) || data_util::ContainsEmail(groups))) { + base::UmaHistogramEnumeration(name + ".AddressPlusContact", event, + NUM_FORM_EVENTS); + } +} + void AddressFormEventLogger::RecordPollSuggestions() { base::RecordAction( base::UserMetricsAction("Autofill_PolledProfileSuggestions")); diff --git a/chromium/components/autofill/core/browser/metrics/address_form_event_logger.h b/chromium/components/autofill/core/browser/metrics/address_form_event_logger.h index a115ffbde83..52d467dca02 100644 --- a/chromium/components/autofill/core/browser/metrics/address_form_event_logger.h +++ b/chromium/components/autofill/core/browser/metrics/address_form_event_logger.h @@ -5,10 +5,15 @@ #ifndef COMPONENTS_AUTOFILL_CORE_BROWSER_METRICS_ADDRESS_FORM_EVENT_LOGGER_H_ #define COMPONENTS_AUTOFILL_CORE_BROWSER_METRICS_ADDRESS_FORM_EVENT_LOGGER_H_ -#include "components/autofill/core/browser/autofill_data_model.h" +#include <string> + +#include "components/autofill/core/browser/autofill_field.h" #include "components/autofill/core/browser/autofill_metrics.h" +#include "components/autofill/core/browser/autofill_profile.h" +#include "components/autofill/core/browser/form_structure.h" #include "components/autofill/core/browser/metrics/form_event_logger_base.h" #include "components/autofill/core/browser/metrics/form_events.h" +#include "components/autofill/core/browser/sync_utils.h" namespace autofill { @@ -38,6 +43,9 @@ class AddressFormEventLogger : public FormEventLoggerBase { void RecordPollSuggestions() override; void RecordParseForm() override; void RecordShowSuggestions() override; + void OnLog(const std::string& name, + FormEvent event, + const FormStructure& form) const override; }; } // namespace autofill diff --git a/chromium/components/autofill/core/browser/metrics/credit_card_form_event_logger.cc b/chromium/components/autofill/core/browser/metrics/credit_card_form_event_logger.cc index ea19e7317b9..03aea4fe00c 100644 --- a/chromium/components/autofill/core/browser/metrics/credit_card_form_event_logger.cc +++ b/chromium/components/autofill/core/browser/metrics/credit_card_form_event_logger.cc @@ -9,13 +9,8 @@ #include "base/metrics/histogram_functions.h" #include "base/metrics/user_metrics.h" #include "base/metrics/user_metrics_action.h" -#include "components/autofill/core/browser/autofill_client.h" -#include "components/autofill/core/browser/autofill_metrics.h" -#include "components/autofill/core/browser/credit_card.h" +#include "base/strings/string16.h" #include "components/autofill/core/browser/form_data_importer.h" -#include "components/autofill/core/browser/form_structure.h" -#include "components/autofill/core/browser/metrics/form_events.h" -#include "components/autofill/core/browser/personal_data_manager.h" #include "components/autofill/core/browser/validation.h" namespace autofill { @@ -155,7 +150,8 @@ void CreditCardFormEventLogger::OnSuggestionsShownSubmittedOnce( } void CreditCardFormEventLogger::OnLog(const std::string& name, - FormEvent event) const { + FormEvent event, + const FormStructure& form) const { // Log in a different histogram for credit card forms on nonsecure pages so // that form interactions on nonsecure pages can be analyzed on their own. if (!is_context_secure_) { diff --git a/chromium/components/autofill/core/browser/metrics/credit_card_form_event_logger.h b/chromium/components/autofill/core/browser/metrics/credit_card_form_event_logger.h index 67a16324dae..05c64a9fca2 100644 --- a/chromium/components/autofill/core/browser/metrics/credit_card_form_event_logger.h +++ b/chromium/components/autofill/core/browser/metrics/credit_card_form_event_logger.h @@ -8,12 +8,15 @@ #include <string> #include "components/autofill/core/browser/autofill_client.h" -#include "components/autofill/core/browser/autofill_data_model.h" +#include "components/autofill/core/browser/autofill_field.h" #include "components/autofill/core/browser/autofill_metrics.h" #include "components/autofill/core/browser/credit_card.h" +#include "components/autofill/core/browser/form_structure.h" #include "components/autofill/core/browser/metrics/form_event_logger_base.h" #include "components/autofill/core/browser/metrics/form_events.h" #include "components/autofill/core/browser/personal_data_manager.h" +#include "components/autofill/core/browser/sync_utils.h" +#include "components/autofill/core/common/signatures_util.h" namespace autofill { @@ -67,7 +70,9 @@ class CreditCardFormEventLogger : public FormEventLoggerBase { void LogUkmInteractedWithForm(FormSignature form_signature) override; void OnSuggestionsShownOnce() override; void OnSuggestionsShownSubmittedOnce(const FormStructure& form) override; - void OnLog(const std::string& name, FormEvent event) const override; + void OnLog(const std::string& name, + FormEvent event, + const FormStructure& form) const override; // Bringing base class' Log function into scope to allow overloading. using FormEventLoggerBase::Log; diff --git a/chromium/components/autofill/core/browser/metrics/form_event_logger_base.cc b/chromium/components/autofill/core/browser/metrics/form_event_logger_base.cc index 99025b5070b..7a7edfcf177 100644 --- a/chromium/components/autofill/core/browser/metrics/form_event_logger_base.cc +++ b/chromium/components/autofill/core/browser/metrics/form_event_logger_base.cc @@ -4,22 +4,10 @@ #include "components/autofill/core/browser/metrics/form_event_logger_base.h" -#include <string> - #include "base/metrics/histogram_functions.h" #include "base/metrics/user_metrics.h" #include "base/metrics/user_metrics_action.h" #include "base/time/time.h" -#include "components/autofill/core/browser/autofill_data_model.h" -#include "components/autofill/core/browser/autofill_field.h" -#include "components/autofill/core/browser/autofill_metrics.h" -#include "components/autofill/core/browser/autofill_profile.h" -#include "components/autofill/core/browser/credit_card.h" -#include "components/autofill/core/browser/form_structure.h" -#include "components/autofill/core/browser/metrics/form_events.h" -#include "components/autofill/core/browser/sync_utils.h" -#include "components/autofill/core/common/form_field_data.h" -#include "components/autofill/core/common/signatures_util.h" namespace autofill { @@ -151,8 +139,8 @@ void FormEventLoggerBase::Log(FormEvent event, name + (is_in_main_frame_ ? ".IsInMainFrame" : ".IsInIFrame"), event, NUM_FORM_EVENTS); - // Allow specialized type of logging. - OnLog(name, event); + // Allow specialized types of logging, e.g. splitting metrics in useful ways. + OnLog(name, event, form); // Logging again in a different histogram for segmentation purposes. if (server_record_type_count_ == 0 && local_record_type_count_ == 0) diff --git a/chromium/components/autofill/core/browser/metrics/form_event_logger_base.h b/chromium/components/autofill/core/browser/metrics/form_event_logger_base.h index 173df3b0ddd..f07e69504db 100644 --- a/chromium/components/autofill/core/browser/metrics/form_event_logger_base.h +++ b/chromium/components/autofill/core/browser/metrics/form_event_logger_base.h @@ -7,15 +7,13 @@ #include <string> -#include "components/autofill/core/browser/autofill_data_model.h" #include "components/autofill/core/browser/autofill_field.h" #include "components/autofill/core/browser/autofill_metrics.h" -#include "components/autofill/core/browser/autofill_profile.h" -#include "components/autofill/core/browser/credit_card.h" #include "components/autofill/core/browser/form_structure.h" #include "components/autofill/core/browser/metrics/form_events.h" #include "components/autofill/core/browser/sync_utils.h" #include "components/autofill/core/common/form_field_data.h" +#include "components/autofill/core/common/signatures_util.h" namespace autofill { @@ -77,7 +75,14 @@ class FormEventLoggerBase { virtual void OnSuggestionsShownOnce() {} virtual void OnSuggestionsShownSubmittedOnce(const FormStructure& form) {} - virtual void OnLog(const std::string& name, FormEvent event) const {} + + // Logs |event| in a histogram prefixed with |name| according to the + // FormEventLogger type and |form|. For example, in the address context, it + // may be useful to analyze metrics for forms (A) with only name and address + // fields and (B) with only name and phone fields separately. + virtual void OnLog(const std::string& name, + FormEvent event, + const FormStructure& form) const {} // Constructor parameters. std::string form_type_name_; diff --git a/chromium/components/autofill/core/browser/password_generator.cc b/chromium/components/autofill/core/browser/password_generator.cc deleted file mode 100644 index 99101938f7a..00000000000 --- a/chromium/components/autofill/core/browser/password_generator.cc +++ /dev/null @@ -1,222 +0,0 @@ -// Copyright 2018 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "components/autofill/core/browser/password_generator.h" - -#include <algorithm> -#include <limits> -#include <map> -#include <vector> - -#include "base/logging.h" -#include "base/rand_util.h" -#include "base/strings/utf_string_conversions.h" -#include "components/autofill/core/browser/proto/password_requirements.pb.h" - -namespace autofill { - -// The default length for a generated password. Keep this the same as the -// default length known to the classification pipeline on the autofill -// crowd-sourcing server. (The server predicts password lengths only if the -// prediction is smaller than the default.) -const uint32_t kDefaultPasswordLength = 15; - -namespace { - -// Default character sets used if the spec does not override the character set. -// Removed characters due to visual similarity: -// - l (lowercase L) -// - I (capital i) -// - 1 (one) -// - O (capital o) -// - 0 (zero) -// - o (lowercase O) -constexpr char kLowerCaseChars[] = "abcdefghijkmnpqrstuvwxyz"; -constexpr char kUpperCaseChars[] = "ABCDEFGHJKLMNPQRSTUVWXYZ"; -constexpr char kAlphabeticChars[] = - "abcdefghijkmnpqrstuvwxyzABCDEFGHJKLMNPQRSTUVWXYZ"; -constexpr char kDigits[] = "23456789"; -constexpr char kSymbols[] = "-_.:!"; - -// Returns a default password requirements specification that requires: -// - at least one lower case letter -// - at least one upper case letter -// - at least one number -// - no symbols -PasswordRequirementsSpec BuildDefaultSpec() { - // Note the the fields below should be initialized in the order of their - // proto field numbers to reduce the risk of forgetting a field. - PasswordRequirementsSpec spec; - spec.set_priority(0); - spec.set_spec_version(1); - // spec.min_length and spec.max_length remain unset to fall back to - // PasswordGenerator::kDefaultPasswordLength. - - spec.mutable_lower_case()->set_character_set(kLowerCaseChars); - spec.mutable_lower_case()->set_min(1); - spec.mutable_lower_case()->set_max(std::numeric_limits<int32_t>::max()); - - spec.mutable_upper_case()->set_character_set(kUpperCaseChars); - spec.mutable_upper_case()->set_min(1); - spec.mutable_upper_case()->set_max(std::numeric_limits<int32_t>::max()); - - spec.mutable_alphabetic()->set_character_set(kAlphabeticChars); - spec.mutable_alphabetic()->set_min(0); - spec.mutable_alphabetic()->set_max(0); - - spec.mutable_numeric()->set_character_set(kDigits); - spec.mutable_numeric()->set_min(1); - spec.mutable_numeric()->set_max(std::numeric_limits<int32_t>::max()); - - spec.mutable_symbols()->set_character_set(kSymbols); - spec.mutable_symbols()->set_min(0); - spec.mutable_symbols()->set_max(0); - return spec; -} - -// Returns whether the password is difficult to read because it contains -// sequences of '-' or '_' that are joined into long strokes on the screen -// in many fonts. -bool IsDifficultToRead(const base::string16& password) { - return std::adjacent_find(password.begin(), password.end(), - [](auto a, auto b) { - return a == b && (a == '-' || a == '_'); - }) != password.end(); -} - -// Generates a password according to |spec| and tries to maximze the entropy -// while not caring for pronounceable passwords. -// -// |spec| must contain values for at least all fields that are defined -// in the spec of BuildDefaultSpec(). -base::string16 GenerateMaxEntropyPassword(PasswordRequirementsSpec spec) { - using CharacterClass = PasswordRequirementsSpec_CharacterClass; - - // Determine target length. - uint32_t target_length = kDefaultPasswordLength; - if (spec.has_min_length()) - target_length = std::max(target_length, spec.min_length()); - if (spec.has_max_length()) - target_length = std::min(target_length, spec.max_length()); - // Avoid excessively long passwords. - target_length = std::min(target_length, 200u); - - // The password that is being generated in this function. - base::string16 password; - password.reserve(target_length); - - // A list of CharacterClasses that have not been fully used. - std::vector<CharacterClass*> classes; - // The list of allowed characters in a specific class. This map exists - // to calculate the string16 conversion only once. - std::map<CharacterClass*, base::string16> characters_of_class; - - // These are guaranteed to exist because |spec| is an overlay of the default - // spec. - DCHECK(spec.has_lower_case()); - DCHECK(spec.has_upper_case()); - DCHECK(spec.has_alphabetic()); - DCHECK(spec.has_numeric()); - DCHECK(spec.has_symbols()); - - // Initialize |classes| and |characters_of_class| and sanitize |spec| - // if necessary. - for (CharacterClass* character_class : - {spec.mutable_lower_case(), spec.mutable_upper_case(), - spec.mutable_alphabetic(), spec.mutable_numeric(), - spec.mutable_symbols()}) { - DCHECK(character_class->has_character_set()); - DCHECK(character_class->has_min()); - DCHECK(character_class->has_max()); - - // If the character set is empty, we cannot generate characters from it. - if (character_class->character_set().empty()) - character_class->set_max(0); - - // The the maximum is smaller than the minimum, limit the minimum. - if (character_class->max() < character_class->min()) - character_class->set_min(character_class->max()); - - if (character_class->max() > 0) { - classes.push_back(character_class); - characters_of_class[character_class] = - base::UTF8ToUTF16(character_class->character_set()); - } - } - - // Generate a password that contains the minimum number of characters of the - // various character classes as per requirements. This stops when the target - // length is achieved. Note that this is just a graceful handling of a buggy - // spec. It should not happen that more characters are needed than can - // accommodated. - for (CharacterClass* character_class : classes) { - while (character_class->min() > 0 && password.length() < target_length) { - const base::string16& possible_chars = - characters_of_class[character_class]; - password += possible_chars[base::RandGenerator(possible_chars.length())]; - character_class->set_min(character_class->min() - 1); - character_class->set_max(character_class->max() - 1); - } - } - - // Now fill the rest of the password with random characters. - while (password.length() < target_length) { - // Determine how many different characters are in all remaining character - // classes. - size_t number_of_possible_chars = 0; - for (CharacterClass* character_class : classes) { - if (character_class->max() > 0) { - number_of_possible_chars += - characters_of_class[character_class].length(); - } - } - if (number_of_possible_chars == 0) - break; - uint64_t choice = base::RandGenerator(number_of_possible_chars); - // Now figure out which character was chosen and append it. - for (CharacterClass* character_class : classes) { - if (character_class->max() > 0) { - size_t size_of_class = characters_of_class[character_class].length(); - if (choice < size_of_class) { - password += characters_of_class[character_class][choice]; - character_class->set_max(character_class->max() - 1); - break; - } else { - choice -= size_of_class; - } - } - } - } - - // So far the password contains the minimally required characters at the - // the beginning. Therefore, we create a random permutation. - // TODO(crbug.com/847200): Once the unittests allow controlling the generated - // string, test that '--' and '__' are eliminated. - int remaining_attempts = 5; - do { - base::RandomShuffle(password.begin(), password.end()); - } while (IsDifficultToRead(password) && remaining_attempts-- > 0); - - return password; -} - -} // namespace - -base::string16 GeneratePassword(const PasswordRequirementsSpec& spec) { - PasswordRequirementsSpec actual_spec = BuildDefaultSpec(); - - // Override all fields that are set in |spec|. Character classes are merged - // recursively. - actual_spec.MergeFrom(spec); - - base::string16 password = GenerateMaxEntropyPassword(std::move(actual_spec)); - - // Catch cases where supplied spec is infeasible. - if (password.empty()) - password = GenerateMaxEntropyPassword(BuildDefaultSpec()); - - return password; -} - -} // namespace autofill diff --git a/chromium/components/autofill/core/browser/password_generator.h b/chromium/components/autofill/core/browser/password_generator.h deleted file mode 100644 index 4ff870f942d..00000000000 --- a/chromium/components/autofill/core/browser/password_generator.h +++ /dev/null @@ -1,30 +0,0 @@ -// Copyright 2018 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef COMPONENTS_AUTOFILL_CORE_BROWSER_PASSWORD_GENERATOR_H_ -#define COMPONENTS_AUTOFILL_CORE_BROWSER_PASSWORD_GENERATOR_H_ - -#include "base/strings/string16.h" - -namespace autofill { - -class PasswordRequirementsSpec; - -extern const uint32_t kDefaultPasswordLength; - -// Returns a password that follows the |spec| as well as possible. If this is -// impossible, a password that nearly meets the requirements can be returned. -// In this case the user is asked to fix the password themselves. -// -// If |spec| is empty, a password of length |kDefaultPasswordLength| is -// generated that contains -// - at least 1 lower case latin character -// - at least 1 upper case latin character -// - at least 1 number (digit) -// - no symbols -base::string16 GeneratePassword(const PasswordRequirementsSpec& spec); - -} // namespace autofill - -#endif // COMPONENTS_AUTOFILL_CORE_BROWSER_PASSWORD_GENERATOR_H_ diff --git a/chromium/components/autofill/core/browser/password_generator_fips181.cc b/chromium/components/autofill/core/browser/password_generator_fips181.cc deleted file mode 100644 index 3226576ea9b..00000000000 --- a/chromium/components/autofill/core/browser/password_generator_fips181.cc +++ /dev/null @@ -1,124 +0,0 @@ -// Copyright 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "components/autofill/core/browser/password_generator_fips181.h" - -#include <stddef.h> - -#include <algorithm> -#include <vector> - -#include "base/rand_util.h" -#include "base/strings/string_util.h" -#include "third_party/fips181/fips181.h" - -namespace { - -const int kMinUpper = 65; // First upper case letter 'A' -const int kMaxUpper = 90; // Last upper case letter 'Z' -const int kMinLower = 97; // First lower case letter 'a' -const int kMaxLower = 122; // Last lower case letter 'z' -const int kMinDigit = 48; // First digit '0' -const int kMaxDigit = 57; // Last digit '9' -const int kMinPasswordLength = 4; -const int kMaxPasswordLength = 15; - -// A helper function to get the length of the generated password from -// |max_length| retrieved from input password field. -int GetLengthFromHint(int max_length, int default_length) { - if (max_length >= kMinPasswordLength && max_length <= kMaxPasswordLength) - return max_length; - return default_length; -} - -// We want the password to have uppercase, lowercase, and at least one number. -bool VerifyPassword(const std::string& password) { - int num_lower_case = 0; - int num_upper_case = 0; - int num_digits = 0; - - for (size_t i = 0; i < password.size(); ++i) { - if (password[i] >= kMinUpper && password[i] <= kMaxUpper) - ++num_upper_case; - if (password[i] >= kMinLower && password[i] <= kMaxLower) - ++num_lower_case; - if (password[i] >= kMinDigit && password[i] <= kMaxDigit) - ++num_digits; - } - - return num_lower_case && num_upper_case && num_digits; -} - -// Password generation function for unit testing, default to nullptr. -// If not null, ForceFixPassword() will also always use |kMinDigit| as the digit -// replacement, instead of choosing randomly. -int (*g_test_override_generator)(char* word, - char* hypenated_word, - unsigned short minlen, - unsigned short maxlen, - unsigned int pass_mode) = nullptr; - -} // namespace - -namespace autofill { - -const int PasswordGeneratorFips181::kDefaultPasswordLength = 15; - -void ForceFixPassword(std::string* password) { - for (char& it : *password) { - if (islower(it)) { - it = base::ToUpperASCII(it); - break; - } - } - for (std::string::reverse_iterator iter = password->rbegin(); - iter != password->rend(); ++iter) { - if (islower(*iter)) { - // Tests will use |PasswordGeneratorFips181::SetGeneratorForTest| to put a - // non-random generator in |g_test_override_generator|. To eliminate the - // other source of randomness, always fix the chosen digit to |kMinDigit| - // in such case. - *iter = g_test_override_generator == nullptr - ? base::RandInt(kMinDigit, kMaxDigit) - : kMinDigit; - break; - } - } -} - -PasswordGeneratorFips181::PasswordGeneratorFips181(int max_length) - : password_length_(GetLengthFromHint(max_length, kDefaultPasswordLength)) {} -PasswordGeneratorFips181::~PasswordGeneratorFips181() {} - -void PasswordGeneratorFips181::SetGeneratorForTest( - int (*generator)(char* word, - char* hypenated_word, - unsigned short minlen, - unsigned short maxlen, - unsigned int pass_mode)) { - g_test_override_generator = generator; -} - -std::string PasswordGeneratorFips181::Generate() const { - char password[255]; - char unused_hypenated_password[255]; - // Generate passwords that have numbers and upper and lower case letters. - // No special characters included for now. - unsigned int mode = S_NB | S_CL | S_SL; - - // Generate the password and fix afterwards if needed. - auto generator = - g_test_override_generator ? g_test_override_generator : gen_pron_pass; - generator(password, unused_hypenated_password, password_length_, - password_length_, mode); - std::string str_password(password); - - if (VerifyPassword(str_password)) - return str_password; - - ForceFixPassword(&str_password); - return str_password; -} - -} // namespace autofill diff --git a/chromium/components/autofill/core/browser/password_generator_fips181.h b/chromium/components/autofill/core/browser/password_generator_fips181.h deleted file mode 100644 index 732cc732b8d..00000000000 --- a/chromium/components/autofill/core/browser/password_generator_fips181.h +++ /dev/null @@ -1,62 +0,0 @@ -// Copyright 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef COMPONENTS_AUTOFILL_CORE_BROWSER_PASSWORD_GENERATOR_FIPS181_H_ -#define COMPONENTS_AUTOFILL_CORE_BROWSER_PASSWORD_GENERATOR_FIPS181_H_ - -#include <string> - -#include "base/gtest_prod_util.h" -#include "base/macros.h" - -namespace autofill { - -// Make sure that there is at least one upper case and one number in the -// password. |password| must not be null, and must point to a string containing -// at least 3 lower-case letters. -extern void ForceFixPassword(std::string* password); - -// Class to generate random passwords. Currently we just use a generic algorithm -// for all sites, but eventually we can incorporate additional information to -// determine passwords that are likely to be accepted (i.e. use pattern field, -// previous generated passwords, crowdsourcing, etc.) -class PasswordGeneratorFips181 { - public: - // |max_length| is used as a hint for the generated password's length. - explicit PasswordGeneratorFips181(int max_length); - ~PasswordGeneratorFips181(); - - // Returns a random password such that: - // (1) Each character is guaranteed to be a non-whitespace printable ASCII - // character. - // (2) The generated password will contain AT LEAST one upper case letter, one - // lower case letter, and one digit. - // (3) The password length will be equal to |password_length_| (see comment - // for the constructor). - // Not thread safe. - std::string Generate() const; - - // This method allows to substitute a replacement for the fips181 method - // gen_pron_pass, used by the generator to generate the password. This is - // useful in tests, for providing a deterministic generator. - static void SetGeneratorForTest(int (*generator)(char* word, - char* hypenated_word, - unsigned short minlen, - unsigned short maxlen, - unsigned int pass_mode)); - - private: - // Unit test also need to access |kDefaultPasswordLength|. - static const int kDefaultPasswordLength; - FRIEND_TEST_ALL_PREFIXES(PasswordGeneratorFips181Test, PasswordLength); - - // The length of the generated password. - const int password_length_; - - DISALLOW_COPY_AND_ASSIGN(PasswordGeneratorFips181); -}; - -} // namespace autofill - -#endif // COMPONENTS_AUTOFILL_CORE_BROWSER_PASSWORD_GENERATOR_FIPS181_H_ diff --git a/chromium/components/autofill/core/browser/password_generator_fips181_fuzzer.cc b/chromium/components/autofill/core/browser/password_generator_fips181_fuzzer.cc deleted file mode 100644 index 83d6b2618d4..00000000000 --- a/chromium/components/autofill/core/browser/password_generator_fips181_fuzzer.cc +++ /dev/null @@ -1,47 +0,0 @@ -// Copyright 2018 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include <stddef.h> -#include <stdint.h> - -#include <string> - -#include "components/autofill/core/browser/password_generator_fips181.h" - -namespace autofill { - -namespace { - -const char* g_password_text = nullptr; - -// The "PasswordGeneratorFips181" is a wrapper around Fips181's gen_pron_pass(). -// The former processes the random string from the latter and ensures that it -// meets some constraints. GenerateForTest here substitutes for gen_pron_pass(), -// so that the fuzzer tests the wrapper's logic rather than the third-party's -// generator implementation. -int GenerateForTest(char* word, - char* hypenated_word, - unsigned short minlen, - unsigned short maxlen, - unsigned int pass_mode) { - strncpy(word, g_password_text, maxlen); - g_password_text = nullptr; - // Resize password to |maxlen|. - word[maxlen] = '\0'; - return static_cast<int>(strlen(word)); -} - -} // namespace - -extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) { - autofill::PasswordGeneratorFips181::SetGeneratorForTest(GenerateForTest); - std::string generator_string(reinterpret_cast<const char*>(data), size); - g_password_text = generator_string.c_str(); - autofill::PasswordGeneratorFips181 pg(size); - std::string password = pg.Generate(); - autofill::PasswordGeneratorFips181::SetGeneratorForTest(nullptr); - return 0; -} - -} // namespace autofill diff --git a/chromium/components/autofill/core/browser/password_generator_fips181_unittest.cc b/chromium/components/autofill/core/browser/password_generator_fips181_unittest.cc deleted file mode 100644 index 6188aa74421..00000000000 --- a/chromium/components/autofill/core/browser/password_generator_fips181_unittest.cc +++ /dev/null @@ -1,117 +0,0 @@ -// Copyright 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include <stddef.h> -#include <string.h> - -#include <locale> - -#include "components/autofill/core/browser/password_generator_fips181.h" -#include "testing/gtest/include/gtest/gtest.h" - -namespace { - -void CheckPasswordCorrectness(const std::string& password) { - int num_upper_case_letters = 0; - int num_lower_case_letters = 0; - int num_digits = 0; - for (size_t i = 0; i < password.size(); i++) { - if (isupper(password[i])) - ++num_upper_case_letters; - else if (islower(password[i])) - ++num_lower_case_letters; - else if (isdigit(password[i])) - ++num_digits; - } - EXPECT_GT(num_upper_case_letters, 0) << password; - EXPECT_GT(num_lower_case_letters, 0) << password; - EXPECT_GT(num_digits, 0) << password; -} - -const char* g_password_text = nullptr; - -int GenerateForTest(char* word, - char* hypenated_word, - unsigned short minlen, - unsigned short maxlen, - unsigned int pass_mode) { - EXPECT_LE(minlen, maxlen); - EXPECT_TRUE(word); - EXPECT_TRUE(hypenated_word); - EXPECT_TRUE(g_password_text) << "Set g_password_text before every call"; - strncpy(word, g_password_text, maxlen); - g_password_text = nullptr; - // Resize password to |maxlen|. - word[maxlen] = '\0'; - EXPECT_GE(strlen(word), minlen) - << "Make sure to provide enough characters in g_password_text"; - return static_cast<int>(strlen(word)); -} - -class PasswordGeneratorFips181Test : public ::testing::Test { - public: - PasswordGeneratorFips181Test() { - autofill::PasswordGeneratorFips181::SetGeneratorForTest(GenerateForTest); - } - ~PasswordGeneratorFips181Test() override { - autofill::PasswordGeneratorFips181::SetGeneratorForTest(nullptr); - } - - private: - DISALLOW_COPY_AND_ASSIGN(PasswordGeneratorFips181Test); -}; - -} // namespace - -namespace autofill { - -TEST_F(PasswordGeneratorFips181Test, PasswordLength) { - PasswordGeneratorFips181 pg1(10); - g_password_text = "Aa12345678901234567890"; - std::string password = pg1.Generate(); - EXPECT_EQ(password.size(), 10u); - - PasswordGeneratorFips181 pg2(-1); - g_password_text = "Aa12345678901234567890"; - password = pg2.Generate(); - EXPECT_EQ( - password.size(), - static_cast<size_t>(PasswordGeneratorFips181::kDefaultPasswordLength)); - - PasswordGeneratorFips181 pg3(100); - g_password_text = "Aa12345678901234567890"; - password = pg3.Generate(); - EXPECT_EQ( - password.size(), - static_cast<size_t>(PasswordGeneratorFips181::kDefaultPasswordLength)); -} - -TEST_F(PasswordGeneratorFips181Test, PasswordPattern) { - PasswordGeneratorFips181 pg1(12); - g_password_text = "012345678jkl"; - std::string password1 = pg1.Generate(); - CheckPasswordCorrectness(password1); - - PasswordGeneratorFips181 pg2(12); - g_password_text = "abcDEFGHIJKL"; - std::string password2 = pg2.Generate(); - CheckPasswordCorrectness(password2); - - PasswordGeneratorFips181 pg3(12); - g_password_text = "abcdefghijkl"; - std::string password3 = pg3.Generate(); - CheckPasswordCorrectness(password3); -} - -TEST_F(PasswordGeneratorFips181Test, ForceFixPasswordTest) { - std::string passwords_to_fix[] = {"nonumbersoruppercase", - "nonumbersWithuppercase", - "numbers3Anduppercase", "UmpAwgemHoc"}; - for (auto& password : passwords_to_fix) { - ForceFixPassword(&password); - CheckPasswordCorrectness(password); - } -} - -} // namespace autofill diff --git a/chromium/components/autofill/core/browser/password_generator_proto_fuzzer.cc b/chromium/components/autofill/core/browser/password_generator_proto_fuzzer.cc deleted file mode 100644 index 2967bc68616..00000000000 --- a/chromium/components/autofill/core/browser/password_generator_proto_fuzzer.cc +++ /dev/null @@ -1,15 +0,0 @@ -// Copyright 2018 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "components/autofill/core/browser/password_generator.h" -#include "components/autofill/core/browser/proto/password_requirements.pb.h" -#include "testing/libfuzzer/proto/lpm_interface.h" - -namespace autofill { - -DEFINE_PROTO_FUZZER(const PasswordRequirementsSpec& spec) { - GeneratePassword(spec); -} - -} // namespace autofill diff --git a/chromium/components/autofill/core/browser/password_generator_unittest.cc b/chromium/components/autofill/core/browser/password_generator_unittest.cc deleted file mode 100644 index 85343887168..00000000000 --- a/chromium/components/autofill/core/browser/password_generator_unittest.cc +++ /dev/null @@ -1,273 +0,0 @@ -// Copyright 2018 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "components/autofill/core/browser/password_generator.h" - -#include "base/logging.h" -#include "components/autofill/core/browser/proto/password_requirements.pb.h" -#include "testing/gtest/include/gtest/gtest.h" - -namespace autofill { - -namespace { - -// These are strings instead of enums to have an easy way of logging them. -constexpr char kLowerCase[] = "lower_case"; -constexpr char kUpperCase[] = "upper_case"; -constexpr char kAlphabetic[] = "alphabetic"; -constexpr char kNumeric[] = "numeric"; -constexpr char kSymbol[] = "symbol"; - -constexpr const char* kAllClassesButSymbols[] = {kLowerCase, kUpperCase, - kAlphabetic, kNumeric}; -constexpr const char* kAllClassesButSymbolsAndAlphabetic[] = { - kLowerCase, kUpperCase, kNumeric}; - -bool IsCharInClass(base::char16 c, const std::string& class_name) { - if (class_name == kLowerCase) { - return 'a' <= c && c <= 'z'; - } else if (class_name == kUpperCase) { - return 'A' <= c && c <= 'Z'; - } else if (class_name == kAlphabetic) { - return IsCharInClass(c, kLowerCase) || IsCharInClass(c, kUpperCase); - } else if (class_name == kNumeric) { - return '0' <= c && c <= '9'; - } - // Symbols are not covered because there is not fixed definition and because - // symbols are treated like other character classes, so the importance of - // dealing with them here is limited. - NOTREACHED() << "Don't call IsCharInClass for symbols"; - return false; -} - -size_t CountCharsInClass(const base::string16& password, - const std::string& class_name) { - size_t num = 0; - for (base::char16 c : password) { - if (IsCharInClass(c, class_name)) - ++num; - } - return num; -} - -PasswordRequirementsSpec_CharacterClass* GetMutableCharClass( - PasswordRequirementsSpec* spec, - const std::string& class_name) { - if (class_name == kLowerCase) { - return spec->mutable_lower_case(); - } else if (class_name == kUpperCase) { - return spec->mutable_upper_case(); - } else if (class_name == kAlphabetic) { - return spec->mutable_alphabetic(); - } else if (class_name == kNumeric) { - return spec->mutable_numeric(); - } else if (class_name == kSymbol) { - return spec->mutable_symbols(); - } - NOTREACHED(); - return nullptr; -} - -class PasswordGeneratorTest : public testing::Test { - public: - PasswordGeneratorTest() { spec_.set_spec_version(1); } - ~PasswordGeneratorTest() override = default; - - PasswordRequirementsSpec spec_; -}; - -TEST_F(PasswordGeneratorTest, PasswordLengthDefault) { - EXPECT_EQ(kDefaultPasswordLength, GeneratePassword(spec_).length()); -} - -TEST_F(PasswordGeneratorTest, PasswordLengthMaxLength) { - // Limit length according to requirement. - spec_.set_max_length(kDefaultPasswordLength - 5u); - EXPECT_EQ(kDefaultPasswordLength - 5u, GeneratePassword(spec_).length()); - - // If max is higher than default, it does not matter. - spec_.set_max_length(kDefaultPasswordLength + 5); - EXPECT_EQ(kDefaultPasswordLength, GeneratePassword(spec_).length()); -} - -TEST_F(PasswordGeneratorTest, PasswordLengthMinLength) { - // If min is smaller than default, it does not matter. - spec_.set_min_length(kDefaultPasswordLength - 5u); - EXPECT_EQ(kDefaultPasswordLength, GeneratePassword(spec_).length()); - - // If a higher minimum length is explicitly set, use it. - spec_.set_min_length(kDefaultPasswordLength + 5u); - EXPECT_EQ(kDefaultPasswordLength + 5u, GeneratePassword(spec_).length()); -} - -TEST_F(PasswordGeneratorTest, PasswordLengthMinAndMax) { - // Configure a contradicting min and max length. The max length wins. - spec_.set_min_length(kDefaultPasswordLength + 5u); - spec_.set_max_length(kDefaultPasswordLength - 5u); - EXPECT_EQ(kDefaultPasswordLength - 5u, GeneratePassword(spec_).length()); -} - -TEST_F(PasswordGeneratorTest, MinCharFrequenciesRespected) { - for (std::string char_class : kAllClassesButSymbols) { - SCOPED_TRACE(char_class); - spec_ = PasswordRequirementsSpec(); - spec_.set_spec_version(1); - auto* char_class_config = GetMutableCharClass(&spec_, char_class); - char_class_config->set_min(10); - char_class_config->set_max(1000); - - base::string16 password = GeneratePassword(spec_); - EXPECT_GE(CountCharsInClass(password, char_class), 10u); - } -} - -TEST_F(PasswordGeneratorTest, MinCharFrequenciesInsane) { - // Nothing breaks if the min frequencies are way beyond what's possible - // with the password length. In this case the generated passwor may contain - // just characters of one class but its target length does not increase. - for (std::string char_class : kAllClassesButSymbols) { - SCOPED_TRACE(char_class); - spec_ = PasswordRequirementsSpec(); - spec_.set_spec_version(1); - auto* char_class_config = GetMutableCharClass(&spec_, char_class); - char_class_config->set_min(1000); - char_class_config->set_max(1000); - - base::string16 password = GeneratePassword(spec_); - // At least some of the characters should be there. - EXPECT_GE(CountCharsInClass(password, char_class), 1u); - // But the password length does not change by minimum length requirements. - EXPECT_EQ(kDefaultPasswordLength, GeneratePassword(spec_).length()); - } -} - -TEST_F(PasswordGeneratorTest, MinCharFrequenciesBiggerThanMax) { - spec_.set_min_length(15); - spec_.set_max_length(15); - for (std::string char_class : kAllClassesButSymbolsAndAlphabetic) { - auto* char_class_config = GetMutableCharClass(&spec_, char_class); - // Min is reduced to max --> each class should have 5 representatives. - char_class_config->set_min(10); - char_class_config->set_max(5); - } - - base::string16 password = GeneratePassword(spec_); - - for (std::string char_class : kAllClassesButSymbolsAndAlphabetic) { - SCOPED_TRACE(char_class); - // Check that each character class is represented by 5 characters. - EXPECT_EQ(5u, CountCharsInClass(password, char_class)); - } - EXPECT_EQ(15u, password.length()); -} - -TEST_F(PasswordGeneratorTest, MaxFrequenciesRespected) { - // Limit the maximum occurrences of characters of some classes to 2 and - // validate that this is respected. - for (std::string char_class : kAllClassesButSymbolsAndAlphabetic) { - SCOPED_TRACE(char_class); - spec_ = PasswordRequirementsSpec(); - spec_.set_spec_version(1); - auto* char_class_config = GetMutableCharClass(&spec_, char_class); - char_class_config->set_max(2); - - base::string16 password = GeneratePassword(spec_); - EXPECT_LE(CountCharsInClass(password, char_class), 2u); - // Ensure that the other character classes that are not limited fill up the - // password to the desired length. - EXPECT_EQ(kDefaultPasswordLength, GeneratePassword(spec_).length()); - } -} - -TEST_F(PasswordGeneratorTest, MaxFrequenciesInsufficient) { - spec_.set_min_length(15); - spec_.set_max_length(15); - // Limit the maximum occurrences of characters of all classes to 2 which - // sums up to less than 15. - for (std::string char_class : kAllClassesButSymbolsAndAlphabetic) { - auto* char_class_config = GetMutableCharClass(&spec_, char_class); - char_class_config->set_max(2); - } - // The resulting password can contain only 6 characters. - EXPECT_EQ(6u, GeneratePassword(spec_).length()); -} - -TEST_F(PasswordGeneratorTest, CharacterSetCanBeOverridden) { - // Limit lower case chars to 'a' and 'b' and require exacty 5 of those. - spec_.mutable_lower_case()->set_character_set("ab"); - spec_.mutable_lower_case()->set_min(5); - spec_.mutable_lower_case()->set_max(5); - base::string16 password = GeneratePassword(spec_); - // Then ensure that 'a's and 'b's are generated at the expected frequencies - // as an indicator that the override was respected. - size_t num_as_and_bs = 0; - for (base::char16 c : password) { - if (c == 'a' || c == 'b') - ++num_as_and_bs; - } - EXPECT_EQ(5u, num_as_and_bs); -} - -TEST_F(PasswordGeneratorTest, AllCharactersAreGenerated) { - // Limit lower case chars to 'a' and 'b' and require exacty 5 of those. - spec_.mutable_lower_case()->set_character_set("ab"); - spec_.mutable_lower_case()->set_min(5); - spec_.mutable_lower_case()->set_max(5); - bool success = false; - // The chance of not seing both an 'a' and a 'b' in one run are only 2/32 per - // run. Ultimately we should see success. If none of the 100 generated - // passwords contained an 'a' (or 'b'), then this would indicate that the - // generator does not fully use the character set (probably due to an - // off-by-one error). - for (size_t attempt = 0; attempt < 100; ++attempt) { - base::string16 password = GeneratePassword(spec_); - size_t num_as = 0; - size_t num_bs = 0; - for (base::char16 c : password) { - if (c == 'a') - ++num_as; - if (c == 'b') - ++num_bs; - } - if (num_as > 0u && num_bs > 0u) { - success = true; - break; - } - } - EXPECT_TRUE(success); -} - -TEST_F(PasswordGeneratorTest, PasswordCanBeGeneratedWithEmptyCharSet) { - // If the character set is empty, min and max should be ignored. - spec_.mutable_lower_case()->set_character_set(""); - spec_.mutable_lower_case()->set_min(5); - spec_.mutable_lower_case()->set_max(5); - base::string16 password = GeneratePassword(spec_); - EXPECT_EQ(0u, CountCharsInClass(password, kLowerCase)); - EXPECT_EQ(kDefaultPasswordLength, GeneratePassword(spec_).length()); -} - -TEST_F(PasswordGeneratorTest, AllCharactersForbidden) { - spec_.set_min_length(kDefaultPasswordLength + 2); - spec_.set_max_length(kDefaultPasswordLength + 2); - for (std::string char_class : kAllClassesButSymbolsAndAlphabetic) { - auto* char_class_config = GetMutableCharClass(&spec_, char_class); - char_class_config->set_max(0); - } - // If it is impossible to generate a password (due to max = 0), the generator - // delivers a password as per default spec and ignores everything else. - EXPECT_EQ(kDefaultPasswordLength, GeneratePassword(spec_).length()); -} - -TEST_F(PasswordGeneratorTest, ZeroLength) { - spec_.set_min_length(0); - spec_.set_max_length(0); - // If the generated password following the spec is empty, a default spec is - // applied. - EXPECT_EQ(kDefaultPasswordLength, GeneratePassword(spec_).length()); -} - -} // namespace - -} // namespace autofill diff --git a/chromium/components/autofill/core/browser/password_requirements_spec_fetcher.h b/chromium/components/autofill/core/browser/password_requirements_spec_fetcher.h deleted file mode 100644 index d07997de389..00000000000 --- a/chromium/components/autofill/core/browser/password_requirements_spec_fetcher.h +++ /dev/null @@ -1,41 +0,0 @@ -// Copyright 2018 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef COMPONENTS_AUTOFILL_CORE_BROWSER_PASSWORD_REQUIREMENTS_SPEC_FETCHER_H_ -#define COMPONENTS_AUTOFILL_CORE_BROWSER_PASSWORD_REQUIREMENTS_SPEC_FETCHER_H_ - -#include "base/callback.h" -#include "url/gurl.h" - -namespace autofill { - -class PasswordRequirementsSpec; - -// Fetches PasswordRequirementsSpec for a specific origin. -class PasswordRequirementsSpecFetcher { - public: - using FetchCallback = - base::OnceCallback<void(const PasswordRequirementsSpec&)>; - - virtual ~PasswordRequirementsSpecFetcher() = default; - - // Fetches a configuration for |origin|. - // - // |origin| references the origin in the PasswordForm for which rules need to - // be fetched. - // - // The |callback| must remain valid until called back, but this class may be - // destroyed before the |callback| has been triggered. - // - // Fetch() may be called multiple times concurrently. Requests are batched - // if possible. - // - // If the network request fails or times out, the callback receives an empty - // spec. - virtual void Fetch(GURL origin, FetchCallback callback) = 0; -}; - -} // namespace autofill - -#endif // COMPONENTS_AUTOFILL_CORE_BROWSER_PASSWORD_REQUIREMENTS_SPEC_FETCHER_H_ diff --git a/chromium/components/autofill/core/browser/password_requirements_spec_fetcher_impl.cc b/chromium/components/autofill/core/browser/password_requirements_spec_fetcher_impl.cc deleted file mode 100644 index ff4367110f0..00000000000 --- a/chromium/components/autofill/core/browser/password_requirements_spec_fetcher_impl.cc +++ /dev/null @@ -1,315 +0,0 @@ -// Copyright 2018 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "components/autofill/core/browser/password_requirements_spec_fetcher_impl.h" - -#include "base/bind.h" -#include "base/logging.h" -#include "base/md5.h" -#include "base/metrics/histogram_functions.h" -#include "base/metrics/histogram_macros.h" -#include "base/strings/stringprintf.h" -#include "base/time/time.h" -#include "components/autofill/core/browser/password_requirements_spec_printer.h" -#include "components/autofill/core/browser/proto/password_requirements.pb.h" -#include "components/autofill/core/browser/proto/password_requirements_shard.pb.h" -#include "net/base/load_flags.h" -#include "net/base/net_errors.h" -#include "net/base/registry_controlled_domains/registry_controlled_domain.h" -#include "services/network/public/cpp/resource_request.h" -#include "services/network/public/cpp/shared_url_loader_factory.h" -#include "services/network/public/cpp/simple_url_loader.h" -#include "url/url_canon.h" - -namespace autofill { - -PasswordRequirementsSpecFetcherImpl::PasswordRequirementsSpecFetcherImpl( - scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory, - int version, - size_t prefix_length, - int timeout) - : url_loader_factory_(std::move(url_loader_factory)), - version_(version), - prefix_length_(prefix_length), - timeout_(timeout) { - DCHECK_GE(version_, 0); - DCHECK_LE(prefix_length_, 32u); - DCHECK_GE(timeout_, 0); -} - -PasswordRequirementsSpecFetcherImpl::~PasswordRequirementsSpecFetcherImpl() = - default; - -PasswordRequirementsSpecFetcherImpl::LookupInFlight::LookupInFlight() = default; -PasswordRequirementsSpecFetcherImpl::LookupInFlight::~LookupInFlight() = - default; - -namespace { - -// Hashes the eTLD+1 of |origin| via MD5 and returns a filename with the first -// |prefix_length| bits populated. The returned value corresponds to the first -// 4 bytes of the truncated MD5 prefix in hex notation. -// For example: -// "https://www.example.com" has a eTLD+1 of "example.com". -// The MD5SUM of that is 5ababd603b22780302dd8d83498e5172. -// Stripping this to the first 8 bits (prefix_length = 8) gives -// 500000000000000000000000000000000. The file name is always cut to the first -// four bytes, i.e. 5000 in this example. -std::string GetHashPrefix(const GURL& origin, size_t prefix_length) { - DCHECK_LE(prefix_length, 32u); - std::string domain_and_registry = - net::registry_controlled_domains::GetDomainAndRegistry( - origin, net::registry_controlled_domains::INCLUDE_PRIVATE_REGISTRIES); - - base::MD5Digest digest; - base::MD5Sum(domain_and_registry.data(), domain_and_registry.size(), &digest); - - for (size_t i = 0; i < base::size(digest.a); ++i) { - if (prefix_length >= 8) { - prefix_length -= 8; - continue; - } else { - // Determine the |prefix_length| most significant bits by calculating - // the 8 - |prefix_length| least significant bits and inverting the - // result. - digest.a[i] &= ~((1 << (8 - prefix_length)) - 1); - prefix_length = 0; - } - } - - return base::MD5DigestToBase16(digest).substr(0, 4); -} - -// Returns the URL on gstatic.com where the passwords spec file can be found -// that contains data for |hash_prefix|. -GURL GetUrlForRequirementsSpec(int version, const std::string& hash_prefix) { - return GURL(base::StringPrintf( - "https://www.gstatic.com/chrome/autofill/password_generation_specs/%d/%s", - version, hash_prefix.c_str())); -} - -} // namespace - -void PasswordRequirementsSpecFetcherImpl::Fetch( - GURL origin, - FetchCallback callback) { - DCHECK(origin.is_valid()); - VLOG(1) << "Fetching password requirements spec for " << origin; - - if (!url_loader_factory_) { - VLOG(1) << "No url_logger_factory_ available"; - TriggerCallback(std::move(callback), ResultCode::kErrorNoUrlLoader, - PasswordRequirementsSpec()); - return; - } - - if (!url_loader_factory_) { - TriggerCallback(std::move(callback), ResultCode::kErrorNoUrlLoader, - PasswordRequirementsSpec()); - return; - } - - if (!url_loader_factory_) { - TriggerCallback(std::move(callback), ResultCode::kErrorNoUrlLoader, - PasswordRequirementsSpec()); - return; - } - - if (!origin.is_valid() || origin.HostIsIPAddress() || - !origin.SchemeIsHTTPOrHTTPS()) { - VLOG(1) << "No valid origin"; - TriggerCallback(std::move(callback), ResultCode::kErrorInvalidOrigin, - PasswordRequirementsSpec()); - return; - } - - // Canonicalize away trailing periods in hostname. - while (!origin.host().empty() && origin.host().back() == '.') { - std::string new_host = origin.host().substr(0, origin.host().length() - 1); - url::Replacements<char> replacements; - replacements.SetHost(new_host.c_str(), - url::Component(0, new_host.length())); - origin = origin.ReplaceComponents(replacements); - } - - std::string hash_prefix = GetHashPrefix(origin, prefix_length_); - - // If a lookup is happening already, just register another callback. - auto iter = lookups_in_flight_.find(hash_prefix); - if (iter != lookups_in_flight_.end()) { - iter->second->callbacks.push_back( - std::make_pair(origin, std::move(callback))); - VLOG(1) << "Lookup already in flight"; - return; - } - - // Start another lookup otherwise. - auto lookup = std::make_unique<LookupInFlight>(); - lookup->callbacks.push_back(std::make_pair(origin, std::move(callback))); - lookup->start_of_request = base::TimeTicks::Now(); - - net::NetworkTrafficAnnotationTag traffic_annotation = - net::DefineNetworkTrafficAnnotation("password_requirements_spec_fetch", - R"( - semantics { - sender: "Password requirements specification fetcher" - description: - "Fetches the password requirements for a set of domains whose origin " - "hash starts with a certain prefix." - trigger: - "When the user triggers a password generation (this can happen by " - "just focussing a password field)." - data: - "The URL encodes a hash prefix from which it is not possible to " - "derive the original origin. No user information is sent." - destination: WEBSITE - } - policy { - cookies_allowed: NO - setting: "Unconditionally enabled." - policy_exception_justification: - "Not implemented, considered not useful." - })"); - auto resource_request = std::make_unique<network::ResourceRequest>(); - resource_request->url = GetUrlForRequirementsSpec(version_, hash_prefix); - resource_request->load_flags = net::LOAD_DO_NOT_SAVE_COOKIES | - net::LOAD_DO_NOT_SEND_COOKIES | - net::LOAD_DO_NOT_SEND_AUTH_DATA; - lookup->url_loader = network::SimpleURLLoader::Create( - std::move(resource_request), traffic_annotation); - lookup->url_loader->DownloadToStringOfUnboundedSizeUntilCrashAndDie( - url_loader_factory_.get(), - base::BindOnce(&PasswordRequirementsSpecFetcherImpl::OnFetchComplete, - base::Unretained(this), hash_prefix)); - - lookup->download_timer.Start( - FROM_HERE, base::TimeDelta::FromMilliseconds(timeout_), - base::BindRepeating(&PasswordRequirementsSpecFetcherImpl::OnFetchTimeout, - base::Unretained(this), hash_prefix)); - - lookups_in_flight_[hash_prefix] = std::move(lookup); -} - -void PasswordRequirementsSpecFetcherImpl::OnFetchComplete( - const std::string& hash_prefix, - std::unique_ptr<std::string> response_body) { - std::unique_ptr<LookupInFlight> lookup = RemoveLookupInFlight(hash_prefix); - - lookup->download_timer.Stop(); - UMA_HISTOGRAM_TIMES("PasswordManager.RequirementsSpecFetcher.NetworkDuration", - base::TimeTicks::Now() - lookup->start_of_request); - base::UmaHistogramSparse( - "PasswordManager.RequirementsSpecFetcher.NetErrorCode", - lookup->url_loader->NetError()); - if (lookup->url_loader->ResponseInfo() && - lookup->url_loader->ResponseInfo()->headers) { - base::UmaHistogramSparse( - "PasswordManager.RequirementsSpecFetcher.HttpResponseCode", - lookup->url_loader->ResponseInfo()->headers->response_code()); - } - - if (!response_body || lookup->url_loader->NetError() != net::Error::OK) { - VLOG(1) << "Fetch for " << hash_prefix << ": failed to fetch " - << lookup->url_loader->NetError(); - TriggerCallbackToAll(&lookup->callbacks, ResultCode::kErrorFailedToFetch, - PasswordRequirementsSpec()); - return; - } - - PasswordRequirementsShard shard; - if (!shard.ParseFromString(*response_body)) { - VLOG(1) << "Fetch for " << hash_prefix << ": failed to parse response"; - TriggerCallbackToAll(&lookup->callbacks, ResultCode::kErrorFailedToParse, - PasswordRequirementsSpec()); - return; - } - for (auto& callback_pair : lookup->callbacks) { - const GURL& origin = callback_pair.first; - FetchCallback& callback_function = callback_pair.second; - - // Search shard for matches for origin by looking up the (canonicalized) - // host name and then stripping domain prefixes until the eTLD+1 is reached. - DCHECK(!origin.HostIsIPAddress()); - // |host| is a std::string instead of StringPiece as the protbuf::Map - // implementation does not support StringPieces as parameters for find. - std::string host = origin.host(); - auto host_iter = shard.specs().find(host); - if (host_iter != shard.specs().end()) { - const PasswordRequirementsSpec& spec = host_iter->second; - VLOG(1) << "Found for " << host << ": " << spec; - TriggerCallback(std::move(callback_function), ResultCode::kFoundSpec, - spec); - continue; - } - - bool found_entry = false; - const std::string domain_and_registry = - net::registry_controlled_domains::GetDomainAndRegistry( - origin, - net::registry_controlled_domains::INCLUDE_PRIVATE_REGISTRIES); - while (host.length() > 0 && host != domain_and_registry) { - size_t pos = host.find('.'); - if (pos != std::string::npos) { // strip prefix - host = host.substr(pos + 1); - } else { - break; - } - // If an entry has ben found, exit with that. - auto it = shard.specs().find(host); - if (it != shard.specs().end()) { - const PasswordRequirementsSpec& spec = it->second; - found_entry = true; - VLOG(1) << "Found for " << host << ": " << spec; - TriggerCallback(std::move(callback_function), ResultCode::kFoundSpec, - spec); - break; - } - } - - if (!found_entry) { - VLOG(1) << "Found no entry for " << host; - TriggerCallback(std::move(callback_function), ResultCode::kFoundNoSpec, - PasswordRequirementsSpec()); - } - } -} - -void PasswordRequirementsSpecFetcherImpl::OnFetchTimeout( - const std::string& hash_prefix) { - std::unique_ptr<LookupInFlight> lookup = RemoveLookupInFlight(hash_prefix); - UMA_HISTOGRAM_TIMES("PasswordManager.RequirementsSpecFetcher.NetworkDuration", - base::TimeTicks::Now() - lookup->start_of_request); - TriggerCallbackToAll(&lookup->callbacks, ResultCode::kErrorTimeout, - PasswordRequirementsSpec()); -} - -void PasswordRequirementsSpecFetcherImpl::TriggerCallbackToAll( - std::list<std::pair<GURL, FetchCallback>>* callbacks, - ResultCode result, - const PasswordRequirementsSpec& spec) { - for (auto& callback_pair : *callbacks) { - TriggerCallback(std::move(callback_pair.second), result, spec); - } -} - -void PasswordRequirementsSpecFetcherImpl::TriggerCallback( - FetchCallback callback, - ResultCode result, - const PasswordRequirementsSpec& spec) { - UMA_HISTOGRAM_ENUMERATION("PasswordManager.RequirementsSpecFetcher.Result", - result); - std::move(callback).Run(spec); -} - -std::unique_ptr<PasswordRequirementsSpecFetcherImpl::LookupInFlight> -PasswordRequirementsSpecFetcherImpl::RemoveLookupInFlight( - const std::string& hash_prefix) { - DCHECK(lookups_in_flight_.find(hash_prefix) != lookups_in_flight_.end()); - std::unique_ptr<LookupInFlight> lookup; - std::swap(lookup, lookups_in_flight_[hash_prefix]); - lookups_in_flight_.erase(hash_prefix); - return lookup; -} - -} // namespace autofill diff --git a/chromium/components/autofill/core/browser/password_requirements_spec_fetcher_impl.h b/chromium/components/autofill/core/browser/password_requirements_spec_fetcher_impl.h deleted file mode 100644 index 3d22b0e8af9..00000000000 --- a/chromium/components/autofill/core/browser/password_requirements_spec_fetcher_impl.h +++ /dev/null @@ -1,143 +0,0 @@ -// Copyright 2018 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef COMPONENTS_AUTOFILL_CORE_BROWSER_PASSWORD_REQUIREMENTS_SPEC_FETCHER_IMPL_H_ -#define COMPONENTS_AUTOFILL_CORE_BROWSER_PASSWORD_REQUIREMENTS_SPEC_FETCHER_IMPL_H_ - -#include <list> -#include <map> -#include <memory> -#include <string> -#include <utility> - -#include "base/callback.h" -#include "base/macros.h" -#include "base/timer/timer.h" -#include "components/autofill/core/browser/password_requirements_spec_fetcher.h" -#include "url/gurl.h" - -namespace network { -class SharedURLLoaderFactory; -class SimpleURLLoader; -} // namespace network - -namespace autofill { - -class PasswordRequirementsSpec; - -// A concrete implementation for PasswordRequirementsSpecFetcher that talks -// to the network. -class PasswordRequirementsSpecFetcherImpl - : public PasswordRequirementsSpecFetcher { - public: - // This enum is used in histograms. Do not change or reuse values. - enum class ResultCode { - // Fetched spec file, parsed it, but found no entry for the origin. - kFoundNoSpec = 0, - // Fetched spec file, parsed it and found an entry. - kFoundSpec = 1, - // The origin is an IP address, not HTTP/HTTPS, or not a valid URL. - kErrorInvalidOrigin = 2, - // Server responded with an empty document or an error code. - kErrorFailedToFetch = 3, - // Server timed out. - kErrorTimeout = 4, - // Server responded with a document but it could not be parsed. - kErrorFailedToParse = 5, - // No URL loader configured for the PasswordRequirementsSpecFetcher. - kErrorNoUrlLoader = 6, - kMaxValue = kErrorNoUrlLoader, - }; - - // See the member variables for explanations of these parameters. - PasswordRequirementsSpecFetcherImpl( - scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory, - int version, - size_t prefix_length, - int timeout); - ~PasswordRequirementsSpecFetcherImpl() override; - - // Implementation for PasswordRequirementsSpecFetcher: - void Fetch(GURL origin, FetchCallback callback) override; - - private: - // This structure bundles all data that are associated to a network request - // for a file with a specific hash prefix. - struct LookupInFlight { - LookupInFlight(); - ~LookupInFlight(); - - // Callbacks to be called if the network request resolves or is aborted. - // The GURL represents the origin due to which a spec was fetched. - // Used a std::list instead of std::vector to grow this cheaply. - std::list<std::pair<GURL, FetchCallback>> callbacks; - - // Timer to kill pending downloads after |timeout_|. - base::OneShotTimer download_timer; - - std::unique_ptr<network::SimpleURLLoader> url_loader; - - // Time when the network request is started. - base::TimeTicks start_of_request; - - private: - DISALLOW_COPY_AND_ASSIGN(LookupInFlight); - }; - - // These are the two ways how a network request can end. The functions remove - // the entry corresponding to |hash_prefix| out of |lookups_in_flight_| as - // their first order of business. - void OnFetchComplete(const std::string& hash_prefix, - std::unique_ptr<std::string> response_body); - void OnFetchTimeout(const std::string& hash_prefix); - - // Calls all |callbacks| in order. Note that these callbacks are OnceCallback - // instances. Therefore, entries are reset after this function returns. - void TriggerCallbackToAll( - std::list<std::pair<GURL, FetchCallback>>* callbacks, - ResultCode result, - const PasswordRequirementsSpec& spec); - - // Calls the |callback| with the specific data and records some metrics. - void TriggerCallback(FetchCallback callback, - ResultCode result, - const PasswordRequirementsSpec& spec); - - std::unique_ptr<LookupInFlight> RemoveLookupInFlight( - const std::string& hash_prefix); - - scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory_; - - // A version counter for requirements specs. If data changes on the server, - // a new version number is pushed out to prevent that clients continue - // using old cached data. This allows setting the HTTP caching expiration to - // infinity. - int version_; - - // The fetcher determines the URL of the spec file by first hashing the eTLD+1 - // of |origin| and then taking the first |prefix_length_| bits of the hash - // value as part of the file name. (See the code for details.) - // |prefix_length_| should always be <= 32 as filenames are limited to the - // first 4 bytes of the hash prefix. - size_t prefix_length_; - - // Timeout in milliseconds after which any ongoing fetch operation is - // canceled. - int timeout_; - - // Data about network requests in flight. - // The key is the name of the file being fetched without the common URL prefix - // (e.g. "0000"). The value contains callbacks that should process the result - // and a timer to cancel the lookup after some time. - // The invariant of |lookups_in_flight_| is that entries exist from the - // time of starting the network request until receiving the response or a - // timeout. - std::map<std::string, std::unique_ptr<LookupInFlight>> lookups_in_flight_; - - DISALLOW_COPY_AND_ASSIGN(PasswordRequirementsSpecFetcherImpl); -}; - -} // namespace autofill - -#endif // COMPONENTS_AUTOFILL_CORE_BROWSER_PASSWORD_REQUIREMENTS_SPEC_FETCHER_IMPL_H_ diff --git a/chromium/components/autofill/core/browser/password_requirements_spec_fetcher_unittest.cc b/chromium/components/autofill/core/browser/password_requirements_spec_fetcher_unittest.cc deleted file mode 100644 index 3f7bd199b1f..00000000000 --- a/chromium/components/autofill/core/browser/password_requirements_spec_fetcher_unittest.cc +++ /dev/null @@ -1,343 +0,0 @@ -// Copyright 2018 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "components/autofill/core/browser/password_requirements_spec_fetcher_impl.h" - -#include "base/logging.h" -#include "base/test/bind_test_util.h" -#include "base/test/metrics/histogram_tester.h" -#include "base/test/scoped_task_environment.h" -#include "components/autofill/core/browser/proto/password_requirements.pb.h" -#include "components/autofill/core/browser/proto/password_requirements_shard.pb.h" -#include "services/network/public/cpp/weak_wrapper_shared_url_loader_factory.h" -#include "services/network/test/test_url_loader_factory.h" -#include "testing/gtest/include/gtest/gtest.h" - -namespace autofill { - -namespace { - -// URL prefix for spec requests. -#define SERVER_URL \ - "https://www.gstatic.com/chrome/autofill/password_generation_specs/" - -TEST(PasswordRequirementsSpecFetcherTest, FetchData) { - using ResultCode = PasswordRequirementsSpecFetcherImpl::ResultCode; - - // An empty spec is returned for all error cases (time outs, server responding - // with anything but HTTP_OK). - PasswordRequirementsSpec empty_spec; - - PasswordRequirementsSpec success_spec_for_example_com; - success_spec_for_example_com.set_min_length(17); - PasswordRequirementsSpec success_spec_for_m_example_com; - success_spec_for_m_example_com.set_min_length(18); - PasswordRequirementsSpec spec_for_ip; - success_spec_for_m_example_com.set_min_length(19); - PasswordRequirementsSpec success_spec_for_uber_example_com; - success_spec_for_uber_example_com.set_min_length(20); - - std::string serialized_shard; - PasswordRequirementsShard shard; - (*shard.mutable_specs())["example.com"] = success_spec_for_example_com; - (*shard.mutable_specs())["m.example.com"] = success_spec_for_m_example_com; - // This spec is stored in the buffer but is not expected to be processed. - // Only real hostnames are supposed to be parsed. - (*shard.mutable_specs())["192.168.1.1"] = spec_for_ip; - // Punycoded entry. - (*shard.mutable_specs())["xn--ber-example-shb.com"] = - success_spec_for_uber_example_com; - shard.SerializeToString(&serialized_shard); - - // If this magic timeout value is set, simulate a timeout. - const int kMagicTimeout = 10; - - struct { - // Name of the test for log output. - const char* test_name; - - // Origin for which the spec is fetched. - const char* origin; - - // Current configuration that would be set via Finch. - int generation = 1; - int prefix_length = 32; - int timeout = 1000; - - // Handler for the spec requests. - const char* requested_url; - std::string response_content; - net::HttpStatusCode response_status = net::HTTP_OK; - - // Expected spec. - PasswordRequirementsSpec* expected_spec; - ResultCode expected_result; - } tests[] = { - { - .test_name = "Business as usual", - .origin = "https://www.example.com", - // See echo -n example.com | md5sum | cut -b 1-4 - .requested_url = SERVER_URL "1/5aba", - .response_content = serialized_shard, - .expected_spec = &success_spec_for_example_com, - .expected_result = ResultCode::kFoundSpec, - }, - { - .test_name = "Parts before the eTLD+1 don't matter", - // m.example.com instead of www.example.com creates the same hash - // prefix. - .origin = "https://m.example.com", - .requested_url = SERVER_URL "1/5aba", - .response_content = serialized_shard, - // But shard contains a special entry for m.example.com, so verify - // that the more specific element is returned. - .expected_spec = &success_spec_for_m_example_com, - .expected_result = ResultCode::kFoundSpec, - }, - { - .test_name = "The generation is encoded in the url", - .origin = "https://www.example.com", - // Here the test differs from the default: - .generation = 2, - .requested_url = SERVER_URL "2/5aba", - .response_content = serialized_shard, - .expected_spec = &success_spec_for_example_com, - .expected_result = ResultCode::kFoundSpec, - }, - { - .test_name = "Shorter prefixes are reflected in the URL", - .origin = "https://m.example.com", - // The prefix "5abc" starts with 0b01011010. If the prefix is limited - // to the first 3 bits, b0100 = 0x4 remains and the rest is zeroed - // out. - .prefix_length = 3, - .requested_url = SERVER_URL "1/4000", - .response_content = serialized_shard, - .expected_spec = &success_spec_for_m_example_com, - .expected_result = ResultCode::kFoundSpec, - }, - { - .test_name = "Simulate a 404 response", - .origin = "https://www.example.com", - .requested_url = SERVER_URL "1/5aba", - .response_content = "Not found", - // If a file is not found on the server, the spec should be empty. - .response_status = net::HTTP_NOT_FOUND, - .expected_spec = &empty_spec, - .expected_result = ResultCode::kErrorFailedToFetch, - }, - { - .test_name = "Simulate a timeout", - .origin = "https://www.example.com", - // This simulates a timeout. - .timeout = kMagicTimeout, - // This makes sure that the server does not respond by itself as - // TestURLLoaderFactory reacts as if a response has been added to - // a URL. - .requested_url = SERVER_URL "dont_respond", - .response_content = serialized_shard, - .expected_spec = &empty_spec, - .expected_result = ResultCode::kErrorTimeout, - }, - { - .test_name = "Zero prefix", - .origin = "https://www.example.com", - // A zero prefix will be the hard-coded Finch default and should work. - .prefix_length = 0, - .requested_url = SERVER_URL "1/0000", - .response_content = serialized_shard, - .expected_spec = &success_spec_for_example_com, - .expected_result = ResultCode::kFoundSpec, - }, - { - .test_name = "IP addresses give the empty spec", - .origin = "http://192.168.1.1/", - // By setting the prefix to 0, the URL of the shard is predefined, - // but actually, not network request should be sent as password - // requirements are not supported for IP addresses. - .prefix_length = 0, - .requested_url = SERVER_URL "0/0000", - .response_content = serialized_shard, - .expected_spec = &empty_spec, - .expected_result = ResultCode::kErrorInvalidOrigin, - }, - { - .test_name = "IP addresses give the empty spec", - .origin = "chrome://settings", - // By setting the prefix to 0, the URL of the shard is predefined, - // but actually, not network request should be sent as password - // requirements are not supported the chrome:// scheme. - .prefix_length = 0, - .requested_url = SERVER_URL "0/0000", - .response_content = serialized_shard, - .expected_spec = &empty_spec, - .expected_result = ResultCode::kErrorInvalidOrigin, - }, - { - .test_name = "Trailing period is normalized", - // Despite the trailing '.', everything is like for example.com - .origin = "https://www.example.com.", - .requested_url = SERVER_URL "1/5aba", - .response_content = serialized_shard, - .expected_spec = &success_spec_for_example_com, - .expected_result = ResultCode::kFoundSpec, - }, - { - .test_name = "Test punycoding", - .origin = "https://www.über-example.com", - // See echo -n xn--ber-example-shb.com | md5sum | cut -b 1-4 - .requested_url = SERVER_URL "1/e5db", - .response_content = serialized_shard, - .expected_spec = &success_spec_for_uber_example_com, - .expected_result = ResultCode::kFoundSpec, - }, - { - .test_name = "Test no entry", - .origin = "https://www.no-entry.com", - // See echo -n no-entry.com | md5sum | cut -b 1-4 - .requested_url = SERVER_URL "1/7579", - .response_content = serialized_shard, - .expected_spec = &empty_spec, - .expected_result = ResultCode::kFoundNoSpec, - }, - }; - - for (const auto& test : tests) { - SCOPED_TRACE(test.test_name); - base::HistogramTester histogram_tester; - - base::test::ScopedTaskEnvironment environment( - base::test::ScopedTaskEnvironment::MainThreadType::MOCK_TIME); - network::TestURLLoaderFactory loader_factory; - loader_factory.AddResponse(test.requested_url, test.response_content, - test.response_status); - - // Data to be collected from the callback. - bool callback_called = false; - PasswordRequirementsSpec returned_spec; - - // Trigger the network request and record data of the callback. - PasswordRequirementsSpecFetcherImpl fetcher( - base::MakeRefCounted<network::WeakWrapperSharedURLLoaderFactory>( - &loader_factory), - test.generation, test.prefix_length, test.timeout); - auto callback = - base::BindLambdaForTesting([&](const PasswordRequirementsSpec& spec) { - callback_called = true; - returned_spec = spec; - }); - fetcher.Fetch(GURL(test.origin), callback); - - environment.RunUntilIdle(); - - if (test.timeout == kMagicTimeout) { - // Make sure that the request takes longer than the timeout and gets - // killed by the timer. - environment.FastForwardBy( - base::TimeDelta::FromMilliseconds(2 * kMagicTimeout)); - environment.RunUntilIdle(); - } - - ASSERT_TRUE(callback_called); - EXPECT_EQ(test.expected_spec->SerializeAsString(), - returned_spec.SerializeAsString()); - histogram_tester.ExpectUniqueSample( - "PasswordManager.RequirementsSpecFetcher.Result", test.expected_result, - 1u); - } -} - -// Test two requests to fetch the same shard before the network responded. -// In this case, only one network request should be sent. -TEST(PasswordRequirementsSpecFetcherTest, FetchDataInterleaved) { - for (bool simulate_timeout : {false, true}) { - SCOPED_TRACE(::testing::Message() - << "Simulate timeout? " << simulate_timeout); - - // Set up the data that will be served. - std::string serialized_shard; - PasswordRequirementsShard shard; - (*shard.mutable_specs())["a.com"].set_min_length(17); - (*shard.mutable_specs())["b.com"].set_min_length(18); - shard.SerializeToString(&serialized_shard); - - base::test::ScopedTaskEnvironment environment( - base::test::ScopedTaskEnvironment::MainThreadType::MOCK_TIME); - network::TestURLLoaderFactory loader_factory; - - // Target into which data will be written by the callback. - PasswordRequirementsSpec spec_for_a; - PasswordRequirementsSpec spec_for_b; - // Set some values to see whether they get overridden by the callback. - spec_for_a.set_min_length(1); - spec_for_b.set_min_length(1); - - const int kVersion = 1; - // With a prefix length of 0, we guarantee that only one shard exists - // and therefore that the requests go to the same endpoint and can be - // unified into one network request. - const size_t kPrefixLength = 0; - const int kTimeout = 1000; - PasswordRequirementsSpecFetcherImpl fetcher( - base::MakeRefCounted<network::WeakWrapperSharedURLLoaderFactory>( - &loader_factory), - kVersion, kPrefixLength, kTimeout); - - fetcher.Fetch( - GURL("http://a.com"), - base::BindLambdaForTesting( - [&](const PasswordRequirementsSpec& spec) { spec_for_a = spec; })); - fetcher.Fetch( - GURL("http://b.com"), - base::BindLambdaForTesting( - [&](const PasswordRequirementsSpec& spec) { spec_for_b = spec; })); - - EXPECT_EQ(1, loader_factory.NumPending()); - - if (simulate_timeout) { - environment.FastForwardBy( - base::TimeDelta::FromMilliseconds(2 * kTimeout)); - environment.RunUntilIdle(); - EXPECT_FALSE(spec_for_a.has_min_length()); - EXPECT_FALSE(spec_for_b.has_min_length()); - } else { - loader_factory.AddResponse(SERVER_URL "1/0000", serialized_shard, - net::HTTP_OK); - environment.RunUntilIdle(); - - EXPECT_EQ(17u, spec_for_a.min_length()); - EXPECT_EQ(18u, spec_for_b.min_length()); - } - } -} - -// In case of incognito mode, we won't have a URL loader factory. -// Test that an empty spec is returned by the spec fetcher in this case. -TEST(PasswordRequirementsSpecFetcherTest, FetchDataWithoutURLLoaderFactory) { - base::test::ScopedTaskEnvironment environment; - - // Target into which data will be written by the callback. - PasswordRequirementsSpec received_spec; - // Set some values to see whether they get overridden by the callback. - received_spec.set_min_length(1); - - const int kVersion = 1; - const size_t kPrefixLength = 0; - const int kTimeout = 1000; - PasswordRequirementsSpecFetcherImpl fetcher(nullptr, kVersion, kPrefixLength, - kTimeout); - - fetcher.Fetch( - GURL("http://a.com"), - base::BindLambdaForTesting( - [&](const PasswordRequirementsSpec& spec) { received_spec = spec; })); - environment.RunUntilIdle(); - EXPECT_FALSE(received_spec.has_min_length()); -} - -#undef SERVER_URL - -} // namespace - -} // namespace autofill diff --git a/chromium/components/autofill/core/browser/password_requirements_spec_printer.cc b/chromium/components/autofill/core/browser/password_requirements_spec_printer.cc deleted file mode 100644 index dd7049d34da..00000000000 --- a/chromium/components/autofill/core/browser/password_requirements_spec_printer.cc +++ /dev/null @@ -1,48 +0,0 @@ -// Copyright 2018 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "components/autofill/core/browser/password_requirements_spec_printer.h" - -namespace autofill { - -std::ostream& operator<<( - std::ostream& out, - const PasswordRequirementsSpec::CharacterClass& character_class) { - out << "{"; - if (character_class.has_character_set()) - out << "character_set: \"" << character_class.character_set() << "\", "; - if (character_class.has_min()) - out << "min: " << character_class.min() << ", "; - if (character_class.has_max()) - out << "max: " << character_class.max() << ", "; - out << "}"; - return out; -} - -std::ostream& operator<<(std::ostream& out, - const PasswordRequirementsSpec& spec) { - out << "{"; - if (spec.has_priority()) - out << "priority: " << spec.priority() << ", "; - if (spec.has_spec_version()) - out << "spec_version: " << spec.spec_version() << ", "; - if (spec.has_min_length()) - out << "min_length: " << spec.min_length() << ", "; - if (spec.has_max_length()) - out << "max_length: " << spec.max_length() << ", "; - if (spec.has_lower_case()) - out << "lower_case: " << spec.lower_case() << ", "; - if (spec.has_upper_case()) - out << "upper_case: " << spec.upper_case() << ", "; - if (spec.has_alphabetic()) - out << "alphabetic: " << spec.alphabetic() << ", "; - if (spec.has_numeric()) - out << "numeric: " << spec.alphabetic() << ", "; - if (spec.has_symbols()) - out << "symbols: " << spec.symbols() << ", "; - out << "}"; - return out; -} - -} // namespace autofill diff --git a/chromium/components/autofill/core/browser/password_requirements_spec_printer.h b/chromium/components/autofill/core/browser/password_requirements_spec_printer.h deleted file mode 100644 index 81169340bce..00000000000 --- a/chromium/components/autofill/core/browser/password_requirements_spec_printer.h +++ /dev/null @@ -1,23 +0,0 @@ -// Copyright 2018 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef COMPONENTS_AUTOFILL_CORE_BROWSER_PASSWORD_REQUIREMENTS_SPEC_PRINTER_H_ -#define COMPONENTS_AUTOFILL_CORE_BROWSER_PASSWORD_REQUIREMENTS_SPEC_PRINTER_H_ - -#include <ostream> - -#include "components/autofill/core/browser/proto/password_requirements.pb.h" - -namespace autofill { - -std::ostream& operator<<( - std::ostream& out, - const PasswordRequirementsSpec::CharacterClass& character_class); - -std::ostream& operator<<(std::ostream& out, - const PasswordRequirementsSpec& spec); - -} // namespace autofill - -#endif // COMPONENTS_AUTOFILL_CORE_BROWSER_PASSWORD_REQUIREMENTS_SPEC_PRINTER_H_ diff --git a/chromium/components/autofill/core/browser/payments/OWNERS b/chromium/components/autofill/core/browser/payments/OWNERS new file mode 100644 index 00000000000..c3fbe351b77 --- /dev/null +++ b/chromium/components/autofill/core/browser/payments/OWNERS @@ -0,0 +1 @@ +jsaul@google.com diff --git a/chromium/components/autofill/core/browser/account_info_getter.h b/chromium/components/autofill/core/browser/payments/account_info_getter.h index 44fa238ebec..42bf2fe3fbb 100644 --- a/chromium/components/autofill/core/browser/account_info_getter.h +++ b/chromium/components/autofill/core/browser/payments/account_info_getter.h @@ -2,8 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#ifndef COMPONENTS_AUTOFILL_CORE_BROWSER_ACCOUNT_INFO_GETTER_H_ -#define COMPONENTS_AUTOFILL_CORE_BROWSER_ACCOUNT_INFO_GETTER_H_ +#ifndef COMPONENTS_AUTOFILL_CORE_BROWSER_PAYMENTS_ACCOUNT_INFO_GETTER_H_ +#define COMPONENTS_AUTOFILL_CORE_BROWSER_PAYMENTS_ACCOUNT_INFO_GETTER_H_ #include <string> @@ -30,4 +30,4 @@ class AccountInfoGetter { } // namespace autofill -#endif // COMPONENTS_AUTOFILL_CORE_BROWSER_ACCOUNT_INFO_GETTER_H_ +#endif // COMPONENTS_AUTOFILL_CORE_BROWSER_PAYMENTS_ACCOUNT_INFO_GETTER_H_ diff --git a/chromium/components/autofill/core/browser/autofill_credit_card_filling_infobar_delegate_mobile.cc b/chromium/components/autofill/core/browser/payments/autofill_credit_card_filling_infobar_delegate_mobile.cc index fe4a4be83f1..aadf087dd49 100644 --- a/chromium/components/autofill/core/browser/autofill_credit_card_filling_infobar_delegate_mobile.cc +++ b/chromium/components/autofill/core/browser/payments/autofill_credit_card_filling_infobar_delegate_mobile.cc @@ -2,8 +2,9 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "components/autofill/core/browser/autofill_credit_card_filling_infobar_delegate_mobile.h" +#include "components/autofill/core/browser/payments/autofill_credit_card_filling_infobar_delegate_mobile.h" +#include "build/build_config.h" #include "components/autofill/core/browser/credit_card.h" #include "components/autofill/core/common/autofill_constants.h" #include "components/autofill/core/common/autofill_features.h" diff --git a/chromium/components/autofill/core/browser/autofill_credit_card_filling_infobar_delegate_mobile.h b/chromium/components/autofill/core/browser/payments/autofill_credit_card_filling_infobar_delegate_mobile.h index c7b8172a5c3..721af6e2491 100644 --- a/chromium/components/autofill/core/browser/autofill_credit_card_filling_infobar_delegate_mobile.h +++ b/chromium/components/autofill/core/browser/payments/autofill_credit_card_filling_infobar_delegate_mobile.h @@ -2,8 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#ifndef COMPONENTS_AUTOFILL_CORE_BROWSER_AUTOFILL_CREDIT_CARD_FILLING_INFOBAR_DELEGATE_MOBILE_H_ -#define COMPONENTS_AUTOFILL_CORE_BROWSER_AUTOFILL_CREDIT_CARD_FILLING_INFOBAR_DELEGATE_MOBILE_H_ +#ifndef COMPONENTS_AUTOFILL_CORE_BROWSER_PAYMENTS_AUTOFILL_CREDIT_CARD_FILLING_INFOBAR_DELEGATE_MOBILE_H_ +#define COMPONENTS_AUTOFILL_CORE_BROWSER_PAYMENTS_AUTOFILL_CREDIT_CARD_FILLING_INFOBAR_DELEGATE_MOBILE_H_ #include <memory> @@ -67,4 +67,4 @@ class AutofillCreditCardFillingInfoBarDelegateMobile } // namespace autofill -#endif // COMPONENTS_AUTOFILL_CORE_BROWSER_AUTOFILL_CREDIT_CARD_FILLING_INFOBAR_DELEGATE_MOBILE_H_ +#endif // COMPONENTS_AUTOFILL_CORE_BROWSER_PAYMENTS_AUTOFILL_CREDIT_CARD_FILLING_INFOBAR_DELEGATE_MOBILE_H_ diff --git a/chromium/components/autofill/core/browser/autofill_save_card_infobar_delegate_mobile.cc b/chromium/components/autofill/core/browser/payments/autofill_save_card_infobar_delegate_mobile.cc index 22fc50b9595..dda1712233f 100644 --- a/chromium/components/autofill/core/browser/autofill_save_card_infobar_delegate_mobile.cc +++ b/chromium/components/autofill/core/browser/payments/autofill_save_card_infobar_delegate_mobile.cc @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "components/autofill/core/browser/autofill_save_card_infobar_delegate_mobile.h" +#include "components/autofill/core/browser/payments/autofill_save_card_infobar_delegate_mobile.h" #include <utility> @@ -11,7 +11,7 @@ #include "base/values.h" #include "components/autofill/core/browser/autofill_experiments.h" #include "components/autofill/core/browser/credit_card.h" -#include "components/autofill/core/browser/legal_message_line.h" +#include "components/autofill/core/browser/payments/legal_message_line.h" #include "components/autofill/core/common/autofill_constants.h" #include "components/autofill/core/common/autofill_features.h" #include "components/autofill/core/common/autofill_prefs.h" diff --git a/chromium/components/autofill/core/browser/autofill_save_card_infobar_delegate_mobile.h b/chromium/components/autofill/core/browser/payments/autofill_save_card_infobar_delegate_mobile.h index a99817a0ec5..62742f82744 100644 --- a/chromium/components/autofill/core/browser/autofill_save_card_infobar_delegate_mobile.h +++ b/chromium/components/autofill/core/browser/payments/autofill_save_card_infobar_delegate_mobile.h @@ -2,8 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#ifndef COMPONENTS_AUTOFILL_CORE_BROWSER_AUTOFILL_SAVE_CARD_INFOBAR_DELEGATE_MOBILE_H_ -#define COMPONENTS_AUTOFILL_CORE_BROWSER_AUTOFILL_SAVE_CARD_INFOBAR_DELEGATE_MOBILE_H_ +#ifndef COMPONENTS_AUTOFILL_CORE_BROWSER_PAYMENTS_AUTOFILL_SAVE_CARD_INFOBAR_DELEGATE_MOBILE_H_ +#define COMPONENTS_AUTOFILL_CORE_BROWSER_PAYMENTS_AUTOFILL_SAVE_CARD_INFOBAR_DELEGATE_MOBILE_H_ #include <memory> @@ -12,7 +12,7 @@ #include "base/strings/string16.h" #include "components/autofill/core/browser/autofill_client.h" #include "components/autofill/core/browser/autofill_metrics.h" -#include "components/autofill/core/browser/legal_message_line.h" +#include "components/autofill/core/browser/payments/legal_message_line.h" #include "components/infobars/core/confirm_infobar_delegate.h" class PrefService; @@ -127,4 +127,4 @@ class AutofillSaveCardInfoBarDelegateMobile : public ConfirmInfoBarDelegate { } // namespace autofill -#endif // COMPONENTS_AUTOFILL_CORE_BROWSER_AUTOFILL_SAVE_CARD_INFOBAR_DELEGATE_MOBILE_H_ +#endif // COMPONENTS_AUTOFILL_CORE_BROWSER_PAYMENTS_AUTOFILL_SAVE_CARD_INFOBAR_DELEGATE_MOBILE_H_ diff --git a/chromium/components/autofill/core/browser/autofill_save_card_infobar_mobile.h b/chromium/components/autofill/core/browser/payments/autofill_save_card_infobar_mobile.h index 995bc7d9e08..969131b3a1e 100644 --- a/chromium/components/autofill/core/browser/autofill_save_card_infobar_mobile.h +++ b/chromium/components/autofill/core/browser/payments/autofill_save_card_infobar_mobile.h @@ -2,8 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#ifndef COMPONENTS_AUTOFILL_CORE_BROWSER_AUTOFILL_SAVE_CARD_INFOBAR_MOBILE_H_ -#define COMPONENTS_AUTOFILL_CORE_BROWSER_AUTOFILL_SAVE_CARD_INFOBAR_MOBILE_H_ +#ifndef COMPONENTS_AUTOFILL_CORE_BROWSER_PAYMENTS_AUTOFILL_SAVE_CARD_INFOBAR_MOBILE_H_ +#define COMPONENTS_AUTOFILL_CORE_BROWSER_PAYMENTS_AUTOFILL_SAVE_CARD_INFOBAR_MOBILE_H_ #include <memory> @@ -21,4 +21,4 @@ std::unique_ptr<infobars::InfoBar> CreateSaveCardInfoBarMobile( } // namespace autofill -#endif // COMPONENTS_AUTOFILL_CORE_BROWSER_AUTOFILL_SAVE_CARD_INFOBAR_MOBILE_H_ +#endif // COMPONENTS_AUTOFILL_CORE_BROWSER_PAYMENTS_AUTOFILL_SAVE_CARD_INFOBAR_MOBILE_H_ diff --git a/chromium/components/autofill/core/browser/autofill_wallet_data_type_controller.cc b/chromium/components/autofill/core/browser/payments/autofill_wallet_data_type_controller.cc index 7ad8b87e824..576d1bbf07b 100644 --- a/chromium/components/autofill/core/browser/autofill_wallet_data_type_controller.cc +++ b/chromium/components/autofill/core/browser/payments/autofill_wallet_data_type_controller.cc @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "components/autofill/core/browser/autofill_wallet_data_type_controller.h" +#include "components/autofill/core/browser/payments/autofill_wallet_data_type_controller.h" #include <utility> @@ -21,8 +21,8 @@ namespace browser_sync { AutofillWalletDataTypeController::AutofillWalletDataTypeController( syncer::ModelType type, - scoped_refptr<base::SingleThreadTaskRunner> db_thread, - const base::Closure& dump_stack, + scoped_refptr<base::SequencedTaskRunner> db_thread, + const base::RepeatingClosure& dump_stack, syncer::SyncService* sync_service, syncer::SyncClient* sync_client, const PersonalDataManagerProvider& pdm_provider, @@ -56,10 +56,8 @@ bool AutofillWalletDataTypeController::StartModels() { DCHECK(CalledOnValidThread()); DCHECK_EQ(state(), MODEL_STARTING); - if (!IsEnabled()) { - DisableForPolicy(); + if (!IsEnabled()) return false; - } if (!web_data_service_) return false; @@ -69,8 +67,8 @@ bool AutofillWalletDataTypeController::StartModels() { if (!callback_registered_) { web_data_service_->RegisterDBLoadedCallback( - base::Bind(&AutofillWalletDataTypeController::OnModelLoaded, - base::AsWeakPtr(this))); + base::BindRepeating(&AutofillWalletDataTypeController::OnModelLoaded, + base::AsWeakPtr(this))); callback_registered_ = true; } @@ -123,13 +121,7 @@ void AutofillWalletDataTypeController::OnUserPrefChanged() { return; // No change to sync state. currently_enabled_ = new_enabled; - if (currently_enabled_) { - // The preference was just enabled. Trigger a reconfiguration. This will do - // nothing if the type isn't preferred. - sync_service()->ReenableDatatype(type()); - } else { - DisableForPolicy(); - } + sync_service()->ReadyForStartChanged(type()); } bool AutofillWalletDataTypeController::IsEnabled() { @@ -141,12 +133,5 @@ bool AutofillWalletDataTypeController::IsEnabled() { sync_client()->GetPrefService()->GetBoolean( autofill::prefs::kAutofillCreditCardEnabled); } -void AutofillWalletDataTypeController::DisableForPolicy() { - if (state() != NOT_RUNNING && state() != STOPPING) { - CreateErrorHandler()->OnUnrecoverableError( - syncer::SyncError(FROM_HERE, syncer::SyncError::DATATYPE_POLICY_ERROR, - "Wallet syncing is disabled by policy.", type())); - } -} } // namespace browser_sync diff --git a/chromium/components/autofill/core/browser/autofill_wallet_data_type_controller.h b/chromium/components/autofill/core/browser/payments/autofill_wallet_data_type_controller.h index be0e0fff83a..e6a1b54381c 100644 --- a/chromium/components/autofill/core/browser/autofill_wallet_data_type_controller.h +++ b/chromium/components/autofill/core/browser/payments/autofill_wallet_data_type_controller.h @@ -2,12 +2,12 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#ifndef COMPONENTS_AUTOFILL_CORE_BROWSER_AUTOFILL_WALLET_DATA_TYPE_CONTROLLER_H_ -#define COMPONENTS_AUTOFILL_CORE_BROWSER_AUTOFILL_WALLET_DATA_TYPE_CONTROLLER_H_ +#ifndef COMPONENTS_AUTOFILL_CORE_BROWSER_PAYMENTS_AUTOFILL_WALLET_DATA_TYPE_CONTROLLER_H_ +#define COMPONENTS_AUTOFILL_CORE_BROWSER_PAYMENTS_AUTOFILL_WALLET_DATA_TYPE_CONTROLLER_H_ #include "base/callback.h" #include "base/macros.h" -#include "base/single_thread_task_runner.h" +#include "base/sequenced_task_runner.h" #include "components/prefs/pref_change_registrar.h" #include "components/sync/driver/async_directory_type_controller.h" @@ -34,29 +34,26 @@ class AutofillWalletDataTypeController // |dump_stack| is called when an unrecoverable error occurs. AutofillWalletDataTypeController( syncer::ModelType type, - scoped_refptr<base::SingleThreadTaskRunner> db_thread, - const base::Closure& dump_stack, + scoped_refptr<base::SequencedTaskRunner> db_thread, + const base::RepeatingClosure& dump_stack, syncer::SyncService* sync_service, syncer::SyncClient* sync_client, const PersonalDataManagerProvider& pdm_provider, const scoped_refptr<autofill::AutofillWebDataService>& web_data_service); ~AutofillWalletDataTypeController() override; - private: // AsyncDirectoryTypeController implementation. bool StartModels() override; void StopModels() override; bool ReadyForStart() const override; + private: // Callback for changes to the autofill pref. void OnUserPrefChanged(); // Returns true if the prefs are set such that wallet sync should be enabled. bool IsEnabled(); - // Report an error (which will stop the datatype asynchronously). - void DisableForPolicy(); - // Callback that allows accessing PersonalDataManager lazily. const PersonalDataManagerProvider pdm_provider_; @@ -78,4 +75,4 @@ class AutofillWalletDataTypeController } // namespace browser_sync -#endif // COMPONENTS_AUTOFILL_CORE_BROWSER_AUTOFILL_WALLET_DATA_TYPE_CONTROLLER_H_ +#endif // COMPONENTS_AUTOFILL_CORE_BROWSER_PAYMENTS_AUTOFILL_WALLET_DATA_TYPE_CONTROLLER_H_ diff --git a/chromium/components/autofill/core/browser/autofill_wallet_data_type_controller_unittest.cc b/chromium/components/autofill/core/browser/payments/autofill_wallet_data_type_controller_unittest.cc index c8a98aff248..40d771670df 100644 --- a/chromium/components/autofill/core/browser/autofill_wallet_data_type_controller_unittest.cc +++ b/chromium/components/autofill/core/browser/payments/autofill_wallet_data_type_controller_unittest.cc @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "components/autofill/core/browser/autofill_wallet_data_type_controller.h" +#include "components/autofill/core/browser/payments/autofill_wallet_data_type_controller.h" #include <memory> @@ -24,7 +24,7 @@ #include "components/sync/driver/configure_context.h" #include "components/sync/driver/data_type_controller_mock.h" #include "components/sync/driver/fake_generic_change_processor.h" -#include "components/sync/driver/fake_sync_service.h" +#include "components/sync/driver/mock_sync_service.h" #include "components/sync/driver/sync_client_mock.h" #include "components/sync/driver/sync_service.h" #include "components/sync/model/fake_syncable_service.h" @@ -47,7 +47,7 @@ class FakeWebDataService : public AutofillWebDataService { const scoped_refptr<base::SingleThreadTaskRunner>& db_task_runner) : AutofillWebDataService(ui_task_runner, db_task_runner), is_database_loaded_(false), - db_loaded_callback_(base::Callback<void(void)>()) {} + db_loaded_callback_(base::RepeatingCallback<void(void)>()) {} // Mark the database as loaded and send out the appropriate notification. void LoadDatabase() { @@ -57,14 +57,17 @@ class FakeWebDataService : public AutofillWebDataService { db_loaded_callback_.Run(); // Clear the callback here or the WDS and DTC will have refs to each other // and create a memory leak. - db_loaded_callback_ = base::Callback<void(void)>(); + // TODO(crbug.com/941530): Solve this with a OnceCallback. Note that + // RegisterDBLoadedCallback overrides other functions that still use + // base::[Repeating]Callbacks, so it would affect non-Autofill code. + db_loaded_callback_ = base::RepeatingCallback<void(void)>(); } } bool IsDatabaseLoaded() override { return is_database_loaded_; } void RegisterDBLoadedCallback( - const base::Callback<void(void)>& callback) override { + const base::RepeatingCallback<void(void)>& callback) override { db_loaded_callback_ = callback; } @@ -72,14 +75,17 @@ class FakeWebDataService : public AutofillWebDataService { ~FakeWebDataService() override {} bool is_database_loaded_; - base::Callback<void(void)> db_loaded_callback_; + base::RepeatingCallback<void(void)> db_loaded_callback_; DISALLOW_COPY_AND_ASSIGN(FakeWebDataService); }; class AutofillWalletDataTypeControllerTest : public testing::Test { public: - AutofillWalletDataTypeControllerTest() : last_type_(syncer::UNSPECIFIED) {} + AutofillWalletDataTypeControllerTest() : last_type_(syncer::UNSPECIFIED) { + ON_CALL(sync_service_, GetUserShare()).WillByDefault(Return(&user_share_)); + } + ~AutofillWalletDataTypeControllerTest() override {} void SetUp() override { @@ -97,7 +103,7 @@ class AutofillWalletDataTypeControllerTest : public testing::Test { base::ThreadTaskRunnerHandle::Get()); autofill_wallet_dtc_ = std::make_unique<AutofillWalletDataTypeController>( syncer::AUTOFILL_WALLET_DATA, base::ThreadTaskRunnerHandle::Get(), - base::DoNothing(), &sync_service_, &sync_client_, + /*dump_stack=*/base::DoNothing(), &sync_service_, &sync_client_, AutofillWalletDataTypeController::PersonalDataManagerProvider(), web_data_service_); @@ -120,18 +126,21 @@ class AutofillWalletDataTypeControllerTest : public testing::Test { syncer::AUTOFILL_WALLET_DATA))); } - void Start() { + bool Start() { autofill_wallet_dtc_->LoadModels( syncer::ConfigureContext(), - base::Bind(&AutofillWalletDataTypeControllerTest::OnLoadFinished, - base::Unretained(this))); + base::BindRepeating( + &AutofillWalletDataTypeControllerTest::OnLoadFinished, + base::Unretained(this))); base::RunLoop().RunUntilIdle(); if (autofill_wallet_dtc_->state() != - syncer::DataTypeController::MODEL_LOADED) - return; - autofill_wallet_dtc_->StartAssociating(base::Bind( + syncer::DataTypeController::MODEL_LOADED) { + return false; + } + autofill_wallet_dtc_->StartAssociating(base::BindRepeating( &syncer::StartCallbackMock::Run, base::Unretained(&start_callback_))); base::RunLoop().RunUntilIdle(); + return true; } void OnLoadFinished(syncer::ModelType type, const syncer::SyncError& error) { @@ -141,7 +150,8 @@ class AutofillWalletDataTypeControllerTest : public testing::Test { base::test::ScopedTaskEnvironment task_environment_; TestingPrefServiceSimple prefs_; - syncer::FakeSyncService sync_service_; + syncer::UserShare user_share_; + testing::NiceMock<syncer::MockSyncService> sync_service_; syncer::StartCallbackMock start_callback_; syncer::FakeSyncableService syncable_service_; std::unique_ptr<AutofillWalletDataTypeController> autofill_wallet_dtc_; @@ -179,10 +189,13 @@ TEST_F(AutofillWalletDataTypeControllerTest, EXPECT_EQ(syncer::DataTypeController::RUNNING, autofill_wallet_dtc_->state()); EXPECT_FALSE(last_error_.IsSet()); EXPECT_EQ(syncer::AUTOFILL_WALLET_DATA, last_type_); + + EXPECT_CALL(sync_service_, + ReadyForStartChanged(syncer::AUTOFILL_WALLET_DATA)); autofill::prefs::SetPaymentsIntegrationEnabled(&prefs_, false); autofill::prefs::SetCreditCardAutofillEnabled(&prefs_, true); + EXPECT_FALSE(autofill_wallet_dtc_->ReadyForStart()); base::RunLoop().RunUntilIdle(); - EXPECT_TRUE(last_error_.IsSet()); } TEST_F(AutofillWalletDataTypeControllerTest, @@ -198,10 +211,13 @@ TEST_F(AutofillWalletDataTypeControllerTest, EXPECT_EQ(syncer::DataTypeController::RUNNING, autofill_wallet_dtc_->state()); EXPECT_FALSE(last_error_.IsSet()); EXPECT_EQ(syncer::AUTOFILL_WALLET_DATA, last_type_); + + EXPECT_CALL(sync_service_, + ReadyForStartChanged(syncer::AUTOFILL_WALLET_DATA)); autofill::prefs::SetPaymentsIntegrationEnabled(&prefs_, true); autofill::prefs::SetCreditCardAutofillEnabled(&prefs_, false); + EXPECT_FALSE(autofill_wallet_dtc_->ReadyForStart()); base::RunLoop().RunUntilIdle(); - EXPECT_TRUE(last_error_.IsSet()); } TEST_F(AutofillWalletDataTypeControllerTest, @@ -214,7 +230,8 @@ TEST_F(AutofillWalletDataTypeControllerTest, autofill_wallet_dtc_->state()); Start(); base::RunLoop().RunUntilIdle(); - EXPECT_TRUE(last_error_.IsSet()); + // OnLoadFinished() should not have been called. + EXPECT_EQ(syncer::UNSPECIFIED, last_type_); } TEST_F(AutofillWalletDataTypeControllerTest, @@ -227,7 +244,8 @@ TEST_F(AutofillWalletDataTypeControllerTest, autofill_wallet_dtc_->state()); Start(); base::RunLoop().RunUntilIdle(); - EXPECT_TRUE(last_error_.IsSet()); + // OnLoadFinished() should not have been called. + EXPECT_EQ(syncer::UNSPECIFIED, last_type_); } } // namespace diff --git a/chromium/components/autofill/core/browser/autofill_wallet_model_type_controller.cc b/chromium/components/autofill/core/browser/payments/autofill_wallet_model_type_controller.cc index e725f1e87c9..c415ccfbc40 100644 --- a/chromium/components/autofill/core/browser/autofill_wallet_model_type_controller.cc +++ b/chromium/components/autofill/core/browser/payments/autofill_wallet_model_type_controller.cc @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "components/autofill/core/browser/autofill_wallet_model_type_controller.h" +#include "components/autofill/core/browser/payments/autofill_wallet_model_type_controller.h" #include <utility> @@ -10,7 +10,9 @@ #include "base/bind_helpers.h" #include "components/autofill/core/common/autofill_prefs.h" #include "components/prefs/pref_service.h" +#include "components/sync/driver/sync_auth_util.h" #include "components/sync/driver/sync_service.h" +#include "google_apis/gaia/google_service_auth_error.h" namespace browser_sync { @@ -24,8 +26,10 @@ AutofillWalletModelTypeController::AutofillWalletModelTypeController( sync_service_(sync_service) { DCHECK(type == syncer::AUTOFILL_WALLET_DATA || type == syncer::AUTOFILL_WALLET_METADATA); - currently_enabled_ = IsEnabled(); SubscribeToPrefChanges(); + // TODO(crbug.com/906995): remove this observing mechanism once all sync + // datatypes are stopped by ProfileSyncService, when sync is paused. + sync_service_->AddObserver(this); } AutofillWalletModelTypeController::AutofillWalletModelTypeController( @@ -41,36 +45,45 @@ AutofillWalletModelTypeController::AutofillWalletModelTypeController( sync_service_(sync_service) { DCHECK(type == syncer::AUTOFILL_WALLET_DATA || type == syncer::AUTOFILL_WALLET_METADATA); - currently_enabled_ = IsEnabled(); SubscribeToPrefChanges(); + // TODO(crbug.com/906995): remove this observing mechanism once all sync + // datatypes are stopped by ProfileSyncService, when sync is paused. + sync_service_->AddObserver(this); } -AutofillWalletModelTypeController::~AutofillWalletModelTypeController() {} - -bool AutofillWalletModelTypeController::ReadyForStart() const { - DCHECK(CalledOnValidThread()); - return currently_enabled_; +AutofillWalletModelTypeController::~AutofillWalletModelTypeController() { + sync_service_->RemoveObserver(this); } -void AutofillWalletModelTypeController::OnUserPrefChanged() { +void AutofillWalletModelTypeController::Stop( + syncer::ShutdownReason shutdown_reason, + StopCallback callback) { DCHECK(CalledOnValidThread()); - - bool newly_enabled = IsEnabled(); - if (currently_enabled_ == newly_enabled) { - return; // No change to sync state. + switch (shutdown_reason) { + case syncer::STOP_SYNC: + // Special case: For AUTOFILL_WALLET_DATA and AUTOFILL_WALLET_METADATA, we + // want to clear all data even when Sync is stopped temporarily. + shutdown_reason = syncer::DISABLE_SYNC; + break; + case syncer::DISABLE_SYNC: + case syncer::BROWSER_SHUTDOWN: + break; } - - currently_enabled_ = newly_enabled; - sync_service_->ReadyForStartChanged(type()); + ModelTypeController::Stop(shutdown_reason, std::move(callback)); } -bool AutofillWalletModelTypeController::IsEnabled() const { +bool AutofillWalletModelTypeController::ReadyForStart() const { DCHECK(CalledOnValidThread()); - - // Require two user-visible prefs to be enabled to sync Wallet data/metadata. return pref_service_->GetBoolean( autofill::prefs::kAutofillWalletImportEnabled) && - pref_service_->GetBoolean(autofill::prefs::kAutofillCreditCardEnabled); + pref_service_->GetBoolean( + autofill::prefs::kAutofillCreditCardEnabled) && + !syncer::IsWebSignout(sync_service_->GetAuthError()); +} + +void AutofillWalletModelTypeController::OnUserPrefChanged() { + DCHECK(CalledOnValidThread()); + sync_service_->ReadyForStartChanged(type()); } void AutofillWalletModelTypeController::SubscribeToPrefChanges() { @@ -85,4 +98,10 @@ void AutofillWalletModelTypeController::SubscribeToPrefChanges() { base::Unretained(this))); } +void AutofillWalletModelTypeController::OnStateChanged( + syncer::SyncService* sync) { + DCHECK(CalledOnValidThread()); + sync_service_->ReadyForStartChanged(type()); +} + } // namespace browser_sync diff --git a/chromium/components/autofill/core/browser/autofill_wallet_model_type_controller.h b/chromium/components/autofill/core/browser/payments/autofill_wallet_model_type_controller.h index 1f9fcb50815..cee6054e828 100644 --- a/chromium/components/autofill/core/browser/autofill_wallet_model_type_controller.h +++ b/chromium/components/autofill/core/browser/payments/autofill_wallet_model_type_controller.h @@ -2,8 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#ifndef COMPONENTS_AUTOFILL_CORE_BROWSER_AUTOFILL_WALLET_MODEL_TYPE_CONTROLLER_H_ -#define COMPONENTS_AUTOFILL_CORE_BROWSER_AUTOFILL_WALLET_MODEL_TYPE_CONTROLLER_H_ +#ifndef COMPONENTS_AUTOFILL_CORE_BROWSER_PAYMENTS_AUTOFILL_WALLET_MODEL_TYPE_CONTROLLER_H_ +#define COMPONENTS_AUTOFILL_CORE_BROWSER_PAYMENTS_AUTOFILL_WALLET_MODEL_TYPE_CONTROLLER_H_ #include <memory> #include <string> @@ -11,6 +11,7 @@ #include "base/macros.h" #include "components/prefs/pref_change_registrar.h" #include "components/sync/driver/model_type_controller.h" +#include "components/sync/driver/sync_service_observer.h" class PrefService; @@ -21,7 +22,8 @@ class SyncService; namespace browser_sync { // Controls syncing of AUTOFILL_WALLET_DATA and AUTOFILL_WALLET_METADATA. -class AutofillWalletModelTypeController : public syncer::ModelTypeController { +class AutofillWalletModelTypeController : public syncer::ModelTypeController, + public syncer::SyncServiceObserver { public: // The delegates and |sync_client| must not be null. Furthermore, // |sync_client| must outlive this object. @@ -39,8 +41,13 @@ class AutofillWalletModelTypeController : public syncer::ModelTypeController { ~AutofillWalletModelTypeController() override; // DataTypeController overrides. + void Stop(syncer::ShutdownReason shutdown_reason, + StopCallback callback) override; bool ReadyForStart() const override; + // syncer::SyncServiceObserver implementation. + void OnStateChanged(syncer::SyncService* sync) override; + private: // Callback for changes to the autofill pref. void OnUserPrefChanged(); @@ -53,11 +60,9 @@ class AutofillWalletModelTypeController : public syncer::ModelTypeController { PrefChangeRegistrar pref_registrar_; - bool currently_enabled_; - DISALLOW_COPY_AND_ASSIGN(AutofillWalletModelTypeController); }; } // namespace browser_sync -#endif // COMPONENTS_AUTOFILL_CORE_BROWSER_AUTOFILL_WALLET_MODEL_TYPE_CONTROLLER_H_ +#endif // COMPONENTS_AUTOFILL_CORE_BROWSER_PAYMENTS_AUTOFILL_WALLET_MODEL_TYPE_CONTROLLER_H_ diff --git a/chromium/components/autofill/core/browser/card_unmask_delegate.cc b/chromium/components/autofill/core/browser/payments/card_unmask_delegate.cc index f22bbb1ce77..82d06ecd0ac 100644 --- a/chromium/components/autofill/core/browser/card_unmask_delegate.cc +++ b/chromium/components/autofill/core/browser/payments/card_unmask_delegate.cc @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "components/autofill/core/browser/card_unmask_delegate.h" +#include "components/autofill/core/browser/payments/card_unmask_delegate.h" namespace autofill { diff --git a/chromium/components/autofill/core/browser/card_unmask_delegate.h b/chromium/components/autofill/core/browser/payments/card_unmask_delegate.h index 232a348d2ad..729e5a34cc7 100644 --- a/chromium/components/autofill/core/browser/card_unmask_delegate.h +++ b/chromium/components/autofill/core/browser/payments/card_unmask_delegate.h @@ -2,8 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#ifndef COMPONENTS_AUTOFILL_CORE_BROWSER_CARD_UNMASK_DELEGATE_H_ -#define COMPONENTS_AUTOFILL_CORE_BROWSER_CARD_UNMASK_DELEGATE_H_ +#ifndef COMPONENTS_AUTOFILL_CORE_BROWSER_PAYMENTS_CARD_UNMASK_DELEGATE_H_ +#define COMPONENTS_AUTOFILL_CORE_BROWSER_PAYMENTS_CARD_UNMASK_DELEGATE_H_ #include <string> @@ -41,4 +41,4 @@ class CardUnmaskDelegate { } // namespace autofill -#endif // COMPONENTS_AUTOFILL_CORE_BROWSER_CARD_UNMASK_DELEGATE_H_ +#endif // COMPONENTS_AUTOFILL_CORE_BROWSER_PAYMENTS_CARD_UNMASK_DELEGATE_H_ diff --git a/chromium/components/autofill/core/browser/credit_card_save_manager.cc b/chromium/components/autofill/core/browser/payments/credit_card_save_manager.cc index 910d5e02fd6..e35c805e3eb 100644 --- a/chromium/components/autofill/core/browser/credit_card_save_manager.cc +++ b/chromium/components/autofill/core/browser/payments/credit_card_save_manager.cc @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "components/autofill/core/browser/credit_card_save_manager.h" +#include "components/autofill/core/browser/payments/credit_card_save_manager.h" #include <stddef.h> #include <stdint.h> @@ -33,15 +33,16 @@ #include "components/autofill/core/browser/autofill_type.h" #include "components/autofill/core/browser/credit_card.h" #include "components/autofill/core/browser/form_structure.h" -#include "components/autofill/core/browser/legacy_strike_database.h" +#include "components/autofill/core/browser/payments/legacy_strike_database.h" #include "components/autofill/core/browser/payments/payments_client.h" #include "components/autofill/core/browser/payments/payments_util.h" +#include "components/autofill/core/browser/payments/strike_database.h" #include "components/autofill/core/browser/personal_data_manager.h" -#include "components/autofill/core/browser/strike_database.h" #include "components/autofill/core/browser/validation.h" #include "components/autofill/core/common/autofill_clock.h" #include "components/autofill/core/common/autofill_constants.h" #include "components/autofill/core/common/autofill_features.h" +#include "components/autofill/core/common/autofill_payments_features.h" #include "components/autofill/core/common/autofill_util.h" #include "services/identity/public/cpp/identity_manager.h" #include "url/gurl.h" @@ -101,11 +102,13 @@ CreditCardSaveManager::CreditCardSaveManager( CreditCardSaveManager::~CreditCardSaveManager() {} void CreditCardSaveManager::AttemptToOfferCardLocalSave( + bool from_dynamic_change_form, bool has_non_focusable_field, const CreditCard& card) { local_card_save_candidate_ = card; show_save_prompt_ = base::nullopt; has_non_focusable_field_ = has_non_focusable_field; + from_dynamic_change_form_ = from_dynamic_change_form; // Query the Autofill StrikeDatabase on if we should pop up the // offer-to-save prompt for this card. @@ -130,6 +133,7 @@ void CreditCardSaveManager::AttemptToOfferCardLocalSave( void CreditCardSaveManager::AttemptToOfferCardUploadSave( const FormStructure& submitted_form, + bool from_dynamic_change_form, bool has_non_focusable_field, const CreditCard& card, const bool uploading_local_card) { @@ -158,6 +162,7 @@ void CreditCardSaveManager::AttemptToOfferCardUploadSave( found_cvc_value_in_non_cvc_field_ = false; has_non_focusable_field_ = has_non_focusable_field; + from_dynamic_change_form_ = from_dynamic_change_form; for (const auto& field : submitted_form) { const bool is_valid_cvc = IsValidCreditCardSecurityCode( @@ -187,7 +192,10 @@ void CreditCardSaveManager::AttemptToOfferCardUploadSave( upload_decision_metrics_ |= AutofillMetrics::UPLOAD_OFFERED_FROM_NON_FOCUSABLE_FIELD; } - + if (submitted_form.value_from_dynamic_change_form()) { + upload_decision_metrics_ |= + AutofillMetrics::UPLOAD_OFFERED_FROM_DYNAMIC_CHANGE_FORM; + } if (upload_request_.cvc.empty()) { // Apply the CVC decision to |upload_decision_metrics_| to denote a problem // was found. @@ -293,7 +301,8 @@ bool CreditCardSaveManager::IsCreditCardUploadEnabled() { #endif // defined(OS_IOS) return ::autofill::IsCreditCardUploadEnabled( client_->GetPrefs(), client_->GetSyncService(), - personal_data_manager_->GetAccountInfoForPaymentsServer().email); + personal_data_manager_->GetAccountInfoForPaymentsServer().email, + personal_data_manager_->GetSyncSigninState()); } bool CreditCardSaveManager::IsUploadEnabledForNetwork( @@ -444,8 +453,12 @@ void CreditCardSaveManager::OnDidGetUploadDetails( features::kAutofillDoNotUploadSaveUnsupportedCards) && !supported_card_bin_ranges.empty() && !IsCreditCardSupported(supported_card_bin_ranges)) { - AttemptToOfferCardLocalSave(has_non_focusable_field_, - upload_request_.card); + // Attempt local card save if card not already saved. + if (!uploading_local_card_) { + AttemptToOfferCardLocalSave(from_dynamic_change_form_, + has_non_focusable_field_, + upload_request_.card); + } upload_decision_metrics_ |= AutofillMetrics::UPLOAD_NOT_OFFERED_UNSUPPORTED_BIN_RANGE; LogCardUploadDecisions(upload_decision_metrics_); @@ -484,7 +497,8 @@ void CreditCardSaveManager::OnDidGetUploadDetails( upload_request_.detected_values & DetectedValue::POSTAL_CODE && upload_request_.detected_values & DetectedValue::CVC; if (found_name_and_postal_code_and_cvc && !uploading_local_card_) { - AttemptToOfferCardLocalSave(has_non_focusable_field_, + AttemptToOfferCardLocalSave(from_dynamic_change_form_, + has_non_focusable_field_, upload_request_.card); } upload_decision_metrics_ |= @@ -538,6 +552,7 @@ void CreditCardSaveManager::OfferCardUploadSave() { client_->ConfirmSaveCreditCardToCloud( upload_request_.card, std::move(legal_message_), AutofillClient::SaveCreditCardOptions() + .with_from_dynamic_change_form(from_dynamic_change_form_) .with_has_non_focusable_field(has_non_focusable_field_) .with_should_request_name_from_user(should_request_name_from_user_) .with_should_request_expiration_date_from_user( @@ -802,8 +817,7 @@ int CreditCardSaveManager::GetDetectedValues() const { // Payments account. Include a bit for existence of this account (NOT the id // itself), as it will help determine if a new Payments customer might need to // be created when save is accepted. - if (payments::GetBillingCustomerId(personal_data_manager_, - payments_client_->GetPrefService()) != 0) { + if (payments::GetBillingCustomerId(personal_data_manager_) != 0) { detected_values |= DetectedValue::HAS_GOOGLE_PAYMENTS_ACCOUNT; } @@ -964,8 +978,8 @@ void CreditCardSaveManager::SendUploadCardRequest() { if (observer_for_testing_) observer_for_testing_->OnSentUploadCardRequest(); upload_request_.app_locale = app_locale_; - upload_request_.billing_customer_number = payments::GetBillingCustomerId( - personal_data_manager_, payments_client_->GetPrefService()); + upload_request_.billing_customer_number = + payments::GetBillingCustomerId(personal_data_manager_); AutofillMetrics::LogUploadAcceptedCardOriginMetric( uploading_local_card_ diff --git a/chromium/components/autofill/core/browser/credit_card_save_manager.h b/chromium/components/autofill/core/browser/payments/credit_card_save_manager.h index 5cffff6e8c9..3319c5fb6cb 100644 --- a/chromium/components/autofill/core/browser/credit_card_save_manager.h +++ b/chromium/components/autofill/core/browser/payments/credit_card_save_manager.h @@ -2,8 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#ifndef COMPONENTS_AUTOFILL_CORE_BROWSER_CREDIT_CARD_SAVE_MANAGER_H_ -#define COMPONENTS_AUTOFILL_CORE_BROWSER_CREDIT_CARD_SAVE_MANAGER_H_ +#ifndef COMPONENTS_AUTOFILL_CORE_BROWSER_PAYMENTS_CREDIT_CARD_SAVE_MANAGER_H_ +#define COMPONENTS_AUTOFILL_CORE_BROWSER_PAYMENTS_CREDIT_CARD_SAVE_MANAGER_H_ #include <map> #include <memory> @@ -17,9 +17,9 @@ #include "components/autofill/core/browser/autofill_client.h" #include "components/autofill/core/browser/autofill_metrics.h" #include "components/autofill/core/browser/credit_card.h" -#include "components/autofill/core/browser/credit_card_save_strike_database.h" #include "components/autofill/core/browser/form_structure.h" -#include "components/autofill/core/browser/local_card_migration_strike_database.h" +#include "components/autofill/core/browser/payments/credit_card_save_strike_database.h" +#include "components/autofill/core/browser/payments/local_card_migration_strike_database.h" #include "components/autofill/core/browser/payments/payments_client.h" #include "components/autofill/core/browser/personal_data_manager.h" #include "url/origin.h" @@ -97,15 +97,21 @@ class CreditCardSaveManager { // Begins the process to offer local credit card save to the user. // If |has_non_focusable_field| is true, the save is triggered by a form that // has non_focusable fields. - void AttemptToOfferCardLocalSave(bool has_non_focusable_field, + // If |from_dynamic_change_form| is true, the save is triggered by a dynamic + // change form. + void AttemptToOfferCardLocalSave(bool from_dynamic_change_form, + bool has_non_focusable_field, const CreditCard& card); // Begins the process to offer upload credit card save to the user if the // imported card passes all requirements and Google Payments approves. // If |has_non_focusable_field| is true, the save is triggered by a form that // has non-focusable fields. if |uploading_local_card| is true, the card being - // offered for upload is already a local card on the device. + // offered for upload is already a local card on the device. If + // |from_dynamic_change_form| is true, the save is triggered by a dynamic + // change form. void AttemptToOfferCardUploadSave(const FormStructure& submitted_form, + bool from_dynamic_change_form, bool has_non_focusable_field, const CreditCard& card, const bool uploading_local_card); @@ -335,6 +341,10 @@ class CreditCardSaveManager { // |is_focusable| is false. bool has_non_focusable_field_ = false; + // |from_dynamic_change_form_| is |true| values imported from dynamic change + // form. + bool from_dynamic_change_form_ = false; + // The origin of the top level frame from which a form is uploaded. url::Origin pending_upload_request_origin_; @@ -366,4 +376,4 @@ class CreditCardSaveManager { } // namespace autofill -#endif // COMPONENTS_AUTOFILL_CORE_BROWSER_CREDIT_CARD_SAVE_MANAGER_H_ +#endif // COMPONENTS_AUTOFILL_CORE_BROWSER_PAYMENTS_CREDIT_CARD_SAVE_MANAGER_H_ diff --git a/chromium/components/autofill/core/browser/credit_card_save_manager_unittest.cc b/chromium/components/autofill/core/browser/payments/credit_card_save_manager_unittest.cc index d4d246aaf5f..17fc2ea63da 100644 --- a/chromium/components/autofill/core/browser/credit_card_save_manager_unittest.cc +++ b/chromium/components/autofill/core/browser/payments/credit_card_save_manager_unittest.cc @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "components/autofill/core/browser/credit_card_save_manager.h" +#include "components/autofill/core/browser/payments/credit_card_save_manager.h" #include <stddef.h> @@ -28,21 +28,23 @@ #include "components/autofill/core/browser/autofill_test_utils.h" #include "components/autofill/core/browser/credit_card.h" #include "components/autofill/core/browser/mock_autocomplete_history_manager.h" +#include "components/autofill/core/browser/payments/payments_customer_data.h" +#include "components/autofill/core/browser/payments/test_credit_card_save_manager.h" +#include "components/autofill/core/browser/payments/test_credit_card_save_strike_database.h" +#include "components/autofill/core/browser/payments/test_legacy_strike_database.h" #include "components/autofill/core/browser/payments/test_payments_client.h" #include "components/autofill/core/browser/personal_data_manager.h" #include "components/autofill/core/browser/test_autofill_client.h" #include "components/autofill/core/browser/test_autofill_clock.h" #include "components/autofill/core/browser/test_autofill_driver.h" #include "components/autofill/core/browser/test_autofill_manager.h" -#include "components/autofill/core/browser/test_credit_card_save_manager.h" -#include "components/autofill/core/browser/test_credit_card_save_strike_database.h" #include "components/autofill/core/browser/test_form_data_importer.h" -#include "components/autofill/core/browser/test_legacy_strike_database.h" #include "components/autofill/core/browser/test_personal_data_manager.h" #include "components/autofill/core/browser/validation.h" #include "components/autofill/core/browser/webdata/autofill_webdata_service.h" #include "components/autofill/core/common/autofill_clock.h" #include "components/autofill/core/common/autofill_features.h" +#include "components/autofill/core/common/autofill_payments_features.h" #include "components/autofill/core/common/autofill_prefs.h" #include "components/autofill/core/common/form_data.h" #include "components/autofill/core/common/form_field_data.h" @@ -127,7 +129,7 @@ class CreditCardSaveManagerTest : public testing::Test { base::ThreadTaskRunnerHandle::Get()); autofill_driver_->SetURLRequestContext(request_context_.get()); payments_client_ = new payments::TestPaymentsClient( - autofill_driver_->GetURLLoaderFactory(), autofill_client_.GetPrefs(), + autofill_driver_->GetURLLoaderFactory(), autofill_client_.GetIdentityManager(), &personal_data_); autofill_client_.set_test_payments_client( std::unique_ptr<payments::TestPaymentsClient>(payments_client_)); @@ -183,19 +185,21 @@ class CreditCardSaveManagerTest : public testing::Test { bool is_https, bool use_month_type, bool split_names = false, - bool is_from_non_focusable_form = false) { + bool is_from_non_focusable_form = false, + bool is_google_host = false) { form->name = ASCIIToUTF16("MyForm"); - if (is_https) { - form->origin = GURL("https://myform.com/form.html"); - form->action = GURL("https://myform.com/submit.html"); - form->main_frame_origin = - url::Origin::Create(GURL("https://myform_root.com/form.html")); - } else { - form->origin = GURL("http://myform.com/form.html"); - form->action = GURL("http://myform.com/submit.html"); - form->main_frame_origin = - url::Origin::Create(GURL("http://myform_root.com/form.html")); - } + base::string16 scheme = + is_https ? ASCIIToUTF16("https://") : ASCIIToUTF16("http://"); + base::string16 host = is_google_host ? ASCIIToUTF16("pay.google.com") + : ASCIIToUTF16("myform.com"); + base::string16 root_host = is_google_host ? ASCIIToUTF16("pay.google.com") + : ASCIIToUTF16("myform.root.com"); + base::string16 form_path = ASCIIToUTF16("/form.html"); + base::string16 submit_path = ASCIIToUTF16("/submit.html"); + form->url = GURL(scheme + host + form_path); + form->action = GURL(scheme + host + submit_path); + form->main_frame_origin = + url::Origin::Create(GURL(scheme + root_host + form_path)); FormFieldData field; if (split_names) { @@ -666,7 +670,7 @@ TEST_F(CreditCardSaveManagerTest, LocalCreditCard_LastAndFirstName) { // fields. FormData credit_card_form; credit_card_form.name = ASCIIToUTF16("MyForm"); - credit_card_form.origin = GURL("https://myform.com/form.html"); + credit_card_form.url = GURL("https://myform.com/form.html"); credit_card_form.action = GURL("https://myform.com/submit.html"); credit_card_form.main_frame_origin = url::Origin::Create(GURL("https://myform_root.com/form.html")); @@ -996,7 +1000,7 @@ TEST_F(CreditCardSaveManagerTest, UploadCreditCard_LastAndFirstName) { // fields. FormData credit_card_form; credit_card_form.name = ASCIIToUTF16("MyForm"); - credit_card_form.origin = GURL("https://myform.com/form.html"); + credit_card_form.url = GURL("https://myform.com/form.html"); credit_card_form.action = GURL("https://myform.com/submit.html"); credit_card_form.main_frame_origin = url::Origin::Create(GURL("https://myform_root.com/form.html")); @@ -1273,7 +1277,7 @@ TEST_F(CreditCardSaveManagerTest, UploadCreditCard_MultipleCvcFields) { // Set up our credit card form data. FormData credit_card_form; credit_card_form.name = ASCIIToUTF16("MyForm"); - credit_card_form.origin = GURL("https://myform.com/form.html"); + credit_card_form.url = GURL("https://myform.com/form.html"); credit_card_form.action = GURL("https://myform.com/submit.html"); credit_card_form.main_frame_origin = url::Origin::Create(GURL("http://myform_root.com/form.html")); @@ -1328,7 +1332,7 @@ TEST_F(CreditCardSaveManagerTest, UploadCreditCard_NoCvcFieldOnForm) { // Set up our credit card form data. Note that CVC field is missing. FormData credit_card_form; credit_card_form.name = ASCIIToUTF16("MyForm"); - credit_card_form.origin = GURL("https://myform.com/form.html"); + credit_card_form.url = GURL("https://myform.com/form.html"); credit_card_form.action = GURL("https://myform.com/submit.html"); credit_card_form.main_frame_origin = url::Origin::Create(GURL("http://myform_root.com/form.html")); @@ -1381,7 +1385,7 @@ TEST_F(CreditCardSaveManagerTest, // Set up our credit card form data. Note that CVC field is missing. FormData credit_card_form; credit_card_form.name = ASCIIToUTF16("MyForm"); - credit_card_form.origin = GURL("https://myform.com/form.html"); + credit_card_form.url = GURL("https://myform.com/form.html"); credit_card_form.action = GURL("https://myform.com/submit.html"); credit_card_form.main_frame_origin = url::Origin::Create(GURL("http://myform_root.com/form.html")); @@ -1437,7 +1441,7 @@ TEST_F(CreditCardSaveManagerTest, // Set up our credit card form data. Note that CVC field is missing. FormData credit_card_form; credit_card_form.name = ASCIIToUTF16("MyForm"); - credit_card_form.origin = GURL("https://myform.com/form.html"); + credit_card_form.url = GURL("https://myform.com/form.html"); credit_card_form.action = GURL("https://myform.com/submit.html"); credit_card_form.main_frame_origin = url::Origin::Create(GURL("http://myform_root.com/form.html")); @@ -1495,7 +1499,7 @@ TEST_F(CreditCardSaveManagerTest, // Set up our credit card form data. Note that CVC field is missing. FormData credit_card_form; credit_card_form.name = ASCIIToUTF16("MyForm"); - credit_card_form.origin = GURL("https://myform.com/form.html"); + credit_card_form.url = GURL("https://myform.com/form.html"); credit_card_form.action = GURL("https://myform.com/submit.html"); credit_card_form.main_frame_origin = url::Origin::Create(GURL("http://myform_root.com/form.html")); @@ -2254,6 +2258,75 @@ TEST_F( CreditCardSaveManager::DetectedValue::USER_PROVIDED_NAME); } +TEST_F(CreditCardSaveManagerTest, + GoogleHostSite_ShouldNotOfferSaveIfUploadEnabled) { + // Create, fill and submit an address form in order to establish a recent + // profile which can be selected for the upload request. + FormData address_form; + test::CreateTestAddressFormData(&address_form); + FormsSeen(std::vector<FormData>(1, address_form)); + ManuallyFillAddressForm("Flo", "Master", "77401", "US", &address_form); + FormSubmitted(address_form); + // Set up our credit card form data. + FormData credit_card_form; + CreateTestCreditCardFormData(&credit_card_form, /*is_https=*/true, + /*split_names=*/false, /*split_names=*/false, + /*is_from_non_focusable_form*/ false, + /*is_google_host*/ true); + FormsSeen(std::vector<FormData>(1, credit_card_form)); + + // Edit the data, and submit. + credit_card_form.fields[0].value = ASCIIToUTF16("Flo Master"); + credit_card_form.fields[1].value = ASCIIToUTF16("4111111111111111"); + credit_card_form.fields[2].value = ASCIIToUTF16(NextMonth()); + credit_card_form.fields[3].value = ASCIIToUTF16(NextYear()); + credit_card_form.fields[4].value = ASCIIToUTF16("123"); + + base::HistogramTester histogram_tester; + + // The credit card should neither be saved locally or uploaded. + FormSubmitted(credit_card_form); + EXPECT_FALSE(autofill_client_.ConfirmSaveCardLocallyWasCalled()); + EXPECT_FALSE(credit_card_save_manager_->CreditCardWasUploaded()); + + // Verify that no histogram entry was logged. + histogram_tester.ExpectTotalCount("Autofill.CardUploadDecisionMetric", 0); +} + +TEST_F(CreditCardSaveManagerTest, + GoogleHostSite_ShouldOfferSaveIfUploadDisabled) { + credit_card_save_manager_->SetCreditCardUploadEnabled(false); + + // Create, fill and submit an address form in order to establish a recent + // profile which can be selected for the upload request. + FormData address_form; + test::CreateTestAddressFormData(&address_form); + FormsSeen(std::vector<FormData>(1, address_form)); + ManuallyFillAddressForm("Flo", "Master", "77401", "US", &address_form); + FormSubmitted(address_form); + // Set up our credit card form data. + FormData credit_card_form; + CreateTestCreditCardFormData(&credit_card_form, /*is_https=*/true, + /*split_names=*/false, /*split_names=*/false, + /*is_from_non_focusable_form*/ false, + /*is_google_host*/ true); + FormsSeen(std::vector<FormData>(1, credit_card_form)); + + // Edit the data, and submit. + credit_card_form.fields[0].value = ASCIIToUTF16("Flo Master"); + credit_card_form.fields[1].value = ASCIIToUTF16("4111111111111111"); + credit_card_form.fields[2].value = ASCIIToUTF16(NextMonth()); + credit_card_form.fields[3].value = ASCIIToUTF16(NextYear()); + credit_card_form.fields[4].value = ASCIIToUTF16("123"); + + base::HistogramTester histogram_tester; + + // The credit card should be saved locally. + FormSubmitted(credit_card_form); + EXPECT_TRUE(autofill_client_.ConfirmSaveCardLocallyWasCalled()); + EXPECT_FALSE(credit_card_save_manager_->CreditCardWasUploaded()); +} + TEST_F( CreditCardSaveManagerTest, UploadCreditCard_DoNotRequestCardholderNameIfNameExistsAndNoPaymentsCustomer) { @@ -2301,10 +2374,10 @@ TEST_F( scoped_feature_list_.InitAndEnableFeature( features::kAutofillUpstreamEditableCardholderName); - // Set the billing_customer_number Priority Preference to designate existence - // of a Payments account. - autofill_client_.GetPrefs()->SetDouble(prefs::kAutofillBillingCustomerNumber, - 12345); + // Set the billing_customer_number to designate existence of a Payments + // account. + personal_data_.SetPaymentsCustomerData( + std::make_unique<PaymentsCustomerData>(/*customer_id=*/"123456")); // Create, fill and submit an address form in order to establish a recent // profile which can be selected for the upload request. @@ -2349,10 +2422,10 @@ TEST_F( scoped_feature_list_.InitAndEnableFeature( features::kAutofillUpstreamEditableCardholderName); - // Set the billing_customer_number Priority Preference to designate existence - // of a Payments account. - autofill_client_.GetPrefs()->SetDouble(prefs::kAutofillBillingCustomerNumber, - 12345); + // Set the billing_customer_number to designate existence of a Payments + // account. + personal_data_.SetPaymentsCustomerData( + std::make_unique<PaymentsCustomerData>(/*customer_id=*/"123456")); // Create, fill and submit an address form in order to establish a recent // profile which can be selected for the upload request. @@ -2514,10 +2587,11 @@ TEST_F( // Verify the |credit_card_save_manager_| is requesting cardholder name. EXPECT_TRUE(credit_card_save_manager_->should_request_name_from_user_); - // Simulate a Chrome/Payments sync where billing_customer_number was newly - // set. - autofill_client_.GetPrefs()->SetDouble(prefs::kAutofillBillingCustomerNumber, - 12345); + // Set the billing_customer_number to designate existence of a Payments + // account. + personal_data_.SetPaymentsCustomerData( + std::make_unique<PaymentsCustomerData>(/*customer_id=*/"123456")); + // Run through the form submit in exactly the same way (but now Chrome knows // that the user is a Google Payments customer). personal_data_.ClearCreditCards(); @@ -3340,10 +3414,10 @@ TEST_P(CreditCardSaveManagerFeatureParameterizedTest, DetectCountryCode) { TEST_P(CreditCardSaveManagerFeatureParameterizedTest, DetectHasGooglePaymentAccount) { - // Set the billing_customer_number Priority Preference to designate existence - // of a Payments account. - autofill_client_.GetPrefs()->SetDouble(prefs::kAutofillBillingCustomerNumber, - 12345); + // Set the billing_customer_number to designate existence of a Payments + // account. + personal_data_.SetPaymentsCustomerData( + std::make_unique<PaymentsCustomerData>(/*customer_id=*/"123456")); // Set up our credit card form data. FormData credit_card_form; @@ -5535,6 +5609,40 @@ TEST_F(CreditCardSaveManagerTest, UploadSaveNotOfferedForUnsupportedCard) { EXPECT_FALSE(credit_card_save_manager_->CreditCardWasUploaded()); } +// Tests that if a card doesn't fall in any of the supported bin ranges, but is +// already saved, then local save is not offered. +TEST_F(CreditCardSaveManagerTest, LocalSaveNotOfferedForSavedUnsupportedCard) { + scoped_feature_list_.InitAndEnableFeature( + features::kAutofillDoNotUploadSaveUnsupportedCards); + std::vector<std::pair<int, int>> supported_card_bin_ranges{ + std::make_pair(4111, 4113), std::make_pair(34, 34), + std::make_pair(300, 305)}; + payments_client_->SetSupportedBINRanges(supported_card_bin_ranges); + // Set up our credit card form data. + FormData credit_card_form; + CreateTestCreditCardFormData(&credit_card_form, true, false); + FormsSeen(std::vector<FormData>(1, credit_card_form)); + + // Add a local credit card whose number matches what we will + // enter below. + CreditCard local_card; + test::SetCreditCardInfo(&local_card, "Flo Master", "5454545454545454", + NextMonth().c_str(), NextYear().c_str(), "1"); + local_card.set_record_type(CreditCard::LOCAL_CARD); + personal_data_.AddCreditCard(local_card); + + // Edit the data, and submit. + credit_card_form.fields[0].value = ASCIIToUTF16("Flo Master"); + credit_card_form.fields[1].value = ASCIIToUTF16("5454545454545454"); + credit_card_form.fields[2].value = ASCIIToUTF16(NextMonth()); + credit_card_form.fields[3].value = ASCIIToUTF16(NextYear()); + credit_card_form.fields[4].value = ASCIIToUTF16("123"); + + // Since card is already saved, local save should not be offered. + FormSubmitted(credit_card_form); + EXPECT_FALSE(autofill_client_.ConfirmSaveCardLocallyWasCalled()); +} + // Tests that if a card falls in one of the supported bin ranges, upload save // is offered. TEST_F(CreditCardSaveManagerTest, UploadSaveOfferedForSupportedCard) { diff --git a/chromium/components/autofill/core/browser/credit_card_save_strike_database.cc b/chromium/components/autofill/core/browser/payments/credit_card_save_strike_database.cc index 5df822f385e..cd0fd9e0a93 100644 --- a/chromium/components/autofill/core/browser/credit_card_save_strike_database.cc +++ b/chromium/components/autofill/core/browser/payments/credit_card_save_strike_database.cc @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "components/autofill/core/browser/credit_card_save_strike_database.h" +#include "components/autofill/core/browser/payments/credit_card_save_strike_database.h" #include "components/autofill/core/browser/proto/strike_data.pb.h" diff --git a/chromium/components/autofill/core/browser/credit_card_save_strike_database.h b/chromium/components/autofill/core/browser/payments/credit_card_save_strike_database.h index 537682256f1..fbe68217b74 100644 --- a/chromium/components/autofill/core/browser/credit_card_save_strike_database.h +++ b/chromium/components/autofill/core/browser/payments/credit_card_save_strike_database.h @@ -2,13 +2,13 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#ifndef COMPONENTS_AUTOFILL_CORE_BROWSER_CREDIT_CARD_SAVE_STRIKE_DATABASE_H_ -#define COMPONENTS_AUTOFILL_CORE_BROWSER_CREDIT_CARD_SAVE_STRIKE_DATABASE_H_ +#ifndef COMPONENTS_AUTOFILL_CORE_BROWSER_PAYMENTS_CREDIT_CARD_SAVE_STRIKE_DATABASE_H_ +#define COMPONENTS_AUTOFILL_CORE_BROWSER_PAYMENTS_CREDIT_CARD_SAVE_STRIKE_DATABASE_H_ #include <string> -#include "components/autofill/core/browser/strike_database.h" -#include "components/autofill/core/browser/strike_database_integrator_base.h" +#include "components/autofill/core/browser/payments/strike_database.h" +#include "components/autofill/core/browser/payments/strike_database_integrator_base.h" namespace autofill { @@ -27,4 +27,4 @@ class CreditCardSaveStrikeDatabase : public StrikeDatabaseIntegratorBase { } // namespace autofill -#endif // COMPONENTS_AUTOFILL_CORE_BROWSER_CREDIT_CARD_SAVE_STRIKE_DATABASE_H_ +#endif // COMPONENTS_AUTOFILL_CORE_BROWSER_PAYMENTS_CREDIT_CARD_SAVE_STRIKE_DATABASE_H_ diff --git a/chromium/components/autofill/core/browser/payments/full_card_request.cc b/chromium/components/autofill/core/browser/payments/full_card_request.cc index 9aa14cbf0a0..746db66cdf2 100644 --- a/chromium/components/autofill/core/browser/payments/full_card_request.cc +++ b/chromium/components/autofill/core/browser/payments/full_card_request.cc @@ -69,8 +69,7 @@ void FullCardRequest::GetFullCard(const CreditCard& card, if (should_unmask_card_) { payments_client_->Prepare(); request_->billing_customer_number = GetBillingCustomerId( - personal_data_manager_, payments_client_->GetPrefService(), - /*should_log_validity=*/true); + personal_data_manager_, /*should_log_validity=*/true); } ui_delegate_->ShowUnmaskPrompt(request_->card, reason, diff --git a/chromium/components/autofill/core/browser/payments/full_card_request.h b/chromium/components/autofill/core/browser/payments/full_card_request.h index 38779049166..661ddad98e7 100644 --- a/chromium/components/autofill/core/browser/payments/full_card_request.h +++ b/chromium/components/autofill/core/browser/payments/full_card_request.h @@ -13,7 +13,7 @@ #include "base/strings/string16.h" #include "base/time/time.h" #include "components/autofill/core/browser/autofill_client.h" -#include "components/autofill/core/browser/card_unmask_delegate.h" +#include "components/autofill/core/browser/payments/card_unmask_delegate.h" #include "components/autofill/core/browser/payments/payments_client.h" namespace autofill { diff --git a/chromium/components/autofill/core/browser/payments/full_card_request_unittest.cc b/chromium/components/autofill/core/browser/payments/full_card_request_unittest.cc index fc4486c4cc6..a1177a2bf64 100644 --- a/chromium/components/autofill/core/browser/payments/full_card_request_unittest.cc +++ b/chromium/components/autofill/core/browser/payments/full_card_request_unittest.cc @@ -18,10 +18,6 @@ #include "components/autofill/core/browser/test_autofill_client.h" #include "components/autofill/core/browser/test_autofill_driver.h" #include "components/autofill/core/browser/test_personal_data_manager.h" -#include "components/autofill/core/common/autofill_prefs.h" -#include "components/prefs/pref_registry_simple.h" -#include "components/prefs/pref_service.h" -#include "components/prefs/testing_pref_service.h" #include "net/url_request/url_request_test_util.h" #include "services/network/public/cpp/shared_url_loader_factory.h" #include "services/network/public/cpp/weak_wrapper_shared_url_loader_factory.h" @@ -77,14 +73,9 @@ class FullCardRequestTest : public testing::Test { test_shared_loader_factory_( base::MakeRefCounted<network::WeakWrapperSharedURLLoaderFactory>( &test_url_loader_factory_)) { - std::unique_ptr<TestingPrefServiceSimple> pref_service( - new TestingPrefServiceSimple()); - pref_service->registry()->RegisterDoublePref( - prefs::kAutofillBillingCustomerNumber, 0.0); - autofill_client_.SetPrefs(std::move(pref_service)); payments_client_ = std::make_unique<PaymentsClient>( - test_shared_loader_factory_, autofill_client_.GetPrefs(), - autofill_client_.GetIdentityManager(), &personal_data_); + test_shared_loader_factory_, autofill_client_.GetIdentityManager(), + &personal_data_); request_ = std::make_unique<FullCardRequest>( &autofill_client_, payments_client_.get(), &personal_data_); personal_data_.SetAccountInfoForPayments( diff --git a/chromium/components/autofill/core/browser/legacy_strike_database.cc b/chromium/components/autofill/core/browser/payments/legacy_strike_database.cc index d575b2e43ae..9baf216e59b 100644 --- a/chromium/components/autofill/core/browser/legacy_strike_database.cc +++ b/chromium/components/autofill/core/browser/payments/legacy_strike_database.cc @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "components/autofill/core/browser/legacy_strike_database.h" +#include "components/autofill/core/browser/payments/legacy_strike_database.h" #include <string> #include <utility> diff --git a/chromium/components/autofill/core/browser/legacy_strike_database.h b/chromium/components/autofill/core/browser/payments/legacy_strike_database.h index c0aca236581..38e7c29f4ee 100644 --- a/chromium/components/autofill/core/browser/legacy_strike_database.h +++ b/chromium/components/autofill/core/browser/payments/legacy_strike_database.h @@ -2,8 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#ifndef COMPONENTS_AUTOFILL_CORE_BROWSER_LEGACY_STRIKE_DATABASE_H_ -#define COMPONENTS_AUTOFILL_CORE_BROWSER_LEGACY_STRIKE_DATABASE_H_ +#ifndef COMPONENTS_AUTOFILL_CORE_BROWSER_PAYMENTS_LEGACY_STRIKE_DATABASE_H_ +#define COMPONENTS_AUTOFILL_CORE_BROWSER_PAYMENTS_LEGACY_STRIKE_DATABASE_H_ #include <memory> #include <string> @@ -145,4 +145,4 @@ class LegacyStrikeDatabase : public KeyedService { } // namespace autofill -#endif // COMPONENTS_AUTOFILL_CORE_BROWSER_LEGACY_STRIKE_DATABASE_H_ +#endif // COMPONENTS_AUTOFILL_CORE_BROWSER_PAYMENTS_LEGACY_STRIKE_DATABASE_H_ diff --git a/chromium/components/autofill/core/browser/legacy_strike_database_unittest.cc b/chromium/components/autofill/core/browser/payments/legacy_strike_database_unittest.cc index 44e60a4ae0c..cbcd36eb25b 100644 --- a/chromium/components/autofill/core/browser/legacy_strike_database_unittest.cc +++ b/chromium/components/autofill/core/browser/payments/legacy_strike_database_unittest.cc @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "components/autofill/core/browser/legacy_strike_database.h" +#include "components/autofill/core/browser/payments/legacy_strike_database.h" #include <utility> #include <vector> diff --git a/chromium/components/autofill/core/browser/legal_message_line.cc b/chromium/components/autofill/core/browser/payments/legal_message_line.cc index dc28aebb703..b18bc273c41 100644 --- a/chromium/components/autofill/core/browser/legal_message_line.cc +++ b/chromium/components/autofill/core/browser/payments/legal_message_line.cc @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "components/autofill/core/browser/legal_message_line.h" +#include "components/autofill/core/browser/payments/legal_message_line.h" #include "base/i18n/message_formatter.h" #include "base/logging.h" @@ -78,63 +78,70 @@ LegalMessageLine::LegalMessageLine(const LegalMessageLine& other) = default; LegalMessageLine::~LegalMessageLine() {} // static -bool LegalMessageLine::Parse(const base::DictionaryValue& legal_message, +bool LegalMessageLine::Parse(const base::Value& legal_message, LegalMessageLines* out, bool escape_apostrophes) { - const base::ListValue* lines_list = nullptr; - if (legal_message.GetList("line", &lines_list)) { + DCHECK(legal_message.is_dict()); + const base::Value* lines_list = + legal_message.FindKeyOfType("line", base::Value::Type::LIST); + if (lines_list) { LegalMessageLines lines; - lines.reserve(lines_list->GetSize()); - for (size_t i = 0; i < lines_list->GetSize(); ++i) { + lines.reserve(lines_list->GetList().size()); + for (const base::Value& single_line : lines_list->GetList()) { lines.emplace_back(LegalMessageLine()); - const base::DictionaryValue* single_line; - if (!lines_list->GetDictionary(i, &single_line) || - !lines.back().ParseLine(*single_line, escape_apostrophes)) + if (!single_line.is_dict() || + !lines.back().ParseLine(single_line, escape_apostrophes)) return false; } out->swap(lines); } - return true; } -bool LegalMessageLine::ParseLine(const base::DictionaryValue& line, +bool LegalMessageLine::ParseLine(const base::Value& line, bool escape_apostrophes) { DCHECK(text_.empty()); DCHECK(links_.empty()); + DCHECK(line.is_dict()); // |display_texts| elements are the strings that will be substituted for // "{0}", "{1}", etc. in the template string. std::vector<base::string16> display_texts; // Process all the template parameters. - const base::ListValue* template_parameters = nullptr; - if (line.GetList("template_parameter", &template_parameters)) { - display_texts.resize(template_parameters->GetSize()); - links_.reserve(template_parameters->GetSize()); - - for (size_t parameter_index = 0; - parameter_index < template_parameters->GetSize(); ++parameter_index) { - const base::DictionaryValue* single_parameter; - std::string url; - if (!template_parameters->GetDictionary(parameter_index, - &single_parameter) || - !single_parameter->GetString("display_text", - &display_texts[parameter_index]) || - !single_parameter->GetString("url", &url)) + const base::Value* template_parameters = + line.FindKeyOfType("template_parameter", base::Value::Type::LIST); + if (template_parameters) { + const base::Value::ListStorage& template_parameters_storage = + template_parameters->GetList(); + display_texts.reserve(template_parameters_storage.size()); + links_.reserve(template_parameters_storage.size()); + + for (const base::Value& parameter : template_parameters_storage) { + if (!parameter.is_dict()) + return false; + + const std::string* display_text = parameter.FindStringKey("display_text"); + if (!display_text) + return false; + + const std::string* url = parameter.FindStringKey("url"); + if (!url) return false; - links_.emplace_back(0, 0, url); + display_texts.push_back(base::UTF8ToUTF16(*display_text)); + links_.emplace_back(0, 0, *url); } } // Read the template string. It's a small subset of the ICU message format // syntax. - base::string16 template_icu; - if (!line.GetString("template", &template_icu)) + const std::string* template_icu_utf8 = line.FindStringKey("template"); + if (!template_icu_utf8) return false; + base::string16 template_icu = base::UTF8ToUTF16(*template_icu_utf8); if (escape_apostrophes) { // The ICU standard counts "'{" as beginning an escaped string literal, even // if there's no closing apostrophe. This fails legal message templates diff --git a/chromium/components/autofill/core/browser/legal_message_line.h b/chromium/components/autofill/core/browser/payments/legal_message_line.h index 141ea92dd70..4d9f2659be5 100644 --- a/chromium/components/autofill/core/browser/legal_message_line.h +++ b/chromium/components/autofill/core/browser/payments/legal_message_line.h @@ -2,8 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#ifndef COMPONENTS_AUTOFILL_CORE_BROWSER_LEGAL_MESSAGE_LINE_H_ -#define COMPONENTS_AUTOFILL_CORE_BROWSER_LEGAL_MESSAGE_LINE_H_ +#ifndef COMPONENTS_AUTOFILL_CORE_BROWSER_PAYMENTS_LEGAL_MESSAGE_LINE_H_ +#define COMPONENTS_AUTOFILL_CORE_BROWSER_PAYMENTS_LEGAL_MESSAGE_LINE_H_ #include <string> #include <vector> @@ -15,7 +15,7 @@ #include "url/gurl.h" namespace base { -class DictionaryValue; +class Value; } namespace autofill { @@ -68,7 +68,9 @@ class LegalMessageLine { // text in MessageFormat, "'{0}" gets treated as a literal. To avoid // situations like these, setting |escape_apostrophes| to true will escape // all ASCII apostrophes by doubling them up. - static bool Parse(const base::DictionaryValue& legal_message, + // + // |legal_message| must be a base::Value of type DICTIONARY. + static bool Parse(const base::Value& legal_message, LegalMessageLines* out, bool escape_apostrophes = false); @@ -78,7 +80,7 @@ class LegalMessageLine { private: friend class TestLegalMessageLine; - bool ParseLine(const base::DictionaryValue& line, bool escape_apostrophes); + bool ParseLine(const base::Value& line, bool escape_apostrophes); base::string16 text_; std::vector<Link> links_; @@ -86,4 +88,4 @@ class LegalMessageLine { } // namespace autofill -#endif // COMPONENTS_AUTOFILL_CORE_BROWSER_LEGAL_MESSAGE_LINE_H_ +#endif // COMPONENTS_AUTOFILL_CORE_BROWSER_PAYMENTS_LEGAL_MESSAGE_LINE_H_ diff --git a/chromium/components/autofill/core/browser/legal_message_line_unittest.cc b/chromium/components/autofill/core/browser/payments/legal_message_line_unittest.cc index 6a5c5ba8fd8..d5a10a1b5cc 100644 --- a/chromium/components/autofill/core/browser/legal_message_line_unittest.cc +++ b/chromium/components/autofill/core/browser/payments/legal_message_line_unittest.cc @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "components/autofill/core/browser/legal_message_line.h" +#include "components/autofill/core/browser/payments/legal_message_line.h" #include <memory> #include <string> @@ -103,15 +103,12 @@ class LegalMessageLineTest : public ::testing::TestWithParam<TestCase> { // Verifies that legal message parsing is correct. TEST_P(LegalMessageLineTest, Parsing) { - std::unique_ptr<base::Value> value( - base::JSONReader::ReadDeprecated(GetParam().message_json)); + base::Optional<base::Value> value( + base::JSONReader::Read(GetParam().message_json)); ASSERT_TRUE(value); - base::DictionaryValue* dictionary = nullptr; - EXPECT_TRUE(value->GetAsDictionary(&dictionary)); - ASSERT_TRUE(dictionary); + ASSERT_TRUE(value->is_dict()); LegalMessageLines actual_lines; - LegalMessageLine::Parse(*dictionary, &actual_lines, - GetParam().escape_apostrophes); + LegalMessageLine::Parse(*value, &actual_lines, GetParam().escape_apostrophes); EXPECT_EQ(GetParam().expected_lines, actual_lines); } diff --git a/chromium/components/autofill/core/browser/local_card_migration_manager.cc b/chromium/components/autofill/core/browser/payments/local_card_migration_manager.cc index f77d16d7bde..a9ce3821024 100644 --- a/chromium/components/autofill/core/browser/local_card_migration_manager.cc +++ b/chromium/components/autofill/core/browser/payments/local_card_migration_manager.cc @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "components/autofill/core/browser/local_card_migration_manager.h" +#include "components/autofill/core/browser/payments/local_card_migration_manager.h" #include <stddef.h> @@ -22,6 +22,7 @@ #include "components/autofill/core/browser/payments/payments_util.h" #include "components/autofill/core/browser/personal_data_manager.h" #include "components/autofill/core/common/autofill_features.h" +#include "components/autofill/core/common/autofill_payments_features.h" #include "components/autofill/core/common/autofill_prefs.h" #include "services/identity/public/cpp/identity_manager.h" @@ -190,38 +191,9 @@ void LocalCardMigrationManager::OnUserDeletedLocalCardViaMigrationDialog( } bool LocalCardMigrationManager::IsCreditCardMigrationEnabled() { - // Confirm that the user is signed in, syncing, and the proper experiment - // flags are enabled. - bool migration_experiment_enabled = - features::GetLocalCardMigrationExperimentalFlag() != - features::LocalCardMigrationExperimentalFlag::kMigrationDisabled; - - // If |observer_for_testing_| is set, assume we are in a browsertest and - // credit card upload should be enabled by default. Cannot get around this as - // Chrome OS testing requires an unsupported email domain (i.e. - // stub-user@example.com). - bool credit_card_upload_enabled = - observer_for_testing_ || - ::autofill::IsCreditCardUploadEnabled( - client_->GetPrefs(), client_->GetSyncService(), - personal_data_manager_->GetAccountInfoForPaymentsServer().email); - - bool has_google_payments_account = - (payments::GetBillingCustomerId(personal_data_manager_, - payments_client_->GetPrefService()) != 0); - - AutofillSyncSigninState sync_state = - personal_data_manager_->GetSyncSigninState(); - - return migration_experiment_enabled && credit_card_upload_enabled && - has_google_payments_account && - // User signed-in and turned sync on. - (sync_state == AutofillSyncSigninState::kSignedInAndSyncFeature || - // User signed-in but not turned on sync. - (sync_state == AutofillSyncSigninState:: - kSignedInAndWalletSyncTransportEnabled && - base::FeatureList::IsEnabled( - features::kAutofillEnableLocalCardMigrationForNonSyncUser))); + return ::autofill::IsCreditCardMigrationEnabled( + personal_data_manager_, client_->GetPrefs(), client_->GetSyncService(), + /*is_test_mode=*/observer_for_testing_); } void LocalCardMigrationManager::OnDidGetUploadDetails( @@ -337,8 +309,8 @@ void LocalCardMigrationManager::SendMigrateLocalCardsRequest() { observer_for_testing_->OnSentMigrateCardsRequest(); migration_request_.app_locale = app_locale_; - migration_request_.billing_customer_number = payments::GetBillingCustomerId( - personal_data_manager_, payments_client_->GetPrefService()); + migration_request_.billing_customer_number = + payments::GetBillingCustomerId(personal_data_manager_); payments_client_->MigrateCards( migration_request_, migratable_credit_cards_, base::BindOnce(&LocalCardMigrationManager::OnDidMigrateLocalCards, @@ -390,8 +362,7 @@ int LocalCardMigrationManager::GetDetectedValues() const { // Local card migration should ONLY be offered when the user already has a // Google Payments account. - DCHECK_NE(0, payments::GetBillingCustomerId( - personal_data_manager_, payments_client_->GetPrefService())); + DCHECK_NE(0, payments::GetBillingCustomerId(personal_data_manager_)); detected_values |= CreditCardSaveManager::DetectedValue::HAS_GOOGLE_PAYMENTS_ACCOUNT; diff --git a/chromium/components/autofill/core/browser/local_card_migration_manager.h b/chromium/components/autofill/core/browser/payments/local_card_migration_manager.h index 02365d324a1..9c12b4ec0b0 100644 --- a/chromium/components/autofill/core/browser/local_card_migration_manager.h +++ b/chromium/components/autofill/core/browser/payments/local_card_migration_manager.h @@ -2,8 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#ifndef COMPONENTS_AUTOFILL_CORE_BROWSER_LOCAL_CARD_MIGRATION_MANAGER_H_ -#define COMPONENTS_AUTOFILL_CORE_BROWSER_LOCAL_CARD_MIGRATION_MANAGER_H_ +#ifndef COMPONENTS_AUTOFILL_CORE_BROWSER_PAYMENTS_LOCAL_CARD_MIGRATION_MANAGER_H_ +#define COMPONENTS_AUTOFILL_CORE_BROWSER_PAYMENTS_LOCAL_CARD_MIGRATION_MANAGER_H_ #include <memory> #include <string> @@ -13,7 +13,7 @@ #include "base/strings/string16.h" #include "components/autofill/core/browser/autofill_client.h" #include "components/autofill/core/browser/autofill_metrics.h" -#include "components/autofill/core/browser/local_card_migration_strike_database.h" +#include "components/autofill/core/browser/payments/local_card_migration_strike_database.h" #include "components/autofill/core/browser/payments/payments_client.h" namespace autofill { @@ -222,4 +222,4 @@ class LocalCardMigrationManager { } // namespace autofill -#endif // COMPONENTS_AUTOFILL_CORE_BROWSER_LOCAL_CARD_MIGRATION_MANAGER_H_ +#endif // COMPONENTS_AUTOFILL_CORE_BROWSER_PAYMENTS_LOCAL_CARD_MIGRATION_MANAGER_H_ diff --git a/chromium/components/autofill/core/browser/local_card_migration_manager_unittest.cc b/chromium/components/autofill/core/browser/payments/local_card_migration_manager_unittest.cc index 9e6e3a98e10..00b217d4483 100644 --- a/chromium/components/autofill/core/browser/local_card_migration_manager_unittest.cc +++ b/chromium/components/autofill/core/browser/payments/local_card_migration_manager_unittest.cc @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "components/autofill/core/browser/local_card_migration_manager.h" +#include "components/autofill/core/browser/payments/local_card_migration_manager.h" #include <stddef.h> @@ -27,6 +27,9 @@ #include "components/autofill/core/browser/autofill_test_utils.h" #include "components/autofill/core/browser/credit_card.h" #include "components/autofill/core/browser/mock_autocomplete_history_manager.h" +#include "components/autofill/core/browser/payments/payments_customer_data.h" +#include "components/autofill/core/browser/payments/test_credit_card_save_manager.h" +#include "components/autofill/core/browser/payments/test_local_card_migration_manager.h" #include "components/autofill/core/browser/payments/test_payments_client.h" #include "components/autofill/core/browser/personal_data_manager.h" #include "components/autofill/core/browser/sync_utils.h" @@ -34,14 +37,13 @@ #include "components/autofill/core/browser/test_autofill_clock.h" #include "components/autofill/core/browser/test_autofill_driver.h" #include "components/autofill/core/browser/test_autofill_manager.h" -#include "components/autofill/core/browser/test_credit_card_save_manager.h" #include "components/autofill/core/browser/test_form_data_importer.h" -#include "components/autofill/core/browser/test_local_card_migration_manager.h" #include "components/autofill/core/browser/test_personal_data_manager.h" #include "components/autofill/core/browser/validation.h" #include "components/autofill/core/browser/webdata/autofill_webdata_service.h" #include "components/autofill/core/common/autofill_clock.h" #include "components/autofill/core/common/autofill_features.h" +#include "components/autofill/core/common/autofill_payments_features.h" #include "components/autofill/core/common/autofill_prefs.h" #include "components/autofill/core/common/form_data.h" #include "components/autofill/core/common/form_field_data.h" @@ -71,7 +73,7 @@ class LocalCardMigrationManagerTest : public testing::Test { base::ThreadTaskRunnerHandle::Get()); autofill_driver_->SetURLRequestContext(request_context_.get()); payments_client_ = new payments::TestPaymentsClient( - autofill_driver_->GetURLLoaderFactory(), autofill_client_.GetPrefs(), + autofill_driver_->GetURLLoaderFactory(), autofill_client_.GetIdentityManager(), &personal_data_); autofill_client_.set_test_payments_client( std::unique_ptr<payments::TestPaymentsClient>(payments_client_)); @@ -188,10 +190,11 @@ TEST_F(LocalCardMigrationManagerTest, scoped_feature_list_.InitAndEnableFeature( features::kAutofillCreditCardLocalCardMigration); - // Set the billing_customer_number Priority Preference to designate - // existence of a Payments account. - autofill_client_.GetPrefs()->SetDouble(prefs::kAutofillBillingCustomerNumber, - 12345); + // Set the billing_customer_number to designate existence of a Payments + // account. + personal_data_.SetPaymentsCustomerData( + std::make_unique<PaymentsCustomerData>(/*customer_id=*/"123456")); + // Add a local credit card whose |TypeAndLastFourDigits| matches what we will // enter below. AddLocalCreditCard(personal_data_, "Flo Master", "4111111111111111", "11", @@ -222,10 +225,11 @@ TEST_F(LocalCardMigrationManagerTest, scoped_feature_list_.InitAndEnableFeature( features::kAutofillCreditCardLocalCardMigration); - // Set the billing_customer_number Priority Preference to designate - // existence of a Payments account. - autofill_client_.GetPrefs()->SetDouble(prefs::kAutofillBillingCustomerNumber, - 12345); + // Set the billing_customer_number to designate existence of a Payments + // account. + personal_data_.SetPaymentsCustomerData( + std::make_unique<PaymentsCustomerData>(/*customer_id=*/"123456")); + // Add a local credit card (but it will not match what we will enter below). AddLocalCreditCard(personal_data_, "Flo Master", "4111111111111111", "11", test::NextYear().c_str(), "1", "guid1"); @@ -253,10 +257,11 @@ TEST_F(LocalCardMigrationManagerTest, scoped_feature_list_.InitAndEnableFeature( features::kAutofillCreditCardLocalCardMigration); - // Set the billing_customer_number Priority Preference to designate - // existence of a Payments account. - autofill_client_.GetPrefs()->SetDouble(prefs::kAutofillBillingCustomerNumber, - 12345); + // Set the billing_customer_number to designate existence of a Payments + // account. + personal_data_.SetPaymentsCustomerData( + std::make_unique<PaymentsCustomerData>(/*customer_id=*/"123456")); + // Add a local credit card whose |TypeAndLastFourDigits| matches what we will // enter below. AddLocalCreditCard(personal_data_, "Flo Master", "4111111111111111", "11", @@ -300,10 +305,11 @@ TEST_F(LocalCardMigrationManagerTest, scoped_feature_list_.InitAndEnableFeature( features::kAutofillCreditCardLocalCardMigration); - // Set the billing_customer_number Priority Preference to designate - // existence of a Payments account. - autofill_client_.GetPrefs()->SetDouble(prefs::kAutofillBillingCustomerNumber, - 12345); + // Set the billing_customer_number to designate existence of a Payments + // account. + personal_data_.SetPaymentsCustomerData( + std::make_unique<PaymentsCustomerData>(/*customer_id=*/"123456")); + // Add a local credit card whose |TypeAndLastFourDigits| matches what we will // enter below. AddLocalCreditCard(personal_data_, "Flo Master", "4111111111111111", "11", @@ -334,10 +340,11 @@ TEST_F(LocalCardMigrationManagerTest, scoped_feature_list_.InitAndEnableFeature( features::kAutofillCreditCardLocalCardMigration); - // Set the billing_customer_number Priority Preference to designate - // existence of a Payments account. - autofill_client_.GetPrefs()->SetDouble(prefs::kAutofillBillingCustomerNumber, - 12345); + // Set the billing_customer_number to designate existence of a Payments + // account. + personal_data_.SetPaymentsCustomerData( + std::make_unique<PaymentsCustomerData>(/*customer_id=*/"123456")); + // Add a masked server credit card whose |TypeAndLastFourDigits| matches what // we will enter below. CreditCard credit_card(CreditCard::MASKED_SERVER_CARD, "a123"); @@ -384,10 +391,11 @@ TEST_F(LocalCardMigrationManagerTest, scoped_feature_list_.InitAndEnableFeature( features::kAutofillCreditCardLocalCardMigration); - // Set the billing_customer_number Priority Preference to designate - // existence of a Payments account. - autofill_client_.GetPrefs()->SetDouble(prefs::kAutofillBillingCustomerNumber, - 12345); + // Set the billing_customer_number to designate existence of a Payments + // account. + personal_data_.SetPaymentsCustomerData( + std::make_unique<PaymentsCustomerData>(/*customer_id=*/"123456")); + // Add a masked credit card whose |TypeAndLastFourDigits| matches what we will // enter below. CreditCard credit_card(CreditCard::MASKED_SERVER_CARD, "a123"); @@ -427,10 +435,11 @@ TEST_F(LocalCardMigrationManagerTest, MigrateCreditCard_FeatureNotEnabled) { scoped_feature_list_.InitAndDisableFeature( features::kAutofillCreditCardLocalCardMigration); - // Set the billing_customer_number Priority Preference to designate - // existence of a Payments account. - autofill_client_.GetPrefs()->SetDouble(prefs::kAutofillBillingCustomerNumber, - 12345); + // Set the billing_customer_number to designate existence of a Payments + // account. + personal_data_.SetPaymentsCustomerData( + std::make_unique<PaymentsCustomerData>(/*customer_id=*/"123456")); + // Add a local credit card whose |TypeAndLastFourDigits| matches what we will // enter below. AddLocalCreditCard(personal_data_, "Flo Master", "4111111111111111", "11", @@ -460,10 +469,10 @@ TEST_F(LocalCardMigrationManagerTest, MigrateCreditCard_SignInOnlyWhenExpOff) { // Disabled {features::kAutofillEnableLocalCardMigrationForNonSyncUser}); - // Set the billing_customer_number Priority Preference to designate - // existence of a Payments account. - autofill_client_.GetPrefs()->SetDouble(prefs::kAutofillBillingCustomerNumber, - 12345); + // Set the billing_customer_number to designate existence of a Payments + // account. + personal_data_.SetPaymentsCustomerData( + std::make_unique<PaymentsCustomerData>(/*customer_id=*/"123456")); // Mock Chrome Sync is disabled. local_card_migration_manager_->ResetSyncState( @@ -499,10 +508,10 @@ TEST_F(LocalCardMigrationManagerTest, MigrateCreditCard_SignInOnlyWhenExpOn) { // Disabled {}); - // Set the billing_customer_number Priority Preference to designate - // existence of a Payments account. - autofill_client_.GetPrefs()->SetDouble(prefs::kAutofillBillingCustomerNumber, - 12345); + // Set the billing_customer_number to designate existence of a Payments + // account. + personal_data_.SetPaymentsCustomerData( + std::make_unique<PaymentsCustomerData>(/*customer_id=*/"123456")); // Mock Chrome Sync is disabled. local_card_migration_manager_->ResetSyncState( @@ -561,10 +570,11 @@ TEST_F(LocalCardMigrationManagerTest, scoped_feature_list_.InitAndEnableFeature( features::kAutofillCreditCardLocalCardMigration); - // Set the billing_customer_number Priority Preference to designate - // existence of a Payments account. - autofill_client_.GetPrefs()->SetDouble(prefs::kAutofillBillingCustomerNumber, - 12345); + // Set the billing_customer_number to designate existence of a Payments + // account. + personal_data_.SetPaymentsCustomerData( + std::make_unique<PaymentsCustomerData>(/*customer_id=*/"123456")); + // Add a masked server card whose |TypeAndLastFourDigits| matches a local // card. CreditCard server_card(CreditCard::MASKED_SERVER_CARD, "a123"); @@ -599,10 +609,11 @@ TEST_F(LocalCardMigrationManagerTest, scoped_feature_list_.InitAndEnableFeature( features::kAutofillCreditCardLocalCardMigration); - // Set the billing_customer_number Priority Preference to designate - // existence of a Payments account. - autofill_client_.GetPrefs()->SetDouble(prefs::kAutofillBillingCustomerNumber, - 12345); + // Set the billing_customer_number to designate existence of a Payments + // account. + personal_data_.SetPaymentsCustomerData( + std::make_unique<PaymentsCustomerData>(/*customer_id=*/"123456")); + // Add a full server card whose number matches a local card. CreditCard server_card(CreditCard::FULL_SERVER_CARD, "a123"); test::SetCreditCardInfo(&server_card, "Flo Master", "4111111111111111", "11", @@ -632,10 +643,11 @@ TEST_F(LocalCardMigrationManagerTest, GetDetectedValues_AllWithCardHolderName) { scoped_feature_list_.InitAndEnableFeature( features::kAutofillCreditCardLocalCardMigration); - // Set the billing_customer_number Priority Preference to designate - // existence of a Payments account. - autofill_client_.GetPrefs()->SetDouble(prefs::kAutofillBillingCustomerNumber, - 12345); + // Set the billing_customer_number to designate existence of a Payments + // account. + personal_data_.SetPaymentsCustomerData( + std::make_unique<PaymentsCustomerData>(/*customer_id=*/"123456")); + // Add a local credit card whose |TypeAndLastFourDigits| matches what we will // enter below. AddLocalCreditCard(personal_data_, "Flo Master", "4111111111111111", "11", @@ -665,10 +677,11 @@ TEST_F(LocalCardMigrationManagerTest, scoped_feature_list_.InitAndEnableFeature( features::kAutofillCreditCardLocalCardMigration); - // Set the billing_customer_number Priority Preference to designate - // existence of a Payments account. - autofill_client_.GetPrefs()->SetDouble(prefs::kAutofillBillingCustomerNumber, - 12345); + // Set the billing_customer_number to designate existence of a Payments + // account. + personal_data_.SetPaymentsCustomerData( + std::make_unique<PaymentsCustomerData>(/*customer_id=*/"123456")); + // Add a local credit card whose |TypeAndLastFourDigits| matches what we will // enter below. AddLocalCreditCard(personal_data_, "Flo Master", "4111111111111111", "11", @@ -697,10 +710,11 @@ TEST_F(LocalCardMigrationManagerTest, scoped_feature_list_.InitAndEnableFeature( features::kAutofillCreditCardLocalCardMigration); - // Set the billing_customer_number Priority Preference to designate - // existence of a Payments account. - autofill_client_.GetPrefs()->SetDouble(prefs::kAutofillBillingCustomerNumber, - 12345); + // Set the billing_customer_number to designate existence of a Payments + // account. + personal_data_.SetPaymentsCustomerData( + std::make_unique<PaymentsCustomerData>(/*customer_id=*/"123456")); + // Add a local credit card whose |TypeAndLastFourDigits| matches what we will // enter below. AddLocalCreditCard(personal_data_, "Flo Master", "4111111111111111", "11", @@ -729,10 +743,11 @@ TEST_F(LocalCardMigrationManagerTest, scoped_feature_list_.InitAndEnableFeature( features::kAutofillCreditCardLocalCardMigration); - // Set the billing_customer_number Priority Preference to designate - // existence of a Payments account. - autofill_client_.GetPrefs()->SetDouble(prefs::kAutofillBillingCustomerNumber, - 12345); + // Set the billing_customer_number to designate existence of a Payments + // account. + personal_data_.SetPaymentsCustomerData( + std::make_unique<PaymentsCustomerData>(/*customer_id=*/"123456")); + // Add a local credit card whose |TypeAndLastFourDigits| matches what we will // enter below. AddLocalCreditCard(personal_data_, "Flo Master", "4111111111111111", "11", @@ -763,10 +778,11 @@ TEST_F(LocalCardMigrationManagerTest, scoped_feature_list_.InitAndEnableFeature( features::kAutofillCreditCardLocalCardMigration); - // Set the billing_customer_number Priority Preference to designate - // existence of a Payments account. - autofill_client_.GetPrefs()->SetDouble(prefs::kAutofillBillingCustomerNumber, - 12345); + // Set the billing_customer_number to designate existence of a Payments + // account. + personal_data_.SetPaymentsCustomerData( + std::make_unique<PaymentsCustomerData>(/*customer_id=*/"123456")); + // Add a local credit card whose |TypeAndLastFourDigits| matches what we will // enter below. AddLocalCreditCard(personal_data_, "Flo Master", "4111111111111111", "11", @@ -797,10 +813,11 @@ TEST_F(LocalCardMigrationManagerTest, scoped_feature_list_.InitAndEnableFeature( features::kAutofillCreditCardLocalCardMigration); - // Set the billing_customer_number Priority Preference to designate - // existence of a Payments account. - autofill_client_.GetPrefs()->SetDouble(prefs::kAutofillBillingCustomerNumber, - 12345); + // Set the billing_customer_number to designate existence of a Payments + // account. + personal_data_.SetPaymentsCustomerData( + std::make_unique<PaymentsCustomerData>(/*customer_id=*/"123456")); + // Add a local credit card. One migratable credit card will still trigger // migration on settings page. AddLocalCreditCard(personal_data_, "Flo Master", "4111111111111111", "11", @@ -827,10 +844,11 @@ TEST_F(LocalCardMigrationManagerTest, scoped_feature_list_.InitAndEnableFeature( features::kAutofillCreditCardLocalCardMigration); - // Set the billing_customer_number Priority Preference to designate - // existence of a Payments account. - autofill_client_.GetPrefs()->SetDouble(prefs::kAutofillBillingCustomerNumber, - 12345); + // Set the billing_customer_number to designate existence of a Payments + // account. + personal_data_.SetPaymentsCustomerData( + std::make_unique<PaymentsCustomerData>(/*customer_id=*/"123456")); + // Add a local credit card. One migratable credit card will still trigger // migration on settings page. AddLocalCreditCard(personal_data_, "Flo Master", "4111111111111111", "11", @@ -867,10 +885,11 @@ TEST_F(LocalCardMigrationManagerTest, scoped_feature_list_.InitAndEnableFeature( features::kAutofillCreditCardLocalCardMigration); - // Set the billing_customer_number Priority Preference to designate - // existence of a Payments account. - autofill_client_.GetPrefs()->SetDouble(prefs::kAutofillBillingCustomerNumber, - 12345); + // Set the billing_customer_number to designate existence of a Payments + // account. + personal_data_.SetPaymentsCustomerData( + std::make_unique<PaymentsCustomerData>(/*customer_id=*/"123456")); + // Add a local credit card whose |TypeAndLastFourDigits| matches what we will // enter below. AddLocalCreditCard(personal_data_, "Flo Master", "4111111111111111", "11", @@ -899,10 +918,10 @@ TEST_F(LocalCardMigrationManagerTest, scoped_feature_list_.InitAndEnableFeature( features::kAutofillCreditCardLocalCardMigration); - // Set the billing_customer_number Priority Preference to designate - // existence of a Payments account. - autofill_client_.GetPrefs()->SetDouble(prefs::kAutofillBillingCustomerNumber, - 12345); + // Set the billing_customer_number to designate existence of a Payments + // account. + personal_data_.SetPaymentsCustomerData( + std::make_unique<PaymentsCustomerData>(/*customer_id=*/"123456")); // Set that previously user rejected this prompt. prefs::SetLocalCardMigrationPromptPreviouslyCancelled( @@ -937,10 +956,11 @@ TEST_F(LocalCardMigrationManagerTest, MigrateCreditCard_MigrationSuccess) { scoped_feature_list_.InitAndEnableFeature( features::kAutofillCreditCardLocalCardMigration); - // Set the billing_customer_number Priority Preference to designate - // existence of a Payments account. - autofill_client_.GetPrefs()->SetDouble(prefs::kAutofillBillingCustomerNumber, - 12345); + // Set the billing_customer_number to designate existence of a Payments + // account. + personal_data_.SetPaymentsCustomerData( + std::make_unique<PaymentsCustomerData>(/*customer_id=*/"123456")); + // Add a local credit card for migration. AddLocalCreditCard(personal_data_, "Flo Master", "4111111111111111", "11", test::NextYear().c_str(), "1", "guid1"); @@ -979,10 +999,11 @@ TEST_F(LocalCardMigrationManagerTest, scoped_feature_list_.InitAndEnableFeature( features::kAutofillCreditCardLocalCardMigration); - // Set the billing_customer_number Priority Preference to designate - // existence of a Payments account. - autofill_client_.GetPrefs()->SetDouble(prefs::kAutofillBillingCustomerNumber, - 12345); + // Set the billing_customer_number to designate existence of a Payments + // account. + personal_data_.SetPaymentsCustomerData( + std::make_unique<PaymentsCustomerData>(/*customer_id=*/"123456")); + // Add a local credit card. One migratable credit card will still trigger // migration on settings page. AddLocalCreditCard(personal_data_, "Flo Master", "4111111111111111", "11", @@ -1023,10 +1044,11 @@ TEST_F(LocalCardMigrationManagerTest, scoped_feature_list_.InitAndEnableFeature( features::kAutofillCreditCardLocalCardMigration); - // Set the billing_customer_number Priority Preference to designate - // existence of a Payments account. - autofill_client_.GetPrefs()->SetDouble(prefs::kAutofillBillingCustomerNumber, - 12345); + // Set the billing_customer_number to designate existence of a Payments + // account. + personal_data_.SetPaymentsCustomerData( + std::make_unique<PaymentsCustomerData>(/*customer_id=*/"123456")); + // Add a local credit card. One migratable credit card will still trigger // migration on settings page. AddLocalCreditCard(personal_data_, "Flo Master", "4111111111111111", "11", @@ -1068,8 +1090,11 @@ TEST_F(LocalCardMigrationManagerTest, MigrateCreditCard_ToggleIsChosen) { test::NextYear().c_str(), "1", "guid1"); AddLocalCreditCard(personal_data_, "Flo Master", "5454545454545454", "11", test::NextYear().c_str(), "1", "guid2"); - autofill_client_.GetPrefs()->SetDouble(prefs::kAutofillBillingCustomerNumber, - 12345); + // Set the billing_customer_number to designate existence of a Payments + // account. + personal_data_.SetPaymentsCustomerData( + std::make_unique<PaymentsCustomerData>(/*customer_id=*/"123456")); + local_card_migration_manager_->GetMigratableCreditCards(); autofill_client_.set_migration_card_selections( @@ -1117,10 +1142,11 @@ TEST_F(LocalCardMigrationManagerTest, EXPECT_EQ(local_card_migration_strike_database.GetStrikes(), 7); - // Set the billing_customer_number Priority Preference to designate - // existence of a Payments account. - autofill_client_.GetPrefs()->SetDouble(prefs::kAutofillBillingCustomerNumber, - 12345); + // Set the billing_customer_number to designate existence of a Payments + // account. + personal_data_.SetPaymentsCustomerData( + std::make_unique<PaymentsCustomerData>(/*customer_id=*/"123456")); + // Add a local credit card whose |TypeAndLastFourDigits| matches what we will // enter below. AddLocalCreditCard(personal_data_, "Flo Master", "4111111111111111", "11", @@ -1166,10 +1192,10 @@ TEST_F(LocalCardMigrationManagerTest, EXPECT_EQ(local_card_migration_strike_database.GetStrikes(), 7); - // Set the billing_customer_number Priority Preference to designate - // existence of a Payments account. - autofill_client_.GetPrefs()->SetDouble(prefs::kAutofillBillingCustomerNumber, - 12345); + // Set the billing_customer_number to designate existence of a Payments + // account. + personal_data_.SetPaymentsCustomerData( + std::make_unique<PaymentsCustomerData>(/*customer_id=*/"123456")); // Add a masked server credit card whose |TypeAndLastFourDigits| matches what // we will enter below. @@ -1222,8 +1248,10 @@ TEST_F(LocalCardMigrationManagerTest, test::NextYear().c_str(), "1", "guid1"); AddLocalCreditCard(personal_data_, "Flo Master", "5454545454545454", "11", test::NextYear().c_str(), "1", "guid2"); - autofill_client_.GetPrefs()->SetDouble(prefs::kAutofillBillingCustomerNumber, - 12345); + // Set the billing_customer_number to designate existence of a Payments + // account. + personal_data_.SetPaymentsCustomerData( + std::make_unique<PaymentsCustomerData>(/*customer_id=*/"123456")); local_card_migration_manager_->GetMigratableCreditCards(); // Only select one of the two cards. @@ -1248,8 +1276,10 @@ TEST_F(LocalCardMigrationManagerTest, MigrateCreditCard_StrikeCountUMALogged) { test::NextYear().c_str(), "1", "guid1"); AddLocalCreditCard(personal_data_, "Flo Master", "5454545454545454", "11", test::NextYear().c_str(), "1", "guid2"); - autofill_client_.GetPrefs()->SetDouble(prefs::kAutofillBillingCustomerNumber, - 12345); + // Set the billing_customer_number to designate existence of a Payments + // account. + personal_data_.SetPaymentsCustomerData( + std::make_unique<PaymentsCustomerData>(/*customer_id=*/"123456")); local_card_migration_manager_->GetMigratableCreditCards(); // Add 4 LocalCardMigration strikes. diff --git a/chromium/components/autofill/core/browser/local_card_migration_strike_database.cc b/chromium/components/autofill/core/browser/payments/local_card_migration_strike_database.cc index 5c204950aa7..7cc649b6c58 100644 --- a/chromium/components/autofill/core/browser/local_card_migration_strike_database.cc +++ b/chromium/components/autofill/core/browser/payments/local_card_migration_strike_database.cc @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "components/autofill/core/browser/local_card_migration_strike_database.h" +#include "components/autofill/core/browser/payments/local_card_migration_strike_database.h" #include "components/autofill/core/browser/proto/strike_data.pb.h" diff --git a/chromium/components/autofill/core/browser/local_card_migration_strike_database.h b/chromium/components/autofill/core/browser/payments/local_card_migration_strike_database.h index 1124374313e..c63866dbd83 100644 --- a/chromium/components/autofill/core/browser/local_card_migration_strike_database.h +++ b/chromium/components/autofill/core/browser/payments/local_card_migration_strike_database.h @@ -2,13 +2,13 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#ifndef COMPONENTS_AUTOFILL_CORE_BROWSER_LOCAL_CARD_MIGRATION_STRIKE_DATABASE_H_ -#define COMPONENTS_AUTOFILL_CORE_BROWSER_LOCAL_CARD_MIGRATION_STRIKE_DATABASE_H_ +#ifndef COMPONENTS_AUTOFILL_CORE_BROWSER_PAYMENTS_LOCAL_CARD_MIGRATION_STRIKE_DATABASE_H_ +#define COMPONENTS_AUTOFILL_CORE_BROWSER_PAYMENTS_LOCAL_CARD_MIGRATION_STRIKE_DATABASE_H_ #include <string> -#include "components/autofill/core/browser/strike_database.h" -#include "components/autofill/core/browser/strike_database_integrator_base.h" +#include "components/autofill/core/browser/payments/strike_database.h" +#include "components/autofill/core/browser/payments/strike_database_integrator_base.h" namespace autofill { @@ -36,4 +36,4 @@ class LocalCardMigrationStrikeDatabase : public StrikeDatabaseIntegratorBase { } // namespace autofill -#endif // COMPONENTS_AUTOFILL_CORE_BROWSER_LOCAL_CARD_MIGRATION_STRIKE_DATABASE_H_ +#endif // COMPONENTS_AUTOFILL_CORE_BROWSER_PAYMENTS_LOCAL_CARD_MIGRATION_STRIKE_DATABASE_H_ diff --git a/chromium/components/autofill/core/browser/payments/payments_client.cc b/chromium/components/autofill/core/browser/payments/payments_client.cc index 3fda27d89e6..25fea378744 100644 --- a/chromium/components/autofill/core/browser/payments/payments_client.cc +++ b/chromium/components/autofill/core/browser/payments/payments_client.cc @@ -13,20 +13,22 @@ #include "base/json/json_reader.h" #include "base/json/json_writer.h" #include "base/strings/string_number_conversions.h" +#include "base/strings/string_split.h" #include "base/strings/string_util.h" #include "base/strings/stringprintf.h" #include "base/strings/utf_string_conversions.h" #include "base/values.h" #include "build/build_config.h" -#include "components/autofill/core/browser/account_info_getter.h" #include "components/autofill/core/browser/autofill_data_model.h" #include "components/autofill/core/browser/autofill_experiments.h" #include "components/autofill/core/browser/autofill_type.h" #include "components/autofill/core/browser/credit_card.h" -#include "components/autofill/core/browser/local_card_migration_manager.h" +#include "components/autofill/core/browser/payments/account_info_getter.h" +#include "components/autofill/core/browser/payments/local_card_migration_manager.h" #include "components/autofill/core/browser/payments/payments_request.h" #include "components/autofill/core/browser/payments/payments_service_url.h" #include "components/autofill/core/common/autofill_features.h" +#include "components/autofill/core/common/autofill_payments_features.h" #include "components/data_use_measurement/core/data_use_user_data.h" #include "components/variations/net/variations_http_headers.h" #include "net/base/escape.h" @@ -91,32 +93,6 @@ GURL GetRequestUrl(const std::string& path) { return GetBaseSecureUrl().Resolve(path); } -// Tries to get the string |out_value| from the |dictionary| with the given -// |key|. -// Returns true if the string value was found, false otherwise. -bool TryGetString(std::string key, - base::Value& dictionary, - std::string* out_value) { - base::Value* str_ptr = dictionary.FindKey(key); - if (str_ptr) { - *out_value = str_ptr->GetString(); - } - return str_ptr; -} - -// Tries to get the string |out_value| from the |dictionary| with the given -// |path|. -// Returns true if the string value was found, false otherwise. -bool TryGetStringByPath(std::initializer_list<base::StringPiece> path, - base::Value& dictionary, - std::string* out_value) { - base::Value* str_ptr = dictionary.FindPath(path); - if (str_ptr) { - *out_value = str_ptr->GetString(); - } - return str_ptr; -} - base::Value BuildCustomerContextDictionary(int64_t external_customer_id) { base::Value customer_context(base::Value::Type::DICTIONARY); customer_context.SetKey("external_customer_id", @@ -314,8 +290,9 @@ class UnmaskCardRequest : public PaymentsRequest { return request_content; } - void ParseResponse(base::Value response) override { - TryGetString("pan", response, &real_pan_); + void ParseResponse(const base::Value& response) override { + const auto* pan = response.FindStringKey("pan"); + real_pan_ = pan ? *pan : std::string(); } bool IsResponseComplete() override { return !real_pan_.empty(); } @@ -331,6 +308,8 @@ class UnmaskCardRequest : public PaymentsRequest { const std::string&)> callback_; std::string real_pan_; + + DISALLOW_COPY_AND_ASSIGN(UnmaskCardRequest); }; class GetUploadDetailsRequest : public PaymentsRequest { @@ -434,25 +413,21 @@ class GetUploadDetailsRequest : public PaymentsRequest { return request_content; } - void ParseResponse(base::Value response) override { - std::string context_token_utf8; - if (TryGetString("context_token", response, &context_token_utf8)) { - context_token_ = base::UTF8ToUTF16(context_token_utf8); - } + void ParseResponse(const base::Value& response) override { + const auto* context_token = response.FindStringKey("context_token"); + context_token_ = + context_token ? base::UTF8ToUTF16(*context_token) : base::string16(); - base::Value* dictionary_value = response.FindKey("legal_message"); + const base::Value* dictionary_value = + response.FindKeyOfType("legal_message", base::Value::Type::DICTIONARY); if (dictionary_value) legal_message_ = std::make_unique<base::Value>(dictionary_value->Clone()); - base::Value* list_ptr = response.FindKey("supported_card_bin_ranges"); - if (list_ptr && list_ptr->is_list()) { - for (base::Value& result : list_ptr->GetList()) { - DCHECK(result.is_dict()); - base::Optional<int> start = response.FindIntKey("start"); - base::Optional<int> end = response.FindIntKey("end"); - supported_card_bin_ranges_.push_back(std::make_pair(*start, *end)); - } - } + const auto* supported_card_bin_ranges_string = + response.FindStringKey("supported_card_bin_ranges_string"); + supported_card_bin_ranges_ = ParseSupportedCardBinRangesString( + supported_card_bin_ranges_string ? *supported_card_bin_ranges_string + : base::EmptyString()); } bool IsResponseComplete() override { @@ -465,6 +440,35 @@ class GetUploadDetailsRequest : public PaymentsRequest { } private: + // Helper for ParseResponse(). Input format should be :"1234,30000-55555,765", + // where ranges are separated by commas and items separated with a dash means + // the start and ends of the range. Items without a dash have the same start + // and end (ex. 1234-1234) + std::vector<std::pair<int, int>> ParseSupportedCardBinRangesString( + const std::string& supported_card_bin_ranges_string) { + std::vector<std::pair<int, int>> supported_card_bin_ranges; + std::vector<std::string> range_strings = + base::SplitString(supported_card_bin_ranges_string, ",", + base::TRIM_WHITESPACE, base::SPLIT_WANT_NONEMPTY); + + for (std::string& range_string : range_strings) { + std::vector<std::string> range = base::SplitString( + range_string, "-", base::TRIM_WHITESPACE, base::SPLIT_WANT_NONEMPTY); + DCHECK(range.size() <= 2); + int start; + base::StringToInt(range[0], &start); + if (range.size() == 1) { + supported_card_bin_ranges.push_back(std::make_pair(start, start)); + } else { + int end; + base::StringToInt(range[1], &end); + DCHECK_LE(start, end); + supported_card_bin_ranges.push_back(std::make_pair(start, end)); + } + } + return supported_card_bin_ranges; + } + const std::vector<AutofillProfile> addresses_; const int detected_values_; const std::vector<const char*> active_experiments_; @@ -480,6 +484,8 @@ class GetUploadDetailsRequest : public PaymentsRequest { std::vector<std::pair<int, int>> supported_card_bin_ranges_; const int billable_service_number_; PaymentsClient::UploadCardSource upload_card_source_; + + DISALLOW_COPY_AND_ASSIGN(GetUploadDetailsRequest); }; class UploadCardRequest : public PaymentsRequest { @@ -575,8 +581,10 @@ class UploadCardRequest : public PaymentsRequest { return request_content; } - void ParseResponse(base::Value response) override { - TryGetString("credit_card_id", response, &server_id_); + void ParseResponse(const base::Value& response) override { + const std::string* credit_card_id = + response.FindStringKey("credit_card_id"); + server_id_ = credit_card_id ? *credit_card_id : std::string(); } bool IsResponseComplete() override { return true; } @@ -592,6 +600,8 @@ class UploadCardRequest : public PaymentsRequest { const std::string&)> callback_; std::string server_id_; + + DISALLOW_COPY_AND_ASSIGN(UploadCardRequest); }; class MigrateCardsRequest : public PaymentsRequest { @@ -666,26 +676,27 @@ class MigrateCardsRequest : public PaymentsRequest { return request_content; } - void ParseResponse(base::Value response) override { - base::Value* list_ptr = response.FindKey("save_result"); - if (!list_ptr || !list_ptr->is_list()) + void ParseResponse(const base::Value& response) override { + const auto* found_list = + response.FindKeyOfType("save_result", base::Value::Type::LIST); + if (!found_list) return; + save_result_ = std::make_unique<std::unordered_map<std::string, std::string>>(); - - for (base::Value& result : list_ptr->GetList()) { + for (const base::Value& result : found_list->GetList()) { if (result.is_dict()) { - std::string unique_id; - TryGetString("unique_id", result, &unique_id); - - std::string save_result; - TryGetString("status", result, &save_result); - - save_result_->insert(std::make_pair(unique_id, save_result)); + const std::string* unique_id = result.FindStringKey("unique_id"); + const std::string* status = result.FindStringKey("status"); + save_result_->insert( + std::make_pair(unique_id ? *unique_id : std::string(), + status ? *status : std::string())); } } - TryGetString("value_prop_display_text", response, &display_text_); + const std::string* display_text = + response.FindStringKey("value_prop_display_text"); + display_text_ = display_text ? *display_text : std::string(); } bool IsResponseComplete() override { @@ -720,6 +731,8 @@ class MigrateCardsRequest : public PaymentsRequest { MigrateCardsCallback callback_; std::unique_ptr<std::unordered_map<std::string, std::string>> save_result_; std::string display_text_; + + DISALLOW_COPY_AND_ASSIGN(MigrateCardsRequest); }; } // namespace @@ -744,12 +757,10 @@ PaymentsClient::MigrationRequestDetails::~MigrationRequestDetails() {} PaymentsClient::PaymentsClient( scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory, - PrefService* pref_service, identity::IdentityManager* identity_manager, AccountInfoGetter* account_info_getter, bool is_off_the_record) : url_loader_factory_(url_loader_factory), - pref_service_(pref_service), identity_manager_(identity_manager), account_info_getter_(account_info_getter), is_off_the_record_(is_off_the_record), @@ -763,10 +774,6 @@ void PaymentsClient::Prepare() { StartTokenFetch(false); } -PrefService* PaymentsClient::GetPrefService() const { - return pref_service_; -} - void PaymentsClient::UnmaskCard( const PaymentsClient::UnmaskRequestDetails& request_details, base::OnceCallback<void(AutofillClient::PaymentsRpcResult, @@ -885,7 +892,6 @@ void PaymentsClient::OnSimpleLoaderComplete( void PaymentsClient::OnSimpleLoaderCompleteInternal(int response_code, const std::string& data) { - base::Value response_dict(base::Value::Type::DICTIONARY); VLOG(2) << "Got data: " << data; AutofillClient::PaymentsRpcResult result = AutofillClient::SUCCESS; @@ -894,13 +900,13 @@ void PaymentsClient::OnSimpleLoaderCompleteInternal(int response_code, // Valid response. case net::HTTP_OK: { std::string error_code; - std::unique_ptr<base::Value> message_value = - base::JSONReader::ReadDeprecated(data); - if (message_value.get() && message_value->is_dict()) { - response_dict = - base::Value::FromUniquePtrValue(std::move(message_value)); - TryGetStringByPath({"error", "code"}, response_dict, &error_code); - request_->ParseResponse(std::move(response_dict)); + base::Optional<base::Value> message_value = base::JSONReader::Read(data); + if (message_value && message_value->is_dict()) { + const auto* found = message_value->FindPathOfType( + {"error", "code"}, base::Value::Type::STRING); + if (found) + error_code = found->GetString(); + request_->ParseResponse(*message_value); } if (base::LowerCaseEqualsASCII(error_code, "internal")) diff --git a/chromium/components/autofill/core/browser/payments/payments_client.h b/chromium/components/autofill/core/browser/payments/payments_client.h index ad6c075aa75..9f6d6247949 100644 --- a/chromium/components/autofill/core/browser/payments/payments_client.h +++ b/chromium/components/autofill/core/browser/payments/payments_client.h @@ -13,9 +13,8 @@ #include "base/memory/weak_ptr.h" #include "components/autofill/core/browser/autofill_client.h" #include "components/autofill/core/browser/autofill_profile.h" -#include "components/autofill/core/browser/card_unmask_delegate.h" #include "components/autofill/core/browser/credit_card.h" -#include "components/prefs/pref_service.h" +#include "components/autofill/core/browser/payments/card_unmask_delegate.h" #include "google_apis/gaia/google_service_auth_error.h" #include "services/identity/public/cpp/access_token_fetcher.h" #include "services/identity/public/cpp/access_token_info.h" @@ -134,13 +133,11 @@ class PaymentsClient { }; // |url_loader_factory| is reference counted so it has no lifetime or - // ownership requirements. |pref_service| is used to get the registered - // preference value, |identity_manager| and |account_info_getter| - // must all outlive |this|. Either delegate might be nullptr. - // |is_off_the_record| denotes incognito mode. + // ownership requirements. |identity_manager| and |account_info_getter| must + // all outlive |this|. Either delegate might be nullptr. |is_off_the_record| + // denotes incognito mode. PaymentsClient( scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory, - PrefService* const pref_service, identity::IdentityManager* const identity_manager, AccountInfoGetter* const account_info_getter, bool is_off_the_record = false); @@ -154,8 +151,6 @@ class PaymentsClient { // accepted an upload prompt. void Prepare(); - PrefService* GetPrefService() const; - // The user has attempted to unmask a card with the given cvc. void UnmaskCard(const UnmaskRequestDetails& request_details, base::OnceCallback<void(AutofillClient::PaymentsRpcResult, @@ -247,9 +242,6 @@ class PaymentsClient { // The URL loader factory for the request. scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory_; - // The pref service for this client. - PrefService* const pref_service_; - // Provided in constructor; not owned by PaymentsClient. identity::IdentityManager* const identity_manager_; diff --git a/chromium/components/autofill/core/browser/payments/payments_client_unittest.cc b/chromium/components/autofill/core/browser/payments/payments_client_unittest.cc index 6f9edcede0d..620f21c128e 100644 --- a/chromium/components/autofill/core/browser/payments/payments_client_unittest.cc +++ b/chromium/components/autofill/core/browser/payments/payments_client_unittest.cc @@ -17,14 +17,13 @@ #include "base/values.h" #include "components/autofill/core/browser/autofill_experiments.h" #include "components/autofill/core/browser/autofill_test_utils.h" -#include "components/autofill/core/browser/credit_card_save_manager.h" -#include "components/autofill/core/browser/local_card_migration_manager.h" +#include "components/autofill/core/browser/payments/credit_card_save_manager.h" +#include "components/autofill/core/browser/payments/local_card_migration_manager.h" #include "components/autofill/core/browser/payments/payments_client.h" #include "components/autofill/core/browser/test_personal_data_manager.h" #include "components/autofill/core/common/autofill_features.h" +#include "components/autofill/core/common/autofill_payments_features.h" #include "components/autofill/core/common/autofill_switches.h" -#include "components/prefs/pref_registry_simple.h" -#include "components/prefs/testing_pref_service.h" #include "components/variations/net/variations_http_headers.h" #include "components/variations/variations_associated_data.h" #include "components/variations/variations_http_header_provider.h" @@ -77,10 +76,9 @@ class PaymentsClientTest : public testing::Test { test_shared_loader_factory_ = base::MakeRefCounted<network::WeakWrapperSharedURLLoaderFactory>( &test_url_loader_factory_); - TestingPrefServiceSimple pref_service_; client_ = std::make_unique<PaymentsClient>( - test_shared_loader_factory_, &pref_service_, - identity_test_env_.identity_manager(), &test_personal_data_); + test_shared_loader_factory_, identity_test_env_.identity_manager(), + &test_personal_data_); test_personal_data_.SetAccountInfoForPayments( identity_test_env_.MakePrimaryAccountAvailable("example@gmail.com")); } @@ -513,29 +511,6 @@ TEST_F(PaymentsClientTest, GetDetailsIncludesUnknownUploadCardSourceInRequest) { std::string::npos); } -TEST_F(PaymentsClientTest, GetUploadAccountFromSyncTest) { - EnableAutofillGetPaymentsIdentityFromSync(); - // Set up a different account. - const AccountInfo& secondary_account_info = - identity_test_env_.MakeAccountAvailable("secondary@gmail.com"); - test_personal_data_.SetAccountInfoForPayments(secondary_account_info); - - StartUploading(/*include_cvc=*/true); - ReturnResponse(net::HTTP_OK, "{}"); - - // Issue a token for the secondary account. - identity_test_env_.WaitForAccessTokenRequestIfNecessaryAndRespondWithToken( - secondary_account_info.account_id, "secondary_account_token", - base::Time::Now() + base::TimeDelta::FromDays(10)); - - // Verify the auth header. - std::string auth_header_value; - EXPECT_TRUE(intercepted_headers_.GetHeader( - net::HttpRequestHeaders::kAuthorization, &auth_header_value)) - << intercepted_headers_.ToString(); - EXPECT_EQ("Bearer secondary_account_token", auth_header_value); -} - TEST_F(PaymentsClientTest, GetUploadDetailsVariationsTest) { // Register a trial and variation id, so that there is data in variations // headers. Also, the variations header provider may have been registered to @@ -567,6 +542,103 @@ TEST_F(PaymentsClientTest, GetUploadDetailsVariationsTestExperimentFlagOff) { variations::VariationsHttpHeaderProvider::GetInstance()->ResetForTesting(); } +TEST_F(PaymentsClientTest, GetDetailsIncludeBillableServiceNumber) { + StartGettingUploadDetails(); + + // Verify that billable service number was included in the request. + EXPECT_TRUE(GetUploadData().find("\"billable_service\":12345") != + std::string::npos); +} + +TEST_F(PaymentsClientTest, GetDetailsFollowedByUploadSuccess) { + StartGettingUploadDetails(); + ReturnResponse( + net::HTTP_OK, + "{ \"context_token\": \"some_token\", \"legal_message\": {} }"); + EXPECT_EQ(AutofillClient::SUCCESS, result_); + + result_ = AutofillClient::NONE; + + StartUploading(/*include_cvc=*/true); + IssueOAuthToken(); + ReturnResponse(net::HTTP_OK, "{}"); + EXPECT_EQ(AutofillClient::SUCCESS, result_); +} + +TEST_F(PaymentsClientTest, GetDetailsFollowedByMigrationSuccess) { + StartGettingUploadDetails(); + ReturnResponse( + net::HTTP_OK, + "{ \"context_token\": \"some_token\", \"legal_message\": {} }"); + EXPECT_EQ(AutofillClient::SUCCESS, result_); + + result_ = AutofillClient::NONE; + + StartMigrating(/*has_cardholder_name=*/true); + IssueOAuthToken(); + ReturnResponse( + net::HTTP_OK, + "{\"save_result\":[],\"value_prop_display_text\":\"display text\"}"); + EXPECT_EQ(AutofillClient::SUCCESS, result_); +} + +TEST_F(PaymentsClientTest, GetDetailsMissingContextToken) { + StartGettingUploadDetails(); + ReturnResponse(net::HTTP_OK, "{ \"legal_message\": {} }"); + EXPECT_EQ(AutofillClient::PERMANENT_FAILURE, result_); +} + +TEST_F(PaymentsClientTest, GetDetailsMissingLegalMessage) { + StartGettingUploadDetails(); + ReturnResponse(net::HTTP_OK, "{ \"context_token\": \"some_token\" }"); + EXPECT_EQ(AutofillClient::PERMANENT_FAILURE, result_); + EXPECT_EQ(nullptr, legal_message_.get()); +} + +TEST_F(PaymentsClientTest, SupportedCardBinRangesParsesCorrectly) { + StartGettingUploadDetails(); + ReturnResponse( + net::HTTP_OK, + "{" + " \"context_token\" : \"some_token\"," + " \"legal_message\" : {}," + " \"supported_card_bin_ranges_string\" : \"1234,300000-555555,765\"" + "}"); + EXPECT_EQ(AutofillClient::SUCCESS, result_); + // Check that |supported_card_bin_ranges_| has the two entries specified in + // ReturnResponse(~) above. + ASSERT_EQ(3U, supported_card_bin_ranges_.size()); + EXPECT_EQ(1234, supported_card_bin_ranges_[0].first); + EXPECT_EQ(1234, supported_card_bin_ranges_[0].second); + EXPECT_EQ(300000, supported_card_bin_ranges_[1].first); + EXPECT_EQ(555555, supported_card_bin_ranges_[1].second); + EXPECT_EQ(765, supported_card_bin_ranges_[2].first); + EXPECT_EQ(765, supported_card_bin_ranges_[2].second); +} + +TEST_F(PaymentsClientTest, GetUploadAccountFromSyncTest) { + EnableAutofillGetPaymentsIdentityFromSync(); + // Set up a different account. + const AccountInfo& secondary_account_info = + identity_test_env_.MakeAccountAvailable("secondary@gmail.com"); + test_personal_data_.SetAccountInfoForPayments(secondary_account_info); + + StartUploading(/*include_cvc=*/true); + ReturnResponse(net::HTTP_OK, "{}"); + + // Issue a token for the secondary account. + identity_test_env_.WaitForAccessTokenRequestIfNecessaryAndRespondWithToken( + secondary_account_info.account_id, "secondary_account_token", + base::Time::Now() + base::TimeDelta::FromDays(10)); + + // Verify the auth header. + std::string auth_header_value; + EXPECT_TRUE(intercepted_headers_.GetHeader( + net::HttpRequestHeaders::kAuthorization, &auth_header_value)) + << intercepted_headers_.ToString(); + EXPECT_EQ("Bearer secondary_account_token", auth_header_value); +} + TEST_F(PaymentsClientTest, UploadCardVariationsTest) { // Register a trial and variation id, so that there is data in variations // headers. Also, the variations header provider may have been registered to @@ -664,14 +736,6 @@ TEST_F(PaymentsClientTest, MigrateCardsVariationsTestExperimentFlagOff) { variations::VariationsHttpHeaderProvider::GetInstance()->ResetForTesting(); } -TEST_F(PaymentsClientTest, GetDetailsIncludeBillableServiceNumber) { - StartGettingUploadDetails(); - - // Verify that billable service number was included in the request. - EXPECT_TRUE(GetUploadData().find("\"billable_service\":12345") != - std::string::npos); -} - TEST_F(PaymentsClientTest, UploadSuccessWithoutServerId) { StartUploading(/*include_cvc=*/true); IssueOAuthToken(); @@ -914,57 +978,12 @@ TEST_F(PaymentsClientTest, MigrationSuccessWithDisplayText) { EXPECT_EQ("display text", display_text_); } -TEST_F(PaymentsClientTest, GetDetailsFollowedByUploadSuccess) { - StartGettingUploadDetails(); - ReturnResponse( - net::HTTP_OK, - "{ \"context_token\": \"some_token\", \"legal_message\": {} }"); - EXPECT_EQ(AutofillClient::SUCCESS, result_); - - result_ = AutofillClient::NONE; - - StartUploading(/*include_cvc=*/true); - IssueOAuthToken(); - ReturnResponse(net::HTTP_OK, "{}"); - EXPECT_EQ(AutofillClient::SUCCESS, result_); -} - -TEST_F(PaymentsClientTest, GetDetailsFollowedByMigrationSuccess) { - StartGettingUploadDetails(); - ReturnResponse( - net::HTTP_OK, - "{ \"context_token\": \"some_token\", \"legal_message\": {} }"); - EXPECT_EQ(AutofillClient::SUCCESS, result_); - - result_ = AutofillClient::NONE; - - StartMigrating(/*has_cardholder_name=*/true); - IssueOAuthToken(); - ReturnResponse( - net::HTTP_OK, - "{\"save_result\":[],\"value_prop_display_text\":\"display text\"}"); - EXPECT_EQ(AutofillClient::SUCCESS, result_); -} - TEST_F(PaymentsClientTest, UnmaskMissingPan) { StartUnmasking(); ReturnResponse(net::HTTP_OK, "{}"); EXPECT_EQ(AutofillClient::PERMANENT_FAILURE, result_); } -TEST_F(PaymentsClientTest, GetDetailsMissingContextToken) { - StartGettingUploadDetails(); - ReturnResponse(net::HTTP_OK, "{ \"legal_message\": {} }"); - EXPECT_EQ(AutofillClient::PERMANENT_FAILURE, result_); -} - -TEST_F(PaymentsClientTest, GetDetailsMissingLegalMessage) { - StartGettingUploadDetails(); - ReturnResponse(net::HTTP_OK, "{ \"context_token\": \"some_token\" }"); - EXPECT_EQ(AutofillClient::PERMANENT_FAILURE, result_); - EXPECT_EQ(nullptr, legal_message_.get()); -} - TEST_F(PaymentsClientTest, RetryFailure) { StartUnmasking(); IssueOAuthToken(); diff --git a/chromium/components/autofill/core/browser/payments/payments_request.h b/chromium/components/autofill/core/browser/payments/payments_request.h index e71d554d7de..61916ad82cc 100644 --- a/chromium/components/autofill/core/browser/payments/payments_request.h +++ b/chromium/components/autofill/core/browser/payments/payments_request.h @@ -28,7 +28,7 @@ class PaymentsRequest { virtual std::string GetRequestContent() = 0; // Parses the required elements of the HTTP response. - virtual void ParseResponse(base::Value response) = 0; + virtual void ParseResponse(const base::Value& response) = 0; // Returns true if all of the required elements were successfully retrieved by // a call to ParseResponse. diff --git a/chromium/components/autofill/core/browser/payments/payments_service_url.cc b/chromium/components/autofill/core/browser/payments/payments_service_url.cc index f545e9a16d7..442f7fa25ca 100644 --- a/chromium/components/autofill/core/browser/payments/payments_service_url.cc +++ b/chromium/components/autofill/core/browser/payments/payments_service_url.cc @@ -21,11 +21,22 @@ namespace autofill { namespace { +// Service URLs used for calls to Google Payments endpoints. const char kProdPaymentsServiceUrl[] = "https://payments.google.com/"; - const char kSandboxPaymentsSecureServiceUrl[] = "https://payments.sandbox.google.com/"; +// URLs used when opening the Payment methods management page from +// chrome://settings/payments. +const char kProdPaymentsManageCardsUrl[] = + "https://pay.google.com/payments/" + "home?utm_source=chrome&utm_medium=settings&utm_campaign=payment-methods#" + "paymentMethods"; +const char kSandboxPaymentsManageCardsUrl[] = + "https://pay.sandbox.google.com/payments/" + "home?utm_source=chrome&utm_medium=settings&utm_campaign=payment-methods#" + "paymentMethods"; + } // namespace namespace payments { @@ -44,15 +55,14 @@ GURL GetBaseSecureUrl() { : kSandboxPaymentsSecureServiceUrl); } -GURL GetManageInstrumentsUrl(size_t user_index) { - std::string path = - base::StringPrintf("u/%" PRIuS "#paymentMethods", user_index); - return GetBaseSecureUrl().Resolve(path); +GURL GetManageInstrumentsUrl() { + return GURL(IsPaymentsProductionEnabled() ? kProdPaymentsManageCardsUrl + : kSandboxPaymentsManageCardsUrl); } -GURL GetManageAddressesUrl(size_t user_index) { +GURL GetManageAddressesUrl() { // Billing addresses are now managed as a part of the payment instrument. - return GetManageInstrumentsUrl(user_index); + return GetManageInstrumentsUrl(); } } // namespace payments diff --git a/chromium/components/autofill/core/browser/payments/payments_service_url.h b/chromium/components/autofill/core/browser/payments/payments_service_url.h index b28aa36fd83..a4c5d232482 100644 --- a/chromium/components/autofill/core/browser/payments/payments_service_url.h +++ b/chromium/components/autofill/core/browser/payments/payments_service_url.h @@ -16,16 +16,13 @@ namespace payments { // should be used. bool IsPaymentsProductionEnabled(); -// Returns the base URL to use for all Google Payments activity (RPCs and/or -// navigation). +// Returns the base URL to use for calls to Google Payments endpoints. GURL GetBaseSecureUrl(); // Returns the URL to navigate to in order to allow the user to edit or delete -// payment instruments (credit cards) or addresses, respectively. |user_index| -// is the index into the list of signed-in GAIA profiles for which this request -// is being made. -GURL GetManageInstrumentsUrl(size_t user_index); -GURL GetManageAddressesUrl(size_t user_index); +// payment instruments (credit cards) or addresses, respectively. +GURL GetManageInstrumentsUrl(); +GURL GetManageAddressesUrl(); } // namespace payments } // namespace autofill diff --git a/chromium/components/autofill/core/browser/payments/payments_service_url_unittest.cc b/chromium/components/autofill/core/browser/payments/payments_service_url_unittest.cc index 8cdc5001257..49182d3f94d 100644 --- a/chromium/components/autofill/core/browser/payments/payments_service_url_unittest.cc +++ b/chromium/components/autofill/core/browser/payments/payments_service_url_unittest.cc @@ -16,20 +16,25 @@ TEST(PaymentsServiceSandboxUrl, CheckSandboxUrls) { switches::kWalletServiceUseSandbox, "1"); const char kExpectedSandboxURL[] = - "https://payments.sandbox.google.com/u/1#paymentMethods"; + "https://pay.sandbox.google.com/payments/" + "home?utm_source=chrome&utm_medium=settings&utm_campaign=payment-methods#" + "paymentMethods"; - EXPECT_EQ(kExpectedSandboxURL, GetManageInstrumentsUrl(1).spec()); - EXPECT_EQ(kExpectedSandboxURL, GetManageAddressesUrl(1).spec()); + EXPECT_EQ(kExpectedSandboxURL, GetManageInstrumentsUrl().spec()); + EXPECT_EQ(kExpectedSandboxURL, GetManageAddressesUrl().spec()); } TEST(PaymentsServiceSandboxUrl, CheckProdUrls) { base::CommandLine::ForCurrentProcess()->AppendSwitchASCII( switches::kWalletServiceUseSandbox, "0"); - const char kExpectedURL[] = "https://payments.google.com/u/1#paymentMethods"; + const char kExpectedURL[] = + "https://pay.google.com/payments/" + "home?utm_source=chrome&utm_medium=settings&utm_campaign=payment-methods#" + "paymentMethods"; - EXPECT_EQ(kExpectedURL, GetManageInstrumentsUrl(1).spec()); - EXPECT_EQ(kExpectedURL, GetManageAddressesUrl(1).spec()); + EXPECT_EQ(kExpectedURL, GetManageInstrumentsUrl().spec()); + EXPECT_EQ(kExpectedURL, GetManageAddressesUrl().spec()); } } // namespace payments diff --git a/chromium/components/autofill/core/browser/payments/payments_util.cc b/chromium/components/autofill/core/browser/payments/payments_util.cc index 51beb608048..b5775344bbb 100644 --- a/chromium/components/autofill/core/browser/payments/payments_util.cc +++ b/chromium/components/autofill/core/browser/payments/payments_util.cc @@ -4,58 +4,53 @@ #include "components/autofill/core/browser/payments/payments_util.h" -#include "base/feature_list.h" #include "base/strings/string_number_conversions.h" #include "base/strings/string_piece.h" #include "components/autofill/core/browser/autofill_metrics.h" #include "components/autofill/core/browser/payments/payments_customer_data.h" #include "components/autofill/core/browser/personal_data_manager.h" -#include "components/autofill/core/common/autofill_features.h" -#include "components/autofill/core/common/autofill_prefs.h" -#include "components/prefs/pref_service.h" namespace autofill { namespace payments { +namespace { +constexpr int kCustomerHasNoBillingCustomerNumber = 0; +} + int64_t GetBillingCustomerId(PersonalDataManager* personal_data_manager, - PrefService* pref_service, bool should_log_validity) { DCHECK(personal_data_manager); - DCHECK(pref_service); - - if (base::FeatureList::IsEnabled( - features::kAutofillUsePaymentsCustomerData) || - base::FeatureList::IsEnabled( - features::kAutofillEnableAccountWalletStorage)) { - // Get billing customer ID from the synced PaymentsCustomerData. - PaymentsCustomerData* customer_data = - personal_data_manager->GetPaymentsCustomerData(); - if (customer_data && !customer_data->customer_id.empty()) { - int64_t billing_customer_id = 0; - if (base::StringToInt64(base::StringPiece(customer_data->customer_id), - &billing_customer_id)) { - if (should_log_validity) { - AutofillMetrics::LogPaymentsCustomerDataBillingIdStatus( - AutofillMetrics::BillingIdStatus::VALID); - } - return billing_customer_id; - } else { - if (should_log_validity) { - AutofillMetrics::LogPaymentsCustomerDataBillingIdStatus( - AutofillMetrics::BillingIdStatus::PARSE_ERROR); - } + + // Get billing customer ID from the synced PaymentsCustomerData. + PaymentsCustomerData* customer_data = + personal_data_manager->GetPaymentsCustomerData(); + if (customer_data && !customer_data->customer_id.empty()) { + int64_t billing_customer_id = 0; + if (base::StringToInt64(base::StringPiece(customer_data->customer_id), + &billing_customer_id)) { + if (should_log_validity) { + AutofillMetrics::LogPaymentsCustomerDataBillingIdStatus( + AutofillMetrics::BillingIdStatus::VALID); } + return billing_customer_id; } else { if (should_log_validity) { AutofillMetrics::LogPaymentsCustomerDataBillingIdStatus( - AutofillMetrics::BillingIdStatus::MISSING); + AutofillMetrics::BillingIdStatus::PARSE_ERROR); } } + } else { + if (should_log_validity) { + AutofillMetrics::LogPaymentsCustomerDataBillingIdStatus( + AutofillMetrics::BillingIdStatus::MISSING); + } } + return kCustomerHasNoBillingCustomerNumber; +} - // Get billing customer ID from priority preferences. - return static_cast<int64_t>( - pref_service->GetDouble(prefs::kAutofillBillingCustomerNumber)); +bool HasGooglePaymentsAccount(PersonalDataManager* personal_data_manager) { + return GetBillingCustomerId(personal_data_manager) != + kCustomerHasNoBillingCustomerNumber; } } // namespace payments diff --git a/chromium/components/autofill/core/browser/payments/payments_util.h b/chromium/components/autofill/core/browser/payments/payments_util.h index aeca52bf3b4..31ca1053e15 100644 --- a/chromium/components/autofill/core/browser/payments/payments_util.h +++ b/chromium/components/autofill/core/browser/payments/payments_util.h @@ -7,8 +7,6 @@ #include <stdint.h> -class PrefService; - namespace autofill { class PersonalDataManager; @@ -20,9 +18,11 @@ namespace payments { // if the customer ID was not found. If |should_log_validity| is true, will // report on the validity state of the customer ID in PaymentsCustomerData. int64_t GetBillingCustomerId(PersonalDataManager* personal_data_manager, - PrefService* pref_service, bool should_log_validity = false); +// Returns if the customer has an existing Google payments account. +bool HasGooglePaymentsAccount(PersonalDataManager* personal_data_manager); + } // namespace payments } // namespace autofill diff --git a/chromium/components/autofill/core/browser/payments/payments_util_unittest.cc b/chromium/components/autofill/core/browser/payments/payments_util_unittest.cc index 9ce775cea00..d2fb85040a6 100644 --- a/chromium/components/autofill/core/browser/payments/payments_util_unittest.cc +++ b/chromium/components/autofill/core/browser/payments/payments_util_unittest.cc @@ -5,14 +5,9 @@ #include "components/autofill/core/browser/payments/payments_util.h" #include "base/test/metrics/histogram_tester.h" -#include "base/test/scoped_feature_list.h" #include "components/autofill/core/browser/autofill_metrics.h" #include "components/autofill/core/browser/payments/payments_customer_data.h" #include "components/autofill/core/browser/test_personal_data_manager.h" -#include "components/autofill/core/common/autofill_features.h" -#include "components/autofill/core/common/autofill_prefs.h" -#include "components/prefs/pref_registry_simple.h" -#include "components/prefs/testing_pref_service.h" #include "testing/gtest/include/gtest/gtest.h" namespace autofill { @@ -24,30 +19,20 @@ class PaymentsUtilTest : public testing::Test { ~PaymentsUtilTest() override {} protected: - void SetUp() override { - pref_service_.registry()->RegisterDoublePref( - prefs::kAutofillBillingCustomerNumber, 0.0); - } - - base::test::ScopedFeatureList scoped_feature_list_; TestPersonalDataManager personal_data_manager_; - TestingPrefServiceSimple pref_service_; private: DISALLOW_COPY_AND_ASSIGN(PaymentsUtilTest); }; TEST_F(PaymentsUtilTest, GetBillingCustomerId_PaymentsCustomerData_Normal) { - scoped_feature_list_.InitAndEnableFeature( - features::kAutofillUsePaymentsCustomerData); base::HistogramTester histogram_tester; personal_data_manager_.SetPaymentsCustomerData( std::make_unique<PaymentsCustomerData>(/*customer_id=*/"123456")); - EXPECT_EQ(123456, - GetBillingCustomerId(&personal_data_manager_, &pref_service_, - /*should_log_validity=*/true)); + EXPECT_EQ(123456, GetBillingCustomerId(&personal_data_manager_, + /*should_log_validity=*/true)); histogram_tester.ExpectUniqueSample( "Autofill.PaymentsCustomerDataBillingIdStatus", @@ -55,14 +40,12 @@ TEST_F(PaymentsUtilTest, GetBillingCustomerId_PaymentsCustomerData_Normal) { } TEST_F(PaymentsUtilTest, GetBillingCustomerId_PaymentsCustomerData_Garbage) { - scoped_feature_list_.InitAndEnableFeature( - features::kAutofillUsePaymentsCustomerData); base::HistogramTester histogram_tester; personal_data_manager_.SetPaymentsCustomerData( std::make_unique<PaymentsCustomerData>(/*customer_id=*/"garbage")); - EXPECT_EQ(0, GetBillingCustomerId(&personal_data_manager_, &pref_service_, + EXPECT_EQ(0, GetBillingCustomerId(&personal_data_manager_, /*should_log_validity=*/true)); histogram_tester.ExpectUniqueSample( @@ -71,57 +54,27 @@ TEST_F(PaymentsUtilTest, GetBillingCustomerId_PaymentsCustomerData_Garbage) { } TEST_F(PaymentsUtilTest, GetBillingCustomerId_PaymentsCustomerData_NoData) { - scoped_feature_list_.InitAndEnableFeature( - features::kAutofillUsePaymentsCustomerData); base::HistogramTester histogram_tester; // Explictly do not set PaymentsCustomerData. Nothing crashes and the returned // customer ID is 0. - EXPECT_EQ(0, GetBillingCustomerId(&personal_data_manager_, &pref_service_, + EXPECT_EQ(0, GetBillingCustomerId(&personal_data_manager_, /*should_log_validity=*/true)); histogram_tester.ExpectUniqueSample( "Autofill.PaymentsCustomerDataBillingIdStatus", AutofillMetrics::BillingIdStatus::MISSING, 1); } -TEST_F(PaymentsUtilTest, - GetBillingCustomerId_PaymentsCustomerData_NoDataFallback) { - scoped_feature_list_.InitAndEnableFeature( - features::kAutofillUsePaymentsCustomerData); - base::HistogramTester histogram_tester; - - // Explictly do not set PaymentsCustomerData but set a fallback to prefs. - pref_service_.SetDouble(prefs::kAutofillBillingCustomerNumber, 123456.0); - - // We got the data from prefs and log that the PaymentsCustomerData is - // invalid. - EXPECT_EQ(123456, - GetBillingCustomerId(&personal_data_manager_, &pref_service_, - /*should_log_validity=*/true)); - histogram_tester.ExpectUniqueSample( - "Autofill.PaymentsCustomerDataBillingIdStatus", - AutofillMetrics::BillingIdStatus::MISSING, 1); -} - -TEST_F(PaymentsUtilTest, GetBillingCustomerId_PriorityPrefs_Normal) { - scoped_feature_list_.InitAndDisableFeature( - features::kAutofillUsePaymentsCustomerData); - - pref_service_.SetDouble(prefs::kAutofillBillingCustomerNumber, 123456.0); +TEST_F(PaymentsUtilTest, HasGooglePaymentsAccount_Normal) { + personal_data_manager_.SetPaymentsCustomerData( + std::make_unique<PaymentsCustomerData>(/*customer_id=*/"123456")); - EXPECT_EQ(123456, - GetBillingCustomerId(&personal_data_manager_, &pref_service_, - /*should_log_validity=*/true)); + EXPECT_TRUE(HasGooglePaymentsAccount(&personal_data_manager_)); } -TEST_F(PaymentsUtilTest, GetBillingCustomerId_PriorityPrefs_NoData) { - scoped_feature_list_.InitAndDisableFeature( - features::kAutofillUsePaymentsCustomerData); - - // Explictly do not set Prefs data. Nothing crashes and the returned customer - // ID is 0. - EXPECT_EQ(0, GetBillingCustomerId(&personal_data_manager_, &pref_service_, - /*should_log_validity=*/true)); +TEST_F(PaymentsUtilTest, HasGooglePaymentsAccount_NoData) { + // Explicitly do not set Prefs data. Nothing crashes and returns false. + EXPECT_FALSE(HasGooglePaymentsAccount(&personal_data_manager_)); } } // namespace payments diff --git a/chromium/components/autofill/core/browser/risk_data_loader.h b/chromium/components/autofill/core/browser/payments/risk_data_loader.h index 2b8468bb584..a9860ee588c 100644 --- a/chromium/components/autofill/core/browser/risk_data_loader.h +++ b/chromium/components/autofill/core/browser/payments/risk_data_loader.h @@ -2,8 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#ifndef COMPONENTS_AUTOFILL_CORE_BROWSER_RISK_DATA_LOADER_H_ -#define COMPONENTS_AUTOFILL_CORE_BROWSER_RISK_DATA_LOADER_H_ +#ifndef COMPONENTS_AUTOFILL_CORE_BROWSER_PAYMENTS_RISK_DATA_LOADER_H_ +#define COMPONENTS_AUTOFILL_CORE_BROWSER_PAYMENTS_RISK_DATA_LOADER_H_ #include <string> @@ -23,4 +23,4 @@ class RiskDataLoader { } // namespace autofill -#endif // COMPONENTS_AUTOFILL_CORE_BROWSER_RISK_DATA_LOADER_H_ +#endif // COMPONENTS_AUTOFILL_CORE_BROWSER_PAYMENTS_RISK_DATA_LOADER_H_ diff --git a/chromium/components/autofill/core/browser/strike_database.cc b/chromium/components/autofill/core/browser/payments/strike_database.cc index 41002501b2b..10ff55f4dc7 100644 --- a/chromium/components/autofill/core/browser/strike_database.cc +++ b/chromium/components/autofill/core/browser/payments/strike_database.cc @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "components/autofill/core/browser/strike_database.h" +#include "components/autofill/core/browser/payments/strike_database.h" #include <algorithm> #include <string> diff --git a/chromium/components/autofill/core/browser/strike_database.h b/chromium/components/autofill/core/browser/payments/strike_database.h index 8b8915df770..029aebe6e3f 100644 --- a/chromium/components/autofill/core/browser/strike_database.h +++ b/chromium/components/autofill/core/browser/payments/strike_database.h @@ -2,8 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#ifndef COMPONENTS_AUTOFILL_CORE_BROWSER_STRIKE_DATABASE_H_ -#define COMPONENTS_AUTOFILL_CORE_BROWSER_STRIKE_DATABASE_H_ +#ifndef COMPONENTS_AUTOFILL_CORE_BROWSER_PAYMENTS_STRIKE_DATABASE_H_ +#define COMPONENTS_AUTOFILL_CORE_BROWSER_PAYMENTS_STRIKE_DATABASE_H_ #include <map> #include <memory> @@ -165,4 +165,4 @@ class StrikeDatabase : public KeyedService { } // namespace autofill -#endif // COMPONENTS_AUTOFILL_CORE_BROWSER_STRIKE_DATABASE_H_ +#endif // COMPONENTS_AUTOFILL_CORE_BROWSER_PAYMENTS_STRIKE_DATABASE_H_ diff --git a/chromium/components/autofill/core/browser/strike_database_integrator_base.cc b/chromium/components/autofill/core/browser/payments/strike_database_integrator_base.cc index 5b0426188a7..1d0f11324dd 100644 --- a/chromium/components/autofill/core/browser/strike_database_integrator_base.cc +++ b/chromium/components/autofill/core/browser/payments/strike_database_integrator_base.cc @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "components/autofill/core/browser/strike_database_integrator_base.h" +#include "components/autofill/core/browser/payments/strike_database_integrator_base.h" #include <algorithm> #include <string> diff --git a/chromium/components/autofill/core/browser/strike_database_integrator_base.h b/chromium/components/autofill/core/browser/payments/strike_database_integrator_base.h index 3e1bf565d8a..63e624e56f0 100644 --- a/chromium/components/autofill/core/browser/strike_database_integrator_base.h +++ b/chromium/components/autofill/core/browser/payments/strike_database_integrator_base.h @@ -2,10 +2,10 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#ifndef COMPONENTS_AUTOFILL_CORE_BROWSER_STRIKE_DATABASE_INTEGRATOR_BASE_H_ -#define COMPONENTS_AUTOFILL_CORE_BROWSER_STRIKE_DATABASE_INTEGRATOR_BASE_H_ +#ifndef COMPONENTS_AUTOFILL_CORE_BROWSER_PAYMENTS_STRIKE_DATABASE_INTEGRATOR_BASE_H_ +#define COMPONENTS_AUTOFILL_CORE_BROWSER_PAYMENTS_STRIKE_DATABASE_INTEGRATOR_BASE_H_ -#include "components/autofill/core/browser/strike_database.h" +#include "components/autofill/core/browser/payments/strike_database.h" namespace autofill { @@ -104,4 +104,4 @@ class StrikeDatabaseIntegratorBase { } // namespace autofill -#endif // COMPONENTS_AUTOFILL_CORE_BROWSER_STRIKE_DATABASE_INTEGRATOR_BASE_H_ +#endif // COMPONENTS_AUTOFILL_CORE_BROWSER_PAYMENTS_STRIKE_DATABASE_INTEGRATOR_BASE_H_ diff --git a/chromium/components/autofill/core/browser/strike_database_integrator_test_strike_database.cc b/chromium/components/autofill/core/browser/payments/strike_database_integrator_test_strike_database.cc index c5be5139c42..99e701a1233 100644 --- a/chromium/components/autofill/core/browser/strike_database_integrator_test_strike_database.cc +++ b/chromium/components/autofill/core/browser/payments/strike_database_integrator_test_strike_database.cc @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "components/autofill/core/browser/strike_database_integrator_test_strike_database.h" +#include "components/autofill/core/browser/payments/strike_database_integrator_test_strike_database.h" #include "components/autofill/core/browser/proto/strike_data.pb.h" diff --git a/chromium/components/autofill/core/browser/strike_database_integrator_test_strike_database.h b/chromium/components/autofill/core/browser/payments/strike_database_integrator_test_strike_database.h index 3a50f6e75f5..22afb7a7883 100644 --- a/chromium/components/autofill/core/browser/strike_database_integrator_test_strike_database.h +++ b/chromium/components/autofill/core/browser/payments/strike_database_integrator_test_strike_database.h @@ -2,13 +2,13 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#ifndef COMPONENTS_AUTOFILL_CORE_BROWSER_STRIKE_DATABASE_INTEGRATOR_TEST_STRIKE_DATABASE_H_ -#define COMPONENTS_AUTOFILL_CORE_BROWSER_STRIKE_DATABASE_INTEGRATOR_TEST_STRIKE_DATABASE_H_ +#ifndef COMPONENTS_AUTOFILL_CORE_BROWSER_PAYMENTS_STRIKE_DATABASE_INTEGRATOR_TEST_STRIKE_DATABASE_H_ +#define COMPONENTS_AUTOFILL_CORE_BROWSER_PAYMENTS_STRIKE_DATABASE_INTEGRATOR_TEST_STRIKE_DATABASE_H_ #include <string> -#include "components/autofill/core/browser/strike_database.h" -#include "components/autofill/core/browser/strike_database_integrator_base.h" +#include "components/autofill/core/browser/payments/strike_database.h" +#include "components/autofill/core/browser/payments/strike_database_integrator_base.h" namespace autofill { @@ -33,4 +33,4 @@ class StrikeDatabaseIntegratorTestStrikeDatabase } // namespace autofill -#endif // COMPONENTS_AUTOFILL_CORE_BROWSER_STRIKE_DATABASE_INTEGRATOR_TEST_STRIKE_DATABASE_H_ +#endif // COMPONENTS_AUTOFILL_CORE_BROWSER_PAYMENTS_STRIKE_DATABASE_INTEGRATOR_TEST_STRIKE_DATABASE_H_ diff --git a/chromium/components/autofill/core/browser/strike_database_integrator_test_strike_database_unittest.cc b/chromium/components/autofill/core/browser/payments/strike_database_integrator_test_strike_database_unittest.cc index a6e961b7fde..971af060325 100644 --- a/chromium/components/autofill/core/browser/strike_database_integrator_test_strike_database_unittest.cc +++ b/chromium/components/autofill/core/browser/payments/strike_database_integrator_test_strike_database_unittest.cc @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "components/autofill/core/browser/strike_database_integrator_test_strike_database.h" +#include "components/autofill/core/browser/payments/strike_database_integrator_test_strike_database.h" #include <utility> #include <vector> @@ -22,11 +22,13 @@ namespace autofill { class StrikeDatabaseIntegratorTestStrikeDatabaseTest : public ::testing::Test { public: StrikeDatabaseIntegratorTestStrikeDatabaseTest() - : strike_database_(new StrikeDatabase(InitFilePath())) {} + : strike_database_service_(InitFilePath()), + strike_database_(&strike_database_service_) {} protected: base::HistogramTester* GetHistogramTester() { return &histogram_tester_; } base::test::ScopedTaskEnvironment scoped_task_environment_; + StrikeDatabase strike_database_service_; StrikeDatabaseIntegratorTestStrikeDatabase strike_database_; private: diff --git a/chromium/components/autofill/core/browser/strike_database_unittest.cc b/chromium/components/autofill/core/browser/payments/strike_database_unittest.cc index 88a5edeed45..508a1bc7652 100644 --- a/chromium/components/autofill/core/browser/strike_database_unittest.cc +++ b/chromium/components/autofill/core/browser/payments/strike_database_unittest.cc @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "components/autofill/core/browser/strike_database.h" +#include "components/autofill/core/browser/payments/strike_database.h" #include <utility> #include <vector> diff --git a/chromium/components/autofill/core/browser/test_credit_card_save_manager.cc b/chromium/components/autofill/core/browser/payments/test_credit_card_save_manager.cc index 21007fe0eb0..19fc90cace1 100644 --- a/chromium/components/autofill/core/browser/test_credit_card_save_manager.cc +++ b/chromium/components/autofill/core/browser/payments/test_credit_card_save_manager.cc @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "components/autofill/core/browser/test_credit_card_save_manager.h" +#include "components/autofill/core/browser/payments/test_credit_card_save_manager.h" #include "components/autofill/core/browser/payments/test_payments_client.h" diff --git a/chromium/components/autofill/core/browser/test_credit_card_save_manager.h b/chromium/components/autofill/core/browser/payments/test_credit_card_save_manager.h index c01c302f7b8..7a16e63e196 100644 --- a/chromium/components/autofill/core/browser/test_credit_card_save_manager.h +++ b/chromium/components/autofill/core/browser/payments/test_credit_card_save_manager.h @@ -2,12 +2,12 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#ifndef COMPONENTS_AUTOFILL_CORE_BROWSER_TEST_CREDIT_CARD_SAVE_MANAGER_H_ -#define COMPONENTS_AUTOFILL_CORE_BROWSER_TEST_CREDIT_CARD_SAVE_MANAGER_H_ +#ifndef COMPONENTS_AUTOFILL_CORE_BROWSER_PAYMENTS_TEST_CREDIT_CARD_SAVE_MANAGER_H_ +#define COMPONENTS_AUTOFILL_CORE_BROWSER_PAYMENTS_TEST_CREDIT_CARD_SAVE_MANAGER_H_ #include <string> -#include "components/autofill/core/browser/credit_card_save_manager.h" +#include "components/autofill/core/browser/payments/credit_card_save_manager.h" namespace autofill { @@ -56,4 +56,4 @@ class TestCreditCardSaveManager : public CreditCardSaveManager { } // namespace autofill -#endif // COMPONENTS_AUTOFILL_CORE_BROWSER_TEST_CREDIT_CARD_SAVE_MANAGER_H_ +#endif // COMPONENTS_AUTOFILL_CORE_BROWSER_PAYMENTS_TEST_CREDIT_CARD_SAVE_MANAGER_H_ diff --git a/chromium/components/autofill/core/browser/test_credit_card_save_strike_database.cc b/chromium/components/autofill/core/browser/payments/test_credit_card_save_strike_database.cc index ebeb05ae93c..14d8505572b 100644 --- a/chromium/components/autofill/core/browser/test_credit_card_save_strike_database.cc +++ b/chromium/components/autofill/core/browser/payments/test_credit_card_save_strike_database.cc @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "components/autofill/core/browser/test_credit_card_save_strike_database.h" +#include "components/autofill/core/browser/payments/test_credit_card_save_strike_database.h" namespace autofill { diff --git a/chromium/components/autofill/core/browser/test_credit_card_save_strike_database.h b/chromium/components/autofill/core/browser/payments/test_credit_card_save_strike_database.h index 070337c3510..0db857c5753 100644 --- a/chromium/components/autofill/core/browser/test_credit_card_save_strike_database.h +++ b/chromium/components/autofill/core/browser/payments/test_credit_card_save_strike_database.h @@ -2,10 +2,10 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#ifndef COMPONENTS_AUTOFILL_CORE_BROWSER_TEST_CREDIT_CARD_SAVE_STRIKE_DATABASE_H_ -#define COMPONENTS_AUTOFILL_CORE_BROWSER_TEST_CREDIT_CARD_SAVE_STRIKE_DATABASE_H_ +#ifndef COMPONENTS_AUTOFILL_CORE_BROWSER_PAYMENTS_TEST_CREDIT_CARD_SAVE_STRIKE_DATABASE_H_ +#define COMPONENTS_AUTOFILL_CORE_BROWSER_PAYMENTS_TEST_CREDIT_CARD_SAVE_STRIKE_DATABASE_H_ -#include "components/autofill/core/browser/credit_card_save_strike_database.h" +#include "components/autofill/core/browser/payments/credit_card_save_strike_database.h" namespace autofill { @@ -16,4 +16,4 @@ class TestCreditCardSaveStrikeDatabase : public CreditCardSaveStrikeDatabase { } // namespace autofill -#endif // COMPONENTS_AUTOFILL_CORE_BROWSER_CREDIT_CARD_SAVE_STRIKE_DATABASE_H_ +#endif // COMPONENTS_AUTOFILL_CORE_BROWSER_PAYMENTS_TEST_CREDIT_CARD_SAVE_STRIKE_DATABASE_H_ diff --git a/chromium/components/autofill/core/browser/test_legacy_strike_database.cc b/chromium/components/autofill/core/browser/payments/test_legacy_strike_database.cc index 28d334b3475..0ec6a57d837 100644 --- a/chromium/components/autofill/core/browser/test_legacy_strike_database.cc +++ b/chromium/components/autofill/core/browser/payments/test_legacy_strike_database.cc @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "components/autofill/core/browser/test_legacy_strike_database.h" +#include "components/autofill/core/browser/payments/test_legacy_strike_database.h" #include "components/autofill/core/browser/proto/strike_data.pb.h" diff --git a/chromium/components/autofill/core/browser/test_legacy_strike_database.h b/chromium/components/autofill/core/browser/payments/test_legacy_strike_database.h index ddf878fcf34..ca8ca1a7498 100644 --- a/chromium/components/autofill/core/browser/test_legacy_strike_database.h +++ b/chromium/components/autofill/core/browser/payments/test_legacy_strike_database.h @@ -2,8 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#ifndef COMPONENTS_AUTOFILL_CORE_BROWSER_TEST_LEGACY_STRIKE_DATABASE_H_ -#define COMPONENTS_AUTOFILL_CORE_BROWSER_TEST_LEGACY_STRIKE_DATABASE_H_ +#ifndef COMPONENTS_AUTOFILL_CORE_BROWSER_PAYMENTS_TEST_LEGACY_STRIKE_DATABASE_H_ +#define COMPONENTS_AUTOFILL_CORE_BROWSER_PAYMENTS_TEST_LEGACY_STRIKE_DATABASE_H_ #include <memory> #include <string> @@ -11,7 +11,7 @@ #include <utility> #include <vector> -#include "components/autofill/core/browser/legacy_strike_database.h" +#include "components/autofill/core/browser/payments/legacy_strike_database.h" namespace autofill { @@ -42,4 +42,4 @@ class TestLegacyStrikeDatabase : public LegacyStrikeDatabase { } // namespace autofill -#endif // COMPONENTS_AUTOFILL_CORE_BROWSER_TEST_LEGACY_STRIKE_DATABASE_H_ +#endif // COMPONENTS_AUTOFILL_CORE_BROWSER_PAYMENTS_TEST_LEGACY_STRIKE_DATABASE_H_ diff --git a/chromium/components/autofill/core/browser/test_local_card_migration_manager.cc b/chromium/components/autofill/core/browser/payments/test_local_card_migration_manager.cc index b9808476079..0ccf4c7f93a 100644 --- a/chromium/components/autofill/core/browser/test_local_card_migration_manager.cc +++ b/chromium/components/autofill/core/browser/payments/test_local_card_migration_manager.cc @@ -2,12 +2,12 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "components/autofill/core/browser/test_local_card_migration_manager.h" +#include "components/autofill/core/browser/payments/test_local_card_migration_manager.h" #include "components/autofill/core/browser/autofill_metrics.h" +#include "components/autofill/core/browser/payments/payments_util.h" #include "components/autofill/core/browser/payments/test_payments_client.h" -#include "components/autofill/core/common/autofill_features.h" -#include "components/autofill/core/common/autofill_prefs.h" +#include "components/autofill/core/common/autofill_payments_features.h" namespace autofill { @@ -30,12 +30,11 @@ bool TestLocalCardMigrationManager::IsCreditCardMigrationEnabled() { features::LocalCardMigrationExperimentalFlag::kMigrationDisabled; bool has_google_payments_account = - (static_cast<int64_t>(payments_client_->GetPrefService()->GetDouble( - prefs::kAutofillBillingCustomerNumber)) != 0); + (payments::GetBillingCustomerId(personal_data_manager_) != 0); bool sync_feature_enabled = (personal_data_manager_->GetSyncSigninState() == - AutofillSyncSigninState::kSignedInAndSyncFeature); + AutofillSyncSigninState::kSignedInAndSyncFeatureEnabled); return migration_experiment_enabled && has_google_payments_account && (sync_feature_enabled || diff --git a/chromium/components/autofill/core/browser/test_local_card_migration_manager.h b/chromium/components/autofill/core/browser/payments/test_local_card_migration_manager.h index 722d366dd20..25d38d7aefb 100644 --- a/chromium/components/autofill/core/browser/test_local_card_migration_manager.h +++ b/chromium/components/autofill/core/browser/payments/test_local_card_migration_manager.h @@ -2,15 +2,15 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#ifndef COMPONENTS_AUTOFILL_CORE_BROWSER_TEST_LOCAL_CARD_MIGRATION_MANAGER_H_ -#define COMPONENTS_AUTOFILL_CORE_BROWSER_TEST_LOCAL_CARD_MIGRATION_MANAGER_H_ +#ifndef COMPONENTS_AUTOFILL_CORE_BROWSER_PAYMENTS_TEST_LOCAL_CARD_MIGRATION_MANAGER_H_ +#define COMPONENTS_AUTOFILL_CORE_BROWSER_PAYMENTS_TEST_LOCAL_CARD_MIGRATION_MANAGER_H_ #include <memory> #include <string> #include <utility> #include <vector> -#include "components/autofill/core/browser/local_card_migration_manager.h" +#include "components/autofill/core/browser/payments/local_card_migration_manager.h" #include "components/autofill/core/browser/sync_utils.h" #include "components/autofill/core/browser/test_personal_data_manager.h" @@ -79,4 +79,4 @@ class TestLocalCardMigrationManager : public LocalCardMigrationManager { } // namespace autofill -#endif // COMPONENTS_AUTOFILL_CORE_BROWSER_TEST_LOCAL_CARD_MIGRATION_MANAGER_H_ +#endif // COMPONENTS_AUTOFILL_CORE_BROWSER_PAYMENTS_TEST_LOCAL_CARD_MIGRATION_MANAGER_H_ diff --git a/chromium/components/autofill/core/browser/payments/test_payments_client.cc b/chromium/components/autofill/core/browser/payments/test_payments_client.cc index e58fe67248f..ddcce624bf8 100644 --- a/chromium/components/autofill/core/browser/payments/test_payments_client.cc +++ b/chromium/components/autofill/core/browser/payments/test_payments_client.cc @@ -13,11 +13,9 @@ namespace payments { TestPaymentsClient::TestPaymentsClient( scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory_, - PrefService* pref_service, identity::IdentityManager* identity_manager, PersonalDataManager* personal_data_manager) : PaymentsClient(url_loader_factory_, - pref_service, identity_manager, personal_data_manager) {} diff --git a/chromium/components/autofill/core/browser/payments/test_payments_client.h b/chromium/components/autofill/core/browser/payments/test_payments_client.h index e7f6c928e48..779326cb54f 100644 --- a/chromium/components/autofill/core/browser/payments/test_payments_client.h +++ b/chromium/components/autofill/core/browser/payments/test_payments_client.h @@ -22,7 +22,6 @@ class TestPaymentsClient : public payments::PaymentsClient { public: TestPaymentsClient( scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory_, - PrefService* pref_service, identity::IdentityManager* identity_manager, PersonalDataManager* personal_data_manager); diff --git a/chromium/components/autofill/core/browser/test_strike_database.cc b/chromium/components/autofill/core/browser/payments/test_strike_database.cc index 4aee9cb4746..7b96773e25b 100644 --- a/chromium/components/autofill/core/browser/test_strike_database.cc +++ b/chromium/components/autofill/core/browser/payments/test_strike_database.cc @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "components/autofill/core/browser/test_strike_database.h" +#include "components/autofill/core/browser/payments/test_strike_database.h" #include "components/autofill/core/browser/proto/strike_data.pb.h" diff --git a/chromium/components/autofill/core/browser/test_strike_database.h b/chromium/components/autofill/core/browser/payments/test_strike_database.h index d46be27bc4b..803a1f152e4 100644 --- a/chromium/components/autofill/core/browser/test_strike_database.h +++ b/chromium/components/autofill/core/browser/payments/test_strike_database.h @@ -2,8 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#ifndef COMPONENTS_AUTOFILL_CORE_BROWSER_TEST_STRIKE_DATABASE_H_ -#define COMPONENTS_AUTOFILL_CORE_BROWSER_TEST_STRIKE_DATABASE_H_ +#ifndef COMPONENTS_AUTOFILL_CORE_BROWSER_PAYMENTS_TEST_STRIKE_DATABASE_H_ +#define COMPONENTS_AUTOFILL_CORE_BROWSER_PAYMENTS_TEST_STRIKE_DATABASE_H_ #include <memory> #include <string> @@ -11,7 +11,7 @@ #include <utility> #include <vector> -#include "components/autofill/core/browser/strike_database.h" +#include "components/autofill/core/browser/payments/strike_database.h" namespace autofill { @@ -41,4 +41,4 @@ class TestStrikeDatabase : public StrikeDatabase { } // namespace autofill -#endif // COMPONENTS_AUTOFILL_CORE_BROWSER_TEST_STRIKE_DATABASE_H_ +#endif // COMPONENTS_AUTOFILL_CORE_BROWSER_PAYMENTS_TEST_STRIKE_DATABASE_H_ diff --git a/chromium/components/autofill/core/browser/personal_data_manager.cc b/chromium/components/autofill/core/browser/personal_data_manager.cc index 902884a4b06..fc041e632ee 100644 --- a/chromium/components/autofill/core/browser/personal_data_manager.cc +++ b/chromium/components/autofill/core/browser/personal_data_manager.cc @@ -28,6 +28,7 @@ #include "components/autofill/core/browser/address_i18n.h" #include "components/autofill/core/browser/autofill-inl.h" #include "components/autofill/core/browser/autofill_country.h" +#include "components/autofill/core/browser/autofill_data_util.h" #include "components/autofill/core/browser/autofill_download_manager.h" #include "components/autofill/core/browser/autofill_experiments.h" #include "components/autofill/core/browser/autofill_field.h" @@ -36,6 +37,8 @@ #include "components/autofill/core/browser/country_data.h" #include "components/autofill/core/browser/country_names.h" #include "components/autofill/core/browser/form_structure.h" +#include "components/autofill/core/browser/label_formatter.h" +#include "components/autofill/core/browser/label_formatter_utils.h" #include "components/autofill/core/browser/personal_data_manager_observer.h" #include "components/autofill/core/browser/phone_number.h" #include "components/autofill/core/browser/phone_number_i18n.h" @@ -67,9 +70,6 @@ using ::i18n::addressinput::AddressField; using ::i18n::addressinput::GetStreetAddressLinesAsSingleLine; using ::i18n::addressinput::STREET_ADDRESS; -// The length of a local profile GUID. -const int LOCAL_GUID_LENGTH = 36; - template <typename T> class FormGroupMatchesByGUIDFunctor { public: @@ -482,12 +482,21 @@ void PersonalDataManager::OnWebDataServiceRequestDone( } is_data_loaded_ = true; - NotifyPersonalDataChanged(); + NotifyPersonalDataObserver(); } } -void PersonalDataManager::AutofillMultipleChanged() { - has_synced_new_data_ = true; +void PersonalDataManager::AutofillMultipleChangedBySync() { + // After each change coming from sync we go through a two-step process: + // - First, we post a task on the DB sequence to (potentially) convert server + // addresses to local addresses and update cards accordingly. + // - This conversion task is concluded by a + // AutofillAddressConversionCompleted() notification. As a second step, we + // need to refresh the PDM's view of the data. + ConvertWalletAddressesAndUpdateWalletCards(); +} + +void PersonalDataManager::AutofillAddressConversionCompleted() { Refresh(); } @@ -571,7 +580,17 @@ AutofillSyncSigninState PersonalDataManager::GetSyncSigninState() const { // Check if the user has turned on sync. if (sync_service_->IsSyncFeatureEnabled()) { - return AutofillSyncSigninState::kSignedInAndSyncFeature; + // TODO(crbug.com/906995): Remove this once the kStopSyncInPausedState + // feature is launched. + if (syncer::IsWebSignout(sync_service_->GetAuthError())) { + return AutofillSyncSigninState::kSyncPaused; + } + return AutofillSyncSigninState::kSignedInAndSyncFeatureEnabled; + } + + if (sync_service_->GetDisableReasons() == + syncer::SyncService::DISABLE_REASON_PAUSED) { + return AutofillSyncSigninState::kSyncPaused; } // Check if the feature is enabled and if Wallet data types are supported. @@ -1011,7 +1030,7 @@ void PersonalDataManager::UpdateClientValidityStates( profile->set_is_client_validity_states_updated(false); ongoing_profile_changes_[profile->guid()].push_back( AutofillProfileDeepChange(AutofillProfileChange::UPDATE, *profile)); - ongoing_profile_changes_[profile->guid()].back().set_enforce_update(); + ongoing_profile_changes_[profile->guid()].back().set_enforced(); client_profile_validator_->StartProfileValidation( profile, base::BindOnce(&PersonalDataManager::OnValidated, weak_factory_.GetWeakPtr())); @@ -1138,16 +1157,13 @@ std::vector<Suggestion> PersonalDataManager::GetProfileSuggestions( // Get the profiles to suggest, which are already sorted. std::vector<AutofillProfile*> sorted_profiles = GetProfilesToSuggest(); - // When suggesting with no prefix to match, consider suppressing disused - // address suggestions as well as those based on invalid profile data. + // When suggesting with no prefix to match, suppress disused address + // suggestions as well as those based on invalid profile data. if (field_contents_canon.empty()) { - if (base::FeatureList::IsEnabled( - features::kAutofillSuppressDisusedAddresses)) { - const base::Time min_last_used = - AutofillClock::Now() - kDisusedDataModelTimeDelta; - suggestion_selection::RemoveProfilesNotUsedSinceTimestamp( - min_last_used, &sorted_profiles); - } + const base::Time min_last_used = + AutofillClock::Now() - kDisusedDataModelTimeDelta; + suggestion_selection::RemoveProfilesNotUsedSinceTimestamp(min_last_used, + &sorted_profiles); } std::vector<AutofillProfile*> matched_profiles; @@ -1163,20 +1179,29 @@ std::vector<Suggestion> PersonalDataManager::GetProfileSuggestions( matched_profiles, suggestions, &unique_matched_profiles); + std::unique_ptr<LabelFormatter> formatter; + +#if !defined(OS_ANDROID) && !defined(OS_IOS) + formatter = base::FeatureList::IsEnabled( + autofill::features::kAutofillUseImprovedLabelDisambiguation) + ? LabelFormatter::Create(app_locale_, type.GetStorableType(), + field_types, unique_matched_profiles) + : nullptr; +#endif + // Generate disambiguating labels based on the list of matches. std::vector<base::string16> labels; - AutofillProfile::CreateInferredLabels(unique_matched_profiles, &field_types, - type.GetStorableType(), 1, app_locale_, - &labels); - DCHECK_EQ(unique_suggestions.size(), labels.size()); - for (size_t i = 0; i < labels.size(); i++) { - // A suggestion's label has one line of disambiguating information to show - // to the user. However, when the two-line suggestion display experiment is - // enabled on desktop, label is replaced by additional label. - unique_suggestions[i].label = labels[i]; - unique_suggestions[i].additional_label = labels[i]; + if (formatter) { + labels = formatter->GetLabels(unique_matched_profiles); + } else { + AutofillProfile::CreateInferredLabels(unique_matched_profiles, &field_types, + type.GetStorableType(), 1, + app_locale_, &labels); } + suggestion_selection::PrepareSuggestions( + formatter && data_util::ContainsAddress(formatter->groups()), labels, + &unique_suggestions); return unique_suggestions; } @@ -1246,11 +1271,8 @@ std::vector<Suggestion> PersonalDataManager::GetCreditCardSuggestions( return std::vector<Suggestion>(); std::vector<CreditCard*> cards = GetCreditCardsToSuggest(include_server_cards); - // If enabled, suppress disused address profiles when triggered from an empty - // field. - if (field_contents.empty() && - base::FeatureList::IsEnabled( - features::kAutofillSuppressDisusedCreditCards)) { + // Suppress disused address profiles when triggered from an empty field. + if (field_contents.empty()) { const base::Time min_last_used = AutofillClock::Now() - kDisusedDataModelTimeDelta; RemoveExpiredCreditCardsNotUsedSinceTimestamp(AutofillClock::Now(), @@ -1398,7 +1420,7 @@ void PersonalDataManager::OnValidated(const AutofillProfile* profile) { if (!profile) return; - if (!ProfileChangesAreOnGoing(profile->guid())) + if (!ProfileChangesAreOngoing(profile->guid())) return; // Set the validity states updated, only when the validation has occurred. If @@ -1589,26 +1611,46 @@ void PersonalDataManager::SetProfiles(std::vector<AutofillProfile>* profiles) { ClearOnGoingProfileChanges(); + // Means that a profile was added, removed or updated. + bool change_happened = false; + // Any profiles that are not in the new profile list should be removed from // the web database for (const auto& it : web_profiles_) { - if (!FindByGUID<AutofillProfile>(*profiles, it->guid())) + if (!FindByGUID<AutofillProfile>(*profiles, it->guid())) { RemoveProfileFromDB(it->guid()); + change_happened = true; + } } // Update the web database with the new and existing profiles. for (const AutofillProfile& it : *profiles) { - if (FindByGUID<AutofillProfile>(web_profiles_, it.guid())) { - UpdateProfileInDB(it); - } else { - AddProfileToDB(it); + const auto* existing_profile = GetProfileByGUID(it.guid()); + // In SetProfiles, exceptionally, profiles are directly added/updated on the + // web_profiles_ before they are ready to be added or get updated in the + // database. Enforce the changes to make sure the database is also updated. + if (existing_profile) { + if (!existing_profile->EqualsForUpdatePurposes(it)) { + UpdateProfileInDB(it, /*enforced=*/true); + change_happened = true; + } + } else if (!FindByContents(web_profiles_, it)) { + AddProfileToDB(it, /*enforced=*/true); + change_happened = true; } } - // Copy in the new profiles. - web_profiles_.clear(); - for (const AutofillProfile& it : *profiles) { - web_profiles_.push_back(std::make_unique<AutofillProfile>(it)); + if (change_happened) { + // Copy in the new profiles. + web_profiles_.clear(); + for (const AutofillProfile& it : *profiles) { + web_profiles_.push_back(std::make_unique<AutofillProfile>(it)); + } + } else { + // When a change happens (add, update, remove), we would consequently call + // the NotifyPersonalDataChanged which notifies the tests to stop waiting. + // Otherwise, we need to stop them by calling the function directly. + NotifyPersonalDataObserver(); } } @@ -1744,23 +1786,6 @@ std::string PersonalDataManager::SaveImportedProfile( return guid; } -void PersonalDataManager::NotifyPersonalDataChanged() { - bool profile_changes_are_on_going = ProfileChangesAreOnGoing(); - for (PersonalDataManagerObserver& observer : observers_) { - observer.OnPersonalDataChanged(); - if (!profile_changes_are_on_going) { - observer.OnPersonalDataFinishedProfileTasks(); - } - } - - // If new data was synced, try to convert new server profiles and update - // server cards. - if (has_synced_new_data_) { - has_synced_new_data_ = false; - ConvertWalletAddressesAndUpdateWalletCards(); - } -} - std::string PersonalDataManager::OnAcceptedLocalCreditCardSave( const CreditCard& imported_card) { DCHECK(!imported_card.number().empty()); @@ -1871,7 +1896,7 @@ void PersonalDataManager::EnableWalletIntegrationPrefChanged() { // Re-mask all server cards when the user turns off wallet card // integration. ResetFullServerCards(); - NotifyPersonalDataChanged(); + NotifyPersonalDataObserver(); } } @@ -1974,7 +1999,7 @@ void PersonalDataManager::OnAutofillProfileChanged( const auto& profile = *(change.profile()); DCHECK(guid == profile.guid()); // Happens only in tests. - if (!ProfileChangesAreOnGoing(guid)) { + if (!ProfileChangesAreOngoing(guid)) { DVLOG(1) << "Received an unexpected response from database."; return; } @@ -1991,7 +2016,7 @@ void PersonalDataManager::OnAutofillProfileChanged( case AutofillProfileChange::UPDATE: profiles_server_validities_need_update_ = true; if (profile_exists && - (change.enforce_update() || + (change.enforced() || !existing_profile->EqualsForUpdatePurposes(profile))) { web_profiles_.erase( FindElementByGUID<AutofillProfile>(web_profiles_, guid)); @@ -2025,6 +2050,16 @@ void PersonalDataManager::OnUserAcceptedUpstreamOffer() { } } +void PersonalDataManager::NotifyPersonalDataObserver() { + bool profile_changes_are_ongoing = ProfileChangesAreOngoing(); + for (PersonalDataManagerObserver& observer : observers_) { + observer.OnPersonalDataChanged(); + if (!profile_changes_are_ongoing) { + observer.OnPersonalDataFinishedProfileTasks(); + } + } +} + std::vector<Suggestion> PersonalDataManager::GetSuggestionsForCards( const AutofillType& type, const base::string16& field_contents, @@ -2303,171 +2338,23 @@ void PersonalDataManager::UpdateCardsBillingAddressReference( } void PersonalDataManager::ConvertWalletAddressesAndUpdateWalletCards() { - // Copy the local profiles into a vector<AutofillProfile>. Theses are the - // existing profiles. Get them sorted in decreasing order of frecency, so the - // "best" profiles are checked first. Put the verified profiles last so the - // server addresses have a chance to merge into the non-verified local - // profiles. - std::vector<AutofillProfile> local_profiles; - for (AutofillProfile* existing_profile : GetProfiles()) { - local_profiles.push_back(*existing_profile); - } - - // Since we are already iterating on all the server profiles to convert Wallet - // addresses and we will need to access them by guid later to update the - // Wallet cards, create a map here. - std::unordered_map<std::string, AutofillProfile*> server_id_profiles_map; - - // Create the map used to update credit card's billing addresses after the - // conversion/merge. - std::unordered_map<std::string, std::string> guids_merge_map; - - bool has_converted_addresses = ConvertWalletAddressesToLocalProfiles( - &local_profiles, &server_id_profiles_map, &guids_merge_map); - bool should_update_cards = UpdateWalletCardsAlreadyConvertedBillingAddresses( - local_profiles, server_id_profiles_map, &guids_merge_map); - - if (has_converted_addresses) { - // Save the local profiles to the DB. - SetProfiles(&local_profiles); - } - - if (should_update_cards || has_converted_addresses) { - // Update the credit cards billing address relationship. - UpdateCardsBillingAddressReference(guids_merge_map); - - // Force a reload of the profiles and cards. - } -} - -bool PersonalDataManager::ConvertWalletAddressesToLocalProfiles( - std::vector<AutofillProfile>* local_profiles, - std::unordered_map<std::string, AutofillProfile*>* server_id_profiles_map, - std::unordered_map<std::string, std::string>* guids_merge_map) { // If the full Sync feature isn't enabled, then do NOT convert any Wallet // addresses to local ones. if (!IsSyncFeatureEnabled()) { - return false; - } - - bool has_converted_addresses = false; - for (std::unique_ptr<AutofillProfile>& wallet_address : server_profiles_) { - // Add the profile to the map. - server_id_profiles_map->emplace(wallet_address->server_id(), - wallet_address.get()); - - // If the address has not been converted yet, convert it. - if (!wallet_address->has_converted()) { - // Try to merge the server address into a similar local profile, or create - // a new local profile if no similar profile is found. - std::string address_guid = MergeServerAddressesIntoProfiles( - *wallet_address, local_profiles, app_locale_, - GetAccountInfoForPaymentsServer().email); - - // Update the map to transfer the billing address relationship from the - // server address to the converted/merged local profile. - guids_merge_map->emplace(wallet_address->server_id(), address_guid); - - // Update the wallet addresses metadata to record the conversion. - wallet_address->set_has_converted(true); - database_helper_->GetServerDatabase()->UpdateServerAddressMetadata( - *wallet_address); - - has_converted_addresses = true; - } - } - - return has_converted_addresses; -} - -bool PersonalDataManager::UpdateWalletCardsAlreadyConvertedBillingAddresses( - const std::vector<AutofillProfile>& local_profiles, - const std::unordered_map<std::string, AutofillProfile*>& - server_id_profiles_map, - std::unordered_map<std::string, std::string>* guids_merge_map) const { - // Look for server cards that still refer to server addresses but for which - // there is no mapping. This can happen if it's a new card for which the - // billing address has already been converted. This should be a no-op for most - // situations. Otherwise, it should affect only one Wallet card, sinces users - // do not add a lot of credit cards. - AutofillProfileComparator comparator(app_locale_); - bool should_update_cards = false; - for (const std::unique_ptr<CreditCard>& wallet_card : server_credit_cards_) { - std::string billing_address_id = wallet_card->billing_address_id(); - - // If billing address refers to a server id and that id is not a key in the - // |guids_merge_map|, it means that the card is new but the address was - // already converted. Look for the matching converted profile. - if (!billing_address_id.empty() && - billing_address_id.length() != LOCAL_GUID_LENGTH && - guids_merge_map->find(billing_address_id) == guids_merge_map->end()) { - // Get the profile. - auto it = server_id_profiles_map.find(billing_address_id); - if (it != server_id_profiles_map.end()) { - const AutofillProfile* billing_address = it->second; - - // Look for a matching local profile (DO NOT MERGE). - for (const auto& local_profile : local_profiles) { - if (comparator.AreMergeable(*billing_address, local_profile)) { - // The Wallet address matches this local profile. Add this to the - // merge mapping. - guids_merge_map->emplace(billing_address_id, local_profile.guid()); - should_update_cards = true; - break; - } - } - } - } - } - - return should_update_cards; -} - -// TODO(crbug.com/687975): Reuse MergeProfile in this function. -// static -std::string PersonalDataManager::MergeServerAddressesIntoProfiles( - const AutofillProfile& server_address, - std::vector<AutofillProfile>* existing_profiles, - const std::string& app_locale, - const std::string& primary_account_email) { - // If there is already a local profile that is very similar, merge in any - // missing values. Only merge with the first match. - AutofillProfileComparator comparator(app_locale); - for (auto& local_profile : *existing_profiles) { - if (comparator.AreMergeable(server_address, local_profile) && - local_profile.SaveAdditionalInfo(server_address, app_locale)) { - local_profile.set_modification_date(AutofillClock::Now()); - AutofillMetrics::LogWalletAddressConversionType( - AutofillMetrics::CONVERTED_ADDRESS_MERGED); - return local_profile.guid(); - } + // PDM expects that each call to + // ConvertWalletAddressesAndUpdateWalletCards() is followed by a + // AutofillAddressConversionCompleted() notification, simulate the + // notification here. + AutofillAddressConversionCompleted(); + return; } - // If the server address was not merged with a local profile, add it to the - // list. - existing_profiles->push_back(server_address); - // Set the profile as being local. - existing_profiles->back().set_record_type(AutofillProfile::LOCAL_PROFILE); - existing_profiles->back().set_modification_date(AutofillClock::Now()); - - // Wallet addresses don't have an email address, use the one from the - // currently signed-in account. - base::string16 email = base::UTF8ToUTF16(primary_account_email); - if (!email.empty()) - existing_profiles->back().SetRawInfo(EMAIL_ADDRESS, email); - - AutofillMetrics::LogWalletAddressConversionType( - AutofillMetrics::CONVERTED_ADDRESS_ADDED); - - return server_address.guid(); + database_helper_->GetServerDatabase() + ->ConvertWalletAddressesAndUpdateWalletCards( + app_locale_, GetAccountInfoForPaymentsServer().email); } bool PersonalDataManager::DeleteDisusedCreditCards() { - if (!base::FeatureList::IsEnabled( - features::kAutofillDeleteDisusedCreditCards)) { - return false; - } - // Only delete local cards, as server cards are managed by Payments. auto cards = GetLocalCreditCards(); @@ -2499,12 +2386,6 @@ bool PersonalDataManager::DeleteDisusedCreditCards() { } bool PersonalDataManager::DeleteDisusedAddresses() { - if (!base::FeatureList::IsEnabled( - features::kAutofillDeleteDisusedAddresses)) { - DVLOG(1) << "Deletion is disabled"; - return false; - } - const std::vector<AutofillProfile*>& profiles = GetProfiles(); // Early exit when there are no profiles. @@ -2584,21 +2465,25 @@ void PersonalDataManager::ResetProfileValidity() { profiles_server_validities_need_update_ = true; } -void PersonalDataManager::AddProfileToDB(const AutofillProfile& profile) { +void PersonalDataManager::AddProfileToDB(const AutofillProfile& profile, + bool enforced) { if (profile.IsEmpty(app_locale_)) { - NotifyPersonalDataChanged(); + NotifyPersonalDataObserver(); return; } - if (!ProfileChangesAreOnGoing(profile.guid())) { - if (FindByGUID<AutofillProfile>(web_profiles_, profile.guid()) || - FindByContents(web_profiles_, profile)) { - NotifyPersonalDataChanged(); + if (!ProfileChangesAreOngoing(profile.guid())) { + if (!enforced && + (FindByGUID<AutofillProfile>(web_profiles_, profile.guid()) || + FindByContents(web_profiles_, profile))) { + NotifyPersonalDataObserver(); return; } } ongoing_profile_changes_[profile.guid()].push_back( AutofillProfileDeepChange(AutofillProfileChange::ADD, profile)); + if (enforced) + ongoing_profile_changes_[profile.guid()].back().set_enforced(); UpdateClientValidityStates(profile); } @@ -2606,11 +2491,11 @@ void PersonalDataManager::UpdateProfileInDB(const AutofillProfile& profile, bool enforced) { // if the update is enforced, don't check if a similar profile already exists // or not. Otherwise, check if updating the profile makes sense. - if (!enforced && !ProfileChangesAreOnGoing(profile.guid())) { + if (!enforced && !ProfileChangesAreOngoing(profile.guid())) { const auto* existing_profile = GetProfileByGUID(profile.guid()); bool profile_exists = (existing_profile != nullptr); if (!profile_exists || existing_profile->EqualsForUpdatePurposes(profile)) { - NotifyPersonalDataChanged(); + NotifyPersonalDataObserver(); return; } } @@ -2618,18 +2503,22 @@ void PersonalDataManager::UpdateProfileInDB(const AutofillProfile& profile, ongoing_profile_changes_[profile.guid()].push_back( AutofillProfileDeepChange(AutofillProfileChange::UPDATE, profile)); if (enforced) - ongoing_profile_changes_[profile.guid()].back().set_enforce_update(); + ongoing_profile_changes_[profile.guid()].back().set_enforced(); UpdateClientValidityStates(profile); } void PersonalDataManager::RemoveProfileFromDB(const std::string& guid) { - bool profile_exists = FindByGUID<AutofillProfile>(web_profiles_, guid); - if (!profile_exists && !ProfileChangesAreOnGoing(guid)) { - NotifyPersonalDataChanged(); + auto profile_it = FindElementByGUID<AutofillProfile>(web_profiles_, guid); + bool profile_exists = profile_it != web_profiles_.end(); + if (!profile_exists && !ProfileChangesAreOngoing(guid)) { + NotifyPersonalDataObserver(); return; } - AutofillProfileDeepChange change(AutofillProfileChange::REMOVE, guid); - if (!ProfileChangesAreOnGoing(guid)) { + const AutofillProfile* profile = + profile_exists ? profile_it->get() + : ongoing_profile_changes_[guid].back().profile(); + AutofillProfileDeepChange change(AutofillProfileChange::REMOVE, *profile); + if (!ProfileChangesAreOngoing(guid)) { database_helper_->GetLocalDatabase()->RemoveAutofillProfile(guid); change.set_is_ongoing_on_background(); } @@ -2637,7 +2526,7 @@ void PersonalDataManager::RemoveProfileFromDB(const std::string& guid) { } void PersonalDataManager::HandleNextProfileChange(const std::string& guid) { - if (!ProfileChangesAreOnGoing(guid)) + if (!ProfileChangesAreOngoing(guid)) return; const auto& change = ongoing_profile_changes_[guid].front(); @@ -2665,7 +2554,8 @@ void PersonalDataManager::HandleNextProfileChange(const std::string& guid) { return; if (change_type == AutofillProfileChange::ADD) { - if (profile_exists || FindByContents(web_profiles_, profile)) { + if (!change.enforced() && + (profile_exists || FindByContents(web_profiles_, profile))) { OnProfileChangeDone(guid); return; } @@ -2674,7 +2564,7 @@ void PersonalDataManager::HandleNextProfileChange(const std::string& guid) { return; } - if (profile_exists && (change.enforce_update() || + if (profile_exists && (change.enforced() || !existing_profile->EqualsForUpdatePurposes(profile))) { database_helper_->GetLocalDatabase()->UpdateAutofillProfile(profile); change.set_is_ongoing_on_background(); @@ -2683,15 +2573,15 @@ void PersonalDataManager::HandleNextProfileChange(const std::string& guid) { } } -bool PersonalDataManager::ProfileChangesAreOnGoing(const std::string& guid) { +bool PersonalDataManager::ProfileChangesAreOngoing(const std::string& guid) { return ongoing_profile_changes_.find(guid) != ongoing_profile_changes_.end() && !ongoing_profile_changes_[guid].empty(); } -bool PersonalDataManager::ProfileChangesAreOnGoing() { +bool PersonalDataManager::ProfileChangesAreOngoing() { for (const auto& task : ongoing_profile_changes_) { - if (ProfileChangesAreOnGoing(task.first)) { + if (ProfileChangesAreOngoing(task.first)) { return true; } } @@ -2701,10 +2591,10 @@ bool PersonalDataManager::ProfileChangesAreOnGoing() { void PersonalDataManager::OnProfileChangeDone(const std::string& guid) { ongoing_profile_changes_[guid].pop_front(); - if (!ProfileChangesAreOnGoing()) { + if (!ProfileChangesAreOngoing()) { Refresh(); } else { - NotifyPersonalDataChanged(); + NotifyPersonalDataObserver(); HandleNextProfileChange(guid); } } diff --git a/chromium/components/autofill/core/browser/personal_data_manager.h b/chromium/components/autofill/core/browser/personal_data_manager.h index df97465f599..24e2e0107bd 100644 --- a/chromium/components/autofill/core/browser/personal_data_manager.h +++ b/chromium/components/autofill/core/browser/personal_data_manager.h @@ -19,11 +19,11 @@ #include "base/observer_list.h" #include "base/strings/string16.h" #include "build/build_config.h" -#include "components/autofill/core/browser/account_info_getter.h" #include "components/autofill/core/browser/autofill_profile.h" #include "components/autofill/core/browser/autofill_profile_validator.h" #include "components/autofill/core/browser/credit_card.h" #include "components/autofill/core/browser/field_types.h" +#include "components/autofill/core/browser/payments/account_info_getter.h" #include "components/autofill/core/browser/payments/payments_customer_data.h" #include "components/autofill/core/browser/proto/server.pb.h" #include "components/autofill/core/browser/suggestion.h" @@ -111,7 +111,8 @@ class PersonalDataManager : public KeyedService, std::unique_ptr<WDTypedResult> result) override; // AutofillWebDataServiceObserverOnUISequence: - void AutofillMultipleChanged() override; + void AutofillMultipleChangedBySync() override; + void AutofillAddressConversionCompleted() override; void SyncStarted(syncer::ModelType model_type) override; // SyncServiceObserver: @@ -351,9 +352,6 @@ class PersonalDataManager : public KeyedService, static void DedupeCreditCardToSuggest( std::list<CreditCard*>* cards_to_suggest); - // Notifies test observers that personal data has changed. - void NotifyPersonalDataChangedForTest() { NotifyPersonalDataChanged(); } - // Cancels any pending queries to the server web database. void CancelPendingServerQueries(); @@ -386,6 +384,9 @@ class PersonalDataManager : public KeyedService, // Records the sync transport consent if the user is in sync transport mode. virtual void OnUserAcceptedUpstreamOffer(); + // Notifies observers that the waiting should be stopped. + void NotifyPersonalDataObserver(); + void set_client_profile_validator_for_test( AutofillProfileValidator* validator) { client_profile_validator_ = validator; @@ -519,9 +520,6 @@ class PersonalDataManager : public KeyedService, // to the query handle. void CancelPendingServerQuery(WebDataServiceBase::Handle* handle); - // Notifies observers that personal data has changed. - void NotifyPersonalDataChanged(); - // The first time this is called, logs a UMA metrics about the user's autofill // addresses. On subsequent calls, does nothing. void LogStoredProfileMetrics() const; @@ -721,10 +719,9 @@ class PersonalDataManager : public KeyedService, // Resets |synced_profile_validity_|. void ResetProfileValidity(); - // Add/Update/Remove |profile| on DB. - void AddProfileToDB(const AutofillProfile& profile); - // |enforced| is true when the update should happen regardless of an equal - // profile. (equal in the sense of AutofillProfile::EqualForUpdate) + // Add/Update/Remove |profile| on DB. |enforced| should be true when the + // add/update should happen regardless of an existing/equal profile. + void AddProfileToDB(const AutofillProfile& profile, bool enforced = false); void UpdateProfileInDB(const AutofillProfile& profile, bool enforced = false); void RemoveProfileFromDB(const std::string& guid); @@ -734,11 +731,11 @@ class PersonalDataManager : public KeyedService, // Look at the next profile change for profile with guid = |guid|, and handle // it. void HandleNextProfileChange(const std::string& guid); - // returns true if there is any profile change that's still on going. - bool ProfileChangesAreOnGoing(); + // returns true if there is any profile change that's still ongoing. + bool ProfileChangesAreOngoing(); // returns true if there is any ongoing change for profile with guid = |guid| - // that's still on going. - bool ProfileChangesAreOnGoing(const std::string& guid); + // that's still ongoing. + bool ProfileChangesAreOngoing(const std::string& guid); // Remove the change from the |ongoing_profile_changes_|, handle next task or // Refresh. void OnProfileChangeDone(const std::string& guid); @@ -766,7 +763,7 @@ class PersonalDataManager : public KeyedService, // |profile_validities_need_update_| whenever this is changed. std::unique_ptr<UserProfileValidityMap> synced_profile_validity_; - // A timely ordered list of on going changes for each profile. + // A timely ordered list of ongoing changes for each profile. std::unordered_map<std::string, std::deque<AutofillProfileDeepChange>> ongoing_profile_changes_; @@ -801,9 +798,6 @@ class PersonalDataManager : public KeyedService, // True if autofill profile cleanup needs to be performed. bool is_autofill_profile_cleanup_pending_ = false; - // Whether new information was received from the sync server. - bool has_synced_new_data_ = false; - // Used to create test data. If the AutofillCreateDataForTest feature is // enabled, this helper creates autofill profiles and credit card data that // would otherwise be difficult to create manually using the UI. diff --git a/chromium/components/autofill/core/browser/personal_data_manager_unittest.cc b/chromium/components/autofill/core/browser/personal_data_manager_unittest.cc index 20fb473789c..7a49029d808 100644 --- a/chromium/components/autofill/core/browser/personal_data_manager_unittest.cc +++ b/chromium/components/autofill/core/browser/personal_data_manager_unittest.cc @@ -38,6 +38,7 @@ #include "components/autofill/core/browser/autofill_test_utils.h" #include "components/autofill/core/browser/field_types.h" #include "components/autofill/core/browser/form_structure.h" +#include "components/autofill/core/browser/label_formatter_utils.h" #include "components/autofill/core/browser/personal_data_manager_observer.h" #include "components/autofill/core/browser/suggestion_selection.h" #include "components/autofill/core/browser/sync_utils.h" @@ -526,14 +527,10 @@ class PersonalDataManagerHelper : public PersonalDataManagerTestBase { } void ConvertWalletAddressesAndUpdateWalletCards() { - base::RunLoop run_loop; - EXPECT_CALL(personal_data_observer_, OnPersonalDataFinishedProfileTasks()) - .WillOnce(QuitMessageLoop(&run_loop)); - EXPECT_CALL(personal_data_observer_, OnPersonalDataChanged()) - .Times(testing::AnyNumber()); - - personal_data_->ConvertWalletAddressesAndUpdateWalletCards(); - run_loop.Run(); + // Simulate new data is coming from sync which triggers a conversion of + // wallet addresses which in turn triggers a refresh. + personal_data_->AutofillMultipleChangedBySync(); + WaitForOnPersonalDataChanged(); } std::unique_ptr<PersonalDataManager> personal_data_; @@ -2229,10 +2226,6 @@ TEST_F(PersonalDataManagerTest, ResetPersonalDataManager(USER_MODE_NORMAL); - base::test::ScopedFeatureList scoped_features; - scoped_features.InitAndEnableFeature( - features::kAutofillSuppressDisusedAddresses); - // Query with empty string only returns profile2. { std::vector<Suggestion> suggestions = personal_data_->GetProfileSuggestions( @@ -2270,23 +2263,6 @@ TEST_F(PersonalDataManagerTest, base::ASCIIToUTF16("456 Zoo St., Second Line, Third line, unit 5"), suggestions[0].value); } - - // When suppression is disabled, returns all suggestions. - { - base::test::ScopedFeatureList scoped_features; - scoped_features.InitAndDisableFeature( - features::kAutofillSuppressDisusedAddresses); - std::vector<Suggestion> suggestions = personal_data_->GetProfileSuggestions( - AutofillType(ADDRESS_HOME_STREET_ADDRESS), base::string16(), false, - std::vector<ServerFieldType>()); - ASSERT_EQ(2U, suggestions.size()); - EXPECT_EQ( - base::ASCIIToUTF16("456 Zoo St., Second Line, Third line, unit 5"), - suggestions[0].value); - EXPECT_EQ( - base::ASCIIToUTF16("123 Zoo St., Second Line, Third line, unit 5"), - suggestions[1].value); - } } // Tests that suggestions based on invalid data are handled correctly. @@ -2294,7 +2270,7 @@ TEST_F(PersonalDataManagerTest, GetProfileSuggestions_Validity) { // Set up 2 different profiles: one valid and one invalid. AutofillProfile valid_profile(test::GetFullValidProfileForCanada()); valid_profile.set_use_date(AutofillClock::Now() - - base::TimeDelta::FromDays(200)); + base::TimeDelta::FromDays(1)); valid_profile.set_use_count(1); AddProfileToPersonalDataManager(valid_profile); @@ -2303,8 +2279,9 @@ TEST_F(PersonalDataManagerTest, GetProfileSuggestions_Validity) { "invalid email", "Fox", "123 Zoo St.\nSecond Line\nThird line", "unit 5", "Hollywood", "CA", "91601", "US", "Invalid Phone"); - invalid_profile.set_use_date(AutofillClock::Now()); - invalid_profile.set_use_count(1000); + invalid_profile.set_use_date(AutofillClock::Now() - + base::TimeDelta::FromDays(1)); + invalid_profile.set_use_count(1); AddProfileToPersonalDataManager(invalid_profile); auto profiles = personal_data_->GetProfiles(); @@ -2317,7 +2294,7 @@ TEST_F(PersonalDataManagerTest, GetProfileSuggestions_Validity) { scoped_features.InitWithFeatures( /*enabled_features=*/{features::kAutofillProfileServerValidation, features::kAutofillProfileClientValidation}, - /*disabled_features=*/{features::kAutofillSuppressDisusedAddresses}); + /*disabled_features=*/{}); std::vector<Suggestion> email_suggestions = personal_data_->GetProfileSuggestions(AutofillType(EMAIL_ADDRESS), base::string16(), false, @@ -2366,7 +2343,7 @@ TEST_F(PersonalDataManagerTest, GetProfileSuggestions_Validity) { scoped_features.InitWithFeatures( /*enabled_features=*/{features::kAutofillProfileClientValidation, features::kAutofillProfileServerValidation}, - /*disabled_features=*/{features::kAutofillSuppressDisusedAddresses}); + /*disabled_features=*/{}); std::vector<Suggestion> email_suggestions = personal_data_->GetProfileSuggestions(AutofillType(EMAIL_ADDRESS), @@ -2396,8 +2373,7 @@ TEST_F(PersonalDataManagerTest, GetProfileSuggestions_Validity) { base::test::ScopedFeatureList scoped_features; scoped_features.InitWithFeatures( /*enabled_features=*/{features::kAutofillProfileClientValidation}, - /*disabled_features=*/{features::kAutofillSuppressDisusedAddresses, - features::kAutofillProfileServerValidation}); + /*disabled_features=*/{features::kAutofillProfileServerValidation}); std::vector<Suggestion> email_suggestions = personal_data_->GetProfileSuggestions(AutofillType(EMAIL_ADDRESS), base::string16(), false, @@ -2427,9 +2403,7 @@ TEST_F(PersonalDataManagerTest, GetProfileSuggestions_Validity) { base::test::ScopedFeatureList scoped_features; scoped_features.InitWithFeatures( /*enabled_features=*/{features::kAutofillProfileServerValidation}, - /*disabled_features=*/{features::kAutofillProfileClientValidation, - features::kAutofillSuppressDisusedAddresses}); - LOG(ERROR) << __FUNCTION__; + /*disabled_features=*/{features::kAutofillProfileClientValidation}); std::vector<Suggestion> email_suggestions = personal_data_->GetProfileSuggestions(AutofillType(EMAIL_ADDRESS), base::string16(), false, @@ -2570,6 +2544,216 @@ TEST_F(PersonalDataManagerTest, EXPECT_EQ(0U, personal_data_->GetProfiles().size()); } +#if !defined(OS_ANDROID) && !defined(OS_IOS) +TEST_F(PersonalDataManagerTest, GetProfileSuggestions_ForContactForm) { + AutofillProfile profile(base::GenerateGUID(), test::kEmptyOrigin); + test::SetProfileInfo(&profile, "Hoa", "", "Pham", "hoa.pham@comcast.net", "", + "401 Merrimack St", "", "Lowell", "MA", "01852", "US", + "19786744120"); + AddProfileToPersonalDataManager(profile); + + base::test::ScopedFeatureList scoped_features; + scoped_features.InitAndEnableFeature( + features::kAutofillUseImprovedLabelDisambiguation); + + EXPECT_THAT( + personal_data_->GetProfileSuggestions( + AutofillType(NAME_FIRST), base::string16(), false, + std::vector<ServerFieldType>{NAME_FIRST, NAME_LAST, EMAIL_ADDRESS, + PHONE_HOME_WHOLE_NUMBER}), + ElementsAre(AllOf( + testing::Field( + &Suggestion::label, + ConstructLabelLine({base::ASCIIToUTF16("(978) 674-4120"), + base::ASCIIToUTF16("hoa.pham@comcast.net")})), + testing::Field( + &Suggestion::additional_label, + ConstructLabelLine({base::ASCIIToUTF16("(978) 674-4120"), + base::ASCIIToUTF16("hoa.pham@comcast.net")})), + testing::Field(&Suggestion::icon, "accountBoxIcon")))); +} +#endif // #if !defined(OS_ANDROID) && !defined(OS_IOS) + +#if !defined(OS_ANDROID) && !defined(OS_IOS) +TEST_F(PersonalDataManagerTest, GetProfileSuggestions_ForAddressForm) { + AutofillProfile profile(base::GenerateGUID(), test::kEmptyOrigin); + test::SetProfileInfo(&profile, "Hoa", "", "Pham", "hoa.pham@comcast.net", "", + "401 Merrimack St", "", "Lowell", "MA", "01852", "US", + "19786744120"); + AddProfileToPersonalDataManager(profile); + + base::test::ScopedFeatureList scoped_features; + scoped_features.InitAndEnableFeature( + features::kAutofillUseImprovedLabelDisambiguation); + + EXPECT_THAT(personal_data_->GetProfileSuggestions( + AutofillType(NAME_FULL), base::string16(), false, + std::vector<ServerFieldType>{ + NAME_FULL, ADDRESS_HOME_STREET_ADDRESS, ADDRESS_HOME_CITY, + ADDRESS_HOME_STATE, ADDRESS_HOME_ZIP}), + ElementsAre(AllOf( + testing::Field( + &Suggestion::label, + base::ASCIIToUTF16("401 Merrimack St, Lowell, MA 01852")), + testing::Field( + &Suggestion::additional_label, + base::ASCIIToUTF16("401 Merrimack St, Lowell, MA 01852")), + testing::Field(&Suggestion::icon, "accountBoxIcon")))); +} +#endif // #if !defined(OS_ANDROID) && !defined(OS_IOS) + +#if !defined(OS_ANDROID) && !defined(OS_IOS) +TEST_F(PersonalDataManagerTest, GetProfileSuggestions_ForAddressPhoneForm) { + AutofillProfile profile(base::GenerateGUID(), test::kEmptyOrigin); + test::SetProfileInfo(&profile, "Hoa", "", "Pham", "hoa.pham@comcast.net", "", + "401 Merrimack St", "", "Lowell", "MA", "01852", "US", + "19786744120"); + AddProfileToPersonalDataManager(profile); + + base::test::ScopedFeatureList scoped_features; + scoped_features.InitAndEnableFeature( + features::kAutofillUseImprovedLabelDisambiguation); + + EXPECT_THAT( + personal_data_->GetProfileSuggestions( + AutofillType(NAME_FULL), base::string16(), false, + std::vector<ServerFieldType>{NAME_FULL, ADDRESS_HOME_STREET_ADDRESS, + PHONE_HOME_WHOLE_NUMBER}), + ElementsAre(AllOf( + testing::Field( + &Suggestion::label, + ConstructLabelLine({base::ASCIIToUTF16("(978) 674-4120"), + base::ASCIIToUTF16("401 Merrimack St")})), + testing::Field( + &Suggestion::additional_label, + ConstructLabelLine({base::ASCIIToUTF16("(978) 674-4120"), + base::ASCIIToUTF16("401 Merrimack St")})), + testing::Field(&Suggestion::icon, "accountBoxIcon")))); +} +#endif // #if !defined(OS_ANDROID) && !defined(OS_IOS) + +#if !defined(OS_ANDROID) && !defined(OS_IOS) +TEST_F(PersonalDataManagerTest, GetProfileSuggestions_ForAddressEmailForm) { + AutofillProfile profile(base::GenerateGUID(), test::kEmptyOrigin); + test::SetProfileInfo(&profile, "Hoa", "", "Pham", "hoa.pham@comcast.net", "", + "401 Merrimack St", "", "Lowell", "MA", "01852", "US", + "19786744120"); + AddProfileToPersonalDataManager(profile); + + base::test::ScopedFeatureList scoped_features; + scoped_features.InitAndEnableFeature( + features::kAutofillUseImprovedLabelDisambiguation); + + EXPECT_THAT( + personal_data_->GetProfileSuggestions( + AutofillType(NAME_FULL), base::string16(), false, + std::vector<ServerFieldType>{NAME_FULL, ADDRESS_HOME_STREET_ADDRESS, + EMAIL_ADDRESS}), + ElementsAre(AllOf( + testing::Field( + &Suggestion::label, + ConstructLabelLine({base::ASCIIToUTF16("401 Merrimack St"), + base::ASCIIToUTF16("hoa.pham@comcast.net")})), + testing::Field( + &Suggestion::additional_label, + ConstructLabelLine({base::ASCIIToUTF16("401 Merrimack St"), + base::ASCIIToUTF16("hoa.pham@comcast.net")})), + testing::Field(&Suggestion::icon, "accountBoxIcon")))); +} +#endif // #if !defined(OS_ANDROID) && !defined(OS_IOS) + +#if !defined(OS_ANDROID) && !defined(OS_IOS) +TEST_F(PersonalDataManagerTest, GetProfileSuggestions_FormWithOneProfile) { + AutofillProfile profile(base::GenerateGUID(), test::kEmptyOrigin); + test::SetProfileInfo(&profile, "Hoa", "", "Pham", "hoa.pham@comcast.net", "", + "401 Merrimack St", "", "Lowell", "MA", "01852", "US", + "19786744120"); + AddProfileToPersonalDataManager(profile); + + base::test::ScopedFeatureList scoped_features; + scoped_features.InitAndEnableFeature( + features::kAutofillUseImprovedLabelDisambiguation); + + EXPECT_THAT( + personal_data_->GetProfileSuggestions( + AutofillType(NAME_FULL), base::string16(), false, + std::vector<ServerFieldType>{NAME_FULL, ADDRESS_HOME_STREET_ADDRESS, + EMAIL_ADDRESS, PHONE_HOME_WHOLE_NUMBER}), + ElementsAre(AllOf( + testing::Field( + &Suggestion::label, + ConstructLabelLine({base::ASCIIToUTF16("401 Merrimack St")})), + testing::Field( + &Suggestion::additional_label, + ConstructLabelLine({base::ASCIIToUTF16("401 Merrimack St")})), + testing::Field(&Suggestion::icon, "accountBoxIcon")))); +} +#endif // #if !defined(OS_ANDROID) && !defined(OS_IOS) + +#if !defined(OS_ANDROID) && !defined(OS_IOS) +TEST_F(PersonalDataManagerTest, + GetProfileSuggestions_ForAddressContactFormWithProfiles) { + AutofillProfile profile1(base::GenerateGUID(), test::kEmptyOrigin); + test::SetProfileInfo(&profile1, "Hoa", "", "Pham", "hoa.pham@comcast.net", "", + "401 Merrimack St", "", "Lowell", "MA", "01852", "US", + "19786744120"); + + AutofillProfile profile2(base::GenerateGUID(), test::kEmptyOrigin); + test::SetProfileInfo(&profile2, "Hoa", "", "Pham", "hp@aol.com", "", + "216 Broadway St", "", "Lowell", "MA", "01854", "US", + "19784523366"); + + // The profiles' use dates and counts are set make this test deterministic. + // The suggestion created with data from profile1 should be ranked higher + // than profile2's associated suggestion. This ensures that profile1's + // suggestion is the first element in the collection returned by + // GetProfileSuggestions. + profile1.set_use_date(AutofillClock::Now()); + profile1.set_use_count(10); + profile2.set_use_date(AutofillClock::Now() - base::TimeDelta::FromDays(10)); + profile2.set_use_count(1); + + EXPECT_TRUE(profile1.HasGreaterFrecencyThan(&profile2, base::Time::Now())); + + AddProfileToPersonalDataManager(profile1); + AddProfileToPersonalDataManager(profile2); + + base::test::ScopedFeatureList scoped_features; + scoped_features.InitAndEnableFeature( + features::kAutofillUseImprovedLabelDisambiguation); + + EXPECT_THAT( + personal_data_->GetProfileSuggestions( + AutofillType(NAME_FULL), base::string16(), false, + std::vector<ServerFieldType>{NAME_FULL, ADDRESS_HOME_STREET_ADDRESS, + EMAIL_ADDRESS, PHONE_HOME_WHOLE_NUMBER}), + ElementsAre( + AllOf( + testing::Field(&Suggestion::label, + ConstructLabelLine( + {base::ASCIIToUTF16("401 Merrimack St"), + base::ASCIIToUTF16("(978) 674-4120"), + base::ASCIIToUTF16("hoa.pham@comcast.net")})), + testing::Field(&Suggestion::additional_label, + ConstructLabelLine( + {base::ASCIIToUTF16("401 Merrimack St"), + base::ASCIIToUTF16("(978) 674-4120"), + base::ASCIIToUTF16("hoa.pham@comcast.net")})), + testing::Field(&Suggestion::icon, "accountBoxIcon")), + AllOf(testing::Field( + &Suggestion::label, + ConstructLabelLine({base::ASCIIToUTF16("216 Broadway St"), + base::ASCIIToUTF16("(978) 452-3366"), + base::ASCIIToUTF16("hp@aol.com")})), + testing::Field( + &Suggestion::additional_label, + ConstructLabelLine({base::ASCIIToUTF16("216 Broadway St"), + base::ASCIIToUTF16("(978) 452-3366"), + base::ASCIIToUTF16("hp@aol.com")})), + testing::Field(&Suggestion::icon, "accountBoxIcon")))); +} +#endif // #if !defined(OS_ANDROID) && !defined(OS_IOS) + TEST_F(PersonalDataManagerTest, IsKnownCard_MatchesMaskedServerCard) { // Add a masked server card. std::vector<CreditCard> server_cards; @@ -3081,27 +3265,6 @@ TEST_F(PersonalDataManagerTest, WaitForOnPersonalDataChanged(); ASSERT_EQ(4U, personal_data_->GetCreditCards().size()); - // Verify no suppression if feature is disabled. - { - base::test::ScopedFeatureList scoped_features; - scoped_features.InitAndDisableFeature( - features::kAutofillSuppressDisusedCreditCards); - - std::vector<Suggestion> suggestions = - personal_data_->GetCreditCardSuggestions( - AutofillType(CREDIT_CARD_NAME_FULL), base::string16(), - /*include_server_cards=*/true); - EXPECT_EQ(4U, suggestions.size()); - EXPECT_EQ(base::ASCIIToUTF16("Bonnie Parker"), suggestions[0].value); - EXPECT_EQ(base::ASCIIToUTF16("Clyde Barrow"), suggestions[1].value); - EXPECT_EQ(base::ASCIIToUTF16("Jane Doe"), suggestions[2].value); - EXPECT_EQ(base::ASCIIToUTF16("John Dillinger"), suggestions[3].value); - } - - base::test::ScopedFeatureList scoped_features; - scoped_features.InitAndEnableFeature( - features::kAutofillSuppressDisusedCreditCards); - // Query with empty string only returns card0 and card1. Note expired // masked card2 is not suggested on empty fields. { @@ -5079,31 +5242,10 @@ TEST_F(PersonalDataManagerTest, ApplyDedupingRoutine_OncePerVersion) { EXPECT_EQ(2U, personal_data_->GetProfiles().size()); } -// Tests that DeleteDisusedAddresses is not run if the feature is disabled. -TEST_F(PersonalDataManagerTest, DeleteDisusedAddresses_DoNothingWhenDisabled) { - base::test::ScopedFeatureList scoped_features; - scoped_features.InitAndDisableFeature( - features::kAutofillDeleteDisusedAddresses); - - CreateDeletableDisusedProfile(); - - // DeleteDisusedCreditCards should return false to indicate it was not run. - EXPECT_FALSE(personal_data_->DeleteDisusedAddresses()); - - personal_data_->Refresh(); - - EXPECT_EQ(1U, personal_data_->GetProfiles().size()); -} - // Tests that DeleteDisusedAddresses only deletes the addresses that are // supposed to be deleted. TEST_F(PersonalDataManagerTest, DeleteDisusedAddresses_DeleteDesiredAddressesOnly) { - // Enable the feature. - base::test::ScopedFeatureList scoped_features; - scoped_features.InitAndEnableFeature( - features::kAutofillDeleteDisusedAddresses); - auto now = AutofillClock::Now(); // Create unverified/disused/not-used-by-valid-credit-card @@ -5182,31 +5324,9 @@ TEST_F(PersonalDataManagerTest, personal_data_->GetProfiles()[2]->GetRawInfo(NAME_LAST)); } -// Tests that DeleteDisusedCreditCards is not run if the feature is disabled. -TEST_F(PersonalDataManagerTest, - DeleteDisusedCreditCards_DoNothingWhenDisabled) { - base::test::ScopedFeatureList scoped_features; - scoped_features.InitAndDisableFeature( - features::kAutofillDeleteDisusedCreditCards); - - CreateDeletableExpiredAndDisusedCreditCard(); - - // DeleteDisusedCreditCards should return false to indicate it was not run. - EXPECT_FALSE(personal_data_->DeleteDisusedCreditCards()); - - personal_data_->Refresh(); - - EXPECT_EQ(1U, personal_data_->GetCreditCards().size()); -} - // Tests that DeleteDisusedCreditCards deletes desired credit cards only. TEST_F(PersonalDataManagerTest, DeleteDisusedCreditCards_OnlyDeleteExpiredDisusedLocalCards) { - // Enable the feature. - base::test::ScopedFeatureList scoped_features; - scoped_features.InitAndEnableFeature( - features::kAutofillDeleteDisusedCreditCards); - const char kHistogramName[] = "Autofill.CreditCardsDeletedForDisuse"; auto now = AutofillClock::Now(); @@ -5563,14 +5683,7 @@ TEST_F(PersonalDataManagerTest, /////////////////////////////////////////////////////////////////////// // Tested method. /////////////////////////////////////////////////////////////////////// - personal_data_->ConvertWalletAddressesAndUpdateWalletCards(); - - // Since there should be no change in data, OnPersonalDataChanged should not - // have been called. - EXPECT_CALL(personal_data_observer_, OnPersonalDataChanged()).Times(0); - - personal_data_->Refresh(); - WaitForOnPersonalDataChanged(); + ConvertWalletAddressesAndUpdateWalletCards(); // There should be no local profiles added. EXPECT_EQ(0U, personal_data_->GetProfiles().size()); @@ -5841,18 +5954,11 @@ TEST_F(PersonalDataManagerTest, DoNotConvertWalletAddressesInEphemeralStorage) { /////////////////////////////////////////////////////////////////////// // Since the wallet addresses are in ephemeral storage, they should *not* get // converted to local addresses. - personal_data_->ConvertWalletAddressesAndUpdateWalletCards(); + ConvertWalletAddressesAndUpdateWalletCards(); /////////////////////////////////////////////////////////////////////// // Validation. /////////////////////////////////////////////////////////////////////// - // Since there should be no change in data, OnPersonalDataChanged should not - // get called. - EXPECT_CALL(personal_data_observer_, OnPersonalDataChanged()).Times(0); - - personal_data_->Refresh(); - WaitForOnPersonalDataChanged(); - // There should be no changes to the local profiles: No new one added, and no // changes to the existing one (even though the second server profile contains // additional information and is mergeable in principle). @@ -7662,7 +7768,7 @@ TEST_F(PersonalDataManagerTest, GetSyncSigninState) { // Check that the sync state is |SignedInAndSyncFeature| if the sync feature // is enabled. - EXPECT_EQ(AutofillSyncSigninState::kSignedInAndSyncFeature, + EXPECT_EQ(AutofillSyncSigninState::kSignedInAndSyncFeatureEnabled, personal_data_->GetSyncSigninState()); // Check that the sync state is |SignedInAndSyncFeature| if the the sync @@ -7674,7 +7780,7 @@ TEST_F(PersonalDataManagerTest, GetSyncSigninState) { /*enabled_features=*/{features::kAutofillEnableAccountWalletStorage, features::kAutofillGetPaymentsIdentityFromSync}, /*disabled_features=*/{}); - EXPECT_EQ(AutofillSyncSigninState::kSignedInAndSyncFeature, + EXPECT_EQ(AutofillSyncSigninState::kSignedInAndSyncFeatureEnabled, personal_data_->GetSyncSigninState()); } } @@ -7760,7 +7866,7 @@ TEST_F(PersonalDataManagerTest, OnUserAcceptedUpstreamOffer) { identity_test_env_.SetPrimaryAccount(active_info.email); sync_service_.SetIsAuthenticatedAccountPrimary(true); { - EXPECT_EQ(AutofillSyncSigninState::kSignedInAndSyncFeature, + EXPECT_EQ(AutofillSyncSigninState::kSignedInAndSyncFeatureEnabled, personal_data_->GetSyncSigninState()); // Make sure an opt-in does not get recorded even if the user accepted an diff --git a/chromium/components/autofill/core/browser/phone_number.cc b/chromium/components/autofill/core/browser/phone_number.cc index f60a58b5d42..7498365f806 100644 --- a/chromium/components/autofill/core/browser/phone_number.cc +++ b/chromium/components/autofill/core/browser/phone_number.cc @@ -31,7 +31,7 @@ std::string GetRegion(const AutofillProfile& profile, } // namespace -PhoneNumber::PhoneNumber(AutofillProfile* profile) : profile_(profile) {} +PhoneNumber::PhoneNumber(const AutofillProfile* profile) : profile_(profile) {} PhoneNumber::PhoneNumber(const PhoneNumber& number) : profile_(nullptr) { *this = number; diff --git a/chromium/components/autofill/core/browser/phone_number.h b/chromium/components/autofill/core/browser/phone_number.h index 4773e8cb34c..ab350f3201d 100644 --- a/chromium/components/autofill/core/browser/phone_number.h +++ b/chromium/components/autofill/core/browser/phone_number.h @@ -21,7 +21,7 @@ class AutofillProfile; // A form group that stores phone number information. class PhoneNumber : public FormGroup { public: - explicit PhoneNumber(AutofillProfile* profile); + explicit PhoneNumber(const AutofillProfile* profile); PhoneNumber(const PhoneNumber& number); ~PhoneNumber() override; @@ -29,7 +29,7 @@ class PhoneNumber : public FormGroup { bool operator==(const PhoneNumber& other) const; bool operator!=(const PhoneNumber& other) const { return !operator==(other); } - void set_profile(AutofillProfile* profile) { profile_ = profile; } + void set_profile(const AutofillProfile* profile) { profile_ = profile; } // FormGroup implementation: void GetMatchingTypes(const base::string16& text, diff --git a/chromium/components/autofill/core/browser/phone_number_i18n.cc b/chromium/components/autofill/core/browser/phone_number_i18n.cc index 956eed000e7..ecfbe9ad12e 100644 --- a/chromium/components/autofill/core/browser/phone_number_i18n.cc +++ b/chromium/components/autofill/core/browser/phone_number_i18n.cc @@ -265,6 +265,8 @@ bool PhoneNumbersMatch(const base::string16& number_a, const base::string16& number_b, const std::string& raw_region, const std::string& app_locale) { + // TODO(crbug.com/953678): Maybe return true if two empty strings are given. + // Sanitize the provided |raw_region| before trying to use it for parsing. const std::string region = SanitizeRegion(raw_region, app_locale); diff --git a/chromium/components/autofill/core/browser/proto/api_v1.proto b/chromium/components/autofill/core/browser/proto/api_v1.proto index d19c41905d6..0b26c68c576 100644 --- a/chromium/components/autofill/core/browser/proto/api_v1.proto +++ b/chromium/components/autofill/core/browser/proto/api_v1.proto @@ -24,7 +24,7 @@ message AutofillPageResourceQueryRequest { // Request to retrieve field suggestions for multiple forms in a page. You can // see this as batched form requests. -// Next ID: 3 +// Next ID: 4 message AutofillPageQueryRequest { // Next ID: 3 message Form { @@ -54,6 +54,8 @@ message AutofillPageQueryRequest { optional string client_version = 1 [deprecated = true]; // Forms in the same page for which we want fields suggestions. repeated Form forms = 2; + // The collection of server-side experiments to use. + repeated int64 experiments = 3; }; // Response containing field suggestions from Autofill API for diff --git a/chromium/components/autofill/core/browser/proto/legacy_proto_bridge.cc b/chromium/components/autofill/core/browser/proto/legacy_proto_bridge.cc index 3bd19b491aa..9ce166cb9dc 100644 --- a/chromium/components/autofill/core/browser/proto/legacy_proto_bridge.cc +++ b/chromium/components/autofill/core/browser/proto/legacy_proto_bridge.cc @@ -56,6 +56,7 @@ AutofillQueryResponseContents::Field CreateLegacyFieldFromApiField( AutofillPageQueryRequest CreateApiRequestFromLegacyRequest( const AutofillQueryContents& legacy_request) { AutofillPageQueryRequest api_request; + *api_request.mutable_experiments() = legacy_request.experiments(); api_request.set_client_version(legacy_request.client_version()); for (const auto& legacy_form : legacy_request.form()) { *api_request.add_forms() = CreateApiFormFromLegacyForm(legacy_form); diff --git a/chromium/components/autofill/core/browser/proto/legacy_proto_bridge_unittest.cc b/chromium/components/autofill/core/browser/proto/legacy_proto_bridge_unittest.cc index bd875b3931d..6c4f791dd1c 100644 --- a/chromium/components/autofill/core/browser/proto/legacy_proto_bridge_unittest.cc +++ b/chromium/components/autofill/core/browser/proto/legacy_proto_bridge_unittest.cc @@ -70,6 +70,8 @@ AutofillQueryResponse::FormSuggestion::FieldSuggestion MakeFieldSuggestion( TEST(ProtoBridgeTest, TestCreateApiRequestFromLegacyRequest) { AutofillQueryContents legacy_request; legacy_request.set_client_version("dummy client v1"); + legacy_request.add_experiments(1234); + legacy_request.add_experiments(5678); AutofillQueryContents::Form* new_form = legacy_request.add_form(); new_form->set_signature(1234U); *new_form->mutable_form_metadata() = GetformMetadata(); @@ -86,6 +88,8 @@ TEST(ProtoBridgeTest, TestCreateApiRequestFromLegacyRequest) { CreateApiRequestFromLegacyRequest(legacy_request); EXPECT_EQ(api_request.client_version(), "dummy client v1"); + EXPECT_EQ(api_request.experiments(0), 1234); + EXPECT_EQ(api_request.experiments(1), 5678); EXPECT_EQ(api_request.forms(0).signature(), 1234U); EXPECT_EQ(api_request.forms(0).metadata().id().encoding_type(), AutofillRandomizedValue::BIT_1); diff --git a/chromium/components/autofill/core/browser/proto/server.proto b/chromium/components/autofill/core/browser/proto/server.proto index 86bc91e222d..02f57c7440e 100644 --- a/chromium/components/autofill/core/browser/proto/server.proto +++ b/chromium/components/autofill/core/browser/proto/server.proto @@ -186,7 +186,7 @@ message AutofillRandomizedFieldMetadata { // This message contains information about the field types in a single form. // It is sent by the toolbar to contribute to the field type statistics. -// Next available id: 39 +// Next available id: 40 message AutofillUploadContents { required string client_version = 1; required fixed64 form_signature = 2; @@ -343,6 +343,13 @@ message AutofillUploadContents { // Noisifed password length. optional uint32 password_length = 29; + + // If |password_has_special_symbol| is true, this field contains nosified + // information about a special symbol used in a user-created password stored + // in ASCII code. + // Otherwise, this field is unset. + optional uint32 password_special_symbol = 39; + // The end of the section of password attributes. // Event observed by the password manager which indicated that the form was diff --git a/chromium/components/autofill/core/browser/suggestion_selection.cc b/chromium/components/autofill/core/browser/suggestion_selection.cc index 0a8d6c04a10..05fd1c4b25c 100644 --- a/chromium/components/autofill/core/browser/suggestion_selection.cc +++ b/chromium/components/autofill/core/browser/suggestion_selection.cc @@ -9,7 +9,9 @@ #include "base/strings/string_util.h" #include "base/strings/utf_string_conversions.h" #include "base/time/time.h" +#include "build/build_config.h" #include "components/autofill/core/browser/address_i18n.h" +#include "components/autofill/core/browser/autofill_data_util.h" #include "components/autofill/core/browser/autofill_metrics.h" #include "components/autofill/core/browser/autofill_profile.h" #include "components/autofill/core/browser/autofill_profile_comparator.h" @@ -84,6 +86,22 @@ std::vector<Suggestion> GetPrefixMatchedSuggestions( suggestion_canon, field_contents_canon, type, /* is_masked_server_card= */ false, &prefix_matched_suggestion)) { matched_profiles->push_back(profile); + +#if !defined(OS_ANDROID) && !defined(OS_IOS) + // If the field with which the user is interacting is a phone number or + // part of a phone number, then display it in the national format + // corresponding to the profile's country. For example, (508) 488-0800 + // will be shown rather than 15084880800, 508 488 0800, or +15084880800 + // for US phone numbers. + if (base::FeatureList::IsEnabled( + autofill::features::kAutofillUseImprovedLabelDisambiguation) && + type.group() == PHONE_HOME) { + value = base::UTF8ToUTF16(i18n::FormatPhoneNationallyForDisplay( + base::UTF16ToUTF8(value), data_util::GetCountryCodeWithFallback( + *profile, comparator.app_locale()))); + } +#endif + suggestions.push_back(Suggestion(value)); suggestions.back().backend_id = profile->guid(); suggestions.back().match = prefix_matched_suggestion @@ -204,5 +222,23 @@ void RemoveProfilesNotUsedSinceTimestamp( num_profiles_supressed); } +void PrepareSuggestions(bool contains_address, + const std::vector<base::string16>& labels, + std::vector<Suggestion>* suggestions) { + DCHECK_EQ(suggestions->size(), labels.size()); + + for (size_t i = 0; i < labels.size(); ++i) { + (*suggestions)[i].additional_label = base::string16(labels[i]); + (*suggestions)[i].label = base::string16(labels[i]); + +#if !defined(OS_ANDROID) && !defined(OS_IOS) + if (base::FeatureList::IsEnabled( + autofill::features::kAutofillUseImprovedLabelDisambiguation)) { + (*suggestions)[i].icon = "accountBoxIcon"; + } +#endif + } +} + } // namespace suggestion_selection } // namespace autofill diff --git a/chromium/components/autofill/core/browser/suggestion_selection.h b/chromium/components/autofill/core/browser/suggestion_selection.h index 0e6909e4c51..817c0d20756 100644 --- a/chromium/components/autofill/core/browser/suggestion_selection.h +++ b/chromium/components/autofill/core/browser/suggestion_selection.h @@ -59,6 +59,15 @@ void RemoveProfilesNotUsedSinceTimestamp( base::Time min_last_used, std::vector<AutofillProfile*>* profiles); +// Prepares a collection of Suggestions to show to the user. Adds |labels| to +// their corresponding |suggestions|. A label corresponds to the suggestion with +// the same index. +// |contains_address| determines which icon to add to suggestions in the +// autofill-use-improved-label-disambiguation experiment. +void PrepareSuggestions(bool contains_address, + const std::vector<base::string16>& labels, + std::vector<Suggestion>* suggestions); + } // namespace suggestion_selection } // namespace autofill diff --git a/chromium/components/autofill/core/browser/sync_utils.h b/chromium/components/autofill/core/browser/sync_utils.h index 2774bedb055..1024c4072b7 100644 --- a/chromium/components/autofill/core/browser/sync_utils.h +++ b/chromium/components/autofill/core/browser/sync_utils.h @@ -18,7 +18,10 @@ enum AutofillSyncSigninState { kSignedInAndWalletSyncTransportEnabled, // The user is signed in, has enabled the sync feature and has not disabled // Wallet sync. - kSignedInAndSyncFeature, + kSignedInAndSyncFeatureEnabled, + // The user has enabled the sync feature, but has then signed out, so sync is + // paused. + kSyncPaused, kNumSyncStates, }; diff --git a/chromium/components/autofill/core/browser/test_autofill_client.cc b/chromium/components/autofill/core/browser/test_autofill_client.cc index dadbbd1dfed..fe92b8c4974 100644 --- a/chromium/components/autofill/core/browser/test_autofill_client.cc +++ b/chromium/components/autofill/core/browser/test_autofill_client.cc @@ -7,7 +7,7 @@ #include "base/strings/utf_string_conversions.h" #include "components/autofill/core/browser/autofill_metrics.h" #include "components/autofill/core/browser/autofill_test_utils.h" -#include "components/autofill/core/browser/local_card_migration_manager.h" +#include "components/autofill/core/browser/payments/local_card_migration_manager.h" #include "components/autofill/core/browser/webdata/autofill_webdata_service.h" namespace autofill { diff --git a/chromium/components/autofill/core/browser/test_autofill_client.h b/chromium/components/autofill/core/browser/test_autofill_client.h index 71baad73db0..70217e9ffff 100644 --- a/chromium/components/autofill/core/browser/test_autofill_client.h +++ b/chromium/components/autofill/core/browser/test_autofill_client.h @@ -16,12 +16,12 @@ #include "build/build_config.h" #include "components/autofill/core/browser/autofill_client.h" #include "components/autofill/core/browser/mock_autocomplete_history_manager.h" +#include "components/autofill/core/browser/payments/test_legacy_strike_database.h" #include "components/autofill/core/browser/payments/test_payments_client.h" +#include "components/autofill/core/browser/payments/test_strike_database.h" #include "components/autofill/core/browser/test_address_normalizer.h" #include "components/autofill/core/browser/test_form_data_importer.h" -#include "components/autofill/core/browser/test_legacy_strike_database.h" #include "components/autofill/core/browser/test_personal_data_manager.h" -#include "components/autofill/core/browser/test_strike_database.h" #include "components/prefs/pref_service.h" #include "components/ukm/test_ukm_recorder.h" #include "services/identity/public/cpp/identity_test_environment.h" diff --git a/chromium/components/autofill/core/browser/test_personal_data_manager.cc b/chromium/components/autofill/core/browser/test_personal_data_manager.cc index 209cf497334..f1d48c3d9bc 100644 --- a/chromium/components/autofill/core/browser/test_personal_data_manager.cc +++ b/chromium/components/autofill/core/browser/test_personal_data_manager.cc @@ -50,7 +50,7 @@ void TestPersonalDataManager::AddProfile(const AutofillProfile& profile) { std::unique_ptr<AutofillProfile> profile_ptr = std::make_unique<AutofillProfile>(profile); web_profiles_.push_back(std::move(profile_ptr)); - NotifyPersonalDataChanged(); + NotifyPersonalDataObserver(); } void TestPersonalDataManager::UpdateProfile(const AutofillProfile& profile) { @@ -86,7 +86,7 @@ void TestPersonalDataManager::AddCreditCard(const CreditCard& credit_card) { std::unique_ptr<CreditCard> local_credit_card = std::make_unique<CreditCard>(credit_card); local_credit_cards_.push_back(std::move(local_credit_card)); - NotifyPersonalDataChanged(); + NotifyPersonalDataObserver(); } void TestPersonalDataManager::DeleteLocalCreditCards( @@ -94,7 +94,7 @@ void TestPersonalDataManager::DeleteLocalCreditCards( for (const auto& card : cards) RemoveByGUID(card.guid()); - NotifyPersonalDataChanged(); + NotifyPersonalDataObserver(); } void TestPersonalDataManager::UpdateCreditCard(const CreditCard& credit_card) { @@ -287,7 +287,7 @@ void TestPersonalDataManager::AddServerCreditCard( std::unique_ptr<CreditCard> server_credit_card = std::make_unique<CreditCard>(credit_card); server_credit_cards_.push_back(std::move(server_credit_card)); - NotifyPersonalDataChanged(); + NotifyPersonalDataObserver(); } } // namespace autofill diff --git a/chromium/components/autofill/core/browser/test_personal_data_manager.h b/chromium/components/autofill/core/browser/test_personal_data_manager.h index 8aedd182f36..0dd399b004b 100644 --- a/chromium/components/autofill/core/browser/test_personal_data_manager.h +++ b/chromium/components/autofill/core/browser/test_personal_data_manager.h @@ -135,7 +135,7 @@ class TestPersonalDataManager : public PersonalDataManager { base::Optional<bool> autofill_wallet_import_enabled_; bool sync_feature_enabled_ = false; AutofillSyncSigninState sync_and_signin_state_ = - AutofillSyncSigninState::kSignedInAndSyncFeature; + AutofillSyncSigninState::kSignedInAndSyncFeatureEnabled; bool sync_service_initialized_ = false; CoreAccountInfo account_info_; diff --git a/chromium/components/autofill/core/browser/ui/DEPS b/chromium/components/autofill/core/browser/ui/payments/DEPS index ed07b2dd031..ed07b2dd031 100644 --- a/chromium/components/autofill/core/browser/ui/DEPS +++ b/chromium/components/autofill/core/browser/ui/payments/DEPS diff --git a/chromium/components/autofill/core/browser/ui/payments/OWNERS b/chromium/components/autofill/core/browser/ui/payments/OWNERS new file mode 100644 index 00000000000..a6f6a368d86 --- /dev/null +++ b/chromium/components/autofill/core/browser/ui/payments/OWNERS @@ -0,0 +1 @@ +file://components/autofill/core/browser/payments/OWNERS diff --git a/chromium/components/autofill/core/browser/ui/card_expiration_date_fix_flow_view_delegate_mobile.cc b/chromium/components/autofill/core/browser/ui/payments/card_expiration_date_fix_flow_view_delegate_mobile.cc index 812c157cc11..f60bd3e41df 100644 --- a/chromium/components/autofill/core/browser/ui/card_expiration_date_fix_flow_view_delegate_mobile.cc +++ b/chromium/components/autofill/core/browser/ui/payments/card_expiration_date_fix_flow_view_delegate_mobile.cc @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "components/autofill/core/browser/ui/card_expiration_date_fix_flow_view_delegate_mobile.h" +#include "components/autofill/core/browser/ui/payments/card_expiration_date_fix_flow_view_delegate_mobile.h" #include <utility> diff --git a/chromium/components/autofill/core/browser/ui/card_expiration_date_fix_flow_view_delegate_mobile.h b/chromium/components/autofill/core/browser/ui/payments/card_expiration_date_fix_flow_view_delegate_mobile.h index d749b79ad1f..fcc6e3afb7b 100644 --- a/chromium/components/autofill/core/browser/ui/card_expiration_date_fix_flow_view_delegate_mobile.h +++ b/chromium/components/autofill/core/browser/ui/payments/card_expiration_date_fix_flow_view_delegate_mobile.h @@ -2,8 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#ifndef COMPONENTS_AUTOFILL_CORE_BROWSER_UI_CARD_EXPIRATION_DATE_FIX_FLOW_VIEW_DELEGATE_MOBILE_H_ -#define COMPONENTS_AUTOFILL_CORE_BROWSER_UI_CARD_EXPIRATION_DATE_FIX_FLOW_VIEW_DELEGATE_MOBILE_H_ +#ifndef COMPONENTS_AUTOFILL_CORE_BROWSER_UI_PAYMENTS_CARD_EXPIRATION_DATE_FIX_FLOW_VIEW_DELEGATE_MOBILE_H_ +#define COMPONENTS_AUTOFILL_CORE_BROWSER_UI_PAYMENTS_CARD_EXPIRATION_DATE_FIX_FLOW_VIEW_DELEGATE_MOBILE_H_ #include <memory> @@ -57,4 +57,4 @@ class CardExpirationDateFixFlowViewDelegateMobile { } // namespace autofill -#endif // COMPONENTS_AUTOFILL_CORE_BROWSER_UI_CARD_EXPIRATION_DATE_FIX_FLOW_VIEW_DELEGATE_MOBILE_H_ +#endif // COMPONENTS_AUTOFILL_CORE_BROWSER_UI_PAYMENTS_CARD_EXPIRATION_DATE_FIX_FLOW_VIEW_DELEGATE_MOBILE_H_ diff --git a/chromium/components/autofill/core/browser/ui/card_name_fix_flow_view_delegate_mobile.cc b/chromium/components/autofill/core/browser/ui/payments/card_name_fix_flow_view_delegate_mobile.cc index c5d3b1f8980..aebe3e2cdad 100644 --- a/chromium/components/autofill/core/browser/ui/card_name_fix_flow_view_delegate_mobile.cc +++ b/chromium/components/autofill/core/browser/ui/payments/card_name_fix_flow_view_delegate_mobile.cc @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "components/autofill/core/browser/ui/card_name_fix_flow_view_delegate_mobile.h" +#include "components/autofill/core/browser/ui/payments/card_name_fix_flow_view_delegate_mobile.h" #include <utility> diff --git a/chromium/components/autofill/core/browser/ui/card_name_fix_flow_view_delegate_mobile.h b/chromium/components/autofill/core/browser/ui/payments/card_name_fix_flow_view_delegate_mobile.h index dcad3d0ee06..64415a44661 100644 --- a/chromium/components/autofill/core/browser/ui/card_name_fix_flow_view_delegate_mobile.h +++ b/chromium/components/autofill/core/browser/ui/payments/card_name_fix_flow_view_delegate_mobile.h @@ -2,8 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#ifndef COMPONENTS_AUTOFILL_CORE_BROWSER_UI_CARD_NAME_FIX_FLOW_VIEW_DELEGATE_MOBILE_H_ -#define COMPONENTS_AUTOFILL_CORE_BROWSER_UI_CARD_NAME_FIX_FLOW_VIEW_DELEGATE_MOBILE_H_ +#ifndef COMPONENTS_AUTOFILL_CORE_BROWSER_UI_PAYMENTS_CARD_NAME_FIX_FLOW_VIEW_DELEGATE_MOBILE_H_ +#define COMPONENTS_AUTOFILL_CORE_BROWSER_UI_PAYMENTS_CARD_NAME_FIX_FLOW_VIEW_DELEGATE_MOBILE_H_ #include <memory> @@ -34,7 +34,6 @@ class CardNameFixFlowViewDelegateMobile { void Shown(); private: - // Inferred cardholder name from Gaia account. base::string16 inferred_cardholder_name_; @@ -53,4 +52,4 @@ class CardNameFixFlowViewDelegateMobile { } // namespace autofill -#endif // COMPONENTS_AUTOFILL_CORE_BROWSER_UI_CARD_NAME_FIX_FLOW_VIEW_DELEGATE_MOBILE_H_ +#endif // COMPONENTS_AUTOFILL_CORE_BROWSER_UI_PAYMENTS_CARD_NAME_FIX_FLOW_VIEW_DELEGATE_MOBILE_H_ diff --git a/chromium/components/autofill/core/browser/ui/card_unmask_prompt_controller.h b/chromium/components/autofill/core/browser/ui/payments/card_unmask_prompt_controller.h index 68e71be5927..b4c5da8a029 100644 --- a/chromium/components/autofill/core/browser/ui/card_unmask_prompt_controller.h +++ b/chromium/components/autofill/core/browser/ui/payments/card_unmask_prompt_controller.h @@ -2,8 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#ifndef COMPONENTS_AUTOFILL_CORE_BROWSER_UI_CARD_UNMASK_PROMPT_CONTROLLER_H_ -#define COMPONENTS_AUTOFILL_CORE_BROWSER_UI_CARD_UNMASK_PROMPT_CONTROLLER_H_ +#ifndef COMPONENTS_AUTOFILL_CORE_BROWSER_UI_PAYMENTS_CARD_UNMASK_PROMPT_CONTROLLER_H_ +#define COMPONENTS_AUTOFILL_CORE_BROWSER_UI_PAYMENTS_CARD_UNMASK_PROMPT_CONTROLLER_H_ #include "base/strings/string16.h" #include "components/autofill/core/browser/autofill_client.h" @@ -44,4 +44,4 @@ class CardUnmaskPromptController { } // namespace autofill -#endif // COMPONENTS_AUTOFILL_CORE_BROWSER_UI_CARD_UNMASK_PROMPT_CONTROLLER_H_ +#endif // COMPONENTS_AUTOFILL_CORE_BROWSER_UI_PAYMENTS_CARD_UNMASK_PROMPT_CONTROLLER_H_ diff --git a/chromium/components/autofill/core/browser/ui/card_unmask_prompt_controller_impl.cc b/chromium/components/autofill/core/browser/ui/payments/card_unmask_prompt_controller_impl.cc index 7a3c321db04..1015cfb9d56 100644 --- a/chromium/components/autofill/core/browser/ui/card_unmask_prompt_controller_impl.cc +++ b/chromium/components/autofill/core/browser/ui/payments/card_unmask_prompt_controller_impl.cc @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "components/autofill/core/browser/ui/card_unmask_prompt_controller_impl.h" +#include "components/autofill/core/browser/ui/payments/card_unmask_prompt_controller_impl.h" #include <stddef.h> @@ -14,9 +14,10 @@ #include "build/build_config.h" #include "components/autofill/core/browser/autofill_experiments.h" #include "components/autofill/core/browser/autofill_metrics.h" -#include "components/autofill/core/browser/ui/card_unmask_prompt_view.h" +#include "components/autofill/core/browser/ui/payments/card_unmask_prompt_view.h" #include "components/autofill/core/browser/validation.h" #include "components/autofill/core/common/autofill_clock.h" +#include "components/autofill/core/common/autofill_payments_features.h" #include "components/autofill/core/common/autofill_prefs.h" #include "components/grit/components_scaled_resources.h" #include "components/prefs/pref_service.h" @@ -94,8 +95,7 @@ void CardUnmaskPromptControllerImpl::OnVerificationResult( AutofillMetrics::LogRealPanResult(result); AutofillMetrics::LogUnmaskingDuration( AutofillClock::Now() - verify_timestamp_, result); - card_unmask_view_->GotVerificationResult(error_message, - AllowsRetry(result)); + card_unmask_view_->GotVerificationResult(error_message, AllowsRetry(result)); } void CardUnmaskPromptControllerImpl::OnUnmaskDialogClosed() { @@ -126,8 +126,8 @@ void CardUnmaskPromptControllerImpl::OnUnmaskResponse( if (CanStoreLocally()) { pending_response_.should_store_pan = should_store_pan; // Remember the last choice the user made (on this device). - pref_service_->SetBoolean( - prefs::kAutofillWalletImportStorageCheckboxState, should_store_pan); + pref_service_->SetBoolean(prefs::kAutofillWalletImportStorageCheckboxState, + should_store_pan); } else { DCHECK(!should_store_pan); pending_response_.should_store_pan = false; @@ -198,6 +198,10 @@ bool CardUnmaskPromptControllerImpl::ShouldRequestExpirationDate() const { } bool CardUnmaskPromptControllerImpl::CanStoreLocally() const { + if (base::FeatureList::IsEnabled( + features::kAutofillNoLocalSaveOnUnmaskSuccess)) { + return false; + } // Never offer to save for incognito. if (is_off_the_record_) return false; @@ -205,6 +209,7 @@ bool CardUnmaskPromptControllerImpl::CanStoreLocally() const { return false; if (card_.record_type() == CreditCard::LOCAL_CARD) return false; + return OfferStoreUnmaskedCards(is_off_the_record_); } @@ -254,7 +259,8 @@ base::TimeDelta CardUnmaskPromptControllerImpl::GetSuccessMessageDuration() return base::TimeDelta::FromMilliseconds( card_.record_type() == CreditCard::LOCAL_CARD || reason_ == AutofillClient::UNMASK_FOR_PAYMENT_REQUEST - ? 0 : 500); + ? 0 + : 500); } AutofillClient::PaymentsRpcResult diff --git a/chromium/components/autofill/core/browser/ui/card_unmask_prompt_controller_impl.h b/chromium/components/autofill/core/browser/ui/payments/card_unmask_prompt_controller_impl.h index c7e3fb311f4..6a920e8e4b9 100644 --- a/chromium/components/autofill/core/browser/ui/card_unmask_prompt_controller_impl.h +++ b/chromium/components/autofill/core/browser/ui/payments/card_unmask_prompt_controller_impl.h @@ -2,8 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#ifndef COMPONENTS_AUTOFILL_CORE_BROWSER_UI_CARD_UNMASK_PROMPT_CONTROLLER_IMPL_H_ -#define COMPONENTS_AUTOFILL_CORE_BROWSER_UI_CARD_UNMASK_PROMPT_CONTROLLER_IMPL_H_ +#ifndef COMPONENTS_AUTOFILL_CORE_BROWSER_UI_PAYMENTS_CARD_UNMASK_PROMPT_CONTROLLER_IMPL_H_ +#define COMPONENTS_AUTOFILL_CORE_BROWSER_UI_PAYMENTS_CARD_UNMASK_PROMPT_CONTROLLER_IMPL_H_ #include <string> @@ -11,9 +11,9 @@ #include "base/macros.h" #include "base/memory/weak_ptr.h" #include "components/autofill/core/browser/autofill_metrics.h" -#include "components/autofill/core/browser/card_unmask_delegate.h" #include "components/autofill/core/browser/credit_card.h" -#include "components/autofill/core/browser/ui/card_unmask_prompt_controller.h" +#include "components/autofill/core/browser/payments/card_unmask_delegate.h" +#include "components/autofill/core/browser/ui/payments/card_unmask_prompt_controller.h" namespace autofill { @@ -21,9 +21,8 @@ class CardUnmaskPromptView; class CardUnmaskPromptControllerImpl : public CardUnmaskPromptController { public: - CardUnmaskPromptControllerImpl( - PrefService* pref_service, - bool is_off_the_record); + CardUnmaskPromptControllerImpl(PrefService* pref_service, + bool is_off_the_record); virtual ~CardUnmaskPromptControllerImpl(); // Functions called by ChromeAutofillClient. @@ -90,4 +89,4 @@ class CardUnmaskPromptControllerImpl : public CardUnmaskPromptController { } // namespace autofill -#endif // COMPONENTS_AUTOFILL_CORE_BROWSER_UI_CARD_UNMASK_PROMPT_CONTROLLER_IMPL_H_ +#endif // COMPONENTS_AUTOFILL_CORE_BROWSER_UI_PAYMENTS_CARD_UNMASK_PROMPT_CONTROLLER_IMPL_H_ diff --git a/chromium/components/autofill/core/browser/ui/card_unmask_prompt_controller_impl_unittest.cc b/chromium/components/autofill/core/browser/ui/payments/card_unmask_prompt_controller_impl_unittest.cc index 9012160a9b2..c916a47fd12 100644 --- a/chromium/components/autofill/core/browser/ui/card_unmask_prompt_controller_impl_unittest.cc +++ b/chromium/components/autofill/core/browser/ui/payments/card_unmask_prompt_controller_impl_unittest.cc @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "components/autofill/core/browser/ui/card_unmask_prompt_controller_impl.h" +#include "components/autofill/core/browser/ui/payments/card_unmask_prompt_controller_impl.h" #include <stddef.h> @@ -16,7 +16,8 @@ #include "components/autofill/core/browser/autofill_metrics.h" #include "components/autofill/core/browser/autofill_test_utils.h" #include "components/autofill/core/browser/credit_card.h" -#include "components/autofill/core/browser/ui/card_unmask_prompt_view.h" +#include "components/autofill/core/browser/ui/payments/card_unmask_prompt_view.h" +#include "components/autofill/core/common/autofill_payments_features.h" #include "components/autofill/core/common/autofill_prefs.h" #include "components/prefs/pref_registry_simple.h" #include "components/prefs/testing_pref_service.h" @@ -65,7 +66,8 @@ class TestCardUnmaskPromptController : public CardUnmaskPromptControllerImpl { explicit TestCardUnmaskPromptController( TestingPrefServiceSimple* pref_service) : CardUnmaskPromptControllerImpl(pref_service, false), - can_store_locally_(true), + can_store_locally_(!base::FeatureList::IsEnabled( + features::kAutofillNoLocalSaveOnUnmaskSuccess)), weak_factory_(this) {} bool CanStoreLocally() const override { return can_store_locally_; } @@ -92,35 +94,30 @@ class CardUnmaskPromptControllerImplGenericTest { CardUnmaskPromptControllerImplGenericTest() {} void ShowPrompt() { - controller_->ShowPrompt(test_unmask_prompt_view_.get(), - test::GetMaskedServerCard(), - AutofillClient::UNMASK_FOR_AUTOFILL, - delegate_->GetWeakPtr()); + controller_->ShowPrompt( + test_unmask_prompt_view_.get(), test::GetMaskedServerCard(), + AutofillClient::UNMASK_FOR_AUTOFILL, delegate_->GetWeakPtr()); } void ShowPromptAmex() { - controller_->ShowPrompt(test_unmask_prompt_view_.get(), - test::GetMaskedServerCardAmex(), - AutofillClient::UNMASK_FOR_AUTOFILL, - delegate_->GetWeakPtr()); + controller_->ShowPrompt( + test_unmask_prompt_view_.get(), test::GetMaskedServerCardAmex(), + AutofillClient::UNMASK_FOR_AUTOFILL, delegate_->GetWeakPtr()); } void ShowPromptAndSimulateResponse(bool should_store_pan) { ShowPrompt(); - controller_->OnUnmaskResponse(ASCIIToUTF16("444"), - ASCIIToUTF16("01"), - ASCIIToUTF16("2050"), - should_store_pan); - EXPECT_EQ( - should_store_pan, - pref_service_->GetBoolean( - prefs::kAutofillWalletImportStorageCheckboxState)); + controller_->OnUnmaskResponse(ASCIIToUTF16("444"), ASCIIToUTF16("01"), + ASCIIToUTF16("2050"), should_store_pan); + EXPECT_EQ(should_store_pan, + pref_service_->GetBoolean( + prefs::kAutofillWalletImportStorageCheckboxState)); } protected: void SetImportCheckboxState(bool value) { - pref_service_->SetBoolean( - prefs::kAutofillWalletImportStorageCheckboxState, value); + pref_service_->SetBoolean(prefs::kAutofillWalletImportStorageCheckboxState, + value); } std::unique_ptr<TestCardUnmaskPromptView> test_unmask_prompt_view_; @@ -156,9 +153,8 @@ TEST_F(CardUnmaskPromptControllerImplTest, LogShown) { base::HistogramTester histogram_tester; ShowPrompt(); - histogram_tester.ExpectUniqueSample( - "Autofill.UnmaskPrompt.Events", - AutofillMetrics::UNMASK_PROMPT_SHOWN, 1); + histogram_tester.ExpectUniqueSample("Autofill.UnmaskPrompt.Events", + AutofillMetrics::UNMASK_PROMPT_SHOWN, 1); } TEST_F(CardUnmaskPromptControllerImplTest, LogClosedNoAttempts) { @@ -195,8 +191,7 @@ TEST_F(CardUnmaskPromptControllerImplTest, LogClosedFailedToUnmaskRetriable) { histogram_tester.ExpectBucketCount( "Autofill.UnmaskPrompt.Events", - AutofillMetrics - ::UNMASK_PROMPT_CLOSED_FAILED_TO_UNMASK_RETRIABLE_FAILURE, + AutofillMetrics ::UNMASK_PROMPT_CLOSED_FAILED_TO_UNMASK_RETRIABLE_FAILURE, 1); } @@ -214,8 +209,8 @@ TEST_F(CardUnmaskPromptControllerImplTest, histogram_tester.ExpectBucketCount( "Autofill.UnmaskPrompt.Events", - AutofillMetrics - ::UNMASK_PROMPT_CLOSED_FAILED_TO_UNMASK_NON_RETRIABLE_FAILURE, + AutofillMetrics :: + UNMASK_PROMPT_CLOSED_FAILED_TO_UNMASK_NON_RETRIABLE_FAILURE, 1); } @@ -238,8 +233,7 @@ TEST_F(CardUnmaskPromptControllerImplTest, LogUnmaskedCardFirstAttempt) { TEST_F(CardUnmaskPromptControllerImplTest, LogUnmaskedCardAfterFailure) { ShowPromptAndSimulateResponse(false); controller_->OnVerificationResult(AutofillClient::TRY_AGAIN_FAILURE); - controller_->OnUnmaskResponse(ASCIIToUTF16("444"), - ASCIIToUTF16("01"), + controller_->OnUnmaskResponse(ASCIIToUTF16("444"), ASCIIToUTF16("01"), ASCIIToUTF16("2050"), false /* should_store_pan */); base::HistogramTester histogram_tester; diff --git a/chromium/components/autofill/core/browser/ui/card_unmask_prompt_view.h b/chromium/components/autofill/core/browser/ui/payments/card_unmask_prompt_view.h index a234739f1c5..d0970ccf55e 100644 --- a/chromium/components/autofill/core/browser/ui/card_unmask_prompt_view.h +++ b/chromium/components/autofill/core/browser/ui/payments/card_unmask_prompt_view.h @@ -2,8 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#ifndef COMPONENTS_AUTOFILL_CORE_BROWSER_UI_CARD_UNMASK_PROMPT_VIEW_H_ -#define COMPONENTS_AUTOFILL_CORE_BROWSER_UI_CARD_UNMASK_PROMPT_VIEW_H_ +#ifndef COMPONENTS_AUTOFILL_CORE_BROWSER_UI_PAYMENTS_CARD_UNMASK_PROMPT_VIEW_H_ +#define COMPONENTS_AUTOFILL_CORE_BROWSER_UI_PAYMENTS_CARD_UNMASK_PROMPT_VIEW_H_ #include "base/macros.h" #include "base/strings/string16.h" @@ -31,4 +31,4 @@ class CardUnmaskPromptView { } // namespace autofill -#endif // COMPONENTS_AUTOFILL_CORE_BROWSER_UI_CARD_UNMASK_PROMPT_VIEW_H_ +#endif // COMPONENTS_AUTOFILL_CORE_BROWSER_UI_PAYMENTS_CARD_UNMASK_PROMPT_VIEW_H_ diff --git a/chromium/components/autofill/core/browser/ui/local_card_migration_bubble_controller.h b/chromium/components/autofill/core/browser/ui/payments/local_card_migration_bubble_controller.h index f28eac96a70..ff23e775412 100644 --- a/chromium/components/autofill/core/browser/ui/local_card_migration_bubble_controller.h +++ b/chromium/components/autofill/core/browser/ui/payments/local_card_migration_bubble_controller.h @@ -2,8 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#ifndef COMPONENTS_AUTOFILL_CORE_BROWSER_UI_LOCAL_CARD_MIGRATION_BUBBLE_CONTROLLER_H_ -#define COMPONENTS_AUTOFILL_CORE_BROWSER_UI_LOCAL_CARD_MIGRATION_BUBBLE_CONTROLLER_H_ +#ifndef COMPONENTS_AUTOFILL_CORE_BROWSER_UI_PAYMENTS_LOCAL_CARD_MIGRATION_BUBBLE_CONTROLLER_H_ +#define COMPONENTS_AUTOFILL_CORE_BROWSER_UI_PAYMENTS_LOCAL_CARD_MIGRATION_BUBBLE_CONTROLLER_H_ #include "base/macros.h" #include "base/strings/string16.h" @@ -30,4 +30,4 @@ class LocalCardMigrationBubbleController { } // namespace autofill -#endif // COMPONENTS_AUTOFILL_CORE_BROWSER_UI_LOCAL_CARD_MIGRATION_BUBBLE_CONTROLLER_H_ +#endif // COMPONENTS_AUTOFILL_CORE_BROWSER_UI_PAYMENTS_LOCAL_CARD_MIGRATION_BUBBLE_CONTROLLER_H_ diff --git a/chromium/components/autofill/core/browser/ui/local_card_migration_dialog_controller.h b/chromium/components/autofill/core/browser/ui/payments/local_card_migration_dialog_controller.h index f2dcc17dd9c..915edea65a2 100644 --- a/chromium/components/autofill/core/browser/ui/local_card_migration_dialog_controller.h +++ b/chromium/components/autofill/core/browser/ui/payments/local_card_migration_dialog_controller.h @@ -2,15 +2,15 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#ifndef COMPONENTS_AUTOFILL_CORE_BROWSER_UI_LOCAL_CARD_MIGRATION_DIALOG_CONTROLLER_H_ -#define COMPONENTS_AUTOFILL_CORE_BROWSER_UI_LOCAL_CARD_MIGRATION_DIALOG_CONTROLLER_H_ +#ifndef COMPONENTS_AUTOFILL_CORE_BROWSER_UI_PAYMENTS_LOCAL_CARD_MIGRATION_DIALOG_CONTROLLER_H_ +#define COMPONENTS_AUTOFILL_CORE_BROWSER_UI_PAYMENTS_LOCAL_CARD_MIGRATION_DIALOG_CONTROLLER_H_ #include <memory> #include <vector> #include "base/macros.h" #include "base/strings/string16.h" -#include "components/autofill/core/browser/legal_message_line.h" +#include "components/autofill/core/browser/payments/legal_message_line.h" #include "url/gurl.h" namespace autofill { @@ -46,4 +46,4 @@ class LocalCardMigrationDialogController { } // namespace autofill -#endif // COMPONENTS_AUTOFILL_CORE_BROWSER_UI_LOCAL_CARD_MIGRATION_DIALOG_CONTROLLER_H_ +#endif // COMPONENTS_AUTOFILL_CORE_BROWSER_UI_PAYMENTS_LOCAL_CARD_MIGRATION_DIALOG_CONTROLLER_H_ diff --git a/chromium/components/autofill/core/browser/ui/save_card_bubble_controller.h b/chromium/components/autofill/core/browser/ui/payments/save_card_bubble_controller.h index d549f559552..04ba8d4bb9e 100644 --- a/chromium/components/autofill/core/browser/ui/save_card_bubble_controller.h +++ b/chromium/components/autofill/core/browser/ui/payments/save_card_bubble_controller.h @@ -2,8 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#ifndef COMPONENTS_AUTOFILL_CORE_BROWSER_UI_SAVE_CARD_BUBBLE_CONTROLLER_H_ -#define COMPONENTS_AUTOFILL_CORE_BROWSER_UI_SAVE_CARD_BUBBLE_CONTROLLER_H_ +#ifndef COMPONENTS_AUTOFILL_CORE_BROWSER_UI_PAYMENTS_SAVE_CARD_BUBBLE_CONTROLLER_H_ +#define COMPONENTS_AUTOFILL_CORE_BROWSER_UI_PAYMENTS_SAVE_CARD_BUBBLE_CONTROLLER_H_ #include <memory> #include <vector> @@ -11,7 +11,7 @@ #include "base/macros.h" #include "base/strings/string16.h" #include "components/autofill/core/browser/autofill_client.h" -#include "components/autofill/core/browser/legal_message_line.h" +#include "components/autofill/core/browser/payments/legal_message_line.h" #include "components/autofill/core/browser/sync_utils.h" #include "components/signin/core/browser/account_info.h" #include "url/gurl.h" @@ -98,4 +98,4 @@ class SaveCardBubbleController { } // namespace autofill -#endif // COMPONENTS_AUTOFILL_CORE_BROWSER_UI_SAVE_CARD_BUBBLE_CONTROLLER_H_ +#endif // COMPONENTS_AUTOFILL_CORE_BROWSER_UI_PAYMENTS_SAVE_CARD_BUBBLE_CONTROLLER_H_ diff --git a/chromium/components/autofill/core/browser/webdata/OWNERS b/chromium/components/autofill/core/browser/webdata/OWNERS index edcc64dbae7..0953786ed87 100644 --- a/chromium/components/autofill/core/browser/webdata/OWNERS +++ b/chromium/components/autofill/core/browser/webdata/OWNERS @@ -1,2 +1,8 @@ per-file *sync_bridge*=jkrcal@chromium.org per-file *sync_bridge*=file://components/sync/OWNERS + +per-file *syncable_service*=jkrcal@chromium.org +per-file *syncable_service*=file://components/sync/OWNERS + +per-file *type_controller*=jkrcal@chromium.org +per-file *type_controller*=file://components/sync/OWNERS diff --git a/chromium/components/autofill/core/browser/webdata/autocomplete_sync_bridge.cc b/chromium/components/autofill/core/browser/webdata/autocomplete_sync_bridge.cc index 1eebf032d16..d8b1239f701 100644 --- a/chromium/components/autofill/core/browser/webdata/autocomplete_sync_bridge.cc +++ b/chromium/components/autofill/core/browser/webdata/autocomplete_sync_bridge.cc @@ -330,9 +330,9 @@ Optional<syncer::ModelError> AutocompleteSyncBridge::MergeSyncData( SyncDifferenceTracker tracker(GetAutofillTable()); for (const auto& change : entity_data) { - DCHECK(change.data().specifics.has_autofill()); + DCHECK(change->data().specifics.has_autofill()); RETURN_IF_ERROR(tracker.IncorporateRemoteSpecifics( - change.storage_key(), change.data().specifics.autofill())); + change->storage_key(), change->data().specifics.autofill())); } RETURN_IF_ERROR(tracker.FlushToLocal(web_data_backend_)); @@ -346,6 +346,7 @@ Optional<syncer::ModelError> AutocompleteSyncBridge::MergeSyncData( web_data_backend_->RemoveExpiredFormElements(); } + web_data_backend_->CommitChanges(); web_data_backend_->NotifyThatSyncHasStarted(syncer::AUTOFILL); return {}; } @@ -356,13 +357,13 @@ Optional<ModelError> AutocompleteSyncBridge::ApplySyncChanges( DCHECK(thread_checker_.CalledOnValidThread()); SyncDifferenceTracker tracker(GetAutofillTable()); - for (const EntityChange& change : entity_changes) { - if (change.type() == EntityChange::ACTION_DELETE) { - RETURN_IF_ERROR(tracker.IncorporateRemoteDelete(change.storage_key())); + for (const std::unique_ptr<EntityChange>& change : entity_changes) { + if (change->type() == EntityChange::ACTION_DELETE) { + RETURN_IF_ERROR(tracker.IncorporateRemoteDelete(change->storage_key())); } else { - DCHECK(change.data().specifics.has_autofill()); + DCHECK(change->data().specifics.has_autofill()); RETURN_IF_ERROR(tracker.IncorporateRemoteSpecifics( - change.storage_key(), change.data().specifics.autofill())); + change->storage_key(), change->data().specifics.autofill())); } } @@ -376,6 +377,8 @@ Optional<ModelError> AutocompleteSyncBridge::ApplySyncChanges( autofill::features::kAutocompleteRetentionPolicyEnabled)) { web_data_backend_->RemoveExpiredFormElements(); } + + web_data_backend_->CommitChanges(); return {}; } @@ -470,6 +473,11 @@ void AutocompleteSyncBridge::ActOnLocalChanges( } } + // We do not need to commit any local changes (written by the processor via + // the metadata change list) because the open WebDatabase transaction is + // committed by the AutofillWebDataService when the original local write + // operation (that triggered this notification to the bridge) finishes. + if (Optional<ModelError> error = metadata_change_list->TakeError()) change_processor()->ReportError(*error); } diff --git a/chromium/components/autofill/core/browser/webdata/autocomplete_sync_bridge.h b/chromium/components/autofill/core/browser/webdata/autocomplete_sync_bridge.h index a36fce9f138..78f71ad157f 100644 --- a/chromium/components/autofill/core/browser/webdata/autocomplete_sync_bridge.h +++ b/chromium/components/autofill/core/browser/webdata/autocomplete_sync_bridge.h @@ -12,6 +12,7 @@ #include "base/optional.h" #include "base/scoped_observer.h" #include "base/supports_user_data.h" +#include "base/threading/thread_checker.h" #include "components/autofill/core/browser/webdata/autofill_change.h" #include "components/autofill/core/browser/webdata/autofill_webdata_service_observer.h" #include "components/sync/model/metadata_change_list.h" diff --git a/chromium/components/autofill/core/browser/webdata/autocomplete_sync_bridge_unittest.cc b/chromium/components/autofill/core/browser/webdata/autocomplete_sync_bridge_unittest.cc index d7dfa2eff27..4547ed5acca 100644 --- a/chromium/components/autofill/core/browser/webdata/autocomplete_sync_bridge_unittest.cc +++ b/chromium/components/autofill/core/browser/webdata/autocomplete_sync_bridge_unittest.cc @@ -49,7 +49,6 @@ using syncer::DataBatch; using syncer::EntityChange; using syncer::EntityChangeList; using syncer::EntityData; -using syncer::EntityDataPtr; using syncer::HasInitialSyncDone; using syncer::IsEmptyMetadataBatch; using syncer::KeyAndData; @@ -186,7 +185,7 @@ class AutocompleteSyncBridgeTest : public testing::Test { for (const AutofillSpecifics& specifics : remote_data) { initial_updates.push_back(SpecificsToUpdateResponse(specifics)); } - real_processor_->OnUpdateReceived(state, initial_updates); + real_processor_->OnUpdateReceived(state, std::move(initial_updates)); } void SaveSpecificsToTable( @@ -223,15 +222,13 @@ class AutocompleteSyncBridgeTest : public testing::Test { } std::string GetClientTag(const AutofillSpecifics& specifics) { - std::string tag = - bridge()->GetClientTag(SpecificsToEntity(specifics).value()); + std::string tag = bridge()->GetClientTag(*SpecificsToEntity(specifics)); EXPECT_FALSE(tag.empty()); return tag; } std::string GetStorageKey(const AutofillSpecifics& specifics) { - std::string key = - bridge()->GetStorageKey(SpecificsToEntity(specifics).value()); + std::string key = bridge()->GetStorageKey(*SpecificsToEntity(specifics)); EXPECT_FALSE(key.empty()); return key; } @@ -246,24 +243,25 @@ class AutocompleteSyncBridgeTest : public testing::Test { return changes; } - EntityDataPtr SpecificsToEntity(const AutofillSpecifics& specifics) { - EntityData data; - *data.specifics.mutable_autofill() = specifics; - data.client_tag_hash = syncer::GenerateSyncableHash( - syncer::AUTOFILL, bridge()->GetClientTag(data)); - return data.PassToPtr(); + std::unique_ptr<EntityData> SpecificsToEntity( + const AutofillSpecifics& specifics) { + auto data = std::make_unique<EntityData>(); + *data->specifics.mutable_autofill() = specifics; + data->client_tag_hash = syncer::GenerateSyncableHash( + syncer::AUTOFILL, bridge()->GetClientTag(*data)); + return data; } - syncer::UpdateResponseData SpecificsToUpdateResponse( + std::unique_ptr<syncer::UpdateResponseData> SpecificsToUpdateResponse( const AutofillSpecifics& specifics) { - syncer::UpdateResponseData data; - data.entity = SpecificsToEntity(specifics); + auto data = std::make_unique<syncer::UpdateResponseData>(); + data->entity = SpecificsToEntity(specifics); return data; } - void ApplyChanges(const EntityChangeList& changes) { + void ApplyChanges(EntityChangeList changes) { const auto error = bridge()->ApplySyncChanges( - bridge()->CreateMetadataChangeList(), changes); + bridge()->CreateMetadataChangeList(), std::move(changes)); EXPECT_FALSE(error); } @@ -440,10 +438,19 @@ TEST_F(AutocompleteSyncBridgeTest, ApplySyncChangesSimple) { ASSERT_NE(specifics1.SerializeAsString(), specifics2.SerializeAsString()); ASSERT_NE(GetStorageKey(specifics1), GetStorageKey(specifics2)); + EXPECT_CALL(*backend(), CommitChanges()); + EXPECT_CALL(*backend(), NotifyOfMultipleAutofillChanges()); + ApplyAdds({specifics1, specifics2}); VerifyAllData({specifics1, specifics2}); - ApplyChanges({EntityChange::CreateDelete(GetStorageKey(specifics1))}); + EXPECT_CALL(*backend(), CommitChanges()); + EXPECT_CALL(*backend(), NotifyOfMultipleAutofillChanges()); + + syncer::EntityChangeList entity_change_list; + entity_change_list.push_back( + EntityChange::CreateDelete(GetStorageKey(specifics1))); + ApplyChanges(std::move(entity_change_list)); VerifyAllData({specifics2}); } @@ -479,13 +486,24 @@ TEST_F(AutocompleteSyncBridgeTest, // existing ones. TEST_F(AutocompleteSyncBridgeTest, ApplySyncChangesWrongChangeType) { AutofillSpecifics specifics = CreateSpecifics(1, {1}); - ApplyChanges({EntityChange::CreateDelete(GetStorageKey(specifics))}); + syncer::EntityChangeList entity_change_list1; + entity_change_list1.push_back( + EntityChange::CreateDelete(GetStorageKey(specifics))); + ApplyChanges(std::move(entity_change_list1)); VerifyAllData(std::vector<AutofillSpecifics>()); - ApplyChanges({EntityChange::CreateUpdate(GetStorageKey(specifics), - SpecificsToEntity(specifics))}); + EXPECT_CALL(*backend(), CommitChanges()); + EXPECT_CALL(*backend(), NotifyOfMultipleAutofillChanges()); + + syncer::EntityChangeList entity_change_list2; + entity_change_list2.push_back(EntityChange::CreateUpdate( + GetStorageKey(specifics), SpecificsToEntity(specifics))); + ApplyChanges(std::move(entity_change_list2)); VerifyAllData({specifics}); + EXPECT_CALL(*backend(), CommitChanges()); + EXPECT_CALL(*backend(), NotifyOfMultipleAutofillChanges()); + specifics.add_usage_timestamp(Time::FromTimeT(2).ToInternalValue()); ApplyAdds({specifics}); VerifyAllData({specifics}); @@ -564,9 +582,10 @@ TEST_F(AutocompleteSyncBridgeTest, ApplySyncChangesMinMaxTimestamps) { // should never happen in practice because storage keys should be generated at // runtime by the bridge and not loaded from disk. TEST_F(AutocompleteSyncBridgeTest, ApplySyncChangesBadStorageKey) { + syncer::EntityChangeList entity_change_list; + entity_change_list.push_back(EntityChange::CreateDelete("bogus storage key")); const auto error = bridge()->ApplySyncChanges( - bridge()->CreateMetadataChangeList(), - {EntityChange::CreateDelete("bogus storage key")}); + bridge()->CreateMetadataChangeList(), std::move(entity_change_list)); EXPECT_TRUE(error); } @@ -587,6 +606,11 @@ TEST_F(AutocompleteSyncBridgeTest, LocalEntriesAdded) { EXPECT_CALL(mock_processor(), Put(_, HasSpecifics(added_specifics1), _)); EXPECT_CALL(mock_processor(), Put(_, HasSpecifics(added_specifics2), _)); + // Bridge should not commit transaction on local changes (it is committed by + // the AutofillWebDataService itself). + EXPECT_CALL(*backend(), CommitChanges()).Times(0); + EXPECT_CALL(*backend(), NotifyOfMultipleAutofillChanges()).Times(0); + bridge()->AutofillEntriesChanged( {AutofillChange(AutofillChange::ADD, added_entry1.key()), AutofillChange(AutofillChange::ADD, added_entry2.key())}); @@ -598,6 +622,10 @@ TEST_F(AutocompleteSyncBridgeTest, LocalEntryAddedThenUpdated) { const AutofillEntry added_entry = CreateAutofillEntry(added_specifics); table()->UpdateAutofillEntries({added_entry}); EXPECT_CALL(mock_processor(), Put(_, HasSpecifics(added_specifics), _)); + // Bridge should not commit transaction on local changes (it is committed by + // the AutofillWebDataService itself). + EXPECT_CALL(*backend(), CommitChanges()).Times(0); + EXPECT_CALL(*backend(), NotifyOfMultipleAutofillChanges()).Times(0); bridge()->AutofillEntriesChanged( {AutofillChange(AutofillChange::ADD, added_entry.key())}); @@ -606,6 +634,10 @@ TEST_F(AutocompleteSyncBridgeTest, LocalEntryAddedThenUpdated) { const AutofillEntry updated_entry = CreateAutofillEntry(updated_specifics); table()->UpdateAutofillEntries({updated_entry}); EXPECT_CALL(mock_processor(), Put(_, HasSpecifics(updated_specifics), _)); + // Bridge should not commit transaction on local changes (it is committed by + // the AutofillWebDataService itself). + EXPECT_CALL(*backend(), CommitChanges()).Times(0); + EXPECT_CALL(*backend(), NotifyOfMultipleAutofillChanges()).Times(0); bridge()->AutofillEntriesChanged( {AutofillChange(AutofillChange::UPDATE, updated_entry.key())}); @@ -618,6 +650,11 @@ TEST_F(AutocompleteSyncBridgeTest, LocalEntryDeleted) { const std::string storage_key = GetStorageKey(deleted_specifics); EXPECT_CALL(mock_processor(), Delete(storage_key, _)); + // Bridge should not commit transaction on local changes (it is committed by + // the AutofillWebDataService itself). + EXPECT_CALL(*backend(), CommitChanges()).Times(0); + EXPECT_CALL(*backend(), NotifyOfMultipleAutofillChanges()).Times(0); + bridge()->AutofillEntriesChanged( {AutofillChange(AutofillChange::REMOVE, deleted_entry.key())}); } @@ -640,6 +677,10 @@ TEST_F(AutocompleteSyncBridgeTest, LocalEntryExpired) { ASSERT_EQ(1U, batch.TakeAllMetadata().size()); EXPECT_CALL(mock_processor(), UntrackEntityForStorageKey(storage_key)); + // Bridge should not commit transaction on local changes (it is committed by + // the AutofillWebDataService itself). + EXPECT_CALL(*backend(), CommitChanges()).Times(0); + EXPECT_CALL(*backend(), NotifyOfMultipleAutofillChanges()).Times(0); bridge()->AutofillEntriesChanged( {AutofillChange(AutofillChange::EXPIRE, expired_entry.key())}); @@ -673,6 +714,9 @@ TEST_F(AutocompleteSyncBridgeTest, LoadMetadataReportsErrorForMissingDB) { TEST_F(AutocompleteSyncBridgeTest, MergeSyncDataEmpty) { EXPECT_CALL(mock_processor(), Delete(_, _)).Times(0); EXPECT_CALL(mock_processor(), Put(_, _, _)).Times(0); + EXPECT_CALL(*backend(), NotifyOfMultipleAutofillChanges()).Times(0); + // The bridge should still commit the model type state change. + EXPECT_CALL(*backend(), CommitChanges()); StartSyncing(/*remote_data=*/std::vector<AutofillSpecifics>()); @@ -685,6 +729,8 @@ TEST_F(AutocompleteSyncBridgeTest, MergeSyncDataRemoteOnly) { EXPECT_CALL(mock_processor(), Delete(_, _)).Times(0); EXPECT_CALL(mock_processor(), Put(_, _, _)).Times(0); + EXPECT_CALL(*backend(), CommitChanges()); + EXPECT_CALL(*backend(), NotifyOfMultipleAutofillChanges()); StartSyncing(/*remote_data=*/{specifics1, specifics2}); @@ -702,6 +748,9 @@ TEST_F(AutocompleteSyncBridgeTest, MergeSyncDataLocalOnly) { ApplyAdds({specifics1, specifics2}); VerifyAllData({specifics1, specifics2}); + EXPECT_CALL(*backend(), NotifyOfMultipleAutofillChanges()).Times(0); + EXPECT_CALL(*backend(), CommitChanges()); + StartSyncing(/*remote_data=*/{}); VerifyAllData({specifics1, specifics2}); } @@ -734,6 +783,9 @@ TEST_F(AutocompleteSyncBridgeTest, MergeSyncDataAllMerged) { ApplyAdds({local1, local2, local3, local4, local5, local6}); + EXPECT_CALL(*backend(), CommitChanges()); + EXPECT_CALL(*backend(), NotifyOfMultipleAutofillChanges()); + StartSyncing( /*remote_data=*/{remote1, remote2, remote3, remote4, remote5, remote6}); VerifyAllData({merged1, merged2, merged3, merged4, merged5, merged6}); @@ -753,6 +805,9 @@ TEST_F(AutocompleteSyncBridgeTest, MergeSyncDataMixed) { ApplyAdds({local1, specifics3, local4}); + EXPECT_CALL(*backend(), CommitChanges()); + EXPECT_CALL(*backend(), NotifyOfMultipleAutofillChanges()); + StartSyncing(/*remote_data=*/{remote2, specifics3, remote4}); VerifyAllData({local1, remote2, specifics3, merged4}); diff --git a/chromium/components/autofill/core/browser/webdata/autofill_change.h b/chromium/components/autofill/core/browser/webdata/autofill_change.h index 9605de1e35b..f23695ad741 100644 --- a/chromium/components/autofill/core/browser/webdata/autofill_change.h +++ b/chromium/components/autofill/core/browser/webdata/autofill_change.h @@ -55,16 +55,12 @@ class AutofillDataModelChange : public GenericAutofillChange<std::string> { // The |type| input specifies the change type. The |key| input is the key // that identifies the |data_model|; it is the GUID of the entry for local // data and server_id of the entry for server data from GPay. - // When |type| == ADD, |data_model| should be non-NULL. - // When |type| == UPDATE, |data_model| should be non-NULL. - // When |type| == REMOVE, |data_model| should be NULL. AutofillDataModelChange(Type type, const std::string& key, const DataType* data_model) : GenericAutofillChange<std::string>(type, key), data_model_(data_model) { - DCHECK(type == REMOVE ? !data_model - : data_model && (data_model->guid() == key || - data_model->server_id() == key)); + DCHECK(data_model && + (data_model->guid() == key || data_model->server_id() == key)); } ~AutofillDataModelChange() override {} @@ -90,11 +86,6 @@ class AutofillProfileDeepChange : public AutofillProfileChange { : AutofillProfileChange(type, profile.guid(), &profile), profile_(profile) {} - AutofillProfileDeepChange(Type type, const std::string& guid) - : AutofillProfileChange(type, guid, nullptr), profile_(guid, "") { - DCHECK(type == GenericAutofillChange::REMOVE); - } - ~AutofillProfileDeepChange() override {} const AutofillProfile* profile() const { return &profile_; } @@ -106,8 +97,8 @@ class AutofillProfileDeepChange : public AutofillProfileChange { void validation_effort_made() const { validation_effort_made_ = true; } bool has_validation_effort_made() const { return validation_effort_made_; } - void set_enforce_update() { enforce_update_ = true; } - bool enforce_update() const { return enforce_update_; } + void set_enforced() { enforced_ = true; } + bool enforced() const { return enforced_; } private: AutofillProfile profile_; @@ -121,9 +112,9 @@ class AutofillProfileDeepChange : public AutofillProfileChange { // validity may or may not be updated. mutable bool validation_effort_made_ = false; - // Is true when the update should happen regardless of an equal profile. - // (equal in the sense of AutofillProfile::EqualForUpdate) - mutable bool enforce_update_ = false; + // Is true when the change should happen regardless of an existing or equal + // profile. + mutable bool enforced_ = false; }; } // namespace autofill diff --git a/chromium/components/autofill/core/browser/webdata/autofill_profile_data_type_controller.cc b/chromium/components/autofill/core/browser/webdata/autofill_profile_data_type_controller.cc index bd2bff78a16..aff933bf806 100644 --- a/chromium/components/autofill/core/browser/webdata/autofill_profile_data_type_controller.cc +++ b/chromium/components/autofill/core/browser/webdata/autofill_profile_data_type_controller.cc @@ -14,7 +14,6 @@ #include "components/autofill/core/common/autofill_features.h" #include "components/autofill/core/common/autofill_prefs.h" #include "components/prefs/pref_service.h" -#include "components/sync/base/experiments.h" #include "components/sync/driver/sync_client.h" #include "components/sync/driver/sync_service.h" #include "components/sync/model/sync_error.h" @@ -23,7 +22,7 @@ namespace browser_sync { AutofillProfileDataTypeController::AutofillProfileDataTypeController( - scoped_refptr<base::SingleThreadTaskRunner> db_thread, + scoped_refptr<base::SequencedTaskRunner> db_thread, const base::Closure& dump_stack, syncer::SyncService* sync_service, syncer::SyncClient* sync_client, @@ -76,10 +75,9 @@ bool AutofillProfileDataTypeController::StartModels() { DCHECK(CalledOnValidThread()); DCHECK_EQ(state(), MODEL_STARTING); - if (!IsEnabled()) { - DisableForPolicy(); + if (!IsEnabled()) return false; - } + autofill::PersonalDataManager* personal_data = pdm_provider_.Run(); // Make sure PDM has the sync service. This is needed because in the account @@ -135,13 +133,7 @@ void AutofillProfileDataTypeController::OnUserPrefChanged() { return; // No change to sync state. currently_enabled_ = new_enabled; - if (currently_enabled_) { - // The preference was just enabled. Trigger a reconfiguration. This will do - // nothing if the type isn't preferred. - sync_service()->ReenableDatatype(type()); - } else { - DisableForPolicy(); - } + sync_service()->ReadyForStartChanged(type()); } bool AutofillProfileDataTypeController::IsEnabled() { @@ -152,12 +144,4 @@ bool AutofillProfileDataTypeController::IsEnabled() { sync_client()->GetPrefService()); } -void AutofillProfileDataTypeController::DisableForPolicy() { - if (state() != NOT_RUNNING && state() != STOPPING) { - CreateErrorHandler()->OnUnrecoverableError( - syncer::SyncError(FROM_HERE, syncer::SyncError::DATATYPE_POLICY_ERROR, - "Profile syncing is disabled by policy.", type())); - } -} - } // namespace browser_sync diff --git a/chromium/components/autofill/core/browser/webdata/autofill_profile_data_type_controller.h b/chromium/components/autofill/core/browser/webdata/autofill_profile_data_type_controller.h index 4641b0d223d..f755ca28659 100644 --- a/chromium/components/autofill/core/browser/webdata/autofill_profile_data_type_controller.h +++ b/chromium/components/autofill/core/browser/webdata/autofill_profile_data_type_controller.h @@ -10,7 +10,7 @@ #include "base/macros.h" #include "base/memory/ref_counted.h" #include "base/scoped_observer.h" -#include "base/single_thread_task_runner.h" +#include "base/sequenced_task_runner.h" #include "components/autofill/core/browser/personal_data_manager_observer.h" #include "components/prefs/pref_change_registrar.h" #include "components/sync/driver/async_directory_type_controller.h" @@ -37,7 +37,7 @@ class AutofillProfileDataTypeController // |dump_stack| is called when an unrecoverable error occurs. AutofillProfileDataTypeController( - scoped_refptr<base::SingleThreadTaskRunner> db_thread, + scoped_refptr<base::SequencedTaskRunner> db_thread, const base::Closure& dump_stack, syncer::SyncService* sync_service, syncer::SyncClient* sync_client, @@ -64,9 +64,6 @@ class AutofillProfileDataTypeController // Returns true if the pref is set such that autofill sync should be enabled. bool IsEnabled(); - // Report an error (which will stop the datatype asynchronously). - void DisableForPolicy(); - // Callback that allows accessing PersonalDataManager lazily. const PersonalDataManagerProvider pdm_provider_; diff --git a/chromium/components/autofill/core/browser/webdata/autofill_profile_sync_bridge.cc b/chromium/components/autofill/core/browser/webdata/autofill_profile_sync_bridge.cc index a5047b4ae5b..0e91e96b37f 100644 --- a/chromium/components/autofill/core/browser/webdata/autofill_profile_sync_bridge.cc +++ b/chromium/components/autofill/core/browser/webdata/autofill_profile_sync_bridge.cc @@ -108,14 +108,15 @@ Optional<syncer::ModelError> AutofillProfileSyncBridge::MergeSyncData( GetAutofillTable()); for (const auto& change : entity_data) { - DCHECK(change.data().specifics.has_autofill_profile()); + DCHECK(change->data().specifics.has_autofill_profile()); std::unique_ptr<AutofillProfile> remote = CreateAutofillProfileFromSpecifics( - change.data().specifics.autofill_profile()); + change->data().specifics.autofill_profile()); if (!remote) { - DVLOG(2) << "[AUTOFILL SYNC] Invalid remote specifics " - << change.data().specifics.autofill_profile().SerializeAsString() - << " received from the server in an initial sync."; + DVLOG(2) + << "[AUTOFILL SYNC] Invalid remote specifics " + << change->data().specifics.autofill_profile().SerializeAsString() + << " received from the server in an initial sync."; continue; } RETURN_IF_ERROR( @@ -128,6 +129,7 @@ Optional<syncer::ModelError> AutofillProfileSyncBridge::MergeSyncData( &initial_sync_tracker, AutofillProfileSyncChangeOrigin::kInitial)); + web_data_backend_->CommitChanges(); web_data_backend_->NotifyThatSyncHasStarted(syncer::AUTOFILL_PROFILE); return base::nullopt; } @@ -138,18 +140,18 @@ Optional<ModelError> AutofillProfileSyncBridge::ApplySyncChanges( DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); AutofillProfileSyncDifferenceTracker tracker(GetAutofillTable()); - for (const syncer::EntityChange& change : entity_changes) { - if (change.type() == syncer::EntityChange::ACTION_DELETE) { - RETURN_IF_ERROR(tracker.IncorporateRemoteDelete(change.storage_key())); + for (const std::unique_ptr<syncer::EntityChange>& change : entity_changes) { + if (change->type() == syncer::EntityChange::ACTION_DELETE) { + RETURN_IF_ERROR(tracker.IncorporateRemoteDelete(change->storage_key())); } else { - DCHECK(change.data().specifics.has_autofill_profile()); + DCHECK(change->data().specifics.has_autofill_profile()); std::unique_ptr<AutofillProfile> remote = CreateAutofillProfileFromSpecifics( - change.data().specifics.autofill_profile()); + change->data().specifics.autofill_profile()); if (!remote) { DVLOG(2) << "[AUTOFILL SYNC] Invalid remote specifics " - << change.data().specifics.autofill_profile().SerializeAsString() + << change->data().specifics.autofill_profile().SerializeAsString() << " received from the server in an initial sync."; continue; } @@ -157,8 +159,12 @@ Optional<ModelError> AutofillProfileSyncBridge::ApplySyncChanges( } } - return FlushSyncTracker(std::move(metadata_change_list), &tracker, - AutofillProfileSyncChangeOrigin::kIncrementalRemote); + RETURN_IF_ERROR( + FlushSyncTracker(std::move(metadata_change_list), &tracker, + AutofillProfileSyncChangeOrigin::kIncrementalRemote)); + + web_data_backend_->CommitChanges(); + return base::nullopt; } void AutofillProfileSyncBridge::GetData(StorageKeyList storage_keys, @@ -203,12 +209,8 @@ void AutofillProfileSyncBridge::GetAllDataForDebugging(DataCallback callback) { void AutofillProfileSyncBridge::ActOnLocalChange( const AutofillProfileChange& change) { - DCHECK((change.type() == AutofillProfileChange::REMOVE) == - (change.data_model() == nullptr)); - if (!change_processor()->IsTrackingMetadata()) { - return; - } - if (change.data_model() && + DCHECK(change.data_model()); + if (!change_processor()->IsTrackingMetadata() || change.data_model()->record_type() != AutofillProfile::LOCAL_PROFILE) { return; } @@ -218,19 +220,10 @@ void AutofillProfileSyncBridge::ActOnLocalChange( GetAutofillTable(), syncer::AUTOFILL_PROFILE); // TODO(crbug.com/904390): Remove when the investigation is over. - bool is_converted_from_server = false; - if (change.type() == AutofillProfileChange::REMOVE) { - // The profile is not available any more so we cannot compare its value, - // instead we use a rougher test based on the id - whether it is a local - // GUID or a server id. As a result, it has a different semantics compared - // to AddOrUpdate. - is_converted_from_server = !base::IsValidGUID(change.key()); - } else { - std::vector<std::unique_ptr<AutofillProfile>> server_profiles; - GetAutofillTable()->GetServerProfiles(&server_profiles); - is_converted_from_server = IsLocalProfileEqualToServerProfile( - server_profiles, *change.data_model(), app_locale_); - } + std::vector<std::unique_ptr<AutofillProfile>> server_profiles; + GetAutofillTable()->GetServerProfiles(&server_profiles); + bool is_converted_from_server = IsLocalProfileEqualToServerProfile( + server_profiles, *change.data_model(), app_locale_); switch (change.type()) { case AutofillProfileChange::ADD: @@ -247,12 +240,6 @@ void AutofillProfileSyncBridge::ActOnLocalChange( : AutofillProfileSyncChangeOrigin::kTrulyLocal); break; case AutofillProfileChange::REMOVE: - // Removals have no data_model() so this change can still be for a - // SERVER_PROFILE. We have no simple way to rule it out. For the time - // being we rely on the processor ignoring deletions for storage keys it - // does not know. - // TODO(jkrcal): implement a hash map of known storage_keys and use it - // here. change_processor()->Delete(change.key(), metadata_change_list.get()); // TODO(crbug.com/904390): Remove when the investigation is over. @@ -267,6 +254,11 @@ void AutofillProfileSyncBridge::ActOnLocalChange( break; } + // We do not need to commit any local changes (written by the processor via + // the metadata change list) because the open WebDatabase transaction is + // committed by the AutofillWebDataService when the original local write + // operation (that triggered this notification to the bridge) finishes. + if (Optional<ModelError> error = metadata_change_list->TakeError()) { change_processor()->ReportError(*error); } diff --git a/chromium/components/autofill/core/browser/webdata/autofill_profile_sync_bridge_unittest.cc b/chromium/components/autofill/core/browser/webdata/autofill_profile_sync_bridge_unittest.cc index 08e50b60dfa..4b1986b1a61 100644 --- a/chromium/components/autofill/core/browser/webdata/autofill_profile_sync_bridge_unittest.cc +++ b/chromium/components/autofill/core/browser/webdata/autofill_profile_sync_bridge_unittest.cc @@ -53,7 +53,6 @@ using syncer::DataBatch; using syncer::EntityChange; using syncer::EntityChangeList; using syncer::EntityData; -using syncer::EntityDataPtr; using syncer::KeyAndData; using syncer::MockModelTypeChangeProcessor; using syncer::ModelType; @@ -264,12 +263,12 @@ class AutofillProfileSyncBridgeTest : public testing::Test { for (const AutofillProfileSpecifics& specifics : remote_data) { initial_updates.push_back(SpecificsToUpdateResponse(specifics)); } - real_processor_->OnUpdateReceived(state, initial_updates); + real_processor_->OnUpdateReceived(state, std::move(initial_updates)); } - void ApplySyncChanges(const EntityChangeList& changes) { + void ApplySyncChanges(EntityChangeList changes) { const base::Optional<syncer::ModelError> error = bridge()->ApplySyncChanges( - bridge()->CreateMetadataChangeList(), changes); + bridge()->CreateMetadataChangeList(), std::move(changes)); EXPECT_FALSE(error) << error->ToString(); } @@ -293,18 +292,19 @@ class AutofillProfileSyncBridgeTest : public testing::Test { return data; } - EntityDataPtr SpecificsToEntity(const AutofillProfileSpecifics& specifics) { - EntityData data; - *data.specifics.mutable_autofill_profile() = specifics; - data.client_tag_hash = syncer::GenerateSyncableHash( - syncer::AUTOFILL_PROFILE, bridge()->GetClientTag(data)); - return data.PassToPtr(); + std::unique_ptr<EntityData> SpecificsToEntity( + const AutofillProfileSpecifics& specifics) { + auto data = std::make_unique<EntityData>(); + *data->specifics.mutable_autofill_profile() = specifics; + data->client_tag_hash = syncer::GenerateSyncableHash( + syncer::AUTOFILL_PROFILE, bridge()->GetClientTag(*data)); + return data; } - syncer::UpdateResponseData SpecificsToUpdateResponse( + std::unique_ptr<syncer::UpdateResponseData> SpecificsToUpdateResponse( const AutofillProfileSpecifics& specifics) { - syncer::UpdateResponseData data; - data.entity = SpecificsToEntity(specifics); + auto data = std::make_unique<syncer::UpdateResponseData>(); + data->entity = SpecificsToEntity(specifics); return data; } @@ -342,6 +342,9 @@ TEST_F(AutofillProfileSyncBridgeTest, AutofillProfileChanged_Added) { EXPECT_CALL( mock_processor(), Put(kGuidA, HasSpecifics(CreateAutofillProfileSpecifics(local)), _)); + // The bridge does not need to commit when reacting to a notification about a + // local change. + EXPECT_CALL(*backend(), CommitChanges()).Times(0); bridge()->AutofillProfileChanged(change); } @@ -358,6 +361,9 @@ TEST_F(AutofillProfileSyncBridgeTest, EXPECT_CALL( mock_processor(), Put(kGuidA, HasSpecifics(CreateAutofillProfileSpecifics(local)), _)); + // The bridge does not need to commit when reacting to a notification about a + // local change. + EXPECT_CALL(*backend(), CommitChanges()).Times(0); bridge()->AutofillProfileChanged(change); } @@ -374,6 +380,9 @@ TEST_F(AutofillProfileSyncBridgeTest, EXPECT_CALL( mock_processor(), Put(kGuidA, HasSpecifics(CreateAutofillProfileSpecifics(local)), _)); + // The bridge does not need to commit when reacting to a notification about a + // local change. + EXPECT_CALL(*backend(), CommitChanges()).Times(0); bridge()->AutofillProfileChanged(change); } @@ -389,6 +398,9 @@ TEST_F(AutofillProfileSyncBridgeTest, AutofillProfileChanged_Updated) { EXPECT_CALL( mock_processor(), Put(kGuidA, HasSpecifics(CreateAutofillProfileSpecifics(local)), _)); + // The bridge does not need to commit when reacting to a notification about a + // local change. + EXPECT_CALL(*backend(), CommitChanges()).Times(0); bridge()->AutofillProfileChanged(change); } @@ -417,6 +429,9 @@ TEST_F(AutofillProfileSyncBridgeTest, EXPECT_CALL( mock_processor(), Put(kGuidA, HasSpecifics(CreateAutofillProfileSpecifics(local)), _)); + // The bridge does not need to commit when reacting to a notification about a + // local change. + EXPECT_CALL(*backend(), CommitChanges()).Times(0); bridge()->AutofillProfileChanged(change); } @@ -438,12 +453,31 @@ TEST_F(AutofillProfileSyncBridgeTest, TEST_F(AutofillProfileSyncBridgeTest, AutofillProfileChanged_Deleted) { StartSyncing({}); - AutofillProfileChange change(AutofillProfileChange::REMOVE, kGuidB, nullptr); + AutofillProfile local(kGuidB, kHttpsOrigin); + local.SetRawInfo(NAME_FIRST, ASCIIToUTF16("Jane")); + AutofillProfileChange change(AutofillProfileChange::REMOVE, kGuidB, &local); EXPECT_CALL(mock_processor(), Delete(kGuidB, _)); + // The bridge does not need to commit when reacting to a notification about a + // local change. + EXPECT_CALL(*backend(), CommitChanges()).Times(0); bridge()->AutofillProfileChanged(change); } +// Server profile updates should be ignored. +TEST_F(AutofillProfileSyncBridgeTest, + AutofillProfileChanged_Deleted_IgnoreServerProfiles) { + StartSyncing({}); + + AutofillProfile server_profile(AutofillProfile::SERVER_PROFILE, "server-id"); + AutofillProfileChange change(AutofillProfileChange::REMOVE, + server_profile.guid(), &server_profile); + + EXPECT_CALL(mock_processor(), Put(_, _, _)).Times(0); + // Should not crash. + bridge()->AutofillProfileChanged(change); +} + TEST_F(AutofillProfileSyncBridgeTest, GetAllDataForDebugging) { AutofillProfile local1 = AutofillProfile(kGuidA, kHttpsOrigin); local1.SetRawInfo(NAME_FIRST, ASCIIToUTF16("John")); @@ -503,6 +537,7 @@ TEST_F(AutofillProfileSyncBridgeTest, MergeSyncData) { mock_processor(), Put(kGuidA, HasSpecifics(CreateAutofillProfileSpecifics(local1)), _)); EXPECT_CALL(mock_processor(), Delete(_, _)).Times(0); + EXPECT_CALL(*backend(), CommitChanges()); StartSyncing({remote1, remote2, remote3}); @@ -521,6 +556,8 @@ TEST_F(AutofillProfileSyncBridgeTest, MergeSyncData_SyncAllFieldsToServer) { // This complete profile is fully uploaded to sync. EXPECT_CALL(mock_processor(), Put(_, HasSpecifics(ConstructCompleteSpecifics()), _)); + EXPECT_CALL(*backend(), CommitChanges()); + StartSyncing({}); // No changes locally. @@ -531,6 +568,7 @@ TEST_F(AutofillProfileSyncBridgeTest, MergeSyncData_SyncAllFieldsToServer) { // the client (and nothing gets uploaded back). TEST_F(AutofillProfileSyncBridgeTest, MergeSyncData_SyncAllFieldsToClient) { EXPECT_CALL(mock_processor(), Put(_, _, _)).Times(0); + EXPECT_CALL(*backend(), CommitChanges()); StartSyncing({ConstructCompleteSpecifics()}); EXPECT_THAT(GetAllLocalData(), @@ -562,6 +600,7 @@ TEST_F(AutofillProfileSyncBridgeTest, MergeSyncData_IdenticalProfiles) { AutofillProfileSpecifics merged2(remote2); merged2.set_origin(kSettingsOrigin); EXPECT_CALL(mock_processor(), Put(kGuidD, HasSpecifics(merged2), _)); + EXPECT_CALL(*backend(), CommitChanges()); StartSyncing({remote1, remote2}); @@ -595,6 +634,7 @@ TEST_F(AutofillProfileSyncBridgeTest, MergeSyncData_NonSimilarProfiles) { mock_processor(), Put(kGuidA, HasSpecifics(CreateAutofillProfileSpecifics(local)), _)); EXPECT_CALL(mock_processor(), Delete(_, _)).Times(0); + EXPECT_CALL(*backend(), CommitChanges()); StartSyncing({remote}); @@ -646,6 +686,7 @@ TEST_F(AutofillProfileSyncBridgeTest, MergeSyncData_SimilarProfiles) { mock_processor(), Put(kGuidB, HasSpecifics(CreateAutofillProfileSpecifics(local2)), _)); EXPECT_CALL(mock_processor(), Delete(_, _)).Times(0); + EXPECT_CALL(*backend(), CommitChanges()); StartSyncing({remote1, remote2}); @@ -680,6 +721,7 @@ TEST_F(AutofillProfileSyncBridgeTest, merged.set_use_date(30); merged.add_phone_home_whole_number("650234567"); EXPECT_CALL(mock_processor(), Put(kGuidB, HasSpecifics(merged), _)); + EXPECT_CALL(*backend(), CommitChanges()); StartSyncing({remote}); } @@ -703,6 +745,7 @@ TEST_F(AutofillProfileSyncBridgeTest, AutofillProfileSpecifics merged(remote); merged.add_phone_home_whole_number("650234567"); EXPECT_CALL(mock_processor(), Put(kGuidB, HasSpecifics(merged), _)); + EXPECT_CALL(*backend(), CommitChanges()); StartSyncing({remote}); } @@ -726,6 +769,7 @@ TEST_F(AutofillProfileSyncBridgeTest, merged.set_use_count(12); merged.add_phone_home_whole_number("650234567"); EXPECT_CALL(mock_processor(), Put(kGuidB, HasSpecifics(merged), _)); + EXPECT_CALL(*backend(), CommitChanges()); StartSyncing({remote}); } @@ -751,6 +795,7 @@ TEST_F(AutofillProfileSyncBridgeTest, // explicitly covered by previous tests but happens. merged.set_address_home_language_code(""); EXPECT_CALL(mock_processor(), Put(kGuidB, HasSpecifics(merged), _)); + EXPECT_CALL(*backend(), CommitChanges()); StartSyncing({remote}); } @@ -770,6 +815,7 @@ TEST_F(AutofillProfileSyncBridgeTest, // Expect no sync events to add origin to the remote data. EXPECT_CALL(mock_processor(), Put(_, _, _)).Times(0); + EXPECT_CALL(*backend(), CommitChanges()); StartSyncing({remote}); // Expect the local autofill profile to still have an origin after sync. @@ -795,6 +841,7 @@ TEST_F(AutofillProfileSyncBridgeTest, ASSERT_FALSE(remote.has_origin()); EXPECT_CALL(mock_processor(), Put(_, _, _)).Times(0); + EXPECT_CALL(*backend(), CommitChanges()); StartSyncing({remote}); EXPECT_THAT(GetAllLocalData(), ElementsAre(local)); } @@ -811,10 +858,13 @@ TEST_F(AutofillProfileSyncBridgeTest, ApplySyncChanges) { EXPECT_CALL(mock_processor(), Put(_, _, _)).Times(0); EXPECT_CALL(mock_processor(), Delete(_, _)).Times(0); + EXPECT_CALL(*backend(), CommitChanges()); - ApplySyncChanges( - {EntityChange::CreateDelete(kGuidA), - EntityChange::CreateAdd(kGuidB, SpecificsToEntity(remote))}); + syncer::EntityChangeList entity_change_list; + entity_change_list.push_back(EntityChange::CreateDelete(kGuidA)); + entity_change_list.push_back( + EntityChange::CreateAdd(kGuidB, SpecificsToEntity(remote))); + ApplySyncChanges(std::move(entity_change_list)); EXPECT_THAT(GetAllLocalData(), ElementsAre(CreateAutofillProfile(remote))); } @@ -829,10 +879,14 @@ TEST_F(AutofillProfileSyncBridgeTest, ApplySyncChanges_OmitsInvalidSpecifics) { CreateAutofillProfileSpecifics(kGuidInvalid, std::string()); EXPECT_CALL(mock_processor(), Put(_, _, _)).Times(0); - ApplySyncChanges( - {EntityChange::CreateAdd(kGuidA, SpecificsToEntity(remote_valid)), - EntityChange::CreateAdd(kGuidInvalid, - SpecificsToEntity(remote_invalid))}); + EXPECT_CALL(*backend(), CommitChanges()); + + syncer::EntityChangeList entity_change_list; + entity_change_list.push_back( + EntityChange::CreateAdd(kGuidA, SpecificsToEntity(remote_valid))); + entity_change_list.push_back( + EntityChange::CreateAdd(kGuidInvalid, SpecificsToEntity(remote_invalid))); + ApplySyncChanges(std::move(entity_change_list)); EXPECT_THAT(GetAllLocalData(), ElementsAre(CreateAutofillProfile(remote_valid))); @@ -888,6 +942,7 @@ TEST_F(AutofillProfileSyncBridgeTest, remote.set_address_home_street_address( "456 El Camino Real\n" "Suite #1337"); + EXPECT_CALL(*backend(), CommitChanges()); StartSyncing({remote}); @@ -922,6 +977,7 @@ TEST_F(AutofillProfileSyncBridgeTest, // No update to sync, no change in local data. EXPECT_CALL(mock_processor(), Put(_, _, _)).Times(0); + EXPECT_CALL(*backend(), CommitChanges()); StartSyncing({remote}); EXPECT_THAT(GetAllLocalData(), ElementsAre(local)); } @@ -940,6 +996,7 @@ TEST_F(AutofillProfileSyncBridgeTest, // No update to sync, no change in local data. EXPECT_CALL(mock_processor(), Put(_, _, _)).Times(0); + EXPECT_CALL(*backend(), CommitChanges()); StartSyncing({remote}); EXPECT_THAT(GetAllLocalData(), ElementsAre(local)); } @@ -958,6 +1015,7 @@ TEST_F(AutofillProfileSyncBridgeTest, // No update to sync, remote language code overwrites the empty local one. EXPECT_CALL(mock_processor(), Put(_, _, _)).Times(0); + EXPECT_CALL(*backend(), CommitChanges()); StartSyncing({remote}); EXPECT_THAT(GetAllLocalData(), ElementsAre(CreateAutofillProfile(remote))); } @@ -976,6 +1034,7 @@ TEST_F(AutofillProfileSyncBridgeTest, // No update to sync, remote language code overwrites the local one. EXPECT_CALL(mock_processor(), Put(_, _, _)).Times(0); + EXPECT_CALL(*backend(), CommitChanges()); StartSyncing({remote}); EXPECT_THAT(GetAllLocalData(), ElementsAre(CreateAutofillProfile(remote))); } @@ -1001,6 +1060,7 @@ TEST_F(AutofillProfileSyncBridgeTest, // No update to sync, remote language code overwrites the local one. EXPECT_CALL(mock_processor(), Put(_, _, _)).Times(0); + EXPECT_CALL(*backend(), CommitChanges()); StartSyncing({remote}); EXPECT_THAT(GetAllLocalData(), ElementsAre(merged)); } @@ -1021,6 +1081,7 @@ TEST_F(AutofillProfileSyncBridgeTest, // No update to sync, no change in local data. EXPECT_CALL(mock_processor(), Put(_, _, _)).Times(0); + EXPECT_CALL(*backend(), CommitChanges()); StartSyncing({remote}); EXPECT_THAT(GetAllLocalData(), ElementsAre(local)); } @@ -1040,6 +1101,7 @@ TEST_F(AutofillProfileSyncBridgeTest, // No update to sync, the validity bitfield should be stored to local. EXPECT_CALL(mock_processor(), Put(_, _, _)).Times(0); + EXPECT_CALL(*backend(), CommitChanges()); StartSyncing({remote}); EXPECT_THAT(GetAllLocalData(), ElementsAre(CreateAutofillProfile(remote))); } @@ -1059,6 +1121,7 @@ TEST_F(AutofillProfileSyncBridgeTest, // No update to sync, the remote validity bitfield should overwrite local. EXPECT_CALL(mock_processor(), Put(_, _, _)).Times(0); + EXPECT_CALL(*backend(), CommitChanges()); StartSyncing({remote}); EXPECT_THAT(GetAllLocalData(), ElementsAre(CreateAutofillProfile(remote))); } @@ -1083,6 +1146,7 @@ TEST_F(AutofillProfileSyncBridgeTest, // No update to sync, the local validity bitfield should stay untouched. EXPECT_CALL(mock_processor(), Put(_, _, _)).Times(0); + EXPECT_CALL(*backend(), CommitChanges()); StartSyncing({remote}); EXPECT_THAT(GetAllLocalData(), ElementsAre(merged)); } @@ -1102,6 +1166,7 @@ TEST_F(AutofillProfileSyncBridgeTest, // No update to sync, no change in local data. EXPECT_CALL(mock_processor(), Put(_, _, _)).Times(0); + EXPECT_CALL(*backend(), CommitChanges()); StartSyncing({remote}); EXPECT_THAT(GetAllLocalData(), ElementsAre(local)); } @@ -1128,6 +1193,7 @@ TEST_F(AutofillProfileSyncBridgeTest, // No update to sync, no change in local data. EXPECT_CALL(mock_processor(), Put(_, _, _)).Times(0); + EXPECT_CALL(*backend(), CommitChanges()); StartSyncing({remote}); EXPECT_THAT(GetAllLocalData(), ElementsAre(merged)); } @@ -1151,6 +1217,7 @@ TEST_F(AutofillProfileSyncBridgeTest, // No update to sync, no change in local data. EXPECT_CALL(mock_processor(), Put(_, _, _)).Times(0); + EXPECT_CALL(*backend(), CommitChanges()); StartSyncing({remote}); EXPECT_THAT(GetAllLocalData(), ElementsAre(WithUsageStats(local))); } @@ -1203,6 +1270,7 @@ TEST_P(AutofillProfileSyncBridgeUpdatesUsageStatsTest, UpdatesUsageStats) { // Expect no changes to remote data. EXPECT_CALL(mock_processor(), Put(_, _, _)).Times(0); + EXPECT_CALL(*backend(), CommitChanges()); StartSyncing({remote}); EXPECT_THAT(GetAllLocalData(), ElementsAre(WithUsageStats(merged))); diff --git a/chromium/components/autofill/core/browser/webdata/autofill_profile_syncable_service.cc b/chromium/components/autofill/core/browser/webdata/autofill_profile_syncable_service.cc index 8022c6abd15..1a6b46119b3 100644 --- a/chromium/components/autofill/core/browser/webdata/autofill_profile_syncable_service.cc +++ b/chromium/components/autofill/core/browser/webdata/autofill_profile_syncable_service.cc @@ -94,6 +94,12 @@ AutofillProfileSyncableService::FromWebDataService( AutofillProfileSyncableService::AutofillProfileSyncableService() : webdata_backend_(nullptr), scoped_observer_(this) {} +void AutofillProfileSyncableService::WaitUntilReadyToSync( + base::OnceClosure done) { + // Not used in the legacy directory-based architecture. + NOTREACHED(); +} + syncer::SyncMergeResult AutofillProfileSyncableService::MergeDataAndStartSyncing( syncer::ModelType type, @@ -602,33 +608,21 @@ AutofillProfileSyncableService::CreateOrUpdateProfile( void AutofillProfileSyncableService::ActOnChange( const AutofillProfileChange& change) { - DCHECK( - (change.type() == AutofillProfileChange::REMOVE && - !change.data_model()) || - (change.type() != AutofillProfileChange::REMOVE && change.data_model())); + DCHECK(change.data_model()); DCHECK(sync_processor_); - if (change.data_model() && - change.data_model()->record_type() != AutofillProfile::LOCAL_PROFILE) { + if (change.data_model()->record_type() != AutofillProfile::LOCAL_PROFILE) { return; } // TODO(crbug.com/904390): Remove when the investigation is over. bool is_converted_from_server = false; - if (change.type() == AutofillProfileChange::REMOVE) { - // The profile is not available any more so we cannot compare its value, - // instead we use a rougher test based on the id - whether it is a local - // GUID or a server id. As a result, it has a different semantics compared - // to AddOrUpdate. - is_converted_from_server = !base::IsValidGUID(change.key()); - } else { - // |webdata_backend_|, used by GetAutofillTable() may be null in unit-tests. - if (webdata_backend_ != nullptr) { - std::vector<std::unique_ptr<AutofillProfile>> server_profiles; - GetAutofillTable()->GetServerProfiles(&server_profiles); - is_converted_from_server = IsLocalProfileEqualToServerProfile( - server_profiles, *change.data_model(), app_locale_); - } + // |webdata_backend_|, used by GetAutofillTable() may be null in unit-tests. + if (webdata_backend_ != nullptr) { + std::vector<std::unique_ptr<AutofillProfile>> server_profiles; + GetAutofillTable()->GetServerProfiles(&server_profiles); + is_converted_from_server = IsLocalProfileEqualToServerProfile( + server_profiles, *change.data_model(), app_locale_); } syncer::SyncChangeList new_changes; @@ -668,13 +662,10 @@ void AutofillProfileSyncableService::ActOnChange( break; } case AutofillProfileChange::REMOVE: { - // Removals have no data_model() so this change can still be for a - // SERVER_PROFILE. Rule it out by a lookup in profiles_map_. if (profiles_map_.find(change.key()) != profiles_map_.end()) { - AutofillProfile empty_profile(change.key(), std::string()); new_changes.push_back( syncer::SyncChange(FROM_HERE, syncer::SyncChange::ACTION_DELETE, - CreateData(empty_profile))); + CreateData(*(change.data_model())))); profiles_map_.erase(change.key()); // TODO(crbug.com/904390): Remove when the investigation is over. ReportAutofillProfileDeleteOrigin( diff --git a/chromium/components/autofill/core/browser/webdata/autofill_profile_syncable_service.h b/chromium/components/autofill/core/browser/webdata/autofill_profile_syncable_service.h index 079ff91ee41..d9638107dbc 100644 --- a/chromium/components/autofill/core/browser/webdata/autofill_profile_syncable_service.h +++ b/chromium/components/autofill/core/browser/webdata/autofill_profile_syncable_service.h @@ -70,6 +70,7 @@ class AutofillProfileSyncableService static syncer::ModelType model_type() { return syncer::AUTOFILL_PROFILE; } // syncer::SyncableService implementation. + void WaitUntilReadyToSync(base::OnceClosure done) override; syncer::SyncMergeResult MergeDataAndStartSyncing( syncer::ModelType type, const syncer::SyncDataList& initial_sync_data, diff --git a/chromium/components/autofill/core/browser/webdata/autofill_profile_syncable_service_unittest.cc b/chromium/components/autofill/core/browser/webdata/autofill_profile_syncable_service_unittest.cc index 1b605e9446b..6291ce17df9 100644 --- a/chromium/components/autofill/core/browser/webdata/autofill_profile_syncable_service_unittest.cc +++ b/chromium/components/autofill/core/browser/webdata/autofill_profile_syncable_service_unittest.cc @@ -593,7 +593,8 @@ TEST_F(AutofillProfileSyncableServiceTest, AutofillProfileDeleted) { AutofillProfileChange change1(AutofillProfileChange::ADD, kGuid1, &profile); autofill_syncable_service_.AutofillProfileChanged(change1); - AutofillProfileChange change2(AutofillProfileChange::REMOVE, kGuid1, nullptr); + AutofillProfileChange change2(AutofillProfileChange::REMOVE, kGuid1, + &profile); autofill_syncable_service_.AutofillProfileChanged(change2); ASSERT_EQ(1U, sync_change_processor->changes().size()); @@ -611,7 +612,9 @@ TEST_F(AutofillProfileSyncableServiceTest, TestSyncChangeProcessor* sync_change_processor = new TestSyncChangeProcessor; autofill_syncable_service_.set_sync_processor(sync_change_processor); - AutofillProfileChange change(AutofillProfileChange::REMOVE, kGuid2, nullptr); + AutofillProfile profile(kGuid2, kEmptyOrigin); + profile.SetRawInfo(NAME_FIRST, ASCIIToUTF16("Jane")); + AutofillProfileChange change(AutofillProfileChange::REMOVE, kGuid2, &profile); autofill_syncable_service_.AutofillProfileChanged(change); ASSERT_EQ(0U, sync_change_processor->changes().size()); diff --git a/chromium/components/autofill/core/browser/webdata/autofill_sync_bridge_util.cc b/chromium/components/autofill/core/browser/webdata/autofill_sync_bridge_util.cc index d0647c4bf0e..d7a591940ed 100644 --- a/chromium/components/autofill/core/browser/webdata/autofill_sync_bridge_util.cc +++ b/chromium/components/autofill/core/browser/webdata/autofill_sync_bridge_util.cc @@ -114,45 +114,6 @@ CreditCard::CardType CardTypeFromWalletCardClass( } } -// Creates an AutofillProfile from the specified |address| specifics. -AutofillProfile ProfileFromSpecifics( - const sync_pb::WalletPostalAddress& address) { - AutofillProfile profile(AutofillProfile::SERVER_PROFILE, std::string()); - - // AutofillProfile stores multi-line addresses with newline separators. - std::vector<base::StringPiece> street_address( - address.street_address().begin(), address.street_address().end()); - profile.SetRawInfo(ADDRESS_HOME_STREET_ADDRESS, - base::UTF8ToUTF16(base::JoinString(street_address, "\n"))); - - profile.SetRawInfo(COMPANY_NAME, base::UTF8ToUTF16(address.company_name())); - profile.SetRawInfo(ADDRESS_HOME_STATE, - base::UTF8ToUTF16(address.address_1())); - profile.SetRawInfo(ADDRESS_HOME_CITY, base::UTF8ToUTF16(address.address_2())); - profile.SetRawInfo(ADDRESS_HOME_DEPENDENT_LOCALITY, - base::UTF8ToUTF16(address.address_3())); - // AutofillProfile doesn't support address_4 ("sub dependent locality"). - profile.SetRawInfo(ADDRESS_HOME_ZIP, - base::UTF8ToUTF16(address.postal_code())); - profile.SetRawInfo(ADDRESS_HOME_SORTING_CODE, - base::UTF8ToUTF16(address.sorting_code())); - profile.SetRawInfo(ADDRESS_HOME_COUNTRY, - base::UTF8ToUTF16(address.country_code())); - profile.set_language_code(address.language_code()); - - // SetInfo instead of SetRawInfo so the constituent pieces will be parsed - // for these data types. - profile.SetInfo(NAME_FULL, base::UTF8ToUTF16(address.recipient_name()), - profile.language_code()); - profile.SetInfo(PHONE_HOME_WHOLE_NUMBER, - base::UTF8ToUTF16(address.phone_number()), - profile.language_code()); - - profile.GenerateServerProfileIdentifier(); - - return profile; -} - // Creates an AutofillProfile from the specified |card| specifics. CreditCard CardFromSpecifics(const sync_pb::WalletMaskedCreditCard& card) { CreditCard result(CreditCard::MASKED_SERVER_CARD, card.id()); @@ -306,6 +267,44 @@ void SetAutofillWalletSpecificsFromPaymentsCustomerData( mutable_customer_data->set_id(customer_data.customer_id); } +AutofillProfile ProfileFromSpecifics( + const sync_pb::WalletPostalAddress& address) { + AutofillProfile profile(AutofillProfile::SERVER_PROFILE, std::string()); + + // AutofillProfile stores multi-line addresses with newline separators. + std::vector<base::StringPiece> street_address( + address.street_address().begin(), address.street_address().end()); + profile.SetRawInfo(ADDRESS_HOME_STREET_ADDRESS, + base::UTF8ToUTF16(base::JoinString(street_address, "\n"))); + + profile.SetRawInfo(COMPANY_NAME, base::UTF8ToUTF16(address.company_name())); + profile.SetRawInfo(ADDRESS_HOME_STATE, + base::UTF8ToUTF16(address.address_1())); + profile.SetRawInfo(ADDRESS_HOME_CITY, base::UTF8ToUTF16(address.address_2())); + profile.SetRawInfo(ADDRESS_HOME_DEPENDENT_LOCALITY, + base::UTF8ToUTF16(address.address_3())); + // AutofillProfile doesn't support address_4 ("sub dependent locality"). + profile.SetRawInfo(ADDRESS_HOME_ZIP, + base::UTF8ToUTF16(address.postal_code())); + profile.SetRawInfo(ADDRESS_HOME_SORTING_CODE, + base::UTF8ToUTF16(address.sorting_code())); + profile.SetRawInfo(ADDRESS_HOME_COUNTRY, + base::UTF8ToUTF16(address.country_code())); + profile.set_language_code(address.language_code()); + + // SetInfo instead of SetRawInfo so the constituent pieces will be parsed + // for these data types. + profile.SetInfo(NAME_FULL, base::UTF8ToUTF16(address.recipient_name()), + profile.language_code()); + profile.SetInfo(PHONE_HOME_WHOLE_NUMBER, + base::UTF8ToUTF16(address.phone_number()), + profile.language_code()); + + profile.GenerateServerProfileIdentifier(); + + return profile; +} + void CopyRelevantWalletMetadataFromDisk( const AutofillTable& table, std::vector<CreditCard>* cards_from_server) { @@ -340,11 +339,11 @@ void PopulateWalletTypesFromSyncData( std::vector<PaymentsCustomerData>* customer_data) { std::map<std::string, std::string> ids; - for (const syncer::EntityChange& change : entity_data) { - DCHECK(change.data().specifics.has_autofill_wallet()); + for (const std::unique_ptr<syncer::EntityChange>& change : entity_data) { + DCHECK(change->data().specifics.has_autofill_wallet()); const sync_pb::AutofillWalletSpecifics& autofill_specifics = - change.data().specifics.autofill_wallet(); + change->data().specifics.autofill_wallet(); switch (autofill_specifics.type()) { case sync_pb::AutofillWalletSpecifics::MASKED_CREDIT_CARD: diff --git a/chromium/components/autofill/core/browser/webdata/autofill_sync_bridge_util.h b/chromium/components/autofill/core/browser/webdata/autofill_sync_bridge_util.h index fc6812fc600..d346a679895 100644 --- a/chromium/components/autofill/core/browser/webdata/autofill_sync_bridge_util.h +++ b/chromium/components/autofill/core/browser/webdata/autofill_sync_bridge_util.h @@ -48,6 +48,10 @@ void SetAutofillWalletSpecificsFromPaymentsCustomerData( const PaymentsCustomerData& customer_data, sync_pb::AutofillWalletSpecifics* wallet_specifics); +// Creates an AutofillProfile from the specified |address| specifics. +AutofillProfile ProfileFromSpecifics( + const sync_pb::WalletPostalAddress& address); + // TODO(sebsg): This should probably copy the converted state for the address // too. // Copies the metadata from the local cards (if present) to the corresponding diff --git a/chromium/components/autofill/core/browser/webdata/autofill_sync_bridge_util_unittest.cc b/chromium/components/autofill/core/browser/webdata/autofill_sync_bridge_util_unittest.cc index eb1f65eba3e..a76503580ee 100644 --- a/chromium/components/autofill/core/browser/webdata/autofill_sync_bridge_util_unittest.cc +++ b/chromium/components/autofill/core/browser/webdata/autofill_sync_bridge_util_unittest.cc @@ -45,11 +45,12 @@ class TestAutofillTable : public AutofillTable { DISALLOW_COPY_AND_ASSIGN(TestAutofillTable); }; -EntityData SpecificsToEntity(const sync_pb::AutofillWalletSpecifics& specifics, - const std::string& client_tag) { - EntityData data; - *data.specifics.mutable_autofill_wallet() = specifics; - data.client_tag_hash = +std::unique_ptr<EntityData> SpecificsToEntity( + const sync_pb::AutofillWalletSpecifics& specifics, + const std::string& client_tag) { + auto data = std::make_unique<syncer::EntityData>(); + *data->specifics.mutable_autofill_wallet() = specifics; + data->client_tag_hash = syncer::GenerateSyncableHash(syncer::AUTOFILL_WALLET_DATA, client_tag); return data; } @@ -72,20 +73,17 @@ TEST_F(AutofillSyncBridgeUtilTest, PopulateWalletTypesFromSyncData) { entity_data.push_back(EntityChange::CreateAdd( address_id, SpecificsToEntity(CreateAutofillWalletSpecificsForAddress(address_id), - /*client_tag=*/"address-address1") - .PassToPtr())); + /*client_tag=*/"address-address1"))); entity_data.push_back(EntityChange::CreateAdd( "card1", SpecificsToEntity(CreateAutofillWalletSpecificsForCard( /*id=*/"card1", /*billing_address_id=*/address_id), - /*client_tag=*/"card-card1") - .PassToPtr())); + /*client_tag=*/"card-card1"))); entity_data.push_back(EntityChange::CreateAdd( "deadbeef", SpecificsToEntity(CreateAutofillWalletSpecificsForPaymentsCustomerData( /*specifics_id=*/"deadbeef"), - /*client_tag=*/"customer-deadbeef") - .PassToPtr())); + /*client_tag=*/"customer-deadbeef"))); std::vector<CreditCard> wallet_cards; std::vector<AutofillProfile> wallet_addresses; @@ -201,4 +199,4 @@ TEST_F(AutofillSyncBridgeUtilTest, } } // namespace -} // namespace autofill
\ No newline at end of file +} // namespace autofill diff --git a/chromium/components/autofill/core/browser/webdata/autofill_table.cc b/chromium/components/autofill/core/browser/webdata/autofill_table.cc index 44741c86d84..c174b5a4785 100644 --- a/chromium/components/autofill/core/browser/webdata/autofill_table.cc +++ b/chromium/components/autofill/core/browser/webdata/autofill_table.cc @@ -1705,8 +1705,8 @@ bool AutofillTable::ClearAllLocalData() { bool AutofillTable::RemoveAutofillDataModifiedBetween( const base::Time& delete_begin, const base::Time& delete_end, - std::vector<std::string>* profile_guids, - std::vector<std::string>* credit_card_guids) { + std::vector<std::unique_ptr<AutofillProfile>>* profiles, + std::vector<std::unique_ptr<CreditCard>>* credit_cards) { DCHECK(delete_end.is_null() || delete_begin < delete_end); time_t delete_begin_t = delete_begin.ToTimeT(); @@ -1719,17 +1719,20 @@ bool AutofillTable::RemoveAutofillDataModifiedBetween( s_profiles_get.BindInt64(0, delete_begin_t); s_profiles_get.BindInt64(1, delete_end_t); - profile_guids->clear(); + profiles->clear(); while (s_profiles_get.Step()) { std::string guid = s_profiles_get.ColumnString(0); - profile_guids->push_back(guid); + std::unique_ptr<AutofillProfile> profile = GetAutofillProfile(guid); + if (!profile) + return false; + profiles->push_back(std::move(profile)); } if (!s_profiles_get.Succeeded()) return false; // Remove the profile pieces. - for (const std::string& guid : *profile_guids) { - if (!RemoveAutofillProfilePieces(guid, db_)) + for (const std::unique_ptr<AutofillProfile>& profile : *profiles) { + if (!RemoveAutofillProfilePieces(profile->guid(), db_)) return false; } @@ -1750,10 +1753,13 @@ bool AutofillTable::RemoveAutofillDataModifiedBetween( s_credit_cards_get.BindInt64(0, delete_begin_t); s_credit_cards_get.BindInt64(1, delete_end_t); - credit_card_guids->clear(); + credit_cards->clear(); while (s_credit_cards_get.Step()) { std::string guid = s_credit_cards_get.ColumnString(0); - credit_card_guids->push_back(guid); + std::unique_ptr<CreditCard> credit_card = GetCreditCard(guid); + if (!credit_card) + return false; + credit_cards->push_back(std::move(credit_card)); } if (!s_credit_cards_get.Succeeded()) return false; @@ -2767,9 +2773,9 @@ bool AutofillTable::GetAllSyncEntityMetadata( while (s.Step()) { std::string storage_key = s.ColumnString(0); std::string serialized_metadata = s.ColumnString(1); - sync_pb::EntityMetadata entity_metadata; - if (entity_metadata.ParseFromString(serialized_metadata)) { - metadata_batch->AddMetadata(storage_key, entity_metadata); + auto entity_metadata = std::make_unique<sync_pb::EntityMetadata>(); + if (entity_metadata->ParseFromString(serialized_metadata)) { + metadata_batch->AddMetadata(storage_key, std::move(entity_metadata)); } else { DLOG(WARNING) << "Failed to deserialize AUTOFILL model type " "sync_pb::EntityMetadata."; diff --git a/chromium/components/autofill/core/browser/webdata/autofill_table.h b/chromium/components/autofill/core/browser/webdata/autofill_table.h index ae7114f18b4..4c57a958aaf 100644 --- a/chromium/components/autofill/core/browser/webdata/autofill_table.h +++ b/chromium/components/autofill/core/browser/webdata/autofill_table.h @@ -452,8 +452,8 @@ class AutofillTable : public WebDatabaseTable, bool RemoveAutofillDataModifiedBetween( const base::Time& delete_begin, const base::Time& delete_end, - std::vector<std::string>* profile_guids, - std::vector<std::string>* credit_card_guids); + std::vector<std::unique_ptr<AutofillProfile>>* profiles, + std::vector<std::unique_ptr<CreditCard>>* credit_cards); // Removes origin URLs from the autofill_profiles and credit_cards tables if // they were written on or after |delete_begin| and strictly before diff --git a/chromium/components/autofill/core/browser/webdata/autofill_table_unittest.cc b/chromium/components/autofill/core/browser/webdata/autofill_table_unittest.cc index 5ca2d3bd78a..b2f8812369a 100644 --- a/chromium/components/autofill/core/browser/webdata/autofill_table_unittest.cc +++ b/chromium/components/autofill/core/browser/webdata/autofill_table_unittest.cc @@ -1519,16 +1519,15 @@ TEST_F(AutofillTableTest, RemoveAutofillDataModifiedBetween) { "VALUES('00000000-0000-0000-0000-000000000011', 67);")); // Remove all entries modified in the bounded time range [17,41). - std::vector<std::string> profile_guids; - std::vector<std::string> credit_card_guids; + std::vector<std::unique_ptr<AutofillProfile>> profiles; + std::vector<std::unique_ptr<CreditCard>> credit_cards; table_->RemoveAutofillDataModifiedBetween( - Time::FromTimeT(17), Time::FromTimeT(41), - &profile_guids, &credit_card_guids); + Time::FromTimeT(17), Time::FromTimeT(41), &profiles, &credit_cards); // Two profiles should have been removed. - ASSERT_EQ(2UL, profile_guids.size()); - EXPECT_EQ("00000000-0000-0000-0000-000000000001", profile_guids[0]); - EXPECT_EQ("00000000-0000-0000-0000-000000000002", profile_guids[1]); + ASSERT_EQ(2UL, profiles.size()); + EXPECT_EQ("00000000-0000-0000-0000-000000000001", profiles[0]->guid()); + EXPECT_EQ("00000000-0000-0000-0000-000000000002", profiles[1]->guid()); // Make sure that only the expected profiles are still present. sql::Statement s_autofill_profiles_bounded( @@ -1595,10 +1594,10 @@ TEST_F(AutofillTableTest, RemoveAutofillDataModifiedBetween) { EXPECT_FALSE(s_autofill_profile_phones_bounded.Step()); // Three cards should have been removed. - ASSERT_EQ(3UL, credit_card_guids.size()); - EXPECT_EQ("00000000-0000-0000-0000-000000000006", credit_card_guids[0]); - EXPECT_EQ("00000000-0000-0000-0000-000000000007", credit_card_guids[1]); - EXPECT_EQ("00000000-0000-0000-0000-000000000008", credit_card_guids[2]); + ASSERT_EQ(3UL, credit_cards.size()); + EXPECT_EQ("00000000-0000-0000-0000-000000000006", credit_cards[0]->guid()); + EXPECT_EQ("00000000-0000-0000-0000-000000000007", credit_cards[1]->guid()); + EXPECT_EQ("00000000-0000-0000-0000-000000000008", credit_cards[2]->guid()); // Make sure the expected profiles are still present. sql::Statement s_credit_cards_bounded( @@ -1614,12 +1613,11 @@ TEST_F(AutofillTableTest, RemoveAutofillDataModifiedBetween) { EXPECT_FALSE(s_credit_cards_bounded.Step()); // Remove all entries modified on or after time 51 (unbounded range). - table_->RemoveAutofillDataModifiedBetween( - Time::FromTimeT(51), Time(), - &profile_guids, &credit_card_guids); - ASSERT_EQ(2UL, profile_guids.size()); - EXPECT_EQ("00000000-0000-0000-0000-000000000004", profile_guids[0]); - EXPECT_EQ("00000000-0000-0000-0000-000000000005", profile_guids[1]); + table_->RemoveAutofillDataModifiedBetween(Time::FromTimeT(51), Time(), + &profiles, &credit_cards); + ASSERT_EQ(2UL, profiles.size()); + EXPECT_EQ("00000000-0000-0000-0000-000000000004", profiles[0]->guid()); + EXPECT_EQ("00000000-0000-0000-0000-000000000005", profiles[1]->guid()); // Make sure that only the expected profile names are still present. sql::Statement s_autofill_profiles_unbounded( @@ -1670,9 +1668,9 @@ TEST_F(AutofillTableTest, RemoveAutofillDataModifiedBetween) { EXPECT_FALSE(s_autofill_profile_phones_unbounded.Step()); // Two cards should have been removed. - ASSERT_EQ(2UL, credit_card_guids.size()); - EXPECT_EQ("00000000-0000-0000-0000-000000000010", credit_card_guids[0]); - EXPECT_EQ("00000000-0000-0000-0000-000000000011", credit_card_guids[1]); + ASSERT_EQ(2UL, credit_cards.size()); + EXPECT_EQ("00000000-0000-0000-0000-000000000010", credit_cards[0]->guid()); + EXPECT_EQ("00000000-0000-0000-0000-000000000011", credit_cards[1]->guid()); // Make sure the remaining card is the expected one. sql::Statement s_credit_cards_unbounded( @@ -1684,14 +1682,13 @@ TEST_F(AutofillTableTest, RemoveAutofillDataModifiedBetween) { EXPECT_FALSE(s_credit_cards_unbounded.Step()); // Remove all remaining entries. - table_->RemoveAutofillDataModifiedBetween( - Time(), Time(), - &profile_guids, &credit_card_guids); + table_->RemoveAutofillDataModifiedBetween(Time(), Time(), &profiles, + &credit_cards); // Two profiles should have been removed. - ASSERT_EQ(2UL, profile_guids.size()); - EXPECT_EQ("00000000-0000-0000-0000-000000000000", profile_guids[0]); - EXPECT_EQ("00000000-0000-0000-0000-000000000003", profile_guids[1]); + ASSERT_EQ(2UL, profiles.size()); + EXPECT_EQ("00000000-0000-0000-0000-000000000000", profiles[0]->guid()); + EXPECT_EQ("00000000-0000-0000-0000-000000000003", profiles[1]->guid()); // Make sure there are no profiles remaining. sql::Statement s_autofill_profiles_empty( @@ -1722,8 +1719,8 @@ TEST_F(AutofillTableTest, RemoveAutofillDataModifiedBetween) { EXPECT_FALSE(s_autofill_profile_phones_empty.Step()); // One credit card should have been deleted. - ASSERT_EQ(1UL, credit_card_guids.size()); - EXPECT_EQ("00000000-0000-0000-0000-000000000009", credit_card_guids[0]); + ASSERT_EQ(1UL, credit_cards.size()); + EXPECT_EQ("00000000-0000-0000-0000-000000000009", credit_cards[0]->guid()); // There should be no cards left. sql::Statement s_credit_cards_empty( @@ -2677,12 +2674,12 @@ TEST_F(AutofillTableTest, DeleteUnmaskedCard) { table_->UnmaskServerCreditCard(masked_card, full_number); // Delete data in a range a year in the future. - std::vector<std::string> profile_guids; - std::vector<std::string> credit_card_guids; + std::vector<std::unique_ptr<AutofillProfile>> profiles; + std::vector<std::unique_ptr<CreditCard>> credit_cards; ASSERT_TRUE(table_->RemoveAutofillDataModifiedBetween( unmasked_time + base::TimeDelta::FromDays(365), - unmasked_time + base::TimeDelta::FromDays(530), - &profile_guids, &credit_card_guids)); + unmasked_time + base::TimeDelta::FromDays(530), &profiles, + &credit_cards)); // This should not affect the unmasked card (should be unmasked). std::vector<std::unique_ptr<CreditCard>> outputs; @@ -2697,8 +2694,7 @@ TEST_F(AutofillTableTest, DeleteUnmaskedCard) { // the database uses. base::Time now = base::Time::Now() + base::TimeDelta::FromSeconds(1); ASSERT_TRUE(table_->RemoveAutofillDataModifiedBetween( - now - base::TimeDelta::FromDays(1), now, - &profile_guids, &credit_card_guids)); + now - base::TimeDelta::FromDays(1), now, &profiles, &credit_cards)); // This should re-mask. ASSERT_TRUE(table_->GetServerCreditCards(&outputs)); @@ -2717,7 +2713,7 @@ TEST_F(AutofillTableTest, DeleteUnmaskedCard) { // Delete all data. ASSERT_TRUE(table_->RemoveAutofillDataModifiedBetween( - base::Time(), base::Time::Max(), &profile_guids, &credit_card_guids)); + base::Time(), base::Time::Max(), &profiles, &credit_cards)); // Should be masked again. ASSERT_TRUE(table_->GetServerCreditCards(&outputs)); @@ -2911,8 +2907,8 @@ TEST_P(AutofillTableTestPerModelType, AutofillGetAllSyncMetadata) { EntityMetadataMap metadata_records = metadata_batch.TakeAllMetadata(); EXPECT_EQ(metadata_records.size(), 2u); - EXPECT_EQ(metadata_records[storage_key].sequence_number(), 1); - EXPECT_EQ(metadata_records[storage_key2].sequence_number(), 2); + EXPECT_EQ(metadata_records[storage_key]->sequence_number(), 1); + EXPECT_EQ(metadata_records[storage_key2]->sequence_number(), 2); // Now check that a model type state update replaces the old value model_type_state.set_initial_sync_done(false); diff --git a/chromium/components/autofill/core/browser/webdata/autofill_wallet_metadata_sync_bridge.cc b/chromium/components/autofill/core/browser/webdata/autofill_wallet_metadata_sync_bridge.cc index 5f511af4a6c..cf4486920bb 100644 --- a/chromium/components/autofill/core/browser/webdata/autofill_wallet_metadata_sync_bridge.cc +++ b/chromium/components/autofill/core/browser/webdata/autofill_wallet_metadata_sync_bridge.cc @@ -4,11 +4,14 @@ #include "components/autofill/core/browser/webdata/autofill_wallet_metadata_sync_bridge.h" -#include <unordered_map> +#include <map> +#include <unordered_set> #include <utility> +#include <vector> #include "base/base64.h" #include "base/logging.h" +#include "base/metrics/histogram_macros.h" #include "base/optional.h" #include "base/pickle.h" #include "components/autofill/core/browser/autofill_metadata.h" @@ -18,6 +21,7 @@ #include "components/autofill/core/browser/webdata/autofill_table.h" #include "components/autofill/core/browser/webdata/autofill_webdata_backend.h" #include "components/autofill/core/browser/webdata/autofill_webdata_service.h" +#include "components/autofill/core/common/autofill_clock.h" #include "components/autofill/core/common/autofill_util.h" #include "components/sync/model/entity_data.h" #include "components/sync/model/mutable_data_batch.h" @@ -80,16 +84,17 @@ struct TypeAndMetadataId { TypeAndMetadataId ParseWalletMetadataStorageKey( const std::string& storage_key) { - TypeAndMetadataId parsed; - base::Pickle pickle(storage_key.data(), storage_key.size()); base::PickleIterator iterator(pickle); int type_int; - if (!iterator.ReadInt(&type_int) || - !iterator.ReadString(&parsed.metadata_id)) { + std::string specifics_id; + if (!iterator.ReadInt(&type_int) || !iterator.ReadString(&specifics_id)) { NOTREACHED() << "Unsupported storage_key provided " << storage_key; } + + TypeAndMetadataId parsed; parsed.type = static_cast<WalletMetadataSpecifics::Type>(type_int); + parsed.metadata_id = GetMetadataIdForSpecificsId(specifics_id); return parsed; } @@ -157,22 +162,22 @@ bool HasLocalBillingAddress(const AutofillMetadata& metadata) { return metadata.billing_address_id.size() == kLocalGuidSize; } -bool IsRemoteBillingAddressEqualOrBetter(const AutofillMetadata& local, - const AutofillMetadata& remote) { - // If local is empty, remote is better (or equal). Otherwise, if remote is - // empty, local is better. - if (local.billing_address_id.empty()) { +bool IsNewerBillingAddressEqualOrBetter(const AutofillMetadata& older, + const AutofillMetadata& newer) { + // If older is empty, newer is better (or equal). Otherwise, if newer is + // empty, older is better. + if (older.billing_address_id.empty()) { return true; - } else if (remote.billing_address_id.empty()) { + } else if (newer.billing_address_id.empty()) { return false; } // Now we need to decide between non-empty profiles. Prefer id's pointing to // local profiles over ids of non-local profiles. - if (HasLocalBillingAddress(local) != HasLocalBillingAddress(remote)) { - return HasLocalBillingAddress(remote); + if (HasLocalBillingAddress(older) != HasLocalBillingAddress(newer)) { + return HasLocalBillingAddress(newer); } - // For both local / both remote, we prefer the more recently used. - return remote.use_date >= local.use_date; + // For both older / both newer, we prefer the more recently used. + return newer.use_date >= older.use_date; } AutofillMetadata MergeMetadata(WalletMetadataSpecifics::Type type, @@ -187,7 +192,8 @@ AutofillMetadata MergeMetadata(WalletMetadataSpecifics::Type type, merged.has_converted = local.has_converted || remote.has_converted; break; case WalletMetadataSpecifics::CARD: - if (IsRemoteBillingAddressEqualOrBetter(local, remote)) { + if (IsNewerBillingAddressEqualOrBetter(/*older=*/local, + /*newer=*/remote)) { merged.billing_address_id = remote.billing_address_id; } else { merged.billing_address_id = local.billing_address_id; @@ -232,12 +238,25 @@ bool IsMetadataWorthUpdating(AutofillMetadata existing_entry, if (!existing_entry.has_converted && new_entry.has_converted) { return true; } - if (existing_entry.billing_address_id != new_entry.billing_address_id) { + if (existing_entry.billing_address_id != new_entry.billing_address_id && + IsNewerBillingAddressEqualOrBetter(/*older=*/existing_entry, + /*newer=*/new_entry)) { return true; } return false; } +bool IsAnyMetadataDeletable( + const std::map<std::string, AutofillMetadata>& metadata_map) { + for (const auto& pair : metadata_map) { + const AutofillMetadata& metadata = pair.second; + if (metadata.IsDeletable()) { + return true; + } + } + return false; +} + bool AddServerMetadata(AutofillTable* table, WalletMetadataSpecifics::Type type, const AutofillMetadata& metadata) { @@ -269,7 +288,6 @@ bool RemoveServerMetadata(AutofillTable* table, bool UpdateServerMetadata(AutofillTable* table, WalletMetadataSpecifics::Type type, const AutofillMetadata& metadata) { - // TODO: Create UpdateServerAddressMetadata() that takes metadata as arg. switch (type) { case WalletMetadataSpecifics::ADDRESS: return table->UpdateServerAddressMetadata(metadata); @@ -318,6 +336,8 @@ AutofillWalletMetadataSyncBridge::AutofillWalletMetadataSyncBridge( scoped_observer_.Add(web_data_backend_); LoadDataCacheAndMetadata(); + + DeleteOldOrphanMetadata(); } AutofillWalletMetadataSyncBridge::~AutofillWalletMetadataSyncBridge() { @@ -388,12 +408,39 @@ std::string AutofillWalletMetadataSyncBridge::GetStorageKey( entity_data.specifics.wallet_metadata().id()); } +void AutofillWalletMetadataSyncBridge::ApplyStopSyncChanges( + std::unique_ptr<syncer::MetadataChangeList> delete_metadata_change_list) { + // If a metadata change list gets passed in, that means sync is actually + // disabled, so we want to delete the data as well (i.e. the wallet metadata + // entities). + if (delete_metadata_change_list) { + for (const std::pair<std::string, AutofillMetadata>& pair : cache_) { + TypeAndMetadataId parsed_storage_key = + ParseWalletMetadataStorageKey(pair.first); + RemoveServerMetadata(GetAutofillTable(), parsed_storage_key.type, + parsed_storage_key.metadata_id); + } + cache_.clear(); + + // We do not notify the change to the UI because the data bridge will notify + // anyway and notifying on metadata deletion potentially before the data + // deletion is risky. This can cause another conversion of server addresses + // to local addresses as we lack the metadata (that it has been converted + // already). + + // Commit the transaction to make sure the sync data (deleted here) and the + // sync metadata and the progress marker (deleted by the processor via + // |delete_metadata_change_list|) get wiped from the DB. This is especially + // important on Android where we cannot rely on committing transactions on + // shutdown). + web_data_backend_->CommitChanges(); + } +} + void AutofillWalletMetadataSyncBridge::AutofillProfileChanged( const AutofillProfileChange& change) { - // Skip local profiles (if possible, i.e. if it is not a deletion where - // data_model() is not set). - if (change.data_model() && - change.data_model()->record_type() != AutofillProfile::SERVER_PROFILE) { + // Skip local profiles. + if (change.data_model()->record_type() != AutofillProfile::SERVER_PROFILE) { return; } LocalMetadataChanged(WalletMetadataSpecifics::ADDRESS, change); @@ -429,10 +476,26 @@ void AutofillWalletMetadataSyncBridge::LoadDataCacheAndMetadata() { for (const auto& it : addresses_metadata) { cache_[GetStorageKeyForWalletMetadataTypeAndId( WalletMetadataSpecifics::ADDRESS, it.first)] = it.second; + // TODO(crbug.com/949034): Consider adding standard functions for recording + // large times in seconds/minutes. + UMA_HISTOGRAM_CUSTOM_COUNTS( + "Autofill.WalletUseDateInMinutes.Address", + /*sample=*/(AutofillClock::Now() - it.second.use_date).InMinutes(), + /*min=*/base::TimeDelta::FromMinutes(1).InMinutes(), + /*max=*/base::TimeDelta::FromDays(365).InMinutes(), + /*bucket_count=*/50); } for (const auto& it : cards_metadata) { cache_[GetStorageKeyForWalletMetadataTypeAndId( WalletMetadataSpecifics::CARD, it.first)] = it.second; + // TODO(crbug.com/949034): Consider adding standard functions for recording + // large times in seconds/minutes. + UMA_HISTOGRAM_CUSTOM_COUNTS( + "Autofill.WalletUseDateInMinutes.Card", + /*sample=*/(AutofillClock::Now() - it.second.use_date).InMinutes(), + /*min=*/base::TimeDelta::FromMinutes(1).InMinutes(), + /*max=*/base::TimeDelta::FromDays(365).InMinutes(), + /*bucket_count=*/50); } // Load the metadata and send to the processor. @@ -447,6 +510,62 @@ void AutofillWalletMetadataSyncBridge::LoadDataCacheAndMetadata() { change_processor()->ModelReadyToSync(std::move(batch)); } +void AutofillWalletMetadataSyncBridge::DeleteOldOrphanMetadata() { + if (!web_data_backend_ || !web_data_backend_->GetDatabase() || + !GetAutofillTable()) { + // We have a problem with the database, not an issue, we clean up next time. + return; + } + if (!IsAnyMetadataDeletable(cache_)) { + return; + } + + // Load up (metadata) ids for which data exists; we do not delete those. + std::unordered_set<std::string> non_orphan_ids; + std::vector<std::unique_ptr<AutofillProfile>> profiles; + std::vector<std::unique_ptr<CreditCard>> cards; + if (!GetAutofillTable()->GetServerProfiles(&profiles) || + !GetAutofillTable()->GetServerCreditCards(&cards)) { + return; + } + for (const std::unique_ptr<AutofillProfile>& profile : profiles) { + non_orphan_ids.insert(profile->server_id()); + } + for (const std::unique_ptr<CreditCard>& card : cards) { + non_orphan_ids.insert(card->server_id()); + } + + // Identify storage keys of old orphans (we delete them below to avoid + // modifying |cache_| while iterating). + std::unordered_set<std::string> old_orphan_keys; + for (const auto& pair : cache_) { + const AutofillMetadata& metadata = pair.second; + if (metadata.IsDeletable() && !non_orphan_ids.count(metadata.id)) { + old_orphan_keys.insert(pair.first); + } + } + + if (old_orphan_keys.empty()) { + return; + } + + std::unique_ptr<MetadataChangeList> metadata_change_list = + CreateMetadataChangeList(); + for (const std::string storage_key : old_orphan_keys) { + TypeAndMetadataId parsed_storage_key = + ParseWalletMetadataStorageKey(storage_key); + if (RemoveServerMetadata(GetAutofillTable(), parsed_storage_key.type, + parsed_storage_key.metadata_id)) { + cache_.erase(storage_key); + change_processor()->Delete(storage_key, metadata_change_list.get()); + } + } + // Commit the transaction to make sure the data and the metadata is written + // down (especially on Android where we cannot rely on committing transactions + // on shutdown). + web_data_backend_->CommitChanges(); +} + void AutofillWalletMetadataSyncBridge::GetDataImpl( base::Optional<std::unordered_set<std::string>> storage_keys_set, DataCallback callback) { @@ -478,10 +597,10 @@ void AutofillWalletMetadataSyncBridge::UploadInitialLocalData( local_keys_to_upload.insert(it.first); } // Strip |local_keys_to_upload| of the keys of data provided by the server. - for (const EntityChange& change : entity_data) { - DCHECK_EQ(change.type(), EntityChange::ACTION_ADD) + for (const std::unique_ptr<EntityChange>& change : entity_data) { + DCHECK_EQ(change->type(), EntityChange::ACTION_ADD) << "Illegal change; can only be called during initial MergeSyncData()"; - local_keys_to_upload.erase(change.storage_key()); + local_keys_to_upload.erase(change->storage_key()); } // Upload the remaining storage keys for (const std::string& storage_key : local_keys_to_upload) { @@ -502,24 +621,24 @@ AutofillWalletMetadataSyncBridge::MergeRemoteChanges( AutofillTable* table = GetAutofillTable(); - for (const EntityChange& change : entity_data) { + for (const std::unique_ptr<EntityChange>& change : entity_data) { TypeAndMetadataId parsed_storage_key = - ParseWalletMetadataStorageKey(change.storage_key()); - switch (change.type()) { + ParseWalletMetadataStorageKey(change->storage_key()); + switch (change->type()) { case EntityChange::ACTION_ADD: case EntityChange::ACTION_UPDATE: { const WalletMetadataSpecifics& specifics = - change.data().specifics.wallet_metadata(); + change->data().specifics.wallet_metadata(); AutofillMetadata remote = CreateAutofillMetadataFromWalletMetadataSpecifics(specifics); - auto it = cache_.find(change.storage_key()); + auto it = cache_.find(change->storage_key()); base::Optional<AutofillMetadata> local = base::nullopt; if (it != cache_.end()) { local = it->second; } if (!local) { - cache_[change.storage_key()] = remote; + cache_[change->storage_key()] = remote; is_any_local_modified |= AddServerMetadata( GetAutofillTable(), parsed_storage_key.type, remote); continue; @@ -529,12 +648,12 @@ AutofillWalletMetadataSyncBridge::MergeRemoteChanges( AutofillMetadata merged = MergeMetadata(parsed_storage_key.type, *local, remote); if (merged != *local) { - cache_[change.storage_key()] = merged; + cache_[change->storage_key()] = merged; is_any_local_modified |= UpdateServerMetadata(table, parsed_storage_key.type, merged); } if (merged != remote) { - change_processor()->Put(change.storage_key(), + change_processor()->Put(change->storage_key(), CreateEntityDataFromAutofillMetadata( parsed_storage_key.type, merged), metadata_change_list.get()); @@ -542,14 +661,27 @@ AutofillWalletMetadataSyncBridge::MergeRemoteChanges( break; } case EntityChange::ACTION_DELETE: { - cache_.erase(change.storage_key()); - is_any_local_modified |= RemoveServerMetadata( - table, parsed_storage_key.type, parsed_storage_key.metadata_id); + // We intentionally ignore remote deletions in order to avoid + // delete-create ping pongs (if we delete metadata for address data + // entity that still locally exists, PDM will think the server address + // has not been converted to a local address yet and will trigger + // conversion that in turn triggers creating and committing the metadata + // entity again). + // This is safe because this client will delete the wallet_metadata + // entity locally as soon as the wallet_data entity gets deleted. + // Corner cases are handled by DeleteOldOrphanMetadata(). break; } } } + // Commit the transaction to make sure the data and the metadata with the + // new progress marker is written down (especially on Android where we + // cannot rely on committing transactions on shutdown). We need to commit + // even if !|is_any_local_modified| because the model type state or local + // metadata may have changed. + web_data_backend_->CommitChanges(); + if (is_any_local_modified) { web_data_backend_->NotifyOfMultipleAutofillChanges(); } @@ -576,9 +708,7 @@ void AutofillWalletMetadataSyncBridge::LocalMetadataChanged( if (RemoveServerMetadata(GetAutofillTable(), type, metadata_id)) { cache_.erase(storage_key); // Send up deletion only if we had this entry in the DB. It is not there - // if (i) it was previously deleted by a remote deletion or (ii) this is - // notification for a LOCAL_PROFILE (which have non-overlapping - // storage_keys). + // if it was previously deleted by a remote deletion. change_processor()->Delete(storage_key, metadata_change_list.get()); } return; @@ -612,6 +742,11 @@ void AutofillWalletMetadataSyncBridge::LocalMetadataChanged( metadata_change_list.get()); return; } + + // We do not need to commit any local changes (written by the processor via + // the metadata change list) because the open WebDatabase transaction is + // committed by the AutofillWebDataService when the original local write + // operation (that triggered this notification to the bridge) finishes. } } // namespace autofill diff --git a/chromium/components/autofill/core/browser/webdata/autofill_wallet_metadata_sync_bridge.h b/chromium/components/autofill/core/browser/webdata/autofill_wallet_metadata_sync_bridge.h index 16feaf2dd78..59428a945ba 100644 --- a/chromium/components/autofill/core/browser/webdata/autofill_wallet_metadata_sync_bridge.h +++ b/chromium/components/autofill/core/browser/webdata/autofill_wallet_metadata_sync_bridge.h @@ -74,6 +74,8 @@ class AutofillWalletMetadataSyncBridge void GetAllDataForDebugging(DataCallback callback) override; std::string GetClientTag(const syncer::EntityData& entity_data) override; std::string GetStorageKey(const syncer::EntityData& entity_data) override; + void ApplyStopSyncChanges(std::unique_ptr<syncer::MetadataChangeList> + delete_metadata_change_list) override; // AutofillWebDataServiceObserverOnDBSequence implementation. void AutofillProfileChanged(const AutofillProfileChange& change) override; @@ -88,6 +90,16 @@ class AutofillWalletMetadataSyncBridge // tracking changes. void LoadDataCacheAndMetadata(); + // Deletes old metadata entities that have no corresponding data entities. + // This routine is here to help with really corner-case scenarios, e.g. + // - having one client create a metadata entity M for new data D while other + // clients are off; + // - switch off this client forever and remove the entity D from Wallet; + // - turn on other clients so that they receive M from sync; + // - these other clients never knew about D and thus they have no reason to + // delete M when they receive an update from the Walllet server. + void DeleteOldOrphanMetadata(); + // Reads local wallet metadata from the database and passes them into // |callback|. If |storage_keys_set| is not set, it returns all data entries. // Otherwise, it returns only entries with storage key in |storage_keys_set|. diff --git a/chromium/components/autofill/core/browser/webdata/autofill_wallet_metadata_sync_bridge_unittest.cc b/chromium/components/autofill/core/browser/webdata/autofill_wallet_metadata_sync_bridge_unittest.cc index a9322372bcb..c887bde454f 100644 --- a/chromium/components/autofill/core/browser/webdata/autofill_wallet_metadata_sync_bridge_unittest.cc +++ b/chromium/components/autofill/core/browser/webdata/autofill_wallet_metadata_sync_bridge_unittest.cc @@ -19,6 +19,7 @@ #include "base/test/bind_test_util.h" #include "base/test/scoped_task_environment.h" #include "base/time/time.h" +#include "components/autofill/core/browser/autofill_metadata.h" #include "components/autofill/core/browser/autofill_profile.h" #include "components/autofill/core/browser/country_names.h" #include "components/autofill/core/browser/credit_card.h" @@ -44,7 +45,6 @@ using base::ScopedTempDir; using sync_pb::WalletMetadataSpecifics; using syncer::DataBatch; using syncer::EntityData; -using syncer::EntityDataPtr; using syncer::KeyAndData; using syncer::MockModelTypeChangeProcessor; using syncer::ModelType; @@ -85,13 +85,14 @@ const char kLocalAddr1ServerId[] = "e171e3ed-858a-4dd5-9bf3-8517f14ba5fc"; const char kLocalAddr2ServerId[] = "fa232b9a-f248-4e5a-8d76-d46f821c0c5f"; const char kLocaleString[] = "en-US"; -const base::Time kJune2017 = base::Time::FromDoubleT(1497552271); base::Time UseDateFromProtoValue(int64_t use_date_proto_value) { return base::Time::FromDeltaSinceWindowsEpoch( base::TimeDelta::FromMicroseconds(use_date_proto_value)); } +const base::Time kDefaultTime = UseDateFromProtoValue(100); + int64_t UseDateToProtoValue(base::Time use_date) { return use_date.ToDeltaSinceWindowsEpoch().InMicroseconds(); } @@ -127,7 +128,7 @@ WalletMetadataSpecifics CreateWalletMetadataSpecificsForAddress( // clock value is overrided by TestAutofillClock in the test fixture). return CreateWalletMetadataSpecificsForAddressWithDetails( specifics_id, /*use_count=*/1, - /*use_date=*/UseDateToProtoValue(kJune2017)); + /*use_date=*/UseDateToProtoValue(kDefaultTime)); } WalletMetadataSpecifics CreateWalletMetadataSpecificsForCardWithDetails( @@ -152,7 +153,7 @@ WalletMetadataSpecifics CreateWalletMetadataSpecificsForCard( // clock value is overrided by TestAutofillClock in the test fixture). return CreateWalletMetadataSpecificsForCardWithDetails( specifics_id, /*use_count=*/1, - /*use_date=*/UseDateToProtoValue(kJune2017)); + /*use_date=*/UseDateToProtoValue(kDefaultTime)); } AutofillProfile CreateServerProfileWithDetails(const std::string& server_id, @@ -265,7 +266,7 @@ class AutofillWalletMetadataSyncBridgeTest : public testing::Test { void SetUp() override { // Fix a time for implicitly constructed use_dates in AutofillProfile. - test_clock_.SetNow(kJune2017); + test_clock_.SetNow(kDefaultTime); CountryNames::SetLocaleString(kLocaleString); ASSERT_TRUE(temp_dir_.CreateUniqueTempDir()); db_.AddTable(&table_); @@ -291,6 +292,12 @@ class AutofillWalletMetadataSyncBridgeTest : public testing::Test { mock_processor_.CreateForwardingProcessor(), &backend_)); } + void StopSyncing() { + real_processor_->OnSyncStopping(syncer::CLEAR_METADATA); + } + + void Shutdown() { real_processor_->OnSyncStopping(syncer::KEEP_METADATA); } + void StartSyncing( const std::vector<WalletMetadataSpecifics>& remote_data = {}) { base::RunLoop loop; @@ -307,8 +314,7 @@ class AutofillWalletMetadataSyncBridgeTest : public testing::Test { ReceiveUpdates(remote_data); } - void ReceiveUpdates( - const std::vector<WalletMetadataSpecifics>& remote_data = {}) { + void ReceiveUpdates(const std::vector<WalletMetadataSpecifics>& remote_data) { // Make sure each update has an updated response version so that it does not // get filtered out as reflection by the processor. ++response_version; @@ -320,22 +326,48 @@ class AutofillWalletMetadataSyncBridgeTest : public testing::Test { for (const WalletMetadataSpecifics& specifics : remote_data) { updates.push_back(SpecificsToUpdateResponse(specifics)); } - real_processor_->OnUpdateReceived(state, updates); + real_processor_->OnUpdateReceived(state, std::move(updates)); } - EntityData SpecificsToEntity(const WalletMetadataSpecifics& specifics) { - EntityData data; - *data.specifics.mutable_wallet_metadata() = specifics; - data.client_tag_hash = syncer::GenerateSyncableHash( - syncer::AUTOFILL_WALLET_METADATA, bridge()->GetClientTag(data)); + void ReceiveTombstones( + const std::vector<WalletMetadataSpecifics>& remote_tombstones) { + // Make sure each update has an updated response version so that it does not + // get filtered out as reflection by the processor. + ++response_version; + // After this update initial sync is for sure done. + sync_pb::ModelTypeState state; + state.set_initial_sync_done(true); + + syncer::UpdateResponseDataList updates; + for (const WalletMetadataSpecifics& specifics : remote_tombstones) { + updates.push_back( + SpecificsToUpdateResponse(specifics, /*is_deleted=*/true)); + } + real_processor_->OnUpdateReceived(state, std::move(updates)); + } + + std::unique_ptr<EntityData> SpecificsToEntity( + const WalletMetadataSpecifics& specifics, + bool is_deleted = false) { + auto data = std::make_unique<EntityData>(); + *data->specifics.mutable_wallet_metadata() = specifics; + data->client_tag_hash = syncer::GenerateSyncableHash( + syncer::AUTOFILL_WALLET_METADATA, bridge()->GetClientTag(*data)); + if (is_deleted) { + // Specifics had to be set in order to generate the client tag. Since + // deleted entity is defined by specifics being empty, we need to clear + // them now. + data->specifics = sync_pb::EntitySpecifics(); + } return data; } - syncer::UpdateResponseData SpecificsToUpdateResponse( - const WalletMetadataSpecifics& specifics) { - syncer::UpdateResponseData data; - data.entity = SpecificsToEntity(specifics).PassToPtr(); - data.response_version = response_version; + std::unique_ptr<syncer::UpdateResponseData> SpecificsToUpdateResponse( + const WalletMetadataSpecifics& specifics, + bool is_deleted = false) { + auto data = std::make_unique<syncer::UpdateResponseData>(); + data->entity = SpecificsToEntity(specifics, is_deleted); + data->response_version = response_version; return data; } @@ -380,12 +412,35 @@ class AutofillWalletMetadataSyncBridgeTest : public testing::Test { return data; } + std::vector<std::string> GetLocalSyncMetadataStorageKeys() { + std::vector<std::string> storage_keys; + + AutofillTable* table = AutofillTable::FromWebDatabase(&db_); + syncer::MetadataBatch batch; + if (table->GetAllSyncMetadata(syncer::AUTOFILL_WALLET_METADATA, &batch)) { + for (const std::pair<const std::string, + std::unique_ptr<sync_pb::EntityMetadata>>& entry : + batch.GetAllMetadata()) { + storage_keys.push_back(entry.first); + } + } + return storage_keys; + } + + void AdvanceTestClockByTwoYears() { + test_clock_.Advance(base::TimeDelta::FromDays(365 * 2)); + } + AutofillWalletMetadataSyncBridge* bridge() { return bridge_.get(); } syncer::MockModelTypeChangeProcessor& mock_processor() { return mock_processor_; } + syncer::ClientTagBasedModelTypeProcessor* real_processor() { + return real_processor_.get(); + } + AutofillTable* table() { return &table_; } MockAutofillWebDataBackend* backend() { return &backend_; } @@ -410,7 +465,7 @@ TEST_F(AutofillWalletMetadataSyncBridgeTest, GetClientTagForAddress) { ResetBridge(); WalletMetadataSpecifics specifics = CreateWalletMetadataSpecificsForAddress(kAddr1SpecificsId); - EXPECT_EQ(bridge()->GetClientTag(SpecificsToEntity(specifics)), + EXPECT_EQ(bridge()->GetClientTag(*SpecificsToEntity(specifics)), kAddr1SyncTag); } @@ -418,7 +473,7 @@ TEST_F(AutofillWalletMetadataSyncBridgeTest, GetClientTagForCard) { ResetBridge(); WalletMetadataSpecifics specifics = CreateWalletMetadataSpecificsForCard(kCard1SpecificsId); - EXPECT_EQ(bridge()->GetClientTag(SpecificsToEntity(specifics)), + EXPECT_EQ(bridge()->GetClientTag(*SpecificsToEntity(specifics)), kCard1SyncTag); } @@ -427,7 +482,7 @@ TEST_F(AutofillWalletMetadataSyncBridgeTest, GetStorageKeyForAddress) { ResetBridge(); WalletMetadataSpecifics specifics = CreateWalletMetadataSpecificsForAddress(kAddr1SpecificsId); - EXPECT_EQ(bridge()->GetStorageKey(SpecificsToEntity(specifics)), + EXPECT_EQ(bridge()->GetStorageKey(*SpecificsToEntity(specifics)), GetAddressStorageKey(kAddr1SpecificsId)); } @@ -435,7 +490,7 @@ TEST_F(AutofillWalletMetadataSyncBridgeTest, GetStorageKeyForCard) { ResetBridge(); WalletMetadataSpecifics specifics = CreateWalletMetadataSpecificsForCard(kCard1SpecificsId); - EXPECT_EQ(bridge()->GetStorageKey(SpecificsToEntity(specifics)), + EXPECT_EQ(bridge()->GetStorageKey(*SpecificsToEntity(specifics)), GetCardStorageKey(kCard1SpecificsId)); } @@ -516,6 +571,50 @@ TEST_F(AutofillWalletMetadataSyncBridgeTest, GetData_ShouldReturnCompleteData) { EqualsSpecifics(card_specifics))); } +TEST_F(AutofillWalletMetadataSyncBridgeTest, + ApplyStopSyncChanges_ShouldWipeLocalDataWhenSyncStopped) { + // Perform initial sync to create sync data & metadata. + ResetBridge(/*initial_sync_done=*/false); + WalletMetadataSpecifics profile = + CreateWalletMetadataSpecificsForAddressWithDetails( + kAddr1SpecificsId, /*use_count=*/10, /*use_date=*/20); + WalletMetadataSpecifics card = + CreateWalletMetadataSpecificsForCardWithDetails( + kCard1SpecificsId, /*use_count=*/30, /*use_date=*/40); + StartSyncing({profile, card}); + + // Now stop sync. This should wipe the data but not notify the backend (as the + // data bridge will do that). + EXPECT_CALL(*backend(), CommitChanges()); + EXPECT_CALL(*backend(), NotifyOfMultipleAutofillChanges()).Times(0); + StopSyncing(); + + EXPECT_THAT(GetAllLocalDataInclRestart(), IsEmpty()); +} + +TEST_F(AutofillWalletMetadataSyncBridgeTest, + ApplyStopSyncChanges_ShouldKeepLocalDataOnShutdown) { + // Perform initial sync to create sync data & metadata. + ResetBridge(/*initial_sync_done=*/false); + WalletMetadataSpecifics profile = + CreateWalletMetadataSpecificsForAddressWithDetails( + kAddr1SpecificsId, /*use_count=*/10, /*use_date=*/20); + WalletMetadataSpecifics card = + CreateWalletMetadataSpecificsForCardWithDetails( + kCard1SpecificsId, /*use_count=*/30, /*use_date=*/40); + StartSyncing({profile, card}); + + // Now simulate shutting down the browser. This should not touch any of the + // data and thus also not notify the backend. + EXPECT_CALL(*backend(), CommitChanges()).Times(0); + EXPECT_CALL(*backend(), NotifyOfMultipleAutofillChanges()).Times(0); + Shutdown(); + + EXPECT_THAT( + GetAllLocalDataInclRestart(), + UnorderedElementsAre(EqualsSpecifics(profile), EqualsSpecifics(card))); +} + // Verify that lower values of metadata are not sent to the sync server when // local metadata is updated. TEST_F(AutofillWalletMetadataSyncBridgeTest, @@ -532,6 +631,9 @@ TEST_F(AutofillWalletMetadataSyncBridgeTest, kCard1ServerId, /*use_count=*/2, /*use_date=*/5); EXPECT_CALL(mock_processor(), Put(_, _, _)).Times(0); + // Local changes should not cause local DB writes. + EXPECT_CALL(*backend(), CommitChanges()).Times(0); + EXPECT_CALL(*backend(), NotifyOfMultipleAutofillChanges()).Times(0); bridge()->AutofillProfileChanged( AutofillProfileChange(AutofillProfileChange::UPDATE, @@ -567,6 +669,9 @@ TEST_F(AutofillWalletMetadataSyncBridgeTest, kCard1ServerId, /*use_count=*/2, /*use_date=*/5); EXPECT_CALL(mock_processor(), Put(_, _, _)).Times(0); + // Local changes should not cause local DB writes. + EXPECT_CALL(*backend(), CommitChanges()).Times(0); + EXPECT_CALL(*backend(), NotifyOfMultipleAutofillChanges()).Times(0); bridge()->AutofillProfileChanged( AutofillProfileChange(AutofillProfileChange::ADD, @@ -611,6 +716,9 @@ TEST_F(AutofillWalletMetadataSyncBridgeTest, Put(kAddr1StorageKey, HasSpecifics(expected_profile_specifics), _)); EXPECT_CALL(mock_processor(), Put(kCard1StorageKey, HasSpecifics(expected_card_specifics), _)); + // Local changes should not cause local DB writes. + EXPECT_CALL(*backend(), CommitChanges()).Times(0); + EXPECT_CALL(*backend(), NotifyOfMultipleAutofillChanges()).Times(0); bridge()->AutofillProfileChanged( AutofillProfileChange(AutofillProfileChange::UPDATE, @@ -645,6 +753,9 @@ TEST_F(AutofillWalletMetadataSyncBridgeTest, Put(kAddr1StorageKey, HasSpecifics(expected_profile_specifics), _)); EXPECT_CALL(mock_processor(), Put(kCard1StorageKey, HasSpecifics(expected_card_specifics), _)); + // Local changes should not cause local DB writes. + EXPECT_CALL(*backend(), CommitChanges()).Times(0); + EXPECT_CALL(*backend(), NotifyOfMultipleAutofillChanges()).Times(0); bridge()->AutofillProfileChanged(AutofillProfileChange( AutofillProfileChange::ADD, new_profile.server_id(), &new_profile)); @@ -679,6 +790,9 @@ TEST_F(AutofillWalletMetadataSyncBridgeTest, SendNewDataToServerOnLocalUpdate) { Put(kAddr1StorageKey, HasSpecifics(expected_profile_specifics), _)); EXPECT_CALL(mock_processor(), Put(kCard1StorageKey, HasSpecifics(expected_card_specifics), _)); + // Local changes should not cause local DB writes. + EXPECT_CALL(*backend(), CommitChanges()).Times(0); + EXPECT_CALL(*backend(), NotifyOfMultipleAutofillChanges()).Times(0); bridge()->AutofillProfileChanged(AutofillProfileChange( AutofillProfileChange::UPDATE, new_profile.server_id(), &new_profile)); @@ -704,11 +818,15 @@ TEST_F(AutofillWalletMetadataSyncBridgeTest, EXPECT_CALL(mock_processor(), Delete(kAddr1StorageKey, _)); EXPECT_CALL(mock_processor(), Delete(kCard1StorageKey, _)); + // Local changes should not cause local DB writes. + EXPECT_CALL(*backend(), CommitChanges()).Times(0); + EXPECT_CALL(*backend(), NotifyOfMultipleAutofillChanges()).Times(0); - bridge()->AutofillProfileChanged(AutofillProfileChange( - AutofillProfileChange::REMOVE, existing_profile.server_id(), nullptr)); + bridge()->AutofillProfileChanged( + AutofillProfileChange(AutofillProfileChange::REMOVE, + existing_profile.server_id(), &existing_profile)); bridge()->CreditCardChanged(CreditCardChange( - CreditCardChange::REMOVE, existing_card.server_id(), nullptr)); + CreditCardChange::REMOVE, existing_card.server_id(), &existing_card)); // Check that there is no metadata anymore. EXPECT_THAT(GetAllLocalDataInclRestart(), IsEmpty()); @@ -730,16 +848,230 @@ TEST_F(AutofillWalletMetadataSyncBridgeTest, ASSERT_THAT(GetAllLocalDataInclRestart(), IsEmpty()); EXPECT_CALL(mock_processor(), Delete(_, _)).Times(0); + // Local changes should not cause local DB writes. + EXPECT_CALL(*backend(), CommitChanges()).Times(0); + EXPECT_CALL(*backend(), NotifyOfMultipleAutofillChanges()).Times(0); - bridge()->AutofillProfileChanged(AutofillProfileChange( - AutofillProfileChange::REMOVE, existing_profile.server_id(), nullptr)); + bridge()->AutofillProfileChanged( + AutofillProfileChange(AutofillProfileChange::REMOVE, + existing_profile.server_id(), &existing_profile)); bridge()->CreditCardChanged(CreditCardChange( - CreditCardChange::REMOVE, existing_card.server_id(), nullptr)); + CreditCardChange::REMOVE, existing_card.server_id(), &existing_card)); // Check that there is also no metadata at the end. EXPECT_THAT(GetAllLocalDataInclRestart(), IsEmpty()); } +// Verify that old orphan metadata gets deleted on startup. +TEST_F(AutofillWalletMetadataSyncBridgeTest, DeleteOldOrphanMetadataOnStartup) { + WalletMetadataSpecifics profile = + CreateWalletMetadataSpecificsForAddressWithDetails( + kAddr1SpecificsId, /*use_count=*/10, /*use_date=*/20); + WalletMetadataSpecifics card = + CreateWalletMetadataSpecificsForCardWithDetails( + kCard1SpecificsId, /*use_count=*/30, /*use_date=*/40); + + // Save only metadata and not data - simulate an orphan. + table()->AddServerAddressMetadata( + CreateServerProfileFromSpecifics(profile).GetMetadata()); + table()->AddServerCardMetadata( + CreateServerCreditCardFromSpecifics(card).GetMetadata()); + + // Make the orphans old by advancing time. + AdvanceTestClockByTwoYears(); + + EXPECT_CALL(mock_processor(), Delete(kAddr1StorageKey, _)); + EXPECT_CALL(mock_processor(), Delete(kCard1StorageKey, _)); + EXPECT_CALL(*backend(), CommitChanges()); + + ResetBridge(); + + ASSERT_THAT(GetAllLocalDataInclRestart(), IsEmpty()); +} + +// Verify that recent orphan metadata does not get deleted on startup. +TEST_F(AutofillWalletMetadataSyncBridgeTest, + DoNotDeleteOldNonOrphanMetadataOnStartup) { + WalletMetadataSpecifics profile = + CreateWalletMetadataSpecificsForAddressWithDetails( + kAddr1SpecificsId, /*use_count=*/10, /*use_date=*/20); + WalletMetadataSpecifics card = + CreateWalletMetadataSpecificsForCardWithDetails( + kCard1SpecificsId, /*use_count=*/30, /*use_date=*/40); + + // Save both data and metadata - these are not orphans. + table()->SetServerProfiles({CreateServerProfileFromSpecifics(profile)}); + table()->SetServerCreditCards({CreateServerCreditCardFromSpecifics(card)}); + + // Make the entities old by advancing time. + AdvanceTestClockByTwoYears(); + + // Since the entities are non-oprhans, they should not get deleted. + EXPECT_CALL(mock_processor(), Delete(_, _)).Times(0); + EXPECT_CALL(*backend(), CommitChanges()).Times(0); + + ResetBridge(); + + EXPECT_THAT( + GetAllLocalDataInclRestart(), + UnorderedElementsAre(EqualsSpecifics(profile), EqualsSpecifics(card))); +} + +// Verify that recent orphan metadata does not get deleted on startup. +TEST_F(AutofillWalletMetadataSyncBridgeTest, + DoNotDeleteRecentOrphanMetadataOnStartup) { + WalletMetadataSpecifics profile = + CreateWalletMetadataSpecificsForAddressWithDetails( + kAddr1SpecificsId, /*use_count=*/10, /*use_date=*/20); + WalletMetadataSpecifics card = + CreateWalletMetadataSpecificsForCardWithDetails( + kCard1SpecificsId, /*use_count=*/30, /*use_date=*/40); + + // Save only metadata and not data - simulate an orphan. + table()->AddServerAddressMetadata( + CreateServerProfileFromSpecifics(profile).GetMetadata()); + table()->AddServerCardMetadata( + CreateServerCreditCardFromSpecifics(card).GetMetadata()); + + // We do not advance time so the orphans are recent, should not get deleted. + EXPECT_CALL(mock_processor(), Delete(_, _)).Times(0); + EXPECT_CALL(*backend(), CommitChanges()).Times(0); + + ResetBridge(); + + EXPECT_THAT( + GetAllLocalDataInclRestart(), + UnorderedElementsAre(EqualsSpecifics(profile), EqualsSpecifics(card))); +} + +// Test that both local cards and local profiles that are not in the remote data +// set are uploaded during initial sync. This should rarely happen in practice +// because we wipe local data when disabling sync. Still there are corner cases +// such as when PDM manages to change metadata before the metadata bridge +// performs initial sync. +TEST_F(AutofillWalletMetadataSyncBridgeTest, + InitialSync_UploadUniqueLocalData) { + WalletMetadataSpecifics preexisting_profile = + CreateWalletMetadataSpecificsForAddressWithDetails( + kAddr1SpecificsId, /*use_count=*/10, /*use_date=*/20); + WalletMetadataSpecifics preexisting_card = + CreateWalletMetadataSpecificsForCardWithDetails( + kCard1SpecificsId, /*use_count=*/30, /*use_date=*/40); + + table()->SetServerProfiles( + {CreateServerProfileFromSpecifics(preexisting_profile)}); + table()->SetServerCreditCards( + {CreateServerCreditCardFromSpecifics(preexisting_card)}); + + // Have different entities on the server. + WalletMetadataSpecifics remote_profile = + CreateWalletMetadataSpecificsForAddressWithDetails( + kAddr2SpecificsId, /*use_count=*/10, /*use_date=*/20); + WalletMetadataSpecifics remote_card = + CreateWalletMetadataSpecificsForCardWithDetails( + kCard2SpecificsId, /*use_count=*/30, /*use_date=*/40); + + // The bridge should upload the unique local entities and store the remote + // ones locally. + EXPECT_CALL(mock_processor(), + Put(kAddr1StorageKey, HasSpecifics(preexisting_profile), _)); + EXPECT_CALL(mock_processor(), + Put(kCard1StorageKey, HasSpecifics(preexisting_card), _)); + EXPECT_CALL(mock_processor(), Delete(_, _)).Times(0); + EXPECT_CALL(*backend(), CommitChanges()); + EXPECT_CALL(*backend(), NotifyOfMultipleAutofillChanges()); + + ResetBridge(/*initial_sync_done=*/false); + StartSyncing({remote_profile, remote_card}); + + EXPECT_THAT(GetAllLocalDataInclRestart(), + UnorderedElementsAre(EqualsSpecifics(preexisting_profile), + EqualsSpecifics(preexisting_card), + EqualsSpecifics(remote_profile), + EqualsSpecifics(remote_card))); +} + +// Test that the initial sync correctly distinguishes data that is unique in the +// local data set from data that is both in the local data and in the remote +// data. We should only upload the local data. This should rarely happen in +// practice because we wipe local data when disabling sync. Still there are +// corner cases such as when PDM manages to change metadata before the metadata +// bridge performs initial sync. +TEST_F(AutofillWalletMetadataSyncBridgeTest, + InitialSync_UploadOnlyUniqueLocalData) { + WalletMetadataSpecifics preexisting_profile = + CreateWalletMetadataSpecificsForAddressWithDetails( + kAddr1SpecificsId, /*use_count=*/10, /*use_date=*/20); + WalletMetadataSpecifics preexisting_card = + CreateWalletMetadataSpecificsForCardWithDetails( + kCard1SpecificsId, /*use_count=*/30, /*use_date=*/40); + + table()->SetServerProfiles( + {CreateServerProfileFromSpecifics(preexisting_profile)}); + table()->SetServerCreditCards( + {CreateServerCreditCardFromSpecifics(preexisting_card)}); + + // The remote profile has the same id as local profile, only is newer. + WalletMetadataSpecifics remote_profile = + CreateWalletMetadataSpecificsForAddressWithDetails( + kAddr1SpecificsId, /*use_count=*/15, /*use_date=*/25); + WalletMetadataSpecifics remote_card = + CreateWalletMetadataSpecificsForCardWithDetails( + kCard2SpecificsId, /*use_count=*/30, /*use_date=*/40); + + // Upload _only_ the unique local data, only the card. + EXPECT_CALL(mock_processor(), + Put(kCard1StorageKey, HasSpecifics(preexisting_card), _)); + EXPECT_CALL(mock_processor(), Delete(_, _)).Times(0); + EXPECT_CALL(*backend(), CommitChanges()); + EXPECT_CALL(*backend(), NotifyOfMultipleAutofillChanges()); + + ResetBridge(/*initial_sync_done=*/false); + StartSyncing({remote_profile, remote_card}); + + EXPECT_THAT(GetAllLocalDataInclRestart(), + UnorderedElementsAre(EqualsSpecifics(preexisting_card), + EqualsSpecifics(remote_profile), + EqualsSpecifics(remote_card))); +} + +// Test that remote deletions are ignored. +TEST_F(AutofillWalletMetadataSyncBridgeTest, + RemoteDeletion_ShouldNotDeleteExistingLocalData) { + // Perform initial sync to create sync data & metadata. + ResetBridge(/*initial_sync_done=*/false); + WalletMetadataSpecifics profile = + CreateWalletMetadataSpecificsForAddressWithDetails( + kAddr1SpecificsId, /*use_count=*/10, /*use_date=*/20); + WalletMetadataSpecifics card = + CreateWalletMetadataSpecificsForCardWithDetails( + kCard1SpecificsId, /*use_count=*/30, /*use_date=*/40); + StartSyncing({profile, card}); + + // Verify that both the processor and the local DB contain sync metadata. + ASSERT_TRUE(real_processor()->IsTrackingEntityForTest(kAddr1StorageKey)); + ASSERT_TRUE(real_processor()->IsTrackingEntityForTest(kCard1StorageKey)); + ASSERT_THAT(GetLocalSyncMetadataStorageKeys(), + UnorderedElementsAre(kAddr1StorageKey, kCard1StorageKey)); + + // Now delete the profile. + // We still need to commit the updated progress marker and sync metadata. + EXPECT_CALL(*backend(), CommitChanges()); + // Changes should _not_ happen in the local autofill database. + EXPECT_CALL(*backend(), NotifyOfMultipleAutofillChanges()).Times(0); + ReceiveTombstones({profile, card}); + + // Verify that even though the processor does not track these entities any + // more and the sync metadata is gone, the actual data entities still exist in + // the local DB. + EXPECT_FALSE(real_processor()->IsTrackingEntityForTest(kAddr1StorageKey)); + EXPECT_FALSE(real_processor()->IsTrackingEntityForTest(kCard1StorageKey)); + EXPECT_THAT(GetLocalSyncMetadataStorageKeys(), IsEmpty()); + EXPECT_THAT( + GetAllLocalDataInclRestart(), + UnorderedElementsAre(EqualsSpecifics(profile), EqualsSpecifics(card))); +} + enum RemoteChangesMode { INITIAL_SYNC_ADD, // Initial sync -> ADD changes. LATER_SYNC_ADD, // Later sync; the client receives the data for the first @@ -759,8 +1091,7 @@ class AutofillWalletMetadataSyncBridgeRemoteChangesTest void ResetBridgeWithPotentialInitialSync( const std::vector<WalletMetadataSpecifics>& remote_data) { - AutofillWalletMetadataSyncBridgeTest::ResetBridge( - /*initial_sync_done=*/GetParam() != INITIAL_SYNC_ADD); + ResetBridge(/*initial_sync_done=*/GetParam() != INITIAL_SYNC_ADD); if (GetParam() == LATER_SYNC_UPDATE) { StartSyncing(remote_data); @@ -768,11 +1099,11 @@ class AutofillWalletMetadataSyncBridgeRemoteChangesTest } void ReceivePotentiallyInitialUpdates( - const std::vector<WalletMetadataSpecifics>& remote_data = {}) { + const std::vector<WalletMetadataSpecifics>& remote_data) { if (GetParam() != LATER_SYNC_UPDATE) { StartSyncing(remote_data); } else { - AutofillWalletMetadataSyncBridgeTest::ReceiveUpdates(remote_data); + ReceiveUpdates(remote_data); } } @@ -783,10 +1114,14 @@ class AutofillWalletMetadataSyncBridgeRemoteChangesTest // No upstream communication or local DB change happens if the server sends an // empty update. TEST_P(AutofillWalletMetadataSyncBridgeRemoteChangesTest, EmptyUpdateIgnored) { + ResetBridgeWithPotentialInitialSync({}); + EXPECT_CALL(mock_processor(), Delete(_, _)).Times(0); EXPECT_CALL(mock_processor(), Put(_, _, _)).Times(0); + EXPECT_CALL(*backend(), NotifyOfMultipleAutofillChanges()).Times(0); + // We still need to commit the updated progress marker. + EXPECT_CALL(*backend(), CommitChanges()); - ResetBridgeWithPotentialInitialSync({}); ReceivePotentiallyInitialUpdates({}); EXPECT_THAT(GetAllLocalDataInclRestart(), IsEmpty()); @@ -808,6 +1143,9 @@ TEST_P(AutofillWalletMetadataSyncBridgeRemoteChangesTest, SameDataIgnored) { EXPECT_CALL(mock_processor(), Delete(_, _)).Times(0); EXPECT_CALL(mock_processor(), Put(_, _, _)).Times(0); + EXPECT_CALL(*backend(), NotifyOfMultipleAutofillChanges()).Times(0); + // We still need to commit the updated progress marker. + EXPECT_CALL(*backend(), CommitChanges()); ReceivePotentiallyInitialUpdates({profile, card}); @@ -840,6 +1178,8 @@ TEST_P(AutofillWalletMetadataSyncBridgeRemoteChangesTest, EXPECT_CALL(mock_processor(), Delete(_, _)).Times(0); EXPECT_CALL(mock_processor(), Put(_, _, _)).Times(0); + EXPECT_CALL(*backend(), CommitChanges()); + EXPECT_CALL(*backend(), NotifyOfMultipleAutofillChanges()); ReceivePotentiallyInitialUpdates( {updated_remote_profile, updated_remote_card}); @@ -875,6 +1215,9 @@ TEST_P(AutofillWalletMetadataSyncBridgeRemoteChangesTest, EXPECT_CALL(mock_processor(), Put(kAddr1StorageKey, HasSpecifics(profile), _)); EXPECT_CALL(mock_processor(), Put(kCard1StorageKey, HasSpecifics(card), _)); + EXPECT_CALL(*backend(), NotifyOfMultipleAutofillChanges()).Times(0); + // We still need to commit the updated progress marker. + EXPECT_CALL(*backend(), CommitChanges()); ReceivePotentiallyInitialUpdates( {updated_remote_profile, updated_remote_card}); @@ -918,6 +1261,8 @@ TEST_P(AutofillWalletMetadataSyncBridgeRemoteChangesTest, Put(kAddr1StorageKey, HasSpecifics(merged_profile), _)); EXPECT_CALL(mock_processor(), Put(kCard1StorageKey, HasSpecifics(merged_card), _)); + EXPECT_CALL(*backend(), CommitChanges()); + EXPECT_CALL(*backend(), NotifyOfMultipleAutofillChanges()); ReceivePotentiallyInitialUpdates( {updated_remote_profile, updated_remote_card}); @@ -962,6 +1307,8 @@ TEST_P(AutofillWalletMetadataSyncBridgeRemoteChangesTest, Put(kAddr1StorageKey, HasSpecifics(merged_profile), _)); EXPECT_CALL(mock_processor(), Put(kCard1StorageKey, HasSpecifics(merged_card), _)); + EXPECT_CALL(*backend(), CommitChanges()); + EXPECT_CALL(*backend(), NotifyOfMultipleAutofillChanges()); ReceivePotentiallyInitialUpdates( {updated_remote_profile, updated_remote_card}); @@ -995,6 +1342,8 @@ TEST_P(AutofillWalletMetadataSyncBridgeRemoteChangesTest, EXPECT_CALL(mock_processor(), Delete(_, _)).Times(0); EXPECT_CALL(mock_processor(), Put(_, _, _)).Times(0); + EXPECT_CALL(*backend(), CommitChanges()); + EXPECT_CALL(*backend(), NotifyOfMultipleAutofillChanges()); ReceivePotentiallyInitialUpdates( {updated_remote_profile, updated_remote_card}); @@ -1024,6 +1373,8 @@ TEST_P(AutofillWalletMetadataSyncBridgeRemoteChangesTest, EXPECT_CALL(mock_processor(), Delete(_, _)).Times(0); EXPECT_CALL(mock_processor(), Put(_, _, _)).Times(0); + EXPECT_CALL(*backend(), CommitChanges()); + EXPECT_CALL(*backend(), NotifyOfMultipleAutofillChanges()); ReceivePotentiallyInitialUpdates({updated_remote_card}); @@ -1051,6 +1402,9 @@ TEST_P(AutofillWalletMetadataSyncBridgeRemoteChangesTest, EXPECT_CALL(mock_processor(), Delete(_, _)).Times(0); EXPECT_CALL(mock_processor(), Put(kCard1StorageKey, HasSpecifics(card), _)); + EXPECT_CALL(*backend(), NotifyOfMultipleAutofillChanges()).Times(0); + // We still need to commit the updated progress marker. + EXPECT_CALL(*backend(), CommitChanges()); ReceivePotentiallyInitialUpdates({updated_remote_card}); @@ -1078,6 +1432,8 @@ TEST_P(AutofillWalletMetadataSyncBridgeRemoteChangesTest, EXPECT_CALL(mock_processor(), Delete(_, _)).Times(0); EXPECT_CALL(mock_processor(), Put(_, _, _)).Times(0); + EXPECT_CALL(*backend(), CommitChanges()); + EXPECT_CALL(*backend(), NotifyOfMultipleAutofillChanges()); ReceivePotentiallyInitialUpdates({updated_remote_card}); @@ -1105,6 +1461,9 @@ TEST_P(AutofillWalletMetadataSyncBridgeRemoteChangesTest, EXPECT_CALL(mock_processor(), Delete(_, _)).Times(0); EXPECT_CALL(mock_processor(), Put(kCard1StorageKey, HasSpecifics(card), _)); + EXPECT_CALL(*backend(), NotifyOfMultipleAutofillChanges()).Times(0); + // We still need to commit the updated progress marker. + EXPECT_CALL(*backend(), CommitChanges()); ReceivePotentiallyInitialUpdates({updated_remote_card}); @@ -1132,6 +1491,8 @@ TEST_P(AutofillWalletMetadataSyncBridgeRemoteChangesTest, EXPECT_CALL(mock_processor(), Delete(_, _)).Times(0); EXPECT_CALL(mock_processor(), Put(_, _, _)).Times(0); + EXPECT_CALL(*backend(), CommitChanges()); + EXPECT_CALL(*backend(), NotifyOfMultipleAutofillChanges()); ReceivePotentiallyInitialUpdates({updated_remote_card}); @@ -1159,6 +1520,9 @@ TEST_P(AutofillWalletMetadataSyncBridgeRemoteChangesTest, EXPECT_CALL(mock_processor(), Delete(_, _)).Times(0); EXPECT_CALL(mock_processor(), Put(kCard1StorageKey, HasSpecifics(card), _)); + EXPECT_CALL(*backend(), NotifyOfMultipleAutofillChanges()).Times(0); + // We still need to commit the updated progress marker. + EXPECT_CALL(*backend(), CommitChanges()); ReceivePotentiallyInitialUpdates({updated_remote_card}); @@ -1195,6 +1559,8 @@ TEST_P(AutofillWalletMetadataSyncBridgeRemoteChangesTest, EXPECT_CALL(mock_processor(), Delete(_, _)).Times(0); EXPECT_CALL(mock_processor(), Put(kCard1StorageKey, HasSpecifics(merged_card), _)); + EXPECT_CALL(*backend(), CommitChanges()); + EXPECT_CALL(*backend(), NotifyOfMultipleAutofillChanges()); ReceivePotentiallyInitialUpdates({updated_remote_card}); @@ -1231,6 +1597,8 @@ TEST_P(AutofillWalletMetadataSyncBridgeRemoteChangesTest, EXPECT_CALL(mock_processor(), Delete(_, _)).Times(0); EXPECT_CALL(mock_processor(), Put(kCard1StorageKey, HasSpecifics(merged_card), _)); + EXPECT_CALL(*backend(), CommitChanges()); + EXPECT_CALL(*backend(), NotifyOfMultipleAutofillChanges()); ReceivePotentiallyInitialUpdates({updated_remote_card}); @@ -1258,6 +1626,8 @@ TEST_P(AutofillWalletMetadataSyncBridgeRemoteChangesTest, EXPECT_CALL(mock_processor(), Delete(_, _)).Times(0); EXPECT_CALL(mock_processor(), Put(_, _, _)).Times(0); + EXPECT_CALL(*backend(), CommitChanges()); + EXPECT_CALL(*backend(), NotifyOfMultipleAutofillChanges()); ReceivePotentiallyInitialUpdates({updated_remote_profile}); @@ -1285,6 +1655,9 @@ TEST_P(AutofillWalletMetadataSyncBridgeRemoteChangesTest, EXPECT_CALL(mock_processor(), Delete(_, _)).Times(0); EXPECT_CALL(mock_processor(), Put(kAddr1StorageKey, HasSpecifics(profile), _)); + EXPECT_CALL(*backend(), NotifyOfMultipleAutofillChanges()).Times(0); + // We still need to commit the updated progress marker. + EXPECT_CALL(*backend(), CommitChanges()); ReceivePotentiallyInitialUpdates({updated_remote_profile}); @@ -1319,6 +1692,8 @@ TEST_P(AutofillWalletMetadataSyncBridgeRemoteChangesTest, EXPECT_CALL(mock_processor(), Delete(_, _)).Times(0); EXPECT_CALL(mock_processor(), Put(kAddr1StorageKey, HasSpecifics(merged_profile), _)); + EXPECT_CALL(*backend(), CommitChanges()); + EXPECT_CALL(*backend(), NotifyOfMultipleAutofillChanges()); ReceivePotentiallyInitialUpdates({updated_remote_profile}); @@ -1353,6 +1728,8 @@ TEST_P(AutofillWalletMetadataSyncBridgeRemoteChangesTest, EXPECT_CALL(mock_processor(), Delete(_, _)).Times(0); EXPECT_CALL(mock_processor(), Put(kAddr1StorageKey, HasSpecifics(merged_profile), _)); + EXPECT_CALL(*backend(), CommitChanges()); + EXPECT_CALL(*backend(), NotifyOfMultipleAutofillChanges()); ReceivePotentiallyInitialUpdates({updated_remote_profile}); diff --git a/chromium/components/autofill/core/browser/webdata/autofill_wallet_metadata_syncable_service.cc b/chromium/components/autofill/core/browser/webdata/autofill_wallet_metadata_syncable_service.cc index 7b88c1b8b36..e577d9565b9 100644 --- a/chromium/components/autofill/core/browser/webdata/autofill_wallet_metadata_syncable_service.cc +++ b/chromium/components/autofill/core/browser/webdata/autofill_wallet_metadata_syncable_service.cc @@ -7,12 +7,14 @@ #include <stddef.h> #include <utility> +#include <vector> #include "base/base64.h" #include "base/bind.h" #include "base/location.h" #include "base/logging.h" #include "base/memory/ptr_util.h" +#include "base/metrics/histogram_macros.h" #include "base/numerics/safe_conversions.h" #include "base/time/time.h" #include "components/autofill/core/browser/autofill_data_model.h" @@ -22,6 +24,7 @@ #include "components/autofill/core/browser/webdata/autofill_table.h" #include "components/autofill/core/browser/webdata/autofill_webdata_backend.h" #include "components/autofill/core/browser/webdata/autofill_webdata_service.h" +#include "components/autofill/core/common/autofill_clock.h" #include "components/autofill/core/common/autofill_util.h" #include "components/sync/model/sync_change.h" #include "components/sync/model/sync_change_processor.h" @@ -362,6 +365,12 @@ void AutofillWalletMetadataSyncableService::OnWalletDataTrackingStateChanged( } } +void AutofillWalletMetadataSyncableService::WaitUntilReadyToSync( + base::OnceClosure done) { + // Not used in the legacy directory-based architecture. + NOTREACHED(); +} + syncer::SyncMergeResult AutofillWalletMetadataSyncableService::MergeDataAndStartSyncing( syncer::ModelType type, @@ -383,6 +392,39 @@ AutofillWalletMetadataSyncableService::MergeDataAndStartSyncing( result = MergeData(initial_sync_data); } + // Record ages for individual metadata entities to UMA. + for (const syncer::SyncData& data : cache_) { + const sync_pb::WalletMetadataSpecifics& specifics = + data.GetSpecifics().wallet_metadata(); + base::Time use_date = base::Time::FromDeltaSinceWindowsEpoch( + base::TimeDelta::FromMicroseconds(specifics.use_date())); + switch (specifics.type()) { + case sync_pb::WalletMetadataSpecifics::ADDRESS: + // TODO(crbug.com/949034): Consider adding standard functions for + // recording large times in seconds/minutes. + UMA_HISTOGRAM_CUSTOM_COUNTS( + "Autofill.WalletUseDateInMinutes.Address", + /*sample=*/(AutofillClock::Now() - use_date).InMinutes(), + /*min=*/base::TimeDelta::FromMinutes(1).InMinutes(), + /*max=*/base::TimeDelta::FromDays(365).InMinutes(), + /*bucket_count=*/50); + break; + case sync_pb::WalletMetadataSpecifics::CARD: + // TODO(crbug.com/949034): Consider adding standard functions for + // recording large times in seconds/minutes. + UMA_HISTOGRAM_CUSTOM_COUNTS( + "Autofill.WalletUseDateInMinutes.Card", + /*sample=*/(AutofillClock::Now() - use_date).InMinutes(), + /*min=*/base::TimeDelta::FromMinutes(1).InMinutes(), + /*max=*/base::TimeDelta::FromDays(365).InMinutes(), + /*bucket_count=*/50); + break; + case sync_pb::WalletMetadataSpecifics::UNKNOWN: + NOTREACHED(); + break; + } + } + // Notify that sync has started. This callback does not currently take into // account whether we're actually tracking wallet data. if (web_data_backend_) @@ -507,8 +549,8 @@ syncer::SyncError AutofillWalletMetadataSyncableService::ProcessSyncChanges( status = SendChangesToSyncServer(changes_to_sync); if (is_any_local_modified) { // TODO(crbug.com/900607): Remove the need to listen to - // AutofillMultipleChanged() in the new USS implementation so that we can - // get rid of this hack. + // AutofillMultipleChangedBySync() in the new USS implementation so that we + // can get rid of this hack. DCHECK(!ignore_multiple_changed_notification_); ignore_multiple_changed_notification_ = true; web_data_backend_->NotifyOfMultipleAutofillChanges(); @@ -521,19 +563,18 @@ syncer::SyncError AutofillWalletMetadataSyncableService::ProcessSyncChanges( void AutofillWalletMetadataSyncableService::AutofillProfileChanged( const AutofillProfileChange& change) { DCHECK(thread_checker_.CalledOnValidThread()); + DCHECK(change.data_model()); if (!track_wallet_data_) { return; } - if (sync_processor_ && change.data_model() && + if (sync_processor_ && change.type() == AutofillProfileChange::UPDATE && change.data_model()->record_type() != AutofillProfile::LOCAL_PROFILE) { std::string server_id = GetServerId(*change.data_model()); auto it = FindServerIdAndTypeInCache( server_id, sync_pb::WalletMetadataSpecifics::ADDRESS, &cache_); if (it == cache_.end()) return; - // Implicitly, we filter out ADD (not in cache) and REMOVE (!data_model()). - DCHECK(change.type() == AutofillProfileChange::UPDATE); const sync_pb::WalletMetadataSpecifics& remote = it->GetSpecifics().wallet_metadata(); @@ -568,7 +609,7 @@ void AutofillWalletMetadataSyncableService::CreditCardChanged( if (it == cache_.end()) return; // Deletions and creations are treated by Wallet data sync (and propagated - // here by AutofillMultipleChanged()). We only treat updates here. + // here by AutofillMultipleChangedBySync()). We only treat updates here. if (change.type() != AutofillProfileChange::UPDATE) { return; } @@ -589,11 +630,11 @@ void AutofillWalletMetadataSyncableService::CreditCardChanged( } } -void AutofillWalletMetadataSyncableService::AutofillMultipleChanged() { +void AutofillWalletMetadataSyncableService::AutofillMultipleChangedBySync() { if (ignore_multiple_changed_notification_) { // TODO(crbug.com/900607): Remove the need to listen to - // AutofillMultipleChanged() in the new USS implementation so that we can - // get rid of this hack. + // AutofillMultipleChangedBySync() in the new USS implementation so that we + // can get rid of this hack. return; } @@ -754,8 +795,8 @@ syncer::SyncMergeResult AutofillWalletMetadataSyncableService::MergeData( result.set_error(SendChangesToSyncServer(changes_to_sync)); if (is_any_local_modified) { // TODO(crbug.com/900607): Remove the need to listen to - // AutofillMultipleChanged() in the new USS implementation so that we can - // get rid of this hack. + // AutofillMultipleChangedBySync() in the new USS implementation so that we + // can get rid of this hack. DCHECK(!ignore_multiple_changed_notification_); ignore_multiple_changed_notification_ = true; web_data_backend_->NotifyOfMultipleAutofillChanges(); diff --git a/chromium/components/autofill/core/browser/webdata/autofill_wallet_metadata_syncable_service.h b/chromium/components/autofill/core/browser/webdata/autofill_wallet_metadata_syncable_service.h index 0169b0deb07..0f963a71ebe 100644 --- a/chromium/components/autofill/core/browser/webdata/autofill_wallet_metadata_syncable_service.h +++ b/chromium/components/autofill/core/browser/webdata/autofill_wallet_metadata_syncable_service.h @@ -64,6 +64,7 @@ class AutofillWalletMetadataSyncableService } // syncer::SyncableService implementation. + void WaitUntilReadyToSync(base::OnceClosure done) override; syncer::SyncMergeResult MergeDataAndStartSyncing( syncer::ModelType type, const syncer::SyncDataList& initial_sync_data, @@ -78,7 +79,7 @@ class AutofillWalletMetadataSyncableService // AutofillWebDataServiceObserverOnDBSequence implementation. void AutofillProfileChanged(const AutofillProfileChange& change) override; void CreditCardChanged(const CreditCardChange& change) override; - void AutofillMultipleChanged() override; + void AutofillMultipleChangedBySync() override; // Creates a new AutofillWalletMetadataSyncableService and hangs it off of // |web_data_service|, which takes ownership. This method should only be diff --git a/chromium/components/autofill/core/browser/webdata/autofill_wallet_metadata_syncable_service_unittest.cc b/chromium/components/autofill/core/browser/webdata/autofill_wallet_metadata_syncable_service_unittest.cc index bd930b38b5a..39b72ca2ffe 100644 --- a/chromium/components/autofill/core/browser/webdata/autofill_wallet_metadata_syncable_service_unittest.cc +++ b/chromium/components/autofill/core/browser/webdata/autofill_wallet_metadata_syncable_service_unittest.cc @@ -597,7 +597,7 @@ TEST_F(AutofillWalletMetadataSyncableServiceTest, AddToServerOnMultiChange) { sync_pb::WalletMetadataSpecifics::CARD, kCard2Utf8, 7, 8, kAddr2Utf8)))); - local_.AutofillMultipleChanged(); + local_.AutofillMultipleChangedBySync(); } // Verify that higher values of existing metadata are sent to the sync server @@ -623,7 +623,7 @@ TEST_F(AutofillWalletMetadataSyncableServiceTest, sync_pb::WalletMetadataSpecifics::CARD, kCard1Utf8, 7, 8, kAddr2Utf8)))); - local_.AutofillMultipleChanged(); + local_.AutofillMultipleChangedBySync(); } // Verify that lower values of existing metadata are not sent to the sync server @@ -641,7 +641,7 @@ TEST_F(AutofillWalletMetadataSyncableServiceTest, EXPECT_CALL(local_, SendChangesToSyncServer(_)).Times(0); - local_.AutofillMultipleChanged(); + local_.AutofillMultipleChangedBySync(); } // Verify that erased local metadata is also erased from the sync server when @@ -663,7 +663,7 @@ TEST_F(AutofillWalletMetadataSyncableServiceTest, SyncChangeMatches(syncer::SyncChange::ACTION_DELETE, kCard1SyncTag)))); - local_.AutofillMultipleChanged(); + local_.AutofillMultipleChangedBySync(); } // Verify that erased local metadata is not erased from the sync server when @@ -682,7 +682,7 @@ TEST_F(AutofillWalletMetadataSyncableServiceTest, EXPECT_CALL(local_, SendChangesToSyncServer(_)).Times(0); - local_.AutofillMultipleChanged(); + local_.AutofillMultipleChangedBySync(); } // Verify that erased local metadata is also erased from the sync server when @@ -706,7 +706,7 @@ TEST_F(AutofillWalletMetadataSyncableServiceTest, SyncChangeMatches(syncer::SyncChange::ACTION_DELETE, kCard1SyncTag)))); - local_.AutofillMultipleChanged(); + local_.AutofillMultipleChangedBySync(); local_.OnWalletDataTrackingStateChanged(true); } @@ -1001,7 +1001,7 @@ TEST_F(AutofillWalletMetadataSyncableServiceTest, SyncChangeMatches(syncer::SyncChange::ACTION_DELETE, kCard2SyncTag)))); - local_.AutofillMultipleChanged(); + local_.AutofillMultipleChangedBySync(); } // Verify that Wallet data arriving after metadata will not send lower metadata @@ -1028,7 +1028,7 @@ TEST_F(AutofillWalletMetadataSyncableServiceTest, AutofillCardMetadataMatches(kCard1, 7, 8, kAddr2))); EXPECT_CALL(local_, SendChangesToSyncServer(_)).Times(0); - local_.AutofillMultipleChanged(); + local_.AutofillMultipleChangedBySync(); } // Verify that processing a small subset of metadata changes before any Wallet @@ -1072,7 +1072,7 @@ TEST_F(AutofillWalletMetadataSyncableServiceTest, AutofillCardMetadataMatches(kCard2, 15, 16, kAddr1))); EXPECT_CALL(local_, SendChangesToSyncServer(_)).Times(0); - local_.AutofillMultipleChanged(); + local_.AutofillMultipleChangedBySync(); } // Verify that the merge logic keeps the best data on a field by field basis. @@ -1337,8 +1337,8 @@ TEST_F(AutofillWalletMetadataSyncableServiceTest, // Make the backend broadcast back the notifications it receives ON_CALL(backend_, NotifyOfMultipleAutofillChanges()) .WillByDefault( - DoAll(Invoke(&local_, &MockService::AutofillMultipleChanged), - Invoke(&remote_, &MockService::AutofillMultipleChanged))); + DoAll(Invoke(&local_, &MockService::AutofillMultipleChangedBySync), + Invoke(&remote_, &MockService::AutofillMultipleChangedBySync))); // Get initial data from |remote_| into |local_|. local_.UpdateAddressStats(BuildAddress(kAddr1, 2, 2, true)); diff --git a/chromium/components/autofill/core/browser/webdata/autofill_wallet_sync_bridge.cc b/chromium/components/autofill/core/browser/webdata/autofill_wallet_sync_bridge.cc index a3a4494ddb1..aa51b2fbae7 100644 --- a/chromium/components/autofill/core/browser/webdata/autofill_wallet_sync_bridge.cc +++ b/chromium/components/autofill/core/browser/webdata/autofill_wallet_sync_bridge.cc @@ -198,7 +198,9 @@ base::Optional<syncer::ModelError> AutofillWalletSyncBridge::MergeSyncData( return error; } - SetSyncData(entity_data); + // We want to notify the metadata bridge about all changes so that the + // metadata bridge can track changes in the data bridge and react accordingly. + SetSyncData(entity_data, /*notify_metadata_bridge=*/true); // After the first sync, we are sure that initial sync is done. if (!initial_sync_done_) { @@ -277,7 +279,10 @@ void AutofillWalletSyncBridge::ApplyStopSyncChanges( SyncWalletDataRecordClearedEntitiesCount(count); } - SetSyncData(syncer::EntityChangeList()); + // Do not notify the metadata bridge because we do not want to upstream the + // deletions. The metadata bridge deletes its data independently when sync + // gets stopped. + SetSyncData(syncer::EntityChangeList(), /*notify_metadata_bridge=*/false); initial_sync_done_ = false; } @@ -323,7 +328,8 @@ void AutofillWalletSyncBridge::GetAllDataImpl(DataCallback callback, } void AutofillWalletSyncBridge::SetSyncData( - const syncer::EntityChangeList& entity_data) { + const syncer::EntityChangeList& entity_data, + bool notify_metadata_bridge) { bool wallet_data_changed = false; // Extract the Autofill types from the sync |entity_data|. @@ -336,10 +342,10 @@ void AutofillWalletSyncBridge::SetSyncData( bool should_log_diff; wallet_data_changed |= SetPaymentsCustomerData(std::move(customer_data), &should_log_diff); - wallet_data_changed |= - SetWalletCards(std::move(wallet_cards), should_log_diff); - wallet_data_changed |= - SetWalletAddresses(std::move(wallet_addresses), should_log_diff); + wallet_data_changed |= SetWalletCards( + std::move(wallet_cards), should_log_diff, notify_metadata_bridge); + wallet_data_changed |= SetWalletAddresses( + std::move(wallet_addresses), should_log_diff, notify_metadata_bridge); // Commit the transaction to make sure the data and the metadata with the // new progress marker is written down (especially on Android where we @@ -354,7 +360,8 @@ void AutofillWalletSyncBridge::SetSyncData( bool AutofillWalletSyncBridge::SetWalletCards( std::vector<CreditCard> wallet_cards, - bool log_diff) { + bool log_diff, + bool notify_metadata_bridge) { // Users can set billing address of the server credit card locally, but that // information does not propagate to either Chrome Sync or Google Payments // server. To preserve user's preferred billing address and most recent use @@ -386,8 +393,11 @@ bool AutofillWalletSyncBridge::SetWalletCards( } else { table->SetServerCreditCards(wallet_cards); } - for (const CreditCardChange& change : diff.changes) - web_data_backend_->NotifyOfCreditCardChanged(change); + if (notify_metadata_bridge) { + for (const CreditCardChange& change : diff.changes) { + web_data_backend_->NotifyOfCreditCardChanged(change); + } + } return true; } return false; @@ -395,7 +405,16 @@ bool AutofillWalletSyncBridge::SetWalletCards( bool AutofillWalletSyncBridge::SetWalletAddresses( std::vector<AutofillProfile> wallet_addresses, - bool log_diff) { + bool log_diff, + bool notify_metadata_bridge) { + // We do not have to CopyRelevantWalletMetadataFromDisk() because we will + // never overwrite the same entity with different data (server_id is generated + // based on content so addresses have the same server_id iff they have the + // same content). For that reason it is impossible to issue a DELETE and ADD + // for the same entity just because some of its fields got changed. As a + // result, we do not need to care to have up-to-date use stats for cards + // because we never notify on an existing one. + // In the common case, the database won't have changed. Committing an update // to the database will require at least one DB page write and will schedule // a fsync. To avoid this I/O, it should be more efficient to do a read and @@ -422,8 +441,11 @@ bool AutofillWalletSyncBridge::SetWalletAddresses( } else { table->SetServerProfiles(wallet_addresses); } - for (const AutofillProfileChange& change : diff.changes) - web_data_backend_->NotifyOfAutofillProfileChanged(change); + if (notify_metadata_bridge) { + for (const AutofillProfileChange& change : diff.changes) { + web_data_backend_->NotifyOfAutofillProfileChanged(change); + } + } return true; } return false; @@ -491,8 +513,11 @@ AutofillWalletSyncBridge::ComputeAutofillWalletDiff( std::sort(old_ptrs.begin(), old_ptrs.end(), compare); std::sort(new_ptrs.begin(), new_ptrs.end(), compare); - // Walk over both of them and count added/removed elements. AutofillWalletDiff<Item> result; + // We collect ADD changes separately to ensure proper order. + std::vector<AutofillDataModelChange<Item>> add_changes; + + // Walk over both of them and count added/removed elements. auto old_it = old_ptrs.begin(); auto new_it = new_ptrs.begin(); while (old_it != old_ptrs.end() || new_it != new_ptrs.end()) { @@ -508,19 +533,25 @@ AutofillWalletSyncBridge::ComputeAutofillWalletDiff( if (cmp < 0) { ++result.items_removed; result.changes.emplace_back(AutofillDataModelChange<Item>::REMOVE, - (*old_it)->server_id(), nullptr); + (*old_it)->server_id(), *old_it); ++old_it; } else if (cmp == 0) { ++old_it; ++new_it; } else { ++result.items_added; - result.changes.emplace_back(AutofillDataModelChange<Item>::ADD, - (*new_it)->server_id(), *new_it); + add_changes.emplace_back(AutofillDataModelChange<Item>::ADD, + (*new_it)->server_id(), *new_it); ++new_it; } } + // Append ADD changes to make sure they all come after all REMOVE changes. + // Since we CopyRelevantWalletMetadataFromDisk(), the ADD contains all current + // metadata if we happen to REMOVE and ADD the same entity. + result.changes.insert(result.changes.end(), add_changes.begin(), + add_changes.end()); + DCHECK_EQ(old_data.size() + result.items_added - result.items_removed, new_data.size()); diff --git a/chromium/components/autofill/core/browser/webdata/autofill_wallet_sync_bridge.h b/chromium/components/autofill/core/browser/webdata/autofill_wallet_sync_bridge.h index 3f91a3c6276..3fbf638ba0f 100644 --- a/chromium/components/autofill/core/browser/webdata/autofill_wallet_sync_bridge.h +++ b/chromium/components/autofill/core/browser/webdata/autofill_wallet_sync_bridge.h @@ -88,8 +88,10 @@ class AutofillWalletSyncBridge : public base::SupportsUserData::Data, void GetAllDataImpl(DataCallback callback, bool enforce_utf8); // Sets the wallet data from |entity_data| to this client and records metrics - // about added/deleted data. - void SetSyncData(const syncer::EntityChangeList& entity_data); + // about added/deleted data. If |notify_metadata_bridge|, it also notifies + // the metadata sync bridge about individual changes. + void SetSyncData(const syncer::EntityChangeList& entity_data, + bool notify_metadata_bridge); // Sets |customer_data| to this client and returns whether any change has been // applied (i.e., whether |customer_data| was different from local data) and @@ -100,14 +102,21 @@ class AutofillWalletSyncBridge : public base::SupportsUserData::Data, // Sets |wallet_cards| to this client, records metrics about added/deleted // data (if |log_diff| is true) and returns whether any change has been - // applied (i.e., whether |wallet_cards| was different from local data). - bool SetWalletCards(std::vector<CreditCard> wallet_cards, bool log_diff); + // applied (i.e., whether |wallet_cards| was different from local data). If + // |notify_metadata_bridge|, it also notifies via WebDataBackend about any + // individual entity changes. + bool SetWalletCards(std::vector<CreditCard> wallet_cards, + bool log_diff, + bool notify_metadata_bridge); // Sets |wallet_addresses| to this client, records metrics about added/deleted // data (if |log_diff| is true) and returns whether any change has been // applied (i.e., whether |wallet_addresses| was different from local data). + // If |notify_metadata_bridge|, it also notifies via WebDataBackend about any + // individual entity changes. bool SetWalletAddresses(std::vector<AutofillProfile> wallet_addresses, - bool log_diff); + bool log_diff, + bool notify_metadata_bridge); // Computes a "diff" (items added, items removed) of two vectors of items, // which should be either CreditCard or AutofillProfile. This is used for diff --git a/chromium/components/autofill/core/browser/webdata/autofill_wallet_sync_bridge_unittest.cc b/chromium/components/autofill/core/browser/webdata/autofill_wallet_sync_bridge_unittest.cc index 9549f984cc4..c595c29bfbc 100644 --- a/chromium/components/autofill/core/browser/webdata/autofill_wallet_sync_bridge_unittest.cc +++ b/chromium/components/autofill/core/browser/webdata/autofill_wallet_sync_bridge_unittest.cc @@ -57,7 +57,6 @@ using sync_pb::ModelTypeState; using syncer::DataBatch; using syncer::EntityChange; using syncer::EntityData; -using syncer::EntityDataPtr; using syncer::HasInitialSyncDone; using syncer::KeyAndData; using syncer::MockModelTypeChangeProcessor; @@ -276,7 +275,7 @@ class AutofillWalletSyncBridgeTest : public UssSwitchToggler, for (const AutofillWalletSpecifics& specifics : remote_data) { initial_updates.push_back(SpecificsToUpdateResponse(specifics)); } - real_processor_->OnUpdateReceived(state, initial_updates); + real_processor_->OnUpdateReceived(state, std::move(initial_updates)); } void ExpectAddressesDiffInHistograms(int added, int removed) { @@ -329,11 +328,12 @@ class AutofillWalletSyncBridgeTest : public UssSwitchToggler, EXPECT_EQ(addresses_count, addresses_metadata.size()); } - EntityData SpecificsToEntity(const AutofillWalletSpecifics& specifics) { - EntityData data; - *data.specifics.mutable_autofill_wallet() = specifics; - data.client_tag_hash = syncer::GenerateSyncableHash( - syncer::AUTOFILL_WALLET_DATA, bridge()->GetClientTag(data)); + std::unique_ptr<EntityData> SpecificsToEntity( + const AutofillWalletSpecifics& specifics) { + auto data = std::make_unique<EntityData>(); + *data->specifics.mutable_autofill_wallet() = specifics; + data->client_tag_hash = syncer::GenerateSyncableHash( + syncer::AUTOFILL_WALLET_DATA, bridge()->GetClientTag(*data)); return data; } @@ -350,10 +350,10 @@ class AutofillWalletSyncBridgeTest : public UssSwitchToggler, return data; } - syncer::UpdateResponseData SpecificsToUpdateResponse( + std::unique_ptr<syncer::UpdateResponseData> SpecificsToUpdateResponse( const AutofillWalletSpecifics& specifics) { - syncer::UpdateResponseData data; - data.entity = SpecificsToEntity(specifics).PassToPtr(); + auto data = std::make_unique<syncer::UpdateResponseData>(); + data->entity = SpecificsToEntity(specifics); return data; } @@ -392,14 +392,14 @@ class AutofillWalletSyncBridgeTest : public UssSwitchToggler, TEST_P(AutofillWalletSyncBridgeTest, GetClientTagForAddress) { AutofillWalletSpecifics specifics = CreateAutofillWalletSpecificsForAddress(kAddr1SpecificsId); - EXPECT_EQ(bridge()->GetClientTag(SpecificsToEntity(specifics)), + EXPECT_EQ(bridge()->GetClientTag(*SpecificsToEntity(specifics)), kAddr1SyncTag); } TEST_P(AutofillWalletSyncBridgeTest, GetClientTagForCard) { AutofillWalletSpecifics specifics = CreateAutofillWalletSpecificsForCard(kCard1SpecificsId); - EXPECT_EQ(bridge()->GetClientTag(SpecificsToEntity(specifics)), + EXPECT_EQ(bridge()->GetClientTag(*SpecificsToEntity(specifics)), kCard1SyncTag); } @@ -407,7 +407,7 @@ TEST_P(AutofillWalletSyncBridgeTest, GetClientTagForCustomerData) { AutofillWalletSpecifics specifics = CreateAutofillWalletSpecificsForPaymentsCustomerData( kCustomerDataSyncTag); - EXPECT_EQ(bridge()->GetClientTag(SpecificsToEntity(specifics)), + EXPECT_EQ(bridge()->GetClientTag(*SpecificsToEntity(specifics)), kCustomerDataSyncTag); } @@ -415,21 +415,21 @@ TEST_P(AutofillWalletSyncBridgeTest, GetClientTagForCustomerData) { TEST_P(AutofillWalletSyncBridgeTest, GetStorageKeyForAddress) { AutofillWalletSpecifics specifics1 = CreateAutofillWalletSpecificsForAddress(kAddr1SpecificsId); - EXPECT_EQ(bridge()->GetStorageKey(SpecificsToEntity(specifics1)), + EXPECT_EQ(bridge()->GetStorageKey(*SpecificsToEntity(specifics1)), kAddr1SpecificsId); } TEST_P(AutofillWalletSyncBridgeTest, GetStorageKeyForCard) { AutofillWalletSpecifics specifics2 = CreateAutofillWalletSpecificsForCard(kCard1SpecificsId); - EXPECT_EQ(bridge()->GetStorageKey(SpecificsToEntity(specifics2)), + EXPECT_EQ(bridge()->GetStorageKey(*SpecificsToEntity(specifics2)), kCard1SpecificsId); } TEST_P(AutofillWalletSyncBridgeTest, GetStorageKeyForCustomerData) { AutofillWalletSpecifics specifics3 = CreateAutofillWalletSpecificsForPaymentsCustomerData(kCustomerDataId); - EXPECT_EQ(bridge()->GetStorageKey(SpecificsToEntity(specifics3)), + EXPECT_EQ(bridge()->GetStorageKey(*SpecificsToEntity(specifics3)), kCustomerDataId); } @@ -826,10 +826,9 @@ TEST_P(AutofillWalletSyncBridgeTest, ApplyStopSyncChanges_ClearAllData) { EXPECT_CALL(*backend(), CommitChanges()); EXPECT_CALL(*backend(), NotifyOfMultipleAutofillChanges()); - EXPECT_CALL(*backend(), NotifyOfAutofillProfileChanged( - RemoveChange(local_profile.server_id()))); - EXPECT_CALL(*backend(), - NotifyOfCreditCardChanged(RemoveChange(local_card.server_id()))); + EXPECT_CALL(*backend(), NotifyOfAutofillProfileChanged(_)).Times(0); + EXPECT_CALL(*backend(), NotifyOfCreditCardChanged(_)).Times(0); + // Passing in a non-null metadata change list indicates to the bridge that // sync is stopping because it was disabled. bridge()->ApplyStopSyncChanges( diff --git a/chromium/components/autofill/core/browser/webdata/autofill_wallet_syncable_service.cc b/chromium/components/autofill/core/browser/webdata/autofill_wallet_syncable_service.cc index 3cc21a09948..86f17c89f42 100644 --- a/chromium/components/autofill/core/browser/webdata/autofill_wallet_syncable_service.cc +++ b/chromium/components/autofill/core/browser/webdata/autofill_wallet_syncable_service.cc @@ -206,6 +206,12 @@ AutofillWalletSyncableService::AutofillWalletSyncableService( AutofillWalletSyncableService::~AutofillWalletSyncableService() {} +void AutofillWalletSyncableService::WaitUntilReadyToSync( + base::OnceClosure done) { + // Not used in the legacy directory-based architecture. + NOTREACHED(); +} + syncer::SyncMergeResult AutofillWalletSyncableService::MergeDataAndStartSyncing( syncer::ModelType type, const syncer::SyncDataList& initial_sync_data, diff --git a/chromium/components/autofill/core/browser/webdata/autofill_wallet_syncable_service.h b/chromium/components/autofill/core/browser/webdata/autofill_wallet_syncable_service.h index e8c130d73ca..9d3ff000790 100644 --- a/chromium/components/autofill/core/browser/webdata/autofill_wallet_syncable_service.h +++ b/chromium/components/autofill/core/browser/webdata/autofill_wallet_syncable_service.h @@ -35,6 +35,7 @@ class AutofillWalletSyncableService ~AutofillWalletSyncableService() override; // syncer::SyncableService implementation. + void WaitUntilReadyToSync(base::OnceClosure done) override; syncer::SyncMergeResult MergeDataAndStartSyncing( syncer::ModelType type, const syncer::SyncDataList& initial_sync_data, diff --git a/chromium/components/autofill/core/browser/webdata/autofill_webdata.h b/chromium/components/autofill/core/browser/webdata/autofill_webdata.h deleted file mode 100644 index 3ae94e14cae..00000000000 --- a/chromium/components/autofill/core/browser/webdata/autofill_webdata.h +++ /dev/null @@ -1,144 +0,0 @@ -// Copyright 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef COMPONENTS_AUTOFILL_CORE_BROWSER_WEBDATA_AUTOFILL_WEBDATA_H_ -#define COMPONENTS_AUTOFILL_CORE_BROWSER_WEBDATA_AUTOFILL_WEBDATA_H_ - -#include <string> -#include <vector> - -#include "base/strings/string16.h" -#include "components/webdata/common/web_data_service_base.h" - -namespace base { - -class Time; - -} // namespace base - -class WebDataServiceConsumer; - -namespace autofill { - -class AutofillEntry; -class AutofillProfile; -class CreditCard; -struct FormFieldData; - -// Pure virtual interface for retrieving Autofill data. API users -// should use AutofillWebDataService. -class AutofillWebData { - public: - virtual ~AutofillWebData() {} - - // Schedules a task to add form fields to the web database. - virtual void AddFormFields( - const std::vector<FormFieldData>& fields) = 0; - - // Initiates the request for a vector of values which have been entered in - // form input fields named |name|. The method OnWebDataServiceRequestDone of - // |consumer| gets called back when the request is finished, with the vector - // included in the argument |result|. - virtual WebDataServiceBase::Handle GetFormValuesForElementName( - const base::string16& name, - const base::string16& prefix, - int limit, - WebDataServiceConsumer* consumer) = 0; - - // Removes form elements recorded for Autocomplete from the database. - virtual void RemoveFormElementsAddedBetween( - const base::Time& delete_begin, const base::Time& delete_end) = 0; - - virtual void RemoveFormValueForElementName(const base::string16& name, - const base::string16& value) = 0; - - // Schedules a task to add an Autofill profile to the web database. - virtual void AddAutofillProfile(const AutofillProfile& profile) = 0; - - // Schedules a task to update an Autofill profile in the web database. - virtual void UpdateAutofillProfile(const AutofillProfile& profile) = 0; - - // Schedules a task to remove an Autofill profile from the web database. - // |guid| is the identifier of the profile to remove. - virtual void RemoveAutofillProfile(const std::string& guid) = 0; - - // Initiates the request for local/server 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. - virtual WebDataServiceBase::Handle GetAutofillProfiles( - WebDataServiceConsumer* consumer) = 0; - virtual WebDataServiceBase::Handle GetServerProfiles( - WebDataServiceConsumer* consumer) = 0; - - // Schedules a task to count the number of unique autofill values contained - // in the time interval [|begin|, |end|). |begin| and |end| can be null - // to indicate no time limitation. - virtual WebDataServiceBase::Handle GetCountOfValuesContainedBetween( - const base::Time& begin, - const base::Time& end, - WebDataServiceConsumer* consumer) = 0; - - // Schedules a task to update autofill entries in the web database. - virtual void UpdateAutofillEntries( - const std::vector<AutofillEntry>& autofill_entries) = 0; - - // Schedules a task to add credit card to the web database. - virtual void AddCreditCard(const CreditCard& credit_card) = 0; - - // Schedules a task to update credit card in the web database. - virtual void UpdateCreditCard(const CreditCard& credit_card) = 0; - - // Schedules a task to remove a credit card from the web database. - // |guid| is identifier of the credit card to remove. - virtual void RemoveCreditCard(const std::string& guid) = 0; - - // Schedules a task to add a full server credit card to the web database. - virtual void AddFullServerCreditCard(const CreditCard& credit_card) = 0; - - // Initiates the request for local/server 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. - virtual WebDataServiceBase::Handle GetCreditCards( - WebDataServiceConsumer* consumer) = 0; - virtual WebDataServiceBase::Handle GetServerCreditCards( - WebDataServiceConsumer* consumer) = 0; - - // Toggles the record for a server credit card between masked (only last 4 - // digits) and full (all digits). - virtual void UnmaskServerCreditCard(const CreditCard& credit_card, - const base::string16& full_number) = 0; - virtual void MaskServerCreditCard(const std::string& id) = 0; - - // Initiates the request for Payments customer data. The method - // OnWebDataServiceRequestDone of |consumer| gets called when the request is - // finished, with the customer data included in the argument |result|. The - // consumer owns the data. - virtual WebDataServiceBase::Handle GetPaymentsCustomerData( - WebDataServiceConsumer* consumer) = 0; - - // Updates the metadata for a server card (masked or not). - virtual void UpdateServerCardMetadata(const CreditCard& credit_card) = 0; - - // Updates the metadata for a server address. - virtual void UpdateServerAddressMetadata(const AutofillProfile& profile) = 0; - - // Removes Autofill records from the database. - virtual void RemoveAutofillDataModifiedBetween( - const base::Time& delete_begin, const base::Time& delete_end) = 0; - - // Removes origin URLs associated with Autofill profiles and credit cards from - // the database. - virtual void RemoveOriginURLsModifiedBetween( - const base::Time& delete_begin, const base::Time& delete_end) = 0; - - // Removes the orphan rows in the autofill_profile_names, - // autofill_profile_emails and autofill_profile_phones tables. - virtual void RemoveOrphanAutofillTableRows() = 0; -}; - -} // namespace autofill - -#endif // COMPONENTS_AUTOFILL_CORE_BROWSER_WEBDATA_AUTOFILL_WEBDATA_H_ diff --git a/chromium/components/autofill/core/browser/webdata/autofill_webdata_backend.h b/chromium/components/autofill/core/browser/webdata/autofill_webdata_backend.h index aa37b89bc4d..57be6d9e2d1 100644 --- a/chromium/components/autofill/core/browser/webdata/autofill_webdata_backend.h +++ b/chromium/components/autofill/core/browser/webdata/autofill_webdata_backend.h @@ -59,6 +59,12 @@ class AutofillWebDataBackend { // sequence notifications are asynchronous. virtual void NotifyOfMultipleAutofillChanges() = 0; + // Notifies listeners on the UI sequence that conversion of server profiles + // into local profiles is completed. + // NOTE: This method is intended to be called from the DB sequence. The UI + // sequence notifications are asynchronous. + virtual void NotifyOfAddressConversionCompleted() = 0; + // Notifies listeners on the UI sequence that sync has started for // |model_type|. // NOTE: This method is intended to be called from the DB sequence. The UI diff --git a/chromium/components/autofill/core/browser/webdata/autofill_webdata_backend_impl.cc b/chromium/components/autofill/core/browser/webdata/autofill_webdata_backend_impl.cc index d7cb6af4768..3d1c7083aac 100644 --- a/chromium/components/autofill/core/browser/webdata/autofill_webdata_backend_impl.cc +++ b/chromium/components/autofill/core/browser/webdata/autofill_webdata_backend_impl.cc @@ -15,6 +15,7 @@ #include "components/autofill/core/browser/webdata/autofill_change.h" #include "components/autofill/core/browser/webdata/autofill_entry.h" #include "components/autofill/core/browser/webdata/autofill_table.h" +#include "components/autofill/core/browser/webdata/autofill_webdata_backend_util.h" #include "components/autofill/core/browser/webdata/autofill_webdata_service.h" #include "components/autofill/core/browser/webdata/autofill_webdata_service_observer.h" #include "components/autofill/core/common/form_field_data.h" @@ -36,12 +37,15 @@ AutofillWebDataBackendImpl::AutofillWebDataBackendImpl( scoped_refptr<base::SingleThreadTaskRunner> ui_task_runner, scoped_refptr<base::SingleThreadTaskRunner> db_task_runner, const base::Closure& on_changed_callback, + const base::Closure& on_address_conversion_completed_callback, const base::Callback<void(syncer::ModelType)>& on_sync_started_callback) : base::RefCountedDeleteOnSequence<AutofillWebDataBackendImpl>( std::move(db_task_runner)), ui_task_runner_(ui_task_runner), web_database_backend_(web_database_backend), on_changed_callback_(on_changed_callback), + on_address_conversion_completed_callback_( + on_address_conversion_completed_callback), on_sync_started_callback_(on_sync_started_callback) {} void AutofillWebDataBackendImpl::AddObserver( @@ -121,12 +125,20 @@ void AutofillWebDataBackendImpl::NotifyOfMultipleAutofillChanges() { // DB sequence notification. for (auto& db_observer : db_observer_list_) - db_observer.AutofillMultipleChanged(); + db_observer.AutofillMultipleChangedBySync(); // UI sequence notification. ui_task_runner_->PostTask(FROM_HERE, on_changed_callback_); } +void AutofillWebDataBackendImpl::NotifyOfAddressConversionCompleted() { + DCHECK(owning_task_runner()->RunsTasksInCurrentSequence()); + + // UI sequence notification. + ui_task_runner_->PostTask(FROM_HERE, + on_address_conversion_completed_callback_); +} + void AutofillWebDataBackendImpl::NotifyThatSyncHasStarted( syncer::ModelType model_type) { DCHECK(owning_task_runner()->RunsTasksInCurrentSequence()); @@ -294,15 +306,17 @@ WebDatabase::State AutofillWebDataBackendImpl::RemoveAutofillProfile( } // Send GUID-based notification. - AutofillProfileChange change(AutofillProfileChange::REMOVE, guid, nullptr); + AutofillProfileChange change(AutofillProfileChange::REMOVE, guid, + profile.get()); for (auto& db_observer : db_observer_list_) db_observer.AutofillProfileChanged(change); if (!on_autofill_profile_changed_cb_.is_null()) { ui_task_runner_->PostTask( - FROM_HERE, base::BindOnce(on_autofill_profile_changed_cb_, - AutofillProfileDeepChange( - AutofillProfileChange::REMOVE, guid))); + FROM_HERE, + base::BindOnce(on_autofill_profile_changed_cb_, + AutofillProfileDeepChange(AutofillProfileChange::REMOVE, + *profile.get()))); } return WebDatabase::COMMIT_NEEDED; @@ -328,6 +342,16 @@ std::unique_ptr<WDTypedResult> AutofillWebDataBackendImpl::GetServerProfiles( AUTOFILL_PROFILES_RESULT, std::move(profiles))); } +WebDatabase::State +AutofillWebDataBackendImpl::ConvertWalletAddressesAndUpdateWalletCards( + const std::string& app_locale, + const std::string& primary_account_email, + WebDatabase* db) { + DCHECK(owning_task_runner()->RunsTasksInCurrentSequence()); + return util::ConvertWalletAddressesAndUpdateWalletCards( + app_locale, primary_account_email, this, db); +} + std::unique_ptr<WDTypedResult> AutofillWebDataBackendImpl::GetCountOfValuesContainedBetween( const base::Time& begin, @@ -391,6 +415,13 @@ WebDatabase::State AutofillWebDataBackendImpl::UpdateCreditCard( WebDatabase::State AutofillWebDataBackendImpl::RemoveCreditCard( const std::string& guid, WebDatabase* db) { DCHECK(owning_task_runner()->RunsTasksInCurrentSequence()); + std::unique_ptr<CreditCard> card = + AutofillTable::FromWebDatabase(db)->GetCreditCard(guid); + if (!card) { + NOTREACHED(); + return WebDatabase::COMMIT_NOT_NEEDED; + } + if (!AutofillTable::FromWebDatabase(db)->RemoveCreditCard(guid)) { NOTREACHED(); return WebDatabase::COMMIT_NOT_NEEDED; @@ -398,7 +429,7 @@ WebDatabase::State AutofillWebDataBackendImpl::RemoveCreditCard( for (auto& db_observer : db_observer_list_) { db_observer.CreditCardChanged( - CreditCardChange(CreditCardChange::REMOVE, guid, nullptr)); + CreditCardChange(CreditCardChange::REMOVE, guid, card.get())); } return WebDatabase::COMMIT_NEEDED; } @@ -530,23 +561,20 @@ WebDatabase::State const base::Time& delete_end, WebDatabase* db) { DCHECK(owning_task_runner()->RunsTasksInCurrentSequence()); - std::vector<std::string> profile_guids; - std::vector<std::string> credit_card_guids; + std::vector<std::unique_ptr<AutofillProfile>> profiles; + std::vector<std::unique_ptr<CreditCard>> credit_cards; if (AutofillTable::FromWebDatabase(db)->RemoveAutofillDataModifiedBetween( - delete_begin, - delete_end, - &profile_guids, - &credit_card_guids)) { - for (const std::string& guid : profile_guids) { + delete_begin, delete_end, &profiles, &credit_cards)) { + for (const std::unique_ptr<AutofillProfile>& profile : profiles) { for (auto& db_observer : db_observer_list_) { db_observer.AutofillProfileChanged(AutofillProfileChange( - AutofillProfileChange::REMOVE, guid, nullptr)); + AutofillProfileChange::REMOVE, profile->guid(), profile.get())); } } - for (const std::string& guid : credit_card_guids) { + for (const std::unique_ptr<CreditCard>& credit_card : credit_cards) { for (auto& db_observer : db_observer_list_) { - db_observer.CreditCardChanged( - CreditCardChange(CreditCardChange::REMOVE, guid, nullptr)); + db_observer.CreditCardChanged(CreditCardChange( + CreditCardChange::REMOVE, credit_card->guid(), credit_card.get())); } } // Note: It is the caller's responsibility to post notifications for any diff --git a/chromium/components/autofill/core/browser/webdata/autofill_webdata_backend_impl.h b/chromium/components/autofill/core/browser/webdata/autofill_webdata_backend_impl.h index b508bda93b1..ebd32175352 100644 --- a/chromium/components/autofill/core/browser/webdata/autofill_webdata_backend_impl.h +++ b/chromium/components/autofill/core/browser/webdata/autofill_webdata_backend_impl.h @@ -12,7 +12,6 @@ #include "base/memory/ref_counted_delete_on_sequence.h" #include "base/observer_list.h" #include "base/supports_user_data.h" -#include "components/autofill/core/browser/webdata/autofill_webdata.h" #include "components/autofill/core/browser/webdata/autofill_webdata_backend.h" #include "components/autofill/core/common/form_field_data.h" #include "components/webdata/common/web_data_results.h" @@ -53,6 +52,7 @@ class AutofillWebDataBackendImpl scoped_refptr<base::SingleThreadTaskRunner> ui_task_runner, scoped_refptr<base::SingleThreadTaskRunner> db_task_runner, const base::Closure& on_changed_callback, + const base::Closure& on_address_conversion_completed_callback, const base::Callback<void(syncer::ModelType)>& on_sync_started_callback); void SetAutofillProfileChangedCallback( @@ -69,6 +69,7 @@ class AutofillWebDataBackendImpl const AutofillProfileChange& change) override; void NotifyOfCreditCardChanged(const CreditCardChange& change) override; void NotifyOfMultipleAutofillChanges() override; + void NotifyOfAddressConversionCompleted() override; void NotifyThatSyncHasStarted(syncer::ModelType model_type) override; void CommitChanges() override; @@ -134,6 +135,15 @@ class AutofillWebDataBackendImpl std::unique_ptr<WDTypedResult> GetAutofillProfiles(WebDatabase* db); std::unique_ptr<WDTypedResult> GetServerProfiles(WebDatabase* db); + // Converts server profiles to local profiles, comparing profiles using + // |app_locale| and filling in |primary_account_email| into newly converted + // profiles. The task only converts profiles that have not been converted + // before. + WebDatabase::State ConvertWalletAddressesAndUpdateWalletCards( + const std::string& app_locale, + const std::string& primary_account_email, + WebDatabase* db); + // Returns the number of values such that all for autofill entries with that // value, the interval between creation date and last usage is entirely // contained between [|begin|, |end|). @@ -246,6 +256,7 @@ class AutofillWebDataBackendImpl scoped_refptr<WebDatabaseBackend> web_database_backend_; base::Closure on_changed_callback_; + base::Closure on_address_conversion_completed_callback_; base::Callback<void(syncer::ModelType)> on_sync_started_callback_; base::RepeatingCallback<void(const AutofillProfileDeepChange&)> diff --git a/chromium/components/autofill/core/browser/webdata/autofill_webdata_backend_util.cc b/chromium/components/autofill/core/browser/webdata/autofill_webdata_backend_util.cc new file mode 100644 index 00000000000..0af8ed2b2cc --- /dev/null +++ b/chromium/components/autofill/core/browser/webdata/autofill_webdata_backend_util.cc @@ -0,0 +1,264 @@ +// Copyright 2019 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "components/autofill/core/browser/webdata/autofill_webdata_backend_util.h" + +#include "base/bind.h" +#include "base/location.h" +#include "base/logging.h" +#include "base/single_thread_task_runner.h" +#include "base/strings/utf_string_conversions.h" +#include "components/autofill/core/browser/autofill_country.h" +#include "components/autofill/core/browser/autofill_metrics.h" +#include "components/autofill/core/browser/autofill_profile.h" +#include "components/autofill/core/browser/autofill_profile_comparator.h" +#include "components/autofill/core/browser/credit_card.h" +#include "components/autofill/core/browser/payments/payments_customer_data.h" +#include "components/autofill/core/browser/webdata/autofill_change.h" +#include "components/autofill/core/browser/webdata/autofill_entry.h" +#include "components/autofill/core/browser/webdata/autofill_table.h" +#include "components/autofill/core/browser/webdata/autofill_webdata_backend_impl.h" +#include "components/autofill/core/common/autofill_clock.h" + +namespace autofill { + +namespace util { + +namespace { + +// The length of a local profile GUID. +const int LOCAL_GUID_LENGTH = 36; + +// TODO(crbug.com/687975): Reuse MergeProfile in this function. +// static +std::string MergeServerAddressesIntoProfiles( + const AutofillProfile& server_address, + std::vector<std::unique_ptr<AutofillProfile>>* existing_profiles, + const std::string& app_locale, + const std::string& primary_account_email, + AutofillWebDataBackendImpl* backend, + WebDatabase* db) { + // If there is already a local profile that is very similar, merge in any + // missing values. Only merge with the first match. + AutofillProfileComparator comparator(app_locale); + for (auto& local_profile : *existing_profiles) { + if (comparator.AreMergeable(server_address, *local_profile) && + local_profile->SaveAdditionalInfo(server_address, app_locale)) { + local_profile->set_modification_date(AutofillClock::Now()); + backend->UpdateAutofillProfile(*local_profile, db); + AutofillMetrics::LogWalletAddressConversionType( + AutofillMetrics::CONVERTED_ADDRESS_MERGED); + return local_profile->guid(); + } + } + + // If the server address was not merged with a local profile, add it to the + // list. + existing_profiles->push_back( + std::make_unique<AutofillProfile>(server_address)); + // Set the profile as being local. + existing_profiles->back()->set_record_type(AutofillProfile::LOCAL_PROFILE); + existing_profiles->back()->set_modification_date(AutofillClock::Now()); + + // Wallet addresses don't have an email address, use the one from the + // currently signed-in account. + base::string16 email = base::UTF8ToUTF16(primary_account_email); + if (!email.empty()) + existing_profiles->back()->SetRawInfo(EMAIL_ADDRESS, email); + + backend->AddAutofillProfile(*existing_profiles->back(), db); + AutofillMetrics::LogWalletAddressConversionType( + AutofillMetrics::CONVERTED_ADDRESS_ADDED); + + return existing_profiles->back()->guid(); +} + +bool ConvertWalletAddressesToLocalProfiles( + const std::string& app_locale, + const std::string& primary_account_email, + const std::vector<std::unique_ptr<AutofillProfile>>& server_profiles, + std::vector<std::unique_ptr<AutofillProfile>>* local_profiles, + std::unordered_map<std::string, AutofillProfile*>* server_id_profiles_map, + std::unordered_map<std::string, std::string>* guids_merge_map, + AutofillWebDataBackendImpl* backend, + WebDatabase* db) { + bool has_converted_addresses = false; + for (const std::unique_ptr<AutofillProfile>& wallet_address : + server_profiles) { + // Add the profile to the map. + server_id_profiles_map->emplace(wallet_address->server_id(), + wallet_address.get()); + + // If the address has not been converted yet, convert it. + if (!wallet_address->has_converted()) { + // Try to merge the server address into a similar local profile, or create + // a new local profile if no similar profile is found. + std::string address_guid = MergeServerAddressesIntoProfiles( + *wallet_address, local_profiles, app_locale, primary_account_email, + backend, db); + + // Update the map to transfer the billing address relationship from the + // server address to the converted/merged local profile. + guids_merge_map->emplace(wallet_address->server_id(), address_guid); + + // Update the wallet addresses metadata to record the conversion. + AutofillProfile updated_address = *wallet_address; + updated_address.set_has_converted(true); + backend->UpdateServerAddressMetadata(updated_address, db); + + has_converted_addresses = true; + } + } + + return has_converted_addresses; +} + +bool UpdateWalletCardsAlreadyConvertedBillingAddresses( + const std::vector<std::unique_ptr<AutofillProfile>>& local_profiles, + const std::vector<std::unique_ptr<CreditCard>>& server_cards, + const std::unordered_map<std::string, AutofillProfile*>& + server_id_profiles_map, + const std::string& app_locale, + std::unordered_map<std::string, std::string>* guids_merge_map) { + // Look for server cards that still refer to server addresses but for which + // there is no mapping. This can happen if it's a new card for which the + // billing address has already been converted. This should be a no-op for most + // situations. Otherwise, it should affect only one Wallet card, sinces users + // do not add a lot of credit cards. + AutofillProfileComparator comparator(app_locale); + bool should_update_cards = false; + for (const std::unique_ptr<CreditCard>& wallet_card : server_cards) { + std::string billing_address_id = wallet_card->billing_address_id(); + + // If billing address refers to a server id and that id is not a key in the + // |guids_merge_map|, it means that the card is new but the address was + // already converted. Look for the matching converted profile. + if (!billing_address_id.empty() && + billing_address_id.length() != LOCAL_GUID_LENGTH && + guids_merge_map->find(billing_address_id) == guids_merge_map->end()) { + // Get the profile. + auto it = server_id_profiles_map.find(billing_address_id); + if (it != server_id_profiles_map.end()) { + const AutofillProfile* billing_address = it->second; + + // Look for a matching local profile (DO NOT MERGE). + for (const auto& local_profile : local_profiles) { + if (comparator.AreMergeable(*billing_address, *local_profile)) { + // The Wallet address matches this local profile. Add this to the + // merge mapping. + guids_merge_map->emplace(billing_address_id, local_profile->guid()); + should_update_cards = true; + break; + } + } + } + } + } + + return should_update_cards; +} + +// TODO(crbug.com/911133): This function implements the same logic as the +// function with the same name in PDM. Move ApplyDedupingRoutine to the backend +// thread as well and thus get rid of the code duplicity. +void UpdateCardsBillingAddressReference( + const std::unordered_map<std::string, std::string>& guids_merge_map, + std::vector<std::unique_ptr<CreditCard>> credit_cards, + AutofillWebDataBackendImpl* backend, + WebDatabase* db) { + /* Here is an example of what the graph might look like. + + A -> B + \ + -> E + / + C -> D + */ + + for (std::unique_ptr<CreditCard>& credit_card : credit_cards) { + // If the credit card is not associated with a billing address, skip it. + if (credit_card->billing_address_id().empty()) + break; + + // If the billing address profile associated with the card has been merged, + // replace it by the id of the profile in which it was merged. Repeat the + // process until the billing address has not been merged into another one. + bool was_modified = false; + auto it = guids_merge_map.find(credit_card->billing_address_id()); + while (it != guids_merge_map.end()) { + was_modified = true; + credit_card->set_billing_address_id(it->second); + it = guids_merge_map.find(credit_card->billing_address_id()); + } + + if (was_modified) { + if (credit_card->record_type() == CreditCard::LOCAL_CARD) { + backend->UpdateCreditCard(*credit_card, db); + } else { + backend->UpdateServerCardMetadata(*credit_card, db); + } + } + } +} + +} // namespace + +WebDatabase::State ConvertWalletAddressesAndUpdateWalletCards( + const std::string& app_locale, + const std::string& primary_account_email, + AutofillWebDataBackendImpl* backend, + WebDatabase* db) { + AutofillTable* table = AutofillTable::FromWebDatabase(db); + + // Get a copy of local profiles. + std::vector<std::unique_ptr<AutofillProfile>> local_profiles; + std::vector<std::unique_ptr<AutofillProfile>> server_profiles; + std::vector<std::unique_ptr<CreditCard>> server_cards; + if (!table->GetAutofillProfiles(&local_profiles) || + !table->GetServerProfiles(&server_profiles) || + !table->GetServerCreditCards(&server_cards)) { + return WebDatabase::COMMIT_NOT_NEEDED; + } + + // Since we are already iterating on all the server profiles to convert Wallet + // addresses and we will need to access them by guid later to update the + // Wallet cards, create a map here. + std::unordered_map<std::string, AutofillProfile*> server_id_profiles_map; + + // Create the map used to update credit card's billing addresses after the + // conversion/merge. + std::unordered_map<std::string, std::string> guids_merge_map; + + bool has_converted_addresses = ConvertWalletAddressesToLocalProfiles( + app_locale, primary_account_email, server_profiles, &local_profiles, + &server_id_profiles_map, &guids_merge_map, backend, db); + bool should_update_cards = UpdateWalletCardsAlreadyConvertedBillingAddresses( + local_profiles, server_cards, server_id_profiles_map, app_locale, + &guids_merge_map); + + if (should_update_cards || has_converted_addresses) { + std::vector<std::unique_ptr<CreditCard>> all_cards; + if (!table->GetCreditCards(&all_cards)) { + return WebDatabase::COMMIT_NEEDED; + } + for (std::unique_ptr<CreditCard>& server_card : server_cards) { + all_cards.push_back(std::move(server_card)); + } + + // Update the credit cards billing address relationship. + UpdateCardsBillingAddressReference(guids_merge_map, std::move(all_cards), + backend, db); + // Notify the PDM about the conversion being completed. + backend->NotifyOfAddressConversionCompleted(); + return WebDatabase::COMMIT_NEEDED; + } + + // We need to notify the PDM even if we do not change any data (it relies on + // it to refresh its local view). + backend->NotifyOfAddressConversionCompleted(); + return WebDatabase::COMMIT_NOT_NEEDED; +} + +} // namespace util +} // namespace autofill diff --git a/chromium/components/autofill/core/browser/webdata/autofill_webdata_backend_util.h b/chromium/components/autofill/core/browser/webdata/autofill_webdata_backend_util.h new file mode 100644 index 00000000000..7c0d07e637d --- /dev/null +++ b/chromium/components/autofill/core/browser/webdata/autofill_webdata_backend_util.h @@ -0,0 +1,27 @@ +// Copyright 2019 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef COMPONENTS_AUTOFILL_CORE_BROWSER_WEBDATA_AUTOFILL_WEBDATA_BACKEND_UTIL_H_ +#define COMPONENTS_AUTOFILL_CORE_BROWSER_WEBDATA_AUTOFILL_WEBDATA_BACKEND_UTIL_H_ + +#include "components/webdata/common/web_database.h" + +namespace autofill { + +class AutofillWebDataBackendImpl; + +namespace util { + +// Converts server profiles to local profiles. The task only converts profiles +// that have not been converted before. +WebDatabase::State ConvertWalletAddressesAndUpdateWalletCards( + const std::string& app_locale, + const std::string& primary_account_email, + AutofillWebDataBackendImpl* backend, + WebDatabase* db); + +} // namespace util +} // namespace autofill + +#endif // COMPONENTS_AUTOFILL_CORE_BROWSER_WEBDATA_AUTOFILL_WEBDATA_BACKEND_UTIL_H_ diff --git a/chromium/components/autofill/core/browser/webdata/autofill_webdata_service.cc b/chromium/components/autofill/core/browser/webdata/autofill_webdata_service.cc index ebb033556c9..007d48f6809 100644 --- a/chromium/components/autofill/core/browser/webdata/autofill_webdata_service.cc +++ b/chromium/components/autofill/core/browser/webdata/autofill_webdata_service.cc @@ -39,12 +39,17 @@ AutofillWebDataService::AutofillWebDataService( base::Closure on_changed_callback = Bind(&AutofillWebDataService::NotifyAutofillMultipleChangedOnUISequence, weak_ptr_factory_.GetWeakPtr()); + base::Closure on_address_conversion_completed_callback = + Bind(&AutofillWebDataService:: + NotifyAutofillAddressConversionCompletedOnUISequence, + weak_ptr_factory_.GetWeakPtr()); base::Callback<void(syncer::ModelType)> on_sync_started_callback = Bind(&AutofillWebDataService::NotifySyncStartedOnUISequence, weak_ptr_factory_.GetWeakPtr()); autofill_backend_ = new AutofillWebDataBackendImpl( wdbs_->GetBackend(), ui_task_runner_, db_task_runner_, - on_changed_callback, on_sync_started_callback); + on_changed_callback, on_address_conversion_completed_callback, + on_sync_started_callback); } AutofillWebDataService::AutofillWebDataService( @@ -60,6 +65,7 @@ AutofillWebDataService::AutofillWebDataService( ui_task_runner_, db_task_runner_, base::Closure(), + base::Closure(), base::Callback<void(syncer::ModelType)>())), weak_ptr_factory_(this) {} @@ -141,6 +147,15 @@ WebDataServiceBase::Handle AutofillWebDataService::GetServerProfiles( consumer); } +void AutofillWebDataService::ConvertWalletAddressesAndUpdateWalletCards( + const std::string& app_locale, + const std::string& primary_account_email) { + wdbs_->ScheduleDBTask( + FROM_HERE, Bind(&AutofillWebDataBackendImpl:: + ConvertWalletAddressesAndUpdateWalletCards, + autofill_backend_, app_locale, primary_account_email)); +} + WebDataServiceBase::Handle AutofillWebDataService::GetCountOfValuesContainedBetween( const Time& begin, const Time& end, WebDataServiceConsumer* consumer) { @@ -336,7 +351,14 @@ AutofillWebDataService::~AutofillWebDataService() { void AutofillWebDataService::NotifyAutofillMultipleChangedOnUISequence() { DCHECK(ui_task_runner_->RunsTasksInCurrentSequence()); for (auto& ui_observer : ui_observer_list_) - ui_observer.AutofillMultipleChanged(); + ui_observer.AutofillMultipleChangedBySync(); +} + +void AutofillWebDataService:: + NotifyAutofillAddressConversionCompletedOnUISequence() { + DCHECK(ui_task_runner_->RunsTasksInCurrentSequence()); + for (auto& ui_observer : ui_observer_list_) + ui_observer.AutofillAddressConversionCompleted(); } void AutofillWebDataService::NotifySyncStartedOnUISequence( diff --git a/chromium/components/autofill/core/browser/webdata/autofill_webdata_service.h b/chromium/components/autofill/core/browser/webdata/autofill_webdata_service.h index f25b3b0cf35..f82e891ec5d 100644 --- a/chromium/components/autofill/core/browser/webdata/autofill_webdata_service.h +++ b/chromium/components/autofill/core/browser/webdata/autofill_webdata_service.h @@ -13,7 +13,6 @@ #include "base/observer_list.h" #include "base/supports_user_data.h" #include "components/autofill/core/browser/webdata/autofill_change.h" -#include "components/autofill/core/browser/webdata/autofill_webdata.h" #include "components/autofill/core/common/form_field_data.h" #include "components/sync/base/model_type.h" #include "components/webdata/common/web_data_results.h" @@ -38,8 +37,7 @@ class AutofillWebDataServiceObserverOnUISequence; class CreditCard; // API for Autofill web data. -class AutofillWebDataService : public AutofillWebData, - public WebDataServiceBase { +class AutofillWebDataService : public WebDataServiceBase { public: AutofillWebDataService( scoped_refptr<base::SingleThreadTaskRunner> ui_task_runner, @@ -53,72 +51,122 @@ class AutofillWebDataService : public AutofillWebData, // WebDataServiceBase implementation. void ShutdownOnUISequence() override; - // AutofillWebData implementation. - void AddFormFields(const std::vector<FormFieldData>& fields) override; - WebDataServiceBase::Handle GetFormValuesForElementName( + // Schedules a task to add form fields to the web database. + virtual void AddFormFields(const std::vector<FormFieldData>& fields); + + // Initiates the request for a vector of values which have been entered in + // form input fields named |name|. The method OnWebDataServiceRequestDone of + // |consumer| gets called back when the request is finished, with the vector + // included in the argument |result|. + virtual WebDataServiceBase::Handle GetFormValuesForElementName( const base::string16& name, const base::string16& prefix, int limit, - WebDataServiceConsumer* consumer) override; + WebDataServiceConsumer* consumer); + // Removes form elements recorded for Autocomplete from the database. void RemoveFormElementsAddedBetween(const base::Time& delete_begin, - const base::Time& delete_end) override; + const base::Time& delete_end); void RemoveFormValueForElementName(const base::string16& name, - const base::string16& value) override; + const base::string16& value); - // Profiles. - void AddAutofillProfile(const AutofillProfile& profile) override; - void UpdateAutofillProfile(const AutofillProfile& profile) override; - void RemoveAutofillProfile(const std::string& guid) override; - WebDataServiceBase::Handle GetAutofillProfiles( - WebDataServiceConsumer* consumer) override; + // Schedules a task to add an Autofill profile to the web database. + void AddAutofillProfile(const AutofillProfile& profile); + + // Schedules a task to update an Autofill profile in the web database. + void UpdateAutofillProfile(const AutofillProfile& profile); + + // Schedules a task to remove an Autofill profile from the web database. + // |guid| is the identifier of the profile to remove. + void RemoveAutofillProfile(const std::string& guid); - // Server profiles. + // Initiates the request for local/server Autofill profiles. The method + // OnWebDataServiceRequestDone of |consumer| gets called when the request is + // finished, with the profiles included in the argument |result|. The + WebDataServiceBase::Handle GetAutofillProfiles( + WebDataServiceConsumer* consumer); WebDataServiceBase::Handle GetServerProfiles( - WebDataServiceConsumer* consumer) override; + WebDataServiceConsumer* consumer); + // Schedules a task to convert server profiles to local profiles, comparing + // profiles using |app_locale| and filling in |primary_account_email| into + // newly converted profiles. The task only converts profiles that have not + // been converted before. + void ConvertWalletAddressesAndUpdateWalletCards( + const std::string& app_locale, + const std::string& primary_account_email); + + // Schedules a task to count the number of unique autofill values contained + // in the time interval [|begin|, |end|). |begin| and |end| can be null + // to indicate no time limitation. WebDataServiceBase::Handle GetCountOfValuesContainedBetween( const base::Time& begin, const base::Time& end, - WebDataServiceConsumer* consumer) override; + WebDataServiceConsumer* consumer); + + // Schedules a task to update autofill entries in the web database. void UpdateAutofillEntries( - const std::vector<AutofillEntry>& autofill_entries) override; + const std::vector<AutofillEntry>& autofill_entries); void SetAutofillProfileChangedCallback( base::RepeatingCallback<void(const AutofillProfileDeepChange&)> change_cb); - // Credit cards. - void AddCreditCard(const CreditCard& credit_card) override; - void UpdateCreditCard(const CreditCard& credit_card) override; - void RemoveCreditCard(const std::string& guid) override; - void AddFullServerCreditCard(const CreditCard& credit_card) override; - WebDataServiceBase::Handle GetCreditCards( - WebDataServiceConsumer* consumer) override; + // Schedules a task to add credit card to the web database. + void AddCreditCard(const CreditCard& credit_card); - // Server cards. + // Schedules a task to update credit card in the web database. + void UpdateCreditCard(const CreditCard& credit_card); + + // Schedules a task to remove a credit card from the web database. + // |guid| is identifier of the credit card to remove. + void RemoveCreditCard(const std::string& guid); + + // Schedules a task to add a full server credit card to the web database. + void AddFullServerCreditCard(const CreditCard& credit_card); + + // Initiates the request for local/server 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. + WebDataServiceBase::Handle GetCreditCards(WebDataServiceConsumer* consumer); WebDataServiceBase::Handle GetServerCreditCards( - WebDataServiceConsumer* consumer) override; + WebDataServiceConsumer* consumer); + + // Toggles the record for a server credit card between masked (only last 4 + // digits) and full (all digits). void UnmaskServerCreditCard(const CreditCard& card, - const base::string16& full_number) override; - void MaskServerCreditCard(const std::string& id) override; + const base::string16& full_number); + void MaskServerCreditCard(const std::string& id); - // PaymentsCustomerData. + // Initiates the request for Payments customer data. The method + // OnWebDataServiceRequestDone of |consumer| gets called when the request is + // finished, with the customer data included in the argument |result|. The + // consumer owns the data. WebDataServiceBase::Handle GetPaymentsCustomerData( - WebDataServiceConsumer* consumer) override; + WebDataServiceConsumer* consumer); void ClearAllServerData(); void ClearAllLocalData(); - void UpdateServerCardMetadata(const CreditCard& credit_card) override; - void UpdateServerAddressMetadata(const AutofillProfile& profile) override; + // Updates the metadata for a server card (masked or not). + void UpdateServerCardMetadata(const CreditCard& credit_card); + + // Updates the metadata for a server address. + void UpdateServerAddressMetadata(const AutofillProfile& profile); + // Removes Autofill records from the database. void RemoveAutofillDataModifiedBetween(const base::Time& delete_begin, - const base::Time& delete_end) override; + const base::Time& delete_end); + + // Removes origin URLs associated with Autofill profiles and credit cards from + // the database. void RemoveOriginURLsModifiedBetween(const base::Time& delete_begin, - const base::Time& delete_end) override; + const base::Time& delete_end); - void RemoveOrphanAutofillTableRows() override; + // Removes the orphan rows in the autofill_profile_names, + // autofill_profile_emails and autofill_profile_phones tables. + void RemoveOrphanAutofillTableRows(); void AddObserver(AutofillWebDataServiceObserverOnDBSequence* observer); void RemoveObserver(AutofillWebDataServiceObserverOnDBSequence* observer); @@ -150,9 +198,9 @@ class AutofillWebDataService : public AutofillWebData, protected: ~AutofillWebDataService() override; - virtual void NotifyAutofillMultipleChangedOnUISequence(); - - virtual void NotifySyncStartedOnUISequence(syncer::ModelType model_type); + void NotifyAutofillMultipleChangedOnUISequence(); + void NotifyAutofillAddressConversionCompletedOnUISequence(); + void NotifySyncStartedOnUISequence(syncer::ModelType model_type); base::WeakPtr<AutofillWebDataService> AsWeakPtr() { return weak_ptr_factory_.GetWeakPtr(); diff --git a/chromium/components/autofill/core/browser/webdata/autofill_webdata_service_observer.h b/chromium/components/autofill/core/browser/webdata/autofill_webdata_service_observer.h index 7477ce7781b..7fd955e98cc 100644 --- a/chromium/components/autofill/core/browser/webdata/autofill_webdata_service_observer.h +++ b/chromium/components/autofill/core/browser/webdata/autofill_webdata_service_observer.h @@ -25,7 +25,10 @@ class AutofillWebDataServiceObserverOnDBSequence { // Called on DB sequence when multiple Autofill entries have been modified by // Sync. - virtual void AutofillMultipleChanged() {} + // TODO(crbug.com/900607): Remove AutofillMultipleChangedBySync() from + // AutofillWebDataServiceObserverOnDBSequence once USS for wallet_metadata + // launches. + virtual void AutofillMultipleChangedBySync() {} protected: virtual ~AutofillWebDataServiceObserverOnDBSequence() {} @@ -35,7 +38,9 @@ class AutofillWebDataServiceObserverOnUISequence { public: // Called on UI sequence when multiple Autofill entries have been modified by // Sync. - virtual void AutofillMultipleChanged() {} + virtual void AutofillMultipleChangedBySync() {} + + virtual void AutofillAddressConversionCompleted() {} virtual void AutofillProfileChanged(const AutofillProfileChange& change) {} diff --git a/chromium/components/autofill/core/browser/webdata/mock_autofill_webdata_backend.h b/chromium/components/autofill/core/browser/webdata/mock_autofill_webdata_backend.h index 3368878abf0..53189231a80 100644 --- a/chromium/components/autofill/core/browser/webdata/mock_autofill_webdata_backend.h +++ b/chromium/components/autofill/core/browser/webdata/mock_autofill_webdata_backend.h @@ -32,6 +32,7 @@ class MockAutofillWebDataBackend : public AutofillWebDataBackend { void(const AutofillProfileChange& change)); MOCK_METHOD1(NotifyOfCreditCardChanged, void(const CreditCardChange& change)); MOCK_METHOD0(NotifyOfMultipleAutofillChanges, void()); + MOCK_METHOD0(NotifyOfAddressConversionCompleted, void()); MOCK_METHOD1(NotifyThatSyncHasStarted, void(syncer::ModelType model_type)); private: diff --git a/chromium/components/autofill/core/browser/webdata/web_data_service_unittest.cc b/chromium/components/autofill/core/browser/webdata/web_data_service_unittest.cc index f1d6e76fcc9..b7503bca43f 100644 --- a/chromium/components/autofill/core/browser/webdata/web_data_service_unittest.cc +++ b/chromium/components/autofill/core/browser/webdata/web_data_service_unittest.cc @@ -17,7 +17,7 @@ #include "base/strings/utf_string_conversions.h" #include "base/synchronization/waitable_event.h" #include "base/task/post_task.h" -#include "base/task/task_scheduler/task_scheduler.h" +#include "base/task/thread_pool/thread_pool.h" #include "base/test/scoped_task_environment.h" #include "base/threading/thread_task_runner_handle.h" #include "base/time/time.h" @@ -153,7 +153,7 @@ class WebDataServiceAutofillTest : public WebDataServiceTest { &AutofillWebDataService::AddObserver; wds_->GetDBTaskRunner()->PostTask( FROM_HERE, base::BindOnce(add_observer_func, wds_, &observer_)); - base::TaskScheduler::GetInstance()->FlushForTesting(); + base::ThreadPool::GetInstance()->FlushForTesting(); } void TearDown() override { @@ -313,7 +313,7 @@ TEST_F(WebDataServiceAutofillTest, ProfileRemove) { // Check that GUID-based notification was sent. const AutofillProfileChange expected_change(AutofillProfileChange::REMOVE, - profile.guid(), nullptr); + profile.guid(), &profile); EXPECT_CALL(observer_, AutofillProfileChanged(expected_change)) .WillOnce(SignalEvent(&done_event_)); @@ -491,7 +491,7 @@ TEST_F(WebDataServiceAutofillTest, AutofillRemoveModifiedBetween) { // Check that GUID-based notification was sent for the profile. const AutofillProfileChange expected_profile_change( - AutofillProfileChange::REMOVE, profile.guid(), nullptr); + AutofillProfileChange::REMOVE, profile.guid(), &profile); EXPECT_CALL(observer_, AutofillProfileChanged(expected_profile_change)) .WillOnce(SignalEvent(&done_event_)); |