summaryrefslogtreecommitdiff
path: root/chromium/components/autofill
diff options
context:
space:
mode:
Diffstat (limited to 'chromium/components/autofill')
-rw-r--r--chromium/components/autofill/DEPS1
-rw-r--r--chromium/components/autofill/PRESUBMIT.py10
-rw-r--r--chromium/components/autofill/content/browser/BUILD.gn7
-rw-r--r--chromium/components/autofill/content/browser/autofill_internals_log_router_unittest.cc8
-rw-r--r--chromium/components/autofill/content/browser/content_autofill_driver.cc45
-rw-r--r--chromium/components/autofill/content/browser/content_autofill_driver.h36
-rw-r--r--chromium/components/autofill/content/browser/content_autofill_driver_factory.cc38
-rw-r--r--chromium/components/autofill/content/browser/content_autofill_driver_factory.h2
-rw-r--r--chromium/components/autofill/content/browser/content_autofill_driver_factory_unittest.cc1
-rw-r--r--chromium/components/autofill/content/browser/content_autofill_router.cc13
-rw-r--r--chromium/components/autofill/content/browser/content_autofill_router.h13
-rw-r--r--chromium/components/autofill/content/browser/form_forest_unittest.cc11
-rw-r--r--chromium/components/autofill/content/browser/risk/fingerprint.cc14
-rw-r--r--chromium/components/autofill/content/browser/test_autofill_manager_injector.h82
-rw-r--r--chromium/components/autofill/content/common/mojom/autofill_driver.mojom10
-rw-r--r--chromium/components/autofill/content/renderer/autofill_agent.cc111
-rw-r--r--chromium/components/autofill/content/renderer/autofill_agent.h4
-rw-r--r--chromium/components/autofill/content/renderer/autofill_agent_browsertest.cc4
-rw-r--r--chromium/components/autofill/content/renderer/form_autofill_util.cc142
-rw-r--r--chromium/components/autofill/content/renderer/form_autofill_util.h21
-rw-r--r--chromium/components/autofill/content/renderer/form_autofill_util_browsertest.cc26
-rw-r--r--chromium/components/autofill/content/renderer/form_cache.cc12
-rw-r--r--chromium/components/autofill/content/renderer/form_tracker.cc11
-rw-r--r--chromium/components/autofill/content/renderer/password_autofill_agent.cc39
-rw-r--r--chromium/components/autofill/content/renderer/password_generation_agent.cc17
-rw-r--r--chromium/components/autofill/content/renderer/renderer_save_password_progress_logger_unittest.cc3
-rw-r--r--chromium/components/autofill/core/browser/BUILD.gn56
-rw-r--r--chromium/components/autofill/core/browser/address_profile_save_manager_unittest.cc48
-rw-r--r--chromium/components/autofill/core/browser/autocomplete_history_manager.cc42
-rw-r--r--chromium/components/autofill/core/browser/autocomplete_history_manager.h15
-rw-r--r--chromium/components/autofill/core/browser/autocomplete_history_manager_unittest.cc274
-rw-r--r--chromium/components/autofill/core/browser/autofill_address_util.cc70
-rw-r--r--chromium/components/autofill/core/browser/autofill_address_util.h10
-rw-r--r--chromium/components/autofill/core/browser/autofill_and_password_manager_internals/OWNERS5
-rw-r--r--chromium/components/autofill/core/browser/autofill_and_password_manager_internals/autofill_and_password_manager_internals.html8
-rw-r--r--chromium/components/autofill/core/browser/autofill_and_password_manager_internals/autofill_and_password_manager_internals.js133
-rw-r--r--chromium/components/autofill/core/browser/autofill_client.cc12
-rw-r--r--chromium/components/autofill/core/browser/autofill_client.h37
-rw-r--r--chromium/components/autofill/core/browser/autofill_data_util_unittest.cc19
-rw-r--r--chromium/components/autofill/core/browser/autofill_download_manager.cc19
-rw-r--r--chromium/components/autofill/core/browser/autofill_download_manager_unittest.cc36
-rw-r--r--chromium/components/autofill/core/browser/autofill_driver.h21
-rw-r--r--chromium/components/autofill/core/browser/autofill_experiments.cc16
-rw-r--r--chromium/components/autofill/core/browser/autofill_external_delegate.cc4
-rw-r--r--chromium/components/autofill/core/browser/autofill_external_delegate.h4
-rw-r--r--chromium/components/autofill/core/browser/autofill_external_delegate_unittest.cc19
-rw-r--r--chromium/components/autofill/core/browser/autofill_field.cc18
-rw-r--r--chromium/components/autofill/core/browser/autofill_field.h16
-rw-r--r--chromium/components/autofill/core/browser/autofill_form_test_utils.cc8
-rw-r--r--chromium/components/autofill/core/browser/autofill_form_test_utils.h2
-rw-r--r--chromium/components/autofill/core/browser/autofill_ie_toolbar_import_win.cc306
-rw-r--r--chromium/components/autofill/core/browser/autofill_ie_toolbar_import_win.h24
-rw-r--r--chromium/components/autofill/core/browser/autofill_ie_toolbar_import_win_unittest.cc231
-rw-r--r--chromium/components/autofill/core/browser/autofill_manager.cc569
-rw-r--r--chromium/components/autofill/core/browser/autofill_manager.h229
-rw-r--r--chromium/components/autofill/core/browser/autofill_manager_unittest.cc56
-rw-r--r--chromium/components/autofill/core/browser/autofill_profile_sync_util.cc20
-rw-r--r--chromium/components/autofill/core/browser/autofill_profile_sync_util_unittest.cc5
-rw-r--r--chromium/components/autofill/core/browser/autofill_progress_dialog_type.h23
-rw-r--r--chromium/components/autofill/core/browser/autofill_regex_constants.h107
-rw-r--r--chromium/components/autofill/core/browser/autofill_regexes.cc102
-rw-r--r--chromium/components/autofill/core/browser/autofill_regexes.h26
-rw-r--r--chromium/components/autofill/core/browser/autofill_suggestion_generator.cc97
-rw-r--r--chromium/components/autofill/core/browser/autofill_suggestion_generator.h17
-rw-r--r--chromium/components/autofill/core/browser/autofill_suggestion_generator_unittest.cc250
-rw-r--r--chromium/components/autofill/core/browser/autofill_test_utils.cc23
-rw-r--r--chromium/components/autofill/core/browser/autofill_test_utils.h8
-rw-r--r--chromium/components/autofill/core/browser/autofill_type.cc141
-rw-r--r--chromium/components/autofill/core/browser/autofill_type_unittest.cc10
-rw-r--r--chromium/components/autofill/core/browser/browser_autofill_manager.cc379
-rw-r--r--chromium/components/autofill/core/browser/browser_autofill_manager.h58
-rw-r--r--chromium/components/autofill/core/browser/browser_autofill_manager_unittest.cc474
-rw-r--r--chromium/components/autofill/core/browser/crypto/rc4_decryptor.h112
-rw-r--r--chromium/components/autofill/core/browser/data_model/autofill_data_model.cc2
-rw-r--r--chromium/components/autofill/core/browser/data_model/autofill_data_model.h2
-rw-r--r--chromium/components/autofill/core/browser/data_model/autofill_profile.cc2
-rw-r--r--chromium/components/autofill/core/browser/data_model/autofill_profile.h2
-rw-r--r--chromium/components/autofill/core/browser/data_model/autofill_profile_comparator.cc15
-rw-r--r--chromium/components/autofill/core/browser/data_model/autofill_profile_comparator_unittest.cc218
-rw-r--r--chromium/components/autofill/core/browser/data_model/autofill_profile_unittest.cc1
-rw-r--r--chromium/components/autofill/core/browser/data_model/autofill_structured_address.cc46
-rw-r--r--chromium/components/autofill/core/browser/data_model/autofill_structured_address.h4
-rw-r--r--chromium/components/autofill/core/browser/data_model/autofill_structured_address_component.cc135
-rw-r--r--chromium/components/autofill/core/browser/data_model/autofill_structured_address_component.h14
-rw-r--r--chromium/components/autofill/core/browser/data_model/autofill_structured_address_component_unittest.cc2
-rw-r--r--chromium/components/autofill/core/browser/data_model/autofill_structured_address_unittest.cc130
-rw-r--r--chromium/components/autofill/core/browser/data_model/birthdate.cc10
-rw-r--r--chromium/components/autofill/core/browser/data_model/birthdate.h2
-rw-r--r--chromium/components/autofill/core/browser/data_model/birthdate_unittest.cc8
-rw-r--r--chromium/components/autofill/core/browser/data_model/contact_info.cc19
-rw-r--r--chromium/components/autofill/core/browser/data_model/credit_card.cc53
-rw-r--r--chromium/components/autofill/core/browser/data_model/credit_card.h16
-rw-r--r--chromium/components/autofill/core/browser/data_model/credit_card_unittest.cc286
-rw-r--r--chromium/components/autofill/core/browser/data_model/data_model_utils.cc6
-rw-r--r--chromium/components/autofill/core/browser/data_model/iban.cc160
-rw-r--r--chromium/components/autofill/core/browser/data_model/iban.h137
-rw-r--r--chromium/components/autofill/core/browser/data_model/iban_unittest.cc149
-rw-r--r--chromium/components/autofill/core/browser/data_model/phone_number.cc46
-rw-r--r--chromium/components/autofill/core/browser/data_model/phone_number.h6
-rw-r--r--chromium/components/autofill/core/browser/data_model/phone_number_unittest.cc41
-rw-r--r--chromium/components/autofill/core/browser/field_filler.cc52
-rw-r--r--chromium/components/autofill/core/browser/field_filler_unittest.cc48
-rw-r--r--chromium/components/autofill/core/browser/field_types.cc118
-rw-r--r--chromium/components/autofill/core/browser/field_types.h143
-rw-r--r--chromium/components/autofill/core/browser/field_types_unittest.cc26
-rw-r--r--chromium/components/autofill/core/browser/form_data_importer.cc411
-rw-r--r--chromium/components/autofill/core/browser/form_data_importer.h84
-rw-r--r--chromium/components/autofill/core/browser/form_data_importer_unittest.cc288
-rw-r--r--chromium/components/autofill/core/browser/form_data_importer_utils.cc244
-rw-r--r--chromium/components/autofill/core/browser/form_data_importer_utils.h171
-rw-r--r--chromium/components/autofill/core/browser/form_data_importer_utils_unittest.cc85
-rw-r--r--chromium/components/autofill/core/browser/form_parsing/address_field.cc4
-rw-r--r--chromium/components/autofill/core/browser/form_parsing/address_field.h2
-rw-r--r--chromium/components/autofill/core/browser/form_parsing/birthdate_field.cc118
-rw-r--r--chromium/components/autofill/core/browser/form_parsing/birthdate_field.h56
-rw-r--r--chromium/components/autofill/core/browser/form_parsing/birthdate_field_unittest.cc132
-rw-r--r--chromium/components/autofill/core/browser/form_parsing/credit_card_field.cc45
-rw-r--r--chromium/components/autofill/core/browser/form_parsing/credit_card_field.h2
-rw-r--r--chromium/components/autofill/core/browser/form_parsing/credit_card_field_unittest.cc14
-rw-r--r--chromium/components/autofill/core/browser/form_parsing/email_field.cc4
-rw-r--r--chromium/components/autofill/core/browser/form_parsing/email_field.h2
-rw-r--r--chromium/components/autofill/core/browser/form_parsing/form_field.cc232
-rw-r--r--chromium/components/autofill/core/browser/form_parsing/form_field.h77
-rw-r--r--chromium/components/autofill/core/browser/form_parsing/form_field_unittest.cc485
-rw-r--r--chromium/components/autofill/core/browser/form_parsing/iban_field.cc42
-rw-r--r--chromium/components/autofill/core/browser/form_parsing/iban_field.h42
-rw-r--r--chromium/components/autofill/core/browser/form_parsing/iban_field_unittest.cc68
-rw-r--r--chromium/components/autofill/core/browser/form_parsing/merchant_promo_code_field.cc4
-rw-r--r--chromium/components/autofill/core/browser/form_parsing/merchant_promo_code_field.h2
-rw-r--r--chromium/components/autofill/core/browser/form_parsing/merchant_promo_code_field_unittest.cc14
-rw-r--r--chromium/components/autofill/core/browser/form_parsing/name_field.cc18
-rw-r--r--chromium/components/autofill/core/browser/form_parsing/name_field.h2
-rw-r--r--chromium/components/autofill/core/browser/form_parsing/name_field_unittest.cc24
-rw-r--r--chromium/components/autofill/core/browser/form_parsing/parsing_test_utils.cc42
-rw-r--r--chromium/components/autofill/core/browser/form_parsing/phone_field.cc93
-rw-r--r--chromium/components/autofill/core/browser/form_parsing/phone_field.h4
-rw-r--r--chromium/components/autofill/core/browser/form_parsing/phone_field_unittest.cc30
-rw-r--r--chromium/components/autofill/core/browser/form_parsing/price_field.cc4
-rw-r--r--chromium/components/autofill/core/browser/form_parsing/price_field.h2
-rw-r--r--chromium/components/autofill/core/browser/form_parsing/price_field_unittest.cc2
-rw-r--r--chromium/components/autofill/core/browser/form_parsing/regex_patterns_unittest.cc12
-rw-r--r--chromium/components/autofill/core/browser/form_parsing/resources/legacy_regex_patterns.json1288
-rw-r--r--chromium/components/autofill/core/browser/form_parsing/search_field.cc4
-rw-r--r--chromium/components/autofill/core/browser/form_parsing/search_field.h2
-rw-r--r--chromium/components/autofill/core/browser/form_parsing/standalone_cvc_field.cc80
-rw-r--r--chromium/components/autofill/core/browser/form_parsing/standalone_cvc_field.h50
-rw-r--r--chromium/components/autofill/core/browser/form_parsing/standalone_cvc_field_unittest.cc78
-rwxr-xr-xchromium/components/autofill/core/browser/form_parsing/transpile_regex_patterns.py47
-rw-r--r--chromium/components/autofill/core/browser/form_parsing/travel_field.cc4
-rw-r--r--chromium/components/autofill/core/browser/form_parsing/travel_field.h2
-rw-r--r--chromium/components/autofill/core/browser/form_processing/label_processing_util.cc18
-rw-r--r--chromium/components/autofill/core/browser/form_processing/label_processing_util_unittest.cc113
-rw-r--r--chromium/components/autofill/core/browser/form_processing/name_processing_util.cc6
-rw-r--r--chromium/components/autofill/core/browser/form_processing/name_processing_util.h1
-rw-r--r--chromium/components/autofill/core/browser/form_structure.cc575
-rw-r--r--chromium/components/autofill/core/browser/form_structure.h13
-rw-r--r--chromium/components/autofill/core/browser/form_structure_test_api.cc (renamed from chromium/components/autofill/core/browser/test_form_structure.cc)46
-rw-r--r--chromium/components/autofill/core/browser/form_structure_test_api.h22
-rw-r--r--chromium/components/autofill/core/browser/form_structure_unittest.cc414
-rw-r--r--chromium/components/autofill/core/browser/geo/address_i18n.cc10
-rw-r--r--chromium/components/autofill/core/browser/geo/address_i18n_unittest.cc4
-rw-r--r--chromium/components/autofill/core/browser/geo/autofill_country.cc5
-rw-r--r--chromium/components/autofill/core/browser/geo/autofill_country.h11
-rw-r--r--chromium/components/autofill/core/browser/geo/autofill_country_unittest.cc5
-rw-r--r--chromium/components/autofill/core/browser/geo/phone_number_i18n.cc3
-rw-r--r--chromium/components/autofill/core/browser/geo/phone_number_i18n_unittest.cc4
-rw-r--r--chromium/components/autofill/core/browser/iban_manager.cc81
-rw-r--r--chromium/components/autofill/core/browser/iban_manager.h81
-rw-r--r--chromium/components/autofill/core/browser/iban_manager_unittest.cc155
-rw-r--r--chromium/components/autofill/core/browser/logging/log_buffer_submitter.cc26
-rw-r--r--chromium/components/autofill/core/browser/logging/log_buffer_submitter_unittest.cc12
-rw-r--r--chromium/components/autofill/core/browser/logging/log_manager.cc11
-rw-r--r--chromium/components/autofill/core/browser/logging/log_manager.h43
-rw-r--r--chromium/components/autofill/core/browser/logging/log_manager_unittest.cc16
-rw-r--r--chromium/components/autofill/core/browser/logging/log_receiver.h6
-rw-r--r--chromium/components/autofill/core/browser/logging/log_router.cc20
-rw-r--r--chromium/components/autofill/core/browser/logging/log_router.h13
-rw-r--r--chromium/components/autofill/core/browser/logging/log_router_unittest.cc60
-rw-r--r--chromium/components/autofill/core/browser/logging/stub_log_manager.cc2
-rw-r--r--chromium/components/autofill/core/browser/logging/stub_log_manager.h2
-rw-r--r--chromium/components/autofill/core/browser/merchant_promo_code_manager.cc39
-rw-r--r--chromium/components/autofill/core/browser/merchant_promo_code_manager.h17
-rw-r--r--chromium/components/autofill/core/browser/merchant_promo_code_manager_unittest.cc312
-rw-r--r--chromium/components/autofill/core/browser/metrics/README.md22
-rw-r--r--chromium/components/autofill/core/browser/metrics/autofill_metrics.cc384
-rw-r--r--chromium/components/autofill/core/browser/metrics/autofill_metrics.h235
-rw-r--r--chromium/components/autofill/core/browser/metrics/autofill_metrics_test_base.cc16
-rw-r--r--chromium/components/autofill/core/browser/metrics/autofill_metrics_test_base.h22
-rw-r--r--chromium/components/autofill/core/browser/metrics/autofill_metrics_unittest.cc1730
-rw-r--r--chromium/components/autofill/core/browser/metrics/form_events/form_event_logger_base.cc74
-rw-r--r--chromium/components/autofill/core/browser/metrics/form_events/form_event_logger_base.h12
-rw-r--r--chromium/components/autofill/core/browser/metrics/payments/local_card_migration_metrics.cc114
-rw-r--r--chromium/components/autofill/core/browser/metrics/payments/local_card_migration_metrics.h176
-rw-r--r--chromium/components/autofill/core/browser/metrics/payments/offers_metrics.cc170
-rw-r--r--chromium/components/autofill/core/browser/metrics/payments/offers_metrics.h65
-rw-r--r--chromium/components/autofill/core/browser/metrics/payments/offers_metrics_unittest.cc43
-rw-r--r--chromium/components/autofill/core/browser/metrics/shadow_prediction_metrics.cc7
-rw-r--r--chromium/components/autofill/core/browser/metrics/shadow_prediction_metrics_unittest.cc43
-rw-r--r--chromium/components/autofill/core/browser/mock_autocomplete_history_manager.h6
-rw-r--r--chromium/components/autofill/core/browser/mock_iban_manager.cc14
-rw-r--r--chromium/components/autofill/core/browser/mock_iban_manager.h51
-rw-r--r--chromium/components/autofill/core/browser/mock_merchant_promo_code_manager.h6
-rw-r--r--chromium/components/autofill/core/browser/mock_single_field_form_fill_router.h6
-rw-r--r--chromium/components/autofill/core/browser/payments/autofill_offer_notification_infobar_delegate_mobile.cc17
-rw-r--r--chromium/components/autofill/core/browser/payments/credit_card_access_manager.cc32
-rw-r--r--chromium/components/autofill/core/browser/payments/credit_card_access_manager.h15
-rw-r--r--chromium/components/autofill/core/browser/payments/credit_card_access_manager_unittest.cc6
-rw-r--r--chromium/components/autofill/core/browser/payments/credit_card_fido_authenticator.cc35
-rw-r--r--chromium/components/autofill/core/browser/payments/credit_card_fido_authenticator.h2
-rw-r--r--chromium/components/autofill/core/browser/payments/credit_card_save_manager.cc26
-rw-r--r--chromium/components/autofill/core/browser/payments/credit_card_save_manager_unittest.cc374
-rw-r--r--chromium/components/autofill/core/browser/payments/local_card_migration_manager.cc67
-rw-r--r--chromium/components/autofill/core/browser/payments/local_card_migration_manager.h3
-rw-r--r--chromium/components/autofill/core/browser/payments/local_card_migration_manager_unittest.cc187
-rw-r--r--chromium/components/autofill/core/browser/payments/payments_requests/upload_card_request.cc4
-rw-r--r--chromium/components/autofill/core/browser/payments/virtual_card_enrollment_manager.cc64
-rw-r--r--chromium/components/autofill/core/browser/payments/virtual_card_enrollment_manager.h18
-rw-r--r--chromium/components/autofill/core/browser/payments/virtual_card_enrollment_manager_unittest.cc119
-rw-r--r--chromium/components/autofill/core/browser/personal_data_manager.cc148
-rw-r--r--chromium/components/autofill/core/browser/personal_data_manager.h84
-rw-r--r--chromium/components/autofill/core/browser/personal_data_manager_cleaner_unittest.cc1290
-rw-r--r--chromium/components/autofill/core/browser/personal_data_manager_test_base.cc191
-rw-r--r--chromium/components/autofill/core/browser/personal_data_manager_test_base.h87
-rw-r--r--chromium/components/autofill/core/browser/personal_data_manager_unittest.cc1866
-rw-r--r--chromium/components/autofill/core/browser/proto/server.proto3
-rw-r--r--chromium/components/autofill/core/browser/randomized_encoder.cc1
-rw-r--r--chromium/components/autofill/core/browser/randomized_encoder.h1
-rw-r--r--chromium/components/autofill/core/browser/rationalization_util.cc35
-rw-r--r--chromium/components/autofill/core/browser/single_field_form_fill_router.cc28
-rw-r--r--chromium/components/autofill/core/browser/single_field_form_fill_router.h6
-rw-r--r--chromium/components/autofill/core/browser/single_field_form_fill_router_unittest.cc187
-rw-r--r--chromium/components/autofill/core/browser/single_field_form_filler.h26
-rw-r--r--chromium/components/autofill/core/browser/test_autofill_client.cc25
-rw-r--r--chromium/components/autofill/core/browser/test_autofill_client.h22
-rw-r--r--chromium/components/autofill/core/browser/test_autofill_clock.cc15
-rw-r--r--chromium/components/autofill/core/browser/test_autofill_clock.h9
-rw-r--r--chromium/components/autofill/core/browser/test_autofill_driver.cc49
-rw-r--r--chromium/components/autofill/core/browser/test_autofill_driver.h29
-rw-r--r--chromium/components/autofill/core/browser/test_autofill_manager_waiter.cc205
-rw-r--r--chromium/components/autofill/core/browser/test_autofill_manager_waiter.h163
-rw-r--r--chromium/components/autofill/core/browser/test_browser_autofill_manager.cc134
-rw-r--r--chromium/components/autofill/core/browser/test_browser_autofill_manager.h43
-rw-r--r--chromium/components/autofill/core/browser/test_event_waiter.h1
-rw-r--r--chromium/components/autofill/core/browser/test_form_data_importer.h4
-rw-r--r--chromium/components/autofill/core/browser/test_form_structure.h43
-rw-r--r--chromium/components/autofill/core/browser/test_personal_data_manager.cc14
-rw-r--r--chromium/components/autofill/core/browser/test_personal_data_manager.h1
-rw-r--r--chromium/components/autofill/core/browser/touch_to_fill_delegate.cc19
-rw-r--r--chromium/components/autofill/core/browser/touch_to_fill_delegate.h31
-rw-r--r--chromium/components/autofill/core/browser/touch_to_fill_delegate_impl.cc86
-rw-r--r--chromium/components/autofill/core/browser/touch_to_fill_delegate_impl.h69
-rw-r--r--chromium/components/autofill/core/browser/touch_to_fill_delegate_impl_unittest.cc297
-rw-r--r--chromium/components/autofill/core/browser/ui/address_combobox_model.cc33
-rw-r--r--chromium/components/autofill/core/browser/ui/address_combobox_model.h19
-rw-r--r--chromium/components/autofill/core/browser/ui/address_combobox_model_unittest.cc35
-rw-r--r--chromium/components/autofill/core/browser/ui/address_contact_form_label_formatter_unittest.cc66
-rw-r--r--chromium/components/autofill/core/browser/ui/address_email_form_label_formatter_unittest.cc45
-rw-r--r--chromium/components/autofill/core/browser/ui/address_phone_form_label_formatter_unittest.cc6
-rw-r--r--chromium/components/autofill/core/browser/ui/autofill_popup_delegate.h2
-rw-r--r--chromium/components/autofill/core/browser/ui/country_combobox_model.cc8
-rw-r--r--chromium/components/autofill/core/browser/ui/country_combobox_model.h6
-rw-r--r--chromium/components/autofill/core/browser/ui/country_combobox_model_unittest.cc2
-rw-r--r--chromium/components/autofill/core/browser/ui/label_formatter.cc12
-rw-r--r--chromium/components/autofill/core/browser/ui/label_formatter.h6
-rw-r--r--chromium/components/autofill/core/browser/ui/label_formatter_utils.cc11
-rw-r--r--chromium/components/autofill/core/browser/ui/mobile_label_formatter.cc2
-rw-r--r--chromium/components/autofill/core/browser/ui/payments/card_unmask_prompt_controller_impl_unittest.cc52
-rw-r--r--chromium/components/autofill/core/browser/ui/popup_item_ids.h4
-rw-r--r--chromium/components/autofill/core/browser/ui/popup_types.h6
-rw-r--r--chromium/components/autofill/core/browser/ui/region_combobox_model.cc19
-rw-r--r--chromium/components/autofill/core/browser/ui/region_combobox_model.h6
-rw-r--r--chromium/components/autofill/core/browser/ui/region_combobox_model_unittest.cc4
-rw-r--r--chromium/components/autofill/core/browser/ui/suggestion.h18
-rw-r--r--chromium/components/autofill/core/browser/ui/touch_to_fill_delegate.h19
-rw-r--r--chromium/components/autofill/core/browser/validation.cc25
-rw-r--r--chromium/components/autofill/core/browser/validation_unittest.cc27
-rw-r--r--chromium/components/autofill/core/browser/webdata/autocomplete_sync_bridge_unittest.cc4
-rw-r--r--chromium/components/autofill/core/browser/webdata/autofill_change.h2
-rw-r--r--chromium/components/autofill/core/browser/webdata/autofill_profile_sync_bridge_unittest.cc4
-rw-r--r--chromium/components/autofill/core/browser/webdata/autofill_table.cc3552
-rw-r--r--chromium/components/autofill/core/browser/webdata/autofill_table.h62
-rw-r--r--chromium/components/autofill/core/browser/webdata/autofill_table_unittest.cc86
-rw-r--r--chromium/components/autofill/core/browser/webdata/autofill_wallet_metadata_sync_bridge_unittest.cc2
-rw-r--r--chromium/components/autofill/core/browser/webdata/autofill_wallet_offer_sync_bridge.cc3
-rw-r--r--chromium/components/autofill/core/browser/webdata/autofill_wallet_offer_sync_bridge_unittest.cc2
-rw-r--r--chromium/components/autofill/core/browser/webdata/autofill_wallet_sync_bridge_unittest.cc4
-rw-r--r--chromium/components/autofill/core/browser/webdata/autofill_webdata_backend_impl.cc68
-rw-r--r--chromium/components/autofill/core/browser/webdata/autofill_webdata_backend_impl.h13
-rw-r--r--chromium/components/autofill/core/browser/webdata/autofill_webdata_service.cc27
-rw-r--r--chromium/components/autofill/core/browser/webdata/autofill_webdata_service.h17
-rw-r--r--chromium/components/autofill/core/browser/webdata/autofill_webdata_service_observer.h4
-rw-r--r--chromium/components/autofill/core/common/BUILD.gn11
-rw-r--r--chromium/components/autofill/core/common/autocomplete_parsing_util.cc297
-rw-r--r--chromium/components/autofill/core/common/autocomplete_parsing_util.h55
-rw-r--r--chromium/components/autofill/core/common/autocomplete_parsing_util_unittest.cc103
-rw-r--r--chromium/components/autofill/core/common/autofill_features.cc82
-rw-r--r--chromium/components/autofill/core/common/autofill_features.h18
-rw-r--r--chromium/components/autofill/core/common/autofill_internals/log_message_unittest.cc2
-rw-r--r--chromium/components/autofill/core/common/autofill_internals/logging_scope_unittest.cc2
-rw-r--r--chromium/components/autofill/core/common/autofill_l10n_util.cc4
-rw-r--r--chromium/components/autofill/core/common/autofill_l10n_util_unittest.cc35
-rw-r--r--chromium/components/autofill/core/common/autofill_payments_features.cc50
-rw-r--r--chromium/components/autofill/core/common/autofill_payments_features.h13
-rw-r--r--chromium/components/autofill/core/common/autofill_prefs.cc28
-rw-r--r--chromium/components/autofill/core/common/autofill_prefs.h8
-rw-r--r--chromium/components/autofill/core/common/autofill_prefs_unittest.cc79
-rw-r--r--chromium/components/autofill/core/common/autofill_regex_constants.h (renamed from chromium/components/autofill/core/browser/autofill_regex_constants.cc)177
-rw-r--r--chromium/components/autofill/core/common/autofill_regexes.cc96
-rw-r--r--chromium/components/autofill/core/common/autofill_regexes.h87
-rw-r--r--chromium/components/autofill/core/common/autofill_regexes_unittest.cc (renamed from chromium/components/autofill/core/browser/autofill_regexes_unittest.cc)66
-rw-r--r--chromium/components/autofill/core/common/autofill_util.h5
-rw-r--r--chromium/components/autofill/core/common/form_data.h17
-rw-r--r--chromium/components/autofill/core/common/form_field_data.cc139
-rw-r--r--chromium/components/autofill/core/common/form_field_data.h150
-rw-r--r--chromium/components/autofill/core/common/html_field_types.cc23
-rw-r--r--chromium/components/autofill/core/common/html_field_types.h115
-rw-r--r--chromium/components/autofill/core/common/logging/log_buffer.cc92
-rw-r--r--chromium/components/autofill/core/common/logging/log_buffer.h60
-rw-r--r--chromium/components/autofill/core/common/logging/log_buffer_unittest.cc46
-rw-r--r--chromium/components/autofill/core/common/logging/log_macros.h52
-rw-r--r--chromium/components/autofill/core/common/mojom/BUILD.gn4
-rw-r--r--chromium/components/autofill/core/common/mojom/autofill_types.mojom39
-rw-r--r--chromium/components/autofill/core/common/mojom/autofill_types_mojom_traits.cc93
-rw-r--r--chromium/components/autofill/core/common/mojom/autofill_types_mojom_traits.h86
-rw-r--r--chromium/components/autofill/core/common/mojom/autofill_types_mojom_traits_unittest.cc67
-rw-r--r--chromium/components/autofill/core/common/mojom/test_autofill_types.mojom1
-rw-r--r--chromium/components/autofill/ios/browser/autofill_agent.mm94
-rw-r--r--chromium/components/autofill/ios/browser/autofill_agent_unittests.mm12
-rw-r--r--chromium/components/autofill/ios/browser/autofill_driver_ios.h3
-rw-r--r--chromium/components/autofill/ios/browser/autofill_driver_ios.mm12
-rw-r--r--chromium/components/autofill/ios/browser/autofill_java_script_feature.h45
-rw-r--r--chromium/components/autofill/ios/browser/autofill_java_script_feature.mm22
-rw-r--r--chromium/components/autofill/ios/browser/autofill_util.h7
-rw-r--r--chromium/components/autofill/ios/browser/autofill_util.mm135
-rw-r--r--chromium/components/autofill/ios/browser/resources/autofill_controller.js4
-rw-r--r--chromium/components/autofill/ios/browser/resources/suggestion_controller.js2
-rw-r--r--chromium/components/autofill/ios/form_util/resources/fill.js77
-rw-r--r--chromium/components/autofill/ios/form_util/resources/form_handlers.js8
338 files changed, 16931 insertions, 12653 deletions
diff --git a/chromium/components/autofill/DEPS b/chromium/components/autofill/DEPS
index 51fd81751ef..a89377bb4b1 100644
--- a/chromium/components/autofill/DEPS
+++ b/chromium/components/autofill/DEPS
@@ -1,4 +1,5 @@
include_rules = [
+ "+components/autofill_assistant/core/public/autofill_assistant_intent.h",
"+components/autofill/android/jni_headers",
"+components/prefs",
"+components/strings/grit/components_strings.h",
diff --git a/chromium/components/autofill/PRESUBMIT.py b/chromium/components/autofill/PRESUBMIT.py
index 68d395017f8..f98de555916 100644
--- a/chromium/components/autofill/PRESUBMIT.py
+++ b/chromium/components/autofill/PRESUBMIT.py
@@ -92,6 +92,7 @@ def _CheckWebViewExposedExperiments(input_api, output_api):
_PRODUCTION_SUPPORT_FILE = ('android_webview/java/src/org/chromium/' +
'android_webview/common/ProductionSupportedFlagList.java')
+ _GENERATE_FLAG_LABELS_PY = 'android_webview/tools/generate_flag_labels.py'
def is_autofill_features_file(f):
return (f.LocalPath().startswith('components/autofill/') and
@@ -106,9 +107,12 @@ def _CheckWebViewExposedExperiments(input_api, output_api):
warnings = []
if (any_file_matches(is_autofill_features_file)
and not any_file_matches(is_webview_features_file)):
- warnings += [ output_api.PresubmitPromptWarning(
- 'You may need to modify {} if your feature affects WebView.'
- .format(_PRODUCTION_SUPPORT_FILE)) ]
+ warnings += [
+ output_api.PresubmitPromptWarning((
+ 'You may need to modify {} and run {} and follow its '+
+ 'instructions if your feature affects WebView.'
+ ).format(_PRODUCTION_SUPPORT_FILE, _GENERATE_FLAG_LABELS_PY))
+ ]
return warnings
diff --git a/chromium/components/autofill/content/browser/BUILD.gn b/chromium/components/autofill/content/browser/BUILD.gn
index f4478af4054..4e660b6503e 100644
--- a/chromium/components/autofill/content/browser/BUILD.gn
+++ b/chromium/components/autofill/content/browser/BUILD.gn
@@ -37,6 +37,7 @@ static_library("browser") {
deps = [
"//base",
"//base:i18n",
+ "//components/autofill_assistant/core/public:public",
"//components/os_crypt",
"//components/prefs",
"//components/profile_metrics",
@@ -80,9 +81,13 @@ source_set("test_support") {
"content_autofill_router_test_api.h",
"form_forest_test_api.cc",
"form_forest_test_api.h",
+ "test_autofill_manager_injector.h",
]
- public_deps = [ ":browser" ]
+ public_deps = [
+ ":browser",
+ "//content/public/browser",
+ ]
deps = [ "//base" ]
}
diff --git a/chromium/components/autofill/content/browser/autofill_internals_log_router_unittest.cc b/chromium/components/autofill/content/browser/autofill_internals_log_router_unittest.cc
index 186c2fdb381..65bdc6a597d 100644
--- a/chromium/components/autofill/content/browser/autofill_internals_log_router_unittest.cc
+++ b/chromium/components/autofill/content/browser/autofill_internals_log_router_unittest.cc
@@ -23,7 +23,7 @@ class MockLogReceiver : public autofill::LogReceiver {
public:
MockLogReceiver() {}
- MOCK_METHOD(void, LogEntry, (const base::Value&), (override));
+ MOCK_METHOD(void, LogEntry, (const base::Value::Dict&), (override));
};
} // namespace
@@ -53,10 +53,10 @@ TEST_F(AutofillLogRouterFactoryTest, ServiceActiveNonIncognito) {
testing::StrictMock<MockLogReceiver> receiver;
ASSERT_TRUE(log_router);
- EXPECT_EQ(std::vector<base::Value>(),
- log_router->RegisterReceiver(&receiver));
+ log_router->RegisterReceiver(&receiver);
- base::Value log_entry = autofill::LogRouter::CreateEntryForText(kTestText);
+ base::Value::Dict log_entry =
+ autofill::LogRouter::CreateEntryForText(kTestText);
EXPECT_CALL(receiver, LogEntry(testing::Eq(testing::ByRef(log_entry))))
.Times(1);
log_router->ProcessLog(kTestText);
diff --git a/chromium/components/autofill/content/browser/content_autofill_driver.cc b/chromium/components/autofill/content/browser/content_autofill_driver.cc
index 3e47876252d..8c12f8b8339 100644
--- a/chromium/components/autofill/content/browser/content_autofill_driver.cc
+++ b/chromium/components/autofill/content/browser/content_autofill_driver.cc
@@ -79,6 +79,10 @@ bool ContentAutofillDriver::IsIncognito() const {
->IsOffTheRecord();
}
+bool ContentAutofillDriver::IsInActiveFrame() const {
+ return render_frame_host_->IsActive();
+}
+
bool ContentAutofillDriver::IsInAnyMainFrame() const {
return render_frame_host_->GetMainFrame() == render_frame_host_;
}
@@ -111,17 +115,6 @@ bool ContentAutofillDriver::RendererIsAvailable() {
return render_frame_host_->GetRenderViewHost() != nullptr;
}
-webauthn::InternalAuthenticator*
-ContentAutofillDriver::GetOrCreateCreditCardInternalAuthenticator() {
- if (!authenticator_impl_ && autofill_manager_ &&
- autofill_manager_->client()) {
- authenticator_impl_ =
- autofill_manager_->client()->CreateCreditCardInternalAuthenticator(
- render_frame_host_);
- }
- return authenticator_impl_.get();
-}
-
void ContentAutofillDriver::PopupHidden() {
// If the unmask prompt is shown, keep showing the preview. The preview
// will be cleared when the prompt closes.
@@ -167,11 +160,6 @@ void ContentAutofillDriver::FillOrPreviewFormImpl(
GetAutofillAgent()->FillOrPreviewForm(query_id, data, action);
}
-void ContentAutofillDriver::HandleParsedForms(
- const std::vector<const FormData*>& forms) {
- // No op.
-}
-
void ContentAutofillDriver::SendAutofillTypePredictionsToRendererImpl(
const std::vector<FormDataPredictions>& type_predictions) {
if (!RendererIsAvailable())
@@ -331,13 +319,13 @@ void ContentAutofillDriver::SelectControlDidChangeImpl(
}
void ContentAutofillDriver::AskForValuesToFillImpl(
- int32_t query_id,
const FormData& form,
const FormFieldData& field,
const gfx::RectF& bounding_box,
+ int32_t query_id,
bool autoselect_first_suggestion,
TouchToFillEligible touch_to_fill_eligible) {
- autofill_manager_->OnAskForValuesToFill(query_id, form, field, bounding_box,
+ autofill_manager_->OnAskForValuesToFill(form, field, bounding_box, query_id,
autoselect_first_suggestion,
touch_to_fill_eligible);
}
@@ -374,24 +362,27 @@ void ContentAutofillDriver::DidEndTextFieldEditingImpl() {
void ContentAutofillDriver::SelectFieldOptionsDidChangeImpl(
const FormData& form) {
- autofill_manager_->SelectFieldOptionsDidChange(form);
+ autofill_manager_->OnSelectFieldOptionsDidChange(form);
}
void ContentAutofillDriver::JavaScriptChangedAutofilledValueImpl(
const FormData& form,
const FormFieldData& field,
const std::u16string& old_value) {
- autofill_manager_->JavaScriptChangedAutofilledValue(form, field, old_value);
+ autofill_manager_->OnJavaScriptChangedAutofilledValue(form, field, old_value);
}
void ContentAutofillDriver::FillFormForAssistantImpl(
const AutofillableData& fill_data,
const FormData& form,
- const FormFieldData& field) {
+ const FormFieldData& field,
+ const autofill_assistant::AutofillAssistantIntent intent) {
DCHECK(autofill_manager_);
if (fill_data.is_profile()) {
+ autofill_manager_->SetProfileFillViaAutofillAssistantIntent(intent);
autofill_manager_->FillProfileForm(fill_data.profile(), form, field);
} else if (fill_data.is_credit_card()) {
+ autofill_manager_->SetCreditCardFillViaAutofillAssistantIntent(intent);
autofill_manager_->FillCreditCardForm(
/*query_id=*/kNoQueryId, form, field, fill_data.credit_card(),
fill_data.cvc());
@@ -487,10 +478,10 @@ void ContentAutofillDriver::SelectControlDidChange(
}
void ContentAutofillDriver::AskForValuesToFill(
- int32_t query_id,
const FormData& raw_form,
const FormFieldData& raw_field,
const gfx::RectF& bounding_box,
+ int32_t query_id,
bool autoselect_first_suggestion,
TouchToFillEligible touch_to_fill_eligible) {
if (!bad_message::CheckFrameNotPrerendering(render_frame_host_))
@@ -499,8 +490,8 @@ void ContentAutofillDriver::AskForValuesToFill(
FormFieldData field = raw_field;
SetFrameAndFormMetaData(form, &field);
GetAutofillRouter().AskForValuesToFill(
- this, query_id, form, field,
- TransformBoundingBoxToViewportCoordinates(bounding_box),
+ this, form, field,
+ TransformBoundingBoxToViewportCoordinates(bounding_box), query_id,
autoselect_first_suggestion, touch_to_fill_eligible);
}
@@ -573,11 +564,13 @@ void ContentAutofillDriver::JavaScriptChangedAutofilledValue(
void ContentAutofillDriver::FillFormForAssistant(
const AutofillableData& fill_data,
const FormData& raw_form,
- const FormFieldData& raw_field) {
+ const FormFieldData& raw_field,
+ const autofill_assistant::AutofillAssistantIntent intent) {
FormData form = raw_form;
FormFieldData field = raw_field;
SetFrameAndFormMetaData(form, &field);
- GetAutofillRouter().FillFormForAssistant(this, fill_data, form, field);
+ GetAutofillRouter().FillFormForAssistant(this, fill_data, form, field,
+ intent);
}
void ContentAutofillDriver::DidNavigateFrame(
diff --git a/chromium/components/autofill/content/browser/content_autofill_driver.h b/chromium/components/autofill/content/browser/content_autofill_driver.h
index ab8995b1cee..fc6caef891f 100644
--- a/chromium/components/autofill/content/browser/content_autofill_driver.h
+++ b/chromium/components/autofill/content/browser/content_autofill_driver.h
@@ -17,7 +17,7 @@
#include "components/autofill/core/browser/autofill_driver.h"
#include "components/autofill/core/browser/autofill_manager.h"
#include "components/autofill/core/common/form_data_predictions.h"
-#include "components/webauthn/core/browser/internal_authenticator.h"
+#include "components/autofill_assistant/core/public/autofill_assistant_intent.h"
#include "content/public/browser/render_frame_host.h"
#include "content/public/browser/render_widget_host.h"
#include "mojo/public/cpp/bindings/associated_receiver.h"
@@ -133,15 +133,14 @@ class ContentAutofillDriver : public AutofillDriver,
// AutofillDriver:
bool IsIncognito() const override;
+ bool IsInActiveFrame() const override;
bool IsInAnyMainFrame() const override;
bool IsPrerendering() const override;
bool CanShowAutofillUi() const override;
ui::AXTreeID GetAxTreeId() const override;
scoped_refptr<network::SharedURLLoaderFactory> GetURLLoaderFactory() override;
bool RendererIsAvailable() override;
- webauthn::InternalAuthenticator* GetOrCreateCreditCardInternalAuthenticator()
- override;
- void HandleParsedForms(const std::vector<const FormData*>& forms) override;
+ void HandleParsedForms(const std::vector<FormData>& forms) override {}
void PopupHidden() override;
net::IsolationInfo IsolationInfo() override;
@@ -221,10 +220,10 @@ class ContentAutofillDriver : public AutofillDriver,
void SelectControlDidChange(const FormData& form,
const FormFieldData& field,
const gfx::RectF& bounding_box) override;
- void AskForValuesToFill(int32_t query_id,
- const FormData& form,
+ void AskForValuesToFill(const FormData& form,
const FormFieldData& field,
const gfx::RectF& bounding_box,
+ int32_t query_id,
bool autoselect_first_suggestion,
TouchToFillEligible touch_to_fill_eligible) override;
void HidePopup() override;
@@ -260,10 +259,10 @@ class ContentAutofillDriver : public AutofillDriver,
void SelectControlDidChangeImpl(const FormData& form,
const FormFieldData& field,
const gfx::RectF& bounding_box);
- void AskForValuesToFillImpl(int32_t query_id,
- const FormData& form,
+ void AskForValuesToFillImpl(const FormData& form,
const FormFieldData& field,
const gfx::RectF& bounding_box,
+ int32_t query_id,
bool autoselect_first_suggestion,
TouchToFillEligible touch_to_fill_eligible);
void HidePopupImpl();
@@ -288,14 +287,16 @@ class ContentAutofillDriver : public AutofillDriver,
// FillFormForAssistant() is located in ContentAutofillDriver so that
// |raw_form| and |raw_field| get their meta data set analogous to
// AskForValuesToFill().
- // TODO(crbug/1224094): Migrate Autofill Assistant to the standard Autofill
- // flow.
- void FillFormForAssistant(const AutofillableData& fill_data,
- const FormData& raw_form,
- const FormFieldData& raw_field);
- void FillFormForAssistantImpl(const AutofillableData& fill_data,
- const FormData& form,
- const FormFieldData& field);
+ void FillFormForAssistant(
+ const AutofillableData& fill_data,
+ const FormData& raw_form,
+ const FormFieldData& raw_field,
+ const autofill_assistant::AutofillAssistantIntent intent);
+ void FillFormForAssistantImpl(
+ const AutofillableData& fill_data,
+ const FormData& form,
+ const FormFieldData& fiel,
+ const autofill_assistant::AutofillAssistantIntent intent);
// Transform bounding box coordinates to real viewport coordinates. In the
// case of a page spanning multiple renderer processes, subframe renderers
@@ -384,9 +385,6 @@ class ContentAutofillDriver : public AutofillDriver,
// code.
std::unique_ptr<AutofillManager> autofill_manager_ = nullptr;
- // Pointer to an implementation of InternalAuthenticator.
- std::unique_ptr<webauthn::InternalAuthenticator> authenticator_impl_;
-
content::RenderWidgetHost::KeyPressEventCallback key_press_handler_;
mojo::AssociatedReceiver<mojom::AutofillDriver> receiver_{this};
diff --git a/chromium/components/autofill/content/browser/content_autofill_driver_factory.cc b/chromium/components/autofill/content/browser/content_autofill_driver_factory.cc
index 7992fb1794d..85785d46cd5 100644
--- a/chromium/components/autofill/content/browser/content_autofill_driver_factory.cc
+++ b/chromium/components/autofill/content/browser/content_autofill_driver_factory.cc
@@ -160,8 +160,8 @@ void ContentAutofillDriverFactory::RenderFrameDeleted(
ContentAutofillDriver* driver = it->second.get();
DCHECK(driver);
- if (render_frame_host->GetLifecycleState() !=
- content::RenderFrameHost::LifecycleState::kPrerendering &&
+ if (!render_frame_host->IsInLifecycleState(
+ content::RenderFrameHost::LifecycleState::kPrerendering) &&
driver->autofill_manager()) {
driver->autofill_manager()->ReportAutofillWebOTPMetrics(
render_frame_host->DocumentUsedWebOTP());
@@ -174,8 +174,8 @@ void ContentAutofillDriverFactory::RenderFrameDeleted(
// and therefore won't close the popup.
bool is_iframe = !driver->IsInAnyMainFrame();
if (is_iframe && router_.last_queried_source() == driver) {
- DCHECK_NE(content::RenderFrameHost::LifecycleState::kPrerendering,
- render_frame_host->GetLifecycleState());
+ DCHECK(!render_frame_host->IsInLifecycleState(
+ content::RenderFrameHost::LifecycleState::kPrerendering));
router_.HidePopup(driver);
}
@@ -208,8 +208,11 @@ void ContentAutofillDriverFactory::DidFinishNavigation(
navigation_handle->HasSubframeNavigationEntryCommitted())) {
if (auto* driver =
DriverForFrame(navigation_handle->GetRenderFrameHost())) {
- if (!navigation_handle->IsInPrerenderedMainFrame())
+ if (!navigation_handle->IsInPrerenderedMainFrame()) {
client_->HideAutofillPopup(PopupHidingReason::kNavigation);
+ if (client_->IsTouchToFillCreditCardSupported())
+ client_->HideTouchToFillCreditCard();
+ }
driver->DidNavigateFrame(navigation_handle);
}
}
@@ -217,29 +220,10 @@ void ContentAutofillDriverFactory::DidFinishNavigation(
void ContentAutofillDriverFactory::OnVisibilityChanged(
content::Visibility visibility) {
- if (visibility == content::Visibility::HIDDEN)
+ if (visibility == content::Visibility::HIDDEN) {
client_->HideAutofillPopup(PopupHidingReason::kTabGone);
-}
-
-void ContentAutofillDriverFactory::ReadyToCommitNavigation(
- content::NavigationHandle* navigation_handle) {
- content::RenderFrameHost* render_frame_host =
- navigation_handle->GetRenderFrameHost();
- content::GlobalRenderFrameHostId render_frame_host_id(
- render_frame_host->GetProcess()->GetID(),
- render_frame_host->GetRoutingID());
- // No need to report the metrics here if navigating to a different
- // RenderFrameHost. It will be reported in |RenderFrameDeleted|.
- // TODO(crbug.com/936696): Remove this logic when RenderDocument is enabled
- // everywhere.
- if (render_frame_host_id !=
- navigation_handle->GetPreviousRenderFrameHostId()) {
- return;
- }
- // Do not report metrics if prerendering.
- if (render_frame_host->GetLifecycleState() ==
- content::RenderFrameHost::LifecycleState::kPrerendering) {
- return;
+ if (client_->IsTouchToFillCreditCardSupported())
+ client_->HideTouchToFillCreditCard();
}
}
diff --git a/chromium/components/autofill/content/browser/content_autofill_driver_factory.h b/chromium/components/autofill/content/browser/content_autofill_driver_factory.h
index 33aa10fa79b..fc52dfc2923 100644
--- a/chromium/components/autofill/content/browser/content_autofill_driver_factory.h
+++ b/chromium/components/autofill/content/browser/content_autofill_driver_factory.h
@@ -78,8 +78,6 @@ class ContentAutofillDriverFactory : public content::WebContentsObserver,
void DidFinishNavigation(
content::NavigationHandle* navigation_handle) override;
void OnVisibilityChanged(content::Visibility visibility) override;
- void ReadyToCommitNavigation(
- content::NavigationHandle* navigation_handle) override;
AutofillClient* client() { return client_; }
diff --git a/chromium/components/autofill/content/browser/content_autofill_driver_factory_unittest.cc b/chromium/components/autofill/content/browser/content_autofill_driver_factory_unittest.cc
index cae01dbd367..b17c0448468 100644
--- a/chromium/components/autofill/content/browser/content_autofill_driver_factory_unittest.cc
+++ b/chromium/components/autofill/content/browser/content_autofill_driver_factory_unittest.cc
@@ -16,6 +16,7 @@
#include "components/autofill/core/browser/test_autofill_driver.h"
#include "components/autofill/core/common/autofill_features.h"
#include "content/public/browser/render_frame_host.h"
+#include "content/public/browser/web_contents.h"
#include "content/public/common/content_features.h"
#include "content/public/test/navigation_simulator.h"
#include "content/public/test/test_renderer_host.h"
diff --git a/chromium/components/autofill/content/browser/content_autofill_router.cc b/chromium/components/autofill/content/browser/content_autofill_router.cc
index 3b8038f0caa..a507bb05f5e 100644
--- a/chromium/components/autofill/content/browser/content_autofill_router.cc
+++ b/chromium/components/autofill/content/browser/content_autofill_router.cc
@@ -349,14 +349,14 @@ void ContentAutofillRouter::SelectControlDidChange(
void ContentAutofillRouter::AskForValuesToFill(
ContentAutofillDriver* source,
- int32_t query_id,
const FormData& form,
const FormFieldData& field,
const gfx::RectF& bounding_box,
+ int32_t query_id,
bool autoselect_first_suggestion,
TouchToFillEligible touch_to_fill_eligible) {
if (!base::FeatureList::IsEnabled(features::kAutofillAcrossIframes)) {
- source->AskForValuesToFillImpl(query_id, form, field, bounding_box,
+ source->AskForValuesToFillImpl(form, field, bounding_box, query_id,
autoselect_first_suggestion,
touch_to_fill_eligible);
return;
@@ -374,7 +374,7 @@ void ContentAutofillRouter::AskForValuesToFill(
AFCHECK(target, return );
SetLastQueriedSource(source);
SetLastQueriedTarget(target);
- target->AskForValuesToFillImpl(query_id, browser_form, field, bounding_box,
+ target->AskForValuesToFillImpl(browser_form, field, bounding_box, query_id,
autoselect_first_suggestion,
touch_to_fill_eligible);
}
@@ -559,9 +559,10 @@ void ContentAutofillRouter::FillFormForAssistant(
ContentAutofillDriver* source,
const AutofillableData& fill_data,
const FormData& form,
- const FormFieldData& field) {
+ const FormFieldData& field,
+ const autofill_assistant::AutofillAssistantIntent intent) {
if (!base::FeatureList::IsEnabled(features::kAutofillAcrossIframes)) {
- source->FillFormForAssistantImpl(fill_data, form, field);
+ source->FillFormForAssistantImpl(fill_data, form, field, intent);
return;
}
@@ -577,7 +578,7 @@ void ContentAutofillRouter::FillFormForAssistant(
AFCHECK(target, return );
SetLastQueriedSource(source);
SetLastQueriedTarget(target);
- target->FillFormForAssistantImpl(fill_data, form, field);
+ target->FillFormForAssistantImpl(fill_data, form, field, intent);
}
// Routing of events triggered by the browser.
diff --git a/chromium/components/autofill/content/browser/content_autofill_router.h b/chromium/components/autofill/content/browser/content_autofill_router.h
index 61d97cdc6ea..72ec08667f1 100644
--- a/chromium/components/autofill/content/browser/content_autofill_router.h
+++ b/chromium/components/autofill/content/browser/content_autofill_router.h
@@ -16,6 +16,7 @@
#include "components/autofill/core/common/form_data.h"
#include "components/autofill/core/common/form_data_predictions.h"
#include "components/autofill/core/common/form_field_data.h"
+#include "components/autofill_assistant/core/public/autofill_assistant_intent.h"
#include "content/public/browser/render_frame_host.h"
#include "content/public/browser/render_widget_host.h"
#include "third_party/abseil-cpp/absl/types/optional.h"
@@ -189,10 +190,10 @@ class ContentAutofillRouter {
const FormFieldData& field,
const gfx::RectF& bounding_box);
void AskForValuesToFill(ContentAutofillDriver* source_driver,
- int32_t query_id,
const FormData& form,
const FormFieldData& field,
const gfx::RectF& bounding_box,
+ int32_t query_id,
bool autoselect_first_suggestion,
TouchToFillEligible touch_to_fill_eligible);
void HidePopup(ContentAutofillDriver* source_driver);
@@ -215,10 +216,12 @@ class ContentAutofillRouter {
const std::u16string& old_value);
// Event called by Autofill Assistant as if it was called by the renderer.
- void FillFormForAssistant(ContentAutofillDriver* source_driver,
- const AutofillableData& fill_data,
- const FormData& form,
- const FormFieldData& field);
+ void FillFormForAssistant(
+ ContentAutofillDriver* source_driver,
+ const AutofillableData& fill_data,
+ const FormData& form,
+ const FormFieldData& field,
+ const autofill_assistant::AutofillAssistantIntent intent);
// Routing of events called by the browser:
std::vector<FieldGlobalId> FillOrPreviewForm(
diff --git a/chromium/components/autofill/content/browser/form_forest_unittest.cc b/chromium/components/autofill/content/browser/form_forest_unittest.cc
index 0e20d765940..5f8d31fea4a 100644
--- a/chromium/components/autofill/content/browser/form_forest_unittest.cc
+++ b/chromium/components/autofill/content/browser/form_forest_unittest.cc
@@ -10,8 +10,10 @@
#include <utility>
#include <vector>
+#include "base/containers/contains.h"
#include "base/strings/strcat.h"
#include "base/strings/string_piece.h"
+#include "base/strings/utf_string_conversions.h"
#include "base/test/scoped_feature_list.h"
#include "components/autofill/content/browser/form_forest.h"
#include "components/autofill/content/browser/form_forest_test_api.h"
@@ -23,6 +25,7 @@
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/blink/public/common/permissions_policy/permissions_policy.h"
+#include "third_party/blink/public/mojom/permissions_policy/permissions_policy.mojom-shared.h"
using FrameData = autofill::internal::FormForest::FrameData;
using FrameDataSet =
@@ -147,6 +150,7 @@ auto CreateFieldTypeMap(const FormData& form) {
// A profile is a 6-bit integer, whose bits indicate different values of first
// and last name, credit card number, expiration month, expiration year, CVC.
using Profile = base::StrongAlias<struct ProfileTag, size_t>;
+using ::autofill::test::WithoutValues;
// Fills the fields 0..5 of |form| with data according to |profile|, the
// fields 6..11 with |profile|+1, etc.
@@ -166,13 +170,6 @@ FormData WithValues(FormData& form, Profile profile = Profile(0)) {
return form;
}
-// Clears the values of all fields in |form|.
-FormData WithoutValues(FormData form) {
- for (FormFieldData& field : form.fields)
- field.value.clear();
- return form;
-}
-
// Utility functions and constants.
// Use strings for non-opaque origins and URLs because constructors must not be
diff --git a/chromium/components/autofill/content/browser/risk/fingerprint.cc b/chromium/components/autofill/content/browser/risk/fingerprint.cc
index 9b474a64008..b20c65da8fa 100644
--- a/chromium/components/autofill/content/browser/risk/fingerprint.cc
+++ b/chromium/components/autofill/content/browser/risk/fingerprint.cc
@@ -88,14 +88,14 @@ std::string GetOperatingSystemVersion() {
}
// Adds the list of |fonts| to the |machine|.
-void AddFontsToFingerprint(const base::ListValue& fonts,
+void AddFontsToFingerprint(const base::Value::List& fonts,
Fingerprint::MachineCharacteristics* machine) {
- for (const auto& it : fonts.GetListDeprecated()) {
+ for (const auto& it : fonts) {
// Each item in the list is a two-element list such that the first element
// is the font family and the second is the font name.
DCHECK(it.is_list());
- std::string font_name = it.GetListDeprecated()[1].GetString();
+ std::string font_name = it.GetList()[1].GetString();
machine->add_font(font_name);
}
@@ -203,7 +203,7 @@ class FingerprintDataLoader : public content::GpuDataManagerObserver {
void OnGpuInfoUpdate() override;
// Callbacks for asynchronously loaded data.
- void OnGotFonts(std::unique_ptr<base::ListValue> fonts);
+ void OnGotFonts(base::Value::List fonts);
void OnGotPlugins(const std::vector<content::WebPluginInfo>& plugins);
void OnGotGeoposition(device::mojom::GeopositionPtr geoposition);
@@ -238,7 +238,7 @@ class FingerprintDataLoader : public content::GpuDataManagerObserver {
const base::Time install_time_;
// Data that will be loaded asynchronously.
- std::unique_ptr<base::ListValue> fonts_;
+ std::unique_ptr<base::Value::List> fonts_;
std::vector<content::WebPluginInfo> plugins_;
bool waiting_on_plugins_;
device::mojom::Geoposition geoposition_;
@@ -329,9 +329,9 @@ void FingerprintDataLoader::OnGpuInfoUpdate() {
MaybeFillFingerprint();
}
-void FingerprintDataLoader::OnGotFonts(std::unique_ptr<base::ListValue> fonts) {
+void FingerprintDataLoader::OnGotFonts(base::Value::List fonts) {
DCHECK(!fonts_);
- fonts_ = std::move(fonts);
+ fonts_ = std::make_unique<base::Value::List>(std::move(fonts));
MaybeFillFingerprint();
}
diff --git a/chromium/components/autofill/content/browser/test_autofill_manager_injector.h b/chromium/components/autofill/content/browser/test_autofill_manager_injector.h
new file mode 100644
index 00000000000..733bae614bf
--- /dev/null
+++ b/chromium/components/autofill/content/browser/test_autofill_manager_injector.h
@@ -0,0 +1,82 @@
+// Copyright 2022 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_CONTENT_BROWSER_TEST_AUTOFILL_MANAGER_INJECTOR_H_
+#define COMPONENTS_AUTOFILL_CONTENT_BROWSER_TEST_AUTOFILL_MANAGER_INJECTOR_H_
+
+#include "components/autofill/content/browser/content_autofill_driver.h"
+#include "components/autofill/content/browser/content_autofill_driver_factory.h"
+#include "components/autofill/core/browser/autofill_client.h"
+#include "content/public/browser/navigation_handle.h"
+#include "content/public/browser/web_contents.h"
+#include "content/public/browser/web_contents_observer.h"
+
+namespace autofill {
+
+// Upon construction, and in response to ReadyToCommitNavigation, installs an
+// AutofillManager of type `T`.
+//
+// Typical usage as a RAII type:
+//
+// class MockAutofillManager : BrowserAutofillManager {
+// public:
+// MockAutofillManager(ContentAutofillDriver* driver,
+// AutofillClient* client)
+// : BrowserAutofillManager(driver, client, "en-US",
+// EnableDownloadManager(true)) {}
+// MOCK_METHOD(...);
+// ...
+// };
+//
+// TestAutofillManagerInjector<MockAutofillManager> injector(web_contents());
+// NavigateToURL(...);
+template <typename T>
+class TestAutofillManagerInjector : public content::WebContentsObserver {
+ public:
+ // Builds the managers using `T(ContentAutofillDriver*, AutofillClient*)`.
+ explicit TestAutofillManagerInjector(content::WebContents* web_contents)
+ : WebContentsObserver(web_contents) {
+ Inject(web_contents->GetPrimaryMainFrame());
+ }
+
+ ~TestAutofillManagerInjector() override = default;
+
+ T* GetForPrimaryMainFrame() {
+ return GetForFrame(web_contents()->GetPrimaryMainFrame());
+ }
+
+ T* GetForFrame(content::RenderFrameHost* rfh) {
+ ContentAutofillDriverFactory* driver_factory =
+ ContentAutofillDriverFactory::FromWebContents(web_contents());
+ return static_cast<T*>(
+ driver_factory->DriverForFrame(rfh)->autofill_manager());
+ }
+
+ private:
+ // content::WebContentsObserver:
+ void ReadyToCommitNavigation(
+ content::NavigationHandle* navigation_handle) override {
+ if (!navigation_handle->IsPrerenderedPageActivation() &&
+ !navigation_handle->IsSameDocument()) {
+ Inject(navigation_handle->GetRenderFrameHost());
+ }
+ }
+
+ void Inject(content::RenderFrameHost* rfh) {
+ ContentAutofillDriverFactory* driver_factory =
+ ContentAutofillDriverFactory::FromWebContents(web_contents());
+ AutofillClient* client = driver_factory->client();
+ ContentAutofillDriver* driver = driver_factory->DriverForFrame(rfh);
+ driver->set_autofill_manager(CreateManager(driver, client));
+ }
+
+ std::unique_ptr<T> CreateManager(ContentAutofillDriver* driver,
+ AutofillClient* client) {
+ return std::make_unique<T>(driver, client);
+ }
+};
+
+} // namespace autofill
+
+#endif // COMPONENTS_AUTOFILL_CONTENT_BROWSER_TEST_AUTOFILL_MANAGER_INJECTOR_H_
diff --git a/chromium/components/autofill/content/common/mojom/autofill_driver.mojom b/chromium/components/autofill/content/common/mojom/autofill_driver.mojom
index 5db3e7b4486..e823c14b3f2 100644
--- a/chromium/components/autofill/content/common/mojom/autofill_driver.mojom
+++ b/chromium/components/autofill/content/common/mojom/autofill_driver.mojom
@@ -56,10 +56,10 @@ interface AutofillDriver {
// |touch_to_fill_eligible| indicates if the Touch To Fill surface could
// be used for showing suggestions (e.g. when the user taps an input element
// but not on text change).
- AskForValuesToFill(int32 query_id,
- FormData form,
+ AskForValuesToFill(FormData form,
FormFieldData field,
gfx.mojom.RectF bounding_box,
+ int32 query_id,
bool autoselect_first_suggestion,
TouchToFillEligible touch_to_fill_eligible);
@@ -106,10 +106,8 @@ interface PasswordManagerDriver {
PasswordFormsParsed(array<FormData> forms_data);
// Notification that initial layout has occurred and the following password
- // forms are visible on the page (e.g. not set to display:none.), and whether
- // all frames in the page have been rendered.
- PasswordFormsRendered(array<FormData> visible_forms_data,
- bool did_stop_loading);
+ // forms are visible on the page (e.g. not set to display:none.).
+ PasswordFormsRendered(array<FormData> visible_forms_data);
// Notification that this password form was submitted by the user.
PasswordFormSubmitted(FormData form_data);
diff --git a/chromium/components/autofill/content/renderer/autofill_agent.cc b/chromium/components/autofill/content/renderer/autofill_agent.cc
index 88d7f1dd32f..e9b7331aa6f 100644
--- a/chromium/components/autofill/content/renderer/autofill_agent.cc
+++ b/chromium/components/autofill/content/renderer/autofill_agent.cc
@@ -46,7 +46,6 @@
#include "content/public/common/origin_util.h"
#include "content/public/common/url_constants.h"
#include "content/public/renderer/render_frame.h"
-#include "content/public/renderer/render_view.h"
#include "net/cert/cert_status_flags.h"
#include "services/service_manager/public/cpp/interface_provider.h"
#include "third_party/abseil-cpp/absl/types/optional.h"
@@ -176,14 +175,15 @@ class AutofillAgent::DeferringAutofillDriver : public mojom::AutofillDriver {
void SelectFieldOptionsDidChange(const FormData& form) override {
DeferMsg(&mojom::AutofillDriver::SelectFieldOptionsDidChange, form);
}
- void AskForValuesToFill(int32_t query_id,
- const FormData& form,
+ void AskForValuesToFill(const FormData& form,
const FormFieldData& field,
const gfx::RectF& bounding_box,
+ int32_t query_id,
bool autoselect_first_suggestion,
TouchToFillEligible touch_to_fill_eligible) override {
- DeferMsg(&mojom::AutofillDriver::AskForValuesToFill, query_id, form, field,
- bounding_box, autoselect_first_suggestion, touch_to_fill_eligible);
+ DeferMsg(&mojom::AutofillDriver::AskForValuesToFill, form, field,
+ bounding_box, query_id, autoselect_first_suggestion,
+ touch_to_fill_eligible);
}
void HidePopup() override { DeferMsg(&mojom::AutofillDriver::HidePopup); }
void FocusNoLongerOnForm(bool had_interacted_form) override {
@@ -238,7 +238,7 @@ AutofillAgent::AutofillAgent(content::RenderFrame* render_frame,
render_frame->GetWebFrame()->SetAutofillClient(this);
password_autofill_agent->SetAutofillAgent(this);
AddFormObserver(this);
- registry->AddInterface(base::BindRepeating(
+ registry->AddInterface<mojom::AutofillAgent>(base::BindRepeating(
&AutofillAgent::BindPendingReceiver, base::Unretained(this)));
}
@@ -255,14 +255,7 @@ void AutofillAgent::BindPendingReceiver(
}
void AutofillAgent::DidCommitProvisionalLoad(ui::PageTransition transition) {
- blink::WebFrame* frame = render_frame()->GetWebFrame();
- // TODO(dvadym): check if we need to check if it is main frame navigation
- // http://crbug.com/443155
- if (frame->Parent())
- return; // Not a top-level navigation.
-
// Navigation to a new page or a page refresh.
-
element_.Reset();
form_cache_.Reset();
@@ -295,14 +288,17 @@ void AutofillAgent::DidChangeScrollOffset() {
void AutofillAgent::DidChangeScrollOffsetImpl(
const WebFormControlElement& element) {
- if (element != element_ || element_.IsNull() || focus_requires_scroll_ ||
- !is_popup_possibly_visible_ || !element_.Focused())
+ if (element != element_ || element.IsNull() || focus_requires_scroll_ ||
+ !is_popup_possibly_visible_ || !element.Focused()) {
return;
+ }
+
+ DCHECK(IsOwnedByFrame(element, render_frame()));
FormData form;
FormFieldData field;
if (FindFormAndFieldForFormControlElement(
- element_, field_data_manager_.get(),
+ element, field_data_manager_.get(),
static_cast<ExtractMask>(form_util::EXTRACT_BOUNDS |
GetExtractDatalistMask()),
&form, &field)) {
@@ -323,11 +319,13 @@ void AutofillAgent::FocusedElementChanged(const WebElement& element) {
return;
}
- const WebInputElement input = element.DynamicTo<WebInputElement>();
+ const WebFormControlElement form_control_element =
+ element.DynamicTo<WebFormControlElement>();
bool focus_moved_to_new_form = false;
if (!last_interacted_form_.IsNull() &&
- (input.IsNull() || last_interacted_form_ != input.Form())) {
+ (form_control_element.IsNull() ||
+ last_interacted_form_ != form_control_element.Form())) {
// The focused element is not part of the last interacted form (could be
// in a different form).
GetAutofillDriver().FocusNoLongerOnForm(/*had_interacted_form=*/true);
@@ -349,11 +347,13 @@ void AutofillAgent::FocusedElementChanged(const WebElement& element) {
if (focus_moved_to_new_form)
return;
- if (input.IsNull() || !input.IsEnabled() || input.IsReadOnly() ||
- !input.IsTextField())
+ if (form_control_element.IsNull() || !form_control_element.IsEnabled() ||
+ form_control_element.IsReadOnly() ||
+ !form_util::IsTextAreaElementOrTextInput(form_control_element)) {
return;
+ }
- element_ = input;
+ element_ = form_control_element;
FormData form;
FormFieldData field;
@@ -526,8 +526,8 @@ void AutofillAgent::TriggerRefillIfNeeded(const FormData& form) {
WebLocalFrame* frame = render_frame()->GetWebFrame();
std::vector<FormData> forms;
forms.push_back(updated_form);
- // Always communicate to browser process for topmost frame.
- if (!forms.empty() || !frame->Parent()) {
+ // Always communicate to browser process for the outermost main frame.
+ if (!forms.empty() || frame->IsOutermostMainFrame()) {
GetAutofillDriver().FormsSeen(forms, {});
}
}
@@ -630,9 +630,8 @@ void AutofillAgent::FillFieldWithValue(FieldRendererId field_id,
return;
}
- WebInputElement input_element = element_.DynamicTo<WebInputElement>();
- if (!input_element.IsNull())
- DoFillFieldWithValue(value, input_element, WebAutofillState::kAutofilled);
+ if (form_util::IsTextAreaElementOrTextInput(element_))
+ DoFillFieldWithValue(value, element_, WebAutofillState::kAutofilled);
}
void AutofillAgent::PreviewFieldWithValue(FieldRendererId field_id,
@@ -688,14 +687,7 @@ void AutofillAgent::AcceptDataListSuggestion(
WebInputElement input_element = element_.DynamicTo<WebInputElement>();
if (input_element.IsNull()) {
- // For reasons not understood yet, this is triggered on elements which are
- // not input elements.
-
- // TODO(crbug.com/1048270) Gather debug data.
- DEBUG_ALIAS_FOR_CSTR(element_name, element_.TagName().Latin1().c_str(), 64);
- base::debug::DumpWithoutCrashing();
-
- // Keep this return after removing the TODO(crbug.com/1048270) above.
+ // Early return for non-input fields such as textarea.
return;
}
std::u16string new_value = suggested_value;
@@ -721,7 +713,7 @@ void AutofillAgent::AcceptDataListSuggestion(
new_value = base::JoinString(parts, u",");
}
- DoFillFieldWithValue(new_value, input_element, WebAutofillState::kNotFilled);
+ DoFillFieldWithValue(new_value, element_, WebAutofillState::kNotFilled);
}
void AutofillAgent::FillPasswordSuggestion(const std::u16string& username,
@@ -945,18 +937,24 @@ void AutofillAgent::QueryAutofillSuggestions(
is_popup_possibly_visible_ = true;
GetAutofillDriver().AskForValuesToFill(
- autofill_query_id_, form, field, field.bounds,
+ form, field, field.bounds, autofill_query_id_,
autoselect_first_suggestion, touch_to_fill_eligible);
}
void AutofillAgent::DoFillFieldWithValue(const std::u16string& value,
- WebInputElement& node,
+ blink::WebFormControlElement& element,
WebAutofillState autofill_state) {
- DCHECK(IsOwnedByFrame(node, render_frame()));
+ DCHECK(IsOwnedByFrame(element, render_frame()));
form_tracker_.set_ignore_control_changes(true);
- node.SetAutofillValue(blink::WebString::FromUTF16(value), autofill_state);
- password_autofill_agent_->UpdateStateForTextChange(node);
+
+ element.SetAutofillValue(blink::WebString::FromUTF16(value), autofill_state);
+
+ WebInputElement input_element = element.DynamicTo<WebInputElement>();
+ // `input_element` can be null for textarea elements.
+ if (!input_element.IsNull())
+ password_autofill_agent_->UpdateStateForTextChange(input_element);
+
form_tracker_.set_ignore_control_changes(false);
}
@@ -984,9 +982,9 @@ void AutofillAgent::ProcessForms() {
FormCache::UpdateFormCacheResult cache =
form_cache_.UpdateFormCache(field_data_manager_.get());
- // Always communicate to browser process for topmost frame.
+ // Always communicate to browser process for the outermost main frame.
if (!cache.updated_forms.empty() || !cache.removed_forms.empty() ||
- !render_frame()->GetWebFrame()->Parent()) {
+ render_frame()->GetWebFrame()->IsOutermostMainFrame()) {
GetAutofillDriver().FormsSeen(cache.updated_forms,
std::move(cache.removed_forms).extract());
}
@@ -1155,10 +1153,11 @@ void AutofillAgent::HandleFocusChangeComplete() {
// are used, treat the focused node as if it was the last clicked. Also check
// to ensure focus is on a field where text can be entered.
if ((focused_node_was_last_clicked_ || is_screen_reader_enabled_) &&
- !focused_element.IsNull() && focused_element.IsFormControlElement() &&
- (form_util::IsTextInput(focused_element.DynamicTo<WebInputElement>()) ||
- focused_element.HasHTMLTagName("textarea"))) {
- FormControlElementClicked(focused_element.To<WebFormControlElement>());
+ !focused_element.IsNull() && focused_element.IsFormControlElement()) {
+ WebFormControlElement focused_form_control_element =
+ focused_element.To<WebFormControlElement>();
+ if (form_util::IsTextAreaElementOrTextInput(focused_form_control_element))
+ FormControlElementClicked(focused_form_control_element);
}
focused_node_was_last_clicked_ = false;
@@ -1269,19 +1268,13 @@ void AutofillAgent::OnFormSubmitted(const WebFormElement& form) {
}
void AutofillAgent::OnInferredFormSubmission(SubmissionSource source) {
- // Only handle iframe for FRAME_DETACHED or main frame for
- // SAME_DOCUMENT_NAVIGATION.
- if ((source == SubmissionSource::FRAME_DETACHED &&
- !render_frame()->GetWebFrame()->Parent()) ||
- (source == SubmissionSource::SAME_DOCUMENT_NAVIGATION &&
- render_frame()->GetWebFrame()->Parent())) {
- ResetLastInteractedElements();
- OnFormNoLongerSubmittable();
- SendPotentiallySubmittedFormToBrowser();
- return;
- }
-
- if (source == SubmissionSource::FRAME_DETACHED) {
+ if (source == SubmissionSource::FRAME_DETACHED &&
+ render_frame()->GetWebFrame()->IsOutermostMainFrame()) {
+ // No op.
+ } else if (source == SubmissionSource::SAME_DOCUMENT_NAVIGATION &&
+ !render_frame()->GetWebFrame()->IsOutermostMainFrame()) {
+ // No op.
+ } else if (source == SubmissionSource::FRAME_DETACHED) {
// Should not access the frame because it is now detached. Instead, use
// |provisionally_saved_form_|.
if (provisionally_saved_form_.has_value())
diff --git a/chromium/components/autofill/content/renderer/autofill_agent.h b/chromium/components/autofill/content/renderer/autofill_agent.h
index 4de7f06270c..c2f1e044490 100644
--- a/chromium/components/autofill/content/renderer/autofill_agent.h
+++ b/chromium/components/autofill/content/renderer/autofill_agent.h
@@ -257,9 +257,9 @@ class AutofillAgent : public content::RenderFrameObserver,
void DoAcceptDataListSuggestion(FieldRendererId field_id,
const std::u16string& suggested_value);
- // Set |node| to display the given |value|.
+ // Set `element` to display the given `value`.
void DoFillFieldWithValue(const std::u16string& value,
- blink::WebInputElement& node,
+ blink::WebFormControlElement& element,
blink::WebAutofillState autofill_state);
// Set |node| to display the given |value| as a preview. The preview is
diff --git a/chromium/components/autofill/content/renderer/autofill_agent_browsertest.cc b/chromium/components/autofill/content/renderer/autofill_agent_browsertest.cc
index ecd2e892178..e70e58e345a 100644
--- a/chromium/components/autofill/content/renderer/autofill_agent_browsertest.cc
+++ b/chromium/components/autofill/content/renderer/autofill_agent_browsertest.cc
@@ -92,10 +92,10 @@ class MockAutofillDriver : public mojom::AutofillDriver {
(override));
MOCK_METHOD(void,
AskForValuesToFill,
- (int32_t query_id,
- const FormData& form,
+ (const FormData& form,
const FormFieldData& field,
const gfx::RectF& bounding_box,
+ int32_t query_id,
bool autoselect_first_suggestion,
TouchToFillEligible touch_to_fill_eligible),
(override));
diff --git a/chromium/components/autofill/content/renderer/form_autofill_util.cc b/chromium/components/autofill/content/renderer/form_autofill_util.cc
index d6a787ff5bc..43c4e11fb7f 100644
--- a/chromium/components/autofill/content/renderer/form_autofill_util.cc
+++ b/chromium/components/autofill/content/renderer/form_autofill_util.cc
@@ -20,6 +20,7 @@
#include "base/containers/flat_set.h"
#include "base/i18n/case_conversion.h"
#include "base/metrics/field_trial.h"
+#include "base/metrics/histogram_functions.h"
#include "base/metrics/histogram_macros.h"
#include "base/no_destructor.h"
#include "base/notreached.h"
@@ -253,34 +254,37 @@ std::u16string FindChildTextInner(const WebNode& node,
return std::u16string();
// Ignore elements known not to contain inferable labels.
+ bool skip_node = false;
if (node.IsElementNode()) {
const WebElement element = node.To<WebElement>();
- if (IsOptionElement(element) || IsScriptElement(element) ||
- IsNoScriptElement(element) ||
+ if (IsOptionElement(element) ||
+ (element.HasHTMLTagName("div") && base::Contains(divs_to_skip, node)) ||
(element.IsFormControlElement() &&
IsAutofillableElement(element.To<WebFormControlElement>()))) {
return std::u16string();
}
-
- if (element.HasHTMLTagName("div") && base::Contains(divs_to_skip, node))
- return std::u16string();
+ skip_node = IsScriptElement(element) || IsNoScriptElement(element);
}
- // Extract the text exactly at this node.
- std::u16string node_text = node.NodeValue().Utf16();
+ std::u16string node_text;
- // Recursively compute the children's text.
- // Preserve inter-element whitespace separation.
- std::u16string child_text =
- FindChildTextInner(node.FirstChild(), depth - 1, divs_to_skip);
- bool add_space = node.IsTextNode() && node_text.empty();
- node_text = CombineAndCollapseWhitespace(node_text, child_text, add_space);
+ if (!skip_node) {
+ // Extract the text exactly at this node.
+ node_text = node.NodeValue().Utf16();
+
+ // Recursively compute the children's text.
+ // Preserve inter-element whitespace separation.
+ std::u16string child_text =
+ FindChildTextInner(node.FirstChild(), depth - 1, divs_to_skip);
+ bool add_space = node.IsTextNode() && node_text.empty();
+ node_text = CombineAndCollapseWhitespace(node_text, child_text, add_space);
+ }
// Recursively compute the siblings' text.
// Again, preserve inter-element whitespace separation.
std::u16string sibling_text =
FindChildTextInner(node.NextSibling(), depth - 1, divs_to_skip);
- add_space = node.IsTextNode() && node_text.empty();
+ bool add_space = node.IsTextNode() && node_text.empty();
node_text = CombineAndCollapseWhitespace(node_text, sibling_text, add_space);
return node_text;
@@ -304,21 +308,14 @@ std::u16string FindChildTextWithIgnoreList(
bool IsLabelValid(base::StringPiece16 inferred_label) {
// List of characters a label can't be entirely made of (this list can grow).
- auto IsStopWord = [](char16_t c) {
- switch (c) {
- case u' ':
- case u'*':
- case u':':
- case u'-':
- case u'–': // U+2013
- case u'(':
- case u')':
- return true;
- default:
- return false;
- }
- };
- return !base::ranges::all_of(inferred_label, IsStopWord);
+ const base::StringPiece16 invalid_chars =
+ base::FeatureList::IsEnabled(
+ features::kAutofillConsiderPhoneNumberSeparatorsValidLabels)
+ ? u" *:"
+ : u" *:-–()"; // U+2013 dash
+ return !base::ranges::all_of(inferred_label, [&](char16_t c) {
+ return base::Contains(invalid_chars, c);
+ });
}
// Shared function for InferLabelFromPrevious() and InferLabelFromNext().
@@ -358,8 +355,13 @@ bool InferLabelFromSibling(const WebFormControlElement& element,
// A text node's value will be empty if it is for a line break.
bool add_space = sibling.IsTextNode() && value.empty();
inferred_label_source = FormFieldData::LabelSource::kCombined;
- inferred_label =
- CombineAndCollapseWhitespace(value, inferred_label, add_space);
+ if (forward) {
+ inferred_label =
+ CombineAndCollapseWhitespace(inferred_label, value, add_space);
+ } else {
+ inferred_label =
+ CombineAndCollapseWhitespace(value, inferred_label, add_space);
+ }
continue;
}
@@ -649,8 +651,14 @@ std::u16string InferLabelFromTableRow(const WebNode& cell) {
// e.g. <div>Some Text<span><input ...></span></div>
// e.g. <div>Some Text</div><div><input ...></div>
//
-// Because this is already traversing the <div> structure, if it finds a <label>
-// sibling along the way, infer from that <label>.
+// Contrary to the other InferLabelFrom* functions, this functions walks up
+// the DOM tree from the original input, instead of down from the surrounding
+// tag. While doing so, if a <label> or text node sibling are found along the
+// way, a label is inferred from them directly. For example, <div>First
+// name<div><input></div>Last name<div><input></div></div> infers "First name"
+// and "Last name" for the two inputs, respectively, by picking up the text
+// nodes on the way to the surrounding div. Without doing so, the label of both
+// inputs becomes "First nameLast name".
std::u16string InferLabelFromDivTable(const WebFormControlElement& element) {
WebNode node = element.ParentNode();
bool looking_for_parent = true;
@@ -679,11 +687,21 @@ std::u16string InferLabelFromDivTable(const WebFormControlElement& element) {
}
looking_for_parent = false;
- } else if (!looking_for_parent && HasTagName(node, *kLabel)) {
- WebLabelElement label_element = node.To<WebLabelElement>();
- if (label_element.CorrespondingControl().IsNull())
+ } else if (!looking_for_parent) {
+ // Infer a label from text nodes and unassigned <label> siblings.
+ if (HasTagName(node, *kLabel) &&
+ node.To<WebLabelElement>().CorrespondingControl().IsNull()) {
inferred_label = FindChildText(node);
- } else if (looking_for_parent && IsTraversableContainerElement(node)) {
+ } else if (node.IsTextNode()) {
+ // TODO(crbug.com/796918): Ideally `FindChildText()` should be used
+ // here as well. But because the function doesn't trim it's return
+ // value on every code path, the `NodeValue()` is explicitly extracted
+ // here. Trimming is necessary to skip indentation.
+ inferred_label = node.NodeValue().Utf16();
+ base::TrimWhitespace(inferred_label, base::TrimPositions::TRIM_ALL,
+ &inferred_label);
+ }
+ } else if (IsTraversableContainerElement(node)) {
// If the element is in a non-div container, its label most likely is too.
break;
}
@@ -1034,7 +1052,8 @@ std::vector<WebFormControlElement> ForEachMatchingFormFieldCommon(
WebFormControlElement& element = *it;
- element.SetAutofillSection(WebString::FromUTF8(data.fields[i].section));
+ element.SetAutofillSection(
+ WebString::FromUTF8(data.fields[i].section.ToString()));
// Only autofill empty fields (or those with the field's default value
// attribute) and the field that initiated the filling, i.e. the field the
@@ -1285,7 +1304,8 @@ struct CompareByRendererId {
FormFieldData* SearchForFormControlByName(
const std::u16string& field_name,
const base::flat_set<std::pair<FormFieldData*, ShadowFieldData>,
- CompareByRendererId>& field_set) {
+ CompareByRendererId>& field_set,
+ AssignedLabelSource& label_source) {
if (field_name.empty())
return nullptr;
@@ -1299,6 +1319,14 @@ FormFieldData* SearchForFormControlByName(
base::Contains(p.second.shadow_host_id_attributes, field_name);
};
it = base::ranges::find_if(field_set, ShadowHostHasTargetName);
+ if (it != end) {
+ label_source =
+ base::Contains(it->second.shadow_host_name_attributes, field_name)
+ ? AssignedLabelSource::kShadowHostName
+ : AssignedLabelSource::kShadowHostId;
+ }
+ } else {
+ label_source = AssignedLabelSource::kName;
}
return it != end ? it->first : nullptr;
}
@@ -1323,12 +1351,13 @@ void MatchLabelsAndFields(
WebLabelElement label = item.To<WebLabelElement>();
WebElement control = label.CorrespondingControl();
FormFieldData* field_data = nullptr;
+ auto label_source = AssignedLabelSource::kId;
if (control.IsNull()) {
// Sometimes site authors will incorrectly specify the corresponding
// field element's name rather than its id, so we compensate here.
field_data = SearchForFormControlByName(label.GetAttribute(*kFor).Utf16(),
- field_set);
+ field_set, label_source);
} else if (control.IsFormControlElement()) {
WebFormControlElement form_control = control.To<WebFormControlElement>();
if (form_control.FormControlTypeForAutofill() == *kHidden)
@@ -1350,6 +1379,7 @@ void MatchLabelsAndFields(
if (!field_data->label.empty() && !label_text.empty())
field_data->label += u" ";
field_data->label += label_text;
+ base::UmaHistogramEnumeration(kAssignedLabelSourceHistogram, label_source);
}
}
@@ -1452,7 +1482,8 @@ bool FormOrFieldsetsToFormData(
}
// Extracts field labels from the <label for="..."> tags.
- {
+ if (!base::FeatureList::IsEnabled(
+ features::kAutofillImprovedLabelForInference)) {
std::vector<std::pair<FormFieldData*, ShadowFieldData>> items;
DCHECK_EQ(form->fields.size(), shadow_fields.size());
for (size_t i = 0; i < form->fields.size(); i++) {
@@ -1597,6 +1628,22 @@ std::string GetAutocompleteAttribute(const WebElement& element) {
return autocomplete_attribute;
}
+// Returns the concatenated label text of all labels assigned to the `element`
+// using <label for=`element.GetIdAttribute()`>, separated by a space.
+std::u16string GetAssignedLabel(const WebFormControlElement& element) {
+ std::u16string concatenated_labels;
+ for (const auto& label : element.Labels()) {
+ if (auto label_text = FindChildText(label); !label_text.empty()) {
+ if (!concatenated_labels.empty())
+ concatenated_labels.push_back(' ');
+ concatenated_labels.append(std::move(label_text));
+ base::UmaHistogramEnumeration(kAssignedLabelSourceHistogram,
+ AssignedLabelSource::kId);
+ }
+ }
+ return concatenated_labels;
+}
+
void FindFormElementUpShadowRoots(const WebElement& element,
WebFormElement* found_form_element) {
// If we are in shadowdom, then look to see if the host(s) are inside a form
@@ -1636,7 +1683,7 @@ bool IsVisibleIframe(const WebElement& element) {
bool IsAdIframe(const WebElement& element) {
DCHECK(element.HasHTMLTagName("iframe"));
WebFrame* iframe = WebFrame::FromFrameOwnerElement(element);
- return iframe && iframe->IsAdSubframe();
+ return iframe && iframe->IsAdFrame();
}
// A necessary condition for an iframe to be added to FormData::child_frames.
@@ -1796,6 +1843,11 @@ bool IsTextAreaElement(const WebFormControlElement& element) {
element.FormControlTypeForAutofill() == "textarea";
}
+bool IsTextAreaElementOrTextInput(const WebFormControlElement& element) {
+ return IsTextAreaElement(element) ||
+ IsTextInput(element.DynamicTo<WebInputElement>());
+}
+
bool IsCheckableElement(const WebInputElement& element) {
if (element.IsNull())
return false;
@@ -1822,7 +1874,7 @@ bool IsWebElementFocusable(const blink::WebElement& element) {
return element.IsFocusable();
}
-bool IsWebElementVisible(blink::WebElement element) {
+bool IsWebElementVisible(const blink::WebElement& element) {
auto HasMinSize = [](auto size) {
constexpr int kMinPixelSize = 10;
return size.width() >= kMinPixelSize && size.height() >= kMinPixelSize;
@@ -1906,6 +1958,10 @@ void WebFormControlElementToFormField(
field->form_control_ax_id = element.GetAxId();
field->form_control_type = element.FormControlTypeForAutofill().Utf8();
field->autocomplete_attribute = GetAutocompleteAttribute(element);
+ if (base::FeatureList::IsEnabled(
+ features::kAutofillImprovedLabelForInference)) {
+ field->label = GetAssignedLabel(element);
+ }
if (base::EqualsCaseInsensitiveASCII(element.GetAttribute(*kRole).Utf16(),
"presentation")) {
field->role = FormFieldData::RoleAttribute::kPresentation;
diff --git a/chromium/components/autofill/content/renderer/form_autofill_util.h b/chromium/components/autofill/content/renderer/form_autofill_util.h
index c9ae9cee1bc..0999f1ea7c1 100644
--- a/chromium/components/autofill/content/renderer/form_autofill_util.h
+++ b/chromium/components/autofill/content/renderer/form_autofill_util.h
@@ -73,6 +73,22 @@ enum ExtractMask {
// kMaxDataLength.
};
+// Autofill supports assigning <label for=x> tags to inputs if x its id/name,
+// or the id/name of a shadow host element containing the input.
+// This enum is used to track how often each case occurs in practise.
+enum class AssignedLabelSource {
+ kId = 0,
+ kName = 1,
+ kShadowHostId = 2,
+ kShadowHostName = 3,
+ kMaxValue = kShadowHostName,
+};
+// This temporary histogram is emitted inline, because browser files like
+// AutofillMetrics cannot be included here.
+// TODO(crbug.com/1339277): Remove.
+inline constexpr char kAssignedLabelSourceHistogram[] =
+ "Autofill.LabelInference.AssignedLabelSource";
+
// Indicates if an iframe |element| is considered actually visible to the user.
//
// This function is not intended to implement a perfect visibility check. It
@@ -157,6 +173,9 @@ bool IsSelectElement(const blink::WebFormControlElement& element);
// Returns true if |element| is a textarea element.
bool IsTextAreaElement(const blink::WebFormControlElement& element);
+// Returns true if `element` is a textarea element or a text input element.
+bool IsTextAreaElementOrTextInput(const blink::WebFormControlElement& element);
+
// Returns true if |element| is a checkbox or a radio button element.
bool IsCheckableElement(const blink::WebInputElement& element);
@@ -194,7 +213,7 @@ bool IsWebElementFocusable(const blink::WebElement& element);
// Exposed for testing purposes.
//
// TODO(crbug.com/1335257): Can input fields or iframes actually overflow?
-bool IsWebElementVisible(blink::WebElement element);
+bool IsWebElementVisible(const blink::WebElement& element);
// Returns the form's |name| attribute if non-empty; otherwise the form's |id|
// attribute.
diff --git a/chromium/components/autofill/content/renderer/form_autofill_util_browsertest.cc b/chromium/components/autofill/content/renderer/form_autofill_util_browsertest.cc
index ba5a2e5c28b..562d0d2e709 100644
--- a/chromium/components/autofill/content/renderer/form_autofill_util_browsertest.cc
+++ b/chromium/components/autofill/content/renderer/form_autofill_util_browsertest.cc
@@ -16,7 +16,6 @@
#include "components/autofill/core/common/mojom/autofill_types.mojom-shared.h"
#include "components/autofill/core/common/unique_ids.h"
#include "content/public/renderer/render_frame.h"
-#include "content/public/renderer/render_view.h"
#include "content/public/test/render_view_test.h"
#include "content/public/test/test_utils.h"
#include "testing/gmock/include/gmock/gmock.h"
@@ -127,7 +126,12 @@ TEST_F(FormAutofillUtilsTest, FindChildTextTest) {
"</div></div></div></div></div></div></div></div></div></div></div></"
"div>",
u"child0child1child2child3child4"},
- };
+ {"Skip script tags",
+ "<div id='target'><script>alert('hello');</script>label</div>",
+ u"label"},
+ {"Script tag whitespacing",
+ "<div id='target'>Auto<script>alert('hello');</script>fill</div>",
+ u"Autofill"}};
for (auto test_case : test_cases) {
SCOPED_TRACE(test_case.description);
LoadHTML(test_case.html);
@@ -188,29 +192,29 @@ TEST_F(FormAutofillUtilsTest, InferLabelForElementTest) {
<div><input id=target></div>
</div>)",
u"label"},
- // TODO(crbug.com/796918): Should be label
{"DIV table test 4", R"(
<div>
<div>should be skipped<input></div>
label
<div><input id=target></div>
</div>)",
- u""},
- // TODO(crbug.com/796918): Should be label
+ u"label"},
{"DIV table test 5",
"<div>"
"<div>label<div><input id='target'/></div>behind</div>"
"</div>",
- u"labelbehind"},
+ u"label"},
{"DIV table test 6", R"(
<div>
label
- <div>-</div>
+ <div>*</div>
<div><input id='target'></div>
</div>)",
- // TODO(crbug.com/796918): Should be "label" or "label-". This happens
- // because "-" is inferred, but discarded because `!IsLabelValid()`.
+ // TODO(crbug.com/796918): Should be "label" or "label*". This happens
+ // because "*" is inferred, but discarded because `!IsLabelValid()`.
u""},
+ {"Infer from next sibling",
+ "<input id='target' type='checkbox'>hello <b>world</b>", u"hello world"},
};
for (auto test_case : test_cases) {
SCOPED_TRACE(test_case.description);
@@ -249,7 +253,11 @@ TEST_F(FormAutofillUtilsTest, InferLabelSourceTest) {
FormFieldData::LabelSource::kAriaLabel},
{"<input id='target' value='label'/>",
FormFieldData::LabelSource::kValue},
+ // In the next test, the text node is picked up on the way up the DOM-tree
+ // by the div extraction logic.
{"<li>label<div><input id='target'/></div></li>",
+ FormFieldData::LabelSource::kDivTable},
+ {"<li><span>label</span><div><input id='target'/></div></li>",
FormFieldData::LabelSource::kLiTag},
{"<table><tr><td>label</td><td><input id='target'/></td></tr></table>",
FormFieldData::LabelSource::kTdTag},
diff --git a/chromium/components/autofill/content/renderer/form_cache.cc b/chromium/components/autofill/content/renderer/form_cache.cc
index be8cf7d64e2..3f5bbf250a6 100644
--- a/chromium/components/autofill/content/renderer/form_cache.cc
+++ b/chromium/components/autofill/content/renderer/form_cache.cc
@@ -383,8 +383,10 @@ bool FormCache::ShowPredictions(const FormDataPredictions& form,
// If the flag is enabled, attach the prediction to the field.
if (attach_predictions_to_dom) {
constexpr size_t kMaxLabelSize = 100;
- const std::u16string truncated_label = field_data.label.substr(
- 0, std::min(field_data.label.length(), kMaxLabelSize));
+ // TODO(crbug/1165780): Use `parseable_label()` once the feature is
+ // launched.
+ const std::u16string truncated_label =
+ field_data.label.substr(0, kMaxLabelSize);
std::string form_id =
base::NumberToString(form.data.unique_renderer_id.value());
@@ -420,6 +422,12 @@ bool FormCache::ShowPredictions(const FormDataPredictions& form,
"\nfield renderer id: ",
field_id_str});
+ WebString kAutocomplete = WebString::FromASCII("autocomplete");
+ if (element.HasAttribute(kAutocomplete)) {
+ title += "\nautocomplete: " +
+ element.GetAttribute(kAutocomplete).Utf8().substr(0, 100);
+ }
+
// Set this debug string to the title so that a developer can easily debug
// by hovering the mouse over the input field.
element.SetAttribute("title", WebString::FromUTF8(title));
diff --git a/chromium/components/autofill/content/renderer/form_tracker.cc b/chromium/components/autofill/content/renderer/form_tracker.cc
index 1cd65a47621..f7bc4bd9bba 100644
--- a/chromium/components/autofill/content/renderer/form_tracker.cc
+++ b/chromium/components/autofill/content/renderer/form_tracker.cc
@@ -130,8 +130,11 @@ void FormTracker::FormControlDidChangeImpl(
const WebFormControlElement& element,
Observer::ElementChangeSource change_source) {
DCHECK_CALLED_ON_VALID_SEQUENCE(form_tracker_sequence_checker_);
- // Render frame could be gone as this is the post task.
- if (!render_frame()) return;
+ // The frame or document could be null because this function is called
+ // asynchronously.
+ const blink::WebDocument& doc = element.GetDocument();
+ if (!render_frame() || doc.IsNull() || !doc.GetFrame())
+ return;
if (element.Form().IsNull()) {
last_interacted_formless_element_ = element;
@@ -159,8 +162,8 @@ void FormTracker::DidStartNavigation(
absl::optional<blink::WebNavigationType> navigation_type) {
DCHECK_CALLED_ON_VALID_SEQUENCE(form_tracker_sequence_checker_);
blink::WebLocalFrame* navigated_frame = render_frame()->GetWebFrame();
- // Ony handle main frame.
- if (navigated_frame->Parent())
+ // Ony handle primary main frame.
+ if (!navigated_frame->IsOutermostMainFrame())
return;
// Bug fix for crbug.com/368690. isProcessingUserGesture() is false when
diff --git a/chromium/components/autofill/content/renderer/password_autofill_agent.cc b/chromium/components/autofill/content/renderer/password_autofill_agent.cc
index b302034d368..7fa1f1f1bf9 100644
--- a/chromium/components/autofill/content/renderer/password_autofill_agent.cc
+++ b/chromium/components/autofill/content/renderer/password_autofill_agent.cc
@@ -41,7 +41,6 @@
#include "components/password_manager/core/common/password_manager_features.h"
#include "components/safe_browsing/buildflags.h"
#include "content/public/renderer/render_frame.h"
-#include "content/public/renderer/render_view.h"
#include "net/base/registry_controlled_domains/registry_controlled_domain.h"
#include "services/service_manager/public/cpp/interface_provider.h"
#include "third_party/blink/public/common/associated_interfaces/associated_interface_provider.h"
@@ -353,7 +352,7 @@ WebInputElement FindUsernameElementPrecedingPasswordElement(
// Returns true if |element|'s frame origin is not PSL matched with the origin
// of any parent frame.
-bool IsInCrossOriginIframe(const WebInputElement& element) {
+bool IsInCrossOriginIframeOrEmbeddedFrame(const WebInputElement& element) {
WebFrame* cur_frame = element.GetDocument().GetFrame();
WebString bottom_frame_origin = cur_frame->GetSecurityOrigin().ToString();
@@ -367,6 +366,17 @@ bool IsInCrossOriginIframe(const WebInputElement& element) {
return true;
}
}
+ // In MPArch, if we haven't reached the primary main frame, it means
+ // we are in a nested frame tree. Fenced Frames are always considered
+ // cross origin so we should return true here. Adding NOTREACHED for now
+ // for future nested inner frame trees.
+ if (!cur_frame->IsOutermostMainFrame()) {
+ if (element.GetDocument().GetFrame()->IsInFencedFrameTree()) {
+ return true;
+ } else {
+ NOTREACHED();
+ }
+ }
return false;
}
@@ -534,10 +544,10 @@ class PasswordAutofillAgent::DeferringPasswordManagerDriver
void PasswordFormsParsed(const std::vector<FormData>& forms_data) override {
DeferMsg(&mojom::PasswordManagerDriver::PasswordFormsParsed, forms_data);
}
- void PasswordFormsRendered(const std::vector<FormData>& visible_forms_data,
- bool did_stop_loading) override {
+ void PasswordFormsRendered(
+ const std::vector<FormData>& visible_forms_data) override {
DeferMsg(&mojom::PasswordManagerDriver::PasswordFormsRendered,
- visible_forms_data, did_stop_loading);
+ visible_forms_data);
}
void PasswordFormSubmitted(const FormData& form_data) override {
DeferMsg(&mojom::PasswordManagerDriver::PasswordFormSubmitted, form_data);
@@ -616,7 +626,7 @@ PasswordAutofillAgent::PasswordAutofillAgent(
checked_safe_browsing_reputation_(false),
focus_state_notifier_(this),
password_generation_agent_(nullptr) {
- registry->AddInterface(base::BindRepeating(
+ registry->AddInterface<mojom::PasswordAutofillAgent>(base::BindRepeating(
&PasswordAutofillAgent::BindPendingReceiver, base::Unretained(this)));
}
@@ -1319,10 +1329,7 @@ void PasswordAutofillAgent::SendPasswordForms(bool only_visible) {
// Send the PasswordFormsRendered message regardless of whether
// |password_forms_data| is empty. The empty |password_forms_data| are a
// possible signal to the browser that a pending login attempt succeeded.
- WebFrame* main_frame = render_frame()->GetWebFrame()->Top();
- bool did_stop_loading = !main_frame || !main_frame->IsLoading();
- GetPasswordManagerDriver().PasswordFormsRendered(password_forms_data,
- did_stop_loading);
+ GetPasswordManagerDriver().PasswordFormsRendered(password_forms_data);
} else {
// If there is a password field, but the list of password forms is empty for
// some reason, add a dummy form to the list. It will cause a request to the
@@ -1369,7 +1376,9 @@ void PasswordAutofillAgent::OnFrameDetached() {
// If a sub frame has been destroyed while the user was entering information
// into a password form, try to save the data. See https://crbug.com/450806
// for examples of sites that perform login using this technique.
- if (render_frame()->GetWebFrame()->Parent() && browser_has_form_to_process_) {
+ // We are treating primary main frame and the root of embedded frames the same
+ // on purpose.
+ if (browser_has_form_to_process_ && render_frame()->GetWebFrame()->Parent()) {
DCHECK(FrameCanAccessPasswordManager());
GetPasswordManagerDriver().DynamicFormSubmission(
SubmissionIndicatorEvent::FRAME_DETACHED);
@@ -1397,12 +1406,12 @@ void PasswordAutofillAgent::ReadyToCommitNavigation(
}
WebLocalFrame* navigated_frame = render_frame()->GetWebFrame();
- if (navigated_frame->Parent()) {
- LogMessage(logger.get(), Logger::STRING_FRAME_NOT_MAIN_FRAME);
- } else {
+ if (navigated_frame->IsOutermostMainFrame()) {
// This is a new navigation, so require a new user gesture before filling in
// passwords.
gatekeeper_.Reset();
+ } else {
+ LogMessage(logger.get(), Logger::STRING_FRAME_NOT_MAIN_FRAME);
}
CleanupOnDocumentShutdown();
@@ -1776,7 +1785,7 @@ bool PasswordAutofillAgent::FillUserNameAndPassword(
WebInputElement main_element =
is_single_username_fill ? username_element : password_element;
- if (IsInCrossOriginIframe(main_element)) {
+ if (IsInCrossOriginIframeOrEmbeddedFrame(main_element)) {
LogMessage(logger, Logger::STRING_FAILED_TO_FILL_INTO_IFRAME);
LogFirstFillingResult(fill_data, FillingResult::kBlockedByFrameHierarchy);
return false;
diff --git a/chromium/components/autofill/content/renderer/password_generation_agent.cc b/chromium/components/autofill/content/renderer/password_generation_agent.cc
index e780918243d..ce8c5c7606a 100644
--- a/chromium/components/autofill/content/renderer/password_generation_agent.cc
+++ b/chromium/components/autofill/content/renderer/password_generation_agent.cc
@@ -23,7 +23,6 @@
#include "components/autofill/core/common/password_generation_util.h"
#include "components/autofill/core/common/signatures.h"
#include "content/public/renderer/render_frame.h"
-#include "content/public/renderer/render_view.h"
#include "google_apis/gaia/gaia_urls.h"
#include "third_party/blink/public/common/associated_interfaces/associated_interface_provider.h"
#include "third_party/blink/public/common/features.h"
@@ -206,7 +205,7 @@ struct PasswordGenerationAgent::GenerationItemInfo {
// True when PasswordGenerationAgent updates other password fields on the page
// due to the generated password being edited. It's used to suppress the fake
// blur events coming from there.
- bool updating_other_password_fileds_ = false;
+ bool updating_other_password_fields_ = false;
};
PasswordGenerationAgent::PasswordGenerationAgent(
@@ -218,7 +217,7 @@ PasswordGenerationAgent::PasswordGenerationAgent(
base::CommandLine::ForCurrentProcess()->HasSwitch(
switches::kShowAutofillSignatures)),
password_agent_(password_agent) {
- registry->AddInterface(base::BindRepeating(
+ registry->AddInterface<mojom::PasswordGenerationAgent>(base::BindRepeating(
&PasswordGenerationAgent::BindPendingReceiver, base::Unretained(this)));
password_agent_->SetPasswordGenerationAgent(this);
}
@@ -233,8 +232,8 @@ void PasswordGenerationAgent::BindPendingReceiver(
void PasswordGenerationAgent::DidCommitProvisionalLoad(
ui::PageTransition transition) {
- // Update stats for main frame navigation.
- if (!render_frame()->GetWebFrame()->Parent()) {
+ // Update stats for primary main frame navigation.
+ if (render_frame()->GetWebFrame()->IsOutermostMainFrame()) {
if (current_generation_item_) {
if (current_generation_item_->password_edited_) {
password_generation::LogPasswordGenerationEvent(
@@ -281,7 +280,7 @@ void PasswordGenerationAgent::OnFieldAutofilled(
bool PasswordGenerationAgent::ShouldIgnoreBlur() const {
return current_generation_item_ &&
- current_generation_item_->updating_other_password_fileds_;
+ current_generation_item_->updating_other_password_fields_;
}
bool PasswordGenerationAgent::IsPrerendering() const {
@@ -302,7 +301,7 @@ void PasswordGenerationAgent::GeneratedPasswordAccepted(
LogMessage(Logger::STRING_GENERATION_RENDERER_GENERATED_PASSWORD_ACCEPTED);
for (auto& password_element : current_generation_item_->password_elements_) {
base::AutoReset<bool> auto_reset_update_confirmation_password(
- &current_generation_item_->updating_other_password_fileds_, true);
+ &current_generation_item_->updating_other_password_fields_, true);
password_element.SetAutofillValue(blink::WebString::FromUTF16(password));
// setAutofillValue() above may have resulted in JavaScript closing the
// frame.
@@ -555,7 +554,7 @@ bool PasswordGenerationAgent::TextDidChangeInTextField(
} else if (current_generation_item_->password_is_generated_) {
current_generation_item_->password_edited_ = true;
base::AutoReset<bool> auto_reset_update_confirmation_password(
- &current_generation_item_->updating_other_password_fileds_, true);
+ &current_generation_item_->updating_other_password_fields_, true);
// Mirror edits to any confirmation password fields.
CopyElementValueToOtherInputElements(
&element, &current_generation_item_->password_elements_);
@@ -650,7 +649,7 @@ void PasswordGenerationAgent::PasswordNoLongerGenerated() {
for (WebInputElement& element :
current_generation_item_->password_elements_) {
base::AutoReset<bool> auto_reset_update_confirmation_password(
- &current_generation_item_->updating_other_password_fileds_, true);
+ &current_generation_item_->updating_other_password_fields_, true);
if (current_generation_item_->generation_element_ != element)
element.SetAutofillValue(blink::WebString());
}
diff --git a/chromium/components/autofill/content/renderer/renderer_save_password_progress_logger_unittest.cc b/chromium/components/autofill/content/renderer/renderer_save_password_progress_logger_unittest.cc
index 6475369839a..d7b89c20bb9 100644
--- a/chromium/components/autofill/content/renderer/renderer_save_password_progress_logger_unittest.cc
+++ b/chromium/components/autofill/content/renderer/renderer_save_password_progress_logger_unittest.cc
@@ -45,8 +45,7 @@ class FakeContentPasswordManagerDriver : public mojom::PasswordManagerDriver {
const std::vector<autofill::FormData>& form_data) override {}
void PasswordFormsRendered(
- const std::vector<autofill::FormData>& visible_forms_data,
- bool did_stop_loading) override {}
+ const std::vector<autofill::FormData>& visible_forms_data) override {}
void PasswordFormSubmitted(const autofill::FormData& form_data) override {}
diff --git a/chromium/components/autofill/core/browser/BUILD.gn b/chromium/components/autofill/core/browser/BUILD.gn
index 04a0eb767c9..e7579184760 100644
--- a/chromium/components/autofill/core/browser/BUILD.gn
+++ b/chromium/components/autofill/core/browser/BUILD.gn
@@ -4,7 +4,7 @@
import("//build/buildflag_header.gni")
import("//build/config/chrome_build.gni")
-import("//build/util/version.gni")
+import("//chrome/version.gni")
import("//testing/libfuzzer/fuzzer_test.gni")
import("//tools/grit/grit_rule.gni")
if (is_android) {
@@ -104,10 +104,6 @@ static_library("browser") {
"autofill_profile_sync_util.h",
"autofill_profile_update_strike_database.cc",
"autofill_profile_update_strike_database.h",
- "autofill_regex_constants.cc",
- "autofill_regex_constants.h",
- "autofill_regexes.cc",
- "autofill_regexes.h",
"autofill_subject.cc",
"autofill_subject.h",
"autofill_suggestion_generator.cc",
@@ -159,6 +155,8 @@ static_library("browser") {
"data_model/data_model_utils.h",
"data_model/form_group.cc",
"data_model/form_group.h",
+ "data_model/iban.cc",
+ "data_model/iban.h",
"data_model/phone_number.cc",
"data_model/phone_number.h",
"data_model/test_data_creator.cc",
@@ -169,11 +167,15 @@ static_library("browser") {
"field_types.h",
"form_data_importer.cc",
"form_data_importer.h",
+ "form_data_importer_utils.cc",
+ "form_data_importer_utils.h",
"form_parsing/address_field.cc",
"form_parsing/address_field.h",
"form_parsing/autofill_parsing_utils.h",
"form_parsing/autofill_scanner.cc",
"form_parsing/autofill_scanner.h",
+ "form_parsing/birthdate_field.cc",
+ "form_parsing/birthdate_field.h",
"form_parsing/credit_card_field.cc",
"form_parsing/credit_card_field.h",
"form_parsing/email_field.cc",
@@ -182,6 +184,8 @@ static_library("browser") {
"form_parsing/field_candidates.h",
"form_parsing/form_field.cc",
"form_parsing/form_field.h",
+ "form_parsing/iban_field.cc",
+ "form_parsing/iban_field.h",
"form_parsing/merchant_promo_code_field.cc",
"form_parsing/merchant_promo_code_field.h",
"form_parsing/name_field.cc",
@@ -227,6 +231,8 @@ static_library("browser") {
"geo/state_names.h",
"geo/subkey_requester.cc",
"geo/subkey_requester.h",
+ "iban_manager.cc",
+ "iban_manager.h",
"logging/log_buffer_submitter.cc",
"logging/log_buffer_submitter.h",
"logging/log_manager.cc",
@@ -248,6 +254,8 @@ static_library("browser") {
"metrics/form_events/form_events.h",
"metrics/form_interactions_counter.cc",
"metrics/form_interactions_counter.h",
+ "metrics/payments/local_card_migration_metrics.cc",
+ "metrics/payments/local_card_migration_metrics.h",
"metrics/payments/manage_cards_prompt_metrics.cc",
"metrics/payments/manage_cards_prompt_metrics.h",
"metrics/payments/offers_metrics.cc",
@@ -344,8 +352,8 @@ static_library("browser") {
"suggestions_context.cc",
"suggestions_context.h",
"sync_utils.h",
- "touch_to_fill_delegate.cc",
- "touch_to_fill_delegate.h",
+ "touch_to_fill_delegate_impl.cc",
+ "touch_to_fill_delegate_impl.h",
"ui/accessory_sheet_data.cc",
"ui/accessory_sheet_data.h",
"ui/accessory_sheet_enums.h",
@@ -384,6 +392,7 @@ static_library("browser") {
"ui/suggestion.h",
"ui/suggestion_selection.cc",
"ui/suggestion_selection.h",
+ "ui/touch_to_fill_delegate.h",
"validation.cc",
"validation.h",
"webdata/autocomplete_sync_bridge.cc",
@@ -423,13 +432,6 @@ static_library("browser") {
sources += get_target_outputs(":regex_patterns_inl_h")
- if (is_win) {
- sources += [
- "autofill_ie_toolbar_import_win.cc",
- "autofill_ie_toolbar_import_win.h",
- ]
- }
-
if (is_ios) {
sources += [
"autofill_save_update_address_profile_delegate_ios.cc",
@@ -507,6 +509,7 @@ static_library("browser") {
"//base:i18n",
"//build:branding_buildflags",
"//build:chromeos_buildflags",
+ "//components/autofill_assistant/core/public:public",
"//components/feature_engagement",
"//components/google/core/common",
"//components/history/core/browser",
@@ -600,6 +603,7 @@ static_library("test_support") {
"autofill_test_utils.h",
"data_model/test_autofill_data_model.cc",
"data_model/test_autofill_data_model.h",
+ "form_structure_test_api.cc",
"form_structure_test_api.h",
"geo/alternative_state_name_map_test_utils.cc",
"geo/alternative_state_name_map_test_utils.h",
@@ -613,6 +617,8 @@ static_library("test_support") {
"metrics/autofill_metrics_test_base.h",
"mock_autocomplete_history_manager.cc",
"mock_autocomplete_history_manager.h",
+ "mock_iban_manager.cc",
+ "mock_iban_manager.h",
"mock_merchant_promo_code_manager.cc",
"mock_merchant_promo_code_manager.h",
"mock_single_field_form_fill_router.cc",
@@ -646,6 +652,8 @@ static_library("test_support") {
"test_autofill_driver.h",
"test_autofill_external_delegate.cc",
"test_autofill_external_delegate.h",
+ "test_autofill_manager_waiter.cc",
+ "test_autofill_manager_waiter.h",
"test_autofill_tick_clock.cc",
"test_autofill_tick_clock.h",
"test_browser_autofill_manager.cc",
@@ -653,8 +661,6 @@ static_library("test_support") {
"test_event_waiter.h",
"test_form_data_importer.cc",
"test_form_data_importer.h",
- "test_form_structure.cc",
- "test_form_structure.h",
"test_inmemory_strike_database.cc",
"test_inmemory_strike_database.h",
"test_personal_data_manager.cc",
@@ -784,7 +790,6 @@ source_set("unit_tests") {
"autofill_profile_save_strike_database_unittest.cc",
"autofill_profile_sync_util_unittest.cc",
"autofill_profile_update_strike_database_unittest.cc",
- "autofill_regexes_unittest.cc",
"autofill_subject_unittest.cc",
"autofill_suggestion_generator_unittest.cc",
"autofill_type_unittest.cc",
@@ -804,14 +809,18 @@ source_set("unit_tests") {
"data_model/borrowed_transliterator_unittest.cc",
"data_model/contact_info_unittest.cc",
"data_model/credit_card_unittest.cc",
+ "data_model/iban_unittest.cc",
"data_model/phone_number_unittest.cc",
"field_filler_unittest.cc",
"field_types_unittest.cc",
"form_data_importer_unittest.cc",
+ "form_data_importer_utils_unittest.cc",
"form_parsing/address_field_unittest.cc",
+ "form_parsing/birthdate_field_unittest.cc",
"form_parsing/credit_card_field_unittest.cc",
"form_parsing/field_candidates_unittest.cc",
"form_parsing/form_field_unittest.cc",
+ "form_parsing/iban_field_unittest.cc",
"form_parsing/merchant_promo_code_field_unittest.cc",
"form_parsing/name_field_unittest.cc",
"form_parsing/parsing_test_utils.cc",
@@ -831,6 +840,7 @@ source_set("unit_tests") {
"geo/country_names_unittest.cc",
"geo/phone_number_i18n_unittest.cc",
"geo/subkey_requester_unittest.cc",
+ "iban_manager_unittest.cc",
"logging/log_buffer_submitter_unittest.cc",
"logging/log_manager_unittest.cc",
"logging/log_router_unittest.cc",
@@ -853,6 +863,9 @@ source_set("unit_tests") {
"payments/virtual_card_enrollment_manager_unittest.cc",
"payments/virtual_card_enrollment_strike_database_unittest.cc",
"payments/wait_for_signal_or_timeout_unittest.cc",
+ "personal_data_manager_cleaner_unittest.cc",
+ "personal_data_manager_test_base.cc",
+ "personal_data_manager_test_base.h",
"personal_data_manager_unittest.cc",
"randomized_encoder_unittest.cc",
"rationalization_util_unittest.cc",
@@ -861,6 +874,7 @@ source_set("unit_tests") {
"strike_database_unittest.cc",
"test_utils/test_profiles.cc",
"test_utils/test_profiles.h",
+ "touch_to_fill_delegate_impl_unittest.cc",
"ui/address_combobox_model_unittest.cc",
"ui/autofill_image_fetcher_unittest.cc",
"ui/country_combobox_model_unittest.cc",
@@ -879,10 +893,6 @@ source_set("unit_tests") {
"webdata/web_data_service_unittest.cc",
]
- if (is_win) {
- sources += [ "autofill_ie_toolbar_import_win_unittest.cc" ]
- }
-
if (is_ios) {
sources +=
[ "autofill_save_update_address_profile_delegate_ios_unittest.cc" ]
@@ -929,6 +939,7 @@ source_set("unit_tests") {
"//base/test:test_support",
"//build:chromeos_buildflags",
"//components/autofill/core/common",
+ "//components/autofill_assistant/core/public:public",
"//components/feature_engagement",
"//components/image_fetcher/core:core",
"//components/image_fetcher/core:test_support",
@@ -942,8 +953,7 @@ source_set("unit_tests") {
"//components/signin/public/identity_manager:test_support",
"//components/strings",
"//components/sync",
- "//components/sync:test_support_model",
- "//components/sync/driver:test_support",
+ "//components/sync:test_support",
"//components/translate/core/browser",
"//components/translate/core/common",
"//components/ukm",
diff --git a/chromium/components/autofill/core/browser/address_profile_save_manager_unittest.cc b/chromium/components/autofill/core/browser/address_profile_save_manager_unittest.cc
index 99ed61bc8ec..08faa9eb532 100644
--- a/chromium/components/autofill/core/browser/address_profile_save_manager_unittest.cc
+++ b/chromium/components/autofill/core/browser/address_profile_save_manager_unittest.cc
@@ -427,28 +427,23 @@ void AddressProfileSaveManagerTest::TestImportScenario(
}
if (is_confirmable_merge &&
- test_scenario.user_decision == UserDecision::kAccepted) {
- histogram_tester.ExpectTotalCount(
- kProfileUpdateAffectedTypesHistogram,
- test_scenario.expected_affeceted_types_in_merge_for_metrics.size());
-
+ (test_scenario.user_decision == UserDecision::kAccepted ||
+ test_scenario.user_decision == UserDecision::kDeclined)) {
+ std::string changed_histogram_suffix;
+ switch (test_scenario.user_decision) {
+ case UserDecision::kAccepted:
+ changed_histogram_suffix = ".Accepted";
+ break;
+
+ case UserDecision::kDeclined:
+ changed_histogram_suffix = ".Declined";
+ break;
+
+ default:
+ NOTREACHED() << "Decision not covered by test logic.";
+ }
for (auto changed_type :
test_scenario.expected_affeceted_types_in_merge_for_metrics) {
- histogram_tester.ExpectBucketCount(kProfileUpdateAffectedTypesHistogram,
- changed_type, 1);
- std::string changed_histogram_suffix;
- switch (test_scenario.user_decision) {
- case UserDecision::kAccepted:
- changed_histogram_suffix = ".Accepted";
- break;
-
- case UserDecision::kDeclined:
- changed_histogram_suffix = ".Declined";
- break;
-
- default:
- NOTREACHED() << "Decision not covered by test logic.";
- }
histogram_tester.ExpectBucketCount(
base::StrCat({kProfileUpdateAffectedTypesHistogram,
changed_histogram_suffix}),
@@ -456,7 +451,8 @@ void AddressProfileSaveManagerTest::TestImportScenario(
}
histogram_tester.ExpectUniqueSample(
- kProfileUpdateNumberOfAffectedTypesHistogram,
+ base::StrCat({kProfileUpdateNumberOfAffectedTypesHistogram,
+ changed_histogram_suffix}),
test_scenario.expected_affeceted_types_in_merge_for_metrics.size(),
1);
}
@@ -907,7 +903,10 @@ TEST_P(AddressProfileSaveManagerTest, UserConfirmableMerge_Declined) {
.is_profile_change_expected = false,
.merge_candidate = mergeable_profile,
.import_candidate = final_profile,
- .expected_final_profiles = {mergeable_profile}};
+ .expected_final_profiles = {mergeable_profile},
+ .expected_affeceted_types_in_merge_for_metrics = {
+ AutofillMetrics::SettingsVisibleFieldTypeForMetrics::kZip,
+ AutofillMetrics::SettingsVisibleFieldTypeForMetrics::kCity}};
TestImportScenario(test_scenario);
}
@@ -1070,7 +1069,10 @@ TEST_P(AddressProfileSaveManagerTest,
.merge_candidate = mergeable_profile,
.import_candidate = merged_profile,
.expected_final_profiles = {existing_duplicate, updated_profile,
- mergeable_profile}};
+ mergeable_profile},
+ .expected_affeceted_types_in_merge_for_metrics = {
+ AutofillMetrics::SettingsVisibleFieldTypeForMetrics::kZip,
+ AutofillMetrics::SettingsVisibleFieldTypeForMetrics::kCity}};
TestImportScenario(test_scenario);
}
diff --git a/chromium/components/autofill/core/browser/autocomplete_history_manager.cc b/chromium/components/autofill/core/browser/autocomplete_history_manager.cc
index de40d0d5282..cc1ba6db9d2 100644
--- a/chromium/components/autofill/core/browser/autocomplete_history_manager.cc
+++ b/chromium/components/autofill/core/browser/autocomplete_history_manager.cc
@@ -11,10 +11,10 @@
#include "base/bind.h"
#include "base/containers/cxx20_erase.h"
+#include "base/debug/dump_without_crashing.h"
#include "base/memory/weak_ptr.h"
#include "base/strings/utf_string_conversions.h"
#include "components/autofill/core/browser/autofill_experiments.h"
-#include "components/autofill/core/browser/autofill_regexes.h"
#include "components/autofill/core/browser/metrics/autofill_metrics.h"
#include "components/autofill/core/browser/suggestions_context.h"
#include "components/autofill/core/browser/ui/suggestion.h"
@@ -23,6 +23,7 @@
#include "components/autofill/core/common/autofill_clock.h"
#include "components/autofill/core/common/autofill_features.h"
#include "components/autofill/core/common/autofill_prefs.h"
+#include "components/autofill/core/common/autofill_regexes.h"
#include "components/autofill/core/common/form_data.h"
#include "components/prefs/pref_service.h"
#include "components/version_info/version_info.h"
@@ -51,9 +52,9 @@ bool IsTextField(const FormFieldData& field) {
// that a different website or different form uses the same field name for a
// totally different purpose.
bool IsMeaningfulFieldName(const std::u16string& name) {
- return !MatchesPattern(
- name,
- u"^(((field|input)(_|-)?\\d+)|title|otp|tan)$|(cvc|cvn|cvv|captcha)");
+ static constexpr char16_t kRegex[] =
+ u"^(((field|input)(_|-)?\\d+)|title|otp|tan)$|(cvc|cvn|cvv|captcha)";
+ return !MatchesRegex<kRegex>(name);
}
} // namespace
@@ -78,37 +79,44 @@ AutocompleteHistoryManager::~AutocompleteHistoryManager() {
CancelAllPendingQueries();
}
-void AutocompleteHistoryManager::OnGetSingleFieldSuggestions(
+bool AutocompleteHistoryManager::OnGetSingleFieldSuggestions(
int query_id,
bool is_autocomplete_enabled,
bool autoselect_first_suggestion,
- const std::u16string& name,
- const std::u16string& prefix,
- const std::string& form_control_type,
+ const FormFieldData& field,
base::WeakPtr<SuggestionsHandler> handler,
const SuggestionsContext& context) {
+ if (!field.should_autocomplete)
+ return false;
+
CancelPendingQueries(handler.get());
- if (!IsMeaningfulFieldName(name) || !is_autocomplete_enabled ||
- form_control_type == "textarea" ||
+ if (!IsMeaningfulFieldName(field.name) || !is_autocomplete_enabled ||
+ field.form_control_type == "textarea" ||
IsInAutofillSuggestionsDisabledExperiment()) {
SendSuggestions({}, QueryHandler(query_id, autoselect_first_suggestion,
- prefix, handler));
- uma_recorder_.OnGetAutocompleteSuggestions(name,
+ field.value, handler));
+ uma_recorder_.OnGetAutocompleteSuggestions(field.name,
0 /* pending_query_handle */);
- return;
+ return true;
}
if (profile_database_) {
auto query_handle = profile_database_->GetFormValuesForElementName(
- name, prefix, kMaxAutocompleteMenuItems, this);
- uma_recorder_.OnGetAutocompleteSuggestions(name, query_handle);
+ field.name, field.value, kMaxAutocompleteMenuItems, this);
+ uma_recorder_.OnGetAutocompleteSuggestions(field.name, query_handle);
// We can simply insert, since |query_handle| is always unique.
pending_queries_.insert(
- {query_handle,
- QueryHandler(query_id, autoselect_first_suggestion, prefix, handler)});
+ {query_handle, QueryHandler(query_id, autoselect_first_suggestion,
+ field.value, handler)});
+ return true;
}
+
+ // TODO(crbug.com/1190334): Remove this after ensuring that in practice
+ // |profile_database_| is never null.
+ base::debug::DumpWithoutCrashing();
+ return false;
}
void AutocompleteHistoryManager::OnWillSubmitFormWithFields(
diff --git a/chromium/components/autofill/core/browser/autocomplete_history_manager.h b/chromium/components/autofill/core/browser/autocomplete_history_manager.h
index bfb446ce9ee..546bc670af8 100644
--- a/chromium/components/autofill/core/browser/autocomplete_history_manager.h
+++ b/chromium/components/autofill/core/browser/autocomplete_history_manager.h
@@ -44,14 +44,13 @@ class AutocompleteHistoryManager : public SingleFieldFormFiller,
~AutocompleteHistoryManager() override;
// SingleFieldFormFiller overrides:
- void OnGetSingleFieldSuggestions(int query_id,
- bool is_autocomplete_enabled,
- bool autoselect_first_suggestion,
- const std::u16string& name,
- const std::u16string& prefix,
- const std::string& form_control_type,
- base::WeakPtr<SuggestionsHandler> handler,
- const SuggestionsContext& context) override;
+ [[nodiscard]] bool OnGetSingleFieldSuggestions(
+ int query_id,
+ bool is_autocomplete_enabled,
+ bool autoselect_first_suggestion,
+ const FormFieldData& field,
+ base::WeakPtr<SuggestionsHandler> handler,
+ const SuggestionsContext& context) override;
void OnWillSubmitFormWithFields(const std::vector<FormFieldData>& fields,
bool is_autocomplete_enabled) override;
void CancelPendingQueries(const SuggestionsHandler* handler) override;
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 aae2f13d31c..fb24001e6f9 100644
--- a/chromium/components/autofill/core/browser/autocomplete_history_manager_unittest.cc
+++ b/chromium/components/autofill/core/browser/autocomplete_history_manager_unittest.cc
@@ -101,6 +101,8 @@ class AutocompleteHistoryManagerTest : public testing::Test {
web_data_service_ = base::MakeRefCounted<MockAutofillWebDataService>();
autocomplete_manager_ = std::make_unique<AutocompleteHistoryManager>();
autocomplete_manager_->Init(web_data_service_, prefs_.get(), false);
+ test::CreateTestFormField(/*label=*/"", "Some Field Name", "SomePrefix",
+ "Some Type", &test_field_);
}
void TearDown() override {
@@ -144,6 +146,7 @@ class AutocompleteHistoryManagerTest : public testing::Test {
scoped_refptr<MockAutofillWebDataService> web_data_service_;
std::unique_ptr<AutocompleteHistoryManager> autocomplete_manager_;
std::unique_ptr<PrefService> prefs_;
+ FormFieldData test_field_;
TestAutofillClock test_clock;
};
@@ -455,6 +458,27 @@ TEST_F(AutocompleteHistoryManagerTest,
/*is_off_the_record=*/false);
}
+// Make sure suggestions are not returned if the field should not autocomplete.
+TEST_F(AutocompleteHistoryManagerTest,
+ OnGetSingleFieldSuggestions_FieldShouldNotAutocomplete) {
+ test_field_.should_autocomplete = false;
+
+ auto suggestions_handler = std::make_unique<MockSuggestionsHandler>();
+ int test_query_id = 2;
+
+ // Setting up mock to verify that call to the handler's OnSuggestionsReturned
+ // is not triggered.
+ EXPECT_CALL(*suggestions_handler, OnSuggestionsReturned).Times(0);
+
+ EXPECT_CALL(*web_data_service_, GetFormValuesForElementName).Times(0);
+
+ // Simulate request for suggestions.
+ EXPECT_FALSE(autocomplete_manager_->OnGetSingleFieldSuggestions(
+ test_query_id, /*is_autocomplete_enabled=*/true,
+ /*autoselect_first_suggestion=*/false, test_field_,
+ suggestions_handler->GetWeakPtr(), SuggestionsContext()));
+}
+
// Make sure our handler is called at the right time.
TEST_F(AutocompleteHistoryManagerTest,
SuggestionsReturned_InvokeHandler_Empty) {
@@ -462,8 +486,6 @@ TEST_F(AutocompleteHistoryManagerTest,
auto suggestions_handler = std::make_unique<MockSuggestionsHandler>();
int test_query_id = 2;
- std::u16string test_name = u"Some Field Name";
- std::u16string test_prefix = u"SomePrefix";
std::vector<AutofillEntry> expected_values;
@@ -471,15 +493,15 @@ TEST_F(AutocompleteHistoryManagerTest,
GetMockedDbResults(expected_values);
EXPECT_CALL(*web_data_service_,
- GetFormValuesForElementName(test_name, test_prefix, _,
- autocomplete_manager_.get()))
+ GetFormValuesForElementName(test_field_.name, test_field_.value,
+ _, autocomplete_manager_.get()))
.WillOnce(Return(mocked_db_query_id));
// Simulate request for suggestions.
- autocomplete_manager_->OnGetSingleFieldSuggestions(
+ EXPECT_TRUE(autocomplete_manager_->OnGetSingleFieldSuggestions(
test_query_id, /*is_autocomplete_enabled=*/true,
- /*autoselect_first_suggestion=*/false, test_name, test_prefix,
- "Some Type", suggestions_handler->GetWeakPtr(), SuggestionsContext());
+ /*autoselect_first_suggestion=*/false, test_field_,
+ suggestions_handler->GetWeakPtr(), SuggestionsContext()));
// Setting up mock to verify that DB response triggers a call to the handler's
// OnSuggestionsReturned
@@ -499,20 +521,20 @@ TEST_F(AutocompleteHistoryManagerTest,
DoQuerySuggestionsForMeaninglessFieldNames_FilterSubStringName) {
auto suggestions_handler = std::make_unique<MockSuggestionsHandler>();
int test_query_id = 2;
- std::u16string test_name = u"payment_cvv_info";
- std::u16string test_prefix;
+ test::CreateTestFormField(/*label=*/"", "payment_cvv_info", /*value=*/"",
+ "Some Type", &test_field_);
// Only expect a call when the name is not filtered out.
EXPECT_CALL(*web_data_service_,
- GetFormValuesForElementName(test_name, test_prefix, _,
- autocomplete_manager_.get()))
+ GetFormValuesForElementName(test_field_.name, test_field_.value,
+ _, autocomplete_manager_.get()))
.Times(0);
// Simulate request for suggestions.
- autocomplete_manager_->OnGetSingleFieldSuggestions(
+ EXPECT_TRUE(autocomplete_manager_->OnGetSingleFieldSuggestions(
test_query_id, /*is_autocomplete_enabled=*/true,
- /*autoselect_first_suggestion=*/false, test_name, test_prefix,
- "Some Type", suggestions_handler->GetWeakPtr(), SuggestionsContext());
+ /*autoselect_first_suggestion=*/false, test_field_,
+ suggestions_handler->GetWeakPtr(), SuggestionsContext()));
// Setting up mock to verify that DB response does not trigger a call to the
// handler's OnSuggestionsReturned.
@@ -528,20 +550,20 @@ TEST_F(AutocompleteHistoryManagerTest,
DoQuerySuggestionsForMeaninglessFieldNames_FilterName) {
auto suggestions_handler = std::make_unique<MockSuggestionsHandler>();
int test_query_id = 2;
- std::u16string test_name = u"input_123";
- std::u16string test_prefix;
+ test::CreateTestFormField(/*label=*/"", "input_123", /*value=*/"",
+ "Some Type", &test_field_);
// Only expect a call when the name is not filtered out.
EXPECT_CALL(*web_data_service_,
- GetFormValuesForElementName(test_name, test_prefix, _,
- autocomplete_manager_.get()))
+ GetFormValuesForElementName(test_field_.name, test_field_.value,
+ _, autocomplete_manager_.get()))
.Times(0);
// Simulate request for suggestions.
- autocomplete_manager_->OnGetSingleFieldSuggestions(
+ EXPECT_TRUE(autocomplete_manager_->OnGetSingleFieldSuggestions(
test_query_id, /*is_autocomplete_enabled=*/true,
- /*autoselect_first_suggestion=*/false, test_name, test_prefix,
- "Some Type", suggestions_handler->GetWeakPtr(), SuggestionsContext());
+ /*autoselect_first_suggestion=*/false, test_field_,
+ suggestions_handler->GetWeakPtr(), SuggestionsContext()));
// Setting up mock to verify that DB response does not trigger a call to the
// handler's OnSuggestionsReturned.
@@ -557,9 +579,9 @@ TEST_F(AutocompleteHistoryManagerTest,
DoQuerySuggestionsForMeaninglessFieldNames_PassNameWithSubstring) {
auto suggestions_handler = std::make_unique<MockSuggestionsHandler>();
int test_query_id = 2;
- std::u16string test_name = u"foOTPace";
- std::u16string test_prefix;
int mocked_db_query_id = 100;
+ test::CreateTestFormField(/*label=*/"", "foOTPace", /*value=*/"", "Some Type",
+ &test_field_);
std::vector<AutofillEntry> expected_values;
@@ -568,15 +590,15 @@ TEST_F(AutocompleteHistoryManagerTest,
// Expect a call because the name is not filtered.
EXPECT_CALL(*web_data_service_,
- GetFormValuesForElementName(test_name, test_prefix, _,
- autocomplete_manager_.get()))
+ GetFormValuesForElementName(test_field_.name, test_field_.value,
+ _, autocomplete_manager_.get()))
.WillOnce(Return(mocked_db_query_id));
// Simulate request for suggestions.
- autocomplete_manager_->OnGetSingleFieldSuggestions(
+ EXPECT_TRUE(autocomplete_manager_->OnGetSingleFieldSuggestions(
test_query_id, /*is_autocomplete_enabled=*/true,
- /*autoselect_first_suggestion=*/false, test_name, test_prefix,
- "Some Type", suggestions_handler->GetWeakPtr(), SuggestionsContext());
+ /*autoselect_first_suggestion=*/false, test_field_,
+ suggestions_handler->GetWeakPtr(), SuggestionsContext()));
// Setting up mock to verify that DB response triggers a call to the handler's
EXPECT_CALL(*suggestions_handler.get(),
@@ -592,9 +614,9 @@ TEST_F(AutocompleteHistoryManagerTest,
DoQuerySuggestionsForMeaninglessFieldNames_PassName) {
auto suggestions_handler = std::make_unique<MockSuggestionsHandler>();
int test_query_id = 2;
- std::u16string test_name = u"addressline_1";
- std::u16string test_prefix;
int mocked_db_query_id = 100;
+ test::CreateTestFormField(/*label=*/"", "addressline_1", /*value=*/"",
+ "Some Type", &test_field_);
std::vector<AutofillEntry> expected_values;
@@ -603,15 +625,15 @@ TEST_F(AutocompleteHistoryManagerTest,
// Expect a call because the name is not filtered.
EXPECT_CALL(*web_data_service_,
- GetFormValuesForElementName(test_name, test_prefix, _,
- autocomplete_manager_.get()))
+ GetFormValuesForElementName(test_field_.name, test_field_.value,
+ _, autocomplete_manager_.get()))
.WillOnce(Return(mocked_db_query_id));
// Simulate request for suggestions.
- autocomplete_manager_->OnGetSingleFieldSuggestions(
+ EXPECT_TRUE(autocomplete_manager_->OnGetSingleFieldSuggestions(
test_query_id, /*is_autocomplete_enabled=*/true,
- /*autoselect_first_suggestion=*/false, test_name, test_prefix,
- "Some Type", suggestions_handler->GetWeakPtr(), SuggestionsContext());
+ /*autoselect_first_suggestion=*/false, test_field_,
+ suggestions_handler->GetWeakPtr(), SuggestionsContext()));
// Setting up mock to verify that DB response triggers a call to the handler's
EXPECT_CALL(*suggestions_handler.get(),
@@ -628,25 +650,23 @@ TEST_F(AutocompleteHistoryManagerTest,
auto suggestions_handler = std::make_unique<MockSuggestionsHandler>();
int test_query_id = 2;
- std::u16string test_name = u"Some Field Name";
- std::u16string test_prefix = u"SomePrefix";
std::vector<AutofillEntry> expected_values = {
- GetAutofillEntry(test_name, u"SomePrefixOne")};
+ GetAutofillEntry(test_field_.name, u"SomePrefixOne")};
std::unique_ptr<WDTypedResult> mocked_results =
GetMockedDbResults(expected_values);
EXPECT_CALL(*web_data_service_,
- GetFormValuesForElementName(test_name, test_prefix, _,
- autocomplete_manager_.get()))
+ GetFormValuesForElementName(test_field_.name, test_field_.value,
+ _, autocomplete_manager_.get()))
.WillOnce(Return(mocked_db_query_id));
// Simulate request for suggestions.
- autocomplete_manager_->OnGetSingleFieldSuggestions(
+ EXPECT_TRUE(autocomplete_manager_->OnGetSingleFieldSuggestions(
test_query_id, /*is_autocomplete_enabled=*/true,
- /*autoselect_first_suggestion=*/false, test_name, test_prefix,
- "Some Type", suggestions_handler->GetWeakPtr(), SuggestionsContext());
+ /*autoselect_first_suggestion=*/false, test_field_,
+ suggestions_handler->GetWeakPtr(), SuggestionsContext()));
// Setting up mock to verify that DB response triggers a call to the handler's
EXPECT_CALL(*suggestions_handler.get(),
@@ -670,25 +690,23 @@ TEST_F(AutocompleteHistoryManagerTest,
auto suggestions_handler = std::make_unique<MockSuggestionsHandler>();
int test_query_id = 2;
- std::u16string test_name = u"Some Field Name";
- std::u16string test_prefix = u"SomePrefix";
std::vector<AutofillEntry> expected_values = {
- GetAutofillEntry(test_name, u"SomePrefixOne")};
+ GetAutofillEntry(test_field_.name, u"SomePrefixOne")};
std::unique_ptr<WDTypedResult> mocked_results =
GetMockedDbResults(expected_values);
EXPECT_CALL(*web_data_service_,
- GetFormValuesForElementName(test_name, test_prefix, _,
- autocomplete_manager_.get()))
+ GetFormValuesForElementName(test_field_.name, test_field_.value,
+ _, autocomplete_manager_.get()))
.WillOnce(Return(mocked_db_query_id));
// Simulate request for suggestions.
- autocomplete_manager_->OnGetSingleFieldSuggestions(
+ EXPECT_TRUE(autocomplete_manager_->OnGetSingleFieldSuggestions(
test_query_id, /*is_autocomplete_enabled=*/true,
- /*autoselect_first_suggestion=*/true, test_name, test_prefix, "Some Type",
- suggestions_handler->GetWeakPtr(), SuggestionsContext());
+ /*autoselect_first_suggestion=*/true, test_field_,
+ suggestions_handler->GetWeakPtr(), SuggestionsContext()));
// Setting up mock to verify that DB response triggers a call to the handler's
EXPECT_CALL(*suggestions_handler.get(),
@@ -712,25 +730,23 @@ TEST_F(AutocompleteHistoryManagerTest,
auto suggestions_handler = std::make_unique<MockSuggestionsHandler>();
int test_query_id = 2;
- std::u16string test_name = u"Some Field Name";
- std::u16string test_prefix = u"SomePrefix";
std::vector<AutofillEntry> expected_values = {
- GetAutofillEntry(test_name, test_prefix)};
+ GetAutofillEntry(test_field_.name, test_field_.value)};
std::unique_ptr<WDTypedResult> mocked_results =
GetMockedDbResults(expected_values);
EXPECT_CALL(*web_data_service_,
- GetFormValuesForElementName(test_name, test_prefix, _,
- autocomplete_manager_.get()))
+ GetFormValuesForElementName(test_field_.name, test_field_.value,
+ _, autocomplete_manager_.get()))
.WillOnce(Return(mocked_db_query_id));
// Simulate request for suggestions.
- autocomplete_manager_->OnGetSingleFieldSuggestions(
+ EXPECT_TRUE(autocomplete_manager_->OnGetSingleFieldSuggestions(
test_query_id, /*is_autocomplete_enabled=*/true,
- /*autoselect_first_suggestion=*/false, test_name, test_prefix,
- "Some Type", suggestions_handler->GetWeakPtr(), SuggestionsContext());
+ /*autoselect_first_suggestion=*/false, test_field_,
+ suggestions_handler->GetWeakPtr(), SuggestionsContext()));
// Setting up mock to verify that DB response triggers a call to the handler's
EXPECT_CALL(*suggestions_handler.get(),
@@ -751,25 +767,23 @@ TEST_F(AutocompleteHistoryManagerTest,
auto suggestions_handler = std::make_unique<MockSuggestionsHandler>();
int test_query_id = 2;
- std::u16string test_name = u"Some Field Name";
- std::u16string test_prefix = u"SomePrefix";
std::vector<AutofillEntry> expected_values = {
- GetAutofillEntry(test_name, u"someprefix")};
+ GetAutofillEntry(test_field_.name, u"someprefix")};
std::unique_ptr<WDTypedResult> mocked_results =
GetMockedDbResults(expected_values);
EXPECT_CALL(*web_data_service_,
- GetFormValuesForElementName(test_name, test_prefix, _,
- autocomplete_manager_.get()))
+ GetFormValuesForElementName(test_field_.name, test_field_.value,
+ _, autocomplete_manager_.get()))
.WillOnce(Return(mocked_db_query_id));
// Simulate request for suggestions.
- autocomplete_manager_->OnGetSingleFieldSuggestions(
+ EXPECT_TRUE(autocomplete_manager_->OnGetSingleFieldSuggestions(
test_query_id, /*is_autocomplete_enabled=*/true,
- /*autoselect_first_suggestion=*/false, test_name, test_prefix,
- "Some Type", suggestions_handler->GetWeakPtr(), SuggestionsContext());
+ /*autoselect_first_suggestion=*/false, test_field_,
+ suggestions_handler->GetWeakPtr(), SuggestionsContext()));
// Setting up mock to verify that DB response triggers a call to the handler's
EXPECT_CALL(*suggestions_handler.get(),
@@ -793,17 +807,15 @@ TEST_F(AutocompleteHistoryManagerTest,
auto suggestions_handler = std::make_unique<MockSuggestionsHandler>();
int test_query_id = 2;
- std::u16string test_name = u"Some Field Name";
- std::u16string test_prefix = u"SomePrefix";
std::u16string test_value = u"SomePrefixOne";
std::u16string other_test_value = u"SomePrefixOne";
int days_since_last_use = 10;
std::vector<AutofillEntry> expected_values = {
- GetAutofillEntry(test_name, test_value,
+ GetAutofillEntry(test_field_.name, test_value,
AutofillClock::Now() - base::Days(30),
AutofillClock::Now() - base::Days(days_since_last_use)),
- GetAutofillEntry(test_name, other_test_value,
+ GetAutofillEntry(test_field_.name, other_test_value,
AutofillClock::Now() - base::Days(30),
AutofillClock::Now() - base::Days(days_since_last_use))};
@@ -811,17 +823,17 @@ TEST_F(AutocompleteHistoryManagerTest,
GetMockedDbResults(expected_values);
EXPECT_CALL(*web_data_service_,
- GetFormValuesForElementName(test_name, test_prefix, _,
- autocomplete_manager_.get()))
+ GetFormValuesForElementName(test_field_.name, test_field_.value,
+ _, autocomplete_manager_.get()))
.WillOnce(Return(mocked_db_query_id));
EXPECT_CALL(*suggestions_handler.get(), OnSuggestionsReturned);
// Simulate request for suggestions.
- autocomplete_manager_->OnGetSingleFieldSuggestions(
+ EXPECT_TRUE(autocomplete_manager_->OnGetSingleFieldSuggestions(
test_query_id, /*is_autocomplete_enabled=*/true,
- /*autoselect_first_suggestion=*/false, test_name, test_prefix,
- "Some Type", suggestions_handler->GetWeakPtr(), SuggestionsContext());
+ /*autoselect_first_suggestion=*/false, test_field_,
+ suggestions_handler->GetWeakPtr(), SuggestionsContext()));
// Simulate response from DB.
autocomplete_manager_->OnWebDataServiceRequestDone(mocked_db_query_id,
@@ -846,14 +858,12 @@ TEST_F(AutocompleteHistoryManagerTest,
auto suggestions_handler = std::make_unique<MockSuggestionsHandler>();
int test_query_id_first = 2;
int test_query_id_second = 3;
- std::u16string test_name = u"Some Field Name";
- std::u16string test_prefix = u"SomePrefix";
std::vector<AutofillEntry> expected_values_first = {
- GetAutofillEntry(test_name, u"SomePrefixOne")};
+ GetAutofillEntry(test_field_.name, u"SomePrefixOne")};
std::vector<AutofillEntry> expected_values_second = {
- GetAutofillEntry(test_name, u"SomePrefixTwo")};
+ GetAutofillEntry(test_field_.name, u"SomePrefixTwo")};
std::unique_ptr<WDTypedResult> mocked_results_first =
GetMockedDbResults(expected_values_first);
@@ -862,25 +872,25 @@ TEST_F(AutocompleteHistoryManagerTest,
GetMockedDbResults(expected_values_second);
EXPECT_CALL(*web_data_service_,
- GetFormValuesForElementName(test_name, test_prefix, _,
- autocomplete_manager_.get()))
+ GetFormValuesForElementName(test_field_.name, test_field_.value,
+ _, autocomplete_manager_.get()))
.WillOnce(Return(mocked_db_query_id_first))
.WillOnce(Return(mocked_db_query_id_second));
// Simulate request for the first suggestions.
- autocomplete_manager_->OnGetSingleFieldSuggestions(
+ EXPECT_TRUE(autocomplete_manager_->OnGetSingleFieldSuggestions(
test_query_id_first, /*is_autocomplete_enabled=*/true,
- /*autoselect_first_suggestion=*/false, test_name, test_prefix,
- "Some Type", suggestions_handler->GetWeakPtr(), SuggestionsContext());
+ /*autoselect_first_suggestion=*/false, test_field_,
+ suggestions_handler->GetWeakPtr(), SuggestionsContext()));
// Simulate request for the second suggestions (this will cancel the first
// one).
EXPECT_CALL(*web_data_service_, CancelRequest(mocked_db_query_id_first))
.Times(1);
- autocomplete_manager_->OnGetSingleFieldSuggestions(
+ EXPECT_TRUE(autocomplete_manager_->OnGetSingleFieldSuggestions(
test_query_id_second, /*is_autocomplete_enabled=*/true,
- /*autoselect_first_suggestion=*/false, test_name, test_prefix,
- "Some Type", suggestions_handler->GetWeakPtr(), SuggestionsContext());
+ /*autoselect_first_suggestion=*/false, test_field_,
+ suggestions_handler->GetWeakPtr(), SuggestionsContext()));
// Setting up mock to verify that we can get the second response first.
EXPECT_CALL(*suggestions_handler.get(),
@@ -916,14 +926,12 @@ TEST_F(AutocompleteHistoryManagerTest,
auto suggestions_handler_second = std::make_unique<MockSuggestionsHandler>();
int test_query_id_first = 2;
int test_query_id_second = 3;
- std::u16string test_name = u"Some Field Name";
- std::u16string test_prefix = u"SomePrefix";
std::vector<AutofillEntry> expected_values_first = {
- GetAutofillEntry(test_name, u"SomePrefixOne")};
+ GetAutofillEntry(test_field_.name, u"SomePrefixOne")};
std::vector<AutofillEntry> expected_values_second = {
- GetAutofillEntry(test_name, u"SomePrefixTwo")};
+ GetAutofillEntry(test_field_.name, u"SomePrefixTwo")};
std::unique_ptr<WDTypedResult> mocked_results_first =
GetMockedDbResults(expected_values_first);
@@ -932,24 +940,22 @@ TEST_F(AutocompleteHistoryManagerTest,
GetMockedDbResults(expected_values_second);
EXPECT_CALL(*web_data_service_,
- GetFormValuesForElementName(test_name, test_prefix, _,
- autocomplete_manager_.get()))
+ GetFormValuesForElementName(test_field_.name, test_field_.value,
+ _, autocomplete_manager_.get()))
.WillOnce(Return(mocked_db_query_id_first))
.WillOnce(Return(mocked_db_query_id_second));
// Simulate request for the first suggestions.
- autocomplete_manager_->OnGetSingleFieldSuggestions(
+ EXPECT_TRUE(autocomplete_manager_->OnGetSingleFieldSuggestions(
test_query_id_first, /*is_autocomplete_enabled=*/true,
- /*autoselect_first_suggestion=*/false, test_name, test_prefix,
- "Some Type", suggestions_handler_first->GetWeakPtr(),
- SuggestionsContext());
+ /*autoselect_first_suggestion=*/false, test_field_,
+ suggestions_handler_first->GetWeakPtr(), SuggestionsContext()));
// Simulate request for the second suggestions.
- autocomplete_manager_->OnGetSingleFieldSuggestions(
+ EXPECT_TRUE(autocomplete_manager_->OnGetSingleFieldSuggestions(
test_query_id_second, /*is_autocomplete_enabled=*/true,
- /*autoselect_first_suggestion=*/false, test_name, test_prefix,
- "Some Type", suggestions_handler_second->GetWeakPtr(),
- SuggestionsContext());
+ /*autoselect_first_suggestion=*/false, test_field_,
+ suggestions_handler_second->GetWeakPtr(), SuggestionsContext()));
// Setting up mock to verify that we get the second response first.
EXPECT_CALL(*suggestions_handler_second.get(),
@@ -980,16 +986,13 @@ TEST_F(AutocompleteHistoryManagerTest,
TEST_F(AutocompleteHistoryManagerTest,
SuggestionsReturned_CancelOne_ReturnOne) {
- std::u16string test_name = u"Some Field Name";
- std::u16string test_prefix = u"SomePrefix";
-
// Initialize variables for the first handler, which is the one that will be
// cancelled.
auto suggestions_handler_one = std::make_unique<MockSuggestionsHandler>();
int mocked_db_query_id_one = 100;
int test_query_id_one = 1;
std::vector<AutofillEntry> expected_values_one = {
- GetAutofillEntry(test_name, u"SomePrefixOne")};
+ GetAutofillEntry(test_field_.name, u"SomePrefixOne")};
std::unique_ptr<WDTypedResult> mocked_results_one =
GetMockedDbResults(expected_values_one);
@@ -998,27 +1001,27 @@ TEST_F(AutocompleteHistoryManagerTest,
int test_query_id_two = 2;
int mocked_db_query_id_two = 101;
std::vector<AutofillEntry> expected_values_two = {
- GetAutofillEntry(test_name, u"SomePrefixTwo")};
+ GetAutofillEntry(test_field_.name, u"SomePrefixTwo")};
std::unique_ptr<WDTypedResult> mocked_results_two =
GetMockedDbResults(expected_values_two);
// Simulate first handler request for autocomplete suggestions.
EXPECT_CALL(*web_data_service_,
- GetFormValuesForElementName(test_name, test_prefix, _,
- autocomplete_manager_.get()))
+ GetFormValuesForElementName(test_field_.name, test_field_.value,
+ _, autocomplete_manager_.get()))
.WillOnce(Return(mocked_db_query_id_one))
.WillOnce(Return(mocked_db_query_id_two));
- autocomplete_manager_->OnGetSingleFieldSuggestions(
+ EXPECT_TRUE(autocomplete_manager_->OnGetSingleFieldSuggestions(
test_query_id_one, /*is_autocomplete_enabled=*/true,
- /*autoselect_first_suggestion=*/false, test_name, test_prefix,
- "Some Type", suggestions_handler_one->GetWeakPtr(), SuggestionsContext());
+ /*autoselect_first_suggestion=*/false, test_field_,
+ suggestions_handler_one->GetWeakPtr(), SuggestionsContext()));
// Simlate second handler request for autocomplete suggestions.
- autocomplete_manager_->OnGetSingleFieldSuggestions(
+ EXPECT_TRUE(autocomplete_manager_->OnGetSingleFieldSuggestions(
test_query_id_two, /*is_autocomplete_enabled=*/true,
- /*autoselect_first_suggestion=*/false, test_name, test_prefix,
- "Some Type", suggestions_handler_two->GetWeakPtr(), SuggestionsContext());
+ /*autoselect_first_suggestion=*/false, test_field_,
+ suggestions_handler_two->GetWeakPtr(), SuggestionsContext()));
// Simlate first handler cancelling its request.
EXPECT_CALL(*web_data_service_, CancelRequest(mocked_db_query_id_one))
@@ -1063,11 +1066,10 @@ TEST_F(AutocompleteHistoryManagerTest, NoAutocompleteSuggestionsForTextarea) {
base::HistogramTester histogram_tester;
- autocomplete_manager_->OnGetSingleFieldSuggestions(
+ EXPECT_TRUE(autocomplete_manager_->OnGetSingleFieldSuggestions(
0, /*is_autocomplete_enabled=*/true,
- /*autoselect_first_suggestion=*/false, field.name, field.value,
- field.form_control_type, suggestions_handler->GetWeakPtr(),
- SuggestionsContext());
+ /*autoselect_first_suggestion=*/false, field,
+ suggestions_handler->GetWeakPtr(), SuggestionsContext()));
histogram_tester.ExpectBucketCount("Autofill.AutocompleteQuery", 0, 1);
histogram_tester.ExpectBucketCount("Autofill.AutocompleteQuery", 1, 0);
@@ -1093,11 +1095,10 @@ TEST_F(AutocompleteHistoryManagerTest, AutocompleteUMAQueryCreated) {
EXPECT_CALL(*suggestions_handler.get(),
OnSuggestionsReturned(0, /*autoselect_first_suggestion=*/false,
testing::Truly(IsEmptySuggestionVector)));
- autocomplete_manager_->OnGetSingleFieldSuggestions(
+ EXPECT_TRUE(autocomplete_manager_->OnGetSingleFieldSuggestions(
0, /*is_autocomplete_enabled=*/true,
- /*autoselect_first_suggestion=*/false, field.name, field.value,
- field.form_control_type, suggestions_handler->GetWeakPtr(),
- SuggestionsContext());
+ /*autoselect_first_suggestion=*/false, field,
+ suggestions_handler->GetWeakPtr(), SuggestionsContext()));
histogram_tester.ExpectBucketCount("Autofill.AutocompleteQuery", 1, 1);
histogram_tester.ExpectBucketCount("Autofill.AutocompleteQuery", 0, 0);
@@ -1124,11 +1125,10 @@ TEST_F(AutocompleteHistoryManagerTest, AutocompleteUMAQueryCreated) {
EXPECT_CALL(*suggestions_handler.get(),
OnSuggestionsReturned(0, /*autoselect_first_suggestion=*/false,
testing::Truly(NonEmptySuggestionVector)));
- autocomplete_manager_->OnGetSingleFieldSuggestions(
+ EXPECT_TRUE(autocomplete_manager_->OnGetSingleFieldSuggestions(
0, /*is_autocomplete_enabled=*/true,
- /*autoselect_first_suggestion=*/false, field.name, field.value,
- field.form_control_type, suggestions_handler->GetWeakPtr(),
- SuggestionsContext());
+ /*autoselect_first_suggestion=*/false, field,
+ suggestions_handler->GetWeakPtr(), SuggestionsContext()));
histogram_tester.ExpectBucketCount("Autofill.AutocompleteQuery", 1, 2);
histogram_tester.ExpectBucketCount("Autofill.AutocompleteQuery", 0, 0);
@@ -1151,28 +1151,24 @@ TEST_F(AutocompleteHistoryManagerTest, DestructorCancelsRequests) {
auto suggestions_handler_second = std::make_unique<MockSuggestionsHandler>();
int test_query_id_first = 2;
int test_query_id_second = 3;
- std::u16string test_name = u"Some Field Name";
- std::u16string test_prefix = u"SomePrefix";
EXPECT_CALL(*web_data_service_,
- GetFormValuesForElementName(test_name, test_prefix, _,
- autocomplete_manager_.get()))
+ GetFormValuesForElementName(test_field_.name, test_field_.value,
+ _, autocomplete_manager_.get()))
.WillOnce(Return(mocked_db_query_id_first))
.WillOnce(Return(mocked_db_query_id_second));
// Simulate request for the first suggestions.
- autocomplete_manager_->OnGetSingleFieldSuggestions(
+ EXPECT_TRUE(autocomplete_manager_->OnGetSingleFieldSuggestions(
test_query_id_first, /*is_autocomplete_enabled=*/true,
- /*autoselect_first_suggestion=*/false, test_name, test_prefix,
- "Some Type", suggestions_handler_first->GetWeakPtr(),
- SuggestionsContext());
+ /*autoselect_first_suggestion=*/false, test_field_,
+ suggestions_handler_first->GetWeakPtr(), SuggestionsContext()));
// Simulate request for the second suggestions.
- autocomplete_manager_->OnGetSingleFieldSuggestions(
+ EXPECT_TRUE(autocomplete_manager_->OnGetSingleFieldSuggestions(
test_query_id_second, /*is_autocomplete_enabled=*/true,
- /*autoselect_first_suggestion=*/false, test_name, test_prefix,
- "Some Type", suggestions_handler_second->GetWeakPtr(),
- SuggestionsContext());
+ /*autoselect_first_suggestion=*/false, test_field_,
+ suggestions_handler_second->GetWeakPtr(), SuggestionsContext()));
// Expect cancel calls for both requests.
EXPECT_CALL(*web_data_service_, CancelRequest(mocked_db_query_id_first))
diff --git a/chromium/components/autofill/core/browser/autofill_address_util.cc b/chromium/components/autofill/core/browser/autofill_address_util.cc
index 3000d73edd8..72c04fe0d5f 100644
--- a/chromium/components/autofill/core/browser/autofill_address_util.cc
+++ b/chromium/components/autofill/core/browser/autofill_address_util.cc
@@ -23,7 +23,6 @@
#include "components/strings/grit/components_strings.h"
#include "third_party/libaddressinput/src/cpp/include/libaddressinput/address_ui.h"
#include "third_party/libaddressinput/src/cpp/include/libaddressinput/address_ui_component.h"
-#include "third_party/libaddressinput/src/cpp/include/libaddressinput/localization.h"
#include "third_party/re2/src/re2/re2.h"
#include "ui/base/l10n/l10n_util.h"
@@ -35,39 +34,6 @@ namespace autofill {
namespace {
-// Extend `components` using Autofill's address format extensions. These are
-// used to add support for fields that are not strictly required for a valid
-// address, and thus not provided by libaddressinput, but still commonly appear
-// in forms.
-void ExtendAddressComponents(std::vector<AddressUiComponent>& components,
- const std::string& country_code,
- const Localization& localization) {
- AutofillCountry country(country_code);
- for (const AutofillCountry::AddressFormatExtension& rule :
- country.address_format_extensions()) {
- // Find the location of `rule.placed_after` in `components`.
- // `components.field` is only valid if `components.literal.empty()`.
- auto prev_component = base::ranges::find_if(
- components, [&rule](const AddressUiComponent& component) {
- return component.literal.empty() &&
- component.field == rule.placed_after;
- });
- DCHECK(prev_component != components.end());
-
- // Insert the separator and `rule.type` afterwards.
- components.insert(
- ++prev_component,
- {AddressUiComponent{.literal =
- std::string(rule.separator_before_label)},
- AddressUiComponent{
- .field = rule.type,
- .name = localization.GetString(rule.label_id),
- .length_hint = rule.large_sized
- ? AddressUiComponent::HINT_LONG
- : AddressUiComponent::HINT_SHORT}});
- }
-}
-
// Returns a vector of AddressUiComponent for `country_code` when using
// `ui_language_code`. If no components are available for `country_code`, it
// defaults back to the US. If `ui_language_code` is not valid, the default
@@ -86,7 +52,8 @@ std::vector<AddressUiComponent> GetAddressComponents(
::i18n::addressinput::BuildComponentsWithLiterals(
country, localization, ui_language_code, components_language_code);
if (!components.empty()) {
- ExtendAddressComponents(components, country, localization);
+ ExtendAddressComponents(components, country, localization,
+ /*include_literals=*/true);
return components;
}
}
@@ -96,6 +63,39 @@ std::vector<AddressUiComponent> GetAddressComponents(
} // namespace
+void ExtendAddressComponents(std::vector<AddressUiComponent>& components,
+ const std::string& country_code,
+ const Localization& localization,
+ bool include_literals) {
+ AutofillCountry country(country_code);
+ for (const AutofillCountry::AddressFormatExtension& rule :
+ country.address_format_extensions()) {
+ // Find the location of `rule.placed_after` in `components`.
+ // `components.field` is only valid if `components.literal.empty()`.
+ auto prev_component = base::ranges::find_if(
+ components, [&rule](const AddressUiComponent& component) {
+ return component.literal.empty() &&
+ component.field == rule.placed_after;
+ });
+ DCHECK(prev_component != components.end());
+
+ // Insert the separator and `rule.type` after `prev_component`.
+ if (include_literals) {
+ prev_component = components.insert(
+ ++prev_component,
+ AddressUiComponent{.literal =
+ std::string(rule.separator_before_label)});
+ }
+ components.insert(
+ ++prev_component,
+ AddressUiComponent{
+ .field = rule.type,
+ .name = localization.GetString(rule.label_id),
+ .length_hint = rule.large_sized ? AddressUiComponent::HINT_LONG
+ : AddressUiComponent::HINT_SHORT});
+ }
+}
+
void GetAddressComponents(
const std::string& country_code,
const std::string& ui_language_code,
diff --git a/chromium/components/autofill/core/browser/autofill_address_util.h b/chromium/components/autofill/core/browser/autofill_address_util.h
index 31cdd6fe172..f04b8a510a7 100644
--- a/chromium/components/autofill/core/browser/autofill_address_util.h
+++ b/chromium/components/autofill/core/browser/autofill_address_util.h
@@ -10,12 +10,22 @@
#include "components/autofill/core/browser/data_model/autofill_profile_comparator.h"
#include "components/autofill/core/browser/field_types.h"
#include "third_party/libaddressinput/src/cpp/include/libaddressinput/address_ui_component.h"
+#include "third_party/libaddressinput/src/cpp/include/libaddressinput/localization.h"
namespace autofill {
class AutofillProfile;
class PersonalDataManager;
+// Extend `components` using Autofill's address format extensions. These are
+// used make fields beyond libaddressinput's format available in Autofill's
+// settings UI and import dialogs.
+void ExtendAddressComponents(
+ std::vector<::i18n::addressinput::AddressUiComponent>& components,
+ const std::string& country_code,
+ const ::i18n::addressinput::Localization& localization,
+ bool include_literals);
+
// |address_components| is a 2D array for the address components in each line.
// Fills |address_components| with the address UI components that should be used
// to input an address for |country_code| when UI BCP 47 language code is
diff --git a/chromium/components/autofill/core/browser/autofill_and_password_manager_internals/OWNERS b/chromium/components/autofill/core/browser/autofill_and_password_manager_internals/OWNERS
new file mode 100644
index 00000000000..27291aac8ca
--- /dev/null
+++ b/chromium/components/autofill/core/browser/autofill_and_password_manager_internals/OWNERS
@@ -0,0 +1,5 @@
+# For most changes:
+file://components/autofill/OWNERS
+
+# For trivial or mechanical horizontal JS/CSS/HTML changes.
+file://ui/webui/PLATFORM_OWNERS
diff --git a/chromium/components/autofill/core/browser/autofill_and_password_manager_internals/autofill_and_password_manager_internals.html b/chromium/components/autofill/core/browser/autofill_and_password_manager_internals/autofill_and_password_manager_internals.html
index f3e66bf71c5..5db94c45067 100644
--- a/chromium/components/autofill/core/browser/autofill_and_password_manager_internals/autofill_and_password_manager_internals.html
+++ b/chromium/components/autofill/core/browser/autofill_and_password_manager_internals/autofill_and_password_manager_internals.html
@@ -29,11 +29,13 @@ html {
#control-panel {
display: block;
font-size: 120%;
+ line-height: calc(120% + 2ex);
padding: 1ex;
}
#control-panel label {
padding-inline-end: 1em;
+ white-space: nowrap;
}
.fake-button {
@@ -274,7 +276,6 @@ html {
position: absolute;
right: 20px;
}
-
</style>
</head>
<body>
@@ -282,10 +283,13 @@ html {
<h1 id="h1-title"></h1>
<div id="control-panel">
<span id="marker-fake-button" class="fake-button">Add Marker</span>
- <input type="checkbox" id="enable-autoscroll" checked><label for="enable-autoscroll">Enable autoscroll</label>
+ <label><input type="checkbox" id="enable-autoscroll" checked> Enable autoscroll</label>
<span id="checkbox-placeholder"></span>
<span id="reset-cache-fake-button" class="fake-button" style="display: none">Reset Cache</span>
<span id="download-fake-button" class="fake-button">Download Log</span>
+ <label><input type="checkbox" id="currently-recording" checked> Record new events</label>
+ <label><input type="checkbox" id="automatically-stop-recording" checked> Automatically stop recording in <span id="stop-recording-time">M:SS</span></label>
+ <span id="reset-upm-eviction-fake-button" class="fake-button" style="display: none">Reset UPM eviction</span>
</div>
</div>
<div id="logging-note"></div>
diff --git a/chromium/components/autofill/core/browser/autofill_and_password_manager_internals/autofill_and_password_manager_internals.js b/chromium/components/autofill/core/browser/autofill_and_password_manager_internals/autofill_and_password_manager_internals.js
index 91503420ffe..d2e0451e4ee 100644
--- a/chromium/components/autofill/core/browser/autofill_and_password_manager_internals/autofill_and_password_manager_internals.js
+++ b/chromium/components/autofill/core/browser/autofill_and_password_manager_internals/autofill_and_password_manager_internals.js
@@ -9,6 +9,14 @@ import 'chrome://resources/js/ios/web_ui.js';
import {addWebUIListener} from 'chrome://resources/js/cr.m.js';
import {$} from 'chrome://resources/js/util.m.js';
+// By default this page only records metrics for a given period of time in order
+// to not waste too much memory. This constant defines the default period until
+// recording ceases.
+const kDefaultLoggingPeriodInSeconds = 300;
+
+// Indicates whether logs should be recorded at the moment.
+let recordLogs = true;
+
// Renders a simple dialog with |text| as a message and a close button.
function showModalDialog(text) {
const dialog = document.createElement('div');
@@ -120,7 +128,10 @@ function nodeToDomNode(node) {
return domNode;
}
-function addStructuredLog(node) {
+function addStructuredLog(node, ignoreRecordLogs = false) {
+ if (!recordLogs && !ignoreRecordLogs) {
+ return;
+ }
const logDiv = $('log-entries');
if (!logDiv) {
return;
@@ -141,6 +152,88 @@ function addStructuredLog(node) {
}
}
+// Sets up a couple of event handlers and interval handlers for automatically
+// stopping the recording of autofill events. We stop the recording because
+// you may forget an internals page in some tab and don't want it to keep
+// growing it's memory consumption forever.
+// We have two checkboxes
+// [x] Record new events
+// [x] Automatically stop recording in 0:30
+// with the following behavior:
+// - While the first checkbox is checked, log entries are recorded.
+// - While both checkboxes are checked, the countdown decreases.
+// - If the countdown reaches 0:00, the first checkbox gets unchecked.
+// - If any checkbox is toggled, we reset the countdown time to
+// kDefaultLoggingPeriodInSeconds.
+function setUpStopRecording() {
+ // Timestamp (in ms after epoch), when the countdown to stop recording should
+ // happen.
+ let stopRecordingLogsAt = undefined;
+ // Interval ID generated by setInterval, which is called every second to
+ // update the remaining time.
+ let countdown = undefined;
+
+ const currentlyRecordingChkBox =
+ document.getElementById('currently-recording');
+ const autoStopRecordingChkBox =
+ document.getElementById('automatically-stop-recording');
+
+ // Formats a number of seconds into a [M]M:SS format.
+ const secondsToString = (seconds) => {
+ const minutes = Math.floor(seconds / 60);
+ seconds = seconds % 60;
+ return `${minutes}:${seconds < 10 ? '0' : ''}${seconds}`;
+ };
+
+ // Updates the time label and reacts to the countdown reaching 0.
+ const countdownHandler = () => {
+ const remainingSeconds = Math.round(
+ Math.max((stopRecordingLogsAt - new Date().getTime()) / 1000, 0));
+ document.getElementById('stop-recording-time').innerText =
+ secondsToString(remainingSeconds);
+
+ if (remainingSeconds == 0) {
+ recordLogs = false;
+ currentlyRecordingChkBox.checked = false;
+ resetTimeout();
+ }
+ };
+ const startCountDown = () => {
+ if (!countdown) {
+ countdown = window.setInterval(countdownHandler, 1000);
+ }
+ };
+ const stopCountDown = () => {
+ if (countdown) {
+ window.clearInterval(countdown);
+ countdown = undefined;
+ }
+ };
+ const startOrStopCountDown = () => {
+ if (currentlyRecordingChkBox.checked && autoStopRecordingChkBox.checked) {
+ startCountDown();
+ } else {
+ stopCountDown();
+ }
+ };
+ const resetTimeout = () => {
+ stopRecordingLogsAt =
+ new Date().getTime() + kDefaultLoggingPeriodInSeconds * 1000;
+ countdownHandler(); // Update the string shown to the user.
+ startOrStopCountDown();
+ };
+
+ currentlyRecordingChkBox.addEventListener('click', () => {
+ recordLogs = currentlyRecordingChkBox.checked;
+ resetTimeout();
+ });
+ autoStopRecordingChkBox.addEventListener('click', () => {
+ resetTimeout();
+ });
+
+ resetTimeout();
+}
+
function setUpAutofillInternals() {
document.title = 'Autofill Internals';
document.getElementById('h1-title').textContent = 'Autofill Internals';
@@ -152,6 +245,7 @@ function setUpAutofillInternals() {
setUpLogDisplayConfig();
setUpMarker();
setUpDownload('autofill');
+ setUpStopRecording();
}
function setUpPasswordManagerInternals() {
@@ -165,11 +259,18 @@ function setUpPasswordManagerInternals() {
'Captured password manager logs are not available in Incognito.';
setUpMarker();
setUpDownload('password-manager');
+ setUpStopRecording();
+ addWebUIListener(
+ 'enable-reset-upm-eviction-button', enableResetUpmEvictionButton);
}
function enableResetCacheButton() {
- document.getElementById('reset-cache-fake-button').style.display =
- 'inline-block';
+ document.getElementById('reset-cache-fake-button').style.display = 'inline';
+}
+
+function enableResetUpmEvictionButton(isEnabled) {
+ document.getElementById('reset-upm-eviction-fake-button').style.display =
+ isEnabled ? 'inline' : 'none';
}
function notifyAboutIncognito(isIncognito) {
@@ -195,12 +296,14 @@ function setUpMarker() {
markerFakeButton.addEventListener('click', () => {
++markerCounter;
const scrollAfterInsert = needsScrollDown();
- addStructuredLog({
- type: 'element',
- value: 'div',
- attributes: {'class': 'marker', 'contenteditable': 'true'},
- children: [{type: 'text', value: `#${markerCounter} `}]
- });
+ addStructuredLog(
+ {
+ type: 'element',
+ value: 'div',
+ attributes: {'class': 'marker', 'contenteditable': 'true'},
+ children: [{type: 'text', value: `#${markerCounter} `}],
+ },
+ /*ignoreRecordLogs=*/ true);
if (scrollAfterInsert) {
scrollDown();
// Focus marker div, set caret at end of line.
@@ -294,9 +397,8 @@ function setUpLogDisplayConfig() {
input.addEventListener('change', changeHandler);
changeHandler(); // Call once to initialize |logDiv|'s classes.
const label = document.createElement('label');
- label.setAttribute('for', `checkbox-${scope}`);
- label.innerText = scope;
- checkboxPlaceholder.appendChild(input);
+ label.appendChild(input);
+ label.appendChild(document.createTextNode(' ' + scope));
checkboxPlaceholder.appendChild(label);
}
}
@@ -318,4 +420,11 @@ document.addEventListener('DOMContentLoaded', function(event) {
resetCacheFakeButton.addEventListener('click', () => {
chrome.send('resetCache');
});
+
+ const resetUpmEvictionButton =
+ document.getElementById('reset-upm-eviction-fake-button');
+ resetUpmEvictionButton.addEventListener('click', () => {
+ chrome.send('resetUpmEviction');
+ showModalDialog('UPM re-enabled. Please, restart Chrome.');
+ });
});
diff --git a/chromium/components/autofill/core/browser/autofill_client.cc b/chromium/components/autofill/core/browser/autofill_client.cc
index 1bb339fa7f1..76e714fd475 100644
--- a/chromium/components/autofill/core/browser/autofill_client.cc
+++ b/chromium/components/autofill/core/browser/autofill_client.cc
@@ -51,6 +51,14 @@ AutofillClient::GetSingleFieldFormFillRouter() {
GetAutocompleteHistoryManager(), GetMerchantPromoCodeManager());
}
+CreditCardCVCAuthenticator* AutofillClient::GetCVCAuthenticator() {
+ return nullptr;
+}
+
+CreditCardOtpAuthenticator* AutofillClient::GetOtpAuthenticator() {
+ return nullptr;
+}
+
AutofillOfferManager* AutofillClient::GetAutofillOfferManager() {
return nullptr;
}
@@ -104,8 +112,7 @@ void AutofillClient::HideVirtualCardEnrollBubbleAndIconIfVisible() {
#if !BUILDFLAG(IS_IOS)
std::unique_ptr<webauthn::InternalAuthenticator>
-AutofillClient::CreateCreditCardInternalAuthenticator(
- content::RenderFrameHost* rfh) {
+AutofillClient::CreateCreditCardInternalAuthenticator(AutofillDriver* driver) {
return nullptr;
}
#endif
@@ -149,6 +156,7 @@ void AutofillClient::ShowVirtualCardErrorDialog(bool is_permanent_error) {
}
void AutofillClient::ShowAutofillProgressDialog(
+ AutofillProgressDialogType autofill_progress_dialog_type,
base::OnceClosure cancel_callback) {
// This is overridden by platform subclasses. Currently only
// ChromeAutofillClient (Chrome Desktop & Android) implements this.
diff --git a/chromium/components/autofill/core/browser/autofill_client.h b/chromium/components/autofill/core/browser/autofill_client.h
index d7994f5f4a4..5dee1a18199 100644
--- a/chromium/components/autofill/core/browser/autofill_client.h
+++ b/chromium/components/autofill/core/browser/autofill_client.h
@@ -20,6 +20,7 @@
#include "components/autofill/core/browser/payments/risk_data_loader.h"
#include "components/autofill/core/browser/ui/popup_item_ids.h"
#include "components/autofill/core/browser/ui/popup_types.h"
+#include "components/autofill/core/browser/ui/touch_to_fill_delegate.h"
#include "components/profile_metrics/browser_profile_type.h"
#include "components/security_state/core/security_state.h"
#include "components/translate/core/browser/language_state.h"
@@ -35,10 +36,6 @@
class PrefService;
-namespace content {
-class RenderFrameHost;
-}
-
namespace signin {
class IdentityManager;
}
@@ -65,10 +62,13 @@ class AutofillProfile;
class AutocompleteHistoryManager;
class AutofillOfferManager;
class AutofillPopupDelegate;
+enum class AutofillProgressDialogType;
struct CardUnmaskChallengeOption;
class CardUnmaskDelegate;
class CreditCard;
+class CreditCardCVCAuthenticator;
enum class CreditCardFetchResult;
+class CreditCardOtpAuthenticator;
class FormDataImporter;
class FormStructure;
class LogManager;
@@ -325,6 +325,10 @@ class AutofillClient : public RiskDataLoader {
// client (can be null for unsupported platforms).
virtual MerchantPromoCodeManager* GetMerchantPromoCodeManager();
+ // Can be null on unsupported platforms.
+ virtual CreditCardCVCAuthenticator* GetCVCAuthenticator();
+ virtual CreditCardOtpAuthenticator* GetOtpAuthenticator();
+
// Creates and returns a SingleFieldFormFillRouter using the
// AutocompleteHistoryManager instance associated with the client.
std::unique_ptr<SingleFieldFormFillRouter> GetSingleFieldFormFillRouter();
@@ -388,7 +392,7 @@ class AutofillClient : public RiskDataLoader {
// null for platforms that don't support this, in which case standard CVC
// authentication will be used instead.
virtual std::unique_ptr<webauthn::InternalAuthenticator>
- CreateCreditCardInternalAuthenticator(content::RenderFrameHost* rfh);
+ CreateCreditCardInternalAuthenticator(AutofillDriver* driver);
#endif
// Causes the Autofill settings UI to be shown. If |show_credit_card_settings|
@@ -553,6 +557,8 @@ class AutofillClient : public RiskDataLoader {
// Called after credit card upload is finished. Will show upload result to
// users. |card_saved| indicates if the card is successfully saved.
+ // TODO(crbug.com/932818): This function is overridden in iOS codebase.
+ // Ideally should remove it if iOS is not using it to do anything.
virtual void CreditCardUploadCompleted(bool card_saved) = 0;
// Will show an infobar to get user consent for Credit Card assistive filling.
@@ -581,6 +587,23 @@ class AutofillClient : public RiskDataLoader {
// HasCreditCardScanFeature() returns true.
virtual void ScanCreditCard(CreditCardScanCallback callback) = 0;
+ // Returns true if the Touch To Fill feature is both supported by platform and
+ // enabled. Should be called before |ShowTouchToFillCreditCard| or
+ // |HideTouchToFillCreditCard|.
+ virtual bool IsTouchToFillCreditCardSupported() = 0;
+
+ // Shows the Touch To Fill surface for filling credit card information, if
+ // possible, and returns |true| on success. |delegate| will be notified of
+ // events. Should be called only if |IsTouchToFillCreditCardSupported|
+ // returns true.
+ virtual bool ShowTouchToFillCreditCard(
+ base::WeakPtr<TouchToFillDelegate> delegate) = 0;
+
+ // Hides the Touch To Fill surface for filling credit card information
+ // if one is currently shown. Should be called only if
+ // |IsTouchToFillCreditCardSupported| returns true.
+ virtual void HideTouchToFillCreditCard() = 0;
+
// Shows an Autofill popup with the given |values|, |labels|, |icons|, and
// |identifiers| for the element at |element_bounds|. |delegate| will be
// notified of popup events.
@@ -643,7 +666,9 @@ class AutofillClient : public RiskDataLoader {
// Show/dismiss the progress dialog which contains a throbber and a text
// message indicating that something is in progress.
- virtual void ShowAutofillProgressDialog(base::OnceClosure cancel_callback);
+ virtual void ShowAutofillProgressDialog(
+ AutofillProgressDialogType autofill_progress_dialog_type,
+ base::OnceClosure cancel_callback);
virtual void CloseAutofillProgressDialog(
bool show_confirmation_before_closing);
diff --git a/chromium/components/autofill/core/browser/autofill_data_util_unittest.cc b/chromium/components/autofill/core/browser/autofill_data_util_unittest.cc
index f8f2f399c8d..c4942eeed27 100644
--- a/chromium/components/autofill/core/browser/autofill_data_util_unittest.cc
+++ b/chromium/components/autofill/core/browser/autofill_data_util_unittest.cc
@@ -40,16 +40,6 @@ TEST(AutofillDataUtilTest, DetermineGroupsForHomeNameAndAddress) {
EXPECT_EQ(expected_group_bitmask, group_bitmask);
}
-TEST(AutofillDataUtilTest, DetermineGroupsForBillingNameAndAddress) {
- const std::vector<ServerFieldType> field_types{
- NAME_BILLING_FULL, ADDRESS_BILLING_LINE1, ADDRESS_BILLING_CITY,
- ADDRESS_BILLING_STATE, ADDRESS_BILLING_ZIP};
-
- const uint32_t expected_group_bitmask = kName | kAddress;
- const uint32_t group_bitmask = data_util::DetermineGroups(field_types);
- EXPECT_EQ(expected_group_bitmask, group_bitmask);
-}
-
TEST(AutofillDataUtilTest, DetermineGroupsForHomeNamePhoneAndEmail) {
const std::vector<ServerFieldType> field_types{
NAME_FULL, PHONE_HOME_CITY_AND_NUMBER, EMAIL_ADDRESS};
@@ -59,15 +49,6 @@ TEST(AutofillDataUtilTest, DetermineGroupsForHomeNamePhoneAndEmail) {
EXPECT_EQ(expected_group_bitmask, group_bitmask);
}
-TEST(AutofillDataUtilTest, DetermineGroupsForBillingNamePhoneAndEmail) {
- const std::vector<ServerFieldType> field_types{
- NAME_BILLING_FULL, PHONE_BILLING_WHOLE_NUMBER, EMAIL_ADDRESS};
-
- const uint32_t expected_group_bitmask = kName | kPhone | kEmail;
- const uint32_t group_bitmask = data_util::DetermineGroups(field_types);
- EXPECT_EQ(expected_group_bitmask, group_bitmask);
-}
-
TEST(AutofillDataUtilTest, DetermineGroupsForUnknownServerFieldType) {
const std::vector<ServerFieldType> field_types{UNKNOWN_TYPE, NAME_FULL,
ADDRESS_HOME_ZIP};
diff --git a/chromium/components/autofill/core/browser/autofill_download_manager.cc b/chromium/components/autofill/core/browser/autofill_download_manager.cc
index 611d90111bb..1d5504c01fa 100644
--- a/chromium/components/autofill/core/browser/autofill_download_manager.cc
+++ b/chromium/components/autofill/core/browser/autofill_download_manager.cc
@@ -406,7 +406,7 @@ LogBuffer& operator<<(LogBuffer& out, const AutofillUploadContents& upload) {
out << Tr{} << "has_form_tag:" << upload.has_form_tag();
if (upload.has_single_username_data()) {
- LogBuffer single_username_data;
+ LogBuffer single_username_data(LogBuffer::IsActive(true));
single_username_data << Tag{"span"} << "[";
single_username_data
<< Tr{} << "username_form_signature:"
@@ -476,10 +476,9 @@ bool CanThrottleUpload(const FormStructure& form,
std::string key = base::StringPrintf(
"%03X",
static_cast<int>(form.form_signature().value() % kNumUploadBuckets));
- auto* upload_events =
- pref_service->GetDictionary(prefs::kAutofillUploadEvents);
- auto* found = upload_events->FindKeyOfType(key, base::Value::Type::INTEGER);
- int value = found ? found->GetInt() : 0;
+ const auto& upload_events =
+ pref_service->GetValueDict(prefs::kAutofillUploadEvents);
+ int value = upload_events.FindInt(key).value_or(0);
// Calculate the mask we expect to be set for the form's upload bucket.
const int bit = static_cast<int>(form.submission_source());
@@ -736,12 +735,10 @@ bool AutofillDownloadManager::StartUploadRequest(
request_data.payload = std::move(payload);
DVLOG(1) << "Sending Autofill Upload Request:\n" << upload;
- if (log_manager_) {
- log_manager_->Log() << LoggingScope::kAutofillServer
- << LogMessage::kSendAutofillUpload << Br{}
- << "Allow upload?: " << allow_upload << Br{}
- << "Data: " << Br{} << upload;
- }
+ LOG_AF(log_manager_) << LoggingScope::kAutofillServer
+ << LogMessage::kSendAutofillUpload << Br{}
+ << "Allow upload?: " << allow_upload << Br{}
+ << "Data: " << Br{} << upload;
if (!allow_upload)
return false;
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 9f53d43dc35..2a2549fd8f3 100644
--- a/chromium/components/autofill/core/browser/autofill_download_manager_unittest.cc
+++ b/chromium/components/autofill/core/browser/autofill_download_manager_unittest.cc
@@ -345,8 +345,8 @@ TEST_F(AutofillDownloadManagerTest, QueryAndUploadTest) {
form_structures.push_back(std::make_unique<FormStructure>(form));
for (auto& form_structure : form_structures) {
- for (auto& field : *form_structure)
- field->host_form_signature = form_structure->form_signature();
+ for (auto& fs_field : *form_structure)
+ fs_field->host_form_signature = form_structure->form_signature();
}
// Make download manager.
@@ -726,8 +726,8 @@ TEST_F(AutofillDownloadManagerTest, UploadToAPITest) {
FormStructure form_structure(form);
form_structure.set_submission_source(SubmissionSource::FORM_SUBMISSION);
- for (auto& field : form_structure)
- field->host_form_signature = form_structure.form_signature();
+ for (auto& fs_field : form_structure)
+ fs_field->host_form_signature = form_structure.form_signature();
std::unique_ptr<PrefService> pref_service = test::PrefServiceForTesting();
AutofillDownloadManager download_manager(
@@ -805,8 +805,8 @@ TEST_F(AutofillDownloadManagerTest, UploadWithRawMetadata) {
form.fields.push_back(field);
FormStructure form_structure(form);
form_structure.set_submission_source(SubmissionSource::FORM_SUBMISSION);
- for (auto& field : form_structure)
- field->host_form_signature = form_structure.form_signature();
+ for (auto& fs_field : form_structure)
+ fs_field->host_form_signature = form_structure.form_signature();
std::unique_ptr<PrefService> pref_service = test::PrefServiceForTesting();
AutofillDownloadManager download_manager(
@@ -881,8 +881,8 @@ TEST_F(AutofillDownloadManagerTest, BackoffLogic_Query) {
std::vector<std::unique_ptr<FormStructure>> form_structures;
form_structures.push_back(std::make_unique<FormStructure>(form));
for (auto& form_structure : form_structures) {
- for (auto& field : *form_structure)
- field->host_form_signature = form_structure->form_signature();
+ for (auto& fs_field : *form_structure)
+ fs_field->host_form_signature = form_structure->form_signature();
}
// Request with id 0.
@@ -954,8 +954,8 @@ TEST_F(AutofillDownloadManagerTest, BackoffLogic_Upload) {
auto form_structure = std::make_unique<FormStructure>(form);
form_structure->set_submission_source(SubmissionSource::FORM_SUBMISSION);
- for (auto& field : *form_structure)
- field->host_form_signature = form_structure->form_signature();
+ for (auto& fs_field : *form_structure)
+ fs_field->host_form_signature = form_structure->form_signature();
// Request with id 0.
EXPECT_TRUE(download_manager_.StartUploadRequest(
@@ -1123,8 +1123,8 @@ TEST_F(AutofillDownloadManagerTest, RetryLimit_Upload) {
auto form_structure = std::make_unique<FormStructure>(form);
form_structure->set_submission_source(SubmissionSource::FORM_SUBMISSION);
- for (auto& field : *form_structure)
- field->host_form_signature = form_structure->form_signature();
+ for (auto& fs_field : *form_structure)
+ fs_field->host_form_signature = form_structure->form_signature();
// Request with id 0.
EXPECT_TRUE(download_manager_.StartUploadRequest(
@@ -1956,8 +1956,8 @@ TEST_P(AutofillUploadTest, RichMetadata) {
AutofillDownloadManager download_manager(driver_.get(), this);
FormStructure form_structure(form);
form_structure.set_current_page_language(LanguageCode("fr"));
- for (auto& field : form_structure)
- field->host_form_signature = form_structure.form_signature();
+ for (auto& fs_field : form_structure)
+ fs_field->host_form_signature = form_structure.form_signature();
pref_service_->SetBoolean(
RandomizedEncoder::kUrlKeyedAnonymizedDataCollectionEnabled, true);
@@ -2096,10 +2096,10 @@ TEST_P(AutofillUploadTest, ThrottlingDisabled) {
AutofillDownloadManager download_manager(driver_.get(), this);
FormStructure form_structure(form);
FormStructure small_form_structure(small_form);
- for (auto& field : form_structure)
- field->host_form_signature = form_structure.form_signature();
- for (auto& field : small_form_structure)
- field->host_form_signature = small_form_structure.form_signature();
+ for (auto& fs_field : form_structure)
+ fs_field->host_form_signature = form_structure.form_signature();
+ for (auto& fs_field : small_form_structure)
+ fs_field->host_form_signature = small_form_structure.form_signature();
for (int i = 0; i <= static_cast<int>(SubmissionSource::kMaxValue); ++i) {
base::HistogramTester histogram_tester;
diff --git a/chromium/components/autofill/core/browser/autofill_driver.h b/chromium/components/autofill/core/browser/autofill_driver.h
index 59815c14e1a..7d4b9b62fdd 100644
--- a/chromium/components/autofill/core/browser/autofill_driver.h
+++ b/chromium/components/autofill/core/browser/autofill_driver.h
@@ -17,10 +17,6 @@
#include "ui/accessibility/ax_tree_id.h"
#include "url/origin.h"
-#if !BUILDFLAG(IS_IOS)
-#include "components/webauthn/core/browser/internal_authenticator.h"
-#endif
-
namespace network {
class SharedURLLoaderFactory;
}
@@ -63,8 +59,13 @@ class AutofillDriver {
// Returns whether the user is currently operating in an incognito context.
virtual bool IsIncognito() const = 0;
- // Returns whether AutofillDriver instance is associated with a main frame,
- // and this can be a primary or non-primary main frame.
+ // Returns whether the AutofillDriver instance is associated with an active
+ // frame in the MPArch sense.
+ virtual bool IsInActiveFrame() const = 0;
+
+ // Returns whether the AutofillDriver instance is associated with a main
+ // frame, in the MPArch sense. This can be a primary or non-primary main
+ // frame.
virtual bool IsInAnyMainFrame() const = 0;
// Returns whether the AutofillDriver instance is associated with a
@@ -85,12 +86,6 @@ class AutofillDriver {
// Returns true iff the renderer is available for communication.
virtual bool RendererIsAvailable() = 0;
-#if !BUILDFLAG(IS_IOS)
- // Gets or creates a pointer to an implementation of InternalAuthenticator.
- virtual webauthn::InternalAuthenticator*
- GetOrCreateCreditCardInternalAuthenticator() = 0;
-#endif
-
// Forwards |data| to the renderer which shall preview or fill the values of
// |data|'s fields into the relevant DOM elements.
//
@@ -117,7 +112,7 @@ class AutofillDriver {
const base::flat_map<FieldGlobalId, ServerFieldType>& field_type_map) = 0;
// Forwards parsed |forms| to the embedder.
- virtual void HandleParsedForms(const std::vector<const FormData*>& forms) = 0;
+ virtual void HandleParsedForms(const std::vector<FormData>& forms) = 0;
// Sends the field type predictions specified in |forms| to the renderer. This
// method is a no-op if the renderer is not available or the appropriate
diff --git a/chromium/components/autofill/core/browser/autofill_experiments.cc b/chromium/components/autofill/core/browser/autofill_experiments.cc
index 710f91c976a..dc2274c5166 100644
--- a/chromium/components/autofill/core/browser/autofill_experiments.cc
+++ b/chromium/components/autofill/core/browser/autofill_experiments.cc
@@ -43,19 +43,15 @@
namespace autofill {
namespace {
-void LogCardUploadDisabled(LogManager* log_manager, std::string context) {
- if (log_manager) {
- log_manager->Log() << LoggingScope::kCreditCardUploadStatus
- << LogMessage::kCreditCardUploadDisabled << context
- << CTag{};
- }
+void LogCardUploadDisabled(LogManager* log_manager, base::StringPiece context) {
+ LOG_AF(log_manager) << LoggingScope::kCreditCardUploadStatus
+ << LogMessage::kCreditCardUploadDisabled << context
+ << CTag{};
}
void LogCardUploadEnabled(LogManager* log_manager) {
- if (log_manager) {
- log_manager->Log() << LoggingScope::kCreditCardUploadStatus
- << LogMessage::kCreditCardUploadEnabled << CTag{};
- }
+ LOG_AF(log_manager) << LoggingScope::kCreditCardUploadStatus
+ << LogMessage::kCreditCardUploadEnabled << CTag{};
}
// Given an email account domain, returns the contents before the first dot.
diff --git a/chromium/components/autofill/core/browser/autofill_external_delegate.cc b/chromium/components/autofill/core/browser/autofill_external_delegate.cc
index 1423b9902fe..d86f0181645 100644
--- a/chromium/components/autofill/core/browser/autofill_external_delegate.cc
+++ b/chromium/components/autofill/core/browser/autofill_external_delegate.cc
@@ -368,8 +368,8 @@ base::WeakPtr<AutofillExternalDelegate> AutofillExternalDelegate::GetWeakPtr() {
}
void AutofillExternalDelegate::OnCreditCardScanned(const CreditCard& card) {
- manager_->FillCreditCardForm(query_id_, query_form_, query_field_, card,
- std::u16string());
+ manager_->FillCreditCardFormImpl(query_form_, query_field_, card,
+ std::u16string(), query_id_);
}
void AutofillExternalDelegate::FillAutofillFormData(int unique_id,
diff --git a/chromium/components/autofill/core/browser/autofill_external_delegate.h b/chromium/components/autofill/core/browser/autofill_external_delegate.h
index c6af1bb013f..40dce87f18a 100644
--- a/chromium/components/autofill/core/browser/autofill_external_delegate.h
+++ b/chromium/components/autofill/core/browser/autofill_external_delegate.h
@@ -40,7 +40,7 @@ class AutofillExternalDelegate : public AutofillPopupDelegate {
AutofillExternalDelegate(const AutofillExternalDelegate&) = delete;
AutofillExternalDelegate& operator=(const AutofillExternalDelegate&) = delete;
- virtual ~AutofillExternalDelegate();
+ ~AutofillExternalDelegate() override;
// AutofillPopupDelegate implementation.
void OnPopupShown() override;
@@ -117,7 +117,7 @@ class AutofillExternalDelegate : public AutofillPopupDelegate {
private:
FRIEND_TEST_ALL_PREFIXES(AutofillExternalDelegateUnitTest,
- FillCreditCardForm);
+ FillCreditCardFormImpl);
// Called when a credit card is scanned using device camera.
void OnCreditCardScanned(const CreditCard& card);
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 3a3a5a102a8..45cdd7a3307 100644
--- a/chromium/components/autofill/core/browser/autofill_external_delegate_unittest.cc
+++ b/chromium/components/autofill/core/browser/autofill_external_delegate_unittest.cc
@@ -30,6 +30,7 @@
#include "components/autofill/core/common/form_data.h"
#include "components/autofill/core/common/form_field_data.h"
#include "components/autofill/core/common/password_form_fill_data.h"
+#include "components/autofill_assistant/core/public/autofill_assistant_intent.h"
#include "components/strings/grit/components_strings.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -157,12 +158,12 @@ class MockBrowserAutofillManager : public BrowserAutofillManager {
int unique_id),
(override));
MOCK_METHOD(void,
- FillCreditCardForm,
- (int query_id,
- const FormData& form,
+ FillCreditCardFormImpl,
+ (const FormData& form,
const FormFieldData& field,
const CreditCard& credit_card,
- const std::u16string& cvc),
+ const std::u16string& cvc,
+ int query_id),
(override));
private:
@@ -213,7 +214,7 @@ class AutofillExternalDelegateUnitTest : public testing::Test {
query_id, suggestions, /*autoselect_first_suggestion=*/false);
}
- base::test::SingleThreadTaskEnvironment task_environment_;
+ base::test::TaskEnvironment task_environment_;
NiceMock<MockAutofillClient> autofill_client_;
std::unique_ptr<NiceMock<MockAutofillDriver>> autofill_driver_;
@@ -842,12 +843,12 @@ MATCHER_P(CreditCardMatches, card, "") {
// Test that autofill manager will fill the credit card form after user scans a
// credit card.
-TEST_F(AutofillExternalDelegateUnitTest, FillCreditCardForm) {
+TEST_F(AutofillExternalDelegateUnitTest, FillCreditCardFormImpl) {
CreditCard card;
test::SetCreditCardInfo(&card, "Alice", "4111", "1", "3000", "1");
- EXPECT_CALL(
- *browser_autofill_manager_,
- FillCreditCardForm(_, _, _, CreditCardMatches(card), std::u16string()));
+ EXPECT_CALL(*browser_autofill_manager_,
+ FillCreditCardFormImpl(_, _, CreditCardMatches(card),
+ std::u16string(), _));
external_delegate_->OnCreditCardScanned(card);
}
diff --git a/chromium/components/autofill/core/browser/autofill_field.cc b/chromium/components/autofill/core/browser/autofill_field.cc
index d53d042400a..67f1f694864 100644
--- a/chromium/components/autofill/core/browser/autofill_field.cc
+++ b/chromium/components/autofill/core/browser/autofill_field.cc
@@ -111,13 +111,6 @@ void AutofillField::SetHtmlType(HtmlFieldType type, HtmlFieldMode mode) {
html_type_ = type;
html_mode_ = mode;
overall_type_ = AutofillType(NO_SERVER_DATA);
-
- if (type == HTML_TYPE_TEL_LOCAL_PREFIX)
- phone_part_ = PHONE_PREFIX;
- else if (type == HTML_TYPE_TEL_LOCAL_SUFFIX)
- phone_part_ = PHONE_SUFFIX;
- else
- phone_part_ = IGNORED;
}
void AutofillField::SetTypeTo(const AutofillType& type) {
@@ -211,8 +204,14 @@ AutofillType AutofillField::ComputedType() const {
(heuristic_type() == ADDRESS_HOME_STREET_NAME ||
heuristic_type() == ADDRESS_HOME_HOUSE_NUMBER));
+ // For merchant promo code fields the heuristic predictions get precedence
+ // over the server predictions.
believe_server =
- believe_server && !(heuristic_type() == MERCHANT_PROMO_CODE);
+ believe_server && (heuristic_type() != MERCHANT_PROMO_CODE);
+
+ // For international bank account number (IBAN) fields the heuristic
+ // predictions get precedence over the server predictions.
+ believe_server = believe_server && (heuristic_type() != IBAN_VALUE);
if (believe_server)
return AutofillType(server_type());
@@ -251,9 +250,6 @@ std::string AutofillField::FieldSignatureAsStr() const {
}
bool AutofillField::IsFieldFillable() const {
- if (!base::FeatureList::IsEnabled(features::kAutofillFixFillableFieldTypes))
- return !Type().IsUnknown();
-
ServerFieldType field_type = Type().GetStorableType();
return IsFillableFieldType(field_type);
}
diff --git a/chromium/components/autofill/core/browser/autofill_field.h b/chromium/components/autofill/core/browser/autofill_field.h
index 920b0959882..15ee399ca60 100644
--- a/chromium/components/autofill/core/browser/autofill_field.h
+++ b/chromium/components/autofill/core/browser/autofill_field.h
@@ -32,12 +32,6 @@ typedef std::map<ServerFieldType, AutofillDataModel::ValidityState>
class AutofillField : public FormFieldData {
public:
- enum PhonePart {
- IGNORED = 0,
- PHONE_PREFIX = 1,
- PHONE_SUFFIX = 2,
- };
-
AutofillField();
explicit AutofillField(const FormFieldData& field);
@@ -70,7 +64,6 @@ class AutofillField : public FormFieldData {
const ServerFieldTypeValidityStatesMap& possible_types_validities() const {
return possible_types_validities_;
}
- PhonePart phone_part() const { return phone_part_; }
bool previously_autofilled() const { return previously_autofilled_; }
const std::u16string& parseable_name() const { return parseable_name_; }
const std::u16string& parseable_label() const { return parseable_label_; }
@@ -128,9 +121,9 @@ class AutofillField : public FormFieldData {
// (i.e. overall_type_ != NO_SERVER_DATA ? overall_type_ : ComputedType())
AutofillType Type() const;
- // This function automatically chooses between server and heuristic autofill
- // type, depending on the data available for this field alone.
- // This type does not take into account the rationalization involving the
+ // This function automatically chooses among the Autofill server, heuristic
+ // and html type, depending on the data available for this field alone. This
+ // type does not take into account the rationalization involving the
// surrounding fields.
AutofillType ComputedType() const;
@@ -275,9 +268,6 @@ class AutofillField : public FormFieldData {
// The set of possible types and their validity for this field.
ServerFieldTypeValidityStatesMap possible_types_validities_;
- // Used to track whether this field is a phone prefix or suffix.
- PhonePart phone_part_ = IGNORED;
-
// A low-entropy hash of the field's initial value before user-interactions or
// automatic fillings. This field is used to detect static placeholders.
absl::optional<uint32_t> initial_value_hash_;
diff --git a/chromium/components/autofill/core/browser/autofill_form_test_utils.cc b/chromium/components/autofill/core/browser/autofill_form_test_utils.cc
index 3acab8e9ef3..92f5273ca2a 100644
--- a/chromium/components/autofill/core/browser/autofill_form_test_utils.cc
+++ b/chromium/components/autofill/core/browser/autofill_form_test_utils.cc
@@ -115,6 +115,7 @@ FormData GetFormData(const FormDataDescription& d) {
ff.is_autofilled = dd.is_autofilled.value_or(false);
ff.origin = dd.origin.value_or(f.main_frame_origin);
ff.should_autocomplete = dd.should_autocomplete;
+ ff.properties_mask = dd.properties_mask;
f.fields.push_back(ff);
}
return f;
@@ -159,7 +160,7 @@ void FormStructureTest::CheckFormStructureTestData(
static_cast<int>(form_structure->autofill_count()));
}
if (test_case.form_flags.section_count) {
- std::set<std::string> section_names;
+ std::set<Section> section_names;
for (const auto& field : *form_structure)
section_names.insert(field->section);
EXPECT_EQ(*test_case.form_flags.section_count,
@@ -172,11 +173,6 @@ void FormStructureTest::CheckFormStructureTestData(
form_structure->field(i)->html_type());
}
for (size_t i = 0;
- i < test_case.expected_field_types.expected_phone_part.size(); i++) {
- EXPECT_EQ(test_case.expected_field_types.expected_phone_part[i],
- form_structure->field(i)->phone_part());
- }
- for (size_t i = 0;
i < test_case.expected_field_types.expected_heuristic_type.size();
i++) {
EXPECT_EQ(test_case.expected_field_types.expected_heuristic_type[i],
diff --git a/chromium/components/autofill/core/browser/autofill_form_test_utils.h b/chromium/components/autofill/core/browser/autofill_form_test_utils.h
index 8da4714b0f9..076711dc928 100644
--- a/chromium/components/autofill/core/browser/autofill_form_test_utils.h
+++ b/chromium/components/autofill/core/browser/autofill_form_test_utils.h
@@ -47,6 +47,7 @@ struct FieldDataDescription {
absl::optional<bool> is_autofilled;
absl::optional<url::Origin> origin;
std::vector<SelectOption> select_options = {};
+ FieldPropertiesMask properties_mask = 0;
};
// Attributes provided to the test form.
@@ -89,7 +90,6 @@ struct TestFormFlags {
template <typename = void>
struct ExpectedFieldTypeValues {
std::vector<HtmlFieldType> expected_html_type = {};
- std::vector<AutofillField::PhonePart> expected_phone_part = {};
std::vector<ServerFieldType> expected_heuristic_type = {};
std::vector<ServerFieldType> expected_overall_type = {};
};
diff --git a/chromium/components/autofill/core/browser/autofill_ie_toolbar_import_win.cc b/chromium/components/autofill/core/browser/autofill_ie_toolbar_import_win.cc
deleted file mode 100644
index bf3af43c9fa..00000000000
--- a/chromium/components/autofill/core/browser/autofill_ie_toolbar_import_win.cc
+++ /dev/null
@@ -1,306 +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/autofill_ie_toolbar_import_win.h"
-
-#include <stddef.h>
-#include <stdint.h>
-#include <map>
-#include <string>
-#include <vector>
-
-#include "base/check.h"
-#include "base/compiler_specific.h"
-#include "base/memory/raw_ptr.h"
-#include "base/win/registry.h"
-#include "components/autofill/core/browser/crypto/rc4_decryptor.h"
-#include "components/autofill/core/browser/data_model/autofill_profile.h"
-#include "components/autofill/core/browser/data_model/credit_card.h"
-#include "components/autofill/core/browser/data_model/form_group.h"
-#include "components/autofill/core/browser/data_model/phone_number.h"
-#include "components/autofill/core/browser/field_types.h"
-#include "components/autofill/core/browser/geo/autofill_country.h"
-#include "components/autofill/core/browser/geo/phone_number_i18n.h"
-#include "components/autofill/core/browser/personal_data_manager.h"
-#include "components/autofill/core/browser/personal_data_manager_observer.h"
-#include "components/os_crypt/os_crypt.h"
-
-using base::win::RegKey;
-
-namespace autofill {
-
-// Forward declaration. This function is not in unnamed namespace as it
-// is referenced in the unittest.
-bool ImportCurrentUserProfiles(const std::string& app_locale,
- std::vector<AutofillProfile>* profiles,
- std::vector<CreditCard>* credit_cards);
-namespace {
-
-const wchar_t* const kProfileKey =
- L"Software\\Google\\Google Toolbar\\4.0\\Autofill\\Profiles";
-const wchar_t* const kCreditCardKey =
- L"Software\\Google\\Google Toolbar\\4.0\\Autofill\\Credit Cards";
-const wchar_t* const kPasswordHashValue = L"password_hash";
-const wchar_t* const kSaltValue = L"salt";
-
-// This string is stored along with saved addresses and credit cards in the
-// WebDB, and hence should not be modified, so that it remains consistent over
-// time.
-const char kIEToolbarImportOrigin[] = "Imported from Internet Explorer";
-
-// This is RC4 decryption for Toolbar credit card data. This is necessary
-// because it is not standard, so Crypto API cannot be used.
-std::wstring DecryptCCNumber(const std::wstring& data) {
- const wchar_t* kEmptyKey =
- L"\x3605\xCEE5\xCE49\x44F7\xCF4E\xF6CC\x604B\xFCBE\xC70A\x08FD";
- const size_t kMacLen = 10;
-
- if (data.length() <= kMacLen)
- return std::wstring();
-
- RC4Decryptor rc4_algorithm(kEmptyKey);
- return rc4_algorithm.Run(data.substr(kMacLen));
-}
-
-bool IsEmptySalt(std::wstring const& salt) {
- // Empty salt in IE Toolbar is \x1\x2...\x14
- if (salt.length() != 20)
- return false;
- for (size_t i = 0; i < salt.length(); ++i) {
- if (salt[i] != i + 1)
- return false;
- }
- return true;
-}
-
-std::wstring ReadAndDecryptValue(const RegKey& key, const wchar_t* value_name) {
- DWORD data_type = REG_BINARY;
- DWORD data_size = 0;
- LONG result = key.ReadValue(value_name, nullptr, &data_size, &data_type);
- if ((result != ERROR_SUCCESS) || !data_size || data_type != REG_BINARY)
- return std::wstring();
- std::string data;
- data.resize(data_size);
- result = key.ReadValue(value_name, &(data[0]), &data_size, &data_type);
- if (result == ERROR_SUCCESS) {
- std::string out_data;
- if (OSCrypt::DecryptString(data, &out_data)) {
- // The actual data is in UTF16 already.
- if (!(out_data.size() & 1) && (out_data.size() > 2) &&
- !out_data[out_data.size() - 1] && !out_data[out_data.size() - 2]) {
- return reinterpret_cast<const wchar_t*>(out_data.c_str());
- }
- }
- }
- return std::wstring();
-}
-
-struct {
- ServerFieldType field_type;
- const wchar_t *reg_value_name;
-} profile_reg_values[] = {
- {NAME_FIRST, L"name_first"},
- {NAME_MIDDLE, L"name_middle"},
- {NAME_LAST, L"name_last"},
- {NAME_SUFFIX, L"name_suffix"},
- {EMAIL_ADDRESS, L"email"},
- {COMPANY_NAME, L"company_name"},
- {PHONE_HOME_NUMBER, L"phone_home_number"},
- {PHONE_HOME_CITY_CODE, L"phone_home_city_code"},
- {PHONE_HOME_COUNTRY_CODE, L"phone_home_country_code"},
- {ADDRESS_HOME_LINE1, L"address_home_line1"},
- {ADDRESS_HOME_LINE2, L"address_home_line2"},
- {ADDRESS_HOME_CITY, L"address_home_city"},
- {ADDRESS_HOME_STATE, L"address_home_state"},
- {ADDRESS_HOME_ZIP, L"address_home_zip"},
- {ADDRESS_HOME_COUNTRY, L"address_home_country"},
- {ADDRESS_BILLING_LINE1, L"address_billing_line1"},
- {ADDRESS_BILLING_LINE2, L"address_billing_line2"},
- {ADDRESS_BILLING_CITY, L"address_billing_city"},
- {ADDRESS_BILLING_STATE, L"address_billing_state"},
- {ADDRESS_BILLING_ZIP, L"address_billing_zip"},
- {ADDRESS_BILLING_COUNTRY, L"address_billing_country"},
- {CREDIT_CARD_NAME_FULL, L"credit_card_name_full"},
- {CREDIT_CARD_NUMBER, L"credit_card_number"},
- {CREDIT_CARD_EXP_MONTH, L"credit_card_exp_month"},
- {CREDIT_CARD_EXP_4_DIGIT_YEAR, L"credit_card_exp_4_digit_year"},
- {CREDIT_CARD_TYPE, L"credit_card_type"},
- // We do not import verification code.
-};
-
-typedef std::map<std::wstring, ServerFieldType> RegToFieldMap;
-
-// Imports address or credit card data from the given registry |key| into the
-// given |form_group|, with the help of |reg_to_field|. When importing address
-// data, writes the phone data into |phone|; otherwise, |phone| should be null.
-// Returns true if any fields were set, false otherwise.
-bool ImportSingleFormGroup(const RegKey& key,
- const RegToFieldMap& reg_to_field,
- const std::string& app_locale,
- FormGroup* form_group,
- PhoneNumber::PhoneCombineHelper* phone) {
- if (!key.Valid())
- return false;
-
- bool has_non_empty_fields = false;
-
- for (uint32_t i = 0; i < key.GetValueCount(); ++i) {
- std::wstring value_name;
- if (key.GetValueNameAt(i, &value_name) != ERROR_SUCCESS)
- continue;
-
- RegToFieldMap::const_iterator it = reg_to_field.find(value_name);
- if (it == reg_to_field.end())
- continue; // This field is not imported.
-
- std::wstring field_value = ReadAndDecryptValue(key, value_name.c_str());
- if (!field_value.empty()) {
- if (it->second == CREDIT_CARD_NUMBER)
- field_value = DecryptCCNumber(field_value);
-
- // Phone numbers are stored piece-by-piece, and then reconstructed from
- // the pieces. The rest of the fields are set "as is".
- if (!phone || !phone->SetInfo(AutofillType(it->second),
- base::WideToUTF16(field_value))) {
- has_non_empty_fields = true;
- form_group->SetInfo(AutofillType(it->second),
- base::WideToUTF16(field_value), app_locale);
- }
- }
- }
-
- return has_non_empty_fields;
-}
-
-// Imports address data from the given registry |key| into the given |profile|,
-// with the help of |reg_to_field|. Returns true if any fields were set, false
-// otherwise.
-bool ImportSingleProfile(const std::string& app_locale,
- const RegKey& key,
- const RegToFieldMap& reg_to_field,
- AutofillProfile* profile) {
- PhoneNumber::PhoneCombineHelper phone;
- bool has_non_empty_fields =
- ImportSingleFormGroup(key, reg_to_field, app_locale, profile, &phone);
-
- // Now re-construct the phones if needed.
- std::u16string constructed_number;
- if (phone.ParseNumber(*profile, app_locale, &constructed_number)) {
- has_non_empty_fields = true;
- profile->SetRawInfo(PHONE_HOME_WHOLE_NUMBER, constructed_number);
- }
-
- return has_non_empty_fields;
-}
-
-// Imports profiles from the IE toolbar and stores them. Asynchronous
-// if PersonalDataManager has not been loaded yet. Deletes itself on completion.
-class AutofillImporter : public PersonalDataManagerObserver {
- public:
- explicit AutofillImporter(PersonalDataManager* personal_data_manager)
- : personal_data_manager_(personal_data_manager) {
- personal_data_manager_->AddObserver(this);
- }
-
- bool ImportProfiles() {
- if (!ImportCurrentUserProfiles(personal_data_manager_->app_locale(),
- &profiles_,
- &credit_cards_)) {
- delete this;
- return false;
- }
- if (personal_data_manager_->IsDataLoaded())
- OnPersonalDataChanged();
- return true;
- }
-
- // PersonalDataManagerObserver:
- void OnPersonalDataChanged() override {
- for (const AutofillProfile& it : profiles_)
- personal_data_manager_->AddProfile(it);
- for (const CreditCard& it : credit_cards_)
- personal_data_manager_->AddCreditCard(it);
- delete this;
- }
-
- private:
- ~AutofillImporter() override { personal_data_manager_->RemoveObserver(this); }
-
- raw_ptr<PersonalDataManager> personal_data_manager_;
- std::vector<AutofillProfile> profiles_;
- std::vector<CreditCard> credit_cards_;
-};
-
-} // namespace
-
-// Imports Autofill profiles and credit cards from IE Toolbar if present and not
-// password protected. Returns true if data is successfully retrieved. False if
-// there is no data, data is password protected or error occurred.
-bool ImportCurrentUserProfiles(const std::string& app_locale,
- std::vector<AutofillProfile>* profiles,
- std::vector<CreditCard>* credit_cards) {
- DCHECK(profiles);
- DCHECK(credit_cards);
-
- // Create a map of possible fields for a quick access.
- RegToFieldMap reg_to_field;
- for (const auto& profile_reg_value : profile_reg_values) {
- reg_to_field[std::wstring(profile_reg_value.reg_value_name)] =
- profile_reg_value.field_type;
- }
-
- base::win::RegistryKeyIterator iterator_profiles(HKEY_CURRENT_USER,
- kProfileKey);
- for (; iterator_profiles.Valid(); ++iterator_profiles) {
- std::wstring key_name(kProfileKey);
- key_name.append(L"\\");
- key_name.append(iterator_profiles.Name());
- RegKey key(HKEY_CURRENT_USER, key_name.c_str(), KEY_READ);
- AutofillProfile profile;
- profile.set_origin(kIEToolbarImportOrigin);
- if (ImportSingleProfile(app_locale, key, reg_to_field, &profile)) {
- // Combine phones into whole phone #.
- profiles->push_back(profile);
- }
- }
- std::wstring password_hash;
- std::wstring salt;
- RegKey cc_key(HKEY_CURRENT_USER, kCreditCardKey, KEY_READ);
- if (cc_key.Valid()) {
- password_hash = ReadAndDecryptValue(cc_key, kPasswordHashValue);
- salt = ReadAndDecryptValue(cc_key, kSaltValue);
- }
-
- // We import CC profiles only if they are not password protected.
- if (password_hash.empty() && IsEmptySalt(salt)) {
- base::win::RegistryKeyIterator iterator_cc(HKEY_CURRENT_USER,
- kCreditCardKey);
- for (; iterator_cc.Valid(); ++iterator_cc) {
- std::wstring key_name(kCreditCardKey);
- key_name.append(L"\\");
- key_name.append(iterator_cc.Name());
- RegKey key(HKEY_CURRENT_USER, key_name.c_str(), KEY_READ);
- CreditCard credit_card;
- credit_card.set_origin(kIEToolbarImportOrigin);
- if (ImportSingleFormGroup(key, reg_to_field, app_locale, &credit_card,
- nullptr)) {
- std::u16string cc_number = credit_card.GetRawInfo(CREDIT_CARD_NUMBER);
- if (!cc_number.empty())
- credit_cards->push_back(credit_card);
- }
- }
- }
- return (profiles->size() + credit_cards->size()) > 0;
-}
-
-bool ImportAutofillDataWin(PersonalDataManager* pdm) {
- // In incognito mode we do not have PDM - and we should not import anything.
- if (!pdm)
- return false;
- AutofillImporter* importer = new AutofillImporter(pdm);
- // importer will self delete.
- return importer->ImportProfiles();
-}
-
-} // namespace autofill
diff --git a/chromium/components/autofill/core/browser/autofill_ie_toolbar_import_win.h b/chromium/components/autofill/core/browser/autofill_ie_toolbar_import_win.h
deleted file mode 100644
index 830aac2555f..00000000000
--- a/chromium/components/autofill/core/browser/autofill_ie_toolbar_import_win.h
+++ /dev/null
@@ -1,24 +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_AUTOFILL_IE_TOOLBAR_IMPORT_WIN_H_
-#define COMPONENTS_AUTOFILL_CORE_BROWSER_AUTOFILL_IE_TOOLBAR_IMPORT_WIN_H_
-
-namespace autofill {
-
-// This importer is here and not in chrome/browser/importer/toolbar_importer.cc
-// because of the following:
-// 1. The data is not saved in profile, but rather in registry, thus it is
-// accessed without going through toolbar front end.
-// 2. This applies to IE (thus Windows) toolbar only.
-// 3. The functionality relevant only to and completely encapsulated in the
-// autofill.
-// 4. This is completely automated as opposed to Importers, which are explicit.
-class PersonalDataManager;
-
-bool ImportAutofillDataWin(PersonalDataManager* pdm);
-
-} // namespace autofill
-
-#endif // COMPONENTS_AUTOFILL_CORE_BROWSER_AUTOFILL_IE_TOOLBAR_IMPORT_WIN_H_
diff --git a/chromium/components/autofill/core/browser/autofill_ie_toolbar_import_win_unittest.cc b/chromium/components/autofill/core/browser/autofill_ie_toolbar_import_win_unittest.cc
deleted file mode 100644
index 22051ec9175..00000000000
--- a/chromium/components/autofill/core/browser/autofill_ie_toolbar_import_win_unittest.cc
+++ /dev/null
@@ -1,231 +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/autofill_ie_toolbar_import_win.h"
-
-#include <stddef.h>
-#include <windows.h>
-
-#include <string>
-
-#include "base/strings/utf_string_conversions.h"
-#include "base/win/registry.h"
-#include "components/autofill/core/browser/data_model/autofill_profile.h"
-#include "components/autofill/core/browser/data_model/credit_card.h"
-#include "components/autofill/core/browser/field_types.h"
-#include "components/os_crypt/os_crypt.h"
-#include "components/os_crypt/os_crypt_mocker.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-using base::win::RegKey;
-
-namespace autofill {
-
-// Defined in autofill_ie_toolbar_import_win.cc. Not exposed in the header file.
-bool ImportCurrentUserProfiles(const std::string& app_locale,
- std::vector<AutofillProfile>* profiles,
- std::vector<CreditCard>* credit_cards);
-
-namespace {
-
-const wchar_t kUnitTestRegistrySubKey[] = L"SOFTWARE\\Chromium Unit Tests";
-const wchar_t kUnitTestUserOverrideSubKey[] =
- L"SOFTWARE\\Chromium Unit Tests\\HKCU Override";
-
-const wchar_t kProfileKey[] =
- L"Software\\Google\\Google Toolbar\\4.0\\Autofill\\Profiles";
-const wchar_t kCreditCardKey[] =
- L"Software\\Google\\Google Toolbar\\4.0\\Autofill\\Credit Cards";
-const wchar_t kPasswordHashValue[] = L"password_hash";
-const wchar_t kSaltValue[] = L"salt";
-
-struct ValueDescription {
- wchar_t const* const value_name;
- wchar_t const* const value;
-};
-
-ValueDescription profile1[] = {
- { L"name_first", L"John" },
- { L"name_middle", L"Herman" },
- { L"name_last", L"Doe" },
- { L"email", L"jdoe@test.com" },
- { L"company_name", L"Testcompany" },
- { L"phone_home_number", L"555-5555" },
- { L"phone_home_city_code", L"650" },
- { L"phone_home_country_code", L"1" },
-};
-
-ValueDescription profile2[] = {
- { L"name_first", L"Jane" },
- { L"name_last", L"Doe" },
- { L"email", L"janedoe@test.com" },
- { L"company_name", L"Testcompany" },
-};
-
-ValueDescription credit_card[] = {
- {L"credit_card_name_full", L"Tommy Gun"},
- // "4111111111111111" encrypted:
- {L"credit_card_number",
- L"\xE53F\x19AB\xC1BF\xC9EB\xECCC\x9BDA\x8515"
- L"\xE14D\x6852\x80A8\x50A3\x4375\xFD9F\x1E07"
- L"\x790E\x7336\xB773\xAF33\x93EA\xB846\xEC89"
- L"\x265C\xD0E6\x4E23\xB75F\x7983"},
- {L"credit_card_exp_month", L"11"},
- {L"credit_card_exp_4_digit_year", L"2011"},
-};
-
-ValueDescription empty_salt = {
- kSaltValue,
- L"\x1\x2\x3\x4\x5\x6\x7\x8\x9\xA\xB\xC\xD\xE\xF\x10\x11\x12\x13\x14"
-};
-
-ValueDescription empty_password = {
- kPasswordHashValue, L""
-};
-
-ValueDescription protected_salt = {
- kSaltValue, L"\x4854\xB906\x9C7C\x50A6\x4376\xFD9D\x1E02"
-};
-
-ValueDescription protected_password = {
- kPasswordHashValue, L"\x18B7\xE586\x459B\x7457\xA066\x3842\x71DA"
-};
-
-void EncryptAndWrite(RegKey* key, const ValueDescription* value) {
- std::string data;
- size_t data_size = (lstrlen(value->value) + 1) * sizeof(wchar_t);
- data.resize(data_size);
- memcpy(&data[0], value->value, data_size);
-
- std::string encrypted_data;
- OSCrypt::EncryptString(data, &encrypted_data);
- EXPECT_EQ(ERROR_SUCCESS, key->WriteValue(value->value_name,
- &encrypted_data[0], encrypted_data.size(), REG_BINARY));
-}
-
-void CreateSubkey(RegKey* key, wchar_t const* subkey_name,
- const ValueDescription* values, size_t values_size) {
- RegKey subkey;
- subkey.Create(key->Handle(), subkey_name, KEY_ALL_ACCESS);
- EXPECT_TRUE(subkey.Valid());
- for (size_t i = 0; i < values_size; ++i)
- EncryptAndWrite(&subkey, values + i);
-}
-
-} // namespace
-
-class AutofillIeToolbarImportTest : public testing::Test {
- public:
- AutofillIeToolbarImportTest();
-
- AutofillIeToolbarImportTest(const AutofillIeToolbarImportTest&) = delete;
- AutofillIeToolbarImportTest& operator=(const AutofillIeToolbarImportTest&) =
- delete;
-
- // testing::Test method overrides:
- void SetUp() override;
- void TearDown() override;
-
- private:
- RegKey temp_hkcu_hive_key_;
-};
-
-AutofillIeToolbarImportTest::AutofillIeToolbarImportTest() {
-}
-
-void AutofillIeToolbarImportTest::SetUp() {
- OSCryptMocker::SetUp();
- temp_hkcu_hive_key_.Create(HKEY_CURRENT_USER,
- kUnitTestUserOverrideSubKey,
- KEY_ALL_ACCESS);
- EXPECT_TRUE(temp_hkcu_hive_key_.Valid());
- EXPECT_EQ(ERROR_SUCCESS, RegOverridePredefKey(HKEY_CURRENT_USER,
- temp_hkcu_hive_key_.Handle()));
-}
-
-void AutofillIeToolbarImportTest::TearDown() {
- EXPECT_EQ(ERROR_SUCCESS, RegOverridePredefKey(HKEY_CURRENT_USER, nullptr));
- temp_hkcu_hive_key_.Close();
- RegKey key(HKEY_CURRENT_USER, kUnitTestRegistrySubKey, KEY_ALL_ACCESS);
- key.DeleteKey(L"");
- OSCryptMocker::TearDown();
-}
-
-TEST_F(AutofillIeToolbarImportTest, TestAutofillImport) {
- RegKey profile_key;
- profile_key.Create(HKEY_CURRENT_USER, kProfileKey, KEY_ALL_ACCESS);
- EXPECT_TRUE(profile_key.Valid());
-
- CreateSubkey(&profile_key, L"0", profile1, std::size(profile1));
- CreateSubkey(&profile_key, L"1", profile2, std::size(profile2));
-
- RegKey cc_key;
- cc_key.Create(HKEY_CURRENT_USER, kCreditCardKey, KEY_ALL_ACCESS);
- EXPECT_TRUE(cc_key.Valid());
- CreateSubkey(&cc_key, L"0", credit_card, std::size(credit_card));
- EncryptAndWrite(&cc_key, &empty_password);
- EncryptAndWrite(&cc_key, &empty_salt);
-
- profile_key.Close();
- cc_key.Close();
-
- std::vector<AutofillProfile> profiles;
- std::vector<CreditCard> credit_cards;
- EXPECT_TRUE(ImportCurrentUserProfiles("en-US", &profiles, &credit_cards));
- ASSERT_EQ(2U, profiles.size());
- // The profiles are read in reverse order.
- EXPECT_EQ(base::WideToUTF16(profile1[0].value),
- profiles[1].GetRawInfo(NAME_FIRST));
- EXPECT_EQ(base::WideToUTF16(profile1[1].value),
- profiles[1].GetRawInfo(NAME_MIDDLE));
- EXPECT_EQ(base::WideToUTF16(profile1[2].value),
- profiles[1].GetRawInfo(NAME_LAST));
- EXPECT_EQ(base::WideToUTF16(profile1[3].value),
- profiles[1].GetRawInfo(EMAIL_ADDRESS));
- EXPECT_EQ(base::WideToUTF16(profile1[4].value),
- profiles[1].GetRawInfo(COMPANY_NAME));
- EXPECT_EQ(base::WideToUTF16(profile1[7].value),
- profiles[1].GetInfo(AutofillType(PHONE_HOME_COUNTRY_CODE), "US"));
- EXPECT_EQ(base::WideToUTF16(profile1[6].value),
- profiles[1].GetInfo(AutofillType(PHONE_HOME_CITY_CODE), "US"));
- EXPECT_EQ(u"5555555",
- profiles[1].GetInfo(AutofillType(PHONE_HOME_NUMBER), "US"));
- EXPECT_EQ(u"1 650-555-5555", profiles[1].GetRawInfo(PHONE_HOME_WHOLE_NUMBER));
-
- EXPECT_EQ(base::WideToUTF16(profile2[0].value),
- profiles[0].GetRawInfo(NAME_FIRST));
- EXPECT_EQ(base::WideToUTF16(profile2[1].value),
- profiles[0].GetRawInfo(NAME_LAST));
- EXPECT_EQ(base::WideToUTF16(profile2[2].value),
- profiles[0].GetRawInfo(EMAIL_ADDRESS));
- EXPECT_EQ(base::WideToUTF16(profile2[3].value),
- profiles[0].GetRawInfo(COMPANY_NAME));
-
- ASSERT_EQ(1U, credit_cards.size());
- EXPECT_EQ(base::WideToUTF16(credit_card[0].value),
- credit_cards[0].GetRawInfo(CREDIT_CARD_NAME_FULL));
- EXPECT_EQ(u"4111111111111111",
- credit_cards[0].GetRawInfo(CREDIT_CARD_NUMBER));
- EXPECT_EQ(base::WideToUTF16(credit_card[2].value),
- credit_cards[0].GetRawInfo(CREDIT_CARD_EXP_MONTH));
- EXPECT_EQ(base::WideToUTF16(credit_card[3].value),
- credit_cards[0].GetRawInfo(CREDIT_CARD_EXP_4_DIGIT_YEAR));
-
- // Mock password encrypted cc.
- cc_key.Open(HKEY_CURRENT_USER, kCreditCardKey, KEY_ALL_ACCESS);
- EXPECT_TRUE(cc_key.Valid());
- EncryptAndWrite(&cc_key, &protected_password);
- EncryptAndWrite(&cc_key, &protected_salt);
- cc_key.Close();
-
- profiles.clear();
- credit_cards.clear();
- EXPECT_TRUE(ImportCurrentUserProfiles("en-US", &profiles, &credit_cards));
- // Profiles are not protected.
- EXPECT_EQ(2U, profiles.size());
- // Credit cards are.
- EXPECT_EQ(0U, credit_cards.size());
-}
-
-} // namespace autofill
diff --git a/chromium/components/autofill/core/browser/autofill_manager.cc b/chromium/components/autofill/core/browser/autofill_manager.cc
index 858cec0d810..54ae9d91a5e 100644
--- a/chromium/components/autofill/core/browser/autofill_manager.cc
+++ b/chromium/components/autofill/core/browser/autofill_manager.cc
@@ -4,9 +4,14 @@
#include "components/autofill/core/browser/autofill_manager.h"
+#include "base/bind.h"
#include "base/command_line.h"
#include "base/containers/adapters.h"
+#include "base/containers/contains.h"
#include "base/feature_list.h"
+#include "base/metrics/histogram_macros.h"
+#include "base/task/thread_pool.h"
+#include "components/autofill/core/browser/data_model/credit_card.h"
#include "components/autofill/core/browser/form_structure.h"
#include "components/autofill/core/browser/logging/log_manager.h"
#include "components/autofill/core/common/autofill_constants.h"
@@ -18,6 +23,7 @@
#include "components/autofill/core/common/autofill_switches.h"
#include "components/autofill/core/common/autofill_tick_clock.h"
#include "components/translate/core/common/language_detection_details.h"
+#include "components/translate/core/common/translate_constants.h"
#include "google_apis/google_api_keys.h"
#include "ui/gfx/geometry/rect_f.h"
@@ -25,6 +31,37 @@ namespace autofill {
namespace {
+// Creates a reply callback for ParseFormAsync().
+//
+// An event
+// AutofillManager::OnFoo(const FormData& form, args...)
+// is handled by
+// asynchronously parsing the form and then calling
+// AutofillManager::OnFooImpl(const FormData& form, args...)
+// unless the AutofillManager has been destructed or reset in the meantime.
+//
+// ParsingCallback(&AutofillManager::OnFooImpl, args...) creates the
+// corresponding callback to be passed to ParseFormAsync().
+//
+// The `after_event` is supposed to be &Observer::OnAfterFoo (or nullptr if no
+// such event exists). The callback notifies the observers of `after_event`.
+template <typename Functor, typename... Args>
+base::OnceCallback<void(AutofillManager&, const FormData&)> ParsingCallback(
+ Functor&& functor,
+ void (AutofillManager::Observer::*after_event)(),
+ Args&&... args) {
+ return base::BindOnce(
+ [](Functor&& functor, void (AutofillManager::Observer::*after_event)(),
+ std::remove_reference_t<Args&&>... args, AutofillManager& self,
+ const FormData& form) {
+ base::invoke(std::forward<Functor>(functor), self, form,
+ std::forward<Args>(args)...);
+ if (after_event)
+ self.NotifyObservers(after_event);
+ },
+ std::forward<Functor>(functor), after_event, std::forward<Args>(args)...);
+}
+
// Returns the AutofillField* corresponding to |field| in |form| or nullptr,
// if not found.
AutofillField* FindAutofillFillField(const FormStructure& form,
@@ -42,6 +79,7 @@ AutofillField* FindAutofillFillField(const FormStructure& form,
}
// Returns true if |live_form| does not match |cached_form|.
+// TODO(crbug.com/1211834): This should be some form of FormData::DeepEqual().
bool CachedFormNeedsUpdate(const FormData& live_form,
const FormStructure& cached_form) {
if (cached_form.version() > live_form.version)
@@ -73,8 +111,6 @@ std::string GetAPIKeyForUrl(version_info::Channel channel) {
} // namespace
-using base::TimeTicks;
-
// static
void AutofillManager::LogAutofillTypePredictionsAvailable(
LogManager* log_manager,
@@ -85,15 +121,12 @@ void AutofillManager::LogAutofillTypePredictionsAvailable(
VLOG(1) << *form;
}
- if (!log_manager || !log_manager->IsLoggingActive())
- return;
-
- LogBuffer buffer;
+ LogBuffer buffer(IsLoggingActive(log_manager));
for (FormStructure* form : forms)
- buffer << *form;
+ LOG_AF(buffer) << *form;
- log_manager->Log() << LoggingScope::kParsing << LogMessage::kParsedForms
- << std::move(buffer);
+ LOG_AF(log_manager) << LoggingScope::kParsing << LogMessage::kParsedForms
+ << std::move(buffer);
}
// static
@@ -127,20 +160,69 @@ AutofillManager::AutofillManager(AutofillDriver* driver,
}
AutofillManager::~AutofillManager() {
+ NotifyObservers(&Observer::OnAutofillManagerDestroyed);
translate_observation_.Reset();
}
void AutofillManager::OnLanguageDetermined(
const translate::LanguageDetectionDetails& details) {
- if (!base::FeatureList::IsEnabled(features::kAutofillPageLanguageDetection)) {
+ if (!base::FeatureList::IsEnabled(features::kAutofillPageLanguageDetection))
+ return;
+ if (details.adopted_language == translate::kUnknownLanguageCode ||
+ !driver_->IsInActiveFrame()) {
return;
}
- for (auto& [form_id, form_structure] : form_structures_) {
- form_structure->set_current_page_language(
- LanguageCode(details.adopted_language));
- form_structure->DetermineHeuristicTypes(form_interactions_ukm_logger(),
- log_manager_);
+
+ NotifyObservers(&Observer::OnBeforeLanguageDetermined);
+ LanguageCode lang(details.adopted_language);
+ for (auto& [form_id, form_structure] : form_structures_)
+ form_structure->set_current_page_language(lang);
+
+ if (!base::FeatureList::IsEnabled(features::kAutofillParseAsync)) {
+ for (auto& [form_id, form_structure] : form_structures_) {
+ form_structure->DetermineHeuristicTypes(form_interactions_ukm_logger(),
+ log_manager_);
+ }
+ NotifyObservers(&Observer::OnAfterLanguageDetermined);
+ return;
}
+
+ // To be run on a different task (must not access global or member
+ // variables).
+ // TODO(crbug.com/1309848): We can't pass a UKM logger and a LogManager
+ // because they're member variables. To be fixed.
+ auto RunHeuristics = [](std::map<FormGlobalId, std::unique_ptr<FormStructure>>
+ form_structures) {
+ SCOPED_UMA_HISTOGRAM_TIMER(
+ "Autofill.Timing.OnLanguageDetermined.RunHeuristics");
+ for (auto& [id, form_structure] : form_structures) {
+ form_structure->DetermineHeuristicTypes(
+ /*form_interactions_ukm_logger=*/nullptr,
+ /*log_manager=*/nullptr);
+ }
+ return form_structures;
+ };
+
+ // To be run on the main thread (accesses member variables).
+ auto UpdateCache = [](base::WeakPtr<AutofillManager> self,
+ std::map<FormGlobalId, std::unique_ptr<FormStructure>>
+ form_structures) {
+ SCOPED_UMA_HISTOGRAM_TIMER(
+ "Autofill.Timing.OnLanguageDetermined.UpdateCache");
+ if (!self)
+ return;
+ for (auto& [id, form_structure] : form_structures)
+ self->form_structures_[id] = std::move(form_structure);
+ self->NotifyObservers(&Observer::OnAfterLanguageDetermined);
+ };
+
+ // Transfers the cached `form_structures_` to the worker task, which will
+ // eventually move them back into `form_structures_`. This means
+ // AutofillManager knows no forms for a brief period of time.
+ parsing_task_runner_->PostTaskAndReplyWithResult(
+ FROM_HERE, base::BindOnce(RunHeuristics, std::move(form_structures_)),
+ base::BindOnce(UpdateCache, parsing_weak_ptr_factory_.GetWeakPtr()));
+ form_structures_.clear();
}
void AutofillManager::OnTranslateDriverDestroyed(
@@ -156,14 +238,58 @@ LanguageCode AutofillManager::GetCurrentPageLanguage() {
return LanguageCode(language_state->current_language());
}
+void AutofillManager::FillCreditCardForm(int query_id,
+ const FormData& form,
+ const FormFieldData& field,
+ const CreditCard& credit_card,
+ const std::u16string& cvc) {
+ if (!base::FeatureList::IsEnabled(features::kAutofillParseAsync)) {
+ FillCreditCardFormImpl(form, field, credit_card, cvc, query_id);
+ return;
+ }
+ ParseFormAsync(form, ParsingCallback(&AutofillManager::FillCreditCardFormImpl,
+ /*after_event=*/nullptr, field,
+ credit_card, cvc, query_id));
+}
+
+void AutofillManager::FillProfileForm(const AutofillProfile& profile,
+ const FormData& form,
+ const FormFieldData& field) {
+ if (!base::FeatureList::IsEnabled(features::kAutofillParseAsync)) {
+ FillProfileFormImpl(form, field, profile);
+ return;
+ }
+ ParseFormAsync(form,
+ ParsingCallback(&AutofillManager::FillProfileFormImpl,
+ /*after_event=*/nullptr, field, profile));
+}
+
+void AutofillManager::OnDidFillAutofillFormData(
+ const FormData& form,
+ const base::TimeTicks timestamp) {
+ if (!IsValidFormData(form))
+ return;
+
+ NotifyObservers(&Observer::OnBeforeDidFillAutofillFormData);
+ if (!base::FeatureList::IsEnabled(features::kAutofillParseAsync)) {
+ OnDidFillAutofillFormDataImpl(form, timestamp);
+ NotifyObservers(&Observer::OnAfterDidFillAutofillFormData);
+ return;
+ }
+ ParseFormAsync(
+ form,
+ ParsingCallback(&AutofillManager::OnDidFillAutofillFormDataImpl,
+ &Observer::OnAfterDidFillAutofillFormData, timestamp));
+}
+
void AutofillManager::OnFormSubmitted(const FormData& form,
- bool known_success,
- mojom::SubmissionSource source) {
- if (IsValidFormData(form))
- OnFormSubmittedImpl(form, known_success, source);
+ const bool known_success,
+ const mojom::SubmissionSource source) {
+ if (!IsValidFormData(form))
+ return;
- for (Observer& observer : observers_)
- observer.OnFormSubmitted();
+ NotifyObservers(&Observer::OnFormSubmitted);
+ OnFormSubmittedImpl(form, known_success, source);
}
void AutofillManager::OnFormsSeen(
@@ -183,41 +309,52 @@ void AutofillManager::OnFormsSeen(
if (!ShouldParseForms(updated_forms))
return;
- std::vector<const FormData*> new_forms;
- for (const FormData& form : updated_forms) {
- const auto parse_form_start_time = AutofillTickClock::NowTicks();
- FormStructure* cached_form_structure =
- FindCachedFormByRendererId(form.global_id());
-
- // Not updating signatures of credit card forms is legacy behaviour. We
- // believe that the signatures are kept stable for voting purposes.
- bool update_form_signature = false;
- if (cached_form_structure) {
- const DenseSet<FormType>& form_types =
- cached_form_structure->GetFormTypes();
- update_form_signature =
- form_types.size() > form_types.count(FormType::kCreditCardForm);
+ NotifyObservers(&Observer::OnBeforeFormsSeen);
+ if (!base::FeatureList::IsEnabled(features::kAutofillParseAsync)) {
+ std::vector<FormData> parsed_forms;
+ for (const FormData& form : updated_forms) {
+ const auto parse_form_start_time = AutofillTickClock::NowTicks();
+ FormStructure* cached_form_structure =
+ FindCachedFormByRendererId(form.global_id());
+
+ // Not updating signatures of credit card forms is legacy behaviour. We
+ // believe that the signatures are kept stable for voting purposes.
+ bool update_form_signature = false;
+ if (cached_form_structure) {
+ const DenseSet<FormType>& form_types =
+ cached_form_structure->GetFormTypes();
+ update_form_signature =
+ form_types.size() > form_types.count(FormType::kCreditCardForm);
+ }
+
+ FormStructure* form_structure = ParseForm(form, cached_form_structure);
+ if (!form_structure)
+ continue;
+ DCHECK(form_structure);
+
+ if (update_form_signature)
+ form_structure->set_form_signature(CalculateFormSignature(form));
+
+ parsed_forms.push_back(form);
+ AutofillMetrics::LogParseFormTiming(AutofillTickClock::NowTicks() -
+ parse_form_start_time);
}
-
- FormStructure* form_structure = ParseForm(form, cached_form_structure);
- if (!form_structure)
- continue;
- DCHECK(form_structure);
-
- if (update_form_signature)
- form_structure->set_form_signature(CalculateFormSignature(form));
-
- new_forms.push_back(&form);
- AutofillMetrics::LogParseFormTiming(AutofillTickClock::NowTicks() -
- parse_form_start_time);
- }
-
- if (new_forms.empty())
+ if (!parsed_forms.empty())
+ OnFormsParsed(parsed_forms);
+ NotifyObservers(&Observer::OnAfterFormsSeen);
return;
- OnFormsParsed(new_forms);
+ }
+ DCHECK(base::FeatureList::IsEnabled(features::kAutofillParseAsync));
+ auto ProcessParsedForms = [](AutofillManager& self,
+ const std::vector<FormData>& parsed_forms) {
+ if (!parsed_forms.empty())
+ self.OnFormsParsed(parsed_forms);
+ self.NotifyObservers(&Observer::OnAfterFormsSeen);
+ };
+ ParseFormsAsync(updated_forms, base::BindOnce(ProcessParsedForms));
}
-void AutofillManager::OnFormsParsed(const std::vector<const FormData*>& forms) {
+void AutofillManager::OnFormsParsed(const std::vector<FormData>& forms) {
DCHECK(!forms.empty());
OnBeforeProcessParsedForms();
@@ -226,9 +363,9 @@ void AutofillManager::OnFormsParsed(const std::vector<const FormData*>& forms) {
std::vector<FormStructure*> non_queryable_forms;
std::vector<FormStructure*> queryable_forms;
DenseSet<FormType> form_types;
- for (const FormData* form : forms) {
+ for (const FormData& form : forms) {
FormStructure* form_structure =
- FindCachedFormByRendererId(form->global_id());
+ FindCachedFormByRendererId(form.global_id());
if (!form_structure) {
NOTREACHED();
continue;
@@ -238,12 +375,13 @@ void AutofillManager::OnFormsParsed(const std::vector<const FormData*>& forms) {
// Configure the query encoding for this form and add it to the appropriate
// collection of forms: queryable vs non-queryable.
- if (form_structure->ShouldBeQueried())
+ if (form_structure->ShouldBeQueried()) {
queryable_forms.push_back(form_structure);
- else
+ } else {
non_queryable_forms.push_back(form_structure);
+ }
- OnFormProcessed(*form, *form_structure);
+ OnFormProcessed(form, *form_structure);
}
if (!queryable_forms.empty() || !non_queryable_forms.empty()) {
@@ -274,15 +412,21 @@ void AutofillManager::OnFormsParsed(const std::vector<const FormData*>& forms) {
void AutofillManager::OnTextFieldDidChange(const FormData& form,
const FormFieldData& field,
const gfx::RectF& bounding_box,
- const TimeTicks timestamp) {
+ const base::TimeTicks timestamp) {
if (!IsValidFormData(form) || !IsValidFormFieldData(field))
return;
- OnTextFieldDidChangeImpl(form, field, bounding_box, timestamp);
-
- for (Observer& observer : observers_) {
- observer.OnTextFieldDidChange();
+ NotifyObservers(&Observer::OnBeforeTextFieldDidChange);
+ NotifyObservers(&Observer::OnTextFieldDidChange);
+ if (!base::FeatureList::IsEnabled(features::kAutofillParseAsync)) {
+ OnTextFieldDidChangeImpl(form, field, bounding_box, timestamp);
+ NotifyObservers(&Observer::OnAfterTextFieldDidChange);
+ return;
}
+ ParseFormAsync(form,
+ ParsingCallback(&AutofillManager::OnTextFieldDidChangeImpl,
+ &Observer::OnAfterTextFieldDidChange, field,
+ bounding_box, timestamp));
}
void AutofillManager::OnTextFieldDidScroll(const FormData& form,
@@ -291,10 +435,14 @@ void AutofillManager::OnTextFieldDidScroll(const FormData& form,
if (!IsValidFormData(form) || !IsValidFormFieldData(field))
return;
- OnTextFieldDidScrollImpl(form, field, bounding_box);
-
- for (Observer& observer : observers_)
- observer.OnTextFieldDidScroll();
+ NotifyObservers(&Observer::OnTextFieldDidScroll);
+ if (!base::FeatureList::IsEnabled(features::kAutofillParseAsync)) {
+ OnTextFieldDidScrollImpl(form, field, bounding_box);
+ return;
+ }
+ ParseFormAsync(form,
+ ParsingCallback(&AutofillManager::OnTextFieldDidScrollImpl,
+ /*after_event=*/nullptr, field, bounding_box));
}
void AutofillManager::OnSelectControlDidChange(const FormData& form,
@@ -303,24 +451,39 @@ void AutofillManager::OnSelectControlDidChange(const FormData& form,
if (!IsValidFormData(form) || !IsValidFormFieldData(field))
return;
- OnSelectControlDidChangeImpl(form, field, bounding_box);
-
- for (Observer& observer : observers_)
- observer.OnSelectControlDidChange();
+ NotifyObservers(&Observer::OnSelectControlDidChange);
+ if (!base::FeatureList::IsEnabled(features::kAutofillParseAsync)) {
+ OnSelectControlDidChangeImpl(form, field, bounding_box);
+ return;
+ }
+ ParseFormAsync(form,
+ ParsingCallback(&AutofillManager::OnSelectControlDidChangeImpl,
+ /*after_event=*/nullptr, field, bounding_box));
}
void AutofillManager::OnAskForValuesToFill(
- int query_id,
const FormData& form,
const FormFieldData& field,
const gfx::RectF& bounding_box,
+ int query_id,
bool autoselect_first_suggestion,
TouchToFillEligible touch_to_fill_eligible) {
if (!IsValidFormData(form) || !IsValidFormFieldData(field))
return;
- OnAskForValuesToFillImpl(query_id, form, field, bounding_box,
- autoselect_first_suggestion, touch_to_fill_eligible);
+ NotifyObservers(&Observer::OnBeforeAskForValuesToFill);
+ if (!base::FeatureList::IsEnabled(features::kAutofillParseAsync)) {
+ OnAskForValuesToFillImpl(form, field, bounding_box, query_id,
+ autoselect_first_suggestion,
+ touch_to_fill_eligible);
+ NotifyObservers(&Observer::OnAfterAskForValuesToFill);
+ return;
+ }
+ ParseFormAsync(
+ form, ParsingCallback(&AutofillManager::OnAskForValuesToFillImpl,
+ &Observer::OnAfterAskForValuesToFill, field,
+ bounding_box, query_id, autoselect_first_suggestion,
+ touch_to_fill_eligible));
}
void AutofillManager::OnFocusOnFormField(const FormData& form,
@@ -329,7 +492,61 @@ void AutofillManager::OnFocusOnFormField(const FormData& form,
if (!IsValidFormData(form) || !IsValidFormFieldData(field))
return;
- OnFocusOnFormFieldImpl(form, field, bounding_box);
+ if (!base::FeatureList::IsEnabled(features::kAutofillParseAsync)) {
+ OnFocusOnFormFieldImpl(form, field, bounding_box);
+ return;
+ }
+ ParseFormAsync(form,
+ ParsingCallback(&AutofillManager::OnFocusOnFormFieldImpl,
+ /*after_event=*/nullptr, field, bounding_box));
+}
+
+void AutofillManager::OnFocusNoLongerOnForm(bool had_interacted_form) {
+ OnFocusNoLongerOnFormImpl(had_interacted_form);
+}
+
+void AutofillManager::OnDidPreviewAutofillFormData() {
+ OnDidPreviewAutofillFormDataImpl();
+}
+
+void AutofillManager::OnDidEndTextFieldEditing() {
+ OnDidEndTextFieldEditingImpl();
+}
+
+void AutofillManager::OnHidePopup() {
+ OnHidePopupImpl();
+}
+
+void AutofillManager::OnSelectFieldOptionsDidChange(const FormData& form) {
+ if (!IsValidFormData(form))
+ return;
+
+ if (!base::FeatureList::IsEnabled(features::kAutofillParseAsync)) {
+ OnSelectFieldOptionsDidChangeImpl(form);
+ return;
+ }
+ ParseFormAsync(
+ form, ParsingCallback(&AutofillManager::OnSelectFieldOptionsDidChangeImpl,
+ /*after_event=*/nullptr));
+}
+
+void AutofillManager::OnJavaScriptChangedAutofilledValue(
+ const FormData& form,
+ const FormFieldData& field,
+ const std::u16string& old_value) {
+ if (!IsValidFormData(form))
+ return;
+
+ NotifyObservers(&Observer::OnBeforeAskForValuesToFill);
+ if (!base::FeatureList::IsEnabled(features::kAutofillParseAsync)) {
+ OnJavaScriptChangedAutofilledValueImpl(form, field, old_value);
+ NotifyObservers(&Observer::OnAfterAskForValuesToFill);
+ return;
+ }
+ ParseFormAsync(
+ form,
+ ParsingCallback(&AutofillManager::OnJavaScriptChangedAutofilledValueImpl,
+ &Observer::OnAfterAskForValuesToFill, field, old_value));
}
// Returns true if |live_form| does not match |cached_form|.
@@ -340,7 +557,8 @@ bool AutofillManager::GetCachedFormAndField(const FormData& form,
// Maybe find an existing FormStructure that corresponds to |form|.
FormStructure* cached_form = FindCachedFormByRendererId(form.global_id());
if (cached_form) {
- if (!CachedFormNeedsUpdate(form, *cached_form)) {
+ if (base::FeatureList::IsEnabled(features::kAutofillParseAsync) ||
+ !CachedFormNeedsUpdate(form, *cached_form)) {
// There is no data to return if there are no auto-fillable fields.
if (!cached_form->autofill_count())
return false;
@@ -352,6 +570,9 @@ bool AutofillManager::GetCachedFormAndField(const FormData& form,
}
}
+ if (base::FeatureList::IsEnabled(features::kAutofillParseAsync))
+ return false;
+
// The form is new or updated, parse it and discard |cached_form|.
// i.e., |cached_form| is no longer valid after this call.
*form_structure = ParseForm(form, cached_form);
@@ -402,13 +623,197 @@ FormStructure* AutofillManager::FindCachedFormByRendererId(
return it != form_structures_.end() ? it->second.get() : nullptr;
}
+void AutofillManager::ParseFormsAsync(
+ const std::vector<FormData>& forms,
+ base::OnceCallback<void(AutofillManager&, const std::vector<FormData>&)>
+ callback) {
+ SCOPED_UMA_HISTOGRAM_TIMER("Autofill.Timing.ParseFormsAsync");
+ DCHECK(base::FeatureList::IsEnabled(features::kAutofillParseAsync));
+
+ // `num_managed_forms` is the number of forms that will be managed by this
+ // AutofillManager after ParseFormsAsync() and its asynchronous callees have
+ // finished.
+ size_t num_managed_forms = form_structures_.size();
+
+ // To be run on the main thread (accesses member variables).
+ std::vector<FormData> parsed_forms;
+ std::vector<std::unique_ptr<FormStructure>> form_structures;
+ for (const FormData& form_data : forms) {
+ bool is_new_form = !base::Contains(form_structures_, form_data.global_id());
+ if (num_managed_forms + is_new_form > kAutofillManagerMaxFormCacheSize) {
+ LOG_AF(log_manager_) << LoggingScope::kAbortParsing
+ << LogMessage::kAbortParsingTooManyForms
+ << form_data;
+ continue;
+ }
+
+ auto form_structure = std::make_unique<FormStructure>(form_data);
+ form_structure->ParseFieldTypesFromAutocompleteAttributes();
+ if (!form_structure->ShouldBeParsed(log_manager_))
+ continue;
+
+ num_managed_forms += is_new_form;
+ DCHECK_LE(num_managed_forms, kAutofillManagerMaxFormCacheSize);
+
+ if (FormStructure* cached_form_structure =
+ FindCachedFormByRendererId(form_data.global_id())) {
+ // We need to keep the server data if available. We need to use them while
+ // determining the heuristics.
+ form_structure->RetrieveFromCache(
+ *cached_form_structure,
+ /*should_keep_cached_value=*/true,
+ /*only_server_and_autofill_state=*/true);
+ if (form_structure->value_from_dynamic_change_form())
+ value_from_dynamic_change_form_ = true;
+
+ // Not updating signatures of credit card forms is legacy behaviour. We
+ // believe that the signatures are kept stable for voting purposes.
+ DenseSet<FormType> form_types = cached_form_structure->GetFormTypes();
+ if (form_types.size() > form_types.count(FormType::kCreditCardForm))
+ form_structure->set_form_signature(CalculateFormSignature(form_data));
+ }
+
+ form_structure->set_current_page_language(GetCurrentPageLanguage());
+ form_structures.push_back(std::move(form_structure));
+ parsed_forms.push_back(form_data);
+ }
+
+ // Remove duplicates by their FormGlobalId. Otherwise, after moving the forms
+ // into `form_structures_`, duplicates may be destroyed and we'd end up with
+ // dangling pointers.
+ base::ranges::sort(form_structures, {}, &FormStructure::global_id);
+ form_structures.erase(
+ base::ranges::unique(form_structures, {}, &FormStructure::global_id),
+ form_structures.end());
+
+ // To be run on a different task (must not access global or member
+ // variables).
+ // TODO(crbug.com/1309848): We can't pass a UKM logger and a LogManager
+ // because they're member variables. To be fixed.
+ auto RunHeuristics =
+ [](std::vector<std::unique_ptr<FormStructure>> form_structures) {
+ SCOPED_UMA_HISTOGRAM_TIMER(
+ "Autofill.Timing.ParseFormsAsync.RunHeuristics");
+ for (auto& form_structure : form_structures) {
+ form_structure->DetermineHeuristicTypes(
+ /*form_interactions_ukm_logger=*/nullptr,
+ /*log_manager=*/nullptr);
+ }
+ return form_structures;
+ };
+
+ // To be run on the main thread (accesses member variables).
+ auto UpdateCache =
+ [](base::WeakPtr<AutofillManager> self,
+ base::OnceCallback<void(AutofillManager&,
+ const std::vector<FormData>&)> callback,
+ const std::vector<FormData>& parsed_forms,
+ std::vector<std::unique_ptr<FormStructure>> form_structures) {
+ SCOPED_UMA_HISTOGRAM_TIMER(
+ "Autofill.Timing.ParseFormsAsync.UpdateCache");
+ if (!self)
+ return;
+ for (auto& form_structure : form_structures) {
+ FormGlobalId id = form_structure->global_id();
+ self->form_structures_[id] = std::move(form_structure);
+ }
+ self->NotifyObservers(&Observer::OnFormParsed);
+ std::move(callback).Run(*self, parsed_forms);
+ };
+
+ parsing_task_runner_->PostTaskAndReplyWithResult(
+ FROM_HERE, base::BindOnce(RunHeuristics, std::move(form_structures)),
+ base::BindOnce(UpdateCache, parsing_weak_ptr_factory_.GetWeakPtr(),
+ std::move(callback), parsed_forms));
+}
+
+void AutofillManager::ParseFormAsync(
+ const FormData& form_data,
+ base::OnceCallback<void(AutofillManager&, const FormData&)> callback) {
+ SCOPED_UMA_HISTOGRAM_TIMER("Autofill.Timing.ParseFormAsync");
+ DCHECK(base::FeatureList::IsEnabled(features::kAutofillParseAsync));
+
+ bool is_new_form = !base::Contains(form_structures_, form_data.global_id());
+ if (form_structures_.size() + is_new_form >
+ kAutofillManagerMaxFormCacheSize) {
+ LOG_AF(log_manager_) << LoggingScope::kAbortParsing
+ << LogMessage::kAbortParsingTooManyForms << form_data;
+ return;
+ }
+
+ auto form_structure = std::make_unique<FormStructure>(form_data);
+ form_structure->ParseFieldTypesFromAutocompleteAttributes();
+ if (!form_structure->ShouldBeParsed(log_manager_)) {
+ // For Autocomplete, events need to be handled even for forms that cannot be
+ // parsed.
+ std::move(callback).Run(*this, form_data);
+ return;
+ }
+
+ if (FormStructure* cached_form_structure =
+ FindCachedFormByRendererId(form_data.global_id())) {
+ if (!CachedFormNeedsUpdate(form_data, *cached_form_structure)) {
+ std::move(callback).Run(*this, form_data);
+ return;
+ }
+
+ // We need to keep the server data if available. We need to use them while
+ // determining the heuristics.
+ form_structure->RetrieveFromCache(*cached_form_structure,
+ /*should_keep_cached_value=*/true,
+ /*only_server_and_autofill_state=*/true);
+ if (form_structure->value_from_dynamic_change_form())
+ value_from_dynamic_change_form_ = true;
+ }
+ form_structure->set_current_page_language(GetCurrentPageLanguage());
+
+ // To be run on a different task (must not access global or member
+ // variables).
+ // TODO(crbug.com/1309848): We can't pass a UKM logger and a LogManager
+ // because they're member variables. To be fixed.
+ auto RunHeuristics = [](std::unique_ptr<FormStructure> form_structure) {
+ SCOPED_UMA_HISTOGRAM_TIMER("Autofill.Timing.ParseFormAsync.RunHeuristics");
+ form_structure->DetermineHeuristicTypes(
+ /*form_interactions_ukm_logger=*/nullptr,
+ /*log_manager=*/nullptr);
+ return form_structure;
+ };
+
+ // To be run on the main thread (accesses member variables).
+ // The reason this takes both `form_data` and `form_structure` is that they
+ // may disagree on the form's values: if the form is seen for the second time,
+ // RetrieveFromCache() resets the `form_structure`'s fields.
+ // TODO(crbug/1345089): Make FormStructure's and FormData's fields correspond,
+ // migrate all event handlers in BrowserAutofillManager take a FormStructure,
+ // and drop the FormData from UpdateCache().
+ auto UpdateCache =
+ [](base::WeakPtr<AutofillManager> self,
+ base::OnceCallback<void(AutofillManager&, const FormData&)> callback,
+ const FormData& form_data,
+ std::unique_ptr<FormStructure> form_structure) {
+ SCOPED_UMA_HISTOGRAM_TIMER(
+ "Autofill.Timing.ParseFormAsync.UpdateCache");
+ if (!self)
+ return;
+ FormGlobalId id = form_structure->global_id();
+ self->form_structures_[id] = std::move(form_structure);
+ self->NotifyObservers(&Observer::OnFormParsed);
+ std::move(callback).Run(*self, form_data);
+ };
+
+ parsing_task_runner_->PostTaskAndReplyWithResult(
+ FROM_HERE, base::BindOnce(RunHeuristics, std::move(form_structure)),
+ base::BindOnce(UpdateCache, parsing_weak_ptr_factory_.GetWeakPtr(),
+ std::move(callback), form_data));
+}
+
FormStructure* AutofillManager::ParseForm(const FormData& form,
const FormStructure* cached_form) {
+ DCHECK(!base::FeatureList::IsEnabled(features::kAutofillParseAsync));
+
if (form_structures_.size() >= kAutofillManagerMaxFormCacheSize) {
- if (log_manager_) {
- log_manager_->Log() << LoggingScope::kAbortParsing
- << LogMessage::kAbortParsingTooManyForms << form;
- }
+ LOG_AF(log_manager_) << LoggingScope::kAbortParsing
+ << LogMessage::kAbortParsingTooManyForms << form;
return nullptr;
}
@@ -424,9 +829,7 @@ FormStructure* AutofillManager::ParseForm(const FormData& form,
/*should_keep_cached_value=*/true,
/*only_server_and_autofill_state=*/true);
- for (Observer& observer : observers_)
- observer.OnFormParsed();
-
+ NotifyObservers(&Observer::OnFormParsed);
if (form_structure.get()->value_from_dynamic_change_form())
value_from_dynamic_change_form_ = true;
}
@@ -452,6 +855,8 @@ FormStructure* AutofillManager::ParseForm(const FormData& form,
}
void AutofillManager::Reset() {
+ parsing_weak_ptr_factory_.InvalidateWeakPtrs();
+ NotifyObservers(&Observer::OnAutofillManagerReset);
form_structures_.clear();
form_interactions_ukm_logger_ = CreateFormInteractionsUkmLogger();
}
diff --git a/chromium/components/autofill/core/browser/autofill_manager.h b/chromium/components/autofill/core/browser/autofill_manager.h
index 9997b3401c0..2354a2fa121 100644
--- a/chromium/components/autofill/core/browser/autofill_manager.h
+++ b/chromium/components/autofill/core/browser/autofill_manager.h
@@ -10,10 +10,12 @@
#include <string>
#include <vector>
-#include "base/cancelable_callback.h"
+#include "base/bind.h"
#include "base/memory/raw_ptr.h"
+#include "base/memory/weak_ptr.h"
#include "base/observer_list.h"
#include "base/scoped_observation.h"
+#include "base/task/thread_pool.h"
#include "base/time/time.h"
#include "base/types/strong_alias.h"
#include "build/build_config.h"
@@ -26,6 +28,7 @@
#include "components/autofill/core/common/mojom/autofill_types.mojom.h"
#include "components/autofill/core/common/signatures.h"
#include "components/autofill/core/common/unique_ids.h"
+#include "components/autofill_assistant/core/public/autofill_assistant_intent.h"
#include "components/translate/core/browser/translate_driver.h"
#include "components/version_info/channel.h"
@@ -55,23 +58,46 @@ class AutofillManager
: public AutofillDownloadManager::Observer,
public translate::TranslateDriver::LanguageDetectionObserver {
public:
- // An observer class used by browsertests that gets notified whenever
- // particular actions occur.
+ // Observer of AutofillManager events.
+ //
+ // OnAfterFoo() is called, perhaps asynchronously (but on the UI thread),
+ // after OnBeforeFoo(). The only exceptions where OnBeforeFoo() may be called
+ // without a corresponding OnAfterFoo() call are:
+ // - if the number of cached forms exceeds `kAutofillManagerMaxFormCacheSize`;
+ // - if this AutofillManager has been destroyed or reset in the meantime.
+ //
+ // The main purpose are unit tests. New pairs of events may be added as
+ // needed.
class Observer : public base::CheckedObserver {
public:
- virtual void OnFormParsed(){};
+ virtual void OnAutofillManagerDestroyed() {}
+ virtual void OnAutofillManagerReset() {}
- // See |AutofillManager::OnTextFieldDidChange|.
- virtual void OnTextFieldDidChange(){};
+ virtual void OnBeforeLanguageDetermined() {}
+ virtual void OnAfterLanguageDetermined() {}
- // See |AutofillManager::OnTextFieldDidScroll|.
- virtual void OnTextFieldDidScroll(){};
+ virtual void OnBeforeFormsSeen() {}
+ virtual void OnAfterFormsSeen() {}
- // See |AutofillManager::OnSelectControlDidChange|.
- virtual void OnSelectControlDidChange(){};
+ virtual void OnBeforeTextFieldDidChange() {}
+ virtual void OnAfterTextFieldDidChange() {}
- // See |AutofillManager::OnFormSubmitted|.
- virtual void OnFormSubmitted(){};
+ virtual void OnBeforeDidFillAutofillFormData() {}
+ virtual void OnAfterDidFillAutofillFormData() {}
+
+ virtual void OnBeforeAskForValuesToFill() {}
+ virtual void OnAfterAskForValuesToFill() {}
+
+ virtual void OnBeforeJavaScriptChangedAutofilledValue() {}
+ virtual void OnAfterJavaScriptChangedAutofilledValue() {}
+
+ // TODO(crbug.com/1330105): Clean up API: delete the events that don't
+ // follow the OnBeforeFoo() / OnAfterFoo() pattern.
+ virtual void OnFormParsed() {}
+ virtual void OnTextFieldDidChange() {}
+ virtual void OnTextFieldDidScroll() {}
+ virtual void OnSelectControlDidChange() {}
+ virtual void OnFormSubmitted() {}
};
using EnableDownloadManager =
@@ -104,21 +130,27 @@ class AutofillManager
return client_;
}
+ // Returns a WeakPtr to the leaf class.
+ virtual base::WeakPtr<AutofillManager> GetWeakPtr() = 0;
+
// May return nullptr.
virtual AutofillOfferManager* GetOfferManager() = 0;
// May return nullptr.
virtual CreditCardAccessManager* GetCreditCardAccessManager() = 0;
+ // Events triggered by the renderer.
+
// Returns true only if the previewed form should be cleared.
virtual bool ShouldClearPreviewedForm() = 0;
// Invoked when the value of textfield is changed.
// |bounding_box| are viewport coordinates.
- void OnTextFieldDidChange(const FormData& form,
- const FormFieldData& field,
- const gfx::RectF& bounding_box,
- const base::TimeTicks timestamp);
+ // Virtual for testing.
+ virtual void OnTextFieldDidChange(const FormData& form,
+ const FormFieldData& field,
+ const gfx::RectF& bounding_box,
+ const base::TimeTicks timestamp);
// Invoked when the textfield is scrolled.
// |bounding_box| are viewport coordinates.
@@ -138,12 +170,13 @@ class AutofillManager
// |touch_to_fill_eligible| indicates if the Touch To Fill surface could be
// used for showing suggestion. Note that it doesn't guarantee the given form
// input field is eligible for autofilling.
- void OnAskForValuesToFill(int query_id,
- const FormData& form,
- const FormFieldData& field,
- const gfx::RectF& bounding_box,
- bool autoselect_first_suggestion,
- TouchToFillEligible touch_to_fill_eligible);
+ // Virtual for testing.
+ virtual void OnAskForValuesToFill(const FormData& form,
+ const FormFieldData& field,
+ const gfx::RectF& bounding_box,
+ int query_id,
+ bool autoselect_first_suggestion,
+ TouchToFillEligible touch_to_fill_eligible);
// Invoked when |form|'s |field| has focus.
// |bounding_box| are viewport coordinates.
@@ -154,56 +187,72 @@ class AutofillManager
// Invoked when |form| has been submitted.
// Processes the submitted |form|, saving any new Autofill data to the user's
// personal profile.
- void OnFormSubmitted(const FormData& form,
- bool known_success,
- mojom::SubmissionSource source);
-
- virtual void FillCreditCardForm(int query_id,
- const FormData& form,
- const FormFieldData& field,
- const CreditCard& credit_card,
- const std::u16string& cvc) = 0;
- virtual void FillProfileForm(const AutofillProfile& profile,
- const FormData& form,
- const FormFieldData& field) = 0;
+ // Virtual for testing.
+ virtual void OnFormSubmitted(const FormData& form,
+ bool known_success,
+ mojom::SubmissionSource source);
+
+ void FillCreditCardForm(int query_id,
+ const FormData& form,
+ const FormFieldData& field,
+ const CreditCard& credit_card,
+ const std::u16string& cvc);
+
+ void FillProfileForm(const AutofillProfile& profile,
+ const FormData& form,
+ const FormFieldData& field);
+
+ // Invoked when |form| has been filled with the value given by
+ // FillOrPreviewForm.
+ // Virtual for testing.
+ virtual void OnDidFillAutofillFormData(const FormData& form,
+ const base::TimeTicks timestamp);
+
+ // Profile Autofill was triggered by assistant's |intent|. This only affects
+ // metrics logging.
+ virtual void SetProfileFillViaAutofillAssistantIntent(
+ const autofill_assistant::AutofillAssistantIntent intent) = 0;
+
+ // Credit Card Autofill was triggered by assistant's |intent|. This only
+ // affects metrics logging.
+ virtual void SetCreditCardFillViaAutofillAssistantIntent(
+ const autofill_assistant::AutofillAssistantIntent intent) = 0;
// Invoked when changes of the forms have been detected: the forms in
// |updated_forms| are either new or have changed, and the forms in
// |removed_forms| have been removed from the DOM (but may be re-added to the
// DOM later).
+ // Virtual for testing.
virtual void OnFormsSeen(const std::vector<FormData>& updated_forms,
const std::vector<FormGlobalId>& removed_forms);
// Invoked when focus is no longer on form. |had_interacted_form| indicates
// whether focus was previously on a form with which the user had interacted.
- virtual void OnFocusNoLongerOnForm(bool had_interacted_form) = 0;
-
- // Invoked when |form| has been filled with the value given by
- // FillOrPreviewForm.
- virtual void OnDidFillAutofillFormData(const FormData& form,
- const base::TimeTicks timestamp) = 0;
+ void OnFocusNoLongerOnForm(bool had_interacted_form);
// Invoked when preview autofill value has been shown.
- virtual void OnDidPreviewAutofillFormData() = 0;
+ void OnDidPreviewAutofillFormData();
// Invoked when textfeild editing ended
- virtual void OnDidEndTextFieldEditing() = 0;
+ void OnDidEndTextFieldEditing();
// Invoked when popup window should be hidden.
- virtual void OnHidePopup() = 0;
+ void OnHidePopup();
// Invoked when the options of a select element in the |form| changed.
- virtual void SelectFieldOptionsDidChange(const FormData& form) = 0;
+ void OnSelectFieldOptionsDidChange(const FormData& form);
// Invoked after JavaScript set the value of |field| in |form|. Only called
// if |field| was in autofilled state. Note that from a renderer's
// perspective, modifying the value with JavaScript leads to a state where
// the field is not considered autofilled anymore. So this notification won't
// be sent again until the field gets autofilled again.
- virtual void JavaScriptChangedAutofilledValue(
+ virtual void OnJavaScriptChangedAutofilledValue(
const FormData& form,
const FormFieldData& field,
- const std::u16string& old_value) = 0;
+ const std::u16string& old_value);
+
+ // Other events.
// Invoked when the field type predictions are downloaded from the autofill
// server.
@@ -220,8 +269,8 @@ class AutofillManager
translate::TranslateDriver* translate_driver) override;
// Invoked when the language has been detected by the Translate component.
// As this usually happens after Autofill has parsed the forms for the first
- // time, the heuristics need to be re-run by this function in order to run
- // use language-specific patterns.
+ // time, the heuristics need to be re-run by this function in order to use
+ // language-specific patterns.
void OnLanguageDetermined(
const translate::LanguageDetectionDetails& details) override;
@@ -247,6 +296,11 @@ class AutofillManager
observers_.RemoveObserver(observer);
}
+ void NotifyObservers(void (Observer::*event)()) {
+ for (Observer& observer : observers_)
+ base::invoke(event, observer);
+ }
+
// Returns the present form structures seen by Autofill handler.
const std::map<FormGlobalId, std::unique_ptr<FormStructure>>&
form_structures() const {
@@ -328,10 +382,10 @@ class AutofillManager
const gfx::RectF& bounding_box) = 0;
virtual void OnAskForValuesToFillImpl(
- int query_id,
const FormData& form,
const FormFieldData& field,
const gfx::RectF& bounding_box,
+ int query_id,
bool autoselect_first_suggestion,
TouchToFillEligible touch_to_fill_eligible) = 0;
@@ -343,16 +397,46 @@ class AutofillManager
const FormFieldData& field,
const gfx::RectF& bounding_box) = 0;
+ virtual void OnDidFillAutofillFormDataImpl(
+ const FormData& form,
+ const base::TimeTicks timestamp) = 0;
+
+ virtual void FillCreditCardFormImpl(const FormData& form,
+ const FormFieldData& field,
+ const CreditCard& credit_card,
+ const std::u16string& cvc,
+ int query_id) = 0;
+ virtual void FillProfileFormImpl(const FormData& form,
+ const FormFieldData& field,
+ const AutofillProfile& profile) = 0;
+
+ virtual void OnFocusNoLongerOnFormImpl(bool had_interacted_form) = 0;
+
+ virtual void OnDidPreviewAutofillFormDataImpl() = 0;
+
+ virtual void OnDidEndTextFieldEditingImpl() = 0;
+
+ virtual void OnHidePopupImpl() = 0;
+
+ virtual void OnSelectFieldOptionsDidChangeImpl(const FormData& form) = 0;
+
+ virtual void OnJavaScriptChangedAutofilledValueImpl(
+ const FormData& form,
+ const FormFieldData& field,
+ const std::u16string& old_value) = 0;
+
// Return whether the |forms| from OnFormSeen() should be parsed to
// form_structures.
virtual bool ShouldParseForms(const std::vector<FormData>& forms) = 0;
// Invoked before parsing the forms.
+ // TODO(crbug.com/1309848): Rename to some consistent scheme, e.g.,
+ // OnBeforeParsedForm().
virtual void OnBeforeProcessParsedForms() = 0;
// Invoked when the given |form| has been processed to the given
// |form_structure|.
- virtual void OnFormProcessed(const FormData& form,
+ virtual void OnFormProcessed(const FormData& form_data,
const FormStructure& form_structure) = 0;
// Invoked after all forms have been processed, |form_types| is a set of
// FormType found.
@@ -365,6 +449,40 @@ class AutofillManager
FormSignature form_signature,
std::vector<FormStructure*>* form_structures) const;
+ // Parses multiple forms in one go. The function proceeds in three stages:
+ //
+ // 1. Turn (almost) every FormData into a FormStructure.
+ // 2. Run DetermineHeuristicTypes() on all FormStructures.
+ // 3. Update the cache member variable `form_structures_` and call `callback`.
+ //
+ // Step 1 runs synchronously on the main thread.
+ // Step 2 runs asynchronously on a worker task.
+ // Step 3 runs again on the main thread.
+ //
+ // There are two conditions under which a FormData is skipped in Step 1:
+ // - if the overall number exceeds `kAutofillManagerMaxFormCacheSize`;
+ // - if the form should not be parsed according to ShouldParseForms().
+ //
+ // TODO(crbug.com/1309848): Add unit tests.
+ // TODO(crbug.com/1345089): Eliminate either the ParseFormsAsync() or
+ // ParseFormAsync(). There are a few possible directions:
+ // - Let ParseFormAync() wrap the FormData in a vector, call
+ // ParseFormsAsync(), and then unwrap the vector again.
+ // - Let OnFormsSeen() take a single FormData. That simplifies also
+ // ContentAutofillDriver and ContentAutofillRouter a bit, but then the
+ // AutofillDownloadManager needs to collect forms to send a batch query.
+ // - Let all other events take a FormGlobalId instead of a FormData and fire
+ // OnFormsSeen() before these events if necessary.
+ void ParseFormsAsync(
+ const std::vector<FormData>& forms,
+ base::OnceCallback<void(AutofillManager&, const std::vector<FormData>&)>
+ callback);
+
+ // Parses a single form analogously to ParseFormsAsync().
+ void ParseFormAsync(
+ const FormData& form,
+ base::OnceCallback<void(AutofillManager&, const FormData&)> callback);
+
// Parses the |form| with the server data retrieved from the |cached_form|
// (if any). Returns nullptr if the form should not be parsed. Otherwise, adds
// the returned form structure to the |form_structures_|.
@@ -397,7 +515,7 @@ class AutofillManager
// Invoked when forms from OnFormsSeen() have been parsed to
// |form_structures|.
- void OnFormsParsed(const std::vector<const FormData*>& forms);
+ void OnFormsParsed(const std::vector<FormData>& forms);
std::unique_ptr<AutofillMetrics::FormInteractionsUkmLogger>
CreateFormInteractionsUkmLogger();
@@ -434,6 +552,15 @@ class AutofillManager
// Observers that listen to updates of this instance.
base::ObserverList<Observer> observers_;
+
+ // DetermineHeuristicTypes() should only be run on the `parsing_task_runner_`.
+ // The reply will be called on the main thread and should be a no-op if this
+ // AutofillManager has been destroyed or reset; to detect this, the reply
+ // should take a WeakPtr from `parsing_weak_ptr_factory_`.
+ scoped_refptr<base::SequencedTaskRunner> parsing_task_runner_ =
+ base::ThreadPool::CreateSequencedTaskRunner(
+ {base::TaskPriority::USER_VISIBLE});
+ base::WeakPtrFactory<AutofillManager> parsing_weak_ptr_factory_{this};
};
} // namespace autofill
diff --git a/chromium/components/autofill/core/browser/autofill_manager_unittest.cc b/chromium/components/autofill/core/browser/autofill_manager_unittest.cc
index dd63441f56a..21c00f619c4 100644
--- a/chromium/components/autofill/core/browser/autofill_manager_unittest.cc
+++ b/chromium/components/autofill/core/browser/autofill_manager_unittest.cc
@@ -16,6 +16,7 @@
#include "components/autofill/core/browser/autofill_test_utils.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_autofill_manager_waiter.h"
#include "components/autofill/core/common/autofill_constants.h"
#include "components/autofill/core/common/autofill_features.h"
#include "components/autofill/core/common/autofill_tick_clock.h"
@@ -55,6 +56,11 @@ class MockAutofillManager : public AutofillManager {
client,
client->GetChannel(),
EnableDownloadManager(false)) {}
+
+ base::WeakPtr<AutofillManager> GetWeakPtr() override {
+ return weak_ptr_factory_.GetWeakPtr();
+ }
+
MOCK_METHOD(bool, ShouldClearPreviewedForm, (), (override));
MOCK_METHOD(AutofillOfferManager*, GetOfferManager, (), (override));
MOCK_METHOD(CreditCardAccessManager*,
@@ -62,36 +68,44 @@ class MockAutofillManager : public AutofillManager {
(),
(override));
MOCK_METHOD(void,
- FillCreditCardForm,
- (int query_id,
- const FormData& form,
+ FillCreditCardFormImpl,
+ (const FormData& form,
const FormFieldData& field,
const CreditCard& credit_card,
- const std::u16string& cvc),
+ const std::u16string& cvc,
+ int query_id),
+ (override));
+ MOCK_METHOD(void,
+ FillProfileFormImpl,
+ (const FormData& form,
+ const FormFieldData& field,
+ const AutofillProfile& profile),
+ (override));
+ MOCK_METHOD(void,
+ SetProfileFillViaAutofillAssistantIntent,
+ (const autofill_assistant::AutofillAssistantIntent intent),
(override));
MOCK_METHOD(void,
- FillProfileForm,
- (const autofill::AutofillProfile& profile,
- const FormData& form,
- const FormFieldData& field),
+ SetCreditCardFillViaAutofillAssistantIntent,
+ (const autofill_assistant::AutofillAssistantIntent intent),
(override));
MOCK_METHOD(void,
- OnFocusNoLongerOnForm,
+ OnFocusNoLongerOnFormImpl,
(bool had_interacted_form),
(override));
MOCK_METHOD(void,
- OnDidFillAutofillFormData,
+ OnDidFillAutofillFormDataImpl,
(const FormData& form, const base::TimeTicks timestamp),
(override));
- MOCK_METHOD(void, OnDidPreviewAutofillFormData, (), (override));
- MOCK_METHOD(void, OnDidEndTextFieldEditing, (), (override));
- MOCK_METHOD(void, OnHidePopup, (), (override));
+ MOCK_METHOD(void, OnDidPreviewAutofillFormDataImpl, (), (override));
+ MOCK_METHOD(void, OnDidEndTextFieldEditingImpl, (), (override));
+ MOCK_METHOD(void, OnHidePopupImpl, (), (override));
MOCK_METHOD(void,
- SelectFieldOptionsDidChange,
+ OnSelectFieldOptionsDidChangeImpl,
(const FormData& form),
(override));
MOCK_METHOD(void,
- JavaScriptChangedAutofilledValue,
+ OnJavaScriptChangedAutofilledValueImpl,
(const FormData& form,
const FormFieldData& field,
const std::u16string& old_value),
@@ -121,10 +135,10 @@ class MockAutofillManager : public AutofillManager {
(override));
MOCK_METHOD(void,
OnAskForValuesToFillImpl,
- (int query_id,
- const FormData& form,
+ (const FormData& form,
const FormFieldData& field,
const gfx::RectF& bounding_box,
+ int query_id,
bool autoselect_first_suggestion,
TouchToFillEligible touch_to_fill_eligible),
(override));
@@ -147,7 +161,7 @@ class MockAutofillManager : public AutofillManager {
MOCK_METHOD(void, OnBeforeProcessParsedForms, (), (override));
MOCK_METHOD(void,
OnFormProcessed,
- (const FormData& form, const FormStructure& form_structure),
+ (const FormData& form_data, const FormStructure& form_structure),
(override));
MOCK_METHOD(void,
OnAfterProcessParsedForms,
@@ -157,6 +171,9 @@ class MockAutofillManager : public AutofillManager {
ReportAutofillWebOTPMetrics,
(bool used_web_otp),
(override));
+
+ private:
+ base::WeakPtrFactory<MockAutofillManager> weak_ptr_factory_{this};
};
class MockAutofillObserver : public AutofillManager::Observer {
@@ -225,7 +242,10 @@ void OnFormsSeenWithExpectations(MockAutofillManager& manager,
EXPECT_CALL(manager, OnBeforeProcessParsedForms()).Times(num > 0);
EXPECT_CALL(manager, OnFormProcessed(_, _)).Times(num);
EXPECT_CALL(manager, OnAfterProcessParsedForms(_)).Times(num > 0);
+ TestAutofillManagerWaiter waiter(
+ manager, {&AutofillManager::Observer::OnAfterFormsSeen});
manager.OnFormsSeen(updated_forms, removed_forms);
+ ASSERT_TRUE(waiter.Wait());
EXPECT_THAT(manager.form_structures(), HaveSameFormIdsAs(expectation));
}
diff --git a/chromium/components/autofill/core/browser/autofill_profile_sync_util.cc b/chromium/components/autofill/core/browser/autofill_profile_sync_util.cc
index dedac9690a7..c76723c09cf 100644
--- a/chromium/components/autofill/core/browser/autofill_profile_sync_util.cc
+++ b/chromium/components/autofill/core/browser/autofill_profile_sync_util.cc
@@ -237,13 +237,9 @@ std::unique_ptr<EntityData> CreateEntityDataFromAutofillProfile(
entry.GetVerificationStatus(ADDRESS_HOME_HOUSE_NUMBER)));
// Set birthdate-related values.
- if (base::FeatureList::IsEnabled(
- features::kAutofillEnableCompatibilitySupportForBirthdates)) {
- specifics->set_birthdate_day(entry.GetRawInfoAsInt(BIRTHDATE_DAY));
- specifics->set_birthdate_month(entry.GetRawInfoAsInt(BIRTHDATE_MONTH));
- specifics->set_birthdate_year(
- entry.GetRawInfoAsInt(BIRTHDATE_YEAR_4_DIGITS));
- }
+ specifics->set_birthdate_day(entry.GetRawInfoAsInt(BIRTHDATE_DAY));
+ specifics->set_birthdate_month(entry.GetRawInfoAsInt(BIRTHDATE_MONTH));
+ specifics->set_birthdate_year(entry.GetRawInfoAsInt(BIRTHDATE_4_DIGIT_YEAR));
return entity_data;
}
@@ -468,13 +464,9 @@ std::unique_ptr<AutofillProfile> CreateAutofillProfileFromSpecifics(
specifics.address_home_subpremise_name_status()));
// Set birthdate-related fields.
- if (base::FeatureList::IsEnabled(
- features::kAutofillEnableCompatibilitySupportForBirthdates)) {
- profile->SetRawInfoAsInt(BIRTHDATE_DAY, specifics.birthdate_day());
- profile->SetRawInfoAsInt(BIRTHDATE_MONTH, specifics.birthdate_month());
- profile->SetRawInfoAsInt(BIRTHDATE_YEAR_4_DIGITS,
- specifics.birthdate_year());
- }
+ profile->SetRawInfoAsInt(BIRTHDATE_DAY, specifics.birthdate_day());
+ profile->SetRawInfoAsInt(BIRTHDATE_MONTH, specifics.birthdate_month());
+ profile->SetRawInfoAsInt(BIRTHDATE_4_DIGIT_YEAR, specifics.birthdate_year());
// The profile may be in a legacy state. By calling |FinalizeAfterImport()|
// * The profile is migrated if the name structure is in legacy state.
diff --git a/chromium/components/autofill/core/browser/autofill_profile_sync_util_unittest.cc b/chromium/components/autofill/core/browser/autofill_profile_sync_util_unittest.cc
index c9f74d78433..ee4962d3067 100644
--- a/chromium/components/autofill/core/browser/autofill_profile_sync_util_unittest.cc
+++ b/chromium/components/autofill/core/browser/autofill_profile_sync_util_unittest.cc
@@ -126,7 +126,7 @@ AutofillProfile ConstructCompleteProfile() {
// Set testing values for the birthdate.
profile.SetRawInfoAsInt(BIRTHDATE_DAY, 14);
profile.SetRawInfoAsInt(BIRTHDATE_MONTH, 3);
- profile.SetRawInfoAsInt(BIRTHDATE_YEAR_4_DIGITS, 1997);
+ profile.SetRawInfoAsInt(BIRTHDATE_4_DIGIT_YEAR, 1997);
return profile;
}
@@ -292,8 +292,7 @@ TEST_F(AutofillProfileSyncUtilTest, CreateEntityDataFromAutofillProfile) {
structured_names_feature.InitWithFeatures(
{features::kAutofillEnableSupportForMoreStructureInAddresses,
features::kAutofillEnableSupportForMoreStructureInNames,
- features::kAutofillEnableSupportForHonorificPrefixes,
- features::kAutofillEnableCompatibilitySupportForBirthdates},
+ features::kAutofillEnableSupportForHonorificPrefixes},
{});
AutofillProfile profile = ConstructCompleteProfile();
diff --git a/chromium/components/autofill/core/browser/autofill_progress_dialog_type.h b/chromium/components/autofill/core/browser/autofill_progress_dialog_type.h
new file mode 100644
index 00000000000..4b622ac66fd
--- /dev/null
+++ b/chromium/components/autofill/core/browser/autofill_progress_dialog_type.h
@@ -0,0 +1,23 @@
+// Copyright 2022 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_AUTOFILL_PROGRESS_DIALOG_TYPE_H_
+#define COMPONENTS_AUTOFILL_CORE_BROWSER_AUTOFILL_PROGRESS_DIALOG_TYPE_H_
+
+namespace autofill {
+
+// The type of autofill progress dialog to show.
+enum class AutofillProgressDialogType {
+ // Unspecified progress dialog type.
+ kUnspecified = 0,
+ // Used when authenticating with FIDO.
+ // This progress dialog type applies to Android only.
+ kAndroidFIDOProgressDialog = 1,
+ // Used when unmasking virtual cards.
+ kVirtualCardUnmaskProgressDialog = 2
+};
+
+} // namespace autofill
+
+#endif // COMPONENTS_AUTOFILL_CORE_BROWSER_AUTOFILL_PROGRESS_DIALOG_TYPE_H_
diff --git a/chromium/components/autofill/core/browser/autofill_regex_constants.h b/chromium/components/autofill/core/browser/autofill_regex_constants.h
deleted file mode 100644
index 639a7680f39..00000000000
--- a/chromium/components/autofill/core/browser/autofill_regex_constants.h
+++ /dev/null
@@ -1,107 +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_AUTOFILL_REGEX_CONSTANTS_H_
-#define COMPONENTS_AUTOFILL_CORE_BROWSER_AUTOFILL_REGEX_CONSTANTS_H_
-
-namespace autofill {
-
-extern const char16_t kAttentionIgnoredRe[];
-extern const char16_t kRegionIgnoredRe[];
-extern const char16_t kAddressNameIgnoredRe[];
-extern const char16_t kCompanyRe[];
-extern const char16_t kHouseNumberRe[];
-extern const char16_t kApartmentNumberRe[];
-extern const char16_t kStreetNameRe[];
-extern const char16_t kAddressLine1Re[];
-extern const char16_t kAddressLine1LabelRe[];
-extern const char16_t kAddressLine2Re[];
-extern const char16_t kAddressLine2LabelRe[];
-extern const char16_t kAddressLinesExtraRe[];
-extern const char16_t kAddressLookupRe[];
-extern const char16_t kCountryRe[];
-extern const char16_t kDependentLocality[];
-extern const char16_t kCountryLocationRe[];
-extern const char16_t kZipCodeRe[];
-extern const char16_t kZip4Re[];
-extern const char16_t kDependentLocalityRe[];
-extern const char16_t kCityRe[];
-extern const char16_t kStateRe[];
-extern const char16_t kNameOnCardRe[];
-extern const char16_t kNameOnCardContextualRe[];
-extern const char16_t kCardNumberRe[];
-extern const char16_t kCardCvcRe[];
-extern const char16_t kCardTypeRe[];
-extern const char16_t kExpirationMonthRe[];
-extern const char16_t kExpirationYearRe[];
-extern const char16_t kExpirationDate2DigitYearRe[];
-extern const char16_t kExpirationDate4DigitYearRe[];
-extern const char16_t kExpirationDateRe[];
-extern const char16_t kCardIgnoredRe[];
-extern const char16_t kGiftCardRe[];
-extern const char16_t kDebitGiftCardRe[];
-extern const char16_t kDebitCardRe[];
-extern const char16_t kDayRe[];
-extern const char16_t kEmailRe[];
-extern const char16_t kNameIgnoredRe[];
-extern const char16_t kFullNameRe[];
-extern const char16_t kNameGenericRe[];
-extern const char16_t kFirstNameRe[];
-extern const char16_t kMiddleInitialRe[];
-extern const char16_t kMiddleNameRe[];
-extern const char16_t kLastNameRe[];
-extern const char16_t kHonorificPrefixRe[];
-extern const char16_t kNameLastFirstRe[];
-extern const char16_t kNameLastSecondRe[];
-extern const char16_t kPhoneRe[];
-extern const char16_t kAugmentedPhoneCountryCodeRe[];
-extern const char16_t kCountryCodeRe[];
-extern const char16_t kAreaCodeNotextRe[];
-extern const char16_t kAreaCodeRe[];
-extern const char16_t kFaxRe[];
-extern const char16_t kPhonePrefixSeparatorRe[];
-extern const char16_t kPhoneSuffixSeparatorRe[];
-extern const char16_t kPhonePrefixRe[];
-extern const char16_t kPhoneSuffixRe[];
-extern const char16_t kPhoneExtensionRe[];
-extern const char16_t kSearchTermRe[];
-extern const char16_t kPassportRe[];
-extern const char16_t kTravelOriginRe[];
-extern const char16_t kTravelDestinationRe[];
-extern const char16_t kFlightRe[];
-extern const char16_t kPriceRe[];
-extern const char16_t kCreditCardCVCPattern[];
-extern const char16_t kCreditCard4DigitExpYearPattern[];
-extern const char16_t kSocialSecurityRe[];
-extern const char16_t kOneTimePwdRe[];
-extern const char16_t kHiddenValueRe[];
-extern const char16_t kMerchantPromoCodeRe[];
-extern const char16_t kEmailValueRe[];
-extern const char16_t kPhoneValueRe[];
-extern const char16_t kUsernameLikeValueRe[];
-
-// Used to match field data that might be a UPI Virtual Payment Address.
-// See:
-// - http://crbug.com/702220
-// - https://upipayments.co.in/virtual-payment-address-vpa/
-extern const char16_t kUPIVirtualPaymentAddressRe[];
-
-// Used to match field data that might be an International Bank Account Number.
-// TODO(crbug.com/977377): The regex doesn't match IBANs for Saint Lucia (LC),
-// Kazakhstan (KZ) and Romania (RO). Consider replace the regex with something
-// like "(?:IT|SM)\d{2}[A-Z]\d{22}|CY\d{2}[A-Z]\d{23}...". For reference:
-// - https://www.swift.com/resource/iban-registry-pdf
-extern const char16_t kInternationalBankAccountNumberRe[];
-
-// Match the path values for form actions that look like generic search:
-// e.g. /search
-// /search/
-// /search/products...
-// /products/search/
-// /blah/search_all.jsp
-extern const char16_t kUrlSearchActionRe[];
-
-} // namespace autofill
-
-#endif // COMPONENTS_AUTOFILL_CORE_BROWSER_AUTOFILL_REGEX_CONSTANTS_H_
diff --git a/chromium/components/autofill/core/browser/autofill_regexes.cc b/chromium/components/autofill/core/browser/autofill_regexes.cc
deleted file mode 100644
index f5aa6a9b59b..00000000000
--- a/chromium/components/autofill/core/browser/autofill_regexes.cc
+++ /dev/null
@@ -1,102 +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/autofill_regexes.h"
-
-#include <map>
-#include <memory>
-#include <string>
-#include <utility>
-
-#include "base/check.h"
-#include "base/i18n/unicodestring.h"
-#include "base/no_destructor.h"
-#include "base/synchronization/lock.h"
-#include "third_party/icu/source/i18n/unicode/regex.h"
-
-namespace {
-
-// Maximum length of the string to match to avoid causing an icu::RegexMatcher
-// stack overflow. (crbug.com/1198219)
-constexpr int kMaxStringLength = 5000;
-
-// A thread-local class that serves as a cache of compiled regex patterns.
-//
-// The regexp state can be accessed from multiple threads in single process
-// mode, and this class offers per-thread instance instead of per-process
-// singleton instance (https://crbug.com/812182).
-class AutofillRegexes {
- public:
- AutofillRegexes() = default;
-
- AutofillRegexes(const AutofillRegexes&) = delete;
- AutofillRegexes& operator=(const AutofillRegexes&) = delete;
-
- // Returns the compiled regex matcher corresponding to |pattern|.
- icu::RegexMatcher* GetMatcher(const base::StringPiece16& pattern);
-
- private:
- ~AutofillRegexes() = default;
-
- // Maps patterns to their corresponding regex matchers.
- std::map<std::u16string, std::unique_ptr<icu::RegexMatcher>, std::less<>>
- matchers_;
-};
-
-icu::RegexMatcher* AutofillRegexes::GetMatcher(
- const base::StringPiece16& pattern) {
- auto it = matchers_.find(pattern);
- if (it == matchers_.end()) {
- const icu::UnicodeString icu_pattern(false, pattern.data(),
- pattern.length());
-
- UErrorCode status = U_ZERO_ERROR;
- auto matcher = std::make_unique<icu::RegexMatcher>(
- icu_pattern, UREGEX_CASE_INSENSITIVE, status);
- DCHECK(U_SUCCESS(status));
-
- auto result = matchers_.insert(std::make_pair(pattern, std::move(matcher)));
- DCHECK(result.second);
- it = result.first;
- }
- return it->second.get();
-}
-
-} // namespace
-
-namespace autofill {
-
-bool MatchesPattern(const base::StringPiece16& input,
- const base::StringPiece16& pattern,
- std::vector<std::u16string>* groups) {
- if (input.size() > kMaxStringLength)
- return false;
-
- static base::NoDestructor<AutofillRegexes> g_autofill_regexes;
- static base::NoDestructor<base::Lock> g_lock;
- base::AutoLock lock(*g_lock);
-
- icu::RegexMatcher* matcher = g_autofill_regexes->GetMatcher(pattern);
- icu::UnicodeString icu_input(false, input.data(), input.length());
- matcher->reset(icu_input);
-
- UErrorCode status = U_ZERO_ERROR;
- UBool matched = matcher->find(0, status);
- DCHECK(U_SUCCESS(status));
-
- if (matched && groups) {
- int32_t matched_groups = matcher->groupCount();
- groups->resize(matched_groups + 1);
-
- for (int32_t i = 0; i < matched_groups + 1; ++i) {
- icu::UnicodeString match_unicode = matcher->group(i, status);
- DCHECK(U_SUCCESS(status));
- (*groups)[i] = base::i18n::UnicodeStringToString16(match_unicode);
- }
- }
-
- return matched;
-}
-
-} // namespace autofill
diff --git a/chromium/components/autofill/core/browser/autofill_regexes.h b/chromium/components/autofill/core/browser/autofill_regexes.h
deleted file mode 100644
index 75d72047e8f..00000000000
--- a/chromium/components/autofill/core/browser/autofill_regexes.h
+++ /dev/null
@@ -1,26 +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_AUTOFILL_REGEXES_H_
-#define COMPONENTS_AUTOFILL_CORE_BROWSER_AUTOFILL_REGEXES_H_
-
-#include <string>
-#include <vector>
-
-#include "base/strings/string_piece.h"
-
-// Parsing utilities.
-namespace autofill {
-
-// Case-insensitive regular expression matching.
-// Returns true if |pattern| is found in |input|.
-// If |groups| is non-null, it gets resized and the found capture groups
-// are written into it.
-bool MatchesPattern(const base::StringPiece16& input,
- const base::StringPiece16& pattern,
- std::vector<std::u16string>* groups = nullptr);
-
-} // namespace autofill
-
-#endif // COMPONENTS_AUTOFILL_CORE_BROWSER_AUTOFILL_REGEXES_H_
diff --git a/chromium/components/autofill/core/browser/autofill_suggestion_generator.cc b/chromium/components/autofill/core/browser/autofill_suggestion_generator.cc
index 0dbe739c53f..20c60866af0 100644
--- a/chromium/components/autofill/core/browser/autofill_suggestion_generator.cc
+++ b/chromium/components/autofill/core/browser/autofill_suggestion_generator.cc
@@ -14,6 +14,7 @@
#include "components/autofill/core/browser/autofill_field.h"
#include "components/autofill/core/browser/data_model/autofill_offer_data.h"
#include "components/autofill/core/browser/data_model/credit_card.h"
+#include "components/autofill/core/browser/data_model/iban.h"
#include "components/autofill/core/browser/field_filler.h"
#include "components/autofill/core/browser/form_structure.h"
#include "components/autofill/core/browser/metrics/autofill_metrics.h"
@@ -180,6 +181,21 @@ AutofillSuggestionGenerator::GetSuggestionsForCreditCards(
}
// static
+std::vector<Suggestion> AutofillSuggestionGenerator::GetSuggestionsForIBANs(
+ const std::vector<IBAN*>& ibans) {
+ std::vector<Suggestion> suggestions;
+ for (const IBAN* iban : ibans) {
+ Suggestion& suggestion = suggestions.emplace_back(iban->value());
+ suggestion.frontend_id = POPUP_ITEM_ID_IBAN_ENTRY;
+ suggestion.payload = iban->guid();
+ suggestion.main_text.value = iban->GetIdentifierStringForAutofillDisplay();
+ if (!iban->nickname().empty())
+ suggestion.label = iban->nickname();
+ }
+ return suggestions;
+}
+
+// static
std::vector<Suggestion>
AutofillSuggestionGenerator::GetPromoCodeSuggestionsFromPromoCodeOffers(
const std::vector<const AutofillOfferData*>& promo_code_offers) {
@@ -209,6 +225,13 @@ AutofillSuggestionGenerator::GetPromoCodeSuggestionsFromPromoCodeOffers(
// one suggestion with a valid offer details url before adding the footer.
DCHECK(suggestions.size() > 0);
if (!footer_offer_details_url.is_empty()) {
+ // Add the footer separator since we will now have a footer in the offers
+ // suggestions popup.
+ suggestions.emplace_back();
+ suggestions.back().frontend_id = POPUP_ITEM_ID_SEPARATOR;
+
+ // Add the footer suggestion that navigates the user to the promo code
+ // details page in the offers suggestions popup.
suggestions.emplace_back(l10n_util::GetStringUTF16(
IDS_AUTOFILL_PROMO_CODE_SUGGESTIONS_FOOTER_TEXT));
Suggestion& suggestion = suggestions.back();
@@ -315,25 +338,10 @@ Suggestion AutofillSuggestionGenerator::CreateCreditCardSuggestion(
suggestion.main_text = Suggestion::Text(credit_card.GetInfo(type, app_locale),
Suggestion::Text::IsPrimary(true));
suggestion.icon = credit_card.CardIconStringForAutofillSuggestion();
- std::string backend_id = credit_card.guid();
+ suggestion.payload = credit_card.guid();
suggestion.match = prefix_matched_suggestion ? Suggestion::PREFIX_MATCH
: Suggestion::SUBSTRING_MATCH;
- GURL card_art_url_for_virtual_card_option;
- if (virtual_card_option &&
- credit_card.record_type() == CreditCard::MASKED_SERVER_CARD) {
- card_art_url_for_virtual_card_option = credit_card.card_art_url();
- } else if (virtual_card_option &&
- credit_card.record_type() == CreditCard::LOCAL_CARD) {
- const CreditCard* server_duplicate_card =
- GetServerCardForLocalCard(&credit_card);
- DCHECK(server_duplicate_card);
- card_art_url_for_virtual_card_option =
- server_duplicate_card->card_art_url();
- backend_id = server_duplicate_card->guid();
- }
- suggestion.payload = backend_id;
-
// Get the nickname for the card suggestion, which may not be the same as
// the card's nickname if there are duplicates of the card on file.
std::u16string suggestion_nickname =
@@ -345,8 +353,8 @@ Suggestion AutofillSuggestionGenerator::CreateCreditCardSuggestion(
base::FeatureList::IsEnabled(features::kAutofillKeyboardAccessory) ? 2
: 4;
// If the value is the card number, the label is the expiration date.
- // Otherwise the label is the card number, or if that is empty the
- // cardholder name. The label should never repeat the value.
+ // Otherwise the label is the card number, or if that is empty the cardholder
+ // name. The label should never repeat the value.
if (type.GetStorableType() == CREDIT_CARD_NUMBER) {
suggestion.main_text =
Suggestion::Text(credit_card.CardIdentifierStringForAutofillDisplay(
@@ -391,40 +399,59 @@ Suggestion AutofillSuggestionGenerator::CreateCreditCardSuggestion(
#endif
}
+ // For virtual cards, use issuer's card art icon instead of network icon.
if (virtual_card_option) {
-#if BUILDFLAG(IS_ANDROID)
- suggestion.custom_icon_url = credit_card.card_art_url();
-#endif // BUILDFLAG(IS_ANDROID)
+ GURL card_art_url_for_virtual_card_option;
+ if (credit_card.record_type() == CreditCard::MASKED_SERVER_CARD) {
+ card_art_url_for_virtual_card_option = credit_card.card_art_url();
+ } else if (credit_card.record_type() == CreditCard::LOCAL_CARD) {
+ const CreditCard* server_duplicate_card =
+ GetServerCardForLocalCard(&credit_card);
+ DCHECK(server_duplicate_card);
+ card_art_url_for_virtual_card_option =
+ server_duplicate_card->card_art_url();
+ suggestion.payload = server_duplicate_card->guid();
+ }
suggestion.frontend_id = POPUP_ITEM_ID_VIRTUAL_CREDIT_CARD_ENTRY;
- suggestion.minor_text.value = suggestion.main_text.value;
- suggestion.main_text.value = l10n_util::GetStringUTF16(
- IDS_AUTOFILL_VIRTUAL_CARD_SUGGESTION_OPTION_VALUE);
-
suggestion.feature_for_iph =
feature_engagement::kIPHAutofillVirtualCardSuggestionFeature.name;
+ // TODO(crbug.com/1344629): Update "Virtual card" label for other fields.
+ // For virtual cards, prefix "Virtual card" label to field suggestions. For
+ // card number field in a dropdown, show the "Virtual card" label below the
+ // card number for Metadata experiment.
+ if (!base::FeatureList::IsEnabled(
+ features::kAutofillEnableVirtualCardMetadata) ||
+ type.GetStorableType() != CREDIT_CARD_NUMBER ||
+ base::FeatureList::IsEnabled(features::kAutofillKeyboardAccessory)) {
+ suggestion.minor_text.value = suggestion.main_text.value;
+ suggestion.main_text.value = l10n_util::GetStringUTF16(
+ IDS_AUTOFILL_VIRTUAL_CARD_SUGGESTION_OPTION_VALUE);
+ } else {
+ suggestion.label = l10n_util::GetStringUTF16(
+ IDS_AUTOFILL_VIRTUAL_CARD_SUGGESTION_OPTION_VALUE);
+ }
+
+#if BUILDFLAG(IS_ANDROID)
+ suggestion.custom_icon_url = card_art_url_for_virtual_card_option;
+#else
gfx::Image* image = personal_data_->GetCreditCardArtImageForUrl(
card_art_url_for_virtual_card_option);
if (image)
suggestion.custom_icon = *image;
+#endif // BUILDFLAG(IS_ANDROID)
}
-
+#if BUILDFLAG(IS_ANDROID)
+ // The card art icon should always be shown at the start of the suggestion.
+ suggestion.is_icon_at_start = true;
+#endif // BUILDFLAG(IS_ANDROID)
return suggestion;
}
bool AutofillSuggestionGenerator::ShouldShowVirtualCardOption(
const CreditCard* candidate_card,
const FormStructure& form_structure) const {
- // If the form is an incomplete form and the incomplete form experiment is
- // disabled, do not offer a virtual card option. We will likely not be able to
- // fill in all information, and the user doesn't have the info either.
- if (!IsCompleteCreditCardFormIncludingCvcField(form_structure) &&
- !base::FeatureList::IsEnabled(
- features::kAutofillSuggestVirtualCardsOnIncompleteForm)) {
- return false;
- }
-
switch (candidate_card->record_type()) {
case CreditCard::MASKED_SERVER_CARD:
return candidate_card->virtual_card_enrollment_state() ==
diff --git a/chromium/components/autofill/core/browser/autofill_suggestion_generator.h b/chromium/components/autofill/core/browser/autofill_suggestion_generator.h
index d2caa220b73..94a39c653b7 100644
--- a/chromium/components/autofill/core/browser/autofill_suggestion_generator.h
+++ b/chromium/components/autofill/core/browser/autofill_suggestion_generator.h
@@ -26,6 +26,7 @@ class AutofillType;
class CreditCard;
struct FormFieldData;
class FormStructure;
+class IBAN;
class PersonalDataManager;
struct Suggestion;
@@ -57,6 +58,10 @@ class AutofillSuggestionGenerator {
const std::string& app_locale,
bool* should_display_gpay_logo);
+ // Generates suggestions for all available IBANs.
+ static std::vector<Suggestion> GetSuggestionsForIBANs(
+ const std::vector<IBAN*>& ibans);
+
// Converts the vector of promo code offers that is passed in to a vector of
// suggestions that can be displayed to the user for a promo code field.
static std::vector<Suggestion> GetPromoCodeSuggestionsFromPromoCodeOffers(
@@ -89,6 +94,18 @@ class AutofillSuggestionGenerator {
CreateCreditCardSuggestion_LocalCard);
FRIEND_TEST_ALL_PREFIXES(AutofillSuggestionGeneratorTest,
CreateCreditCardSuggestion_ServerCard);
+ FRIEND_TEST_ALL_PREFIXES(
+ AutofillSuggestionGeneratorTest,
+ CreateCreditCardSuggestion_PopupWithMetadata_VirtualCardNameField);
+ FRIEND_TEST_ALL_PREFIXES(
+ AutofillSuggestionGeneratorTest,
+ CreateCreditCardSuggestion_PopupWithMetadata_VirtualCardNumberField);
+ FRIEND_TEST_ALL_PREFIXES(
+ AutofillSuggestionGeneratorTest,
+ CreateCreditCardSuggestion_PopupWithMetadata_NonVirtualCardNameField);
+ FRIEND_TEST_ALL_PREFIXES(
+ AutofillSuggestionGeneratorTest,
+ CreateCreditCardSuggestion_PopupWithMetadata_NonVirtualCardNumberField);
FRIEND_TEST_ALL_PREFIXES(AutofillSuggestionGeneratorTest,
GetServerCardForLocalCard);
FRIEND_TEST_ALL_PREFIXES(AutofillSuggestionGeneratorTest,
diff --git a/chromium/components/autofill/core/browser/autofill_suggestion_generator_unittest.cc b/chromium/components/autofill/core/browser/autofill_suggestion_generator_unittest.cc
index 222d4f876b6..dbc694e0c18 100644
--- a/chromium/components/autofill/core/browser/autofill_suggestion_generator_unittest.cc
+++ b/chromium/components/autofill/core/browser/autofill_suggestion_generator_unittest.cc
@@ -6,6 +6,7 @@
#include "base/guid.h"
#include "base/rand_util.h"
+#include "base/strings/strcat.h"
#include "base/test/metrics/histogram_tester.h"
#include "base/test/scoped_feature_list.h"
#include "base/test/task_environment.h"
@@ -13,8 +14,9 @@
#include "components/autofill/core/browser/autofill_suggestion_generator.h"
#include "components/autofill/core/browser/autofill_test_utils.h"
#include "components/autofill/core/browser/data_model/credit_card.h"
+#include "components/autofill/core/browser/data_model/iban.h"
+#include "components/autofill/core/browser/form_structure_test_api.h"
#include "components/autofill/core/browser/test_autofill_client.h"
-#include "components/autofill/core/browser/test_form_structure.h"
#include "components/autofill/core/browser/test_personal_data_manager.h"
#include "components/autofill/core/browser/webdata/autofill_webdata_service.h"
#include "components/autofill/core/common/autofill_clock.h"
@@ -55,6 +57,9 @@ class AutofillSuggestionGeneratorTest : public testing::Test {
TestPersonalDataManager* personal_data() { return &personal_data_; }
+ protected:
+ base::test::ScopedFeatureList scoped_feature_list_;
+
private:
base::test::TaskEnvironment task_environment_{
base::test::TaskEnvironment::TimeSource::SYSTEM_TIME};
@@ -62,7 +67,6 @@ class AutofillSuggestionGeneratorTest : public testing::Test {
TestAutofillClient autofill_client_;
scoped_refptr<AutofillWebDataService> database_;
TestPersonalDataManager personal_data_;
- base::test::ScopedFeatureList scoped_feature_list_;
};
TEST_F(AutofillSuggestionGeneratorTest,
@@ -341,11 +345,180 @@ TEST_F(AutofillSuggestionGeneratorTest, CreateCreditCardSuggestion_LocalCard) {
EXPECT_TRUE(real_card_suggestion.custom_icon.IsEmpty());
}
+// Credit card name field suggestion with metadata for virtual cards in Autofill
+// popup.
+TEST_F(AutofillSuggestionGeneratorTest,
+ CreateCreditCardSuggestion_PopupWithMetadata_VirtualCardNameField) {
+ scoped_feature_list_.InitAndEnableFeature(
+ features::kAutofillEnableVirtualCardMetadata);
+
+ // Create a server card.
+ CreditCard server_card = test::GetMaskedServerCard();
+ server_card.set_server_id("server_id1");
+ server_card.set_guid("00000000-0000-0000-0000-000000000001");
+ test::SetCreditCardInfo(&server_card, "Mojo Jojo", "4111111111111111", "04",
+ test::NextYear().c_str(), "1");
+ server_card.SetNetworkForMaskedCard(kVisaCard);
+
+ // Name field suggestion for virtual cards.
+ Suggestion virtual_card_name_field_suggestion =
+ suggestion_generator()->CreateCreditCardSuggestion(
+ server_card, AutofillType(CREDIT_CARD_NAME_FULL),
+ /*prefix_matched_suggestion=*/false, /*virtual_card_option=*/true,
+ "");
+
+ // "Virtual card" text is prefixed to the name.
+ EXPECT_EQ(virtual_card_name_field_suggestion.main_text.value,
+ u"Virtual card");
+ EXPECT_EQ(virtual_card_name_field_suggestion.minor_text.value, u"Mojo Jojo");
+
+#if BUILDFLAG(IS_ANDROID)
+ // For Android, the label is "Network ....1234".
+ EXPECT_EQ(virtual_card_name_field_suggestion.label,
+ base::StrCat({u"Visa ", internal::GetObfuscatedStringForCardDigits(
+ u"1111", 4)}));
+#elif BUILDFLAG(IS_IOS)
+ // For IOS, the label is "....1234".
+ EXPECT_EQ(virtual_card_name_field_suggestion.label,
+ internal::GetObfuscatedStringForCardDigits(u"1111", 4));
+#else
+ // For Desktop, the label is the descriptive expiration date formatted as
+ // "Network ....1234, expires on mm/yy".
+ EXPECT_EQ(
+ virtual_card_name_field_suggestion.label,
+ base::StrCat({u"Visa ",
+ internal::GetObfuscatedStringForCardDigits(u"1111", 4),
+ u", expires on 04/",
+ base::UTF8ToUTF16(test::NextYear().substr(2))}));
+#endif
+}
+
+// Credit card number field suggestion with metadata for virtual cards in
+// Autofill popup.
+TEST_F(AutofillSuggestionGeneratorTest,
+ CreateCreditCardSuggestion_PopupWithMetadata_VirtualCardNumberField) {
+ scoped_feature_list_.InitAndEnableFeature(
+ features::kAutofillEnableVirtualCardMetadata);
+
+ // Create a server card.
+ CreditCard server_card = test::GetMaskedServerCard();
+ server_card.set_server_id("server_id1");
+ server_card.set_guid("00000000-0000-0000-0000-000000000001");
+ test::SetCreditCardInfo(&server_card, "Mojo Jojo", "4111111111111111", "04",
+ test::NextYear().c_str(), "1");
+ server_card.SetNetworkForMaskedCard(kVisaCard);
+
+ // Card number field suggestion for virtual cards.
+ Suggestion virtual_card_number_field_suggestion =
+ suggestion_generator()->CreateCreditCardSuggestion(
+ server_card, AutofillType(CREDIT_CARD_NUMBER),
+ /*prefix_matched_suggestion=*/false, /*virtual_card_option=*/true,
+ "");
+
+ // Only card number is displayed on the first line.
+ EXPECT_EQ(virtual_card_number_field_suggestion.main_text.value,
+ base::StrCat({u"Visa ", internal::GetObfuscatedStringForCardDigits(
+ u"1111", 4)}));
+ EXPECT_EQ(virtual_card_number_field_suggestion.minor_text.value, u"");
+
+ // "Virtual card" is the label.
+ EXPECT_EQ(virtual_card_number_field_suggestion.label, u"Virtual card");
+}
+
+// Credit card name field suggestion with metadata for non-virtual cards in
+// Autofill popup.
+TEST_F(AutofillSuggestionGeneratorTest,
+ CreateCreditCardSuggestion_PopupWithMetadata_NonVirtualCardNameField) {
+ scoped_feature_list_.InitAndEnableFeature(
+ features::kAutofillEnableVirtualCardMetadata);
+
+ // Create a server card.
+ CreditCard server_card = test::GetMaskedServerCard();
+ server_card.set_server_id("server_id1");
+ server_card.set_guid("00000000-0000-0000-0000-000000000001");
+ test::SetCreditCardInfo(&server_card, "Mojo Jojo", "4111111111111111", "04",
+ test::NextYear().c_str(), "1");
+ server_card.SetNetworkForMaskedCard(kVisaCard);
+
+ // Name field suggestion for non-virtual cards.
+ Suggestion real_card_name_field_suggestion =
+ suggestion_generator()->CreateCreditCardSuggestion(
+ server_card, AutofillType(CREDIT_CARD_NAME_FULL),
+ /*prefix_matched_suggestion=*/false, /*virtual_card_option=*/false,
+ "");
+
+ // Only the name is displayed on the first line.
+ EXPECT_EQ(real_card_name_field_suggestion.main_text.value, u"Mojo Jojo");
+ EXPECT_EQ(real_card_name_field_suggestion.minor_text.value, u"");
+
+#if BUILDFLAG(IS_ANDROID)
+ // For Android, the label is "Network ....1234".
+ EXPECT_EQ(real_card_name_field_suggestion.label,
+ base::StrCat({u"Visa ", internal::GetObfuscatedStringForCardDigits(
+ u"1111", 4)}));
+#elif BUILDFLAG(IS_IOS)
+ // For IOS, the label is "....1234".
+ EXPECT_EQ(real_card_name_field_suggestion.label,
+ internal::GetObfuscatedStringForCardDigits(u"1111", 4));
+#else
+ // For Desktop, the label is the descriptive expiration date formatted as
+ // "Network ....1234, expires on mm/yy".
+ EXPECT_EQ(
+ real_card_name_field_suggestion.label,
+ base::StrCat({u"Visa ",
+ internal::GetObfuscatedStringForCardDigits(u"1111", 4),
+ u", expires on 04/",
+ base::UTF8ToUTF16(test::NextYear().substr(2))}));
+#endif
+}
+
+// Credit card number field suggestion with metadata for non-virtual cards in
+// Autofill popup.
+TEST_F(AutofillSuggestionGeneratorTest,
+ CreateCreditCardSuggestion_PopupWithMetadata_NonVirtualCardNumberField) {
+ scoped_feature_list_.InitAndEnableFeature(
+ features::kAutofillEnableVirtualCardMetadata);
+
+ // Create a server card.
+ CreditCard server_card = test::GetMaskedServerCard();
+ server_card.set_server_id("server_id1");
+ server_card.set_guid("00000000-0000-0000-0000-000000000001");
+ test::SetCreditCardInfo(&server_card, "Mojo Jojo", "4111111111111111", "04",
+ test::NextYear().c_str(), "1");
+ server_card.SetNetworkForMaskedCard(kVisaCard);
+
+ // Card number field suggestion for non-virtual cards.
+ Suggestion real_card_number_field_suggestion =
+ suggestion_generator()->CreateCreditCardSuggestion(
+ server_card, AutofillType(CREDIT_CARD_NUMBER),
+ /*prefix_matched_suggestion=*/false, /*virtual_card_option=*/false,
+ "");
+
+ // Only the card number is displayed on the first line.
+ EXPECT_EQ(real_card_number_field_suggestion.main_text.value,
+ base::StrCat({u"Visa ", internal::GetObfuscatedStringForCardDigits(
+ u"1111", 4)}));
+ EXPECT_EQ(real_card_number_field_suggestion.minor_text.value, u"");
+
+#if BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_IOS)
+ // For mobile devices, the label is the expiration date formatted as mm/yy.
+ EXPECT_EQ(
+ real_card_number_field_suggestion.label,
+ base::StrCat({u"04/", base::UTF8ToUTF16(test::NextYear().substr(2))}));
+#else
+ // For Desktop, the label is the descriptive expiration date formatted as
+ // "Expires on mm/yy".
+ EXPECT_EQ(real_card_number_field_suggestion.label,
+ base::StrCat({u"Expires on 04/",
+ base::UTF8ToUTF16(test::NextYear().substr(2))}));
+#endif
+}
+
TEST_F(AutofillSuggestionGeneratorTest, ShouldShowVirtualCardOption) {
// Create a complete form.
FormData credit_card_form;
test::CreateTestCreditCardFormData(&credit_card_form, true, false);
- TestFormStructure form_structure(credit_card_form);
+ FormStructure form_structure(credit_card_form);
form_structure.DetermineHeuristicTypes(nullptr, nullptr);
// Clear the heuristic types, and instead set the appropriate server types.
std::vector<ServerFieldType> heuristic_types, server_types;
@@ -353,7 +526,8 @@ TEST_F(AutofillSuggestionGeneratorTest, ShouldShowVirtualCardOption) {
heuristic_types.push_back(UNKNOWN_TYPE);
server_types.push_back(form_structure.field(i)->heuristic_type());
}
- form_structure.SetFieldTypes(heuristic_types, server_types);
+ FormStructureTestApi(&form_structure)
+ .SetFieldTypes(heuristic_types, server_types);
// Create a server card.
CreditCard server_card = test::GetMaskedServerCard();
@@ -377,13 +551,6 @@ TEST_F(AutofillSuggestionGeneratorTest, ShouldShowVirtualCardOption) {
EXPECT_TRUE(suggestion_generator()->ShouldShowVirtualCardOption(
&local_card, form_structure));
- // Reset form to reset field storage types to mock as an incomplete form.
- TestFormStructure incomplete_form_structure(credit_card_form);
-
- // If it is an incomplete form, it should return false;
- EXPECT_FALSE(suggestion_generator()->ShouldShowVirtualCardOption(
- &server_card, incomplete_form_structure));
-
// Reset server card virtual card enrollment state.
server_card.set_virtual_card_enrollment_state(
CreditCard::VirtualCardEnrollmentState::UNSPECIFIED);
@@ -404,6 +571,53 @@ TEST_F(AutofillSuggestionGeneratorTest, ShouldShowVirtualCardOption) {
&local_card, form_structure));
}
+TEST_F(AutofillSuggestionGeneratorTest, GetIBANSuggestions) {
+ std::vector<IBAN*> ibans;
+
+ IBAN iban0(base::GenerateGUID());
+ iban0.set_value(u"CH56 0483 5012 3456 7800 9");
+ iban0.set_nickname(u"My doctor's IBAN");
+ ibans.push_back(&iban0);
+
+ IBAN iban1(base::GenerateGUID());
+ iban1.set_value(u"DE91 1000 0000 0123 4567 89");
+ iban1.set_nickname(u"My brother's IBAN");
+ ibans.push_back(&iban1);
+
+ IBAN iban2(base::GenerateGUID());
+ iban2.set_value(u"GR96 0810 0010 0000 0123 4567 890");
+ iban2.set_nickname(u"My teacher's IBAN");
+ ibans.push_back(&iban2);
+
+ IBAN iban3(base::GenerateGUID());
+ iban3.set_value(u"PK70 BANK 0000 1234 5678 9000");
+ ibans.push_back(&iban3);
+
+ std::vector<Suggestion> iban_suggestions =
+ AutofillSuggestionGenerator::GetSuggestionsForIBANs(ibans);
+ EXPECT_TRUE(iban_suggestions.size() == 4);
+
+ EXPECT_EQ(iban_suggestions[0].main_text.value,
+ u"CH" + iban0.RepeatEllipsisForTesting(4) + u"9");
+ EXPECT_EQ(iban_suggestions[0].label, u"My doctor's IBAN");
+ EXPECT_EQ(iban_suggestions[0].frontend_id, POPUP_ITEM_ID_IBAN_ENTRY);
+
+ EXPECT_EQ(iban_suggestions[1].main_text.value,
+ u"DE" + iban1.RepeatEllipsisForTesting(4) + u"89");
+ EXPECT_EQ(iban_suggestions[1].label, u"My brother's IBAN");
+ EXPECT_EQ(iban_suggestions[1].frontend_id, POPUP_ITEM_ID_IBAN_ENTRY);
+
+ EXPECT_EQ(iban_suggestions[2].main_text.value,
+ u"GR" + iban2.RepeatEllipsisForTesting(5) + u"890");
+ EXPECT_EQ(iban_suggestions[2].label, u"My teacher's IBAN");
+ EXPECT_EQ(iban_suggestions[2].frontend_id, POPUP_ITEM_ID_IBAN_ENTRY);
+
+ EXPECT_EQ(iban_suggestions[3].main_text.value,
+ u"PK" + iban3.RepeatEllipsisForTesting(4) + u"9000");
+ EXPECT_EQ(iban_suggestions[3].label, u"");
+ EXPECT_EQ(iban_suggestions[3].frontend_id, POPUP_ITEM_ID_IBAN_ENTRY);
+}
+
TEST_F(AutofillSuggestionGeneratorTest,
GetPromoCodeSuggestionsFromPromoCodeOffers_ValidPromoCodes) {
std::vector<const AutofillOfferData*> promo_code_offers;
@@ -433,26 +647,28 @@ TEST_F(AutofillSuggestionGeneratorTest,
std::vector<Suggestion> promo_code_suggestions =
AutofillSuggestionGenerator::GetPromoCodeSuggestionsFromPromoCodeOffers(
promo_code_offers);
- EXPECT_TRUE(promo_code_suggestions.size() == 3);
+ EXPECT_TRUE(promo_code_suggestions.size() == 4);
EXPECT_EQ(promo_code_suggestions[0].main_text.value, u"test_promo_code_1");
EXPECT_EQ(promo_code_suggestions[0].label, u"test_value_prop_text_1");
- EXPECT_EQ(absl::get<std::string>(promo_code_suggestions[0].payload), "1");
+ EXPECT_EQ(promo_code_suggestions[0].GetPayload<std::string>(), "1");
EXPECT_EQ(promo_code_suggestions[0].frontend_id,
POPUP_ITEM_ID_MERCHANT_PROMO_CODE_ENTRY);
EXPECT_EQ(promo_code_suggestions[1].main_text.value, u"test_promo_code_2");
EXPECT_EQ(promo_code_suggestions[1].label, u"test_value_prop_text_2");
- EXPECT_EQ(absl::get<std::string>(promo_code_suggestions[1].payload), "2");
+ EXPECT_EQ(promo_code_suggestions[1].GetPayload<std::string>(), "2");
EXPECT_EQ(promo_code_suggestions[1].frontend_id,
POPUP_ITEM_ID_MERCHANT_PROMO_CODE_ENTRY);
- EXPECT_EQ(promo_code_suggestions[2].main_text.value,
+ EXPECT_EQ(promo_code_suggestions[2].frontend_id, POPUP_ITEM_ID_SEPARATOR);
+
+ EXPECT_EQ(promo_code_suggestions[3].main_text.value,
l10n_util::GetStringUTF16(
IDS_AUTOFILL_PROMO_CODE_SUGGESTIONS_FOOTER_TEXT));
- EXPECT_EQ(absl::get<GURL>(promo_code_suggestions[2].payload),
+ EXPECT_EQ(promo_code_suggestions[3].GetPayload<GURL>(),
offer1.GetOfferDetailsUrl().spec());
- EXPECT_EQ(promo_code_suggestions[2].frontend_id,
+ EXPECT_EQ(promo_code_suggestions[3].frontend_id,
POPUP_ITEM_ID_SEE_PROMO_CODE_DETAILS);
}
diff --git a/chromium/components/autofill/core/browser/autofill_test_utils.cc b/chromium/components/autofill/core/browser/autofill_test_utils.cc
index ec8485a3b14..8d74afe8ba5 100644
--- a/chromium/components/autofill/core/browser/autofill_test_utils.cc
+++ b/chromium/components/autofill/core/browser/autofill_test_utils.cc
@@ -17,6 +17,7 @@
#include "components/autofill/core/browser/data_model/autofill_profile.h"
#include "components/autofill/core/browser/data_model/credit_card.h"
#include "components/autofill/core/browser/data_model/credit_card_test_api.h"
+#include "components/autofill/core/browser/data_model/iban.h"
#include "components/autofill/core/browser/field_types.h"
#include "components/autofill/core/browser/randomized_encoder.h"
#include "components/autofill/core/browser/webdata/autofill_table.h"
@@ -99,6 +100,12 @@ FieldGlobalId MakeFieldGlobalId(RandomizeFrame randomize) {
return {MakeLocalFrameToken(randomize), MakeFieldRendererId()};
}
+FormData WithoutValues(FormData form) {
+ for (FormFieldData& field : form.fields)
+ field.value.clear();
+ return form;
+}
+
void SetFormGroupValues(FormGroup& form_group,
const std::vector<FormGroupValue>& values) {
for (const auto& value : values) {
@@ -474,6 +481,13 @@ AutofillProfile GetServerProfile2() {
return profile;
}
+IBAN GetIBAN() {
+ IBAN iban(base::GenerateGUID());
+ iban.set_value(u"DE91 1000 0000 0123 4567 89");
+ iban.set_nickname(u"Nickname for Iban");
+ return iban;
+}
+
CreditCard GetCreditCard() {
CreditCard credit_card(base::GenerateGUID(), kEmptyOrigin);
SetCreditCardInfo(&credit_card, "Test User", "4111111111111111" /* Visa */,
@@ -559,15 +573,6 @@ CreditCard GetMaskedServerCardWithNickname() {
return credit_card;
}
-CreditCard GetMaskedServerCardWithInvalidNickname() {
- CreditCard credit_card(CreditCard::MASKED_SERVER_CARD, "c789");
- test::SetCreditCardInfo(&credit_card, "Test user", "1111" /* Visa */,
- NextMonth().c_str(), NextYear().c_str(), "1");
- credit_card.SetNetworkForMaskedCard(kVisaCard);
- credit_card.SetNickname(u"Invalid nickname which is too long");
- return credit_card;
-}
-
CreditCard GetFullServerCard() {
CreditCard credit_card(CreditCard::FULL_SERVER_CARD, "c123");
test::SetCreditCardInfo(&credit_card, "Full Carter",
diff --git a/chromium/components/autofill/core/browser/autofill_test_utils.h b/chromium/components/autofill/core/browser/autofill_test_utils.h
index bbeea1f9057..ecb2ada072f 100644
--- a/chromium/components/autofill/core/browser/autofill_test_utils.h
+++ b/chromium/components/autofill/core/browser/autofill_test_utils.h
@@ -14,6 +14,7 @@
#include "components/autofill/core/browser/data_model/autofill_profile.h"
#include "components/autofill/core/browser/data_model/credit_card.h"
#include "components/autofill/core/browser/data_model/credit_card_cloud_token_data.h"
+#include "components/autofill/core/browser/data_model/iban.h"
#include "components/autofill/core/browser/field_types.h"
#include "components/autofill/core/browser/form_structure.h"
#include "components/autofill/core/browser/proto/api_v1.pb.h"
@@ -92,6 +93,9 @@ FormGlobalId MakeFormGlobalId(
FieldGlobalId MakeFieldGlobalId(
RandomizeFrame randomize_frame = RandomizeFrame(false));
+// Returns a copy of `form` with cleared values.
+FormData WithoutValues(FormData form);
+
// Helper function to set values and verification statuses to a form group.
void SetFormGroupValues(FormGroup& form_group,
const std::vector<FormGroupValue>& values);
@@ -202,6 +206,9 @@ AutofillProfile GetServerProfile();
// Returns a server profile full of dummy info, different to the above.
AutofillProfile GetServerProfile2();
+// Returns an IBAN full of dummy info.
+IBAN GetIBAN();
+
// Returns a credit card full of dummy info.
CreditCard GetCreditCard();
@@ -221,7 +228,6 @@ CreditCard GetMaskedServerCardWithNonLegacyId();
CreditCard GetMaskedServerCardWithLegacyId();
CreditCard GetMaskedServerCardAmex();
CreditCard GetMaskedServerCardWithNickname();
-CreditCard GetMaskedServerCardWithInvalidNickname();
// Returns a full server card full of dummy info.
CreditCard GetFullServerCard();
diff --git a/chromium/components/autofill/core/browser/autofill_type.cc b/chromium/components/autofill/core/browser/autofill_type.cc
index ec58ca421cb..fa7224ea415 100644
--- a/chromium/components/autofill/core/browser/autofill_type.cc
+++ b/chromium/components/autofill/core/browser/autofill_type.cc
@@ -24,14 +24,6 @@ FieldTypeGroup GroupTypeOfServerFieldType(ServerFieldType field_type) {
case NAME_FULL_WITH_HONORIFIC_PREFIX:
return FieldTypeGroup::kName;
- case NAME_BILLING_FIRST:
- case NAME_BILLING_MIDDLE:
- case NAME_BILLING_LAST:
- case NAME_BILLING_MIDDLE_INITIAL:
- case NAME_BILLING_FULL:
- case NAME_BILLING_SUFFIX:
- return FieldTypeGroup::kNameBilling;
-
case EMAIL_ADDRESS:
case USERNAME_AND_EMAIL_ADDRESS:
return FieldTypeGroup::kEmail;
@@ -48,13 +40,6 @@ FieldTypeGroup GroupTypeOfServerFieldType(ServerFieldType field_type) {
case PHONE_HOME_EXTENSION:
return FieldTypeGroup::kPhoneHome;
- case PHONE_BILLING_NUMBER:
- case PHONE_BILLING_CITY_CODE:
- case PHONE_BILLING_COUNTRY_CODE:
- case PHONE_BILLING_CITY_AND_NUMBER:
- case PHONE_BILLING_WHOLE_NUMBER:
- return FieldTypeGroup::kPhoneBilling;
-
case ADDRESS_HOME_LINE1:
case ADDRESS_HOME_LINE2:
case ADDRESS_HOME_LINE3:
@@ -78,19 +63,6 @@ FieldTypeGroup GroupTypeOfServerFieldType(ServerFieldType field_type) {
case ADDRESS_HOME_FLOOR:
return FieldTypeGroup::kAddressHome;
- case ADDRESS_BILLING_LINE1:
- case ADDRESS_BILLING_LINE2:
- case ADDRESS_BILLING_LINE3:
- case ADDRESS_BILLING_APT_NUM:
- case ADDRESS_BILLING_CITY:
- case ADDRESS_BILLING_STATE:
- case ADDRESS_BILLING_ZIP:
- case ADDRESS_BILLING_COUNTRY:
- case ADDRESS_BILLING_STREET_ADDRESS:
- case ADDRESS_BILLING_SORTING_CODE:
- case ADDRESS_BILLING_DEPENDENT_LOCALITY:
- return FieldTypeGroup::kAddressBilling;
-
case CREDIT_CARD_NAME_FULL:
case CREDIT_CARD_NAME_FIRST:
case CREDIT_CARD_NAME_LAST:
@@ -107,11 +79,6 @@ FieldTypeGroup GroupTypeOfServerFieldType(ServerFieldType field_type) {
case COMPANY_NAME:
return FieldTypeGroup::kCompany;
- case MERCHANT_PROMO_CODE:
- // TODO(crbug/1190334): Create new field type group kMerchantPromoCode.
- // (This involves updating many switch statements.)
- return FieldTypeGroup::kNoGroup;
-
case PASSWORD:
case ACCOUNT_CREATION_PASSWORD:
case NOT_ACCOUNT_CREATION_PASSWORD:
@@ -127,14 +94,12 @@ FieldTypeGroup GroupTypeOfServerFieldType(ServerFieldType field_type) {
case NO_SERVER_DATA:
case EMPTY_TYPE:
case AMBIGUOUS_TYPE:
- case PHONE_FAX_NUMBER:
- case PHONE_FAX_CITY_CODE:
- case PHONE_FAX_COUNTRY_CODE:
- case PHONE_FAX_CITY_AND_NUMBER:
- case PHONE_FAX_WHOLE_NUMBER:
case FIELD_WITH_DEFAULT_VALUE:
case MERCHANT_EMAIL_SIGNUP:
+ case MERCHANT_PROMO_CODE:
+ case IBAN_VALUE:
case UPI_VPA:
+ case CREDIT_CARD_STANDALONE_VERIFICATION_CODE:
return FieldTypeGroup::kNoGroup;
case MAX_VALID_FIELD_TYPE:
@@ -146,7 +111,7 @@ FieldTypeGroup GroupTypeOfServerFieldType(ServerFieldType field_type) {
case BIRTHDATE_DAY:
case BIRTHDATE_MONTH:
- case BIRTHDATE_YEAR_4_DIGITS:
+ case BIRTHDATE_4_DIGIT_YEAR:
return FieldTypeGroup::kBirthdateField;
case PRICE:
@@ -222,6 +187,11 @@ FieldTypeGroup GroupTypeOfHtmlFieldType(HtmlFieldType field_type,
case HTML_TYPE_EMAIL:
return FieldTypeGroup::kEmail;
+ case HTML_TYPE_BIRTHDATE_DAY:
+ case HTML_TYPE_BIRTHDATE_MONTH:
+ case HTML_TYPE_BIRTHDATE_YEAR:
+ return FieldTypeGroup::kBirthdateField;
+
case HTML_TYPE_UPI_VPA:
// TODO(crbug/702223): Add support for UPI-VPA.
return FieldTypeGroup::kNoGroup;
@@ -232,6 +202,9 @@ FieldTypeGroup GroupTypeOfHtmlFieldType(HtmlFieldType field_type,
case HTML_TYPE_MERCHANT_PROMO_CODE:
return FieldTypeGroup::kNoGroup;
+ case HTML_TYPE_IBAN:
+ return FieldTypeGroup::kNoGroup;
+
case HTML_TYPE_UNSPECIFIED:
case HTML_TYPE_UNRECOGNIZED:
return FieldTypeGroup::kNoGroup;
@@ -264,80 +237,8 @@ bool AutofillType::IsUnknown() const {
}
ServerFieldType AutofillType::GetStorableType() const {
- // Map billing types to the equivalent non-billing types.
- switch (server_type_) {
- case ADDRESS_BILLING_LINE1:
- return ADDRESS_HOME_LINE1;
-
- case ADDRESS_BILLING_LINE2:
- return ADDRESS_HOME_LINE2;
-
- case ADDRESS_BILLING_LINE3:
- return ADDRESS_HOME_LINE3;
-
- case ADDRESS_BILLING_APT_NUM:
- return ADDRESS_HOME_APT_NUM;
-
- case ADDRESS_BILLING_CITY:
- return ADDRESS_HOME_CITY;
-
- case ADDRESS_BILLING_STATE:
- return ADDRESS_HOME_STATE;
-
- case ADDRESS_BILLING_ZIP:
- return ADDRESS_HOME_ZIP;
-
- case ADDRESS_BILLING_COUNTRY:
- return ADDRESS_HOME_COUNTRY;
-
- case PHONE_BILLING_WHOLE_NUMBER:
- return PHONE_HOME_WHOLE_NUMBER;
-
- case PHONE_BILLING_NUMBER:
- return PHONE_HOME_NUMBER;
-
- case PHONE_BILLING_CITY_CODE:
- return PHONE_HOME_CITY_CODE;
-
- case PHONE_BILLING_COUNTRY_CODE:
- return PHONE_HOME_COUNTRY_CODE;
-
- case PHONE_BILLING_CITY_AND_NUMBER:
- return PHONE_HOME_CITY_AND_NUMBER;
-
- case NAME_BILLING_FIRST:
- return NAME_FIRST;
-
- case NAME_BILLING_MIDDLE:
- return NAME_MIDDLE;
-
- case NAME_BILLING_LAST:
- return NAME_LAST;
-
- case NAME_BILLING_MIDDLE_INITIAL:
- return NAME_MIDDLE_INITIAL;
-
- case NAME_BILLING_FULL:
- return NAME_FULL;
-
- case NAME_BILLING_SUFFIX:
- return NAME_SUFFIX;
-
- case ADDRESS_BILLING_STREET_ADDRESS:
- return ADDRESS_HOME_STREET_ADDRESS;
-
- case ADDRESS_BILLING_SORTING_CODE:
- return ADDRESS_HOME_SORTING_CODE;
-
- case ADDRESS_BILLING_DEPENDENT_LOCALITY:
- return ADDRESS_HOME_DEPENDENT_LOCALITY;
-
- case UNKNOWN_TYPE:
- break; // Try to parse HTML types instead.
-
- default:
- return server_type_;
- }
+ if (server_type_ != UNKNOWN_TYPE)
+ return server_type_;
switch (html_type_) {
case HTML_TYPE_UNSPECIFIED:
@@ -433,9 +334,13 @@ ServerFieldType AutofillType::GetStorableType() const {
return PHONE_HOME_CITY_CODE;
case HTML_TYPE_TEL_LOCAL:
+ return PHONE_HOME_NUMBER;
+
case HTML_TYPE_TEL_LOCAL_PREFIX:
+ return PHONE_HOME_NUMBER_PREFIX;
+
case HTML_TYPE_TEL_LOCAL_SUFFIX:
- return PHONE_HOME_NUMBER;
+ return PHONE_HOME_NUMBER_SUFFIX;
case HTML_TYPE_TEL_EXTENSION:
return PHONE_HOME_EXTENSION;
@@ -443,6 +348,13 @@ ServerFieldType AutofillType::GetStorableType() const {
case HTML_TYPE_EMAIL:
return EMAIL_ADDRESS;
+ case HTML_TYPE_BIRTHDATE_DAY:
+ return BIRTHDATE_DAY;
+ case HTML_TYPE_BIRTHDATE_MONTH:
+ return BIRTHDATE_MONTH;
+ case HTML_TYPE_BIRTHDATE_YEAR:
+ return BIRTHDATE_4_DIGIT_YEAR;
+
case HTML_TYPE_ADDITIONAL_NAME_INITIAL:
return NAME_MIDDLE_INITIAL;
@@ -466,6 +378,7 @@ ServerFieldType AutofillType::GetStorableType() const {
case HTML_TYPE_TRANSACTION_CURRENCY:
case HTML_TYPE_ONE_TIME_CODE:
case HTML_TYPE_MERCHANT_PROMO_CODE:
+ case HTML_TYPE_IBAN:
return UNKNOWN_TYPE;
case HTML_TYPE_UNRECOGNIZED:
diff --git a/chromium/components/autofill/core/browser/autofill_type_unittest.cc b/chromium/components/autofill/core/browser/autofill_type_unittest.cc
index 9c4a5bb3a9d..ef7b9e64474 100644
--- a/chromium/components/autofill/core/browser/autofill_type_unittest.cc
+++ b/chromium/components/autofill/core/browser/autofill_type_unittest.cc
@@ -29,16 +29,6 @@ TEST(AutofillTypeTest, ServerFieldTypes) {
EXPECT_EQ(PHONE_HOME_NUMBER, phone.GetStorableType());
EXPECT_EQ(FieldTypeGroup::kPhoneHome, phone.group());
- // Billing type.
- AutofillType billing_address(ADDRESS_BILLING_LINE1);
- EXPECT_EQ(ADDRESS_HOME_LINE1, billing_address.GetStorableType());
- EXPECT_EQ(FieldTypeGroup::kAddressBilling, billing_address.group());
-
- // Last value, to check any offset errors.
- AutofillType last(NAME_BILLING_SUFFIX);
- EXPECT_EQ(NAME_SUFFIX, last.GetStorableType());
- EXPECT_EQ(FieldTypeGroup::kNameBilling, last.group());
-
// Boundary (error) condition.
AutofillType boundary(MAX_VALID_FIELD_TYPE);
EXPECT_EQ(UNKNOWN_TYPE, boundary.GetStorableType());
diff --git a/chromium/components/autofill/core/browser/browser_autofill_manager.cc b/chromium/components/autofill/core/browser/browser_autofill_manager.cc
index 2dad433c7de..4d123df8304 100644
--- a/chromium/components/autofill/core/browser/browser_autofill_manager.cc
+++ b/chromium/components/autofill/core/browser/browser_autofill_manager.cc
@@ -52,7 +52,6 @@
#include "components/autofill/core/browser/autofill_experiments.h"
#include "components/autofill/core/browser/autofill_external_delegate.h"
#include "components/autofill/core/browser/autofill_field.h"
-#include "components/autofill/core/browser/autofill_regexes.h"
#include "components/autofill/core/browser/autofill_suggestion_generator.h"
#include "components/autofill/core/browser/autofill_type.h"
#include "components/autofill/core/browser/browser_autofill_manager_test_delegate.h"
@@ -77,6 +76,7 @@
#include "components/autofill/core/browser/suggestions_context.h"
#include "components/autofill/core/browser/ui/popup_item_ids.h"
#include "components/autofill/core/browser/validation.h"
+#include "components/autofill/core/common/autocomplete_parsing_util.h"
#include "components/autofill/core/common/autofill_clock.h"
#include "components/autofill/core/common/autofill_constants.h"
#include "components/autofill/core/common/autofill_data_validation.h"
@@ -85,6 +85,7 @@
#include "components/autofill/core/common/autofill_internals/logging_scope.h"
#include "components/autofill/core/common/autofill_payments_features.h"
#include "components/autofill/core/common/autofill_prefs.h"
+#include "components/autofill/core/common/autofill_regexes.h"
#include "components/autofill/core/common/autofill_tick_clock.h"
#include "components/autofill/core/common/form_data.h"
#include "components/autofill/core/common/form_data_predictions.h"
@@ -203,6 +204,41 @@ void LogLanguageMetrics(const translate::LanguageState* language_state) {
}
}
+void LogAutocompletePredictionCollisionTypeMetrics(
+ const FormStructure& form_structure) {
+ for (size_t i = 0; i < form_structure.field_count(); i++) {
+ const AutofillField* field = form_structure.field(i);
+ auto heuristic_type = field->heuristic_type();
+ auto server_type = field->server_type();
+
+ auto prediction_state = AutofillMetrics::PredictionState::kNone;
+ if (IsFillableFieldType(heuristic_type)) {
+ prediction_state = IsFillableFieldType(server_type)
+ ? AutofillMetrics::PredictionState::kBoth
+ : AutofillMetrics::PredictionState::kHeuristics;
+ } else if (IsFillableFieldType(server_type)) {
+ prediction_state = AutofillMetrics::PredictionState::kServer;
+ }
+
+ // An unparsable autocomplete attribute is treated like kNone.
+ auto autocomplete_state = AutofillMetrics::AutocompleteState::kNone;
+ if (ShouldIgnoreAutocompleteAttribute(field->autocomplete_attribute)) {
+ autocomplete_state = AutofillMetrics::AutocompleteState::kOff;
+ } else if (auto autocomplete = ParseAutocompleteAttribute(*field)) {
+ autocomplete_state = autocomplete->field_type != HTML_TYPE_UNRECOGNIZED
+ ? AutofillMetrics::AutocompleteState::kValid
+ : AutofillMetrics::AutocompleteState::kGarbage;
+ }
+
+ AutofillMetrics::LogAutocompletePredictionCollisionState(
+ prediction_state, autocomplete_state);
+ if (autocomplete_state == AutofillMetrics::AutocompleteState::kGarbage) {
+ AutofillMetrics::LogAutocompletePredictionCollisionTypes(server_type,
+ heuristic_type);
+ }
+ }
+}
+
// Finds the first field in |form_structure| with |field.value|=|value|.
AutofillField* FindFirstFieldWithValue(const FormStructure& form_structure,
const std::u16string& value) {
@@ -371,16 +407,6 @@ size_t TypeValueFormFillingLimit(ServerFieldType field_type) {
}
}
-// Logs the reason for suppressing autofill suggestions to
-// chrome://autofill-internals.
-void LogSuppressReason(LogManager* log_manager, const std::string& reason) {
- if (!log_manager)
- return;
- log_manager->Log() << LoggingScope::kFilling
- << LogMessage::kSuggestionSuppressed
- << " Reason: " << reason;
-}
-
} // namespace
BrowserAutofillManager::FillingContext::FillingContext(
@@ -419,7 +445,7 @@ BrowserAutofillManager::BrowserAutofillManager(
enable_download_manager),
external_delegate_(
std::make_unique<AutofillExternalDelegate>(this, driver)),
- touch_to_fill_delegate_(std::make_unique<TouchToFillDelegate>()),
+ touch_to_fill_delegate_(std::make_unique<TouchToFillDelegateImpl>(this)),
app_locale_(app_locale),
personal_data_(client->GetPersonalDataManager()),
field_filler_(app_locale, client->GetAddressNormalizer()),
@@ -454,6 +480,10 @@ BrowserAutofillManager::~BrowserAutofillManager() {
single_field_form_fill_router_->CancelPendingQueries(this);
}
+base::WeakPtr<AutofillManager> BrowserAutofillManager::GetWeakPtr() {
+ return weak_ptr_factory_.GetWeakPtr();
+}
+
AutofillOfferManager* BrowserAutofillManager::GetOfferManager() {
return offer_manager_;
}
@@ -644,14 +674,10 @@ bool BrowserAutofillManager::ShouldParseForms(
has_logged_autofill_enabled_ = true;
}
- // TODO(crbug.com/1293341): Enable the experiment by default.
- // The placement of the IsEnabled() call is chosen very intentionally.
- // Only users with disabled autofill will go into the control or experiment
- // group.
- return autofill_enabled ||
- (base::FeatureList::IsEnabled(
- features::kAutofillFixServerQueriesIfPasswordManagerIsEnabled) &&
- password_manager_enabled);
+ // Enable the parsing also for the password manager, so that we fetch server
+ // classifications if the password manager is enabled but autofill is
+ // disabled.
+ return autofill_enabled || password_manager_enabled;
}
void BrowserAutofillManager::OnFormSubmittedImpl(const FormData& form,
@@ -659,13 +685,11 @@ void BrowserAutofillManager::OnFormSubmittedImpl(const FormData& form,
SubmissionSource source) {
base::UmaHistogramEnumeration("Autofill.FormSubmission.PerProfileType",
client()->GetProfileType());
- if (log_manager()) {
- log_manager()->Log() << LoggingScope::kSubmission
- << LogMessage::kFormSubmissionDetected << Br{}
- << "known_success: " << known_success << Br{}
- << "source: " << SubmissionSourceToString(source)
- << Br{} << form;
- }
+ LOG_AF(log_manager()) << LoggingScope::kSubmission
+ << LogMessage::kFormSubmissionDetected << Br{}
+ << "known_success: " << known_success << Br{}
+ << "source: " << SubmissionSourceToString(source)
+ << Br{} << form;
// Always upload page language metrics.
LogLanguageMetrics(client()->GetLanguageState());
@@ -681,6 +705,9 @@ void BrowserAutofillManager::OnFormSubmittedImpl(const FormData& form,
return;
}
+ // Log metrics about the autocomplete attribute usage in the submitted form.
+ LogAutocompletePredictionCollisionTypeMetrics(*submitted_form);
+
// Log interaction time metrics for the ablation study.
if (!initial_interaction_timestamp_.is_null()) {
base::TimeDelta time_from_interaction_to_submission =
@@ -707,8 +734,12 @@ void BrowserAutofillManager::OnFormSubmittedImpl(const FormData& form,
form_for_autocomplete.fields[i].should_autocomplete = false;
}
+ // If the field was edited by the user and there existed an autofillable
+ // value for the field, log whether the value on submission is same as the
+ // autofillable value.
if (submitted_form->field(i)
- ->value_not_autofilled_over_existing_value_hash()) {
+ ->value_not_autofilled_over_existing_value_hash() &&
+ (submitted_form->field(i)->properties_mask & kUserTyped)) {
// Compare and record if the currently filled value is same as the
// non-empty value that was to be autofilled in the field.
AutofillMetrics::
@@ -946,10 +977,10 @@ bool BrowserAutofillManager::IsFormNonSecure(const FormData& form) const {
}
void BrowserAutofillManager::OnAskForValuesToFillImpl(
- int query_id,
const FormData& form,
const FormFieldData& field,
const gfx::RectF& transformed_box,
+ int query_id,
bool autoselect_first_suggestion,
TouchToFillEligible touch_to_fill_eligible) {
if (base::FeatureList::IsEnabled(features::kAutofillDisableFilling)) {
@@ -972,17 +1003,25 @@ void BrowserAutofillManager::OnAskForValuesToFillImpl(
single_field_form_fill_router_->CancelPendingQueries(this);
external_delegate_->OnSuggestionsReturned(query_id, suggestions,
autoselect_first_suggestion);
- LogSuppressReason(log_manager(), "Ablation experiment");
+ LOG_AF(log_manager())
+ << LoggingScope::kFilling << LogMessage::kSuggestionSuppressed
+ << " Reason: Ablation experiment";
return;
case SuppressReason::kInsecureForm:
- LogSuppressReason(log_manager(), "Insecure form");
+ LOG_AF(log_manager())
+ << LoggingScope::kFilling << LogMessage::kSuggestionSuppressed
+ << " Reason: Insecure form";
return;
case SuppressReason::kAutocompleteOff:
- LogSuppressReason(log_manager(), "autocomplete=off");
+ LOG_AF(log_manager())
+ << LoggingScope::kFilling << LogMessage::kSuggestionSuppressed
+ << " Reason: autocomplete=off";
return;
case SuppressReason::kAutocompleteUnrecognized:
- LogSuppressReason(log_manager(), "autocomplete=unrecognized");
+ LOG_AF(log_manager())
+ << LoggingScope::kFilling << LogMessage::kSuggestionSuppressed
+ << " Reason: autocomplete=unrecognized";
return;
}
@@ -1003,18 +1042,18 @@ void BrowserAutofillManager::OnAskForValuesToFillImpl(
}
}
- auto ShouldOfferAutocomplete = [&] {
- // Do not offer autocomplete if one of the following:
+ auto ShouldOfferSingleFieldFormFill = [&] {
+ // Do not offer single field form fill if one of the following is true:
// * There are already suggestions.
// * Credit card sign-in promo is offered.
- // * Autocomplete for the field is disabled.
- if (!suggestions.empty() || ShouldShowCreditCardSigninPromo(form, field) ||
- !field.should_autocomplete) {
+ if (!suggestions.empty() || ShouldShowCreditCardSigninPromo(form, field))
return false;
- }
- // Do not offer autocomplete suggestions for credit card number, cvc and
- // expiration date related fields.
+ // Do not offer single field form fill suggestions for credit card number,
+ // cvc, and expiration date related fields. Standalone cvc fields (used to
+ // re-authenticate the use of a credit card the website has on file) will be
+ // handled separately because those have the field type
+ // CREDIT_CARD_STANDALONE_VERIFICATION_CODE.
ServerFieldType server_type =
context.focused_field ? context.focused_field->Type().GetStorableType()
: UNKNOWN_TYPE;
@@ -1024,9 +1063,9 @@ void BrowserAutofillManager::OnAskForValuesToFillImpl(
return false;
}
- // Do not offer autocomplete suggestions if popups are suppressed due to an
- // unrecognized autocomplete attribute. Note that in the context of
- // Autofill, the popup for credit card related fields is not getting
+ // Do not offer single field form fill suggestions if popups are suppressed
+ // due to an unrecognized autocomplete attribute. Note that in the context
+ // of Autofill, the popup for credit card related fields is not getting
// suppressed due to an unrecognized autocomplete attribute.
if (context.suppress_reason == SuppressReason::kAutocompleteUnrecognized) {
return false;
@@ -1045,20 +1084,25 @@ void BrowserAutofillManager::OnAskForValuesToFillImpl(
return true;
};
- if (ShouldOfferAutocomplete()) {
+ if (ShouldOfferSingleFieldFormFill()) {
// Suggestions come back asynchronously, so the SingleFieldFormFillRouter
// will handle sending the results back to the renderer.
- single_field_form_fill_router_->OnGetSingleFieldSuggestions(
- query_id, client()->IsAutocompleteEnabled(),
- autoselect_first_suggestion, field.name, field.value,
- field.form_control_type, weak_ptr_factory_.GetWeakPtr(), context);
- return;
+ bool handled_by_single_field_form_filler =
+ single_field_form_fill_router_->OnGetSingleFieldSuggestions(
+ query_id, client()->IsAutocompleteEnabled(),
+ autoselect_first_suggestion, field, weak_ptr_factory_.GetWeakPtr(),
+ context);
+ if (handled_by_single_field_form_filler)
+ return;
}
single_field_form_fill_router_->CancelPendingQueries(this);
- if (touch_to_fill_eligible &&
- touch_to_fill_delegate_->TryToShowTouchToFill(query_id, form, field)) {
- // Touch To Fill is shown.
+ if (touch_to_fill_delegate_->IsShowingTouchToFill() ||
+ (touch_to_fill_eligible &&
+ touch_to_fill_delegate_->TryToShowTouchToFill(query_id, form, field))) {
+ // Touch To Fill surface is shown, so abort showing regular Autofill UI.
+ // Now the flow is controlled by the |touch_to_fill_delegate_| instead
+ // of |external_delegate_|.
return;
}
// Send Autofill suggestions (could be an empty list).
@@ -1165,11 +1209,12 @@ void BrowserAutofillManager::FillOrPreviewForm(
FillOrPreviewProfileForm(action, query_id, form, field, *profile);
}
-void BrowserAutofillManager::FillCreditCardForm(int query_id,
- const FormData& form,
- const FormFieldData& field,
- const CreditCard& credit_card,
- const std::u16string& cvc) {
+void BrowserAutofillManager::FillCreditCardFormImpl(
+ const FormData& form,
+ const FormFieldData& field,
+ const CreditCard& credit_card,
+ const std::u16string& cvc,
+ int query_id) {
if (!IsValidFormData(form) || !IsValidFormFieldData(field) ||
!driver()->RendererIsAvailable()) {
return;
@@ -1185,13 +1230,24 @@ void BrowserAutofillManager::FillCreditCardForm(int query_id,
autofill_field);
}
-void BrowserAutofillManager::FillProfileForm(const AutofillProfile& profile,
- const FormData& form,
- const FormFieldData& field) {
+void BrowserAutofillManager::FillProfileFormImpl(
+ const FormData& form,
+ const FormFieldData& field,
+ const AutofillProfile& profile) {
FillOrPreviewProfileForm(mojom::RendererFormDataAction::kFill,
/*query_id=*/kNoQueryId, form, field, profile);
}
+void BrowserAutofillManager::SetProfileFillViaAutofillAssistantIntent(
+ const autofill_assistant::AutofillAssistantIntent intent) {
+ address_form_event_logger_->SetAutofillAssistantIntentForFilling(intent);
+}
+
+void BrowserAutofillManager::SetCreditCardFillViaAutofillAssistantIntent(
+ const autofill_assistant::AutofillAssistantIntent intent) {
+ credit_card_form_event_logger_->SetAutofillAssistantIntentForFilling(intent);
+}
+
void BrowserAutofillManager::FillOrPreviewVirtualCardInformation(
mojom::RendererFormDataAction action,
const std::string& guid,
@@ -1211,7 +1267,8 @@ void BrowserAutofillManager::FillOrPreviewVirtualCardInformation(
}
}
-void BrowserAutofillManager::OnFocusNoLongerOnForm(bool had_interacted_form) {
+void BrowserAutofillManager::OnFocusNoLongerOnFormImpl(
+ bool had_interacted_form) {
// For historical reasons, Chrome takes action on this message only if focus
// was previously on a form with which the user had interacted.
// TODO(crbug.com/1140473): Remove need for this short-circuit.
@@ -1265,12 +1322,12 @@ void BrowserAutofillManager::OnSelectControlDidChangeImpl(
// TODO(crbug.com/814961): Handle select control change.
}
-void BrowserAutofillManager::OnDidPreviewAutofillFormData() {
+void BrowserAutofillManager::OnDidPreviewAutofillFormDataImpl() {
if (test_delegate_)
test_delegate_->DidPreviewFormData();
}
-void BrowserAutofillManager::OnDidFillAutofillFormData(
+void BrowserAutofillManager::OnDidFillAutofillFormDataImpl(
const FormData& form,
const TimeTicks timestamp) {
if (test_delegate_)
@@ -1346,12 +1403,13 @@ void BrowserAutofillManager::DidShowSuggestions(bool has_autofill_suggestions,
}
}
-void BrowserAutofillManager::OnHidePopup() {
+void BrowserAutofillManager::OnHidePopupImpl() {
if (!IsAutofillEnabled())
return;
single_field_form_fill_router_->CancelPendingQueries(this);
client()->HideAutofillPopup(PopupHidingReason::kRendererEvent);
+ touch_to_fill_delegate_->HideTouchToFill();
}
bool BrowserAutofillManager::GetDeletionConfirmationText(
@@ -1470,12 +1528,14 @@ void BrowserAutofillManager::SetDataList(
external_delegate_->SetCurrentDataListValues(values, labels);
}
-void BrowserAutofillManager::SelectFieldOptionsDidChange(const FormData& form) {
- // Look for a cached version of the form. It will be a null pointer if none is
- // found, which is fine.
- FormStructure* cached_form = FindCachedFormByRendererId(form.global_id());
-
- FormStructure* form_structure = ParseForm(form, cached_form);
+void BrowserAutofillManager::OnSelectFieldOptionsDidChangeImpl(
+ const FormData& form) {
+ FormStructure* form_structure = FindCachedFormByRendererId(form.global_id());
+ if (!base::FeatureList::IsEnabled(features::kAutofillParseAsync)) {
+ // If AutofillParseAsync is enabled, the form has just been parsed
+ // asynchronously if necessary.
+ form_structure = ParseForm(form, form_structure);
+ }
if (!form_structure)
return;
@@ -1485,45 +1545,44 @@ void BrowserAutofillManager::SelectFieldOptionsDidChange(const FormData& form) {
TriggerRefill(form);
}
-void BrowserAutofillManager::JavaScriptChangedAutofilledValue(
+void BrowserAutofillManager::OnJavaScriptChangedAutofilledValueImpl(
const FormData& form,
const FormFieldData& field,
const std::u16string& old_value) {
// Log to chrome://autofill-internals that a field's value was set by
// JavaScript.
- if (log_manager()) {
- auto StructureOfString = [](std::u16string str) {
- for (auto& c : str) {
- if (base::IsAsciiAlpha(c)) {
- c = 'a';
- } else if (base::IsAsciiDigit(c)) {
- c = '0';
- } else if (base::IsAsciiWhitespace(c)) {
- c = ' ';
- } else {
- c = '$';
- }
+ auto StructureOfString = [](std::u16string str) {
+ for (auto& c : str) {
+ if (base::IsAsciiAlpha(c)) {
+ c = 'a';
+ } else if (base::IsAsciiDigit(c)) {
+ c = '0';
+ } else if (base::IsAsciiWhitespace(c)) {
+ c = ' ';
+ } else {
+ c = '$';
}
- return str;
- };
- std::string field_number = "unknown";
+ }
+ return str;
+ };
+ auto GetFieldNumber = [&]() {
for (size_t i = 0; i < form.fields.size(); ++i) {
- if (form.fields[i].global_id() == field.global_id()) {
- field_number = base::StringPrintf("Field %zu", i);
- }
+ if (form.fields[i].global_id() == field.global_id())
+ return base::StringPrintf("Field %zu", i);
}
- LogBuffer change;
- change << Tag{"div"} << Attrib{"class", "form"};
- change << field << Br{};
- change << "Old value structure: '"
- << StructureOfString(old_value.substr(0, 80)) << "'" << Br{};
- change << "New value structure: '"
- << StructureOfString(field.value.substr(0, 80)) << "'";
- log_manager()->Log() << LoggingScope::kWebsiteModifiedFieldValue
- << LogMessage::kJavaScriptChangedAutofilledValue
- << Br{} << Tag{"table"} << Tr{} << field_number
- << std::move(change);
- }
+ return std::string("unknown");
+ };
+ LogBuffer change(IsLoggingActive(log_manager()));
+ LOG_AF(change) << Tag{"div"} << Attrib{"class", "form"};
+ LOG_AF(change) << field << Br{};
+ LOG_AF(change) << "Old value structure: '"
+ << StructureOfString(old_value.substr(0, 80)) << "'" << Br{};
+ LOG_AF(change) << "New value structure: '"
+ << StructureOfString(field.value.substr(0, 80)) << "'";
+ LOG_AF(log_manager()) << LoggingScope::kWebsiteModifiedFieldValue
+ << LogMessage::kJavaScriptChangedAutofilledValue << Br{}
+ << Tag{"table"} << Tr{} << GetFieldNumber()
+ << std::move(change);
MaybeTriggerRefillForExpirationDate(form, field, old_value);
}
@@ -1548,14 +1607,15 @@ void BrowserAutofillManager::MaybeTriggerRefillForExpirationDate(
if (old_value == field.value)
return;
- const char16_t* kFormatRegEx = uR"(^(\d\d)(\s?[/-]?\s?)?(\d\d|\d\d\d\d)$)";
+ static constexpr char16_t kFormatRegEx[] =
+ uR"(^(\d\d)(\s?[/-]?\s?)?(\d\d|\d\d\d\d)$)";
std::vector<std::u16string> old_groups;
- if (!MatchesPattern(old_value, kFormatRegEx, &old_groups))
+ if (!MatchesRegex<kFormatRegEx>(old_value, &old_groups))
return;
DCHECK_EQ(old_groups.size(), 4u);
std::vector<std::u16string> new_groups;
- if (!MatchesPattern(field.value, kFormatRegEx, &new_groups))
+ if (!MatchesRegex<kFormatRegEx>(field.value, &new_groups))
return;
DCHECK_EQ(new_groups.size(), 4u);
@@ -1619,16 +1679,22 @@ void BrowserAutofillManager::OnCreditCardFetched(CreditCardFetchResult result,
card_art_image ? *card_art_image : gfx::Image());
}
- FillCreditCardForm(credit_card_query_id_, credit_card_form_,
- credit_card_field_, *credit_card, cvc);
+ // After a server card is fetched, save its instrument id.
+ client()->GetFormDataImporter()->SetFetchedCardInstrumentId(
+ credit_card->instrument_id());
+
+ FillCreditCardFormImpl(credit_card_form_, credit_card_field_, *credit_card,
+ cvc, credit_card_query_id_);
if (credit_card->record_type() == CreditCard::FULL_SERVER_CARD ||
credit_card->record_type() == CreditCard::VIRTUAL_CARD) {
credit_card_access_manager_->CacheUnmaskedCardInfo(*credit_card, cvc);
}
}
-void BrowserAutofillManager::OnDidEndTextFieldEditing() {
+void BrowserAutofillManager::OnDidEndTextFieldEditingImpl() {
external_delegate_->DidEndTextFieldEditing();
+ // Should not hide the Touch To Fill surface, since it is an overlay UI
+ // which ends editing.
}
bool BrowserAutofillManager::IsAutofillEnabled() const {
@@ -1671,7 +1737,7 @@ void BrowserAutofillManager::UploadFormDataAsyncCallback(
const TimeTicks& submission_time,
bool observed_submission) {
if (submitted_form->ShouldRunHeuristics() ||
- submitted_form->ShouldRunPromoCodeHeuristics() ||
+ submitted_form->ShouldRunHeuristicsForSingleFieldForms() ||
submitted_form->ShouldBeQueried()) {
submitted_form->LogQualityMetrics(
submitted_form->form_parsed_timestamp(), interaction_time,
@@ -1710,6 +1776,15 @@ void BrowserAutofillManager::Reset() {
// save a card is shown after page navigation.
ProcessPendingFormForUpload();
DCHECK(!pending_form_data_);
+ // {address, credit_card}_form_event_logger_ need to be reset before
+ // AutofillManager::Reset() because ~FormEventLoggerBase() uses
+ // form_interactions_ukm_logger_ that is created and assigned in
+ // AutofillManager::Reset(). The new form_interactions_ukm_logger_ instance
+ // is needed for constructing the new *form_event_logger_ instances which is
+ // why calling AutofillManager::Reset() after constructing *form_event_logger_
+ // instances is not an option.
+ address_form_event_logger_.reset();
+ credit_card_form_event_logger_.reset();
AutofillManager::Reset();
address_form_event_logger_ = std::make_unique<AddressFormEventLogger>(
driver()->IsInAnyMainFrame(), form_interactions_ukm_logger(),
@@ -1735,6 +1810,7 @@ void BrowserAutofillManager::Reset() {
credit_card_action_ = mojom::RendererFormDataAction::kPreview;
initial_interaction_timestamp_ = TimeTicks();
external_delegate_->Reset();
+ touch_to_fill_delegate_->Reset();
filling_context_.clear();
form_interactions_counter_ = std::make_unique<FormInteractionsCounter>();
}
@@ -1805,11 +1881,11 @@ void BrowserAutofillManager::FillOrPreviewDataModelForm(
DCHECK(form_structure);
DCHECK(autofill_field);
- LogBuffer buffer;
- buffer << "is credit card section: " << is_credit_card << Br{};
- buffer << "is refill: " << is_refill << Br{};
- buffer << *form_structure << Br{};
- buffer << Tag{"table"};
+ LogBuffer buffer(IsLoggingActive(log_manager()));
+ LOG_AF(buffer) << "is credit card section: " << is_credit_card << Br{};
+ LOG_AF(buffer) << "is refill: " << is_refill << Br{};
+ LOG_AF(buffer) << *form_structure << Br{};
+ LOG_AF(buffer) << Tag{"table"};
form_structure->RationalizePhoneNumbersInSection(autofill_field->section);
@@ -1853,13 +1929,15 @@ void BrowserAutofillManager::FillOrPreviewDataModelForm(
result.fields[i].section = form_structure->field(i)->section;
if (form_structure->field(i)->section != autofill_field->section) {
- buffer << Tr{} << field_number << "Skipped: not part of filled section";
+ LOG_AF(buffer) << Tr{} << field_number
+ << "Skipped: not part of filled section";
continue;
}
if (form_structure->field(i)->only_fill_when_focused() &&
!form_structure->field(i)->SameFieldAs(field)) {
- buffer << Tr{} << field_number << "Skipped: only fill when focused";
+ LOG_AF(buffer) << Tr{} << field_number
+ << "Skipped: only fill when focused";
continue;
}
@@ -1879,7 +1957,7 @@ void BrowserAutofillManager::FillOrPreviewDataModelForm(
->LogHiddenRepresentationalFieldSkipDecision(*form_structure,
*cached_field, skip);
if (skip) {
- buffer << Tr{} << field_number << "Skipped: invisible field";
+ LOG_AF(buffer) << Tr{} << field_number << "Skipped: invisible field";
continue;
}
}
@@ -1896,6 +1974,8 @@ void BrowserAutofillManager::FillOrPreviewDataModelForm(
// case.
if (base::FeatureList::IsEnabled(
features::kAutofillPreventOverridingPrefilledValues)) {
+ form_structure->field(i)
+ ->set_value_not_autofilled_over_existing_value_hash(absl::nullopt);
if (form.fields[i].form_control_type != "select-one" &&
!form.fields[i].value.empty() && !has_override &&
!FormFieldData::DeepEqual(form.fields[i], field)) {
@@ -1907,18 +1987,16 @@ void BrowserAutofillManager::FillOrPreviewDataModelForm(
optional_cvc ? *optional_cvc : kEmptyCvc, action,
&unused_failure_to_fill);
if (action == mojom::RendererFormDataAction::kFill &&
- !fill_value.empty() && fill_value != form.fields[i].value) {
- // Save the value that was supposed to be autofilled for this field.
+ !fill_value.empty() && fill_value != form.fields[i].value &&
+ !form_structure->field(i)->value.empty()) {
+ // Save the value that was supposed to be autofilled for this field if
+ // the field contained an initial value.
form_structure->field(i)
->set_value_not_autofilled_over_existing_value_hash(
base::FastHash(base::UTF16ToUTF8(fill_value)));
}
continue;
}
-
- // Clear out the value in case the autofill happens for the field.
- form_structure->field(i)
- ->set_value_not_autofilled_over_existing_value_hash(absl::nullopt);
}
// Do not fill fields that have been edited by the user, except if the field
@@ -1929,8 +2007,8 @@ void BrowserAutofillManager::FillOrPreviewDataModelForm(
(!form.fields[i].value.empty() ||
!form_structure->field(i)->value.empty()) &&
!cached_field->SameFieldAs(field)) {
- buffer << Tr{} << field_number
- << "Skipped: don't fill user-filled fields";
+ LOG_AF(buffer) << Tr{} << field_number
+ << "Skipped: don't fill user-filled fields";
continue;
}
@@ -1938,15 +2016,16 @@ void BrowserAutofillManager::FillOrPreviewDataModelForm(
// when it's a refill.
if (result.fields[i].is_autofilled && !cached_field->SameFieldAs(field) &&
!is_refill) {
- buffer << Tr{} << field_number
- << "Skipped: don't fill previously filled fields unless during a "
- "refill";
+ LOG_AF(buffer)
+ << Tr{} << field_number
+ << "Skipped: don't fill previously filled fields unless during a "
+ "refill";
continue;
}
if (field_group_type == FieldTypeGroup::kNoGroup) {
- buffer << Tr{} << field_number
- << "Skipped: field type has no fillable group";
+ LOG_AF(buffer) << Tr{} << field_number
+ << "Skipped: field type has no fillable group";
continue;
}
@@ -1955,9 +2034,10 @@ void BrowserAutofillManager::FillOrPreviewDataModelForm(
if (is_refill &&
!base::Contains(filling_context->type_groups_originally_filled,
field_group_type)) {
- buffer << Tr{} << field_number
- << "Skipped: in a refill, only fields from the group that was "
- "filled in the initial fill may be filled";
+ LOG_AF(buffer)
+ << Tr{} << field_number
+ << "Skipped: in a refill, only fields from the group that was "
+ "filled in the initial fill may be filled";
continue;
}
@@ -1967,16 +2047,16 @@ void BrowserAutofillManager::FillOrPreviewDataModelForm(
if (data_util::IsCreditCardExpirationType(field_type) &&
(is_credit_card && absl::get<const CreditCard*>(profile_or_credit_card)
->IsExpired(AutofillClock::Now()))) {
- buffer << Tr{} << field_number
- << "Skipped: don't fill expiration date of expired cards";
+ LOG_AF(buffer) << Tr{} << field_number
+ << "Skipped: don't fill expiration date of expired cards";
continue;
}
// A field with a specific type is only allowed to be filled a limited
// number of times given by |TypeValueFormFillingLimit(field_type)|.
if (++type_count[field_type] > TypeValueFormFillingLimit(field_type)) {
- buffer << Tr{} << field_number
- << "Skipped: field-type filling-limit reached";
+ LOG_AF(buffer) << Tr{} << field_number
+ << "Skipped: field-type filling-limit reached";
continue;
}
@@ -2018,16 +2098,17 @@ void BrowserAutofillManager::FillOrPreviewDataModelForm(
bool has_value_after = !result.fields[i].value.empty();
bool is_autofilled_after = result.fields[i].is_autofilled;
- buffer << Tr{} << field_number
- << base::StringPrintf(
- "Fillable - has value: %d->%d; autofilled: %d->%d. %s",
- has_value_before, has_value_after, is_autofilled_before,
- is_autofilled_after, failure_to_fill.c_str());
+ LOG_AF(buffer)
+ << Tr{} << field_number
+ << base::StringPrintf(
+ "Fillable - has value: %d->%d; autofilled: %d->%d. %s",
+ has_value_before, has_value_after, is_autofilled_before,
+ is_autofilled_after, failure_to_fill.c_str());
if (!cached_field->IsFocusable() && result.fields[i].is_autofilled)
AutofillMetrics::LogHiddenOrPresentationalSelectFieldsFilled();
}
- buffer << CTag{"table"};
+ LOG_AF(buffer) << CTag{"table"};
autofilled_form_signatures_.push_front(form_structure->FormSignatureAsStr());
// Only remember the last few forms that we've seen, both to avoid false
@@ -2035,11 +2116,9 @@ void BrowserAutofillManager::FillOrPreviewDataModelForm(
if (autofilled_form_signatures_.size() > kMaxRecentFormSignaturesToRemember)
autofilled_form_signatures_.pop_back();
- if (log_manager()) {
- log_manager()->Log() << LoggingScope::kFilling
- << LogMessage::kSendFillingData << Br{}
- << std::move(buffer);
- }
+ LOG_AF(log_manager()) << LoggingScope::kFilling
+ << LogMessage::kSendFillingData << Br{}
+ << std::move(buffer);
auto field_types = base::MakeFlatMap<FieldGlobalId, ServerFieldType>(
*form_structure, {}, [](const auto& field) {
@@ -2159,6 +2238,8 @@ std::vector<Suggestion> BrowserAutofillManager::GetCreditCardSuggestions(
return suggestions;
}
+// TODO(crbug.com/1309848) Eliminate and replace with a listener?
+// Should we do the same with all the other BrowserAutofillManager events?
void BrowserAutofillManager::OnBeforeProcessParsedForms() {
has_parsed_forms_ = true;
@@ -2648,6 +2729,8 @@ void BrowserAutofillManager::GetAvailableSuggestions(
// warning message and don't offer autofill. The warning is shown even if
// there are no autofill suggestions available.
if (IsFormMixedContent(client(), form) &&
+ client()->GetPrefs()->FindPreference(
+ ::prefs::kMixedFormsWarningsEnabled) &&
client()->GetPrefs()->GetBoolean(::prefs::kMixedFormsWarningsEnabled)) {
suggestions->clear();
// If the user begins typing, we interpret that as dismissing the warning.
diff --git a/chromium/components/autofill/core/browser/browser_autofill_manager.h b/chromium/components/autofill/core/browser/browser_autofill_manager.h
index d6d33df9090..c33ab8422d4 100644
--- a/chromium/components/autofill/core/browser/browser_autofill_manager.h
+++ b/chromium/components/autofill/core/browser/browser_autofill_manager.h
@@ -37,7 +37,7 @@
#include "components/autofill/core/browser/personal_data_manager.h"
#include "components/autofill/core/browser/single_field_form_fill_router.h"
#include "components/autofill/core/browser/sync_utils.h"
-#include "components/autofill/core/browser/touch_to_fill_delegate.h"
+#include "components/autofill/core/browser/touch_to_fill_delegate_impl.h"
#include "components/autofill/core/browser/ui/popup_types.h"
#include "components/autofill/core/common/dense_set.h"
#include "components/autofill/core/common/form_data.h"
@@ -157,28 +157,31 @@ class BrowserAutofillManager : public AutofillManager,
// Called from our external delegate so they cannot be private.
// FillCreditCardForm() is also called by Autofill Assistant through
// ContentAutofillDriver::FillFormForAssistant().
+ // TODO(crbug.com/1330108): Clean up the API.
virtual void FillOrPreviewForm(mojom::RendererFormDataAction action,
int query_id,
const FormData& form,
const FormFieldData& field,
int unique_id);
- void FillCreditCardForm(int query_id,
- const FormData& form,
- const FormFieldData& field,
- const CreditCard& credit_card,
- const std::u16string& cvc) override;
+ void FillCreditCardFormImpl(const FormData& form,
+ const FormFieldData& field,
+ const CreditCard& credit_card,
+ const std::u16string& cvc,
+ int query_id) override;
void DidShowSuggestions(bool has_autofill_suggestions,
const FormData& form,
const FormFieldData& field);
// Called only from Autofill Assistant through
// ContentAutofillDriver::FillFormForAssistant().
- void FillProfileForm(const AutofillProfile& profile,
- const FormData& form,
- const FormFieldData& field) override;
+ // TODO(crbug.com/1330108): Clean up the API.
+ void FillProfileFormImpl(const FormData& form,
+ const FormFieldData& field,
+ const AutofillProfile& profile) override;
// Fetches the related virtual card information given the related actual card
// |guid| and fills the information into the form.
+ // TODO(crbug.com/1330108): Clean up the API.
virtual void FillOrPreviewVirtualCardInformation(
mojom::RendererFormDataAction action,
const std::string& guid,
@@ -238,20 +241,21 @@ class BrowserAutofillManager : public AutofillManager,
void DidSuppressPopup(const FormData& form, const FormFieldData& field);
// AutofillManager:
+ base::WeakPtr<AutofillManager> GetWeakPtr() override;
AutofillOfferManager* GetOfferManager() override;
CreditCardAccessManager* GetCreditCardAccessManager() override;
bool ShouldClearPreviewedForm() override;
- void OnFocusNoLongerOnForm(bool had_interacted_form) override;
+ void OnFocusNoLongerOnFormImpl(bool had_interacted_form) override;
void OnFocusOnFormFieldImpl(const FormData& form,
const FormFieldData& field,
const gfx::RectF& bounding_box) override;
- void OnDidFillAutofillFormData(const FormData& form,
- const base::TimeTicks timestamp) override;
- void OnDidPreviewAutofillFormData() override;
- void OnDidEndTextFieldEditing() override;
- void OnHidePopup() override;
- void SelectFieldOptionsDidChange(const FormData& form) override;
- void JavaScriptChangedAutofilledValue(
+ void OnDidFillAutofillFormDataImpl(const FormData& form,
+ const base::TimeTicks timestamp) override;
+ void OnDidPreviewAutofillFormDataImpl() override;
+ void OnDidEndTextFieldEditingImpl() override;
+ void OnHidePopupImpl() override;
+ void OnSelectFieldOptionsDidChangeImpl(const FormData& form) override;
+ void OnJavaScriptChangedAutofilledValueImpl(
const FormData& form,
const FormFieldData& field,
const std::u16string& old_value) override;
@@ -281,6 +285,12 @@ class BrowserAutofillManager : public AutofillManager,
// to be uploadable. Exposed for testing.
bool ShouldUploadForm(const FormStructure& form);
+ void SetProfileFillViaAutofillAssistantIntent(
+ const autofill_assistant::AutofillAssistantIntent intent) override;
+
+ void SetCreditCardFillViaAutofillAssistantIntent(
+ const autofill_assistant::AutofillAssistantIntent intent) override;
+
// Returns the last form the autofill manager considered in this frame.
virtual const FormData& last_query_form() const;
@@ -313,8 +323,8 @@ class BrowserAutofillManager : public AutofillManager,
external_delegate_ = std::move(external_delegate);
}
- void SetTouchToFillDelegateForTest(
- std::unique_ptr<TouchToFillDelegate> touch_to_fill_delegate) {
+ void SetTouchToFillDelegateImplForTest(
+ std::unique_ptr<TouchToFillDelegateImpl> touch_to_fill_delegate) {
touch_to_fill_delegate_ = std::move(touch_to_fill_delegate);
}
@@ -380,10 +390,10 @@ class BrowserAutofillManager : public AutofillManager,
const FormFieldData& field,
const gfx::RectF& bounding_box) override {}
void OnAskForValuesToFillImpl(
- int query_id,
const FormData& form,
const FormFieldData& field,
const gfx::RectF& transformed_box,
+ int query_id,
bool autoselect_first_suggestion,
TouchToFillEligible touch_to_fill_eligible) override;
void OnSelectControlDidChangeImpl(const FormData& form,
@@ -483,6 +493,7 @@ class BrowserAutofillManager : public AutofillManager,
// Fills or previews the credit card form.
// Assumes the form and field are valid.
+ // TODO(crbug.com/1330108): Clean up the API.
void FillOrPreviewCreditCardForm(mojom::RendererFormDataAction action,
int query_id,
const FormData& form,
@@ -491,6 +502,7 @@ class BrowserAutofillManager : public AutofillManager,
// Fills or previews the profile form.
// Assumes the form and field are valid.
+ // TODO(crbug.com/1330108): Clean up the API.
void FillOrPreviewProfileForm(mojom::RendererFormDataAction action,
int query_id,
const FormData& form,
@@ -498,6 +510,7 @@ class BrowserAutofillManager : public AutofillManager,
const AutofillProfile& profile);
// Fills or previews |data_model| in the |form|.
+ // TODO(crbug.com/1330108): Clean up the API.
void FillOrPreviewDataModelForm(
mojom::RendererFormDataAction action,
int query_id,
@@ -662,7 +675,7 @@ class BrowserAutofillManager : public AutofillManager,
// Delegates to perform external processing (display, selection) on
// our behalf.
std::unique_ptr<AutofillExternalDelegate> external_delegate_;
- std::unique_ptr<TouchToFillDelegate> touch_to_fill_delegate_;
+ std::unique_ptr<TouchToFillDelegateImpl> touch_to_fill_delegate_;
std::string app_locale_;
@@ -765,11 +778,12 @@ class BrowserAutofillManager : public AutofillManager,
friend class AutofillAssistantTest;
friend class AutofillMetricsCrossFrameFormTest;
friend class BrowserAutofillManagerTest;
- friend class AutofillMetricsTest;
friend class metrics::AutofillMetricsBaseTest;
friend class FormStructureBrowserTest;
friend class GetMatchingTypesTest;
friend class CreditCardAccessoryControllerTest;
+ FRIEND_TEST_ALL_PREFIXES(BrowserAutofillManagerTest,
+ OnCreditCardFetched_StoreInstrumentId);
};
} // namespace autofill
diff --git a/chromium/components/autofill/core/browser/browser_autofill_manager_unittest.cc b/chromium/components/autofill/core/browser/browser_autofill_manager_unittest.cc
index b287800c248..1dcdd51bebb 100644
--- a/chromium/components/autofill/core/browser/browser_autofill_manager_unittest.cc
+++ b/chromium/components/autofill/core/browser/browser_autofill_manager_unittest.cc
@@ -23,6 +23,7 @@
#include "base/metrics/metrics_hashes.h"
#include "base/strings/strcat.h"
#include "base/strings/string_number_conversions.h"
+#include "base/strings/string_piece.h"
#include "base/strings/string_util.h"
#include "base/strings/stringprintf.h"
#include "base/strings/utf_string_conversions.h"
@@ -39,6 +40,7 @@
#include "components/autofill/core/browser/autofill_test_utils.h"
#include "components/autofill/core/browser/data_model/autofill_profile.h"
#include "components/autofill/core/browser/data_model/credit_card.h"
+#include "components/autofill/core/browser/form_structure_test_api.h"
#include "components/autofill/core/browser/geo/alternative_state_name_map_test_utils.h"
#include "components/autofill/core/browser/metrics/form_events/form_events.h"
#include "components/autofill/core/browser/mock_autocomplete_history_manager.h"
@@ -52,10 +54,10 @@
#include "components/autofill/core/browser/test_autofill_download_manager.h"
#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_waiter.h"
#include "components/autofill/core/browser/test_autofill_tick_clock.h"
#include "components/autofill/core/browser/test_browser_autofill_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"
#include "components/autofill/core/browser/ui/popup_item_ids.h"
#include "components/autofill/core/browser/ui/suggestion.h"
@@ -140,6 +142,7 @@ class MockAutofillClient : public TestAutofillClient {
GetProfileType,
(),
(const override));
+ MOCK_METHOD(void, HideAutofillPopup, (PopupHidingReason reason), (override));
MOCK_METHOD(bool, IsPasswordManagerEnabled, (), (override));
};
@@ -163,17 +166,21 @@ class MockAutofillDownloadManager : public TestAutofillDownloadManager {
(override));
};
-class MockTouchToFillDelegate : public TouchToFillDelegate {
+class MockTouchToFillDelegateImpl : public TouchToFillDelegateImpl {
public:
- MockTouchToFillDelegate() = default;
- MockTouchToFillDelegate(const MockTouchToFillDelegate&) = delete;
- MockTouchToFillDelegate& operator=(const MockTouchToFillDelegate&) = delete;
- ~MockTouchToFillDelegate() override = default;
+ explicit MockTouchToFillDelegateImpl(BrowserAutofillManager* manager)
+ : TouchToFillDelegateImpl(manager) {}
+ MockTouchToFillDelegateImpl(const MockTouchToFillDelegateImpl&) = delete;
+ MockTouchToFillDelegateImpl& operator=(const MockTouchToFillDelegateImpl&) =
+ delete;
+ ~MockTouchToFillDelegateImpl() override = default;
MOCK_METHOD(bool,
TryToShowTouchToFill,
(int query_id, const FormData& form, const FormFieldData& field),
(override));
+ MOCK_METHOD(bool, IsShowingTouchToFill, (), (override));
+ MOCK_METHOD(void, HideTouchToFill, (), (override));
};
void ExpectFilledField(const char* expected_label,
@@ -397,13 +404,14 @@ class BrowserAutofillManagerTest : public testing::Test {
new TestCreditCardSaveManager(autofill_driver_.get(), &autofill_client_,
payments_client_, &personal_data());
credit_card_save_manager->SetCreditCardUploadEnabled(true);
- TestFormDataImporter* test_form_data_importer = new TestFormDataImporter(
- &autofill_client_, payments_client_,
- std::unique_ptr<CreditCardSaveManager>(credit_card_save_manager),
- &personal_data(), "en-US");
+ auto test_form_data_importer =
+ std::make_unique<autofill::TestFormDataImporter>(
+ &autofill_client_, payments_client_,
+ std::unique_ptr<CreditCardSaveManager>(credit_card_save_manager),
+ &personal_data(), "en-US");
+ test_form_data_importer_ = test_form_data_importer.get();
autofill_client_.set_test_form_data_importer(
- std::unique_ptr<autofill::TestFormDataImporter>(
- test_form_data_importer));
+ std::move(test_form_data_importer));
browser_autofill_manager_ = std::make_unique<TestBrowserAutofillManager>(
autofill_driver_.get(), &autofill_client_);
@@ -411,6 +419,12 @@ class BrowserAutofillManagerTest : public testing::Test {
std::make_unique<NiceMock<MockSingleFieldFormFillRouter>>(
autocomplete_history_manager_.get(),
merchant_promo_code_manager_.get());
+ // By default, if we offer single field form fill, suggestions should be
+ // returned because it is assumed |field.should_autocomplete| is set to
+ // true. This should be overridden in tests where
+ // |field.should_autocomplete| is set to false.
+ ON_CALL(*single_field_form_fill_router, OnGetSingleFieldSuggestions)
+ .WillByDefault(testing::Return(true));
single_field_form_fill_router_ = single_field_form_fill_router.get();
browser_autofill_manager_->set_single_field_form_fill_router_for_test(
std::move(single_field_form_fill_router));
@@ -428,9 +442,12 @@ class BrowserAutofillManagerTest : public testing::Test {
browser_autofill_manager_->SetExternalDelegateForTest(
std::move(external_delegate));
- auto touch_to_fill_delegate = std::make_unique<MockTouchToFillDelegate>();
+ auto touch_to_fill_delegate = std::make_unique<MockTouchToFillDelegateImpl>(
+ browser_autofill_manager_.get());
+ ON_CALL(*touch_to_fill_delegate, IsShowingTouchToFill())
+ .WillByDefault(Return(false));
touch_to_fill_delegate_ = touch_to_fill_delegate.get();
- browser_autofill_manager_->SetTouchToFillDelegateForTest(
+ browser_autofill_manager_->SetTouchToFillDelegateImplForTest(
std::move(touch_to_fill_delegate));
auto test_strike_database = std::make_unique<TestStrikeDatabase>();
@@ -503,7 +520,7 @@ class BrowserAutofillManagerTest : public testing::Test {
const FormData& form,
const FormFieldData& field) {
browser_autofill_manager_->OnAskForValuesToFill(
- query_id, form, field, gfx::RectF(),
+ form, field, gfx::RectF(), query_id,
/*autoselect_first_suggestion=*/false, TouchToFillEligible(false));
}
@@ -517,7 +534,7 @@ class BrowserAutofillManagerTest : public testing::Test {
const FormFieldData& field,
TouchToFillEligible touch_to_fill_eligible) {
browser_autofill_manager_->OnAskForValuesToFill(
- query_id, form, field, gfx::RectF(),
+ form, field, gfx::RectF(), query_id,
/*autoselect_first_suggestion=*/false, touch_to_fill_eligible);
}
@@ -547,6 +564,9 @@ class BrowserAutofillManagerTest : public testing::Test {
const FormData& form,
const FormFieldData& field,
int unique_id) {
+ browser_autofill_manager_->OnAskForValuesToFill(
+ form, field, {}, query_id, /*autoselect_first_suggestion=*/true,
+ TouchToFillEligible(false));
browser_autofill_manager_->FillOrPreviewForm(
mojom::RendererFormDataAction::kFill, query_id, form, field, unique_id);
}
@@ -662,8 +682,9 @@ class BrowserAutofillManagerTest : public testing::Test {
const std::string& real_pan,
bool is_virtual_card = false) {
payments::FullCardRequest* full_card_request =
- browser_autofill_manager_->credit_card_access_manager_
- ->cvc_authenticator_->full_card_request_.get();
+ browser_autofill_manager_->client()
+ ->GetCVCAuthenticator()
+ ->full_card_request_.get();
DCHECK(full_card_request);
// Mock user response.
@@ -683,8 +704,8 @@ class BrowserAutofillManagerTest : public testing::Test {
// Convenience method to cast the FullCardRequest into a CardUnmaskDelegate.
CardUnmaskDelegate* full_card_unmask_delegate() {
payments::FullCardRequest* full_card_request =
- browser_autofill_manager_->credit_card_access_manager_
- ->GetOrCreateCVCAuthenticator()
+ browser_autofill_manager_->client()
+ ->GetCVCAuthenticator()
->full_card_request_.get();
DCHECK(full_card_request);
return static_cast<CardUnmaskDelegate*>(full_card_request);
@@ -761,7 +782,7 @@ class BrowserAutofillManagerTest : public testing::Test {
std::unique_ptr<MockAutofillDriver> autofill_driver_;
std::unique_ptr<TestBrowserAutofillManager> browser_autofill_manager_;
raw_ptr<TestAutofillExternalDelegate> external_delegate_;
- raw_ptr<MockTouchToFillDelegate> touch_to_fill_delegate_;
+ raw_ptr<MockTouchToFillDelegateImpl> touch_to_fill_delegate_;
scoped_refptr<AutofillWebDataService> database_;
raw_ptr<MockAutofillDownloadManager> download_manager_;
std::unique_ptr<MockAutocompleteHistoryManager> autocomplete_history_manager_;
@@ -770,6 +791,7 @@ class BrowserAutofillManagerTest : public testing::Test {
base::test::ScopedFeatureList scoped_feature_list_;
raw_ptr<TestStrikeDatabase> strike_database_;
raw_ptr<payments::TestPaymentsClient> payments_client_;
+ raw_ptr<TestFormDataImporter> test_form_data_importer_;
private:
int ToHistogramSample(AutofillMetrics::CardUploadDecisionMetric metric) {
@@ -859,9 +881,14 @@ class BrowserAutofillManagerStructuredProfileTest
void BrowserAutofillManagerStructuredProfileTest::InitializeFeatures() {
structured_names_and_addresses_ = GetParam();
+ // The BrowserAutofillManagerStructuredProfileTest test suite will run every
+ // test once with these flags on, and once with these flags off.
std::vector<base::Feature> features = {
features::kAutofillEnableSupportForMoreStructureInAddresses,
- features::kAutofillEnableSupportForMoreStructureInNames};
+ features::kAutofillEnableSupportForMoreStructureInNames,
+ // TODO(crbug.com/1190334): Remove this feature flag once the GPay
+ // activated promo code autofill project is fully launched and stable.
+ features::kAutofillFillMerchantPromoCodeFields};
if (structured_names_and_addresses_) {
scoped_features_.InitWithFeatures(features, {});
} else {
@@ -1105,9 +1132,9 @@ TEST_P(BrowserAutofillManagerStructuredProfileTest,
std::vector<FormData> forms(1, form);
FormsSeen(forms);
- // Ensure that the single field form fill router is not called for
+ // Ensure that the SingleFieldFormFillRouter is not called for
// suggestions either.
- EXPECT_CALL(*(single_field_form_fill_router_), OnGetSingleFieldSuggestions)
+ EXPECT_CALL(*single_field_form_fill_router_, OnGetSingleFieldSuggestions)
.Times(0);
// Suggestions should be returned for the first two fields.
@@ -1141,8 +1168,8 @@ TEST_P(BrowserAutofillManagerStructuredProfileTest,
std::vector<FormData> forms(1, form);
FormsSeen(forms);
- // Ensure that the single field form fill router is called for both fields.
- EXPECT_CALL(*(single_field_form_fill_router_), OnGetSingleFieldSuggestions)
+ // Ensure that the SingleFieldFormFillRouter is called for both fields.
+ EXPECT_CALL(*single_field_form_fill_router_, OnGetSingleFieldSuggestions)
.Times(2);
GetAutofillSuggestions(form, form.fields[0]);
@@ -1838,7 +1865,7 @@ TEST_P(BrowserAutofillManagerStructuredProfileTest,
browser_autofill_manager_->ShouldShowCreditCardSigninPromo(form, field));
// Single field form fill suggestions are not queried.
- EXPECT_CALL(*(single_field_form_fill_router_), OnGetSingleFieldSuggestions)
+ EXPECT_CALL(*single_field_form_fill_router_, OnGetSingleFieldSuggestions)
.Times(0);
GetAutofillSuggestions(form, field);
@@ -2363,6 +2390,26 @@ TEST_F(BrowserAutofillManagerTest,
browser_autofill_manager_->GetPackedCreditCardID(1)));
}
+TEST_F(BrowserAutofillManagerTest, OnCreditCardFetched_StoreInstrumentId) {
+ FormData form;
+ CreateTestCreditCardFormData(&form, true, false);
+ std::vector<FormData> forms(1, form);
+ FormsSeen(forms);
+ CreditCard credit_card = test::GetMaskedServerCard();
+ browser_autofill_manager_->FillOrPreviewCreditCardForm(
+ mojom::RendererFormDataAction::kFill, kDefaultPageID, form,
+ form.fields[0], &credit_card);
+
+ browser_autofill_manager_->OnCreditCardFetched(
+ CreditCardFetchResult::kSuccess, &credit_card,
+ /*cvc=*/u"123");
+
+ ASSERT_TRUE(
+ test_form_data_importer_->fetched_card_instrument_id().has_value());
+ EXPECT_EQ(test_form_data_importer_->fetched_card_instrument_id().value(),
+ credit_card.instrument_id());
+}
+
// Test that we return profile and credit card suggestions for combined forms.
TEST_P(SuggestionMatchingTest, GetAddressAndCreditCardSuggestions) {
// Set up our form data.
@@ -2750,8 +2797,7 @@ TEST_P(BrowserAutofillManagerLogAblationTest, TestLogging) {
DisableAutofillViaAblation(scoped_feature_list_, /*for_addresses=*/true,
/*for_credit_cards=*/true);
- TestAutofillTickClock clock;
- clock.SetNowTicks(base::TimeTicks::Now());
+ TestAutofillTickClock clock(AutofillTickClock::NowTicks());
base::HistogramTester histogram_tester;
// Set up our form data. In the kMixed case the form will contain the fields
@@ -2950,26 +2996,9 @@ TEST_F(BrowserAutofillManagerTest, DetermineStateFieldTypeForUpload) {
EXPECT_TRUE(form_structure.field(1)->state_is_a_matching_type());
}
-// Test fixture which enables
-// features::kAutofillFixServerQueriesIfPasswordManagerIsEnabled.
-// TODO(crbug.com/1293341) Once enabled by default, delete this test
-// fixture and use BrowserAutofillManagerTest in the test below.
-class BrowserAutofillManagerTestWithFixForQueries
- : public BrowserAutofillManagerTest {
- public:
- BrowserAutofillManagerTestWithFixForQueries() {
- features_.InitAndEnableFeature(
- features::kAutofillFixServerQueriesIfPasswordManagerIsEnabled);
- }
- ~BrowserAutofillManagerTestWithFixForQueries() override = default;
-
- private:
- base::test::ScopedFeatureList features_;
-};
-
// Ensures that if autofill is disabled but the password manager is enabled,
// Autofill still performs a lookup to the server.
-TEST_F(BrowserAutofillManagerTestWithFixForQueries,
+TEST_F(BrowserAutofillManagerTest,
OnFormsSeen_AutofillDisabledPasswordManagerEnabled) {
// Set up our form data.
FormData form;
@@ -4742,12 +4771,15 @@ TEST_P(BrowserAutofillManagerStructuredProfileTest, FillPhoneNumber) {
// In one form, rely on the max length attribute to imply US phone number
// parts. In the other form, rely on the autocomplete type attribute.
FormData form_with_us_number_max_length;
+ form_with_us_number_max_length.unique_renderer_id =
+ test::MakeFormRendererId();
form_with_us_number_max_length.name = u"MyMaxlengthPhoneForm";
form_with_us_number_max_length.url =
GURL("https://myform.com/phone_form.html");
form_with_us_number_max_length.action =
GURL("https://myform.com/phone_submit.html");
FormData form_with_autocompletetype = form_with_us_number_max_length;
+ form_with_autocompletetype.unique_renderer_id = test::MakeFormRendererId();
form_with_autocompletetype.name = u"MyAutocompletetypePhoneForm";
struct {
@@ -4819,10 +4851,7 @@ TEST_P(BrowserAutofillManagerStructuredProfileTest, FillPhoneNumber) {
EXPECT_EQ(u"4567", response_data2.fields[3].value);
EXPECT_EQ(std::u16string(), response_data2.fields[4].value);
- // We should not be able to fill international numbers correctly in a form
- // containing fields with US max_length. However, the field should fill with
- // the number of digits equal to the max length specified, starting from the
- // right.
+ // For other countries, fill prefix and suffix fields with best effort.
work_profile->SetRawInfo(ADDRESS_HOME_COUNTRY, u"GB");
work_profile->SetRawInfo(PHONE_HOME_WHOLE_NUMBER, u"447700954321");
page_id = 3;
@@ -4837,7 +4866,7 @@ TEST_P(BrowserAutofillManagerStructuredProfileTest, FillPhoneNumber) {
ASSERT_EQ(5U, response_data3.fields.size());
EXPECT_EQ(u"4", response_data3.fields[0].value);
EXPECT_EQ(u"700", response_data3.fields[1].value);
- EXPECT_EQ(u"321", response_data3.fields[2].value);
+ EXPECT_EQ(u"95", response_data3.fields[2].value);
EXPECT_EQ(u"4321", response_data3.fields[3].value);
EXPECT_EQ(std::u16string(), response_data3.fields[4].value);
@@ -4853,8 +4882,8 @@ TEST_P(BrowserAutofillManagerStructuredProfileTest, FillPhoneNumber) {
ASSERT_EQ(5U, response_data4.fields.size());
EXPECT_EQ(u"44", response_data4.fields[0].value);
EXPECT_EQ(u"7700", response_data4.fields[1].value);
- EXPECT_EQ(u"954321", response_data4.fields[2].value);
- EXPECT_EQ(u"954321", response_data4.fields[3].value);
+ EXPECT_EQ(u"95", response_data4.fields[2].value);
+ EXPECT_EQ(u"4321", response_data4.fields[3].value);
EXPECT_EQ(std::u16string(), response_data4.fields[4].value);
}
@@ -4870,6 +4899,8 @@ TEST_P(BrowserAutofillManagerStructuredProfileTest,
// 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.unique_renderer_id =
+ test::MakeFormRendererId();
form_with_multiple_componentized_phone_fields.url =
GURL("https://www.foo.com/");
@@ -4936,6 +4967,8 @@ TEST_P(BrowserAutofillManagerStructuredProfileTest,
std::string guid(work_profile->guid());
FormData form_with_multiple_whole_number_fields;
+ form_with_multiple_whole_number_fields.unique_renderer_id =
+ test::MakeFormRendererId();
form_with_multiple_whole_number_fields.url = GURL("https://www.foo.com/");
FormFieldData field;
@@ -4988,6 +5021,8 @@ TEST_P(BrowserAutofillManagerStructuredProfileTest,
// 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.unique_renderer_id =
+ test::MakeFormRendererId();
form_with_multiple_componentized_phone_fields.url =
GURL("https://www.foo.com/");
@@ -5059,6 +5094,8 @@ TEST_P(BrowserAutofillManagerStructuredProfileTest,
std::string guid(work_profile->guid());
FormData form_with_misclassified_extension;
+ form_with_misclassified_extension.unique_renderer_id =
+ test::MakeFormRendererId();
form_with_misclassified_extension.url = GURL("https://www.foo.com/");
FormFieldData field;
@@ -5122,6 +5159,7 @@ TEST_P(BrowserAutofillManagerStructuredProfileTest,
std::string guid(work_profile->guid());
FormData form_with_no_complete_number;
+ form_with_no_complete_number.unique_renderer_id = test::MakeFormRendererId();
form_with_no_complete_number.url = GURL("https://www.foo.com/");
FormFieldData field;
@@ -5179,6 +5217,8 @@ TEST_P(BrowserAutofillManagerStructuredProfileTest,
std::string guid(work_profile->guid());
FormData form_with_multiple_whole_number_fields;
+ form_with_multiple_whole_number_fields.unique_renderer_id =
+ test::MakeFormRendererId();
form_with_multiple_whole_number_fields.url = GURL("https://www.foo.com/");
FormFieldData field;
@@ -5232,6 +5272,8 @@ TEST_P(BrowserAutofillManagerStructuredProfileTest,
std::string guid(work_profile->guid());
FormData form_with_multiple_whole_number_fields;
+ form_with_multiple_whole_number_fields.unique_renderer_id =
+ test::MakeFormRendererId();
form_with_multiple_whole_number_fields.url = GURL("https://www.foo.com/");
FormFieldData field;
@@ -5280,6 +5322,7 @@ TEST_P(BrowserAutofillManagerStructuredProfileTest,
TEST_P(BrowserAutofillManagerStructuredProfileTest,
FormWithHiddenOrPresentationalSelects) {
FormData form;
+ form.unique_renderer_id = test::MakeFormRendererId();
form.name = u"MyForm";
form.url = GURL("https://myform.com/form.html");
form.action = GURL("https://myform.com/submit.html");
@@ -5356,6 +5399,7 @@ TEST_P(BrowserAutofillManagerStructuredProfileTest,
std::string guid(work_profile->guid());
FormData form_with_multiple_sections;
+ form_with_multiple_sections.unique_renderer_id = test::MakeFormRendererId();
form_with_multiple_sections.url = GURL("https://www.foo.com/");
FormFieldData field;
@@ -5448,12 +5492,13 @@ TEST_P(BrowserAutofillManagerStructuredProfileTest, FormChangesRemoveField) {
test::CreateTestFormField("Some", "field", "", "text", &field);
form.fields.insert(form.fields.begin() + 3, field);
- std::vector<FormData> forms(1, form);
- FormsSeen(forms);
+ FormsSeen({form});
// Now, after the call to |FormsSeen|, we remove the field before filling.
form.fields.erase(form.fields.begin() + 3);
+ FormsSeen({form});
+
const char guid[] = "00000000-0000-0000-0000-000000000001";
int response_page_id = 0;
FormData response_data;
@@ -5484,6 +5529,8 @@ TEST_P(BrowserAutofillManagerStructuredProfileTest, FormChangesAddField) {
// Now, after the call to |FormsSeen|, we restore the field before filling.
form.fields.insert(pos, field);
+ FormsSeen({form});
+
const char guid[] = "00000000-0000-0000-0000-000000000001";
int response_page_id = 0;
FormData response_data;
@@ -5500,6 +5547,7 @@ TEST_P(BrowserAutofillManagerStructuredProfileTest,
FormChangesVisibilityOfFields) {
// Set up our form data.
FormData form;
+ form.unique_renderer_id = test::MakeFormRendererId();
form.url = GURL("https://www.foo.com/");
FormFieldData field;
@@ -5551,6 +5599,7 @@ TEST_P(BrowserAutofillManagerStructuredProfileTest,
// the right fields are getting filled.)
response_data.fields[3].is_focusable = true;
response_data.fields[4].is_focusable = true;
+
FormData later_response_data;
const char guid2[] = "00000000-0000-0000-0000-000000000002";
FillAutofillFormDataAndSaveResults(kDefaultPageID, response_data,
@@ -5628,7 +5677,7 @@ TEST_P(BrowserAutofillManagerStructuredProfileTest,
FormData form;
test::CreateTestAddressFormData(&form);
- EXPECT_CALL(*(single_field_form_fill_router_), OnWillSubmitForm(_, _, true));
+ EXPECT_CALL(*single_field_form_fill_router_, OnWillSubmitForm(_, _, true));
FormSubmitted(form);
}
@@ -5662,7 +5711,7 @@ TEST_P(BrowserAutofillManagerStructuredProfileTest, ValuePatternsMetric) {
}
// Test that when Autofill is disabled, single field form fill suggestions are
-// still queried.
+// still queried as a fallback.
TEST_P(BrowserAutofillManagerStructuredProfileTest,
SingleFieldFormFillSuggestions_SomeWhenAutofillDisabled) {
browser_autofill_manager_->SetAutofillProfileEnabled(false);
@@ -5681,39 +5730,14 @@ TEST_P(BrowserAutofillManagerStructuredProfileTest,
FormsSeen(forms);
const FormFieldData& field = form.fields[0];
- // Expect the single field form fill router to be called for suggestions.
- EXPECT_CALL(*(single_field_form_fill_router_), OnGetSingleFieldSuggestions);
+ // Expect the SingleFieldFormFillRouter to be called for suggestions.
+ EXPECT_CALL(*single_field_form_fill_router_, OnGetSingleFieldSuggestions);
GetAutofillSuggestions(form, field);
-}
-
-// Test that when Autofill is disabled and the field should not autocomplete,
-// single field form fill suggestions are not queried.
-TEST_P(
- BrowserAutofillManagerStructuredProfileTest,
- SingleFieldFormFillSuggestions_AutofillDisabledAndFieldShouldNotAutocomplete) {
- browser_autofill_manager_->SetAutofillProfileEnabled(false);
- browser_autofill_manager_->SetAutofillCreditCardEnabled(false);
- auto external_delegate = std::make_unique<TestAutofillExternalDelegate>(
- browser_autofill_manager_.get(), autofill_driver_.get(),
- /*call_parent_methods=*/false);
- external_delegate_ = external_delegate.get();
- browser_autofill_manager_->SetExternalDelegateForTest(
- std::move(external_delegate));
- // Set up our form data.
- FormData form;
- test::CreateTestAddressFormData(&form);
- std::vector<FormData> forms(1, form);
- FormsSeen(forms);
- FormFieldData field = form.fields[0];
- field.should_autocomplete = false;
-
- // Single field form fill router is not called for suggestions.
- EXPECT_CALL(*(single_field_form_fill_router_), OnGetSingleFieldSuggestions)
- .Times(0);
-
- GetAutofillSuggestions(form, field);
+ // Single field form fill suggestions were returned, so we should not go
+ // through the normal autofill flow.
+ EXPECT_FALSE(external_delegate_->on_suggestions_returned_seen());
}
// Test that we do not query for single field form fill suggestions when there
@@ -5727,8 +5751,8 @@ TEST_P(BrowserAutofillManagerStructuredProfileTest,
FormsSeen(forms);
const FormFieldData& field = form.fields[0];
- // Single field form fill router is not called for suggestions.
- EXPECT_CALL(*(single_field_form_fill_router_), OnGetSingleFieldSuggestions)
+ // SingleFieldFormFillRouter is not called for suggestions.
+ EXPECT_CALL(*single_field_form_fill_router_, OnGetSingleFieldSuggestions)
.Times(0);
GetAutofillSuggestions(form, field);
@@ -5752,7 +5776,7 @@ TEST_P(BrowserAutofillManagerStructuredProfileTest,
// Single field form fill manager is called for suggestions because Autofill
// is empty.
- EXPECT_CALL(*(single_field_form_fill_router_), OnGetSingleFieldSuggestions);
+ EXPECT_CALL(*single_field_form_fill_router_, OnGetSingleFieldSuggestions);
GetAutofillSuggestions(form, field);
}
@@ -5787,8 +5811,8 @@ TEST_P(BrowserAutofillManagerStructuredProfileTest,
FormFieldData field = form.fields[0];
field.should_autocomplete = true;
- // Single field form fill router is not called for suggestions.
- EXPECT_CALL(*(single_field_form_fill_router_), OnGetSingleFieldSuggestions);
+ // SingleFieldFormFillRouter is called for suggestions.
+ EXPECT_CALL(*single_field_form_fill_router_, OnGetSingleFieldSuggestions);
GetAutofillSuggestions(form, field);
}
@@ -5823,19 +5847,20 @@ TEST_P(BrowserAutofillManagerStructuredProfileTest,
FormFieldData field = form.fields[1];
field.should_autocomplete = true;
- // Single field form fill router is not called for suggestions.
- EXPECT_CALL(*(single_field_form_fill_router_), OnGetSingleFieldSuggestions)
+ // SingleFieldFormFillRouter is not called for suggestions.
+ EXPECT_CALL(*single_field_form_fill_router_, OnGetSingleFieldSuggestions)
.Times(0);
GetAutofillSuggestions(form, field);
}
-// Test that we do not query for single field form fill suggestions when there
-// are no Autofill suggestions available, and that the field should not
-// autocomplete.
+// Test that the situation where there are no Autofill suggestions available,
+// and no single field form fill conditions were met is correctly handled. The
+// single field form fill conditions were not met because autocomplete is set to
+// off and the field is not recognized as a promo code field.
TEST_F(
BrowserAutofillManagerTest,
- SingleFieldFormFillSuggestions_NoneWhenAutofillEmptyFieldShouldNotAutocomplete) {
+ SingleFieldFormFillSuggestions_NoneWhenAutofillEmptyAndSingleFieldFormFillConditionsNotMet) {
// Set up our form data.
FormData form;
test::CreateTestAddressFormData(&form);
@@ -5847,15 +5872,25 @@ TEST_F(
field.should_autocomplete = false;
test::CreateTestFormField("Email", "email", "donkey", "email", &field);
- // Single field form fill router is not called for suggestions.
- EXPECT_CALL(*(single_field_form_fill_router_), OnGetSingleFieldSuggestions)
- .Times(0);
+ // Autocomplete is set to off, so suggestions should not get returned from
+ // |single_field_form_fill_router_|.
+ EXPECT_CALL(*single_field_form_fill_router_, OnGetSingleFieldSuggestions)
+ .WillRepeatedly(testing::Return(false));
GetAutofillSuggestions(form, field);
+
+ // Single field form fill was not triggered, so go through the normal autofill
+ // flow.
+ EXPECT_TRUE(external_delegate_->on_suggestions_returned_seen());
}
-TEST_P(BrowserAutofillManagerStructuredProfileTest,
- AutocompleteOffRespectedForSingleFieldFormFill) {
+// Test that the situation where no single field form fill conditions were met
+// is handled correctly. The single field form fill conditions were not met
+// because autocomplete is set to off and the field is not recognized as a promo
+// code field.
+TEST_P(
+ BrowserAutofillManagerStructuredProfileTest,
+ SingleFieldFormFillSuggestions_NoneWhenSingleFieldFormFillConditionsNotMet) {
browser_autofill_manager_->SetAutofillProfileEnabled(false);
browser_autofill_manager_->SetAutofillCreditCardEnabled(false);
auto external_delegate = std::make_unique<TestAutofillExternalDelegate>(
@@ -5865,9 +5900,6 @@ TEST_P(BrowserAutofillManagerStructuredProfileTest,
browser_autofill_manager_->SetExternalDelegateForTest(
std::move(external_delegate));
- EXPECT_CALL(*(single_field_form_fill_router_), OnGetSingleFieldSuggestions)
- .Times(0);
-
// Set up our form data.
FormData form;
test::CreateTestAddressFormData(&form);
@@ -5875,12 +5907,22 @@ TEST_P(BrowserAutofillManagerStructuredProfileTest,
FormsSeen(forms);
FormFieldData* field = &form.fields[0];
field->should_autocomplete = false;
+
+ // Autocomplete is set to off, so suggestions should not get returned from
+ // |single_field_form_fill_router_|.
+ EXPECT_CALL(*single_field_form_fill_router_, OnGetSingleFieldSuggestions)
+ .WillRepeatedly(testing::Return(false));
+
GetAutofillSuggestions(form, *field);
+
+ // Single field form fill was not triggered, so go through the normal autofill
+ // flow.
+ EXPECT_TRUE(external_delegate_->on_suggestions_returned_seen());
}
TEST_P(BrowserAutofillManagerStructuredProfileTest,
DestructorCancelsSingleFieldFormFillQueries) {
- EXPECT_CALL(*(single_field_form_fill_router_), CancelPendingQueries).Times(1);
+ EXPECT_CALL(*single_field_form_fill_router_, CancelPendingQueries).Times(1);
browser_autofill_manager_.reset();
}
@@ -5919,9 +5961,9 @@ TEST_P(BrowserAutofillManagerStructuredProfileTest,
form.fields.push_back(field);
// Simulate having seen this form on page load.
// |form_structure_instance| will be owned by |browser_autofill_manager_|.
- auto form_structure_instance = std::make_unique<TestFormStructure>(form);
+ auto form_structure_instance = std::make_unique<FormStructure>(form);
// This pointer is valid as long as autofill manager lives.
- TestFormStructure* form_structure = form_structure_instance.get();
+ FormStructure* form_structure = form_structure_instance.get();
form_structure->DetermineHeuristicTypes(nullptr, nullptr);
browser_autofill_manager_->AddSeenFormStructure(
std::move(form_structure_instance));
@@ -5939,9 +5981,9 @@ TEST_P(BrowserAutofillManagerStructuredProfileTest,
form2.fields.push_back(field);
test::CreateTestFormField("Postal Code", "zipcode", "", "text", &field);
form2.fields.push_back(field);
- auto form_structure_instance2 = std::make_unique<TestFormStructure>(form2);
+ auto form_structure_instance2 = std::make_unique<FormStructure>(form2);
// This pointer is valid as long as autofill manager lives.
- TestFormStructure* form_structure2 = form_structure_instance2.get();
+ FormStructure* form_structure2 = form_structure_instance2.get();
form_structure2->DetermineHeuristicTypes(nullptr, nullptr);
browser_autofill_manager_->AddSeenFormStructure(
std::move(form_structure_instance2));
@@ -6013,12 +6055,11 @@ TEST_P(BrowserAutofillManagerStructuredProfileTest,
// Simulate having seen this form on page load.
// |form_structure| will be owned by |browser_autofill_manager_|.
- TestFormStructure* form_structure = new TestFormStructure(form);
+ auto form_structure = std::make_unique<FormStructure>(form);
form_structure->DetermineHeuristicTypes(nullptr, nullptr);
std::vector<FormSignature> signatures =
test::GetEncodedSignatures(*form_structure);
- browser_autofill_manager_->AddSeenFormStructure(
- std::unique_ptr<TestFormStructure>(form_structure));
+ browser_autofill_manager_->AddSeenFormStructure(std::move(form_structure));
AutofillQueryResponse response;
auto* form_suggestion = response.add_form_suggestions();
@@ -6073,10 +6114,13 @@ TEST_P(BrowserAutofillManagerStructuredProfileTest,
// Simulate having seen this form on page load.
// |form_structure| will be owned by |browser_autofill_manager_|.
- TestFormStructure* form_structure = new TestFormStructure(form);
- form_structure->DetermineHeuristicTypes(nullptr, nullptr);
- browser_autofill_manager_->AddSeenFormStructure(
- std::unique_ptr<TestFormStructure>(form_structure));
+ FormStructure* form_structure = [&] {
+ auto form_structure = std::make_unique<FormStructure>(form);
+ FormStructure* ptr = form_structure.get();
+ form_structure->DetermineHeuristicTypes(nullptr, nullptr);
+ browser_autofill_manager_->AddSeenFormStructure(std::move(form_structure));
+ return ptr;
+ }();
AutofillQueryResponse response;
auto* form_suggestion = response.add_form_suggestions();
@@ -6147,7 +6191,7 @@ TEST_P(BrowserAutofillManagerStructuredProfileTest, FormSubmittedServerTypes) {
// Simulate having seen this form on page load.
// |form_structure| will be owned by |browser_autofill_manager_|.
- TestFormStructure* form_structure = new TestFormStructure(form);
+ auto form_structure = std::make_unique<FormStructure>(form);
form_structure->DetermineHeuristicTypes(nullptr, nullptr);
// Clear the heuristic types, and instead set the appropriate server types.
@@ -6156,9 +6200,9 @@ TEST_P(BrowserAutofillManagerStructuredProfileTest, FormSubmittedServerTypes) {
heuristic_types.push_back(UNKNOWN_TYPE);
server_types.push_back(form_structure->field(i)->heuristic_type());
}
- form_structure->SetFieldTypes(heuristic_types, server_types);
- browser_autofill_manager_->AddSeenFormStructure(
- std::unique_ptr<TestFormStructure>(form_structure));
+ FormStructureTestApi(form_structure.get())
+ .SetFieldTypes(heuristic_types, server_types);
+ browser_autofill_manager_->AddSeenFormStructure(std::move(form_structure));
// Fill the form.
const char guid[] = "00000000-0000-0000-0000-000000000001";
@@ -6363,8 +6407,8 @@ const ProfileMatchingTypesTestCase kProfileMatchingTypesTestCases[] = {
{"1", {PHONE_HOME_COUNTRY_CODE}, {PHONE_HOME_COUNTRY_CODE}},
{"234", {PHONE_HOME_CITY_CODE}, {PHONE_HOME_CITY_CODE}},
{"5678901", {PHONE_HOME_NUMBER}, {PHONE_HOME_NUMBER}},
- {"567", {PHONE_HOME_NUMBER}, {PHONE_HOME_NUMBER}},
- {"8901", {PHONE_HOME_NUMBER}, {PHONE_HOME_NUMBER}},
+ {"567", {PHONE_HOME_NUMBER_PREFIX}, {PHONE_HOME_NUMBER_PREFIX}},
+ {"8901", {PHONE_HOME_NUMBER_SUFFIX}, {PHONE_HOME_NUMBER_SUFFIX}},
// Test a European profile.
{"Paris", {ADDRESS_HOME_CITY}, {ADDRESS_HOME_CITY}},
@@ -7392,7 +7436,7 @@ TEST_P(BrowserAutofillManagerStructuredProfileTest,
TEST_P(BrowserAutofillManagerStructuredProfileTest,
DontSaveCvcInAutocompleteHistory) {
FormData form_seen_by_ahm;
- EXPECT_CALL(*(single_field_form_fill_router_), OnWillSubmitForm(_, _, true))
+ EXPECT_CALL(*single_field_form_fill_router_, OnWillSubmitForm(_, _, true))
.WillOnce(SaveArg<0>(&form_seen_by_ahm));
FormData form;
@@ -8081,8 +8125,7 @@ TEST_P(BrowserAutofillManagerStructuredProfileTest,
}
// Verify that suggestions are shown on desktop for credit card related fields
-// even if the initiating field field has the "autocomplete" attribute set to
-// off.
+// even if the initiating field has the "autocomplete" attribute set to off.
TEST_P(BrowserAutofillManagerStructuredProfileTest,
DisplaySuggestions_AutocompleteOff_CreditCardField) {
// Set up a credit card form.
@@ -8107,7 +8150,15 @@ TEST_P(BrowserAutofillManagerStructuredProfileTest,
// Suggestions should always be displayed.
for (const FormFieldData& mixed_form_field : mixed_form.fields) {
+ // Single field form fill suggestions being returned are directly correlated
+ // to whether or not the field has autocomplete set to true or false. We
+ // know autocomplete must be the single field form filler in this case due
+ // to the field not having a type that would route to any of the other
+ // single field form fillers.
+ ON_CALL(*single_field_form_fill_router_, OnGetSingleFieldSuggestions)
+ .WillByDefault(testing::Return(mixed_form_field.should_autocomplete));
GetAutofillSuggestions(mixed_form, mixed_form_field);
+
EXPECT_TRUE(external_delegate_->on_suggestions_returned_seen());
}
}
@@ -8130,7 +8181,7 @@ TEST_P(BrowserAutofillManagerStructuredProfileTest,
test::CreateTestFormField("Field 3", "field3", "", "text", &field);
form.fields.push_back(field);
- auto form_structure = std::make_unique<TestFormStructure>(form);
+ auto form_structure = std::make_unique<FormStructure>(form);
form_structure->DetermineHeuristicTypes(nullptr, nullptr);
// Make sure the form can not be autofilled now.
ASSERT_EQ(0u, form_structure->autofill_count());
@@ -8143,7 +8194,8 @@ TEST_P(BrowserAutofillManagerStructuredProfileTest,
UNKNOWN_TYPE);
const std::vector<ServerFieldType> server_types{NAME_FIRST, NAME_MIDDLE,
NAME_LAST};
- form_structure->SetFieldTypes(heuristic_types, server_types);
+ FormStructureTestApi(form_structure.get())
+ .SetFieldTypes(heuristic_types, server_types);
browser_autofill_manager_->AddSeenFormStructure(std::move(form_structure));
// Make sure the form can be autofilled.
@@ -8248,10 +8300,6 @@ TEST_P(BrowserAutofillManagerStructuredProfileTest,
TEST_P(BrowserAutofillManagerStructuredProfileTest,
GetCreditCardSuggestions_VirtualCard) {
- base::test::ScopedFeatureList scoped_feature_list;
- scoped_feature_list.InitAndDisableFeature(
- features::kAutofillSuggestVirtualCardsOnIncompleteForm);
-
personal_data().ClearCreditCards();
CreditCard masked_server_card(CreditCard::MASKED_SERVER_CARD,
/*server_id=*/"a123");
@@ -8320,7 +8368,7 @@ TEST_P(BrowserAutofillManagerStructuredProfileTest,
GetAutofillSuggestions(form, field);
CheckSuggestions(
- kDefaultPageID,
+ kDefaultPageID, virtual_card_suggestion,
Suggestion("Elvis Presley", label, kVisaCard,
browser_autofill_manager_->GetPackedCreditCardID(7)));
}
@@ -8333,6 +8381,7 @@ TEST_P(BrowserAutofillManagerStructuredProfileTest,
FormFieldData field;
test::CreateTestFormField("Something", "something", "", "text", &field);
form.fields.push_back(field);
+ FormsSeen({form});
base::HistogramTester histogram_tester;
browser_autofill_manager_->DidShowSuggestions(
@@ -8353,6 +8402,7 @@ TEST_P(BrowserAutofillManagerStructuredProfileTest,
DidShowSuggestions_LogAutofillAddressShownMetric) {
FormData form;
test::CreateTestAddressFormData(&form);
+ FormsSeen({form});
base::HistogramTester histogram_tester;
browser_autofill_manager_->DidShowSuggestions(
@@ -8398,6 +8448,7 @@ TEST_P(BrowserAutofillManagerStructuredProfileTest,
form.fields.push_back(field);
test::CreateTestFormField("Address Line 1", "addr1", "", "text", &field);
form.fields.push_back(field);
+ FormsSeen({form});
base::HistogramTester histogram_tester;
browser_autofill_manager_->DidShowSuggestions(
@@ -8442,6 +8493,7 @@ TEST_P(BrowserAutofillManagerStructuredProfileTest,
form.fields.push_back(field);
test::CreateTestFormField("Postal Code", "zipcode", "", "text", &field);
form.fields.push_back(field);
+ FormsSeen({form});
base::HistogramTester histogram_tester;
browser_autofill_manager_->DidShowSuggestions(
@@ -8486,6 +8538,7 @@ TEST_P(BrowserAutofillManagerStructuredProfileTest,
form.fields.push_back(field);
test::CreateTestFormField("Email", "email", "", "email", &field);
form.fields.push_back(field);
+ FormsSeen({form});
base::HistogramTester histogram_tester;
browser_autofill_manager_->DidShowSuggestions(
@@ -8529,6 +8582,7 @@ TEST_P(BrowserAutofillManagerStructuredProfileTest,
form.fields.push_back(field);
test::CreateTestFormField("Email", "email", "", "email", &field);
form.fields.push_back(field);
+ FormsSeen({form});
base::HistogramTester histogram_tester;
browser_autofill_manager_->DidShowSuggestions(
@@ -8572,6 +8626,7 @@ TEST_P(BrowserAutofillManagerStructuredProfileTest,
form.fields.push_back(field);
test::CreateTestFormField("Phone Number", "phonenumber", "", "tel", &field);
form.fields.push_back(field);
+ FormsSeen({form});
base::HistogramTester histogram_tester;
browser_autofill_manager_->DidShowSuggestions(
@@ -8615,6 +8670,7 @@ TEST_P(BrowserAutofillManagerStructuredProfileTest,
form.fields.push_back(field);
test::CreateTestFormField("Last Name", "lastname", "", "text", &field);
form.fields.push_back(field);
+ FormsSeen({form});
base::HistogramTester histogram_tester;
browser_autofill_manager_->DidShowSuggestions(
@@ -8660,6 +8716,7 @@ TEST_P(BrowserAutofillManagerStructuredProfileTest,
form.fields.push_back(field);
test::CreateTestFormField("Email", "email", "", "email", &field);
form.fields.push_back(field);
+ FormsSeen({form});
base::HistogramTester histogram_tester;
browser_autofill_manager_->DidShowSuggestions(
@@ -8710,6 +8767,7 @@ TEST_P(BrowserAutofillManagerStructuredProfileTest,
form.fields.push_back(field);
test::CreateTestFormField("Email", "email", "", "email", &field);
form.fields.push_back(field);
+ FormsSeen({form});
base::HistogramTester histogram_tester;
browser_autofill_manager_->DidShowSuggestions(
@@ -8762,6 +8820,7 @@ TEST_P(BrowserAutofillManagerStructuredProfileTest,
form.fields.push_back(field);
test::CreateTestFormField("Phone Number", "phonenumber", "", "tel", &field);
form.fields.push_back(field);
+ FormsSeen({form});
base::HistogramTester histogram_tester;
browser_autofill_manager_->DidShowSuggestions(
@@ -8812,6 +8871,7 @@ TEST_P(BrowserAutofillManagerStructuredProfileTest,
form.fields.push_back(field);
test::CreateTestFormField("Phone Number", "phonenumber", "", "tel", &field);
form.fields.push_back(field);
+ FormsSeen({form});
base::HistogramTester histogram_tester;
browser_autofill_manager_->DidShowSuggestions(
@@ -8866,6 +8926,7 @@ TEST_P(BrowserAutofillManagerStructuredProfileTest,
form.fields.push_back(field);
test::CreateTestFormField("Email", "email", "", "email", &field);
form.fields.push_back(field);
+ FormsSeen({form});
base::HistogramTester histogram_tester;
browser_autofill_manager_->DidShowSuggestions(
@@ -8915,6 +8976,7 @@ TEST_P(BrowserAutofillManagerStructuredProfileTest,
form.fields.push_back(field);
test::CreateTestFormField("Email", "email", "", "email", &field);
form.fields.push_back(field);
+ FormsSeen({form});
base::HistogramTester histogram_tester;
browser_autofill_manager_->DidShowSuggestions(
@@ -8948,6 +9010,7 @@ TEST_P(BrowserAutofillManagerStructuredProfileTest,
DidShowSuggestions_LogAutofillCreditCardShownMetric) {
FormData form;
CreateTestCreditCardFormData(&form, true, false);
+ FormsSeen({form});
base::HistogramTester histogram_tester;
browser_autofill_manager_->DidShowSuggestions(
@@ -8976,6 +9039,7 @@ TEST_P(BrowserAutofillManagerStructuredProfileTest,
DidSuppressPopup_LogAutofillAddressPopupSuppressed) {
FormData form;
test::CreateTestAddressFormData(&form);
+ browser_autofill_manager_->OnFormsSeen({form}, {});
base::HistogramTester histogram_tester;
browser_autofill_manager_->DidSuppressPopup(form, form.fields[0]);
@@ -8995,6 +9059,7 @@ TEST_P(BrowserAutofillManagerStructuredProfileTest,
FormData form;
CreateTestCreditCardFormData(&form, true, false);
+ browser_autofill_manager_->OnFormsSeen({form}, {});
base::HistogramTester histogram_tester;
browser_autofill_manager_->DidSuppressPopup(form, form.fields[0]);
histogram_tester.ExpectBucketCount("Autofill.FormEvents.CreditCard",
@@ -9099,11 +9164,24 @@ TEST_F(BrowserAutofillManagerTest, PageLanguageGetsCorrectlySet) {
ASSERT_EQ(LanguageCode("zh"), parsed_form->current_page_language());
}
-TEST_F(BrowserAutofillManagerTest, PageLanguageGetsCorrectlyDetected) {
- base::test::ScopedFeatureList scoped_feature_list;
- scoped_feature_list.InitAndEnableFeature(
- features::kAutofillPageLanguageDetection);
+// Test language detection on frames depending on whether the frame is active or
+// not.
+class BrowserAutofillManagerTestPageLanguageDetection
+ : public BrowserAutofillManagerTest,
+ public testing::WithParamInterface<bool> {
+ public:
+ BrowserAutofillManagerTestPageLanguageDetection() {
+ scoped_features_.InitAndEnableFeature(
+ features::kAutofillPageLanguageDetection);
+ }
+ bool is_in_active_frame() const { return GetParam(); };
+
+ private:
+ base::test::ScopedFeatureList scoped_features_;
+};
+
+TEST_P(BrowserAutofillManagerTestPageLanguageDetection, GetsCorrectlyDetected) {
FormData form;
test::CreateTestAddressFormData(&form);
@@ -9115,17 +9193,26 @@ TEST_F(BrowserAutofillManagerTest, PageLanguageGetsCorrectlyDetected) {
ASSERT_EQ(LanguageCode(), parsed_form->current_page_language());
translate::LanguageDetectionDetails language_detection_details;
- language_detection_details.adopted_language = "zh";
+ language_detection_details.adopted_language = "hu";
+ autofill_driver_->SetIsInActiveFrame(is_in_active_frame());
browser_autofill_manager_->OnLanguageDetermined(language_detection_details);
- autofill_client_.GetLanguageState()->SetCurrentLanguage("zh");
+ autofill_client_.GetLanguageState()->SetCurrentLanguage("hu");
parsed_form =
browser_autofill_manager_->FindCachedFormByRendererId(form.global_id());
- ASSERT_EQ(LanguageCode("zh"), parsed_form->current_page_language());
+ // Language detection is used only for active frames.
+ auto expected_language_code =
+ is_in_active_frame() ? LanguageCode("hu") : LanguageCode();
+
+ ASSERT_EQ(*expected_language_code, *parsed_form->current_page_language());
}
+INSTANTIATE_TEST_SUITE_P(All,
+ BrowserAutofillManagerTestPageLanguageDetection,
+ testing::Bool());
+
// BrowserAutofillManagerTest with different browser profile types.
class BrowserAutofillManagerProfileMetricsTest
: public BrowserAutofillManagerTest,
@@ -9146,8 +9233,7 @@ TEST_P(BrowserAutofillManagerProfileMetricsTest,
// Set up our form data.
FormData form;
test::CreateTestAddressFormData(&form);
- std::vector<FormData> forms(1, form);
- FormsSeen(forms);
+ FormsSeen({form});
FormFieldData field = form.fields[0];
GetAutofillSuggestions(form, field);
@@ -9167,6 +9253,70 @@ INSTANTIATE_TEST_SUITE_P(
profile_metrics::BrowserProfileType::kIncognito,
profile_metrics::BrowserProfileType::kGuest}));
+// Tests that autocomplete-related metrics are emitted correctly on form
+// submission.
+TEST_F(BrowserAutofillManagerTest, AutocompleteMetrics) {
+ // `kAutocompleteValues` corresponds to empty, valid, garbage and off.
+ constexpr base::StringPiece kAutocompleteValues[]{"", "name", "asdf", "off"};
+ // The 4 possible combinations of heuristic and server type status:
+ // - Neither a fillable heuristic type nor a fillable server type.
+ // - Only a fillable server type.
+ // - Only a fillable heuristic type.
+ // - Both a fillable heuristic type and a fillable server type.
+ // NO_SERVER_DATA and UNKNOWN_TYPE are both unfillable types, but
+ // NO_SERVER_DATA is ignored in the PredictionCollisionType metric.
+ constexpr ServerFieldType kTypeClasses[][2]{
+ {UNKNOWN_TYPE, NO_SERVER_DATA},
+ {UNKNOWN_TYPE, EMAIL_ADDRESS},
+ {ADDRESS_HOME_COUNTRY, UNKNOWN_TYPE},
+ {ADDRESS_HOME_COUNTRY, EMAIL_ADDRESS}};
+
+ // Create a form with one field per kAutofillValue x kTypeClass combination.
+ FormData form;
+ form.name = u"MyForm";
+ form.url = GURL("https://myform.com/form.html");
+ form.action = GURL("https://myform.com/submit.html");
+ std::vector<ServerFieldType> heuristic_types, server_types;
+ for (const auto& autocomplete : kAutocompleteValues) {
+ for (const auto& types : kTypeClasses) {
+ FormFieldData field;
+ test::CreateTestFormField("", "", "", "text", &field);
+ field.autocomplete_attribute = std::string(autocomplete);
+ form.fields.push_back(field);
+ heuristic_types.push_back(types[0]);
+ server_types.push_back(types[1]);
+ }
+ }
+ // Override the types and simulate seeing the form on page load.
+ auto form_structure = std::make_unique<FormStructure>(form);
+ form_structure->DetermineHeuristicTypes(nullptr, nullptr);
+ FormStructureTestApi(form_structure.get())
+ .SetFieldTypes(heuristic_types, server_types);
+ browser_autofill_manager_->AddSeenFormStructure(std::move(form_structure));
+
+ // Submit the form and verify that all metrics are collected correctly.
+ base::HistogramTester histogram_tester;
+ FormSubmitted(form);
+
+ // Expect one entry for each possible PredictionStateAutocompleteStatePair.
+ // Fields without type predictions and autocomplete attributes are ignored.
+ histogram_tester.ExpectTotalCount(
+ "Autofill.Autocomplete.PredictionCollisionState", form.fields.size() - 1);
+ for (int i = 0; i < 15; i++) {
+ histogram_tester.ExpectBucketCount(
+ "Autofill.Autocomplete.PredictionCollisionState", i, 1);
+ }
+
+ // The PredictionCollisionType metric is collected for every field with
+ // autocomplete=garbage. This amounts 1 vote per `kTypeClass` here.
+ // Fields NO_SERVER_DATA are ignored for the .Server metric.
+ const std::string kTypeHistogram =
+ "Autofill.Autocomplete.PredictionCollisionType.";
+ histogram_tester.ExpectTotalCount(kTypeHistogram + "Heuristics", 4);
+ histogram_tester.ExpectTotalCount(kTypeHistogram + "Server", 3);
+ histogram_tester.ExpectTotalCount(kTypeHistogram + "ServerOrHeuristics", 4);
+}
+
// Test that if a form is mixed content we show a warning instead of any
// suggestions.
TEST_F(BrowserAutofillManagerTest, GetSuggestions_MixedForm) {
@@ -9399,6 +9549,22 @@ TEST_F(BrowserAutofillManagerTest, AutofillOverridePrefilledValue) {
EXPECT_EQ(response_data.fields[3].value, u"Test Country");
}
+// Tests that both Autofill popup and TTF are hidden on renderer event.
+TEST_F(BrowserAutofillManagerTest, HideAutofillPopupAndTouchToFillOnHidePopup) {
+ EXPECT_CALL(autofill_client_,
+ HideAutofillPopup(PopupHidingReason::kRendererEvent));
+ EXPECT_CALL(*touch_to_fill_delegate_, HideTouchToFill);
+ browser_autofill_manager_->OnHidePopup();
+}
+
+// Tests that only Autofill popup is hidden on editing end, but not TTF.
+TEST_F(BrowserAutofillManagerTest, OnDidEndTextFieldEditing) {
+ EXPECT_CALL(autofill_client_,
+ HideAutofillPopup(PopupHidingReason::kEndEditing));
+ EXPECT_CALL(*touch_to_fill_delegate_, HideTouchToFill).Times(0);
+ browser_autofill_manager_->OnDidEndTextFieldEditing();
+}
+
// Tests that Autofill suggestions are not shown if TTF is eligible and shown.
TEST_F(BrowserAutofillManagerTest, AutofillSuggestionsOrTouchToFill) {
FormData form;
@@ -9428,6 +9594,24 @@ TEST_F(BrowserAutofillManagerTest, AutofillSuggestionsOrTouchToFill) {
EXPECT_FALSE(external_delegate_->on_suggestions_returned_seen());
}
+// Tests that neither Autofill suggestions nor TTF is triggered if TTF is
+// already shown.
+TEST_F(BrowserAutofillManagerTest, ShowNothingIfTouchToFillAlreadyShown) {
+ FormData form;
+ CreateTestCreditCardFormData(&form, /*is_https=*/true,
+ /*use_month_type=*/false);
+ FormsSeen({form});
+ const FormFieldData& field = form.fields[1];
+
+ EXPECT_CALL(*touch_to_fill_delegate_, IsShowingTouchToFill)
+ .WillOnce(Return(true));
+ EXPECT_CALL(*touch_to_fill_delegate_,
+ TryToShowTouchToFill(kDefaultPageID, _, _))
+ .Times(0);
+ TryToShowTouchToFill(kDefaultPageID, form, field, TouchToFillEligible(true));
+ EXPECT_FALSE(external_delegate_->on_suggestions_returned_seen());
+}
+
// Desktop only tests.
#if !BUILDFLAG(IS_ANDROID) && !BUILDFLAG(IS_IOS)
class BrowserAutofillManagerTestForVirtualCardOption
@@ -10099,7 +10283,7 @@ TEST_P(BrowserAutofillManagerRefillTest,
// Simulate that JavaScript modifies the expiration date field.
FormData form_after_js_modification = first_fill_data;
form_after_js_modification.fields[2].value = test_case.exp_date_from_js;
- browser_autofill_manager_->JavaScriptChangedAutofilledValue(
+ browser_autofill_manager_->OnJavaScriptChangedAutofilledValue(
form_after_js_modification, form_after_js_modification.fields[2],
u"04/2999");
diff --git a/chromium/components/autofill/core/browser/crypto/rc4_decryptor.h b/chromium/components/autofill/core/browser/crypto/rc4_decryptor.h
deleted file mode 100644
index 4598274fc2e..00000000000
--- a/chromium/components/autofill/core/browser/crypto/rc4_decryptor.h
+++ /dev/null
@@ -1,112 +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_CRYPTO_RC4_DECRYPTOR_H_
-#define COMPONENTS_AUTOFILL_CORE_BROWSER_CRYPTO_RC4_DECRYPTOR_H_
-
-#include <stdint.h>
-#include <string.h>
-
-#include <memory>
-#include <string>
-
-namespace autofill {
-
-// This is modified RC4 decryption used for import of Toolbar autofill data
-// only. The difference from the Crypto Api implementation is twofold:
-// First, it uses a non-standard key size (160 bit), not supported by Microsoft
-// (it supports only 40 and 128 bit for RC4). Second, it codes 128 words with
-// value 0x0020 at the beginning of the code to enhance security.
-//
-// This class used in
-// components/autofill/core/browser/autofill_ie_toolbar_import_win.cc.
-//
-// This class should not be used anywhere else!!!
-class RC4Decryptor {
- public:
- explicit RC4Decryptor(wchar_t const* password) {
- PrepareKey(reinterpret_cast<const uint8_t*>(password),
- wcslen(password) * sizeof(wchar_t));
- std::wstring data;
- // First 128 bytes should be spaces.
- data.resize(128, L' ');
- Run(data.c_str());
- }
-
- // Run the algorithm
- std::wstring Run(const std::wstring& data) {
- int data_size = data.length() * sizeof(wchar_t);
-
- std::unique_ptr<wchar_t[]> buffer(new wchar_t[data.length() + 1]);
- memset(buffer.get(), 0, (data.length() + 1) * sizeof(wchar_t));
- memcpy(buffer.get(), data.c_str(), data_size);
-
- RunInternal(reinterpret_cast<uint8_t*>(buffer.get()), data_size);
-
- std::wstring result(buffer.get());
-
- // Clear the memory
- memset(buffer.get(), 0, data_size);
- return result;
- }
-
- private:
- static const int kKeyDataSize = 256;
- struct Rc4Key {
- uint8_t state[kKeyDataSize];
- uint8_t x;
- uint8_t y;
- };
-
- void SwapByte(uint8_t* byte1, uint8_t* byte2) {
- uint8_t temp = *byte1;
- *byte1 = *byte2;
- *byte2 = temp;
- }
-
- void PrepareKey(const uint8_t* key_data, int key_data_len) {
- uint8_t index1 = 0;
- uint8_t index2 = 0;
- uint8_t* state;
- short counter;
-
- state = &key_.state[0];
- for (counter = 0; counter < kKeyDataSize; ++counter)
- state[counter] = static_cast<uint8_t>(counter);
-
- key_.x = key_.y = 0;
-
- for (counter = 0; counter < kKeyDataSize; counter++) {
- index2 = (key_data[index1] + state[counter] + index2) % kKeyDataSize;
- SwapByte(&state[counter], &state[index2]);
- index1 = (index1 + 1) % key_data_len;
- }
- }
-
- void RunInternal(uint8_t* buffer, int buffer_len) {
- uint8_t x, y;
- uint8_t xor_index = 0;
- uint8_t* state;
- int counter;
-
- x = key_.x;
- y = key_.y;
- state = &key_.state[0];
- for (counter = 0; counter < buffer_len; ++counter) {
- x = (x + 1) % kKeyDataSize;
- y = (state[x] + y) % kKeyDataSize;
- SwapByte(&state[x], &state[y]);
- xor_index = (state[x] + state[y]) % kKeyDataSize;
- buffer[counter] ^= state[xor_index];
- }
- key_.x = x;
- key_.y = y;
- }
-
- Rc4Key key_;
-};
-
-} // namespace autofill
-
-#endif // COMPONENTS_AUTOFILL_CORE_BROWSER_CRYPTO_RC4_DECRYPTOR_H_
diff --git a/chromium/components/autofill/core/browser/data_model/autofill_data_model.cc b/chromium/components/autofill/core/browser/data_model/autofill_data_model.cc
index 631f9191bf0..f244e931a31 100644
--- a/chromium/components/autofill/core/browser/data_model/autofill_data_model.cc
+++ b/chromium/components/autofill/core/browser/data_model/autofill_data_model.cc
@@ -83,7 +83,7 @@ AutofillMetadata AutofillDataModel::GetMetadata() const {
return metadata;
}
-bool AutofillDataModel::SetMetadata(const AutofillMetadata metadata) {
+bool AutofillDataModel::SetMetadata(const AutofillMetadata& metadata) {
use_count_ = metadata.use_count;
use_date_ = metadata.use_date;
return true;
diff --git a/chromium/components/autofill/core/browser/data_model/autofill_data_model.h b/chromium/components/autofill/core/browser/data_model/autofill_data_model.h
index 0219cd73ffa..392d5b391a9 100644
--- a/chromium/components/autofill/core/browser/data_model/autofill_data_model.h
+++ b/chromium/components/autofill/core/browser/data_model/autofill_data_model.h
@@ -88,7 +88,7 @@ class AutofillDataModel : public FormGroup {
// Sets the |use_count_| and |use_date_| of this autofill data model. Returns
// whether the metadata was set.
- virtual bool SetMetadata(const AutofillMetadata metadata);
+ virtual bool SetMetadata(const AutofillMetadata& metadata);
// Returns whether the data model is deletable: if it has not been used for
// longer than |kDisusedCreditCardDeletionTimeDelta|.
diff --git a/chromium/components/autofill/core/browser/data_model/autofill_profile.cc b/chromium/components/autofill/core/browser/data_model/autofill_profile.cc
index a6a61be5b64..62ffaa67bdb 100644
--- a/chromium/components/autofill/core/browser/data_model/autofill_profile.cc
+++ b/chromium/components/autofill/core/browser/data_model/autofill_profile.cc
@@ -286,7 +286,7 @@ AutofillMetadata AutofillProfile::GetMetadata() const {
return metadata;
}
-bool AutofillProfile::SetMetadata(const AutofillMetadata metadata) {
+bool AutofillProfile::SetMetadata(const AutofillMetadata& metadata) {
// Make sure the ids matches.
if (metadata.id != (record_type_ == LOCAL_PROFILE ? guid() : server_id_))
return false;
diff --git a/chromium/components/autofill/core/browser/data_model/autofill_profile.h b/chromium/components/autofill/core/browser/data_model/autofill_profile.h
index 6099221f2f9..63949ac312f 100644
--- a/chromium/components/autofill/core/browser/data_model/autofill_profile.h
+++ b/chromium/components/autofill/core/browser/data_model/autofill_profile.h
@@ -56,7 +56,7 @@ class AutofillProfile : public AutofillDataModel {
// AutofillDataModel:
AutofillMetadata GetMetadata() const override;
- bool SetMetadata(const AutofillMetadata metadata) override;
+ bool SetMetadata(const AutofillMetadata& metadata) override;
// Returns whether the profile is deletable: if it is not verified and has not
// been used for longer than |kDisusedAddressDeletionTimeDelta|.
bool IsDeletable() const override;
diff --git a/chromium/components/autofill/core/browser/data_model/autofill_profile_comparator.cc b/chromium/components/autofill/core/browser/data_model/autofill_profile_comparator.cc
index f24164ecae5..210e0dda5a4 100644
--- a/chromium/components/autofill/core/browser/data_model/autofill_profile_comparator.cc
+++ b/chromium/components/autofill/core/browser/data_model/autofill_profile_comparator.cc
@@ -43,8 +43,6 @@ std::ostream& operator<<(std::ostream& os,
const ::i18n::phonenumbers::PhoneNumber& n) {
os << "country_code: " << n.country_code() << " "
<< "national_number: " << n.national_number();
- if (n.has_extension())
- os << " extension: \"" << n.extension() << "\"";
if (n.has_italian_leading_zero())
os << " italian_leading_zero: " << n.italian_leading_zero();
if (n.has_number_of_leading_zeros())
@@ -718,11 +716,6 @@ bool AutofillProfileComparator::MergePhoneNumbers(
HasInternationalCountryCode(n1) ? n1.country_code() : n2.country_code());
merged_number.set_national_number(
std::max(n1.national_number(), n2.national_number()));
- if (n1.has_extension() && !n1.extension().empty()) {
- merged_number.set_extension(n1.extension());
- } else if (n2.has_extension() && !n2.extension().empty()) {
- merged_number.set_extension(n2.extension());
- }
if (n1.has_italian_leading_zero() || n2.has_italian_leading_zero()) {
merged_number.set_italian_leading_zero(n1.italian_leading_zero() ||
n2.italian_leading_zero());
@@ -1011,10 +1004,6 @@ bool AutofillProfileComparator::MergeAddresses(const AutofillProfile& p1,
bool AutofillProfileComparator::MergeBirthdates(const AutofillProfile& p1,
const AutofillProfile& p2,
Birthdate& birthdate) const {
- if (!base::FeatureList::IsEnabled(
- features::kAutofillEnableCompatibilitySupportForBirthdates)) {
- return true;
- }
DCHECK(HaveMergeableBirthdates(p1, p2));
for (ServerFieldType component : Birthdate::GetRawComponents()) {
@@ -1475,10 +1464,6 @@ bool AutofillProfileComparator::HaveMergeableAddresses(
bool AutofillProfileComparator::HaveMergeableBirthdates(
const AutofillProfile& p1,
const AutofillProfile& p2) const {
- if (!base::FeatureList::IsEnabled(
- features::kAutofillEnableCompatibilitySupportForBirthdates)) {
- return true;
- }
return base::ranges::all_of(
Birthdate::GetRawComponents(), [&](ServerFieldType component) {
const std::u16string& component1 = p1.GetInfo(component, app_locale_);
diff --git a/chromium/components/autofill/core/browser/data_model/autofill_profile_comparator_unittest.cc b/chromium/components/autofill/core/browser/data_model/autofill_profile_comparator_unittest.cc
index 21015691393..e1f91f5c32b 100644
--- a/chromium/components/autofill/core/browser/data_model/autofill_profile_comparator_unittest.cc
+++ b/chromium/components/autofill/core/browser/data_model/autofill_profile_comparator_unittest.cc
@@ -32,9 +32,9 @@ using autofill::ADDRESS_HOME_SORTING_CODE;
using autofill::ADDRESS_HOME_STATE;
using autofill::ADDRESS_HOME_STREET_ADDRESS;
using autofill::ADDRESS_HOME_ZIP;
+using autofill::BIRTHDATE_4_DIGIT_YEAR;
using autofill::BIRTHDATE_DAY;
using autofill::BIRTHDATE_MONTH;
-using autofill::BIRTHDATE_YEAR_4_DIGITS;
using autofill::COMPANY_NAME;
using autofill::EMAIL_ADDRESS;
using autofill::NAME_FIRST;
@@ -45,7 +45,6 @@ using autofill::NAME_MIDDLE;
using autofill::PHONE_HOME_CITY_AND_NUMBER;
using autofill::PHONE_HOME_CITY_CODE;
using autofill::PHONE_HOME_COUNTRY_CODE;
-using autofill::PHONE_HOME_EXTENSION;
using autofill::PHONE_HOME_NUMBER;
using autofill::PHONE_HOME_WHOLE_NUMBER;
@@ -193,7 +192,7 @@ class AutofillProfileComparatorTest
AutofillProfile profile(base::GenerateGUID(), "http://www.example.com/");
profile.SetRawInfo(BIRTHDATE_DAY, base::UTF8ToUTF16(day));
profile.SetRawInfo(BIRTHDATE_MONTH, base::UTF8ToUTF16(month));
- profile.SetRawInfo(BIRTHDATE_YEAR_4_DIGITS, base::UTF8ToUTF16(year));
+ profile.SetRawInfo(BIRTHDATE_4_DIGIT_YEAR, base::UTF8ToUTF16(year));
return profile;
}
@@ -276,8 +275,6 @@ class AutofillProfileComparatorTest
actual.GetInfo(AutofillType(PHONE_HOME_CITY_CODE), kLocale));
EXPECT_EQ(expected.GetInfo(AutofillType(PHONE_HOME_NUMBER), kLocale),
actual.GetInfo(AutofillType(PHONE_HOME_NUMBER), kLocale));
- EXPECT_EQ(expected.GetInfo(AutofillType(PHONE_HOME_EXTENSION), kLocale),
- actual.GetInfo(AutofillType(PHONE_HOME_EXTENSION), kLocale));
}
void MergeAddressesAndExpect(const AutofillProfile& a,
@@ -653,30 +650,14 @@ TEST_P(AutofillProfileComparatorTest, HaveMergeableCompanyNames) {
TEST_P(AutofillProfileComparatorTest, HaveMergeablePhoneNumbers) {
AutofillProfile empty = CreateProfileWithPhoneNumber("");
AutofillProfile p1 = CreateProfileWithPhoneNumber("+1 (800) 670-8700");
- AutofillProfile p2 = CreateProfileWithPhoneNumber("800.670.8700x321");
- AutofillProfile p3 = CreateProfileWithPhoneNumber("670-8700 ext321");
- AutofillProfile p4 = CreateProfileWithPhoneNumber("6708700");
+ AutofillProfile p2 = CreateProfileWithPhoneNumber("6708700");
AutofillProfile different = CreateProfileWithPhoneNumber("1-800-321-4567");
EXPECT_TRUE(comparator_.HaveMergeablePhoneNumbers(p1, p1));
EXPECT_TRUE(comparator_.HaveMergeablePhoneNumbers(p1, p2));
- EXPECT_TRUE(comparator_.HaveMergeablePhoneNumbers(p1, p3));
- EXPECT_TRUE(comparator_.HaveMergeablePhoneNumbers(p1, p4));
EXPECT_TRUE(comparator_.HaveMergeablePhoneNumbers(p2, p1));
EXPECT_TRUE(comparator_.HaveMergeablePhoneNumbers(p2, p2));
- EXPECT_TRUE(comparator_.HaveMergeablePhoneNumbers(p2, p3));
- EXPECT_TRUE(comparator_.HaveMergeablePhoneNumbers(p2, p4));
-
- EXPECT_TRUE(comparator_.HaveMergeablePhoneNumbers(p3, p1));
- EXPECT_TRUE(comparator_.HaveMergeablePhoneNumbers(p3, p2));
- EXPECT_TRUE(comparator_.HaveMergeablePhoneNumbers(p3, p3));
- EXPECT_TRUE(comparator_.HaveMergeablePhoneNumbers(p3, p4));
-
- EXPECT_TRUE(comparator_.HaveMergeablePhoneNumbers(p4, p1));
- EXPECT_TRUE(comparator_.HaveMergeablePhoneNumbers(p4, p2));
- EXPECT_TRUE(comparator_.HaveMergeablePhoneNumbers(p4, p3));
- EXPECT_TRUE(comparator_.HaveMergeablePhoneNumbers(p4, p4));
EXPECT_TRUE(comparator_.HaveMergeablePhoneNumbers(p1, empty));
EXPECT_TRUE(comparator_.HaveMergeablePhoneNumbers(empty, p2));
@@ -742,10 +723,6 @@ TEST_P(AutofillProfileComparatorTest, HaveMergeableAddresses) {
}
TEST_P(AutofillProfileComparatorTest, HaveMergeableBirthdates) {
- base::test::ScopedFeatureList feature;
- feature.InitAndEnableFeature(
- autofill::features::kAutofillEnableCompatibilitySupportForBirthdates);
-
// Birthdates are mergeable if the components are either equal or one of them
// is empty.
AutofillProfile p1 = CreateProfileWithBirthdate("14", "", "1997");
@@ -780,7 +757,7 @@ TEST_P(AutofillProfileComparatorTest, AreMergeable) {
{ADDRESS_HOME_LINE1, u"123 zoo st. w., #5"},
{ADDRESS_HOME_LINE1, u""},
{ADDRESS_HOME_STATE, u"california"},
- {PHONE_HOME_WHOLE_NUMBER, u"5678910 ext. 77"}});
+ {PHONE_HOME_WHOLE_NUMBER, u"5678910"}});
AutofillProfile not_mergeable_by_name =
CopyAndModify(p, {{NAME_FIRST, u"Steven"},
{NAME_FULL, u""},
@@ -1074,143 +1051,50 @@ TEST_P(AutofillProfileComparatorTest, MergeCompanyNames) {
}
TEST_P(AutofillProfileComparatorTest, MergePhoneNumbers_NA) {
- static const char kPhoneA[] = "5550199";
- static const char16_t kPhoneA16[] = u"5550199";
- static const char kPhoneB[] = "555.0199";
- static const char16_t kPhoneB16[] = u"555.0199";
- static const char kPhoneC[] = "555-0199 ext321";
- static const char16_t kPhoneC16[] = u"555-0199 ext321";
- static const char kPhoneD[] = "8005550199";
- static const char16_t kPhoneD16[] = u"8005550199";
- static const char kPhoneE[] = "800-555-0199 #321";
- static const char16_t kPhoneE16[] = u"800-555-0199 #321";
- static const char kPhoneF[] = "1-800-555-0199 #321";
- static const char16_t kPhoneF16[] = u"1-800-555-0199 #321";
- static const char kPhoneG[] = "+1 (800) 555.0199;ext=321";
- static const char16_t kPhoneG16[] = u"+1 (800) 555.0199;ext=321";
- static const char16_t kMergedShortNumber[] = u"555-0199";
- static const char16_t kMergedShortNumberExt[] = u"555-0199 ext. 321";
- static const char16_t kMergedNationalNumber[] = u"(800) 555-0199";
- static const char16_t kMergedNationalNumberExt[] = u"(800) 555-0199 ext. 321";
- static const char16_t kMergedFullNumberExt[] = u"+1 800-555-0199 ext. 321";
-
- AutofillProfile profile_a = CreateProfileWithPhoneNumber(kPhoneA);
- AutofillProfile profile_b = CreateProfileWithPhoneNumber(kPhoneB);
- AutofillProfile profile_c = CreateProfileWithPhoneNumber(kPhoneC);
- AutofillProfile profile_d = CreateProfileWithPhoneNumber(kPhoneD);
- AutofillProfile profile_e = CreateProfileWithPhoneNumber(kPhoneE);
- AutofillProfile profile_f = CreateProfileWithPhoneNumber(kPhoneF);
- AutofillProfile profile_g = CreateProfileWithPhoneNumber(kPhoneG);
+ AutofillProfile profile_a = CreateProfileWithPhoneNumber("5550199");
+ AutofillProfile profile_b = CreateProfileWithPhoneNumber("555.0199");
+ AutofillProfile profile_c = CreateProfileWithPhoneNumber("8005550199");
// Profile A
- MergePhoneNumbersAndExpect(profile_a, profile_a, kPhoneA16);
- MergePhoneNumbersAndExpect(profile_a, profile_b, kMergedShortNumber);
- MergePhoneNumbersAndExpect(profile_a, profile_c, kMergedShortNumberExt);
- MergePhoneNumbersAndExpect(profile_a, profile_d, kMergedNationalNumber);
- MergePhoneNumbersAndExpect(profile_a, profile_e, kMergedNationalNumberExt);
- MergePhoneNumbersAndExpect(profile_a, profile_f, kMergedFullNumberExt);
- MergePhoneNumbersAndExpect(profile_a, profile_g, kMergedFullNumberExt);
+ MergePhoneNumbersAndExpect(profile_a, profile_a, u"5550199");
+ MergePhoneNumbersAndExpect(profile_a, profile_b, u"555-0199");
+ MergePhoneNumbersAndExpect(profile_a, profile_c, u"(800) 555-0199");
// Profile B
- MergePhoneNumbersAndExpect(profile_b, profile_a, kMergedShortNumber);
- MergePhoneNumbersAndExpect(profile_b, profile_b, kPhoneB16);
- MergePhoneNumbersAndExpect(profile_b, profile_c, kMergedShortNumberExt);
- MergePhoneNumbersAndExpect(profile_b, profile_d, kMergedNationalNumber);
- MergePhoneNumbersAndExpect(profile_b, profile_e, kMergedNationalNumberExt);
- MergePhoneNumbersAndExpect(profile_b, profile_f, kMergedFullNumberExt);
- MergePhoneNumbersAndExpect(profile_b, profile_g, kMergedFullNumberExt);
-
- // Profile C
- MergePhoneNumbersAndExpect(profile_c, profile_a, kMergedShortNumberExt);
- MergePhoneNumbersAndExpect(profile_c, profile_b, kMergedShortNumberExt);
- MergePhoneNumbersAndExpect(profile_c, profile_c, kPhoneC16);
- MergePhoneNumbersAndExpect(profile_c, profile_d, kMergedNationalNumberExt);
- MergePhoneNumbersAndExpect(profile_c, profile_e, kMergedNationalNumberExt);
- MergePhoneNumbersAndExpect(profile_c, profile_f, kMergedFullNumberExt);
- MergePhoneNumbersAndExpect(profile_c, profile_g, kMergedFullNumberExt);
+ MergePhoneNumbersAndExpect(profile_b, profile_a, u"555-0199");
+ MergePhoneNumbersAndExpect(profile_b, profile_b, u"555.0199");
+ MergePhoneNumbersAndExpect(profile_b, profile_c, u"(800) 555-0199");
// Profile D
- MergePhoneNumbersAndExpect(profile_d, profile_a, kMergedNationalNumber);
- MergePhoneNumbersAndExpect(profile_d, profile_b, kMergedNationalNumber);
- MergePhoneNumbersAndExpect(profile_d, profile_c, kMergedNationalNumberExt);
- MergePhoneNumbersAndExpect(profile_d, profile_d, kPhoneD16);
- MergePhoneNumbersAndExpect(profile_d, profile_e, kMergedNationalNumberExt);
- MergePhoneNumbersAndExpect(profile_d, profile_f, kMergedFullNumberExt);
- MergePhoneNumbersAndExpect(profile_d, profile_g, kMergedFullNumberExt);
-
- // Profile E
- MergePhoneNumbersAndExpect(profile_e, profile_a, kMergedNationalNumberExt);
- MergePhoneNumbersAndExpect(profile_e, profile_b, kMergedNationalNumberExt);
- MergePhoneNumbersAndExpect(profile_e, profile_c, kMergedNationalNumberExt);
- MergePhoneNumbersAndExpect(profile_e, profile_d, kMergedNationalNumberExt);
- MergePhoneNumbersAndExpect(profile_e, profile_e, kPhoneE16);
- MergePhoneNumbersAndExpect(profile_e, profile_f, kMergedFullNumberExt);
- MergePhoneNumbersAndExpect(profile_e, profile_g, kMergedFullNumberExt);
-
- // Profile F
- MergePhoneNumbersAndExpect(profile_f, profile_a, kMergedFullNumberExt);
- MergePhoneNumbersAndExpect(profile_f, profile_b, kMergedFullNumberExt);
- MergePhoneNumbersAndExpect(profile_f, profile_c, kMergedFullNumberExt);
- MergePhoneNumbersAndExpect(profile_f, profile_d, kMergedFullNumberExt);
- MergePhoneNumbersAndExpect(profile_f, profile_e, kMergedFullNumberExt);
- MergePhoneNumbersAndExpect(profile_f, profile_f, kPhoneF16);
- MergePhoneNumbersAndExpect(profile_f, profile_g, kMergedFullNumberExt);
-
- // Profile G
- MergePhoneNumbersAndExpect(profile_g, profile_a, kMergedFullNumberExt);
- MergePhoneNumbersAndExpect(profile_g, profile_b, kMergedFullNumberExt);
- MergePhoneNumbersAndExpect(profile_g, profile_c, kMergedFullNumberExt);
- MergePhoneNumbersAndExpect(profile_g, profile_d, kMergedFullNumberExt);
- MergePhoneNumbersAndExpect(profile_g, profile_e, kMergedFullNumberExt);
- MergePhoneNumbersAndExpect(profile_g, profile_f, kMergedFullNumberExt);
- MergePhoneNumbersAndExpect(profile_g, profile_g, kPhoneG16);
+ MergePhoneNumbersAndExpect(profile_c, profile_a, u"(800) 555-0199");
+ MergePhoneNumbersAndExpect(profile_c, profile_b, u"(800) 555-0199");
+ MergePhoneNumbersAndExpect(profile_c, profile_c, u"8005550199");
}
TEST_P(AutofillProfileComparatorTest, MergePhoneNumbers_Intl) {
- const std::u16string kGermany = u"DE";
- const AutofillType kCountry(ADDRESS_HOME_COUNTRY);
-
- static const char kPhoneA[] = "+49492180185611";
- static const char16_t kPhoneA16[] = u"+49492180185611";
- static const char kPhoneB[] = "+49 4921 801 856-11";
- static const char16_t kPhoneB16[] = u"+49 4921 801 856-11";
- static const char kPhoneC[] = "+49 4921 8018 5611;ext=22";
- static const char16_t kPhoneC16[] = u"+49 4921 8018 5611;ext=22";
- static const char kPhoneD[] = "04921 80185611"; // National Format.
- static const char16_t kPhoneD16[] = u"04921 80185611"; // National Format.
- static const char16_t kMergedFullNumber[] = u"+49 4921 80185611";
- static const char16_t kMergedFullNumberExt[] = u"+49 4921 80185611 ext. 22";
-
- AutofillProfile profile_a = CreateProfileWithPhoneNumber(kPhoneA);
- AutofillProfile profile_b = CreateProfileWithPhoneNumber(kPhoneB);
- AutofillProfile profile_c = CreateProfileWithPhoneNumber(kPhoneC);
- AutofillProfile profile_d = CreateProfileWithPhoneNumber(kPhoneD);
-
- profile_a.SetInfo(kCountry, kGermany, kLocale);
- profile_b.SetInfo(kCountry, kGermany, kLocale);
- profile_c.SetInfo(kCountry, kGermany, kLocale);
- profile_d.SetInfo(kCountry, kGermany, kLocale);
+ AutofillProfile profile_a = CreateProfileWithPhoneNumber("+49492180185611");
+ AutofillProfile profile_b =
+ CreateProfileWithPhoneNumber("+49 4921 801 856-11");
+ AutofillProfile profile_c = CreateProfileWithPhoneNumber("04921 80185611");
+
+ profile_a.SetInfo(ADDRESS_HOME_COUNTRY, u"DE", kLocale);
+ profile_b.SetInfo(ADDRESS_HOME_COUNTRY, u"DE", kLocale);
+ profile_c.SetInfo(ADDRESS_HOME_COUNTRY, u"DE", kLocale);
// Profile A
- MergePhoneNumbersAndExpect(profile_a, profile_a, kPhoneA16);
- MergePhoneNumbersAndExpect(profile_a, profile_b, kMergedFullNumber);
- MergePhoneNumbersAndExpect(profile_a, profile_c, kMergedFullNumberExt);
+ MergePhoneNumbersAndExpect(profile_a, profile_a, u"+49492180185611");
+ MergePhoneNumbersAndExpect(profile_a, profile_b, u"+49 4921 80185611");
+ MergePhoneNumbersAndExpect(profile_a, profile_c, u"+49 4921 80185611");
// Profile B
- MergePhoneNumbersAndExpect(profile_b, profile_a, kMergedFullNumber);
- MergePhoneNumbersAndExpect(profile_b, profile_b, kPhoneB16);
- MergePhoneNumbersAndExpect(profile_b, profile_c, kMergedFullNumberExt);
-
- // Profile C
- MergePhoneNumbersAndExpect(profile_c, profile_a, kMergedFullNumberExt);
- MergePhoneNumbersAndExpect(profile_c, profile_b, kMergedFullNumberExt);
- MergePhoneNumbersAndExpect(profile_c, profile_c, kPhoneC16);
+ MergePhoneNumbersAndExpect(profile_b, profile_a, u"+49 4921 80185611");
+ MergePhoneNumbersAndExpect(profile_b, profile_b, u"+49 4921 801 856-11");
+ MergePhoneNumbersAndExpect(profile_b, profile_c, u"+49 4921 80185611");
// Profile D
- MergePhoneNumbersAndExpect(profile_d, profile_a, kMergedFullNumber);
- MergePhoneNumbersAndExpect(profile_d, profile_b, kMergedFullNumber);
- MergePhoneNumbersAndExpect(profile_d, profile_c, kMergedFullNumberExt);
- MergePhoneNumbersAndExpect(profile_d, profile_d, kPhoneD16);
+ MergePhoneNumbersAndExpect(profile_c, profile_a, u"+49 4921 80185611");
+ MergePhoneNumbersAndExpect(profile_c, profile_b, u"+49 4921 80185611");
+ MergePhoneNumbersAndExpect(profile_c, profile_c, u"04921 80185611");
}
TEST_P(AutofillProfileComparatorTest, MergeAddresses) {
@@ -1364,17 +1248,13 @@ TEST_P(AutofillProfileComparatorTest,
}
TEST_P(AutofillProfileComparatorTest, MergeBirthdates) {
- base::test::ScopedFeatureList feature;
- feature.InitAndEnableFeature(
- autofill::features::kAutofillEnableCompatibilitySupportForBirthdates);
-
AutofillProfile profile1 = CreateProfileWithBirthdate("14", "", "1997");
AutofillProfile profile2 = CreateProfileWithBirthdate("", "3", "1997");
Birthdate expected;
expected.SetRawInfo(BIRTHDATE_DAY, u"14");
expected.SetRawInfo(BIRTHDATE_MONTH, u"3");
- expected.SetRawInfo(BIRTHDATE_YEAR_4_DIGITS, u"1997");
+ expected.SetRawInfo(BIRTHDATE_4_DIGIT_YEAR, u"1997");
Birthdate actual;
EXPECT_TRUE(comparator_.MergeBirthdates(profile1, profile2, actual));
@@ -1386,20 +1266,29 @@ TEST_P(AutofillProfileComparatorTest, MergeBirthdates) {
// Checks for various scenarios for determining mergeability of profiles w.r.t.
// the state.
TEST_P(AutofillProfileComparatorTest, CheckStatesMergeability) {
+ // |kAutofillEnableSupportForMoreStructureInAddresses| is not compatible with
+ // AlternativeStateNameMap merging logic.
+ if (structured_addresses_enabled_)
+ return;
+
base::test::ScopedFeatureList feature;
feature.InitAndEnableFeature(
autofill::features::kAutofillUseAlternativeStateNameMap);
-
autofill::test::ClearAlternativeStateNameMapForTesting();
- autofill::test::PopulateAlternativeStateNameMapForTesting();
+ autofill::test::PopulateAlternativeStateNameMapForTesting(
+ "DE", "RandomState",
+ {{.canonical_name = "RandomState",
+ .abbreviations = {"RS"},
+ .alternative_names = {"AlternateRandomState"}}});
AutofillProfile empty = CreateProfileWithAddress("", "", "", "", "", "DE");
- AutofillProfile p1 = CreateProfileWithAddress("", "", "", "Bayern", "", "DE");
+ AutofillProfile p1 =
+ CreateProfileWithAddress("", "", "", "RandomState", "", "DE");
AutofillProfile p2 = CreateProfileWithAddress("", "", "", "Random", "", "DE");
- AutofillProfile p3 =
- CreateProfileWithAddress("", "", "", "Bayern - BY - Bavaria", "", "DE");
+ AutofillProfile p3 = CreateProfileWithAddress(
+ "", "", "", "RandomState - RS - AlternateRandomState", "", "DE");
AutofillProfile p4 =
- CreateProfileWithAddress("", "", "", "Bavaria", "", "DE");
+ CreateProfileWithAddress("", "", "", "AlternateRandomState", "", "DE");
EXPECT_TRUE(comparator_.HaveMergeableAddresses(empty, empty));
EXPECT_TRUE(comparator_.HaveMergeableAddresses(p1, empty));
@@ -1696,13 +1585,8 @@ TEST_P(AutofillProfileComparatorTest, GetMergeCandidate) {
// Tests that the profiles are merged when they have common states.
TEST_P(AutofillProfileComparatorTest, MergeProfilesBasedOnState) {
base::test::ScopedFeatureList feature;
- // The feature
- // |autofill::features::kAutofillEnableSupportForMoreStructureInAddresses| is
- // disabled since it is incompatible with the feature
- // |autofill::features::kAutofillUseStateMappingCache|.
- feature.InitWithFeatures(
- {autofill::features::kAutofillUseAlternativeStateNameMap},
- {autofill::features::kAutofillEnableSupportForMoreStructureInAddresses});
+ feature.InitAndEnableFeature(
+ autofill::features::kAutofillUseAlternativeStateNameMap);
autofill::test::ClearAlternativeStateNameMapForTesting();
autofill::test::PopulateAlternativeStateNameMapForTesting();
diff --git a/chromium/components/autofill/core/browser/data_model/autofill_profile_unittest.cc b/chromium/components/autofill/core/browser/data_model/autofill_profile_unittest.cc
index 7474affa4a6..fbfb1f4f776 100644
--- a/chromium/components/autofill/core/browser/data_model/autofill_profile_unittest.cc
+++ b/chromium/components/autofill/core/browser/data_model/autofill_profile_unittest.cc
@@ -615,7 +615,6 @@ TEST_P(AutofillProfileTest, CreateInferredLabelsNoDuplicatedFields) {
// should not fall back to the full name as a distinguishing field.
std::vector<ServerFieldType> suggested_fields;
suggested_fields.push_back(ADDRESS_HOME_LINE1);
- suggested_fields.push_back(ADDRESS_BILLING_LINE1);
suggested_fields.push_back(EMAIL_ADDRESS);
std::vector<std::u16string> labels;
AutofillProfile::CreateInferredLabels(ToRawPointerVector(profiles),
diff --git a/chromium/components/autofill/core/browser/data_model/autofill_structured_address.cc b/chromium/components/autofill/core/browser/data_model/autofill_structured_address.cc
index 6a289ce4625..b094a2234c7 100644
--- a/chromium/components/autofill/core/browser/data_model/autofill_structured_address.cc
+++ b/chromium/components/autofill/core/browser/data_model/autofill_structured_address.cc
@@ -6,21 +6,18 @@
#include <utility>
#include "base/containers/contains.h"
-#include "base/i18n/case_conversion.h"
-#include "base/strings/strcat.h"
+#include "base/feature_list.h"
#include "base/strings/string_split.h"
#include "base/strings/string_util.h"
#include "base/strings/utf_string_conversions.h"
-#include "components/autofill/core/browser/address_rewriter.h"
#include "components/autofill/core/browser/autofill_type.h"
-#include "components/autofill/core/browser/data_model/autofill_structured_address_constants.h"
#include "components/autofill/core/browser/data_model/autofill_structured_address_regex_provider.h"
#include "components/autofill/core/browser/data_model/autofill_structured_address_utils.h"
#include "components/autofill/core/browser/field_types.h"
+#include "components/autofill/core/browser/geo/alternative_state_name_map.h"
+#include "components/autofill/core/common/autofill_features.h"
-namespace autofill {
-
-namespace structured_address {
+namespace autofill::structured_address {
std::u16string AddressComponentWithRewriter::RewriteValue(
const std::u16string& value,
@@ -316,10 +313,39 @@ State::State(AddressComponent* parent)
: AddressComponentWithRewriter(
ADDRESS_HOME_STATE,
parent,
- MergeMode::kPickShorterIfOneContainsTheOther | kReplaceEmpty) {}
+ kPickShorterIfOneContainsTheOther |
+ (base::FeatureList::IsEnabled(
+ features::kAutofillUseAlternativeStateNameMap)
+ ? MergeMode::kMergeBasedOnCanonicalizedValues
+ : 0) |
+ kReplaceEmpty) {}
State::~State() = default;
+absl::optional<std::u16string> State::GetCanonicalizedValue() const {
+ if (!base::FeatureList::IsEnabled(
+ features::kAutofillUseAlternativeStateNameMap)) {
+ return absl::nullopt;
+ }
+
+ std::string country_code =
+ base::UTF16ToUTF8(GetRootNode().GetValueForType(ADDRESS_HOME_COUNTRY));
+
+ if (country_code.empty()) {
+ return absl::nullopt;
+ }
+
+ absl::optional<AlternativeStateNameMap::CanonicalStateName>
+ canonicalized_state_name = AlternativeStateNameMap::GetCanonicalStateName(
+ country_code, GetValue());
+
+ if (!canonicalized_state_name.has_value()) {
+ return absl::nullopt;
+ }
+
+ return canonicalized_state_name.value().value();
+}
+
// Zips are mergeable when one is a substring of the other one.
// For merging, the shorter substring is taken.
PostalCode::PostalCode(AddressComponent* parent)
@@ -389,6 +415,4 @@ void Address::MigrateLegacyStructure(bool is_verified_profile) {
}
}
-} // namespace structured_address
-
-} // namespace autofill
+} // namespace autofill::structured_address
diff --git a/chromium/components/autofill/core/browser/data_model/autofill_structured_address.h b/chromium/components/autofill/core/browser/data_model/autofill_structured_address.h
index 971d418b2de..3765788dc55 100644
--- a/chromium/components/autofill/core/browser/data_model/autofill_structured_address.h
+++ b/chromium/components/autofill/core/browser/data_model/autofill_structured_address.h
@@ -188,6 +188,10 @@ class State : public AddressComponentWithRewriter {
public:
explicit State(AddressComponent* parent);
~State() override;
+
+ // For states we use the AlternativeStateNameMap to offer canonicalized state
+ // names.
+ absl::optional<std::u16string> GetCanonicalizedValue() const override;
};
// Stores the postal code of an address.
diff --git a/chromium/components/autofill/core/browser/data_model/autofill_structured_address_component.cc b/chromium/components/autofill/core/browser/data_model/autofill_structured_address_component.cc
index 54d5276b045..ed64141235e 100644
--- a/chromium/components/autofill/core/browser/data_model/autofill_structured_address_component.cc
+++ b/chromium/components/autofill/core/browser/data_model/autofill_structured_address_component.cc
@@ -9,7 +9,6 @@
#include <string>
#include <utility>
-#include "base/feature_list.h"
#include "base/notreached.h"
#include "base/strings/strcat.h"
#include "base/strings/string_piece.h"
@@ -17,14 +16,10 @@
#include "base/strings/string_util.h"
#include "base/strings/utf_string_conversions.h"
#include "components/autofill/core/browser/autofill_type.h"
-#include "components/autofill/core/browser/data_model/autofill_structured_address_constants.h"
#include "components/autofill/core/browser/data_model/autofill_structured_address_utils.h"
#include "components/autofill/core/browser/field_types.h"
-#include "components/autofill/core/common/autofill_features.h"
-namespace autofill {
-
-namespace structured_address {
+namespace autofill::structured_address {
bool IsLessSignificantVerificationStatus(VerificationStatus left,
VerificationStatus right) {
@@ -217,6 +212,10 @@ const std::u16string& AddressComponent::GetValue() const {
return base::EmptyString16();
}
+absl::optional<std::u16string> AddressComponent::GetCanonicalizedValue() const {
+ return absl::nullopt;
+}
+
bool AddressComponent::IsValueAssigned() const {
return value_.has_value();
}
@@ -808,8 +807,10 @@ const std::vector<AddressToken> AddressComponent::GetSortedTokens() const {
bool AddressComponent::IsMergeableWithComponent(
const AddressComponent& newer_component) const {
- const std::u16string value = ValueForComparison(newer_component);
- const std::u16string value_newer = newer_component.ValueForComparison(*this);
+ const std::u16string older_comparison_value =
+ ValueForComparison(newer_component);
+ const std::u16string newer_comparison_value =
+ newer_component.ValueForComparison(*this);
// If both components are the same, there is nothing to do.
if (SameAs(newer_component))
@@ -820,18 +821,52 @@ bool AddressComponent::IsMergeableWithComponent(
return true;
}
- if ((merge_mode_ & kReplaceEmpty) && (value.empty() || value_newer.empty())) {
+ if ((merge_mode_ & kReplaceEmpty) &&
+ (older_comparison_value.empty() || newer_comparison_value.empty())) {
return true;
}
- if (merge_mode_ & kUseBetterOrNewerForSameValue) {
- if (base::ToUpperASCII(value) == base::ToUpperASCII(value_newer)) {
+ SortedTokenComparisonResult token_comparison_result =
+ CompareSortedTokens(older_comparison_value, newer_comparison_value);
+
+ bool comparison_values_are_substrings_of_each_other =
+ (older_comparison_value.find(newer_comparison_value) !=
+ std::u16string::npos ||
+ newer_comparison_value.find(older_comparison_value) !=
+ std::u16string::npos);
+
+ if (merge_mode_ & kMergeBasedOnCanonicalizedValues) {
+ absl::optional<std::u16string> older_canonical_value =
+ GetCanonicalizedValue();
+ absl::optional<std::u16string> newer_canonical_value =
+ newer_component.GetCanonicalizedValue();
+
+ bool older_has_canonical_value = older_canonical_value.has_value();
+ bool newer_has_canonical_value = newer_canonical_value.has_value();
+
+ // If both have a canonical value and the value is the same, they are
+ // obviously mergeable.
+ if (older_has_canonical_value && newer_has_canonical_value &&
+ older_canonical_value == newer_canonical_value) {
+ return true;
+ }
+
+ // If one value does not have canonicalized representation but the actual
+ // values are substrings of each other, or the tokens contain each other we
+ // will merge by just using the one with the canonicalized name.
+ if (older_has_canonical_value != newer_has_canonical_value &&
+ (comparison_values_are_substrings_of_each_other ||
+ token_comparison_result.ContainEachOther())) {
return true;
}
}
- SortedTokenComparisonResult token_comparison_result =
- CompareSortedTokens(value, value_newer);
+ if (merge_mode_ & kUseBetterOrNewerForSameValue) {
+ if (base::ToUpperASCII(older_comparison_value) ==
+ base::ToUpperASCII(newer_comparison_value)) {
+ return true;
+ }
+ }
if ((merge_mode_ & (kRecursivelyMergeTokenEquivalentValues |
kRecursivelyMergeSingleTokenSubset)) &&
@@ -859,8 +894,7 @@ bool AddressComponent::IsMergeableWithComponent(
// If the one value is a substring of the other, use the substring of the
// corresponding mode is active.
if ((merge_mode_ & kUseMostRecentSubstring) &&
- (value.find(value_newer) != std::u16string::npos ||
- value_newer.find(value) != std::u16string::npos)) {
+ comparison_values_are_substrings_of_each_other) {
return true;
}
@@ -893,6 +927,16 @@ bool AddressComponent::MergeWithComponent(
const std::u16string value = ValueForComparison(newer_component);
const std::u16string value_newer = newer_component.ValueForComparison(*this);
+
+ bool newer_component_has_better_or_equal_status =
+ !IsLessSignificantVerificationStatus(
+ newer_component.GetVerificationStatus(), GetVerificationStatus());
+ bool components_have_the_same_status =
+ GetVerificationStatus() == newer_component.GetVerificationStatus();
+ bool newer_component_has_better_status =
+ newer_component_has_better_or_equal_status &&
+ !components_have_the_same_status;
+
if (SameAs(newer_component))
return true;
@@ -933,8 +977,7 @@ bool AddressComponent::MergeWithComponent(
// Replace the subset with the superset if the corresponding mode is active.
if ((merge_mode_ & kReplaceSubset) && token_comparison_result.OneIsSubset()) {
if (token_comparison_result.status == SUBSET &&
- !IsLessSignificantVerificationStatus(
- newer_component.GetVerificationStatus(), GetVerificationStatus())) {
+ newer_component_has_better_or_equal_status) {
CopyFrom(newer_component);
}
return true;
@@ -952,8 +995,7 @@ bool AddressComponent::MergeWithComponent(
if ((merge_mode_ & (kReplaceSuperset | kReplaceSubset)) &&
token_comparison_result.status == MATCH) {
if (newer_was_more_recently_used &&
- !IsLessSignificantVerificationStatus(
- newer_component.GetVerificationStatus(), GetVerificationStatus())) {
+ newer_component_has_better_or_equal_status) {
CopyFrom(newer_component);
}
return true;
@@ -988,12 +1030,59 @@ bool AddressComponent::MergeWithComponent(
(value.find(value_newer) != std::u16string::npos ||
value_newer.find(value) != std::u16string::npos)) {
if (newer_was_more_recently_used &&
- !IsLessSignificantVerificationStatus(
- newer_component.GetVerificationStatus(), GetVerificationStatus()))
+ newer_component_has_better_or_equal_status) {
CopyFrom(newer_component);
+ }
return true;
}
+ bool comparison_values_are_substrings_of_each_other =
+ (value.find(value_newer) != std::u16string::npos ||
+ value_newer.find(value) != std::u16string::npos);
+
+ if (merge_mode_ & kMergeBasedOnCanonicalizedValues) {
+ absl::optional<std::u16string> canonical_value = GetCanonicalizedValue();
+ absl::optional<std::u16string> other_canonical_value =
+ newer_component.GetCanonicalizedValue();
+
+ bool this_has_canonical_value = canonical_value.has_value();
+ bool newer_has_canonical_value = other_canonical_value.has_value();
+
+ // When both have the same canonical value they are obviously mergeable.
+ if (canonical_value.has_value() && other_canonical_value.has_value() &&
+ *canonical_value == *other_canonical_value) {
+ // If the newer component has a better verification status use the newer
+ // one.
+ if (newer_component_has_better_status) {
+ CopyFrom(newer_component);
+ }
+ // If they have the same status use the shorter one.
+ if (components_have_the_same_status &&
+ newer_component.GetValue().size() <= GetValue().size()) {
+ CopyFrom(newer_component);
+ }
+ return true;
+ }
+
+ // If only one component has a canonicalized name but the actual values
+ // contain each other either tokens-wise or as substrings, use the component
+ // that has a canonicalized name unless the other component has a better
+ // verification status.
+ if (this_has_canonical_value != newer_has_canonical_value &&
+ (comparison_values_are_substrings_of_each_other ||
+ token_comparison_result.ContainEachOther())) {
+ // Copy the new component if it has a canoniscalized name and a status
+ // that is not worse of it if has a better stastus even if it is not
+ // canoniscalized.
+ if ((!this_has_canonical_value &&
+ newer_component_has_better_or_equal_status) ||
+ (this_has_canonical_value && newer_component_has_better_status)) {
+ CopyFrom(newer_component);
+ }
+ return true;
+ }
+ }
+
if ((merge_mode_ & kPickShorterIfOneContainsTheOther) &&
token_comparison_result.ContainEachOther()) {
if (newer_component.GetValue().size() <= GetValue().size() &&
@@ -1307,6 +1396,4 @@ std::u16string AddressComponent::ValueForComparison(
return NormalizedValue();
}
-} // namespace structured_address
-
-} // namespace autofill
+} // namespace autofill::structured_address
diff --git a/chromium/components/autofill/core/browser/data_model/autofill_structured_address_component.h b/chromium/components/autofill/core/browser/data_model/autofill_structured_address_component.h
index 5da2898e1c6..15e4ddf3b33 100644
--- a/chromium/components/autofill/core/browser/data_model/autofill_structured_address_component.h
+++ b/chromium/components/autofill/core/browser/data_model/autofill_structured_address_component.h
@@ -84,15 +84,17 @@ enum MergeMode {
kRecursivelyMergeSingleTokenSubset = 1 << 6,
// If one is a substring of the other use the most recent one.
kUseMostRecentSubstring = 1 << 7,
- // Merge the child nodes and reformat the node from its children after merge
- // if the value has changed.
+ // If the tokens match or one is a subset of the other, pick the shorter one.
kPickShorterIfOneContainsTheOther = 1 << 8,
// If the normalized values are different, use the better one in terms
// of verification score or the most recent one if both scores are the same.
kUseBetterOrMostRecentIfDifferent = 1 << 9,
- // Defines the default merging behavior.
+ // Merge the child nodes and reformat the node from its children after merge
+ // if the value has changed.
kMergeChildrenAndReformatIfNeeded = 1 << 10,
- // If the tokens match or one is a subset of the other, pick the shorter one.
+ // Make a merge decision based on canonicalized values.
+ kMergeBasedOnCanonicalizedValues = 1 << 11,
+ // Defines the default merging behavior.
kDefault = kRecursivelyMergeTokenEquivalentValues
};
@@ -182,6 +184,10 @@ class AddressComponent {
// assigned, an empty string is returned.
const std::u16string& GetValue() const;
+ // Returns a canonicalized version of the value or absl::nullopt if
+ // canonicalization is not possible or not implemented.
+ virtual absl::optional<std::u16string> GetCanonicalizedValue() const;
+
// Returns true if the value of this AddressComponent is assigned.
bool IsValueAssigned() const;
diff --git a/chromium/components/autofill/core/browser/data_model/autofill_structured_address_component_unittest.cc b/chromium/components/autofill/core/browser/data_model/autofill_structured_address_component_unittest.cc
index ec0fbf78877..b37dc253067 100644
--- a/chromium/components/autofill/core/browser/data_model/autofill_structured_address_component_unittest.cc
+++ b/chromium/components/autofill/core/browser/data_model/autofill_structured_address_component_unittest.cc
@@ -263,7 +263,7 @@ class TestNonProperFirstNameAddressComponent : public AddressComponent {
TestAtomicFirstNameAddressComponent second_name_first_node_{this};
};
-// Tests the merging of two atomic component with |type|, and vales
+// Tests the merging of two atomic component with |type|, and values
// |older_values| and |newer_values| respectively, and |merge_modes|.
// If |is_mergeable| it is expected that the two components are mergeable.
// If |newer_was_more_recently_used| the newer component was also more recently
diff --git a/chromium/components/autofill/core/browser/data_model/autofill_structured_address_unittest.cc b/chromium/components/autofill/core/browser/data_model/autofill_structured_address_unittest.cc
index 9a5b12693a7..a2bf928478a 100644
--- a/chromium/components/autofill/core/browser/data_model/autofill_structured_address_unittest.cc
+++ b/chromium/components/autofill/core/browser/data_model/autofill_structured_address_unittest.cc
@@ -12,8 +12,11 @@
#include "base/feature_list.h"
#include "base/strings/utf_string_conversions.h"
+#include "base/test/scoped_feature_list.h"
#include "components/autofill/core/browser/data_model/autofill_structured_address_test_utils.h"
#include "components/autofill/core/browser/data_model/autofill_structured_address_utils.h"
+#include "components/autofill/core/browser/geo/alternative_state_name_map.h"
+#include "components/autofill/core/browser/geo/alternative_state_name_map_test_utils.h"
#include "components/autofill/core/common/autofill_features.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -639,6 +642,133 @@ TEST(AutofillStructuredAddress, TestGetCommonCountryForMerge) {
EXPECT_EQ(country2.GetCommonCountryForMerge(country1), u"");
}
+struct MergeStatesWithCanonicalNamesTestCase {
+ std::string older_state;
+ VerificationStatus older_status;
+ std::string newer_state;
+ VerificationStatus newer_status;
+ std::string expectation;
+ bool is_mergeable;
+};
+
+class MergeStatesWithCanonicalNamesTest
+ : public testing::Test,
+ public testing::WithParamInterface<
+ MergeStatesWithCanonicalNamesTestCase> {
+ private:
+ void SetUp() override {
+ feature_list_.InitAndEnableFeature(
+ autofill::features::kAutofillUseAlternativeStateNameMap);
+
+ AlternativeStateNameMap::GetInstance()
+ ->ClearAlternativeStateNameMapForTesting();
+
+ autofill::test::PopulateAlternativeStateNameMapForTesting(
+ "XX", "CS",
+ {{.canonical_name = "CanonicalState",
+ .abbreviations = {"AS"},
+ .alternative_names = {"CoolState"}}});
+ autofill::test::PopulateAlternativeStateNameMapForTesting(
+ "XX", "OS",
+ {{.canonical_name = "OtherState",
+ .abbreviations = {"OS"},
+ .alternative_names = {""}}});
+ }
+
+ base::test::ScopedFeatureList feature_list_;
+};
+
+// Test that the correct country for merging structured addresses is computed.
+TEST_P(MergeStatesWithCanonicalNamesTest, MergeTest) {
+ MergeStatesWithCanonicalNamesTestCase test_case = GetParam();
+
+ AddressComponentTestValues older_values = {
+ {.type = ADDRESS_HOME_COUNTRY,
+ .value = "XX",
+ .status = VerificationStatus::kUserVerified},
+ {.type = ADDRESS_HOME_STATE,
+ .value = test_case.older_state,
+ .status = test_case.older_status},
+ };
+
+ AddressComponentTestValues newer_values = {
+ {.type = ADDRESS_HOME_COUNTRY,
+ .value = "XX",
+ .status = VerificationStatus::kUserVerified},
+ {.type = ADDRESS_HOME_STATE,
+ .value = test_case.newer_state,
+ .status = test_case.newer_status},
+ };
+
+ // In the expectations it is already assumed that the higher
+ // verification status should always win.
+ AddressComponentTestValues expectation_values = {
+ {.type = ADDRESS_HOME_COUNTRY,
+ .value = "XX",
+ .status = VerificationStatus::kUserVerified},
+ {.type = ADDRESS_HOME_STATE,
+ .value = test_case.expectation,
+ .status = IsLessSignificantVerificationStatus(test_case.older_status,
+ test_case.newer_status)
+ ? test_case.newer_status
+ : test_case.older_status},
+ };
+
+ Address older_address;
+ SetTestValues(&older_address, older_values);
+
+ Address newer_address;
+ SetTestValues(&newer_address, newer_values);
+
+ EXPECT_EQ(test_case.is_mergeable,
+ older_address.IsMergeableWithComponent(newer_address));
+
+ Address expectation_address;
+ SetTestValues(&expectation_address, expectation_values);
+
+ older_address.MergeWithComponent(newer_address);
+ EXPECT_TRUE(older_address.SameAs(expectation_address));
+};
+
+INSTANTIATE_TEST_SUITE_P(
+ AutofillStructuredAddress,
+ MergeStatesWithCanonicalNamesTest,
+ ::testing::Values(
+
+ // Both have the same canonical name but the older one has the better
+ // status and should win in the merge.
+ MergeStatesWithCanonicalNamesTestCase{
+ "CanonicalState", VerificationStatus::kUserVerified, "CoolState",
+ VerificationStatus::kParsed, "CanonicalState", true},
+
+ // Both have the same canonical name but the newer one has the better
+ // status and should win in the merge.
+ MergeStatesWithCanonicalNamesTestCase{
+ "CanonicalState", VerificationStatus::kObserved, "CoolState",
+ VerificationStatus::kUserVerified, "CoolState", true},
+
+ // The newer one has no canonical name but the value is a substring of
+ // the older one. The older has a higher status and should win.
+ MergeStatesWithCanonicalNamesTestCase{
+ "CanonicalState", VerificationStatus::kUserVerified, "state",
+ VerificationStatus::kParsed, "CanonicalState", true},
+
+ // The other way round: Now the old one remains because it is a
+ // substring and has the better status.
+ MergeStatesWithCanonicalNamesTestCase{
+ "state", VerificationStatus::kUserVerified, "CanonicalState",
+ VerificationStatus::kParsed, "state", true},
+
+ // Those two are not mergeable but both have a canonical name.
+ MergeStatesWithCanonicalNamesTestCase{
+ "CanonicalState", VerificationStatus::kUserVerified, "OtherState",
+ VerificationStatus::kParsed, "CanonicalState", false},
+
+ // Here the newer one does not have a canonical test.
+ MergeStatesWithCanonicalNamesTestCase{
+ "CanonicalState", VerificationStatus::kUserVerified, "Random",
+ VerificationStatus::kParsed, "CanonicalState", false}));
+
} // namespace
} // namespace structured_address
} // namespace autofill
diff --git a/chromium/components/autofill/core/browser/data_model/birthdate.cc b/chromium/components/autofill/core/browser/data_model/birthdate.cc
index ce34cf2415d..09bf0d95d9a 100644
--- a/chromium/components/autofill/core/browser/data_model/birthdate.cc
+++ b/chromium/components/autofill/core/browser/data_model/birthdate.cc
@@ -22,7 +22,7 @@ std::u16string Birthdate::GetRawInfo(ServerFieldType type) const {
switch (type) {
case BIRTHDATE_DAY:
case BIRTHDATE_MONTH:
- case BIRTHDATE_YEAR_4_DIGITS: {
+ case BIRTHDATE_4_DIGIT_YEAR: {
int value = GetRawInfoAsInt(type);
return value != 0 ? base::NumberToString16(value) : std::u16string();
}
@@ -38,7 +38,7 @@ int Birthdate::GetRawInfoAsInt(ServerFieldType type) const {
return day_;
case BIRTHDATE_MONTH:
return month_;
- case BIRTHDATE_YEAR_4_DIGITS:
+ case BIRTHDATE_4_DIGIT_YEAR:
return year_;
default:
NOTREACHED();
@@ -54,7 +54,7 @@ void Birthdate::SetRawInfoWithVerificationStatus(ServerFieldType type,
switch (type) {
case BIRTHDATE_DAY:
case BIRTHDATE_MONTH:
- case BIRTHDATE_YEAR_4_DIGITS: {
+ case BIRTHDATE_4_DIGIT_YEAR: {
// If |value| is not a number, |StringToInt()| sets it to 0, which will
// clear the field.
int int_value;
@@ -83,7 +83,7 @@ void Birthdate::SetRawInfoAsIntWithVerificationStatus(
case BIRTHDATE_MONTH:
month_ = ValueIfInRangeOrZero(1, 12);
break;
- case BIRTHDATE_YEAR_4_DIGITS:
+ case BIRTHDATE_4_DIGIT_YEAR:
year_ = ValueIfInRangeOrZero(1900, 9999);
break;
default:
@@ -94,7 +94,7 @@ void Birthdate::SetRawInfoAsIntWithVerificationStatus(
void Birthdate::GetSupportedTypes(ServerFieldTypeSet* supported_types) const {
supported_types->insert(BIRTHDATE_DAY);
supported_types->insert(BIRTHDATE_MONTH);
- supported_types->insert(BIRTHDATE_YEAR_4_DIGITS);
+ supported_types->insert(BIRTHDATE_4_DIGIT_YEAR);
}
} // namespace autofill
diff --git a/chromium/components/autofill/core/browser/data_model/birthdate.h b/chromium/components/autofill/core/browser/data_model/birthdate.h
index ec07d067f55..a18555aea57 100644
--- a/chromium/components/autofill/core/browser/data_model/birthdate.h
+++ b/chromium/components/autofill/core/browser/data_model/birthdate.h
@@ -25,7 +25,7 @@ class Birthdate : public FormGroup {
// Convenience accessor to the day, month and 4 digit year components.
static ServerFieldTypeSet GetRawComponents() {
- return {BIRTHDATE_DAY, BIRTHDATE_MONTH, BIRTHDATE_YEAR_4_DIGITS};
+ return {BIRTHDATE_DAY, BIRTHDATE_MONTH, BIRTHDATE_4_DIGIT_YEAR};
}
// FormGroup:
diff --git a/chromium/components/autofill/core/browser/data_model/birthdate_unittest.cc b/chromium/components/autofill/core/browser/data_model/birthdate_unittest.cc
index 819e63f4591..17554223d83 100644
--- a/chromium/components/autofill/core/browser/data_model/birthdate_unittest.cc
+++ b/chromium/components/autofill/core/browser/data_model/birthdate_unittest.cc
@@ -16,7 +16,7 @@ Birthdate CreateBirthdate(const std::u16string& day,
Birthdate birthdate;
birthdate.SetRawInfo(BIRTHDATE_DAY, day);
birthdate.SetRawInfo(BIRTHDATE_MONTH, month);
- birthdate.SetRawInfo(BIRTHDATE_YEAR_4_DIGITS, year);
+ birthdate.SetRawInfo(BIRTHDATE_4_DIGIT_YEAR, year);
return birthdate;
}
@@ -26,7 +26,7 @@ void VerifyValues(const Birthdate& birthdate,
const std::u16string& year) {
EXPECT_EQ(birthdate.GetRawInfo(BIRTHDATE_DAY), day);
EXPECT_EQ(birthdate.GetRawInfo(BIRTHDATE_MONTH), month);
- EXPECT_EQ(birthdate.GetRawInfo(BIRTHDATE_YEAR_4_DIGITS), year);
+ EXPECT_EQ(birthdate.GetRawInfo(BIRTHDATE_4_DIGIT_YEAR), year);
}
// Expect that setting |field| to |value| clears the |field|. This is used to
@@ -61,8 +61,8 @@ TEST(BirthdateTest, Validation) {
SetFieldAndExpectEmpty(BIRTHDATE_DAY, u"NaN");
SetFieldAndExpectEmpty(BIRTHDATE_MONTH, u"13");
SetFieldAndExpectEmpty(BIRTHDATE_MONTH, u"a");
- SetFieldAndExpectEmpty(BIRTHDATE_YEAR_4_DIGITS, u"12345");
- SetFieldAndExpectEmpty(BIRTHDATE_YEAR_4_DIGITS, u"1234");
+ SetFieldAndExpectEmpty(BIRTHDATE_4_DIGIT_YEAR, u"12345");
+ SetFieldAndExpectEmpty(BIRTHDATE_4_DIGIT_YEAR, u"1234");
}
// Tests that empty values clear the corresponding fields.
diff --git a/chromium/components/autofill/core/browser/data_model/contact_info.cc b/chromium/components/autofill/core/browser/data_model/contact_info.cc
index 1e734b70666..988c42ce088 100644
--- a/chromium/components/autofill/core/browser/data_model/contact_info.cc
+++ b/chromium/components/autofill/core/browser/data_model/contact_info.cc
@@ -13,12 +13,12 @@
#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_regexes.h"
#include "components/autofill/core/browser/autofill_type.h"
#include "components/autofill/core/browser/data_model/autofill_profile.h"
#include "components/autofill/core/browser/data_model/autofill_structured_address_utils.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 {
@@ -381,16 +381,15 @@ void CompanyInfo::SetRawInfoWithVerificationStatus(ServerFieldType type,
}
bool CompanyInfo::IsValidOrVerified(const std::u16string& value) const {
- // TODO(crbug/1117296): retrieve regular expressions dynamically.
- static const char* kBirthyearRe = "^(19|20)\\d{2}$";
- static const char* kSocialTitleRe =
- "^(Ms\\.?|Mrs\\.?|Mr\\.?|Miss|Mistress|Mister|"
- "Frau|Herr|"
- "Mlle|Mme|M\\.|"
- "Dr\\.?|Prof\\.?)$";
+ static constexpr char16_t kBirthyearRe[] = u"^(19|20)\\d{2}$";
+ static constexpr char16_t kSocialTitleRe[] =
+ u"^(Ms\\.?|Mrs\\.?|Mr\\.?|Miss|Mistress|Mister|"
+ u"Frau|Herr|"
+ u"Mlle|Mme|M\\.|"
+ u"Dr\\.?|Prof\\.?)$";
return (profile_ && profile_->IsVerified()) ||
- (!MatchesPattern(value, base::UTF8ToUTF16(kBirthyearRe)) &&
- !MatchesPattern(value, base::UTF8ToUTF16(kSocialTitleRe)));
+ (!MatchesRegex<kBirthyearRe>(value) &&
+ !MatchesRegex<kSocialTitleRe>(value));
}
} // namespace autofill
diff --git a/chromium/components/autofill/core/browser/data_model/credit_card.cc b/chromium/components/autofill/core/browser/data_model/credit_card.cc
index b9e126b5f38..a357783fc89 100644
--- a/chromium/components/autofill/core/browser/data_model/credit_card.cc
+++ b/chromium/components/autofill/core/browser/data_model/credit_card.cc
@@ -24,7 +24,6 @@
#include "build/build_config.h"
#include "components/autofill/core/browser/autofill_data_util.h"
#include "components/autofill/core/browser/autofill_field.h"
-#include "components/autofill/core/browser/autofill_regexes.h"
#include "components/autofill/core/browser/autofill_type.h"
#include "components/autofill/core/browser/data_model/autofill_metadata.h"
#include "components/autofill/core/browser/data_model/data_model_utils.h"
@@ -34,6 +33,7 @@
#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_regexes.h"
#include "components/autofill/core/common/form_field_data.h"
#include "components/grit/components_scaled_resources.h"
#include "components/strings/grit/components_strings.h"
@@ -403,7 +403,7 @@ double CreditCard::GetRankingScore(base::Time current_time) const {
return AutofillDataModel::GetRankingScore(current_time) + virtual_card_boost;
}
-bool CreditCard::SetMetadata(const AutofillMetadata metadata) {
+bool CreditCard::SetMetadata(const AutofillMetadata& metadata) {
// Make sure the ids matches.
if (metadata.id != (record_type_ == LOCAL_CARD ? guid() : server_id_))
return false;
@@ -563,8 +563,9 @@ void CreditCard::GetMatchingTypes(const std::u16string& text,
}
void CreditCard::SetInfoForMonthInputType(const std::u16string& value) {
+ static constexpr char16_t kDateRegex[] = u"^[0-9]{4}-[0-9]{1,2}$";
// Check if |text| is "yyyy-mm" format first, and check normal month format.
- if (!MatchesPattern(value, u"^[0-9]{4}-[0-9]{1,2}$"))
+ if (!MatchesRegex<kDateRegex>(value))
return;
std::vector<base::StringPiece16> year_month = base::SplitStringPiece(
@@ -819,10 +820,12 @@ bool CreditCard::SetExpirationYearFromString(const std::u16string& text) {
}
void CreditCard::SetExpirationDateFromString(const std::u16string& text) {
+ static constexpr char16_t kDateRegex[] =
+ uR"(^\s*[0-9]{1,2}\s*[-/|]?\s*[0-9]{2,4}\s*$)";
// Check that |text| fits the supported patterns: mmyy, mmyyyy, m-yy,
// mm-yy, m-yyyy and mm-yyyy. Note that myy and myyyy matched by this pattern
// but are not supported (ambiguous). Separators: -, / and |.
- if (!MatchesPattern(text, uR"(^\s*[0-9]{1,2}\s*[-/|]?\s*[0-9]{2,4}\s*$)"))
+ if (!MatchesRegex<kDateRegex>(text))
return;
std::u16string month;
@@ -863,9 +866,7 @@ void CreditCard::SetExpirationDateFromString(const std::u16string& text) {
SetExpirationYear(num);
}
-const std::pair<std::u16string, std::u16string> CreditCard::LabelPieces()
- const {
- std::u16string label;
+std::pair<std::u16string, std::u16string> CreditCard::LabelPieces() const {
if (number().empty()) {
// No CC number, if valid nickname is present, return nickname only.
// Otherwise, return cardholder name only.
@@ -875,22 +876,16 @@ const std::pair<std::u16string, std::u16string> CreditCard::LabelPieces()
return std::make_pair(name_on_card_, std::u16string());
}
- std::u16string obfuscated_cc_number =
- CardIdentifierStringForAutofillDisplay();
- // No expiration date set.
- if (!expiration_month_ || !expiration_year_)
- return std::make_pair(obfuscated_cc_number, std::u16string());
-
- std::u16string formatted_date = ExpirationDateForDisplay();
-
- std::u16string separator =
- l10n_util::GetStringUTF16(IDS_AUTOFILL_ADDRESS_SUMMARY_SEPARATOR);
- return std::make_pair(obfuscated_cc_number, separator + formatted_date);
+ return std::make_pair(CardIdentifierStringForAutofillDisplay(),
+ name_on_card_);
}
-const std::u16string CreditCard::Label() const {
+std::u16string CreditCard::Label() const {
std::pair<std::u16string, std::u16string> pieces = LabelPieces();
- return pieces.first + pieces.second;
+ if (pieces.first.empty() || pieces.second.empty())
+ return pieces.first + pieces.second;
+
+ return pieces.first + u", " + pieces.second;
}
std::u16string CreditCard::LastFourDigits() const {
@@ -949,6 +944,12 @@ std::u16string CreditCard::CardIdentifierStringForAutofillDisplay(
int obfuscation_length) const {
if (HasNonEmptyValidNickname() || !customized_nickname.empty()) {
return NicknameAndLastFourDigits(customized_nickname, obfuscation_length);
+ } else if (base::FeatureList::IsEnabled(
+ features::kAutofillEnableCardProductName) &&
+ !product_description_.empty()) {
+ // If product description is available, format card label as 'Product
+ // description ****2345'.
+ return ProductDescriptionAndLastFourdigits(obfuscation_length);
}
return NetworkAndLastFourDigits(obfuscation_length);
}
@@ -1113,6 +1114,18 @@ std::u16string CreditCard::NicknameAndLastFourDigits(
internal::GetObfuscatedStringForCardDigits(digits, obfuscation_length);
}
+std::u16string CreditCard::ProductDescriptionAndLastFourdigits(
+ int obfuscation_length) const {
+ DCHECK(!product_description_.empty());
+ const std::u16string digits = LastFourDigits();
+ // If digits are empty, return product description.
+ if (digits.empty())
+ return product_description_;
+
+ return product_description_ + u" " +
+ internal::GetObfuscatedStringForCardDigits(digits, obfuscation_length);
+}
+
void CreditCard::SetNumber(const std::u16string& number) {
number_ = number;
diff --git a/chromium/components/autofill/core/browser/data_model/credit_card.h b/chromium/components/autofill/core/browser/data_model/credit_card.h
index 44a74f8ae28..cb8daaf72fb 100644
--- a/chromium/components/autofill/core/browser/data_model/credit_card.h
+++ b/chromium/components/autofill/core/browser/data_model/credit_card.h
@@ -134,7 +134,7 @@ class CreditCard : public AutofillDataModel {
// AutofillDataModel:
AutofillMetadata GetMetadata() const override;
double GetRankingScore(base::Time current_time) const override;
- bool SetMetadata(const AutofillMetadata metadata) override;
+ bool SetMetadata(const AutofillMetadata& metadata) override;
// Returns whether the card is deletable: if it is expired and has not been
// used for longer than |kDisusedCreditCardDeletionTimeDelta|.
bool IsDeletable() const override;
@@ -275,11 +275,11 @@ class CreditCard : public AutofillDataModel {
// Various display functions.
- // Card preview summary, for example: "Nickname/Network - ****1234",
- // ", 01/2020".
- const std::pair<std::u16string, std::u16string> LabelPieces() const;
+ // Card preview summary, for example: "Nickname/Network - ****1234 John
+ // Smith".
+ std::pair<std::u16string, std::u16string> LabelPieces() const;
// Like LabelPieces, but appends the two pieces together.
- const std::u16string Label() const;
+ std::u16string Label() const;
// The last four digits of the card number (or possibly less if there aren't
// enough characters).
std::u16string LastFourDigits() const;
@@ -403,6 +403,12 @@ class CreditCard : public AutofillDataModel {
std::u16string customized_nickname = std::u16string(),
int obfuscation_length = 4) const;
+ // A label for the card formatted as 'Product description ****LastFour' like
+ // 'ABC Bank XYZ Card ****1234'. Check that product description exists before
+ // calling this method. By default, the `obfuscation_length` is set to 4.
+ std::u16string ProductDescriptionAndLastFourdigits(
+ int obfuscation_length = 4) const;
+
// Sets the name_on_card_ value based on the saved name parts.
void SetNameOnCardFromSeparateParts();
diff --git a/chromium/components/autofill/core/browser/data_model/credit_card_unittest.cc b/chromium/components/autofill/core/browser/data_model/credit_card_unittest.cc
index 7b8c201f425..3e704144d4d 100644
--- a/chromium/components/autofill/core/browser/data_model/credit_card_unittest.cc
+++ b/chromium/components/autofill/core/browser/data_model/credit_card_unittest.cc
@@ -103,81 +103,133 @@ TEST(CreditCardTest, GetObfuscatedStringForCardDigits) {
// Tests credit card summary string generation. This test simulates a variety
// of different possible summary strings. Variations occur based on the
// existence of credit card number, month, and year fields.
-TEST(CreditCardTest, PreviewSummaryAndNetworkAndLastFourDigitsStrings) {
+TEST(CreditCardTest, LabelSummary) {
std::u16string valid_nickname = u"My Visa Card";
// Case 0: empty credit card.
CreditCard credit_card0(base::GenerateGUID(), "https://www.example.com/");
- std::u16string summary0 = credit_card0.Label();
- EXPECT_EQ(std::u16string(), summary0);
- std::u16string obfuscated0 = credit_card0.NetworkAndLastFourDigits();
- EXPECT_EQ(ASCIIToUTF16(std::string("Card")), obfuscated0);
+ EXPECT_EQ(std::u16string(), credit_card0.Label());
// Case 00: Empty credit card with empty strings.
CreditCard credit_card00(base::GenerateGUID(), "https://www.example.com/");
test::SetCreditCardInfo(&credit_card00, "John Dillinger", "", "", "", "");
- std::u16string summary00 = credit_card00.Label();
- EXPECT_EQ(std::u16string(u"John Dillinger"), summary00);
- std::u16string obfuscated00 = credit_card00.NetworkAndLastFourDigits();
- EXPECT_EQ(ASCIIToUTF16(std::string("Card")), obfuscated00);
+ EXPECT_EQ(std::u16string(u"John Dillinger"), credit_card00.Label());
// Case 1: No credit card number.
CreditCard credit_card1(base::GenerateGUID(), "https://www.example.com/");
test::SetCreditCardInfo(&credit_card1, "John Dillinger", "", "01", "2010",
"1");
- std::u16string summary1 = credit_card1.Label();
- EXPECT_EQ(std::u16string(u"John Dillinger"), summary1);
- std::u16string obfuscated1 = credit_card1.NetworkAndLastFourDigits();
- EXPECT_EQ(ASCIIToUTF16(std::string("Card")), obfuscated1);
+ EXPECT_EQ(std::u16string(u"John Dillinger"), credit_card1.Label());
// Case 1.1: No credit card number, but has nickname.
CreditCard credit_card11(base::GenerateGUID(), "https://www.example.com/");
test::SetCreditCardInfo(&credit_card11, "John Dillinger", "", "01", "2010",
"1");
credit_card11.SetNickname(valid_nickname);
- std::u16string summary11 = credit_card11.Label();
- EXPECT_EQ(valid_nickname, summary11);
- std::u16string obfuscated11 = credit_card11.NetworkAndLastFourDigits();
- EXPECT_EQ(ASCIIToUTF16(std::string("Card")), obfuscated11);
+ EXPECT_EQ(valid_nickname, credit_card11.Label());
// Case 2: No month.
CreditCard credit_card2(base::GenerateGUID(), "https://www.example.com/");
test::SetCreditCardInfo(&credit_card2, "John Dillinger",
"5105 1051 0510 5100", "", "2010", "1");
- std::u16string summary2 = credit_card2.Label();
EXPECT_EQ(UTF8ToUTF16(std::string("Mastercard ") +
- test::ObfuscatedCardDigitsAsUTF8("5100")),
- summary2);
- std::u16string obfuscated2 = credit_card2.NetworkAndLastFourDigits();
- EXPECT_EQ(UTF8ToUTF16(std::string("Mastercard ") +
- test::ObfuscatedCardDigitsAsUTF8("5100")),
- obfuscated2);
+ test::ObfuscatedCardDigitsAsUTF8("5100") +
+ ", John Dillinger"),
+ credit_card2.Label());
// Case 3: No year.
CreditCard credit_card3(base::GenerateGUID(), "https://www.example.com/");
test::SetCreditCardInfo(&credit_card3, "John Dillinger",
"5105 1051 0510 5100", "01", "", "1");
- std::u16string summary3 = credit_card3.Label();
+ EXPECT_EQ(UTF8ToUTF16(std::string("Mastercard ") +
+ test::ObfuscatedCardDigitsAsUTF8("5100") +
+ ", John Dillinger"),
+ credit_card3.Label());
+
+ // Case 4: Have everything except nickname.
+ CreditCard credit_card4(base::GenerateGUID(), "https://www.example.com/");
+ test::SetCreditCardInfo(&credit_card4, "John Dillinger",
+ "5105 1051 0510 5100", "01", "2010", "1");
+ EXPECT_EQ(UTF8ToUTF16(std::string("Mastercard ") +
+ test::ObfuscatedCardDigitsAsUTF8("5100") +
+ ", John Dillinger"),
+ credit_card4.Label());
+
+ // Case 5: Very long credit card
+ CreditCard credit_card5(base::GenerateGUID(), "https://www.example.com/");
+ test::SetCreditCardInfo(
+ &credit_card5, "John Dillinger",
+ "0123456789 0123456789 0123456789 5105 1051 0510 5100", "01", "2010",
+ "1");
+ EXPECT_EQ(UTF8ToUTF16(std::string("Card ") +
+ test::ObfuscatedCardDigitsAsUTF8("5100") +
+ ", John Dillinger"),
+ credit_card5.Label());
+
+ // Case 6: Have everything including nickname.
+ CreditCard credit_card6(base::GenerateGUID(), "https://www.example.com/");
+ test::SetCreditCardInfo(&credit_card6, "John Dillinger",
+ "5105 1051 0510 5100", "01", "2010", "1");
+ credit_card6.SetNickname(valid_nickname);
+ EXPECT_EQ(
+ valid_nickname + UTF8ToUTF16(std::string(" ") +
+ test::ObfuscatedCardDigitsAsUTF8("5100") +
+ ", John Dillinger"),
+ credit_card6.Label());
+}
+
+TEST(CreditCardTest, NetworkAndLastFourDigits) {
+ std::u16string valid_nickname = u"My Visa Card";
+
+ // Case 0: empty credit card.
+ CreditCard credit_card0(base::GenerateGUID(), "https://www.example.com/");
+ EXPECT_EQ(ASCIIToUTF16(std::string("Card")),
+ credit_card0.NetworkAndLastFourDigits());
+
+ // Case 00: Empty credit card with empty strings.
+ CreditCard credit_card00(base::GenerateGUID(), "https://www.example.com/");
+ test::SetCreditCardInfo(&credit_card00, "John Dillinger", "", "", "", "");
+ EXPECT_EQ(ASCIIToUTF16(std::string("Card")),
+ credit_card00.NetworkAndLastFourDigits());
+
+ // Case 1: No credit card number.
+ CreditCard credit_card1(base::GenerateGUID(), "https://www.example.com/");
+ test::SetCreditCardInfo(&credit_card1, "John Dillinger", "", "01", "2010",
+ "1");
+ EXPECT_EQ(ASCIIToUTF16(std::string("Card")),
+ credit_card1.NetworkAndLastFourDigits());
+
+ // Case 1.1: No credit card number, but has nickname.
+ CreditCard credit_card11(base::GenerateGUID(), "https://www.example.com/");
+ test::SetCreditCardInfo(&credit_card11, "John Dillinger", "", "01", "2010",
+ "1");
+ credit_card11.SetNickname(valid_nickname);
+ EXPECT_EQ(ASCIIToUTF16(std::string("Card")),
+ credit_card11.NetworkAndLastFourDigits());
+
+ // Case 2: No month.
+ CreditCard credit_card2(base::GenerateGUID(), "https://www.example.com/");
+ test::SetCreditCardInfo(&credit_card2, "John Dillinger",
+ "5105 1051 0510 5100", "", "2010", "1");
EXPECT_EQ(UTF8ToUTF16(std::string("Mastercard ") +
test::ObfuscatedCardDigitsAsUTF8("5100")),
- summary3);
- std::u16string obfuscated3 = credit_card3.NetworkAndLastFourDigits();
+ credit_card2.NetworkAndLastFourDigits());
+
+ // Case 3: No year.
+ CreditCard credit_card3(base::GenerateGUID(), "https://www.example.com/");
+ test::SetCreditCardInfo(&credit_card3, "John Dillinger",
+ "5105 1051 0510 5100", "01", "", "1");
EXPECT_EQ(UTF8ToUTF16(std::string("Mastercard ") +
test::ObfuscatedCardDigitsAsUTF8("5100")),
- obfuscated3);
+ credit_card3.NetworkAndLastFourDigits());
// Case 4: Have everything except nickname.
CreditCard credit_card4(base::GenerateGUID(), "https://www.example.com/");
test::SetCreditCardInfo(&credit_card4, "John Dillinger",
"5105 1051 0510 5100", "01", "2010", "1");
- std::u16string summary4 = credit_card4.Label();
- EXPECT_EQ(UTF8ToUTF16(std::string("Mastercard ") +
- test::ObfuscatedCardDigitsAsUTF8("5100") + ", 01/2010"),
- summary4);
- std::u16string obfuscated4 = credit_card4.NetworkAndLastFourDigits();
EXPECT_EQ(UTF8ToUTF16(std::string("Mastercard ") +
test::ObfuscatedCardDigitsAsUTF8("5100")),
- obfuscated4);
+ credit_card4.NetworkAndLastFourDigits());
// Case 5: Very long credit card
CreditCard credit_card5(base::GenerateGUID(), "https://www.example.com/");
@@ -185,26 +237,18 @@ TEST(CreditCardTest, PreviewSummaryAndNetworkAndLastFourDigitsStrings) {
&credit_card5, "John Dillinger",
"0123456789 0123456789 0123456789 5105 1051 0510 5100", "01", "2010",
"1");
- std::u16string summary5 = credit_card5.Label();
- EXPECT_EQ(UTF8ToUTF16(std::string("Card ") +
- test::ObfuscatedCardDigitsAsUTF8("5100") + ", 01/2010"),
- summary5);
- std::u16string obfuscated5 = credit_card5.NetworkAndLastFourDigits();
EXPECT_EQ(UTF8ToUTF16(std::string("Card ") +
test::ObfuscatedCardDigitsAsUTF8("5100")),
- obfuscated5);
+ credit_card5.NetworkAndLastFourDigits());
// Case 6: Have everything including nickname.
CreditCard credit_card6(base::GenerateGUID(), "https://www.example.com/");
test::SetCreditCardInfo(&credit_card6, "John Dillinger",
"5105 1051 0510 5100", "01", "2010", "1");
credit_card6.SetNickname(valid_nickname);
- std::u16string summary6 = credit_card6.Label();
- EXPECT_EQ(
- valid_nickname +
- UTF8ToUTF16(std::string(" ") +
- test::ObfuscatedCardDigitsAsUTF8("5100") + ", 01/2010"),
- summary6);
+ EXPECT_EQ(UTF8ToUTF16(std::string("Mastercard ") +
+ test::ObfuscatedCardDigitsAsUTF8("5100")),
+ credit_card6.NetworkAndLastFourDigits());
}
TEST(CreditCardTest, NicknameAndLastFourDigitsStrings) {
@@ -228,33 +272,153 @@ TEST(CreditCardTest, NicknameAndLastFourDigitsStrings) {
credit_card2.NicknameAndLastFourDigitsForTesting());
}
-TEST(CreditCardTest, CardIdentifierStringsForAutofillDisplay) {
+// Test that card identifier string falls back to issuer network when both
+// nickname and product description are unavailable.
+TEST(CreditCardTest,
+ CardIdentifierStringsForAutofillDisplay_NoNicknameNoProductDescription) {
base::test::ScopedFeatureList scoped_feature_list;
- std::u16string valid_nickname = u"My Visa Card";
- std::u16string invalid_nickname = u"Nickname length exceeds 25 characters";
+ scoped_feature_list.InitAndEnableFeature(
+ features::kAutofillEnableCardProductName);
- // Case 1: Nickname name is invalid -> show network name.
- CreditCard credit_card1(base::GenerateGUID(), "https://www.example.com/");
- test::SetCreditCardInfo(&credit_card1, "John Dillinger",
+ CreditCard credit_card(base::GenerateGUID(), "https://www.example.com/");
+ test::SetCreditCardInfo(&credit_card, "John Dillinger",
"5105 1051 0510 5100" /* Mastercard */, "01", "2020",
"1");
- credit_card1.SetNickname(invalid_nickname);
- EXPECT_FALSE(credit_card1.HasNonEmptyValidNickname());
+ EXPECT_FALSE(credit_card.HasNonEmptyValidNickname());
EXPECT_EQ(UTF8ToUTF16(std::string("Mastercard ") +
test::ObfuscatedCardDigitsAsUTF8("5100")),
- credit_card1.CardIdentifierStringForAutofillDisplay());
+ credit_card.CardIdentifierStringForAutofillDisplay());
+}
- // Case 2: Experiment is on and nickname is valid -> show nickname.
- CreditCard credit_card2(base::GenerateGUID(), "https://www.example.com/");
- test::SetCreditCardInfo(&credit_card2, "John Dillinger",
+// Test that card identifier string falls back to issuer network when nickname
+// is invalid and product description is unavailable.
+TEST(
+ CreditCardTest,
+ CardIdentifierStringsForAutofillDisplay_InvalidNicknameNoProductDescription) {
+ base::test::ScopedFeatureList scoped_feature_list;
+ scoped_feature_list.InitAndEnableFeature(
+ features::kAutofillEnableCardProductName);
+
+ CreditCard credit_card(base::GenerateGUID(), "https://www.example.com/");
+ test::SetCreditCardInfo(&credit_card, "John Dillinger",
"5105 1051 0510 5100" /* Mastercard */, "01", "2020",
"1");
- credit_card2.SetNickname(valid_nickname);
- EXPECT_TRUE(credit_card2.HasNonEmptyValidNickname());
+ credit_card.SetNickname(u"Nickname length exceeds 25 characters");
+ EXPECT_FALSE(credit_card.HasNonEmptyValidNickname());
+ EXPECT_EQ(UTF8ToUTF16(std::string("Mastercard ") +
+ test::ObfuscatedCardDigitsAsUTF8("5100")),
+ credit_card.CardIdentifierStringForAutofillDisplay());
+}
+
+// Test that card identifier string falls back to product description when
+// nickname is unavailable.
+TEST(CreditCardTest,
+ CardIdentifierStringsForAutofillDisplay_NoNicknameWithProductDescription) {
+ base::test::ScopedFeatureList scoped_feature_list;
+ scoped_feature_list.InitAndEnableFeature(
+ features::kAutofillEnableCardProductName);
+
+ std::u16string product_description = u"ABC bank XYZ card";
+
+ CreditCard credit_card(base::GenerateGUID(), "https://www.example.com/");
+ test::SetCreditCardInfo(&credit_card, "John Dillinger",
+ "5105 1051 0510 5100" /* Mastercard */, "01", "2020",
+ "1");
+ credit_card.set_product_description(product_description);
+ EXPECT_FALSE(credit_card.HasNonEmptyValidNickname());
+ EXPECT_EQ(product_description +
+ UTF8ToUTF16(std::string(" ") +
+ test::ObfuscatedCardDigitsAsUTF8("5100")),
+ credit_card.CardIdentifierStringForAutofillDisplay());
+}
+
+// Test that card identifier string falls back to product description when
+// nickname is invalid.
+TEST(
+ CreditCardTest,
+ CardIdentifierStringsForAutofillDisplay_InvalidNicknameWithProductDescription) {
+ base::test::ScopedFeatureList scoped_feature_list;
+ scoped_feature_list.InitAndEnableFeature(
+ features::kAutofillEnableCardProductName);
+
+ std::u16string product_description = u"ABC bank XYZ card";
+
+ CreditCard credit_card(base::GenerateGUID(), "https://www.example.com/");
+ test::SetCreditCardInfo(&credit_card, "John Dillinger",
+ "5105 1051 0510 5100" /* Mastercard */, "01", "2020",
+ "1");
+ credit_card.SetNickname(u"Nickname length exceeds 25 characters");
+ credit_card.set_product_description(product_description);
+ EXPECT_FALSE(credit_card.HasNonEmptyValidNickname());
+ EXPECT_EQ(product_description +
+ UTF8ToUTF16(std::string(" ") +
+ test::ObfuscatedCardDigitsAsUTF8("5100")),
+ credit_card.CardIdentifierStringForAutofillDisplay());
+}
+
+// Test that card identifier string shows nickname when it is valid.
+TEST(CreditCardTest,
+ CardIdentifierStringsForAutofillDisplay_WithValidNickname) {
+ base::test::ScopedFeatureList scoped_feature_list;
+ scoped_feature_list.InitAndEnableFeature(
+ features::kAutofillEnableCardProductName);
+
+ std::u16string valid_nickname = u"My Visa Card";
+
+ CreditCard credit_card(base::GenerateGUID(), "https://www.example.com/");
+ test::SetCreditCardInfo(&credit_card, "John Dillinger",
+ "5105 1051 0510 5100" /* Mastercard */, "01", "2020",
+ "1");
+ credit_card.SetNickname(valid_nickname);
+ credit_card.set_product_description(u"ABC bank XYZ card");
+ EXPECT_TRUE(credit_card.HasNonEmptyValidNickname());
EXPECT_EQ(
valid_nickname + UTF8ToUTF16(std::string(" ") +
test::ObfuscatedCardDigitsAsUTF8("5100")),
- credit_card2.CardIdentifierStringForAutofillDisplay());
+ credit_card.CardIdentifierStringForAutofillDisplay());
+}
+
+// Test that customized nickname takes precedence over credit card's nickname.
+TEST(CreditCardTest,
+ CardIdentifierStringsForAutofillDisplay_WithCustomizedNickname) {
+ base::test::ScopedFeatureList scoped_feature_list;
+ scoped_feature_list.InitAndEnableFeature(
+ features::kAutofillEnableCardProductName);
+
+ std::u16string customized_nickname = u"My grocery shopping Visa card";
+
+ CreditCard credit_card(base::GenerateGUID(), "https://www.example.com/");
+ test::SetCreditCardInfo(&credit_card, "John Dillinger",
+ "5105 1051 0510 5100" /* Mastercard */, "01", "2020",
+ "1");
+ credit_card.SetNickname(u"My Visa Card");
+ credit_card.set_product_description(u"ABC bank XYZ card");
+ EXPECT_TRUE(credit_card.HasNonEmptyValidNickname());
+ EXPECT_EQ(
+ customized_nickname +
+ UTF8ToUTF16(std::string(" ") +
+ test::ObfuscatedCardDigitsAsUTF8("5100")),
+ credit_card.CardIdentifierStringForAutofillDisplay(customized_nickname));
+}
+
+// Test that the card number is formatted as per the obfuscation length.
+TEST(CreditCardTest,
+ CardIdentifierStringsForAutofillDisplay_WithObfuscationLength) {
+ base::test::ScopedFeatureList scoped_feature_list;
+ scoped_feature_list.InitAndEnableFeature(
+ features::kAutofillEnableCardProductName);
+
+ int obfuscation_length = 2;
+
+ CreditCard credit_card(base::GenerateGUID(), "https://www.example.com/");
+ test::SetCreditCardInfo(&credit_card, "John Dillinger",
+ "5105 1051 0510 5100" /* Mastercard */, "01", "2020",
+ "1");
+ EXPECT_EQ(
+ UTF8ToUTF16(std::string("Mastercard ") +
+ test::ObfuscatedCardDigitsAsUTF8("5100", obfuscation_length)),
+ credit_card.CardIdentifierStringForAutofillDisplay(u"",
+ obfuscation_length));
}
TEST(CreditCardTest, AssignmentOperator) {
diff --git a/chromium/components/autofill/core/browser/data_model/data_model_utils.cc b/chromium/components/autofill/core/browser/data_model/data_model_utils.cc
index 12d2e4069e8..2eb0ae1aedd 100644
--- a/chromium/components/autofill/core/browser/data_model/data_model_utils.cc
+++ b/chromium/components/autofill/core/browser/data_model/data_model_utils.cc
@@ -9,9 +9,9 @@
#include "base/strings/string_number_conversions.h"
#include "base/strings/string_util.h"
#include "base/time/time.h"
-#include "components/autofill/core/browser/autofill_regex_constants.h"
-#include "components/autofill/core/browser/autofill_regexes.h"
#include "components/autofill/core/common/autofill_clock.h"
+#include "components/autofill/core/common/autofill_regex_constants.h"
+#include "components/autofill/core/common/autofill_regexes.h"
#include "third_party/icu/source/common/unicode/uloc.h"
#include "third_party/icu/source/i18n/unicode/dtfmtsym.h"
@@ -145,7 +145,7 @@ std::u16string FindPossiblePhoneCountryCode(const std::u16string& text) {
if (text.find(u"00") != std::u16string::npos ||
text.find('+') != std::u16string::npos) {
std::vector<std::u16string> captures;
- if (MatchesPattern(text, kAugmentedPhoneCountryCodeRe, &captures))
+ if (MatchesRegex<kAugmentedPhoneCountryCodeRe>(text, &captures))
return captures[1];
}
diff --git a/chromium/components/autofill/core/browser/data_model/iban.cc b/chromium/components/autofill/core/browser/data_model/iban.cc
new file mode 100644
index 00000000000..9efe62d7ac3
--- /dev/null
+++ b/chromium/components/autofill/core/browser/data_model/iban.cc
@@ -0,0 +1,160 @@
+// Copyright 2022 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/data_model/iban.h"
+
+#include <string>
+
+#include "base/guid.h"
+#include "base/notreached.h"
+#include "components/autofill/core/browser/autofill_field.h"
+#include "components/autofill/core/browser/data_model/autofill_metadata.h"
+
+namespace autofill {
+
+// Unicode characters used in IBAN value obfuscation:
+// - \u2022 - Bullet.
+// - \u2006 - SIX-PER-EM SPACE (small space between bullets).
+constexpr char16_t kMidlineEllipsisFourDotsAndOneSpace[] =
+ u"\u2022\u2022\u2022\u2022\u2006";
+constexpr char16_t kMidlineEllipsisTwoDotsAndOneSpace[] = u"\u2022\u2022\u2006";
+
+IBAN::IBAN(const std::string& guid)
+ : AutofillDataModel(guid, /*origin=*/std::string()),
+ record_type_(LOCAL_IBAN) {}
+
+IBAN::IBAN() : IBAN(base::GenerateGUID()) {}
+
+IBAN::IBAN(const IBAN& iban) : IBAN() {
+ operator=(iban);
+}
+
+IBAN::~IBAN() = default;
+
+IBAN& IBAN::operator=(const IBAN& iban) = default;
+
+AutofillMetadata IBAN::GetMetadata() const {
+ AutofillMetadata metadata = AutofillDataModel::GetMetadata();
+ metadata.id = (record_type_ == LOCAL_IBAN ? guid() : server_id_);
+ return metadata;
+}
+
+bool IBAN::SetMetadata(const AutofillMetadata& metadata) {
+ // Make sure the ids match.
+ return ((metadata.id !=
+ (record_type_ == LOCAL_IBAN ? guid() : server_id_))) &&
+ AutofillDataModel::SetMetadata(metadata);
+}
+
+bool IBAN::IsDeletable() const {
+ return false;
+}
+
+std::u16string IBAN::GetRawInfo(ServerFieldType type) const {
+ if (type == IBAN_VALUE) {
+ return value_;
+ }
+
+ NOTREACHED();
+ return std::u16string();
+}
+
+void IBAN::SetRawInfoWithVerificationStatus(
+ ServerFieldType type,
+ const std::u16string& value,
+ structured_address::VerificationStatus status) {
+ if (type == IBAN_VALUE) {
+ set_value(value);
+ } else {
+ NOTREACHED() << "Attempting to set unknown info-type" << type;
+ }
+}
+
+void IBAN::GetSupportedTypes(ServerFieldTypeSet* supported_types) const {
+ supported_types->insert(IBAN_VALUE);
+}
+
+bool IBAN::IsEmpty(const std::string& app_locale) const {
+ ServerFieldTypeSet types;
+ GetNonEmptyTypes(app_locale, &types);
+ return types.empty();
+}
+
+int IBAN::Compare(const IBAN& iban) const {
+ int comparison = server_id_.compare(iban.server_id_);
+ if (comparison != 0) {
+ return comparison;
+ }
+
+ comparison = nickname_.compare(iban.nickname_);
+ if (comparison != 0) {
+ return comparison;
+ }
+
+ return value_.compare(iban.value_);
+}
+
+bool IBAN::operator==(const IBAN& iban) const {
+ return guid() == iban.guid() && record_type() == iban.record_type() &&
+ Compare(iban) == 0;
+}
+
+bool IBAN::operator!=(const IBAN& iban) const {
+ return !operator==(iban);
+}
+
+void IBAN::set_nickname(const std::u16string& nickname) {
+ // First replace all tabs and newlines with whitespaces and store it as
+ // |nickname_|.
+ base::ReplaceChars(nickname, u"\t\r\n", u" ", &nickname_);
+ // An additional step to collapse whitespaces, this step does:
+ // 1. Trim leading and trailing whitespaces.
+ // 2. All other whitespace sequences are converted to a single space.
+ nickname_ =
+ base::CollapseWhitespace(nickname_,
+ /*trim_sequences_with_line_breaks=*/true);
+}
+
+std::u16string IBAN::GetIdentifierStringForAutofillDisplay() const {
+ const std::u16string stripped_value = GetStrippedValue();
+ size_t value_length = stripped_value.size();
+ // Directly return an empty string if the length of IBAN value is invalid.
+ if (value_length < 5 || value_length > 34)
+ return std::u16string();
+
+ std::u16string value_to_display = stripped_value.substr(0, 2);
+
+ // Get the number of groups of four characters to be obfuscated.
+ size_t number_of_groups = value_length % 4 == 0 ? (value_length - 4) / 4 - 1
+ : (value_length - 4) / 4;
+ // Get the position of rest of characters to be revealed.
+ size_t first_revealed_digit_pos = value_length % 4 == 0
+ ? value_length - 4
+ : value_length - (value_length % 4);
+
+ value_to_display.append(RepeatEllipsis(number_of_groups));
+
+ value_to_display.append(stripped_value.substr(first_revealed_digit_pos));
+ return value_to_display;
+}
+
+std::u16string IBAN::GetStrippedValue() const {
+ std::u16string stripped_value;
+ base::RemoveChars(value_, u"- ", &stripped_value);
+ return stripped_value;
+}
+
+std::u16string IBAN::RepeatEllipsis(size_t number_of_groups) const {
+ std::u16string ellipsis_value;
+ ellipsis_value.reserve(sizeof(kMidlineEllipsisTwoDotsAndOneSpace) +
+ number_of_groups *
+ sizeof(kMidlineEllipsisFourDotsAndOneSpace));
+ ellipsis_value.append(kMidlineEllipsisTwoDotsAndOneSpace);
+ for (size_t i = 0; i < number_of_groups; ++i)
+ ellipsis_value.append(kMidlineEllipsisFourDotsAndOneSpace);
+
+ return ellipsis_value;
+}
+
+} // namespace autofill
diff --git a/chromium/components/autofill/core/browser/data_model/iban.h b/chromium/components/autofill/core/browser/data_model/iban.h
new file mode 100644
index 00000000000..d7266c719c5
--- /dev/null
+++ b/chromium/components/autofill/core/browser/data_model/iban.h
@@ -0,0 +1,137 @@
+// Copyright 2022 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_DATA_MODEL_IBAN_H_
+#define COMPONENTS_AUTOFILL_CORE_BROWSER_DATA_MODEL_IBAN_H_
+
+#include <string>
+
+#include "base/time/time.h"
+#include "components/autofill/core/browser/autofill_type.h"
+#include "components/autofill/core/browser/data_model/autofill_data_model.h"
+
+namespace autofill {
+
+// A form group that stores IBAN information.
+class IBAN : public AutofillDataModel {
+ public:
+ enum RecordType {
+ // An IBAN stored and editable locally.
+ // Note: We only have local IBAN for now.
+ LOCAL_IBAN,
+ // An IBAN synced down from the server. These are read-only locally.
+ // Note: Server IBAN is not supported for now.
+ SERVER_IBAN,
+ };
+
+ explicit IBAN(const std::string& guid);
+
+ IBAN();
+ IBAN(const IBAN&);
+ ~IBAN() override;
+
+ IBAN& operator=(const IBAN& iban);
+
+ // AutofillDataModel:
+ AutofillMetadata GetMetadata() const override;
+ bool SetMetadata(const AutofillMetadata& metadata) override;
+
+ // Whether the IBAN is deletable. Always returns false for now as IBAN
+ // never expires.
+ bool IsDeletable() const override;
+
+ std::u16string GetRawInfo(ServerFieldType type) const override;
+ void SetRawInfoWithVerificationStatus(
+ ServerFieldType type,
+ const std::u16string& value,
+ structured_address::VerificationStatus status) override;
+ void GetSupportedTypes(ServerFieldTypeSet* supported_types) const override;
+
+ // How this IBAN is stored.
+ RecordType record_type() const { return record_type_; }
+ void set_record_type(RecordType type) { record_type_ = type; }
+
+ // Returns true if there are no values (field types) set.
+ bool IsEmpty(const std::string& app_locale) const;
+
+ // Comparison for Sync. Returns 0 if |iban| is the same as this, or < 0,
+ // or > 0 if it is different. The implied ordering can be used for culling
+ // duplicates. The ordering is based on the collation order of the textual
+ // contents of the fields.
+ // GUIDs, origins, and server id are not compared, only the values of
+ // the IBANs themselves.
+ int Compare(const IBAN& iban) const;
+
+ // Equality operators compare GUIDs, origins, |record_type_|, |value_|,
+ // |nickname_| and the |server_id_|.
+ bool operator==(const IBAN& iban) const;
+ bool operator!=(const IBAN& iban) const;
+
+ // Returns the ID assigned by the server. |server_id_| is empty if it's a
+ // local IBAN.
+ const std::string& server_id() const { return server_id_; }
+
+ // Returns the value (the actual bank account number) of IBAN.
+ const std::u16string& value() const { return value_; }
+ void set_value(const std::u16string& value) { value_ = value; }
+
+ const std::u16string& nickname() const { return nickname_; }
+ // Set the |nickname_| with the processed input (replace all tabs and newlines
+ // with whitespaces, condense multiple whitespaces into a single one, and
+ // trim leading/trailing whitespaces).
+ void set_nickname(const std::u16string& nickname);
+
+ // Converts value (E.g., CH12 1234 1234 1234 1234) of IBAN to a partial masked
+ // text formatted by the following steps:
+ // 1. Reveal the first two characters, containing the country code.
+ // 2. Obfuscate the following two check digits.
+ // 3. Arrange the remaining digits in groups of four and obfuscate them,
+ // adding a space between each group.
+ // Note: If the number of remaining digits is a multiple of four, reveal
+ // the last four digits.
+ // 4. Reveal any leftover digits not in a group of four.
+ //
+ // Here are some examples:
+ // BE71 0961 2345 6769 will be shown as: BE** **** **** 6769.
+ // CH56 0483 5012 3456 7800 9 will be shown as: CH** **** **** **** **** 9.
+ // DE91 1000 0000 0123 4567 89 will be show as: DE** **** **** **** **** 89.
+ std::u16string GetIdentifierStringForAutofillDisplay() const;
+
+#if defined(UNIT_TEST)
+ // Call RepeatEllipsis for testing purposes.
+ std::u16string RepeatEllipsisForTesting(size_t number_of_groups) const {
+ return RepeatEllipsis(number_of_groups);
+ }
+#endif
+
+ private:
+ // Returns a version of |value_| which does not have any separator characters
+ // (e.g., '-' and ' ').
+ std::u16string GetStrippedValue() const;
+
+ // This method does the following steps:
+ // 1. Adds two bullets and a space which represent the two characters after
+ // the country code.
+ // 2. Adds |number_of_groups| groups of "**** " to obfuscate the value of
+ // IBAN.
+ std::u16string RepeatEllipsis(size_t number_of_groups) const;
+
+ // This is the ID assigned by the server to uniquely identify this IBAN.
+ // Note: server_id is empty for now as only local IBAN is supported.
+ std::string server_id_;
+
+ // Type of how IBAN is stored, either local or server.
+ // Note: IBAN will only be stored locally for now.
+ RecordType record_type_;
+
+ // The IBAN's value, i.e., the actual bank account number.
+ std::u16string value_;
+
+ // The nickname of the IBAN. May be empty.
+ std::u16string nickname_;
+};
+
+} // namespace autofill
+
+#endif // COMPONENTS_AUTOFILL_CORE_BROWSER_DATA_MODEL_IBAN_H_
diff --git a/chromium/components/autofill/core/browser/data_model/iban_unittest.cc b/chromium/components/autofill/core/browser/data_model/iban_unittest.cc
new file mode 100644
index 00000000000..b6580a5b989
--- /dev/null
+++ b/chromium/components/autofill/core/browser/data_model/iban_unittest.cc
@@ -0,0 +1,149 @@
+// Copyright 2022 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/data_model/iban.h"
+
+#include <string>
+
+#include "base/guid.h"
+#include "components/autofill/core/browser/autofill_test_utils.h"
+#include "components/autofill/core/browser/data_model/autofill_metadata.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace autofill {
+
+TEST(IBANTest, AssignmentOperator) {
+ // Creates two IBANs with different parameters.
+ std::string guid = base::GenerateGUID();
+ IBAN iban_0;
+ iban_0.set_guid(guid);
+ iban_0.set_nickname(u"Nickname 0");
+ iban_0.set_value(u"DE91 1000 0000 0123 4567 89");
+ IBAN iban_1;
+ guid = base::GenerateGUID();
+ iban_1.set_guid(guid);
+ iban_1.set_nickname(u"Nickname 1");
+ iban_1.set_value(u"IE64 IRCE 9205 0112 3456 78");
+ iban_1 = iban_0;
+
+ EXPECT_EQ(iban_0, iban_1);
+}
+
+TEST(IBANTest, GetMetadata) {
+ IBAN local_iban = test::GetIBAN();
+ local_iban.set_use_count(2);
+ local_iban.set_use_date(base::Time::FromDoubleT(25));
+ AutofillMetadata local_metadata = local_iban.GetMetadata();
+
+ EXPECT_EQ(local_iban.guid(), local_metadata.id);
+ EXPECT_EQ(local_iban.use_count(), local_metadata.use_count);
+ EXPECT_EQ(local_iban.use_date(), local_metadata.use_date);
+}
+
+// Verify that we set nickname with the processed string. We replace all tabs
+// and newlines with whitespace, replace multiple spaces into a single one
+// and trim leading/trailing whitespace.
+TEST(IBANTest, SetNickname) {
+ IBAN iban(base::GenerateGUID());
+
+ // Normal input nickname.
+ iban.set_nickname(u"My doctor's IBAN");
+ EXPECT_EQ(u"My doctor's IBAN", iban.nickname());
+
+ // Input nickname has leading and trailing whitespaces.
+ iban.set_nickname(u" My doctor's IBAN ");
+ EXPECT_EQ(u"My doctor's IBAN", iban.nickname());
+
+ // Input nickname has newlines.
+ iban.set_nickname(u"\r\n My doctor's\nIBAN \r\n");
+ EXPECT_EQ(u"My doctor's IBAN", iban.nickname());
+
+ // Input nickname has tabs.
+ iban.set_nickname(u" \tMy doctor's\t IBAN\t ");
+ EXPECT_EQ(u"My doctor's IBAN", iban.nickname());
+
+ // Input nickname has newlines & whitespaces & tabs.
+ iban.set_nickname(u"\n\t My doctor's \tIBAN \n \r\n");
+ EXPECT_EQ(u"My doctor's IBAN", iban.nickname());
+
+ // Input nickname has newlines & tabs & multi spaces.
+ iban.set_nickname(u"\n\t My doctor's \tIBAN \n \r\n");
+ EXPECT_EQ(u"My doctor's IBAN", iban.nickname());
+}
+
+TEST(IBANTest, SetValue) {
+ IBAN iban(base::GenerateGUID());
+
+ // Input value.
+ iban.set_value(u"DE91 1000 0000 0123 4567 89");
+ EXPECT_EQ(u"DE91 1000 0000 0123 4567 89", iban.value());
+}
+
+TEST(IBANTest, SetRawData) {
+ IBAN iban(base::GenerateGUID());
+
+ // Verify RawInfo can be correctly set and read.
+ iban.SetRawInfoWithVerificationStatus(
+ IBAN_VALUE, u"DE91 1000 0000 0123 4567 89",
+ structured_address::VerificationStatus::kUserVerified);
+ EXPECT_EQ(u"DE91 1000 0000 0123 4567 89", iban.GetRawInfo(IBAN_VALUE));
+}
+
+// Verify that for all invalid IBAN values, empty identifier value will
+// be returned.
+TEST(IBANTest, GetObfuscatedStringForValue_InvalidIbanValue) {
+ IBAN iban(base::GenerateGUID());
+ iban.set_value(u"CH56-0483-5012-3456-7800-9999-9999-9999-9999");
+ EXPECT_EQ(u"", iban.GetIdentifierStringForAutofillDisplay());
+
+ iban.set_value(u"");
+ EXPECT_EQ(u"", iban.GetIdentifierStringForAutofillDisplay());
+
+ iban.set_value(u"CH5");
+ EXPECT_EQ(u"", iban.GetIdentifierStringForAutofillDisplay());
+}
+
+TEST(IBANTest, GetObfuscatedStringForValue_ValidIbanValue) {
+ // Verify each case of an IBAN ending in 1, 2, 3, and 4 unobfuscated
+ // digits.
+ IBAN iban(base::GenerateGUID());
+
+ iban.set_value(u"CH56 0483 5012 3456 7800 9");
+ std::u16string leading_digits = u"CH";
+ std::u16string trailing_digits = u"9";
+ // Obfuscated value is: CH** **** **** **** **** 9
+ std::u16string expected =
+ leading_digits + iban.RepeatEllipsisForTesting(4) + trailing_digits;
+
+ EXPECT_EQ(expected, iban.GetIdentifierStringForAutofillDisplay());
+
+ iban.set_value(u"DE91 1000 0000 0123 4567 89");
+ leading_digits = u"DE";
+ trailing_digits = u"89";
+ // Obfuscated value is: DE** **** **** **** **** 89
+ expected =
+ leading_digits + iban.RepeatEllipsisForTesting(4) + trailing_digits;
+
+ EXPECT_EQ(expected, iban.GetIdentifierStringForAutofillDisplay());
+
+ iban.set_value(u"GR96 0810 0010 0000 0123 4567 890");
+ leading_digits = u"GR";
+ trailing_digits = u"890";
+ // Obfuscated value is: GR** **** **** **** **** **** 890
+ expected =
+ leading_digits + iban.RepeatEllipsisForTesting(5) + trailing_digits;
+
+ EXPECT_EQ(expected, iban.GetIdentifierStringForAutofillDisplay());
+
+ iban.set_value(u"PK70 BANK 0000 1234 5678 9000");
+ leading_digits = u"PK";
+ trailing_digits = u"9000";
+ // Obfuscated value is: PK** **** **** **** **** 9000
+ expected =
+ leading_digits + iban.RepeatEllipsisForTesting(4) + trailing_digits;
+
+ EXPECT_EQ(expected, iban.GetIdentifierStringForAutofillDisplay());
+}
+
+} // namespace autofill
diff --git a/chromium/components/autofill/core/browser/data_model/phone_number.cc b/chromium/components/autofill/core/browser/data_model/phone_number.cc
index ab2cb1424c2..f31a7707c12 100644
--- a/chromium/components/autofill/core/browser/data_model/phone_number.cc
+++ b/chromium/components/autofill/core/browser/data_model/phone_number.cc
@@ -68,6 +68,8 @@ bool PhoneNumber::operator==(const PhoneNumber& other) const {
void PhoneNumber::GetSupportedTypes(ServerFieldTypeSet* supported_types) const {
supported_types->insert(PHONE_HOME_WHOLE_NUMBER);
supported_types->insert(PHONE_HOME_NUMBER);
+ supported_types->insert(PHONE_HOME_NUMBER_PREFIX);
+ supported_types->insert(PHONE_HOME_NUMBER_SUFFIX);
supported_types->insert(PHONE_HOME_CITY_CODE);
supported_types->insert(PHONE_HOME_CITY_AND_NUMBER);
supported_types->insert(PHONE_HOME_COUNTRY_CODE);
@@ -119,17 +121,6 @@ void PhoneNumber::GetMatchingTypes(const std::u16string& text,
base::RemoveChars(stripped_text, u" .()-", &stripped_text);
FormGroup::GetMatchingTypes(stripped_text, app_locale, matching_types);
- // For US numbers, also compare to the three-digit prefix and the four-digit
- // suffix, since web sites often split numbers into these two fields.
- std::u16string number = GetInfo(AutofillType(PHONE_HOME_NUMBER), app_locale);
- if (GetRegion(*profile_, app_locale) == "US" &&
- number.size() == (kPrefixLength + kSuffixLength)) {
- std::u16string prefix = number.substr(kPrefixOffset, kPrefixLength);
- std::u16string suffix = number.substr(kSuffixOffset, kSuffixLength);
- if (text == prefix || text == suffix)
- matching_types->insert(PHONE_HOME_NUMBER);
- }
-
// TODO(crbug.com/581391): Investigate the use of PhoneNumberUtil when
// matching phone numbers for upload.
// If there is not already a match for PHONE_HOME_WHOLE_NUMBER, normalize the
@@ -234,9 +225,10 @@ std::u16string PhoneNumber::GetInfoImpl(const AutofillType& type,
// autocomplete="tel-local-suffix" corresponds to. In all countries using
// this format that we are aware of (see unit tests), the suffix consists
// of the last 4 digits, while the length of the prefix varies.
- constexpr int kSuffixLength = 4;
- DCHECK(number.size() >= kSuffixLength);
- return number.substr(number.size() - kSuffixLength);
+ constexpr size_t kHomePhoneNumberSuffixLength = 4;
+ return number.size() >= kHomePhoneNumberSuffixLength
+ ? number.substr(number.size() - kHomePhoneNumberSuffixLength)
+ : number;
}
case PHONE_HOME_CITY_CODE_WITH_TRUNK_PREFIX:
@@ -274,6 +266,8 @@ std::u16string PhoneNumber::GetInfoImpl(const AutofillType& type,
}
case PHONE_HOME_EXTENSION:
+ // Autofill doesn't support filling extensions, but some basic local
+ // heuristics classify them.
return std::u16string();
default:
@@ -306,6 +300,16 @@ bool PhoneNumber::SetInfoWithVerificationStatusImpl(
// doesn't contain formatting marks.
if (base::ContainsOnlyChars(number_, u"+0123456789")) {
number_ = cached_parsed_phone_.GetFormattedNumber();
+ } else {
+ // Strip `number_` of extensions, e.g. "(123)-123 ext. 123" -> "(123)-123".
+ // In the if case, this is done by `GetFormattedNumber()` already. To
+ // preserve the formatting, everything after the last digit of the whole
+ // number is removed manually here. The whole number only consists of digits
+ // and has any extensions removed already.
+ size_t i = 0;
+ for (auto digit : cached_parsed_phone_.GetWholeNumber())
+ i = number_.find(digit, i) + 1; // Skip `digit`.
+ number_ = number_.substr(0, i);
}
return true;
}
@@ -336,12 +340,14 @@ bool PhoneNumber::PhoneCombineHelper::SetInfo(const AutofillType& type,
return true;
}
- if (storable_type == PHONE_HOME_CITY_CODE) {
+ if (storable_type == PHONE_HOME_CITY_CODE ||
+ storable_type == PHONE_HOME_CITY_CODE_WITH_TRUNK_PREFIX) {
city_ = value;
return true;
}
- if (storable_type == PHONE_HOME_CITY_AND_NUMBER) {
+ if (storable_type == PHONE_HOME_CITY_AND_NUMBER ||
+ storable_type == PHONE_HOME_CITY_AND_NUMBER_WITHOUT_TRUNK_PREFIX) {
phone_ = value;
return true;
}
@@ -351,7 +357,13 @@ bool PhoneNumber::PhoneCombineHelper::SetInfo(const AutofillType& type,
return true;
}
- if (storable_type == PHONE_HOME_NUMBER) {
+ if (storable_type == PHONE_HOME_NUMBER ||
+ storable_type == PHONE_HOME_NUMBER_PREFIX) {
+ phone_ = value;
+ return true;
+ }
+
+ if (storable_type == PHONE_HOME_NUMBER_SUFFIX) {
phone_.append(value);
return true;
}
diff --git a/chromium/components/autofill/core/browser/data_model/phone_number.h b/chromium/components/autofill/core/browser/data_model/phone_number.h
index aa7665755aa..4d3bb90f35c 100644
--- a/chromium/components/autofill/core/browser/data_model/phone_number.h
+++ b/chromium/components/autofill/core/browser/data_model/phone_number.h
@@ -39,12 +39,6 @@ class PhoneNumber : public FormGroup {
const std::u16string& value,
structured_address::VerificationStatus status) override;
- // Size and offset of the prefix and suffix portions of phone numbers.
- static const size_t kPrefixOffset = 0;
- static const size_t kPrefixLength = 3;
- static const size_t kSuffixOffset = 3;
- static const size_t kSuffixLength = 4;
-
// The class used to combine home phone parts into a whole number.
class PhoneCombineHelper {
public:
diff --git a/chromium/components/autofill/core/browser/data_model/phone_number_unittest.cc b/chromium/components/autofill/core/browser/data_model/phone_number_unittest.cc
index 52bd3f6aa0b..e81a743476f 100644
--- a/chromium/components/autofill/core/browser/data_model/phone_number_unittest.cc
+++ b/chromium/components/autofill/core/browser/data_model/phone_number_unittest.cc
@@ -67,8 +67,8 @@ TEST(PhoneNumberTest, Matcher) {
{u"16502345678", {PHONE_HOME_WHOLE_NUMBER}},
{u"650", {PHONE_HOME_CITY_CODE}},
{u"2345678", {PHONE_HOME_NUMBER}},
- {u"234", {PHONE_HOME_NUMBER}},
- {u"5678", {PHONE_HOME_NUMBER}},
+ {u"234", {PHONE_HOME_NUMBER_PREFIX}},
+ {u"5678", {PHONE_HOME_NUMBER_SUFFIX}},
{u"2345", {}},
{u"6502345678", {PHONE_HOME_CITY_AND_NUMBER}},
{u"(650)2345678", {PHONE_HOME_CITY_AND_NUMBER}}});
@@ -241,7 +241,7 @@ TEST(PhoneNumberTest, PhoneCombineHelper) {
profile.SetRawInfo(ADDRESS_HOME_COUNTRY, u"US");
PhoneNumber::PhoneCombineHelper number1;
- EXPECT_FALSE(number1.SetInfo(AutofillType(ADDRESS_BILLING_CITY), u"1"));
+ EXPECT_FALSE(number1.SetInfo(AutofillType(ADDRESS_HOME_COUNTRY), u"1"));
EXPECT_TRUE(number1.SetInfo(AutofillType(PHONE_HOME_COUNTRY_CODE), u"1"));
EXPECT_TRUE(number1.SetInfo(AutofillType(PHONE_HOME_CITY_CODE), u"650"));
EXPECT_TRUE(number1.SetInfo(AutofillType(PHONE_HOME_NUMBER), u"2345678"));
@@ -272,8 +272,8 @@ TEST(PhoneNumberTest, PhoneCombineHelper) {
PhoneNumber::PhoneCombineHelper number6;
EXPECT_TRUE(number6.SetInfo(AutofillType(PHONE_HOME_CITY_CODE), u"650"));
- EXPECT_TRUE(number6.SetInfo(AutofillType(PHONE_HOME_NUMBER), u"234"));
- EXPECT_TRUE(number6.SetInfo(AutofillType(PHONE_HOME_NUMBER), u"5682"));
+ EXPECT_TRUE(number6.SetInfo(AutofillType(PHONE_HOME_NUMBER_PREFIX), u"234"));
+ EXPECT_TRUE(number6.SetInfo(AutofillType(PHONE_HOME_NUMBER_SUFFIX), u"5682"));
EXPECT_TRUE(number6.ParseNumber(profile, "en-US", &parsed_phone));
EXPECT_EQ(u"(650) 234-5682", parsed_phone);
@@ -281,8 +281,8 @@ TEST(PhoneNumberTest, PhoneCombineHelper) {
// based on the app locale.
PhoneNumber::PhoneCombineHelper number7;
EXPECT_TRUE(number7.SetInfo(AutofillType(PHONE_HOME_CITY_CODE), u"650"));
- EXPECT_TRUE(number7.SetInfo(AutofillType(PHONE_HOME_NUMBER), u"234"));
- EXPECT_TRUE(number7.SetInfo(AutofillType(PHONE_HOME_NUMBER), u"5682"));
+ EXPECT_TRUE(number7.SetInfo(AutofillType(PHONE_HOME_NUMBER_PREFIX), u"234"));
+ EXPECT_TRUE(number7.SetInfo(AutofillType(PHONE_HOME_NUMBER_SUFFIX), u"5682"));
EXPECT_TRUE(number7.ParseNumber(AutofillProfile(), "en-US", &parsed_phone));
EXPECT_EQ(u"(650) 234-5682", parsed_phone);
}
@@ -370,6 +370,13 @@ TEST(PhoneNumberTest, TrunkPrefix) {
u"3381234567");
TestNumber(u"338 1234567", u"338", u"338", u"3381234567", u"3381234567");
}
+
+ // RU: An 8 is used as a trunk prefix.
+ {
+ profile.SetRawInfo(ADDRESS_HOME_COUNTRY, u"RU");
+ TestNumber(u"+7 495 123 45 67", u"8495", u"495", u"84951234567",
+ u"4951234567");
+ }
}
// Tests that PHONE_HOME_NUMBER_PREFIX and PHONE_HOME_NUMBER_PREFIX are
@@ -385,7 +392,7 @@ TEST(PhoneNumberTest, NumberPreAndSuffixes) {
// The `locale` is irrelevant, as the `profile` has country information.
const std::string locale = "en-US";
PhoneNumber phone_number(&profile);
- phone_number.SetInfo(PHONE_HOME_WHOLE_NUMBER, number, locale);
+ EXPECT_TRUE(phone_number.SetInfo(PHONE_HOME_WHOLE_NUMBER, number, locale));
EXPECT_EQ(prefix, phone_number.GetInfo(PHONE_HOME_NUMBER_PREFIX, locale));
EXPECT_EQ(suffix, phone_number.GetInfo(PHONE_HOME_NUMBER_SUFFIX, locale));
};
@@ -402,6 +409,24 @@ TEST(PhoneNumberTest, NumberPreAndSuffixes) {
TestNumber(u"090-1234-5678", u"1234", u"5678"); // Mobile
TestNumber(u"+81 824-86-3123", u"86", u"3123"); // Different length prefix
}
+ // DE
+ {
+ // Emergency numbers can be shorter than 4 digits. Make sure we don't crash.
+ profile.SetRawInfo(ADDRESS_HOME_COUNTRY, u"DE");
+ TestNumber(u"110", u"", u"110");
+ }
+}
+
+// Tests that extensions are not stored and even stripped from the raw info.
+TEST(PhoneNumberTest, Extension) {
+ AutofillProfile profile;
+ PhoneNumber phone(&profile);
+ const std::string locale = "en-US";
+ EXPECT_TRUE(phone.SetInfo(PHONE_HOME_WHOLE_NUMBER, u"(650) 234-2345 ext. 234",
+ locale));
+ EXPECT_EQ(u"(650) 234-2345", phone.GetRawInfo(PHONE_HOME_WHOLE_NUMBER));
+ EXPECT_EQ(u"6502342345", phone.GetInfo(PHONE_HOME_WHOLE_NUMBER, locale));
+ EXPECT_TRUE(phone.GetInfo(PHONE_HOME_EXTENSION, locale).empty());
}
// Tests whether the |PHONE_HOME_COUNTRY_CODE| is added to the set of matching
diff --git a/chromium/components/autofill/core/browser/field_filler.cc b/chromium/components/autofill/core/browser/field_filler.cc
index f7309c0055e..f4ae5b2d479 100644
--- a/chromium/components/autofill/core/browser/field_filler.cc
+++ b/chromium/components/autofill/core/browser/field_filler.cc
@@ -18,7 +18,6 @@
#include "components/autofill/core/browser/address_normalizer.h"
#include "components/autofill/core/browser/autofill_data_util.h"
#include "components/autofill/core/browser/autofill_field.h"
-#include "components/autofill/core/browser/autofill_regexes.h"
#include "components/autofill/core/browser/autofill_type.h"
#include "components/autofill/core/browser/data_model/autofill_data_model.h"
#include "components/autofill/core/browser/data_model/credit_card.h"
@@ -32,6 +31,7 @@
#include "components/autofill/core/browser/proto/states.pb.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"
#include "components/autofill/core/common/autofill_util.h"
#include "components/strings/grit/components_strings.h"
#include "third_party/libaddressinput/src/cpp/include/libaddressinput/address_data.h"
@@ -268,7 +268,11 @@ bool FillStateSelectControl(const std::u16string& value,
for (const auto& alternative_name : state_entry->alternative_names())
full_names.push_back(base::UTF8ToUTF16(alternative_name));
} else {
- full_names.push_back(value);
+ if (value.size() > 2) {
+ full_names.push_back(value);
+ } else {
+ abbreviations.push_back(value);
+ }
}
}
@@ -283,6 +287,17 @@ bool FillStateSelectControl(const std::u16string& value,
if (!state_abbreviation.empty())
abbreviations.push_back(std::move(state_abbreviation));
+ // Remove `abbreviations` from the `full_names` as a precautionary measure in
+ // case the `AlternativeStateNameMap` contains bad data.
+ base::ranges::sort(abbreviations);
+ full_names.erase(
+ base::ranges::remove_if(full_names,
+ [&](const std::u16string& full_name) {
+ return base::ranges::binary_search(
+ abbreviations, full_name);
+ }),
+ full_names.end());
+
// Try an exact match of the abbreviation first.
for (const auto& abbreviation : abbreviations) {
if (!abbreviation.empty() &&
@@ -756,13 +771,14 @@ std::u16string GetExpirationDateForInput(const CreditCard& credit_card,
if (base::FeatureList::IsEnabled(
features::kAutofillFillCreditCardAsPerFormatString)) {
std::vector<std::u16string> groups;
- const char16_t* kFormatRegEx = u"mm(\\s?[/-]?\\s?)?yy(yy)?";
- // ^^^^ optional white space
- // ^^^^^ optional separator
- // ^^^ optional white space
- // ^^^^^ 4 digit year?
- if (MatchesPattern(field.placeholder, kFormatRegEx, &groups) ||
- MatchesPattern(field.label, kFormatRegEx, &groups)) {
+ static const char16_t kFormatRegEx[] = u"mm(\\s?[/-]?\\s?)?yy(yy)?";
+ // ^^^^ opt white space
+ // ^^^^^ opt separator
+ // ^^^ opt white space
+ // ^^^^^ 4 digit
+ // year?
+ if (MatchesRegex<kFormatRegEx>(field.placeholder, &groups) ||
+ MatchesRegex<kFormatRegEx>(field.label, &groups)) {
bool is_two_digit_year = groups[2].empty();
std::u16string expiration_candidate =
base::StrCat({month, groups[1],
@@ -1077,24 +1093,6 @@ std::u16string FieldFiller::GetPhoneNumberValueForInput(
const std::u16string& number,
const std::u16string& phone_home_city_and_number,
const FormFieldData& field_data) {
- // TODO(crbug.com/581485): Investigate the use of libphonenumber here.
- // Check to see if the |field| size matches the "prefix" or "suffix" size or
- // if the field was labeled as such. If so, return the appropriate substring.
- if (number.length() ==
- PhoneNumber::kPrefixLength + PhoneNumber::kSuffixLength) {
- if (field.phone_part() == AutofillField::PHONE_PREFIX ||
- field_data.max_length == PhoneNumber::kPrefixLength) {
- return number.substr(PhoneNumber::kPrefixOffset,
- PhoneNumber::kPrefixLength);
- }
-
- if (field.phone_part() == AutofillField::PHONE_SUFFIX ||
- field_data.max_length == PhoneNumber::kSuffixLength) {
- return number.substr(PhoneNumber::kSuffixOffset,
- PhoneNumber::kSuffixLength);
- }
- }
-
// If no max length was specified, return the complete number.
if (field_data.max_length == 0)
return number;
diff --git a/chromium/components/autofill/core/browser/field_filler_unittest.cc b/chromium/components/autofill/core/browser/field_filler_unittest.cc
index 195b28ad333..030677576df 100644
--- a/chromium/components/autofill/core/browser/field_filler_unittest.cc
+++ b/chromium/components/autofill/core/browser/field_filler_unittest.cc
@@ -167,21 +167,21 @@ TEST_F(AutofillFieldFillerTest, Type) {
EXPECT_EQ(FieldTypeGroup::kName, field.Type().group());
// Set the server type and check it.
- prediction.set_type(ADDRESS_BILLING_LINE1);
+ prediction.set_type(ADDRESS_HOME_LINE1);
field.set_server_predictions({prediction});
EXPECT_EQ(ADDRESS_HOME_LINE1, field.Type().GetStorableType());
- EXPECT_EQ(FieldTypeGroup::kAddressBilling, field.Type().group());
+ EXPECT_EQ(FieldTypeGroup::kAddressHome, field.Type().group());
// Checks that overall_type trumps everything.
- field.SetTypeTo(AutofillType(ADDRESS_BILLING_ZIP));
+ field.SetTypeTo(AutofillType(ADDRESS_HOME_ZIP));
EXPECT_EQ(ADDRESS_HOME_ZIP, field.Type().GetStorableType());
- EXPECT_EQ(FieldTypeGroup::kAddressBilling, field.Type().group());
+ EXPECT_EQ(FieldTypeGroup::kAddressHome, field.Type().group());
// Checks that setting server type resets overall type.
- prediction.set_type(ADDRESS_BILLING_LINE1);
+ prediction.set_type(ADDRESS_HOME_LINE1);
field.set_server_predictions({prediction});
EXPECT_EQ(ADDRESS_HOME_LINE1, field.Type().GetStorableType());
- EXPECT_EQ(FieldTypeGroup::kAddressBilling, field.Type().group());
+ EXPECT_EQ(FieldTypeGroup::kAddressHome, field.Type().group());
// Remove the server type to make sure the heuristic type is preserved.
prediction.set_type(NO_SERVER_DATA);
@@ -190,9 +190,9 @@ TEST_F(AutofillFieldFillerTest, Type) {
EXPECT_EQ(FieldTypeGroup::kName, field.Type().group());
// Checks that overall_type trumps everything.
- field.SetTypeTo(AutofillType(ADDRESS_BILLING_ZIP));
+ field.SetTypeTo(AutofillType(ADDRESS_HOME_ZIP));
EXPECT_EQ(ADDRESS_HOME_ZIP, field.Type().GetStorableType());
- EXPECT_EQ(FieldTypeGroup::kAddressBilling, field.Type().group());
+ EXPECT_EQ(FieldTypeGroup::kAddressHome, field.Type().group());
// Set the heuristic type and check it and reset overall Type.
field.set_heuristic_type(GetActivePatternSource(), NAME_FIRST);
@@ -577,11 +577,6 @@ INSTANTIATE_TEST_SUITE_P(
AutofillPhoneFieldFillerTestCase{HTML_TYPE_TEL_LOCAL_SUFFIX,
/*field_max_length=*/0, u"4578",
u"+15145554578"},
- // Filling a phone type field with a max length of 3 should fill only
- // the prefix.
- AutofillPhoneFieldFillerTestCase{HTML_TYPE_TEL_LOCAL,
- /*field_max_length=*/3, u"555",
- u"+15145554578"},
// TODO(crbug.com/581485): There should be a test case where the full
// number is requested (HTML_TYPE_TEL) but a field_max_length of 3 would
// fill the prefix.
@@ -2058,6 +2053,31 @@ TEST_F(AutofillFieldFillerTest, FillUpperCaseAbbreviationInStateTextField) {
EXPECT_EQ(u"BY", field.value);
}
+// Tests that Autofill does not fill the state when abbreviated data is stored
+// in the profile and none of the options match with the abbreviated state.
+TEST_F(AutofillFieldFillerTest,
+ DoNotFillStateFieldWhenAbbrStoredInProfileAndNotInOptionsList) {
+ base::test::ScopedFeatureList feature;
+ feature.InitAndEnableFeature(features::kAutofillUseAlternativeStateNameMap);
+
+ test::ClearAlternativeStateNameMapForTesting();
+ std::vector<const char*> kState = {"Colombia", "Connecticut", "Colifornia"};
+
+ AutofillField field;
+ test::CreateTestSelectField(kState, &field);
+ field.set_heuristic_type(GetActivePatternSource(), ADDRESS_HOME_STATE);
+
+ AutofillProfile address;
+ address.SetRawInfo(ADDRESS_HOME_STATE, u"CO");
+ address.SetRawInfo(ADDRESS_HOME_COUNTRY, u"US");
+
+ FieldFiller filler(/*app_locale=*/"en-US", /*address_normalizer=*/nullptr);
+ filler.FillFormField(field, &address, /*forced_fill_values=*/{}, &field,
+ /*cvc=*/std::u16string(),
+ mojom::RendererFormDataAction::kFill);
+ EXPECT_EQ(u"", field.value);
+}
+
TEST_F(AutofillFieldFillerTest, PreviewVirtualMonth) {
AutofillField field;
field.form_control_type = "text";
@@ -2228,7 +2248,6 @@ TEST_F(AutofillFieldFillerTest, PreviewVirtualCVC) {
}
TEST_F(AutofillFieldFillerTest, PreviewVirtualCVCAmericanExpress) {
- const char kAmericanExpressCard[] = "americanExpressCC";
AutofillField field;
field.form_control_type = "text";
FieldFiller filler(/*app_locale=*/"en-US", /*address_normalizer=*/nullptr);
@@ -2249,7 +2268,6 @@ TEST_F(AutofillFieldFillerTest, PreviewVirtualCardNumber) {
field.set_heuristic_type(GetActivePatternSource(), CREDIT_CARD_NUMBER);
field.set_credit_card_number_offset(50);
field.form_control_type = "text";
- const char kMasterCard[] = "masterCardCC";
CreditCard card = test::GetVirtualCard();
card.SetNumber(u"5454545454545454");
diff --git a/chromium/components/autofill/core/browser/field_types.cc b/chromium/components/autofill/core/browser/field_types.cc
index 15d1af444c1..774e1e75f30 100644
--- a/chromium/components/autofill/core/browser/field_types.cc
+++ b/chromium/components/autofill/core/browser/field_types.cc
@@ -23,10 +23,15 @@ ServerFieldType ToSafeServerFieldType(
// Shipping addresses (values [44,50]) are deprecated.
!(44 <= t && t <= 50) &&
// Probably-account creation password (value 94) is deprecated.
- !(t == 94) &&
- // Fax numbers (values [20,24]) are deprecated in Chrome, but still
- // supported by the server.
- !(t >= PHONE_FAX_NUMBER && t <= PHONE_FAX_WHOLE_NUMBER);
+ t != 94 &&
+ // Billing addresses (values [37,43], 78, 80, 82, 84) are deprecated.
+ !(37 <= t && t <= 43) && t != 78 && t != 80 && t != 82 && t != 84 &&
+ // Billing phone numbers (values [62,66]) are deprecated.
+ !(62 <= t && t <= 66) &&
+ // Billing names (values [67,72]) are deprecated.
+ !(67 <= t && t <= 72) &&
+ // Fax numbers (values [20,24]) are deprecated.
+ !(20 <= t && t <= 24);
};
return IsValid(raw_value) ? static_cast<ServerFieldType>(raw_value)
: fallback_value;
@@ -80,32 +85,6 @@ bool IsFillableFieldType(ServerFieldType field_type) {
case ADDRESS_HOME_FLOOR:
return true;
- // Billing address types that should not be returned by GetStorableType().
- case NAME_BILLING_FIRST:
- case NAME_BILLING_MIDDLE:
- case NAME_BILLING_LAST:
- case NAME_BILLING_MIDDLE_INITIAL:
- case NAME_BILLING_FULL:
- case NAME_BILLING_SUFFIX:
- case PHONE_BILLING_NUMBER:
- case PHONE_BILLING_CITY_CODE:
- case PHONE_BILLING_COUNTRY_CODE:
- case PHONE_BILLING_CITY_AND_NUMBER:
- case PHONE_BILLING_WHOLE_NUMBER:
- case ADDRESS_BILLING_LINE1:
- case ADDRESS_BILLING_LINE2:
- case ADDRESS_BILLING_LINE3:
- case ADDRESS_BILLING_APT_NUM:
- case ADDRESS_BILLING_CITY:
- case ADDRESS_BILLING_STATE:
- case ADDRESS_BILLING_ZIP:
- case ADDRESS_BILLING_COUNTRY:
- case ADDRESS_BILLING_STREET_ADDRESS:
- case ADDRESS_BILLING_SORTING_CODE:
- case ADDRESS_BILLING_DEPENDENT_LOCALITY:
- NOTREACHED();
- return false;
-
case CREDIT_CARD_NAME_FULL:
case CREDIT_CARD_NAME_FIRST:
case CREDIT_CARD_NAME_LAST:
@@ -117,11 +96,15 @@ bool IsFillableFieldType(ServerFieldType field_type) {
case CREDIT_CARD_EXP_DATE_4_DIGIT_YEAR:
case CREDIT_CARD_TYPE:
case CREDIT_CARD_VERIFICATION_CODE:
+ case CREDIT_CARD_STANDALONE_VERIFICATION_CODE:
return true;
case UPI_VPA:
return base::FeatureList::IsEnabled(features::kAutofillSaveAndFillVPA);
+ case IBAN_VALUE:
+ return base::FeatureList::IsEnabled(features::kAutofillParseIBANFields);
+
case COMPANY_NAME:
return true;
@@ -153,18 +136,13 @@ bool IsFillableFieldType(ServerFieldType field_type) {
case NO_SERVER_DATA:
case EMPTY_TYPE:
case AMBIGUOUS_TYPE:
- case PHONE_FAX_NUMBER:
- case PHONE_FAX_CITY_CODE:
- case PHONE_FAX_COUNTRY_CODE:
- case PHONE_FAX_CITY_AND_NUMBER:
- case PHONE_FAX_WHOLE_NUMBER:
case FIELD_WITH_DEFAULT_VALUE:
case MERCHANT_EMAIL_SIGNUP:
case PRICE:
case SEARCH_TERM:
case BIRTHDATE_DAY:
case BIRTHDATE_MONTH:
- case BIRTHDATE_YEAR_4_DIGITS:
+ case BIRTHDATE_4_DIGIT_YEAR:
case UNKNOWN_TYPE:
case MAX_VALID_FIELD_TYPE:
return false;
@@ -205,18 +183,6 @@ base::StringPiece FieldTypeToStringPiece(ServerFieldType type) {
return "NAME_FULL";
case NAME_SUFFIX:
return "NAME_SUFFIX";
- case NAME_BILLING_FIRST:
- return "NAME_BILLING_FIRST";
- case NAME_BILLING_MIDDLE:
- return "NAME_BILLING_MIDDLE";
- case NAME_BILLING_LAST:
- return "NAME_BILLING_LAST";
- case NAME_BILLING_MIDDLE_INITIAL:
- return "NAME_BILLING_MIDDLE_INITIAL";
- case NAME_BILLING_FULL:
- return "NAME_BILLING_FULL";
- case NAME_BILLING_SUFFIX:
- return "NAME_BILLING_SUFFIX";
case EMAIL_ADDRESS:
return "EMAIL_ADDRESS";
case PHONE_HOME_NUMBER:
@@ -239,16 +205,6 @@ base::StringPiece FieldTypeToStringPiece(ServerFieldType type) {
return "PHONE_HOME_WHOLE_NUMBER";
case PHONE_HOME_EXTENSION:
return "PHONE_HOME_EXTENSION";
- case PHONE_FAX_NUMBER:
- return "PHONE_FAX_NUMBER";
- case PHONE_FAX_CITY_CODE:
- return "PHONE_FAX_CITY_CODE";
- case PHONE_FAX_COUNTRY_CODE:
- return "PHONE_FAX_COUNTRY_CODE";
- case PHONE_FAX_CITY_AND_NUMBER:
- return "PHONE_FAX_CITY_AND_NUMBER";
- case PHONE_FAX_WHOLE_NUMBER:
- return "PHONE_FAX_WHOLE_NUMBER";
case ADDRESS_HOME_ADDRESS:
return "ADDRESS_HOME_ADDRESS";
case ADDRESS_HOME_ADDRESS_WITH_NAME:
@@ -271,27 +227,11 @@ base::StringPiece FieldTypeToStringPiece(ServerFieldType type) {
return "ADDRESS_HOME_ZIP";
case ADDRESS_HOME_COUNTRY:
return "ADDRESS_HOME_COUNTRY";
- case ADDRESS_BILLING_LINE1:
- return "ADDRESS_BILLING_LINE1";
- case ADDRESS_BILLING_LINE2:
- return "ADDRESS_BILLING_LINE2";
- case ADDRESS_BILLING_LINE3:
- return "ADDRESS_BILLING_LINE3";
- case ADDRESS_BILLING_APT_NUM:
- return "ADDRESS_BILLING_APT_NUM";
- case ADDRESS_BILLING_CITY:
- return "ADDRESS_BILLING_CITY";
- case ADDRESS_BILLING_STATE:
- return "ADDRESS_BILLING_STATE";
- case ADDRESS_BILLING_ZIP:
- return "ADDRESS_BILLING_ZIP";
- case ADDRESS_BILLING_COUNTRY:
- return "ADDRESS_BILLING_COUNTRY";
case BIRTHDATE_DAY:
return "BIRTHDATE_DAY";
case BIRTHDATE_MONTH:
return "BIRTHDATE_MONTH";
- case BIRTHDATE_YEAR_4_DIGITS:
+ case BIRTHDATE_4_DIGIT_YEAR:
return "BIRTHDATE_YEAR_4_DIGITS";
case CREDIT_CARD_NAME_FULL:
return "CREDIT_CARD_NAME_FULL";
@@ -319,16 +259,6 @@ base::StringPiece FieldTypeToStringPiece(ServerFieldType type) {
return "COMPANY_NAME";
case FIELD_WITH_DEFAULT_VALUE:
return "FIELD_WITH_DEFAULT_VALUE";
- case PHONE_BILLING_NUMBER:
- return "PHONE_BILLING_NUMBER";
- case PHONE_BILLING_CITY_CODE:
- return "PHONE_BILLING_CITY_CODE";
- case PHONE_BILLING_COUNTRY_CODE:
- return "PHONE_BILLING_COUNTRY_CODE";
- case PHONE_BILLING_CITY_AND_NUMBER:
- return "PHONE_BILLING_CITY_AND_NUMBER";
- case PHONE_BILLING_WHOLE_NUMBER:
- return "PHONE_BILLING_WHOLE_NUMBER";
case MERCHANT_EMAIL_SIGNUP:
return "MERCHANT_EMAIL_SIGNUP";
case MERCHANT_PROMO_CODE:
@@ -339,16 +269,10 @@ base::StringPiece FieldTypeToStringPiece(ServerFieldType type) {
return "ACCOUNT_CREATION_PASSWORD";
case ADDRESS_HOME_STREET_ADDRESS:
return "ADDRESS_HOME_STREET_ADDRESS";
- case ADDRESS_BILLING_STREET_ADDRESS:
- return "ADDRESS_BILLING_STREET_ADDRESS";
case ADDRESS_HOME_SORTING_CODE:
return "ADDRESS_HOME_SORTING_CODE";
- case ADDRESS_BILLING_SORTING_CODE:
- return "ADDRESS_BILLING_SORTING_CODE";
case ADDRESS_HOME_DEPENDENT_LOCALITY:
return "ADDRESS_HOME_DEPENDENT_LOCALITY";
- case ADDRESS_BILLING_DEPENDENT_LOCALITY:
- return "ADDRESS_BILLING_DEPENDENT_LOCALITY";
case NOT_ACCOUNT_CREATION_PASSWORD:
return "NOT_ACCOUNT_CREATION_PASSWORD";
case USERNAME:
@@ -391,6 +315,10 @@ base::StringPiece FieldTypeToStringPiece(ServerFieldType type) {
return "ADDRESS_HOME_OTHER_SUBUNIT";
case AMBIGUOUS_TYPE:
return "AMBIGUOUS_TYPE";
+ case IBAN_VALUE:
+ return "IBAN_VALUE";
+ case CREDIT_CARD_STANDALONE_VERIFICATION_CODE:
+ return "CREDIT_CARD_STANDALONE_VERIFICATION_CODE";
case MAX_VALID_FIELD_TYPE:
return "";
}
@@ -473,6 +401,12 @@ base::StringPiece FieldTypeToStringPiece(HtmlFieldType type) {
return "HTML_TYPE_TEL_EXTENSION";
case HTML_TYPE_EMAIL:
return "HTML_TYPE_EMAIL";
+ case HTML_TYPE_BIRTHDATE_DAY:
+ return "HTML_TYPE_BIRTHDATE_DAY";
+ case HTML_TYPE_BIRTHDATE_MONTH:
+ return "HTML_TYPE_BIRTHDATE_MONTH";
+ case HTML_TYPE_BIRTHDATE_YEAR:
+ return "HTML_TYPE_BIRTHDATE_YEAR";
case HTML_TYPE_TRANSACTION_AMOUNT:
return "HTML_TYPE_TRANSACTION_AMOUNT";
case HTML_TYPE_TRANSACTION_CURRENCY:
@@ -493,6 +427,8 @@ base::StringPiece FieldTypeToStringPiece(HtmlFieldType type) {
return "HTML_TYPE_ONE_TIME_CODE";
case HTML_TYPE_MERCHANT_PROMO_CODE:
return "HTML_TYPE_MERCHANT_PROMO_CODE";
+ case HTML_TYPE_IBAN:
+ return "HTML_TYPE_IBAN";
case HTML_TYPE_UNRECOGNIZED:
return "HTML_TYPE_UNRECOGNIZED";
}
diff --git a/chromium/components/autofill/core/browser/field_types.h b/chromium/components/autofill/core/browser/field_types.h
index adc66c8bec1..d424d24955f 100644
--- a/chromium/components/autofill/core/browser/field_types.h
+++ b/chromium/components/autofill/core/browser/field_types.h
@@ -9,6 +9,7 @@
#include "base/strings/string_piece_forward.h"
#include "components/autofill/core/common/dense_set.h"
+#include "components/autofill/core/common/html_field_types.h"
namespace autofill {
@@ -50,15 +51,7 @@ enum ServerFieldType {
PHONE_HOME_WHOLE_NUMBER = 14,
// Work phone numbers (values [15,19]) are deprecated.
-
- // Fax numbers (values [20,24]) are deprecated in Chrome, but still supported
- // by the server.
- PHONE_FAX_NUMBER = 20,
- PHONE_FAX_CITY_CODE = 21,
- PHONE_FAX_COUNTRY_CODE = 22,
- PHONE_FAX_CITY_AND_NUMBER = 23,
- PHONE_FAX_WHOLE_NUMBER = 24,
-
+ // Fax numbers (values [20,24]) are deprecated.
// Cell phone numbers (values [25, 29]) are deprecated.
ADDRESS_HOME_LINE1 = 30,
@@ -68,15 +61,9 @@ enum ServerFieldType {
ADDRESS_HOME_STATE = 34,
ADDRESS_HOME_ZIP = 35,
ADDRESS_HOME_COUNTRY = 36,
- ADDRESS_BILLING_LINE1 = 37,
- ADDRESS_BILLING_LINE2 = 38,
- ADDRESS_BILLING_APT_NUM = 39,
- ADDRESS_BILLING_CITY = 40,
- ADDRESS_BILLING_STATE = 41,
- ADDRESS_BILLING_ZIP = 42,
- ADDRESS_BILLING_COUNTRY = 43,
- // ADDRESS_SHIPPING values [44,50] are deprecated.
+ // ADDRESS_BILLING values [37, 43] are deprecated.
+ // ADDRESS_SHIPPING values [44, 50] are deprecated.
CREDIT_CARD_NAME_FULL = 51,
CREDIT_CARD_NUMBER = 52,
@@ -93,18 +80,8 @@ enum ServerFieldType {
// Generic type whose default value is known.
FIELD_WITH_DEFAULT_VALUE = 61,
- PHONE_BILLING_NUMBER = 62,
- PHONE_BILLING_CITY_CODE = 63,
- PHONE_BILLING_COUNTRY_CODE = 64,
- PHONE_BILLING_CITY_AND_NUMBER = 65,
- PHONE_BILLING_WHOLE_NUMBER = 66,
-
- NAME_BILLING_FIRST = 67,
- NAME_BILLING_MIDDLE = 68,
- NAME_BILLING_LAST = 69,
- NAME_BILLING_MIDDLE_INITIAL = 70,
- NAME_BILLING_FULL = 71,
- NAME_BILLING_SUFFIX = 72,
+ // PHONE_BILLING values [62, 66] are deprecated.
+ // NAME_BILLING values [67, 72] are deprecated.
// Field types for options generally found in merchant buyflows. Given that
// these are likely to be filled out differently on a case by case basis,
@@ -124,7 +101,7 @@ enum ServerFieldType {
// 123 Main Street,
// Apt. #42
ADDRESS_HOME_STREET_ADDRESS = 77,
- ADDRESS_BILLING_STREET_ADDRESS = 78,
+ // ADDRESS_BILLING_STREET_ADDRESS 78 is deprecated.
// A sorting code is similar to a postal code. However, whereas a postal code
// normally refers to a single geographical location, a sorting code often
@@ -132,17 +109,17 @@ enum ServerFieldType {
// might be geographically distributed. The most prominent example of a
// sorting code system is CEDEX in France.
ADDRESS_HOME_SORTING_CODE = 79,
- ADDRESS_BILLING_SORTING_CODE = 80,
+ // ADDRESS_BILLING_SORTING_CODE 80 is deprecated.
// A dependent locality is a subunit of a locality, where a "locality" is
// roughly equivalent to a city. Examples of dependent localities include
// inner-city districts and suburbs.
ADDRESS_HOME_DEPENDENT_LOCALITY = 81,
- ADDRESS_BILLING_DEPENDENT_LOCALITY = 82,
+ // ADDRESS_BILLING_DEPENDENT_LOCALITY 82 is deprecated.
// The third line of the street address.
ADDRESS_HOME_LINE3 = 83,
- ADDRESS_BILLING_LINE3 = 84,
+ // ADDRESS_BILLING_LINE3 84 is deprecated.
// Inverse of ACCOUNT_CREATION_PASSWORD. Sent when there is data that
// a previous upload of ACCOUNT_CREATION_PASSWORD was incorrect.
@@ -161,6 +138,7 @@ enum ServerFieldType {
CREDIT_CARD_NAME_FIRST = 91,
CREDIT_CARD_NAME_LAST = 92,
+ // Extensions are detected, but not filled.
PHONE_HOME_EXTENSION = 93,
// PROBABLY_ACCOUNT_CREATION_PASSWORD value 94 is deprecated.
@@ -246,7 +224,7 @@ enum ServerFieldType {
// Types to represent a birthdate.
BIRTHDATE_DAY = 118,
BIRTHDATE_MONTH = 119,
- BIRTHDATE_YEAR_4_DIGITS = 120,
+ BIRTHDATE_4_DIGIT_YEAR = 120,
// Types for better trunk prefix support for phone numbers.
// Like PHONE_HOME_CITY_CODE, but with a trunk prefix, if applicable in the
@@ -261,97 +239,16 @@ enum ServerFieldType {
PHONE_HOME_NUMBER_PREFIX = 123,
PHONE_HOME_NUMBER_SUFFIX = 124,
+ // International Bank Account Number (IBAN) details are usually entered on
+ // banking and merchant websites used to make international transactions.
+ // See https://en.wikipedia.org/wiki/International_Bank_Account_Number.
+ IBAN_VALUE = 125,
+
+ // Standalone card verification code (CVC).
+ CREDIT_CARD_STANDALONE_VERIFICATION_CODE = 126,
// No new types can be added without a corresponding change to the Autofill
// server.
- MAX_VALID_FIELD_TYPE = 125,
-};
-
-// The list of all HTML autocomplete field type hints supported by Chrome.
-// See [ http://is.gd/whatwg_autocomplete ] for the full list of specced hints.
-enum HtmlFieldType {
- // Default type.
- HTML_TYPE_UNSPECIFIED,
-
- // Name types.
- HTML_TYPE_NAME,
- HTML_TYPE_HONORIFIC_PREFIX,
- HTML_TYPE_GIVEN_NAME,
- HTML_TYPE_ADDITIONAL_NAME,
- HTML_TYPE_FAMILY_NAME,
-
- // Business types.
- HTML_TYPE_ORGANIZATION,
-
- // Address types.
- HTML_TYPE_STREET_ADDRESS,
- HTML_TYPE_ADDRESS_LINE1,
- HTML_TYPE_ADDRESS_LINE2,
- HTML_TYPE_ADDRESS_LINE3,
- HTML_TYPE_ADDRESS_LEVEL1, // For U.S. addresses, corresponds to the state.
- HTML_TYPE_ADDRESS_LEVEL2, // For U.S. addresses, corresponds to the city.
- HTML_TYPE_ADDRESS_LEVEL3, // An area that is more specific than LEVEL2.
- HTML_TYPE_COUNTRY_CODE, // The ISO 3166-1-alpha-2 country code.
- HTML_TYPE_COUNTRY_NAME, // The localized country name.
- HTML_TYPE_POSTAL_CODE,
- HTML_TYPE_FULL_ADDRESS, // The complete address, formatted for display.
-
- // Credit card types.
- HTML_TYPE_CREDIT_CARD_NAME_FULL,
- HTML_TYPE_CREDIT_CARD_NAME_FIRST,
- HTML_TYPE_CREDIT_CARD_NAME_LAST,
- HTML_TYPE_CREDIT_CARD_NUMBER,
- HTML_TYPE_CREDIT_CARD_EXP,
- HTML_TYPE_CREDIT_CARD_EXP_MONTH,
- HTML_TYPE_CREDIT_CARD_EXP_YEAR,
- HTML_TYPE_CREDIT_CARD_VERIFICATION_CODE,
- HTML_TYPE_CREDIT_CARD_TYPE,
-
- // Phone number types.
- HTML_TYPE_TEL,
- HTML_TYPE_TEL_COUNTRY_CODE,
- HTML_TYPE_TEL_NATIONAL,
- HTML_TYPE_TEL_AREA_CODE,
- HTML_TYPE_TEL_LOCAL,
- HTML_TYPE_TEL_LOCAL_PREFIX,
- HTML_TYPE_TEL_LOCAL_SUFFIX,
- HTML_TYPE_TEL_EXTENSION,
-
- // Email.
- HTML_TYPE_EMAIL,
-
- // Transaction details.
- HTML_TYPE_TRANSACTION_AMOUNT,
- HTML_TYPE_TRANSACTION_CURRENCY,
-
- // Variants of type hints specified in the HTML specification that are
- // inferred based on a field's 'maxlength' attribute.
- // TODO(isherman): Remove these types, in favor of understanding maxlength
- // when filling fields. See also: AutofillField::phone_part_.
- HTML_TYPE_ADDITIONAL_NAME_INITIAL,
- HTML_TYPE_CREDIT_CARD_EXP_DATE_2_DIGIT_YEAR,
- HTML_TYPE_CREDIT_CARD_EXP_DATE_4_DIGIT_YEAR,
- HTML_TYPE_CREDIT_CARD_EXP_2_DIGIT_YEAR,
- HTML_TYPE_CREDIT_CARD_EXP_4_DIGIT_YEAR,
-
- // Universal Payment Interface - Virtual Payment Address.
- HTML_TYPE_UPI_VPA,
-
- // Phone number verification one-time-codes.
- HTML_TYPE_ONE_TIME_CODE,
-
- // Promo code for merchant sites.
- HTML_TYPE_MERCHANT_PROMO_CODE,
-
- // Non-standard autocomplete types.
- HTML_TYPE_UNRECOGNIZED,
-};
-
-// The list of all HTML autocomplete field mode hints supported by Chrome.
-// See [ http://is.gd/whatwg_autocomplete ] for the full list of specced hints.
-enum HtmlFieldMode {
- HTML_MODE_NONE,
- HTML_MODE_BILLING,
- HTML_MODE_SHIPPING,
+ MAX_VALID_FIELD_TYPE = 127,
};
enum class FieldTypeGroup {
diff --git a/chromium/components/autofill/core/browser/field_types_unittest.cc b/chromium/components/autofill/core/browser/field_types_unittest.cc
index f4afb70f6f9..c0b406bddc7 100644
--- a/chromium/components/autofill/core/browser/field_types_unittest.cc
+++ b/chromium/components/autofill/core/browser/field_types_unittest.cc
@@ -36,13 +36,6 @@ TEST(FieldTypesTest, IsValidServerFieldType) {
ADDRESS_HOME_STATE,
ADDRESS_HOME_ZIP,
ADDRESS_HOME_COUNTRY,
- ADDRESS_BILLING_LINE1,
- ADDRESS_BILLING_LINE2,
- ADDRESS_BILLING_APT_NUM,
- ADDRESS_BILLING_CITY,
- ADDRESS_BILLING_STATE,
- ADDRESS_BILLING_ZIP,
- ADDRESS_BILLING_COUNTRY,
CREDIT_CARD_NAME_FULL,
CREDIT_CARD_NUMBER,
CREDIT_CARD_EXP_MONTH,
@@ -50,33 +43,19 @@ TEST(FieldTypesTest, IsValidServerFieldType) {
CREDIT_CARD_EXP_4_DIGIT_YEAR,
CREDIT_CARD_EXP_DATE_2_DIGIT_YEAR,
CREDIT_CARD_EXP_DATE_4_DIGIT_YEAR,
+ CREDIT_CARD_STANDALONE_VERIFICATION_CODE,
CREDIT_CARD_TYPE,
CREDIT_CARD_VERIFICATION_CODE,
COMPANY_NAME,
FIELD_WITH_DEFAULT_VALUE,
- PHONE_BILLING_NUMBER,
- PHONE_BILLING_CITY_CODE,
- PHONE_BILLING_COUNTRY_CODE,
- PHONE_BILLING_CITY_AND_NUMBER,
- PHONE_BILLING_WHOLE_NUMBER,
- NAME_BILLING_FIRST,
- NAME_BILLING_MIDDLE,
- NAME_BILLING_LAST,
- NAME_BILLING_MIDDLE_INITIAL,
- NAME_BILLING_FULL,
- NAME_BILLING_SUFFIX,
MERCHANT_EMAIL_SIGNUP,
MERCHANT_PROMO_CODE,
PASSWORD,
ACCOUNT_CREATION_PASSWORD,
ADDRESS_HOME_STREET_ADDRESS,
- ADDRESS_BILLING_STREET_ADDRESS,
ADDRESS_HOME_SORTING_CODE,
- ADDRESS_BILLING_SORTING_CODE,
ADDRESS_HOME_DEPENDENT_LOCALITY,
- ADDRESS_BILLING_DEPENDENT_LOCALITY,
ADDRESS_HOME_LINE3,
- ADDRESS_BILLING_LINE3,
NOT_ACCOUNT_CREATION_PASSWORD,
USERNAME,
USERNAME_AND_EMAIL_ADDRESS,
@@ -94,6 +73,7 @@ TEST(FieldTypesTest, IsValidServerFieldType) {
SINGLE_USERNAME,
NOT_USERNAME,
UPI_VPA,
+ IBAN_VALUE,
ADDRESS_HOME_STREET_NAME,
ADDRESS_HOME_HOUSE_NUMBER,
ADDRESS_HOME_SUBPREMISE,
@@ -111,7 +91,7 @@ TEST(FieldTypesTest, IsValidServerFieldType) {
NAME_FULL_WITH_HONORIFIC_PREFIX,
BIRTHDATE_DAY,
BIRTHDATE_MONTH,
- BIRTHDATE_YEAR_4_DIGITS,
+ BIRTHDATE_4_DIGIT_YEAR,
};
ServerFieldType kInvalidValue = static_cast<ServerFieldType>(123456);
ASSERT_FALSE(kValidFieldTypes.count(kInvalidValue));
diff --git a/chromium/components/autofill/core/browser/form_data_importer.cc b/chromium/components/autofill/core/browser/form_data_importer.cc
index e87e427c1e8..609323198c9 100644
--- a/chromium/components/autofill/core/browser/form_data_importer.cc
+++ b/chromium/components/autofill/core/browser/form_data_importer.cc
@@ -38,7 +38,6 @@
#include "components/autofill/core/browser/payments/virtual_card_enrollment_manager.h"
#include "components/autofill/core/browser/personal_data_manager.h"
#include "components/autofill/core/browser/validation.h"
-#include "components/autofill/core/common/autofill_clock.h"
#include "components/autofill/core/common/autofill_features.h"
#include "components/autofill/core/common/autofill_internals/log_message.h"
#include "components/autofill/core/common/autofill_internals/logging_scope.h"
@@ -80,145 +79,52 @@ bool IsValidFieldTypeAndValue(const ServerFieldTypeSet types_seen,
? field_type_group != FieldTypeGroup::kPhoneBilling &&
field_type_group != FieldTypeGroup::kPhoneHome
: field_type != PHONE_HOME_NUMBER)) {
- if (import_log_buffer) {
- *import_log_buffer << LogMessage::kImportAddressProfileFromFormFailed
- << "Multiple fields of type "
- << AutofillType::ServerFieldTypeToString(field_type)
- << "." << CTag{};
- }
+ LOG_AF(import_log_buffer)
+ << LogMessage::kImportAddressProfileFromFormFailed
+ << "Multiple fields of type "
+ << AutofillType::ServerFieldTypeToString(field_type) << "." << CTag{};
return false;
}
// Abandon the import if an email address value shows up in a field that is
// not an email address.
if (field_type != EMAIL_ADDRESS && IsValidEmailAddress(value)) {
- if (import_log_buffer) {
- *import_log_buffer << LogMessage::kImportAddressProfileFromFormFailed
- << "Email address found in field of different type: "
- << AutofillType::ServerFieldTypeToString(field_type)
- << CTag{};
- }
+ LOG_AF(import_log_buffer)
+ << LogMessage::kImportAddressProfileFromFormFailed
+ << "Email address found in field of different type: "
+ << AutofillType::ServerFieldTypeToString(field_type) << CTag{};
return false;
}
return true;
}
-// Returns true if minimum requirements for import of a given |profile| have
-// been met. An address submitted via a form must have at least the fields
-// required as determined by its country code.
-// No verification of validity of the contents is performed. This is an
-// existence check only.
-bool IsMinimumAddress(const AutofillProfile& profile,
- const std::string& predicted_country_code,
- const std::string& app_locale,
- LogBuffer* import_log_buffer,
- bool collect_metrics) {
- AutofillCountry country(predicted_country_code, app_locale);
-
- // Include the details of the country to the log.
- if (import_log_buffer)
- *import_log_buffer << country;
-
- // Check the |ADDRESS_HOME_LINE1| requirement.
- bool is_line1_missing = false;
- if (country.requires_line1() && !profile.HasRawInfo(ADDRESS_HOME_LINE1) &&
- !profile.HasRawInfo(ADDRESS_HOME_STREET_NAME)) {
- if (import_log_buffer) {
- *import_log_buffer << LogMessage::kImportAddressProfileFromFormFailed
- << "Missing required ADDRESS_HOME_LINE1." << CTag{};
- }
- is_line1_missing = true;
- }
-
- // Check the |ADDRESS_HOME_CITY| requirement.
- bool is_city_missing = false;
- if (country.requires_city() && !profile.HasRawInfo(ADDRESS_HOME_CITY)) {
- if (import_log_buffer) {
- *import_log_buffer << LogMessage::kImportAddressProfileFromFormFailed
- << "Missing required ADDRESS_HOME_CITY." << CTag{};
- }
- is_city_missing = true;
- }
-
- // Check the |ADDRESS_HOME_STATE| requirement.
- bool is_state_missing = false;
- if (country.requires_state() && !profile.HasRawInfo(ADDRESS_HOME_STATE)) {
- if (import_log_buffer) {
- *import_log_buffer << LogMessage::kImportAddressProfileFromFormFailed
- << "Missing required ADDRESS_HOME_STATE." << CTag{};
- }
- is_state_missing = true;
- }
-
- // Check the |ADDRESS_HOME_ZIP| requirement.
- bool is_zip_missing = false;
- if (country.requires_zip() && !profile.HasRawInfo(ADDRESS_HOME_ZIP)) {
- if (import_log_buffer) {
- *import_log_buffer << LogMessage::kImportAddressProfileFromFormFailed
- << "Missing required ADDRESS_HOME_ZIP." << CTag{};
- }
- is_zip_missing = true;
+// |imported_credit_card| refers to credit card that was most recently submitted
+// and |fetched_card_instrument_id| refers to the instrument id of the most
+// recently downstreamed (fetched from the server) credit card. These need to
+// match to offer virtual card enrollment for the |imported_credit_card| .
+bool ShouldOfferVirtualCardEnrollment(
+ const CreditCard* imported_credit_card,
+ absl::optional<int64_t> fetched_card_instrument_id) {
+ if (!base::FeatureList::IsEnabled(
+ features::kAutofillEnableUpdateVirtualCardEnrollment)) {
+ return false;
}
- bool is_zip_or_state_requirement_violated = false;
- if (country.requires_zip_or_state() &&
- !profile.HasRawInfo(ADDRESS_HOME_ZIP) &&
- !profile.HasRawInfo(ADDRESS_HOME_STATE)) {
- if (import_log_buffer) {
- *import_log_buffer
- << LogMessage::kImportAddressProfileFromFormFailed
- << "Missing required ADDRESS_HOME_ZIP or ADDRESS_HOME_STATE."
- << CTag{};
- }
- is_zip_or_state_requirement_violated = true;
- }
+ if (!imported_credit_card)
+ return false;
- bool is_line1_or_house_number_violated = false;
- if (country.requires_line1_or_house_number() &&
- !profile.HasRawInfo(ADDRESS_HOME_LINE1) &&
- !profile.HasRawInfo(ADDRESS_HOME_HOUSE_NUMBER)) {
- if (import_log_buffer) {
- *import_log_buffer
- << LogMessage::kImportAddressProfileFromFormFailed
- << "Missing required ADDRESS_HOME_LINE1 or ADDRESS_HOME_HOUSE_NUMBER."
- << CTag{};
- }
- is_line1_or_house_number_violated = true;
+ if (imported_credit_card->virtual_card_enrollment_state() !=
+ CreditCard::VirtualCardEnrollmentState::UNENROLLED_AND_ELIGIBLE) {
+ return false;
}
- // Collect metrics regarding the requirements.
- if (collect_metrics) {
- AutofillMetrics::LogAddressFormImportRequirementMetric(
- is_line1_missing
- ? AddressImportRequirement::LINE1_REQUIREMENT_VIOLATED
- : AddressImportRequirement::LINE1_REQUIREMENT_FULFILLED);
-
- AutofillMetrics::LogAddressFormImportRequirementMetric(
- is_city_missing ? AddressImportRequirement::CITY_REQUIREMENT_VIOLATED
- : AddressImportRequirement::CITY_REQUIREMENT_FULFILLED);
-
- AutofillMetrics::LogAddressFormImportRequirementMetric(
- is_state_missing
- ? AddressImportRequirement::STATE_REQUIREMENT_VIOLATED
- : AddressImportRequirement::STATE_REQUIREMENT_FULFILLED);
-
- AutofillMetrics::LogAddressFormImportRequirementMetric(
- is_zip_missing ? AddressImportRequirement::ZIP_REQUIREMENT_VIOLATED
- : AddressImportRequirement::ZIP_REQUIREMENT_FULFILLED);
-
- AutofillMetrics::LogAddressFormImportRequirementMetric(
- is_zip_or_state_requirement_violated
- ? AddressImportRequirement::ZIP_OR_STATE_REQUIREMENT_VIOLATED
- : AddressImportRequirement::ZIP_OR_STATE_REQUIREMENT_FULFILLED);
-
- AutofillMetrics::LogAddressFormImportCountrySpecificFieldRequirementsMetric(
- is_zip_missing, is_state_missing, is_city_missing, is_line1_missing);
+ if (!fetched_card_instrument_id.has_value() ||
+ imported_credit_card->instrument_id() !=
+ fetched_card_instrument_id.value()) {
+ return false;
}
- // Return true if all requirements are fulfilled.
- return !(is_line1_missing || is_city_missing || is_state_missing ||
- is_zip_missing || is_zip_or_state_requirement_violated ||
- is_line1_or_house_number_violated);
+ return true;
}
} // namespace
@@ -250,7 +156,9 @@ FormDataImporter::FormDataImporter(AutofillClient* client,
virtual_card_enrollment_manager_(
std::make_unique<VirtualCardEnrollmentManager>(personal_data_manager,
payments_client,
- client)) {
+ client)),
+ multistep_importer_(app_locale,
+ client_->GetVariationConfigCountryCode()) {
if (personal_data_manager_)
personal_data_manager_->AddObserver(this);
}
@@ -291,6 +199,7 @@ void FormDataImporter::ImportFormData(const FormStructure& submitted_form,
bool cc_prompt_potentially_shown = ProcessCreditCardImportCandidate(
submitted_form, std::move(imported_credit_card), detected_upi_id,
credit_card_autofill_enabled, is_credit_card_upstream_enabled);
+ fetched_card_instrument_id_.reset();
// If a prompt for credit cards is potentially shown, do not allow for a
// second address profile import dialog.
@@ -305,44 +214,6 @@ CreditCard FormDataImporter::ExtractCreditCardFromForm(
}
// static
-std::string FormDataImporter::GetPredictedCountryCode(
- const AutofillProfile& profile,
- const std::string& variation_country_code,
- const std::string& app_locale,
- LogBuffer* import_log_buffer) {
- // Try to acquire the country code form the filled form.
- std::string country_code =
- base::UTF16ToASCII(profile.GetRawInfo(ADDRESS_HOME_COUNTRY));
-
- if (import_log_buffer && !country_code.empty()) {
- *import_log_buffer << LogMessage::kImportAddressProfileFromFormCountrySource
- << "Country entry in form." << CTag{};
- }
-
- // As a fallback, use the variation service state to get a country code.
- if (country_code.empty() && !variation_country_code.empty()) {
- country_code = variation_country_code;
- if (import_log_buffer) {
- *import_log_buffer
- << LogMessage::kImportAddressProfileFromFormCountrySource
- << "Variations service." << CTag{};
- }
- }
-
- // As the last resort, derive the country code from the app_locale.
- if (country_code.empty()) {
- country_code = AutofillCountry::CountryCodeForLocale(app_locale);
- if (import_log_buffer && !country_code.empty()) {
- *import_log_buffer
- << LogMessage::kImportAddressProfileFromFormCountrySource
- << "App locale." << CTag{};
- }
- }
-
- return country_code;
-}
-
-// static
bool FormDataImporter::IsValidLearnableProfile(
const AutofillProfile& profile,
const std::string& predicted_country_code,
@@ -352,32 +223,28 @@ bool FormDataImporter::IsValidLearnableProfile(
bool is_email_invalid = false;
std::u16string email = profile.GetRawInfo(EMAIL_ADDRESS);
if (!email.empty() && !IsValidEmailAddress(email)) {
- if (import_log_buffer) {
- *import_log_buffer << LogMessage::kImportAddressProfileFromFormFailed
- << "Invalid email address." << CTag{};
- }
+ LOG_AF(import_log_buffer) << LogMessage::kImportAddressProfileFromFormFailed
+ << "Invalid email address." << CTag{};
is_email_invalid = true;
}
// Reject profiles with an invalid |HOME_ADDRESS_STATE| entry.
bool is_state_invalid = false;
if (profile.IsPresentButInvalid(ADDRESS_HOME_STATE)) {
- if (import_log_buffer)
- *import_log_buffer
- << LogMessage::kImportAddressProfileFromFormFailed
- << "Invalid state as of AutofillProfile::IsPresentButInvalid()."
- << CTag{};
+ LOG_AF(import_log_buffer)
+ << LogMessage::kImportAddressProfileFromFormFailed
+ << "Invalid state as of AutofillProfile::IsPresentButInvalid()."
+ << CTag{};
is_state_invalid = true;
}
// Reject profiles with an invalid |HOME_ADDRESS_ZIP| entry.
bool is_zip_invalid = false;
if (profile.IsPresentButInvalid(ADDRESS_HOME_ZIP)) {
- if (import_log_buffer)
- *import_log_buffer
- << LogMessage::kImportAddressProfileFromFormFailed
- << "Invalid ZIP as of AutofillProfile::IsPresentButInvalid()."
- << CTag{};
+ LOG_AF(import_log_buffer)
+ << LogMessage::kImportAddressProfileFromFormFailed
+ << "Invalid ZIP as of AutofillProfile::IsPresentButInvalid()."
+ << CTag{};
is_zip_invalid = true;
}
@@ -484,6 +351,10 @@ void FormDataImporter::CacheFetchedVirtualCard(
fetched_virtual_cards_.insert(last_four);
}
+void FormDataImporter::SetFetchedCardInstrumentId(int64_t instrument_id) {
+ fetched_card_instrument_id_ = instrument_id;
+}
+
bool FormDataImporter::ImportFormData(
const FormStructure& submitted_form,
bool profile_autofill_enabled,
@@ -528,11 +399,12 @@ bool FormDataImporter::ImportAddressProfiles(
const FormStructure& form,
std::vector<AddressProfileImportCandidate>& import_candidates) {
// Create a buffer to collect logging output for the autofill-internals.
- LogBuffer import_log_buffer;
- import_log_buffer << LoggingScope::kAddressProfileFormImport;
+ LogManager* log_manager = client_->GetLogManager();
+ LogBuffer import_log_buffer(IsLoggingActive(log_manager));
+ LOG_AF(import_log_buffer) << LoggingScope::kAddressProfileFormImport;
// Print the full form into the logging scope.
- import_log_buffer << LogMessage::kImportAddressProfileFromForm << form
- << CTag{};
+ LOG_AF(import_log_buffer)
+ << LogMessage::kImportAddressProfileFromForm << form << CTag{};
// We save a maximum of 2 profiles per submitted form (e.g. for shipping and
// billing).
@@ -540,31 +412,32 @@ bool FormDataImporter::ImportAddressProfiles(
size_t num_complete_profiles = 0;
if (!form.field_count()) {
- import_log_buffer << LogMessage::kImportAddressProfileFromFormFailed
- << "Form is empty." << CTag{};
+ LOG_AF(import_log_buffer) << LogMessage::kImportAddressProfileFromFormFailed
+ << "Form is empty." << CTag{};
} else {
// Relevant sections for address fields.
- std::set<std::string> sections;
+ std::set<Section> sections;
for (const auto& field : form) {
if (field->Type().group() != FieldTypeGroup::kCreditCard)
sections.insert(field->section);
}
- for (const std::string& section : sections) {
+ for (const Section& section : sections) {
if (num_complete_profiles == kMaxNumAddressProfilesSaved)
break;
// Log the output from a section in a separate div for readability.
- import_log_buffer << Tag{"div"}
- << Attrib{"class", "profile_import_from_form_section"};
- import_log_buffer << LogMessage::kImportAddressProfileFromFormSection
- << section << CTag{};
+ LOG_AF(import_log_buffer)
+ << Tag{"div"} << Attrib{"class", "profile_import_from_form_section"};
+ LOG_AF(import_log_buffer)
+ << LogMessage::kImportAddressProfileFromFormSection << section
+ << CTag{};
// Try to import an address profile from the form fields of this section.
// Only allow for a prompt if no other complete profile was found so far.
if (ImportAddressProfileForSection(form, section, import_candidates,
&import_log_buffer))
num_complete_profiles++;
// And close the div of the section import log.
- import_log_buffer << CTag{"div"};
+ LOG_AF(import_log_buffer) << CTag{"div"};
}
// Run the import on the union of the section if the import was not
// successful and if there is more than one section.
@@ -573,7 +446,7 @@ bool FormDataImporter::ImportAddressProfiles(
AutofillMetrics::AddressProfileImportStatusMetric::REGULAR_IMPORT);
} else if (sections.size() > 1) {
// Try to import by combining all sections.
- if (ImportAddressProfileForSection(form, "", import_candidates,
+ if (ImportAddressProfileForSection(form, absl::nullopt, import_candidates,
&import_log_buffer)) {
num_complete_profiles++;
AutofillMetrics::LogAddressFormImportStatusMetric(
@@ -586,20 +459,19 @@ bool FormDataImporter::ImportAddressProfiles(
AutofillMetrics::AddressProfileImportStatusMetric::NO_IMPORT);
}
}
- import_log_buffer << LogMessage::kImportAddressProfileFromFormNumberOfImports
- << num_complete_profiles << CTag{};
+ LOG_AF(import_log_buffer)
+ << LogMessage::kImportAddressProfileFromFormNumberOfImports
+ << num_complete_profiles << CTag{};
// Write log buffer to autofill-internals.
- LogManager* log_manager = client_->GetLogManager();
- if (log_manager)
- log_manager->Log() << std::move(import_log_buffer);
+ LOG_AF(log_manager) << std::move(import_log_buffer);
return num_complete_profiles > 0;
}
bool FormDataImporter::ImportAddressProfileForSection(
const FormStructure& form,
- const std::string& section,
+ const absl::optional<Section>& section,
std::vector<AddressProfileImportCandidate>& import_candidates,
LogBuffer* import_log_buffer) {
// The candidate for profile import. There are many ways for the candidate to
@@ -639,8 +511,8 @@ bool FormDataImporter::ImportAddressProfileForSection(
// Go through each |form| field and attempt to constitute a valid profile.
for (const auto& field : form) {
// Reject fields that are not within the specified |section|.
- // If section is empty, use all fields.
- if (field->section != section && !section.empty())
+ // If no section is passed, use all fields.
+ if (section && field->section != *section)
continue;
std::u16string value;
@@ -673,11 +545,9 @@ bool FormDataImporter::ImportAddressProfileForSection(
if (server_field_type == EMAIL_ADDRESS &&
types_seen.count(server_field_type) &&
candidate_profile.GetRawInfo(EMAIL_ADDRESS) != value) {
- if (import_log_buffer) {
- *import_log_buffer << LogMessage::kImportAddressProfileFromFormFailed
- << "Multiple different email addresses present."
- << CTag{};
- }
+ LOG_AF(import_log_buffer)
+ << LogMessage::kImportAddressProfileFromFormFailed
+ << "Multiple different email addresses present." << CTag{};
has_multiple_distinct_email_addresses = true;
}
@@ -737,10 +607,9 @@ bool FormDataImporter::ImportAddressProfileForSection(
}
// Check if the country code was still not determined correctly.
if (!candidate_profile.HasRawInfo(ADDRESS_HOME_COUNTRY)) {
- if (import_log_buffer) {
- *import_log_buffer << LogMessage::kImportAddressProfileFromFormFailed
- << "Missing country." << CTag{};
- }
+ LOG_AF(import_log_buffer)
+ << LogMessage::kImportAddressProfileFromFormFailed
+ << "Missing country." << CTag{};
has_invalid_country = true;
}
}
@@ -760,10 +629,9 @@ bool FormDataImporter::ImportAddressProfileForSection(
import_metadata.did_remove_invalid_phone_number = true;
} else {
has_invalid_phone_number = true;
- if (import_log_buffer) {
- *import_log_buffer << LogMessage::kImportAddressProfileFromFormFailed
- << "Invalid phone number." << CTag{};
- }
+ LOG_AF(import_log_buffer)
+ << LogMessage::kImportAddressProfileFromFormFailed
+ << "Invalid phone number." << CTag{};
}
}
@@ -784,8 +652,9 @@ bool FormDataImporter::ImportAddressProfileForSection(
// This requires the profile to be finalized to apply the merging logic.
if (finalized_import && has_address_related_fields &&
!has_invalid_information) {
- ProcessMultiStepImport(candidate_profile, import_metadata,
- url::Origin::Create(form.source_url()));
+ multistep_importer_.ProcessMultiStepImport(
+ candidate_profile, import_metadata,
+ url::Origin::Create(form.source_url()));
// The predicted country code has possibly changed, if |candidate_profile|
// was merged with a profile containing country information.
predicted_country_code =
@@ -925,15 +794,11 @@ bool FormDataImporter::ProcessCreditCardImportCandidate(
if (client_->IsAutofillAssistantShowing())
return false;
- if (base::FeatureList::IsEnabled(
- features::kAutofillEnableUpdateVirtualCardEnrollment)) {
- if (imported_credit_card &&
- imported_credit_card->virtual_card_enrollment_state() ==
- CreditCard::VirtualCardEnrollmentState::UNENROLLED_AND_ELIGIBLE) {
- virtual_card_enrollment_manager_->InitVirtualCardEnroll(
- *imported_credit_card, VirtualCardEnrollmentSource::kDownstream);
- return true;
- }
+ if (ShouldOfferVirtualCardEnrollment(imported_credit_card.get(),
+ fetched_card_instrument_id_)) {
+ virtual_card_enrollment_manager_->InitVirtualCardEnroll(
+ *imported_credit_card, VirtualCardEnrollmentSource::kDownstream);
+ return true;
}
#if !BUILDFLAG(IS_ANDROID) && !BUILDFLAG(IS_IOS)
@@ -1217,114 +1082,16 @@ bool FormDataImporter::ShouldOfferUploadCardOrLocalCardSave(
return true;
}
-void FormDataImporter::ProcessMultiStepImport(
- AutofillProfile& profile,
- ProfileImportMetadata& import_metadata,
- const url::Origin& origin) {
- if (!base::FeatureList::IsEnabled(
- features::kAutofillEnableMultiStepImports)) {
- return;
- }
-
- RemoveOutdatedMultiStepCandidates(origin);
- bool has_min_address_requirements =
- MergeProfileWithMultiStepCandidates(profile, import_metadata, origin);
-
- if (!has_min_address_requirements ||
- features::kAutofillEnableMultiStepImportComplements.Get()) {
- // Add |profile| as a |multistep_candidate|. This happens for incomplete
- // profiles, which can then be complemented in later steps. When
- // |kAutofillEnableMultiStepImportComplements| is enabled, complete profiles
- // are stored too, which enables updating them in later steps.
- // In the latter case, Autofill tries to import the `profile`. This logs
- // metrics depending on `import_metadata`. To prevent double counting,
- // an we store an empty `ProfileImportMetadata` object in this case.
- multistep_candidates_.push_front(MultiStepFormProfileCandidate{
- .profile = profile,
- .import_metadata = has_min_address_requirements
- ? ProfileImportMetadata()
- : import_metadata,
- .timestamp = AutofillClock::Now()});
- multistep_candidates_origin_ = origin;
- }
-}
-
-void FormDataImporter::RemoveOutdatedMultiStepCandidates(
- const url::Origin& origin) {
- // All |multistep_candidates| share |multistep_candidates_origin|.
- if (multistep_candidates_origin_.has_value() &&
- multistep_candidates_origin_.value() != origin) {
- multistep_candidates_.clear();
- } else {
- // Remove candidates that reached their TTL.
- const base::TimeDelta ttl =
- features::kAutofillMultiStepImportCandidateTTL.Get();
- const base::Time now = AutofillClock::Now();
- while (!multistep_candidates_.empty() &&
- now - multistep_candidates_.back().timestamp > ttl) {
- multistep_candidates_.pop_back();
- }
- }
- if (multistep_candidates_.empty()) {
- multistep_candidates_origin_.reset();
- }
-}
-
-bool FormDataImporter::MergeProfileWithMultiStepCandidates(
- AutofillProfile& profile,
- ProfileImportMetadata& import_metadata,
- const url::Origin& origin) {
- // Greedily merge with a prefix of |multistep_candidates|.
- AutofillProfileComparator comparator(app_locale_);
- std::deque<MultiStepFormProfileCandidate>::iterator merge_candidate =
- multistep_candidates_.begin();
- AutofillProfile completed_profile = profile;
- ProfileImportMetadata completed_metadata = import_metadata;
- // Country completion has not happened yet, so this field can be ignored.
- DCHECK(!completed_metadata.did_remove_invalid_phone_number);
- while (
- merge_candidate != multistep_candidates_.end() &&
- comparator.AreMergeable(completed_profile, merge_candidate->profile) &&
- completed_profile.MergeDataFrom(merge_candidate->profile, app_locale_)) {
- // ProfileImportMetadata is only relevant for metrics. If the phone number
- // was removed from a partial profile, we still want that removal to appear
- // in the metrics, because it would have hindered that partial profile from
- // import and merging.
- completed_metadata.did_remove_invalid_phone_number |=
- merge_candidate->import_metadata.did_remove_invalid_phone_number;
- merge_candidate++;
- }
-
- // The minimum address requirements depend on the country, which has possibly
- // changed as a result of the merge.
- if (IsMinimumAddress(
- completed_profile,
- GetPredictedCountryCode(completed_profile,
- client_->GetVariationConfigCountryCode(),
- app_locale_, /*import_log_buffer=*/nullptr),
- app_locale_,
- /*import_log_buffer=*/nullptr, /*collect_metrics=*/false)) {
- profile = std::move(completed_profile);
- import_metadata = std::move(completed_metadata);
- multistep_candidates_.clear();
- return true;
- } else {
- // Remove all profiles that couldn't be merged.
- multistep_candidates_.erase(merge_candidate, multistep_candidates_.end());
- return false;
- }
-}
-
void FormDataImporter::OnBrowsingHistoryCleared(
const history::DeletionInfo& deletion_info) {
// Delete all multi-step import candidates when:
// - The entire browsing history is cleared, or
- // - At least one URL from the same origin as `multistep_candidates_origin_`
+ // - At least one URL from the same origin as `multistep_importer_`
// is deleted.
if (deletion_info.IsAllHistory() ||
- (multistep_candidates_origin_.has_value() &&
+ (multistep_importer_.Origin() &&
base::Contains(deletion_info.deleted_rows(),
- *multistep_candidates_origin_,
+ *multistep_importer_.Origin(),
[](const history::URLRow& url_row) {
return url::Origin::Create(url_row.url());
}))) {
diff --git a/chromium/components/autofill/core/browser/form_data_importer.h b/chromium/components/autofill/core/browser/form_data_importer.h
index 70abf5e3f42..5a27bb327e2 100644
--- a/chromium/components/autofill/core/browser/form_data_importer.h
+++ b/chromium/components/autofill/core/browser/form_data_importer.h
@@ -5,7 +5,6 @@
#ifndef COMPONENTS_AUTOFILL_CORE_BROWSER_FORM_DATA_IMPORTER_H_
#define COMPONENTS_AUTOFILL_CORE_BROWSER_FORM_DATA_IMPORTER_H_
-#include <deque>
#include <map>
#include <memory>
#include <string>
@@ -13,10 +12,10 @@
#include "base/gtest_prod_util.h"
#include "base/memory/raw_ptr.h"
-#include "base/time/time.h"
#include "build/build_config.h"
#include "components/autofill/core/browser/autofill_client.h"
#include "components/autofill/core/browser/autofill_profile_import_process.h"
+#include "components/autofill/core/browser/form_data_importer_utils.h"
#include "components/autofill/core/browser/form_structure.h"
#include "components/autofill/core/browser/payments/credit_card_save_manager.h"
#include "components/autofill/core/browser/payments/local_card_migration_manager.h"
@@ -73,19 +72,6 @@ class FormDataImporter : public PersonalDataManagerObserver {
// duplicated field types in the form.
CreditCard ExtractCreditCardFromForm(const FormStructure& form);
- // Tries to infer the country |profile| is from, which can be useful to
- // verify whether the data is sensible. Returns a two-letter ISO country code
- // by considering, in decreasing order of priority:
- // - The country specified in |profile|
- // - The country determined by the variation service stored in
- // |variation_country_code|
- // - The country code corresponding to |app_locale|
- static std::string GetPredictedCountryCode(
- const AutofillProfile& profile,
- const std::string& variation_country_code,
- const std::string& app_locale,
- LogBuffer* import_log_buffer);
-
// Checks suitability of |profile| for adding to the user's set of profiles.
static bool IsValidLearnableProfile(const AutofillProfile& profile,
const std::string& predicted_country_code,
@@ -106,10 +92,10 @@ class FormDataImporter : public PersonalDataManagerObserver {
return virtual_card_enrollment_manager_.get();
}
- void ClearMultiStepImportCandidates() {
- multistep_candidates_.clear();
- multistep_candidates_origin_.reset();
- }
+ void ClearMultiStepImportCandidates() { multistep_importer_.Clear(); }
+
+ // See comment for |fetched_card_instrument_id_|.
+ void SetFetchedCardInstrumentId(int64_t instrument_id);
// PersonalDataManagerObserver
void OnBrowsingHistoryCleared(
@@ -130,6 +116,12 @@ class FormDataImporter : public PersonalDataManagerObserver {
}
#endif // !BUILDFLAG(IS_ANDROID) && !BUILDFLAG(IS_IOS)
+ // The instrument id of the card that has been most recently retrieved via
+ // Autofill Downstream (card retrieval from server). This can be used to
+ // decide whether the card submitted is the same card retrieved. This field is
+ // optional and is set when an Autofill Downstream has happened.
+ absl::optional<int64_t> fetched_card_instrument_id_;
+
private:
// Defines a candidate for address profile import.
struct AddressProfileImportCandidate {
@@ -170,11 +162,11 @@ class FormDataImporter : public PersonalDataManagerObserver {
std::vector<AddressProfileImportCandidate>& import_candidates);
// Helper method for ImportAddressProfiles which only considers the fields for
- // a specified |section|. If |section| is the empty string, the import is
- // performed on the union of all sections.
+ // a specified |section|. If no section is passed, the import is performed on
+ // the union of all sections.
bool ImportAddressProfileForSection(
const FormStructure& form,
- const std::string& section,
+ const absl::optional<Section>& section,
std::vector<AddressProfileImportCandidate>& import_candidates,
LogBuffer* import_log_buffer);
@@ -262,33 +254,6 @@ class FormDataImporter : public PersonalDataManagerObserver {
AutofillProfile& profile,
const std::string& predicted_country_code);
- // Removes updated multi-step candidates, merges |profile| with multi-step
- // candidates and potentially stores it as a multi-step candidate itself.
- // |profile| and |import_metadata| are updated accordingly, if the profile can
- // be merged. See |MergeProfileWithMultiStepCandidates()| for details.
- // Only applicable when |kAutofillEnableMultiStepImports| is enabled.
- void ProcessMultiStepImport(AutofillProfile& profile,
- ProfileImportMetadata& import_metadata,
- const url::Origin& origin);
-
- // Removes any MultiStepFormProfileCandidate from |multistep_candidates_| that
- // reached their TTL or have a different |origin|.
- void RemoveOutdatedMultiStepCandidates(const url::Origin& origin);
-
- // Merges a given |profile| stepwise with |multistep_candidates_| to
- // complete it. |profile| is assumed to contain no invalid information.
- // Returns true if the resulting profile satisfies the minimum address
- // requirements. |profile| and |import_metadata| are updated in this case with
- // the result of merging all relevant candidates.
- // Returns false otherwise and leaves |profile| and |import_metadata|
- // unchanged.
- // Any merged or colliding |multistep_candidates_| are cleared.
- // |origin|: The origin of the form where |profile| was imported from.
- bool MergeProfileWithMultiStepCandidates(
- AutofillProfile& profile,
- ProfileImportMetadata& import_metadata,
- const url::Origin& origin);
-
// Whether a dynamic change form is imported.
bool from_dynamic_change_form_ = false;
@@ -333,22 +298,8 @@ class FormDataImporter : public PersonalDataManagerObserver {
std::unique_ptr<VirtualCardEnrollmentManager>
virtual_card_enrollment_manager_;
- // Represents a submitted form, stored to be considered as a merge candidate
- // for other candidate profiles in future submits in a multi-step import flow.
- struct MultiStepFormProfileCandidate {
- // The import candidate.
- AutofillProfile profile;
- // Metadata about how |profile| was constructed.
- ProfileImportMetadata import_metadata;
- // Timestamp when the submit happened.
- base::Time timestamp;
- };
- // Current multi-step import candidates, in increasing order of their
- // |timestamp|.
- std::deque<MultiStepFormProfileCandidate> multistep_candidates_;
- // All |multistep_candidates_| share the same origin. Has a value iff
- // |multistep_candidates_| is not empty.
- absl::optional<url::Origin> multistep_candidates_origin_;
+ // Enables importing from multi-step import flows.
+ MultiStepImportMerger multistep_importer_;
friend class AutofillMergeTest;
friend class FormDataImporterTest;
@@ -360,6 +311,9 @@ class FormDataImporter : public PersonalDataManagerObserver {
FRIEND_TEST_ALL_PREFIXES(AutofillMergeTest, MergeProfiles);
FRIEND_TEST_ALL_PREFIXES(FormDataImporterNonParameterizedTest,
ProcessCreditCardImportCandidate_EmptyCreditCard);
+ FRIEND_TEST_ALL_PREFIXES(
+ FormDataImporterNonParameterizedTest,
+ ProcessCreditCardImportCandidate_VirtualCardEligible);
FRIEND_TEST_ALL_PREFIXES(FormDataImporterNonParameterizedTest,
ShouldOfferUploadCardOrLocalCardSave);
FRIEND_TEST_ALL_PREFIXES(FormDataImporterTest,
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 feeaed88ff5..1f3bceaa28a 100644
--- a/chromium/components/autofill/core/browser/form_data_importer_unittest.cc
+++ b/chromium/components/autofill/core/browser/form_data_importer_unittest.cc
@@ -15,7 +15,6 @@
#include <vector>
#include "base/callback_helpers.h"
-#include "base/command_line.h"
#include "base/feature_list.h"
#include "base/guid.h"
#include "base/memory/raw_ptr.h"
@@ -34,6 +33,7 @@
#include "components/autofill/core/browser/field_types.h"
#include "components/autofill/core/browser/form_structure.h"
#include "components/autofill/core/browser/metrics/autofill_metrics.h"
+#include "components/autofill/core/browser/payments/test_virtual_card_enrollment_manager.h"
#include "components/autofill/core/browser/personal_data_manager.h"
#include "components/autofill/core/browser/personal_data_manager_observer.h"
#include "components/autofill/core/browser/test_autofill_client.h"
@@ -44,12 +44,11 @@
#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"
#include "components/autofill/core/common/form_data.h"
#include "components/autofill/core/common/form_field_data.h"
-#include "components/os_crypt/os_crypt_mocker.h"
#include "components/prefs/pref_service.h"
+#include "components/signin/public/identity_manager/identity_test_environment.h"
#include "components/sync/driver/test_sync_service.h"
#include "components/webdata/common/web_data_service_base.h"
#include "components/webdata/common/web_database_service.h"
@@ -57,6 +56,7 @@
#include "testing/gtest/include/gtest/gtest.h"
using base::UTF8ToUTF16;
+using testing::_;
namespace autofill {
namespace {
@@ -72,6 +72,7 @@ constexpr char kDefaultZip[] = "94102";
constexpr char kDefaultCity[] = "Los Angeles";
constexpr char kDefaultDependentLocality[] = "Nob Hill";
constexpr char kDefaultState[] = "California";
+constexpr char kDefaultCountry[] = "US";
constexpr char kDefaultPhone[] = "+1 650-555-0000";
constexpr char kDefaultPhoneAlternativeFormatting[] = "650-555-0000";
constexpr char kDefaultPhoneDomesticFormatting[] = "(650) 555-0000";
@@ -104,7 +105,10 @@ constexpr char kThirdDependentLocality[] = "Down Town";
constexpr char kThirdState[] = "Oregon";
constexpr char kThirdPhone[] = "+1 851-777-2222";
+constexpr char kDefaultCreditCardName[] = "Biggie Smalls";
constexpr char kDefaultCreditCardNumber[] = "4111 1111 1111 1111";
+constexpr char kDefaultCreditCardExpMonth[] = "01";
+constexpr char kDefaultCreditCardExpYear[] = "2999";
// For a given ServerFieldType |type| returns a pair of field name and label
// that should be parsed into this type by our field type parsers.
@@ -125,7 +129,10 @@ std::pair<std::string, std::string> GetLabelAndNameForType(
{ADDRESS_HOME_DEPENDENT_LOCALITY, {"Neighborhood:", "neighborhood"}},
{ADDRESS_HOME_COUNTRY, {"Country:", "country"}},
{PHONE_HOME_WHOLE_NUMBER, {"Phone:", "phone"}},
+ {CREDIT_CARD_NAME_FULL, {"Name on card:", "name_on_card"}},
{CREDIT_CARD_NUMBER, {"Credit Card Number:", "card_number"}},
+ {CREDIT_CARD_EXP_MONTH, {"Exp Month:", "exp_month"}},
+ {CREDIT_CARD_EXP_4_DIGIT_YEAR, {"Exp Year:", "exp_year"}},
};
auto it = name_type_map.find(type);
if (it == name_type_map.end()) {
@@ -213,9 +220,25 @@ GetDefaultProfileTypeValuePairs() {
{ADDRESS_HOME_CITY, kDefaultCity},
{ADDRESS_HOME_STATE, kDefaultState},
{ADDRESS_HOME_ZIP, kDefaultZip},
+ {ADDRESS_HOME_COUNTRY, kDefaultCountry},
};
}
+// Wraps `GetDefaultProfileTypeValuePairs()` but replaces `kDefaultCountry` with
+// `country`. If `country` is empty, ADDRESS_HOME_COUNTRY is removed entirely.
+std::vector<std::pair<ServerFieldType, std::string>>
+GetDefaultProfileTypeValuePairsWithOverriddenCountry(
+ const std::string& country) {
+ constexpr int kCountryIndex = 9;
+ auto pairs = GetDefaultProfileTypeValuePairs();
+ DCHECK_EQ(pairs[kCountryIndex].first, ADDRESS_HOME_COUNTRY);
+ if (country.empty())
+ pairs.erase(pairs.begin() + kCountryIndex);
+ else
+ pairs[kCountryIndex].second = country;
+ return pairs;
+}
+
// Same as |GetDefaultProfileTypeValuePairs()|, but split into two parts to test
// multi-step imports. No part by itself satisfies the import requirements.
// |part| specifies the requested half and can be either 1 or 2.
@@ -224,9 +247,12 @@ GetSplitDefaultProfileTypeValuePairs(int part) {
DCHECK(part == 1 || part == 2);
if (part == 1) {
return {
- {NAME_FIRST, kDefaultFirstName}, {NAME_LAST, kDefaultLastName},
- {EMAIL_ADDRESS, kDefaultMail}, {ADDRESS_HOME_CITY, kDefaultCity},
+ {NAME_FIRST, kDefaultFirstName},
+ {NAME_LAST, kDefaultLastName},
+ {EMAIL_ADDRESS, kDefaultMail},
+ {ADDRESS_HOME_CITY, kDefaultCity},
{ADDRESS_HOME_STATE, kDefaultState},
+ {ADDRESS_HOME_COUNTRY, kDefaultCountry},
};
} else {
return {
@@ -238,15 +264,6 @@ GetSplitDefaultProfileTypeValuePairs(int part) {
}
}
-// Same as |GetDefaultProfileTypeValuePairs()| but with ADDRESS_HOME_COUNTRY
-// set to |country|.
-std::vector<std::pair<ServerFieldType, std::string>>
-GetDefaultProfileTypeValuePairsWithCountry(const std::string& country) {
- auto profile_typed_value_pairs = GetDefaultProfileTypeValuePairs();
- profile_typed_value_pairs.emplace_back(ADDRESS_HOME_COUNTRY, country);
- return profile_typed_value_pairs;
-}
-
// Same as |GetDefaultProfileTypeValuePairs()| but with the second profile
// information.
std::vector<std::pair<ServerFieldType, std::string>>
@@ -261,6 +278,7 @@ GetSecondProfileTypeValuePairs() {
{ADDRESS_HOME_CITY, kSecondCity},
{ADDRESS_HOME_STATE, kSecondState},
{ADDRESS_HOME_ZIP, kSecondZip},
+ {ADDRESS_HOME_COUNTRY, kDefaultCountry},
};
}
@@ -278,6 +296,18 @@ GetThirdProfileTypeValuePairs() {
{ADDRESS_HOME_CITY, kThirdCity},
{ADDRESS_HOME_STATE, kThirdState},
{ADDRESS_HOME_ZIP, kThirdZip},
+ {ADDRESS_HOME_COUNTRY, kDefaultCountry},
+ };
+}
+
+// Same as `GetDefaultProfileTypeValuePairs()`, but for credit cards.
+std::vector<std::pair<ServerFieldType, std::string>>
+GetDefaultCreditCardTypeValuePairs() {
+ return {
+ {CREDIT_CARD_NAME_FULL, kDefaultCreditCardName},
+ {CREDIT_CARD_NUMBER, kDefaultCreditCardNumber},
+ {CREDIT_CARD_EXP_MONTH, kDefaultCreditCardExpMonth},
+ {CREDIT_CARD_EXP_4_DIGIT_YEAR, kDefaultCreditCardExpYear},
};
}
@@ -286,10 +316,12 @@ AutofillProfile ConstructDefaultProfile() {
return ConstructProfileFromTypeValuePairs(GetDefaultProfileTypeValuePairs());
}
-// Same as |ConstructDefaultProfile()| but with |country|.
-AutofillProfile ConstructDefaultProfileWithCountry(const std::string& country) {
+// Wraps `ConstructDefaultProfile()`, but overrides ADDRESS_HOME_COUNTRY with
+// `country`.
+AutofillProfile ConstructDefaultProfileWithOverriddenCountry(
+ const std::string& country) {
return ConstructProfileFromTypeValuePairs(
- GetDefaultProfileTypeValuePairsWithCountry(country));
+ GetDefaultProfileTypeValuePairsWithOverriddenCountry(country));
}
// Returns the second AutofillProfile used in this test file.
@@ -318,13 +350,6 @@ std::unique_ptr<FormStructure> ConstructSplitDefaultProfileFormStructure(
GetSplitDefaultProfileTypeValuePairs(part));
}
-// Same as |ConstructDefaultFormStructure()| but with |country|.
-std::unique_ptr<FormStructure> ConstructDefaultProfileFormStructureWithCountry(
- const std::string& country) {
- return ConstructFormStructureFromTypeValuePairs(
- GetDefaultProfileTypeValuePairsWithCountry(country));
-}
-
// Same as |ConstructDefaultFormStructure()| but for the second profile.
std::unique_ptr<FormStructure> ConstructSecondProfileFormStructure() {
return ConstructFormStructureFromTypeValuePairs(
@@ -337,6 +362,12 @@ std::unique_ptr<FormStructure> ConstructThirdProfileFormStructure() {
GetThirdProfileTypeValuePairs());
}
+// Same as `ConstructDefaultFormStructure()` but for credit cards.
+std::unique_ptr<FormStructure> ConstructDefaultCreditCardFormStructure() {
+ return ConstructFormStructureFromTypeValuePairs(
+ GetDefaultCreditCardTypeValuePairs());
+}
+
// Constructs a |FormData| instance that carries the information of the default
// profile.
FormData ConstructDefaultFormData() {
@@ -394,6 +425,32 @@ auto UnorderedElementsCompareEqual(Matchers... matchers) {
} // anonymous namespace
+class MockVirtualCardEnrollmentManager
+ : public TestVirtualCardEnrollmentManager {
+ public:
+ MockVirtualCardEnrollmentManager(
+ TestPersonalDataManager* personal_data_manager,
+ payments::TestPaymentsClient* payments_client,
+ TestAutofillClient* autofill_client)
+ : TestVirtualCardEnrollmentManager(personal_data_manager,
+ payments_client,
+ autofill_client){};
+ MOCK_METHOD(
+ void,
+ InitVirtualCardEnroll,
+ (const CreditCard& credit_card,
+ VirtualCardEnrollmentSource virtual_card_enrollment_source,
+ absl::optional<
+ payments::PaymentsClient::GetDetailsForEnrollmentResponseDetails>
+ get_details_for_enrollment_response_details,
+ const raw_ptr<PrefService> user_prefs,
+ VirtualCardEnrollmentManager::RiskAssessmentFunction
+ risk_assessment_function,
+ VirtualCardEnrollmentManager::VirtualCardEnrollmentFieldsLoadedCallback
+ virtual_card_enrollment_fields_loaded_callback),
+ (override));
+};
+
class FormDataImporterTestBase {
protected:
FormDataImporterTestBase() : autofill_table_(nullptr) {}
@@ -404,6 +461,9 @@ class FormDataImporterTestBase {
// reference to `personal_data_manager_` that otherwise points to garbage.
form_data_importer_.reset();
+ if (personal_data_manager_) {
+ personal_data_manager_->Shutdown();
+ }
personal_data_manager_ = std::make_unique<PersonalDataManager>("en", "US");
personal_data_manager_->set_auto_accept_address_imports_for_testing(true);
personal_data_manager_->Init(
@@ -411,7 +471,7 @@ class FormDataImporterTestBase {
/*account_database=*/nullptr,
/*pref_service=*/prefs_.get(),
/*local_state=*/prefs_.get(),
- /*identity_manager=*/nullptr,
+ /*identity_manager=*/identity_test_env_.identity_manager(),
/*history_service=*/nullptr,
/*strike_database=*/nullptr,
/*image_fetcher=*/nullptr,
@@ -427,6 +487,12 @@ class FormDataImporterTestBase {
std::make_unique<FormDataImporter>(autofill_client_.get(),
/*payments::PaymentsClient=*/nullptr,
personal_data_manager_.get(), "en");
+ auto virtual_card_enrollment_manager =
+ std::make_unique<MockVirtualCardEnrollmentManager>(
+ nullptr, nullptr, autofill_client_.get());
+ virtual_card_enrollment_manager_ = virtual_card_enrollment_manager.get();
+ form_data_importer_->virtual_card_enrollment_manager_ =
+ std::move(virtual_card_enrollment_manager);
}
void SetUpHelper() {
@@ -456,6 +522,12 @@ class FormDataImporterTestBase {
prefs::kAutofillLastVersionDeduped, 0);
}
+ void TearDownHelper() {
+ if (personal_data_manager_) {
+ personal_data_manager_->Shutdown();
+ }
+ }
+
// Helper method that will add credit card fields in |form|, according to the
// specified values. If a value is nullptr, the corresponding field won't get
// added (empty string will add a field with an empty string as the value).
@@ -621,6 +693,7 @@ class FormDataImporterTestBase {
base::test::SingleThreadTaskEnvironment task_environment_{
base::test::SingleThreadTaskEnvironment::MainThreadType::UI};
std::unique_ptr<PrefService> prefs_;
+ signin::IdentityTestEnvironment identity_test_env_;
scoped_refptr<AutofillWebDataService> autofill_database_service_;
scoped_refptr<WebDatabaseService> web_database_;
raw_ptr<AutofillTable> autofill_table_; // weak ref
@@ -628,6 +701,7 @@ class FormDataImporterTestBase {
std::unique_ptr<TestAutofillClient> autofill_client_;
std::unique_ptr<PersonalDataManager> personal_data_manager_;
std::unique_ptr<FormDataImporter> form_data_importer_;
+ MockVirtualCardEnrollmentManager* virtual_card_enrollment_manager_;
base::test::ScopedFeatureList scoped_feature_list_;
};
@@ -653,6 +727,8 @@ class FormDataImporterTest
SetUpHelper();
}
+ void TearDown() override { TearDownHelper(); }
+
void InitializeFeatures() {
support_for_apartment_numbers_ = std::get<0>(GetParam());
support_for_depending_locality_ = std::get<1>(GetParam());
@@ -685,56 +761,38 @@ class FormDataImporterTest
bool consider_variation_country_code_for_phone_numbers_;
};
-TEST_P(FormDataImporterTest, GetPredictedCountryCode) {
- const AutofillProfile us_profile =
- ConstructProfileFromTypeValuePairs({{ADDRESS_HOME_COUNTRY, "US"}});
- const AutofillProfile empty_profile;
- // Test prioritization: profile > variation service state > app locale
- EXPECT_EQ(FormDataImporter::GetPredictedCountryCode(us_profile, "DE", "de-AT",
- nullptr),
- "US");
- EXPECT_EQ(FormDataImporter::GetPredictedCountryCode(us_profile, "", "de-AT",
- nullptr),
- "US");
- EXPECT_EQ(FormDataImporter::GetPredictedCountryCode(empty_profile, "DE",
- "de-AT", nullptr),
- "DE");
- EXPECT_EQ(FormDataImporter::GetPredictedCountryCode(empty_profile, "",
- "de-AT", nullptr),
- "AT");
-}
-
TEST_P(FormDataImporterTest, ComplementCountry) {
base::test::ScopedFeatureList complement_country_feature;
complement_country_feature.InitAndEnableFeature(
features::kAutofillComplementCountryCodeOnImport);
- auto import_with_country =
+ auto ImportWithCountry =
[this](const std::string& form_country,
const std::vector<AutofillProfile>& expected_profiles) {
// Remove existing profiles, to prevent an update instead of an import.
personal_data_manager_->ClearAllLocalData();
std::unique_ptr<FormStructure> form_structure =
- form_country.empty()
- ? ConstructDefaultProfileFormStructure()
- : ConstructDefaultProfileFormStructureWithCountry(form_country);
+ ConstructFormStructureFromTypeValuePairs(
+ GetDefaultProfileTypeValuePairsWithOverriddenCountry(
+ form_country));
ImportAddressProfilesAndVerifyExpectation(*form_structure,
expected_profiles);
};
// Country part of the form:
// If a valid country was entered, use that.
- import_with_country("Germany", {ConstructDefaultProfileWithCountry("DE")});
+ ImportWithCountry("Germany",
+ {ConstructDefaultProfileWithOverriddenCountry("DE")});
// Reject the profile if an invalid country was entered.
- import_with_country("Somewhere", {});
+ ImportWithCountry("Somewhere", {});
// Country not part of the form: Complement using
// FormDataImporter::GetPredictedCountryCode
// If no variation config country code is available, default to locale (US)
- import_with_country("", {ConstructDefaultProfileWithCountry("US")});
+ ImportWithCountry("", {ConstructDefaultProfileWithOverriddenCountry("US")});
// Prefer variation config country code over locale
autofill_client_->SetVariationConfigCountryCode("DE");
- import_with_country("", {ConstructDefaultProfileWithCountry("DE")});
+ ImportWithCountry("", {ConstructDefaultProfileWithOverriddenCountry("DE")});
}
TEST_P(FormDataImporterTest, InvalidPhoneNumber) {
@@ -784,9 +842,12 @@ TEST_P(FormDataImporterTest, PhoneNumberRegionMetrics) {
// Remove existing profiles, to prevent an update instead of an import.
personal_data_manager_->ClearAllLocalData();
+ // In order to test the phone number region deduction via the variation
+ // country code and app local, the form cannot contain a country field.
+ // Passing an empty country archives that.
std::vector<std::pair<ServerFieldType, std::string>>
profile_with_invalid_phone_number =
- GetDefaultProfileTypeValuePairs();
+ GetDefaultProfileTypeValuePairsWithOverriddenCountry("");
ASSERT_EQ(profile_with_invalid_phone_number[3].first,
PHONE_HOME_WHOLE_NUMBER);
profile_with_invalid_phone_number[3].second = number;
@@ -1134,7 +1195,8 @@ TEST_P(FormDataImporterTest, ImportAddressProfileFromUnifiedSection) {
ConstructDefaultProfileFormStructure();
// Assign the address field another section than the other fields.
- form_structure->field(4)->section = "another_section";
+ form_structure->field(4)->section.SetPrefixFromAutocomplete(
+ {.section = "another_section", .mode = HtmlFieldMode::HTML_MODE_NONE});
ImportAddressProfileAndVerifyImportOfDefaultProfile(*form_structure);
}
@@ -1225,7 +1287,9 @@ TEST_P(FormDataImporterTest,
{{NAME_FIRST, kDefaultFirstName},
{NAME_LAST, kDefaultLastName},
{EMAIL_ADDRESS, kDefaultMail},
- // Add six phone number fields.
+ // Add two phone number fields, split across 3 fields each.
+ // They are all declared as PHONE_HOME_WHOLE_NUMBER, which only affects
+ // the label. Local heuristics will classify them correctly.
{PHONE_HOME_WHOLE_NUMBER, kDefaultPhoneAreaCode},
{PHONE_HOME_WHOLE_NUMBER, kDefaultPhonePrefix},
{PHONE_HOME_WHOLE_NUMBER, kDefaultPhoneSuffix},
@@ -1236,7 +1300,8 @@ TEST_P(FormDataImporterTest,
{ADDRESS_HOME_DEPENDENT_LOCALITY, kDefaultDependentLocality},
{ADDRESS_HOME_CITY, kDefaultCity},
{ADDRESS_HOME_STATE, kDefaultState},
- {ADDRESS_HOME_ZIP, kDefaultZip}});
+ {ADDRESS_HOME_ZIP, kDefaultZip},
+ {ADDRESS_HOME_COUNTRY, kDefaultCountry}});
form_data.fields[3].max_length = 3;
form_data.fields[4].max_length = 3;
@@ -1260,7 +1325,8 @@ TEST_P(FormDataImporterTest,
{ADDRESS_HOME_LINE1, kDefaultAddressLine1},
{ADDRESS_HOME_CITY, kDefaultCity},
{ADDRESS_HOME_STATE, kDefaultState},
- {ADDRESS_HOME_ZIP, kDefaultZip}})});
+ {ADDRESS_HOME_ZIP, kDefaultZip},
+ {ADDRESS_HOME_COUNTRY, kDefaultCountry}})});
}
// Tests that not enough filled fields will result in not importing an address.
@@ -1340,7 +1406,8 @@ TEST_P(FormDataImporterTest,
{ADDRESS_HOME_DEPENDENT_LOCALITY, kDefaultDependentLocality},
{ADDRESS_HOME_CITY, kDefaultCity},
{ADDRESS_HOME_STATE, kDefaultState},
- {ADDRESS_HOME_ZIP, kDefaultZip}});
+ {ADDRESS_HOME_ZIP, kDefaultZip},
+ {ADDRESS_HOME_COUNTRY, kDefaultCountry}});
// Define the length of the phone number fields to allow the parser to
// identify them as area code, prefix and suffix.
@@ -1361,7 +1428,8 @@ TEST_P(FormDataImporterTest,
{ADDRESS_HOME_DEPENDENT_LOCALITY, kDefaultDependentLocality},
{ADDRESS_HOME_CITY, kDefaultCity},
{ADDRESS_HOME_STATE, kDefaultState},
- {ADDRESS_HOME_ZIP, kDefaultZip}})});
+ {ADDRESS_HOME_ZIP, kDefaultZip},
+ {ADDRESS_HOME_COUNTRY, kDefaultCountry}})});
}
TEST_P(FormDataImporterTest, ImportAddressProfiles_UnFocussableFields) {
@@ -1505,6 +1573,7 @@ TEST_P(FormDataImporterTest, ImportAddressProfiles_SameProfileWithConflict) {
{ADDRESS_HOME_CITY, kDefaultCity},
{ADDRESS_HOME_STATE, kDefaultState},
{ADDRESS_HOME_ZIP, kDefaultZip},
+ {ADDRESS_HOME_COUNTRY, kDefaultCountry},
{PHONE_HOME_WHOLE_NUMBER, kDefaultPhoneDomesticFormatting},
};
AutofillProfile initial_profile =
@@ -1563,6 +1632,7 @@ TEST_P(FormDataImporterTest, ImportAddressProfiles_MissingInfoInOld) {
{ADDRESS_HOME_CITY, kDefaultCity},
{ADDRESS_HOME_STATE, kDefaultState},
{ADDRESS_HOME_ZIP, kDefaultZip},
+ {ADDRESS_HOME_COUNTRY, kDefaultCountry},
{PHONE_HOME_WHOLE_NUMBER, kDefaultPhone},
};
AutofillProfile initial_profile =
@@ -1600,6 +1670,7 @@ TEST_P(FormDataImporterTest, ImportAddressProfiles_MissingInfoInNew) {
{ADDRESS_HOME_CITY, kDefaultCity},
{ADDRESS_HOME_STATE, kDefaultState},
{ADDRESS_HOME_ZIP, kDefaultZip},
+ {ADDRESS_HOME_COUNTRY, kDefaultCountry},
{PHONE_HOME_WHOLE_NUMBER, kDefaultPhone},
});
// Create a superset that includes a new email address.
@@ -2082,18 +2153,11 @@ TEST_P(FormDataImporterTest,
// Tests that a valid credit card is extracted.
TEST_P(FormDataImporterTest, ImportCreditCard_Valid) {
- // Add a single valid credit card form.
- FormData form;
- form.url = GURL("https://wwww.foo.com");
-
- AddFullCreditCardForm(&form, "Biggie Smalls", "4111-1111-1111-1111", "01",
- "2999");
-
- FormStructure form_structure(form);
- form_structure.DetermineHeuristicTypes(nullptr, nullptr);
+ std::unique_ptr<FormStructure> form_structure =
+ ConstructDefaultCreditCardFormStructure();
std::unique_ptr<CreditCard> imported_credit_card;
base::HistogramTester histogram_tester;
- EXPECT_TRUE(ImportCreditCard(form_structure, false, &imported_credit_card));
+ EXPECT_TRUE(ImportCreditCard(*form_structure, false, &imported_credit_card));
ASSERT_TRUE(imported_credit_card);
histogram_tester.ExpectUniqueSample(
"Autofill.SubmittedCardState",
@@ -2213,16 +2277,10 @@ TEST_P(FormDataImporterTest, ImportCreditCard_MonthSelectInvalidText) {
TEST_P(FormDataImporterTest, ImportCreditCard_TwoValidCards) {
// Start with a single valid credit card form.
- FormData form1;
- form1.url = GURL("https://wwww.foo.com");
-
- AddFullCreditCardForm(&form1, "Biggie Smalls", "4111-1111-1111-1111", "01",
- "2999");
-
- FormStructure form_structure1(form1);
- form_structure1.DetermineHeuristicTypes(nullptr, nullptr);
+ std::unique_ptr<FormStructure> form_structure1 =
+ ConstructDefaultCreditCardFormStructure();
std::unique_ptr<CreditCard> imported_credit_card;
- EXPECT_TRUE(ImportCreditCard(form_structure1, false, &imported_credit_card));
+ EXPECT_TRUE(ImportCreditCard(*form_structure1, false, &imported_credit_card));
ASSERT_TRUE(imported_credit_card);
personal_data_manager_->OnAcceptedLocalCreditCardSave(*imported_credit_card);
@@ -3165,6 +3223,8 @@ TEST_P(FormDataImporterTest, ImportFormData_OneAddressOneCreditCard) {
form.fields.push_back(field);
test::CreateTestFormField("Zip:", "zip", "94102", "text", &field);
form.fields.push_back(field);
+ test::CreateTestFormField("Country:", "country", "US", "text", &field);
+ form.fields.push_back(field);
// Credit card section.
AddFullCreditCardForm(&form, "Biggie Smalls", "4111-1111-1111-1111", "01",
@@ -3189,7 +3249,7 @@ TEST_P(FormDataImporterTest, ImportFormData_OneAddressOneCreditCard) {
AutofillProfile expected_address(base::GenerateGUID(), test::kEmptyOrigin);
test::SetProfileInfo(&expected_address, "George", nullptr, "Washington",
"theprez@gmail.com", nullptr, "21 Laussat St", nullptr,
- "San Francisco", "California", "94102", "", nullptr);
+ "San Francisco", "California", "94102", "US", nullptr);
const std::vector<AutofillProfile*>& results_addr =
personal_data_manager_->GetProfiles();
ASSERT_EQ(1U, results_addr.size());
@@ -3427,6 +3487,8 @@ TEST_P(FormDataImporterTest, ImportFormData_OneAddressCreditCardDisabled) {
form.fields.push_back(field);
test::CreateTestFormField("Zip:", "zip", "94102", "text", &field);
form.fields.push_back(field);
+ test::CreateTestFormField("Country:", "country", "US", "text", &field);
+ form.fields.push_back(field);
// Credit card section.
AddFullCreditCardForm(&form, "Biggie Smalls", "4111-1111-1111-1111", "01",
@@ -3450,7 +3512,7 @@ TEST_P(FormDataImporterTest, ImportFormData_OneAddressCreditCardDisabled) {
AutofillProfile expected_address(base::GenerateGUID(), test::kEmptyOrigin);
test::SetProfileInfo(&expected_address, "George", nullptr, "Washington",
"theprez@gmail.com", nullptr, "21 Laussat St", nullptr,
- "San Francisco", "California", "94102", "", nullptr);
+ "San Francisco", "California", "94102", "US", nullptr);
const std::vector<AutofillProfile*>& results_addr =
personal_data_manager_->GetProfiles();
ASSERT_EQ(1U, results_addr.size());
@@ -3618,19 +3680,12 @@ TEST_P(FormDataImporterTest, ImportFormData_HiddenCreditCardFormAfterEntered) {
// UPI ID.
TEST_P(FormDataImporterTest,
ImportFormData_DontSetUpiIdWhenOnlyCreditCardExists) {
- // Simulate a form submission with a new credit card.
- FormData form;
- form.url = GURL("https://wwww.foo.com");
-
- AddFullCreditCardForm(&form, "Biggie Smalls", "4111 1111 1111 1111", "01",
- "2999");
-
- FormStructure form_structure(form);
- form_structure.DetermineHeuristicTypes(nullptr, nullptr);
+ std::unique_ptr<FormStructure> form_structure =
+ ConstructDefaultCreditCardFormStructure();
std::unique_ptr<CreditCard> imported_credit_card;
absl::optional<std::string> imported_upi_id;
EXPECT_TRUE(ImportFormDataAndProcessAddressCandidates(
- form_structure, /*profile_autofill_enabled=*/true,
+ *form_structure, /*profile_autofill_enabled=*/true,
/*credit_card_autofill_enabled=*/true,
/*should_return_local_card=*/true, &imported_credit_card,
&imported_upi_id));
@@ -4448,13 +4503,14 @@ class FormDataImporterNonParameterizedTest : public FormDataImporterTestBase,
public testing::Test {
private:
void SetUp() override { SetUpHelper(); }
+ void TearDown() override { TearDownHelper(); }
};
TEST_F(FormDataImporterNonParameterizedTest,
ProcessCreditCardImportCandidate_EmptyCreditCard) {
std::unique_ptr<CreditCard> imported_credit_card;
- FormData form;
- AddFullCreditCardForm(&form, "Clyde Barrow", "378282246310005", "04", "2999");
+ std::unique_ptr<FormStructure> form_structure =
+ ConstructDefaultCreditCardFormStructure();
// |form_data_importer_|'s |imported_credit_card_record_type_| is set to
// LOCAL_CARD because we need to make sure we do not return early in the
@@ -4469,13 +4525,59 @@ TEST_F(FormDataImporterNonParameterizedTest,
personal_data_manager_->OnSyncServiceInitialized(&sync_service);
EXPECT_FALSE(form_data_importer_->ProcessCreditCardImportCandidate(
- FormStructure(form), std::move(imported_credit_card),
+ *form_structure, std::move(imported_credit_card),
/*detected_upi_id=*/"",
/*credit_card_autofill_enabled=*/true,
/*is_credit_card_upstream_enabled=*/true));
personal_data_manager_->OnSyncServiceInitialized(nullptr);
}
+#if !BUILDFLAG(IS_IOS)
+TEST_F(FormDataImporterNonParameterizedTest,
+ ProcessCreditCardImportCandidate_VirtualCardEligible) {
+ CreditCard imported_credit_card = test::GetMaskedServerCard();
+ imported_credit_card.SetNetworkForMaskedCard(kAmericanExpressCard);
+ imported_credit_card.set_instrument_id(1111);
+ imported_credit_card.set_virtual_card_enrollment_state(
+ CreditCard::VirtualCardEnrollmentState::UNENROLLED_AND_ELIGIBLE);
+ std::unique_ptr<FormStructure> form_structure =
+ ConstructDefaultCreditCardFormStructure();
+
+ form_data_importer_->imported_credit_card_record_type_ =
+ FormDataImporter::ImportedCreditCardRecordType::SERVER_CARD;
+ form_data_importer_->SetFetchedCardInstrumentId(2222);
+
+ // We need a sync service so that
+ // LocalCardMigrationManager::ShouldOfferLocalCardMigration() does not
+ // crash.
+ syncer::TestSyncService sync_service;
+ personal_data_manager_->OnSyncServiceInitialized(&sync_service);
+
+ EXPECT_CALL(*virtual_card_enrollment_manager_,
+ InitVirtualCardEnroll(_, VirtualCardEnrollmentSource::kDownstream,
+ _, _, _, _))
+ .Times(0);
+ EXPECT_FALSE(form_data_importer_->ProcessCreditCardImportCandidate(
+ *form_structure, std::make_unique<CreditCard>(imported_credit_card),
+ /*detected_upi_id=*/"",
+ /*credit_card_autofill_enabled=*/true,
+ /*is_credit_card_upstream_enabled=*/true));
+
+ form_data_importer_->SetFetchedCardInstrumentId(1111);
+ EXPECT_CALL(*virtual_card_enrollment_manager_,
+ InitVirtualCardEnroll(_, VirtualCardEnrollmentSource::kDownstream,
+ _, _, _, _))
+ .Times(1);
+ EXPECT_TRUE(form_data_importer_->ProcessCreditCardImportCandidate(
+ *form_structure, std::make_unique<CreditCard>(imported_credit_card),
+ /*detected_upi_id=*/"",
+ /*credit_card_autofill_enabled=*/true,
+ /*is_credit_card_upstream_enabled=*/true));
+
+ personal_data_manager_->OnSyncServiceInitialized(nullptr);
+}
+#endif
+
TEST_F(FormDataImporterNonParameterizedTest,
ShouldOfferUploadCardOrLocalCardSave) {
// Should not offer save for null cards.
diff --git a/chromium/components/autofill/core/browser/form_data_importer_utils.cc b/chromium/components/autofill/core/browser/form_data_importer_utils.cc
new file mode 100644
index 00000000000..978b2d8be02
--- /dev/null
+++ b/chromium/components/autofill/core/browser/form_data_importer_utils.cc
@@ -0,0 +1,244 @@
+// Copyright 2022 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/form_data_importer_utils.h"
+
+#include "base/strings/utf_string_conversions.h"
+#include "components/autofill/core/browser/data_model/autofill_profile_comparator.h"
+#include "components/autofill/core/browser/geo/autofill_country.h"
+#include "components/autofill/core/browser/logging/log_manager.h"
+#include "components/autofill/core/browser/metrics/autofill_metrics.h"
+#include "components/autofill/core/common/autofill_features.h"
+#include "components/autofill/core/common/autofill_internals/log_message.h"
+
+namespace autofill {
+
+namespace {
+
+using AddressImportRequirement =
+ AutofillMetrics::AddressProfileImportRequirementMetric;
+
+} // anonymous namespace
+
+bool IsMinimumAddress(const AutofillProfile& profile,
+ const std::string& predicted_country_code,
+ const std::string& app_locale,
+ LogBuffer* import_log_buffer,
+ bool collect_metrics) {
+ AutofillCountry country(predicted_country_code, app_locale);
+
+ // Include the details of the country to the log.
+ LOG_AF(import_log_buffer) << country;
+
+ // Check the |ADDRESS_HOME_LINE1| requirement.
+ bool is_line1_missing = false;
+ if (country.requires_line1() && !profile.HasRawInfo(ADDRESS_HOME_LINE1) &&
+ !profile.HasRawInfo(ADDRESS_HOME_STREET_NAME)) {
+ LOG_AF(import_log_buffer)
+ << LogMessage::kImportAddressProfileFromFormFailed
+ << "Missing required ADDRESS_HOME_LINE1." << CTag{};
+ is_line1_missing = true;
+ }
+
+ // Check the |ADDRESS_HOME_CITY| requirement.
+ bool is_city_missing = false;
+ if (country.requires_city() && !profile.HasRawInfo(ADDRESS_HOME_CITY)) {
+ LOG_AF(import_log_buffer)
+ << LogMessage::kImportAddressProfileFromFormFailed
+ << "Missing required ADDRESS_HOME_CITY." << CTag{};
+ is_city_missing = true;
+ }
+
+ // Check the |ADDRESS_HOME_STATE| requirement.
+ bool is_state_missing = false;
+ if (country.requires_state() && !profile.HasRawInfo(ADDRESS_HOME_STATE)) {
+ LOG_AF(import_log_buffer)
+ << LogMessage::kImportAddressProfileFromFormFailed
+ << "Missing required ADDRESS_HOME_STATE." << CTag{};
+ is_state_missing = true;
+ }
+
+ // Check the |ADDRESS_HOME_ZIP| requirement.
+ bool is_zip_missing = false;
+ if (country.requires_zip() && !profile.HasRawInfo(ADDRESS_HOME_ZIP)) {
+ LOG_AF(import_log_buffer) << LogMessage::kImportAddressProfileFromFormFailed
+ << "Missing required ADDRESS_HOME_ZIP." << CTag{};
+ is_zip_missing = true;
+ }
+
+ bool is_zip_or_state_requirement_violated = false;
+ if (country.requires_zip_or_state() &&
+ !profile.HasRawInfo(ADDRESS_HOME_ZIP) &&
+ !profile.HasRawInfo(ADDRESS_HOME_STATE)) {
+ LOG_AF(import_log_buffer)
+ << LogMessage::kImportAddressProfileFromFormFailed
+ << "Missing required ADDRESS_HOME_ZIP or ADDRESS_HOME_STATE." << CTag{};
+ is_zip_or_state_requirement_violated = true;
+ }
+
+ bool is_line1_or_house_number_violated = false;
+ if (country.requires_line1_or_house_number() &&
+ !profile.HasRawInfo(ADDRESS_HOME_LINE1) &&
+ !profile.HasRawInfo(ADDRESS_HOME_HOUSE_NUMBER)) {
+ LOG_AF(import_log_buffer)
+ << LogMessage::kImportAddressProfileFromFormFailed
+ << "Missing required ADDRESS_HOME_LINE1 or ADDRESS_HOME_HOUSE_NUMBER."
+ << CTag{};
+ is_line1_or_house_number_violated = true;
+ }
+
+ // Collect metrics regarding the requirements.
+ if (collect_metrics) {
+ AutofillMetrics::LogAddressFormImportRequirementMetric(
+ is_line1_missing
+ ? AddressImportRequirement::LINE1_REQUIREMENT_VIOLATED
+ : AddressImportRequirement::LINE1_REQUIREMENT_FULFILLED);
+
+ AutofillMetrics::LogAddressFormImportRequirementMetric(
+ is_city_missing ? AddressImportRequirement::CITY_REQUIREMENT_VIOLATED
+ : AddressImportRequirement::CITY_REQUIREMENT_FULFILLED);
+
+ AutofillMetrics::LogAddressFormImportRequirementMetric(
+ is_state_missing
+ ? AddressImportRequirement::STATE_REQUIREMENT_VIOLATED
+ : AddressImportRequirement::STATE_REQUIREMENT_FULFILLED);
+
+ AutofillMetrics::LogAddressFormImportRequirementMetric(
+ is_zip_missing ? AddressImportRequirement::ZIP_REQUIREMENT_VIOLATED
+ : AddressImportRequirement::ZIP_REQUIREMENT_FULFILLED);
+
+ AutofillMetrics::LogAddressFormImportRequirementMetric(
+ is_zip_or_state_requirement_violated
+ ? AddressImportRequirement::ZIP_OR_STATE_REQUIREMENT_VIOLATED
+ : AddressImportRequirement::ZIP_OR_STATE_REQUIREMENT_FULFILLED);
+
+ AutofillMetrics::LogAddressFormImportCountrySpecificFieldRequirementsMetric(
+ is_zip_missing, is_state_missing, is_city_missing, is_line1_missing);
+ }
+
+ // Return true if all requirements are fulfilled.
+ return !(is_line1_missing || is_city_missing || is_state_missing ||
+ is_zip_missing || is_zip_or_state_requirement_violated ||
+ is_line1_or_house_number_violated);
+}
+
+std::string GetPredictedCountryCode(const AutofillProfile& profile,
+ const std::string& variation_country_code,
+ const std::string& app_locale,
+ LogBuffer* import_log_buffer) {
+ // Try to acquire the country code form the filled form.
+ std::string country_code =
+ base::UTF16ToASCII(profile.GetRawInfo(ADDRESS_HOME_COUNTRY));
+
+ if (import_log_buffer && !country_code.empty()) {
+ *import_log_buffer << LogMessage::kImportAddressProfileFromFormCountrySource
+ << "Country entry in form." << CTag{};
+ }
+
+ // As a fallback, use the variation service state to get a country code.
+ if (country_code.empty() && !variation_country_code.empty()) {
+ country_code = variation_country_code;
+ if (import_log_buffer) {
+ *import_log_buffer
+ << LogMessage::kImportAddressProfileFromFormCountrySource
+ << "Variations service." << CTag{};
+ }
+ }
+
+ // As the last resort, derive the country code from the app_locale.
+ if (country_code.empty()) {
+ country_code = AutofillCountry::CountryCodeForLocale(app_locale);
+ if (import_log_buffer && !country_code.empty()) {
+ *import_log_buffer
+ << LogMessage::kImportAddressProfileFromFormCountrySource
+ << "App locale." << CTag{};
+ }
+ }
+
+ return country_code;
+}
+
+MultiStepImportMerger::MultiStepImportMerger(
+ const std::string& app_locale,
+ const std::string& variation_country_code)
+ : app_locale_(app_locale),
+ variation_country_code_(variation_country_code) {}
+MultiStepImportMerger::~MultiStepImportMerger() {}
+
+void MultiStepImportMerger::ProcessMultiStepImport(
+ AutofillProfile& profile,
+ ProfileImportMetadata& import_metadata,
+ const url::Origin& origin) {
+ if (!base::FeatureList::IsEnabled(
+ features::kAutofillEnableMultiStepImports)) {
+ return;
+ }
+
+ multistep_candidates_.RemoveOutdatedItems(
+ features::kAutofillMultiStepImportCandidateTTL.Get(), origin);
+ bool has_min_address_requirements =
+ MergeProfileWithMultiStepCandidates(profile, import_metadata, origin);
+
+ if (!has_min_address_requirements ||
+ features::kAutofillEnableMultiStepImportComplements.Get()) {
+ // Add `profile| as a `multistep_candidate`. This happens for incomplete
+ // profiles, which can then be complemented in later steps. When
+ // `kAutofillEnableMultiStepImportComplements` is enabled, complete profiles
+ // are stored too, which enables updating them in later steps.
+ // In the latter case, Autofill tries to import the `profile`. This logs
+ // metrics depending on `import_metadata`. To prevent double counting,
+ // an we store an empty `ProfileImportMetadata` object in this case.
+ multistep_candidates_.Push({.profile = profile,
+ .import_metadata = has_min_address_requirements
+ ? ProfileImportMetadata()
+ : import_metadata},
+ origin);
+ }
+}
+
+bool MultiStepImportMerger::MergeProfileWithMultiStepCandidates(
+ AutofillProfile& profile,
+ ProfileImportMetadata& import_metadata,
+ const url::Origin& origin) {
+ // Greedily merge with a prefix of |multistep_candidates|.
+ AutofillProfileComparator comparator(app_locale_);
+ auto candidate = multistep_candidates_.begin();
+ AutofillProfile completed_profile = profile;
+ ProfileImportMetadata completed_metadata = import_metadata;
+ // Country completion has not happened yet, so this field can be ignored.
+ DCHECK(!completed_metadata.did_complement_country);
+ while (candidate != multistep_candidates_.end()) {
+ if (!comparator.AreMergeable(completed_profile, candidate->profile) ||
+ completed_profile.MergeDataFrom(candidate->profile, app_locale_)) {
+ break;
+ }
+ // ProfileImportMetadata is only relevant for metrics. If the phone number
+ // was removed from a partial profile, we still want that removal to appear
+ // in the metrics, because it would have hindered that partial profile from
+ // import and merging.
+ completed_metadata.did_remove_invalid_phone_number |=
+ candidate->import_metadata.did_remove_invalid_phone_number;
+ candidate++;
+ }
+
+ // The minimum address requirements depend on the country, which has possibly
+ // changed as a result of the merge.
+ if (IsMinimumAddress(
+ completed_profile,
+ GetPredictedCountryCode(completed_profile, variation_country_code_,
+ app_locale_, /*import_log_buffer=*/nullptr),
+ app_locale_,
+ /*import_log_buffer=*/nullptr, /*collect_metrics=*/false)) {
+ profile = std::move(completed_profile);
+ import_metadata = std::move(completed_metadata);
+ multistep_candidates_.Clear();
+ return true;
+ } else {
+ // Remove all profiles that couldn't be merged.
+ multistep_candidates_.erase(candidate, multistep_candidates_.end());
+ return false;
+ }
+}
+
+} // namespace autofill
diff --git a/chromium/components/autofill/core/browser/form_data_importer_utils.h b/chromium/components/autofill/core/browser/form_data_importer_utils.h
new file mode 100644
index 00000000000..ee2b64596ad
--- /dev/null
+++ b/chromium/components/autofill/core/browser/form_data_importer_utils.h
@@ -0,0 +1,171 @@
+// Copyright 2022 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_FORM_DATA_IMPORTER_UTILS_H_
+#define COMPONENTS_AUTOFILL_CORE_BROWSER_FORM_DATA_IMPORTER_UTILS_H_
+
+#include <iterator>
+#include <list>
+#include <string>
+#include <utility>
+
+#include "base/time/time.h"
+#include "components/autofill/core/browser/autofill_profile_import_process.h"
+#include "components/autofill/core/browser/data_model/autofill_profile.h"
+#include "components/autofill/core/common/autofill_clock.h"
+#include "components/autofill/core/common/logging/log_buffer.h"
+#include "third_party/abseil-cpp/absl/types/optional.h"
+#include "url/origin.h"
+
+namespace autofill {
+
+// Encapsulates a list of Ts, ordered by the time they were added (newest
+// first). All Ts share the same `origin`. This is useful for tracking
+// relationships between submitted forms on the same origin, within a small
+// period of time.
+template <class T>
+class TimestampedSameOriginQueue {
+ public:
+ // The queue stores Ts augmented with a timestamp.
+ struct value_type : public T {
+ value_type(T t, base::Time timestamp)
+ : T(std::move(t)), timestamp(std::move(timestamp)) {}
+
+ const base::Time timestamp;
+ };
+ using const_iterator = typename std::list<value_type>::const_iterator;
+
+ // Pushes `item` at the current timestamp.
+ void Push(T item, const url::Origin& item_origin) {
+ DCHECK(!origin_ || *origin_ == item_origin);
+ items_.emplace_front(std::move(item), AutofillClock::Now());
+ origin_ = item_origin;
+ }
+
+ // Removes the oldest element from the queue.
+ void Pop() { erase(std::prev(end()), end()); }
+
+ // Removes all `items` from a different `origin` or older than `ttl`.
+ // This is not done as part of `Push()`, as outdated items (for example in the
+ // multi-step import use-case) should be deleted as soon as possible for
+ // privacy reasons, even when no `Push()` happens.
+ void RemoveOutdatedItems(const base::TimeDelta& ttl,
+ const url::Origin& new_origin) {
+ if (origin_ && *origin_ != new_origin) {
+ Clear();
+ } else {
+ const base::Time now = AutofillClock::Now();
+ while (!empty() && now - items_.back().timestamp > ttl)
+ Pop();
+ }
+ }
+
+ // Returns the origin shared by the elements in the queue. Or nullopt, if
+ // the queue is currently `Empty()`.
+ const absl::optional<url::Origin>& Origin() const { return origin_; }
+
+ size_t size() const { return items_.size(); }
+ bool empty() const { return items_.empty(); }
+
+ // Removes the items [first, last[.
+ void erase(const_iterator first, const_iterator last) {
+ items_.erase(first, last);
+ if (empty())
+ origin_.reset();
+ }
+
+ void Clear() { erase(begin(), end()); }
+
+ // The elements are ordered from newest to latest.
+ const_iterator begin() const { return items_.begin(); }
+ const_iterator end() const { return items_.end(); }
+
+ private:
+ std::list<value_type> items_;
+ // If the queue is not `empty()`, this represents the origin of all `items_`.
+ absl::optional<url::Origin> origin_;
+};
+
+// Returns true if minimum requirements for import of a given `profile` have
+// been met. An address submitted via a form must have at least the fields
+// required as determined by its country code.
+// No verification of validity of the contents is performed. This is an
+// existence check only.
+bool IsMinimumAddress(const AutofillProfile& profile,
+ const std::string& predicted_country_code,
+ const std::string& app_locale,
+ LogBuffer* import_log_buffer,
+ bool collect_metrics);
+
+// Tries to infer the country `profile` is from, which can be useful to
+// verify whether the data is sensible. Returns a two-letter ISO country code
+// by considering, in decreasing order of priority:
+// - The country specified in `profile`.
+// - The country determined by the variation service stored in
+// `variation_country_code`.
+// - The country code corresponding to `app_locale`.
+std::string GetPredictedCountryCode(const AutofillProfile& profile,
+ const std::string& variation_country_code,
+ const std::string& app_locale,
+ LogBuffer* import_log_buffer);
+
+// Stores recently submitted profile fragments, which are merged against future
+// import candidates to construct a complete profile. This enables importing
+// from multi-step import flows.
+class MultiStepImportMerger {
+ public:
+ MultiStepImportMerger(const std::string& app_locale,
+ const std::string& variation_country_code);
+ ~MultiStepImportMerger();
+
+ // Removes updated multi-step candidates, merges `profile` with multi-step
+ // candidates and potentially stores it as a multi-step candidate itself.
+ // `profile` and `import_metadata` are updated accordingly, if the profile
+ // can be merged. See `MergeProfileWithMultiStepCandidates()` for details.
+ // Only applicable when `kAutofillEnableMultiStepImports` is enabled.
+ void ProcessMultiStepImport(AutofillProfile& profile,
+ ProfileImportMetadata& import_metadata,
+ const url::Origin& origin);
+
+ const absl::optional<url::Origin>& Origin() const {
+ return multistep_candidates_.Origin();
+ }
+
+ void Clear() { multistep_candidates_.Clear(); }
+
+ private:
+ // Merges a given `profile` stepwise with `multistep_candidates_` to
+ // complete it. `profile` is assumed to contain no invalid information.
+ // Returns true if the resulting profile satisfies the minimum address
+ // requirements. `profile` and `import_metadata` are updated in this case
+ // with the result of merging all relevant candidates.
+ // Returns false otherwise and leaves `profile` and `import_metadata`
+ // unchanged. Any merged or colliding `multistep_candidates_` are cleared.
+ // `origin`: The origin of the form where `profile` was imported from.
+ bool MergeProfileWithMultiStepCandidates(
+ AutofillProfile& profile,
+ ProfileImportMetadata& import_metadata,
+ const url::Origin& origin);
+
+ // Needed to predict the country code of a merged import candidate, to
+ // ultimately decide if the profile meets the minimum import requirements.
+ std::string app_locale_;
+ std::string variation_country_code_;
+
+ // Represents a submitted form, stored to be considered as a merge candidate
+ // for other candidate profiles in future submits in a multi-step import
+ // flow.
+ struct MultiStepFormProfileCandidate {
+ // The import candidate.
+ AutofillProfile profile;
+ // Metadata about how `profile` was constructed.
+ ProfileImportMetadata import_metadata;
+ };
+ TimestampedSameOriginQueue<MultiStepFormProfileCandidate>
+ multistep_candidates_;
+};
+
+} // namespace autofill
+
+#endif // COMPONENTS_AUTOFILL_CORE_BROWSER_FORM_DATA_IMPORTER_UTILS_H_
diff --git a/chromium/components/autofill/core/browser/form_data_importer_utils_unittest.cc b/chromium/components/autofill/core/browser/form_data_importer_utils_unittest.cc
new file mode 100644
index 00000000000..f20b2073d42
--- /dev/null
+++ b/chromium/components/autofill/core/browser/form_data_importer_utils_unittest.cc
@@ -0,0 +1,85 @@
+// Copyright 2022 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/form_data_importer_utils.h"
+
+#include <vector>
+
+#include "base/time/time.h"
+#include "components/autofill/core/browser/test_autofill_clock.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace autofill {
+
+namespace {
+
+// As TimestampedSameOriginQueue cannot be initialized with primitive types,
+// this wrapper is used for testing.
+struct IntWrapper {
+ int value;
+};
+bool operator==(IntWrapper x, int y) {
+ return x.value == y;
+}
+
+} // anonymous namespace
+
+// TimestampedSameOriginQueue's queue-like functionality works as expected.
+TEST(FormDataImporterUtilsTest, TimestampedSameOriginQueue) {
+ TimestampedSameOriginQueue<IntWrapper> queue;
+ EXPECT_TRUE(queue.empty());
+ const url::Origin irrelevant_origin;
+ for (int i = 0; i < 4; i++)
+ queue.Push({i}, irrelevant_origin);
+ EXPECT_EQ(queue.size(), 4u);
+ EXPECT_THAT(queue, testing::ElementsAre(3, 2, 1, 0));
+ queue.Pop();
+ EXPECT_THAT(queue, testing::ElementsAre(3, 2, 1));
+ queue.erase(std::next(queue.begin()), queue.end());
+ EXPECT_THAT(queue, testing::ElementsAre(3));
+ queue.Clear();
+ EXPECT_TRUE(queue.empty());
+}
+
+// RemoveOutdatedItems clears the queue if the origin doesn't match.
+TEST(FormDataImporterUtilsTest, TimestampedSameOriginQueue_DifferentOrigins) {
+ TimestampedSameOriginQueue<IntWrapper> queue;
+ auto foo_origin = url::Origin::Create(GURL("http://foo.com"));
+ queue.Push({0}, foo_origin);
+ EXPECT_EQ(queue.Origin(), foo_origin);
+ // The TTL or 1 hour is irrelevant here.
+ queue.RemoveOutdatedItems(base::Hours(1),
+ url::Origin::Create(GURL("http://bar.com")));
+ EXPECT_EQ(queue.Origin(), absl::nullopt);
+ EXPECT_TRUE(queue.empty());
+}
+
+// RemoveOutdatedItems clears items past their TTL.
+TEST(FormDataImporterUtilsTest, TimestampedSameOriginQueue_TTL) {
+ TimestampedSameOriginQueue<IntWrapper> queue;
+ const url::Origin irrelevant_origin;
+ TestAutofillClock test_clock;
+ for (int i = 0; i < 4; i++) {
+ queue.Push({i}, irrelevant_origin);
+ test_clock.Advance(base::Minutes(1));
+ }
+ // Remove all items older than 2.5 min.
+ queue.RemoveOutdatedItems(base::Seconds(150), irrelevant_origin);
+ EXPECT_THAT(queue, testing::ElementsAre(3, 2));
+}
+
+TEST(FormDataImporterUtilsTest, GetPredictedCountryCode) {
+ AutofillProfile us_profile;
+ us_profile.SetRawInfo(ADDRESS_HOME_COUNTRY, u"US");
+ AutofillProfile empty_profile;
+ // Test prioritization: profile > variation service state > app locale
+ EXPECT_EQ(GetPredictedCountryCode(us_profile, "DE", "de-AT", nullptr), "US");
+ EXPECT_EQ(GetPredictedCountryCode(us_profile, "", "de-AT", nullptr), "US");
+ EXPECT_EQ(GetPredictedCountryCode(empty_profile, "DE", "de-AT", nullptr),
+ "DE");
+ EXPECT_EQ(GetPredictedCountryCode(empty_profile, "", "de-AT", nullptr), "AT");
+}
+
+} // namespace autofill
diff --git a/chromium/components/autofill/core/browser/form_parsing/address_field.cc b/chromium/components/autofill/core/browser/form_parsing/address_field.cc
index 32cacb9bace..01bf673df74 100644
--- a/chromium/components/autofill/core/browser/form_parsing/address_field.cc
+++ b/chromium/components/autofill/core/browser/form_parsing/address_field.cc
@@ -13,11 +13,11 @@
#include "base/check.h"
#include "base/strings/string_util.h"
#include "components/autofill/core/browser/autofill_field.h"
-#include "components/autofill/core/browser/autofill_regex_constants.h"
#include "components/autofill/core/browser/field_types.h"
#include "components/autofill/core/browser/form_parsing/autofill_scanner.h"
#include "components/autofill/core/browser/form_parsing/regex_patterns.h"
#include "components/autofill/core/common/autofill_features.h"
+#include "components/autofill/core/common/autofill_regex_constants.h"
namespace autofill {
@@ -193,7 +193,7 @@ AddressField::AddressField(LogManager* log_manager)
: log_manager_(log_manager) {}
void AddressField::AddClassifications(
- FieldCandidatesMap* field_candidates) const {
+ FieldCandidatesMap& field_candidates) const {
// The page can request the address lines as a single textarea input or as
// multiple text fields (or not at all), but it shouldn't be possible to
// request both.
diff --git a/chromium/components/autofill/core/browser/form_parsing/address_field.h b/chromium/components/autofill/core/browser/form_parsing/address_field.h
index 5b485650c75..9ed051d6d8e 100644
--- a/chromium/components/autofill/core/browser/form_parsing/address_field.h
+++ b/chromium/components/autofill/core/browser/form_parsing/address_field.h
@@ -33,7 +33,7 @@ class AddressField : public FormField {
AddressField& operator=(const AddressField&) = delete;
protected:
- void AddClassifications(FieldCandidatesMap* field_candidates) const override;
+ void AddClassifications(FieldCandidatesMap& field_candidates) const override;
private:
// When parsing a field's label and name separately with a given pattern:
diff --git a/chromium/components/autofill/core/browser/form_parsing/birthdate_field.cc b/chromium/components/autofill/core/browser/form_parsing/birthdate_field.cc
new file mode 100644
index 00000000000..005a4b87646
--- /dev/null
+++ b/chromium/components/autofill/core/browser/form_parsing/birthdate_field.cc
@@ -0,0 +1,118 @@
+// Copyright 2022 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/form_parsing/birthdate_field.h"
+
+#include "base/memory/ptr_util.h"
+#include "base/ranges/algorithm.h"
+#include "base/strings/string_number_conversions.h"
+#include "components/autofill/core/browser/autofill_field.h"
+#include "components/autofill/core/browser/form_parsing/autofill_scanner.h"
+#include "components/autofill/core/browser/form_parsing/regex_patterns.h"
+#include "components/autofill/core/common/autofill_clock.h"
+#include "components/autofill/core/common/autofill_regex_constants.h"
+
+namespace autofill {
+
+namespace {
+
+// Checks if the `option`'s content or value represents a number with value
+// contained in [a, b].
+bool IsSelectValueBetween(const SelectOption& option, int a, int b) {
+ auto IsValueBetween = [&](base::StringPiece16 string) {
+ int value;
+ return base::StringToInt(string, &value) && a <= value && value <= b;
+ };
+ return IsValueBetween(option.content) || IsValueBetween(option.value);
+}
+
+} // namespace
+
+BirthdateField::BirthdateField(const AutofillField* day,
+ const AutofillField* month,
+ const AutofillField* year)
+ : day_(day), month_(month), year_(year) {}
+
+// static
+std::unique_ptr<FormField> BirthdateField::Parse(
+ AutofillScanner* scanner,
+ const LanguageCode& page_language,
+ PatternSource pattern_source,
+ LogManager* log_manager) {
+ // Currently only <select> elements are considered.
+ AutofillField* day = nullptr;
+ AutofillField* month = nullptr;
+ AutofillField* year = nullptr;
+ // Expect at most 31 days/12 months plus one placeholder.
+ if (FormField::ParseInAnyOrder(
+ scanner,
+ {{&day, base::BindRepeating(&IsSelectWithIncreasingValues, scanner,
+ 28, 32)},
+ {&month, base::BindRepeating(&IsSelectWithIncreasingValues, scanner,
+ 12, 13)},
+ {&year, base::BindRepeating(&IsLikelyBirthdateYearSelectField,
+ scanner)}})) {
+ return base::WrapUnique(new BirthdateField(day, month, year));
+ }
+ return nullptr;
+}
+
+// static
+bool BirthdateField::IsSelectWithIncreasingValues(AutofillScanner* scanner,
+ int max_value,
+ size_t max_options) {
+ AutofillField* field = scanner->Cursor();
+ if (!MatchesFormControlType(field->form_control_type,
+ {MatchFieldType::kSelect})) {
+ return false;
+ }
+ auto options = field->options;
+ if (options.empty() || options.size() > max_options)
+ return false;
+ auto it = options.cbegin();
+ // Skip a possible placeholder.
+ if (!IsSelectValueBetween(*it, 1, 1))
+ it++;
+ // Check that there are the enough options remaining.
+ if (options.cend() - it < max_value)
+ return false;
+ for (int i = 1; i <= max_value; i++) {
+ if (!IsSelectValueBetween(*it, i, i))
+ return false;
+ it++;
+ }
+ return true;
+}
+
+// static
+bool BirthdateField::IsLikelyBirthdateYearSelectField(
+ AutofillScanner* scanner) {
+ AutofillField* field = scanner->Cursor();
+ if (!MatchesFormControlType(field->form_control_type,
+ {MatchFieldType::kSelect})) {
+ return false;
+ }
+ auto options = field->options;
+ base::Time::Exploded current_date;
+ AutofillClock::Now().UTCExplode(&current_date);
+ DCHECK(current_date.HasValidValues());
+ return !options.empty() &&
+ base::ranges::all_of(options.begin() + 1, options.end(),
+ [&](const SelectOption& option) {
+ return IsSelectValueBetween(option, 1900,
+ current_date.year);
+ });
+}
+
+void BirthdateField::AddClassifications(
+ FieldCandidatesMap& field_candidates) const {
+ AddClassification(day_, BIRTHDATE_DAY, kBaseBirthdateParserScore,
+ field_candidates);
+ AddClassification(month_, BIRTHDATE_MONTH, kBaseBirthdateParserScore,
+ field_candidates);
+ AddClassification(year_, BIRTHDATE_4_DIGIT_YEAR, kBaseBirthdateParserScore,
+ field_candidates);
+}
+
+} // namespace autofill
diff --git a/chromium/components/autofill/core/browser/form_parsing/birthdate_field.h b/chromium/components/autofill/core/browser/form_parsing/birthdate_field.h
new file mode 100644
index 00000000000..8a91ee0ab77
--- /dev/null
+++ b/chromium/components/autofill/core/browser/form_parsing/birthdate_field.h
@@ -0,0 +1,56 @@
+// Copyright 2022 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_FORM_PARSING_BIRTHDATE_FIELD_H_
+#define COMPONENTS_AUTOFILL_CORE_BROWSER_FORM_PARSING_BIRTHDATE_FIELD_H_
+
+#include <vector>
+
+#include "base/memory/raw_ptr.h"
+#include "components/autofill/core/browser/form_parsing/form_field.h"
+#include "components/autofill/core/common/language_code.h"
+
+namespace autofill {
+
+// Birthdate fields are currently not filled, but identifying them will help to
+// reduce the number of false positive credit card expiration dates.
+class BirthdateField : public FormField {
+ public:
+ static std::unique_ptr<FormField> Parse(AutofillScanner* scanner,
+ const LanguageCode& page_language,
+ PatternSource pattern_source,
+ LogManager* log_manager);
+
+ BirthdateField(const BirthdateField&) = delete;
+ BirthdateField& operator=(const BirthdateField&) = delete;
+
+ protected:
+ void AddClassifications(FieldCandidatesMap& field_candidates) const override;
+
+ private:
+ BirthdateField(const AutofillField* day,
+ const AutofillField* month,
+ const AutofillField* year);
+
+ // Checks if the scanner's current field is a <select> and if its options
+ // contains the values [1, `max_value`] in increasing order, possibly after a
+ // placeholder. Moreover checks that at most max_options options are present.
+ static bool IsSelectWithIncreasingValues(AutofillScanner* scanner,
+ int max_value,
+ size_t max_options);
+
+ // Checks if the scanner's current field is a <select> and if all but the
+ // first of its options represents a numerical value in [1900, current-year].
+ // The first option might contain a placeholder.
+ static bool IsLikelyBirthdateYearSelectField(AutofillScanner* scanner);
+
+ private:
+ raw_ptr<const AutofillField> day_;
+ raw_ptr<const AutofillField> month_;
+ raw_ptr<const AutofillField> year_;
+};
+
+} // namespace autofill
+
+#endif // COMPONENTS_AUTOFILL_CORE_BROWSER_FORM_PARSING_BIRTHDATE_FIELD_H_
diff --git a/chromium/components/autofill/core/browser/form_parsing/birthdate_field_unittest.cc b/chromium/components/autofill/core/browser/form_parsing/birthdate_field_unittest.cc
new file mode 100644
index 00000000000..56abba77f8e
--- /dev/null
+++ b/chromium/components/autofill/core/browser/form_parsing/birthdate_field_unittest.cc
@@ -0,0 +1,132 @@
+// Copyright 2022 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/form_parsing/birthdate_field.h"
+
+#include <vector>
+
+#include "base/strings/string_number_conversions.h"
+#include "components/autofill/core/browser/form_parsing/parsing_test_utils.h"
+
+namespace autofill {
+
+namespace {
+
+// Returns a vector of consecutive SelectOption items with values and content in
+// [`low`, `high`] in either in- or decreasing order.
+std::vector<SelectOption> GetSelectOptionRange(int low,
+ int high,
+ bool increasing) {
+ std::vector<SelectOption> options;
+ for (int i = 0; i <= high - low; i++) {
+ std::u16string value =
+ base::NumberToString16(increasing ? low + i : high - i);
+ options.push_back({value, value});
+ }
+ return options;
+}
+
+std::vector<SelectOption> GetDays() {
+ return GetSelectOptionRange(1, 31, /*increasing=*/true);
+}
+std::vector<SelectOption> GetMonths() {
+ return GetSelectOptionRange(1, 12, /*increasing=*/true);
+}
+std::vector<SelectOption> GetYears() {
+ return GetSelectOptionRange(1900, 2022, /*increasing=*/false);
+}
+
+} // namespace
+
+class BirthdateFieldTest
+ : public FormFieldTestBase,
+ public testing::TestWithParam<PatternProviderFeatureState> {
+ public:
+ BirthdateFieldTest() : FormFieldTestBase(GetParam()) {}
+ BirthdateFieldTest(const BirthdateFieldTest&) = delete;
+ BirthdateFieldTest& operator=(const BirthdateFieldTest&) = delete;
+
+ protected:
+ std::unique_ptr<FormField> Parse(
+ AutofillScanner* scanner,
+ const LanguageCode& page_language = LanguageCode("en")) override {
+ return BirthdateField::Parse(scanner, page_language,
+ GetActivePatternSource(),
+ /*log_manager=*/nullptr);
+ }
+};
+
+INSTANTIATE_TEST_SUITE_P(
+ BirthdateFieldTest,
+ BirthdateFieldTest,
+ ::testing::ValuesIn(PatternProviderFeatureState::All()));
+
+TEST_P(BirthdateFieldTest, ParseDMY) {
+ AddSelectOneFormFieldData("", "", GetDays(), BIRTHDATE_DAY);
+ AddSelectOneFormFieldData("", "", GetMonths(), BIRTHDATE_MONTH);
+ AddSelectOneFormFieldData("", "", GetYears(), BIRTHDATE_4_DIGIT_YEAR);
+ ClassifyAndVerify(ParseResult::PARSED);
+}
+
+TEST_P(BirthdateFieldTest, ParseYMD) {
+ AddSelectOneFormFieldData("", "", GetYears(), BIRTHDATE_4_DIGIT_YEAR);
+ AddSelectOneFormFieldData("", "", GetMonths(), BIRTHDATE_MONTH);
+ AddSelectOneFormFieldData("", "", GetDays(), BIRTHDATE_DAY);
+ ClassifyAndVerify(ParseResult::PARSED);
+}
+
+TEST_P(BirthdateFieldTest, DefaultOptions) {
+ auto days = GetDays();
+ days.insert(days.begin(), {u"", u"Day"});
+ auto months = GetMonths();
+ months.insert(months.begin(), {u"", u"Month"});
+ auto years = GetYears();
+ years.insert(years.begin(), {u"", u"Year"});
+ AddSelectOneFormFieldData("", "", days, BIRTHDATE_DAY);
+ AddSelectOneFormFieldData("", "", months, BIRTHDATE_MONTH);
+ AddSelectOneFormFieldData("", "", years, BIRTHDATE_4_DIGIT_YEAR);
+ ClassifyAndVerify(ParseResult::PARSED);
+}
+
+TEST_P(BirthdateFieldTest, LeadingZeros) {
+ // Replace the first 9 day entries with 01-09.
+ auto days = GetDays();
+ ASSERT_GE(days.size(), 9u);
+ for (int i = 0; i < 9; i++) {
+ std::u16string value = u"0" + base::NumberToString16(i + 1);
+ days[i] = {value, value};
+ }
+ AddSelectOneFormFieldData("", "", days, BIRTHDATE_DAY);
+ AddSelectOneFormFieldData("", "", GetMonths(), BIRTHDATE_MONTH);
+ AddSelectOneFormFieldData("", "", GetYears(), BIRTHDATE_4_DIGIT_YEAR);
+ ClassifyAndVerify(ParseResult::PARSED);
+}
+
+TEST_P(BirthdateFieldTest, TooManyOptions) {
+ auto days = GetDays();
+ days.insert(days.begin(), {u"", u"Hello"});
+ days.insert(days.begin(), {u"", u"World"});
+ EXPECT_GT(days.size(), 13u); // Too many options for a day selector.
+ AddSelectOneFormFieldData("", "", days, BIRTHDATE_DAY);
+ AddSelectOneFormFieldData("", "", GetMonths(), BIRTHDATE_MONTH);
+ AddSelectOneFormFieldData("", "", GetYears(), BIRTHDATE_4_DIGIT_YEAR);
+ ClassifyAndVerify(ParseResult::NOT_PARSED);
+}
+
+TEST_P(BirthdateFieldTest, MissingYear) {
+ AddSelectOneFormFieldData("", "", GetDays(), BIRTHDATE_DAY);
+ AddSelectOneFormFieldData("", "", GetMonths(), BIRTHDATE_MONTH);
+ ClassifyAndVerify(ParseResult::NOT_PARSED);
+}
+
+TEST_P(BirthdateFieldTest, IncompleteMonth) {
+ auto months = GetMonths();
+ months.resize(5);
+ AddSelectOneFormFieldData("", "", GetDays(), BIRTHDATE_DAY);
+ AddSelectOneFormFieldData("", "", months, BIRTHDATE_MONTH);
+ AddSelectOneFormFieldData("", "", GetYears(), BIRTHDATE_4_DIGIT_YEAR);
+ ClassifyAndVerify(ParseResult::NOT_PARSED);
+}
+
+} // namespace autofill
diff --git a/chromium/components/autofill/core/browser/form_parsing/credit_card_field.cc b/chromium/components/autofill/core/browser/form_parsing/credit_card_field.cc
index 806c8b74ae7..d025e90600b 100644
--- a/chromium/components/autofill/core/browser/form_parsing/credit_card_field.cc
+++ b/chromium/components/autofill/core/browser/form_parsing/credit_card_field.cc
@@ -15,8 +15,6 @@
#include "base/strings/string_util.h"
#include "base/time/time.h"
#include "components/autofill/core/browser/autofill_field.h"
-#include "components/autofill/core/browser/autofill_regex_constants.h"
-#include "components/autofill/core/browser/autofill_regexes.h"
#include "components/autofill/core/browser/field_filler.h"
#include "components/autofill/core/browser/field_types.h"
#include "components/autofill/core/browser/form_parsing/autofill_scanner.h"
@@ -24,6 +22,8 @@
#include "components/autofill/core/browser/form_parsing/regex_patterns.h"
#include "components/autofill/core/common/autofill_clock.h"
#include "components/autofill/core/common/autofill_features.h"
+#include "components/autofill/core/common/autofill_regex_constants.h"
+#include "components/autofill/core/common/autofill_regexes.h"
#include "components/strings/grit/components_strings.h"
#include "ui/base/l10n/l10n_util.h"
@@ -302,18 +302,18 @@ bool CreditCardField::LikelyCardMonthSelectField(AutofillScanner* scanner) {
// Filter out years.
const std::u16string kNumericalYearRe = u"[1-9][0-9][0-9][0-9]";
for (const auto& option : field->options) {
- if (MatchesPattern(option.value, kNumericalYearRe))
+ if (MatchesRegexWithCache(option.value, kNumericalYearRe))
return false;
}
for (const auto& option : field->options) {
- if (MatchesPattern(option.content, kNumericalYearRe))
+ if (MatchesRegexWithCache(option.content, kNumericalYearRe))
return false;
}
// Look for numerical months.
const std::u16string kNumericalMonthRe = u"12";
- if (MatchesPattern(field->options.back().value, kNumericalMonthRe) ||
- MatchesPattern(field->options.back().content, kNumericalMonthRe)) {
+ if (MatchesRegexWithCache(field->options.back().value, kNumericalMonthRe) ||
+ MatchesRegexWithCache(field->options.back().content, kNumericalMonthRe)) {
return true;
}
@@ -343,7 +343,7 @@ bool CreditCardField::LikelyCardYearSelectField(
// numbers 1 to 9 as well in them, which we can filter on.
const std::u16string kSingleDigitDateRe = u"\\b[1-9]\\b";
for (const auto& option : field->options) {
- if (MatchesPattern(option.content, kSingleDigitDateRe)) {
+ if (MatchesRegexWithCache(option.content, kSingleDigitDateRe)) {
return false;
}
}
@@ -361,7 +361,7 @@ bool CreditCardField::LikelyCardYearSelectField(
// expiration year, but show it in the context of a birth year selector.
const std::u16string kBirthYearRe = u"(1999|99)";
for (const auto& option : field->options) {
- if (MatchesPattern(option.content, kBirthYearRe)) {
+ if (MatchesRegexWithCache(option.content, kBirthYearRe)) {
return false;
}
}
@@ -472,9 +472,9 @@ CreditCardField::CreditCardField(LogManager* log_manager)
CreditCardField::~CreditCardField() {}
void CreditCardField::AddClassifications(
- FieldCandidatesMap* field_candidates) const {
- for (size_t index = 0; index < numbers_.size(); ++index) {
- AddClassification(numbers_[index], CREDIT_CARD_NUMBER,
+ FieldCandidatesMap& field_candidates) const {
+ for (auto* number : numbers_) {
+ AddClassification(number, CREDIT_CARD_NUMBER,
kBaseCreditCardParserScore, field_candidates);
}
@@ -528,23 +528,18 @@ bool CreditCardField::ParseExpirationDate(AutofillScanner* scanner,
// First try to parse split month/year expiration fields by looking for a
// pair of select fields that look like month/year.
- size_t month_year_saved_cursor = scanner->SaveCursor();
-
- if (LikelyCardMonthSelectField(scanner)) {
- expiration_month_ = scanner->Cursor();
- scanner->Advance();
- if (LikelyCardYearSelectField(scanner, log_manager, page_language,
- pattern_source)) {
- expiration_year_ = scanner->Cursor();
- scanner->Advance();
- return true;
- }
- expiration_month_ = nullptr;
- expiration_year_ = nullptr;
+ if (ParseInAnyOrder(
+ scanner, {{&expiration_month_,
+ base::BindRepeating(&LikelyCardMonthSelectField, scanner)},
+ {&expiration_year_,
+ base::BindRepeating(&LikelyCardYearSelectField, scanner,
+ log_manager, page_language,
+ pattern_source)}})) {
+ return true;
}
// If that fails, do a general regex search.
- scanner->RewindTo(month_year_saved_cursor);
+ size_t month_year_saved_cursor = scanner->SaveCursor();
const auto kMatchCCType =
kDefaultMatchParamsWith<MatchFieldType::kNumber,
MatchFieldType::kTelephone,
diff --git a/chromium/components/autofill/core/browser/form_parsing/credit_card_field.h b/chromium/components/autofill/core/browser/form_parsing/credit_card_field.h
index b2b8dc7c100..9b0055e0476 100644
--- a/chromium/components/autofill/core/browser/form_parsing/credit_card_field.h
+++ b/chromium/components/autofill/core/browser/form_parsing/credit_card_field.h
@@ -34,7 +34,7 @@ class CreditCardField : public FormField {
LogManager* log_manager);
protected:
- void AddClassifications(FieldCandidatesMap* field_candidates) const override;
+ void AddClassifications(FieldCandidatesMap& field_candidates) const override;
private:
friend class CreditCardFieldTestBase;
diff --git a/chromium/components/autofill/core/browser/form_parsing/credit_card_field_unittest.cc b/chromium/components/autofill/core/browser/form_parsing/credit_card_field_unittest.cc
index 15bf02bde14..bc2387b46be 100644
--- a/chromium/components/autofill/core/browser/form_parsing/credit_card_field_unittest.cc
+++ b/chromium/components/autofill/core/browser/form_parsing/credit_card_field_unittest.cc
@@ -4,6 +4,7 @@
#include "components/autofill/core/browser/form_parsing/credit_card_field.h"
+#include <algorithm>
#include <memory>
#include <vector>
@@ -105,7 +106,7 @@ class CreditCardFieldTestBase : public FormFieldTestBase {
if (field_ == nullptr) {
scanner.Advance();
} else {
- field_->AddClassificationsForTesting(&field_candidates_map_);
+ field_->AddClassificationsForTesting(field_candidates_map_);
}
}
TestClassificationExpectations();
@@ -167,13 +168,16 @@ struct CreditCardFieldYearTestCase {
class CreditCardFieldYearTest
: public CreditCardFieldTestBase,
public testing::TestWithParam<std::tuple<PatternProviderFeatureState,
- CreditCardFieldYearTestCase>> {
+ CreditCardFieldYearTestCase,
+ bool>> {
public:
CreditCardFieldYearTest()
: CreditCardFieldTestBase(std::get<0>(GetParam())) {}
bool with_noise() const { return std::get<1>(GetParam()).with_noise; }
+ bool ShouldSwapMonthAndYear() const { return std::get<2>(GetParam()); }
+
ServerFieldType expected_type() const {
return std::get<1>(GetParam()).expected_type;
}
@@ -201,6 +205,9 @@ TEST_P(CreditCardFieldYearTest, ParseMinimumCreditCardWithExpiryDateOptions) {
expected_type() == CREDIT_CARD_EXP_2_DIGIT_YEAR ? 2 : 4,
MakeOptionVector(), expected_type());
+ if (ShouldSwapMonthAndYear())
+ std::swap(list_[1], list_[2]);
+
ClassifyAndVerify(ParseResult::PARSED);
}
@@ -213,7 +220,8 @@ INSTANTIATE_TEST_SUITE_P(
CreditCardFieldYearTestCase{false, CREDIT_CARD_EXP_2_DIGIT_YEAR},
CreditCardFieldYearTestCase{false, CREDIT_CARD_EXP_4_DIGIT_YEAR},
CreditCardFieldYearTestCase{true, CREDIT_CARD_EXP_2_DIGIT_YEAR},
- CreditCardFieldYearTestCase{true, CREDIT_CARD_EXP_4_DIGIT_YEAR})));
+ CreditCardFieldYearTestCase{true, CREDIT_CARD_EXP_4_DIGIT_YEAR}),
+ testing::Bool()));
TEST_P(CreditCardFieldTest, ParseFullCreditCard) {
AddTextFormFieldData("name_on_card", "Name on Card", CREDIT_CARD_NAME_FULL);
diff --git a/chromium/components/autofill/core/browser/form_parsing/email_field.cc b/chromium/components/autofill/core/browser/form_parsing/email_field.cc
index 864642a4893..85d78a6c719 100644
--- a/chromium/components/autofill/core/browser/form_parsing/email_field.cc
+++ b/chromium/components/autofill/core/browser/form_parsing/email_field.cc
@@ -4,9 +4,9 @@
#include "components/autofill/core/browser/form_parsing/email_field.h"
-#include "components/autofill/core/browser/autofill_regex_constants.h"
#include "components/autofill/core/browser/form_parsing/autofill_scanner.h"
#include "components/autofill/core/browser/form_parsing/regex_patterns.h"
+#include "components/autofill/core/common/autofill_regex_constants.h"
namespace autofill {
@@ -30,7 +30,7 @@ std::unique_ptr<FormField> EmailField::Parse(AutofillScanner* scanner,
EmailField::EmailField(const AutofillField* field) : field_(field) {}
void EmailField::AddClassifications(
- FieldCandidatesMap* field_candidates) const {
+ FieldCandidatesMap& field_candidates) const {
AddClassification(field_, EMAIL_ADDRESS, kBaseEmailParserScore,
field_candidates);
}
diff --git a/chromium/components/autofill/core/browser/form_parsing/email_field.h b/chromium/components/autofill/core/browser/form_parsing/email_field.h
index 8fc4af8dde7..b21f21a4f86 100644
--- a/chromium/components/autofill/core/browser/form_parsing/email_field.h
+++ b/chromium/components/autofill/core/browser/form_parsing/email_field.h
@@ -28,7 +28,7 @@ class EmailField : public FormField {
EmailField& operator=(const EmailField&) = delete;
protected:
- void AddClassifications(FieldCandidatesMap* field_candidates) const override;
+ void AddClassifications(FieldCandidatesMap& field_candidates) const override;
private:
raw_ptr<const AutofillField> field_;
diff --git a/chromium/components/autofill/core/browser/form_parsing/form_field.cc b/chromium/components/autofill/core/browser/form_parsing/form_field.cc
index 9cd4d3699a9..d185d20b8a9 100644
--- a/chromium/components/autofill/core/browser/form_parsing/form_field.cc
+++ b/chromium/components/autofill/core/browser/form_parsing/form_field.cc
@@ -8,32 +8,40 @@
#include <cstddef>
#include <iterator>
#include <memory>
+#include <numeric>
#include <string>
#include <utility>
#include "base/feature_list.h"
#include "base/strings/string_piece.h"
#include "base/strings/string_util.h"
+#include "base/strings/utf_string_conversions.h"
#include "components/autofill/core/browser/autofill_field.h"
-#include "components/autofill/core/browser/autofill_regexes.h"
#include "components/autofill/core/browser/autofill_type.h"
+#include "components/autofill/core/browser/field_types.h"
#include "components/autofill/core/browser/form_parsing/address_field.h"
#include "components/autofill/core/browser/form_parsing/autofill_parsing_utils.h"
#include "components/autofill/core/browser/form_parsing/autofill_scanner.h"
+#include "components/autofill/core/browser/form_parsing/birthdate_field.h"
#include "components/autofill/core/browser/form_parsing/credit_card_field.h"
#include "components/autofill/core/browser/form_parsing/email_field.h"
+#include "components/autofill/core/browser/form_parsing/iban_field.h"
#include "components/autofill/core/browser/form_parsing/merchant_promo_code_field.h"
#include "components/autofill/core/browser/form_parsing/name_field.h"
#include "components/autofill/core/browser/form_parsing/phone_field.h"
#include "components/autofill/core/browser/form_parsing/price_field.h"
#include "components/autofill/core/browser/form_parsing/search_field.h"
+#include "components/autofill/core/browser/form_parsing/standalone_cvc_field.h"
#include "components/autofill/core/browser/form_parsing/travel_field.h"
+#include "components/autofill/core/common/autocomplete_parsing_util.h"
#include "components/autofill/core/browser/form_structure.h"
#include "components/autofill/core/browser/logging/log_manager.h"
#include "components/autofill/core/common/autofill_constants.h"
#include "components/autofill/core/common/autofill_features.h"
#include "components/autofill/core/common/autofill_internals/log_message.h"
#include "components/autofill/core/common/autofill_internals/logging_scope.h"
+#include "components/autofill/core/common/autofill_payments_features.h"
+#include "components/autofill/core/common/autofill_regexes.h"
#include "components/autofill/core/common/autofill_util.h"
namespace autofill {
@@ -47,121 +55,146 @@ constexpr bool IsEmpty(const char16_t* s) {
} // namespace
// static
-FieldCandidatesMap FormField::ParseFormFields(
+bool FormField::MatchesRegexWithCache(base::StringPiece16 input,
+ base::StringPiece16 pattern,
+ std::vector<std::u16string>* groups) {
+ // TODO(crbug.com/1309848): If ParseForm() is called from the same thread,
+ // use a thread-unsafe parser.
+ static base::NoDestructor<AutofillRegexCache> cache(ThreadSafe(true));
+ const icu::RegexPattern* regex_pattern = cache->GetRegexPattern(pattern);
+ return autofill::MatchesRegex(input, *regex_pattern, groups);
+}
+
+// static
+void FormField::ParseFormFields(
const std::vector<std::unique_ptr<AutofillField>>& fields,
const LanguageCode& page_language,
bool is_form_tag,
PatternSource pattern_source,
+ FieldCandidatesMap& field_candidates,
LogManager* log_manager) {
std::vector<AutofillField*> processed_fields = RemoveCheckableFields(fields);
- FieldCandidatesMap field_candidates;
// Email pass.
- ParseFormFieldsPass(EmailField::Parse, processed_fields, &field_candidates,
+ ParseFormFieldsPass(EmailField::Parse, processed_fields, field_candidates,
page_language, pattern_source, log_manager);
const size_t email_count = field_candidates.size();
- // Merchant promo code pass.
- ParseFormFieldsPass(MerchantPromoCodeField::Parse, processed_fields,
- &field_candidates, page_language, pattern_source,
- log_manager);
- const size_t promo_code_count = field_candidates.size() - email_count;
+ // Single fields pass.
+ ParseSingleFieldForms(fields, page_language, is_form_tag, pattern_source,
+ field_candidates, log_manager);
+ const size_t fillable_single_fields = field_candidates.size() - email_count;
// Phone pass.
- ParseFormFieldsPass(PhoneField::Parse, processed_fields, &field_candidates,
+ ParseFormFieldsPass(PhoneField::Parse, processed_fields, field_candidates,
page_language, pattern_source, log_manager);
// Travel pass.
- ParseFormFieldsPass(TravelField::Parse, processed_fields, &field_candidates,
+ ParseFormFieldsPass(TravelField::Parse, processed_fields, field_candidates,
page_language, pattern_source, log_manager);
// Address pass.
- ParseFormFieldsPass(AddressField::Parse, processed_fields, &field_candidates,
+ ParseFormFieldsPass(AddressField::Parse, processed_fields, field_candidates,
page_language, pattern_source, log_manager);
+ // Birthdate pass.
+ if (base::FeatureList::IsEnabled(features::kAutofillEnableBirthdateParsing)) {
+ ParseFormFieldsPass(BirthdateField::Parse, processed_fields,
+ field_candidates, page_language, pattern_source,
+ log_manager);
+ }
+
// Credit card pass.
ParseFormFieldsPass(CreditCardField::Parse, processed_fields,
- &field_candidates, page_language, pattern_source,
+ field_candidates, page_language, pattern_source,
log_manager);
// Price pass.
- ParseFormFieldsPass(PriceField::Parse, processed_fields, &field_candidates,
+ ParseFormFieldsPass(PriceField::Parse, processed_fields, field_candidates,
page_language, pattern_source, log_manager);
// Name pass.
- ParseFormFieldsPass(NameField::Parse, processed_fields, &field_candidates,
+ ParseFormFieldsPass(NameField::Parse, processed_fields, field_candidates,
page_language, pattern_source, log_manager);
// Search pass.
- ParseFormFieldsPass(SearchField::Parse, processed_fields, &field_candidates,
+ ParseFormFieldsPass(SearchField::Parse, processed_fields, field_candidates,
page_language, pattern_source, log_manager);
+ // Deduce `field_candidates` for the `processed_fields` by parsing their
+ // `parsable_name()` as an autocomplete attribute.
+ if (base::FeatureList::IsEnabled(
+ features::kAutofillParseNameAsAutocompleteType)) {
+ ParseUsingAutocompleteAttributes(processed_fields, field_candidates);
+ }
+
size_t fillable_fields = 0;
- if (base::FeatureList::IsEnabled(features::kAutofillFixFillableFieldTypes)) {
- for (const auto& [field_id, candidates] : field_candidates) {
- if (IsFillableFieldType(candidates.BestHeuristicType()))
- ++fillable_fields;
- }
- } else {
- fillable_fields = field_candidates.size();
+ for (const auto& [field_id, candidates] : field_candidates) {
+ if (IsFillableFieldType(candidates.BestHeuristicType()))
+ ++fillable_fields;
}
// Do not autofill a form if there aren't enough fields. Otherwise, it is
// very easy to have false positives. See http://crbug.com/447332
// For <form> tags, make an exception for email fields, which are commonly
// the only recognized field on account registration sites. Also make an
- // exception for promo code fields, which are often a single field in its own
- // form.
+ // exception for single-field Autofillable types, even when the form contains
+ // less than kMinRequiredFieldsForHeuristics fields in its form signature.
if (fillable_fields < kMinRequiredFieldsForHeuristics) {
- if ((is_form_tag && email_count > 0) || promo_code_count > 0) {
+ if ((is_form_tag && email_count > 0) || fillable_single_fields > 0) {
base::EraseIf(field_candidates, [&](const auto& candidate) {
return !(candidate.second.BestHeuristicType() == EMAIL_ADDRESS ||
- candidate.second.BestHeuristicType() == MERCHANT_PROMO_CODE);
+ FormField::IsSingleFieldParseableType(
+ candidate.second.BestHeuristicType()));
});
} else {
- if (log_manager) {
- LogBuffer table_rows;
- for (const auto& field : fields) {
- table_rows << Tr{} << "Field:" << *field;
- }
- for (const auto& [field_id, candidates] : field_candidates) {
- LogBuffer name;
- name << "Type candidate for frame and renderer ID: " << field_id;
- LogBuffer description;
- ServerFieldType field_type = candidates.BestHeuristicType();
- description << "BestHeuristicType: "
- << AutofillType::ServerFieldTypeToString(field_type)
- << ", is fillable: " << IsFillableFieldType(field_type);
- table_rows << Tr{} << std::move(name) << std::move(description);
- }
- log_manager->Log()
- << LoggingScope::kParsing
- << LogMessage::kLocalHeuristicDidNotFindEnoughFillableFields
- << Tag{"table"} << Attrib{"class", "form"} << std::move(table_rows)
- << CTag{"table"};
+ LogBuffer table_rows(IsLoggingActive(log_manager));
+ for (const auto& field : fields)
+ LOG_AF(table_rows) << Tr{} << "Field:" << *field;
+ for (const auto& [field_id, candidates] : field_candidates) {
+ LogBuffer name(IsLoggingActive(log_manager));
+ name << "Type candidate for frame and renderer ID: " << field_id;
+ LogBuffer description(IsLoggingActive(log_manager));
+ LOG_AF(description)
+ << "BestHeuristicType: "
+ << AutofillType::ServerFieldTypeToString(
+ candidates.BestHeuristicType())
+ << ", is fillable: "
+ << IsFillableFieldType(candidates.BestHeuristicType());
+ LOG_AF(table_rows) << Tr{} << std::move(name) << std::move(description);
}
+ LOG_AF(log_manager)
+ << LoggingScope::kParsing
+ << LogMessage::kLocalHeuristicDidNotFindEnoughFillableFields
+ << Tag{"table"} << Attrib{"class", "form"} << std::move(table_rows)
+ << CTag{"table"};
field_candidates.clear();
}
}
-
- return field_candidates;
}
-FieldCandidatesMap FormField::ParseFormFieldsForPromoCodes(
+void FormField::ParseSingleFieldForms(
const std::vector<std::unique_ptr<AutofillField>>& fields,
const LanguageCode& page_language,
bool is_form_tag,
PatternSource pattern_source,
+ FieldCandidatesMap& field_candidates,
LogManager* log_manager) {
std::vector<AutofillField*> processed_fields = RemoveCheckableFields(fields);
- FieldCandidatesMap field_candidates;
// Merchant promo code pass.
- ParseFormFieldsPass(MerchantPromoCodeField::Parse, processed_fields,
- &field_candidates, page_language, pattern_source,
- log_manager);
+ if (base::FeatureList::IsEnabled(
+ features::kAutofillParseMerchantPromoCodeFields)) {
+ ParseFormFieldsPass(MerchantPromoCodeField::Parse, processed_fields,
+ field_candidates, page_language, pattern_source,
+ log_manager);
+ }
- return field_candidates;
+ // IBAN pass.
+ if (base::FeatureList::IsEnabled(features::kAutofillParseIBANFields)) {
+ ParseFormFieldsPass(IBANField::Parse, processed_fields, field_candidates,
+ page_language, pattern_source, log_manager);
+ }
}
// static
@@ -244,6 +277,7 @@ bool FormField::ParseFieldSpecificsWithNewPatterns(
return false;
}
+// static
bool FormField::ParseFieldSpecifics(
AutofillScanner* scanner,
base::StringPiece16 pattern,
@@ -260,6 +294,42 @@ bool FormField::ParseFieldSpecifics(
}
// static
+bool FormField::ParseInAnyOrder(
+ AutofillScanner* scanner,
+ std::vector<std::pair<AutofillField**, base::RepeatingCallback<bool()>>>
+ fields_and_parsers) {
+ if (scanner->IsEnd())
+ return fields_and_parsers.empty();
+ auto original_pos = scanner->SaveCursor();
+ // The implementation tries matching every permutation `p` of parsers with the
+ // scanners fields. While this has a terrible runtime for general n, the only
+ // planned use cases are dates (2 or 3 components).
+ // If necessary, bipartite matching could be used for general n.
+ DCHECK(fields_and_parsers.size() <= 3);
+ std::vector<int> p(fields_and_parsers.size());
+ std::iota(p.begin(), p.end(), 0);
+ do {
+ bool matches = true;
+ for (int i : p) {
+ const auto& [field, parser] = fields_and_parsers[i];
+ if (!scanner->IsEnd() && parser.Run()) {
+ *field = scanner->Cursor();
+ scanner->Advance();
+ } else {
+ matches = false;
+ break;
+ }
+ }
+ if (matches)
+ return true;
+ scanner->RewindTo(original_pos);
+ } while (std::next_permutation(p.begin(), p.end()));
+ for (const auto& [field, _] : fields_and_parsers)
+ *field = nullptr;
+ return false;
+}
+
+// static
bool FormField::ParseEmptyLabel(AutofillScanner* scanner,
AutofillField** match) {
return ParseFieldSpecificsWithLegacyPattern(
@@ -272,12 +342,12 @@ bool FormField::ParseEmptyLabel(AutofillScanner* scanner,
void FormField::AddClassification(const AutofillField* field,
ServerFieldType type,
float score,
- FieldCandidatesMap* field_candidates) {
+ FieldCandidatesMap& field_candidates) {
// Several fields are optional.
if (field == nullptr)
return;
- FieldCandidates& candidates = (*field_candidates)[field->global_id()];
+ FieldCandidates& candidates = field_candidates[field->global_id()];
candidates.AddFieldCandidate(type, score);
}
@@ -341,19 +411,21 @@ bool FormField::Match(const AutofillField* field,
const bool match_label =
match_type.attributes.contains(MatchAttribute::kLabel);
- if (match_label && MatchesPattern(label, pattern, capture_destination)) {
+ if (match_label &&
+ MatchesRegexWithCache(label, pattern, capture_destination)) {
found_match = true;
match_type_string = "Match in label";
value = label;
} else if (match_type.attributes.contains(MatchAttribute::kName) &&
- MatchesPattern(name, pattern, capture_destination)) {
+ MatchesRegexWithCache(name, pattern, capture_destination)) {
found_match = true;
match_type_string = "Match in name";
value = name;
} else if (match_label &&
base::FeatureList::IsEnabled(
features::kAutofillConsiderPlaceholderForParsing) &&
- MatchesPattern(field->placeholder, pattern, capture_destination)) {
+ MatchesRegexWithCache(field->placeholder, pattern,
+ capture_destination)) {
// TODO(crbug.com/1317961): The label and placeholder cases should logically
// be grouped together. Placeholder is currently last, because for the finch
// study we want the group assignment to happen as late as possible.
@@ -363,15 +435,16 @@ bool FormField::Match(const AutofillField* field,
value = field->placeholder;
}
- if (found_match && logging.log_manager) {
- LogBuffer table_rows;
- table_rows << Tr{} << "Match type:" << match_type_string;
- table_rows << Tr{} << "RegEx:" << logging.regex_name;
- table_rows << Tr{} << "Value: " << HighlightValue(value, matches[0]);
+ if (found_match) {
+ LogBuffer table_rows(IsLoggingActive(logging.log_manager));
+ LOG_AF(table_rows) << Tr{} << "Match type:" << match_type_string;
+ LOG_AF(table_rows) << Tr{} << "RegEx:" << logging.regex_name;
+ LOG_AF(table_rows) << Tr{}
+ << "Value: " << HighlightValue(value, matches[0]);
// The matched substring is reported once more as the highlighting is not
// particularly copy&paste friendly.
- table_rows << Tr{} << "Matched substring: " << matches[0];
- logging.log_manager->Log()
+ LOG_AF(table_rows) << Tr{} << "Matched substring: " << matches[0];
+ LOG_AF(logging.log_manager)
<< LoggingScope::kParsing << LogMessage::kLocalHeuristicRegExMatched
<< Tag{"table"} << std::move(table_rows) << CTag{"table"};
}
@@ -382,7 +455,7 @@ bool FormField::Match(const AutofillField* field,
// static
void FormField::ParseFormFieldsPass(ParseFunction parse,
const std::vector<AutofillField*>& fields,
- FieldCandidatesMap* field_candidates,
+ FieldCandidatesMap& field_candidates,
const LanguageCode& page_language,
PatternSource pattern_source,
LogManager* log_manager) {
@@ -430,4 +503,27 @@ bool FormField::MatchesFormControlType(base::StringPiece type,
return false;
}
+// static
+bool FormField::IsSingleFieldParseableType(ServerFieldType field_type) {
+ return field_type == MERCHANT_PROMO_CODE || field_type == IBAN_VALUE ||
+ field_type == CREDIT_CARD_STANDALONE_VERIFICATION_CODE;
+}
+
+// static
+void FormField::ParseUsingAutocompleteAttributes(
+ const std::vector<AutofillField*>& fields,
+ FieldCandidatesMap& field_candidates) {
+ for (const AutofillField* field : fields) {
+ HtmlFieldType html_type = FieldTypeFromAutocompleteAttributeValue(
+ base::UTF16ToUTF8(field->parseable_name()), *field);
+ // The HTML_MODE is irrelevant when converting to a ServerFieldType.
+ ServerFieldType type =
+ AutofillType(html_type, HTML_MODE_NONE).GetStorableType();
+ if (type != UNKNOWN_TYPE) {
+ AddClassification(field, type, kBaseAutocompleteParserScore,
+ field_candidates);
+ }
+ }
+}
+
} // namespace autofill
diff --git a/chromium/components/autofill/core/browser/form_parsing/form_field.h b/chromium/components/autofill/core/browser/form_parsing/form_field.h
index 12af574a32e..6cd50974db3 100644
--- a/chromium/components/autofill/core/browser/form_parsing/form_field.h
+++ b/chromium/components/autofill/core/browser/form_parsing/form_field.h
@@ -7,8 +7,10 @@
#include <memory>
#include <string>
+#include <utility>
#include <vector>
+#include "base/callback.h"
#include "base/gtest_prod_util.h"
#include "base/memory/raw_ptr.h"
#include "base/strings/string_piece.h"
@@ -44,28 +46,45 @@ class FormField {
virtual ~FormField() = default;
// Classifies each field in |fields| with its heuristically detected type.
- // Each field has a derived unique name that is used as the key into the
- // returned FieldCandidatesMap.
- static FieldCandidatesMap ParseFormFields(
+ // Each field has a derived unique name that is used as the key into
+ // |field_candidates|.
+ static void ParseFormFields(
const std::vector<std::unique_ptr<AutofillField>>& fields,
const LanguageCode& page_language,
bool is_form_tag,
PatternSource pattern_source,
+ FieldCandidatesMap& field_candidates,
LogManager* log_manager = nullptr);
- // Looks for a promo code field in |fields|. Each field has a derived unique
- // name that is used as the key into the returned FieldCandidatesMap.
- static FieldCandidatesMap ParseFormFieldsForPromoCodes(
+ // Looks for types that are allowed to appear in solitary (such as merchant
+ // promo codes) inside |fields|. Each field has a derived unique name that is
+ // used as the key into |field_candidates|.
+ static void ParseSingleFieldForms(
const std::vector<std::unique_ptr<AutofillField>>& fields,
const LanguageCode& page_language,
bool is_form_tag,
PatternSource pattern_source,
+ FieldCandidatesMap& field_candidates,
LogManager* log_manager = nullptr);
#if defined(UNIT_TEST)
+ static bool MatchForTesting(const AutofillField* field,
+ base::StringPiece16 pattern,
+ MatchParams match_type,
+ const RegExLogging& logging = {}) {
+ return FormField::Match(field, pattern, match_type, logging);
+ }
+
+ static bool ParseInAnyOrderForTesting(
+ AutofillScanner* scanner,
+ std::vector<std::pair<AutofillField**, base::RepeatingCallback<bool()>>>
+ fields_and_parsers) {
+ return FormField::ParseInAnyOrder(scanner, fields_and_parsers);
+ }
+
// Assign types to the fields for the testing purposes.
void AddClassificationsForTesting(
- FieldCandidatesMap* field_candidates_for_testing) const {
+ FieldCandidatesMap& field_candidates_for_testing) const {
AddClassifications(field_candidates_for_testing);
}
#endif
@@ -74,23 +93,33 @@ class FormField {
// Initial values assigned to FieldCandidates by their corresponding parsers.
// There's an implicit precedence determined by the values assigned here.
// Email is currently the most important followed by Phone, Travel, Address,
- // Credit Card, Price, Name, Merchant promo code, and Search.
+ // Birthdate, Credit Card, IBAN, Price, Name, Merchant promo code, and Search.
static constexpr float kBaseEmailParserScore = 1.4f;
static constexpr float kBasePhoneParserScore = 1.3f;
static constexpr float kBaseTravelParserScore = 1.2f;
static constexpr float kBaseAddressParserScore = 1.1f;
+ static constexpr float kBaseBirthdateParserScore = 1.05f;
static constexpr float kBaseCreditCardParserScore = 1.0f;
+ static constexpr float kBaseIBANParserScore = 0.975f;
static constexpr float kBasePriceParserScore = 0.95f;
static constexpr float kBaseNameParserScore = 0.9f;
static constexpr float kBaseMerchantPromoCodeParserScore = 0.85f;
static constexpr float kBaseSearchParserScore = 0.8f;
+ static constexpr float kBaseAutocompleteParserScore = 0.05f;
// Only derived classes may instantiate.
FormField() = default;
+ // Calls MatchesRegex() with a thread-safe cache.
+ // Should not be called from the UI thread as it may be blocked on a worker
+ // thread.
+ static bool MatchesRegexWithCache(
+ base::StringPiece16 input,
+ base::StringPiece16 pattern,
+ std::vector<std::u16string>* groups = nullptr);
+
// Attempts to parse a form field with the given pattern. Returns true on
// success and fills |match| with a pointer to the field.
-
static bool ParseField(AutofillScanner* scanner,
base::StringPiece16 pattern,
base::span<const MatchPatternRef> patterns,
@@ -111,29 +140,41 @@ class FormField {
// on success and fills |match| with a pointer to the field.
static bool ParseEmptyLabel(AutofillScanner* scanner, AutofillField** match);
+ // Attempts to parse several fields using the specified parsing functions in
+ // arbitrary order. This is useful e.g. when parsing dates, where both dd/mm
+ // and mm/dd makes sense.
+ // Returns true if all fields were parsed successfully. In this case, the
+ // fields are assigned with the matching ones.
+ // If no order is matched every parser, false is returned, all fields are
+ // reset to nullptr and the scanner is rewound to it's original position.
+ static bool ParseInAnyOrder(
+ AutofillScanner* scanner,
+ std::vector<std::pair<AutofillField**, base::RepeatingCallback<bool()>>>
+ fields_and_parsers);
+
// Adds an association between a |field| and a |type| into |field_candidates|.
// This association is weighted by |score|, the higher the stronger the
// association.
static void AddClassification(const AutofillField* field,
ServerFieldType type,
float score,
- FieldCandidatesMap* field_candidates);
+ FieldCandidatesMap& field_candidates);
// Returns true iff |type| matches |match_type|.
static bool MatchesFormControlType(base::StringPiece type,
DenseSet<MatchFieldType> match_type);
+ // Returns true if |field_type| is a single field parseable type.
+ static bool IsSingleFieldParseableType(ServerFieldType field_type);
+
// Derived classes must implement this interface to supply field type
// information. |ParseFormFields| coordinates the parsing and extraction
// of types from an input vector of |AutofillField| objects and delegates
// the type extraction via this method.
virtual void AddClassifications(
- FieldCandidatesMap* field_candidates) const = 0;
+ FieldCandidatesMap& field_candidates) const = 0;
private:
- FRIEND_TEST_ALL_PREFIXES(FormFieldTest, Match);
- FRIEND_TEST_ALL_PREFIXES(FormFieldTest, TestParseableLabels);
-
// Function pointer type for the parsing function that should be passed to the
// ParseFormFieldsPass() helper function.
typedef std::unique_ptr<FormField> ParseFunction(
@@ -190,10 +231,16 @@ class FormField {
// |field_candidates|.
static void ParseFormFieldsPass(ParseFunction parse,
const std::vector<AutofillField*>& fields,
- FieldCandidatesMap* field_candidates,
+ FieldCandidatesMap& field_candidates,
const LanguageCode& page_language,
PatternSource pattern_source,
LogManager* log_manager);
+
+ // Interpret the fields' `parsable_name()` (id or name attribute) as an
+ // autocomplete type and classify them by it. E.g. <input id=given-name>.
+ static void ParseUsingAutocompleteAttributes(
+ const std::vector<AutofillField*>& fields,
+ FieldCandidatesMap& field_candidates);
};
} // namespace autofill
diff --git a/chromium/components/autofill/core/browser/form_parsing/form_field_unittest.cc b/chromium/components/autofill/core/browser/form_parsing/form_field_unittest.cc
index 60c40e83b39..0199d105e3d 100644
--- a/chromium/components/autofill/core/browser/form_parsing/form_field_unittest.cc
+++ b/chromium/components/autofill/core/browser/form_parsing/form_field_unittest.cc
@@ -9,304 +9,303 @@
#include "base/strings/utf_string_conversions.h"
#include "base/test/scoped_feature_list.h"
#include "components/autofill/core/browser/autofill_field.h"
+#include "components/autofill/core/browser/form_parsing/autofill_scanner.h"
#include "components/autofill/core/browser/form_parsing/buildflags.h"
#include "components/autofill/core/browser/form_parsing/form_field.h"
+#include "components/autofill/core/browser/form_parsing/parsing_test_utils.h"
#include "components/autofill/core/browser/form_structure.h"
#include "components/autofill/core/common/autofill_features.h"
#include "components/autofill/core/common/autofill_payments_features.h"
+#include "testing/gmock/include/gmock/gmock-matchers.h"
#include "testing/gtest/include/gtest/gtest.h"
-using autofill::features::kAutofillFixFillableFieldTypes;
-
namespace autofill {
-namespace {
-FieldRendererId MakeFieldRendererId() {
- static uint64_t id_counter_ = 0;
- return FieldRendererId(++id_counter_);
-}
-
-// Sets both the field label and parseable label to |label|.
-void SetFieldLabels(AutofillField* field, const std::u16string& label) {
- field->label = label;
- field->set_parseable_label(label);
-}
-
-} // namespace
-
class FormFieldTest
- : public testing::TestWithParam<std::tuple<bool, PatternSource>> {
+ : public FormFieldTestBase,
+ public ::testing::TestWithParam<PatternProviderFeatureState> {
public:
- FormFieldTest() {
- scoped_feature_list_.InitWithFeatureState(
- features::kAutofillParsingPatternProvider,
- enable_parsing_pattern_provider());
- }
+ FormFieldTest() : FormFieldTestBase(GetParam()) {}
FormFieldTest(const FormFieldTest&) = delete;
FormFieldTest& operator=(const FormFieldTest&) = delete;
- ~FormFieldTest() override = default;
- bool enable_parsing_pattern_provider() const {
- return std::get<0>(GetParam());
+ protected:
+ // Parses all added fields using `ParseFormFields`.
+ // Returns the number of fields parsed.
+ int ParseFormFields() {
+ FormField::ParseFormFields(list_, LanguageCode(""),
+ /*is_form_tag=*/true, GetActivePatternSource(),
+ field_candidates_map_,
+ /*log_manager=*/nullptr);
+ return field_candidates_map_.size();
}
- PatternSource pattern_source() const { return std::get<1>(GetParam()); }
+ // Like `ParseFormFields()`, but using `ParseSingleFieldForms()` instead.
+ int ParseSingleFieldForms() {
+ FormField::ParseSingleFieldForms(
+ list_, LanguageCode(""),
+ /*is_form_tag=*/true, GetActivePatternSource(), field_candidates_map_);
+ return field_candidates_map_.size();
+ }
- private:
- base::test::ScopedFeatureList scoped_feature_list_;
+ // FormFieldTestBase:
+ // This function is unused in these unit tests, because FormField is not a
+ // parser itself, but the infrastructure combining them.
+ std::unique_ptr<FormField> Parse(AutofillScanner* scanner,
+ const LanguageCode& page_language) override {
+ return nullptr;
+ }
+};
+
+INSTANTIATE_TEST_SUITE_P(
+ FormFieldTest,
+ FormFieldTest,
+ ::testing::ValuesIn(PatternProviderFeatureState::All()));
+
+struct MatchTestCase {
+ std::u16string label;
+ std::vector<std::u16string> positive_patterns;
+ std::vector<std::u16string> negative_patterns;
};
+class MatchTest : public testing::TestWithParam<MatchTestCase> {};
+
+const MatchTestCase kMatchTestCases[]{
+ // Empty strings match empty patterns, but not non-empty ones.
+ {u"", {u"", u"^$"}, {u"a"}},
+ // Non-empty strings don't match empty patterns.
+ {u"a", {u""}, {u"^$"}},
+ // Beginning and end of the line and exact matches.
+ {u"head_tail",
+ {u"^head", u"tail$", u"^head_tail$"},
+ {u"head$", u"^tail", u"^head$", u"^tail$"}},
+ // Escaped dots.
+ // Note: The unescaped "." characters are wild cards.
+ {u"m.i.", {u"m.i.", u"m\\.i\\."}},
+ {u"mXiX", {u"m.i."}, {u"m\\.i\\."}},
+ // Repetition.
+ {u"headtail", {u"head.*tail"}, {u"head.+tail"}},
+ {u"headXtail", {u"head.*tail", u"head.+tail"}},
+ {u"headXXXtail", {u"head.*tail", u"head.+tail"}},
+ // Alternation.
+ {u"head_tail", {u"head|other", u"tail|other"}, {u"bad|good"}},
+ // Case sensitivity.
+ {u"xxxHeAd_tAiLxxx", {u"head_tail"}},
+ // Word boundaries.
+ {u"contains word:", {u"\\bword\\b"}, {u"\\bcon\\b"}},
+ // Make sure the circumflex in 'crêpe' is not treated as a word boundary.
+ {u"crêpe", {}, {u"\\bcr\\b"}}};
+
INSTANTIATE_TEST_SUITE_P(FormFieldTest,
- FormFieldTest,
- ::testing::Combine(::testing::Bool(),
- ::testing::Values(
-#if BUILDFLAG(USE_INTERNAL_AUTOFILL_HEADERS)
- PatternSource::kDefault,
- PatternSource::kExperimental,
- PatternSource::kNextGen,
-#endif
- PatternSource::kLegacy)));
-
-TEST_P(FormFieldTest, Match) {
- constexpr MatchParams kMatchLabel{{MatchAttribute::kLabel}, {}};
+ MatchTest,
+ testing::ValuesIn(kMatchTestCases));
+TEST_P(MatchTest, Match) {
+ const auto& [label, positive_patterns, negative_patterns] = GetParam();
+ constexpr MatchParams kMatchLabel{{MatchAttribute::kLabel}, {}};
AutofillField field;
-
- // Empty strings match.
- EXPECT_TRUE(FormField::Match(&field, std::u16string(), kMatchLabel));
-
- // Empty pattern matches non-empty string.
- SetFieldLabels(&field, u"a");
- EXPECT_TRUE(FormField::Match(&field, std::u16string(), kMatchLabel));
-
- // Strictly empty pattern matches empty string.
- SetFieldLabels(&field, u"");
- EXPECT_TRUE(FormField::Match(&field, u"^$", kMatchLabel));
-
- // Strictly empty pattern does not match non-empty string.
- SetFieldLabels(&field, u"a");
- EXPECT_FALSE(FormField::Match(&field, u"^$", kMatchLabel));
-
- // Non-empty pattern doesn't match empty string.
- SetFieldLabels(&field, u"");
- EXPECT_FALSE(FormField::Match(&field, u"a", kMatchLabel));
-
- // Beginning of line.
- SetFieldLabels(&field, u"head_tail");
- EXPECT_TRUE(FormField::Match(&field, u"^head", kMatchLabel));
- EXPECT_FALSE(FormField::Match(&field, u"^tail", kMatchLabel));
-
- // End of line.
- SetFieldLabels(&field, u"head_tail");
- EXPECT_FALSE(FormField::Match(&field, u"head$", kMatchLabel));
- EXPECT_TRUE(FormField::Match(&field, u"tail$", kMatchLabel));
-
- // Exact.
- SetFieldLabels(&field, u"head_tail");
- EXPECT_FALSE(FormField::Match(&field, u"^head$", kMatchLabel));
- EXPECT_FALSE(FormField::Match(&field, u"^tail$", kMatchLabel));
- EXPECT_TRUE(FormField::Match(&field, u"^head_tail$", kMatchLabel));
-
- // Escaped dots.
- SetFieldLabels(&field, u"m.i.");
- // Note: This pattern is misleading as the "." characters are wild cards.
- EXPECT_TRUE(FormField::Match(&field, u"m.i.", kMatchLabel));
- EXPECT_TRUE(FormField::Match(&field, u"m\\.i\\.", kMatchLabel));
- SetFieldLabels(&field, u"mXiX");
- EXPECT_TRUE(FormField::Match(&field, u"m.i.", kMatchLabel));
- EXPECT_FALSE(FormField::Match(&field, u"m\\.i\\.", kMatchLabel));
-
- // Repetition.
- SetFieldLabels(&field, u"headtail");
- EXPECT_TRUE(FormField::Match(&field, u"head.*tail", kMatchLabel));
- SetFieldLabels(&field, u"headXtail");
- EXPECT_TRUE(FormField::Match(&field, u"head.*tail", kMatchLabel));
- SetFieldLabels(&field, u"headXXXtail");
- EXPECT_TRUE(FormField::Match(&field, u"head.*tail", kMatchLabel));
- SetFieldLabels(&field, u"headtail");
- EXPECT_FALSE(FormField::Match(&field, u"head.+tail", kMatchLabel));
- SetFieldLabels(&field, u"headXtail");
- EXPECT_TRUE(FormField::Match(&field, u"head.+tail", kMatchLabel));
- SetFieldLabels(&field, u"headXXXtail");
- EXPECT_TRUE(FormField::Match(&field, u"head.+tail", kMatchLabel));
-
- // Alternation.
- SetFieldLabels(&field, u"head_tail");
- EXPECT_TRUE(FormField::Match(&field, u"head|other", kMatchLabel));
- EXPECT_TRUE(FormField::Match(&field, u"tail|other", kMatchLabel));
- EXPECT_FALSE(FormField::Match(&field, u"bad|good", kMatchLabel));
-
- // Case sensitivity.
- SetFieldLabels(&field, u"xxxHeAd_tAiLxxx");
- EXPECT_TRUE(FormField::Match(&field, u"head_tail", kMatchLabel));
-
- // Word boundaries.
- SetFieldLabels(&field, u"contains word:");
- EXPECT_TRUE(FormField::Match(&field, u"\\bword\\b", kMatchLabel));
- EXPECT_FALSE(FormField::Match(&field, u"\\bcon\\b", kMatchLabel));
- // Make sure the circumflex in 'crêpe' is not treated as a word boundary.
- field.label = u"crêpe";
- EXPECT_FALSE(FormField::Match(&field, u"\\bcr\\b", kMatchLabel));
+ SCOPED_TRACE("label = " + base::UTF16ToUTF8(label));
+ field.label = label;
+ field.set_parseable_label(label);
+ for (const auto& pattern : positive_patterns) {
+ SCOPED_TRACE("positive_pattern = " + base::UTF16ToUTF8(pattern));
+ EXPECT_TRUE(FormField::MatchForTesting(&field, pattern, kMatchLabel));
+ }
+ for (const auto& pattern : negative_patterns) {
+ SCOPED_TRACE("negative_pattern = " + base::UTF16ToUTF8(pattern));
+ EXPECT_FALSE(FormField::MatchForTesting(&field, pattern, kMatchLabel));
+ }
}
// Test that we ignore checkable elements.
-TEST_P(FormFieldTest, ParseFormFields) {
- std::vector<std::unique_ptr<AutofillField>> fields;
- FormFieldData field_data;
- field_data.form_control_type = "text";
-
- field_data.check_status = FormFieldData::CheckStatus::kCheckableButUnchecked;
- field_data.label = u"Is PO Box";
- field_data.unique_renderer_id = MakeFieldRendererId();
- fields.push_back(std::make_unique<AutofillField>(field_data));
-
- // Does not parse since there are only field and it's checkable.
- // An empty page_language means the language is unknown and patterns of all
- // languages are used.
- EXPECT_TRUE(FormField::ParseFormFields(fields, LanguageCode(""),
- /*is_form_tag=*/true, pattern_source(),
- /*log_manager=*/nullptr)
- .empty());
-
- // reset |is_checkable| to false.
- field_data.check_status = FormFieldData::CheckStatus::kNotCheckable;
- field_data.label = u"Address line1";
- field_data.unique_renderer_id = MakeFieldRendererId();
- fields.push_back(std::make_unique<AutofillField>(field_data));
-
- // Parse a single address line 1 field.
- ASSERT_EQ(0u,
- FormField::ParseFormFields(fields, LanguageCode(""),
- /*is_form_tag=*/true, pattern_source(),
- /*log_manager=*/nullptr)
- .size());
-
- // Parses address line 1 and 2.
- field_data.label = u"Address line2";
- field_data.unique_renderer_id = MakeFieldRendererId();
- fields.push_back(std::make_unique<AutofillField>(field_data));
-
- // An empty page_language means the language is unknown and patterns of
- // all languages are used.
- ASSERT_EQ(0u,
- FormField::ParseFormFields(fields, LanguageCode(""),
- /*is_form_tag=*/true, pattern_source(),
- /*log_manager=*/nullptr)
- .size());
+TEST_P(FormFieldTest, ParseFormFieldsIgnoreCheckableElements) {
+ AddFormFieldData("checkbox", "", "Is PO Box", UNKNOWN_TYPE);
+ // Add 3 dummy fields to reach kMinRequiredFieldsForHeuristics = 3.
+ AddTextFormFieldData("", "Address line 1", ADDRESS_HOME_LINE1);
+ AddTextFormFieldData("", "Address line 2", ADDRESS_HOME_LINE2);
+ AddTextFormFieldData("", "Address line 3", ADDRESS_HOME_LINE3);
+ EXPECT_EQ(3, ParseFormFields());
+ TestClassificationExpectations();
}
// Test that the minimum number of required fields for the heuristics considers
// whether a field is actually fillable.
-TEST_P(FormFieldTest, ParseFormFieldEnforceMinFillableFields) {
- std::vector<std::unique_ptr<AutofillField>> fields;
- FormFieldData field_data;
- field_data.form_control_type = "text";
-
- field_data.label = u"Address line 1";
- field_data.unique_renderer_id = MakeFieldRendererId();
- fields.push_back(std::make_unique<AutofillField>(field_data));
-
- field_data.label = u"Address line 2";
- field_data.unique_renderer_id = MakeFieldRendererId();
- fields.push_back(std::make_unique<AutofillField>(field_data));
-
- // Don't parse forms with 2 fields.
- // An empty page_language means the language is unknown and patterns of all
- // languages are used.
- EXPECT_EQ(0u,
- FormField::ParseFormFields(fields, LanguageCode(""),
- /*is_form_tag=*/true, pattern_source(),
- /*log_manager=*/nullptr)
- .size());
-
- field_data.label = u"Search";
- field_data.unique_renderer_id = MakeFieldRendererId();
- fields.push_back(std::make_unique<AutofillField>(field_data));
-
- // Before the fix in kAutofillFixFillableFieldTypes, we would parse the form
- // now, although a search field is not fillable.
- {
- base::test::ScopedFeatureList feature_list;
- feature_list.InitAndDisableFeature(kAutofillFixFillableFieldTypes);
- // An empty page_language means the language is unknown and patterns of all
- // languages are used.
- EXPECT_EQ(3u, FormField::ParseFormFields(
- fields, LanguageCode(""), /*is_form_tag=*/true,
- pattern_source(), /*log_manager=*/nullptr)
- .size());
- }
+TEST_P(FormFieldTest, ParseFormFieldsEnforceMinFillableFields) {
+ AddTextFormFieldData("", "Address line 1", ADDRESS_HOME_LINE1);
+ AddTextFormFieldData("", "Address line 2", ADDRESS_HOME_LINE2);
+ AddTextFormFieldData("", "Search", SEARCH_TERM);
+ // We don't parse the form because search fields are not fillable (therefore,
+ // the form has only 2 fillable fields).
+ EXPECT_EQ(0, ParseFormFields());
+}
- // With the fix, we don't parse the form because search fields are not
- // fillable (therefore, the form has only 2 fillable fields).
- {
- base::test::ScopedFeatureList feature_list;
- feature_list.InitAndEnableFeature(kAutofillFixFillableFieldTypes);
- // An empty page_language means the language is unknown and patterns of all
- // languages are used.
- const FieldCandidatesMap field_candidates_map = FormField::ParseFormFields(
- fields, LanguageCode(""), /*is_form_tag=*/true, pattern_source(),
- /*log_manager=*/nullptr);
- EXPECT_EQ(0u, FormField::ParseFormFields(
- fields, LanguageCode(""), /*is_form_tag=*/true,
- pattern_source(), /*log_manager=*/nullptr)
- .size());
- }
+// Tests that the `parseable_name()` is parsed as an autocomplete type.
+TEST_P(FormFieldTest, ParseNameAsAutocompleteType) {
+ base::test::ScopedFeatureList autocomplete_feature;
+ autocomplete_feature.InitAndEnableFeature(
+ features::kAutofillParseNameAsAutocompleteType);
+
+ AddTextFormFieldData("given-name", "", NAME_FIRST);
+ AddTextFormFieldData("family-name", "", NAME_LAST);
+ AddTextFormFieldData("cc-exp-month", "", CREDIT_CARD_EXP_MONTH);
+ // The label is not parsed as an autocomplete type.
+ AddTextFormFieldData("", "cc-exp-month", UNKNOWN_TYPE);
+ EXPECT_EQ(3, ParseFormFields());
+ TestClassificationExpectations();
}
// Test that the parseable label is used when the feature is enabled.
TEST_P(FormFieldTest, TestParseableLabels) {
- FormFieldData field_data;
- field_data.form_control_type = "text";
-
- field_data.label = u"not a parseable label";
- field_data.unique_renderer_id = MakeFieldRendererId();
- auto autofill_field = std::make_unique<AutofillField>(field_data);
+ AddTextFormFieldData("", "not a parseable label", UNKNOWN_TYPE);
+ AutofillField* autofill_field = list_.back().get();
autofill_field->set_parseable_label(u"First Name");
+
+ constexpr MatchParams kMatchLabel{{MatchAttribute::kLabel}, {}};
{
base::test::ScopedFeatureList feature_list;
feature_list.InitAndEnableFeature(
features::kAutofillEnableSupportForParsingWithSharedLabels);
- EXPECT_TRUE(FormField::Match(autofill_field.get(), u"First Name",
- MatchParams({MatchAttribute::kLabel}, {})));
+ EXPECT_TRUE(
+ FormField::MatchForTesting(autofill_field, u"First Name", kMatchLabel));
}
{
base::test::ScopedFeatureList feature_list;
feature_list.InitAndDisableFeature(
features::kAutofillEnableSupportForParsingWithSharedLabels);
- EXPECT_FALSE(FormField::Match(autofill_field.get(), u"First Name",
- MatchParams({MatchAttribute::kLabel}, {})));
+ EXPECT_FALSE(
+ FormField::MatchForTesting(autofill_field, u"First Name", kMatchLabel));
}
}
-// Test that |ParseFormFieldsForPromoCodes| parses single field promo codes.
-TEST_P(FormFieldTest, ParseFormFieldsForPromoCodes) {
+// Tests that `ParseSingleFieldForms` is called as part of `ParseFormFields`.
+TEST_P(FormFieldTest, ParseSingleFieldFormsInsideParseFormField) {
base::test::ScopedFeatureList scoped_feature;
scoped_feature.InitAndEnableFeature(
features::kAutofillParseMerchantPromoCodeFields);
- std::vector<std::unique_ptr<AutofillField>> fields;
- FormFieldData field_data;
- field_data.form_control_type = "text";
+ AddTextFormFieldData("", "Phone", PHONE_HOME_WHOLE_NUMBER);
+ AddTextFormFieldData("", "Email", EMAIL_ADDRESS);
+ AddTextFormFieldData("", "Promo code", MERCHANT_PROMO_CODE);
+
+ // `ParseSingleFieldForms` should detect the promo code.
+ EXPECT_EQ(3, ParseFormFields());
+ TestClassificationExpectations();
+}
+
+// Test that `ParseSingleFieldForms` parses single field promo codes.
+TEST_P(FormFieldTest, ParseFormFieldsForSingleFieldPromoCode) {
+ base::test::ScopedFeatureList scoped_feature;
+ scoped_feature.InitAndEnableFeature(
+ features::kAutofillParseMerchantPromoCodeFields);
// Parse single field promo code.
- field_data.label = u"Promo code";
- field_data.unique_renderer_id = MakeFieldRendererId();
- fields.push_back(std::make_unique<AutofillField>(field_data));
+ AddTextFormFieldData("", "Promo code", MERCHANT_PROMO_CODE);
+ EXPECT_EQ(1, ParseSingleFieldForms());
+ TestClassificationExpectations();
- EXPECT_EQ(
- 1u, FormField::ParseFormFieldsForPromoCodes(
- fields, LanguageCode(""), /*is_form_tag=*/true, pattern_source())
- .size());
+ // Don't parse other fields.
+ // UNKNOWN_TYPE is used as the expected type, which prevents it from being
+ // part of the expectations in `TestClassificationExpectations()`.
+ AddTextFormFieldData("", "Address line 1", UNKNOWN_TYPE);
+ EXPECT_EQ(1, ParseSingleFieldForms());
+ TestClassificationExpectations();
+}
+
+// Test that `ParseSingleFieldForms` parses single field IBAN.
+TEST_P(FormFieldTest, ParseSingleFieldFormsIban) {
+ base::test::ScopedFeatureList scoped_feature;
+ scoped_feature.InitAndEnableFeature(features::kAutofillParseIBANFields);
+
+ // Parse single field IBAN.
+ AddTextFormFieldData("", "IBAN", IBAN_VALUE);
+ EXPECT_EQ(1, ParseSingleFieldForms());
+ TestClassificationExpectations();
// Don't parse other fields.
- field_data.label = u"Address line 1";
- field_data.unique_renderer_id = MakeFieldRendererId();
- fields.push_back(std::make_unique<AutofillField>(field_data));
-
- // Still only the promo code field should be parsed.
- EXPECT_EQ(
- 1u, FormField::ParseFormFieldsForPromoCodes(
- fields, LanguageCode(""), /*is_form_tag=*/true, pattern_source())
- .size());
+ // UNKNOWN_TYPE is used as the expected type, which prevents it from being
+ // part of the expectations in `TestClassificationExpectations()`.
+ AddTextFormFieldData("", "Address line 1", UNKNOWN_TYPE);
+ EXPECT_EQ(1, ParseSingleFieldForms());
+ TestClassificationExpectations();
+}
+
+struct ParseInAnyOrderTestcase {
+ // An nxn matrix, describing that field i is matched by parser j.
+ std::vector<std::vector<bool>> field_matches_parser;
+ // The expected order in which the n fields are matched, or empty, if the
+ // matching is expected to fail.
+ std::vector<int> expected_permutation;
+};
+
+class ParseInAnyOrderTest
+ : public testing::TestWithParam<ParseInAnyOrderTestcase> {};
+
+const ParseInAnyOrderTestcase kParseInAnyOrderTestcases[]{
+ // Field i is only matched by parser i -> matched in order.
+ {{{true, false, false}, {false, true, false}, {false, false, true}},
+ {0, 1, 2}},
+ // Opposite order.
+ {{{false, true}, {true, false}}, {1, 0}},
+ // The second field has to go first, because it is only matched by the first
+ // parser.
+ {{{true, true}, {true, false}}, {1, 0}},
+ // The second parser doesn't match any field, thus no match.
+ {{{true, false}, {true, false}}, {}},
+ // No field matches.
+ {{{false, false}, {false, false}}, {}}};
+
+INSTANTIATE_TEST_SUITE_P(FormFieldTest,
+ ParseInAnyOrderTest,
+ testing::ValuesIn(kParseInAnyOrderTestcases));
+
+TEST_P(ParseInAnyOrderTest, ParseInAnyOrder) {
+ auto testcase = GetParam();
+ bool expect_success = !testcase.expected_permutation.empty();
+ size_t n = testcase.field_matches_parser.size();
+
+ std::vector<std::unique_ptr<AutofillField>> fields;
+ // Creates n fields and encodes their ids in `max_length`, as `id_attribute`
+ // is a string.
+ for (size_t i = 0; i < n; i++) {
+ FormFieldData form_field_data;
+ form_field_data.max_length = i;
+ fields.push_back(std::make_unique<AutofillField>(form_field_data));
+ }
+
+ // Checks if `matching_ids` of the `scanner`'s current position is true.
+ // This is used to simulate different parsers, as described by
+ // `testcase.field_matches_parser`.
+ auto Matches = [](AutofillScanner* scanner,
+ const std::vector<bool>& matching_ids) -> bool {
+ return matching_ids[scanner->Cursor()->max_length];
+ };
+
+ // Construct n parsers from `testcase.field_matches_parser`.
+ AutofillScanner scanner(fields);
+ std::vector<AutofillField*> matched_fields(n);
+ std::vector<std::pair<AutofillField**, base::RepeatingCallback<bool()>>>
+ fields_and_parsers;
+ for (size_t i = 0; i < n; i++) {
+ fields_and_parsers.emplace_back(
+ &matched_fields[i],
+ base::BindRepeating(Matches, &scanner,
+ testcase.field_matches_parser[i]));
+ }
+
+ EXPECT_EQ(FormField::ParseInAnyOrderForTesting(&scanner, fields_and_parsers),
+ expect_success);
+
+ if (expect_success) {
+ EXPECT_TRUE(scanner.IsEnd());
+ ASSERT_EQ(testcase.expected_permutation.size(), n);
+ for (size_t i = 0; i < n; i++) {
+ EXPECT_EQ(matched_fields[i],
+ fields[testcase.expected_permutation[i]].get());
+ }
+ } else {
+ EXPECT_EQ(scanner.CursorPosition(), 0u);
+ EXPECT_THAT(matched_fields, ::testing::Each(nullptr));
+ }
}
+
} // namespace autofill
diff --git a/chromium/components/autofill/core/browser/form_parsing/iban_field.cc b/chromium/components/autofill/core/browser/form_parsing/iban_field.cc
new file mode 100644
index 00000000000..deff52803d1
--- /dev/null
+++ b/chromium/components/autofill/core/browser/form_parsing/iban_field.cc
@@ -0,0 +1,42 @@
+// Copyright 2022 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/form_parsing/iban_field.h"
+
+#include "components/autofill/core/browser/autofill_field.h"
+#include "components/autofill/core/common/autofill_regex_constants.h"
+#include "components/autofill/core/browser/form_parsing/autofill_scanner.h"
+#include "components/autofill/core/common/autofill_payments_features.h"
+
+namespace autofill {
+
+// static
+std::unique_ptr<FormField> IBANField::Parse(AutofillScanner* scanner,
+ const LanguageCode& page_language,
+ PatternSource pattern_source,
+ LogManager* log_manager) {
+ if (!base::FeatureList::IsEnabled(features::kAutofillParseIBANFields))
+ return nullptr;
+
+ AutofillField* field;
+ base::span<const MatchPatternRef> iban_patterns =
+ GetMatchPatterns(IBAN_VALUE, page_language, pattern_source);
+
+ if (ParseFieldSpecifics(scanner, kIBANRe,
+ kDefaultMatchParamsWith<MatchFieldType::kNumber,
+ MatchFieldType::kTextArea>,
+ iban_patterns, &field, {log_manager, "kIBANRe"})) {
+ return std::make_unique<IBANField>(field);
+ }
+
+ return nullptr;
+}
+
+IBANField::IBANField(const AutofillField* field) : field_(field) {}
+
+void IBANField::AddClassifications(FieldCandidatesMap& field_candidates) const {
+ AddClassification(field_, IBAN_VALUE, kBaseIBANParserScore, field_candidates);
+}
+
+} // namespace autofill
diff --git a/chromium/components/autofill/core/browser/form_parsing/iban_field.h b/chromium/components/autofill/core/browser/form_parsing/iban_field.h
new file mode 100644
index 00000000000..d8b433961b2
--- /dev/null
+++ b/chromium/components/autofill/core/browser/form_parsing/iban_field.h
@@ -0,0 +1,42 @@
+// Copyright 2022 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_FORM_PARSING_IBAN_FIELD_H_
+#define COMPONENTS_AUTOFILL_CORE_BROWSER_FORM_PARSING_IBAN_FIELD_H_
+
+#include <memory>
+
+#include "base/memory/raw_ptr.h"
+#include "components/autofill/core/browser/form_parsing/form_field.h"
+#include "components/autofill/core/common/language_code.h"
+
+namespace autofill {
+
+class AutofillField;
+class AutofillScanner;
+class LogManager;
+
+// A form field that accepts International Bank Account Number (IBAN).
+class IBANField : public FormField {
+ public:
+ static std::unique_ptr<FormField> Parse(AutofillScanner* scanner,
+ const LanguageCode& page_language,
+ PatternSource pattern_source,
+ LogManager* log_manager);
+
+ explicit IBANField(const AutofillField* field);
+
+ IBANField(const IBANField&) = delete;
+ IBANField& operator=(const IBANField&) = delete;
+
+ protected:
+ void AddClassifications(FieldCandidatesMap& field_candidates) const override;
+
+ private:
+ raw_ptr<const AutofillField> field_;
+};
+
+} // namespace autofill
+
+#endif // COMPONENTS_AUTOFILL_CORE_BROWSER_FORM_PARSING_IBAN_FIELD_H_
diff --git a/chromium/components/autofill/core/browser/form_parsing/iban_field_unittest.cc b/chromium/components/autofill/core/browser/form_parsing/iban_field_unittest.cc
new file mode 100644
index 00000000000..f5a39d16071
--- /dev/null
+++ b/chromium/components/autofill/core/browser/form_parsing/iban_field_unittest.cc
@@ -0,0 +1,68 @@
+// Copyright 2022 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/form_parsing/iban_field.h"
+
+#include "base/test/scoped_feature_list.h"
+#include "components/autofill/core/browser/form_parsing/parsing_test_utils.h"
+#include "components/autofill/core/common/autofill_payments_features.h"
+
+namespace autofill {
+
+class IBANFieldTest
+ : public FormFieldTestBase,
+ public testing::TestWithParam<PatternProviderFeatureState> {
+ public:
+ IBANFieldTest() : FormFieldTestBase(GetParam()) {}
+ IBANFieldTest(const IBANFieldTest&) = delete;
+ IBANFieldTest& operator=(const IBANFieldTest&) = delete;
+
+ void SetUp() override {
+ scoped_feature_list_.InitAndEnableFeature(
+ features::kAutofillParseIBANFields);
+ }
+
+ protected:
+ std::unique_ptr<FormField> Parse(
+ AutofillScanner* scanner,
+ const LanguageCode& page_language = LanguageCode("en")) override {
+ return IBANField::Parse(scanner, page_language, GetActivePatternSource(),
+ /*log_manager=*/nullptr);
+ }
+
+ base::test::ScopedFeatureList scoped_feature_list_;
+};
+
+INSTANTIATE_TEST_SUITE_P(
+ IBANFieldTest,
+ IBANFieldTest,
+ ::testing::ValuesIn(PatternProviderFeatureState::All()));
+
+// Match IBAN
+TEST_P(IBANFieldTest, ParseIban) {
+ AddTextFormFieldData("iban-field", "Enter account number", IBAN_VALUE);
+
+ ClassifyAndVerify(ParseResult::PARSED);
+}
+
+TEST_P(IBANFieldTest, ParseIbanBanks) {
+ AddTextFormFieldData("accountNumber", "IBAN*", IBAN_VALUE);
+
+ ClassifyAndVerify(ParseResult::PARSED);
+}
+
+TEST_P(IBANFieldTest, ParseNonIban) {
+ AddTextFormFieldData("other-field", "Field for Account Number", UNKNOWN_TYPE);
+
+ ClassifyAndVerify(ParseResult::NOT_PARSED);
+}
+
+TEST_P(IBANFieldTest, ParseIbanFlagOff) {
+ base::test::ScopedFeatureList scoped_feature_list;
+ scoped_feature_list.InitAndDisableFeature(features::kAutofillParseIBANFields);
+ AddTextFormFieldData("iban-field", "Enter IBAN here", IBAN_VALUE);
+
+ ClassifyAndVerify(ParseResult::NOT_PARSED);
+}
+} // namespace autofill
diff --git a/chromium/components/autofill/core/browser/form_parsing/merchant_promo_code_field.cc b/chromium/components/autofill/core/browser/form_parsing/merchant_promo_code_field.cc
index aa18677c381..14d755d8bfd 100644
--- a/chromium/components/autofill/core/browser/form_parsing/merchant_promo_code_field.cc
+++ b/chromium/components/autofill/core/browser/form_parsing/merchant_promo_code_field.cc
@@ -5,9 +5,9 @@
#include "components/autofill/core/browser/form_parsing/merchant_promo_code_field.h"
#include "components/autofill/core/browser/autofill_field.h"
-#include "components/autofill/core/browser/autofill_regex_constants.h"
#include "components/autofill/core/browser/form_parsing/autofill_scanner.h"
#include "components/autofill/core/common/autofill_payments_features.h"
+#include "components/autofill/core/common/autofill_regex_constants.h"
namespace autofill {
@@ -41,7 +41,7 @@ MerchantPromoCodeField::MerchantPromoCodeField(const AutofillField* field)
: field_(field) {}
void MerchantPromoCodeField::AddClassifications(
- FieldCandidatesMap* field_candidates) const {
+ FieldCandidatesMap& field_candidates) const {
AddClassification(field_, MERCHANT_PROMO_CODE,
kBaseMerchantPromoCodeParserScore, field_candidates);
}
diff --git a/chromium/components/autofill/core/browser/form_parsing/merchant_promo_code_field.h b/chromium/components/autofill/core/browser/form_parsing/merchant_promo_code_field.h
index 1b918aea03f..61e02bad6c7 100644
--- a/chromium/components/autofill/core/browser/form_parsing/merchant_promo_code_field.h
+++ b/chromium/components/autofill/core/browser/form_parsing/merchant_promo_code_field.h
@@ -33,7 +33,7 @@ class MerchantPromoCodeField : public FormField {
MerchantPromoCodeField& operator=(const MerchantPromoCodeField&) = delete;
protected:
- void AddClassifications(FieldCandidatesMap* field_candidates) const override;
+ void AddClassifications(FieldCandidatesMap& field_candidates) const override;
private:
FRIEND_TEST_ALL_PREFIXES(MerchantPromoCodeFieldTest, ParsePromoCode);
diff --git a/chromium/components/autofill/core/browser/form_parsing/merchant_promo_code_field_unittest.cc b/chromium/components/autofill/core/browser/form_parsing/merchant_promo_code_field_unittest.cc
index f16d20fe52e..5edb5687e25 100644
--- a/chromium/components/autofill/core/browser/form_parsing/merchant_promo_code_field_unittest.cc
+++ b/chromium/components/autofill/core/browser/form_parsing/merchant_promo_code_field_unittest.cc
@@ -45,7 +45,7 @@ INSTANTIATE_TEST_SUITE_P(
// Match promo(tion|tional)?[-_. ]*code
TEST_P(MerchantPromoCodeFieldTest, ParsePromoCode) {
- AddTextFormFieldData("Enter promo code here", "promoCodeField",
+ AddTextFormFieldData("promoCodeField", "Enter promo code here",
MERCHANT_PROMO_CODE);
ClassifyAndVerify(ParseResult::PARSED);
@@ -53,7 +53,7 @@ TEST_P(MerchantPromoCodeFieldTest, ParsePromoCode) {
// Match promo(tion|tional)?[-_. ]*code
TEST_P(MerchantPromoCodeFieldTest, ParsePromotionalCode) {
- AddTextFormFieldData("Use the promotional code here", "promoCodeField",
+ AddTextFormFieldData("promoCodeField", "Use the promotional code here",
MERCHANT_PROMO_CODE);
ClassifyAndVerify(ParseResult::PARSED);
@@ -69,7 +69,7 @@ TEST_P(MerchantPromoCodeFieldTest, ParsePromoCodeWithPrefixAndSuffix) {
// Match coupon[-_. ]*code
TEST_P(MerchantPromoCodeFieldTest, ParseCouponCode) {
- AddTextFormFieldData("Enter new coupon__code", "couponCodeField",
+ AddTextFormFieldData("couponCodeField", "Enter new coupon__code",
MERCHANT_PROMO_CODE);
ClassifyAndVerify(ParseResult::PARSED);
@@ -77,7 +77,7 @@ TEST_P(MerchantPromoCodeFieldTest, ParseCouponCode) {
// Match gift[-_. ]*code
TEST_P(MerchantPromoCodeFieldTest, ParseGiftCode) {
- AddTextFormFieldData("Check out with gift.codes", "giftCodeField",
+ AddTextFormFieldData("giftCodeField", "Check out with gift.codes",
MERCHANT_PROMO_CODE);
ClassifyAndVerify(ParseResult::PARSED);
@@ -85,7 +85,7 @@ TEST_P(MerchantPromoCodeFieldTest, ParseGiftCode) {
// Match discount[-_. ]*code
TEST_P(MerchantPromoCodeFieldTest, ParseDiscountCode) {
- AddTextFormFieldData("Check out with discount-code", "discountCodeField",
+ AddTextFormFieldData("discountCodeField", "Check out with discount-code",
MERCHANT_PROMO_CODE);
ClassifyAndVerify(ParseResult::PARSED);
@@ -93,7 +93,7 @@ TEST_P(MerchantPromoCodeFieldTest, ParseDiscountCode) {
TEST_P(MerchantPromoCodeFieldTest, ParseNonPromoCode) {
// Regex relies on "promo/coupon/gift" + "code" together.
- AddTextFormFieldData("Field for gift card or promo details", "otherField",
+ AddTextFormFieldData("otherField", "Field for gift card or promo details",
UNKNOWN_TYPE);
ClassifyAndVerify(ParseResult::NOT_PARSED);
@@ -103,7 +103,7 @@ TEST_P(MerchantPromoCodeFieldTest, ParsePromoCodeFlagOff) {
base::test::ScopedFeatureList scoped_feature_list;
scoped_feature_list.InitAndDisableFeature(
features::kAutofillParseMerchantPromoCodeFields);
- AddTextFormFieldData("Enter promo code here", "promoCodeField",
+ AddTextFormFieldData("promoCodeField", "Enter promo code here",
MERCHANT_PROMO_CODE);
ClassifyAndVerify(ParseResult::NOT_PARSED);
diff --git a/chromium/components/autofill/core/browser/form_parsing/name_field.cc b/chromium/components/autofill/core/browser/form_parsing/name_field.cc
index 858750b27bb..3aeb7204c9e 100644
--- a/chromium/components/autofill/core/browser/form_parsing/name_field.cc
+++ b/chromium/components/autofill/core/browser/form_parsing/name_field.cc
@@ -10,11 +10,11 @@
#include "base/memory/ptr_util.h"
#include "base/memory/raw_ptr.h"
#include "base/strings/string_util.h"
-#include "components/autofill/core/browser/autofill_regex_constants.h"
#include "components/autofill/core/browser/autofill_type.h"
#include "components/autofill/core/browser/form_parsing/autofill_scanner.h"
#include "components/autofill/core/browser/form_parsing/regex_patterns.h"
#include "components/autofill/core/common/autofill_features.h"
+#include "components/autofill/core/common/autofill_regex_constants.h"
namespace autofill {
namespace {
@@ -32,7 +32,7 @@ class FullNameField : public NameField {
FullNameField& operator=(const FullNameField&) = delete;
protected:
- void AddClassifications(FieldCandidatesMap* field_candidates) const override;
+ void AddClassifications(FieldCandidatesMap& field_candidates) const override;
private:
raw_ptr<AutofillField> field_;
@@ -57,7 +57,7 @@ class FirstTwoLastNamesField : public NameField {
FirstTwoLastNamesField& operator=(const FirstTwoLastNamesField&) = delete;
protected:
- void AddClassifications(FieldCandidatesMap* field_candidates) const override;
+ void AddClassifications(FieldCandidatesMap& field_candidates) const override;
private:
FirstTwoLastNamesField();
@@ -111,7 +111,7 @@ class FirstLastNameField : public NameField {
FirstLastNameField& operator=(const FirstLastNameField&) = delete;
protected:
- void AddClassifications(FieldCandidatesMap* field_candidates) const override;
+ void AddClassifications(FieldCandidatesMap& field_candidates) const override;
private:
FirstLastNameField();
@@ -152,8 +152,8 @@ std::unique_ptr<FormField> NameField::Parse(AutofillScanner* scanner,
return field;
}
-// This is overriden in concrete subclasses.
-void NameField::AddClassifications(FieldCandidatesMap* field_candidates) const {
+// This is overridden in concrete subclasses.
+void NameField::AddClassifications(FieldCandidatesMap& field_candidates) const {
}
// static
@@ -192,7 +192,7 @@ std::unique_ptr<FullNameField> FullNameField::Parse(
}
void FullNameField::AddClassifications(
- FieldCandidatesMap* field_candidates) const {
+ FieldCandidatesMap& field_candidates) const {
AddClassification(field_, NAME_FULL, kBaseNameParserScore, field_candidates);
}
@@ -303,7 +303,7 @@ FirstTwoLastNamesField::ParseComponentNames(AutofillScanner* scanner,
}
void FirstTwoLastNamesField::AddClassifications(
- FieldCandidatesMap* field_candidates) const {
+ FieldCandidatesMap& field_candidates) const {
AddClassification(honorific_prefix_, NAME_HONORIFIC_PREFIX,
kBaseNameParserScore, field_candidates);
AddClassification(first_name_, NAME_FIRST, kBaseNameParserScore,
@@ -539,7 +539,7 @@ std::unique_ptr<FirstLastNameField> FirstLastNameField::Parse(
FirstLastNameField::FirstLastNameField() = default;
void FirstLastNameField::AddClassifications(
- FieldCandidatesMap* field_candidates) const {
+ FieldCandidatesMap& field_candidates) const {
AddClassification(honorific_prefix_, NAME_HONORIFIC_PREFIX,
kBaseNameParserScore, field_candidates);
AddClassification(first_name_, NAME_FIRST, kBaseNameParserScore,
diff --git a/chromium/components/autofill/core/browser/form_parsing/name_field.h b/chromium/components/autofill/core/browser/form_parsing/name_field.h
index d3b23f5c5da..5abd312f09a 100644
--- a/chromium/components/autofill/core/browser/form_parsing/name_field.h
+++ b/chromium/components/autofill/core/browser/form_parsing/name_field.h
@@ -32,7 +32,7 @@ class NameField : public FormField {
protected:
NameField() = default;
- void AddClassifications(FieldCandidatesMap* field_candidates) const override;
+ void AddClassifications(FieldCandidatesMap& field_candidates) const override;
};
} // namespace autofill
diff --git a/chromium/components/autofill/core/browser/form_parsing/name_field_unittest.cc b/chromium/components/autofill/core/browser/form_parsing/name_field_unittest.cc
index db913d825ae..08855900810 100644
--- a/chromium/components/autofill/core/browser/form_parsing/name_field_unittest.cc
+++ b/chromium/components/autofill/core/browser/form_parsing/name_field_unittest.cc
@@ -8,10 +8,10 @@
#include <vector>
#include "base/test/scoped_feature_list.h"
-#include "components/autofill/core/browser/autofill_regex_constants.h"
-#include "components/autofill/core/browser/autofill_regexes.h"
#include "components/autofill/core/browser/form_parsing/parsing_test_utils.h"
#include "components/autofill/core/common/autofill_features.h"
+#include "components/autofill/core/common/autofill_regex_constants.h"
+#include "components/autofill/core/common/autofill_regexes.h"
#include "components/autofill/core/common/form_field_data.h"
namespace autofill {
@@ -39,9 +39,9 @@ INSTANTIATE_TEST_SUITE_P(
::testing::ValuesIn(PatternProviderFeatureState::All()));
TEST_P(NameFieldTest, FirstMiddleLast) {
- AddTextFormFieldData("First Name", "First", NAME_FIRST);
- AddTextFormFieldData("Name Middle", "Middle", NAME_MIDDLE);
- AddTextFormFieldData("Last Name", "Last", NAME_LAST);
+ AddTextFormFieldData("First", "First Name", NAME_FIRST);
+ AddTextFormFieldData("Middle", "Name Middle", NAME_MIDDLE);
+ AddTextFormFieldData("Last", "Last Name", NAME_LAST);
ClassifyAndVerify(ParseResult::PARSED);
}
@@ -185,9 +185,9 @@ TEST_P(NameFieldTest, FirstNameAndOptionalMiddleNameAndHispanicLastNames) {
features::kAutofillEnableSupportForMoreStructureInNames);
AddTextFormFieldData("nombre", "nombre", NAME_FIRST);
- AddTextFormFieldData("middle name", "middle_name", NAME_MIDDLE);
- AddTextFormFieldData("apellido paterno", "apellido_paterno", NAME_LAST_FIRST);
- AddTextFormFieldData("segunda apellido", "segunda_apellido",
+ AddTextFormFieldData("middle_name", "middle name", NAME_MIDDLE);
+ AddTextFormFieldData("apellido_paterno", "apellido paterno", NAME_LAST_FIRST);
+ AddTextFormFieldData("segunda_apellido", "segunda apellido",
NAME_LAST_SECOND);
ClassifyAndVerify(ParseResult::PARSED);
@@ -221,18 +221,18 @@ TEST_P(NameFieldTest, HispanicLastNameRegexConverage) {
for (const auto& string : first_last_name_strings) {
SCOPED_TRACE(string);
- EXPECT_TRUE(MatchesPattern(string, kNameLastFirstRe, nullptr));
+ EXPECT_TRUE(MatchesRegex<kNameLastFirstRe>(string));
}
for (const auto& string : second_last_name_strings) {
SCOPED_TRACE(string);
- EXPECT_TRUE(MatchesPattern(string, kNameLastSecondRe, nullptr));
+ EXPECT_TRUE(MatchesRegex<kNameLastSecondRe>(string));
}
for (const auto& string : neither_first_or_second_last_name_strings) {
SCOPED_TRACE(string);
- EXPECT_FALSE(MatchesPattern(string, kNameLastFirstRe, nullptr));
- EXPECT_FALSE(MatchesPattern(string, kNameLastSecondRe, nullptr));
+ EXPECT_FALSE(MatchesRegex<kNameLastFirstRe>(string));
+ EXPECT_FALSE(MatchesRegex<kNameLastSecondRe>(string));
}
}
diff --git a/chromium/components/autofill/core/browser/form_parsing/parsing_test_utils.cc b/chromium/components/autofill/core/browser/form_parsing/parsing_test_utils.cc
index e4930640356..8089ceab8e9 100644
--- a/chromium/components/autofill/core/browser/form_parsing/parsing_test_utils.cc
+++ b/chromium/components/autofill/core/browser/form_parsing/parsing_test_utils.cc
@@ -105,38 +105,28 @@ void FormFieldTestBase::ClassifyAndVerify(ParseResult parse_result,
return;
}
ASSERT_NE(nullptr, field_.get());
- field_->AddClassificationsForTesting(&field_candidates_map_);
+ field_->AddClassificationsForTesting(field_candidates_map_);
TestClassificationExpectations();
}
void FormFieldTestBase::TestClassificationExpectations() {
- for (const auto [field_id, field_type] : expected_classifications_) {
- if (field_type != UNKNOWN_TYPE) {
- SCOPED_TRACE(testing::Message()
- << "Found type "
- << AutofillType::ServerFieldTypeToString(
- field_candidates_map_[field_id].BestHeuristicType())
- << ", expected type "
- << AutofillType::ServerFieldTypeToString(field_type));
-
- ASSERT_TRUE(field_candidates_map_.find(field_id) !=
- field_candidates_map_.end());
- EXPECT_EQ(field_type,
- field_candidates_map_[field_id].BestHeuristicType());
- } else {
- SCOPED_TRACE(
- testing::Message()
- << "Expected type UNKNOWN_TYPE but got "
- << AutofillType::ServerFieldTypeToString(
- field_candidates_map_.find(field_id) !=
- field_candidates_map_.end()
- ? field_candidates_map_[field_id].BestHeuristicType()
- : UNKNOWN_TYPE));
- EXPECT_EQ(field_candidates_map_.find(field_id),
- field_candidates_map_.end());
- }
+ size_t num_classifications = 0;
+ for (const auto [field_id, expected_field_type] : expected_classifications_) {
+ ServerFieldType actual_field_type =
+ field_candidates_map_.contains(field_id)
+ ? field_candidates_map_[field_id].BestHeuristicType()
+ : UNKNOWN_TYPE;
+ SCOPED_TRACE(testing::Message()
+ << "Found type "
+ << AutofillType::ServerFieldTypeToString(actual_field_type)
+ << ", expected type "
+ << AutofillType::ServerFieldTypeToString(expected_field_type));
+ EXPECT_EQ(expected_field_type, actual_field_type);
+ num_classifications += expected_field_type != UNKNOWN_TYPE;
}
+ // There shouldn't be any classifications for other fields.
+ EXPECT_EQ(num_classifications, field_candidates_map_.size());
}
FieldRendererId FormFieldTestBase::MakeFieldRendererId() {
diff --git a/chromium/components/autofill/core/browser/form_parsing/phone_field.cc b/chromium/components/autofill/core/browser/form_parsing/phone_field.cc
index 523d186dcb0..0c6cabf3004 100644
--- a/chromium/components/autofill/core/browser/form_parsing/phone_field.cc
+++ b/chromium/components/autofill/core/browser/form_parsing/phone_field.cc
@@ -16,11 +16,12 @@
#include "base/strings/strcat.h"
#include "base/strings/string_util.h"
#include "components/autofill/core/browser/autofill_field.h"
-#include "components/autofill/core/browser/autofill_regex_constants.h"
-#include "components/autofill/core/browser/autofill_regexes.h"
#include "components/autofill/core/browser/form_parsing/autofill_scanner.h"
#include "components/autofill/core/browser/form_parsing/regex_patterns.h"
+#include "components/autofill/core/browser/metrics/autofill_metrics.h"
#include "components/autofill/core/common/autofill_features.h"
+#include "components/autofill/core/common/autofill_regex_constants.h"
+#include "components/autofill/core/common/autofill_regexes.h"
namespace autofill {
namespace {
@@ -57,81 +58,76 @@ std::u16string GetAreaRegex() {
// The following notation is used to describe the patterns:
// <cc> - country code field.
// <ac> - area code field.
+// TODO(crbug.com/1348137): Add a separate prefix type.
// <phone> - phone or prefix.
// <suffix> - suffix.
-// <ext> - extension.
// :N means field is limited to N characters, otherwise it is unlimited.
// (pattern <field>)? means pattern is optional and matched separately.
// static
const std::vector<PhoneField::PhoneGrammar>& PhoneField::GetPhoneGrammars() {
static const base::NoDestructor<std::vector<PhoneGrammar>> grammars({
- // Country code: <cc> Area Code: <ac> Phone: <phone> (- <suffix>
- // (Ext: <ext>)?)?
+ // Country code: <cc> Area Code: <ac> Phone: <phone>
{{REGEX_COUNTRY, FIELD_COUNTRY_CODE},
{REGEX_AREA, FIELD_AREA_CODE},
{REGEX_PHONE, FIELD_PHONE}},
- // \( <ac> \) <phone>:3 <suffix>:4 (Ext: <ext>)?
+ // \( <ac> \) <phone>:3 <suffix>:4
{{REGEX_AREA_NOTEXT, FIELD_AREA_CODE, 3},
{REGEX_PREFIX_SEPARATOR, FIELD_PHONE, 3},
{REGEX_PHONE, FIELD_SUFFIX, 4}},
- // Phone: <cc> <ac>:3 - <phone>:3 - <suffix>:4 (Ext: <ext>)?
+ // Phone: <cc> <ac>:3 - <phone>:3 - <suffix>:4
{{REGEX_PHONE, FIELD_COUNTRY_CODE},
{REGEX_PHONE, FIELD_AREA_CODE, 3},
{REGEX_PREFIX_SEPARATOR, FIELD_PHONE, 3},
{REGEX_SUFFIX_SEPARATOR, FIELD_SUFFIX, 4}},
- // Phone: <cc>:3 <ac>:3 <phone>:3 <suffix>:4 (Ext: <ext>)?
+ // Phone: <cc>:3 <ac>:3 <phone>:3 <suffix>:4
{{REGEX_PHONE, FIELD_COUNTRY_CODE, 3},
{REGEX_PHONE, FIELD_AREA_CODE, 3},
{REGEX_PHONE, FIELD_PHONE, 3},
{REGEX_PHONE, FIELD_SUFFIX, 4}},
- // Area Code: <ac> Phone: <phone> (- <suffix> (Ext: <ext>)?)?
+ // Area Code: <ac> Phone: <phone>
{{REGEX_AREA, FIELD_AREA_CODE}, {REGEX_PHONE, FIELD_PHONE}},
- // Phone: <ac> <phone>:3 <suffix>:4 (Ext: <ext>)?
+ // Phone: <ac> <phone>:3 <suffix>:4
{{REGEX_PHONE, FIELD_AREA_CODE},
{REGEX_PHONE, FIELD_PHONE, 3},
{REGEX_PHONE, FIELD_SUFFIX, 4}},
- // Phone: <cc> \( <ac> \) <phone> (- <suffix> (Ext: <ext>)?)?
+ // Phone: <cc> \( <ac> \) <phone>
{{REGEX_PHONE, FIELD_COUNTRY_CODE},
{REGEX_AREA_NOTEXT, FIELD_AREA_CODE},
{REGEX_PREFIX_SEPARATOR, FIELD_PHONE}},
- // Phone: \( <ac> \) <phone> (- <suffix> (Ext: <ext>)?)?
- {{REGEX_PHONE, FIELD_COUNTRY_CODE},
- {REGEX_AREA_NOTEXT, FIELD_AREA_CODE},
- {REGEX_PREFIX_SEPARATOR, FIELD_PHONE}},
- // Phone: <cc> - <ac> - <phone> - <suffix> (Ext: <ext>)?
+ // Phone: <cc> - <ac> - <phone> - <suffix>
{{REGEX_PHONE, FIELD_COUNTRY_CODE},
{REGEX_PREFIX_SEPARATOR, FIELD_AREA_CODE},
{REGEX_PREFIX_SEPARATOR, FIELD_PHONE},
{REGEX_SUFFIX_SEPARATOR, FIELD_SUFFIX}},
- // Area code: <ac>:3 Prefix: <prefix>:3 Suffix: <suffix>:4 (Ext: <ext>)?
+ // Area code: <ac>:3 Prefix: <prefix>:3 Suffix: <suffix>:4
{{REGEX_AREA, FIELD_AREA_CODE, 3},
{REGEX_PREFIX, FIELD_PHONE, 3},
{REGEX_SUFFIX, FIELD_SUFFIX, 4}},
- // Phone: <ac> Prefix: <phone> Suffix: <suffix> (Ext: <ext>)?
+ // Phone: <ac> Prefix: <phone> Suffix: <suffix>
{{REGEX_PHONE, FIELD_AREA_CODE},
{REGEX_PREFIX, FIELD_PHONE},
{REGEX_SUFFIX, FIELD_SUFFIX}},
- // Phone: <ac> - <phone>:3 - <suffix>:4 (Ext: <ext>)?
+ // Phone: <ac> - <phone>:3 - <suffix>:4
{{REGEX_PHONE, FIELD_AREA_CODE},
{REGEX_PREFIX_SEPARATOR, FIELD_PHONE, 3},
{REGEX_SUFFIX_SEPARATOR, FIELD_SUFFIX, 4}},
- // Phone: <cc> - <ac> - <phone> (Ext: <ext>)?
+ // Phone: <cc> - <ac> - <phone>
{{REGEX_PHONE, FIELD_COUNTRY_CODE},
{REGEX_PREFIX_SEPARATOR, FIELD_AREA_CODE},
{REGEX_SUFFIX_SEPARATOR, FIELD_PHONE}},
- // Phone: <ac> - <phone> (Ext: <ext>)?
+ // Phone: <ac> - <phone>
{{REGEX_AREA, FIELD_AREA_CODE}, {REGEX_PHONE, FIELD_PHONE}},
- // Phone: <cc>:3 - <phone> (Ext: <ext>)?
+ // Phone: <cc>:3 - <phone>
{{REGEX_PHONE, FIELD_COUNTRY_CODE, 3}, {REGEX_PHONE, FIELD_PHONE}},
- // Phone: <cc> <ac> <phone> (Ext: <ext>)?
+ // Phone: <cc> <ac> <phone>
// Indistinguishable from <area> <prefix> <suffix>
{{REGEX_PHONE, FIELD_COUNTRY_CODE},
{EMPTY_LABEL, FIELD_AREA_CODE},
{EMPTY_LABEL, FIELD_PHONE}},
- // Phone: <cc> <phone> (Ext: <ext>)?
+ // Phone: <cc> <phone>
// Indistinguishable from <area> <phone>
{{REGEX_PHONE, FIELD_COUNTRY_CODE}, {EMPTY_LABEL, FIELD_PHONE}},
- // Phone: <phone> (Ext: <ext>)?
+ // Phone: <phone>
{{REGEX_PHONE, FIELD_PHONE}},
});
return *grammars;
@@ -169,7 +165,7 @@ bool PhoneField::LikelyAugmentedPhoneCountryCode(
int total_positive_options = 0;
for (const auto& option : field->options) {
- if (MatchesPattern(option.content, kAugmentedPhoneCountryCodeRe))
+ if (MatchesRegexWithCache(option.content, kAugmentedPhoneCountryCodeRe))
total_positive_options++;
}
@@ -258,6 +254,7 @@ std::unique_ptr<FormField> PhoneField::Parse(AutofillScanner* scanner,
// Find the first matching grammar.
bool found_matching_grammar = false;
+ int grammar_id = 0;
for (const PhoneGrammar& grammar : GetPhoneGrammars()) {
std::fill(parsed_fields.begin(), parsed_fields.end(), nullptr);
if (ParseGrammar(grammar, parsed_fields, scanner, page_language,
@@ -266,6 +263,7 @@ std::unique_ptr<FormField> PhoneField::Parse(AutofillScanner* scanner,
break;
}
scanner->RewindTo(start_cursor);
+ grammar_id++;
}
if (!found_matching_grammar)
return nullptr;
@@ -273,20 +271,26 @@ std::unique_ptr<FormField> PhoneField::Parse(AutofillScanner* scanner,
DCHECK(parsed_fields[FIELD_PHONE] != nullptr);
// Look for a suffix field using two different regex.
+ // TODO(crbug.com/1348137): Revise or remove.
+ bool suffix_matched = false;
if (!parsed_fields[FIELD_SUFFIX]) {
- ParsePhoneField(scanner, kPhoneSuffixRe, &parsed_fields[FIELD_SUFFIX],
- {log_manager, "kPhoneSuffixRe"},
- /*is_country_code_field=*/false, "PHONE_SUFFIX",
- page_language, pattern_source) ||
+ suffix_matched =
+ ParsePhoneField(scanner, kPhoneSuffixRe, &parsed_fields[FIELD_SUFFIX],
+ {log_manager, "kPhoneSuffixRe"},
+ /*is_country_code_field=*/false, "PHONE_SUFFIX",
+ page_language, pattern_source) ||
ParsePhoneField(
scanner, kPhoneSuffixSeparatorRe, &parsed_fields[FIELD_SUFFIX],
{log_manager, "kPhoneSuffixSeparatorRe"},
/*is_country_code_field=*/false, "PHONE_SUFFIX_SEPARATOR",
page_language, pattern_source);
}
+ AutofillMetrics::LogPhoneNumberGrammarMatched(grammar_id, suffix_matched,
+ GetPhoneGrammars().size());
+
// Now look for an extension.
- // The extension is not actually used, so this just eats the field so other
- // parsers do not mistaken it for something else.
+ // The extension is unused, but it is parsed to prevent other parsers from
+ // misclassifying it as something else.
ParsePhoneField(scanner, kPhoneExtensionRe, &parsed_fields[FIELD_EXTENSION],
{log_manager, "kPhoneExtensionRe"},
/*is_country_code_field=*/false, "PHONE_EXTENSION",
@@ -296,7 +300,7 @@ std::unique_ptr<FormField> PhoneField::Parse(AutofillScanner* scanner,
}
void PhoneField::AddClassifications(
- FieldCandidatesMap* field_candidates) const {
+ FieldCandidatesMap& field_candidates) const {
DCHECK(parsed_phone_fields_[FIELD_PHONE]); // Phone was correctly parsed.
bool has_country_code = parsed_phone_fields_[FIELD_COUNTRY_CODE] != nullptr;
@@ -319,24 +323,27 @@ void PhoneField::AddClassifications(
AddClassification(parsed_phone_fields_[FIELD_AREA_CODE], area_code_type,
kBasePhoneParserScore, field_candidates);
} else if (has_country_code) {
- // Only if we can find country code without city code, it means the phone
- // number include city code.
field_number_type =
base::FeatureList::IsEnabled(
features::kAutofillEnableSupportForPhoneNumberTrunkTypes)
? PHONE_HOME_CITY_AND_NUMBER_WITHOUT_TRUNK_PREFIX
: PHONE_HOME_CITY_AND_NUMBER;
}
- // We tag the prefix as PHONE_HOME_NUMBER, then when filling the form
- // we fill only the prefix depending on the size of the input field.
- AddClassification(parsed_phone_fields_[FIELD_PHONE], field_number_type,
- kBasePhoneParserScore, field_candidates);
- // We tag the suffix as PHONE_HOME_NUMBER, then when filling the form
- // we fill only the suffix depending on the size of the input field.
+ // PHONE_HOME_NUMBER = PHONE_HOME_NUMBER_PREFIX + PHONE_HOME_NUMBER_SUFFIX
+ // is technically dialable (seven-digit dialing), and thus not contained in
+ // the area code branch.
if (parsed_phone_fields_[FIELD_SUFFIX]) {
- AddClassification(parsed_phone_fields_[FIELD_SUFFIX], PHONE_HOME_NUMBER,
- kBasePhoneParserScore, field_candidates);
+ // TODO(crbug.com/1348137): Ideally we want to DCHECK that
+ // `parsed_phone_fields_[FIELD_AREA_CODE] || !has_country_code` here.
+ // With the current grammars this can be violated, even though it
+ // seemingly never happens in practice according to our metrics.
+ field_number_type = PHONE_HOME_NUMBER_PREFIX;
+ AddClassification(parsed_phone_fields_[FIELD_SUFFIX],
+ PHONE_HOME_NUMBER_SUFFIX, kBasePhoneParserScore,
+ field_candidates);
}
+ AddClassification(parsed_phone_fields_[FIELD_PHONE], field_number_type,
+ kBasePhoneParserScore, field_candidates);
} else {
AddClassification(parsed_phone_fields_[FIELD_PHONE],
PHONE_HOME_WHOLE_NUMBER, kBasePhoneParserScore,
diff --git a/chromium/components/autofill/core/browser/form_parsing/phone_field.h b/chromium/components/autofill/core/browser/form_parsing/phone_field.h
index 68f9a02024a..7b38d05d01d 100644
--- a/chromium/components/autofill/core/browser/form_parsing/phone_field.h
+++ b/chromium/components/autofill/core/browser/form_parsing/phone_field.h
@@ -40,13 +40,13 @@ class PhoneField : public FormField {
#if defined(UNIT_TEST)
// Assign types to the fields for the testing purposes.
void AddClassificationsForTesting(
- FieldCandidatesMap* field_candidates_for_testing) const {
+ FieldCandidatesMap& field_candidates_for_testing) const {
AddClassifications(field_candidates_for_testing);
}
#endif
protected:
- void AddClassifications(FieldCandidatesMap* field_candidates) const override;
+ void AddClassifications(FieldCandidatesMap& field_candidates) const override;
private:
// This is for easy description of the possible parsing paths of the phone
diff --git a/chromium/components/autofill/core/browser/form_parsing/phone_field_unittest.cc b/chromium/components/autofill/core/browser/form_parsing/phone_field_unittest.cc
index 05edafbe122..bd17d9f5ea3 100644
--- a/chromium/components/autofill/core/browser/form_parsing/phone_field_unittest.cc
+++ b/chromium/components/autofill/core/browser/form_parsing/phone_field_unittest.cc
@@ -12,6 +12,7 @@
#include "base/containers/contains.h"
#include "base/memory/ptr_util.h"
#include "base/strings/utf_string_conversions.h"
+#include "base/test/metrics/histogram_tester.h"
#include "base/test/scoped_feature_list.h"
#include "components/autofill/core/browser/autofill_field.h"
#include "components/autofill/core/browser/form_parsing/autofill_scanner.h"
@@ -147,7 +148,7 @@ void PhoneFieldTest::RunParsingTest(const std::vector<TestFieldData>& fields,
// Verify expecations.
if (expect_success) {
- field_->AddClassificationsForTesting(&field_candidates_map_);
+ field_->AddClassificationsForTesting(field_candidates_map_);
for (size_t i = 0; i < fields.size(); i++) {
CheckField(global_ids[i], fields[i].expected_type);
}
@@ -201,8 +202,10 @@ TEST_P(PhoneFieldTest, ThreePartPhoneNumber) {
for (const char* field_type : kFieldTypes) {
RunParsingTest(
{{field_type, u"Phone:", u"dayphone1", PHONE_HOME_CITY_CODE},
- {field_type, u"-", u"dayphone2", PHONE_HOME_NUMBER, /*max_length=*/3},
- {field_type, u"-", u"dayphone3", PHONE_HOME_NUMBER, /*max_length=*/4},
+ {field_type, u"-", u"dayphone2", PHONE_HOME_NUMBER_PREFIX,
+ /*max_length=*/3},
+ {field_type, u"-", u"dayphone3", PHONE_HOME_NUMBER_SUFFIX,
+ /*max_length=*/4},
{field_type, u"ext.:", u"dayphone4", PHONE_HOME_EXTENSION}});
}
}
@@ -213,8 +216,8 @@ TEST_P(PhoneFieldTest, ThreePartPhoneNumber) {
TEST_P(PhoneFieldTest, ThreePartPhoneNumberPrefixSuffix) {
for (const char* field_type : kFieldTypes) {
RunParsingTest({{field_type, u"Phone:", u"area", PHONE_HOME_CITY_CODE},
- {field_type, u"", u"prefix", PHONE_HOME_NUMBER},
- {field_type, u"", u"suffix", PHONE_HOME_NUMBER,
+ {field_type, u"", u"prefix", PHONE_HOME_NUMBER_PREFIX},
+ {field_type, u"", u"suffix", PHONE_HOME_NUMBER_SUFFIX,
/*max_length=*/4}});
}
}
@@ -223,8 +226,9 @@ TEST_P(PhoneFieldTest, ThreePartPhoneNumberPrefixSuffix2) {
for (const char* field_type : kFieldTypes) {
RunParsingTest(
{{field_type, u"(", u"phone1", PHONE_HOME_CITY_CODE, /*max_length=*/3},
- {field_type, u")", u"phone2", PHONE_HOME_NUMBER, /*max_length=*/3},
- {field_type, u"", u"phone3", PHONE_HOME_NUMBER,
+ {field_type, u")", u"phone2", PHONE_HOME_NUMBER_PREFIX,
+ /*max_length=*/3},
+ {field_type, u"", u"phone3", PHONE_HOME_NUMBER_SUFFIX,
/*max_length=*/4}});
}
}
@@ -258,6 +262,18 @@ TEST_P(PhoneFieldTest, EmptyLabels) {
{"text", u"", u"", PHONE_HOME_NUMBER}});
}
+// Tests that when a phone field is parsed, a metric indicating the used grammar
+// is emitted.
+TEST_P(PhoneFieldTest, GrammarMetrics) {
+ // PHONE_HOME_WHOLE_NUMBER corresponds to the last grammar. We thus expect
+ // that 2*16 + 1 = 33 is logged.
+ base::HistogramTester histogram_tester;
+ RunParsingTest({{"text", u"Phone", u"phone", PHONE_HOME_WHOLE_NUMBER}});
+ EXPECT_THAT(histogram_tester.GetAllSamples(
+ "Autofill.FieldPrediction.PhoneNumberGrammarUsage"),
+ BucketsAre(base::Bucket(33, 1)));
+}
+
TEST_P(PhoneFieldTest, TrunkPrefixTypes) {
base::test::ScopedFeatureList trunk_types_enabled;
trunk_types_enabled.InitAndEnableFeature(
diff --git a/chromium/components/autofill/core/browser/form_parsing/price_field.cc b/chromium/components/autofill/core/browser/form_parsing/price_field.cc
index a91e7a34e14..7fcf9df69a1 100644
--- a/chromium/components/autofill/core/browser/form_parsing/price_field.cc
+++ b/chromium/components/autofill/core/browser/form_parsing/price_field.cc
@@ -5,9 +5,9 @@
#include "components/autofill/core/browser/form_parsing/price_field.h"
#include "components/autofill/core/browser/autofill_field.h"
-#include "components/autofill/core/browser/autofill_regex_constants.h"
#include "components/autofill/core/browser/form_parsing/autofill_scanner.h"
#include "components/autofill/core/browser/form_parsing/regex_patterns.h"
+#include "components/autofill/core/common/autofill_regex_constants.h"
namespace autofill {
@@ -35,7 +35,7 @@ std::unique_ptr<FormField> PriceField::Parse(AutofillScanner* scanner,
PriceField::PriceField(const AutofillField* field) : field_(field) {}
void PriceField::AddClassifications(
- FieldCandidatesMap* field_candidates) const {
+ FieldCandidatesMap& field_candidates) const {
AddClassification(field_, PRICE, kBasePriceParserScore, field_candidates);
}
diff --git a/chromium/components/autofill/core/browser/form_parsing/price_field.h b/chromium/components/autofill/core/browser/form_parsing/price_field.h
index e550b750d1d..d81a319c123 100644
--- a/chromium/components/autofill/core/browser/form_parsing/price_field.h
+++ b/chromium/components/autofill/core/browser/form_parsing/price_field.h
@@ -33,7 +33,7 @@ class PriceField : public FormField {
PriceField& operator=(const PriceField&) = delete;
protected:
- void AddClassifications(FieldCandidatesMap* field_candidates) const override;
+ void AddClassifications(FieldCandidatesMap& field_candidates) const override;
private:
FRIEND_TEST_ALL_PREFIXES(PriceFieldTest, ParsePrice);
diff --git a/chromium/components/autofill/core/browser/form_parsing/price_field_unittest.cc b/chromium/components/autofill/core/browser/form_parsing/price_field_unittest.cc
index 56380de0c4e..72747db2198 100644
--- a/chromium/components/autofill/core/browser/form_parsing/price_field_unittest.cc
+++ b/chromium/components/autofill/core/browser/form_parsing/price_field_unittest.cc
@@ -33,7 +33,7 @@ INSTANTIATE_TEST_SUITE_P(
::testing::ValuesIn(PatternProviderFeatureState::All()));
TEST_P(PriceFieldTest, ParsePrice) {
- AddTextFormFieldData("name your price", "userPrice", PRICE);
+ AddTextFormFieldData("userPrice", "name your price", PRICE);
ClassifyAndVerify(ParseResult::PARSED);
}
diff --git a/chromium/components/autofill/core/browser/form_parsing/regex_patterns_unittest.cc b/chromium/components/autofill/core/browser/form_parsing/regex_patterns_unittest.cc
index 875821b3f8c..d51d5fcb153 100644
--- a/chromium/components/autofill/core/browser/form_parsing/regex_patterns_unittest.cc
+++ b/chromium/components/autofill/core/browser/form_parsing/regex_patterns_unittest.cc
@@ -16,10 +16,10 @@
#include "base/logging.h"
#include "base/ranges/ranges.h"
#include "base/strings/utf_string_conversions.h"
-#include "components/autofill/core/browser/autofill_regexes.h"
#include "components/autofill/core/browser/form_parsing/buildflags.h"
#include "components/autofill/core/browser/form_parsing/regex_patterns_inl.h"
#include "components/autofill/core/common/autofill_features.h"
+#include "components/autofill/core/common/autofill_regexes.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -59,10 +59,12 @@ MatchPatternRefTestApi test_api(MatchPatternRef p) {
return MatchPatternRefTestApi(p);
}
-auto Matches(base::StringPiece16 pattern) {
- return ::testing::Truly([pattern](base::StringPiece actual) {
- return MatchesPattern(base::UTF8ToUTF16(actual), pattern);
- });
+auto Matches(base::StringPiece16 regex) {
+ icu::RegexPattern regex_pattern = *CompileRegex(regex);
+ return ::testing::Truly(
+ [regex_pattern = std::move(regex_pattern)](base::StringPiece actual) {
+ return MatchesRegex(base::UTF8ToUTF16(actual), regex_pattern);
+ });
}
auto Matches(MatchingPattern pattern) {
diff --git a/chromium/components/autofill/core/browser/form_parsing/resources/legacy_regex_patterns.json b/chromium/components/autofill/core/browser/form_parsing/resources/legacy_regex_patterns.json
index a4217b5a21d..1e5fb2764c7 100644
--- a/chromium/components/autofill/core/browser/form_parsing/resources/legacy_regex_patterns.json
+++ b/chromium/components/autofill/core/browser/form_parsing/resources/legacy_regex_patterns.json
@@ -22,8 +22,8 @@
"positive_pattern": "street",
"positive_score": 1.1,
"negative_pattern": null,
- "match_field_attributes": [0, 1],
- "match_field_input_types": [0, 7]
+ "match_field_attributes": ["LABEL", "NAME"],
+ "match_field_input_types": ["TEXT", "SEARCH"]
}
],
"de" : [
@@ -32,8 +32,8 @@
"positive_pattern": "stra(ss|ß)e",
"positive_score": 1.1,
"negative_pattern": null,
- "match_field_attributes": [0, 1],
- "match_field_input_types": [0, 7]
+ "match_field_attributes": ["LABEL", "NAME"],
+ "match_field_input_types": ["TEXT", "SEARCH"]
}
],
"es" : [
@@ -42,8 +42,8 @@
"positive_pattern": "calle",
"positive_score": 1.1,
"negative_pattern": null,
- "match_field_attributes": [0, 1],
- "match_field_input_types": [0, 7]
+ "match_field_attributes": ["LABEL", "NAME"],
+ "match_field_input_types": ["TEXT", "SEARCH"]
}
],
"ru" : [
@@ -52,8 +52,8 @@
"positive_pattern": "улица|название.?улицы",
"positive_score": 1.1,
"negative_pattern": null,
- "match_field_attributes": [0, 1],
- "match_field_input_types": [0, 7]
+ "match_field_attributes": ["LABEL", "NAME"],
+ "match_field_input_types": ["TEXT", "SEARCH"]
}
],
"pt" : [
@@ -62,8 +62,8 @@
"positive_pattern": "rua|avenida|((?<!do |de )endereço)",
"positive_score": 1.1,
"negative_pattern": null,
- "match_field_attributes": [0, 1],
- "match_field_input_types": [0, 7]
+ "match_field_attributes": ["LABEL", "NAME"],
+ "match_field_input_types": ["TEXT", "SEARCH"]
}
]
},
@@ -74,8 +74,8 @@
"positive_pattern": "apartment",
"positive_score": 1.1,
"negative_pattern": null,
- "match_field_attributes": [0, 1],
- "match_field_input_types": [0, 2, 6]
+ "match_field_attributes": ["LABEL", "NAME"],
+ "match_field_input_types": ["TEXT", "TELEPHONE", "NUMBER"]
}
],
"es": [
@@ -84,8 +84,8 @@
"positive_pattern": "interior|número.*apartamento",
"positive_score": 1.1,
"negative_pattern": null,
- "match_field_attributes": [0, 1],
- "match_field_input_types": [0, 2, 6]
+ "match_field_attributes": ["LABEL", "NAME"],
+ "match_field_input_types": ["TEXT", "TELEPHONE", "NUMBER"]
}
],
"de": [
@@ -94,8 +94,8 @@
"positive_pattern": "wohnung",
"positive_score": 1.1,
"negative_pattern": null,
- "match_field_attributes": [0, 1],
- "match_field_input_types": [0, 2, 6]
+ "match_field_attributes": ["LABEL", "NAME"],
+ "match_field_input_types": ["TEXT", "TELEPHONE", "NUMBER"]
}
],
"ru": [
@@ -104,8 +104,8 @@
"positive_pattern": "квартир",
"positive_score": 1.1,
"negative_pattern": null,
- "match_field_attributes": [0, 1],
- "match_field_input_types": [0, 2, 6]
+ "match_field_attributes": ["LABEL", "NAME"],
+ "match_field_input_types": ["TEXT", "TELEPHONE", "NUMBER"]
}
],
"it": [
@@ -114,8 +114,8 @@
"positive_pattern": "numero.*appartamento",
"positive_score": 1.1,
"negative_pattern": null,
- "match_field_attributes": [0, 1],
- "match_field_input_types": [0, 2, 6]
+ "match_field_attributes": ["LABEL", "NAME"],
+ "match_field_input_types": ["TEXT", "TELEPHONE", "NUMBER"]
}
],
"fr": [
@@ -124,8 +124,8 @@
"positive_pattern": "numéro.*appartement",
"positive_score": 1.1,
"negative_pattern": null,
- "match_field_attributes": [0, 1],
- "match_field_input_types": [0, 2, 6]
+ "match_field_attributes": ["LABEL", "NAME"],
+ "match_field_input_types": ["TEXT", "TELEPHONE", "NUMBER"]
}
]
},
@@ -136,8 +136,8 @@
"positive_pattern": "(house.?|street.?|^)(number|no\\.?$)",
"positive_score": 1.1,
"negative_pattern": null,
- "match_field_attributes": [0, 1],
- "match_field_input_types": [0, 2, 6]
+ "match_field_attributes": ["LABEL", "NAME"],
+ "match_field_input_types": ["TEXT", "TELEPHONE", "NUMBER"]
}
],
"de": [
@@ -146,8 +146,8 @@
"positive_pattern": "(haus|^)(nummer|nr)",
"positive_score": 1.1,
"negative_pattern": null,
- "match_field_attributes": [0, 1],
- "match_field_input_types": [0, 2, 6]
+ "match_field_attributes": ["LABEL", "NAME"],
+ "match_field_input_types": ["TEXT", "TELEPHONE", "NUMBER"]
}
],
"pt": [
@@ -156,8 +156,8 @@
"positive_pattern": "^\\*?.?número(.?\\*?$| da residência)",
"positive_score": 1.1,
"negative_pattern": null,
- "match_field_attributes": [0, 1],
- "match_field_input_types": [0, 2, 6]
+ "match_field_attributes": ["LABEL", "NAME"],
+ "match_field_input_types": ["TEXT", "TELEPHONE", "NUMBER"]
}
],
"es": [
@@ -166,8 +166,8 @@
"positive_pattern": "n(u|ú)mero.*apartamento|exterior",
"positive_score": 1.1,
"negative_pattern": null,
- "match_field_attributes": [0, 1],
- "match_field_input_types": [0, 2, 6]
+ "match_field_attributes": ["LABEL", "NAME"],
+ "match_field_input_types": ["TEXT", "TELEPHONE", "NUMBER"]
}
],
"ru": [
@@ -176,8 +176,8 @@
"positive_pattern": "дом|номер.?дома",
"positive_score": 1.1,
"negative_pattern": null,
- "match_field_attributes": [0, 1],
- "match_field_input_types": [0, 2, 6]
+ "match_field_attributes": ["LABEL", "NAME"],
+ "match_field_input_types": ["TEXT", "TELEPHONE", "NUMBER"]
}
]
},
@@ -188,8 +188,8 @@
"positive_pattern": "attention|attn",
"positive_score": 1.1,
"negative_pattern": null,
- "match_field_attributes": [0, 1],
- "match_field_input_types": [0]
+ "match_field_attributes": ["LABEL", "NAME"],
+ "match_field_input_types": ["TEXT"]
}
]
},
@@ -200,8 +200,8 @@
"positive_pattern": "province|region|other",
"positive_score": 1.1,
"negative_pattern": null,
- "match_field_attributes": [0, 1],
- "match_field_input_types": [0]
+ "match_field_attributes": ["LABEL", "NAME"],
+ "match_field_input_types": ["TEXT"]
}
],
"es": [
@@ -210,8 +210,8 @@
"positive_pattern": "provincia",
"positive_score": 1.1,
"negative_pattern": null,
- "match_field_attributes": [0, 1],
- "match_field_input_types": [0]
+ "match_field_attributes": ["LABEL", "NAME"],
+ "match_field_input_types": ["TEXT"]
}
],
"pt": [
@@ -220,8 +220,8 @@
"positive_pattern": "bairro|suburb",
"positive_score": 1.1,
"negative_pattern": null,
- "match_field_attributes": [0, 1],
- "match_field_input_types": [0]
+ "match_field_attributes": ["LABEL", "NAME"],
+ "match_field_input_types": ["TEXT"]
}
]
},
@@ -232,8 +232,8 @@
"positive_pattern": "address.*nickname|address.*label",
"positive_score": 1.1,
"negative_pattern": null,
- "match_field_attributes": [0, 1],
- "match_field_input_types": [0]
+ "match_field_attributes": ["LABEL", "NAME"],
+ "match_field_input_types": ["TEXT"]
}
],
"tr": [
@@ -242,8 +242,8 @@
"positive_pattern": "adres ([İi]sim|başlığı|adı)",
"positive_score": 1.1,
"negative_pattern": null,
- "match_field_attributes": [0, 1],
- "match_field_input_types": [0]
+ "match_field_attributes": ["LABEL", "NAME"],
+ "match_field_input_types": ["TEXT"]
}
],
"pt": [
@@ -252,8 +252,8 @@
"positive_pattern": "identificação do endereço",
"positive_score": 1.1,
"negative_pattern": null,
- "match_field_attributes": [0, 1],
- "match_field_input_types": [0]
+ "match_field_attributes": ["LABEL", "NAME"],
+ "match_field_input_types": ["TEXT"]
}
],
"id": [
@@ -262,8 +262,8 @@
"positive_pattern": "(label|judul|nama) alamat",
"positive_score": 1.1,
"negative_pattern": null,
- "match_field_attributes": [0, 1],
- "match_field_input_types": [0]
+ "match_field_attributes": ["LABEL", "NAME"],
+ "match_field_input_types": ["TEXT"]
}
]
},
@@ -274,8 +274,8 @@
"positive_pattern": "company|business|organization|organisation",
"positive_score": 1.1,
"negative_pattern": null,
- "match_field_attributes": [0, 1],
- "match_field_input_types": [0]
+ "match_field_attributes": ["LABEL", "NAME"],
+ "match_field_input_types": ["TEXT"]
}
],
"de": [
@@ -284,8 +284,8 @@
"positive_pattern": "(?<!con)firma|firmenname",
"positive_score": 1.1,
"negative_pattern": null,
- "match_field_attributes": [0, 1],
- "match_field_input_types": [0]
+ "match_field_attributes": ["LABEL", "NAME"],
+ "match_field_input_types": ["TEXT"]
}
],
"es": [
@@ -294,8 +294,8 @@
"positive_pattern": "empresa",
"positive_score": 1.1,
"negative_pattern": null,
- "match_field_attributes": [0, 1],
- "match_field_input_types": [0]
+ "match_field_attributes": ["LABEL", "NAME"],
+ "match_field_input_types": ["TEXT"]
}
],
"fr": [
@@ -304,8 +304,8 @@
"positive_pattern": "societe|société",
"positive_score": 1.1,
"negative_pattern": null,
- "match_field_attributes": [0, 1],
- "match_field_input_types": [0]
+ "match_field_attributes": ["LABEL", "NAME"],
+ "match_field_input_types": ["TEXT"]
}
],
"it": [
@@ -314,8 +314,8 @@
"positive_pattern": "ragione.?sociale",
"positive_score": 1.1,
"negative_pattern": null,
- "match_field_attributes": [0, 1],
- "match_field_input_types": [0]
+ "match_field_attributes": ["LABEL", "NAME"],
+ "match_field_input_types": ["TEXT"]
}
],
"ja": [
@@ -324,8 +324,8 @@
"positive_pattern": "会社",
"positive_score": 1.1,
"negative_pattern": null,
- "match_field_attributes": [0, 1],
- "match_field_input_types": [0]
+ "match_field_attributes": ["LABEL", "NAME"],
+ "match_field_input_types": ["TEXT"]
}
],
"ru": [
@@ -334,8 +334,8 @@
"positive_pattern": "название.?компании",
"positive_score": 1.1,
"negative_pattern": null,
- "match_field_attributes": [0, 1],
- "match_field_input_types": [0]
+ "match_field_attributes": ["LABEL", "NAME"],
+ "match_field_input_types": ["TEXT"]
}
],
"zh-CN": [
@@ -344,8 +344,8 @@
"positive_pattern": "单位|公司",
"positive_score": 1.1,
"negative_pattern": null,
- "match_field_attributes": [0, 1],
- "match_field_input_types": [0]
+ "match_field_attributes": ["LABEL", "NAME"],
+ "match_field_input_types": ["TEXT"]
}
],
"fa": [
@@ -354,8 +354,8 @@
"positive_pattern": "شرکت",
"positive_score": 1.1,
"negative_pattern": null,
- "match_field_attributes": [0, 1],
- "match_field_input_types": [0]
+ "match_field_attributes": ["LABEL", "NAME"],
+ "match_field_input_types": ["TEXT"]
}
],
"ko": [
@@ -364,8 +364,8 @@
"positive_pattern": "회사|직장",
"positive_score": 1.1,
"negative_pattern": null,
- "match_field_attributes": [0, 1],
- "match_field_input_types": [0]
+ "match_field_attributes": ["LABEL", "NAME"],
+ "match_field_input_types": ["TEXT"]
}
],
"id": [
@@ -374,8 +374,8 @@
"positive_pattern": "(nama.?)?perusahaan",
"positive_score": 1.1,
"negative_pattern": null,
- "match_field_attributes": [0, 1],
- "match_field_input_types": [0]
+ "match_field_attributes": ["LABEL", "NAME"],
+ "match_field_input_types": ["TEXT"]
}
]
},
@@ -386,16 +386,16 @@
"positive_pattern": "^address$|address[_-]?line(one)?|address1|addr1|street|(?:shipping|billing)address$|house.?name",
"positive_score": 1.1,
"negative_pattern": null,
- "match_field_attributes": [0, 1],
- "match_field_input_types": [0, 7]
+ "match_field_attributes": ["LABEL", "NAME"],
+ "match_field_input_types": ["TEXT", "SEARCH"]
},
{
"pattern_identifier": "en_address_line_1_label_preserving",
"positive_pattern": "(^\\W*address)|(address\\W*$)|(?:shipping|billing|mailing|pick.?up|drop.?off|delivery|sender|postal|recipient|home|work|office|school|business|mail)[\\s\\-]+address|address\\s+(of|for|to|from)|street.*(house|building|apartment|floor)|(house|building|apartment|floor).*street",
"positive_score": 1.1,
"negative_pattern": null,
- "match_field_attributes": [0],
- "match_field_input_types": [0, 7]
+ "match_field_attributes": ["LABEL"],
+ "match_field_input_types": ["TEXT", "SEARCH"]
}
],
"de": [
@@ -404,8 +404,8 @@
"positive_pattern": "strasse|straße",
"positive_score": 1.1,
"negative_pattern": null,
- "match_field_attributes": [0, 1],
- "match_field_input_types": [0, 7]
+ "match_field_attributes": ["LABEL", "NAME"],
+ "match_field_input_types": ["TEXT", "SEARCH"]
}
],
"es": [
@@ -414,8 +414,8 @@
"positive_pattern": "direccion|dirección",
"positive_score": 1.1,
"negative_pattern": null,
- "match_field_attributes": [0, 1],
- "match_field_input_types": [0, 7]
+ "match_field_attributes": ["LABEL", "NAME"],
+ "match_field_input_types": ["TEXT", "SEARCH"]
}
],
"fr": [
@@ -424,16 +424,16 @@
"positive_pattern": "adresse",
"positive_score": 1.1,
"negative_pattern": null,
- "match_field_attributes": [0, 1],
- "match_field_input_types": [0, 7]
+ "match_field_attributes": ["LABEL", "NAME"],
+ "match_field_input_types": ["TEXT", "SEARCH"]
},
{
"pattern_identifier": "fr_address_line_1_label_preserving",
"positive_pattern": "adresse",
"positive_score": 1.1,
"negative_pattern": null,
- "match_field_attributes": [0],
- "match_field_input_types": [0, 7]
+ "match_field_attributes": ["LABEL"],
+ "match_field_input_types": ["TEXT", "SEARCH"]
}
],
"it": [
@@ -442,16 +442,16 @@
"positive_pattern": "indirizzo",
"positive_score": 1.1,
"negative_pattern": null,
- "match_field_attributes": [0, 1],
- "match_field_input_types": [0, 7]
+ "match_field_attributes": ["LABEL", "NAME"],
+ "match_field_input_types": ["TEXT", "SEARCH"]
},
{
"pattern_identifier": "it_address_line_1_label_preserving",
"positive_pattern": "indirizzo",
"positive_score": 1.1,
"negative_pattern": null,
- "match_field_attributes": [0],
- "match_field_input_types": [0, 7]
+ "match_field_attributes": ["LABEL"],
+ "match_field_input_types": ["TEXT", "SEARCH"]
}
],
"ja": [
@@ -460,16 +460,16 @@
"positive_pattern": "^住所$|住所1",
"positive_score": 1.1,
"negative_pattern": null,
- "match_field_attributes": [0, 1],
- "match_field_input_types": [0, 7]
+ "match_field_attributes": ["LABEL", "NAME"],
+ "match_field_input_types": ["TEXT", "SEARCH"]
},
{
"pattern_identifier": "ja_address_line_1_label_preserving",
"positive_pattern": "住所",
"positive_score": 1.1,
"negative_pattern": null,
- "match_field_attributes": [0],
- "match_field_input_types": [0, 7]
+ "match_field_attributes": ["LABEL"],
+ "match_field_input_types": ["TEXT", "SEARCH"]
}
],
"pt": [
@@ -478,8 +478,8 @@
"positive_pattern": "morada|((?<!do |de )endereço)",
"positive_score": 1.1,
"negative_pattern": null,
- "match_field_attributes": [0, 1],
- "match_field_input_types": [0, 7]
+ "match_field_attributes": ["LABEL", "NAME"],
+ "match_field_input_types": ["TEXT", "SEARCH"]
}
],
"ru": [
@@ -488,16 +488,16 @@
"positive_pattern": "Адрес",
"positive_score": 1.1,
"negative_pattern": null,
- "match_field_attributes": [0, 1],
- "match_field_input_types": [0, 7]
+ "match_field_attributes": ["LABEL", "NAME"],
+ "match_field_input_types": ["TEXT", "SEARCH"]
},
{
"pattern_identifier": "ru_address_line_1_label_preserving",
"positive_pattern": "улиц.*(дом|корпус|квартир|этаж)|(дом|корпус|квартир|этаж).*улиц",
"positive_score": 1.1,
"negative_pattern": null,
- "match_field_attributes": [0],
- "match_field_input_types": [0, 7]
+ "match_field_attributes": ["LABEL"],
+ "match_field_input_types": ["TEXT", "SEARCH"]
}
],
"zh-CN": [
@@ -506,8 +506,8 @@
"positive_pattern": "地址",
"positive_score": 1.1,
"negative_pattern": null,
- "match_field_attributes": [0, 1],
- "match_field_input_types": [0, 7]
+ "match_field_attributes": ["LABEL", "NAME"],
+ "match_field_input_types": ["TEXT", "SEARCH"]
}
],
"tr": [
@@ -516,16 +516,16 @@
"positive_pattern": "(\\b|_)adres(?! tarifi)(\\b|_)",
"positive_score": 1.1,
"negative_pattern": null,
- "match_field_attributes": [0, 1],
- "match_field_input_types": [0, 7]
+ "match_field_attributes": ["LABEL", "NAME"],
+ "match_field_input_types": ["TEXT", "SEARCH"]
},
{
"pattern_identifier": "tr_address_line_1_label_preserving",
"positive_pattern": "(\\b|_)adres(?! tarifi)(\\b|_)|(sokak|cadde).*(apartman|bina|daire|mahalle)|(apartman|bina|daire|mahalle).*(sokak|cadde)",
"positive_score": 1.1,
"negative_pattern": null,
- "match_field_attributes": [0],
- "match_field_input_types": [0, 7]
+ "match_field_attributes": ["LABEL"],
+ "match_field_input_types": ["TEXT", "SEARCH"]
}
],
"ko": [
@@ -534,8 +534,8 @@
"positive_pattern": "^주소.?$|주소.?1",
"positive_score": 1.1,
"negative_pattern": null,
- "match_field_attributes": [0, 1],
- "match_field_input_types": [0, 7]
+ "match_field_attributes": ["LABEL", "NAME"],
+ "match_field_input_types": ["TEXT", "SEARCH"]
}
,
{
@@ -543,8 +543,8 @@
"positive_pattern": "주소",
"positive_score": 1.1,
"negative_pattern": null,
- "match_field_attributes": [0],
- "match_field_input_types": [0, 7]
+ "match_field_attributes": ["LABEL"],
+ "match_field_input_types": ["TEXT", "SEARCH"]
}
],
"id": [
@@ -553,8 +553,8 @@
"positive_pattern": "^alamat",
"positive_score": 1.1,
"negative_pattern": null,
- "match_field_attributes": [0, 1],
- "match_field_input_types": [0, 7]
+ "match_field_attributes": ["LABEL", "NAME"],
+ "match_field_input_types": ["TEXT", "SEARCH"]
}
,
{
@@ -562,8 +562,8 @@
"positive_pattern": "^alamat",
"positive_score": 1.1,
"negative_pattern": null,
- "match_field_attributes": [0],
- "match_field_input_types": [0, 7]
+ "match_field_attributes": ["LABEL"],
+ "match_field_input_types": ["TEXT", "SEARCH"]
}
]
},
@@ -574,16 +574,16 @@
"positive_pattern": "address[_-]?line(2|two)|address2|addr2|street|suite|unit",
"positive_score": 1.1,
"negative_pattern": null,
- "match_field_attributes": [0, 1],
- "match_field_input_types": [0]
+ "match_field_attributes": ["LABEL", "NAME"],
+ "match_field_input_types": ["TEXT"]
},
{
"pattern_identifier": "en_address_line_2_label_preserving",
"positive_pattern": "address|line",
"positive_score": 1.1,
"negative_pattern": null,
- "match_field_attributes": [0],
- "match_field_input_types": [0]
+ "match_field_attributes": ["LABEL"],
+ "match_field_input_types": ["TEXT"]
}
],
"de": [
@@ -592,8 +592,8 @@
"positive_pattern": "adresszusatz|ergänzende.?angaben",
"positive_score": 1.1,
"negative_pattern": null,
- "match_field_attributes": [0, 1],
- "match_field_input_types": [0]
+ "match_field_attributes": ["LABEL", "NAME"],
+ "match_field_input_types": ["TEXT"]
}
],
"es": [
@@ -602,8 +602,8 @@
"positive_pattern": "direccion2|colonia|adicional",
"positive_score": 1.1,
"negative_pattern": null,
- "match_field_attributes": [0, 1],
- "match_field_input_types": [0]
+ "match_field_attributes": ["LABEL", "NAME"],
+ "match_field_input_types": ["TEXT"]
}
],
"fr": [
@@ -612,16 +612,16 @@
"positive_pattern": "addresssuppl|complementnom|appartement",
"positive_score": 1.1,
"negative_pattern": null,
- "match_field_attributes": [0, 1],
- "match_field_input_types": [0]
+ "match_field_attributes": ["LABEL", "NAME"],
+ "match_field_input_types": ["TEXT"]
},
{
"pattern_identifier": "fr_address_line_2_label_preserving",
"positive_pattern": "adresse",
"positive_score": 1.1,
"negative_pattern": null,
- "match_field_attributes": [0],
- "match_field_input_types": [0]
+ "match_field_attributes": ["LABEL"],
+ "match_field_input_types": ["TEXT"]
}
],
"it": [
@@ -630,16 +630,16 @@
"positive_pattern": "indirizzo2",
"positive_score": 1.1,
"negative_pattern": null,
- "match_field_attributes": [0, 1],
- "match_field_input_types": [0]
+ "match_field_attributes": ["LABEL", "NAME"],
+ "match_field_input_types": ["TEXT"]
},
{
"pattern_identifier": "it_address_line_2_label_preserving",
"positive_pattern": "indirizzo",
"positive_score": 1.1,
"negative_pattern": null,
- "match_field_attributes": [0],
- "match_field_input_types": [0]
+ "match_field_attributes": ["LABEL"],
+ "match_field_input_types": ["TEXT"]
}
],
"ja": [
@@ -648,8 +648,8 @@
"positive_pattern": "住所2",
"positive_score": 1.1,
"negative_pattern": null,
- "match_field_attributes": [0, 1],
- "match_field_input_types": [0]
+ "match_field_attributes": ["LABEL", "NAME"],
+ "match_field_input_types": ["TEXT"]
}
],
"pt": [
@@ -658,8 +658,8 @@
"positive_pattern": "complemento|addrcomplement",
"positive_score": 1.1,
"negative_pattern": null,
- "match_field_attributes": [0, 1],
- "match_field_input_types": [0]
+ "match_field_attributes": ["LABEL", "NAME"],
+ "match_field_input_types": ["TEXT"]
}
],
"ru": [
@@ -668,8 +668,8 @@
"positive_pattern": "Улица",
"positive_score": 1.1,
"negative_pattern": null,
- "match_field_attributes": [0, 1],
- "match_field_input_types": [0]
+ "match_field_attributes": ["LABEL", "NAME"],
+ "match_field_input_types": ["TEXT"]
}
],
"zh-CN": [
@@ -678,16 +678,16 @@
"positive_pattern": "地址2",
"positive_score": 1.1,
"negative_pattern": null,
- "match_field_attributes": [0, 1],
- "match_field_input_types": [0]
+ "match_field_attributes": ["LABEL", "NAME"],
+ "match_field_input_types": ["TEXT"]
},
{
"pattern_identifier": "zh_address_line_2_label_preserving",
"positive_pattern": "地址",
"positive_score": 1.1,
"negative_pattern": null,
- "match_field_attributes": [0],
- "match_field_input_types": [0]
+ "match_field_attributes": ["LABEL"],
+ "match_field_input_types": ["TEXT"]
}
],
"ko": [
@@ -696,16 +696,16 @@
"positive_pattern": "주소.?2",
"positive_score": 1.1,
"negative_pattern": null,
- "match_field_attributes": [0, 1],
- "match_field_input_types": [0]
+ "match_field_attributes": ["LABEL", "NAME"],
+ "match_field_input_types": ["TEXT"]
},
{
"pattern_identifier": "ko_address_line_2_label_preserving",
"positive_pattern": "주소",
"positive_score": 1.1,
"negative_pattern": null,
- "match_field_attributes": [0],
- "match_field_input_types": [0]
+ "match_field_attributes": ["LABEL"],
+ "match_field_input_types": ["TEXT"]
}
]
},
@@ -716,8 +716,8 @@
"positive_pattern": "address.*line[3-9]|address[3-9]|addr[3-9]|street|line[3-9]",
"positive_score": 1.1,
"negative_pattern": null,
- "match_field_attributes": [0, 1],
- "match_field_input_types": [0]
+ "match_field_attributes": ["LABEL", "NAME"],
+ "match_field_input_types": ["TEXT"]
}
],
"es": [
@@ -726,8 +726,8 @@
"positive_pattern": "municipio",
"positive_score": 1.1,
"negative_pattern": null,
- "match_field_attributes": [0, 1],
- "match_field_input_types": [0]
+ "match_field_attributes": ["LABEL", "NAME"],
+ "match_field_input_types": ["TEXT"]
}
],
"fr": [
@@ -736,8 +736,8 @@
"positive_pattern": "batiment|residence",
"positive_score": 1.1,
"negative_pattern": null,
- "match_field_attributes": [0, 1],
- "match_field_input_types": [0]
+ "match_field_attributes": ["LABEL", "NAME"],
+ "match_field_input_types": ["TEXT"]
}
],
"it": [
@@ -746,8 +746,8 @@
"positive_pattern": "indirizzo[3-9]",
"positive_score": 1.1,
"negative_pattern": null,
- "match_field_attributes": [0, 1],
- "match_field_input_types": [0]
+ "match_field_attributes": ["LABEL", "NAME"],
+ "match_field_input_types": ["TEXT"]
}
]
},
@@ -758,8 +758,8 @@
"positive_pattern": "lookup",
"positive_score": 1.1,
"negative_pattern": null,
- "match_field_attributes": [0, 1],
- "match_field_input_types": [0]
+ "match_field_attributes": ["LABEL", "NAME"],
+ "match_field_input_types": ["TEXT"]
}
]
},
@@ -770,8 +770,8 @@
"positive_pattern": "country|countries",
"positive_score": 1.1,
"negative_pattern": null,
- "match_field_attributes": [0, 1],
- "match_field_input_types": [0, 3, 7]
+ "match_field_attributes": ["LABEL", "NAME"],
+ "match_field_input_types": ["TEXT", "SELECT", "SEARCH"]
}
],
"es": [
@@ -780,8 +780,8 @@
"positive_pattern": "país|pais",
"positive_score": 1.1,
"negative_pattern": null,
- "match_field_attributes": [0, 1],
- "match_field_input_types": [0, 3, 7]
+ "match_field_attributes": ["LABEL", "NAME"],
+ "match_field_input_types": ["TEXT", "SELECT", "SEARCH"]
}
],
"de": [
@@ -790,8 +790,8 @@
"positive_pattern": "(\\b|_)land(\\b|_)(?!.*(mark.*))",
"positive_score": 1.1,
"negative_pattern": null,
- "match_field_attributes": [0, 1],
- "match_field_input_types": [0, 3, 7]
+ "match_field_attributes": ["LABEL", "NAME"],
+ "match_field_input_types": ["TEXT", "SELECT", "SEARCH"]
}
],
"ja": [
@@ -800,8 +800,8 @@
"positive_pattern": "(?<!(入|出))国",
"positive_score": 1.1,
"negative_pattern": null,
- "match_field_attributes": [0, 1],
- "match_field_input_types": [0, 3, 7]
+ "match_field_attributes": ["LABEL", "NAME"],
+ "match_field_input_types": ["TEXT", "SELECT", "SEARCH"]
}
],
"zh-CN": [
@@ -810,8 +810,8 @@
"positive_pattern": "国家",
"positive_score": 1.1,
"negative_pattern": null,
- "match_field_attributes": [0, 1],
- "match_field_input_types": [0, 3, 7]
+ "match_field_attributes": ["LABEL", "NAME"],
+ "match_field_input_types": ["TEXT", "SELECT", "SEARCH"]
}
],
"ko": [
@@ -820,8 +820,8 @@
"positive_pattern": "국가|나라",
"positive_score": 1.1,
"negative_pattern": null,
- "match_field_attributes": [0, 1],
- "match_field_input_types": [0, 3, 7]
+ "match_field_attributes": ["LABEL", "NAME"],
+ "match_field_input_types": ["TEXT", "SELECT", "SEARCH"]
}
],
"tr": [
@@ -830,8 +830,8 @@
"positive_pattern": "(\\b|_)(ülke|ulce|ulke)(\\b|_)",
"positive_score": 1.1,
"negative_pattern": null,
- "match_field_attributes": [0, 1],
- "match_field_input_types": [0, 3, 7]
+ "match_field_attributes": ["LABEL", "NAME"],
+ "match_field_input_types": ["TEXT", "SELECT", "SEARCH"]
}
],
"fa": [
@@ -840,8 +840,8 @@
"positive_pattern": "کشور",
"positive_score": 1.1,
"negative_pattern": null,
- "match_field_attributes": [0, 1],
- "match_field_input_types": [0, 3, 7]
+ "match_field_attributes": ["LABEL", "NAME"],
+ "match_field_input_types": ["TEXT", "SELECT", "SEARCH"]
}
],
"id": [
@@ -850,8 +850,8 @@
"positive_pattern": "negara",
"positive_score": 1.1,
"negative_pattern": null,
- "match_field_attributes": [0, 1],
- "match_field_input_types": [0, 3, 7]
+ "match_field_attributes": ["LABEL", "NAME"],
+ "match_field_input_types": ["TEXT", "SELECT", "SEARCH"]
}
]
},
@@ -862,8 +862,8 @@
"positive_pattern": "location",
"positive_score": 1.1,
"negative_pattern": null,
- "match_field_attributes": [0, 1],
- "match_field_input_types": [3, 7]
+ "match_field_attributes": ["LABEL", "NAME"],
+ "match_field_input_types": ["SELECT", "SEARCH"]
}
]
},
@@ -875,8 +875,8 @@
"positive_score": 1.1,
"negative_pattern": "\\.zip\\b",
"negative_patterns_explainer": ".zip refers to a file extension. However, there are field billingAddress.zip",
- "match_field_attributes": [0, 1],
- "match_field_input_types": [0, 2, 6]
+ "match_field_attributes": ["LABEL", "NAME"],
+ "match_field_input_types": ["TEXT", "TELEPHONE", "NUMBER"]
},
{
"pattern_identifier": "en_zip_code_preserving",
@@ -884,8 +884,8 @@
"positive_score": 1.1,
"negative_pattern": null,
"negative_patterns_explainer": "",
- "match_field_attributes": [0, 1],
- "match_field_input_types": [0, 2, 6]
+ "match_field_attributes": ["LABEL", "NAME"],
+ "match_field_input_types": ["TEXT", "TELEPHONE", "NUMBER"]
}
],
"de": [
@@ -894,8 +894,8 @@
"positive_pattern": "postleitzahl",
"positive_score": 1.1,
"negative_pattern": null,
- "match_field_attributes": [0, 1],
- "match_field_input_types": [0, 2, 6]
+ "match_field_attributes": ["LABEL", "NAME"],
+ "match_field_input_types": ["TEXT", "TELEPHONE", "NUMBER"]
}
],
"es": [
@@ -904,8 +904,8 @@
"positive_pattern": "\\bcp\\b",
"positive_score": 1.1,
"negative_pattern": null,
- "match_field_attributes": [0, 1],
- "match_field_input_types": [0, 2, 6]
+ "match_field_attributes": ["LABEL", "NAME"],
+ "match_field_input_types": ["TEXT", "TELEPHONE", "NUMBER"]
}
],
"fr": [
@@ -914,8 +914,8 @@
"positive_pattern": "\\bcdp\\b",
"positive_score": 1.1,
"negative_pattern": null,
- "match_field_attributes": [0, 1],
- "match_field_input_types": [0, 2, 6]
+ "match_field_attributes": ["LABEL", "NAME"],
+ "match_field_input_types": ["TEXT", "TELEPHONE", "NUMBER"]
}
],
"it": [
@@ -924,8 +924,8 @@
"positive_pattern": "\\bcap\\b",
"positive_score": 1.1,
"negative_pattern": null,
- "match_field_attributes": [0, 1],
- "match_field_input_types": [0, 2, 6]
+ "match_field_attributes": ["LABEL", "NAME"],
+ "match_field_input_types": ["TEXT", "TELEPHONE", "NUMBER"]
}
],
"ja": [
@@ -934,8 +934,8 @@
"positive_pattern": "郵便番号",
"positive_score": 1.1,
"negative_pattern": null,
- "match_field_attributes": [0, 1],
- "match_field_input_types": [0, 2, 6]
+ "match_field_attributes": ["LABEL", "NAME"],
+ "match_field_input_types": ["TEXT", "TELEPHONE", "NUMBER"]
}
],
"pt": [
@@ -944,8 +944,8 @@
"positive_pattern": "codigo|codpos|\\bcep\\b",
"positive_score": 1.1,
"negative_pattern": null,
- "match_field_attributes": [0, 1],
- "match_field_input_types": [0, 2, 6]
+ "match_field_attributes": ["LABEL", "NAME"],
+ "match_field_input_types": ["TEXT", "TELEPHONE", "NUMBER"]
}
],
"ru": [
@@ -954,8 +954,8 @@
"positive_pattern": "Почтовый.?Индекс",
"positive_score": 1.1,
"negative_pattern": null,
- "match_field_attributes": [0, 1],
- "match_field_input_types": [0, 2, 6]
+ "match_field_attributes": ["LABEL", "NAME"],
+ "match_field_input_types": ["TEXT", "TELEPHONE", "NUMBER"]
}
],
"hi": [
@@ -964,8 +964,8 @@
"positive_pattern": "पिन.?कोड",
"positive_score": 1.1,
"negative_pattern": null,
- "match_field_attributes": [0, 1],
- "match_field_input_types": [0, 2, 6]
+ "match_field_attributes": ["LABEL", "NAME"],
+ "match_field_input_types": ["TEXT", "TELEPHONE", "NUMBER"]
}
],
"ml": [
@@ -974,8 +974,8 @@
"positive_pattern": "പിന്‍കോഡ്",
"positive_score": 1.1,
"negative_pattern": null,
- "match_field_attributes": [0, 1],
- "match_field_input_types": [0, 2, 6]
+ "match_field_attributes": ["LABEL", "NAME"],
+ "match_field_input_types": ["TEXT", "TELEPHONE", "NUMBER"]
}
],
"zh-CN": [
@@ -984,8 +984,8 @@
"positive_pattern": "邮政编码|邮编",
"positive_score": 1.1,
"negative_pattern": null,
- "match_field_attributes": [0, 1],
- "match_field_input_types": [0, 2, 6]
+ "match_field_attributes": ["LABEL", "NAME"],
+ "match_field_input_types": ["TEXT", "TELEPHONE", "NUMBER"]
}
],
"zh-TW": [
@@ -994,8 +994,8 @@
"positive_pattern": "郵遞區號",
"positive_score": 1.1,
"negative_pattern": null,
- "match_field_attributes": [0, 1],
- "match_field_input_types": [0, 2, 6]
+ "match_field_attributes": ["LABEL", "NAME"],
+ "match_field_input_types": ["TEXT", "TELEPHONE", "NUMBER"]
}
],
"tr": [
@@ -1004,8 +1004,8 @@
"positive_pattern": "(\\b|_)posta kodu(\\b|_)",
"positive_score": 1.1,
"negative_pattern": null,
- "match_field_attributes": [0, 1],
- "match_field_input_types": [0, 2, 6]
+ "match_field_attributes": ["LABEL", "NAME"],
+ "match_field_input_types": ["TEXT", "TELEPHONE", "NUMBER"]
}
],
"ko": [
@@ -1014,8 +1014,8 @@
"positive_pattern": "우편.?번호",
"positive_score": 1.1,
"negative_pattern": null,
- "match_field_attributes": [0, 1],
- "match_field_input_types": [0, 2, 6]
+ "match_field_attributes": ["LABEL", "NAME"],
+ "match_field_input_types": ["TEXT", "TELEPHONE", "NUMBER"]
}
],
"id": [
@@ -1024,8 +1024,8 @@
"positive_pattern": "kode.?pos",
"positive_score": 1.1,
"negative_pattern": null,
- "match_field_attributes": [0, 1],
- "match_field_input_types": [0, 2, 6]
+ "match_field_attributes": ["LABEL", "NAME"],
+ "match_field_input_types": ["TEXT", "TELEPHONE", "NUMBER"]
}
]
},
@@ -1037,8 +1037,8 @@
"positive_score": 1.1,
"negative_pattern": "\\.zip",
"negative_patterns_explainer": ".zip refers to a file extension",
- "match_field_attributes": [0, 1],
- "match_field_input_types": [0, 2, 6]
+ "match_field_attributes": ["LABEL", "NAME"],
+ "match_field_input_types": ["TEXT", "TELEPHONE", "NUMBER"]
}
],
"pt": [
@@ -1047,8 +1047,8 @@
"positive_pattern": "codpos2",
"positive_score": 1.1,
"negative_pattern": null,
- "match_field_attributes": [0, 1],
- "match_field_input_types": [0, 2, 6]
+ "match_field_attributes": ["LABEL", "NAME"],
+ "match_field_input_types": ["TEXT", "TELEPHONE", "NUMBER"]
}
]
},
@@ -1059,8 +1059,8 @@
"positive_pattern": "neighbo(u)?rhood",
"positive_score": 1.1,
"negative_pattern": null,
- "match_field_attributes": [0, 1],
- "match_field_input_types": [0, 3, 7]
+ "match_field_attributes": ["LABEL", "NAME"],
+ "match_field_input_types": ["TEXT", "SELECT", "SEARCH"]
}
],
"pt": [
@@ -1069,8 +1069,8 @@
"positive_pattern": "bairro",
"positive_score": 1.1,
"negative_pattern": null,
- "match_field_attributes": [0, 1],
- "match_field_input_types": [0, 3, 7]
+ "match_field_attributes": ["LABEL", "NAME"],
+ "match_field_input_types": ["TEXT", "SELECT", "SEARCH"]
}
],
"tr": [
@@ -1079,8 +1079,8 @@
"positive_pattern": "mahalle|köy",
"positive_score": 1.1,
"negative_pattern": null,
- "match_field_attributes": [0, 1],
- "match_field_input_types": [0, 3, 7]
+ "match_field_attributes": ["LABEL", "NAME"],
+ "match_field_input_types": ["TEXT", "SELECT", "SEARCH"]
}
],
"id": [
@@ -1089,8 +1089,8 @@
"positive_pattern": "kecamatan",
"positive_score": 1.1,
"negative_pattern": null,
- "match_field_attributes": [0, 1],
- "match_field_input_types": [0, 3, 7]
+ "match_field_attributes": ["LABEL", "NAME"],
+ "match_field_input_types": ["TEXT", "SELECT", "SEARCH"]
}
]
},
@@ -1101,8 +1101,8 @@
"positive_pattern": "city|town|suburb",
"positive_score": 1.1,
"negative_pattern": null,
- "match_field_attributes": [0, 1],
- "match_field_input_types": [0, 3, 7]
+ "match_field_attributes": ["LABEL", "NAME"],
+ "match_field_input_types": ["TEXT", "SELECT", "SEARCH"]
}
],
"de": [
@@ -1111,8 +1111,8 @@
"positive_pattern": "\\bort\\b|stadt",
"positive_score": 1.1,
"negative_pattern": null,
- "match_field_attributes": [0, 1],
- "match_field_input_types": [0, 3, 7]
+ "match_field_attributes": ["LABEL", "NAME"],
+ "match_field_input_types": ["TEXT", "SELECT", "SEARCH"]
}
],
"es": [
@@ -1121,8 +1121,8 @@
"positive_pattern": "ciudad|provincia|localidad|poblacion",
"positive_score": 1.1,
"negative_pattern": null,
- "match_field_attributes": [0, 1],
- "match_field_input_types": [0, 3, 7]
+ "match_field_attributes": ["LABEL", "NAME"],
+ "match_field_input_types": ["TEXT", "SELECT", "SEARCH"]
}
],
"fr": [
@@ -1131,8 +1131,8 @@
"positive_pattern": "ville|commune",
"positive_score": 1.1,
"negative_pattern": null,
- "match_field_attributes": [0, 1],
- "match_field_input_types": [0, 3, 7]
+ "match_field_attributes": ["LABEL", "NAME"],
+ "match_field_input_types": ["TEXT", "SELECT", "SEARCH"]
}
],
"it": [
@@ -1141,8 +1141,8 @@
"positive_pattern": "localita",
"positive_score": 1.1,
"negative_pattern": null,
- "match_field_attributes": [0, 1],
- "match_field_input_types": [0, 3, 7]
+ "match_field_attributes": ["LABEL", "NAME"],
+ "match_field_input_types": ["TEXT", "SELECT", "SEARCH"]
}
],
"ja": [
@@ -1151,8 +1151,8 @@
"positive_pattern": "市区町村",
"positive_score": 1.1,
"negative_pattern": null,
- "match_field_attributes": [0, 1],
- "match_field_input_types": [0, 3, 7]
+ "match_field_attributes": ["LABEL", "NAME"],
+ "match_field_input_types": ["TEXT", "SELECT", "SEARCH"]
}
],
"pt": [
@@ -1161,8 +1161,8 @@
"positive_pattern": "cidade|município",
"positive_score": 1.1,
"negative_pattern": null,
- "match_field_attributes": [0, 1],
- "match_field_input_types": [0, 3, 7]
+ "match_field_attributes": ["LABEL", "NAME"],
+ "match_field_input_types": ["TEXT", "SELECT", "SEARCH"]
}
],
"ru": [
@@ -1171,8 +1171,8 @@
"positive_pattern": "Город|Насел(е|ё)нный.?пункт",
"positive_score": 1.1,
"negative_pattern": null,
- "match_field_attributes": [0, 1],
- "match_field_input_types": [0, 3, 7]
+ "match_field_attributes": ["LABEL", "NAME"],
+ "match_field_input_types": ["TEXT", "SELECT", "SEARCH"]
}
],
"zh-TW": [
@@ -1181,8 +1181,8 @@
"positive_pattern": "市|分區",
"positive_score": 1.1,
"negative_pattern": null,
- "match_field_attributes": [0, 1],
- "match_field_input_types": [0, 3, 7]
+ "match_field_attributes": ["LABEL", "NAME"],
+ "match_field_input_types": ["TEXT", "SELECT", "SEARCH"]
}
],
"fa": [
@@ -1191,8 +1191,8 @@
"positive_pattern": "شهر",
"positive_score": 1.1,
"negative_pattern": null,
- "match_field_attributes": [0, 1],
- "match_field_input_types": [0, 3, 7]
+ "match_field_attributes": ["LABEL", "NAME"],
+ "match_field_input_types": ["TEXT", "SELECT", "SEARCH"]
}
],
"hi": [
@@ -1201,8 +1201,8 @@
"positive_pattern": "शहर|ग्राम|गाँव",
"positive_score": 1.1,
"negative_pattern": null,
- "match_field_attributes": [0, 1],
- "match_field_input_types": [0, 3, 7]
+ "match_field_attributes": ["LABEL", "NAME"],
+ "match_field_input_types": ["TEXT", "SELECT", "SEARCH"]
}
],
"ml": [
@@ -1211,8 +1211,8 @@
"positive_pattern": "നഗരം|ഗ്രാമം",
"positive_score": 1.1,
"negative_pattern": null,
- "match_field_attributes": [0, 1],
- "match_field_input_types": [0, 3, 7]
+ "match_field_attributes": ["LABEL", "NAME"],
+ "match_field_input_types": ["TEXT", "SELECT", "SEARCH"]
}
],
"tr": [
@@ -1221,8 +1221,8 @@
"positive_pattern": "((\\b|_|\\*)([İii̇]l[cç]e(miz|niz)?)(\\b|_|\\*))",
"positive_score": 1.1,
"negative_pattern": null,
- "match_field_attributes": [0, 1],
- "match_field_input_types": [0, 3, 7]
+ "match_field_attributes": ["LABEL", "NAME"],
+ "match_field_input_types": ["TEXT", "SELECT", "SEARCH"]
}
],
"ko": [
@@ -1231,8 +1231,8 @@
"positive_pattern": "^시[^도·・]|시[·・]?군[·・]?구",
"positive_score": 1.1,
"negative_pattern": null,
- "match_field_attributes": [0, 1],
- "match_field_input_types": [0, 3, 7]
+ "match_field_attributes": ["LABEL", "NAME"],
+ "match_field_input_types": ["TEXT", "SELECT", "SEARCH"]
}
],
"id": [
@@ -1241,8 +1241,8 @@
"positive_pattern": "kota|kabupaten",
"positive_score": 1.1,
"negative_pattern": null,
- "match_field_attributes": [0, 1],
- "match_field_input_types": [0, 3, 7]
+ "match_field_attributes": ["LABEL", "NAME"],
+ "match_field_input_types": ["TEXT", "SELECT", "SEARCH"]
}
]
},
@@ -1253,8 +1253,8 @@
"positive_pattern": "(?<!(united|hist|history).?)state|county|region|province|county|principality",
"positive_score": 1.1,
"negative_pattern": null,
- "match_field_attributes": [0, 1],
- "match_field_input_types": [0, 3, 7]
+ "match_field_attributes": ["LABEL", "NAME"],
+ "match_field_input_types": ["TEXT", "SELECT", "SEARCH"]
}
],
"ja": [
@@ -1263,8 +1263,8 @@
"positive_pattern": "都道府県",
"positive_score": 1.1,
"negative_pattern": null,
- "match_field_attributes": [0, 1],
- "match_field_input_types": [0, 3, 7]
+ "match_field_attributes": ["LABEL", "NAME"],
+ "match_field_input_types": ["TEXT", "SELECT", "SEARCH"]
}
],
"pt": [
@@ -1273,8 +1273,8 @@
"positive_pattern": "estado|provincia",
"positive_score": 1.1,
"negative_pattern": null,
- "match_field_attributes": [0, 1],
- "match_field_input_types": [0, 3, 7]
+ "match_field_attributes": ["LABEL", "NAME"],
+ "match_field_input_types": ["TEXT", "SELECT", "SEARCH"]
}
],
"ru": [
@@ -1283,8 +1283,8 @@
"positive_pattern": "область",
"positive_score": 1.1,
"negative_pattern": null,
- "match_field_attributes": [0, 1],
- "match_field_input_types": [0, 3, 7]
+ "match_field_attributes": ["LABEL", "NAME"],
+ "match_field_input_types": ["TEXT", "SELECT", "SEARCH"]
}
],
"zh-TW": [
@@ -1293,8 +1293,8 @@
"positive_pattern": "省|地區",
"positive_score": 1.1,
"negative_pattern": null,
- "match_field_attributes": [0, 1],
- "match_field_input_types": [0, 3, 7]
+ "match_field_attributes": ["LABEL", "NAME"],
+ "match_field_input_types": ["TEXT", "SELECT", "SEARCH"]
}
],
"ml": [
@@ -1303,8 +1303,8 @@
"positive_pattern": "സംസ്ഥാനം",
"positive_score": 1.1,
"negative_pattern": null,
- "match_field_attributes": [0, 1],
- "match_field_input_types": [0, 3, 7]
+ "match_field_attributes": ["LABEL", "NAME"],
+ "match_field_input_types": ["TEXT", "SELECT", "SEARCH"]
}
],
"fa": [
@@ -1313,8 +1313,8 @@
"positive_pattern": "استان",
"positive_score": 1.1,
"negative_pattern": null,
- "match_field_attributes": [0, 1],
- "match_field_input_types": [0, 3, 7]
+ "match_field_attributes": ["LABEL", "NAME"],
+ "match_field_input_types": ["TEXT", "SELECT", "SEARCH"]
}
],
"hi": [
@@ -1323,8 +1323,8 @@
"positive_pattern": "राज्य",
"positive_score": 1.1,
"negative_pattern": null,
- "match_field_attributes": [0, 1],
- "match_field_input_types": [0, 3, 7]
+ "match_field_attributes": ["LABEL", "NAME"],
+ "match_field_input_types": ["TEXT", "SELECT", "SEARCH"]
}
],
"tr": [
@@ -1333,8 +1333,8 @@
"positive_pattern": "((\\b|_|\\*)(eyalet|[şs]ehir|[İii̇]l(imiz)?|kent)(\\b|_|\\*))",
"positive_score": 1.1,
"negative_pattern": null,
- "match_field_attributes": [0, 1],
- "match_field_input_types": [0, 3, 7]
+ "match_field_attributes": ["LABEL", "NAME"],
+ "match_field_input_types": ["TEXT", "SELECT", "SEARCH"]
}
],
"ko": [
@@ -1343,8 +1343,8 @@
"positive_pattern": "^시[·・]?도",
"positive_score": 1.1,
"negative_pattern": null,
- "match_field_attributes": [0, 1],
- "match_field_input_types": [0, 3, 7]
+ "match_field_attributes": ["LABEL", "NAME"],
+ "match_field_input_types": ["TEXT", "SELECT", "SEARCH"]
}
],
"id": [
@@ -1353,8 +1353,8 @@
"positive_pattern": "provinci",
"positive_score": 1.1,
"negative_pattern": null,
- "match_field_attributes": [0, 1],
- "match_field_input_types": [0, 3, 7]
+ "match_field_attributes": ["LABEL", "NAME"],
+ "match_field_input_types": ["TEXT", "SELECT", "SEARCH"]
}
]
},
@@ -1365,8 +1365,8 @@
"positive_pattern": "^q$|search|query|qry",
"positive_score": 0.8,
"negative_pattern": null,
- "match_field_attributes": [0, 1],
- "match_field_input_types": [0, 4, 7]
+ "match_field_attributes": ["LABEL", "NAME"],
+ "match_field_input_types": ["TEXT", "TEXT_AREA", "SEARCH"]
}
],
"de": [
@@ -1375,8 +1375,8 @@
"positive_pattern": "suche.*",
"positive_score": 0.8,
"negative_pattern": null,
- "match_field_attributes": [0, 1],
- "match_field_input_types": [0, 4, 7]
+ "match_field_attributes": ["LABEL", "NAME"],
+ "match_field_input_types": ["TEXT", "TEXT_AREA", "SEARCH"]
}
],
"zh-CN": [
@@ -1385,8 +1385,8 @@
"positive_pattern": "搜索",
"positive_score": 0.8,
"negative_pattern": null,
- "match_field_attributes": [0, 1],
- "match_field_input_types": [0, 4, 7]
+ "match_field_attributes": ["LABEL", "NAME"],
+ "match_field_input_types": ["TEXT", "TEXT_AREA", "SEARCH"]
}
],
"ja": [
@@ -1395,8 +1395,8 @@
"positive_pattern": "探す|検索",
"positive_score": 0.8,
"negative_pattern": null,
- "match_field_attributes": [0, 1],
- "match_field_input_types": [0, 4, 7]
+ "match_field_attributes": ["LABEL", "NAME"],
+ "match_field_input_types": ["TEXT", "TEXT_AREA", "SEARCH"]
}
],
"fr": [
@@ -1405,8 +1405,8 @@
"positive_pattern": "recherch.*",
"positive_score": 0.8,
"negative_pattern": null,
- "match_field_attributes": [0, 1],
- "match_field_input_types": [0, 4, 7]
+ "match_field_attributes": ["LABEL", "NAME"],
+ "match_field_input_types": ["TEXT", "TEXT_AREA", "SEARCH"]
}
],
"pt": [
@@ -1415,8 +1415,8 @@
"positive_pattern": "busca",
"positive_score": 0.8,
"negative_pattern": null,
- "match_field_attributes": [0, 1],
- "match_field_input_types": [0, 4, 7]
+ "match_field_attributes": ["LABEL", "NAME"],
+ "match_field_input_types": ["TEXT", "TEXT_AREA", "SEARCH"]
}
],
"fa": [
@@ -1425,8 +1425,8 @@
"positive_pattern": "جستجو",
"positive_score": 0.8,
"negative_pattern": null,
- "match_field_attributes": [0, 1],
- "match_field_input_types": [0, 4, 7]
+ "match_field_attributes": ["LABEL", "NAME"],
+ "match_field_input_types": ["TEXT", "TEXT_AREA", "SEARCH"]
}
],
"ru": [
@@ -1435,8 +1435,8 @@
"positive_pattern": "искать|найти|поиск",
"positive_score": 0.8,
"negative_pattern": null,
- "match_field_attributes": [0, 1],
- "match_field_input_types": [0, 4, 7]
+ "match_field_attributes": ["LABEL", "NAME"],
+ "match_field_input_types": ["TEXT", "TEXT_AREA", "SEARCH"]
}
]
},
@@ -1447,8 +1447,8 @@
"positive_pattern": "\\bprice\\b|\\brate\\b|\\bcost\\b",
"positive_score": 0.95,
"negative_pattern": null,
- "match_field_attributes": [0, 1],
- "match_field_input_types": [0, 3, 4, 6, 7]
+ "match_field_attributes": ["LABEL", "NAME"],
+ "match_field_input_types": ["TEXT", "SELECT", "TEXT_AREA", "NUMBER", "SEARCH"]
}
],
"ar": [
@@ -1457,8 +1457,8 @@
"positive_pattern": "قیمة‎|سعر‎",
"positive_score": 0.95,
"negative_pattern": null,
- "match_field_attributes": [0, 1],
- "match_field_input_types": [0, 3, 4, 6, 7]
+ "match_field_attributes": ["LABEL", "NAME"],
+ "match_field_input_types": ["TEXT", "SELECT", "TEXT_AREA", "NUMBER", "SEARCH"]
}
],
"fa": [
@@ -1467,8 +1467,8 @@
"positive_pattern": "قیمت",
"positive_score": 0.95,
"negative_pattern": null,
- "match_field_attributes": [0, 1],
- "match_field_input_types": [0, 3, 4, 6, 7]
+ "match_field_attributes": ["LABEL", "NAME"],
+ "match_field_input_types": ["TEXT", "SELECT", "TEXT_AREA", "NUMBER", "SEARCH"]
}
],
"fr": [
@@ -1477,8 +1477,8 @@
"positive_pattern": "\\bprix\\b|\\bcoût\\b|\\bcout\\b|\\btarif\\b",
"positive_score": 0.95,
"negative_pattern": null,
- "match_field_attributes": [0, 1],
- "match_field_input_types": [0, 3, 4, 6, 7]
+ "match_field_attributes": ["LABEL", "NAME"],
+ "match_field_input_types": ["TEXT", "SELECT", "TEXT_AREA", "NUMBER", "SEARCH"]
}
]
},
@@ -1489,8 +1489,8 @@
"positive_pattern": "card.?(?:holder|owner)|name.*(\\b)?on(\\b)?.*card|(?:card|cc).?name|cc.?full.?name",
"positive_score": 1.0,
"negative_pattern": null,
- "match_field_attributes": [0, 1],
- "match_field_input_types": [0]
+ "match_field_attributes": ["LABEL", "NAME"],
+ "match_field_input_types": ["TEXT"]
}
],
"de": [
@@ -1499,8 +1499,8 @@
"positive_pattern": "karteninhaber",
"positive_score": 1.0,
"negative_pattern": null,
- "match_field_attributes": [0, 1],
- "match_field_input_types": [0]
+ "match_field_attributes": ["LABEL", "NAME"],
+ "match_field_input_types": ["TEXT"]
}
],
"es": [
@@ -1509,8 +1509,8 @@
"positive_pattern": "nombre.*tarjeta",
"positive_score": 1.0,
"negative_pattern": null,
- "match_field_attributes": [0, 1],
- "match_field_input_types": [0]
+ "match_field_attributes": ["LABEL", "NAME"],
+ "match_field_input_types": ["TEXT"]
}
],
"fr": [
@@ -1519,8 +1519,8 @@
"positive_pattern": "nom.*carte",
"positive_score": 1.0,
"negative_pattern": null,
- "match_field_attributes": [0, 1],
- "match_field_input_types": [0]
+ "match_field_attributes": ["LABEL", "NAME"],
+ "match_field_input_types": ["TEXT"]
}
],
"it": [
@@ -1529,8 +1529,8 @@
"positive_pattern": "nome.*cart",
"positive_score": 1.0,
"negative_pattern": null,
- "match_field_attributes": [0, 1],
- "match_field_input_types": [0]
+ "match_field_attributes": ["LABEL", "NAME"],
+ "match_field_input_types": ["TEXT"]
}
],
"ja": [
@@ -1539,8 +1539,8 @@
"positive_pattern": "名前",
"positive_score": 1.0,
"negative_pattern": null,
- "match_field_attributes": [0, 1],
- "match_field_input_types": [0]
+ "match_field_attributes": ["LABEL", "NAME"],
+ "match_field_input_types": ["TEXT"]
}
],
"ru": [
@@ -1549,8 +1549,8 @@
"positive_pattern": "Имя.*карты",
"positive_score": 1.0,
"negative_pattern": null,
- "match_field_attributes": [0, 1],
- "match_field_input_types": [0]
+ "match_field_attributes": ["LABEL", "NAME"],
+ "match_field_input_types": ["TEXT"]
}
],
"zh-CN": [
@@ -1559,8 +1559,8 @@
"positive_pattern": "信用卡开户名|开户名|持卡人姓名|持卡人姓名",
"positive_score": 1.0,
"negative_pattern": null,
- "match_field_attributes": [0, 1],
- "match_field_input_types": [0]
+ "match_field_attributes": ["LABEL", "NAME"],
+ "match_field_input_types": ["TEXT"]
}
],
"id": [
@@ -1569,8 +1569,8 @@
"positive_pattern": "nama.*kartu",
"positive_score": 1.0,
"negative_pattern": null,
- "match_field_attributes": [0, 1],
- "match_field_input_types": [0]
+ "match_field_attributes": ["LABEL", "NAME"],
+ "match_field_input_types": ["TEXT"]
}
]
},
@@ -1581,8 +1581,8 @@
"positive_pattern": "name",
"positive_score": 1.0,
"negative_pattern": null,
- "match_field_attributes": [0, 1],
- "match_field_input_types": [0]
+ "match_field_attributes": ["LABEL", "NAME"],
+ "match_field_input_types": ["TEXT"]
}
]
},
@@ -1593,8 +1593,8 @@
"positive_pattern": "(add)?(?:card|cc|acct).?(?:number|#|no|num|field|pan)",
"positive_score": 1.0,
"negative_pattern": null,
- "match_field_attributes": [0, 1],
- "match_field_input_types": [0, 2, 5, 6]
+ "match_field_attributes": ["LABEL", "NAME"],
+ "match_field_input_types": ["TEXT", "TELEPHONE", "PASSWORD", "NUMBER"]
}
],
"de": [
@@ -1603,8 +1603,8 @@
"positive_pattern": "(?<!telefon|haus|person|fødsels|kunden)nummer",
"positive_score": 1.0,
"negative_pattern": null,
- "match_field_attributes": [0, 1],
- "match_field_input_types": [0, 2, 5, 6]
+ "match_field_attributes": ["LABEL", "NAME"],
+ "match_field_input_types": ["TEXT", "TELEPHONE", "PASSWORD", "NUMBER"]
}
],
"ja": [
@@ -1613,8 +1613,8 @@
"positive_pattern": "カード番号",
"positive_score": 1.0,
"negative_pattern": null,
- "match_field_attributes": [0, 1],
- "match_field_input_types": [0, 2, 5, 6]
+ "match_field_attributes": ["LABEL", "NAME"],
+ "match_field_input_types": ["TEXT", "TELEPHONE", "PASSWORD", "NUMBER"]
}
],
"ru": [
@@ -1623,8 +1623,8 @@
"positive_pattern": "Номер.*карты",
"positive_score": 1.0,
"negative_pattern": null,
- "match_field_attributes": [0, 1],
- "match_field_input_types": [0, 2, 5, 6]
+ "match_field_attributes": ["LABEL", "NAME"],
+ "match_field_input_types": ["TEXT", "TELEPHONE", "PASSWORD", "NUMBER"]
}
],
"zh-CN": [
@@ -1633,8 +1633,8 @@
"positive_pattern": "信用卡号|信用卡号码",
"positive_score": 1.0,
"negative_pattern": null,
- "match_field_attributes": [0, 1],
- "match_field_input_types": [0, 2, 5, 6]
+ "match_field_attributes": ["LABEL", "NAME"],
+ "match_field_input_types": ["TEXT", "TELEPHONE", "PASSWORD", "NUMBER"]
}
],
"zh-TW": [
@@ -1643,8 +1643,8 @@
"positive_pattern": "信用卡卡號",
"positive_score": 1.0,
"negative_pattern": null,
- "match_field_attributes": [0, 1],
- "match_field_input_types": [0, 2, 5, 6]
+ "match_field_attributes": ["LABEL", "NAME"],
+ "match_field_input_types": ["TEXT", "TELEPHONE", "PASSWORD", "NUMBER"]
}
],
"ko": [
@@ -1653,8 +1653,8 @@
"positive_pattern": "카드",
"positive_score": 1.0,
"negative_pattern": null,
- "match_field_attributes": [0, 1],
- "match_field_input_types": [0, 2, 5, 6]
+ "match_field_attributes": ["LABEL", "NAME"],
+ "match_field_input_types": ["TEXT", "TELEPHONE", "PASSWORD", "NUMBER"]
}
],
"es": [
@@ -1663,8 +1663,8 @@
"positive_pattern": "(numero|número|numéro)(?!.*(document|fono|phone|réservation))",
"positive_score": 1.0,
"negative_pattern": null,
- "match_field_attributes": [0, 1],
- "match_field_input_types": [0, 2, 5, 6]
+ "match_field_attributes": ["LABEL", "NAME"],
+ "match_field_input_types": ["TEXT", "TELEPHONE", "PASSWORD", "NUMBER"]
}
],
"pt": [
@@ -1673,8 +1673,8 @@
"positive_pattern": "(numero|número|numéro)(?!.*(document|fono|phone|réservation))",
"positive_score": 1.0,
"negative_pattern": null,
- "match_field_attributes": [0, 1],
- "match_field_input_types": [0, 2, 5, 6]
+ "match_field_attributes": ["LABEL", "NAME"],
+ "match_field_input_types": ["TEXT", "TELEPHONE", "PASSWORD", "NUMBER"]
}
],
"fr": [
@@ -1683,8 +1683,8 @@
"positive_pattern": "(numero|número|numéro)(?!.*(document|fono|phone|réservation))",
"positive_score": 1.0,
"negative_pattern": null,
- "match_field_attributes": [0, 1],
- "match_field_input_types": [0, 2, 5, 6]
+ "match_field_attributes": ["LABEL", "NAME"],
+ "match_field_input_types": ["TEXT", "TELEPHONE", "PASSWORD", "NUMBER"]
}
],
"id": [
@@ -1693,8 +1693,8 @@
"positive_pattern": "no.*kartu",
"positive_score": 1.0,
"negative_pattern": null,
- "match_field_attributes": [0, 1],
- "match_field_input_types": [0, 2, 5, 6]
+ "match_field_attributes": ["LABEL", "NAME"],
+ "match_field_input_types": ["TEXT", "TELEPHONE", "PASSWORD", "NUMBER"]
}
]
},
@@ -1705,8 +1705,8 @@
"positive_pattern": "verification|card.?identification|security.?code|card.?code|security.?value|security.?number|card.?pin|c-v-v|(cvn|cvv|cvc|csc|cvd|cid|ccv)(field)?|\\bcid\\b",
"positive_score": 1.0,
"negative_pattern": null,
- "match_field_attributes": [0, 1],
- "match_field_input_types": [0, 2, 5, 6]
+ "match_field_attributes": ["LABEL", "NAME"],
+ "match_field_input_types": ["TEXT", "TELEPHONE", "PASSWORD", "NUMBER"]
}
]
},
@@ -1717,8 +1717,8 @@
"positive_pattern": "expir|exp.*mo|exp.*date|ccmonth|cardmonth|addmonth",
"positive_score": 1.0,
"negative_pattern": null,
- "match_field_attributes": [0, 1],
- "match_field_input_types": [0, 2, 3, 6, 7]
+ "match_field_attributes": ["LABEL", "NAME"],
+ "match_field_input_types": ["TEXT", "TELEPHONE", "SELECT", "NUMBER", "SEARCH"]
}
],
"de": [
@@ -1727,8 +1727,8 @@
"positive_pattern": "gueltig|gültig|monat",
"positive_score": 1.0,
"negative_pattern": null,
- "match_field_attributes": [0, 1],
- "match_field_input_types": [0, 2, 3, 6, 7]
+ "match_field_attributes": ["LABEL", "NAME"],
+ "match_field_input_types": ["TEXT", "TELEPHONE", "SELECT", "NUMBER", "SEARCH"]
}
],
"es": [
@@ -1737,8 +1737,8 @@
"positive_pattern": "fecha",
"positive_score": 1.0,
"negative_pattern": null,
- "match_field_attributes": [0, 1],
- "match_field_input_types": [0, 2, 3, 6, 7]
+ "match_field_attributes": ["LABEL", "NAME"],
+ "match_field_input_types": ["TEXT", "TELEPHONE", "SELECT", "NUMBER", "SEARCH"]
}
],
"fr": [
@@ -1747,8 +1747,8 @@
"positive_pattern": "date.*exp",
"positive_score": 1.0,
"negative_pattern": null,
- "match_field_attributes": [0, 1],
- "match_field_input_types": [0, 2, 3, 6, 7]
+ "match_field_attributes": ["LABEL", "NAME"],
+ "match_field_input_types": ["TEXT", "TELEPHONE", "SELECT", "NUMBER", "SEARCH"]
}
],
"it": [
@@ -1757,8 +1757,8 @@
"positive_pattern": "scadenza",
"positive_score": 1.0,
"negative_pattern": null,
- "match_field_attributes": [0, 1],
- "match_field_input_types": [0, 2, 3, 6, 7]
+ "match_field_attributes": ["LABEL", "NAME"],
+ "match_field_input_types": ["TEXT", "TELEPHONE", "SELECT", "NUMBER", "SEARCH"]
}
],
"ja": [
@@ -1767,8 +1767,8 @@
"positive_pattern": "有効期限",
"positive_score": 1.0,
"negative_pattern": null,
- "match_field_attributes": [0, 1],
- "match_field_input_types": [0, 2, 3, 6, 7]
+ "match_field_attributes": ["LABEL", "NAME"],
+ "match_field_input_types": ["TEXT", "TELEPHONE", "SELECT", "NUMBER", "SEARCH"]
}
],
"pt": [
@@ -1777,8 +1777,8 @@
"positive_pattern": "validade",
"positive_score": 1.0,
"negative_pattern": null,
- "match_field_attributes": [0, 1],
- "match_field_input_types": [0, 2, 3, 6, 7]
+ "match_field_attributes": ["LABEL", "NAME"],
+ "match_field_input_types": ["TEXT", "TELEPHONE", "SELECT", "NUMBER", "SEARCH"]
}
],
"ru": [
@@ -1787,8 +1787,8 @@
"positive_pattern": "Срок действия карты",
"positive_score": 1.0,
"negative_pattern": null,
- "match_field_attributes": [0, 1],
- "match_field_input_types": [0, 2, 3, 6, 7]
+ "match_field_attributes": ["LABEL", "NAME"],
+ "match_field_input_types": ["TEXT", "TELEPHONE", "SELECT", "NUMBER", "SEARCH"]
}
],
"zh-CN": [
@@ -1797,8 +1797,8 @@
"positive_pattern": "月",
"positive_score": 1.0,
"negative_pattern": null,
- "match_field_attributes": [0, 1],
- "match_field_input_types": [0, 2, 3, 6, 7]
+ "match_field_attributes": ["LABEL", "NAME"],
+ "match_field_input_types": ["TEXT", "TELEPHONE", "SELECT", "NUMBER", "SEARCH"]
}
],
"id": [
@@ -1807,8 +1807,8 @@
"positive_pattern": "masa berlaku|berlaku hingga",
"positive_score": 1.0,
"negative_pattern": null,
- "match_field_attributes": [0, 1],
- "match_field_input_types": [0, 2, 3, 6, 7]
+ "match_field_attributes": ["LABEL", "NAME"],
+ "match_field_input_types": ["TEXT", "TELEPHONE", "SELECT", "NUMBER", "SEARCH"]
}
]
},
@@ -1819,8 +1819,8 @@
"positive_pattern": "exp|^/|(add)?year",
"positive_score": 1.0,
"negative_pattern": null,
- "match_field_attributes": [0, 1],
- "match_field_input_types": [0, 2, 3, 6, 7]
+ "match_field_attributes": ["LABEL", "NAME"],
+ "match_field_input_types": ["TEXT", "TELEPHONE", "SELECT", "NUMBER", "SEARCH"]
}
],
"de": [
@@ -1829,8 +1829,8 @@
"positive_pattern": "ablaufdatum|gueltig|gültig|jahr",
"positive_score": 1.0,
"negative_pattern": null,
- "match_field_attributes": [0, 1],
- "match_field_input_types": [0, 2, 3, 6, 7]
+ "match_field_attributes": ["LABEL", "NAME"],
+ "match_field_input_types": ["TEXT", "TELEPHONE", "SELECT", "NUMBER", "SEARCH"]
}
],
"es": [
@@ -1839,8 +1839,8 @@
"positive_pattern": "fecha",
"positive_score": 1.0,
"negative_pattern": null,
- "match_field_attributes": [0, 1],
- "match_field_input_types": [0, 2, 3, 6, 7]
+ "match_field_attributes": ["LABEL", "NAME"],
+ "match_field_input_types": ["TEXT", "TELEPHONE", "SELECT", "NUMBER", "SEARCH"]
}
],
"it": [
@@ -1849,8 +1849,8 @@
"positive_pattern": "scadenza",
"positive_score": 1.0,
"negative_pattern": null,
- "match_field_attributes": [0, 1],
- "match_field_input_types": [0, 2, 3, 6, 7]
+ "match_field_attributes": ["LABEL", "NAME"],
+ "match_field_input_types": ["TEXT", "TELEPHONE", "SELECT", "NUMBER", "SEARCH"]
}
],
"ja": [
@@ -1859,8 +1859,8 @@
"positive_pattern": "有効期限",
"positive_score": 1.0,
"negative_pattern": null,
- "match_field_attributes": [0, 1],
- "match_field_input_types": [0, 2, 3, 6, 7]
+ "match_field_attributes": ["LABEL", "NAME"],
+ "match_field_input_types": ["TEXT", "TELEPHONE", "SELECT", "NUMBER", "SEARCH"]
}
],
"pt": [
@@ -1869,8 +1869,8 @@
"positive_pattern": "validade",
"positive_score": 1.0,
"negative_pattern": null,
- "match_field_attributes": [0, 1],
- "match_field_input_types": [0, 2, 3, 6, 7]
+ "match_field_attributes": ["LABEL", "NAME"],
+ "match_field_input_types": ["TEXT", "TELEPHONE", "SELECT", "NUMBER", "SEARCH"]
}
],
"ru": [
@@ -1879,8 +1879,8 @@
"positive_pattern": "Срок действия карты",
"positive_score": 1.0,
"negative_pattern": null,
- "match_field_attributes": [0, 1],
- "match_field_input_types": [0, 2, 3, 6, 7]
+ "match_field_attributes": ["LABEL", "NAME"],
+ "match_field_input_types": ["TEXT", "TELEPHONE", "SELECT", "NUMBER", "SEARCH"]
}
],
"zh-CN": [
@@ -1889,8 +1889,8 @@
"positive_pattern": "年|有效期",
"positive_score": 1.0,
"negative_pattern": null,
- "match_field_attributes": [0, 1],
- "match_field_input_types": [0, 2, 3, 6, 7]
+ "match_field_attributes": ["LABEL", "NAME"],
+ "match_field_input_types": ["TEXT", "TELEPHONE", "SELECT", "NUMBER", "SEARCH"]
}
],
"id": [
@@ -1899,8 +1899,8 @@
"positive_pattern": "masa berlaku|berlaku hingga",
"positive_score": 1.0,
"negative_pattern": null,
- "match_field_attributes": [0, 1],
- "match_field_input_types": [0, 2, 3, 6, 7]
+ "match_field_attributes": ["LABEL", "NAME"],
+ "match_field_input_types": ["TEXT", "TELEPHONE", "SELECT", "NUMBER", "SEARCH"]
}
]
},
@@ -1911,8 +1911,8 @@
"positive_pattern": "(?:exp.*date[^y\\n\\r]*|mm\\s*[-/]?\\s*)yy(?:[^y]|$)",
"positive_score": 1.0,
"negative_pattern": null,
- "match_field_attributes": [0, 1],
- "match_field_input_types": [0, 2, 3, 6, 7]
+ "match_field_attributes": ["LABEL", "NAME"],
+ "match_field_input_types": ["TEXT", "TELEPHONE", "SELECT", "NUMBER", "SEARCH"]
}
]
},
@@ -1923,8 +1923,8 @@
"positive_pattern": "(?:exp.*date[^y\\n\\r]*|mm\\s*[-/]?\\s*)yyyy(?:[^y]|$)",
"positive_score": 1.0,
"negative_pattern": null,
- "match_field_attributes": [0, 1],
- "match_field_input_types": [0, 2, 3, 6, 7]
+ "match_field_attributes": ["LABEL", "NAME"],
+ "match_field_input_types": ["TEXT", "TELEPHONE", "SELECT", "NUMBER", "SEARCH"]
}
]
},
@@ -1935,8 +1935,8 @@
"positive_pattern": "expir|exp.*date|^expfield$",
"positive_score": 1.0,
"negative_pattern": null,
- "match_field_attributes": [0, 1],
- "match_field_input_types": [0, 2, 3, 6, 7]
+ "match_field_attributes": ["LABEL", "NAME"],
+ "match_field_input_types": ["TEXT", "TELEPHONE", "SELECT", "NUMBER", "SEARCH"]
}
],
"de": [
@@ -1945,8 +1945,8 @@
"positive_pattern": "gueltig|gültig",
"positive_score": 1.0,
"negative_pattern": null,
- "match_field_attributes": [0, 1],
- "match_field_input_types": [0, 2, 3, 6, 7]
+ "match_field_attributes": ["LABEL", "NAME"],
+ "match_field_input_types": ["TEXT", "TELEPHONE", "SELECT", "NUMBER", "SEARCH"]
}
],
"es": [
@@ -1955,8 +1955,8 @@
"positive_pattern": "fecha",
"positive_score": 1.0,
"negative_pattern": null,
- "match_field_attributes": [0, 1],
- "match_field_input_types": [0, 2, 3, 6, 7]
+ "match_field_attributes": ["LABEL", "NAME"],
+ "match_field_input_types": ["TEXT", "TELEPHONE", "SELECT", "NUMBER", "SEARCH"]
}
],
"fr": [
@@ -1965,8 +1965,8 @@
"positive_pattern": "date.*exp",
"positive_score": 1.0,
"negative_pattern": null,
- "match_field_attributes": [0, 1],
- "match_field_input_types": [0, 2, 3, 6, 7]
+ "match_field_attributes": ["LABEL", "NAME"],
+ "match_field_input_types": ["TEXT", "TELEPHONE", "SELECT", "NUMBER", "SEARCH"]
}
],
"it": [
@@ -1975,8 +1975,8 @@
"positive_pattern": "scadenza",
"positive_score": 1.0,
"negative_pattern": null,
- "match_field_attributes": [0, 1],
- "match_field_input_types": [0, 2, 3, 6, 7]
+ "match_field_attributes": ["LABEL", "NAME"],
+ "match_field_input_types": ["TEXT", "TELEPHONE", "SELECT", "NUMBER", "SEARCH"]
}
],
"ja": [
@@ -1985,8 +1985,8 @@
"positive_pattern": "有効期限",
"positive_score": 1.0,
"negative_pattern": null,
- "match_field_attributes": [0, 1],
- "match_field_input_types": [0, 2, 3, 6, 7]
+ "match_field_attributes": ["LABEL", "NAME"],
+ "match_field_input_types": ["TEXT", "TELEPHONE", "SELECT", "NUMBER", "SEARCH"]
}
],
"pt": [
@@ -1995,8 +1995,8 @@
"positive_pattern": "validade",
"positive_score": 1.0,
"negative_pattern": null,
- "match_field_attributes": [0, 1],
- "match_field_input_types": [0, 2, 3, 6, 7]
+ "match_field_attributes": ["LABEL", "NAME"],
+ "match_field_input_types": ["TEXT", "TELEPHONE", "SELECT", "NUMBER", "SEARCH"]
}
],
"ru": [
@@ -2005,8 +2005,8 @@
"positive_pattern": "Срок действия карты",
"positive_score": 1.0,
"negative_pattern": null,
- "match_field_attributes": [0, 1],
- "match_field_input_types": [0, 2, 3, 6, 7]
+ "match_field_attributes": ["LABEL", "NAME"],
+ "match_field_input_types": ["TEXT", "TELEPHONE", "SELECT", "NUMBER", "SEARCH"]
}
]
},
@@ -2017,8 +2017,8 @@
"positive_pattern": "^mm$",
"positive_score": 1.0,
"negative_pattern": null,
- "match_field_attributes": [0, 1],
- "match_field_input_types": [0, 2, 3, 6, 7]
+ "match_field_attributes": ["LABEL", "NAME"],
+ "match_field_input_types": ["TEXT", "TELEPHONE", "SELECT", "NUMBER", "SEARCH"]
}
]
},
@@ -2029,8 +2029,8 @@
"positive_pattern": "^(yy|yyyy)$",
"positive_score": 1.0,
"negative_pattern": null,
- "match_field_attributes": [0, 1],
- "match_field_input_types": [0, 2, 3, 6, 7]
+ "match_field_attributes": ["LABEL", "NAME"],
+ "match_field_input_types": ["TEXT", "TELEPHONE", "SELECT", "NUMBER", "SEARCH"]
}
]
},
@@ -2041,8 +2041,8 @@
"positive_pattern": "gift.?(card|cert)",
"positive_score": 1.0,
"negative_pattern": null,
- "match_field_attributes": [0, 1],
- "match_field_input_types": [0, 2, 6, 7]
+ "match_field_attributes": ["LABEL", "NAME"],
+ "match_field_input_types": ["TEXT", "TELEPHONE", "NUMBER", "SEARCH"]
}
]
},
@@ -2053,8 +2053,8 @@
"positive_pattern": "(?:visa|mastercard|discover|amex|american express).*gift.?card",
"positive_score": 1.0,
"negative_pattern": null,
- "match_field_attributes": [0, 1],
- "match_field_input_types": [0, 2, 6, 7]
+ "match_field_attributes": ["LABEL", "NAME"],
+ "match_field_input_types": ["TEXT", "TELEPHONE", "NUMBER", "SEARCH"]
}
]
},
@@ -2065,8 +2065,8 @@
"positive_pattern": "debit.*card",
"positive_score": 1.0,
"negative_pattern": null,
- "match_field_attributes": [0, 1],
- "match_field_input_types": [0, 2, 6, 7]
+ "match_field_attributes": ["LABEL", "NAME"],
+ "match_field_input_types": ["TEXT", "TELEPHONE", "NUMBER", "SEARCH"]
}
]
},
@@ -2077,8 +2077,8 @@
"positive_pattern": "day",
"positive_score": 1.0,
"negative_pattern": null,
- "match_field_attributes": [0, 1],
- "match_field_input_types": [0, 3]
+ "match_field_attributes": ["LABEL", "NAME"],
+ "match_field_input_types": ["TEXT", "SELECT"]
}
]
},
@@ -2089,8 +2089,8 @@
"positive_pattern": "e.?mail",
"positive_score": 1.4,
"negative_pattern": null,
- "match_field_attributes": [0, 1],
- "match_field_input_types": [0, 1]
+ "match_field_attributes": ["LABEL", "NAME"],
+ "match_field_input_types": ["TEXT", "EMAIL"]
}
],
"fr": [
@@ -2099,8 +2099,8 @@
"positive_pattern": "courriel",
"positive_score": 1.4,
"negative_pattern": null,
- "match_field_attributes": [0, 1],
- "match_field_input_types": [0, 1]
+ "match_field_attributes": ["LABEL", "NAME"],
+ "match_field_input_types": ["TEXT", "EMAIL"]
}
],
"es": [
@@ -2109,8 +2109,8 @@
"positive_pattern": "correo.*electr(o|ó)nico",
"positive_score": 1.4,
"negative_pattern": null,
- "match_field_attributes": [0, 1],
- "match_field_input_types": [0, 1]
+ "match_field_attributes": ["LABEL", "NAME"],
+ "match_field_input_types": ["TEXT", "EMAIL"]
}
],
"ja": [
@@ -2119,8 +2119,8 @@
"positive_pattern": "メールアドレス",
"positive_score": 1.4,
"negative_pattern": null,
- "match_field_attributes": [0, 1],
- "match_field_input_types": [0, 1]
+ "match_field_attributes": ["LABEL", "NAME"],
+ "match_field_input_types": ["TEXT", "EMAIL"]
}
],
"ru": [
@@ -2129,8 +2129,8 @@
"positive_pattern": "Электронн(ая|ой).?Почт(а|ы)",
"positive_score": 1.4,
"negative_pattern": null,
- "match_field_attributes": [0, 1],
- "match_field_input_types": [0, 1]
+ "match_field_attributes": ["LABEL", "NAME"],
+ "match_field_input_types": ["TEXT", "EMAIL"]
}
],
"zh-CN": [
@@ -2139,8 +2139,8 @@
"positive_pattern": "邮件|邮箱|電子郵件",
"positive_score": 1.4,
"negative_pattern": null,
- "match_field_attributes": [0, 1],
- "match_field_input_types": [0, 1]
+ "match_field_attributes": ["LABEL", "NAME"],
+ "match_field_input_types": ["TEXT", "EMAIL"]
}
],
"zh-TW": [
@@ -2149,8 +2149,8 @@
"positive_pattern": "電郵地址|電子信箱",
"positive_score": 1.4,
"negative_pattern": null,
- "match_field_attributes": [0, 1],
- "match_field_input_types": [0, 1]
+ "match_field_attributes": ["LABEL", "NAME"],
+ "match_field_input_types": ["TEXT", "EMAIL"]
}
],
"ml": [
@@ -2159,8 +2159,8 @@
"positive_pattern": "ഇ-മെയില്‍|ഇലക്ട്രോണിക്.?മെയിൽ",
"positive_score": 1.4,
"negative_pattern": null,
- "match_field_attributes": [0, 1],
- "match_field_input_types": [0, 1]
+ "match_field_attributes": ["LABEL", "NAME"],
+ "match_field_input_types": ["TEXT", "EMAIL"]
}
],
"fa": [
@@ -2169,8 +2169,8 @@
"positive_pattern": "ایمیل|پست.*الکترونیک",
"positive_score": 1.4,
"negative_pattern": null,
- "match_field_attributes": [0, 1],
- "match_field_input_types": [0, 1]
+ "match_field_attributes": ["LABEL", "NAME"],
+ "match_field_input_types": ["TEXT", "EMAIL"]
}
],
"hi": [
@@ -2179,8 +2179,8 @@
"positive_pattern": "ईमेल|इलॅक्ट्रॉनिक.?मेल",
"positive_score": 1.4,
"negative_pattern": null,
- "match_field_attributes": [0, 1],
- "match_field_input_types": [0, 1]
+ "match_field_attributes": ["LABEL", "NAME"],
+ "match_field_input_types": ["TEXT", "EMAIL"]
}
],
"tr": [
@@ -2189,8 +2189,8 @@
"positive_pattern": "(\\b|_)eposta(\\b|_)",
"positive_score": 1.4,
"negative_pattern": null,
- "match_field_attributes": [0, 1],
- "match_field_input_types": [0, 1]
+ "match_field_attributes": ["LABEL", "NAME"],
+ "match_field_input_types": ["TEXT", "EMAIL"]
}
],
"ko": [
@@ -2199,8 +2199,8 @@
"positive_pattern": "(?:이메일|전자.?우편|[Ee]-?mail)(.?주소)?",
"positive_score": 1.4,
"negative_pattern": null,
- "match_field_attributes": [0, 1],
- "match_field_input_types": [0, 1]
+ "match_field_attributes": ["LABEL", "NAME"],
+ "match_field_input_types": ["TEXT", "EMAIL"]
}
]
},
@@ -2211,8 +2211,8 @@
"positive_pattern": "user.?name|user.?id|nickname|maiden name|title|prefix|suffix|mail",
"positive_score": 0.9,
"negative_pattern": null,
- "match_field_attributes": [0, 1],
- "match_field_input_types": [0, 3, 7]
+ "match_field_attributes": ["LABEL", "NAME"],
+ "match_field_input_types": ["TEXT", "SELECT", "SEARCH"]
}
],
"de": [
@@ -2221,8 +2221,8 @@
"positive_pattern": "vollständiger.?name",
"positive_score": 0.9,
"negative_pattern": null,
- "match_field_attributes": [0, 1],
- "match_field_input_types": [0, 3, 7]
+ "match_field_attributes": ["LABEL", "NAME"],
+ "match_field_input_types": ["TEXT", "SELECT", "SEARCH"]
}
],
"zh-CN": [
@@ -2231,8 +2231,8 @@
"positive_pattern": "用户名",
"positive_score": 0.9,
"negative_pattern": null,
- "match_field_attributes": [0, 1],
- "match_field_input_types": [0, 3, 7]
+ "match_field_attributes": ["LABEL", "NAME"],
+ "match_field_input_types": ["TEXT", "SELECT", "SEARCH"]
}
],
"ko": [
@@ -2241,8 +2241,8 @@
"positive_pattern": "(?:사용자.?)?아이디|사용자.?ID",
"positive_score": 0.9,
"negative_pattern": null,
- "match_field_attributes": [0, 1],
- "match_field_input_types": [0, 3, 7]
+ "match_field_attributes": ["LABEL", "NAME"],
+ "match_field_input_types": ["TEXT", "SELECT", "SEARCH"]
}
]
},
@@ -2253,8 +2253,8 @@
"positive_pattern": "^name|full.?name|your.?name|customer.?name|bill.?name|ship.?name|name.*first.*last|firstandlastname|contact.?(name|person)",
"positive_score": 0.9,
"negative_pattern": null,
- "match_field_attributes": [0, 1],
- "match_field_input_types": [0]
+ "match_field_attributes": ["LABEL", "NAME"],
+ "match_field_input_types": ["TEXT"]
}
],
"es": [
@@ -2263,8 +2263,8 @@
"positive_pattern": "nombre.*y.*apellidos",
"positive_score": 0.9,
"negative_pattern": null,
- "match_field_attributes": [0, 1],
- "match_field_input_types": [0]
+ "match_field_attributes": ["LABEL", "NAME"],
+ "match_field_input_types": ["TEXT"]
}
],
"fr": [
@@ -2273,8 +2273,8 @@
"positive_pattern": "^nom(?![a-zA-Z])",
"positive_score": 0.9,
"negative_pattern": null,
- "match_field_attributes": [0, 1],
- "match_field_input_types": [0]
+ "match_field_attributes": ["LABEL", "NAME"],
+ "match_field_input_types": ["TEXT"]
}
],
"ja": [
@@ -2283,8 +2283,8 @@
"positive_pattern": "お名前|氏名",
"positive_score": 0.9,
"negative_pattern": null,
- "match_field_attributes": [0, 1],
- "match_field_input_types": [0]
+ "match_field_attributes": ["LABEL", "NAME"],
+ "match_field_input_types": ["TEXT"]
}
],
"pt": [
@@ -2293,8 +2293,8 @@
"positive_pattern": "^nome",
"positive_score": 0.9,
"negative_pattern": null,
- "match_field_attributes": [0, 1],
- "match_field_input_types": [0]
+ "match_field_attributes": ["LABEL", "NAME"],
+ "match_field_input_types": ["TEXT"]
}
],
"fa": [
@@ -2303,8 +2303,8 @@
"positive_pattern": "نام.*نام.*خانوادگی",
"positive_score": 0.9,
"negative_pattern": null,
- "match_field_attributes": [0, 1],
- "match_field_input_types": [0]
+ "match_field_attributes": ["LABEL", "NAME"],
+ "match_field_input_types": ["TEXT"]
}
],
"zh-CN": [
@@ -2313,8 +2313,8 @@
"positive_pattern": "姓\\s*名",
"positive_score": 0.9,
"negative_pattern": null,
- "match_field_attributes": [0, 1],
- "match_field_input_types": [0]
+ "match_field_attributes": ["LABEL", "NAME"],
+ "match_field_input_types": ["TEXT"]
}
],
"ru": [
@@ -2323,8 +2323,8 @@
"positive_pattern": "контактное.?лицо",
"positive_score": 0.9,
"negative_pattern": null,
- "match_field_attributes": [0, 1],
- "match_field_input_types": [0]
+ "match_field_attributes": ["LABEL", "NAME"],
+ "match_field_input_types": ["TEXT"]
}
],
"tr": [
@@ -2333,8 +2333,8 @@
"positive_pattern": "(\\b|_|\\*)ad[ı]? soyad[ı]?(\\b|_|\\*)",
"positive_score": 0.9,
"negative_pattern": null,
- "match_field_attributes": [0, 1],
- "match_field_input_types": [0]
+ "match_field_attributes": ["LABEL", "NAME"],
+ "match_field_input_types": ["TEXT"]
}
],
"ko": [
@@ -2343,8 +2343,8 @@
"positive_pattern": "성명",
"positive_score": 0.9,
"negative_pattern": null,
- "match_field_attributes": [0, 1],
- "match_field_input_types": [0]
+ "match_field_attributes": ["LABEL", "NAME"],
+ "match_field_input_types": ["TEXT"]
}
],
"id": [
@@ -2353,8 +2353,8 @@
"positive_pattern": "nama.?(lengkap|penerima|kamu)",
"positive_score": 0.9,
"negative_pattern": null,
- "match_field_attributes": [0, 1],
- "match_field_input_types": [0]
+ "match_field_attributes": ["LABEL", "NAME"],
+ "match_field_input_types": ["TEXT"]
}
]
},
@@ -2365,8 +2365,8 @@
"positive_pattern": "^name",
"positive_score": 0.9,
"negative_pattern": null,
- "match_field_attributes": [0, 1],
- "match_field_input_types": [0]
+ "match_field_attributes": ["LABEL", "NAME"],
+ "match_field_input_types": ["TEXT"]
}
],
"fr": [
@@ -2375,8 +2375,8 @@
"positive_pattern": "^nom",
"positive_score": 0.9,
"negative_pattern": null,
- "match_field_attributes": [0, 1],
- "match_field_input_types": [0]
+ "match_field_attributes": ["LABEL", "NAME"],
+ "match_field_input_types": ["TEXT"]
}
],
"pt": [
@@ -2385,8 +2385,8 @@
"positive_pattern": "^nome",
"positive_score": 0.9,
"negative_pattern": null,
- "match_field_attributes": [0, 1],
- "match_field_input_types": [0]
+ "match_field_attributes": ["LABEL", "NAME"],
+ "match_field_input_types": ["TEXT"]
}
]
},
@@ -2397,8 +2397,8 @@
"positive_pattern": "first.*name|initials|fname|first$|given.*name",
"positive_score": 0.9,
"negative_pattern": null,
- "match_field_attributes": [0, 1],
- "match_field_input_types": [0]
+ "match_field_attributes": ["LABEL", "NAME"],
+ "match_field_input_types": ["TEXT"]
}
],
"de": [
@@ -2407,8 +2407,8 @@
"positive_pattern": "vorname",
"positive_score": 0.9,
"negative_pattern": null,
- "match_field_attributes": [0, 1],
- "match_field_input_types": [0]
+ "match_field_attributes": ["LABEL", "NAME"],
+ "match_field_input_types": ["TEXT"]
}
],
"es": [
@@ -2417,8 +2417,8 @@
"positive_pattern": "nombre",
"positive_score": 0.9,
"negative_pattern": null,
- "match_field_attributes": [0, 1],
- "match_field_input_types": [0]
+ "match_field_attributes": ["LABEL", "NAME"],
+ "match_field_input_types": ["TEXT"]
}
],
"fr": [
@@ -2427,8 +2427,8 @@
"positive_pattern": "forename|prénom|prenom",
"positive_score": 0.9,
"negative_pattern": null,
- "match_field_attributes": [0, 1],
- "match_field_input_types": [0]
+ "match_field_attributes": ["LABEL", "NAME"],
+ "match_field_input_types": ["TEXT"]
}
],
"ja": [
@@ -2437,8 +2437,8 @@
"positive_pattern": "名",
"positive_score": 0.9,
"negative_pattern": null,
- "match_field_attributes": [0, 1],
- "match_field_input_types": [0]
+ "match_field_attributes": ["LABEL", "NAME"],
+ "match_field_input_types": ["TEXT"]
}
],
"pt": [
@@ -2447,8 +2447,8 @@
"positive_pattern": "nome",
"positive_score": 0.9,
"negative_pattern": null,
- "match_field_attributes": [0, 1],
- "match_field_input_types": [0]
+ "match_field_attributes": ["LABEL", "NAME"],
+ "match_field_input_types": ["TEXT"]
}
],
"ru": [
@@ -2457,8 +2457,8 @@
"positive_pattern": "Имя",
"positive_score": 0.9,
"negative_pattern": null,
- "match_field_attributes": [0, 1],
- "match_field_input_types": [0]
+ "match_field_attributes": ["LABEL", "NAME"],
+ "match_field_input_types": ["TEXT"]
}
],
"fa": [
@@ -2467,8 +2467,8 @@
"positive_pattern": "نام",
"positive_score": 0.9,
"negative_pattern": null,
- "match_field_attributes": [0, 1],
- "match_field_input_types": [0]
+ "match_field_attributes": ["LABEL", "NAME"],
+ "match_field_input_types": ["TEXT"]
}
],
"ko": [
@@ -2477,8 +2477,8 @@
"positive_pattern": "이름",
"positive_score": 0.9,
"negative_pattern": null,
- "match_field_attributes": [0, 1],
- "match_field_input_types": [0]
+ "match_field_attributes": ["LABEL", "NAME"],
+ "match_field_input_types": ["TEXT"]
}
],
"ml": [
@@ -2487,8 +2487,8 @@
"positive_pattern": "പേര്",
"positive_score": 0.9,
"negative_pattern": null,
- "match_field_attributes": [0, 1],
- "match_field_input_types": [0]
+ "match_field_attributes": ["LABEL", "NAME"],
+ "match_field_input_types": ["TEXT"]
}
],
"tr": [
@@ -2497,8 +2497,8 @@
"positive_pattern": "(\\b|_|\\*)(isim|ad|ad(i|ı|iniz|ınız)?)(\\b|_|\\*)",
"positive_score": 0.9,
"negative_pattern": null,
- "match_field_attributes": [0, 1],
- "match_field_input_types": [0]
+ "match_field_attributes": ["LABEL", "NAME"],
+ "match_field_input_types": ["TEXT"]
}
],
"hi": [
@@ -2507,8 +2507,8 @@
"positive_pattern": "नाम",
"positive_score": 0.9,
"negative_pattern": null,
- "match_field_attributes": [0, 1],
- "match_field_input_types": [0]
+ "match_field_attributes": ["LABEL", "NAME"],
+ "match_field_input_types": ["TEXT"]
}
],
"id": [
@@ -2517,8 +2517,8 @@
"positive_pattern": "nama depan",
"positive_score": 0.9,
"negative_pattern": null,
- "match_field_attributes": [0, 1],
- "match_field_input_types": [0]
+ "match_field_attributes": ["LABEL", "NAME"],
+ "match_field_input_types": ["TEXT"]
}
]
},
@@ -2529,8 +2529,8 @@
"positive_pattern": "middle.*initial|m\\.i\\.|mi$|\\bmi\\b",
"positive_score": 0.9,
"negative_pattern": null,
- "match_field_attributes": [0, 1],
- "match_field_input_types": [0]
+ "match_field_attributes": ["LABEL", "NAME"],
+ "match_field_input_types": ["TEXT"]
}
]
},
@@ -2541,8 +2541,8 @@
"positive_pattern": "middle.*name|mname|middle$",
"positive_score": 0.9,
"negative_pattern": null,
- "match_field_attributes": [0, 1],
- "match_field_input_types": [0]
+ "match_field_attributes": ["LABEL", "NAME"],
+ "match_field_input_types": ["TEXT"]
}
]
},
@@ -2553,8 +2553,8 @@
"positive_pattern": "last.*name|lname|surname(?!\\d)|last$|secondname|family.*name",
"positive_score": 0.9,
"negative_pattern": null,
- "match_field_attributes": [0, 1],
- "match_field_input_types": [0]
+ "match_field_attributes": ["LABEL", "NAME"],
+ "match_field_input_types": ["TEXT"]
}
],
"de": [
@@ -2563,8 +2563,8 @@
"positive_pattern": "nachname",
"positive_score": 0.9,
"negative_pattern": null,
- "match_field_attributes": [0, 1],
- "match_field_input_types": [0]
+ "match_field_attributes": ["LABEL", "NAME"],
+ "match_field_input_types": ["TEXT"]
}
],
"es": [
@@ -2573,8 +2573,8 @@
"positive_pattern": "apellidos?",
"positive_score": 0.9,
"negative_pattern": null,
- "match_field_attributes": [0, 1],
- "match_field_input_types": [0]
+ "match_field_attributes": ["LABEL", "NAME"],
+ "match_field_input_types": ["TEXT"]
}
],
"fr": [
@@ -2583,8 +2583,8 @@
"positive_pattern": "famille|^nom(?![a-zA-Z])",
"positive_score": 0.9,
"negative_pattern": null,
- "match_field_attributes": [0, 1],
- "match_field_input_types": [0]
+ "match_field_attributes": ["LABEL", "NAME"],
+ "match_field_input_types": ["TEXT"]
}
],
"it": [
@@ -2593,8 +2593,8 @@
"positive_pattern": "cognome",
"positive_score": 0.9,
"negative_pattern": null,
- "match_field_attributes": [0, 1],
- "match_field_input_types": [0]
+ "match_field_attributes": ["LABEL", "NAME"],
+ "match_field_input_types": ["TEXT"]
}
],
"ja": [
@@ -2603,8 +2603,8 @@
"positive_pattern": "姓",
"positive_score": 0.9,
"negative_pattern": null,
- "match_field_attributes": [0, 1],
- "match_field_input_types": [0]
+ "match_field_attributes": ["LABEL", "NAME"],
+ "match_field_input_types": ["TEXT"]
}
],
"pt": [
@@ -2613,8 +2613,8 @@
"positive_pattern": "apelidos|surename|sobrenome",
"positive_score": 0.9,
"negative_pattern": null,
- "match_field_attributes": [0, 1],
- "match_field_input_types": [0]
+ "match_field_attributes": ["LABEL", "NAME"],
+ "match_field_input_types": ["TEXT"]
}
],
"ru": [
@@ -2623,8 +2623,8 @@
"positive_pattern": "Фамилия",
"positive_score": 0.9,
"negative_pattern": null,
- "match_field_attributes": [0, 1],
- "match_field_input_types": [0]
+ "match_field_attributes": ["LABEL", "NAME"],
+ "match_field_input_types": ["TEXT"]
}
],
"fa": [
@@ -2633,8 +2633,8 @@
"positive_pattern": "نام.*خانوادگی",
"positive_score": 0.9,
"negative_pattern": null,
- "match_field_attributes": [0, 1],
- "match_field_input_types": [0]
+ "match_field_attributes": ["LABEL", "NAME"],
+ "match_field_input_types": ["TEXT"]
}
],
"hi": [
@@ -2643,8 +2643,8 @@
"positive_pattern": "उपनाम",
"positive_score": 0.9,
"negative_pattern": null,
- "match_field_attributes": [0, 1],
- "match_field_input_types": [0]
+ "match_field_attributes": ["LABEL", "NAME"],
+ "match_field_input_types": ["TEXT"]
}
],
"ml": [
@@ -2653,8 +2653,8 @@
"positive_pattern": "മറുപേര്",
"positive_score": 0.9,
"negative_pattern": null,
- "match_field_attributes": [0, 1],
- "match_field_input_types": [0]
+ "match_field_attributes": ["LABEL", "NAME"],
+ "match_field_input_types": ["TEXT"]
}
],
"tr": [
@@ -2663,8 +2663,8 @@
"positive_pattern": "(\\b|_|\\*)(soyisim|soyad(i|ı|iniz|ınız)?)(\\b|_|\\*)",
"positive_score": 0.9,
"negative_pattern": null,
- "match_field_attributes": [0, 1],
- "match_field_input_types": [0]
+ "match_field_attributes": ["LABEL", "NAME"],
+ "match_field_input_types": ["TEXT"]
}
],
"ko": [
@@ -2673,8 +2673,8 @@
"positive_pattern": "\\b성(?:[^명]|\\b)",
"positive_score": 0.9,
"negative_pattern": null,
- "match_field_attributes": [0, 1],
- "match_field_input_types": [0]
+ "match_field_attributes": ["LABEL", "NAME"],
+ "match_field_input_types": ["TEXT"]
}
],
"id": [
@@ -2683,8 +2683,8 @@
"positive_pattern": "nama belakang",
"positive_score": 0.9,
"negative_pattern": null,
- "match_field_attributes": [0, 1],
- "match_field_input_types": [0]
+ "match_field_attributes": ["LABEL", "NAME"],
+ "match_field_input_types": ["TEXT"]
}
]
},
@@ -2695,8 +2695,8 @@
"positive_pattern": "(primer.*apellido)|(apellido1)|(apellido.*paterno)|surname_?1|first(\\s|_)?surname",
"positive_score": 0.9,
"negative_pattern": null,
- "match_field_attributes": [0, 1],
- "match_field_input_types": [0]
+ "match_field_attributes": ["LABEL", "NAME"],
+ "match_field_input_types": ["TEXT"]
}
]
},
@@ -2707,8 +2707,8 @@
"positive_pattern": "(segund.*apellido)|(apellido2)|(apellido.*materno)|surname_?2|second(\\s|_)?surname",
"positive_score": 0.9,
"negative_pattern": null,
- "match_field_attributes": [0, 1],
- "match_field_input_types": [0]
+ "match_field_attributes": ["LABEL", "NAME"],
+ "match_field_input_types": ["TEXT"]
}
]
},
@@ -2719,8 +2719,8 @@
"positive_pattern": "^title:?$|(salutation(?! and given name))",
"positive_score": 0.9,
"negative_pattern": null,
- "match_field_attributes": [0, 1],
- "match_field_input_types": [0]
+ "match_field_attributes": ["LABEL", "NAME"],
+ "match_field_input_types": ["TEXT"]
}
],
"de": [
@@ -2729,8 +2729,8 @@
"positive_pattern": "anrede|titel",
"positive_score": 0.9,
"negative_pattern": null,
- "match_field_attributes": [0, 1],
- "match_field_input_types": [0]
+ "match_field_attributes": ["LABEL", "NAME"],
+ "match_field_input_types": ["TEXT"]
}
],
"es": [
@@ -2739,8 +2739,8 @@
"positive_pattern": "tratamiento|encabezamiento",
"positive_score": 0.9,
"negative_pattern": null,
- "match_field_attributes": [0, 1],
- "match_field_input_types": [0]
+ "match_field_attributes": ["LABEL", "NAME"],
+ "match_field_input_types": ["TEXT"]
}
],
"it": [
@@ -2749,8 +2749,8 @@
"positive_pattern": "titolo",
"positive_score": 0.9,
"negative_pattern": null,
- "match_field_attributes": [0, 1],
- "match_field_input_types": [0]
+ "match_field_attributes": ["LABEL", "NAME"],
+ "match_field_input_types": ["TEXT"]
}
],
"fr": [
@@ -2759,8 +2759,8 @@
"positive_pattern": "titre",
"positive_score": 0.9,
"negative_pattern": null,
- "match_field_attributes": [0, 1],
- "match_field_input_types": [0]
+ "match_field_attributes": ["LABEL", "NAME"],
+ "match_field_input_types": ["TEXT"]
}
],
"ru": [
@@ -2769,8 +2769,8 @@
"positive_pattern": "обращение|звание",
"positive_score": 0.9,
"negative_pattern": null,
- "match_field_attributes": [0, 1],
- "match_field_input_types": [0]
+ "match_field_attributes": ["LABEL", "NAME"],
+ "match_field_input_types": ["TEXT"]
}
],
"el": [
@@ -2779,8 +2779,8 @@
"positive_pattern": "προσφώνηση",
"positive_score": 0.9,
"negative_pattern": null,
- "match_field_attributes": [0, 1],
- "match_field_input_types": [0]
+ "match_field_attributes": ["LABEL", "NAME"],
+ "match_field_input_types": ["TEXT"]
}
],
"tr": [
@@ -2789,8 +2789,8 @@
"positive_pattern": "hitap",
"positive_score": 0.9,
"negative_pattern": null,
- "match_field_attributes": [0, 1],
- "match_field_input_types": [0]
+ "match_field_attributes": ["LABEL", "NAME"],
+ "match_field_input_types": ["TEXT"]
}
]
},
@@ -2801,8 +2801,8 @@
"positive_pattern": "phone|mobile|contact.?number",
"positive_score": 1.2,
"negative_pattern": null,
- "match_field_attributes": [0, 1],
- "match_field_input_types": [0, 2, 6]
+ "match_field_attributes": ["LABEL", "NAME"],
+ "match_field_input_types": ["TEXT", "TELEPHONE", "NUMBER"]
}
],
"de": [
@@ -2811,8 +2811,8 @@
"positive_pattern": "telefonnummer",
"positive_score": 1.2,
"negative_pattern": null,
- "match_field_attributes": [0, 1],
- "match_field_input_types": [0, 2, 6]
+ "match_field_attributes": ["LABEL", "NAME"],
+ "match_field_input_types": ["TEXT", "TELEPHONE", "NUMBER"]
}
],
"es": [
@@ -2821,8 +2821,8 @@
"positive_pattern": "telefono|teléfono",
"positive_score": 1.2,
"negative_pattern": null,
- "match_field_attributes": [0, 1],
- "match_field_input_types": [0, 2, 6]
+ "match_field_attributes": ["LABEL", "NAME"],
+ "match_field_input_types": ["TEXT", "TELEPHONE", "NUMBER"]
}
],
"fr": [
@@ -2831,8 +2831,8 @@
"positive_pattern": "telfixe",
"positive_score": 1.2,
"negative_pattern": null,
- "match_field_attributes": [0, 1],
- "match_field_input_types": [0, 2, 6]
+ "match_field_attributes": ["LABEL", "NAME"],
+ "match_field_input_types": ["TEXT", "TELEPHONE", "NUMBER"]
}
],
"ja": [
@@ -2841,8 +2841,8 @@
"positive_pattern": "電話",
"positive_score": 1.2,
"negative_pattern": null,
- "match_field_attributes": [0, 1],
- "match_field_input_types": [0, 2, 6]
+ "match_field_attributes": ["LABEL", "NAME"],
+ "match_field_input_types": ["TEXT", "TELEPHONE", "NUMBER"]
}
],
"pt": [
@@ -2851,8 +2851,8 @@
"positive_pattern": "telefone|telemovel",
"positive_score": 1.2,
"negative_pattern": null,
- "match_field_attributes": [0, 1],
- "match_field_input_types": [0, 2, 6]
+ "match_field_attributes": ["LABEL", "NAME"],
+ "match_field_input_types": ["TEXT", "TELEPHONE", "NUMBER"]
}
],
"ru": [
@@ -2861,8 +2861,8 @@
"positive_pattern": "телефон",
"positive_score": 1.2,
"negative_pattern": null,
- "match_field_attributes": [0, 1],
- "match_field_input_types": [0, 2, 6]
+ "match_field_attributes": ["LABEL", "NAME"],
+ "match_field_input_types": ["TEXT", "TELEPHONE", "NUMBER"]
}
],
"hi": [
@@ -2871,8 +2871,8 @@
"positive_pattern": "मोबाइल",
"positive_score": 1.2,
"negative_pattern": null,
- "match_field_attributes": [0, 1],
- "match_field_input_types": [0, 2, 6]
+ "match_field_attributes": ["LABEL", "NAME"],
+ "match_field_input_types": ["TEXT", "TELEPHONE", "NUMBER"]
}
],
"tr": [
@@ -2881,8 +2881,8 @@
"positive_pattern": "(\\b|_|\\*)telefon(\\b|_|\\*)",
"positive_score": 1.2,
"negative_pattern": null,
- "match_field_attributes": [0, 1],
- "match_field_input_types": [0, 2, 6]
+ "match_field_attributes": ["LABEL", "NAME"],
+ "match_field_input_types": ["TEXT", "TELEPHONE", "NUMBER"]
}
],
"zh-CN": [
@@ -2891,8 +2891,8 @@
"positive_pattern": "电话",
"positive_score": 1.2,
"negative_pattern": null,
- "match_field_attributes": [0, 1],
- "match_field_input_types": [0, 2, 6]
+ "match_field_attributes": ["LABEL", "NAME"],
+ "match_field_input_types": ["TEXT", "TELEPHONE", "NUMBER"]
}
],
"ml": [
@@ -2901,8 +2901,8 @@
"positive_pattern": "മൊബൈല്‍",
"positive_score": 1.2,
"negative_pattern": null,
- "match_field_attributes": [0, 1],
- "match_field_input_types": [0, 2, 6]
+ "match_field_attributes": ["LABEL", "NAME"],
+ "match_field_input_types": ["TEXT", "TELEPHONE", "NUMBER"]
}
],
"ko": [
@@ -2911,8 +2911,8 @@
"positive_pattern": "(?:전화|핸드폰|휴대폰|휴대전화)(?:.?번호)?",
"positive_score": 1.2,
"negative_pattern": null,
- "match_field_attributes": [0, 1],
- "match_field_input_types": [0, 2, 6]
+ "match_field_attributes": ["LABEL", "NAME"],
+ "match_field_input_types": ["TEXT", "TELEPHONE", "NUMBER"]
}
],
"id": [
@@ -2921,8 +2921,8 @@
"positive_pattern": "telepon|ponsel|(nomor|no\\.?).?(hp|handphone)",
"positive_score": 1.2,
"negative_pattern": null,
- "match_field_attributes": [0, 1],
- "match_field_input_types": [0, 2, 6]
+ "match_field_attributes": ["LABEL", "NAME"],
+ "match_field_input_types": ["TEXT", "TELEPHONE", "NUMBER"]
}
]
},
@@ -2933,8 +2933,8 @@
"positive_pattern": "^[^0-9+]*(?:\\+|00)\\s*([1-9]\\d{0,3})\\D*$",
"positive_score": 1.3,
"negative_pattern": null,
- "match_field_attributes": [0, 1],
- "match_field_input_types": [0]
+ "match_field_attributes": ["LABEL", "NAME"],
+ "match_field_input_types": ["TEXT"]
}
]
},
@@ -2945,8 +2945,8 @@
"positive_pattern": "country.*code|ccode|_cc|phone.*code|user.*phone.*code",
"positive_score": 1.3,
"negative_pattern": null,
- "match_field_attributes": [0, 1],
- "match_field_input_types": [0, 2, 3, 6]
+ "match_field_attributes": ["LABEL", "NAME"],
+ "match_field_input_types": ["TEXT", "TELEPHONE", "SELECT", "NUMBER"]
}
]
},
@@ -2957,8 +2957,8 @@
"positive_pattern": "^\\($",
"positive_score": 1.3,
"negative_pattern": null,
- "match_field_attributes": [0, 1],
- "match_field_input_types": [0, 2, 6]
+ "match_field_attributes": ["LABEL", "NAME"],
+ "match_field_input_types": ["TEXT", "TELEPHONE", "NUMBER"]
}
]
},
@@ -2969,8 +2969,8 @@
"positive_pattern": "area.*code|acode|area",
"positive_score": 1.3,
"negative_pattern": null,
- "match_field_attributes": [0, 1],
- "match_field_input_types": [0, 2, 6]
+ "match_field_attributes": ["LABEL", "NAME"],
+ "match_field_input_types": ["TEXT", "TELEPHONE", "NUMBER"]
}
],
"ko": [
@@ -2979,8 +2979,8 @@
"positive_pattern": "지역.?번호",
"positive_score": 1.3,
"negative_pattern": null,
- "match_field_attributes": [0, 1],
- "match_field_input_types": [0, 2, 6]
+ "match_field_attributes": ["LABEL", "NAME"],
+ "match_field_input_types": ["TEXT", "TELEPHONE", "NUMBER"]
}
]
},
@@ -2991,8 +2991,8 @@
"positive_pattern": "^-$|^\\)$",
"positive_score": 1.3,
"negative_pattern": null,
- "match_field_attributes": [0, 1],
- "match_field_input_types": [0, 2, 6]
+ "match_field_attributes": ["LABEL", "NAME"],
+ "match_field_input_types": ["TEXT", "TELEPHONE", "NUMBER"]
}
]
},
@@ -3003,8 +3003,8 @@
"positive_pattern": "^-$",
"positive_score": 1.3,
"negative_pattern": null,
- "match_field_attributes": [0, 1],
- "match_field_input_types": [0, 2, 6]
+ "match_field_attributes": ["LABEL", "NAME"],
+ "match_field_input_types": ["TEXT", "TELEPHONE", "NUMBER"]
}
]
},
@@ -3015,8 +3015,8 @@
"positive_pattern": "prefix|exchange",
"positive_score": 1.3,
"negative_pattern": null,
- "match_field_attributes": [0, 1],
- "match_field_input_types": [0, 2, 6]
+ "match_field_attributes": ["LABEL", "NAME"],
+ "match_field_input_types": ["TEXT", "TELEPHONE", "NUMBER"]
}
],
"fr": [
@@ -3025,8 +3025,8 @@
"positive_pattern": "preselection",
"positive_score": 1.3,
"negative_pattern": null,
- "match_field_attributes": [0, 1],
- "match_field_input_types": [0, 2, 6]
+ "match_field_attributes": ["LABEL", "NAME"],
+ "match_field_input_types": ["TEXT", "TELEPHONE", "NUMBER"]
}
],
"pt": [
@@ -3035,8 +3035,8 @@
"positive_pattern": "ddd",
"positive_score": 1.3,
"negative_pattern": null,
- "match_field_attributes": [0, 1],
- "match_field_input_types": [0, 2, 6]
+ "match_field_attributes": ["LABEL", "NAME"],
+ "match_field_input_types": ["TEXT", "TELEPHONE", "NUMBER"]
}
]
},
@@ -3047,8 +3047,8 @@
"positive_pattern": "suffix",
"positive_score": 1.3,
"negative_pattern": null,
- "match_field_attributes": [0, 1],
- "match_field_input_types": [0, 2, 6]
+ "match_field_attributes": ["LABEL", "NAME"],
+ "match_field_input_types": ["TEXT", "TELEPHONE", "NUMBER"]
}
]
},
@@ -3059,8 +3059,8 @@
"positive_pattern": "\\bext|ext\\b|extension",
"positive_score": 1.3,
"negative_pattern": null,
- "match_field_attributes": [0, 1],
- "match_field_input_types": [0, 2, 6]
+ "match_field_attributes": ["LABEL", "NAME"],
+ "match_field_input_types": ["TEXT", "TELEPHONE", "NUMBER"]
}
],
"pt": [
@@ -3069,8 +3069,8 @@
"positive_pattern": "ramal",
"positive_score": 1.3,
"negative_pattern": null,
- "match_field_attributes": [0, 1],
- "match_field_input_types": [0, 2, 6]
+ "match_field_attributes": ["LABEL", "NAME"],
+ "match_field_input_types": ["TEXT", "TELEPHONE", "NUMBER"]
}
]
},
@@ -3081,8 +3081,8 @@
"positive_pattern": "document.*number|passport",
"positive_score": 1.2,
"negative_pattern": null,
- "match_field_attributes": [0, 1],
- "match_field_input_types": [0]
+ "match_field_attributes": ["LABEL", "NAME"],
+ "match_field_input_types": ["TEXT"]
}
],
"fr": [
@@ -3091,8 +3091,8 @@
"positive_pattern": "passeport",
"positive_score": 1.2,
"negative_pattern": null,
- "match_field_attributes": [0, 1],
- "match_field_input_types": [0]
+ "match_field_attributes": ["LABEL", "NAME"],
+ "match_field_input_types": ["TEXT"]
}
],
"es": [
@@ -3101,8 +3101,8 @@
"positive_pattern": "numero.*documento|pasaporte",
"positive_score": 1.2,
"negative_pattern": null,
- "match_field_attributes": [0, 1],
- "match_field_input_types": [0]
+ "match_field_attributes": ["LABEL", "NAME"],
+ "match_field_input_types": ["TEXT"]
}
],
"ja": [
@@ -3111,8 +3111,8 @@
"positive_pattern": "書類",
"positive_score": 1.2,
"negative_pattern": null,
- "match_field_attributes": [0, 1],
- "match_field_input_types": [0]
+ "match_field_attributes": ["LABEL", "NAME"],
+ "match_field_input_types": ["TEXT"]
}
]
},
@@ -3123,8 +3123,8 @@
"positive_pattern": "point.*of.*entry|arrival",
"positive_score": 1.2,
"negative_pattern": null,
- "match_field_attributes": [0, 1],
- "match_field_input_types": [0]
+ "match_field_attributes": ["LABEL", "NAME"],
+ "match_field_input_types": ["TEXT"]
}
],
"es": [
@@ -3133,8 +3133,8 @@
"positive_pattern": "punto.*internaci(o|ó)n|fecha.*llegada",
"positive_score": 1.2,
"negative_pattern": null,
- "match_field_attributes": [0, 1],
- "match_field_input_types": [0]
+ "match_field_attributes": ["LABEL", "NAME"],
+ "match_field_input_types": ["TEXT"]
}
],
"ja": [
@@ -3143,8 +3143,8 @@
"positive_pattern": "入国",
"positive_score": 1.2,
"negative_pattern": null,
- "match_field_attributes": [0, 1],
- "match_field_input_types": [0]
+ "match_field_attributes": ["LABEL", "NAME"],
+ "match_field_input_types": ["TEXT"]
}
]
},
@@ -3155,8 +3155,8 @@
"positive_pattern": "departure",
"positive_score": 1.2,
"negative_pattern": null,
- "match_field_attributes": [0, 1],
- "match_field_input_types": [0]
+ "match_field_attributes": ["LABEL", "NAME"],
+ "match_field_input_types": ["TEXT"]
}
],
"es": [
@@ -3165,8 +3165,8 @@
"positive_pattern": "fecha.*salida|destino",
"positive_score": 1.2,
"negative_pattern": null,
- "match_field_attributes": [0, 1],
- "match_field_input_types": [0]
+ "match_field_attributes": ["LABEL", "NAME"],
+ "match_field_input_types": ["TEXT"]
}
],
"ja": [
@@ -3175,8 +3175,8 @@
"positive_pattern": "出国",
"positive_score": 1.2,
"negative_pattern": null,
- "match_field_attributes": [0, 1],
- "match_field_input_types": [0]
+ "match_field_attributes": ["LABEL", "NAME"],
+ "match_field_input_types": ["TEXT"]
}
]
},
@@ -3187,8 +3187,8 @@
"positive_pattern": "airline|flight",
"positive_score": 1.2,
"negative_pattern": null,
- "match_field_attributes": [0, 1],
- "match_field_input_types": [0]
+ "match_field_attributes": ["LABEL", "NAME"],
+ "match_field_input_types": ["TEXT"]
}
],
"es": [
@@ -3197,8 +3197,8 @@
"positive_pattern": "aerol(i|í)nea|n(u|ú)mero.*vuelo",
"positive_score": 1.2,
"negative_pattern": null,
- "match_field_attributes": [0, 1],
- "match_field_input_types": [0]
+ "match_field_attributes": ["LABEL", "NAME"],
+ "match_field_input_types": ["TEXT"]
}
],
"ja": [
@@ -3207,8 +3207,8 @@
"positive_pattern": "便名|航空会社",
"positive_score": 1.2,
"negative_pattern": null,
- "match_field_attributes": [0, 1],
- "match_field_input_types": [0]
+ "match_field_attributes": ["LABEL", "NAME"],
+ "match_field_input_types": ["TEXT"]
}
]
},
@@ -3219,16 +3219,16 @@
"positive_pattern": "^[\\w.+-_]+@(\\w+\\.ifsc\\.npci|aadhaar\\.npci|mobile\\.npci|rupay\\.npci)$",
"positive_score": 0,
"negative_pattern": null,
- "match_field_attributes": [0, 1],
- "match_field_input_types": [0]
+ "match_field_attributes": ["LABEL", "NAME"],
+ "match_field_input_types": ["TEXT"]
},
{
"pattern_identifier": "en_upi_virtual_payment_address_user@(bank_list)_preserving",
"positive_pattern": "^[\\w.+-_]+@(airtel|airtelpaymentsbank|albk|allahabadbank|allbank|andb|apb|apl|axis|axisbank|axisgo|bandhan|barodampay|birla|boi|cbin|cboi|centralbank|cmsidfc|cnrb|csbcash|csbpay|cub|dbs|dcb|dcbbank|denabank|dlb|eazypay|equitas|ezeepay|fbl|federal|finobank|hdfcbank|hsbc|icici|idbi|idbibank|idfc|idfcbank|idfcnetc|ikwik|imobile|indbank|indianbank|indianbk|indus|iob|jkb|jsb|jsbp|karb|karurvysyabank|kaypay|kbl|kbl052|kmb|kmbl|kotak|kvb|kvbank|lime|lvb|lvbank|mahb|obc|okaxis|okbizaxis|okhdfcbank|okicici|oksbi|paytm|payzapp|pingpay|pnb|pockets|psb|purz|rajgovhdfcbank|rbl|sbi|sc|scb|scbl|scmobile|sib|srcb|synd|syndbank|syndicate|tjsb|tjsp|ubi|uboi|uco|unionbank|unionbankofindia|united|upi|utbi|vijayabank|vijb|vjb|ybl|yesbank|yesbankltd)$",
"positive_score": 0,
"negative_pattern": null,
- "match_field_attributes": [0, 1],
- "match_field_input_types": [0]
+ "match_field_attributes": ["LABEL", "NAME"],
+ "match_field_input_types": ["TEXT"]
}
]
},
@@ -3239,8 +3239,8 @@
"positive_pattern": "^[a-zA-Z]{2}[0-9]{2}[a-zA-Z0-9]{4}[0-9]{7}([a-zA-Z0-9]?){0,16}$",
"positive_score": 0,
"negative_pattern": null,
- "match_field_attributes": [0, 1],
- "match_field_input_types": [0]
+ "match_field_attributes": ["LABEL", "NAME"],
+ "match_field_input_types": ["TEXT"]
}
]
},
@@ -3251,8 +3251,8 @@
"positive_pattern": "^\\d{3,4}$",
"positive_score": 0,
"negative_pattern": null,
- "match_field_attributes": [0, 1],
- "match_field_input_types": [0]
+ "match_field_attributes": ["LABEL", "NAME"],
+ "match_field_input_types": ["TEXT"]
}
]
},
@@ -3263,8 +3263,8 @@
"positive_pattern": "^[2][0][1-9][0-9]$",
"positive_score": 0,
"negative_pattern": null,
- "match_field_attributes": [0, 1],
- "match_field_input_types": [0]
+ "match_field_attributes": ["LABEL", "NAME"],
+ "match_field_input_types": ["TEXT"]
}
]
},
@@ -3275,8 +3275,8 @@
"positive_pattern": "/search(/|((\\w*\\.\\w+)?$))",
"positive_score": 0,
"negative_pattern": null,
- "match_field_attributes": [0, 1],
- "match_field_input_types": [0]
+ "match_field_attributes": ["LABEL", "NAME"],
+ "match_field_input_types": ["TEXT"]
}
]
},
@@ -3287,8 +3287,8 @@
"positive_pattern": "ssn|social.?security.?(num(ber)?|#)*",
"positive_score": 0,
"negative_pattern": null,
- "match_field_attributes": [0, 1],
- "match_field_input_types": [0]
+ "match_field_attributes": ["LABEL", "NAME"],
+ "match_field_input_types": ["TEXT"]
}
]
},
@@ -3299,8 +3299,8 @@
"positive_pattern": "one.?time|sms.?(code|token|password|pwd|pass)",
"positive_score": 0,
"negative_pattern": null,
- "match_field_attributes": [0, 1],
- "match_field_input_types": [0]
+ "match_field_attributes": ["LABEL", "NAME"],
+ "match_field_input_types": ["TEXT"]
}
]
},
@@ -3311,8 +3311,20 @@
"positive_pattern": "(promo(tion|tional)?|gift|discount|coupon)[-_. ]*code",
"positive_score": 0.85,
"negative_pattern": null,
- "match_field_attributes": [0, 1],
- "match_field_input_types": [0]
+ "match_field_attributes": ["LABEL", "NAME"],
+ "match_field_input_types": ["TEXT"]
+ }
+ ]
+ },
+ "IBAN_VALUE": {
+ "en": [
+ {
+ "pattern_identifier": "en_iban_preserving",
+ "positive_pattern": "(\\biban(\\b|_)|international bank account number)",
+ "positive_score": 0.975,
+ "negative_pattern": null,
+ "match_field_attributes": ["LABEL", "NAME"],
+ "match_field_input_types": ["TEXT"]
}
]
}
diff --git a/chromium/components/autofill/core/browser/form_parsing/search_field.cc b/chromium/components/autofill/core/browser/form_parsing/search_field.cc
index 26867e2f81d..fdce2b87e5a 100644
--- a/chromium/components/autofill/core/browser/form_parsing/search_field.cc
+++ b/chromium/components/autofill/core/browser/form_parsing/search_field.cc
@@ -5,9 +5,9 @@
#include "components/autofill/core/browser/form_parsing/search_field.h"
#include "components/autofill/core/browser/autofill_field.h"
-#include "components/autofill/core/browser/autofill_regex_constants.h"
#include "components/autofill/core/browser/form_parsing/autofill_scanner.h"
#include "components/autofill/core/browser/form_parsing/regex_patterns.h"
+#include "components/autofill/core/common/autofill_regex_constants.h"
namespace autofill {
@@ -33,7 +33,7 @@ std::unique_ptr<FormField> SearchField::Parse(AutofillScanner* scanner,
SearchField::SearchField(const AutofillField* field) : field_(field) {}
void SearchField::AddClassifications(
- FieldCandidatesMap* field_candidates) const {
+ FieldCandidatesMap& field_candidates) const {
AddClassification(field_, SEARCH_TERM, kBaseSearchParserScore,
field_candidates);
}
diff --git a/chromium/components/autofill/core/browser/form_parsing/search_field.h b/chromium/components/autofill/core/browser/form_parsing/search_field.h
index 91b7766bb69..e17e68582da 100644
--- a/chromium/components/autofill/core/browser/form_parsing/search_field.h
+++ b/chromium/components/autofill/core/browser/form_parsing/search_field.h
@@ -33,7 +33,7 @@ class SearchField : public FormField {
SearchField& operator=(const SearchField&) = delete;
protected:
- void AddClassifications(FieldCandidatesMap* field_candidates) const override;
+ void AddClassifications(FieldCandidatesMap& field_candidates) const override;
private:
FRIEND_TEST_ALL_PREFIXES(SearchFieldTest, ParseSearchTerm);
diff --git a/chromium/components/autofill/core/browser/form_parsing/standalone_cvc_field.cc b/chromium/components/autofill/core/browser/form_parsing/standalone_cvc_field.cc
new file mode 100644
index 00000000000..1110d613293
--- /dev/null
+++ b/chromium/components/autofill/core/browser/form_parsing/standalone_cvc_field.cc
@@ -0,0 +1,80 @@
+// Copyright 2022 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/form_parsing/standalone_cvc_field.h"
+
+#include "components/autofill/core/browser/autofill_field.h"
+#include "components/autofill/core/browser/autofill_regex_constants.h"
+#include "components/autofill/core/browser/autofill_regexes.h"
+#include "components/autofill/core/browser/form_parsing/autofill_scanner.h"
+#include "components/autofill/core/common/autofill_payments_features.h"
+
+namespace autofill {
+
+// static
+std::unique_ptr<FormField> StandaloneCvcField::Parse(
+ AutofillScanner* scanner,
+ const LanguageCode& page_language,
+ PatternSource pattern_source,
+ LogManager* log_manager) {
+ if (!base::FeatureList::IsEnabled(
+ features::kAutofillParseVcnCardOnFileStandaloneCvcFields)) {
+ return nullptr;
+ }
+
+ // Ignore gift card fields as both |kGiftCardRe| and |kCardCvcRe| matches
+ // "gift card pin" and "gift card code" but it should only match
+ // |kGiftCardRe|.
+ if (MatchGiftCard(scanner, log_manager, page_language, pattern_source)) {
+ return nullptr;
+ }
+
+ AutofillField* field;
+ base::span<const MatchPatternRef> cvc_patterns = GetMatchPatterns(
+ CREDIT_CARD_VERIFICATION_CODE, page_language, pattern_source);
+
+ // CVC fields can occur in many different field types so we check for each
+ const auto kMatchNumTelAndPwd =
+ kDefaultMatchParamsWith<MatchFieldType::kNumber,
+ MatchFieldType::kTelephone,
+ MatchFieldType::kPassword>;
+ if (ParseFieldSpecifics(scanner, kCardCvcRe, kMatchNumTelAndPwd, cvc_patterns,
+ &field, {log_manager, "kCardCvcRe(standalone)"})) {
+ return std::make_unique<StandaloneCvcField>(field);
+ }
+
+ return nullptr;
+}
+
+StandaloneCvcField::~StandaloneCvcField() = default;
+
+// static
+bool StandaloneCvcField::MatchGiftCard(AutofillScanner* scanner,
+ LogManager* log_manager,
+ const LanguageCode& page_language,
+ PatternSource pattern_source) {
+ if (scanner->IsEnd())
+ return false;
+
+ const auto kMatchFieldType = kDefaultMatchParamsWith<
+ MatchFieldType::kNumber, MatchFieldType::kTelephone,
+ MatchFieldType::kSearch, MatchFieldType::kPassword>;
+ base::span<const MatchPatternRef> gift_card_patterns =
+ GetMatchPatterns("GIFT_CARD", page_language, pattern_source);
+
+ return ParseFieldSpecifics(scanner, kGiftCardRe, kMatchFieldType,
+ gift_card_patterns, nullptr,
+ {log_manager, "kGiftCardRe"});
+}
+
+StandaloneCvcField::StandaloneCvcField(const AutofillField* field)
+ : field_(field) {}
+
+void StandaloneCvcField::AddClassifications(
+ FieldCandidatesMap& field_candidates) const {
+ AddClassification(field_, CREDIT_CARD_STANDALONE_VERIFICATION_CODE,
+ kBaseCreditCardParserScore, field_candidates);
+}
+
+} // namespace autofill
diff --git a/chromium/components/autofill/core/browser/form_parsing/standalone_cvc_field.h b/chromium/components/autofill/core/browser/form_parsing/standalone_cvc_field.h
new file mode 100644
index 00000000000..d4b272f0dfd
--- /dev/null
+++ b/chromium/components/autofill/core/browser/form_parsing/standalone_cvc_field.h
@@ -0,0 +1,50 @@
+// Copyright 2022 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_FORM_PARSING_STANDALONE_CVC_FIELD_H_
+#define COMPONENTS_AUTOFILL_CORE_BROWSER_FORM_PARSING_STANDALONE_CVC_FIELD_H_
+
+#include <memory>
+
+#include "base/memory/raw_ptr.h"
+#include "components/autofill/core/browser/form_parsing/form_field.h"
+#include "components/autofill/core/common/language_code.h"
+
+namespace autofill {
+
+class AutofillField;
+class AutofillScanner;
+class LogManager;
+
+// A form field that accepts a standalone cvc.
+class StandaloneCvcField : public FormField {
+ public:
+ static std::unique_ptr<FormField> Parse(AutofillScanner* scanner,
+ const LanguageCode& page_language,
+ PatternSource pattern_source,
+ LogManager* log_manager);
+
+ explicit StandaloneCvcField(const AutofillField* field);
+
+ ~StandaloneCvcField() override;
+
+ StandaloneCvcField(const StandaloneCvcField&) = delete;
+ StandaloneCvcField& operator=(const StandaloneCvcField&) = delete;
+
+ protected:
+ void AddClassifications(FieldCandidatesMap& field_candidates) const override;
+
+ private:
+ raw_ptr<const AutofillField> field_;
+
+ // static
+ static bool MatchGiftCard(AutofillScanner* scanner,
+ LogManager* log_manager,
+ const LanguageCode& page_language,
+ PatternSource pattern_source);
+};
+
+} // namespace autofill
+
+#endif // COMPONENTS_AUTOFILL_CORE_BROWSER_FORM_PARSING_STANDALONE_CVC_FIELD_H_
diff --git a/chromium/components/autofill/core/browser/form_parsing/standalone_cvc_field_unittest.cc b/chromium/components/autofill/core/browser/form_parsing/standalone_cvc_field_unittest.cc
new file mode 100644
index 00000000000..604ccc6a070
--- /dev/null
+++ b/chromium/components/autofill/core/browser/form_parsing/standalone_cvc_field_unittest.cc
@@ -0,0 +1,78 @@
+// Copyright 2022 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/form_parsing/standalone_cvc_field.h"
+
+#include "base/test/scoped_feature_list.h"
+#include "components/autofill/core/browser/form_parsing/parsing_test_utils.h"
+#include "components/autofill/core/common/autofill_payments_features.h"
+
+namespace autofill {
+
+class StandaloneCvcFieldTest
+ : public FormFieldTestBase,
+ public testing::TestWithParam<PatternProviderFeatureState> {
+ public:
+ StandaloneCvcFieldTest() : FormFieldTestBase(GetParam()) {}
+ StandaloneCvcFieldTest(const StandaloneCvcFieldTest&) = delete;
+ StandaloneCvcFieldTest& operator=(const StandaloneCvcFieldTest&) = delete;
+
+ protected:
+ std::unique_ptr<FormField> Parse(
+ AutofillScanner* scanner,
+ const LanguageCode& page_language = LanguageCode("en")) override {
+ return StandaloneCvcField::Parse(scanner, page_language,
+ GetActivePatternSource(),
+ /*log_manager=*/nullptr);
+ }
+
+ base::test::ScopedFeatureList scoped_feature_list_;
+};
+
+INSTANTIATE_TEST_SUITE_P(
+ StandaloneCvcFieldTest,
+ StandaloneCvcFieldTest,
+ ::testing::ValuesIn(PatternProviderFeatureState::All()));
+
+// Match standalone cvc.
+TEST_P(StandaloneCvcFieldTest, ParseStandaloneCvc) {
+ scoped_feature_list_.InitAndEnableFeature(
+ features::kAutofillParseVcnCardOnFileStandaloneCvcFields);
+
+ AddTextFormFieldData("cvc", "CVC:", CREDIT_CARD_STANDALONE_VERIFICATION_CODE);
+
+ ClassifyAndVerify(ParseResult::PARSED);
+}
+
+// Do not parse non cvc standalone fields.
+TEST_P(StandaloneCvcFieldTest, ParseNonStandaloneCvc) {
+ scoped_feature_list_.InitAndEnableFeature(
+ features::kAutofillParseVcnCardOnFileStandaloneCvcFields);
+
+ AddTextFormFieldData("other-field", "Other Field:", UNKNOWN_TYPE);
+
+ ClassifyAndVerify(ParseResult::NOT_PARSED);
+}
+
+// Do not parse when standalone cvc flag is disabled.
+TEST_P(StandaloneCvcFieldTest, ParseStandaloneCvcFlagOff) {
+ scoped_feature_list_.InitAndDisableFeature(
+ features::kAutofillParseVcnCardOnFileStandaloneCvcFields);
+
+ AddTextFormFieldData("cvc", "CVC:", CREDIT_CARD_STANDALONE_VERIFICATION_CODE);
+
+ ClassifyAndVerify(ParseResult::NOT_PARSED);
+}
+
+// Do not parse gift card as standalone cvc fields.
+TEST_P(StandaloneCvcFieldTest, NotParseGiftCardAsStandaloneCvc) {
+ scoped_feature_list_.InitAndEnableFeature(
+ features::kAutofillParseVcnCardOnFileStandaloneCvcFields);
+
+ AddTextFormFieldData("gift-card", "Gift Card Pin:", UNKNOWN_TYPE);
+
+ ClassifyAndVerify(ParseResult::NOT_PARSED);
+}
+
+} // namespace autofill
diff --git a/chromium/components/autofill/core/browser/form_parsing/transpile_regex_patterns.py b/chromium/components/autofill/core/browser/form_parsing/transpile_regex_patterns.py
index ebcd89a6000..6a795b01aea 100755
--- a/chromium/components/autofill/core/browser/form_parsing/transpile_regex_patterns.py
+++ b/chromium/components/autofill/core/browser/form_parsing/transpile_regex_patterns.py
@@ -8,6 +8,7 @@ import argparse
from collections import defaultdict
import io
import json
+import re
import sys
# Generates a set of C++ constexpr constants to facilitate lookup of a set of
@@ -36,11 +37,6 @@ import sys
# lookup pattern name -> language code -> span of MatchPatternRefs, but it's
# significantly simpler.
def generate_cpp_constants(id_to_name_to_lang_to_patterns):
- # The enum constant of the MatchAttribute::kName.
- kName = 1
- yield f'static_assert(MatchAttribute::kName == To<MatchAttribute,{kName}>());'
- yield ''
-
# Stores a `key` in `dictionary` and assigns it a natural number.
#
# For example, after memoize("foo", d) and memoize("bar", d),
@@ -64,17 +60,30 @@ def generate_cpp_constants(id_to_name_to_lang_to_patterns):
def json_to_cpp_u16string_literal(json_string_literal):
return 'u'+ json.dumps(json_string_literal or '')
- # Maps a list of natural numbers to a DenseSet<MatchAttribute> expression.
+ # Maps a list of strings to a DenseSet containing these values.
+ # The strings represents constants in the format FOO_BAR.
+ # They're translated to the C++ constant kFooBar.
+ def json_to_cpp_dense_set(json_enum_values, cpp_enum_type):
+ # Converts FOO_BAR into kFooBar.
+ def json_to_cpp_constant_symbol(json):
+ assert json.isupper()
+ return f'{cpp_enum_type}::k' + re.sub(
+ r'(^|_)([a-z])', lambda matched: matched.group(2).upper(),
+ json.lower())
+ cpp_enum_values = [json_to_cpp_constant_symbol(c) for c in json_enum_values]
+ return (f'DenseSet<{cpp_enum_type}>{{' + ','.join(cpp_enum_values) + f'}}')
+
+ # Maps a list of strings to a DenseSet<MatchAttribute> expression.
+ # The strings must be the names of MatchAttribute constants, e.g., NAME.
+ # They're mapped to C++ constants, e.g., kName.
def json_to_cpp_match_field_attributes(enum_values):
- return f'DenseSet<MatchAttribute>{{' \
- f"{','.join(f'To<MatchAttribute,{i}>()' for i in enum_values)}" \
- f'}}'
+ return json_to_cpp_dense_set(enum_values, 'MatchAttribute')
- # Maps a list of natural numbers to a DenseSet<MatchFieldType> expression.
+ # Maps a list of strings to a DenseSet<MatchFieldType> expression.
+ # The strings must be the names of MatchFieldType constants, e.g., TEXT_AREA.
+ # They're mapped to C++ constants, e.g., kTextArea.
def json_to_cpp_match_field_input_types(enum_values):
- return f'DenseSet<MatchFieldType>{{' \
- f"{','.join(f'To<MatchFieldType,{i}>()' for i in enum_values)}" \
- f'}}'
+ return json_to_cpp_dense_set(enum_values, 'MatchFieldType')
# Maps a JSON object representing a pattern to a C++ MatchingPattern
# expression.
@@ -136,7 +145,7 @@ def generate_cpp_constants(id_to_name_to_lang_to_patterns):
if 'en' not in lang_to_patterns:
continue
def make_supplementary_pattern(p):
- assert kName in p['match_field_attributes']
+ assert "NAME" in p['match_field_attributes']
p = p.copy()
p['supplementary'] = True
return p
@@ -145,7 +154,7 @@ def generate_cpp_constants(id_to_name_to_lang_to_patterns):
patterns.extend(
make_supplementary_pattern(p)
for p in lang_to_patterns['en']
- if kName in p['match_field_attributes'])
+ if "NAME" in p['match_field_attributes'])
# Populate the two maps:
# - a map from C++ MatchingPattern expressions to their index.
@@ -266,14 +275,6 @@ constexpr MatchPatternRef MakeMatchPatternRef(
return MatchPatternRef(is_supplementary, index);
}
-// Converts an integer to the associated enum class constant.
-template<typename Enum, int i>
-constexpr Enum To() {
- static_assert(0 <= i);
- static_assert(static_cast<Enum>(i) <= Enum::kMaxValue);
- return static_cast<Enum>(i);
-}
-
// A pair of const char* used as keys in the `kPatternMap`.
struct NameAndLanguage {
using StringPiecePair = std::pair<base::StringPiece, base::StringPiece>;
diff --git a/chromium/components/autofill/core/browser/form_parsing/travel_field.cc b/chromium/components/autofill/core/browser/form_parsing/travel_field.cc
index c6a696b0296..0d1618ea482 100644
--- a/chromium/components/autofill/core/browser/form_parsing/travel_field.cc
+++ b/chromium/components/autofill/core/browser/form_parsing/travel_field.cc
@@ -7,8 +7,8 @@
#include <memory>
#include <utility>
-#include "components/autofill/core/browser/autofill_regex_constants.h"
#include "components/autofill/core/browser/form_parsing/regex_patterns.h"
+#include "components/autofill/core/common/autofill_regex_constants.h"
namespace autofill {
@@ -49,7 +49,7 @@ std::unique_ptr<FormField> TravelField::Parse(AutofillScanner* scanner,
}
void TravelField::AddClassifications(
- FieldCandidatesMap* field_candidates) const {
+ FieldCandidatesMap& field_candidates) const {
// Simply tag all the fields as unknown types. Travel is currently used as
// filter.
AddClassification(passport_, UNKNOWN_TYPE, kBaseTravelParserScore,
diff --git a/chromium/components/autofill/core/browser/form_parsing/travel_field.h b/chromium/components/autofill/core/browser/form_parsing/travel_field.h
index 17784dcc45e..07d45601a45 100644
--- a/chromium/components/autofill/core/browser/form_parsing/travel_field.h
+++ b/chromium/components/autofill/core/browser/form_parsing/travel_field.h
@@ -25,7 +25,7 @@ class TravelField : public FormField {
LogManager* log_manager);
protected:
- void AddClassifications(FieldCandidatesMap* field_candidates) const override;
+ void AddClassifications(FieldCandidatesMap& field_candidates) const override;
private:
// All of the following fields are optional.
diff --git a/chromium/components/autofill/core/browser/form_processing/label_processing_util.cc b/chromium/components/autofill/core/browser/form_processing/label_processing_util.cc
index 4a4f1c45a45..66bd8187ff0 100644
--- a/chromium/components/autofill/core/browser/form_processing/label_processing_util.cc
+++ b/chromium/components/autofill/core/browser/form_processing/label_processing_util.cc
@@ -29,7 +29,7 @@ absl::optional<std::vector<std::u16string>> GetParseableLabels(
// the subsequent fields.
size_t label_index = 0;
while (label_index < labels.size()) {
- const auto& label = labels.at(label_index);
+ const base::StringPiece16& label = labels[label_index];
// If the label is empty or has a size that exceeds
// |kMaxLengthOfShareableLabel| it can not be shared with subsequent fields.
if (label.empty() || label.size() > kMaxLengthOfShareableLabel) {
@@ -37,16 +37,16 @@ absl::optional<std::vector<std::u16string>> GetParseableLabels(
continue;
}
- // Otherwise search if the subsequent fields are empty.
+ // Otherwise search if the subsequent fields are empty or share the same
+ // label. Checking for the same label is needed, because label inference
+ // often derives the same label for consecutive fields.
size_t scan_index = label_index + 1;
- while (scan_index < labels.size()) {
- if (!labels.at(scan_index).empty()) {
- break;
- }
+ while (scan_index < labels.size() &&
+ (labels[scan_index].empty() || labels[scan_index] == label)) {
++scan_index;
}
- // After the loop, the |scan_index| points to the first subsequent field
- // that does not have an empty label or is the first out-of-bound index.
+ // After the loop, the `scan_index` points to the first subsequent field
+ // which the label cannot be shared with or to the first out-of-bound index.
// Calculate the number of fields that may share a label.
size_t fields_to_share_label = scan_index - label_index;
@@ -87,7 +87,7 @@ absl::optional<std::vector<std::u16string>> GetParseableLabels(
shared_labels_found = true;
// Otherwise assign the label components to the fields.
for (size_t i = 0; i < label_components.size(); ++i) {
- shared_labels[shared_label_starting_index + i] = label_components.at(i);
+ shared_labels[shared_label_starting_index + i] = label_components[i];
}
}
diff --git a/chromium/components/autofill/core/browser/form_processing/label_processing_util_unittest.cc b/chromium/components/autofill/core/browser/form_processing/label_processing_util_unittest.cc
index 584ac357e2b..0b9f2a44088 100644
--- a/chromium/components/autofill/core/browser/form_processing/label_processing_util_unittest.cc
+++ b/chromium/components/autofill/core/browser/form_processing/label_processing_util_unittest.cc
@@ -10,108 +10,53 @@
#include "components/autofill/core/common/autofill_features.h"
#include "testing/gtest/include/gtest/gtest.h"
-using base::ASCIIToUTF16;
-
-namespace {
-
-std::vector<base::StringPiece16> StringsToStringPieces(
- const std::vector<std::u16string>& strings) {
- std::vector<base::StringPiece16> string_pieces;
- for (const auto& s : strings) {
- string_pieces.emplace_back(base::StringPiece16(s));
- }
- return string_pieces;
-}
-
-} // namespace
-
namespace autofill {
TEST(LabelProcessingUtil, GetParseableNameStringPieces) {
- std::vector<std::u16string> labels;
- labels.push_back(u"City");
- labels.push_back(u"Street & House Number");
- labels.push_back(u"");
- labels.push_back(u"Zip");
-
- auto expectation = absl::make_optional(std::vector<std::u16string>());
- expectation->push_back(u"City");
- expectation->push_back(u"Street");
- expectation->push_back(u"House Number");
- expectation->push_back(u"Zip");
-
- EXPECT_EQ(GetParseableLabels(StringsToStringPieces(labels)), expectation);
+ std::vector<base::StringPiece16> labels{u"City", u"Street & House Number",
+ u"", u"Zip"};
+ auto expectation = absl::make_optional(
+ std::vector<std::u16string>{u"City", u"Street", u"House Number", u"Zip"});
+ EXPECT_EQ(GetParseableLabels(labels), expectation);
+
+ // The label is also split when consecutive fields share the same label.
+ labels[2] = labels[1];
+ EXPECT_EQ(GetParseableLabels(labels), expectation);
}
TEST(LabelProcessingUtil, GetParseableNameStringPieces_ThreeComponents) {
- std::vector<std::u16string> labels;
- labels.push_back(u"City");
- labels.push_back(u"Street & House Number & Floor");
- labels.push_back(u"");
- labels.push_back(u"");
- labels.push_back(u"Zip");
-
- auto expectation = absl::make_optional(std::vector<std::u16string>());
- expectation->push_back(u"City");
- expectation->push_back(u"Street");
- expectation->push_back(u"House Number");
- expectation->push_back(u"Floor");
- expectation->push_back(u"Zip");
-
- EXPECT_EQ(GetParseableLabels(StringsToStringPieces(labels)), expectation);
+ EXPECT_EQ(GetParseableLabels(
+ {u"City", u"Street & House Number & Floor", u"", u"", u"Zip"}),
+ absl::make_optional(std::vector<std::u16string>{
+ u"City", u"Street", u"House Number", u"Floor", u"Zip"}));
}
TEST(LabelProcessingUtil, GetParseableNameStringPieces_TooManyComponents) {
- std::vector<std::u16string> labels;
- labels.push_back(u"City");
- labels.push_back(u"Street & House Number & Floor & Stairs");
- labels.push_back(u"");
- labels.push_back(u"");
- labels.push_back(u"");
- labels.push_back(u"Zip");
-
- absl::optional<std::vector<std::u16string>> expectation = absl::nullopt;
- ;
-
- EXPECT_EQ(GetParseableLabels(StringsToStringPieces(labels)), expectation);
+ EXPECT_EQ(
+ GetParseableLabels({u"City", u"Street & House Number & Floor & Stairs",
+ u"", u"", u"", u"Zip"}),
+ absl::nullopt);
}
TEST(LabelProcessingUtil, GetParseableNameStringPieces_UnmachtingComponents) {
- std::vector<std::u16string> labels;
- labels.push_back(u"City");
- labels.push_back(u"Street & House Number & Floor");
- labels.push_back(u"");
- labels.push_back(u"Zip");
-
- absl::optional<std::vector<std::u16string>> expectation = absl::nullopt;
-
- EXPECT_EQ(GetParseableLabels(StringsToStringPieces(labels)), expectation);
+ EXPECT_EQ(GetParseableLabels(
+ {u"City", u"Street & House Number & Floor", u"", u"Zip"}),
+ absl::nullopt);
}
TEST(LabelProcessingUtil, GetParseableNameStringPieces_SplitableLabelAtEnd) {
- std::vector<std::u16string> labels;
- labels.push_back(u"City");
- labels.push_back(u"");
- labels.push_back(u"Zip");
- labels.push_back(u"Street & House Number & Floor");
-
- absl::optional<std::vector<std::u16string>> expectation = absl::nullopt;
-
- EXPECT_EQ(GetParseableLabels(StringsToStringPieces(labels)), expectation);
+ EXPECT_EQ(GetParseableLabels(
+ {u"City", u"", u"Zip", u"Street & House Number & Floor"}),
+ absl::nullopt);
}
TEST(LabelProcessingUtil, GetParseableNameStringPieces_TooLongLabel) {
- std::vector<std::u16string> labels;
- labels.push_back(u"City");
- labels.push_back(
- u"Street & House Number with a lot of additional text that exceeds 40 "
- u"characters by far");
- labels.push_back(u"");
- labels.push_back(u"Zip");
-
- absl::optional<std::vector<std::u16string>> expectation = absl::nullopt;
-
- EXPECT_EQ(GetParseableLabels(StringsToStringPieces(labels)), expectation);
+ EXPECT_EQ(GetParseableLabels({u"City",
+ u"Street & House Number with a lot of "
+ u"additional text that exceeds 40 "
+ u"characters by far",
+ u"", u"Zip"}),
+ absl::nullopt);
}
} // namespace autofill
diff --git a/chromium/components/autofill/core/browser/form_processing/name_processing_util.cc b/chromium/components/autofill/core/browser/form_processing/name_processing_util.cc
index f4699090542..ce3786be67a 100644
--- a/chromium/components/autofill/core/browser/form_processing/name_processing_util.cc
+++ b/chromium/components/autofill/core/browser/form_processing/name_processing_util.cc
@@ -6,9 +6,9 @@
#include "base/feature_list.h"
#include "base/strings/utf_string_conversions.h"
-#include "components/autofill/core/browser/autofill_regexes.h"
#include "components/autofill/core/browser/form_structure.h"
#include "components/autofill/core/common/autofill_features.h"
+#include "components/autofill/core/common/autofill_regexes.h"
namespace autofill {
@@ -84,9 +84,7 @@ size_t FindLongestCommonPrefixLengthInStringsWithMinimalLength(
// Returns true if |parseable_name| is a valid parseable_name. Current criterion
// is the |kParseableNameValidationRe| regex.
bool IsValidParseableName(const base::StringPiece16 parseable_name) {
- static const std::u16string kParseableNameValidationPattern =
- kParseableNameValidationRe;
- return MatchesPattern(parseable_name, kParseableNameValidationPattern);
+ return MatchesRegex<kParseableNameValidationRe>(parseable_name);
}
// Tries to strip |offset_left| and |offset_right| from entriees in
diff --git a/chromium/components/autofill/core/browser/form_processing/name_processing_util.h b/chromium/components/autofill/core/browser/form_processing/name_processing_util.h
index 6c644d5e411..2bbb77e6531 100644
--- a/chromium/components/autofill/core/browser/form_processing/name_processing_util.h
+++ b/chromium/components/autofill/core/browser/form_processing/name_processing_util.h
@@ -9,7 +9,6 @@
#include "base/strings/string_piece.h"
#include "base/strings/utf_string_conversions.h"
-#include "components/autofill/core/browser/autofill_regexes.h"
#include "components/autofill/core/browser/form_structure.h"
#include "third_party/abseil-cpp/absl/types/optional.h"
diff --git a/chromium/components/autofill/core/browser/form_structure.cc b/chromium/components/autofill/core/browser/form_structure.cc
index d7d3c5a898a..5491f1bd32f 100644
--- a/chromium/components/autofill/core/browser/form_structure.cc
+++ b/chromium/components/autofill/core/browser/form_structure.cc
@@ -34,8 +34,6 @@
#include "base/strings/utf_string_conversions.h"
#include "base/time/time.h"
#include "components/autofill/core/browser/autofill_data_util.h"
-#include "components/autofill/core/browser/autofill_regex_constants.h"
-#include "components/autofill/core/browser/autofill_regexes.h"
#include "components/autofill/core/browser/autofill_type.h"
#include "components/autofill/core/browser/field_types.h"
#include "components/autofill/core/browser/form_parsing/buildflags.h"
@@ -48,11 +46,14 @@
#include "components/autofill/core/browser/randomized_encoder.h"
#include "components/autofill/core/browser/rationalization_util.h"
#include "components/autofill/core/browser/validation.h"
+#include "components/autofill/core/common/autocomplete_parsing_util.h"
#include "components/autofill/core/common/autofill_constants.h"
#include "components/autofill/core/common/autofill_features.h"
#include "components/autofill/core/common/autofill_internals/log_message.h"
#include "components/autofill/core/common/autofill_internals/logging_scope.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_tick_clock.h"
#include "components/autofill/core/common/autofill_util.h"
#include "components/autofill/core/common/dense_set.h"
@@ -73,12 +74,6 @@ using mojom::SubmissionIndicatorEvent;
namespace {
-constexpr char kBillingMode[] = "billing";
-constexpr char kShippingMode[] = "shipping";
-
-// Default section name for the fields.
-constexpr char kDefaultSection[] = "-default";
-
// Returns true if the scheme given by |url| is one for which autofill is
// allowed to activate. By default this only returns true for HTTP and HTTPS.
bool HasAllowedScheme(const GURL& url) {
@@ -121,168 +116,6 @@ std::string EncodeFieldTypes(const ServerFieldTypeSet& available_field_types) {
return data_presence;
}
-// Returns |true| iff the |token| is a type hint for a contact field, as
-// specified in the implementation section of http://is.gd/whatwg_autocomplete
-// Note that "fax" and "pager" are intentionally ignored, as Chrome does not
-// support filling either type of information.
-bool IsContactTypeHint(const std::string& token) {
- return token == "home" || token == "work" || token == "mobile";
-}
-
-// Returns |true| iff the |token| is a type hint appropriate for a field of the
-// given |field_type|, as specified in the implementation section of
-// http://is.gd/whatwg_autocomplete
-bool ContactTypeHintMatchesFieldType(const std::string& token,
- HtmlFieldType field_type) {
- // The "home" and "work" type hints are only appropriate for email and phone
- // number field types.
- if (token == "home" || token == "work") {
- return field_type == HTML_TYPE_EMAIL ||
- (field_type >= HTML_TYPE_TEL &&
- field_type <= HTML_TYPE_TEL_LOCAL_SUFFIX);
- }
-
- // The "mobile" type hint is only appropriate for phone number field types.
- // Note that "fax" and "pager" are intentionally ignored, as Chrome does not
- // support filling either type of information.
- if (token == "mobile") {
- return field_type >= HTML_TYPE_TEL &&
- field_type <= HTML_TYPE_TEL_LOCAL_SUFFIX;
- }
-
- return false;
-}
-
-// Rationalizes the HTML `type` of `field`, based on the fields properties. At
-// the moment only `max_length` is considered. For example, a max_length of 4
-// might indicate a 4 digit year.
-// In case no rationalization rule applies, the original type is returned.
-HtmlFieldType RationalizeAutocompleteType(HtmlFieldType type,
- const AutofillField& field) {
- // (original-type, max-length) -> new-type
- static constexpr auto rules =
- base::MakeFixedFlatMap<std::pair<HtmlFieldType, uint64_t>, HtmlFieldType>(
- {
- {{HTML_TYPE_ADDITIONAL_NAME, 1},
- HTML_TYPE_ADDITIONAL_NAME_INITIAL},
- {{HTML_TYPE_CREDIT_CARD_EXP, 5},
- HTML_TYPE_CREDIT_CARD_EXP_DATE_2_DIGIT_YEAR},
- {{HTML_TYPE_CREDIT_CARD_EXP, 7},
- HTML_TYPE_CREDIT_CARD_EXP_DATE_4_DIGIT_YEAR},
- {{HTML_TYPE_CREDIT_CARD_EXP_YEAR, 2},
- HTML_TYPE_CREDIT_CARD_EXP_2_DIGIT_YEAR},
- {{HTML_TYPE_CREDIT_CARD_EXP_YEAR, 4},
- HTML_TYPE_CREDIT_CARD_EXP_4_DIGIT_YEAR},
- });
-
- auto* it = rules.find(std::make_pair(type, field.max_length));
- return it == rules.end() ? type : it->second;
-}
-
-// Chrome Autofill supports a subset of the field types listed at
-// http://is.gd/whatwg_autocomplete. Returns the corresponding HtmlFieldType, if
-// `value` matches any of them.
-absl::optional<HtmlFieldType> ParseStandardizedAutocompleteAttribute(
- base::StringPiece value) {
- static constexpr auto standardized_attributes =
- base::MakeFixedFlatMap<base::StringPiece, HtmlFieldType>({
- {"additional-name", HTML_TYPE_ADDITIONAL_NAME},
- {"address-level1", HTML_TYPE_ADDRESS_LEVEL1},
- {"address-level2", HTML_TYPE_ADDRESS_LEVEL2},
- {"address-level3", HTML_TYPE_ADDRESS_LEVEL3},
- {"address-line1", HTML_TYPE_ADDRESS_LINE1},
- {"address-line2", HTML_TYPE_ADDRESS_LINE2},
- {"address-line3", HTML_TYPE_ADDRESS_LINE3},
- {"cc-csc", HTML_TYPE_CREDIT_CARD_VERIFICATION_CODE},
- {"cc-exp", HTML_TYPE_CREDIT_CARD_EXP},
- {"cc-exp-month", HTML_TYPE_CREDIT_CARD_EXP_MONTH},
- {"cc-exp-year", HTML_TYPE_CREDIT_CARD_EXP_YEAR},
- {"cc-family-name", HTML_TYPE_CREDIT_CARD_NAME_LAST},
- {"cc-given-name", HTML_TYPE_CREDIT_CARD_NAME_FIRST},
- {"cc-name", HTML_TYPE_CREDIT_CARD_NAME_FULL},
- {"cc-number", HTML_TYPE_CREDIT_CARD_NUMBER},
- {"cc-type", HTML_TYPE_CREDIT_CARD_TYPE},
- {"country", HTML_TYPE_COUNTRY_CODE},
- {"country-name", HTML_TYPE_COUNTRY_NAME},
- {"email", HTML_TYPE_EMAIL},
- {"family-name", HTML_TYPE_FAMILY_NAME},
- {"given-name", HTML_TYPE_GIVEN_NAME},
- {"honorific-prefix", HTML_TYPE_HONORIFIC_PREFIX},
- {"name", HTML_TYPE_NAME},
- {"one-time-code", HTML_TYPE_ONE_TIME_CODE},
- {"organization", HTML_TYPE_ORGANIZATION},
- {"postal-code", HTML_TYPE_POSTAL_CODE},
- {"street-address", HTML_TYPE_STREET_ADDRESS},
- {"tel-area-code", HTML_TYPE_TEL_AREA_CODE},
- {"tel-country-code", HTML_TYPE_TEL_COUNTRY_CODE},
- {"tel-extension", HTML_TYPE_TEL_EXTENSION},
- {"tel", HTML_TYPE_TEL},
- {"tel-local", HTML_TYPE_TEL_LOCAL},
- {"tel-local-prefix", HTML_TYPE_TEL_LOCAL_PREFIX},
- {"tel-local-suffix", HTML_TYPE_TEL_LOCAL_SUFFIX},
- {"tel-national", HTML_TYPE_TEL_NATIONAL},
- {"transaction-amount", HTML_TYPE_TRANSACTION_AMOUNT},
- {"transaction-currency", HTML_TYPE_TRANSACTION_CURRENCY},
- });
-
- auto* it = standardized_attributes.find(value);
- return it != standardized_attributes.end()
- ? absl::optional<HtmlFieldType>(it->second)
- : absl::nullopt;
-}
-
-// Tries mapping a non-standardized html autocomplete `value` to an
-// HtmlFieldType.
-absl::optional<HtmlFieldType> ParseAutocompleteAttributeExtensions(
- base::StringPiece value) {
- static constexpr auto extensions =
- base::MakeFixedFlatMap<base::StringPiece, HtmlFieldType>({
- {"address", HTML_TYPE_STREET_ADDRESS},
- {"company", HTML_TYPE_ORGANIZATION},
- {"coupon-code", HTML_TYPE_MERCHANT_PROMO_CODE},
- {"first-name", HTML_TYPE_GIVEN_NAME},
- {"gift-code", HTML_TYPE_MERCHANT_PROMO_CODE},
- {"locality", HTML_TYPE_ADDRESS_LEVEL2},
- {"promo-code", HTML_TYPE_MERCHANT_PROMO_CODE},
- {"promotional-code", HTML_TYPE_MERCHANT_PROMO_CODE},
- {"promotion-code", HTML_TYPE_MERCHANT_PROMO_CODE},
- {"region", HTML_TYPE_ADDRESS_LEVEL1},
- {"tel-ext", HTML_TYPE_TEL_EXTENSION},
- {"upi", HTML_TYPE_UPI_VPA},
- {"upi-vpa", HTML_TYPE_UPI_VPA},
- {"username", HTML_TYPE_EMAIL},
- });
-
- auto* it = extensions.find(value);
- return it != extensions.end() ? absl::optional<HtmlFieldType>(it->second)
- : absl::nullopt;
-}
-
-// Returns the Chrome Autofill-supported field type corresponding to a given
-// autocomplete `value`, if there is one, in the context of the given
-// `field`.
-HtmlFieldType FieldTypeFromAutocompleteAttributeValue(
- std::string value,
- const AutofillField& field) {
- if (value.empty())
- return HTML_TYPE_UNSPECIFIED;
-
- // We are lenient and accept '_' instead of '-' as a separator. E.g.
- // "given_name" is treated like "given-name".
- base::ReplaceChars(value, "_", "-", &value);
- // We accept e.g. "phone-country" instead of "tel-country".
- if (base::StartsWith(value, "phone"))
- base::ReplaceFirstSubstringAfterOffset(&value, 0, "phone", "tel");
-
- absl::optional<HtmlFieldType> type =
- ParseStandardizedAutocompleteAttribute(value);
- if (!type.has_value())
- type = ParseAutocompleteAttributeExtensions(value);
-
- return type.has_value() ? RationalizeAutocompleteType(type.value(), field)
- : HTML_TYPE_UNRECOGNIZED;
-}
-
std::ostream& operator<<(std::ostream& out,
const AutofillQueryResponse& response) {
for (const auto& form : response.form_suggestions()) {
@@ -447,6 +280,12 @@ void PopulateRandomizedFieldMetadata(
field.placeholder, /*include_checksum=*/false,
metadata->mutable_placeholder());
}
+ if (!field.autocomplete_attribute.empty()) {
+ EncodeRandomizedValue(
+ encoder, form_signature, field_signature,
+ RandomizedEncoder::FIELD_AUTOCOMPLETE, field.autocomplete_attribute,
+ /*include_checksum=*/false, metadata->mutable_autocomplete());
+ }
}
// Defines necessary types for the rationalization logic, meaning that fields of
@@ -456,7 +295,7 @@ void PopulateRandomizedFieldMetadata(
ServerFieldTypeSet GetNecessaryTypesFor(ServerFieldType type) {
switch (type) {
case PHONE_HOME_COUNTRY_CODE:
- return {PHONE_HOME_NUMBER,
+ return {PHONE_HOME_NUMBER, PHONE_HOME_NUMBER_PREFIX,
base::FeatureList::IsEnabled(
features::kAutofillEnableSupportForPhoneNumberTrunkTypes)
? PHONE_HOME_CITY_AND_NUMBER_WITHOUT_TRUNK_PREFIX
@@ -466,39 +305,6 @@ ServerFieldTypeSet GetNecessaryTypesFor(ServerFieldType type) {
}
}
-LogBufferSubmitter LogRationalization(LogManager* log_manager) {
- if (!log_manager)
- return LogManager::DevNull();
- LogBufferSubmitter submitter = log_manager->Log();
- submitter << LoggingScope::kRationalization << LogMessage::kRationalization;
- return submitter;
-}
-
-// Creates a unique name for the section that starts with |field|.
-//
-// The section name is a string of the form "%s_%u_%u", where the first string
-// is the field's name and the two integers are the field's frame ID and its
-// renderer ID.
-//
-// For the frame ID, we do not use LocalFrameTokens but instead map them to
-// consecutive integers using |frame_token_ids|, which uniquely identify a frame
-// within a given FormStructure. Since we do not intend to compare sections from
-// different FormStructures, this is sufficient.
-//
-// We intentionally do not include the LocalFrameToken in the section string
-// because frame tokens should not be sent to a renderer.
-//
-// TODO(crbug.com/1257141): Remove special handling of FrameTokens.
-std::u16string GetSectionName(
- const AutofillField& field,
- base::flat_map<LocalFrameToken, size_t>& frame_token_ids) {
- size_t id = frame_token_ids.emplace(field.host_frame, frame_token_ids.size())
- .first->second;
- return base::StrCat(
- {field.name, u"_", base::NumberToString16(id), u"_",
- base::NumberToString16(field.unique_renderer_id.value())});
-}
-
} // namespace
class FormStructure::SectionedFieldsIndexes {
@@ -780,10 +586,8 @@ void FormStructure::ProcessQueryResponse(
using FieldSuggestion =
AutofillQueryResponse::FormSuggestion::FieldSuggestion;
AutofillMetrics::LogServerQueryMetric(AutofillMetrics::QUERY_RESPONSE_PARSED);
- if (log_manager) {
- log_manager->Log() << LoggingScope::kParsing
- << LogMessage::kProcessingServerData;
- }
+ LOG_AF(log_manager) << LoggingScope::kParsing
+ << LogMessage::kProcessingServerData;
bool heuristics_detected_fillable_field = false;
bool query_response_overrode_heuristics = false;
@@ -909,7 +713,7 @@ std::vector<FormDataPredictions> FormStructure::GetFieldTypePredictions(
annotated_field.overall_type = field->Type().ToString();
annotated_field.parseable_name =
base::UTF16ToUTF8(field->parseable_name());
- annotated_field.section = field->section;
+ annotated_field.section = field->section.ToString();
form.fields.push_back(annotated_field);
}
@@ -988,10 +792,8 @@ void FormStructure::UpdateAutofillCount() {
bool FormStructure::ShouldBeParsed(LogManager* log_manager) const {
// Exclude URLs not on the web via HTTP(S).
if (!HasAllowedScheme(source_url_)) {
- if (log_manager) {
- log_manager->Log() << LoggingScope::kAbortParsing
- << LogMessage::kAbortParsingNotAllowedScheme << *this;
- }
+ LOG_AF(log_manager) << LoggingScope::kAbortParsing
+ << LogMessage::kAbortParsingNotAllowedScheme << *this;
return false;
}
@@ -1002,35 +804,28 @@ bool FormStructure::ShouldBeParsed(LogManager* log_manager) const {
(!all_fields_are_passwords() ||
active_field_count() < kRequiredFieldsForFormsWithOnlyPasswordFields) &&
!has_author_specified_types_) {
- if (log_manager) {
- log_manager->Log() << LoggingScope::kAbortParsing
- << LogMessage::kAbortParsingNotEnoughFields
- << active_field_count() << *this;
- }
+ LOG_AF(log_manager) << LoggingScope::kAbortParsing
+ << LogMessage::kAbortParsingNotEnoughFields
+ << active_field_count() << *this;
return false;
}
// Rule out search forms.
- if (MatchesPattern(base::UTF8ToUTF16(target_url_.path_piece()),
- kUrlSearchActionRe)) {
- if (log_manager) {
- log_manager->Log() << LoggingScope::kAbortParsing
- << LogMessage::kAbortParsingUrlMatchesSearchRegex
- << *this;
- }
+ if (MatchesRegex<kUrlSearchActionRe>(
+ base::UTF8ToUTF16(target_url_.path_piece()))) {
+ LOG_AF(log_manager) << LoggingScope::kAbortParsing
+ << LogMessage::kAbortParsingUrlMatchesSearchRegex
+ << *this;
return false;
}
- bool has_text_field = false;
- for (const auto& it : *this) {
- has_text_field |= it->form_control_type != "select-one";
+ bool has_text_field = base::ranges::any_of(*this, [](const auto& field) {
+ return field->form_control_type != "select-one";
+ });
+ if (!has_text_field) {
+ LOG_AF(log_manager) << LoggingScope::kAbortParsing
+ << LogMessage::kAbortParsingFormHasNoTextfield << *this;
}
-
- if (!has_text_field && log_manager) {
- log_manager->Log() << LoggingScope::kAbortParsing
- << LogMessage::kAbortParsingFormHasNoTextfield << *this;
- }
-
return has_text_field;
}
@@ -1039,10 +834,8 @@ bool FormStructure::ShouldRunHeuristics() const {
HasAllowedScheme(source_url_);
}
-bool FormStructure::ShouldRunPromoCodeHeuristics() const {
- return base::FeatureList::IsEnabled(
- features::kAutofillParseMerchantPromoCodeFields) &&
- active_field_count() > 0 && HasAllowedScheme(source_url_);
+bool FormStructure::ShouldRunHeuristicsForSingleFieldForms() const {
+ return active_field_count() > 0 && HasAllowedScheme(source_url_);
}
bool FormStructure::ShouldBeQueried() const {
@@ -1460,106 +1253,33 @@ void FormStructure::ParseFieldTypesFromAutocompleteAttributes() {
has_author_specified_sections_ = false;
has_author_specified_upi_vpa_hint_ = false;
for (const std::unique_ptr<AutofillField>& field : fields_) {
- // To prevent potential section name collisions, add a default suffix for
- // other fields. Without this, 'autocomplete' attribute values
- // "section--shipping street-address" and "shipping street-address" would be
- // parsed identically, given the section handling code below. We do this
- // before any validation so that fields with invalid attributes still end up
- // in the default section. These default section names will be overridden
- // by subsequent heuristic parsing steps if there are no author-specified
- // section names.
- field->section = kDefaultSection;
-
- std::vector<std::string> tokens =
- LowercaseAndTokenizeAttributeString(field->autocomplete_attribute);
-
- // The autocomplete attribute is overloaded: it can specify either a field
- // type hint or whether autocomplete should be enabled at all. Ignore the
- // latter type of attribute value.
- if (tokens.empty() ||
- (tokens.size() == 1 &&
- (tokens[0] == "on" || tokens[0] == "off" || tokens[0] == "false"))) {
+ field->section = Section();
+ auto parsing_result = ParseAutocompleteAttribute(*field);
+ if (!parsing_result)
continue;
- }
- // Any other value, even it is invalid, is considered to be a type hint.
- // This allows a website's author to specify an attribute like
- // autocomplete="other" on a field to disable all Autofill heuristics for
- // the form.
+ // A parsable autocomplete value was specified. Even an invalid field_type
+ // is considered a type hint. This allows a website's author to specify an
+ // attribute like autocomplete="other" on a field to disable all Autofill
+ // heuristics for the form.
has_author_specified_types_ = true;
-
- // Per the spec, the tokens are parsed in reverse order. The expected
- // pattern is:
- // [section-*] [shipping|billing] [type_hint] field_type
-
- // (1) The final token must be the field type. If it is not one of the known
- // types, abort.
- std::string field_type_token = tokens.back();
- tokens.pop_back();
- HtmlFieldType field_type =
- FieldTypeFromAutocompleteAttributeValue(field_type_token, *field);
- if (field_type == HTML_TYPE_UPI_VPA) {
- has_author_specified_upi_vpa_hint_ = true;
- // TODO(crbug.com/702223): Flesh out support for UPI-VPA.
- field_type = HTML_TYPE_UNRECOGNIZED;
- }
- if (field_type == HTML_TYPE_UNSPECIFIED)
+ if (parsing_result->field_type == HTML_TYPE_UNSPECIFIED)
continue;
- // (2) The preceding token, if any, may be a type hint.
- if (!tokens.empty() && IsContactTypeHint(tokens.back())) {
- // If it is, it must match the field type; otherwise, abort.
- // Note that an invalid token invalidates the entire attribute value, even
- // if the other tokens are valid.
- if (!ContactTypeHintMatchesFieldType(tokens.back(), field_type))
- continue;
-
- // Chrome Autofill ignores these type hints.
- tokens.pop_back();
- }
-
- DCHECK_EQ(kDefaultSection, field->section);
- std::string section = field->section;
- HtmlFieldMode mode = HTML_MODE_NONE;
-
- // (3) The preceding token, if any, may be a fixed string that is either
- // "shipping" or "billing". Chrome Autofill treats these as implicit
- // section name suffixes.
- if (!tokens.empty()) {
- if (tokens.back() == kShippingMode)
- mode = HTML_MODE_SHIPPING;
- else if (tokens.back() == kBillingMode)
- mode = HTML_MODE_BILLING;
-
- if (mode != HTML_MODE_NONE) {
- section = "-" + tokens.back();
- tokens.pop_back();
- }
- }
-
- // (4) The preceding token, if any, may be a named section.
- const base::StringPiece kSectionPrefix = "section-";
- if (!tokens.empty() && base::StartsWith(tokens.back(), kSectionPrefix,
- base::CompareCase::SENSITIVE)) {
- // Prepend this section name to the suffix set in the preceding block.
- section = tokens.back().substr(kSectionPrefix.size()) + section;
- tokens.pop_back();
+ // TODO(crbug.com/702223): Flesh out support for UPI-VPA.
+ if (parsing_result->field_type == HTML_TYPE_UPI_VPA) {
+ has_author_specified_upi_vpa_hint_ = true;
+ parsing_result->field_type = HTML_TYPE_UNRECOGNIZED;
}
- // (5) No other tokens are allowed. If there are any remaining, abort.
- if (!tokens.empty())
- continue;
-
- if (section != kDefaultSection) {
+ // Compute a section name based on the specified hints and apply the result.
+ if (field->section.SetPrefixFromAutocomplete(
+ {.section = parsing_result->section,
+ .mode = parsing_result->mode})) {
has_author_specified_sections_ = true;
- field->section = section;
}
-
- // No errors encountered while parsing!
- // Update the |field|'s type based on what was parsed from the attribute.
- field->SetHtmlType(field_type, mode);
+ field->SetHtmlType(parsing_result->field_type, parsing_result->mode);
}
-
was_parsed_for_autocomplete_attributes_ = true;
}
@@ -1567,13 +1287,12 @@ void FormStructure::ParseFieldTypesWithPatterns(PatternSource pattern_source,
LogManager* log_manager) {
FieldCandidatesMap field_type_map;
if (ShouldRunHeuristics()) {
- field_type_map =
- FormField::ParseFormFields(fields_, current_page_language_,
- is_form_tag_, pattern_source, log_manager);
- } else if (ShouldRunPromoCodeHeuristics()) {
- field_type_map = FormField::ParseFormFieldsForPromoCodes(
- fields_, current_page_language_, is_form_tag_, pattern_source,
- log_manager);
+ FormField::ParseFormFields(fields_, current_page_language_, is_form_tag_,
+ pattern_source, field_type_map, log_manager);
+ } else if (ShouldRunHeuristicsForSingleFieldForms()) {
+ FormField::ParseSingleFieldForms(fields_, current_page_language_,
+ is_form_tag_, pattern_source,
+ field_type_map, log_manager);
}
if (field_type_map.empty())
return;
@@ -1680,7 +1399,6 @@ void FormStructure::RationalizeCreditCardFieldPredictions(
cc_cvc_found = true;
break;
case ADDRESS_HOME_ZIP:
- case ADDRESS_BILLING_ZIP:
// Zip/Postal code often appears as part of a Credit Card form. Do
// not count it as a non-cc-related field.
break;
@@ -1712,7 +1430,8 @@ void FormStructure::RationalizeCreditCardFieldPredictions(
cc_num_found || num_cc_fields_found >= 3 || num_other_fields_found == 0;
if (!keep_cc_fields && num_cc_fields_found && log_manager) {
- LogRationalization(log_manager)
+ LOG_AF(log_manager)
+ << LoggingScope::kRationalization << LogMessage::kRationalization
<< "Credit card rationalization: Did not find credit card number, did "
"not find >= 3 credit card fields ("
<< num_cc_fields_found << "), and had non-cc fields ("
@@ -1759,7 +1478,9 @@ void FormStructure::RationalizeCreditCardFieldPredictions(
// month field(s) not immediately preceding an expiry year field.
if (!keep_cc_fields || !cc_date_found) {
if (!cc_date_found && log_manager) {
- LogRationalization(log_manager)
+ LOG_AF(log_manager)
+ << LoggingScope::kRationalization
+ << LogMessage::kRationalization
<< "Credit card rationalization: Found CC expiration month but "
"not a full date.";
}
@@ -1768,7 +1489,9 @@ void FormStructure::RationalizeCreditCardFieldPredictions(
auto it2 = it + 1;
if (it2 == fields_.end()) {
field->SetTypeTo(AutofillType(UNKNOWN_TYPE));
- LogRationalization(log_manager)
+ LOG_AF(log_manager)
+ << LoggingScope::kRationalization
+ << LogMessage::kRationalization
<< "Credit card rationalization: Found multiple expiration "
"months and the last field was an expiration month";
field->SetTypeTo(AutofillType(UNKNOWN_TYPE));
@@ -1778,7 +1501,9 @@ void FormStructure::RationalizeCreditCardFieldPredictions(
next_field_type != CREDIT_CARD_EXP_4_DIGIT_YEAR) {
field->SetTypeTo(AutofillType(UNKNOWN_TYPE));
}
- LogRationalization(log_manager)
+ LOG_AF(log_manager)
+ << LoggingScope::kRationalization
+ << LogMessage::kRationalization
<< "Credit card rationalization: Found multiple expiration "
"months and the field following one is not an "
"expiration year but "
@@ -1791,7 +1516,9 @@ void FormStructure::RationalizeCreditCardFieldPredictions(
if (!keep_cc_fields || !cc_date_found) {
field->SetTypeTo(AutofillType(UNKNOWN_TYPE));
if (!cc_date_found && log_manager) {
- LogRationalization(log_manager)
+ LOG_AF(log_manager)
+ << LoggingScope::kRationalization
+ << LogMessage::kRationalization
<< "Credit card rationalization: Found expiration year but no "
"full expriration date.";
}
@@ -1825,7 +1552,8 @@ void FormStructure::RationalizeStreetAddressAndAddressLine(
continue;
}
if (log_manager) {
- LogRationalization(log_manager)
+ LOG_AF(log_manager)
+ << LoggingScope::kRationalization << LogMessage::kRationalization
<< "Street Address Rationalization: Converting sequence of (street "
"address, address line 2) to (address line 1, address line 2)";
}
@@ -1833,9 +1561,8 @@ void FormStructure::RationalizeStreetAddressAndAddressLine(
}
}
-void FormStructure::RationalizePhoneNumbersInSection(
- const std::string& section) {
- if (phone_rationalized_[section])
+void FormStructure::RationalizePhoneNumbersInSection(const Section& section) {
+ if (base::Contains(phone_rationalized_, section))
return;
std::vector<AutofillField*> fields;
for (size_t i = 0; i < field_count(); ++i) {
@@ -1844,7 +1571,7 @@ void FormStructure::RationalizePhoneNumbersInSection(
fields.push_back(field(i));
}
rationalization_util::RationalizePhoneNumberFields(fields);
- phone_rationalized_[section] = true;
+ phone_rationalized_.insert(section);
}
void FormStructure::ApplyRationalizationsToFieldAndLog(
@@ -1880,24 +1607,30 @@ void FormStructure::RationalizeAddressLineFields(
int nb_address_rationalized = 0;
for (auto field_index : *current_section) {
- LogBufferSubmitter log_submitter = LogRationalization(log_manager);
- log_submitter
+ LOG_AF(log_manager)
+ << LoggingScope::kRationalization << LogMessage::kRationalization
<< "RationalizeAddressLineFields ADDRESS_HOME_STREET_ADDRESS to ";
switch (nb_address_rationalized) {
case 0:
ApplyRationalizationsToFieldAndLog(field_index, ADDRESS_HOME_LINE1,
form_interactions_ukm_logger);
- log_submitter << "ADDRESS_HOME_LINE1";
+ LOG_AF(log_manager)
+ << LoggingScope::kRationalization << LogMessage::kRationalization
+ << "ADDRESS_HOME_LINE1";
break;
case 1:
ApplyRationalizationsToFieldAndLog(field_index, ADDRESS_HOME_LINE2,
form_interactions_ukm_logger);
- log_submitter << "ADDRESS_HOME_LINE2";
+ LOG_AF(log_manager)
+ << LoggingScope::kRationalization << LogMessage::kRationalization
+ << "ADDRESS_HOME_LINE2";
break;
case 2:
ApplyRationalizationsToFieldAndLog(field_index, ADDRESS_HOME_LINE3,
form_interactions_ukm_logger);
- log_submitter << "ADDRESS_HOME_LINE3";
+ LOG_AF(log_manager)
+ << LoggingScope::kRationalization << LogMessage::kRationalization
+ << "ADDRESS_HOME_LINE3";
break;
default:
NOTREACHED();
@@ -2005,14 +1738,13 @@ void FormStructure::RationalizeAddressStateCountry(
AutofillMetrics::FormInteractionsUkmLogger* form_interactions_ukm_logger,
LogManager* log_manager) {
// Walk on the sections of state and country indexes simultaneously. If they
- // both point to the same section, it means that that section includes both
- // the country and the state type. This means that no that rationalization is
- // needed. So, walk both pointers forward. Otherwise, look at the section that
- // appears earlier on the form. That section doesn't have any field of the
- // other type. Rationalize the fields on the earlier section if needed. Walk
- // the pointer that points to the earlier section forward. Stop when both
- // sections of indexes are processed. (This resembles the merge in the merge
- // sort.)
+ // both point to the same section, it means that the section includes both the
+ // country and the state type. This means that no rationalization is needed.
+ // So, walk both pointers forward. Otherwise, look at the section that appears
+ // earlier on the form. That section doesn't have any field of the other type.
+ // Rationalize the fields on the earlier section if needed. Walk the pointer
+ // that points to the earlier section forward. Stop when both sections of
+ // indexes are processed. (This resembles the merge in the merge sort.)
sections_of_state_indexes->Reset();
sections_of_country_indexes->Reset();
@@ -2073,7 +1805,8 @@ void FormStructure::RationalizeAddressStateCountry(
ApplyRationalizationsToFields(
upper_index, lower_index, fields_[upper_index]->heuristic_type(),
fields_[lower_index]->heuristic_type(), form_interactions_ukm_logger);
- LogRationalization(log_manager)
+ LOG_AF(log_manager)
+ << LoggingScope::kRationalization << LogMessage::kRationalization
<< "RationalizeAddressStateCountry: Heuristics are applicable";
continue;
}
@@ -2082,14 +1815,18 @@ void FormStructure::RationalizeAddressStateCountry(
ApplyRationalizationsToFields(upper_index, lower_index,
ADDRESS_HOME_COUNTRY, ADDRESS_HOME_STATE,
form_interactions_ukm_logger);
- LogRationalization(log_manager) << "RationalizeAddressStateCountry: "
- "FieldShouldBeRationalizedToCountry";
+ LOG_AF(log_manager) << LoggingScope::kRationalization
+ << LogMessage::kRationalization
+ << "RationalizeAddressStateCountry: "
+ "FieldShouldBeRationalizedToCountry";
} else {
ApplyRationalizationsToFields(upper_index, lower_index,
ADDRESS_HOME_STATE, ADDRESS_HOME_COUNTRY,
form_interactions_ukm_logger);
- LogRationalization(log_manager) << "RationalizeAddressStateCountry: "
- "!FieldShouldBeRationalizedToCountry";
+ LOG_AF(log_manager) << LoggingScope::kRationalization
+ << LogMessage::kRationalization
+ << "RationalizeAddressStateCountry: "
+ "!FieldShouldBeRationalizedToCountry";
}
}
}
@@ -2129,8 +1866,6 @@ void FormStructure::RationalizeRepeatedFields(
RationalizeAddressLineFields(
&(sectioned_field_indexes_by_type[ADDRESS_HOME_STREET_ADDRESS]),
form_interactions_ukm_logger, log_manager);
- // Since the billing types are mapped to the non-billing ones, no need to
- // take care of ADDRESS_BILLING_STATE and .. .
RationalizeAddressStateCountry(
&(sectioned_field_indexes_by_type[ADDRESS_HOME_STATE]),
&(sectioned_field_indexes_by_type[ADDRESS_HOME_COUNTRY]),
@@ -2140,9 +1875,8 @@ void FormStructure::RationalizeRepeatedFields(
void FormStructure::RationalizeFieldTypePredictions(LogManager* log_manager) {
RationalizeCreditCardFieldPredictions(log_manager);
RationalizeStreetAddressAndAddressLine(log_manager);
- for (const auto& field : fields_) {
+ for (const auto& field : fields_)
field->SetTypeTo(field->Type());
- }
RationalizeTypeRelationships(log_manager);
}
@@ -2295,9 +2029,11 @@ void FormStructure::IdentifySectionsWithNewMethod() {
base::FeatureList::IsEnabled(
features::kAutofillSectionUponRedundantNameInfo);
+ // Create a unique identifier for the section based on the field.
base::flat_map<LocalFrameToken, size_t> frame_token_ids;
- std::u16string current_section =
- GetSectionName(*fields_.front(), frame_token_ids);
+ Section current_section;
+ current_section.SetPrefixFromFieldIdentifier(*fields_.front(),
+ frame_token_ids);
// Keep track of the types we've seen in this section.
ServerFieldTypeSet seen_types;
@@ -2308,13 +2044,13 @@ void FormStructure::IdentifySectionsWithNewMethod() {
bool previous_autocomplete_section_present = false;
bool is_hidden_section = false;
- std::u16string last_visible_section;
+ Section last_visible_section;
for (const auto& field : fields_) {
const ServerFieldType current_type = field->Type().GetStorableType();
// All credit card fields belong to the same section that's different
// from address sections.
if (AutofillType(current_type).group() == FieldTypeGroup::kCreditCard) {
- field->section = "credit-card";
+ field->section.SetPrefixToCreditCard();
continue;
}
@@ -2365,24 +2101,20 @@ void FormStructure::IdentifySectionsWithNewMethod() {
if (current_type == previous_type)
already_saw_current_type = false;
- // Boolean flag that is set to true when the |field| has
- // autocomplete-section attribute defined.
- bool autocomplete_section_attribute_present =
- (field->section != kDefaultSection);
-
- // Boolean flag that is set to true when the |field| has
- // autocomplete-section attribute defined and is different that the
- // previous field.
- bool different_autocomplete_section_than_previous =
- (autocomplete_section_attribute_present &&
- (!field_index || fields_[field_index - 1]->section != field->section));
-
- // Start a new section if the |current_type| was already seen or the
- // autocomplete-section attribute is defined for the |field| which is
- // different than the previous field.
+ // Boolean flag that is set to true when the section of the `field` is
+ // derived from the autocomplete attribute and its section is different than
+ // the previous field's section.
+ bool different_autocomplete_section_than_previous_field_section =
+ field->section.is_from_autocomplete() &&
+ (field_index == 0 ||
+ fields_[field_index - 1]->section != field->section);
+
+ // Start a new section if the `current_type` was already seen or the section
+ // is derived from the autocomplete attribute which is different than the
+ // previous field's section.
if (current_type != UNKNOWN_TYPE &&
(already_saw_current_type ||
- different_autocomplete_section_than_previous)) {
+ different_autocomplete_section_than_previous_field_section)) {
// Keep track of seen_types if the new section is hidden. The next
// visible section might be the continuation of the previous visible
// section.
@@ -2391,33 +2123,34 @@ void FormStructure::IdentifySectionsWithNewMethod() {
last_visible_section = current_section;
}
- if (!is_hidden_section && (!autocomplete_section_attribute_present ||
- different_autocomplete_section_than_previous))
+ if (!is_hidden_section &&
+ (!field->section.is_from_autocomplete() ||
+ different_autocomplete_section_than_previous_field_section)) {
seen_types.clear();
+ }
- if (autocomplete_section_attribute_present &&
+ if (field->section.is_from_autocomplete() &&
!previous_autocomplete_section_present) {
// If this field is the first field within the section with a defined
// autocomplete section, then change the section attribute of all the
- // parsed fields in the current section to |field->section|.
+ // parsed fields in the current section to `field->section`.
int i = static_cast<int>(field_index - 1);
- while (i >= 0 &&
- base::UTF8ToUTF16(fields_[i]->section) == current_section) {
+ while (i >= 0 && fields_[i]->section == current_section) {
fields_[i]->section = field->section;
i--;
}
}
// The end of a section, so start a new section.
- current_section = GetSectionName(*field, frame_token_ids);
+ current_section.SetPrefixFromFieldIdentifier(*field, frame_token_ids);
// The section described in the autocomplete section attribute
// overrides the value determined by the heuristic.
- if (autocomplete_section_attribute_present)
- current_section = base::UTF8ToUTF16(field->section);
+ if (field->section.is_from_autocomplete())
+ current_section = field->section;
previous_autocomplete_section_present =
- autocomplete_section_attribute_present;
+ field->section.is_from_autocomplete();
}
// Only consider a type "seen" if it was not ignored. Some forms have
@@ -2433,17 +2166,17 @@ void FormStructure::IdentifySectionsWithNewMethod() {
is_hidden_section = false;
}
- field->section = base::UTF16ToUTF8(current_section);
+ field->section = current_section;
}
// Ensure that credit card and address fields are in separate sections.
// This simplifies the section-aware logic in autofill_manager.cc.
for (const auto& field : fields_) {
FieldTypeGroup field_type_group = field->Type().group();
- if (field_type_group == FieldTypeGroup::kCreditCard)
- field->section = field->section + "-cc";
- else
- field->section = field->section + "-default";
+ field->section.set_field_type_group(
+ field_type_group == FieldTypeGroup::kCreditCard
+ ? Section::FieldTypeGroupSuffix::kCreditCard
+ : Section::FieldTypeGroupSuffix::kDefault);
}
// Since this function has changed the sections, subsequent calls to
@@ -2467,22 +2200,24 @@ void FormStructure::IdentifySections(bool has_author_specified_sections) {
features::kAutofillSectionUponRedundantNameInfo);
if (!has_author_specified_sections) {
+ // Create a unique identifier based on the field for the section.
base::flat_map<LocalFrameToken, size_t> frame_token_ids;
- std::u16string current_section =
- GetSectionName(*fields_.front(), frame_token_ids);
+ Section current_section;
+ current_section.SetPrefixFromFieldIdentifier(*fields_.front(),
+ frame_token_ids);
// Keep track of the types we've seen in this section.
ServerFieldTypeSet seen_types;
ServerFieldType previous_type = UNKNOWN_TYPE;
bool is_hidden_section = false;
- std::u16string last_visible_section;
+ Section last_visible_section;
for (const auto& field : fields_) {
const ServerFieldType current_type = field->Type().GetStorableType();
// All credit card fields belong to the same section that's different
// from address sections.
if (AutofillType(current_type).group() == FieldTypeGroup::kCreditCard) {
- field->section = "credit-card";
+ field->section.SetPrefixToCreditCard();
continue;
}
@@ -2533,9 +2268,7 @@ void FormStructure::IdentifySections(bool has_author_specified_sections) {
if (current_type == previous_type)
already_saw_current_type = false;
- // Start a new section if the |current_type| was already seen or the
- // autocomplete-section attribute is defined for the |field| which is
- // different than the previous field.
+ // Start a new section if the |current_type| was already seen.
if (current_type != UNKNOWN_TYPE && already_saw_current_type) {
// Keep track of seen_types if the new section is hidden. The next
// visible section might be the continuation of the previous visible
@@ -2549,7 +2282,7 @@ void FormStructure::IdentifySections(bool has_author_specified_sections) {
seen_types.clear();
// The end of a section, so start a new section.
- current_section = GetSectionName(*field, frame_token_ids);
+ current_section.SetPrefixFromFieldIdentifier(*field, frame_token_ids);
}
// Only consider a type "seen" if it was not ignored. Some forms have
@@ -2565,7 +2298,7 @@ void FormStructure::IdentifySections(bool has_author_specified_sections) {
is_hidden_section = false;
}
- field->section = base::UTF16ToUTF8(current_section);
+ field->section = current_section;
}
}
@@ -2573,10 +2306,10 @@ void FormStructure::IdentifySections(bool has_author_specified_sections) {
// This simplifies the section-aware logic in autofill_manager.cc.
for (const auto& field : fields_) {
FieldTypeGroup field_type_group = field->Type().group();
- if (field_type_group == FieldTypeGroup::kCreditCard)
- field->section = field->section + "-cc";
- else
- field->section = field->section + "-default";
+ field->section.set_field_type_group(
+ field_type_group == FieldTypeGroup::kCreditCard
+ ? Section::FieldTypeGroupSuffix::kCreditCard
+ : Section::FieldTypeGroupSuffix::kDefault);
}
// Since this function has changed the sections, subsequent calls to
@@ -2678,7 +2411,7 @@ void FormStructure::RationalizeTypeRelationships(LogManager* log_manager) {
// We have relationship rules for this type, but no `neccessary_type` was
// found. Disabling Autofill for this field.
field->SetTypeTo(AutofillType(UNKNOWN_TYPE));
- LogRationalization(log_manager)
+ LOG_AF(log_manager)
<< "RationalizeTypeRelationships: Fields of type "
<< FieldTypeToStringPiece(field_type)
<< " can only exist if other fields of specific types exist.";
@@ -2825,8 +2558,14 @@ LogBuffer& operator<<(LogBuffer& buffer, const FormStructure& form) {
buffer << Tr{} << "Section:" << field->section;
constexpr size_t kMaxLabelSize = 100;
+ // TODO(crbug/1165780): Remove once shared labels are launched.
+ const std::u16string& label =
+ base::FeatureList::IsEnabled(
+ features::kAutofillEnableSupportForParsingWithSharedLabels)
+ ? field->parseable_label()
+ : field->label;
const std::u16string truncated_label =
- field->label.substr(0, std::min(field->label.length(), kMaxLabelSize));
+ label.substr(0, std::min(label.length(), kMaxLabelSize));
buffer << Tr{} << "Label:" << truncated_label;
buffer << Tr{} << "Is empty:" << (field->IsEmpty() ? "Yes" : "No");
diff --git a/chromium/components/autofill/core/browser/form_structure.h b/chromium/components/autofill/core/browser/form_structure.h
index ca9a21f1382..1c0859df4e6 100644
--- a/chromium/components/autofill/core/browser/form_structure.h
+++ b/chromium/components/autofill/core/browser/form_structure.h
@@ -7,7 +7,6 @@
#include <stddef.h>
-#include <map>
#include <memory>
#include <set>
#include <string>
@@ -25,6 +24,7 @@
#include "components/autofill/core/browser/metrics/form_interactions_counter.h"
#include "components/autofill/core/browser/proto/api_v1.pb.h"
#include "components/autofill/core/common/dense_set.h"
+#include "components/autofill/core/common/form_field_data.h"
#include "components/autofill/core/common/language_code.h"
#include "components/autofill/core/common/mojom/autofill_types.mojom.h"
#include "components/autofill/core/common/unique_ids.h"
@@ -171,9 +171,10 @@ class FormStructure {
// this form.
bool ShouldRunHeuristics() const;
- // Returns true if heuristic autofill type detection for promo codes should be
- // attempted for this form.
- bool ShouldRunPromoCodeHeuristics() const;
+ // Returns true if autofill's heuristic field type detection should be
+ // attempted for this form given that |kMinRequiredFieldsForHeuristics| is not
+ // met.
+ bool ShouldRunHeuristicsForSingleFieldForms() const;
// Returns true if we should query the crowd-sourcing server to determine this
// form's field types. If the form includes author-specified types, this will
@@ -246,7 +247,7 @@ class FormStructure {
// 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(const std::string& section);
+ void RationalizePhoneNumbersInSection(const Section& section);
// Overrides server predictions with specific heuristic predictions:
// * NAME_LAST_SECOND heuristic predictions are unconditionally used.
@@ -667,7 +668,7 @@ class FormStructure {
base::TimeTicks form_parsed_timestamp_;
// If phone number rationalization has been performed for a given section.
- std::map<std::string, bool> phone_rationalized_;
+ std::set<Section> phone_rationalized_;
// True iff the form is a password form and the user has seen the password
// value before accepting the prompt to save. Used for crowdsourcing.
diff --git a/chromium/components/autofill/core/browser/test_form_structure.cc b/chromium/components/autofill/core/browser/form_structure_test_api.cc
index cbf12d6c15b..a1a1b79a6b9 100644
--- a/chromium/components/autofill/core/browser/test_form_structure.cc
+++ b/chromium/components/autofill/core/browser/form_structure_test_api.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_form_structure.h"
+#include "components/autofill/core/browser/form_structure_test_api.h"
#include "components/autofill/core/browser/form_parsing/field_candidates.h"
#include "testing/gmock/include/gmock/gmock.h"
@@ -15,39 +15,19 @@ using ::testing::Contains;
using ::testing::Each;
using ::testing::Pair;
-TestFormStructure::TestFormStructure(const FormData& form)
- : FormStructure(form) {}
-
-TestFormStructure::~TestFormStructure() {}
-
-void TestFormStructure::SetFieldTypes(
- const std::vector<ServerFieldType>& heuristic_types,
- const std::vector<ServerFieldType>& server_types) {
- std::vector<std::vector<std::pair<PatternSource, ServerFieldType>>>
- all_heuristic_types;
-
- base::ranges::transform(
- heuristic_types, std::back_inserter(all_heuristic_types),
- [](ServerFieldType type)
- -> std::vector<std::pair<PatternSource, ServerFieldType>> {
- return {{GetActivePatternSource(), type}};
- });
-
- SetFieldTypes(all_heuristic_types, server_types);
-}
-
-void TestFormStructure::SetFieldTypes(
+// static
+void FormStructureTestApi::SetFieldTypes(
const std::vector<std::vector<std::pair<PatternSource, ServerFieldType>>>&
heuristic_types,
const std::vector<ServerFieldType>& server_types) {
- ASSERT_EQ(field_count(), heuristic_types.size());
- ASSERT_EQ(field_count(), server_types.size());
+ ASSERT_EQ(form_structure_->field_count(), heuristic_types.size());
+ ASSERT_EQ(form_structure_->field_count(), server_types.size());
ASSERT_THAT(heuristic_types,
Each(Contains(Pair(GetActivePatternSource(), _))))
<< "There must be a default heuristic prediction for every field.";
- for (size_t i = 0; i < field_count(); ++i) {
- AutofillField* form_field = field(i);
+ for (size_t i = 0; i < form_structure_->field_count(); ++i) {
+ AutofillField* form_field = form_structure_->field(i);
ASSERT_TRUE(form_field);
for (const auto& [source, type] : heuristic_types[i])
@@ -58,7 +38,17 @@ void TestFormStructure::SetFieldTypes(
form_field->set_server_predictions({prediction});
}
- UpdateAutofillCount();
+ form_structure_->UpdateAutofillCount();
+}
+
+void FormStructureTestApi::SetFieldTypes(
+ const std::vector<ServerFieldType>& heuristic_types,
+ const std::vector<ServerFieldType>& server_types) {
+ std::vector<std::vector<std::pair<PatternSource, ServerFieldType>>>
+ all_heuristic_types;
+ for (ServerFieldType type : heuristic_types)
+ all_heuristic_types.push_back({{GetActivePatternSource(), type}});
+ SetFieldTypes(all_heuristic_types, server_types);
}
} // namespace autofill
diff --git a/chromium/components/autofill/core/browser/form_structure_test_api.h b/chromium/components/autofill/core/browser/form_structure_test_api.h
index 08894272f87..eeca25c1f6a 100644
--- a/chromium/components/autofill/core/browser/form_structure_test_api.h
+++ b/chromium/components/autofill/core/browser/form_structure_test_api.h
@@ -7,6 +7,7 @@
#include <string>
+#include "base/containers/contains.h"
#include "base/memory/raw_ptr.h"
#include "base/strings/string_piece.h"
#include "components/autofill/core/browser/form_structure.h"
@@ -42,6 +43,22 @@ class FormStructureTestApi {
DCHECK(form_structure_);
}
+ // Set the heuristic and server types for each field. The `heuristic_types`
+ // and `server_types` vectors must be aligned with the indices of the fields
+ // in the form. For each field in `heuristic_types` there must be exactly one
+ // `GetActivePatternSource()` prediction and any number of alternative
+ // predictions.
+ void SetFieldTypes(
+ const std::vector<std::vector<std::pair<PatternSource, ServerFieldType>>>&
+ heuristic_types,
+ const std::vector<ServerFieldType>& server_types);
+
+ // Set the heuristic and server types for each field. The `heuristic_types`
+ // and `server_types` vectors must be aligned with the indices of the fields
+ // in the form.
+ void SetFieldTypes(const std::vector<ServerFieldType>& heuristic_types,
+ const std::vector<ServerFieldType>& server_types);
+
const std::vector<std::unique_ptr<AutofillField>>& fields() {
return form_structure_->fields_;
}
@@ -50,9 +67,8 @@ class FormStructureTestApi {
form_structure_->IdentifySections(has_author_specified_sections);
}
- bool phone_rationalized(const std::string& section) const {
- auto it = form_structure_->phone_rationalized_.find(section);
- return it != form_structure_->phone_rationalized_.end() && it->second;
+ bool phone_rationalized(const Section& section) const {
+ return base::Contains(form_structure_->phone_rationalized_, section);
}
void ParseFieldTypesWithPatterns(PatternSource pattern_source) {
diff --git a/chromium/components/autofill/core/browser/form_structure_unittest.cc b/chromium/components/autofill/core/browser/form_structure_unittest.cc
index 8bfe6ca5cd3..f88a89d1490 100644
--- a/chromium/components/autofill/core/browser/form_structure_unittest.cc
+++ b/chromium/components/autofill/core/browser/form_structure_unittest.cc
@@ -28,6 +28,7 @@
#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"
+#include "components/autofill/core/common/html_field_types.h"
#include "components/autofill/core/common/signatures.h"
#include "components/prefs/pref_registry_simple.h"
#include "components/prefs/pref_service.h"
@@ -152,8 +153,8 @@ class FormStructureTestImpl : public test::FormStructureTest {
return FormStructure(form).ShouldRunHeuristics();
}
- bool FormShouldRunPromoCodeHeuristics(const FormData& form) {
- return FormStructure(form).ShouldRunPromoCodeHeuristics();
+ bool FormShouldRunHeuristicsForSingleFieldForms(const FormData& form) {
+ return FormStructure(form).ShouldRunHeuristicsForSingleFieldForms();
}
bool FormShouldBeQueried(const FormData& form) {
@@ -573,6 +574,20 @@ TEST_F(FormStructureTestImpl, ShouldBeParsed_TwoFields_HasAutocomplete) {
EXPECT_TRUE(form_structure->ShouldBeParsed());
}
+// Tests that unmappable autocomplete values containing "address" are treated
+// as HTML_TYPE_UNSPECIFIED instead of HTML_TYPE_UNRECOGNIZED.
+TEST_F(FormStructureTestImpl, IgnoreUnmappableAutocompleteValues) {
+ base::test::ScopedFeatureList feature_list;
+ feature_list.InitAndEnableFeature(
+ features::kAutofillIgnoreUnmappableAutocompleteValues);
+
+ CheckFormStructureTestData(
+ {{{.description_for_logging = "IgnoreUnmappableAutocompleteValues",
+ .fields = {{.autocomplete_attribute = "address-info"}}},
+ {.determine_heuristic_type = true},
+ {.expected_html_type = {HTML_TYPE_UNSPECIFIED}}}});
+}
+
// Tests that ShouldBeParsed returns true for a form containing less than three
// fields if at least one has an autocomplete attribute.
TEST_F(FormStructureTestImpl, DetermineHeuristicTypes_AutocompleteFalse) {
@@ -1019,10 +1034,7 @@ TEST_F(FormStructureTestImpl, HeuristicsAutocompleteAttributePhoneTypes) {
.field_count = 3,
.autofill_count = 3},
{.expected_html_type = {HTML_TYPE_TEL_LOCAL, HTML_TYPE_TEL_LOCAL_PREFIX,
- HTML_TYPE_TEL_LOCAL_SUFFIX},
- .expected_phone_part = {AutofillField::IGNORED,
- AutofillField::PHONE_PREFIX,
- AutofillField::PHONE_SUFFIX}}}});
+ HTML_TYPE_TEL_LOCAL_SUFFIX}}}});
}
// The heuristics and server predictions should run if there are more than two
@@ -1171,7 +1183,8 @@ TEST_F(FormStructureTestImpl,
}
}
-// Tests that promo code heuristics are run for forms with fewer than 3 fields.
+// Tests that heuristics for single field parseable types are run for forms with
+// fewer than 3 fields.
TEST_F(FormStructureTestImpl, PromoCodeHeuristics_SmallForm) {
base::test::ScopedFeatureList scoped_feature;
scoped_feature.InitAndEnableFeature(
@@ -1187,7 +1200,7 @@ TEST_F(FormStructureTestImpl, PromoCodeHeuristics_SmallForm) {
field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
- EXPECT_TRUE(FormShouldRunPromoCodeHeuristics(form));
+ EXPECT_TRUE(FormShouldRunHeuristicsForSingleFieldForms(form));
// Default configuration.
{
@@ -1310,7 +1323,7 @@ TEST_F(FormStructureTestImpl, HeuristicsAutocompleteAttributeWithSections) {
// All of the fields in this form should be parsed as belonging to different
// sections.
- std::set<std::string> section_names;
+ std::set<Section> section_names;
for (size_t i = 0; i < 9; ++i) {
section_names.insert(form_structure.field(i)->section);
}
@@ -1364,7 +1377,7 @@ TEST_F(FormStructureTestImpl,
// All of the fields in this form should be parsed as belonging to the same
// section.
- std::set<std::string> section_names;
+ std::set<Section> section_names;
for (size_t i = 0; i < 6; ++i) {
section_names.insert(form_structure.field(i)->section);
}
@@ -1398,7 +1411,7 @@ TEST_F(FormStructureTestImpl,
// All of the fields in this form should be parsed as belonging to the same
// section.
- std::set<std::string> section_names;
+ std::set<Section> section_names;
for (size_t i = 0; i < 2; ++i) {
section_names.insert(form_structure.field(i)->section);
}
@@ -2151,13 +2164,11 @@ TEST_F(FormStructureTestImpl, ThreePartPhoneNumber) {
ASSERT_EQ(4U, form_structure->field_count());
ASSERT_EQ(4U, form_structure->autofill_count());
- // Area code.
EXPECT_EQ(PHONE_HOME_CITY_CODE, form_structure->field(0)->heuristic_type());
- // Phone number suffix.
- EXPECT_EQ(PHONE_HOME_NUMBER, form_structure->field(1)->heuristic_type());
- // Phone number suffix.
- EXPECT_EQ(PHONE_HOME_NUMBER, form_structure->field(2)->heuristic_type());
- // Phone extension.
+ EXPECT_EQ(PHONE_HOME_NUMBER_PREFIX,
+ form_structure->field(1)->heuristic_type());
+ EXPECT_EQ(PHONE_HOME_NUMBER_SUFFIX,
+ form_structure->field(2)->heuristic_type());
EXPECT_EQ(PHONE_HOME_EXTENSION, form_structure->field(3)->heuristic_type());
}
@@ -2696,8 +2707,8 @@ TEST_F(FormStructureTestImpl, EncodeUploadRequest_WithMatchingValidities) {
form_structure->set_password_attributes_vote(
std::make_pair(PasswordAttribute::kHasLowercaseLetter, true));
form_structure->set_password_length_vote(10u);
- for (auto& field : *form_structure)
- field->host_form_signature = form_structure->form_signature();
+ for (auto& fs_field : *form_structure)
+ fs_field->host_form_signature = form_structure->form_signature();
ASSERT_EQ(form_structure->field_count(), possible_field_types.size());
ASSERT_EQ(form_structure->field_count(),
@@ -2714,8 +2725,6 @@ TEST_F(FormStructureTestImpl, EncodeUploadRequest_WithMatchingValidities) {
available_field_types.insert(ADDRESS_HOME_LINE1);
available_field_types.insert(ADDRESS_HOME_LINE2);
available_field_types.insert(ADDRESS_HOME_COUNTRY);
- available_field_types.insert(ADDRESS_BILLING_LINE1);
- available_field_types.insert(ADDRESS_BILLING_LINE2);
available_field_types.insert(EMAIL_ADDRESS);
available_field_types.insert(PHONE_HOME_WHOLE_NUMBER);
@@ -2725,7 +2734,7 @@ TEST_F(FormStructureTestImpl, EncodeUploadRequest_WithMatchingValidities) {
upload.set_client_version(GetProductNameAndVersionForUserAgent());
upload.set_form_signature(form_structure->form_signature().value());
upload.set_autofill_used(false);
- upload.set_data_present("144200030e");
+ upload.set_data_present("1442000308");
upload.set_passwords_revealed(false);
upload.set_password_has_lowercase_letter(true);
upload.set_password_length(10u);
@@ -2770,18 +2779,16 @@ TEST_F(FormStructureTestImpl, EncodeUploadRequest_WithMatchingValidities) {
form.fields.push_back(field);
test::InitializePossibleTypesAndValidities(
possible_field_types, possible_field_types_validities,
- {ADDRESS_HOME_LINE1, ADDRESS_HOME_LINE2, ADDRESS_BILLING_LINE1,
- ADDRESS_BILLING_LINE2},
- {AutofillProfile::VALID, AutofillProfile::VALID,
- AutofillProfile::INVALID, AutofillProfile::INVALID});
+ {ADDRESS_HOME_LINE1, ADDRESS_HOME_LINE2},
+ {AutofillProfile::VALID, AutofillProfile::VALID});
}
form_structure = std::make_unique<FormStructure>(form);
form_structure->set_password_attributes_vote(
std::make_pair(PasswordAttribute::kHasLowercaseLetter, true));
form_structure->set_password_length_vote(10u);
- for (auto& field : *form_structure)
- field->host_form_signature = form_structure->form_signature();
+ for (auto& fs_field : *form_structure)
+ fs_field->host_form_signature = form_structure->form_signature();
ASSERT_EQ(form_structure->field_count(), possible_field_types.size());
ASSERT_EQ(form_structure->field_count(),
@@ -2798,9 +2805,9 @@ TEST_F(FormStructureTestImpl, EncodeUploadRequest_WithMatchingValidities) {
// Create an additional 2 fields (total of 7). Put the appropriate autofill
// type on the different address fields.
test::FillUploadField(upload.add_field(), 509334676U, "address", "text",
- nullptr, {30U, 31U, 37U, 38U}, {2, 2, 3, 3});
+ nullptr, {30U, 31U}, {2, 2});
test::FillUploadField(upload.add_field(), 509334676U, "address", "text",
- nullptr, {30U, 31U, 37U, 38U}, {2, 2, 3, 3});
+ nullptr, {30U, 31U}, {2, 2});
EXPECT_THAT(form_structure->EncodeUploadRequest(available_field_types, false,
std::string(), true, true),
@@ -2879,8 +2886,8 @@ TEST_F(FormStructureTestImpl, EncodeUploadRequest_WithNonMatchingValidities) {
form_structure->set_password_attributes_vote(
std::make_pair(PasswordAttribute::kHasLowercaseLetter, true));
form_structure->set_password_length_vote(10u);
- for (auto& field : *form_structure)
- field->host_form_signature = form_structure->form_signature();
+ for (auto& fs_field : *form_structure)
+ fs_field->host_form_signature = form_structure->form_signature();
ASSERT_EQ(form_structure->field_count(), possible_field_types.size());
ASSERT_EQ(form_structure->field_count(),
@@ -2897,8 +2904,6 @@ TEST_F(FormStructureTestImpl, EncodeUploadRequest_WithNonMatchingValidities) {
available_field_types.insert(ADDRESS_HOME_LINE1);
available_field_types.insert(ADDRESS_HOME_LINE2);
available_field_types.insert(ADDRESS_HOME_COUNTRY);
- available_field_types.insert(ADDRESS_BILLING_LINE1);
- available_field_types.insert(ADDRESS_BILLING_LINE2);
available_field_types.insert(EMAIL_ADDRESS);
available_field_types.insert(PHONE_HOME_WHOLE_NUMBER);
@@ -2908,7 +2913,7 @@ TEST_F(FormStructureTestImpl, EncodeUploadRequest_WithNonMatchingValidities) {
upload.set_client_version(GetProductNameAndVersionForUserAgent());
upload.set_form_signature(form_structure->form_signature().value());
upload.set_autofill_used(false);
- upload.set_data_present("144200030e");
+ upload.set_data_present("1442000308");
upload.set_passwords_revealed(false);
upload.set_password_has_lowercase_letter(true);
upload.set_password_length(10u);
@@ -3005,8 +3010,8 @@ TEST_F(FormStructureTestImpl, EncodeUploadRequest_WithMultipleValidities) {
form_structure->set_password_attributes_vote(
std::make_pair(PasswordAttribute::kHasLowercaseLetter, true));
form_structure->set_password_length_vote(10u);
- for (auto& field : *form_structure)
- field->host_form_signature = form_structure->form_signature();
+ for (auto& fs_field : *form_structure)
+ fs_field->host_form_signature = form_structure->form_signature();
ASSERT_EQ(form_structure->field_count(), possible_field_types.size());
ASSERT_EQ(form_structure->field_count(),
@@ -3023,8 +3028,6 @@ TEST_F(FormStructureTestImpl, EncodeUploadRequest_WithMultipleValidities) {
available_field_types.insert(ADDRESS_HOME_LINE1);
available_field_types.insert(ADDRESS_HOME_LINE2);
available_field_types.insert(ADDRESS_HOME_COUNTRY);
- available_field_types.insert(ADDRESS_BILLING_LINE1);
- available_field_types.insert(ADDRESS_BILLING_LINE2);
available_field_types.insert(EMAIL_ADDRESS);
available_field_types.insert(PHONE_HOME_WHOLE_NUMBER);
@@ -3034,7 +3037,7 @@ TEST_F(FormStructureTestImpl, EncodeUploadRequest_WithMultipleValidities) {
upload.set_client_version(GetProductNameAndVersionForUserAgent());
upload.set_form_signature(form_structure->form_signature().value());
upload.set_autofill_used(false);
- upload.set_data_present("144200030e");
+ upload.set_data_present("1442000308");
upload.set_passwords_revealed(false);
upload.set_password_has_lowercase_letter(true);
upload.set_password_length(10u);
@@ -3128,8 +3131,8 @@ TEST_F(FormStructureTestImpl, EncodeUploadRequest) {
form_structure->set_password_length_vote(10u);
form_structure->set_submission_event(
SubmissionIndicatorEvent::HTML_FORM_SUBMISSION);
- for (auto& field : *form_structure)
- field->host_form_signature = form_structure->form_signature();
+ for (auto& fs_field : *form_structure)
+ fs_field->host_form_signature = form_structure->form_signature();
ASSERT_EQ(form_structure->field_count(), possible_field_types.size());
ASSERT_EQ(form_structure->field_count(),
@@ -3146,8 +3149,6 @@ TEST_F(FormStructureTestImpl, EncodeUploadRequest) {
available_field_types.insert(ADDRESS_HOME_LINE1);
available_field_types.insert(ADDRESS_HOME_LINE2);
available_field_types.insert(ADDRESS_HOME_COUNTRY);
- available_field_types.insert(ADDRESS_BILLING_LINE1);
- available_field_types.insert(ADDRESS_BILLING_LINE2);
available_field_types.insert(EMAIL_ADDRESS);
available_field_types.insert(PHONE_HOME_WHOLE_NUMBER);
@@ -3158,7 +3159,7 @@ TEST_F(FormStructureTestImpl, EncodeUploadRequest) {
upload.set_client_version(GetProductNameAndVersionForUserAgent());
upload.set_form_signature(form_structure->form_signature().value());
upload.set_autofill_used(false);
- upload.set_data_present("144200030e");
+ upload.set_data_present("1442000308");
upload.set_passwords_revealed(false);
upload.set_password_has_lowercase_letter(true);
upload.set_password_length(10u);
@@ -3194,8 +3195,7 @@ TEST_F(FormStructureTestImpl, EncodeUploadRequest) {
form.fields.push_back(field);
test::InitializePossibleTypesAndValidities(
possible_field_types, possible_field_types_validities,
- {ADDRESS_HOME_LINE1, ADDRESS_HOME_LINE2, ADDRESS_BILLING_LINE1,
- ADDRESS_BILLING_LINE2});
+ {ADDRESS_HOME_LINE1, ADDRESS_HOME_LINE2});
}
form_structure = std::make_unique<FormStructure>(form);
@@ -3228,9 +3228,9 @@ TEST_F(FormStructureTestImpl, EncodeUploadRequest) {
}
// Put the appropriate autofill type on the different address fields.
test::FillUploadField(upload.mutable_field(5), 509334676U, "address", "text",
- nullptr, {31U, 37U, 38U});
+ nullptr, 31U);
test::FillUploadField(upload.mutable_field(6), 509334676U, "address", "text",
- nullptr, {31U, 37U, 38U});
+ nullptr, 31U);
EXPECT_THAT(form_structure->EncodeUploadRequest(available_field_types, false,
std::string(), true, true),
@@ -3246,8 +3246,7 @@ TEST_F(FormStructureTestImpl, EncodeUploadRequest) {
form.fields.push_back(field);
test::InitializePossibleTypesAndValidities(
possible_field_types, possible_field_types_validities,
- {ADDRESS_HOME_LINE1, ADDRESS_HOME_LINE2, ADDRESS_BILLING_LINE1,
- ADDRESS_BILLING_LINE2});
+ {ADDRESS_HOME_LINE1, ADDRESS_HOME_LINE2});
}
form_structure = std::make_unique<FormStructure>(form);
ASSERT_EQ(form_structure->field_count(), possible_field_types.size());
@@ -3318,8 +3317,8 @@ TEST_F(FormStructureTestImpl,
{ACCOUNT_CREATION_PASSWORD});
form_structure = std::make_unique<FormStructure>(form);
- for (auto& field : *form_structure)
- field->host_form_signature = form_structure->form_signature();
+ for (auto& fs_field : *form_structure)
+ fs_field->host_form_signature = form_structure->form_signature();
ASSERT_EQ(form_structure->field_count(), possible_field_types.size());
ASSERT_EQ(form_structure->field_count(),
@@ -3431,8 +3430,8 @@ TEST_F(FormStructureTestImpl, EncodeUploadRequest_WithAutocomplete) {
possible_field_types, possible_field_types_validities, {EMAIL_ADDRESS});
form_structure = std::make_unique<FormStructure>(form);
- for (auto& field : *form_structure)
- field->host_form_signature = form_structure->form_signature();
+ for (auto& fs_field : *form_structure)
+ fs_field->host_form_signature = form_structure->form_signature();
ASSERT_EQ(form_structure->field_count(), possible_field_types.size());
ASSERT_EQ(form_structure->field_count(),
@@ -3525,8 +3524,8 @@ TEST_F(FormStructureTestImpl, EncodeUploadRequestWithPropertiesMask) {
possible_field_types, possible_field_types_validities, {EMAIL_ADDRESS});
form_structure = std::make_unique<FormStructure>(form);
- for (auto& field : *form_structure)
- field->host_form_signature = form_structure->form_signature();
+ for (auto& fs_field : *form_structure)
+ fs_field->host_form_signature = form_structure->form_signature();
ASSERT_EQ(form_structure->field_count(), possible_field_types.size());
ASSERT_EQ(form_structure->field_count(),
@@ -3610,8 +3609,8 @@ TEST_F(FormStructureTestImpl, EncodeUploadRequest_ObservedSubmissionFalse) {
possible_field_types, possible_field_types_validities, {EMAIL_ADDRESS});
form_structure = std::make_unique<FormStructure>(form);
- for (auto& field : *form_structure)
- field->host_form_signature = form_structure->form_signature();
+ for (auto& fs_field : *form_structure)
+ fs_field->host_form_signature = form_structure->form_signature();
ASSERT_EQ(form_structure->field_count(), possible_field_types.size());
ASSERT_EQ(form_structure->field_count(),
@@ -3684,8 +3683,8 @@ TEST_F(FormStructureTestImpl, EncodeUploadRequest_WithLabels) {
possible_field_types, possible_field_types_validities, {EMAIL_ADDRESS});
form_structure = std::make_unique<FormStructure>(form);
- for (auto& field : *form_structure)
- field->host_form_signature = form_structure->form_signature();
+ for (auto& fs_field : *form_structure)
+ fs_field->host_form_signature = form_structure->form_signature();
ASSERT_EQ(form_structure->field_count(), possible_field_types.size());
ASSERT_EQ(form_structure->field_count(),
@@ -3757,8 +3756,8 @@ TEST_F(FormStructureTestImpl, EncodeUploadRequest_WithCssClassesAndIds) {
possible_field_types, possible_field_types_validities, {EMAIL_ADDRESS});
std::unique_ptr<FormStructure> form_structure(new FormStructure(form));
- for (auto& field : *form_structure)
- field->host_form_signature = form_structure->form_signature();
+ for (auto& fs_field : *form_structure)
+ fs_field->host_form_signature = form_structure->form_signature();
ASSERT_EQ(form_structure->field_count(), possible_field_types.size());
ASSERT_EQ(form_structure->field_count(),
@@ -3839,8 +3838,8 @@ TEST_F(FormStructureTestImpl, EncodeUploadRequest_WithFormName) {
possible_field_types, possible_field_types_validities, {EMAIL_ADDRESS});
form_structure = std::make_unique<FormStructure>(form);
- for (auto& field : *form_structure)
- field->host_form_signature = form_structure->form_signature();
+ for (auto& fs_field : *form_structure)
+ fs_field->host_form_signature = form_structure->form_signature();
form_structure->set_submission_source(SubmissionSource::FRAME_DETACHED);
ASSERT_EQ(form_structure->field_count(), possible_field_types.size());
@@ -3921,8 +3920,8 @@ TEST_F(FormStructureTestImpl, EncodeUploadRequestPartialMetadata) {
possible_field_types, possible_field_types_validities, {EMAIL_ADDRESS});
form_structure = std::make_unique<FormStructure>(form);
- for (auto& field : *form_structure)
- field->host_form_signature = form_structure->form_signature();
+ for (auto& fs_field : *form_structure)
+ fs_field->host_form_signature = form_structure->form_signature();
ASSERT_EQ(form_structure->field_count(), possible_field_types.size());
ASSERT_EQ(form_structure->field_count(),
@@ -4012,8 +4011,8 @@ TEST_F(FormStructureTestImpl, EncodeUploadRequest_DisabledMetadata) {
possible_field_types, possible_field_types_validities, {EMAIL_ADDRESS});
form_structure = std::make_unique<FormStructure>(form);
- for (auto& field : *form_structure)
- field->host_form_signature = form_structure->form_signature();
+ for (auto& fs_field : *form_structure)
+ fs_field->host_form_signature = form_structure->form_signature();
ASSERT_EQ(form_structure->field_count(), possible_field_types.size());
ASSERT_EQ(form_structure->field_count(),
@@ -4227,8 +4226,8 @@ TEST_F(FormStructureTestImpl, CheckDataPresence) {
FormStructure form_structure(form);
form_structure.set_submission_source(SubmissionSource::FORM_SUBMISSION);
- for (auto& field : form_structure)
- field->host_form_signature = form_structure.form_signature();
+ for (auto& fs_field : form_structure)
+ fs_field->host_form_signature = form_structure.form_signature();
std::vector<ServerFieldTypeSet> possible_field_types;
std::vector<ServerFieldTypeValidityStatesMap> possible_field_types_validities;
@@ -4608,8 +4607,8 @@ TEST_F(FormStructureTestImpl, EncodeUploadRequest_PasswordsRevealed) {
FormStructure form_structure(form);
form_structure.set_passwords_were_revealed(true);
- for (auto& field : form_structure)
- field->host_form_signature = form_structure.form_signature();
+ for (auto& fs_field : form_structure)
+ fs_field->host_form_signature = form_structure.form_signature();
std::vector<AutofillUploadContents> uploads =
form_structure.EncodeUploadRequest(
@@ -4635,8 +4634,8 @@ TEST_F(FormStructureTestImpl, EncodeUploadRequest_IsFormTag) {
form.is_form_tag = is_form_tag;
FormStructure form_structure(form);
- for (auto& field : form_structure)
- field->host_form_signature = form_structure.form_signature();
+ for (auto& fs_field : form_structure)
+ fs_field->host_form_signature = form_structure.form_signature();
form_structure.set_passwords_were_revealed(true);
std::vector<AutofillUploadContents> uploads =
form_structure.EncodeUploadRequest(
@@ -4652,19 +4651,21 @@ TEST_F(FormStructureTestImpl, EncodeUploadRequest_IsFormTag) {
TEST_F(FormStructureTestImpl, EncodeUploadRequest_RichMetadata) {
struct FieldMetadata {
const char *id, *name, *label, *placeholder, *aria_label, *aria_description,
- *css_classes;
+ *css_classes, *autocomplete;
};
static const FieldMetadata kFieldMetadata[] = {
{"fname_id", "fname_name", "First Name:", "Please enter your first name",
- "Type your first name", "You can type your first name here", "blah"},
+ "Type your first name", "You can type your first name here", "blah",
+ "given-name"},
{"lname_id", "lname_name", "Last Name:", "Please enter your last name",
- "Type your lat name", "You can type your last name here", "blah"},
+ "Type your lat name", "You can type your last name here", "blah",
+ "family-name"},
{"email_id", "email_name", "Email:", "Please enter your email address",
"Type your email address", "You can type your email address here",
- "blah"},
- {"id_only", "", "", "", "", "", ""},
- {"", "name_only", "", "", "", "", ""},
+ "blah", "email"},
+ {"id_only", "", "", "", "", "", "", ""},
+ {"", "name_only", "", "", "", "", "", ""},
};
FormData form;
@@ -4683,6 +4684,7 @@ TEST_F(FormStructureTestImpl, EncodeUploadRequest_RichMetadata) {
field.aria_label = ASCIIToUTF16(f.aria_label);
field.aria_description = ASCIIToUTF16(f.aria_description);
field.css_classes = ASCIIToUTF16(f.css_classes);
+ field.autocomplete_attribute = f.autocomplete;
field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
}
@@ -4812,6 +4814,15 @@ TEST_F(FormStructureTestImpl, EncodeUploadRequest_RichMetadata) {
RandomizedEncoder::FIELD_PLACEHOLDER,
field.placeholder));
}
+ if (field.autocomplete_attribute.empty()) {
+ EXPECT_FALSE(metadata.has_autocomplete());
+ } else {
+ EXPECT_EQ(metadata.autocomplete().encoded_bits(),
+ encoder.EncodeForTesting(
+ form_signature, field_signature,
+ RandomizedEncoder::FIELD_AUTOCOMPLETE,
+ base::UTF8ToUTF16(field.autocomplete_attribute)));
+ }
}
}
@@ -5129,8 +5140,8 @@ TEST_F(FormStructureTestImpl, EncodeQueryRequest_MissingNames) {
form.fields.push_back(field);
FormStructure form_structure(form);
- for (auto& field : form_structure)
- field->host_form_signature = form_structure.form_signature();
+ for (auto& fs_field : form_structure)
+ fs_field->host_form_signature = form_structure.form_signature();
std::vector<FormStructure*> forms;
forms.push_back(&form_structure);
@@ -5166,8 +5177,8 @@ TEST_F(FormStructureTestImpl, EncodeUploadRequest_WithSingleUsernameVoteType) {
FormStructure form_structure(form);
form_structure.field(0)->set_single_username_vote_type(
AutofillUploadContents::Field::STRONG);
- for (auto& field : form_structure)
- field->host_form_signature = form_structure.form_signature();
+ for (auto& fs_field : form_structure)
+ fs_field->host_form_signature = form_structure.form_signature();
std::vector<AutofillUploadContents> uploads =
form_structure.EncodeUploadRequest(
@@ -5823,7 +5834,7 @@ TEST_F(FormStructureTestImpl, ParseApiQueryResponse) {
auto* field_prediction0 = field0->add_predictions();
field_prediction0->set_type(NAME_FULL);
auto* field_prediction1 = field0->add_predictions();
- field_prediction1->set_type(PHONE_FAX_COUNTRY_CODE);
+ field_prediction1->set_type(PHONE_HOME_COUNTRY_CODE);
AddFieldSuggestionToForm(form_suggestion, form.fields[1], ADDRESS_HOME_LINE1);
// Make form 2 suggestions.
form_suggestion = api_response.add_form_suggestions();
@@ -5846,7 +5857,8 @@ TEST_F(FormStructureTestImpl, ParseApiQueryResponse) {
EXPECT_EQ(NAME_FULL, forms[0]->field(0)->server_type());
ASSERT_EQ(2U, forms[0]->field(0)->server_predictions().size());
EXPECT_EQ(NAME_FULL, forms[0]->field(0)->server_predictions()[0].type());
- EXPECT_EQ(NO_SERVER_DATA, forms[0]->field(0)->server_predictions()[1].type());
+ EXPECT_EQ(PHONE_HOME_COUNTRY_CODE,
+ forms[0]->field(0)->server_predictions()[1].type());
EXPECT_EQ(ADDRESS_HOME_LINE1, forms[0]->field(1)->server_type());
ASSERT_EQ(1U, forms[0]->field(1)->server_predictions().size());
EXPECT_EQ(ADDRESS_HOME_LINE1,
@@ -6250,11 +6262,10 @@ TEST_F(FormStructureTestImpl, RationalizePhoneNumber_RunsOncePerSection) {
test::GetEncodedSignatures(forms),
nullptr, nullptr);
- EXPECT_FALSE(
- test_api(&form_structure).phone_rationalized("fullName_0_11-default"));
- form_structure.RationalizePhoneNumbersInSection("fullName_0_11-default");
- EXPECT_TRUE(
- test_api(&form_structure).phone_rationalized("fullName_0_11-default"));
+ Section s = forms[0]->field(0)->section;
+ EXPECT_FALSE(test_api(&form_structure).phone_rationalized(s));
+ form_structure.RationalizePhoneNumbersInSection(s);
+ EXPECT_TRUE(test_api(&form_structure).phone_rationalized(s));
ASSERT_EQ(1U, forms.size());
ASSERT_EQ(4U, forms[0]->field_count());
EXPECT_EQ(NAME_FULL, forms[0]->field(0)->server_type());
@@ -6578,39 +6589,41 @@ TEST_F(FormStructureTestImpl,
field.form_control_type = "text";
field.max_length = 10000;
+ // Billing.
+ field.section.SetPrefixFromAutocomplete(
+ {.section = "Billing", .mode = HtmlFieldMode::HTML_MODE_NONE});
+
field.label = u"Full Name";
field.name = u"fullName";
- field.section = "Billing";
field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.label = u"Address";
field.name = u"address";
- field.section = "Billing";
field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.label = u"City";
field.name = u"city";
- field.section = "Billing";
field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
+ // Shipping.
+ field.section.SetPrefixFromAutocomplete(
+ {.section = "Shipping", .mode = HtmlFieldMode::HTML_MODE_NONE});
+
field.label = u"Full Name";
field.name = u"fullName";
- field.section = "Shipping";
field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.label = u"Address";
field.name = u"address";
- field.section = "Shipping";
field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.label = u"City";
field.name = u"city";
- field.section = "Shipping";
field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
@@ -6664,96 +6677,87 @@ TEST_F(
field.form_control_type = "text";
field.max_length = 10000;
- // Shipping
+ // Shipping.
+ field.section.SetPrefixFromAutocomplete(
+ {.section = "Shipping", .mode = HtmlFieldMode::HTML_MODE_NONE});
field.label = u"Full Name";
field.name = u"fullName";
- field.section = "Shipping";
field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.label = u"Address";
field.name = u"address";
- field.section = "Shipping";
field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.label = u"Address";
field.name = u"address";
- field.section = "Shipping";
field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.label = u"City";
field.name = u"city";
- field.section = "Shipping";
field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
- // Billing
+ // Billing.
+ field.section.SetPrefixFromAutocomplete(
+ {.section = "Billing", .mode = HtmlFieldMode::HTML_MODE_NONE});
field.label = u"Full Name";
field.name = u"fullName";
- field.section = "Billing";
field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.label = u"Address";
field.name = u"address";
- field.section = "Billing";
field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.label = u"Address";
field.name = u"address";
- field.section = "Billing";
field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.label = u"Address";
field.name = u"address";
- field.section = "Billing";
field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.label = u"City";
field.name = u"city";
- field.section = "Billing";
field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
- // Work address (not realistic)
+ // Work address (not realistic).
+ field.section.SetPrefixFromAutocomplete(
+ {.section = "Work", .mode = HtmlFieldMode::HTML_MODE_NONE});
field.label = u"Full Name";
field.name = u"fullName";
- field.section = "Work";
field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.label = u"Address";
field.name = u"address";
- field.section = "Work";
field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.label = u"Address";
field.name = u"address";
- field.section = "Work";
field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.label = u"Address";
field.name = u"address";
- field.section = "Work";
field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.label = u"Address";
field.name = u"address";
- field.section = "Work";
field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.label = u"City";
field.name = u"city";
- field.section = "Work";
field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
@@ -7126,7 +7130,9 @@ TEST_F(FormStructureTestImpl,
field.form_control_type = "text";
field.max_length = 10000;
- field.section = "shipping";
+ // Shipping.
+ field.section.SetPrefixFromAutocomplete(
+ {.section = "shipping", .mode = HtmlFieldMode::HTML_MODE_NONE});
field.label = u"Full Name";
field.name = u"fullName";
@@ -7148,7 +7154,9 @@ TEST_F(FormStructureTestImpl,
field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
- field.section = "billing";
+ // Billing.
+ field.section.SetPrefixFromAutocomplete(
+ {.section = "billing", .mode = HtmlFieldMode::HTML_MODE_NONE});
field.label = u"Country";
field.name = u"country2";
@@ -7197,7 +7205,9 @@ TEST_F(FormStructureTestImpl,
field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
- field.section = "billing-2";
+ // Billing-2.
+ field.section.SetPrefixFromAutocomplete(
+ {.section = "billing-2", .mode = HtmlFieldMode::HTML_MODE_NONE});
field.label = u"Country";
field.name = u"country";
@@ -7232,13 +7242,13 @@ TEST_F(FormStructureTestImpl,
AddFieldSuggestionToForm(form_suggestion, form.fields[8], ADDRESS_HOME_STATE);
AddFieldSuggestionToForm(form_suggestion, form.fields[9], NAME_FULL);
AddFieldSuggestionToForm(form_suggestion, form.fields[10],
- ADDRESS_BILLING_STATE);
+ ADDRESS_HOME_STATE);
// third section
AddFieldSuggestionToForm(form_suggestion, form.fields[11],
- ADDRESS_BILLING_STATE);
+ ADDRESS_HOME_STATE);
AddFieldSuggestionToForm(form_suggestion, form.fields[12], NAME_FULL);
AddFieldSuggestionToForm(form_suggestion, form.fields[13],
- ADDRESS_BILLING_STATE);
+ ADDRESS_HOME_STATE);
std::string response_string = SerializeAndEncode(response);
@@ -7385,15 +7395,15 @@ TEST_F(FormStructureTestImpl,
ADDRESS_HOME_COUNTRY);
AddFieldSuggestionToForm(form_suggestion, form.fields[7], ADDRESS_HOME_CITY);
AddFieldSuggestionToForm(form_suggestion, form.fields[8],
- ADDRESS_BILLING_COUNTRY);
+ ADDRESS_HOME_COUNTRY);
// third section
AddFieldSuggestionToForm(form_suggestion, form.fields[9], ADDRESS_HOME_CITY);
AddFieldSuggestionToForm(form_suggestion, form.fields[10],
- ADDRESS_BILLING_COUNTRY);
+ ADDRESS_HOME_COUNTRY);
AddFieldSuggestionToForm(form_suggestion, form.fields[11],
ADDRESS_HOME_COUNTRY);
AddFieldSuggestionToForm(form_suggestion, form.fields[12],
- ADDRESS_BILLING_COUNTRY);
+ ADDRESS_HOME_COUNTRY);
AddFieldSuggestionToForm(form_suggestion, form.fields[13],
ADDRESS_HOME_COUNTRY);
@@ -7434,7 +7444,8 @@ TEST_F(FormStructureTestImpl,
field.form_control_type = "text";
field.max_length = 10000;
- field.section = "billing";
+ field.section.SetPrefixFromAutocomplete(
+ {.section = "billing", .mode = HtmlFieldMode::HTML_MODE_NONE});
field.label = u"Country";
field.name = u"country";
@@ -7473,8 +7484,7 @@ TEST_F(FormStructureTestImpl,
AddFieldSuggestionToForm(form_suggestion, form.fields[1], ADDRESS_HOME_STATE);
AddFieldSuggestionToForm(form_suggestion, form.fields[2], ADDRESS_HOME_STATE);
AddFieldSuggestionToForm(form_suggestion, form.fields[3], NAME_FULL);
- AddFieldSuggestionToForm(form_suggestion, form.fields[4],
- ADDRESS_BILLING_STATE);
+ AddFieldSuggestionToForm(form_suggestion, form.fields[4], ADDRESS_HOME_STATE);
std::string response_string = SerializeAndEncode(response);
@@ -7504,7 +7514,8 @@ TEST_F(FormStructureTestImpl,
field.form_control_type = "text";
field.max_length = 10000;
- field.section = "billing";
+ field.section.SetPrefixFromAutocomplete(
+ {.section = "billing", .mode = HtmlFieldMode::HTML_MODE_NONE});
field.label = u"Country";
field.name = u"country";
@@ -8165,13 +8176,18 @@ TEST_F(FormStructureTestImpl, NoAutocompleteSectionNames) {
// Assert the correct number of fields.
ASSERT_EQ(6U, form_structure.field_count());
-
- EXPECT_EQ("fullName_0_11-default", form_structure.field(0)->section);
- EXPECT_EQ("fullName_0_11-default", form_structure.field(1)->section);
- EXPECT_EQ("fullName_0_11-default", form_structure.field(2)->section);
- EXPECT_EQ("fullName_0_14-default", form_structure.field(3)->section);
- EXPECT_EQ("fullName_0_14-default", form_structure.field(4)->section);
- EXPECT_EQ("fullName_0_14-default", form_structure.field(5)->section);
+ EXPECT_EQ("fullName_0_11-default",
+ form_structure.field(0)->section.ToString());
+ EXPECT_EQ("fullName_0_11-default",
+ form_structure.field(1)->section.ToString());
+ EXPECT_EQ("fullName_0_11-default",
+ form_structure.field(2)->section.ToString());
+ EXPECT_EQ("fullName_0_14-default",
+ form_structure.field(3)->section.ToString());
+ EXPECT_EQ("fullName_0_14-default",
+ form_structure.field(4)->section.ToString());
+ EXPECT_EQ("fullName_0_14-default",
+ form_structure.field(5)->section.ToString());
}
// Tests that the immediate recurrence of the |PHONE_HOME_NUMBER| type does not
@@ -8229,8 +8245,8 @@ TEST_F(FormStructureTestImpl, NoSplitByRecurringPhoneFieldType) {
form_structure.set_overall_field_type_for_testing(1, PHONE_HOME_NUMBER);
form_structure.set_overall_field_type_for_testing(2, PHONE_HOME_NUMBER);
form_structure.set_overall_field_type_for_testing(3, NAME_FULL);
- form_structure.set_overall_field_type_for_testing(4, PHONE_BILLING_NUMBER);
- form_structure.set_overall_field_type_for_testing(5, PHONE_BILLING_NUMBER);
+ form_structure.set_overall_field_type_for_testing(4, PHONE_HOME_NUMBER);
+ form_structure.set_overall_field_type_for_testing(5, PHONE_HOME_NUMBER);
form_structure.set_overall_field_type_for_testing(6, ADDRESS_HOME_COUNTRY);
std::vector<FormStructure*> forms;
@@ -8241,13 +8257,20 @@ TEST_F(FormStructureTestImpl, NoSplitByRecurringPhoneFieldType) {
// Assert the correct number of fields.
ASSERT_EQ(7U, form_structure.field_count());
- EXPECT_EQ("blue-billing-default", form_structure.field(0)->section);
- EXPECT_EQ("blue-billing-default", form_structure.field(1)->section);
- EXPECT_EQ("blue-billing-default", form_structure.field(2)->section);
- EXPECT_EQ("blue-billing-default", form_structure.field(3)->section);
- EXPECT_EQ("blue-billing-default", form_structure.field(4)->section);
- EXPECT_EQ("blue-billing-default", form_structure.field(5)->section);
- EXPECT_EQ("blue-billing-default", form_structure.field(6)->section);
+ EXPECT_EQ("blue-billing-default",
+ form_structure.field(0)->section.ToString());
+ EXPECT_EQ("blue-billing-default",
+ form_structure.field(1)->section.ToString());
+ EXPECT_EQ("blue-billing-default",
+ form_structure.field(2)->section.ToString());
+ EXPECT_EQ("blue-billing-default",
+ form_structure.field(3)->section.ToString());
+ EXPECT_EQ("blue-billing-default",
+ form_structure.field(4)->section.ToString());
+ EXPECT_EQ("blue-billing-default",
+ form_structure.field(5)->section.ToString());
+ EXPECT_EQ("blue-billing-default",
+ form_structure.field(6)->section.ToString());
}
// Tests if a new logical form is started with the second appearance of a field
@@ -8300,10 +8323,14 @@ TEST_F(FormStructureTestImpl, SplitByRecurringFieldType) {
// Assert the correct number of fields.
ASSERT_EQ(4U, form_structure.field_count());
- EXPECT_EQ("blue-shipping-default", form_structure.field(0)->section);
- EXPECT_EQ("blue-shipping-default", form_structure.field(1)->section);
- EXPECT_EQ("blue-shipping-default", form_structure.field(2)->section);
- EXPECT_EQ("country_0_14-default", form_structure.field(3)->section);
+ EXPECT_EQ("blue-shipping-default",
+ form_structure.field(0)->section.ToString());
+ EXPECT_EQ("blue-shipping-default",
+ form_structure.field(1)->section.ToString());
+ EXPECT_EQ("blue-shipping-default",
+ form_structure.field(2)->section.ToString());
+ EXPECT_EQ("country_0_14-default",
+ form_structure.field(3)->section.ToString());
}
// Tests if a new logical form is started with the second appearance of a field
@@ -8359,10 +8386,14 @@ TEST_F(FormStructureTestImpl,
// Assert the correct number of fields.
ASSERT_EQ(4U, form_structure.field_count());
- EXPECT_EQ("blue-shipping-default", form_structure.field(0)->section);
- EXPECT_EQ("blue-billing-default", form_structure.field(1)->section);
- EXPECT_EQ("blue-billing-default", form_structure.field(2)->section);
- EXPECT_EQ("country_0_14-default", form_structure.field(3)->section);
+ EXPECT_EQ("blue-shipping-default",
+ form_structure.field(0)->section.ToString());
+ EXPECT_EQ("blue-billing-default",
+ form_structure.field(1)->section.ToString());
+ EXPECT_EQ("blue-billing-default",
+ form_structure.field(2)->section.ToString());
+ EXPECT_EQ("country_0_14-default",
+ form_structure.field(3)->section.ToString());
}
// Tests if a new logical form is started with the second appearance of a field
@@ -8416,10 +8447,14 @@ TEST_F(FormStructureTestImpl, SplitByNewAutocompleteSectionName) {
// Assert the correct number of fields.
ASSERT_EQ(4U, form_structure.field_count());
- EXPECT_EQ("blue-shipping-default", form_structure.field(0)->section);
- EXPECT_EQ("blue-shipping-default", form_structure.field(1)->section);
- EXPECT_EQ("blue-billing-default", form_structure.field(2)->section);
- EXPECT_EQ("blue-billing-default", form_structure.field(3)->section);
+ EXPECT_EQ("blue-shipping-default",
+ form_structure.field(0)->section.ToString());
+ EXPECT_EQ("blue-shipping-default",
+ form_structure.field(1)->section.ToString());
+ EXPECT_EQ("blue-billing-default",
+ form_structure.field(2)->section.ToString());
+ EXPECT_EQ("blue-billing-default",
+ form_structure.field(3)->section.ToString());
}
// Tests if a new logical form is started with the second appearance of a field
@@ -8474,10 +8509,14 @@ TEST_F(
// Assert the correct number of fields.
ASSERT_EQ(4U, form_structure.field_count());
- EXPECT_EQ("blue-shipping-default", form_structure.field(0)->section);
- EXPECT_EQ("blue-shipping-default", form_structure.field(1)->section);
- EXPECT_EQ("blue-billing-default", form_structure.field(2)->section);
- EXPECT_EQ("blue-billing-default", form_structure.field(3)->section);
+ EXPECT_EQ("blue-shipping-default",
+ form_structure.field(0)->section.ToString());
+ EXPECT_EQ("blue-shipping-default",
+ form_structure.field(1)->section.ToString());
+ EXPECT_EQ("blue-billing-default",
+ form_structure.field(2)->section.ToString());
+ EXPECT_EQ("blue-billing-default",
+ form_structure.field(3)->section.ToString());
}
// Tests if all the fields in the form belong to the same section when the
@@ -8516,8 +8555,10 @@ TEST_F(FormStructureTestImpl, FromEmptyAutocompleteSectionToDefinedOne) {
// Assert the correct number of fields.
ASSERT_EQ(2U, form_structure.field_count());
- EXPECT_EQ("blue-shipping-default", form_structure.field(0)->section);
- EXPECT_EQ("blue-shipping-default", form_structure.field(1)->section);
+ EXPECT_EQ("blue-shipping-default",
+ form_structure.field(0)->section.ToString());
+ EXPECT_EQ("blue-shipping-default",
+ form_structure.field(1)->section.ToString());
}
// Tests if all the fields in the form belong to the same section when one of
@@ -8565,50 +8606,9 @@ TEST_F(FormStructureTestImpl,
// Assert the correct number of fields.
ASSERT_EQ(3U, form_structure.field_count());
- EXPECT_EQ("-shipping-default", form_structure.field(0)->section);
- EXPECT_EQ("-shipping-default", form_structure.field(1)->section);
- EXPECT_EQ("-shipping-default", form_structure.field(2)->section);
-}
-
-// Tests if the autocomplete section name other than 'shipping' and 'billing'
-// are ignored.
-TEST_F(FormStructureTestImpl, IgnoreAribtraryAutocompleteSectionName) {
- base::test::ScopedFeatureList enabled;
- enabled.InitAndEnableFeature(features::kAutofillUseNewSectioningMethod);
-
- FormData form;
- form.url = GURL("http://foo.com");
- FormFieldData field;
- field.form_control_type = "text";
- field.max_length = 10000;
-
- field.label = u"Full Name";
- field.name = u"fullName";
- field.autocomplete_attribute = "section-red ship name";
- field.unique_renderer_id = MakeFieldRendererId();
- form.fields.push_back(field);
-
- field.label = u"Country";
- field.name = u"country";
- field.autocomplete_attribute = "section-blue shipping country";
- field.unique_renderer_id = MakeFieldRendererId();
- form.fields.push_back(field);
-
- FormStructure form_structure(form);
-
- form_structure.set_overall_field_type_for_testing(0, NAME_FULL);
- form_structure.set_overall_field_type_for_testing(1, ADDRESS_HOME_COUNTRY);
-
- std::vector<FormStructure*> forms;
- forms.push_back(&form_structure);
-
- form_structure.identify_sections_for_testing();
-
- // Assert the correct number of fields.
- ASSERT_EQ(2U, form_structure.field_count());
-
- EXPECT_EQ("blue-shipping-default", form_structure.field(0)->section);
- EXPECT_EQ("blue-shipping-default", form_structure.field(1)->section);
+ EXPECT_EQ("-shipping-default", form_structure.field(0)->section.ToString());
+ EXPECT_EQ("-shipping-default", form_structure.field(1)->section.ToString());
+ EXPECT_EQ("-shipping-default", form_structure.field(2)->section.ToString());
}
TEST_F(FormStructureTestImpl, FindFieldsEligibleForManualFilling) {
diff --git a/chromium/components/autofill/core/browser/geo/address_i18n.cc b/chromium/components/autofill/core/browser/geo/address_i18n.cc
index fb38157dcfb..1eeef91ed77 100644
--- a/chromium/components/autofill/core/browser/geo/address_i18n.cc
+++ b/chromium/components/autofill/core/browser/geo/address_i18n.cc
@@ -94,39 +94,30 @@ ServerFieldType TypeForField(AddressField address_field) {
bool FieldForType(ServerFieldType server_type, AddressField* field) {
switch (server_type) {
- case ADDRESS_BILLING_COUNTRY:
case ADDRESS_HOME_COUNTRY:
if (field)
*field = ::i18n::addressinput::COUNTRY;
return true;
- case ADDRESS_BILLING_STATE:
case ADDRESS_HOME_STATE:
if (field)
*field = ::i18n::addressinput::ADMIN_AREA;
return true;
- case ADDRESS_BILLING_CITY:
case ADDRESS_HOME_CITY:
if (field)
*field = ::i18n::addressinput::LOCALITY;
return true;
- case ADDRESS_BILLING_DEPENDENT_LOCALITY:
case ADDRESS_HOME_DEPENDENT_LOCALITY:
if (field)
*field = ::i18n::addressinput::DEPENDENT_LOCALITY;
return true;
- case ADDRESS_BILLING_SORTING_CODE:
case ADDRESS_HOME_SORTING_CODE:
if (field)
*field = ::i18n::addressinput::SORTING_CODE;
return true;
- case ADDRESS_BILLING_ZIP:
case ADDRESS_HOME_ZIP:
if (field)
*field = ::i18n::addressinput::POSTAL_CODE;
return true;
- case ADDRESS_BILLING_STREET_ADDRESS:
- case ADDRESS_BILLING_LINE1:
- case ADDRESS_BILLING_LINE2:
case ADDRESS_HOME_STREET_ADDRESS:
case ADDRESS_HOME_LINE1:
case ADDRESS_HOME_LINE2:
@@ -137,7 +128,6 @@ bool FieldForType(ServerFieldType server_type, AddressField* field) {
if (field)
*field = ::i18n::addressinput::ORGANIZATION;
return true;
- case NAME_BILLING_FULL:
case NAME_FULL:
if (field)
*field = ::i18n::addressinput::RECIPIENT;
diff --git a/chromium/components/autofill/core/browser/geo/address_i18n_unittest.cc b/chromium/components/autofill/core/browser/geo/address_i18n_unittest.cc
index bd9f81602a7..7268c8bdcc4 100644
--- a/chromium/components/autofill/core/browser/geo/address_i18n_unittest.cc
+++ b/chromium/components/autofill/core/browser/geo/address_i18n_unittest.cc
@@ -90,10 +90,6 @@ INSTANTIATE_TEST_SUITE_P(AddressI18nTest,
FieldTypeUnidirectionalConversionsTest,
testing::Values(
FieldTypeUnidirectionalConversionsTestCase{
- ADDRESS_BILLING_LINE1, STREET_ADDRESS},
- FieldTypeUnidirectionalConversionsTestCase{
- ADDRESS_BILLING_LINE2, STREET_ADDRESS},
- FieldTypeUnidirectionalConversionsTestCase{
ADDRESS_HOME_LINE1, STREET_ADDRESS},
FieldTypeUnidirectionalConversionsTestCase{
ADDRESS_HOME_LINE2, STREET_ADDRESS}));
diff --git a/chromium/components/autofill/core/browser/geo/autofill_country.cc b/chromium/components/autofill/core/browser/geo/autofill_country.cc
index 5f0cdae2611..ad65c3c325a 100644
--- a/chromium/components/autofill/core/browser/geo/autofill_country.cc
+++ b/chromium/components/autofill/core/browser/geo/autofill_country.cc
@@ -32,7 +32,7 @@ const size_t kLocaleCapacity =
} // namespace
AutofillCountry::AutofillCountry(const std::string& country_code,
- const std::string& locale) {
+ const absl::optional<std::string>& locale) {
CountryDataMap* country_data_map = CountryDataMap::GetInstance();
// If the country code is an alias (e.g. "GB" for "UK") expand the country
@@ -46,7 +46,8 @@ AutofillCountry::AutofillCountry(const std::string& country_code,
country_data_map->GetRequiredFieldsForAddressImport(country_code_);
// Translate the country name by the supplied local.
- name_ = l10n_util::GetDisplayNameForCountry(country_code_, locale);
+ if (locale)
+ name_ = l10n_util::GetDisplayNameForCountry(country_code_, *locale);
}
AutofillCountry::~AutofillCountry() {}
diff --git a/chromium/components/autofill/core/browser/geo/autofill_country.h b/chromium/components/autofill/core/browser/geo/autofill_country.h
index 3a46edff14c..5983099f164 100644
--- a/chromium/components/autofill/core/browser/geo/autofill_country.h
+++ b/chromium/components/autofill/core/browser/geo/autofill_country.h
@@ -10,6 +10,7 @@
#include "base/containers/span.h"
#include "base/strings/string_piece.h"
#include "components/autofill/core/browser/geo/country_data.h"
+#include "third_party/abseil-cpp/absl/types/optional.h"
#include "third_party/libaddressinput/src/cpp/include/libaddressinput/address_field.h"
namespace autofill {
@@ -24,8 +25,9 @@ class AutofillCountry {
// `country_code`.
// `locale` is used translate the `name()` appropriately and can be ignored
// if the name is not queried.
- explicit AutofillCountry(const std::string& country_code,
- const std::string& locale = "en");
+ explicit AutofillCountry(
+ const std::string& country_code,
+ const absl::optional<std::string>& locale = absl::nullopt);
AutofillCountry(const AutofillCountry&) = delete;
AutofillCountry& operator=(const AutofillCountry&) = delete;
@@ -63,7 +65,12 @@ class AutofillCountry {
// mapping from the locale is available.
static const std::string CountryCodeForLocale(const std::string& locale);
+ // The `country_code` provided to the constructor, with aliases like "GB"
+ // replaced by their canonical version ("UK", in this case).
const std::string& country_code() const { return country_code_; }
+
+ // Returns the name of the country translated into the `locale` provided to
+ // the constructor. If no `locale` was provided, an empty string is returned.
const std::u16string& name() const { return name_; }
// City is expected in a complete address for this country.
diff --git a/chromium/components/autofill/core/browser/geo/autofill_country_unittest.cc b/chromium/components/autofill/core/browser/geo/autofill_country_unittest.cc
index b9ce7000597..8583dc8e527 100644
--- a/chromium/components/autofill/core/browser/geo/autofill_country_unittest.cc
+++ b/chromium/components/autofill/core/browser/geo/autofill_country_unittest.cc
@@ -48,6 +48,11 @@ TEST(AutofillCountryTest, AutofillCountry) {
// Unrecognizable country codes remain that way.
AutofillCountry unknown("Unknown", "en_US");
EXPECT_EQ("Unknown", unknown.country_code());
+
+ // If no locale is provided, no `name()` is returned.
+ AutofillCountry empty_locale("AT");
+ EXPECT_EQ("AT", empty_locale.country_code());
+ EXPECT_TRUE(empty_locale.name().empty());
}
// Test locale to country code mapping.
diff --git a/chromium/components/autofill/core/browser/geo/phone_number_i18n.cc b/chromium/components/autofill/core/browser/geo/phone_number_i18n.cc
index 8368f0d69ff..9fe04651044 100644
--- a/chromium/components/autofill/core/browser/geo/phone_number_i18n.cc
+++ b/chromium/components/autofill/core/browser/geo/phone_number_i18n.cc
@@ -386,9 +386,12 @@ PhoneObject::PhoneObject(const std::u16string& number,
i18n_number_->has_country_code()) {
country_code_ = base::NumberToString16(i18n_number_->country_code());
}
+ // Autofill doesn't support filling extensions, so we should not store them.
+ i18n_number_->clear_extension();
} else {
// Parsing failed. Store passed phone "as is" into |whole_number_|.
whole_number_ = number;
+ // We have no way of removing any extensions.
}
}
diff --git a/chromium/components/autofill/core/browser/geo/phone_number_i18n_unittest.cc b/chromium/components/autofill/core/browser/geo/phone_number_i18n_unittest.cc
index 88de443bf02..4a68eee2e0d 100644
--- a/chromium/components/autofill/core/browser/geo/phone_number_i18n_unittest.cc
+++ b/chromium/components/autofill/core/browser/geo/phone_number_i18n_unittest.cc
@@ -66,7 +66,7 @@ class ParseNumberTest : public testing::TestWithParam<ParseNumberTestCase> {};
TEST_P(ParseNumberTest, ParsePhoneNumber) {
auto test_case = GetParam();
- SCOPED_TRACE(test_case.input.c_str());
+ SCOPED_TRACE(base::UTF16ToUTF8(test_case.input));
std::u16string country_code, city_code, number;
std::string deduced_region;
@@ -99,7 +99,7 @@ INSTANTIATE_TEST_SUITE_P(
// unknown("ZZ") deduced region.
ParseNumberTestCase{true, u"7134567", "US", u"7134567", u"", u"", "ZZ"},
// Valid Canadian toll-free number.
- ParseNumberTestCase{true, u"3101234", "CA", u"3101234", u"", u"", "ZZ"},
+ ParseNumberTestCase{true, u"3101234", "CA", u"1234", u"310", u"", "CA"},
// Test for string with greater than 7 digits but less than 10 digits.
// Should fail parsing in US.
ParseNumberTestCase{false, u"123456789", "US"},
diff --git a/chromium/components/autofill/core/browser/iban_manager.cc b/chromium/components/autofill/core/browser/iban_manager.cc
new file mode 100644
index 00000000000..ef691ec2d8b
--- /dev/null
+++ b/chromium/components/autofill/core/browser/iban_manager.cc
@@ -0,0 +1,81 @@
+// Copyright 2022 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/iban_manager.h"
+
+#include "base/containers/contains.h"
+#include "components/autofill/core/browser/autofill_suggestion_generator.h"
+#include "components/autofill/core/browser/browser_autofill_manager.h"
+#include "components/autofill/core/browser/personal_data_manager.h"
+#include "components/autofill/core/browser/suggestions_context.h"
+#include "components/autofill/core/common/autofill_clock.h"
+
+namespace autofill {
+
+IBANManager::IBANManager(PersonalDataManager* personal_data_manager,
+ bool is_off_the_record)
+ : personal_data_manager_(personal_data_manager),
+ is_off_the_record_(is_off_the_record) {}
+
+IBANManager::~IBANManager() = default;
+
+bool IBANManager::OnGetSingleFieldSuggestions(
+ int query_id,
+ bool is_autocomplete_enabled,
+ bool autoselect_first_suggestion,
+ const FormFieldData& field,
+ base::WeakPtr<SuggestionsHandler> handler,
+ const SuggestionsContext& context) {
+ if (!is_off_the_record_ && personal_data_manager_) {
+ std::vector<IBAN*> ibans = personal_data_manager_->GetIBANs();
+ if (!ibans.empty()) {
+ // Rank the IBANs by ranking score (see AutoFillDataModel for details).
+ base::Time comparison_time = AutofillClock::Now();
+ base::ranges::sort(
+ ibans, [comparison_time](const IBAN* iban0, const IBAN* iban1) {
+ return iban0->HasGreaterRankingThan(iban1, comparison_time);
+ });
+ SendIBANSuggestions(ibans,
+ QueryHandler(query_id, autoselect_first_suggestion,
+ field.value, handler));
+ return true;
+ }
+ }
+ return false;
+}
+
+base::WeakPtr<IBANManager> IBANManager::GetWeakPtr() {
+ return weak_ptr_factory_.GetWeakPtr();
+}
+
+void IBANManager::SendIBANSuggestions(const std::vector<IBAN*>& ibans,
+ const QueryHandler& query_handler) {
+ if (!query_handler.handler_) {
+ // Either the handler has been destroyed, or it is invalid.
+ return;
+ }
+
+ // If the input box content equals any of the available IBANs, then
+ // assume the IBAN has been filled, and don't show any suggestions.
+ // Note: this |prefix_| is actually the value of form and we are comparing
+ // the value with the full IBAN value. However, once we land
+ // MASKED_SERVER_IBANs and Chrome doesn't know the whole value, we'll have
+ // check 'prefix'(E.g., the first ~5 characters).
+ if (base::Contains(ibans, query_handler.prefix_, &IBAN::value)) {
+ // Return empty suggestions to query handler. This will result in no
+ // suggestions being displayed.
+ query_handler.handler_->OnSuggestionsReturned(
+ query_handler.client_query_id_,
+ query_handler.autoselect_first_suggestion_, {});
+ return;
+ }
+
+ // Return suggestions to query handler.
+ query_handler.handler_->OnSuggestionsReturned(
+ query_handler.client_query_id_,
+ query_handler.autoselect_first_suggestion_,
+ AutofillSuggestionGenerator::GetSuggestionsForIBANs(ibans));
+}
+
+} // namespace autofill
diff --git a/chromium/components/autofill/core/browser/iban_manager.h b/chromium/components/autofill/core/browser/iban_manager.h
new file mode 100644
index 00000000000..dbbc61b1a76
--- /dev/null
+++ b/chromium/components/autofill/core/browser/iban_manager.h
@@ -0,0 +1,81 @@
+// Copyright 2022 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_IBAN_MANAGER_H_
+#define COMPONENTS_AUTOFILL_CORE_BROWSER_IBAN_MANAGER_H_
+
+#include "base/gtest_prod_util.h"
+#include "components/autofill/core/browser/autofill_subject.h"
+#include "components/autofill/core/browser/data_model/iban.h"
+#include "components/autofill/core/browser/personal_data_manager.h"
+#include "components/autofill/core/browser/single_field_form_filler.h"
+#include "components/keyed_service/core/keyed_service.h"
+#include "components/webdata/common/web_data_service_consumer.h"
+
+namespace autofill {
+
+class PersonalDataManager;
+struct SuggestionsContext;
+
+// Per-profile IBAN Manager. This class handles IBAN-related functionality
+// such as retrieving IBAN data, managing IBAN suggestions, filling IBAN fields,
+// and handling form submission data when there is an IBAN field present.
+class IBANManager : public SingleFieldFormFiller,
+ public KeyedService,
+ public AutofillSubject {
+ public:
+ // Initializes the instance with the given parameters. |personal_data_manager|
+ // is a profile-scope data manager used to retrieve IBAN data from the
+ // local autofill table. |is_off_the_record| indicates whether the user is
+ // currently operating in an off-the-record context (i.e. incognito).
+ explicit IBANManager(PersonalDataManager* personal_data_manager,
+ bool is_off_the_record);
+
+ IBANManager(const IBANManager&) = delete;
+ IBANManager& operator=(const IBANManager&) = delete;
+
+ ~IBANManager() override;
+
+ // SingleFieldFormFiller overrides:
+ [[nodiscard]] bool OnGetSingleFieldSuggestions(
+ int query_id,
+ bool is_autocomplete_enabled,
+ bool autoselect_first_suggestion,
+ const FormFieldData& field,
+ base::WeakPtr<SuggestionsHandler> handler,
+ const SuggestionsContext& context) override;
+ void OnWillSubmitFormWithFields(const std::vector<FormFieldData>& fields,
+ bool is_autocomplete_enabled) override {}
+ void CancelPendingQueries(const SuggestionsHandler* handler) override {}
+ void OnRemoveCurrentSingleFieldSuggestion(const std::u16string& field_name,
+ const std::u16string& value,
+ int frontend_id) override {}
+ void OnSingleFieldSuggestionSelected(const std::u16string& value,
+ int frontend_id) override {}
+
+ base::WeakPtr<IBANManager> GetWeakPtr();
+
+#if defined(UNIT_TEST)
+ // Assign types to the fields for the testing purposes.
+ void SetOffTheRecordForTesting(bool is_off_the_record) {
+ is_off_the_record_ = is_off_the_record;
+ }
+#endif
+
+ private:
+ // Sends suggestions for |ibans| to the |query_handler|'s handler for display
+ // in the associated Autofill popup.
+ void SendIBANSuggestions(const std::vector<IBAN*>& ibans,
+ const QueryHandler& query_handler);
+
+ PersonalDataManager* personal_data_manager_ = nullptr;
+
+ bool is_off_the_record_ = false;
+
+ base::WeakPtrFactory<IBANManager> weak_ptr_factory_{this};
+};
+
+} // namespace autofill
+
+#endif // COMPONENTS_AUTOFILL_CORE_BROWSER_IBAN_MANAGER_H_
diff --git a/chromium/components/autofill/core/browser/iban_manager_unittest.cc b/chromium/components/autofill/core/browser/iban_manager_unittest.cc
new file mode 100644
index 00000000000..adeda73149a
--- /dev/null
+++ b/chromium/components/autofill/core/browser/iban_manager_unittest.cc
@@ -0,0 +1,155 @@
+// Copyright 2022 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/iban_manager.h"
+
+#include "base/guid.h"
+#include "components/autofill/core/browser/suggestions_context.h"
+#include "components/autofill/core/browser/test_personal_data_manager.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+using testing::_;
+using testing::Field;
+using testing::Truly;
+using testing::UnorderedElementsAre;
+
+namespace autofill {
+
+namespace {
+
+class MockSuggestionsHandler : public IBANManager::SuggestionsHandler {
+ public:
+ MockSuggestionsHandler() = default;
+ MockSuggestionsHandler(const MockSuggestionsHandler&) = delete;
+ MockSuggestionsHandler& operator=(const MockSuggestionsHandler&) = delete;
+ ~MockSuggestionsHandler() override = default;
+
+ MOCK_METHOD(void,
+ OnSuggestionsReturned,
+ (int query_id,
+ bool autoselect_first_suggestion,
+ const std::vector<Suggestion>& suggestions),
+ (override));
+
+ base::WeakPtr<MockSuggestionsHandler> GetWeakPtr() {
+ return weak_ptr_factory_.GetWeakPtr();
+ }
+
+ private:
+ base::WeakPtrFactory<MockSuggestionsHandler> weak_ptr_factory_{this};
+};
+
+} // namespace
+
+class IBANManagerTest : public testing::Test {
+ protected:
+ IBANManagerTest()
+ : iban_manager_(&personal_data_manager_, /*is_off_the_record=*/false) {}
+
+ // Sets up the TestPersonalDataManager with an IBAN.
+ IBAN SetUpIBAN(base::StringPiece16 value, base::StringPiece16 nickname) {
+ IBAN iban;
+ std::string guid = base::GenerateGUID();
+ iban.set_guid(guid);
+ iban.set_value(std::u16string(value));
+ iban.set_nickname(std::u16string(nickname));
+ personal_data_manager_.AddIBANForTest(std::make_unique<IBAN>(iban));
+ return iban;
+ }
+
+ // Sets up the TestPersonalDataManager with an IBAN and corresponding
+ // suggestion.
+ Suggestion SetUpIBANAndSuggestion(base::StringPiece16 value,
+ base::StringPiece16 nickname) {
+ IBAN iban = SetUpIBAN(value, nickname);
+ Suggestion iban_suggestion(iban.GetIdentifierStringForAutofillDisplay());
+ return iban_suggestion;
+ }
+
+ MockSuggestionsHandler suggestions_handler_;
+ TestPersonalDataManager personal_data_manager_;
+ IBANManager iban_manager_;
+};
+
+TEST_F(IBANManagerTest, ShowsIBANSuggestions) {
+ int test_query_id = 2;
+ Suggestion iban_suggestion_0 =
+ SetUpIBANAndSuggestion(u"IE12 BOFI 9000 0112 3456 78", u"Nickname 0");
+ Suggestion iban_suggestion_1 =
+ SetUpIBANAndSuggestion(u"CH56 0483 5012 3456 7800 9", u"Nickname 1");
+
+ SuggestionsContext context;
+ FormFieldData test_field;
+
+ // Setting up mock to verify that the handler is returned a list of
+ // iban-based suggestions and the iban details line.
+ EXPECT_CALL(
+ suggestions_handler_,
+ OnSuggestionsReturned(
+ test_query_id, /*autoselect_first_suggestion=*/false,
+ UnorderedElementsAre(
+ Field(&Suggestion::main_text, iban_suggestion_0.main_text),
+ Field(&Suggestion::main_text, iban_suggestion_1.main_text))))
+ .Times(1);
+
+ // Simulate request for suggestions.
+ // Because all criteria are met to trigger returning to the handler,
+ // the handler should be triggered and this should return true.
+ EXPECT_TRUE(iban_manager_.OnGetSingleFieldSuggestions(
+ test_query_id, /*is_autocomplete_enabled=*/false,
+ /*autoselect_first_suggestion=*/false, test_field,
+ suggestions_handler_.GetWeakPtr(),
+ /*context=*/context));
+}
+
+TEST_F(IBANManagerTest, ShowsIBANSuggestions_OnlyPrefixMatch) {
+ int test_query_id = 2;
+ base::StringPiece16 value_0 = u"IE12 BOFI 9000 0112 3456 78";
+ Suggestion iban_suggestion_0 = SetUpIBANAndSuggestion(value_0, u"Nickname 0");
+ Suggestion iban_suggestion_1 =
+ SetUpIBANAndSuggestion(u"CH56 0483 5012 3456 7800 9", u"Nickname 1");
+
+ SuggestionsContext context;
+ FormFieldData test_field;
+ test_field.value = std::u16string(value_0);
+
+ // Setting up mock to verify that the handler is not returned any iban-based
+ // suggestions as the field already contains an iban.
+ EXPECT_CALL(suggestions_handler_,
+ OnSuggestionsReturned(
+ _, _,
+ testing::Truly(
+ [](const std::vector<Suggestion>& returned_suggestions) {
+ return returned_suggestions.empty();
+ })));
+
+ // Simulate request for suggestions.
+ // Because all criteria are met to trigger returning to the handler,
+ // the handler should be triggered and this should return true.
+ EXPECT_TRUE(iban_manager_.OnGetSingleFieldSuggestions(
+ test_query_id, /*is_autocomplete_enabled=*/false,
+ /*autoselect_first_suggestion=*/false, test_field,
+ suggestions_handler_.GetWeakPtr(),
+ /*context=*/context));
+}
+
+TEST_F(IBANManagerTest, DoesNotShowIBANsForOffTheRecord) {
+ IBAN iban_0 = SetUpIBAN(u"IE12 BOFI 9000 0112 3456 78", u"Nickname 0");
+ iban_manager_.SetOffTheRecordForTesting(true);
+ SuggestionsContext context;
+ FormFieldData test_field;
+
+ // Setting up mock to verify that suggestions returning is not triggered if
+ // the user is off the record.
+ EXPECT_CALL(suggestions_handler_, OnSuggestionsReturned).Times(0);
+
+ // Simulate request for suggestions.
+ EXPECT_FALSE(iban_manager_.OnGetSingleFieldSuggestions(
+ /*query_id=*/2, /*is_autocomplete_enabled=*/true,
+ /*autoselect_first_suggestion=*/false, test_field,
+ suggestions_handler_.GetWeakPtr(), /*context=*/context));
+}
+
+} // namespace autofill
diff --git a/chromium/components/autofill/core/browser/logging/log_buffer_submitter.cc b/chromium/components/autofill/core/browser/logging/log_buffer_submitter.cc
index 7ef67ffe52b..a084333c0b5 100644
--- a/chromium/components/autofill/core/browser/logging/log_buffer_submitter.cc
+++ b/chromium/components/autofill/core/browser/logging/log_buffer_submitter.cc
@@ -9,28 +9,32 @@
namespace autofill {
LogBufferSubmitter::LogBufferSubmitter(LogRouter* destination, bool active)
- : destination_(destination) {
- buffer_.set_active(destination != nullptr && active);
-}
-
-LogBufferSubmitter::LogBufferSubmitter(LogBufferSubmitter&& that) noexcept {
- operator=(std::move(that));
+ : destination_(destination),
+ buffer_(LogBuffer::IsActive(destination != nullptr && active)),
+ destruct_with_logging_(buffer_.active()) {}
+
+LogBufferSubmitter::LogBufferSubmitter(LogBufferSubmitter&& that) noexcept
+ : destination_(std::move(that.destination_)),
+ buffer_(std::move(that.buffer_)),
+ destruct_with_logging_(std::move(that.destruct_with_logging_)) {
+ that.destruct_with_logging_ = false;
}
LogBufferSubmitter& LogBufferSubmitter::operator=(LogBufferSubmitter&& that) {
- destination_ = that.destination_;
+ destination_ = std::move(that.destination_);
buffer_ = std::move(that.buffer_);
+ destruct_with_logging_ = std::move(that.destruct_with_logging_);
that.destruct_with_logging_ = false;
return *this;
}
LogBufferSubmitter::~LogBufferSubmitter() {
- if (!destruct_with_logging_)
+ if (!destruct_with_logging_ || !destination_)
return;
- base::Value message = buffer_.RetrieveResult();
- if (!destination_ || message.is_none())
+ absl::optional<base::Value::Dict> message = buffer_.RetrieveResult();
+ if (!message)
return;
- destination_->ProcessLog(std::move(message));
+ destination_->ProcessLog(*message);
}
} // namespace autofill
diff --git a/chromium/components/autofill/core/browser/logging/log_buffer_submitter_unittest.cc b/chromium/components/autofill/core/browser/logging/log_buffer_submitter_unittest.cc
index 03b293d4dab..b5f99a87041 100644
--- a/chromium/components/autofill/core/browser/logging/log_buffer_submitter_unittest.cc
+++ b/chromium/components/autofill/core/browser/logging/log_buffer_submitter_unittest.cc
@@ -20,21 +20,21 @@ namespace autofill {
class MockLogReceiver : public LogReceiver {
public:
- MOCK_METHOD(void, LogEntry, (const base::Value&), (override));
+ MOCK_METHOD(void, LogEntry, (const base::Value::Dict&), (override));
};
TEST(LogBufferSubmitter, VerifySubmissionOnDestruction) {
LogBuffer buffer;
buffer << 42;
- base::Value expected = buffer.RetrieveResult();
+ absl::optional<base::Value::Dict> expected = buffer.RetrieveResult();
MockLogReceiver receiver;
LogRouter router;
- std::ignore = router.RegisterReceiver(&receiver);
+ router.RegisterReceiver(&receiver);
std::unique_ptr<LogManager> log_manager =
LogManager::Create(&router, base::NullCallback());
- EXPECT_CALL(receiver, LogEntry(testing::Eq(testing::ByRef(expected))));
+ EXPECT_CALL(receiver, LogEntry(testing::Eq(testing::ByRef(*expected))));
log_manager->Log() << 42;
log_manager.reset();
router.UnregisterReceiver(&receiver);
@@ -43,7 +43,7 @@ TEST(LogBufferSubmitter, VerifySubmissionOnDestruction) {
TEST(LogBufferSubmitter, NoEmptySubmission) {
MockLogReceiver receiver;
LogRouter router;
- std::ignore = router.RegisterReceiver(&receiver);
+ router.RegisterReceiver(&receiver);
std::unique_ptr<LogManager> log_manager =
LogManager::Create(&router, base::NullCallback());
@@ -60,7 +60,7 @@ TEST(LogBufferSubmitter, CorrectActivation) {
LogRouter router;
MockLogReceiver receiver;
- std::ignore = router.RegisterReceiver(&receiver);
+ router.RegisterReceiver(&receiver);
std::unique_ptr<LogManager> log_manager_2 =
LogManager::Create(&router, base::NullCallback());
EXPECT_TRUE(log_manager_2->Log().buffer().active());
diff --git a/chromium/components/autofill/core/browser/logging/log_manager.cc b/chromium/components/autofill/core/browser/logging/log_manager.cc
index 2cd1f7c73db..023a9391f08 100644
--- a/chromium/components/autofill/core/browser/logging/log_manager.cc
+++ b/chromium/components/autofill/core/browser/logging/log_manager.cc
@@ -25,7 +25,7 @@ class LogManagerImpl : public LogManager {
void OnLogRouterAvailabilityChanged(bool router_can_be_used) override;
void SetSuspended(bool suspended) override;
void LogTextMessage(const std::string& text) const override;
- void LogEntry(base::Value&& entry) const override;
+ void LogEntry(const base::Value::Dict& entry) const override;
bool IsLoggingActive() const override;
LogBufferSubmitter Log() override;
@@ -83,10 +83,10 @@ void LogManagerImpl::LogTextMessage(const std::string& text) const {
log_router_->ProcessLog(text);
}
-void LogManagerImpl::LogEntry(base::Value&& entry) const {
+void LogManagerImpl::LogEntry(const base::Value::Dict& entry) const {
if (!IsLoggingActive())
return;
- log_router_->ProcessLog(std::move(entry));
+ log_router_->ProcessLog(entry);
}
bool LogManagerImpl::IsLoggingActive() const {
@@ -107,9 +107,4 @@ std::unique_ptr<LogManager> LogManager::Create(
std::move(notification_callback));
}
-// static
-LogBufferSubmitter LogManager::DevNull() {
- return LogBufferSubmitter(nullptr, false);
-}
-
} // namespace autofill
diff --git a/chromium/components/autofill/core/browser/logging/log_manager.h b/chromium/components/autofill/core/browser/logging/log_manager.h
index b0656116517..bbdc3a908de 100644
--- a/chromium/components/autofill/core/browser/logging/log_manager.h
+++ b/chromium/components/autofill/core/browser/logging/log_manager.h
@@ -7,9 +7,11 @@
#include <memory>
#include <string>
+#include <type_traits>
#include "base/callback.h"
#include "components/autofill/core/browser/logging/log_buffer_submitter.h"
+#include "components/autofill/core/common/logging/log_macros.h"
namespace base {
class Value;
@@ -41,7 +43,7 @@ class LogManager {
// Forward a DOM structured log entry to the LogRouter (if registered with
// one).
- virtual void LogEntry(base::Value&& entry) const = 0;
+ virtual void LogEntry(const base::Value::Dict& entry) const = 0;
// Returns true if logs recorded via LogTextMessage will be displayed, and
// false otherwise.
@@ -56,11 +58,46 @@ class LogManager {
// This is the preferred way to submitting log entries.
virtual LogBufferSubmitter Log() = 0;
+};
+
+inline LogBuffer::IsActive IsLoggingActive(LogManager* log_manager) {
+ return LogBuffer::IsActive(log_manager && log_manager->IsLoggingActive());
+}
- // Returns a LogBufferSubmitter that ignores all input.
- static LogBufferSubmitter DevNull();
+namespace internal {
+
+// Traits for LOG_AF() macro for `LogManager*`.
+template <typename T>
+struct LoggerTraits<
+ T,
+ typename std::enable_if_t<std::is_convertible_v<decltype(std::declval<T>()),
+ const LogManager*>>> {
+ static bool active(const LogManager* log_manager) {
+ return log_manager && log_manager->IsLoggingActive();
+ }
+
+ static LogBufferSubmitter get_stream(LogManager* log_manager) {
+ return log_manager->Log();
+ }
};
+// Traits for LOG_AF() macro for `LogManager&`.
+template <typename T>
+struct LoggerTraits<
+ T,
+ typename std::enable_if_t<std::is_convertible_v<decltype(std::declval<T>()),
+ const LogManager&>>> {
+ static bool active(const LogManager& log_manager) {
+ return log_manager.IsLoggingActive();
+ }
+
+ static LogBufferSubmitter get_stream(LogManager& log_manager) {
+ return log_manager.Log();
+ }
+};
+
+} // namespace internal
+
} // namespace autofill
#endif // COMPONENTS_AUTOFILL_CORE_BROWSER_LOGGING_LOG_MANAGER_H_
diff --git a/chromium/components/autofill/core/browser/logging/log_manager_unittest.cc b/chromium/components/autofill/core/browser/logging/log_manager_unittest.cc
index a0b0b017f94..3d13dff491e 100644
--- a/chromium/components/autofill/core/browser/logging/log_manager_unittest.cc
+++ b/chromium/components/autofill/core/browser/logging/log_manager_unittest.cc
@@ -26,7 +26,7 @@ class MockLogReceiver : public autofill::LogReceiver {
MockLogReceiver(const MockLogReceiver&) = delete;
MockLogReceiver& operator=(const MockLogReceiver&) = delete;
- MOCK_METHOD(void, LogEntry, (const base::Value&), (override));
+ MOCK_METHOD(void, LogEntry, (const base::Value::Dict&), (override));
};
class MockNotifiedObject {
@@ -72,10 +72,10 @@ TEST_F(LogManagerTest, LogTextMessageAttachReceiver) {
EXPECT_FALSE(manager_->IsLoggingActive());
EXPECT_CALL(notified_object_, NotifyAboutLoggingActivity());
- EXPECT_EQ(std::vector<base::Value>(), router_.RegisterReceiver(&receiver_));
+ router_.RegisterReceiver(&receiver_);
EXPECT_TRUE(manager_->IsLoggingActive());
// After attaching the logger, text should be passed.
- base::Value log_entry = LogRouter::CreateEntryForText(kTestText);
+ base::Value::Dict log_entry = LogRouter::CreateEntryForText(kTestText);
EXPECT_CALL(receiver_, LogEntry(testing::Eq(testing::ByRef(log_entry))));
manager_->LogTextMessage(kTestText);
EXPECT_CALL(notified_object_, NotifyAboutLoggingActivity());
@@ -85,7 +85,7 @@ TEST_F(LogManagerTest, LogTextMessageAttachReceiver) {
TEST_F(LogManagerTest, LogTextMessageDetachReceiver) {
EXPECT_CALL(notified_object_, NotifyAboutLoggingActivity());
- EXPECT_EQ(std::vector<base::Value>(), router_.RegisterReceiver(&receiver_));
+ router_.RegisterReceiver(&receiver_);
EXPECT_TRUE(manager_->IsLoggingActive());
EXPECT_CALL(notified_object_, NotifyAboutLoggingActivity());
router_.UnregisterReceiver(&receiver_);
@@ -98,13 +98,13 @@ TEST_F(LogManagerTest, LogTextMessageDetachReceiver) {
TEST_F(LogManagerTest, NullCallbackWillNotCrash) {
manager_ = LogManager::Create(&router_, base::NullCallback());
- EXPECT_EQ(std::vector<base::Value>(), router_.RegisterReceiver(&receiver_));
+ router_.RegisterReceiver(&receiver_);
router_.UnregisterReceiver(&receiver_);
}
TEST_F(LogManagerTest, SetSuspended_WithActiveLogging) {
EXPECT_CALL(notified_object_, NotifyAboutLoggingActivity());
- EXPECT_EQ(std::vector<base::Value>(), router_.RegisterReceiver(&receiver_));
+ router_.RegisterReceiver(&receiver_);
EXPECT_TRUE(manager_->IsLoggingActive());
EXPECT_CALL(notified_object_, NotifyAboutLoggingActivity());
@@ -134,7 +134,7 @@ TEST_F(LogManagerTest, InterleaveSuspendAndLoggingActivation_SuspendFirst) {
manager_->SetSuspended(true);
EXPECT_FALSE(manager_->IsLoggingActive());
- EXPECT_EQ(std::vector<base::Value>(), router_.RegisterReceiver(&receiver_));
+ router_.RegisterReceiver(&receiver_);
EXPECT_FALSE(manager_->IsLoggingActive());
EXPECT_CALL(notified_object_, NotifyAboutLoggingActivity());
@@ -150,7 +150,7 @@ TEST_F(LogManagerTest, InterleaveSuspendAndLoggingActivation_ActiveFirst) {
EXPECT_FALSE(manager_->IsLoggingActive());
EXPECT_CALL(notified_object_, NotifyAboutLoggingActivity());
- EXPECT_EQ(std::vector<base::Value>(), router_.RegisterReceiver(&receiver_));
+ router_.RegisterReceiver(&receiver_);
EXPECT_TRUE(manager_->IsLoggingActive());
EXPECT_CALL(notified_object_, NotifyAboutLoggingActivity());
diff --git a/chromium/components/autofill/core/browser/logging/log_receiver.h b/chromium/components/autofill/core/browser/logging/log_receiver.h
index e984c33eaac..16d6fa91120 100644
--- a/chromium/components/autofill/core/browser/logging/log_receiver.h
+++ b/chromium/components/autofill/core/browser/logging/log_receiver.h
@@ -13,14 +13,14 @@ namespace autofill {
// logs about progress of actions like saving a password.
class LogReceiver {
public:
- LogReceiver() {}
+ LogReceiver() = default;
LogReceiver(const LogReceiver&) = delete;
LogReceiver& operator=(const LogReceiver&) = delete;
- virtual ~LogReceiver() {}
+ virtual ~LogReceiver() = default;
- virtual void LogEntry(const base::Value& entry) = 0;
+ virtual void LogEntry(const base::Value::Dict& entry) = 0;
};
} // namespace autofill
diff --git a/chromium/components/autofill/core/browser/logging/log_router.cc b/chromium/components/autofill/core/browser/logging/log_router.cc
index 52ebb49d8ce..1e4507900a0 100644
--- a/chromium/components/autofill/core/browser/logging/log_router.cc
+++ b/chromium/components/autofill/core/browser/logging/log_router.cc
@@ -18,28 +18,27 @@ LogRouter::LogRouter() = default;
LogRouter::~LogRouter() = default;
// static
-base::Value LogRouter::CreateEntryForText(const std::string& text) {
- LogBuffer buffer;
+base::Value::Dict LogRouter::CreateEntryForText(const std::string& text) {
+ LogBuffer buffer(LogBuffer::IsActive(true));
buffer << Tag{"div"};
for (const auto& line : base::SplitStringPiece(
text, "\n", base::TRIM_WHITESPACE, base::SPLIT_WANT_NONEMPTY)) {
buffer << line << Br{};
}
buffer << CTag{};
- return buffer.RetrieveResult();
+ return *buffer.RetrieveResult();
}
void LogRouter::ProcessLog(const std::string& text) {
ProcessLog(CreateEntryForText(text));
}
-void LogRouter::ProcessLog(base::Value&& node) {
+void LogRouter::ProcessLog(const base::Value::Dict& node) {
// This may not be called when there are no receivers (i.e., the router is
// inactive), because in that case the logs cannot be displayed.
DCHECK(!receivers_.empty());
- accumulated_logs_.emplace_back(std::move(node));
for (LogReceiver& receiver : receivers_)
- receiver.LogEntry(accumulated_logs_.back());
+ receiver.LogEntry(node);
}
bool LogRouter::RegisterManager(LogManager* manager) {
@@ -53,26 +52,19 @@ void LogRouter::UnregisterManager(LogManager* manager) {
managers_.RemoveObserver(manager);
}
-const std::vector<base::Value>& LogRouter::RegisterReceiver(
- LogReceiver* receiver) {
+void LogRouter::RegisterReceiver(LogReceiver* receiver) {
DCHECK(receiver);
- DCHECK(accumulated_logs_.empty() || !receivers_.empty());
-
if (receivers_.empty()) {
for (LogManager& manager : managers_)
manager.OnLogRouterAvailabilityChanged(true);
}
receivers_.AddObserver(receiver);
- return accumulated_logs_;
}
void LogRouter::UnregisterReceiver(LogReceiver* receiver) {
DCHECK(receivers_.HasObserver(receiver));
receivers_.RemoveObserver(receiver);
if (receivers_.empty()) {
- // |accumulated_logs_| can become very long; use the swap instead of clear()
- // to ensure that the memory is freed.
- std::vector<base::Value>().swap(accumulated_logs_);
for (LogManager& manager : managers_)
manager.OnLogRouterAvailabilityChanged(false);
}
diff --git a/chromium/components/autofill/core/browser/logging/log_router.h b/chromium/components/autofill/core/browser/logging/log_router.h
index 2ef73cc25d7..b335bd35e47 100644
--- a/chromium/components/autofill/core/browser/logging/log_router.h
+++ b/chromium/components/autofill/core/browser/logging/log_router.h
@@ -32,11 +32,11 @@ class LogRouter : public KeyedService {
~LogRouter() override;
// Returns a JSON entry that can be fed into the logger.
- static base::Value CreateEntryForText(const std::string& text);
+ static base::Value::Dict CreateEntryForText(const std::string& text);
// Passes logs to the router. Only call when there are receivers registered.
void ProcessLog(const std::string& text);
- void ProcessLog(base::Value&& node);
+ void ProcessLog(const base::Value::Dict& node);
// All four (Unr|R)egister* methods below are safe to call from the
// constructor of the registered object, because they do not call that object,
@@ -50,11 +50,7 @@ class LogRouter : public KeyedService {
void UnregisterManager(LogManager* manager);
// The receivers must register to get updates with new logs in the future.
- // RegisterReceiver adds |receiver| to the right observer list, and returns
- // the logs accumulated so far. (It returns by value, not const ref, to
- // provide a snapshot as opposed to a link to |accumulated_logs_|.)
- [[nodiscard]] const std::vector<base::Value>& RegisterReceiver(
- LogReceiver* receiver);
+ void RegisterReceiver(LogReceiver* receiver);
// Remove |receiver| from the observers list.
void UnregisterReceiver(LogReceiver* receiver);
@@ -64,9 +60,6 @@ class LogRouter : public KeyedService {
// on destruction.
base::ObserverList<LogManager, true>::Unchecked managers_;
base::ObserverList<LogReceiver, true>::Unchecked receivers_;
-
- // Logs accumulated since the first receiver was registered.
- std::vector<base::Value> accumulated_logs_;
};
} // namespace autofill
diff --git a/chromium/components/autofill/core/browser/logging/log_router_unittest.cc b/chromium/components/autofill/core/browser/logging/log_router_unittest.cc
index 987a453c599..1e5464958f7 100644
--- a/chromium/components/autofill/core/browser/logging/log_router_unittest.cc
+++ b/chromium/components/autofill/core/browser/logging/log_router_unittest.cc
@@ -25,7 +25,7 @@ class MockLogReceiver : public LogReceiver {
MockLogReceiver(const MockLogReceiver&) = delete;
MockLogReceiver& operator=(const MockLogReceiver&) = delete;
- MOCK_METHOD(void, LogEntry, (const base::Value&), (override));
+ MOCK_METHOD(void, LogEntry, (const base::Value::Dict&), (override));
};
class MockLogManager : public StubLogManager {
@@ -47,57 +47,23 @@ class LogRouterTest : public testing::Test {
testing::StrictMock<MockLogManager> manager_;
};
-TEST_F(LogRouterTest, ProcessLog_NoReceiver) {
- LogRouter router;
- EXPECT_EQ(std::vector<base::Value>(), router.RegisterReceiver(&receiver_));
- base::Value log_entry = LogRouter::CreateEntryForText(kTestText);
- EXPECT_CALL(receiver_, LogEntry(testing::Eq(testing::ByRef(log_entry))))
- .Times(1);
- router.ProcessLog(kTestText);
- router.UnregisterReceiver(&receiver_);
- // Without receivers, accumulated logs should not have been kept. That means
- // that on the registration of the first receiver, none are returned.
- EXPECT_EQ(std::vector<base::Value>(), router.RegisterReceiver(&receiver_));
- router.UnregisterReceiver(&receiver_);
-}
-
TEST_F(LogRouterTest, ProcessLog_OneReceiver) {
LogRouter router;
- EXPECT_EQ(std::vector<base::Value>(), router.RegisterReceiver(&receiver_));
- // Check that logs generated after activation are passed.
- base::Value log_entry = LogRouter::CreateEntryForText(kTestText);
- EXPECT_CALL(receiver_, LogEntry(testing::Eq(testing::ByRef(log_entry))))
- .Times(1);
- router.ProcessLog(kTestText);
- router.UnregisterReceiver(&receiver_);
-}
-
-TEST_F(LogRouterTest, ProcessLog_TwoReceiversAccumulatedLogsPassed) {
- LogRouter router;
- EXPECT_EQ(std::vector<base::Value>(), router.RegisterReceiver(&receiver_));
-
- // Log something with only the first receiver, to accumulate some logs.
- base::Value log_entry = LogRouter::CreateEntryForText(kTestText);
+ router.RegisterReceiver(&receiver_);
+ base::Value::Dict log_entry = LogRouter::CreateEntryForText(kTestText);
EXPECT_CALL(receiver_, LogEntry(testing::Eq(testing::ByRef(log_entry))))
.Times(1);
- EXPECT_CALL(receiver2_, LogEntry(testing::Eq(testing::ByRef(log_entry))))
- .Times(0);
router.ProcessLog(kTestText);
- // Accumulated logs get passed on registration.
- std::vector<base::Value> expected_logs;
- expected_logs.emplace_back(log_entry.Clone());
- EXPECT_EQ(expected_logs, router.RegisterReceiver(&receiver2_));
router.UnregisterReceiver(&receiver_);
- router.UnregisterReceiver(&receiver2_);
}
TEST_F(LogRouterTest, ProcessLog_TwoReceiversBothUpdated) {
LogRouter router;
- EXPECT_EQ(std::vector<base::Value>(), router.RegisterReceiver(&receiver_));
- EXPECT_EQ(std::vector<base::Value>(), router.RegisterReceiver(&receiver2_));
+ router.RegisterReceiver(&receiver_);
+ router.RegisterReceiver(&receiver2_);
// Check that both receivers get log updates.
- base::Value log_entry = LogRouter::CreateEntryForText(kTestText);
+ base::Value::Dict log_entry = LogRouter::CreateEntryForText(kTestText);
EXPECT_CALL(receiver_, LogEntry(testing::Eq(testing::ByRef(log_entry))))
.Times(1);
EXPECT_CALL(receiver2_, LogEntry(testing::Eq(testing::ByRef(log_entry))))
@@ -109,13 +75,13 @@ TEST_F(LogRouterTest, ProcessLog_TwoReceiversBothUpdated) {
TEST_F(LogRouterTest, ProcessLog_TwoReceiversNoUpdateAfterUnregistering) {
LogRouter router;
- EXPECT_EQ(std::vector<base::Value>(), router.RegisterReceiver(&receiver_));
- EXPECT_EQ(std::vector<base::Value>(), router.RegisterReceiver(&receiver2_));
+ router.RegisterReceiver(&receiver_);
+ router.RegisterReceiver(&receiver2_);
// Check that no logs are passed to an unregistered receiver.
router.UnregisterReceiver(&receiver_);
EXPECT_CALL(receiver_, LogEntry(_)).Times(0);
- base::Value log_entry = LogRouter::CreateEntryForText(kTestText);
+ base::Value::Dict log_entry = LogRouter::CreateEntryForText(kTestText);
EXPECT_CALL(receiver2_, LogEntry(testing::Eq(testing::ByRef(log_entry))))
.Times(1);
router.ProcessLog(kTestText);
@@ -131,7 +97,7 @@ TEST_F(LogRouterTest, RegisterManager_NoReceivers) {
TEST_F(LogRouterTest, RegisterManager_OneReceiverBeforeManager) {
LogRouter router;
// First register a receiver.
- EXPECT_EQ(std::vector<base::Value>(), router.RegisterReceiver(&receiver_));
+ router.RegisterReceiver(&receiver_);
// The manager should be told the LogRouter has some receivers.
EXPECT_TRUE(router.RegisterManager(&manager_));
// Now unregister the receiver. The manager should be told the LogRouter has
@@ -148,7 +114,7 @@ TEST_F(LogRouterTest, RegisterManager_OneManagerBeforeReceiver) {
EXPECT_FALSE(router.RegisterManager(&manager_));
// Now register the receiver. The manager should be notified.
EXPECT_CALL(manager_, OnLogRouterAvailabilityChanged(true));
- EXPECT_EQ(std::vector<base::Value>(), router.RegisterReceiver(&receiver_));
+ router.RegisterReceiver(&receiver_);
// Now unregister the manager.
router.UnregisterManager(&manager_);
// Now unregister the receiver. The manager should not hear about it.
@@ -163,10 +129,10 @@ TEST_F(LogRouterTest, RegisterManager_OneManagerTwoReceivers) {
EXPECT_FALSE(router.RegisterManager(&manager_));
// Now register the 1st receiver. The manager should be notified.
EXPECT_CALL(manager_, OnLogRouterAvailabilityChanged(true));
- EXPECT_EQ(std::vector<base::Value>(), router.RegisterReceiver(&receiver_));
+ router.RegisterReceiver(&receiver_);
// Now register the 2nd receiver. The manager should not be notified.
EXPECT_CALL(manager_, OnLogRouterAvailabilityChanged(true)).Times(0);
- EXPECT_EQ(std::vector<base::Value>(), router.RegisterReceiver(&receiver2_));
+ router.RegisterReceiver(&receiver2_);
// Now unregister the 1st receiver. The manager should not hear about it.
EXPECT_CALL(manager_, OnLogRouterAvailabilityChanged(false)).Times(0);
router.UnregisterReceiver(&receiver_);
diff --git a/chromium/components/autofill/core/browser/logging/stub_log_manager.cc b/chromium/components/autofill/core/browser/logging/stub_log_manager.cc
index 8fab7f94dd5..00a6ad19621 100644
--- a/chromium/components/autofill/core/browser/logging/stub_log_manager.cc
+++ b/chromium/components/autofill/core/browser/logging/stub_log_manager.cc
@@ -12,7 +12,7 @@ void StubLogManager::SetSuspended(bool suspended) {}
void StubLogManager::LogTextMessage(const std::string& text) const {}
-void StubLogManager::LogEntry(base::Value&& entry) const {}
+void StubLogManager::LogEntry(const base::Value::Dict& entry) const {}
bool StubLogManager::IsLoggingActive() const {
return false;
diff --git a/chromium/components/autofill/core/browser/logging/stub_log_manager.h b/chromium/components/autofill/core/browser/logging/stub_log_manager.h
index 66b4290ae09..949bfe2bf32 100644
--- a/chromium/components/autofill/core/browser/logging/stub_log_manager.h
+++ b/chromium/components/autofill/core/browser/logging/stub_log_manager.h
@@ -26,7 +26,7 @@ class StubLogManager : public LogManager {
void OnLogRouterAvailabilityChanged(bool router_can_be_used) override;
void SetSuspended(bool suspended) override;
void LogTextMessage(const std::string& text) const override;
- void LogEntry(base::Value&& entry) const override;
+ void LogEntry(const base::Value::Dict& entry) const override;
bool IsLoggingActive() const override;
LogBufferSubmitter Log() override;
};
diff --git a/chromium/components/autofill/core/browser/merchant_promo_code_manager.cc b/chromium/components/autofill/core/browser/merchant_promo_code_manager.cc
index 0c78f120478..ee3af4bcdbf 100644
--- a/chromium/components/autofill/core/browser/merchant_promo_code_manager.cc
+++ b/chromium/components/autofill/core/browser/merchant_promo_code_manager.cc
@@ -18,29 +18,43 @@ MerchantPromoCodeManager::MerchantPromoCodeManager() = default;
MerchantPromoCodeManager::~MerchantPromoCodeManager() = default;
-void MerchantPromoCodeManager::OnGetSingleFieldSuggestions(
+bool MerchantPromoCodeManager::OnGetSingleFieldSuggestions(
int query_id,
bool is_autocomplete_enabled,
bool autoselect_first_suggestion,
- const std::u16string& name,
- const std::u16string& prefix,
- const std::string& form_control_type,
+ const FormFieldData& field,
base::WeakPtr<SuggestionsHandler> handler,
const SuggestionsContext& context) {
+ // We don't check whether |is_autocomplete_enabled| is false because it is
+ // redundant. If |is_autocomplete_enabled| is false, then autofill
+ // wallet import must be disabled. Disabling autofill wallet import (turning
+ // off the "Save and fill payment methods" toggle) will disable offering
+ // suggestions and filling promo codes, because it will cause
+ // PersonalDataManager::GetActiveAutofillPromoCodeOffersForOrigin() to return
+ // an empty vector.
+ bool field_is_eligible =
+ context.focused_field &&
+ context.focused_field->Type().GetStorableType() == MERCHANT_PROMO_CODE;
+ if (!field_is_eligible)
+ return false;
+
// If merchant promo code offers are available for the given site, and the
// profile is not OTR, show the promo code offers.
if (!is_off_the_record_ && personal_data_manager_) {
- std::vector<const AutofillOfferData*> promo_code_offers =
+ const std::vector<const AutofillOfferData*> promo_code_offers =
personal_data_manager_->GetActiveAutofillPromoCodeOffersForOrigin(
context.form_structure->main_frame_origin().GetURL());
if (!promo_code_offers.empty()) {
SendPromoCodeSuggestions(
- promo_code_offers,
- QueryHandler(query_id, autoselect_first_suggestion, prefix, handler));
- uma_recorder_.OnOffersSuggestionsShown(name, promo_code_offers);
- return;
+ promo_code_offers, QueryHandler(query_id, autoselect_first_suggestion,
+ field.value, handler));
+ // TODO(crbug.com/1190334): Fix the metrics logging to not log if we will
+ // not show promo code autofill suggestions.
+ uma_recorder_.OnOffersSuggestionsShown(field.name, promo_code_offers);
+ return true;
}
}
+ return false;
}
void MerchantPromoCodeManager::OnWillSubmitFormWithFields(
@@ -73,7 +87,7 @@ base::WeakPtr<MerchantPromoCodeManager> MerchantPromoCodeManager::GetWeakPtr() {
void MerchantPromoCodeManager::UMARecorder::OnOffersSuggestionsShown(
const std::u16string& name,
- std::vector<const AutofillOfferData*>& offers) {
+ const std::vector<const AutofillOfferData*>& offers) {
// Log metrics related to the showing of overall offers suggestions popup.
autofill_metrics::LogOffersSuggestionsPopupShown(
/*first_time_being_logged=*/most_recent_suggestions_shown_field_name_ !=
@@ -156,6 +170,11 @@ void MerchantPromoCodeManager::SendPromoCodeSuggestions(
for (const AutofillOfferData* promo_code_offer : promo_code_offers) {
if (query_handler.prefix_ ==
base::ASCIIToUTF16(promo_code_offer->GetPromoCode())) {
+ // Return empty suggestions to query handler. This will result in no
+ // suggestions being displayed.
+ query_handler.handler_->OnSuggestionsReturned(
+ query_handler.client_query_id_,
+ query_handler.autoselect_first_suggestion_, {});
return;
}
}
diff --git a/chromium/components/autofill/core/browser/merchant_promo_code_manager.h b/chromium/components/autofill/core/browser/merchant_promo_code_manager.h
index d461ae9cae9..ec0c0c3e196 100644
--- a/chromium/components/autofill/core/browser/merchant_promo_code_manager.h
+++ b/chromium/components/autofill/core/browser/merchant_promo_code_manager.h
@@ -33,14 +33,13 @@ class MerchantPromoCodeManager : public SingleFieldFormFiller,
~MerchantPromoCodeManager() override;
// SingleFieldFormFiller overrides:
- void OnGetSingleFieldSuggestions(int query_id,
- bool is_autocomplete_enabled,
- bool autoselect_first_suggestion,
- const std::u16string& name,
- const std::u16string& prefix,
- const std::string& form_control_type,
- base::WeakPtr<SuggestionsHandler> handler,
- const SuggestionsContext& context) override;
+ [[nodiscard]] bool OnGetSingleFieldSuggestions(
+ int query_id,
+ bool is_autocomplete_enabled,
+ bool autoselect_first_suggestion,
+ const FormFieldData& field,
+ base::WeakPtr<SuggestionsHandler> handler,
+ const SuggestionsContext& context) override;
void OnWillSubmitFormWithFields(const std::vector<FormFieldData>& fields,
bool is_autocomplete_enabled) override;
void CancelPendingQueries(const SuggestionsHandler* handler) override;
@@ -80,7 +79,7 @@ class MerchantPromoCodeManager : public SingleFieldFormFiller,
void OnOffersSuggestionsShown(
const std::u16string& name,
- std::vector<const AutofillOfferData*>& offers);
+ const std::vector<const AutofillOfferData*>& offers);
void OnOfferSuggestionSelected(int frontend_id);
private:
diff --git a/chromium/components/autofill/core/browser/merchant_promo_code_manager_unittest.cc b/chromium/components/autofill/core/browser/merchant_promo_code_manager_unittest.cc
index b6543802b03..e2b1ca8e82b 100644
--- a/chromium/components/autofill/core/browser/merchant_promo_code_manager_unittest.cc
+++ b/chromium/components/autofill/core/browser/merchant_promo_code_manager_unittest.cc
@@ -6,9 +6,9 @@
#include "base/test/metrics/histogram_tester.h"
#include "base/test/scoped_feature_list.h"
#include "components/autofill/core/browser/autofill_test_utils.h"
+#include "components/autofill/core/browser/form_structure.h"
#include "components/autofill/core/browser/metrics/payments/offers_metrics.h"
#include "components/autofill/core/browser/suggestions_context.h"
-#include "components/autofill/core/browser/test_form_structure.h"
#include "components/autofill/core/browser/test_personal_data_manager.h"
#include "components/autofill/core/common/autofill_payments_features.h"
#include "components/autofill/core/common/form_data.h"
@@ -17,11 +17,16 @@
#include "testing/gtest/include/gtest/gtest.h"
#include "ui/base/l10n/l10n_util.h"
+using testing::_;
using testing::Field;
+using testing::Truly;
using testing::UnorderedElementsAre;
namespace autofill {
+using FieldPrediction =
+ AutofillQueryResponse::FormSuggestion::FieldSuggestion::FieldPrediction;
+
namespace {
class MockSuggestionsHandler
@@ -55,6 +60,8 @@ class MerchantPromoCodeManagerTest : public testing::Test {
merchant_promo_code_manager_ = std::make_unique<MerchantPromoCodeManager>();
merchant_promo_code_manager_->Init(personal_data_manager_.get(),
/*is_off_the_record=*/false);
+ test::CreateTestFormField(/*label=*/"", "Some Field Name", "SomePrefix",
+ "Some Type", &test_field_);
}
// Sets up the TestPersonalDataManager with a promo code offer for the given
@@ -64,6 +71,7 @@ class MerchantPromoCodeManagerTest : public testing::Test {
std::string SetUpPromoCodeOffer(std::string origin,
const GURL& offer_details_url) {
personal_data_manager_.get()->SetAutofillWalletImportEnabled(true);
+ personal_data_manager_.get()->SetAutofillCreditCardEnabled(true);
AutofillOfferData testPromoCodeOfferData =
test::GetPromoCodeOfferData(GURL(origin));
testPromoCodeOfferData.SetOfferDetailsUrl(offer_details_url);
@@ -72,26 +80,35 @@ class MerchantPromoCodeManagerTest : public testing::Test {
return testPromoCodeOfferData.GetPromoCode();
}
+ // Adds a promo code focused field to the suggestions context.
+ void AddPromoCodeFocusedFieldToSuggestionsContext(SuggestionsContext* out) {
+ FieldPrediction merchant_promo_code_field_prediction;
+ merchant_promo_code_field_prediction.set_type(MERCHANT_PROMO_CODE);
+ autofill_field_.set_server_predictions(
+ {merchant_promo_code_field_prediction});
+ out->focused_field = &autofill_field_;
+ }
+
std::unique_ptr<MerchantPromoCodeManager> merchant_promo_code_manager_;
std::unique_ptr<TestPersonalDataManager> personal_data_manager_;
+ FormFieldData test_field_;
+ AutofillField autofill_field_;
};
TEST_F(MerchantPromoCodeManagerTest, ShowsPromoCodeSuggestions) {
base::HistogramTester histogram_tester;
auto suggestions_handler = std::make_unique<MockSuggestionsHandler>();
int test_query_id = 2;
- std::u16string test_name = u"Some Field Name";
- std::u16string test_prefix = u"SomePrefix";
bool autoselect_first_suggestion = false;
bool is_autocomplete_enabled = true;
- std::string form_control_type = "Some Type";
std::string last_committed_origin_url = "https://www.example.com";
FormData form_data;
form_data.main_frame_origin =
url::Origin::Create(GURL(last_committed_origin_url));
- TestFormStructure form_structure{form_data};
+ FormStructure form_structure{form_data};
SuggestionsContext context;
context.form_structure = &form_structure;
+ AddPromoCodeFocusedFieldToSuggestionsContext(&context);
std::string promo_code = SetUpPromoCodeOffer(
last_committed_origin_url, GURL("https://offer-details-url.com/"));
Suggestion promo_code_suggestion = Suggestion(base::ASCIIToUTF16(promo_code));
@@ -106,6 +123,7 @@ TEST_F(MerchantPromoCodeManagerTest, ShowsPromoCodeSuggestions) {
test_query_id, autoselect_first_suggestion,
UnorderedElementsAre(
Field(&Suggestion::main_text, promo_code_suggestion.main_text),
+ Field(&Suggestion::frontend_id, POPUP_ITEM_ID_SEPARATOR),
Field(&Suggestion::main_text, footer_suggestion.main_text))))
.Times(3);
@@ -113,27 +131,27 @@ TEST_F(MerchantPromoCodeManagerTest, ShowsPromoCodeSuggestions) {
// Because all criteria are met, active promo code suggestions for the given
// merchant site will be displayed instead of requesting Autocomplete
// suggestions.
- merchant_promo_code_manager_->OnGetSingleFieldSuggestions(
+ EXPECT_TRUE(merchant_promo_code_manager_->OnGetSingleFieldSuggestions(
test_query_id, is_autocomplete_enabled, autoselect_first_suggestion,
- test_name, test_prefix, form_control_type,
- suggestions_handler->GetWeakPtr(),
- /*context=*/context);
+ test_field_, suggestions_handler->GetWeakPtr(),
+ /*context=*/context));
// Trigger offers suggestions popup again to be able to test that we do not
// log metrics twice for the same field.
- merchant_promo_code_manager_->OnGetSingleFieldSuggestions(
+ EXPECT_TRUE(merchant_promo_code_manager_->OnGetSingleFieldSuggestions(
test_query_id, is_autocomplete_enabled, autoselect_first_suggestion,
- test_name, test_prefix, form_control_type,
- suggestions_handler->GetWeakPtr(),
- /*context=*/context);
+ test_field_, suggestions_handler->GetWeakPtr(),
+ /*context=*/context));
// Trigger offers suggestions popup again to be able to test that we log
// metrics more than once if it is a different field.
- merchant_promo_code_manager_->OnGetSingleFieldSuggestions(
+ FormFieldData other_field;
+ test::CreateTestFormField(/*label=*/"", "Some Other Name", "SomePrefix",
+ "Some Type", &other_field);
+ EXPECT_TRUE(merchant_promo_code_manager_->OnGetSingleFieldSuggestions(
test_query_id, is_autocomplete_enabled, autoselect_first_suggestion,
- u"other_name", test_prefix, form_control_type,
- suggestions_handler->GetWeakPtr(),
- /*context=*/context);
+ other_field, suggestions_handler->GetWeakPtr(),
+ /*context=*/context));
histogram_tester.ExpectBucketCount(
"Autofill.Offer.SuggestionsPopupShown",
@@ -154,6 +172,41 @@ TEST_F(MerchantPromoCodeManagerTest, ShowsPromoCodeSuggestions) {
}
TEST_F(MerchantPromoCodeManagerTest,
+ DoesNotShowPromoCodeOffersIfFieldIsNotAPromoCodeField) {
+ base::HistogramTester histogram_tester;
+ auto suggestions_handler = std::make_unique<MockSuggestionsHandler>();
+
+ // Setting up mock to verify that suggestions returning is not triggered if
+ // the field is not a promo code field.
+ EXPECT_CALL(*suggestions_handler, OnSuggestionsReturned).Times(0);
+
+ // Simulate request for suggestions.
+ EXPECT_FALSE(merchant_promo_code_manager_->OnGetSingleFieldSuggestions(
+ /*query_id=*/2, /*is_autocomplete_enabled=*/true,
+ /*autoselect_first_suggestion=*/false, test_field_,
+ suggestions_handler->GetWeakPtr(),
+ /*context=*/SuggestionsContext()));
+
+ // Ensure that no metrics were logged.
+ histogram_tester.ExpectBucketCount(
+ "Autofill.Offer.SuggestionsPopupShown",
+ autofill_metrics::OffersSuggestionsPopupEvent::
+ kOffersSuggestionsPopupShownOnce,
+ 0);
+ histogram_tester.ExpectBucketCount(
+ "Autofill.Offer.SuggestionsPopupShown",
+ autofill_metrics::OffersSuggestionsPopupEvent::
+ kOffersSuggestionsPopupShown,
+ 0);
+ histogram_tester.ExpectBucketCount(
+ "Autofill.Offer.Suggestion.GPayPromoCodeOffer",
+ autofill_metrics::OffersSuggestionsEvent::kOfferSuggestionShownOnce, 0);
+ histogram_tester.ExpectBucketCount(
+ "Autofill.Offer.Suggestion.GPayPromoCodeOffer",
+ autofill_metrics::OffersSuggestionsEvent::kOfferSuggestionShown, 0);
+}
+
+TEST_F(MerchantPromoCodeManagerTest,
DoesNotShowPromoCodeOffersForOffTheRecord) {
base::HistogramTester histogram_tester;
auto suggestions_handler = std::make_unique<MockSuggestionsHandler>();
@@ -163,9 +216,10 @@ TEST_F(MerchantPromoCodeManagerTest,
FormData form_data;
form_data.main_frame_origin =
url::Origin::Create(GURL(last_committed_origin_url));
- TestFormStructure form_structure{form_data};
+ FormStructure form_structure{form_data};
SuggestionsContext context;
context.form_structure = &form_structure;
+ AddPromoCodeFocusedFieldToSuggestionsContext(&context);
merchant_promo_code_manager_->is_off_the_record_ = true;
// Setting up mock to verify that suggestions returning is not triggered if
@@ -173,11 +227,11 @@ TEST_F(MerchantPromoCodeManagerTest,
EXPECT_CALL(*suggestions_handler, OnSuggestionsReturned).Times(0);
// Simulate request for suggestions.
- merchant_promo_code_manager_->OnGetSingleFieldSuggestions(
+ EXPECT_FALSE(merchant_promo_code_manager_->OnGetSingleFieldSuggestions(
/*query_id=*/2, /*is_autocomplete_enabled=*/true,
- /*autoselect_first_suggestion=*/false, /*name=*/u"Some Field Name",
- /*prefix=*/u"SomePrefix", "Some Type", suggestions_handler->GetWeakPtr(),
- /*context=*/context);
+ /*autoselect_first_suggestion=*/false, test_field_,
+ suggestions_handler->GetWeakPtr(),
+ /*context=*/context));
// Ensure that no metrics were logged.
histogram_tester.ExpectBucketCount(
@@ -206,9 +260,10 @@ TEST_F(MerchantPromoCodeManagerTest,
FormData form_data;
form_data.main_frame_origin =
url::Origin::Create(GURL(last_committed_origin_url));
- TestFormStructure form_structure{form_data};
+ FormStructure form_structure{form_data};
SuggestionsContext context;
context.form_structure = &form_structure;
+ AddPromoCodeFocusedFieldToSuggestionsContext(&context);
merchant_promo_code_manager_->personal_data_manager_ = nullptr;
// Setting up mock to verify that suggestions returning is not triggered if
@@ -216,11 +271,11 @@ TEST_F(MerchantPromoCodeManagerTest,
EXPECT_CALL(*suggestions_handler, OnSuggestionsReturned).Times(0);
// Simulate request for suggestions.
- merchant_promo_code_manager_->OnGetSingleFieldSuggestions(
+ EXPECT_FALSE(merchant_promo_code_manager_->OnGetSingleFieldSuggestions(
/*query_id=*/2, /*is_autocomplete_enabled=*/true,
- /*autoselect_first_suggestion=*/false, /*name=*/u"Some Field Name",
- /*prefix=*/u"SomePrefix", "Some Type", suggestions_handler->GetWeakPtr(),
- /*context=*/context);
+ /*autoselect_first_suggestion=*/false, test_field_,
+ suggestions_handler->GetWeakPtr(),
+ /*context=*/context));
// Ensure that no metrics were logged.
histogram_tester.ExpectBucketCount(
@@ -246,23 +301,25 @@ TEST_F(MerchantPromoCodeManagerTest, NoPromoCodeOffers) {
auto suggestions_handler = std::make_unique<MockSuggestionsHandler>();
std::string last_committed_origin_url = "https://www.example.com";
personal_data_manager_.get()->SetAutofillWalletImportEnabled(true);
+ personal_data_manager_.get()->SetAutofillCreditCardEnabled(true);
FormData form_data;
form_data.main_frame_origin =
url::Origin::Create(GURL(last_committed_origin_url));
- TestFormStructure form_structure{form_data};
+ FormStructure form_structure{form_data};
SuggestionsContext context;
context.form_structure = &form_structure;
+ AddPromoCodeFocusedFieldToSuggestionsContext(&context);
// Setting up mock to verify that suggestions returning is not triggered if
// there are no promo code offers to suggest.
EXPECT_CALL(*suggestions_handler, OnSuggestionsReturned).Times(0);
// Simulate request for suggestions.
- merchant_promo_code_manager_->OnGetSingleFieldSuggestions(
+ EXPECT_FALSE(merchant_promo_code_manager_->OnGetSingleFieldSuggestions(
/*query_id=*/2, /*is_autocomplete_enabled=*/true,
- /*autoselect_first_suggestion=*/false, /*name=*/u"Some Field Name",
- /*prefix=*/u"SomePrefix", "Some Type", suggestions_handler->GetWeakPtr(),
- /*context=*/context);
+ /*autoselect_first_suggestion=*/false, test_field_,
+ suggestions_handler->GetWeakPtr(),
+ /*context=*/context));
// Ensure that no metrics were logged.
histogram_tester.ExpectBucketCount(
@@ -283,25 +340,174 @@ TEST_F(MerchantPromoCodeManagerTest, NoPromoCodeOffers) {
autofill_metrics::OffersSuggestionsEvent::kOfferSuggestionShown, 0);
}
+// This test case exists to ensure that disabling autofill wallet import (by
+// turning off the "Payment methods, offers, and addresses using Google Pay"
+// toggle) disables offering suggestions and autofilling for promo codes.
+TEST_F(MerchantPromoCodeManagerTest, AutofillWalletImportDisabled) {
+ base::HistogramTester histogram_tester;
+ auto suggestions_handler = std::make_unique<MockSuggestionsHandler>();
+ std::string last_committed_origin_url = "https://www.example.com";
+ FormData form_data;
+ form_data.main_frame_origin =
+ url::Origin::Create(GURL(last_committed_origin_url));
+ FormStructure form_structure{form_data};
+ SuggestionsContext context;
+ context.form_structure = &form_structure;
+ AddPromoCodeFocusedFieldToSuggestionsContext(&context);
+ SetUpPromoCodeOffer(last_committed_origin_url,
+ GURL("https://offer-details-url.com/"));
+ personal_data_manager_->SetAutofillWalletImportEnabled(false);
+
+ // Autofill wallet import is disabled, so check that we do not return
+ // suggestions to the handler.
+ EXPECT_CALL(*suggestions_handler, OnSuggestionsReturned).Times(0);
+
+ // Simulate request for suggestions.
+ EXPECT_FALSE(merchant_promo_code_manager_->OnGetSingleFieldSuggestions(
+ /*query_id=*/2, /*is_autocomplete_enabled=*/true,
+ /*autoselect_first_suggestion=*/false, test_field_,
+ suggestions_handler->GetWeakPtr(),
+ /*context=*/context));
+
+ // Ensure that no metrics were logged.
+ histogram_tester.ExpectBucketCount(
+ "Autofill.Offer.SuggestionsPopupShown",
+ autofill_metrics::OffersSuggestionsPopupEvent::
+ kOffersSuggestionsPopupShownOnce,
+ 0);
+ histogram_tester.ExpectBucketCount(
+ "Autofill.Offer.SuggestionsPopupShown",
+ autofill_metrics::OffersSuggestionsPopupEvent::
+ kOffersSuggestionsPopupShown,
+ 0);
+ histogram_tester.ExpectBucketCount(
+ "Autofill.Offer.Suggestion.GPayPromoCodeOffer",
+ autofill_metrics::OffersSuggestionsEvent::kOfferSuggestionShownOnce, 0);
+ histogram_tester.ExpectBucketCount(
+ "Autofill.Offer.Suggestion.GPayPromoCodeOffer",
+ autofill_metrics::OffersSuggestionsEvent::kOfferSuggestionShown, 0);
+}
+
+// This test case exists to ensure that disabling autofill credit card (by
+// turning off the "Save and fill payment methods" toggle) disables offering
+// suggestions and autofilling for promo codes.
+TEST_F(MerchantPromoCodeManagerTest, AutofillCreditCardDisabled) {
+ base::HistogramTester histogram_tester;
+ auto suggestions_handler = std::make_unique<MockSuggestionsHandler>();
+ std::string last_committed_origin_url = "https://www.example.com";
+ FormData form_data;
+ form_data.main_frame_origin =
+ url::Origin::Create(GURL(last_committed_origin_url));
+ FormStructure form_structure{form_data};
+ SuggestionsContext context;
+ context.form_structure = &form_structure;
+ AddPromoCodeFocusedFieldToSuggestionsContext(&context);
+ SetUpPromoCodeOffer(last_committed_origin_url,
+ GURL("https://offer-details-url.com/"));
+ personal_data_manager_->SetAutofillCreditCardEnabled(false);
+
+ // Autofill credit card is disabled, so check that we do not return
+ // suggestions to the handler.
+ EXPECT_CALL(*suggestions_handler, OnSuggestionsReturned).Times(0);
+
+ // Simulate request for suggestions.
+ EXPECT_FALSE(merchant_promo_code_manager_->OnGetSingleFieldSuggestions(
+ /*query_id=*/2, /*is_autocomplete_enabled=*/true,
+ /*autoselect_first_suggestion=*/false, test_field_,
+ suggestions_handler->GetWeakPtr(),
+ /*context=*/context));
+
+ // Ensure that no metrics were logged.
+ histogram_tester.ExpectBucketCount(
+ "Autofill.Offer.SuggestionsPopupShown",
+ autofill_metrics::OffersSuggestionsPopupEvent::
+ kOffersSuggestionsPopupShownOnce,
+ 0);
+ histogram_tester.ExpectBucketCount(
+ "Autofill.Offer.SuggestionsPopupShown",
+ autofill_metrics::OffersSuggestionsPopupEvent::
+ kOffersSuggestionsPopupShown,
+ 0);
+ histogram_tester.ExpectBucketCount(
+ "Autofill.Offer.Suggestion.GPayPromoCodeOffer",
+ autofill_metrics::OffersSuggestionsEvent::kOfferSuggestionShownOnce, 0);
+ histogram_tester.ExpectBucketCount(
+ "Autofill.Offer.Suggestion.GPayPromoCodeOffer",
+ autofill_metrics::OffersSuggestionsEvent::kOfferSuggestionShown, 0);
+}
+
+// This test case exists to ensure that we do not offer promo code offer
+// suggestions if the field already contains a promo code.
+TEST_F(MerchantPromoCodeManagerTest, PrefixMatched) {
+ base::HistogramTester histogram_tester;
+ auto suggestions_handler = std::make_unique<MockSuggestionsHandler>();
+ std::string last_committed_origin_url = "https://www.example.com";
+ FormData form_data;
+ form_data.main_frame_origin =
+ url::Origin::Create(GURL(last_committed_origin_url));
+ FormStructure form_structure{form_data};
+ SuggestionsContext context;
+ context.form_structure = &form_structure;
+ AddPromoCodeFocusedFieldToSuggestionsContext(&context);
+ test_field_.value = base::ASCIIToUTF16(SetUpPromoCodeOffer(
+ last_committed_origin_url, GURL("https://offer-details-url.com/")));
+
+ // The field contains the promo code already, so check that we do not return
+ // suggestions to the handler.
+ EXPECT_CALL(*suggestions_handler,
+ OnSuggestionsReturned(
+ _, _,
+ testing::Truly(
+ [](const std::vector<Suggestion>& returned_suggestions) {
+ return returned_suggestions.empty();
+ })));
+
+ // Simulate request for suggestions.
+ EXPECT_TRUE(merchant_promo_code_manager_->OnGetSingleFieldSuggestions(
+ /*query_id=*/2, /*is_autocomplete_enabled=*/true,
+ /*autoselect_first_suggestion=*/false, test_field_,
+ suggestions_handler->GetWeakPtr(),
+ /*context=*/context));
+
+ // Log that suggestions were attempted to be shown.
+ // TODO(crbug.com/1190334): Fix the metrics logging to not log if we will not
+ // show promo code autofill suggestions.
+ // histogram_tester.ExpectBucketCount(
+ // "Autofill.Offer.SuggestionsPopupShown",
+ // autofill_metrics::OffersSuggestionsPopupEvent::
+ // kOffersSuggestionsPopupShownOnce,
+ // 0);
+ // histogram_tester.ExpectBucketCount(
+ // "Autofill.Offer.SuggestionsPopupShown",
+ // autofill_metrics::OffersSuggestionsPopupEvent::
+ // kOffersSuggestionsPopupShown,
+ // 0);
+ // histogram_tester.ExpectBucketCount(
+ // "Autofill.Offer.Suggestion.GPayPromoCodeOffer",
+ // autofill_metrics::OffersSuggestionsEvent::kOfferSuggestionShownOnce,
+ // 0);
+ // histogram_tester.ExpectBucketCount(
+ // "Autofill.Offer.Suggestion.GPayPromoCodeOffer",
+ // autofill_metrics::OffersSuggestionsEvent::kOfferSuggestionShown, 0);
+}
+
TEST_F(MerchantPromoCodeManagerTest,
OnSingleFieldSuggestion_GPayPromoCodeOfferSuggestion) {
// Set up the test.
base::HistogramTester histogram_tester;
auto suggestions_handler = std::make_unique<MockSuggestionsHandler>();
int test_query_id = 2;
- std::u16string test_name = u"Some Field Name";
- std::u16string test_prefix = u"SomePrefix";
std::u16string test_promo_code = u"test_promo_code";
bool autoselect_first_suggestion = false;
bool is_autocomplete_enabled = true;
- std::string form_control_type = "Some Type";
std::string last_committed_origin_url = "https://www.example.com";
FormData form_data;
form_data.main_frame_origin =
url::Origin::Create(GURL(last_committed_origin_url));
- TestFormStructure form_structure{form_data};
+ FormStructure form_structure{form_data};
SuggestionsContext context;
context.form_structure = &form_structure;
+ AddPromoCodeFocusedFieldToSuggestionsContext(&context);
SetUpPromoCodeOffer(last_committed_origin_url,
GURL("https://offer-details-url.com/"));
@@ -314,11 +520,10 @@ TEST_F(MerchantPromoCodeManagerTest,
autofill_metrics::OffersSuggestionsEvent::kOfferSuggestionSelected, 0);
// Simulate showing the promo code offers suggestions popup.
- merchant_promo_code_manager_->OnGetSingleFieldSuggestions(
+ EXPECT_TRUE(merchant_promo_code_manager_->OnGetSingleFieldSuggestions(
test_query_id, is_autocomplete_enabled, autoselect_first_suggestion,
- test_name, test_prefix, form_control_type,
- suggestions_handler->GetWeakPtr(),
- /*context=*/context);
+ test_field_, suggestions_handler->GetWeakPtr(),
+ /*context=*/context));
// Simulate selecting a promo code offer suggestion.
merchant_promo_code_manager_->OnSingleFieldSuggestionSelected(
@@ -334,11 +539,10 @@ TEST_F(MerchantPromoCodeManagerTest,
1);
// Simulate showing the promo code offers suggestions popup.
- merchant_promo_code_manager_->OnGetSingleFieldSuggestions(
+ EXPECT_TRUE(merchant_promo_code_manager_->OnGetSingleFieldSuggestions(
test_query_id, is_autocomplete_enabled, autoselect_first_suggestion,
- test_name, test_prefix, form_control_type,
- suggestions_handler->GetWeakPtr(),
- /*context=*/context);
+ test_field_, suggestions_handler->GetWeakPtr(),
+ /*context=*/context));
// Simulate selecting a promo code offer suggestion.
merchant_promo_code_manager_->OnSingleFieldSuggestionSelected(
@@ -360,19 +564,17 @@ TEST_F(MerchantPromoCodeManagerTest,
base::HistogramTester histogram_tester;
auto suggestions_handler = std::make_unique<MockSuggestionsHandler>();
int test_query_id = 2;
- std::u16string test_name = u"Some Field Name";
- std::u16string test_prefix = u"SomePrefix";
std::u16string test_promo_code = u"test_promo_code";
bool autoselect_first_suggestion = false;
bool is_autocomplete_enabled = true;
- std::string form_control_type = "Some Type";
std::string last_committed_origin_url = "https://www.example.com";
FormData form_data;
form_data.main_frame_origin =
url::Origin::Create(GURL(last_committed_origin_url));
- TestFormStructure form_structure{form_data};
+ FormStructure form_structure{form_data};
SuggestionsContext context;
context.form_structure = &form_structure;
+ AddPromoCodeFocusedFieldToSuggestionsContext(&context);
SetUpPromoCodeOffer(last_committed_origin_url,
GURL("https://offer-details-url.com/"));
@@ -387,11 +589,10 @@ TEST_F(MerchantPromoCodeManagerTest,
0);
// Simulate showing the promo code offers suggestions popup.
- merchant_promo_code_manager_->OnGetSingleFieldSuggestions(
+ EXPECT_TRUE(merchant_promo_code_manager_->OnGetSingleFieldSuggestions(
test_query_id, is_autocomplete_enabled, autoselect_first_suggestion,
- test_name, test_prefix, form_control_type,
- suggestions_handler->GetWeakPtr(),
- /*context=*/context);
+ test_field_, suggestions_handler->GetWeakPtr(),
+ /*context=*/context));
// Simulate selecting a promo code offer suggestion.
merchant_promo_code_manager_->OnSingleFieldSuggestionSelected(
@@ -410,11 +611,10 @@ TEST_F(MerchantPromoCodeManagerTest,
1);
// Simulate showing the promo code offers suggestions popup.
- merchant_promo_code_manager_->OnGetSingleFieldSuggestions(
+ EXPECT_TRUE(merchant_promo_code_manager_->OnGetSingleFieldSuggestions(
test_query_id, is_autocomplete_enabled, autoselect_first_suggestion,
- test_name, test_prefix, form_control_type,
- suggestions_handler->GetWeakPtr(),
- /*context=*/context);
+ test_field_, suggestions_handler->GetWeakPtr(),
+ /*context=*/context));
// Simulate selecting a promo code offer suggestion.
merchant_promo_code_manager_->OnSingleFieldSuggestionSelected(
diff --git a/chromium/components/autofill/core/browser/metrics/README.md b/chromium/components/autofill/core/browser/metrics/README.md
index 8e8b69649e1..d851058ae56 100644
--- a/chromium/components/autofill/core/browser/metrics/README.md
+++ b/chromium/components/autofill/core/browser/metrics/README.md
@@ -50,17 +50,17 @@ located, as well as how hard it was to find **all** metrics for a given feature.
### The new way
-**Don't** use a class, but **do** use the `autofill::metrics` namespace. Then,
+**Don't** use a class, but **do** use the `autofill::autofill_metrics` namespace. Then,
combine all metrics that are part of a single feature together, so they're not
intertwined with the rest of Autofill's metrics.
*cool_feature_metrics.h*:
+(Put this header file under components/autofill/core/browser/metrics/[optional_sub_directory])
```c++ {.good}
// [Copyright notice and include guards]
-namespace autofill {
-namespace metrics {
+namespace autofill::autofill_metrics {
enum class CoolFeatureInteractionMetric {
// User accepted the cool feature.
@@ -72,10 +72,9 @@ enum class CoolFeatureInteractionMetric {
kMaxValue = kIgnored,
};
-static void LogCoolFeatureInteraction(CoolFeatureInteractionMetric metric);
+void LogCoolFeatureInteraction(CoolFeatureInteractionMetric metric);
-} // namespace metrics
-} // namespace autofill
+} // namespace autofill::autofill_metrics
```
*cool_feature_metrics.cc*:
@@ -83,12 +82,10 @@ static void LogCoolFeatureInteraction(CoolFeatureInteractionMetric metric);
```c++ {.good}
// [Copyright notice]
-#include "components/autofill/core/browser/metrics/cool_feature_metrics.h"
+#include "components/autofill/core/browser/metrics/[optional_sub_directory]/cool_feature_metrics.h"
-namespace autofill {
-namespace metrics {
+namespace autofill::autofill_metrics {
-// static
void LogCoolFeatureInteraction(CoolFeatureInteractionMetric metric) {
base::UmaHistogramEnumeration("Autofill.CoolFeatureInteraction", metric);
}
@@ -96,9 +93,8 @@ void LogCoolFeatureInteraction(CoolFeatureInteractionMetric metric) {
// If there are other metrics related to this feature, they'd go here, and it
// would be very obvious they're related!
-} // namespace metrics
-} // namespace autofill
+} // namespace autofill::autofill_metrics
```
The calling code of this function would be
-`autofill::metrics::LogCoolFeatureInteraction(~)`.
+`autofill::autofill_metrics::LogCoolFeatureInteraction(~)`.
diff --git a/chromium/components/autofill/core/browser/metrics/autofill_metrics.cc b/chromium/components/autofill/core/browser/metrics/autofill_metrics.cc
index 8fea197ba19..d77e28d1fc4 100644
--- a/chromium/components/autofill/core/browser/metrics/autofill_metrics.cc
+++ b/chromium/components/autofill/core/browser/metrics/autofill_metrics.cc
@@ -335,18 +335,6 @@ int GetFieldTypeGroupPredictionQualityMetric(
case PHONE_HOME_CITY_AND_NUMBER:
case PHONE_HOME_CITY_AND_NUMBER_WITHOUT_TRUNK_PREFIX:
case PHONE_HOME_WHOLE_NUMBER:
- case PHONE_FAX_NUMBER:
- case PHONE_FAX_CITY_CODE:
- case PHONE_FAX_COUNTRY_CODE:
- case PHONE_FAX_CITY_AND_NUMBER:
- case PHONE_FAX_WHOLE_NUMBER:
- case ADDRESS_BILLING_LINE1:
- case ADDRESS_BILLING_LINE2:
- case ADDRESS_BILLING_APT_NUM:
- case ADDRESS_BILLING_CITY:
- case ADDRESS_BILLING_STATE:
- case ADDRESS_BILLING_ZIP:
- case ADDRESS_BILLING_COUNTRY:
case CREDIT_CARD_NAME_FULL:
case CREDIT_CARD_NUMBER:
case CREDIT_CARD_EXP_MONTH:
@@ -358,25 +346,10 @@ int GetFieldTypeGroupPredictionQualityMetric(
case CREDIT_CARD_VERIFICATION_CODE:
case COMPANY_NAME:
case FIELD_WITH_DEFAULT_VALUE:
- case PHONE_BILLING_NUMBER:
- case PHONE_BILLING_CITY_CODE:
- case PHONE_BILLING_COUNTRY_CODE:
- case PHONE_BILLING_CITY_AND_NUMBER:
- case PHONE_BILLING_WHOLE_NUMBER:
- case NAME_BILLING_FIRST:
- case NAME_BILLING_MIDDLE:
- case NAME_BILLING_LAST:
- case NAME_BILLING_MIDDLE_INITIAL:
- case NAME_BILLING_FULL:
- case NAME_BILLING_SUFFIX:
case MERCHANT_EMAIL_SIGNUP:
case MERCHANT_PROMO_CODE:
case PASSWORD:
case ACCOUNT_CREATION_PASSWORD:
- case ADDRESS_BILLING_STREET_ADDRESS:
- case ADDRESS_BILLING_SORTING_CODE:
- case ADDRESS_BILLING_DEPENDENT_LOCALITY:
- case ADDRESS_BILLING_LINE3:
case NOT_ACCOUNT_CREATION_PASSWORD:
case USERNAME:
case USERNAME_AND_EMAIL_ADDRESS:
@@ -401,8 +374,10 @@ int GetFieldTypeGroupPredictionQualityMetric(
case NAME_FULL_WITH_HONORIFIC_PREFIX:
case BIRTHDATE_DAY:
case BIRTHDATE_MONTH:
- case BIRTHDATE_YEAR_4_DIGITS:
+ case BIRTHDATE_4_DIGIT_YEAR:
+ case IBAN_VALUE:
case MAX_VALID_FIELD_TYPE:
+ case CREDIT_CARD_STANDALONE_VERIFICATION_CODE:
NOTREACHED() << field_type << " type is not in that group.";
group = GROUP_AMBIGUOUS;
break;
@@ -860,14 +835,6 @@ void AutofillMetrics::LogCreditCardSaveNotOfferedDueToMaxStrikesMetric(
}
// static
-void AutofillMetrics::LogLocalCardMigrationNotOfferedDueToMaxStrikesMetric(
- SaveTypeMetric metric) {
- UMA_HISTOGRAM_ENUMERATION(
- "Autofill.StrikeDatabase.LocalCardMigrationNotOfferedDueToMaxStrikes",
- metric);
-}
-
-// static
void AutofillMetrics::LogUploadOfferedCardOriginMetric(
UploadOfferedCardOriginMetric metric) {
DCHECK_LT(metric, NUM_UPLOAD_OFFERED_CARD_ORIGIN_METRICS);
@@ -1120,227 +1087,42 @@ void AutofillMetrics::LogScanCreditCardCompleted(
}
// static
-void AutofillMetrics::LogLocalCardMigrationDecisionMetric(
- LocalCardMigrationDecisionMetric metric) {
- UMA_HISTOGRAM_ENUMERATION("Autofill.LocalCardMigrationDecision", metric);
-}
-
-// static
-void AutofillMetrics::LogLocalCardMigrationBubbleOfferMetric(
- LocalCardMigrationBubbleOfferMetric metric,
- bool is_reshow) {
- DCHECK_LT(metric, NUM_LOCAL_CARD_MIGRATION_BUBBLE_OFFER_METRICS);
- std::string histogram_name = "Autofill.LocalCardMigrationBubbleOffer.";
- histogram_name += is_reshow ? "Reshows" : "FirstShow";
- base::UmaHistogramEnumeration(histogram_name, metric,
- NUM_LOCAL_CARD_MIGRATION_BUBBLE_OFFER_METRICS);
-}
-
-// static
-void AutofillMetrics::LogLocalCardMigrationBubbleResultMetric(
- LocalCardMigrationBubbleResultMetric metric,
- bool is_reshow) {
- DCHECK_LT(metric, NUM_LOCAL_CARD_MIGRATION_BUBBLE_RESULT_METRICS);
- std::string suffix = is_reshow ? ".Reshows" : ".FirstShow";
- base::UmaHistogramEnumeration(
- "Autofill.LocalCardMigrationBubbleResult" + suffix, metric,
- NUM_LOCAL_CARD_MIGRATION_BUBBLE_RESULT_METRICS);
-}
-
-// static
-void AutofillMetrics::LogLocalCardMigrationDialogOfferMetric(
- LocalCardMigrationDialogOfferMetric metric) {
- DCHECK_LT(metric, NUM_LOCAL_CARD_MIGRATION_DIALOG_OFFER_METRICS);
- std::string histogram_name = "Autofill.LocalCardMigrationDialogOffer";
- base::UmaHistogramEnumeration(histogram_name, metric,
- NUM_LOCAL_CARD_MIGRATION_DIALOG_OFFER_METRICS);
-}
-
-// static
-void AutofillMetrics::LogLocalCardMigrationDialogUserInteractionMetric(
- const base::TimeDelta& duration,
- LocalCardMigrationDialogUserInteractionMetric metric) {
- DCHECK_LT(metric, NUM_LOCAL_CARD_MIGRATION_DIALOG_USER_INTERACTION_METRICS);
- base::UmaHistogramEnumeration(
- "Autofill.LocalCardMigrationDialogUserInteraction", metric,
- NUM_LOCAL_CARD_MIGRATION_DIALOG_USER_INTERACTION_METRICS);
-
- // Do not log duration metrics for
- // LOCAL_CARD_MIGRATION_DIALOG_DELETE_CARD_ICON_CLICKED, as it can happen
- // multiple times in one dialog.
- std::string suffix;
- switch (metric) {
- case LOCAL_CARD_MIGRATION_DIALOG_CLOSED_SAVE_BUTTON_CLICKED:
- suffix = "Accepted";
- break;
- case LOCAL_CARD_MIGRATION_DIALOG_CLOSED_CANCEL_BUTTON_CLICKED:
- suffix = "Denied";
- break;
- case LOCAL_CARD_MIGRATION_DIALOG_CLOSED_VIEW_CARDS_BUTTON_CLICKED:
- case LOCAL_CARD_MIGRATION_DIALOG_CLOSED_DONE_BUTTON_CLICKED:
- suffix = "Closed";
- break;
- default:
- return;
- }
-
- base::UmaHistogramLongTimes(
- "Autofill.LocalCardMigrationDialogActiveDuration." + suffix, duration);
-}
-
-// static
-void AutofillMetrics::LogLocalCardMigrationDialogUserSelectionPercentageMetric(
- int selected,
- int total) {
- UMA_HISTOGRAM_PERCENTAGE(
- "Autofill.LocalCardMigrationDialogUserSelectionPercentage",
- 100 * selected / total);
-}
-
-// static
-void AutofillMetrics::LogLocalCardMigrationPromptMetric(
- LocalCardMigrationOrigin local_card_migration_origin,
- LocalCardMigrationPromptMetric metric) {
- DCHECK_LT(metric, NUM_LOCAL_CARD_MIGRATION_PROMPT_METRICS);
- std::string histogram_name = "Autofill.LocalCardMigrationOrigin.";
- // Switch to different sub-histogram depending on local card migration origin.
- switch (local_card_migration_origin) {
- case LocalCardMigrationOrigin::UseOfLocalCard:
- histogram_name += "UseOfLocalCard";
- break;
- case LocalCardMigrationOrigin::UseOfServerCard:
- histogram_name += "UseOfServerCard";
- break;
- case LocalCardMigrationOrigin::SettingsPage:
- histogram_name += "SettingsPage";
- break;
- default:
- NOTREACHED();
- return;
- }
- base::UmaHistogramEnumeration(histogram_name, metric,
- NUM_LOCAL_CARD_MIGRATION_PROMPT_METRICS);
-}
-
-// static
-void AutofillMetrics::LogOfferNotificationBubbleOfferMetric(
- AutofillOfferData::OfferType offer_type,
- bool is_reshow) {
- std::string histogram_name = "Autofill.OfferNotificationBubbleOffer.";
- // Switch to different sub-histogram depending on offer type being displayed.
- switch (offer_type) {
- case AutofillOfferData::OfferType::GPAY_CARD_LINKED_OFFER:
- histogram_name += "CardLinkedOffer";
- break;
- case AutofillOfferData::OfferType::GPAY_PROMO_CODE_OFFER:
- histogram_name += "GPayPromoCodeOffer";
- break;
- case AutofillOfferData::OfferType::FREE_LISTING_COUPON_OFFER:
- histogram_name += "FreeListingCouponOffer";
- break;
- case AutofillOfferData::OfferType::UNKNOWN:
- NOTREACHED();
- return;
- }
- base::UmaHistogramBoolean(histogram_name, is_reshow);
-}
-
-// static
-void AutofillMetrics::LogOfferNotificationBubbleResultMetric(
- AutofillOfferData::OfferType offer_type,
- OfferNotificationBubbleResultMetric metric,
- bool is_reshow) {
- DCHECK_LE(metric, OfferNotificationBubbleResultMetric::kMaxValue);
- std::string histogram_name = "Autofill.OfferNotificationBubbleResult.";
- // Switch to different sub-histogram depending on offer type being displayed.
- switch (offer_type) {
- case AutofillOfferData::OfferType::GPAY_CARD_LINKED_OFFER:
- histogram_name += "CardLinkedOffer.";
- break;
- case AutofillOfferData::OfferType::GPAY_PROMO_CODE_OFFER:
- histogram_name += "GPayPromoCodeOffer.";
- break;
- case AutofillOfferData::OfferType::FREE_LISTING_COUPON_OFFER:
- histogram_name += "FreeListingCouponOffer.";
- break;
- case AutofillOfferData::OfferType::UNKNOWN:
- NOTREACHED();
- return;
- }
- // Add subhistogram for |is_reshow| decision.
- histogram_name += is_reshow ? "Reshows" : "FirstShow";
- base::UmaHistogramEnumeration(histogram_name, metric);
-}
-
-// static
-void AutofillMetrics::LogOfferNotificationBubblePromoCodeButtonClicked(
- AutofillOfferData::OfferType offer_type) {
- std::string histogram_name =
- "Autofill.OfferNotificationBubblePromoCodeButtonClicked.";
- // Switch to different sub-histogram depending on offer type being displayed.
- // Card-linked offers do not have a promo code button.
- switch (offer_type) {
- case AutofillOfferData::OfferType::GPAY_PROMO_CODE_OFFER:
- histogram_name += "GPayPromoCodeOffer";
+void AutofillMetrics::LogProgressDialogResultMetric(
+ bool is_canceled_by_user,
+ AutofillProgressDialogType autofill_progress_dialog_type) {
+ std::string dialog_type;
+ switch (autofill_progress_dialog_type) {
+ case AutofillProgressDialogType::kAndroidFIDOProgressDialog:
+ dialog_type = "AndroidFIDO";
break;
- case AutofillOfferData::OfferType::FREE_LISTING_COUPON_OFFER:
- histogram_name += "FreeListingCouponOffer";
+ case AutofillProgressDialogType::kVirtualCardUnmaskProgressDialog:
+ dialog_type = "CardUnmask";
break;
- case AutofillOfferData::OfferType::GPAY_CARD_LINKED_OFFER:
- case AutofillOfferData::OfferType::UNKNOWN:
+ case AutofillProgressDialogType::kUnspecified:
NOTREACHED();
return;
}
- base::UmaHistogramBoolean(histogram_name, true);
+ base::UmaHistogramBoolean(
+ "Autofill.ProgressDialog." + dialog_type + ".Result",
+ is_canceled_by_user);
}
-// static
-void AutofillMetrics::LogOfferNotificationBubbleSuppressed(
- AutofillOfferData::OfferType offer_type) {
- std::string histogram_name = "Autofill.OfferNotificationBubbleSuppressed.";
- // Switch to different sub-histogram depending on offer type being suppressed.
- // Card-linked offers will not be suppressed.
- switch (offer_type) {
- case AutofillOfferData::OfferType::GPAY_PROMO_CODE_OFFER:
- histogram_name += "GPayPromoCodeOffer";
+void AutofillMetrics::LogProgressDialogShown(
+ AutofillProgressDialogType autofill_progress_dialog_type) {
+ std::string dialog_type;
+ switch (autofill_progress_dialog_type) {
+ case AutofillProgressDialogType::kAndroidFIDOProgressDialog:
+ dialog_type = "AndroidFIDO";
break;
- case AutofillOfferData::OfferType::FREE_LISTING_COUPON_OFFER:
- histogram_name += "FreeListingCouponOffer";
+ case AutofillProgressDialogType::kVirtualCardUnmaskProgressDialog:
+ dialog_type = "CardUnmask";
break;
- case AutofillOfferData::OfferType::GPAY_CARD_LINKED_OFFER:
- case AutofillOfferData::OfferType::UNKNOWN:
+ case AutofillProgressDialogType::kUnspecified:
NOTREACHED();
return;
}
- base::UmaHistogramBoolean(histogram_name, true);
-}
-
-// static
-void AutofillMetrics::LogOfferNotificationInfoBarDeepLinkClicked() {
- base::RecordAction(base::UserMetricsAction(
- "Autofill_OfferNotificationInfoBar_DeepLinkClicked"));
-}
-
-// static
-void AutofillMetrics::LogOfferNotificationInfoBarResultMetric(
- OfferNotificationInfoBarResultMetric metric) {
- DCHECK_LE(metric, OfferNotificationInfoBarResultMetric::kMaxValue);
- base::UmaHistogramEnumeration(
- "Autofill.OfferNotificationInfoBarResult.CardLinkedOffer", metric);
-}
-
-void AutofillMetrics::LogOfferNotificationInfoBarShown() {
- base::UmaHistogramBoolean(
- "Autofill.OfferNotificationInfoBarOffer.CardLinkedOffer", true);
-}
-
-void AutofillMetrics::LogProgressDialogResultMetric(bool is_canceled_by_user) {
- base::UmaHistogramBoolean("Autofill.ProgressDialog.CardUnmask.Result",
- is_canceled_by_user);
-}
-
-void AutofillMetrics::LogProgressDialogShown() {
- base::UmaHistogramBoolean("Autofill.ProgressDialog.CardUnmask.Shown", true);
+ base::UmaHistogramBoolean("Autofill.ProgressDialog." + dialog_type + ".Shown",
+ true);
}
// static
@@ -2236,11 +2018,6 @@ void AutofillMetrics::LogStoredCreditCardMetrics(
}
// static
-void AutofillMetrics::LogSyncedOfferDataBeingValid(bool valid) {
- base::UmaHistogramBoolean("Autofill.Offer.SyncedOfferDataBeingValid", valid);
-}
-
-// static
void AutofillMetrics::LogNumberOfCreditCardsSuppressedForDisuse(
size_t num_cards) {
UMA_HISTOGRAM_COUNTS_1000("Autofill.CreditCardsSuppressedForDisuse",
@@ -3102,6 +2879,33 @@ void AutofillMetrics::FormInteractionsUkmLogger::LogFormSubmitted(
builder.Record(ukm_recorder_);
}
+void AutofillMetrics::FormInteractionsUkmLogger::LogKeyMetrics(
+ const DenseSet<FormType>& form_types,
+ bool data_to_fill_available,
+ bool suggestions_shown,
+ bool edited_autofilled_field,
+ bool suggestion_filled,
+ autofill_assistant::AutofillAssistantIntent intent) {
+ if (!CanLog())
+ return;
+
+ ukm::builders::Autofill_KeyMetrics builder(source_id_);
+ builder.SetFillingReadiness(data_to_fill_available)
+ .SetFillingAssistance(suggestion_filled)
+ .SetFormTypes(FormTypesToBitVector(form_types));
+
+ if (intent != autofill_assistant::AutofillAssistantIntent::UNDEFINED_INTENT)
+ builder.SetAutofillAssistantIntent(static_cast<int64_t>(intent));
+
+ if (suggestions_shown)
+ builder.SetFillingAcceptance(suggestion_filled);
+
+ if (suggestion_filled)
+ builder.SetFillingCorrectness(!edited_autofilled_field);
+
+ builder.Record(ukm_recorder_);
+}
+
void AutofillMetrics::FormInteractionsUkmLogger::LogFormEvent(
FormEvent form_event,
const DenseSet<FormType>& form_types,
@@ -3328,16 +3132,6 @@ void AutofillMetrics::LogProfileUpdateWithRemovedPhoneNumberImportDecision(
void AutofillMetrics::LogProfileUpdateAffectedType(
ServerFieldType affected_type,
AutofillClient::SaveAddressProfileOfferUserDecision decision) {
- // TODO(crbug.com/1253798): Remove the special-case metric in favor of more
- // general one once the majority of clients contribute to the more general
- // one.
- if (decision ==
- AutofillClient::SaveAddressProfileOfferUserDecision::kAccepted) {
- base::UmaHistogramEnumeration(
- "Autofill.ProfileImport.UpdateProfileAffectedType",
- ConvertSettingsVisibleFieldTypeForMetrics(affected_type));
- }
-
// Record the decision-specific metric.
base::UmaHistogramEnumeration(
base::StrCat({"Autofill.ProfileImport.UpdateProfileAffectedType",
@@ -3372,25 +3166,16 @@ void AutofillMetrics::LogUpdateProfileNumberOfEditedFields(
void AutofillMetrics::LogUpdateProfileNumberOfAffectedFields(
int number_of_edited_fields,
AutofillClient::SaveAddressProfileOfferUserDecision decision) {
- // TODO(crbug.com/1253798): Remove the special-case metric in favor of more
- // general one once the majority of clients contribute to the more general
- // one.
- if (decision ==
- AutofillClient::SaveAddressProfileOfferUserDecision::kAccepted) {
- base::UmaHistogramExactLinear(
- "Autofill.ProfileImport.UpdateProfileNumberOfAffectedFields",
- number_of_edited_fields, /*exclusive_max=*/15);
- }
-
// Record the decision-specific metric.
base::UmaHistogramExactLinear(
- base::StrCat({"Autofill.ProfileImport.UpdateProfileAffectedType",
- GetSaveAndUpdatePromptDecisionMetricsSuffix(decision)}),
+ base::StrCat(
+ {"Autofill.ProfileImport.UpdateProfileNumberOfAffectedFields",
+ GetSaveAndUpdatePromptDecisionMetricsSuffix(decision)}),
number_of_edited_fields, /*exclusive_max=*/15);
// But also collect an histogram for any decision.
base::UmaHistogramExactLinear(
- "Autofill.ProfileImport.UpdateProfileAffectedType.Any",
+ "Autofill.ProfileImport.UpdateProfileNumberOfAffectedFields.Any",
number_of_edited_fields, /*exclusive_max=*/15);
}
@@ -3418,6 +3203,19 @@ void AutofillMetrics::LogPhoneNumberImportParsingResult(
(with_variation_country_code << 1) | with_app_locale));
}
+// static
+void AutofillMetrics::LogPhoneNumberGrammarMatched(int grammar_id,
+ bool suffix_matched,
+ int num_grammars) {
+ DCHECK(0 <= grammar_id && grammar_id < num_grammars);
+ int metric = 2 * grammar_id + suffix_matched;
+ int max_metric = 2 * (num_grammars - 1) + 1;
+ // Add 1 everywhere, because UmaHistogramExactLinear is 1-based.
+ base::UmaHistogramExactLinear(
+ "Autofill.FieldPrediction.PhoneNumberGrammarUsage", metric + 1,
+ /*exclusive_max=*/max_metric + 2);
+}
+
void AutofillMetrics::LogVerificationStatusOfNameTokensOnProfileUsage(
const AutofillProfile& profile) {
constexpr base::StringPiece base_histogram_name =
@@ -3556,10 +3354,48 @@ void AutofillMetrics::LogOtpInputDialogNewOtpRequested() {
void AutofillMetrics::
LogIsValueNotAutofilledOverExistingValueSameAsSubmittedValue(bool is_same) {
base::UmaHistogramBoolean(
- "Autofill.IsValueNotAutofilledOverExistingValueSameAsSubmittedValue",
+ "Autofill.IsValueNotAutofilledOverExistingValueSameAsSubmittedValue2",
is_same);
}
+// static
+void AutofillMetrics::LogAutocompletePredictionCollisionState(
+ PredictionState prediction_state,
+ AutocompleteState autocomplete_state) {
+ if (prediction_state == PredictionState::kNone &&
+ autocomplete_state == AutocompleteState::kNone) {
+ return;
+ }
+ // The buckets are calculated by using the least significant two bits to
+ // encode the `autocomplete_state`, and the next two bits to encode the
+ // `prediction_state`.
+ int bucket = (static_cast<int>(prediction_state) << 2) |
+ static_cast<int>(autocomplete_state);
+ // Without (kNone, kNone), 4*4 - 1 = 15 possible pairs remain. Log the bucket
+ // 0-based, in order to interpret the metric as an enum.
+ DCHECK(1 <= bucket && bucket <= 15);
+ UMA_HISTOGRAM_ENUMERATION("Autofill.Autocomplete.PredictionCollisionState",
+ bucket - 1, 15);
+}
+
+// static
+void AutofillMetrics::LogAutocompletePredictionCollisionTypes(
+ ServerFieldType server_type,
+ ServerFieldType heuristic_type) {
+ const std::string kHistogramName =
+ "Autofill.Autocomplete.PredictionCollisionType.";
+ if (server_type != NO_SERVER_DATA) {
+ base::UmaHistogramEnumeration(kHistogramName + "Server", server_type,
+ ServerFieldType::MAX_VALID_FIELD_TYPE);
+ }
+ base::UmaHistogramEnumeration(kHistogramName + "Heuristics", heuristic_type,
+ ServerFieldType::MAX_VALID_FIELD_TYPE);
+ base::UmaHistogramEnumeration(
+ kHistogramName + "ServerOrHeuristics",
+ server_type != NO_SERVER_DATA ? server_type : heuristic_type,
+ ServerFieldType::MAX_VALID_FIELD_TYPE);
+}
+
const std::string PaymentsRpcResultToMetricsSuffix(
AutofillClient::PaymentsRpcResult result) {
std::string result_suffix;
diff --git a/chromium/components/autofill/core/browser/metrics/autofill_metrics.h b/chromium/components/autofill/core/browser/metrics/autofill_metrics.h
index 3259088da19..891ea1e9e1b 100644
--- a/chromium/components/autofill/core/browser/metrics/autofill_metrics.h
+++ b/chromium/components/autofill/core/browser/metrics/autofill_metrics.h
@@ -18,7 +18,7 @@
#include "base/time/time.h"
#include "components/autofill/core/browser/autofill_client.h"
#include "components/autofill/core/browser/autofill_profile_import_process.h"
-#include "components/autofill/core/browser/data_model/autofill_offer_data.h"
+#include "components/autofill/core/browser/autofill_progress_dialog_type.h"
#include "components/autofill/core/browser/data_model/autofill_profile.h"
#include "components/autofill/core/browser/field_types.h"
#include "components/autofill/core/browser/form_types.h"
@@ -30,6 +30,7 @@
#include "components/autofill/core/common/mojom/autofill_types.mojom-forward.h"
#include "components/autofill/core/common/signatures.h"
#include "components/autofill/core/common/unique_ids.h"
+#include "components/autofill_assistant/core/public/autofill_assistant_intent.h"
#include "components/security_state/core/security_state.h"
#include "services/metrics/public/cpp/ukm_recorder.h"
#include "services/metrics/public/cpp/ukm_source_id.h"
@@ -43,7 +44,6 @@ class Autofill_CreditCardFill;
namespace autofill {
class AutofillField;
-class AutofillOfferData;
class CreditCard;
class FormEventLoggerBase;
@@ -293,36 +293,6 @@ class AutofillMetrics {
NUM_SAVE_CARD_PROMPT_RESULT_METRICS,
};
- // Metrics to track event when the offer notification bubble is closed.
- enum class OfferNotificationBubbleResultMetric {
- // These values are persisted to logs. Entries should not be renumbered and
- // numeric values should never be reused.
-
- // The user explicitly acknowledged the bubble by clicking the ok button.
- OFFER_NOTIFICATION_BUBBLE_ACKNOWLEDGED = 0,
- // The user explicitly closed the prompt with the close button or ESC.
- OFFER_NOTIFICATION_BUBBLE_CLOSED = 1,
- // The user did not interact with the prompt.
- OFFER_NOTIFICATION_BUBBLE_NOT_INTERACTED = 2,
- // The prompt lost focus and was deactivated.
- OFFER_NOTIFICATION_BUBBLE_LOST_FOCUS = 3,
- kMaxValue = OFFER_NOTIFICATION_BUBBLE_LOST_FOCUS,
- };
-
- // Metrics to track event when the offer notification infobar is closed.
- enum class OfferNotificationInfoBarResultMetric {
- // These values are persisted to logs. Entries should not be renumbered and
- // numeric values should never be reused.
-
- // User acknowledged the infobar by clicking the ok button.
- OFFER_NOTIFICATION_INFOBAR_ACKNOWLEDGED = 0,
- // User explicitly closed the infobar with the close button.
- OFFER_NOTIFICATION_INFOBAR_CLOSED = 1,
- // InfoBar was shown but user did not interact with the it.
- OFFER_NOTIFICATION_INFOBAR_IGNORED = 2,
- kMaxValue = OFFER_NOTIFICATION_INFOBAR_IGNORED,
- };
-
// Metrics to track events in CardUnmaskAuthenticationSelectionDialog.
enum class CardUnmaskAuthenticationSelectionDialogResultMetric {
// These values are persisted to logs. Entries should not be renumbered and
@@ -545,116 +515,6 @@ class AutofillMetrics {
NUM_SCAN_CREDIT_CARD_PROMPT_METRICS,
};
- // Metrics to record the decision on whether to offer local card migration.
- enum class LocalCardMigrationDecisionMetric {
- // All the required conditions are satisfied and main prompt is shown.
- OFFERED = 0,
- // Migration not offered because user uses new card.
- NOT_OFFERED_USE_NEW_CARD = 1,
- // Migration not offered because failed migration prerequisites.
- NOT_OFFERED_FAILED_PREREQUISITES = 2,
- // The Autofill StrikeDatabase decided not to allow offering migration
- // because max strike count was reached.
- NOT_OFFERED_REACHED_MAX_STRIKE_COUNT = 3,
- // Migration not offered because no migratable cards.
- NOT_OFFERED_NO_MIGRATABLE_CARDS = 4,
- // Met the migration requirements but the request to Payments for upload
- // details failed.
- NOT_OFFERED_GET_UPLOAD_DETAILS_FAILED = 5,
- // Abandoned the migration because no supported local cards were left after
- // filtering out unsupported cards.
- NOT_OFFERED_NO_SUPPORTED_CARDS = 6,
- // User used a local card and they only have a single migratable local card
- // on file, we will offer Upstream instead.
- NOT_OFFERED_SINGLE_LOCAL_CARD = 7,
- // User used an unsupported local card, we will abort the migration.
- NOT_OFFERED_USE_UNSUPPORTED_LOCAL_CARD = 8,
- // Legal message was invalid, we will abort the migration.
- NOT_OFFERED_INVALID_LEGAL_MESSAGE = 9,
- kMaxValue = NOT_OFFERED_INVALID_LEGAL_MESSAGE,
- };
-
- // Metrics to track events when local credit card migration is offered.
- enum LocalCardMigrationBubbleOfferMetric {
- // The bubble is requested due to a credit card being used or
- // local card migration icon in the omnibox being clicked.
- LOCAL_CARD_MIGRATION_BUBBLE_REQUESTED = 0,
- // The bubble is actually shown to the user.
- LOCAL_CARD_MIGRATION_BUBBLE_SHOWN = 1,
- NUM_LOCAL_CARD_MIGRATION_BUBBLE_OFFER_METRICS,
- };
-
- // Metrics to track user action result of the bubble when the bubble is
- // closed.
- enum LocalCardMigrationBubbleResultMetric {
- // The user explicitly accepted the offer.
- LOCAL_CARD_MIGRATION_BUBBLE_ACCEPTED = 0,
- // The user explicitly closed the bubble with the close button or ESC.
- LOCAL_CARD_MIGRATION_BUBBLE_CLOSED = 1,
- // The user did not interact with the bubble.
- LOCAL_CARD_MIGRATION_BUBBLE_NOT_INTERACTED = 2,
- // The bubble lost its focus and was deactivated.
- LOCAL_CARD_MIGRATION_BUBBLE_LOST_FOCUS = 3,
- // The reason why the prompt is closed is not clear. Possible reason is the
- // logging function is invoked before the closed reason is correctly set.
- LOCAL_CARD_MIGRATION_BUBBLE_RESULT_UNKNOWN = 4,
- NUM_LOCAL_CARD_MIGRATION_BUBBLE_RESULT_METRICS,
- };
-
- // Metrics to track events when local card migration dialog is offered.
- enum LocalCardMigrationDialogOfferMetric {
- // The dialog is shown to the user.
- LOCAL_CARD_MIGRATION_DIALOG_SHOWN = 0,
- // The dialog is not shown due to legal message being invalid.
- LOCAL_CARD_MIGRATION_DIALOG_NOT_SHOWN_INVALID_LEGAL_MESSAGE = 1,
- // The dialog is shown when migration feedback is available.
- LOCAL_CARD_MIGRATION_DIALOG_FEEDBACK_SHOWN = 2,
- // The dialog is shown when migration fails due to server error.
- LOCAL_CARD_MIGRATION_DIALOG_FEEDBACK_SERVER_ERROR_SHOWN = 3,
- NUM_LOCAL_CARD_MIGRATION_DIALOG_OFFER_METRICS,
- };
-
- // Metrics to track user interactions with the dialog.
- enum LocalCardMigrationDialogUserInteractionMetric {
- // The user explicitly accepts the offer by clicking the save button.
- LOCAL_CARD_MIGRATION_DIALOG_CLOSED_SAVE_BUTTON_CLICKED = 0,
- // The user explicitly denies the offer by clicking the cancel button.
- LOCAL_CARD_MIGRATION_DIALOG_CLOSED_CANCEL_BUTTON_CLICKED = 1,
- // The user clicks the legal message.
- LOCAL_CARD_MIGRATION_DIALOG_LEGAL_MESSAGE_CLICKED = 2,
- // The user clicks the view card button after successfully migrated cards.
- LOCAL_CARD_MIGRATION_DIALOG_CLOSED_VIEW_CARDS_BUTTON_CLICKED = 3,
- // The user clicks the done button to close dialog after migration.
- LOCAL_CARD_MIGRATION_DIALOG_CLOSED_DONE_BUTTON_CLICKED = 4,
- // The user clicks the trash icon to delete invalid card.
- LOCAL_CARD_MIGRATION_DIALOG_DELETE_CARD_ICON_CLICKED = 5,
- NUM_LOCAL_CARD_MIGRATION_DIALOG_USER_INTERACTION_METRICS,
- };
-
- // These metrics are logged for each local card migration origin. These are
- // used to derive the conversion rate for each triggering source.
- enum LocalCardMigrationPromptMetric {
- // The intermediate bubble is shown to the user.
- INTERMEDIATE_BUBBLE_SHOWN = 0,
- // The intermediate bubble is accepted by the user.
- INTERMEDIATE_BUBBLE_ACCEPTED = 1,
- // The main dialog is shown to the user.
- MAIN_DIALOG_SHOWN = 2,
- // The main dialog is accepted by the user.
- MAIN_DIALOG_ACCEPTED = 3,
- NUM_LOCAL_CARD_MIGRATION_PROMPT_METRICS,
- };
-
- // Local card migration origin denotes from where the migration is triggered.
- enum LocalCardMigrationOrigin {
- // Trigger when user submitted a form using local card.
- UseOfLocalCard,
- // Trigger when user submitted a form using server card.
- UseOfServerCard,
- // Trigger from settings page.
- SettingsPage,
- };
-
// Each of these metrics is logged only for potentially autofillable forms,
// i.e. forms with at least three fields, etc.
// These are used to derive certain "user happiness" metrics. For example, we
@@ -1290,6 +1150,12 @@ class AutofillMetrics {
const base::TimeTicks& form_parsed_timestamp,
FormSignature form_signature,
const FormInteractionCounts& form_interaction_counts);
+ void LogKeyMetrics(const DenseSet<FormType>& form_types,
+ bool data_to_fill_available,
+ bool suggestions_shown,
+ bool edited_autofilled_field,
+ bool suggestion_filled,
+ autofill_assistant::AutofillAssistantIntent intent);
void LogFormEvent(FormEvent form_event,
const DenseSet<FormType>& form_types,
const base::TimeTicks& form_parsed_timestamp);
@@ -1335,6 +1201,22 @@ class AutofillMetrics {
const raw_ptr<FormInteractionsUkmLogger> logger_;
};
+ enum class PredictionState {
+ kNone = 0,
+ kServer = 1,
+ kHeuristics = 2,
+ kBoth = 3,
+ kMaxValue = kBoth
+ };
+
+ enum class AutocompleteState {
+ kNone = 0,
+ kValid = 1,
+ kGarbage = 2,
+ kOff = 3,
+ kMaxValue = kOff
+ };
+
AutofillMetrics() = delete;
AutofillMetrics(const AutofillMetrics&) = delete;
AutofillMetrics& operator=(const AutofillMetrics&) = delete;
@@ -1357,11 +1239,6 @@ class AutofillMetrics {
static void LogCreditCardSaveNotOfferedDueToMaxStrikesMetric(
SaveTypeMetric metric);
- // When local card migration is not offered due to max strike limit reached,
- // logs the occurrence.
- static void LogLocalCardMigrationNotOfferedDueToMaxStrikesMetric(
- SaveTypeMetric metric);
-
// When credit card upload is offered, logs whether the card being offered is
// already a local card on the device or not.
static void LogUploadOfferedCardOriginMetric(
@@ -1417,42 +1294,11 @@ class AutofillMetrics {
static void LogCreditCardUploadFeedbackMetric(
CreditCardUploadFeedbackMetric metric);
static void LogScanCreditCardPromptMetric(ScanCreditCardPromptMetric metric);
- static void LogLocalCardMigrationDecisionMetric(
- LocalCardMigrationDecisionMetric metric);
- static void LogLocalCardMigrationBubbleOfferMetric(
- LocalCardMigrationBubbleOfferMetric metric,
- bool is_reshow);
- static void LogLocalCardMigrationBubbleResultMetric(
- LocalCardMigrationBubbleResultMetric metric,
- bool is_reshow);
- static void LogLocalCardMigrationDialogOfferMetric(
- LocalCardMigrationDialogOfferMetric metric);
- static void LogLocalCardMigrationDialogUserInteractionMetric(
- const base::TimeDelta& duration,
- LocalCardMigrationDialogUserInteractionMetric metric);
- static void LogLocalCardMigrationDialogUserSelectionPercentageMetric(
- int selected,
- int total);
- static void LogLocalCardMigrationPromptMetric(
- LocalCardMigrationOrigin local_card_migration_origin,
- LocalCardMigrationPromptMetric metric);
- static void LogOfferNotificationBubbleOfferMetric(
- AutofillOfferData::OfferType offer_type,
- bool is_reshow);
- static void LogOfferNotificationBubbleResultMetric(
- AutofillOfferData::OfferType offer_type,
- OfferNotificationBubbleResultMetric metric,
- bool is_reshow);
- static void LogOfferNotificationBubblePromoCodeButtonClicked(
- AutofillOfferData::OfferType offer_type);
- static void LogOfferNotificationBubbleSuppressed(
- AutofillOfferData::OfferType offer_type);
- static void LogOfferNotificationInfoBarDeepLinkClicked();
- static void LogOfferNotificationInfoBarResultMetric(
- OfferNotificationInfoBarResultMetric metric);
- static void LogOfferNotificationInfoBarShown();
- static void LogProgressDialogResultMetric(bool is_canceled_by_user);
- static void LogProgressDialogShown();
+ static void LogProgressDialogResultMetric(
+ bool is_canceled_by_user,
+ AutofillProgressDialogType autofill_progress_dialog_type);
+ static void LogProgressDialogShown(
+ AutofillProgressDialogType autofill_progress_dialog_type);
static void LogVirtualCardManualFallbackBubbleShown(bool is_reshow);
static void LogVirtualCardManualFallbackBubbleResultMetric(
VirtualCardManualFallbackBubbleResultMetric metric,
@@ -1708,9 +1554,6 @@ class AutofillMetrics {
size_t server_card_count_with_card_art_image,
base::TimeDelta disused_data_threshold);
- // Logs whether the synced autofill offer data is valid.
- static void LogSyncedOfferDataBeingValid(bool invalid);
-
// Log the number of autofill credit card suggestions suppressed because they
// have not been used for a long time and are expired. Note that these cards
// are only suppressed when the user has not typed any data into the field
@@ -2051,6 +1894,15 @@ class AutofillMetrics {
bool with_variation_country_code,
bool with_app_locale);
+ // Logs that local heuristics matched phone number fields using `grammar_id`.
+ // `suffix_matched` indicates if the special case handling for phone number
+ // suffixes was triggered.
+ // `num_grammars` indicates the total number of phone number grammars. It is
+ // not logged and used for validation.
+ static void LogPhoneNumberGrammarMatched(int grammar_id,
+ bool suffix_matched,
+ int num_grammars);
+
// Logs when the virtual card metadata for one card have been updated.
static void LogVirtualCardMetadataSynced(bool existing_card);
@@ -2114,6 +1966,17 @@ class AutofillMetrics {
static void LogIsValueNotAutofilledOverExistingValueSameAsSubmittedValue(
bool is_same);
+ // Logs a field's (PredictionState, AutocompleteState) pair on form submit.
+ static void LogAutocompletePredictionCollisionState(
+ PredictionState prediction_state,
+ AutocompleteState autocomplete_state);
+
+ // Logs a field's server and heuristic type on form submit. This is only used
+ // for fields with autocomplete=garbage.
+ static void LogAutocompletePredictionCollisionTypes(
+ ServerFieldType server_type,
+ ServerFieldType heuristic_types);
+
private:
static void Log(AutocompleteEvent event);
};
diff --git a/chromium/components/autofill/core/browser/metrics/autofill_metrics_test_base.cc b/chromium/components/autofill/core/browser/metrics/autofill_metrics_test_base.cc
index 158a195d005..1bf6bad7c66 100644
--- a/chromium/components/autofill/core/browser/metrics/autofill_metrics_test_base.cc
+++ b/chromium/components/autofill/core/browser/metrics/autofill_metrics_test_base.cc
@@ -145,10 +145,10 @@ void AutofillMetricsBaseTest::OnDidGetRealPan(
AutofillClient::PaymentsRpcResult result,
const std::string& real_pan,
bool is_virtual_card) {
- payments::FullCardRequest* full_card_request =
- autofill_manager()
- .credit_card_access_manager_->GetOrCreateCVCAuthenticator()
- ->full_card_request_.get();
+ payments::FullCardRequest* full_card_request = autofill_manager()
+ .client()
+ ->GetCVCAuthenticator()
+ ->full_card_request_.get();
DCHECK(full_card_request);
// Fake user response.
@@ -164,10 +164,10 @@ void AutofillMetricsBaseTest::OnDidGetRealPan(
}
void AutofillMetricsBaseTest::OnDidGetRealPanWithNonHttpOkResponse() {
- payments::FullCardRequest* full_card_request =
- autofill_manager()
- .credit_card_access_manager_->GetOrCreateCVCAuthenticator()
- ->full_card_request_.get();
+ payments::FullCardRequest* full_card_request = autofill_manager()
+ .client()
+ ->GetCVCAuthenticator()
+ ->full_card_request_.get();
DCHECK(full_card_request);
// Fake user response.
diff --git a/chromium/components/autofill/core/browser/metrics/autofill_metrics_test_base.h b/chromium/components/autofill/core/browser/metrics/autofill_metrics_test_base.h
index c869713d05d..82a00417be0 100644
--- a/chromium/components/autofill/core/browser/metrics/autofill_metrics_test_base.h
+++ b/chromium/components/autofill/core/browser/metrics/autofill_metrics_test_base.h
@@ -86,6 +86,28 @@ class AutofillMetricsBaseTest : public testing::Test {
void ResetDriverToCommitMetrics() { autofill_driver_.reset(); }
+ void ChangeTextField(const FormData& form,
+ const FormFieldData& field,
+ base::TimeTicks timestamp = {}) {
+ autofill_manager().OnTextFieldDidChange(form, field, gfx::RectF(),
+ timestamp);
+ }
+
+ void FillAutofillFormData(const FormData& form,
+ base::TimeTicks timestamp = {}) {
+ autofill_manager().OnDidFillAutofillFormData(form, timestamp);
+ }
+
+ void SeeForm(const FormData& form) {
+ autofill_manager().OnFormsSeen({form}, {});
+ }
+
+ void SubmitForm(const FormData& form) {
+ autofill_manager().OnFormSubmitted(
+ form, /*known_success=*/false,
+ mojom::SubmissionSource::FORM_SUBMISSION);
+ }
+
// Mocks a credit card fetching was completed. This mock starts from the
// BrowserAutofillManager. Use these if your test does not depends on
// OnDidGetRealPan but just need to mock the card fetching result (so that
diff --git a/chromium/components/autofill/core/browser/metrics/autofill_metrics_unittest.cc b/chromium/components/autofill/core/browser/metrics/autofill_metrics_unittest.cc
index 12031ebda35..dc84f884673 100644
--- a/chromium/components/autofill/core/browser/metrics/autofill_metrics_unittest.cc
+++ b/chromium/components/autofill/core/browser/metrics/autofill_metrics_unittest.cc
@@ -35,6 +35,7 @@
#include "components/autofill/core/browser/autofill_test_utils.h"
#include "components/autofill/core/browser/data_model/credit_card.h"
#include "components/autofill/core/browser/field_types.h"
+#include "components/autofill/core/browser/form_structure_test_api.h"
#include "components/autofill/core/browser/metrics/autofill_metrics_test_base.h"
#include "components/autofill/core/browser/metrics/form_events/address_form_event_logger.h"
#include "components/autofill/core/browser/metrics/form_events/credit_card_form_event_logger.h"
@@ -50,7 +51,6 @@
#include "components/autofill/core/browser/test_autofill_tick_clock.h"
#include "components/autofill/core/browser/test_browser_autofill_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"
#include "components/autofill/core/browser/ui/popup_item_ids.h"
#include "components/autofill/core/browser/ui/popup_types.h"
@@ -118,6 +118,7 @@ using UkmFieldFillStatusType = ukm::builders::Autofill_FieldFillStatus;
using UkmFormEventType = ukm::builders::Autofill_FormEvent;
using UkmEditedAutofilledFieldAtSubmission =
ukm::builders::Autofill_EditedAutofilledFieldAtSubmission;
+using UkmAutofillKeyMetricsType = ukm::builders::Autofill_KeyMetrics;
using ExpectedUkmMetricsRecord = std::vector<std::pair<const char*, int64_t>>;
using ExpectedUkmMetrics = std::vector<ExpectedUkmMetricsRecord>;
@@ -409,14 +410,12 @@ TEST_F(AutofillMetricsTest, NumberOfAutofilledFieldsAtSubmission) {
autofill_manager().AddSeenForm(form, heuristic_types, server_types);
// Simulate user changing the second field of the form.
- autofill_manager().OnTextFieldDidChange(form, form.fields[1], gfx::RectF(),
- TimeTicks());
+ ChangeTextField(form, form.fields[1]);
form.fields.at(1).is_autofilled = false;
// Simulate form submission.
base::HistogramTester histogram_tester;
- autofill_manager().OnFormSubmitted(form, /*known_success=*/false,
- SubmissionSource::FORM_SUBMISSION);
+ SubmitForm(form);
// Test that the correct bucket for the number of filled fields received a
// count while the others remain at zero counts.
@@ -489,14 +488,12 @@ TEST_F(AutofillMetricsTest,
autofill_manager().AddSeenForm(form, heuristic_types, server_types);
// Simulate user changing the second and forth field of the form.
- autofill_manager().OnTextFieldDidChange(form, form.fields[1], gfx::RectF(),
- TimeTicks());
+ ChangeTextField(form, form.fields[1]);
form.fields.at(1).is_autofilled = false;
// Simulate form submission.
base::HistogramTester histogram_tester;
- autofill_manager().OnFormSubmitted(form, /*known_success=*/false,
- SubmissionSource::FORM_SUBMISSION);
+ SubmitForm(form);
// Test that the correct bucket for the number of filled fields with an
// unrecognized autocomplete attriute received a count while the others remain
@@ -525,326 +522,131 @@ TEST_F(AutofillMetricsTest,
}
}
-// Test that we log the perfect filling metric correctly for an address form in
-// which every field is autofilled.
-TEST_F(AutofillMetricsTest, PerfectFillingForAddresses_AllAutofillFilled) {
- // Set up our form data with two autofilled fields.
- FormData form =
- test::GetFormData({.description_for_logging = "PerectFilling",
- .fields =
- {
- {.label = u"Name",
- .name = u"name",
- .value = u"Elvis Aaron Presley",
- .is_autofilled = true},
- {.label = u"Email",
- .name = u"email",
- .value = u"buddy@gmail.com",
- .is_autofilled = true},
- {.label = u"City",
- .name = u"city",
- .value = u"Munich",
- .is_autofilled = true},
- },
- .unique_renderer_id = test::MakeFormRendererId(),
- .main_frame_origin = url::Origin::Create(
- autofill_client_->form_origin())});
-
- std::vector<ServerFieldType> heuristic_types = {NAME_FULL, EMAIL_ADDRESS,
- ADDRESS_HOME_CITY};
- std::vector<ServerFieldType> server_types = {NAME_FULL, EMAIL_ADDRESS,
- ADDRESS_HOME_CITY};
-
- // Simulate having seen this form on page load.
- autofill_manager().AddSeenForm(form, heuristic_types, server_types);
-
- // Simulate form submission.
- base::HistogramTester histogram_tester;
- autofill_manager().OnFormSubmitted(form, /*known_success=*/false,
- SubmissionSource::FORM_SUBMISSION);
-
- // Here, it is expected that there is a count for perfect filling for
- // addresses.
- EXPECT_THAT(
- histogram_tester.GetAllSamples("Autofill.PerfectFilling.Addresses"),
- BucketsAre(Bucket(false, 0), Bucket(true, 1)));
- EXPECT_THAT(
- histogram_tester.GetAllSamples("Autofill.PerfectFilling.CreditCards"),
- BucketsAre(Bucket(false, 0), Bucket(true, 0)));
-}
-
-// Test that we log the perfect filling metric correctly for an address form in
-// which every field is autofilled or empty.
-TEST_F(AutofillMetricsTest,
- PerfectFillingForAddresses_AllAutofillFilledOrEmpty) {
- // Set up our form data with two autofilled fields.
- FormData form =
- test::GetFormData({.description_for_logging = "PerectFilling",
- .fields =
- {
- {.label = u"Name",
- .name = u"name",
- .value = u"Elvis Aaron Presley",
- .is_autofilled = true},
- {.label = u"Email",
- .name = u"email",
- .value = u"buddy@gmail.com",
- .is_autofilled = true},
- {.label = u"City",
- .name = u"city",
- .value = u"",
- .is_autofilled = false},
- },
- .unique_renderer_id = test::MakeFormRendererId(),
- .main_frame_origin = url::Origin::Create(
- autofill_client_->form_origin())});
-
- std::vector<ServerFieldType> heuristic_types = {NAME_FULL, EMAIL_ADDRESS,
- ADDRESS_HOME_CITY};
- std::vector<ServerFieldType> server_types = {NAME_FULL, EMAIL_ADDRESS,
- ADDRESS_HOME_CITY};
-
- // Simulate having seen this form on page load.
- autofill_manager().AddSeenForm(form, heuristic_types, server_types);
-
- // Simulate form submission.
- base::HistogramTester histogram_tester;
- autofill_manager().OnFormSubmitted(form, /*known_success=*/false,
- SubmissionSource::FORM_SUBMISSION);
-
- // Here, it is expected that there is a count for perfect filling for
- // addresses.
- EXPECT_THAT(
- histogram_tester.GetAllSamples("Autofill.PerfectFilling.Addresses"),
- BucketsAre(Bucket(false, 0), Bucket(true, 1)));
- EXPECT_THAT(
- histogram_tester.GetAllSamples("Autofill.PerfectFilling.CreditCards"),
- BucketsAre(Bucket(false, 0), Bucket(true, 0)));
-}
-
-// Test that we log the perfect filling metric correctly for an address form in
-// which a non-empty field is not autofilled.
-TEST_F(AutofillMetricsTest, PerfectFillingForAddresses_NotAllAutofilled) {
- // Set up our form data with two autofilled fields.
- FormData form =
- test::GetFormData({.description_for_logging = "PerectFilling",
- .fields =
- {
- {.label = u"Name",
- .name = u"name",
- .value = u"Elvis Aaron Presley",
- .is_autofilled = true},
- {.label = u"Email",
- .name = u"email",
- .value = u"buddy@gmail.com",
- .is_autofilled = true},
- {.label = u"City",
- .name = u"city",
- .value = u"Munich",
- .is_autofilled = false},
- },
- .unique_renderer_id = test::MakeFormRendererId(),
- .main_frame_origin = url::Origin::Create(
- autofill_client_->form_origin())});
-
- std::vector<ServerFieldType> heuristic_types = {NAME_FULL, EMAIL_ADDRESS,
- ADDRESS_HOME_CITY};
- std::vector<ServerFieldType> server_types = {NAME_FULL, EMAIL_ADDRESS,
- ADDRESS_HOME_CITY};
-
- // Simulate having seen this form on page load.
- autofill_manager().AddSeenForm(form, heuristic_types, server_types);
-
- // Simulate form submission.
- base::HistogramTester histogram_tester;
- autofill_manager().OnFormSubmitted(form, /*known_success=*/false,
- SubmissionSource::FORM_SUBMISSION);
-
- // Here, it is expected that there is a count for non-perfect filling for
- // addresses.
- EXPECT_THAT(
- histogram_tester.GetAllSamples("Autofill.PerfectFilling.Addresses"),
- BucketsAre(Bucket(false, 1), Bucket(true, 0)));
- EXPECT_THAT(
- histogram_tester.GetAllSamples("Autofill.PerfectFilling.CreditCards"),
- BucketsAre(Bucket(false, 0), Bucket(true, 0)));
-}
-
-// Test that we log the perfect filling metric correctly for a credit card form
-// in which every field is autofilled.
-TEST_F(AutofillMetricsTest, PerfectFillingForCreditCards_AllAutofilled) {
- // Set up our form data with two autofilled fields.
- FormData form =
- test::GetFormData({.description_for_logging = "PerectFilling",
- .fields =
- {
- {.label = u"Name",
- .name = u"name",
- .value = u"Elvis Aaron Presley",
- .is_autofilled = true},
- {.label = u"CCNumber",
- .name = u"ccnumber",
- .value = u"01230123012399",
- .is_autofilled = true},
- },
- .unique_renderer_id = test::MakeFormRendererId(),
- .main_frame_origin = url::Origin::Create(
- autofill_client_->form_origin())});
-
- std::vector<ServerFieldType> heuristic_types = {CREDIT_CARD_NAME_FULL,
- CREDIT_CARD_NUMBER};
- std::vector<ServerFieldType> server_types = {CREDIT_CARD_NAME_FULL,
- CREDIT_CARD_NUMBER};
-
- // Simulate having seen this form on page load.
- autofill_manager().AddSeenForm(form, heuristic_types, server_types);
-
- // Simulate form submission.
- base::HistogramTester histogram_tester;
- autofill_manager().OnFormSubmitted(form, /*known_success=*/false,
- SubmissionSource::FORM_SUBMISSION);
-
- // Here, it is expected that there is a count for perfect filling for credit
- // cards.
- EXPECT_THAT(
- histogram_tester.GetAllSamples("Autofill.PerfectFilling.Addresses"),
- BucketsAre(Bucket(false, 0), Bucket(true, 0)));
- EXPECT_THAT(
- histogram_tester.GetAllSamples("Autofill.PerfectFilling.CreditCards"),
- BucketsAre(Bucket(false, 0), Bucket(true, 1)));
-}
-
-// Test that we log the perfect filling metric correctly for a credit card form
-// in which not every field is autofilled or empty.
-TEST_F(AutofillMetricsTest, PerfectFillingForCreditCards_NotAllAutofilled) {
- // Set up our form data with two autofilled fields.
- FormData form =
- test::GetFormData({.description_for_logging = "PerectFilling",
- .fields =
- {
- {.label = u"Name",
- .name = u"name",
- .value = u"Elvis Aaron Presley",
- .is_autofilled = true},
- {.label = u"CCNumber",
- .name = u"ccnumber",
- .value = u"01230123012399",
- .is_autofilled = false},
- },
- .unique_renderer_id = test::MakeFormRendererId(),
- .main_frame_origin = url::Origin::Create(
- autofill_client_->form_origin())});
-
- std::vector<ServerFieldType> heuristic_types = {CREDIT_CARD_NAME_FULL,
- CREDIT_CARD_NUMBER};
- std::vector<ServerFieldType> server_types = {CREDIT_CARD_NAME_FULL,
- CREDIT_CARD_NUMBER};
-
- // Simulate having seen this form on page load.
- autofill_manager().AddSeenForm(form, heuristic_types, server_types);
-
- // Simulate form submission.
- base::HistogramTester histogram_tester;
- autofill_manager().OnFormSubmitted(form, /*known_success=*/false,
- SubmissionSource::FORM_SUBMISSION);
-
- // Here, it is expected that there is a count for non-perfect filling for
- // credit cards.
- EXPECT_THAT(
- histogram_tester.GetAllSamples("Autofill.PerfectFilling.Addresses"),
- BucketsAre(Bucket(false, 0), Bucket(true, 0)));
- EXPECT_THAT(
- histogram_tester.GetAllSamples("Autofill.PerfectFilling.CreditCards"),
- BucketsAre(Bucket(false, 1), Bucket(true, 0)));
-}
-
-// Test that we log the perfect filling metric correctly for a form that
-// contains both credit card and address information. Here, the form is fully
-// autofilled resulting in a perfect count for both addresses and credit cards.
-TEST_F(AutofillMetricsTest, PerfectFillingForMixedForm_AllAutofilled) {
- // Set up our form data with two autofilled fields.
- FormData form =
- test::GetFormData({.description_for_logging = "PerectFilling",
- .fields =
- {
- {.label = u"Name",
- .name = u"name",
- .value = u"Elvis Aaron Presley",
- .is_autofilled = true},
- {.label = u"CCNumber",
- .name = u"ccnumber",
- .value = u"01230123012399",
- .is_autofilled = true},
- },
- .unique_renderer_id = test::MakeFormRendererId(),
- .main_frame_origin = url::Origin::Create(
- autofill_client_->form_origin())});
-
- std::vector<ServerFieldType> heuristic_types = {NAME_FULL,
- CREDIT_CARD_NUMBER};
- std::vector<ServerFieldType> server_types = {NAME_FULL, CREDIT_CARD_NUMBER};
-
- // Simulate having seen this form on page load.
- autofill_manager().AddSeenForm(form, heuristic_types, server_types);
+struct Field {
+ ServerFieldType field_type;
+ bool is_autofilled = true;
+ absl::optional<std::u16string> value = absl::nullopt;
+};
- // Simulate form submission.
- base::HistogramTester histogram_tester;
- autofill_manager().OnFormSubmitted(form, /*known_success=*/false,
- SubmissionSource::FORM_SUBMISSION);
+struct PerfectFillingTestCase {
+ std::string description;
+ std::vector<Field> fields;
+ std::vector<Bucket> address_buckets;
+ std::vector<Bucket> credit_card_buckets;
+};
- // Here, it is expected that there is a count for perfect filling for credit
- // cards and for addresses.
- EXPECT_THAT(
- histogram_tester.GetAllSamples("Autofill.PerfectFilling.Addresses"),
- BucketsAre(Bucket(false, 0), Bucket(true, 1)));
- EXPECT_THAT(
- histogram_tester.GetAllSamples("Autofill.PerfectFilling.CreditCards"),
- BucketsAre(Bucket(false, 0), Bucket(true, 1)));
-}
+class AutofillPerfectFillingMetricsTest
+ : public AutofillMetricsTest,
+ public ::testing::WithParamInterface<PerfectFillingTestCase> {
+ public:
+ std::vector<test::FieldDataDescription> GetFields(std::vector<Field> fields) {
+ std::vector<test::FieldDataDescription> fields_to_return;
+ for (const auto& field : fields) {
+ test::FieldDataDescription f;
+ if (field.value) {
+ f.value = field.value;
+ } else if (field.field_type == NAME_FULL ||
+ field.field_type == CREDIT_CARD_NAME_FULL) {
+ f.value = u"Elvis Aaron Presley";
+ } else if (field.field_type == EMAIL_ADDRESS) {
+ f.value = u"buddy@gmail.com";
+ } else if (field.field_type == ADDRESS_HOME_CITY) {
+ f.value = u"Munich";
+ } else if (field.field_type == CREDIT_CARD_NUMBER) {
+ f.value = u"01230123012399";
+ } else {
+ NOTREACHED();
+ }
+ f.role = field.field_type;
+ f.is_autofilled = field.is_autofilled;
+ fields_to_return.push_back(f);
+ }
+ return fields_to_return;
+ }
+};
-// Test that we log the perfect filling metric correctly for a form that
-// contains both credit card and address information. Here, the form is not
-// fully autofilled resulting in a non-perfect count for both addresses and
-// credit cards
-TEST_F(AutofillMetricsTest, PerfectFillingForMixedForm_NotAllAutofilled) {
- // Set up our form data with two autofilled fields.
+INSTANTIATE_TEST_SUITE_P(
+ AutofillPerfectFillingMetricsTest,
+ AutofillPerfectFillingMetricsTest,
+ testing::Values(
+ // Test that we log the perfect filling metric correctly for an address
+ // form in which every field is autofilled.
+ PerfectFillingTestCase{
+ "PerfectFillingForAddresses_AllAutofillFilled",
+ {{NAME_FULL}, {EMAIL_ADDRESS}, {ADDRESS_HOME_CITY}},
+ {Bucket(false, 0), Bucket(true, 1)},
+ {Bucket(false, 0), Bucket(true, 0)}},
+ // Test that we log the perfect filling metric correctly for an address
+ // form in which every field is autofilled or empty.
+ PerfectFillingTestCase{
+ "PerfectFillingForAddresses_AllAutofillFilledOrEmpty",
+ {{NAME_FULL}, {EMAIL_ADDRESS}, {ADDRESS_HOME_CITY, false, u""}},
+ {Bucket(false, 0), Bucket(true, 1)},
+ {Bucket(false, 0), Bucket(true, 0)}},
+ // Test that we log the perfect filling metric correctly for an address
+ // form in which a non-empty field is not autofilled.
+ PerfectFillingTestCase{
+ "PerfectFillingForAddresses_NotAllAutofilled",
+ {{NAME_FULL}, {EMAIL_ADDRESS}, {ADDRESS_HOME_CITY, false}},
+ {Bucket(false, 1), Bucket(true, 0)},
+ {Bucket(false, 0), Bucket(true, 0)}},
+ // Test that we log the perfect filling metric correctly for a credit
+ // card form in which every field is autofilled.
+ PerfectFillingTestCase{"PerfectFillingForCreditCards_AllAutofilled",
+ {{CREDIT_CARD_NAME_FULL}, {CREDIT_CARD_NUMBER}},
+ {Bucket(false, 0), Bucket(true, 0)},
+ {Bucket(false, 0), Bucket(true, 1)}},
+ // Test that we log the perfect filling metric correctly for a credit
+ // card form in which not every field is autofilled or empty.
+ PerfectFillingTestCase{
+ "PerfectFillingForCreditCards_NotAllAutofilled",
+ {{CREDIT_CARD_NAME_FULL}, {CREDIT_CARD_NUMBER, false}},
+ {Bucket(false, 0), Bucket(true, 0)},
+ {Bucket(false, 1), Bucket(true, 0)}},
+ // Test that we log the perfect filling metric correctly for a form that
+ // contains both credit card and address information. Here, the form is
+ // fully autofilled resulting in a perfect count for both addresses and
+ // credit cards.
+ PerfectFillingTestCase{"PerfectFillingForMixedForm_AllAutofilled",
+ {{NAME_FULL}, {CREDIT_CARD_NUMBER}},
+ {Bucket(false, 0), Bucket(true, 1)},
+ {Bucket(false, 0), Bucket(true, 1)}},
+ // Test that we log the perfect filling metric correctly for a form that
+ // contains both credit card and address information. Here, the form is
+ // not fully autofilled resulting in a non-perfect count for both
+ // addresses and credit cards.
+ PerfectFillingTestCase{"PerfectFillingForMixedForm_NotAllAutofilled",
+ {{NAME_FULL}, {CREDIT_CARD_NUMBER, false}},
+ {Bucket(false, 1), Bucket(true, 0)},
+ {Bucket(false, 1), Bucket(true, 0)}}));
+
+TEST_P(AutofillPerfectFillingMetricsTest,
+ PerfectFilling_Addresses_CreditCards) {
+ auto test_case = GetParam();
FormData form =
- test::GetFormData({.description_for_logging = "PerectFilling",
- .fields =
- {
- {.label = u"Name",
- .name = u"name",
- .value = u"Elvis Aaron Presley",
- .is_autofilled = true},
- {.label = u"CCNumber",
- .name = u"ccnumber",
- .value = u"01230123012399",
- .is_autofilled = false},
- },
+ test::GetFormData({.description_for_logging = test_case.description,
+ .fields = GetFields(test_case.fields),
.unique_renderer_id = test::MakeFormRendererId(),
.main_frame_origin = url::Origin::Create(
autofill_client_->form_origin())});
- std::vector<ServerFieldType> heuristic_types = {NAME_FULL,
- CREDIT_CARD_NUMBER};
- std::vector<ServerFieldType> server_types = {NAME_FULL, CREDIT_CARD_NUMBER};
+ std::vector<ServerFieldType> field_types;
+ for (const auto& f : test_case.fields)
+ field_types.push_back(f.field_type);
// Simulate having seen this form on page load.
- autofill_manager().AddSeenForm(form, heuristic_types, server_types);
+ autofill_manager().AddSeenForm(form, field_types, field_types);
// Simulate form submission.
base::HistogramTester histogram_tester;
- autofill_manager().OnFormSubmitted(form, /*known_success=*/false,
- SubmissionSource::FORM_SUBMISSION);
+ SubmitForm(form);
- // Here, it is expected that there is a count for non-perfect filling for
- // credit cards and for addresses.
EXPECT_THAT(
histogram_tester.GetAllSamples("Autofill.PerfectFilling.Addresses"),
- BucketsAre(Bucket(false, 1), Bucket(true, 0)));
+ BucketsAre(test_case.address_buckets));
EXPECT_THAT(
histogram_tester.GetAllSamples("Autofill.PerfectFilling.CreditCards"),
- BucketsAre(Bucket(false, 1), Bucket(true, 0)));
+ BucketsAre(test_case.credit_card_buckets));
}
// Test that we log quality metrics appropriately.
@@ -893,8 +695,7 @@ TEST_F(AutofillMetricsTest, QualityMetrics) {
// Simulate form submission.
base::HistogramTester histogram_tester;
- autofill_manager().OnFormSubmitted(form, /*known_success=*/false,
- SubmissionSource::FORM_SUBMISSION);
+ SubmitForm(form);
// Auxiliary function for GetAllSamples() expectations.
auto b = [](ServerFieldType field_type,
@@ -997,8 +798,7 @@ TEST_F(AutofillMetricsTest, ProfileImportStatus_NoImport) {
// Simulate form submission.
base::HistogramTester histogram_tester;
- autofill_manager().OnFormSubmitted(form, /*known_success=*/false,
- SubmissionSource::FORM_SUBMISSION);
+ SubmitForm(form);
using Metric = AutofillMetrics::AddressProfileImportStatusMetric;
EXPECT_THAT(
@@ -1045,8 +845,7 @@ TEST_F(AutofillMetricsTest, ProfileImportStatus_RegularImport) {
// Simulate form submission.
base::HistogramTester histogram_tester;
- autofill_manager().OnFormSubmitted(form, /*known_success=*/false,
- SubmissionSource::FORM_SUBMISSION);
+ SubmitForm(form);
using Metric = AutofillMetrics::AddressProfileImportStatusMetric;
EXPECT_THAT(
@@ -1105,8 +904,7 @@ TEST_F(AutofillMetricsTest, ProfileImportStatus_UnionImport) {
base::HistogramTester histogram_tester;
- autofill_manager().OnFormSubmitted(form, /*known_success=*/false,
- SubmissionSource::FORM_SUBMISSION);
+ SubmitForm(form);
using Metric = AutofillMetrics::AddressProfileImportStatusMetric;
EXPECT_THAT(
@@ -1154,8 +952,7 @@ TEST_F(AutofillMetricsTest, ProfileImportRequirements_AllFulfilled) {
// Simulate form submission.
base::HistogramTester histogram_tester;
- autofill_manager().OnFormSubmitted(form, /*known_success=*/false,
- SubmissionSource::FORM_SUBMISSION);
+ SubmitForm(form);
std::vector<AddressProfileImportRequirementExpectations> expectations = {
{AddressImportRequirements::STATE_VALID_REQUIREMENT_FULFILLED, true},
@@ -1235,8 +1032,7 @@ TEST_F(AutofillMetricsTest, ProfileImportRequirements_MissingHomeLineOne) {
// Simulate form submission.
base::HistogramTester histogram_tester;
- autofill_manager().OnFormSubmitted(form, /*known_success=*/false,
- SubmissionSource::FORM_SUBMISSION);
+ SubmitForm(form);
std::vector<AddressProfileImportRequirementExpectations> expectations = {
{AddressImportRequirements::STATE_VALID_REQUIREMENT_FULFILLED, true},
@@ -1320,8 +1116,7 @@ TEST_F(AutofillMetricsTest,
// Simulate form submission.
base::HistogramTester histogram_tester;
- autofill_manager().OnFormSubmitted(form, /*known_success=*/false,
- SubmissionSource::FORM_SUBMISSION);
+ SubmitForm(form);
std::vector<AddressProfileImportRequirementExpectations> expectations = {
{AddressImportRequirements::STATE_VALID_REQUIREMENT_FULFILLED, true},
@@ -1411,8 +1206,7 @@ TEST_F(AutofillMetricsTest,
// Simulate form submission.
base::HistogramTester histogram_tester;
- autofill_manager().OnFormSubmitted(form, /*known_success=*/false,
- SubmissionSource::FORM_SUBMISSION);
+ SubmitForm(form);
std::vector<AddressProfileImportRequirementExpectations> expectations = {
{AddressImportRequirements::STATE_VALID_REQUIREMENT_FULFILLED, false},
@@ -1505,8 +1299,7 @@ TEST_F(AutofillMetricsTest, ProfileImportRequirements_NonUniqueEmail) {
// Simulate form submission.
base::HistogramTester histogram_tester;
- autofill_manager().OnFormSubmitted(form, /*known_success=*/false,
- SubmissionSource::FORM_SUBMISSION);
+ SubmitForm(form);
std::vector<AddressProfileImportRequirementExpectations> expectations = {
{AddressImportRequirements::STATE_VALID_REQUIREMENT_FULFILLED, true},
@@ -1587,8 +1380,7 @@ TEST_F(AutofillMetricsTest, ProfileImportRequirements_OnlyAddressLineOne) {
// Simulate form submission.
base::HistogramTester histogram_tester;
- autofill_manager().OnFormSubmitted(form, /*known_success=*/false,
- SubmissionSource::FORM_SUBMISSION);
+ SubmitForm(form);
std::vector<AddressProfileImportRequirementExpectations> expectations = {
{AddressImportRequirements::STATE_VALID_REQUIREMENT_FULFILLED, true},
@@ -1701,8 +1493,7 @@ TEST_F(AutofillMetricsTest,
// Simulate form submission.
base::HistogramTester histogram_tester;
- autofill_manager().OnFormSubmitted(form, /*known_success=*/false,
- SubmissionSource::FORM_SUBMISSION);
+ SubmitForm(form);
// Rationalization quality.
{
@@ -1769,8 +1560,7 @@ TEST_F(AutofillMetricsTest,
// Simulate form submission.
base::HistogramTester histogram_tester;
- autofill_manager().OnFormSubmitted(form, /*known_success=*/false,
- SubmissionSource::FORM_SUBMISSION);
+ SubmitForm(form);
// Rationalization quality.
{
@@ -1976,11 +1766,9 @@ TEST_F(AutofillMetricsTest, LogRepeatedAddressTypeRationalized) {
FormSignature form_signature = Collapse(CalculateFormSignature(form));
FormStructure form_structure(form);
- std::vector<FormStructure*> forms;
- forms.push_back(&form_structure);
std::vector<ServerFieldType> field_types;
- for (size_t i = 0; i < forms[0]->field_count(); ++i)
+ for (size_t i = 0; i < form_structure.field_count(); ++i)
field_types.push_back(UNKNOWN_TYPE);
// Simulate having seen this form on page load.
@@ -1997,7 +1785,8 @@ TEST_F(AutofillMetricsTest, LogRepeatedAddressTypeRationalized) {
std::string response_string = SerializeAndEncode(response);
FormStructure::ParseApiQueryResponse(
- response_string, forms, test::GetEncodedSignatures(forms),
+ response_string, {&form_structure},
+ test::GetEncodedSignatures({&form_structure}),
autofill_manager().form_interactions_ukm_logger(), nullptr);
ASSERT_EQ(test_ukm_recorder_
@@ -2093,11 +1882,9 @@ TEST_F(AutofillMetricsTest, LogRepeatedStateCountryTypeRationalized) {
FormSignature form_signature = Collapse(CalculateFormSignature(form));
FormStructure form_structure(form);
- std::vector<FormStructure*> forms;
- forms.push_back(&form_structure);
std::vector<ServerFieldType> field_types;
- for (size_t i = 0; i < forms[0]->field_count(); ++i)
+ for (size_t i = 0; i < form_structure.field_count(); ++i)
field_types.push_back(UNKNOWN_TYPE);
// Simulate having seen this form on page load.
@@ -2116,7 +1903,8 @@ TEST_F(AutofillMetricsTest, LogRepeatedStateCountryTypeRationalized) {
std::string response_string = SerializeAndEncode(response);
FormStructure::ParseApiQueryResponse(
- response_string, forms, test::GetEncodedSignatures(forms),
+ response_string, {&form_structure},
+ test::GetEncodedSignatures({&form_structure}),
autofill_manager().form_interactions_ukm_logger(), nullptr);
ASSERT_EQ(test_ukm_recorder_
@@ -2129,7 +1917,7 @@ TEST_F(AutofillMetricsTest, LogRepeatedStateCountryTypeRationalized) {
test_ukm_recorder_, form,
UkmLogRepeatedServerTypePredictionRationalized::kEntryName,
{{{UkmLogRepeatedServerTypePredictionRationalized::kFormSignatureName,
- form_signature.value()},
+ *form_signature},
{UkmLogRepeatedServerTypePredictionRationalized::kFieldSignatureName,
field_signature[0].value()},
{UkmLogRepeatedServerTypePredictionRationalized::kFieldTypeGroupName,
@@ -2149,7 +1937,7 @@ TEST_F(AutofillMetricsTest, LogRepeatedStateCountryTypeRationalized) {
kFieldNewOverallTypeName,
ADDRESS_HOME_COUNTRY}},
{{UkmLogRepeatedServerTypePredictionRationalized::kFormSignatureName,
- form_signature.value()},
+ *form_signature},
{UkmLogRepeatedServerTypePredictionRationalized::kFieldSignatureName,
field_signature[1].value()},
{UkmLogRepeatedServerTypePredictionRationalized::kFieldTypeGroupName,
@@ -2169,7 +1957,7 @@ TEST_F(AutofillMetricsTest, LogRepeatedStateCountryTypeRationalized) {
{UkmLogRepeatedServerTypePredictionRationalized::kServerTypeName,
ADDRESS_HOME_COUNTRY}},
{{UkmLogRepeatedServerTypePredictionRationalized::kFormSignatureName,
- form_signature.value()},
+ *form_signature},
{UkmLogRepeatedServerTypePredictionRationalized::kFieldSignatureName,
field_signature[2].value()},
{UkmLogRepeatedServerTypePredictionRationalized::kFieldTypeGroupName,
@@ -2246,8 +2034,7 @@ TEST_F(AutofillMetricsTest,
// Simulate form submission.
base::HistogramTester histogram_tester;
- autofill_manager().OnFormSubmitted(form, /*known_success=*/false,
- SubmissionSource::FORM_SUBMISSION);
+ SubmitForm(form);
// Rationalization quality.
{
@@ -2330,8 +2117,7 @@ TEST_F(AutofillMetricsTest,
// Simulate form submission.
base::HistogramTester histogram_tester;
- autofill_manager().OnFormSubmitted(form, /*known_success=*/false,
- SubmissionSource::FORM_SUBMISSION);
+ SubmitForm(form);
// Auxiliary function for GetAllSamples() expectations.
auto b = [](ServerFieldType field_type,
@@ -2581,8 +2367,7 @@ TEST_P(QualityMetricsTest, Classification) {
// Run the form submission code while tracking the histograms.
base::HistogramTester histogram_tester;
- autofill_manager().OnFormSubmitted(form, /*known_success=*/false,
- SubmissionSource::FORM_SUBMISSION);
+ SubmitForm(form);
ExpectedUkmMetrics expected_ukm_metrics;
AppendFieldTypeUkm(form, heuristic_types, server_types, actual_types,
@@ -2735,11 +2520,7 @@ TEST_F(AutofillMetricsTest, TimingMetrics) {
field.is_autofilled = false;
form.fields.push_back(field);
- // Simulate a OnFormsSeen() call that should trigger the recording.
- std::vector<FormData> forms;
- forms.push_back(form);
- autofill_manager().OnFormsSeen(/*updated_forms=*/forms,
- /*removed_forms=*/{});
+ SeeForm(form);
// Because these metrics are related to timing, it is not possible to know in
// advance which bucket the sample will fall into, so we just need to make
@@ -2747,8 +2528,22 @@ TEST_F(AutofillMetricsTest, TimingMetrics) {
EXPECT_FALSE(
histogram_tester.GetAllSamples("Autofill.Timing.DetermineHeuristicTypes")
.empty());
- EXPECT_FALSE(
- histogram_tester.GetAllSamples("Autofill.Timing.ParseForm").empty());
+ if (!base::FeatureList::IsEnabled(features::kAutofillParseAsync)) {
+ EXPECT_FALSE(
+ histogram_tester.GetAllSamples("Autofill.Timing.ParseForm").empty());
+ } else {
+ EXPECT_FALSE(
+ histogram_tester.GetAllSamples("Autofill.Timing.ParseFormsAsync")
+ .empty());
+ EXPECT_FALSE(
+ histogram_tester
+ .GetAllSamples("Autofill.Timing.ParseFormsAsync.RunHeuristics")
+ .empty());
+ EXPECT_FALSE(
+ histogram_tester
+ .GetAllSamples("Autofill.Timing.ParseFormsAsync.UpdateCache")
+ .empty());
+ }
}
// Test that we log quality metrics appropriately when an upload is triggered
@@ -2808,138 +2603,64 @@ TEST_F(AutofillMetricsTest, QualityMetrics_NoSubmission) {
autofill_manager().AddSeenForm(form, heuristic_types, server_types);
// Simulate text input on one of the fields.
- autofill_manager().OnTextFieldDidChange(form, form.fields[0], gfx::RectF(),
- TimeTicks());
+ ChangeTextField(form, form.fields[0]);
+ autofill_manager().SetSeenFormPredictions(form.global_id(), heuristic_types,
+ server_types);
// Trigger a form upload and metrics by Resetting the manager.
base::HistogramTester histogram_tester;
autofill_manager().Reset();
- // Heuristic predictions.
- {
- std::string aggregate_histogram =
- "Autofill.FieldPredictionQuality.Aggregate.Heuristic.NoSubmission";
- std::string by_field_type_histogram =
- "Autofill.FieldPredictionQuality.ByFieldType.Heuristic.NoSubmission";
- // False Negative:
- histogram_tester.ExpectBucketCount(
- aggregate_histogram, AutofillMetrics::FALSE_NEGATIVE_UNKNOWN, 1);
- histogram_tester.ExpectBucketCount(
- by_field_type_histogram,
- GetFieldTypeGroupPredictionQualityMetric(
- ADDRESS_HOME_COUNTRY, AutofillMetrics::FALSE_NEGATIVE_UNKNOWN),
- 1);
- // Match:
- histogram_tester.ExpectBucketCount(aggregate_histogram,
- AutofillMetrics::TRUE_POSITIVE, 2);
- histogram_tester.ExpectBucketCount(
- by_field_type_histogram,
- GetFieldTypeGroupPredictionQualityMetric(
- NAME_FULL, AutofillMetrics::TRUE_POSITIVE),
- 1);
- histogram_tester.ExpectBucketCount(
- by_field_type_histogram,
- GetFieldTypeGroupPredictionQualityMetric(
- PHONE_HOME_WHOLE_NUMBER, AutofillMetrics::TRUE_POSITIVE),
- 1);
- // Mismatch:
- histogram_tester.ExpectBucketCount(
- aggregate_histogram, AutofillMetrics::FALSE_NEGATIVE_MISMATCH, 1);
- histogram_tester.ExpectBucketCount(
- by_field_type_histogram,
- GetFieldTypeGroupPredictionQualityMetric(
- EMAIL_ADDRESS, AutofillMetrics::FALSE_NEGATIVE_MISMATCH),
- 1);
- histogram_tester.ExpectBucketCount(
- by_field_type_histogram,
- GetFieldTypeGroupPredictionQualityMetric(
- PHONE_HOME_NUMBER, AutofillMetrics::FALSE_POSITIVE_MISMATCH),
- 1);
- // False Positives:
- histogram_tester.ExpectBucketCount(
- aggregate_histogram, AutofillMetrics::FALSE_POSITIVE_EMPTY, 1);
- histogram_tester.ExpectBucketCount(
- by_field_type_histogram,
- GetFieldTypeGroupPredictionQualityMetric(
- NAME_FULL, AutofillMetrics::FALSE_POSITIVE_EMPTY),
- 1);
- histogram_tester.ExpectBucketCount(
- aggregate_histogram, AutofillMetrics::FALSE_POSITIVE_UNKNOWN, 1);
- histogram_tester.ExpectBucketCount(
- by_field_type_histogram,
- GetFieldTypeGroupPredictionQualityMetric(
- PHONE_HOME_NUMBER, AutofillMetrics::FALSE_POSITIVE_UNKNOWN),
- 1);
+ auto Buck = [](ServerFieldType field_type,
+ AutofillMetrics::FieldTypeQualityMetric metric, size_t n) {
+ return Bucket(GetFieldTypeGroupPredictionQualityMetric(field_type, metric),
+ n);
+ };
- // Sanity Check:
- histogram_tester.ExpectTotalCount(aggregate_histogram, 6);
- histogram_tester.ExpectTotalCount(by_field_type_histogram, 7);
+ for (const std::string source : {"Heuristic", "Server", "Overall"}) {
+ EXPECT_THAT(histogram_tester.GetAllSamples(
+ "Autofill.FieldPredictionQuality.Aggregate." + source +
+ ".NoSubmission"),
+ BucketsAre(Bucket(AutofillMetrics::FALSE_NEGATIVE_UNKNOWN, 1),
+ Bucket(AutofillMetrics::TRUE_POSITIVE, 2),
+ Bucket(AutofillMetrics::FALSE_NEGATIVE_MISMATCH, 1),
+ Bucket(AutofillMetrics::FALSE_POSITIVE_EMPTY, 1),
+ Bucket(AutofillMetrics::FALSE_POSITIVE_UNKNOWN, 1)))
+ << "source=" << source;
}
+ // Heuristic predictions.
+ EXPECT_THAT(
+ histogram_tester.GetAllSamples(
+ "Autofill.FieldPredictionQuality.ByFieldType.Heuristic.NoSubmission"),
+ BucketsAre(
+ Buck(ADDRESS_HOME_COUNTRY, AutofillMetrics::FALSE_NEGATIVE_UNKNOWN,
+ 1),
+ Buck(NAME_FULL, AutofillMetrics::TRUE_POSITIVE, 1),
+ Buck(PHONE_HOME_WHOLE_NUMBER, AutofillMetrics::TRUE_POSITIVE, 1),
+ Buck(EMAIL_ADDRESS, AutofillMetrics::FALSE_NEGATIVE_MISMATCH, 1),
+ Buck(PHONE_HOME_NUMBER, AutofillMetrics::FALSE_POSITIVE_MISMATCH, 1),
+ Buck(NAME_FULL, AutofillMetrics::FALSE_POSITIVE_EMPTY, 1),
+ Buck(PHONE_HOME_NUMBER, AutofillMetrics::FALSE_POSITIVE_UNKNOWN, 1)));
+
// Server predictions override heuristics, so server and overall will be the
// same.
for (const std::string source : {"Server", "Overall"}) {
- std::string aggregate_histogram =
- "Autofill.FieldPredictionQuality.Aggregate." + source + ".NoSubmission";
- std::string by_field_type_histogram =
- "Autofill.FieldPredictionQuality.ByFieldType." + source +
- ".NoSubmission";
-
- // Unknown.
- histogram_tester.ExpectBucketCount(
- aggregate_histogram, AutofillMetrics::FALSE_NEGATIVE_UNKNOWN, 1);
- histogram_tester.ExpectBucketCount(
- by_field_type_histogram,
- GetFieldTypeGroupPredictionQualityMetric(
- ADDRESS_HOME_COUNTRY, AutofillMetrics::FALSE_NEGATIVE_UNKNOWN),
- 1);
- // Match:
- histogram_tester.ExpectBucketCount(aggregate_histogram,
- AutofillMetrics::TRUE_POSITIVE, 2);
- histogram_tester.ExpectBucketCount(
- by_field_type_histogram,
- GetFieldTypeGroupPredictionQualityMetric(
- EMAIL_ADDRESS, AutofillMetrics::TRUE_POSITIVE),
- 1);
- histogram_tester.ExpectBucketCount(
- by_field_type_histogram,
- GetFieldTypeGroupPredictionQualityMetric(
- PHONE_HOME_WHOLE_NUMBER, AutofillMetrics::TRUE_POSITIVE),
- 1);
- // Mismatch:
- histogram_tester.ExpectBucketCount(
- aggregate_histogram, AutofillMetrics::FALSE_NEGATIVE_MISMATCH, 1);
- histogram_tester.ExpectBucketCount(
- by_field_type_histogram,
- GetFieldTypeGroupPredictionQualityMetric(
- NAME_FULL, AutofillMetrics::FALSE_NEGATIVE_MISMATCH),
- 1);
- histogram_tester.ExpectBucketCount(
- by_field_type_histogram,
- GetFieldTypeGroupPredictionQualityMetric(
- NAME_FIRST, AutofillMetrics::FALSE_POSITIVE_MISMATCH),
- 1);
-
- // False Positives:
- histogram_tester.ExpectBucketCount(
- aggregate_histogram, AutofillMetrics::FALSE_POSITIVE_EMPTY, 1);
- histogram_tester.ExpectBucketCount(
- by_field_type_histogram,
- GetFieldTypeGroupPredictionQualityMetric(
- NAME_FIRST, AutofillMetrics::FALSE_POSITIVE_EMPTY),
- 1);
- histogram_tester.ExpectBucketCount(
- aggregate_histogram, AutofillMetrics::FALSE_POSITIVE_UNKNOWN, 1);
- histogram_tester.ExpectBucketCount(
- by_field_type_histogram,
- GetFieldTypeGroupPredictionQualityMetric(
- EMAIL_ADDRESS, AutofillMetrics::FALSE_POSITIVE_UNKNOWN),
- 1);
-
- // Sanity Check:
- histogram_tester.ExpectTotalCount(aggregate_histogram, 6);
- histogram_tester.ExpectTotalCount(by_field_type_histogram, 7);
+ EXPECT_THAT(
+ histogram_tester.GetAllSamples(
+ "Autofill.FieldPredictionQuality.ByFieldType." + source +
+ ".NoSubmission"),
+ BucketsAre(
+ Buck(ADDRESS_HOME_COUNTRY, AutofillMetrics::FALSE_NEGATIVE_UNKNOWN,
+ 1),
+ Buck(EMAIL_ADDRESS, AutofillMetrics::TRUE_POSITIVE, 1),
+ Buck(PHONE_HOME_WHOLE_NUMBER, AutofillMetrics::TRUE_POSITIVE, 1),
+ Buck(NAME_FULL, AutofillMetrics::FALSE_NEGATIVE_MISMATCH, 1),
+ Buck(NAME_FIRST, AutofillMetrics::FALSE_POSITIVE_MISMATCH, 1),
+ Buck(NAME_FIRST, AutofillMetrics::FALSE_POSITIVE_EMPTY, 1),
+ Buck(EMAIL_ADDRESS, AutofillMetrics::FALSE_POSITIVE_UNKNOWN, 1)))
+ << "source=" << source;
}
}
@@ -2976,9 +2697,9 @@ TEST_F(AutofillMetricsTest, QualityMetrics_BasedOnAutocomplete) {
field.autocomplete_attribute = "";
form.fields.push_back(field);
- std::unique_ptr<TestFormStructure> form_structure =
- std::make_unique<TestFormStructure>(form);
- TestFormStructure* form_structure_ptr = form_structure.get();
+ std::unique_ptr<FormStructure> form_structure =
+ std::make_unique<FormStructure>(form);
+ FormStructure* form_structure_ptr = form_structure.get();
form_structure->DetermineHeuristicTypes(nullptr, nullptr);
ASSERT_TRUE(
autofill_manager()
@@ -3100,8 +2821,7 @@ TEST_F(AutofillMetricsTest, UpiVirtualPaymentAddress) {
// Simulate form submission.
base::HistogramTester histogram_tester;
- autofill_manager().OnFormSubmitted(form, /*known_success=*/false,
- SubmissionSource::FORM_SUBMISSION);
+ SubmitForm(form);
histogram_tester.ExpectBucketCount(
"Autofill.UserHappiness", AutofillMetrics::USER_DID_ENTER_UPI_VPA, 1);
@@ -3170,8 +2890,7 @@ TEST_F(AutofillMetricsTest, SaneMetricsWithCacheMismatch) {
// Simulate form submission.
base::HistogramTester histogram_tester;
- autofill_manager().OnFormSubmitted(form, /*known_success=*/false,
- SubmissionSource::FORM_SUBMISSION);
+ SubmitForm(form);
for (const std::string source : {"Heuristic", "Server", "Overall"}) {
std::string aggregate_histogram =
@@ -3238,14 +2957,10 @@ TEST_F(AutofillMetricsTest, StoredProfileCountAutofillableFormSubmission) {
test::CreateTestFormField("Phone", "phone", "", "text", &field);
form.fields.push_back(field);
- std::vector<FormData> forms(1, form);
-
// Simulate form submission.
base::HistogramTester histogram_tester;
- autofill_manager().OnFormsSeen(/*updated_forms=*/forms,
- /*removed_forms=*/{});
- autofill_manager().OnFormSubmitted(form, /*known_success=*/false,
- SubmissionSource::FORM_SUBMISSION);
+ SeeForm(form);
+ SubmitForm(form);
// An autofillable form was submitted, and the number of stored profiles is
// logged.
@@ -3273,14 +2988,10 @@ TEST_F(AutofillMetricsTest, StoredProfileCountNonAutofillableFormSubmission) {
test::CreateTestFormField("Email", "email", "", "text", &field);
form.fields.push_back(field);
- std::vector<FormData> forms(1, form);
-
// Simulate form submission.
base::HistogramTester histogram_tester;
- autofill_manager().OnFormsSeen(/*updated_forms=*/forms,
- /*removed_forms=*/{});
- autofill_manager().OnFormSubmitted(form, /*known_success=*/false,
- SubmissionSource::FORM_SUBMISSION);
+ SeeForm(form);
+ SubmitForm(form);
// A non-autofillable form was submitted, and number of stored profiles is NOT
// logged.
@@ -3330,12 +3041,10 @@ TEST_F(AutofillMetricsTest, TypeOfEditedAutofilledFieldsUkmLogging) {
base::HistogramTester histogram_tester;
// Simulate text input in the first and second fields.
- autofill_manager().OnTextFieldDidChange(form, form.fields[0], gfx::RectF(),
- TimeTicks());
+ ChangeTextField(form, form.fields[0]);
// Simulate form submission.
- autofill_manager().OnFormSubmitted(form, /*known_success=*/false,
- SubmissionSource::FORM_SUBMISSION);
+ SubmitForm(form);
ExpectedUkmMetricsRecord name_field_ukm_record{
{UkmEditedAutofilledFieldAtSubmission::kFieldSignatureName,
Collapse(CalculateFieldSignatureForField(form.fields[0])).value()},
@@ -3387,14 +3096,11 @@ TEST_F(AutofillMetricsTest, TypeOfEditedAutofilledFieldsUmaLogging) {
base::HistogramTester histogram_tester;
// Simulate text input in the first and second fields.
- autofill_manager().OnTextFieldDidChange(form, form.fields[0], gfx::RectF(),
- TimeTicks());
- autofill_manager().OnTextFieldDidChange(form, form.fields[1], gfx::RectF(),
- TimeTicks());
+ ChangeTextField(form, form.fields[0]);
+ ChangeTextField(form, form.fields[1]);
// Simulate form submission.
- autofill_manager().OnFormSubmitted(form, /*known_success=*/false,
- SubmissionSource::FORM_SUBMISSION);
+ SubmitForm(form);
// The |NAME_FULL| field was edited (bucket 112).
histogram_tester.ExpectBucketCount(
@@ -3467,14 +3173,11 @@ TEST_F(AutofillMetricsTest, NumberOfEditedAutofilledFields) {
base::HistogramTester histogram_tester;
// Simulate text input in the first and second fields.
- autofill_manager().OnTextFieldDidChange(form, form.fields[0], gfx::RectF(),
- TimeTicks());
- autofill_manager().OnTextFieldDidChange(form, form.fields[1], gfx::RectF(),
- TimeTicks());
+ ChangeTextField(form, form.fields[0]);
+ ChangeTextField(form, form.fields[1]);
// Simulate form submission.
- autofill_manager().OnFormSubmitted(form, /*known_success=*/false,
- SubmissionSource::FORM_SUBMISSION);
+ SubmitForm(form);
// An autofillable form was submitted, and the number of edited autofilled
// fields is logged.
@@ -3522,8 +3225,7 @@ TEST_F(AutofillMetricsTest, NumberOfEditedAutofilledFields_NoSubmission) {
base::HistogramTester histogram_tester;
// Simulate text input in the first field.
- autofill_manager().OnTextFieldDidChange(form, form.fields[0], gfx::RectF(),
- TimeTicks());
+ ChangeTextField(form, form.fields[0]);
// We expect metrics to be logged when the manager is reset.
autofill_manager().Reset();
@@ -3551,27 +3253,23 @@ TEST_F(AutofillMetricsTest, DeveloperEngagement) {
test::CreateTestFormField("Email", "email", "", "text", &field);
form.fields.push_back(field);
- std::vector<FormData> forms(1, form);
-
// Ensure no metrics are logged when small form support is disabled (min
// number of fields enforced).
{
base::HistogramTester histogram_tester;
- autofill_manager().OnFormsSeen(/*updated_forms=*/forms,
- /*removed_forms=*/{});
+ SeeForm(form);
autofill_manager().Reset();
histogram_tester.ExpectTotalCount("Autofill.DeveloperEngagement", 0);
}
// Add another field to the form, so that it becomes fillable.
test::CreateTestFormField("Phone", "phone", "", "text", &field);
- forms.back().fields.push_back(field);
+ form.fields.push_back(field);
// Expect the "form parsed without hints" metric to be logged.
{
base::HistogramTester histogram_tester;
- autofill_manager().OnFormsSeen(/*updated_forms=*/forms,
- /*removed_forms=*/{});
+ SeeForm(form);
autofill_manager().Reset();
histogram_tester.ExpectUniqueSample(
"Autofill.DeveloperEngagement",
@@ -3585,19 +3283,18 @@ TEST_F(AutofillMetricsTest, DeveloperEngagement) {
// local heuristics to detect field types in the rest of the form.
test::CreateTestFormField("", "", "", "text", &field);
field.autocomplete_attribute = "given-name";
- forms.back().fields.push_back(field);
+ form.fields.push_back(field);
test::CreateTestFormField("", "", "", "text", &field);
field.autocomplete_attribute = "email";
- forms.back().fields.push_back(field);
+ form.fields.push_back(field);
test::CreateTestFormField("", "", "", "text", &field);
field.autocomplete_attribute = "address-line1";
- forms.back().fields.push_back(field);
+ form.fields.push_back(field);
// Expect the "form parsed with field type hints" metric to be logged.
{
base::HistogramTester histogram_tester;
- autofill_manager().OnFormsSeen(/*updated_forms=*/forms,
- /*removed_forms=*/{});
+ SeeForm(form);
autofill_manager().Reset();
histogram_tester.ExpectBucketCount(
"Autofill.DeveloperEngagement",
@@ -3611,14 +3308,13 @@ TEST_F(AutofillMetricsTest, DeveloperEngagement) {
// Add a field with an author-specified UPI-VPA field type in the form.
test::CreateTestFormField("", "", "", "text", &field);
field.autocomplete_attribute = "upi-vpa";
- forms.back().fields.push_back(field);
+ form.fields.push_back(field);
// Expect the "form parsed with type hints" metric, and the
// "author-specified upi-vpa type" metric to be logged.
{
base::HistogramTester histogram_tester;
- autofill_manager().OnFormsSeen(/*updated_forms=*/forms,
- /*removed_forms=*/{});
+ SeeForm(form);
autofill_manager().Reset();
histogram_tester.ExpectBucketCount(
"Autofill.DeveloperEngagement",
@@ -3648,12 +3344,9 @@ TEST_F(AutofillMetricsTest,
test::CreateTestFormField("Email", "email", "", "text", &field);
form.fields.push_back(field);
- std::vector<FormData> forms(1, form);
-
// Ensure no entries are logged when loading a non-fillable form.
{
- autofill_manager().OnFormsSeen(/*updated_forms=*/forms,
- /*removed_forms=*/{});
+ SeeForm(form);
autofill_manager().Reset();
EXPECT_EQ(0ul, test_ukm_recorder_->entries_count());
@@ -3661,17 +3354,16 @@ TEST_F(AutofillMetricsTest,
// Add another field to the form, so that it becomes fillable.
test::CreateTestFormField("Phone", "phone", "", "text", &field);
- forms.back().fields.push_back(field);
+ form.fields.push_back(field);
// Expect the "form parsed without field type hints" metric and the
// "form loaded" form interaction event to be logged.
{
- autofill_manager().OnFormsSeen(/*updated_forms=*/forms,
- /*removed_forms=*/{});
+ SeeForm(form);
autofill_manager().Reset();
VerifyDeveloperEngagementUkm(
- test_ukm_recorder_, forms.back(), /*is_for_credit_card=*/false,
+ test_ukm_recorder_, form, /*is_for_credit_card=*/false,
{FormType::kAddressForm},
{AutofillMetrics::FILLABLE_FORM_PARSED_WITHOUT_TYPE_HINTS});
}
@@ -3695,11 +3387,9 @@ TEST_F(AutofillMetricsTest,
test::CreateTestFormField("Email", "email", "", "text", &field);
form.fields.push_back(field);
- std::vector<FormData> forms(1, form);
-
// Add another field to the form, so that it becomes fillable.
test::CreateTestFormField("Phone", "phone", "", "text", &field);
- forms.back().fields.push_back(field);
+ form.fields.push_back(field);
// Add some fields with an author-specified field type to the form.
// We need to add at least three fields, because a form must have at least
@@ -3708,23 +3398,22 @@ TEST_F(AutofillMetricsTest,
// local heuristics to detect field types in the rest of the form.
test::CreateTestFormField("", "", "", "text", &field);
field.autocomplete_attribute = "given-name";
- forms.back().fields.push_back(field);
+ form.fields.push_back(field);
test::CreateTestFormField("", "", "", "text", &field);
field.autocomplete_attribute = "email";
- forms.back().fields.push_back(field);
+ form.fields.push_back(field);
test::CreateTestFormField("", "", "", "text", &field);
field.autocomplete_attribute = "address-line1";
- forms.back().fields.push_back(field);
+ form.fields.push_back(field);
// Expect the "form parsed without field type hints" metric and the
// "form loaded" form interaction event to be logged.
{
- autofill_manager().OnFormsSeen(/*updated_forms=*/forms,
- /*removed_forms=*/{});
+ SeeForm(form);
autofill_manager().Reset();
VerifyDeveloperEngagementUkm(
- test_ukm_recorder_, forms.back(), /*is_for_credit_card=*/false,
+ test_ukm_recorder_, form, /*is_for_credit_card=*/false,
{FormType::kAddressForm},
{AutofillMetrics::FILLABLE_FORM_PARSED_WITH_TYPE_HINTS});
}
@@ -3753,15 +3442,12 @@ TEST_F(AutofillMetricsTest, UkmDeveloperEngagement_LogUpiVpaTypeHint) {
field.autocomplete_attribute = "address-line1";
form.fields.push_back(field);
- std::vector<FormData> forms(1, form);
-
{
SCOPED_TRACE("VPA and other autocomplete hint present");
- autofill_manager().OnFormsSeen(/*updated_forms=*/forms,
- /*removed_forms=*/{});
+ SeeForm(form);
VerifyDeveloperEngagementUkm(
- test_ukm_recorder_, forms.back(), /*is_for_credit_card=*/false,
+ test_ukm_recorder_, form, /*is_for_credit_card=*/false,
/* UPI VPA has Unknown form type.*/
{FormType::kAddressForm, FormType::kUnknownFormType},
{AutofillMetrics::FILLABLE_FORM_PARSED_WITH_TYPE_HINTS,
@@ -4149,12 +3835,12 @@ TEST_F(AutofillMetricsTest, CreditCardCheckoutFlowUserActions) {
test::CreateTestFormField("Name on card", "cc-name", "", "text", &field);
form.fields.push_back(field);
field_types.push_back(CREDIT_CARD_NAME_FULL);
- test::CreateTestFormField("Credit card", "card", "", "text", &field);
+ test::CreateTestFormField("Credit card", "cardnum", "", "text", &field);
form.fields.push_back(field);
field_types.push_back(CREDIT_CARD_NUMBER);
- test::CreateTestFormField("Month", "card_month", "", "text", &field);
+ test::CreateTestFormField("Expiration date", "expdate", "", "text", &field);
form.fields.push_back(field);
- field_types.push_back(CREDIT_CARD_EXP_MONTH);
+ field_types.push_back(CREDIT_CARD_EXP_DATE_2_DIGIT_YEAR);
// Simulate having seen this form on page load.
// |form_structure| will be owned by `autofill_manager()`.
@@ -4261,8 +3947,7 @@ TEST_F(AutofillMetricsTest, CreditCardCheckoutFlowUserActions) {
{
base::UserActionTester user_action_tester;
autofill_manager().OnAskForValuesToFillTest(form, field);
- autofill_manager().OnFormSubmitted(form, /*known_success=*/false,
- SubmissionSource::FORM_SUBMISSION);
+ SubmitForm(form);
EXPECT_EQ(1,
user_action_tester.GetActionCount("Autofill_OnWillSubmitForm"));
EXPECT_EQ(1, user_action_tester.GetActionCount(
@@ -4338,13 +4023,10 @@ TEST_F(AutofillMetricsTest, UpiVpaUkmTest) {
&field);
form.fields.push_back(field);
- std::vector<FormData> forms(1, form);
-
{
- autofill_manager().OnFormsSeen(/*updated_forms=*/forms,
- /*removed_forms=*/{});
+ SeeForm(form);
- VerifySubmitFormUkm(test_ukm_recorder_, forms.back(),
+ VerifySubmitFormUkm(test_ukm_recorder_, form,
AutofillMetrics::NON_FILLABLE_FORM_OR_NEW_DATA,
/*is_for_credit_card=*/false,
/* has_upi_vpa_field */ true,
@@ -4440,8 +4122,7 @@ TEST_F(AutofillMetricsTest, ProfileCheckoutFlowUserActions) {
{
base::UserActionTester user_action_tester;
autofill_manager().OnAskForValuesToFillTest(form, field);
- autofill_manager().OnFormSubmitted(form, /*known_success=*/false,
- SubmissionSource::FORM_SUBMISSION);
+ SubmitForm(form);
EXPECT_EQ(1,
user_action_tester.GetActionCount("Autofill_OnWillSubmitForm"));
EXPECT_EQ(1, user_action_tester.GetActionCount(
@@ -4516,12 +4197,12 @@ TEST_F(AutofillMetricsTest, PolledCreditCardSuggestions_DebounceLogs) {
test::CreateTestFormField("Name on card", "cc-name", "", "text", &field);
form.fields.push_back(field);
field_types.push_back(CREDIT_CARD_NAME_FULL);
- test::CreateTestFormField("Credit card", "card", "", "text", &field);
+ test::CreateTestFormField("Credit card", "cardnum", "", "text", &field);
form.fields.push_back(field);
field_types.push_back(CREDIT_CARD_NUMBER);
- test::CreateTestFormField("Month", "card_month", "", "text", &field);
+ test::CreateTestFormField("Expiration date", "expdate", "", "text", &field);
form.fields.push_back(field);
- field_types.push_back(CREDIT_CARD_EXP_MONTH);
+ field_types.push_back(CREDIT_CARD_EXP_DATE_2_DIGIT_YEAR);
// Simulate having seen this form on page load.
// |form_structure| will be owned by `autofill_manager()`.
@@ -4576,7 +4257,7 @@ TEST_F(AutofillMetricsTest, QueriedCreditCardFormIsSecure) {
test::CreateTestFormField("Year", "card_year", "", "text", &field);
form.fields.push_back(field);
field_types.push_back(CREDIT_CARD_EXP_2_DIGIT_YEAR);
- test::CreateTestFormField("Credit card", "card", "", "text", &field);
+ test::CreateTestFormField("Credit card", "cardnum", "", "text", &field);
form.fields.push_back(field);
field_types.push_back(CREDIT_CARD_NUMBER);
@@ -4705,12 +4386,8 @@ TEST_P(AutofillMetricsIFrameTest, CreditCardParsedFormEvents) {
field_types.push_back(CREDIT_CARD_VERIFICATION_CODE);
// Simulate seeing and parsing the form.
- std::vector<FormData> forms;
- forms.push_back(form);
-
base::HistogramTester histogram_tester;
- autofill_manager().OnFormsSeen(/*updated_forms=*/forms,
- /*removed_forms=*/{});
+ SeeForm(form);
histogram_tester.ExpectUniqueSample(
"Autofill.FormEvents.CreditCard.WithNoData", FORM_EVENT_DID_PARSE_FORM,
1);
@@ -4735,7 +4412,7 @@ TEST_P(AutofillMetricsIFrameTest, CreditCardInteractedFormEvents) {
test::CreateTestFormField("Year", "card_year", "", "text", &field);
form.fields.push_back(field);
field_types.push_back(CREDIT_CARD_EXP_2_DIGIT_YEAR);
- test::CreateTestFormField("Credit card", "card", "", "text", &field);
+ test::CreateTestFormField("Credit card", "cardnum", "", "text", &field);
form.fields.push_back(field);
field_types.push_back(CREDIT_CARD_NUMBER);
@@ -4790,7 +4467,7 @@ TEST_P(AutofillMetricsIFrameTest, CreditCardPopupSuppressedFormEvents) {
test::CreateTestFormField("Year", "card_year", "", "text", &field);
form.fields.push_back(field);
field_types.push_back(CREDIT_CARD_EXP_2_DIGIT_YEAR);
- test::CreateTestFormField("Credit card", "card", "", "text", &field);
+ test::CreateTestFormField("Credit card", "cardnum", "", "text", &field);
form.fields.push_back(field);
field_types.push_back(CREDIT_CARD_NUMBER);
@@ -4850,7 +4527,7 @@ TEST_P(AutofillMetricsIFrameTest, CreditCardShownFormEvents) {
test::CreateTestFormField("Year", "card_year", "", "text", &field);
form.fields.push_back(field);
field_types.push_back(CREDIT_CARD_EXP_2_DIGIT_YEAR);
- test::CreateTestFormField("Credit card", "card", "", "text", &field);
+ test::CreateTestFormField("Credit card", "cardnum", "", "text", &field);
form.fields.push_back(field);
field_types.push_back(CREDIT_CARD_NUMBER);
@@ -4932,7 +4609,7 @@ TEST_P(AutofillMetricsIFrameTest, VirtualCreditCardShownFormEvents) {
test::CreateTestFormField("CVC", "cvc", "", "text", &field);
form.fields.push_back(field);
field_types.push_back(CREDIT_CARD_VERIFICATION_CODE);
- test::CreateTestFormField("Credit card", "card", "", "text", &field);
+ test::CreateTestFormField("Credit card", "cardnum", "", "text", &field);
form.fields.push_back(field);
field_types.push_back(CREDIT_CARD_NUMBER);
@@ -5101,7 +4778,7 @@ TEST_P(AutofillMetricsIFrameTest, CreditCardSelectedFormEvents) {
test::CreateTestFormField("Year", "card_year", "", "text", &field);
form.fields.push_back(field);
field_types.push_back(CREDIT_CARD_EXP_2_DIGIT_YEAR);
- test::CreateTestFormField("Credit card", "card", "", "text", &field);
+ test::CreateTestFormField("Credit card", "cardnum", "", "text", &field);
form.fields.push_back(field);
field_types.push_back(CREDIT_CARD_NUMBER);
@@ -5248,7 +4925,7 @@ TEST_P(AutofillMetricsIFrameTest, CreditCardFilledFormEvents) {
test::CreateTestFormField("Year", "card_year", "", "text", &field);
form.fields.push_back(field);
field_types.push_back(CREDIT_CARD_EXP_2_DIGIT_YEAR);
- test::CreateTestFormField("Credit card", "card", "", "text", &field);
+ test::CreateTestFormField("Credit card", "cardnum", "", "text", &field);
form.fields.push_back(field);
field_types.push_back(CREDIT_CARD_NUMBER);
@@ -5318,8 +4995,7 @@ TEST_P(AutofillMetricsIFrameTest, CreditCardFilledFormEvents) {
autofill_manager().suggestion_generator()->MakeFrontendId(
guid, std::string()));
OnCreditCardFetchingSuccessful(u"6011000990139424");
- autofill_manager().OnFormSubmitted(form, /*known_success=*/false,
- SubmissionSource::FORM_SUBMISSION);
+ SubmitForm(form);
histogram_tester.ExpectBucketCount(
"Autofill.FormEvents.CreditCard",
FORM_EVENT_MASKED_SERVER_CARD_SUGGESTION_FILLED, 1);
@@ -5500,7 +5176,7 @@ TEST_F(AutofillMetricsTest, CreditCardUnmaskingPreflightCall) {
FormData form;
FormFieldData field;
std::vector<ServerFieldType> field_types;
- test::CreateTestFormField("Credit card", "card", "", "text", &field);
+ test::CreateTestFormField("Credit card", "cardnum", "", "text", &field);
form.fields.push_back(field);
field_types.push_back(CREDIT_CARD_NUMBER);
@@ -5636,7 +5312,7 @@ TEST_F(AutofillMetricsTest, CreditCardGetRealPanDuration_ServerCard) {
test::CreateTestFormField("Year", "card_year", "", "text", &field);
form.fields.push_back(field);
field_types.push_back(CREDIT_CARD_EXP_2_DIGIT_YEAR);
- test::CreateTestFormField("Credit card", "card", "", "text", &field);
+ test::CreateTestFormField("Credit card", "cardnum", "", "text", &field);
form.fields.push_back(field);
field_types.push_back(CREDIT_CARD_NUMBER);
@@ -5839,7 +5515,7 @@ TEST_F(AutofillMetricsTest,
test::CreateTestFormField("Year", "card_year", "", "text", &field);
form.fields.push_back(field);
field_types.push_back(CREDIT_CARD_EXP_2_DIGIT_YEAR);
- test::CreateTestFormField("Credit card", "card", "", "text", &field);
+ test::CreateTestFormField("Credit card", "cardnum", "", "text", &field);
form.fields.push_back(field);
field_types.push_back(CREDIT_CARD_NUMBER);
@@ -5851,8 +5527,7 @@ TEST_F(AutofillMetricsTest,
base::HistogramTester histogram_tester;
autofill_manager().DidShowSuggestions(true /* is_new_popup */, form, field);
autofill_manager().OnAskForValuesToFillTest(form, field);
- autofill_manager().OnFormSubmitted(form, /*known_success=*/false,
- SubmissionSource::FORM_SUBMISSION);
+ SubmitForm(form);
histogram_tester.ExpectBucketCount(
"Autofill.FormEvents.CreditCard",
FORM_EVENT_SUBMIT_WITHOUT_SELECTING_SUGGESTIONS_NO_CARD, 1);
@@ -5882,7 +5557,8 @@ TEST_P(AutofillMetricsIFrameTest,
test::CreateTestFormField("Year", "card_year", "", "text", &field);
form.fields.push_back(field);
field_types.push_back(CREDIT_CARD_EXP_2_DIGIT_YEAR);
- test::CreateTestFormField("Credit card", "card", "411111111", "text", &field);
+ test::CreateTestFormField("Credit card", "cardnum", "411111111", "text",
+ &field);
form.fields.push_back(field);
field_types.push_back(CREDIT_CARD_NUMBER);
@@ -5894,8 +5570,7 @@ TEST_P(AutofillMetricsIFrameTest,
base::HistogramTester histogram_tester;
autofill_manager().DidShowSuggestions(true /* is_new_popup */, form, field);
autofill_manager().OnAskForValuesToFillTest(form, field);
- autofill_manager().OnFormSubmitted(form, /*known_success=*/false,
- SubmissionSource::FORM_SUBMISSION);
+ SubmitForm(form);
histogram_tester.ExpectBucketCount(
"Autofill.FormEvents.CreditCard",
FORM_EVENT_SUBMIT_WITHOUT_SELECTING_SUGGESTIONS_WRONG_SIZE_CARD, 1);
@@ -5928,8 +5603,8 @@ TEST_P(AutofillMetricsIFrameTest,
test::CreateTestFormField("Year", "card_year", "", "text", &field);
form.fields.push_back(field);
field_types.push_back(CREDIT_CARD_EXP_2_DIGIT_YEAR);
- test::CreateTestFormField("Credit card", "card", "4444444444444444", "text",
- &field);
+ test::CreateTestFormField("Credit card", "cardnum", "4444444444444444",
+ "text", &field);
form.fields.push_back(field);
field_types.push_back(CREDIT_CARD_NUMBER);
@@ -5941,8 +5616,7 @@ TEST_P(AutofillMetricsIFrameTest,
base::HistogramTester histogram_tester;
autofill_manager().DidShowSuggestions(true /* is_new_popup */, form, field);
autofill_manager().OnAskForValuesToFillTest(form, field);
- autofill_manager().OnFormSubmitted(form, /*known_success=*/false,
- SubmissionSource::FORM_SUBMISSION);
+ SubmitForm(form);
histogram_tester.ExpectBucketCount(
"Autofill.FormEvents.CreditCard",
FORM_EVENT_SUBMIT_WITHOUT_SELECTING_SUGGESTIONS_FAIL_LUHN_CHECK_CARD, 1);
@@ -5976,8 +5650,8 @@ TEST_P(AutofillMetricsIFrameTest,
test::CreateTestFormField("Year", "card_year", "", "text", &field);
form.fields.push_back(field);
field_types.push_back(CREDIT_CARD_EXP_2_DIGIT_YEAR);
- test::CreateTestFormField("Credit card", "card", "5105105105105100", "text",
- &field);
+ test::CreateTestFormField("Credit card", "cardnum", "5105105105105100",
+ "text", &field);
form.fields.push_back(field);
field_types.push_back(CREDIT_CARD_NUMBER);
@@ -5989,8 +5663,7 @@ TEST_P(AutofillMetricsIFrameTest,
base::HistogramTester histogram_tester;
autofill_manager().DidShowSuggestions(true /* is_new_popup */, form, field);
autofill_manager().OnAskForValuesToFillTest(form, field);
- autofill_manager().OnFormSubmitted(form, /*known_success=*/false,
- SubmissionSource::FORM_SUBMISSION);
+ SubmitForm(form);
histogram_tester.ExpectBucketCount(
"Autofill.FormEvents.CreditCard",
FORM_EVENT_SUBMIT_WITHOUT_SELECTING_SUGGESTIONS_UNKNOWN_CARD, 1);
@@ -6024,8 +5697,8 @@ TEST_P(AutofillMetricsIFrameTest,
test::CreateTestFormField("Year", "card_year", "", "text", &field);
form.fields.push_back(field);
field_types.push_back(CREDIT_CARD_EXP_2_DIGIT_YEAR);
- test::CreateTestFormField("Credit card", "card", "4111111111111111", "text",
- &field);
+ test::CreateTestFormField("Credit card", "cardnum", "4111111111111111",
+ "text", &field);
form.fields.push_back(field);
field_types.push_back(CREDIT_CARD_NUMBER);
@@ -6037,8 +5710,7 @@ TEST_P(AutofillMetricsIFrameTest,
base::HistogramTester histogram_tester;
autofill_manager().DidShowSuggestions(true /* is_new_popup */, form, field);
autofill_manager().OnAskForValuesToFillTest(form, field);
- autofill_manager().OnFormSubmitted(form, /*known_success=*/false,
- SubmissionSource::FORM_SUBMISSION);
+ SubmitForm(form);
histogram_tester.ExpectBucketCount(
"Autofill.FormEvents.CreditCard",
FORM_EVENT_SUBMIT_WITHOUT_SELECTING_SUGGESTIONS_KNOWN_CARD, 1);
@@ -6072,8 +5744,8 @@ TEST_P(AutofillMetricsIFrameTest,
test::CreateTestFormField("Year", "card_year", "", "text", &field);
form.fields.push_back(field);
field_types.push_back(CREDIT_CARD_EXP_2_DIGIT_YEAR);
- test::CreateTestFormField("Credit card", "card", "4111111111111111", "text",
- &field);
+ test::CreateTestFormField("Credit card", "cardnum", "4111111111111111",
+ "text", &field);
form.fields.push_back(field);
field_types.push_back(CREDIT_CARD_NUMBER);
@@ -6091,8 +5763,7 @@ TEST_P(AutofillMetricsIFrameTest,
autofill_manager().suggestion_generator()->MakeFrontendId(guid,
std::string()));
- autofill_manager().OnFormSubmitted(form, /*known_success=*/false,
- SubmissionSource::FORM_SUBMISSION);
+ SubmitForm(form);
histogram_tester.ExpectBucketCount(
"Autofill.FormEvents.CreditCard",
FORM_EVENT_SUBMIT_WITHOUT_SELECTING_SUGGESTIONS_KNOWN_CARD, 0);
@@ -6145,8 +5816,7 @@ TEST_F(AutofillMetricsTest, ShouldNotLogFormEventNoCardForAddressForm) {
base::HistogramTester histogram_tester;
autofill_manager().DidShowSuggestions(true /* is_new_popup */, form, field);
autofill_manager().OnAskForValuesToFillTest(form, field);
- autofill_manager().OnFormSubmitted(form, /*known_success=*/false,
- SubmissionSource::FORM_SUBMISSION);
+ SubmitForm(form);
histogram_tester.ExpectBucketCount(
"Autofill.FormEvents.Address",
FORM_EVENT_SUBMIT_WITHOUT_SELECTING_SUGGESTIONS_NO_CARD, 0);
@@ -6176,7 +5846,7 @@ TEST_P(AutofillMetricsIFrameTest, CreditCardSubmittedFormEvents) {
test::CreateTestFormField("Year", "card_year", "", "text", &field);
form.fields.push_back(field);
field_types.push_back(CREDIT_CARD_EXP_2_DIGIT_YEAR);
- test::CreateTestFormField("Credit card", "card", "", "text", &field);
+ test::CreateTestFormField("Credit card", "cardnum", "", "text", &field);
form.fields.push_back(field);
field_types.push_back(CREDIT_CARD_NUMBER);
@@ -6188,8 +5858,7 @@ TEST_P(AutofillMetricsIFrameTest, CreditCardSubmittedFormEvents) {
// Simulating submission with no filled data.
base::HistogramTester histogram_tester;
autofill_manager().OnAskForValuesToFillTest(form, field);
- autofill_manager().OnFormSubmitted(form, /*known_success=*/false,
- SubmissionSource::FORM_SUBMISSION);
+ SubmitForm(form);
histogram_tester.ExpectBucketCount(
"Autofill.FormEvents.CreditCard",
@@ -6221,8 +5890,7 @@ TEST_P(AutofillMetricsIFrameTest, CreditCardSubmittedFormEvents) {
base::HistogramTester histogram_tester;
autofill_manager().DidShowSuggestions(true /* is_new_popup */, form, field);
autofill_manager().OnAskForValuesToFillTest(form, field);
- autofill_manager().OnFormSubmitted(form, /*known_success=*/false,
- SubmissionSource::FORM_SUBMISSION);
+ SubmitForm(form);
histogram_tester.ExpectBucketCount(
"Autofill.FormEvents.CreditCard",
FORM_EVENT_SUGGESTION_SHOWN_SUBMITTED_ONCE, 1);
@@ -6266,8 +5934,7 @@ TEST_P(AutofillMetricsIFrameTest, CreditCardSubmittedFormEvents) {
base::HistogramTester histogram_tester;
autofill_manager().DidShowSuggestions(true /* is_new_popup */, form, field);
autofill_manager().OnAskForValuesToFillTest(form, field);
- autofill_manager().OnFormSubmitted(form, /*known_success=*/false,
- SubmissionSource::FORM_SUBMISSION);
+ SubmitForm(form);
// Trigger UploadFormDataAsyncCallback.
autofill_manager().Reset();
histogram_tester.ExpectBucketCount(
@@ -6315,8 +5982,7 @@ TEST_P(AutofillMetricsIFrameTest, CreditCardSubmittedFormEvents) {
mojom::RendererFormDataAction::kFill, 0, form, form.fields.front(),
autofill_manager().suggestion_generator()->MakeFrontendId(
guid, std::string()));
- autofill_manager().OnFormSubmitted(form, /*known_success=*/false,
- SubmissionSource::FORM_SUBMISSION);
+ SubmitForm(form);
histogram_tester.ExpectBucketCount(
"Autofill.FormEvents.CreditCard",
FORM_EVENT_LOCAL_SUGGESTION_WILL_SUBMIT_ONCE, 1);
@@ -6363,8 +6029,7 @@ TEST_P(AutofillMetricsIFrameTest, CreditCardSubmittedFormEvents) {
form.fields.front());
OnCreditCardFetchingSuccessful(u"6011000990139424",
/*is_virtual_card=*/true);
- autofill_manager().OnFormSubmitted(form, /*known_success=*/false,
- SubmissionSource::FORM_SUBMISSION);
+ SubmitForm(form);
histogram_tester.ExpectBucketCount(
"Autofill.FormEvents.CreditCard",
FORM_EVENT_VIRTUAL_CARD_SUGGESTION_WILL_SUBMIT_ONCE, 1);
@@ -6410,8 +6075,7 @@ TEST_P(AutofillMetricsIFrameTest, CreditCardSubmittedFormEvents) {
mojom::RendererFormDataAction::kFill, 0, form, form.fields.front(),
autofill_manager().suggestion_generator()->MakeFrontendId(
guid, std::string()));
- autofill_manager().OnFormSubmitted(form, /*known_success=*/false,
- SubmissionSource::FORM_SUBMISSION);
+ SubmitForm(form);
histogram_tester.ExpectBucketCount(
"Autofill.FormEvents.CreditCard",
FORM_EVENT_SERVER_SUGGESTION_WILL_SUBMIT_ONCE, 1);
@@ -6457,8 +6121,7 @@ TEST_P(AutofillMetricsIFrameTest, CreditCardSubmittedFormEvents) {
autofill_manager().suggestion_generator()->MakeFrontendId(
guid, std::string()));
OnCreditCardFetchingSuccessful(u"6011000990139424");
- autofill_manager().OnFormSubmitted(form, /*known_success=*/false,
- SubmissionSource::FORM_SUBMISSION);
+ SubmitForm(form);
histogram_tester.ExpectBucketCount(
"Autofill.FormEvents.CreditCard",
FORM_EVENT_MASKED_SERVER_CARD_SUGGESTION_FILLED, 1);
@@ -6507,8 +6170,7 @@ TEST_P(AutofillMetricsIFrameTest, CreditCardSubmittedFormEvents) {
// Simulating multiple submissions.
base::HistogramTester histogram_tester;
autofill_manager().OnAskForValuesToFillTest(form, field);
- autofill_manager().OnFormSubmitted(form, /*known_success=*/false,
- SubmissionSource::FORM_SUBMISSION);
+ SubmitForm(form);
VerifySubmitFormUkm(test_ukm_recorder_, form,
AutofillMetrics::NON_FILLABLE_FORM_OR_NEW_DATA,
@@ -6516,8 +6178,7 @@ TEST_P(AutofillMetricsIFrameTest, CreditCardSubmittedFormEvents) {
/* has_upi_vpa_field=*/false,
{FormType::kCreditCardForm});
- autofill_manager().OnFormSubmitted(form, /*known_success=*/false,
- SubmissionSource::FORM_SUBMISSION);
+ SubmitForm(form);
VerifyUkm(
test_ukm_recorder_, form, UkmFormSubmittedType::kEntryName,
@@ -6618,8 +6279,7 @@ TEST_P(AutofillMetricsIFrameTest, CreditCardSubmittedFormEvents) {
// interaction.
base::HistogramTester histogram_tester;
autofill_manager().DidShowSuggestions(true /* is_new_popup */, form, field);
- autofill_manager().OnFormSubmitted(form, /*known_success=*/false,
- SubmissionSource::FORM_SUBMISSION);
+ SubmitForm(form);
histogram_tester.ExpectBucketCount(
"Autofill.FormEvents.CreditCard",
FORM_EVENT_SUGGESTION_SHOWN_SUBMITTED_ONCE, 0);
@@ -6725,7 +6385,7 @@ TEST_P(AutofillMetricsIFrameTest, CreditCardWillSubmitFormEvents) {
test::CreateTestFormField("Year", "card_year", "", "text", &field);
form.fields.push_back(field);
field_types.push_back(CREDIT_CARD_EXP_2_DIGIT_YEAR);
- test::CreateTestFormField("Credit card", "card", "", "text", &field);
+ test::CreateTestFormField("Credit card", "cardnum", "", "text", &field);
form.fields.push_back(field);
field_types.push_back(CREDIT_CARD_NUMBER);
@@ -6737,8 +6397,7 @@ TEST_P(AutofillMetricsIFrameTest, CreditCardWillSubmitFormEvents) {
// Simulating submission with no filled data.
base::HistogramTester histogram_tester;
autofill_manager().OnAskForValuesToFillTest(form, field);
- autofill_manager().OnFormSubmitted(form, /*known_success=*/false,
- SubmissionSource::FORM_SUBMISSION);
+ SubmitForm(form);
histogram_tester.ExpectBucketCount(
"Autofill.FormEvents.CreditCard",
FORM_EVENT_NO_SUGGESTION_WILL_SUBMIT_ONCE, 1);
@@ -6762,8 +6421,7 @@ TEST_P(AutofillMetricsIFrameTest, CreditCardWillSubmitFormEvents) {
base::HistogramTester histogram_tester;
autofill_manager().DidShowSuggestions(true /* is_new_popup */, form, field);
autofill_manager().OnAskForValuesToFillTest(form, field);
- autofill_manager().OnFormSubmitted(form, /*known_success=*/false,
- SubmissionSource::FORM_SUBMISSION);
+ SubmitForm(form);
histogram_tester.ExpectBucketCount(
"Autofill.FormEvents.CreditCard",
FORM_EVENT_SUGGESTION_SHOWN_WILL_SUBMIT_ONCE, 1);
@@ -6791,8 +6449,7 @@ TEST_P(AutofillMetricsIFrameTest, CreditCardWillSubmitFormEvents) {
mojom::RendererFormDataAction::kFill, 0, form, form.fields.front(),
autofill_manager().suggestion_generator()->MakeFrontendId(
guid, std::string()));
- autofill_manager().OnFormSubmitted(form, /*known_success=*/false,
- SubmissionSource::FORM_SUBMISSION);
+ SubmitForm(form);
histogram_tester.ExpectBucketCount(
"Autofill.FormEvents.CreditCard",
FORM_EVENT_LOCAL_SUGGESTION_WILL_SUBMIT_ONCE, 1);
@@ -6822,8 +6479,7 @@ TEST_P(AutofillMetricsIFrameTest, CreditCardWillSubmitFormEvents) {
form.fields.front());
OnCreditCardFetchingSuccessful(u"6011000990139424",
/*is_virtual_card=*/true);
- autofill_manager().OnFormSubmitted(form, /*known_success=*/false,
- SubmissionSource::FORM_SUBMISSION);
+ SubmitForm(form);
histogram_tester.ExpectBucketCount(
"Autofill.FormEvents.CreditCard",
FORM_EVENT_VIRTUAL_CARD_SUGGESTION_WILL_SUBMIT_ONCE, 1);
@@ -6852,8 +6508,7 @@ TEST_P(AutofillMetricsIFrameTest, CreditCardWillSubmitFormEvents) {
mojom::RendererFormDataAction::kFill, 0, form, form.fields.front(),
autofill_manager().suggestion_generator()->MakeFrontendId(
guid, std::string()));
- autofill_manager().OnFormSubmitted(form, /*known_success=*/false,
- SubmissionSource::FORM_SUBMISSION);
+ SubmitForm(form);
histogram_tester.ExpectBucketCount(
"Autofill.FormEvents.CreditCard",
FORM_EVENT_SERVER_SUGGESTION_WILL_SUBMIT_ONCE, 1);
@@ -6911,10 +6566,8 @@ TEST_P(AutofillMetricsIFrameTest, CreditCardWillSubmitFormEvents) {
// Simulating multiple submissions.
base::HistogramTester histogram_tester;
autofill_manager().OnAskForValuesToFillTest(form, field);
- autofill_manager().OnFormSubmitted(form, /*known_success=*/false,
- SubmissionSource::FORM_SUBMISSION);
- autofill_manager().OnFormSubmitted(form, /*known_success=*/false,
- SubmissionSource::FORM_SUBMISSION);
+ SubmitForm(form);
+ SubmitForm(form);
histogram_tester.ExpectBucketCount(
"Autofill.FormEvents.CreditCard",
FORM_EVENT_NO_SUGGESTION_WILL_SUBMIT_ONCE, 1);
@@ -6986,8 +6639,7 @@ TEST_P(AutofillMetricsIFrameTest, CreditCardWillSubmitFormEvents) {
// interaction.
base::HistogramTester histogram_tester;
autofill_manager().DidShowSuggestions(true /* is_new_popup */, form, field);
- autofill_manager().OnFormSubmitted(form, /*known_success=*/false,
- SubmissionSource::FORM_SUBMISSION);
+ SubmitForm(form);
histogram_tester.ExpectBucketCount(
"Autofill.FormEvents.CreditCard",
FORM_EVENT_SUGGESTION_SHOWN_SUBMITTED_ONCE, 0);
@@ -7068,7 +6720,7 @@ TEST_F(AutofillMetricsTest, LogServerOfferFormEvents) {
test::CreateTestFormField("Year", "card_year", "", "text", &field);
form.fields.push_back(field);
field_types.push_back(CREDIT_CARD_EXP_2_DIGIT_YEAR);
- test::CreateTestFormField("Credit card", "card", "", "text", &field);
+ test::CreateTestFormField("Credit card", "cardnum", "", "text", &field);
form.fields.push_back(field);
field_types.push_back(CREDIT_CARD_NUMBER);
@@ -7143,8 +6795,7 @@ TEST_F(AutofillMetricsTest, LogServerOfferFormEvents) {
guid, std::string()));
OnDidGetRealPan(AutofillClient::PaymentsRpcResult::kSuccess,
"6011000990139424");
- autofill_manager().OnFormSubmitted(form, /*known_success=*/false,
- SubmissionSource::FORM_SUBMISSION);
+ SubmitForm(form);
EXPECT_THAT(
histogram_tester.GetAllSamples(
"Autofill.FormEvents.CreditCard.WithOffer"),
@@ -7192,8 +6843,7 @@ TEST_F(AutofillMetricsTest, LogServerOfferFormEvents) {
guid, std::string()));
OnDidGetRealPan(AutofillClient::PaymentsRpcResult::kSuccess,
"6011000990139424");
- autofill_manager().OnFormSubmitted(form, /*known_success=*/false,
- SubmissionSource::FORM_SUBMISSION);
+ SubmitForm(form);
histogram_tester.ExpectBucketCount(
"Autofill.FormEvents.CreditCard.WithOffer",
FORM_EVENT_SUGGESTIONS_SHOWN, 1);
@@ -7256,8 +6906,7 @@ TEST_F(AutofillMetricsTest, LogServerOfferFormEvents) {
guid, std::string()));
OnDidGetRealPan(AutofillClient::PaymentsRpcResult::kSuccess,
"6011000990139424");
- autofill_manager().OnFormSubmitted(form, /*known_success=*/false,
- SubmissionSource::FORM_SUBMISSION);
+ SubmitForm(form);
// Histograms without ".WithOffer" should be recorded.
histogram_tester.ExpectBucketCount("Autofill.FormEvents.CreditCard",
FORM_EVENT_SUGGESTIONS_SHOWN, 1);
@@ -7336,8 +6985,7 @@ TEST_F(AutofillMetricsTest, LogServerOfferFormEvents) {
// previously filled card info.
autofill_manager().OnAskForValuesToFillTest(form, field);
autofill_manager().DidShowSuggestions(true /* is_new_popup */, form, field);
- autofill_manager().OnFormSubmitted(form, /*known_success=*/false,
- SubmissionSource::FORM_SUBMISSION);
+ SubmitForm(form);
histogram_tester.ExpectBucketCount(
"Autofill.FormEvents.CreditCard.WithOffer",
FORM_EVENT_SUGGESTIONS_SHOWN, 2);
@@ -7395,8 +7043,7 @@ TEST_F(AutofillMetricsTest, LogServerOfferFormEvents) {
std::string());
// Submitting the form without the filled suggestion.
- autofill_manager().OnFormSubmitted(form, /*known_success=*/false,
- SubmissionSource::FORM_SUBMISSION);
+ SubmitForm(form);
histogram_tester.ExpectBucketCount(
"Autofill.FormEvents.CreditCard.WithOffer",
FORM_EVENT_SUGGESTIONS_SHOWN, 1);
@@ -7461,8 +7108,7 @@ TEST_F(AutofillMetricsTest, LogServerOfferFormEvents) {
mojom::RendererFormDataAction::kFill, 0, form, form.fields.back(),
autofill_manager().suggestion_generator()->MakeFrontendId(
guid, std::string()));
- autofill_manager().OnFormSubmitted(form, /*known_success=*/false,
- SubmissionSource::FORM_SUBMISSION);
+ SubmitForm(form);
EXPECT_THAT(
histogram_tester.GetAllSamples(
"Autofill.FormEvents.CreditCard.WithOffer"),
@@ -7523,12 +7169,8 @@ TEST_F(AutofillMetricsTest, MixedParsedFormEvents) {
field_types.push_back(CREDIT_CARD_VERIFICATION_CODE);
// Simulate seeing and parsing the form.
- std::vector<FormData> forms;
- forms.push_back(form);
-
base::HistogramTester histogram_tester;
- autofill_manager().OnFormsSeen(/*updated_forms=*/forms,
- /*removed_forms=*/{});
+ SeeForm(form);
histogram_tester.ExpectUniqueSample("Autofill.FormEvents.Address.WithNoData",
FORM_EVENT_DID_PARSE_FORM, 1);
histogram_tester.ExpectUniqueSample(
@@ -7560,12 +7202,8 @@ TEST_F(AutofillMetricsTest, AddressParsedFormEvents) {
field_types.push_back(ADDRESS_HOME_STREET_ADDRESS);
// Simulate seeing and parsing the form.
- std::vector<FormData> forms;
- forms.push_back(form);
-
base::HistogramTester histogram_tester;
- autofill_manager().OnFormsSeen(/*updated_forms=*/forms,
- /*removed_forms=*/{});
+ SeeForm(form);
histogram_tester.ExpectUniqueSample("Autofill.FormEvents.Address.WithNoData",
FORM_EVENT_DID_PARSE_FORM, 1);
@@ -8022,8 +7660,7 @@ TEST_F(AutofillMetricsTest, AddressSubmittedFormEvents) {
// Simulating submission with no filled data.
base::HistogramTester histogram_tester;
autofill_manager().OnAskForValuesToFillTest(form, field);
- autofill_manager().OnFormSubmitted(form, /*known_success=*/false,
- SubmissionSource::FORM_SUBMISSION);
+ SubmitForm(form);
histogram_tester.ExpectBucketCount(
"Autofill.FormEvents.Address",
FORM_EVENT_NO_SUGGESTION_WILL_SUBMIT_ONCE, 1);
@@ -8048,8 +7685,7 @@ TEST_F(AutofillMetricsTest, AddressSubmittedFormEvents) {
// triggered.
base::HistogramTester histogram_tester;
autofill_manager().OnAskForValuesToFillTest(form, field);
- autofill_manager().OnFormSubmitted(form, /*known_success=*/false,
- SubmissionSource::FORM_SUBMISSION);
+ SubmitForm(form);
// Trigger UploadFormDataAsyncCallback.
autofill_manager().Reset();
histogram_tester.ExpectBucketCount(
@@ -8075,8 +7711,7 @@ TEST_F(AutofillMetricsTest, AddressSubmittedFormEvents) {
base::HistogramTester histogram_tester;
autofill_manager().DidShowSuggestions(true /* is_new_popup */, form, field);
autofill_manager().OnAskForValuesToFillTest(form, field);
- autofill_manager().OnFormSubmitted(form, /*known_success=*/false,
- SubmissionSource::FORM_SUBMISSION);
+ SubmitForm(form);
histogram_tester.ExpectBucketCount(
"Autofill.FormEvents.Address",
FORM_EVENT_SUGGESTION_SHOWN_WILL_SUBMIT_ONCE, 1);
@@ -8099,8 +7734,7 @@ TEST_F(AutofillMetricsTest, AddressSubmittedFormEvents) {
mojom::RendererFormDataAction::kFill, 0, form, form.fields.front(),
autofill_manager().suggestion_generator()->MakeFrontendId(std::string(),
guid));
- autofill_manager().OnFormSubmitted(form, /*known_success=*/false,
- SubmissionSource::FORM_SUBMISSION);
+ SubmitForm(form);
histogram_tester.ExpectBucketCount(
"Autofill.FormEvents.Address",
FORM_EVENT_LOCAL_SUGGESTION_WILL_SUBMIT_ONCE, 1);
@@ -8117,10 +7751,8 @@ TEST_F(AutofillMetricsTest, AddressSubmittedFormEvents) {
// Simulating multiple submissions.
base::HistogramTester histogram_tester;
autofill_manager().OnAskForValuesToFillTest(form, field);
- autofill_manager().OnFormSubmitted(form, /*known_success=*/false,
- SubmissionSource::FORM_SUBMISSION);
- autofill_manager().OnFormSubmitted(form, /*known_success=*/false,
- SubmissionSource::FORM_SUBMISSION);
+ SubmitForm(form);
+ SubmitForm(form);
EXPECT_THAT(
histogram_tester.GetAllSamples("Autofill.FormEvents.Address"),
@@ -8144,8 +7776,7 @@ TEST_F(AutofillMetricsTest, AddressSubmittedFormEvents) {
// interaction.
base::HistogramTester histogram_tester;
autofill_manager().DidShowSuggestions(true /* is_new_popup */, form, field);
- autofill_manager().OnFormSubmitted(form, /*known_success=*/false,
- SubmissionSource::FORM_SUBMISSION);
+ SubmitForm(form);
EXPECT_THAT(
histogram_tester.GetAllSamples("Autofill.FormEvents.Address"),
@@ -8203,8 +7834,7 @@ TEST_F(AutofillMetricsTest, AddressWillSubmitFormEvents) {
// Simulating submission with no filled data.
base::HistogramTester histogram_tester;
autofill_manager().OnAskForValuesToFillTest(form, field);
- autofill_manager().OnFormSubmitted(form, /*known_success=*/false,
- SubmissionSource::FORM_SUBMISSION);
+ SubmitForm(form);
histogram_tester.ExpectBucketCount(
"Autofill.FormEvents.Address",
FORM_EVENT_NO_SUGGESTION_WILL_SUBMIT_ONCE, 1);
@@ -8223,8 +7853,7 @@ TEST_F(AutofillMetricsTest, AddressWillSubmitFormEvents) {
base::HistogramTester histogram_tester;
autofill_manager().DidShowSuggestions(true /* is_new_popup */, form, field);
autofill_manager().OnAskForValuesToFillTest(form, field);
- autofill_manager().OnFormSubmitted(form, /*known_success=*/false,
- SubmissionSource::FORM_SUBMISSION);
+ SubmitForm(form);
histogram_tester.ExpectBucketCount(
"Autofill.FormEvents.Address",
FORM_EVENT_SUGGESTION_SHOWN_WILL_SUBMIT_ONCE, 1);
@@ -8247,8 +7876,7 @@ TEST_F(AutofillMetricsTest, AddressWillSubmitFormEvents) {
mojom::RendererFormDataAction::kFill, 0, form, form.fields.front(),
autofill_manager().suggestion_generator()->MakeFrontendId(std::string(),
guid));
- autofill_manager().OnFormSubmitted(form, /*known_success=*/false,
- SubmissionSource::FORM_SUBMISSION);
+ SubmitForm(form);
histogram_tester.ExpectBucketCount(
"Autofill.FormEvents.Address",
FORM_EVENT_LOCAL_SUGGESTION_WILL_SUBMIT_ONCE, 1);
@@ -8266,10 +7894,8 @@ TEST_F(AutofillMetricsTest, AddressWillSubmitFormEvents) {
// Simulating multiple submissions.
base::HistogramTester histogram_tester;
autofill_manager().OnAskForValuesToFillTest(form, field);
- autofill_manager().OnFormSubmitted(form, /*known_success=*/false,
- SubmissionSource::FORM_SUBMISSION);
- autofill_manager().OnFormSubmitted(form, /*known_success=*/false,
- SubmissionSource::FORM_SUBMISSION);
+ SubmitForm(form);
+ SubmitForm(form);
EXPECT_THAT(
histogram_tester.GetAllSamples("Autofill.FormEvents.Address"),
BucketsInclude(
@@ -8301,8 +7927,7 @@ TEST_F(AutofillMetricsTest, AddressWillSubmitFormEvents) {
// interaction.
base::HistogramTester histogram_tester;
autofill_manager().DidShowSuggestions(true /* is_new_popup */, form, field);
- autofill_manager().OnFormSubmitted(form, /*known_success=*/false,
- SubmissionSource::FORM_SUBMISSION);
+ SubmitForm(form);
EXPECT_THAT(
histogram_tester.GetAllSamples("Autofill.FormEvents.Address"),
BucketsInclude(
@@ -8368,7 +7993,7 @@ TEST_F(AutofillMetricsTest, CreditCardFormEventsAreSegmented) {
test::CreateTestFormField("Year", "card_year", "", "text", &field);
form.fields.push_back(field);
field_types.push_back(CREDIT_CARD_EXP_2_DIGIT_YEAR);
- test::CreateTestFormField("Credit card", "card", "", "text", &field);
+ test::CreateTestFormField("Credit card", "cardnum", "", "text", &field);
form.fields.push_back(field);
field_types.push_back(CREDIT_CARD_NUMBER);
@@ -8683,13 +8308,11 @@ TEST_F(AutofillMetricsTest, AutofillFormSubmittedState) {
form.fields.push_back(field);
test::CreateTestFormField("Unknown", "unknown", "", "text", &field);
form.fields.push_back(field);
- std::vector<FormData> forms(1, form);
// Expect no notifications when the form is first seen.
{
base::HistogramTester histogram_tester;
- autofill_manager().OnFormsSeen(/*updated_forms=*/forms,
- /*removed_forms=*/{});
+ SeeForm(form);
histogram_tester.ExpectTotalCount("Autofill.FormSubmittedState", 0);
VerifyDeveloperEngagementUkm(
@@ -8705,8 +8328,7 @@ TEST_F(AutofillMetricsTest, AutofillFormSubmittedState) {
{
base::HistogramTester histogram_tester;
base::UserActionTester user_action_tester;
- autofill_manager().OnFormSubmitted(form, /*known_success=*/false,
- SubmissionSource::FORM_SUBMISSION);
+ SubmitForm(form);
histogram_tester.ExpectUniqueSample(
"Autofill.FormSubmittedState",
AutofillMetrics::NON_FILLABLE_FORM_OR_NEW_DATA, 1);
@@ -8738,13 +8360,11 @@ TEST_F(AutofillMetricsTest, AutofillFormSubmittedState) {
// Non fillable form.
form.fields[0].value = u"Unknown Person";
form.fields[1].value = u"unknown.person@gmail.com";
- forms.front() = form;
{
base::HistogramTester histogram_tester;
base::UserActionTester user_action_tester;
- autofill_manager().OnFormSubmitted(form, /*known_success=*/false,
- SubmissionSource::FORM_SUBMISSION);
+ SubmitForm(form);
histogram_tester.ExpectUniqueSample(
"Autofill.FormSubmittedState",
AutofillMetrics::NON_FILLABLE_FORM_OR_NEW_DATA, 1);
@@ -8777,14 +8397,12 @@ TEST_F(AutofillMetricsTest, AutofillFormSubmittedState) {
form.fields[0].value = u"Elvis Aaron Presley";
form.fields[1].value = u"theking@gmail.com";
form.fields[2].value = u"12345678901";
- forms.front() = form;
// Autofilled none with no suggestions shown.
{
base::HistogramTester histogram_tester;
base::UserActionTester user_action_tester;
- autofill_manager().OnFormSubmitted(form, /*known_success=*/false,
- SubmissionSource::FORM_SUBMISSION);
+ SubmitForm(form);
histogram_tester.ExpectUniqueSample(
"Autofill.FormSubmittedState",
AutofillMetrics::FILLABLE_FORM_AUTOFILLED_NONE_DID_NOT_SHOW_SUGGESTIONS,
@@ -8821,8 +8439,7 @@ TEST_F(AutofillMetricsTest, AutofillFormSubmittedState) {
{
base::HistogramTester histogram_tester;
base::UserActionTester user_action_tester;
- autofill_manager().OnFormSubmitted(form, /*known_success=*/false,
- SubmissionSource::FORM_SUBMISSION);
+ SubmitForm(form);
histogram_tester.ExpectUniqueSample(
"Autofill.FormSubmittedState",
AutofillMetrics::FILLABLE_FORM_AUTOFILLED_NONE_DID_SHOW_SUGGESTIONS, 1);
@@ -8866,14 +8483,12 @@ TEST_F(AutofillMetricsTest, AutofillFormSubmittedState) {
// Mark one of the fields as autofilled.
form.fields[1].is_autofilled = true;
- forms.front() = form;
// Autofilled some of the fields.
{
base::HistogramTester histogram_tester;
base::UserActionTester user_action_tester;
- autofill_manager().OnFormSubmitted(form, /*known_success=*/false,
- SubmissionSource::FORM_SUBMISSION);
+ SubmitForm(form);
histogram_tester.ExpectUniqueSample(
"Autofill.FormSubmittedState",
AutofillMetrics::FILLABLE_FORM_AUTOFILLED_SOME, 1);
@@ -8905,14 +8520,12 @@ TEST_F(AutofillMetricsTest, AutofillFormSubmittedState) {
// Mark all of the fillable fields as autofilled.
form.fields[0].is_autofilled = true;
form.fields[2].is_autofilled = true;
- forms.front() = form;
// Autofilled all the fields.
{
base::HistogramTester histogram_tester;
base::UserActionTester user_action_tester;
- autofill_manager().OnFormSubmitted(form, /*known_success=*/false,
- SubmissionSource::FORM_SUBMISSION);
+ SubmitForm(form);
histogram_tester.ExpectUniqueSample(
"Autofill.FormSubmittedState",
AutofillMetrics::FILLABLE_FORM_AUTOFILLED_ALL, 1);
@@ -8940,10 +8553,6 @@ TEST_F(AutofillMetricsTest, AutofillFormSubmittedState) {
VerifyUkm(test_ukm_recorder_, form, UkmFieldFillStatusType::kEntryName,
expected_field_fill_status_ukm_metrics);
}
-
- // Clear out the third field's value.
- form.fields[2].value = std::u16string();
- forms.front() = form;
}
// Verify that we correctly log the submitted form's state with fields
@@ -8970,15 +8579,12 @@ TEST_F(
&field);
form.fields.push_back(field);
- std::vector<FormData> forms(1, form);
-
// Verify if the form is otherwise filled with a field having
// |only_fill_when_focused|=true, we consider the form is all filled.
{
base::HistogramTester histogram_tester;
base::UserActionTester user_action_tester;
- autofill_manager().OnFormsSeen(/*updated_forms=*/forms,
- /*removed_forms=*/{});
+ SeeForm(form);
VerifyDeveloperEngagementUkm(
test_ukm_recorder_, form, /*is_for_credit_card=*/false,
{FormType::kAddressForm},
@@ -8992,8 +8598,7 @@ TEST_F(
form.fields[2].value = u"12345678901";
form.fields[2].is_autofilled = true;
- autofill_manager().OnFormSubmitted(form, /*known_success=*/false,
- SubmissionSource::FORM_SUBMISSION);
+ SubmitForm(form);
histogram_tester.ExpectUniqueSample(
"Autofill.FormSubmittedState",
AutofillMetrics::FILLABLE_FORM_AUTOFILLED_ALL, 1);
@@ -9100,13 +8705,10 @@ TEST_F(AutofillMetricsTest, UserHappinessFormInteraction_EmptyForm) {
form.action = GURL("http://example.com/submit.html");
form.main_frame_origin = url::Origin::Create(autofill_client_->form_origin());
- std::vector<FormData> forms(1, form);
-
// Expect a notification when the form is first seen.
{
base::HistogramTester histogram_tester;
- autofill_manager().OnFormsSeen(/*updated_forms=*/forms,
- /*removed_forms=*/{});
+ SeeForm(form);
histogram_tester.ExpectTotalCount("Autofill.UserHappiness", 0);
histogram_tester.ExpectTotalCount("Autofill.UserHappiness.CreditCard", 0);
histogram_tester.ExpectTotalCount("Autofill.UserHappiness.Address", 0);
@@ -9132,25 +8734,18 @@ TEST_F(AutofillMetricsTest, UserHappinessFormInteraction_CreditCardForm) {
// Construct a valid credit card form.
FormFieldData field;
- std::vector<ServerFieldType> field_types;
test::CreateTestFormField("Card Number", "card_number", "", "text", &field);
form.fields.push_back(field);
- field_types.push_back(CREDIT_CARD_NAME_FULL);
test::CreateTestFormField("Expiration", "cc_exp", "", "text", &field);
form.fields.push_back(field);
- field_types.push_back(CREDIT_CARD_EXP_MONTH);
test::CreateTestFormField("Verification", "verification", "", "text", &field);
form.fields.push_back(field);
- field_types.push_back(CREDIT_CARD_VERIFICATION_CODE);
-
- std::vector<FormData> forms(1, form);
// Expect a notification when the form is first seen.
{
SCOPED_TRACE("First seen");
base::HistogramTester histogram_tester;
- autofill_manager().OnFormsSeen(/*updated_forms=*/forms,
- /*removed_forms=*/{});
+ SeeForm(form);
histogram_tester.ExpectUniqueSample("Autofill.UserHappiness",
AutofillMetrics::FORMS_LOADED, 1);
histogram_tester.ExpectUniqueSample("Autofill.UserHappiness.CreditCard",
@@ -9161,8 +8756,7 @@ TEST_F(AutofillMetricsTest, UserHappinessFormInteraction_CreditCardForm) {
{
SCOPED_TRACE("Initial typing");
base::HistogramTester histogram_tester;
- autofill_manager().OnTextFieldDidChange(form, form.fields.front(),
- gfx::RectF(), TimeTicks());
+ ChangeTextField(form, form.fields.front());
histogram_tester.ExpectUniqueSample("Autofill.UserHappiness",
AutofillMetrics::USER_DID_TYPE, 1);
histogram_tester.ExpectUniqueSample("Autofill.UserHappiness.CreditCard",
@@ -9170,7 +8764,7 @@ TEST_F(AutofillMetricsTest, UserHappinessFormInteraction_CreditCardForm) {
}
autofill_manager().Reset();
- autofill_manager().AddSeenForm(form, field_types, field_types);
+ SeeForm(form);
// Simulate suggestions shown twice with separate popups.
{
@@ -9190,7 +8784,7 @@ TEST_F(AutofillMetricsTest, UserHappinessFormInteraction_CreditCardForm) {
}
autofill_manager().Reset();
- autofill_manager().AddSeenForm(form, field_types, field_types);
+ SeeForm(form);
// Simulate suggestions shown twice for a single edit (i.e. multiple
// keystrokes in a single field).
@@ -9225,7 +8819,7 @@ TEST_F(AutofillMetricsTest, UserHappinessFormInteraction_CreditCardForm) {
{
SCOPED_TRACE("Invoke autofill");
base::HistogramTester histogram_tester;
- autofill_manager().OnDidFillAutofillFormData(form, TimeTicks());
+ FillAutofillFormData(form);
histogram_tester.ExpectBucketCount("Autofill.UserHappiness",
AutofillMetrics::USER_DID_AUTOFILL, 1);
histogram_tester.ExpectBucketCount(
@@ -9246,11 +8840,9 @@ TEST_F(AutofillMetricsTest, UserHappinessFormInteraction_CreditCardForm) {
mojom::RendererFormDataAction::kFill, 0, form, form.fields.front(),
autofill_manager().suggestion_generator()->MakeFrontendId(
guid, std::string()));
- autofill_manager().OnTextFieldDidChange(form, form.fields.front(),
- gfx::RectF(), TimeTicks());
+ ChangeTextField(form, form.fields.front());
// Simulate a second keystroke; make sure we don't log the metric twice.
- autofill_manager().OnTextFieldDidChange(form, form.fields.front(),
- gfx::RectF(), TimeTicks());
+ ChangeTextField(form, form.fields.front());
histogram_tester.ExpectBucketCount(
"Autofill.UserHappiness",
AutofillMetrics::USER_DID_EDIT_AUTOFILLED_FIELD, 1);
@@ -9269,7 +8861,7 @@ TEST_F(AutofillMetricsTest, UserHappinessFormInteraction_CreditCardForm) {
{
SCOPED_TRACE("Invoke autofill again");
base::HistogramTester histogram_tester;
- autofill_manager().OnDidFillAutofillFormData(form, TimeTicks());
+ FillAutofillFormData(form);
histogram_tester.ExpectUniqueSample("Autofill.UserHappiness",
AutofillMetrics::USER_DID_AUTOFILL, 1);
histogram_tester.ExpectUniqueSample("Autofill.UserHappiness.CreditCard",
@@ -9280,8 +8872,7 @@ TEST_F(AutofillMetricsTest, UserHappinessFormInteraction_CreditCardForm) {
{
SCOPED_TRACE("Edit another autofilled field");
base::HistogramTester histogram_tester;
- autofill_manager().OnTextFieldDidChange(form, form.fields[1], gfx::RectF(),
- TimeTicks());
+ ChangeTextField(form, form.fields[1]);
histogram_tester.ExpectUniqueSample(
"Autofill.UserHappiness",
AutofillMetrics::USER_DID_EDIT_AUTOFILLED_FIELD, 1);
@@ -9311,13 +8902,10 @@ TEST_F(AutofillMetricsTest, UserHappinessFormInteraction_AddressForm) {
test::CreateTestFormField("Phone", "phone", "", "text", &field);
form.fields.push_back(field);
- std::vector<FormData> forms(1, form);
-
// Expect a notification when the form is first seen.
{
base::HistogramTester histogram_tester;
- autofill_manager().OnFormsSeen(/*updated_forms=*/forms,
- /*removed_forms=*/{});
+ SeeForm(form);
histogram_tester.ExpectUniqueSample("Autofill.UserHappiness",
AutofillMetrics::FORMS_LOADED, 1);
histogram_tester.ExpectUniqueSample("Autofill.UserHappiness.Address",
@@ -9327,8 +8915,7 @@ TEST_F(AutofillMetricsTest, UserHappinessFormInteraction_AddressForm) {
// Simulate typing.
{
base::HistogramTester histogram_tester;
- autofill_manager().OnTextFieldDidChange(form, form.fields.front(),
- gfx::RectF(), TimeTicks());
+ ChangeTextField(form, form.fields.front());
histogram_tester.ExpectUniqueSample("Autofill.UserHappiness",
AutofillMetrics::USER_DID_TYPE, 1);
histogram_tester.ExpectUniqueSample("Autofill.UserHappiness.Address",
@@ -9352,8 +8939,7 @@ TEST_F(AutofillMetricsTest, UserHappinessFormInteraction_AddressForm) {
}
autofill_manager().Reset();
- autofill_manager().OnFormsSeen(/*updated_forms=*/forms,
- /*removed_forms=*/{});
+ SeeForm(form);
// Simulate suggestions shown twice for a single edit (i.e. multiple
// keystrokes in a single field).
{
@@ -9384,7 +8970,7 @@ TEST_F(AutofillMetricsTest, UserHappinessFormInteraction_AddressForm) {
// Simulate invoking autofill.
{
base::HistogramTester histogram_tester;
- autofill_manager().OnDidFillAutofillFormData(form, TimeTicks());
+ FillAutofillFormData(form);
histogram_tester.ExpectBucketCount("Autofill.UserHappiness",
AutofillMetrics::USER_DID_AUTOFILL, 1);
histogram_tester.ExpectBucketCount(
@@ -9404,11 +8990,9 @@ TEST_F(AutofillMetricsTest, UserHappinessFormInteraction_AddressForm) {
mojom::RendererFormDataAction::kFill, 0, form, form.fields.front(),
autofill_manager().suggestion_generator()->MakeFrontendId(std::string(),
guid));
- autofill_manager().OnTextFieldDidChange(form, form.fields.front(),
- gfx::RectF(), TimeTicks());
+ ChangeTextField(form, form.fields.front());
// Simulate a second keystroke; make sure we don't log the metric twice.
- autofill_manager().OnTextFieldDidChange(form, form.fields.front(),
- gfx::RectF(), TimeTicks());
+ ChangeTextField(form, form.fields.front());
histogram_tester.ExpectBucketCount(
"Autofill.UserHappiness",
AutofillMetrics::USER_DID_EDIT_AUTOFILLED_FIELD, 1);
@@ -9426,7 +9010,7 @@ TEST_F(AutofillMetricsTest, UserHappinessFormInteraction_AddressForm) {
// Simulate invoking autofill again.
{
base::HistogramTester histogram_tester;
- autofill_manager().OnDidFillAutofillFormData(form, TimeTicks());
+ FillAutofillFormData(form);
histogram_tester.ExpectUniqueSample("Autofill.UserHappiness",
AutofillMetrics::USER_DID_AUTOFILL, 1);
histogram_tester.ExpectUniqueSample("Autofill.UserHappiness.Address",
@@ -9436,8 +9020,7 @@ TEST_F(AutofillMetricsTest, UserHappinessFormInteraction_AddressForm) {
// Simulate editing another autofilled field.
{
base::HistogramTester histogram_tester;
- autofill_manager().OnTextFieldDidChange(form, form.fields[1], gfx::RectF(),
- TimeTicks());
+ ChangeTextField(form, form.fields[1]);
histogram_tester.ExpectUniqueSample(
"Autofill.UserHappiness",
AutofillMetrics::USER_DID_EDIT_AUTOFILLED_FIELD, 1);
@@ -9573,8 +9156,6 @@ TEST_F(AutofillMetricsTest, FormFillDuration) {
test::CreateTestFormField("Phone", "phone", "", "text", &field);
form.fields.push_back(field);
- const std::vector<FormData> forms(1, form);
-
// Fill additional form.
FormData second_form = form;
second_form.host_frame = test::MakeLocalFrameToken();
@@ -9582,9 +9163,8 @@ TEST_F(AutofillMetricsTest, FormFillDuration) {
test::CreateTestFormField("Second Phone", "second_phone", "", "text", &field);
second_form.fields.push_back(field);
- std::vector<FormData> second_forms(1, second_form);
-
// Fill the field values for form submission.
+ FormData submitted_form = form;
form.fields[0].value = u"Elvis Aaron Presley";
form.fields[1].value = u"theking@gmail.com";
form.fields[2].value = u"12345678901";
@@ -9600,15 +9180,13 @@ TEST_F(AutofillMetricsTest, FormFillDuration) {
{
SCOPED_TRACE("Test 1");
base::HistogramTester histogram_tester;
- autofill_manager().OnFormsSeen(/*updated_forms=*/forms,
- /*removed_forms=*/{});
+ SeeForm(test::WithoutValues(form));
base::TimeTicks parse_time = autofill_manager()
.form_structures()
.begin()
->second->form_parsed_timestamp();
test_clock.SetNowTicks(parse_time + base::Microseconds(17));
- autofill_manager().OnFormSubmitted(form, /*known_success=*/false,
- SubmissionSource::FORM_SUBMISSION);
+ SubmitForm(form);
histogram_tester.ExpectTotalCount(
"Autofill.FillDuration.FromLoad.WithAutofill", 0);
@@ -9626,18 +9204,15 @@ TEST_F(AutofillMetricsTest, FormFillDuration) {
{
SCOPED_TRACE("Test 2");
base::HistogramTester histogram_tester;
- autofill_manager().OnFormsSeen(/*updated_forms=*/forms,
- /*removed_forms=*/{});
+ SeeForm(test::WithoutValues(form));
base::TimeTicks parse_time = autofill_manager()
.form_structures()
.begin()
->second->form_parsed_timestamp();
- autofill_manager().OnTextFieldDidChange(form, form.fields.front(),
- gfx::RectF(),
- parse_time + base::Microseconds(3));
+ ChangeTextField(form, form.fields.front(),
+ parse_time + base::Microseconds(3));
test_clock.SetNowTicks(parse_time + base::Microseconds(17));
- autofill_manager().OnFormSubmitted(form, /*known_success=*/false,
- SubmissionSource::FORM_SUBMISSION);
+ SubmitForm(form);
histogram_tester.ExpectTotalCount(
"Autofill.FillDuration.FromLoad.WithAutofill", 0);
@@ -9657,17 +9232,14 @@ TEST_F(AutofillMetricsTest, FormFillDuration) {
{
SCOPED_TRACE("Test 3");
base::HistogramTester histogram_tester;
- autofill_manager().OnFormsSeen(/*updated_forms=*/forms,
- /*removed_forms=*/{});
+ SeeForm(test::WithoutValues(form));
base::TimeTicks parse_time = autofill_manager()
.form_structures()
.begin()
->second->form_parsed_timestamp();
- autofill_manager().OnDidFillAutofillFormData(
- form, parse_time + base::Microseconds(5));
+ FillAutofillFormData(form, parse_time + base::Microseconds(5));
test_clock.SetNowTicks(parse_time + base::Microseconds(17));
- autofill_manager().OnFormSubmitted(form, /*known_success=*/false,
- SubmissionSource::FORM_SUBMISSION);
+ SubmitForm(form);
histogram_tester.ExpectUniqueSample(
"Autofill.FillDuration.FromLoad.WithAutofill", 16, 1);
@@ -9689,21 +9261,17 @@ TEST_F(AutofillMetricsTest, FormFillDuration) {
SCOPED_TRACE("Test 4");
base::HistogramTester histogram_tester;
- autofill_manager().OnFormsSeen(/*updated_forms=*/forms,
- /*removed_forms=*/{});
+ SeeForm(test::WithoutValues(form));
base::TimeTicks parse_time = autofill_manager()
.form_structures()
.begin()
->second->form_parsed_timestamp();
- autofill_manager().OnDidFillAutofillFormData(
- form, parse_time + base::Microseconds(5));
+ FillAutofillFormData(form, parse_time + base::Microseconds(5));
- autofill_manager().OnTextFieldDidChange(form, form.fields.front(),
- gfx::RectF(),
- parse_time + base::Microseconds(3));
+ ChangeTextField(form, form.fields.front(),
+ parse_time + base::Microseconds(3));
test_clock.SetNowTicks(parse_time + base::Microseconds(17));
- autofill_manager().OnFormSubmitted(form, /*known_success=*/false,
- SubmissionSource::FORM_SUBMISSION);
+ SubmitForm(form);
histogram_tester.ExpectUniqueSample(
"Autofill.FillDuration.FromLoad.WithAutofill", 16, 1);
@@ -9723,22 +9291,17 @@ TEST_F(AutofillMetricsTest, FormFillDuration) {
{
SCOPED_TRACE("Test 5");
base::HistogramTester histogram_tester;
- autofill_manager().OnFormsSeen(/*updated_forms=*/forms,
- /*removed_forms=*/{});
+ SeeForm(test::WithoutValues(form));
base::TimeTicks parse_time = autofill_manager()
.form_structures()
.begin()
->second->form_parsed_timestamp();
- autofill_manager().OnFormsSeen(/*updated_forms=*/second_forms,
- /*removed_forms=*/{});
- autofill_manager().OnDidFillAutofillFormData(
- form, parse_time + base::Microseconds(5));
- autofill_manager().OnTextFieldDidChange(form, form.fields.front(),
- gfx::RectF(),
- parse_time + base::Microseconds(3));
+ SeeForm(test::WithoutValues(second_form));
+ FillAutofillFormData(form, parse_time + base::Microseconds(5));
+ ChangeTextField(form, form.fields.front(),
+ parse_time + base::Microseconds(3));
test_clock.SetNowTicks(parse_time + base::Microseconds(17));
- autofill_manager().OnFormSubmitted(form, /*known_success=*/false,
- SubmissionSource::FORM_SUBMISSION);
+ SubmitForm(form);
histogram_tester.ExpectUniqueSample(
"Autofill.FillDuration.FromLoad.WithAutofill", 16, 1);
@@ -9758,18 +9321,15 @@ TEST_F(AutofillMetricsTest, FormFillDuration) {
{
SCOPED_TRACE("Test 6");
base::HistogramTester histogram_tester;
- autofill_manager().OnFormsSeen(/*updated_forms=*/forms,
- /*removed_forms=*/{});
- autofill_manager().OnFormsSeen(/*updated_forms=*/second_forms,
- /*removed_forms=*/{});
+ SeeForm(test::WithoutValues(form));
+ SeeForm(test::WithoutValues(second_form));
base::TimeTicks parse_time{};
for (const auto& kv : autofill_manager().form_structures()) {
if (kv.second->form_parsed_timestamp() > parse_time)
parse_time = kv.second->form_parsed_timestamp();
}
test_clock.SetNowTicks(parse_time + base::Microseconds(17));
- autofill_manager().OnFormSubmitted(second_form, /*known_success=*/false,
- SubmissionSource::FORM_SUBMISSION);
+ SubmitForm(second_form);
histogram_tester.ExpectTotalCount(
"Autofill.FillDuration.FromLoad.WithAutofill", 0);
@@ -10026,19 +9586,9 @@ TEST_F(AutofillMetricsTest, ProfileActionOnFormSubmitted) {
test::CreateTestFormField("Organization", "organization", "", "text", &field);
form.fields.push_back(field);
- std::vector<FormData> forms(1, form);
-
- // Fill second form.
FormData second_form = form;
- std::vector<FormData> second_forms(1, second_form);
-
- // Fill a third form.
FormData third_form = form;
- std::vector<FormData> third_forms(1, third_form);
-
- // Fill a fourth form.
FormData fourth_form = form;
- std::vector<FormData> fourth_forms(1, fourth_form);
// Fill the field values for the first form submission.
form.fields[0].value = u"Albert Canuck";
@@ -10070,10 +9620,8 @@ TEST_F(AutofillMetricsTest, ProfileActionOnFormSubmitted) {
// Expect to log NEW_PROFILE_CREATED for the metric since a new profile is
// submitted.
- autofill_manager().OnFormsSeen(/*updated_forms=*/forms,
- /*removed_forms=*/{});
- autofill_manager().OnFormSubmitted(form, /*known_success=*/false,
- SubmissionSource::FORM_SUBMISSION);
+ SeeForm(test::WithoutValues(form));
+ SubmitForm(form);
EXPECT_THAT(
histogram_tester.GetAllSamples("Autofill.ProfileActionOnFormSubmitted"),
BucketsAre(Bucket(AutofillMetrics::NEW_PROFILE_CREATED, 1),
@@ -10082,10 +9630,8 @@ TEST_F(AutofillMetricsTest, ProfileActionOnFormSubmitted) {
// Expect to log EXISTING_PROFILE_USED for the metric since the same profile
// is submitted.
- autofill_manager().OnFormsSeen(/*updated_forms=*/second_forms,
- /*removed_forms=*/{});
- autofill_manager().OnFormSubmitted(second_form, /*known_success=*/false,
- SubmissionSource::FORM_SUBMISSION);
+ SeeForm(test::WithoutValues(second_form));
+ SubmitForm(second_form);
EXPECT_THAT(
histogram_tester.GetAllSamples("Autofill.ProfileActionOnFormSubmitted"),
BucketsAre(Bucket(AutofillMetrics::NEW_PROFILE_CREATED, 1),
@@ -10094,10 +9640,8 @@ TEST_F(AutofillMetricsTest, ProfileActionOnFormSubmitted) {
// Expect to log NEW_PROFILE_CREATED for the metric since a new profile is
// submitted.
- autofill_manager().OnFormsSeen(/*updated_forms=*/third_forms,
- /*removed_forms=*/{});
- autofill_manager().OnFormSubmitted(third_form, /*known_success=*/false,
- SubmissionSource::FORM_SUBMISSION);
+ SeeForm(test::WithoutValues(third_form));
+ SubmitForm(third_form);
EXPECT_THAT(
histogram_tester.GetAllSamples("Autofill.ProfileActionOnFormSubmitted"),
BucketsAre(Bucket(AutofillMetrics::NEW_PROFILE_CREATED, 2),
@@ -10106,10 +9650,8 @@ TEST_F(AutofillMetricsTest, ProfileActionOnFormSubmitted) {
// Expect to log EXISTING_PROFILE_UPDATED for the metric since the profile was
// updated.
- autofill_manager().OnFormsSeen(/*updated_forms=*/fourth_forms,
- /*removed_forms=*/{});
- autofill_manager().OnFormSubmitted(fourth_form, /*known_success=*/false,
- SubmissionSource::FORM_SUBMISSION);
+ SeeForm(test::WithoutValues(fourth_form));
+ SubmitForm(fourth_form);
EXPECT_THAT(
histogram_tester.GetAllSamples("Autofill.ProfileActionOnFormSubmitted"),
BucketsAre(Bucket(AutofillMetrics::NEW_PROFILE_CREATED, 2),
@@ -10296,12 +9838,15 @@ TEST_F(AutofillMetricsTest, NonsecureCreditCardForm) {
test::CreateTestFormField("Name on card", "cc-name", "", "text", &field);
form.fields.push_back(field);
field_types.push_back(CREDIT_CARD_NAME_FULL);
- test::CreateTestFormField("Credit card", "card", "", "text", &field);
+ test::CreateTestFormField("Credit card", "cardnum", "", "text", &field);
form.fields.push_back(field);
field_types.push_back(CREDIT_CARD_NUMBER);
- test::CreateTestFormField("Month", "card_month", "", "text", &field);
+ test::CreateTestFormField("Month", "cardmonth", "", "text", &field);
form.fields.push_back(field);
field_types.push_back(CREDIT_CARD_EXP_MONTH);
+ test::CreateTestFormField("Expiration date", "expdate", "", "text", &field);
+ form.fields.push_back(field);
+ field_types.push_back(CREDIT_CARD_EXP_DATE_2_DIGIT_YEAR);
// Simulate having seen this form on page load.
// |form_structure| will be owned by `autofill_manager()`.
@@ -10318,8 +9863,7 @@ TEST_F(AutofillMetricsTest, NonsecureCreditCardForm) {
// Simulate submitting the credit card form.
{
base::HistogramTester histograms;
- autofill_manager().OnFormSubmitted(form, /*known_success=*/false,
- SubmissionSource::FORM_SUBMISSION);
+ SubmitForm(form);
histograms.ExpectBucketCount(
"Autofill.FormEvents.CreditCard.OnNonsecurePage",
FORM_EVENT_NO_SUGGESTION_SUBMITTED_ONCE, 1);
@@ -10357,12 +9901,12 @@ TEST_F(AutofillMetricsTest,
test::CreateTestFormField("Name on card", "cc-name", "", "text", &field);
form.fields.push_back(field);
field_types.push_back(CREDIT_CARD_NAME_FULL);
- test::CreateTestFormField("Credit card", "card", "", "text", &field);
+ test::CreateTestFormField("Credit card", "cardnum", "", "text", &field);
form.fields.push_back(field);
field_types.push_back(CREDIT_CARD_NUMBER);
- test::CreateTestFormField("Month", "card_month", "", "text", &field);
+ test::CreateTestFormField("Expiration date", "expdate", "", "text", &field);
form.fields.push_back(field);
- field_types.push_back(CREDIT_CARD_EXP_MONTH);
+ field_types.push_back(CREDIT_CARD_EXP_DATE_2_DIGIT_YEAR);
// Simulate having seen this form on page load.
// |form_structure| will be owned by `autofill_manager()`.
@@ -10379,8 +9923,7 @@ TEST_F(AutofillMetricsTest,
// Simulate submitting the credit card form.
{
base::HistogramTester histograms;
- autofill_manager().OnFormSubmitted(form, /*known_success=*/false,
- SubmissionSource::FORM_SUBMISSION);
+ SubmitForm(form);
histograms.ExpectBucketCount("Autofill.FormEvents.CreditCard",
FORM_EVENT_NO_SUGGESTION_WILL_SUBMIT_ONCE, 1);
histograms.ExpectBucketCount("Autofill.FormEvents.CreditCard",
@@ -10482,7 +10025,7 @@ TEST_F(AutofillMetricsTest, DISABLED_AutofillSuggestionShownTest) {
test::CreateTestFormField("Name on card", "cc-name", "", "text", &field);
form.fields.push_back(field);
field_types.push_back(CREDIT_CARD_NAME_FULL);
- test::CreateTestFormField("Credit card", "card", "", "text", &field);
+ test::CreateTestFormField("Credit card", "cardnum", "", "text", &field);
form.fields.push_back(field);
field_types.push_back(CREDIT_CARD_NUMBER);
test::CreateTestFormField("Month", "card_month", "", "text", &field);
@@ -10643,15 +10186,12 @@ TEST_F(AutofillMetricsTest, LogUserHappinessBySecurityLevel_FromFormEvents) {
test::CreateTestFormField("Phone", "phone", "", "text", &field);
form.fields.push_back(field);
- std::vector<FormData> forms(1, form);
-
// Simulate seeing the form.
{
base::HistogramTester histogram_tester;
autofill_client_->set_security_level(
security_state::SecurityLevel::DANGEROUS);
- autofill_manager().OnFormsSeen(/*updated_forms=*/forms,
- /*removed_forms=*/{});
+ SeeForm(form);
histogram_tester.ExpectBucketCount(
"Autofill.UserHappiness.Address.DANGEROUS",
AutofillMetrics::FORMS_LOADED, 1);
@@ -10934,7 +10474,7 @@ TEST_F(AutofillMetricsTest, FrameHasNoForm) {
// Verify that we correctly log metrics if a frame has
// autocomplete="one-time-code".
TEST_F(AutofillMetricsTest, FrameHasAutocompleteOneTimeCode) {
- FormData form;
+ FormData form; // Form with one time code.
form.host_frame = test::MakeLocalFrameToken();
form.unique_renderer_id = test::MakeFormRendererId();
form.name = u"TestForm";
@@ -10943,18 +10483,14 @@ TEST_F(AutofillMetricsTest, FrameHasAutocompleteOneTimeCode) {
form.main_frame_origin = url::Origin::Create(autofill_client_->form_origin());
FormFieldData field;
-
- std::vector<FormData> forms_with_one_time_code(1, form);
-
test::CreateTestFormField("", "", "", "password", &field);
field.autocomplete_attribute = "one-time-code";
- forms_with_one_time_code.back().fields.push_back(field);
+ form.fields.push_back(field);
test::CreateTestFormField("", "", "", "password", &field);
- forms_with_one_time_code.back().fields.push_back(field);
+ form.fields.push_back(field);
base::HistogramTester histogram_tester;
- autofill_manager().OnFormsSeen(
- /*updated_forms=*/forms_with_one_time_code, /*removed_forms=*/{});
+ SeeForm(form);
autofill_driver_.reset();
// Verifies that autocomplete="one-time-code" in a form is correctly recorded.
histogram_tester.ExpectBucketCount(
@@ -10968,7 +10504,7 @@ TEST_F(AutofillMetricsTest, FrameHasAutocompleteOneTimeCode) {
// Verify that we correctly log metrics if a frame does not have
// autocomplete="one-time-code".
TEST_F(AutofillMetricsTest, FrameDoesNotHaveAutocompleteOneTimeCode) {
- FormData form;
+ FormData form; // Form without one time code.
form.host_frame = test::MakeLocalFrameToken();
form.unique_renderer_id = test::MakeFormRendererId();
form.name = u"TestForm";
@@ -10977,14 +10513,11 @@ TEST_F(AutofillMetricsTest, FrameDoesNotHaveAutocompleteOneTimeCode) {
form.main_frame_origin = url::Origin::Create(autofill_client_->form_origin());
FormFieldData field;
- std::vector<FormData> forms_without_one_time_code(1, form);
-
test::CreateTestFormField("", "", "", "password", &field);
- forms_without_one_time_code.back().fields.push_back(field);
+ form.fields.push_back(field);
base::HistogramTester histogram_tester;
- autofill_manager().OnFormsSeen(
- /*updated_forms=*/forms_without_one_time_code, /*removed_forms=*/{});
+ SeeForm(form);
autofill_driver_.reset();
histogram_tester.ExpectBucketCount(
"Autofill.WebOTP.OneTimeCode.FromAutocomplete",
@@ -10997,7 +10530,7 @@ TEST_F(AutofillMetricsTest, FrameDoesNotHaveAutocompleteOneTimeCode) {
// Verify that we correctly log metrics when a phone number field does not have
// autocomplete attribute but there are at least 3 fields in the form.
TEST_F(AutofillMetricsTest, FrameHasPhoneNumberFieldWithoutAutocomplete) {
- FormData form;
+ FormData form; // Form with phone number.
form.host_frame = test::MakeLocalFrameToken();
form.unique_renderer_id = test::MakeFormRendererId();
form.name = u"TestForm";
@@ -11005,22 +10538,18 @@ TEST_F(AutofillMetricsTest, FrameHasPhoneNumberFieldWithoutAutocomplete) {
form.action = GURL("http://example.com/submit.html");
form.main_frame_origin = url::Origin::Create(autofill_client_->form_origin());
- FormFieldData field;
-
- std::vector<FormData> forms_with_phone_number(1, form);
-
// At least 3 fields are necessary for FormStructure to compute proper field
// types if autocomplete attribute value is not available.
+ FormFieldData field;
test::CreateTestFormField("Phone", "phone", "", "tel", &field);
- forms_with_phone_number.back().fields.push_back(field);
+ form.fields.push_back(field);
test::CreateTestFormField("Last Name", "lastname", "", "text", &field);
- forms_with_phone_number.back().fields.push_back(field);
+ form.fields.push_back(field);
test::CreateTestFormField("First Name", "firstname", "", "text", &field);
- forms_with_phone_number.back().fields.push_back(field);
+ form.fields.push_back(field);
base::HistogramTester histogram_tester;
- autofill_manager().OnFormsSeen(
- /*updated_forms=*/forms_with_phone_number, /*removed_forms=*/{});
+ SeeForm(form);
autofill_driver_.reset();
histogram_tester.ExpectBucketCount(
"Autofill.WebOTP.PhoneNumberCollection.ParseResult",
@@ -11033,7 +10562,7 @@ TEST_F(AutofillMetricsTest, FrameHasPhoneNumberFieldWithoutAutocomplete) {
// Verify that we correctly log metrics when a phone number field does not have
// autocomplete attribute and there are less than 3 fields in the form.
TEST_F(AutofillMetricsTest, FrameHasSinglePhoneNumberFieldWithoutAutocomplete) {
- FormData form;
+ FormData form; // Form with single phone number field.
form.host_frame = test::MakeLocalFrameToken();
form.unique_renderer_id = test::MakeFormRendererId();
form.name = u"TestForm";
@@ -11041,18 +10570,14 @@ TEST_F(AutofillMetricsTest, FrameHasSinglePhoneNumberFieldWithoutAutocomplete) {
form.action = GURL("http://example.com/submit.html");
form.main_frame_origin = url::Origin::Create(autofill_client_->form_origin());
- FormFieldData field;
- std::vector<FormData> forms_with_single_phone_number_field(1, form);
-
// At least 3 fields are necessary for FormStructure to compute proper field
// types if autocomplete attribute value is not available.
+ FormFieldData field;
test::CreateTestFormField("Phone", "phone", "", "tel", &field);
- forms_with_single_phone_number_field.back().fields.push_back(field);
+ form.fields.push_back(field);
base::HistogramTester histogram_tester;
- autofill_manager().OnFormsSeen(
- /*updated_forms=*/forms_with_single_phone_number_field,
- /*removed_forms=*/{});
+ SeeForm(form);
autofill_driver_.reset();
histogram_tester.ExpectBucketCount(
"Autofill.WebOTP.PhoneNumberCollection.ParseResult",
@@ -11065,14 +10590,12 @@ TEST_F(AutofillMetricsTest, FrameHasSinglePhoneNumberFieldWithoutAutocomplete) {
// Verify that we correctly log metrics when a phone number field has
// autocomplete attribute.
TEST_F(AutofillMetricsTest, FrameHasPhoneNumberFieldWithAutocomplete) {
- FormData form;
+ FormData form; // Form with phone number.
CreateSimpleForm(autofill_client_->form_origin(), form);
AddAutoCompleteFieldToForm("phone", form);
- std::vector<FormData> forms_with_phone_number(1, form);
base::HistogramTester histogram_tester;
- autofill_manager().OnFormsSeen(
- /*updated_forms=*/forms_with_phone_number, /*removed_forms=*/{});
+ SeeForm(form);
autofill_driver_.reset();
histogram_tester.ExpectBucketCount(
"Autofill.WebOTP.PhoneNumberCollection.ParseResult",
@@ -11094,14 +10617,11 @@ TEST_F(AutofillMetricsTest, FrameDoesNotHavePhoneNumberField) {
form.main_frame_origin = url::Origin::Create(autofill_client_->form_origin());
FormFieldData field;
- std::vector<FormData> forms_without_phone_number(1, form);
-
test::CreateTestFormField("", "", "", "password", &field);
- forms_without_phone_number.back().fields.push_back(field);
+ form.fields.push_back(field);
base::HistogramTester histogram_tester;
- autofill_manager().OnFormsSeen(
- /*updated_forms=*/forms_without_phone_number, /*removed_forms=*/{});
+ SeeForm(form);
autofill_driver_.reset();
histogram_tester.ExpectBucketCount(
"Autofill.WebOTP.PhoneNumberCollection.ParseResult",
@@ -11114,143 +10634,81 @@ TEST_F(AutofillMetricsTest, FrameDoesNotHavePhoneNumberField) {
// ContentAutofillDriver is not visible to TestAutofillDriver on iOS.
// In addition, WebOTP will not ship on iOS.
#if !BUILDFLAG(IS_IOS)
-// Verify that we correctly log PhoneCollectionMetricState::kNone.
-TEST_F(AutofillMetricsTest, WebOTPPhoneCollectionMetricsStateNone) {
- FormData form;
- CreateSimpleForm(autofill_client_->form_origin(), form);
- AddAutoCompleteFieldToForm("password", form);
- std::vector<FormData> forms(1, form);
- base::HistogramTester histogram_tester;
- autofill_manager().OnFormsSeen(/*updated_forms=*/forms,
- /*removed_forms=*/{});
- autofill_manager().ReportAutofillWebOTPMetrics(false);
- histogram_tester.ExpectBucketCount("Autofill.WebOTP.PhonePlusWebOTPPlusOTC",
- PhoneCollectionMetricState::kNone, 1);
- histogram_tester.ExpectTotalCount("Autofill.WebOTP.PhonePlusWebOTPPlusOTC",
- 1);
-}
-
-// Verify that we correctly log PhoneCollectionMetricState::kOTC.
-TEST_F(AutofillMetricsTest, WebOTPPhoneCollectionMetricsStateOTC) {
- FormData form;
- CreateSimpleForm(autofill_client_->form_origin(), form);
- AddAutoCompleteFieldToForm("one-time-code", form);
-
- std::vector<FormData> forms(1, form);
- base::HistogramTester histogram_tester;
- autofill_manager().OnFormsSeen(/*updated_forms=*/forms,
- /*removed_forms=*/{});
- autofill_manager().ReportAutofillWebOTPMetrics(false);
- histogram_tester.ExpectBucketCount("Autofill.WebOTP.PhonePlusWebOTPPlusOTC",
- PhoneCollectionMetricState::kOTC, 1);
- histogram_tester.ExpectTotalCount("Autofill.WebOTP.PhonePlusWebOTPPlusOTC",
- 1);
-}
-
-// Verify that we correctly log PhoneCollectionMetricState::kWebOTP.
-TEST_F(AutofillMetricsTest, WebOTPPhoneCollectionMetricsStateWebOTP) {
- // If WebOTP is used, even if there is no form on the page we still need to
- // report it.
- base::HistogramTester histogram_tester;
- autofill_manager().ReportAutofillWebOTPMetrics(true);
- histogram_tester.ExpectBucketCount("Autofill.WebOTP.PhonePlusWebOTPPlusOTC",
- PhoneCollectionMetricState::kWebOTP, 1);
- histogram_tester.ExpectTotalCount("Autofill.WebOTP.PhonePlusWebOTPPlusOTC",
- 1);
-}
-
-// Verify that we correctly log PhoneCollectionMetricState::kWebOTPPlusOTC.
-TEST_F(AutofillMetricsTest, WebOTPPhoneCollectionMetricsStateWebOTPPlusOTC) {
- FormData form;
- CreateSimpleForm(autofill_client_->form_origin(), form);
- AddAutoCompleteFieldToForm("one-time-code", form);
-
- std::vector<FormData> forms(1, form);
- base::HistogramTester histogram_tester;
- autofill_manager().OnFormsSeen(/*updated_forms=*/forms,
- /*removed_forms=*/{});
- autofill_manager().ReportAutofillWebOTPMetrics(true);
- histogram_tester.ExpectBucketCount("Autofill.WebOTP.PhonePlusWebOTPPlusOTC",
- PhoneCollectionMetricState::kWebOTPPlusOTC,
- 1);
- histogram_tester.ExpectTotalCount("Autofill.WebOTP.PhonePlusWebOTPPlusOTC",
- 1);
-}
-
-// Verify that we correctly log PhoneCollectionMetricState::kPhone.
-TEST_F(AutofillMetricsTest, WebOTPPhoneCollectionMetricsStatePhone) {
- FormData form;
- CreateSimpleForm(autofill_client_->form_origin(), form);
- AddAutoCompleteFieldToForm("tel", form);
-
- std::vector<FormData> forms(1, form);
- base::HistogramTester histogram_tester;
- autofill_manager().OnFormsSeen(/*updated_forms=*/forms,
- /*removed_forms=*/{});
- autofill_manager().ReportAutofillWebOTPMetrics(false);
- histogram_tester.ExpectBucketCount("Autofill.WebOTP.PhonePlusWebOTPPlusOTC",
- PhoneCollectionMetricState::kPhone, 1);
- histogram_tester.ExpectTotalCount("Autofill.WebOTP.PhonePlusWebOTPPlusOTC",
- 1);
-}
+struct WebOTPPhoneCollectionMetricsTestCase {
+ std::vector<std::string> autocomplete_field;
+ PhoneCollectionMetricState phone_collection_metric_state;
+ bool report_autofill_web_otp_metrics = false;
+};
-// Verify that we correctly log PhoneCollectionMetricState::kPhonePlusOTC.
-TEST_F(AutofillMetricsTest, WebOTPPhoneCollectionMetricsStatePhonePlusOTC) {
- FormData form;
- CreateSimpleForm(autofill_client_->form_origin(), form);
- AddAutoCompleteFieldToForm("tel", form);
- AddAutoCompleteFieldToForm("one-time-code", form);
+class WebOTPPhoneCollectionMetricsTest
+ : public AutofillMetricsTest,
+ public ::testing::WithParamInterface<
+ WebOTPPhoneCollectionMetricsTestCase> {};
- std::vector<FormData> forms(1, form);
- base::HistogramTester histogram_tester;
- autofill_manager().OnFormsSeen(/*updated_forms=*/forms,
- /*removed_forms=*/{});
- autofill_manager().ReportAutofillWebOTPMetrics(false);
- histogram_tester.ExpectBucketCount("Autofill.WebOTP.PhonePlusWebOTPPlusOTC",
- PhoneCollectionMetricState::kPhonePlusOTC,
- 1);
- histogram_tester.ExpectTotalCount("Autofill.WebOTP.PhonePlusWebOTPPlusOTC",
- 1);
-}
+INSTANTIATE_TEST_SUITE_P(
+ WebOTPPhoneCollectionMetricsTest,
+ WebOTPPhoneCollectionMetricsTest,
+ testing::Values(
+ // Verify that we correctly log PhoneCollectionMetricState::kNone.
+ WebOTPPhoneCollectionMetricsTestCase{{"password"},
+ PhoneCollectionMetricState::kNone},
+ // Verify that we correctly log PhoneCollectionMetricState::kOTC.
+ WebOTPPhoneCollectionMetricsTestCase{{"one-time-code"},
+ PhoneCollectionMetricState::kOTC},
+ // Verify that we correctly log PhoneCollectionMetricState::kWebOTP.
+ WebOTPPhoneCollectionMetricsTestCase{
+ {},
+ PhoneCollectionMetricState::kWebOTP,
+ true},
+ // Verify that we correctly log
+ // PhoneCollectionMetricState::kWebOTPPlusOTC.
+ WebOTPPhoneCollectionMetricsTestCase{
+ {"one-time-code"},
+ PhoneCollectionMetricState::kWebOTPPlusOTC,
+ true},
+ // Verify that we correctly log PhoneCollectionMetricState::kPhone.
+ WebOTPPhoneCollectionMetricsTestCase{
+ {"tel"},
+ PhoneCollectionMetricState::kPhone},
+ // Verify that we correctly log
+ // PhoneCollectionMetricState::kPhonePlusOTC.
+ WebOTPPhoneCollectionMetricsTestCase{
+ {"tel", "one-time-code"},
+ PhoneCollectionMetricState::kPhonePlusOTC},
+ // Verify that we correctly log
+ // PhoneCollectionMetricState::kPhonePlusWebOTP.
+ WebOTPPhoneCollectionMetricsTestCase{
+ {"tel"},
+ PhoneCollectionMetricState::kPhonePlusWebOTP,
+ true},
+ // Verify that we correctly log
+ // PhoneCollectionMetricState::kPhonePlusWebOTPPlusOTC.
+ WebOTPPhoneCollectionMetricsTestCase{
+ {"tel", "one-time-code"},
+ PhoneCollectionMetricState::kPhonePlusWebOTPPlusOTC,
+ true}));
+
+TEST_P(WebOTPPhoneCollectionMetricsTest,
+ TestWebOTPPhoneCollectionMetricsState) {
+ auto test_case = GetParam();
+
+ if (!test_case.autocomplete_field.empty()) {
+ FormData form;
+ CreateSimpleForm(autofill_client_->form_origin(), form);
+ for (const auto& autocomplete : test_case.autocomplete_field)
+ AddAutoCompleteFieldToForm(autocomplete, form);
-// Verify that we correctly log PhoneCollectionMetricState::kPhonePlusWebOTP.
-TEST_F(AutofillMetricsTest, WebOTPPhoneCollectionMetricsStatePhonePlusWebOTP) {
- FormData form;
- CreateSimpleForm(autofill_client_->form_origin(), form);
- AddAutoCompleteFieldToForm("tel", form);
+ SeeForm(form);
+ }
- std::vector<FormData> forms(1, form);
base::HistogramTester histogram_tester;
- autofill_manager().OnFormsSeen(/*updated_forms=*/forms,
- /*removed_forms=*/{});
- autofill_manager().ReportAutofillWebOTPMetrics(true);
- histogram_tester.ExpectBucketCount(
- "Autofill.WebOTP.PhonePlusWebOTPPlusOTC",
- PhoneCollectionMetricState::kPhonePlusWebOTP, 1);
- histogram_tester.ExpectTotalCount("Autofill.WebOTP.PhonePlusWebOTPPlusOTC",
- 1);
-}
+ autofill_manager().ReportAutofillWebOTPMetrics(
+ test_case.report_autofill_web_otp_metrics);
-// Verify that we correctly log
-// PhoneCollectionMetricState::kPhonePlusWebOTPPlusOTC.
-TEST_F(AutofillMetricsTest,
- WebOTPPhoneCollectionMetricsStatePhonePlusWebOTPPlusOTC) {
- FormData form;
- CreateSimpleForm(autofill_client_->form_origin(), form);
- AddAutoCompleteFieldToForm("tel", form);
- AddAutoCompleteFieldToForm("one-time-code", form);
-
- std::vector<FormData> forms(1, form);
- base::HistogramTester histogram_tester;
- autofill_manager().OnFormsSeen(/*updated_forms=*/forms,
- /*removed_forms=*/{});
- autofill_manager().ReportAutofillWebOTPMetrics(true);
- histogram_tester.ExpectBucketCount(
- "Autofill.WebOTP.PhonePlusWebOTPPlusOTC",
- PhoneCollectionMetricState::kPhonePlusWebOTPPlusOTC, 1);
- histogram_tester.ExpectTotalCount("Autofill.WebOTP.PhonePlusWebOTPPlusOTC",
- 1);
+ EXPECT_THAT(
+ histogram_tester.GetAllSamples("Autofill.WebOTP.PhonePlusWebOTPPlusOTC"),
+ BucketsAre(Bucket(test_case.phone_collection_metric_state, 1)));
}
// Verify that proper PhoneCollectionMetricsState is logged to UKM.
@@ -11266,10 +10724,8 @@ TEST_F(AutofillMetricsTest, WebOTPPhoneCollectionMetricsStateLoggedToUKM) {
// Document uses OntTimeCode
AddAutoCompleteFieldToForm("one-time-code", form);
- std::vector<FormData> forms(1, form);
base::HistogramTester histogram_tester;
- autofill_manager().OnFormsSeen(/*updated_forms=*/forms,
- /*removed_forms=*/{});
+ SeeForm(form);
autofill_manager().ReportAutofillWebOTPMetrics(true);
entries = test_ukm_recorder_->GetEntriesByName(
@@ -11300,20 +10756,17 @@ TEST_F(AutofillMetricsTest, AutocompleteOneTimeCodeFormFilledDuration) {
field.autocomplete_attribute = "one-time-code";
form.fields.push_back(field);
- std::vector<FormData> forms(1, form);
form.fields[0].value = u"123456";
{
base::HistogramTester histogram_tester;
- autofill_manager().OnFormsSeen(/*updated_forms=*/forms,
- /*removed_forms=*/{});
+ SeeForm(form);
base::TimeTicks parse_time = autofill_manager()
.form_structures()
.begin()
->second->form_parsed_timestamp();
test_clock.SetNowTicks(parse_time + base::Microseconds(17));
- autofill_manager().OnFormSubmitted(form, /*known_success=*/false,
- SubmissionSource::FORM_SUBMISSION);
+ SubmitForm(form);
histogram_tester.ExpectTotalCount(
"Autofill.WebOTP.OneTimeCode.FillDuration.FromLoad", 1);
@@ -11324,20 +10777,16 @@ TEST_F(AutofillMetricsTest, AutocompleteOneTimeCodeFormFilledDuration) {
{
base::HistogramTester histogram_tester;
- autofill_manager().OnFormsSeen(/*updated_forms=*/forms,
- /*removed_forms=*/{});
+ SeeForm(form);
base::TimeTicks parse_time = autofill_manager()
.form_structures()
.begin()
->second->form_parsed_timestamp();
- autofill_manager().OnDidFillAutofillFormData(
- form, parse_time + base::Microseconds(5));
- autofill_manager().OnTextFieldDidChange(form, form.fields.front(),
- gfx::RectF(),
- parse_time + base::Microseconds(3));
+ FillAutofillFormData(form, parse_time + base::Microseconds(5));
+ ChangeTextField(form, form.fields.front(),
+ parse_time + base::Microseconds(3));
test_clock.SetNowTicks(parse_time + base::Microseconds(17));
- autofill_manager().OnFormSubmitted(form, /*known_success=*/false,
- SubmissionSource::FORM_SUBMISSION);
+ SubmitForm(form);
histogram_tester.ExpectUniqueSample(
"Autofill.WebOTP.OneTimeCode.FillDuration.FromInteraction", 14, 1);
@@ -11450,9 +10899,7 @@ TEST_F(AutofillMetricsTest, LogNumberOfAutocompleteEntriesCleanedUp) {
TEST_F(AutofillMetricsTest, FormEventMetrics_BySyncState) {
FormData form;
FormStructure form_structure(form);
- std::vector<FormData> forms(1, form);
- autofill_manager().OnFormsSeen(/*updated_forms=*/forms,
- /*removed_forms=*/{});
+ SeeForm(form);
autofill_manager().Reset();
{
@@ -11574,8 +11021,7 @@ TEST_P(AutofillMetricsFunnelTest, LogFunnelMetrics) {
const bool user_submitted_form = GetParam() >= 4;
// Simulate that the autofill manager has seen this form on page load.
- autofill_manager().OnFormsSeen(/*updated_forms=*/{form},
- /*removed_forms=*/{});
+ SeeForm(form);
if (!user_saw_suggestion) {
// Remove the profile to prevent suggestion from being shown.
@@ -11604,8 +11050,7 @@ TEST_P(AutofillMetricsFunnelTest, LogFunnelMetrics) {
// Simulate form submission.
if (user_submitted_form) {
- autofill_manager().OnFormSubmitted(form, /*known_success=*/false,
- SubmissionSource::FORM_SUBMISSION);
+ SubmitForm(form);
}
ResetDriverToCommitMetrics();
@@ -11661,6 +11106,12 @@ TEST_P(AutofillMetricsFunnelTest, LogFunnelMetrics) {
"Autofill.Autocomplete.NotOff.FillingAcceptance.Address", 1, 1);
histogram_tester.ExpectTotalCount(
"Autofill.Autocomplete.Off.FillingAcceptance.Address", 0);
+ VerifyUkm(test_ukm_recorder_, form, UkmAutofillKeyMetricsType::kEntryName,
+ {{{UkmAutofillKeyMetricsType::kFillingReadinessName, 1},
+ {UkmAutofillKeyMetricsType::kFillingAcceptanceName, 1},
+ {UkmAutofillKeyMetricsType::kFillingCorrectnessName, 1},
+ {UkmAutofillKeyMetricsType::kFillingAssistanceName, 1},
+ {UkmAutofillKeyMetricsType::kFormTypesName, 2}}});
} else {
histogram_tester.ExpectTotalCount(
"Autofill.KeyMetrics.FillingReadiness.Address", 0);
@@ -11721,19 +11172,16 @@ TEST_F(AutofillMetricsFunnelTest, AblationState) {
base::HistogramTester histogram_tester;
// Simulate that the autofill manager has seen this form on page load.
- autofill_manager().OnFormsSeen(/*updated_forms=*/{form},
- /*removed_forms=*/{});
+ SeeForm(form);
// Simulate interacting with the form.
autofill_manager().OnAskForValuesToFillTest(form, form.fields[0]);
// Don't simulate a suggestion but simulate the user typing.
- autofill_manager().OnTextFieldDidChange(form, form.fields[0], gfx::RectF(),
- TimeTicks());
+ ChangeTextField(form, form.fields[0]);
// Simulate form submission.
- autofill_manager().OnFormSubmitted(form, /*known_success=*/false,
- SubmissionSource::FORM_SUBMISSION);
+ SubmitForm(form);
ResetDriverToCommitMetrics();
@@ -11806,13 +11254,11 @@ TEST_F(AutofillMetricsKeyMetricsTest, LogEmptyForm) {
base::HistogramTester histogram_tester;
// Simulate page load.
- autofill_manager().OnFormsSeen(/*updated_forms=*/{form_},
- /*removed_forms=*/{});
+ SeeForm(form_);
autofill_manager().OnAskForValuesToFillTest(form_, form_.fields[0]);
// Simulate form submission.
- autofill_manager().OnFormSubmitted(form_, false,
- SubmissionSource::FORM_SUBMISSION);
+ SubmitForm(form_);
ResetDriverToCommitMetrics();
@@ -11826,6 +11272,11 @@ TEST_F(AutofillMetricsKeyMetricsTest, LogEmptyForm) {
"Autofill.KeyMetrics.FillingAssistance.Address", 0, 1);
histogram_tester.ExpectTotalCount(
"Autofill.KeyMetrics.FormSubmission.NotAutofilled.Address", 0);
+
+ VerifyUkm(test_ukm_recorder_, form_, UkmAutofillKeyMetricsType::kEntryName,
+ {{{UkmAutofillKeyMetricsType::kFillingReadinessName, 1},
+ {UkmAutofillKeyMetricsType::kFillingAssistanceName, 0},
+ {UkmAutofillKeyMetricsType::kFormTypesName, 2}}});
}
// Validate Autofill.KeyMetrics.* in case the user has no address profile on
@@ -11835,19 +11286,15 @@ TEST_F(AutofillMetricsKeyMetricsTest, LogNoProfile) {
// Simulate that no data is available.
personal_data().ClearProfiles();
- autofill_manager().OnFormsSeen(/*updated_forms=*/{form_},
- /*removed_forms=*/{});
+ SeeForm(form_);
autofill_manager().OnAskForValuesToFillTest(form_, form_.fields[0]);
// Simulate user typing the address.
- autofill_manager().OnTextFieldDidChange(form_, form_.fields[0], gfx::RectF(),
- TimeTicks());
- autofill_manager().OnTextFieldDidChange(form_, form_.fields[1], gfx::RectF(),
- TimeTicks());
+ ChangeTextField(form_, form_.fields[0]);
+ ChangeTextField(form_, form_.fields[1]);
// Simulate form submission.
- autofill_manager().OnFormSubmitted(form_, false,
- SubmissionSource::FORM_SUBMISSION);
+ SubmitForm(form_);
ResetDriverToCommitMetrics();
@@ -11861,6 +11308,11 @@ TEST_F(AutofillMetricsKeyMetricsTest, LogNoProfile) {
"Autofill.KeyMetrics.FillingAssistance.Address", 0, 1);
histogram_tester.ExpectBucketCount(
"Autofill.KeyMetrics.FormSubmission.NotAutofilled.Address", 1, 1);
+
+ VerifyUkm(test_ukm_recorder_, form_, UkmAutofillKeyMetricsType::kEntryName,
+ {{{UkmAutofillKeyMetricsType::kFillingReadinessName, 0},
+ {UkmAutofillKeyMetricsType::kFillingAssistanceName, 0},
+ {UkmAutofillKeyMetricsType::kFormTypesName, 2}}});
}
// Validate Autofill.KeyMetrics.* in case the user does not accept a suggestion.
@@ -11868,21 +11320,17 @@ TEST_F(AutofillMetricsKeyMetricsTest, LogUserDoesNotAcceptSuggestion) {
base::HistogramTester histogram_tester;
// Simulate that suggestion is shown but user does not accept it.
- autofill_manager().OnFormsSeen(/*updated_forms=*/{form_},
- /*removed_forms=*/{});
+ SeeForm(form_);
autofill_manager().OnAskForValuesToFillTest(form_, form_.fields[0]);
autofill_manager().DidShowSuggestions(
/*has_autofill_suggestions=*/true, form_, form_.fields[0]);
// Simulate user typing the address.
- autofill_manager().OnTextFieldDidChange(form_, form_.fields[0], gfx::RectF(),
- TimeTicks());
- autofill_manager().OnTextFieldDidChange(form_, form_.fields[1], gfx::RectF(),
- TimeTicks());
+ ChangeTextField(form_, form_.fields[0]);
+ ChangeTextField(form_, form_.fields[1]);
// Simulate form submission.
- autofill_manager().OnFormSubmitted(form_, false,
- SubmissionSource::FORM_SUBMISSION);
+ SubmitForm(form_);
ResetDriverToCommitMetrics();
@@ -11896,6 +11344,12 @@ TEST_F(AutofillMetricsKeyMetricsTest, LogUserDoesNotAcceptSuggestion) {
"Autofill.KeyMetrics.FillingAssistance.Address", 0, 1);
histogram_tester.ExpectBucketCount(
"Autofill.KeyMetrics.FormSubmission.NotAutofilled.Address", 1, 1);
+
+ VerifyUkm(test_ukm_recorder_, form_, UkmAutofillKeyMetricsType::kEntryName,
+ {{{UkmAutofillKeyMetricsType::kFillingReadinessName, 1},
+ {UkmAutofillKeyMetricsType::kFillingAcceptanceName, 0},
+ {UkmAutofillKeyMetricsType::kFillingAssistanceName, 0},
+ {UkmAutofillKeyMetricsType::kFormTypesName, 2}}});
}
// Validate Autofill.KeyMetrics.* in case the user has to fix the filled data.
@@ -11903,8 +11357,7 @@ TEST_F(AutofillMetricsKeyMetricsTest, LogUserFixesFilledData) {
base::HistogramTester histogram_tester;
// Simulate that suggestion is shown and user accepts it.
- autofill_manager().OnFormsSeen(/*updated_forms=*/{form_},
- /*removed_forms=*/{});
+ SeeForm(form_);
autofill_manager().OnAskForValuesToFillTest(form_, form_.fields[0]);
autofill_manager().DidShowSuggestions(
/*has_autofill_suggestions=*/true, form_, form_.fields[0]);
@@ -11914,12 +11367,10 @@ TEST_F(AutofillMetricsKeyMetricsTest, LogUserFixesFilledData) {
kTestGuid));
// Simulate user fixing the address.
- autofill_manager().OnTextFieldDidChange(form_, form_.fields[1], gfx::RectF(),
- TimeTicks());
+ ChangeTextField(form_, form_.fields[1]);
// Simulate form submission.
- autofill_manager().OnFormSubmitted(form_, false,
- SubmissionSource::FORM_SUBMISSION);
+ SubmitForm(form_);
ResetDriverToCommitMetrics();
@@ -11933,6 +11384,13 @@ TEST_F(AutofillMetricsKeyMetricsTest, LogUserFixesFilledData) {
"Autofill.KeyMetrics.FillingAssistance.Address", 1, 1);
histogram_tester.ExpectBucketCount(
"Autofill.KeyMetrics.FormSubmission.Autofilled.Address", 1, 1);
+
+ VerifyUkm(test_ukm_recorder_, form_, UkmAutofillKeyMetricsType::kEntryName,
+ {{{UkmAutofillKeyMetricsType::kFillingReadinessName, 1},
+ {UkmAutofillKeyMetricsType::kFillingAcceptanceName, 1},
+ {UkmAutofillKeyMetricsType::kFillingCorrectnessName, 0},
+ {UkmAutofillKeyMetricsType::kFillingAssistanceName, 1},
+ {UkmAutofillKeyMetricsType::kFormTypesName, 2}}});
}
// Validate Autofill.KeyMetrics.* in case the user fixes the filled data but
@@ -11941,8 +11399,7 @@ TEST_F(AutofillMetricsKeyMetricsTest, LogUserFixesFilledDataButDoesNotSubmit) {
base::HistogramTester histogram_tester;
// Simulate that suggestion is shown and user accepts it.
- autofill_manager().OnFormsSeen(/*updated_forms=*/{form_},
- /*removed_forms=*/{});
+ SeeForm(form_);
autofill_manager().OnAskForValuesToFillTest(form_, form_.fields[0]);
autofill_manager().DidShowSuggestions(
/*has_autofill_suggestions=*/true, form_, form_.fields[0]);
@@ -11952,8 +11409,7 @@ TEST_F(AutofillMetricsKeyMetricsTest, LogUserFixesFilledDataButDoesNotSubmit) {
kTestGuid));
// Simulate user fixing the address.
- autofill_manager().OnTextFieldDidChange(form_, form_.fields[1], gfx::RectF(),
- TimeTicks());
+ ChangeTextField(form_, form_.fields[1]);
// Don't submit form.
@@ -11969,6 +11425,13 @@ TEST_F(AutofillMetricsKeyMetricsTest, LogUserFixesFilledDataButDoesNotSubmit) {
"Autofill.KeyMetrics.FillingAssistance.Address", 0);
histogram_tester.ExpectBucketCount(
"Autofill.KeyMetrics.FormSubmission.Autofilled.Address", 0, 1);
+
+ VerifyUkm(test_ukm_recorder_, form_, UkmAutofillKeyMetricsType::kEntryName,
+ {{{UkmAutofillKeyMetricsType::kFillingReadinessName, 0},
+ {UkmAutofillKeyMetricsType::kFillingAcceptanceName, 0},
+ {UkmAutofillKeyMetricsType::kFillingCorrectnessName, 0},
+ {UkmAutofillKeyMetricsType::kFillingAssistanceName, 0},
+ {UkmAutofillKeyMetricsType::kFormTypesName, 2}}});
}
TEST_F(AutofillMetricsTest, GetFieldTypeUserEditStatusMetric) {
@@ -12000,8 +11463,7 @@ TEST_F(AutofillMetricsTest, PageLanguageMetricsExpectedCase) {
// Simulate form submission.
base::HistogramTester histogram_tester;
- autofill_manager().OnFormSubmitted(form, /*known_success=*/false,
- SubmissionSource::FORM_SUBMISSION);
+ SubmitForm(form);
histogram_tester.ExpectUniqueSample(
"Autofill.ParsedFieldTypesUsingTranslatedPageLanguage", language_code, 1);
@@ -12024,8 +11486,7 @@ TEST_F(AutofillMetricsTest, PageLanguageMetricsInvalidLanguage) {
// Simulate form submission.
base::HistogramTester histogram_tester;
- autofill_manager().OnFormSubmitted(form, /*known_success=*/false,
- SubmissionSource::FORM_SUBMISSION);
+ SubmitForm(form);
histogram_tester.ExpectUniqueSample(
"Autofill.ParsedFieldTypesUsingTranslatedPageLanguage", 0, 1);
@@ -12068,8 +11529,7 @@ TEST_F(AutofillMetricsTest, AutofilledStateFieldSource) {
// Simulate form submission.
base::HistogramTester histogram_tester;
- autofill_manager().OnFormSubmitted(form, /*known_success=*/false,
- SubmissionSource::FORM_SUBMISSION);
+ SubmitForm(form);
histogram_tester.ExpectUniqueSample(
"Autofill.AutofilledFieldAtSubmission.ByStateSelectionField",
@@ -12080,22 +11540,22 @@ TEST_F(AutofillMetricsTest, AutofilledStateFieldSource) {
// Tests the following 4 cases when |kAutofillPreventOverridingPrefilledValues|
// is enabled:
-// 1. The field is not autofilled since it has a prefilled value but the value
+// 1. The field is not autofilled since it has an initial value but the value
// is edited before the form submission and is same as the value that was
// to be autofilled in the field.
-// |Autofill.IsValueNotAutofilledOverExistingValueSameAsSubmittedValue|
+// |Autofill.IsValueNotAutofilledOverExistingValueSameAsSubmittedValue2|
// should emit true for this case.
-// 2. The field is not autofilled since it has a prefilled value but the value
+// 2. The field is not autofilled since it has an initial value but the value
// is edited before the form submission and is different than the value that
// was to be autofilled in the field.
-// |Autofill.IsValueNotAutofilledOverExistingValueSameAsSubmittedValue|
+// |Autofill.IsValueNotAutofilledOverExistingValueSameAsSubmittedValue2|
// should emit false for this case.
-// 3. The field had a prefilled value that was similar to the value to be
+// 3. The field had an initial value that was similar to the value to be
// autofilled in the field.
-// |Autofill.IsValueNotAutofilledOverExistingValueSameAsSubmittedValue|
+// |Autofill.IsValueNotAutofilledOverExistingValueSameAsSubmittedValue2|
// should not record anything in this case.
// 4. Selection fields are always overridden by Autofill.
-// |Autofill.IsValueNotAutofilledOverExistingValueSameAsSubmittedValue|
+// |Autofill.IsValueNotAutofilledOverExistingValueSameAsSubmittedValue2|
// should not record anything in this case.
TEST_F(AutofillMetricsTest,
IsValueNotAutofilledOverExistingValueSameAsSubmittedValue) {
@@ -12106,20 +11566,23 @@ TEST_F(AutofillMetricsTest,
FormData form = test::GetFormData(
{.description_for_logging = "AutofilledStateFieldSource",
- .fields = {{.role = ServerFieldType::NAME_FULL},
- {.role = ServerFieldType::ADDRESS_HOME_CITY,
- .value = u"Sacremento"}, // Case #1
- {.role = ServerFieldType::ADDRESS_HOME_STATE,
- .value = u"CA",
- .form_control_type = "select-one",
- .select_options = {{u"TN", u"Tennesse"},
- {u"CA", u"California"},
- {u"WA", u"Washington DC"}}}, // Case #4
- {.role = ServerFieldType::ADDRESS_HOME_ZIP,
- .value = u"00000"}, // Case #2
- {.role = ServerFieldType::PHONE_HOME_WHOLE_NUMBER,
- .value = u"12345678901"}, // Case #3
- {.role = ServerFieldType::ADDRESS_HOME_COUNTRY}}});
+ .fields = {
+ {.role = ServerFieldType::NAME_FULL},
+ {.role = ServerFieldType::ADDRESS_HOME_CITY,
+ .value = u"Sacremento",
+ .properties_mask = FieldPropertiesFlags::kUserTyped}, // Case #1
+ {.role = ServerFieldType::ADDRESS_HOME_STATE,
+ .value = u"CA",
+ .form_control_type = "select-one",
+ .select_options = {{u"TN", u"Tennesse"},
+ {u"CA", u"California"},
+ {u"WA", u"Washington DC"}}}, // Case #4
+ {.role = ServerFieldType::ADDRESS_HOME_ZIP,
+ .value = u"00000",
+ .properties_mask = FieldPropertiesFlags::kUserTyped}, // Case #2
+ {.role = ServerFieldType::PHONE_HOME_WHOLE_NUMBER,
+ .value = u"12345678901"}, // Case #3
+ {.role = ServerFieldType::ADDRESS_HOME_COUNTRY}}});
std::vector<ServerFieldType> heuristic_types = {
NAME_FULL, ADDRESS_HOME_CITY, ADDRESS_HOME_STATE,
@@ -12129,7 +11592,8 @@ TEST_F(AutofillMetricsTest,
ADDRESS_HOME_ZIP, PHONE_HOME_WHOLE_NUMBER, ADDRESS_HOME_COUNTRY};
// Simulate having seen this form on page load.
- autofill_manager().AddSeenForm(form, heuristic_types, server_types);
+ autofill_manager().AddSeenForm(form, heuristic_types, server_types,
+ /*preserve_values_in_form_structure=*/true);
autofill_manager().OnAskForValuesToFillTest(form, form.fields[0]);
autofill_manager().DidShowSuggestions(
@@ -12144,25 +11608,22 @@ TEST_F(AutofillMetricsTest,
// Case #1: Change submitted value to expected autofilled value for the field.
// The histogram should emit true for this.
form.fields[1].value = u"Memphis";
- autofill_manager().OnTextFieldDidChange(form, form.fields[1], gfx::RectF(),
- TimeTicks());
+ ChangeTextField(form, form.fields[1]);
// Case #2: Change submitted value such that it different than expected
// autofilled value for the field. The histogram should emit false for this.
form.fields[3].value = u"00001";
- autofill_manager().OnTextFieldDidChange(form, form.fields[3], gfx::RectF(),
- TimeTicks());
+ ChangeTextField(form, form.fields[3]);
// Simulate form submission.
base::HistogramTester histogram_tester;
- autofill_manager().OnFormSubmitted(form, /*known_success=*/false,
- SubmissionSource::FORM_SUBMISSION);
+ SubmitForm(form);
histogram_tester.ExpectBucketCount(
- "Autofill.IsValueNotAutofilledOverExistingValueSameAsSubmittedValue",
+ "Autofill.IsValueNotAutofilledOverExistingValueSameAsSubmittedValue2",
true, 1);
histogram_tester.ExpectBucketCount(
- "Autofill.IsValueNotAutofilledOverExistingValueSameAsSubmittedValue",
+ "Autofill.IsValueNotAutofilledOverExistingValueSameAsSubmittedValue2",
false, 1);
}
@@ -12178,8 +11639,7 @@ TEST_F(AutofillMetricsTest, FormInteractionsAreCounted) {
// WHEN
// Simulate manual text field change.
const auto field = form.fields[0];
- autofill_manager().OnTextFieldDidChange(form, field, gfx::RectF(),
- TimeTicks());
+ ChangeTextField(form, field);
// Simulate Autocomplete filling twice.
autofill_manager().OnSingleFieldSuggestionSelected(
u"", POPUP_ITEM_ID_AUTOCOMPLETE_ENTRY);
@@ -12192,8 +11652,7 @@ TEST_F(AutofillMetricsTest, FormInteractionsAreCounted) {
autofill_manager().suggestion_generator()->MakeFrontendId(std::string(),
guid));
// Simulate form submission.
- autofill_manager().OnFormSubmitted(form, /*known_success=*/false,
- SubmissionSource::FORM_SUBMISSION);
+ SubmitForm(form);
// THEN
VerifySubmitFormUkm(
@@ -12215,8 +11674,7 @@ TEST_F(AutofillMetricsTest, FormInteractionsAreInitiallyZero) {
// WHEN
// Simulate form submission.
- autofill_manager().OnFormSubmitted(form, /*known_success=*/false,
- SubmissionSource::FORM_SUBMISSION);
+ SubmitForm(form);
// THEN
VerifySubmitFormUkm(
@@ -12306,15 +11764,6 @@ class AutofillMetricsCrossFrameFormTest : public AutofillMetricsTest {
this));
}
- void SeeForm() {
- std::vector<ServerFieldType> field_types = {
- CREDIT_CARD_NAME_FULL, CREDIT_CARD_NUMBER,
- CREDIT_CARD_EXP_DATE_4_DIGIT_YEAR, CREDIT_CARD_VERIFICATION_CODE};
- autofill_manager().AddSeenForm(form_, field_types, field_types);
- autofill_manager().OnFormsSeen(/*updated_forms=*/{form_},
- /*removed_forms=*/{});
- }
-
CreditCardAndCvc& fill_data() { return credit_card_with_cvc_; }
// Any call to FillForm() should be followed by a SetFormValues() call to
@@ -12351,11 +11800,6 @@ class AutofillMetricsCrossFrameFormTest : public AutofillMetricsTest {
}
}
- void SubmitForm() {
- autofill_manager().OnFormSubmitted(form_, /*known_success=*/false,
- SubmissionSource::FORM_SUBMISSION);
- }
-
FormFieldData& GetFieldById(FieldGlobalId field) {
auto it =
base::ranges::find(form_.fields, field, &FormFieldData::global_id);
@@ -12415,7 +11859,7 @@ TEST_F(AutofillMetricsSeamlessnessTest,
DoNotLogCreditCardSeamlessFillsMetricIfNotAutofilled) {
using UkmBuilder = ukm::builders::Autofill_CreditCardFill;
base::HistogramTester histogram_tester;
- SeeForm();
+ SeeForm(form_);
// Fake manual fill.
SetFormValues(
@@ -12426,7 +11870,7 @@ TEST_F(AutofillMetricsSeamlessnessTest,
// Fakes an Autofill.
// This fills nothing because all fields have been manually filled.
FillForm(FormFieldData());
- SubmitForm();
+ SubmitForm(form_);
ResetDriverToCommitMetrics();
for (auto fill : {kFills, kFillable}) {
@@ -12471,7 +11915,7 @@ TEST_F(AutofillMetricsSeamlessnessTest,
return histogram_tester.GetAllSamples(metric.str());
};
- SeeForm();
+ SeeForm(form_);
fill_data().cvc = u"";
@@ -12498,7 +11942,7 @@ TEST_F(AutofillMetricsSeamlessnessTest,
SetFormValues({CREDIT_CARD_NUMBER},
/*is_autofilled=*/true, /*is_user_typed=*/false);
- SubmitForm();
+ SubmitForm(form_);
ResetDriverToCommitMetrics();
// Bitmask metrics.
diff --git a/chromium/components/autofill/core/browser/metrics/form_events/form_event_logger_base.cc b/chromium/components/autofill/core/browser/metrics/form_events/form_event_logger_base.cc
index 41272e27bb5..d76b215fc93 100644
--- a/chromium/components/autofill/core/browser/metrics/form_events/form_event_logger_base.cc
+++ b/chromium/components/autofill/core/browser/metrics/form_events/form_event_logger_base.cc
@@ -154,6 +154,7 @@ void FormEventLoggerBase::OnWillSubmitForm(AutofillSyncSigninState sync_state,
if (has_logged_will_submit_)
return;
has_logged_will_submit_ = true;
+ submitted_form_types_ = form.GetFormTypes();
LogWillSubmitForm(form);
@@ -256,11 +257,11 @@ void FormEventLoggerBase::LogUkmInteractedWithForm(
}
void FormEventLoggerBase::RecordFunnelAndKeyMetrics() {
- LogBuffer funnel_rows;
- LogBuffer key_metrics_rows;
+ LogBuffer funnel_rows(IsLoggingActive(log_manager_));
+ LogBuffer key_metrics_rows(IsLoggingActive(log_manager_));
- funnel_rows << Tr{} << "Form Type: " << form_type_name_;
- key_metrics_rows << Tr{} << "Form Type: " << form_type_name_;
+ LOG_AF(funnel_rows) << Tr{} << "Form Type: " << form_type_name_;
+ LOG_AF(key_metrics_rows) << Tr{} << "Form Type: " << form_type_name_;
UmaHistogramBoolean("Autofill.Funnel.ParsedAsType." + form_type_name_,
has_parsed_form_);
@@ -270,28 +271,29 @@ void FormEventLoggerBase::RecordFunnelAndKeyMetrics() {
UmaHistogramBoolean(
"Autofill.Funnel.InteractionAfterParsedAsType." + form_type_name_,
has_logged_interacted_);
- funnel_rows << Tr{} << "InteractionAfterParsedAsType"
- << has_logged_interacted_;
+ LOG_AF(funnel_rows) << Tr{} << "InteractionAfterParsedAsType"
+ << has_logged_interacted_;
if (has_logged_interacted_) {
UmaHistogramBoolean(
"Autofill.Funnel.SuggestionAfterInteraction." + form_type_name_,
has_logged_suggestions_shown_);
- funnel_rows << Tr{} << "SuggestionAfterInteraction"
- << has_logged_suggestions_shown_;
+ LOG_AF(funnel_rows) << Tr{} << "SuggestionAfterInteraction"
+ << has_logged_suggestions_shown_;
}
if (has_logged_interacted_ && has_logged_suggestions_shown_) {
UmaHistogramBoolean(
"Autofill.Funnel.FillAfterSuggestion." + form_type_name_,
has_logged_suggestion_filled_);
- funnel_rows << Tr{} << "FillAfterSuggestion"
- << has_logged_suggestion_filled_;
+ LOG_AF(funnel_rows) << Tr{} << "FillAfterSuggestion"
+ << has_logged_suggestion_filled_;
}
if (has_logged_interacted_ && has_logged_suggestions_shown_ &&
has_logged_suggestion_filled_) {
UmaHistogramBoolean(
"Autofill.Funnel.SubmissionAfterFill." + form_type_name_,
has_logged_will_submit_);
- funnel_rows << Tr{} << "SubmissionAfterFill" << has_logged_will_submit_;
+ LOG_AF(funnel_rows) << Tr{} << "SubmissionAfterFill"
+ << has_logged_will_submit_;
}
// Log key success metrics, always preconditioned on a form submission (except
// for the Autofill.KeyMetrics.FormSubmission metrics which measure whether
@@ -304,16 +306,16 @@ void FormEventLoggerBase::RecordFunnelAndKeyMetrics() {
UmaHistogramBoolean(
"Autofill.KeyMetrics.FillingReadiness." + form_type_name_,
has_logged_data_to_fill_available_);
- key_metrics_rows << Tr{} << "FillingReadiness"
- << has_logged_data_to_fill_available_;
+ LOG_AF(key_metrics_rows)
+ << Tr{} << "FillingReadiness" << has_logged_data_to_fill_available_;
if (has_logged_suggestions_shown_) {
// Whether a user accepted a filling suggestion they saw for a form that
// was later submitted.
UmaHistogramBoolean(
"Autofill.KeyMetrics.FillingAcceptance." + form_type_name_,
has_logged_suggestion_filled_);
- key_metrics_rows << Tr{} << "FillingAcceptance"
- << has_logged_suggestion_filled_;
+ LOG_AF(key_metrics_rows)
+ << Tr{} << "FillingAcceptance" << has_logged_suggestion_filled_;
UmaHistogramBoolean(
base::StrCat({"Autofill.Autocomplete.",
(has_logged_autocomplete_off_ ? "Off" : "NotOff"),
@@ -326,15 +328,22 @@ void FormEventLoggerBase::RecordFunnelAndKeyMetrics() {
UmaHistogramBoolean(
"Autofill.KeyMetrics.FillingCorrectness." + form_type_name_,
!has_logged_edited_autofilled_field_);
- key_metrics_rows << Tr{} << "FillingCorrectness"
- << !has_logged_edited_autofilled_field_;
+ LOG_AF(key_metrics_rows) << Tr{} << "FillingCorrectness"
+ << !has_logged_edited_autofilled_field_;
}
// Whether a submitted form was filled.
UmaHistogramBoolean(
"Autofill.KeyMetrics.FillingAssistance." + form_type_name_,
has_logged_suggestion_filled_);
- key_metrics_rows << Tr{} << "FillingAssistance"
- << has_logged_suggestion_filled_;
+ LOG_AF(key_metrics_rows)
+ << Tr{} << "FillingAssistance" << has_logged_suggestion_filled_;
+
+ if (form_interactions_ukm_logger_) {
+ form_interactions_ukm_logger_->LogKeyMetrics(
+ submitted_form_types_, has_logged_data_to_fill_available_,
+ has_logged_suggestions_shown_, has_logged_edited_autofilled_field_,
+ has_logged_suggestion_filled_, intent_);
+ }
}
if (has_logged_typed_into_non_filled_field_ ||
has_logged_suggestion_filled_) {
@@ -345,20 +354,18 @@ void FormEventLoggerBase::RecordFunnelAndKeyMetrics() {
(has_logged_suggestion_filled_ ? "Autofilled." : "NotAutofilled."),
form_type_name_}),
has_logged_will_submit_);
- key_metrics_rows << Tr{} << "FormSubmission.Autofilled"
- << has_logged_suggestion_filled_;
- key_metrics_rows << Tr{} << "FormSubmission.Submission"
- << has_logged_will_submit_;
+ LOG_AF(key_metrics_rows)
+ << Tr{} << "FormSubmission.Autofilled" << has_logged_suggestion_filled_;
+ LOG_AF(key_metrics_rows)
+ << Tr{} << "FormSubmission.Submission" << has_logged_will_submit_;
}
- if (log_manager_) {
- log_manager_->Log() << LoggingScope::kMetrics << LogMessage::kFunnelMetrics
- << Tag{"table"} << std::move(funnel_rows)
- << CTag{"table"};
- log_manager_->Log() << LoggingScope::kMetrics << LogMessage::kKeyMetrics
- << Tag{"table"} << std::move(key_metrics_rows)
- << CTag{"table"};
- }
+ LOG_AF(log_manager_) << LoggingScope::kMetrics << LogMessage::kFunnelMetrics
+ << Tag{"table"} << std::move(funnel_rows)
+ << CTag{"table"};
+ LOG_AF(log_manager_) << LoggingScope::kMetrics << LogMessage::kKeyMetrics
+ << Tag{"table"} << std::move(key_metrics_rows)
+ << CTag{"table"};
}
void FormEventLoggerBase::RecordAblationMetrics() {
@@ -409,4 +416,9 @@ void FormEventLoggerBase::RecordAblationMetrics() {
}
}
+void FormEventLoggerBase::SetAutofillAssistantIntentForFilling(
+ const autofill_assistant::AutofillAssistantIntent intent) {
+ intent_ = intent;
+}
+
} // namespace autofill
diff --git a/chromium/components/autofill/core/browser/metrics/form_events/form_event_logger_base.h b/chromium/components/autofill/core/browser/metrics/form_events/form_event_logger_base.h
index cfd570010e3..fe0903a6657 100644
--- a/chromium/components/autofill/core/browser/metrics/form_events/form_event_logger_base.h
+++ b/chromium/components/autofill/core/browser/metrics/form_events/form_event_logger_base.h
@@ -16,7 +16,7 @@
#include "components/autofill/core/browser/metrics/form_events/form_events.h"
#include "components/autofill/core/browser/sync_utils.h"
#include "components/autofill/core/common/form_field_data.h"
-#include "third_party/abseil-cpp/absl/types/optional.h"
+#include "components/autofill_assistant/core/public/autofill_assistant_intent.h"
namespace autofill {
@@ -69,6 +69,9 @@ class FormEventLoggerBase {
void OnTypedIntoNonFilledField();
void OnEditedAutofilledField();
+ void SetAutofillAssistantIntentForFilling(
+ const autofill_assistant::AutofillAssistantIntent intent);
+
// See BrowserAutofillManager::SuggestionContext for the definitions of the
// AblationGroup parameters.
void SetAblationStatus(AblationGroup ablation_group,
@@ -139,6 +142,13 @@ class FormEventLoggerBase {
// The last field that was polled for suggestions.
FormFieldData last_polled_field_;
+ // The Autofill Assistant intent triggering Autofill, if existing
+ autofill_assistant::AutofillAssistantIntent intent_ =
+ autofill_assistant::AutofillAssistantIntent::UNDEFINED_INTENT;
+
+ // Form types of the submitted form
+ DenseSet<FormType> submitted_form_types_;
+
// Weak reference.
raw_ptr<AutofillMetrics::FormInteractionsUkmLogger>
form_interactions_ukm_logger_;
diff --git a/chromium/components/autofill/core/browser/metrics/payments/local_card_migration_metrics.cc b/chromium/components/autofill/core/browser/metrics/payments/local_card_migration_metrics.cc
new file mode 100644
index 00000000000..f506255fade
--- /dev/null
+++ b/chromium/components/autofill/core/browser/metrics/payments/local_card_migration_metrics.cc
@@ -0,0 +1,114 @@
+// Copyright 2022 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/metrics/payments/local_card_migration_metrics.h"
+
+#include "base/metrics/histogram_functions.h"
+#include "base/metrics/histogram_macros.h"
+
+namespace autofill::autofill_metrics {
+
+void LogLocalCardMigrationBubbleOfferMetric(
+ LocalCardMigrationBubbleOfferMetric metric,
+ bool is_reshow) {
+ DCHECK_LT(metric, NUM_LOCAL_CARD_MIGRATION_BUBBLE_OFFER_METRICS);
+ std::string histogram_name = "Autofill.LocalCardMigrationBubbleOffer.";
+ histogram_name += is_reshow ? "Reshows" : "FirstShow";
+ base::UmaHistogramEnumeration(histogram_name, metric,
+ NUM_LOCAL_CARD_MIGRATION_BUBBLE_OFFER_METRICS);
+}
+
+void LogLocalCardMigrationBubbleResultMetric(
+ LocalCardMigrationBubbleResultMetric metric,
+ bool is_reshow) {
+ DCHECK_LT(metric, NUM_LOCAL_CARD_MIGRATION_BUBBLE_RESULT_METRICS);
+ std::string suffix = is_reshow ? ".Reshows" : ".FirstShow";
+ base::UmaHistogramEnumeration(
+ "Autofill.LocalCardMigrationBubbleResult" + suffix, metric,
+ NUM_LOCAL_CARD_MIGRATION_BUBBLE_RESULT_METRICS);
+}
+
+void LogLocalCardMigrationDecisionMetric(
+ LocalCardMigrationDecisionMetric metric) {
+ UMA_HISTOGRAM_ENUMERATION("Autofill.LocalCardMigrationDecision", metric);
+}
+
+void LogLocalCardMigrationDialogOfferMetric(
+ LocalCardMigrationDialogOfferMetric metric) {
+ DCHECK_LT(metric, NUM_LOCAL_CARD_MIGRATION_DIALOG_OFFER_METRICS);
+ std::string histogram_name = "Autofill.LocalCardMigrationDialogOffer";
+ base::UmaHistogramEnumeration(histogram_name, metric,
+ NUM_LOCAL_CARD_MIGRATION_DIALOG_OFFER_METRICS);
+}
+
+void LogLocalCardMigrationDialogUserInteractionMetric(
+ const base::TimeDelta& duration,
+ LocalCardMigrationDialogUserInteractionMetric metric) {
+ DCHECK_LT(metric, NUM_LOCAL_CARD_MIGRATION_DIALOG_USER_INTERACTION_METRICS);
+ base::UmaHistogramEnumeration(
+ "Autofill.LocalCardMigrationDialogUserInteraction", metric,
+ NUM_LOCAL_CARD_MIGRATION_DIALOG_USER_INTERACTION_METRICS);
+
+ // Do not log duration metrics for
+ // LOCAL_CARD_MIGRATION_DIALOG_DELETE_CARD_ICON_CLICKED, as it can happen
+ // multiple times in one dialog.
+ std::string suffix;
+ switch (metric) {
+ case LOCAL_CARD_MIGRATION_DIALOG_CLOSED_SAVE_BUTTON_CLICKED:
+ suffix = "Accepted";
+ break;
+ case LOCAL_CARD_MIGRATION_DIALOG_CLOSED_CANCEL_BUTTON_CLICKED:
+ suffix = "Denied";
+ break;
+ case LOCAL_CARD_MIGRATION_DIALOG_CLOSED_VIEW_CARDS_BUTTON_CLICKED:
+ case LOCAL_CARD_MIGRATION_DIALOG_CLOSED_DONE_BUTTON_CLICKED:
+ suffix = "Closed";
+ break;
+ default:
+ return;
+ }
+
+ base::UmaHistogramLongTimes(
+ "Autofill.LocalCardMigrationDialogActiveDuration." + suffix, duration);
+}
+
+void LogLocalCardMigrationDialogUserSelectionPercentageMetric(int selected,
+ int total) {
+ UMA_HISTOGRAM_PERCENTAGE(
+ "Autofill.LocalCardMigrationDialogUserSelectionPercentage",
+ 100 * selected / total);
+}
+
+void LogLocalCardMigrationNotOfferedDueToMaxStrikesMetric(
+ AutofillMetrics::SaveTypeMetric metric) {
+ UMA_HISTOGRAM_ENUMERATION(
+ "Autofill.StrikeDatabase.LocalCardMigrationNotOfferedDueToMaxStrikes",
+ metric);
+}
+
+void LogLocalCardMigrationPromptMetric(
+ LocalCardMigrationOrigin local_card_migration_origin,
+ LocalCardMigrationPromptMetric metric) {
+ DCHECK_LT(metric, NUM_LOCAL_CARD_MIGRATION_PROMPT_METRICS);
+ std::string histogram_name = "Autofill.LocalCardMigrationOrigin.";
+ // Switch to different sub-histogram depending on local card migration origin.
+ switch (local_card_migration_origin) {
+ case LocalCardMigrationOrigin::UseOfLocalCard:
+ histogram_name += "UseOfLocalCard";
+ break;
+ case LocalCardMigrationOrigin::UseOfServerCard:
+ histogram_name += "UseOfServerCard";
+ break;
+ case LocalCardMigrationOrigin::SettingsPage:
+ histogram_name += "SettingsPage";
+ break;
+ default:
+ NOTREACHED();
+ return;
+ }
+ base::UmaHistogramEnumeration(histogram_name, metric,
+ NUM_LOCAL_CARD_MIGRATION_PROMPT_METRICS);
+}
+
+} // namespace autofill::autofill_metrics
diff --git a/chromium/components/autofill/core/browser/metrics/payments/local_card_migration_metrics.h b/chromium/components/autofill/core/browser/metrics/payments/local_card_migration_metrics.h
new file mode 100644
index 00000000000..0126c0594dc
--- /dev/null
+++ b/chromium/components/autofill/core/browser/metrics/payments/local_card_migration_metrics.h
@@ -0,0 +1,176 @@
+// Copyright 2022 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_METRICS_PAYMENTS_LOCAL_CARD_MIGRATION_METRICS_H_
+#define COMPONENTS_AUTOFILL_CORE_BROWSER_METRICS_PAYMENTS_LOCAL_CARD_MIGRATION_METRICS_H_
+
+#include "base/time/time.h"
+#include "components/autofill/core/browser/metrics/autofill_metrics.h"
+
+namespace autofill::autofill_metrics {
+
+// Metrics to track events when local credit card migration is offered.
+enum LocalCardMigrationBubbleOfferMetric {
+ // These values are persisted to logs. Entries should not be renumbered and
+ // numeric values should never be reused.
+
+ // The bubble is requested due to a credit card being used or
+ // local card migration icon in the omnibox being clicked.
+ LOCAL_CARD_MIGRATION_BUBBLE_REQUESTED = 0,
+ // The bubble is actually shown to the user.
+ LOCAL_CARD_MIGRATION_BUBBLE_SHOWN = 1,
+ NUM_LOCAL_CARD_MIGRATION_BUBBLE_OFFER_METRICS,
+};
+
+// Metrics to track user action result of the bubble when the bubble is
+// closed.
+enum LocalCardMigrationBubbleResultMetric {
+ // These values are persisted to logs. Entries should not be renumbered and
+ // numeric values should never be reused.
+
+ // The user explicitly accepted the offer.
+ LOCAL_CARD_MIGRATION_BUBBLE_ACCEPTED = 0,
+ // The user explicitly closed the bubble with the close button or ESC.
+ LOCAL_CARD_MIGRATION_BUBBLE_CLOSED = 1,
+ // The user did not interact with the bubble.
+ LOCAL_CARD_MIGRATION_BUBBLE_NOT_INTERACTED = 2,
+ // The bubble lost its focus and was deactivated.
+ LOCAL_CARD_MIGRATION_BUBBLE_LOST_FOCUS = 3,
+ // The reason why the prompt is closed is not clear. Possible reason is the
+ // logging function is invoked before the closed reason is correctly set.
+ LOCAL_CARD_MIGRATION_BUBBLE_RESULT_UNKNOWN = 4,
+ NUM_LOCAL_CARD_MIGRATION_BUBBLE_RESULT_METRICS,
+};
+
+// Metrics to record the decision on whether to offer local card migration.
+enum class LocalCardMigrationDecisionMetric {
+ // These values are persisted to logs. Entries should not be renumbered and
+ // numeric values should never be reused.
+
+ // All the required conditions are satisfied and main prompt is shown.
+ OFFERED = 0,
+ // Migration not offered because user uses new card.
+ NOT_OFFERED_USE_NEW_CARD = 1,
+ // Migration not offered because failed migration prerequisites.
+ NOT_OFFERED_FAILED_PREREQUISITES = 2,
+ // The Autofill StrikeDatabase decided not to allow offering migration
+ // because max strike count was reached.
+ NOT_OFFERED_REACHED_MAX_STRIKE_COUNT = 3,
+ // Migration not offered because no migratable cards.
+ NOT_OFFERED_NO_MIGRATABLE_CARDS = 4,
+ // Met the migration requirements but the request to Payments for upload
+ // details failed.
+ NOT_OFFERED_GET_UPLOAD_DETAILS_FAILED = 5,
+ // Abandoned the migration because no supported local cards were left after
+ // filtering out unsupported cards.
+ NOT_OFFERED_NO_SUPPORTED_CARDS = 6,
+ // User used a local card and they only have a single migratable local card
+ // on file, we will offer Upstream instead.
+ NOT_OFFERED_SINGLE_LOCAL_CARD = 7,
+ // User used an unsupported local card, we will abort the migration.
+ NOT_OFFERED_USE_UNSUPPORTED_LOCAL_CARD = 8,
+ // Legal message was invalid, we will abort the migration.
+ NOT_OFFERED_INVALID_LEGAL_MESSAGE = 9,
+ kMaxValue = NOT_OFFERED_INVALID_LEGAL_MESSAGE,
+};
+
+// Metrics to track events when local card migration dialog is offered.
+enum LocalCardMigrationDialogOfferMetric {
+ // These values are persisted to logs. Entries should not be renumbered and
+ // numeric values should never be reused.
+
+ // The dialog is shown to the user.
+ LOCAL_CARD_MIGRATION_DIALOG_SHOWN = 0,
+ // The dialog is not shown due to legal message being invalid.
+ LOCAL_CARD_MIGRATION_DIALOG_NOT_SHOWN_INVALID_LEGAL_MESSAGE = 1,
+ // The dialog is shown when migration feedback is available.
+ LOCAL_CARD_MIGRATION_DIALOG_FEEDBACK_SHOWN = 2,
+ // The dialog is shown when migration fails due to server error.
+ LOCAL_CARD_MIGRATION_DIALOG_FEEDBACK_SERVER_ERROR_SHOWN = 3,
+ NUM_LOCAL_CARD_MIGRATION_DIALOG_OFFER_METRICS,
+};
+
+// Metrics to track user interactions with the dialog.
+enum LocalCardMigrationDialogUserInteractionMetric {
+ // These values are persisted to logs. Entries should not be renumbered and
+ // numeric values should never be reused.
+
+ // The user explicitly accepts the offer by clicking the save button.
+ LOCAL_CARD_MIGRATION_DIALOG_CLOSED_SAVE_BUTTON_CLICKED = 0,
+ // The user explicitly denies the offer by clicking the cancel button.
+ LOCAL_CARD_MIGRATION_DIALOG_CLOSED_CANCEL_BUTTON_CLICKED = 1,
+ // The user clicks the legal message.
+ LOCAL_CARD_MIGRATION_DIALOG_LEGAL_MESSAGE_CLICKED = 2,
+ // The user clicks the view card button after successfully migrated cards.
+ LOCAL_CARD_MIGRATION_DIALOG_CLOSED_VIEW_CARDS_BUTTON_CLICKED = 3,
+ // The user clicks the done button to close dialog after migration.
+ LOCAL_CARD_MIGRATION_DIALOG_CLOSED_DONE_BUTTON_CLICKED = 4,
+ // The user clicks the trash icon to delete invalid card.
+ LOCAL_CARD_MIGRATION_DIALOG_DELETE_CARD_ICON_CLICKED = 5,
+ NUM_LOCAL_CARD_MIGRATION_DIALOG_USER_INTERACTION_METRICS,
+};
+
+// These metrics are logged for each local card migration origin. These are
+// used to derive the conversion rate for each triggering source.
+enum LocalCardMigrationPromptMetric {
+ // These values are persisted to logs. Entries should not be renumbered and
+ // numeric values should never be reused.
+
+ // The intermediate bubble is shown to the user.
+ INTERMEDIATE_BUBBLE_SHOWN = 0,
+ // The intermediate bubble is accepted by the user.
+ INTERMEDIATE_BUBBLE_ACCEPTED = 1,
+ // The main dialog is shown to the user.
+ MAIN_DIALOG_SHOWN = 2,
+ // The main dialog is accepted by the user.
+ MAIN_DIALOG_ACCEPTED = 3,
+ NUM_LOCAL_CARD_MIGRATION_PROMPT_METRICS,
+};
+
+// Local card migration origin denotes from where the migration is triggered.
+enum LocalCardMigrationOrigin {
+ // These values are persisted to logs. Entries should not be renumbered and
+ // numeric values should never be reused.
+
+ // Trigger when user submitted a form using local card.
+ UseOfLocalCard,
+ // Trigger when user submitted a form using server card.
+ UseOfServerCard,
+ // Trigger from settings page.
+ SettingsPage,
+};
+
+void LogLocalCardMigrationBubbleOfferMetric(
+ LocalCardMigrationBubbleOfferMetric metric,
+ bool is_reshow);
+
+void LogLocalCardMigrationBubbleResultMetric(
+ LocalCardMigrationBubbleResultMetric metric,
+ bool is_reshow);
+
+void LogLocalCardMigrationDecisionMetric(
+ LocalCardMigrationDecisionMetric metric);
+
+void LogLocalCardMigrationDialogOfferMetric(
+ LocalCardMigrationDialogOfferMetric metric);
+
+void LogLocalCardMigrationDialogUserInteractionMetric(
+ const base::TimeDelta& duration,
+ LocalCardMigrationDialogUserInteractionMetric metric);
+
+void LogLocalCardMigrationDialogUserSelectionPercentageMetric(int selected,
+ int total);
+
+// When local card migration is not offered due to max strike limit reached,
+// logs the occurrence.
+void LogLocalCardMigrationNotOfferedDueToMaxStrikesMetric(
+ AutofillMetrics::SaveTypeMetric metric);
+
+void LogLocalCardMigrationPromptMetric(
+ LocalCardMigrationOrigin local_card_migration_origin,
+ LocalCardMigrationPromptMetric metric);
+
+} // namespace autofill::autofill_metrics
+
+#endif // COMPONENTS_AUTOFILL_CORE_BROWSER_METRICS_PAYMENTS_LOCAL_CARD_MIGRATION_METRICS_H_
diff --git a/chromium/components/autofill/core/browser/metrics/payments/offers_metrics.cc b/chromium/components/autofill/core/browser/metrics/payments/offers_metrics.cc
index 4a7b997d46d..f82c7cb1ae7 100644
--- a/chromium/components/autofill/core/browser/metrics/payments/offers_metrics.cc
+++ b/chromium/components/autofill/core/browser/metrics/payments/offers_metrics.cc
@@ -7,11 +7,118 @@
#include <unordered_map>
#include "base/metrics/histogram_functions.h"
+#include "base/metrics/user_metrics.h"
#include "base/notreached.h"
#include "components/autofill/core/browser/data_model/autofill_offer_data.h"
namespace autofill::autofill_metrics {
+void LogOfferNotificationBubbleOfferMetric(
+ AutofillOfferData::OfferType offer_type,
+ bool is_reshow) {
+ std::string histogram_name = "Autofill.OfferNotificationBubbleOffer.";
+ // Switch to different sub-histogram depending on offer type being displayed.
+ switch (offer_type) {
+ case AutofillOfferData::OfferType::GPAY_CARD_LINKED_OFFER:
+ histogram_name += "CardLinkedOffer";
+ break;
+ case AutofillOfferData::OfferType::GPAY_PROMO_CODE_OFFER:
+ histogram_name += "GPayPromoCodeOffer";
+ break;
+ case AutofillOfferData::OfferType::FREE_LISTING_COUPON_OFFER:
+ histogram_name += "FreeListingCouponOffer";
+ break;
+ case AutofillOfferData::OfferType::UNKNOWN:
+ NOTREACHED();
+ return;
+ }
+ base::UmaHistogramBoolean(histogram_name, is_reshow);
+}
+
+void LogOfferNotificationBubblePromoCodeButtonClicked(
+ AutofillOfferData::OfferType offer_type) {
+ std::string histogram_name =
+ "Autofill.OfferNotificationBubblePromoCodeButtonClicked.";
+ // Switch to different sub-histogram depending on offer type being displayed.
+ // Card-linked offers do not have a promo code button.
+ switch (offer_type) {
+ case AutofillOfferData::OfferType::GPAY_PROMO_CODE_OFFER:
+ histogram_name += "GPayPromoCodeOffer";
+ break;
+ case AutofillOfferData::OfferType::FREE_LISTING_COUPON_OFFER:
+ histogram_name += "FreeListingCouponOffer";
+ break;
+ case AutofillOfferData::OfferType::GPAY_CARD_LINKED_OFFER:
+ case AutofillOfferData::OfferType::UNKNOWN:
+ NOTREACHED();
+ return;
+ }
+ base::UmaHistogramBoolean(histogram_name, true);
+}
+
+void LogOfferNotificationBubbleResultMetric(
+ AutofillOfferData::OfferType offer_type,
+ OfferNotificationBubbleResultMetric metric,
+ bool is_reshow) {
+ DCHECK_LE(metric, OfferNotificationBubbleResultMetric::kMaxValue);
+ std::string histogram_name = "Autofill.OfferNotificationBubbleResult.";
+ // Switch to different sub-histogram depending on offer type being displayed.
+ switch (offer_type) {
+ case AutofillOfferData::OfferType::GPAY_CARD_LINKED_OFFER:
+ histogram_name += "CardLinkedOffer.";
+ break;
+ case AutofillOfferData::OfferType::GPAY_PROMO_CODE_OFFER:
+ histogram_name += "GPayPromoCodeOffer.";
+ break;
+ case AutofillOfferData::OfferType::FREE_LISTING_COUPON_OFFER:
+ histogram_name += "FreeListingCouponOffer.";
+ break;
+ case AutofillOfferData::OfferType::UNKNOWN:
+ NOTREACHED();
+ return;
+ }
+ // Add subhistogram for |is_reshow| decision.
+ histogram_name += is_reshow ? "Reshows" : "FirstShow";
+ base::UmaHistogramEnumeration(histogram_name, metric);
+}
+
+void LogOfferNotificationBubbleSuppressed(
+ AutofillOfferData::OfferType offer_type) {
+ std::string histogram_name = "Autofill.OfferNotificationBubbleSuppressed.";
+ // Switch to different sub-histogram depending on offer type being suppressed.
+ // Card-linked offers will not be suppressed.
+ switch (offer_type) {
+ case AutofillOfferData::OfferType::GPAY_PROMO_CODE_OFFER:
+ histogram_name += "GPayPromoCodeOffer";
+ break;
+ case AutofillOfferData::OfferType::FREE_LISTING_COUPON_OFFER:
+ histogram_name += "FreeListingCouponOffer";
+ break;
+ case AutofillOfferData::OfferType::GPAY_CARD_LINKED_OFFER:
+ case AutofillOfferData::OfferType::UNKNOWN:
+ NOTREACHED();
+ return;
+ }
+ base::UmaHistogramBoolean(histogram_name, true);
+}
+
+void LogOfferNotificationInfoBarDeepLinkClicked() {
+ base::RecordAction(base::UserMetricsAction(
+ "Autofill_OfferNotificationInfoBar_DeepLinkClicked"));
+}
+
+void LogOfferNotificationInfoBarResultMetric(
+ OfferNotificationInfoBarResultMetric metric) {
+ DCHECK_LE(metric, OfferNotificationInfoBarResultMetric::kMaxValue);
+ base::UmaHistogramEnumeration(
+ "Autofill.OfferNotificationInfoBarResult.CardLinkedOffer", metric);
+}
+
+void LogOfferNotificationInfoBarShown() {
+ base::UmaHistogramBoolean(
+ "Autofill.OfferNotificationInfoBarOffer.CardLinkedOffer", true);
+}
+
void LogStoredOfferMetrics(
const std::vector<std::unique_ptr<AutofillOfferData>>& offers) {
std::unordered_map<AutofillOfferData::OfferType, int> offer_count;
@@ -25,27 +132,39 @@ void LogStoredOfferMetrics(
offer_count[offer->GetOfferType()]++;
+ std::string related_merchant_count_histogram_name =
+ "Autofill.Offer.StoredOfferRelatedMerchantCount";
+ // Switch to different sub-histogram depending on offer type being
+ // displayed.
+ switch (offer->GetOfferType()) {
+ case AutofillOfferData::OfferType::GPAY_PROMO_CODE_OFFER:
+ related_merchant_count_histogram_name += ".GPayPromoCodeOffer";
+ break;
+ case AutofillOfferData::OfferType::GPAY_CARD_LINKED_OFFER:
+ related_merchant_count_histogram_name += ".CardLinkedOffer";
+ break;
+ case AutofillOfferData::OfferType::FREE_LISTING_COUPON_OFFER:
+ case AutofillOfferData::OfferType::UNKNOWN:
+ NOTREACHED();
+ continue;
+ }
+ base::UmaHistogramCounts1000(related_merchant_count_histogram_name,
+ offer->GetMerchantOrigins().size());
+
if (offer->GetOfferType() ==
AutofillOfferData::OfferType::GPAY_CARD_LINKED_OFFER) {
- base::UmaHistogramCounts1000(
- "Autofill.Offer.StoredOfferRelatedMerchantCount",
- offer->GetMerchantOrigins().size());
base::UmaHistogramCounts1000("Autofill.Offer.StoredOfferRelatedCardCount",
offer->GetEligibleInstrumentIds().size());
}
}
- if (offer_count[AutofillOfferData::OfferType::GPAY_PROMO_CODE_OFFER] > 0) {
- base::UmaHistogramCounts1000(
- "Autofill.Offer.StoredOfferCount.GPayPromoCodeOffer",
- offer_count[AutofillOfferData::OfferType::GPAY_PROMO_CODE_OFFER]);
- }
+ base::UmaHistogramCounts1000(
+ "Autofill.Offer.StoredOfferCount2.GPayPromoCodeOffer",
+ offer_count[AutofillOfferData::OfferType::GPAY_PROMO_CODE_OFFER]);
- if (offer_count[AutofillOfferData::OfferType::GPAY_CARD_LINKED_OFFER] > 0) {
- base::UmaHistogramCounts1000(
- "Autofill.Offer.StoredOfferCount.CardLinkedOffer",
- offer_count[AutofillOfferData::OfferType::GPAY_CARD_LINKED_OFFER]);
- }
+ base::UmaHistogramCounts1000(
+ "Autofill.Offer.StoredOfferCount2.CardLinkedOffer",
+ offer_count[AutofillOfferData::OfferType::GPAY_CARD_LINKED_OFFER]);
}
void LogOffersSuggestionsPopupShown(bool first_time_being_logged) {
@@ -86,4 +205,29 @@ void LogIndividualOfferSuggestionEvent(
base::UmaHistogramEnumeration(histogram_name, event);
}
+// static
+void LogSyncedOfferDataBeingValid(bool valid) {
+ base::UmaHistogramBoolean("Autofill.Offer.SyncedOfferDataBeingValid", valid);
+}
+
+void LogPageLoadsWithOfferIconShown(AutofillOfferData::OfferType offer_type) {
+ std::string histogram_name = "Autofill.PageLoadsWithOfferIconShowing";
+ // Switch to different sub-histogram depending on offer type being displayed.
+ switch (offer_type) {
+ case AutofillOfferData::OfferType::FREE_LISTING_COUPON_OFFER:
+ histogram_name += ".FreeListingCouponOffer";
+ break;
+ case AutofillOfferData::OfferType::GPAY_CARD_LINKED_OFFER:
+ histogram_name += "CardLinkedOffer";
+ break;
+ case AutofillOfferData::OfferType::GPAY_PROMO_CODE_OFFER:
+ histogram_name += ".GPayPromoCodeOffer";
+ break;
+ case AutofillOfferData::OfferType::UNKNOWN:
+ NOTREACHED();
+ return;
+ }
+ base::UmaHistogramBoolean(histogram_name, true);
+}
+
} // namespace autofill::autofill_metrics
diff --git a/chromium/components/autofill/core/browser/metrics/payments/offers_metrics.h b/chromium/components/autofill/core/browser/metrics/payments/offers_metrics.h
index 38cc516e439..c57c4bd5507 100644
--- a/chromium/components/autofill/core/browser/metrics/payments/offers_metrics.h
+++ b/chromium/components/autofill/core/browser/metrics/payments/offers_metrics.h
@@ -12,10 +12,35 @@
namespace autofill::autofill_metrics {
-// Logs the offer data associated with a profile. This should be called each
-// time a Chrome profile is launched.
-void LogStoredOfferMetrics(
- const std::vector<std::unique_ptr<AutofillOfferData>>& offers);
+// Metrics to track event when the offer notification bubble is closed.
+enum class OfferNotificationBubbleResultMetric {
+ // These values are persisted to logs. Entries should not be renumbered and
+ // numeric values should never be reused.
+
+ // The user explicitly acknowledged the bubble by clicking the ok button.
+ OFFER_NOTIFICATION_BUBBLE_ACKNOWLEDGED = 0,
+ // The user explicitly closed the prompt with the close button or ESC.
+ OFFER_NOTIFICATION_BUBBLE_CLOSED = 1,
+ // The user did not interact with the prompt.
+ OFFER_NOTIFICATION_BUBBLE_NOT_INTERACTED = 2,
+ // The prompt lost focus and was deactivated.
+ OFFER_NOTIFICATION_BUBBLE_LOST_FOCUS = 3,
+ kMaxValue = OFFER_NOTIFICATION_BUBBLE_LOST_FOCUS,
+};
+
+// Metrics to track event when the offer notification infobar is closed.
+enum class OfferNotificationInfoBarResultMetric {
+ // These values are persisted to logs. Entries should not be renumbered and
+ // numeric values should never be reused.
+
+ // User acknowledged the infobar by clicking the ok button.
+ OFFER_NOTIFICATION_INFOBAR_ACKNOWLEDGED = 0,
+ // User explicitly closed the infobar with the close button.
+ OFFER_NOTIFICATION_INFOBAR_CLOSED = 1,
+ // InfoBar was shown but user did not interact with the it.
+ OFFER_NOTIFICATION_INFOBAR_IGNORED = 2,
+ kMaxValue = OFFER_NOTIFICATION_INFOBAR_IGNORED,
+};
// Metrics to track events related to the offers suggestions popup.
enum class OffersSuggestionsPopupEvent {
@@ -63,6 +88,21 @@ enum class OffersSuggestionsEvent {
kMaxValue = kOfferSuggestionSeeOfferDetailsSelectedOnce,
};
+void LogOfferNotificationBubbleOfferMetric(
+ AutofillOfferData::OfferType offer_type,
+ bool is_reshow);
+
+void LogOfferNotificationBubblePromoCodeButtonClicked(
+ AutofillOfferData::OfferType offer_type);
+
+void LogOfferNotificationBubbleResultMetric(
+ AutofillOfferData::OfferType offer_type,
+ OfferNotificationBubbleResultMetric metric,
+ bool is_reshow);
+
+void LogOfferNotificationBubbleSuppressed(
+ AutofillOfferData::OfferType offer_type);
+
// Log that the offers suggestions popup was shown. If |first_time_being_logged|
// is true, it represents that it has not been logged yet for the promo code
// offer field that the user is on, so additional logging is needed for the
@@ -73,6 +113,23 @@ void LogOffersSuggestionsPopupShown(bool first_time_being_logged);
void LogIndividualOfferSuggestionEvent(OffersSuggestionsEvent event,
AutofillOfferData::OfferType offer_type);
+void LogOfferNotificationInfoBarDeepLinkClicked();
+void LogOfferNotificationInfoBarResultMetric(
+ OfferNotificationInfoBarResultMetric metric);
+void LogOfferNotificationInfoBarShown();
+
+// Logs the offer data associated with a profile. This should be called each
+// time a Chrome profile is launched.
+void LogStoredOfferMetrics(
+ const std::vector<std::unique_ptr<AutofillOfferData>>& offers);
+
+// Logs whether the synced autofill offer data is valid.
+void LogSyncedOfferDataBeingValid(bool invalid);
+
+// Log the presence of the offer notification icon shows on navigation event
+// for |offer_type|.
+void LogPageLoadsWithOfferIconShown(AutofillOfferData::OfferType offer_type);
+
} // namespace autofill::autofill_metrics
#endif // COMPONENTS_AUTOFILL_CORE_BROWSER_METRICS_PAYMENTS_OFFERS_METRICS_H_
diff --git a/chromium/components/autofill/core/browser/metrics/payments/offers_metrics_unittest.cc b/chromium/components/autofill/core/browser/metrics/payments/offers_metrics_unittest.cc
index d30bdc96067..98dbcc7ece0 100644
--- a/chromium/components/autofill/core/browser/metrics/payments/offers_metrics_unittest.cc
+++ b/chromium/components/autofill/core/browser/metrics/payments/offers_metrics_unittest.cc
@@ -27,12 +27,22 @@ TEST_F(OffersMetricsTest, LogStoredOfferMetrics) {
AutofillOfferData offer1 = test::GetCardLinkedOfferData1();
AutofillOfferData offer2 = test::GetCardLinkedOfferData2();
AutofillOfferData offer3 = test::GetPromoCodeOfferData();
+ AutofillOfferData offer4 = test::GetPromoCodeOfferData();
+
+ // Add the test case of having several cards linked to an offer.
offer2.SetEligibleInstrumentIdForTesting({222222, 999999, 888888});
+
+ // Add the test case of having two merchant origins related to an offer.
offer2.SetMerchantOriginForTesting(
{GURL("http://www.example2.com"), GURL("https://www.example3.com/")});
+
+ // Add the test case of having no merchant origins related to an offer.
+ offer4.SetMerchantOriginForTesting({});
+
offers.push_back(std::make_unique<AutofillOfferData>(offer1));
offers.push_back(std::make_unique<AutofillOfferData>(offer2));
offers.push_back(std::make_unique<AutofillOfferData>(offer3));
+ offers.push_back(std::make_unique<AutofillOfferData>(offer4));
base::HistogramTester histogram_tester;
@@ -43,14 +53,37 @@ TEST_F(OffersMetricsTest, LogStoredOfferMetrics) {
};
// Validate the count metrics.
- EXPECT_THAT(SamplesOf("Autofill.Offer.StoredOfferCount.CardLinkedOffer"),
+ EXPECT_THAT(SamplesOf("Autofill.Offer.StoredOfferCount2.CardLinkedOffer"),
BucketsAre(Bucket(2, 1)));
- EXPECT_THAT(SamplesOf("Autofill.Offer.StoredOfferCount.GPayPromoCodeOffer"),
- BucketsAre(Bucket(1, 1)));
- EXPECT_THAT(SamplesOf("Autofill.Offer.StoredOfferRelatedMerchantCount"),
- BucketsAre(Bucket(1, 1), Bucket(2, 1)));
+ EXPECT_THAT(SamplesOf("Autofill.Offer.StoredOfferCount2.GPayPromoCodeOffer"),
+ BucketsAre(Bucket(2, 1)));
+ EXPECT_THAT(
+ SamplesOf(
+ "Autofill.Offer.StoredOfferRelatedMerchantCount.CardLinkedOffer"),
+ BucketsAre(Bucket(1, 1), Bucket(2, 1)));
+ EXPECT_THAT(
+ SamplesOf(
+ "Autofill.Offer.StoredOfferRelatedMerchantCount.GPayPromoCodeOffer"),
+ BucketsAre(Bucket(0, 1), Bucket(1, 1)));
EXPECT_THAT(SamplesOf("Autofill.Offer.StoredOfferRelatedCardCount"),
BucketsAre(Bucket(1, 1), Bucket(3, 1)));
}
+TEST_F(OffersMetricsTest, LogStoredOfferMetrics_NoOffers) {
+ base::HistogramTester histogram_tester;
+
+ autofill_metrics::LogStoredOfferMetrics(
+ std::vector<std::unique_ptr<AutofillOfferData>>());
+
+ auto SamplesOf = [&histogram_tester](base::StringPiece metric) {
+ return histogram_tester.GetAllSamples(metric);
+ };
+
+ // Validate the count metrics.
+ EXPECT_THAT(SamplesOf("Autofill.Offer.StoredOfferCount2.CardLinkedOffer"),
+ BucketsAre(Bucket(0, 1)));
+ EXPECT_THAT(SamplesOf("Autofill.Offer.StoredOfferCount2.GPayPromoCodeOffer"),
+ BucketsAre(Bucket(0, 1)));
+}
+
} // namespace autofill::autofill_metrics
diff --git a/chromium/components/autofill/core/browser/metrics/shadow_prediction_metrics.cc b/chromium/components/autofill/core/browser/metrics/shadow_prediction_metrics.cc
index 9c5f350b4fe..975cbb80575 100644
--- a/chromium/components/autofill/core/browser/metrics/shadow_prediction_metrics.cc
+++ b/chromium/components/autofill/core/browser/metrics/shadow_prediction_metrics.cc
@@ -67,10 +67,15 @@ int GetShadowPrediction(ServerFieldType current,
}
void LogShadowPredictionComparison(const AutofillField& field) {
-#if BUILDFLAG(USE_INTERNAL_AUTOFILL_HEADERS)
const auto& submitted_types = field.possible_types();
base::UmaHistogramSparse(
+ "Autofill.ShadowPredictions.DefaultHeuristicToDefaultServer",
+ GetShadowPrediction(field.heuristic_type(), field.server_type(),
+ submitted_types));
+
+#if BUILDFLAG(USE_INTERNAL_AUTOFILL_HEADERS)
+ base::UmaHistogramSparse(
"Autofill.ShadowPredictions.ExperimentalToDefault",
GetShadowPrediction(field.heuristic_type(PatternSource::kDefault),
field.heuristic_type(PatternSource::kExperimental),
diff --git a/chromium/components/autofill/core/browser/metrics/shadow_prediction_metrics_unittest.cc b/chromium/components/autofill/core/browser/metrics/shadow_prediction_metrics_unittest.cc
index 07fd12addd7..f7f15c27651 100644
--- a/chromium/components/autofill/core/browser/metrics/shadow_prediction_metrics_unittest.cc
+++ b/chromium/components/autofill/core/browser/metrics/shadow_prediction_metrics_unittest.cc
@@ -30,12 +30,12 @@ constexpr int kNameFirstDifferentPredictionsValueAgreesWithOld = 21;
constexpr int kNameFirstDifferentPredictionsValueAgreesWithBoth = 24;
constexpr int kNameFirstDifferentPredictionsValueAgreesWithNeither = 23;
constexpr int kEmailAddressDifferentPredictionsValueAgreesWithNew = 58;
-#if BUILDFLAG(USE_INTERNAL_AUTOFILL_HEADERS)
constexpr int kNameFullSamePredictionValueAgrees = 43;
+constexpr int kSearchTermDifferentPredictionsValueAgreesWithNew = 586;
+#if BUILDFLAG(USE_INTERNAL_AUTOFILL_HEADERS)
constexpr int kNameFullDifferentPredictionsValueAgreesWithOld = 45;
constexpr int kEmailAddressDifferentPredictionsValueAgreesWithOld = 57;
constexpr int kSearchTermSamePredictionValueDisagrees = 584;
-constexpr int kSearchTermDifferentPredictionsValueAgreesWithNew = 586;
#endif
namespace {
@@ -96,7 +96,8 @@ TEST(AutofillShadowPredictionComparisonTest, ComparisonContainsAllTypes) {
// If this test fails after adding a type, update
// `AutofillPredictionsComparisonResult` in tools/metrics/histograms/enums.xml
// and set `last_known_type` to the last entry in the enum.
- constexpr ServerFieldType last_known_type = PHONE_HOME_NUMBER_SUFFIX;
+ constexpr ServerFieldType last_known_type =
+ CREDIT_CARD_STANDALONE_VERIFICATION_CODE;
int max_comparison =
GetShadowPrediction(last_known_type, NAME_FIRST, {NAME_LAST});
@@ -211,6 +212,42 @@ TEST_F(AutofillShadowPredictionMetricsTest,
}
#endif
+// Test that Autofill.ShadowPredictions.DefaultHeuristicToDefaultServer compares
+// heuristics to server predictions.
+TEST_F(AutofillShadowPredictionMetricsTest, CompareHeuristicsAndServer) {
+#if BUILDFLAG(USE_INTERNAL_AUTOFILL_HEADERS)
+ constexpr PatternSource source = PatternSource::kDefault;
+#else
+ constexpr PatternSource source = PatternSource::kLegacy;
+#endif
+
+ FormData form = GetFormWith2Fields(autofill_client_->form_origin());
+ form.fields[0].value = u"Elvis Aaron Presley"; // A known `NAME_FULL`.
+ form.fields[1].value = u"buddy@gmail.com"; // A known `EMAIL_ADDRESS`.
+
+ std::vector<ServerFieldType> server_types = {NAME_FULL, EMAIL_ADDRESS};
+
+ // Simulate having seen this form on page load.
+ autofill_manager().AddSeenForm(form,
+ {// Field 0
+ {{source, NAME_FULL}},
+ // Field 1
+ {{source, SEARCH_TERM}}},
+ server_types);
+
+ // Simulate form submission.
+ base::HistogramTester histogram_tester;
+ autofill_manager().OnFormSubmitted(form, /*known_success=*/false,
+ SubmissionSource::FORM_SUBMISSION);
+
+ EXPECT_THAT(
+ histogram_tester.GetAllSamples(
+ "Autofill.ShadowPredictions.DefaultHeuristicToDefaultServer"),
+ UnorderedElementsAre(
+ Bucket(kNameFullSamePredictionValueAgrees, 1),
+ Bucket(kSearchTermDifferentPredictionsValueAgreesWithNew, 1)));
+}
+
} // namespace
} // namespace autofill::metrics
diff --git a/chromium/components/autofill/core/browser/mock_autocomplete_history_manager.h b/chromium/components/autofill/core/browser/mock_autocomplete_history_manager.h
index 81772fc85be..ba617b68797 100644
--- a/chromium/components/autofill/core/browser/mock_autocomplete_history_manager.h
+++ b/chromium/components/autofill/core/browser/mock_autocomplete_history_manager.h
@@ -17,14 +17,12 @@ class MockAutocompleteHistoryManager : public AutocompleteHistoryManager {
~MockAutocompleteHistoryManager();
MOCK_METHOD(
- void,
+ bool,
OnGetSingleFieldSuggestions,
(int query_id,
bool is_autocomplete_enabled,
bool autoselect_first_suggestion,
- const std::u16string& name,
- const std::u16string& prefix,
- const std::string& form_control_type,
+ const FormFieldData& field,
base::WeakPtr<AutocompleteHistoryManager::SuggestionsHandler> handler,
const SuggestionsContext& context),
(override));
diff --git a/chromium/components/autofill/core/browser/mock_iban_manager.cc b/chromium/components/autofill/core/browser/mock_iban_manager.cc
new file mode 100644
index 00000000000..02fd609b2a8
--- /dev/null
+++ b/chromium/components/autofill/core/browser/mock_iban_manager.cc
@@ -0,0 +1,14 @@
+// Copyright 2022 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/mock_iban_manager.h"
+
+namespace autofill {
+
+MockIBANManager::MockIBANManager(PersonalDataManager* personal_data_manager)
+ : IBANManager(personal_data_manager, /*is_off_the_record=*/false) {}
+
+MockIBANManager::~MockIBANManager() = default;
+
+} // namespace autofill
diff --git a/chromium/components/autofill/core/browser/mock_iban_manager.h b/chromium/components/autofill/core/browser/mock_iban_manager.h
new file mode 100644
index 00000000000..a2fbdabcc4d
--- /dev/null
+++ b/chromium/components/autofill/core/browser/mock_iban_manager.h
@@ -0,0 +1,51 @@
+// Copyright 2022 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_MOCK_IBAN_MANAGER_H_
+#define COMPONENTS_AUTOFILL_CORE_BROWSER_MOCK_IBAN_MANAGER_H_
+
+#include "base/memory/weak_ptr.h"
+#include "components/autofill/core/browser/iban_manager.h"
+#include "components/autofill/core/browser/personal_data_manager.h"
+#include "testing/gmock/include/gmock/gmock.h"
+
+namespace autofill {
+
+class MockIBANManager : public IBANManager {
+ public:
+ explicit MockIBANManager(PersonalDataManager* personal_data_manager);
+
+ ~MockIBANManager() override;
+
+ MOCK_METHOD(bool,
+ OnGetSingleFieldSuggestions,
+ (int query_id,
+ bool is_autocomplete_enabled,
+ bool autoselect_first_suggestion,
+ const FormFieldData& field,
+ base::WeakPtr<IBANManager::SuggestionsHandler> handler,
+ const SuggestionsContext& context),
+ (override));
+ MOCK_METHOD(void,
+ OnWillSubmitFormWithFields,
+ (const std::vector<FormFieldData>& fields,
+ bool is_autocomplete_enabled),
+ (override));
+ MOCK_METHOD(void,
+ CancelPendingQueries,
+ (const IBANManager::SuggestionsHandler*),
+ (override));
+ MOCK_METHOD(void,
+ OnRemoveCurrentSingleFieldSuggestion,
+ (const std::u16string&, const std::u16string&, int),
+ (override));
+ MOCK_METHOD(void,
+ OnSingleFieldSuggestionSelected,
+ (const std::u16string&, int),
+ (override));
+};
+
+} // namespace autofill
+
+#endif // COMPONENTS_AUTOFILL_CORE_BROWSER_MOCK_IBAN_MANAGER_H_
diff --git a/chromium/components/autofill/core/browser/mock_merchant_promo_code_manager.h b/chromium/components/autofill/core/browser/mock_merchant_promo_code_manager.h
index 3a95b96c446..e45208d0b28 100644
--- a/chromium/components/autofill/core/browser/mock_merchant_promo_code_manager.h
+++ b/chromium/components/autofill/core/browser/mock_merchant_promo_code_manager.h
@@ -17,14 +17,12 @@ class MockMerchantPromoCodeManager : public MerchantPromoCodeManager {
~MockMerchantPromoCodeManager() override;
MOCK_METHOD(
- void,
+ bool,
OnGetSingleFieldSuggestions,
(int query_id,
bool is_autocomplete_enabled,
bool autoselect_first_suggestion,
- const std::u16string& name,
- const std::u16string& prefix,
- const std::string& form_control_type,
+ const FormFieldData& field,
base::WeakPtr<MerchantPromoCodeManager::SuggestionsHandler> handler,
const SuggestionsContext& context),
(override));
diff --git a/chromium/components/autofill/core/browser/mock_single_field_form_fill_router.h b/chromium/components/autofill/core/browser/mock_single_field_form_fill_router.h
index 65d2ec16f30..f3345df2ad9 100644
--- a/chromium/components/autofill/core/browser/mock_single_field_form_fill_router.h
+++ b/chromium/components/autofill/core/browser/mock_single_field_form_fill_router.h
@@ -24,14 +24,12 @@ class MockSingleFieldFormFillRouter : public SingleFieldFormFillRouter {
const FormStructure* form_structure,
bool is_autocomplete_enabled),
(override));
- MOCK_METHOD(void,
+ MOCK_METHOD(bool,
OnGetSingleFieldSuggestions,
(int query_id,
bool is_autocomplete_enabled,
bool autoselect_first_suggestion,
- const std::u16string& name,
- const std::u16string& prefix,
- const std::string& form_control_type,
+ const FormFieldData& field,
base::WeakPtr<SingleFieldFormFiller::SuggestionsHandler> handler,
const SuggestionsContext& context),
(override));
diff --git a/chromium/components/autofill/core/browser/payments/autofill_offer_notification_infobar_delegate_mobile.cc b/chromium/components/autofill/core/browser/payments/autofill_offer_notification_infobar_delegate_mobile.cc
index 8ad48047df4..ec4ba68da52 100644
--- a/chromium/components/autofill/core/browser/payments/autofill_offer_notification_infobar_delegate_mobile.cc
+++ b/chromium/components/autofill/core/browser/payments/autofill_offer_notification_infobar_delegate_mobile.cc
@@ -13,6 +13,7 @@
#include "build/branding_buildflags.h"
#include "components/autofill/core/browser/autofill_experiments.h"
#include "components/autofill/core/browser/data_model/credit_card.h"
+#include "components/autofill/core/browser/metrics/payments/offers_metrics.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"
@@ -38,21 +39,21 @@ AutofillOfferNotificationInfoBarDelegateMobile::
network_icon_id_(CreditCard::IconResourceId(card.network())),
deep_link_url_(offer_details_url),
user_manually_closed_infobar_(false) {
- AutofillMetrics::LogOfferNotificationInfoBarShown();
+ autofill_metrics::LogOfferNotificationInfoBarShown();
}
AutofillOfferNotificationInfoBarDelegateMobile::
~AutofillOfferNotificationInfoBarDelegateMobile() {
if (!user_manually_closed_infobar_) {
- AutofillMetrics::LogOfferNotificationInfoBarResultMetric(
- AutofillMetrics::OfferNotificationInfoBarResultMetric::
+ autofill_metrics::LogOfferNotificationInfoBarResultMetric(
+ autofill_metrics::OfferNotificationInfoBarResultMetric::
OFFER_NOTIFICATION_INFOBAR_IGNORED);
}
}
void AutofillOfferNotificationInfoBarDelegateMobile::OnOfferDeepLinkClicked(
GURL url) {
- AutofillMetrics::LogOfferNotificationInfoBarDeepLinkClicked();
+ autofill_metrics::LogOfferNotificationInfoBarDeepLinkClicked();
infobar()->owner()->OpenURL(url, WindowOpenDisposition::NEW_FOREGROUND_TAB);
}
@@ -87,15 +88,15 @@ std::u16string AutofillOfferNotificationInfoBarDelegateMobile::GetButtonLabel(
}
void AutofillOfferNotificationInfoBarDelegateMobile::InfoBarDismissed() {
- AutofillMetrics::LogOfferNotificationInfoBarResultMetric(
- AutofillMetrics::OfferNotificationInfoBarResultMetric::
+ autofill_metrics::LogOfferNotificationInfoBarResultMetric(
+ autofill_metrics::OfferNotificationInfoBarResultMetric::
OFFER_NOTIFICATION_INFOBAR_CLOSED);
user_manually_closed_infobar_ = true;
}
bool AutofillOfferNotificationInfoBarDelegateMobile::Accept() {
- AutofillMetrics::LogOfferNotificationInfoBarResultMetric(
- AutofillMetrics::OfferNotificationInfoBarResultMetric::
+ autofill_metrics::LogOfferNotificationInfoBarResultMetric(
+ autofill_metrics::OfferNotificationInfoBarResultMetric::
OFFER_NOTIFICATION_INFOBAR_ACKNOWLEDGED);
user_manually_closed_infobar_ = true;
return true;
diff --git a/chromium/components/autofill/core/browser/payments/credit_card_access_manager.cc b/chromium/components/autofill/core/browser/payments/credit_card_access_manager.cc
index ba148d01a98..ae16420fa7f 100644
--- a/chromium/components/autofill/core/browser/payments/credit_card_access_manager.cc
+++ b/chromium/components/autofill/core/browser/payments/credit_card_access_manager.cc
@@ -21,6 +21,7 @@
#include "build/build_config.h"
#include "components/autofill/core/browser/autofill_client.h"
#include "components/autofill/core/browser/autofill_driver.h"
+#include "components/autofill/core/browser/autofill_progress_dialog_type.h"
#include "components/autofill/core/browser/browser_autofill_manager.h"
#include "components/autofill/core/browser/data_model/credit_card.h"
#include "components/autofill/core/browser/metrics/form_events/credit_card_form_event_logger.h"
@@ -492,7 +493,7 @@ void CreditCardAccessManager::Authenticate() {
// authentication flow since the card unmask prompt will pop up.
client_->CloseWebauthnDialog();
#endif
- GetOrCreateCVCAuthenticator()->Authenticate(
+ client_->GetCVCAuthenticator()->Authenticate(
card_.get(), weak_ptr_factory_.GetWeakPtr(), personal_data_manager_);
break;
}
@@ -521,7 +522,7 @@ void CreditCardAccessManager::Authenticate() {
// Delegate the task to CreditCardOtpAuthenticator.
CardUnmaskChallengeOption selected_challenge_option =
*card_unmask_challenge_options_it;
- GetOrCreateOtpAuthenticator()->OnChallengeOptionSelected(
+ client_->GetOtpAuthenticator()->OnChallengeOptionSelected(
card_.get(), selected_challenge_option,
weak_ptr_factory_.GetWeakPtr(),
virtual_card_unmask_response_details_.context_token,
@@ -536,13 +537,6 @@ void CreditCardAccessManager::Authenticate() {
}
}
-CreditCardCVCAuthenticator*
-CreditCardAccessManager::GetOrCreateCVCAuthenticator() {
- if (!cvc_authenticator_)
- cvc_authenticator_ = std::make_unique<CreditCardCVCAuthenticator>(client_);
- return cvc_authenticator_.get();
-}
-
#if !BUILDFLAG(IS_IOS)
CreditCardFIDOAuthenticator*
CreditCardAccessManager::GetOrCreateFIDOAuthenticator() {
@@ -553,13 +547,6 @@ CreditCardAccessManager::GetOrCreateFIDOAuthenticator() {
}
#endif
-CreditCardOtpAuthenticator*
-CreditCardAccessManager::GetOrCreateOtpAuthenticator() {
- if (!otp_authenticator_)
- otp_authenticator_ = std::make_unique<CreditCardOtpAuthenticator>(client_);
- return otp_authenticator_.get();
-}
-
void CreditCardAccessManager::OnCVCAuthenticationComplete(
const CreditCardCVCAuthenticator::CVCAuthenticationResponse& response) {
is_authentication_in_progress_ = false;
@@ -636,7 +623,15 @@ bool CreditCardAccessManager::UserOptedInToFidoFromSettingsPageOnMobile()
#if !BUILDFLAG(IS_IOS)
void CreditCardAccessManager::OnFIDOAuthenticationComplete(
const CreditCardFIDOAuthenticator::FidoAuthenticationResponse& response) {
-#if !BUILDFLAG(IS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
+ if (base::FeatureList::IsEnabled(
+ features::kAutofillEnableFIDOProgressDialog)) {
+ // Close the progress dialog when the authentication for getting the full
+ // card completes.
+ client_->CloseAutofillProgressDialog(
+ /*show_confirmation_before_closing=*/true);
+ }
+#else
// Close the Webauthn verify pending dialog. If FIDO authentication succeeded,
// card is filled to the form, otherwise fall back to CVC authentication which
// does not need the verify pending dialog either.
@@ -969,6 +964,7 @@ void CreditCardAccessManager::FetchMaskedServerCard() {
void CreditCardAccessManager::FetchVirtualCard() {
is_authentication_in_progress_ = true;
client_->ShowAutofillProgressDialog(
+ AutofillProgressDialogType::kVirtualCardUnmaskProgressDialog,
base::BindOnce(&CreditCardAccessManager::OnVirtualCardUnmaskCancelled,
weak_ptr_factory_.GetWeakPtr()));
@@ -1117,7 +1113,7 @@ void CreditCardAccessManager::OnVirtualCardUnmaskCancelled() {
// Virtual Card Unmask request, so we need to reset the state of the
// CreditCardOtpAuthenticator as well to ensure the flow does not continue,
// as continuing the flow can cause a crash.
- GetOrCreateOtpAuthenticator()->Reset();
+ client_->GetOtpAuthenticator()->Reset();
}
AutofillMetrics::VirtualCardUnmaskFlowType flow_type;
diff --git a/chromium/components/autofill/core/browser/payments/credit_card_access_manager.h b/chromium/components/autofill/core/browser/payments/credit_card_access_manager.h
index 8b693f8c7de..268df7b0f14 100644
--- a/chromium/components/autofill/core/browser/payments/credit_card_access_manager.h
+++ b/chromium/components/autofill/core/browser/payments/credit_card_access_manager.h
@@ -159,14 +159,9 @@ class CreditCardAccessManager : public CreditCardCVCAuthenticator::Requester,
// Returns true if a |unmasked_cards_cache| contains an entry for the card.
bool IsCardPresentInUnmaskedCache(const CreditCard& card) const;
- // Accessors to different authenticators. They will first create the
- // authenticators if they do not exist. Otherwise the accessors will simply
- // return references to the authenticators.
- CreditCardCVCAuthenticator* GetOrCreateCVCAuthenticator();
#if !BUILDFLAG(IS_IOS)
CreditCardFIDOAuthenticator* GetOrCreateFIDOAuthenticator();
#endif
- CreditCardOtpAuthenticator* GetOrCreateOtpAuthenticator();
private:
// TODO(crbug.com/1249665): Remove FRIEND and change everything to _ForTesting
@@ -208,9 +203,6 @@ class CreditCardAccessManager : public CreditCardCVCAuthenticator::Requester,
RiskBasedVirtualCardUnmasking_Failure_VirtualCardRetrievalError);
FRIEND_TEST_ALL_PREFIXES(CreditCardAccessManagerTest,
RiskBasedVirtualCardUnmasking_FlowCancelled);
- friend class AutofillAssistantTest;
- friend class BrowserAutofillManagerTest;
- friend class AutofillMetricsTest;
friend class metrics::AutofillMetricsBaseTest;
friend class CreditCardAccessManagerTest;
@@ -220,10 +212,6 @@ class CreditCardAccessManager : public CreditCardCVCAuthenticator::Requester,
fido_authenticator_ = std::move(fido_authenticator);
}
#endif
- void set_otp_authenticator_for_testing(
- std::unique_ptr<CreditCardOtpAuthenticator> otp_authenticator) {
- otp_authenticator_ = std::move(otp_authenticator);
- }
#if defined(UNIT_TEST)
// Mocks that a virtual card was selected, so unit tests that don't run the
@@ -417,9 +405,6 @@ class CreditCardAccessManager : public CreditCardCVCAuthenticator::Requester,
// Timestamp for when fido_authenticator_->IsUserVerifiable() is called.
absl::optional<base::TimeTicks> is_user_verifiable_called_timestamp_;
- // Authenticators for card unmasking.
- std::unique_ptr<CreditCardCVCAuthenticator> cvc_authenticator_;
- std::unique_ptr<CreditCardOtpAuthenticator> otp_authenticator_;
#if !BUILDFLAG(IS_IOS)
std::unique_ptr<CreditCardFIDOAuthenticator> fido_authenticator_;
diff --git a/chromium/components/autofill/core/browser/payments/credit_card_access_manager_unittest.cc b/chromium/components/autofill/core/browser/payments/credit_card_access_manager_unittest.cc
index 0b5758a70fc..ed98c61fdfc 100644
--- a/chromium/components/autofill/core/browser/payments/credit_card_access_manager_unittest.cc
+++ b/chromium/components/autofill/core/browser/payments/credit_card_access_manager_unittest.cc
@@ -28,6 +28,7 @@
#include "base/test/scoped_feature_list.h"
#include "base/test/task_environment.h"
#include "base/threading/thread_task_runner_handle.h"
+#include "base/time/clock.h"
#include "base/time/time.h"
#include "build/build_config.h"
#include "components/autofill/core/browser/autofill_download_manager.h"
@@ -211,8 +212,7 @@ class CreditCardAccessManagerTest : public testing::Test {
auto otp_authenticator =
std::make_unique<TestCreditCardOtpAuthenticator>(&autofill_client_);
otp_authenticator_ = otp_authenticator.get();
- credit_card_access_manager_->set_otp_authenticator_for_testing(
- std::move(otp_authenticator));
+ autofill_client_.set_otp_authenticator(std::move(otp_authenticator));
}
void TearDown() override {
@@ -264,7 +264,7 @@ class CreditCardAccessManagerTest : public testing::Test {
}
CreditCardCVCAuthenticator* GetCVCAuthenticator() {
- return credit_card_access_manager_->GetOrCreateCVCAuthenticator();
+ return autofill_client_.GetCVCAuthenticator();
}
void MockUserResponseForCvcAuth(std::u16string cvc, bool enable_fido) {
diff --git a/chromium/components/autofill/core/browser/payments/credit_card_fido_authenticator.cc b/chromium/components/autofill/core/browser/payments/credit_card_fido_authenticator.cc
index 9043fc665d6..a2311a503ca 100644
--- a/chromium/components/autofill/core/browser/payments/credit_card_fido_authenticator.cc
+++ b/chromium/components/autofill/core/browser/payments/credit_card_fido_authenticator.cc
@@ -21,6 +21,7 @@
#include "build/build_config.h"
#include "components/autofill/core/browser/autofill_client.h"
#include "components/autofill/core/browser/autofill_experiments.h"
+#include "components/autofill/core/browser/autofill_progress_dialog_type.h"
#include "components/autofill/core/browser/data_model/credit_card.h"
#include "components/autofill/core/browser/metrics/autofill_metrics.h"
#include "components/autofill/core/browser/payments/fido_authentication_strike_database.h"
@@ -440,6 +441,18 @@ void CreditCardFIDOAuthenticator::OnDidGetAssertion(
autofill_client_->GetLastCommittedURL().DeprecatedGetOriginAsURL();
}
+#if BUILDFLAG(IS_ANDROID)
+ if (base::FeatureList::IsEnabled(
+ features::kAutofillEnableFIDOProgressDialog)) {
+ // Open the progress dialog when authenticating and getting the full card
+ // from FIDO.
+ autofill_client_->ShowAutofillProgressDialog(
+ AutofillProgressDialogType::kAndroidFIDOProgressDialog,
+ base::BindOnce(&CreditCardFIDOAuthenticator::CancelVerification,
+ weak_ptr_factory_.GetWeakPtr()));
+ }
+#endif
+
full_card_request_->GetFullCardViaFIDO(
*card_, AutofillClient::UnmaskCardReason::kAutofill,
weak_ptr_factory_.GetWeakPtr(), std::move(response),
@@ -811,18 +824,16 @@ void CreditCardFIDOAuthenticator::UpdateUserPref() {
}
webauthn::InternalAuthenticator* CreditCardFIDOAuthenticator::authenticator() {
- if (authenticator_)
- return authenticator_;
-
- authenticator_ =
- autofill_driver_->GetOrCreateCreditCardInternalAuthenticator();
-
- // |authenticator_| may be null for unsupported platforms.
- if (authenticator_) {
- authenticator()->SetEffectiveOrigin(
- url::Origin::Create(payments::GetBaseSecureUrl()));
+ if (!authenticator_) {
+ authenticator_ = autofill_client_->CreateCreditCardInternalAuthenticator(
+ autofill_driver_.get());
+ // `authenticator_` may be null for unsupported platforms.
+ if (authenticator_) {
+ authenticator_->SetEffectiveOrigin(
+ url::Origin::Create(payments::GetBaseSecureUrl()));
+ }
}
-
- return authenticator_;
+ return authenticator_.get();
}
+
} // namespace autofill
diff --git a/chromium/components/autofill/core/browser/payments/credit_card_fido_authenticator.h b/chromium/components/autofill/core/browser/payments/credit_card_fido_authenticator.h
index 0bda2fe812c..dbf86222cda 100644
--- a/chromium/components/autofill/core/browser/payments/credit_card_fido_authenticator.h
+++ b/chromium/components/autofill/core/browser/payments/credit_card_fido_authenticator.h
@@ -263,7 +263,7 @@ class CreditCardFIDOAuthenticator
const raw_ptr<payments::PaymentsClient> payments_client_;
// Authenticator pointer to facilitate WebAuthn.
- raw_ptr<webauthn::InternalAuthenticator> authenticator_ = nullptr;
+ std::unique_ptr<webauthn::InternalAuthenticator> authenticator_;
// Responsible for getting the full card details, including the PAN and the
// CVC.
diff --git a/chromium/components/autofill/core/browser/payments/credit_card_save_manager.cc b/chromium/components/autofill/core/browser/payments/credit_card_save_manager.cc
index 954658510fa..c3abf087215 100644
--- a/chromium/components/autofill/core/browser/payments/credit_card_save_manager.cc
+++ b/chromium/components/autofill/core/browser/payments/credit_card_save_manager.cc
@@ -283,10 +283,16 @@ void CreditCardSaveManager::AttemptToOfferCardUploadSave(
#if !BUILDFLAG(IS_IOS) && !BUILDFLAG(IS_ANDROID)
+ int save_card_ui_experiment_arm =
+ features::kAutofillSaveCardUiExperimentSelectorInNumber.Get();
+
// Adding the Save Card UI Experiment to the active experiments in upload
- // request if the experiment is active.
+ // request if the experiment is active. If 3rd save card ui experiment, aka
+ // Current with Avatar and Email, is selected then we would not add
+ // AutofillSaveCardUiExperiment to the active experiments list, as we want the
+ // current footer to be displayed.
if (base::FeatureList::IsEnabled(features::kAutofillSaveCardUiExperiment) &&
- features::kAutofillSaveCardUiExperimentSelectorInNumber.Get() != 0) {
+ (save_card_ui_experiment_arm == 1 || save_card_ui_experiment_arm == 2)) {
upload_request_.active_experiments.push_back(
"AutofillSaveCardUiExperiment");
}
@@ -1021,18 +1027,17 @@ void CreditCardSaveManager::LogCardUploadDecisions(
void CreditCardSaveManager::LogCardUploadDecisionsToAutofillInternals(
int upload_decision_metrics) {
LogManager* log_manager = client_->GetLogManager();
- if (!log_manager)
- return;
auto final_decision =
(upload_decision_metrics_ & AutofillMetrics::UPLOAD_OFFERED)
? LogMessage::kCardUploadDecisionUploadOffered
: LogMessage::kCardUploadDecisionUploadNotOffered;
- auto buffer = log_manager->Log();
- buffer << LoggingScope::kCardUploadDecision << final_decision;
- buffer << Tag{"div"} << Attrib{"class", "form"} << Tag{"tr"} << Tag{"td"}
- << "Decision Metrics:" << CTag{"td"} << Tag{"td"} << Tag{"table"};
+ LogBuffer buffer(IsLoggingActive(log_manager));
+ LOG_AF(buffer) << LoggingScope::kCardUploadDecision << final_decision;
+ LOG_AF(buffer) << Tag{"div"} << Attrib{"class", "form"} << Tag{"tr"}
+ << Tag{"td"} << "Decision Metrics:" << CTag{"td"} << Tag{"td"}
+ << Tag{"table"};
for (int i = 0; i < AutofillMetrics::kNumCardUploadDecisionMetrics; i++) {
AutofillMetrics::CardUploadDecisionMetric currentBitmaskValue =
@@ -1100,9 +1105,10 @@ void CreditCardSaveManager::LogCardUploadDecisionsToAutofillInternals(
result = "UPLOAD_NOT_OFFERED_INVALID_LEGAL_MESSAGE";
break;
}
- buffer << Tr{} << result;
+ LOG_AF(buffer) << Tr{} << result;
}
- buffer << CTag{"table"} << CTag{"td"} << CTag{"tr"} << CTag{"div"};
+ LOG_AF(buffer) << CTag{"table"} << CTag{"td"} << CTag{"tr"} << CTag{"div"};
+ LOG_AF(log_manager) << std::move(buffer);
}
void CreditCardSaveManager::LogSaveCardRequestExpirationDateReasonMetric() {
diff --git a/chromium/components/autofill/core/browser/payments/credit_card_save_manager_unittest.cc b/chromium/components/autofill/core/browser/payments/credit_card_save_manager_unittest.cc
index 7c2bd346201..93bb8bfdd25 100644
--- a/chromium/components/autofill/core/browser/payments/credit_card_save_manager_unittest.cc
+++ b/chromium/components/autofill/core/browser/payments/credit_card_save_manager_unittest.cc
@@ -504,7 +504,7 @@ TEST_F(CreditCardSaveManagerTest, CreditCardDisabledDoesNotSave) {
FormData address_form;
test::CreateTestAddressFormData(&address_form);
FormsSeen(std::vector<FormData>(1, address_form));
- ManuallyFillAddressForm("Flo", "Master", "77401", "US", &address_form);
+ ManuallyFillAddressForm("Jane", "Doe", "77401", "US", &address_form);
FormSubmitted(address_form);
// Set up our credit card form data.
@@ -513,7 +513,7 @@ TEST_F(CreditCardSaveManagerTest, CreditCardDisabledDoesNotSave) {
FormsSeen(std::vector<FormData>(1, credit_card_form));
// Edit the data, and submit.
- credit_card_form.fields[0].value = u"Flo Master";
+ credit_card_form.fields[0].value = u"Jane Doe";
credit_card_form.fields[1].value = u"4111111111111111";
credit_card_form.fields[2].value = ASCIIToUTF16(test::NextMonth());
credit_card_form.fields[3].value = ASCIIToUTF16(test::NextYear());
@@ -541,7 +541,7 @@ TEST_F(CreditCardSaveManagerTest, UploadCreditCard_OnlyCountryInAddresses) {
FormsSeen(std::vector<FormData>(1, address_form));
ExpectUniqueFillableFormParsedUkm();
- ManuallyFillAddressForm("Flo", "Master", "77401", "US", &address_form);
+ ManuallyFillAddressForm("Jane", "Doe", "77401", "US", &address_form);
FormSubmitted(address_form);
// Set up our credit card form data.
@@ -551,7 +551,7 @@ TEST_F(CreditCardSaveManagerTest, UploadCreditCard_OnlyCountryInAddresses) {
ExpectFillableFormParsedUkm(2 /* num_fillable_forms_parsed */);
// Edit the data, and submit.
- credit_card_form.fields[0].value = u"Flo Master";
+ credit_card_form.fields[0].value = u"Jane Doe";
credit_card_form.fields[1].value = u"4111111111111111";
credit_card_form.fields[2].value = ASCIIToUTF16(test::NextMonth());
credit_card_form.fields[3].value = ASCIIToUTF16(test::NextYear());
@@ -605,7 +605,7 @@ TEST_F(CreditCardSaveManagerTest, LocalCreditCard_FirstAndLastName) {
FormsSeen(std::vector<FormData>(1, address_form));
ExpectUniqueFillableFormParsedUkm();
- ManuallyFillAddressForm("Flo", "Master", "77401", "US", &address_form);
+ ManuallyFillAddressForm("Jane", "Doe", "77401", "US", &address_form);
FormSubmitted(address_form);
// Set up our credit card form data with credit card first and last name
@@ -616,8 +616,8 @@ TEST_F(CreditCardSaveManagerTest, LocalCreditCard_FirstAndLastName) {
FormsSeen(std::vector<FormData>(1, credit_card_form));
// Edit the data, and submit.
- credit_card_form.fields[0].value = u"Flo";
- credit_card_form.fields[1].value = u"Master";
+ credit_card_form.fields[0].value = u"Jane";
+ credit_card_form.fields[1].value = u"Doe";
credit_card_form.fields[2].value = u"4111111111111111";
credit_card_form.fields[3].value = ASCIIToUTF16(test::NextMonth());
credit_card_form.fields[4].value = ASCIIToUTF16(test::NextYear());
@@ -649,7 +649,7 @@ TEST_F(CreditCardSaveManagerTest, LocalCreditCard_LastAndFirstName) {
FormsSeen(std::vector<FormData>(1, address_form));
ExpectUniqueFillableFormParsedUkm();
- ManuallyFillAddressForm("Flo", "Master", "77401", "US", &address_form);
+ ManuallyFillAddressForm("Jane", "Doe", "77401", "US", &address_form);
FormSubmitted(address_form);
// Set up our credit card form data with credit card first and last name
@@ -682,8 +682,8 @@ TEST_F(CreditCardSaveManagerTest, LocalCreditCard_LastAndFirstName) {
FormsSeen(std::vector<FormData>(1, credit_card_form));
// Edit the data, and submit.
- credit_card_form.fields[0].value = u"Master";
- credit_card_form.fields[1].value = u"Flo";
+ credit_card_form.fields[0].value = u"Doe";
+ credit_card_form.fields[1].value = u"Jane";
credit_card_form.fields[2].value = u"4111111111111111";
credit_card_form.fields[3].value = ASCIIToUTF16(test::NextMonth());
credit_card_form.fields[4].value = ASCIIToUTF16(test::NextYear());
@@ -713,7 +713,7 @@ TEST_F(CreditCardSaveManagerTest, LocalCreditCard_ExpirationDateMissing) {
FormData address_form;
test::CreateTestAddressFormData(&address_form);
FormsSeen(std::vector<FormData>(1, address_form));
- ManuallyFillAddressForm("Flo", "Master", "77401", "US", &address_form);
+ ManuallyFillAddressForm("Jane", "Doe", "77401", "US", &address_form);
FormSubmitted(address_form);
// Set up our credit card form.
@@ -722,7 +722,7 @@ TEST_F(CreditCardSaveManagerTest, LocalCreditCard_ExpirationDateMissing) {
FormsSeen(std::vector<FormData>(1, credit_card_form));
// Edit the data, but don't include a expiration date, and submit.
- credit_card_form.fields[0].value = u"Flo Master";
+ credit_card_form.fields[0].value = u"Jane Doe";
credit_card_form.fields[1].value = u"4111111111111111";
credit_card_form.fields[2].value = u"";
credit_card_form.fields[3].value = u"";
@@ -746,7 +746,7 @@ TEST_F(CreditCardSaveManagerTest, UploadCreditCard_WithNonFocusableField) {
FormsSeen(std::vector<FormData>(1, address_form));
ExpectUniqueFillableFormParsedUkm();
- ManuallyFillAddressForm("Flo", "Master", "77401", "US", &address_form);
+ ManuallyFillAddressForm("Jane", "Doe", "77401", "US", &address_form);
FormSubmitted(address_form);
// Set up our credit card form data with non_focusable form field.
@@ -758,8 +758,8 @@ TEST_F(CreditCardSaveManagerTest, UploadCreditCard_WithNonFocusableField) {
FormsSeen(std::vector<FormData>(1, credit_card_form));
// Edit the data, and submit.
- credit_card_form.fields[0].value = u"Flo";
- credit_card_form.fields[1].value = u"Master";
+ credit_card_form.fields[0].value = u"Jane";
+ credit_card_form.fields[1].value = u"Doe";
credit_card_form.fields[2].value = u"4111111111111111";
credit_card_form.fields[3].value = ASCIIToUTF16(test::NextMonth());
credit_card_form.fields[4].value = ASCIIToUTF16(test::NextYear());
@@ -793,7 +793,7 @@ TEST_F(CreditCardSaveManagerTest, LocalCreditCard_WithNonFocusableField) {
FormsSeen(std::vector<FormData>(1, address_form));
ExpectUniqueFillableFormParsedUkm();
- ManuallyFillAddressForm("Flo", "Master", "77401", "US", &address_form);
+ ManuallyFillAddressForm("Jane", "Doe", "77401", "US", &address_form);
FormSubmitted(address_form);
// Set up our credit card form data with non_focusable form field.
@@ -805,8 +805,8 @@ TEST_F(CreditCardSaveManagerTest, LocalCreditCard_WithNonFocusableField) {
FormsSeen(std::vector<FormData>(1, credit_card_form));
// Edit the data, and submit.
- credit_card_form.fields[0].value = u"Flo";
- credit_card_form.fields[1].value = u"Master";
+ credit_card_form.fields[0].value = u"Jane";
+ credit_card_form.fields[1].value = u"Doe";
credit_card_form.fields[2].value = u"4111111111111111";
credit_card_form.fields[3].value = ASCIIToUTF16(test::NextMonth());
credit_card_form.fields[4].value = ASCIIToUTF16(test::NextYear());
@@ -832,8 +832,8 @@ TEST_F(CreditCardSaveManagerTest,
FormsSeen(std::vector<FormData>(1, credit_card_form));
// Edit the data, and submit.
- credit_card_form.fields[0].value = u"Flo";
- credit_card_form.fields[1].value = u"Master";
+ credit_card_form.fields[0].value = u"Jane";
+ credit_card_form.fields[1].value = u"Doe";
credit_card_form.fields[2].value = u"4111111111111111";
credit_card_form.fields[3].value = ASCIIToUTF16(test::NextMonth());
credit_card_form.fields[4].value = ASCIIToUTF16(test::NextYear());
@@ -865,8 +865,8 @@ TEST_F(CreditCardSaveManagerTest,
FormsSeen(std::vector<FormData>(1, credit_card_form));
// Edit the data, and submit.
- credit_card_form.fields[0].value = u"Flo";
- credit_card_form.fields[1].value = u"Master";
+ credit_card_form.fields[0].value = u"Jane";
+ credit_card_form.fields[1].value = u"Doe";
credit_card_form.fields[2].value = u"4111111111111111";
credit_card_form.fields[3].value = ASCIIToUTF16(test::NextMonth());
credit_card_form.fields[4].value = ASCIIToUTF16(test::NextYear());
@@ -896,7 +896,7 @@ TEST_F(
FormsSeen(std::vector<FormData>(1, address_form));
ExpectUniqueFillableFormParsedUkm();
- ManuallyFillAddressForm("Flo", "Master", "77401", "US", &address_form);
+ ManuallyFillAddressForm("Jane", "Doe", "77401", "US", &address_form);
FormSubmitted(address_form);
// Set up our credit card form data with non_focusable form field.
@@ -908,8 +908,8 @@ TEST_F(
FormsSeen(std::vector<FormData>(1, credit_card_form));
// Edit the data, and submit.
- credit_card_form.fields[0].value = u"Flo";
- credit_card_form.fields[1].value = u"Master";
+ credit_card_form.fields[0].value = u"Jane";
+ credit_card_form.fields[1].value = u"Doe";
credit_card_form.fields[2].value = u"4111111111111111";
credit_card_form.fields[3].value = ASCIIToUTF16(test::NextMonth());
credit_card_form.fields[4].value = ASCIIToUTF16(test::NextYear());
@@ -935,7 +935,7 @@ TEST_F(CreditCardSaveManagerTest,
FormsSeen(std::vector<FormData>(1, address_form));
ExpectUniqueFillableFormParsedUkm();
- ManuallyFillAddressForm("Flo", "Master", "77401", "US", &address_form);
+ ManuallyFillAddressForm("Jane", "Doe", "77401", "US", &address_form);
FormSubmitted(address_form);
// Set up our credit card form data with non_focusable form field.
@@ -947,8 +947,8 @@ TEST_F(CreditCardSaveManagerTest,
FormsSeen(std::vector<FormData>(1, credit_card_form));
// Edit the data, and submit.
- credit_card_form.fields[0].value = u"Flo";
- credit_card_form.fields[1].value = u"Master";
+ credit_card_form.fields[0].value = u"Jane";
+ credit_card_form.fields[1].value = u"Doe";
credit_card_form.fields[2].value = u"4111111111111111";
credit_card_form.fields[3].value = ASCIIToUTF16(test::NextMonth());
credit_card_form.fields[4].value = ASCIIToUTF16(test::NextYear());
@@ -973,8 +973,8 @@ TEST_F(CreditCardSaveManagerTest,
FormsSeen(std::vector<FormData>(1, credit_card_form));
// Edit the data, and submit.
- credit_card_form.fields[0].value = u"Flo";
- credit_card_form.fields[1].value = u"Master";
+ credit_card_form.fields[0].value = u"Jane";
+ credit_card_form.fields[1].value = u"Doe";
credit_card_form.fields[2].value = u"4111111111111111";
credit_card_form.fields[3].value = ASCIIToUTF16(test::NextMonth());
credit_card_form.fields[4].value = ASCIIToUTF16(test::NextYear());
@@ -998,11 +998,12 @@ TEST_F(CreditCardSaveManagerTest,
CreateTestCreditCardFormData(&credit_card_form,
CreditCardFormOptions().with_split_names(true));
// Use the two same forms for FormsSeen to mock the dynamic change forms.
- FormsSeen(std::vector<FormData>(2, credit_card_form));
+ FormsSeen({credit_card_form});
+ FormsSeen({credit_card_form});
// Edit the data, and submit.
- credit_card_form.fields[0].value = u"Flo";
- credit_card_form.fields[1].value = u"Master";
+ credit_card_form.fields[0].value = u"Jane";
+ credit_card_form.fields[1].value = u"Doe";
credit_card_form.fields[2].value = u"4111111111111111";
credit_card_form.fields[3].value = ASCIIToUTF16(test::NextMonth());
credit_card_form.fields[4].value = ASCIIToUTF16(test::NextYear());
@@ -1030,11 +1031,12 @@ TEST_F(CreditCardSaveManagerTest,
CreateTestCreditCardFormData(&credit_card_form,
CreditCardFormOptions().with_split_names(true));
// Use the two same forms for FormsSeen to mock the dynamic change forms.
- FormsSeen(std::vector<FormData>(2, credit_card_form));
+ FormsSeen({credit_card_form});
+ FormsSeen({credit_card_form});
// Edit the data, and submit.
- credit_card_form.fields[0].value = u"Flo";
- credit_card_form.fields[1].value = u"Master";
+ credit_card_form.fields[0].value = u"Jane";
+ credit_card_form.fields[1].value = u"Doe";
credit_card_form.fields[2].value = u"4111111111111111";
credit_card_form.fields[3].value = ASCIIToUTF16(test::NextMonth());
credit_card_form.fields[4].value = ASCIIToUTF16(test::NextYear());
@@ -1064,7 +1066,7 @@ TEST_F(
FormsSeen(std::vector<FormData>(1, address_form));
ExpectUniqueFillableFormParsedUkm();
- ManuallyFillAddressForm("Flo", "Master", "77401", "US", &address_form);
+ ManuallyFillAddressForm("Jane", "Doe", "77401", "US", &address_form);
FormSubmitted(address_form);
// Set up our credit card form data without any non_focusable form field.
@@ -1072,11 +1074,12 @@ TEST_F(
CreateTestCreditCardFormData(&credit_card_form,
CreditCardFormOptions().with_split_names(true));
// Use the two same forms for FormsSeen to mock the dynamic change forms.
- FormsSeen(std::vector<FormData>(2, credit_card_form));
+ FormsSeen({credit_card_form});
+ FormsSeen({credit_card_form});
// Edit the data, and submit.
- credit_card_form.fields[0].value = u"Flo";
- credit_card_form.fields[1].value = u"Master";
+ credit_card_form.fields[0].value = u"Jane";
+ credit_card_form.fields[1].value = u"Doe";
credit_card_form.fields[2].value = u"4111111111111111";
credit_card_form.fields[3].value = ASCIIToUTF16(test::NextMonth());
credit_card_form.fields[4].value = ASCIIToUTF16(test::NextYear());
@@ -1102,7 +1105,7 @@ TEST_F(CreditCardSaveManagerTest,
FormsSeen(std::vector<FormData>(1, address_form));
ExpectUniqueFillableFormParsedUkm();
- ManuallyFillAddressForm("Flo", "Master", "77401", "US", &address_form);
+ ManuallyFillAddressForm("Jane", "Doe", "77401", "US", &address_form);
FormSubmitted(address_form);
// Set up our credit card form data without any non_focusable form field.
@@ -1110,11 +1113,12 @@ TEST_F(CreditCardSaveManagerTest,
CreateTestCreditCardFormData(&credit_card_form,
CreditCardFormOptions().with_split_names(true));
// Use the two same forms for FormsSeen to mock the dynamic change forms.
- FormsSeen(std::vector<FormData>(2, credit_card_form));
+ FormsSeen({credit_card_form});
+ FormsSeen({credit_card_form});
// Edit the data, and submit.
- credit_card_form.fields[0].value = u"Flo";
- credit_card_form.fields[1].value = u"Master";
+ credit_card_form.fields[0].value = u"Jane";
+ credit_card_form.fields[1].value = u"Doe";
credit_card_form.fields[2].value = u"4111111111111111";
credit_card_form.fields[3].value = ASCIIToUTF16(test::NextMonth());
credit_card_form.fields[4].value = ASCIIToUTF16(test::NextYear());
@@ -1140,8 +1144,8 @@ TEST_F(CreditCardSaveManagerTest, SaveCreditCardOptions_WithoutDynamicForms) {
FormsSeen(std::vector<FormData>(1, credit_card_form));
// Edit the data, and submit.
- credit_card_form.fields[0].value = u"Flo";
- credit_card_form.fields[1].value = u"Master";
+ credit_card_form.fields[0].value = u"Jane";
+ credit_card_form.fields[1].value = u"Doe";
credit_card_form.fields[2].value = u"4111111111111111";
credit_card_form.fields[3].value = ASCIIToUTF16(test::NextMonth());
credit_card_form.fields[4].value = ASCIIToUTF16(test::NextYear());
@@ -1167,7 +1171,7 @@ TEST_F(CreditCardSaveManagerTest, UploadCreditCard_FirstAndLastName) {
FormsSeen(std::vector<FormData>(1, address_form));
ExpectUniqueFillableFormParsedUkm();
- ManuallyFillAddressForm("Flo", "Master", "77401", "US", &address_form);
+ ManuallyFillAddressForm("Jane", "Doe", "77401", "US", &address_form);
FormSubmitted(address_form);
// Set up our credit card form data with credit card first and last name
@@ -1178,8 +1182,8 @@ TEST_F(CreditCardSaveManagerTest, UploadCreditCard_FirstAndLastName) {
FormsSeen(std::vector<FormData>(1, credit_card_form));
// Edit the data, and submit.
- credit_card_form.fields[0].value = u"Flo";
- credit_card_form.fields[1].value = u"Master";
+ credit_card_form.fields[0].value = u"Jane";
+ credit_card_form.fields[1].value = u"Doe";
credit_card_form.fields[2].value = u"4111111111111111";
credit_card_form.fields[3].value = ASCIIToUTF16(test::NextMonth());
credit_card_form.fields[4].value = ASCIIToUTF16(test::NextYear());
@@ -1223,7 +1227,7 @@ TEST_F(CreditCardSaveManagerTest, UploadCreditCard_LastAndFirstName) {
FormsSeen(std::vector<FormData>(1, address_form));
ExpectUniqueFillableFormParsedUkm();
- ManuallyFillAddressForm("Flo", "Master", "77401", "US", &address_form);
+ ManuallyFillAddressForm("Jane", "Doe", "77401", "US", &address_form);
FormSubmitted(address_form);
// Set up our credit card form data with credit card first and last name
@@ -1256,8 +1260,8 @@ TEST_F(CreditCardSaveManagerTest, UploadCreditCard_LastAndFirstName) {
FormsSeen(std::vector<FormData>(1, credit_card_form));
// Edit the data, and submit.
- credit_card_form.fields[0].value = u"Master";
- credit_card_form.fields[1].value = u"Flo";
+ credit_card_form.fields[0].value = u"Doe";
+ credit_card_form.fields[1].value = u"Jane";
credit_card_form.fields[2].value = u"4111111111111111";
credit_card_form.fields[3].value = ASCIIToUTF16(test::NextMonth());
credit_card_form.fields[4].value = ASCIIToUTF16(test::NextYear());
@@ -1305,7 +1309,7 @@ TEST_F(CreditCardSaveManagerTest, UploadCreditCard_NotSavedLocally) {
test::CreateTestAddressFormData(&address_form);
FormsSeen(std::vector<FormData>(1, address_form));
- ManuallyFillAddressForm("Flo", "Master", "77401", "US", &address_form);
+ ManuallyFillAddressForm("Jane", "Doe", "77401", "US", &address_form);
FormSubmitted(address_form);
// Set up our credit card form data.
@@ -1315,7 +1319,7 @@ TEST_F(CreditCardSaveManagerTest, UploadCreditCard_NotSavedLocally) {
// Edit the data, and submit.
const char* const card_number = "4111111111111111";
- credit_card_form.fields[0].value = u"Flo Master";
+ credit_card_form.fields[0].value = u"Jane Doe";
credit_card_form.fields[1].value = ASCIIToUTF16(card_number);
credit_card_form.fields[2].value = ASCIIToUTF16(test::NextMonth());
credit_card_form.fields[3].value = ASCIIToUTF16(test::NextYear());
@@ -1336,7 +1340,7 @@ TEST_F(CreditCardSaveManagerTest, UploadCreditCard_FeatureNotEnabled) {
FormData address_form;
test::CreateTestAddressFormData(&address_form);
FormsSeen(std::vector<FormData>(1, address_form));
- ManuallyFillAddressForm("Flo", "Master", "77401", "US", &address_form);
+ ManuallyFillAddressForm("Jane", "Doe", "77401", "US", &address_form);
FormSubmitted(address_form);
// Set up our credit card form data.
@@ -1345,7 +1349,7 @@ TEST_F(CreditCardSaveManagerTest, UploadCreditCard_FeatureNotEnabled) {
FormsSeen(std::vector<FormData>(1, credit_card_form));
// Edit the data, and submit.
- credit_card_form.fields[0].value = u"Flo Master";
+ credit_card_form.fields[0].value = u"Jane Doe";
credit_card_form.fields[1].value = u"4111111111111111";
credit_card_form.fields[2].value = ASCIIToUTF16(test::NextMonth());
credit_card_form.fields[3].value = ASCIIToUTF16(test::NextYear());
@@ -1373,7 +1377,7 @@ TEST_F(CreditCardSaveManagerTest, UploadCreditCard_CvcUnavailable) {
FormsSeen(std::vector<FormData>(1, address_form));
ExpectUniqueFillableFormParsedUkm();
- ManuallyFillAddressForm("Flo", "Master", "77401", "US", &address_form);
+ ManuallyFillAddressForm("Jane", "Doe", "77401", "US", &address_form);
FormSubmitted(address_form);
// Set up our credit card form data.
@@ -1383,7 +1387,7 @@ TEST_F(CreditCardSaveManagerTest, UploadCreditCard_CvcUnavailable) {
ExpectFillableFormParsedUkm(2 /* num_fillable_forms_parsed */);
// Edit the data, and submit.
- credit_card_form.fields[0].value = u"Flo Master";
+ credit_card_form.fields[0].value = u"Jane Doe";
credit_card_form.fields[1].value = u"4111111111111111";
credit_card_form.fields[2].value = ASCIIToUTF16(test::NextMonth());
credit_card_form.fields[3].value = ASCIIToUTF16(test::NextYear());
@@ -1416,7 +1420,7 @@ TEST_F(CreditCardSaveManagerTest, UploadCreditCard_CvcInvalidLength) {
FormData address_form;
test::CreateTestAddressFormData(&address_form);
FormsSeen(std::vector<FormData>(1, address_form));
- ManuallyFillAddressForm("Flo", "Master", "77401", "US", &address_form);
+ ManuallyFillAddressForm("Jane", "Doe", "77401", "US", &address_form);
FormSubmitted(address_form);
// Set up our credit card form data.
@@ -1425,7 +1429,7 @@ TEST_F(CreditCardSaveManagerTest, UploadCreditCard_CvcInvalidLength) {
FormsSeen(std::vector<FormData>(1, credit_card_form));
// Edit the data, and submit.
- credit_card_form.fields[0].value = u"Flo Master";
+ credit_card_form.fields[0].value = u"Jane Doe";
credit_card_form.fields[1].value = u"4111111111111111";
credit_card_form.fields[2].value = ASCIIToUTF16(test::NextMonth());
credit_card_form.fields[3].value = ASCIIToUTF16(test::NextYear());
@@ -1458,7 +1462,7 @@ TEST_F(CreditCardSaveManagerTest, UploadCreditCard_MultipleCvcFields) {
FormData address_form;
test::CreateTestAddressFormData(&address_form);
FormsSeen(std::vector<FormData>(1, address_form));
- ManuallyFillAddressForm("Flo", "Master", "77401", "US", &address_form);
+ ManuallyFillAddressForm("Jane", "Doe", "77401", "US", &address_form);
FormSubmitted(address_form);
// Set up our credit card form data.
@@ -1486,7 +1490,7 @@ TEST_F(CreditCardSaveManagerTest, UploadCreditCard_MultipleCvcFields) {
FormsSeen(std::vector<FormData>(1, credit_card_form));
// Edit the data, and submit.
- credit_card_form.fields[0].value = u"Flo Master";
+ credit_card_form.fields[0].value = u"Jane Doe";
credit_card_form.fields[1].value = u"4111111111111111";
credit_card_form.fields[2].value = ASCIIToUTF16(test::NextMonth());
credit_card_form.fields[3].value = ASCIIToUTF16(test::NextYear());
@@ -1517,7 +1521,7 @@ TEST_F(CreditCardSaveManagerTest, UploadCreditCard_NoCvcFieldOnForm) {
FormData address_form;
test::CreateTestAddressFormData(&address_form);
FormsSeen(std::vector<FormData>(1, address_form));
- ManuallyFillAddressForm("Flo", "Master", "77401", "US", &address_form);
+ ManuallyFillAddressForm("Jane", "Doe", "77401", "US", &address_form);
FormSubmitted(address_form);
// Set up our credit card form data. Note that CVC field is missing.
@@ -1541,7 +1545,7 @@ TEST_F(CreditCardSaveManagerTest, UploadCreditCard_NoCvcFieldOnForm) {
FormsSeen(std::vector<FormData>(1, credit_card_form));
// Edit the data, and submit.
- credit_card_form.fields[0].value = u"Flo Master";
+ credit_card_form.fields[0].value = u"Jane Doe";
credit_card_form.fields[1].value = u"4111111111111111";
credit_card_form.fields[2].value = ASCIIToUTF16(test::NextMonth());
credit_card_form.fields[3].value = ASCIIToUTF16(test::NextYear());
@@ -1574,7 +1578,7 @@ TEST_F(CreditCardSaveManagerTest,
FormData address_form;
test::CreateTestAddressFormData(&address_form);
FormsSeen({address_form});
- ManuallyFillAddressForm("Flo", "Master", "77401", "US", &address_form);
+ ManuallyFillAddressForm("Jane", "Doe", "77401", "US", &address_form);
FormSubmitted(address_form);
// Set up our credit card form data. Note that CVC field is missing.
@@ -1600,7 +1604,7 @@ TEST_F(CreditCardSaveManagerTest,
FormsSeen({credit_card_form});
// Enter an invalid cvc in "Random Field" and submit.
- credit_card_form.fields[0].value = u"Flo Master";
+ credit_card_form.fields[0].value = u"Jane Doe";
credit_card_form.fields[1].value = u"4111111111111111";
credit_card_form.fields[2].value = ASCIIToUTF16(test::NextMonth());
credit_card_form.fields[3].value = ASCIIToUTF16(test::NextYear());
@@ -1634,7 +1638,7 @@ TEST_F(CreditCardSaveManagerTest,
FormData address_form;
test::CreateTestAddressFormData(&address_form);
FormsSeen({address_form});
- ManuallyFillAddressForm("Flo", "Master", "77401", "US", &address_form);
+ ManuallyFillAddressForm("Jane", "Doe", "77401", "US", &address_form);
FormSubmitted(address_form);
// Set up our credit card form data. Note that CVC field is missing.
@@ -1660,7 +1664,7 @@ TEST_F(CreditCardSaveManagerTest,
FormsSeen({credit_card_form});
// Enter a valid cvc in "Random Field" and submit.
- credit_card_form.fields[0].value = u"Flo Master";
+ credit_card_form.fields[0].value = u"Jane Doe";
credit_card_form.fields[1].value = u"4111111111111111";
credit_card_form.fields[2].value = ASCIIToUTF16(test::NextMonth());
credit_card_form.fields[3].value = ASCIIToUTF16(test::NextYear());
@@ -1696,7 +1700,7 @@ TEST_F(CreditCardSaveManagerTest,
FormData address_form;
test::CreateTestAddressFormData(&address_form);
FormsSeen({address_form});
- ManuallyFillAddressForm("Flo", "Master", "77401", "US", &address_form);
+ ManuallyFillAddressForm("Jane", "Doe", "77401", "US", &address_form);
FormSubmitted(address_form);
// Set up our credit card form data. Note that CVC field is missing.
@@ -1722,7 +1726,7 @@ TEST_F(CreditCardSaveManagerTest,
FormsSeen({credit_card_form});
// Enter a valid cvc in "Random Field" and submit.
- credit_card_form.fields[0].value = u"Flo Master";
+ credit_card_form.fields[0].value = u"Jane Doe";
credit_card_form.fields[1].value = u"4111111111111111";
credit_card_form.fields[2].value = ASCIIToUTF16(test::NextMonth());
credit_card_form.fields[3].value = ASCIIToUTF16(test::NextYear());
@@ -1758,7 +1762,7 @@ TEST_F(CreditCardSaveManagerTest, UploadCreditCard_NoProfileAvailable) {
FormsSeen(std::vector<FormData>(1, credit_card_form));
// Edit the data, and submit.
- credit_card_form.fields[0].value = u"Bob Master";
+ credit_card_form.fields[0].value = u"Jane Doe";
credit_card_form.fields[1].value = u"4111111111111111";
credit_card_form.fields[2].value = ASCIIToUTF16(test::NextMonth());
credit_card_form.fields[3].value = ASCIIToUTF16(test::NextYear());
@@ -1796,7 +1800,7 @@ TEST_F(CreditCardSaveManagerTest, UploadCreditCard_NoRecentlyUsedProfile) {
test::CreateTestAddressFormData(&address_form);
FormsSeen({address_form});
- ManuallyFillAddressForm("Flo", "Master", "77401", "US", &address_form);
+ ManuallyFillAddressForm("Jane", "Doe", "77401", "US", &address_form);
FormSubmitted(address_form);
// Set the current time to another value.
@@ -1808,7 +1812,7 @@ TEST_F(CreditCardSaveManagerTest, UploadCreditCard_NoRecentlyUsedProfile) {
FormsSeen(std::vector<FormData>(1, credit_card_form));
// Edit the data, and submit.
- credit_card_form.fields[0].value = u"Flo Master";
+ credit_card_form.fields[0].value = u"Jane Doe";
credit_card_form.fields[1].value = u"4111111111111111";
credit_card_form.fields[2].value = ASCIIToUTF16(test::NextMonth());
credit_card_form.fields[3].value = ASCIIToUTF16(test::NextYear());
@@ -1847,7 +1851,7 @@ TEST_F(CreditCardSaveManagerTest,
FormsSeen(std::vector<FormData>(1, credit_card_form));
// Edit the data, and submit.
- credit_card_form.fields[0].value = u"Flo Master";
+ credit_card_form.fields[0].value = u"Jane Doe";
credit_card_form.fields[1].value = u"4111111111111111";
credit_card_form.fields[2].value = ASCIIToUTF16(test::NextMonth());
credit_card_form.fields[3].value = ASCIIToUTF16(test::NextYear());
@@ -1936,7 +1940,7 @@ TEST_F(CreditCardSaveManagerTest,
FormsSeen(std::vector<FormData>(1, credit_card_form));
// Edit the data, and submit.
- credit_card_form.fields[0].value = u"Flo Master";
+ credit_card_form.fields[0].value = u"Jane Doe";
credit_card_form.fields[1].value = u"4111111111111111";
credit_card_form.fields[2].value = ASCIIToUTF16(test::NextMonth());
credit_card_form.fields[3].value = ASCIIToUTF16(test::NextYear());
@@ -1965,7 +1969,40 @@ TEST_F(CreditCardSaveManagerTest,
CreateTestCreditCardFormData(&credit_card_form, CreditCardFormOptions());
FormsSeen(std::vector<FormData>(1, credit_card_form));
- credit_card_form.fields[0].value = u"Flo Master";
+ credit_card_form.fields[0].value = u"Jane Doe";
+ credit_card_form.fields[1].value = u"4111111111111111";
+ credit_card_form.fields[2].value = ASCIIToUTF16(test::NextMonth());
+ credit_card_form.fields[3].value = ASCIIToUTF16(test::NextYear());
+ credit_card_form.fields[4].value = u"123";
+ FormSubmitted(credit_card_form);
+
+ EXPECT_FALSE(autofill_client_.ConfirmSaveCardLocallyWasCalled());
+ EXPECT_TRUE(credit_card_save_manager_->CreditCardWasUploaded());
+
+ std::vector<const char*> active_experiments_in_request =
+ payments_client_->active_experiments_in_request();
+ EXPECT_THAT(active_experiments_in_request,
+ testing::Not(testing::Contains(
+ testing::StrEq("AutofillSaveCardUiExperiment"))));
+}
+
+TEST_F(
+ CreditCardSaveManagerTest,
+ AttemptToOfferCardUploadSave_SaveCardUiExperimentEnabledWithoutAddedInOutgoingRequest) {
+ // Setting the flag and params for the save card ui experiment with value 3 as
+ // we are not getting the updated/experimental TOS for that experiment arm.
+ base::test::ScopedFeatureList scoped_feature_list;
+ scoped_feature_list.InitAndEnableFeatureWithParameters(
+ features::kAutofillSaveCardUiExperiment,
+ {{"autofill_save_card_ui_experiment_selector_in_number", "3"}});
+
+ // Set up our credit card form data.
+ FormData credit_card_form;
+ CreateTestCreditCardFormData(&credit_card_form, CreditCardFormOptions());
+ FormsSeen(std::vector<FormData>(1, credit_card_form));
+
+ // Edit the data, and submit.
+ credit_card_form.fields[0].value = u"Jane Doe";
credit_card_form.fields[1].value = u"4111111111111111";
credit_card_form.fields[2].value = ASCIIToUTF16(test::NextMonth());
credit_card_form.fields[3].value = ASCIIToUTF16(test::NextYear());
@@ -1975,6 +2012,7 @@ TEST_F(CreditCardSaveManagerTest,
EXPECT_FALSE(autofill_client_.ConfirmSaveCardLocallyWasCalled());
EXPECT_TRUE(credit_card_save_manager_->CreditCardWasUploaded());
+ // Confirm that active experiments vector has the correct value.
std::vector<const char*> active_experiments_in_request =
payments_client_->active_experiments_in_request();
EXPECT_THAT(active_experiments_in_request,
@@ -2042,10 +2080,10 @@ TEST_F(CreditCardSaveManagerTest, UploadCreditCard_ZipCodesConflict) {
FormsSeen(address_forms);
ExpectFillableFormParsedUkm(2 /* num_fillable_forms_parsed */);
- ManuallyFillAddressForm("Flo", "Master", "77401-8294", "US", &address_form1);
+ ManuallyFillAddressForm("Jane", "Doe", "77401-8294", "US", &address_form1);
FormSubmitted(address_form1);
- ManuallyFillAddressForm("Flo", "Master", "77401-1234", "US", &address_form2);
+ ManuallyFillAddressForm("Jane", "Doe", "77401-1234", "US", &address_form2);
FormSubmitted(address_form2);
// Set up our credit card form data.
@@ -2055,7 +2093,7 @@ TEST_F(CreditCardSaveManagerTest, UploadCreditCard_ZipCodesConflict) {
ExpectFillableFormParsedUkm(3 /* num_fillable_forms_parsed */);
// Edit the data and submit.
- credit_card_form.fields[0].value = u"Flo Master";
+ credit_card_form.fields[0].value = u"Jane Doe";
credit_card_form.fields[1].value = u"4111111111111111";
credit_card_form.fields[2].value = ASCIIToUTF16(test::NextMonth());
credit_card_form.fields[3].value = ASCIIToUTF16(test::NextYear());
@@ -2089,14 +2127,14 @@ TEST_F(CreditCardSaveManagerTest,
// instead of submitting a form, because they're deduped on form submit.
AutofillProfile profile1;
profile1.set_guid("00000000-0000-0000-0000-000000000001");
- profile1.SetInfo(NAME_FULL, u"Flo Master", "en-US");
+ profile1.SetInfo(NAME_FULL, u"Jane Doe", "en-US");
profile1.SetInfo(ADDRESS_HOME_ZIP, u"H3B2Y5", "en-US");
profile1.SetInfo(ADDRESS_HOME_COUNTRY, u"CA", "en-US");
personal_data().AddProfile(profile1);
AutofillProfile profile2;
profile2.set_guid("00000000-0000-0000-0000-000000000002");
- profile2.SetInfo(NAME_FULL, u"Flo Master", "en-US");
+ profile2.SetInfo(NAME_FULL, u"Jane Doe", "en-US");
profile2.SetInfo(ADDRESS_HOME_ZIP, u"h3b 2y5", "en-US");
profile2.SetInfo(ADDRESS_HOME_COUNTRY, u"CA", "en-US");
personal_data().AddProfile(profile2);
@@ -2107,7 +2145,7 @@ TEST_F(CreditCardSaveManagerTest,
FormsSeen({credit_card_form});
// Edit the data and submit.
- credit_card_form.fields[0].value = u"Flo Master";
+ credit_card_form.fields[0].value = u"Jane Doe";
credit_card_form.fields[1].value = u"4111111111111111";
credit_card_form.fields[2].value = ASCIIToUTF16(test::NextMonth());
credit_card_form.fields[3].value = ASCIIToUTF16(test::NextYear());
@@ -2146,10 +2184,10 @@ TEST_F(CreditCardSaveManagerTest, UploadCreditCard_ZipCodesHavePrefixMatch) {
address_forms.push_back(address_form2);
FormsSeen(address_forms);
- ManuallyFillAddressForm("Flo", "Master", "77401", "US", &address_form1);
+ ManuallyFillAddressForm("Jane", "Doe", "77401", "US", &address_form1);
FormSubmitted(address_form1);
- ManuallyFillAddressForm("Flo", "Master", "77401-8294", "US", &address_form2);
+ ManuallyFillAddressForm("Jane", "Doe", "77401-8294", "US", &address_form2);
FormSubmitted(address_form2);
// Set up our credit card form data.
@@ -2158,7 +2196,7 @@ TEST_F(CreditCardSaveManagerTest, UploadCreditCard_ZipCodesHavePrefixMatch) {
FormsSeen(std::vector<FormData>(1, credit_card_form));
// Edit the data and submit.
- credit_card_form.fields[0].value = u"Flo Master";
+ credit_card_form.fields[0].value = u"Jane Doe";
credit_card_form.fields[1].value = u"4111111111111111";
credit_card_form.fields[2].value = ASCIIToUTF16(test::NextMonth());
credit_card_form.fields[3].value = ASCIIToUTF16(test::NextYear());
@@ -2194,7 +2232,7 @@ TEST_F(CreditCardSaveManagerTest, UploadCreditCard_NoZipCodeAvailable) {
// other countries which autofill requires a zip code for) would result in no
// address being imported at all, and then we never reach the check for
// missing zip code in the upload code.
- ManuallyFillAddressForm("Flo", "Master", "" /* zip_code */, "Venezuela",
+ ManuallyFillAddressForm("Jane", "Doe", "" /* zip_code */, "Venezuela",
&address_form);
FormSubmitted(address_form);
@@ -2204,7 +2242,7 @@ TEST_F(CreditCardSaveManagerTest, UploadCreditCard_NoZipCodeAvailable) {
FormsSeen(std::vector<FormData>(1, credit_card_form));
// Edit the data, and submit.
- credit_card_form.fields[0].value = u"Flo Master";
+ credit_card_form.fields[0].value = u"Jane Doe";
credit_card_form.fields[1].value = u"4111111111111111";
credit_card_form.fields[2].value = ASCIIToUTF16(test::NextMonth());
credit_card_form.fields[3].value = ASCIIToUTF16(test::NextYear());
@@ -2239,11 +2277,11 @@ TEST_F(CreditCardSaveManagerTest, UploadCreditCard_CCFormHasMiddleInitial) {
FormsSeen({address_form1, address_form2});
// Names can be different case.
- ManuallyFillAddressForm("flo", "master", "77401", "US", &address_form1);
+ ManuallyFillAddressForm("jane", "doe", "77401", "US", &address_form1);
FormSubmitted(address_form1);
// And they can have a middle initial even if the other names don't.
- ManuallyFillAddressForm("Flo W", "Master", "77401", "US", &address_form2);
+ ManuallyFillAddressForm("Jane W", "Doe", "77401", "US", &address_form2);
FormSubmitted(address_form2);
// Set up our credit card form data.
@@ -2253,7 +2291,7 @@ TEST_F(CreditCardSaveManagerTest, UploadCreditCard_CCFormHasMiddleInitial) {
// Edit the data, but use the name with a middle initial *and* period, and
// submit.
- credit_card_form.fields[0].value = u"Flo W. Master";
+ credit_card_form.fields[0].value = u"Jane W. Doe";
credit_card_form.fields[1].value = u"4111111111111111";
credit_card_form.fields[2].value = ASCIIToUTF16(test::NextMonth());
credit_card_form.fields[3].value = ASCIIToUTF16(test::NextYear());
@@ -2285,9 +2323,9 @@ TEST_F(CreditCardSaveManagerTest, UploadCreditCard_NoMiddleInitialInCCForm) {
FormsSeen({address_form1, address_form2});
// Names can have different variations of middle initials.
- ManuallyFillAddressForm("flo w.", "master", "77401", "US", &address_form1);
+ ManuallyFillAddressForm("jane w.", "doe", "77401", "US", &address_form1);
FormSubmitted(address_form1);
- ManuallyFillAddressForm("Flo W", "Master", "77401", "US", &address_form2);
+ ManuallyFillAddressForm("Jane W", "Doe", "77401", "US", &address_form2);
FormSubmitted(address_form2);
// Set up our credit card form data.
@@ -2296,7 +2334,7 @@ TEST_F(CreditCardSaveManagerTest, UploadCreditCard_NoMiddleInitialInCCForm) {
FormsSeen({credit_card_form});
// Edit the data, but do not use middle initial.
- credit_card_form.fields[0].value = u"Flo Master";
+ credit_card_form.fields[0].value = u"Jane Doe";
credit_card_form.fields[1].value = u"4111111111111111";
credit_card_form.fields[2].value = ASCIIToUTF16(test::NextMonth());
credit_card_form.fields[3].value = ASCIIToUTF16(test::NextYear());
@@ -2424,10 +2462,10 @@ TEST_F(CreditCardSaveManagerTest, UploadCreditCard_NamesCanMismatch) {
address_forms.push_back(address_form2);
FormsSeen(address_forms);
- ManuallyFillAddressForm("Flo", "Master", "77401", "US", &address_form1);
+ ManuallyFillAddressForm("Jane", "Doe", "77401", "US", &address_form1);
FormSubmitted(address_form1);
- ManuallyFillAddressForm("Master", "Blaster", "77401", "US", &address_form2);
+ ManuallyFillAddressForm("John", "Smith", "77401", "US", &address_form2);
FormSubmitted(address_form2);
// Set up our credit card form data.
@@ -2436,7 +2474,7 @@ TEST_F(CreditCardSaveManagerTest, UploadCreditCard_NamesCanMismatch) {
FormsSeen(std::vector<FormData>(1, credit_card_form));
// Edit the data, but use yet another name, and submit.
- credit_card_form.fields[0].value = u"Bob Master";
+ credit_card_form.fields[0].value = u"Different Person";
credit_card_form.fields[1].value = u"4111111111111111";
credit_card_form.fields[2].value = ASCIIToUTF16(test::NextMonth());
credit_card_form.fields[3].value = ASCIIToUTF16(test::NextYear());
@@ -2479,14 +2517,14 @@ TEST_F(CreditCardSaveManagerTest, UploadCreditCard_IgnoreOldProfiles) {
test::CreateTestAddressFormData(&address_form2);
FormsSeen({address_form1, address_form2});
- ManuallyFillAddressForm("Flo", "Master", "77401", "US", &address_form1);
+ ManuallyFillAddressForm("Jane", "Doe", "77401", "US", &address_form1);
FormSubmitted(address_form1);
// Advance the current time. Since |address_form1| will not be a recently
// used address profile, we will not include it in the candidate profiles.
test_clock.SetNow(kMuchLaterTime);
- ManuallyFillAddressForm("Master", "Blaster", "77401", "US", &address_form2);
+ ManuallyFillAddressForm("John", "Smith", "77401", "US", &address_form2);
FormSubmitted(address_form2);
// Set up our credit card form data.
@@ -2495,7 +2533,7 @@ TEST_F(CreditCardSaveManagerTest, UploadCreditCard_IgnoreOldProfiles) {
FormsSeen(std::vector<FormData>(1, credit_card_form));
// Edit the data, but use yet another name, and submit.
- credit_card_form.fields[0].value = u"Master Blaster";
+ credit_card_form.fields[0].value = u"John Smith";
credit_card_form.fields[1].value = u"4111111111111111";
credit_card_form.fields[2].value = ASCIIToUTF16(test::NextMonth());
credit_card_form.fields[3].value = ASCIIToUTF16(test::NextYear());
@@ -2601,7 +2639,7 @@ TEST_F(CreditCardSaveManagerTest,
FormData address_form;
test::CreateTestAddressFormData(&address_form);
FormsSeen(std::vector<FormData>(1, address_form));
- ManuallyFillAddressForm("Flo", "Master", "77401", "US", &address_form);
+ ManuallyFillAddressForm("Jane", "Doe", "77401", "US", &address_form);
FormSubmitted(address_form);
// Set up our credit card form data.
FormData credit_card_form;
@@ -2610,7 +2648,7 @@ TEST_F(CreditCardSaveManagerTest,
FormsSeen(std::vector<FormData>(1, credit_card_form));
// Edit the data, and submit.
- credit_card_form.fields[0].value = u"Flo Master";
+ credit_card_form.fields[0].value = u"Jane Doe";
credit_card_form.fields[1].value = u"4111111111111111";
credit_card_form.fields[2].value = ASCIIToUTF16(test::NextMonth());
credit_card_form.fields[3].value = ASCIIToUTF16(test::NextYear());
@@ -2636,7 +2674,7 @@ TEST_F(CreditCardSaveManagerTest,
FormData address_form;
test::CreateTestAddressFormData(&address_form);
FormsSeen(std::vector<FormData>(1, address_form));
- ManuallyFillAddressForm("Flo", "Master", "77401", "US", &address_form);
+ ManuallyFillAddressForm("Jane", "Doe", "77401", "US", &address_form);
FormSubmitted(address_form);
// Set up our credit card form data.
FormData credit_card_form;
@@ -2646,7 +2684,7 @@ TEST_F(CreditCardSaveManagerTest,
FormsSeen(std::vector<FormData>(1, credit_card_form));
// Edit the data, and submit.
- credit_card_form.fields[0].value = u"Flo Master";
+ credit_card_form.fields[0].value = u"Jane Doe";
credit_card_form.fields[1].value = u"4111111111111111";
credit_card_form.fields[2].value = ASCIIToUTF16(test::NextMonth());
credit_card_form.fields[3].value = ASCIIToUTF16(test::NextYear());
@@ -2671,7 +2709,7 @@ TEST_F(
FormData address_form;
test::CreateTestAddressFormData(&address_form);
FormsSeen(std::vector<FormData>(1, address_form));
- ManuallyFillAddressForm("Flo", "Master", "77401", "US", &address_form);
+ ManuallyFillAddressForm("Jane", "Doe", "77401", "US", &address_form);
FormSubmitted(address_form);
// Set up our credit card form data.
@@ -2680,7 +2718,7 @@ TEST_F(
FormsSeen(std::vector<FormData>(1, credit_card_form));
// Edit the data, and submit.
- credit_card_form.fields[0].value = u"Flo Master";
+ credit_card_form.fields[0].value = u"Jane Doe";
credit_card_form.fields[1].value = u"4111111111111111";
credit_card_form.fields[2].value = ASCIIToUTF16(test::NextMonth());
credit_card_form.fields[3].value = ASCIIToUTF16(test::NextYear());
@@ -2927,7 +2965,7 @@ TEST_F(
FormData address_form;
test::CreateTestAddressFormData(&address_form);
FormsSeen(std::vector<FormData>(1, address_form));
- ManuallyFillAddressForm("Flo", "Master", "77401", "US", &address_form);
+ ManuallyFillAddressForm("Jane", "Doe", "77401", "US", &address_form);
FormSubmitted(address_form);
// Set up our credit card form data.
@@ -2936,7 +2974,7 @@ TEST_F(
FormsSeen(std::vector<FormData>(1, credit_card_form));
// Edit the data, but don't include a expiration date, and submit.
- credit_card_form.fields[0].value = u"Flo Master";
+ credit_card_form.fields[0].value = u"Jane Doe";
credit_card_form.fields[1].value = u"4111111111111111";
credit_card_form.fields[2].value = u"";
credit_card_form.fields[3].value = u"";
@@ -2969,7 +3007,7 @@ TEST_F(
FormData address_form;
test::CreateTestAddressFormData(&address_form);
FormsSeen(std::vector<FormData>(1, address_form));
- ManuallyFillAddressForm("Flo", "Master", "77401", "US", &address_form);
+ ManuallyFillAddressForm("Jane", "Doe", "77401", "US", &address_form);
FormSubmitted(address_form);
// Set up our credit card form data.
@@ -2978,7 +3016,7 @@ TEST_F(
FormsSeen(std::vector<FormData>(1, credit_card_form));
// Edit the data, but don't include a expiration date, and submit.
- credit_card_form.fields[0].value = u"Flo Master";
+ credit_card_form.fields[0].value = u"Jane Doe";
credit_card_form.fields[1].value = u"4111111111111111";
credit_card_form.fields[2].value = u"";
credit_card_form.fields[3].value = u"";
@@ -3042,7 +3080,7 @@ TEST_F(CreditCardSaveManagerTest,
FormData address_form;
test::CreateTestAddressFormData(&address_form);
FormsSeen(std::vector<FormData>(1, address_form));
- ManuallyFillAddressForm("Flo", "Master", "77401", "US", &address_form);
+ ManuallyFillAddressForm("Jane", "Doe", "77401", "US", &address_form);
FormSubmitted(address_form);
// Set up our credit card form data.
@@ -3340,7 +3378,7 @@ TEST_F(CreditCardSaveManagerTest, UploadCreditCard_UploadDetailsFails) {
FormData address_form;
test::CreateTestAddressFormData(&address_form);
FormsSeen(std::vector<FormData>(1, address_form));
- ManuallyFillAddressForm("Flo", "Master", "77401", "US", &address_form);
+ ManuallyFillAddressForm("Jane", "Doe", "77401", "US", &address_form);
FormSubmitted(address_form);
// Set up our credit card form data.
@@ -3349,7 +3387,7 @@ TEST_F(CreditCardSaveManagerTest, UploadCreditCard_UploadDetailsFails) {
FormsSeen(std::vector<FormData>(1, credit_card_form));
// Edit the data, and submit.
- credit_card_form.fields[0].value = u"Flo Master";
+ credit_card_form.fields[0].value = u"Jane Doe";
credit_card_form.fields[1].value = u"4111111111111111";
credit_card_form.fields[2].value = ASCIIToUTF16(test::NextMonth());
credit_card_form.fields[3].value = ASCIIToUTF16(test::NextYear());
@@ -3378,13 +3416,13 @@ TEST_F(CreditCardSaveManagerTest, DuplicateMaskedCreditCard_NoUpload) {
FormData address_form;
test::CreateTestAddressFormData(&address_form);
FormsSeen(std::vector<FormData>(1, address_form));
- ManuallyFillAddressForm("Flo", "Master", "77401", "US", &address_form);
+ ManuallyFillAddressForm("Jane", "Doe", "77401", "US", &address_form);
FormSubmitted(address_form);
// Add a masked credit card whose |TypeAndLastFourDigits| matches what we will
// enter below.
CreditCard credit_card(CreditCard::MASKED_SERVER_CARD, "a123");
- test::SetCreditCardInfo(&credit_card, "Flo Master", "1111",
+ test::SetCreditCardInfo(&credit_card, "Jane Doe", "1111",
test::NextMonth().c_str(), test::NextYear().c_str(),
"1");
credit_card.SetNetworkForMaskedCard(kVisaCard);
@@ -3396,7 +3434,7 @@ TEST_F(CreditCardSaveManagerTest, DuplicateMaskedCreditCard_NoUpload) {
FormsSeen(std::vector<FormData>(1, credit_card_form));
// Edit the data, and submit.
- credit_card_form.fields[0].value = u"Flo Master";
+ credit_card_form.fields[0].value = u"Jane Doe";
credit_card_form.fields[1].value = u"4111111111111111";
credit_card_form.fields[2].value = ASCIIToUTF16(test::NextMonth());
credit_card_form.fields[3].value = ASCIIToUTF16(test::NextYear());
@@ -4091,7 +4129,7 @@ TEST_F(CreditCardSaveManagerTest,
FormData address_form;
test::CreateTestAddressFormData(&address_form);
FormsSeen(std::vector<FormData>(1, address_form));
- ManuallyFillAddressForm("Flo", "Master", "77401", "US", &address_form);
+ ManuallyFillAddressForm("Jane", "Doe", "77401", "US", &address_form);
FormSubmitted(address_form);
// Set up our credit card form data.
@@ -4100,7 +4138,7 @@ TEST_F(CreditCardSaveManagerTest,
FormsSeen(std::vector<FormData>(1, credit_card_form));
// Edit the data, and submit.
- credit_card_form.fields[0].value = u"Flo Master";
+ credit_card_form.fields[0].value = u"Jane Doe";
credit_card_form.fields[1].value = u"4111111111111111";
credit_card_form.fields[2].value = ASCIIToUTF16(test::NextMonth());
credit_card_form.fields[3].value = ASCIIToUTF16(test::NextYear());
@@ -4189,7 +4227,7 @@ TEST_F(CreditCardSaveManagerTest,
FormData address_form;
test::CreateTestAddressFormData(&address_form);
FormsSeen(std::vector<FormData>(1, address_form));
- ManuallyFillAddressForm("Flo", "Master", "77401", "US", &address_form);
+ ManuallyFillAddressForm("Jane", "Doe", "77401", "US", &address_form);
FormSubmitted(address_form);
// Set up our credit card form data.
@@ -4238,7 +4276,7 @@ TEST_F(CreditCardSaveManagerTest,
// Set up a new address profile without a postal code.
AutofillProfile profile;
profile.set_guid("00000000-0000-0000-0000-000000000200");
- profile.SetInfo(NAME_FULL, u"Flo Master", "en-US");
+ profile.SetInfo(NAME_FULL, u"Jane Doe", "en-US");
profile.SetInfo(ADDRESS_HOME_LINE1, u"123 Testing St.", "en-US");
profile.SetInfo(ADDRESS_HOME_CITY, u"Mountain View", "en-US");
profile.SetInfo(ADDRESS_HOME_STATE, u"California", "en-US");
@@ -4251,7 +4289,7 @@ TEST_F(CreditCardSaveManagerTest,
FormsSeen(std::vector<FormData>(1, credit_card_form));
// Edit the data, and submit.
- credit_card_form.fields[0].value = u"Flo Master";
+ credit_card_form.fields[0].value = u"Jane Doe";
credit_card_form.fields[1].value = u"4111111111111111";
credit_card_form.fields[2].value = ASCIIToUTF16(test::NextMonth());
credit_card_form.fields[3].value = ASCIIToUTF16(test::NextYear());
@@ -4286,7 +4324,7 @@ TEST_F(CreditCardSaveManagerTest,
// Set up two new address profiles with conflicting postal codes.
AutofillProfile profile1;
profile1.set_guid("00000000-0000-0000-0000-000000000200");
- profile1.SetInfo(NAME_FULL, u"Flo Master", "en-US");
+ profile1.SetInfo(NAME_FULL, u"Jane Doe", "en-US");
profile1.SetInfo(ADDRESS_HOME_LINE1, u"123 Testing St.", "en-US");
profile1.SetInfo(ADDRESS_HOME_CITY, u"Mountain View", "en-US");
profile1.SetInfo(ADDRESS_HOME_STATE, u"California", "en-US");
@@ -4295,7 +4333,7 @@ TEST_F(CreditCardSaveManagerTest,
personal_data().AddProfile(profile1);
AutofillProfile profile2;
profile2.set_guid("00000000-0000-0000-0000-000000000201");
- profile2.SetInfo(NAME_FULL, u"Flo Master", "en-US");
+ profile2.SetInfo(NAME_FULL, u"Jane Doe", "en-US");
profile2.SetInfo(ADDRESS_HOME_LINE1, u"234 Other Place", "en-US");
profile2.SetInfo(ADDRESS_HOME_CITY, u"Fake City", "en-US");
profile2.SetInfo(ADDRESS_HOME_STATE, u"Stateland", "en-US");
@@ -4309,7 +4347,7 @@ TEST_F(CreditCardSaveManagerTest,
FormsSeen(std::vector<FormData>(1, credit_card_form));
// Edit the data, and submit.
- credit_card_form.fields[0].value = u"Flo Master";
+ credit_card_form.fields[0].value = u"Jane Doe";
credit_card_form.fields[1].value = u"4111111111111111";
credit_card_form.fields[2].value = ASCIIToUTF16(test::NextMonth());
credit_card_form.fields[3].value = ASCIIToUTF16(test::NextYear());
@@ -4397,7 +4435,7 @@ TEST_F(CreditCardSaveManagerTest, UploadCreditCard_UploadOfLocalCard) {
// Add a local credit card whose |TypeAndLastFourDigits| matches what we will
// enter below.
CreditCard local_card;
- test::SetCreditCardInfo(&local_card, "Flo Master", "4111111111111111",
+ test::SetCreditCardInfo(&local_card, "Jane Doe", "4111111111111111",
test::NextMonth().c_str(), test::NextYear().c_str(),
"1");
local_card.set_record_type(CreditCard::LOCAL_CARD);
@@ -4410,7 +4448,7 @@ TEST_F(CreditCardSaveManagerTest, UploadCreditCard_UploadOfLocalCard) {
FormsSeen(std::vector<FormData>(1, address_form));
ExpectUniqueFillableFormParsedUkm();
- ManuallyFillAddressForm("Flo", "Master", "77401", "US", &address_form);
+ ManuallyFillAddressForm("Jane", "Doe", "77401", "US", &address_form);
FormSubmitted(address_form);
// Set up our credit card form data.
@@ -4420,7 +4458,7 @@ TEST_F(CreditCardSaveManagerTest, UploadCreditCard_UploadOfLocalCard) {
ExpectFillableFormParsedUkm(2 /* num_fillable_forms_parsed */);
// Edit the data, and submit.
- credit_card_form.fields[0].value = u"Flo Master";
+ credit_card_form.fields[0].value = u"Jane Doe";
credit_card_form.fields[1].value = u"4111111111111111";
credit_card_form.fields[2].value = ASCIIToUTF16(test::NextMonth());
credit_card_form.fields[3].value = ASCIIToUTF16(test::NextYear());
@@ -4450,7 +4488,7 @@ TEST_F(CreditCardSaveManagerTest, UploadCreditCard_UploadOfNewCard) {
FormsSeen(std::vector<FormData>(1, address_form));
ExpectUniqueFillableFormParsedUkm();
- ManuallyFillAddressForm("Flo", "Master", "77401", "US", &address_form);
+ ManuallyFillAddressForm("Jane", "Doe", "77401", "US", &address_form);
FormSubmitted(address_form);
// Set up our credit card form data.
@@ -4460,7 +4498,7 @@ TEST_F(CreditCardSaveManagerTest, UploadCreditCard_UploadOfNewCard) {
ExpectFillableFormParsedUkm(2 /* num_fillable_forms_parsed */);
// Edit the data, and submit.
- credit_card_form.fields[0].value = u"Flo Master";
+ credit_card_form.fields[0].value = u"Jane Doe";
credit_card_form.fields[1].value = u"4111111111111111";
credit_card_form.fields[2].value = ASCIIToUTF16(test::NextMonth());
credit_card_form.fields[3].value = ASCIIToUTF16(test::NextYear());
@@ -4493,7 +4531,7 @@ TEST_F(CreditCardSaveManagerTest,
// Add a local credit card whose |TypeAndLastFourDigits| matches what we will
// enter below.
CreditCard local_card;
- test::SetCreditCardInfo(&local_card, "Flo Master", "4111111111111111",
+ test::SetCreditCardInfo(&local_card, "Jane Doe", "4111111111111111",
test::NextMonth().c_str(), test::NextYear().c_str(),
"1");
local_card.set_record_type(CreditCard::LOCAL_CARD);
@@ -4506,7 +4544,7 @@ TEST_F(CreditCardSaveManagerTest,
FormsSeen(std::vector<FormData>(1, address_form));
ExpectUniqueFillableFormParsedUkm();
- ManuallyFillAddressForm("Flo", "Master", "77401", "US", &address_form);
+ ManuallyFillAddressForm("Jane", "Doe", "77401", "US", &address_form);
FormSubmitted(address_form);
// Set up our credit card form data.
@@ -4516,7 +4554,7 @@ TEST_F(CreditCardSaveManagerTest,
ExpectFillableFormParsedUkm(2 /* num_fillable_forms_parsed */);
// Edit the data, and submit.
- credit_card_form.fields[0].value = u"Flo Master";
+ credit_card_form.fields[0].value = u"Jane Doe";
credit_card_form.fields[1].value = u"4111111111111111";
credit_card_form.fields[2].value = ASCIIToUTF16(test::NextMonth());
credit_card_form.fields[3].value = ASCIIToUTF16(test::NextYear());
@@ -4542,7 +4580,7 @@ TEST_F(CreditCardSaveManagerTest,
FormData address_form;
test::CreateTestAddressFormData(&address_form);
FormsSeen(std::vector<FormData>(1, address_form));
- ManuallyFillAddressForm("Flo", "Master", "77401", "US", &address_form);
+ ManuallyFillAddressForm("Jane", "Doe", "77401", "US", &address_form);
FormSubmitted(address_form);
// Set up our credit card form data.
@@ -4551,7 +4589,7 @@ TEST_F(CreditCardSaveManagerTest,
FormsSeen(std::vector<FormData>(1, credit_card_form));
// Edit the data, and submit.
- credit_card_form.fields[0].value = u"Flo Master";
+ credit_card_form.fields[0].value = u"Jane Doe";
credit_card_form.fields[1].value = u"4111111111111111";
credit_card_form.fields[2].value = ASCIIToUTF16(test::NextMonth());
credit_card_form.fields[3].value = ASCIIToUTF16(test::NextYear());
@@ -4572,7 +4610,7 @@ TEST_F(CreditCardSaveManagerTest,
FormData address_form;
test::CreateTestAddressFormData(&address_form);
FormsSeen(std::vector<FormData>(1, address_form));
- ManuallyFillAddressForm("Flo", "Master", "77401", "US", &address_form);
+ ManuallyFillAddressForm("Jane", "Doe", "77401", "US", &address_form);
FormSubmitted(address_form);
// Set up our credit card form data.
@@ -4581,7 +4619,7 @@ TEST_F(CreditCardSaveManagerTest,
FormsSeen(std::vector<FormData>(1, credit_card_form));
// Edit the data, and submit.
- credit_card_form.fields[0].value = u"Flo Master";
+ credit_card_form.fields[0].value = u"Jane Doe";
credit_card_form.fields[1].value = u"4111111111111111";
credit_card_form.fields[2].value = ASCIIToUTF16(test::NextMonth());
credit_card_form.fields[3].value = ASCIIToUTF16(test::NextYear());
@@ -4606,7 +4644,7 @@ TEST_F(CreditCardSaveManagerTest,
FormData address_form;
test::CreateTestAddressFormData(&address_form);
FormsSeen(std::vector<FormData>(1, address_form));
- ManuallyFillAddressForm("Flo", "Master", "77401", "US", &address_form);
+ ManuallyFillAddressForm("Jane", "Doe", "77401", "US", &address_form);
FormSubmitted(address_form);
// Set up our credit card form data.
@@ -4615,7 +4653,7 @@ TEST_F(CreditCardSaveManagerTest,
FormsSeen(std::vector<FormData>(1, credit_card_form));
// Edit the data, and submit.
- credit_card_form.fields[0].value = u"Flo Master";
+ credit_card_form.fields[0].value = u"Jane Doe";
credit_card_form.fields[1].value = u"4111111111111111";
credit_card_form.fields[2].value = ASCIIToUTF16(test::NextMonth());
credit_card_form.fields[3].value = ASCIIToUTF16(test::NextYear());
@@ -4634,7 +4672,7 @@ TEST_F(CreditCardSaveManagerTest,
FormData address_form;
test::CreateTestAddressFormData(&address_form);
FormsSeen(std::vector<FormData>(1, address_form));
- ManuallyFillAddressForm("Flo", "Master", "77401", "US", &address_form);
+ ManuallyFillAddressForm("Jane", "Doe", "77401", "US", &address_form);
FormSubmitted(address_form);
// Set up our credit card form data.
@@ -4643,7 +4681,7 @@ TEST_F(CreditCardSaveManagerTest,
FormsSeen(std::vector<FormData>(1, credit_card_form));
// Edit the data, and submit.
- credit_card_form.fields[0].value = u"Flo Master";
+ credit_card_form.fields[0].value = u"Jane Doe";
credit_card_form.fields[1].value = u"4111111111111111";
credit_card_form.fields[2].value = ASCIIToUTF16(test::NextMonth());
credit_card_form.fields[3].value = ASCIIToUTF16(test::NextYear());
@@ -4674,7 +4712,7 @@ TEST_F(CreditCardSaveManagerTest,
ExpectFillableFormParsedUkm(1 /* num_fillable_forms_parsed */);
// Edit the data, and submit.
- credit_card_form.fields[0].value = u"Flo Master";
+ credit_card_form.fields[0].value = u"Jane Doe";
credit_card_form.fields[1].value = u"4111111111111111";
credit_card_form.fields[2].value = ASCIIToUTF16(test::NextMonth());
credit_card_form.fields[3].value = ASCIIToUTF16(test::NextYear());
@@ -4713,7 +4751,7 @@ TEST_F(CreditCardSaveManagerTest,
FormsSeen(std::vector<FormData>(1, address_form));
ExpectUniqueFillableFormParsedUkm();
- ManuallyFillAddressForm("Flo", "Master", "77401", "US", &address_form);
+ ManuallyFillAddressForm("Jane", "Doe", "77401", "US", &address_form);
FormSubmitted(address_form);
// Set up our credit card form data.
@@ -4723,7 +4761,7 @@ TEST_F(CreditCardSaveManagerTest,
ExpectFillableFormParsedUkm(2 /* num_fillable_forms_parsed */);
// Edit the data, and submit.
- credit_card_form.fields[0].value = u"Flo Master";
+ credit_card_form.fields[0].value = u"Jane Doe";
credit_card_form.fields[1].value = u"4111111111111111";
credit_card_form.fields[2].value = ASCIIToUTF16(test::NextMonth());
credit_card_form.fields[3].value = ASCIIToUTF16(test::NextYear());
@@ -4765,7 +4803,7 @@ TEST_F(CreditCardSaveManagerTest,
ExpectFillableFormParsedUkm(1 /* num_fillable_forms_parsed */);
// Edit the data, and submit.
- credit_card_form.fields[0].value = u"Flo Master";
+ credit_card_form.fields[0].value = u"Jane Doe";
credit_card_form.fields[1].value = u"4111111111111111";
credit_card_form.fields[2].value = ASCIIToUTF16(test::NextMonth());
credit_card_form.fields[3].value = ASCIIToUTF16(test::NextYear());
@@ -4805,7 +4843,7 @@ TEST_F(CreditCardSaveManagerTest, UploadCreditCard_MaxStrikesDisallowsSave) {
FormsSeen(std::vector<FormData>(1, address_form));
ExpectUniqueFillableFormParsedUkm();
- ManuallyFillAddressForm("Flo", "Master", "77401", "US", &address_form);
+ ManuallyFillAddressForm("Jane", "Doe", "77401", "US", &address_form);
FormSubmitted(address_form);
// Set up our credit card form data.
@@ -4815,7 +4853,7 @@ TEST_F(CreditCardSaveManagerTest, UploadCreditCard_MaxStrikesDisallowsSave) {
ExpectFillableFormParsedUkm(2 /* num_fillable_forms_parsed */);
// Edit the data, and submit.
- credit_card_form.fields[0].value = u"Flo Master";
+ credit_card_form.fields[0].value = u"Jane Doe";
credit_card_form.fields[1].value = u"4111111111111111";
credit_card_form.fields[2].value = ASCIIToUTF16(test::NextMonth());
credit_card_form.fields[3].value = ASCIIToUTF16(test::NextYear());
@@ -4863,7 +4901,7 @@ TEST_F(CreditCardSaveManagerTest,
ExpectFillableFormParsedUkm(1 /* num_fillable_forms_parsed */);
// Edit the data, and submit.
- credit_card_form.fields[0].value = u"Flo Master";
+ credit_card_form.fields[0].value = u"Jane Doe";
credit_card_form.fields[1].value = u"4111111111111111";
credit_card_form.fields[2].value = ASCIIToUTF16(test::NextMonth());
credit_card_form.fields[3].value = ASCIIToUTF16(test::NextYear());
@@ -4904,7 +4942,7 @@ TEST_F(CreditCardSaveManagerTest, UploadCreditCard_MaxStrikesStillAllowsSave) {
FormsSeen(std::vector<FormData>(1, address_form));
ExpectUniqueFillableFormParsedUkm();
- ManuallyFillAddressForm("Flo", "Master", "77401", "US", &address_form);
+ ManuallyFillAddressForm("Jane", "Doe", "77401", "US", &address_form);
FormSubmitted(address_form);
// Set up our credit card form data.
@@ -4914,7 +4952,7 @@ TEST_F(CreditCardSaveManagerTest, UploadCreditCard_MaxStrikesStillAllowsSave) {
ExpectFillableFormParsedUkm(2 /* num_fillable_forms_parsed */);
// Edit the data, and submit.
- credit_card_form.fields[0].value = u"Flo Master";
+ credit_card_form.fields[0].value = u"Jane Doe";
credit_card_form.fields[1].value = u"4111111111111111";
credit_card_form.fields[2].value = ASCIIToUTF16(test::NextMonth());
credit_card_form.fields[3].value = ASCIIToUTF16(test::NextYear());
@@ -4956,7 +4994,7 @@ TEST_F(CreditCardSaveManagerTest,
FormsSeen(std::vector<FormData>(1, address_form));
ExpectUniqueFillableFormParsedUkm();
- ManuallyFillAddressForm("Flo", "Master", "77401", "US", &address_form);
+ ManuallyFillAddressForm("Jane", "Doe", "77401", "US", &address_form);
FormSubmitted(address_form);
// Set up our credit card form data with credit card first and last name
@@ -4967,8 +5005,8 @@ TEST_F(CreditCardSaveManagerTest,
FormsSeen(std::vector<FormData>(1, credit_card_form));
// Edit the data, and submit.
- credit_card_form.fields[0].value = u"Flo";
- credit_card_form.fields[1].value = u"Master";
+ credit_card_form.fields[0].value = u"Jane";
+ credit_card_form.fields[1].value = u"Doe";
credit_card_form.fields[2].value = u"4111111111111111";
credit_card_form.fields[3].value = ASCIIToUTF16(test::NextMonth());
credit_card_form.fields[4].value = ASCIIToUTF16(test::NextYear());
@@ -5004,7 +5042,7 @@ TEST_F(CreditCardSaveManagerTest,
FormsSeen(std::vector<FormData>(1, address_form));
ExpectUniqueFillableFormParsedUkm();
- ManuallyFillAddressForm("Flo", "Master", "77401", "US", &address_form);
+ ManuallyFillAddressForm("Jane", "Doe", "77401", "US", &address_form);
FormSubmitted(address_form);
// Set up our credit card form data with credit card first and last name
@@ -5015,8 +5053,8 @@ TEST_F(CreditCardSaveManagerTest,
FormsSeen(std::vector<FormData>(1, credit_card_form));
// Edit the data, and submit.
- credit_card_form.fields[0].value = u"Flo";
- credit_card_form.fields[1].value = u"Master";
+ credit_card_form.fields[0].value = u"Jane";
+ credit_card_form.fields[1].value = u"Doe";
credit_card_form.fields[2].value = u"4111111111111111";
credit_card_form.fields[3].value = ASCIIToUTF16(test::NextMonth());
credit_card_form.fields[4].value = ASCIIToUTF16(test::NextYear());
@@ -5051,7 +5089,7 @@ TEST_F(CreditCardSaveManagerTest, LocallySaveCreditCard_ClearStrikesOnAdd) {
ExpectFillableFormParsedUkm(1 /* num_fillable_forms_parsed */);
// Edit the data, and submit.
- credit_card_form.fields[0].value = u"Flo Master";
+ credit_card_form.fields[0].value = u"Jane Doe";
credit_card_form.fields[1].value = u"4111111111111111";
credit_card_form.fields[2].value = ASCIIToUTF16(test::NextMonth());
credit_card_form.fields[3].value = ASCIIToUTF16(test::NextYear());
@@ -5082,7 +5120,7 @@ TEST_F(CreditCardSaveManagerTest, UploadCreditCard_ClearStrikesOnAdd) {
FormsSeen(std::vector<FormData>(1, address_form));
ExpectUniqueFillableFormParsedUkm();
- ManuallyFillAddressForm("Flo", "Master", "77401", "US", &address_form);
+ ManuallyFillAddressForm("Jane", "Doe", "77401", "US", &address_form);
FormSubmitted(address_form);
// Set up our credit card form data.
@@ -5092,7 +5130,7 @@ TEST_F(CreditCardSaveManagerTest, UploadCreditCard_ClearStrikesOnAdd) {
ExpectFillableFormParsedUkm(2 /* num_fillable_forms_parsed */);
// Edit the data, and submit.
- credit_card_form.fields[0].value = u"Flo Master";
+ credit_card_form.fields[0].value = u"Jane Doe";
credit_card_form.fields[1].value = u"4111111111111111";
credit_card_form.fields[2].value = ASCIIToUTF16(test::NextMonth());
credit_card_form.fields[3].value = ASCIIToUTF16(test::NextYear());
@@ -5125,7 +5163,7 @@ TEST_F(CreditCardSaveManagerTest, LocallySaveCreditCard_NumStrikesLoggedOnAdd) {
ExpectFillableFormParsedUkm(1 /* num_fillable_forms_parsed */);
// Edit the data, and submit.
- credit_card_form.fields[0].value = u"Flo Master";
+ credit_card_form.fields[0].value = u"Jane Doe";
credit_card_form.fields[1].value = u"4111111111111111";
credit_card_form.fields[2].value = ASCIIToUTF16(test::NextMonth());
credit_card_form.fields[3].value = ASCIIToUTF16(test::NextYear());
@@ -5160,7 +5198,7 @@ TEST_F(CreditCardSaveManagerTest, UploadCreditCard_NumStrikesLoggedOnAdd) {
FormsSeen(std::vector<FormData>(1, address_form));
ExpectUniqueFillableFormParsedUkm();
- ManuallyFillAddressForm("Flo", "Master", "77401", "US", &address_form);
+ ManuallyFillAddressForm("Jane", "Doe", "77401", "US", &address_form);
FormSubmitted(address_form);
// Set up our credit card form data.
@@ -5170,7 +5208,7 @@ TEST_F(CreditCardSaveManagerTest, UploadCreditCard_NumStrikesLoggedOnAdd) {
ExpectFillableFormParsedUkm(2 /* num_fillable_forms_parsed */);
// Edit the data, and submit.
- credit_card_form.fields[0].value = u"Flo Master";
+ credit_card_form.fields[0].value = u"Jane Doe";
credit_card_form.fields[1].value = u"4111111111111111";
credit_card_form.fields[2].value = ASCIIToUTF16(test::NextMonth());
credit_card_form.fields[3].value = ASCIIToUTF16(test::NextYear());
@@ -5234,7 +5272,7 @@ TEST_F(CreditCardSaveManagerTest, UploadSaveNotOfferedForUnsupportedCard) {
FormsSeen(std::vector<FormData>(1, credit_card_form));
// Edit the data, and submit.
- credit_card_form.fields[0].value = u"Flo Master";
+ credit_card_form.fields[0].value = u"Jane Doe";
credit_card_form.fields[1].value = u"5454545454545454";
credit_card_form.fields[2].value = ASCIIToUTF16(test::NextMonth());
credit_card_form.fields[3].value = ASCIIToUTF16(test::NextYear());
@@ -5262,14 +5300,14 @@ TEST_F(CreditCardSaveManagerTest, LocalSaveNotOfferedForSavedUnsupportedCard) {
// Add a local credit card whose number matches what we will
// enter below.
CreditCard local_card;
- test::SetCreditCardInfo(&local_card, "Flo Master", "5454545454545454",
+ test::SetCreditCardInfo(&local_card, "Jane Doe", "5454545454545454",
test::NextMonth().c_str(), test::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 = u"Flo Master";
+ credit_card_form.fields[0].value = u"Jane Doe";
credit_card_form.fields[1].value = u"5454545454545454";
credit_card_form.fields[2].value = ASCIIToUTF16(test::NextMonth());
credit_card_form.fields[3].value = ASCIIToUTF16(test::NextYear());
@@ -5294,7 +5332,7 @@ TEST_F(CreditCardSaveManagerTest, UploadSaveOfferedForSupportedCard) {
FormsSeen(std::vector<FormData>(1, credit_card_form));
// Edit the data, and submit.
- credit_card_form.fields[0].value = u"Flo Master";
+ credit_card_form.fields[0].value = u"Jane Doe";
credit_card_form.fields[1].value = u"4111111111111111";
credit_card_form.fields[2].value = ASCIIToUTF16(test::NextMonth());
credit_card_form.fields[3].value = ASCIIToUTF16(test::NextYear());
@@ -5318,7 +5356,7 @@ TEST_F(CreditCardSaveManagerTest, InvalidLegalMessageInOnDidGetUploadDetails) {
test::CreateTestAddressFormData(&address_form);
FormsSeen(std::vector<FormData>(1, address_form));
- ManuallyFillAddressForm("Flo", "Master", "77401", "US", &address_form);
+ ManuallyFillAddressForm("Jane", "Doe", "77401", "US", &address_form);
FormSubmitted(address_form);
// Set up our credit card form data.
@@ -5328,7 +5366,7 @@ TEST_F(CreditCardSaveManagerTest, InvalidLegalMessageInOnDidGetUploadDetails) {
// Edit the data, and submit.
const char* const card_number = "4111111111111111";
- credit_card_form.fields[0].value = u"Flo Master";
+ credit_card_form.fields[0].value = u"Jane Doe";
credit_card_form.fields[1].value = ASCIIToUTF16(card_number);
credit_card_form.fields[2].value = ASCIIToUTF16(test::NextMonth());
credit_card_form.fields[3].value = ASCIIToUTF16(test::NextYear());
@@ -5356,7 +5394,7 @@ TEST_F(CreditCardSaveManagerTest, LegalMessageInOnDidGetUploadDetails) {
test::CreateTestAddressFormData(&address_form);
FormsSeen(std::vector<FormData>(1, address_form));
- ManuallyFillAddressForm("Flo", "Master", "77401", "US", &address_form);
+ ManuallyFillAddressForm("Jane", "Doe", "77401", "US", &address_form);
FormSubmitted(address_form);
// Set up our credit card form data.
@@ -5366,7 +5404,7 @@ TEST_F(CreditCardSaveManagerTest, LegalMessageInOnDidGetUploadDetails) {
// Edit the data, and submit.
const char* const card_number = "4111111111111111";
- credit_card_form.fields[0].value = u"Flo Master";
+ credit_card_form.fields[0].value = u"Jane Doe";
credit_card_form.fields[1].value = ASCIIToUTF16(card_number);
credit_card_form.fields[2].value = ASCIIToUTF16(test::NextMonth());
credit_card_form.fields[3].value = ASCIIToUTF16(test::NextYear());
diff --git a/chromium/components/autofill/core/browser/payments/local_card_migration_manager.cc b/chromium/components/autofill/core/browser/payments/local_card_migration_manager.cc
index 4909a677287..9566ce385cf 100644
--- a/chromium/components/autofill/core/browser/payments/local_card_migration_manager.cc
+++ b/chromium/components/autofill/core/browser/payments/local_card_migration_manager.cc
@@ -19,6 +19,7 @@
#include "components/autofill/core/browser/data_model/credit_card.h"
#include "components/autofill/core/browser/form_data_importer.h"
#include "components/autofill/core/browser/metrics/autofill_metrics.h"
+#include "components/autofill/core/browser/metrics/payments/local_card_migration_metrics.h"
#include "components/autofill/core/browser/payments/payments_client.h"
#include "components/autofill/core/browser/payments/payments_util.h"
#include "components/autofill/core/browser/personal_data_manager.h"
@@ -59,22 +60,22 @@ bool LocalCardMigrationManager::ShouldOfferLocalCardMigration(
switch (imported_credit_card_record_type_) {
case FormDataImporter::ImportedCreditCardRecordType::LOCAL_CARD:
local_card_migration_origin_ =
- AutofillMetrics::LocalCardMigrationOrigin::UseOfLocalCard;
+ autofill_metrics::LocalCardMigrationOrigin::UseOfLocalCard;
break;
case FormDataImporter::ImportedCreditCardRecordType::SERVER_CARD:
local_card_migration_origin_ =
- AutofillMetrics::LocalCardMigrationOrigin::UseOfServerCard;
+ autofill_metrics::LocalCardMigrationOrigin::UseOfServerCard;
break;
default:
- AutofillMetrics::LogLocalCardMigrationDecisionMetric(
- AutofillMetrics::LocalCardMigrationDecisionMetric::
+ autofill_metrics::LogLocalCardMigrationDecisionMetric(
+ autofill_metrics::LocalCardMigrationDecisionMetric::
NOT_OFFERED_USE_NEW_CARD);
return false;
}
if (!IsCreditCardMigrationEnabled()) {
- AutofillMetrics::LogLocalCardMigrationDecisionMetric(
- AutofillMetrics::LocalCardMigrationDecisionMetric::
+ autofill_metrics::LogLocalCardMigrationDecisionMetric(
+ autofill_metrics::LocalCardMigrationDecisionMetric::
NOT_OFFERED_FAILED_PREREQUISITES);
return false;
}
@@ -83,16 +84,16 @@ bool LocalCardMigrationManager::ShouldOfferLocalCardMigration(
if (GetLocalCardMigrationStrikeDatabase()->ShouldBlockFeature()) {
switch (imported_credit_card_record_type_) {
case FormDataImporter::ImportedCreditCardRecordType::LOCAL_CARD:
- AutofillMetrics::LogLocalCardMigrationNotOfferedDueToMaxStrikesMetric(
+ autofill_metrics::LogLocalCardMigrationNotOfferedDueToMaxStrikesMetric(
AutofillMetrics::SaveTypeMetric::LOCAL);
break;
case FormDataImporter::ImportedCreditCardRecordType::SERVER_CARD:
- AutofillMetrics::LogLocalCardMigrationNotOfferedDueToMaxStrikesMetric(
+ autofill_metrics::LogLocalCardMigrationNotOfferedDueToMaxStrikesMetric(
AutofillMetrics::SaveTypeMetric::SERVER);
break;
}
- AutofillMetrics::LogLocalCardMigrationDecisionMetric(
- AutofillMetrics::LocalCardMigrationDecisionMetric::
+ autofill_metrics::LogLocalCardMigrationDecisionMetric(
+ autofill_metrics::LocalCardMigrationDecisionMetric::
NOT_OFFERED_REACHED_MAX_STRIKE_COUNT);
return false;
}
@@ -114,13 +115,13 @@ bool LocalCardMigrationManager::ShouldOfferLocalCardMigration(
} else if (imported_credit_card_record_type_ ==
FormDataImporter::ImportedCreditCardRecordType::LOCAL_CARD &&
migratable_credit_cards_.size() == 1) {
- AutofillMetrics::LogLocalCardMigrationDecisionMetric(
- AutofillMetrics::LocalCardMigrationDecisionMetric::
+ autofill_metrics::LogLocalCardMigrationDecisionMetric(
+ autofill_metrics::LocalCardMigrationDecisionMetric::
NOT_OFFERED_SINGLE_LOCAL_CARD);
return false;
} else {
- AutofillMetrics::LogLocalCardMigrationDecisionMetric(
- AutofillMetrics::LocalCardMigrationDecisionMetric::
+ autofill_metrics::LogLocalCardMigrationDecisionMetric(
+ autofill_metrics::LocalCardMigrationDecisionMetric::
NOT_OFFERED_NO_MIGRATABLE_CARDS);
return false;
}
@@ -153,9 +154,9 @@ void LocalCardMigrationManager::AttemptToOfferLocalCardMigration(
// Call ShowMainMigrationDialog() to pop up a larger, modal dialog showing the
// local cards to be uploaded.
void LocalCardMigrationManager::OnUserAcceptedIntermediateMigrationDialog() {
- AutofillMetrics::LogLocalCardMigrationPromptMetric(
+ autofill_metrics::LogLocalCardMigrationPromptMetric(
local_card_migration_origin_,
- AutofillMetrics::INTERMEDIATE_BUBBLE_ACCEPTED);
+ autofill_metrics::INTERMEDIATE_BUBBLE_ACCEPTED);
ShowMainMigrationDialog();
}
@@ -163,8 +164,8 @@ void LocalCardMigrationManager::OnUserAcceptedIntermediateMigrationDialog() {
void LocalCardMigrationManager::OnUserAcceptedMainMigrationDialog(
const std::vector<std::string>& selected_card_guids) {
user_accepted_main_migration_dialog_ = true;
- AutofillMetrics::LogLocalCardMigrationPromptMetric(
- local_card_migration_origin_, AutofillMetrics::MAIN_DIALOG_ACCEPTED);
+ autofill_metrics::LogLocalCardMigrationPromptMetric(
+ local_card_migration_origin_, autofill_metrics::MAIN_DIALOG_ACCEPTED);
// Log number of LocalCardMigration strikes when migration was accepted.
base::UmaHistogramCounts1000(
@@ -211,8 +212,8 @@ void LocalCardMigrationManager::OnDidGetUploadDetails(
/*escape_apostrophes=*/true);
if (legal_message_lines_.empty()) {
- AutofillMetrics::LogLocalCardMigrationDecisionMetric(
- AutofillMetrics::LocalCardMigrationDecisionMetric::
+ autofill_metrics::LogLocalCardMigrationDecisionMetric(
+ autofill_metrics::LocalCardMigrationDecisionMetric::
NOT_OFFERED_INVALID_LEGAL_MESSAGE);
return;
}
@@ -226,7 +227,7 @@ void LocalCardMigrationManager::OnDidGetUploadDetails(
if (is_from_settings_page) {
// Set the origin to SettingsPage.
local_card_migration_origin_ =
- AutofillMetrics::LocalCardMigrationOrigin::SettingsPage;
+ autofill_metrics::LocalCardMigrationOrigin::SettingsPage;
// Pops up a larger, modal dialog showing the local cards to be uploaded.
ShowMainMigrationDialog();
} else {
@@ -240,8 +241,8 @@ void LocalCardMigrationManager::OnDidGetUploadDetails(
!payments::IsCreditCardNumberSupported(
imported_credit_card_number_.value(),
supported_card_bin_ranges)) {
- AutofillMetrics::LogLocalCardMigrationDecisionMetric(
- AutofillMetrics::LocalCardMigrationDecisionMetric::
+ autofill_metrics::LogLocalCardMigrationDecisionMetric(
+ autofill_metrics::LocalCardMigrationDecisionMetric::
NOT_OFFERED_USE_UNSUPPORTED_LOCAL_CARD);
return;
}
@@ -249,17 +250,17 @@ void LocalCardMigrationManager::OnDidGetUploadDetails(
FilterOutUnsupportedLocalCards(supported_card_bin_ranges);
// Abandon the migration if no supported card left.
if (migratable_credit_cards_.empty()) {
- AutofillMetrics::LogLocalCardMigrationDecisionMetric(
- AutofillMetrics::LocalCardMigrationDecisionMetric::
+ autofill_metrics::LogLocalCardMigrationDecisionMetric(
+ autofill_metrics::LocalCardMigrationDecisionMetric::
NOT_OFFERED_NO_SUPPORTED_CARDS);
return;
}
client_->ShowLocalCardMigrationDialog(base::BindOnce(
&LocalCardMigrationManager::OnUserAcceptedIntermediateMigrationDialog,
weak_ptr_factory_.GetWeakPtr()));
- AutofillMetrics::LogLocalCardMigrationPromptMetric(
+ autofill_metrics::LogLocalCardMigrationPromptMetric(
local_card_migration_origin_,
- AutofillMetrics::INTERMEDIATE_BUBBLE_SHOWN);
+ autofill_metrics::INTERMEDIATE_BUBBLE_SHOWN);
}
// TODO(crbug.com/876895): Clean up the LoadRiskData Bind/BindRepeating
@@ -267,11 +268,11 @@ void LocalCardMigrationManager::OnDidGetUploadDetails(
client_->LoadRiskData(base::BindRepeating(
&LocalCardMigrationManager::OnDidGetMigrationRiskData,
weak_ptr_factory_.GetWeakPtr()));
- AutofillMetrics::LogLocalCardMigrationDecisionMetric(
- AutofillMetrics::LocalCardMigrationDecisionMetric::OFFERED);
+ autofill_metrics::LogLocalCardMigrationDecisionMetric(
+ autofill_metrics::LocalCardMigrationDecisionMetric::OFFERED);
} else {
- AutofillMetrics::LogLocalCardMigrationDecisionMetric(
- AutofillMetrics::LocalCardMigrationDecisionMetric::
+ autofill_metrics::LogLocalCardMigrationDecisionMetric(
+ autofill_metrics::LocalCardMigrationDecisionMetric::
NOT_OFFERED_GET_UPLOAD_DETAILS_FAILED);
}
}
@@ -378,8 +379,8 @@ LocalCardMigrationManager::GetLocalCardMigrationStrikeDatabase() {
// OnUserAcceptedMainMigrationDialog(). Can be called when user agrees to
// migration on the intermediate dialog or directly from settings page.
void LocalCardMigrationManager::ShowMainMigrationDialog() {
- AutofillMetrics::LogLocalCardMigrationPromptMetric(
- local_card_migration_origin_, AutofillMetrics::MAIN_DIALOG_SHOWN);
+ autofill_metrics::LogLocalCardMigrationPromptMetric(
+ local_card_migration_origin_, autofill_metrics::MAIN_DIALOG_SHOWN);
// Pops up a larger, modal dialog showing the local cards to be uploaded.
client_->ConfirmMigrateLocalCardToCloud(
legal_message_lines_,
diff --git a/chromium/components/autofill/core/browser/payments/local_card_migration_manager.h b/chromium/components/autofill/core/browser/payments/local_card_migration_manager.h
index 24d6855e256..defdf46fb25 100644
--- a/chromium/components/autofill/core/browser/payments/local_card_migration_manager.h
+++ b/chromium/components/autofill/core/browser/payments/local_card_migration_manager.h
@@ -15,6 +15,7 @@
#include "base/memory/raw_ptr.h"
#include "components/autofill/core/browser/autofill_client.h"
#include "components/autofill/core/browser/metrics/autofill_metrics.h"
+#include "components/autofill/core/browser/metrics/payments/local_card_migration_metrics.h"
#include "components/autofill/core/browser/payments/legal_message_line.h"
#include "components/autofill/core/browser/payments/local_card_migration_strike_database.h"
#include "components/autofill/core/browser/payments/payments_client.h"
@@ -249,7 +250,7 @@ class LocalCardMigrationManager {
bool user_accepted_main_migration_dialog_ = false;
// Record the triggering source of the local card migration.
- AutofillMetrics::LocalCardMigrationOrigin local_card_migration_origin_;
+ autofill_metrics::LocalCardMigrationOrigin local_card_migration_origin_;
// Initialized only during tests.
raw_ptr<ObserverForTest> observer_for_testing_ = nullptr;
diff --git a/chromium/components/autofill/core/browser/payments/local_card_migration_manager_unittest.cc b/chromium/components/autofill/core/browser/payments/local_card_migration_manager_unittest.cc
index 3182b70031e..612b8ff95d1 100644
--- a/chromium/components/autofill/core/browser/payments/local_card_migration_manager_unittest.cc
+++ b/chromium/components/autofill/core/browser/payments/local_card_migration_manager_unittest.cc
@@ -28,6 +28,7 @@
#include "components/autofill/core/browser/data_model/autofill_profile.h"
#include "components/autofill/core/browser/data_model/credit_card.h"
#include "components/autofill/core/browser/metrics/autofill_metrics.h"
+#include "components/autofill/core/browser/metrics/payments/local_card_migration_metrics.h"
#include "components/autofill/core/browser/payments/payments_customer_data.h"
#include "components/autofill/core/browser/payments/payments_util.h"
#include "components/autofill/core/browser/payments/test_credit_card_save_manager.h"
@@ -162,7 +163,7 @@ class LocalCardMigrationManagerTest : public testing::Test {
// Verify that the correct histogram entry (and only that) was logged.
void ExpectUniqueLocalCardMigrationDecision(
const base::HistogramTester& histogram_tester,
- AutofillMetrics::LocalCardMigrationDecisionMetric metric) {
+ autofill_metrics::LocalCardMigrationDecisionMetric metric) {
histogram_tester.ExpectUniqueSample("Autofill.LocalCardMigrationDecision",
metric, 1);
}
@@ -174,12 +175,12 @@ class LocalCardMigrationManagerTest : public testing::Test {
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",
+ AddLocalCreditCard(personal_data(), "Jane Doe", "4111111111111111", "11",
test::NextYear().c_str(), "1",
base::GUID::GenerateRandomV4());
// Add another local credit card (but it will not match what we will enter
// below).
- AddLocalCreditCard(personal_data(), "Flo Master", "4444333322221111", "11",
+ AddLocalCreditCard(personal_data(), "Jane Doe", "4444333322221111", "11",
test::NextYear().c_str(), "1",
base::GUID::GenerateRandomV4());
@@ -189,7 +190,7 @@ class LocalCardMigrationManagerTest : public testing::Test {
FormsSeen(std::vector<FormData>(1, credit_card_form));
// Edit the data, and submit.
- EditCreditCardFrom(credit_card_form, "Flo Master", "5555555555554444", "11",
+ EditCreditCardFrom(credit_card_form, "Jane Doe", "5555555555554444", "11",
test::NextYear().c_str(), "123");
FormSubmitted(credit_card_form);
}
@@ -202,11 +203,11 @@ class LocalCardMigrationManagerTest : public testing::Test {
// Add a local credit card whose |TypeAndLastFourDigits| matches what we
// will enter below.
- AddLocalCreditCard(personal_data(), "Flo Master", "4111111111111111", "11",
+ AddLocalCreditCard(personal_data(), "Jane Doe", "4111111111111111", "11",
test::NextYear().c_str(), "1",
base::GUID::GenerateRandomV4());
// Add another local credit card.
- AddLocalCreditCard(personal_data(), "Flo Master", "5555555555554444", "11",
+ AddLocalCreditCard(personal_data(), "Jane Doe", "5555555555554444", "11",
test::NextYear().c_str(), "1",
base::GUID::GenerateRandomV4());
@@ -216,7 +217,7 @@ class LocalCardMigrationManagerTest : public testing::Test {
FormsSeen(std::vector<FormData>(1, credit_card_form));
// Edit the data, and submit.
- EditCreditCardFrom(credit_card_form, "Flo Master", "4111111111111111", "11",
+ EditCreditCardFrom(credit_card_form, "Jane Doe", "4111111111111111", "11",
test::NextYear().c_str(), "123");
FormSubmitted(credit_card_form);
}
@@ -229,15 +230,15 @@ class LocalCardMigrationManagerTest : public testing::Test {
// Add a local credit card whose |TypeAndLastFourDigits| matches what we
// will enter below.
- AddLocalCreditCard(personal_data(), "Flo Master", "4111111111111111", "11",
+ AddLocalCreditCard(personal_data(), "Jane Doe", "4111111111111111", "11",
test::NextYear().c_str(), "1",
base::GUID::GenerateRandomV4());
// Add other invalid local credit cards (invalid card number or expired), so
// it will not trigger migration.
- AddLocalCreditCard(personal_data(), "Flo Master", "4111111111111112", "11",
+ AddLocalCreditCard(personal_data(), "Jane Doe", "4111111111111112", "11",
test::NextYear().c_str(), "1",
base::GUID::GenerateRandomV4());
- AddLocalCreditCard(personal_data(), "Flo Master", "5555555555554444", "11",
+ AddLocalCreditCard(personal_data(), "Jane Doe", "5555555555554444", "11",
test::LastYear().c_str(), "1",
base::GUID::GenerateRandomV4());
@@ -247,7 +248,7 @@ class LocalCardMigrationManagerTest : public testing::Test {
FormsSeen(std::vector<FormData>(1, credit_card_form));
// Edit the data, and submit.
- EditCreditCardFrom(credit_card_form, "Flo Master", "4111111111111111", "11",
+ EditCreditCardFrom(credit_card_form, "Jane Doe", "4111111111111111", "11",
test::NextYear().c_str(), "123");
FormSubmitted(credit_card_form);
}
@@ -262,12 +263,12 @@ class LocalCardMigrationManagerTest : public testing::Test {
// what we will enter below.
CreditCard credit_card(CreditCard::MASKED_SERVER_CARD,
/*server_id=*/"a123");
- test::SetCreditCardInfo(&credit_card, "Flo Master", "1111", "11",
+ test::SetCreditCardInfo(&credit_card, "Jane Doe", "1111", "11",
test::NextYear().c_str(), "1");
credit_card.SetNetworkForMaskedCard(kVisaCard);
personal_data().AddServerCreditCard(credit_card);
// Add one valid local credit card, so it will trigger migration
- AddLocalCreditCard(personal_data(), "Flo Master", "5555555555554444", "11",
+ AddLocalCreditCard(personal_data(), "Jane Doe", "5555555555554444", "11",
test::NextYear().c_str(), "1",
base::GUID::GenerateRandomV4());
@@ -277,7 +278,7 @@ class LocalCardMigrationManagerTest : public testing::Test {
FormsSeen(std::vector<FormData>(1, credit_card_form));
// Edit the data, and submit.
- EditCreditCardFrom(credit_card_form, "Flo Master", "4111111111111111", "11",
+ EditCreditCardFrom(credit_card_form, "Jane Doe", "4111111111111111", "11",
test::NextYear().c_str(), "123");
FormSubmitted(credit_card_form);
}
@@ -292,16 +293,16 @@ class LocalCardMigrationManagerTest : public testing::Test {
// will enter below.
CreditCard credit_card(CreditCard::MASKED_SERVER_CARD,
/*server_id=*/"a123");
- test::SetCreditCardInfo(&credit_card, "Flo Master", "1111", "11",
+ test::SetCreditCardInfo(&credit_card, "Jane Doe", "1111", "11",
test::NextYear().c_str(), "1");
credit_card.SetNetworkForMaskedCard(kVisaCard);
personal_data().AddServerCreditCard(credit_card);
// Add other invalid local credit cards (invalid card number or expired), so
// it will not trigger migration.
- AddLocalCreditCard(personal_data(), "Flo Master", "4111111111111112", "11",
+ AddLocalCreditCard(personal_data(), "Jane Doe", "4111111111111112", "11",
test::NextYear().c_str(), "1",
base::GUID::GenerateRandomV4());
- AddLocalCreditCard(personal_data(), "Flo Master", "5555555555554444", "11",
+ AddLocalCreditCard(personal_data(), "Jane Doe", "5555555555554444", "11",
test::LastYear().c_str(), "1",
base::GUID::GenerateRandomV4());
@@ -311,7 +312,7 @@ class LocalCardMigrationManagerTest : public testing::Test {
FormsSeen(std::vector<FormData>(1, credit_card_form));
// Edit the data, and submit.
- EditCreditCardFrom(credit_card_form, "Flo Master", "4111111111111111", "11",
+ EditCreditCardFrom(credit_card_form, "Jane Doe", "4111111111111111", "11",
test::NextYear().c_str(), "123");
FormSubmitted(credit_card_form);
}
@@ -347,7 +348,7 @@ TEST_F(LocalCardMigrationManagerTest,
// Add a local credit card whose |TypeAndLastFourDigits| matches what we will
// enter below.
- AddLocalCreditCard(personal_data(), "Flo Master", "4111111111111111", "11",
+ AddLocalCreditCard(personal_data(), "Jane Doe", "4111111111111111", "11",
test::NextYear().c_str(), "1",
base::GUID::GenerateRandomV4());
@@ -357,7 +358,7 @@ TEST_F(LocalCardMigrationManagerTest,
FormsSeen(std::vector<FormData>(1, credit_card_form));
// Edit the data, and submit.
- EditCreditCardFrom(credit_card_form, "Flo Master", "4111111111111111", "11",
+ EditCreditCardFrom(credit_card_form, "Jane Doe", "4111111111111111", "11",
test::NextYear().c_str(), "123");
FormSubmitted(credit_card_form);
EXPECT_FALSE(local_card_migration_manager_->LocalCardMigrationWasTriggered());
@@ -430,11 +431,11 @@ TEST_F(LocalCardMigrationManagerTest, MigrateCreditCard_SignInOnly) {
TEST_F(LocalCardMigrationManagerTest, MigrateCreditCard_NoPaymentsAccount) {
// Add a local credit card whose |TypeAndLastFourDigits| matches what we will
// enter below.
- AddLocalCreditCard(personal_data(), "Flo Master", "4111111111111111", "11",
+ AddLocalCreditCard(personal_data(), "Jane Doe", "4111111111111111", "11",
test::NextYear().c_str(), "1",
base::GUID::GenerateRandomV4());
// Add another local credit card.
- AddLocalCreditCard(personal_data(), "Flo Master", "5555555555554444", "11",
+ AddLocalCreditCard(personal_data(), "Jane Doe", "5555555555554444", "11",
test::NextYear().c_str(), "1",
base::GUID::GenerateRandomV4());
@@ -444,7 +445,7 @@ TEST_F(LocalCardMigrationManagerTest, MigrateCreditCard_NoPaymentsAccount) {
FormsSeen(std::vector<FormData>(1, credit_card_form));
// Edit the data, and submit.
- EditCreditCardFrom(credit_card_form, "Flo Master", "4111111111111111", "11",
+ EditCreditCardFrom(credit_card_form, "Jane Doe", "4111111111111111", "11",
test::NextYear().c_str(), "123");
FormSubmitted(credit_card_form);
EXPECT_FALSE(local_card_migration_manager_->LocalCardMigrationWasTriggered());
@@ -462,17 +463,17 @@ TEST_F(LocalCardMigrationManagerTest,
// Add a masked server card whose |TypeAndLastFourDigits| matches a local
// card.
CreditCard server_card(CreditCard::MASKED_SERVER_CARD, "a123");
- test::SetCreditCardInfo(&server_card, "Flo Master", "1111", "11",
+ test::SetCreditCardInfo(&server_card, "Jane Doe", "1111", "11",
test::NextYear().c_str(), "1");
server_card.SetNetworkForMaskedCard(kVisaCard);
personal_data().AddServerCreditCard(server_card);
// Add a local card whose |TypeAndLastFourDigits| matches a masked server
// card.
- AddLocalCreditCard(personal_data(), "Flo Master", "4111111111111111", "11",
+ AddLocalCreditCard(personal_data(), "Jane Doe", "4111111111111111", "11",
test::NextYear().c_str(), "1",
base::GUID::GenerateRandomV4());
// Add another local credit card
- AddLocalCreditCard(personal_data(), "Flo Master", "5555555555554444", "11",
+ AddLocalCreditCard(personal_data(), "Jane Doe", "5555555555554444", "11",
test::NextYear().c_str(), "1",
base::GUID::GenerateRandomV4());
@@ -482,7 +483,7 @@ TEST_F(LocalCardMigrationManagerTest,
FormsSeen(std::vector<FormData>(1, credit_card_form));
// Edit the data, and submit.
- EditCreditCardFrom(credit_card_form, "Flo Master", "5555555555554444", "11",
+ EditCreditCardFrom(credit_card_form, "Jane Doe", "5555555555554444", "11",
test::NextYear().c_str(), "123");
FormSubmitted(credit_card_form);
EXPECT_FALSE(local_card_migration_manager_->LocalCardMigrationWasTriggered());
@@ -499,15 +500,15 @@ TEST_F(LocalCardMigrationManagerTest,
// 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",
+ test::SetCreditCardInfo(&server_card, "Jane Doe", "4111111111111111", "11",
test::NextYear().c_str(), "1");
personal_data().AddServerCreditCard(server_card);
// Add a local credit card whose number matches a full server card.
- AddLocalCreditCard(personal_data(), "Flo Master", "4111111111111111", "11",
+ AddLocalCreditCard(personal_data(), "Jane Doe", "4111111111111111", "11",
test::NextYear().c_str(), "1",
base::GUID::GenerateRandomV4());
// Add another local credit card
- AddLocalCreditCard(personal_data(), "Flo Master", "5555555555554444", "11",
+ AddLocalCreditCard(personal_data(), "Jane Doe", "5555555555554444", "11",
test::NextYear().c_str(), "1",
base::GUID::GenerateRandomV4());
@@ -517,7 +518,7 @@ TEST_F(LocalCardMigrationManagerTest,
FormsSeen(std::vector<FormData>(1, credit_card_form));
// Edit the data, and submit.
- EditCreditCardFrom(credit_card_form, "Flo Master", "5555555555554444", "11",
+ EditCreditCardFrom(credit_card_form, "Jane Doe", "5555555555554444", "11",
test::NextYear().c_str(), "123");
FormSubmitted(credit_card_form);
EXPECT_FALSE(local_card_migration_manager_->LocalCardMigrationWasTriggered());
@@ -532,7 +533,7 @@ TEST_F(LocalCardMigrationManagerTest, GetDetectedValues_AllWithCardHolderName) {
// Add a local credit card whose |TypeAndLastFourDigits| matches what we will
// enter below.
- AddLocalCreditCard(personal_data(), "Flo Master", "4111111111111111", "11",
+ AddLocalCreditCard(personal_data(), "Jane Doe", "4111111111111111", "11",
test::NextYear().c_str(), "1",
base::GUID::GenerateRandomV4());
// Add another local credit card with a different cardholder name.
@@ -546,7 +547,7 @@ TEST_F(LocalCardMigrationManagerTest, GetDetectedValues_AllWithCardHolderName) {
FormsSeen(std::vector<FormData>(1, credit_card_form));
// Edit the data, and submit.
- EditCreditCardFrom(credit_card_form, "Flo Master", "4111111111111111", "11",
+ EditCreditCardFrom(credit_card_form, "Jane Doe", "4111111111111111", "11",
test::NextYear().c_str(), "123");
FormSubmitted(credit_card_form);
EXPECT_TRUE(local_card_migration_manager_->LocalCardMigrationWasTriggered());
@@ -565,7 +566,7 @@ TEST_F(LocalCardMigrationManagerTest,
// Add a local credit card whose |TypeAndLastFourDigits| matches what we will
// enter below.
- AddLocalCreditCard(personal_data(), "Flo Master", "4111111111111111", "11",
+ AddLocalCreditCard(personal_data(), "Jane Doe", "4111111111111111", "11",
test::NextYear().c_str(), "1",
base::GUID::GenerateRandomV4());
// Add another local credit card without card holder name.
@@ -578,7 +579,7 @@ TEST_F(LocalCardMigrationManagerTest,
FormsSeen(std::vector<FormData>(1, credit_card_form));
// Edit the data, and submit.
- EditCreditCardFrom(credit_card_form, "Flo Master", "4111111111111111", "11",
+ EditCreditCardFrom(credit_card_form, "Jane Doe", "4111111111111111", "11",
test::NextYear().c_str(), "123");
FormSubmitted(credit_card_form);
EXPECT_TRUE(local_card_migration_manager_->LocalCardMigrationWasTriggered());
@@ -644,7 +645,7 @@ TEST_F(LocalCardMigrationManagerTest,
// Add a local credit card. One migratable credit card will still trigger
// migration on settings page.
- AddLocalCreditCard(personal_data(), "Flo Master", "4111111111111111", "11",
+ AddLocalCreditCard(personal_data(), "Jane Doe", "4111111111111111", "11",
test::NextYear().c_str(), "1",
base::GUID::GenerateRandomV4());
@@ -672,7 +673,7 @@ TEST_F(LocalCardMigrationManagerTest,
// Add a local credit card. One migratable credit card will still trigger
// migration on settings page.
- AddLocalCreditCard(personal_data(), "Flo Master", "4111111111111111", "11",
+ AddLocalCreditCard(personal_data(), "Jane Doe", "4111111111111111", "11",
test::NextYear().c_str(), "1",
base::GUID::GenerateRandomV4());
@@ -704,7 +705,7 @@ TEST_F(LocalCardMigrationManagerTest, MigrateCreditCard_MigrationSuccess) {
std::make_unique<PaymentsCustomerData>(/*customer_id=*/"123456"));
// Add a local credit card for migration.
- AddLocalCreditCard(personal_data(), "Flo Master", "4111111111111111", "11",
+ AddLocalCreditCard(personal_data(), "Jane Doe", "4111111111111111", "11",
test::NextYear().c_str(), "1",
base::GUID::GenerateRandomV4());
@@ -746,7 +747,7 @@ TEST_F(LocalCardMigrationManagerTest,
// Add a local credit card. One migratable credit card will still trigger
// migration on settings page.
- AddLocalCreditCard(personal_data(), "Flo Master", "4111111111111111", "11",
+ AddLocalCreditCard(personal_data(), "Jane Doe", "4111111111111111", "11",
test::NextYear().c_str(), "1",
base::GUID::GenerateRandomV4());
@@ -789,7 +790,7 @@ TEST_F(LocalCardMigrationManagerTest,
// Add a local credit card. One migratable credit card will still trigger
// migration on settings page.
- AddLocalCreditCard(personal_data(), "Flo Master", "4111111111111111", "11",
+ AddLocalCreditCard(personal_data(), "Jane Doe", "4111111111111111", "11",
test::NextYear().c_str(), "1",
base::GUID::GenerateRandomV4());
@@ -824,11 +825,11 @@ TEST_F(LocalCardMigrationManagerTest,
// Verify selected cards are correctly passed to manager.
TEST_F(LocalCardMigrationManagerTest, MigrateCreditCard_ToggleIsChosen) {
const base::GUID guid1 = base::GUID::GenerateRandomV4();
- AddLocalCreditCard(personal_data(), "Flo Master", "4111111111111111", "11",
+ AddLocalCreditCard(personal_data(), "Jane Doe", "4111111111111111", "11",
test::NextYear().c_str(), "1", guid1);
const base::GUID guid2 = base::GUID::GenerateRandomV4();
- AddLocalCreditCard(personal_data(), "Flo Master", "5454545454545454", "11",
+ AddLocalCreditCard(personal_data(), "Jane Doe", "5454545454545454", "11",
test::NextYear().c_str(), "1", guid2);
// Set the billing_customer_number to designate existence of a Payments
@@ -853,7 +854,7 @@ TEST_F(LocalCardMigrationManagerTest, MigrateCreditCard_ToggleIsChosen) {
TEST_F(LocalCardMigrationManagerTest, DeleteLocalCardViaMigrationDialog) {
const base::GUID guid = base::GUID::GenerateRandomV4();
- AddLocalCreditCard(personal_data(), "Flo Master", "4111111111111111", "11",
+ AddLocalCreditCard(personal_data(), "Jane Doe", "4111111111111111", "11",
test::NextYear().c_str(), "1", guid);
const std::string guid_str = guid.AsLowercaseString();
@@ -919,11 +920,11 @@ TEST_F(LocalCardMigrationManagerTest,
// strike count is logged.
TEST_F(LocalCardMigrationManagerTest, MigrateCreditCard_StrikeCountUMALogged) {
const base::GUID guid1 = base::GUID::GenerateRandomV4();
- AddLocalCreditCard(personal_data(), "Flo Master", "4111111111111111", "11",
+ AddLocalCreditCard(personal_data(), "Jane Doe", "4111111111111111", "11",
test::NextYear().c_str(), "1", guid1);
const base::GUID guid2 = base::GUID::GenerateRandomV4();
- AddLocalCreditCard(personal_data(), "Flo Master", "5454545454545454", "11",
+ AddLocalCreditCard(personal_data(), "Jane Doe", "5454545454545454", "11",
test::NextYear().c_str(), "1", guid2);
// Set the billing_customer_number to designate existence of a Payments
@@ -962,11 +963,11 @@ TEST_F(LocalCardMigrationManagerTest,
// Add a local credit card whose |TypeAndLastFourDigits| matches what we will
// enter below.
- AddLocalCreditCard(personal_data(), "Flo Master", "4111111111111111", "11",
+ AddLocalCreditCard(personal_data(), "Jane Doe", "4111111111111111", "11",
test::NextYear().c_str(), "1",
base::GUID::GenerateRandomV4());
// Add another local credit card.
- AddLocalCreditCard(personal_data(), "Flo Master", "5555555555554444", "11",
+ AddLocalCreditCard(personal_data(), "Jane Doe", "5555555555554444", "11",
test::NextYear().c_str(), "1",
base::GUID::GenerateRandomV4());
@@ -982,7 +983,7 @@ TEST_F(LocalCardMigrationManagerTest,
payments_client_->SetSupportedBINRanges(supported_card_bin_ranges);
// Edit the data, and submit.
- EditCreditCardFrom(credit_card_form, "Flo Master", "4111111111111111", "11",
+ EditCreditCardFrom(credit_card_form, "Jane Doe", "4111111111111111", "11",
test::NextYear().c_str(), "123");
FormSubmitted(credit_card_form);
EXPECT_FALSE(local_card_migration_manager_->IntermediatePromptWasShown());
@@ -999,11 +1000,11 @@ TEST_F(LocalCardMigrationManagerTest,
// Add a local credit card whose |TypeAndLastFourDigits| matches what we will
// enter below.
- AddLocalCreditCard(personal_data(), "Flo Master", "4111111111111111", "11",
+ AddLocalCreditCard(personal_data(), "Jane Doe", "4111111111111111", "11",
test::NextYear().c_str(), "1",
base::GUID::GenerateRandomV4());
// Add another local credit card.
- AddLocalCreditCard(personal_data(), "Flo Master", "5555555555554444", "11",
+ AddLocalCreditCard(personal_data(), "Jane Doe", "5555555555554444", "11",
test::NextYear().c_str(), "1",
base::GUID::GenerateRandomV4());
@@ -1019,7 +1020,7 @@ TEST_F(LocalCardMigrationManagerTest,
FormsSeen(std::vector<FormData>(1, credit_card_form));
// Edit the data, and submit.
- EditCreditCardFrom(credit_card_form, "Flo Master", "4111111111111111", "11",
+ EditCreditCardFrom(credit_card_form, "Jane Doe", "4111111111111111", "11",
test::NextYear().c_str(), "123");
FormSubmitted(credit_card_form);
@@ -1046,12 +1047,12 @@ TEST_F(
// Add a masked server credit card whose |TypeAndLastFourDigits| matches what
// we will enter below.
CreditCard credit_card(CreditCard::MASKED_SERVER_CARD, "a123");
- test::SetCreditCardInfo(&credit_card, "Flo Master", "1111", "11",
+ test::SetCreditCardInfo(&credit_card, "Jane Doe", "1111", "11",
test::NextYear().c_str(), "1");
credit_card.SetNetworkForMaskedCard(kVisaCard);
personal_data().AddServerCreditCard(credit_card);
// Add one valid local credit card, so it will trigger migration
- AddLocalCreditCard(personal_data(), "Flo Master", "5555555555554444", "11",
+ AddLocalCreditCard(personal_data(), "Jane Doe", "5555555555554444", "11",
test::NextYear().c_str(), "1",
base::GUID::GenerateRandomV4());
@@ -1067,7 +1068,7 @@ TEST_F(
FormsSeen(std::vector<FormData>(1, credit_card_form));
// Edit the data, and submit.
- EditCreditCardFrom(credit_card_form, "Flo Master", "4111111111111111", "11",
+ EditCreditCardFrom(credit_card_form, "Jane Doe", "4111111111111111", "11",
test::NextYear().c_str(), "123");
FormSubmitted(credit_card_form);
@@ -1087,12 +1088,12 @@ TEST_F(
// Add a masked server credit card whose |TypeAndLastFourDigits| matches what
// we will enter below.
CreditCard credit_card(CreditCard::MASKED_SERVER_CARD, "a123");
- test::SetCreditCardInfo(&credit_card, "Flo Master", "1111", "11",
+ test::SetCreditCardInfo(&credit_card, "Jane Doe", "1111", "11",
test::NextYear().c_str(), "1");
credit_card.SetNetworkForMaskedCard(kVisaCard);
personal_data().AddServerCreditCard(credit_card);
// Add one valid local credit card, so it will trigger migration
- AddLocalCreditCard(personal_data(), "Flo Master", "5555555555554444", "11",
+ AddLocalCreditCard(personal_data(), "Jane Doe", "5555555555554444", "11",
test::NextYear().c_str(), "1",
base::GUID::GenerateRandomV4());
@@ -1108,7 +1109,7 @@ TEST_F(
FormsSeen(std::vector<FormData>(1, credit_card_form));
// Edit the data, and submit.
- EditCreditCardFrom(credit_card_form, "Flo Master", "4111111111111111", "11",
+ EditCreditCardFrom(credit_card_form, "Jane Doe", "4111111111111111", "11",
test::NextYear().c_str(), "123");
FormSubmitted(credit_card_form);
@@ -1139,16 +1140,16 @@ TEST_F(LocalCardMigrationManagerTest,
// sub-histogram.
histogram_tester.ExpectBucketCount(
"Autofill.LocalCardMigrationOrigin.UseOfLocalCard",
- AutofillMetrics::INTERMEDIATE_BUBBLE_SHOWN, 1);
+ autofill_metrics::INTERMEDIATE_BUBBLE_SHOWN, 1);
histogram_tester.ExpectBucketCount(
"Autofill.LocalCardMigrationOrigin.UseOfLocalCard",
- AutofillMetrics::INTERMEDIATE_BUBBLE_ACCEPTED, 1);
+ autofill_metrics::INTERMEDIATE_BUBBLE_ACCEPTED, 1);
histogram_tester.ExpectBucketCount(
"Autofill.LocalCardMigrationOrigin.UseOfLocalCard",
- AutofillMetrics::MAIN_DIALOG_SHOWN, 1);
+ autofill_metrics::MAIN_DIALOG_SHOWN, 1);
histogram_tester.ExpectBucketCount(
"Autofill.LocalCardMigrationOrigin.UseOfLocalCard",
- AutofillMetrics::MAIN_DIALOG_ACCEPTED, 1);
+ autofill_metrics::MAIN_DIALOG_ACCEPTED, 1);
}
// Using a server card when any number of local cards are eligible for migration
@@ -1163,16 +1164,16 @@ TEST_F(LocalCardMigrationManagerTest,
// sub-histogram.
histogram_tester.ExpectBucketCount(
"Autofill.LocalCardMigrationOrigin.UseOfServerCard",
- AutofillMetrics::INTERMEDIATE_BUBBLE_SHOWN, 1);
+ autofill_metrics::INTERMEDIATE_BUBBLE_SHOWN, 1);
histogram_tester.ExpectBucketCount(
"Autofill.LocalCardMigrationOrigin.UseOfServerCard",
- AutofillMetrics::INTERMEDIATE_BUBBLE_ACCEPTED, 1);
+ autofill_metrics::INTERMEDIATE_BUBBLE_ACCEPTED, 1);
histogram_tester.ExpectBucketCount(
"Autofill.LocalCardMigrationOrigin.UseOfServerCard",
- AutofillMetrics::MAIN_DIALOG_SHOWN, 1);
+ autofill_metrics::MAIN_DIALOG_SHOWN, 1);
histogram_tester.ExpectBucketCount(
"Autofill.LocalCardMigrationOrigin.UseOfServerCard",
- AutofillMetrics::MAIN_DIALOG_ACCEPTED, 1);
+ autofill_metrics::MAIN_DIALOG_ACCEPTED, 1);
}
// Using a server card will not trigger migration even if there are other local
@@ -1200,7 +1201,7 @@ TEST_F(LocalCardMigrationManagerTest,
// Add a local credit card. One migratable credit card will still trigger
// migration on settings page.
- AddLocalCreditCard(personal_data(), "Flo Master", "4111111111111111", "11",
+ AddLocalCreditCard(personal_data(), "Jane Doe", "4111111111111111", "11",
test::NextYear().c_str(), "1",
base::GUID::GenerateRandomV4());
@@ -1213,16 +1214,16 @@ TEST_F(LocalCardMigrationManagerTest,
// Triggering from settings page won't show intermediate bubble.
histogram_tester.ExpectBucketCount(
"Autofill.LocalCardMigrationOrigin.SettingsPage",
- AutofillMetrics::INTERMEDIATE_BUBBLE_SHOWN, 0);
+ autofill_metrics::INTERMEDIATE_BUBBLE_SHOWN, 0);
histogram_tester.ExpectBucketCount(
"Autofill.LocalCardMigrationOrigin.SettingsPage",
- AutofillMetrics::INTERMEDIATE_BUBBLE_ACCEPTED, 0);
+ autofill_metrics::INTERMEDIATE_BUBBLE_ACCEPTED, 0);
histogram_tester.ExpectBucketCount(
"Autofill.LocalCardMigrationOrigin.SettingsPage",
- AutofillMetrics::MAIN_DIALOG_SHOWN, 1);
+ autofill_metrics::MAIN_DIALOG_SHOWN, 1);
histogram_tester.ExpectBucketCount(
"Autofill.LocalCardMigrationOrigin.SettingsPage",
- AutofillMetrics::MAIN_DIALOG_ACCEPTED, 1);
+ autofill_metrics::MAIN_DIALOG_ACCEPTED, 1);
}
// Use new card when submit so migration was not offered. Verify the migration
@@ -1232,7 +1233,7 @@ TEST_F(LocalCardMigrationManagerTest, LogMigrationDecisionMetric_UseNewCard) {
UseNewCardWithLocalCardsOnFile();
ExpectUniqueLocalCardMigrationDecision(
- histogram_tester, AutofillMetrics::LocalCardMigrationDecisionMetric::
+ histogram_tester, autofill_metrics::LocalCardMigrationDecisionMetric::
NOT_OFFERED_USE_NEW_CARD);
}
@@ -1244,11 +1245,11 @@ TEST_F(LocalCardMigrationManagerTest,
base::HistogramTester histogram_tester;
// Add a local credit card whose |TypeAndLastFourDigits| matches what we will
// enter below.
- AddLocalCreditCard(personal_data(), "Flo Master", "4111111111111111", "11",
+ AddLocalCreditCard(personal_data(), "Jane Doe", "4111111111111111", "11",
test::NextYear().c_str(), "1",
base::GUID::GenerateRandomV4());
// Add another local credit card.
- AddLocalCreditCard(personal_data(), "Flo Master", "5555555555554444", "11",
+ AddLocalCreditCard(personal_data(), "Jane Doe", "5555555555554444", "11",
test::NextYear().c_str(), "1",
base::GUID::GenerateRandomV4());
@@ -1258,12 +1259,12 @@ TEST_F(LocalCardMigrationManagerTest,
FormsSeen(std::vector<FormData>(1, credit_card_form));
// Edit the data, and submit.
- EditCreditCardFrom(credit_card_form, "Flo Master", "4111111111111111", "11",
+ EditCreditCardFrom(credit_card_form, "Jane Doe", "4111111111111111", "11",
test::NextYear().c_str(), "123");
FormSubmitted(credit_card_form);
ExpectUniqueLocalCardMigrationDecision(
- histogram_tester, AutofillMetrics::LocalCardMigrationDecisionMetric::
+ histogram_tester, autofill_metrics::LocalCardMigrationDecisionMetric::
NOT_OFFERED_FAILED_PREREQUISITES);
}
@@ -1283,7 +1284,7 @@ TEST_F(LocalCardMigrationManagerTest,
UseLocalCardWithOtherLocalCardsOnFile();
ExpectUniqueLocalCardMigrationDecision(
- histogram_tester, AutofillMetrics::LocalCardMigrationDecisionMetric::
+ histogram_tester, autofill_metrics::LocalCardMigrationDecisionMetric::
NOT_OFFERED_REACHED_MAX_STRIKE_COUNT);
}
@@ -1296,7 +1297,7 @@ TEST_F(LocalCardMigrationManagerTest,
UseLocalCardWithInvalidLocalCardsOnFile();
ExpectUniqueLocalCardMigrationDecision(
- histogram_tester, AutofillMetrics::LocalCardMigrationDecisionMetric::
+ histogram_tester, autofill_metrics::LocalCardMigrationDecisionMetric::
NOT_OFFERED_SINGLE_LOCAL_CARD);
}
@@ -1308,7 +1309,7 @@ TEST_F(LocalCardMigrationManagerTest,
UseServerCardWithInvalidLocalCardsOnFile();
ExpectUniqueLocalCardMigrationDecision(
- histogram_tester, AutofillMetrics::LocalCardMigrationDecisionMetric::
+ histogram_tester, autofill_metrics::LocalCardMigrationDecisionMetric::
NOT_OFFERED_NO_MIGRATABLE_CARDS);
}
@@ -1324,7 +1325,7 @@ TEST_F(LocalCardMigrationManagerTest,
UseLocalCardWithOtherLocalCardsOnFile();
ExpectUniqueLocalCardMigrationDecision(
- histogram_tester, AutofillMetrics::LocalCardMigrationDecisionMetric::
+ histogram_tester, autofill_metrics::LocalCardMigrationDecisionMetric::
NOT_OFFERED_GET_UPLOAD_DETAILS_FAILED);
}
@@ -1340,11 +1341,11 @@ TEST_F(LocalCardMigrationManagerTest,
// Add a local credit card whose |TypeAndLastFourDigits| matches what we will
// enter below.
- AddLocalCreditCard(personal_data(), "Flo Master", "4111111111111111", "11",
+ AddLocalCreditCard(personal_data(), "Jane Doe", "4111111111111111", "11",
test::NextYear().c_str(), "1",
base::GUID::GenerateRandomV4());
// Add another local credit card.
- AddLocalCreditCard(personal_data(), "Flo Master", "5555555555554444", "11",
+ AddLocalCreditCard(personal_data(), "Jane Doe", "5555555555554444", "11",
test::NextYear().c_str(), "1",
base::GUID::GenerateRandomV4());
@@ -1361,12 +1362,12 @@ TEST_F(LocalCardMigrationManagerTest,
payments_client_->SetSupportedBINRanges(supported_card_bin_ranges);
// Edit the data, and submit.
- EditCreditCardFrom(credit_card_form, "Flo Master", "4111111111111111", "11",
+ EditCreditCardFrom(credit_card_form, "Jane Doe", "4111111111111111", "11",
test::NextYear().c_str(), "123");
FormSubmitted(credit_card_form);
ExpectUniqueLocalCardMigrationDecision(
- histogram_tester, AutofillMetrics::LocalCardMigrationDecisionMetric::
+ histogram_tester, autofill_metrics::LocalCardMigrationDecisionMetric::
NOT_OFFERED_USE_UNSUPPORTED_LOCAL_CARD);
}
@@ -1383,12 +1384,12 @@ TEST_F(LocalCardMigrationManagerTest,
// Add a masked server credit card whose |TypeAndLastFourDigits| matches what
// we will enter below.
CreditCard credit_card(CreditCard::MASKED_SERVER_CARD, "a123");
- test::SetCreditCardInfo(&credit_card, "Flo Master", "1111", "11",
+ test::SetCreditCardInfo(&credit_card, "Jane Doe", "1111", "11",
test::NextYear().c_str(), "1");
credit_card.SetNetworkForMaskedCard(kVisaCard);
personal_data().AddServerCreditCard(credit_card);
// Add one valid local credit card, so it will trigger migration
- AddLocalCreditCard(personal_data(), "Flo Master", "5555555555554444", "11",
+ AddLocalCreditCard(personal_data(), "Jane Doe", "5555555555554444", "11",
test::NextYear().c_str(), "1",
base::GUID::GenerateRandomV4());
@@ -1405,12 +1406,12 @@ TEST_F(LocalCardMigrationManagerTest,
FormsSeen(std::vector<FormData>(1, credit_card_form));
// Edit the data, and submit.
- EditCreditCardFrom(credit_card_form, "Flo Master", "4111111111111111", "11",
+ EditCreditCardFrom(credit_card_form, "Jane Doe", "4111111111111111", "11",
test::NextYear().c_str(), "123");
FormSubmitted(credit_card_form);
ExpectUniqueLocalCardMigrationDecision(
- histogram_tester, AutofillMetrics::LocalCardMigrationDecisionMetric::
+ histogram_tester, autofill_metrics::LocalCardMigrationDecisionMetric::
NOT_OFFERED_NO_SUPPORTED_CARDS);
}
@@ -1427,12 +1428,12 @@ TEST_F(LocalCardMigrationManagerTest,
// Add a masked server credit card whose |TypeAndLastFourDigits| matches what
// we will enter below.
CreditCard credit_card(CreditCard::MASKED_SERVER_CARD, "a123");
- test::SetCreditCardInfo(&credit_card, "Flo Master", "1111", "11",
+ test::SetCreditCardInfo(&credit_card, "Jane Doe", "1111", "11",
test::NextYear().c_str(), "1");
credit_card.SetNetworkForMaskedCard(kVisaCard);
personal_data().AddServerCreditCard(credit_card);
// Add one valid local credit card, so it will trigger migration
- AddLocalCreditCard(personal_data(), "Flo Master", "5555555555554444", "11",
+ AddLocalCreditCard(personal_data(), "Jane Doe", "5555555555554444", "11",
test::NextYear().c_str(), "1",
base::GUID::GenerateRandomV4());
@@ -1449,12 +1450,12 @@ TEST_F(LocalCardMigrationManagerTest,
FormsSeen(std::vector<FormData>(1, credit_card_form));
// Edit the data, and submit.
- EditCreditCardFrom(credit_card_form, "Flo Master", "4111111111111111", "11",
+ EditCreditCardFrom(credit_card_form, "Jane Doe", "4111111111111111", "11",
test::NextYear().c_str(), "123");
FormSubmitted(credit_card_form);
ExpectUniqueLocalCardMigrationDecision(
- histogram_tester, AutofillMetrics::LocalCardMigrationDecisionMetric::
+ histogram_tester, autofill_metrics::LocalCardMigrationDecisionMetric::
NOT_OFFERED_NO_SUPPORTED_CARDS);
}
@@ -1467,7 +1468,7 @@ TEST_F(LocalCardMigrationManagerTest,
ExpectUniqueLocalCardMigrationDecision(
histogram_tester,
- AutofillMetrics::LocalCardMigrationDecisionMetric::OFFERED);
+ autofill_metrics::LocalCardMigrationDecisionMetric::OFFERED);
}
// Tests that if payment client returns an invalid legal message migration
@@ -1481,7 +1482,7 @@ TEST_F(LocalCardMigrationManagerTest,
// Verify that the correct histogram entries were logged.
ExpectUniqueLocalCardMigrationDecision(
- histogram_tester, AutofillMetrics::LocalCardMigrationDecisionMetric::
+ histogram_tester, autofill_metrics::LocalCardMigrationDecisionMetric::
NOT_OFFERED_INVALID_LEGAL_MESSAGE);
}
diff --git a/chromium/components/autofill/core/browser/payments/payments_requests/upload_card_request.cc b/chromium/components/autofill/core/browser/payments/payments_requests/upload_card_request.cc
index 646142d1311..5d353d366fb 100644
--- a/chromium/components/autofill/core/browser/payments/payments_requests/upload_card_request.cc
+++ b/chromium/components/autofill/core/browser/payments/payments_requests/upload_card_request.cc
@@ -163,10 +163,6 @@ void UploadCardRequest::ParseResponse(const base::Value& response) {
if (base::FeatureList::IsEnabled(
features::
kAutofillEnableGetDetailsForEnrollParsingInUploadCardResponse) &&
- !base::FeatureList::IsEnabled(
- features::kAutofillEnableToolbarStatusChip) &&
- !base::FeatureList::IsEnabled(
- features::kAutofillCreditCardUploadFeedback) &&
upload_card_response_details_.virtual_card_enrollment_state ==
CreditCard::VirtualCardEnrollmentState::UNENROLLED_AND_ELIGIBLE) {
const auto* virtual_card_enrollment_data =
diff --git a/chromium/components/autofill/core/browser/payments/virtual_card_enrollment_manager.cc b/chromium/components/autofill/core/browser/payments/virtual_card_enrollment_manager.cc
index 4a208e67f59..57afdaeca90 100644
--- a/chromium/components/autofill/core/browser/payments/virtual_card_enrollment_manager.cc
+++ b/chromium/components/autofill/core/browser/payments/virtual_card_enrollment_manager.cc
@@ -77,6 +77,7 @@ void VirtualCardEnrollmentManager::InitVirtualCardEnroll(
ShouldBlockVirtualCardEnrollment(
base::NumberToString(credit_card.instrument_id()),
virtual_card_enrollment_source)) {
+ Reset();
return;
}
@@ -120,7 +121,9 @@ void VirtualCardEnrollmentManager::OnCardSavedAnimationComplete() {
}
}
-void VirtualCardEnrollmentManager::Enroll() {
+void VirtualCardEnrollmentManager::Enroll(
+ absl::optional<VirtualCardEnrollmentUpdateResponseCallback>
+ virtual_card_enrollment_update_response_callback) {
LogUpdateVirtualCardEnrollmentRequestAttempt(
state_.virtual_card_enrollment_fields.virtual_card_enrollment_source,
VirtualCardEnrollmentRequestType::kEnroll);
@@ -136,6 +139,9 @@ void VirtualCardEnrollmentManager::Enroll() {
state_.virtual_card_enrollment_fields.credit_card.instrument_id();
request_details.vcn_context_token = state_.vcn_context_token;
+ virtual_card_enrollment_update_response_callback_ =
+ std::move(virtual_card_enrollment_update_response_callback);
+
payments_client_->UpdateVirtualCardEnrollment(
request_details,
base::BindOnce(&VirtualCardEnrollmentManager::
@@ -149,7 +155,10 @@ void VirtualCardEnrollmentManager::Enroll() {
}
}
-void VirtualCardEnrollmentManager::Unenroll(int64_t instrument_id) {
+void VirtualCardEnrollmentManager::Unenroll(
+ int64_t instrument_id,
+ absl::optional<VirtualCardEnrollmentUpdateResponseCallback>
+ virtual_card_enrollment_update_response_callback) {
LogUpdateVirtualCardEnrollmentRequestAttempt(
VirtualCardEnrollmentSource::kSettingsPage,
VirtualCardEnrollmentRequestType::kUnenroll);
@@ -169,6 +178,9 @@ void VirtualCardEnrollmentManager::Unenroll(int64_t instrument_id) {
payments::GetBillingCustomerId(personal_data_manager_);
request_details.instrument_id = instrument_id;
+ virtual_card_enrollment_update_response_callback_ =
+ std::move(virtual_card_enrollment_update_response_callback);
+
payments_client_->UpdateVirtualCardEnrollment(
request_details,
base::BindOnce(&VirtualCardEnrollmentManager::
@@ -181,8 +193,9 @@ bool VirtualCardEnrollmentManager::ShouldBlockVirtualCardEnrollment(
const std::string& instrument_id,
VirtualCardEnrollmentSource virtual_card_enrollment_source) const {
if (virtual_card_enrollment_source ==
- VirtualCardEnrollmentSource::kSettingsPage)
+ VirtualCardEnrollmentSource::kSettingsPage) {
return false;
+ }
if (!GetVirtualCardEnrollmentStrikeDatabase())
return false;
@@ -262,6 +275,13 @@ void VirtualCardEnrollmentManager::OnDidGetUpdateVirtualCardEnrollmentResponse(
state_.virtual_card_enrollment_fields.virtual_card_enrollment_source,
type, result == AutofillClient::PaymentsRpcResult::kSuccess);
Reset();
+ // Relay the response to the server card editor page. This also destroys the
+ // payments delegate if the editor was already closed.
+ if (virtual_card_enrollment_update_response_callback_.has_value()) {
+ std::move(virtual_card_enrollment_update_response_callback_.value())
+ .Run(result == AutofillClient::PaymentsRpcResult::kSuccess);
+ }
+ virtual_card_enrollment_update_response_callback_.reset();
}
void VirtualCardEnrollmentManager::Reset() {
@@ -322,8 +342,9 @@ void VirtualCardEnrollmentManager::ShowVirtualCardEnrollBubble() {
autofill_client_->ShowVirtualCardEnrollDialog(
state_.virtual_card_enrollment_fields,
- base::BindOnce(&VirtualCardEnrollmentManager::Enroll,
- weak_ptr_factory_.GetWeakPtr()),
+ base::BindOnce(
+ &VirtualCardEnrollmentManager::Enroll, weak_ptr_factory_.GetWeakPtr(),
+ /*virtual_card_enrollment_update_response_callback=*/absl::nullopt),
base::BindOnce(
&VirtualCardEnrollmentManager::OnVirtualCardEnrollmentBubbleCancelled,
weak_ptr_factory_.GetWeakPtr()));
@@ -337,24 +358,10 @@ void VirtualCardEnrollmentManager::OnRiskDataLoadedForVirtualCard(
// GetDetailsForEnrollmentResponseDetails were already received, then we
// received it from the UploadCardResponseDetails. Thus, we can skip making
// another GetDetailsForEnrollmentRequest and go straight to showing the
- // bubble if the avatar animation is complete.
+ // bubble.
if (state_.virtual_card_enrollment_fields.virtual_card_enrollment_source ==
VirtualCardEnrollmentSource::kUpstream &&
enroll_response_details_received_) {
-#if !BUILDFLAG(IS_ANDROID)
- if (base::FeatureList::IsEnabled(
- features::kAutofillEnableToolbarStatusChip) &&
- base::FeatureList::IsEnabled(
- features::kAutofillCreditCardUploadFeedback) &&
- !avatar_animation_complete_) {
- // If status chip and upload feedback is enabled, we need to make sure
- // we wait for the upload card animation to complete before showing the
- // virtual card enroll bubble, or else we will have a conflict and the
- // virtual card enroll bubble will not show.
- return;
- }
-#endif
-
// We are about to show the virtual card enroll bubble, so make sure the
// card art image is set to then display in the bubble.
EnsureCardArtImageIsSetBeforeShowingUI();
@@ -426,22 +433,6 @@ void VirtualCardEnrollmentManager::OnDidGetDetailsForEnrollResponse(
DCHECK(IsValidGetDetailsForEnrollmentResponseDetails(response));
SetGetDetailsForEnrollmentResponseDetails(response);
-#if !BUILDFLAG(IS_ANDROID)
- if (base::FeatureList::IsEnabled(
- features::kAutofillEnableToolbarStatusChip) &&
- base::FeatureList::IsEnabled(
- features::kAutofillCreditCardUploadFeedback) &&
- state_.virtual_card_enrollment_fields.virtual_card_enrollment_source ==
- VirtualCardEnrollmentSource::kUpstream &&
- !avatar_animation_complete_) {
- // If status chip and upload feedback is enabled, we need to make sure
- // we wait for the upload card animation to complete before showing the
- // virtual card enroll bubble, or else we will have a conflict and the
- // virtual card enroll bubble will not show.
- return;
- }
-#endif
-
// We are about to show the UI for virtual card enrollment, so make sure the
// card art image is set to then display in the bubble.
EnsureCardArtImageIsSetBeforeShowingUI();
@@ -509,6 +500,7 @@ void VirtualCardEnrollmentManager::EnsureCardArtImageIsSetBeforeShowingUI() {
void VirtualCardEnrollmentManager::SetInitialVirtualCardEnrollFields(
const CreditCard& credit_card,
VirtualCardEnrollmentSource virtual_card_enrollment_source) {
+ // Reset here to override currently pending enrollment.
Reset();
DCHECK_NE(virtual_card_enrollment_source, VirtualCardEnrollmentSource::kNone);
diff --git a/chromium/components/autofill/core/browser/payments/virtual_card_enrollment_manager.h b/chromium/components/autofill/core/browser/payments/virtual_card_enrollment_manager.h
index 26af151fea6..ddc4e4515b8 100644
--- a/chromium/components/autofill/core/browser/payments/virtual_card_enrollment_manager.h
+++ b/chromium/components/autofill/core/browser/payments/virtual_card_enrollment_manager.h
@@ -108,6 +108,9 @@ class VirtualCardEnrollmentManager {
using VirtualCardEnrollmentFieldsLoadedCallback = base::OnceCallback<void(
VirtualCardEnrollmentFields* virtual_card_enrollment_fields)>;
+ using VirtualCardEnrollmentUpdateResponseCallback =
+ base::OnceCallback<void(bool)>;
+
// Starting point for the VCN enroll flow. The fields in |credit_card| will
// be used throughout the flow, such as for request fields as well as credit
// card specific fields for the bubble to display.
@@ -149,10 +152,16 @@ class VirtualCardEnrollmentManager {
// |vcn_context_token_|, which should be set when we receive the
// GetDetailsForEnrollResponse, is used in the
// UpdateVirtualCardEnrollmentRequest to enroll the correct card.
- void Enroll();
+ void Enroll(
+ // The callback lets the Android Settings page know whether
+ // (un)enrollment was successful.
+ absl::optional<VirtualCardEnrollmentUpdateResponseCallback>
+ virtual_card_enrollment_update_response_callback);
// Unenrolls the card mapped to the given |instrument_id|.
- void Unenroll(int64_t instrument_id);
+ void Unenroll(int64_t instrument_id,
+ absl::optional<VirtualCardEnrollmentUpdateResponseCallback>
+ virtual_card_enrollment_update_response_callback);
// Returns true if a credit card identified by its |instrument_id| should be
// blocked for virtual card enrollment and is not attempting to enroll from
@@ -236,6 +245,11 @@ class VirtualCardEnrollmentManager {
VirtualCardEnrollmentFieldsLoadedCallback
virtual_card_enrollment_fields_loaded_callback_;
+ // Callback triggered after getting server response about the success of
+ // virtual card (un)enrollment.
+ absl::optional<VirtualCardEnrollmentUpdateResponseCallback>
+ virtual_card_enrollment_update_response_callback_;
+
private:
friend class VirtualCardEnrollmentManagerTest;
FRIEND_TEST_ALL_PREFIXES(VirtualCardEnrollmentManagerTest,
diff --git a/chromium/components/autofill/core/browser/payments/virtual_card_enrollment_manager_unittest.cc b/chromium/components/autofill/core/browser/payments/virtual_card_enrollment_manager_unittest.cc
index 9630ced0549..d64283ce34b 100644
--- a/chromium/components/autofill/core/browser/payments/virtual_card_enrollment_manager_unittest.cc
+++ b/chromium/components/autofill/core/browser/payments/virtual_card_enrollment_manager_unittest.cc
@@ -477,7 +477,8 @@ TEST_F(VirtualCardEnrollmentManagerTest, Enroll) {
payments_client_->set_update_virtual_card_enrollment_result(
AutofillClient::PaymentsRpcResult::kSuccess);
- virtual_card_enrollment_manager_->Enroll();
+ virtual_card_enrollment_manager_->Enroll(
+ /*virtual_card_enrollment_update_response_callback=*/absl::nullopt);
payments::PaymentsClient::UpdateVirtualCardEnrollmentRequestDetails
request_details =
@@ -518,7 +519,8 @@ TEST_F(VirtualCardEnrollmentManagerTest, Enroll) {
// Starts another request and makes sure it fails.
payments_client_->set_update_virtual_card_enrollment_result(
AutofillClient::PaymentsRpcResult::kVcnRetrievalPermanentFailure);
- virtual_card_enrollment_manager_->Enroll();
+ virtual_card_enrollment_manager_->Enroll(
+ /*virtual_card_enrollment_update_response_callback=*/absl::nullopt);
// Verifies the logging.
histogram_tester.ExpectUniqueSample(
@@ -538,7 +540,8 @@ TEST_F(VirtualCardEnrollmentManagerTest, Unenroll) {
AutofillClient::PaymentsRpcResult::kNone);
virtual_card_enrollment_manager_->Unenroll(
- /*instrument_id=*/9223372036854775807);
+ /*instrument_id=*/9223372036854775807,
+ /*virtual_card_enrollment_update_response_callback=*/absl::nullopt);
payments::PaymentsClient::UpdateVirtualCardEnrollmentRequestDetails
request_details =
@@ -567,7 +570,8 @@ TEST_F(VirtualCardEnrollmentManagerTest, Unenroll) {
payments_client_->set_update_virtual_card_enrollment_result(
AutofillClient::PaymentsRpcResult::kVcnRetrievalPermanentFailure);
virtual_card_enrollment_manager_->Unenroll(
- /*instrument_id=*/9223372036854775807);
+ /*instrument_id=*/9223372036854775807,
+ /*virtual_card_enrollment_update_response_callback=*/absl::nullopt);
// Verifies the logging.
histogram_tester.ExpectUniqueSample(
@@ -578,110 +582,6 @@ TEST_F(VirtualCardEnrollmentManagerTest, Unenroll) {
/*sample=*/false, 1);
}
-#if !BUILDFLAG(IS_ANDROID)
-TEST_F(VirtualCardEnrollmentManagerTest, UpstreamAnimationSync_AnimationFirst) {
- for (bool optimized_upstream : {true, false}) {
- virtual_card_enrollment_manager_->SetBubbleShown(false);
- virtual_card_enrollment_manager_->SetAvatarAnimationComplete(false);
- virtual_card_enrollment_manager_->SetEnrollResponseDetailsReceived(false);
-
- personal_data_manager_->ClearCreditCardArtImages();
- SetUpCard();
- SetValidCardArtImageForCard(*card_);
-
- VirtualCardEnrollmentProcessState* state =
- virtual_card_enrollment_manager_
- ->GetVirtualCardEnrollmentProcessState();
- state->virtual_card_enrollment_fields.credit_card = *card_;
- state->vcn_context_token = kTestVcnContextToken;
- state->virtual_card_enrollment_fields.virtual_card_enrollment_source =
- VirtualCardEnrollmentSource::kUpstream;
-
- payments::PaymentsClient::GetDetailsForEnrollmentResponseDetails response;
- response.vcn_context_token = kTestVcnContextToken;
- response.issuer_legal_message = {
- TestLegalMessageLine("issuer_test_legal_message_line")};
- response.google_legal_message = {
- TestLegalMessageLine("google_test_legal_message_line")};
-
- absl::optional<
- payments::PaymentsClient::GetDetailsForEnrollmentResponseDetails>
- response_optional = response;
- // Update avatar animation complete boolean.
- virtual_card_enrollment_manager_->OnCardSavedAnimationComplete();
- EXPECT_TRUE(virtual_card_enrollment_manager_->GetAvatarAnimationComplete());
-
- // Ensure bubble was not shown yet.
- EXPECT_FALSE(virtual_card_enrollment_manager_->GetBubbleShown());
-
- if (optimized_upstream) {
- virtual_card_enrollment_manager_->InitVirtualCardEnroll(
- *card_, VirtualCardEnrollmentSource::kUpstream, response_optional);
- } else {
- virtual_card_enrollment_manager_->OnDidGetDetailsForEnrollResponse(
- AutofillClient::PaymentsRpcResult::kSuccess, response);
- }
-
- EXPECT_TRUE(
- virtual_card_enrollment_manager_->GetEnrollResponseDetailsReceived());
-
- // Ensure bubble was shown.
- EXPECT_TRUE(virtual_card_enrollment_manager_->GetBubbleShown());
- }
-}
-
-TEST_F(VirtualCardEnrollmentManagerTest, UpstreamAnimationSync_ResponseFirst) {
- base::test::ScopedFeatureList feature_list;
- feature_list.InitWithFeatures({features::kAutofillEnableToolbarStatusChip,
- features::kAutofillCreditCardUploadFeedback},
- {});
- for (bool optimized_upstream : {true, false}) {
- virtual_card_enrollment_manager_->Reset();
- virtual_card_enrollment_manager_->SetBubbleShown(false);
- virtual_card_enrollment_manager_->SetAvatarAnimationComplete(false);
- personal_data_manager_->ClearCreditCardArtImages();
- SetUpCard();
- SetValidCardArtImageForCard(*card_);
-
- VirtualCardEnrollmentProcessState* state =
- virtual_card_enrollment_manager_
- ->GetVirtualCardEnrollmentProcessState();
- state->virtual_card_enrollment_fields.credit_card = *card_;
- state->vcn_context_token = kTestVcnContextToken;
- state->virtual_card_enrollment_fields.virtual_card_enrollment_source =
- VirtualCardEnrollmentSource::kUpstream;
-
- payments::PaymentsClient::GetDetailsForEnrollmentResponseDetails response;
- response.vcn_context_token = kTestVcnContextToken;
- response.issuer_legal_message = {
- TestLegalMessageLine("issuer_test_legal_message_line")};
- response.google_legal_message = {
- TestLegalMessageLine("google_test_legal_message_line")};
-
- absl::optional<
- payments::PaymentsClient::GetDetailsForEnrollmentResponseDetails>
- response_optional = response;
- if (optimized_upstream) {
- virtual_card_enrollment_manager_->InitVirtualCardEnroll(
- *card_, VirtualCardEnrollmentSource::kUpstream, response_optional);
- } else {
- virtual_card_enrollment_manager_->OnDidGetDetailsForEnrollResponse(
- AutofillClient::PaymentsRpcResult::kSuccess, response);
- }
-
- EXPECT_TRUE(
- virtual_card_enrollment_manager_->GetEnrollResponseDetailsReceived());
-
- // Ensure bubble was not shown yet.
- EXPECT_FALSE(virtual_card_enrollment_manager_->GetBubbleShown());
-
- // Update avatar animation complete boolean.
- virtual_card_enrollment_manager_->OnCardSavedAnimationComplete();
- EXPECT_TRUE(virtual_card_enrollment_manager_->GetAvatarAnimationComplete());
- }
-}
-#endif // !BUILDFLAG(IS_ANDROID)
-
#if !BUILDFLAG(IS_IOS)
TEST_F(VirtualCardEnrollmentManagerTest, StrikeDatabase_BubbleAccepted) {
base::HistogramTester histogram_tester;
@@ -703,7 +603,8 @@ TEST_F(VirtualCardEnrollmentManagerTest, StrikeDatabase_BubbleAccepted) {
1);
// Ensure a strike has been removed after enrollment accepted.
- virtual_card_enrollment_manager_->Enroll();
+ virtual_card_enrollment_manager_->Enroll(
+ /*virtual_card_enrollment_update_response_callback=*/absl::nullopt);
EXPECT_EQ(
virtual_card_enrollment_manager_->GetVirtualCardEnrollmentStrikeDatabase()
->GetStrikes(
diff --git a/chromium/components/autofill/core/browser/personal_data_manager.cc b/chromium/components/autofill/core/browser/personal_data_manager.cc
index 594176e85cd..5e5ffbb6431 100644
--- a/chromium/components/autofill/core/browser/personal_data_manager.cc
+++ b/chromium/components/autofill/core/browser/personal_data_manager.cc
@@ -432,21 +432,23 @@ void PersonalDataManager::OnWebDataServiceRequestDone(
DCHECK(pending_profiles_query_ || pending_server_profiles_query_ ||
pending_creditcards_query_ || pending_server_creditcards_query_ ||
pending_server_creditcard_cloud_token_data_query_ ||
- pending_customer_data_query_ || pending_upi_ids_query_ ||
- pending_offer_data_query_);
+ pending_ibans_query_ || pending_customer_data_query_ ||
+ pending_upi_ids_query_ || pending_offer_data_query_);
if (!result) {
// Error from the web database.
- if (h == pending_creditcards_query_)
- pending_creditcards_query_ = 0;
- else if (h == pending_profiles_query_)
+ if (h == pending_profiles_query_)
pending_profiles_query_ = 0;
- else if (h == pending_server_creditcards_query_)
- pending_server_creditcards_query_ = 0;
else if (h == pending_server_profiles_query_)
pending_server_profiles_query_ = 0;
+ else if (h == pending_creditcards_query_)
+ pending_creditcards_query_ = 0;
+ else if (h == pending_server_creditcards_query_)
+ pending_server_creditcards_query_ = 0;
else if (h == pending_server_creditcard_cloud_token_data_query_)
pending_server_creditcard_cloud_token_data_query_ = 0;
+ else if (h == pending_ibans_query_)
+ pending_ibans_query_ = 0;
else if (h == pending_customer_data_query_)
pending_customer_data_query_ = 0;
else if (h == pending_upi_ids_query_)
@@ -487,6 +489,12 @@ void PersonalDataManager::OnWebDataServiceRequestDone(
h, result.get(), &pending_server_creditcard_cloud_token_data_query_,
&server_credit_card_cloud_token_data_);
break;
+ case AUTOFILL_IBANS_RESULT:
+ DCHECK_EQ(h, pending_ibans_query_)
+ << "received ibans from invalid request.";
+ ReceiveLoadedDbValues(h, result.get(), &pending_ibans_query_,
+ &local_ibans_);
+ break;
case AUTOFILL_CUSTOMERDATA_RESULT:
DCHECK_EQ(h, pending_customer_data_query_)
<< "received customer data from invalid request.";
@@ -574,23 +582,12 @@ void PersonalDataManager::OnSyncShutdown(syncer::SyncService* sync_service) {
CoreAccountInfo PersonalDataManager::GetAccountInfoForPaymentsServer() const {
// Return the account of the active signed-in user irrespective of whether
// they enabled sync or not.
- // However if there is no |sync_service_| (e.g. in incognito), return the
- // latest cached AccountInfo of the user's primary account, which is empty if
- // the user has disabled sync.
- // In both cases, the AccountInfo will be empty if the user is not signed in.
- return sync_service_ ? sync_service_->GetAccountInfo()
- : identity_manager_->GetPrimaryAccountInfo(
- signin::ConsentLevel::kSync);
+ return identity_manager_->GetPrimaryAccountInfo(
+ signin::ConsentLevel::kSignin);
}
-// TODO(crbug.com/903914): Clean up this function so that it's more clear what
-// it's checking. It should not check the database helper.
bool PersonalDataManager::IsSyncFeatureEnabled() const {
- if (!sync_service_)
- return false;
-
- return !sync_service_->GetAccountInfo().IsEmpty() &&
- !database_helper_->IsUsingAccountStorageForServerData();
+ return sync_service_ && sync_service_->IsSyncFeatureEnabled();
}
void PersonalDataManager::OnAccountsCookieDeletedByUserAction() {
@@ -777,6 +774,51 @@ AutofillProfile* PersonalDataManager::GetProfileFromProfilesByGUID(
return iter != profiles.end() ? *iter : nullptr;
}
+void PersonalDataManager::AddIBAN(const IBAN& iban) {
+ if (!IsAutofillIBANEnabled())
+ return;
+
+ if (is_off_the_record_ || FindByGUID(local_ibans_, iban.guid()) ||
+ !database_helper_->GetLocalDatabase() ||
+ FindByContents(local_ibans_, iban)) {
+ return;
+ }
+
+ // Add the new iban to the web database.
+ database_helper_->GetLocalDatabase()->AddIBAN(iban);
+
+ // Refresh our local cache and send notifications to observers.
+ Refresh();
+}
+
+void PersonalDataManager::UpdateIBAN(const IBAN& iban) {
+ DCHECK_EQ(IBAN::LOCAL_IBAN, iban.record_type());
+ if (is_off_the_record_) {
+ return;
+ }
+ IBAN* existing_iban = GetIBANByGUID(iban.guid());
+ if (!existing_iban) {
+ return;
+ }
+
+ // Do not overwrite iban if it's existed already.
+ if (existing_iban->Compare(iban) == 0) {
+ return;
+ }
+
+ // Update the cached version.
+ *existing_iban = iban;
+ if (!database_helper_->GetLocalDatabase()) {
+ return;
+ }
+
+ // Make the update.
+ database_helper_->GetLocalDatabase()->UpdateIBAN(iban);
+
+ // Refresh our local cache and send notifications to observers.
+ Refresh();
+}
+
void PersonalDataManager::AddCreditCard(const CreditCard& credit_card) {
if (!IsAutofillCreditCardEnabled())
return;
@@ -1018,16 +1060,25 @@ void PersonalDataManager::RemoveByGUID(const std::string& guid) {
if (!database_helper_->GetLocalDatabase())
return;
- bool is_credit_card = FindByGUID(local_credit_cards_, guid);
- if (is_credit_card) {
+ if (FindByGUID(local_credit_cards_, guid)) {
database_helper_->GetLocalDatabase()->RemoveCreditCard(guid);
// Refresh our local cache and send notifications to observers.
Refresh();
+ } else if (FindByGUID(local_ibans_, guid)) {
+ database_helper_->GetLocalDatabase()->RemoveIBAN(guid);
+ // Refresh our local cache and send notifications to observers.
+ Refresh();
} else {
RemoveAutofillProfileByGUIDAndBlankCreditCardReference(guid);
}
}
+IBAN* PersonalDataManager::GetIBANByGUID(const std::string& guid) {
+ const std::vector<IBAN*>& ibans = GetIBANs();
+ auto iter = FindElementByGUID(ibans, guid);
+ return iter != ibans.end() ? *iter : nullptr;
+}
+
CreditCard* PersonalDataManager::GetCreditCardByGUID(const std::string& guid) {
const std::vector<CreditCard*>& credit_cards = GetCreditCards();
auto iter = FindElementByGUID(credit_cards, guid);
@@ -1118,7 +1169,6 @@ std::vector<CreditCard*> PersonalDataManager::GetServerCreditCards() const {
std::vector<CreditCard*> PersonalDataManager::GetCreditCards() const {
std::vector<CreditCard*> result;
-
result.reserve(local_credit_cards_.size() + server_credit_cards_.size());
for (const auto& card : local_credit_cards_)
result.push_back(card.get());
@@ -1130,6 +1180,15 @@ std::vector<CreditCard*> PersonalDataManager::GetCreditCards() const {
return result;
}
+std::vector<IBAN*> PersonalDataManager::GetIBANs() const {
+ std::vector<IBAN*> result;
+ result.reserve(local_ibans_.size());
+ for (const auto& iban : local_ibans_) {
+ result.push_back(iban.get());
+ }
+ return result;
+}
+
PaymentsCustomerData* PersonalDataManager::GetPaymentsCustomerData() const {
return payments_customer_data_ ? payments_customer_data_.get() : nullptr;
}
@@ -1147,7 +1206,7 @@ PersonalDataManager::GetCreditCardCloudTokenData() const {
}
std::vector<AutofillOfferData*> PersonalDataManager::GetAutofillOffers() const {
- if (!IsAutofillWalletImportEnabled())
+ if (!IsAutofillWalletImportEnabled() || !IsAutofillCreditCardEnabled())
return {};
std::vector<AutofillOfferData*> result;
@@ -1160,7 +1219,7 @@ std::vector<AutofillOfferData*> PersonalDataManager::GetAutofillOffers() const {
std::vector<const AutofillOfferData*>
PersonalDataManager::GetActiveAutofillPromoCodeOffersForOrigin(
GURL origin) const {
- if (!IsAutofillWalletImportEnabled())
+ if (!IsAutofillWalletImportEnabled() || !IsAutofillCreditCardEnabled())
return {};
std::vector<const AutofillOfferData*> promo_code_offers_for_origin;
@@ -1210,6 +1269,7 @@ void PersonalDataManager::Refresh() {
LoadProfiles();
LoadCreditCards();
LoadCreditCardCloudTokenData();
+ LoadIBANs();
LoadPaymentsCustomerData();
LoadUpiIds();
LoadAutofillOffers();
@@ -1367,7 +1427,8 @@ const std::vector<CreditCard*> PersonalDataManager::GetCreditCardsToSuggest(
}
bool PersonalDataManager::IsAutofillEnabled() const {
- return IsAutofillProfileEnabled() || IsAutofillCreditCardEnabled();
+ return IsAutofillProfileEnabled() || IsAutofillCreditCardEnabled() ||
+ IsAutofillIBANEnabled();
}
bool PersonalDataManager::IsAutofillProfileEnabled() const {
@@ -1378,6 +1439,10 @@ bool PersonalDataManager::IsAutofillCreditCardEnabled() const {
return prefs::IsAutofillCreditCardEnabled(pref_service_);
}
+bool PersonalDataManager::IsAutofillIBANEnabled() const {
+ return prefs::IsAutofillIBANEnabled(pref_service_);
+}
+
bool PersonalDataManager::IsAutofillWalletImportEnabled() const {
return prefs::IsPaymentsIntegrationEnabled(pref_service_);
}
@@ -1726,9 +1791,22 @@ void PersonalDataManager::LoadCreditCardCloudTokenData() {
database_helper_->GetServerDatabase()->GetCreditCardCloudTokenData(this);
}
+void PersonalDataManager::LoadIBANs() {
+ if (!database_helper_->GetLocalDatabase()) {
+ NOTREACHED();
+ return;
+ }
+
+ CancelPendingLocalQuery(&pending_ibans_query_);
+
+ pending_ibans_query_ = database_helper_->GetLocalDatabase()->GetIBANs(this);
+}
+
void PersonalDataManager::LoadUpiIds() {
- if (!database_helper_->GetLocalDatabase())
+ if (!database_helper_->GetLocalDatabase()) {
+ NOTREACHED();
return;
+ }
CancelPendingLocalQuery(&pending_upi_ids_query_);
@@ -1778,10 +1856,6 @@ void PersonalDataManager::CancelPendingServerQueries() {
CancelPendingServerQuery(&pending_offer_data_query_);
}
-bool PersonalDataManager::HasPendingQueriesForTesting() {
- return HasPendingQueries();
-}
-
void PersonalDataManager::LoadPaymentsCustomerData() {
if (!database_helper_->GetServerDatabase())
return;
@@ -2094,15 +2168,7 @@ void PersonalDataManager::NotifyPersonalDataObserver() {
}
}
-void PersonalDataManager::OnCreditCardSaved(bool is_local_card) {
- if (!base::FeatureList::IsEnabled(
- features::kAutofillCreditCardUploadFeedback)) {
- return;
- }
- for (PersonalDataManagerObserver& observer : observers_)
- observer.OnCreditCardSaved(
- /*should_show_sign_in_promo_if_applicable=*/is_local_card);
-}
+void PersonalDataManager::OnCreditCardSaved(bool is_local_card) {}
void PersonalDataManager::ConvertWalletAddressesAndUpdateWalletCards() {
// If the full Sync feature isn't enabled, then do NOT convert any Wallet
diff --git a/chromium/components/autofill/core/browser/personal_data_manager.h b/chromium/components/autofill/core/browser/personal_data_manager.h
index c11ab0ed653..510ca157a3d 100644
--- a/chromium/components/autofill/core/browser/personal_data_manager.h
+++ b/chromium/components/autofill/core/browser/personal_data_manager.h
@@ -25,6 +25,7 @@
#include "components/autofill/core/browser/data_model/autofill_profile.h"
#include "components/autofill/core/browser/data_model/credit_card.h"
#include "components/autofill/core/browser/data_model/credit_card_cloud_token_data.h"
+#include "components/autofill/core/browser/data_model/iban.h"
#include "components/autofill/core/browser/field_types.h"
#include "components/autofill/core/browser/geo/alternative_state_name_map_updater.h"
#include "components/autofill/core/browser/payments/account_info_getter.h"
@@ -200,6 +201,13 @@ class PersonalDataManager : public KeyedService,
const std::string& guid,
const std::vector<AutofillProfile*>& profiles);
+ // Adds |iban| to the web database as a local Iban.
+ virtual void AddIBAN(const IBAN& iban);
+
+ // Updates |iban| which already exists in the web database. This
+ // can only be used on local ibans.
+ virtual void UpdateIBAN(const IBAN& iban);
+
// Adds |credit_card| to the web database as a local card.
virtual void AddCreditCard(const CreditCard& credit_card);
@@ -237,6 +245,12 @@ class PersonalDataManager : public KeyedService,
// Sets a server credit card for test.
void AddServerCreditCardForTest(std::unique_ptr<CreditCard> credit_card);
+#if defined(UNIT_TEST)
+ void AddIBANForTest(std::unique_ptr<IBAN> iban) {
+ local_ibans_.push_back(std::move(iban));
+ }
+#endif
+
// Returns whether server credit cards are stored in account (i.e. ephemeral)
// storage.
bool IsUsingAccountStorageForServerDataForTest() const;
@@ -245,6 +259,10 @@ class PersonalDataManager : public KeyedService,
// the real database.
void AddOfferDataForTest(std::unique_ptr<AutofillOfferData> offer_data);
+ // Returns the iban with the specified |guid|, or nullptr if there is no iban
+ // with the specified |guid|.
+ virtual IBAN* GetIBANByGUID(const std::string& guid);
+
// Returns the credit card with the specified |guid|, or nullptr if there is
// no credit card with the specified |guid|.
virtual CreditCard* GetCreditCardByGUID(const std::string& guid);
@@ -280,6 +298,9 @@ class PersonalDataManager : public KeyedService,
// Returns all credit cards, server and local.
virtual std::vector<CreditCard*> GetCreditCards() const;
+ // Returns local Ibans.
+ virtual std::vector<IBAN*> GetIBANs() const;
+
// Returns the Payments customer data. Returns nullptr if no data is present.
virtual PaymentsCustomerData* GetPaymentsCustomerData() const;
@@ -330,12 +351,12 @@ class PersonalDataManager : public KeyedService,
const std::vector<CreditCard*> GetCreditCardsToSuggest(
bool include_server_cards) const;
- // Re-loads profiles and credit cards from the WebDatabase asynchronously.
- // In the general case, this is a no-op and will re-create the same
- // in-memory model as existed prior to the call. If any change occurred to
- // profiles in the WebDatabase directly, as is the case if the browser sync
- // engine processed a change from the cloud, we will learn of these as a
- // result of this call.
+ // Re-loads profiles, credit cards, and IBANs from the WebDatabase
+ // asynchronously. In the general case, this is a no-op and will re-create
+ // the same in-memory model as existed prior to the call. If any change
+ // occurred to profiles in the WebDatabase directly, as is the case if the
+ // browser sync engine processed a change from the cloud, we will learn of
+ // these as a result of this call.
//
// Also see SetProfile for more details.
virtual void Refresh();
@@ -355,6 +376,7 @@ class PersonalDataManager : public KeyedService,
variations_country_code_ = country_code;
}
+#if BUILDFLAG(IS_IOS)
// Returns the raw pointer to PersonalDataManagerCleaner used for testing
// purposes.
PersonalDataManagerCleaner* personal_data_manager_cleaner_for_testing()
@@ -362,7 +384,8 @@ class PersonalDataManager : public KeyedService,
DCHECK(personal_data_manager_cleaner_);
return personal_data_manager_cleaner_.get();
}
-#endif
+#endif // IOS
+#endif // UNIT_TEST
// Returns our best guess for the country a user is likely to use when
// inputting a new address. The value is calculated once and cached, so it
@@ -383,8 +406,10 @@ class PersonalDataManager : public KeyedService,
// Cancels any pending queries to the server web database.
void CancelPendingServerQueries();
+#if defined(UNIT_TEST)
// Returns if there are any pending queries to the web database.
- bool HasPendingQueriesForTesting();
+ bool HasPendingQueriesForTesting() { return HasPendingQueries(); }
+#endif
// This function assumes |credit_card| contains the full PAN. Returns |true|
// if the card number of |credit_card| is equal to any local card or any
@@ -418,6 +443,8 @@ class PersonalDataManager : public KeyedService,
// Notifies observers that the waiting should be stopped.
void NotifyPersonalDataObserver();
+ // TODO(crbug.com/1337392): Revisit the function when card upload feedback is
+ // to be added again. In the new proposal, we may not need to go through PDM.
// Called when at least one (can be multiple) card was saved. |is_local_card|
// indicates if the card is saved to local storage.
void OnCreditCardSaved(bool is_local_card);
@@ -431,6 +458,9 @@ class PersonalDataManager : public KeyedService,
// Returns the value of the AutofillCreditCardEnabled pref.
virtual bool IsAutofillCreditCardEnabled() const;
+ // Returns the value of the AutofillIBANEnabled pref.
+ virtual bool IsAutofillIBANEnabled() const;
+
// Returns the value of the AutofillWalletImportEnabled pref.
virtual bool IsAutofillWalletImportEnabled() const;
@@ -490,32 +520,6 @@ class PersonalDataManager : public KeyedService,
FRIEND_TEST_ALL_PREFIXES(PersonalDataManagerTest, GetCreditCardByServerId);
FRIEND_TEST_ALL_PREFIXES(PersonalDataManagerTest,
AddAndGetCreditCardArtImage);
- FRIEND_TEST_ALL_PREFIXES(PersonalDataManagerTest,
- DedupeProfiles_ProfilesToDelete);
- FRIEND_TEST_ALL_PREFIXES(PersonalDataManagerTest,
- DedupeProfiles_GuidsMergeMap);
- FRIEND_TEST_ALL_PREFIXES(PersonalDataManagerTest,
- UpdateCardsBillingAddressReference);
- FRIEND_TEST_ALL_PREFIXES(PersonalDataManagerTest,
- ApplyDedupingRoutine_CardsBillingAddressIdUpdated);
- FRIEND_TEST_ALL_PREFIXES(PersonalDataManagerTest,
- ApplyDedupingRoutine_MergedProfileValues);
- FRIEND_TEST_ALL_PREFIXES(PersonalDataManagerTest,
- ApplyDedupingRoutine_VerifiedProfileFirst);
- FRIEND_TEST_ALL_PREFIXES(PersonalDataManagerTest,
- ApplyDedupingRoutine_VerifiedProfileLast);
- FRIEND_TEST_ALL_PREFIXES(PersonalDataManagerTest,
- ApplyDedupingRoutine_MultipleVerifiedProfiles);
- FRIEND_TEST_ALL_PREFIXES(PersonalDataManagerTest,
- ApplyDedupingRoutine_FeatureDisabled);
- FRIEND_TEST_ALL_PREFIXES(PersonalDataManagerTest,
- ApplyDedupingRoutine_NopIfZeroProfiles);
- FRIEND_TEST_ALL_PREFIXES(PersonalDataManagerTest,
- ApplyDedupingRoutine_NopIfOneProfile);
- FRIEND_TEST_ALL_PREFIXES(PersonalDataManagerTest,
- ApplyDedupingRoutine_OncePerVersion);
- FRIEND_TEST_ALL_PREFIXES(PersonalDataManagerTest,
- ApplyDedupingRoutine_MultipleDedupes);
FRIEND_TEST_ALL_PREFIXES(
PersonalDataManagerTest,
ConvertWalletAddressesAndUpdateWalletCards_NewProfile);
@@ -535,9 +539,6 @@ class PersonalDataManager : public KeyedService,
DoNotConvertWalletAddressesInEphemeralStorage);
FRIEND_TEST_ALL_PREFIXES(PersonalDataManagerTest,
DeleteDisusedCreditCards_DoNothingWhenDisabled);
- FRIEND_TEST_ALL_PREFIXES(
- PersonalDataManagerTest,
- DeleteDisusedCreditCards_OnlyDeleteExpiredDisusedLocalCards);
FRIEND_TEST_ALL_PREFIXES(PersonalDataManagerTest,
GetProfileSuggestions_ProfileAutofillDisabled);
FRIEND_TEST_ALL_PREFIXES(PersonalDataManagerTest,
@@ -552,6 +553,8 @@ class PersonalDataManager : public KeyedService,
PersonalDataManagerTest,
GetCreditCardsToSuggest_NoCreditCardsAddedIfDisabled);
FRIEND_TEST_ALL_PREFIXES(PersonalDataManagerTest, LogStoredCreditCardMetrics);
+ FRIEND_TEST_ALL_PREFIXES(PersonalDataManagerCleanerTest,
+ UpdateCardsBillingAddressReference);
friend class autofill::AutofillInteractiveTest;
friend class autofill::PersonalDataManagerCleaner;
@@ -600,6 +603,9 @@ class PersonalDataManager : public KeyedService,
// Loads the saved credit card cloud token data from the web database.
virtual void LoadCreditCardCloudTokenData();
+ // Loads the saved IBANs from the web database.
+ virtual void LoadIBANs();
+
// Loads the payments customer data from the web database.
virtual void LoadPaymentsCustomerData();
@@ -662,6 +668,9 @@ class PersonalDataManager : public KeyedService,
std::vector<std::unique_ptr<CreditCard>> local_credit_cards_;
std::vector<std::unique_ptr<CreditCard>> server_credit_cards_;
+ // Cached versions of the local Ibans.
+ std::vector<std::unique_ptr<IBAN>> local_ibans_;
+
// Cached UPI IDs.
std::vector<std::string> upi_ids_;
@@ -686,6 +695,7 @@ class PersonalDataManager : public KeyedService,
WebDataServiceBase::Handle pending_server_creditcards_query_ = 0;
WebDataServiceBase::Handle pending_server_creditcard_cloud_token_data_query_ =
0;
+ WebDataServiceBase::Handle pending_ibans_query_ = 0;
WebDataServiceBase::Handle pending_customer_data_query_ = 0;
WebDataServiceBase::Handle pending_upi_ids_query_ = 0;
WebDataServiceBase::Handle pending_offer_data_query_ = 0;
diff --git a/chromium/components/autofill/core/browser/personal_data_manager_cleaner_unittest.cc b/chromium/components/autofill/core/browser/personal_data_manager_cleaner_unittest.cc
new file mode 100644
index 00000000000..4ad0a096b71
--- /dev/null
+++ b/chromium/components/autofill/core/browser/personal_data_manager_cleaner_unittest.cc
@@ -0,0 +1,1290 @@
+// Copyright 2022 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/personal_data_manager_cleaner.h"
+
+#include "base/guid.h"
+#include "base/test/metrics/histogram_tester.h"
+#include "base/test/scoped_feature_list.h"
+#include "base/test/task_environment.h"
+#include "components/autofill/core/browser/autofill_test_utils.h"
+#include "components/autofill/core/browser/personal_data_manager.h"
+#include "components/autofill/core/browser/personal_data_manager_test_base.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 "testing/gtest/include/gtest/gtest.h"
+
+using ::testing::Matcher;
+using ::testing::Truly;
+
+namespace autofill {
+
+namespace {
+
+const base::Time kArbitraryTime = base::Time::FromDoubleT(25);
+const base::Time kSomeLaterTime = base::Time::FromDoubleT(1000);
+const base::Time kMuchLaterTime = base::Time::FromDoubleT(5000);
+
+ACTION_P(QuitMessageLoop, loop) {
+ loop->Quit();
+}
+
+template <typename T>
+auto HasSameElements(const std::vector<T*>& expectations) {
+ std::vector<Matcher<T*>> matchers;
+ for (const auto& e : expectations)
+ matchers.push_back(Truly([e](T* a) { return a->Compare(*e) == 0; }));
+ return UnorderedElementsAreArray(matchers);
+}
+
+} // anonymous namespace
+
+class PersonalDataManagerCleanerTest : public PersonalDataManagerTestBase,
+ public testing::Test {
+ public:
+ PersonalDataManagerCleanerTest() = default;
+ ~PersonalDataManagerCleanerTest() override = default;
+
+ void SetUp() override {
+ SetUpTest();
+ personal_data_ = std::make_unique<PersonalDataManager>("EN", "US");
+ ResetPersonalDataManager(/*is_incognito=*/false,
+ /*use_sync_transport_mode=*/false,
+ personal_data_.get());
+ personal_data_manager_cleaner_ =
+ std::make_unique<PersonalDataManagerCleaner>(personal_data_.get(),
+ nullptr, prefs_.get());
+ }
+
+ void TearDown() override {
+ if (personal_data_)
+ personal_data_->Shutdown();
+ personal_data_.reset();
+ TearDownTest();
+ }
+
+ protected:
+ // Verifies that the web database has been updated and the notification sent.
+ void WaitForOnPersonalDataChanged(
+ absl::optional<AutofillProfile> profile = absl::nullopt) {
+ base::RunLoop run_loop;
+ EXPECT_CALL(personal_data_observer_, OnPersonalDataFinishedProfileTasks())
+ .WillOnce(QuitMessageLoop(&run_loop));
+ EXPECT_CALL(personal_data_observer_, OnPersonalDataChanged())
+ .Times(testing::AnyNumber());
+ if (profile)
+ personal_data_->AddProfile(profile.value());
+ run_loop.Run();
+ }
+
+ void AddProfileToPersonalDataManager(const AutofillProfile& profile) {
+ WaitForOnPersonalDataChanged(profile);
+ }
+
+ void SetServerCards(const std::vector<CreditCard>& server_cards) {
+ test::SetServerCreditCards(personal_data_->IsSyncFeatureEnabled()
+ ? profile_autofill_table_.get()
+ : account_autofill_table_.get(),
+ server_cards);
+ }
+
+ std::unique_ptr<PersonalDataManager> personal_data_;
+ std::unique_ptr<PersonalDataManagerCleaner> personal_data_manager_cleaner_;
+};
+
+// Tests that DedupeProfiles sets the correct profile guids to
+// delete after merging similar profiles.
+TEST_F(PersonalDataManagerCleanerTest, DedupeProfiles_ProfilesToDelete) {
+ // Create the profile for which to find duplicates. It has the highest
+ // ranking score.
+ AutofillProfile* profile1 =
+ new AutofillProfile(base::GenerateGUID(), test::kEmptyOrigin);
+ test::SetProfileInfo(profile1, "Homer", "Jay", "Simpson",
+ "homer.simpson@abc.com", "", "742. Evergreen Terrace",
+ "", "Springfield", "IL", "91601", "US", "12345678910");
+ profile1->set_use_count(9);
+
+ // Create a different profile that should not be deduped (different address).
+ AutofillProfile* profile2 =
+ new AutofillProfile(base::GenerateGUID(), test::kEmptyOrigin);
+ test::SetProfileInfo(profile2, "Homer", "Jay", "Simpson",
+ "homer.simpson@abc.com", "Fox", "1234 Other Street", "",
+ "Springfield", "IL", "91601", "US", "12345678910");
+ profile2->set_use_count(7);
+
+ // Create a profile similar to profile1 which should be deduped.
+ AutofillProfile* profile3 =
+ new AutofillProfile(base::GenerateGUID(), test::kEmptyOrigin);
+ test::SetProfileInfo(profile3, "Homer", "Jay", "Simpson",
+ "homer.simpson@abc.com", "", "742 Evergreen Terrace", "",
+ "Springfield", "IL", "91601", "US", "12345678910");
+ profile3->set_use_count(5);
+
+ // Create another different profile that should not be deduped (different
+ // name).
+ AutofillProfile* profile4 =
+ new AutofillProfile(base::GenerateGUID(), test::kEmptyOrigin);
+ test::SetProfileInfo(profile4, "Marjorie", "Jacqueline", "Simpson",
+ "homer.simpson@abc.com", "Fox", "742 Evergreen Terrace",
+ "", "Springfield", "IL", "91601", "US", "12345678910");
+ profile4->set_use_count(3);
+
+ // Create another profile similar to profile1. Since that one has the lowest
+ // ranking score, the result of the merge should be in this profile at the end
+ // of the test.
+ AutofillProfile* profile5 =
+ new AutofillProfile(base::GenerateGUID(), test::kEmptyOrigin);
+ test::SetProfileInfo(profile5, "Homer", "Jay", "Simpson",
+ "homer.simpson@abc.com", "Fox", "742 Evergreen Terrace.",
+ "", "Springfield", "IL", "91601", "US", "12345678910");
+ profile5->set_use_count(1);
+
+ // Add the profiles.
+ std::vector<std::unique_ptr<AutofillProfile>> existing_profiles;
+ existing_profiles.push_back(std::unique_ptr<AutofillProfile>(profile1));
+ existing_profiles.push_back(std::unique_ptr<AutofillProfile>(profile2));
+ existing_profiles.push_back(std::unique_ptr<AutofillProfile>(profile3));
+ existing_profiles.push_back(std::unique_ptr<AutofillProfile>(profile4));
+ existing_profiles.push_back(std::unique_ptr<AutofillProfile>(profile5));
+
+ base::HistogramTester histogram_tester;
+ std::unordered_map<std::string, std::string> guids_merge_map;
+ std::unordered_set<std::string> profiles_to_delete;
+ personal_data_manager_cleaner_->DedupeProfilesForTesting(
+ &existing_profiles, &profiles_to_delete, &guids_merge_map);
+ // 5 profiles were considered for dedupe.
+ histogram_tester.ExpectUniqueSample(
+ "Autofill.NumberOfProfilesConsideredForDedupe", 5, 1);
+ // 2 profiles were removed (profiles 1 and 3).
+ histogram_tester.ExpectUniqueSample(
+ "Autofill.NumberOfProfilesRemovedDuringDedupe", 2, 1);
+
+ // Profile1 should be deleted because it was sent as the profile to merge and
+ // thus was merged into profile3 and then into profile5.
+ EXPECT_TRUE(profiles_to_delete.count(profile1->guid()));
+
+ // Profile3 should be deleted because profile1 was merged into it and the
+ // resulting profile was then merged into profile5.
+ EXPECT_TRUE(profiles_to_delete.count(profile3->guid()));
+
+ // Only these two profiles should be deleted.
+ EXPECT_EQ(2U, profiles_to_delete.size());
+
+ // All profiles should still be present in |existing_profiles|.
+ EXPECT_EQ(5U, existing_profiles.size());
+}
+
+// Tests that DedupeProfiles sets the correct merge mapping for billing address
+// id references.
+TEST_F(PersonalDataManagerCleanerTest, DedupeProfiles_GuidsMergeMap) {
+ // Create the profile for which to find duplicates. It has the highest
+ // ranking score.
+ AutofillProfile* profile1 =
+ new AutofillProfile(base::GenerateGUID(), test::kEmptyOrigin);
+ test::SetProfileInfo(profile1, "Homer", "Jay", "Simpson",
+ "homer.simpson@abc.com", "", "742. Evergreen Terrace",
+ "", "Springfield", "IL", "91601", "US", "12345678910");
+ profile1->set_use_count(9);
+
+ // Create a different profile that should not be deduped (different address).
+ AutofillProfile* profile2 =
+ new AutofillProfile(base::GenerateGUID(), test::kEmptyOrigin);
+ test::SetProfileInfo(profile2, "Homer", "Jay", "Simpson",
+ "homer.simpson@abc.com", "Fox", "1234 Other Street", "",
+ "Springfield", "IL", "91601", "US", "12345678910");
+ profile2->set_use_count(7);
+
+ // Create a profile similar to profile1 which should be deduped.
+ AutofillProfile* profile3 =
+ new AutofillProfile(base::GenerateGUID(), test::kEmptyOrigin);
+ test::SetProfileInfo(profile3, "Homer", "Jay", "Simpson",
+ "homer.simpson@abc.com", "", "742 Evergreen Terrace", "",
+ "Springfield", "IL", "91601", "US", "12345678910");
+ profile3->set_use_count(5);
+
+ // Create another different profile that should not be deduped (different
+ // name).
+ AutofillProfile* profile4 =
+ new AutofillProfile(base::GenerateGUID(), test::kEmptyOrigin);
+ test::SetProfileInfo(profile4, "Marjorie", "Jacqueline", "Simpson",
+ "homer.simpson@abc.com", "Fox", "742 Evergreen Terrace",
+ "", "Springfield", "IL", "91601", "US", "12345678910");
+ profile4->set_use_count(3);
+
+ // Create another profile similar to profile1. Since that one has the lowest
+ // ranking score, the result of the merge should be in this profile at the end
+ // of the test.
+ AutofillProfile* profile5 =
+ new AutofillProfile(base::GenerateGUID(), test::kEmptyOrigin);
+ test::SetProfileInfo(profile5, "Homer", "Jay", "Simpson",
+ "homer.simpson@abc.com", "Fox", "742 Evergreen Terrace.",
+ "", "Springfield", "IL", "91601", "US", "12345678910");
+ profile5->set_use_count(1);
+
+ // Add the profiles.
+ std::vector<std::unique_ptr<AutofillProfile>> existing_profiles;
+ existing_profiles.push_back(std::unique_ptr<AutofillProfile>(profile1));
+ existing_profiles.push_back(std::unique_ptr<AutofillProfile>(profile2));
+ existing_profiles.push_back(std::unique_ptr<AutofillProfile>(profile3));
+ existing_profiles.push_back(std::unique_ptr<AutofillProfile>(profile4));
+ existing_profiles.push_back(std::unique_ptr<AutofillProfile>(profile5));
+
+ std::unordered_map<std::string, std::string> guids_merge_map;
+ std::unordered_set<std::string> profiles_to_delete;
+
+ personal_data_manager_cleaner_->DedupeProfilesForTesting(
+ &existing_profiles, &profiles_to_delete, &guids_merge_map);
+
+ // The two profile merges should be recorded in the map.
+ EXPECT_EQ(2U, guids_merge_map.size());
+
+ // Profile 1 was merged into profile 3.
+ ASSERT_TRUE(guids_merge_map.count(profile1->guid()));
+ EXPECT_TRUE(guids_merge_map.at(profile1->guid()) == profile3->guid());
+
+ // Profile 3 was merged into profile 5.
+ ASSERT_TRUE(guids_merge_map.count(profile3->guid()));
+ EXPECT_TRUE(guids_merge_map.at(profile3->guid()) == profile5->guid());
+}
+
+// Tests that UpdateCardsBillingAddressReference sets the correct billing
+// address id as specified in the map.
+TEST_F(PersonalDataManagerCleanerTest, UpdateCardsBillingAddressReference) {
+ /* The merges will be as follow:
+
+ A -> B F (not merged)
+ \
+ -> E
+ /
+ C -> D
+ */
+
+ std::unordered_map<std::string, std::string> guids_merge_map;
+ guids_merge_map.insert(std::pair<std::string, std::string>("A", "B"));
+ guids_merge_map.insert(std::pair<std::string, std::string>("C", "D"));
+ guids_merge_map.insert(std::pair<std::string, std::string>("B", "E"));
+ guids_merge_map.insert(std::pair<std::string, std::string>("D", "E"));
+
+ // Create a credit card without a billing address id
+ CreditCard* credit_card0 =
+ new CreditCard(base::GenerateGUID(), test::kEmptyOrigin);
+
+ // Create cards that use A, D, E and F as their billing address id.
+ CreditCard* credit_card1 =
+ new CreditCard(base::GenerateGUID(), test::kEmptyOrigin);
+ credit_card1->set_billing_address_id("A");
+ CreditCard* credit_card2 =
+ new CreditCard(base::GenerateGUID(), test::kEmptyOrigin);
+ credit_card2->set_billing_address_id("D");
+ CreditCard* credit_card3 =
+ new CreditCard(base::GenerateGUID(), test::kEmptyOrigin);
+ credit_card3->set_billing_address_id("E");
+ CreditCard* credit_card4 =
+ new CreditCard(base::GenerateGUID(), test::kEmptyOrigin);
+ credit_card4->set_billing_address_id("F");
+
+ // Add the credit cards to the database.
+ personal_data_->local_credit_cards_.push_back(
+ std::unique_ptr<CreditCard>(credit_card0));
+ personal_data_->local_credit_cards_.push_back(
+ std::unique_ptr<CreditCard>(credit_card1));
+ personal_data_->server_credit_cards_.push_back(
+ std::unique_ptr<CreditCard>(credit_card2));
+ personal_data_->local_credit_cards_.push_back(
+ std::unique_ptr<CreditCard>(credit_card3));
+ personal_data_->server_credit_cards_.push_back(
+ std::unique_ptr<CreditCard>(credit_card4));
+
+ personal_data_manager_cleaner_->UpdateCardsBillingAddressReferenceForTesting(
+ guids_merge_map);
+
+ // The first card's billing address should now be E.
+ EXPECT_EQ("E", credit_card1->billing_address_id());
+ // The second card's billing address should now be E.
+ EXPECT_EQ("E", credit_card2->billing_address_id());
+ // The third card's billing address should still be E.
+ EXPECT_EQ("E", credit_card3->billing_address_id());
+ // The fourth card's billing address should still be F.
+ EXPECT_EQ("F", credit_card4->billing_address_id());
+}
+
+// Tests that ApplyDedupingRoutine updates the credit cards' billing address id
+// based on the deduped profiles.
+TEST_F(PersonalDataManagerCleanerTest,
+ ApplyDedupingRoutine_CardsBillingAddressIdUpdated) {
+ base::test::ScopedFeatureList feature;
+ feature.InitAndEnableFeature(features::kAutofillEnableProfileDeduplication);
+
+ // A set of 6 profiles will be created. They should merge in this way:
+ // 1 -> 2 -> 3
+ // 4 -> 5
+ // 6
+ // Set their frencency score so that profile 3 has a higher score than 5, and
+ // 5 has a higher score than 6. This will ensure a deterministic order when
+ // verifying results.
+
+ // Create a set of 3 profiles to be merged together.
+ // Create a profile with a higher ranking score.
+ AutofillProfile profile1(base::GenerateGUID(), test::kEmptyOrigin);
+ test::SetProfileInfo(&profile1, "Homer", "J", "Simpson",
+ "homer.simpson@abc.com", "", "742. Evergreen Terrace",
+ "", "Springfield", "IL", "91601", "US", "");
+ profile1.set_use_count(12);
+ profile1.set_use_date(AutofillClock::Now() - base::Days(1));
+
+ // Create a profile with a medium ranking score.
+ AutofillProfile profile2(base::GenerateGUID(), test::kEmptyOrigin);
+ test::SetProfileInfo(&profile2, "Homer", "Jay", "Simpson",
+ "homer.simpson@abc.com", "", "742 Evergreen Terrace", "",
+ "Springfield", "IL", "91601", "", "12345678910");
+ profile2.set_use_count(5);
+ profile2.set_use_date(AutofillClock::Now() - base::Days(3));
+
+ // Create a profile with a lower ranking score.
+ AutofillProfile profile3(base::GenerateGUID(), test::kEmptyOrigin);
+ test::SetProfileInfo(&profile3, "Homer", "J", "Simpson",
+ "homer.simpson@abc.com", "Fox", "742 Evergreen Terrace.",
+ "", "Springfield", "IL", "91601", "", "");
+ profile3.set_use_count(3);
+ profile3.set_use_date(AutofillClock::Now() - base::Days(5));
+
+ // Create a set of two profiles to be merged together.
+ // Create a profile with a higher ranking score.
+ AutofillProfile profile4(base::GenerateGUID(), test::kEmptyOrigin);
+ test::SetProfileInfo(&profile4, "Marge", "B", "Simpson",
+ "marge.simpson@abc.com", "", "742. Evergreen Terrace",
+ "", "Springfield", "IL", "91601", "US", "");
+ profile4.set_use_count(11);
+ profile4.set_use_date(AutofillClock::Now() - base::Days(1));
+
+ // Create a profile with a lower ranking score.
+ AutofillProfile profile5(base::GenerateGUID(), test::kEmptyOrigin);
+ test::SetProfileInfo(&profile5, "Marge", "B", "Simpson",
+ "marge.simpson@abc.com", "Fox", "742 Evergreen Terrace.",
+ "", "Springfield", "IL", "91601", "", "");
+ profile5.set_use_count(5);
+ profile5.set_use_date(AutofillClock::Now() - base::Days(3));
+
+ // Create a unique profile.
+ AutofillProfile profile6(base::GenerateGUID(), test::kEmptyOrigin);
+ test::SetProfileInfo(&profile6, "Bart", "J", "Simpson",
+ "bart.simpson@abc.com", "Fox", "742 Evergreen Terrace.",
+ "", "Springfield", "IL", "91601", "", "");
+ profile6.set_use_count(10);
+ profile6.set_use_date(AutofillClock::Now() - base::Days(1));
+
+ // Add three credit cards. Give them a ranking score so that they are
+ // suggested in order (1, 2, 3). This will ensure a deterministic order for
+ // verifying results.
+ CreditCard credit_card1(base::GenerateGUID(), test::kEmptyOrigin);
+ test::SetCreditCardInfo(&credit_card1, "Clyde Barrow",
+ "378282246310005" /* American Express */, "04",
+ "2999", "1");
+ credit_card1.set_use_count(10);
+
+ CreditCard credit_card2(base::GenerateGUID(), test::kEmptyOrigin);
+ test::SetCreditCardInfo(&credit_card2, "John Dillinger",
+ "4234567890123456" /* Visa */, "01", "2999", "1");
+ credit_card2.set_use_count(5);
+
+ CreditCard credit_card3(base::GenerateGUID(), test::kEmptyOrigin);
+ test::SetCreditCardInfo(&credit_card3, "Bonnie Parker",
+ "5105105105105100" /* Mastercard */, "12", "2999",
+ "1");
+ credit_card3.set_use_count(1);
+
+ // Associate the first card with profile1.
+ credit_card1.set_billing_address_id(profile1.guid());
+ // Associate the second card with profile4.
+ credit_card2.set_billing_address_id(profile4.guid());
+ // Associate the third card with profile6.
+ credit_card3.set_billing_address_id(profile6.guid());
+
+ AddProfileToPersonalDataManager(profile1);
+ AddProfileToPersonalDataManager(profile2);
+ AddProfileToPersonalDataManager(profile3);
+ AddProfileToPersonalDataManager(profile4);
+ AddProfileToPersonalDataManager(profile5);
+ AddProfileToPersonalDataManager(profile6);
+ personal_data_->AddCreditCard(credit_card1);
+ personal_data_->AddCreditCard(credit_card2);
+ personal_data_->AddCreditCard(credit_card3);
+
+ WaitForOnPersonalDataChanged();
+
+ // Make sure the 6 profiles and 3 credit cards were saved.
+ EXPECT_EQ(6U, personal_data_->GetProfiles().size());
+ EXPECT_EQ(3U, personal_data_->GetCreditCards().size());
+
+ EXPECT_TRUE(personal_data_manager_cleaner_->ApplyDedupingRoutineForTesting());
+ WaitForOnPersonalDataChanged();
+
+ // Get the profiles and cards sorted by their ranking score to have a
+ // deterministic order.
+ std::vector<AutofillProfile*> profiles =
+ personal_data_->GetProfilesToSuggest();
+ std::vector<CreditCard*> credit_cards =
+ personal_data_->GetCreditCardsToSuggest(/*include_server_cards=*/true);
+
+ // |profile1| should have been merged into |profile2| which should then have
+ // been merged into |profile3|. |profile4| should have been merged into
+ // |profile5| and |profile6| should not have merged. Therefore there should be
+ // 3 profile left.
+ ASSERT_EQ(3U, profiles.size());
+
+ // Make sure the remaining profiles are the expected ones.
+ EXPECT_EQ(profile3.guid(), profiles[0]->guid());
+ EXPECT_EQ(profile5.guid(), profiles[1]->guid());
+ EXPECT_EQ(profile6.guid(), profiles[2]->guid());
+
+ // |credit_card1|'s billing address should now be profile 3.
+ EXPECT_EQ(profile3.guid(), credit_cards[0]->billing_address_id());
+
+ // |credit_card2|'s billing address should now be profile 5.
+ EXPECT_EQ(profile5.guid(), credit_cards[1]->billing_address_id());
+
+ // |credit_card3|'s billing address should still be profile 6.
+ EXPECT_EQ(profile6.guid(), credit_cards[2]->billing_address_id());
+}
+
+// Tests that ApplyDedupingRoutine merges the profile values correctly, i.e.
+// never lose information and keep the syntax of the profile with the higher
+// ranking score.
+TEST_F(PersonalDataManagerCleanerTest,
+ ApplyDedupingRoutine_MergedProfileValues) {
+ base::test::ScopedFeatureList feature;
+ feature.InitAndEnableFeature(features::kAutofillEnableProfileDeduplication);
+
+ // Create a profile with a higher ranking score.
+ AutofillProfile profile1(base::GenerateGUID(), test::kEmptyOrigin);
+ test::SetProfileInfo(&profile1, "Homer", "J", "Simpson",
+ "homer.simpson@abc.com", "", "742. Evergreen Terrace",
+ "", "Springfield", "IL", "91601", "US", "");
+ profile1.set_use_count(10);
+ profile1.set_use_date(AutofillClock::Now() - base::Days(1));
+
+ // Create a profile with a medium ranking score.
+ AutofillProfile profile2(base::GenerateGUID(), test::kEmptyOrigin);
+ test::SetProfileInfo(&profile2, "Homer", "Jay", "Simpson",
+ "homer.simpson@abc.com", "", "742 Evergreen Terrace", "",
+ "Springfield", "IL", "91601", "", "12345678910");
+ profile2.set_use_count(5);
+ profile2.set_use_date(AutofillClock::Now() - base::Days(3));
+
+ // Create a profile with a lower ranking score.
+ AutofillProfile profile3(base::GenerateGUID(), test::kEmptyOrigin);
+ test::SetProfileInfo(&profile3, "Homer", "J", "Simpson",
+ "homer.simpson@abc.com", "Fox", "742 Evergreen Terrace.",
+ "", "Springfield", "IL", "91601", "", "");
+ profile3.set_use_count(3);
+ profile3.set_use_date(AutofillClock::Now() - base::Days(5));
+
+ AddProfileToPersonalDataManager(profile1);
+ AddProfileToPersonalDataManager(profile2);
+ AddProfileToPersonalDataManager(profile3);
+
+ // Make sure the 3 profiles were saved;
+ EXPECT_EQ(3U, personal_data_->GetProfiles().size());
+
+ base::HistogramTester histogram_tester;
+
+ EXPECT_TRUE(personal_data_manager_cleaner_->ApplyDedupingRoutineForTesting());
+ WaitForOnPersonalDataChanged();
+
+ std::vector<AutofillProfile*> profiles = personal_data_->GetProfiles();
+
+ // |profile1| should have been merged into |profile2| which should then have
+ // been merged into |profile3|. Therefore there should only be 1 saved
+ // profile.
+ ASSERT_EQ(1U, profiles.size());
+ // 3 profiles were considered for dedupe.
+ histogram_tester.ExpectUniqueSample(
+ "Autofill.NumberOfProfilesConsideredForDedupe", 3, 1);
+ // 2 profiles were removed (profiles 1 and 2).
+ histogram_tester.ExpectUniqueSample(
+ "Autofill.NumberOfProfilesRemovedDuringDedupe", 2, 1);
+
+ // Since profiles with higher ranking scores are merged into profiles with
+ // lower ranking scores, the result of the merge should be contained in
+ // profile3 since it had a lower ranking score compared to profile1.
+ EXPECT_EQ(profile3.guid(), profiles[0]->guid());
+ // The address syntax that results from the merge should be the one from the
+ // imported profile (highest ranking).
+ EXPECT_EQ(u"742. Evergreen Terrace",
+ profiles[0]->GetRawInfo(ADDRESS_HOME_LINE1));
+ // The middle name should be full, even if the profile with the higher
+ // ranking only had an initial (no loss of information).
+ EXPECT_EQ(u"Jay", profiles[0]->GetRawInfo(NAME_MIDDLE));
+ // The specified phone number from profile1 should be kept (no loss of
+ // information).
+ EXPECT_EQ(u"12345678910", profiles[0]->GetRawInfo(PHONE_HOME_WHOLE_NUMBER));
+ // The specified company name from profile2 should be kept (no loss of
+ // information).
+ EXPECT_EQ(u"Fox", profiles[0]->GetRawInfo(COMPANY_NAME));
+ // The specified country from the imported profile should be kept (no loss of
+ // information).
+ EXPECT_EQ(u"US", profiles[0]->GetRawInfo(ADDRESS_HOME_COUNTRY));
+ // The use count that results from the merge should be the max of all the
+ // profiles use counts.
+ EXPECT_EQ(10U, profiles[0]->use_count());
+ // The use date that results from the merge should be the one from the
+ // profile1 since it was the most recently used profile.
+ EXPECT_LT(profile1.use_date() - base::Seconds(10), profiles[0]->use_date());
+}
+
+// Tests that ApplyDedupingRoutine only keeps the verified profile with its
+// original data when deduping with similar profiles, even if it has a higher
+// ranking score.
+TEST_F(PersonalDataManagerCleanerTest,
+ ApplyDedupingRoutine_VerifiedProfileFirst) {
+ base::test::ScopedFeatureList feature;
+ feature.InitAndEnableFeature(features::kAutofillEnableProfileDeduplication);
+
+ // Create a verified profile with a higher ranking score.
+ AutofillProfile profile1(base::GenerateGUID(), kSettingsOrigin);
+ test::SetProfileInfo(
+ &profile1, "Homer", "Jay", "Simpson", "homer.simpson@abc.com", "",
+ "742 Evergreen Terrace", "", "Springfield", "IL", "91601", "",
+ "12345678910", /*finalize=*/true,
+ /*status=*/structured_address::VerificationStatus::kUserVerified);
+ profile1.set_use_count(7);
+ profile1.set_use_date(kMuchLaterTime);
+
+ // Create a similar non verified profile with a medium ranking score.
+ AutofillProfile profile2(base::GenerateGUID(), test::kEmptyOrigin);
+ test::SetProfileInfo(&profile2, "Homer", "J", "Simpson",
+ "homer.simpson@abc.com", "", "742. Evergreen Terrace",
+ "", "Springfield", "IL", "91601", "US", "");
+ profile2.set_use_count(5);
+ profile2.set_use_date(kSomeLaterTime);
+
+ // Create a similar non verified profile with a lower ranking score.
+ AutofillProfile profile3(base::GenerateGUID(), test::kEmptyOrigin);
+ test::SetProfileInfo(&profile3, "Homer", "J", "Simpson",
+ "homer.simpson@abc.com", "Fox", "742 Evergreen Terrace.",
+ "", "Springfield", "IL", "91601", "", "");
+ profile3.set_use_count(3);
+ profile3.set_use_date(kArbitraryTime);
+
+ AddProfileToPersonalDataManager(profile1);
+ AddProfileToPersonalDataManager(profile2);
+ AddProfileToPersonalDataManager(profile3);
+
+ // Make sure the 3 profiles were saved.
+ EXPECT_EQ(3U, personal_data_->GetProfiles().size());
+
+ base::HistogramTester histogram_tester;
+
+ EXPECT_TRUE(personal_data_manager_cleaner_->ApplyDedupingRoutineForTesting());
+ WaitForOnPersonalDataChanged();
+
+ std::vector<AutofillProfile*> profiles = personal_data_->GetProfiles();
+
+ // |profile2| should have merged with |profile3|. |profile3|
+ // should then have been discarded because it is similar to the verified
+ // |profile1|.
+ ASSERT_EQ(1U, profiles.size());
+ // 3 profiles were considered for dedupe.
+ histogram_tester.ExpectUniqueSample(
+ "Autofill.NumberOfProfilesConsideredForDedupe", 3, 1);
+ // 2 profile were removed (profiles 2 and 3).
+ histogram_tester.ExpectUniqueSample(
+ "Autofill.NumberOfProfilesRemovedDuringDedupe", 2, 1);
+
+ // Although the profile was verified, the structure of the street address
+ // still evolved with future observations. In this case, the "." was added
+ // from a later observation.
+ profile1.SetRawInfoWithVerificationStatus(
+ ADDRESS_HOME_STREET_NAME, u"Evergreen Terrace",
+ structured_address::VerificationStatus::kParsed);
+ //
+ // Only the verified |profile1| with its original data should have been kept.
+ EXPECT_EQ(profile1.guid(), profiles[0]->guid());
+ EXPECT_TRUE(profile1 == *profiles[0]);
+ EXPECT_EQ(profile1.use_count(), profiles[0]->use_count());
+ EXPECT_EQ(profile1.use_date(), profiles[0]->use_date());
+}
+
+// Tests that ApplyDedupingRoutine only keeps the verified profile with its
+// original data when deduping with similar profiles, even if it has a lower
+// ranking score.
+TEST_F(PersonalDataManagerCleanerTest,
+ ApplyDedupingRoutine_VerifiedProfileLast) {
+ base::test::ScopedFeatureList feature;
+ feature.InitAndEnableFeature(features::kAutofillEnableProfileDeduplication);
+
+ // Create a profile to dedupe with a higher ranking score.
+ AutofillProfile profile1(base::GenerateGUID(), test::kEmptyOrigin);
+ test::SetProfileInfo(&profile1, "Homer", "J", "Simpson",
+ "homer.simpson@abc.com", "", "742. Evergreen Terrace",
+ "", "Springfield", "IL", "91601", "US", "");
+ profile1.set_use_count(5);
+ profile1.set_use_date(kMuchLaterTime);
+
+ // Create a similar non verified profile with a medium ranking score.
+ AutofillProfile profile2(base::GenerateGUID(), test::kEmptyOrigin);
+ test::SetProfileInfo(&profile2, "Homer", "J", "Simpson",
+ "homer.simpson@abc.com", "Fox", "742 Evergreen Terrace.",
+ "", "Springfield", "IL", "91601", "", "");
+ profile2.set_use_count(5);
+ profile2.set_use_date(kSomeLaterTime);
+
+ // Create a similar verified profile with a lower ranking score.
+ AutofillProfile profile3(base::GenerateGUID(), kSettingsOrigin);
+ test::SetProfileInfo(
+ &profile3, "Homer", "Jay", "Simpson", "homer.simpson@abc.com", "",
+ "742 Evergreen Terrace", "", "Springfield", "IL", "91601", "",
+ "12345678910", /*finalize=*/true,
+ /*status=*/structured_address::VerificationStatus::kUserVerified);
+ profile3.set_use_count(3);
+ profile3.set_use_date(kArbitraryTime);
+
+ AddProfileToPersonalDataManager(profile1);
+ AddProfileToPersonalDataManager(profile2);
+ AddProfileToPersonalDataManager(profile3);
+
+ // Make sure the 3 profiles were saved.
+ EXPECT_EQ(3U, personal_data_->GetProfiles().size());
+
+ base::HistogramTester histogram_tester;
+
+ EXPECT_TRUE(personal_data_manager_cleaner_->ApplyDedupingRoutineForTesting());
+ WaitForOnPersonalDataChanged();
+
+ std::vector<AutofillProfile*> profiles = personal_data_->GetProfiles();
+
+ // |profile1| should have merged with |profile2|. |profile2|
+ // should then have been discarded because it is similar to the verified
+ // |profile3|.
+ ASSERT_EQ(1U, profiles.size());
+ // 3 profiles were considered for dedupe.
+ histogram_tester.ExpectUniqueSample(
+ "Autofill.NumberOfProfilesConsideredForDedupe", 3, 1);
+ // 2 profile were removed (profiles 1 and 2).
+ histogram_tester.ExpectUniqueSample(
+ "Autofill.NumberOfProfilesRemovedDuringDedupe", 2, 1);
+
+ // Only the verified |profile3| with it's original data should have been kept.
+ EXPECT_EQ(profile3.guid(), profiles[0]->guid());
+ EXPECT_TRUE(profile3 == *profiles[0]);
+ EXPECT_EQ(profile3.use_count(), profiles[0]->use_count());
+ EXPECT_EQ(profile3.use_date(), profiles[0]->use_date());
+}
+
+// Tests that ApplyDedupingRoutine does not merge unverified data into
+// a verified profile. Also tests that two verified profiles don't get merged.
+TEST_F(PersonalDataManagerCleanerTest,
+ ApplyDedupingRoutine_MultipleVerifiedProfiles) {
+ base::test::ScopedFeatureList feature;
+ feature.InitAndEnableFeature(features::kAutofillEnableProfileDeduplication);
+
+ // Create a profile to dedupe with a higher ranking score.
+ AutofillProfile profile1(base::GenerateGUID(), test::kEmptyOrigin);
+ test::SetProfileInfo(&profile1, "Homer", "J", "Simpson",
+ "homer.simpson@abc.com", "", "742. Evergreen Terrace",
+ "", "Springfield", "IL", "91601", "US", "");
+ profile1.set_use_count(5);
+ profile1.set_use_date(kMuchLaterTime);
+
+ // Create a similar verified profile with a medium ranking score.
+ AutofillProfile profile2(base::GenerateGUID(), kSettingsOrigin);
+ test::SetProfileInfo(
+ &profile2, "Homer", "J", "Simpson", "homer.simpson@abc.com", "Fox",
+ "742 Evergreen Terrace.", "", "Springfield", "IL", "91601", "", "",
+ /*finalize=*/true,
+ /*status=*/structured_address::VerificationStatus::kUserVerified);
+
+ profile2.set_use_count(5);
+ profile2.set_use_date(kSomeLaterTime);
+
+ // Create a similar verified profile with a lower ranking score.
+ AutofillProfile profile3(base::GenerateGUID(), kSettingsOrigin);
+ test::SetProfileInfo(
+ &profile3, "Homer", "Jay", "Simpson", "homer.simpson@abc.com", "",
+ "742 Evergreen Terrace", "", "Springfield", "IL", "91601", "",
+ "12345678910", /*finalize=*/true,
+ /*status*/ structured_address::VerificationStatus::kUserVerified);
+ profile3.set_use_count(3);
+ profile3.set_use_date(kArbitraryTime);
+
+ AddProfileToPersonalDataManager(profile1);
+ AddProfileToPersonalDataManager(profile2);
+ AddProfileToPersonalDataManager(profile3);
+
+ // Make sure the 3 profiles were saved.
+ EXPECT_EQ(3U, personal_data_->GetProfiles().size());
+
+ base::HistogramTester histogram_tester;
+
+ EXPECT_TRUE(personal_data_manager_cleaner_->ApplyDedupingRoutineForTesting());
+ WaitForOnPersonalDataChanged();
+
+ // Get the profiles, sorted by ranking to have a deterministic order.
+ std::vector<AutofillProfile*> profiles =
+ personal_data_->GetProfilesToSuggest();
+
+ // Although the profile was verified, the structure of the street address
+ // still evolved with future observations. In this case, the "." was removed
+ // from a later observation.
+ profile2.SetRawInfoWithVerificationStatus(
+ ADDRESS_HOME_STREET_NAME, u"Evergreen Terrace",
+ structured_address::VerificationStatus::kParsed);
+
+ // |profile1| should have been discarded because the saved profile with the
+ // highest ranking score is verified (|profile2|). Therefore, |profile1|'s
+ // data should not have been merged with |profile2|'s data. Then |profile2|
+ // should have been compared to |profile3| but they should not have merged
+ // because both profiles are verified.
+ ASSERT_EQ(2U, profiles.size());
+ // 3 profiles were considered for dedupe.
+ histogram_tester.ExpectUniqueSample(
+ "Autofill.NumberOfProfilesConsideredForDedupe", 3, 1);
+ // 1 profile was removed (|profile1|).
+ histogram_tester.ExpectUniqueSample(
+ "Autofill.NumberOfProfilesRemovedDuringDedupe", 1, 1);
+
+ EXPECT_EQ(profile2.guid(), profiles[0]->guid());
+ EXPECT_EQ(profile3.guid(), profiles[1]->guid());
+ // The profiles should have kept their original data.
+ EXPECT_TRUE(profile2 == *profiles[0]);
+ EXPECT_TRUE(profile3 == *profiles[1]);
+ EXPECT_EQ(profile2.use_count(), profiles[0]->use_count());
+ EXPECT_EQ(profile3.use_count(), profiles[1]->use_count());
+ EXPECT_EQ(profile2.use_date(), profiles[0]->use_date());
+ EXPECT_EQ(profile3.use_date(), profiles[1]->use_date());
+}
+
+// Tests that ApplyDedupingRoutine works as expected in a realistic scenario.
+// Tests that it merges the diffent set of similar profiles independently and
+// that the resulting profiles have the right values, has no effect on the other
+// profiles and that the data of verified profiles is not modified.
+TEST_F(PersonalDataManagerCleanerTest, ApplyDedupingRoutine_MultipleDedupes) {
+ base::test::ScopedFeatureList feature;
+ feature.InitAndEnableFeature(features::kAutofillEnableProfileDeduplication);
+
+ // Create a Homer home profile with a higher ranking score than other Homer
+ // profiles.
+ AutofillProfile Homer1(base::GenerateGUID(), test::kEmptyOrigin);
+ test::SetProfileInfo(&Homer1, "Homer", "J", "Simpson",
+ "homer.simpson@abc.com", "", "742. Evergreen Terrace",
+ "", "Springfield", "IL", "91601", "US", "");
+ Homer1.set_use_count(10);
+ Homer1.set_use_date(AutofillClock::Now() - base::Days(1));
+
+ // Create a Homer home profile with a medium ranking score compared to other
+ // Homer profiles.
+ AutofillProfile Homer2(base::GenerateGUID(), test::kEmptyOrigin);
+ test::SetProfileInfo(&Homer2, "Homer", "Jay", "Simpson",
+ "homer.simpson@abc.com", "", "742 Evergreen Terrace", "",
+ "Springfield", "IL", "91601", "", "12345678910");
+ Homer2.set_use_count(5);
+ Homer2.set_use_date(AutofillClock::Now() - base::Days(3));
+
+ // Create a Homer home profile with a lower ranking score than other Homer
+ // profiles.
+ AutofillProfile Homer3(base::GenerateGUID(), test::kEmptyOrigin);
+ test::SetProfileInfo(&Homer3, "Homer", "J", "Simpson",
+ "homer.simpson@abc.com", "Fox", "742 Evergreen Terrace.",
+ "", "Springfield", "IL", "91601", "", "");
+ Homer3.set_use_count(3);
+ Homer3.set_use_date(AutofillClock::Now() - base::Days(5));
+
+ // Create a Homer work profile (different address).
+ AutofillProfile Homer4(base::GenerateGUID(), test::kEmptyOrigin);
+ test::SetProfileInfo(&Homer4, "Homer", "J", "Simpson",
+ "homer.simpson@abc.com", "Fox", "12 Nuclear Plant.", "",
+ "Springfield", "IL", "91601", "US", "9876543");
+ Homer4.set_use_count(3);
+ Homer4.set_use_date(AutofillClock::Now() - base::Days(5));
+
+ // Create a Marge profile with a lower ranking score that other Marge
+ // profiles.
+ AutofillProfile Marge1(base::GenerateGUID(), kSettingsOrigin);
+ test::SetProfileInfo(&Marge1, "Marjorie", "J", "Simpson",
+ "marge.simpson@abc.com", "", "742 Evergreen Terrace", "",
+ "Springfield", "IL", "91601", "", "12345678910");
+ Marge1.set_use_count(4);
+ Marge1.set_use_date(AutofillClock::Now() - base::Days(3));
+
+ // Create a verified Marge home profile with a lower ranking score that the
+ // other Marge profile.
+ AutofillProfile Marge2(base::GenerateGUID(), test::kEmptyOrigin);
+ test::SetProfileInfo(&Marge2, "Marjorie", "Jacqueline", "Simpson",
+ "marge.simpson@abc.com", "", "742 Evergreen Terrace", "",
+ "Springfield", "IL", "91601", "", "12345678910");
+ Marge2.set_use_count(2);
+ Marge2.set_use_date(AutofillClock::Now() - base::Days(3));
+
+ // Create a Barney profile (guest user).
+ AutofillProfile Barney(base::GenerateGUID(), test::kEmptyOrigin);
+ test::SetProfileInfo(&Barney, "Barney", "", "Gumble", "barney.gumble@abc.com",
+ "ABC", "123 Other Street", "", "Springfield", "IL",
+ "91601", "", "");
+ Barney.set_use_count(1);
+ Barney.set_use_date(AutofillClock::Now() - base::Days(180));
+ Barney.FinalizeAfterImport();
+
+ AddProfileToPersonalDataManager(Homer1);
+ AddProfileToPersonalDataManager(Homer2);
+ AddProfileToPersonalDataManager(Homer3);
+ AddProfileToPersonalDataManager(Homer4);
+ AddProfileToPersonalDataManager(Marge1);
+ AddProfileToPersonalDataManager(Marge2);
+ AddProfileToPersonalDataManager(Barney);
+
+ // Make sure the 7 profiles were saved;
+ EXPECT_EQ(7U, personal_data_->GetProfiles().size());
+
+ base::HistogramTester histogram_tester;
+
+ // |Homer1| should get merged into |Homer2| which should then be merged into
+ // |Homer3|. |Marge2| should be discarded in favor of |Marge1| which is
+ // verified. |Homer4| and |Barney| should not be deduped at all.
+ EXPECT_TRUE(personal_data_manager_cleaner_->ApplyDedupingRoutineForTesting());
+ WaitForOnPersonalDataChanged();
+
+ // Get the profiles, sorted by ranking score to have a deterministic order.
+ std::vector<AutofillProfile*> profiles =
+ personal_data_->GetProfilesToSuggest();
+
+ // The 2 duplicates Homer home profiles with the higher ranking score and the
+ // unverified Marge profile should have been deduped.
+ ASSERT_EQ(4U, profiles.size());
+ // 7 profiles were considered for dedupe.
+ histogram_tester.ExpectUniqueSample(
+ "Autofill.NumberOfProfilesConsideredForDedupe", 7, 1);
+ // 3 profile were removed (|Homer1|, |Homer2| and |Marge2|).
+ histogram_tester.ExpectUniqueSample(
+ "Autofill.NumberOfProfilesRemovedDuringDedupe", 3, 1);
+
+ // The remaining profiles should be |Homer3|, |Marge1|, |Homer4| and |Barney|
+ // in this order of ranking score.
+ EXPECT_EQ(Homer3.guid(), profiles[0]->guid());
+ EXPECT_EQ(Marge1.guid(), profiles[1]->guid());
+ EXPECT_EQ(Homer4.guid(), profiles[2]->guid());
+ EXPECT_EQ(Barney.guid(), profiles[3]->guid());
+
+ // |Homer3|'s data:
+ // The address should be saved with the syntax of |Homer1| since it has the
+ // highest ranking score.
+ EXPECT_EQ(u"742. Evergreen Terrace",
+ profiles[0]->GetRawInfo(ADDRESS_HOME_LINE1));
+ // The middle name should be the full version found in |Homer2|,
+ EXPECT_EQ(u"Jay", profiles[0]->GetRawInfo(NAME_MIDDLE));
+ // The phone number from |Homer2| should be kept (no loss of information).
+ EXPECT_EQ(u"12345678910", profiles[0]->GetRawInfo(PHONE_HOME_WHOLE_NUMBER));
+ // The company name from |Homer3| should be kept (no loss of information).
+ EXPECT_EQ(u"Fox", profiles[0]->GetRawInfo(COMPANY_NAME));
+ // The country from |Homer1| profile should be kept (no loss of information).
+ EXPECT_EQ(u"US", profiles[0]->GetRawInfo(ADDRESS_HOME_COUNTRY));
+ // The use count that results from the merge should be the max of Homer 1, 2
+ // and 3's respective use counts.
+ EXPECT_EQ(10U, profiles[0]->use_count());
+ // The use date that results from the merge should be the one from the
+ // |Homer1| since it was the most recently used profile.
+ EXPECT_LT(Homer1.use_date() - base::Seconds(5), profiles[0]->use_date());
+ EXPECT_GT(Homer1.use_date() + base::Seconds(5), profiles[0]->use_date());
+
+ // The other profiles should not have been modified.
+ EXPECT_TRUE(Marge1 == *profiles[1]);
+ EXPECT_TRUE(Homer4 == *profiles[2]);
+ EXPECT_TRUE(Barney == *profiles[3]);
+}
+
+TEST_F(PersonalDataManagerCleanerTest, ApplyDedupingRoutine_NopIfZeroProfiles) {
+ base::test::ScopedFeatureList feature;
+ feature.InitAndEnableFeature(features::kAutofillEnableProfileDeduplication);
+ EXPECT_TRUE(personal_data_->GetProfiles().empty());
+ EXPECT_FALSE(
+ personal_data_manager_cleaner_->ApplyDedupingRoutineForTesting());
+}
+
+TEST_F(PersonalDataManagerCleanerTest, ApplyDedupingRoutine_NopIfOneProfile) {
+ base::test::ScopedFeatureList feature;
+ feature.InitAndEnableFeature(features::kAutofillEnableProfileDeduplication);
+
+ // Create a profile to dedupe.
+ AutofillProfile profile(base::GenerateGUID(), test::kEmptyOrigin);
+ test::SetProfileInfo(&profile, "Homer", "J", "Simpson",
+ "homer.simpson@abc.com", "", "742. Evergreen Terrace",
+ "", "Springfield", "IL", "91601", "US", "");
+
+ AddProfileToPersonalDataManager(profile);
+
+ EXPECT_EQ(1U, personal_data_->GetProfiles().size());
+ EXPECT_FALSE(
+ personal_data_manager_cleaner_->ApplyDedupingRoutineForTesting());
+}
+
+// Tests that ApplyDedupingRoutine is not run a second time on the same major
+// version.
+TEST_F(PersonalDataManagerCleanerTest, ApplyDedupingRoutine_OncePerVersion) {
+ base::test::ScopedFeatureList feature;
+ feature.InitAndEnableFeature(features::kAutofillEnableProfileDeduplication);
+
+ // Create a profile to dedupe.
+ AutofillProfile profile1(base::GenerateGUID(), test::kEmptyOrigin);
+ test::SetProfileInfo(&profile1, "Homer", "J", "Simpson",
+ "homer.simpson@abc.com", "", "742. Evergreen Terrace",
+ "", "Springfield", "IL", "91601", "US", "");
+
+ // Create a similar profile.
+ AutofillProfile profile2(base::GenerateGUID(), test::kEmptyOrigin);
+ test::SetProfileInfo(&profile2, "Homer", "J", "Simpson",
+ "homer.simpson@abc.com", "Fox", "742 Evergreen Terrace.",
+ "", "Springfield", "IL", "91601", "", "");
+
+ AddProfileToPersonalDataManager(profile1);
+ AddProfileToPersonalDataManager(profile2);
+
+ EXPECT_EQ(2U, personal_data_->GetProfiles().size());
+
+ // The deduping routine should be run a first time.
+ EXPECT_TRUE(personal_data_manager_cleaner_->ApplyDedupingRoutineForTesting());
+ WaitForOnPersonalDataChanged();
+
+ std::vector<AutofillProfile*> profiles = personal_data_->GetProfiles();
+
+ // The profiles should have been deduped
+ EXPECT_EQ(1U, profiles.size());
+
+ // Add another duplicate profile.
+ AutofillProfile profile3(base::GenerateGUID(), test::kEmptyOrigin);
+ test::SetProfileInfo(&profile3, "Homer", "J", "Simpson",
+ "homer.simpson@abc.com", "Fox", "742 Evergreen Terrace.",
+ "", "Springfield", "IL", "91601", "", "");
+
+ AddProfileToPersonalDataManager(profile3);
+
+ // Make sure |profile3| was saved.
+ EXPECT_EQ(2U, personal_data_->GetProfiles().size());
+
+ // The deduping routine should not be run.
+ EXPECT_FALSE(
+ personal_data_manager_cleaner_->ApplyDedupingRoutineForTesting());
+
+ // The two duplicate profiles should still be present.
+ EXPECT_EQ(2U, personal_data_->GetProfiles().size());
+}
+
+// Tests that settings-inaccessible profile values are removed from every stored
+// profile on startup.
+TEST_F(PersonalDataManagerCleanerTest,
+ RemoveInaccessibleProfileValuesOnStartup) {
+ base::test::ScopedFeatureList feature;
+ feature.InitAndEnableFeatureWithParameters(
+ features::kAutofillRemoveInaccessibleProfileValues,
+ {{features::kAutofillRemoveInaccessibleProfileValuesOnStartup.name,
+ "true"}});
+
+ // Add a German and a US profile.
+ AutofillProfile profile0(base::GenerateGUID(), test::kEmptyOrigin);
+ test::SetProfileInfo(&profile0, "Marion", "Mitchell", "Morrison",
+ "johnwayne@me.xyz", "Fox", "123 Zoo St.", "unit 5",
+ "Hollywood", "CA", "91601", "DE", "12345678910");
+ AutofillProfile profile1(base::GenerateGUID(), test::kEmptyOrigin);
+ test::SetProfileInfo(&profile1, "Josephine", "Alicia", "Saenz",
+ "joewayne@me.xyz", "Fox", "903 Apple Ct.", nullptr,
+ "Orlando", "FL", "32801", "US", "19482937549");
+ AddProfileToPersonalDataManager(profile0);
+ AddProfileToPersonalDataManager(profile1);
+
+ personal_data_manager_cleaner_->RemoveInaccessibleProfileValuesForTesting();
+ WaitForOnPersonalDataChanged();
+
+ // profile0 should have it's state removed, while the US profile should remain
+ // unchanged.
+ profile0.SetRawInfo(ADDRESS_HOME_STATE, u"");
+ std::vector<AutofillProfile*> expected_profiles = {&profile0, &profile1};
+ EXPECT_THAT(personal_data_->GetProfiles(),
+ HasSameElements(expected_profiles));
+}
+
+// Tests that DeleteDisusedAddresses only deletes the addresses that are
+// supposed to be deleted.
+TEST_F(PersonalDataManagerCleanerTest,
+ DeleteDisusedAddresses_DeleteDesiredAddressesOnly) {
+ auto now = AutofillClock::Now();
+
+ // Create unverified/disused/not-used-by-valid-credit-card
+ // address(deletable).
+ AutofillProfile profile0(base::GenerateGUID(), test::kEmptyOrigin);
+ test::SetProfileInfo(&profile0, "Alice", "", "Delete", "", "ACME",
+ "1234 Evergreen Terrace", "Bld. 6", "Springfield", "IL",
+ "32801", "US", "15151231234");
+ profile0.set_use_date(now - base::Days(400));
+ AddProfileToPersonalDataManager(profile0);
+
+ // Create unverified/disused/used-by-expired-credit-card address(deletable).
+ AutofillProfile profile1(base::GenerateGUID(), test::kEmptyOrigin);
+ test::SetProfileInfo(&profile1, "Bob", "", "Delete", "", "ACME",
+ "1234 Evergreen Terrace", "Bld. 7", "Springfield", "IL",
+ "32801", "US", "15151231234");
+ profile1.set_use_date(now - base::Days(400));
+ CreditCard credit_card0(base::GenerateGUID(), test::kEmptyOrigin);
+ test::SetCreditCardInfo(&credit_card0, "Bob",
+ "5105105105105100" /* Mastercard */, "04", "1999",
+ "1");
+ credit_card0.set_use_date(now - base::Days(400));
+ credit_card0.set_billing_address_id(profile1.guid());
+ AddProfileToPersonalDataManager(profile1);
+ personal_data_->AddCreditCard(credit_card0);
+ WaitForOnPersonalDataChanged();
+ // Create verified/disused/not-used-by-valid-credit-card address(not
+ // deletable).
+ AutofillProfile profile2(base::GenerateGUID(), test::kEmptyOrigin);
+ test::SetProfileInfo(&profile2, "Charlie", "", "Keep", "", "ACME",
+ "1234 Evergreen Terrace", "Bld. 8", "Springfield", "IL",
+ "32801", "US", "15151231234");
+ profile2.set_origin(kSettingsOrigin);
+ profile2.set_use_date(now - base::Days(400));
+ AddProfileToPersonalDataManager(profile2);
+
+ // Create unverified/recently-used/not-used-by-valid-credit-card address(not
+ // deletable).
+ AutofillProfile profile3(base::GenerateGUID(), test::kEmptyOrigin);
+ test::SetProfileInfo(&profile3, "Dave", "", "Keep", "", "ACME",
+ "1234 Evergreen Terrace", "Bld. 9", "Springfield", "IL",
+ "32801", "US", "15151231234");
+ profile3.set_use_date(now - base::Days(4));
+ AddProfileToPersonalDataManager(profile3);
+
+ // Create unverified/disused/used-by-valid-credit-card address(not deletable).
+ AutofillProfile profile4(base::GenerateGUID(), test::kEmptyOrigin);
+ test::SetProfileInfo(&profile4, "Emma", "", "Keep", "", "ACME",
+ "1234 Evergreen Terrace", "Bld. 10", "Springfield", "IL",
+ "32801", "US", "15151231234");
+ profile4.set_use_date(now - base::Days(400));
+ CreditCard credit_card1(CreditCard::MASKED_SERVER_CARD, "c987");
+ test::SetCreditCardInfo(&credit_card1, "Emma", "6543", "01", "2999", "1");
+ credit_card1.SetNetworkForMaskedCard(kVisaCard);
+ credit_card1.set_billing_address_id(profile4.guid());
+ credit_card1.set_use_date(now - base::Days(1));
+ AddProfileToPersonalDataManager(profile4);
+ personal_data_->AddCreditCard(credit_card1);
+
+ WaitForOnPersonalDataChanged();
+
+ EXPECT_EQ(5U, personal_data_->GetProfiles().size());
+ EXPECT_EQ(2U, personal_data_->GetCreditCards().size());
+
+ // DeleteDisusedAddresses should return true.
+ EXPECT_TRUE(
+ personal_data_manager_cleaner_->DeleteDisusedAddressesForTesting());
+ WaitForOnPersonalDataChanged();
+
+ EXPECT_EQ(3U, personal_data_->GetProfiles().size());
+ EXPECT_EQ(2U, personal_data_->GetCreditCards().size());
+ EXPECT_EQ(u"Keep", personal_data_->GetProfiles()[0]->GetRawInfo(NAME_LAST));
+ EXPECT_EQ(u"Keep", personal_data_->GetProfiles()[1]->GetRawInfo(NAME_LAST));
+ EXPECT_EQ(u"Keep", personal_data_->GetProfiles()[2]->GetRawInfo(NAME_LAST));
+}
+
+// Tests that DeleteDisusedCreditCards deletes desired credit cards only.
+TEST_F(PersonalDataManagerCleanerTest,
+ DeleteDisusedCreditCards_OnlyDeleteExpiredDisusedLocalCards) {
+ const char kHistogramName[] = "Autofill.CreditCardsDeletedForDisuse";
+ auto now = AutofillClock::Now();
+
+ // Create a recently used local card, it is expected to remain.
+ CreditCard credit_card1(base::GenerateGUID(), test::kEmptyOrigin);
+ test::SetCreditCardInfo(&credit_card1, "Alice",
+ "378282246310005" /* American Express */, "04",
+ "2999", "1");
+ credit_card1.set_use_date(now - base::Days(4));
+
+ // Create a local card that was expired 400 days ago, but recently used.
+ // It is expected to remain.
+ CreditCard credit_card2(base::GenerateGUID(), test::kEmptyOrigin);
+ test::SetCreditCardInfo(&credit_card2, "Bob",
+ "378282246310006" /* American Express */, "04",
+ "1999", "1");
+ credit_card2.set_use_date(now - base::Days(4));
+
+ // Create a local card expired recently, and last used 400 days ago.
+ // It is expected to remain.
+ CreditCard credit_card3(base::GenerateGUID(), test::kEmptyOrigin);
+ base::Time expiry_date = now - base::Days(32);
+ base::Time::Exploded exploded;
+ expiry_date.UTCExplode(&exploded);
+ test::SetCreditCardInfo(&credit_card3, "Clyde", "4111111111111111" /* Visa */,
+ base::StringPrintf("%02d", exploded.month).c_str(),
+ base::StringPrintf("%04d", exploded.year).c_str(),
+ "1");
+ credit_card3.set_use_date(now - base::Days(400));
+
+ // Create a local card expired 400 days ago, and last used 400 days ago.
+ // It is expected to be deleted.
+ CreditCard credit_card4(base::GenerateGUID(), test::kEmptyOrigin);
+ test::SetCreditCardInfo(&credit_card4, "David",
+ "5105105105105100" /* Mastercard */, "04", "1999",
+ "1");
+ credit_card4.set_use_date(now - base::Days(400));
+ personal_data_->AddCreditCard(credit_card1);
+ personal_data_->AddCreditCard(credit_card2);
+ personal_data_->AddCreditCard(credit_card3);
+ personal_data_->AddCreditCard(credit_card4);
+
+ // Create a unmasked server card expired 400 days ago, and last used 400
+ // days ago.
+ // It is expected to remain because we do not delete server cards.
+ CreditCard credit_card5(CreditCard::FULL_SERVER_CARD, "c789");
+ test::SetCreditCardInfo(&credit_card5, "Emma", "4234567890123456" /* Visa */,
+ "04", "1999", "1");
+ credit_card5.set_use_date(now - base::Days(400));
+
+ // Create masked server card expired 400 days ago, and last used 400 days ago.
+ // It is expected to remain because we do not delete server cards.
+ CreditCard credit_card6(CreditCard::MASKED_SERVER_CARD, "c987");
+ test::SetCreditCardInfo(&credit_card6, "Frank", "6543", "01", "1998", "1");
+ credit_card6.set_use_date(now - base::Days(400));
+ credit_card6.SetNetworkForMaskedCard(kVisaCard);
+
+ // Save the server cards and set used_date to desired dates.
+ std::vector<CreditCard> server_cards;
+ server_cards.push_back(credit_card5);
+ server_cards.push_back(credit_card6);
+ SetServerCards(server_cards);
+ personal_data_->UpdateServerCardsMetadata({credit_card5, credit_card6});
+
+ WaitForOnPersonalDataChanged();
+ EXPECT_EQ(6U, personal_data_->GetCreditCards().size());
+
+ // Setup histograms capturing.
+ base::HistogramTester histogram_tester;
+
+ // DeleteDisusedCreditCards should return true to indicate it was run.
+ EXPECT_TRUE(
+ personal_data_manager_cleaner_->DeleteDisusedCreditCardsForTesting());
+
+ // Wait for the data to be refreshed.
+ WaitForOnPersonalDataChanged();
+
+ EXPECT_EQ(5U, personal_data_->GetCreditCards().size());
+ std::unordered_set<std::u16string> expectedToRemain = {
+ u"Alice", u"Bob", u"Clyde", u"Emma", u"Frank"};
+ for (auto* card : personal_data_->GetCreditCards()) {
+ EXPECT_NE(expectedToRemain.end(),
+ expectedToRemain.find(card->GetRawInfo(CREDIT_CARD_NAME_FULL)));
+ }
+
+ // Verify histograms are logged.
+ histogram_tester.ExpectTotalCount(kHistogramName, 1);
+ histogram_tester.ExpectBucketCount(kHistogramName, 1, 1);
+}
+
+// Tests that all the non settings origins of autofill profiles are cleared but
+// that the settings origins are untouched.
+TEST_F(PersonalDataManagerCleanerTest, ClearProfileNonSettingsOrigins) {
+ // Create three profile with a nonsettings, non-empty origin.
+ AutofillProfile profile0(base::GenerateGUID(), "https://www.example.com");
+ test::SetProfileInfo(&profile0, "Marion0", "Mitchell", "Morrison",
+ "johnwayne@me.xyz", "Fox",
+ "123 Zoo St.\nSecond Line\nThird line", "unit 5",
+ "Hollywood", "CA", "91601", "US", "12345678910");
+ profile0.set_use_count(10000);
+ AddProfileToPersonalDataManager(profile0);
+
+ AutofillProfile profile1(base::GenerateGUID(), test::kEmptyOrigin);
+ test::SetProfileInfo(&profile1, "Marion1", "Mitchell", "Morrison",
+ "johnwayne@me.xyz", "Fox",
+ "123 Zoo St.\nSecond Line\nThird line", "unit 5",
+ "Hollywood", "CA", "91601", "US", "12345678910");
+ profile1.set_use_count(1000);
+ AddProfileToPersonalDataManager(profile1);
+
+ AutofillProfile profile2(base::GenerateGUID(), "1234");
+ test::SetProfileInfo(&profile2, "Marion2", "Mitchell", "Morrison",
+ "johnwayne@me.xyz", "Fox",
+ "123 Zoo St.\nSecond Line\nThird line", "unit 5",
+ "Hollywood", "CA", "91601", "US", "12345678910");
+ profile2.set_use_count(100);
+ AddProfileToPersonalDataManager(profile2);
+
+ // Create a profile with a settings origin.
+ AutofillProfile profile3(base::GenerateGUID(), kSettingsOrigin);
+ test::SetProfileInfo(&profile3, "Marion3", "Mitchell", "Morrison",
+ "johnwayne@me.xyz", "Fox",
+ "123 Zoo St.\nSecond Line\nThird line", "unit 5",
+ "Hollywood", "CA", "91601", "US", "12345678910");
+ profile3.set_use_count(10);
+ AddProfileToPersonalDataManager(profile3);
+
+ ASSERT_EQ(4U, personal_data_->GetProfiles().size());
+
+ base::RunLoop run_loop;
+ EXPECT_CALL(personal_data_observer_, OnPersonalDataFinishedProfileTasks())
+ .WillRepeatedly(QuitMessageLoop(&run_loop));
+ EXPECT_CALL(personal_data_observer_, OnPersonalDataChanged())
+ .Times(2); // The setting of profiles 0 and 2 will be cleared.
+
+ personal_data_manager_cleaner_->ClearProfileNonSettingsOriginsForTesting();
+ run_loop.Run();
+
+ ASSERT_EQ(4U, personal_data_->GetProfiles().size());
+
+ // The first three profiles' origin should be cleared and the fourth one still
+ // be the settings origin.
+ EXPECT_TRUE(personal_data_->GetProfilesToSuggest()[0]->origin().empty());
+ EXPECT_TRUE(personal_data_->GetProfilesToSuggest()[1]->origin().empty());
+ EXPECT_TRUE(personal_data_->GetProfilesToSuggest()[2]->origin().empty());
+ EXPECT_EQ(kSettingsOrigin,
+ personal_data_->GetProfilesToSuggest()[3]->origin());
+}
+
+// Tests that all the non settings origins of autofill credit cards are cleared
+// but that the settings origins are untouched.
+TEST_F(PersonalDataManagerCleanerTest, ClearCreditCardNonSettingsOrigins) {
+ // Create three cards with a non settings origin.
+ CreditCard credit_card0(base::GenerateGUID(), "https://www.example.com");
+ test::SetCreditCardInfo(&credit_card0, "Bob0",
+ "5105105105105100" /* Mastercard */, "04", "1999",
+ "1");
+ credit_card0.set_use_count(10000);
+ personal_data_->AddCreditCard(credit_card0);
+
+ CreditCard credit_card1(base::GenerateGUID(), test::kEmptyOrigin);
+ test::SetCreditCardInfo(&credit_card1, "Bob1",
+ "5105105105105101" /* Mastercard */, "04", "1999",
+ "1");
+ credit_card1.set_use_count(1000);
+ personal_data_->AddCreditCard(credit_card1);
+
+ CreditCard credit_card2(base::GenerateGUID(), "1234");
+ test::SetCreditCardInfo(&credit_card2, "Bob2",
+ "5105105105105102" /* Mastercard */, "04", "1999",
+ "1");
+ credit_card2.set_use_count(100);
+ personal_data_->AddCreditCard(credit_card2);
+
+ // Create a card with a settings origin.
+ CreditCard credit_card3(base::GenerateGUID(), kSettingsOrigin);
+ test::SetCreditCardInfo(&credit_card3, "Bob3",
+ "5105105105105103" /* Mastercard */, "04", "1999",
+ "1");
+ credit_card3.set_use_count(10);
+ personal_data_->AddCreditCard(credit_card3);
+
+ WaitForOnPersonalDataChanged();
+ ASSERT_EQ(4U, personal_data_->GetCreditCards().size());
+
+ personal_data_manager_cleaner_->ClearCreditCardNonSettingsOriginsForTesting();
+
+ WaitForOnPersonalDataChanged();
+ ASSERT_EQ(4U, personal_data_->GetCreditCards().size());
+
+ // The first three profiles' origin should be cleared and the fourth one still
+ // be the settings origin.
+ EXPECT_TRUE(
+ personal_data_->GetCreditCardsToSuggest(false)[0]->origin().empty());
+ EXPECT_TRUE(
+ personal_data_->GetCreditCardsToSuggest(false)[1]->origin().empty());
+ EXPECT_TRUE(
+ personal_data_->GetCreditCardsToSuggest(false)[2]->origin().empty());
+ EXPECT_EQ(kSettingsOrigin,
+ personal_data_->GetCreditCardsToSuggest(false)[3]->origin());
+}
+
+} // namespace autofill
diff --git a/chromium/components/autofill/core/browser/personal_data_manager_test_base.cc b/chromium/components/autofill/core/browser/personal_data_manager_test_base.cc
new file mode 100644
index 00000000000..e4e784c7e66
--- /dev/null
+++ b/chromium/components/autofill/core/browser/personal_data_manager_test_base.cc
@@ -0,0 +1,191 @@
+// Copyright 2022 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/personal_data_manager_test_base.h"
+#include "components/autofill/core/browser/autofill_test_utils.h"
+#include "components/autofill/core/browser/personal_data_manager.h"
+#include "components/autofill/core/common/autofill_clock.h"
+#include "components/autofill/core/common/autofill_features.h"
+
+namespace autofill {
+
+namespace {
+
+const char kPrimaryAccountEmail[] = "syncuser@example.com";
+const char kSyncTransportAccountEmail[] = "transport@example.com";
+
+ACTION_P(QuitMessageLoop, loop) {
+ loop->Quit();
+}
+
+} // anonymous namespace
+
+PersonalDataLoadedObserverMock::PersonalDataLoadedObserverMock() = default;
+PersonalDataLoadedObserverMock::~PersonalDataLoadedObserverMock() = default;
+
+// static
+std::vector<base::Feature>
+PersonalDataManagerTestBase::GetDefaultEnabledFeatures() {
+ // Enable account storage by default, some tests will override this to be
+ // false.
+ return {features::kAutofillEnableAccountWalletStorage};
+}
+
+PersonalDataManagerTestBase::PersonalDataManagerTestBase(
+ const std::vector<base::Feature>& additional_enabled_features)
+ : identity_test_env_(&test_url_loader_factory_) {
+ std::vector<base::Feature> all_enabled_features(
+ PersonalDataManagerTestBase::GetDefaultEnabledFeatures());
+ base::ranges::copy(additional_enabled_features,
+ std::back_inserter(all_enabled_features));
+ scoped_features_.InitWithFeatures(all_enabled_features,
+ /*disabled_features=*/{});
+}
+
+PersonalDataManagerTestBase::~PersonalDataManagerTestBase() = default;
+
+void PersonalDataManagerTestBase::SetUpTest() {
+ OSCryptMocker::SetUp();
+ prefs_ = test::PrefServiceForTesting();
+ base::FilePath path(WebDatabase::kInMemoryPath);
+ profile_web_database_ =
+ new WebDatabaseService(path, base::ThreadTaskRunnerHandle::Get(),
+ base::ThreadTaskRunnerHandle::Get());
+
+ // Hacky: hold onto a pointer but pass ownership.
+ profile_autofill_table_ = new AutofillTable;
+ profile_web_database_->AddTable(
+ std::unique_ptr<WebDatabaseTable>(profile_autofill_table_));
+ profile_web_database_->LoadDatabase();
+ profile_database_service_ = new AutofillWebDataService(
+ profile_web_database_, base::ThreadTaskRunnerHandle::Get(),
+ base::ThreadTaskRunnerHandle::Get());
+ profile_database_service_->Init(base::NullCallback());
+
+ account_web_database_ = new WebDatabaseService(
+ base::FilePath(WebDatabase::kInMemoryPath),
+ base::ThreadTaskRunnerHandle::Get(), base::ThreadTaskRunnerHandle::Get());
+ account_autofill_table_ = new AutofillTable;
+ account_web_database_->AddTable(
+ std::unique_ptr<WebDatabaseTable>(account_autofill_table_));
+ account_web_database_->LoadDatabase();
+ account_database_service_ = new AutofillWebDataService(
+ account_web_database_, base::ThreadTaskRunnerHandle::Get(),
+ base::ThreadTaskRunnerHandle::Get());
+ account_database_service_->Init(base::NullCallback());
+
+ strike_database_ = std::make_unique<TestInMemoryStrikeDatabase>();
+
+ test::DisableSystemServices(prefs_.get());
+}
+
+void PersonalDataManagerTestBase::TearDownTest() {
+ // Order of destruction is important as BrowserAutofillManager relies on
+ // PersonalDataManager to be around when it gets destroyed.
+ test::ReenableSystemServices();
+ OSCryptMocker::TearDown();
+}
+
+void PersonalDataManagerTestBase::ResetPersonalDataManager(
+ bool is_incognito,
+ bool use_sync_transport_mode,
+ PersonalDataManager* personal_data) {
+ personal_data->Init(
+ scoped_refptr<AutofillWebDataService>(profile_database_service_),
+ base::FeatureList::IsEnabled(
+ features::kAutofillEnableAccountWalletStorage)
+ ? scoped_refptr<AutofillWebDataService>(account_database_service_)
+ : nullptr,
+ prefs_.get(), prefs_.get(), identity_test_env_.identity_manager(),
+ /*history_service=*/nullptr, strike_database_.get(),
+ /*image_fetcher=*/nullptr, is_incognito);
+
+ personal_data->AddObserver(&personal_data_observer_);
+ std::string email = use_sync_transport_mode ? kSyncTransportAccountEmail
+ : kPrimaryAccountEmail;
+ // Set the account in both IdentityManager and SyncService.
+ CoreAccountInfo account_info;
+ signin::ConsentLevel consent_level = use_sync_transport_mode
+ ? signin::ConsentLevel::kSignin
+ : signin::ConsentLevel::kSync;
+#if !BUILDFLAG(IS_CHROMEOS_ASH)
+ identity_test_env_.ClearPrimaryAccount();
+ account_info = identity_test_env_.SetPrimaryAccount(email, consent_level);
+#else
+ // In ChromeOS-Ash, clearing/resetting the primary account is not supported.
+ // So if an account already exists, reuse it (and make sure it matches).
+ if (identity_test_env_.identity_manager()->HasPrimaryAccount(consent_level)) {
+ account_info = identity_test_env_.identity_manager()->GetPrimaryAccountInfo(
+ consent_level);
+ ASSERT_EQ(account_info.email, email);
+ } else {
+ account_info = identity_test_env_.SetPrimaryAccount(email, consent_level);
+ }
+#endif
+ sync_service_.SetAccountInfo(account_info);
+ sync_service_.SetHasSyncConsent(!use_sync_transport_mode);
+ personal_data->OnSyncServiceInitialized(&sync_service_);
+ personal_data->OnStateChanged(&sync_service_);
+
+ WaitForOnPersonalDataChangedRepeatedly();
+}
+
+[[nodiscard]] bool PersonalDataManagerTestBase::TurnOnSyncFeature(
+ PersonalDataManager* personal_data) {
+ sync_service_.SetHasSyncConsent(true);
+ if (!sync_service_.IsSyncFeatureEnabled())
+ return false;
+ personal_data->OnStateChanged(&sync_service_);
+
+ return personal_data->IsSyncFeatureEnabled();
+}
+
+void PersonalDataManagerTestBase::RemoveByGUIDFromPersonalDataManager(
+ const std::string& guid,
+ PersonalDataManager* personal_data) {
+ 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->RemoveByGUID(guid);
+ run_loop.Run();
+}
+
+void PersonalDataManagerTestBase::SetServerCards(
+ std::vector<CreditCard> server_cards) {
+ test::SetServerCreditCards(account_autofill_table_, server_cards);
+}
+
+// Verify that the web database has been updated and the notification sent.
+void PersonalDataManagerTestBase::WaitOnceForOnPersonalDataChanged() {
+ base::RunLoop run_loop;
+ EXPECT_CALL(personal_data_observer_, OnPersonalDataFinishedProfileTasks())
+ .WillOnce(QuitMessageLoop(&run_loop));
+ EXPECT_CALL(personal_data_observer_, OnPersonalDataChanged()).Times(1);
+ run_loop.Run();
+}
+
+// Verifies that the web database has been updated and the notification sent.
+void PersonalDataManagerTestBase::WaitForOnPersonalDataChanged() {
+ base::RunLoop run_loop;
+ EXPECT_CALL(personal_data_observer_, OnPersonalDataFinishedProfileTasks())
+ .WillOnce(QuitMessageLoop(&run_loop));
+ EXPECT_CALL(personal_data_observer_, OnPersonalDataChanged())
+ .Times(testing::AnyNumber());
+ run_loop.Run();
+}
+
+// Verifies that the web database has been updated and the notification sent.
+void PersonalDataManagerTestBase::WaitForOnPersonalDataChangedRepeatedly() {
+ base::RunLoop run_loop;
+ EXPECT_CALL(personal_data_observer_, OnPersonalDataFinishedProfileTasks())
+ .WillRepeatedly(QuitMessageLoop(&run_loop));
+ EXPECT_CALL(personal_data_observer_, OnPersonalDataChanged())
+ .Times(testing::AnyNumber());
+ run_loop.Run();
+}
+
+} // namespace autofill
diff --git a/chromium/components/autofill/core/browser/personal_data_manager_test_base.h b/chromium/components/autofill/core/browser/personal_data_manager_test_base.h
new file mode 100644
index 00000000000..50a0ec2eef4
--- /dev/null
+++ b/chromium/components/autofill/core/browser/personal_data_manager_test_base.h
@@ -0,0 +1,87 @@
+// Copyright 2022 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_PERSONAL_DATA_MANAGER_TEST_BASE_H_
+#define COMPONENTS_AUTOFILL_CORE_BROWSER_PERSONAL_DATA_MANAGER_TEST_BASE_H_
+
+#include "base/test/scoped_feature_list.h"
+#include "base/test/task_environment.h"
+#include "components/autofill/core/browser/personal_data_manager_observer.h"
+#include "components/autofill/core/browser/test_inmemory_strike_database.h"
+#include "components/autofill/core/browser/webdata/autofill_table.h"
+#include "components/autofill/core/browser/webdata/autofill_webdata_service.h"
+#include "components/autofill/core/common/autofill_clock.h"
+#include "components/os_crypt/os_crypt_mocker.h"
+#include "components/prefs/pref_service.h"
+#include "components/signin/public/identity_manager/identity_test_environment.h"
+#include "components/sync/driver/test_sync_service.h"
+#include "components/webdata/common/web_data_service_base.h"
+#include "components/webdata/common/web_database_service.h"
+#include "services/network/test/test_url_loader_factory.h"
+#include "testing/gmock/include/gmock/gmock.h"
+
+namespace autofill {
+
+class PersonalDataManager;
+
+class PersonalDataLoadedObserverMock : public PersonalDataManagerObserver {
+ public:
+ PersonalDataLoadedObserverMock();
+ ~PersonalDataLoadedObserverMock() override;
+
+ MOCK_METHOD(void, OnPersonalDataChanged, (), (override));
+ MOCK_METHOD(void, OnPersonalDataFinishedProfileTasks, (), (override));
+};
+
+class PersonalDataManagerTestBase {
+ protected:
+ static std::vector<base::Feature> GetDefaultEnabledFeatures();
+
+ explicit PersonalDataManagerTestBase(
+ const std::vector<base::Feature>& additional_enabled_features = {});
+
+ ~PersonalDataManagerTestBase();
+
+ void SetUpTest();
+ void TearDownTest();
+
+ void ResetPersonalDataManager(bool is_incognito,
+ bool use_sync_transport_mode,
+ PersonalDataManager* personal_data);
+
+ [[nodiscard]] bool TurnOnSyncFeature(PersonalDataManager* personal_data);
+
+ void RemoveByGUIDFromPersonalDataManager(const std::string& guid,
+ PersonalDataManager* personal_data);
+
+ void SetServerCards(std::vector<CreditCard> server_cards);
+
+ // Verify that the web database has been updated and the notification sent.
+ void WaitOnceForOnPersonalDataChanged();
+
+ // Verifies that the web database has been updated and the notification sent.
+ void WaitForOnPersonalDataChanged();
+
+ // Verifies that the web database has been updated and the notification sent.
+ void WaitForOnPersonalDataChangedRepeatedly();
+
+ base::test::TaskEnvironment task_environment_;
+ std::unique_ptr<PrefService> prefs_;
+ base::test::ScopedFeatureList scoped_features_;
+ network::TestURLLoaderFactory test_url_loader_factory_;
+ signin::IdentityTestEnvironment identity_test_env_;
+ syncer::TestSyncService sync_service_;
+ scoped_refptr<AutofillWebDataService> profile_database_service_;
+ scoped_refptr<AutofillWebDataService> account_database_service_;
+ scoped_refptr<WebDatabaseService> profile_web_database_;
+ scoped_refptr<WebDatabaseService> account_web_database_;
+ raw_ptr<AutofillTable> profile_autofill_table_; // weak ref
+ raw_ptr<AutofillTable> account_autofill_table_; // weak ref
+ std::unique_ptr<StrikeDatabaseBase> strike_database_;
+ PersonalDataLoadedObserverMock personal_data_observer_;
+};
+
+} // namespace autofill
+
+#endif // COMPONENTS_AUTOFILL_CORE_BROWSER_PERSONAL_DATA_MANAGER_TEST_BASE_H_
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 c0a220df582..ba2d3526528 100644
--- a/chromium/components/autofill/core/browser/personal_data_manager_unittest.cc
+++ b/chromium/components/autofill/core/browser/personal_data_manager_unittest.cc
@@ -14,21 +14,15 @@
#include <utility>
#include <vector>
-#include "base/base64.h"
#include "base/callback_helpers.h"
-#include "base/command_line.h"
#include "base/containers/contains.h"
#include "base/guid.h"
-#include "base/i18n/time_formatting.h"
#include "base/memory/raw_ptr.h"
-#include "base/rand_util.h"
#include "base/run_loop.h"
#include "base/strings/stringprintf.h"
#include "base/strings/utf_string_conversions.h"
-#include "base/synchronization/waitable_event.h"
#include "base/test/metrics/histogram_tester.h"
#include "base/test/scoped_feature_list.h"
-#include "base/test/simple_test_clock.h"
#include "base/test/task_environment.h"
#include "base/threading/thread_task_runner_handle.h"
#include "base/time/time.h"
@@ -43,15 +37,12 @@
#include "components/autofill/core/browser/field_types.h"
#include "components/autofill/core/browser/form_structure.h"
#include "components/autofill/core/browser/metrics/autofill_metrics.h"
-#include "components/autofill/core/browser/personal_data_manager_observer.h"
+#include "components/autofill/core/browser/personal_data_manager_test_base.h"
#include "components/autofill/core/browser/sync_utils.h"
#include "components/autofill/core/browser/test_autofill_clock.h"
-#include "components/autofill/core/browser/test_inmemory_strike_database.h"
#include "components/autofill/core/browser/ui/label_formatter_utils.h"
#include "components/autofill/core/browser/ui/suggestion.h"
#include "components/autofill/core/browser/ui/suggestion_selection.h"
-#include "components/autofill/core/browser/webdata/autofill_table.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_constants.h"
#include "components/autofill/core/common/autofill_features.h"
@@ -59,24 +50,16 @@
#include "components/autofill/core/common/autofill_prefs.h"
#include "components/autofill/core/common/autofill_switches.h"
#include "components/autofill/core/common/form_data.h"
-#include "components/os_crypt/os_crypt_mocker.h"
-#include "components/prefs/pref_service.h"
#include "components/signin/public/base/signin_switches.h"
#include "components/signin/public/identity_manager/identity_test_environment.h"
-#include "components/sync/driver/sync_service_utils.h"
#include "components/sync/driver/test_sync_service.h"
#include "components/version_info/version_info.h"
-#include "components/webdata/common/web_data_service_base.h"
-#include "components/webdata/common/web_database_service.h"
-#include "google_apis/gaia/google_service_auth_error.h"
-#include "services/network/test/test_url_loader_factory.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "ui/gfx/image/image_unittest_util.h"
namespace autofill {
-using structured_address::HonorificPrefixEnabled;
using structured_address::StructuredAddressesEnabled;
using structured_address::StructuredNamesEnabled;
@@ -84,7 +67,6 @@ namespace {
const char kPrimaryAccountEmail[] = "syncuser@example.com";
const char16_t kPrimaryAccountEmail16[] = u"syncuser@example.com";
-const char kSyncTransportAccountEmail[] = "transport@example.com";
enum UserMode { USER_MODE_NORMAL, USER_MODE_INCOGNITO };
@@ -96,15 +78,6 @@ ACTION_P(QuitMessageLoop, loop) {
loop->Quit();
}
-class PersonalDataLoadedObserverMock : public PersonalDataManagerObserver {
- public:
- PersonalDataLoadedObserverMock() = default;
- ~PersonalDataLoadedObserverMock() override = default;
-
- MOCK_METHOD(void, OnPersonalDataChanged, (), (override));
- MOCK_METHOD(void, OnPersonalDataFinishedProfileTasks, (), (override));
-};
-
class PersonalDataManagerMock : public PersonalDataManager {
public:
explicit PersonalDataManagerMock(const std::string& app_locale,
@@ -149,195 +122,8 @@ void ExpectSameElements(const std::vector<T*>& expectations,
results_copy.end());
}
-class ScopedFeatureListWrapper {
- public:
- explicit ScopedFeatureListWrapper(
- const std::vector<base::Feature>& default_enabled_features,
- const std::vector<base::Feature>& additional_enabled_features) {
- std::vector<base::Feature> all_enabled_features(default_enabled_features);
- std::copy(additional_enabled_features.begin(),
- additional_enabled_features.end(),
- std::back_inserter(all_enabled_features));
- scoped_features_.InitWithFeatures(all_enabled_features,
- /*disabled_features=*/{});
- }
- ~ScopedFeatureListWrapper() = default;
-
- private:
- base::test::ScopedFeatureList scoped_features_;
-};
-
} // anonymous namespace
-class PersonalDataManagerTestBase {
- protected:
- static std::vector<base::Feature> GetDefaultEnabledFeatures() {
- // Enable account storage by default, some tests will override this to be
- // false.
- return {features::kAutofillEnableAccountWalletStorage};
- }
-
- PersonalDataManagerTestBase()
- : scoped_features_(
- PersonalDataManagerTestBase::GetDefaultEnabledFeatures(),
- /*additional_enabled_features=*/{}),
- identity_test_env_(&test_url_loader_factory_) {}
-
- explicit PersonalDataManagerTestBase(
- const std::vector<base::Feature>& additioanal_enabled_features)
- : scoped_features_(
- PersonalDataManagerTestBase::GetDefaultEnabledFeatures(),
- additioanal_enabled_features),
- identity_test_env_(&test_url_loader_factory_) {}
-
- void SetUpTest() {
- OSCryptMocker::SetUp();
- prefs_ = test::PrefServiceForTesting();
- base::FilePath path(WebDatabase::kInMemoryPath);
- profile_web_database_ =
- new WebDatabaseService(path, base::ThreadTaskRunnerHandle::Get(),
- base::ThreadTaskRunnerHandle::Get());
-
- // Hacky: hold onto a pointer but pass ownership.
- profile_autofill_table_ = new AutofillTable;
- profile_web_database_->AddTable(
- std::unique_ptr<WebDatabaseTable>(profile_autofill_table_));
- profile_web_database_->LoadDatabase();
- profile_database_service_ = new AutofillWebDataService(
- profile_web_database_, base::ThreadTaskRunnerHandle::Get(),
- base::ThreadTaskRunnerHandle::Get());
- profile_database_service_->Init(base::NullCallback());
-
- account_web_database_ =
- new WebDatabaseService(base::FilePath(WebDatabase::kInMemoryPath),
- base::ThreadTaskRunnerHandle::Get(),
- base::ThreadTaskRunnerHandle::Get());
- account_autofill_table_ = new AutofillTable;
- account_web_database_->AddTable(
- std::unique_ptr<WebDatabaseTable>(account_autofill_table_));
- account_web_database_->LoadDatabase();
- account_database_service_ = new AutofillWebDataService(
- account_web_database_, base::ThreadTaskRunnerHandle::Get(),
- base::ThreadTaskRunnerHandle::Get());
- account_database_service_->Init(base::NullCallback());
-
- strike_database_ = std::make_unique<TestInMemoryStrikeDatabase>();
-
- test::DisableSystemServices(prefs_.get());
- }
-
- void TearDownTest() {
- // Order of destruction is important as BrowserAutofillManager relies on
- // PersonalDataManager to be around when it gets destroyed.
- test::ReenableSystemServices();
- OSCryptMocker::TearDown();
- }
-
- void ResetPersonalDataManager(UserMode user_mode,
- bool use_sync_transport_mode,
- PersonalDataManager* personal_data) {
- bool is_incognito = (user_mode == USER_MODE_INCOGNITO);
-
- personal_data->Init(
- scoped_refptr<AutofillWebDataService>(profile_database_service_),
- base::FeatureList::IsEnabled(
- features::kAutofillEnableAccountWalletStorage)
- ? scoped_refptr<AutofillWebDataService>(account_database_service_)
- : nullptr,
- prefs_.get(), prefs_.get(), identity_test_env_.identity_manager(),
- /*history_service=*/nullptr, strike_database_.get(),
- /*image_fetcher=*/nullptr, is_incognito);
-
- personal_data->AddObserver(&personal_data_observer_);
- AccountInfo account_info;
- account_info.email = use_sync_transport_mode ? kSyncTransportAccountEmail
- : kPrimaryAccountEmail;
- sync_service_.SetAccountInfo(account_info);
- sync_service_.SetHasSyncConsent(!use_sync_transport_mode);
- personal_data->OnSyncServiceInitialized(&sync_service_);
- personal_data->OnStateChanged(&sync_service_);
-
- WaitForOnPersonalDataChangedRepeatedly();
- }
-
- [[nodiscard]] bool TurnOnSyncFeature(PersonalDataManager* personal_data) {
- sync_service_.SetHasSyncConsent(true);
- if (!sync_service_.IsSyncFeatureEnabled())
- return false;
- personal_data->OnStateChanged(&sync_service_);
-
- return personal_data->IsSyncFeatureEnabled();
- }
-
- void RemoveByGUIDFromPersonalDataManager(const std::string& guid,
- PersonalDataManager* personal_data) {
- 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->RemoveByGUID(guid);
- run_loop.Run();
- }
-
- void SetServerCards(std::vector<CreditCard> server_cards) {
- test::SetServerCreditCards(account_autofill_table_, server_cards);
- }
-
- // Verify that the web database has been updated and the notification sent.
- void WaitOnceForOnPersonalDataChanged() {
- base::RunLoop run_loop;
- EXPECT_CALL(personal_data_observer_, OnPersonalDataFinishedProfileTasks())
- .WillOnce(QuitMessageLoop(&run_loop));
- EXPECT_CALL(personal_data_observer_, OnPersonalDataChanged()).Times(1);
- run_loop.Run();
- }
-
- // Verifies that the web database has been updated and the notification sent.
- void WaitForOnPersonalDataChanged() {
- base::RunLoop run_loop;
- EXPECT_CALL(personal_data_observer_, OnPersonalDataFinishedProfileTasks())
- .WillOnce(QuitMessageLoop(&run_loop));
- EXPECT_CALL(personal_data_observer_, OnPersonalDataChanged())
- .Times(testing::AnyNumber());
- run_loop.Run();
- }
-
- // Verifies that the web database has been updated and the notification sent.
- void WaitForOnPersonalDataChangedRepeatedly() {
- base::RunLoop run_loop;
- EXPECT_CALL(personal_data_observer_, OnPersonalDataFinishedProfileTasks())
- .WillRepeatedly(QuitMessageLoop(&run_loop));
- EXPECT_CALL(personal_data_observer_, OnPersonalDataChanged())
- .Times(testing::AnyNumber());
- run_loop.Run();
- }
-
- AccountInfo SetActiveSecondaryAccount() {
- AccountInfo account_info;
- account_info.email = kSyncTransportAccountEmail;
- account_info.account_id = CoreAccountId("account_id");
- sync_service_.SetAccountInfo(account_info);
- sync_service_.SetHasSyncConsent(false);
- return account_info;
- }
- base::test::TaskEnvironment task_environment_;
- std::unique_ptr<PrefService> prefs_;
- ScopedFeatureListWrapper scoped_features_;
- network::TestURLLoaderFactory test_url_loader_factory_;
- signin::IdentityTestEnvironment identity_test_env_;
- syncer::TestSyncService sync_service_;
- scoped_refptr<AutofillWebDataService> profile_database_service_;
- scoped_refptr<AutofillWebDataService> account_database_service_;
- scoped_refptr<WebDatabaseService> profile_web_database_;
- scoped_refptr<WebDatabaseService> account_web_database_;
- raw_ptr<AutofillTable> profile_autofill_table_; // weak ref
- raw_ptr<AutofillTable> account_autofill_table_; // weak ref
- std::unique_ptr<StrikeDatabaseBase> strike_database_;
- PersonalDataLoadedObserverMock personal_data_observer_;
-};
-
class PersonalDataManagerHelper : public PersonalDataManagerTestBase {
protected:
PersonalDataManagerHelper() = default;
@@ -353,12 +139,13 @@ class PersonalDataManagerHelper : public PersonalDataManagerTestBase {
}
void ResetPersonalDataManager(UserMode user_mode,
- bool use_account_server_storage = false) {
+ bool use_sync_transport_mode = false) {
if (personal_data_)
personal_data_->Shutdown();
personal_data_ = std::make_unique<PersonalDataManager>("EN", "US");
PersonalDataManagerTestBase::ResetPersonalDataManager(
- user_mode, use_account_server_storage, personal_data_.get());
+ user_mode == USER_MODE_INCOGNITO, use_sync_transport_mode,
+ personal_data_.get());
}
void ResetProfiles() {
@@ -576,6 +363,18 @@ class PersonalDataManagerTest : public PersonalDataManagerHelper,
void TearDown() override { TearDownTest(); }
};
+class PersonalDataManagerSyncTransportModeTest
+ : public PersonalDataManagerHelper,
+ public testing::Test {
+ protected:
+ void SetUp() override {
+ SetUpTest();
+ ResetPersonalDataManager(USER_MODE_NORMAL,
+ /*use_sync_transport_mode=*/true);
+ }
+ void TearDown() override { TearDownTest(); }
+};
+
#if BUILDFLAG(IS_CHROMEOS_ASH)
class PersonalDataManagerMigrationTest : public PersonalDataManagerHelper,
public testing::Test {
@@ -612,7 +411,8 @@ class PersonalDataManagerMockTest : public PersonalDataManagerTestBase,
personal_data_ =
std::make_unique<PersonalDataManagerMock>("en", std::string());
PersonalDataManagerTestBase::ResetPersonalDataManager(
- user_mode, /*use_sync_transport_mode=*/true, personal_data_.get());
+ user_mode == USER_MODE_INCOGNITO, /*use_sync_transport_mode=*/true,
+ personal_data_.get());
}
bool TurnOnSyncFeature() {
@@ -985,6 +785,80 @@ TEST_F(PersonalDataManagerTest, AddUpdateRemoveProfiles) {
ExpectSameElements(profiles, personal_data_->GetProfiles());
}
+TEST_F(PersonalDataManagerTest, NoIBANsAddedIfDisabled) {
+ prefs::SetAutofillIBANEnabled(prefs_.get(), false);
+ IBAN iban0(base::GenerateGUID());
+ iban0.set_value(u"IE12 BOFI 9000 0112 3456 78");
+ iban0.set_nickname(u"Nickname 0");
+
+ IBAN iban1(base::GenerateGUID());
+ iban1.set_value(u"DE91 1000 0000 0123 4567 89");
+ iban1.set_nickname(u"Nickname 1");
+
+ personal_data_->AddIBAN(iban0);
+ personal_data_->AddIBAN(iban1);
+
+ EXPECT_EQ(0U, personal_data_->GetIBANs().size());
+}
+
+TEST_F(PersonalDataManagerTest, AddUpdateRemoveIbans) {
+ prefs::SetAutofillIBANEnabled(prefs_.get(), true);
+ IBAN iban0(base::GenerateGUID());
+ iban0.set_value(u"IE12 BOFI 9000 0112 3456 78");
+ iban0.set_nickname(u"Nickname 0");
+
+ IBAN iban1(base::GenerateGUID());
+ iban1.set_value(u"DE91 1000 0000 0123 4567 89");
+ iban1.set_nickname(u"Nickname 1");
+
+ IBAN iban2(base::GenerateGUID());
+ iban2.set_value(u"ES79 2100 0813 6101 2345 6789");
+ iban2.set_nickname(u"Nickname 2");
+
+ // Add two test IBANs to the database.
+ personal_data_->AddIBAN(iban0);
+ personal_data_->AddIBAN(iban1);
+
+ WaitForOnPersonalDataChanged();
+
+ std::vector<IBAN*> ibans;
+ ibans.push_back(&iban0);
+ ibans.push_back(&iban1);
+ ExpectSameElements(ibans, personal_data_->GetIBANs());
+
+ // Update IBAN0, remove IBAN1, and add IBAN2.
+ iban0.set_nickname(u"Nickname new 0");
+ iban0.SetRawInfo(IBAN_VALUE, u"GB98 MIDL 0700 9312 3456 78");
+ personal_data_->UpdateIBAN(iban0);
+ RemoveByGUIDFromPersonalDataManager(iban1.guid());
+ personal_data_->AddIBAN(iban2);
+
+ WaitForOnPersonalDataChanged();
+
+ ibans.clear();
+ ibans.push_back(&iban0);
+ ibans.push_back(&iban2);
+ ExpectSameElements(ibans, personal_data_->GetIBANs());
+
+ // Verify that a duplicate IBAN should not be added.
+ IBAN iban0_dup = iban0;
+ personal_data_->AddIBAN(iban0_dup);
+ ibans.clear();
+ ibans.push_back(&iban0);
+ ibans.push_back(&iban2);
+ ExpectSameElements(ibans, personal_data_->GetIBANs());
+
+ // Reset the PersonalDataManager. This tests that the personal data was saved
+ // to the web database, and that we can load the IBANs from the web database.
+ ResetPersonalDataManager(USER_MODE_NORMAL);
+
+ // Verify that we've reloaded the IBANs from the web database.
+ ibans.clear();
+ ibans.push_back(&iban0);
+ ibans.push_back(&iban2);
+ ExpectSameElements(ibans, personal_data_->GetIBANs());
+}
+
TEST_F(PersonalDataManagerTest, AddUpdateRemoveCreditCards) {
CreditCard credit_card0(base::GenerateGUID(), test::kEmptyOrigin);
test::SetCreditCardInfo(&credit_card0, "John Dillinger",
@@ -1331,6 +1205,8 @@ TEST_F(PersonalDataManagerTest, UpdateVerifiedProfilesOrigin) {
}
// Test that ensure local data is not lost on sign-in.
+// Clearing/changing the primary account is not supported on CrOS.
+#if !BUILDFLAG(IS_CHROMEOS_ASH)
TEST_F(PersonalDataManagerTest, KeepExistingLocalDataOnSignIn) {
// Set up the experiment flags.
base::test::ScopedFeatureList scoped_features;
@@ -1338,13 +1214,10 @@ TEST_F(PersonalDataManagerTest, KeepExistingLocalDataOnSignIn) {
/*enabled_features=*/{features::kAutofillEnableAccountWalletStorage},
/*disabled_features=*/{});
-// ClearPrimaryAccount is not supported on CrOS.
-#if !BUILDFLAG(IS_CHROMEOS_ASH)
// Sign out.
identity_test_env_.ClearPrimaryAccount();
EXPECT_EQ(AutofillSyncSigninState::kSignedOut,
personal_data_->GetSyncSigninState());
-#endif
EXPECT_EQ(0U, personal_data_->GetCreditCards().size());
// Add local card.
@@ -1373,6 +1246,7 @@ TEST_F(PersonalDataManagerTest, KeepExistingLocalDataOnSignIn) {
EXPECT_EQ(1U, personal_data_->GetCreditCards().size());
EXPECT_EQ(0, local_card.Compare(*personal_data_->GetCreditCards()[0]));
}
+#endif
TEST_F(PersonalDataManagerTest, AddProfilesAndCreditCards) {
AutofillProfile profile0(base::GenerateGUID(), test::kEmptyOrigin);
@@ -1668,43 +1542,36 @@ TEST_F(PersonalDataManagerTest, GetNonEmptyTypes) {
// Make sure everything is set up correctly.
EXPECT_EQ(1U, personal_data_->GetProfiles().size());
- personal_data_->GetNonEmptyTypes(&non_empty_types);
+ std::vector<ServerFieldType> expected_types{NAME_FIRST,
+ NAME_LAST,
+ NAME_FULL,
+ EMAIL_ADDRESS,
+ ADDRESS_HOME_LINE1,
+ ADDRESS_HOME_STREET_ADDRESS,
+ ADDRESS_HOME_CITY,
+ ADDRESS_HOME_STATE,
+ ADDRESS_HOME_ZIP,
+ ADDRESS_HOME_COUNTRY,
+ PHONE_HOME_NUMBER,
+ PHONE_HOME_NUMBER_PREFIX,
+ PHONE_HOME_NUMBER_SUFFIX,
+ PHONE_HOME_COUNTRY_CODE,
+ PHONE_HOME_CITY_CODE,
+ PHONE_HOME_CITY_AND_NUMBER,
+ PHONE_HOME_WHOLE_NUMBER};
// For structured names and addresses, there are more non-empty types.
// TODO(crbug.com/1103421): Clean once launched.
- unsigned int non_empty_types_expectation = 15;
if (StructuredNamesEnabled())
- non_empty_types_expectation += 1;
- // TODO(crbug.com/1130194): Clean once launched.
- if (StructuredAddressesEnabled())
- non_empty_types_expectation += 2;
- if (HonorificPrefixEnabled())
- non_empty_types_expectation += 1;
-
- EXPECT_EQ(non_empty_types_expectation, non_empty_types.size());
-
- EXPECT_TRUE(non_empty_types.count(NAME_FIRST));
- EXPECT_TRUE(non_empty_types.count(NAME_LAST));
- // TODO(crbug.com/1103421): Clean once launched.
- if (StructuredNamesEnabled())
- EXPECT_TRUE(non_empty_types.count(NAME_LAST_SECOND));
- EXPECT_TRUE(non_empty_types.count(NAME_FULL));
- EXPECT_TRUE(non_empty_types.count(EMAIL_ADDRESS));
- EXPECT_TRUE(non_empty_types.count(ADDRESS_HOME_LINE1));
- EXPECT_TRUE(non_empty_types.count(ADDRESS_HOME_STREET_ADDRESS));
+ expected_types.push_back(NAME_LAST_SECOND);
// TODO(crbug.com/1130194): Clean once launched.
if (StructuredAddressesEnabled()) {
- EXPECT_TRUE(non_empty_types.count(ADDRESS_HOME_STREET_NAME));
- EXPECT_TRUE(non_empty_types.count(ADDRESS_HOME_HOUSE_NUMBER));
+ expected_types.insert(expected_types.end(), {ADDRESS_HOME_STREET_NAME,
+ ADDRESS_HOME_HOUSE_NUMBER});
}
- EXPECT_TRUE(non_empty_types.count(ADDRESS_HOME_CITY));
- EXPECT_TRUE(non_empty_types.count(ADDRESS_HOME_STATE));
- EXPECT_TRUE(non_empty_types.count(ADDRESS_HOME_ZIP));
- EXPECT_TRUE(non_empty_types.count(ADDRESS_HOME_COUNTRY));
- EXPECT_TRUE(non_empty_types.count(PHONE_HOME_NUMBER));
- EXPECT_TRUE(non_empty_types.count(PHONE_HOME_COUNTRY_CODE));
- EXPECT_TRUE(non_empty_types.count(PHONE_HOME_CITY_CODE));
- EXPECT_TRUE(non_empty_types.count(PHONE_HOME_CITY_AND_NUMBER));
- EXPECT_TRUE(non_empty_types.count(PHONE_HOME_WHOLE_NUMBER));
+
+ personal_data_->GetNonEmptyTypes(&non_empty_types);
+ EXPECT_THAT(non_empty_types,
+ testing::UnorderedElementsAreArray(expected_types));
// Test with multiple profiles stored.
AutofillProfile profile1(base::GenerateGUID(), test::kEmptyOrigin);
@@ -1722,44 +1589,13 @@ TEST_F(PersonalDataManagerTest, GetNonEmptyTypes) {
EXPECT_EQ(3U, personal_data_->GetProfiles().size());
+ expected_types.insert(
+ expected_types.end(),
+ {NAME_MIDDLE, NAME_MIDDLE_INITIAL, ADDRESS_HOME_LINE2, COMPANY_NAME});
+
personal_data_->GetNonEmptyTypes(&non_empty_types);
- non_empty_types_expectation = 19;
- // For structured names, there is one more non-empty type.
- // TODO(crbug.com/1103421): Clean once launched.
- if (StructuredNamesEnabled())
- non_empty_types_expectation += 1;
- if (HonorificPrefixEnabled())
- non_empty_types_expectation += 1;
- // TODO(crbug.com/1130194): Clean once launched.
- if (StructuredAddressesEnabled())
- non_empty_types_expectation += 2;
- EXPECT_EQ(non_empty_types_expectation, non_empty_types.size());
- EXPECT_TRUE(non_empty_types.count(NAME_FIRST));
- EXPECT_TRUE(non_empty_types.count(NAME_MIDDLE));
- EXPECT_TRUE(non_empty_types.count(NAME_MIDDLE_INITIAL));
- // TODO(crbug.com/1103421): Clean once launched.
- if (StructuredNamesEnabled())
- EXPECT_TRUE(non_empty_types.count(NAME_LAST));
- EXPECT_TRUE(non_empty_types.count(NAME_FULL));
- EXPECT_TRUE(non_empty_types.count(EMAIL_ADDRESS));
- EXPECT_TRUE(non_empty_types.count(COMPANY_NAME));
- EXPECT_TRUE(non_empty_types.count(ADDRESS_HOME_LINE1));
- EXPECT_TRUE(non_empty_types.count(ADDRESS_HOME_LINE2));
- EXPECT_TRUE(non_empty_types.count(ADDRESS_HOME_STREET_ADDRESS));
- // TODO(crbug.com/1130194): Clean once launched.
- if (StructuredAddressesEnabled()) {
- EXPECT_TRUE(non_empty_types.count(ADDRESS_HOME_STREET_NAME));
- EXPECT_TRUE(non_empty_types.count(ADDRESS_HOME_HOUSE_NUMBER));
- }
- EXPECT_TRUE(non_empty_types.count(ADDRESS_HOME_CITY));
- EXPECT_TRUE(non_empty_types.count(ADDRESS_HOME_STATE));
- EXPECT_TRUE(non_empty_types.count(ADDRESS_HOME_ZIP));
- EXPECT_TRUE(non_empty_types.count(ADDRESS_HOME_COUNTRY));
- EXPECT_TRUE(non_empty_types.count(PHONE_HOME_NUMBER));
- EXPECT_TRUE(non_empty_types.count(PHONE_HOME_CITY_CODE));
- EXPECT_TRUE(non_empty_types.count(PHONE_HOME_COUNTRY_CODE));
- EXPECT_TRUE(non_empty_types.count(PHONE_HOME_CITY_AND_NUMBER));
- EXPECT_TRUE(non_empty_types.count(PHONE_HOME_WHOLE_NUMBER));
+ EXPECT_THAT(non_empty_types,
+ testing::UnorderedElementsAreArray(expected_types));
// Test with credit card information also stored.
CreditCard credit_card(base::GenerateGUID(), test::kEmptyOrigin);
@@ -1770,54 +1606,16 @@ TEST_F(PersonalDataManagerTest, GetNonEmptyTypes) {
WaitForOnPersonalDataChanged();
EXPECT_EQ(1U, personal_data_->GetCreditCards().size());
+ expected_types.insert(
+ expected_types.end(),
+ {CREDIT_CARD_NAME_FULL, CREDIT_CARD_NAME_FIRST, CREDIT_CARD_NAME_LAST,
+ CREDIT_CARD_NUMBER, CREDIT_CARD_TYPE, CREDIT_CARD_EXP_MONTH,
+ CREDIT_CARD_EXP_2_DIGIT_YEAR, CREDIT_CARD_EXP_4_DIGIT_YEAR,
+ CREDIT_CARD_EXP_DATE_2_DIGIT_YEAR, CREDIT_CARD_EXP_DATE_4_DIGIT_YEAR});
+
personal_data_->GetNonEmptyTypes(&non_empty_types);
- // For structured names, there is one more non-empty type.
- // TODO(crbug.com/1103421): Clean once launched.
- non_empty_types_expectation = 29;
- if (StructuredNamesEnabled())
- non_empty_types_expectation += 1;
- if (HonorificPrefixEnabled())
- non_empty_types_expectation += 1;
- // TODO(crbug.com/1130194): Clean once launched.
- if (StructuredAddressesEnabled())
- non_empty_types_expectation += 2;
- EXPECT_EQ(non_empty_types_expectation, non_empty_types.size());
- EXPECT_TRUE(non_empty_types.count(NAME_FIRST));
- EXPECT_TRUE(non_empty_types.count(NAME_MIDDLE));
- EXPECT_TRUE(non_empty_types.count(NAME_MIDDLE_INITIAL));
- EXPECT_TRUE(non_empty_types.count(NAME_LAST));
- EXPECT_TRUE(non_empty_types.count(NAME_FULL));
- if (StructuredNamesEnabled())
- EXPECT_TRUE(non_empty_types.count(NAME_LAST));
- EXPECT_TRUE(non_empty_types.count(EMAIL_ADDRESS));
- EXPECT_TRUE(non_empty_types.count(COMPANY_NAME));
- EXPECT_TRUE(non_empty_types.count(ADDRESS_HOME_LINE1));
- EXPECT_TRUE(non_empty_types.count(ADDRESS_HOME_LINE2));
- EXPECT_TRUE(non_empty_types.count(ADDRESS_HOME_STREET_ADDRESS));
- // TODO(crbug.com/1130194): Clean once launched.
- if (StructuredAddressesEnabled()) {
- EXPECT_TRUE(non_empty_types.count(ADDRESS_HOME_STREET_NAME));
- EXPECT_TRUE(non_empty_types.count(ADDRESS_HOME_HOUSE_NUMBER));
- }
- EXPECT_TRUE(non_empty_types.count(ADDRESS_HOME_CITY));
- EXPECT_TRUE(non_empty_types.count(ADDRESS_HOME_STATE));
- EXPECT_TRUE(non_empty_types.count(ADDRESS_HOME_ZIP));
- EXPECT_TRUE(non_empty_types.count(ADDRESS_HOME_COUNTRY));
- EXPECT_TRUE(non_empty_types.count(PHONE_HOME_NUMBER));
- EXPECT_TRUE(non_empty_types.count(PHONE_HOME_CITY_CODE));
- EXPECT_TRUE(non_empty_types.count(PHONE_HOME_COUNTRY_CODE));
- EXPECT_TRUE(non_empty_types.count(PHONE_HOME_CITY_AND_NUMBER));
- EXPECT_TRUE(non_empty_types.count(PHONE_HOME_WHOLE_NUMBER));
- EXPECT_TRUE(non_empty_types.count(CREDIT_CARD_NAME_FULL));
- EXPECT_TRUE(non_empty_types.count(CREDIT_CARD_NAME_FIRST));
- EXPECT_TRUE(non_empty_types.count(CREDIT_CARD_NAME_LAST));
- EXPECT_TRUE(non_empty_types.count(CREDIT_CARD_NUMBER));
- EXPECT_TRUE(non_empty_types.count(CREDIT_CARD_TYPE));
- EXPECT_TRUE(non_empty_types.count(CREDIT_CARD_EXP_MONTH));
- EXPECT_TRUE(non_empty_types.count(CREDIT_CARD_EXP_2_DIGIT_YEAR));
- EXPECT_TRUE(non_empty_types.count(CREDIT_CARD_EXP_4_DIGIT_YEAR));
- EXPECT_TRUE(non_empty_types.count(CREDIT_CARD_EXP_DATE_2_DIGIT_YEAR));
- EXPECT_TRUE(non_empty_types.count(CREDIT_CARD_EXP_DATE_4_DIGIT_YEAR));
+ EXPECT_THAT(non_empty_types,
+ testing::UnorderedElementsAreArray(expected_types));
}
TEST_F(PersonalDataManagerTest, IncognitoReadOnly) {
@@ -1920,6 +1718,21 @@ TEST_F(PersonalDataManagerMockTest, GetAutofillOffers_WalletImportDisabled) {
EXPECT_EQ(0U, personal_data_->GetAutofillOffers().size());
}
+// Tests that GetAutofillOffers does not return any offers if
+// |IsAutofillCreditCardEnabled()| returns |false|.
+TEST_F(PersonalDataManagerMockTest,
+ GetAutofillOffers_AutofillCreditCardDisabled) {
+ // Add a card-linked offer and a promo code offer.
+ AddOfferDataForTest(test::GetCardLinkedOfferData1());
+ AddOfferDataForTest(test::GetPromoCodeOfferData());
+
+ prefs::SetAutofillCreditCardEnabled(prefs_.get(), false);
+
+ // Should return neither of the offers as the autofill credit card import pref
+ // is disabled.
+ EXPECT_EQ(0U, personal_data_->GetAutofillOffers().size());
+}
+
// Tests that GetActiveAutofillPromoCodeOffersForOrigin returns only active and
// site-relevant promo code offers.
TEST_F(PersonalDataManagerTest, GetActiveAutofillPromoCodeOffersForOrigin) {
@@ -1963,6 +1776,23 @@ TEST_F(PersonalDataManagerMockTest,
.size());
}
+// Tests that GetActiveAutofillPromoCodeOffersForOrigin does not return any
+// promo code offers if |IsAutofillCreditCardEnabled()| returns |false|.
+TEST_F(PersonalDataManagerMockTest,
+ GetActiveAutofillPromoCodeOffersForOrigin_AutofillCreditCardDisabled) {
+ // Add an active promo code offer.
+ AddOfferDataForTest(test::GetPromoCodeOfferData(
+ /*origin=*/GURL("http://www.example.com")));
+
+ prefs::SetAutofillCreditCardEnabled(prefs_.get(), false);
+
+ // Should not return the offer as the autofill credit card pref is disabled.
+ EXPECT_EQ(0U, personal_data_
+ ->GetActiveAutofillPromoCodeOffersForOrigin(
+ GURL("http://www.example.com"))
+ .size());
+}
+
TEST_F(PersonalDataManagerTest, DefaultCountryCodeIsCached) {
// The return value should always be some country code, no matter what.
std::string default_country =
@@ -1986,6 +1816,7 @@ TEST_F(PersonalDataManagerTest, DefaultCountryCodeIsCached) {
// profiles.
prefs::SetAutofillProfileEnabled(prefs_.get(), false);
prefs::SetAutofillCreditCardEnabled(prefs_.get(), false);
+ prefs::SetAutofillIBANEnabled(prefs_.get(), false);
WaitForOnPersonalDataChanged();
EXPECT_EQ(default_country,
personal_data_->GetDefaultCountryCodeForNewAddress());
@@ -3196,8 +3027,8 @@ TEST_F(PersonalDataManagerTest,
ASSERT_EQ(0U, card_to_suggest.size());
}
-// Test that local profiles are not added if |kAutofillProfileEnabled| is set to
-// |false|.
+// Test that local credit cards are not added if |kAutofillCreditCardEnabled| is
+// set to |false|.
TEST_F(PersonalDataManagerTest,
GetCreditCardsToSuggest_NoCreditCardsAddedIfDisabled) {
// Disable Profile autofill.
@@ -3211,7 +3042,7 @@ TEST_F(PersonalDataManagerTest,
"1");
personal_data_->AddCreditCard(credit_card);
- // Expect no profile values or suggestions were added.
+ // Expect no credit card values or suggestions were added.
EXPECT_EQ(0U, personal_data_->GetCreditCards().size());
}
@@ -4054,1090 +3885,6 @@ TEST_F(PersonalDataManagerTest, MAYBE_MergeProfile_UsageStats) {
EXPECT_EQ(kMuchLaterTime, profiles[0].modification_date());
}
-// Tests that DedupeProfiles sets the correct profile guids to
-// delete after merging similar profiles.
-TEST_F(PersonalDataManagerTest, DedupeProfiles_ProfilesToDelete) {
- // Create the profile for which to find duplicates. It has the highest
- // ranking score.
- AutofillProfile* profile1 =
- new AutofillProfile(base::GenerateGUID(), test::kEmptyOrigin);
- test::SetProfileInfo(profile1, "Homer", "Jay", "Simpson",
- "homer.simpson@abc.com", "", "742. Evergreen Terrace",
- "", "Springfield", "IL", "91601", "US", "12345678910");
- profile1->set_use_count(9);
-
- // Create a different profile that should not be deduped (different address).
- AutofillProfile* profile2 =
- new AutofillProfile(base::GenerateGUID(), test::kEmptyOrigin);
- test::SetProfileInfo(profile2, "Homer", "Jay", "Simpson",
- "homer.simpson@abc.com", "Fox", "1234 Other Street", "",
- "Springfield", "IL", "91601", "US", "12345678910");
- profile2->set_use_count(7);
-
- // Create a profile similar to profile1 which should be deduped.
- AutofillProfile* profile3 =
- new AutofillProfile(base::GenerateGUID(), test::kEmptyOrigin);
- test::SetProfileInfo(profile3, "Homer", "Jay", "Simpson",
- "homer.simpson@abc.com", "", "742 Evergreen Terrace", "",
- "Springfield", "IL", "91601", "US", "12345678910");
- profile3->set_use_count(5);
-
- // Create another different profile that should not be deduped (different
- // name).
- AutofillProfile* profile4 =
- new AutofillProfile(base::GenerateGUID(), test::kEmptyOrigin);
- test::SetProfileInfo(profile4, "Marjorie", "Jacqueline", "Simpson",
- "homer.simpson@abc.com", "Fox", "742 Evergreen Terrace",
- "", "Springfield", "IL", "91601", "US", "12345678910");
- profile4->set_use_count(3);
-
- // Create another profile similar to profile1. Since that one has the lowest
- // ranking score, the result of the merge should be in this profile at the end
- // of the test.
- AutofillProfile* profile5 =
- new AutofillProfile(base::GenerateGUID(), test::kEmptyOrigin);
- test::SetProfileInfo(profile5, "Homer", "Jay", "Simpson",
- "homer.simpson@abc.com", "Fox", "742 Evergreen Terrace.",
- "", "Springfield", "IL", "91601", "US", "12345678910");
- profile5->set_use_count(1);
-
- // Add the profiles.
- std::vector<std::unique_ptr<AutofillProfile>> existing_profiles;
- existing_profiles.push_back(std::unique_ptr<AutofillProfile>(profile1));
- existing_profiles.push_back(std::unique_ptr<AutofillProfile>(profile2));
- existing_profiles.push_back(std::unique_ptr<AutofillProfile>(profile3));
- existing_profiles.push_back(std::unique_ptr<AutofillProfile>(profile4));
- existing_profiles.push_back(std::unique_ptr<AutofillProfile>(profile5));
-
- base::HistogramTester histogram_tester;
- std::unordered_map<std::string, std::string> guids_merge_map;
- std::unordered_set<std::string> profiles_to_delete;
- personal_data_->personal_data_manager_cleaner_for_testing()
- ->DedupeProfilesForTesting(&existing_profiles, &profiles_to_delete,
- &guids_merge_map);
- // 5 profiles were considered for dedupe.
- histogram_tester.ExpectUniqueSample(
- "Autofill.NumberOfProfilesConsideredForDedupe", 5, 1);
- // 2 profiles were removed (profiles 1 and 3).
- histogram_tester.ExpectUniqueSample(
- "Autofill.NumberOfProfilesRemovedDuringDedupe", 2, 1);
-
- // Profile1 should be deleted because it was sent as the profile to merge and
- // thus was merged into profile3 and then into profile5.
- EXPECT_TRUE(profiles_to_delete.count(profile1->guid()));
-
- // Profile3 should be deleted because profile1 was merged into it and the
- // resulting profile was then merged into profile5.
- EXPECT_TRUE(profiles_to_delete.count(profile3->guid()));
-
- // Only these two profiles should be deleted.
- EXPECT_EQ(2U, profiles_to_delete.size());
-
- // All profiles should still be present in |existing_profiles|.
- EXPECT_EQ(5U, existing_profiles.size());
-}
-
-// Tests that DedupeProfiles sets the correct merge mapping for billing address
-// id references.
-TEST_F(PersonalDataManagerTest, DedupeProfiles_GuidsMergeMap) {
- // Create the profile for which to find duplicates. It has the highest
- // ranking score.
- AutofillProfile* profile1 =
- new AutofillProfile(base::GenerateGUID(), test::kEmptyOrigin);
- test::SetProfileInfo(profile1, "Homer", "Jay", "Simpson",
- "homer.simpson@abc.com", "", "742. Evergreen Terrace",
- "", "Springfield", "IL", "91601", "US", "12345678910");
- profile1->set_use_count(9);
-
- // Create a different profile that should not be deduped (different address).
- AutofillProfile* profile2 =
- new AutofillProfile(base::GenerateGUID(), test::kEmptyOrigin);
- test::SetProfileInfo(profile2, "Homer", "Jay", "Simpson",
- "homer.simpson@abc.com", "Fox", "1234 Other Street", "",
- "Springfield", "IL", "91601", "US", "12345678910");
- profile2->set_use_count(7);
-
- // Create a profile similar to profile1 which should be deduped.
- AutofillProfile* profile3 =
- new AutofillProfile(base::GenerateGUID(), test::kEmptyOrigin);
- test::SetProfileInfo(profile3, "Homer", "Jay", "Simpson",
- "homer.simpson@abc.com", "", "742 Evergreen Terrace", "",
- "Springfield", "IL", "91601", "US", "12345678910");
- profile3->set_use_count(5);
-
- // Create another different profile that should not be deduped (different
- // name).
- AutofillProfile* profile4 =
- new AutofillProfile(base::GenerateGUID(), test::kEmptyOrigin);
- test::SetProfileInfo(profile4, "Marjorie", "Jacqueline", "Simpson",
- "homer.simpson@abc.com", "Fox", "742 Evergreen Terrace",
- "", "Springfield", "IL", "91601", "US", "12345678910");
- profile4->set_use_count(3);
-
- // Create another profile similar to profile1. Since that one has the lowest
- // ranking score, the result of the merge should be in this profile at the end
- // of the test.
- AutofillProfile* profile5 =
- new AutofillProfile(base::GenerateGUID(), test::kEmptyOrigin);
- test::SetProfileInfo(profile5, "Homer", "Jay", "Simpson",
- "homer.simpson@abc.com", "Fox", "742 Evergreen Terrace.",
- "", "Springfield", "IL", "91601", "US", "12345678910");
- profile5->set_use_count(1);
-
- // Add the profiles.
- std::vector<std::unique_ptr<AutofillProfile>> existing_profiles;
- existing_profiles.push_back(std::unique_ptr<AutofillProfile>(profile1));
- existing_profiles.push_back(std::unique_ptr<AutofillProfile>(profile2));
- existing_profiles.push_back(std::unique_ptr<AutofillProfile>(profile3));
- existing_profiles.push_back(std::unique_ptr<AutofillProfile>(profile4));
- existing_profiles.push_back(std::unique_ptr<AutofillProfile>(profile5));
-
- std::unordered_map<std::string, std::string> guids_merge_map;
- std::unordered_set<std::string> profiles_to_delete;
-
- personal_data_->personal_data_manager_cleaner_for_testing()
- ->DedupeProfilesForTesting(&existing_profiles, &profiles_to_delete,
- &guids_merge_map);
-
- // The two profile merges should be recorded in the map.
- EXPECT_EQ(2U, guids_merge_map.size());
-
- // Profile 1 was merged into profile 3.
- ASSERT_TRUE(guids_merge_map.count(profile1->guid()));
- EXPECT_TRUE(guids_merge_map.at(profile1->guid()) == profile3->guid());
-
- // Profile 3 was merged into profile 5.
- ASSERT_TRUE(guids_merge_map.count(profile3->guid()));
- EXPECT_TRUE(guids_merge_map.at(profile3->guid()) == profile5->guid());
-}
-
-// Tests that UpdateCardsBillingAddressReference sets the correct billing
-// address id as specified in the map.
-TEST_F(PersonalDataManagerTest, UpdateCardsBillingAddressReference) {
- /* The merges will be as follow:
-
- A -> B F (not merged)
- \
- -> E
- /
- C -> D
- */
-
- std::unordered_map<std::string, std::string> guids_merge_map;
- guids_merge_map.insert(std::pair<std::string, std::string>("A", "B"));
- guids_merge_map.insert(std::pair<std::string, std::string>("C", "D"));
- guids_merge_map.insert(std::pair<std::string, std::string>("B", "E"));
- guids_merge_map.insert(std::pair<std::string, std::string>("D", "E"));
-
- // Create a credit card without a billing address id
- CreditCard* credit_card0 =
- new CreditCard(base::GenerateGUID(), test::kEmptyOrigin);
-
- // Create cards that use A, D, E and F as their billing address id.
- CreditCard* credit_card1 =
- new CreditCard(base::GenerateGUID(), test::kEmptyOrigin);
- credit_card1->set_billing_address_id("A");
- CreditCard* credit_card2 =
- new CreditCard(base::GenerateGUID(), test::kEmptyOrigin);
- credit_card2->set_billing_address_id("D");
- CreditCard* credit_card3 =
- new CreditCard(base::GenerateGUID(), test::kEmptyOrigin);
- credit_card3->set_billing_address_id("E");
- CreditCard* credit_card4 =
- new CreditCard(base::GenerateGUID(), test::kEmptyOrigin);
- credit_card4->set_billing_address_id("F");
-
- // Add the credit cards to the database.
- personal_data_->local_credit_cards_.push_back(
- std::unique_ptr<CreditCard>(credit_card0));
- personal_data_->local_credit_cards_.push_back(
- std::unique_ptr<CreditCard>(credit_card1));
- personal_data_->server_credit_cards_.push_back(
- std::unique_ptr<CreditCard>(credit_card2));
- personal_data_->local_credit_cards_.push_back(
- std::unique_ptr<CreditCard>(credit_card3));
- personal_data_->server_credit_cards_.push_back(
- std::unique_ptr<CreditCard>(credit_card4));
-
- personal_data_->personal_data_manager_cleaner_for_testing()
- ->UpdateCardsBillingAddressReferenceForTesting(guids_merge_map);
-
- // The first card's billing address should now be E.
- EXPECT_EQ("E", credit_card1->billing_address_id());
- // The second card's billing address should now be E.
- EXPECT_EQ("E", credit_card2->billing_address_id());
- // The third card's billing address should still be E.
- EXPECT_EQ("E", credit_card3->billing_address_id());
- // The fourth card's billing address should still be F.
- EXPECT_EQ("F", credit_card4->billing_address_id());
-}
-
-// Tests that ApplyDedupingRoutine updates the credit cards' billing address id
-// based on the deduped profiles.
-TEST_F(PersonalDataManagerTest,
- ApplyDedupingRoutine_CardsBillingAddressIdUpdated) {
- base::test::ScopedFeatureList feature;
- feature.InitAndEnableFeature(features::kAutofillEnableProfileDeduplication);
-
- // A set of 6 profiles will be created. They should merge in this way:
- // 1 -> 2 -> 3
- // 4 -> 5
- // 6
- // Set their frencency score so that profile 3 has a higher score than 5, and
- // 5 has a higher score than 6. This will ensure a deterministic order when
- // verifying results.
-
- // Create a set of 3 profiles to be merged together.
- // Create a profile with a higher ranking score.
- AutofillProfile profile1(base::GenerateGUID(), test::kEmptyOrigin);
- test::SetProfileInfo(&profile1, "Homer", "J", "Simpson",
- "homer.simpson@abc.com", "", "742. Evergreen Terrace",
- "", "Springfield", "IL", "91601", "US", "");
- profile1.set_use_count(12);
- profile1.set_use_date(AutofillClock::Now() - base::Days(1));
-
- // Create a profile with a medium ranking score.
- AutofillProfile profile2(base::GenerateGUID(), test::kEmptyOrigin);
- test::SetProfileInfo(&profile2, "Homer", "Jay", "Simpson",
- "homer.simpson@abc.com", "", "742 Evergreen Terrace", "",
- "Springfield", "IL", "91601", "", "12345678910");
- profile2.set_use_count(5);
- profile2.set_use_date(AutofillClock::Now() - base::Days(3));
-
- // Create a profile with a lower ranking score.
- AutofillProfile profile3(base::GenerateGUID(), test::kEmptyOrigin);
- test::SetProfileInfo(&profile3, "Homer", "J", "Simpson",
- "homer.simpson@abc.com", "Fox", "742 Evergreen Terrace.",
- "", "Springfield", "IL", "91601", "", "");
- profile3.set_use_count(3);
- profile3.set_use_date(AutofillClock::Now() - base::Days(5));
-
- // Create a set of two profiles to be merged together.
- // Create a profile with a higher ranking score.
- AutofillProfile profile4(base::GenerateGUID(), test::kEmptyOrigin);
- test::SetProfileInfo(&profile4, "Marge", "B", "Simpson",
- "marge.simpson@abc.com", "", "742. Evergreen Terrace",
- "", "Springfield", "IL", "91601", "US", "");
- profile4.set_use_count(11);
- profile4.set_use_date(AutofillClock::Now() - base::Days(1));
-
- // Create a profile with a lower ranking score.
- AutofillProfile profile5(base::GenerateGUID(), test::kEmptyOrigin);
- test::SetProfileInfo(&profile5, "Marge", "B", "Simpson",
- "marge.simpson@abc.com", "Fox", "742 Evergreen Terrace.",
- "", "Springfield", "IL", "91601", "", "");
- profile5.set_use_count(5);
- profile5.set_use_date(AutofillClock::Now() - base::Days(3));
-
- // Create a unique profile.
- AutofillProfile profile6(base::GenerateGUID(), test::kEmptyOrigin);
- test::SetProfileInfo(&profile6, "Bart", "J", "Simpson",
- "bart.simpson@abc.com", "Fox", "742 Evergreen Terrace.",
- "", "Springfield", "IL", "91601", "", "");
- profile6.set_use_count(10);
- profile6.set_use_date(AutofillClock::Now() - base::Days(1));
-
- // Add three credit cards. Give them a ranking score so that they are
- // suggested in order (1, 2, 3). This will ensure a deterministic order for
- // verifying results.
- CreditCard credit_card1(base::GenerateGUID(), test::kEmptyOrigin);
- test::SetCreditCardInfo(&credit_card1, "Clyde Barrow",
- "378282246310005" /* American Express */, "04",
- "2999", "1");
- credit_card1.set_use_count(10);
-
- CreditCard credit_card2(base::GenerateGUID(), test::kEmptyOrigin);
- test::SetCreditCardInfo(&credit_card2, "John Dillinger",
- "4234567890123456" /* Visa */, "01", "2999", "1");
- credit_card2.set_use_count(5);
-
- CreditCard credit_card3(base::GenerateGUID(), test::kEmptyOrigin);
- test::SetCreditCardInfo(&credit_card3, "Bonnie Parker",
- "5105105105105100" /* Mastercard */, "12", "2999",
- "1");
- credit_card3.set_use_count(1);
-
- // Associate the first card with profile1.
- credit_card1.set_billing_address_id(profile1.guid());
- // Associate the second card with profile4.
- credit_card2.set_billing_address_id(profile4.guid());
- // Associate the third card with profile6.
- credit_card3.set_billing_address_id(profile6.guid());
-
- AddProfileToPersonalDataManager(profile1);
- AddProfileToPersonalDataManager(profile2);
- AddProfileToPersonalDataManager(profile3);
- AddProfileToPersonalDataManager(profile4);
- AddProfileToPersonalDataManager(profile5);
- AddProfileToPersonalDataManager(profile6);
- personal_data_->AddCreditCard(credit_card1);
- personal_data_->AddCreditCard(credit_card2);
- personal_data_->AddCreditCard(credit_card3);
-
- WaitForOnPersonalDataChanged();
-
- // Make sure the 6 profiles and 3 credit cards were saved.
- EXPECT_EQ(6U, personal_data_->GetProfiles().size());
- EXPECT_EQ(3U, personal_data_->GetCreditCards().size());
-
- EXPECT_TRUE(personal_data_->personal_data_manager_cleaner_for_testing()
- ->ApplyDedupingRoutineForTesting());
- WaitForOnPersonalDataChanged();
-
- // Get the profiles and cards sorted by their ranking score to have a
- // deterministic order.
- std::vector<AutofillProfile*> profiles =
- personal_data_->GetProfilesToSuggest();
- std::vector<CreditCard*> credit_cards =
- personal_data_->GetCreditCardsToSuggest(/*include_server_cards=*/true);
-
- // |profile1| should have been merged into |profile2| which should then have
- // been merged into |profile3|. |profile4| should have been merged into
- // |profile5| and |profile6| should not have merged. Therefore there should be
- // 3 profile left.
- ASSERT_EQ(3U, profiles.size());
-
- // Make sure the remaining profiles are the expected ones.
- EXPECT_EQ(profile3.guid(), profiles[0]->guid());
- EXPECT_EQ(profile5.guid(), profiles[1]->guid());
- EXPECT_EQ(profile6.guid(), profiles[2]->guid());
-
- // |credit_card1|'s billing address should now be profile 3.
- EXPECT_EQ(profile3.guid(), credit_cards[0]->billing_address_id());
-
- // |credit_card2|'s billing address should now be profile 5.
- EXPECT_EQ(profile5.guid(), credit_cards[1]->billing_address_id());
-
- // |credit_card3|'s billing address should still be profile 6.
- EXPECT_EQ(profile6.guid(), credit_cards[2]->billing_address_id());
-}
-
-// Tests that ApplyDedupingRoutine merges the profile values correctly, i.e.
-// never lose information and keep the syntax of the profile with the higher
-// ranking score.
-TEST_F(PersonalDataManagerTest, ApplyDedupingRoutine_MergedProfileValues) {
- base::test::ScopedFeatureList feature;
- feature.InitAndEnableFeature(features::kAutofillEnableProfileDeduplication);
-
- // Create a profile with a higher ranking score.
- AutofillProfile profile1(base::GenerateGUID(), test::kEmptyOrigin);
- test::SetProfileInfo(&profile1, "Homer", "J", "Simpson",
- "homer.simpson@abc.com", "", "742. Evergreen Terrace",
- "", "Springfield", "IL", "91601", "US", "");
- profile1.set_use_count(10);
- profile1.set_use_date(AutofillClock::Now() - base::Days(1));
-
- // Create a profile with a medium ranking score.
- AutofillProfile profile2(base::GenerateGUID(), test::kEmptyOrigin);
- test::SetProfileInfo(&profile2, "Homer", "Jay", "Simpson",
- "homer.simpson@abc.com", "", "742 Evergreen Terrace", "",
- "Springfield", "IL", "91601", "", "12345678910");
- profile2.set_use_count(5);
- profile2.set_use_date(AutofillClock::Now() - base::Days(3));
-
- // Create a profile with a lower ranking score.
- AutofillProfile profile3(base::GenerateGUID(), test::kEmptyOrigin);
- test::SetProfileInfo(&profile3, "Homer", "J", "Simpson",
- "homer.simpson@abc.com", "Fox", "742 Evergreen Terrace.",
- "", "Springfield", "IL", "91601", "", "");
- profile3.set_use_count(3);
- profile3.set_use_date(AutofillClock::Now() - base::Days(5));
-
- AddProfileToPersonalDataManager(profile1);
- AddProfileToPersonalDataManager(profile2);
- AddProfileToPersonalDataManager(profile3);
-
- // Make sure the 3 profiles were saved;
- EXPECT_EQ(3U, personal_data_->GetProfiles().size());
-
- base::HistogramTester histogram_tester;
-
- EXPECT_TRUE(personal_data_->personal_data_manager_cleaner_for_testing()
- ->ApplyDedupingRoutineForTesting());
- WaitForOnPersonalDataChanged();
-
- std::vector<AutofillProfile*> profiles = personal_data_->GetProfiles();
-
- // |profile1| should have been merged into |profile2| which should then have
- // been merged into |profile3|. Therefore there should only be 1 saved
- // profile.
- ASSERT_EQ(1U, profiles.size());
- // 3 profiles were considered for dedupe.
- histogram_tester.ExpectUniqueSample(
- "Autofill.NumberOfProfilesConsideredForDedupe", 3, 1);
- // 2 profiles were removed (profiles 1 and 2).
- histogram_tester.ExpectUniqueSample(
- "Autofill.NumberOfProfilesRemovedDuringDedupe", 2, 1);
-
- // Since profiles with higher ranking scores are merged into profiles with
- // lower ranking scores, the result of the merge should be contained in
- // profile3 since it had a lower ranking score compared to profile1.
- EXPECT_EQ(profile3.guid(), profiles[0]->guid());
- // The address syntax that results from the merge should be the one from the
- // imported profile (highest ranking).
- EXPECT_EQ(u"742. Evergreen Terrace",
- profiles[0]->GetRawInfo(ADDRESS_HOME_LINE1));
- // The middle name should be full, even if the profile with the higher
- // ranking only had an initial (no loss of information).
- EXPECT_EQ(u"Jay", profiles[0]->GetRawInfo(NAME_MIDDLE));
- // The specified phone number from profile1 should be kept (no loss of
- // information).
- EXPECT_EQ(u"12345678910", profiles[0]->GetRawInfo(PHONE_HOME_WHOLE_NUMBER));
- // The specified company name from profile2 should be kept (no loss of
- // information).
- EXPECT_EQ(u"Fox", profiles[0]->GetRawInfo(COMPANY_NAME));
- // The specified country from the imported profile shoudl be kept (no loss of
- // information).
- EXPECT_EQ(u"US", profiles[0]->GetRawInfo(ADDRESS_HOME_COUNTRY));
- // The use count that results from the merge should be the max of all the
- // profiles use counts.
- EXPECT_EQ(10U, profiles[0]->use_count());
- // The use date that results from the merge should be the one from the
- // profile1 since it was the most recently used profile.
- EXPECT_LT(profile1.use_date() - base::Seconds(10), profiles[0]->use_date());
-}
-
-// Tests that ApplyDedupingRoutine only keeps the verified profile with its
-// original data when deduping with similar profiles, even if it has a higher
-// ranking score.
-TEST_F(PersonalDataManagerTest, ApplyDedupingRoutine_VerifiedProfileFirst) {
- base::test::ScopedFeatureList feature;
- feature.InitAndEnableFeature(features::kAutofillEnableProfileDeduplication);
-
- // Create a verified profile with a higher ranking score.
- AutofillProfile profile1(base::GenerateGUID(), kSettingsOrigin);
- test::SetProfileInfo(
- &profile1, "Homer", "Jay", "Simpson", "homer.simpson@abc.com", "",
- "742 Evergreen Terrace", "", "Springfield", "IL", "91601", "",
- "12345678910", /*finalize=*/true,
- /*status=*/structured_address::VerificationStatus::kUserVerified);
- profile1.set_use_count(7);
- profile1.set_use_date(kMuchLaterTime);
-
- // Create a similar non verified profile with a medium ranking score.
- AutofillProfile profile2(base::GenerateGUID(), test::kEmptyOrigin);
- test::SetProfileInfo(&profile2, "Homer", "J", "Simpson",
- "homer.simpson@abc.com", "", "742. Evergreen Terrace",
- "", "Springfield", "IL", "91601", "US", "");
- profile2.set_use_count(5);
- profile2.set_use_date(kSomeLaterTime);
-
- // Create a similar non verified profile with a lower ranking score.
- AutofillProfile profile3(base::GenerateGUID(), test::kEmptyOrigin);
- test::SetProfileInfo(&profile3, "Homer", "J", "Simpson",
- "homer.simpson@abc.com", "Fox", "742 Evergreen Terrace.",
- "", "Springfield", "IL", "91601", "", "");
- profile3.set_use_count(3);
- profile3.set_use_date(kArbitraryTime);
-
- AddProfileToPersonalDataManager(profile1);
- AddProfileToPersonalDataManager(profile2);
- AddProfileToPersonalDataManager(profile3);
-
- // Make sure the 3 profiles were saved.
- EXPECT_EQ(3U, personal_data_->GetProfiles().size());
-
- base::HistogramTester histogram_tester;
-
- EXPECT_TRUE(personal_data_->personal_data_manager_cleaner_for_testing()
- ->ApplyDedupingRoutineForTesting());
- WaitForOnPersonalDataChanged();
-
- std::vector<AutofillProfile*> profiles = personal_data_->GetProfiles();
-
- // |profile2| should have merged with |profile3|. |profile3|
- // should then have been discarded because it is similar to the verified
- // |profile1|.
- ASSERT_EQ(1U, profiles.size());
- // 3 profiles were considered for dedupe.
- histogram_tester.ExpectUniqueSample(
- "Autofill.NumberOfProfilesConsideredForDedupe", 3, 1);
- // 2 profile were removed (profiles 2 and 3).
- histogram_tester.ExpectUniqueSample(
- "Autofill.NumberOfProfilesRemovedDuringDedupe", 2, 1);
-
- // Although the profile was verified, the structure of the street address
- // still evolved with future observations. In this case, the "." was added
- // from a later observation.
- profile1.SetRawInfoWithVerificationStatus(
- ADDRESS_HOME_STREET_NAME, u"Evergreen Terrace",
- structured_address::VerificationStatus::kParsed);
- //
- // Only the verified |profile1| with its original data should have been kept.
- EXPECT_EQ(profile1.guid(), profiles[0]->guid());
- EXPECT_TRUE(profile1 == *profiles[0]);
- EXPECT_EQ(profile1.use_count(), profiles[0]->use_count());
- EXPECT_EQ(profile1.use_date(), profiles[0]->use_date());
-}
-
-// Tests that ApplyDedupingRoutine only keeps the verified profile with its
-// original data when deduping with similar profiles, even if it has a lower
-// ranking score.
-TEST_F(PersonalDataManagerTest, ApplyDedupingRoutine_VerifiedProfileLast) {
- base::test::ScopedFeatureList feature;
- feature.InitAndEnableFeature(features::kAutofillEnableProfileDeduplication);
-
- // Create a profile to dedupe with a higher ranking score.
- AutofillProfile profile1(base::GenerateGUID(), test::kEmptyOrigin);
- test::SetProfileInfo(&profile1, "Homer", "J", "Simpson",
- "homer.simpson@abc.com", "", "742. Evergreen Terrace",
- "", "Springfield", "IL", "91601", "US", "");
- profile1.set_use_count(5);
- profile1.set_use_date(kMuchLaterTime);
-
- // Create a similar non verified profile with a medium ranking score.
- AutofillProfile profile2(base::GenerateGUID(), test::kEmptyOrigin);
- test::SetProfileInfo(&profile2, "Homer", "J", "Simpson",
- "homer.simpson@abc.com", "Fox", "742 Evergreen Terrace.",
- "", "Springfield", "IL", "91601", "", "");
- profile2.set_use_count(5);
- profile2.set_use_date(kSomeLaterTime);
-
- // Create a similar verified profile with a lower ranking score.
- AutofillProfile profile3(base::GenerateGUID(), kSettingsOrigin);
- test::SetProfileInfo(
- &profile3, "Homer", "Jay", "Simpson", "homer.simpson@abc.com", "",
- "742 Evergreen Terrace", "", "Springfield", "IL", "91601", "",
- "12345678910", /*finalize=*/true,
- /*status=*/structured_address::VerificationStatus::kUserVerified);
- profile3.set_use_count(3);
- profile3.set_use_date(kArbitraryTime);
-
- AddProfileToPersonalDataManager(profile1);
- AddProfileToPersonalDataManager(profile2);
- AddProfileToPersonalDataManager(profile3);
-
- // Make sure the 3 profiles were saved.
- EXPECT_EQ(3U, personal_data_->GetProfiles().size());
-
- base::HistogramTester histogram_tester;
-
- EXPECT_TRUE(personal_data_->personal_data_manager_cleaner_for_testing()
- ->ApplyDedupingRoutineForTesting());
- WaitForOnPersonalDataChanged();
-
- std::vector<AutofillProfile*> profiles = personal_data_->GetProfiles();
-
- // |profile1| should have merged with |profile2|. |profile2|
- // should then have been discarded because it is similar to the verified
- // |profile3|.
- ASSERT_EQ(1U, profiles.size());
- // 3 profiles were considered for dedupe.
- histogram_tester.ExpectUniqueSample(
- "Autofill.NumberOfProfilesConsideredForDedupe", 3, 1);
- // 2 profile were removed (profiles 1 and 2).
- histogram_tester.ExpectUniqueSample(
- "Autofill.NumberOfProfilesRemovedDuringDedupe", 2, 1);
-
- // Only the verified |profile3| with it's original data should have been kept.
- EXPECT_EQ(profile3.guid(), profiles[0]->guid());
- EXPECT_TRUE(profile3 == *profiles[0]);
- EXPECT_EQ(profile3.use_count(), profiles[0]->use_count());
- EXPECT_EQ(profile3.use_date(), profiles[0]->use_date());
-}
-
-// Tests that ApplyDedupingRoutine does not merge unverified data into
-// a verified profile. Also tests that two verified profiles don't get merged.
-TEST_F(PersonalDataManagerTest, ApplyDedupingRoutine_MultipleVerifiedProfiles) {
- base::test::ScopedFeatureList feature;
- feature.InitAndEnableFeature(features::kAutofillEnableProfileDeduplication);
-
- // Create a profile to dedupe with a higher ranking score.
- AutofillProfile profile1(base::GenerateGUID(), test::kEmptyOrigin);
- test::SetProfileInfo(&profile1, "Homer", "J", "Simpson",
- "homer.simpson@abc.com", "", "742. Evergreen Terrace",
- "", "Springfield", "IL", "91601", "US", "");
- profile1.set_use_count(5);
- profile1.set_use_date(kMuchLaterTime);
-
- // Create a similar verified profile with a medium ranking score.
- AutofillProfile profile2(base::GenerateGUID(), kSettingsOrigin);
- test::SetProfileInfo(
- &profile2, "Homer", "J", "Simpson", "homer.simpson@abc.com", "Fox",
- "742 Evergreen Terrace.", "", "Springfield", "IL", "91601", "", "",
- /*finalize=*/true,
- /*status=*/structured_address::VerificationStatus::kUserVerified);
-
- profile2.set_use_count(5);
- profile2.set_use_date(kSomeLaterTime);
-
- // Create a similar verified profile with a lower ranking score.
- AutofillProfile profile3(base::GenerateGUID(), kSettingsOrigin);
- test::SetProfileInfo(
- &profile3, "Homer", "Jay", "Simpson", "homer.simpson@abc.com", "",
- "742 Evergreen Terrace", "", "Springfield", "IL", "91601", "",
- "12345678910", /*finalize=*/true,
- /*status*/ structured_address::VerificationStatus::kUserVerified);
- profile3.set_use_count(3);
- profile3.set_use_date(kArbitraryTime);
-
- AddProfileToPersonalDataManager(profile1);
- AddProfileToPersonalDataManager(profile2);
- AddProfileToPersonalDataManager(profile3);
-
- // Make sure the 3 profiles were saved.
- EXPECT_EQ(3U, personal_data_->GetProfiles().size());
-
- base::HistogramTester histogram_tester;
-
- EXPECT_TRUE(personal_data_->personal_data_manager_cleaner_for_testing()
- ->ApplyDedupingRoutineForTesting());
- WaitForOnPersonalDataChanged();
-
- // Get the profiles, sorted by ranking to have a deterministic order.
- std::vector<AutofillProfile*> profiles =
- personal_data_->GetProfilesToSuggest();
-
- // Although the profile was verified, the structure of the street address
- // still evolved with future observations. In this case, the "." was removed
- // from a later observation.
- profile2.SetRawInfoWithVerificationStatus(
- ADDRESS_HOME_STREET_NAME, u"Evergreen Terrace",
- structured_address::VerificationStatus::kParsed);
-
- // |profile1| should have been discarded because the saved profile with the
- // highest ranking score is verified (|profile2|). Therefore, |profile1|'s
- // data should not have been merged with |profile2|'s data. Then |profile2|
- // should have been compared to |profile3| but they should not have merged
- // because both profiles are verified.
- ASSERT_EQ(2U, profiles.size());
- // 3 profiles were considered for dedupe.
- histogram_tester.ExpectUniqueSample(
- "Autofill.NumberOfProfilesConsideredForDedupe", 3, 1);
- // 1 profile was removed (|profile1|).
- histogram_tester.ExpectUniqueSample(
- "Autofill.NumberOfProfilesRemovedDuringDedupe", 1, 1);
-
- EXPECT_EQ(profile2.guid(), profiles[0]->guid());
- EXPECT_EQ(profile3.guid(), profiles[1]->guid());
- // The profiles should have kept their original data.
- EXPECT_TRUE(profile2 == *profiles[0]);
- EXPECT_TRUE(profile3 == *profiles[1]);
- EXPECT_EQ(profile2.use_count(), profiles[0]->use_count());
- EXPECT_EQ(profile3.use_count(), profiles[1]->use_count());
- EXPECT_EQ(profile2.use_date(), profiles[0]->use_date());
- EXPECT_EQ(profile3.use_date(), profiles[1]->use_date());
-}
-
-// Tests that ApplyDedupingRoutine works as expected in a realistic scenario.
-// Tests that it merges the diffent set of similar profiles independently and
-// that the resulting profiles have the right values, has no effect on the other
-// profiles and that the data of verified profiles is not modified.
-TEST_F(PersonalDataManagerTest, ApplyDedupingRoutine_MultipleDedupes) {
- base::test::ScopedFeatureList feature;
- feature.InitAndEnableFeature(features::kAutofillEnableProfileDeduplication);
-
- // Create a Homer home profile with a higher ranking score than other Homer
- // profiles.
- AutofillProfile Homer1(base::GenerateGUID(), test::kEmptyOrigin);
- test::SetProfileInfo(&Homer1, "Homer", "J", "Simpson",
- "homer.simpson@abc.com", "", "742. Evergreen Terrace",
- "", "Springfield", "IL", "91601", "US", "");
- Homer1.set_use_count(10);
- Homer1.set_use_date(AutofillClock::Now() - base::Days(1));
-
- // Create a Homer home profile with a medium ranking score compared to other
- // Homer profiles.
- AutofillProfile Homer2(base::GenerateGUID(), test::kEmptyOrigin);
- test::SetProfileInfo(&Homer2, "Homer", "Jay", "Simpson",
- "homer.simpson@abc.com", "", "742 Evergreen Terrace", "",
- "Springfield", "IL", "91601", "", "12345678910");
- Homer2.set_use_count(5);
- Homer2.set_use_date(AutofillClock::Now() - base::Days(3));
-
- // Create a Homer home profile with a lower ranking score than other Homer
- // profiles.
- AutofillProfile Homer3(base::GenerateGUID(), test::kEmptyOrigin);
- test::SetProfileInfo(&Homer3, "Homer", "J", "Simpson",
- "homer.simpson@abc.com", "Fox", "742 Evergreen Terrace.",
- "", "Springfield", "IL", "91601", "", "");
- Homer3.set_use_count(3);
- Homer3.set_use_date(AutofillClock::Now() - base::Days(5));
-
- // Create a Homer work profile (different address).
- AutofillProfile Homer4(base::GenerateGUID(), test::kEmptyOrigin);
- test::SetProfileInfo(&Homer4, "Homer", "J", "Simpson",
- "homer.simpson@abc.com", "Fox", "12 Nuclear Plant.", "",
- "Springfield", "IL", "91601", "US", "9876543");
- Homer4.set_use_count(3);
- Homer4.set_use_date(AutofillClock::Now() - base::Days(5));
-
- // Create a Marge profile with a lower ranking score that other Marge
- // profiles.
- AutofillProfile Marge1(base::GenerateGUID(), kSettingsOrigin);
- test::SetProfileInfo(&Marge1, "Marjorie", "J", "Simpson",
- "marge.simpson@abc.com", "", "742 Evergreen Terrace", "",
- "Springfield", "IL", "91601", "", "12345678910");
- Marge1.set_use_count(4);
- Marge1.set_use_date(AutofillClock::Now() - base::Days(3));
-
- // Create a verified Marge home profile with a lower ranking score that the
- // other Marge profile.
- AutofillProfile Marge2(base::GenerateGUID(), test::kEmptyOrigin);
- test::SetProfileInfo(&Marge2, "Marjorie", "Jacqueline", "Simpson",
- "marge.simpson@abc.com", "", "742 Evergreen Terrace", "",
- "Springfield", "IL", "91601", "", "12345678910");
- Marge2.set_use_count(2);
- Marge2.set_use_date(AutofillClock::Now() - base::Days(3));
-
- // Create a Barney profile (guest user).
- AutofillProfile Barney(base::GenerateGUID(), test::kEmptyOrigin);
- test::SetProfileInfo(&Barney, "Barney", "", "Gumble", "barney.gumble@abc.com",
- "ABC", "123 Other Street", "", "Springfield", "IL",
- "91601", "", "");
- Barney.set_use_count(1);
- Barney.set_use_date(AutofillClock::Now() - base::Days(180));
- Barney.FinalizeAfterImport();
-
- AddProfileToPersonalDataManager(Homer1);
- AddProfileToPersonalDataManager(Homer2);
- AddProfileToPersonalDataManager(Homer3);
- AddProfileToPersonalDataManager(Homer4);
- AddProfileToPersonalDataManager(Marge1);
- AddProfileToPersonalDataManager(Marge2);
- AddProfileToPersonalDataManager(Barney);
-
- // Make sure the 7 profiles were saved;
- EXPECT_EQ(7U, personal_data_->GetProfiles().size());
-
- base::HistogramTester histogram_tester;
-
- // |Homer1| should get merged into |Homer2| which should then be merged into
- // |Homer3|. |Marge2| should be discarded in favor of |Marge1| which is
- // verified. |Homer4| and |Barney| should not be deduped at all.
- EXPECT_TRUE(personal_data_->personal_data_manager_cleaner_for_testing()
- ->ApplyDedupingRoutineForTesting());
- WaitForOnPersonalDataChanged();
-
- // Get the profiles, sorted by ranking score to have a deterministic order.
- std::vector<AutofillProfile*> profiles =
- personal_data_->GetProfilesToSuggest();
-
- // The 2 duplicates Homer home profiles with the higher ranking score and the
- // unverified Marge profile should have been deduped.
- ASSERT_EQ(4U, profiles.size());
- // 7 profiles were considered for dedupe.
- histogram_tester.ExpectUniqueSample(
- "Autofill.NumberOfProfilesConsideredForDedupe", 7, 1);
- // 3 profile were removed (|Homer1|, |Homer2| and |Marge2|).
- histogram_tester.ExpectUniqueSample(
- "Autofill.NumberOfProfilesRemovedDuringDedupe", 3, 1);
-
- // The remaining profiles should be |Homer3|, |Marge1|, |Homer4| and |Barney|
- // in this order of ranking score.
- EXPECT_EQ(Homer3.guid(), profiles[0]->guid());
- EXPECT_EQ(Marge1.guid(), profiles[1]->guid());
- EXPECT_EQ(Homer4.guid(), profiles[2]->guid());
- EXPECT_EQ(Barney.guid(), profiles[3]->guid());
-
- // |Homer3|'s data:
- // The address should be saved with the syntax of |Homer1| since it has the
- // highest ranking score.
- EXPECT_EQ(u"742. Evergreen Terrace",
- profiles[0]->GetRawInfo(ADDRESS_HOME_LINE1));
- // The middle name should be the full version found in |Homer2|,
- EXPECT_EQ(u"Jay", profiles[0]->GetRawInfo(NAME_MIDDLE));
- // The phone number from |Homer2| should be kept (no loss of information).
- EXPECT_EQ(u"12345678910", profiles[0]->GetRawInfo(PHONE_HOME_WHOLE_NUMBER));
- // The company name from |Homer3| should be kept (no loss of information).
- EXPECT_EQ(u"Fox", profiles[0]->GetRawInfo(COMPANY_NAME));
- // The country from |Homer1| profile should be kept (no loss of information).
- EXPECT_EQ(u"US", profiles[0]->GetRawInfo(ADDRESS_HOME_COUNTRY));
- // The use count that results from the merge should be the max of Homer 1, 2
- // and 3's respective use counts.
- EXPECT_EQ(10U, profiles[0]->use_count());
- // The use date that results from the merge should be the one from the
- // |Homer1| since it was the most recently used profile.
- EXPECT_LT(Homer1.use_date() - base::Seconds(5), profiles[0]->use_date());
- EXPECT_GT(Homer1.use_date() + base::Seconds(5), profiles[0]->use_date());
-
- // The other profiles should not have been modified.
- EXPECT_TRUE(Marge1 == *profiles[1]);
- EXPECT_TRUE(Homer4 == *profiles[2]);
- EXPECT_TRUE(Barney == *profiles[3]);
-}
-
-TEST_F(PersonalDataManagerTest, ApplyDedupingRoutine_NopIfZeroProfiles) {
- base::test::ScopedFeatureList feature;
- feature.InitAndEnableFeature(features::kAutofillEnableProfileDeduplication);
- EXPECT_TRUE(personal_data_->GetProfiles().empty());
- EXPECT_FALSE(personal_data_->personal_data_manager_cleaner_for_testing()
- ->ApplyDedupingRoutineForTesting());
-}
-
-TEST_F(PersonalDataManagerTest, ApplyDedupingRoutine_NopIfOneProfile) {
- base::test::ScopedFeatureList feature;
- feature.InitAndEnableFeature(features::kAutofillEnableProfileDeduplication);
-
- // Create a profile to dedupe.
- AutofillProfile profile(base::GenerateGUID(), test::kEmptyOrigin);
- test::SetProfileInfo(&profile, "Homer", "J", "Simpson",
- "homer.simpson@abc.com", "", "742. Evergreen Terrace",
- "", "Springfield", "IL", "91601", "US", "");
-
- AddProfileToPersonalDataManager(profile);
-
- EXPECT_EQ(1U, personal_data_->GetProfiles().size());
- EXPECT_FALSE(personal_data_->personal_data_manager_cleaner_for_testing()
- ->ApplyDedupingRoutineForTesting());
-}
-
-// Tests that ApplyDedupingRoutine is not run a second time on the same major
-// version.
-TEST_F(PersonalDataManagerTest, ApplyDedupingRoutine_OncePerVersion) {
- base::test::ScopedFeatureList feature;
- feature.InitAndEnableFeature(features::kAutofillEnableProfileDeduplication);
-
- // Create a profile to dedupe.
- AutofillProfile profile1(base::GenerateGUID(), test::kEmptyOrigin);
- test::SetProfileInfo(&profile1, "Homer", "J", "Simpson",
- "homer.simpson@abc.com", "", "742. Evergreen Terrace",
- "", "Springfield", "IL", "91601", "US", "");
-
- // Create a similar profile.
- AutofillProfile profile2(base::GenerateGUID(), test::kEmptyOrigin);
- test::SetProfileInfo(&profile2, "Homer", "J", "Simpson",
- "homer.simpson@abc.com", "Fox", "742 Evergreen Terrace.",
- "", "Springfield", "IL", "91601", "", "");
-
- AddProfileToPersonalDataManager(profile1);
- AddProfileToPersonalDataManager(profile2);
-
- EXPECT_EQ(2U, personal_data_->GetProfiles().size());
-
- // The deduping routine should be run a first time.
- EXPECT_TRUE(personal_data_->personal_data_manager_cleaner_for_testing()
- ->ApplyDedupingRoutineForTesting());
- WaitForOnPersonalDataChanged();
-
- std::vector<AutofillProfile*> profiles = personal_data_->GetProfiles();
-
- // The profiles should have been deduped
- EXPECT_EQ(1U, profiles.size());
-
- // Add another duplicate profile.
- AutofillProfile profile3(base::GenerateGUID(), test::kEmptyOrigin);
- test::SetProfileInfo(&profile3, "Homer", "J", "Simpson",
- "homer.simpson@abc.com", "Fox", "742 Evergreen Terrace.",
- "", "Springfield", "IL", "91601", "", "");
-
- AddProfileToPersonalDataManager(profile3);
-
- // Make sure |profile3| was saved.
- EXPECT_EQ(2U, personal_data_->GetProfiles().size());
-
- // The deduping routine should not be run.
- EXPECT_FALSE(personal_data_->personal_data_manager_cleaner_for_testing()
- ->ApplyDedupingRoutineForTesting());
-
- // The two duplicate profiles should still be present.
- EXPECT_EQ(2U, personal_data_->GetProfiles().size());
-}
-
-// Tests that settings-inaccessible profile values are removed from every stored
-// profile on startup.
-TEST_F(PersonalDataManagerTest, RemoveInaccessibleProfileValuesOnStartup) {
- base::test::ScopedFeatureList feature;
- feature.InitAndEnableFeatureWithParameters(
- features::kAutofillRemoveInaccessibleProfileValues,
- {{features::kAutofillRemoveInaccessibleProfileValuesOnStartup.name,
- "true"}});
-
- // Add a German and a US profile.
- AutofillProfile profile0(base::GenerateGUID(), test::kEmptyOrigin);
- test::SetProfileInfo(&profile0, "Marion", "Mitchell", "Morrison",
- "johnwayne@me.xyz", "Fox", "123 Zoo St.", "unit 5",
- "Hollywood", "CA", "91601", "DE", "12345678910");
- AutofillProfile profile1(base::GenerateGUID(), test::kEmptyOrigin);
- test::SetProfileInfo(&profile1, "Josephine", "Alicia", "Saenz",
- "joewayne@me.xyz", "Fox", "903 Apple Ct.", nullptr,
- "Orlando", "FL", "32801", "US", "19482937549");
- AddProfileToPersonalDataManager(profile0);
- AddProfileToPersonalDataManager(profile1);
-
- personal_data_->personal_data_manager_cleaner_for_testing()
- ->RemoveInaccessibleProfileValuesForTesting();
- WaitForOnPersonalDataChanged();
-
- // profile0 should have it's state removed, while the US profile should remain
- // unchanged.
- profile0.SetRawInfo(ADDRESS_HOME_STATE, u"");
- ExpectSameElements({&profile0, &profile1}, personal_data_->GetProfiles());
-}
-
-// Tests that DeleteDisusedAddresses only deletes the addresses that are
-// supposed to be deleted.
-TEST_F(PersonalDataManagerTest,
- DeleteDisusedAddresses_DeleteDesiredAddressesOnly) {
- auto now = AutofillClock::Now();
-
- // Create unverified/disused/not-used-by-valid-credit-card
- // address(deletable).
- AutofillProfile profile0(base::GenerateGUID(), test::kEmptyOrigin);
- test::SetProfileInfo(&profile0, "Alice", "", "Delete", "", "ACME",
- "1234 Evergreen Terrace", "Bld. 6", "Springfield", "IL",
- "32801", "US", "15151231234");
- profile0.set_use_date(now - base::Days(400));
- AddProfileToPersonalDataManager(profile0);
-
- // Create unverified/disused/used-by-expired-credit-card address(deletable).
- AutofillProfile profile1(base::GenerateGUID(), test::kEmptyOrigin);
- test::SetProfileInfo(&profile1, "Bob", "", "Delete", "", "ACME",
- "1234 Evergreen Terrace", "Bld. 7", "Springfield", "IL",
- "32801", "US", "15151231234");
- profile1.set_use_date(now - base::Days(400));
- CreditCard credit_card0(base::GenerateGUID(), test::kEmptyOrigin);
- test::SetCreditCardInfo(&credit_card0, "Bob",
- "5105105105105100" /* Mastercard */, "04", "1999",
- "1");
- credit_card0.set_use_date(now - base::Days(400));
- credit_card0.set_billing_address_id(profile1.guid());
- AddProfileToPersonalDataManager(profile1);
- personal_data_->AddCreditCard(credit_card0);
- WaitForOnPersonalDataChanged();
- // Create verified/disused/not-used-by-valid-credit-card address(not
- // deletable).
- AutofillProfile profile2(base::GenerateGUID(), test::kEmptyOrigin);
- test::SetProfileInfo(&profile2, "Charlie", "", "Keep", "", "ACME",
- "1234 Evergreen Terrace", "Bld. 8", "Springfield", "IL",
- "32801", "US", "15151231234");
- profile2.set_origin(kSettingsOrigin);
- profile2.set_use_date(now - base::Days(400));
- AddProfileToPersonalDataManager(profile2);
-
- // Create unverified/recently-used/not-used-by-valid-credit-card address(not
- // deletable).
- AutofillProfile profile3(base::GenerateGUID(), test::kEmptyOrigin);
- test::SetProfileInfo(&profile3, "Dave", "", "Keep", "", "ACME",
- "1234 Evergreen Terrace", "Bld. 9", "Springfield", "IL",
- "32801", "US", "15151231234");
- profile3.set_use_date(now - base::Days(4));
- AddProfileToPersonalDataManager(profile3);
-
- // Create unverified/disused/used-by-valid-credit-card address(not deletable).
- AutofillProfile profile4(base::GenerateGUID(), test::kEmptyOrigin);
- test::SetProfileInfo(&profile4, "Emma", "", "Keep", "", "ACME",
- "1234 Evergreen Terrace", "Bld. 10", "Springfield", "IL",
- "32801", "US", "15151231234");
- profile4.set_use_date(now - base::Days(400));
- CreditCard credit_card1(CreditCard::MASKED_SERVER_CARD, "c987");
- test::SetCreditCardInfo(&credit_card1, "Emma", "6543", "01", "2999", "1");
- credit_card1.SetNetworkForMaskedCard(kVisaCard);
- credit_card1.set_billing_address_id(profile4.guid());
- credit_card1.set_use_date(now - base::Days(1));
- AddProfileToPersonalDataManager(profile4);
- personal_data_->AddCreditCard(credit_card1);
-
- WaitForOnPersonalDataChanged();
-
- EXPECT_EQ(5U, personal_data_->GetProfiles().size());
- EXPECT_EQ(2U, personal_data_->GetCreditCards().size());
-
- // DeleteDisusedAddresses should return true.
- EXPECT_TRUE(personal_data_->personal_data_manager_cleaner_for_testing()
- ->DeleteDisusedAddressesForTesting());
- WaitForOnPersonalDataChanged();
-
- EXPECT_EQ(3U, personal_data_->GetProfiles().size());
- EXPECT_EQ(2U, personal_data_->GetCreditCards().size());
- EXPECT_EQ(u"Keep", personal_data_->GetProfiles()[0]->GetRawInfo(NAME_LAST));
- EXPECT_EQ(u"Keep", personal_data_->GetProfiles()[1]->GetRawInfo(NAME_LAST));
- EXPECT_EQ(u"Keep", personal_data_->GetProfiles()[2]->GetRawInfo(NAME_LAST));
-}
-
-// Tests that DeleteDisusedCreditCards deletes desired credit cards only.
-TEST_F(PersonalDataManagerTest,
- DeleteDisusedCreditCards_OnlyDeleteExpiredDisusedLocalCards) {
- const char kHistogramName[] = "Autofill.CreditCardsDeletedForDisuse";
- auto now = AutofillClock::Now();
-
- // Create a recently used local card, it is expected to remain.
- CreditCard credit_card1(base::GenerateGUID(), test::kEmptyOrigin);
- test::SetCreditCardInfo(&credit_card1, "Alice",
- "378282246310005" /* American Express */, "04",
- "2999", "1");
- credit_card1.set_use_date(now - base::Days(4));
-
- // Create a local card that was expired 400 days ago, but recently used.
- // It is expected to remain.
- CreditCard credit_card2(base::GenerateGUID(), test::kEmptyOrigin);
- test::SetCreditCardInfo(&credit_card2, "Bob",
- "378282246310006" /* American Express */, "04",
- "1999", "1");
- credit_card2.set_use_date(now - base::Days(4));
-
- // Create a local card expired recently, and last used 400 days ago.
- // It is expected to remain.
- CreditCard credit_card3(base::GenerateGUID(), test::kEmptyOrigin);
- base::Time expiry_date = now - base::Days(32);
- base::Time::Exploded exploded;
- expiry_date.UTCExplode(&exploded);
- test::SetCreditCardInfo(&credit_card3, "Clyde", "4111111111111111" /* Visa */,
- base::StringPrintf("%02d", exploded.month).c_str(),
- base::StringPrintf("%04d", exploded.year).c_str(),
- "1");
- credit_card3.set_use_date(now - base::Days(400));
-
- // Create a local card expired 400 days ago, and last used 400 days ago.
- // It is expected to be deleted.
- CreditCard credit_card4(base::GenerateGUID(), test::kEmptyOrigin);
- test::SetCreditCardInfo(&credit_card4, "David",
- "5105105105105100" /* Mastercard */, "04", "1999",
- "1");
- credit_card4.set_use_date(now - base::Days(400));
- personal_data_->AddCreditCard(credit_card1);
- personal_data_->AddCreditCard(credit_card2);
- personal_data_->AddCreditCard(credit_card3);
- personal_data_->AddCreditCard(credit_card4);
-
- // Create a unmasked server card expired 400 days ago, and last used 400
- // days ago.
- // It is expected to remain because we do not delete server cards.
- CreditCard credit_card5(CreditCard::FULL_SERVER_CARD, "c789");
- test::SetCreditCardInfo(&credit_card5, "Emma", "4234567890123456" /* Visa */,
- "04", "1999", "1");
- credit_card5.set_use_date(now - base::Days(400));
-
- // Create masked server card expired 400 days ago, and last used 400 days ago.
- // It is expected to remain because we do not delete server cards.
- CreditCard credit_card6(CreditCard::MASKED_SERVER_CARD, "c987");
- test::SetCreditCardInfo(&credit_card6, "Frank", "6543", "01", "1998", "1");
- credit_card6.set_use_date(now - base::Days(400));
- credit_card6.SetNetworkForMaskedCard(kVisaCard);
-
- // Save the server cards and set used_date to desired dates.
- std::vector<CreditCard> server_cards;
- server_cards.push_back(credit_card5);
- server_cards.push_back(credit_card6);
- SetServerCards(server_cards);
- personal_data_->UpdateServerCardsMetadata({credit_card5, credit_card6});
-
- WaitForOnPersonalDataChanged();
- EXPECT_EQ(6U, personal_data_->GetCreditCards().size());
-
- // Setup histograms capturing.
- base::HistogramTester histogram_tester;
-
- // DeleteDisusedCreditCards should return true to indicate it was run.
- EXPECT_TRUE(personal_data_->personal_data_manager_cleaner_for_testing()
- ->DeleteDisusedCreditCardsForTesting());
-
- // Wait for the data to be refreshed.
- WaitForOnPersonalDataChanged();
-
- EXPECT_EQ(5U, personal_data_->GetCreditCards().size());
- std::unordered_set<std::u16string> expectedToRemain = {
- u"Alice", u"Bob", u"Clyde", u"Emma", u"Frank"};
- for (auto* card : personal_data_->GetCreditCards()) {
- EXPECT_NE(expectedToRemain.end(),
- expectedToRemain.find(card->GetRawInfo(CREDIT_CARD_NAME_FULL)));
- }
-
- // Verify histograms are logged.
- histogram_tester.ExpectTotalCount(kHistogramName, 1);
- histogram_tester.ExpectBucketCount(kHistogramName, 1, 1);
-}
-
TEST_F(PersonalDataManagerTest, DeleteLocalCreditCards) {
CreditCard credit_card1(base::GenerateGUID(), test::kEmptyOrigin);
test::SetCreditCardInfo(&credit_card1, "Alice",
@@ -5619,12 +4366,11 @@ TEST_F(
// Tests that Wallet addresses do NOT get converted if they're stored in
// ephemeral storage.
-TEST_F(PersonalDataManagerTest, DoNotConvertWalletAddressesInEphemeralStorage) {
+TEST_F(PersonalDataManagerSyncTransportModeTest,
+ DoNotConvertWalletAddressesInEphemeralStorage) {
///////////////////////////////////////////////////////////////////////
// Setup.
///////////////////////////////////////////////////////////////////////
- ResetPersonalDataManager(USER_MODE_NORMAL,
- /*use_account_server_storage=*/true);
ASSERT_FALSE(personal_data_->IsSyncFeatureEnabled());
// Add a local profile.
@@ -6084,12 +4830,13 @@ TEST_F(PersonalDataManagerTest, ExcludeServerSideCards) {
// Sync Transport mode is only for Win, Mac, and Linux.
#if BUILDFLAG(IS_WIN) || BUILDFLAG(IS_MAC) || BUILDFLAG(IS_LINUX) || \
BUILDFLAG(IS_CHROMEOS)
-TEST_F(PersonalDataManagerTest, ServerCardsShowInTransportMode) {
- // Set up PersonalDataManager in transport mode.
- ResetPersonalDataManager(USER_MODE_NORMAL,
- /*use_account_server_storage=*/true);
+TEST_F(PersonalDataManagerSyncTransportModeTest,
+ ServerCardsShowInTransportMode) {
SetUpThreeCardTypes();
- AccountInfo active_info = SetActiveSecondaryAccount();
+
+ CoreAccountInfo active_info =
+ identity_test_env_.identity_manager()->GetPrimaryAccountInfo(
+ signin::ConsentLevel::kSignin);
// Opt-in to seeing server card in sync transport mode.
::autofill::prefs::SetUserOptedInWalletSyncTransport(
@@ -6117,12 +4864,13 @@ TEST_F(PersonalDataManagerTest, ServerCardsShowInTransportMode) {
// Make sure that the opt in is necessary to show server cards if the
// appropriate feature is disabled.
-TEST_F(PersonalDataManagerTest, ServerCardsShowInTransportMode_NeedOptIn) {
- // Set up PersonalDataManager in transport mode.
- ResetPersonalDataManager(USER_MODE_NORMAL,
- /*use_account_server_storage=*/true);
+TEST_F(PersonalDataManagerSyncTransportModeTest,
+ ServerCardsShowInTransportMode_NeedOptIn) {
SetUpThreeCardTypes();
- AccountInfo active_info = SetActiveSecondaryAccount();
+
+ CoreAccountInfo active_info =
+ identity_test_env_.identity_manager()->GetPrimaryAccountInfo(
+ signin::ConsentLevel::kSignin);
// The server cards should not be available at first. The user needs to
// accept the opt-in offer.
@@ -6148,120 +4896,6 @@ TEST_F(PersonalDataManagerTest, ServerCardsShowInTransportMode_NeedOptIn) {
#endif // BUILDFLAG(IS_WIN) || BUILDFLAG(IS_MAC) || BUILDFLAG(IS_LINUX) ||
// BUILDFLAG(IS_CHROMEOS)
-// Tests that all the non settings origins of autofill profiles are cleared but
-// that the settings origins are untouched.
-TEST_F(PersonalDataManagerTest, ClearProfileNonSettingsOrigins) {
- // Create three profile with a nonsettings, non-empty origin.
- AutofillProfile profile0(base::GenerateGUID(), "https://www.example.com");
- test::SetProfileInfo(&profile0, "Marion0", "Mitchell", "Morrison",
- "johnwayne@me.xyz", "Fox",
- "123 Zoo St.\nSecond Line\nThird line", "unit 5",
- "Hollywood", "CA", "91601", "US", "12345678910");
- profile0.set_use_count(10000);
- AddProfileToPersonalDataManager(profile0);
-
- AutofillProfile profile1(base::GenerateGUID(), test::kEmptyOrigin);
- test::SetProfileInfo(&profile1, "Marion1", "Mitchell", "Morrison",
- "johnwayne@me.xyz", "Fox",
- "123 Zoo St.\nSecond Line\nThird line", "unit 5",
- "Hollywood", "CA", "91601", "US", "12345678910");
- profile1.set_use_count(1000);
- AddProfileToPersonalDataManager(profile1);
-
- AutofillProfile profile2(base::GenerateGUID(), "1234");
- test::SetProfileInfo(&profile2, "Marion2", "Mitchell", "Morrison",
- "johnwayne@me.xyz", "Fox",
- "123 Zoo St.\nSecond Line\nThird line", "unit 5",
- "Hollywood", "CA", "91601", "US", "12345678910");
- profile2.set_use_count(100);
- AddProfileToPersonalDataManager(profile2);
-
- // Create a profile with a settings origin.
- AutofillProfile profile3(base::GenerateGUID(), kSettingsOrigin);
- test::SetProfileInfo(&profile3, "Marion3", "Mitchell", "Morrison",
- "johnwayne@me.xyz", "Fox",
- "123 Zoo St.\nSecond Line\nThird line", "unit 5",
- "Hollywood", "CA", "91601", "US", "12345678910");
- profile3.set_use_count(10);
- AddProfileToPersonalDataManager(profile3);
-
- ASSERT_EQ(4U, personal_data_->GetProfiles().size());
-
- base::RunLoop run_loop;
- EXPECT_CALL(personal_data_observer_, OnPersonalDataFinishedProfileTasks())
- .WillRepeatedly(QuitMessageLoop(&run_loop));
- EXPECT_CALL(personal_data_observer_, OnPersonalDataChanged())
- .Times(2); // The setting of profiles 0 and 2 will be cleared.
-
- personal_data_->personal_data_manager_cleaner_for_testing()
- ->ClearProfileNonSettingsOriginsForTesting();
- run_loop.Run();
-
- ASSERT_EQ(4U, personal_data_->GetProfiles().size());
-
- // The first three profiles' origin should be cleared and the fourth one still
- // be the settings origin.
- EXPECT_TRUE(personal_data_->GetProfilesToSuggest()[0]->origin().empty());
- EXPECT_TRUE(personal_data_->GetProfilesToSuggest()[1]->origin().empty());
- EXPECT_TRUE(personal_data_->GetProfilesToSuggest()[2]->origin().empty());
- EXPECT_EQ(kSettingsOrigin,
- personal_data_->GetProfilesToSuggest()[3]->origin());
-}
-
-// Tests that all the non settings origins of autofill credit cards are cleared
-// but that the settings origins are untouched.
-TEST_F(PersonalDataManagerTest, ClearCreditCardNonSettingsOrigins) {
- // Create three cards with a non settings origin.
- CreditCard credit_card0(base::GenerateGUID(), "https://www.example.com");
- test::SetCreditCardInfo(&credit_card0, "Bob0",
- "5105105105105100" /* Mastercard */, "04", "1999",
- "1");
- credit_card0.set_use_count(10000);
- personal_data_->AddCreditCard(credit_card0);
-
- CreditCard credit_card1(base::GenerateGUID(), test::kEmptyOrigin);
- test::SetCreditCardInfo(&credit_card1, "Bob1",
- "5105105105105101" /* Mastercard */, "04", "1999",
- "1");
- credit_card1.set_use_count(1000);
- personal_data_->AddCreditCard(credit_card1);
-
- CreditCard credit_card2(base::GenerateGUID(), "1234");
- test::SetCreditCardInfo(&credit_card2, "Bob2",
- "5105105105105102" /* Mastercard */, "04", "1999",
- "1");
- credit_card2.set_use_count(100);
- personal_data_->AddCreditCard(credit_card2);
-
- // Create a card with a settings origin.
- CreditCard credit_card3(base::GenerateGUID(), kSettingsOrigin);
- test::SetCreditCardInfo(&credit_card3, "Bob3",
- "5105105105105103" /* Mastercard */, "04", "1999",
- "1");
- credit_card3.set_use_count(10);
- personal_data_->AddCreditCard(credit_card3);
-
- WaitForOnPersonalDataChanged();
- ASSERT_EQ(4U, personal_data_->GetCreditCards().size());
-
- personal_data_->personal_data_manager_cleaner_for_testing()
- ->ClearCreditCardNonSettingsOriginsForTesting();
-
- WaitForOnPersonalDataChanged();
- ASSERT_EQ(4U, personal_data_->GetCreditCards().size());
-
- // The first three profiles' origin should be cleared and the fourth one still
- // be the settings origin.
- EXPECT_TRUE(
- personal_data_->GetCreditCardsToSuggest(false)[0]->origin().empty());
- EXPECT_TRUE(
- personal_data_->GetCreditCardsToSuggest(false)[1]->origin().empty());
- EXPECT_TRUE(
- personal_data_->GetCreditCardsToSuggest(false)[2]->origin().empty());
- EXPECT_EQ(kSettingsOrigin,
- personal_data_->GetCreditCardsToSuggest(false)[3]->origin());
-}
-
// Tests that all the non settings origins of autofill profiles are cleared even
// if sync is disabled.
TEST_F(
@@ -6330,8 +4964,9 @@ TEST_F(
// Sanity check that the mode where we use the regular, persistent storage for
// cards still works.
TEST_F(PersonalDataManagerTest, UsePersistentServerStorage) {
- ResetPersonalDataManager(USER_MODE_NORMAL,
- /*use_account_server_storage=*/false);
+ ASSERT_TRUE(identity_test_env_.identity_manager()->HasPrimaryAccount(
+ signin::ConsentLevel::kSync));
+ ASSERT_TRUE(sync_service_.HasSyncConsent());
SetUpThreeCardTypes();
// include_server_cards is set to false, therefore no server cards should be
@@ -6346,10 +4981,8 @@ TEST_F(PersonalDataManagerTest, UsePersistentServerStorage) {
}
// Verify that PDM can switch at runtime between the different storages.
-TEST_F(PersonalDataManagerTest, SwitchServerStorages) {
+TEST_F(PersonalDataManagerSyncTransportModeTest, SwitchServerStorages) {
// Start with account storage.
- ResetPersonalDataManager(USER_MODE_NORMAL,
- /*use_account_server_storage=*/true);
SetUpThreeCardTypes();
// Check that we do have 2 server cards, as expected.
@@ -6384,10 +5017,8 @@ TEST_F(PersonalDataManagerTest, SwitchServerStorages) {
// Sanity check that the mode where we use the regular, persistent storage for
// cards still works.
-TEST_F(PersonalDataManagerTest, UseCorrectStorageForDifferentCards) {
- ResetPersonalDataManager(USER_MODE_NORMAL,
- /*use_account_server_storage=*/true);
-
+TEST_F(PersonalDataManagerSyncTransportModeTest,
+ UseCorrectStorageForDifferentCards) {
// Add a server card.
CreditCard server_card;
test::SetCreditCardInfo(&server_card, "Server Card",
@@ -6525,18 +5156,18 @@ TEST_F(PersonalDataManagerTest,
TEST_F(PersonalDataManagerTest, GetAccountInfoForPaymentsServer) {
// Make the IdentityManager return a non-empty AccountInfo when
// GetPrimaryAccountInfo() is called.
- identity_test_env_.SetPrimaryAccount(kPrimaryAccountEmail,
- signin::ConsentLevel::kSync);
- ResetPersonalDataManager(USER_MODE_NORMAL);
+ std::string sync_account_email =
+ identity_test_env_.identity_manager()
+ ->GetPrimaryAccountInfo(signin::ConsentLevel::kSync)
+ .email;
+ ASSERT_FALSE(sync_account_email.empty());
- // Make the sync service return a non-empty AccountInfo when
- // GetAccountInfo() is called.
- AccountInfo active_info;
- active_info.email = kSyncTransportAccountEmail;
- sync_service_.SetAccountInfo(active_info);
+ // Make the sync service returns consistent AccountInfo when GetAccountInfo()
+ // is called.
+ ASSERT_EQ(sync_service_.GetAccountInfo().email, sync_account_email);
// The Active Sync AccountInfo should be returned.
- EXPECT_EQ(kSyncTransportAccountEmail,
+ EXPECT_EQ(sync_account_email,
personal_data_->GetAccountInfoForPaymentsServer().email);
// The Active Sync AccountInfo should still be returned even if
@@ -6546,7 +5177,7 @@ TEST_F(PersonalDataManagerTest, GetAccountInfoForPaymentsServer) {
scoped_features.InitAndDisableFeature(
features::kAutofillEnableAccountWalletStorage);
- EXPECT_EQ(kSyncTransportAccountEmail,
+ EXPECT_EQ(sync_account_email,
personal_data_->GetAccountInfoForPaymentsServer().email);
}
}
@@ -6556,14 +5187,13 @@ TEST_F(PersonalDataManagerTest, OnAccountsCookieDeletedByUserAction) {
::autofill::prefs::SetUserOptedInWalletSyncTransport(
prefs_.get(), CoreAccountId("account1"), true);
EXPECT_FALSE(
- prefs_->GetDictionary(prefs::kAutofillSyncTransportOptIn)->DictEmpty());
+ prefs_->GetValueDict(prefs::kAutofillSyncTransportOptIn).empty());
// Simulate that the cookies get cleared by the user.
personal_data_->OnAccountsCookieDeletedByUserAction();
// Make sure the pref is now empty.
- EXPECT_TRUE(
- prefs_->GetDictionary(prefs::kAutofillSyncTransportOptIn)->DictEmpty());
+ EXPECT_TRUE(prefs_->GetValueDict(prefs::kAutofillSyncTransportOptIn).empty());
}
TEST_F(PersonalDataManagerTest, SaveProfileUpdateStrikes) {
@@ -6710,7 +5340,8 @@ TEST_F(PersonalDataManagerMigrationTest,
#endif // BUILDFLAG(IS_CHROMEOS_ASH)
#if !BUILDFLAG(IS_ANDROID) && !BUILDFLAG(IS_IOS) && !BUILDFLAG(IS_CHROMEOS_ASH)
-TEST_F(PersonalDataManagerTest, ShouldShowCardsFromAccountOption) {
+TEST_F(PersonalDataManagerSyncTransportModeTest,
+ ShouldShowCardsFromAccountOption) {
// The method should return false if one of these is not respected:
// * The sync_service is not null
// * The sync feature is not enabled
@@ -6720,12 +5351,6 @@ TEST_F(PersonalDataManagerTest, ShouldShowCardsFromAccountOption) {
// independently, one by one.
// Set everything up so that the proposition should be shown.
- // Set an active secondary account.
- AccountInfo active_info;
- active_info.email = kPrimaryAccountEmail;
- active_info.account_id = CoreAccountId("account_id");
- sync_service_.SetAccountInfo(active_info);
- sync_service_.SetHasSyncConsent(false);
// Set a server credit card.
std::vector<CreditCard> server_cards;
@@ -6738,23 +5363,24 @@ TEST_F(PersonalDataManagerTest, ShouldShowCardsFromAccountOption) {
WaitForOnPersonalDataChanged();
// Set the feature to enabled.
- base::test::ScopedFeatureList scoped_features;
- scoped_features.InitWithFeatures(
- /*enabled_features=*/{features::kAutofillEnableAccountWalletStorage},
- /*disabled_features=*/{});
+ base::test::ScopedFeatureList scoped_features(
+ features::kAutofillEnableAccountWalletStorage);
// Make sure the function returns true.
EXPECT_TRUE(personal_data_->ShouldShowCardsFromAccountOption());
// Set that the user already opted-in. Check that the function now returns
// false.
- ::autofill::prefs::SetUserOptedInWalletSyncTransport(
- prefs_.get(), active_info.account_id, true);
+ CoreAccountId account_id =
+ identity_test_env_.identity_manager()->GetPrimaryAccountId(
+ signin::ConsentLevel::kSignin);
+ ::autofill::prefs::SetUserOptedInWalletSyncTransport(prefs_.get(), account_id,
+ true);
EXPECT_FALSE(personal_data_->ShouldShowCardsFromAccountOption());
// Re-opt the user out. Check that the function now returns true.
- ::autofill::prefs::SetUserOptedInWalletSyncTransport(
- prefs_.get(), active_info.account_id, false);
+ ::autofill::prefs::SetUserOptedInWalletSyncTransport(prefs_.get(), account_id,
+ false);
EXPECT_TRUE(personal_data_->ShouldShowCardsFromAccountOption());
// Set that the user has no server cards. Check that the function now returns
@@ -6785,7 +5411,8 @@ TEST_F(PersonalDataManagerTest, ShouldShowCardsFromAccountOption) {
}
#else // !BUILDFLAG(IS_ANDROID) && !BUILDFLAG(IS_IOS) &&
// !BUILDFLAG(IS_CHROMEOS_ASH)
-TEST_F(PersonalDataManagerTest, ShouldShowCardsFromAccountOption) {
+TEST_F(PersonalDataManagerSyncTransportModeTest,
+ ShouldShowCardsFromAccountOption) {
// The method should return false if one of these is not respected:
// * The sync_service is not null
// * The sync feature is not enabled
@@ -6795,12 +5422,6 @@ TEST_F(PersonalDataManagerTest, ShouldShowCardsFromAccountOption) {
// independently, one by one.
// Set everything up so that the proposition should be shown on Desktop.
- // Set an an active secondary account.
- AccountInfo active_info;
- active_info.email = kPrimaryAccountEmail;
- active_info.account_id = CoreAccountId("account_id");
- sync_service_.SetAccountInfo(active_info);
- sync_service_.SetHasSyncConsent(false);
// Set a server credit card.
std::vector<CreditCard> server_cards;
@@ -6823,13 +5444,16 @@ TEST_F(PersonalDataManagerTest, ShouldShowCardsFromAccountOption) {
// Set that the user already opted-in. Check that the function still returns
// false.
- ::autofill::prefs::SetUserOptedInWalletSyncTransport(
- prefs_.get(), active_info.account_id, true);
+ CoreAccountId account_id =
+ identity_test_env_.identity_manager()->GetPrimaryAccountId(
+ signin::ConsentLevel::kSignin);
+ ::autofill::prefs::SetUserOptedInWalletSyncTransport(prefs_.get(), account_id,
+ true);
EXPECT_FALSE(personal_data_->ShouldShowCardsFromAccountOption());
// Re-opt the user out. Check that the function now returns true.
- ::autofill::prefs::SetUserOptedInWalletSyncTransport(
- prefs_.get(), active_info.account_id, false);
+ ::autofill::prefs::SetUserOptedInWalletSyncTransport(prefs_.get(), account_id,
+ false);
EXPECT_FALSE(personal_data_->ShouldShowCardsFromAccountOption());
// Set that the user has no server cards. Check that the function still
@@ -6861,12 +5485,11 @@ TEST_F(PersonalDataManagerTest, ShouldShowCardsFromAccountOption) {
#endif // !BUILDFLAG(IS_ANDROID) && !BUILDFLAG(IS_IOS) &&
// !BUILDFLAG(IS_CHROMEOS_ASH)
-TEST_F(PersonalDataManagerTest, GetSyncSigninState) {
- // Make a non-primary account available with both a refresh token and cookie
- // for the first few tests.
- identity_test_env_.SetPrimaryAccount("test@gmail.com",
- signin::ConsentLevel::kSync);
- sync_service_.SetHasSyncConsent(false);
+TEST_F(PersonalDataManagerSyncTransportModeTest, GetSyncSigninState) {
+ // Make sure a non-sync-consented account is available for the first tests.
+ ASSERT_TRUE(identity_test_env_.identity_manager()->HasPrimaryAccount(
+ signin::ConsentLevel::kSignin));
+ ASSERT_FALSE(sync_service_.HasSyncConsent());
sync_service_.SetActiveDataTypes(
syncer::ModelTypeSet(syncer::AUTOFILL_WALLET_DATA));
@@ -6874,10 +5497,8 @@ TEST_F(PersonalDataManagerTest, GetSyncSigninState) {
// account info is not empty, the kAutofillEnableAccountWalletStorage feature
// is enabled and the Wallet data type is active for the sync service.
{
- base::test::ScopedFeatureList scoped_features;
- scoped_features.InitWithFeatures(
- /*enabled_features=*/{features::kAutofillEnableAccountWalletStorage},
- /*disabled_features=*/{});
+ base::test::ScopedFeatureList scoped_features(
+ features::kAutofillEnableAccountWalletStorage);
EXPECT_EQ(AutofillSyncSigninState::kSignedInAndWalletSyncTransportEnabled,
personal_data_->GetSyncSigninState());
@@ -6887,9 +5508,8 @@ TEST_F(PersonalDataManagerTest, GetSyncSigninState) {
// kAutofillEnableAccountWalletStorage feature is disabled.
{
base::test::ScopedFeatureList scoped_features;
- scoped_features.InitWithFeatures(
- /*enabled_features=*/{},
- /*disabled_features=*/{features::kAutofillEnableAccountWalletStorage});
+ scoped_features.InitAndDisableFeature(
+ features::kAutofillEnableAccountWalletStorage);
EXPECT_EQ(AutofillSyncSigninState::kSignedIn,
personal_data_->GetSyncSigninState());
@@ -6898,10 +5518,8 @@ TEST_F(PersonalDataManagerTest, GetSyncSigninState) {
// Check that the sync state is |SignedIn| if the sync service does not have
// wallet data active.
{
- base::test::ScopedFeatureList scoped_features;
- scoped_features.InitWithFeatures(
- /*enabled_features=*/{features::kAutofillEnableAccountWalletStorage},
- /*disabled_features=*/{});
+ base::test::ScopedFeatureList scoped_features(
+ features::kAutofillEnableAccountWalletStorage);
sync_service_.SetActiveDataTypes(syncer::ModelTypeSet());
EXPECT_EQ(AutofillSyncSigninState::kSignedIn,
@@ -6938,8 +5556,7 @@ TEST_F(PersonalDataManagerTest, GetSyncSigninState) {
// feature is enabled even if the kAutofillEnableAccountWalletStorage feature
// is enabled.
{
- base::test::ScopedFeatureList scoped_features;
- scoped_features.InitAndEnableFeature(
+ base::test::ScopedFeatureList scoped_features(
features::kAutofillEnableAccountWalletStorage);
EXPECT_EQ(AutofillSyncSigninState::kSignedInAndSyncFeatureEnabled,
personal_data_->GetSyncSigninState());
@@ -6949,14 +5566,19 @@ TEST_F(PersonalDataManagerTest, GetSyncSigninState) {
// On mobile, no dedicated opt-in is required for WalletSyncTransport - the
// user is always considered opted-in and thus this test doesn't make sense.
#if !BUILDFLAG(IS_ANDROID) && !BUILDFLAG(IS_IOS)
-TEST_F(PersonalDataManagerTest, OnUserAcceptedUpstreamOffer) {
+TEST_F(PersonalDataManagerSyncTransportModeTest, OnUserAcceptedUpstreamOffer) {
///////////////////////////////////////////////////////////
// kSignedInAndWalletSyncTransportEnabled
///////////////////////////////////////////////////////////
- // Make a primary account with no sync consent available to be in Sync
- // Transport for Wallet mode.
- CoreAccountInfo active_info = identity_test_env_.MakePrimaryAccountAvailable(
- kSyncTransportAccountEmail, signin::ConsentLevel::kSignin);
+ // Make sure a primary account with no sync consent is available so
+ // AUTOFILL_WALLET_DATA can run in sync-transport mode.
+ ASSERT_TRUE(identity_test_env_.identity_manager()->HasPrimaryAccount(
+ signin::ConsentLevel::kSignin));
+ ASSERT_FALSE(identity_test_env_.identity_manager()->HasPrimaryAccount(
+ signin::ConsentLevel::kSync));
+ CoreAccountInfo active_info =
+ identity_test_env_.identity_manager()->GetPrimaryAccountInfo(
+ signin::ConsentLevel::kSignin);
sync_service_.SetAccountInfo(active_info);
sync_service_.SetHasSyncConsent(false);
sync_service_.SetActiveDataTypes(
diff --git a/chromium/components/autofill/core/browser/proto/server.proto b/chromium/components/autofill/core/browser/proto/server.proto
index 25264f3988c..caa3efa92c3 100644
--- a/chromium/components/autofill/core/browser/proto/server.proto
+++ b/chromium/components/autofill/core/browser/proto/server.proto
@@ -218,6 +218,9 @@ message AutofillRandomizedFieldMetadata {
// Example: <input value="VVVVVVV">
// XXXXXXXX = hash("VVVVVVV"")
optional AutofillRandomizedValue initial_value_hash = 9;
+
+ // Value of the autocomplete attribute. Example: <input autocomplete="XXX">
+ optional AutofillRandomizedValue autocomplete = 10;
}
// This message contains information about the field types in a single form.
diff --git a/chromium/components/autofill/core/browser/randomized_encoder.cc b/chromium/components/autofill/core/browser/randomized_encoder.cc
index e9d84a1fcc5..1013f91a280 100644
--- a/chromium/components/autofill/core/browser/randomized_encoder.cc
+++ b/chromium/components/autofill/core/browser/randomized_encoder.cc
@@ -173,6 +173,7 @@ const char RandomizedEncoder::FIELD_CSS_CLASS[] = "field-css-classes";
const char RandomizedEncoder::FIELD_PLACEHOLDER[] = "field-placeholder";
const char RandomizedEncoder::FIELD_INITIAL_VALUE_HASH[] =
"field-initial-hash-value";
+const char RandomizedEncoder::FIELD_AUTOCOMPLETE[] = "field-autocomplete";
// Copy of components/unified_consent/pref_names.cc
// We could not use the constant from components/unified_constants because of a
diff --git a/chromium/components/autofill/core/browser/randomized_encoder.h b/chromium/components/autofill/core/browser/randomized_encoder.h
index 46cba968f16..c2eda37c624 100644
--- a/chromium/components/autofill/core/browser/randomized_encoder.h
+++ b/chromium/components/autofill/core/browser/randomized_encoder.h
@@ -46,6 +46,7 @@ class RandomizedEncoder {
static const char FIELD_CSS_CLASS[];
static const char FIELD_PLACEHOLDER[];
static const char FIELD_INITIAL_VALUE_HASH[];
+ static const char FIELD_AUTOCOMPLETE[];
static const char kUrlKeyedAnonymizedDataCollectionEnabled[];
diff --git a/chromium/components/autofill/core/browser/rationalization_util.cc b/chromium/components/autofill/core/browser/rationalization_util.cc
index 1d606e4c6ef..8118bbe47f1 100644
--- a/chromium/components/autofill/core/browser/rationalization_util.cc
+++ b/chromium/components/autofill/core/browser/rationalization_util.cc
@@ -30,45 +30,37 @@ void RationalizePhoneNumberFields(
ServerFieldType current_field_type = field->Type().GetStorableType();
switch (current_field_type) {
case PHONE_HOME_NUMBER:
- case PHONE_BILLING_NUMBER:
+ found_number_field = field;
+ phone_number_found = true;
+ break;
+ case PHONE_HOME_NUMBER_PREFIX:
if (!found_number_field) {
found_number_field = field;
- if (field->max_length < 5) {
- phone_number_separate_fields = true;
- } else {
- phone_number_found = true;
- }
- break;
+ phone_number_separate_fields = true;
+ }
+ break;
+ case PHONE_HOME_NUMBER_SUFFIX:
+ if (phone_number_separate_fields) {
+ found_number_field_second = field;
+ phone_number_found = true;
}
- // If the form has phone number separated into exchange and subscriber
- // number we mark both of them as number fields.
- // TODO(wuandy): A less hacky solution to have dedicated enum for
- // exchange and subscriber number.
- DCHECK(phone_number_separate_fields);
- DCHECK(!found_number_field_second);
- found_number_field_second = field;
- phone_number_found = true;
break;
case PHONE_HOME_CITY_CODE_WITH_TRUNK_PREFIX:
case PHONE_HOME_CITY_CODE:
- case PHONE_BILLING_CITY_CODE:
if (!found_city_code_field)
found_city_code_field = field;
break;
case PHONE_HOME_COUNTRY_CODE:
- case PHONE_BILLING_COUNTRY_CODE:
if (!found_country_code_field)
found_country_code_field = field;
break;
case PHONE_HOME_CITY_AND_NUMBER:
case PHONE_HOME_CITY_AND_NUMBER_WITHOUT_TRUNK_PREFIX:
- case PHONE_BILLING_CITY_AND_NUMBER:
DCHECK(!phone_number_found && !found_city_and_number_field);
found_city_and_number_field = field;
phone_number_found = true;
break;
case PHONE_HOME_WHOLE_NUMBER:
- case PHONE_BILLING_WHOLE_NUMBER:
DCHECK(!phone_number_found && !found_whole_number_field);
found_whole_number_field = field;
phone_number_found = true;
@@ -125,29 +117,24 @@ void RationalizePhoneNumberFields(
ServerFieldType current_field_type = field->Type().GetStorableType();
switch (current_field_type) {
case PHONE_HOME_NUMBER:
- case PHONE_BILLING_NUMBER:
if (field != found_number_field && field != found_number_field_second)
field->set_only_fill_when_focused(true);
break;
case PHONE_HOME_CITY_CODE:
case PHONE_HOME_CITY_CODE_WITH_TRUNK_PREFIX:
- case PHONE_BILLING_CITY_CODE:
if (field != found_city_code_field)
field->set_only_fill_when_focused(true);
break;
case PHONE_HOME_COUNTRY_CODE:
- case PHONE_BILLING_COUNTRY_CODE:
if (field != found_country_code_field)
field->set_only_fill_when_focused(true);
break;
case PHONE_HOME_CITY_AND_NUMBER:
case PHONE_HOME_CITY_AND_NUMBER_WITHOUT_TRUNK_PREFIX:
- case PHONE_BILLING_CITY_AND_NUMBER:
if (field != found_city_and_number_field)
field->set_only_fill_when_focused(true);
break;
case PHONE_HOME_WHOLE_NUMBER:
- case PHONE_BILLING_WHOLE_NUMBER:
if (field != found_whole_number_field)
field->set_only_fill_when_focused(true);
break;
diff --git a/chromium/components/autofill/core/browser/single_field_form_fill_router.cc b/chromium/components/autofill/core/browser/single_field_form_fill_router.cc
index 9bbc8381b4c..1ad9c237317 100644
--- a/chromium/components/autofill/core/browser/single_field_form_fill_router.cc
+++ b/chromium/components/autofill/core/browser/single_field_form_fill_router.cc
@@ -52,26 +52,28 @@ void SingleFieldFormFillRouter::OnWillSubmitForm(
autocomplete_fields, is_autocomplete_enabled);
}
-void SingleFieldFormFillRouter::OnGetSingleFieldSuggestions(
+bool SingleFieldFormFillRouter::OnGetSingleFieldSuggestions(
int query_id,
bool is_autocomplete_enabled,
bool autoselect_first_suggestion,
- const std::u16string& name,
- const std::u16string& prefix,
- const std::string& form_control_type,
+ const FormFieldData& field,
base::WeakPtr<SingleFieldFormFiller::SuggestionsHandler> handler,
const SuggestionsContext& context) {
// Retrieving suggestions for a new field; select the appropriate filler.
- if (merchant_promo_code_manager_ && context.focused_field &&
- context.focused_field->Type().GetStorableType() == MERCHANT_PROMO_CODE) {
- merchant_promo_code_manager_->OnGetSingleFieldSuggestions(
- query_id, is_autocomplete_enabled, autoselect_first_suggestion, name,
- prefix, form_control_type, handler, context);
- } else {
- autocomplete_history_manager_->OnGetSingleFieldSuggestions(
- query_id, is_autocomplete_enabled, autoselect_first_suggestion, name,
- prefix, form_control_type, handler, context);
+ if (merchant_promo_code_manager_ &&
+ merchant_promo_code_manager_->OnGetSingleFieldSuggestions(
+ query_id, is_autocomplete_enabled, autoselect_first_suggestion, field,
+ handler, context)) {
+ return true;
}
+
+ if (autocomplete_history_manager_->OnGetSingleFieldSuggestions(
+ query_id, is_autocomplete_enabled, autoselect_first_suggestion, field,
+ handler, context)) {
+ return true;
+ }
+
+ return false;
}
void SingleFieldFormFillRouter::OnWillSubmitFormWithFields(
diff --git a/chromium/components/autofill/core/browser/single_field_form_fill_router.h b/chromium/components/autofill/core/browser/single_field_form_fill_router.h
index 28336d2187b..8564d2bb28b 100644
--- a/chromium/components/autofill/core/browser/single_field_form_fill_router.h
+++ b/chromium/components/autofill/core/browser/single_field_form_fill_router.h
@@ -42,13 +42,11 @@ class SingleFieldFormFillRouter : public SingleFieldFormFiller {
bool is_autocomplete_enabled);
// SingleFieldFormFiller overrides:
- void OnGetSingleFieldSuggestions(
+ [[nodiscard]] bool OnGetSingleFieldSuggestions(
int query_id,
bool is_autocomplete_enabled,
bool autoselect_first_suggestion,
- const std::u16string& name,
- const std::u16string& prefix,
- const std::string& form_control_type,
+ const FormFieldData& field,
base::WeakPtr<SingleFieldFormFiller::SuggestionsHandler> handler,
const SuggestionsContext& context) override;
void OnWillSubmitFormWithFields(const std::vector<FormFieldData>& fields,
diff --git a/chromium/components/autofill/core/browser/single_field_form_fill_router_unittest.cc b/chromium/components/autofill/core/browser/single_field_form_fill_router_unittest.cc
index f091d5f6d6d..a2fad7dc872 100644
--- a/chromium/components/autofill/core/browser/single_field_form_fill_router_unittest.cc
+++ b/chromium/components/autofill/core/browser/single_field_form_fill_router_unittest.cc
@@ -6,10 +6,10 @@
#include "base/test/scoped_feature_list.h"
#include "base/test/task_environment.h"
#include "components/autofill/core/browser/autofill_test_utils.h"
+#include "components/autofill/core/browser/form_structure.h"
#include "components/autofill/core/browser/mock_autocomplete_history_manager.h"
#include "components/autofill/core/browser/mock_merchant_promo_code_manager.h"
#include "components/autofill/core/browser/suggestions_context.h"
-#include "components/autofill/core/browser/test_form_structure.h"
#include "components/autofill/core/browser/test_personal_data_manager.h"
#include "components/autofill/core/browser/webdata/mock_autofill_webdata_service.h"
#include "components/autofill/core/common/autofill_features.h"
@@ -25,9 +25,6 @@ using testing::SaveArg;
namespace autofill {
-using FieldPrediction =
- AutofillQueryResponse::FormSuggestion::FieldSuggestion::FieldPrediction;
-
namespace {
class MockSuggestionsHandler
: public SingleFieldFormFiller::SuggestionsHandler {
@@ -74,6 +71,8 @@ class SingleFieldFormFillRouterTest : public testing::Test {
std::make_unique<SingleFieldFormFillRouter>(
autocomplete_history_manager_.get(),
merchant_promo_code_manager_.get());
+ test::CreateTestFormField(/*label=*/"", "Some Field Name", "SomePrefix",
+ "SomeType", &test_field_);
}
base::test::SingleThreadTaskEnvironment task_environment_;
@@ -83,22 +82,36 @@ class SingleFieldFormFillRouterTest : public testing::Test {
std::unique_ptr<MockAutocompleteHistoryManager> autocomplete_history_manager_;
std::unique_ptr<MockMerchantPromoCodeManager> merchant_promo_code_manager_;
std::unique_ptr<PrefService> prefs_;
+ FormFieldData test_field_;
};
// Ensure that the router routes to AutocompleteHistoryManager for this
-// OnGetSingleFieldSuggestions call.
+// OnGetSingleFieldSuggestions call if the field has autocomplete on.
TEST_F(SingleFieldFormFillRouterTest,
RouteToAutocompleteHistoryManager_OnGetSingleFieldSuggestions) {
- auto suggestions_handler = std::make_unique<MockSuggestionsHandler>();
-
- EXPECT_CALL(*autocomplete_history_manager_, OnGetSingleFieldSuggestions);
-
- single_field_form_fill_router_->OnGetSingleFieldSuggestions(
- /*query_id=*/2, /*is_autocomplete_enabled=*/true,
- /*autoselect_first_suggestion=*/false, /*name=*/u"Some Field Name",
- /*prefix=*/u"SomePrefix",
- /*form_control_type=*/"SomeType", suggestions_handler->GetWeakPtr(),
- SuggestionsContext());
+ for (bool test_field_should_autocomplete : {true, false}) {
+ SCOPED_TRACE(testing::Message() << "test_field_should_autocomplete = "
+ << test_field_should_autocomplete);
+ auto suggestions_handler = std::make_unique<MockSuggestionsHandler>();
+ test_field_.should_autocomplete = test_field_should_autocomplete;
+
+ // If |test_field_.should_autocomplete| is true, that means autocomplete is
+ // turned on for the given test field and
+ // AutocompleteHistoryManager::OnGetSingleFieldSuggestions() should return
+ // true. If |test_field_.should_autocomplete| is false, then autocomplete is
+ // turned off for the given test field and
+ // AutocompleteHistoryManager::OnGetSingleFieldSuggestions() should return
+ // false.
+ EXPECT_CALL(*autocomplete_history_manager_, OnGetSingleFieldSuggestions)
+ .Times(1)
+ .WillOnce(testing::Return(test_field_.should_autocomplete));
+
+ EXPECT_EQ(test_field_.should_autocomplete,
+ single_field_form_fill_router_->OnGetSingleFieldSuggestions(
+ /*query_id=*/2, /*is_autocomplete_enabled=*/true,
+ /*autoselect_first_suggestion=*/false, test_field_,
+ suggestions_handler->GetWeakPtr(), SuggestionsContext()));
+ }
}
// Ensure that the router routes to all SingleFieldFormFillers for this
@@ -106,20 +119,11 @@ TEST_F(SingleFieldFormFillRouterTest,
TEST_F(SingleFieldFormFillRouterTest,
RouteToAllSingleFieldFormFillers_OnWillSubmitForm) {
FormData form_data;
- std::vector<FormFieldData> fields;
size_t number_of_fields_for_testing = 3;
- for (size_t i = 0; i < number_of_fields_for_testing; i++) {
- fields.emplace_back();
- }
-
-#if !BUILDFLAG(IS_IOS)
- for (size_t i = 0; i < number_of_fields_for_testing; i++) {
- fields.emplace_back();
- }
-#endif // !BUILDFLAG(IS_IOS)
+ std::vector<FormFieldData> fields(2 * number_of_fields_for_testing);
form_data.fields = fields;
- TestFormStructure form_structure{form_data};
+ FormStructure form_structure{form_data};
// Set the first |number_of_fields_for_testing| fields to be autocomplete
// fields.
@@ -127,14 +131,12 @@ TEST_F(SingleFieldFormFillRouterTest,
form_structure.set_server_field_type_for_testing(i, UNKNOWN_TYPE);
}
-#if !BUILDFLAG(IS_IOS)
// Set the next |number_of_fields_for_testing| fields to be merchant promo
// code fields.
for (size_t i = number_of_fields_for_testing;
i < number_of_fields_for_testing * 2; i++) {
form_structure.set_server_field_type_for_testing(i, MERCHANT_PROMO_CODE);
}
-#endif // !BUILDFLAG(IS_IOS)
std::vector<FormFieldData> submitted_autocomplete_fields;
bool autocomplete_fields_is_autocomplete_enabled = false;
@@ -143,14 +145,12 @@ TEST_F(SingleFieldFormFillRouterTest,
(DoAll(SaveArg<0>(&submitted_autocomplete_fields),
SaveArg<1>(&autocomplete_fields_is_autocomplete_enabled))));
-#if !BUILDFLAG(IS_IOS)
std::vector<FormFieldData> submitted_merchant_promo_code_fields;
bool merchant_promo_code_fields_is_autocomplete_enabled = false;
EXPECT_CALL(*merchant_promo_code_manager_, OnWillSubmitFormWithFields(_, _))
.WillOnce((DoAll(
SaveArg<0>(&submitted_merchant_promo_code_fields),
SaveArg<1>(&merchant_promo_code_fields_is_autocomplete_enabled))));
-#endif // !BUILDFLAG(IS_IOS)
single_field_form_fill_router_->OnWillSubmitForm(
form_data, &form_structure, /*is_autocomplete_enabled=*/true);
@@ -159,11 +159,9 @@ TEST_F(SingleFieldFormFillRouterTest,
number_of_fields_for_testing);
EXPECT_TRUE(autocomplete_fields_is_autocomplete_enabled);
-#if !BUILDFLAG(IS_IOS)
EXPECT_TRUE(submitted_merchant_promo_code_fields.size() ==
number_of_fields_for_testing);
EXPECT_TRUE(merchant_promo_code_fields_is_autocomplete_enabled);
-#endif // !BUILDFLAG(IS_IOS)
}
// Ensure that the router routes to SingleFieldFormFillers for this
@@ -174,9 +172,7 @@ TEST_F(SingleFieldFormFillRouterTest,
EXPECT_CALL(*autocomplete_history_manager_, CancelPendingQueries);
-#if !BUILDFLAG(IS_IOS)
EXPECT_CALL(*merchant_promo_code_manager_, CancelPendingQueries);
-#endif // !BUILDFLAG(IS_IOS)
single_field_form_fill_router_->CancelPendingQueries(
suggestions_handler.get());
@@ -204,34 +200,90 @@ TEST_F(SingleFieldFormFillRouterTest,
/*value=*/u"Value", POPUP_ITEM_ID_AUTOCOMPLETE_ENTRY);
}
-#if !BUILDFLAG(IS_IOS)
// Ensure that the router routes to MerchantPromoCodeManager for this
// OnGetSingleFieldSuggestions call.
TEST_F(SingleFieldFormFillRouterTest,
RouteToMerchantPromoCodeManager_OnGetSingleFieldSuggestions) {
+ for (bool test_field_should_autocomplete : {true, false}) {
+ SCOPED_TRACE(testing::Message() << "test_field_should_autocomplete = "
+ << test_field_should_autocomplete);
+ base::test::ScopedFeatureList feature_list;
+ feature_list.InitWithFeatures(
+ {features::kAutofillFillMerchantPromoCodeFields}, {});
+ auto suggestions_handler = std::make_unique<MockSuggestionsHandler>();
+ test_field_.should_autocomplete = test_field_should_autocomplete;
+
+ // |test_field_.should_autocomplete| should not affect merchant promo code
+ // autofill, so MerchantPromoCodeManager::OnGetSingleFieldSuggestions()
+ // should always be called since the given test field is a merchant promo
+ // code field.
+ EXPECT_CALL(*merchant_promo_code_manager_, OnGetSingleFieldSuggestions)
+ .Times(1)
+ .WillOnce(testing::Return(true));
+
+ EXPECT_TRUE(single_field_form_fill_router_->OnGetSingleFieldSuggestions(
+ /*query_id=*/2, /*is_autocomplete_enabled=*/true,
+ /*autoselect_first_suggestion=*/false, test_field_,
+ suggestions_handler->GetWeakPtr(), SuggestionsContext()));
+ }
+}
+
+// Ensure that the router routes to AutocompleteHistoryManager for this
+// OnGetSingleFieldSuggestions call if MerchantPromoCodeManager is not present.
+TEST_F(SingleFieldFormFillRouterTest, MerchantPromoCodeManagerNotPresent) {
base::test::ScopedFeatureList feature_list;
- feature_list.InitWithFeatures({features::kAutofillFillMerchantPromoCodeFields,
- features::kAutofillServerTypeTakesPrecedence},
- {});
+ feature_list.InitWithFeatures(
+ {features::kAutofillFillMerchantPromoCodeFields}, {});
auto suggestions_handler = std::make_unique<MockSuggestionsHandler>();
- EXPECT_CALL(*merchant_promo_code_manager_, OnGetSingleFieldSuggestions);
- std::vector<FieldPrediction> merchant_promo_code_field_predictions;
- FieldPrediction merchant_promo_code_field_prediction;
- merchant_promo_code_field_prediction.set_type(MERCHANT_PROMO_CODE);
- merchant_promo_code_field_predictions.push_back(
- merchant_promo_code_field_prediction);
- SuggestionsContext context;
- AutofillField autofill_field;
- autofill_field.set_server_predictions(
- std::move(merchant_promo_code_field_predictions));
- context.focused_field = &autofill_field;
- single_field_form_fill_router_->OnGetSingleFieldSuggestions(
+ // This also invalidates the WeakPtr that the |single_field_form_fill_router_|
+ // holds on the promo code manager.
+ merchant_promo_code_manager_.reset();
+
+ // As the merchant promo code manager is gone, we should call
+ // AutocompleteHistoryManager::OnGetSingleFieldSuggestions().
+ EXPECT_CALL(*autocomplete_history_manager_, OnGetSingleFieldSuggestions)
+ .Times(1)
+ .WillOnce(testing::Return(true));
+
+ // As |test_field_.should_autocomplete| is true, this was a valid field for
+ // autocomplete. SingleFieldFormFillRouter::OnGetSingleFieldSuggestions()
+ // should return true.
+ EXPECT_TRUE(single_field_form_fill_router_->OnGetSingleFieldSuggestions(
+ /*query_id=*/2, /*is_autocomplete_enabled=*/true,
+ /*autoselect_first_suggestion=*/false, test_field_,
+ suggestions_handler->GetWeakPtr(), SuggestionsContext()));
+}
+
+// Ensure that the router routes to AutocompleteHistoryManager for this
+// OnGetSingleFieldSuggestions call if
+// MerchantPromoCodeManager::OnGetSingleFieldSuggestions() returns false.
+TEST_F(SingleFieldFormFillRouterTest, MerchantPromoCodeManagerReturnedFalse) {
+ base::test::ScopedFeatureList feature_list;
+ feature_list.InitWithFeatures(
+ {features::kAutofillFillMerchantPromoCodeFields}, {});
+ auto suggestions_handler = std::make_unique<MockSuggestionsHandler>();
+
+ // Mock MerchantPromoCodeManager::OnGetSingleFieldSuggestions() returning
+ // false.
+ EXPECT_CALL(*merchant_promo_code_manager_, OnGetSingleFieldSuggestions)
+ .Times(1)
+ .WillOnce(testing::Return(false));
+
+ // Since MerchantPromoCodeManager::OnGetSingleFieldSuggestions() returned
+ // false, we should call
+ // AutocompleteHistoryManager::OnGetSingleFieldSuggestions().
+ EXPECT_CALL(*autocomplete_history_manager_, OnGetSingleFieldSuggestions)
+ .Times(1)
+ .WillOnce(testing::Return(true));
+
+ // As |test_field_.should_autocomplete| is true, this was a valid field for
+ // autocomplete. SingleFieldFormFillRouter::OnGetSingleFieldSuggestions()
+ // should return true.
+ EXPECT_TRUE(single_field_form_fill_router_->OnGetSingleFieldSuggestions(
/*query_id=*/2, /*is_autocomplete_enabled=*/true,
- /*autoselect_first_suggestion=*/false, /*name=*/u"Some Field Name",
- /*prefix=*/u"SomePrefix",
- /*form_control_type=*/"SomeType", suggestions_handler->GetWeakPtr(),
- context);
+ /*autoselect_first_suggestion=*/false, test_field_,
+ suggestions_handler->GetWeakPtr(), SuggestionsContext()));
}
// Ensure that the router routes to MerchantPromoCodeManager for this
@@ -255,6 +307,31 @@ TEST_F(SingleFieldFormFillRouterTest,
single_field_form_fill_router_->OnSingleFieldSuggestionSelected(
/*value=*/u"Value", POPUP_ITEM_ID_MERCHANT_PROMO_CODE_ENTRY);
}
-#endif // !BUILDFLAG(IS_IOS)
+
+// Ensure that SingleFieldFormFillRouter::OnGetSingleFieldSuggestions() returns
+// false if all single field form fillers returned false.
+TEST_F(
+ SingleFieldFormFillRouterTest,
+ FieldNotEligibleForAnySingleFieldFormFiller_OnGetSingleFieldSuggestions) {
+ base::test::ScopedFeatureList feature_list;
+ feature_list.InitWithFeatures(
+ {features::kAutofillFillMerchantPromoCodeFields}, {});
+ auto suggestions_handler = std::make_unique<MockSuggestionsHandler>();
+
+ EXPECT_CALL(*merchant_promo_code_manager_, OnGetSingleFieldSuggestions)
+ .Times(1)
+ .WillOnce(testing::Return(false));
+
+ EXPECT_CALL(*autocomplete_history_manager_, OnGetSingleFieldSuggestions)
+ .Times(1)
+ .WillOnce(testing::Return(false));
+
+ // All SingleFieldFormFillers returned false, so we should return false as we
+ // did not attempt to display any single field form fill suggestions.
+ EXPECT_FALSE(single_field_form_fill_router_->OnGetSingleFieldSuggestions(
+ /*query_id=*/2, /*is_autocomplete_enabled=*/true,
+ /*autoselect_first_suggestion=*/false, test_field_,
+ suggestions_handler->GetWeakPtr(), SuggestionsContext()));
+}
} // namespace autofill
diff --git a/chromium/components/autofill/core/browser/single_field_form_filler.h b/chromium/components/autofill/core/browser/single_field_form_filler.h
index 41414abe32f..624d8fe6223 100644
--- a/chromium/components/autofill/core/browser/single_field_form_filler.h
+++ b/chromium/components/autofill/core/browser/single_field_form_filler.h
@@ -42,21 +42,23 @@ class SingleFieldFormFiller {
// |query_id| is given by the client as context.
// |is_autocomplete_enabled| is to determine if the feature is enable for the
// requestor's context (e.g. Android WebViews have different contexts).
- // |name| is the name of the field.
- // |prefix| is the field's value.
- // |form_control_type| is the field's control type.
- // |handler| is weak pointer to the requestor, which we will call back once we
- // receive the response. There can only be one pending query per |handler|,
- // hence this function will cancel the previous pending query if it hadn't
- // already been resolved, at which point no method of the handler will be
- // called.
- virtual void OnGetSingleFieldSuggestions(
+ // |field| is the given field. |handler| is weak pointer to the requestor,
+ // which we will call back once we receive the response. There can only be one
+ // pending query per |handler|, hence this function will cancel the previous
+ // pending query if it hadn't already been resolved, at which point no method
+ // of the handler will be called.
+ // The boolean return value denotes whether a SingleFieldFormFiller claims the
+ // opportunity to fill this field. By returning true, the
+ // SingleFieldFormFiller does not promise at this point to have a value
+ // available for filling. It just promises to call back the handler and voids
+ // the opportunity for other SingleFieldFormFillers to offer filling the
+ // field. The callback can happen synchronously even before
+ // OnGetSingleFieldSuggestions returns true.
+ [[nodiscard]] virtual bool OnGetSingleFieldSuggestions(
int query_id,
bool is_autocomplete_enabled,
bool autoselect_first_suggestion,
- const std::u16string& name,
- const std::u16string& prefix,
- const std::string& form_control_type,
+ const FormFieldData& field,
base::WeakPtr<SuggestionsHandler> handler,
const SuggestionsContext& context) = 0;
diff --git a/chromium/components/autofill/core/browser/test_autofill_client.cc b/chromium/components/autofill/core/browser/test_autofill_client.cc
index 55da3ffe7e0..8310d83be6b 100644
--- a/chromium/components/autofill/core/browser/test_autofill_client.cc
+++ b/chromium/components/autofill/core/browser/test_autofill_client.cc
@@ -44,6 +44,18 @@ MerchantPromoCodeManager* TestAutofillClient::GetMerchantPromoCodeManager() {
return &mock_merchant_promo_code_manager_;
}
+CreditCardCVCAuthenticator* TestAutofillClient::GetCVCAuthenticator() {
+ if (!cvc_authenticator_)
+ cvc_authenticator_ = std::make_unique<CreditCardCVCAuthenticator>(this);
+ return cvc_authenticator_.get();
+}
+
+CreditCardOtpAuthenticator* TestAutofillClient::GetOtpAuthenticator() {
+ if (!otp_authenticator_)
+ otp_authenticator_ = std::make_unique<CreditCardOtpAuthenticator>(this);
+ return otp_authenticator_.get();
+}
+
PrefService* TestAutofillClient::GetPrefs() {
return const_cast<PrefService*>(base::as_const(*this).GetPrefs());
}
@@ -116,7 +128,7 @@ std::string TestAutofillClient::GetVariationConfigCountryCode() const {
#if !BUILDFLAG(IS_IOS)
std::unique_ptr<webauthn::InternalAuthenticator>
TestAutofillClient::CreateCreditCardInternalAuthenticator(
- content::RenderFrameHost* rfh) {
+ AutofillDriver* driver) {
return std::make_unique<TestInternalAuthenticator>();
}
#endif
@@ -254,6 +266,17 @@ bool TestAutofillClient::HasCreditCardScanFeature() {
void TestAutofillClient::ScanCreditCard(CreditCardScanCallback callback) {}
+bool TestAutofillClient::IsTouchToFillCreditCardSupported() {
+ return false;
+}
+
+bool TestAutofillClient::ShowTouchToFillCreditCard(
+ base::WeakPtr<TouchToFillDelegate> delegate) {
+ return false;
+}
+
+void TestAutofillClient::HideTouchToFillCreditCard() {}
+
void TestAutofillClient::ShowAutofillPopup(
const AutofillClient::PopupOpenArgs& open_args,
base::WeakPtr<AutofillPopupDelegate> delegate) {}
diff --git a/chromium/components/autofill/core/browser/test_autofill_client.h b/chromium/components/autofill/core/browser/test_autofill_client.h
index a5b9d052531..b0743bbc9f9 100644
--- a/chromium/components/autofill/core/browser/test_autofill_client.h
+++ b/chromium/components/autofill/core/browser/test_autofill_client.h
@@ -17,6 +17,8 @@
#include "components/autofill/core/browser/mock_autocomplete_history_manager.h"
#include "components/autofill/core/browser/mock_merchant_promo_code_manager.h"
#include "components/autofill/core/browser/payments/autofill_offer_manager.h"
+#include "components/autofill/core/browser/payments/credit_card_cvc_authenticator.h"
+#include "components/autofill/core/browser/payments/credit_card_otp_authenticator.h"
#include "components/autofill/core/browser/payments/legal_message_line.h"
#include "components/autofill/core/browser/payments/test_payments_client.h"
#include "components/autofill/core/browser/payments/test_strike_database.h"
@@ -53,6 +55,8 @@ class TestAutofillClient : public AutofillClient {
TestPersonalDataManager* GetPersonalDataManager() override;
AutocompleteHistoryManager* GetAutocompleteHistoryManager() override;
MerchantPromoCodeManager* GetMerchantPromoCodeManager() override;
+ CreditCardCVCAuthenticator* GetCVCAuthenticator() override;
+ CreditCardOtpAuthenticator* GetOtpAuthenticator() override;
PrefService* GetPrefs() override;
const PrefService* GetPrefs() const override;
syncer::SyncService* GetSyncService() override;
@@ -71,7 +75,7 @@ class TestAutofillClient : public AutofillClient {
std::string GetVariationConfigCountryCode() const override;
#if !BUILDFLAG(IS_IOS)
std::unique_ptr<webauthn::InternalAuthenticator>
- CreateCreditCardInternalAuthenticator(content::RenderFrameHost* rfh) override;
+ CreateCreditCardInternalAuthenticator(AutofillDriver* driver) override;
#endif
void ShowAutofillSettings(bool show_credit_card_settings) override;
@@ -140,6 +144,10 @@ class TestAutofillClient : public AutofillClient {
AddressProfileSavePromptCallback callback) override;
bool HasCreditCardScanFeature() override;
void ScanCreditCard(CreditCardScanCallback callback) override;
+ bool IsTouchToFillCreditCardSupported() override;
+ bool ShowTouchToFillCreditCard(
+ base::WeakPtr<TouchToFillDelegate> delegate) override;
+ void HideTouchToFillCreditCard() override;
void ShowAutofillPopup(
const AutofillClient::PopupOpenArgs& open_args,
base::WeakPtr<AutofillPopupDelegate> delegate) override;
@@ -190,6 +198,16 @@ class TestAutofillClient : public AutofillClient {
test_personal_data_manager_ = std::move(pdm);
}
+ void set_cvc_authenticator(
+ std::unique_ptr<CreditCardCVCAuthenticator> authenticator) {
+ cvc_authenticator_ = std::move(authenticator);
+ }
+
+ void set_otp_authenticator(
+ std::unique_ptr<CreditCardOtpAuthenticator> authenticator) {
+ otp_authenticator_ = std::move(authenticator);
+ }
+
void set_test_strike_database(
std::unique_ptr<TestStrikeDatabase> test_strike_database) {
test_strike_database_ = std::move(test_strike_database);
@@ -305,6 +323,8 @@ class TestAutofillClient : public AutofillClient {
std::unique_ptr<PrefService> prefs_;
std::unique_ptr<TestStrikeDatabase> test_strike_database_;
std::unique_ptr<payments::PaymentsClient> payments_client_;
+ std::unique_ptr<CreditCardCVCAuthenticator> cvc_authenticator_;
+ std::unique_ptr<CreditCardOtpAuthenticator> otp_authenticator_;
// AutofillOfferManager and TestFormDataImporter must be destroyed before
// TestPersonalDataManager, because the former's destructors refer to the
diff --git a/chromium/components/autofill/core/browser/test_autofill_clock.cc b/chromium/components/autofill/core/browser/test_autofill_clock.cc
index 41254e32669..8b0dc260d9d 100644
--- a/chromium/components/autofill/core/browser/test_autofill_clock.cc
+++ b/chromium/components/autofill/core/browser/test_autofill_clock.cc
@@ -4,6 +4,7 @@
#include "components/autofill/core/browser/test_autofill_clock.h"
+#include <memory>
#include <utility>
#include "base/test/simple_test_clock.h"
@@ -11,22 +12,28 @@
namespace autofill {
-TestAutofillClock::TestAutofillClock(base::Time now) {
- AutofillClock::SetTestClock(&test_clock_);
+TestAutofillClock::TestAutofillClock(base::Time now)
+ : TestAutofillClock(std::make_unique<base::SimpleTestClock>()) {
SetNow(now);
}
+TestAutofillClock::TestAutofillClock(
+ std::unique_ptr<base::SimpleTestClock> test_clock)
+ : test_clock_(std::move(test_clock)) {
+ AutofillClock::SetTestClock(test_clock_.get());
+}
+
TestAutofillClock::~TestAutofillClock() {
// Destroys the test clock and resets a normal clock.
AutofillClock::SetClock();
}
void TestAutofillClock::SetNow(base::Time now) {
- test_clock_.SetNow(now);
+ test_clock_->SetNow(now);
}
void TestAutofillClock::Advance(base::TimeDelta delta) {
- test_clock_.Advance(delta);
+ test_clock_->Advance(delta);
}
} // namespace autofill
diff --git a/chromium/components/autofill/core/browser/test_autofill_clock.h b/chromium/components/autofill/core/browser/test_autofill_clock.h
index 4fe92015e05..09f004f339a 100644
--- a/chromium/components/autofill/core/browser/test_autofill_clock.h
+++ b/chromium/components/autofill/core/browser/test_autofill_clock.h
@@ -5,10 +5,12 @@
#ifndef COMPONENTS_AUTOFILL_CORE_BROWSER_TEST_AUTOFILL_CLOCK_H_
#define COMPONENTS_AUTOFILL_CORE_BROWSER_TEST_AUTOFILL_CLOCK_H_
-#include "base/test/simple_test_clock.h"
+#include <memory>
+
+#include "base/time/time.h"
namespace base {
-class Time;
+class SimpleTestClock;
} // namespace base
namespace autofill {
@@ -20,6 +22,7 @@ namespace autofill {
class TestAutofillClock {
public:
explicit TestAutofillClock(base::Time now = {});
+ explicit TestAutofillClock(std::unique_ptr<base::SimpleTestClock> test_clock);
TestAutofillClock(const TestAutofillClock&) = delete;
TestAutofillClock& operator=(const TestAutofillClock&) = delete;
@@ -33,7 +36,7 @@ class TestAutofillClock {
void Advance(base::TimeDelta delta);
private:
- base::SimpleTestClock test_clock_;
+ std::unique_ptr<base::SimpleTestClock> test_clock_;
};
} // namespace autofill
diff --git a/chromium/components/autofill/core/browser/test_autofill_driver.cc b/chromium/components/autofill/core/browser/test_autofill_driver.cc
index 80b5a85cea9..d6f2046987b 100644
--- a/chromium/components/autofill/core/browser/test_autofill_driver.cc
+++ b/chromium/components/autofill/core/browser/test_autofill_driver.cc
@@ -31,6 +31,10 @@ bool TestAutofillDriver::IsIncognito() const {
return is_incognito_;
}
+bool TestAutofillDriver::IsInActiveFrame() const {
+ return is_in_active_frame_;
+}
+
bool TestAutofillDriver::IsInAnyMainFrame() const {
return is_in_any_main_frame_;
}
@@ -57,13 +61,6 @@ bool TestAutofillDriver::RendererIsAvailable() {
return true;
}
-#if !BUILDFLAG(IS_IOS)
-webauthn::InternalAuthenticator*
-TestAutofillDriver::GetOrCreateCreditCardInternalAuthenticator() {
- return test_authenticator_.get();
-}
-#endif
-
std::vector<FieldGlobalId> TestAutofillDriver::FillOrPreviewForm(
int query_id,
mojom::RendererFormDataAction action,
@@ -80,48 +77,18 @@ std::vector<FieldGlobalId> TestAutofillDriver::FillOrPreviewForm(
return result;
}
-void TestAutofillDriver::HandleParsedForms(
- const std::vector<const FormData*>& forms) {}
-
-void TestAutofillDriver::SendAutofillTypePredictionsToRenderer(
- const std::vector<FormStructure*>& forms) {
-}
-
-void TestAutofillDriver::RendererShouldAcceptDataListSuggestion(
- const FieldGlobalId& field,
- const std::u16string& value) {}
-
-void TestAutofillDriver::RendererShouldClearFilledSection() {}
-
-void TestAutofillDriver::RendererShouldClearPreviewedForm() {
-}
-
-void TestAutofillDriver::RendererShouldFillFieldWithValue(
- const FieldGlobalId& field,
- const std::u16string& value) {}
-
-void TestAutofillDriver::RendererShouldPreviewFieldWithValue(
- const FieldGlobalId& field,
- const std::u16string& value) {}
-
-void TestAutofillDriver::RendererShouldSetSuggestionAvailability(
- const FieldGlobalId& field,
- const mojom::AutofillState state) {}
-
-void TestAutofillDriver::PopupHidden() {
-}
-
net::IsolationInfo TestAutofillDriver::IsolationInfo() {
return isolation_info_;
}
-void TestAutofillDriver::SendFieldsEligibleForManualFillingToRenderer(
- const std::vector<FieldGlobalId>& fields) {}
-
void TestAutofillDriver::SetIsIncognito(bool is_incognito) {
is_incognito_ = is_incognito;
}
+void TestAutofillDriver::SetIsInActiveFrame(bool is_in_active_frame) {
+ is_in_active_frame_ = is_in_active_frame;
+}
+
void TestAutofillDriver::SetIsInAnyMainFrame(bool is_in_any_main_frame) {
is_in_any_main_frame_ = is_in_any_main_frame;
}
diff --git a/chromium/components/autofill/core/browser/test_autofill_driver.h b/chromium/components/autofill/core/browser/test_autofill_driver.h
index e69366b4cc2..eeee3136d0c 100644
--- a/chromium/components/autofill/core/browser/test_autofill_driver.h
+++ b/chromium/components/autofill/core/browser/test_autofill_driver.h
@@ -44,16 +44,13 @@ class TestAutofillDriver : public ContentAutofillDriver {
// AutofillDriver implementation overrides.
bool IsIncognito() const override;
+ bool IsInActiveFrame() const override;
bool IsInAnyMainFrame() const override;
bool IsPrerendering() const override;
bool CanShowAutofillUi() const override;
ui::AXTreeID GetAxTreeId() const override;
scoped_refptr<network::SharedURLLoaderFactory> GetURLLoaderFactory() override;
bool RendererIsAvailable() override;
-#if !BUILDFLAG(IS_IOS)
- webauthn::InternalAuthenticator* GetOrCreateCreditCardInternalAuthenticator()
- override;
-#endif
// The return value contains the members (field, type) of `field_type_map` for
// which `field_type_filter_.Run(triggered_origin, field, type)` is true.
std::vector<FieldGlobalId> FillOrPreviewForm(
@@ -63,31 +60,32 @@ class TestAutofillDriver : public ContentAutofillDriver {
const url::Origin& triggered_origin,
const base::flat_map<FieldGlobalId, ServerFieldType>& field_type_map)
override;
- void HandleParsedForms(const std::vector<const FormData*>& forms) override;
+ void HandleParsedForms(const std::vector<FormData>& forms) override {}
void SendAutofillTypePredictionsToRenderer(
- const std::vector<FormStructure*>& forms) override;
+ const std::vector<FormStructure*>& forms) override {}
void RendererShouldAcceptDataListSuggestion(
const FieldGlobalId& field,
- const std::u16string& value) override;
- void RendererShouldClearFilledSection() override;
- void RendererShouldClearPreviewedForm() override;
+ const std::u16string& value) override {}
+ void RendererShouldClearFilledSection() override {}
+ void RendererShouldClearPreviewedForm() override {}
void RendererShouldFillFieldWithValue(const FieldGlobalId& field,
- const std::u16string& value) override;
+ const std::u16string& value) override {}
void RendererShouldPreviewFieldWithValue(
const FieldGlobalId& field,
- const std::u16string& value) override;
+ const std::u16string& value) override {}
void RendererShouldSetSuggestionAvailability(
const FieldGlobalId& field,
- const mojom::AutofillState state) override;
- void PopupHidden() override;
+ const mojom::AutofillState state) override {}
+ void PopupHidden() override {}
net::IsolationInfo IsolationInfo() override;
void SendFieldsEligibleForManualFillingToRenderer(
- const std::vector<FieldGlobalId>& fields) override;
+ const std::vector<FieldGlobalId>& fields) override {}
// Methods unique to TestAutofillDriver that tests can use to specialize
// functionality.
void SetIsIncognito(bool is_incognito);
+ void SetIsInActiveFrame(bool is_in_active_frame);
void SetIsInAnyMainFrame(bool is_in_any_main_frame);
void SetIsolationInfo(const net::IsolationInfo& isolation_info);
@@ -106,7 +104,8 @@ class TestAutofillDriver : public ContentAutofillDriver {
network::TestURLLoaderFactory test_url_loader_factory_;
scoped_refptr<network::SharedURLLoaderFactory> test_shared_loader_factory_;
bool is_incognito_ = false;
- bool is_in_any_main_frame_ = false;
+ bool is_in_active_frame_ = true;
+ bool is_in_any_main_frame_ = true;
net::IsolationInfo isolation_info_;
base::RepeatingCallback<
bool(const url::Origin&, FieldGlobalId, ServerFieldType)>
diff --git a/chromium/components/autofill/core/browser/test_autofill_manager_waiter.cc b/chromium/components/autofill/core/browser/test_autofill_manager_waiter.cc
new file mode 100644
index 00000000000..55b2d9d4461
--- /dev/null
+++ b/chromium/components/autofill/core/browser/test_autofill_manager_waiter.cc
@@ -0,0 +1,205 @@
+// Copyright 2022 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/test_autofill_manager_waiter.h"
+
+#include "base/check_op.h"
+#include "base/containers/contains.h"
+#include "base/logging.h"
+#include "base/strings/string_util.h"
+#include "base/strings/stringprintf.h"
+#include "base/test/scoped_run_loop_timeout.h"
+
+namespace autofill {
+
+TestAutofillManagerWaiter::State::State() = default;
+TestAutofillManagerWaiter::State::~State() = default;
+
+TestAutofillManagerWaiter::EventCount* TestAutofillManagerWaiter::State::Get(
+ AfterEvent event) {
+ auto it = base::ranges::find(events, event, &EventCount::event);
+ return it != events.end() ? &*it : nullptr;
+}
+
+TestAutofillManagerWaiter::EventCount&
+TestAutofillManagerWaiter::State::GetOrCreate(AfterEvent event,
+ base::Location location) {
+ if (EventCount* e = Get(event))
+ return *e;
+ return *events.insert(events.end(), {event, location});
+}
+
+size_t TestAutofillManagerWaiter::State::num_pending_calls() const {
+ size_t pending_calls = 0;
+ for (const EventCount& e : events)
+ pending_calls += e.num_pending_calls;
+ return pending_calls;
+}
+
+size_t TestAutofillManagerWaiter::State::num_total_calls() const {
+ size_t total_calls = 0;
+ for (const EventCount& e : events)
+ total_calls += e.num_total_calls;
+ return total_calls;
+}
+
+std::string TestAutofillManagerWaiter::State::Describe() const {
+ std::vector<std::string> strings;
+ for (const auto& e : events) {
+ strings.push_back(base::StringPrintf(
+ "[event=%s, pending=%zu, total=%zu]", e.location.function_name(),
+ e.num_pending_calls, e.num_total_calls));
+ }
+ return base::JoinString(strings, ", ");
+}
+
+TestAutofillManagerWaiter::TestAutofillManagerWaiter(
+ AutofillManager& manager,
+ std::initializer_list<AfterEvent> relevant_events)
+ : relevant_events_(relevant_events) {
+ observation_.Observe(&manager);
+}
+
+TestAutofillManagerWaiter::~TestAutofillManagerWaiter() = default;
+
+void TestAutofillManagerWaiter::OnAutofillManagerDestroyed() {
+ observation_.Reset();
+}
+
+void TestAutofillManagerWaiter::OnAutofillManagerReset() {
+ Reset();
+}
+
+void TestAutofillManagerWaiter::OnBeforeLanguageDetermined() {
+ Increment(&AutofillManager::Observer::OnAfterLanguageDetermined);
+}
+
+void TestAutofillManagerWaiter::OnAfterLanguageDetermined() {
+ Decrement(&AutofillManager::Observer::OnAfterLanguageDetermined);
+}
+
+void TestAutofillManagerWaiter::OnBeforeFormsSeen() {
+ Increment(&AutofillManager::Observer::OnAfterFormsSeen);
+}
+
+void TestAutofillManagerWaiter::OnAfterFormsSeen() {
+ Decrement(&AutofillManager::Observer::OnAfterFormsSeen);
+}
+
+void TestAutofillManagerWaiter::OnBeforeTextFieldDidChange() {
+ Increment(&AutofillManager::Observer::OnAfterTextFieldDidChange);
+}
+
+void TestAutofillManagerWaiter::OnAfterTextFieldDidChange() {
+ Decrement(&AutofillManager::Observer::OnAfterTextFieldDidChange);
+}
+
+void TestAutofillManagerWaiter::OnBeforeAskForValuesToFill() {
+ Increment(&AutofillManager::Observer::OnAfterAskForValuesToFill);
+}
+
+void TestAutofillManagerWaiter::OnAfterAskForValuesToFill() {
+ Decrement(&AutofillManager::Observer::OnAfterAskForValuesToFill);
+}
+
+void TestAutofillManagerWaiter::OnBeforeDidFillAutofillFormData() {
+ Increment(&AutofillManager::Observer::OnAfterDidFillAutofillFormData);
+}
+
+void TestAutofillManagerWaiter::OnAfterDidFillAutofillFormData() {
+ Decrement(&AutofillManager::Observer::OnAfterDidFillAutofillFormData);
+}
+
+void TestAutofillManagerWaiter::OnBeforeJavaScriptChangedAutofilledValue() {
+ Increment(
+ &AutofillManager::Observer::OnAfterJavaScriptChangedAutofilledValue);
+}
+
+void TestAutofillManagerWaiter::OnAfterJavaScriptChangedAutofilledValue() {
+ Decrement(
+ &AutofillManager::Observer::OnAfterJavaScriptChangedAutofilledValue);
+}
+
+void TestAutofillManagerWaiter::Reset() {
+ // The declaration order ensures that `lock` is destroyed before `state`, so
+ // that `state_->lock` has been released at its own destruction time.
+ auto state = std::make_unique<State>();
+ base::AutoLock lock(state_->lock);
+ VLOG(1) << __func__;
+ ASSERT_EQ(state_->num_pending_calls(), 0u) << state_->Describe();
+ using std::swap;
+ swap(state_, state);
+}
+
+bool TestAutofillManagerWaiter::IsRelevant(AfterEvent event) const {
+ return relevant_events_.empty() || base::Contains(relevant_events_, event);
+}
+
+void TestAutofillManagerWaiter::Increment(AfterEvent event,
+ base::Location location) {
+ base::AutoLock lock(state_->lock);
+ if (!IsRelevant(event)) {
+ VLOG(1) << "Ignoring irrelevant event: " << __func__ << "("
+ << location.function_name() << ")";
+ return;
+ }
+ if (state_->run_loop.AnyQuitCalled()) {
+ VLOG(1) << "Ignoring event because no more calls are awaited: " << __func__
+ << "(" << location.function_name() << ")";
+ return;
+ }
+ VLOG(1) << __func__ << "(" << location.function_name() << ")";
+ EventCount& e = state_->GetOrCreate(event, location);
+ e.location = location;
+ ++e.num_total_calls;
+ ++e.num_pending_calls;
+}
+
+void TestAutofillManagerWaiter::Decrement(AfterEvent event,
+ base::Location location) {
+ base::AutoLock lock(state_->lock);
+ if (!IsRelevant(event)) {
+ VLOG(1) << "Ignoring irrelevant event: " << __func__ << "("
+ << location.function_name() << ")";
+ return;
+ }
+ if (state_->run_loop.AnyQuitCalled()) {
+ VLOG(1) << "Ignoring event because no more calls are awaited: " << __func__
+ << "(" << location.function_name() << ")";
+ return;
+ }
+ VLOG(1) << __func__ << "(" << location.function_name() << ")";
+ EventCount* e = state_->Get(event);
+ ASSERT_TRUE(e) << state_->Describe();
+ ASSERT_GT(e->num_pending_calls, 0u) << state_->Describe();
+ if (state_->num_awaiting_total_calls > 0)
+ --state_->num_awaiting_total_calls;
+ --e->num_pending_calls;
+ if (state_->num_pending_calls() == 0 && state_->num_awaiting_total_calls == 0)
+ state_->run_loop.Quit();
+}
+
+testing::AssertionResult TestAutofillManagerWaiter::Wait(
+ size_t num_awaiting_calls) {
+ base::ReleasableAutoLock lock(&state_->lock);
+ if (state_->run_loop.AnyQuitCalled()) {
+ return testing::AssertionFailure()
+ << "Waiter has not been Reset() since last Wait().";
+ }
+ // Some events may already have happened.
+ num_awaiting_calls = num_awaiting_calls > state_->num_total_calls()
+ ? num_awaiting_calls - state_->num_total_calls()
+ : 0u;
+ if (state_->num_pending_calls() > 0 || num_awaiting_calls > 0) {
+ base::test::ScopedRunLoopTimeout run_loop_timeout(
+ FROM_HERE, timeout_,
+ base::BindRepeating(&State::Describe, base::Unretained(state_.get())));
+ state_->num_awaiting_total_calls = num_awaiting_calls;
+ lock.Release();
+ state_->run_loop.Run();
+ }
+ return testing::AssertionSuccess();
+}
+
+} // namespace autofill
diff --git a/chromium/components/autofill/core/browser/test_autofill_manager_waiter.h b/chromium/components/autofill/core/browser/test_autofill_manager_waiter.h
new file mode 100644
index 00000000000..c382bbdf4eb
--- /dev/null
+++ b/chromium/components/autofill/core/browser/test_autofill_manager_waiter.h
@@ -0,0 +1,163 @@
+// Copyright 2022 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_TEST_AUTOFILL_MANAGER_WAITER_H_
+#define COMPONENTS_AUTOFILL_CORE_BROWSER_TEST_AUTOFILL_MANAGER_WAITER_H_
+
+#include <list>
+#include <memory>
+#include <vector>
+
+#include "base/run_loop.h"
+#include "base/scoped_observation.h"
+#include "base/synchronization/lock.h"
+#include "base/time/time.h"
+#include "components/autofill/core/browser/autofill_manager.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace autofill {
+
+// Records AutofillManager::Observer::OnBeforeFoo() events and blocks until the
+// corresponding OnAfterFoo() events have happened.
+//
+// This mechanism relies on AutofillManager::Observer's guarantee that
+// OnBeforeFoo() is followed by OnAfterFoo() in normal circumstances.
+//
+// If an OnBeforeFoo() event happens multiple times, the waiter expects multiple
+// OnAfterFoo() events.
+//
+// Which events Wait() should be waiting for can be limited by providing a list
+// of `relevant_events` to the constructor. This list should contain the
+// OnAfterFoo(), *not* the OnBeforeFoo() events.
+//
+// By default, Wait() succeeds immediately if there are no pending calls, that
+// is, if no OnBeforeFoo() without matching OnAfterFoo() has been observed.
+// Calling Wait(k) with an integer argument `k` overrides this behaviour: in
+// this case, it expects a total of at least `k` OnAfterFoo() events to happen
+// or have happened.
+//
+// The waiter resets itself on OnAutofillManagerDestroyed() events. This makes
+// it suitable for use with TestAutofillManagerInjector.
+//
+// Typical usage is as follows:
+//
+// TestAutofillManagerWaiter waiter(manager,
+// {&AutofillManager::Observer::OnAfterFoo,
+// &AutofillManager::Observer::OnAfterBar,
+// ...});
+// ... trigger events ...
+// ASSERT_TRUE(waiter.Wait()); // Blocks.
+//
+// In browser tests, it may be necessary to tell Wait() to wait for at least,
+// say, 1 event because triggering events is asynchronous due to Mojo:
+//
+// TestAutofillManagerWaiter waiter(manager,
+// {&AutofillManager::Observer::OnAfterFoo,
+// ...});
+// ... trigger asynchronous OnFoo event ...
+// ASSERT_TRUE(waiter.Wait(1)); // Blocks until at least one OnFoo() event
+// // has happened since the creation of
+// // `waiter`.
+//
+// In case of failure, the error message of Wait() informs about the pending
+// OnAfterFoo() calls.
+class TestAutofillManagerWaiter : public AutofillManager::Observer {
+ public:
+ // An OnFooAfter() event. As a convention, throughout this class we use the
+ // OnAfterFoo() events to identify the pair of OnAfterFoo() / OnBeforeFoo().
+ using AfterEvent = void (AutofillManager::Observer::*)();
+
+ explicit TestAutofillManagerWaiter(
+ AutofillManager& manager,
+ std::initializer_list<AfterEvent> relevant_events = {});
+ ~TestAutofillManagerWaiter() override;
+
+ // Blocks until all pending OnAfterFoo() events have been observed and at
+ // least `num_awaiting_calls` relevant events have been observed.
+ [[nodiscard]] testing::AssertionResult Wait(size_t num_awaiting_calls = 0);
+
+ // Equivalent to re-initialization.
+ void Reset();
+
+ // The timeout of the RunLoop.
+ base::TimeDelta timeout() const { return timeout_; }
+ void set_timeout(base::TimeDelta timeout) { timeout_ = timeout; }
+
+ private:
+ struct EventCount {
+ // An AutofillManager::Observer::OnAfterFoo() event.
+ AfterEvent event;
+ // The OnBeforeFoo() function. Used for meaningful error messages.
+ base::Location location;
+ // The total number of recorded OnBeforeFoo() events.
+ size_t num_total_calls = 0;
+ // The number of recorded OnBeforeFoo() events without a corresponding
+ // OnAfterFoo() event.
+ size_t num_pending_calls = 0;
+ };
+
+ // State variables for easy resetting.
+ struct State {
+ State();
+ State(State&) = delete;
+ State& operator=(State&) = delete;
+ ~State();
+
+ EventCount& GetOrCreate(AfterEvent event, base::Location location);
+ EventCount* Get(AfterEvent event);
+
+ size_t num_total_calls() const;
+ size_t num_pending_calls() const;
+
+ std::string Describe() const;
+
+ // Effectively a map from `AfterEvent` to its count. Since `AfterEvent` is
+ // only equality-comparable, we use a list. (The list, rather than a vector,
+ // avoids invalidation of the references returned by GetOrCreate().)
+ std::list<EventCount> events;
+ // Decrement() unblocks Wait() when the number of awaited calls reaches 0.
+ size_t num_awaiting_total_calls = std::numeric_limits<size_t>::max();
+ // Running iff there are no awaited and no pending calls.
+ base::RunLoop run_loop = base::RunLoop();
+ // Functions that access the state should be mutually exclusive.
+ base::Lock lock;
+ };
+
+ bool IsRelevant(AfterEvent event) const;
+ void Increment(AfterEvent event,
+ base::Location location = base::Location::Current());
+ void Decrement(AfterEvent event,
+ base::Location location = base::Location::Current());
+
+ void OnAutofillManagerDestroyed() override;
+ void OnAutofillManagerReset() override;
+
+ void OnBeforeLanguageDetermined() override;
+ void OnAfterLanguageDetermined() override;
+
+ void OnBeforeFormsSeen() override;
+ void OnAfterFormsSeen() override;
+
+ void OnBeforeTextFieldDidChange() override;
+ void OnAfterTextFieldDidChange() override;
+
+ void OnBeforeAskForValuesToFill() override;
+ void OnAfterAskForValuesToFill() override;
+
+ void OnBeforeDidFillAutofillFormData() override;
+ void OnAfterDidFillAutofillFormData() override;
+
+ void OnBeforeJavaScriptChangedAutofilledValue() override;
+ void OnAfterJavaScriptChangedAutofilledValue() override;
+
+ std::vector<AfterEvent> relevant_events_;
+ std::unique_ptr<State> state_ = std::make_unique<State>();
+ base::TimeDelta timeout_ = base::Seconds(5);
+ base::ScopedObservation<AutofillManager, AutofillManager::Observer>
+ observation_{this};
+};
+
+} // namespace autofill
+
+#endif // COMPONENTS_AUTOFILL_CORE_BROWSER_TEST_AUTOFILL_MANAGER_WAITER_H_
diff --git a/chromium/components/autofill/core/browser/test_browser_autofill_manager.cc b/chromium/components/autofill/core/browser/test_browser_autofill_manager.cc
index c51a3563b23..414bbccafd4 100644
--- a/chromium/components/autofill/core/browser/test_browser_autofill_manager.cc
+++ b/chromium/components/autofill/core/browser/test_browser_autofill_manager.cc
@@ -4,15 +4,18 @@
#include "components/autofill/core/browser/test_browser_autofill_manager.h"
+#include "autofill_test_utils.h"
#include "base/strings/stringprintf.h"
#include "base/strings/utf_string_conversions.h"
#include "components/autofill/core/browser/autofill_suggestion_generator.h"
#include "components/autofill/core/browser/field_types.h"
+#include "components/autofill/core/browser/form_structure.h"
#include "components/autofill/core/browser/mock_single_field_form_fill_router.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_form_structure.h"
+#include "components/autofill/core/browser/test_autofill_manager_waiter.h"
#include "components/autofill/core/browser/test_personal_data_manager.h"
+#include "form_structure_test_api.h"
#include "services/network/public/cpp/shared_url_loader_factory.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -30,6 +33,76 @@ TestBrowserAutofillManager::TestBrowserAutofillManager(
TestBrowserAutofillManager::~TestBrowserAutofillManager() = default;
+void TestBrowserAutofillManager::OnLanguageDetermined(
+ const translate::LanguageDetectionDetails& details) {
+ TestAutofillManagerWaiter waiter(
+ *this, {&AutofillManager::Observer::OnAfterLanguageDetermined});
+ AutofillManager::OnLanguageDetermined(details);
+ ASSERT_TRUE(waiter.Wait());
+}
+
+void TestBrowserAutofillManager::OnFormsSeen(
+ const std::vector<FormData>& updated_forms,
+ const std::vector<FormGlobalId>& removed_forms) {
+ TestAutofillManagerWaiter waiter(*this, {&Observer::OnAfterFormsSeen});
+ AutofillManager::OnFormsSeen(updated_forms, removed_forms);
+ ASSERT_TRUE(waiter.Wait());
+}
+
+void TestBrowserAutofillManager::OnTextFieldDidChange(
+ const FormData& form,
+ const FormFieldData& field,
+ const gfx::RectF& bounding_box,
+ const base::TimeTicks timestamp) {
+ TestAutofillManagerWaiter waiter(*this,
+ {&Observer::OnAfterTextFieldDidChange});
+ AutofillManager::OnTextFieldDidChange(form, field, bounding_box, timestamp);
+ ASSERT_TRUE(waiter.Wait());
+}
+
+void TestBrowserAutofillManager::OnDidFillAutofillFormData(
+ const FormData& form,
+ const base::TimeTicks timestamp) {
+ TestAutofillManagerWaiter waiter(*this,
+ {&Observer::OnAfterDidFillAutofillFormData});
+ AutofillManager::OnDidFillAutofillFormData(form, timestamp);
+ ASSERT_TRUE(waiter.Wait());
+}
+
+void TestBrowserAutofillManager::OnAskForValuesToFill(
+ const FormData& form,
+ const FormFieldData& field,
+ const gfx::RectF& bounding_box,
+ int query_id,
+ bool autoselect_first_suggestion,
+ TouchToFillEligible touch_to_fill_eligible) {
+ TestAutofillManagerWaiter waiter(*this,
+ {&Observer::OnAfterAskForValuesToFill});
+ AutofillManager::OnAskForValuesToFill(form, field, bounding_box, query_id,
+ autoselect_first_suggestion,
+ touch_to_fill_eligible);
+ ASSERT_TRUE(waiter.Wait());
+}
+
+void TestBrowserAutofillManager::OnJavaScriptChangedAutofilledValue(
+ const FormData& form,
+ const FormFieldData& field,
+ const std::u16string& old_value) {
+ TestAutofillManagerWaiter waiter(
+ *this, {&Observer::OnAfterJavaScriptChangedAutofilledValue});
+ AutofillManager::OnJavaScriptChangedAutofilledValue(form, field, old_value);
+ ASSERT_TRUE(waiter.Wait());
+}
+
+void TestBrowserAutofillManager::OnFormSubmitted(
+ const FormData& form,
+ const bool known_success,
+ const mojom::SubmissionSource source) {
+ TestAutofillManagerWaiter waiter(*this, {&Observer::OnAfterFormsSeen});
+ AutofillManager::OnFormSubmitted(form, known_success, source);
+ ASSERT_TRUE(waiter.Wait());
+}
+
bool TestBrowserAutofillManager::IsAutofillProfileEnabled() const {
return autofill_profile_enabled_;
}
@@ -107,37 +180,51 @@ int TestBrowserAutofillManager::GetPackedCreditCardID(int credit_card_id) {
void TestBrowserAutofillManager::AddSeenForm(
const FormData& form,
const std::vector<ServerFieldType>& heuristic_types,
- const std::vector<ServerFieldType>& server_types) {
+ const std::vector<ServerFieldType>& server_types,
+ bool preserve_values_in_form_structure) {
std::vector<std::vector<std::pair<PatternSource, ServerFieldType>>>
all_heuristic_types;
-
- base::ranges::transform(
- heuristic_types, std::back_inserter(all_heuristic_types),
- [](ServerFieldType type)
- -> std::vector<std::pair<PatternSource, ServerFieldType>> {
- return {{GetActivePatternSource(), type}};
- });
-
- AddSeenForm(form, all_heuristic_types, server_types);
+ for (ServerFieldType type : heuristic_types)
+ all_heuristic_types.push_back({{GetActivePatternSource(), type}});
+ AddSeenForm(form, all_heuristic_types, server_types,
+ preserve_values_in_form_structure);
}
void TestBrowserAutofillManager::AddSeenForm(
const FormData& form,
const std::vector<std::vector<std::pair<PatternSource, ServerFieldType>>>&
heuristic_types,
+ const std::vector<ServerFieldType>& server_types,
+ bool preserve_values_in_form_structure) {
+ auto form_structure = std::make_unique<FormStructure>(
+ preserve_values_in_form_structure ? form : test::WithoutValues(form));
+ FormGlobalId form_id = form_structure->global_id();
+ AddSeenFormStructure(std::move(form_structure));
+ SetSeenFormPredictions(form_id, heuristic_types, server_types);
+ form_interactions_ukm_logger()->OnFormsParsed(client()->GetUkmSourceId());
+}
+
+void TestBrowserAutofillManager::SetSeenFormPredictions(
+ FormGlobalId form_id,
+ const std::vector<ServerFieldType>& heuristic_types,
const std::vector<ServerFieldType>& server_types) {
- FormData empty_form = form;
- for (auto& field : empty_form.fields) {
- field.value = std::u16string();
- }
+ std::vector<std::vector<std::pair<PatternSource, ServerFieldType>>>
+ all_heuristic_types;
+ for (ServerFieldType type : heuristic_types)
+ all_heuristic_types.push_back({{GetActivePatternSource(), type}});
+ SetSeenFormPredictions(form_id, all_heuristic_types, server_types);
+}
- std::unique_ptr<TestFormStructure> form_structure =
- std::make_unique<TestFormStructure>(empty_form);
- form_structure->SetFieldTypes(heuristic_types, server_types);
+void TestBrowserAutofillManager::SetSeenFormPredictions(
+ FormGlobalId form_id,
+ const std::vector<std::vector<std::pair<PatternSource, ServerFieldType>>>&
+ heuristic_types,
+ const std::vector<ServerFieldType>& server_types) {
+ FormStructure* form_structure = FindCachedFormByRendererId(form_id);
+ ASSERT_TRUE(form_structure);
+ FormStructureTestApi(form_structure)
+ .SetFieldTypes(heuristic_types, server_types);
form_structure->identify_sections_for_testing();
- AddSeenFormStructure(std::move(form_structure));
-
- form_interactions_ukm_logger()->OnFormsParsed(client()->GetUkmSourceId());
}
void TestBrowserAutofillManager::AddSeenFormStructure(
@@ -161,9 +248,12 @@ void TestBrowserAutofillManager::OnAskForValuesToFillTest(
const gfx::RectF& bounding_box,
bool autoselect_first_suggestion,
TouchToFillEligible touch_to_fill_eligible) {
+ TestAutofillManagerWaiter waiter(
+ *this, {&AutofillManager::Observer::OnAfterAskForValuesToFill});
BrowserAutofillManager::OnAskForValuesToFill(
- query_id, form, field, bounding_box, autoselect_first_suggestion,
+ form, field, bounding_box, query_id, autoselect_first_suggestion,
touch_to_fill_eligible);
+ ASSERT_TRUE(waiter.Wait());
}
void TestBrowserAutofillManager::SetAutofillProfileEnabled(
diff --git a/chromium/components/autofill/core/browser/test_browser_autofill_manager.h b/chromium/components/autofill/core/browser/test_browser_autofill_manager.h
index 422bf0e0d49..f017a080f3a 100644
--- a/chromium/components/autofill/core/browser/test_browser_autofill_manager.h
+++ b/chromium/components/autofill/core/browser/test_browser_autofill_manager.h
@@ -37,6 +37,34 @@ class TestBrowserAutofillManager : public BrowserAutofillManager {
TestAutofillClient* client() { return client_; }
TestAutofillDriver* driver() { return driver_; }
+ // AutofillManager overrides.
+ // The overrides ensure that the thread is blocked until the form has been
+ // parsed (perhaps asynchronously, depending on AutofillParseAsync).
+ void OnLanguageDetermined(
+ const translate::LanguageDetectionDetails& details) override;
+ void OnFormsSeen(const std::vector<FormData>& updated_forms,
+ const std::vector<FormGlobalId>& removed_forms) override;
+ void OnTextFieldDidChange(const FormData& form,
+ const FormFieldData& field,
+ const gfx::RectF& bounding_box,
+ const base::TimeTicks timestamp) override;
+ void OnDidFillAutofillFormData(const FormData& form,
+ const base::TimeTicks timestamp) override;
+ void OnAskForValuesToFill(
+ const FormData& form,
+ const FormFieldData& field,
+ const gfx::RectF& bounding_box,
+ int query_id,
+ bool autoselect_first_suggestion,
+ TouchToFillEligible touch_to_fill_eligible) override;
+ void OnJavaScriptChangedAutofilledValue(
+ const FormData& form,
+ const FormFieldData& field,
+ const std::u16string& old_value) override;
+ void OnFormSubmitted(const FormData& form,
+ const bool known_success,
+ const mojom::SubmissionSource source) override;
+
// BrowserAutofillManager overrides.
bool IsAutofillProfileEnabled() const override;
bool IsAutofillCreditCardEnabled() const override;
@@ -58,12 +86,25 @@ class TestBrowserAutofillManager : public BrowserAutofillManager {
void AddSeenForm(const FormData& form,
const std::vector<ServerFieldType>& heuristic_types,
- const std::vector<ServerFieldType>& server_types);
+ const std::vector<ServerFieldType>& server_types,
+ bool preserve_values_in_form_structure = false);
void AddSeenForm(
const FormData& form,
const std::vector<std::vector<std::pair<PatternSource, ServerFieldType>>>&
heuristic_types,
+ const std::vector<ServerFieldType>& server_types,
+ bool preserve_values_in_form_structure = false);
+
+ void SetSeenFormPredictions(
+ FormGlobalId form_id,
+ const std::vector<ServerFieldType>& heuristic_types,
+ const std::vector<ServerFieldType>& server_types);
+
+ void SetSeenFormPredictions(
+ FormGlobalId form_id,
+ const std::vector<std::vector<std::pair<PatternSource, ServerFieldType>>>&
+ heuristic_types,
const std::vector<ServerFieldType>& server_types);
void AddSeenFormStructure(std::unique_ptr<FormStructure> form_structure);
diff --git a/chromium/components/autofill/core/browser/test_event_waiter.h b/chromium/components/autofill/core/browser/test_event_waiter.h
index b3d4ded4341..b9e228acfd9 100644
--- a/chromium/components/autofill/core/browser/test_event_waiter.h
+++ b/chromium/components/autofill/core/browser/test_event_waiter.h
@@ -11,7 +11,6 @@
#include "base/run_loop.h"
#include "base/threading/thread_task_runner_handle.h"
#include "base/time/time.h"
-#include "testing/gtest/include/gtest/gtest.h"
namespace autofill {
diff --git a/chromium/components/autofill/core/browser/test_form_data_importer.h b/chromium/components/autofill/core/browser/test_form_data_importer.h
index 775deefc9fa..12dbe2e9bf4 100644
--- a/chromium/components/autofill/core/browser/test_form_data_importer.h
+++ b/chromium/components/autofill/core/browser/test_form_data_importer.h
@@ -23,6 +23,10 @@ class TestFormDataImporter : public FormDataImporter {
std::unique_ptr<LocalCardMigrationManager> local_card_migration_manager =
nullptr);
~TestFormDataImporter() override = default;
+
+ absl::optional<int64_t> fetched_card_instrument_id() {
+ return fetched_card_instrument_id_;
+ }
};
} // namespace autofill
diff --git a/chromium/components/autofill/core/browser/test_form_structure.h b/chromium/components/autofill/core/browser/test_form_structure.h
deleted file mode 100644
index b4fd0258e91..00000000000
--- a/chromium/components/autofill/core/browser/test_form_structure.h
+++ /dev/null
@@ -1,43 +0,0 @@
-// Copyright 2017 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_TEST_FORM_STRUCTURE_H_
-#define COMPONENTS_AUTOFILL_CORE_BROWSER_TEST_FORM_STRUCTURE_H_
-
-#include <vector>
-
-#include "components/autofill/core/browser/form_parsing/field_candidates.h"
-#include "components/autofill/core/browser/form_structure.h"
-
-namespace autofill {
-
-class TestFormStructure : public FormStructure {
- public:
- explicit TestFormStructure(const FormData& form);
-
- TestFormStructure(const TestFormStructure&) = delete;
- TestFormStructure& operator=(const TestFormStructure&) = delete;
-
- ~TestFormStructure() override;
-
- // Set the heuristic and server types for each field. The `heuristic_types`
- // and `server_types` vectors must be aligned with the indices of the fields
- // in the form.
- void SetFieldTypes(const std::vector<ServerFieldType>& heuristic_types,
- const std::vector<ServerFieldType>& server_types);
-
- // Set the heuristic and server types for each field. The `heuristic_types`
- // and `server_types` vectors must be aligned with the indices of the fields
- // in the form. For each field in `heuristic_types` there must be exactly one
- // `GetActivePatternSource()` prediction and any number of alternative
- // predictions.
- void SetFieldTypes(
- const std::vector<std::vector<std::pair<PatternSource, ServerFieldType>>>&
- heuristic_types,
- const std::vector<ServerFieldType>& server_types);
-};
-
-} // namespace autofill
-
-#endif // COMPONENTS_AUTOFILL_CORE_BROWSER_TEST_FORM_STRUCTURE_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 0eb5bb147a7..fbb123b8556 100644
--- a/chromium/components/autofill/core/browser/test_personal_data_manager.cc
+++ b/chromium/components/autofill/core/browser/test_personal_data_manager.cc
@@ -214,8 +214,20 @@ void TestPersonalDataManager::LoadCreditCardCloudTokenData() {
}
}
+void TestPersonalDataManager::LoadIBANs() {
+ pending_ibans_query_ = 128;
+ {
+ std::vector<std::unique_ptr<IBAN>> ibans;
+ local_ibans_.swap(ibans);
+ std::unique_ptr<WDTypedResult> result =
+ std::make_unique<WDResult<std::vector<std::unique_ptr<IBAN>>>>(
+ AUTOFILL_IBANS_RESULT, std::move(ibans));
+ OnWebDataServiceRequestDone(pending_ibans_query_, std::move(result));
+ }
+}
+
void TestPersonalDataManager::LoadUpiIds() {
- pending_upi_ids_query_ = 128;
+ pending_upi_ids_query_ = 129;
{
std::vector<std::string> upi_ids = {"vpa@indianbank"};
std::unique_ptr<WDTypedResult> result =
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 c97952560e7..b42fd4c7ab8 100644
--- a/chromium/components/autofill/core/browser/test_personal_data_manager.h
+++ b/chromium/components/autofill/core/browser/test_personal_data_manager.h
@@ -59,6 +59,7 @@ class TestPersonalDataManager : public PersonalDataManager {
void LoadProfiles() override;
void LoadCreditCards() override;
void LoadCreditCardCloudTokenData() override;
+ void LoadIBANs() override;
void LoadUpiIds() override;
bool IsAutofillEnabled() const override;
bool IsAutofillProfileEnabled() const override;
diff --git a/chromium/components/autofill/core/browser/touch_to_fill_delegate.cc b/chromium/components/autofill/core/browser/touch_to_fill_delegate.cc
deleted file mode 100644
index 55af4f1d8d9..00000000000
--- a/chromium/components/autofill/core/browser/touch_to_fill_delegate.cc
+++ /dev/null
@@ -1,19 +0,0 @@
-// Copyright 2022 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/touch_to_fill_delegate.h"
-
-namespace autofill {
-
-TouchToFillDelegate::TouchToFillDelegate() = default;
-TouchToFillDelegate::~TouchToFillDelegate() = default;
-
-bool TouchToFillDelegate::TryToShowTouchToFill(int query_id,
- const FormData& form,
- const FormFieldData& field) {
- // TODO(crbug.com/1247698): Add eligibility checks and trigger TTF.
- return false;
-}
-
-} // namespace autofill
diff --git a/chromium/components/autofill/core/browser/touch_to_fill_delegate.h b/chromium/components/autofill/core/browser/touch_to_fill_delegate.h
deleted file mode 100644
index 2bea4e8cbe9..00000000000
--- a/chromium/components/autofill/core/browser/touch_to_fill_delegate.h
+++ /dev/null
@@ -1,31 +0,0 @@
-// Copyright 2022 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_TOUCH_TO_FILL_DELEGATE_H_
-#define COMPONENTS_AUTOFILL_CORE_BROWSER_TOUCH_TO_FILL_DELEGATE_H_
-
-#include "components/autofill/core/common/form_data.h"
-#include "components/autofill/core/common/form_field_data.h"
-
-namespace autofill {
-
-// Delegate for in-browser Touch To Fill (TTF) surface display and selection.
-// TODO(crbug.com/1324900): Consider using more descriptive name.
-class TouchToFillDelegate {
- public:
- TouchToFillDelegate();
- TouchToFillDelegate(const TouchToFillDelegate&) = delete;
- TouchToFillDelegate& operator=(const TouchToFillDelegate&) = delete;
- virtual ~TouchToFillDelegate();
-
- // Checks whether TTF is eligible for the given web form data. On success
- // triggers the corresponding surface and returns |true|.
- virtual bool TryToShowTouchToFill(int query_id,
- const FormData& form,
- const FormFieldData& field);
-};
-
-} // namespace autofill
-
-#endif // COMPONENTS_AUTOFILL_CORE_BROWSER_TOUCH_TO_FILL_DELEGATE_H_
diff --git a/chromium/components/autofill/core/browser/touch_to_fill_delegate_impl.cc b/chromium/components/autofill/core/browser/touch_to_fill_delegate_impl.cc
new file mode 100644
index 00000000000..e71d78a50d2
--- /dev/null
+++ b/chromium/components/autofill/core/browser/touch_to_fill_delegate_impl.cc
@@ -0,0 +1,86 @@
+// Copyright 2022 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/touch_to_fill_delegate_impl.h"
+
+#include "components/autofill/core/browser/browser_autofill_manager.h"
+#include "components/autofill/core/common/autofill_clock.h"
+#include "components/autofill/core/common/autofill_util.h"
+
+namespace autofill {
+
+TouchToFillDelegateImpl::TouchToFillDelegateImpl(
+ BrowserAutofillManager* manager)
+ : manager_(manager) {
+ DCHECK(manager);
+}
+
+TouchToFillDelegateImpl::~TouchToFillDelegateImpl() = default;
+
+bool TouchToFillDelegateImpl::TryToShowTouchToFill(int query_id,
+ const FormData& form,
+ const FormFieldData& field) {
+ // Trigger only for a credit card field/form.
+ // TODO(crbug.com/1247698): Clarify field/form requirements.
+ if (manager_->GetPopupType(form, field) != PopupType::kCreditCards)
+ return false;
+ // Trigger only on supported platforms.
+ if (!manager_->client()->IsTouchToFillCreditCardSupported())
+ return false;
+ // Trigger only if not shown before.
+ if (ttf_credit_card_state_ != TouchToFillState::kShouldShow)
+ return false;
+ // Trigger only on focusable empty field.
+ if (!field.is_focusable || !SanitizedFieldIsEmpty(field.value))
+ return false;
+ // Trigger only if there is at least 1 complete valid credit card on file.
+ // Complete = contains number, expiration date and name on card.
+ // Valid = unexpired with valid number format.
+ PersonalDataManager* pdm = manager_->client()->GetPersonalDataManager();
+ DCHECK(pdm);
+ std::vector<CreditCard*> cards_to_suggest = pdm->GetCreditCardsToSuggest(
+ manager_->client()->AreServerCardsSupported());
+ auto NotACompleteValidCard = [](const CreditCard* card) {
+ return card->IsExpired(AutofillClock::Now()) || !card->HasNameOnCard() ||
+ (card->record_type() != autofill::CreditCard::MASKED_SERVER_CARD &&
+ !card->HasValidCardNumber());
+ };
+ base::EraseIf(cards_to_suggest, NotACompleteValidCard);
+ if (cards_to_suggest.empty())
+ return false;
+ // Trigger only if the UI is available.
+ if (!manager_->driver()->CanShowAutofillUi())
+ return false;
+ // Finally try showing the surface.
+ if (!manager_->client()->ShowTouchToFillCreditCard(GetWeakPtr()))
+ return false;
+
+ ttf_credit_card_state_ = TouchToFillState::kIsShowing;
+ manager_->client()->HideAutofillPopup(
+ PopupHidingReason::kOverlappingWithTouchToFillSurface);
+ return true;
+}
+
+bool TouchToFillDelegateImpl::IsShowingTouchToFill() {
+ return ttf_credit_card_state_ == TouchToFillState::kIsShowing;
+}
+
+// TODO(crbug.com/1348538): Create a central point for TTF hiding decision.
+void TouchToFillDelegateImpl::HideTouchToFill() {
+ if (IsShowingTouchToFill()) {
+ manager_->client()->HideTouchToFillCreditCard();
+ ttf_credit_card_state_ = TouchToFillState::kWasShown;
+ }
+}
+
+void TouchToFillDelegateImpl::Reset() {
+ HideTouchToFill();
+ ttf_credit_card_state_ = TouchToFillState::kShouldShow;
+}
+
+base::WeakPtr<TouchToFillDelegateImpl> TouchToFillDelegateImpl::GetWeakPtr() {
+ return weak_ptr_factory_.GetWeakPtr();
+}
+
+} // namespace autofill
diff --git a/chromium/components/autofill/core/browser/touch_to_fill_delegate_impl.h b/chromium/components/autofill/core/browser/touch_to_fill_delegate_impl.h
new file mode 100644
index 00000000000..7e5b98a60ca
--- /dev/null
+++ b/chromium/components/autofill/core/browser/touch_to_fill_delegate_impl.h
@@ -0,0 +1,69 @@
+// Copyright 2022 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_TOUCH_TO_FILL_DELEGATE_IMPL_H_
+#define COMPONENTS_AUTOFILL_CORE_BROWSER_TOUCH_TO_FILL_DELEGATE_IMPL_H_
+
+#include "base/memory/weak_ptr.h"
+#include "components/autofill/core/browser/ui/touch_to_fill_delegate.h"
+#include "components/autofill/core/common/form_data.h"
+#include "components/autofill/core/common/form_field_data.h"
+
+namespace autofill {
+
+class BrowserAutofillManager;
+
+// Delegate for in-browser Touch To Fill (TTF) surface display and selection.
+// Currently TTF surface is eligible only for credit card forms on click on
+// an empty focusable field.
+//
+// If the surface was shown once, it won't be triggered again on the same page.
+// But calling |Reset()| on navigation restores such showing eligibility.
+//
+// It is supposed to be owned by the given |BrowserAutofillManager|, and
+// interact with it and its |AutofillClient| and |AutofillDriver|.
+//
+// Public methods are marked virtual for testing.
+// TODO(crbug.com/1324900): Consider using more descriptive name.
+class TouchToFillDelegateImpl : public TouchToFillDelegate {
+ public:
+ explicit TouchToFillDelegateImpl(BrowserAutofillManager* manager);
+ TouchToFillDelegateImpl(const TouchToFillDelegateImpl&) = delete;
+ TouchToFillDelegateImpl& operator=(const TouchToFillDelegateImpl&) = delete;
+ ~TouchToFillDelegateImpl() override;
+
+ // Checks whether TTF is eligible for the given web form data. On success
+ // triggers the corresponding surface and returns |true|.
+ virtual bool TryToShowTouchToFill(int query_id,
+ const FormData& form,
+ const FormFieldData& field);
+
+ // Returns whether the TTF surface is currently being shown.
+ virtual bool IsShowingTouchToFill();
+
+ // Hides the TTF surface if one is shown.
+ virtual void HideTouchToFill();
+
+ // Resets the delegate to its starting state (e.g. on navigation).
+ virtual void Reset();
+
+ private:
+ base::WeakPtr<TouchToFillDelegateImpl> GetWeakPtr();
+
+ enum class TouchToFillState {
+ kShouldShow,
+ kIsShowing,
+ kWasShown,
+ };
+
+ TouchToFillState ttf_credit_card_state_ = TouchToFillState::kShouldShow;
+
+ const raw_ptr<BrowserAutofillManager> manager_;
+
+ base::WeakPtrFactory<TouchToFillDelegateImpl> weak_ptr_factory_{this};
+};
+
+} // namespace autofill
+
+#endif // COMPONENTS_AUTOFILL_CORE_BROWSER_TOUCH_TO_FILL_DELEGATE_IMPL_H_
diff --git a/chromium/components/autofill/core/browser/touch_to_fill_delegate_impl_unittest.cc b/chromium/components/autofill/core/browser/touch_to_fill_delegate_impl_unittest.cc
new file mode 100644
index 00000000000..37e6fde6b72
--- /dev/null
+++ b/chromium/components/autofill/core/browser/touch_to_fill_delegate_impl_unittest.cc
@@ -0,0 +1,297 @@
+// Copyright 2022 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/touch_to_fill_delegate_impl.h"
+#include "base/test/task_environment.h"
+#include "components/autofill/core/browser/autofill_test_utils.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_browser_autofill_manager.h"
+#include "components/autofill/core/common/autofill_clock.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+using testing::_;
+using testing::NiceMock;
+using testing::Ref;
+using testing::Return;
+
+namespace autofill {
+
+namespace {
+
+// A constant value to use as a suggestions query ID.
+const int kQueryId = 1;
+
+class MockAutofillDriver : public TestAutofillDriver {
+ public:
+ MockAutofillDriver() = default;
+ MockAutofillDriver(const MockAutofillDriver&) = delete;
+ MockAutofillDriver& operator=(const MockAutofillDriver&) = delete;
+ ~MockAutofillDriver() override = default;
+
+ MOCK_METHOD(bool, CanShowAutofillUi, (), (const, override));
+};
+
+class MockAutofillClient : public TestAutofillClient {
+ public:
+ MockAutofillClient() = default;
+ MockAutofillClient(const MockAutofillClient&) = delete;
+ MockAutofillClient& operator=(const MockAutofillClient&) = delete;
+ ~MockAutofillClient() override = default;
+
+ MOCK_METHOD(bool, IsTouchToFillCreditCardSupported, (), (override));
+ MOCK_METHOD(bool,
+ ShowTouchToFillCreditCard,
+ (base::WeakPtr<autofill::TouchToFillDelegate>),
+ (override));
+ MOCK_METHOD(void, HideTouchToFillCreditCard, (), (override));
+ MOCK_METHOD(void, HideAutofillPopup, (PopupHidingReason reason), (override));
+};
+
+class MockBrowserAutofillManager : public TestBrowserAutofillManager {
+ public:
+ MockBrowserAutofillManager(TestAutofillDriver* driver,
+ TestAutofillClient* client)
+ : TestBrowserAutofillManager(driver, client) {}
+ MockBrowserAutofillManager(const MockBrowserAutofillManager&) = delete;
+ MockBrowserAutofillManager& operator=(const MockBrowserAutofillManager&) =
+ delete;
+ ~MockBrowserAutofillManager() override = default;
+
+ MOCK_METHOD(PopupType,
+ GetPopupType,
+ (const FormData& form, const FormFieldData& field),
+ (override));
+};
+
+} // namespace
+
+class TouchToFillDelegateImplUnitTest : public testing::Test {
+ protected:
+ void SetUp() override {
+ autofill_client_.SetPrefs(test::PrefServiceForTesting());
+ autofill_client_.GetPersonalDataManager()->SetPrefService(
+ autofill_client_.GetPrefs());
+ autofill_driver_ = std::make_unique<NiceMock<MockAutofillDriver>>();
+ browser_autofill_manager_ =
+ std::make_unique<NiceMock<MockBrowserAutofillManager>>(
+ autofill_driver_.get(), &autofill_client_);
+ touch_to_fill_delegate_ = std::make_unique<TouchToFillDelegateImpl>(
+ browser_autofill_manager_.get());
+
+ // Default setup for successful |TryToShowTouchToFill|.
+ field_.is_focusable = true;
+ autofill_client_.GetPersonalDataManager()->AddCreditCard(
+ test::GetCreditCard());
+ ON_CALL(*browser_autofill_manager_, GetPopupType(_, _))
+ .WillByDefault(Return(PopupType::kCreditCards));
+ ON_CALL(autofill_client_, IsTouchToFillCreditCardSupported)
+ .WillByDefault(Return(true));
+ ON_CALL(*autofill_driver_, CanShowAutofillUi).WillByDefault(Return(true));
+ ON_CALL(autofill_client_, ShowTouchToFillCreditCard)
+ .WillByDefault(Return(true));
+ }
+
+ void TearDown() override {
+ browser_autofill_manager_.reset();
+ touch_to_fill_delegate_.reset();
+ autofill_driver_.reset();
+ }
+
+ void TryToShowTouchToFill(bool expected_success) {
+ EXPECT_CALL(autofill_client_,
+ HideAutofillPopup(
+ PopupHidingReason::kOverlappingWithTouchToFillSurface))
+ .Times(expected_success ? 1 : 0);
+ EXPECT_EQ(expected_success, touch_to_fill_delegate_->TryToShowTouchToFill(
+ kQueryId, form_, field_));
+ EXPECT_EQ(expected_success,
+ touch_to_fill_delegate_->IsShowingTouchToFill());
+ }
+
+ FormData form_;
+ FormFieldData field_;
+
+ base::test::TaskEnvironment task_environment_;
+ NiceMock<MockAutofillClient> autofill_client_;
+ std::unique_ptr<NiceMock<MockAutofillDriver>> autofill_driver_;
+ std::unique_ptr<TouchToFillDelegateImpl> touch_to_fill_delegate_;
+ std::unique_ptr<MockBrowserAutofillManager> browser_autofill_manager_;
+};
+
+TEST_F(TouchToFillDelegateImplUnitTest, TryToShowTouchToFillSucceeds) {
+ ASSERT_FALSE(touch_to_fill_delegate_->IsShowingTouchToFill());
+
+ TryToShowTouchToFill(/*expected_success=*/true);
+}
+
+TEST_F(TouchToFillDelegateImplUnitTest,
+ TryToShowTouchToFillFailsIfNotCreditCardField) {
+ ASSERT_FALSE(touch_to_fill_delegate_->IsShowingTouchToFill());
+ EXPECT_CALL(*browser_autofill_manager_, GetPopupType(Ref(form_), Ref(field_)))
+ .WillOnce(Return(PopupType::kAddresses));
+
+ TryToShowTouchToFill(/*expected_success=*/false);
+}
+
+TEST_F(TouchToFillDelegateImplUnitTest,
+ TryToShowTouchToFillFailsIfNotSupported) {
+ ASSERT_FALSE(touch_to_fill_delegate_->IsShowingTouchToFill());
+ EXPECT_CALL(autofill_client_, IsTouchToFillCreditCardSupported)
+ .WillOnce(Return(false));
+
+ TryToShowTouchToFill(/*expected_success=*/false);
+}
+
+TEST_F(TouchToFillDelegateImplUnitTest,
+ TryToShowTouchToFillFailsIfAlreadyShown) {
+ TryToShowTouchToFill(/*expected_success=*/true);
+
+ EXPECT_CALL(
+ autofill_client_,
+ HideAutofillPopup(PopupHidingReason::kOverlappingWithTouchToFillSurface))
+ .Times(0);
+ EXPECT_FALSE(
+ touch_to_fill_delegate_->TryToShowTouchToFill(kQueryId, form_, field_));
+ EXPECT_TRUE(touch_to_fill_delegate_->IsShowingTouchToFill());
+}
+
+TEST_F(TouchToFillDelegateImplUnitTest, TryToShowTouchToFillFailsIfWasShown) {
+ TryToShowTouchToFill(/*expected_success=*/true);
+ touch_to_fill_delegate_->HideTouchToFill();
+
+ TryToShowTouchToFill(/*expected_success=*/false);
+}
+
+TEST_F(TouchToFillDelegateImplUnitTest,
+ TryToShowTouchToFillFailsIfFieldIsNotFocusable) {
+ ASSERT_FALSE(touch_to_fill_delegate_->IsShowingTouchToFill());
+ field_.is_focusable = false;
+
+ TryToShowTouchToFill(/*expected_success=*/false);
+}
+
+TEST_F(TouchToFillDelegateImplUnitTest,
+ TryToShowTouchToFillFailsIfFieldHasValue) {
+ ASSERT_FALSE(touch_to_fill_delegate_->IsShowingTouchToFill());
+ field_.value = u"Initial value";
+
+ TryToShowTouchToFill(/*expected_success=*/false);
+
+ // But should ignore formatting characters.
+ field_.value = u"____-____-____-____";
+
+ TryToShowTouchToFill(/*expected_success=*/true);
+}
+
+TEST_F(TouchToFillDelegateImplUnitTest,
+ TryToShowTouchToFillFailsIfNoCardsOnFile) {
+ ASSERT_FALSE(touch_to_fill_delegate_->IsShowingTouchToFill());
+ autofill_client_.GetPersonalDataManager()->ClearCreditCards();
+
+ TryToShowTouchToFill(/*expected_success=*/false);
+}
+
+TEST_F(TouchToFillDelegateImplUnitTest,
+ TryToShowTouchToFillFailsIfCardIsIncomplete) {
+ ASSERT_FALSE(touch_to_fill_delegate_->IsShowingTouchToFill());
+ autofill_client_.GetPersonalDataManager()->ClearCreditCards();
+ CreditCard cc_no_number = test::GetCreditCard();
+ cc_no_number.SetNumber(u"");
+ autofill_client_.GetPersonalDataManager()->AddCreditCard(cc_no_number);
+
+ TryToShowTouchToFill(/*expected_success=*/false);
+
+ CreditCard cc_no_exp_date = test::GetCreditCard();
+ cc_no_exp_date.SetExpirationMonth(0);
+ cc_no_exp_date.SetExpirationYear(0);
+ autofill_client_.GetPersonalDataManager()->AddCreditCard(cc_no_exp_date);
+
+ TryToShowTouchToFill(/*expected_success=*/false);
+
+ CreditCard cc_no_name = test::GetCreditCard();
+ cc_no_name.SetRawInfo(CREDIT_CARD_NAME_FULL, u"");
+ autofill_client_.GetPersonalDataManager()->AddCreditCard(cc_no_name);
+
+ TryToShowTouchToFill(/*expected_success=*/false);
+}
+
+TEST_F(TouchToFillDelegateImplUnitTest,
+ TryToShowTouchToFillFailsIfCardIsExpired) {
+ ASSERT_FALSE(touch_to_fill_delegate_->IsShowingTouchToFill());
+ autofill_client_.GetPersonalDataManager()->ClearCreditCards();
+ autofill_client_.GetPersonalDataManager()->AddCreditCard(
+ test::GetExpiredCreditCard());
+
+ TryToShowTouchToFill(/*expected_success=*/false);
+}
+
+TEST_F(TouchToFillDelegateImplUnitTest,
+ TryToShowTouchToFillFailsIfCardNumberIsInvalid) {
+ ASSERT_FALSE(touch_to_fill_delegate_->IsShowingTouchToFill());
+ autofill_client_.GetPersonalDataManager()->ClearCreditCards();
+ CreditCard cc_invalid_number = test::GetCreditCard();
+ cc_invalid_number.SetNumber(u"invalid number");
+ autofill_client_.GetPersonalDataManager()->AddCreditCard(cc_invalid_number);
+
+ TryToShowTouchToFill(/*expected_success=*/false);
+
+ // But succeeds for existing masked server card with incomplete number.
+ autofill_client_.GetPersonalDataManager()->AddCreditCard(
+ test::GetMaskedServerCard());
+
+ TryToShowTouchToFill(/*expected_success=*/true);
+}
+
+TEST_F(TouchToFillDelegateImplUnitTest,
+ TryToShowTouchToFillFailsIfCanNotShowUi) {
+ ASSERT_FALSE(touch_to_fill_delegate_->IsShowingTouchToFill());
+ EXPECT_CALL(*autofill_driver_, CanShowAutofillUi).WillOnce(Return(false));
+
+ TryToShowTouchToFill(/*expected_success=*/false);
+}
+
+TEST_F(TouchToFillDelegateImplUnitTest, TryToShowTouchToFillFailsIfShowFails) {
+ ASSERT_FALSE(touch_to_fill_delegate_->IsShowingTouchToFill());
+ EXPECT_CALL(autofill_client_, ShowTouchToFillCreditCard)
+ .WillOnce(Return(false));
+
+ TryToShowTouchToFill(/*expected_success=*/false);
+}
+
+TEST_F(TouchToFillDelegateImplUnitTest, HideTouchToFillDoesNothingIfNotShown) {
+ ASSERT_FALSE(touch_to_fill_delegate_->IsShowingTouchToFill());
+
+ EXPECT_CALL(autofill_client_, HideTouchToFillCreditCard).Times(0);
+ touch_to_fill_delegate_->HideTouchToFill();
+ EXPECT_FALSE(touch_to_fill_delegate_->IsShowingTouchToFill());
+}
+
+TEST_F(TouchToFillDelegateImplUnitTest, HideTouchToFillHidesIfShown) {
+ TryToShowTouchToFill(/*expected_success=*/true);
+
+ EXPECT_CALL(autofill_client_, HideTouchToFillCreditCard).Times(1);
+ touch_to_fill_delegate_->HideTouchToFill();
+ EXPECT_FALSE(touch_to_fill_delegate_->IsShowingTouchToFill());
+}
+
+TEST_F(TouchToFillDelegateImplUnitTest, ResetHidesTouchToFillIfShown) {
+ TryToShowTouchToFill(/*expected_success=*/true);
+
+ EXPECT_CALL(autofill_client_, HideTouchToFillCreditCard).Times(1);
+ touch_to_fill_delegate_->Reset();
+ EXPECT_FALSE(touch_to_fill_delegate_->IsShowingTouchToFill());
+}
+
+TEST_F(TouchToFillDelegateImplUnitTest, ResetAllowsShowingTouchToFillAgain) {
+ TryToShowTouchToFill(/*expected_success=*/true);
+ touch_to_fill_delegate_->HideTouchToFill();
+ TryToShowTouchToFill(/*expected_success=*/false);
+
+ touch_to_fill_delegate_->Reset();
+ TryToShowTouchToFill(/*expected_success=*/true);
+}
+
+} // namespace autofill
diff --git a/chromium/components/autofill/core/browser/ui/address_combobox_model.cc b/chromium/components/autofill/core/browser/ui/address_combobox_model.cc
index d52dc0e925c..58fda879804 100644
--- a/chromium/components/autofill/core/browser/ui/address_combobox_model.cc
+++ b/chromium/components/autofill/core/browser/ui/address_combobox_model.cc
@@ -20,7 +20,7 @@ namespace autofill {
namespace {
// There's one header entry to prompt the user to select an address, and a
// separator.
-int kNbHeaderEntries = 2;
+constexpr size_t kNbHeaderEntries = 2;
} // namespace
AddressComboboxModel::AddressComboboxModel(
@@ -36,7 +36,7 @@ AddressComboboxModel::AddressComboboxModel(
AddressComboboxModel::~AddressComboboxModel() {}
-int AddressComboboxModel::GetItemCount() const {
+size_t AddressComboboxModel::GetItemCount() const {
// When there are not addresses, a special entry is shown to prompt the user
// to add addresses, but nothing else is shown, since there are no address to
// select from, and no need for a separator.
@@ -47,10 +47,9 @@ int AddressComboboxModel::GetItemCount() const {
return addresses_.size() + kNbHeaderEntries;
}
-std::u16string AddressComboboxModel::GetItemAt(int index) const {
- DCHECK_GE(index, 0);
+std::u16string AddressComboboxModel::GetItemAt(size_t index) const {
// A special entry is always added at index 0 and a separator at index 1.
- DCHECK_LT(static_cast<size_t>(index), addresses_.size() + kNbHeaderEntries);
+ DCHECK_LT(index, addresses_.size() + kNbHeaderEntries);
// Special entry when no profiles have been created yet.
if (addresses_.empty())
@@ -59,15 +58,13 @@ std::u16string AddressComboboxModel::GetItemAt(int index) const {
// Always show the "Select" entry at the top, default selection position.
if (index == 0)
return l10n_util::GetStringUTF16(IDS_AUTOFILL_SELECT);
-
- // Always show the "Select" entry at the top, default selection position.
if (index == 1)
return u"---";
return addresses_[index - kNbHeaderEntries].second;
}
-bool AddressComboboxModel::IsItemSeparatorAt(int index) const {
+bool AddressComboboxModel::IsItemSeparatorAt(size_t index) const {
// The only separator is between the "Select" entry at 0 and the first address
// at index 2. So there must be at least one address for a separator to be
// shown.
@@ -75,37 +72,37 @@ bool AddressComboboxModel::IsItemSeparatorAt(int index) const {
return index == 1;
}
-int AddressComboboxModel::GetDefaultIndex() const {
+absl::optional<size_t> AddressComboboxModel::GetDefaultIndex() const {
if (!default_selected_guid_.empty()) {
- int address_index = GetIndexOfIdentifier(default_selected_guid_);
- if (address_index != -1)
- return address_index;
+ const auto index = GetIndexOfIdentifier(default_selected_guid_);
+ if (index.has_value())
+ return index;
}
return ui::ComboboxModel::GetDefaultIndex();
}
-int AddressComboboxModel::AddNewProfile(const AutofillProfile& profile) {
+size_t AddressComboboxModel::AddNewProfile(const AutofillProfile& profile) {
profiles_cache_.push_back(std::make_unique<AutofillProfile>(profile));
UpdateAddresses();
- DCHECK_GT(addresses_.size(), 0UL);
+ DCHECK(!addresses_.empty());
return addresses_.size() + kNbHeaderEntries - 1;
}
-std::string AddressComboboxModel::GetItemIdentifierAt(int index) {
+std::string AddressComboboxModel::GetItemIdentifierAt(size_t index) {
// The first two indices are special entries, with no addresses.
if (index < kNbHeaderEntries)
return std::string();
- DCHECK_LT(static_cast<size_t>(index), addresses_.size() + kNbHeaderEntries);
+ DCHECK_LT(index, addresses_.size() + kNbHeaderEntries);
return addresses_[index - kNbHeaderEntries].first;
}
-int AddressComboboxModel::GetIndexOfIdentifier(
+absl::optional<size_t> AddressComboboxModel::GetIndexOfIdentifier(
const std::string& identifier) const {
for (size_t i = 0; i < addresses_.size(); ++i) {
if (addresses_[i].first == identifier)
return i + kNbHeaderEntries;
}
- return -1;
+ return absl::nullopt;
}
void AddressComboboxModel::UpdateAddresses() {
diff --git a/chromium/components/autofill/core/browser/ui/address_combobox_model.h b/chromium/components/autofill/core/browser/ui/address_combobox_model.h
index 3a41b30c925..a7844d6f7ba 100644
--- a/chromium/components/autofill/core/browser/ui/address_combobox_model.h
+++ b/chromium/components/autofill/core/browser/ui/address_combobox_model.h
@@ -36,22 +36,23 @@ class AddressComboboxModel : public ui::ComboboxModel {
~AddressComboboxModel() override;
// ui::ComboboxModel implementation:
- int GetItemCount() const override;
- std::u16string GetItemAt(int index) const override;
- bool IsItemSeparatorAt(int index) const override;
- int GetDefaultIndex() const override;
+ size_t GetItemCount() const override;
+ std::u16string GetItemAt(size_t index) const override;
+ bool IsItemSeparatorAt(size_t index) const override;
+ absl::optional<size_t> GetDefaultIndex() const override;
// Adds |profile| to model and return its combobox index. The lifespan of
// |profile| beyond this call is undefined so a copy must be made.
- int AddNewProfile(const AutofillProfile& profile);
+ size_t AddNewProfile(const AutofillProfile& profile);
// Returns the unique identifier of the profile at |index|, unless |index|
// refers to a special entry, in which case an empty string is returned.
- std::string GetItemIdentifierAt(int index);
+ std::string GetItemIdentifierAt(size_t index);
- // Returns the combobox index of the item with the given id or -1 if it's not
- // found.
- int GetIndexOfIdentifier(const std::string& identifier) const;
+ // Returns the combobox index of the item with the given id or nullopt if it's
+ // not found.
+ absl::optional<size_t> GetIndexOfIdentifier(
+ const std::string& identifier) const;
private:
// Update |addresses_| based on |profiles_cache_| and notify observers.
diff --git a/chromium/components/autofill/core/browser/ui/address_combobox_model_unittest.cc b/chromium/components/autofill/core/browser/ui/address_combobox_model_unittest.cc
index 24e2c360482..812a7ae745f 100644
--- a/chromium/components/autofill/core/browser/ui/address_combobox_model_unittest.cc
+++ b/chromium/components/autofill/core/browser/ui/address_combobox_model_unittest.cc
@@ -20,10 +20,10 @@ TEST(AddressComboboxModelTest, Empty) {
test_personal_data_manager.SetAutofillProfileEnabled(true);
AddressComboboxModel model(test_personal_data_manager, kAppLocale, "");
- EXPECT_EQ(1, model.GetItemCount());
+ EXPECT_EQ(1u, model.GetItemCount());
EXPECT_FALSE(model.IsItemSeparatorAt(0));
EXPECT_TRUE(model.GetItemIdentifierAt(0).empty());
- EXPECT_EQ(-1, model.GetIndexOfIdentifier("Anything"));
+ EXPECT_FALSE(model.GetIndexOfIdentifier("Anything").has_value());
}
TEST(AddressComboboxModelTest, OneAddress) {
@@ -34,15 +34,15 @@ TEST(AddressComboboxModelTest, OneAddress) {
AddressComboboxModel model(test_personal_data_manager, kAppLocale,
profile1.guid());
- EXPECT_EQ(3, model.GetItemCount());
+ EXPECT_EQ(3u, model.GetItemCount());
EXPECT_FALSE(model.IsItemSeparatorAt(0));
EXPECT_TRUE(model.IsItemSeparatorAt(1));
EXPECT_TRUE(model.GetItemIdentifierAt(0).empty());
EXPECT_TRUE(model.GetItemIdentifierAt(1).empty());
- EXPECT_EQ(-1, model.GetIndexOfIdentifier("Anything"));
+ EXPECT_FALSE(model.GetIndexOfIdentifier("Anything").has_value());
EXPECT_EQ(profile1.guid(), model.GetItemIdentifierAt(2));
- EXPECT_EQ(2, model.GetIndexOfIdentifier(profile1.guid()));
- EXPECT_EQ(2, model.GetDefaultIndex());
+ EXPECT_EQ(2u, model.GetIndexOfIdentifier(profile1.guid()));
+ EXPECT_EQ(2u, model.GetDefaultIndex());
}
TEST(AddressComboboxModelTest, TwoAddresses) {
@@ -58,17 +58,17 @@ TEST(AddressComboboxModelTest, TwoAddresses) {
AddressComboboxModel model(test_personal_data_manager, kAppLocale,
profile2.guid());
- EXPECT_EQ(4, model.GetItemCount());
+ EXPECT_EQ(4u, model.GetItemCount());
EXPECT_FALSE(model.IsItemSeparatorAt(0));
EXPECT_TRUE(model.IsItemSeparatorAt(1));
EXPECT_TRUE(model.GetItemIdentifierAt(0).empty());
EXPECT_TRUE(model.GetItemIdentifierAt(1).empty());
- EXPECT_EQ(-1, model.GetIndexOfIdentifier("Anything"));
+ EXPECT_FALSE(model.GetIndexOfIdentifier("Anything").has_value());
EXPECT_EQ(profile1.guid(), model.GetItemIdentifierAt(2));
EXPECT_EQ(profile2.guid(), model.GetItemIdentifierAt(3));
- EXPECT_EQ(2, model.GetIndexOfIdentifier(profile1.guid()));
- EXPECT_EQ(3, model.GetIndexOfIdentifier(profile2.guid()));
- EXPECT_EQ(3, model.GetDefaultIndex());
+ EXPECT_EQ(2u, model.GetIndexOfIdentifier(profile1.guid()));
+ EXPECT_EQ(3u, model.GetIndexOfIdentifier(profile2.guid()));
+ EXPECT_EQ(3u, model.GetDefaultIndex());
}
TEST(AddressComboboxModelTest, AddAnAddress) {
@@ -78,20 +78,19 @@ TEST(AddressComboboxModelTest, AddAnAddress) {
test_personal_data_manager.AddProfile(profile1);
AddressComboboxModel model(test_personal_data_manager, kAppLocale, "");
- EXPECT_EQ(3, model.GetItemCount());
+ EXPECT_EQ(3u, model.GetItemCount());
EXPECT_EQ(profile1.guid(), model.GetItemIdentifierAt(2));
- EXPECT_EQ(2, model.GetIndexOfIdentifier(profile1.guid()));
+ EXPECT_EQ(2u, model.GetIndexOfIdentifier(profile1.guid()));
AutofillProfile profile2(test::GetFullProfile2());
- int new_profile_index = model.AddNewProfile(profile2);
- EXPECT_EQ(3, new_profile_index);
- EXPECT_EQ(4, model.GetItemCount());
+ EXPECT_EQ(3u, model.AddNewProfile(profile2));
+ EXPECT_EQ(4u, model.GetItemCount());
EXPECT_EQ(profile2.guid(), model.GetItemIdentifierAt(3));
- EXPECT_EQ(3, model.GetIndexOfIdentifier(profile2.guid()));
+ EXPECT_EQ(3u, model.GetIndexOfIdentifier(profile2.guid()));
// First profile shouldn't have changed, here the order is guaranteed.
EXPECT_EQ(profile1.guid(), model.GetItemIdentifierAt(2));
- EXPECT_EQ(2, model.GetIndexOfIdentifier(profile1.guid()));
+ EXPECT_EQ(2u, model.GetIndexOfIdentifier(profile1.guid()));
}
} // namespace autofill
diff --git a/chromium/components/autofill/core/browser/ui/address_contact_form_label_formatter_unittest.cc b/chromium/components/autofill/core/browser/ui/address_contact_form_label_formatter_unittest.cc
index cb8521200e3..40e81a148b1 100644
--- a/chromium/components/autofill/core/browser/ui/address_contact_form_label_formatter_unittest.cc
+++ b/chromium/components/autofill/core/browser/ui/address_contact_form_label_formatter_unittest.cc
@@ -23,23 +23,18 @@ 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};
+ return {NO_SERVER_DATA, NAME_FULL,
+ EMAIL_ADDRESS, ADDRESS_HOME_LINE1,
+ ADDRESS_HOME_LINE2, ADDRESS_HOME_DEPENDENT_LOCALITY,
+ ADDRESS_HOME_CITY, ADDRESS_HOME_STATE,
+ ADDRESS_HOME_ZIP, ADDRESS_HOME_COUNTRY,
+ PHONE_HOME_WHOLE_NUMBER};
}
TEST(AddressContactFormLabelFormatterTest, GetLabelsWithMissingProfiles) {
const std::vector<AutofillProfile*> profiles{};
- const std::unique_ptr<LabelFormatter> formatter = LabelFormatter::Create(
- profiles, "en-US", NAME_BILLING_FULL, GetFieldTypes());
+ const std::unique_ptr<LabelFormatter> formatter =
+ LabelFormatter::Create(profiles, "en-US", NAME_FULL, GetFieldTypes());
EXPECT_TRUE(formatter->GetLabels().empty());
}
@@ -80,8 +75,8 @@ TEST(AddressContactFormLabelFormatterTest,
const std::vector<AutofillProfile*> profiles{&profile1, &profile2, &profile3,
&profile4, &profile5, &profile6};
- const std::unique_ptr<LabelFormatter> formatter = LabelFormatter::Create(
- profiles, "en-US", NAME_BILLING_FULL, GetFieldTypes());
+ const std::unique_ptr<LabelFormatter> formatter =
+ LabelFormatter::Create(profiles, "en-US", NAME_FULL, GetFieldTypes());
EXPECT_THAT(
formatter->GetLabels(),
@@ -131,7 +126,7 @@ TEST(AddressContactFormLabelFormatterTest,
const std::vector<AutofillProfile*> profiles{&profile1, &profile2, &profile3,
&profile4, &profile5, &profile6};
const std::unique_ptr<LabelFormatter> formatter = LabelFormatter::Create(
- profiles, "en-US", ADDRESS_BILLING_LINE1, GetFieldTypes());
+ profiles, "en-US", ADDRESS_HOME_LINE1, GetFieldTypes());
EXPECT_THAT(
formatter->GetLabels(),
@@ -182,7 +177,7 @@ TEST(AddressContactFormLabelFormatterTest,
const std::vector<AutofillProfile*> profiles{&profile1, &profile2, &profile3,
&profile4, &profile5, &profile6};
const std::unique_ptr<LabelFormatter> formatter = LabelFormatter::Create(
- profiles, "en-US", ADDRESS_BILLING_CITY, GetFieldTypes());
+ profiles, "en-US", ADDRESS_HOME_CITY, GetFieldTypes());
EXPECT_THAT(
formatter->GetLabels(),
@@ -283,7 +278,7 @@ TEST(AddressContactFormLabelFormatterTest,
const std::vector<AutofillProfile*> profiles{&profile1, &profile2, &profile3,
&profile4, &profile5, &profile6};
const std::unique_ptr<LabelFormatter> formatter = LabelFormatter::Create(
- profiles, "en-US", PHONE_BILLING_WHOLE_NUMBER, GetFieldTypes());
+ profiles, "en-US", PHONE_HOME_WHOLE_NUMBER, GetFieldTypes());
EXPECT_THAT(
formatter->GetLabels(),
@@ -313,8 +308,8 @@ TEST(AddressContactFormLabelFormatterTest,
"21987650000");
const std::vector<AutofillProfile*> profiles{&profile1, &profile2};
- const std::unique_ptr<LabelFormatter> formatter = LabelFormatter::Create(
- profiles, "pt-BR", NAME_BILLING_FULL, GetFieldTypes());
+ const std::unique_ptr<LabelFormatter> formatter =
+ LabelFormatter::Create(profiles, "pt-BR", NAME_FULL, GetFieldTypes());
EXPECT_THAT(
formatter->GetLabels(),
@@ -343,7 +338,7 @@ TEST(AddressContactFormLabelFormatterTest,
const std::vector<AutofillProfile*> profiles{&profile1, &profile2};
const std::unique_ptr<LabelFormatter> formatter = LabelFormatter::Create(
- profiles, "pt-BR", ADDRESS_BILLING_LINE1, GetFieldTypes());
+ profiles, "pt-BR", ADDRESS_HOME_LINE1, GetFieldTypes());
EXPECT_THAT(
formatter->GetLabels(),
@@ -371,7 +366,7 @@ TEST(AddressContactFormLabelFormatterTest,
const std::vector<AutofillProfile*> profiles{&profile1, &profile2};
const std::unique_ptr<LabelFormatter> formatter = LabelFormatter::Create(
- profiles, "pt-BR", ADDRESS_BILLING_ZIP, GetFieldTypes());
+ profiles, "pt-BR", ADDRESS_HOME_ZIP, GetFieldTypes());
EXPECT_THAT(
formatter->GetLabels(),
@@ -429,7 +424,7 @@ TEST(AddressContactFormLabelFormatterTest,
const std::vector<AutofillProfile*> profiles{&profile1, &profile2};
const std::unique_ptr<LabelFormatter> formatter = LabelFormatter::Create(
- profiles, "pt-BR", PHONE_BILLING_WHOLE_NUMBER, GetFieldTypes());
+ profiles, "pt-BR", PHONE_HOME_WHOLE_NUMBER, GetFieldTypes());
EXPECT_THAT(formatter->GetLabels(),
ElementsAre(ConstructLabelLine({u"Tarsila do Amaral",
@@ -449,10 +444,9 @@ TEST(AddressContactFormLabelFormatterTest,
"16175232338");
const std::vector<AutofillProfile*> profiles{&profile};
- const std::unique_ptr<LabelFormatter> formatter =
- LabelFormatter::Create(profiles, "en-US", EMAIL_ADDRESS,
- {NAME_BILLING_FULL, EMAIL_ADDRESS,
- ADDRESS_BILLING_ZIP, PHONE_BILLING_WHOLE_NUMBER});
+ const std::unique_ptr<LabelFormatter> formatter = LabelFormatter::Create(
+ profiles, "en-US", EMAIL_ADDRESS,
+ {NAME_FULL, EMAIL_ADDRESS, ADDRESS_HOME_ZIP, PHONE_HOME_WHOLE_NUMBER});
// Checks that only address fields in the form are shown in the label.
EXPECT_THAT(formatter->GetLabels(),
@@ -469,18 +463,17 @@ TEST(AddressContactFormLabelFormatterTest,
std::vector<AutofillProfile*> profiles{&profile1};
std::unique_ptr<LabelFormatter> formatter = LabelFormatter::Create(
- profiles, "en-US", ADDRESS_BILLING_LINE1,
- {ADDRESS_BILLING_ZIP, EMAIL_ADDRESS, PHONE_BILLING_WHOLE_NUMBER});
+ profiles, "en-US", ADDRESS_HOME_LINE1,
+ {ADDRESS_HOME_ZIP, EMAIL_ADDRESS, PHONE_HOME_WHOLE_NUMBER});
// Checks that the name is not in the label and that the phone number is for
// a unique profile.
EXPECT_THAT(formatter->GetLabels(), ElementsAre(u"(617) 523-2338"));
profiles = {&profile1, &profile1};
- formatter =
- LabelFormatter::Create(profiles, "en-US", ADDRESS_BILLING_LINE1,
- {ADDRESS_BILLING_LINE1, ADDRESS_BILLING_ZIP,
- EMAIL_ADDRESS, PHONE_BILLING_WHOLE_NUMBER});
+ formatter = LabelFormatter::Create(profiles, "en-US", ADDRESS_HOME_LINE1,
+ {ADDRESS_HOME_LINE1, ADDRESS_HOME_ZIP,
+ EMAIL_ADDRESS, PHONE_HOME_WHOLE_NUMBER});
// Checks that the name is not in the label and that the phone number is for
// multiple profiles with the same phone number and email address.
@@ -494,10 +487,9 @@ TEST(AddressContactFormLabelFormatterTest,
"16175232338");
profiles = {&profile1, &profile2};
- formatter =
- LabelFormatter::Create(profiles, "en-US", ADDRESS_BILLING_LINE1,
- {ADDRESS_BILLING_LINE1, ADDRESS_BILLING_ZIP,
- EMAIL_ADDRESS, PHONE_BILLING_WHOLE_NUMBER});
+ formatter = LabelFormatter::Create(profiles, "en-US", ADDRESS_HOME_LINE1,
+ {ADDRESS_HOME_LINE1, ADDRESS_HOME_ZIP,
+ EMAIL_ADDRESS, PHONE_HOME_WHOLE_NUMBER});
// Checks that the name is not in the label and that the email address is
// shown because the profiles' email addresses are different.
EXPECT_THAT(formatter->GetLabels(),
diff --git a/chromium/components/autofill/core/browser/ui/address_email_form_label_formatter_unittest.cc b/chromium/components/autofill/core/browser/ui/address_email_form_label_formatter_unittest.cc
index a4d3b82341a..6474e331305 100644
--- a/chromium/components/autofill/core/browser/ui/address_email_form_label_formatter_unittest.cc
+++ b/chromium/components/autofill/core/browser/ui/address_email_form_label_formatter_unittest.cc
@@ -25,19 +25,19 @@ 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};
+ ADDRESS_HOME_LINE1,
+ ADDRESS_HOME_LINE2,
+ ADDRESS_HOME_CITY,
+ ADDRESS_HOME_STATE,
+ ADDRESS_HOME_DEPENDENT_LOCALITY,
+ ADDRESS_HOME_ZIP,
+ ADDRESS_HOME_COUNTRY};
}
TEST(AddressEmailFormLabelFormatterTest, GetLabelsWithMissingProfiles) {
const std::vector<AutofillProfile*> profiles{};
- const std::unique_ptr<LabelFormatter> formatter = LabelFormatter::Create(
- profiles, "en-US", NAME_BILLING_FULL, GetFieldTypes());
+ const std::unique_ptr<LabelFormatter> formatter =
+ LabelFormatter::Create(profiles, "en-US", NAME_FULL, GetFieldTypes());
EXPECT_TRUE(formatter->GetLabels().empty());
}
@@ -66,8 +66,8 @@ TEST(AddressEmailFormLabelFormatterTest, GetLabelsForUSProfilesAndFocusedName) {
const std::vector<AutofillProfile*> profiles{&profile1, &profile2, &profile3,
&profile4};
- const std::unique_ptr<LabelFormatter> formatter = LabelFormatter::Create(
- profiles, "en-US", NAME_BILLING_FULL, GetFieldTypes());
+ const std::unique_ptr<LabelFormatter> formatter =
+ LabelFormatter::Create(profiles, "en-US", NAME_FULL, GetFieldTypes());
EXPECT_THAT(
formatter->GetLabels(),
@@ -102,7 +102,7 @@ TEST(AddressEmailFormLabelFormatterTest,
const std::vector<AutofillProfile*> profiles{&profile1, &profile2, &profile3,
&profile4};
const std::unique_ptr<LabelFormatter> formatter = LabelFormatter::Create(
- profiles, "en-US", ADDRESS_BILLING_LINE1, GetFieldTypes());
+ profiles, "en-US", ADDRESS_HOME_LINE1, GetFieldTypes());
EXPECT_THAT(
formatter->GetLabels(),
@@ -137,7 +137,7 @@ TEST(AddressEmailFormLabelFormatterTest,
const std::vector<AutofillProfile*> profiles{&profile1, &profile2, &profile3,
&profile4};
const std::unique_ptr<LabelFormatter> formatter = LabelFormatter::Create(
- profiles, "en-US", ADDRESS_BILLING_ZIP, GetFieldTypes());
+ profiles, "en-US", ADDRESS_HOME_ZIP, GetFieldTypes());
EXPECT_THAT(
formatter->GetLabels(),
@@ -195,8 +195,8 @@ TEST(AddressEmailFormLabelFormatterTest, GetLabelsForBRProfilesAndFocusedName) {
"21987650000");
const std::vector<AutofillProfile*> profiles{&profile1, &profile2};
- const std::unique_ptr<LabelFormatter> formatter = LabelFormatter::Create(
- profiles, "pt-BR", NAME_BILLING_FULL, GetFieldTypes());
+ const std::unique_ptr<LabelFormatter> formatter =
+ LabelFormatter::Create(profiles, "pt-BR", NAME_FULL, GetFieldTypes());
EXPECT_THAT(formatter->GetLabels(),
ElementsAre(ConstructLabelLine({u"Av. Pedro Álvares Cabral, 1301",
@@ -223,7 +223,7 @@ TEST(AddressEmailFormLabelFormatterTest,
const std::vector<AutofillProfile*> profiles{&profile1, &profile2};
const std::unique_ptr<LabelFormatter> formatter = LabelFormatter::Create(
- profiles, "pt-BR", ADDRESS_BILLING_LINE1, GetFieldTypes());
+ profiles, "pt-BR", ADDRESS_HOME_LINE1, GetFieldTypes());
EXPECT_THAT(
formatter->GetLabels(),
@@ -250,7 +250,7 @@ TEST(AddressEmailFormLabelFormatterTest,
const std::vector<AutofillProfile*> profiles{&profile1, &profile2};
const std::unique_ptr<LabelFormatter> formatter = LabelFormatter::Create(
- profiles, "pt-BR", ADDRESS_BILLING_DEPENDENT_LOCALITY, GetFieldTypes());
+ profiles, "pt-BR", ADDRESS_HOME_DEPENDENT_LOCALITY, GetFieldTypes());
EXPECT_THAT(formatter->GetLabels(),
ElementsAre(ConstructLabelLine({u"Av. Pedro Álvares Cabral, 1301",
@@ -296,10 +296,9 @@ TEST(AddressEmailFormLabelFormatterTest,
"US", "16177302000");
const std::vector<AutofillProfile*> profiles{&profile};
- const std::unique_ptr<LabelFormatter> formatter =
- LabelFormatter::Create(profiles, "en-US", EMAIL_ADDRESS,
- {NAME_BILLING_FULL, EMAIL_ADDRESS,
- ADDRESS_BILLING_CITY, ADDRESS_BILLING_STATE});
+ const std::unique_ptr<LabelFormatter> formatter = LabelFormatter::Create(
+ profiles, "en-US", EMAIL_ADDRESS,
+ {NAME_FULL, EMAIL_ADDRESS, ADDRESS_HOME_CITY, ADDRESS_HOME_STATE});
// Checks that only address fields in the form are shown in the label.
EXPECT_THAT(
@@ -316,8 +315,8 @@ TEST(AddressEmailFormLabelFormatterTest, GetLabelsForFormWithoutName) {
const std::vector<AutofillProfile*> profiles{&profile};
const std::unique_ptr<LabelFormatter> formatter = LabelFormatter::Create(
- profiles, "en-US", ADDRESS_BILLING_LINE1,
- {ADDRESS_BILLING_LINE1, ADDRESS_BILLING_ZIP, EMAIL_ADDRESS});
+ profiles, "en-US", ADDRESS_HOME_LINE1,
+ {ADDRESS_HOME_LINE1, ADDRESS_HOME_ZIP, EMAIL_ADDRESS});
// Checks that the name does not appear in the labels.
EXPECT_THAT(formatter->GetLabels(), ElementsAre(u"sarah.revere@aol.com"));
diff --git a/chromium/components/autofill/core/browser/ui/address_phone_form_label_formatter_unittest.cc b/chromium/components/autofill/core/browser/ui/address_phone_form_label_formatter_unittest.cc
index fd0569e4c3a..9936f8eeb1f 100644
--- a/chromium/components/autofill/core/browser/ui/address_phone_form_label_formatter_unittest.cc
+++ b/chromium/components/autofill/core/browser/ui/address_phone_form_label_formatter_unittest.cc
@@ -310,12 +310,12 @@ TEST(AddressPhoneFormLabelFormatterTest, GetLabelsForFormWithoutName) {
const std::vector<AutofillProfile*> profiles{&profile};
const std::unique_ptr<LabelFormatter> formatter = LabelFormatter::Create(
- profiles, "en-US", ADDRESS_BILLING_LINE1,
- {ADDRESS_BILLING_LINE1, ADDRESS_BILLING_ZIP, PHONE_HOME_WHOLE_NUMBER});
+ profiles, "en-US", ADDRESS_HOME_LINE1,
+ {ADDRESS_HOME_LINE1, ADDRESS_HOME_ZIP, PHONE_HOME_WHOLE_NUMBER});
// Checks that the name does not appear in the labels.
EXPECT_THAT(formatter->GetLabels(), ElementsAre(u"(617) 523-2338"));
}
} // namespace
-} // namespace autofill \ No newline at end of file
+} // namespace autofill
diff --git a/chromium/components/autofill/core/browser/ui/autofill_popup_delegate.h b/chromium/components/autofill/core/browser/ui/autofill_popup_delegate.h
index b3410873b5c..d884117b04f 100644
--- a/chromium/components/autofill/core/browser/ui/autofill_popup_delegate.h
+++ b/chromium/components/autofill/core/browser/ui/autofill_popup_delegate.h
@@ -89,6 +89,8 @@ class AutofillPopupDelegate {
// should not outlive it.
virtual void RegisterDeletionCallback(
base::OnceClosure deletion_callback) = 0;
+
+ virtual ~AutofillPopupDelegate() = default;
};
} // namespace autofill
diff --git a/chromium/components/autofill/core/browser/ui/country_combobox_model.cc b/chromium/components/autofill/core/browser/ui/country_combobox_model.cc
index 2abb96fe50f..fbd39e68d21 100644
--- a/chromium/components/autofill/core/browser/ui/country_combobox_model.cc
+++ b/chromium/components/autofill/core/browser/ui/country_combobox_model.cc
@@ -75,11 +75,11 @@ void CountryComboboxModel::SetCountries(
std::back_inserter(countries_));
}
-int CountryComboboxModel::GetItemCount() const {
+size_t CountryComboboxModel::GetItemCount() const {
return countries_.size();
}
-std::u16string CountryComboboxModel::GetItemAt(int index) const {
+std::u16string CountryComboboxModel::GetItemAt(size_t index) const {
AutofillCountry* country = countries_[index].get();
if (country)
return countries_[index]->name();
@@ -89,12 +89,12 @@ std::u16string CountryComboboxModel::GetItemAt(int index) const {
return u"---";
}
-bool CountryComboboxModel::IsItemSeparatorAt(int index) const {
+bool CountryComboboxModel::IsItemSeparatorAt(size_t index) const {
return !countries_[index];
}
std::string CountryComboboxModel::GetDefaultCountryCode() const {
- return countries_[GetDefaultIndex()]->country_code();
+ return countries_[GetDefaultIndex().value()]->country_code();
}
} // namespace autofill
diff --git a/chromium/components/autofill/core/browser/ui/country_combobox_model.h b/chromium/components/autofill/core/browser/ui/country_combobox_model.h
index 873d4838aa2..a9260126977 100644
--- a/chromium/components/autofill/core/browser/ui/country_combobox_model.h
+++ b/chromium/components/autofill/core/browser/ui/country_combobox_model.h
@@ -38,9 +38,9 @@ class CountryComboboxModel : public ui::ComboboxModel {
const std::string& app_locale);
// ui::ComboboxModel implementation:
- int GetItemCount() const override;
- std::u16string GetItemAt(int index) const override;
- bool IsItemSeparatorAt(int index) const override;
+ size_t GetItemCount() const override;
+ std::u16string GetItemAt(size_t index) const override;
+ bool IsItemSeparatorAt(size_t index) const override;
// The list of countries always has the default country at the top as well as
// within the sorted vector.
diff --git a/chromium/components/autofill/core/browser/ui/country_combobox_model_unittest.cc b/chromium/components/autofill/core/browser/ui/country_combobox_model_unittest.cc
index 1e5c5318537..f00d722ba87 100644
--- a/chromium/components/autofill/core/browser/ui/country_combobox_model_unittest.cc
+++ b/chromium/components/autofill/core/browser/ui/country_combobox_model_unittest.cc
@@ -50,7 +50,7 @@ TEST_F(CountryComboboxModelTest, DefaultCountryCode) {
TEST_F(CountryComboboxModelTest, AllCountriesHaveComponents) {
::i18n::addressinput::Localization localization;
std::string unused;
- for (int i = 0; i < model()->GetItemCount(); ++i) {
+ for (size_t i = 0; i < model()->GetItemCount(); ++i) {
if (model()->IsItemSeparatorAt(i))
continue;
diff --git a/chromium/components/autofill/core/browser/ui/label_formatter.cc b/chromium/components/autofill/core/browser/ui/label_formatter.cc
index 9aa99315d2b..0e0eae78dbc 100644
--- a/chromium/components/autofill/core/browser/ui/label_formatter.cc
+++ b/chromium/components/autofill/core/browser/ui/label_formatter.cc
@@ -40,7 +40,7 @@ LabelFormatter::LabelFormatter(const std::vector<AutofillProfile*>& profiles,
app_locale_(app_locale),
focused_field_type_(focused_field_type),
groups_(groups) {
- const FieldTypeGroup focused_group = GetFocusedNonBillingGroup();
+ const FieldTypeGroup focused_group = AutofillType(focused_field_type).group();
DenseSet<FieldTypeGroup> groups_for_labels{
FieldTypeGroup::kName, FieldTypeGroup::kAddressHome,
FieldTypeGroup::kEmail, FieldTypeGroup::kPhoneHome};
@@ -60,7 +60,7 @@ LabelFormatter::LabelFormatter(const std::vector<AutofillProfile*>& profiles,
return groups_for_labels.find(
AutofillType(AutofillType(type).GetStorableType()).group()) !=
groups_for_labels.end() &&
- type != ADDRESS_HOME_COUNTRY && type != ADDRESS_BILLING_COUNTRY;
+ type != ADDRESS_HOME_COUNTRY;
};
std::copy_if(field_types.begin(), field_types.end(),
@@ -73,16 +73,12 @@ LabelFormatter::~LabelFormatter() = default;
std::vector<std::u16string> LabelFormatter::GetLabels() const {
std::vector<std::u16string> labels;
for (const AutofillProfile* profile : profiles_) {
- labels.push_back(GetLabelForProfile(*profile, GetFocusedNonBillingGroup()));
+ labels.push_back(GetLabelForProfile(
+ *profile, AutofillType(focused_field_type_).group()));
}
return labels;
}
-FieldTypeGroup LabelFormatter::GetFocusedNonBillingGroup() const {
- return AutofillType(AutofillType(focused_field_type_).GetStorableType())
- .group();
-}
-
// static
std::unique_ptr<LabelFormatter> LabelFormatter::Create(
const std::vector<AutofillProfile*>& profiles,
diff --git a/chromium/components/autofill/core/browser/ui/label_formatter.h b/chromium/components/autofill/core/browser/ui/label_formatter.h
index cf66bfb3a66..8bb5a3b9cb9 100644
--- a/chromium/components/autofill/core/browser/ui/label_formatter.h
+++ b/chromium/components/autofill/core/browser/ui/label_formatter.h
@@ -49,12 +49,6 @@ class LabelFormatter {
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 kAddressHome instead of kAddressBilling.
- FieldTypeGroup GetFocusedNonBillingGroup() const;
-
const std::string& app_locale() const { return app_locale_; }
ServerFieldType focused_field_type() const { return focused_field_type_; }
diff --git a/chromium/components/autofill/core/browser/ui/label_formatter_utils.cc b/chromium/components/autofill/core/browser/ui/label_formatter_utils.cc
index f7d0ced2e08..506df6e01f8 100644
--- a/chromium/components/autofill/core/browser/ui/label_formatter_utils.cc
+++ b/chromium/components/autofill/core/browser/ui/label_formatter_utils.cc
@@ -86,17 +86,11 @@ std::u16string ConstructMobileLabelLine(
bool IsNonStreetAddressPart(ServerFieldType type) {
switch (type) {
case ADDRESS_HOME_CITY:
- case ADDRESS_BILLING_CITY:
case ADDRESS_HOME_ZIP:
- case ADDRESS_BILLING_ZIP:
case ADDRESS_HOME_STATE:
- case ADDRESS_BILLING_STATE:
case ADDRESS_HOME_COUNTRY:
- case ADDRESS_BILLING_COUNTRY:
case ADDRESS_HOME_SORTING_CODE:
- case ADDRESS_BILLING_SORTING_CODE:
case ADDRESS_HOME_DEPENDENT_LOCALITY:
- case ADDRESS_BILLING_DEPENDENT_LOCALITY:
return true;
default:
return false;
@@ -108,13 +102,8 @@ bool IsStreetAddressPart(ServerFieldType type) {
case ADDRESS_HOME_LINE1:
case ADDRESS_HOME_LINE2:
case ADDRESS_HOME_APT_NUM:
- case ADDRESS_BILLING_LINE1:
- case ADDRESS_BILLING_LINE2:
- case ADDRESS_BILLING_APT_NUM:
case ADDRESS_HOME_STREET_ADDRESS:
- case ADDRESS_BILLING_STREET_ADDRESS:
case ADDRESS_HOME_LINE3:
- case ADDRESS_BILLING_LINE3:
return true;
default:
return false;
diff --git a/chromium/components/autofill/core/browser/ui/mobile_label_formatter.cc b/chromium/components/autofill/core/browser/ui/mobile_label_formatter.cc
index 09f00ce40b0..a37b0232467 100644
--- a/chromium/components/autofill/core/browser/ui/mobile_label_formatter.cc
+++ b/chromium/components/autofill/core/browser/ui/mobile_label_formatter.cc
@@ -35,7 +35,7 @@ MobileLabelFormatter::MobileLabelFormatter(
focused_field_type,
groups,
field_types) {
- const FieldTypeGroup focused_group = GetFocusedNonBillingGroup();
+ const FieldTypeGroup focused_group = AutofillType(focused_field_type).group();
could_show_email_ = HasUnfocusedEmailField(focused_group, groups) &&
!HaveSameEmailAddresses(profiles, app_locale);
diff --git a/chromium/components/autofill/core/browser/ui/payments/card_unmask_prompt_controller_impl_unittest.cc b/chromium/components/autofill/core/browser/ui/payments/card_unmask_prompt_controller_impl_unittest.cc
index 0cd137c9748..a14f7f01f56 100644
--- a/chromium/components/autofill/core/browser/ui/payments/card_unmask_prompt_controller_impl_unittest.cc
+++ b/chromium/components/autofill/core/browser/ui/payments/card_unmask_prompt_controller_impl_unittest.cc
@@ -279,55 +279,13 @@ TEST_F(CardUnmaskPromptControllerImplTest,
TEST_F(CardUnmaskPromptControllerImplTest, DisplayCardInformation) {
ShowPrompt();
#if BUILDFLAG(IS_IOS)
- EXPECT_TRUE(base::UTF16ToUTF8(controller_->GetInstructionsMessage())
- .find("Mastercard " + test::ObfuscatedCardDigitsAsUTF8(
- "2109")) != std::string::npos);
-#else
- EXPECT_TRUE(base::UTF16ToUTF8(controller_->GetWindowTitle())
- .find("Mastercard " + test::ObfuscatedCardDigitsAsUTF8(
- "2109")) != std::string::npos);
-#endif
-}
-
-// Ensures to fallback to network name in the instruction message on iOS and in
-// the title on other platforms when the nickname is invalid.
-TEST_F(CardUnmaskPromptControllerImplTest, Nickname_NicknameInvalid) {
- SetCreditCardForTesting(test::GetMaskedServerCardWithInvalidNickname());
- ShowPrompt();
-#if BUILDFLAG(IS_IOS)
- EXPECT_TRUE(
- base::UTF16ToUTF8(controller_->GetInstructionsMessage()).find("Visa") !=
- std::string::npos);
- EXPECT_FALSE(base::UTF16ToUTF8(controller_->GetInstructionsMessage())
- .find("Invalid nickname which is too long") !=
- std::string::npos);
-#else
- EXPECT_TRUE(base::UTF16ToUTF8(controller_->GetWindowTitle()).find("Visa") !=
+ EXPECT_TRUE(controller_->GetInstructionsMessage().find(
+ card_.CardIdentifierStringForAutofillDisplay()) !=
std::string::npos);
- EXPECT_FALSE(base::UTF16ToUTF8(controller_->GetWindowTitle())
- .find("Invalid nickname which is too long") !=
- std::string::npos);
-#endif
-}
-
-// Ensures the nickname is displayed (instead of network) in the instruction
-// message on iOS and in the title on other platforms when the nickname is
-// valid.
-TEST_F(CardUnmaskPromptControllerImplTest, Nickname_NicknameValid) {
- SetCreditCardForTesting(test::GetMaskedServerCardWithNickname());
- ShowPrompt();
-#if BUILDFLAG(IS_IOS)
- EXPECT_FALSE(
- base::UTF16ToUTF8(controller_->GetInstructionsMessage()).find("Visa") !=
- std::string::npos);
- EXPECT_TRUE(base::UTF16ToUTF8(controller_->GetInstructionsMessage())
- .find("Test nickname") != std::string::npos);
#else
- EXPECT_FALSE(base::UTF16ToUTF8(controller_->GetWindowTitle()).find("Visa") !=
- std::string::npos);
- EXPECT_TRUE(
- base::UTF16ToUTF8(controller_->GetWindowTitle()).find("Test nickname") !=
- std::string::npos);
+ EXPECT_TRUE(controller_->GetWindowTitle().find(
+ card_.CardIdentifierStringForAutofillDisplay()) !=
+ std::string::npos);
#endif
}
diff --git a/chromium/components/autofill/core/browser/ui/popup_item_ids.h b/chromium/components/autofill/core/browser/ui/popup_item_ids.h
index 10d1a3e3d82..8373853fd8e 100644
--- a/chromium/components/autofill/core/browser/ui/popup_item_ids.h
+++ b/chromium/components/autofill/core/browser/ui/popup_item_ids.h
@@ -37,7 +37,9 @@ enum PopupItemId {
POPUP_ITEM_ID_VIRTUAL_CREDIT_CARD_ENTRY = -27,
POPUP_ITEM_ID_WEBAUTHN_CREDENTIAL = -28,
POPUP_ITEM_ID_MERCHANT_PROMO_CODE_ENTRY = -29,
- POPUP_ITEM_ID_SEE_PROMO_CODE_DETAILS = -30
+ POPUP_ITEM_ID_SEE_PROMO_CODE_DETAILS = -30,
+ POPUP_ITEM_ID_WEBAUTHN_SIGN_IN_WITH_ANOTHER_DEVICE = -31,
+ POPUP_ITEM_ID_IBAN_ENTRY = -32,
};
// List of `PopupItemId` that trigger filling a value into an input element
diff --git a/chromium/components/autofill/core/browser/ui/popup_types.h b/chromium/components/autofill/core/browser/ui/popup_types.h
index 048ae1936fc..9d817b25994 100644
--- a/chromium/components/autofill/core/browser/ui/popup_types.h
+++ b/chromium/components/autofill/core/browser/ui/popup_types.h
@@ -62,7 +62,11 @@ enum class PopupHidingReason {
kMouseLocked = 16,
// The password generation popup would overlap and hide autofill popup.
kOverlappingWithPasswordGenerationPopup = 17,
- kMaxValue = kOverlappingWithPasswordGenerationPopup
+ // The Touch To Fill surface is shown instead of autofill suggestions.
+ kOverlappingWithTouchToFillSurface = 18,
+ // The context menu is shown instead of the autofill suggestions.
+ kOverlappingWithAutofillContextMenu = 19,
+ kMaxValue = kOverlappingWithAutofillContextMenu
};
} // namespace autofill
diff --git a/chromium/components/autofill/core/browser/ui/region_combobox_model.cc b/chromium/components/autofill/core/browser/ui/region_combobox_model.cc
index 42626aff427..df17223dd52 100644
--- a/chromium/components/autofill/core/browser/ui/region_combobox_model.cc
+++ b/chromium/components/autofill/core/browser/ui/region_combobox_model.cc
@@ -37,18 +37,15 @@ void RegionComboboxModel::LoadRegionData(const std::string& country_code,
weak_factory_.GetWeakPtr()));
}
-int RegionComboboxModel::GetItemCount() const {
+size_t RegionComboboxModel::GetItemCount() const {
// The combobox view needs to always have at least one item. If the regions
// have not been completely loaded yet, we display a single "loading" item.
- if (regions_.size() == 0)
- return 1;
- return regions_.size();
+ return std::max(regions_.size(), size_t{1});
}
-std::u16string RegionComboboxModel::GetItemAt(int index) const {
- DCHECK_GE(index, 0);
+std::u16string RegionComboboxModel::GetItemAt(size_t index) const {
// This might happen because of the asynchronous nature of the data.
- if (static_cast<size_t>(index) >= regions_.size())
+ if (index >= regions_.size())
return l10n_util::GetStringUTF16(IDS_AUTOFILL_LOADING_REGIONS);
if (!regions_[index].second.empty())
@@ -59,12 +56,8 @@ std::u16string RegionComboboxModel::GetItemAt(int index) const {
return u"---";
}
-bool RegionComboboxModel::IsItemSeparatorAt(int index) const {
- // This might happen because of the asynchronous nature of the data.
- DCHECK_GE(index, 0);
- if (static_cast<size_t>(index) >= regions_.size())
- return false;
- return regions_[index].first.empty();
+bool RegionComboboxModel::IsItemSeparatorAt(size_t index) const {
+ return index < regions_.size() && regions_[index].first.empty();
}
void RegionComboboxModel::OnRegionDataLoaded(
diff --git a/chromium/components/autofill/core/browser/ui/region_combobox_model.h b/chromium/components/autofill/core/browser/ui/region_combobox_model.h
index 52cffd5d006..ead471de804 100644
--- a/chromium/components/autofill/core/browser/ui/region_combobox_model.h
+++ b/chromium/components/autofill/core/browser/ui/region_combobox_model.h
@@ -51,9 +51,9 @@ class RegionComboboxModel : public ui::ComboboxModel {
}
// ui::ComboboxModel implementation:
- int GetItemCount() const override;
- std::u16string GetItemAt(int index) const override;
- bool IsItemSeparatorAt(int index) const override;
+ size_t GetItemCount() const override;
+ std::u16string GetItemAt(size_t index) const override;
+ bool IsItemSeparatorAt(size_t index) const override;
private:
// Callback for the RegionDataLoader.
diff --git a/chromium/components/autofill/core/browser/ui/region_combobox_model_unittest.cc b/chromium/components/autofill/core/browser/ui/region_combobox_model_unittest.cc
index 3c018e2e55c..6984b134ce8 100644
--- a/chromium/components/autofill/core/browser/ui/region_combobox_model_unittest.cc
+++ b/chromium/components/autofill/core/browser/ui/region_combobox_model_unittest.cc
@@ -38,7 +38,7 @@ TEST(RegionComboboxModelTest, QuebecOntarioRegions) {
test_region_data_loader.SendAsynchronousData(regions);
- EXPECT_EQ(3, model.GetItemCount());
+ EXPECT_EQ(3u, model.GetItemCount());
EXPECT_EQ(u"---", model.GetItemAt(0));
EXPECT_EQ(kQuebecName16, model.GetItemAt(1));
EXPECT_EQ(kOntarioName16, model.GetItemAt(2));
@@ -54,7 +54,7 @@ TEST(RegionComboboxModelTest, FailingSource) {
std::vector<std::pair<std::string, std::string>>());
// There's always 1 item, even in failure cases.
- EXPECT_EQ(1, model.GetItemCount());
+ EXPECT_EQ(1u, model.GetItemCount());
EXPECT_TRUE(model.failed_to_load_data());
}
diff --git a/chromium/components/autofill/core/browser/ui/suggestion.h b/chromium/components/autofill/core/browser/ui/suggestion.h
index ad9eb7894ae..1368f10a3ad 100644
--- a/chromium/components/autofill/core/browser/ui/suggestion.h
+++ b/chromium/components/autofill/core/browser/ui/suggestion.h
@@ -75,9 +75,23 @@ struct Suggestion {
template <typename T>
T GetPayload() const {
+#if DCHECK_IS_ON()
+ DCHECK(Invariant());
+#endif
return absl::holds_alternative<T>(payload) ? absl::get<T>(payload) : T{};
}
+#if DCHECK_IS_ON()
+ bool Invariant() const {
+ switch (frontend_id) {
+ case PopupItemId::POPUP_ITEM_ID_SEE_PROMO_CODE_DETAILS:
+ return absl::holds_alternative<GURL>(payload);
+ default:
+ return absl::holds_alternative<std::string>(payload);
+ }
+ }
+#endif
+
// Payload generated by the backend layer. This payload is either a GUID that
// identifies the exact autofill profile that generated this suggestion, or a
// GURL that the suggestion should navigate to upon being accepted.
@@ -117,6 +131,10 @@ struct Suggestion {
// The url for the custom icon. This is used by android to fetch the image as
// android does not support gfx::Image directly.
GURL custom_icon_url;
+
+ // On Android, the icon can be at the start of the suggestion before the label
+ // or at the end of the label.
+ bool is_icon_at_start = false;
#endif // BUILDFLAG(IS_ANDROID)
// TODO(crbug.com/1019660): Identify icons with enum instead of strings.
diff --git a/chromium/components/autofill/core/browser/ui/touch_to_fill_delegate.h b/chromium/components/autofill/core/browser/ui/touch_to_fill_delegate.h
new file mode 100644
index 00000000000..0f211d9d301
--- /dev/null
+++ b/chromium/components/autofill/core/browser/ui/touch_to_fill_delegate.h
@@ -0,0 +1,19 @@
+// Copyright 2022 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_UI_TOUCH_TO_FILL_DELEGATE_H_
+#define COMPONENTS_AUTOFILL_CORE_BROWSER_UI_TOUCH_TO_FILL_DELEGATE_H_
+
+namespace autofill {
+
+// An interface for interaction with the corresponding UI controller.
+class TouchToFillDelegate {
+ public:
+ // TODO(crbug.com/1247698): Define the API.
+ virtual ~TouchToFillDelegate() = default;
+};
+
+} // namespace autofill
+
+#endif // COMPONENTS_AUTOFILL_CORE_BROWSER_UI_TOUCH_TO_FILL_DELEGATE_H_
diff --git a/chromium/components/autofill/core/browser/validation.cc b/chromium/components/autofill/core/browser/validation.cc
index 53165336edc..afe2c981ab3 100644
--- a/chromium/components/autofill/core/browser/validation.cc
+++ b/chromium/components/autofill/core/browser/validation.cc
@@ -17,12 +17,12 @@
#include "base/strings/utf_string_conversions.h"
#include "base/time/time.h"
#include "components/autofill/core/browser/autofill_data_util.h"
-#include "components/autofill/core/browser/autofill_regex_constants.h"
-#include "components/autofill/core/browser/autofill_regexes.h"
#include "components/autofill/core/browser/data_model/credit_card.h"
#include "components/autofill/core/browser/geo/phone_number_i18n.h"
#include "components/autofill/core/browser/geo/state_names.h"
#include "components/autofill/core/common/autofill_clock.h"
+#include "components/autofill/core/common/autofill_regex_constants.h"
+#include "components/autofill/core/common/autofill_regexes.h"
#include "components/strings/grit/components_strings.h"
#include "ui/base/l10n/l10n_util.h"
@@ -154,7 +154,7 @@ bool IsValidEmailAddress(const std::u16string& text) {
// E-Mail pattern as defined by the WhatWG. (4.10.7.1.5 E-Mail state)
static constexpr char16_t kEmailPattern[] =
u"^[a-zA-Z0-9.!#$%&'*+/=?^_`{|}~-]+@[a-zA-Z0-9-]+(?:\\.[a-zA-Z0-9-]+)*$";
- return MatchesPattern(text, kEmailPattern);
+ return MatchesRegex<kEmailPattern>(text);
}
bool IsValidState(const std::u16string& text) {
@@ -169,7 +169,7 @@ bool IsPossiblePhoneNumber(const std::u16string& text,
bool IsValidZip(const std::u16string& text) {
static constexpr char16_t kZipPattern[] = u"^\\d{5}(-\\d{4})?$";
- return MatchesPattern(text, kZipPattern);
+ return MatchesRegex<kZipPattern>(text);
}
bool IsSSN(const std::u16string& text) {
@@ -290,16 +290,17 @@ bool IsValidForType(const std::u16string& value,
case CREDIT_CARD_EXP_DATE_2_DIGIT_YEAR:
case CREDIT_CARD_EXP_DATE_4_DIGIT_YEAR: {
- const std::u16string pattern = type == CREDIT_CARD_EXP_DATE_2_DIGIT_YEAR
- ? u"^[0-9]{1,2}[-/|]?[0-9]{2}$"
- : u"^[0-9]{1,2}[-/|]?[0-9]{4}$";
+ static constexpr char16_t kDateYY[] = u"^[0-9]{1,2}[-/|]?[0-9]{2}$";
+ static constexpr char16_t kDateYYYY[] = u"^[0-9]{1,2}[-/|]?[0-9]{4}$";
CreditCard temp;
temp.SetExpirationDateFromString(value);
// Expiration date was in an invalid format.
if (temp.expiration_month() == 0 || temp.expiration_year() == 0 ||
- !MatchesPattern(value, pattern)) {
+ (type == CREDIT_CARD_EXP_DATE_2_DIGIT_YEAR
+ ? !MatchesRegex<kDateYY>(value)
+ : !MatchesRegex<kDateYYYY>(value))) {
if (error_message) {
*error_message = l10n_util::GetStringUTF16(
IDS_PAYMENTS_CARD_EXPIRATION_INVALID_VALIDATION_MESSAGE);
@@ -343,20 +344,20 @@ size_t GetCvcLengthForCardNetwork(const base::StringPiece card_network) {
}
bool IsUPIVirtualPaymentAddress(const std::u16string& value) {
- return MatchesPattern(value, kUPIVirtualPaymentAddressRe);
+ return MatchesRegex<kUPIVirtualPaymentAddressRe>(value);
}
bool IsInternationalBankAccountNumber(const std::u16string& value) {
std::u16string no_spaces;
base::RemoveChars(value, u" ", &no_spaces);
- return MatchesPattern(no_spaces, kInternationalBankAccountNumberRe);
+ return MatchesRegex<kInternationalBankAccountNumberValueRe>(no_spaces);
}
bool IsPlausibleCreditCardCVCNumber(const std::u16string& value) {
- return MatchesPattern(value, kCreditCardCVCPattern);
+ return MatchesRegex<kCreditCardCVCPattern>(value);
}
bool IsPlausible4DigitExpirationYear(const std::u16string& value) {
- return MatchesPattern(value, kCreditCard4DigitExpYearPattern);
+ return MatchesRegex<kCreditCard4DigitExpYearPattern>(value);
}
} // namespace autofill
diff --git a/chromium/components/autofill/core/browser/validation_unittest.cc b/chromium/components/autofill/core/browser/validation_unittest.cc
index 378094b085e..7628002ce6a 100644
--- a/chromium/components/autofill/core/browser/validation_unittest.cc
+++ b/chromium/components/autofill/core/browser/validation_unittest.cc
@@ -98,11 +98,11 @@ const char16_t* const kPlausibleCreditCardCVCNumbers[] = {u"1234", u"2099",
TEST(AutofillValidation, IsValidCreditCardNumber) {
for (const char16_t* valid_number : kValidNumbers) {
- SCOPED_TRACE(valid_number);
+ SCOPED_TRACE(base::UTF16ToUTF8(valid_number));
EXPECT_TRUE(IsValidCreditCardNumber(valid_number));
}
for (const char16_t* invalid_number : kInvalidNumbers) {
- SCOPED_TRACE(invalid_number);
+ SCOPED_TRACE(base::UTF16ToUTF8(invalid_number));
EXPECT_FALSE(IsValidCreditCardNumber(invalid_number));
}
}
@@ -111,25 +111,26 @@ TEST(AutofillValidation, IsValidCreditCardNumber) {
TEST(AutofillValidation, IsPlausibleCreditCardExparationYear) {
for (const char16_t* plausible_year : kPlausibleCreditCardExpirationYears) {
EXPECT_TRUE(IsPlausible4DigitExpirationYear(plausible_year))
- << plausible_year;
+ << base::UTF16ToUTF8(plausible_year);
}
for (const char16_t* unplausible_year :
kUnplausibleCreditCardExpirationYears) {
EXPECT_FALSE(IsPlausible4DigitExpirationYear(unplausible_year))
- << unplausible_year;
+ << base::UTF16ToUTF8(unplausible_year);
}
}
// Test the plausibility of supplied CVC numbers.
TEST(AutofillValidation, IsPlausibleCreditCardCVCNumber) {
for (const char16_t* plausible_cvc : kPlausibleCreditCardCVCNumbers) {
- EXPECT_TRUE(IsPlausibleCreditCardCVCNumber(plausible_cvc)) << plausible_cvc;
+ EXPECT_TRUE(IsPlausibleCreditCardCVCNumber(plausible_cvc))
+ << base::UTF16ToUTF8(plausible_cvc);
}
for (const char16_t* unplausible_cvc : kUnplausibleCreditCardCVCNumbers) {
EXPECT_FALSE(IsPlausibleCreditCardCVCNumber(unplausible_cvc))
- << unplausible_cvc;
+ << base::UTF16ToUTF8(unplausible_cvc);
}
}
@@ -151,13 +152,13 @@ TEST(AutofillValidation, IsValidCreditCardIntExpirationDate) {
TEST(AutofillValidation, IsValidCreditCardSecurityCode) {
for (const auto data : kValidSecurityCodeCardTypePairs) {
- SCOPED_TRACE(data.security_code);
+ SCOPED_TRACE(base::UTF16ToUTF8(data.security_code));
SCOPED_TRACE(data.card_network);
EXPECT_TRUE(
IsValidCreditCardSecurityCode(data.security_code, data.card_network));
}
for (const auto data : kInvalidSecurityCodeCardTypePairs) {
- SCOPED_TRACE(data.security_code);
+ SCOPED_TRACE(base::UTF16ToUTF8(data.security_code));
SCOPED_TRACE(data.card_network);
EXPECT_FALSE(
IsValidCreditCardSecurityCode(data.security_code, data.card_network));
@@ -166,11 +167,11 @@ TEST(AutofillValidation, IsValidCreditCardSecurityCode) {
TEST(AutofillValidation, IsValidEmailAddress) {
for (const char16_t* valid_email : kValidEmailAddress) {
- SCOPED_TRACE(valid_email);
+ SCOPED_TRACE(base::UTF16ToUTF8(valid_email));
EXPECT_TRUE(IsValidEmailAddress(valid_email));
}
for (const char16_t* invalid_email : kInvalidEmailAddress) {
- SCOPED_TRACE(invalid_email);
+ SCOPED_TRACE(base::UTF16ToUTF8(invalid_email));
EXPECT_FALSE(IsValidEmailAddress(invalid_email));
}
}
@@ -200,8 +201,8 @@ TEST_P(AutofillTypeValidationTest, IsValidForType) {
EXPECT_EQ(
GetParam().expected_valid,
IsValidForType(GetParam().value, GetParam().field_type, &error_message))
- << "Failed to validate " << GetParam().value << " (type "
- << GetParam().field_type << ")";
+ << "Failed to validate " << base::UTF16ToUTF8(GetParam().value)
+ << " (type " << GetParam().field_type << ")";
if (!GetParam().expected_valid) {
EXPECT_EQ(l10n_util::GetStringUTF16(GetParam().expected_error_id),
error_message);
@@ -360,7 +361,7 @@ TEST_P(AutofillCCNumberValidationTest, IsValidCreditCardNumber) {
IsValidCreditCardNumberForBasicCardNetworks(
GetParam().value, GetParam().supported_basic_card_networks,
&error_message))
- << "Failed to validate CC number " << GetParam().value;
+ << "Failed to validate CC number " << base::UTF16ToUTF8(GetParam().value);
if (!GetParam().expected_valid) {
EXPECT_EQ(l10n_util::GetStringUTF16(GetParam().expected_error_id),
error_message);
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 7912eff9149..e074e8c79b9 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
@@ -33,8 +33,8 @@
#include "components/sync/protocol/autofill_specifics.pb.h"
#include "components/sync/protocol/entity_metadata.pb.h"
#include "components/sync/protocol/model_type_state.pb.h"
-#include "components/sync/test/model/mock_model_type_change_processor.h"
-#include "components/sync/test/model/test_matchers.h"
+#include "components/sync/test/mock_model_type_change_processor.h"
+#include "components/sync/test/test_matchers.h"
#include "components/webdata/common/web_database.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
diff --git a/chromium/components/autofill/core/browser/webdata/autofill_change.h b/chromium/components/autofill/core/browser/webdata/autofill_change.h
index 9da26e5da7c..a7dbcca157a 100644
--- a/chromium/components/autofill/core/browser/webdata/autofill_change.h
+++ b/chromium/components/autofill/core/browser/webdata/autofill_change.h
@@ -16,6 +16,7 @@
namespace autofill {
class CreditCard;
+class IBAN;
// For classic Autofill form fields, the KeyType is AutofillKey.
// Autofill++ types such as AutofillProfile and CreditCard simply use a string.
@@ -80,6 +81,7 @@ class AutofillDataModelChange : public GenericAutofillChange<std::string> {
typedef AutofillDataModelChange<AutofillProfile> AutofillProfileChange;
typedef AutofillDataModelChange<CreditCard> CreditCardChange;
+typedef AutofillDataModelChange<IBAN> IBANChange;
class AutofillProfileDeepChange : public AutofillProfileChange {
public:
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 1b7749f9dc7..19385e1de0e 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
@@ -42,8 +42,8 @@
#include "components/sync/protocol/entity_data.h"
#include "components/sync/protocol/entity_specifics.pb.h"
#include "components/sync/protocol/model_type_state.pb.h"
-#include "components/sync/test/model/mock_model_type_change_processor.h"
-#include "components/sync/test/model/sync_error_factory_mock.h"
+#include "components/sync/test/mock_model_type_change_processor.h"
+#include "components/sync/test/sync_error_factory_mock.h"
#include "components/webdata/common/web_database.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
diff --git a/chromium/components/autofill/core/browser/webdata/autofill_table.cc b/chromium/components/autofill/core/browser/webdata/autofill_table.cc
index 3366f595c0c..0eeacd5407e 100644
--- a/chromium/components/autofill/core/browser/webdata/autofill_table.cc
+++ b/chromium/components/autofill/core/browser/webdata/autofill_table.cc
@@ -7,11 +7,13 @@
#include <stdint.h>
#include <algorithm>
+#include <initializer_list>
#include <limits>
#include <map>
#include <memory>
#include <set>
#include <utility>
+#include <vector>
#include "base/command_line.h"
#include "base/containers/contains.h"
@@ -21,6 +23,7 @@
#include "base/numerics/safe_conversions.h"
#include "base/strings/strcat.h"
#include "base/strings/string_number_conversions.h"
+#include "base/strings/string_piece.h"
#include "base/strings/string_util.h"
#include "base/strings/utf_string_conversions.h"
#include "base/time/time.h"
@@ -30,6 +33,7 @@
#include "components/autofill/core/browser/data_model/autofill_profile.h"
#include "components/autofill/core/browser/data_model/credit_card.h"
#include "components/autofill/core/browser/data_model/credit_card_cloud_token_data.h"
+#include "components/autofill/core/browser/data_model/iban.h"
#include "components/autofill/core/browser/geo/autofill_country.h"
#include "components/autofill/core/browser/payments/payments_customer_data.h"
#include "components/autofill/core/browser/personal_data_manager.h"
@@ -57,6 +61,432 @@ namespace autofill {
namespace {
+constexpr base::StringPiece kAutofillTable = "autofill";
+constexpr base::StringPiece kName = "name";
+constexpr base::StringPiece kValue = "value";
+constexpr base::StringPiece kValueLower = "value_lower";
+constexpr base::StringPiece kDateCreated = "date_created";
+constexpr base::StringPiece kDateLastUsed = "date_last_used";
+constexpr base::StringPiece kCount = "count";
+
+constexpr base::StringPiece kAutofillProfilesTable = "autofill_profiles";
+constexpr base::StringPiece kGuid = "guid";
+constexpr base::StringPiece kLabel = "label";
+constexpr base::StringPiece kCompanyName = "company_name";
+constexpr base::StringPiece kStreetAddress = "street_address";
+constexpr base::StringPiece kDependentLocality = "dependent_locality";
+constexpr base::StringPiece kCity = "city";
+constexpr base::StringPiece kState = "state";
+constexpr base::StringPiece kZipcode = "zipcode";
+constexpr base::StringPiece kSortingCode = "sorting_code";
+constexpr base::StringPiece kCountryCode = "country_code";
+constexpr base::StringPiece kUseCount = "use_count";
+constexpr base::StringPiece kUseDate = "use_date";
+constexpr base::StringPiece kDateModified = "date_modified";
+constexpr base::StringPiece kOrigin = "origin";
+constexpr base::StringPiece kLanguageCode = "language_code";
+constexpr base::StringPiece kDisallowSettingsVisibleUpdates =
+ "disallow_settings_visible_updates";
+
+constexpr base::StringPiece kAutofillProfileAddressesTable =
+ "autofill_profile_addresses";
+// kGuid = "guid"
+// kStreetAddress = "street_address"
+constexpr base::StringPiece kStreetName = "street_name";
+constexpr base::StringPiece kDependentStreetName = "dependent_street_name";
+constexpr base::StringPiece kHouseNumber = "house_number";
+constexpr base::StringPiece kSubpremise = "subpremise";
+// kDependentLocality = "dependent_locality"
+// kCity = "city"
+// kState = "state"
+constexpr base::StringPiece kZipCode = "zip_code";
+// kCountryCode = "country_code"
+// kSortingCode = "sorting_code"
+constexpr base::StringPiece kPremiseName = "premise_name";
+constexpr base::StringPiece kApartmentNumber = "apartment_number";
+constexpr base::StringPiece kFloor = "floor";
+constexpr base::StringPiece kStreetAddressStatus = "street_address_status";
+constexpr base::StringPiece kStreetNameStatus = "street_name_status";
+constexpr base::StringPiece kDependentStreetNameStatus =
+ "dependent_street_name_status";
+constexpr base::StringPiece kHouseNumberStatus = "house_number_status";
+constexpr base::StringPiece kSubpremiseStatus = "subpremise_status";
+constexpr base::StringPiece kPremiseNameStatus = "premise_name_status";
+constexpr base::StringPiece kDependentLocalityStatus =
+ "dependent_locality_status";
+constexpr base::StringPiece kCityStatus = "city_status";
+constexpr base::StringPiece kStateStatus = "state_status";
+constexpr base::StringPiece kZipCodeStatus = "zip_code_status";
+constexpr base::StringPiece kCountryCodeStatus = "country_code_status";
+constexpr base::StringPiece kSortingCodeStatus = "sorting_code_status";
+constexpr base::StringPiece kApartmentNumberStatus = "apartment_number_status";
+constexpr base::StringPiece kFloorStatus = "floor_status";
+
+constexpr base::StringPiece kAutofillProfileNamesTable =
+ "autofill_profile_names";
+// kGuid = "guid"
+constexpr base::StringPiece kHonorificPrefix = "honorific_prefix";
+constexpr base::StringPiece kFirstName = "first_name";
+constexpr base::StringPiece kMiddleName = "middle_name";
+constexpr base::StringPiece kLastName = "last_name";
+constexpr base::StringPiece kFirstLastName = "first_last_name";
+constexpr base::StringPiece kConjunctionLastName = "conjunction_last_name";
+constexpr base::StringPiece kSecondLastName = "second_last_name";
+constexpr base::StringPiece kFullName = "full_name";
+constexpr base::StringPiece kFullNameWithHonorificPrefix =
+ "full_name_with_honorific_prefix";
+constexpr base::StringPiece kHonorificPrefixStatus = "honorific_prefix_status";
+constexpr base::StringPiece kFirstNameStatus = "first_name_status";
+constexpr base::StringPiece kMiddleNameStatus = "middle_name_status";
+constexpr base::StringPiece kLastNameStatus = "last_name_status";
+constexpr base::StringPiece kFirstLastNameStatus = "first_last_name_status";
+constexpr base::StringPiece kConjunctionLastNameStatus =
+ "conjunction_last_name_status";
+constexpr base::StringPiece kSecondLastNameStatus = "second_last_name_status";
+constexpr base::StringPiece kFullNameStatus = "full_name_status";
+constexpr base::StringPiece kFullNameWithHonorificPrefixStatus =
+ "full_name_with_honorific_prefix_status";
+
+constexpr base::StringPiece kAutofillProfileEmailsTable =
+ "autofill_profile_emails";
+// kGuid = "guid"
+constexpr base::StringPiece kEmail = "email";
+
+constexpr base::StringPiece kAutofillProfilePhonesTable =
+ "autofill_profile_phones";
+// kGuid = "guid"
+constexpr base::StringPiece kNumber = "number";
+
+constexpr base::StringPiece kAutofillProfileBirthdatesTable =
+ "autofill_profile_birthdates";
+// kGuid = "guid"
+constexpr base::StringPiece kDay = "day";
+constexpr base::StringPiece kMonth = "month";
+constexpr base::StringPiece kYear = "year";
+
+constexpr base::StringPiece kCreditCardsTable = "credit_cards";
+// kGuid = "guid"
+constexpr base::StringPiece kNameOnCard = "name_on_card";
+constexpr base::StringPiece kExpirationMonth = "expiration_month";
+constexpr base::StringPiece kExpirationYear = "expiration_year";
+constexpr base::StringPiece kCardNumberEncrypted = "card_number_encrypted";
+// kUseCount = "use_count"
+// kUseDate = "use_date"
+// kDateModified = "date_modified"
+// kOrigin = "origin"
+constexpr base::StringPiece kBillingAddressId = "billing_address_id";
+constexpr base::StringPiece kNickname = "nickname";
+
+constexpr base::StringPiece kMaskedCreditCardsTable = "masked_credit_cards";
+constexpr base::StringPiece kId = "id";
+constexpr base::StringPiece kStatus = "status";
+// kNameOnCard = "name_on_card"
+constexpr base::StringPiece kNetwork = "network";
+constexpr base::StringPiece kLastFour = "last_four";
+constexpr base::StringPiece kExpMonth = "exp_month";
+constexpr base::StringPiece kExpYear = "exp_year";
+constexpr base::StringPiece kBankName = "bank_name";
+// kNickname = "nickname"
+constexpr base::StringPiece kCardIssuer = "card_issuer";
+constexpr base::StringPiece kInstrumentId = "instrument_id";
+constexpr base::StringPiece kVirtualCardEnrollmentState =
+ "virtual_card_enrollment_state";
+constexpr base::StringPiece kCardArtUrl = "card_art_url";
+constexpr base::StringPiece kProductDescription = "product_description";
+
+constexpr base::StringPiece kUnmaskedCreditCardsTable = "unmasked_credit_cards";
+// kId = "id"
+// kCardNumberEncrypted = "card_number_encrypted"
+constexpr base::StringPiece kUnmaskDate = "unmask_date";
+
+constexpr base::StringPiece kServerCardCloudTokenDataTable =
+ "server_card_cloud_token_data";
+// kId = "id"
+constexpr base::StringPiece kSuffix = "suffix";
+// kExpMonth = "exp_month"
+// kExpYear = "exp_year"
+// kCardArtUrl = "card_art_url"
+constexpr base::StringPiece kInstrumentToken = "instrument_token";
+
+constexpr base::StringPiece kServerCardMetadataTable = "server_card_metadata";
+// kId = "id"
+// kUseCount = "use_count"
+// kUseDate = "use_date"
+// kBillingAddressId = "billing_address_id"
+
+constexpr base::StringPiece kIBANsTable = "ibans";
+// kGuid = "guid"
+// kUseCount = "use_count"
+// kUseDate = "use_date"
+// kValue = "value"
+// kNickname = "nickname"
+
+constexpr base::StringPiece kServerAddressesTable = "server_addresses";
+// kId = "id"
+constexpr base::StringPiece kRecipientName = "recipient_name";
+// kCompanyName = "company_name"
+// kStreetAddress = "street_address"
+constexpr base::StringPiece kAddress1 = "address_1";
+constexpr base::StringPiece kAddress2 = "address_2";
+constexpr base::StringPiece kAddress3 = "address_3";
+constexpr base::StringPiece kAddress4 = "address_4";
+constexpr base::StringPiece kPostalCode = "postal_code";
+// kSortingCode = "sorting_code"
+// kCountryCode = "country_code"
+// kLanguageCode = "language_code"
+constexpr base::StringPiece kPhoneNumber = "phone_number";
+
+constexpr base::StringPiece kServerAddressMetadataTable =
+ "server_address_metadata";
+// kId = "id"
+// kUseCount = "use_count"
+// kUseDate = "use_date"
+constexpr base::StringPiece kHasConverted = "has_converted";
+
+constexpr base::StringPiece kAutofillSyncMetadataTable =
+ "autofill_sync_metadata";
+constexpr base::StringPiece kModelType = "model_type";
+constexpr base::StringPiece kStorageKey = "storage_key";
+// kValue = "value"
+
+constexpr base::StringPiece kAutofillModelTypeStateTable =
+ "autofill_model_type_state";
+// kModelType = "model_type"
+// kValue = "value"
+
+constexpr base::StringPiece kPaymentsCustomerDataTable =
+ "payments_customer_data";
+constexpr base::StringPiece kCustomerId = "customer_id";
+
+constexpr base::StringPiece kPaymentsUpiVpaTable = "payments_upi_vpa";
+constexpr base::StringPiece kVpa = "vpa";
+
+constexpr base::StringPiece kOfferDataTable = "offer_data";
+constexpr base::StringPiece kOfferId = "offer_id";
+constexpr base::StringPiece kOfferRewardAmount = "offer_reward_amount";
+constexpr base::StringPiece kExpiry = "expiry";
+constexpr base::StringPiece kOfferDetailsUrl = "offer_details_url";
+constexpr base::StringPiece kPromoCode = "promo_code";
+constexpr base::StringPiece kValuePropText = "value_prop_text";
+constexpr base::StringPiece kSeeDetailsText = "see_details_text";
+constexpr base::StringPiece kUsageInstructionsText = "usage_instructions_text";
+
+constexpr base::StringPiece kOfferEligibleInstrumentTable =
+ "offer_eligible_instrument";
+// kOfferId = "offer_id"
+// kInstrumentId = "instrument_id"
+
+constexpr base::StringPiece kOfferMerchantDomainTable = "offer_merchant_domain";
+// kOfferId = "offer_id"
+constexpr base::StringPiece kMerchantDomain = "merchant_domain";
+
+// Helper functions to construct SQL statements from string constants.
+// - Functions with names corresponding to SQL keywords execute the statement
+// directly and return if it was successful.
+// - Builder functions only assign the statement, which enables binding
+// values to placeholders before running it.
+
+// Executes a CREATE TABLE statement on `db` which the provided `table_name`.
+// The columns are described in `column_names_and_types` as pairs of
+// (name, type), where type can include modifiers such as NOT NULL.
+// By specifying `compositive_primary_key`, a PRIMARY KEY (col1, col2, ..)
+// clause is generated.
+// Returns true if successful.
+bool CreateTable(
+ sql::Database* db,
+ base::StringPiece table_name,
+ std::initializer_list<std::pair<base::StringPiece, base::StringPiece>>
+ column_names_and_types,
+ std::initializer_list<base::StringPiece> composite_primary_key = {}) {
+ DCHECK(composite_primary_key.size() == 0 ||
+ composite_primary_key.size() >= 2);
+
+ std::vector<std::string> combined_names_and_types;
+ combined_names_and_types.reserve(column_names_and_types.size());
+ for (const auto& [name, type] : column_names_and_types)
+ combined_names_and_types.push_back(base::StrCat({name, " ", type}));
+
+ auto primary_key_clause =
+ composite_primary_key.size() == 0
+ ? ""
+ : base::StrCat({", PRIMARY KEY (",
+ base::JoinString(composite_primary_key, ", "), ")"});
+
+ return db->Execute(
+ base::StrCat({"CREATE TABLE ", table_name, " (",
+ base::JoinString(combined_names_and_types, ", "),
+ primary_key_clause, ")"})
+ .c_str());
+}
+
+// Wrapper around `CreateTable()` that condition the creation on the
+// `table_name` not existing.
+// Returns true if the table now exists.
+bool CreateTableIfNotExists(
+ sql::Database* db,
+ base::StringPiece table_name,
+ std::initializer_list<std::pair<base::StringPiece, base::StringPiece>>
+ column_names_and_types,
+ std::initializer_list<base::StringPiece> composite_primary_key = {}) {
+ return db->DoesTableExist(table_name) ||
+ CreateTable(db, table_name, column_names_and_types,
+ composite_primary_key);
+}
+
+// Creates and index on `table_name` for the provided `columns`.
+// The index is named after the table and columns, separated by '_'.
+// Returns true if successful.
+bool CreateIndex(sql::Database* db,
+ base::StringPiece table_name,
+ std::initializer_list<base::StringPiece> columns) {
+ auto index_name =
+ base::StrCat({table_name, "_", base::JoinString(columns, "_")});
+ return db->Execute(
+ base::StrCat({"CREATE INDEX ", index_name, " ON ", table_name, "(",
+ base::JoinString(columns, ", "), ")"})
+ .c_str());
+}
+
+// Initializes `statement` with INSERT INTO `table_name`, with placeholders for
+// all `column_names`.
+// By setting `or_replace`, INSERT OR REPLACE INTO is used instead.
+void InsertBuilder(sql::Database* db,
+ sql::Statement& statement,
+ base::StringPiece table_name,
+ std::initializer_list<base::StringPiece> column_names,
+ bool or_replace = false) {
+ auto insert_or_replace =
+ base::StrCat({"INSERT ", or_replace ? "OR REPLACE " : ""});
+ auto placeholders = base::JoinString(
+ std::vector<std::string>(column_names.size(), "?"), ", ");
+ statement.Assign(db->GetUniqueStatement(
+ base::StrCat({insert_or_replace, "INTO ", table_name, " (",
+ base::JoinString(column_names, ", "), ") VALUES (",
+ placeholders, ")"})
+ .c_str()));
+}
+
+// Renames the table `from` into `to` and returns true if successful.
+bool RenameTable(sql::Database* db,
+ base::StringPiece from,
+ base::StringPiece to) {
+ return db->Execute(
+ base::StrCat({"ALTER TABLE ", from, " RENAME TO ", to}).c_str());
+}
+
+// Wrapper around `sql::Database::DoesColumnExist()`, because that function
+// only accepts const char* parameters.
+bool DoesColumnExist(sql::Database* db,
+ base::StringPiece table_name,
+ base::StringPiece column_name) {
+ return db->DoesColumnExist(std::string(table_name).c_str(),
+ std::string(column_name).c_str());
+}
+
+// Adds a column named `column_name` of `type` to `table_name` and returns true
+// if successful.
+bool AddColumn(sql::Database* db,
+ base::StringPiece table_name,
+ base::StringPiece column_name,
+ base::StringPiece type) {
+ return db->Execute(base::StrCat({"ALTER TABLE ", table_name, " ADD COLUMN ",
+ column_name, " ", type})
+ .c_str());
+}
+
+// Like `AddColumn()`, but conditioned on `column` not existing in `table_name`.
+// Returns true if the column is now part of the table
+bool AddColumnIfNotExists(sql::Database* db,
+ base::StringPiece table_name,
+ base::StringPiece column_name,
+ base::StringPiece type) {
+ return DoesColumnExist(db, table_name, column_name) ||
+ AddColumn(db, table_name, column_name, type);
+}
+
+// Drops `table_name` and returns true if successful.
+bool DropTable(sql::Database* db, base::StringPiece table_name) {
+ return db->Execute(base::StrCat({"DROP TABLE ", table_name}).c_str());
+}
+
+// Initializes `statement` with DELETE FROM `table_name`. A WHERE clause
+// can optionally be specified in `where_clause`.
+void DeleteBuilder(sql::Database* db,
+ sql::Statement& statement,
+ base::StringPiece table_name,
+ base::StringPiece where_clause = "") {
+ auto where =
+ where_clause.empty() ? "" : base::StrCat({" WHERE ", where_clause});
+ statement.Assign(db->GetUniqueStatement(
+ base::StrCat({"DELETE FROM ", table_name, where}).c_str()));
+}
+
+// Like `DeleteBuilder()`, but runs the statement and returns true if it was
+// successful.
+bool Delete(sql::Database* db,
+ base::StringPiece table_name,
+ base::StringPiece where_clause = "") {
+ sql::Statement statement;
+ DeleteBuilder(db, statement, table_name, where_clause);
+ return statement.Run();
+}
+
+// Wrapper around `DeleteBuilder()`, which initializes the where clause as
+// `column` = `value`.
+// Runs the statement and returns true if it was successful.
+bool DeleteWhereColumnEq(sql::Database* db,
+ base::StringPiece table_name,
+ base::StringPiece column,
+ base::StringPiece value) {
+ sql::Statement statement;
+ DeleteBuilder(db, statement, table_name, base::StrCat({column, " = ?"}));
+ statement.BindString(0, value);
+ return statement.Run();
+}
+
+// Initializes `statement` with SELECT `columns` FROM `table_name` and
+// optionally further `modifiers`, such as WHERE, ORDER BY, etc.
+void SelectBuilder(sql::Database* db,
+ sql::Statement& statement,
+ base::StringPiece table_name,
+ std::initializer_list<base::StringPiece> columns,
+ base::StringPiece modifiers = "") {
+ statement.Assign(db->GetUniqueStatement(
+ base::StrCat({"SELECT ", base::JoinString(columns, ", "), " FROM ",
+ table_name, " ", modifiers})
+ .c_str()));
+}
+
+// Wrapper around `SelectBuilder()` that restricts the it to the provided `guid`
+// and limits the results to 1. Returns `statement.is_valid() &&
+// statement.Step()`.
+bool SelectByGuid(sql::Database* db,
+ sql::Statement& statement,
+ base::StringPiece table_name,
+ std::initializer_list<base::StringPiece> columns,
+ base::StringPiece guid) {
+ DCHECK(base::Contains(columns, kGuid));
+ SelectBuilder(db, statement, table_name, columns, "WHERE guid=? LIMIT 1");
+ statement.BindString(0, guid);
+ return statement.is_valid() && statement.Step();
+}
+
+// Wrapper around `SelectBuilder()` that restricts it to the half-open interval
+// [low, high[ of `column_between`.
+void SelectBetween(sql::Database* db,
+ sql::Statement& statement,
+ base::StringPiece table_name,
+ std::initializer_list<base::StringPiece> columns,
+ base::StringPiece column_between,
+ int64_t low,
+ int64_t high) {
+ auto between_selector = base::StrCat(
+ {"WHERE ", column_between, " >= ? AND ", column_between, " < ?"});
+ SelectBuilder(db, statement, table_name, columns, between_selector);
+ statement.BindInt64(0, low);
+ statement.BindInt64(1, high);
+}
+
// Constant to assign an unset verification status to structured address
// components stored for legacy profiles.
constexpr structured_address::VerificationStatus kNoStatus =
@@ -90,14 +520,12 @@ void BindAutofillProfileToStatement(const AutofillProfile& profile,
int index = 0;
s->BindString(index++, profile.guid());
- s->BindString16(index++, GetInfo(profile, COMPANY_NAME));
- s->BindString16(index++, GetInfo(profile, ADDRESS_HOME_STREET_ADDRESS));
- s->BindString16(index++, GetInfo(profile, ADDRESS_HOME_DEPENDENT_LOCALITY));
- s->BindString16(index++, GetInfo(profile, ADDRESS_HOME_CITY));
- s->BindString16(index++, GetInfo(profile, ADDRESS_HOME_STATE));
- s->BindString16(index++, GetInfo(profile, ADDRESS_HOME_ZIP));
- s->BindString16(index++, GetInfo(profile, ADDRESS_HOME_SORTING_CODE));
- s->BindString16(index++, GetInfo(profile, ADDRESS_HOME_COUNTRY));
+ for (ServerFieldType type :
+ {COMPANY_NAME, ADDRESS_HOME_STREET_ADDRESS,
+ ADDRESS_HOME_DEPENDENT_LOCALITY, ADDRESS_HOME_CITY, ADDRESS_HOME_STATE,
+ ADDRESS_HOME_ZIP, ADDRESS_HOME_SORTING_CODE, ADDRESS_HOME_COUNTRY}) {
+ s->BindString16(index++, GetInfo(profile, type));
+ }
s->BindInt64(index++, profile.use_count());
s->BindInt64(index++, profile.use_date().ToTimeT());
s->BindInt64(index++, modification_date.ToTimeT());
@@ -110,15 +538,12 @@ void BindAutofillProfileToStatement(const AutofillProfile& profile,
void AddAutofillProfileDetailsFromStatement(sql::Statement& s,
AutofillProfile* profile) {
int index = 1; // 0 is for the guid.
- profile->SetRawInfo(COMPANY_NAME, s.ColumnString16(index++));
- profile->SetRawInfo(ADDRESS_HOME_STREET_ADDRESS, s.ColumnString16(index++));
- profile->SetRawInfo(ADDRESS_HOME_DEPENDENT_LOCALITY,
- s.ColumnString16(index++));
- profile->SetRawInfo(ADDRESS_HOME_CITY, s.ColumnString16(index++));
- profile->SetRawInfo(ADDRESS_HOME_STATE, s.ColumnString16(index++));
- profile->SetRawInfo(ADDRESS_HOME_ZIP, s.ColumnString16(index++));
- profile->SetRawInfo(ADDRESS_HOME_SORTING_CODE, s.ColumnString16(index++));
- profile->SetRawInfo(ADDRESS_HOME_COUNTRY, s.ColumnString16(index++));
+ for (ServerFieldType type :
+ {COMPANY_NAME, ADDRESS_HOME_STREET_ADDRESS,
+ ADDRESS_HOME_DEPENDENT_LOCALITY, ADDRESS_HOME_CITY, ADDRESS_HOME_STATE,
+ ADDRESS_HOME_ZIP, ADDRESS_HOME_SORTING_CODE, ADDRESS_HOME_COUNTRY}) {
+ profile->SetRawInfo(type, s.ColumnString16(index++));
+ }
profile->set_use_count(s.ColumnInt64(index++));
profile->set_use_date(base::Time::FromTimeT(s.ColumnInt64(index++)));
profile->set_modification_date(base::Time::FromTimeT(s.ColumnInt64(index++)));
@@ -145,9 +570,10 @@ void BindCreditCardToStatement(const CreditCard& credit_card,
int index = 0;
s->BindString(index++, credit_card.guid());
- s->BindString16(index++, GetInfo(credit_card, CREDIT_CARD_NAME_FULL));
- s->BindString16(index++, GetInfo(credit_card, CREDIT_CARD_EXP_MONTH));
- s->BindString16(index++, GetInfo(credit_card, CREDIT_CARD_EXP_4_DIGIT_YEAR));
+ for (ServerFieldType type : {CREDIT_CARD_NAME_FULL, CREDIT_CARD_EXP_MONTH,
+ CREDIT_CARD_EXP_4_DIGIT_YEAR}) {
+ s->BindString16(index++, GetInfo(credit_card, type));
+ }
BindEncryptedCardToColumn(
s, index++, credit_card.GetRawInfo(CREDIT_CARD_NUMBER), encryptor);
@@ -159,6 +585,20 @@ void BindCreditCardToStatement(const CreditCard& credit_card,
s->BindString16(index++, credit_card.nickname());
}
+void BindIBANToStatement(const IBAN& iban,
+ sql::Statement* s,
+ const AutofillTableEncryptor& encryptor) {
+ DCHECK(base::IsValidGUID(iban.guid()));
+ int index = 0;
+ s->BindString(index++, iban.guid());
+
+ s->BindInt64(index++, iban.use_count());
+ s->BindInt64(index++, iban.use_date().ToTimeT());
+
+ s->BindString16(index++, iban.value());
+ s->BindString16(index++, iban.nickname());
+}
+
std::u16string UnencryptedCardFromColumn(
sql::Statement& s,
int column_index,
@@ -180,10 +620,10 @@ std::unique_ptr<CreditCard> CreditCardFromStatement(
credit_card->set_guid(s.ColumnString(index++));
DCHECK(base::IsValidGUID(credit_card->guid()));
- credit_card->SetRawInfo(CREDIT_CARD_NAME_FULL, s.ColumnString16(index++));
- credit_card->SetRawInfo(CREDIT_CARD_EXP_MONTH, s.ColumnString16(index++));
- credit_card->SetRawInfo(CREDIT_CARD_EXP_4_DIGIT_YEAR,
- s.ColumnString16(index++));
+ for (ServerFieldType type : {CREDIT_CARD_NAME_FULL, CREDIT_CARD_EXP_MONTH,
+ CREDIT_CARD_EXP_4_DIGIT_YEAR}) {
+ credit_card->SetRawInfo(type, s.ColumnString16(index++));
+ }
credit_card->SetRawInfo(CREDIT_CARD_NUMBER,
UnencryptedCardFromColumn(s, index++, encryptor));
credit_card->set_use_count(s.ColumnInt64(index++));
@@ -196,57 +636,55 @@ std::unique_ptr<CreditCard> CreditCardFromStatement(
return credit_card;
}
+std::unique_ptr<IBAN> IBANFromStatement(
+ sql::Statement& s,
+ const AutofillTableEncryptor& encryptor) {
+ auto iban = std::make_unique<IBAN>();
+
+ int index = 0;
+ iban->set_guid(s.ColumnString(index++));
+ DCHECK(base::IsValidGUID(iban->guid()));
+ iban->set_use_count(s.ColumnInt64(index++));
+ iban->set_use_date(base::Time::FromTimeT(s.ColumnInt64(index++)));
+
+ iban->SetRawInfo(IBAN_VALUE, s.ColumnString16(index++));
+ iban->set_nickname(s.ColumnString16(index++));
+ return iban;
+}
+
bool AddAutofillProfileNames(const AutofillProfile& profile,
sql::Database* db) {
if (base::FeatureList::IsEnabled(
features::kAutofillEnableSupportForMoreStructureInNames)) {
- sql::Statement s(db->GetUniqueStatement(
- "INSERT INTO autofill_profile_names "
- "(guid, "
- "honorific_prefix, honorific_prefix_status, "
- "first_name, first_name_status, "
- "middle_name, middle_name_status, "
- "first_last_name, first_last_name_status, "
- "conjunction_last_name, conjunction_last_name_status, "
- "second_last_name, second_last_name_status, "
- "last_name, last_name_status, "
- "full_name, full_name_status, "
- "full_name_with_honorific_prefix, "
- "full_name_with_honorific_prefix_status) "
- "VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)"));
+ sql::Statement s;
+ InsertBuilder(
+ db, s, kAutofillProfileNamesTable,
+ {kGuid, kHonorificPrefix, kHonorificPrefixStatus, kFirstName,
+ kFirstNameStatus, kMiddleName, kMiddleNameStatus, kFirstLastName,
+ kFirstLastNameStatus, kConjunctionLastName, kConjunctionLastNameStatus,
+ kSecondLastName, kSecondLastNameStatus, kLastName, kLastNameStatus,
+ kFullName, kFullNameStatus, kFullNameWithHonorificPrefix,
+ kFullNameWithHonorificPrefixStatus});
s.BindString(0, profile.guid());
- s.BindString16(1, profile.GetRawInfo(NAME_HONORIFIC_PREFIX));
- s.BindInt(2, profile.GetVerificationStatusInt(NAME_HONORIFIC_PREFIX));
- s.BindString16(3, profile.GetRawInfo(NAME_FIRST));
- s.BindInt(4, profile.GetVerificationStatusInt(NAME_FIRST));
- s.BindString16(5, profile.GetRawInfo(NAME_MIDDLE));
- s.BindInt(6, profile.GetVerificationStatusInt(NAME_MIDDLE));
- s.BindString16(7, profile.GetRawInfo(NAME_LAST_FIRST));
- s.BindInt(8, profile.GetVerificationStatusInt(NAME_LAST_FIRST));
- s.BindString16(9, profile.GetRawInfo(NAME_LAST_CONJUNCTION));
- s.BindInt(10, profile.GetVerificationStatusInt(NAME_LAST_CONJUNCTION));
- s.BindString16(11, profile.GetRawInfo(NAME_LAST_SECOND));
- s.BindInt(12, profile.GetVerificationStatusInt(NAME_LAST_SECOND));
- s.BindString16(13, profile.GetRawInfo(NAME_LAST));
- s.BindInt(14, profile.GetVerificationStatusInt(NAME_LAST));
- s.BindString16(15, profile.GetRawInfo(NAME_FULL));
- s.BindInt(16, profile.GetVerificationStatusInt(NAME_FULL));
- s.BindString16(17, profile.GetRawInfo(NAME_FULL_WITH_HONORIFIC_PREFIX));
- s.BindInt(
- 18, profile.GetVerificationStatusInt(NAME_FULL_WITH_HONORIFIC_PREFIX));
+ int index = 1;
+ for (ServerFieldType type :
+ {NAME_HONORIFIC_PREFIX, NAME_FIRST, NAME_MIDDLE, NAME_LAST_FIRST,
+ NAME_LAST_CONJUNCTION, NAME_LAST_SECOND, NAME_LAST, NAME_FULL,
+ NAME_FULL_WITH_HONORIFIC_PREFIX}) {
+ s.BindString16(index++, profile.GetRawInfo(type));
+ s.BindInt(index++, profile.GetVerificationStatusInt(type));
+ }
return s.Run();
}
// Add the new name.
- sql::Statement s(
- db->GetUniqueStatement("INSERT INTO autofill_profile_names"
- " (guid, first_name, middle_name, last_name, "
- "full_name) "
- "VALUES (?,?,?,?,?)"));
+ sql::Statement s;
+ InsertBuilder(db, s, kAutofillProfileNamesTable,
+ {kGuid, kFirstName, kMiddleName, kLastName, kFullName});
s.BindString(0, profile.guid());
- s.BindString16(1, profile.GetRawInfo(NAME_FIRST));
- s.BindString16(2, profile.GetRawInfo(NAME_MIDDLE));
- s.BindString16(3, profile.GetRawInfo(NAME_LAST));
- s.BindString16(4, profile.GetRawInfo(NAME_FULL));
+ int index = 1;
+ for (ServerFieldType type : {NAME_FIRST, NAME_MIDDLE, NAME_LAST, NAME_FULL}) {
+ s.BindString16(index++, profile.GetRawInfo(type));
+ }
return s.Run();
}
@@ -257,57 +695,50 @@ bool AddAutofillProfileAddresses(const AutofillProfile& profile,
// votes.
if (base::FeatureList::IsEnabled(
features::kAutofillEnableSupportForMoreStructureInAddresses)) {
- sql::Statement s(db->GetUniqueStatement(
- "INSERT INTO autofill_profile_addresses "
- "(guid, "
- "street_address, street_address_status, "
- "street_name, street_name_status, "
- "dependent_street_name, dependent_street_name_status, "
- "house_number, house_number_status, "
- "subpremise, subpremise_status, "
- "premise_name, premise_name_status, "
- "dependent_locality, dependent_locality_status, "
- "city, city_status, "
- "state, state_status, "
- "zip_code, zip_code_status, "
- "sorting_code, sorting_code_status, "
- "country_code, country_code_status, "
- "apartment_number, apartment_number_status, "
- "floor, floor_status) "
- "VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)"));
+ sql::Statement s;
+ InsertBuilder(db, s, kAutofillProfileAddressesTable,
+ {kGuid,
+ kStreetAddress,
+ kStreetAddressStatus,
+ kStreetName,
+ kStreetNameStatus,
+ kDependentStreetName,
+ kDependentStreetNameStatus,
+ kHouseNumber,
+ kHouseNumberStatus,
+ kSubpremise,
+ kSubpremiseStatus,
+ kPremiseName,
+ kPremiseNameStatus,
+ kDependentLocality,
+ kDependentLocalityStatus,
+ kCity,
+ kCityStatus,
+ kState,
+ kStateStatus,
+ kZipCode,
+ kZipCodeStatus,
+ kSortingCode,
+ kSortingCodeStatus,
+ kCountryCode,
+ kCountryCodeStatus,
+ kApartmentNumber,
+ kApartmentNumberStatus,
+ kFloor,
+ kFloorStatus});
s.BindString(0, profile.guid());
- s.BindString16(1, profile.GetRawInfo(ADDRESS_HOME_STREET_ADDRESS));
- s.BindInt(2, profile.GetVerificationStatusInt(ADDRESS_HOME_STREET_ADDRESS));
- s.BindString16(3, profile.GetRawInfo(ADDRESS_HOME_STREET_NAME));
- s.BindInt(4, profile.GetVerificationStatusInt(ADDRESS_HOME_STREET_NAME));
- s.BindString16(5, profile.GetRawInfo(ADDRESS_HOME_DEPENDENT_STREET_NAME));
- s.BindInt(6, profile.GetVerificationStatusInt(
- ADDRESS_HOME_DEPENDENT_STREET_NAME));
- s.BindString16(7, profile.GetRawInfo(ADDRESS_HOME_HOUSE_NUMBER));
- s.BindInt(8, profile.GetVerificationStatusInt(ADDRESS_HOME_HOUSE_NUMBER));
- s.BindString16(9, profile.GetRawInfo(ADDRESS_HOME_SUBPREMISE));
- s.BindInt(10, profile.GetVerificationStatusInt(ADDRESS_HOME_SUBPREMISE));
- s.BindString16(11, profile.GetRawInfo(ADDRESS_HOME_PREMISE_NAME));
- s.BindInt(12, profile.GetVerificationStatusInt(ADDRESS_HOME_PREMISE_NAME));
- s.BindString16(13, profile.GetRawInfo(ADDRESS_HOME_DEPENDENT_LOCALITY));
- s.BindInt(
- 14, profile.GetVerificationStatusInt(ADDRESS_HOME_DEPENDENT_LOCALITY));
- s.BindString16(15, profile.GetRawInfo(ADDRESS_HOME_CITY));
- s.BindInt(16, profile.GetVerificationStatusInt(ADDRESS_HOME_CITY));
- s.BindString16(17, profile.GetRawInfo(ADDRESS_HOME_STATE));
- s.BindInt(18, profile.GetVerificationStatusInt(ADDRESS_HOME_STATE));
- s.BindString16(19, profile.GetRawInfo(ADDRESS_HOME_ZIP));
- s.BindInt(20, profile.GetVerificationStatusInt(ADDRESS_HOME_ZIP));
- s.BindString16(21, profile.GetRawInfo(ADDRESS_HOME_SORTING_CODE));
- s.BindInt(22, profile.GetVerificationStatusInt(ADDRESS_HOME_SORTING_CODE));
- s.BindString16(23, profile.GetRawInfo(ADDRESS_HOME_COUNTRY));
- s.BindInt(24, profile.GetVerificationStatusInt(ADDRESS_HOME_COUNTRY));
- s.BindString16(25, profile.GetRawInfo(ADDRESS_HOME_APT_NUM));
- s.BindInt(26, profile.GetVerificationStatusInt(ADDRESS_HOME_APT_NUM));
- s.BindString16(27, profile.GetRawInfo(ADDRESS_HOME_FLOOR));
- s.BindInt(28, profile.GetVerificationStatusInt(ADDRESS_HOME_FLOOR));
-
+ int index = 1;
+ for (ServerFieldType type :
+ {ADDRESS_HOME_STREET_ADDRESS, ADDRESS_HOME_STREET_NAME,
+ ADDRESS_HOME_DEPENDENT_STREET_NAME, ADDRESS_HOME_HOUSE_NUMBER,
+ ADDRESS_HOME_SUBPREMISE, ADDRESS_HOME_PREMISE_NAME,
+ ADDRESS_HOME_DEPENDENT_LOCALITY, ADDRESS_HOME_CITY,
+ ADDRESS_HOME_STATE, ADDRESS_HOME_ZIP, ADDRESS_HOME_SORTING_CODE,
+ ADDRESS_HOME_COUNTRY, ADDRESS_HOME_APT_NUM, ADDRESS_HOME_FLOOR}) {
+ s.BindString16(index++, profile.GetRawInfo(type));
+ s.BindInt(index++, profile.GetVerificationStatusInt(type));
+ }
return s.Run();
}
return true;
@@ -315,27 +746,16 @@ bool AddAutofillProfileAddresses(const AutofillProfile& profile,
bool AddAutofillProfileNamesToProfile(sql::Database* db,
AutofillProfile* profile) {
- sql::Statement s(db->GetUniqueStatement(
- "SELECT "
- "guid, "
- "honorific_prefix, honorific_prefix_status, "
- "first_name, first_name_status, "
- "middle_name, middle_name_status, "
- "first_last_name, first_last_name_status, "
- "conjunction_last_name, conjunction_last_name_status, "
- "second_last_name, second_last_name_status, "
- "last_name, last_name_status, "
- "full_name, full_name_status, "
- "full_name_with_honorific_prefix, full_name_with_honorific_prefix_status "
- "FROM autofill_profile_names "
- "WHERE guid=? "
- "LIMIT 1"));
- s.BindString(0, profile->guid());
-
- if (!s.is_valid())
- return false;
-
- if (s.Step()) {
+ sql::Statement s;
+ if (SelectByGuid(
+ db, s, kAutofillProfileNamesTable,
+ {kGuid, kHonorificPrefix, kHonorificPrefixStatus, kFirstName,
+ kFirstNameStatus, kMiddleName, kMiddleNameStatus, kFirstLastName,
+ kFirstLastNameStatus, kConjunctionLastName,
+ kConjunctionLastNameStatus, kSecondLastName, kSecondLastNameStatus,
+ kLastName, kLastNameStatus, kFullName, kFullNameStatus,
+ kFullNameWithHonorificPrefix, kFullNameWithHonorificPrefixStatus},
+ profile->guid())) {
DCHECK_EQ(profile->guid(), s.ColumnString(0));
if (base::FeatureList::IsEnabled(
@@ -343,25 +763,15 @@ bool AddAutofillProfileNamesToProfile(sql::Database* db,
// Whether or not the name has a legacy structure, set all
// components. The Profile can detect that it must be migrated because
// all values have the validation status |kNoStatus|.
- profile->SetRawInfoWithVerificationStatusInt(
- NAME_HONORIFIC_PREFIX, s.ColumnString16(1), s.ColumnInt(2));
- profile->SetRawInfoWithVerificationStatusInt(
- NAME_FIRST, s.ColumnString16(3), s.ColumnInt(4));
- profile->SetRawInfoWithVerificationStatusInt(
- NAME_MIDDLE, s.ColumnString16(5), s.ColumnInt(6));
- profile->SetRawInfoWithVerificationStatusInt(
- NAME_LAST_FIRST, s.ColumnString16(7), s.ColumnInt(8));
- profile->SetRawInfoWithVerificationStatusInt(
- NAME_LAST_CONJUNCTION, s.ColumnString16(9), s.ColumnInt(10));
- profile->SetRawInfoWithVerificationStatusInt(
- NAME_LAST_SECOND, s.ColumnString16(11), s.ColumnInt(12));
- profile->SetRawInfoWithVerificationStatusInt(
- NAME_LAST, s.ColumnString16(13), s.ColumnInt(14));
- profile->SetRawInfoWithVerificationStatusInt(
- NAME_FULL, s.ColumnString16(15), s.ColumnInt(16));
- profile->SetRawInfoWithVerificationStatusInt(
- NAME_FULL_WITH_HONORIFIC_PREFIX, s.ColumnString16(17),
- s.ColumnInt(18));
+ int index = 1;
+ for (ServerFieldType type :
+ {NAME_HONORIFIC_PREFIX, NAME_FIRST, NAME_MIDDLE, NAME_LAST_FIRST,
+ NAME_LAST_CONJUNCTION, NAME_LAST_SECOND, NAME_LAST, NAME_FULL,
+ NAME_FULL_WITH_HONORIFIC_PREFIX}) {
+ profile->SetRawInfoWithVerificationStatusInt(
+ type, s.ColumnString16(index), s.ColumnInt(index + 1));
+ index += 2;
+ }
} else {
// If structured components are not enabled, only use the legacy
// structure.
@@ -380,121 +790,102 @@ bool AddAutofillProfileNamesToProfile(sql::Database* db,
bool AddAutofillProfileAddressesToProfile(sql::Database* db,
AutofillProfile* profile) {
- if (base::FeatureList::IsEnabled(
+ if (!base::FeatureList::IsEnabled(
features::kAutofillEnableSupportForMoreStructureInAddresses)) {
- sql::Statement s(db->GetUniqueStatement(
- "SELECT "
- "guid, "
- "street_address, street_address_status, "
- "street_name, street_name_status, "
- "dependent_street_name, dependent_street_name_status, "
- "house_number, house_number_status, "
- "subpremise, subpremise_status, "
- "premise_name, premise_name_status, "
- "dependent_locality, dependent_locality_status, "
- "city, city_status, "
- "state, state_status, "
- "zip_code, zip_code_status, "
- "sorting_code, sorting_code_status, "
- "country_code, country_code_status, "
- "apartment_number, apartment_number_status, "
- "floor, floor_status "
- "FROM autofill_profile_addresses "
- "WHERE guid=? "
- "LIMIT 1"));
- s.BindString(0, profile->guid());
-
- if (!s.is_valid())
- return false;
-
- if (s.Step()) {
- DCHECK_EQ(profile->guid(), s.ColumnString(0));
- std::u16string street_address = s.ColumnString16(1);
- std::u16string dependent_locality = s.ColumnString16(13);
- std::u16string city = s.ColumnString16(15);
- std::u16string state = s.ColumnString16(17);
- std::u16string zip_code = s.ColumnString16(19);
- std::u16string sorting_code = s.ColumnString16(21);
- std::u16string country = s.ColumnString16(23);
-
- std::u16string street_address_legacy =
- profile->GetRawInfo(ADDRESS_HOME_STREET_ADDRESS);
- std::u16string dependent_locality_legacy =
- profile->GetRawInfo(ADDRESS_HOME_DEPENDENT_LOCALITY);
- std::u16string city_legacy = profile->GetRawInfo(ADDRESS_HOME_CITY);
- std::u16string state_legacy = profile->GetRawInfo(ADDRESS_HOME_STATE);
- std::u16string zip_code_legacy = profile->GetRawInfo(ADDRESS_HOME_ZIP);
- std::u16string sorting_code_legacy =
- profile->GetRawInfo(ADDRESS_HOME_SORTING_CODE);
- std::u16string country_legacy = profile->GetRawInfo(ADDRESS_HOME_COUNTRY);
-
- // At this stage, the unstructured address was already written to
- // the profile. If the address was changed by a legacy client, the
- // information diverged from the one in this table that is only written by
- // new clients. In this case remove the corresponding row from this table.
- // Otherwise, read the new structured tokens and set the verification
- // statuses for all tokens.
- if (street_address == street_address_legacy &&
- dependent_locality == dependent_locality_legacy &&
- city == city_legacy && state == state_legacy &&
- zip_code == zip_code_legacy && sorting_code == sorting_code_legacy &&
- country == country_legacy) {
- profile->SetRawInfoWithVerificationStatusInt(
- ADDRESS_HOME_STREET_ADDRESS, street_address, s.ColumnInt(2));
- profile->SetRawInfoWithVerificationStatusInt(
- ADDRESS_HOME_STREET_NAME, s.ColumnString16(3), s.ColumnInt(4));
- profile->SetRawInfoWithVerificationStatusInt(
- ADDRESS_HOME_DEPENDENT_STREET_NAME, s.ColumnString16(5),
- s.ColumnInt(6));
- profile->SetRawInfoWithVerificationStatusInt(
- ADDRESS_HOME_HOUSE_NUMBER, s.ColumnString16(7), s.ColumnInt(8));
- profile->SetRawInfoWithVerificationStatusInt(
- ADDRESS_HOME_SUBPREMISE, s.ColumnString16(9), s.ColumnInt(10));
- profile->SetRawInfoWithVerificationStatusInt(
- ADDRESS_HOME_PREMISE_NAME, s.ColumnString16(11), s.ColumnInt(12));
- profile->SetRawInfoWithVerificationStatusInt(
- ADDRESS_HOME_DEPENDENT_LOCALITY, dependent_locality,
- s.ColumnInt(14));
- profile->SetRawInfoWithVerificationStatusInt(ADDRESS_HOME_CITY, city,
- s.ColumnInt(16));
- profile->SetRawInfoWithVerificationStatusInt(ADDRESS_HOME_STATE, state,
- s.ColumnInt(18));
- profile->SetRawInfoWithVerificationStatusInt(ADDRESS_HOME_ZIP, zip_code,
- s.ColumnInt(20));
- profile->SetRawInfoWithVerificationStatusInt(
- ADDRESS_HOME_SORTING_CODE, sorting_code, s.ColumnInt(22));
- profile->SetRawInfoWithVerificationStatusInt(ADDRESS_HOME_COUNTRY,
- country, s.ColumnInt(24));
- profile->SetRawInfoWithVerificationStatusInt(
- ADDRESS_HOME_APT_NUM, s.ColumnString16(25), s.ColumnInt(26));
+ return true;
+ }
+ sql::Statement s;
+ if (SelectByGuid(db, s, kAutofillProfileAddressesTable,
+ {kGuid,
+ kStreetAddress,
+ kStreetAddressStatus,
+ kStreetName,
+ kStreetNameStatus,
+ kDependentStreetName,
+ kDependentStreetNameStatus,
+ kHouseNumber,
+ kHouseNumberStatus,
+ kSubpremise,
+ kSubpremiseStatus,
+ kPremiseName,
+ kPremiseNameStatus,
+ kDependentLocality,
+ kDependentLocalityStatus,
+ kCity,
+ kCityStatus,
+ kState,
+ kStateStatus,
+ kZipCode,
+ kZipCodeStatus,
+ kSortingCode,
+ kSortingCodeStatus,
+ kCountryCode,
+ kCountryCodeStatus,
+ kApartmentNumber,
+ kApartmentNumberStatus,
+ kFloor,
+ kFloorStatus},
+ profile->guid())) {
+ DCHECK_EQ(profile->guid(), s.ColumnString(0));
+ std::u16string street_address = s.ColumnString16(1);
+ std::u16string dependent_locality = s.ColumnString16(13);
+ std::u16string city = s.ColumnString16(15);
+ std::u16string state = s.ColumnString16(17);
+ std::u16string zip_code = s.ColumnString16(19);
+ std::u16string sorting_code = s.ColumnString16(21);
+ std::u16string country = s.ColumnString16(23);
+
+ std::u16string street_address_legacy =
+ profile->GetRawInfo(ADDRESS_HOME_STREET_ADDRESS);
+ std::u16string dependent_locality_legacy =
+ profile->GetRawInfo(ADDRESS_HOME_DEPENDENT_LOCALITY);
+ std::u16string city_legacy = profile->GetRawInfo(ADDRESS_HOME_CITY);
+ std::u16string state_legacy = profile->GetRawInfo(ADDRESS_HOME_STATE);
+ std::u16string zip_code_legacy = profile->GetRawInfo(ADDRESS_HOME_ZIP);
+ std::u16string sorting_code_legacy =
+ profile->GetRawInfo(ADDRESS_HOME_SORTING_CODE);
+ std::u16string country_legacy = profile->GetRawInfo(ADDRESS_HOME_COUNTRY);
+
+ // At this stage, the unstructured address was already written to
+ // the profile. If the address was changed by a legacy client, the
+ // information diverged from the one in this table that is only written by
+ // new clients. In this case remove the corresponding row from this table.
+ // Otherwise, read the new structured tokens and set the verification
+ // statuses for all tokens.
+ if (street_address == street_address_legacy &&
+ dependent_locality == dependent_locality_legacy &&
+ city == city_legacy && state == state_legacy &&
+ zip_code == zip_code_legacy && sorting_code == sorting_code_legacy &&
+ country == country_legacy) {
+ int index = 1;
+ for (ServerFieldType type :
+ {ADDRESS_HOME_STREET_ADDRESS, ADDRESS_HOME_STREET_NAME,
+ ADDRESS_HOME_DEPENDENT_STREET_NAME, ADDRESS_HOME_HOUSE_NUMBER,
+ ADDRESS_HOME_SUBPREMISE, ADDRESS_HOME_PREMISE_NAME,
+ ADDRESS_HOME_DEPENDENT_LOCALITY, ADDRESS_HOME_CITY,
+ ADDRESS_HOME_STATE, ADDRESS_HOME_ZIP, ADDRESS_HOME_SORTING_CODE,
+ ADDRESS_HOME_COUNTRY, ADDRESS_HOME_APT_NUM, ADDRESS_HOME_FLOOR}) {
profile->SetRawInfoWithVerificationStatusInt(
- ADDRESS_HOME_FLOOR, s.ColumnString16(27), s.ColumnInt(28));
- } else {
- // Remove the structured information from the table for
- // eventual deletion consistency.
- sql::Statement s1(db->GetUniqueStatement(
- "DELETE FROM autofill_profile_addresses WHERE guid = ?"));
- s1.BindString(0, profile->guid());
- s1.Run();
+ type, s.ColumnString16(index), s.ColumnInt(index + 1));
+ index += 2;
}
+ } else {
+ // Remove the structured information from the table for
+ // eventual deletion consistency.
+ DeleteWhereColumnEq(db, kAutofillProfileAddressesTable, kGuid,
+ profile->guid());
}
- return s.Succeeded();
}
- return true;
+ return s.Succeeded();
}
bool AddAutofillProfileEmailsToProfile(sql::Database* db,
AutofillProfile* profile) {
// TODO(estade): update schema so that multiple emails are not associated
// per unique profile guid. Please refer https://crbug.com/497934.
- sql::Statement s(db->GetUniqueStatement(
- "SELECT guid, email FROM autofill_profile_emails WHERE guid=? LIMIT 1"));
- s.BindString(0, profile->guid());
-
- if (!s.is_valid())
- return false;
-
- if (s.Step()) {
+ sql::Statement s;
+ if (SelectByGuid(db, s, kAutofillProfileEmailsTable, {kGuid, kEmail},
+ profile->guid())) {
DCHECK_EQ(profile->guid(), s.ColumnString(0));
profile->SetRawInfo(EMAIL_ADDRESS, s.ColumnString16(1));
}
@@ -506,14 +897,9 @@ bool AddAutofillProfilePhonesToProfile(sql::Database* db,
// TODO(estade): update schema so that multiple phone numbers are not
// associated per unique profile guid. Please refer
// https://crbug.com/497934.
- sql::Statement s(db->GetUniqueStatement(
- "SELECT guid, number FROM autofill_profile_phones WHERE guid=? LIMIT 1"));
- s.BindString(0, profile->guid());
-
- if (!s.is_valid())
- return false;
-
- if (s.Step()) {
+ sql::Statement s;
+ if (SelectByGuid(db, s, kAutofillProfilePhonesTable, {kGuid, kNumber},
+ profile->guid())) {
DCHECK_EQ(profile->guid(), s.ColumnString(0));
profile->SetRawInfo(PHONE_HOME_WHOLE_NUMBER, s.ColumnString16(1));
}
@@ -522,24 +908,13 @@ bool AddAutofillProfilePhonesToProfile(sql::Database* db,
bool AddAutofillProfileBirthdateToProfile(sql::Database* db,
AutofillProfile* profile) {
- if (!base::FeatureList::IsEnabled(
- features::kAutofillEnableCompatibilitySupportForBirthdates)) {
- return true;
- }
-
- sql::Statement s(db->GetUniqueStatement(
- "SELECT guid, day, month, year FROM autofill_profile_birthdates WHERE "
- "guid=? LIMIT 1"));
- s.BindString(0, profile->guid());
-
- if (!s.is_valid())
- return false;
-
- if (s.Step()) {
+ sql::Statement s;
+ if (SelectByGuid(db, s, kAutofillProfileBirthdatesTable,
+ {kGuid, kDay, kMonth, kYear}, profile->guid())) {
DCHECK_EQ(profile->guid(), s.ColumnString(0));
profile->SetRawInfoAsInt(BIRTHDATE_DAY, s.ColumnInt(1));
profile->SetRawInfoAsInt(BIRTHDATE_MONTH, s.ColumnInt(2));
- profile->SetRawInfoAsInt(BIRTHDATE_YEAR_4_DIGITS, s.ColumnInt(3));
+ profile->SetRawInfoAsInt(BIRTHDATE_4_DIGIT_YEAR, s.ColumnInt(3));
}
return s.Succeeded();
}
@@ -547,8 +922,8 @@ bool AddAutofillProfileBirthdateToProfile(sql::Database* db,
bool AddAutofillProfileEmails(const AutofillProfile& profile,
sql::Database* db) {
// Add the new email.
- sql::Statement s(db->GetUniqueStatement(
- "INSERT INTO autofill_profile_emails (guid, email) VALUES (?,?)"));
+ sql::Statement s;
+ InsertBuilder(db, s, kAutofillProfileEmailsTable, {kGuid, kEmail});
s.BindString(0, profile.guid());
s.BindString16(1, profile.GetRawInfo(EMAIL_ADDRESS));
@@ -558,8 +933,8 @@ bool AddAutofillProfileEmails(const AutofillProfile& profile,
bool AddAutofillProfilePhones(const AutofillProfile& profile,
sql::Database* db) {
// Add the new number.
- sql::Statement s(db->GetUniqueStatement(
- "INSERT INTO autofill_profile_phones (guid, number) VALUES (?,?)"));
+ sql::Statement s;
+ InsertBuilder(db, s, kAutofillProfilePhonesTable, {kGuid, kNumber});
s.BindString(0, profile.guid());
s.BindString16(1, profile.GetRawInfo(PHONE_HOME_WHOLE_NUMBER));
@@ -568,77 +943,33 @@ bool AddAutofillProfilePhones(const AutofillProfile& profile,
bool AddAutofillProfileBirthdate(const AutofillProfile& profile,
sql::Database* db) {
- if (!base::FeatureList::IsEnabled(
- features::kAutofillEnableCompatibilitySupportForBirthdates)) {
- return true;
- }
-
// Add the new birthdate.
- sql::Statement s(
- db->GetUniqueStatement("INSERT INTO autofill_profile_birthdates (guid, "
- "day, month, year) VALUES (?,?,?,?)"));
+ sql::Statement s;
+ InsertBuilder(db, s, kAutofillProfileBirthdatesTable,
+ {kGuid, kDay, kMonth, kYear});
s.BindString(0, profile.guid());
s.BindInt(1, profile.GetRawInfoAsInt(BIRTHDATE_DAY));
s.BindInt(2, profile.GetRawInfoAsInt(BIRTHDATE_MONTH));
- s.BindInt(3, profile.GetRawInfoAsInt(BIRTHDATE_YEAR_4_DIGITS));
+ s.BindInt(3, profile.GetRawInfoAsInt(BIRTHDATE_4_DIGIT_YEAR));
return s.Run();
}
bool AddAutofillProfilePieces(const AutofillProfile& profile,
sql::Database* db) {
- if (!AddAutofillProfileNames(profile, db))
- return false;
-
- if (!AddAutofillProfileEmails(profile, db))
- return false;
-
- if (!AddAutofillProfilePhones(profile, db))
- return false;
-
- if (!AddAutofillProfileAddresses(profile, db))
- return false;
-
- if (!AddAutofillProfileBirthdate(profile, db))
- return false;
-
- return true;
+ return AddAutofillProfileNames(profile, db) &&
+ AddAutofillProfileEmails(profile, db) &&
+ AddAutofillProfilePhones(profile, db) &&
+ AddAutofillProfileAddresses(profile, db) &&
+ AddAutofillProfileBirthdate(profile, db);
}
bool RemoveAutofillProfilePieces(const std::string& guid, sql::Database* db) {
- sql::Statement s1(db->GetUniqueStatement(
- "DELETE FROM autofill_profile_names WHERE guid = ?"));
- s1.BindString(0, guid);
-
- if (!s1.Run())
- return false;
-
- sql::Statement s2(db->GetUniqueStatement(
- "DELETE FROM autofill_profile_emails WHERE guid = ?"));
- s2.BindString(0, guid);
-
- if (!s2.Run())
- return false;
-
- sql::Statement s3(db->GetUniqueStatement(
- "DELETE FROM autofill_profile_phones WHERE guid = ?"));
- s3.BindString(0, guid);
-
- if (!s3.Run())
- return false;
-
- sql::Statement s4(db->GetUniqueStatement(
- "DELETE FROM autofill_profile_addresses WHERE guid = ?"));
- s4.BindString(0, guid);
-
- if (!s4.Run())
- return false;
-
- sql::Statement s5(db->GetUniqueStatement(
- "DELETE FROM autofill_profile_birthdates WHERE guid = ?"));
- s5.BindString(0, guid);
-
- return s5.Run();
+ return DeleteWhereColumnEq(db, kAutofillProfileNamesTable, kGuid, guid) &&
+ DeleteWhereColumnEq(db, kAutofillProfileEmailsTable, kGuid, guid) &&
+ DeleteWhereColumnEq(db, kAutofillProfilePhonesTable, kGuid, guid) &&
+ DeleteWhereColumnEq(db, kAutofillProfileAddressesTable, kGuid, guid) &&
+ DeleteWhereColumnEq(db, kAutofillProfileBirthdatesTable, kGuid, guid);
}
WebDatabaseTable::TypeKey GetKey() {
@@ -699,16 +1030,17 @@ WebDatabaseTable::TypeKey AutofillTable::GetTypeKey() const {
}
bool AutofillTable::CreateTablesIfNecessary() {
- return (InitMainTable() && InitCreditCardsTable() && InitProfilesTable() &&
- InitProfileAddressesTable() && InitProfileNamesTable() &&
- InitProfileEmailsTable() && InitProfilePhonesTable() &&
- InitProfileBirthdatesTable() && InitMaskedCreditCardsTable() &&
- InitUnmaskedCreditCardsTable() && InitServerCardMetadataTable() &&
- InitServerAddressesTable() && InitServerAddressMetadataTable() &&
- InitAutofillSyncMetadataTable() && InitModelTypeStateTable() &&
- InitPaymentsCustomerDataTable() && InitPaymentsUPIVPATable() &&
- InitServerCreditCardCloudTokenDataTable() && InitOfferDataTable() &&
- InitOfferEligibleInstrumentTable() && InitOfferMerchantDomainTable());
+ return InitMainTable() && InitCreditCardsTable() && InitIBANsTable() &&
+ InitProfilesTable() && InitProfileAddressesTable() &&
+ InitProfileNamesTable() && InitProfileEmailsTable() &&
+ InitProfilePhonesTable() && InitProfileBirthdatesTable() &&
+ InitMaskedCreditCardsTable() && InitUnmaskedCreditCardsTable() &&
+ InitServerCardMetadataTable() && InitServerAddressesTable() &&
+ InitServerAddressMetadataTable() && InitAutofillSyncMetadataTable() &&
+ InitModelTypeStateTable() && InitPaymentsCustomerDataTable() &&
+ InitPaymentsUPIVPATable() &&
+ InitServerCreditCardCloudTokenDataTable() && InitOfferDataTable() &&
+ InitOfferEligibleInstrumentTable() && InitOfferMerchantDomainTable();
}
bool AutofillTable::IsSyncable() {
@@ -719,69 +1051,6 @@ bool AutofillTable::MigrateToVersion(int version,
bool* update_compatible_version) {
// Migrate if necessary.
switch (version) {
- case 54:
- *update_compatible_version = true;
- return MigrateToVersion54AddI18nFieldsAndRemoveDeprecatedFields();
- case 55:
- *update_compatible_version = true;
- return MigrateToVersion55MergeAutofillDatesTable();
- case 56:
- *update_compatible_version = true;
- return MigrateToVersion56AddProfileLanguageCodeForFormatting();
- case 57:
- *update_compatible_version = true;
- return MigrateToVersion57AddFullNameField();
- case 60:
- *update_compatible_version = false;
- return MigrateToVersion60AddServerCards();
- case 61:
- *update_compatible_version = false;
- return MigrateToVersion61AddUsageStats();
- case 62:
- *update_compatible_version = false;
- return MigrateToVersion62AddUsageStatsForUnmaskedCards();
- case 63:
- *update_compatible_version = false;
- return MigrateToVersion63AddServerRecipientName();
- case 64:
- *update_compatible_version = false;
- return MigrateToVersion64AddUnmaskDate();
- case 65:
- *update_compatible_version = false;
- return MigrateToVersion65AddServerMetadataTables();
- case 66:
- *update_compatible_version = false;
- return MigrateToVersion66AddCardBillingAddress();
- case 67:
- *update_compatible_version = false;
- return MigrateToVersion67AddMaskedCardBillingAddress();
- case 70:
- *update_compatible_version = false;
- return MigrateToVersion70AddSyncMetadata();
- case 71:
- *update_compatible_version = true;
- return MigrateToVersion71AddHasConvertedAndBillingAddressIdMetadata();
- case 72:
- *update_compatible_version = true;
- return MigrateToVersion72RenameCardTypeToIssuerNetwork();
- case 73:
- *update_compatible_version = false;
- return MigrateToVersion73AddMaskedCardBankName();
- case 74:
- *update_compatible_version = false;
- return MigrateToVersion74AddServerCardTypeColumn();
- case 75:
- *update_compatible_version = false;
- return MigrateToVersion75AddProfileValidityBitfieldColumn();
- case 78:
- *update_compatible_version = true;
- return MigrateToVersion78AddModelTypeColumns();
- case 80:
- *update_compatible_version = true;
- return MigrateToVersion80AddIsClientValidityStatesUpdatedColumn();
- case 81:
- *update_compatible_version = true;
- return MigrateToVersion81CleanUpWrongModelTypeData();
case 83:
*update_compatible_version = true;
return MigrateToVersion83RemoveServerCardTypeColumn();
@@ -844,6 +1113,9 @@ bool AutofillTable::MigrateToVersion(int version,
case 104:
*update_compatible_version = false;
return MigrateToVersion104AddProductDescriptionColumn();
+ case 105:
+ *update_compatible_version = false;
+ return MigrateToVersion105AddAutofillIBANTable();
}
return true;
}
@@ -869,10 +1141,9 @@ bool AutofillTable::GetFormValuesForElementName(
if (prefix.empty()) {
sql::Statement s;
- s.Assign(db_->GetUniqueStatement(
- "SELECT name, value, date_created, date_last_used FROM autofill "
- "WHERE name = ? "
- "ORDER BY count DESC LIMIT ?"));
+ SelectBuilder(db_, s, kAutofillTable,
+ {kName, kValue, kDateCreated, kDateLastUsed},
+ "WHERE name = ? ORDER BY count DESC LIMIT ?");
s.BindString16(0, name);
s.BindInt(1, limit);
@@ -892,13 +1163,13 @@ bool AutofillTable::GetFormValuesForElementName(
next_prefix.back()++;
sql::Statement s1;
- s1.Assign(db_->GetUniqueStatement(
- "SELECT name, value, date_created, date_last_used FROM autofill "
- "WHERE name = ? AND "
- "value_lower >= ? AND "
- "value_lower < ? "
- "ORDER BY count DESC "
- "LIMIT ?"));
+ SelectBuilder(db_, s1, kAutofillTable,
+ {kName, kValue, kDateCreated, kDateLastUsed},
+ "WHERE name = ? AND "
+ "value_lower >= ? AND "
+ "value_lower < ? "
+ "ORDER BY count DESC "
+ "LIMIT ?");
s1.BindString16(0, name);
s1.BindString16(1, prefix_lower);
s1.BindString16(2, next_prefix);
@@ -917,17 +1188,17 @@ bool AutofillTable::GetFormValuesForElementName(
if (IsFeatureSubstringMatchEnabled()) {
sql::Statement s2;
- s2.Assign(db_->GetUniqueStatement(
- "SELECT name, value, date_created, date_last_used FROM autofill "
- "WHERE name = ? AND ("
- " value LIKE '% ' || :prefix || '%' ESCAPE '!' OR "
- " value LIKE '%.' || :prefix || '%' ESCAPE '!' OR "
- " value LIKE '%,' || :prefix || '%' ESCAPE '!' OR "
- " value LIKE '%-' || :prefix || '%' ESCAPE '!' OR "
- " value LIKE '%@' || :prefix || '%' ESCAPE '!' OR "
- " value LIKE '%!_' || :prefix || '%' ESCAPE '!' ) "
- "ORDER BY count DESC "
- "LIMIT ?"));
+ SelectBuilder(db_, s2, kAutofillTable,
+ {kName, kValue, kDateCreated, kDateLastUsed},
+ "WHERE name = ? AND ("
+ " value LIKE '% ' || :prefix || '%' ESCAPE '!' OR "
+ " value LIKE '%.' || :prefix || '%' ESCAPE '!' OR "
+ " value LIKE '%,' || :prefix || '%' ESCAPE '!' OR "
+ " value LIKE '%-' || :prefix || '%' ESCAPE '!' OR "
+ " value LIKE '%@' || :prefix || '%' ESCAPE '!' OR "
+ " value LIKE '%!_' || :prefix || '%' ESCAPE '!' ) "
+ "ORDER BY count DESC "
+ "LIMIT ?");
s2.BindString16(0, name);
// escaper as L'!' -> 0x21.
@@ -957,10 +1228,11 @@ bool AutofillTable::RemoveFormElementsAddedBetween(
// Query for the name, value, count, and access dates of all form elements
// that were used between the given times.
- sql::Statement s(db_->GetUniqueStatement(
- "SELECT name, value, count, date_created, date_last_used FROM autofill "
- "WHERE (date_created >= ? AND date_created < ?) OR "
- " (date_last_used >= ? AND date_last_used < ?)"));
+ sql::Statement s;
+ SelectBuilder(db_, s, kAutofillTable,
+ {kName, kValue, kCount, kDateCreated, kDateLastUsed},
+ "WHERE (date_created >= ? AND date_created < ?) OR "
+ " (date_last_used >= ? AND date_last_used < ?)");
s.BindInt64(0, delete_begin_time_t);
s.BindInt64(1, delete_end_time_t);
s.BindInt64(2, delete_begin_time_t);
@@ -1024,8 +1296,9 @@ bool AutofillTable::RemoveFormElementsAddedBetween(
return false;
// As a single transaction, remove or update the elements appropriately.
- sql::Statement s_delete(db_->GetUniqueStatement(
- "DELETE FROM autofill WHERE date_created >= ? AND date_last_used < ?"));
+ sql::Statement s_delete;
+ DeleteBuilder(db_, s_delete, kAutofillTable,
+ "date_created >= ? AND date_last_used < ?");
s_delete.BindInt64(0, delete_begin_time_t);
s_delete.BindInt64(1, delete_end_time_t);
sql::Transaction transaction(db_);
@@ -1061,8 +1334,9 @@ bool AutofillTable::RemoveExpiredFormElements(
// Query for the name and value of all form elements that were last used
// before the |expiration_time|.
- sql::Statement select_for_delete(db_->GetUniqueStatement(
- "SELECT name, value FROM autofill WHERE date_last_used < ?"));
+ sql::Statement select_for_delete;
+ SelectBuilder(db_, select_for_delete, kAutofillTable, {kName, kValue},
+ "WHERE date_last_used < ?");
select_for_delete.BindInt64(0, expiration_time.ToTimeT());
std::vector<AutofillChange> tentative_changes;
while (select_for_delete.Step()) {
@@ -1074,8 +1348,9 @@ bool AutofillTable::RemoveExpiredFormElements(
if (!select_for_delete.Succeeded())
return false;
- sql::Statement delete_data_statement(
- db_->GetUniqueStatement("DELETE FROM autofill WHERE date_last_used < ?"));
+ sql::Statement delete_data_statement;
+ DeleteBuilder(db_, delete_data_statement, kAutofillTable,
+ "date_last_used < ?");
delete_data_statement.BindInt64(0, expiration_time.ToTimeT());
if (!delete_data_statement.Run())
return false;
@@ -1086,8 +1361,8 @@ bool AutofillTable::RemoveExpiredFormElements(
bool AutofillTable::RemoveFormElement(const std::u16string& name,
const std::u16string& value) {
- sql::Statement s(db_->GetUniqueStatement(
- "DELETE FROM autofill WHERE name = ? AND value= ?"));
+ sql::Statement s;
+ DeleteBuilder(db_, s, kAutofillTable, "name = ? AND value= ?");
s.BindString16(0, name);
s.BindString16(1, value);
return s.Run();
@@ -1116,8 +1391,9 @@ int AutofillTable::GetCountOfValuesContainedBetween(const base::Time& begin,
}
bool AutofillTable::GetAllAutofillEntries(std::vector<AutofillEntry>* entries) {
- sql::Statement s(db_->GetUniqueStatement(
- "SELECT name, value, date_created, date_last_used FROM autofill"));
+ sql::Statement s;
+ SelectBuilder(db_, s, kAutofillTable,
+ {kName, kValue, kDateCreated, kDateLastUsed});
while (s.Step()) {
std::u16string name = s.ColumnString16(0);
@@ -1135,9 +1411,9 @@ bool AutofillTable::GetAutofillTimestamps(const std::u16string& name,
const std::u16string& value,
base::Time* date_created,
base::Time* date_last_used) {
- sql::Statement s(db_->GetUniqueStatement(
- "SELECT date_created, date_last_used FROM autofill "
- "WHERE name = ? AND value = ?"));
+ sql::Statement s;
+ SelectBuilder(db_, s, kAutofillTable, {kDateCreated, kDateLastUsed},
+ "WHERE name = ? AND value = ?");
s.BindString16(0, name);
s.BindString16(1, value);
if (!s.Step())
@@ -1157,8 +1433,8 @@ bool AutofillTable::UpdateAutofillEntries(
// Remove all existing entries.
for (const auto& entry : entries) {
- sql::Statement s(db_->GetUniqueStatement(
- "DELETE FROM autofill WHERE name = ? AND value = ?"));
+ sql::Statement s;
+ DeleteBuilder(db_, s, kAutofillTable, "name = ? AND value = ?");
s.BindString16(0, entry.key().name());
s.BindString16(1, entry.key().value());
if (!s.Run())
@@ -1175,13 +1451,12 @@ bool AutofillTable::UpdateAutofillEntries(
}
bool AutofillTable::AddAutofillProfile(const AutofillProfile& profile) {
- sql::Statement s(db_->GetUniqueStatement(
- "INSERT INTO autofill_profiles"
- "(guid, company_name, street_address, dependent_locality, city, state,"
- " zipcode, sorting_code, country_code, use_count, use_date, "
- " date_modified, origin, language_code, "
- " label, disallow_settings_visible_updates) "
- "VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)"));
+ sql::Statement s;
+ InsertBuilder(
+ db_, s, kAutofillProfilesTable,
+ {kGuid, kCompanyName, kStreetAddress, kDependentLocality, kCity, kState,
+ kZipcode, kSortingCode, kCountryCode, kUseCount, kUseDate, kDateModified,
+ kOrigin, kLanguageCode, kLabel, kDisallowSettingsVisibleUpdates});
BindAutofillProfileToStatement(profile, AutofillClock::Now(), &s);
if (!s.Run())
@@ -1228,26 +1503,20 @@ bool AutofillTable::UpdateAutofillProfile(const AutofillProfile& profile) {
bool AutofillTable::RemoveAutofillProfile(const std::string& guid) {
DCHECK(base::IsValidGUID(guid));
- sql::Statement s(
- db_->GetUniqueStatement("DELETE FROM autofill_profiles WHERE guid = ?"));
- s.BindString(0, guid);
-
- if (!s.Run())
- return false;
-
- return RemoveAutofillProfilePieces(guid, db_);
+ return DeleteWhereColumnEq(db_, kAutofillProfilesTable, kGuid, guid) &&
+ RemoveAutofillProfilePieces(guid, db_);
}
std::unique_ptr<AutofillProfile> AutofillTable::GetAutofillProfile(
const std::string& guid) {
DCHECK(base::IsValidGUID(guid));
- sql::Statement s(db_->GetUniqueStatement(
- "SELECT guid, company_name, street_address, dependent_locality, city,"
- " state, zipcode, sorting_code, country_code, use_count, use_date,"
- " date_modified, origin, language_code, label,"
- " disallow_settings_visible_updates "
- "FROM autofill_profiles "
- "WHERE guid=?"));
+ sql::Statement s;
+ SelectBuilder(
+ db_, s, kAutofillProfilesTable,
+ {kGuid, kCompanyName, kStreetAddress, kDependentLocality, kCity, kState,
+ kZipcode, kSortingCode, kCountryCode, kUseCount, kUseDate, kDateModified,
+ kOrigin, kLanguageCode, kLabel, kDisallowSettingsVisibleUpdates},
+ "WHERE guid=?");
s.BindString(0, guid);
if (!s.Step())
@@ -1290,8 +1559,9 @@ bool AutofillTable::GetAutofillProfiles(
DCHECK(profiles);
profiles->clear();
- sql::Statement s(db_->GetUniqueStatement(
- "SELECT guid FROM autofill_profiles ORDER BY date_modified DESC, guid"));
+ sql::Statement s;
+ SelectBuilder(db_, s, kAutofillProfilesTable, {kGuid},
+ "ORDER BY date_modified DESC, guid");
while (s.Step()) {
std::string guid = s.ColumnString(0);
@@ -1308,26 +1578,20 @@ bool AutofillTable::GetServerProfiles(
std::vector<std::unique_ptr<AutofillProfile>>* profiles) const {
profiles->clear();
- sql::Statement s(db_->GetUniqueStatement(
- "SELECT "
- "id,"
- "use_count,"
- "use_date,"
- "recipient_name,"
- "company_name,"
- "street_address,"
- "address_1," // ADDRESS_HOME_STATE
- "address_2," // ADDRESS_HOME_CITY
- "address_3," // ADDRESS_HOME_DEPENDENT_LOCALITY
- "address_4," // Not supported in AutofillProfile yet.
- "postal_code," // ADDRESS_HOME_ZIP
- "sorting_code," // ADDRESS_HOME_SORTING_CODE
- "country_code," // ADDRESS_HOME_COUNTRY
- "phone_number," // PHONE_HOME_WHOLE_NUMBER
- "language_code, "
- "has_converted "
- "FROM server_addresses addresses "
- "LEFT OUTER JOIN server_address_metadata USING (id)"));
+ sql::Statement s;
+ SelectBuilder(
+ db_, s, kServerAddressesTable,
+ {kId, kUseCount, kUseDate, kRecipientName, kCompanyName, kStreetAddress,
+ kAddress1, // ADDRESS_HOME_STATE
+ kAddress2, // ADDRESS_HOME_CITY
+ kAddress3, // ADDRESS_HOME_DEPENDENT_LOCALITY
+ kAddress4, // Not supported in AutofillProfile yet.
+ kPostalCode, // ADDRESS_HOME_ZIP
+ kSortingCode, // ADDRESS_HOME_SORTING_CODE
+ kCountryCode, // ADDRESS_HOME_COUNTRY
+ kPhoneNumber, // PHONE_HOME_WHOLE_NUMBER
+ kLanguageCode, kHasConverted},
+ "LEFT OUTER JOIN server_address_metadata USING (id)");
while (s.Step()) {
int index = 0;
@@ -1342,16 +1606,16 @@ bool AutofillTable::GetServerProfiles(
profile->set_modification_date(base::Time());
std::u16string recipient_name = s.ColumnString16(index++);
- profile->SetRawInfo(COMPANY_NAME, s.ColumnString16(index++));
- profile->SetRawInfo(ADDRESS_HOME_STREET_ADDRESS, s.ColumnString16(index++));
- profile->SetRawInfo(ADDRESS_HOME_STATE, s.ColumnString16(index++));
- profile->SetRawInfo(ADDRESS_HOME_CITY, s.ColumnString16(index++));
- profile->SetRawInfo(ADDRESS_HOME_DEPENDENT_LOCALITY,
- s.ColumnString16(index++));
+ for (ServerFieldType type :
+ {COMPANY_NAME, ADDRESS_HOME_STREET_ADDRESS, ADDRESS_HOME_STATE,
+ ADDRESS_HOME_CITY, ADDRESS_HOME_DEPENDENT_LOCALITY}) {
+ profile->SetRawInfo(type, s.ColumnString16(index++));
+ }
index++; // Skip address_4 which we haven't added to AutofillProfile yet.
- profile->SetRawInfo(ADDRESS_HOME_ZIP, s.ColumnString16(index++));
- profile->SetRawInfo(ADDRESS_HOME_SORTING_CODE, s.ColumnString16(index++));
- profile->SetRawInfo(ADDRESS_HOME_COUNTRY, s.ColumnString16(index++));
+ for (ServerFieldType type :
+ {ADDRESS_HOME_ZIP, ADDRESS_HOME_SORTING_CODE, ADDRESS_HOME_COUNTRY}) {
+ profile->SetRawInfo(type, s.ColumnString16(index++));
+ }
std::u16string phone_number = s.ColumnString16(index++);
profile->set_language_code(s.ColumnString(index++));
profile->set_has_converted(s.ColumnBool(index++));
@@ -1372,76 +1636,148 @@ bool AutofillTable::GetServerProfiles(
return s.Succeeded();
}
-void AutofillTable::SetServerProfiles(
- const std::vector<AutofillProfile>& profiles) {
+void AutofillTable::SetServerProfilesAndMetadata(
+ const std::vector<AutofillProfile>& profiles,
+ bool update_metadata) {
sql::Transaction transaction(db_);
if (!transaction.Begin())
return;
// Delete all old ones first.
- sql::Statement delete_old(
- db_->GetUniqueStatement("DELETE FROM server_addresses"));
- delete_old.Run();
-
- sql::Statement insert(db_->GetUniqueStatement(
- "INSERT INTO server_addresses("
- "id,"
- "recipient_name,"
- "company_name,"
- "street_address,"
- "address_1," // ADDRESS_HOME_STATE
- "address_2," // ADDRESS_HOME_CITY
- "address_3," // ADDRESS_HOME_DEPENDENT_LOCALITY
- "address_4," // Not supported in AutofillProfile yet.
- "postal_code," // ADDRESS_HOME_ZIP
- "sorting_code," // ADDRESS_HOME_SORTING_CODE
- "country_code," // ADDRESS_HOME_COUNTRY
- "phone_number," // PHONE_HOME_WHOLE_NUMBER
- "language_code) "
- "VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?)"));
+ Delete(db_, kServerAddressesTable);
+
+ sql::Statement insert;
+ InsertBuilder(db_, insert, kServerAddressesTable,
+ {kId, kRecipientName, kCompanyName, kStreetAddress,
+ kAddress1, // ADDRESS_HOME_STATE
+ kAddress2, // ADDRESS_HOME_CITY
+ kAddress3, // ADDRESS_HOME_DEPENDENT_LOCALITY
+ kAddress4, // Not supported in AutofillProfile yet.
+ kPostalCode, // ADDRESS_HOME_ZIP
+ kSortingCode, // ADDRESS_HOME_SORTING_CODE
+ kCountryCode, // ADDRESS_HOME_COUNTRY
+ kPhoneNumber, // PHONE_HOME_WHOLE_NUMBER
+ kLanguageCode});
for (const auto& profile : profiles) {
DCHECK(profile.record_type() == AutofillProfile::SERVER_PROFILE);
int index = 0;
insert.BindString(index++, profile.server_id());
- insert.BindString16(index++, profile.GetRawInfo(NAME_FULL));
- insert.BindString16(index++, profile.GetRawInfo(COMPANY_NAME));
- insert.BindString16(index++,
- profile.GetRawInfo(ADDRESS_HOME_STREET_ADDRESS));
- insert.BindString16(index++, profile.GetRawInfo(ADDRESS_HOME_STATE));
- insert.BindString16(index++, profile.GetRawInfo(ADDRESS_HOME_CITY));
- insert.BindString16(index++,
- profile.GetRawInfo(ADDRESS_HOME_DEPENDENT_LOCALITY));
- index++; // SKip address_4 which we haven't added to AutofillProfile yet.
- insert.BindString16(index++, profile.GetRawInfo(ADDRESS_HOME_ZIP));
- insert.BindString16(index++, profile.GetRawInfo(ADDRESS_HOME_SORTING_CODE));
- insert.BindString16(index++, profile.GetRawInfo(ADDRESS_HOME_COUNTRY));
- insert.BindString16(index++, profile.GetRawInfo(PHONE_HOME_WHOLE_NUMBER));
+ for (ServerFieldType type :
+ {NAME_FULL, COMPANY_NAME, ADDRESS_HOME_STREET_ADDRESS,
+ ADDRESS_HOME_STATE, ADDRESS_HOME_CITY,
+ ADDRESS_HOME_DEPENDENT_LOCALITY}) {
+ insert.BindString16(index++, profile.GetRawInfo(type));
+ }
+ index++; // Skip address_4 which we haven't added to AutofillProfile yet.
+ for (ServerFieldType type :
+ {ADDRESS_HOME_ZIP, ADDRESS_HOME_SORTING_CODE, ADDRESS_HOME_COUNTRY,
+ PHONE_HOME_WHOLE_NUMBER}) {
+ insert.BindString16(index++, profile.GetRawInfo(type));
+ }
insert.BindString(index++, profile.language_code());
insert.Run();
insert.Reset(true);
- // Save the use count and use date of the profile.
- UpdateServerAddressMetadata(profile);
+ if (update_metadata) {
+ // Save the use count and use date of the profile.
+ UpdateServerAddressMetadata(profile);
+ }
}
- // Delete metadata that's no longer relevant.
- sql::Statement metadata_delete(db_->GetUniqueStatement(
- "DELETE FROM server_address_metadata WHERE id NOT IN "
- "(SELECT id FROM server_addresses)"));
- metadata_delete.Run();
+ if (update_metadata) {
+ // Delete metadata that's no longer relevant.
+ Delete(db_, kServerAddressMetadataTable,
+ "id NOT IN (SELECT id FROM server_addresses)");
+ }
transaction.Commit();
}
-bool AutofillTable::AddCreditCard(const CreditCard& credit_card) {
+void AutofillTable::SetServerProfiles(
+ const std::vector<AutofillProfile>& profiles) {
+ SetServerProfilesAndMetadata(profiles, /*update_metadata=*/true);
+}
+
+bool AutofillTable::AddIBAN(const IBAN& iban) {
+ sql::Statement s;
+ InsertBuilder(db_, s, kIBANsTable,
+ {kGuid, kUseCount, kUseDate, kValue, kNickname});
+ BindIBANToStatement(iban, &s, *autofill_table_encryptor_);
+ if (!s.Run())
+ return false;
+
+ DCHECK_GT(db_->GetLastChangeCount(), 0);
+ return true;
+}
+
+bool AutofillTable::UpdateIBAN(const IBAN& iban) {
+ DCHECK(base::IsValidGUID(iban.guid()));
+
+ std::unique_ptr<IBAN> old_iban = GetIBAN(iban.guid());
+ if (!old_iban) {
+ return false;
+ }
+
+ if (*old_iban == iban) {
+ return true;
+ }
+
sql::Statement s(db_->GetUniqueStatement(
- "INSERT INTO credit_cards"
- "(guid, name_on_card, expiration_month, expiration_year, "
- " card_number_encrypted, use_count, use_date, date_modified, origin,"
- " billing_address_id, nickname)"
- "VALUES (?,?,?,?,?,?,?,?,?,?,?)"));
+ "UPDATE ibans "
+ "SET guid=?, use_count=?, use_date=?, value=?, nickname=? "
+ "WHERE guid=?1"));
+ BindIBANToStatement(iban, &s, *autofill_table_encryptor_);
+
+ bool result = s.Run();
+ DCHECK_GT(db_->GetLastChangeCount(), 0);
+ return result;
+}
+
+bool AutofillTable::RemoveIBAN(const std::string& guid) {
+ DCHECK(base::IsValidGUID(guid));
+ return DeleteWhereColumnEq(db_, kIBANsTable, kGuid, guid);
+}
+
+std::unique_ptr<IBAN> AutofillTable::GetIBAN(const std::string& guid) {
+ DCHECK(base::IsValidGUID(guid));
+ sql::Statement s;
+ SelectBuilder(db_, s, kIBANsTable,
+ {kGuid, kUseCount, kUseDate, kValue, kNickname},
+ "WHERE guid = ?");
+ s.BindString(0, guid);
+
+ if (!s.Step())
+ return nullptr;
+
+ return IBANFromStatement(s, *autofill_table_encryptor_);
+}
+
+bool AutofillTable::GetIBANs(std::vector<std::unique_ptr<IBAN>>* ibans) {
+ DCHECK(ibans);
+ ibans->clear();
+
+ sql::Statement s;
+ SelectBuilder(db_, s, kIBANsTable, {kGuid}, "ORDER BY use_date DESC, guid");
+
+ while (s.Step()) {
+ std::string guid = s.ColumnString(0);
+ std::unique_ptr<IBAN> iban = GetIBAN(guid);
+ if (!iban)
+ return false;
+ ibans->push_back(std::move(iban));
+ }
+
+ return s.Succeeded();
+}
+
+bool AutofillTable::AddCreditCard(const CreditCard& credit_card) {
+ sql::Statement s;
+ InsertBuilder(db_, s, kCreditCardsTable,
+ {kGuid, kNameOnCard, kExpirationMonth, kExpirationYear,
+ kCardNumberEncrypted, kUseCount, kUseDate, kDateModified,
+ kOrigin, kBillingAddressId, kNickname});
BindCreditCardToStatement(credit_card, AutofillClock::Now(), &s,
*autofill_table_encryptor_);
@@ -1481,11 +1817,7 @@ bool AutofillTable::UpdateCreditCard(const CreditCard& credit_card) {
bool AutofillTable::RemoveCreditCard(const std::string& guid) {
DCHECK(base::IsValidGUID(guid));
- sql::Statement s(
- db_->GetUniqueStatement("DELETE FROM credit_cards WHERE guid = ?"));
- s.BindString(0, guid);
-
- return s.Run();
+ return DeleteWhereColumnEq(db_, kCreditCardsTable, kGuid, guid);
}
bool AutofillTable::AddFullServerCreditCard(const CreditCard& credit_card) {
@@ -1518,12 +1850,12 @@ bool AutofillTable::AddFullServerCreditCard(const CreditCard& credit_card) {
std::unique_ptr<CreditCard> AutofillTable::GetCreditCard(
const std::string& guid) {
DCHECK(base::IsValidGUID(guid));
- sql::Statement s(db_->GetUniqueStatement(
- "SELECT guid, name_on_card, expiration_month, expiration_year, "
- "card_number_encrypted, use_count, use_date, date_modified, "
- "origin, billing_address_id, nickname "
- "FROM credit_cards "
- "WHERE guid = ?"));
+ sql::Statement s;
+ SelectBuilder(db_, s, kCreditCardsTable,
+ {kGuid, kNameOnCard, kExpirationMonth, kExpirationYear,
+ kCardNumberEncrypted, kUseCount, kUseDate, kDateModified,
+ kOrigin, kBillingAddressId, kNickname},
+ "WHERE guid = ?");
s.BindString(0, guid);
if (!s.Step())
@@ -1537,8 +1869,9 @@ bool AutofillTable::GetCreditCards(
DCHECK(credit_cards);
credit_cards->clear();
- sql::Statement s(db_->GetUniqueStatement(
- "SELECT guid FROM credit_cards ORDER BY date_modified DESC, guid"));
+ sql::Statement s;
+ SelectBuilder(db_, s, kCreditCardsTable, {kGuid},
+ "ORDER BY date_modified DESC, guid");
while (s.Step()) {
std::string guid = s.ColumnString(0);
@@ -1555,28 +1888,17 @@ bool AutofillTable::GetServerCreditCards(
std::vector<std::unique_ptr<CreditCard>>* credit_cards) const {
credit_cards->clear();
- sql::Statement s(db_->GetUniqueStatement(
- "SELECT "
- "card_number_encrypted, " // 0
- "last_four," // 1
- "masked.id," // 2
- "metadata.use_count," // 3
- "metadata.use_date," // 4
- "network," // 5
- "name_on_card," // 6
- "exp_month," // 7
- "exp_year," // 8
- "metadata.billing_address_id," // 9
- "bank_name," // 10
- "nickname," // 11
- "card_issuer," // 12
- "instrument_id, " // 13
- "virtual_card_enrollment_state, " // 14
- "card_art_url, " // 15
- "product_description " // 16
- "FROM masked_credit_cards masked "
+ sql::Statement s;
+ SelectBuilder(
+ db_, s, base::StrCat({kMaskedCreditCardsTable, " AS masked"}),
+ {kCardNumberEncrypted, kLastFour, base::StrCat({"masked.", kId}),
+ base::StrCat({"metadata.", kUseCount}),
+ base::StrCat({"metadata.", kUseDate}), kNetwork, kNameOnCard, kExpMonth,
+ kExpYear, base::StrCat({"metadata.", kBillingAddressId}), kBankName,
+ kNickname, kCardIssuer, kInstrumentId, kVirtualCardEnrollmentState,
+ kCardArtUrl, kProductDescription},
"LEFT OUTER JOIN unmasked_credit_cards USING (id) "
- "LEFT OUTER JOIN server_card_metadata metadata USING (id)"));
+ "LEFT OUTER JOIN server_card_metadata AS metadata USING (id)");
while (s.Step()) {
int index = 0;
@@ -1636,22 +1958,16 @@ void AutofillTable::SetServerCreditCards(
return;
// Delete all old values.
- sql::Statement masked_delete(
- db_->GetUniqueStatement("DELETE FROM masked_credit_cards"));
- masked_delete.Run();
+ Delete(db_, kMaskedCreditCardsTable);
AddMaskedCreditCards(credit_cards);
// Delete all items in the unmasked table that aren't in the new set.
- sql::Statement unmasked_delete(db_->GetUniqueStatement(
- "DELETE FROM unmasked_credit_cards WHERE id NOT IN "
- "(SELECT id FROM masked_credit_cards)"));
- unmasked_delete.Run();
+ Delete(db_, kUnmaskedCreditCardsTable,
+ "id NOT IN (SELECT id FROM masked_credit_cards)");
// Do the same for metadata.
- sql::Statement metadata_delete(db_->GetUniqueStatement(
- "DELETE FROM server_card_metadata WHERE id NOT IN "
- "(SELECT id FROM masked_credit_cards)"));
- metadata_delete.Run();
+ Delete(db_, kServerCardMetadataTable,
+ "id NOT IN (SELECT id FROM masked_credit_cards)");
transaction.Commit();
}
@@ -1684,10 +2000,9 @@ bool AutofillTable::MaskServerCreditCard(const std::string& id) {
bool AutofillTable::AddServerCardMetadata(
const AutofillMetadata& card_metadata) {
- sql::Statement s(
- db_->GetUniqueStatement("INSERT INTO server_card_metadata(use_count, "
- "use_date, billing_address_id, id)"
- "VALUES (?,?,?,?)"));
+ sql::Statement s;
+ InsertBuilder(db_, s, kServerCardMetadataTable,
+ {kUseCount, kUseDate, kBillingAddressId, kId});
s.BindInt64(0, card_metadata.use_count);
s.BindInt64(1, card_metadata.use_date.ToInternalValue());
s.BindString(2, card_metadata.billing_address_id);
@@ -1700,15 +2015,12 @@ bool AutofillTable::AddServerCardMetadata(
bool AutofillTable::UpdateServerCardMetadata(const CreditCard& credit_card) {
DCHECK_NE(CreditCard::LOCAL_CARD, credit_card.record_type());
- sql::Statement remove(
- db_->GetUniqueStatement("DELETE FROM server_card_metadata WHERE id = ?"));
- remove.BindString(0, credit_card.server_id());
- remove.Run();
+ DeleteWhereColumnEq(db_, kServerCardMetadataTable, kId,
+ credit_card.server_id());
- sql::Statement s(
- db_->GetUniqueStatement("INSERT INTO server_card_metadata(use_count, "
- "use_date, billing_address_id, id)"
- "VALUES (?,?,?,?)"));
+ sql::Statement s;
+ InsertBuilder(db_, s, kServerCardMetadataTable,
+ {kUseCount, kUseDate, kBillingAddressId, kId});
s.BindInt64(0, credit_card.use_count());
s.BindInt64(1, credit_card.use_date().ToInternalValue());
s.BindString(2, credit_card.billing_address_id());
@@ -1723,10 +2035,9 @@ bool AutofillTable::UpdateServerCardMetadata(
// Do not check if there was a record that got deleted. Inserting a new one is
// also fine.
RemoveServerCardMetadata(card_metadata.id);
- sql::Statement s(
- db_->GetUniqueStatement("INSERT INTO server_card_metadata(use_count, "
- "use_date, billing_address_id, id)"
- "VALUES (?,?,?,?)"));
+ sql::Statement s;
+ InsertBuilder(db_, s, kServerCardMetadataTable,
+ {kUseCount, kUseDate, kBillingAddressId, kId});
s.BindInt64(0, card_metadata.use_count);
s.BindInt64(1, card_metadata.use_date.ToInternalValue());
s.BindString(2, card_metadata.billing_address_id);
@@ -1737,11 +2048,7 @@ bool AutofillTable::UpdateServerCardMetadata(
}
bool AutofillTable::RemoveServerCardMetadata(const std::string& id) {
- sql::Statement remove(
- db_->GetUniqueStatement("DELETE FROM server_card_metadata WHERE id = ?"));
- remove.BindString(0, id);
- remove.Run();
-
+ DeleteWhereColumnEq(db_, kServerCardMetadataTable, kId, id);
return db_->GetLastChangeCount() > 0;
}
@@ -1749,9 +2056,9 @@ bool AutofillTable::GetServerCardsMetadata(
std::map<std::string, AutofillMetadata>* cards_metadata) const {
cards_metadata->clear();
- sql::Statement s(
- db_->GetUniqueStatement("SELECT id, use_count, use_date, "
- "billing_address_id FROM server_card_metadata"));
+ sql::Statement s;
+ SelectBuilder(db_, s, kServerCardMetadataTable,
+ {kId, kUseCount, kUseDate, kBillingAddressId});
while (s.Step()) {
int index = 0;
@@ -1769,10 +2076,9 @@ bool AutofillTable::GetServerCardsMetadata(
bool AutofillTable::AddServerAddressMetadata(
const AutofillMetadata& address_metadata) {
- sql::Statement s(
- db_->GetUniqueStatement("INSERT INTO server_address_metadata(use_count, "
- "use_date, has_converted, id)"
- "VALUES (?,?,?,?)"));
+ sql::Statement s;
+ InsertBuilder(db_, s, kServerAddressMetadataTable,
+ {kUseCount, kUseDate, kHasConverted, kId});
s.BindInt64(0, address_metadata.use_count);
s.BindInt64(1, address_metadata.use_date.ToInternalValue());
s.BindBool(2, address_metadata.has_converted);
@@ -1792,15 +2098,13 @@ bool AutofillTable::UpdateServerAddressMetadata(
if (!transaction.Begin())
return false;
- sql::Statement remove(db_->GetUniqueStatement(
- "DELETE FROM server_address_metadata WHERE id = ?"));
- remove.BindString(0, profile.server_id());
- remove.Run();
+ DeleteWhereColumnEq(db_, kServerAddressMetadataTable, kId,
+ profile.server_id());
+
+ sql::Statement s;
+ InsertBuilder(db_, s, kServerAddressMetadataTable,
+ {kUseCount, kUseDate, kHasConverted, kId});
- sql::Statement s(
- db_->GetUniqueStatement("INSERT INTO server_address_metadata(use_count, "
- "use_date, has_converted, id)"
- "VALUES (?,?,?,?)"));
s.BindInt64(0, profile.use_count());
s.BindInt64(1, profile.use_date().ToInternalValue());
s.BindBool(2, profile.has_converted());
@@ -1817,10 +2121,9 @@ bool AutofillTable::UpdateServerAddressMetadata(
// Do not check if there was a record that got deleted. Inserting a new one is
// also fine.
RemoveServerAddressMetadata(address_metadata.id);
- sql::Statement s(
- db_->GetUniqueStatement("INSERT INTO server_address_metadata(use_count, "
- "use_date, has_converted, id)"
- "VALUES (?,?,?,?)"));
+ sql::Statement s;
+ InsertBuilder(db_, s, kServerAddressMetadataTable,
+ {kUseCount, kUseDate, kHasConverted, kId});
s.BindInt64(0, address_metadata.use_count);
s.BindInt64(1, address_metadata.use_date.ToInternalValue());
s.BindBool(2, address_metadata.has_converted);
@@ -1831,11 +2134,7 @@ bool AutofillTable::UpdateServerAddressMetadata(
}
bool AutofillTable::RemoveServerAddressMetadata(const std::string& id) {
- sql::Statement remove(db_->GetUniqueStatement(
- "DELETE FROM server_address_metadata WHERE id = ?"));
- remove.BindString(0, id);
- remove.Run();
-
+ DeleteWhereColumnEq(db_, kServerAddressMetadataTable, kId, id);
return db_->GetLastChangeCount() > 0;
}
@@ -1843,9 +2142,9 @@ bool AutofillTable::GetServerAddressesMetadata(
std::map<std::string, AutofillMetadata>* addresses_metadata) const {
addresses_metadata->clear();
- sql::Statement s(
- db_->GetUniqueStatement("SELECT id, use_count, use_date, has_converted "
- "FROM server_address_metadata"));
+ sql::Statement s;
+ SelectBuilder(db_, s, kServerAddressMetadataTable,
+ {kId, kUseCount, kUseDate, kHasConverted});
while (s.Step()) {
int index = 0;
@@ -1867,27 +2166,16 @@ void AutofillTable::SetServerCardsData(
return;
// Delete all old values.
- sql::Statement masked_delete(
- db_->GetUniqueStatement("DELETE FROM masked_credit_cards"));
- masked_delete.Run();
+ Delete(db_, kMaskedCreditCardsTable);
// Add all the masked cards.
- sql::Statement masked_insert(
- db_->GetUniqueStatement("INSERT INTO masked_credit_cards("
- "id," // 0
- "network," // 1
- "name_on_card," // 2
- "last_four," // 3
- "exp_month," // 4
- "exp_year," // 5
- "bank_name," // 6
- "nickname," // 7
- "card_issuer," // 8
- "instrument_id," // 9
- "virtual_card_enrollment_state," // 10
- "card_art_url," // 11
- "product_description) " // 12
- "VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?)"));
+ sql::Statement masked_insert;
+ InsertBuilder(
+ db_, masked_insert, kMaskedCreditCardsTable,
+ {kId, kNetwork, kNameOnCard, kLastFour, kExpMonth, kExpYear, kBankName,
+ kNickname, kCardIssuer, kInstrumentId, kVirtualCardEnrollmentState,
+ kCardArtUrl, kProductDescription});
+
int index;
for (const CreditCard& card : credit_cards) {
DCHECK_EQ(CreditCard::MASKED_SERVER_CARD, card.record_type());
@@ -1912,67 +2200,15 @@ void AutofillTable::SetServerCardsData(
}
// Delete all items in the unmasked table that aren't in the new set.
- sql::Statement unmasked_delete(db_->GetUniqueStatement(
- "DELETE FROM unmasked_credit_cards WHERE id NOT IN "
- "(SELECT id FROM masked_credit_cards)"));
- unmasked_delete.Run();
+ Delete(db_, kUnmaskedCreditCardsTable,
+ "id NOT IN (SELECT id FROM masked_credit_cards)");
transaction.Commit();
}
void AutofillTable::SetServerAddressesData(
const std::vector<AutofillProfile>& profiles) {
- sql::Transaction transaction(db_);
- if (!transaction.Begin())
- return;
-
- // Delete existing server addresses.
- sql::Statement delete_old(
- db_->GetUniqueStatement("DELETE FROM server_addresses"));
- delete_old.Run();
-
- // Add the new server addresses.
- sql::Statement insert(db_->GetUniqueStatement(
- "INSERT INTO server_addresses("
- "id,"
- "recipient_name,"
- "company_name,"
- "street_address,"
- "address_1," // ADDRESS_HOME_STATE
- "address_2," // ADDRESS_HOME_CITY
- "address_3," // ADDRESS_HOME_DEPENDENT_LOCALITY
- "address_4," // Not supported in AutofillProfile yet.
- "postal_code," // ADDRESS_HOME_ZIP
- "sorting_code," // ADDRESS_HOME_SORTING_CODE
- "country_code," // ADDRESS_HOME_COUNTRY
- "phone_number," // PHONE_HOME_WHOLE_NUMBER
- "language_code) "
- "VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?)"));
- for (const auto& profile : profiles) {
- DCHECK(profile.record_type() == AutofillProfile::SERVER_PROFILE);
-
- int index = 0;
- insert.BindString(index++, profile.server_id());
- insert.BindString16(index++, profile.GetRawInfo(NAME_FULL));
- insert.BindString16(index++, profile.GetRawInfo(COMPANY_NAME));
- insert.BindString16(index++,
- profile.GetRawInfo(ADDRESS_HOME_STREET_ADDRESS));
- insert.BindString16(index++, profile.GetRawInfo(ADDRESS_HOME_STATE));
- insert.BindString16(index++, profile.GetRawInfo(ADDRESS_HOME_CITY));
- insert.BindString16(index++,
- profile.GetRawInfo(ADDRESS_HOME_DEPENDENT_LOCALITY));
- index++; // SKip address_4 which we haven't added to AutofillProfile yet.
- insert.BindString16(index++, profile.GetRawInfo(ADDRESS_HOME_ZIP));
- insert.BindString16(index++, profile.GetRawInfo(ADDRESS_HOME_SORTING_CODE));
- insert.BindString16(index++, profile.GetRawInfo(ADDRESS_HOME_COUNTRY));
- insert.BindString16(index++, profile.GetRawInfo(PHONE_HOME_WHOLE_NUMBER));
- insert.BindString(index++, profile.language_code());
-
- insert.Run();
- insert.Reset(true);
- }
-
- transaction.Commit();
+ SetServerProfilesAndMetadata(profiles, /*update_metadata=*/false);
}
void AutofillTable::SetCreditCardCloudTokenData(
@@ -1982,20 +2218,13 @@ void AutofillTable::SetCreditCardCloudTokenData(
return;
// Deletes all old values.
- sql::Statement delete_cloud_token(
- db_->GetUniqueStatement("DELETE FROM server_card_cloud_token_data"));
- delete_cloud_token.Run();
+ Delete(db_, kServerCardCloudTokenDataTable);
// Inserts new values.
- sql::Statement insert_cloud_token(
- db_->GetUniqueStatement("INSERT INTO server_card_cloud_token_data("
- "id," // 0
- "suffix," // 1
- "exp_month," // 2
- "exp_year," // 3
- "card_art_url," // 4
- "instrument_token) " // 5
- "VALUES (?,?,?,?,?,?)"));
+ sql::Statement insert_cloud_token;
+ InsertBuilder(
+ db_, insert_cloud_token, kServerCardCloudTokenDataTable,
+ {kId, kSuffix, kExpMonth, kExpYear, kCardArtUrl, kInstrumentToken});
for (const CreditCardCloudTokenData& data : credit_card_cloud_token_data) {
insert_cloud_token.BindString(0, data.masked_card_id);
@@ -2015,15 +2244,10 @@ bool AutofillTable::GetCreditCardCloudTokenData(
credit_card_cloud_token_data) {
credit_card_cloud_token_data->clear();
- sql::Statement s(
- db_->GetUniqueStatement("SELECT "
- "id, " // 0
- "suffix, " // 1
- "exp_month, " // 2
- "exp_year, " // 3
- "card_art_url, " // 4
- "instrument_token " // 5
- "FROM server_card_cloud_token_data"));
+ sql::Statement s;
+ SelectBuilder(
+ db_, s, kServerCardCloudTokenDataTable,
+ {kId, kSuffix, kExpMonth, kExpYear, kCardArtUrl, kInstrumentToken});
while (s.Step()) {
int index = 0;
@@ -2048,13 +2272,12 @@ void AutofillTable::SetPaymentsCustomerData(
return;
// Delete all old values.
- sql::Statement customer_data_delete(
- db_->GetUniqueStatement("DELETE FROM payments_customer_data"));
- customer_data_delete.Run();
+ Delete(db_, kPaymentsCustomerDataTable);
if (customer_data) {
- sql::Statement insert_customer_data(db_->GetUniqueStatement(
- "INSERT INTO payments_customer_data (customer_id) VALUES (?)"));
+ sql::Statement insert_customer_data;
+ InsertBuilder(db_, insert_customer_data, kPaymentsCustomerDataTable,
+ {kCustomerId});
insert_customer_data.BindString(0, customer_data->customer_id);
insert_customer_data.Run();
}
@@ -2064,8 +2287,8 @@ void AutofillTable::SetPaymentsCustomerData(
bool AutofillTable::GetPaymentsCustomerData(
std::unique_ptr<PaymentsCustomerData>* customer_data) const {
- sql::Statement s(db_->GetUniqueStatement(
- "SELECT customer_id FROM payments_customer_data"));
+ sql::Statement s;
+ SelectBuilder(db_, s, kPaymentsCustomerDataTable, {kCustomerId});
if (s.Step()) {
*customer_data = std::make_unique<PaymentsCustomerData>(
/*customer_id=*/s.ColumnString(0));
@@ -2081,28 +2304,16 @@ void AutofillTable::SetAutofillOffers(
return;
// Delete all old values.
- sql::Statement delete_offers(
- db_->GetUniqueStatement("DELETE FROM offer_data"));
- sql::Statement delete_offer_eligible_instruments(
- db_->GetUniqueStatement("DELETE FROM offer_eligible_instrument"));
- sql::Statement delete_offer_merchant_domains(
- db_->GetUniqueStatement("DELETE FROM offer_merchant_domain"));
- delete_offers.Run();
- delete_offer_eligible_instruments.Run();
- delete_offer_merchant_domains.Run();
+ Delete(db_, kOfferDataTable);
+ Delete(db_, kOfferEligibleInstrumentTable);
+ Delete(db_, kOfferMerchantDomainTable);
// Insert new values.
- sql::Statement insert_offers(
- db_->GetUniqueStatement("INSERT INTO offer_data("
- "offer_id, " // 0
- "offer_reward_amount, " // 1
- "expiry, " // 2
- "offer_details_url, " // 3
- "promo_code, " // 4
- "value_prop_text, " // 5
- "see_details_text, " // 6
- "usage_instructions_text) " // 7
- "VALUES (?,?,?,?,?,?,?,?)"));
+ sql::Statement insert_offers;
+ InsertBuilder(
+ db_, insert_offers, kOfferDataTable,
+ {kOfferId, kOfferRewardAmount, kExpiry, kOfferDetailsUrl, kPromoCode,
+ kValuePropText, kSeeDetailsText, kUsageInstructionsText});
for (const AutofillOfferData& data : autofill_offer_data) {
insert_offers.BindInt64(0, data.GetOfferId());
@@ -2120,28 +2331,22 @@ void AutofillTable::SetAutofillOffers(
for (const int64_t instrument_id : data.GetEligibleInstrumentIds()) {
// Insert new offer_eligible_instrument values.
- sql::Statement insert_offer_eligible_instruments(
- db_->GetUniqueStatement("INSERT INTO offer_eligible_instrument("
- "offer_id, " // 0
- "instrument_id) " // 1
- "VALUES (?,?)"));
+ sql::Statement insert_offer_eligible_instruments;
+ InsertBuilder(db_, insert_offer_eligible_instruments,
+ kOfferEligibleInstrumentTable, {kOfferId, kInstrumentId});
insert_offer_eligible_instruments.BindInt64(0, data.GetOfferId());
insert_offer_eligible_instruments.BindInt64(1, instrument_id);
insert_offer_eligible_instruments.Run();
- insert_offer_eligible_instruments.Reset(true);
}
for (const GURL& merchant_origin : data.GetMerchantOrigins()) {
// Insert new offer_merchant_domain values.
- sql::Statement insert_offer_merchant_domains(
- db_->GetUniqueStatement("INSERT INTO offer_merchant_domain("
- "offer_id, " // 0
- "merchant_domain) " // 1
- "VALUES (?,?)"));
+ sql::Statement insert_offer_merchant_domains;
+ InsertBuilder(db_, insert_offer_merchant_domains,
+ kOfferMerchantDomainTable, {kOfferId, kMerchantDomain});
insert_offer_merchant_domains.BindInt64(0, data.GetOfferId());
insert_offer_merchant_domains.BindString(1, merchant_origin.spec());
insert_offer_merchant_domains.Run();
- insert_offer_merchant_domains.Reset(true);
}
}
transaction.Commit();
@@ -2151,17 +2356,11 @@ bool AutofillTable::GetAutofillOffers(
std::vector<std::unique_ptr<AutofillOfferData>>* autofill_offer_data) {
autofill_offer_data->clear();
- sql::Statement s(
- db_->GetUniqueStatement("SELECT "
- "offer_id, " // 0
- "offer_reward_amount, " // 1
- "expiry, " // 2
- "offer_details_url, " // 3
- "promo_code, " // 4
- "value_prop_text, " // 5
- "see_details_text, " // 6
- "usage_instructions_text " // 7
- "FROM offer_data"));
+ sql::Statement s;
+ SelectBuilder(
+ db_, s, kOfferDataTable,
+ {kOfferId, kOfferRewardAmount, kExpiry, kOfferDetailsUrl, kPromoCode,
+ kValuePropText, kSeeDetailsText, kUsageInstructionsText});
while (s.Step()) {
int index = 0;
@@ -2179,12 +2378,10 @@ bool AutofillTable::GetAutofillOffers(
std::vector<int64_t> eligible_instrument_id;
std::vector<GURL> merchant_origins;
- sql::Statement s_offer_eligible_instrument(
- db_->GetUniqueStatement("SELECT "
- "offer_id, " // 0
- "instrument_id " // 1
- "FROM offer_eligible_instrument "
- "WHERE offer_id = ?"));
+ sql::Statement s_offer_eligible_instrument;
+ SelectBuilder(db_, s_offer_eligible_instrument,
+ kOfferEligibleInstrumentTable, {kOfferId, kInstrumentId},
+ "WHERE offer_id = ?");
s_offer_eligible_instrument.BindInt64(0, offer_id);
while (s_offer_eligible_instrument.Step()) {
const int64_t instrument_id = s_offer_eligible_instrument.ColumnInt64(1);
@@ -2193,12 +2390,9 @@ bool AutofillTable::GetAutofillOffers(
}
}
- sql::Statement s_offer_merchant_domain(
- db_->GetUniqueStatement("SELECT "
- "offer_id, " // 0
- "merchant_domain " // 1
- "FROM offer_merchant_domain "
- "WHERE offer_id = ?"));
+ sql::Statement s_offer_merchant_domain;
+ SelectBuilder(db_, s_offer_merchant_domain, kOfferMerchantDomainTable,
+ {kOfferId, kMerchantDomain}, "WHERE offer_id = ?");
s_offer_merchant_domain.BindInt64(0, offer_id);
while (s_offer_merchant_domain.Step()) {
const std::string merchant_domain =
@@ -2230,8 +2424,8 @@ bool AutofillTable::InsertUpiId(const std::string& upi_id) {
if (!transaction.Begin())
return false;
- sql::Statement insert_upi_id_statement(
- db_->GetUniqueStatement("INSERT INTO payments_upi_vpa (vpa) VALUES (?)"));
+ sql::Statement insert_upi_id_statement;
+ InsertBuilder(db_, insert_upi_id_statement, kPaymentsUpiVpaTable, {kVpa});
insert_upi_id_statement.BindString(0, upi_id);
insert_upi_id_statement.Run();
@@ -2241,8 +2435,8 @@ bool AutofillTable::InsertUpiId(const std::string& upi_id) {
}
std::vector<std::string> AutofillTable::GetAllUpiIds() {
- sql::Statement select_upi_id_statement(
- db_->GetUniqueStatement("SELECT vpa FROM payments_upi_vpa"));
+ sql::Statement select_upi_id_statement;
+ SelectBuilder(db_, select_upi_id_statement, kPaymentsUpiVpaTable, {kVpa});
std::vector<std::string> upi_ids;
while (select_upi_id_statement.Step()) {
@@ -2256,55 +2450,16 @@ bool AutofillTable::ClearAllServerData() {
if (!transaction.Begin())
return false; // Some error, nothing was changed.
- sql::Statement masked(
- db_->GetUniqueStatement("DELETE FROM masked_credit_cards"));
- masked.Run();
- bool changed = db_->GetLastChangeCount() > 0;
-
- sql::Statement unmasked(
- db_->GetUniqueStatement("DELETE FROM unmasked_credit_cards"));
- unmasked.Run();
- changed |= db_->GetLastChangeCount() > 0;
-
- sql::Statement addresses(
- db_->GetUniqueStatement("DELETE FROM server_addresses"));
- addresses.Run();
- changed |= db_->GetLastChangeCount() > 0;
-
- sql::Statement card_metadata(
- db_->GetUniqueStatement("DELETE FROM server_card_metadata"));
- card_metadata.Run();
- changed |= db_->GetLastChangeCount() > 0;
-
- sql::Statement address_metadata(
- db_->GetUniqueStatement("DELETE FROM server_address_metadata"));
- address_metadata.Run();
- changed |= db_->GetLastChangeCount() > 0;
-
- sql::Statement customer_data(
- db_->GetUniqueStatement("DELETE FROM payments_customer_data"));
- customer_data.Run();
- changed |= db_->GetLastChangeCount() > 0;
-
- sql::Statement cloud_token_data(
- db_->GetUniqueStatement("DELETE FROM server_card_cloud_token_data"));
- cloud_token_data.Run();
- changed |= db_->GetLastChangeCount() > 0;
-
- sql::Statement autofill_offer_data(
- db_->GetUniqueStatement("DELETE FROM offer_data"));
- autofill_offer_data.Run();
- changed |= db_->GetLastChangeCount() > 0;
-
- sql::Statement autofill_offer_eligible_instrument(
- db_->GetUniqueStatement("DELETE FROM offer_eligible_instrument"));
- autofill_offer_eligible_instrument.Run();
- changed |= db_->GetLastChangeCount() > 0;
-
- sql::Statement autofill_offer_merchant_domain(
- db_->GetUniqueStatement("DELETE FROM offer_merchant_domain"));
- autofill_offer_merchant_domain.Run();
- changed |= db_->GetLastChangeCount() > 0;
+ bool changed = false;
+ for (base::StringPiece table_name :
+ {kMaskedCreditCardsTable, kUnmaskedCreditCardsTable,
+ kServerAddressesTable, kServerCardMetadataTable,
+ kServerAddressMetadataTable, kPaymentsCustomerDataTable,
+ kServerCardCloudTokenDataTable, kOfferDataTable,
+ kOfferEligibleInstrumentTable, kOfferMerchantDomainTable}) {
+ Delete(db_, table_name);
+ changed |= db_->GetLastChangeCount() > 0;
+ }
transaction.Commit();
return changed;
@@ -2335,11 +2490,9 @@ bool AutofillTable::RemoveAutofillDataModifiedBetween(
time_t delete_end_t = GetEndTime(delete_end);
// Remember Autofill profiles in the time range.
- sql::Statement s_profiles_get(db_->GetUniqueStatement(
- "SELECT guid FROM autofill_profiles "
- "WHERE date_modified >= ? AND date_modified < ?"));
- s_profiles_get.BindInt64(0, delete_begin_t);
- s_profiles_get.BindInt64(1, delete_end_t);
+ sql::Statement s_profiles_get;
+ SelectBetween(db_, s_profiles_get, kAutofillProfilesTable, {kGuid},
+ kDateModified, delete_begin_t, delete_end_t);
profiles->clear();
while (s_profiles_get.Step()) {
@@ -2359,9 +2512,9 @@ bool AutofillTable::RemoveAutofillDataModifiedBetween(
}
// Remove Autofill profiles in the time range.
- sql::Statement s_profiles(db_->GetUniqueStatement(
- "DELETE FROM autofill_profiles "
- "WHERE date_modified >= ? AND date_modified < ?"));
+ sql::Statement s_profiles;
+ DeleteBuilder(db_, s_profiles, kAutofillProfilesTable,
+ "date_modified >= ? AND date_modified < ?");
s_profiles.BindInt64(0, delete_begin_t);
s_profiles.BindInt64(1, delete_end_t);
@@ -2369,11 +2522,9 @@ bool AutofillTable::RemoveAutofillDataModifiedBetween(
return false;
// Remember Autofill credit cards in the time range.
- sql::Statement s_credit_cards_get(db_->GetUniqueStatement(
- "SELECT guid FROM credit_cards "
- "WHERE date_modified >= ? AND date_modified < ?"));
- s_credit_cards_get.BindInt64(0, delete_begin_t);
- s_credit_cards_get.BindInt64(1, delete_end_t);
+ sql::Statement s_credit_cards_get;
+ SelectBetween(db_, s_credit_cards_get, kCreditCardsTable, {kGuid},
+ kDateModified, delete_begin_t, delete_end_t);
credit_cards->clear();
while (s_credit_cards_get.Step()) {
@@ -2387,18 +2538,18 @@ bool AutofillTable::RemoveAutofillDataModifiedBetween(
return false;
// Remove Autofill credit cards in the time range.
- sql::Statement s_credit_cards(db_->GetUniqueStatement(
- "DELETE FROM credit_cards "
- "WHERE date_modified >= ? AND date_modified < ?"));
+ sql::Statement s_credit_cards;
+ DeleteBuilder(db_, s_credit_cards, kCreditCardsTable,
+ "date_modified >= ? AND date_modified < ?");
s_credit_cards.BindInt64(0, delete_begin_t);
s_credit_cards.BindInt64(1, delete_end_t);
if (!s_credit_cards.Run())
return false;
// Remove unmasked credit cards in the time range.
- sql::Statement s_unmasked_cards(
- db_->GetUniqueStatement("DELETE FROM unmasked_credit_cards "
- "WHERE unmask_date >= ? AND unmask_date < ?"));
+ sql::Statement s_unmasked_cards;
+ DeleteBuilder(db_, s_unmasked_cards, kUnmaskedCreditCardsTable,
+ "unmask_date >= ? AND unmask_date < ?");
s_unmasked_cards.BindInt64(0, delete_begin.ToInternalValue());
s_unmasked_cards.BindInt64(1, delete_end.ToInternalValue());
return s_unmasked_cards.Run();
@@ -2414,11 +2565,9 @@ bool AutofillTable::RemoveOriginURLsModifiedBetween(
time_t delete_end_t = GetEndTime(delete_end);
// Remember Autofill profiles with URL origins in the time range.
- sql::Statement s_profiles_get(db_->GetUniqueStatement(
- "SELECT guid, origin FROM autofill_profiles "
- "WHERE date_modified >= ? AND date_modified < ?"));
- s_profiles_get.BindInt64(0, delete_begin_t);
- s_profiles_get.BindInt64(1, delete_end_t);
+ sql::Statement s_profiles_get;
+ SelectBetween(db_, s_profiles_get, kAutofillProfilesTable, {kGuid, kOrigin},
+ kDateModified, delete_begin_t, delete_end_t);
std::vector<std::string> profile_guids;
while (s_profiles_get.Step()) {
@@ -2446,11 +2595,9 @@ bool AutofillTable::RemoveOriginURLsModifiedBetween(
}
// Remember Autofill credit cards with URL origins in the time range.
- sql::Statement s_credit_cards_get(db_->GetUniqueStatement(
- "SELECT guid, origin FROM credit_cards "
- "WHERE date_modified >= ? AND date_modified < ?"));
- s_credit_cards_get.BindInt64(0, delete_begin_t);
- s_credit_cards_get.BindInt64(1, delete_end_t);
+ sql::Statement s_credit_cards_get;
+ SelectBetween(db_, s_credit_cards_get, kCreditCardsTable, {kGuid, kOrigin},
+ kDateModified, delete_begin_t, delete_end_t);
std::vector<std::string> credit_card_guids;
while (s_credit_cards_get.Step()) {
@@ -2475,44 +2622,16 @@ bool AutofillTable::RemoveOriginURLsModifiedBetween(
}
bool AutofillTable::ClearAutofillProfiles() {
- sql::Statement s1(db_->GetUniqueStatement("DELETE FROM autofill_profiles"));
-
- if (!s1.Run())
- return false;
-
- sql::Statement s2(
- db_->GetUniqueStatement("DELETE FROM autofill_profile_names"));
-
- if (!s2.Run())
- return false;
-
- sql::Statement s3(
- db_->GetUniqueStatement("DELETE FROM autofill_profile_emails"));
-
- if (!s3.Run())
- return false;
-
- sql::Statement s4(
- db_->GetUniqueStatement("DELETE FROM autofill_profile_addresses"));
-
- if (!s4.Run())
- return false;
-
- sql::Statement s5(
- db_->GetUniqueStatement("DELETE FROM autofill_profile_phones"));
-
- if (!s5.Run())
- return false;
-
- sql::Statement s6(
- db_->GetUniqueStatement("DELETE FROM autofill_profile_birthdates"));
-
- return s6.Run();
+ return Delete(db_, kAutofillProfilesTable) &&
+ Delete(db_, kAutofillProfileNamesTable) &&
+ Delete(db_, kAutofillProfileEmailsTable) &&
+ Delete(db_, kAutofillProfileAddressesTable) &&
+ Delete(db_, kAutofillProfilePhonesTable) &&
+ Delete(db_, kAutofillProfileBirthdatesTable);
}
bool AutofillTable::ClearCreditCards() {
- sql::Statement s1(db_->GetUniqueStatement("DELETE FROM credit_cards"));
- return s1.Run();
+ return Delete(db_, kCreditCardsTable);
}
bool AutofillTable::GetAllSyncMetadata(syncer::ModelType model_type,
@@ -2539,9 +2658,10 @@ bool AutofillTable::UpdateSyncMetadata(
DCHECK(SupportsMetadataForModelType(model_type))
<< "Model type " << model_type << " not supported for metadata";
- sql::Statement s(db_->GetUniqueStatement(
- "INSERT OR REPLACE INTO autofill_sync_metadata "
- "(model_type, storage_key, value) VALUES(?, ?, ?)"));
+ sql::Statement s;
+ InsertBuilder(db_, s, kAutofillSyncMetadataTable,
+ {kModelType, kStorageKey, kValue},
+ /*or_replace=*/true);
s.BindInt(0, GetKeyValueForModelType(model_type));
s.BindString(1, storage_key);
s.BindString(2, metadata.SerializeAsString());
@@ -2554,9 +2674,9 @@ bool AutofillTable::ClearSyncMetadata(syncer::ModelType model_type,
DCHECK(SupportsMetadataForModelType(model_type))
<< "Model type " << model_type << " not supported for metadata";
- sql::Statement s(
- db_->GetUniqueStatement("DELETE FROM autofill_sync_metadata WHERE "
- "model_type=? AND storage_key=?"));
+ sql::Statement s;
+ DeleteBuilder(db_, s, kAutofillSyncMetadataTable,
+ "model_type=? AND storage_key=?");
s.BindInt(0, GetKeyValueForModelType(model_type));
s.BindString(1, storage_key);
@@ -2571,9 +2691,9 @@ bool AutofillTable::UpdateModelTypeState(
// Hardcode the id to force a collision, ensuring that there remains only a
// single entry.
- sql::Statement s(db_->GetUniqueStatement(
- "INSERT OR REPLACE INTO autofill_model_type_state (model_type, value) "
- "VALUES(?,?)"));
+ sql::Statement s;
+ InsertBuilder(db_, s, kAutofillModelTypeStateTable, {kModelType, kValue},
+ /*or_replace=*/true);
s.BindInt(0, GetKeyValueForModelType(model_type));
s.BindString(1, model_type_state.SerializeAsString());
@@ -2584,8 +2704,8 @@ bool AutofillTable::ClearModelTypeState(syncer::ModelType model_type) {
DCHECK(SupportsMetadataForModelType(model_type))
<< "Model type " << model_type << " not supported for metadata";
- sql::Statement s(db_->GetUniqueStatement(
- "DELETE FROM autofill_model_type_state WHERE model_type=?"));
+ sql::Statement s;
+ DeleteBuilder(db_, s, kAutofillModelTypeStateTable, "model_type=?");
s.BindInt(0, GetKeyValueForModelType(model_type));
return s.Run();
@@ -2619,747 +2739,63 @@ bool AutofillTable::RemoveOrphanAutofillTableRows() {
return true;
}
-bool AutofillTable::MigrateToVersion54AddI18nFieldsAndRemoveDeprecatedFields() {
- sql::Transaction transaction(db_);
- if (!transaction.Begin())
- return false;
-
- // Test the existence of the |address_line_1| column as an indication that a
- // migration is needed. It is possible that the new |autofill_profile_phones|
- // schema is in place because the table was newly created when migrating from
- // a pre-version-23 database.
- if (db_->DoesColumnExist("autofill_profiles", "address_line_1")) {
- // Create a temporary copy of the autofill_profiles table in the (newer)
- // version 54 format. This table
- // (a) adds columns for street_address, dependent_locality, and
- // sorting_code,
- // (b) removes the address_line_1 and address_line_2 columns, which are
- // replaced by the street_address column, and
- // (c) removes the country column, which was long deprecated.
- if (db_->DoesTableExist("autofill_profiles_temp") ||
- !db_->Execute("CREATE TABLE autofill_profiles_temp ( "
- "guid VARCHAR PRIMARY KEY, "
- "company_name VARCHAR, "
- "street_address VARCHAR, "
- "dependent_locality VARCHAR, "
- "city VARCHAR, "
- "state VARCHAR, "
- "zipcode VARCHAR, "
- "sorting_code VARCHAR, "
- "country_code VARCHAR, "
- "date_modified INTEGER NOT NULL DEFAULT 0, "
- "origin VARCHAR DEFAULT '')")) {
- return false;
- }
-
- // Copy over the data from the autofill_profiles table, taking care to merge
- // the address lines 1 and 2 into the new street_address column.
- if (!db_->Execute("INSERT INTO autofill_profiles_temp "
- "SELECT guid, company_name, '', '', city, state, zipcode,"
- " '', country_code, date_modified, origin "
- "FROM autofill_profiles")) {
- return false;
- }
- sql::Statement s(db_->GetUniqueStatement(
- "SELECT guid, address_line_1, address_line_2 FROM autofill_profiles"));
- while (s.Step()) {
- std::string guid = s.ColumnString(0);
- std::u16string line1 = s.ColumnString16(1);
- std::u16string line2 = s.ColumnString16(2);
- std::u16string street_address = line1;
- if (!line2.empty())
- street_address += u"\n" + line2;
-
- sql::Statement s_update(db_->GetUniqueStatement(
- "UPDATE autofill_profiles_temp SET street_address=? WHERE guid=?"));
- s_update.BindString16(0, street_address);
- s_update.BindString(1, guid);
- if (!s_update.Run())
- return false;
- }
- if (!s.Succeeded())
- return false;
-
- // Delete the existing (version 53) table and replace it with the contents
- // of the temporary table.
- if (!db_->Execute("DROP TABLE autofill_profiles") ||
- !db_->Execute("ALTER TABLE autofill_profiles_temp "
- "RENAME TO autofill_profiles")) {
- return false;
- }
- }
-
- // Test the existence of the |type| column as an indication that a migration
- // is needed. It is possible that the new |autofill_profile_phones| schema is
- // in place because the table was newly created when migrating from a
- // pre-version-23 database.
- if (db_->DoesColumnExist("autofill_profile_phones", "type")) {
- // Create a temporary copy of the autofill_profile_phones table in the
- // (newer) version 54 format. This table removes the deprecated |type|
- // column.
- if (db_->DoesTableExist("autofill_profile_phones_temp") ||
- !db_->Execute("CREATE TABLE autofill_profile_phones_temp ( "
- "guid VARCHAR, "
- "number VARCHAR)")) {
- return false;
- }
-
- // Copy over the data from the autofill_profile_phones table.
- if (!db_->Execute("INSERT INTO autofill_profile_phones_temp "
- "SELECT guid, number FROM autofill_profile_phones")) {
- return false;
- }
-
- // Delete the existing (version 53) table and replace it with the contents
- // of the temporary table.
- if (!db_->Execute("DROP TABLE autofill_profile_phones"))
- return false;
- if (!db_->Execute("ALTER TABLE autofill_profile_phones_temp "
- "RENAME TO autofill_profile_phones")) {
- return false;
- }
- }
-
- return transaction.Commit();
-}
-
-bool AutofillTable::MigrateToVersion55MergeAutofillDatesTable() {
- sql::Transaction transaction(db_);
- if (!transaction.Begin())
- return false;
-
- if (db_->DoesTableExist("autofill_temp") ||
- !db_->Execute("CREATE TABLE autofill_temp ("
- "name VARCHAR, "
- "value VARCHAR, "
- "value_lower VARCHAR, "
- "date_created INTEGER DEFAULT 0, "
- "date_last_used INTEGER DEFAULT 0, "
- "count INTEGER DEFAULT 1, "
- "PRIMARY KEY (name, value))")) {
- return false;
- }
-
- // Slurp up the data from the existing table and write it to the new table.
- sql::Statement s(db_->GetUniqueStatement(
- "SELECT name, value, value_lower, count, MIN(date_created),"
- " MAX(date_created) "
- "FROM autofill a JOIN autofill_dates ad ON a.pair_id=ad.pair_id "
- "GROUP BY name, value, value_lower, count"));
- while (s.Step()) {
- sql::Statement s_insert(db_->GetUniqueStatement(
- "INSERT INTO autofill_temp "
- "(name, value, value_lower, count, date_created, date_last_used) "
- "VALUES (?, ?, ?, ?, ?, ?)"));
- s_insert.BindString16(0, s.ColumnString16(0));
- s_insert.BindString16(1, s.ColumnString16(1));
- s_insert.BindString16(2, s.ColumnString16(2));
- s_insert.BindInt(3, s.ColumnInt(3));
- s_insert.BindInt64(4, s.ColumnInt64(4));
- s_insert.BindInt64(5, s.ColumnInt64(5));
- if (!s_insert.Run())
- return false;
- }
-
- if (!s.Succeeded())
- return false;
-
- // Delete the existing (version 54) tables and replace them with the contents
- // of the temporary table.
- if (!db_->Execute("DROP TABLE autofill") ||
- !db_->Execute("DROP TABLE autofill_dates") ||
- !db_->Execute("ALTER TABLE autofill_temp "
- "RENAME TO autofill")) {
- return false;
- }
-
- // Create indices on the new table, for fast lookups.
- if (!db_->Execute("CREATE INDEX autofill_name ON autofill (name)") ||
- !db_->Execute("CREATE INDEX autofill_name_value_lower ON "
- "autofill (name, value_lower)")) {
- return false;
- }
-
- return transaction.Commit();
-}
-
-bool AutofillTable::MigrateToVersion56AddProfileLanguageCodeForFormatting() {
- return db_->Execute(
- "ALTER TABLE autofill_profiles ADD COLUMN language_code VARCHAR");
-}
-
-bool AutofillTable::MigrateToVersion57AddFullNameField() {
- return db_->Execute(
- "ALTER TABLE autofill_profile_names ADD COLUMN full_name VARCHAR");
-}
-
-bool AutofillTable::MigrateToVersion60AddServerCards() {
- sql::Transaction transaction(db_);
- if (!transaction.Begin())
- return false;
-
- if (!db_->DoesTableExist("masked_credit_cards") &&
- !db_->Execute("CREATE TABLE masked_credit_cards ("
- "id VARCHAR,"
- "status VARCHAR,"
- "name_on_card VARCHAR,"
- "type VARCHAR,"
- "last_four VARCHAR,"
- "exp_month INTEGER DEFAULT 0,"
- "exp_year INTEGER DEFAULT 0)")) {
- return false;
- }
-
- if (!db_->DoesTableExist("unmasked_credit_cards") &&
- !db_->Execute("CREATE TABLE unmasked_credit_cards ("
- "id VARCHAR,"
- "card_number_encrypted VARCHAR)")) {
- return false;
- }
-
- if (!db_->DoesTableExist("server_addresses") &&
- !db_->Execute("CREATE TABLE server_addresses ("
- "id VARCHAR,"
- "company_name VARCHAR,"
- "street_address VARCHAR,"
- "address_1 VARCHAR,"
- "address_2 VARCHAR,"
- "address_3 VARCHAR,"
- "address_4 VARCHAR,"
- "postal_code VARCHAR,"
- "sorting_code VARCHAR,"
- "country_code VARCHAR,"
- "language_code VARCHAR)")) {
- return false;
- }
-
- return transaction.Commit();
-}
-
-bool AutofillTable::MigrateToVersion61AddUsageStats() {
- sql::Transaction transaction(db_);
- if (!transaction.Begin())
- return false;
-
- // Add use_count to autofill_profiles.
- if (!db_->DoesColumnExist("autofill_profiles", "use_count") &&
- !db_->Execute("ALTER TABLE autofill_profiles ADD COLUMN "
- "use_count INTEGER NOT NULL DEFAULT 0")) {
- return false;
- }
-
- // Add use_date to autofill_profiles.
- if (!db_->DoesColumnExist("autofill_profiles", "use_date") &&
- !db_->Execute("ALTER TABLE autofill_profiles ADD COLUMN "
- "use_date INTEGER NOT NULL DEFAULT 0")) {
- return false;
- }
-
- // Add use_count to credit_cards.
- if (!db_->DoesColumnExist("credit_cards", "use_count") &&
- !db_->Execute("ALTER TABLE credit_cards ADD COLUMN "
- "use_count INTEGER NOT NULL DEFAULT 0")) {
- return false;
- }
-
- // Add use_date to credit_cards.
- if (!db_->DoesColumnExist("credit_cards", "use_date") &&
- !db_->Execute("ALTER TABLE credit_cards ADD COLUMN "
- "use_date INTEGER NOT NULL DEFAULT 0")) {
- return false;
- }
-
- return transaction.Commit();
-}
-
-bool AutofillTable::MigrateToVersion62AddUsageStatsForUnmaskedCards() {
- sql::Transaction transaction(db_);
- if (!transaction.Begin())
- return false;
-
- // Add use_count to unmasked_credit_cards.
- if (!db_->DoesColumnExist("unmasked_credit_cards", "use_count") &&
- !db_->Execute("ALTER TABLE unmasked_credit_cards ADD COLUMN "
- "use_count INTEGER NOT NULL DEFAULT 0")) {
- return false;
- }
-
- // Add use_date to unmasked_credit_cards.
- if (!db_->DoesColumnExist("unmasked_credit_cards", "use_date") &&
- !db_->Execute("ALTER TABLE unmasked_credit_cards ADD COLUMN "
- "use_date INTEGER NOT NULL DEFAULT 0")) {
- return false;
- }
-
- return transaction.Commit();
-}
-
-bool AutofillTable::MigrateToVersion63AddServerRecipientName() {
- if (!db_->DoesColumnExist("server_addresses", "recipient_name") &&
- !db_->Execute("ALTER TABLE server_addresses ADD COLUMN "
- "recipient_name VARCHAR")) {
- return false;
- }
- return true;
-}
-
-bool AutofillTable::MigrateToVersion64AddUnmaskDate() {
- sql::Transaction transaction(db_);
- if (!transaction.Begin())
- return false;
-
- if (!db_->DoesColumnExist("unmasked_credit_cards", "unmask_date") &&
- !db_->Execute("ALTER TABLE unmasked_credit_cards ADD COLUMN "
- "unmask_date INTEGER NOT NULL DEFAULT 0")) {
- return false;
- }
- if (!db_->DoesColumnExist("server_addresses", "phone_number") &&
- !db_->Execute("ALTER TABLE server_addresses ADD COLUMN "
- "phone_number VARCHAR")) {
- return false;
- }
-
- return transaction.Commit();
-}
-
-bool AutofillTable::MigrateToVersion65AddServerMetadataTables() {
- sql::Transaction transaction(db_);
- if (!transaction.Begin())
- return false;
-
- if (!db_->DoesTableExist("server_card_metadata") &&
- !db_->Execute("CREATE TABLE server_card_metadata ("
- "id VARCHAR NOT NULL,"
- "use_count INTEGER NOT NULL DEFAULT 0, "
- "use_date INTEGER NOT NULL DEFAULT 0)")) {
- return false;
- }
-
- // This clobbers existing usage metadata, which is not synced and only
- // applies to unmasked cards. Trying to migrate the usage metadata would be
- // tricky as multiple devices for the same user get DB upgrades.
- if (!db_->Execute("UPDATE unmasked_credit_cards "
- "SET use_count=0, use_date=0")) {
- return false;
- }
-
- if (!db_->DoesTableExist("server_address_metadata") &&
- !db_->Execute("CREATE TABLE server_address_metadata ("
- "id VARCHAR NOT NULL,"
- "use_count INTEGER NOT NULL DEFAULT 0, "
- "use_date INTEGER NOT NULL DEFAULT 0)")) {
- return false;
- }
-
- // Get existing server addresses and generate IDs for them.
- sql::Statement s(db_->GetUniqueStatement(
- "SELECT "
- "id,"
- "recipient_name,"
- "company_name,"
- "street_address,"
- "address_1," // ADDRESS_HOME_STATE
- "address_2," // ADDRESS_HOME_CITY
- "address_3," // ADDRESS_HOME_DEPENDENT_LOCALITY
- "address_4," // Not supported in AutofillProfile yet.
- "postal_code," // ADDRESS_HOME_ZIP
- "sorting_code," // ADDRESS_HOME_SORTING_CODE
- "country_code," // ADDRESS_HOME_COUNTRY
- "phone_number," // PHONE_HOME_WHOLE_NUMBER
- "language_code "
- "FROM server_addresses addresses"));
- std::vector<AutofillProfile> profiles;
- while (s.Step()) {
- int index = 0;
- AutofillProfile profile(AutofillProfile::SERVER_PROFILE,
- s.ColumnString(index++));
-
- std::u16string recipient_name = s.ColumnString16(index++);
- profile.SetRawInfo(COMPANY_NAME, s.ColumnString16(index++));
- profile.SetRawInfo(ADDRESS_HOME_STREET_ADDRESS, s.ColumnString16(index++));
- profile.SetRawInfo(ADDRESS_HOME_STATE, s.ColumnString16(index++));
- profile.SetRawInfo(ADDRESS_HOME_CITY, s.ColumnString16(index++));
- profile.SetRawInfo(ADDRESS_HOME_DEPENDENT_LOCALITY,
- s.ColumnString16(index++));
- index++; // Skip address_4 which we haven't added to AutofillProfile yet.
- profile.SetRawInfo(ADDRESS_HOME_ZIP, s.ColumnString16(index++));
- profile.SetRawInfo(ADDRESS_HOME_SORTING_CODE, s.ColumnString16(index++));
- profile.SetRawInfo(ADDRESS_HOME_COUNTRY, s.ColumnString16(index++));
- std::u16string phone_number = s.ColumnString16(index++);
- profile.set_language_code(s.ColumnString(index++));
- profile.SetInfo(NAME_FULL, recipient_name, profile.language_code());
- profile.SetInfo(PHONE_HOME_WHOLE_NUMBER, phone_number,
- profile.language_code());
- profile.GenerateServerProfileIdentifier();
- profiles.push_back(profile);
- }
-
- // Reinsert with the generated IDs.
- sql::Statement delete_old(
- db_->GetUniqueStatement("DELETE FROM server_addresses"));
- delete_old.Run();
-
- sql::Statement insert(db_->GetUniqueStatement(
- "INSERT INTO server_addresses("
- "id,"
- "recipient_name,"
- "company_name,"
- "street_address,"
- "address_1," // ADDRESS_HOME_STATE
- "address_2," // ADDRESS_HOME_CITY
- "address_3," // ADDRESS_HOME_DEPENDENT_LOCALITY
- "address_4," // Not supported in AutofillProfile yet.
- "postal_code," // ADDRESS_HOME_ZIP
- "sorting_code," // ADDRESS_HOME_SORTING_CODE
- "country_code," // ADDRESS_HOME_COUNTRY
- "phone_number," // PHONE_HOME_WHOLE_NUMBER
- "language_code) "
- "VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?)"));
- for (const AutofillProfile& profile : profiles) {
- int index = 0;
- insert.BindString(index++, profile.server_id());
- insert.BindString16(index++, profile.GetRawInfo(NAME_FULL));
- insert.BindString16(index++, profile.GetRawInfo(COMPANY_NAME));
- insert.BindString16(index++,
- profile.GetRawInfo(ADDRESS_HOME_STREET_ADDRESS));
- insert.BindString16(index++, profile.GetRawInfo(ADDRESS_HOME_STATE));
- insert.BindString16(index++, profile.GetRawInfo(ADDRESS_HOME_CITY));
- insert.BindString16(index++,
- profile.GetRawInfo(ADDRESS_HOME_DEPENDENT_LOCALITY));
- index++; // SKip address_4 which we haven't added to AutofillProfile yet.
- insert.BindString16(index++, profile.GetRawInfo(ADDRESS_HOME_ZIP));
- insert.BindString16(index++, profile.GetRawInfo(ADDRESS_HOME_SORTING_CODE));
- insert.BindString16(index++, profile.GetRawInfo(ADDRESS_HOME_COUNTRY));
- insert.BindString16(index++, profile.GetRawInfo(PHONE_HOME_WHOLE_NUMBER));
- insert.BindString(index++, profile.language_code());
- insert.Run();
- insert.Reset(true);
- }
-
- return transaction.Commit();
-}
-
-bool AutofillTable::MigrateToVersion66AddCardBillingAddress() {
- // The default value for this column is null, but Connection::ColumnString()
- // returns an empty string for that.
- return db_->Execute(
- "ALTER TABLE credit_cards ADD COLUMN billing_address_id VARCHAR");
-}
-
-bool AutofillTable::MigrateToVersion67AddMaskedCardBillingAddress() {
- // The default value for this column is null, but Connection::ColumnString()
- // returns an empty string for that.
- return db_->Execute(
- "ALTER TABLE masked_credit_cards ADD COLUMN billing_address_id VARCHAR");
-}
-
-bool AutofillTable::MigrateToVersion70AddSyncMetadata() {
- if (!db_->Execute("CREATE TABLE autofill_sync_metadata ("
- "storage_key VARCHAR PRIMARY KEY NOT NULL,"
- "value BLOB)")) {
- return false;
- }
- return db_->Execute(
- "CREATE TABLE autofill_model_type_state (id INTEGER PRIMARY KEY, value "
- "BLOB)");
-}
-
-bool AutofillTable::
- MigrateToVersion71AddHasConvertedAndBillingAddressIdMetadata() {
- sql::Transaction transaction(db_);
- if (!transaction.Begin())
- return false;
-
- // Add the new has_converted column to the server_address_metadata table.
- if (!db_->DoesColumnExist("server_address_metadata", "has_converted") &&
- !db_->Execute("ALTER TABLE server_address_metadata ADD COLUMN "
- "has_converted BOOL NOT NULL DEFAULT FALSE")) {
- return false;
- }
-
- // Add the new billing_address_id column to the server_card_metadata table.
- if (!db_->DoesColumnExist("server_card_metadata", "billing_address_id") &&
- !db_->Execute("ALTER TABLE server_card_metadata ADD COLUMN "
- "billing_address_id VARCHAR")) {
- return false;
- }
-
- // Copy over the billing_address_id from the masked_server_cards to
- // server_card_metadata.
- if (!db_->Execute("UPDATE server_card_metadata "
- "SET billing_address_id = "
- "(SELECT billing_address_id "
- "FROM masked_credit_cards "
- "WHERE id = server_card_metadata.id)")) {
- return false;
- }
-
- if (db_->DoesTableExist("masked_credit_cards_temp") &&
- !db_->Execute("DROP TABLE masked_credit_cards_temp")) {
- return false;
- }
-
- // Remove the billing_address_id column from the masked_credit_cards table.
- // Create a temporary table that is a copy of masked_credit_cards but without
- // the billing_address_id column.
- if (!db_->Execute("CREATE TABLE masked_credit_cards_temp ("
- "id VARCHAR,"
- "status VARCHAR,"
- "name_on_card VARCHAR,"
- "type VARCHAR,"
- "last_four VARCHAR,"
- "exp_month INTEGER DEFAULT 0,"
- "exp_year INTEGER DEFAULT 0)")) {
- return false;
- }
- // Copy over the data from the original masked_credit_cards table.
- if (!db_->Execute("INSERT INTO masked_credit_cards_temp "
- "SELECT id, status, name_on_card, type, last_four, "
- "exp_month, exp_year "
- "FROM masked_credit_cards")) {
- return false;
- }
- // Delete the existing table and replace it with the contents of the
- // temporary table.
- if (!db_->Execute("DROP TABLE masked_credit_cards") ||
- !db_->Execute("ALTER TABLE masked_credit_cards_temp "
- "RENAME TO masked_credit_cards")) {
- return false;
- }
-
- return transaction.Commit();
-}
-
-bool AutofillTable::MigrateToVersion72RenameCardTypeToIssuerNetwork() {
- sql::Transaction transaction(db_);
- if (!transaction.Begin())
- return false;
-
- if (db_->DoesTableExist("masked_credit_cards_temp") &&
- !db_->Execute("DROP TABLE masked_credit_cards_temp")) {
- return false;
- }
-
- return db_->Execute(
- "CREATE TABLE masked_credit_cards_temp ("
- "id VARCHAR,"
- "status VARCHAR,"
- "name_on_card VARCHAR,"
- "network VARCHAR,"
- "last_four VARCHAR,"
- "exp_month INTEGER DEFAULT 0,"
- "exp_year INTEGER DEFAULT 0)") &&
- db_->Execute(
- "INSERT INTO masked_credit_cards_temp ("
- "id, status, name_on_card, network, last_four, exp_month, exp_year"
- ") SELECT "
- "id, status, name_on_card, type, last_four, exp_month, exp_year"
- " FROM masked_credit_cards") &&
- db_->Execute("DROP TABLE masked_credit_cards") &&
- db_->Execute(
- "ALTER TABLE masked_credit_cards_temp "
- "RENAME TO masked_credit_cards") &&
- transaction.Commit();
-}
-
-bool AutofillTable::MigrateToVersion73AddMaskedCardBankName() {
- // Add the new bank_name column to the masked_credit_cards table.
- return db_->DoesColumnExist("masked_credit_cards", "bank_name") ||
- db_->Execute(
- "ALTER TABLE masked_credit_cards ADD COLUMN bank_name VARCHAR");
-}
-
-bool AutofillTable::MigrateToVersion74AddServerCardTypeColumn() {
- // Version 73 was actually used by two different schemas; an attempt to add
- // the "type" column (as in this version 74) was landed and reverted, and then
- // the "bank_name" column was added (and stuck). Some clients may have been
- // upgraded to one and some the other. Figure out which is the case.
- const bool added_type_column_in_v73 =
- db_->DoesColumnExist("masked_credit_cards", "type");
-
- // If we previously added the "type" column, then it's already present with
- // the correct semantics, but we now need to run the "bank_name" migration.
- // Otherwise, we need to add "type" now.
- return added_type_column_in_v73 ? MigrateToVersion73AddMaskedCardBankName()
- : db_->Execute(
- "ALTER TABLE masked_credit_cards ADD "
- "COLUMN type INTEGER DEFAULT 0");
-}
-
-bool AutofillTable::MigrateToVersion75AddProfileValidityBitfieldColumn() {
- // Add the new valdity_bitfield column to the autofill_profiles table.
- return db_->Execute(
- "ALTER TABLE autofill_profiles ADD COLUMN validity_bitfield UNSIGNED NOT "
- "NULL DEFAULT 0");
-}
-
-bool AutofillTable::MigrateToVersion78AddModelTypeColumns() {
- // Add the new model type columns to the autofill metadata tables.
- sql::Transaction transaction(db_);
- if (!transaction.Begin())
- return false;
-
- if (db_->DoesTableExist("autofill_sync_metadata_temp") &&
- !db_->Execute("DROP TABLE autofill_sync_metadata_temp")) {
- return false;
- }
-
- if (db_->DoesTableExist("autofill_model_type_state_temp") &&
- !db_->Execute("DROP TABLE autofill_model_type_state_temp")) {
- return false;
- }
-
- if (!db_->Execute("CREATE TABLE autofill_sync_metadata_temp ("
- "model_type INTEGER NOT NULL, "
- "storage_key VARCHAR NOT NULL, "
- "value BLOB, "
- "PRIMARY KEY (model_type, storage_key))") ||
- !db_->Execute("CREATE TABLE autofill_model_type_state_temp ("
- "model_type INTEGER NOT NULL PRIMARY KEY, value BLOB)")) {
- return false;
- }
-
- sql::Statement insert_metadata(
- db_->GetUniqueStatement("INSERT INTO autofill_sync_metadata_temp "
- "(model_type, storage_key, value) "
- "SELECT ?, storage_key, value "
- "FROM autofill_sync_metadata"));
- // Note: This uses the *wrong* ID for the ModelType - instead of
- // |syncer::ModelTypeHistogramValue|, this should be |GetKeyValueForModelType|
- // aka |syncer::ModelTypeToStableIdentifier|. But at this point, fixing it
- // here would just make an even bigger mess. Instead, we clean this up in the
- // migration to version 81. See also crbug.com/895826.
- insert_metadata.BindInt(
- 0, static_cast<int>(syncer::ModelTypeHistogramValue(syncer::AUTOFILL)));
-
- // Prior to this migration, the table was a singleton, containing only one
- // entry with id being hard-coded to 1.
- sql::Statement insert_state(
- db_->GetUniqueStatement("INSERT INTO autofill_model_type_state_temp "
- "(model_type, value) SELECT ?, value "
- "FROM autofill_model_type_state WHERE id=1"));
- // Note: Like above, this uses the *wrong* ID for the ModelType.
- insert_state.BindInt(
- 0, static_cast<int>(syncer::ModelTypeHistogramValue(syncer::AUTOFILL)));
-
- if (!insert_metadata.Run() || !insert_state.Run()) {
- return false;
- }
-
- return db_->Execute("DROP TABLE autofill_sync_metadata") &&
- db_->Execute(
- "ALTER TABLE autofill_sync_metadata_temp "
- "RENAME TO autofill_sync_metadata") &&
- db_->Execute("DROP TABLE autofill_model_type_state") &&
- db_->Execute(
- "ALTER TABLE autofill_model_type_state_temp "
- "RENAME TO autofill_model_type_state") &&
- transaction.Commit();
-}
-
-bool AutofillTable::MigrateToVersion80AddIsClientValidityStatesUpdatedColumn() {
- // Add the client validity states updated flag column to the autofill_profiles
- // table.
- return db_->Execute(
- "ALTER TABLE autofill_profiles ADD COLUMN "
- "is_client_validity_states_updated BOOL NOT "
- "NULL DEFAULT FALSE");
-}
-
-bool AutofillTable::MigrateToVersion81CleanUpWrongModelTypeData() {
- // The migration to version 78 inserted Sync data with wrong values in the
- // model_type column of the autofill_model_type_state and
- // autofill_sync_metadata tables. Here we just delete the bad data - no point
- // in trying to recover anything, since by now it'll have been redownloaded
- // anyway.
- const int bad_model_type_id =
- static_cast<int>(syncer::ModelTypeHistogramValue(syncer::AUTOFILL));
- DCHECK_NE(bad_model_type_id, GetKeyValueForModelType(syncer::AUTOFILL));
-
- sql::Transaction transaction(db_);
- if (!transaction.Begin())
- return false;
-
- sql::Statement delete_bad_model_type_state(db_->GetUniqueStatement(
- "DELETE FROM autofill_model_type_state WHERE model_type = ?;"));
- delete_bad_model_type_state.BindInt(0, bad_model_type_id);
-
- sql::Statement delete_bad_sync_metadata(db_->GetUniqueStatement(
- "DELETE FROM autofill_sync_metadata WHERE model_type = ?;"));
- delete_bad_sync_metadata.BindInt(0, bad_model_type_id);
-
- return delete_bad_model_type_state.Run() && delete_bad_sync_metadata.Run() &&
- transaction.Commit();
-}
-
bool AutofillTable::MigrateToVersion83RemoveServerCardTypeColumn() {
// Sqlite does not support "alter table drop column" syntax, so it has be done
// manually.
+ constexpr base::StringPiece kMaskedCreditCardsTempTable =
+ "masked_credit_cards_temp";
sql::Transaction transaction(db_);
return transaction.Begin() &&
- db_->Execute(
- "CREATE TABLE masked_credit_cards_temp ("
- "id VARCHAR,"
- "status VARCHAR,"
- "name_on_card VARCHAR,"
- "network VARCHAR,"
- "last_four VARCHAR,"
- "exp_month INTEGER DEFAULT 0,"
- "exp_year INTEGER DEFAULT 0, "
- "bank_name VARCHAR)") &&
+ CreateTable(db_, kMaskedCreditCardsTempTable,
+ {{kId, "VARCHAR"},
+ {kStatus, "VARCHAR"},
+ {kNameOnCard, "VARCHAR"},
+ {kNetwork, "VARCHAR"},
+ {kLastFour, "VARCHAR"},
+ {kExpMonth, "INTEGER DEFAULT 0"},
+ {kExpYear, "INTEGER DEFAULT 0"},
+ {kBankName, "VARCHAR"}}) &&
db_->Execute(
"INSERT INTO masked_credit_cards_temp "
"SELECT id, status, name_on_card, network, last_four, exp_month,"
"exp_year, bank_name "
"FROM masked_credit_cards") &&
- db_->Execute("DROP TABLE masked_credit_cards") &&
- db_->Execute(
- "ALTER TABLE masked_credit_cards_temp "
- "RENAME TO masked_credit_cards") &&
+ DropTable(db_, kMaskedCreditCardsTable) &&
+ RenameTable(db_, kMaskedCreditCardsTempTable,
+ kMaskedCreditCardsTable) &&
transaction.Commit();
}
bool AutofillTable::MigrateToVersion84AddNicknameColumn() {
// Add the nickname column to the masked_credit_cards table.
- return db_->DoesColumnExist("masked_credit_cards", "nickname") ||
- db_->Execute(
- "ALTER TABLE masked_credit_cards ADD COLUMN nickname VARCHAR");
+ return AddColumnIfNotExists(db_, kMaskedCreditCardsTable, kNickname,
+ "VARCHAR");
}
bool AutofillTable::MigrateToVersion85AddCardIssuerColumnToMaskedCreditCard() {
// Add the new card_issuer column to the masked_credit_cards table and set the
// default value to ISSUER_UNKNOWN.
- return db_->DoesColumnExist("masked_credit_cards", "card_issuer") ||
- db_->Execute(
- "ALTER TABLE masked_credit_cards "
- "ADD COLUMN card_issuer INTEGER "
- "DEFAULT 0");
+ return AddColumnIfNotExists(db_, kMaskedCreditCardsTable, kCardIssuer,
+ "INTEGER DEFAULT 0");
}
bool AutofillTable::MigrateToVersion88AddNewNameColumns() {
- for (const char* column : {"honorific_prefix", "first_last_name",
- "conjunction_last_name", "second_last_name"}) {
- if (!db_->DoesColumnExist("autofill_profile_names", column) &&
- !db_->Execute(
- base::StrCat({"ALTER TABLE autofill_profile_names ADD COLUMN ",
- column, " VARCHAR"})
- .c_str())) {
+ for (base::StringPiece column : {kHonorificPrefix, kFirstLastName,
+ kConjunctionLastName, kSecondLastName}) {
+ if (!AddColumnIfNotExists(db_, kAutofillProfileNamesTable, column,
+ "VARCHAR")) {
return false;
}
}
- for (const char* column :
- {"honorific_prefix_status", "first_name_status", "middle_name_status",
- "last_name_status", "first_last_name_status",
- "conjunction_last_name_status", "second_last_name_status",
- "full_name_status"}) {
+ for (base::StringPiece column :
+ {kHonorificPrefixStatus, kFirstNameStatus, kMiddleNameStatus,
+ kLastNameStatus, kFirstLastNameStatus, kConjunctionLastNameStatus,
+ kSecondLastNameStatus, kFullNameStatus}) {
// The default value of 0 corresponds to the verification status
// |kNoStatus|.
- if (!db_->DoesColumnExist("autofill_profile_names", column) &&
- !db_->Execute(
- base::StrCat({"ALTER TABLE autofill_profile_names ADD COLUMN ",
- column, " INTEGER DEFAULT 0"})
- .c_str())) {
+ if (!AddColumnIfNotExists(db_, kAutofillProfileNamesTable, column,
+ "INTEGER DEFAULT 0")) {
return false;
}
}
@@ -3367,78 +2803,58 @@ bool AutofillTable::MigrateToVersion88AddNewNameColumns() {
}
bool AutofillTable::MigrateToVersion92AddNewPrefixedNameColumn() {
- if (!db_->DoesColumnExist("autofill_profile_names",
- "full_name_with_honorific_prefix") &&
- !db_->Execute(
- base::StrCat({"ALTER TABLE autofill_profile_names ADD COLUMN ",
- "full_name_with_honorific_prefix", " VARCHAR"})
- .c_str())) {
- return false;
- }
- if (!db_->DoesColumnExist("autofill_profile_names",
- "full_name_with_honorific_prefix_status") &&
- !db_->Execute(
- base::StrCat({"ALTER TABLE autofill_profile_names ADD COLUMN ",
- "full_name_with_honorific_prefix_status",
- " INTEGER DEFAULT 0"})
- .c_str())) {
- return false;
- }
- return true;
+ return AddColumnIfNotExists(db_, kAutofillProfileNamesTable,
+ kFullNameWithHonorificPrefix, "VARCHAR") &&
+ AddColumnIfNotExists(db_, kAutofillProfileNamesTable,
+ kFullNameWithHonorificPrefixStatus,
+ "INTEGER DEFAULT 0");
}
bool AutofillTable::MigrateToVersion86RemoveUnmaskedCreditCardsUseColumns() {
// Sqlite does not support "alter table drop column" syntax, so it has be
// done manually.
+ constexpr base::StringPiece kUnmaskedCreditCardsTempTable =
+ "unmasked_credit_cards_temp";
sql::Transaction transaction(db_);
return transaction.Begin() &&
- db_->Execute(
- "CREATE TABLE unmasked_credit_cards_temp ("
- "id VARCHAR,"
- "card_number_encrypted VARCHAR,"
- "unmask_date INTEGER NOT NULL DEFAULT 0)") &&
+ CreateTable(db_, kUnmaskedCreditCardsTempTable,
+ {{kId, "VARCHAR"},
+ {kCardNumberEncrypted, "VARCHAR"},
+ {kUnmaskDate, "INTEGER NOT NULL DEFAULT 0"}}) &&
db_->Execute(
"INSERT INTO unmasked_credit_cards_temp "
"SELECT id, card_number_encrypted, unmask_date "
"FROM unmasked_credit_cards") &&
- db_->Execute("DROP TABLE unmasked_credit_cards") &&
- db_->Execute(
- "ALTER TABLE unmasked_credit_cards_temp "
- "RENAME TO unmasked_credit_cards") &&
+ DropTable(db_, kUnmaskedCreditCardsTable) &&
+ RenameTable(db_, kUnmaskedCreditCardsTempTable,
+ kUnmaskedCreditCardsTable) &&
transaction.Commit();
}
bool AutofillTable::MigrateToVersion87AddCreditCardNicknameColumn() {
// Add the nickname column to the credit_card table.
- return db_->DoesColumnExist("credit_cards", "nickname") ||
- db_->Execute("ALTER TABLE credit_cards ADD COLUMN nickname VARCHAR");
+ return AddColumnIfNotExists(db_, kCreditCardsTable, kNickname, "VARCHAR");
}
bool AutofillTable::MigrateToVersion90AddNewStructuredAddressColumns() {
if (!db_->DoesTableExist("autofill_profile_addresses"))
InitProfileAddressesTable();
- for (const char* column : {"dependent_locality", "city", "state", "zip_code",
- "sorting_code", "country_code"}) {
- if (!db_->DoesColumnExist("autofill_profile_addresses", column) &&
- !db_->Execute(
- base::StrCat({"ALTER TABLE autofill_profile_addresses ADD COLUMN ",
- column, " VARCHAR"})
- .c_str())) {
+ for (base::StringPiece column : {kDependentLocality, kCity, kState, kZipCode,
+ kSortingCode, kCountryCode}) {
+ if (!AddColumnIfNotExists(db_, kAutofillProfileAddressesTable, column,
+ "VARCHAR")) {
return false;
}
}
- for (const char* column :
- {"dependent_locality_status", "city_status", "state_status",
- "zip_code_status", "sorting_code_status", "country_code_status"}) {
+ for (base::StringPiece column :
+ {kDependentLocalityStatus, kCityStatus, kStateStatus, kZipCodeStatus,
+ kSortingCodeStatus, kCountryCodeStatus}) {
// The default value of 0 corresponds to the verification status
// |kNoStatus|.
- if (!db_->DoesColumnExist("autofill_profile_addresses", column) &&
- !db_->Execute(
- base::StrCat({"ALTER TABLE autofill_profile_addresses ADD COLUMN ",
- column, " INTEGER DEFAULT 0"})
- .c_str())) {
+ if (!AddColumnIfNotExists(db_, kAutofillProfileAddressesTable, column,
+ "INTEGER DEFAULT 0")) {
return false;
}
}
@@ -3446,27 +2862,21 @@ bool AutofillTable::MigrateToVersion90AddNewStructuredAddressColumns() {
}
bool AutofillTable::MigrateToVersion91AddMoreStructuredAddressColumns() {
- if (!db_->DoesTableExist("autofill_profile_addresses"))
+ if (!db_->DoesTableExist(kAutofillProfileAddressesTable))
InitProfileAddressesTable();
- for (const char* column : {"apartment_number", "floor"}) {
- if (!db_->DoesColumnExist("autofill_profile_addresses", column) &&
- !db_->Execute(
- base::StrCat({"ALTER TABLE autofill_profile_addresses ADD COLUMN ",
- column, " VARCHAR"})
- .c_str())) {
+ for (base::StringPiece column : {kApartmentNumber, kFloor}) {
+ if (!AddColumnIfNotExists(db_, kAutofillProfileAddressesTable, column,
+ "VARCHAR")) {
return false;
}
}
- for (const char* column : {"apartment_number_status", "floor_status"}) {
+ for (base::StringPiece column : {kApartmentNumberStatus, kFloorStatus}) {
// The default value of 0 corresponds to the verification status
// |kNoStatus|.
- if (!db_->DoesColumnExist("autofill_profile_addresses", column) &&
- !db_->Execute(
- base::StrCat({"ALTER TABLE autofill_profile_addresses ADD COLUMN ",
- column, " INTEGER DEFAULT 0"})
- .c_str())) {
+ if (!AddColumnIfNotExists(db_, kAutofillProfileAddressesTable, column,
+ "INTEGER DEFAULT 0")) {
return false;
}
}
@@ -3474,34 +2884,28 @@ bool AutofillTable::MigrateToVersion91AddMoreStructuredAddressColumns() {
}
bool AutofillTable::MigrateToVersion93AddAutofillProfileLabelColumn() {
- if (!db_->DoesTableExist("autofill_profiles"))
+ if (!db_->DoesTableExist(kAutofillProfilesTable))
InitProfileAddressesTable();
- return db_->DoesColumnExist("autofill_profiles", "label") ||
- db_->Execute("ALTER TABLE autofill_profiles ADD COLUMN label VARCHAR");
+ return AddColumnIfNotExists(db_, kAutofillProfilesTable, kLabel, "VARCHAR");
}
bool AutofillTable::
MigrateToVersion96AddAutofillProfileDisallowConfirmableMergesColumn() {
- if (!db_->DoesTableExist("autofill_profiles"))
+ if (!db_->DoesTableExist(kAutofillProfilesTable))
InitProfileAddressesTable();
- return db_->DoesColumnExist("autofill_profiles",
- "disallow_settings_visible_updates") ||
- db_->Execute(
- "ALTER TABLE autofill_profiles ADD COLUMN "
- "disallow_settings_visible_updates INTEGER NOT NULL DEFAULT 0");
+ return AddColumnIfNotExists(db_, kAutofillProfilesTable,
+ kDisallowSettingsVisibleUpdates,
+ "INTEGER NOT NULL DEFAULT 0");
}
bool AutofillTable::
MigrateToVersion89AddInstrumentIdColumnToMaskedCreditCard() {
// Add the new instrument_id column to the masked_credit_cards table and set
// the default value to 0.
- return db_->DoesColumnExist("masked_credit_cards", "instrument_id") ||
- db_->Execute(
- "ALTER TABLE masked_credit_cards "
- "ADD COLUMN instrument_id INTEGER "
- "DEFAULT 0");
+ return AddColumnIfNotExists(db_, kMaskedCreditCardsTable, kInstrumentId,
+ "INTEGER DEFAULT 0");
}
bool AutofillTable::MigrateToVersion94AddPromoCodeColumnsToOfferData() {
@@ -3509,17 +2913,14 @@ bool AutofillTable::MigrateToVersion94AddPromoCodeColumnsToOfferData() {
if (!transaction.Begin())
return false;
- if (!db_->DoesTableExist("offer_data"))
+ if (!db_->DoesTableExist(kOfferDataTable))
InitOfferDataTable();
// Add the new promo_code and DisplayStrings text columns to the offer_data
// table.
- for (const char* column : {"promo_code", "value_prop_text",
- "see_details_text", "usage_instructions_text"}) {
- if (!db_->DoesColumnExist("offer_data", column) &&
- !db_->Execute(base::StrCat({"ALTER TABLE offer_data ADD COLUMN ",
- column, " VARCHAR"})
- .c_str())) {
+ for (base::StringPiece column :
+ {kPromoCode, kValuePropText, kSeeDetailsText, kUsageInstructionsText}) {
+ if (!AddColumnIfNotExists(db_, kOfferDataTable, column, "VARCHAR")) {
return false;
}
}
@@ -3531,21 +2932,18 @@ bool AutofillTable::MigrateToVersion95AddVirtualCardMetadata() {
if (!transaction.Begin())
return false;
- if (!db_->DoesTableExist("masked_credit_cards"))
+ if (!db_->DoesTableExist(kMaskedCreditCardsTable))
InitMaskedCreditCardsTable();
// Add virtual_card_enrollment_state to masked_credit_cards.
- if (!db_->DoesColumnExist("masked_credit_cards",
- "virtual_card_enrollment_state") &&
- !db_->Execute("ALTER TABLE masked_credit_cards ADD COLUMN "
- "virtual_card_enrollment_state INTEGER DEFAULT 0")) {
+ if (!AddColumnIfNotExists(db_, kMaskedCreditCardsTable,
+ kVirtualCardEnrollmentState, "INTEGER DEFAULT 0")) {
return false;
}
// Add card_art_url to masked_credit_cards.
- if (!db_->DoesColumnExist("masked_credit_cards", "card_art_url") &&
- !db_->Execute("ALTER TABLE masked_credit_cards ADD COLUMN "
- "card_art_url VARCHAR")) {
+ if (!AddColumnIfNotExists(db_, kMaskedCreditCardsTable, kCardArtUrl,
+ "VARCHAR")) {
return false;
}
@@ -3555,39 +2953,38 @@ bool AutofillTable::MigrateToVersion95AddVirtualCardMetadata() {
bool AutofillTable::MigrateToVersion98RemoveStatusColumnMaskedCreditCards() {
// Sqlite does not support "alter table drop column" syntax, so it has be done
// manually.
+ constexpr base::StringPiece kMaskedCreditCardsTempTable =
+ "masked_credit_cards_temp";
sql::Transaction transaction(db_);
return transaction.Begin() &&
- db_->Execute(
- "CREATE TABLE masked_credit_cards_temp ("
- "id VARCHAR,"
- "name_on_card VARCHAR,"
- "network VARCHAR,"
- "last_four VARCHAR,"
- "exp_month INTEGER DEFAULT 0,"
- "exp_year INTEGER DEFAULT 0, "
- "bank_name VARCHAR, "
- "nickname VARCHAR, "
- "card_issuer INTEGER DEFAULT 0, "
- "instrument_id INTEGER DEFAULT 0, "
- "virtual_card_enrollment_state INTEGER DEFAULT 0, "
- "card_art_url VARCHAR)") &&
+ CreateTable(db_, kMaskedCreditCardsTempTable,
+ {{kId, "VARCHAR"},
+ {kNameOnCard, "VARCHAR"},
+ {kNetwork, "VARCHAR"},
+ {kLastFour, "VARCHAR"},
+ {kExpMonth, "INTEGER DEFAULT 0"},
+ {kExpYear, "INTEGER DEFAULT 0"},
+ {kBankName, "VARCHAR"},
+ {kNickname, "VARCHAR"},
+ {kCardIssuer, "INTEGER DEFAULT 0"},
+ {kInstrumentId, "INTEGER DEFAULT 0"},
+ {kVirtualCardEnrollmentState, "INTEGER DEFAULT 0"},
+ {kCardArtUrl, "VARCHAR"}}) &&
db_->Execute(
"INSERT INTO masked_credit_cards_temp "
"SELECT id, name_on_card, network, last_four, exp_month, "
"exp_year, bank_name, nickname, card_issuer, instrument_id, "
"virtual_card_enrollment_state, card_art_url "
"FROM masked_credit_cards") &&
- db_->Execute("DROP TABLE masked_credit_cards") &&
- db_->Execute(
- "ALTER TABLE masked_credit_cards_temp "
- "RENAME TO masked_credit_cards") &&
+ DropTable(db_, kMaskedCreditCardsTable) &&
+ RenameTable(db_, kMaskedCreditCardsTempTable,
+ kMaskedCreditCardsTable) &&
transaction.Commit();
}
bool AutofillTable::MigrateToVersion99RemoveAutofillProfilesTrashTable() {
sql::Transaction transaction(db_);
- return transaction.Begin() &&
- db_->Execute("DROP TABLE autofill_profiles_trash") &&
+ return transaction.Begin() && DropTable(db_, "autofill_profiles_trash") &&
transaction.Commit();
}
@@ -3597,24 +2994,24 @@ bool AutofillTable::MigrateToVersion100RemoveProfileValidityBitfieldColumn() {
sql::Transaction transaction(db_);
return transaction.Begin() &&
- db_->Execute(
- "CREATE TABLE autofill_profiles_tmp ( "
- "guid VARCHAR PRIMARY KEY, "
- "company_name VARCHAR, "
- "street_address VARCHAR, "
- "dependent_locality VARCHAR, "
- "city VARCHAR, "
- "state VARCHAR, "
- "zipcode VARCHAR, "
- "sorting_code VARCHAR, "
- "country_code VARCHAR, "
- "date_modified INTEGER NOT NULL DEFAULT 0, "
- "origin VARCHAR DEFAULT '', "
- "language_code VARCHAR, "
- "use_count INTEGER NOT NULL DEFAULT 0, "
- "use_date INTEGER NOT NULL DEFAULT 0, "
- "label VARCHAR, "
- "disallow_settings_visible_updates INTEGER NOT NULL DEFAULT 0)") &&
+ CreateTable(db_, "autofill_profiles_tmp",
+ {{kGuid, "VARCHAR PRIMARY KEY"},
+ {kCompanyName, "VARCHAR"},
+ {kStreetAddress, "VARCHAR"},
+ {kDependentLocality, "VARCHAR"},
+ {kCity, "VARCHAR"},
+ {kState, "VARCHAR"},
+ {kZipcode, "VARCHAR"},
+ {kSortingCode, "VARCHAR"},
+ {kCountryCode, "VARCHAR"},
+ {kDateModified, "INTEGER NOT NULL DEFAULT 0"},
+ {kOrigin, "VARCHAR DEFAULT ''"},
+ {kLanguageCode, "VARCHAR"},
+ {kUseCount, "INTEGER NOT NULL DEFAULT 0"},
+ {kUseDate, "INTEGER NOT NULL DEFAULT 0"},
+ {kLabel, "VARCHAR"},
+ {kDisallowSettingsVisibleUpdates,
+ "INTEGER NOT NULL DEFAULT 0"}}) &&
db_->Execute(
"INSERT INTO autofill_profiles_tmp "
"SELECT guid, company_name, street_address, dependent_locality, "
@@ -3622,10 +3019,8 @@ bool AutofillTable::MigrateToVersion100RemoveProfileValidityBitfieldColumn() {
"origin, language_code, use_count, use_date, label, "
"disallow_settings_visible_updates "
" FROM autofill_profiles") &&
- db_->Execute("DROP TABLE autofill_profiles") &&
- db_->Execute(
- "ALTER TABLE autofill_profiles_tmp "
- "RENAME TO autofill_profiles") &&
+ DropTable(db_, kAutofillProfilesTable) &&
+ RenameTable(db_, "autofill_profiles_tmp", kAutofillProfilesTable) &&
transaction.Commit();
}
@@ -3639,12 +3034,11 @@ bool AutofillTable::MigrateToVersion101RemoveCreditCardArtImageTable() {
bool AutofillTable::MigrateToVersion102AddAutofillBirthdatesTable() {
sql::Transaction transaction(db_);
return transaction.Begin() &&
- db_->Execute(
- "CREATE TABLE autofill_profile_birthdates ( "
- "guid VARCHAR, "
- "day INTEGER DEFAULT 0, "
- "month INTEGER DEFAULT 0, "
- "year INTEGER DEFAULT 0)") &&
+ CreateTable(db_, kAutofillProfileBirthdatesTable,
+ {{kGuid, "VARCHAR"},
+ {kDay, "INTEGER DEFAULT 0"},
+ {kMonth, "INTEGER DEFAULT 0"},
+ {kYear, "INTEGER DEFAULT 0"}}) &&
transaction.Commit();
}
@@ -3653,19 +3047,30 @@ bool AutofillTable::MigrateToVersion104AddProductDescriptionColumn() {
if (!transaction.Begin())
return false;
- if (!db_->DoesTableExist("masked_credit_cards"))
+ if (!db_->DoesTableExist(kMaskedCreditCardsTable))
InitMaskedCreditCardsTable();
// Add product_description to masked_credit_cards.
- if (!db_->DoesColumnExist("masked_credit_cards", "product_description") &&
- !db_->Execute("ALTER TABLE masked_credit_cards ADD COLUMN "
- "product_description VARCHAR")) {
+ if (!AddColumnIfNotExists(db_, kMaskedCreditCardsTable, kProductDescription,
+ "VARCHAR")) {
return false;
}
return transaction.Commit();
}
+bool AutofillTable::MigrateToVersion105AddAutofillIBANTable() {
+ sql::Transaction transaction(db_);
+ return transaction.Begin() &&
+ CreateTable(db_, kIBANsTable,
+ {{kGuid, "VARCHAR"},
+ {kUseCount, "INTEGER NOT NULL DEFAULT 0"},
+ {kUseDate, "INTEGER NOT NULL DEFAULT 0"},
+ {kValue, "VARCHAR"},
+ {kNickname, "VARCHAR"}}) &&
+ transaction.Commit();
+}
+
bool AutofillTable::AddFormFieldValuesTime(
const std::vector<FormFieldData>& elements,
std::vector<AutofillChange>* changes,
@@ -3709,10 +3114,10 @@ bool AutofillTable::AddFormFieldValueTime(const FormFieldData& element,
return false;
} else {
time_t time_as_time_t = time.ToTimeT();
- sql::Statement s(db_->GetUniqueStatement(
- "INSERT INTO autofill "
- "(name, value, value_lower, date_created, date_last_used, count) "
- "VALUES (?, ?, ?, ?, ?, ?)"));
+ sql::Statement s;
+ InsertBuilder(
+ db_, s, kAutofillTable,
+ {kName, kValue, kValueLower, kDateCreated, kDateLastUsed, kCount});
s.BindString16(0, element.name);
s.BindString16(1, element.value);
s.BindString16(2, base::i18n::ToLower(element.value));
@@ -3750,9 +3155,9 @@ bool AutofillTable::GetAllSyncEntityMetadata(
<< "Model type " << model_type << " not supported for metadata";
DCHECK(metadata_batch);
- sql::Statement s(
- db_->GetUniqueStatement("SELECT storage_key, value FROM "
- "autofill_sync_metadata WHERE model_type=?"));
+ sql::Statement s;
+ SelectBuilder(db_, s, kAutofillSyncMetadataTable, {kStorageKey, kValue},
+ "WHERE model_type=?");
s.BindInt(0, GetKeyValueForModelType(model_type));
while (s.Step()) {
@@ -3775,8 +3180,9 @@ bool AutofillTable::GetModelTypeState(syncer::ModelType model_type,
DCHECK(SupportsMetadataForModelType(model_type))
<< "Model type " << model_type << " not supported for metadata";
- sql::Statement s(db_->GetUniqueStatement(
- "SELECT value FROM autofill_model_type_state WHERE model_type=?"));
+ sql::Statement s;
+ SelectBuilder(db_, s, kAutofillModelTypeStateTable, {kValue},
+ "WHERE model_type=?");
s.BindInt(0, GetKeyValueForModelType(model_type));
if (!s.Step()) {
@@ -3788,11 +3194,10 @@ bool AutofillTable::GetModelTypeState(syncer::ModelType model_type,
}
bool AutofillTable::InsertAutofillEntry(const AutofillEntry& entry) {
- std::string sql =
- "INSERT INTO autofill "
- "(name, value, value_lower, date_created, date_last_used, count) "
- "VALUES (?, ?, ?, ?, ?, ?)";
- sql::Statement s(db_->GetUniqueStatement(sql.c_str()));
+ sql::Statement s;
+ InsertBuilder(
+ db_, s, kAutofillTable,
+ {kName, kValue, kValueLower, kDateCreated, kDateLastUsed, kCount});
s.BindString16(0, entry.key().name());
s.BindString16(1, entry.key().value());
s.BindString16(2, base::i18n::ToLower(entry.key().value()));
@@ -3809,22 +3214,13 @@ bool AutofillTable::InsertAutofillEntry(const AutofillEntry& entry) {
void AutofillTable::AddMaskedCreditCards(
const std::vector<CreditCard>& credit_cards) {
DCHECK_GT(db_->transaction_nesting(), 0);
- sql::Statement masked_insert(
- db_->GetUniqueStatement("INSERT INTO masked_credit_cards("
- "id," // 0
- "network," // 1
- "name_on_card," // 2
- "last_four," // 3
- "exp_month," // 4
- "exp_year," // 5
- "bank_name," // 6
- "nickname," // 7
- "card_issuer," // 8
- "instrument_id," // 9
- "virtual_card_enrollment_state, " // 10
- "card_art_url, " // 11
- "product_description )" // 12
- "VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?)"));
+ sql::Statement masked_insert;
+ InsertBuilder(
+ db_, masked_insert, kMaskedCreditCardsTable,
+ {kId, kNetwork, kNameOnCard, kLastFour, kExpMonth, kExpYear, kBankName,
+ kNickname, kCardIssuer, kInstrumentId, kVirtualCardEnrollmentState,
+ kCardArtUrl, kProductDescription});
+
int index;
for (const CreditCard& card : credit_cards) {
DCHECK_EQ(CreditCard::MASKED_SERVER_CARD, card.record_type());
@@ -3853,12 +3249,9 @@ void AutofillTable::AddMaskedCreditCards(
void AutofillTable::AddUnmaskedCreditCard(const std::string& id,
const std::u16string& full_number) {
- sql::Statement s(
- db_->GetUniqueStatement("INSERT INTO unmasked_credit_cards("
- "id,"
- "card_number_encrypted,"
- "unmask_date)"
- "VALUES (?,?,?)"));
+ sql::Statement s;
+ InsertBuilder(db_, s, kUnmaskedCreditCardsTable,
+ {kId, kCardNumberEncrypted, kUnmaskDate});
s.BindString(0, id);
std::string encrypted_data;
@@ -3870,394 +3263,271 @@ void AutofillTable::AddUnmaskedCreditCard(const std::string& id,
}
bool AutofillTable::DeleteFromMaskedCreditCards(const std::string& id) {
- sql::Statement s(
- db_->GetUniqueStatement("DELETE FROM masked_credit_cards WHERE id = ?"));
- s.BindString(0, id);
- s.Run();
+ DeleteWhereColumnEq(db_, kMaskedCreditCardsTable, kId, id);
return db_->GetLastChangeCount() > 0;
}
bool AutofillTable::DeleteFromUnmaskedCreditCards(const std::string& id) {
- sql::Statement s(db_->GetUniqueStatement(
- "DELETE FROM unmasked_credit_cards WHERE id = ?"));
- s.BindString(0, id);
- s.Run();
+ DeleteWhereColumnEq(db_, kUnmaskedCreditCardsTable, kId, id);
return db_->GetLastChangeCount() > 0;
}
bool AutofillTable::InitMainTable() {
- if (!db_->DoesTableExist("autofill")) {
- if (!db_->Execute("CREATE TABLE autofill ("
- "name VARCHAR, "
- "value VARCHAR, "
- "value_lower VARCHAR, "
- "date_created INTEGER DEFAULT 0, "
- "date_last_used INTEGER DEFAULT 0, "
- "count INTEGER DEFAULT 1, "
- "PRIMARY KEY (name, value))") ||
- !db_->Execute("CREATE INDEX autofill_name ON autofill (name)") ||
- !db_->Execute("CREATE INDEX autofill_name_value_lower ON "
- "autofill (name, value_lower)")) {
- NOTREACHED();
- return false;
- }
+ if (!db_->DoesTableExist(kAutofillTable)) {
+ return CreateTable(db_, kAutofillTable,
+ {{kName, "VARCHAR"},
+ {kValue, "VARCHAR"},
+ {kValueLower, "VARCHAR"},
+ {kDateCreated, "INTEGER DEFAULT 0"},
+ {kDateLastUsed, "INTEGER DEFAULT 0"},
+ {kCount, "INTEGER DEFAULT 1"}},
+ {kName, kValue}) &&
+ CreateIndex(db_, kAutofillTable, {kName}) &&
+ CreateIndex(db_, kAutofillTable, {kName, kValueLower});
}
return true;
}
bool AutofillTable::InitCreditCardsTable() {
- if (!db_->DoesTableExist("credit_cards")) {
- if (!db_->Execute("CREATE TABLE credit_cards ( "
- "guid VARCHAR PRIMARY KEY, "
- "name_on_card VARCHAR, "
- "expiration_month INTEGER, "
- "expiration_year INTEGER, "
- "card_number_encrypted BLOB, "
- "date_modified INTEGER NOT NULL DEFAULT 0, "
- "origin VARCHAR DEFAULT '', "
- "use_count INTEGER NOT NULL DEFAULT 0, "
- "use_date INTEGER NOT NULL DEFAULT 0, "
- "billing_address_id VARCHAR, "
- "nickname VARCHAR)")) {
- NOTREACHED();
- return false;
- }
- }
-
- return true;
+ return CreateTableIfNotExists(db_, kCreditCardsTable,
+ {{kGuid, "VARCHAR PRIMARY KEY"},
+ {kNameOnCard, "VARCHAR"},
+ {kExpirationMonth, "INTEGER"},
+ {kExpirationYear, "INTEGER"},
+ {kCardNumberEncrypted, "BLOB"},
+ {kDateModified, "INTEGER NOT NULL DEFAULT 0"},
+ {kOrigin, "VARCHAR DEFAULT ''"},
+ {kUseCount, "INTEGER NOT NULL DEFAULT 0"},
+ {kUseDate, "INTEGER NOT NULL DEFAULT 0"},
+ {kBillingAddressId, "VARCHAR"},
+ {kNickname, "VARCHAR"}});
+}
+
+bool AutofillTable::InitIBANsTable() {
+ return CreateTableIfNotExists(db_, kIBANsTable,
+ {{kGuid, "VARCHAR PRIMARY KEY"},
+ {kUseCount, "INTEGER NOT NULL DEFAULT 0"},
+ {kUseDate, "INTEGER NOT NULL DEFAULT 0"},
+ {kValue, "VARCHAR"},
+ {kNickname, "VARCHAR"}});
}
bool AutofillTable::InitProfilesTable() {
- if (!db_->DoesTableExist("autofill_profiles")) {
- if (!db_->Execute(
- "CREATE TABLE autofill_profiles ( "
- "guid VARCHAR PRIMARY KEY, "
- "company_name VARCHAR, "
- "street_address VARCHAR, "
- "dependent_locality VARCHAR, "
- "city VARCHAR, "
- "state VARCHAR, "
- "zipcode VARCHAR, "
- "sorting_code VARCHAR, "
- "country_code VARCHAR, "
- "date_modified INTEGER NOT NULL DEFAULT 0, "
- "origin VARCHAR DEFAULT '', "
- "language_code VARCHAR, "
- "use_count INTEGER NOT NULL DEFAULT 0, "
- "use_date INTEGER NOT NULL DEFAULT 0, "
- "label VARCHAR, "
- "disallow_settings_visible_updates INTEGER NOT NULL DEFAULT 0)")) {
- NOTREACHED();
- return false;
- }
- }
- return true;
+ return CreateTableIfNotExists(
+ db_, kAutofillProfilesTable,
+ {{kGuid, "VARCHAR PRIMARY KEY"},
+ {kCompanyName, "VARCHAR"},
+ {kStreetAddress, "VARCHAR"},
+ {kDependentLocality, "VARCHAR"},
+ {kCity, "VARCHAR"},
+ {kState, "VARCHAR"},
+ {kZipcode, "VARCHAR"},
+ {kSortingCode, "VARCHAR"},
+ {kCountryCode, "VARCHAR"},
+ {kDateModified, "INTEGER NOT NULL DEFAULT 0"},
+ {kOrigin, "VARCHAR DEFAULT ''"},
+ {kLanguageCode, "VARCHAR"},
+ {kUseCount, "INTEGER NOT NULL DEFAULT 0"},
+ {kUseDate, "INTEGER NOT NULL DEFAULT 0"},
+ {kLabel, "VARCHAR"},
+ {kDisallowSettingsVisibleUpdates, "INTEGER NOT NULL DEFAULT 0"}});
}
bool AutofillTable::InitProfileNamesTable() {
- if (!db_->DoesTableExist("autofill_profile_names")) {
- // The default value of 0 corresponds to the verification status
- // |kNoStatus|.
- if (!db_->Execute(
- "CREATE TABLE autofill_profile_names ( "
- "guid VARCHAR, "
- "first_name VARCHAR, "
- "middle_name VARCHAR, "
- "last_name VARCHAR, "
- "full_name VARCHAR, "
- "honorific_prefix VARCHAR, "
- "first_last_name VARCHAR, "
- "conjunction_last_name VARCHAR, "
- "second_last_name VARCHAR, "
- "honorific_prefix_status INTEGER DEFAULT 0, "
- "first_name_status INTEGER DEFAULT 0, "
- "middle_name_status INTEGER DEFAULT 0, "
- "last_name_status INTEGER DEFAULT 0, "
- "first_last_name_status INTEGER DEFAULT 0, "
- "conjunction_last_name_status INTEGER DEFAULT 0, "
- "second_last_name_status INTEGER DEFAULT 0, "
- "full_name_status INTEGER DEFAULT 0, "
- "full_name_with_honorific_prefix VARCHAR, "
- "full_name_with_honorific_prefix_status INTEGER DEFAULT 0)")) {
- NOTREACHED();
- return false;
- }
- }
- return true;
+ // The default value of 0 corresponds to the verification status
+ // |kNoStatus|.
+ return CreateTableIfNotExists(
+ db_, kAutofillProfileNamesTable,
+ {{kGuid, "VARCHAR"},
+ {kFirstName, "VARCHAR"},
+ {kMiddleName, "VARCHAR"},
+ {kLastName, "VARCHAR"},
+ {kFullName, "VARCHAR"},
+ {kHonorificPrefix, "VARCHAR"},
+ {kFirstLastName, "VARCHAR"},
+ {kConjunctionLastName, "VARCHAR"},
+ {kSecondLastName, "VARCHAR"},
+ {kHonorificPrefixStatus, "INTEGER DEFAULT 0"},
+ {kFirstNameStatus, "INTEGER DEFAULT 0"},
+ {kMiddleNameStatus, "INTEGER DEFAULT 0"},
+ {kLastNameStatus, "INTEGER DEFAULT 0"},
+ {kFirstLastNameStatus, "INTEGER DEFAULT 0"},
+ {kConjunctionLastNameStatus, "INTEGER DEFAULT 0"},
+ {kSecondLastNameStatus, "INTEGER DEFAULT 0"},
+ {kFullNameStatus, "INTEGER DEFAULT 0"},
+ {kFullNameWithHonorificPrefix, "VARCHAR"},
+ {kFullNameWithHonorificPrefixStatus, "INTEGER DEFAULT 0"}});
}
bool AutofillTable::InitProfileAddressesTable() {
- if (!db_->DoesTableExist("autofill_profile_addresses")) {
- // The default value of 0 corresponds to the verification status
- // |kNoStatus|.
- if (!db_->Execute("CREATE TABLE autofill_profile_addresses ( "
- "guid VARCHAR, "
- "street_address VARCHAR, "
- "street_name VARCHAR, "
- "dependent_street_name VARCHAR, "
- "house_number VARCHAR, "
- "subpremise VARCHAR, "
- "premise_name VARCHAR, "
- "street_address_status INTEGER DEFAULT 0, "
- "street_name_status INTEGER DEFAULT 0, "
- "dependent_street_name_status INTEGER DEFAULT 0, "
- "house_number_status INTEGER DEFAULT 0, "
- "subpremise_status INTEGER DEFAULT 0, "
- "premise_name_status INTEGER DEFAULT 0, "
- "dependent_locality VARCHAR, "
- "city VARCHAR, "
- "state VARCHAR, "
- "zip_code VARCHAR, "
- "sorting_code VARCHAR, "
- "country_code VARCHAR, "
- "dependent_locality_status INTEGER DEFAULT 0, "
- "city_status INTEGER DEFAULT 0, "
- "state_status INTEGER DEFAULT 0, "
- "zip_code_status INTEGER DEFAULT 0, "
- "sorting_code_status INTEGER DEFAULT 0, "
- "country_code_status INTEGER DEFAULT 0, "
- "apartment_number VARCHAR, "
- "floor VARCHAR, "
- "apartment_number_status INTEGER DEFAULT 0, "
- "floor_status INTEGER DEFAULT 0)")) {
- NOTREACHED();
- return false;
- }
- }
- return true;
+ // The default value of 0 corresponds to the verification status
+ // |kNoStatus|.
+ return CreateTableIfNotExists(
+ db_, kAutofillProfileAddressesTable,
+ {{kGuid, "VARCHAR"},
+ {kStreetAddress, "VARCHAR"},
+ {kStreetName, "VARCHAR"},
+ {kDependentStreetName, "VARCHAR"},
+ {kHouseNumber, "VARCHAR"},
+ {kSubpremise, "VARCHAR"},
+ {kPremiseName, "VARCHAR"},
+ {kStreetAddressStatus, "INTEGER DEFAULT 0"},
+ {kStreetNameStatus, "INTEGER DEFAULT 0"},
+ {kDependentStreetNameStatus, "INTEGER DEFAULT 0"},
+ {kHouseNumberStatus, "INTEGER DEFAULT 0"},
+ {kSubpremiseStatus, "INTEGER DEFAULT 0"},
+ {kPremiseNameStatus, "INTEGER DEFAULT 0"},
+ {kDependentLocality, "VARCHAR"},
+ {kCity, "VARCHAR"},
+ {kState, "VARCHAR"},
+ {kZipCode, "VARCHAR"},
+ {kSortingCode, "VARCHAR"},
+ {kCountryCode, "VARCHAR"},
+ {kDependentLocalityStatus, "INTEGER DEFAULT 0"},
+ {kCityStatus, "INTEGER DEFAULT 0"},
+ {kStateStatus, "INTEGER DEFAULT 0"},
+ {kZipCodeStatus, "INTEGER DEFAULT 0"},
+ {kSortingCodeStatus, "INTEGER DEFAULT 0"},
+ {kCountryCodeStatus, "INTEGER DEFAULT 0"},
+ {kApartmentNumber, "VARCHAR"},
+ {kFloor, "VARCHAR"},
+ {kApartmentNumberStatus, "INTEGER DEFAULT 0"},
+ {kFloorStatus, "INTEGER DEFAULT 0"}});
}
bool AutofillTable::InitProfileEmailsTable() {
- if (!db_->DoesTableExist("autofill_profile_emails")) {
- if (!db_->Execute("CREATE TABLE autofill_profile_emails ( "
- "guid VARCHAR, "
- "email VARCHAR)")) {
- NOTREACHED();
- return false;
- }
- }
- return true;
+ return CreateTableIfNotExists(db_, kAutofillProfileEmailsTable,
+ {{kGuid, "VARCHAR"}, {kEmail, "VARCHAR"}});
}
bool AutofillTable::InitProfilePhonesTable() {
- if (!db_->DoesTableExist("autofill_profile_phones")) {
- if (!db_->Execute("CREATE TABLE autofill_profile_phones ( "
- "guid VARCHAR, "
- "number VARCHAR)")) {
- NOTREACHED();
- return false;
- }
- }
- return true;
+ return CreateTableIfNotExists(db_, kAutofillProfilePhonesTable,
+ {{kGuid, "VARCHAR"}, {kNumber, "VARCHAR"}});
}
bool AutofillTable::InitProfileBirthdatesTable() {
- if (!db_->DoesTableExist("autofill_profile_birthdates")) {
- if (!db_->Execute("CREATE TABLE autofill_profile_birthdates ( "
- "guid VARCHAR, "
- "day INTEGER DEFAULT 0, "
- "month INTEGER DEFAULT 0, "
- "year INTEGER DEFAULT 0)")) {
- NOTREACHED();
- return false;
- }
- }
- return true;
+ return CreateTableIfNotExists(db_, kAutofillProfileBirthdatesTable,
+ {{kGuid, "VARCHAR"},
+ {kDay, "INTEGER DEFAULT 0"},
+ {kMonth, "INTEGER DEFAULT 0"},
+ {kYear, "INTEGER DEFAULT 0"}});
}
bool AutofillTable::InitMaskedCreditCardsTable() {
- if (!db_->DoesTableExist("masked_credit_cards")) {
- if (!db_->Execute("CREATE TABLE masked_credit_cards ("
- "id VARCHAR,"
- "name_on_card VARCHAR,"
- "network VARCHAR,"
- "last_four VARCHAR,"
- "exp_month INTEGER DEFAULT 0,"
- "exp_year INTEGER DEFAULT 0, "
- "bank_name VARCHAR, "
- "nickname VARCHAR, "
- "card_issuer INTEGER DEFAULT 0, "
- "instrument_id INTEGER DEFAULT 0, "
- "virtual_card_enrollment_state INTEGER DEFAULT 0, "
- "card_art_url VARCHAR, "
- "product_description VARCHAR)")) {
- NOTREACHED();
- return false;
- }
- }
- return true;
+ return CreateTableIfNotExists(
+ db_, kMaskedCreditCardsTable,
+ {{kId, "VARCHAR"},
+ {kNameOnCard, "VARCHAR"},
+ {kNetwork, "VARCHAR"},
+ {kLastFour, "VARCHAR"},
+ {kExpMonth, "INTEGER DEFAULT 0"},
+ {kExpYear, "INTEGER DEFAULT 0"},
+ {kBankName, "VARCHAR"},
+ {kNickname, "VARCHAR"},
+ {kCardIssuer, "INTEGER DEFAULT 0"},
+ {kInstrumentId, "INTEGER DEFAULT 0"},
+ {kVirtualCardEnrollmentState, "INTEGER DEFAULT 0"},
+ {kCardArtUrl, "VARCHAR"},
+ {kProductDescription, "VARCHAR"}});
}
bool AutofillTable::InitUnmaskedCreditCardsTable() {
- if (!db_->DoesTableExist("unmasked_credit_cards")) {
- if (!db_->Execute("CREATE TABLE unmasked_credit_cards ("
- "id VARCHAR,"
- "card_number_encrypted VARCHAR,"
- "unmask_date INTEGER NOT NULL DEFAULT 0)")) {
- NOTREACHED();
- return false;
- }
- }
- return true;
+ return CreateTableIfNotExists(db_, kUnmaskedCreditCardsTable,
+ {{kId, "VARCHAR"},
+ {kCardNumberEncrypted, "VARCHAR"},
+ {kUnmaskDate, "INTEGER NOT NULL DEFAULT 0"}});
}
bool AutofillTable::InitServerCardMetadataTable() {
- if (!db_->DoesTableExist("server_card_metadata")) {
- if (!db_->Execute("CREATE TABLE server_card_metadata ("
- "id VARCHAR NOT NULL,"
- "use_count INTEGER NOT NULL DEFAULT 0, "
- "use_date INTEGER NOT NULL DEFAULT 0, "
- "billing_address_id VARCHAR)")) {
- NOTREACHED();
- return false;
- }
- }
- return true;
+ return CreateTableIfNotExists(db_, kServerCardMetadataTable,
+ {{kId, "VARCHAR NOT NULL"},
+ {kUseCount, "INTEGER NOT NULL DEFAULT 0"},
+ {kUseDate, "INTEGER NOT NULL DEFAULT 0"},
+ {kBillingAddressId, "VARCHAR"}});
}
bool AutofillTable::InitServerAddressesTable() {
- if (!db_->DoesTableExist("server_addresses")) {
- // The space after language_code is necessary to match what sqlite does
- // when it appends the column in migration.
- if (!db_->Execute("CREATE TABLE server_addresses ("
- "id VARCHAR,"
- "company_name VARCHAR,"
- "street_address VARCHAR,"
- "address_1 VARCHAR,"
- "address_2 VARCHAR,"
- "address_3 VARCHAR,"
- "address_4 VARCHAR,"
- "postal_code VARCHAR,"
- "sorting_code VARCHAR,"
- "country_code VARCHAR,"
- "language_code VARCHAR, " // Space required.
- "recipient_name VARCHAR, " // Ditto.
- "phone_number VARCHAR)")) {
- NOTREACHED();
- return false;
- }
- }
- return true;
+ return CreateTableIfNotExists(db_, kServerAddressesTable,
+ {{kId, "VARCHAR"},
+ {kCompanyName, "VARCHAR"},
+ {kStreetAddress, "VARCHAR"},
+ {kAddress1, "VARCHAR"},
+ {kAddress2, "VARCHAR"},
+ {kAddress3, "VARCHAR"},
+ {kAddress4, "VARCHAR"},
+ {kPostalCode, "VARCHAR"},
+ {kSortingCode, "VARCHAR"},
+ {kCountryCode, "VARCHAR"},
+ {kLanguageCode, "VARCHAR"},
+ {kRecipientName, "VARCHAR"},
+ {kPhoneNumber, "VARCHAR"}});
}
bool AutofillTable::InitServerAddressMetadataTable() {
- if (!db_->DoesTableExist("server_address_metadata")) {
- if (!db_->Execute("CREATE TABLE server_address_metadata ("
- "id VARCHAR NOT NULL,"
- "use_count INTEGER NOT NULL DEFAULT 0, "
- "use_date INTEGER NOT NULL DEFAULT 0, "
- "has_converted BOOL NOT NULL DEFAULT FALSE)")) {
- NOTREACHED();
- return false;
- }
- }
- return true;
+ return CreateTableIfNotExists(
+ db_, kServerAddressMetadataTable,
+ {{kId, "VARCHAR NOT NULL"},
+ {kUseCount, "INTEGER NOT NULL DEFAULT 0"},
+ {kUseDate, "INTEGER NOT NULL DEFAULT 0"},
+ {kHasConverted, "BOOL NOT NULL DEFAULT FALSE"}});
}
bool AutofillTable::InitAutofillSyncMetadataTable() {
- if (!db_->DoesTableExist("autofill_sync_metadata")) {
- if (!db_->Execute("CREATE TABLE autofill_sync_metadata ("
- "model_type INTEGER NOT NULL, "
- "storage_key VARCHAR NOT NULL, "
- "value BLOB, "
- "PRIMARY KEY (model_type, storage_key))")) {
- NOTREACHED();
- return false;
- }
- }
- return true;
+ return CreateTableIfNotExists(db_, kAutofillSyncMetadataTable,
+ {{kModelType, "INTEGER NOT NULL"},
+ {kStorageKey, "VARCHAR NOT NULL"},
+ {kValue, "BLOB"}},
+ {kModelType, kStorageKey});
}
bool AutofillTable::InitModelTypeStateTable() {
- if (!db_->DoesTableExist("autofill_model_type_state")) {
- if (!db_->Execute("CREATE TABLE autofill_model_type_state ("
- "model_type INTEGER NOT NULL PRIMARY KEY, value BLOB)")) {
- NOTREACHED();
- return false;
- }
- }
- return true;
+ return CreateTableIfNotExists(
+ db_, kAutofillModelTypeStateTable,
+ {{kModelType, "INTEGER NOT NULL PRIMARY KEY"}, {kValue, "BLOB"}});
}
bool AutofillTable::InitPaymentsCustomerDataTable() {
- if (!db_->DoesTableExist("payments_customer_data")) {
- if (!db_->Execute("CREATE TABLE payments_customer_data "
- "(customer_id VARCHAR)")) {
- NOTREACHED();
- return false;
- }
- }
- return true;
+ return CreateTableIfNotExists(db_, kPaymentsCustomerDataTable,
+ {{kCustomerId, "VARCHAR"}});
}
bool AutofillTable::InitPaymentsUPIVPATable() {
- if (!db_->DoesTableExist("payments_upi_vpa")) {
- if (!db_->Execute("CREATE TABLE payments_upi_vpa ("
- "vpa VARCHAR)")) {
- NOTREACHED();
- return false;
- }
- }
- return true;
+ return CreateTableIfNotExists(db_, kPaymentsUpiVpaTable, {{kVpa, "VARCHAR"}});
}
bool AutofillTable::InitServerCreditCardCloudTokenDataTable() {
- if (!db_->DoesTableExist("server_card_cloud_token_data")) {
- if (!db_->Execute("CREATE TABLE server_card_cloud_token_data ( "
- "id VARCHAR, "
- "suffix VARCHAR, "
- "exp_month INTEGER DEFAULT 0, "
- "exp_year INTEGER DEFAULT 0, "
- "card_art_url VARCHAR, "
- "instrument_token VARCHAR)")) {
- NOTREACHED();
- return false;
- }
- }
- return true;
+ return CreateTableIfNotExists(db_, kServerCardCloudTokenDataTable,
+ {{kId, "VARCHAR"},
+ {kSuffix, "VARCHAR"},
+ {kExpMonth, "INTEGER DEFAULT 0"},
+ {kExpYear, "INTEGER DEFAULT 0"},
+ {kCardArtUrl, "VARCHAR"},
+ {kInstrumentToken, "VARCHAR"}});
}
bool AutofillTable::InitOfferDataTable() {
- if (!db_->DoesTableExist("offer_data")) {
- if (!db_->Execute("CREATE TABLE offer_data ( "
- "offer_id UNSIGNED LONG, "
- "offer_reward_amount VARCHAR, "
- "expiry UNSIGNED LONG, "
- "offer_details_url VARCHAR, "
- "merchant_domain VARCHAR, "
- "promo_code VARCHAR, "
- "value_prop_text VARCHAR, "
- "see_details_text VARCHAR, "
- "usage_instructions_text VARCHAR)")) {
- NOTREACHED();
- return false;
- }
- }
- return true;
+ return CreateTableIfNotExists(db_, kOfferDataTable,
+ {{kOfferId, "UNSIGNED LONG"},
+ {kOfferRewardAmount, "VARCHAR"},
+ {kExpiry, "UNSIGNED LONG"},
+ {kOfferDetailsUrl, "VARCHAR"},
+ {kMerchantDomain, "VARCHAR"},
+ {kPromoCode, "VARCHAR"},
+ {kValuePropText, "VARCHAR"},
+ {kSeeDetailsText, "VARCHAR"},
+ {kUsageInstructionsText, "VARCHAR"}});
}
bool AutofillTable::InitOfferEligibleInstrumentTable() {
- if (!db_->DoesTableExist("offer_eligible_instrument")) {
- if (!db_->Execute("CREATE TABLE offer_eligible_instrument ( "
- "offer_id UNSIGNED LONG,"
- "instrument_id UNSIGNED LONG)")) {
- NOTREACHED();
- return false;
- }
- }
- return true;
+ return CreateTableIfNotExists(
+ db_, kOfferEligibleInstrumentTable,
+ {{kOfferId, "UNSIGNED LONG"}, {kInstrumentId, "UNSIGNED LONG"}});
}
bool AutofillTable::InitOfferMerchantDomainTable() {
- if (!db_->DoesTableExist("offer_merchant_domain")) {
- if (!db_->Execute("CREATE TABLE offer_merchant_domain ( "
- "offer_id UNSIGNED LONG,"
- "merchant_domain VARCHAR)")) {
- NOTREACHED();
- return false;
- }
- }
- return true;
+ return CreateTableIfNotExists(
+ db_, kOfferMerchantDomainTable,
+ {{kOfferId, "UNSIGNED LONG"}, {kMerchantDomain, "VARCHAR"}});
}
} // namespace autofill
diff --git a/chromium/components/autofill/core/browser/webdata/autofill_table.h b/chromium/components/autofill/core/browser/webdata/autofill_table.h
index 351bc47b789..dbc504ef185 100644
--- a/chromium/components/autofill/core/browser/webdata/autofill_table.h
+++ b/chromium/components/autofill/core/browser/webdata/autofill_table.h
@@ -39,6 +39,7 @@ class AutofillTableTest;
class CreditCard;
struct CreditCardCloudTokenData;
struct FormFieldData;
+class IBAN;
struct PaymentsCustomerData;
// This class manages the various Autofill tables within the SQLite database
@@ -180,6 +181,7 @@ struct PaymentsCustomerData;
// first_last_name_status
// conjunction_last_name_status
// second_last_name_status
+// full_name_status
// full_name_with_honorific_prefix_status
// Each token of the names has an additional validation
// status that indicates if Autofill parsed the value out
@@ -322,6 +324,19 @@ struct PaymentsCustomerData;
// database, but always returned as an empty string in
// CreditCard. Added in version 71.
//
+// ibans This table contains International Bank Account
+// Number(IBAN) data added by the user. The columns are
+// standard entries in an Iban form.
+//
+// guid A guid string to uniquely identify the IBAN.
+// use_count The number of times this IBAN has been used to fill
+// a form.
+// use_date The date this IBAN was last used to fill a form,
+// in time_t.
+// value Actual value of the IBAN (the bank account number).
+// nickname A nickname for the IBAN, entered by the user.
+//
+//
// server_addresses This table contains Autofill address data synced from
// the wallet server. It's basically the same as the
// autofill_profiles table but locally immutable.
@@ -390,7 +405,7 @@ struct PaymentsCustomerData;
// payments_upi_vpa Contains saved UPI/VPA payment data.
// https://en.wikipedia.org/wiki/Unified_Payments_Interface
//
-// vpa_id A string representing the UPI ID (a.k.a. VPA) value.
+// vpa A string representing the UPI ID (a.k.a. VPA) value.
//
// offer_data The data for Autofill offers which will be presented in
// payments autofill flows.
@@ -532,6 +547,22 @@ class AutofillTable : public WebDatabaseTable,
// the given ones.
void SetServerProfiles(const std::vector<AutofillProfile>& profiles);
+ // Records a single IBAN in the iban table.
+ bool AddIBAN(const IBAN& iban);
+
+ // Updates the database values for the specified IBAN.
+ bool UpdateIBAN(const IBAN& iban);
+
+ // Removes a row from the ibans table. |guid| is the identifier of the
+ // IBAN to remove.
+ bool RemoveIBAN(const std::string& guid);
+
+ // Retrieves an IBAN with the given |guid|.
+ std::unique_ptr<IBAN> GetIBAN(const std::string& guid);
+
+ // Retrieves the local IBANs in the database.
+ bool GetIBANs(std::vector<std::unique_ptr<IBAN>>* ibans);
+
// Records a single credit card in the credit_cards table.
bool AddCreditCard(const CreditCard& credit_card);
@@ -679,27 +710,6 @@ class AutofillTable : public WebDatabaseTable,
// functions in this class. The implementation of a function such as
// GetCreditCard may change over time, but MigrateToVersionXX should never
// change.
- bool MigrateToVersion54AddI18nFieldsAndRemoveDeprecatedFields();
- bool MigrateToVersion55MergeAutofillDatesTable();
- bool MigrateToVersion56AddProfileLanguageCodeForFormatting();
- bool MigrateToVersion57AddFullNameField();
- bool MigrateToVersion60AddServerCards();
- bool MigrateToVersion61AddUsageStats();
- bool MigrateToVersion62AddUsageStatsForUnmaskedCards();
- bool MigrateToVersion63AddServerRecipientName();
- bool MigrateToVersion64AddUnmaskDate();
- bool MigrateToVersion65AddServerMetadataTables();
- bool MigrateToVersion66AddCardBillingAddress();
- bool MigrateToVersion67AddMaskedCardBillingAddress();
- bool MigrateToVersion70AddSyncMetadata();
- bool MigrateToVersion71AddHasConvertedAndBillingAddressIdMetadata();
- bool MigrateToVersion72RenameCardTypeToIssuerNetwork();
- bool MigrateToVersion73AddMaskedCardBankName();
- bool MigrateToVersion74AddServerCardTypeColumn();
- bool MigrateToVersion75AddProfileValidityBitfieldColumn();
- bool MigrateToVersion78AddModelTypeColumns();
- bool MigrateToVersion80AddIsClientValidityStatesUpdatedColumn();
- bool MigrateToVersion81CleanUpWrongModelTypeData();
bool MigrateToVersion83RemoveServerCardTypeColumn();
bool MigrateToVersion84AddNicknameColumn();
bool MigrateToVersion85AddCardIssuerColumnToMaskedCreditCard();
@@ -720,6 +730,7 @@ class AutofillTable : public WebDatabaseTable,
bool MigrateToVersion101RemoveCreditCardArtImageTable();
bool MigrateToVersion102AddAutofillBirthdatesTable();
bool MigrateToVersion104AddProductDescriptionColumn();
+ bool MigrateToVersion105AddAutofillIBANTable();
// Max data length saved in the table, AKA the maximum length allowed for
// form data.
@@ -805,8 +816,15 @@ class AutofillTable : public WebDatabaseTable,
bool DeleteFromMaskedCreditCards(const std::string& id);
bool DeleteFromUnmaskedCreditCards(const std::string& id);
+ // Helper function extracting common code between `SetServerProfiles()` and
+ // `SetServerAddressData()`.
+ void SetServerProfilesAndMetadata(
+ const std::vector<AutofillProfile>& profiles,
+ bool update_metadata);
+
bool InitMainTable();
bool InitCreditCardsTable();
+ bool InitIBANsTable();
bool InitProfilesTable();
bool InitProfileAddressesTable();
bool InitProfileNamesTable();
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 48029c5ab8e..9d8f77d6dfe 100644
--- a/chromium/components/autofill/core/browser/webdata/autofill_table_unittest.cc
+++ b/chromium/components/autofill/core/browser/webdata/autofill_table_unittest.cc
@@ -1230,8 +1230,7 @@ TEST_F(AutofillTableTest,
TEST_F(AutofillTableTest, AutofillProfile_StructuredNames) {
// Enable the structured names and birthdates.
scoped_feature_list_.InitWithFeatures(
- {features::kAutofillEnableSupportForMoreStructureInNames,
- features::kAutofillEnableCompatibilitySupportForBirthdates},
+ {features::kAutofillEnableSupportForMoreStructureInNames},
{features::kAutofillEnableSupportForMoreStructureInAddresses});
AutofillProfile home_profile;
@@ -1283,7 +1282,7 @@ TEST_F(AutofillTableTest, AutofillProfile_StructuredNames) {
home_profile.SetRawInfo(PHONE_HOME_WHOLE_NUMBER, u"18181234567");
home_profile.SetRawInfoAsInt(BIRTHDATE_DAY, 14);
home_profile.SetRawInfoAsInt(BIRTHDATE_MONTH, 3);
- home_profile.SetRawInfoAsInt(BIRTHDATE_YEAR_4_DIGITS, 1997);
+ home_profile.SetRawInfoAsInt(BIRTHDATE_4_DIGIT_YEAR, 1997);
home_profile.set_disallow_settings_visible_updates(true);
home_profile.set_language_code("en");
Time pre_creation_time = AutofillClock::Now();
@@ -1380,7 +1379,7 @@ TEST_F(AutofillTableTest, AutofillProfile_StructuredNames) {
billing_profile.SetRawInfo(PHONE_HOME_WHOLE_NUMBER, u"18181230000");
billing_profile.SetRawInfoAsInt(BIRTHDATE_DAY, 4);
billing_profile.SetRawInfoAsInt(BIRTHDATE_MONTH, 5);
- billing_profile.SetRawInfoAsInt(BIRTHDATE_YEAR_4_DIGITS, 1977);
+ billing_profile.SetRawInfoAsInt(BIRTHDATE_4_DIGIT_YEAR, 1977);
Time pre_modification_time_2 = AutofillClock::Now();
EXPECT_TRUE(table_->UpdateAutofillProfile(billing_profile));
@@ -1412,9 +1411,8 @@ TEST_F(AutofillTableTest, AutofillProfile) {
// Disable the structured names since this test is only applicable if
// structured names are not used.
scoped_feature_list_.InitWithFeatures(
- {features::kAutofillEnableCompatibilitySupportForBirthdates},
- {features::kAutofillEnableSupportForMoreStructureInAddresses,
- features::kAutofillEnableSupportForMoreStructureInNames});
+ {}, {features::kAutofillEnableSupportForMoreStructureInAddresses,
+ features::kAutofillEnableSupportForMoreStructureInNames});
// Add a 'Home' profile with non-default data. The specific values are not
// important.
@@ -1436,7 +1434,7 @@ TEST_F(AutofillTableTest, AutofillProfile) {
home_profile.SetRawInfo(PHONE_HOME_WHOLE_NUMBER, u"18181234567");
home_profile.SetRawInfoAsInt(BIRTHDATE_DAY, 14);
home_profile.SetRawInfoAsInt(BIRTHDATE_MONTH, 3);
- home_profile.SetRawInfoAsInt(BIRTHDATE_YEAR_4_DIGITS, 1997);
+ home_profile.SetRawInfoAsInt(BIRTHDATE_4_DIGIT_YEAR, 1997);
home_profile.set_language_code("en");
Time pre_creation_time = AutofillClock::Now();
@@ -1518,7 +1516,7 @@ TEST_F(AutofillTableTest, AutofillProfile) {
billing_profile.SetRawInfo(PHONE_HOME_WHOLE_NUMBER, u"18181230000");
billing_profile.SetRawInfoAsInt(BIRTHDATE_DAY, 4);
billing_profile.SetRawInfoAsInt(BIRTHDATE_MONTH, 5);
- billing_profile.SetRawInfoAsInt(BIRTHDATE_YEAR_4_DIGITS, 1977);
+ billing_profile.SetRawInfoAsInt(BIRTHDATE_4_DIGIT_YEAR, 1977);
Time pre_modification_time_2 = AutofillClock::Now();
EXPECT_TRUE(table_->UpdateAutofillProfile(billing_profile));
@@ -1544,6 +1542,71 @@ TEST_F(AutofillTableTest, AutofillProfile) {
EXPECT_FALSE(db_profile);
}
+TEST_F(AutofillTableTest, IBAN) {
+ // Add a valid IBAN.
+ IBAN iban;
+ std::string guid = base::GenerateGUID();
+ iban.set_guid(guid);
+ iban.SetRawInfo(IBAN_VALUE, u"IE12 BOFI 9000 0112 3456 78");
+ iban.set_nickname(u"My doctor's IBAN");
+
+ EXPECT_TRUE(table_->AddIBAN(iban));
+
+ // Get the inserted Iban.
+ std::unique_ptr<IBAN> db_iban = table_->GetIBAN(iban.guid());
+ ASSERT_TRUE(db_iban);
+ EXPECT_EQ(guid, db_iban->guid());
+ sql::Statement s_work(db_->GetSQLConnection()->GetUniqueStatement(
+ "SELECT guid, use_count, use_date, "
+ "value, nickname FROM ibans WHERE guid = ?"));
+ s_work.BindString(0, iban.guid());
+ ASSERT_TRUE(s_work.is_valid());
+ ASSERT_TRUE(s_work.Step());
+ EXPECT_FALSE(s_work.Step());
+
+ // Add another valid IBAN.
+ IBAN another_iban;
+ std::string another_guid = base::GenerateGUID();
+ another_iban.set_guid(another_guid);
+ another_iban.SetRawInfo(IBAN_VALUE, u"DE91 1000 0000 0123 4567 89");
+ another_iban.set_nickname(u"My brother's IBAN");
+
+ EXPECT_TRUE(table_->AddIBAN(another_iban));
+
+ db_iban = table_->GetIBAN(another_iban.guid());
+ ASSERT_TRUE(db_iban);
+
+ EXPECT_EQ(another_guid, db_iban->guid());
+ sql::Statement s_target(db_->GetSQLConnection()->GetUniqueStatement(
+ "SELECT guid, use_count, use_date, "
+ "value, nickname FROM ibans WHERE guid = ?"));
+ s_target.BindString(0, another_iban.guid());
+ ASSERT_TRUE(s_target.is_valid());
+ ASSERT_TRUE(s_target.Step());
+ EXPECT_FALSE(s_target.Step());
+
+ // Update the another_iban.
+ another_iban.set_origin("Interactive Autofill dialog");
+ another_iban.SetRawInfo(IBAN_VALUE, u"GB98 MIDL 0700 9312 3456 78");
+ another_iban.set_nickname(u"My teacher's IBAN");
+ EXPECT_TRUE(table_->UpdateIBAN(another_iban));
+ db_iban = table_->GetIBAN(another_iban.guid());
+ ASSERT_TRUE(db_iban);
+ EXPECT_EQ(another_guid, db_iban->guid());
+ sql::Statement s_target_updated(db_->GetSQLConnection()->GetUniqueStatement(
+ "SELECT guid, use_count, use_date, "
+ "value, nickname FROM ibans WHERE guid = ?"));
+ s_target_updated.BindString(0, another_iban.guid());
+ ASSERT_TRUE(s_target_updated.is_valid());
+ ASSERT_TRUE(s_target_updated.Step());
+ EXPECT_FALSE(s_target_updated.Step());
+
+ // Remove the 'Target' IBAN.
+ EXPECT_TRUE(table_->RemoveIBAN(another_iban.guid()));
+ db_iban = table_->GetIBAN(another_iban.guid());
+ EXPECT_FALSE(db_iban);
+}
+
TEST_F(AutofillTableTest, CreditCard) {
// Add a 'Work' credit card.
CreditCard work_creditcard;
@@ -1646,9 +1709,6 @@ TEST_F(AutofillTableTest, AddFullServerCreditCard) {
}
TEST_F(AutofillTableTest, UpdateAutofillProfile) {
- scoped_feature_list_.InitWithFeatures(
- {features::kAutofillEnableCompatibilitySupportForBirthdates}, {});
-
// Add a profile to the db.
AutofillProfile profile;
profile.SetRawInfo(NAME_FIRST, u"John");
@@ -1665,7 +1725,7 @@ TEST_F(AutofillTableTest, UpdateAutofillProfile) {
profile.SetRawInfo(PHONE_HOME_WHOLE_NUMBER, u"18181234567");
profile.SetRawInfoAsInt(BIRTHDATE_DAY, 14);
profile.SetRawInfoAsInt(BIRTHDATE_MONTH, 3);
- profile.SetRawInfoAsInt(BIRTHDATE_YEAR_4_DIGITS, 1997);
+ profile.SetRawInfoAsInt(BIRTHDATE_4_DIGIT_YEAR, 1997);
profile.set_language_code("en");
profile.FinalizeAfterImport();
table_->AddAutofillProfile(profile);
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 01ed4da16e9..d17ada8aca2 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
@@ -39,7 +39,7 @@
#include "components/sync/protocol/entity_metadata.pb.h"
#include "components/sync/protocol/entity_specifics.pb.h"
#include "components/sync/protocol/model_type_state.pb.h"
-#include "components/sync/test/model/mock_model_type_change_processor.h"
+#include "components/sync/test/mock_model_type_change_processor.h"
#include "components/webdata/common/web_database.h"
#include "testing/gtest/include/gtest/gtest.h"
diff --git a/chromium/components/autofill/core/browser/webdata/autofill_wallet_offer_sync_bridge.cc b/chromium/components/autofill/core/browser/webdata/autofill_wallet_offer_sync_bridge.cc
index 5aa6ca0f788..88f055352d4 100644
--- a/chromium/components/autofill/core/browser/webdata/autofill_wallet_offer_sync_bridge.cc
+++ b/chromium/components/autofill/core/browser/webdata/autofill_wallet_offer_sync_bridge.cc
@@ -10,6 +10,7 @@
#include "base/logging.h"
#include "components/autofill/core/browser/data_model/autofill_offer_data.h"
#include "components/autofill/core/browser/metrics/autofill_metrics.h"
+#include "components/autofill/core/browser/metrics/payments/offers_metrics.h"
#include "components/autofill/core/browser/webdata/autofill_sync_bridge_util.h"
#include "components/autofill/core/browser/webdata/autofill_table.h"
#include "components/autofill/core/browser/webdata/autofill_webdata_backend.h"
@@ -181,7 +182,7 @@ void AutofillWalletOfferSyncBridge::MergeRemoteData(
if (offer_valid) {
offer_data.push_back(AutofillOfferDataFromOfferSpecifics(specifics));
}
- AutofillMetrics::LogSyncedOfferDataBeingValid(offer_valid);
+ autofill_metrics::LogSyncedOfferDataBeingValid(offer_valid);
}
AutofillTable* table = GetAutofillTable();
diff --git a/chromium/components/autofill/core/browser/webdata/autofill_wallet_offer_sync_bridge_unittest.cc b/chromium/components/autofill/core/browser/webdata/autofill_wallet_offer_sync_bridge_unittest.cc
index 9bdf7467cb3..4d6c4bcb529 100644
--- a/chromium/components/autofill/core/browser/webdata/autofill_wallet_offer_sync_bridge_unittest.cc
+++ b/chromium/components/autofill/core/browser/webdata/autofill_wallet_offer_sync_bridge_unittest.cc
@@ -35,7 +35,7 @@
#include "components/sync/protocol/entity_data.h"
#include "components/sync/protocol/entity_specifics.pb.h"
#include "components/sync/protocol/model_type_state.pb.h"
-#include "components/sync/test/model/mock_model_type_change_processor.h"
+#include "components/sync/test/mock_model_type_change_processor.h"
#include "components/webdata/common/web_database.h"
#include "testing/gtest/include/gtest/gtest.h"
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 2085d07eb07..4bbc99bb2d8 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
@@ -43,8 +43,8 @@
#include "components/sync/protocol/entity_metadata.pb.h"
#include "components/sync/protocol/entity_specifics.pb.h"
#include "components/sync/protocol/model_type_state.pb.h"
-#include "components/sync/test/model/mock_model_type_change_processor.h"
-#include "components/sync/test/model/test_matchers.h"
+#include "components/sync/test/mock_model_type_change_processor.h"
+#include "components/sync/test/test_matchers.h"
#include "components/webdata/common/web_database.h"
#include "testing/gtest/include/gtest/gtest.h"
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 141895fece2..92282bc0297 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
@@ -16,6 +16,7 @@
#include "components/autofill/core/browser/data_model/autofill_profile.h"
#include "components/autofill/core/browser/data_model/credit_card.h"
#include "components/autofill/core/browser/data_model/credit_card_cloud_token_data.h"
+#include "components/autofill/core/browser/data_model/iban.h"
#include "components/autofill/core/browser/geo/autofill_country.h"
#include "components/autofill/core/browser/payments/payments_customer_data.h"
#include "components/autofill/core/browser/webdata/autofill_change.h"
@@ -513,6 +514,73 @@ WebDatabase::State AutofillWebDataBackendImpl::UpdateServerCardMetadata(
return WebDatabase::COMMIT_NEEDED;
}
+std::unique_ptr<WDTypedResult> AutofillWebDataBackendImpl::GetIBANs(
+ WebDatabase* db) {
+ DCHECK(owning_task_runner()->RunsTasksInCurrentSequence());
+ std::vector<std::unique_ptr<IBAN>> ibans;
+ AutofillTable::FromWebDatabase(db)->GetIBANs(&ibans);
+
+ return std::make_unique<WDResult<std::vector<std::unique_ptr<IBAN>>>>(
+ AUTOFILL_IBANS_RESULT, std::move(ibans));
+}
+
+WebDatabase::State AutofillWebDataBackendImpl::AddIBAN(const IBAN& iban,
+ WebDatabase* db) {
+ DCHECK(owning_task_runner()->RunsTasksInCurrentSequence());
+ if (!AutofillTable::FromWebDatabase(db)->AddIBAN(iban)) {
+ NOTREACHED();
+ return WebDatabase::COMMIT_NOT_NEEDED;
+ }
+
+ for (auto& db_observer : db_observer_list_) {
+ db_observer.IBANChanged(IBANChange(IBANChange::ADD, iban.guid(), &iban));
+ }
+ return WebDatabase::COMMIT_NEEDED;
+}
+
+WebDatabase::State AutofillWebDataBackendImpl::UpdateIBAN(const IBAN& iban,
+ WebDatabase* db) {
+ DCHECK(owning_task_runner()->RunsTasksInCurrentSequence());
+ // It is currently valid to try to update a missing IBAN. We simply drop
+ // the write and the caller will detect this on the next refresh.
+ std::unique_ptr<IBAN> original_iban =
+ AutofillTable::FromWebDatabase(db)->GetIBAN(iban.guid());
+ if (!original_iban)
+ return WebDatabase::COMMIT_NOT_NEEDED;
+
+ if (!AutofillTable::FromWebDatabase(db)->UpdateIBAN(iban)) {
+ NOTREACHED();
+ return WebDatabase::COMMIT_NOT_NEEDED;
+ }
+
+ for (auto& db_observer : db_observer_list_) {
+ db_observer.IBANChanged(IBANChange(IBANChange::UPDATE, iban.guid(), &iban));
+ }
+ return WebDatabase::COMMIT_NEEDED;
+}
+
+WebDatabase::State AutofillWebDataBackendImpl::RemoveIBAN(
+ const std::string& guid,
+ WebDatabase* db) {
+ DCHECK(owning_task_runner()->RunsTasksInCurrentSequence());
+ std::unique_ptr<IBAN> iban =
+ AutofillTable::FromWebDatabase(db)->GetIBAN(guid);
+ if (!iban) {
+ NOTREACHED();
+ return WebDatabase::COMMIT_NOT_NEEDED;
+ }
+
+ if (!AutofillTable::FromWebDatabase(db)->RemoveIBAN(guid)) {
+ NOTREACHED();
+ return WebDatabase::COMMIT_NOT_NEEDED;
+ }
+
+ for (auto& db_observer : db_observer_list_) {
+ db_observer.IBANChanged(IBANChange(IBANChange::REMOVE, guid, iban.get()));
+ }
+ return WebDatabase::COMMIT_NEEDED;
+}
+
WebDatabase::State AutofillWebDataBackendImpl::UpdateServerAddressMetadata(
const AutofillProfile& profile,
WebDatabase* db) {
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 8e4f8448aad..69813e85a11 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
@@ -31,6 +31,7 @@ namespace autofill {
class AutofillProfile;
class AutofillWebDataServiceObserverOnDBSequence;
class CreditCard;
+class IBAN;
// Backend implementation for the AutofillWebDataService. This class runs on the
// DB sequence, as it handles reads and writes to the WebDatabase, and functions
@@ -177,6 +178,18 @@ class AutofillWebDataBackendImpl
std::unique_ptr<WDTypedResult> GetCreditCards(WebDatabase* db);
std::unique_ptr<WDTypedResult> GetServerCreditCards(WebDatabase* db);
+ // Returns a vector of local IBANs from the web database.
+ std::unique_ptr<WDTypedResult> GetIBANs(WebDatabase* db);
+
+ // Adds an IBAN to the web database. Valid only for local IBANs.
+ WebDatabase::State AddIBAN(const IBAN& iban, WebDatabase* db);
+
+ // Updates an IBAN in the web database. Valid only for local IBANs.
+ WebDatabase::State UpdateIBAN(const IBAN& iban, WebDatabase* db);
+
+ // Removes an IBAN from the web database. Valid only for local IBANs.
+ WebDatabase::State RemoveIBAN(const std::string& guid, WebDatabase* db);
+
// Server credit cards can be masked (only last 4 digits stored) or unmasked
// (all data stored). These toggle between the two states.
WebDatabase::State UnmaskServerCreditCard(const CreditCard& card,
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 162115635ca..ce6246dc162 100644
--- a/chromium/components/autofill/core/browser/webdata/autofill_webdata_service.cc
+++ b/chromium/components/autofill/core/browser/webdata/autofill_webdata_service.cc
@@ -13,6 +13,7 @@
#include "components/autofill/core/browser/data_model/autofill_offer_data.h"
#include "components/autofill/core/browser/data_model/autofill_profile.h"
#include "components/autofill/core/browser/data_model/credit_card.h"
+#include "components/autofill/core/browser/data_model/iban.h"
#include "components/autofill/core/browser/geo/autofill_country.h"
#include "components/autofill/core/browser/webdata/autofill_change.h"
#include "components/autofill/core/browser/webdata/autofill_entry.h"
@@ -213,6 +214,32 @@ void AutofillWebDataService::AddFullServerCreditCard(
autofill_backend_, credit_card));
}
+void AutofillWebDataService::AddIBAN(const IBAN& iban) {
+ wdbs_->ScheduleDBTask(FROM_HERE,
+ base::BindOnce(&AutofillWebDataBackendImpl::AddIBAN,
+ autofill_backend_, iban));
+}
+
+WebDataServiceBase::Handle AutofillWebDataService::GetIBANs(
+ WebDataServiceConsumer* consumer) {
+ return wdbs_->ScheduleDBTaskWithResult(
+ FROM_HERE,
+ base::BindOnce(&AutofillWebDataBackendImpl::GetIBANs, autofill_backend_),
+ consumer);
+}
+
+void AutofillWebDataService::UpdateIBAN(const IBAN& iban) {
+ wdbs_->ScheduleDBTask(FROM_HERE,
+ base::BindOnce(&AutofillWebDataBackendImpl::UpdateIBAN,
+ autofill_backend_, iban));
+}
+
+void AutofillWebDataService::RemoveIBAN(const std::string& guid) {
+ wdbs_->ScheduleDBTask(FROM_HERE,
+ base::BindOnce(&AutofillWebDataBackendImpl::RemoveIBAN,
+ autofill_backend_, guid));
+}
+
WebDataServiceBase::Handle AutofillWebDataService::GetCreditCards(
WebDataServiceConsumer* consumer) {
return wdbs_->ScheduleDBTaskWithResult(
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 cb92feeb2dd..5aaf22356b8 100644
--- a/chromium/components/autofill/core/browser/webdata/autofill_webdata_service.h
+++ b/chromium/components/autofill/core/browser/webdata/autofill_webdata_service.h
@@ -35,6 +35,7 @@ class AutofillWebDataBackendImpl;
class AutofillWebDataServiceObserverOnDBSequence;
class AutofillWebDataServiceObserverOnUISequence;
class CreditCard;
+class IBAN;
// API for Autofill web data.
class AutofillWebDataService : public WebDataServiceBase {
@@ -114,6 +115,22 @@ class AutofillWebDataService : public WebDataServiceBase {
base::RepeatingCallback<void(const AutofillProfileDeepChange&)>
change_cb);
+ // Schedules a task to add IBAN to the web database.
+ void AddIBAN(const IBAN& iban);
+
+ // Initiates the request for local IBANs. The method
+ // OnWebDataServiceRequestDone of |consumer| gets called when the request is
+ // finished, with the IBAN included in the argument |result|. The consumer
+ // owns the IBAN.
+ WebDataServiceBase::Handle GetIBANs(WebDataServiceConsumer* consumer);
+
+ // Schedules a task to update iban in the web database.
+ void UpdateIBAN(const IBAN& iban);
+
+ // Schedules a task to remove an IBAN from the web database.
+ // |guid| is the identifier of the IBAN to remove.
+ void RemoveIBAN(const std::string& guid);
+
// Schedules a task to add credit card to the web database.
void AddCreditCard(const CreditCard& credit_card);
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 60820bb1a51..6c81abdb5e1 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
@@ -23,6 +23,10 @@ class AutofillWebDataServiceObserverOnDBSequence {
// the WebDatabase.
virtual void CreditCardChanged(const CreditCardChange& change) {}
+ // Called on DB sequence when an IBAN has been added/removed/updated in
+ // the WebDatabase.
+ virtual void IBANChanged(const IBANChange& change) {}
+
protected:
virtual ~AutofillWebDataServiceObserverOnDBSequence() {}
};
diff --git a/chromium/components/autofill/core/common/BUILD.gn b/chromium/components/autofill/core/common/BUILD.gn
index 0660e3adc27..f4a0c89ee8e 100644
--- a/chromium/components/autofill/core/common/BUILD.gn
+++ b/chromium/components/autofill/core/common/BUILD.gn
@@ -5,6 +5,8 @@
static_library("common") {
sources = [
"aliases.h",
+ "autocomplete_parsing_util.cc",
+ "autocomplete_parsing_util.h",
"autofill_clock.cc",
"autofill_clock.h",
"autofill_constants.cc",
@@ -21,6 +23,9 @@ static_library("common") {
"autofill_payments_features.h",
"autofill_prefs.cc",
"autofill_prefs.h",
+ "autofill_regex_constants.h",
+ "autofill_regexes.cc",
+ "autofill_regexes.h",
"autofill_switches.cc",
"autofill_switches.h",
"autofill_tick_clock.cc",
@@ -40,9 +45,12 @@ static_library("common") {
"form_field_data_predictions.h",
"gaia_id_hash.cc",
"gaia_id_hash.h",
+ "html_field_types.cc",
+ "html_field_types.h",
"language_code.h",
"logging/log_buffer.cc",
"logging/log_buffer.h",
+ "logging/log_macros.h",
"password_form_fill_data.cc",
"password_form_fill_data.h",
"password_form_generation_data.h",
@@ -96,10 +104,11 @@ component("features") {
source_set("unit_tests") {
testonly = true
sources = [
+ "autocomplete_parsing_util_unittest.cc",
"autofill_internals/log_message_unittest.cc",
"autofill_internals/logging_scope_unittest.cc",
- "autofill_l10n_util_unittest.cc",
"autofill_prefs_unittest.cc",
+ "autofill_regexes_unittest.cc",
"autofill_util_unittest.cc",
"dense_set_unittest.cc",
"field_data_manager_unittest.cc",
diff --git a/chromium/components/autofill/core/common/autocomplete_parsing_util.cc b/chromium/components/autofill/core/common/autocomplete_parsing_util.cc
new file mode 100644
index 00000000000..dda22921127
--- /dev/null
+++ b/chromium/components/autofill/core/common/autocomplete_parsing_util.cc
@@ -0,0 +1,297 @@
+// Copyright 2022 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/common/autocomplete_parsing_util.h"
+
+#include <vector>
+
+#include "base/containers/fixed_flat_map.h"
+#include "base/notreached.h"
+#include "base/strings/utf_string_conversions.h"
+#include "components/autofill/core/common/autofill_features.h"
+#include "components/autofill/core/common/autofill_regexes.h"
+#include "components/autofill/core/common/autofill_util.h"
+
+namespace autofill {
+
+namespace {
+
+// Returns true iff the `token` is a type hint for a contact field, as
+// specified in the implementation section of http://is.gd/whatwg_autocomplete
+// Note that "fax" and "pager" are intentionally ignored, as Chrome does not
+// support filling either type of information.
+bool IsContactTypeHint(const std::string& token) {
+ return token == "home" || token == "work" || token == "mobile";
+}
+
+// Returns true iff the `token` is a type hint appropriate for a field of the
+// given `field_type`, as specified in the implementation section of
+// http://is.gd/whatwg_autocomplete
+bool ContactTypeHintMatchesFieldType(const std::string& token,
+ HtmlFieldType field_type) {
+ // The "home" and "work" type hints are only appropriate for email and phone
+ // number field types.
+ if (token == "home" || token == "work") {
+ return field_type == HTML_TYPE_EMAIL ||
+ (field_type >= HTML_TYPE_TEL &&
+ field_type <= HTML_TYPE_TEL_LOCAL_SUFFIX);
+ }
+
+ // The "mobile" type hint is only appropriate for phone number field types.
+ // Note that "fax" and "pager" are intentionally ignored, as Chrome does not
+ // support filling either type of information.
+ if (token == "mobile") {
+ return field_type >= HTML_TYPE_TEL &&
+ field_type <= HTML_TYPE_TEL_LOCAL_SUFFIX;
+ }
+
+ return false;
+}
+
+// Rationalizes the HTML `type` of `field`, based on the fields properties. At
+// the moment only `max_length` is considered. For example, a max_length of 4
+// might indicate a 4 digit year.
+// In case no rationalization rule applies, the original type is returned.
+HtmlFieldType RationalizeAutocompleteType(HtmlFieldType type,
+ const FormFieldData& field) {
+ // (original-type, max-length) -> new-type
+ static constexpr auto rules =
+ base::MakeFixedFlatMap<std::pair<HtmlFieldType, uint64_t>, HtmlFieldType>(
+ {
+ {{HTML_TYPE_ADDITIONAL_NAME, 1},
+ HTML_TYPE_ADDITIONAL_NAME_INITIAL},
+ {{HTML_TYPE_CREDIT_CARD_EXP, 5},
+ HTML_TYPE_CREDIT_CARD_EXP_DATE_2_DIGIT_YEAR},
+ {{HTML_TYPE_CREDIT_CARD_EXP, 7},
+ HTML_TYPE_CREDIT_CARD_EXP_DATE_4_DIGIT_YEAR},
+ {{HTML_TYPE_CREDIT_CARD_EXP_YEAR, 2},
+ HTML_TYPE_CREDIT_CARD_EXP_2_DIGIT_YEAR},
+ {{HTML_TYPE_CREDIT_CARD_EXP_YEAR, 4},
+ HTML_TYPE_CREDIT_CARD_EXP_4_DIGIT_YEAR},
+ });
+
+ auto* it = rules.find(std::make_pair(type, field.max_length));
+ return it == rules.end() ? type : it->second;
+}
+
+// Chrome Autofill supports a subset of the field types listed at
+// http://is.gd/whatwg_autocomplete. Returns the corresponding HtmlFieldType, if
+// `value` matches any of them.
+absl::optional<HtmlFieldType> ParseStandardizedAutocompleteAttribute(
+ base::StringPiece value) {
+ static constexpr auto standardized_attributes =
+ base::MakeFixedFlatMap<base::StringPiece, HtmlFieldType>({
+ {"additional-name", HTML_TYPE_ADDITIONAL_NAME},
+ {"address-level1", HTML_TYPE_ADDRESS_LEVEL1},
+ {"address-level2", HTML_TYPE_ADDRESS_LEVEL2},
+ {"address-level3", HTML_TYPE_ADDRESS_LEVEL3},
+ {"address-line1", HTML_TYPE_ADDRESS_LINE1},
+ {"address-line2", HTML_TYPE_ADDRESS_LINE2},
+ {"address-line3", HTML_TYPE_ADDRESS_LINE3},
+ {"bday-day", HTML_TYPE_BIRTHDATE_DAY},
+ {"bday-month", HTML_TYPE_BIRTHDATE_MONTH},
+ {"bday-year", HTML_TYPE_BIRTHDATE_YEAR},
+ {"cc-csc", HTML_TYPE_CREDIT_CARD_VERIFICATION_CODE},
+ {"cc-exp", HTML_TYPE_CREDIT_CARD_EXP},
+ {"cc-exp-month", HTML_TYPE_CREDIT_CARD_EXP_MONTH},
+ {"cc-exp-year", HTML_TYPE_CREDIT_CARD_EXP_YEAR},
+ {"cc-family-name", HTML_TYPE_CREDIT_CARD_NAME_LAST},
+ {"cc-given-name", HTML_TYPE_CREDIT_CARD_NAME_FIRST},
+ {"cc-name", HTML_TYPE_CREDIT_CARD_NAME_FULL},
+ {"cc-number", HTML_TYPE_CREDIT_CARD_NUMBER},
+ {"cc-type", HTML_TYPE_CREDIT_CARD_TYPE},
+ {"country", HTML_TYPE_COUNTRY_CODE},
+ {"country-name", HTML_TYPE_COUNTRY_NAME},
+ {"email", HTML_TYPE_EMAIL},
+ {"family-name", HTML_TYPE_FAMILY_NAME},
+ {"given-name", HTML_TYPE_GIVEN_NAME},
+ {"honorific-prefix", HTML_TYPE_HONORIFIC_PREFIX},
+ {"name", HTML_TYPE_NAME},
+ {"one-time-code", HTML_TYPE_ONE_TIME_CODE},
+ {"organization", HTML_TYPE_ORGANIZATION},
+ {"postal-code", HTML_TYPE_POSTAL_CODE},
+ {"street-address", HTML_TYPE_STREET_ADDRESS},
+ {"tel-area-code", HTML_TYPE_TEL_AREA_CODE},
+ {"tel-country-code", HTML_TYPE_TEL_COUNTRY_CODE},
+ {"tel-extension", HTML_TYPE_TEL_EXTENSION},
+ {"tel", HTML_TYPE_TEL},
+ {"tel-local", HTML_TYPE_TEL_LOCAL},
+ {"tel-local-prefix", HTML_TYPE_TEL_LOCAL_PREFIX},
+ {"tel-local-suffix", HTML_TYPE_TEL_LOCAL_SUFFIX},
+ {"tel-national", HTML_TYPE_TEL_NATIONAL},
+ {"transaction-amount", HTML_TYPE_TRANSACTION_AMOUNT},
+ {"transaction-currency", HTML_TYPE_TRANSACTION_CURRENCY},
+ });
+
+ auto* it = standardized_attributes.find(value);
+ return it != standardized_attributes.end()
+ ? absl::optional<HtmlFieldType>(it->second)
+ : absl::nullopt;
+}
+
+// Maps `value`s that Autofill has proposed for the HTML autocomplete standard,
+// but which are not standardized, to their HtmlFieldType.
+absl::optional<HtmlFieldType> ParseProposedAutocompleteAttribute(
+ base::StringPiece value) {
+ static constexpr auto proposed_attributes =
+ base::MakeFixedFlatMap<base::StringPiece, HtmlFieldType>({
+ {"address", HTML_TYPE_STREET_ADDRESS},
+ {"coupon-code", HTML_TYPE_MERCHANT_PROMO_CODE},
+ // TODO(crbug.com/1351760): Investigate if this mapping makes sense.
+ {"username", HTML_TYPE_EMAIL},
+ });
+
+ auto* it = proposed_attributes.find(value);
+ return it != proposed_attributes.end()
+ ? absl::optional<HtmlFieldType>(it->second)
+ : absl::nullopt;
+}
+
+// Maps non-standardized `value`s for the HTML autocomplete attribute to an
+// HtmlFieldType. This is primarily a list of "reasonable guesses".
+absl::optional<HtmlFieldType> ParseNonStandarizedAutocompleteAttribute(
+ base::StringPiece value) {
+ static constexpr auto non_standardized_attributes =
+ base::MakeFixedFlatMap<base::StringPiece, HtmlFieldType>({
+ {"company", HTML_TYPE_ORGANIZATION},
+ {"first-name", HTML_TYPE_GIVEN_NAME},
+ {"gift-code", HTML_TYPE_MERCHANT_PROMO_CODE},
+ {"iban", HTML_TYPE_IBAN},
+ {"locality", HTML_TYPE_ADDRESS_LEVEL2},
+ {"promo-code", HTML_TYPE_MERCHANT_PROMO_CODE},
+ {"promotional-code", HTML_TYPE_MERCHANT_PROMO_CODE},
+ {"promotion-code", HTML_TYPE_MERCHANT_PROMO_CODE},
+ {"region", HTML_TYPE_ADDRESS_LEVEL1},
+ {"tel-ext", HTML_TYPE_TEL_EXTENSION},
+ {"upi", HTML_TYPE_UPI_VPA},
+ {"upi-vpa", HTML_TYPE_UPI_VPA},
+ });
+
+ auto* it = non_standardized_attributes.find(value);
+ return it != non_standardized_attributes.end()
+ ? absl::optional<HtmlFieldType>(it->second)
+ : absl::nullopt;
+}
+
+// If the autocomplete `value` doesn't match any of Autofill's supported values,
+// Autofill should remain enabled for good intended values. This function checks
+// if there is reason to believe so, by matching `value` against patterns like
+// "address".
+// Ignoring autocomplete="off" and alike is treated separately in
+// `ParseFieldTypesFromAutocompleteAttributes()`.
+bool ShouldIgnoreAutocompleteValue(base::StringPiece value) {
+ static constexpr char16_t kRegex[] = u"address";
+ return MatchesRegex<kRegex>(base::UTF8ToUTF16(value));
+}
+
+} // namespace
+
+HtmlFieldType FieldTypeFromAutocompleteAttributeValue(
+ std::string value,
+ const FormFieldData& field) {
+ if (value.empty())
+ return HTML_TYPE_UNSPECIFIED;
+
+ // We are lenient and accept '_' instead of '-' as a separator. E.g.
+ // "given_name" is treated like "given-name".
+ base::ReplaceChars(value, "_", "-", &value);
+ // We accept e.g. "phone-country" instead of "tel-country".
+ if (base::StartsWith(value, "phone"))
+ base::ReplaceFirstSubstringAfterOffset(&value, 0, "phone", "tel");
+
+ absl::optional<HtmlFieldType> type =
+ ParseStandardizedAutocompleteAttribute(value);
+ if (!type.has_value()) {
+ type = ParseProposedAutocompleteAttribute(value);
+ if (!type.has_value())
+ type = ParseNonStandarizedAutocompleteAttribute(value);
+ }
+
+ if (type.has_value())
+ return RationalizeAutocompleteType(type.value(), field);
+
+ // `value` cannot be mapped to any HtmlFieldType. By classifying the field
+ // as HTML_TYPE_UNRECOGNIZED Autofill is effectively disabled. Instead, check
+ // if we have reason to ignore the value and treat the field as
+ // HTML_TYPE_UNSPECIFIED. This makes us ignore the autocomplete value.
+ return ShouldIgnoreAutocompleteValue(value) &&
+ base::FeatureList::IsEnabled(
+ features::kAutofillIgnoreUnmappableAutocompleteValues)
+ ? HTML_TYPE_UNSPECIFIED
+ : HTML_TYPE_UNRECOGNIZED;
+}
+
+absl::optional<AutocompleteParsingResult> ParseAutocompleteAttribute(
+ const FormFieldData& field) {
+ std::vector<std::string> tokens =
+ LowercaseAndTokenizeAttributeString(field.autocomplete_attribute);
+
+ // The autocomplete attribute is overloaded: it can specify either a field
+ // type hint or whether autocomplete should be enabled at all. Ignore the
+ // latter type of attribute value.
+ if (tokens.empty() ||
+ (tokens.size() == 1 && ShouldIgnoreAutocompleteAttribute(tokens[0]))) {
+ return absl::nullopt;
+ }
+
+ AutocompleteParsingResult result;
+
+ // The "webauthn" token is unused by Autofill, but skipped to parse the type
+ // correctly.
+ if (tokens.back() == "webauthn") {
+ tokens.pop_back();
+ if (tokens.empty())
+ return absl::nullopt;
+ }
+
+ // (1) The final token must be the field type.
+ std::string field_type_token = tokens.back();
+ tokens.pop_back();
+ result.field_type =
+ FieldTypeFromAutocompleteAttributeValue(field_type_token, field);
+
+ // (2) The preceding token, if any, may be a type hint.
+ if (!tokens.empty() && IsContactTypeHint(tokens.back())) {
+ // If it is, it must match the field type; otherwise, abort.
+ // Note that an invalid token invalidates the entire attribute value, even
+ // if the other tokens are valid.
+ if (!ContactTypeHintMatchesFieldType(tokens.back(), result.field_type))
+ return absl::nullopt;
+ // Chrome Autofill ignores these type hints.
+ tokens.pop_back();
+ }
+
+ // (3) The preceding token, if any, may be a fixed string that is either
+ // "shipping" or "billing".
+ result.mode = HTML_MODE_NONE;
+ if (!tokens.empty()) {
+ for (HtmlFieldMode mode : {HTML_MODE_BILLING, HTML_MODE_SHIPPING})
+ if (tokens.back() == HtmlFieldModeToStringPiece(mode)) {
+ result.mode = mode;
+ tokens.pop_back();
+ break;
+ }
+ }
+
+ // (4) The preceding token, if any, may be a named section.
+ constexpr base::StringPiece kSectionPrefix = "section-";
+ if (!tokens.empty() && base::StartsWith(tokens.back(), kSectionPrefix,
+ base::CompareCase::SENSITIVE)) {
+ // Prepend this section name to the suffix set in the preceding block.
+ result.section = tokens.back().substr(kSectionPrefix.size());
+ tokens.pop_back();
+ }
+
+ // (5) No other tokens are allowed. If there are any remaining, abort.
+ if (!tokens.empty())
+ return absl::nullopt;
+
+ return result;
+}
+
+bool ShouldIgnoreAutocompleteAttribute(base::StringPiece autocomplete) {
+ return autocomplete == "on" || autocomplete == "off" ||
+ autocomplete == "false";
+}
+
+} // namespace autofill
diff --git a/chromium/components/autofill/core/common/autocomplete_parsing_util.h b/chromium/components/autofill/core/common/autocomplete_parsing_util.h
new file mode 100644
index 00000000000..7fd6da8ee9e
--- /dev/null
+++ b/chromium/components/autofill/core/common/autocomplete_parsing_util.h
@@ -0,0 +1,55 @@
+// Copyright 2022 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_COMMON_AUTOCOMPLETE_PARSING_UTIL_H_
+#define COMPONENTS_AUTOFILL_CORE_COMMON_AUTOCOMPLETE_PARSING_UTIL_H_
+
+#include <string>
+
+#include "base/strings/string_piece.h"
+#include "components/autofill/core/common/form_field_data.h"
+#include "components/autofill/core/common/html_field_types.h"
+#include "third_party/abseil-cpp/absl/types/optional.h"
+
+namespace autofill {
+
+// The autocomplete attribute consists of several components, as described at
+// http://is.gd/whatwg_autocomplete. Autofill supports part of the specification
+// and parses the following tokens:
+// [section-*] [shipping|billing] [type_hint] field_type [webauthn]
+// The parsing extracts these components from `field.autocomplete_attribute` or
+// returns absl::nullopt, if the parsing fails. The latter happens if:
+// - The autocomplete value is empty or contains more than 5 tokens.
+// - The type_hint doesn't match the field_type.
+// - If ShouldIgnoreAutocompleteAttribute(autocomplete) is true.
+// An unrecognizable field_type doesn't stop parsing and yields
+// HTML_TYPE_UNRECOGNIZED instead.
+struct AutocompleteParsingResult {
+ // `section` corresponds to the string after "section-".
+ std::string section;
+ HtmlFieldMode mode;
+ // Type hints are parsed and validated, but otherwise unused.
+ HtmlFieldType field_type;
+ // webauthn is parsed, but otherwise unused.
+};
+absl::optional<AutocompleteParsingResult> ParseAutocompleteAttribute(
+ const FormFieldData& field);
+
+// Checks if `autocomplete` is one of "on", "off" or "false". These values are
+// currently ignored by Autofill.
+bool ShouldIgnoreAutocompleteAttribute(base::StringPiece autocomplete);
+
+// Parses `value` as an HTML field type and converts it to the corresponding
+// HtmlFieldType, if it is supposed by Autofill. Rationalization based on the
+// `field` is done.
+// HTML_TYPE_UNSPECIFIED is returned if `value` is empty, or if `value` is
+// supposed to be ignored by `kAutofillIgnoreUnmappableAutocompleteValues`.
+// Otherwise HTML_TYPE_UNRECOGNIZED is returned.
+HtmlFieldType FieldTypeFromAutocompleteAttributeValue(
+ std::string value,
+ const FormFieldData& field);
+
+} // namespace autofill
+
+#endif // COMPONENTS_AUTOFILL_CORE_COMMON_AUTOCOMPLETE_PARSING_UTIL_H_
diff --git a/chromium/components/autofill/core/common/autocomplete_parsing_util_unittest.cc b/chromium/components/autofill/core/common/autocomplete_parsing_util_unittest.cc
new file mode 100644
index 00000000000..41f167054cd
--- /dev/null
+++ b/chromium/components/autofill/core/common/autocomplete_parsing_util_unittest.cc
@@ -0,0 +1,103 @@
+// Copyright 2022 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/common/autocomplete_parsing_util.h"
+
+#include <string>
+
+#include "base/strings/string_piece.h"
+#include "components/autofill/core/common/form_field_data.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/abseil-cpp/absl/types/optional.h"
+
+namespace autofill {
+
+// Tests that parsing a field with autocomplete=`autocomplete` and
+// maxlength=`max_length` results in `expected_result`.
+struct AutocompleteAttributeTestcase {
+ base::StringPiece autocomplete;
+ absl::optional<AutocompleteParsingResult> expected_result;
+ int max_length = 0;
+};
+
+class AutocompleteAttributeProcessingUtilTest
+ : public testing::TestWithParam<AutocompleteAttributeTestcase> {};
+
+// In general, `ParseAutocompleteAttribute()` returns absl::nullopt if one of
+// the tokens cannot be parsed. The exception is the field type, which defaults
+// to HTML_TYPE_UNRECOGNIZED.
+const AutocompleteAttributeTestcase kAutocompleteTestcases[]{
+ // Only the field type:
+ {"name", {{"", HTML_MODE_NONE, HTML_TYPE_NAME}}},
+ {"autofill", {{"", HTML_MODE_NONE, HTML_TYPE_UNRECOGNIZED}}},
+ // autocomplete=off is ignored completely.
+ {"off", absl::nullopt},
+
+ // Rationalization based on the field's max_length is done.
+ {"cc-exp-year", {{"", HTML_MODE_NONE, HTML_TYPE_CREDIT_CARD_EXP_YEAR}}},
+ {"cc-exp-year",
+ {{"", HTML_MODE_NONE, HTML_TYPE_CREDIT_CARD_EXP_2_DIGIT_YEAR}},
+ /*max_length=*/2},
+
+ // Type hints:
+ // They are parsed and validated, but otherwise unused. Type hints are only
+ // valid before tel* and email.
+ {"home email", {{"", HTML_MODE_NONE, HTML_TYPE_EMAIL}}},
+ {"work email", {{"", HTML_MODE_NONE, HTML_TYPE_EMAIL}}},
+ {"work cc-number", absl::nullopt},
+ {"unrecognized_type_hint email", absl::nullopt},
+
+ // Billing and shipping modes:
+ {"billing country", {{"", HTML_MODE_BILLING, HTML_TYPE_COUNTRY_CODE}}},
+ {"shipping country", {{"", HTML_MODE_SHIPPING, HTML_TYPE_COUNTRY_CODE}}},
+ {"billing unrecognized", {{"", HTML_MODE_BILLING, HTML_TYPE_UNRECOGNIZED}}},
+ {"shipping work tel-local",
+ {{"", HTML_MODE_SHIPPING, HTML_TYPE_TEL_LOCAL}}},
+ {"unrecognized_mode country", absl::nullopt},
+ {"unrecognized_mode unrecognized", absl::nullopt},
+
+ // Sections:
+ {"section-one tel", {{"one", HTML_MODE_NONE, HTML_TYPE_TEL}}},
+ {"section-one shipping tel", {{"one", HTML_MODE_SHIPPING, HTML_TYPE_TEL}}},
+ {"section-one shipping home tel",
+ {{"one", HTML_MODE_SHIPPING, HTML_TYPE_TEL}}},
+ {"section- tel", {{"", HTML_MODE_NONE, HTML_TYPE_TEL}}},
+ {"section tel", absl::nullopt},
+ {"no_section tel", absl::nullopt},
+ {"no_section work tel", absl::nullopt},
+ {"section-random", {{"", HTML_MODE_NONE, HTML_TYPE_UNRECOGNIZED}}},
+
+ // "webauthn" shouldn't prevent parsing, but is otherwise ignored.
+ {"name webauthn", {{"", HTML_MODE_NONE, HTML_TYPE_NAME}}},
+ {"section-one shipping home tel webauthn",
+ {{"one", HTML_MODE_SHIPPING, HTML_TYPE_TEL}}},
+ {"webauthn", absl::nullopt},
+
+ // Too many tokens.
+ {"hello section-one shipping home tel webauthn", absl::nullopt}};
+
+INSTANTIATE_TEST_SUITE_P(,
+ AutocompleteAttributeProcessingUtilTest,
+ testing::ValuesIn(kAutocompleteTestcases));
+
+TEST_P(AutocompleteAttributeProcessingUtilTest, ParseAutocompleteAttribute) {
+ auto test = GetParam();
+ SCOPED_TRACE(testing::Message()
+ << "autocomplete=\"" << test.autocomplete << "\"");
+
+ FormFieldData field;
+ field.autocomplete_attribute = std::string(test.autocomplete);
+ if (test.max_length)
+ field.max_length = test.max_length;
+
+ auto result = ParseAutocompleteAttribute(field);
+ ASSERT_EQ(result.has_value(), test.expected_result.has_value());
+ if (result.has_value()) {
+ EXPECT_EQ(result->section, test.expected_result->section);
+ EXPECT_EQ(result->mode, test.expected_result->mode);
+ EXPECT_EQ(result->field_type, test.expected_result->field_type);
+ }
+}
+
+} // namespace autofill
diff --git a/chromium/components/autofill/core/common/autofill_features.cc b/chromium/components/autofill/core/common/autofill_features.cc
index f7fb7e74750..9fd9d35b68c 100644
--- a/chromium/components/autofill/core/common/autofill_features.cc
+++ b/chromium/components/autofill/core/common/autofill_features.cc
@@ -95,7 +95,14 @@ const base::Feature kAutofillInferCountryCallingCode{
// determine the address requirements.
// TODO(crbug.com/1297032): Cleanup when launched.
const base::Feature kAutofillComplementCountryCodeOnImport{
- "AutofillComplementCountryCodeOnImport", base::FEATURE_DISABLED_BY_DEFAULT};
+ "AutofillComplementCountryCodeOnImport", base::FEATURE_ENABLED_BY_DEFAULT};
+
+// If enabled, label inference considers strings entirely made up of '(', ')'
+// and '-' as valid labels.
+// TODO(crbug.com/1311937): Cleanup when launched.
+const base::Feature kAutofillConsiderPhoneNumberSeparatorsValidLabels{
+ "AutofillConsiderPhoneNumberSeparatorsValidLabels",
+ base::FEATURE_DISABLED_BY_DEFAULT};
// If enabled, local heuristics fall back to the fields placeholder attribute.
const base::Feature kAutofillConsiderPlaceholderForParsing{
@@ -128,12 +135,6 @@ const base::Feature kAutofillFillCreditCardAsPerFormatString{
"AutofillFillCreditCardAsPerFormatString",
base::FEATURE_DISABLED_BY_DEFAULT};
-// If enabled, AutofillPopupControllerImpl is destructed not immediately in its
-// HideViewAndDie() function, but as a delayed task.
-// TODO(crbug.com/1277218): Cleanup when launched.
-const base::Feature kAutofillDelayPopupControllerDeletion{
- "AutofillDelayPopupControllerDeletion", base::FEATURE_DISABLED_BY_DEFAULT};
-
// Kill switch for Autofill filling.
const base::Feature kAutofillDisableFilling{"AutofillDisableFilling",
base::FEATURE_DISABLED_BY_DEFAULT};
@@ -195,14 +196,11 @@ const base::Feature kAutofillEnableAugmentedPhoneCountryCode{
"AutofillEnableAugmentedPhoneCountryCode",
base::FEATURE_DISABLED_BY_DEFAULT};
-// This feature guards the logic for Autofills future compatibility launch of
-// birthdates. Currently filling is not supported and this effectively
-// disables the birthdate merging logic, reads/writes to the AutofillTable and
-// reading/writing from the sync proto.
-// TODO(crbug.com/1305940): Remove once launched.
-const base::Feature kAutofillEnableCompatibilitySupportForBirthdates{
- "AutofillEnableCompatibilitySupportForBirthdates",
- base::FEATURE_ENABLED_BY_DEFAULT};
+// Enables parsing for birthdate fields. Filling is not supported and parsing
+// is meant to prevent false positive credit card expiration dates.
+// TODO(crbug.com/1306654): Remove once launched.
+const base::Feature kAutofillEnableBirthdateParsing{
+ "AutofillEnableBirthdateParsing", base::FEATURE_DISABLED_BY_DEFAULT};
// Controls if Autofill parses ADDRESS_HOME_DEPENDENT_LOCALITY.
// TODO(crbug.com/1157405): Remove once launched.
@@ -218,7 +216,7 @@ const base::Feature kAutofillEnableExtendedAddressFormats{
// Controls whether to save the first number in a form with multiple phone
// numbers instead of aborting the import.
-// TODO(crbug.com/1167484) Remove once launched
+// TODO(crbug.com/1167484) Remove once launched.
const base::Feature kAutofillEnableImportWhenMultiplePhoneNumbers{
"AutofillEnableImportWhenMultiplePhoneNumbers",
base::FEATURE_DISABLED_BY_DEFAULT};
@@ -267,13 +265,13 @@ const base::Feature kAutofillEnableProfileDeduplication{
// TODO(crbug.com/1098943): Remove once launched.
const base::Feature kAutofillEnableSupportForMoreStructureInNames{
"AutofillEnableSupportForMoreStructureInNames",
- base::FEATURE_DISABLED_BY_DEFAULT};
+ base::FEATURE_ENABLED_BY_DEFAULT};
// Controls if Autofill supports new structure in addresses.
// TODO(crbug.com/1098943): Remove once launched.
const base::Feature kAutofillEnableSupportForMoreStructureInAddresses{
"AutofillEnableSupportForMoreStructureInAddresses",
- base::FEATURE_DISABLED_BY_DEFAULT};
+ base::FEATURE_ENABLED_BY_DEFAULT};
// Controls if Autofill supports merging subset names.
// TODO(crbug.com/1098943): Remove once launched.
@@ -323,25 +321,6 @@ const base::Feature kAutofillExtractAllDatalists{
const base::Feature kAutofillTypeSpecificPopupWidth{
"AutofillTypeSpecificPopupWidth", base::FEATURE_DISABLED_BY_DEFAULT};
-// Autofill uses the local heuristic such that address forms are only filled if
-// at least 3 fields are fillable according to local heuristics. Unfortunately,
-// the criterion for fillability is only that the field type is unknown. So many
-// field types that we don't fill (search term, price, ...) count towards that
-// counter, effectively reducing the threshold for some forms.
-const base::Feature kAutofillFixFillableFieldTypes{
- "AutofillFixFillableFieldTypes", base::FEATURE_ENABLED_BY_DEFAULT};
-
-// Lookups for field classifications are gated on either Autofill for addresses
-// or payments being enabled. As a consequence, if both are disabled, the
-// password manager does not get server-side field classifications anymore
-// and its performance is reduced. When this feature is enabled, Autofill parse
-// forms and perform server lookups even if only the password manager is
-// enabled.
-// TODO(crbug.com/1293341): Remove once launched.
-const base::Feature kAutofillFixServerQueriesIfPasswordManagerIsEnabled{
- "AutofillFixServerQueriesIfPasswordManagerIsEnabled",
- base::FEATURE_DISABLED_BY_DEFAULT};
-
// When enabled, the Autofill popup ignores second clicks for a certain period
// (kAutofillIgnoreEarlyClicksOnPopupDuration) after the Autofill popup was
// shown. This is to prevent double clicks accidentally accepting suggestions.
@@ -356,7 +335,20 @@ const base::Feature kAutofillIgnoreEarlyClicksOnPopup{
const base::FeatureParam<base::TimeDelta>
kAutofillIgnoreEarlyClicksOnPopupDuration{
&kAutofillIgnoreEarlyClicksOnPopup, "duration",
- base::Milliseconds(250)};
+ base::Milliseconds(500)};
+
+// When enabled, HTML autocomplete values that do not map to any known type, but
+// look reasonable (e.g. contain "address") are simply ignored. Without the
+// feature, Autofill is disabled on such fields.
+const base::Feature kAutofillIgnoreUnmappableAutocompleteValues{
+ "AutofillIgnoreUnmappableAutocompleteValues",
+ base::FEATURE_DISABLED_BY_DEFAULT};
+
+// When enabled, <label for=..> inference relies on control.labels() instead of
+// iterating through all <label> tags manually.
+// TODO(crbug.com/1339277) Remove once launched.
+const base::Feature kAutofillImprovedLabelForInference{
+ "AutofillImprovedLabelForInference", base::FEATURE_DISABLED_BY_DEFAULT};
// When enabled, only changed values are highlighted in preview mode.
// TODO(crbug/1248585): Remove when launched.
@@ -434,6 +426,19 @@ const base::FeatureParam<std::string> kAutofillParsingPatternActiveSource{
const base::Feature kAutofillPageLanguageDetection{
"AutofillPageLanguageDetection", base::FEATURE_DISABLED_BY_DEFAULT};
+// If enabled, AutofillManager::ParseForm() isn't called synchronously.
+// Instead, all incoming events parse the form asynchronously and proceed
+// afterwards.
+// TODO(crbug.com/1309848) Remove once launched.
+const base::Feature kAutofillParseAsync{"AutofillParseAsync",
+ base::FEATURE_DISABLED_BY_DEFAULT};
+
+// If enabled, local heuristics fall back to interpreting the fields' name as an
+// autocomplete type.
+// TODO(crbug.com/TODO) Remove once launched.
+const base::Feature kAutofillParseNameAsAutocompleteType{
+ "AutofillParseNameAsAutocompleteType", base::FEATURE_DISABLED_BY_DEFAULT};
+
// If the feature is enabled, FormTracker's probable-form-submission detection
// is disabled and replaced with browser-side detection.
// TODO(crbug/1117451): Remove once it works.
@@ -536,6 +541,7 @@ const base::Feature kAutofillSilentProfileUpdateForInsufficientImport{
// Controls whether inferred label is considered for comparing in
// FormFieldData.SimilarFieldAs.
+// TODO(crbug.com/1211834): The experiment seems dead; remove?
const base::Feature kAutofillSkipComparingInferredLabels{
"AutofillSkipComparingInferredLabels", base::FEATURE_DISABLED_BY_DEFAULT};
diff --git a/chromium/components/autofill/core/common/autofill_features.h b/chromium/components/autofill/core/common/autofill_features.h
index d8b3036b433..56cff1ad9b2 100644
--- a/chromium/components/autofill/core/common/autofill_features.h
+++ b/chromium/components/autofill/core/common/autofill_features.h
@@ -49,6 +49,8 @@ extern const base::Feature kAutofillInferCountryCallingCode;
COMPONENT_EXPORT(AUTOFILL)
extern const base::Feature kAutofillComplementCountryCodeOnImport;
COMPONENT_EXPORT(AUTOFILL)
+extern const base::Feature kAutofillConsiderPhoneNumberSeparatorsValidLabels;
+COMPONENT_EXPORT(AUTOFILL)
extern const base::Feature kAutofillConsiderPlaceholderForParsing;
COMPONENT_EXPORT(AUTOFILL)
extern const base::Feature kAutofillConsiderVariationCountryCodeForPhoneNumbers;
@@ -60,8 +62,6 @@ COMPONENT_EXPORT(AUTOFILL)
extern const base::Feature kAutofillFillAndImportFromMoreFields;
COMPONENT_EXPORT(AUTOFILL)
extern const base::Feature kAutofillFillCreditCardAsPerFormatString;
-COMPONENT_EXPORT(AUTOFILL)
-extern const base::Feature kAutofillDelayPopupControllerDeletion;
COMPONENT_EXPORT(AUTOFILL) extern const base::Feature kAutofillDisableFilling;
COMPONENT_EXPORT(AUTOFILL)
extern const base::Feature kAutofillDisableAddressImport;
@@ -72,7 +72,7 @@ extern const base::Feature kAutofillEnableAccountWalletStorage;
COMPONENT_EXPORT(AUTOFILL)
extern const base::Feature kAutofillEnableAugmentedPhoneCountryCode;
COMPONENT_EXPORT(AUTOFILL)
-extern const base::Feature kAutofillEnableCompatibilitySupportForBirthdates;
+extern const base::Feature kAutofillEnableBirthdateParsing;
COMPONENT_EXPORT(AUTOFILL)
extern const base::Feature kAutofillEnableDependentLocalityParsing;
COMPONENT_EXPORT(AUTOFILL)
@@ -124,15 +124,15 @@ extern const base::Feature kAutofillRefillModifiedCreditCardExpirationDates;
COMPONENT_EXPORT(AUTOFILL)
extern const base::Feature kAutofillTypeSpecificPopupWidth;
COMPONENT_EXPORT(AUTOFILL)
-extern const base::Feature kAutofillFixFillableFieldTypes;
-COMPONENT_EXPORT(AUTOFILL)
-extern const base::Feature kAutofillFixServerQueriesIfPasswordManagerIsEnabled;
-COMPONENT_EXPORT(AUTOFILL)
extern const base::Feature kAutofillIgnoreEarlyClicksOnPopup;
COMPONENT_EXPORT(AUTOFILL)
extern const base::FeatureParam<base::TimeDelta>
kAutofillIgnoreEarlyClicksOnPopupDuration;
COMPONENT_EXPORT(AUTOFILL)
+extern const base::Feature kAutofillIgnoreUnmappableAutocompleteValues;
+COMPONENT_EXPORT(AUTOFILL)
+extern const base::Feature kAutofillImprovedLabelForInference;
+COMPONENT_EXPORT(AUTOFILL)
extern const base::Feature kAutofillHighlightOnlyChangedValuesInPreviewMode;
COMPONENT_EXPORT(AUTOFILL)
extern const base::Feature kAutofillServerTypeTakesPrecedence;
@@ -151,6 +151,10 @@ extern const base::FeatureParam<int>
COMPONENT_EXPORT(AUTOFILL)
extern const base::Feature kAutofillPageLanguageDetection;
COMPONENT_EXPORT(AUTOFILL)
+extern const base::Feature kAutofillParseAsync;
+COMPONENT_EXPORT(AUTOFILL)
+extern const base::Feature kAutofillParseNameAsAutocompleteType;
+COMPONENT_EXPORT(AUTOFILL)
extern const base::Feature kAutofillParsingPatternProvider;
COMPONENT_EXPORT(AUTOFILL)
extern const base::FeatureParam<std::string>
diff --git a/chromium/components/autofill/core/common/autofill_internals/log_message_unittest.cc b/chromium/components/autofill/core/common/autofill_internals/log_message_unittest.cc
index 2d4f225cb99..f6fbb63e67b 100644
--- a/chromium/components/autofill/core/common/autofill_internals/log_message_unittest.cc
+++ b/chromium/components/autofill/core/common/autofill_internals/log_message_unittest.cc
@@ -14,7 +14,7 @@ TEST(LogMessage, Serialization) {
LogBuffer buffer;
buffer << LogMessage::kParsedForms;
std::string json;
- EXPECT_TRUE(base::JSONWriter::Write(buffer.RetrieveResult(), &json));
+ EXPECT_TRUE(base::JSONWriter::Write(*buffer.RetrieveResult(), &json));
EXPECT_EQ(R"({"attributes":{"class":"log-message","message":"ParsedForms"},)"
R"("children":[{"type":"text","value":"Parsed forms:"}],)"
R"("type":"element","value":"div"})",
diff --git a/chromium/components/autofill/core/common/autofill_internals/logging_scope_unittest.cc b/chromium/components/autofill/core/common/autofill_internals/logging_scope_unittest.cc
index 16ffe96f22c..25c6dfdc3a3 100644
--- a/chromium/components/autofill/core/common/autofill_internals/logging_scope_unittest.cc
+++ b/chromium/components/autofill/core/common/autofill_internals/logging_scope_unittest.cc
@@ -14,7 +14,7 @@ TEST(LoggingScope, Serialization) {
LogBuffer buffer;
buffer << LoggingScope::kContext;
std::string json;
- EXPECT_TRUE(base::JSONWriter::Write(buffer.RetrieveResult(), &json));
+ EXPECT_TRUE(base::JSONWriter::Write(*buffer.RetrieveResult(), &json));
EXPECT_EQ(R"({"attributes":{"class":"log-entry","scope":"Context"},)"
R"("type":"element","value":"div"})",
json);
diff --git a/chromium/components/autofill/core/common/autofill_l10n_util.cc b/chromium/components/autofill/core/common/autofill_l10n_util.cc
index 07a94b1d1ea..207c09762ac 100644
--- a/chromium/components/autofill/core/common/autofill_l10n_util.cc
+++ b/chromium/components/autofill/core/common/autofill_l10n_util.cc
@@ -10,7 +10,6 @@
#include "base/i18n/string_compare.h"
#include "base/logging.h"
#include "base/memory/ptr_util.h"
-#include "base/metrics/histogram_macros.h"
namespace autofill {
namespace l10n {
@@ -38,9 +37,6 @@ std::unique_ptr<icu::Collator> GetCollatorForLocale(const icu::Locale& locale) {
<< "locale.";
}
}
-
- UMA_HISTOGRAM_BOOLEAN("Autofill.IcuCollatorCreationSuccess",
- (!!collator && U_SUCCESS(error_code)));
return collator;
}
diff --git a/chromium/components/autofill/core/common/autofill_l10n_util_unittest.cc b/chromium/components/autofill/core/common/autofill_l10n_util_unittest.cc
deleted file mode 100644
index 6692ebee5ba..00000000000
--- a/chromium/components/autofill/core/common/autofill_l10n_util_unittest.cc
+++ /dev/null
@@ -1,35 +0,0 @@
-// Copyright 2015 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/common/autofill_l10n_util.h"
-
-#include "base/test/metrics/histogram_tester.h"
-#include "testing/gtest/include/gtest/gtest.h"
-#include "third_party/icu/source/common/unicode/locid.h"
-
-namespace autofill {
-namespace l10n {
-
-// Test the success in the creation of the ICU Collator.
-TEST(CaseInsensitiveCompareTest, IcuCollatorCreation_Success) {
- base::HistogramTester histogram_tester;
- CaseInsensitiveCompare compare;
- histogram_tester.ExpectUniqueSample("Autofill.IcuCollatorCreationSuccess",
- true, 1);
-}
-
-// Test the failure in creating the ICU Collator.
-TEST(CaseInsensitiveCompareTest, IcuCollatorCreation_FailureBadLocale) {
- // Setting the locale to a bogus value.
- icu::Locale bogusLocale = icu::Locale::createFromName("bogus");
- bogusLocale.setToBogus();
-
- base::HistogramTester histogram_tester;
- CaseInsensitiveCompare compare(bogusLocale);
- histogram_tester.ExpectUniqueSample("Autofill.IcuCollatorCreationSuccess",
- false, 1);
-}
-
-} // namespace l10n
-} // namespace autofill
diff --git a/chromium/components/autofill/core/common/autofill_payments_features.cc b/chromium/components/autofill/core/common/autofill_payments_features.cc
index 4ebd3a423e5..57064945746 100644
--- a/chromium/components/autofill/core/common/autofill_payments_features.cc
+++ b/chromium/components/autofill/core/common/autofill_payments_features.cc
@@ -47,12 +47,6 @@ const base::Feature kAutofillCreditCardAuthentication{
#endif
};
-// When enabled, if credit card upload succeeded, the avatar icon will show a
-// highlight otherwise, the credit card icon image will be updated and if user
-// clicks on the icon, a save card failure bubble will pop up.
-const base::Feature kAutofillCreditCardUploadFeedback{
- "AutofillCreditCardUploadFeedback", base::FEATURE_DISABLED_BY_DEFAULT};
-
// When enabled, the GetDetailsForEnrollResponseDetails in the
// UploadCardResponseDetails will be parsed, which will allow the Virtual Card
// Enrollment flow to skip making a new GetDetailsForEnroll request. This is an
@@ -62,11 +56,22 @@ const base::Feature
"AutofillEnableGetDetailsForEnrollParsingInUploadCardResponse",
base::FEATURE_ENABLED_BY_DEFAULT};
+// When enabled, a progress dialog will display while authenticating with FIDO.
+// TODO(crbug.com/1337380): Clean up kAutofillEnableFIDOProgressDialog when it's
+// fully rolled out.
+const base::Feature kAutofillEnableFIDOProgressDialog{
+ "AutofillEnableFIDOProgressDialog", base::FEATURE_DISABLED_BY_DEFAULT};
+
// When enabled, enable manual falling component for virtual cards on Android.
const base::Feature kAutofillEnableManualFallbackForVirtualCards{
"AutofillEnableManualFallbackForVirtualCards",
base::FEATURE_ENABLED_BY_DEFAULT};
+// When enabled, card product name (instead of issuer network) will be shown in
+// Payments UI.
+const base::Feature kAutofillEnableCardProductName{
+ "AutofillEnableCardProductName", base::FEATURE_DISABLED_BY_DEFAULT};
+
// When enabled, a notification will be displayed on page navigation if the
// domain has an eligible merchant promo code offer or reward.
const base::Feature kAutofillEnableOfferNotificationForPromoCodes{
@@ -79,11 +84,15 @@ const base::Feature kAutofillEnableOffersInClankKeyboardAccessory{
"AutofillEnableOffersInClankKeyboardAccessory",
base::FEATURE_DISABLED_BY_DEFAULT};
+// When enabled, some extra metrics logging for Autofill Downstream will start.
+const base::Feature kAutofillEnableRemadeDownstreamMetrics{
+ "AutofillEnableRemadeDownstreamMetrics", base::FEATURE_ENABLED_BY_DEFAULT};
+
// Controls whether we send billing customer number in GetUploadDetails
// preflight call.
const base::Feature kAutofillEnableSendingBcnInGetUploadDetails{
"AutofillEnableSendingBcnInGetUploadDetails",
- base::FEATURE_DISABLED_BY_DEFAULT};
+ base::FEATURE_ENABLED_BY_DEFAULT};
// When enabled, if the user interacts with the manual fallback bottom sheet
// on Android, it'll remain sticky until the user dismisses it.
@@ -91,11 +100,6 @@ const base::Feature kAutofillEnableStickyManualFallbackForCards{
"AutofillEnableStickyManualFallbackForCards",
base::FEATURE_DISABLED_BY_DEFAULT};
-// When enabled, Autofill data related icons will be shown in the status
-// chip in toolbar along with the avatar toolbar button.
-const base::Feature kAutofillEnableToolbarStatusChip{
- "AutofillEnableToolbarStatusChip", base::FEATURE_DISABLED_BY_DEFAULT};
-
// When enabled, UnmaskCardRequest will set instrument id, which is Chrome-side
// field for non-legacy ID.
const base::Feature kAutofillEnableUnmaskCardRequestSetInstrumentId{
@@ -145,16 +149,32 @@ const base::Feature kAutofillEnableVirtualCardMetadata{
const base::Feature kAutofillEnforceDelaysInStrikeDatabase{
"AutofillEnforceDelaysInStrikeDatabase", base::FEATURE_DISABLED_BY_DEFAULT};
+// When enabled, Autofill will attempt to fill IBAN (International Bank Account
+// Number) fields when data is available.
+const base::Feature kAutofillFillIbanFields{"AutofillFillIbanFields",
+ base::FEATURE_DISABLED_BY_DEFAULT};
+
// When enabled, Autofill will attempt to fill merchant promo/coupon/gift code
// fields when data is available.
const base::Feature kAutofillFillMerchantPromoCodeFields{
"AutofillFillMerchantPromoCodeFields", base::FEATURE_DISABLED_BY_DEFAULT};
+// When enabled, Autofill will attempt to find International Bank Account Number
+// (IBAN) fields when parsing forms.
+const base::Feature kAutofillParseIBANFields{"AutofillParseIBANFields",
+ base::FEATURE_DISABLED_BY_DEFAULT};
+
// When enabled, Autofill will attempt to find merchant promo/coupon/gift code
// fields when parsing forms.
const base::Feature kAutofillParseMerchantPromoCodeFields{
"AutofillParseMerchantPromoCodeFields", base::FEATURE_DISABLED_BY_DEFAULT};
+// When enabled, Autofill will attempt to find standalone CVC fields for VCN
+// card on file when parsing forms.
+const base::Feature kAutofillParseVcnCardOnFileStandaloneCvcFields{
+ "AutofillParseVcnCardOnFileStandaloneCvcFields",
+ base::FEATURE_DISABLED_BY_DEFAULT};
+
// When enabled, the Save Card infobar will be dismissed by a user initiated
// navigation other than one caused by submitted form.
const base::Feature kAutofillSaveCardDismissOnNavigation{
@@ -187,12 +207,6 @@ const base::Feature kAutofillShowUnmaskedCachedCardInManualFillingView{
"AutofillShowUnmaskedCachedCardInManualFillingView",
base::FEATURE_DISABLED_BY_DEFAULT};
-// When enabled, merchant bound virtual cards will be suggested even if we don't
-// detect all of the card number, exp date and CVC fields in the payment form.
-const base::Feature kAutofillSuggestVirtualCardsOnIncompleteForm{
- "AutofillSuggestVirtualCardsOnIncompleteForm",
- base::FEATURE_DISABLED_BY_DEFAULT};
-
// Controls offering credit card upload to Google Payments. Cannot ever be
// ENABLED_BY_DEFAULT because the feature state depends on the user's country.
// The set of launched countries is listed in autofill_experiments.cc, and this
diff --git a/chromium/components/autofill/core/common/autofill_payments_features.h b/chromium/components/autofill/core/common/autofill_payments_features.h
index 96a96778243..1d0b5f95d66 100644
--- a/chromium/components/autofill/core/common/autofill_payments_features.h
+++ b/chromium/components/autofill/core/common/autofill_payments_features.h
@@ -9,10 +9,6 @@
#include "base/metrics/field_trial_params.h"
#include "build/build_config.h"
-namespace base {
-struct Feature;
-}
-
namespace autofill {
namespace features {
@@ -20,15 +16,16 @@ namespace features {
extern const base::Feature kAutofillAlwaysReturnCloudTokenizedCard;
extern const base::Feature kAutofillAutoTriggerManualFallbackForCards;
extern const base::Feature kAutofillCreditCardAuthentication;
-extern const base::Feature kAutofillCreditCardUploadFeedback;
extern const base::Feature
kAutofillEnableGetDetailsForEnrollParsingInUploadCardResponse;
+extern const base::Feature kAutofillEnableFIDOProgressDialog;
extern const base::Feature kAutofillEnableManualFallbackForVirtualCards;
+extern const base::Feature kAutofillEnableCardProductName;
extern const base::Feature kAutofillEnableOfferNotificationForPromoCodes;
extern const base::Feature kAutofillEnableOffersInClankKeyboardAccessory;
+extern const base::Feature kAutofillEnableRemadeDownstreamMetrics;
extern const base::Feature kAutofillEnableSendingBcnInGetUploadDetails;
extern const base::Feature kAutofillEnableStickyManualFallbackForCards;
-extern const base::Feature kAutofillEnableToolbarStatusChip;
extern const base::Feature kAutofillEnableUnmaskCardRequestSetInstrumentId;
extern const base::Feature kAutofillEnableUpdateVirtualCardEnrollment;
extern const base::Feature kAutofillEnableVirtualCard;
@@ -37,8 +34,11 @@ extern const base::Feature
kAutofillEnableVirtualCardManagementInDesktopSettingsPage;
extern const base::Feature kAutofillEnableVirtualCardMetadata;
extern const base::Feature kAutofillEnforceDelaysInStrikeDatabase;
+extern const base::Feature kAutofillFillIbanFields;
extern const base::Feature kAutofillFillMerchantPromoCodeFields;
+extern const base::Feature kAutofillParseIBANFields;
extern const base::Feature kAutofillParseMerchantPromoCodeFields;
+extern const base::Feature kAutofillParseVcnCardOnFileStandaloneCvcFields;
extern const base::Feature kAutofillRemoveCardExpiryFromDownstreamSuggestion;
extern const base::Feature kAutofillSaveCardDismissOnNavigation;
extern const base::Feature kAutofillSaveCardInfobarEditSupport;
@@ -46,7 +46,6 @@ extern const base::Feature kAutofillSaveCardUiExperiment;
extern const base::FeatureParam<int>
kAutofillSaveCardUiExperimentSelectorInNumber;
extern const base::Feature kAutofillShowUnmaskedCachedCardInManualFillingView;
-extern const base::Feature kAutofillSuggestVirtualCardsOnIncompleteForm;
extern const base::Feature kAutofillUpstream;
extern const base::Feature kAutofillUpstreamAllowAdditionalEmailDomains;
extern const base::Feature kAutofillUpstreamAllowAllEmailDomains;
diff --git a/chromium/components/autofill/core/common/autofill_prefs.cc b/chromium/components/autofill/core/common/autofill_prefs.cc
index d2e741e5593..07d39cd9ea6 100644
--- a/chromium/components/autofill/core/common/autofill_prefs.cc
+++ b/chromium/components/autofill/core/common/autofill_prefs.cc
@@ -19,19 +19,13 @@ namespace {
// was found.
int GetSyncTransportOptInBitFieldForAccount(const PrefService* prefs,
const std::string& account_hash) {
- auto* dictionary = prefs->GetDictionary(prefs::kAutofillSyncTransportOptIn);
-
- // If there is no dictionary it means the account didn't opt-in. Use 0 because
- // it's the same as not having opted-in to anything.
- if (!dictionary) {
- return 0;
- }
+ const auto& dictionary =
+ prefs->GetValueDict(prefs::kAutofillSyncTransportOptIn);
// If there is no entry in the dictionary, it means the account didn't opt-in.
// Use 0 because it's the same as not having opted-in to anything.
- auto* found =
- dictionary->FindKeyOfType(account_hash, base::Value::Type::INTEGER);
- return found ? found->GetInt() : 0;
+ const auto found = dictionary.FindInt(account_hash);
+ return found.value_or(0);
}
} // namespace
@@ -61,6 +55,9 @@ const char kAutofillEnabledDeprecated[] = "autofill.enabled";
const char kAutofillJapanCityFieldMigratedDeprecated[] =
"autofill.japan_city_field_migrated_to_street_address";
+// Boolean that is true if Autofill is enabled and allowed to save IBAN data.
+extern const char kAutofillIBANEnabled[] = "autofill.iban_enabled";
+
// Integer that is set to the last version where the profile deduping routine
// was run. This routine will be run once per version.
const char kAutofillLastVersionDeduped[] = "autofill.last_version_deduped";
@@ -135,6 +132,9 @@ void RegisterProfilePrefs(user_prefs::PrefRegistrySyncable* registry) {
registry->RegisterBooleanPref(
prefs::kAutofillCreditCardEnabled, true,
user_prefs::PrefRegistrySyncable::SYNCABLE_PREF);
+ registry->RegisterBooleanPref(
+ prefs::kAutofillIBANEnabled, true,
+ user_prefs::PrefRegistrySyncable::SYNCABLE_PREF);
// Non-synced prefs. Used for per-device choices, e.g., signin promo.
registry->RegisterBooleanPref(prefs::kAutofillCreditCardFidoAuthEnabled,
@@ -217,6 +217,14 @@ void SetAutofillCreditCardEnabled(PrefService* prefs, bool enabled) {
prefs->SetBoolean(kAutofillCreditCardEnabled, enabled);
}
+bool IsAutofillIBANEnabled(const PrefService* prefs) {
+ return prefs->GetBoolean(kAutofillIBANEnabled);
+}
+
+void SetAutofillIBANEnabled(PrefService* prefs, bool enabled) {
+ prefs->SetBoolean(kAutofillIBANEnabled, enabled);
+}
+
bool IsAutofillManaged(const PrefService* prefs) {
return prefs->IsManagedPreference(kAutofillEnabledDeprecated);
}
diff --git a/chromium/components/autofill/core/common/autofill_prefs.h b/chromium/components/autofill/core/common/autofill_prefs.h
index f086613bc5b..12d118243ce 100644
--- a/chromium/components/autofill/core/common/autofill_prefs.h
+++ b/chromium/components/autofill/core/common/autofill_prefs.h
@@ -28,8 +28,10 @@ extern const char kAutofillCreditCardFidoAuthEnabled[];
extern const char kAutofillCreditCardFidoAuthOfferCheckboxState[];
#endif
extern const char kAutofillCreditCardSigninPromoImpressionCount[];
-// Please use kAutofillCreditCardEnabled and kAutofillProfileEnabled instead.
+// Please use kAutofillCreditCardEnabled, kAutofillIBANEnabled and
+// kAutofillProfileEnabled instead.
extern const char kAutofillEnabledDeprecated[];
+extern const char kAutofillIBANEnabled[];
extern const char kAutofillJapanCityFieldMigratedDeprecated[];
extern const char kAutofillLastVersionDeduped[];
extern const char kAutofillLastVersionDisusedAddressesDeleted[];
@@ -68,6 +70,10 @@ bool IsAutofillCreditCardEnabled(const PrefService* prefs);
void SetAutofillCreditCardEnabled(PrefService* prefs, bool enabled);
+bool IsAutofillIBANEnabled(const PrefService* prefs);
+
+void SetAutofillIBANEnabled(PrefService* prefs, bool enabled);
+
bool IsAutofillManaged(const PrefService* prefs);
bool IsAutofillProfileManaged(const PrefService* prefs);
diff --git a/chromium/components/autofill/core/common/autofill_prefs_unittest.cc b/chromium/components/autofill/core/common/autofill_prefs_unittest.cc
index 7576fceced2..a294b6617e6 100644
--- a/chromium/components/autofill/core/common/autofill_prefs_unittest.cc
+++ b/chromium/components/autofill/core/common/autofill_prefs_unittest.cc
@@ -89,45 +89,43 @@ TEST_F(AutofillPrefsTest, WalletSyncTransportPref_GetAndSet) {
ASSERT_FALSE(IsUserOptedInWalletSyncTransport(pref_service(), account1));
ASSERT_FALSE(IsUserOptedInWalletSyncTransport(pref_service(), account2));
// There should be no entry for the accounts in the dictionary.
- EXPECT_TRUE(pref_service()
- ->GetDictionary(prefs::kAutofillSyncTransportOptIn)
- ->DictEmpty());
+ EXPECT_TRUE(
+ pref_service()->GetValueDict(prefs::kAutofillSyncTransportOptIn).empty());
// Set the opt-in for the first account.
SetUserOptedInWalletSyncTransport(pref_service(), account1, true);
EXPECT_TRUE(IsUserOptedInWalletSyncTransport(pref_service(), account1));
EXPECT_FALSE(IsUserOptedInWalletSyncTransport(pref_service(), account2));
// There should only be one entry in the dictionary.
- EXPECT_EQ(1U, pref_service()
- ->GetDictionary(prefs::kAutofillSyncTransportOptIn)
- ->DictSize());
+ EXPECT_EQ(
+ 1U,
+ pref_service()->GetValueDict(prefs::kAutofillSyncTransportOptIn).size());
// Unset the opt-in for the first account.
SetUserOptedInWalletSyncTransport(pref_service(), account1, false);
EXPECT_FALSE(IsUserOptedInWalletSyncTransport(pref_service(), account1));
EXPECT_FALSE(IsUserOptedInWalletSyncTransport(pref_service(), account2));
// There should be no entry for the accounts in the dictionary.
- EXPECT_TRUE(pref_service()
- ->GetDictionary(prefs::kAutofillSyncTransportOptIn)
- ->DictEmpty());
+ EXPECT_TRUE(
+ pref_service()->GetValueDict(prefs::kAutofillSyncTransportOptIn).empty());
// Set the opt-in for the second account.
SetUserOptedInWalletSyncTransport(pref_service(), account2, true);
EXPECT_FALSE(IsUserOptedInWalletSyncTransport(pref_service(), account1));
EXPECT_TRUE(IsUserOptedInWalletSyncTransport(pref_service(), account2));
// There should only be one entry in the dictionary.
- EXPECT_EQ(1U, pref_service()
- ->GetDictionary(prefs::kAutofillSyncTransportOptIn)
- ->DictSize());
+ EXPECT_EQ(
+ 1U,
+ pref_service()->GetValueDict(prefs::kAutofillSyncTransportOptIn).size());
// Set the opt-in for the first account too.
SetUserOptedInWalletSyncTransport(pref_service(), account1, true);
EXPECT_TRUE(IsUserOptedInWalletSyncTransport(pref_service(), account1));
EXPECT_TRUE(IsUserOptedInWalletSyncTransport(pref_service(), account1));
// There should be tow entries in the dictionary.
- EXPECT_EQ(2U, pref_service()
- ->GetDictionary(prefs::kAutofillSyncTransportOptIn)
- ->DictSize());
+ EXPECT_EQ(
+ 2U,
+ pref_service()->GetValueDict(prefs::kAutofillSyncTransportOptIn).size());
}
#endif // !BUILDFLAG(IS_ANDROID) && !BUILDFLAG(IS_IOS)
@@ -137,21 +135,18 @@ TEST_F(AutofillPrefsTest, WalletSyncTransportPref_UsesHashAccountId) {
const CoreAccountId account1("account1");
// There should be no opt-in recorded at first.
- EXPECT_TRUE(pref_service()
- ->GetDictionary(prefs::kAutofillSyncTransportOptIn)
- ->DictEmpty());
+ EXPECT_TRUE(
+ pref_service()->GetValueDict(prefs::kAutofillSyncTransportOptIn).empty());
// Set the opt-in for the first account.
SetUserOptedInWalletSyncTransport(pref_service(), account1, true);
- EXPECT_FALSE(pref_service()
- ->GetDictionary(prefs::kAutofillSyncTransportOptIn)
- ->DictEmpty());
+ EXPECT_FALSE(
+ pref_service()->GetValueDict(prefs::kAutofillSyncTransportOptIn).empty());
// Make sure that the dictionary keys don't contain the account id.
- auto* dictionary =
- pref_service()->GetDictionary(prefs::kAutofillSyncTransportOptIn);
- EXPECT_EQ(nullptr, dictionary->FindKeyOfType(account1.ToString(),
- base::Value::Type::INTEGER));
+ const auto& dictionary =
+ pref_service()->GetValueDict(prefs::kAutofillSyncTransportOptIn);
+ EXPECT_EQ(absl::nullopt, dictionary.FindInt(account1.ToString()));
}
// Tests that clearing the AutofillSyncTransportOptIn works as expected.
@@ -160,27 +155,23 @@ TEST_F(AutofillPrefsTest, WalletSyncTransportPref_Clear) {
const CoreAccountId account2("account2");
// There should be no opt-in recorded at first.
- EXPECT_TRUE(pref_service()
- ->GetDictionary(prefs::kAutofillSyncTransportOptIn)
- ->DictEmpty());
+ EXPECT_TRUE(
+ pref_service()->GetValueDict(prefs::kAutofillSyncTransportOptIn).empty());
// Set the opt-in for the first account.
SetUserOptedInWalletSyncTransport(pref_service(), account1, true);
- EXPECT_FALSE(pref_service()
- ->GetDictionary(prefs::kAutofillSyncTransportOptIn)
- ->DictEmpty());
+ EXPECT_FALSE(
+ pref_service()->GetValueDict(prefs::kAutofillSyncTransportOptIn).empty());
// Set the opt-in for the second account.
SetUserOptedInWalletSyncTransport(pref_service(), account2, true);
- EXPECT_FALSE(pref_service()
- ->GetDictionary(prefs::kAutofillSyncTransportOptIn)
- ->DictEmpty());
+ EXPECT_FALSE(
+ pref_service()->GetValueDict(prefs::kAutofillSyncTransportOptIn).empty());
// Clear all opt-ins. The dictionary should be empty.
ClearSyncTransportOptIns(pref_service());
- EXPECT_TRUE(pref_service()
- ->GetDictionary(prefs::kAutofillSyncTransportOptIn)
- ->DictEmpty());
+ EXPECT_TRUE(
+ pref_service()->GetValueDict(prefs::kAutofillSyncTransportOptIn).empty());
}
// Tests that the account id hash that we generate can be written and read from
@@ -190,17 +181,15 @@ TEST_F(AutofillPrefsTest, WalletSyncTransportPref_CanBeSetAndReadFromJSON) {
// Set the opt-in for the first account.
SetUserOptedInWalletSyncTransport(pref_service(), account1, true);
- EXPECT_FALSE(pref_service()
- ->GetDictionary(prefs::kAutofillSyncTransportOptIn)
- ->DictEmpty());
+ EXPECT_FALSE(
+ pref_service()->GetValueDict(prefs::kAutofillSyncTransportOptIn).empty());
- const base::Value* dictionary =
- pref_service()->GetDictionary(prefs::kAutofillSyncTransportOptIn);
- ASSERT_TRUE(dictionary);
+ const base::Value::Dict& dictionary =
+ pref_service()->GetValueDict(prefs::kAutofillSyncTransportOptIn);
std::string output_js;
- ASSERT_TRUE(base::JSONWriter::Write(*dictionary, &output_js));
- EXPECT_EQ(*dictionary, *base::JSONReader::Read(output_js));
+ ASSERT_TRUE(base::JSONWriter::Write(dictionary, &output_js));
+ EXPECT_EQ(dictionary, *base::JSONReader::Read(output_js));
}
} // namespace prefs
diff --git a/chromium/components/autofill/core/browser/autofill_regex_constants.cc b/chromium/components/autofill/core/common/autofill_regex_constants.h
index b09c8608887..91466aa2f35 100644
--- a/chromium/components/autofill/core/browser/autofill_regex_constants.cc
+++ b/chromium/components/autofill/core/common/autofill_regex_constants.h
@@ -2,26 +2,25 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-// This file contains UTF16 strings that we want as char16_t arrays.
-
-#include "components/autofill/core/browser/autofill_regex_constants.h"
+#ifndef COMPONENTS_AUTOFILL_CORE_COMMON_AUTOFILL_REGEX_CONSTANTS_H_
+#define COMPONENTS_AUTOFILL_CORE_COMMON_AUTOFILL_REGEX_CONSTANTS_H_
namespace autofill {
/////////////////////////////////////////////////////////////////////////////
// address_field.cc
/////////////////////////////////////////////////////////////////////////////
-const char16_t kAttentionIgnoredRe[] = u"attention|attn";
-const char16_t kRegionIgnoredRe[] =
+inline constexpr char16_t kAttentionIgnoredRe[] = u"attention|attn";
+inline constexpr char16_t kRegionIgnoredRe[] =
u"province|region|other"
u"|provincia" // es
u"|bairro|suburb"; // pt-BR, pt-PT
-const char16_t kAddressNameIgnoredRe[] =
+inline constexpr char16_t kAddressNameIgnoredRe[] =
u"address.*nickname|address.*label"
u"|adres ([İi]sim|başlığı|adı)" // tr
u"|identificação do endereço" // pt-BR, pt-PT
u"|(label|judul|nama) alamat"; // id
-const char16_t kCompanyRe[] =
+inline constexpr char16_t kCompanyRe[] =
u"company|business|organization|organisation"
u"|(?<!con)firma|firmenname" // de-DE
u"|empresa" // es
@@ -33,26 +32,26 @@ const char16_t kCompanyRe[] =
u"|شرکت" // fa
u"|회사|직장" // ko-KR
u"|(nama.?)?perusahaan"; // id
-const char16_t kStreetNameRe[] =
+inline constexpr char16_t kStreetNameRe[] =
u"stra(ss|ß)e" // de
u"|street" // en
u"|улица|название.?улицы" // ru
u"|rua|avenida" // pt-PT, pt-BR
u"|((?<!do |de )endereço)" // pt-BR
u"|calle"; // es-MX
-const char16_t kHouseNumberRe[] =
+inline constexpr char16_t kHouseNumberRe[] =
u"(house.?|street.?|^)(number|no\\.?$)" // en
u"|(haus|^)(nummer|nr)" // de
u"|^\\*?.?número(.?\\*?$| da residência)" // pt-BR, pt-PT
u"|дом|номер.?дома" // ru
u"|exterior"; // es-MX
-const char16_t kApartmentNumberRe[] =
+inline constexpr char16_t kApartmentNumberRe[] =
u"apartment" // en
u"|interior" // es-MX
u"|n(u|ú)mero.*app?art(a|e)ment" // es,fr,it
u"|Wohnung" // de
u"|квартир"; // ru
-const char16_t kAddressLine1Re[] =
+inline constexpr char16_t kAddressLine1Re[] =
u"^address$|address[_-]?line(one)?|address1|addr1|street"
u"|(?:shipping|billing)address$"
u"|strasse|straße|hausnummer|housenumber" // de-DE
@@ -67,7 +66,7 @@ const char16_t kAddressLine1Re[] =
u"|(\\b|_)adres(?! tarifi)(\\b|_)" // tr
u"|^주소.?$|주소.?1" // ko-KR
u"|^alamat"; // id
-const char16_t kAddressLine1LabelRe[] =
+inline constexpr char16_t kAddressLine1LabelRe[] =
u"(^\\W*address)"
u"|(address\\W*$)"
u"|(?:shipping|billing|mailing|pick.?up|drop.?off|delivery|sender|postal|"
@@ -86,7 +85,7 @@ const char16_t kAddressLine1LabelRe[] =
u"|(sokak|cadde).*(apartman|bina|daire|mahalle)" // tr
u"|(apartman|bina|daire|mahalle).*(sokak|cadde)"
u"|улиц.*(дом|корпус|квартир|этаж)|(дом|корпус|квартир|этаж).*улиц"; // ru
-const char16_t kAddressLine2Re[] =
+inline constexpr char16_t kAddressLine2Re[] =
u"address[_-]?line(2|two)|address2|addr2|street|suite|unit"
u"|adresszusatz|ergänzende.?angaben" // de-DE
u"|direccion2|colonia|adicional" // es
@@ -97,19 +96,19 @@ const char16_t kAddressLine2Re[] =
u"|Улица" // ru
u"|地址2" // zh-CN
u"|주소.?2"; // ko-KR
-const char16_t kAddressLine2LabelRe[] =
+inline constexpr char16_t kAddressLine2LabelRe[] =
u"address|line"
u"|adresse" // fr-FR
u"|indirizzo" // it-IT
u"|地址" // zh-CN
u"|주소"; // ko-KR
-const char16_t kAddressLinesExtraRe[] =
+inline constexpr char16_t kAddressLinesExtraRe[] =
u"address.*line[3-9]|address[3-9]|addr[3-9]|street|line[3-9]"
u"|municipio" // es
u"|batiment|residence" // fr-FR
u"|indirizzo[3-9]"; // it-IT
-const char16_t kAddressLookupRe[] = u"lookup";
-const char16_t kCountryRe[] =
+inline constexpr char16_t kAddressLookupRe[] = u"lookup";
+inline constexpr char16_t kCountryRe[] =
u"country|countries"
u"|país|pais" // es
u"|(\\b|_)land(\\b|_)(?!.*(mark.*))" // de-DE landmark is a type in india.
@@ -119,8 +118,8 @@ const char16_t kCountryRe[] =
u"|(\\b|_)(ülke|ulce|ulke)(\\b|_)" // tr
u"|کشور" // fa
u"|negara"; // id
-const char16_t kCountryLocationRe[] = u"location";
-const char16_t kZipCodeRe[] =
+inline constexpr char16_t kCountryLocationRe[] = u"location";
+inline constexpr char16_t kZipCodeRe[] =
u"((?<!\\.))zip" // .zip indicates a file extension
u"|postal|post.*code|pcode"
u"|pin.?code" // en-IN
@@ -138,16 +137,16 @@ const char16_t kZipCodeRe[] =
u"|(\\b|_)posta kodu(\\b|_)" // tr
u"|우편.?번호" // ko-KR
u"|kode.?pos"; // id
-const char16_t kZip4Re[] =
+inline constexpr char16_t kZip4Re[] =
u"((?<!\\.))zip" // .zip indicates a file extension
u"|^-$|post2"
u"|codpos2"; // pt-BR, pt-PT
-const char16_t kDependentLocalityRe[] =
+inline constexpr char16_t kDependentLocalityRe[] =
u"neighbo(u)?rhood" // en
u"|bairro" // pt-BR, pt-PT
u"|mahalle|köy" // tr
u"|kecamatan"; // id
-const char16_t kCityRe[] =
+inline constexpr char16_t kCityRe[] =
u"city|town"
u"|\\bort\\b|stadt" // de-DE
u"|suburb" // en-AU
@@ -166,7 +165,7 @@ const char16_t kCityRe[] =
u"|((\\b|_|\\*)([İii̇]l[cç]e(miz|niz)?)(\\b|_|\\*))" // tr
u"|^시[^도·・]|시[·・]?군[·・]?구" // ko-KR
u"|kota|kabupaten"; // id
-const char16_t kStateRe[] =
+inline constexpr char16_t kStateRe[] =
u"(?<!(united|hist|history).?)state|county|region|province"
u"|county|principality" // en-UK
u"|都道府県" // ja-JP
@@ -184,7 +183,7 @@ const char16_t kStateRe[] =
/////////////////////////////////////////////////////////////////////////////
// search_field.cc
/////////////////////////////////////////////////////////////////////////////
-const char16_t kSearchTermRe[] =
+inline constexpr char16_t kSearchTermRe[] =
u"^q$"
u"|search"
u"|query"
@@ -200,7 +199,7 @@ const char16_t kSearchTermRe[] =
/////////////////////////////////////////////////////////////////////////////
// field_price.cc
/////////////////////////////////////////////////////////////////////////////
-const char16_t kPriceRe[] =
+inline constexpr char16_t kPriceRe[] =
u"\\bprice\\b|\\brate\\b|\\bcost\\b"
u"|قیمة‎|سعر‎" // ar
u"|قیمت" // fa
@@ -209,7 +208,7 @@ const char16_t kPriceRe[] =
/////////////////////////////////////////////////////////////////////////////
// credit_card_field.cc
/////////////////////////////////////////////////////////////////////////////
-const char16_t kNameOnCardRe[] =
+inline constexpr char16_t kNameOnCardRe[] =
u"card.?(?:holder|owner)|name.*(\\b)?on(\\b)?.*card"
u"|(?:card|cc).?name|cc.?full.?name"
u"|karteninhaber" // de-DE
@@ -221,8 +220,8 @@ const char16_t kNameOnCardRe[] =
u"|nama.*kartu" // id
u"|信用卡开户名|开户名|持卡人姓名" // zh-CN
u"|持卡人姓名"; // zh-TW
-const char16_t kNameOnCardContextualRe[] = u"name";
-const char16_t kCardNumberRe[] =
+inline constexpr char16_t kNameOnCardContextualRe[] = u"name";
+inline constexpr char16_t kCardNumberRe[] =
u"(add)?(?:card|cc|acct).?(?:number|#|no|num|field|pan)"
u"|(?<!telefon|haus|person|fødsels|kunden)nummer" // de-DE, sv-SE, no
u"|カード番号" // ja-JP
@@ -234,7 +233,7 @@ const char16_t kCardNumberRe[] =
// es/pt/fr
u"|(numero|número|numéro)(?!.*(document|fono|phone|réservation))";
-const char16_t kCardCvcRe[] =
+inline constexpr char16_t kCardCvcRe[] =
u"verification|card.?identification|security.?code|card.?code"
u"|security.?value"
u"|security.?number|card.?pin|c-v-v"
@@ -253,7 +252,7 @@ const char16_t kCardCvcRe[] =
// Toolbar Bug 51451: indeed, simply matching "month" is too general for
// https://rps.fidelity.com/ftgw/rps/RtlCust/CreatePIN/Init.
// Instead, we match only words beginning with "month".
-const char16_t kExpirationMonthRe[] =
+inline constexpr char16_t kExpirationMonthRe[] =
u"expir|exp.*mo|exp.*date|ccmonth|cardmonth|addmonth"
u"|gueltig|gültig|monat" // de-DE
u"|fecha" // es
@@ -264,7 +263,7 @@ const char16_t kExpirationMonthRe[] =
u"|Срок действия карты" // ru
u"|masa berlaku|berlaku hingga" // id
u"|月"; // zh-CN
-const char16_t kExpirationYearRe[] =
+inline constexpr char16_t kExpirationYearRe[] =
u"exp|^/|(add)?year"
u"|ablaufdatum|gueltig|gültig|jahr" // de-DE
u"|fecha" // es
@@ -282,16 +281,16 @@ const char16_t kExpirationYearRe[] =
// - (optional) Separated by white-space and/or a dash or slash.
// - (optional) Prepended with some text similar to "Expiration Date".
// Tested in components/autofill/core/browser/autofill_regexes_unittest.cc
-const char16_t kExpirationDate2DigitYearRe[] =
+inline constexpr char16_t kExpirationDate2DigitYearRe[] =
u"(?:exp.*date[^y\\n\\r]*|mm\\s*[-/]?\\s*)yy(?:[^y]|$)";
// Used to match a expiration date field with a four digit year.
// Same requirements as |kExpirationDate2DigitYearRe| except:
// - Exactly four adjacent y's.
// Tested in components/autofill/core/browser/autofill_regexes_unittest.cc
-const char16_t kExpirationDate4DigitYearRe[] =
+inline constexpr char16_t kExpirationDate4DigitYearRe[] =
u"(?:exp.*date[^y\\n\\r]*|mm\\s*[-/]?\\s*)yyyy(?:[^y]|$)";
// Used to match expiration date fields that do not specify a year length.
-const char16_t kExpirationDateRe[] =
+inline constexpr char16_t kExpirationDateRe[] =
u"expir|exp.*date|^expfield$"
u"|gueltig|gültig" // de-DE
u"|fecha" // es
@@ -300,16 +299,16 @@ const char16_t kExpirationDateRe[] =
u"|有効期限" // ja-JP
u"|validade" // pt-BR, pt-PT
u"|Срок действия карты"; // ru
-const char16_t kGiftCardRe[] = u"gift.?(card|cert)";
-const char16_t kDebitGiftCardRe[] =
+inline constexpr char16_t kGiftCardRe[] = u"gift.?(card|cert)";
+inline constexpr char16_t kDebitGiftCardRe[] =
u"(?:visa|mastercard|discover|amex|american express).*gift.?card";
-const char16_t kDebitCardRe[] = u"debit.*card";
-const char16_t kDayRe[] = u"day";
+inline constexpr char16_t kDebitCardRe[] = u"debit.*card";
+inline constexpr char16_t kDayRe[] = u"day";
/////////////////////////////////////////////////////////////////////////////
// email_field.cc
/////////////////////////////////////////////////////////////////////////////
-const char16_t kEmailRe[] =
+inline constexpr char16_t kEmailRe[] =
u"e.?mail"
u"|courriel" // fr
u"|correo.*electr(o|ó)nico" // es-ES
@@ -327,12 +326,12 @@ const char16_t kEmailRe[] =
/////////////////////////////////////////////////////////////////////////////
// name_field.cc
/////////////////////////////////////////////////////////////////////////////
-const char16_t kNameIgnoredRe[] =
+inline constexpr char16_t kNameIgnoredRe[] =
u"user.?name|user.?id|nickname|maiden name|title|prefix|suffix|mail"
u"|vollständiger.?name" // de-DE
u"|用户名" // zh-CN
u"|(?:사용자.?)?아이디|사용자.?ID"; // ko-KR
-const char16_t kFullNameRe[] =
+inline constexpr char16_t kFullNameRe[] =
u"^name|full.?name|your.?name|customer.?name|bill.?name|ship.?name"
u"|name.*first.*last|firstandlastname|contact.?(name|person)"
u"|nombre.*y.*apellidos" // es
@@ -345,11 +344,11 @@ const char16_t kFullNameRe[] =
u"|(\\b|_|\\*)ad[ı]? soyad[ı]?(\\b|_|\\*)" // tr
u"|성명" // ko-KR
u"|nama.?(lengkap|penerima|kamu)"; // id
-const char16_t kNameGenericRe[] =
+inline constexpr char16_t kNameGenericRe[] =
u"^name"
u"|^nom" // fr-FR
u"|^nome"; // pt-BR, pt-PT
-const char16_t kFirstNameRe[] =
+inline constexpr char16_t kFirstNameRe[] =
u"first.*name|initials|fname|first$|given.*name"
u"|vorname" // de-DE
u"|nombre" // es
@@ -363,9 +362,10 @@ const char16_t kFirstNameRe[] =
u"|(\\b|_|\\*)(isim|ad|ad(i|ı|iniz|ınız)?)(\\b|_|\\*)" // tr
u"|नाम" // hi
u"|nama depan"; // id
-const char16_t kMiddleInitialRe[] = u"middle.*initial|m\\.i\\.|mi$|\\bmi\\b";
-const char16_t kMiddleNameRe[] = u"middle.*name|mname|middle$";
-const char16_t kLastNameRe[] =
+inline constexpr char16_t kMiddleInitialRe[] =
+ u"middle.*initial|m\\.i\\.|mi$|\\bmi\\b";
+inline constexpr char16_t kMiddleNameRe[] = u"middle.*name|mname|middle$";
+inline constexpr char16_t kLastNameRe[] =
u"last.*name|lname|surname(?!\\d)|last$|secondname|family.*name"
u"|nachname" // de-DE
u"|apellidos?" // es
@@ -380,17 +380,17 @@ const char16_t kLastNameRe[] =
u"|(\\b|_|\\*)(soyisim|soyad(i|ı|iniz|ınız)?)(\\b|_|\\*)" // tr
u"|\\b성(?:[^명]|\\b)" // ko-KR
u"|nama belakang"; // id
-const char16_t kNameLastFirstRe[] =
+inline constexpr char16_t kNameLastFirstRe[] =
u"(primer.*apellido)" // es
u"|(apellido1)" // es
u"|(apellido.*paterno)" // es
u"|surname_?1|first(\\s|_)?surname"; // es
-const char16_t kNameLastSecondRe[] =
+inline constexpr char16_t kNameLastSecondRe[] =
u"(segund.*apellido)" // es
u"|(apellido2)" // es
u"|(apellido.*materno)" // es
u"|surname_?2|second(\\s|_)?surname"; // es
-const char16_t kHonorificPrefixRe[] =
+inline constexpr char16_t kHonorificPrefixRe[] =
u"anrede|titel" // de-DE
u"|tratamiento|encabezamiento" // es
u"|^title:?$" // Matched only if there is no prefix or suffix.
@@ -403,7 +403,7 @@ const char16_t kHonorificPrefixRe[] =
/////////////////////////////////////////////////////////////////////////////
// phone_field.cc
/////////////////////////////////////////////////////////////////////////////
-const char16_t kPhoneRe[] =
+inline constexpr char16_t kPhoneRe[] =
u"phone|mobile|contact.?number"
u"|telefonnummer" // de-DE
u"|telefono|teléfono" // es
@@ -417,22 +417,22 @@ const char16_t kPhoneRe[] =
u"|മൊബൈല്‍" // ml for mobile
u"|(?:전화|핸드폰|휴대폰|휴대전화)(?:.?번호)?" // ko-KR
u"|telepon|ponsel|(nomor|no\\.?).?(hp|handphone)"; // id
-const char16_t kAugmentedPhoneCountryCodeRe[] =
+inline constexpr char16_t kAugmentedPhoneCountryCodeRe[] =
u"^[^0-9+]*(?:\\+|00)\\s*([1-9]\\d{0,3})\\D*$";
-const char16_t kCountryCodeRe[] =
+inline constexpr char16_t kCountryCodeRe[] =
u"country.*code|ccode|_cc|phone.*code|user.*phone.*code";
-const char16_t kAreaCodeNotextRe[] = u"^\\($";
-const char16_t kAreaCodeRe[] =
+inline constexpr char16_t kAreaCodeNotextRe[] = u"^\\($";
+inline constexpr char16_t kAreaCodeRe[] =
u"area.*code|acode|area"
u"|지역.?번호"; // ko-KR
-const char16_t kPhonePrefixSeparatorRe[] = u"^-$|^\\)$";
-const char16_t kPhoneSuffixSeparatorRe[] = u"^-$";
-const char16_t kPhonePrefixRe[] =
+inline constexpr char16_t kPhonePrefixSeparatorRe[] = u"^-$|^\\)$";
+inline constexpr char16_t kPhoneSuffixSeparatorRe[] = u"^-$";
+inline constexpr char16_t kPhonePrefixRe[] =
u"prefix|exchange"
u"|preselection" // fr-FR
u"|ddd"; // pt-BR, pt-PT
-const char16_t kPhoneSuffixRe[] = u"suffix";
-const char16_t kPhoneExtensionRe[] =
+inline constexpr char16_t kPhoneSuffixRe[] = u"suffix";
+inline constexpr char16_t kPhoneExtensionRe[] =
u"\\bext|ext\\b|extension"
u"|ramal"; // pt-BR, pt-PT
@@ -440,20 +440,20 @@ const char16_t kPhoneExtensionRe[] =
// travel_field.cc
/////////////////////////////////////////////////////////////////////////////
-const char16_t kPassportRe[] =
+inline constexpr char16_t kPassportRe[] =
u"document.*number|passport" // en-US
u"|passeport" // fr-FR
u"|numero.*documento|pasaporte" // es-ES
u"|書類"; // ja-JP
-const char16_t kTravelOriginRe[] =
+inline constexpr char16_t kTravelOriginRe[] =
u"point.*of.*entry|arrival" // en-US
u"|punto.*internaci(o|ó)n|fecha.*llegada" // es-ES
u"|入国"; // ja-JP
-const char16_t kTravelDestinationRe[] =
+inline constexpr char16_t kTravelDestinationRe[] =
u"departure" // en-US
u"|fecha.*salida|destino" // es-ES
u"|出国"; // ja-JP
-const char16_t kFlightRe[] =
+inline constexpr char16_t kFlightRe[] =
u"airline|flight" // en-US
u"|aerol(i|í)nea|n(u|ú)mero.*vuelo" // es-ES
u"|便名|航空会社"; // ja-JP
@@ -461,7 +461,12 @@ const char16_t kFlightRe[] =
/////////////////////////////////////////////////////////////////////////////
// validation.cc
/////////////////////////////////////////////////////////////////////////////
-const char16_t kUPIVirtualPaymentAddressRe[] =
+
+// Used to match field data that might be a UPI Virtual Payment Address.
+// See:
+// - http://crbug.com/702220
+// - https://upipayments.co.in/virtual-payment-address-vpa/
+inline constexpr char16_t kUPIVirtualPaymentAddressRe[] =
u"^[\\w.+-_]+@(" // eg user@
u"\\w+\\.ifsc\\.npci|" // IFSC code
u"aadhaar\\.npci|" // Aadhaar number
@@ -576,44 +581,66 @@ const char16_t kUPIVirtualPaymentAddressRe[] =
u"yesbankltd"
u")$";
-const char16_t kInternationalBankAccountNumberRe[] =
+// Used to match the HTML name and label for International Bank Account Number
+// (IBAN).
+inline constexpr char16_t kIBANRe[] =
+ u"(\\biban(\\b|_)|international bank account number)";
+
+// Used to match field value that might be an International Bank Account Number.
+// TODO(crbug.com/977377): The regex doesn't match IBANs for Saint Lucia (LC),
+// Kazakhstan (KZ) and Romania (RO). Consider replace the regex with something
+// like "(?:IT|SM)\d{2}[A-Z]\d{22}|CY\d{2}[A-Z]\d{23}...". For reference:
+// - https://www.swift.com/resource/iban-registry-pdf
+inline constexpr char16_t kInternationalBankAccountNumberValueRe[] =
u"^[a-zA-Z]{2}[0-9]{2}[a-zA-Z0-9]{4}[0-9]{7}([a-zA-Z0-9]?){0,16}$";
// Matches all 3 and 4 digit numbers.
-const char16_t kCreditCardCVCPattern[] = u"^\\d{3,4}$";
+inline constexpr char16_t kCreditCardCVCPattern[] = u"^\\d{3,4}$";
// Matches numbers in the range [2010-2099].
-const char16_t kCreditCard4DigitExpYearPattern[] = u"^[2][0][1-9][0-9]$";
+inline constexpr char16_t kCreditCard4DigitExpYearPattern[] =
+ u"^[2][0][1-9][0-9]$";
/////////////////////////////////////////////////////////////////////////////
// form_structure.cc
/////////////////////////////////////////////////////////////////////////////
-const char16_t kUrlSearchActionRe[] = u"/search(/|((\\w*\\.\\w+)?$))";
+
+// Match the path values for form actions that look like generic search:
+// e.g. /search
+// /search/
+// /search/products...
+// /products/search/
+// /blah/search_all.jsp
+inline constexpr char16_t kUrlSearchActionRe[] =
+ u"/search(/|((\\w*\\.\\w+)?$))";
/////////////////////////////////////////////////////////////////////////////
// form_parser.cc
/////////////////////////////////////////////////////////////////////////////
-const char16_t kSocialSecurityRe[] = u"ssn|social.?security.?(num(ber)?|#)*";
-const char16_t kOneTimePwdRe[] =
+inline constexpr char16_t kSocialSecurityRe[] =
+ u"ssn|social.?security.?(num(ber)?|#)*";
+inline constexpr char16_t kOneTimePwdRe[] =
u"one.?time|sms.?(code|token|password|pwd|pass)";
// Matches strings that consist of one repeated non alphanumeric symbol,
// that is likely a result of website modifying the value to hide it.
-const char16_t kHiddenValueRe[] = u"^(\\W)\\1+$";
+inline constexpr char16_t kHiddenValueRe[] = u"^(\\W)\\1+$";
/////////////////////////////////////////////////////////////////////////////
// merchant_promo_code_field.cc
/////////////////////////////////////////////////////////////////////////////
// "promo code", "promotion code", "promotional code" are all acceptable
// keywords.
-const char16_t kMerchantPromoCodeRe[] =
+inline constexpr char16_t kMerchantPromoCodeRe[] =
u"(promo(tion|tional)?|gift|discount|coupon)[-_. ]*code";
/////////////////////////////////////////////////////////////////////////////
// votes_uploader.cc
/////////////////////////////////////////////////////////////////////////////
-const char16_t kEmailValueRe[] =
+inline constexpr char16_t kEmailValueRe[] =
u"^[a-zA-Z0-9.!#$%&’*+/=?^_`{|}~-]+@[a-zA-Z0-9-]+(?:\\.[a-zA-Z0-9-]+)*$";
-const char16_t kPhoneValueRe[] = u"^[0-9()+-]{6,25}$";
-const char16_t kUsernameLikeValueRe[] = u"[A-Za-z0-9_\\-.]{7,30}";
+inline constexpr char16_t kPhoneValueRe[] = u"^[0-9()+-]{6,25}$";
+inline constexpr char16_t kUsernameLikeValueRe[] = u"[A-Za-z0-9_\\-.]{7,30}";
} // namespace autofill
+
+#endif // COMPONENTS_AUTOFILL_CORE_BROWSER_AUTOFILL_REGEX_CONSTANTS_H_
diff --git a/chromium/components/autofill/core/common/autofill_regexes.cc b/chromium/components/autofill/core/common/autofill_regexes.cc
new file mode 100644
index 00000000000..b62c57a7a64
--- /dev/null
+++ b/chromium/components/autofill/core/common/autofill_regexes.cc
@@ -0,0 +1,96 @@
+// 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/common/autofill_regexes.h"
+
+#include <map>
+#include <memory>
+#include <string>
+#include <utility>
+
+#include "base/check.h"
+#include "base/i18n/unicodestring.h"
+#include "base/memory/ptr_util.h"
+
+namespace {
+
+// Maximum length of the string to match to avoid causing an icu::RegexMatcher
+// stack overflow. (crbug.com/1198219)
+constexpr int kMaxStringLength = 5000;
+
+} // namespace
+
+namespace autofill {
+
+std::unique_ptr<const icu::RegexPattern> CompileRegex(
+ base::StringPiece16 regex) {
+ const icu::UnicodeString icu_regex(false, regex.data(), regex.length());
+ UErrorCode status = U_ZERO_ERROR;
+ std::unique_ptr<icu::RegexPattern> regex_pattern = base::WrapUnique(
+ icu::RegexPattern::compile(icu_regex, UREGEX_CASE_INSENSITIVE, status));
+ DCHECK(U_SUCCESS(status));
+ return regex_pattern;
+}
+
+bool MatchesRegex(base::StringPiece16 input,
+ const icu::RegexPattern& regex_pattern,
+ std::vector<std::u16string>* groups) {
+ if (input.size() > kMaxStringLength)
+ return false;
+
+ UErrorCode status = U_ZERO_ERROR;
+ // `icu_input` must outlive `regex_matcher` because it holds a reference to
+ // it.
+ icu::UnicodeString icu_input(false, input.data(), input.length());
+ std::unique_ptr<icu::RegexMatcher> regex_matcher =
+ base::WrapUnique(regex_pattern.matcher(icu_input, status));
+ UBool matched = regex_matcher->find(0, status);
+ DCHECK(U_SUCCESS(status));
+
+ if (matched && groups) {
+ int32_t matched_groups = regex_matcher->groupCount();
+ groups->resize(matched_groups + 1);
+ for (int32_t i = 0; i < matched_groups + 1; ++i) {
+ icu::UnicodeString match_unicode = regex_matcher->group(i, status);
+ DCHECK(U_SUCCESS(status));
+ (*groups)[i] = base::i18n::UnicodeStringToString16(match_unicode);
+ }
+ }
+ return matched;
+}
+
+AutofillRegexCache::AutofillRegexCache(ThreadSafe thread_safe)
+ : thread_safe_(thread_safe) {
+ if (!thread_safe_)
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+}
+
+AutofillRegexCache::~AutofillRegexCache() {
+ if (!thread_safe_)
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+}
+
+const icu::RegexPattern* AutofillRegexCache::GetRegexPattern(
+ base::StringPiece16 regex) {
+ auto GetOrCreate = [&]() {
+ auto it = cache_.find(regex);
+ if (it == cache_.end()) {
+ bool success;
+ std::tie(it, success) =
+ cache_.emplace(std::u16string(regex), CompileRegex(regex));
+ DCHECK(success);
+ }
+ DCHECK(it != cache_.end());
+ DCHECK(it->second.get());
+ return it->second.get();
+ };
+ if (!thread_safe_) {
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+ return GetOrCreate();
+ }
+ base::AutoLock lock(lock_);
+ return GetOrCreate();
+}
+
+} // namespace autofill
diff --git a/chromium/components/autofill/core/common/autofill_regexes.h b/chromium/components/autofill/core/common/autofill_regexes.h
new file mode 100644
index 00000000000..d378abbf621
--- /dev/null
+++ b/chromium/components/autofill/core/common/autofill_regexes.h
@@ -0,0 +1,87 @@
+// 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_COMMON_AUTOFILL_REGEXES_H_
+#define COMPONENTS_AUTOFILL_CORE_COMMON_AUTOFILL_REGEXES_H_
+
+#include <map>
+#include <memory>
+#include <string>
+#include <vector>
+
+#include "base/no_destructor.h"
+#include "base/sequence_checker.h"
+#include "base/strings/string_piece.h"
+#include "base/synchronization/lock.h"
+#include "base/types/strong_alias.h"
+#include "third_party/icu/source/i18n/unicode/regex.h"
+
+namespace autofill {
+
+using ThreadSafe = base::StrongAlias<struct ThreadSafeTag, bool>;
+
+// Compiles a case-insensitive regular expression.
+//
+// The return icu::RegexPattern is thread-safe (because it's const and icu
+// guarantees thread-safety of the const functions). In particularly this
+// includes icu::RegexPattern::matcher().
+//
+// May also be used to initialize `static base::NoDestructor<icu::RegexPattern>`
+// function-scope variables.
+std::unique_ptr<const icu::RegexPattern> CompileRegex(
+ base::StringPiece16 regex);
+
+// Returns true if `regex` is found in `input`.
+// If `groups` is non-null, it gets resized and the found capture groups
+// are written into it.
+// Thread-safe.
+bool MatchesRegex(base::StringPiece16 input,
+ const icu::RegexPattern& regex_pattern,
+ std::vector<std::u16string>* groups = nullptr);
+
+// Calls MatchesRegex() after compiling the `regex` on the first call and
+// retrieving it from a static variable in subsequent calls.
+//
+// This function is thread-safe.
+template <const char16_t regex[]>
+bool MatchesRegex(base::StringPiece16 input,
+ std::vector<std::u16string>* groups = nullptr) {
+ static base::NoDestructor<std::unique_ptr<const icu::RegexPattern>>
+ regex_pattern(CompileRegex(regex));
+ return MatchesRegex(input, **regex_pattern, groups);
+}
+
+// A cache of compiled regex patterns. It can be configured to be thread-safe
+// (using a mutex) or not (in which case it uses a sequence checker).
+class AutofillRegexCache {
+ public:
+ explicit AutofillRegexCache(ThreadSafe thread_safe);
+ ~AutofillRegexCache();
+
+ AutofillRegexCache(const AutofillRegexCache&) = delete;
+ AutofillRegexCache& operator=(const AutofillRegexCache&) = delete;
+
+ // Returns the compiled regex corresponding to `regex`.
+ // This function is thread-safe if `thread_safe_`.
+ // The returned object is thread-safe in any case (because it's const).
+ // Although the returned pointer is guaranteed to be non-nullptr, we do not
+ // return a reference to avoid accidental copies.
+ const icu::RegexPattern* GetRegexPattern(base::StringPiece16 regex);
+
+ private:
+ // `MatchesPattern()` uses the lock if `thread_safe_`. Otherwise, it validates
+ // the sequence.
+ ThreadSafe thread_safe_{false};
+ base::Lock lock_;
+ SEQUENCE_CHECKER(sequence_checker_);
+
+ // Maps regex strings to their corresponding compiled regex patterns.
+ std::
+ map<std::u16string, std::unique_ptr<const icu::RegexPattern>, std::less<>>
+ cache_;
+};
+
+} // namespace autofill
+
+#endif // COMPONENTS_AUTOFILL_CORE_BROWSER_AUTOFILL_REGEXES_H_
diff --git a/chromium/components/autofill/core/browser/autofill_regexes_unittest.cc b/chromium/components/autofill/core/common/autofill_regexes_unittest.cc
index 236b9fc5288..dffad89354c 100644
--- a/chromium/components/autofill/core/browser/autofill_regexes_unittest.cc
+++ b/chromium/components/autofill/core/common/autofill_regexes_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_regexes.h"
+#include "components/autofill/core/common/autofill_regexes.h"
// Keep these tests in sync with
// components/autofill/core/browser/pattern_provider/default_regex_patterns_unittest.cc
@@ -12,12 +12,24 @@
#include <string>
-#include "components/autofill/core/browser/autofill_regex_constants.h"
+#include "base/strings/utf_string_conversions.h"
+#include "components/autofill/core/common/autofill_regex_constants.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace autofill {
+namespace {
+
+bool MatchesRegex(base::StringPiece16 input,
+ base::StringPiece16 regex,
+ std::vector<std::u16string>* groups = nullptr) {
+ static base::NoDestructor<AutofillRegexCache> cache(ThreadSafe(true));
+ return autofill::MatchesRegex(input, *cache->GetRegexPattern(regex), groups);
+}
+
+} // namespace
+
struct InputPatternTestCase {
const char16_t* const input;
const char16_t* const pattern;
@@ -28,12 +40,12 @@ class PositiveSampleTest : public testing::TestWithParam<InputPatternTestCase> {
TEST_P(PositiveSampleTest, SampleRegexes) {
auto test_case = GetParam();
- SCOPED_TRACE(test_case.input);
- SCOPED_TRACE(test_case.pattern);
- EXPECT_TRUE(MatchesPattern(test_case.input, test_case.pattern));
+ SCOPED_TRACE(base::UTF16ToUTF8(test_case.input));
+ SCOPED_TRACE(base::UTF16ToUTF8(test_case.pattern));
+ EXPECT_TRUE(MatchesRegex(test_case.input, test_case.pattern));
}
-INSTANTIATE_TEST_SUITE_P(AutofillRegexes,
+INSTANTIATE_TEST_SUITE_P(AutofillRegexesTest,
PositiveSampleTest,
testing::Values(
// Empty pattern
@@ -56,12 +68,12 @@ class NegativeSampleTest : public testing::TestWithParam<InputPatternTestCase> {
TEST_P(NegativeSampleTest, SampleRegexes) {
auto test_case = GetParam();
- SCOPED_TRACE(test_case.input);
- SCOPED_TRACE(test_case.pattern);
- EXPECT_FALSE(MatchesPattern(test_case.input, test_case.pattern));
+ SCOPED_TRACE(base::UTF16ToUTF8(test_case.input));
+ SCOPED_TRACE(base::UTF16ToUTF8(test_case.pattern));
+ EXPECT_FALSE(MatchesRegex(test_case.input, test_case.pattern));
}
-INSTANTIATE_TEST_SUITE_P(AutofillRegexes,
+INSTANTIATE_TEST_SUITE_P(AutofillRegexesTest,
NegativeSampleTest,
testing::Values(
// Empty string
@@ -90,7 +102,7 @@ TEST_P(CaptureTest, SampleRegexes) {
auto test_case = GetParam();
std::vector<std::u16string> groups;
EXPECT_EQ(test_case.matches,
- MatchesPattern(test_case.input, test_case.pattern, &groups));
+ MatchesRegex(test_case.input, test_case.pattern, &groups));
EXPECT_THAT(groups, testing::Eq(test_case.groups));
}
@@ -123,9 +135,9 @@ class ExpirationDate2DigitYearPositive
TEST_P(ExpirationDate2DigitYearPositive, ExpirationDate2DigitYearRegexes) {
auto test_case = GetParam();
- SCOPED_TRACE(test_case.input);
+ SCOPED_TRACE(base::UTF16ToUTF8(test_case.input));
const std::u16string pattern = kExpirationDate2DigitYearRe;
- EXPECT_TRUE(MatchesPattern(test_case.input, pattern));
+ EXPECT_TRUE(MatchesRegex(test_case.input, pattern));
}
INSTANTIATE_TEST_SUITE_P(
@@ -157,9 +169,9 @@ class ExpirationDate2DigitYearNegative
TEST_P(ExpirationDate2DigitYearNegative, ExpirationDate2DigitYearRegexes) {
auto test_case = GetParam();
- SCOPED_TRACE(test_case.input);
+ SCOPED_TRACE(base::UTF16ToUTF8(test_case.input));
const std::u16string pattern = kExpirationDate2DigitYearRe;
- EXPECT_FALSE(MatchesPattern(test_case.input, pattern));
+ EXPECT_FALSE(MatchesRegex(test_case.input, pattern));
}
INSTANTIATE_TEST_SUITE_P(
@@ -198,8 +210,8 @@ class ExpirationDate4DigitYearPositive
TEST_P(ExpirationDate4DigitYearPositive, ExpirationDate4DigitYearRegexes) {
auto test_case = GetParam();
const std::u16string pattern = kExpirationDate4DigitYearRe;
- SCOPED_TRACE(test_case.input);
- EXPECT_TRUE(MatchesPattern(test_case.input, pattern));
+ SCOPED_TRACE(base::UTF16ToUTF8(test_case.input));
+ EXPECT_TRUE(MatchesRegex(test_case.input, pattern));
}
INSTANTIATE_TEST_SUITE_P(AutofillRegexes,
@@ -233,8 +245,8 @@ class ExpirationDate4DigitYearNegative
TEST_P(ExpirationDate4DigitYearNegative, ExpirationDate4DigitYearRegexes) {
auto test_case = GetParam();
const std::u16string pattern = kExpirationDate4DigitYearRe;
- SCOPED_TRACE(test_case.input);
- EXPECT_FALSE(MatchesPattern(test_case.input, pattern));
+ SCOPED_TRACE(base::UTF16ToUTF8(test_case.input));
+ EXPECT_FALSE(MatchesRegex(test_case.input, pattern));
}
INSTANTIATE_TEST_SUITE_P(
@@ -271,9 +283,9 @@ class ZipCodePositive : public testing::TestWithParam<InputTestCase> {};
TEST_P(ZipCodePositive, ZipCodeRegexes) {
auto test_case = GetParam();
- SCOPED_TRACE(test_case.input);
+ SCOPED_TRACE(base::UTF16ToUTF8(test_case.input));
const std::u16string pattern = kZipCodeRe;
- EXPECT_TRUE(MatchesPattern(test_case.input, pattern));
+ EXPECT_TRUE(MatchesRegex(test_case.input, pattern));
}
INSTANTIATE_TEST_SUITE_P(AutofillRegexes,
@@ -286,9 +298,9 @@ class ZipCodeNegative : public testing::TestWithParam<InputTestCase> {};
TEST_P(ZipCodeNegative, ZipCodeRegexes) {
auto test_case = GetParam();
- SCOPED_TRACE(test_case.input);
+ SCOPED_TRACE(base::UTF16ToUTF8(test_case.input));
const std::u16string pattern = kZipCodeRe;
- EXPECT_FALSE(MatchesPattern(test_case.input, pattern));
+ EXPECT_FALSE(MatchesRegex(test_case.input, pattern));
}
INSTANTIATE_TEST_SUITE_P(
@@ -302,9 +314,9 @@ class Zip4Positive : public testing::TestWithParam<InputTestCase> {};
TEST_P(Zip4Positive, Zip4Regexes) {
auto test_case = GetParam();
- SCOPED_TRACE(test_case.input);
+ SCOPED_TRACE(base::UTF16ToUTF8(test_case.input));
const std::u16string pattern = kZip4Re;
- EXPECT_TRUE(MatchesPattern(test_case.input, pattern));
+ EXPECT_TRUE(MatchesRegex(test_case.input, pattern));
}
INSTANTIATE_TEST_SUITE_P(AutofillRegexes,
@@ -315,9 +327,9 @@ class Zip4Negative : public testing::TestWithParam<InputTestCase> {};
TEST_P(Zip4Negative, Zip4Regexes) {
auto test_case = GetParam();
- SCOPED_TRACE(test_case.input);
+ SCOPED_TRACE(base::UTF16ToUTF8(test_case.input));
const std::u16string pattern = kZip4Re;
- EXPECT_FALSE(MatchesPattern(test_case.input, pattern));
+ EXPECT_FALSE(MatchesRegex(test_case.input, pattern));
}
INSTANTIATE_TEST_SUITE_P(
diff --git a/chromium/components/autofill/core/common/autofill_util.h b/chromium/components/autofill/core/common/autofill_util.h
index 8ac75dcbf93..c48df5696b7 100644
--- a/chromium/components/autofill/core/common/autofill_util.h
+++ b/chromium/components/autofill/core/common/autofill_util.h
@@ -10,14 +10,11 @@
#include <string>
#include <vector>
+#include "base/feature_list.h"
#include "components/autofill/core/common/form_field_data.h"
#include "components/autofill/core/common/mojom/autofill_types.mojom-shared.h"
#include "url/gurl.h"
-namespace base {
-struct Feature;
-}
-
namespace autofill {
// The length of the GUIDs used for local autofill data. It is different than
diff --git a/chromium/components/autofill/core/common/form_data.h b/chromium/components/autofill/core/common/form_data.h
index 4574e8996fa..3b4285c820a 100644
--- a/chromium/components/autofill/core/common/form_data.h
+++ b/chromium/components/autofill/core/common/form_data.h
@@ -134,7 +134,22 @@ struct FrameTokenWithPredecessor {
// [4] https://html.spec.whatwg.org/multipage/input.html#attr-input-type
// clang-format on
struct FormData {
- // Returns true if all members of forms |a| and |b| are identical.
+ // Returns true if many members of forms |a| and |b| are identical.
+ //
+ // "Many" is intended to be "all", but currently the following members are not
+ // being compared:
+ //
+ // - FormData::button_titles,
+ // - FormData::full_url,
+ // - FormData::is_action_empty,
+ // - FormData::main_frame_origin,
+ // - FormData::host_frame,
+ // - FormData::version,
+ // - FormData::submission_event,
+ // - FormData::username_predictions,
+ // - FormData::is_gaia_with_skip_save_password_form,
+ // - FormData::frame_id,
+ // - some fields of FormFieldData (see FormFieldData::Equal()).
static bool DeepEqual(const FormData& a, const FormData& b);
FormData();
diff --git a/chromium/components/autofill/core/common/form_field_data.cc b/chromium/components/autofill/core/common/form_field_data.cc
index e0dd60f8d1f..d99449dc208 100644
--- a/chromium/components/autofill/core/common/form_field_data.cc
+++ b/chromium/components/autofill/core/common/form_field_data.cc
@@ -7,10 +7,13 @@
#include <algorithm>
#include <tuple>
+#include "base/notreached.h"
#include "base/pickle.h"
#include "base/strings/strcat.h"
+#include "base/strings/string_number_conversions.h"
#include "base/strings/string_piece.h"
#include "base/strings/string_util.h"
+#include "base/strings/utf_string_conversions.h"
#include "build/build_config.h"
#include "components/autofill/core/common/autofill_features.h"
#include "components/autofill/core/common/autofill_util.h"
@@ -26,6 +29,9 @@ namespace {
// deserialization routine from previous kFormFieldDataPickleVersion format.
const int kFormFieldDataPickleVersion = 9;
+// Default section name for the fields.
+static constexpr char kDefaultSection[] = "-default";
+
void WriteSelectOption(const SelectOption& option, base::Pickle* pickle) {
pickle->WriteString16(option.value);
pickle->WriteString16(option.content);
@@ -195,6 +201,7 @@ struct LabelInfo {
// Feature |kAutofillSkipComparingInferredLabels| weakens equivalence of
// labels: two labels are equivalent if they were inferred from the same
// type of tag other than a LABEL tag.
+ // TODO(crbug.com/1211834): The experiment seems dead; remove?
return base::FeatureList::IsEnabled(
features::kAutofillSkipComparingInferredLabels) &&
source != FormFieldData::LabelSource::kLabelTag &&
@@ -232,18 +239,134 @@ auto IdentityTuple(const FormFieldData& f) {
// uniquely identify the field as well.
return std::tuple_cat(
SimilarityTuple(f),
- std::tie(
-// TODO(crbug.com/896689): On iOS the unique_id member uniquely addresses
-// this field in the DOM.
-#if BUILDFLAG(IS_IOS)
- f.unique_id,
-#endif
- f.autocomplete_attribute, f.placeholder, f.max_length, f.css_classes,
- f.is_focusable, f.should_autocomplete, f.role, f.text_direction));
+ std::tie(f.autocomplete_attribute, f.placeholder, f.max_length,
+ f.css_classes, f.is_focusable, f.should_autocomplete, f.role,
+ f.text_direction));
}
} // namespace
+Section::Section() = default;
+Section::Section(const Section& section) = default;
+Section::~Section() = default;
+
+bool operator==(const Section::Autocomplete& a,
+ const Section::Autocomplete& b) {
+ return std::tie(a.section, a.mode) == std::tie(b.section, b.mode);
+}
+
+bool operator!=(const Section::Autocomplete& a,
+ const Section::Autocomplete& b) {
+ return !(a == b);
+}
+
+bool operator<(const Section::Autocomplete& a, const Section::Autocomplete& b) {
+ return std::tie(a.section, a.mode) < std::tie(b.section, b.mode);
+}
+
+bool operator==(const Section::FieldIdentifier& a,
+ const Section::FieldIdentifier& b) {
+ return std::tie(a.field_name, a.local_frame_id, a.field_renderer_id) ==
+ std::tie(b.field_name, b.local_frame_id, b.field_renderer_id);
+}
+
+bool operator!=(const Section::FieldIdentifier& a,
+ const Section::FieldIdentifier& b) {
+ return !(a == b);
+}
+
+bool operator<(const Section::FieldIdentifier& a,
+ const Section::FieldIdentifier& b) {
+ return std::tie(a.field_name, a.local_frame_id, a.field_renderer_id) <
+ std::tie(b.field_name, b.local_frame_id, b.field_renderer_id);
+}
+
+bool operator==(const Section& a, const Section& b) {
+ return std::tie(a.field_type_group_, a.prefix_) ==
+ std::tie(b.field_type_group_, b.prefix_);
+}
+
+bool operator!=(const Section& a, const Section& b) {
+ return !(a == b);
+}
+
+bool operator<(const Section& a, const Section& b) {
+ return std::tie(a.field_type_group_, a.prefix_) <
+ std::tie(b.field_type_group_, b.prefix_);
+}
+
+bool Section::is_from_autocomplete() const {
+ return absl::holds_alternative<Autocomplete>(prefix_);
+}
+
+void Section::set_field_type_group(FieldTypeGroupSuffix field_type_group) {
+ field_type_group_ = field_type_group;
+}
+
+void Section::SetPrefixToCreditCard() {
+ prefix_ = CreditCard();
+}
+
+bool Section::SetPrefixFromAutocomplete(Autocomplete autocomplete) {
+ if (autocomplete.section.empty() && autocomplete.mode == HTML_MODE_NONE)
+ return false;
+ prefix_ = std::move(autocomplete);
+ return true;
+}
+
+void Section::SetPrefixFromFieldIdentifier(
+ const FormFieldData& field,
+ base::flat_map<LocalFrameToken, size_t>& frame_token_ids) {
+ size_t generated_frame_id =
+ frame_token_ids.emplace(field.host_frame, frame_token_ids.size())
+ .first->second;
+ prefix_ = FieldIdentifier(base::UTF16ToUTF8(field.name), generated_frame_id,
+ field.unique_renderer_id);
+}
+
+std::string Section::ToString() const {
+ std::string section_name;
+ if (const Autocomplete* autocomplete = absl::get_if<Autocomplete>(&prefix_)) {
+ // To prevent potential section name collisions, append `kDefaultSection`
+ // suffix to fields without a `HtmlFieldMode`. Without this, 'autocomplete'
+ // attribute values "section--shipping street-address" and "shipping
+ // street-address" would have the same prefix.
+ section_name =
+ autocomplete->section +
+ (autocomplete->mode != HTML_MODE_NONE
+ ? "-" + std::string(HtmlFieldModeToStringPiece(autocomplete->mode))
+ : kDefaultSection);
+ } else if (const FieldIdentifier* f =
+ absl::get_if<FieldIdentifier>(&prefix_)) {
+ FieldIdentifier field_identifier = *f;
+ section_name = base::StrCat(
+ {field_identifier.field_name, "_",
+ base::NumberToString(field_identifier.local_frame_id), "_",
+ base::NumberToString(field_identifier.field_renderer_id.value())});
+ } else if (absl::holds_alternative<CreditCard>(prefix_)) {
+ section_name = "credit-card";
+ }
+
+ section_name = section_name.empty() ? kDefaultSection : section_name;
+ switch (field_type_group_) {
+ case FieldTypeGroupSuffix::kNoGroup:
+ return section_name;
+ case FieldTypeGroupSuffix::kDefault:
+ return section_name + kDefaultSection;
+ case FieldTypeGroupSuffix::kCreditCard:
+ return section_name + "-cc";
+ }
+ NOTREACHED();
+}
+
+LogBuffer& operator<<(LogBuffer& buffer, const Section& section) {
+ return buffer << section.ToString();
+}
+
+std::ostream& operator<<(std::ostream& os, const Section& section) {
+ return os << section.ToString();
+}
+
FormFieldData::FormFieldData() = default;
FormFieldData::FormFieldData(const FormFieldData&) = default;
diff --git a/chromium/components/autofill/core/common/form_field_data.h b/chromium/components/autofill/core/common/form_field_data.h
index de784bca427..8214c437d73 100644
--- a/chromium/components/autofill/core/common/form_field_data.h
+++ b/chromium/components/autofill/core/common/form_field_data.h
@@ -14,6 +14,7 @@
#include "base/i18n/rtl.h"
#include "build/build_config.h"
+#include "components/autofill/core/common/html_field_types.h"
#include "components/autofill/core/common/mojom/autofill_types.mojom-shared.h"
#include "components/autofill/core/common/signatures.h"
#include "components/autofill/core/common/unique_ids.h"
@@ -63,6 +64,103 @@ struct SelectOption {
std::u16string content;
};
+// Stores information about the section of the field.
+class Section {
+ public:
+ // In the second pass of `FormStructure::IdentifySections()`, a suffix is
+ // added to the legacy section string based on the field type group.
+ enum class FieldTypeGroupSuffix : uint8_t { kNoGroup, kDefault, kCreditCard };
+
+ struct Autocomplete {
+ std::string section;
+ HtmlFieldMode mode;
+ };
+
+ using Default = base::StrongAlias<struct DefaultTag, absl::monostate>;
+
+ // TODO(crbug.com/1153539): Remove when sectioning is redesigned.
+ using CreditCard = base::StrongAlias<struct CreditCardTag, absl::monostate>;
+
+ struct FieldIdentifier {
+ FieldIdentifier() = default;
+ FieldIdentifier(std::string field_name,
+ size_t local_frame_id,
+ FieldRendererId field_renderer_id)
+ : field_name(std::move(field_name)),
+ local_frame_id(local_frame_id),
+ field_renderer_id(field_renderer_id) {}
+
+ friend bool operator==(const FieldIdentifier& a, const FieldIdentifier& b);
+ friend bool operator!=(const FieldIdentifier& a, const FieldIdentifier& b);
+ friend bool operator<(const FieldIdentifier& a, const FieldIdentifier& b);
+
+ std::string field_name;
+ size_t local_frame_id;
+ FieldRendererId field_renderer_id;
+ };
+
+ // Represents the prefix of the section's name. The type of the variant
+ // represents the origin of the prefix:
+ // - `Default` is the empty, initial value before running any sectioning
+ // algorithm,
+ // - `Autocomplete` represents a prefix derived from the autocomplete
+ // attribute,
+ // - `FieldIdentifier` represents a prefix generated from the first field in
+ // the section,
+ // - `CreditCard` represents the credit card prefix generated by
+ // FormStructure::IdentifySections().
+ //
+ // TODO(crbug.com/1153539): Remove CreditCard when sectioning is redesigned.
+ using SectionPrefix =
+ absl::variant<Default, Autocomplete, FieldIdentifier, CreditCard>;
+
+ friend bool operator==(const Section& a, const Section& b);
+ friend bool operator!=(const Section& a, const Section& b);
+ friend bool operator<(const Section& a, const Section& b);
+
+ Section();
+ Section(const Section& section);
+ ~Section();
+
+ bool is_from_autocomplete() const;
+
+ void set_field_type_group(FieldTypeGroupSuffix field_type_group);
+ void SetPrefixToCreditCard();
+ bool SetPrefixFromAutocomplete(Autocomplete autocomplete);
+
+ // Sets the section prefix based on the field identifiers: the field's name,
+ // mapped frame id, renderer id. We do not use LocalFrameTokens but instead
+ // map them to consecutive integers using `frame_token_ids`, which uniquely
+ // identify a frame within a given FormStructure. Since we do not intend to
+ // compare sections from different FormStructures, this is sufficient.
+ //
+ // We intentionally do not include the LocalFrameToken in the section
+ // because frame tokens should not be sent to a renderer.
+ //
+ // TODO(crbug.com/1257141): Remove special handling of FrameTokens.
+ void SetPrefixFromFieldIdentifier(
+ const FormFieldData& field,
+ base::flat_map<LocalFrameToken, size_t>& frame_token_ids);
+
+ // Reconstructs `this` to a string. The string representation of the section
+ // is used in the renderer.
+ // TODO(crbug/1257141): Remove when fixed.
+ std::string ToString() const;
+
+ private:
+ friend struct mojo::StructTraits<autofill::mojom::SectionDataView,
+ autofill::Section>;
+
+ // The `kNoGroup` is assigned in the beginning, as
+ // `FormStructure::IdentifySections()` was not run yet.
+ FieldTypeGroupSuffix field_type_group_ = FieldTypeGroupSuffix::kNoGroup;
+
+ SectionPrefix prefix_;
+};
+
+LogBuffer& operator<<(LogBuffer& buffer, const Section& section);
+std::ostream& operator<<(std::ostream& os, const Section& section);
+
// Stores information about a field in a form. Read more about forms and fields
// at FormData.
struct FormFieldData {
@@ -70,7 +168,31 @@ struct FormFieldData {
using RoleAttribute = mojom::FormFieldData_RoleAttribute;
using LabelSource = mojom::FormFieldData_LabelSource;
- // Returns true if all members of fields |a| and |b| are identical.
+ // Returns true if many members of fields |a| and |b| are identical.
+ //
+ // "Many" is intended to be "all", but currently the following members are not
+ // being compared:
+ //
+ // - FormFieldData::value,
+ // - FormFieldData::aria_label,
+ // - FormFieldData::aria_description,
+ // - FormFieldData::host_frame,
+ // - FormFieldData::host_form_id,
+ // - FormFieldData::host_form_signature,
+ // - FormFieldData::origin,
+ // - FormFieldData::force_override,
+ // - FormFieldData::form_control_ax_id,
+ // - FormFieldData::section,
+ // - FormFieldData::is_autofilled,
+ // - FormFieldData::properties_mask,
+ // - FormFieldData::is_enabled,
+ // - FormFieldData::is_readonly,
+ // - FormFieldData::user_input,
+ // - FormFieldData::options,
+ // - FormFieldData::label_source,
+ // - FormFieldData::bounds,
+ // - FormFieldData::datalist_values,
+ // - FormFieldData::datalist_labels.
static bool DeepEqual(const FormFieldData& a, const FormFieldData& b);
FormFieldData();
@@ -85,9 +207,10 @@ struct FormFieldData {
FieldGlobalId global_id() const { return {host_frame, unique_renderer_id}; }
// An identifier of the renderer form that contained this field.
- // This may be from the browser form that contains this field in the case of a
- // frame-transcending form. See ContentAutofillRouter and internal::FormForest
- // for details on the distinction between renderer and browser forms.
+ // This may be different from the browser form that contains this field in the
+ // case of a frame-transcending form. See ContentAutofillRouter and
+ // internal::FormForest for details on the distinction between renderer and
+ // browser forms.
FormGlobalId renderer_form_id() const { return {host_frame, host_form_id}; }
// TODO(crbug/1211834): This function is deprecated. Use
@@ -123,26 +246,10 @@ struct FormFieldData {
return is_focusable && role != RoleAttribute::kPresentation;
}
- // These functions do not work for Autofill code.
- // TODO(https://crbug.com/1006745): Fix this.
bool DidUserType() const;
bool HadFocus() const;
bool WasAutofilled() const;
-#if BUILDFLAG(IS_IOS)
- // The identifier which uniquely addresses this field in the DOM. This is an
- // ephemeral value which is not guaranteed to be stable across page loads. It
- // serves to allow a given field to be found during the current navigation.
- //
- // TODO(crbug.com/896689): Expand the logic/application of this to other
- // platforms and/or merge this concept with |unique_renderer_id|.
- std::u16string unique_id;
-#define EXPECT_EQ_UNIQUE_ID(expected, actual) \
- EXPECT_EQ((expected).unique_id, (actual).unique_id)
-#else
-#define EXPECT_EQ_UNIQUE_ID(expected, actual)
-#endif
-
// NOTE: update SameFieldAs() if needed when adding new a member.
// NOTE: update SimilarFieldAs() if needed when adding new a member.
// NOTE: update DynamicallySameFieldAs() if needed when adding new a member.
@@ -197,7 +304,7 @@ struct FormFieldData {
// The unique identifier of the section (e.g. billing vs. shipping address)
// of this field.
- std::string section;
+ Section section;
// Note: we use uint64_t instead of size_t because this struct is sent over
// IPC which could span 32 & 64 bit processes. We chose uint64_t instead of
@@ -262,7 +369,6 @@ std::ostream& operator<<(std::ostream& os, const FormFieldData& field);
// TODO(crbug.com/1208354): Replace this with FormData::DeepEqual().
#define EXPECT_FORM_FIELD_DATA_EQUALS(expected, actual) \
do { \
- EXPECT_EQ_UNIQUE_ID(expected, actual); \
EXPECT_EQ(expected.label, actual.label); \
EXPECT_EQ(expected.name, actual.name); \
EXPECT_EQ(expected.value, actual.value); \
diff --git a/chromium/components/autofill/core/common/html_field_types.cc b/chromium/components/autofill/core/common/html_field_types.cc
new file mode 100644
index 00000000000..d54928a2b29
--- /dev/null
+++ b/chromium/components/autofill/core/common/html_field_types.cc
@@ -0,0 +1,23 @@
+// Copyright 2022 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/common/html_field_types.h"
+
+#include "base/notreached.h"
+#include "base/strings/string_piece.h"
+
+namespace autofill {
+
+base::StringPiece HtmlFieldModeToStringPiece(HtmlFieldMode mode) {
+ switch (mode) {
+ case HTML_MODE_NONE:
+ return "";
+ case HTML_MODE_BILLING:
+ return "billing";
+ case HTML_MODE_SHIPPING:
+ return "shipping";
+ }
+ NOTREACHED();
+}
+
+} // namespace autofill
diff --git a/chromium/components/autofill/core/common/html_field_types.h b/chromium/components/autofill/core/common/html_field_types.h
new file mode 100644
index 00000000000..0cfcdfe2d45
--- /dev/null
+++ b/chromium/components/autofill/core/common/html_field_types.h
@@ -0,0 +1,115 @@
+// Copyright 2022 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_COMMON_HTML_FIELD_TYPES_H_
+#define COMPONENTS_AUTOFILL_CORE_COMMON_HTML_FIELD_TYPES_H_
+
+#include <stdint.h>
+#include "base/strings/string_piece_forward.h"
+
+namespace autofill {
+
+// The list of all HTML autocomplete field type hints supported by Chrome.
+// See [ http://is.gd/whatwg_autocomplete ] for the full list of specced hints.
+enum HtmlFieldType {
+ // Default type.
+ HTML_TYPE_UNSPECIFIED,
+
+ // Name types.
+ HTML_TYPE_NAME,
+ HTML_TYPE_HONORIFIC_PREFIX,
+ HTML_TYPE_GIVEN_NAME,
+ HTML_TYPE_ADDITIONAL_NAME,
+ HTML_TYPE_FAMILY_NAME,
+
+ // Business types.
+ HTML_TYPE_ORGANIZATION,
+
+ // Address types.
+ HTML_TYPE_STREET_ADDRESS,
+ HTML_TYPE_ADDRESS_LINE1,
+ HTML_TYPE_ADDRESS_LINE2,
+ HTML_TYPE_ADDRESS_LINE3,
+ HTML_TYPE_ADDRESS_LEVEL1, // For U.S. addresses, corresponds to the state.
+ HTML_TYPE_ADDRESS_LEVEL2, // For U.S. addresses, corresponds to the city.
+ HTML_TYPE_ADDRESS_LEVEL3, // An area that is more specific than LEVEL2.
+ HTML_TYPE_COUNTRY_CODE, // The ISO 3166-1-alpha-2 country code.
+ HTML_TYPE_COUNTRY_NAME, // The localized country name.
+ HTML_TYPE_POSTAL_CODE,
+ HTML_TYPE_FULL_ADDRESS, // The complete address, formatted for display.
+
+ // Credit card types.
+ HTML_TYPE_CREDIT_CARD_NAME_FULL,
+ HTML_TYPE_CREDIT_CARD_NAME_FIRST,
+ HTML_TYPE_CREDIT_CARD_NAME_LAST,
+ HTML_TYPE_CREDIT_CARD_NUMBER,
+ HTML_TYPE_CREDIT_CARD_EXP,
+ HTML_TYPE_CREDIT_CARD_EXP_MONTH,
+ HTML_TYPE_CREDIT_CARD_EXP_YEAR,
+ HTML_TYPE_CREDIT_CARD_VERIFICATION_CODE,
+ HTML_TYPE_CREDIT_CARD_TYPE,
+
+ // Phone number types.
+ HTML_TYPE_TEL,
+ HTML_TYPE_TEL_COUNTRY_CODE,
+ HTML_TYPE_TEL_NATIONAL,
+ HTML_TYPE_TEL_AREA_CODE,
+ HTML_TYPE_TEL_LOCAL,
+ HTML_TYPE_TEL_LOCAL_PREFIX,
+ HTML_TYPE_TEL_LOCAL_SUFFIX,
+ HTML_TYPE_TEL_EXTENSION,
+
+ // Email.
+ HTML_TYPE_EMAIL,
+
+ // Birthdate.
+ HTML_TYPE_BIRTHDATE_DAY,
+ HTML_TYPE_BIRTHDATE_MONTH,
+ HTML_TYPE_BIRTHDATE_YEAR,
+
+ // Transaction details.
+ HTML_TYPE_TRANSACTION_AMOUNT,
+ HTML_TYPE_TRANSACTION_CURRENCY,
+
+ // Variants of type hints specified in the HTML specification that are
+ // inferred based on a field's 'maxlength' attribute.
+ // TODO(isherman): Remove these types, in favor of understanding maxlength
+ // when filling fields. See also: AutofillField::phone_part_.
+ HTML_TYPE_ADDITIONAL_NAME_INITIAL,
+ HTML_TYPE_CREDIT_CARD_EXP_DATE_2_DIGIT_YEAR,
+ HTML_TYPE_CREDIT_CARD_EXP_DATE_4_DIGIT_YEAR,
+ HTML_TYPE_CREDIT_CARD_EXP_2_DIGIT_YEAR,
+ HTML_TYPE_CREDIT_CARD_EXP_4_DIGIT_YEAR,
+
+ // Universal Payment Interface - Virtual Payment Address.
+ HTML_TYPE_UPI_VPA,
+
+ // Phone number verification one-time-codes.
+ HTML_TYPE_ONE_TIME_CODE,
+
+ // Promo code for merchant sites.
+ HTML_TYPE_MERCHANT_PROMO_CODE,
+
+ // International Bank Account Number (IBAN) for banking and merchant sites.
+ HTML_TYPE_IBAN,
+
+ // Non-standard autocomplete types.
+ HTML_TYPE_UNRECOGNIZED,
+};
+
+// The list of all HTML autocomplete field mode hints supported by Chrome.
+// See [ http://is.gd/whatwg_autocomplete ] for the full list of specced hints.
+enum HtmlFieldMode : uint8_t {
+ HTML_MODE_NONE,
+ HTML_MODE_BILLING,
+ HTML_MODE_SHIPPING,
+};
+
+// Maps HTML_MODE_BILLING and HTML_MODE_SHIPPING to their string constants, as
+// specified in the autocomplete standard.
+base::StringPiece HtmlFieldModeToStringPiece(HtmlFieldMode mode);
+
+} // namespace autofill
+
+#endif // COMPONENTS_AUTOFILL_CORE_COMMON_HTML_FIELD_TYPES_H_
diff --git a/chromium/components/autofill/core/common/logging/log_buffer.cc b/chromium/components/autofill/core/common/logging/log_buffer.cc
index 7f2dffbebf6..c8d955c3f7e 100644
--- a/chromium/components/autofill/core/common/logging/log_buffer.cc
+++ b/chromium/components/autofill/core/common/logging/log_buffer.cc
@@ -13,40 +13,40 @@ namespace autofill {
namespace {
-bool IsElement(const base::Value& value) {
- const std::string* type = value.FindStringKey("type");
+bool IsElement(const base::Value::Dict& value) {
+ const std::string* type = value.FindString("type");
return type && *type == "element";
}
-bool IsTextNode(const base::Value& value) {
- const std::string* type = value.FindStringKey("type");
+bool IsTextNode(const base::Value::Dict& value) {
+ const std::string* type = value.FindString("type");
return type && *type == "text";
}
-bool IsFragment(const base::Value& value) {
- const std::string* type = value.FindStringKey("type");
+bool IsFragment(const base::Value::Dict& value) {
+ const std::string* type = value.FindString("type");
return type && *type == "fragment";
}
-void AppendChildToLastNode(std::vector<base::Value>* buffer,
- base::Value&& new_child) {
+void AppendChildToLastNode(std::vector<base::Value::Dict>* buffer,
+ base::Value::Dict&& new_child) {
if (buffer->empty()) {
buffer->push_back(std::move(new_child));
return;
}
- base::Value& parent = buffer->back();
+ base::Value::Dict& parent = buffer->back();
// Elements and Fragments can have children, but TextNodes cannot.
DCHECK(!IsTextNode(parent));
- if (auto* children = parent.FindListKey("children")) {
+ if (auto* children = parent.FindList("children")) {
children->Append(std::move(new_child));
return;
}
base::Value::List list;
list.Append(std::move(new_child));
- parent.SetKey("children", base::Value(std::move(list)));
+ parent.Set("children", std::move(list));
}
// This is an optimization to reduce the number of text nodes in the DOM.
@@ -57,40 +57,41 @@ void AppendChildToLastNode(std::vector<base::Value>* buffer,
//
// If the last child of the element in buffer is a text node, append |text| to
// it and return true (successful coalescing). Otherwise return false.
-bool TryCoalesceString(std::vector<base::Value>* buffer,
+bool TryCoalesceString(std::vector<base::Value::Dict>* buffer,
base::StringPiece text) {
if (buffer->empty())
return false;
- base::Value& parent = buffer->back();
- auto* children = parent.FindListKey("children");
+ base::Value::Dict& parent = buffer->back();
+ auto* children = parent.FindList("children");
if (!children)
return false;
- DCHECK(!children->GetListDeprecated().empty());
- auto& last_child = children->GetListDeprecated().back();
+ DCHECK(!children->empty());
+ auto& last_child = children->back().GetDict();
if (!IsTextNode(last_child))
return false;
- std::string* old_text = last_child.FindStringKey("value");
+ std::string* old_text = last_child.FindString("value");
old_text->append(text.data(), text.size());
return true;
}
-base::Value CreateEmptyFragment() {
+base::Value::Dict CreateEmptyFragment() {
base::Value::Dict dict;
dict.Set("type", "fragment");
- return base::Value(std::move(dict));
+ return dict;
}
} // namespace
-LogBuffer::LogBuffer() {
- buffer_.push_back(CreateEmptyFragment());
+LogBuffer::LogBuffer(IsActive active) : active_(*active) {
+ if (active_)
+ buffer_.push_back(CreateEmptyFragment());
}
LogBuffer::LogBuffer(LogBuffer&& other) noexcept = default;
LogBuffer& LogBuffer::operator=(LogBuffer&& other) = default;
LogBuffer::~LogBuffer() = default;
-base::Value LogBuffer::RetrieveResult() {
+absl::optional<base::Value::Dict> LogBuffer::RetrieveResult() {
// The buffer should always start with a fragment.
DCHECK(buffer_.size() >= 1);
@@ -98,14 +99,15 @@ base::Value LogBuffer::RetrieveResult() {
while (buffer_.size() > 1)
*this << CTag{};
- auto* children = buffer_[0].FindListKey("children");
- if (!children || children->GetListDeprecated().empty())
- return base::Value();
+ auto* children = buffer_[0].FindList("children");
+ if (!children || children->empty())
+ return absl::nullopt;
// If the fragment has a single child, remove it from |children| and return
// that directly.
- if (children->GetListDeprecated().size() == 1) {
- return std::move(std::move(*children).TakeListDeprecated().back());
+ if (children->size() == 1) {
+ return absl::optional<base::Value::Dict>(
+ std::move((*children).back().GetDict()));
}
return std::exchange(buffer_.back(), CreateEmptyFragment());
@@ -129,7 +131,7 @@ LogBuffer& operator<<(LogBuffer& buf, CTag&& tag) {
if (buf.buffer_.size() <= 1)
return buf;
- base::Value node_to_add = std::move(buf.buffer_.back());
+ base::Value::Dict node_to_add = std::move(buf.buffer_.back());
buf.buffer_.pop_back();
AppendChildToLastNode(&buf.buffer_, std::move(node_to_add));
@@ -140,16 +142,15 @@ LogBuffer& operator<<(LogBuffer& buf, Attrib&& attrib) {
if (!buf.active())
return buf;
- base::Value& node = buf.buffer_.back();
+ base::Value::Dict& node = buf.buffer_.back();
DCHECK(IsElement(node));
- if (auto* attributes = node.FindDictKey("attributes")) {
- attributes->SetKey(std::move(attrib.name),
- base::Value(std::move(attrib.value)));
+ if (auto* attributes = node.FindDict("attributes")) {
+ attributes->Set(attrib.name, std::move(attrib.value));
} else {
base::Value::Dict dict;
dict.Set(attrib.name, std::move(attrib.value));
- node.SetKey("attributes", base::Value(std::move(dict)));
+ node.Set("attributes", std::move(dict));
}
return buf;
@@ -171,12 +172,11 @@ LogBuffer& operator<<(LogBuffer& buf, base::StringPiece text) {
if (TryCoalesceString(&buf.buffer_, text))
return buf;
- base::Value::Dict dict;
- dict.Set("type", "text");
+ base::Value::Dict node_to_add;
+ node_to_add.Set("type", "text");
// This text is not HTML escaped because the rest of the frame work takes care
// of that and it must not be escaped twice.
- dict.Set("value", text);
- base::Value node_to_add(std::move(dict));
+ node_to_add.Set("value", text);
AppendChildToLastNode(&buf.buffer_, std::move(node_to_add));
return buf;
}
@@ -189,19 +189,21 @@ LogBuffer& operator<<(LogBuffer& buf, LogBuffer&& buffer) {
if (!buf.active())
return buf;
- base::Value node_to_add(buffer.RetrieveResult());
- if (node_to_add.is_none())
+ absl::optional<base::Value::Dict> node_to_add = buffer.RetrieveResult();
+ if (!node_to_add)
return buf;
- if (IsFragment(node_to_add)) {
- auto* children = node_to_add.FindListKey("children");
+ if (IsFragment(*node_to_add)) {
+ auto* children = node_to_add->FindList("children");
if (!children)
return buf;
- for (auto& child : children->GetListDeprecated())
- AppendChildToLastNode(&buf.buffer_, std::exchange(child, base::Value()));
+ for (auto& child : *children) {
+ AppendChildToLastNode(
+ &buf.buffer_, std::exchange(child.GetDict(), base::Value::Dict()));
+ }
return buf;
}
- AppendChildToLastNode(&buf.buffer_, std::move(node_to_add));
+ AppendChildToLastNode(&buf.buffer_, std::move(*node_to_add));
return buf;
}
@@ -242,7 +244,7 @@ namespace {
template <typename T, typename CharT = typename T::value_type>
LogBuffer HighlightValueInternal(T haystack, T needle) {
using StringPieceT = base::BasicStringPiece<CharT>;
- LogBuffer buffer;
+ LogBuffer buffer(LogBuffer::IsActive(true));
size_t pos = haystack.find(needle);
if (pos == StringPieceT::npos || needle.empty()) {
buffer << haystack;
diff --git a/chromium/components/autofill/core/common/logging/log_buffer.h b/chromium/components/autofill/core/common/logging/log_buffer.h
index a71b15613ba..c1f8e280438 100644
--- a/chromium/components/autofill/core/common/logging/log_buffer.h
+++ b/chromium/components/autofill/core/common/logging/log_buffer.h
@@ -12,7 +12,9 @@
#include "base/memory/raw_ptr.h"
#include "base/strings/string_number_conversions.h"
#include "base/strings/string_piece.h"
+#include "base/types/strong_alias.h"
#include "base/values.h"
+#include "components/autofill/core/common/logging/log_macros.h"
#include "url/gurl.h"
// The desired pattern to generate log messages is to pass a scope, a log
@@ -46,6 +48,21 @@
// LogBuffer buffer;
// for (...) { buffer << something; }
// LogBuffer() << std::move(buffer);
+//
+// In practice the LogBuffer requires a boolean parameter indicating whether
+// logging should happen. You should rely on
+// components/autofill/core/common/logging/log_macros.h and follow one of the
+// following patterns:
+//
+// (1) void MyFunction(LogManager* log_manager) {
+// LOG_AF(log_mannager) << "foobar";
+// }
+// (2) void MyFunction(LogManager* log_manager) {
+// LogBuffer buffer(
+// /*active=*/ log_manager && log_manager->IsLoggingActive());
+// LOG_AF(buffer) << "foobar";
+// LOG_AF(log_manager) << std::move(buffer);
+// }
namespace autofill {
@@ -76,11 +93,15 @@ struct Br {};
// See LogTableRowBuffer below.
struct Tr {};
+class LogManager;
+
// A buffer into which you can stream values. See the top of this header file
// for samples.
class LogBuffer {
public:
- LogBuffer();
+ using IsActive = base::StrongAlias<struct ActiveTag, bool>;
+
+ explicit LogBuffer(IsActive active = IsActive(true));
~LogBuffer();
LogBuffer(LogBuffer&& other) noexcept;
@@ -89,13 +110,12 @@ class LogBuffer {
LogBuffer(const LogBuffer& other) = delete;
LogBuffer& operator=(const LogBuffer& other) = delete;
- // Returns the contents of the buffer and empties it.
- base::Value RetrieveResult();
+ // Returns the contents of the buffer if any and empties it.
+ absl::optional<base::Value::Dict> RetrieveResult();
// Returns whether an active WebUI is listening. If false, the buffer may
// not do any logging.
bool active() const { return active_; }
- void set_active(bool active) { active_ = active; }
private:
friend LogBuffer& operator<<(LogBuffer& buf, Tag&& tag);
@@ -114,7 +134,7 @@ class LogBuffer {
// constructed. Once it is read (i.e. closed via a CTag), it is popped from
// the stack and attached as a child of the previously second last element.
// Only the first element of buffer_ is a 'fragment' and it is never closed.
- std::vector<base::Value> buffer_;
+ std::vector<base::Value::Dict> buffer_;
bool active_ = true;
};
@@ -205,6 +225,36 @@ LogBuffer HighlightValue(base::StringPiece haystack, base::StringPiece needle);
LogBuffer HighlightValue(base::StringPiece16 haystack,
base::StringPiece16 needle);
+namespace internal {
+
+// Traits for LOG_AF() macro for `LogBuffer*`.
+template <typename T>
+struct LoggerTraits<
+ T,
+ typename std::enable_if_t<
+ std::is_convertible_v<decltype(std::declval<T>()), const LogBuffer*>>> {
+ static bool active(const LogBuffer* log_buffer) {
+ return log_buffer && log_buffer->active();
+ }
+
+ static LogBuffer& get_stream(LogBuffer* log_buffer) { return *log_buffer; }
+};
+
+// Traits for LOG_AF() macro for `LogBuffer&`.
+template <typename T>
+struct LoggerTraits<
+ T,
+ typename std::enable_if_t<
+ std::is_convertible_v<decltype(std::declval<T>()), const LogBuffer&>>> {
+ static bool active(const LogBuffer& log_buffer) {
+ return log_buffer.active();
+ }
+
+ static LogBuffer& get_stream(LogBuffer& log_buffer) { return log_buffer; }
+};
+
+} // namespace internal
+
} // namespace autofill
#endif // COMPONENTS_AUTOFILL_CORE_COMMON_LOGGING_LOG_BUFFER_H_
diff --git a/chromium/components/autofill/core/common/logging/log_buffer_unittest.cc b/chromium/components/autofill/core/common/logging/log_buffer_unittest.cc
index b1ce2386f2a..3083fdd6098 100644
--- a/chromium/components/autofill/core/common/logging/log_buffer_unittest.cc
+++ b/chromium/components/autofill/core/common/logging/log_buffer_unittest.cc
@@ -17,7 +17,7 @@ TEST(LogBuffer, JSONSerializeString) {
LogBuffer buffer;
buffer << "<foo><!--\"";
std::string json;
- EXPECT_TRUE(base::JSONWriter::Write(buffer.RetrieveResult(), &json));
+ EXPECT_TRUE(base::JSONWriter::Write(*buffer.RetrieveResult(), &json));
// JSON takes care of serializing the <, we don't want &lt; as that would then
// be escaped twice.
EXPECT_EQ(R"({"type":"text","value":"\u003Cfoo>\u003C!--\""})", json);
@@ -27,7 +27,7 @@ TEST(LogBuffer, JSONSerializeString16) {
LogBuffer buffer;
buffer << u"<foo><!--\"";
std::string json;
- EXPECT_TRUE(base::JSONWriter::Write(buffer.RetrieveResult(), &json));
+ EXPECT_TRUE(base::JSONWriter::Write(*buffer.RetrieveResult(), &json));
// JSON takes care of serializing the <, we don't want &lt; as that would then
// be escaped twice.
EXPECT_EQ(R"({"type":"text","value":"\u003Cfoo>\u003C!--\""})", json);
@@ -37,7 +37,7 @@ TEST(LogBuffer, SupportNumbers) {
LogBuffer buffer;
buffer << 42;
std::string json;
- EXPECT_TRUE(base::JSONWriter::Write(buffer.RetrieveResult(), &json));
+ EXPECT_TRUE(base::JSONWriter::Write(*buffer.RetrieveResult(), &json));
EXPECT_EQ(R"({"type":"text","value":"42"})", json);
}
@@ -45,21 +45,21 @@ TEST(LogBuffer, SanitizeURLs) {
LogBuffer buffer;
buffer << GURL("https://user:pw@www.example.com:80/foo?bar=1#foo");
std::string json;
- EXPECT_TRUE(base::JSONWriter::Write(buffer.RetrieveResult(), &json));
+ EXPECT_TRUE(base::JSONWriter::Write(*buffer.RetrieveResult(), &json));
// Verify that the url gets scrubbed.
EXPECT_EQ(R"({"type":"text","value":"https://www.example.com:80/"})", json);
}
TEST(LogBuffer, Empty) {
LogBuffer buffer;
- EXPECT_EQ(base::Value(), buffer.RetrieveResult());
+ EXPECT_FALSE(buffer.RetrieveResult());
}
TEST(LogBuffer, UnclosedTag) {
LogBuffer buffer;
buffer << Tag{"foo"};
std::string json;
- EXPECT_TRUE(base::JSONWriter::Write(buffer.RetrieveResult(), &json));
+ EXPECT_TRUE(base::JSONWriter::Write(*buffer.RetrieveResult(), &json));
EXPECT_EQ(R"({"type":"element","value":"foo"})", json);
}
@@ -67,7 +67,7 @@ TEST(LogBuffer, ClosedTag) {
LogBuffer buffer;
buffer << Tag{"foo"} << CTag{};
std::string json;
- EXPECT_TRUE(base::JSONWriter::Write(buffer.RetrieveResult(), &json));
+ EXPECT_TRUE(base::JSONWriter::Write(*buffer.RetrieveResult(), &json));
EXPECT_EQ(R"({"type":"element","value":"foo"})", json);
}
@@ -75,7 +75,7 @@ TEST(LogBuffer, NestedTag) {
LogBuffer buffer;
buffer << Tag{"foo"} << Tag{"bar"} << CTag{} << CTag{};
std::string json;
- EXPECT_TRUE(base::JSONWriter::Write(buffer.RetrieveResult(), &json));
+ EXPECT_TRUE(base::JSONWriter::Write(*buffer.RetrieveResult(), &json));
EXPECT_EQ(R"({"children":[{"type":"element","value":"bar"}],)"
R"("type":"element","value":"foo"})",
json);
@@ -85,7 +85,7 @@ TEST(LogBuffer, NestedTagClosingTooOften) {
LogBuffer buffer;
buffer << Tag{"foo"} << Tag{"bar"} << CTag{} << CTag{} << CTag{};
std::string json;
- EXPECT_TRUE(base::JSONWriter::Write(buffer.RetrieveResult(), &json));
+ EXPECT_TRUE(base::JSONWriter::Write(*buffer.RetrieveResult(), &json));
EXPECT_EQ(R"({"children":[{"type":"element","value":"bar"}],)"
R"("type":"element","value":"foo"})",
json);
@@ -95,7 +95,7 @@ TEST(LogBuffer, NestedTagClosingNotAtAll) {
LogBuffer buffer;
buffer << Tag{"foo"} << Tag{"bar"};
std::string json;
- EXPECT_TRUE(base::JSONWriter::Write(buffer.RetrieveResult(), &json));
+ EXPECT_TRUE(base::JSONWriter::Write(*buffer.RetrieveResult(), &json));
EXPECT_EQ(R"({"children":[{"type":"element","value":"bar"}],)"
R"("type":"element","value":"foo"})",
json);
@@ -106,7 +106,7 @@ TEST(LogBuffer, NestedTagWithAttributes) {
buffer << Tag{"foo"} << Tag{"bar"} << Attrib{"b1", "1"} << Attrib{"b2", "2"}
<< CTag{} << Attrib{"f1", "1"};
std::string json;
- EXPECT_TRUE(base::JSONWriter::Write(buffer.RetrieveResult(), &json));
+ EXPECT_TRUE(base::JSONWriter::Write(*buffer.RetrieveResult(), &json));
EXPECT_EQ(
R"({"attributes":{"f1":"1"},"children":[)"
R"({"attributes":{"b1":"1","b2":"2"},"type":"element","value":"bar"})"
@@ -118,7 +118,7 @@ TEST(LogBuffer, DivWithBr) {
LogBuffer buffer;
buffer << Tag{"div"} << "foo" << Br{} << "bar" << CTag{};
std::string json;
- EXPECT_TRUE(base::JSONWriter::Write(buffer.RetrieveResult(), &json));
+ EXPECT_TRUE(base::JSONWriter::Write(*buffer.RetrieveResult(), &json));
EXPECT_EQ(R"({"children":[{"type":"text","value":"foo"},)"
R"({"type":"element","value":"br"},{"type":"text","value":"bar"}],)"
R"("type":"element","value":"div"})",
@@ -130,7 +130,7 @@ TEST(LogBuffer, CoalesceStrings) {
buffer << Tag{"div"} << "foo"
<< "bar";
std::string json;
- EXPECT_TRUE(base::JSONWriter::Write(buffer.RetrieveResult(), &json));
+ EXPECT_TRUE(base::JSONWriter::Write(*buffer.RetrieveResult(), &json));
EXPECT_EQ(R"({"children":[{"type":"text","value":"foobar"}],)"
R"("type":"element","value":"div"})",
json);
@@ -156,7 +156,7 @@ TEST(LogBuffer, CanStreamCustomObjects) {
SampleObject o{42, "foobar<!--"};
buffer << o;
std::string json;
- EXPECT_TRUE(base::JSONWriter::Write(buffer.RetrieveResult(), &json));
+ EXPECT_TRUE(base::JSONWriter::Write(*buffer.RetrieveResult(), &json));
EXPECT_EQ(R"({"children":[)" // table
/**/ R"({"children":[)" // tr
/****/ R"({"children":[{"type":"text","value":"x"}],)" // td
@@ -185,14 +185,14 @@ TEST(LogBuffer, LogTableRowBuffer) {
actual << Tr{} << Attrib{"class", "awesome"} << "Foo"
<< "Bar";
actual << CTag{"table"};
- EXPECT_EQ(expected.RetrieveResult(), actual.RetrieveResult());
+ EXPECT_EQ(*expected.RetrieveResult(), *actual.RetrieveResult());
}
TEST(LogBuffer, CreateFragment) {
LogBuffer buffer;
buffer << "foo" << Br{} << "bar";
std::string json;
- EXPECT_TRUE(base::JSONWriter::Write(buffer.RetrieveResult(), &json));
+ EXPECT_TRUE(base::JSONWriter::Write(*buffer.RetrieveResult(), &json));
EXPECT_EQ(R"({"children":[{"type":"text","value":"foo"},)"
R"({"type":"element","value":"br"},{"type":"text","value":"bar"}],)"
R"("type":"fragment"})",
@@ -205,7 +205,7 @@ TEST(LogBuffer, AppendFragmentByInlining) {
LogBuffer buffer;
buffer << std::move(tmp_buffer);
std::string json;
- EXPECT_TRUE(base::JSONWriter::Write(buffer.RetrieveResult(), &json));
+ EXPECT_TRUE(base::JSONWriter::Write(*buffer.RetrieveResult(), &json));
EXPECT_EQ(R"({"children":[{"type":"text","value":"foo"},)"
R"({"type":"element","value":"br"},{"type":"text","value":"bar"}],)"
R"("type":"fragment"})",
@@ -218,7 +218,7 @@ TEST(LogBuffer, AppendSingleElementBuffer) {
LogBuffer buffer;
buffer << std::move(tmp_buffer);
std::string json;
- EXPECT_TRUE(base::JSONWriter::Write(buffer.RetrieveResult(), &json));
+ EXPECT_TRUE(base::JSONWriter::Write(*buffer.RetrieveResult(), &json));
EXPECT_EQ(R"({"type":"text","value":"foo"})", json);
}
@@ -227,7 +227,7 @@ TEST(LogBuffer, Highlight) {
expected << "foo" << Tag{"b"} << "bar" << CTag{"b"} << "baz";
LogBuffer actual;
actual << HighlightValue("foobarbaz", "bar");
- EXPECT_EQ(expected.RetrieveResult(), actual.RetrieveResult());
+ EXPECT_EQ(*expected.RetrieveResult(), *actual.RetrieveResult());
}
TEST(LogBuffer, HighlightAtStart) {
@@ -235,7 +235,7 @@ TEST(LogBuffer, HighlightAtStart) {
expected << Tag{"b"} << "foo" << CTag{"b"} << "barbaz";
LogBuffer actual;
actual << HighlightValue("foobarbaz", "foo");
- EXPECT_EQ(expected.RetrieveResult(), actual.RetrieveResult());
+ EXPECT_EQ(*expected.RetrieveResult(), *actual.RetrieveResult());
}
TEST(LogBuffer, HighlightAtEnd) {
@@ -243,7 +243,7 @@ TEST(LogBuffer, HighlightAtEnd) {
expected << "foobar" << Tag{"b"} << "baz" << CTag{"b"};
LogBuffer actual;
actual << HighlightValue("foobarbaz", "baz");
- EXPECT_EQ(expected.RetrieveResult(), actual.RetrieveResult());
+ EXPECT_EQ(*expected.RetrieveResult(), *actual.RetrieveResult());
}
TEST(LogBuffer, HighlightEmpty) {
@@ -251,7 +251,7 @@ TEST(LogBuffer, HighlightEmpty) {
expected << "foobarbaz";
LogBuffer actual;
actual << HighlightValue("foobarbaz", "");
- EXPECT_EQ(expected.RetrieveResult(), actual.RetrieveResult());
+ EXPECT_EQ(*expected.RetrieveResult(), *actual.RetrieveResult());
}
TEST(LogBuffer, HighlightNotFound) {
@@ -259,7 +259,7 @@ TEST(LogBuffer, HighlightNotFound) {
expected << "foobarbaz";
LogBuffer actual;
actual << HighlightValue("foobarbaz", "notfound");
- EXPECT_EQ(expected.RetrieveResult(), actual.RetrieveResult());
+ EXPECT_EQ(*expected.RetrieveResult(), *actual.RetrieveResult());
}
TEST(LogBuffer, HighlightEmptyString) {
diff --git a/chromium/components/autofill/core/common/logging/log_macros.h b/chromium/components/autofill/core/common/logging/log_macros.h
new file mode 100644
index 00000000000..e7253ad0a21
--- /dev/null
+++ b/chromium/components/autofill/core/common/logging/log_macros.h
@@ -0,0 +1,52 @@
+// Copyright 2022 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_COMMON_LOGGING_LOG_MACROS_H_
+#define COMPONENTS_AUTOFILL_CORE_COMMON_LOGGING_LOG_MACROS_H_
+
+// Logging macro in the style of LOG(INFO) intended for
+// chrome://autofill-internals.
+//
+// In `LOG_AF(logger) << expression`, the `expression` is evaluated only
+// if the `logger` is active. The expression `logger` must be of type
+// `LogManager` or `LogBuffer` or `LogManager*` or `LogBuffer`*.
+//
+// Support for other types of `logger` can be added by adding template
+// specializations of `LoggerTraits`.
+#define LOG_AF(logger) \
+ !::autofill::internal::LoggerTraits<decltype(logger)>::active(logger) \
+ ? (void)0 \
+ : ::autofill::internal::Voidify() & \
+ ::autofill::internal::LoggerTraits<decltype(logger)>::get_stream( \
+ logger)
+
+namespace autofill::internal {
+
+// Traits for targets of LOG_AF(). There are currently specializations for
+// `LogManager*` and `LogBuffer*`.
+template <typename T, typename Enable = void>
+struct LoggerTraits {
+ // Returns true iff logging to should be enabled.
+ static bool active(const T& logger) { return false; }
+
+ // Returns an object that implements the stream insertion operator
+ // operator<<().
+ static int get_stream(const T& logger) { return {}; }
+};
+
+// This class is used to explicitly ignore values in the conditional
+// logging macros. This avoids compiler warnings like "value computed
+// is not used" and "statement has no effect".
+class Voidify {
+ public:
+ Voidify() = default;
+ // This has to be an operator with a precedence lower than << but
+ // higher than ?:
+ template <typename U>
+ void operator&(const U&) {}
+};
+
+} // namespace autofill::internal
+
+#endif // COMPONENTS_AUTOFILL_CORE_COMMON_LOGGING_LOG_MACROS_H_
diff --git a/chromium/components/autofill/core/common/mojom/BUILD.gn b/chromium/components/autofill/core/common/mojom/BUILD.gn
index f076b75e8cb..e4a2f5efc99 100644
--- a/chromium/components/autofill/core/common/mojom/BUILD.gn
+++ b/chromium/components/autofill/core/common/mojom/BUILD.gn
@@ -19,6 +19,10 @@ mojom("mojo_types") {
{
types = [
{
+ mojom = "autofill.mojom.Section"
+ cpp = "::autofill::Section"
+ },
+ {
mojom = "autofill.mojom.FormData"
cpp = "::autofill::FormData"
},
diff --git a/chromium/components/autofill/core/common/mojom/autofill_types.mojom b/chromium/components/autofill/core/common/mojom/autofill_types.mojom
index a709ecc3fba..0afc2f8cce1 100644
--- a/chromium/components/autofill/core/common/mojom/autofill_types.mojom
+++ b/chromium/components/autofill/core/common/mojom/autofill_types.mojom
@@ -35,8 +35,9 @@ enum SubmissionSource {
NONE, // No submission signal was detected.
SAME_DOCUMENT_NAVIGATION, // The form was removed in same document
// navigation.
- XHR_SUCCEEDED, // The form was removed whem XHR succeeded.
- FRAME_DETACHED, // The subframe which has form was detached.
+ XHR_SUCCEEDED, // The form was removed when XHR succeeded.
+ FRAME_DETACHED, // The subframe or non primary main frame
+ // containing the form was detached.
DOM_MUTATION_AFTER_XHR, // The form was removed after XHR.
PROBABLY_FORM_SUBMITTED, // The form was probably submitted since new page
// is loaded.
@@ -136,6 +137,38 @@ struct SelectOption {
mojo_base.mojom.String16 content;
};
+// autofill::Section::Autocomplete
+// (components/autofill/core/common/form_field_data.h)
+struct SectionAutocomplete {
+ string section;
+ // autofill::HtmlFieldMode
+ uint8 html_field_mode;
+};
+
+// autofill::Section::FieldIdentifier
+// (components/autofill/core/common/form_field_data.h)
+struct SectionFieldIdentifier {
+ string field_name;
+ uint64 local_frame_id;
+ FieldRendererId field_renderer_id;
+};
+
+// autofill::Section::SectionPrefix
+// (components/autofill/core/common/form_field_data.h)
+union SectionPrefix {
+ bool default_prefix;
+ SectionAutocomplete autocomplete_section_prefix;
+ SectionFieldIdentifier from_field_prefix;
+ bool credit_card_prefix;
+};
+
+// autofill::Section (components/autofill/core/common/form_field_data.h)
+struct Section {
+ // autofill::Section::FieldTypeGroupSuffix
+ uint8 field_type_group;
+ SectionPrefix prefix;
+};
+
// autofill::FormFieldData (components/autofill/core/common/form_field_data.h)
struct FormFieldData {
enum CheckStatus {
@@ -185,7 +218,7 @@ struct FormFieldData {
uint64 max_length;
bool is_autofilled;
- string section;
+ Section section;
CheckStatus check_status;
bool is_focusable;
bool is_visible;
diff --git a/chromium/components/autofill/core/common/mojom/autofill_types_mojom_traits.cc b/chromium/components/autofill/core/common/mojom/autofill_types_mojom_traits.cc
index 88fe33bc5f2..1e41d1570d2 100644
--- a/chromium/components/autofill/core/common/mojom/autofill_types_mojom_traits.cc
+++ b/chromium/components/autofill/core/common/mojom/autofill_types_mojom_traits.cc
@@ -5,6 +5,8 @@
#include "components/autofill/core/common/mojom/autofill_types_mojom_traits.h"
#include "base/i18n/rtl.h"
+#include "components/autofill/core/common/form_field_data.h"
+#include "components/autofill/core/common/html_field_types.h"
#include "mojo/public/cpp/base/string16_mojom_traits.h"
#include "mojo/public/cpp/base/time_mojom_traits.h"
#include "third_party/abseil-cpp/absl/types/variant.h"
@@ -69,6 +71,97 @@ bool StructTraits<
}
// static
+autofill::mojom::SectionPrefixDataView::Tag
+UnionTraits<autofill::mojom::SectionPrefixDataView,
+ autofill::Section::SectionPrefix>::
+ GetTag(const autofill::Section::SectionPrefix& r) {
+ if (absl::holds_alternative<autofill::Section::Default>(r))
+ return autofill::mojom::SectionPrefixDataView::Tag::kDefaultPrefix;
+ if (absl::holds_alternative<autofill::Section::Autocomplete>(r)) {
+ return autofill::mojom::SectionPrefixDataView::Tag::
+ kAutocompleteSectionPrefix;
+ }
+ if (absl::holds_alternative<autofill::Section::FieldIdentifier>(r))
+ return autofill::mojom::SectionPrefixDataView::Tag::kFromFieldPrefix;
+ if (absl::holds_alternative<autofill::Section::CreditCard>(r))
+ return autofill::mojom::SectionPrefixDataView::Tag::kCreditCardPrefix;
+
+ NOTREACHED();
+ return autofill::mojom::SectionPrefixDataView::Tag::kDefaultPrefix;
+}
+
+// static
+bool UnionTraits<autofill::mojom::SectionPrefixDataView,
+ autofill::Section::SectionPrefix>::
+ Read(autofill::mojom::SectionPrefixDataView data,
+ autofill::Section::SectionPrefix* out) {
+ switch (data.tag()) {
+ case autofill::mojom::SectionPrefixDataView::Tag::kDefaultPrefix:
+ *out = autofill::Section::Default();
+ break;
+ case autofill::mojom::SectionPrefixDataView::Tag::
+ kAutocompleteSectionPrefix: {
+ autofill::Section::Autocomplete autocomplete_section_prefix;
+ if (!data.ReadAutocompleteSectionPrefix(&autocomplete_section_prefix))
+ return false;
+ *out = std::move(autocomplete_section_prefix);
+ break;
+ }
+ case autofill::mojom::SectionPrefixDataView::Tag::kFromFieldPrefix: {
+ autofill::Section::FieldIdentifier field_identifier;
+ if (!data.ReadFromFieldPrefix(&field_identifier))
+ return false;
+ *out = std::move(field_identifier);
+ break;
+ }
+ case autofill::mojom::SectionPrefixDataView::Tag::kCreditCardPrefix:
+ *out = autofill::Section::CreditCard();
+ break;
+ }
+ return true;
+}
+
+// static
+bool StructTraits<autofill::mojom::SectionAutocompleteDataView,
+ autofill::Section::Autocomplete>::
+ Read(autofill::mojom::SectionAutocompleteDataView data,
+ autofill::Section::Autocomplete* out) {
+ if (!data.ReadSection(&out->section))
+ return false;
+ static_assert(sizeof(data.html_field_mode()) <=
+ sizeof(autofill::HtmlFieldMode));
+ out->mode = static_cast<autofill::HtmlFieldMode>(data.html_field_mode());
+ return true;
+}
+
+// static
+bool StructTraits<autofill::mojom::SectionFieldIdentifierDataView,
+ autofill::Section::FieldIdentifier>::
+ Read(autofill::mojom::SectionFieldIdentifierDataView data,
+ autofill::Section::FieldIdentifier* out) {
+ if (!data.ReadFieldName(&out->field_name))
+ return false;
+ out->local_frame_id = data.local_frame_id();
+ if (!data.ReadFieldRendererId(&out->field_renderer_id))
+ return false;
+ return true;
+}
+
+// static
+bool StructTraits<autofill::mojom::SectionDataView, autofill::Section>::Read(
+ autofill::mojom::SectionDataView data,
+ autofill::Section* out) {
+ static_assert(sizeof(data.field_type_group()) <=
+ sizeof(autofill::Section::FieldTypeGroupSuffix));
+ out->field_type_group_ = static_cast<autofill::Section::FieldTypeGroupSuffix>(
+ data.field_type_group());
+
+ if (!data.ReadPrefix(&out->prefix_))
+ return false;
+ return true;
+}
+
+// static
bool StructTraits<
autofill::mojom::FormFieldDataDataView,
autofill::FormFieldData>::Read(autofill::mojom::FormFieldDataDataView data,
diff --git a/chromium/components/autofill/core/common/mojom/autofill_types_mojom_traits.h b/chromium/components/autofill/core/common/mojom/autofill_types_mojom_traits.h
index 9060cf6a44a..0710814c876 100644
--- a/chromium/components/autofill/core/common/mojom/autofill_types_mojom_traits.h
+++ b/chromium/components/autofill/core/common/mojom/autofill_types_mojom_traits.h
@@ -14,7 +14,6 @@
#include "components/autofill/core/common/aliases.h"
#include "components/autofill/core/common/form_data.h"
#include "components/autofill/core/common/form_data_predictions.h"
-#include "components/autofill/core/common/form_field_data.h"
#include "components/autofill/core/common/form_field_data_predictions.h"
#include "components/autofill/core/common/mojom/autofill_types.mojom-shared.h"
#include "components/autofill/core/common/password_form_fill_data.h"
@@ -92,6 +91,89 @@ struct StructTraits<autofill::mojom::SelectOptionDataView,
};
template <>
+struct UnionTraits<autofill::mojom::SectionPrefixDataView,
+ autofill::Section::SectionPrefix> {
+ static autofill::mojom::SectionPrefixDataView::Tag GetTag(
+ const autofill::Section::SectionPrefix& r);
+
+ static bool default_prefix(const autofill::Section::SectionPrefix& r) {
+ DCHECK(absl::holds_alternative<autofill::Section::Default>(r));
+ return true;
+ }
+
+ static autofill::Section::Autocomplete autocomplete_section_prefix(
+ const autofill::Section::SectionPrefix& r) {
+ return absl::get<autofill::Section::Autocomplete>(r);
+ }
+
+ static autofill::Section::FieldIdentifier from_field_prefix(
+ const autofill::Section::SectionPrefix& r) {
+ return absl::get<autofill::Section::FieldIdentifier>(r);
+ }
+
+ static bool credit_card_prefix(const autofill::Section::SectionPrefix& r) {
+ DCHECK(absl::holds_alternative<autofill::Section::CreditCard>(r));
+ return true;
+ }
+
+ static bool Read(autofill::mojom::SectionPrefixDataView data,
+ autofill::Section::SectionPrefix* out);
+};
+
+template <>
+struct StructTraits<autofill::mojom::SectionAutocompleteDataView,
+ autofill::Section::Autocomplete> {
+ static const std::string& section(const autofill::Section::Autocomplete& r) {
+ return r.section;
+ }
+
+ static uint8_t html_field_mode(const autofill::Section::Autocomplete& r) {
+ static_assert(sizeof(r.mode) <= sizeof(uint8_t));
+ return r.mode;
+ }
+
+ static bool Read(autofill::mojom::SectionAutocompleteDataView data,
+ autofill::Section::Autocomplete* out);
+};
+
+template <>
+struct StructTraits<autofill::mojom::SectionFieldIdentifierDataView,
+ autofill::Section::FieldIdentifier> {
+ static const std::string& field_name(
+ const autofill::Section::FieldIdentifier& r) {
+ return r.field_name;
+ }
+
+ static size_t local_frame_id(const autofill::Section::FieldIdentifier& r) {
+ return r.local_frame_id;
+ }
+
+ static autofill::FieldRendererId field_renderer_id(
+ const autofill::Section::FieldIdentifier& r) {
+ return r.field_renderer_id;
+ }
+
+ static bool Read(autofill::mojom::SectionFieldIdentifierDataView data,
+ autofill::Section::FieldIdentifier* out);
+};
+
+template <>
+struct StructTraits<autofill::mojom::SectionDataView, autofill::Section> {
+ static uint8_t field_type_group(const autofill::Section& r) {
+ static_assert(sizeof(r.field_type_group_) <= sizeof(uint8_t));
+ return static_cast<uint8_t>(r.field_type_group_);
+ }
+
+ static const autofill::Section::SectionPrefix& prefix(
+ const autofill::Section& r) {
+ return r.prefix_;
+ }
+
+ static bool Read(autofill::mojom::SectionDataView data,
+ autofill::Section* out);
+};
+
+template <>
struct StructTraits<autofill::mojom::FormFieldDataDataView,
autofill::FormFieldData> {
static const std::u16string& label(const autofill::FormFieldData& r) {
@@ -168,7 +250,7 @@ struct StructTraits<autofill::mojom::FormFieldDataDataView,
return r.is_autofilled;
}
- static const std::string& section(const autofill::FormFieldData& r) {
+ static const autofill::Section& section(const autofill::FormFieldData& r) {
return r.section;
}
diff --git a/chromium/components/autofill/core/common/mojom/autofill_types_mojom_traits_unittest.cc b/chromium/components/autofill/core/common/mojom/autofill_types_mojom_traits_unittest.cc
index b3f8d8f0a82..d1b2aa7799c 100644
--- a/chromium/components/autofill/core/common/mojom/autofill_types_mojom_traits_unittest.cc
+++ b/chromium/components/autofill/core/common/mojom/autofill_types_mojom_traits_unittest.cc
@@ -12,6 +12,7 @@
#include "components/autofill/core/common/autofill_clock.h"
#include "components/autofill/core/common/form_data.h"
#include "components/autofill/core/common/form_field_data.h"
+#include "components/autofill/core/common/html_field_types.h"
#include "components/autofill/core/common/mojom/test_autofill_types.mojom.h"
#include "components/autofill/core/common/password_generation_util.h"
#include "components/autofill/core/common/signatures.h"
@@ -145,6 +146,10 @@ class AutofillTypeTraitsTestImpl : public testing::Test,
std::move(callback).Run(s);
}
+ void PassSection(const Section& s, PassSectionCallback callback) override {
+ std::move(callback).Run(s);
+ }
+
void PassFormDataPredictions(
const FormDataPredictions& s,
PassFormDataPredictionsCallback callback) override {
@@ -241,6 +246,64 @@ void ExpectPasswordGenerationUIData(
std::move(closure).Run();
}
+// Test all Section::SectionPrefix states.
+class AutofillTypeTraitsTestImplSectionTest
+ : public AutofillTypeTraitsTestImpl,
+ public testing::WithParamInterface<Section> {
+ public:
+ const Section& section() const { return GetParam(); }
+};
+
+TEST_P(AutofillTypeTraitsTestImplSectionTest, PassSection) {
+ base::RunLoop loop;
+ mojo::Remote<mojom::TypeTraitsTest> remote(GetTypeTraitsTestRemote());
+ remote->PassSection(
+ section(),
+ base::BindOnce(
+ [](const Section& a, base::OnceClosure closure, const Section& b) {
+ EXPECT_EQ(a, b);
+ std::move(closure).Run();
+ },
+ section(), loop.QuitClosure()));
+ loop.Run();
+}
+
+std::vector<Section> SectionTestCases() {
+ std::vector<Section> test_cases;
+ Section s;
+ // Default.
+ test_cases.push_back(s);
+
+ // Autocomplete.
+ s = Section();
+ s.SetPrefixFromAutocomplete({.section = "autocomplete_section",
+ .mode = HtmlFieldMode::HTML_MODE_BILLING});
+ s.set_field_type_group(Section::FieldTypeGroupSuffix::kDefault);
+ test_cases.push_back(s);
+
+ // FieldIdentifier.
+ s = Section();
+ base::flat_map<LocalFrameToken, size_t> frame_token_ids;
+ FormFieldData field;
+ field.name = u"from_field_name";
+ field.host_frame = test::MakeLocalFrameToken();
+ field.unique_renderer_id = test::MakeFieldRendererId();
+ s.SetPrefixFromFieldIdentifier(field, frame_token_ids);
+ test_cases.push_back(s);
+
+ // CreditCard.
+ s = Section();
+ s.SetPrefixToCreditCard();
+ s.set_field_type_group(Section::FieldTypeGroupSuffix::kCreditCard);
+ test_cases.push_back(s);
+
+ return test_cases;
+}
+
+INSTANTIATE_TEST_SUITE_P(All,
+ AutofillTypeTraitsTestImplSectionTest,
+ testing::ValuesIn(SectionTestCases()));
+
TEST_F(AutofillTypeTraitsTestImpl, PassFormFieldData) {
FormFieldData input;
test::CreateTestSelectField("TestLabel", "TestName", "TestValue", kOptions,
@@ -264,6 +327,10 @@ TEST_F(AutofillTypeTraitsTestImpl, PassFormFieldData) {
input.properties_mask = FieldPropertiesFlags::kHadFocus;
input.user_input = u"TestTypedValue";
input.bounds = gfx::RectF(1, 2, 10, 100);
+ base::flat_map<LocalFrameToken, size_t> frame_token_ids;
+ input.section.SetPrefixFromAutocomplete(
+ {.section = "autocomplete_section",
+ .mode = HtmlFieldMode::HTML_MODE_SHIPPING});
EXPECT_FALSE(input.host_frame.is_empty());
base::RunLoop loop;
diff --git a/chromium/components/autofill/core/common/mojom/test_autofill_types.mojom b/chromium/components/autofill/core/common/mojom/test_autofill_types.mojom
index e73f044924f..3b0b7c51c20 100644
--- a/chromium/components/autofill/core/common/mojom/test_autofill_types.mojom
+++ b/chromium/components/autofill/core/common/mojom/test_autofill_types.mojom
@@ -7,6 +7,7 @@ module autofill.mojom;
import "components/autofill/core/common/mojom/autofill_types.mojom";
interface TypeTraitsTest {
+ PassSection(Section s) => (Section passed);
PassFormData(FormData s) => (FormData passed);
PassFormFieldData(FormFieldData s) => (FormFieldData passed);
PassFormDataPredictions(FormDataPredictions s) =>
diff --git a/chromium/components/autofill/ios/browser/autofill_agent.mm b/chromium/components/autofill/ios/browser/autofill_agent.mm
index c195f976b35..aeb0f6c8a3c 100644
--- a/chromium/components/autofill/ios/browser/autofill_agent.mm
+++ b/chromium/components/autofill/ios/browser/autofill_agent.mm
@@ -90,9 +90,9 @@ typedef void (^FetchFormsCompletionHandler)(BOOL, const FormDataVector&);
// modifies the field's value for the select elements.
void GetFormField(autofill::FormFieldData* field,
const autofill::FormData& form,
- const std::u16string& fieldIdentifier) {
+ FieldRendererId fieldIdentifier) {
for (const auto& currentField : form.fields) {
- if (currentField.unique_id == fieldIdentifier &&
+ if (currentField.unique_renderer_id == fieldIdentifier &&
currentField.is_focusable) {
*field = currentField;
break;
@@ -151,9 +151,9 @@ void GetFormField(autofill::FormFieldData* field,
base::WeakPtr<autofill::AutofillPopupDelegate> _popupDelegate;
// The autofill data that needs to be send when the |webState_| is shown.
- // The pair contains the frame ID and the base::Value to send.
- // If the value is nullptr, no data needs to be sent.
- std::pair<std::string, std::unique_ptr<base::Value>> _pendingFormData;
+ // The pair contains the frame ID and the base::Value::Dict to send.
+ // If the value is nullopt, no data needs to be sent.
+ absl::optional<std::pair<std::string, base::Value::Dict>> _pendingFormData;
// Bridge to listen to pref changes.
std::unique_ptr<PrefObserverBridge> _prefObserverBridge;
@@ -308,7 +308,7 @@ void GetFormField(autofill::FormFieldData* field,
// Sends a request to BrowserAutofillManager to retrieve suggestions for the
// specified form and field.
- (void)queryAutofillForForm:(const autofill::FormData&)form
- fieldIdentifier:(NSString*)fieldIdentifier
+ fieldIdentifier:(FieldRendererId)fieldIdentifier
type:(NSString*)type
typedValue:(NSString*)typedValue
frameID:(NSString*)frameID
@@ -323,7 +323,7 @@ void GetFormField(autofill::FormFieldData* field,
// Find the right field.
autofill::FormFieldData field;
- GetFormField(&field, form, SysNSStringToUTF16(fieldIdentifier));
+ GetFormField(&field, form, fieldIdentifier);
// Save the completion and go look for suggestions.
_suggestionsAvailableCompletion = [completion copy];
@@ -331,8 +331,8 @@ void GetFormField(autofill::FormFieldData* field,
// Query the BrowserAutofillManager for suggestions. Results will arrive in
// -showAutofillPopup:popupDelegate:.
- autofillManager->OnAskForValuesToFill(++_lastQueryID, form, field,
- gfx::RectF(),
+ autofillManager->OnAskForValuesToFill(form, field, gfx::RectF(),
+ ++_lastQueryID,
/*autoselect_first_suggestion=*/false,
autofill::TouchToFillEligible(false));
}
@@ -370,7 +370,7 @@ void GetFormField(autofill::FormFieldData* field,
id completionHandler = ^(BOOL success, const FormDataVector& forms) {
if (success && forms.size() == 1) {
[weakSelf queryAutofillForForm:forms[0]
- fieldIdentifier:formQuery.fieldIdentifier
+ fieldIdentifier:formQuery.uniqueFieldID
type:formQuery.type
typedValue:formQuery.typedValue
frameID:formQuery.frameID
@@ -486,26 +486,25 @@ void GetFormField(autofill::FormFieldData* field,
- (void)fillFormData:(const autofill::FormData&)form
inFrame:(web::WebFrame*)frame {
- auto autofillData =
- std::make_unique<base::Value>(base::Value::Type::DICTIONARY);
- autofillData->SetKey("formName", base::Value(base::UTF16ToUTF8(form.name)));
- autofillData->SetKey(
+ base::Value::Dict autofillData;
+ autofillData.Set("formName", base::Value(base::UTF16ToUTF8(form.name)));
+ autofillData.Set(
"formRendererID",
base::Value(static_cast<int>(form.unique_renderer_id.value())));
- base::Value fieldsData(base::Value::Type::DICTIONARY);
+ base::Value::Dict fieldsData;
for (const auto& field : form.fields) {
// Skip empty fields and those that are not autofilled.
if (field.value.empty() || !field.is_autofilled)
continue;
- base::Value fieldData(base::Value::Type::DICTIONARY);
- fieldData.SetKey("value", base::Value(field.value));
- fieldData.SetKey("section", base::Value(field.section));
- fieldsData.SetKey(NumberToString(field.unique_renderer_id.value()),
- std::move(fieldData));
+ base::Value::Dict fieldData;
+ fieldData.Set("value", field.value);
+ fieldData.Set("section", field.section.ToString());
+ fieldsData.Set(NumberToString(field.unique_renderer_id.value()),
+ std::move(fieldData));
}
- autofillData->SetKey("fields", std::move(fieldsData));
+ autofillData.Set("fields", std::move(fieldsData));
// Store the form data when WebState is not visible, to send it as soon as it
// becomes visible again, e.g., when the CVC unmask prompt is showing.
@@ -536,17 +535,16 @@ void GetFormField(autofill::FormFieldData* field,
return;
}
- auto predictionData =
- std::make_unique<base::Value>(base::Value::Type::DICTIONARY);
+ base::Value::Dict predictionData;
for (const auto& form : forms) {
- base::Value fieldData(base::Value::Type::DICTIONARY);
+ base::Value::Dict fieldData;
DCHECK(form.fields.size() == form.data.fields.size());
for (size_t i = 0; i < form.fields.size(); i++) {
- fieldData.SetKey(base::UTF16ToUTF8(form.data.fields[i].unique_id),
- base::Value(form.fields[i].overall_type));
+ fieldData.Set(
+ NumberToString(form.data.fields[i].unique_renderer_id.value()),
+ base::Value(form.fields[i].overall_type));
}
- predictionData->SetKey(base::UTF16ToUTF8(form.data.name),
- std::move(fieldData));
+ predictionData.Set(base::UTF16ToUTF8(form.data.name), std::move(fieldData));
}
autofill::AutofillJavaScriptFeature::GetInstance()->FillPredictionData(
frame, std::move(predictionData));
@@ -631,16 +629,19 @@ void GetFormField(autofill::FormFieldData* field,
- (void)webStateWasShown:(web::WebState*)webState {
DCHECK_EQ(_webState, webState);
- if (_pendingFormData.second) {
- // The frameID cannot be empty.
- DCHECK(!_pendingFormData.first.empty());
- web::WebFrame* frame = nullptr;
- if (!_pendingFormData.first.empty()) {
- frame = web::GetWebFrameWithId(_webState, _pendingFormData.first);
- }
- [self sendData:std::move(_pendingFormData.second) toFrame:frame];
+ if (!_pendingFormData.has_value()) {
+ return;
}
- _pendingFormData = std::make_pair("", nullptr);
+
+ std::pair<std::string, base::Value::Dict> pendingFormData =
+ std::move(_pendingFormData).value();
+ _pendingFormData = absl::nullopt;
+
+ // The frameID cannot be empty.
+ DCHECK(!pendingFormData.first.empty());
+ web::WebFrame* frame =
+ web::GetWebFrameWithId(_webState, pendingFormData.first);
+ [self sendData:std::move(pendingFormData.second) toFrame:frame];
}
- (void)webState:(web::WebState*)webState
@@ -814,7 +815,7 @@ void GetFormField(autofill::FormFieldData* field,
// -onFormsFetched:formsData:webFrameId:fieldIdentifier.
__weak AutofillAgent* weakSelf = self;
__block const std::string webFrameId = frame->GetFrameId();
- __block const std::string fieldIdentifier = params.field_identifier;
+ __block FieldRendererId fieldIdentifier = params.unique_field_id;
auto completionHandler = ^(BOOL success, const FormDataVector& forms) {
[weakSelf onFormsFetched:success
formsData:forms
@@ -905,11 +906,11 @@ void GetFormField(autofill::FormFieldData* field,
formName:(const std::string&)formName
value:(const std::u16string)value
inFrame:(web::WebFrame*)frame {
- auto data = std::make_unique<base::DictionaryValue>();
- data->SetInteger("unique_renderer_id", uniqueFieldID.value());
- data->SetString("identifier", fieldIdentifier);
- data->SetString("form", formName);
- data->SetString("value", value);
+ base::Value::Dict data;
+ data.Set("unique_renderer_id", static_cast<int>(uniqueFieldID.value()));
+ data.Set("identifier", fieldIdentifier);
+ data.Set("form", formName);
+ data.Set("value", value);
DCHECK(_suggestionHandledCompletion);
__weak AutofillAgent* weakSelf = self;
@@ -948,8 +949,7 @@ void GetFormField(autofill::FormFieldData* field,
}
// Sends the the |data| to |frame| to actually fill the data.
-- (void)sendData:(std::unique_ptr<base::Value>)data
- toFrame:(web::WebFrame*)frame {
+- (void)sendData:(base::Value::Dict)data toFrame:(web::WebFrame*)frame {
DCHECK(_webState->IsVisible());
__weak AutofillAgent* weakSelf = self;
SuggestionHandledCompletion suggestionHandledCompletionCopy =
@@ -976,7 +976,7 @@ void GetFormField(autofill::FormFieldData* field,
- (void)onFormsFetched:(BOOL)success
formsData:(const FormDataVector&)forms
webFrameId:(const std::string&)webFrameId
- fieldIdentifier:(const std::string&)fieldIdentifier {
+ fieldIdentifier:(FieldRendererId)fieldIdentifier {
if (!success || forms.size() != 1)
return;
@@ -995,7 +995,7 @@ void GetFormField(autofill::FormFieldData* field,
return;
autofill::FormFieldData field;
- GetFormField(&field, forms[0], base::UTF8ToUTF16(fieldIdentifier));
+ GetFormField(&field, forms[0], fieldIdentifier);
autofillManager->OnTextFieldDidChange(
forms[0], field, gfx::RectF(), autofill::AutofillTickClock::NowTicks());
}
diff --git a/chromium/components/autofill/ios/browser/autofill_agent_unittests.mm b/chromium/components/autofill/ios/browser/autofill_agent_unittests.mm
index 049f7f025b3..b42ea2c8071 100644
--- a/chromium/components/autofill/ios/browser/autofill_agent_unittests.mm
+++ b/chromium/components/autofill/ios/browser/autofill_agent_unittests.mm
@@ -143,7 +143,6 @@ TEST_F(AutofillAgentTests,
field.name = u"number";
field.name_attribute = field.name;
field.id_attribute = u"number";
- field.unique_id = field.id_attribute;
field.value = u"number_value";
field.is_autofilled = true;
field.unique_renderer_id = FieldRendererId(2);
@@ -152,7 +151,6 @@ TEST_F(AutofillAgentTests,
field.name = u"name";
field.name_attribute = field.name;
field.id_attribute = u"name";
- field.unique_id = field.id_attribute;
field.value = u"name_value";
field.is_autofilled = true;
field.unique_renderer_id = FieldRendererId(3);
@@ -161,7 +159,6 @@ TEST_F(AutofillAgentTests,
field.name = u"expiry_month";
field.name_attribute = field.name;
field.id_attribute = u"expiry_month";
- field.unique_id = field.id_attribute;
field.value = u"01";
field.is_autofilled = false;
field.unique_renderer_id = FieldRendererId(4);
@@ -170,7 +167,6 @@ TEST_F(AutofillAgentTests,
field.name = u"unknown";
field.name_attribute = field.name;
field.id_attribute = u"unknown";
- field.unique_id = field.id_attribute;
field.value = u"";
field.is_autofilled = true;
field.unique_renderer_id = FieldRendererId(5);
@@ -179,10 +175,10 @@ TEST_F(AutofillAgentTests,
fillFormData:form
inFrame:fake_web_state_.GetWebFramesManager()->GetMainWebFrame()];
fake_web_state_.WasShown();
- EXPECT_EQ(u"__gCrWeb.autofill.fillForm({\"fields\":{\"2\":{\"section\":\"\","
- "\"value\":\"number_value\"},"
- "\"3\":{\"section\":\"\",\"value\":\"name_value\"}},"
- "\"formName\":\"CC form\",\"formRendererID\":1}, 0);",
+ EXPECT_EQ(u"__gCrWeb.autofill.fillForm({\"fields\":{\"2\":{\"section\":\"-"
+ u"default\",\"value\":\"number_value\"},\"3\":{\"section\":\"-"
+ u"default\",\"value\":\"name_value\"}},\"formName\":\"CC "
+ u"form\",\"formRendererID\":1}, 0);",
fake_main_frame_->GetLastJavaScriptCall());
}
diff --git a/chromium/components/autofill/ios/browser/autofill_driver_ios.h b/chromium/components/autofill/ios/browser/autofill_driver_ios.h
index 1b183a73150..3e1f25142a1 100644
--- a/chromium/components/autofill/ios/browser/autofill_driver_ios.h
+++ b/chromium/components/autofill/ios/browser/autofill_driver_ios.h
@@ -41,6 +41,7 @@ class AutofillDriverIOS : public AutofillDriver {
// AutofillDriver:
bool IsIncognito() const override;
+ bool IsInActiveFrame() const override;
bool IsInAnyMainFrame() const override;
bool IsPrerendering() const override;
bool CanShowAutofillUi() const override;
@@ -54,7 +55,7 @@ class AutofillDriverIOS : public AutofillDriver {
const url::Origin& triggered_origin,
const base::flat_map<FieldGlobalId, ServerFieldType>& field_type_map)
override;
- void HandleParsedForms(const std::vector<const FormData*>& forms) override;
+ void HandleParsedForms(const std::vector<FormData>& forms) override;
void SendAutofillTypePredictionsToRenderer(
const std::vector<FormStructure*>& forms) override;
void RendererShouldClearFilledSection() override;
diff --git a/chromium/components/autofill/ios/browser/autofill_driver_ios.mm b/chromium/components/autofill/ios/browser/autofill_driver_ios.mm
index 853cc79f283..0a338d48ab5 100644
--- a/chromium/components/autofill/ios/browser/autofill_driver_ios.mm
+++ b/chromium/components/autofill/ios/browser/autofill_driver_ios.mm
@@ -67,6 +67,11 @@ bool AutofillDriverIOS::IsIncognito() const {
return web_state_->GetBrowserState()->IsOffTheRecord();
}
+// Return true as iOS has no MPArch.
+bool AutofillDriverIOS::IsInActiveFrame() const {
+ return true;
+}
+
bool AutofillDriverIOS::IsInAnyMainFrame() const {
web::WebFrame* web_frame = web::GetWebFrameWithId(web_state_, web_frame_id_);
return web_frame ? web_frame->IsMainFrame() : true;
@@ -111,14 +116,13 @@ std::vector<FieldGlobalId> AutofillDriverIOS::FillOrPreviewForm(
return safe_fields;
}
-void AutofillDriverIOS::HandleParsedForms(
- const std::vector<const FormData*>& forms) {
+void AutofillDriverIOS::HandleParsedForms(const std::vector<FormData>& forms) {
const std::map<FormGlobalId, std::unique_ptr<FormStructure>>& map =
browser_autofill_manager_.form_structures();
std::vector<FormStructure*> form_structures;
form_structures.reserve(forms.size());
- for (const FormData* form : forms) {
- auto it = map.find(form->global_id());
+ for (const FormData& form : forms) {
+ auto it = map.find(form.global_id());
if (it != map.end())
form_structures.push_back(it->second.get());
}
diff --git a/chromium/components/autofill/ios/browser/autofill_java_script_feature.h b/chromium/components/autofill/ios/browser/autofill_java_script_feature.h
index c981f3f6ac2..af7192a79c7 100644
--- a/chromium/components/autofill/ios/browser/autofill_java_script_feature.h
+++ b/chromium/components/autofill/ios/browser/autofill_java_script_feature.h
@@ -7,8 +7,6 @@
#import <Foundation/Foundation.h>
-#include <memory>
-
#include "base/callback.h"
#include "base/no_destructor.h"
#include "base/values.h"
@@ -32,49 +30,48 @@ class AutofillJavaScriptFeature : public web::JavaScriptFeature {
// Adds a delay between filling the form fields in frame.
void AddJSDelayInFrame(web::WebFrame* frame);
- // Extracts forms from a web |frame|. Only forms with at least
- // |requiredFieldsCount| fields are extracted. |callback| is called with the
- // JSON string of forms of a web page. |callback| cannot be null.
+ // Extracts forms from a web `frame`. Only forms with at least
+ // `required_fields_count` fields are extracted. `callback` is called
+ // with the JSON string of forms of a web page. `callback` cannot be nil.
void FetchForms(web::WebFrame* frame,
- NSUInteger requiredFieldsCount,
+ NSUInteger required_fields_count,
base::OnceCallback<void(NSString*)> callback);
- // Fills the data in JSON string |dataString| into the active form field in
- // |frame|, then executes the |completionHandler|.
+ // Fills `data` into the active form field in `frame`, then executes the
+ // `callback`. `callback` cannot be nil.
void FillActiveFormField(web::WebFrame* frame,
- std::unique_ptr<base::DictionaryValue> data,
+ base::Value::Dict data,
base::OnceCallback<void(BOOL)> callback);
// Fills a number of fields in the same named form for full-form Autofill.
// Applies Autofill CSS (i.e. yellow background) to filled elements.
// Only empty fields will be filled, except that field named
- // Field identified by |forceFillFieldID| will always be filled even if
- // non-empty. |forceFillFieldID| may be null. Fields must be contained in
- // |frame|. |completionHandler| is called after the forms are filled with the
- // JSON string containing pairs of unique renderer ids of filled fields and
- // corresponding filled values. |completionHandler| cannot be nil.
+ // Field identified by `force_fill_field_id` will always be filled even if
+ // non-empty. `force_fill_field_id` may be null. Fields must be contained in
+ // `frame`. `callback` is called after the forms are filled with `data`
+ // which must contain pairs of unique renderer ids of filled fields and
+ // corresponding filled values. `callback` cannot be nil.
void FillForm(web::WebFrame* frame,
- std::unique_ptr<base::Value> data,
- autofill::FieldRendererId forceFillFieldID,
+ base::Value::Dict data,
+ autofill::FieldRendererId force_fill_field_id,
base::OnceCallback<void(NSString*)> callback);
// Clear autofilled fields of the specified form and frame. Fields that are
// not currently autofilled are not modified. Field contents are cleared, and
// Autofill flag and styling are removed. 'change' events are sent for fields
// whose contents changed.
- // |fieldUniqueID| identifies the field that initiated the
- // clear action. |completionHandler| is called after the forms are filled with
- // the JSON string containing a list of unique renderer ids of cleared fields.
- // |completionHandler| cannot be nil.
+ // `form_renderer_id` and `field_renderer_id` identify the field that
+ // initiated the clear action. `callback is called after the forms are filled
+ // with the JSON string containing a list of unique renderer ids of cleared
+ // fields. `callback` cannot be nil.
void ClearAutofilledFieldsForForm(
web::WebFrame* frame,
- autofill::FormRendererId formRendererID,
- autofill::FieldRendererId fieldRendererID,
+ autofill::FormRendererId form_renderer_id,
+ autofill::FieldRendererId field_renderer_id,
base::OnceCallback<void(NSString*)> callback);
// Marks up the form with autofill field prediction data (diagnostic tool).
- void FillPredictionData(web::WebFrame* frame,
- std::unique_ptr<base::Value> data);
+ void FillPredictionData(web::WebFrame* frame, base::Value::Dict data);
private:
friend class base::NoDestructor<AutofillJavaScriptFeature>;
diff --git a/chromium/components/autofill/ios/browser/autofill_java_script_feature.mm b/chromium/components/autofill/ios/browser/autofill_java_script_feature.mm
index 2663fe1be69..63d9cd4b4e9 100644
--- a/chromium/components/autofill/ios/browser/autofill_java_script_feature.mm
+++ b/chromium/components/autofill/ios/browser/autofill_java_script_feature.mm
@@ -89,11 +89,10 @@ void AutofillJavaScriptFeature::FetchForms(
void AutofillJavaScriptFeature::FillActiveFormField(
web::WebFrame* frame,
- std::unique_ptr<base::DictionaryValue> data,
+ base::Value::Dict data,
base::OnceCallback<void(BOOL)> callback) {
- DCHECK(data);
std::vector<base::Value> parameters;
- parameters.push_back(std::move(*data));
+ parameters.push_back(base::Value(std::move(data)));
CallJavaScriptFunction(frame, "autofill.fillActiveFormField", parameters,
autofill::CreateBoolCallback(std::move(callback)),
base::Seconds(kJavaScriptExecutionTimeoutInSeconds));
@@ -101,16 +100,15 @@ void AutofillJavaScriptFeature::FillActiveFormField(
void AutofillJavaScriptFeature::FillForm(
web::WebFrame* frame,
- std::unique_ptr<base::Value> data,
- autofill::FieldRendererId force_fill_field_unique_id,
+ base::Value::Dict data,
+ autofill::FieldRendererId force_fill_field_id,
base::OnceCallback<void(NSString*)> callback) {
- DCHECK(data);
DCHECK(!callback.is_null());
std::vector<base::Value> parameters;
- parameters.push_back(std::move(*data));
+ parameters.push_back(base::Value(std::move(data)));
parameters.push_back(
- base::Value(static_cast<int>(force_fill_field_unique_id.value())));
+ base::Value(static_cast<int>(force_fill_field_id.value())));
CallJavaScriptFunction(frame, "autofill.fillForm", parameters,
autofill::CreateStringCallback(std::move(callback)),
base::Seconds(kJavaScriptExecutionTimeoutInSeconds));
@@ -132,12 +130,10 @@ void AutofillJavaScriptFeature::ClearAutofilledFieldsForForm(
base::Seconds(kJavaScriptExecutionTimeoutInSeconds));
}
-void AutofillJavaScriptFeature::FillPredictionData(
- web::WebFrame* frame,
- std::unique_ptr<base::Value> data) {
- DCHECK(data);
+void AutofillJavaScriptFeature::FillPredictionData(web::WebFrame* frame,
+ base::Value::Dict data) {
std::vector<base::Value> parameters;
- parameters.push_back(std::move(*data));
+ parameters.push_back(base::Value(std::move(data)));
CallJavaScriptFunction(frame, "autofill.fillPredictionData", parameters);
}
diff --git a/chromium/components/autofill/ios/browser/autofill_util.h b/chromium/components/autofill/ios/browser/autofill_util.h
index d4aa8f77fa8..c65ac0479e5 100644
--- a/chromium/components/autofill/ios/browser/autofill_util.h
+++ b/chromium/components/autofill/ios/browser/autofill_util.h
@@ -7,13 +7,12 @@
#include <vector>
+#include "base/values.h"
+
#import "ios/web/public/js_messaging/web_frame.h"
class GURL;
-namespace base {
-class DictionaryValue;
-}
namespace web {
class WebState;
}
@@ -59,7 +58,7 @@ bool ExtractFormData(const base::Value& form,
// Extracts a single form field from the JSON dictionary into a FormFieldData
// object.
// Returns false if the field could not be extracted.
-bool ExtractFormFieldData(const base::DictionaryValue& field,
+bool ExtractFormFieldData(const base::Value::Dict& field,
FormFieldData* field_data);
typedef base::OnceCallback<void(const base::Value*)> JavaScriptResultCallback;
diff --git a/chromium/components/autofill/ios/browser/autofill_util.mm b/chromium/components/autofill/ios/browser/autofill_util.mm
index 9cde0ac21f7..3705d11269b 100644
--- a/chromium/components/autofill/ios/browser/autofill_util.mm
+++ b/chromium/components/autofill/ios/browser/autofill_util.mm
@@ -118,20 +118,24 @@ bool ExtractFormData(const base::Value& form_value,
autofill::FormData* form_data) {
DCHECK(form_data);
// Each form should be a JSON dictionary.
- const base::DictionaryValue* form_dictionary = nullptr;
- if (!form_value.GetAsDictionary(&form_dictionary))
+ if (!form_value.is_dict())
return false;
+ const base::Value::Dict& form_dictionary = form_value.GetDict();
+
// Form data is copied into a FormData object field-by-field.
- if (!form_dictionary->GetString("name", &form_data->name))
+ const std::string* name = form_dictionary.FindString("name");
+ if (!name)
return false;
+ form_data->name = base::UTF8ToUTF16(*name);
if (filtered && form_name != form_data->name)
return false;
// Origin is mandatory.
- std::u16string origin;
- if (!form_dictionary->GetString("origin", &origin))
+ const std::string* origin_ptr = form_dictionary.FindString("origin");
+ if (!origin_ptr)
return false;
+ std::u16string origin = base::UTF8ToUTF16(*origin_ptr);
// Use GURL object to verify origin of host frame URL.
form_data->url = GURL(origin);
@@ -141,35 +145,44 @@ bool ExtractFormData(const base::Value& form_value,
// main_frame_origin is used for logging UKM.
form_data->main_frame_origin = url::Origin::Create(main_frame_url);
- std::string unique_renderer_id;
- form_dictionary->GetString("unique_renderer_id", &unique_renderer_id);
- if (!unique_renderer_id.empty()) {
- StringToUint(unique_renderer_id, &form_data->unique_renderer_id.value());
+ const std::string* unique_renderer_id =
+ form_dictionary.FindString("unique_renderer_id");
+ if (unique_renderer_id && !unique_renderer_id->empty()) {
+ StringToUint(*unique_renderer_id, &form_data->unique_renderer_id.value());
} else {
form_data->unique_renderer_id = FormRendererId();
}
// Action is optional.
std::u16string action;
- form_dictionary->GetString("action", &action);
+ if (const std::string* action_ptr = form_dictionary.FindString("action")) {
+ action = base::UTF8ToUTF16(*action_ptr);
+ }
form_data->action = GURL(action);
// Optional fields.
- form_dictionary->GetString("name_attribute", &form_data->name_attribute);
- form_dictionary->GetString("id_attribute", &form_data->id_attribute);
- form_data->is_form_tag = form_dictionary->FindBoolKey("is_form_tag")
- .value_or(form_data->is_form_tag);
- form_dictionary->GetString("frame_id", &form_data->frame_id);
+ if (const std::string* name_attribute =
+ form_dictionary.FindString("name_attribute")) {
+ form_data->name_attribute = base::UTF8ToUTF16(*name_attribute);
+ }
+ if (const std::string* id_attribute =
+ form_dictionary.FindString("id_attribute")) {
+ form_data->id_attribute = base::UTF8ToUTF16(*id_attribute);
+ }
+ form_data->is_form_tag =
+ form_dictionary.FindBool("is_form_tag").value_or(form_data->is_form_tag);
+ if (const std::string* frame_id = form_dictionary.FindString("frame_id")) {
+ form_data->frame_id = *frame_id;
+ }
// Field list (mandatory) is extracted.
- const base::ListValue* fields_list = nullptr;
- if (!form_dictionary->GetList("fields", &fields_list))
+ const base::Value::List* fields_list = form_dictionary.FindList("fields");
+ if (!fields_list)
return false;
- for (const auto& field_dict : fields_list->GetListDeprecated()) {
- const base::DictionaryValue* field;
+ for (const auto& field_dict : *fields_list) {
autofill::FormFieldData field_data;
- if (field_dict.GetAsDictionary(&field) &&
- ExtractFormFieldData(*field, &field_data)) {
+ if (field_dict.is_dict() &&
+ ExtractFormFieldData(field_dict.GetDict(), &field_data)) {
form_data->fields.push_back(std::move(field_data));
} else {
return false;
@@ -178,68 +191,80 @@ bool ExtractFormData(const base::Value& form_value,
return true;
}
-bool ExtractFormFieldData(const base::DictionaryValue& field,
+bool ExtractFormFieldData(const base::Value::Dict& field,
autofill::FormFieldData* field_data) {
- if (!field.GetString("name", &field_data->name) ||
- !field.GetString("identifier", &field_data->unique_id) ||
- !field.GetString("form_control_type", &field_data->form_control_type)) {
+ const std::string* name;
+ const std::string* form_control_type;
+ if (!(name = field.FindString("name")) ||
+ !(form_control_type = field.FindString("form_control_type"))) {
return false;
}
- std::string unique_renderer_id;
- field.GetString("unique_renderer_id", &unique_renderer_id);
- if (!unique_renderer_id.empty()) {
- StringToUint(unique_renderer_id, &field_data->unique_renderer_id.value());
+ field_data->name = base::UTF8ToUTF16(*name);
+ field_data->form_control_type = *form_control_type;
+
+ const std::string* unique_renderer_id =
+ field.FindString("unique_renderer_id");
+ if (unique_renderer_id && !unique_renderer_id->empty()) {
+ StringToUint(*unique_renderer_id, &field_data->unique_renderer_id.value());
} else {
field_data->unique_renderer_id = FieldRendererId();
}
// Optional fields.
- field.GetString("name_attribute", &field_data->name_attribute);
- field.GetString("id_attribute", &field_data->id_attribute);
- field.GetString("label", &field_data->label);
- field.GetString("value", &field_data->value);
- field.GetString("autocomplete_attribute",
- &field_data->autocomplete_attribute);
+ if (const std::string* name_attribute = field.FindString("name_attribute")) {
+ field_data->name_attribute = base::UTF8ToUTF16(*name_attribute);
+ }
+ if (const std::string* id_attribute = field.FindString("id_attribute")) {
+ field_data->id_attribute = base::UTF8ToUTF16(*id_attribute);
+ }
+ if (const std::string* label = field.FindString("label")) {
+ field_data->label = base::UTF8ToUTF16(*label);
+ }
+ if (const std::string* value = field.FindString("value")) {
+ field_data->value = base::UTF8ToUTF16(*value);
+ }
+ if (const std::string* autocomplete_attribute =
+ field.FindString("autocomplete_attribute")) {
+ field_data->autocomplete_attribute = *autocomplete_attribute;
+ }
field_data->is_autofilled =
- field.FindBoolKey("is_autofilled").value_or(field_data->is_autofilled);
+ field.FindBool("is_autofilled").value_or(field_data->is_autofilled);
- int max_length = 0;
- if (field.GetInteger("max_length", &max_length))
- field_data->max_length = max_length;
+ if (absl::optional<int> max_length = field.FindInt("max_length")) {
+ field_data->max_length = *max_length;
+ }
// TODO(crbug.com/427614): Extract |is_checked|.
- bool is_checkable = field.FindBoolKey("is_checkable").value_or(false);
+ bool is_checkable = field.FindBool("is_checkable").value_or(false);
autofill::SetCheckStatus(field_data, is_checkable, false);
field_data->is_focusable =
- field.FindBoolKey("is_focusable").value_or(field_data->is_focusable);
+ field.FindBool("is_focusable").value_or(field_data->is_focusable);
field_data->should_autocomplete =
- field.FindBoolKey("should_autocomplete")
+ field.FindBool("should_autocomplete")
.value_or(field_data->should_autocomplete);
// RoleAttribute::kOther is the default value. The only other value as of this
// writing is RoleAttribute::kPresentation.
- int role = 0;
- if (field.GetInteger("role", &role) &&
- role == static_cast<int>(FormFieldData::RoleAttribute::kPresentation)) {
+ absl::optional<int> role = field.FindInt("role");
+ if (role &&
+ *role == static_cast<int>(FormFieldData::RoleAttribute::kPresentation)) {
field_data->role = FormFieldData::RoleAttribute::kPresentation;
}
// TODO(crbug.com/427614): Extract |text_direction|.
// Load option values where present.
- const base::ListValue* option_values;
- const base::ListValue* option_contents;
- if (field.GetList("option_values", &option_values) &&
- field.GetList("option_contents", &option_contents)) {
- auto value_list = option_values->GetListDeprecated();
- auto content_list = option_contents->GetListDeprecated();
- if (value_list.size() != content_list.size())
+ const base::Value::List* option_values = field.FindList("option_values");
+ const base::Value::List* option_contents = field.FindList("option_contents");
+ if (option_values && option_contents) {
+ if (option_values->size() != option_contents->size())
return false;
- auto value_it = value_list.begin();
- auto content_it = content_list.begin();
- while (value_it != value_list.end() && content_it != content_list.end()) {
+ auto value_it = option_values->begin();
+ auto content_it = option_contents->begin();
+ while (value_it != option_values->end() &&
+ content_it != option_contents->end()) {
if (value_it->is_string() && content_it->is_string()) {
field_data->options.push_back(
{.value = base::UTF8ToUTF16(value_it->GetString()),
diff --git a/chromium/components/autofill/ios/browser/resources/autofill_controller.js b/chromium/components/autofill/ios/browser/resources/autofill_controller.js
index efe852b1b15..24e47206d48 100644
--- a/chromium/components/autofill/ios/browser/resources/autofill_controller.js
+++ b/chromium/components/autofill/ios/browser/resources/autofill_controller.js
@@ -556,8 +556,8 @@ __gCrWeb.autofill['fillPredictionData'] = function(data) {
if (!__gCrWeb.fill.isAutofillableElement(element)) {
continue;
}
- const elementName = __gCrWeb.form.getFieldIdentifier(element);
- const value = formData[elementName];
+ const elementID = __gCrWeb.fill.getUniqueID(element);
+ const value = formData[elementID];
if (value) {
element.placeholder = value;
}
diff --git a/chromium/components/autofill/ios/browser/resources/suggestion_controller.js b/chromium/components/autofill/ios/browser/resources/suggestion_controller.js
index de02dcd6b44..0a0cd66a478 100644
--- a/chromium/components/autofill/ios/browser/resources/suggestion_controller.js
+++ b/chromium/components/autofill/ios/browser/resources/suggestion_controller.js
@@ -378,7 +378,7 @@ __gCrWeb.suggestion['hasPreviousElement'] = function(formName, fieldName) {
__gCrWeb.suggestion['hasPreviousNextElements'] = function(formName, fieldName) {
return [
__gCrWeb.suggestion.hasPreviousElement(formName, fieldName),
- __gCrWeb.suggestion.hasNextElement(formName, fieldName)
+ __gCrWeb.suggestion.hasNextElement(formName, fieldName),
].toString();
};
diff --git a/chromium/components/autofill/ios/form_util/resources/fill.js b/chromium/components/autofill/ios/form_util/resources/fill.js
index 5c0b8f96188..6fa6aea5404 100644
--- a/chromium/components/autofill/ios/form_util/resources/fill.js
+++ b/chromium/components/autofill/ios/form_util/resources/fill.js
@@ -219,7 +219,7 @@ function setInputElementAngularValue_(value, input) {
function(parse) {
const setter = parse(angularModel);
setter.assign(angularScope, value);
- }
+ },
]);
}
@@ -327,7 +327,7 @@ function setInputElementValue_(value, input) {
// property.
return value + '';
},
- configurable: true
+ configurable: true,
};
if (oldPropertyDescriptor.set) {
newProperty.set = function(e) {
@@ -1025,9 +1025,9 @@ __gCrWeb.fill.findChildTextInner = function(node, depth, divsToSkip) {
}
// Ignore elements known not to contain inferable labels.
+ let skipNode = false;
if (node.nodeType === Node.ELEMENT_NODE) {
- if (node.tagName === 'OPTION' || node.tagName === 'SCRIPT' ||
- node.tagName === 'NOSCRIPT') {
+ if (node.tagName === 'OPTION') {
return '';
}
if (__gCrWeb.form.isFormControlElement(/** @type {Element} */ (node))) {
@@ -1036,6 +1036,7 @@ __gCrWeb.fill.findChildTextInner = function(node, depth, divsToSkip) {
return '';
}
}
+ skipNode = node.tagName === 'SCRIPT' || node.tagName === 'NOSCRIPT';
}
if (node.tagName === 'DIV') {
@@ -1047,30 +1048,33 @@ __gCrWeb.fill.findChildTextInner = function(node, depth, divsToSkip) {
}
// Extract the text exactly at this node.
- let nodeText = __gCrWeb.fill.nodeValue(node);
- if (node.nodeType === Node.TEXT_NODE && !nodeText) {
- // In the C++ version, this text node would have been stripped completely.
- // Just pass the buck.
- return __gCrWeb.fill.findChildTextInner(
- node.nextSibling, depth, divsToSkip);
- }
+ let nodeText = '';
+ if (!skipNode) {
+ nodeText = __gCrWeb.fill.nodeValue(node);
+ if (node.nodeType === Node.TEXT_NODE && !nodeText) {
+ // In the C++ version, this text node would have been stripped completely.
+ // Just pass the buck.
+ return __gCrWeb.fill.findChildTextInner(
+ node.nextSibling, depth, divsToSkip);
+ }
- // Recursively compute the children's text.
- // Preserve inter-element whitespace separation.
- const childText =
- __gCrWeb.fill.findChildTextInner(node.firstChild, depth - 1, divsToSkip);
- let addSpace = node.nodeType === Node.TEXT_NODE && !nodeText;
- // Emulate apparently incorrect Chromium behavior tracked in
- // https://crbug.com/239819.
- addSpace = false;
- nodeText =
- __gCrWeb.fill.combineAndCollapseWhitespace(nodeText, childText, addSpace);
+ // Recursively compute the children's text.
+ // Preserve inter-element whitespace separation.
+ const childText = __gCrWeb.fill.findChildTextInner(
+ node.firstChild, depth - 1, divsToSkip);
+ let addSpace = node.nodeType === Node.TEXT_NODE && !nodeText;
+ // Emulate apparently incorrect Chromium behavior tracked in
+ // https://crbug.com/239819.
+ addSpace = false;
+ nodeText = __gCrWeb.fill.combineAndCollapseWhitespace(
+ nodeText, childText, addSpace);
+ }
// Recursively compute the siblings' text.
// Again, preserve inter-element whitespace separation.
const siblingText =
__gCrWeb.fill.findChildTextInner(node.nextSibling, depth - 1, divsToSkip);
- addSpace = node.nodeType === Node.TEXT_NODE && !nodeText;
+ let addSpace = node.nodeType === Node.TEXT_NODE && !nodeText;
// Emulate apparently incorrect Chromium behavior tracked in
// https://crbug.com/239819.
addSpace = false;
@@ -1174,8 +1178,13 @@ __gCrWeb.fill.inferLabelFromSibling = function(element, forward) {
const value = __gCrWeb.fill.findChildText(sibling);
// A text node's value will be empty if it is for a line break.
const addSpace = nodeType === Node.TEXT_NODE && value.length === 0;
- inferredLabel = __gCrWeb.fill.combineAndCollapseWhitespace(
- value, inferredLabel, addSpace);
+ if (forward) {
+ inferredLabel = __gCrWeb.fill.combineAndCollapseWhitespace(
+ inferredLabel, value, addSpace);
+ } else {
+ inferredLabel = __gCrWeb.fill.combineAndCollapseWhitespace(
+ value, inferredLabel, addSpace);
+ }
continue;
}
@@ -1575,8 +1584,14 @@ __gCrWeb.fill.inferLabelFromEnclosingLabel = function(element) {
* e.g. <div>Some Text<span><input ...></span></div>
* e.g. <div>Some Text</div><div><input ...></div>
*
- * Because this is already traversing the <div> structure, if it finds a <label>
- * sibling along the way, infer from that <label>.
+ * Contrary to the other InferLabelFrom* functions, this functions walks up
+ * the DOM tree from the original input, instead of down from the surrounding
+ * tag. While doing so, if a <label> or text node sibling are found along the
+ * way, a label is inferred from them directly. For example, <div>First
+ * name<div><input></div>Last name<div><input></div></div> infers "First name"
+ * and "Last name" for the two inputs, respectively, by picking up the text
+ * nodes on the way to the surrounding div. Without doing so, the label of both
+ * inputs becomes "First nameLast name".
*
* It is based on the logic in
* string16 InferLabelFromDivTable(const WebFormControlElement& element)
@@ -1623,12 +1638,14 @@ __gCrWeb.fill.inferLabelFromDivTable = function(element) {
}
lookingForParent = false;
- } else if (!lookingForParent && __gCrWeb.fill.hasTagName(node, 'label')) {
- if (!node.control) {
+ } else if (!lookingForParent) {
+ // Infer a label from text nodes and unassigned <label> siblings.
+ if (__gCrWeb.fill.hasTagName(node, 'label') && !node.control) {
inferredLabel = __gCrWeb.fill.findChildText(node);
+ } else if (node.nodeType === Node.TEXT_NODE) {
+ inferredLabel = __gCrWeb.fill.nodeValue(node).trim();
}
- } else if (
- lookingForParent && __gCrWeb.fill.isTraversableContainerElement(node)) {
+ } else if (__gCrWeb.fill.isTraversableContainerElement(node)) {
// If the element is in a non-div container, its label most likely is too.
break;
}
diff --git a/chromium/components/autofill/ios/form_util/resources/form_handlers.js b/chromium/components/autofill/ios/form_util/resources/form_handlers.js
index b901a5c408e..ce37ce4f0df 100644
--- a/chromium/components/autofill/ios/form_util/resources/form_handlers.js
+++ b/chromium/components/autofill/ios/form_util/resources/form_handlers.js
@@ -130,7 +130,7 @@ function trackPasswordField_(field) {
'fieldType': '',
'type': 'password_form_cleared',
'value': __gCrWeb.stringify(formData),
- 'hasUserGesture': false
+ 'hasUserGesture': false,
};
sendMessageOnNextLoop_(msg);
}
@@ -226,7 +226,7 @@ function formActivity_(evt) {
'fieldType': fieldType,
'type': type,
'value': value,
- 'hasUserGesture': evt.isTrusted
+ 'hasUserGesture': evt.isTrusted,
};
sendMessageOnNextLoop_(msg);
}
@@ -253,7 +253,7 @@ function formSubmitted_(form) {
'frameID': __gCrWeb.message.getFrameId(),
'formName': __gCrWeb.form.getFormIdentifier(form),
'href': getFullyQualifiedUrl_(action),
- 'formData': __gCrWeb.fill.autofillSubmissionData(form)
+ 'formData': __gCrWeb.fill.autofillSubmissionData(form),
});
}
@@ -423,7 +423,7 @@ __gCrWeb.formHandlers['trackFormMutations'] = function(delay) {
'fieldType': '',
'type': 'form_changed',
'value': '',
- 'hasUserGesture': false
+ 'hasUserGesture': false,
};
return sendFormMutationMessageAfterDelay_(msg, delay);
}