summaryrefslogtreecommitdiff
path: root/chromium/components/autofill/core
diff options
context:
space:
mode:
authorAllan Sandfeld Jensen <allan.jensen@qt.io>2017-07-12 14:07:37 +0200
committerAllan Sandfeld Jensen <allan.jensen@qt.io>2017-07-17 10:29:26 +0000
commitec02ee4181c49b61fce1c8fb99292dbb8139cc90 (patch)
tree25cde714b2b71eb639d1cd53f5a22e9ba76e14ef /chromium/components/autofill/core
parentbb09965444b5bb20b096a291445170876225268d (diff)
downloadqtwebengine-chromium-ec02ee4181c49b61fce1c8fb99292dbb8139cc90.tar.gz
BASELINE: Update Chromium to 59.0.3071.134
Change-Id: Id02ef6fb2204c5fd21668a1c3e6911c83b17585a Reviewed-by: Alexandru Croitor <alexandru.croitor@qt.io>
Diffstat (limited to 'chromium/components/autofill/core')
-rw-r--r--chromium/components/autofill/core/browser/BUILD.gn23
-rw-r--r--chromium/components/autofill/core/browser/address_i18n_unittest.cc132
-rw-r--r--chromium/components/autofill/core/browser/autocomplete_history_manager.cc2
-rw-r--r--chromium/components/autofill/core/browser/autocomplete_history_manager_unittest.cc3
-rw-r--r--chromium/components/autofill/core/browser/autofill_address_util.cc165
-rw-r--r--chromium/components/autofill/core/browser/autofill_address_util.h78
-rw-r--r--chromium/components/autofill/core/browser/autofill_assistant_unittest.cc12
-rw-r--r--chromium/components/autofill/core/browser/autofill_client.h23
-rw-r--r--chromium/components/autofill/core/browser/autofill_data_model_unittest.cc104
-rw-r--r--chromium/components/autofill/core/browser/autofill_data_util_unittest.cc293
-rw-r--r--chromium/components/autofill/core/browser/autofill_download_manager.cc78
-rw-r--r--chromium/components/autofill/core/browser/autofill_driver.h9
-rw-r--r--chromium/components/autofill/core/browser/autofill_driver_factory.cc13
-rw-r--r--chromium/components/autofill/core/browser/autofill_driver_factory.h8
-rw-r--r--chromium/components/autofill/core/browser/autofill_driver_factory_unittest.cc61
-rw-r--r--chromium/components/autofill/core/browser/autofill_experiments.cc12
-rw-r--r--chromium/components/autofill/core/browser/autofill_experiments.h5
-rw-r--r--chromium/components/autofill/core/browser/autofill_field_unittest.cc763
-rw-r--r--chromium/components/autofill/core/browser/autofill_manager.cc253
-rw-r--r--chromium/components/autofill/core/browser/autofill_manager.h21
-rw-r--r--chromium/components/autofill/core/browser/autofill_manager_unittest.cc451
-rw-r--r--chromium/components/autofill/core/browser/autofill_metrics.cc244
-rw-r--r--chromium/components/autofill/core/browser/autofill_metrics.h160
-rw-r--r--chromium/components/autofill/core/browser/autofill_metrics_unittest.cc804
-rw-r--r--chromium/components/autofill/core/browser/autofill_profile.cc4
-rw-r--r--chromium/components/autofill/core/browser/autofill_profile_comparator.cc16
-rw-r--r--chromium/components/autofill/core/browser/autofill_profile_unittest.cc33
-rw-r--r--chromium/components/autofill/core/browser/autofill_regex_constants.cc29
-rw-r--r--chromium/components/autofill/core/browser/autofill_regex_constants.h6
-rw-r--r--chromium/components/autofill/core/browser/autofill_save_card_infobar_delegate_mobile.cc1
-rw-r--r--chromium/components/autofill/core/browser/autofill_test_utils.cc10
-rw-r--r--chromium/components/autofill/core/browser/autofill_type.cc10
-rw-r--r--chromium/components/autofill/core/browser/contact_info_unittest.cc398
-rw-r--r--chromium/components/autofill/core/browser/country_combobox_model.h2
-rw-r--r--chromium/components/autofill/core/browser/country_names.cc2
-rw-r--r--chromium/components/autofill/core/browser/credit_card.cc6
-rw-r--r--chromium/components/autofill/core/browser/credit_card_field.h2
-rw-r--r--chromium/components/autofill/core/browser/credit_card_field_unittest.cc263
-rw-r--r--chromium/components/autofill/core/browser/credit_card_unittest.cc883
-rw-r--r--chromium/components/autofill/core/browser/field_types.h5
-rw-r--r--chromium/components/autofill/core/browser/form_group.cc10
-rw-r--r--chromium/components/autofill/core/browser/form_group.h4
-rw-r--r--chromium/components/autofill/core/browser/form_structure.cc154
-rw-r--r--chromium/components/autofill/core/browser/form_structure.h52
-rw-r--r--chromium/components/autofill/core/browser/form_structure_unittest.cc128
-rw-r--r--chromium/components/autofill/core/browser/payments/full_card_request.cc8
-rw-r--r--chromium/components/autofill/core/browser/payments/full_card_request.h7
-rw-r--r--chromium/components/autofill/core/browser/payments/payments_client.cc38
-rw-r--r--chromium/components/autofill/core/browser/personal_data_manager.cc6
-rw-r--r--chromium/components/autofill/core/browser/personal_data_manager.h14
-rw-r--r--chromium/components/autofill/core/browser/personal_data_manager_unittest.cc873
-rw-r--r--chromium/components/autofill/core/browser/phone_number_i18n_unittest.cc126
-rw-r--r--chromium/components/autofill/core/browser/region_combobox_model.cc117
-rw-r--r--chromium/components/autofill/core/browser/region_combobox_model.h88
-rw-r--r--chromium/components/autofill/core/browser/region_combobox_model_unittest.cc107
-rw-r--r--chromium/components/autofill/core/browser/risk_data_loader.h26
-rw-r--r--chromium/components/autofill/core/browser/test_autofill_client.cc18
-rw-r--r--chromium/components/autofill/core/browser/test_autofill_client.h6
-rw-r--r--chromium/components/autofill/core/browser/test_autofill_driver.cc2
-rw-r--r--chromium/components/autofill/core/browser/test_autofill_driver.h2
-rw-r--r--chromium/components/autofill/core/browser/ui/card_unmask_prompt_controller.h1
-rw-r--r--chromium/components/autofill/core/browser/ui/card_unmask_prompt_controller_impl.cc4
-rw-r--r--chromium/components/autofill/core/browser/ui/card_unmask_prompt_controller_impl.h2
-rw-r--r--chromium/components/autofill/core/browser/ui/card_unmask_prompt_controller_impl_unittest.cc219
-rw-r--r--chromium/components/autofill/core/browser/ui/mock_save_card_bubble_controller.cc22
-rw-r--r--chromium/components/autofill/core/browser/ui/mock_save_card_bubble_controller.h42
-rw-r--r--chromium/components/autofill/core/browser/ui/save_card_bubble_controller.h70
-rw-r--r--chromium/components/autofill/core/browser/validation.cc22
-rw-r--r--chromium/components/autofill/core/browser/validation.h16
-rw-r--r--chromium/components/autofill/core/browser/validation_unittest.cc77
-rw-r--r--chromium/components/autofill/core/browser/webdata/autocomplete_sync_bridge.cc6
-rw-r--r--chromium/components/autofill/core/browser/webdata/autocomplete_sync_bridge.h7
-rw-r--r--chromium/components/autofill/core/browser/webdata/autocomplete_sync_bridge_unittest.cc3
-rw-r--r--chromium/components/autofill/core/browser/webdata/autofill_profile_syncable_service_unittest.cc186
-rw-r--r--chromium/components/autofill/core/browser/webdata/autofill_table.cc20
-rw-r--r--chromium/components/autofill/core/browser/webdata/autofill_table.h2
-rw-r--r--chromium/components/autofill/core/browser/webdata/autofill_table_unittest.cc139
-rw-r--r--chromium/components/autofill/core/browser/webdata/autofill_wallet_syncable_service.cc5
-rw-r--r--chromium/components/autofill/core/common/BUILD.gn1
-rw-r--r--chromium/components/autofill/core/common/autofill_clock.cc2
-rw-r--r--chromium/components/autofill/core/common/autofill_clock.h2
-rw-r--r--chromium/components/autofill/core/common/autofill_data_validation.cc1
-rw-r--r--chromium/components/autofill/core/common/autofill_regexes_unittest.cc341
-rw-r--r--chromium/components/autofill/core/common/autofill_util_unittest.cc221
-rw-r--r--chromium/components/autofill/core/common/password_form.cc17
-rw-r--r--chromium/components/autofill/core/common/password_form.h12
-rw-r--r--chromium/components/autofill/core/common/password_form_fill_data.cc11
-rw-r--r--chromium/components/autofill/core/common/password_form_fill_data.h5
-rw-r--r--chromium/components/autofill/core/common/password_form_generation_data.cc21
-rw-r--r--chromium/components/autofill/core/common/password_form_generation_data.h11
-rw-r--r--chromium/components/autofill/core/common/save_password_progress_logger.cc40
-rw-r--r--chromium/components/autofill/core/common/save_password_progress_logger.h16
-rw-r--r--chromium/components/autofill/core/common/save_password_progress_logger_unittest.cc6
93 files changed, 5998 insertions, 2725 deletions
diff --git a/chromium/components/autofill/core/browser/BUILD.gn b/chromium/components/autofill/core/browser/BUILD.gn
index 4e6332c41f8..87a22f6efa1 100644
--- a/chromium/components/autofill/core/browser/BUILD.gn
+++ b/chromium/components/autofill/core/browser/BUILD.gn
@@ -18,6 +18,8 @@ static_library("browser") {
"autocomplete_history_manager.cc",
"autocomplete_history_manager.h",
"autofill-inl.h",
+ "autofill_address_util.cc",
+ "autofill_address_util.h",
"autofill_client.h",
"autofill_country.cc",
"autofill_country.h",
@@ -109,6 +111,9 @@ static_library("browser") {
"phone_number_i18n.cc",
"phone_number_i18n.h",
"popup_item_ids.h",
+ "region_combobox_model.cc",
+ "region_combobox_model.h",
+ "risk_data_loader.h",
"server_field_types_util.cc",
"server_field_types_util.h",
"state_names.cc",
@@ -178,12 +183,19 @@ static_library("browser") {
]
}
+ if (!is_android) {
+ sources += [
+ "ui/save_card_bubble_controller.h",
+ ]
+ }
+
configs += [ "//build/config:precompiled_headers" ]
public_deps = [
"//components/autofill/core/browser/proto",
"//components/autofill/core/common",
"//components/resources",
+ "//skia",
]
deps = [
"//base",
@@ -206,11 +218,10 @@ static_library("browser") {
"//components/webdata/common",
"//google_apis",
"//net",
- "//skia",
"//sql",
"//third_party/fips181",
"//third_party/icu",
- "//third_party/libaddressinput:util",
+ "//third_party/libaddressinput",
"//third_party/libphonenumber",
"//third_party/re2",
"//ui/base",
@@ -247,6 +258,13 @@ static_library("test_support") {
"test_personal_data_manager.h",
]
+ if (!is_android) {
+ sources += [
+ "ui/mock_save_card_bubble_controller.cc",
+ "ui/mock_save_card_bubble_controller.h",
+ ]
+ }
+
public_deps = [
":browser",
]
@@ -336,6 +354,7 @@ source_set("unit_tests") {
"phone_field_unittest.cc",
"phone_number_i18n_unittest.cc",
"phone_number_unittest.cc",
+ "region_combobox_model_unittest.cc",
"ui/card_unmask_prompt_controller_impl_unittest.cc",
"validation_unittest.cc",
"webdata/autocomplete_sync_bridge_unittest.cc",
diff --git a/chromium/components/autofill/core/browser/address_i18n_unittest.cc b/chromium/components/autofill/core/browser/address_i18n_unittest.cc
index 59ddc2137a3..7b0a9a0da21 100644
--- a/chromium/components/autofill/core/browser/address_i18n_unittest.cc
+++ b/chromium/components/autofill/core/browser/address_i18n_unittest.cc
@@ -35,61 +35,91 @@ using ::i18n::addressinput::RECIPIENT;
using ::i18n::addressinput::SORTING_CODE;
using ::i18n::addressinput::STREET_ADDRESS;
-TEST(AddressI18nTest, FieldTypeMirrorConversions) {
- static const struct {
- bool billing;
- ServerFieldType server_field;
- AddressField address_field;
- } kTestData[] = {
- {true, ADDRESS_BILLING_COUNTRY, COUNTRY},
- {true, ADDRESS_BILLING_STATE, ADMIN_AREA},
- {true, ADDRESS_BILLING_CITY, LOCALITY},
- {true, ADDRESS_BILLING_DEPENDENT_LOCALITY, DEPENDENT_LOCALITY},
- {true, ADDRESS_BILLING_SORTING_CODE, SORTING_CODE},
- {true, ADDRESS_BILLING_ZIP, POSTAL_CODE},
- {true, ADDRESS_BILLING_STREET_ADDRESS, STREET_ADDRESS},
- {true, COMPANY_NAME, ORGANIZATION},
- {true, NAME_BILLING_FULL, RECIPIENT},
- {false, ADDRESS_HOME_COUNTRY, COUNTRY},
- {false, ADDRESS_HOME_STATE, ADMIN_AREA},
- {false, ADDRESS_HOME_CITY, LOCALITY},
- {false, ADDRESS_HOME_DEPENDENT_LOCALITY, DEPENDENT_LOCALITY},
- {false, ADDRESS_HOME_SORTING_CODE, SORTING_CODE},
- {false, ADDRESS_HOME_ZIP, POSTAL_CODE},
- {false, ADDRESS_HOME_STREET_ADDRESS, STREET_ADDRESS},
- {false, COMPANY_NAME, ORGANIZATION},
- {false, NAME_FULL, RECIPIENT},
- };
-
- for (const auto& test_data : kTestData) {
- AddressField address_field;
- EXPECT_TRUE(FieldForType(test_data.server_field, &address_field));
- EXPECT_EQ(test_data.address_field, address_field);
-
- ServerFieldType server_field =
- TypeForField(test_data.address_field, test_data.billing);
- EXPECT_EQ(test_data.server_field, server_field);
- }
+struct FieldTypeMirrorConversionsTestCase {
+ bool billing;
+ ServerFieldType server_field;
+ AddressField address_field;
+};
+
+class FieldTypeMirrorConversionsTest
+ : public testing::TestWithParam<FieldTypeMirrorConversionsTestCase> {};
+
+TEST_P(FieldTypeMirrorConversionsTest, FieldTypeMirrorConversions) {
+ auto test_data = GetParam();
+ AddressField address_field;
+ EXPECT_TRUE(FieldForType(test_data.server_field, &address_field));
+ EXPECT_EQ(test_data.address_field, address_field);
+
+ ServerFieldType server_field =
+ TypeForField(test_data.address_field, test_data.billing);
+ EXPECT_EQ(test_data.server_field, server_field);
}
-TEST(AddressI18nTest, FieldTypeUnidirectionalConversions) {
- static const struct {
- ServerFieldType server_field;
- AddressField expected_address_field;
- } kTestData[] = {
- {ADDRESS_BILLING_LINE1, STREET_ADDRESS},
- {ADDRESS_BILLING_LINE2, STREET_ADDRESS},
- {ADDRESS_HOME_LINE1, STREET_ADDRESS},
- {ADDRESS_HOME_LINE2, STREET_ADDRESS},
- };
-
- for (const auto& test_data : kTestData) {
- AddressField actual_address_field;
- FieldForType(test_data.server_field, &actual_address_field);
- EXPECT_EQ(test_data.expected_address_field, actual_address_field);
- }
+INSTANTIATE_TEST_CASE_P(
+ AddressI18nTest,
+ FieldTypeMirrorConversionsTest,
+ testing::Values(
+ FieldTypeMirrorConversionsTestCase{true, ADDRESS_BILLING_COUNTRY,
+ COUNTRY},
+ FieldTypeMirrorConversionsTestCase{true, ADDRESS_BILLING_STATE,
+ ADMIN_AREA},
+ FieldTypeMirrorConversionsTestCase{true, ADDRESS_BILLING_CITY,
+ LOCALITY},
+ FieldTypeMirrorConversionsTestCase{
+ true, ADDRESS_BILLING_DEPENDENT_LOCALITY, DEPENDENT_LOCALITY},
+ FieldTypeMirrorConversionsTestCase{true, ADDRESS_BILLING_SORTING_CODE,
+ SORTING_CODE},
+ FieldTypeMirrorConversionsTestCase{true, ADDRESS_BILLING_ZIP,
+ POSTAL_CODE},
+ FieldTypeMirrorConversionsTestCase{true, ADDRESS_BILLING_STREET_ADDRESS,
+ STREET_ADDRESS},
+ FieldTypeMirrorConversionsTestCase{true, COMPANY_NAME, ORGANIZATION},
+ FieldTypeMirrorConversionsTestCase{true, NAME_BILLING_FULL, RECIPIENT},
+ FieldTypeMirrorConversionsTestCase{false, ADDRESS_HOME_COUNTRY,
+ COUNTRY},
+ FieldTypeMirrorConversionsTestCase{false, ADDRESS_HOME_STATE,
+ ADMIN_AREA},
+ FieldTypeMirrorConversionsTestCase{false, ADDRESS_HOME_CITY, LOCALITY},
+ FieldTypeMirrorConversionsTestCase{
+ false, ADDRESS_HOME_DEPENDENT_LOCALITY, DEPENDENT_LOCALITY},
+ FieldTypeMirrorConversionsTestCase{false, ADDRESS_HOME_SORTING_CODE,
+ SORTING_CODE},
+ FieldTypeMirrorConversionsTestCase{false, ADDRESS_HOME_ZIP,
+ POSTAL_CODE},
+ FieldTypeMirrorConversionsTestCase{false, ADDRESS_HOME_STREET_ADDRESS,
+ STREET_ADDRESS},
+ FieldTypeMirrorConversionsTestCase{false, COMPANY_NAME, ORGANIZATION},
+ FieldTypeMirrorConversionsTestCase{false, NAME_FULL, RECIPIENT}));
+
+struct FieldTypeUnidirectionalConversionsTestCase {
+ ServerFieldType server_field;
+ AddressField expected_address_field;
+};
+
+class FieldTypeUnidirectionalConversionsTest
+ : public testing::TestWithParam<
+ FieldTypeUnidirectionalConversionsTestCase> {};
+
+TEST_P(FieldTypeUnidirectionalConversionsTest,
+ FieldTypeUnidirectionalConversions) {
+ auto test_data = GetParam();
+ AddressField actual_address_field;
+ FieldForType(test_data.server_field, &actual_address_field);
+ EXPECT_EQ(test_data.expected_address_field, actual_address_field);
}
+INSTANTIATE_TEST_CASE_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}));
+
TEST(AddressI18nTest, UnconvertableServerFields) {
EXPECT_FALSE(FieldForType(PHONE_HOME_NUMBER, NULL));
EXPECT_FALSE(FieldForType(EMAIL_ADDRESS, NULL));
diff --git a/chromium/components/autofill/core/browser/autocomplete_history_manager.cc b/chromium/components/autofill/core/browser/autocomplete_history_manager.cc
index fa4aa7ce877..ec5738c43a5 100644
--- a/chromium/components/autofill/core/browser/autocomplete_history_manager.cc
+++ b/chromium/components/autofill/core/browser/autocomplete_history_manager.cc
@@ -78,7 +78,7 @@ void AutocompleteHistoryManager::OnWillSubmitForm(const FormData& form) {
if (!autofill_client_->IsAutocompleteEnabled())
return;
- if (driver_->IsOffTheRecord())
+ if (driver_->IsIncognito())
return;
// We put the following restriction on stored FormFields:
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 df3820d9128..56c8d274114 100644
--- a/chromium/components/autofill/core/browser/autocomplete_history_manager_unittest.cc
+++ b/chromium/components/autofill/core/browser/autocomplete_history_manager_unittest.cc
@@ -10,6 +10,7 @@
#include "base/strings/string16.h"
#include "base/strings/utf_string_conversions.h"
#include "base/synchronization/waitable_event.h"
+#include "base/test/scoped_task_environment.h"
#include "base/threading/thread_task_runner_handle.h"
#include "components/autofill/core/browser/autocomplete_history_manager.h"
#include "components/autofill/core/browser/autofill_external_delegate.h"
@@ -78,7 +79,7 @@ class AutocompleteHistoryManagerTest : public testing::Test {
void TearDown() override { autocomplete_manager_.reset(); }
- base::MessageLoop message_loop_;
+ base::test::ScopedTaskEnvironment scoped_task_environment_;
scoped_refptr<MockWebDataService> web_data_service_;
std::unique_ptr<AutocompleteHistoryManager> autocomplete_manager_;
std::unique_ptr<AutofillDriver> autofill_driver_;
diff --git a/chromium/components/autofill/core/browser/autofill_address_util.cc b/chromium/components/autofill/core/browser/autofill_address_util.cc
new file mode 100644
index 00000000000..c232e002651
--- /dev/null
+++ b/chromium/components/autofill/core/browser/autofill_address_util.cc
@@ -0,0 +1,165 @@
+// 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.
+
+#include "components/autofill/core/browser/autofill_address_util.h"
+
+#include <memory>
+#include <utility>
+
+#include "base/memory/ptr_util.h"
+#include "base/values.h"
+#include "components/autofill/core/browser/autofill_country.h"
+#include "components/autofill/core/browser/country_combobox_model.h"
+#include "components/autofill/core/browser/field_types.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 "ui/base/l10n/l10n_util.h"
+
+using autofill::AutofillCountry;
+using autofill::ServerFieldType;
+using i18n::addressinput::AddressUiComponent;
+
+namespace autofill {
+
+// Dictionary keys for address components info.
+const char kFieldTypeKey[] = "field";
+const char kFieldLengthKey[] = "length";
+const char kFieldNameKey[] = "name";
+
+// Field names for the address components.
+const char kFullNameField[] = "fullName";
+const char kCompanyNameField[] = "companyName";
+const char kAddressLineField[] = "addrLines";
+const char kDependentLocalityField[] = "dependentLocality";
+const char kCityField[] = "city";
+const char kStateField[] = "state";
+const char kPostalCodeField[] = "postalCode";
+const char kSortingCodeField[] = "sortingCode";
+const char kCountryField[] = "country";
+
+// Address field length values.
+const char kShortField[] = "short";
+const char kLongField[] = "long";
+
+// Fills |components| with the address UI components that should be used to
+// input an address for |country_code| when UI BCP 47 language code is
+// |ui_language_code|. If |components_language_code| is not NULL, then sets it
+// to the BCP 47 language code that should be used to format the address for
+// display.
+void GetAddressComponents(const std::string& country_code,
+ const std::string& ui_language_code,
+ base::ListValue* address_components,
+ std::string* components_language_code) {
+ DCHECK(address_components);
+
+ i18n::addressinput::Localization localization;
+ localization.SetGetter(l10n_util::GetStringUTF8);
+ std::string not_used;
+ std::vector<AddressUiComponent> components =
+ i18n::addressinput::BuildComponents(
+ country_code, localization, ui_language_code,
+ components_language_code ? components_language_code : &not_used);
+ if (components.empty()) {
+ static const char kDefaultCountryCode[] = "US";
+ components = i18n::addressinput::BuildComponents(
+ kDefaultCountryCode, localization, ui_language_code,
+ components_language_code ? components_language_code : &not_used);
+ }
+ DCHECK(!components.empty());
+
+ base::ListValue* line = nullptr;
+ for (size_t i = 0; i < components.size(); ++i) {
+ if (i == 0 ||
+ components[i - 1].length_hint == AddressUiComponent::HINT_LONG ||
+ components[i].length_hint == AddressUiComponent::HINT_LONG) {
+ line = new base::ListValue;
+ address_components->Append(base::WrapUnique(line));
+ // |line| is invalidated at this point, so it needs to be reset.
+ address_components->GetList(address_components->GetSize() - 1, &line);
+ }
+
+ std::unique_ptr<base::DictionaryValue> component(new base::DictionaryValue);
+ component->SetString(kFieldNameKey, components[i].name);
+
+ switch (components[i].field) {
+ case i18n::addressinput::COUNTRY:
+ component->SetString(kFieldTypeKey, kCountryField);
+ break;
+ case i18n::addressinput::ADMIN_AREA:
+ component->SetString(kFieldTypeKey, kStateField);
+ break;
+ case i18n::addressinput::LOCALITY:
+ component->SetString(kFieldTypeKey, kCityField);
+ break;
+ case i18n::addressinput::DEPENDENT_LOCALITY:
+ component->SetString(kFieldTypeKey, kDependentLocalityField);
+ break;
+ case i18n::addressinput::SORTING_CODE:
+ component->SetString(kFieldTypeKey, kSortingCodeField);
+ break;
+ case i18n::addressinput::POSTAL_CODE:
+ component->SetString(kFieldTypeKey, kPostalCodeField);
+ break;
+ case i18n::addressinput::STREET_ADDRESS:
+ component->SetString(kFieldTypeKey, kAddressLineField);
+ break;
+ case i18n::addressinput::ORGANIZATION:
+ component->SetString(kFieldTypeKey, kCompanyNameField);
+ break;
+ case i18n::addressinput::RECIPIENT:
+ component->SetString(kFieldTypeKey, kFullNameField);
+ break;
+ }
+
+ switch (components[i].length_hint) {
+ case AddressUiComponent::HINT_LONG:
+ component->SetString(kFieldLengthKey, kLongField);
+ break;
+ case AddressUiComponent::HINT_SHORT:
+ component->SetString(kFieldLengthKey, kShortField);
+ break;
+ }
+
+ line->Append(std::move(component));
+ }
+}
+
+// Sets data related to the country <select>.
+void SetCountryData(const PersonalDataManager& manager,
+ base::DictionaryValue* localized_strings,
+ const std::string& ui_language_code) {
+ autofill::CountryComboboxModel model;
+ model.SetCountries(manager, base::Callback<bool(const std::string&)>(),
+ ui_language_code);
+ const std::vector<std::unique_ptr<autofill::AutofillCountry>>& countries =
+ model.countries();
+ localized_strings->SetString("defaultCountryCode",
+ countries.front()->country_code());
+
+ // An ordered list of options to show in the <select>.
+ std::unique_ptr<base::ListValue> country_list(new base::ListValue());
+ for (size_t i = 0; i < countries.size(); ++i) {
+ std::unique_ptr<base::DictionaryValue> option_details(
+ new base::DictionaryValue());
+ option_details->SetString("name", model.GetItemAt(i));
+ option_details->SetString(
+ "value", countries[i] ? countries[i]->country_code() : "separator");
+ country_list->Append(std::move(option_details));
+ }
+ localized_strings->Set("autofillCountrySelectList", country_list.release());
+
+ std::unique_ptr<base::ListValue> default_country_components(
+ new base::ListValue);
+ std::string default_country_language_code;
+ GetAddressComponents(countries.front()->country_code(), ui_language_code,
+ default_country_components.get(),
+ &default_country_language_code);
+ localized_strings->Set("autofillDefaultCountryComponents",
+ default_country_components.release());
+ localized_strings->SetString("autofillDefaultCountryLanguageCode",
+ default_country_language_code);
+}
+
+} // namespace autofill
diff --git a/chromium/components/autofill/core/browser/autofill_address_util.h b/chromium/components/autofill/core/browser/autofill_address_util.h
new file mode 100644
index 00000000000..e90ff5bfabe
--- /dev/null
+++ b/chromium/components/autofill/core/browser/autofill_address_util.h
@@ -0,0 +1,78 @@
+// 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_AUTOFILL_ADDRESS_UTIL_H_
+#define COMPONENTS_AUTOFILL_CORE_BROWSER_AUTOFILL_ADDRESS_UTIL_H_
+
+#include <string>
+
+namespace base {
+class ListValue;
+class DictionaryValue;
+}
+
+namespace autofill {
+
+class PersonalDataManager;
+
+// Dictionary key for the field type.
+extern const char kFieldTypeKey[];
+
+// Dictionary key for the field length.
+extern const char kFieldLengthKey[];
+
+// Dictionary key for the field name.
+extern const char kFieldNameKey[];
+
+// Field name for autofill::NAME_FULL.
+extern const char kFullNameField[];
+
+// Field name for autofill::COMPANY_NAME.
+extern const char kCompanyNameField[];
+
+// Field name for autofill::ADDRESS_HOME_STREET_ADDRESS.
+extern const char kAddressLineField[];
+
+// Field name for autofill::ADDRESS_HOME_DEPENDENT_LOCALITY.
+extern const char kDependentLocalityField[];
+
+// Field name for autofill::ADDRESS_HOME_CITY.
+extern const char kCityField[];
+
+// Field name for autofill::ADDRESS_HOME_STATE.
+extern const char kStateField[];
+
+// Field name for autofill::ADDRESS_HOME_ZIP.
+extern const char kPostalCodeField[];
+
+// Field name for autofill::ADDRESS_HOME_SORTING_CODE.
+extern const char kSortingCodeField[];
+
+// Field name for autofill::ADDRESS_HOME_COUNTRY.
+extern const char kCountryField[];
+
+// AddressUiComponent::HINT_SHORT.
+extern const char kShortField[];
+
+// AddressUiComponent::HINT_LONG.
+extern const char kLongField[];
+
+// Fills |components| with the address UI components that should be used to
+// input an address for |country_code| when UI BCP 47 language code is
+// |ui_language_code|. If |components_language_code| is not NULL, then sets it
+// to the BCP 47 language code that should be used to format the address for
+// display.
+void GetAddressComponents(const std::string& country_code,
+ const std::string& ui_language_code,
+ base::ListValue* address_components,
+ std::string* components_language_code);
+
+// Sets data related to the country combobox.
+void SetCountryData(const PersonalDataManager& manager,
+ base::DictionaryValue* localized_strings,
+ const std::string& ui_language_code);
+
+} // namespace autofill
+
+#endif // COMPONENTS_AUTOFILL_CORE_BROWSER_AUTOFILL_ADDRESS_UTIL_H_
diff --git a/chromium/components/autofill/core/browser/autofill_assistant_unittest.cc b/chromium/components/autofill/core/browser/autofill_assistant_unittest.cc
index 3364c6f92fd..d5b27e105b2 100644
--- a/chromium/components/autofill/core/browser/autofill_assistant_unittest.cc
+++ b/chromium/components/autofill/core/browser/autofill_assistant_unittest.cc
@@ -103,7 +103,7 @@ class AutofillAssistantTest : public testing::Test {
std::unique_ptr<FormStructure> CreateValidCreditCardForm() {
std::unique_ptr<FormStructure> form_structure;
form_structure.reset(new FormStructure(CreateValidCreditCardFormData()));
- form_structure->DetermineHeuristicTypes();
+ form_structure->DetermineHeuristicTypes(nullptr /* ukm_service */);
return form_structure;
}
@@ -152,7 +152,7 @@ TEST_F(AutofillAssistantTest, CanShowCreditCardAssist_FeatureOn_Secure) {
// Can be shown if the context is secure.
FormData form = CreateValidCreditCardFormData();
std::unique_ptr<FormStructure> form_structure(new FormStructure(form));
- form_structure->DetermineHeuristicTypes();
+ form_structure->DetermineHeuristicTypes(nullptr /* ukm_service */);
std::vector<std::unique_ptr<FormStructure>> form_structures;
form_structures.push_back(std::move(form_structure));
@@ -169,7 +169,7 @@ TEST_F(AutofillAssistantTest, CanShowCreditCardAssist_FeatureOn_NotSecure) {
form.origin = GURL("http://myform.com");
form.action = GURL("http://myform.com/submit");
std::unique_ptr<FormStructure> form_structure(new FormStructure(form));
- form_structure->DetermineHeuristicTypes();
+ form_structure->DetermineHeuristicTypes(nullptr /* ukm_service */);
std::vector<std::unique_ptr<FormStructure>> form_structures;
form_structures.push_back(std::move(form_structure));
@@ -184,7 +184,7 @@ TEST_F(AutofillAssistantTest, CanShowCreditCardAssist_FeatureOn_Javascript) {
FormData form = CreateValidCreditCardFormData();
form.action = GURL("javascript:alert('hello');");
std::unique_ptr<FormStructure> form_structure(new FormStructure(form));
- form_structure->DetermineHeuristicTypes();
+ form_structure->DetermineHeuristicTypes(nullptr /* ukm_service */);
std::vector<std::unique_ptr<FormStructure>> form_structures;
form_structures.push_back(std::move(form_structure));
@@ -199,7 +199,7 @@ TEST_F(AutofillAssistantTest, CanShowCreditCardAssist_FeatureOn_WeirdJs) {
FormData form = CreateValidCreditCardFormData();
form.action = GURL("javascript:myFunc");
std::unique_ptr<FormStructure> form_structure(new FormStructure(form));
- form_structure->DetermineHeuristicTypes();
+ form_structure->DetermineHeuristicTypes(nullptr /* ukm_service */);
std::vector<std::unique_ptr<FormStructure>> form_structures;
form_structures.push_back(std::move(form_structure));
@@ -213,7 +213,7 @@ TEST_F(AutofillAssistantTest, CanShowCreditCardAssist_FeatureOn_EmptyAction) {
FormData form = CreateValidCreditCardFormData();
form.action = GURL();
std::unique_ptr<FormStructure> form_structure(new FormStructure(form));
- form_structure->DetermineHeuristicTypes();
+ form_structure->DetermineHeuristicTypes(nullptr /* ukm_service */);
std::vector<std::unique_ptr<FormStructure>> form_structures;
form_structures.push_back(std::move(form_structure));
diff --git a/chromium/components/autofill/core/browser/autofill_client.h b/chromium/components/autofill/core/browser/autofill_client.h
index d36f0026ffc..f6ff075d059 100644
--- a/chromium/components/autofill/core/browser/autofill_client.h
+++ b/chromium/components/autofill/core/browser/autofill_client.h
@@ -14,6 +14,7 @@
#include "base/memory/weak_ptr.h"
#include "base/strings/string16.h"
#include "base/values.h"
+#include "components/autofill/core/browser/risk_data_loader.h"
#include "ui/base/window_open_disposition.h"
#include "url/gurl.h"
@@ -48,6 +49,7 @@ class CardUnmaskDelegate;
class CreditCard;
class FormStructure;
class PersonalDataManager;
+class SaveCardBubbleController;
struct Suggestion;
// A client interface that needs to be supplied to the Autofill component by the
@@ -57,7 +59,7 @@ struct Suggestion;
// AutofillManager is used (e.g. a single tab), so when we say "for the client"
// below, we mean "in the execution context the client is associated with" (e.g.
// for the tab the AutofillManager is attached to).
-class AutofillClient {
+class AutofillClient : public RiskDataLoader {
public:
enum PaymentsRpcResult {
// Empty result. Used for initializing variables and should generally
@@ -89,7 +91,7 @@ class AutofillClient {
typedef base::Callback<void(const CreditCard&)> CreditCardScanCallback;
- virtual ~AutofillClient() {}
+ ~AutofillClient() override {}
// Gets the PersonalDataManager instance associated with the client.
virtual PersonalDataManager* GetPersonalDataManager() = 0;
@@ -109,9 +111,13 @@ class AutofillClient {
// Gets the RapporServiceImpl associated with the client (for metrics).
virtual rappor::RapporServiceImpl* GetRapporServiceImpl() = 0;
- // Gets the UKM service assiciated with this client (for metrics).
+ // Gets the UKM service associated with this client (for metrics).
virtual ukm::UkmService* GetUkmService() = 0;
+ // Gets the SaveCardBubbleController instance associated with the client.
+ // May return nullptr if the save card bubble has not been shown yet.
+ virtual SaveCardBubbleController* GetSaveCardBubbleController() = 0;
+
// Causes the Autofill settings UI to be shown.
virtual void ShowAutofillSettings() = 0;
@@ -128,10 +134,12 @@ class AutofillClient {
const base::Closure& callback) = 0;
// Runs |callback| if the |card| should be uploaded to Payments. Displays the
- // contents of |legal_message| to the user.
+ // contents of |legal_message| to the user. Display a CVC field in the bubble
+ // if |should_cvc_be_requested| is true.
virtual void ConfirmSaveCreditCardToCloud(
const CreditCard& card,
std::unique_ptr<base::DictionaryValue> legal_message,
+ bool should_cvc_be_requested,
const base::Closure& callback) = 0;
// Will show an infobar to get user consent for Credit Card assistive filling.
@@ -139,10 +147,6 @@ class AutofillClient {
virtual void ConfirmCreditCardFillAssist(const CreditCard& card,
const base::Closure& callback) = 0;
- // Gathers risk data and provides it to |callback|.
- virtual void LoadRiskData(
- const base::Callback<void(const std::string&)>& callback) = 0;
-
// Returns true if both the platform and the device support scanning credit
// cards. Should be called before ScanCreditCard().
virtual bool HasCreditCardScanFeature() = 0;
@@ -183,9 +187,6 @@ class AutofillClient {
const base::string16& autofilled_value,
const base::string16& profile_full_name) = 0;
- // Informs the client that a user gesture has been observed.
- virtual void OnFirstUserGestureObserved() = 0;
-
// If the context is secure.
virtual bool IsContextSecure() = 0;
diff --git a/chromium/components/autofill/core/browser/autofill_data_model_unittest.cc b/chromium/components/autofill/core/browser/autofill_data_model_unittest.cc
index 990217406a1..8432b105cf7 100644
--- a/chromium/components/autofill/core/browser/autofill_data_model_unittest.cc
+++ b/chromium/components/autofill/core/browser/autofill_data_model_unittest.cc
@@ -71,53 +71,63 @@ TEST(AutofillDataModelTest, IsVerified) {
EXPECT_FALSE(model.IsVerified());
}
-TEST(AutofillDataModelTest, CompareFrecency) {
- base::Time now = base::Time::Now();
- enum Expectation { GREATER, LESS };
-
- struct {
- const std::string guid_a;
- const int use_count_a;
- const base::Time use_date_a;
- const std::string guid_b;
- const int use_count_b;
- const base::Time use_date_b;
- Expectation expectation;
- } test_cases[] = {
- // Same frecency, model_a has a smaller GUID (tie breaker).
- {"guid_a", 8, now, "guid_b", 8, now, LESS},
- // Same recency, model_a has a bigger frequency.
- {"guid_a", 10, now, "guid_b", 8, now, GREATER},
- // Same recency, model_a has a smaller frequency.
- {"guid_a", 8, now, "guid_b", 10, now, LESS},
- // Same frequency, model_a is more recent.
- {"guid_a", 8, now, "guid_b", 8, now - base::TimeDelta::FromDays(1),
- GREATER},
- // Same frequency, model_a is less recent.
- {"guid_a", 8, now - base::TimeDelta::FromDays(1), "guid_b", 8, now, LESS},
- // Special case: occasional profiles. A profile with relatively low usage
- // and used recently (model_b) should not rank higher than a more used
- // profile that has been unused for a short amount of time (model_a).
- {"guid_a", 300, now - base::TimeDelta::FromDays(5), "guid_b", 10,
- now - base::TimeDelta::FromDays(1), GREATER},
- // Special case: moving. A new profile used frequently (model_b) should
- // rank higher than a profile with more usage that has not been used for a
- // while (model_a).
- {"guid_a", 300, now - base::TimeDelta::FromDays(15), "guid_b", 10,
- now - base::TimeDelta::FromDays(1), LESS},
- };
-
- for (auto test_case : test_cases) {
- TestAutofillDataModel model_a(test_case.guid_a, test_case.use_count_a,
- test_case.use_date_a);
- TestAutofillDataModel model_b(test_case.guid_b, test_case.use_count_b,
- test_case.use_date_b);
-
- EXPECT_EQ(test_case.expectation == GREATER,
- model_a.CompareFrecency(&model_b, now));
- EXPECT_NE(test_case.expectation == GREATER,
- model_b.CompareFrecency(&model_a, now));
- }
+enum Expectation { GREATER, LESS };
+struct CompareFrecencyTestCase {
+ const std::string guid_a;
+ const int use_count_a;
+ const base::Time use_date_a;
+ const std::string guid_b;
+ const int use_count_b;
+ const base::Time use_date_b;
+ Expectation expectation;
+};
+
+base::Time now = base::Time::Now();
+
+class CompareFrecencyTest
+ : public testing::TestWithParam<CompareFrecencyTestCase> {};
+
+TEST_P(CompareFrecencyTest, CompareFrecency) {
+ auto test_case = GetParam();
+ TestAutofillDataModel model_a(test_case.guid_a, test_case.use_count_a,
+ test_case.use_date_a);
+ TestAutofillDataModel model_b(test_case.guid_b, test_case.use_count_b,
+ test_case.use_date_b);
+
+ EXPECT_EQ(test_case.expectation == GREATER,
+ model_a.CompareFrecency(&model_b, now));
+ EXPECT_NE(test_case.expectation == GREATER,
+ model_b.CompareFrecency(&model_a, now));
}
+INSTANTIATE_TEST_CASE_P(
+ AutofillDataModelTest,
+ CompareFrecencyTest,
+ testing::Values(
+ // Same frecency, model_a has a smaller GUID (tie breaker).
+ CompareFrecencyTestCase{"guid_a", 8, now, "guid_b", 8, now, LESS},
+ // Same recency, model_a has a bigger frequency.
+ CompareFrecencyTestCase{"guid_a", 10, now, "guid_b", 8, now, GREATER},
+ // Same recency, model_a has a smaller frequency.
+ CompareFrecencyTestCase{"guid_a", 8, now, "guid_b", 10, now, LESS},
+ // Same frequency, model_a is more recent.
+ CompareFrecencyTestCase{"guid_a", 8, now, "guid_b", 8,
+ now - base::TimeDelta::FromDays(1), GREATER},
+ // Same frequency, model_a is less recent.
+ CompareFrecencyTestCase{"guid_a", 8, now - base::TimeDelta::FromDays(1),
+ "guid_b", 8, now, LESS},
+ // Special case: occasional profiles. A profile with relatively low
+ // usage and used recently (model_b) should not rank higher than a more
+ // used profile that has been unused for a short amount of time
+ // (model_a).
+ CompareFrecencyTestCase{
+ "guid_a", 300, now - base::TimeDelta::FromDays(5), "guid_b", 10,
+ now - base::TimeDelta::FromDays(1), GREATER},
+ // Special case: moving. A new profile used frequently (model_b) should
+ // rank higher than a profile with more usage that has not been used for
+ // a while (model_a).
+ CompareFrecencyTestCase{"guid_a", 300,
+ now - base::TimeDelta::FromDays(15), "guid_b",
+ 10, now - base::TimeDelta::FromDays(1), LESS}));
+
} // namespace autofill
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 584690d7871..9aadd58bf4f 100644
--- a/chromium/components/autofill/core/browser/autofill_data_util_unittest.cc
+++ b/chromium/components/autofill/core/browser/autofill_data_util_unittest.cc
@@ -11,151 +11,166 @@
namespace autofill {
namespace data_util {
-TEST(AutofillDataUtilTest, IsCJKName) {
- typedef struct {
- const char* full_name;
- bool is_cjk;
- } TestCase;
-
- TestCase test_cases[] = {
- // Non-CJK language with only ASCII characters.
- {"Homer Jay Simpson", false},
- // Non-CJK language with some ASCII characters.
- {"Éloïse Paré", false},
- // Non-CJK language with no ASCII characters.
- {"Σωκράτης", false},
-
- // (Simplified) Chinese name, Unihan.
- {"刘翔", true},
- // (Simplified) Chinese name, Unihan, with an ASCII space.
- {"成 龙", true},
- // Korean name, Hangul.
- {"송지효", true},
- // Korean name, Hangul, with an 'IDEOGRAPHIC SPACE' (U+3000).
- {"김 종국", true},
- // Japanese name, Unihan.
- {"山田貴洋", true},
- // Japanese name, Katakana, with a 'KATAKANA MIDDLE DOT' (U+30FB).
- {"ビル・ゲイツ", true},
- // Japanese name, Katakana, with a 'MIDDLE DOT' (U+00B7) (likely a typo).
- {"ビル·ゲイツ", true},
-
- // CJK names don't have a middle name, so a 3-part name is bogus to us.
- {"반 기 문", false}
- };
-
- for (const TestCase& test_case : test_cases) {
- EXPECT_EQ(test_case.is_cjk,
- IsCJKName(base::UTF8ToUTF16(test_case.full_name)))
- << "Failed for: " << test_case.full_name;
- }
+struct IsCJKNameTestCase {
+ const char* full_name;
+ bool is_cjk;
+};
+
+class IsCJKNameTest : public testing::TestWithParam<IsCJKNameTestCase> {};
+
+TEST_P(IsCJKNameTest, IsCJKName) {
+ auto test_case = GetParam();
+ EXPECT_EQ(test_case.is_cjk, IsCJKName(base::UTF8ToUTF16(test_case.full_name)))
+ << "Failed for: " << test_case.full_name;
}
-TEST(AutofillDataUtilTest, SplitName) {
- typedef struct {
- std::string full_name;
- std::string given_name;
- std::string middle_name;
- std::string family_name;
-
- } TestCase;
-
- const TestCase test_cases[] = {
- // Full name including given, middle and family names.
- {"Homer Jay Simpson", "Homer", "Jay", "Simpson"},
- // No middle name.
- {"Moe Szyslak", "Moe", "", "Szyslak"},
- // Common name prefixes removed.
- {"Reverend Timothy Lovejoy", "Timothy", "", "Lovejoy"},
- // Common name suffixes removed.
- {"John Frink Phd", "John", "", "Frink"},
- // Exception to the name suffix removal.
- {"John Ma", "John", "", "Ma"},
- // Common family name prefixes not considered a middle name.
- {"Milhouse Van Houten", "Milhouse", "", "Van Houten"},
-
- // CJK names have reverse order (surname goes first, given name goes
- // second).
- {"孫 德明", "德明", "", "孫"}, // Chinese name, Unihan
- {"孫 德明", "德明", "", "孫"}, // Chinese name, Unihan, 'IDEOGRAPHIC SPACE'
- {"홍 길동", "길동", "", "홍"}, // Korean name, Hangul
- {"山田 貴洋", "貴洋", "", "山田"}, // Japanese name, Unihan
-
- // In Japanese, foreign names use 'KATAKANA MIDDLE DOT' (U+30FB) as a
- // separator. There is no consensus for the ordering. For now, we use the
- // same ordering as regular Japanese names ("last・first").
- {"ゲイツ・ビル", "ビル", "", "ゲイツ"}, // Foreign name in Japanese, Katakana
- // 'KATAKANA MIDDLE DOT' is occasionally typoed as 'MIDDLE DOT' (U+00B7).
- {"ゲイツ·ビル", "ビル", "", "ゲイツ"}, // Foreign name in Japanese, Katakana
-
- // CJK names don't usually have a space in the middle, but most of the
- // time, the surname is only one character (in Chinese & Korean).
- {"최성훈", "성훈", "", "최"}, // Korean name, Hangul
- {"刘翔", "翔", "", "刘"}, // (Simplified) Chinese name, Unihan
- {"劉翔", "翔", "", "劉"}, // (Traditional) Chinese name, Unihan
-
- // There are a few exceptions. Occasionally, the surname has two
- // characters.
- {"남궁도", "도", "", "남궁"}, // Korean name, Hangul
- {"황보혜정", "혜정", "", "황보"}, // Korean name, Hangul
- {"歐陽靖", "靖", "", "歐陽"}, // (Traditional) Chinese name, Unihan
-
- // In Korean, some 2-character surnames are rare/ambiguous, like "강전":
- // "강" is a common surname, and "전" can be part of a given name. In
- // those cases, we assume it's 1/2 for 3-character names, or 2/2 for
- // 4-character names.
- {"강전희", "전희", "", "강"}, // Korean name, Hangul
- {"황목치승", "치승", "", "황목"}, // Korean name, Hangul
-
- // It occasionally happens that a full name is 2 characters, 1/1.
- {"이도", "도", "", "이"}, // Korean name, Hangul
- {"孫文", "文", "", "孫"} // Chinese name, Unihan
- };
-
- for (TestCase test_case : test_cases) {
- NameParts name_parts = SplitName(base::UTF8ToUTF16(test_case.full_name));
-
- EXPECT_EQ(base::UTF8ToUTF16(test_case.given_name), name_parts.given);
- EXPECT_EQ(base::UTF8ToUTF16(test_case.middle_name), name_parts.middle);
- EXPECT_EQ(base::UTF8ToUTF16(test_case.family_name), name_parts.family);
- }
+INSTANTIATE_TEST_CASE_P(
+ AutofillDataUtilTest,
+ IsCJKNameTest,
+ testing::Values(
+ // Non-CJK language with only ASCII characters.
+ IsCJKNameTestCase{"Homer Jay Simpson", false},
+ // Non-CJK language with some ASCII characters.
+ IsCJKNameTestCase{"Éloïse Paré", false},
+ // Non-CJK language with no ASCII characters.
+ IsCJKNameTestCase{"Σωκράτης", false},
+
+ // (Simplified) Chinese name, Unihan.
+ IsCJKNameTestCase{"刘翔", true},
+ // (Simplified) Chinese name, Unihan, with an ASCII space.
+ IsCJKNameTestCase{"成 龙", true},
+ // Korean name, Hangul.
+ IsCJKNameTestCase{"송지효", true},
+ // Korean name, Hangul, with an 'IDEOGRAPHIC SPACE' (U+3000).
+ IsCJKNameTestCase{"김 종국", true},
+ // Japanese name, Unihan.
+ IsCJKNameTestCase{"山田貴洋", true},
+ // Japanese name, Katakana, with a 'KATAKANA MIDDLE DOT' (U+30FB).
+ IsCJKNameTestCase{"ビル・ゲイツ", true},
+ // Japanese name, Katakana, with a 'MIDDLE DOT' (U+00B7) (likely a
+ // typo).
+ IsCJKNameTestCase{"ビル·ゲイツ", true},
+
+ // CJK names don't have a middle name, so a 3-part name is bogus to us.
+ IsCJKNameTestCase{"반 기 문", false}));
+
+struct FullNameTestCase {
+ std::string full_name;
+ std::string given_name;
+ std::string middle_name;
+ std::string family_name;
+};
+
+class SplitNameTest : public testing::TestWithParam<FullNameTestCase> {};
+
+TEST_P(SplitNameTest, SplitName) {
+ auto test_case = GetParam();
+ NameParts name_parts = SplitName(base::UTF8ToUTF16(test_case.full_name));
+
+ EXPECT_EQ(base::UTF8ToUTF16(test_case.given_name), name_parts.given);
+ EXPECT_EQ(base::UTF8ToUTF16(test_case.middle_name), name_parts.middle);
+ EXPECT_EQ(base::UTF8ToUTF16(test_case.family_name), name_parts.family);
}
-TEST(AutofillDataUtilTest, JoinNameParts) {
- typedef struct {
- std::string given_name;
- std::string middle_name;
- std::string family_name;
- std::string full_name;
- } TestCase;
-
- TestCase test_cases[] = {
- // Full name including given, middle and family names.
- {"Homer", "Jay", "Simpson", "Homer Jay Simpson"},
- // No middle name.
- {"Moe", "", "Szyslak", "Moe Szyslak"},
-
- // CJK names have reversed order, no space.
- {"德明", "", "孫", "孫德明"}, // Chinese name, Unihan
- {"길동", "", "홍", "홍길동"}, // Korean name, Hangul
- {"貴洋", "", "山田", "山田貴洋"}, // Japanese name, Unihan
-
- // These are no CJK names for us, they're just bogus.
- {"Homer", "", "シンプソン", "Homer シンプソン"},
- {"ホーマー", "", "Simpson", "ホーマー Simpson"},
- {"반", "기", "문", "반 기 문"} // Has a middle-name, too unusual
- };
-
- for (const TestCase& test_case : test_cases) {
- base::string16 joined = JoinNameParts(
- base::UTF8ToUTF16(test_case.given_name),
- base::UTF8ToUTF16(test_case.middle_name),
- base::UTF8ToUTF16(test_case.family_name));
-
- EXPECT_EQ(base::UTF8ToUTF16(test_case.full_name), joined);
- }
+INSTANTIATE_TEST_CASE_P(
+ AutofillDataUtil,
+ SplitNameTest,
+ testing::Values(
+ // Full name including given, middle and family names.
+ FullNameTestCase{"Homer Jay Simpson", "Homer", "Jay", "Simpson"},
+ // No middle name.
+ FullNameTestCase{"Moe Szyslak", "Moe", "", "Szyslak"},
+ // Common name prefixes removed.
+ FullNameTestCase{"Reverend Timothy Lovejoy", "Timothy", "", "Lovejoy"},
+ // Common name suffixes removed.
+ FullNameTestCase{"John Frink Phd", "John", "", "Frink"},
+ // Exception to the name suffix removal.
+ FullNameTestCase{"John Ma", "John", "", "Ma"},
+ // Common family name prefixes not considered a middle name.
+ FullNameTestCase{"Milhouse Van Houten", "Milhouse", "", "Van Houten"},
+
+ // CJK names have reverse order (surname goes first, given name goes
+ // second).
+ FullNameTestCase{"孫 德明", "德明", "", "孫"}, // Chinese name, Unihan
+ FullNameTestCase{"孫 德明", "德明", "",
+ "孫"}, // Chinese name, Unihan, 'IDEOGRAPHIC SPACE'
+ FullNameTestCase{"홍 길동", "길동", "", "홍"}, // Korean name, Hangul
+ FullNameTestCase{"山田 貴洋", "貴洋", "",
+ "山田"}, // Japanese name, Unihan
+
+ // In Japanese, foreign names use 'KATAKANA MIDDLE DOT' (U+30FB) as a
+ // separator. There is no consensus for the ordering. For now, we use
+ // the same ordering as regular Japanese names ("last・first").
+ FullNameTestCase{"ゲイツ・ビル", "ビル", "",
+ "ゲイツ"}, // Foreign name in Japanese, Katakana
+ // 'KATAKANA MIDDLE DOT' is occasionally typoed as 'MIDDLE DOT'
+ // (U+00B7).
+ FullNameTestCase{"ゲイツ·ビル", "ビル", "",
+ "ゲイツ"}, // Foreign name in Japanese, Katakana
+
+ // CJK names don't usually have a space in the middle, but most of the
+ // time, the surname is only one character (in Chinese & Korean).
+ FullNameTestCase{"최성훈", "성훈", "", "최"}, // Korean name, Hangul
+ FullNameTestCase{"刘翔", "翔", "",
+ "刘"}, // (Simplified) Chinese name, Unihan
+ FullNameTestCase{"劉翔", "翔", "",
+ "劉"}, // (Traditional) Chinese name, Unihan
+
+ // There are a few exceptions. Occasionally, the surname has two
+ // characters.
+ FullNameTestCase{"남궁도", "도", "", "남궁"}, // Korean name, Hangul
+ FullNameTestCase{"황보혜정", "혜정", "",
+ "황보"}, // Korean name, Hangul
+ FullNameTestCase{"歐陽靖", "靖", "",
+ "歐陽"}, // (Traditional) Chinese name, Unihan
+
+ // In Korean, some 2-character surnames are rare/ambiguous, like "강전":
+ // "강" is a common surname, and "전" can be part of a given name. In
+ // those cases, we assume it's 1/2 for 3-character names, or 2/2 for
+ // 4-character names.
+ FullNameTestCase{"강전희", "전희", "", "강"}, // Korean name, Hangul
+ FullNameTestCase{"황목치승", "치승", "",
+ "황목"}, // Korean name, Hangul
+
+ // It occasionally happens that a full name is 2 characters, 1/1.
+ FullNameTestCase{"이도", "도", "", "이"}, // Korean name, Hangul
+ FullNameTestCase{"孫文", "文", "", "孫"} // Chinese name, Unihan
+ ));
+
+class JoinNamePartsTest : public testing::TestWithParam<FullNameTestCase> {};
+
+TEST_P(JoinNamePartsTest, JoinNameParts) {
+ auto test_case = GetParam();
+ base::string16 joined =
+ JoinNameParts(base::UTF8ToUTF16(test_case.given_name),
+ base::UTF8ToUTF16(test_case.middle_name),
+ base::UTF8ToUTF16(test_case.family_name));
+
+ EXPECT_EQ(base::UTF8ToUTF16(test_case.full_name), joined);
}
+INSTANTIATE_TEST_CASE_P(
+ AutofillDataUtil,
+ JoinNamePartsTest,
+ testing::Values(
+ // Full name including given, middle and family names.
+ FullNameTestCase{"Homer Jay Simpson", "Homer", "Jay", "Simpson"},
+ // No middle name.
+ FullNameTestCase{"Moe Szyslak", "Moe", "", "Szyslak"},
+
+ // CJK names have reversed order, no space.
+ FullNameTestCase{"孫德明", "德明", "", "孫"}, // Chinese name, Unihan
+ FullNameTestCase{"홍길동", "길동", "", "홍"}, // Korean name, Hangul
+ FullNameTestCase{"山田貴洋", "貴洋", "",
+ "山田"}, // Japanese name, Unihan
+
+ // These are no CJK names for us, they're just bogus.
+ FullNameTestCase{"Homer シンプソン", "Homer", "", "シンプソン"},
+ FullNameTestCase{"ホーマー Simpson", "ホーマー", "", "Simpson"},
+ FullNameTestCase{"반 기 문", "반", "기", "문"}
+ // Has a middle-name, too unusual
+ ));
+
TEST(AutofillDataUtilTest, ProfileMatchesFullName) {
autofill::AutofillProfile profile;
autofill::test::SetProfileInfo(
diff --git a/chromium/components/autofill/core/browser/autofill_download_manager.cc b/chromium/components/autofill/core/browser/autofill_download_manager.cc
index 07084c52be4..8d7d72588f4 100644
--- a/chromium/components/autofill/core/browser/autofill_download_manager.cc
+++ b/chromium/components/autofill/core/browser/autofill_download_manager.cc
@@ -24,9 +24,82 @@
#include "net/http/http_request_headers.h"
#include "net/http/http_response_headers.h"
#include "net/http/http_status_code.h"
+#include "net/traffic_annotation/network_traffic_annotation.h"
#include "net/url_request/url_fetcher.h"
#include "url/gurl.h"
+namespace {
+
+net::NetworkTrafficAnnotationTag GetNetworkTrafficAnnotation(
+ const autofill::AutofillDownloadManager::RequestType& request_type) {
+ if (request_type == autofill::AutofillDownloadManager::REQUEST_QUERY) {
+ return net::DefineNetworkTrafficAnnotation("autofill_query", R"(
+ semantics {
+ sender: "Autofill"
+ description:
+ "Chromium can automatically fill in web forms. If the feature is "
+ "enabled, Chromium will send a non-identifying description of the "
+ "form to Google's servers, which will respond with the type of "
+ "data required by each of the form's fields, if known. I.e., if a "
+ "field expects to receive a name, phone number, street address, "
+ "etc."
+ trigger: "User encounters a web form."
+ data:
+ "Hashed descriptions of the form and its fields. User data is not "
+ "sent."
+ destination: GOOGLE_OWNED_SERVICE
+ }
+ policy {
+ cookies_allowed: false
+ setting:
+ "You can enable or disable this feature via 'Enable autofill to "
+ "fill out web forms in a single click.' in Chromium's settings "
+ "under 'Passwords and forms'. The feature is enabled by default."
+ chrome_policy {
+ AutoFillEnabled {
+ policy_options {mode: MANDATORY}
+ AutoFillEnabled: false
+ }
+ }
+ })");
+ }
+
+ DCHECK_EQ(request_type, autofill::AutofillDownloadManager::REQUEST_UPLOAD);
+ return net::DefineNetworkTrafficAnnotation("autofill_upload", R"(
+ semantics {
+ sender: "Autofill"
+ description:
+ "Chromium relies on crowd-sourced field type classifications to "
+ "help it automatically fill in web forms. If the feature is "
+ "enabled, Chromium will send a non-identifying description of the "
+ "form to Google's servers along with the type of data Chromium "
+ "observed being given to the form. I.e., if you entered your first "
+ "name into a form field, Chromium will 'vote' for that form field "
+ "being a first name field."
+ trigger: "User submits a web form."
+ data:
+ "Hashed descriptions of the form and its fields along with type of "
+ "data given to each field, if recognized from the user's "
+ "profile(s). User data is not sent."
+ destination: GOOGLE_OWNED_SERVICE
+ }
+ policy {
+ cookies_allowed: false
+ setting:
+ "You can enable or disable this feature via 'Enable autofill to "
+ "fill out web forms in a single click.' in Chromium's settings "
+ "under 'Passwords and forms'. The feature is enabled by default."
+ chrome_policy {
+ AutoFillEnabled {
+ policy_options {mode: MANDATORY}
+ AutoFillEnabled: false
+ }
+ }
+ })");
+}
+
+} // namespace
+
namespace autofill {
namespace {
@@ -234,7 +307,8 @@ bool AutofillDownloadManager::StartRequest(
// Id is ignored for regular chrome, in unit test id's for fake fetcher
// factory will be 0, 1, 2, ...
std::unique_ptr<net::URLFetcher> owned_fetcher = net::URLFetcher::Create(
- fetcher_id_for_unittest_++, request_url, net::URLFetcher::POST, this);
+ fetcher_id_for_unittest_++, request_url, net::URLFetcher::POST, this,
+ GetNetworkTrafficAnnotation(request_data.request_type));
net::URLFetcher* fetcher = owned_fetcher.get();
data_use_measurement::DataUseUserData::AttachToFetcher(
fetcher, data_use_measurement::DataUseUserData::AUTOFILL);
@@ -251,7 +325,7 @@ bool AutofillDownloadManager::StartRequest(
// not affect transmission of experiments coming from the variations server.
bool is_signed_in = false;
variations::AppendVariationHeaders(fetcher->GetOriginalURL(),
- driver_->IsOffTheRecord(), false,
+ driver_->IsIncognito(), false,
is_signed_in, &headers);
fetcher->SetExtraRequestHeaders(headers.ToString());
fetcher->Start();
diff --git a/chromium/components/autofill/core/browser/autofill_driver.h b/chromium/components/autofill/core/browser/autofill_driver.h
index e8b95d87a02..cc1a5fd38c1 100644
--- a/chromium/components/autofill/core/browser/autofill_driver.h
+++ b/chromium/components/autofill/core/browser/autofill_driver.h
@@ -40,9 +40,8 @@ class AutofillDriver {
virtual ~AutofillDriver() {}
- // Returns whether the user is currently operating in an off-the-record
- // (i.e., incognito) context.
- virtual bool IsOffTheRecord() const = 0;
+ // Returns whether the user is currently operating in an incognito context.
+ virtual bool IsIncognito() const = 0;
// Returns the URL request context information associated with this driver.
virtual net::URLRequestContextGetter* GetURLRequestContext() = 0;
@@ -103,10 +102,6 @@ class AutofillDriver {
// Called when the user interacted with a credit card form, so that
// the current page's security state can be updated appropriately.
virtual void DidInteractWithCreditCardForm() = 0;
-
- // Tells the associated frame that a user gesture was observed somewhere in
- // the tab (including in a different frame).
- virtual void NotifyFirstUserGestureObservedInTab() {}
};
} // namespace autofill
diff --git a/chromium/components/autofill/core/browser/autofill_driver_factory.cc b/chromium/components/autofill/core/browser/autofill_driver_factory.cc
index 224c1efde47..58ec815c2ba 100644
--- a/chromium/components/autofill/core/browser/autofill_driver_factory.cc
+++ b/chromium/components/autofill/core/browser/autofill_driver_factory.cc
@@ -21,7 +21,6 @@ AutofillDriver* AutofillDriverFactory::DriverForKey(void* key) {
}
void AutofillDriverFactory::NavigationFinished() {
- user_gesture_seen_ = false;
client_->HideAutofillPopup();
}
@@ -29,16 +28,6 @@ void AutofillDriverFactory::TabHidden() {
client_->HideAutofillPopup();
}
-void AutofillDriverFactory::OnFirstUserGestureObserved() {
- if (user_gesture_seen_)
- return;
-
- for (auto& driver : driver_map_)
- driver.second->NotifyFirstUserGestureObservedInTab();
-
- user_gesture_seen_ = true;
-}
-
void AutofillDriverFactory::AddForKey(
void* key,
base::Callback<std::unique_ptr<AutofillDriver>()> factory_method) {
@@ -46,8 +35,6 @@ void AutofillDriverFactory::AddForKey(
// This can be called twice for the key representing the main frame.
if (insertion_result.second) {
insertion_result.first->second = factory_method.Run();
- if (user_gesture_seen_)
- insertion_result.first->second->NotifyFirstUserGestureObservedInTab();
}
}
diff --git a/chromium/components/autofill/core/browser/autofill_driver_factory.h b/chromium/components/autofill/core/browser/autofill_driver_factory.h
index ff48bb67ec3..f5e21c68257 100644
--- a/chromium/components/autofill/core/browser/autofill_driver_factory.h
+++ b/chromium/components/autofill/core/browser/autofill_driver_factory.h
@@ -34,12 +34,6 @@ class AutofillDriverFactory {
// Handles hiding of the corresponding tab.
void TabHidden();
- // Call this to notify the factory that one of the frames saw a user gesture.
- // The factory will distribute this information to all drivers when it comes
- // for the first time since the last main frame navigation to a different
- // page. It will also notify drivers added later (see AddForKey).
- void OnFirstUserGestureObserved();
-
AutofillClient* client() { return client_; };
protected:
@@ -61,8 +55,6 @@ class AutofillDriverFactory {
std::unordered_map<void*, std::unique_ptr<AutofillDriver>> driver_map_;
- bool user_gesture_seen_ = false; // The state for OnFirstUserGestureObserved.
-
DISALLOW_COPY_AND_ASSIGN(AutofillDriverFactory);
};
diff --git a/chromium/components/autofill/core/browser/autofill_driver_factory_unittest.cc b/chromium/components/autofill/core/browser/autofill_driver_factory_unittest.cc
index 8355161333c..fdc88828cb2 100644
--- a/chromium/components/autofill/core/browser/autofill_driver_factory_unittest.cc
+++ b/chromium/components/autofill/core/browser/autofill_driver_factory_unittest.cc
@@ -36,19 +36,8 @@ class CountingAutofillDriver : public TestAutofillDriver {
~CountingAutofillDriver() override { --*instance_counter_; }
- // Note that EXPECT_CALL cannot be used here, because creation and
- // notification of the same driver might be done by a single AddForKey call
- // from the test. Therefore tracking the "gesture_observed" flag is done
- // explicitly here.
- void NotifyFirstUserGestureObservedInTab() override {
- gesture_observed_ = true;
- }
-
- bool gesture_observed() { return gesture_observed_; }
-
private:
int* const instance_counter_;
- bool gesture_observed_ = false;
DISALLOW_COPY_AND_ASSIGN(CountingAutofillDriver);
};
@@ -187,54 +176,4 @@ TEST_F(AutofillDriverFactoryTest, TabHidden) {
factory_.TabHidden();
}
-// Without calling OnFirstUserGestureObserved on the factory, the factory will
-// not call NotifyFirstUserGestureObservedInTab on a driver.
-TEST_F(AutofillDriverFactoryTest, OnFirstUserGestureObserved_NotCalled) {
- factory_.AddForKey(KeyFrom(1), CreateDriverCallback());
- EXPECT_FALSE(GetDriver(KeyFrom(1))->gesture_observed());
-}
-
-// Call OnFirstUserGestureObserved on the factory with one driver. The factory
-// will call NotifyFirstUserGestureObservedInTab on that driver.
-TEST_F(AutofillDriverFactoryTest, OnFirstUserGestureObserved_CalledOld) {
- factory_.AddForKey(KeyFrom(1), CreateDriverCallback());
- factory_.OnFirstUserGestureObserved();
- EXPECT_TRUE(GetDriver(KeyFrom(1))->gesture_observed());
-}
-
-// Call OnFirstUserGestureObserved on the factory without drivers. Add a
-// driver. The factory will call NotifyFirstUserGestureObservedInTab on that
-// driver.
-TEST_F(AutofillDriverFactoryTest, OnFirstUserGestureObserved_CalledNew) {
- factory_.OnFirstUserGestureObserved();
- factory_.AddForKey(KeyFrom(1), CreateDriverCallback());
- EXPECT_TRUE(GetDriver(KeyFrom(1))->gesture_observed());
-}
-
-// Combining the CalledOld and CalledNew test cases into one.
-TEST_F(AutofillDriverFactoryTest, OnFirstUserGestureObserved_MultipleDrivers) {
- factory_.AddForKey(KeyFrom(1), CreateDriverCallback());
- factory_.OnFirstUserGestureObserved();
- EXPECT_TRUE(GetDriver(KeyFrom(1))->gesture_observed());
-
- factory_.AddForKey(KeyFrom(7), CreateDriverCallback());
- EXPECT_TRUE(GetDriver(KeyFrom(7))->gesture_observed());
-}
-
-// Call OnFirstUserGestureObserved on the factory with one driver. Simulate
-// navigation to a different page. Add a driver. The factory will not call
-// NotifyFirstUserGestureObservedInTab on that driver.
-TEST_F(AutofillDriverFactoryTest, OnFirstUserGestureObserved_CalledNavigation) {
- factory_.AddForKey(KeyFrom(1), CreateDriverCallback());
- factory_.OnFirstUserGestureObserved();
- EXPECT_TRUE(GetDriver(KeyFrom(1))->gesture_observed());
-
- EXPECT_CALL(client_, HideAutofillPopup());
- factory_.NavigationFinished();
-
- // Adding a sub-frame
- factory_.AddForKey(KeyFrom(2), CreateDriverCallback());
- EXPECT_FALSE(GetDriver(KeyFrom(2))->gesture_observed());
-}
-
} // namespace autofill
diff --git a/chromium/components/autofill/core/browser/autofill_experiments.cc b/chromium/components/autofill/core/browser/autofill_experiments.cc
index b27569f4d8c..ef37213e57a 100644
--- a/chromium/components/autofill/core/browser/autofill_experiments.cc
+++ b/chromium/components/autofill/core/browser/autofill_experiments.cc
@@ -32,8 +32,10 @@ const base::Feature kAutofillCreditCardPopupLayout{
"AutofillCreditCardPopupLayout", base::FEATURE_DISABLED_BY_DEFAULT};
const base::Feature kAutofillCreditCardLastUsedDateDisplay{
"AutofillCreditCardLastUsedDateDisplay", base::FEATURE_DISABLED_BY_DEFAULT};
-const base::Feature kAutofillUkmLogging{"kAutofillUkmLogging",
+const base::Feature kAutofillUkmLogging{"AutofillUkmLogging",
base::FEATURE_DISABLED_BY_DEFAULT};
+const base::Feature kAutofillUpstreamRequestCvcIfMissing{
+ "AutofillUpstreamRequestCvcIfMissing", base::FEATURE_DISABLED_BY_DEFAULT};
const char kCreditCardSigninPromoImpressionLimitParamKey[] = "impression_limit";
const char kAutofillCreditCardPopupBackgroundColorKey[] = "background_color";
const char kAutofillCreditCardPopupDividerColorKey[] = "dropdown_divider_color";
@@ -229,4 +231,12 @@ bool IsUkmLoggingEnabled() {
return base::FeatureList::IsEnabled(kAutofillUkmLogging);
}
+bool IsAutofillUpstreamRequestCvcIfMissingExperimentEnabled() {
+#if defined(OS_ANDROID)
+ return false;
+#else
+ return base::FeatureList::IsEnabled(kAutofillUpstreamRequestCvcIfMissing);
+#endif
+}
+
} // namespace autofill
diff --git a/chromium/components/autofill/core/browser/autofill_experiments.h b/chromium/components/autofill/core/browser/autofill_experiments.h
index 70c3f411c60..ba03ac21eb7 100644
--- a/chromium/components/autofill/core/browser/autofill_experiments.h
+++ b/chromium/components/autofill/core/browser/autofill_experiments.h
@@ -29,6 +29,7 @@ extern const base::Feature kAutofillScanCardholderName;
extern const base::Feature kAutofillCreditCardPopupLayout;
extern const base::Feature kAutofillCreditCardLastUsedDateDisplay;
extern const base::Feature kAutofillUkmLogging;
+extern const base::Feature kAutofillUpstreamRequestCvcIfMissing;
extern const char kCreditCardSigninPromoImpressionLimitParamKey[];
extern const char kAutofillCreditCardPopupSettingsSuggestionValueKey[];
extern const char kAutofillCreditCardLastUsedDateShowExpirationDateKey[];
@@ -104,6 +105,10 @@ unsigned int GetPopupMargin();
// Returns whether the feature to log UKMs is enabled.
bool IsUkmLoggingEnabled();
+// Returns whether the experiment is enabled where Chrome Upstream requests CVC
+// in the offer to save bubble if it was not detected during the checkout flow.
+bool IsAutofillUpstreamRequestCvcIfMissingExperimentEnabled();
+
} // namespace autofill
#endif // COMPONENTS_AUTOFILL_CORE_BROWSER_AUTOFILL_EXPERIMENTS_H_
diff --git a/chromium/components/autofill/core/browser/autofill_field_unittest.cc b/chromium/components/autofill/core/browser/autofill_field_unittest.cc
index ef4c0473f9a..5731f376ace 100644
--- a/chromium/components/autofill/core/browser/autofill_field_unittest.cc
+++ b/chromium/components/autofill/core/browser/autofill_field_unittest.cc
@@ -283,181 +283,240 @@ TEST_F(AutofillFieldTest, FillFormField_AutocompleteOff_CreditCardField) {
EXPECT_EQ(ASCIIToUTF16("4111111111111111"), field.value);
}
+struct AutofillFieldTestCase {
+ HtmlFieldType field_type;
+ size_t field_max_length;
+ std::string value_to_fill;
+ std::string expected_value;
+};
+
+class AutofillFieldPhoneNumberTest
+ : public testing::TestWithParam<AutofillFieldTestCase> {
+ public:
+ AutofillFieldPhoneNumberTest() { CountryNames::SetLocaleString("en-US"); }
+};
+
// TODO(crbug.com/581514): Add support for filling only the prefix/suffix for
// phone numbers with 10 or 11 digits.
-TEST_F(AutofillFieldTest, FillPhoneNumber) {
- typedef struct {
- HtmlFieldType field_type;
- size_t field_max_length;
- std::string value_to_fill;
- std::string expected_value;
- } TestCase;
-
- TestCase test_cases[] = {
- // Filling a phone type field with text should fill the text as is.
- {HTML_TYPE_TEL, /* default value */ 0, "Oh hai", "Oh hai"},
- // Filling a prefix type field with a phone number of 7 digits should just
- // fill the prefix.
- {HTML_TYPE_TEL_LOCAL_PREFIX, /* default value */ 0, "5551234", "555"},
- // Filling a suffix type field with a phone number of 7 digits should just
- // fill the suffix.
- {HTML_TYPE_TEL_LOCAL_SUFFIX, /* default value */ 0, "5551234", "1234"},
- // Filling a phone type field with a max length of 3 with a phone number
- // of
- // 7 digits should fill only the prefix.
- {HTML_TYPE_TEL, 3, "5551234", "555"},
- // Filling a phone type field with a max length of 4 with a phone number
- // of
- // 7 digits should fill only the suffix.
- {HTML_TYPE_TEL, 4, "5551234", "1234"},
- // Filling a phone type field with a max length of 10 with a phone number
- // including the country code should fill the phone number without the
- // country code.
- {HTML_TYPE_TEL, 10, "15141254578", "5141254578"},
- // Filling a phone type field with a max length of 5 with a phone number
- // should fill with the last 5 digits of that phone number.
- {HTML_TYPE_TEL, 5, "5141254578", "54578"}};
-
- for (TestCase test_case : test_cases) {
- AutofillField field;
- field.SetHtmlType(test_case.field_type, HtmlFieldMode());
- field.max_length = test_case.field_max_length;
-
- AutofillField::FillFormField(field, ASCIIToUTF16(test_case.value_to_fill),
- "en-US", "en-US", &field);
- EXPECT_EQ(ASCIIToUTF16(test_case.expected_value), field.value);
- }
+TEST_P(AutofillFieldPhoneNumberTest, FillPhoneNumber) {
+ auto test_case = GetParam();
+ AutofillField field;
+ field.SetHtmlType(test_case.field_type, HtmlFieldMode());
+ field.max_length = test_case.field_max_length;
+
+ AutofillField::FillFormField(field, ASCIIToUTF16(test_case.value_to_fill),
+ "en-US", "en-US", &field);
+ EXPECT_EQ(ASCIIToUTF16(test_case.expected_value), field.value);
}
-TEST_F(AutofillFieldTest, FillExpirationYearInput) {
- typedef struct {
- HtmlFieldType field_type;
- size_t field_max_length;
- std::string value_to_fill;
- std::string expected_value;
- } TestCase;
-
- TestCase test_cases[] = {
- // A field predicted as a 2 digits expiration year should fill the last 2
- // digits of the expiration year if the field has an unspecified max
- // length (0) or if it's greater than 1.
- {HTML_TYPE_CREDIT_CARD_EXP_2_DIGIT_YEAR, /* default value */ 0, "2023",
- "23"},
- {HTML_TYPE_CREDIT_CARD_EXP_2_DIGIT_YEAR, 2, "2023", "23"},
- {HTML_TYPE_CREDIT_CARD_EXP_2_DIGIT_YEAR, 12, "2023", "23"},
- // A field predicted as a 2 digit expiration year should fill the last
- // digit of the expiration year if the field has a max length of 1.
- {HTML_TYPE_CREDIT_CARD_EXP_2_DIGIT_YEAR, 1, "2023", "3"},
- // A field predicted as a 4 digit expiration year should fill the 4
- // digits of the expiration year if the field has an unspecified max
- // length (0) or if it's greater than 3 .
- {HTML_TYPE_CREDIT_CARD_EXP_4_DIGIT_YEAR, /* default value */ 0, "2023",
- "2023"},
- {HTML_TYPE_CREDIT_CARD_EXP_4_DIGIT_YEAR, 4, "2023", "2023"},
- {HTML_TYPE_CREDIT_CARD_EXP_4_DIGIT_YEAR, 12, "2023", "2023"},
- // A field predicted as a 4 digits expiration year should fill the last 2
- // digits of the expiration year if the field has a max length of 2.
- {HTML_TYPE_CREDIT_CARD_EXP_4_DIGIT_YEAR, 2, "2023", "23"},
- // A field predicted as a 4 digits expiration year should fill the last
- // digit of the expiration year if the field has a max length of 1.
- {HTML_TYPE_CREDIT_CARD_EXP_4_DIGIT_YEAR, 1, "2023", "3"},
- };
+INSTANTIATE_TEST_CASE_P(
+ AutofillFieldTest,
+ AutofillFieldPhoneNumberTest,
+ testing::Values(
+ // Filling a phone type field with text should fill the text as is.
+ AutofillFieldTestCase{HTML_TYPE_TEL, /* default value */ 0, "Oh hai",
+ "Oh hai"},
+ // Filling a prefix type field with a phone number of 7 digits should
+ // just fill the prefix.
+ AutofillFieldTestCase{HTML_TYPE_TEL_LOCAL_PREFIX, /* default value */ 0,
+ "5551234", "555"},
+ // Filling a suffix type field with a phone number of 7 digits should
+ // just fill the suffix.
+ AutofillFieldTestCase{HTML_TYPE_TEL_LOCAL_SUFFIX, /* default value */ 0,
+ "5551234", "1234"},
+ // Filling a phone type field with a max length of 3 with a phone number
+ // of
+ // 7 digits should fill only the prefix.
+ AutofillFieldTestCase{HTML_TYPE_TEL, 3, "5551234", "555"},
+ // Filling a phone type field with a max length of 4 with a phone number
+ // of
+ // 7 digits should fill only the suffix.
+ AutofillFieldTestCase{HTML_TYPE_TEL, 4, "5551234", "1234"},
+ // Filling a phone type field with a max length of 10 with a phone
+ // number including the country code should fill the phone number
+ // without the country code.
+ AutofillFieldTestCase{HTML_TYPE_TEL, 10, "15141254578", "5141254578"},
+ // Filling a phone type field with a max length of 5 with a phone number
+ // should fill with the last 5 digits of that phone number.
+ AutofillFieldTestCase{HTML_TYPE_TEL, 5, "5141254578", "54578"}));
+
+class AutofillFieldExpirationYearTest
+ : public testing::TestWithParam<AutofillFieldTestCase> {
+ public:
+ AutofillFieldExpirationYearTest() { CountryNames::SetLocaleString("en-US"); }
+};
- for (TestCase test_case : test_cases) {
- AutofillField field;
- field.form_control_type = "text";
- field.SetHtmlType(test_case.field_type, HtmlFieldMode());
- field.max_length = test_case.field_max_length;
+TEST_P(AutofillFieldExpirationYearTest, FillExpirationYearInput) {
+ auto test_case = GetParam();
+ AutofillField field;
+ field.form_control_type = "text";
+ field.SetHtmlType(test_case.field_type, HtmlFieldMode());
+ field.max_length = test_case.field_max_length;
- AutofillField::FillFormField(field, ASCIIToUTF16(test_case.value_to_fill),
- "en-US", "en-US", &field);
- EXPECT_EQ(ASCIIToUTF16(test_case.expected_value), field.value);
- }
+ AutofillField::FillFormField(field, ASCIIToUTF16(test_case.value_to_fill),
+ "en-US", "en-US", &field);
+ EXPECT_EQ(ASCIIToUTF16(test_case.expected_value), field.value);
}
-TEST_F(AutofillFieldTest, FillExpirationDateInput) {
- typedef struct {
- HtmlFieldType field_type;
- size_t field_max_length;
- std::string value_to_fill;
- std::string expected_value;
- bool expected_response;
- } TestCase;
-
- TestCase test_cases[] = {
- // Test invalid inputs
- {HTML_TYPE_CREDIT_CARD_EXP_DATE_2_DIGIT_YEAR, 0, "1/21", "", false},
- {HTML_TYPE_CREDIT_CARD_EXP_DATE_2_DIGIT_YEAR, 0, "01-21", "", false},
- {HTML_TYPE_CREDIT_CARD_EXP_DATE_4_DIGIT_YEAR, 0, "1/2021", "", false},
- {HTML_TYPE_CREDIT_CARD_EXP_DATE_4_DIGIT_YEAR, 0, "01-2021", "", false},
- // Trim whitespace
- {HTML_TYPE_CREDIT_CARD_EXP_DATE_2_DIGIT_YEAR, 0, "01/22 ", "01/22",
- true},
- {HTML_TYPE_CREDIT_CARD_EXP_DATE_4_DIGIT_YEAR, 0, "01/2022 ", "01/2022",
- true},
- // A field predicted as a expiration date w/ 2 digit year should fill
- // with a format of MM/YY unless it has max-length of:
- // 4: Use format MMYY
- // 6: Use format MMYYYY
- // 7: Use format MM/YYYY
- {HTML_TYPE_CREDIT_CARD_EXP_DATE_2_DIGIT_YEAR, /* default value */ 0,
- "01/23", "01/23", true},
- // Unsupported max lengths of 1-3, fail
- {HTML_TYPE_CREDIT_CARD_EXP_DATE_2_DIGIT_YEAR, 1, "01/23", "", false},
- {HTML_TYPE_CREDIT_CARD_EXP_DATE_2_DIGIT_YEAR, 2, "02/23", "", false},
- {HTML_TYPE_CREDIT_CARD_EXP_DATE_2_DIGIT_YEAR, 3, "03/23", "", false},
- // A max length of 4 indicates a format of MMYY.
- {HTML_TYPE_CREDIT_CARD_EXP_DATE_2_DIGIT_YEAR, 4, "02/23", "0223", true},
- // A max length of 6 indicates a format of MMYYYY, the 21st century is
- // assumed.
- // Desired case of proper max length >= 5
- {HTML_TYPE_CREDIT_CARD_EXP_DATE_2_DIGIT_YEAR, 5, "03/23", "03/23", true},
- {HTML_TYPE_CREDIT_CARD_EXP_DATE_2_DIGIT_YEAR, 6, "04/23", "042023", true},
- // A max length of 7 indicates a format of MM/YYYY, the 21st century is
- // assumed.
- {HTML_TYPE_CREDIT_CARD_EXP_DATE_2_DIGIT_YEAR, 7, "05/23", "05/2023",
- true},
- {HTML_TYPE_CREDIT_CARD_EXP_DATE_2_DIGIT_YEAR, 12, "06/23", "06/23", true},
-
- // A field predicted as a expiration date w/ 4 digit year should fill
- // with a format of MM/YYYY unless it has max-length of:
- // 4: Use format MMYY
- // 5: Use format MM/YY
- // 6: Use format MMYYYY
- {HTML_TYPE_CREDIT_CARD_EXP_DATE_4_DIGIT_YEAR, /* default value */ 0,
- "01/2024", "01/2024", true},
- // Unsupported max lengths of 1-3, fail
- {HTML_TYPE_CREDIT_CARD_EXP_DATE_4_DIGIT_YEAR, 1, "01/2024", "", false},
- {HTML_TYPE_CREDIT_CARD_EXP_DATE_4_DIGIT_YEAR, 2, "02/2024", "", false},
- {HTML_TYPE_CREDIT_CARD_EXP_DATE_4_DIGIT_YEAR, 3, "03/2024", "", false},
- // A max length of 4 indicates a format of MMYY.
- {HTML_TYPE_CREDIT_CARD_EXP_DATE_4_DIGIT_YEAR, 4, "02/2024", "0224", true},
- // A max length of 5 indicates a format of MM/YY.
- {HTML_TYPE_CREDIT_CARD_EXP_DATE_4_DIGIT_YEAR, 5, "03/2024", "03/24",
- true},
- // A max length of 6 indicates a format of MMYYYY.
- {HTML_TYPE_CREDIT_CARD_EXP_DATE_4_DIGIT_YEAR, 6, "04/2024", "042024",
- true},
- // Desired case of proper max length >= 7
- {HTML_TYPE_CREDIT_CARD_EXP_DATE_4_DIGIT_YEAR, 7, "05/2024", "05/2024",
- true},
- {HTML_TYPE_CREDIT_CARD_EXP_DATE_4_DIGIT_YEAR, 12, "06/2024", "06/2024",
- true},
- };
+INSTANTIATE_TEST_CASE_P(
+ AutofillFieldTest,
+ AutofillFieldExpirationYearTest,
+ testing::Values(
+ // A field predicted as a 2 digits expiration year should fill the last
+ // 2 digits of the expiration year if the field has an unspecified max
+ // length (0) or if it's greater than 1.
+ AutofillFieldTestCase{HTML_TYPE_CREDIT_CARD_EXP_2_DIGIT_YEAR,
+ /* default value */ 0, "2023", "23"},
+ AutofillFieldTestCase{HTML_TYPE_CREDIT_CARD_EXP_2_DIGIT_YEAR, 2, "2023",
+ "23"},
+ AutofillFieldTestCase{HTML_TYPE_CREDIT_CARD_EXP_2_DIGIT_YEAR, 12,
+ "2023", "23"},
+ // A field predicted as a 2 digit expiration year should fill the last
+ // digit of the expiration year if the field has a max length of 1.
+ AutofillFieldTestCase{HTML_TYPE_CREDIT_CARD_EXP_2_DIGIT_YEAR, 1, "2023",
+ "3"},
+ // A field predicted as a 4 digit expiration year should fill the 4
+ // digits of the expiration year if the field has an unspecified max
+ // length (0) or if it's greater than 3 .
+ AutofillFieldTestCase{HTML_TYPE_CREDIT_CARD_EXP_4_DIGIT_YEAR,
+ /* default value */ 0, "2023", "2023"},
+ AutofillFieldTestCase{HTML_TYPE_CREDIT_CARD_EXP_4_DIGIT_YEAR, 4, "2023",
+ "2023"},
+ AutofillFieldTestCase{HTML_TYPE_CREDIT_CARD_EXP_4_DIGIT_YEAR, 12,
+ "2023", "2023"},
+ // A field predicted as a 4 digits expiration year should fill the last
+ // 2 digits of the expiration year if the field has a max length of 2.
+ AutofillFieldTestCase{HTML_TYPE_CREDIT_CARD_EXP_4_DIGIT_YEAR, 2, "2023",
+ "23"},
+ // A field predicted as a 4 digits expiration year should fill the last
+ // digit of the expiration year if the field has a max length of 1.
+ AutofillFieldTestCase{HTML_TYPE_CREDIT_CARD_EXP_4_DIGIT_YEAR, 1, "2023",
+ "3"}));
+
+struct AutofillFieldExpirationDateTestCase {
+ HtmlFieldType field_type;
+ size_t field_max_length;
+ std::string value_to_fill;
+ std::string expected_value;
+ bool expected_response;
+};
- for (TestCase test_case : test_cases) {
- AutofillField field;
- field.form_control_type = "text";
- field.SetHtmlType(test_case.field_type, HtmlFieldMode());
- field.max_length = test_case.field_max_length;
+class AutofillFieldExpirationDateTest
+ : public testing::TestWithParam<AutofillFieldExpirationDateTestCase> {
+ public:
+ AutofillFieldExpirationDateTest() { CountryNames::SetLocaleString("en-US"); }
+};
+
+TEST_P(AutofillFieldExpirationDateTest, FillExpirationDateInput) {
+ auto test_case = GetParam();
+ AutofillField field;
+ field.form_control_type = "text";
+ field.SetHtmlType(test_case.field_type, HtmlFieldMode());
+ field.max_length = test_case.field_max_length;
- bool response = AutofillField::FillFormField(
+ bool response = AutofillField::FillFormField(
field, ASCIIToUTF16(test_case.value_to_fill), "en-US", "en-US", &field);
- EXPECT_EQ(ASCIIToUTF16(test_case.expected_value), field.value);
- EXPECT_EQ(response, test_case.expected_response);
- }
+ EXPECT_EQ(ASCIIToUTF16(test_case.expected_value), field.value);
+ EXPECT_EQ(response, test_case.expected_response);
}
+INSTANTIATE_TEST_CASE_P(
+ AutofillFieldTest,
+ AutofillFieldExpirationDateTest,
+ testing::Values(
+ // Test invalid inputs
+ AutofillFieldExpirationDateTestCase{
+ HTML_TYPE_CREDIT_CARD_EXP_DATE_2_DIGIT_YEAR, 0, "1/21", "", false},
+ AutofillFieldExpirationDateTestCase{
+ HTML_TYPE_CREDIT_CARD_EXP_DATE_2_DIGIT_YEAR, 0, "01-21", "", false},
+ AutofillFieldExpirationDateTestCase{
+ HTML_TYPE_CREDIT_CARD_EXP_DATE_4_DIGIT_YEAR, 0, "1/2021", "",
+ false},
+ AutofillFieldExpirationDateTestCase{
+ HTML_TYPE_CREDIT_CARD_EXP_DATE_4_DIGIT_YEAR, 0, "01-2021", "",
+ false},
+ // Trim whitespace
+ AutofillFieldExpirationDateTestCase{
+ HTML_TYPE_CREDIT_CARD_EXP_DATE_2_DIGIT_YEAR, 0, "01/22 ", "01/22",
+ true},
+ AutofillFieldExpirationDateTestCase{
+ HTML_TYPE_CREDIT_CARD_EXP_DATE_4_DIGIT_YEAR, 0, "01/2022 ",
+ "01/2022", true},
+ // A field predicted as a expiration date w/ 2 digit year should fill
+ // with a format of MM/YY unless it has max-length of:
+ // 4: Use format MMYY
+ // 6: Use format MMYYYY
+ // 7: Use format MM/YYYY
+ AutofillFieldExpirationDateTestCase{
+ HTML_TYPE_CREDIT_CARD_EXP_DATE_2_DIGIT_YEAR, /* default value */ 0,
+ "01/23", "01/23", true},
+ // Unsupported max lengths of 1-3, fail
+ AutofillFieldExpirationDateTestCase{
+ HTML_TYPE_CREDIT_CARD_EXP_DATE_2_DIGIT_YEAR, 1, "01/23", "", false},
+ AutofillFieldExpirationDateTestCase{
+ HTML_TYPE_CREDIT_CARD_EXP_DATE_2_DIGIT_YEAR, 2, "02/23", "", false},
+ AutofillFieldExpirationDateTestCase{
+ HTML_TYPE_CREDIT_CARD_EXP_DATE_2_DIGIT_YEAR, 3, "03/23", "", false},
+ // A max length of 4 indicates a format of MMYY.
+ AutofillFieldExpirationDateTestCase{
+ HTML_TYPE_CREDIT_CARD_EXP_DATE_2_DIGIT_YEAR, 4, "02/23", "0223",
+ true},
+ // A max length of 6 indicates a format of MMYYYY, the 21st century is
+ // assumed.
+ // Desired case of proper max length >= 5
+ AutofillFieldExpirationDateTestCase{
+ HTML_TYPE_CREDIT_CARD_EXP_DATE_2_DIGIT_YEAR, 5, "03/23", "03/23",
+ true},
+ AutofillFieldExpirationDateTestCase{
+ HTML_TYPE_CREDIT_CARD_EXP_DATE_2_DIGIT_YEAR, 6, "04/23", "042023",
+ true},
+ // A max length of 7 indicates a format of MM/YYYY, the 21st century is
+ // assumed.
+ AutofillFieldExpirationDateTestCase{
+ HTML_TYPE_CREDIT_CARD_EXP_DATE_2_DIGIT_YEAR, 7, "05/23", "05/2023",
+ true},
+ AutofillFieldExpirationDateTestCase{
+ HTML_TYPE_CREDIT_CARD_EXP_DATE_2_DIGIT_YEAR, 12, "06/23", "06/23",
+ true},
+
+ // A field predicted as a expiration date w/ 4 digit year should fill
+ // with a format of MM/YYYY unless it has max-length of:
+ // 4: Use format MMYY
+ // 5: Use format MM/YY
+ // 6: Use format MMYYYY
+ AutofillFieldExpirationDateTestCase{
+ HTML_TYPE_CREDIT_CARD_EXP_DATE_4_DIGIT_YEAR, /* default value */ 0,
+ "01/2024", "01/2024", true},
+ // Unsupported max lengths of 1-3, fail
+ AutofillFieldExpirationDateTestCase{
+ HTML_TYPE_CREDIT_CARD_EXP_DATE_4_DIGIT_YEAR, 1, "01/2024", "",
+ false},
+ AutofillFieldExpirationDateTestCase{
+ HTML_TYPE_CREDIT_CARD_EXP_DATE_4_DIGIT_YEAR, 2, "02/2024", "",
+ false},
+ AutofillFieldExpirationDateTestCase{
+ HTML_TYPE_CREDIT_CARD_EXP_DATE_4_DIGIT_YEAR, 3, "03/2024", "",
+ false},
+ // A max length of 4 indicates a format of MMYY.
+ AutofillFieldExpirationDateTestCase{
+ HTML_TYPE_CREDIT_CARD_EXP_DATE_4_DIGIT_YEAR, 4, "02/2024", "0224",
+ true},
+ // A max length of 5 indicates a format of MM/YY.
+ AutofillFieldExpirationDateTestCase{
+ HTML_TYPE_CREDIT_CARD_EXP_DATE_4_DIGIT_YEAR, 5, "03/2024", "03/24",
+ true},
+ // A max length of 6 indicates a format of MMYYYY.
+ AutofillFieldExpirationDateTestCase{
+ HTML_TYPE_CREDIT_CARD_EXP_DATE_4_DIGIT_YEAR, 6, "04/2024", "042024",
+ true},
+ // Desired case of proper max length >= 7
+ AutofillFieldExpirationDateTestCase{
+ HTML_TYPE_CREDIT_CARD_EXP_DATE_4_DIGIT_YEAR, 7, "05/2024",
+ "05/2024", true},
+ AutofillFieldExpirationDateTestCase{
+ HTML_TYPE_CREDIT_CARD_EXP_DATE_4_DIGIT_YEAR, 12, "06/2024",
+ "06/2024", true}));
+
TEST_F(AutofillFieldTest, FillSelectControlByValue) {
std::vector<const char*> kOptions = {
"Eenie", "Meenie", "Miney", "Mo",
@@ -493,131 +552,179 @@ TEST_F(AutofillFieldTest, FillSelectControlByContents) {
EXPECT_EQ(ASCIIToUTF16("2"), field.value); // Corresponds to "Miney".
}
-TEST_F(AutofillFieldTest, FillSelectWithStates) {
- typedef struct {
- std::vector<const char*> select_values;
- const char* input_value;
- const char* expected_value;
- } TestCase;
-
- TestCase test_cases[] = {
- // Filling the abbreviation.
- {{"Alabama", "California"}, "CA", "California"},
- // Attempting to fill the full name in a select full of abbreviations.
- {{"AL", "CA"}, "California", "CA"},
- // Different case and diacritics.
- {{"QUÉBEC", "ALBERTA"}, "Quebec", "QUÉBEC"},
- // Inexact state names.
- {{"SC - South Carolina", "CA - California", "NC - North Carolina"},
- "California",
- "CA - California"},
- // Don't accidentally match "Virginia" to "West Virginia".
- {{"WV - West Virginia", "VA - Virginia", "NV - North Virginia"},
- "Virginia",
- "VA - Virginia"},
- // Do accidentally match "Virginia" to "West Virginia".
- // TODO(crbug.com/624770): This test should not pass, but it does because
- // "Virginia" is a substring of "West Virginia".
- {{"WV - West Virginia", "TX - Texas"}, "Virginia", "WV - West Virginia"},
- // Tests that substring matches work for full state names (a full token
- // match isn't required). Also tests that matches work for states with
- // whitespace in the middle.
- {{"California.", "North Carolina."}, "North Carolina", "North Carolina."},
- {{"NC - North Carolina", "CA - California"}, "CA", "CA - California"},
- // These are not states.
- {{"NCNCA", "SCNCA"}, "NC", ""}};
-
- for (TestCase test_case : test_cases) {
- AutofillField field;
- test::CreateTestSelectField(test_case.select_values, &field);
- field.set_heuristic_type(ADDRESS_HOME_STATE);
-
- AutofillField::FillFormField(field, UTF8ToUTF16(test_case.input_value),
- "en-US", "en-US", &field);
- EXPECT_EQ(UTF8ToUTF16(test_case.expected_value), field.value);
- }
-}
+struct FillSelectTestCase {
+ std::vector<const char*> select_values;
+ const char* input_value;
+ const char* expected_value;
+};
+
+class AutofillSelectWithStatesTest
+ : public testing::TestWithParam<FillSelectTestCase> {
+ public:
+ AutofillSelectWithStatesTest() { CountryNames::SetLocaleString("en-US"); }
+};
-TEST_F(AutofillFieldTest, FillSelectWithCountries) {
- typedef struct {
- std::vector<const char*> select_values;
- const char* input_value;
- const char* expected_value;
- } TestCase;
+TEST_P(AutofillSelectWithStatesTest, FillSelectWithStates) {
+ auto test_case = GetParam();
+ AutofillField field;
+ test::CreateTestSelectField(test_case.select_values, &field);
+ field.set_heuristic_type(ADDRESS_HOME_STATE);
- TestCase test_cases[] = {// Full country names.
- {{"Albania", "Canada"}, "CA", "Canada"},
- // Abbreviations.
- {{"AL", "CA"}, "Canada", "CA"}};
+ AutofillField::FillFormField(field, UTF8ToUTF16(test_case.input_value),
+ "en-US", "en-US", &field);
+ EXPECT_EQ(UTF8ToUTF16(test_case.expected_value), field.value);
+}
- for (TestCase test_case : test_cases) {
- AutofillField field;
- test::CreateTestSelectField(test_case.select_values, &field);
- field.set_heuristic_type(ADDRESS_HOME_COUNTRY);
+INSTANTIATE_TEST_CASE_P(
+ AutofillFieldTest,
+ AutofillSelectWithStatesTest,
+ testing::Values(
+ // Filling the abbreviation.
+ FillSelectTestCase{{"Alabama", "California"}, "CA", "California"},
+ // Attempting to fill the full name in a select full of abbreviations.
+ FillSelectTestCase{{"AL", "CA"}, "California", "CA"},
+ // Different case and diacritics.
+ FillSelectTestCase{{"QUÉBEC", "ALBERTA"}, "Quebec", "QUÉBEC"},
+ // Inexact state names.
+ FillSelectTestCase{
+ {"SC - South Carolina", "CA - California", "NC - North Carolina"},
+ "California",
+ "CA - California"},
+ // Don't accidentally match "Virginia" to "West Virginia".
+ FillSelectTestCase{
+ {"WV - West Virginia", "VA - Virginia", "NV - North Virginia"},
+ "Virginia",
+ "VA - Virginia"},
+ // Do accidentally match "Virginia" to "West Virginia".
+ // TODO(crbug.com/624770): This test should not pass, but it does
+ // because "Virginia" is a substring of "West Virginia".
+ FillSelectTestCase{{"WV - West Virginia", "TX - Texas"},
+ "Virginia",
+ "WV - West Virginia"},
+ // Tests that substring matches work for full state names (a full token
+ // match isn't required). Also tests that matches work for states with
+ // whitespace in the middle.
+ FillSelectTestCase{{"California.", "North Carolina."},
+ "North Carolina",
+ "North Carolina."},
+ FillSelectTestCase{{"NC - North Carolina", "CA - California"},
+ "CA",
+ "CA - California"},
+ // These are not states.
+ FillSelectTestCase{{"NCNCA", "SCNCA"}, "NC", ""}));
+
+class AutofillSelectWithCountriesTest
+ : public testing::TestWithParam<FillSelectTestCase> {
+ public:
+ AutofillSelectWithCountriesTest() { CountryNames::SetLocaleString("en-US"); }
+};
- AutofillField::FillFormField(field, UTF8ToUTF16(test_case.input_value),
- "en-US", "en-US", &field);
- EXPECT_EQ(UTF8ToUTF16(test_case.expected_value), field.value);
- }
+TEST_P(AutofillSelectWithCountriesTest, FillSelectWithCountries) {
+ auto test_case = GetParam();
+ AutofillField field;
+ test::CreateTestSelectField(test_case.select_values, &field);
+ field.set_heuristic_type(ADDRESS_HOME_COUNTRY);
+
+ AutofillField::FillFormField(field, UTF8ToUTF16(test_case.input_value),
+ "en-US", "en-US", &field);
+ EXPECT_EQ(UTF8ToUTF16(test_case.expected_value), field.value);
}
-TEST_F(AutofillFieldTest, FillSelectControlWithExpirationMonth) {
- typedef struct {
- std::vector<const char*> select_values;
- std::vector<const char*> select_contents;
- } TestCase;
-
- TestCase test_cases[] = {
- // Values start at 1.
- {{"1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12"},
- NotNumericMonthsContentsNoPlaceholder()},
- // Values start at 1 but single digits are whitespace padded!
- {{" 1", " 2", " 3", " 4", " 5", " 6", " 7", " 8", " 9", "10", "11", "12"},
- NotNumericMonthsContentsNoPlaceholder()},
- // Values start at 0.
- {{"0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11"},
- NotNumericMonthsContentsNoPlaceholder()},
- // Values start at 00.
- {{"00", "01", "02", "03", "04", "05", "06", "07", "08", "09", "10", "11"},
- NotNumericMonthsContentsNoPlaceholder()},
- // The AngularJS framework adds a prefix to number types. Test that it is
- // removed.
- {{"number:1", "number:2", "number:3", "number:4", "number:5", "number:6",
- "number:7", "number:8", "number:9", "number:10", "number:11",
- "number:12"},
- NotNumericMonthsContentsNoPlaceholder()},
- // Values start at 0 and the first content is a placeholder.
- {{"0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12"},
- NotNumericMonthsContentsWithPlaceholder()},
- // Values start at 1 and the first content is a placeholder.
- {{"1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12", "13"},
- NotNumericMonthsContentsWithPlaceholder()},
- // Values start at 01 and the first content is a placeholder.
- {{"01", "02", "03", "04", "05", "06", "07", "08", "09", "10", "11", "12",
- "13"},
- NotNumericMonthsContentsWithPlaceholder()},
- // Values start at 0 after a placeholder.
- {{"?", "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11"},
- NotNumericMonthsContentsWithPlaceholder()},
- // Values start at 1 after a placeholder.
- {{"?", "1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12"},
- NotNumericMonthsContentsWithPlaceholder()},
- // Values start at 0 after a negative number.
- {{"-1", "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11"},
- NotNumericMonthsContentsWithPlaceholder()},
- // Values start at 1 after a negative number.
- {{"-1", "1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12"},
- NotNumericMonthsContentsWithPlaceholder()}};
-
- for (TestCase test_case : test_cases) {
- ASSERT_EQ(test_case.select_values.size(), test_case.select_contents.size());
-
- TestFillingExpirationMonth(test_case.select_values,
- test_case.select_contents,
- test_case.select_values.size());
+INSTANTIATE_TEST_CASE_P(
+ AutofillFieldTest,
+ AutofillSelectWithCountriesTest,
+ testing::Values(
+ // Full country names.
+ FillSelectTestCase{{"Albania", "Canada"}, "CA", "Canada"},
+ // Abbreviations.
+ FillSelectTestCase{{"AL", "CA"}, "Canada", "CA"}));
+
+struct FillWithExpirationMonthTestCase {
+ std::vector<const char*> select_values;
+ std::vector<const char*> select_contents;
+};
+
+class AutofillSelectWithExpirationMonthTest
+ : public testing::TestWithParam<FillWithExpirationMonthTestCase> {
+ public:
+ AutofillSelectWithExpirationMonthTest() {
+ CountryNames::SetLocaleString("en-US");
}
+};
+
+TEST_P(AutofillSelectWithExpirationMonthTest,
+ FillSelectControlWithExpirationMonth) {
+ auto test_case = GetParam();
+ ASSERT_EQ(test_case.select_values.size(), test_case.select_contents.size());
+
+ TestFillingExpirationMonth(test_case.select_values, test_case.select_contents,
+ test_case.select_values.size());
}
+INSTANTIATE_TEST_CASE_P(
+ AutofillFieldTest,
+ AutofillSelectWithExpirationMonthTest,
+ testing::Values(
+ // Values start at 1.
+ FillWithExpirationMonthTestCase{
+ {"1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12"},
+ NotNumericMonthsContentsNoPlaceholder()},
+ // Values start at 1 but single digits are whitespace padded!
+ FillWithExpirationMonthTestCase{
+ {" 1", " 2", " 3", " 4", " 5", " 6", " 7", " 8", " 9", "10", "11",
+ "12"},
+ NotNumericMonthsContentsNoPlaceholder()},
+ // Values start at 0.
+ FillWithExpirationMonthTestCase{
+ {"0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11"},
+ NotNumericMonthsContentsNoPlaceholder()},
+ // Values start at 00.
+ FillWithExpirationMonthTestCase{
+ {"00", "01", "02", "03", "04", "05", "06", "07", "08", "09", "10",
+ "11"},
+ NotNumericMonthsContentsNoPlaceholder()},
+ // The AngularJS framework adds a prefix to number types. Test that it
+ // is removed.
+ FillWithExpirationMonthTestCase{
+ {"number:1", "number:2", "number:3", "number:4", "number:5",
+ "number:6", "number:7", "number:8", "number:9", "number:10",
+ "number:11", "number:12"},
+ NotNumericMonthsContentsNoPlaceholder()},
+ // Values start at 0 and the first content is a placeholder.
+ FillWithExpirationMonthTestCase{
+ {"0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11",
+ "12"},
+ NotNumericMonthsContentsWithPlaceholder()},
+ // Values start at 1 and the first content is a placeholder.
+ FillWithExpirationMonthTestCase{
+ {"1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12",
+ "13"},
+ NotNumericMonthsContentsWithPlaceholder()},
+ // Values start at 01 and the first content is a placeholder.
+ FillWithExpirationMonthTestCase{
+ {"01", "02", "03", "04", "05", "06", "07", "08", "09", "10", "11",
+ "12", "13"},
+ NotNumericMonthsContentsWithPlaceholder()},
+ // Values start at 0 after a placeholder.
+ FillWithExpirationMonthTestCase{
+ {"?", "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11"},
+ NotNumericMonthsContentsWithPlaceholder()},
+ // Values start at 1 after a placeholder.
+ FillWithExpirationMonthTestCase{
+ {"?", "1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11",
+ "12"},
+ NotNumericMonthsContentsWithPlaceholder()},
+ // Values start at 0 after a negative number.
+ FillWithExpirationMonthTestCase{
+ {"-1", "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "10",
+ "11"},
+ NotNumericMonthsContentsWithPlaceholder()},
+ // Values start at 1 after a negative number.
+ FillWithExpirationMonthTestCase{
+ {"-1", "1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11",
+ "12"},
+ NotNumericMonthsContentsWithPlaceholder()}));
+
TEST_F(AutofillFieldTest, FillSelectControlWithAbbreviatedMonthName) {
std::vector<const char*> kMonthsAbbreviated = {
"Jan", "Feb", "Mar", "Apr", "May", "Jun",
@@ -920,50 +1027,64 @@ TEST_F(AutofillFieldTest, FindShortestSubstringMatchInSelect) {
// Tests that text state fields are filled correctly depending on their
// maxlength attribute value.
-TEST_F(AutofillFieldTest, FillStateText) {
- typedef struct {
- HtmlFieldType field_type;
- size_t field_max_length;
- std::string value_to_fill;
- std::string expected_value;
- bool should_fill;
- } TestCase;
-
- TestCase test_cases[] = {
- // Filling a state to a text field with the default maxlength value should
- // fill the state value as is.
- {HTML_TYPE_ADDRESS_LEVEL1, /* default value */ 0, "New York", "New York",
- true},
- {HTML_TYPE_ADDRESS_LEVEL1, /* default value */ 0, "NY", "NY", true},
- // Filling a state to a text field with a maxlength value equal to the
- // value's length should fill the state value as is.
- {HTML_TYPE_ADDRESS_LEVEL1, 8, "New York", "New York", true},
- // Filling a state to a text field with a maxlength value lower than the
- // value's length but higher than the value's abbreviation should fill the
- // state abbreviation.
- {HTML_TYPE_ADDRESS_LEVEL1, 2, "New York", "NY", true},
- {HTML_TYPE_ADDRESS_LEVEL1, 2, "NY", "NY", true},
- // Filling a state to a text field with a maxlength value lower than the
- // value's length and the value's abbreviation should not fill at all.
- {HTML_TYPE_ADDRESS_LEVEL1, 1, "New York", "", false},
- {HTML_TYPE_ADDRESS_LEVEL1, 1, "NY", "", false},
- // Filling a state to a text field with a maxlength value lower than the
- // value's length and that has no associated abbreviation should not fill
- // at all.
- {HTML_TYPE_ADDRESS_LEVEL1, 3, "Quebec", "", false}};
-
- for (const TestCase& test_case : test_cases) {
- AutofillField field;
- field.SetHtmlType(test_case.field_type, HtmlFieldMode());
- field.max_length = test_case.field_max_length;
-
- bool has_filled = AutofillField::FillFormField(
- field, ASCIIToUTF16(test_case.value_to_fill), "en-US", "en-US", &field);
-
- EXPECT_EQ(test_case.should_fill, has_filled);
- EXPECT_EQ(ASCIIToUTF16(test_case.expected_value), field.value);
- }
+struct FillStateTextTestCase {
+ HtmlFieldType field_type;
+ size_t field_max_length;
+ std::string value_to_fill;
+ std::string expected_value;
+ bool should_fill;
+};
+
+class AutofillStateTextTest
+ : public testing::TestWithParam<FillStateTextTestCase> {
+ public:
+ AutofillStateTextTest() { CountryNames::SetLocaleString("en-US"); }
+};
+
+TEST_P(AutofillStateTextTest, FillStateText) {
+ auto test_case = GetParam();
+ AutofillField field;
+ field.SetHtmlType(test_case.field_type, HtmlFieldMode());
+ field.max_length = test_case.field_max_length;
+
+ bool has_filled = AutofillField::FillFormField(
+ field, ASCIIToUTF16(test_case.value_to_fill), "en-US", "en-US", &field);
+
+ EXPECT_EQ(test_case.should_fill, has_filled);
+ EXPECT_EQ(ASCIIToUTF16(test_case.expected_value), field.value);
}
+INSTANTIATE_TEST_CASE_P(
+ AutofillFieldTest,
+ AutofillStateTextTest,
+ testing::Values(
+ // Filling a state to a text field with the default maxlength value
+ // should
+ // fill the state value as is.
+ FillStateTextTestCase{HTML_TYPE_ADDRESS_LEVEL1, /* default value */ 0,
+ "New York", "New York", true},
+ FillStateTextTestCase{HTML_TYPE_ADDRESS_LEVEL1, /* default value */ 0,
+ "NY", "NY", true},
+ // Filling a state to a text field with a maxlength value equal to the
+ // value's length should fill the state value as is.
+ FillStateTextTestCase{HTML_TYPE_ADDRESS_LEVEL1, 8, "New York",
+ "New York", true},
+ // Filling a state to a text field with a maxlength value lower than the
+ // value's length but higher than the value's abbreviation should fill
+ // the state abbreviation.
+ FillStateTextTestCase{HTML_TYPE_ADDRESS_LEVEL1, 2, "New York", "NY",
+ true},
+ FillStateTextTestCase{HTML_TYPE_ADDRESS_LEVEL1, 2, "NY", "NY", true},
+ // Filling a state to a text field with a maxlength value lower than the
+ // value's length and the value's abbreviation should not fill at all.
+ FillStateTextTestCase{HTML_TYPE_ADDRESS_LEVEL1, 1, "New York", "",
+ false},
+ FillStateTextTestCase{HTML_TYPE_ADDRESS_LEVEL1, 1, "NY", "", false},
+ // Filling a state to a text field with a maxlength value lower than the
+ // value's length and that has no associated abbreviation should not
+ // fill at all.
+ FillStateTextTestCase{HTML_TYPE_ADDRESS_LEVEL1, 3, "Quebec", "",
+ false}));
+
} // namespace
} // namespace autofill
diff --git a/chromium/components/autofill/core/browser/autofill_manager.cc b/chromium/components/autofill/core/browser/autofill_manager.cc
index 056793fe09b..933b7c5dd41 100644
--- a/chromium/components/autofill/core/browser/autofill_manager.cc
+++ b/chromium/components/autofill/core/browser/autofill_manager.cc
@@ -26,6 +26,7 @@
#include "base/path_service.h"
#include "base/strings/string16.h"
#include "base/strings/string_number_conversions.h"
+#include "base/strings/string_piece.h"
#include "base/strings/string_split.h"
#include "base/strings/string_util.h"
#include "base/strings/utf_string_conversions.h"
@@ -50,6 +51,7 @@
#include "components/autofill/core/browser/phone_number.h"
#include "components/autofill/core/browser/phone_number_i18n.h"
#include "components/autofill/core/browser/popup_item_ids.h"
+#include "components/autofill/core/browser/ui/save_card_bubble_controller.h"
#include "components/autofill/core/browser/validation.h"
#include "components/autofill/core/common/autofill_clock.h"
#include "components/autofill/core/common/autofill_constants.h"
@@ -60,6 +62,7 @@
#include "components/autofill/core/common/form_data_predictions.h"
#include "components/autofill/core/common/form_field_data.h"
#include "components/autofill/core/common/password_form_fill_data.h"
+#include "components/autofill/core/common/signatures_util.h"
#include "components/pref_registry/pref_registry_syncable.h"
#include "components/prefs/pref_service.h"
#include "components/rappor/public/rappor_utils.h"
@@ -129,9 +132,9 @@ base::string16 SanitizeCreditCardFieldValue(const base::string16& value) {
// want the logic of which variations of names are considered to be the same to
// exactly match the logic applied on the Payments server.
base::string16 RemoveMiddleInitial(const base::string16& name) {
- std::vector<base::string16> parts =
- base::SplitString(name, base::kWhitespaceUTF16, base::KEEP_WHITESPACE,
- base::SPLIT_WANT_NONEMPTY);
+ std::vector<base::StringPiece16> parts =
+ base::SplitStringPiece(name, base::kWhitespaceUTF16,
+ base::KEEP_WHITESPACE, base::SPLIT_WANT_NONEMPTY);
if (parts.size() == 3 && (parts[1].length() == 1 ||
(parts[1].length() == 2 &&
base::EndsWith(parts[1], base::ASCIIToUTF16("."),
@@ -215,16 +218,24 @@ AutofillManager::AutofillManager(
AutofillDownloadManagerState enable_download_manager)
: driver_(driver),
client_(client),
- payments_client_(
- new payments::PaymentsClient(driver->GetURLRequestContext(), this)),
+ payments_client_(base::MakeUnique<payments::PaymentsClient>(
+ driver->GetURLRequestContext(),
+ this)),
app_locale_(app_locale),
personal_data_(client->GetPersonalDataManager()),
autocomplete_history_manager_(
- new AutocompleteHistoryManager(driver, client)),
+ base::MakeUnique<AutocompleteHistoryManager>(driver, client)),
+ form_interactions_ukm_logger_(
+ base::MakeUnique<AutofillMetrics::FormInteractionsUkmLogger>(
+ client->GetUkmService())),
address_form_event_logger_(
- new AutofillMetrics::FormEventLogger(false /* is_for_credit_card */)),
+ base::MakeUnique<AutofillMetrics::FormEventLogger>(
+ false /* is_for_credit_card */,
+ form_interactions_ukm_logger_.get())),
credit_card_form_event_logger_(
- new AutofillMetrics::FormEventLogger(true /* is_for_credit_card */)),
+ base::MakeUnique<AutofillMetrics::FormEventLogger>(
+ true /* is_for_credit_card */,
+ form_interactions_ukm_logger_.get())),
has_logged_autofill_enabled_(false),
has_logged_address_suggestions_count_(false),
did_show_suggestions_(false),
@@ -232,6 +243,7 @@ AutofillManager::AutofillManager(
user_did_autofill_(false),
user_did_edit_autofilled_field_(false),
user_did_accept_upload_prompt_(false),
+ should_cvc_be_requested_(false),
external_delegate_(NULL),
test_delegate_(NULL),
#if defined(OS_ANDROID) || defined(OS_IOS)
@@ -245,10 +257,8 @@ AutofillManager::AutofillManager(
if (personal_data_ && client_)
personal_data_->OnSyncServiceInitialized(client_->GetSyncService());
-#if defined(OS_ANDROID)
if (personal_data_ && driver_)
personal_data_->SetURLRequestContextGetter(driver_->GetURLRequestContext());
-#endif
}
AutofillManager::~AutofillManager() {}
@@ -493,7 +503,7 @@ void AutofillManager::ProcessPendingFormForUpload() {
if (!upload_form)
return;
- StartUploadProcess(std::move(upload_form), base::TimeTicks::Now(), false);
+ StartUploadProcess(std::move(upload_form), TimeTicks::Now(), false);
}
void AutofillManager::OnTextFieldDidChange(const FormData& form,
@@ -512,6 +522,9 @@ void AutofillManager::OnTextFieldDidChange(const FormData& form,
UpdatePendingForm(form);
+ if (!user_did_type_ || autofill_field->is_autofilled)
+ form_interactions_ukm_logger_->LogTextFieldDidChange(*autofill_field);
+
if (!user_did_type_) {
user_did_type_ = true;
AutofillMetrics::LogUserHappinessMetric(AutofillMetrics::USER_DID_TYPE);
@@ -1033,13 +1046,16 @@ void AutofillManager::OnDidGetUploadDetails(
user_did_accept_upload_prompt_ = false;
client_->ConfirmSaveCreditCardToCloud(
upload_request_.card, std::move(legal_message),
+ should_cvc_be_requested_,
base::Bind(&AutofillManager::OnUserDidAcceptUpload,
weak_ptr_factory_.GetWeakPtr()));
client_->LoadRiskData(base::Bind(&AutofillManager::OnDidGetUploadRiskData,
weak_ptr_factory_.GetWeakPtr()));
- AutofillMetrics::LogCardUploadDecisionMetric(
- AutofillMetrics::UPLOAD_OFFERED);
- LogCardUploadDecisionUkm(AutofillMetrics::UPLOAD_OFFERED);
+ AutofillMetrics::CardUploadDecisionMetric card_upload_decision_metric =
+ should_cvc_be_requested_ ? AutofillMetrics::UPLOAD_OFFERED_NO_CVC
+ : AutofillMetrics::UPLOAD_OFFERED;
+ AutofillMetrics::LogCardUploadDecisionMetric(card_upload_decision_metric);
+ LogCardUploadDecisionUkm(card_upload_decision_metric);
} else {
// If the upload details request failed, fall back to a local save. The
// reasoning here is as follows:
@@ -1099,6 +1115,13 @@ void AutofillManager::OnUserDidAcceptUpload() {
user_did_accept_upload_prompt_ = true;
if (!upload_request_.risk_data.empty()) {
upload_request_.app_locale = app_locale_;
+ // If the upload request does not have card CVC, populate it with the
+ // value provided by the user:
+ if (upload_request_.cvc.empty()) {
+ DCHECK(client_->GetSaveCardBubbleController());
+ upload_request_.cvc =
+ client_->GetSaveCardBubbleController()->GetCvcEnteredByUser();
+ }
payments_client_->UploadCard(upload_request_);
}
}
@@ -1107,6 +1130,13 @@ void AutofillManager::OnDidGetUploadRiskData(const std::string& risk_data) {
upload_request_.risk_data = risk_data;
if (user_did_accept_upload_prompt_) {
upload_request_.app_locale = app_locale_;
+ // If the upload request does not have card CVC, populate it with the
+ // value provided by the user:
+ if (upload_request_.cvc.empty()) {
+ DCHECK(client_->GetSaveCardBubbleController());
+ upload_request_.cvc =
+ client_->GetSaveCardBubbleController()->GetCvcEnteredByUser();
+ }
payments_client_->UploadCard(upload_request_);
}
}
@@ -1126,7 +1156,7 @@ bool AutofillManager::IsCreditCardUploadEnabled() {
}
bool AutofillManager::ShouldUploadForm(const FormStructure& form) {
- return IsAutofillEnabled() && !driver_->IsOffTheRecord() &&
+ return IsAutofillEnabled() && !driver_->IsIncognito() &&
form.ShouldBeParsed() &&
(form.active_field_count() >= kRequiredFieldsForUpload ||
(form.all_fields_are_passwords() &&
@@ -1199,9 +1229,11 @@ void AutofillManager::ImportFormData(const FormStructure& submitted_form) {
// because if only one of the two is missing, it may be fixable.
// Check for a CVC to determine whether we can prompt the user to upload
- // their card. If no CVC is present, do nothing. We could fall back to a
- // local save but we believe that sometimes offering upload and sometimes
- // offering local save is a confusing user experience.
+ // their card. If no CVC is present and the experiment is off, do nothing.
+ // We could fall back to a local save but we believe that sometimes offering
+ // upload and sometimes offering local save is a confusing user experience.
+ // If no CVC and the experiment is on, request CVC from the user in the
+ // bubble and save using the provided value.
for (const auto& field : submitted_form) {
if (field->Type().GetStorableType() == CREDIT_CARD_VERIFICATION_CODE &&
IsValidCreditCardSecurityCode(field->value,
@@ -1226,14 +1258,19 @@ void AutofillManager::ImportFormData(const FormStructure& submitted_form) {
// Both the CVC and address checks are done. Conform to the legacy order of
// reporting on CVC then address.
+ should_cvc_be_requested_ = false;
if (upload_request_.cvc.empty()) {
- AutofillMetrics::LogCardUploadDecisionMetric(
- AutofillMetrics::UPLOAD_NOT_OFFERED_NO_CVC);
- LogCardUploadDecisionUkm(AutofillMetrics::UPLOAD_NOT_OFFERED_NO_CVC);
- pending_upload_request_url_ = GURL();
- CollectRapportSample(submitted_form.source_url(),
- "Autofill.CardUploadNotOfferedNoCvc");
- return;
+ if (IsAutofillUpstreamRequestCvcIfMissingExperimentEnabled()) {
+ should_cvc_be_requested_ = true;
+ } else {
+ AutofillMetrics::LogCardUploadDecisionMetric(
+ AutofillMetrics::UPLOAD_NOT_OFFERED_NO_CVC);
+ LogCardUploadDecisionUkm(AutofillMetrics::UPLOAD_NOT_OFFERED_NO_CVC);
+ pending_upload_request_url_ = GURL();
+ CollectRapportSample(submitted_form.source_url(),
+ "Autofill.CardUploadNotOfferedNoCvc");
+ return;
+ }
}
if (!get_profiles_succeeded) {
DCHECK(get_profiles_decision_metric != AutofillMetrics::UPLOAD_OFFERED);
@@ -1378,11 +1415,10 @@ void AutofillManager::UploadFormDataAsyncCallback(
const TimeTicks& interaction_time,
const TimeTicks& submission_time,
bool observed_submission) {
- submitted_form->LogQualityMetrics(load_time, interaction_time,
- submission_time,
- client_->GetRapporServiceImpl(),
- did_show_suggestions_, observed_submission);
-
+ submitted_form->LogQualityMetrics(
+ load_time, interaction_time, submission_time,
+ client_->GetRapporServiceImpl(), form_interactions_ukm_logger_.get(),
+ did_show_suggestions_, observed_submission);
if (submitted_form->ShouldBeCrowdsourced())
UploadFormData(*submitted_form, observed_submission);
}
@@ -1416,10 +1452,12 @@ void AutofillManager::Reset() {
ProcessPendingFormForUpload();
DCHECK(!pending_form_data_);
form_structures_.clear();
- address_form_event_logger_.reset(
- new AutofillMetrics::FormEventLogger(false /* is_for_credit_card */));
- credit_card_form_event_logger_.reset(
- new AutofillMetrics::FormEventLogger(true /* is_for_credit_card */));
+ form_interactions_ukm_logger_.reset(
+ new AutofillMetrics::FormInteractionsUkmLogger(client_->GetUkmService()));
+ address_form_event_logger_.reset(new AutofillMetrics::FormEventLogger(
+ false /* is_for_credit_card */, form_interactions_ukm_logger_.get()));
+ credit_card_form_event_logger_.reset(new AutofillMetrics::FormEventLogger(
+ true /* is_for_credit_card */, form_interactions_ukm_logger_.get()));
#if defined(OS_ANDROID) || defined(OS_IOS)
autofill_assistant_.Reset();
#endif
@@ -1443,16 +1481,24 @@ AutofillManager::AutofillManager(AutofillDriver* driver,
PersonalDataManager* personal_data)
: driver_(driver),
client_(client),
- payments_client_(
- new payments::PaymentsClient(driver->GetURLRequestContext(), this)),
+ payments_client_(base::MakeUnique<payments::PaymentsClient>(
+ driver->GetURLRequestContext(),
+ this)),
app_locale_("en-US"),
personal_data_(personal_data),
autocomplete_history_manager_(
- new AutocompleteHistoryManager(driver, client)),
+ base::MakeUnique<AutocompleteHistoryManager>(driver, client)),
+ form_interactions_ukm_logger_(
+ base::MakeUnique<AutofillMetrics::FormInteractionsUkmLogger>(
+ client->GetUkmService())),
address_form_event_logger_(
- new AutofillMetrics::FormEventLogger(false /* is_for_credit_card */)),
+ base::MakeUnique<AutofillMetrics::FormEventLogger>(
+ false /* is_for_credit_card */,
+ form_interactions_ukm_logger_.get())),
credit_card_form_event_logger_(
- new AutofillMetrics::FormEventLogger(true /* is_for_credit_card */)),
+ base::MakeUnique<AutofillMetrics::FormEventLogger>(
+ true /* is_for_credit_card */,
+ form_interactions_ukm_logger_.get())),
has_logged_autofill_enabled_(false),
has_logged_address_suggestions_count_(false),
did_show_suggestions_(false),
@@ -1483,34 +1529,34 @@ bool AutofillManager::RefreshDataModels() {
// Updating the FormEventLoggers for addresses and credit cards.
{
- bool is_server_data_available = false;
- bool is_local_data_available = false;
+ size_t server_record_type_count = 0;
+ size_t local_record_type_count = 0;
for (CreditCard* credit_card : credit_cards) {
if (credit_card->record_type() == CreditCard::LOCAL_CARD)
- is_local_data_available = true;
+ local_record_type_count++;
else
- is_server_data_available = true;
+ server_record_type_count++;
}
- credit_card_form_event_logger_->set_is_server_data_available(
- is_server_data_available);
- credit_card_form_event_logger_->set_is_local_data_available(
- is_local_data_available);
+ credit_card_form_event_logger_->set_server_record_type_count(
+ server_record_type_count);
+ credit_card_form_event_logger_->set_local_record_type_count(
+ local_record_type_count);
credit_card_form_event_logger_->set_is_context_secure(
client_->IsContextSecure());
}
{
- bool is_server_data_available = false;
- bool is_local_data_available = false;
+ size_t server_record_type_count = 0;
+ size_t local_record_type_count = 0;
for (AutofillProfile* profile : profiles) {
if (profile->record_type() == AutofillProfile::LOCAL_PROFILE)
- is_local_data_available = true;
+ local_record_type_count++;
else if (profile->record_type() == AutofillProfile::SERVER_PROFILE)
- is_server_data_available = true;
+ server_record_type_count++;
}
- address_form_event_logger_->set_is_server_data_available(
- is_server_data_available);
- address_form_event_logger_->set_is_local_data_available(
- is_local_data_available);
+ address_form_event_logger_->set_server_record_type_count(
+ server_record_type_count);
+ address_form_event_logger_->set_local_record_type_count(
+ local_record_type_count);
}
if (profiles.empty() && credit_cards.empty())
@@ -1679,7 +1725,8 @@ void AutofillManager::FillOrPreviewDataModelForm(
std::unique_ptr<FormStructure> AutofillManager::ValidateSubmittedForm(
const FormData& form) {
- std::unique_ptr<FormStructure> submitted_form(new FormStructure(form));
+ std::unique_ptr<FormStructure> submitted_form(
+ base::MakeUnique<FormStructure>(form));
if (!ShouldUploadForm(*submitted_form))
return std::unique_ptr<FormStructure>();
@@ -1689,7 +1736,7 @@ std::unique_ptr<FormStructure> AutofillManager::ValidateSubmittedForm(
if (!FindCachedForm(form, &cached_submitted_form))
return std::unique_ptr<FormStructure>();
- submitted_form->UpdateFromCache(*cached_submitted_form);
+ submitted_form->UpdateFromCache(*cached_submitted_form, false);
return submitted_form;
}
@@ -1702,8 +1749,9 @@ bool AutofillManager::FindCachedForm(const FormData& form,
// protocol with the crowdsourcing server does not permit us to discard the
// original versions of the forms.
*form_structure = NULL;
+ const auto& form_signature = autofill::CalculateFormSignature(form);
for (auto& cur_form : base::Reversed(form_structures_)) {
- if (*cur_form == form) {
+ if (cur_form->form_signature() == form_signature || *cur_form == form) {
*form_structure = cur_form.get();
// The same form might be cached with multiple field counts: in some
@@ -1785,41 +1833,17 @@ bool AutofillManager::UpdateCachedForm(const FormData& live_form,
if (!needs_update)
return true;
- if (form_structures_.size() >= kMaxFormCacheSize)
+ // Note: We _must not_ remove the original version of the cached form from
+ // the list of |form_structures_|. Otherwise, we break parsing of the
+ // crowdsourcing server's response to our query.
+ if (!ParseForm(live_form, updated_form))
return false;
- // Add the new or updated form to our cache.
- form_structures_.push_back(base::MakeUnique<FormStructure>(live_form));
- *updated_form = form_structures_.rbegin()->get();
- (*updated_form)->DetermineHeuristicTypes();
-
- // If we have cached data, propagate it to the updated form.
- if (cached_form) {
- std::map<base::string16, const AutofillField*> cached_fields;
- for (size_t i = 0; i < cached_form->field_count(); ++i) {
- const AutofillField* field = cached_form->field(i);
- cached_fields[field->unique_name()] = field;
- }
-
- for (size_t i = 0; i < (*updated_form)->field_count(); ++i) {
- AutofillField* field = (*updated_form)->field(i);
- auto cached_field = cached_fields.find(field->unique_name());
- if (cached_field != cached_fields.end()) {
- field->set_server_type(cached_field->second->server_type());
- field->is_autofilled = cached_field->second->is_autofilled;
- field->set_previously_autofilled(
- cached_field->second->previously_autofilled());
- }
- }
-
- // Note: We _must not_ remove the original version of the cached form from
- // the list of |form_structures_|. Otherwise, we break parsing of the
- // crowdsourcing server's response to our query.
- }
+ if (cached_form)
+ (*updated_form)->UpdateFromCache(*cached_form, true);
// Annotate the updated form with its predicted types.
- std::vector<FormStructure*> forms(1, *updated_form);
- driver_->SendAutofillTypePredictionsToRenderer(forms);
+ driver_->SendAutofillTypePredictionsToRenderer({*updated_form});
return true;
}
@@ -1878,27 +1902,21 @@ void AutofillManager::ParseForms(const std::vector<FormData>& forms) {
std::vector<FormStructure*> non_queryable_forms;
std::vector<FormStructure*> queryable_forms;
for (const FormData& form : forms) {
- const auto parse_form_start_time = base::TimeTicks::Now();
+ const auto parse_form_start_time = TimeTicks::Now();
- std::unique_ptr<FormStructure> form_structure =
- base::MakeUnique<FormStructure>(form);
- form_structure->ParseFieldTypesFromAutocompleteAttributes();
- if (!form_structure->ShouldBeParsed())
+ FormStructure* form_structure = nullptr;
+ if (!ParseForm(form, &form_structure))
continue;
+ DCHECK(form_structure);
- form_structure->DetermineHeuristicTypes();
-
- // Ownership is transferred to |form_structures_| which maintains it until
- // the manager is Reset() or destroyed. It is safe to use references below
- // as long as receivers don't take ownership.
- form_structures_.push_back(std::move(form_structure));
-
- if (form_structures_.back()->ShouldBeCrowdsourced())
- queryable_forms.push_back(form_structures_.back().get());
+ // Set aside forms with method GET or author-specified types, so that they
+ // are not included in the query to the server.
+ if (form_structure->ShouldBeCrowdsourced())
+ queryable_forms.push_back(form_structure);
else
- non_queryable_forms.push_back(form_structures_.back().get());
+ non_queryable_forms.push_back(form_structure);
- AutofillMetrics::LogParseFormTiming(base::TimeTicks::Now() -
+ AutofillMetrics::LogParseFormTiming(TimeTicks::Now() -
parse_form_start_time);
}
@@ -1909,6 +1927,9 @@ void AutofillManager::ParseForms(const std::vector<FormData>& forms) {
if (!queryable_forms.empty() || !non_queryable_forms.empty()) {
AutofillMetrics::LogUserHappinessMetric(AutofillMetrics::FORMS_LOADED);
+ // Setup the url for metrics that we will collect for this form.
+ form_interactions_ukm_logger_->OnFormsLoaded(forms[0].origin);
+
#if defined(OS_IOS)
// Log this from same location as AutofillMetrics::FORMS_LOADED to ensure
// that KeyboardAccessoryButtonsIOS and UserHappiness UMA metrics will be
@@ -1938,6 +1959,26 @@ void AutofillManager::ParseForms(const std::vector<FormData>& forms) {
driver_->SendAutofillTypePredictionsToRenderer(non_queryable_forms);
}
+bool AutofillManager::ParseForm(const FormData& form,
+ FormStructure** parsed_form_structure) {
+ DCHECK(parsed_form_structure);
+ if (form_structures_.size() >= kMaxFormCacheSize)
+ return false;
+
+ auto form_structure = base::MakeUnique<FormStructure>(form);
+ form_structure->ParseFieldTypesFromAutocompleteAttributes();
+ if (!form_structure->ShouldBeParsed())
+ return false;
+
+ // Ownership is transferred to |form_structures_| which maintains it until
+ // the manager is Reset() or destroyed. It is safe to use references below
+ // as long as receivers don't take ownership.
+ form_structures_.push_back(std::move(form_structure));
+ *parsed_form_structure = form_structures_.back().get();
+ (*parsed_form_structure)->DetermineHeuristicTypes(client_->GetUkmService());
+ return true;
+}
+
int AutofillManager::BackendIDToInt(const std::string& backend_id) const {
if (!base::IsValidGUID(backend_id))
return 0;
@@ -2016,7 +2057,7 @@ void AutofillManager::DeterminePossibleFieldTypesForUpload(
// profile or credit card, identify any stored types that match the value.
for (size_t i = 0; i < submitted_form->field_count(); ++i) {
AutofillField* field = submitted_form->field(i);
- ServerFieldTypeSet matching_types;
+ ServerFieldTypeSet matching_types = field->possible_types();
base::string16 value;
base::TrimWhitespace(field->value, base::TRIM_ALL, &value);
diff --git a/chromium/components/autofill/core/browser/autofill_manager.h b/chromium/components/autofill/core/browser/autofill_manager.h
index 290126ec108..c8597275741 100644
--- a/chromium/components/autofill/core/browser/autofill_manager.h
+++ b/chromium/components/autofill/core/browser/autofill_manager.h
@@ -43,8 +43,6 @@
#define ENABLE_FORM_DEBUG_DUMP
#endif
-class GURL;
-
namespace gfx {
class RectF;
}
@@ -191,9 +189,9 @@ class AutofillManager : public AutofillDownloadManager::Observer,
// Will send an upload based on the |form_structure| data and the local
// Autofill profile data. |observed_submission| is specified if the upload
// follows an observed submission event.
- void StartUploadProcess(std::unique_ptr<FormStructure> form_structure,
- const base::TimeTicks& timestamp,
- bool observed_submission);
+ virtual void StartUploadProcess(std::unique_ptr<FormStructure> form_structure,
+ const base::TimeTicks& timestamp,
+ bool observed_submission);
// Update the pending form with |form|, possibly processing the current
// pending form for upload.
@@ -270,6 +268,10 @@ class AutofillManager : public AutofillDownloadManager::Observer,
return &form_structures_;
}
+ AutofillMetrics::FormInteractionsUkmLogger* form_interactions_ukm_logger() {
+ return form_interactions_ukm_logger_.get();
+ }
+
// Exposed for testing.
AutofillExternalDelegate* external_delegate() {
return external_delegate_;
@@ -414,6 +416,9 @@ class AutofillManager : public AutofillDownloadManager::Observer,
// Parses the forms using heuristic matching and querying the Autofill server.
void ParseForms(const std::vector<FormData>& forms);
+ // Parses the form and adds it to |form_structures_|.
+ bool ParseForm(const FormData& form, FormStructure** parsed_form_structure);
+
// Imports the form data, submitted by the user, into |personal_data_|.
void ImportFormData(const FormStructure& submitted_form);
@@ -507,6 +512,10 @@ class AutofillManager : public AutofillDownloadManager::Observer,
// Handles single-field autocomplete form data.
std::unique_ptr<AutocompleteHistoryManager> autocomplete_history_manager_;
+ // Utility for logging URL keyed metrics.
+ std::unique_ptr<AutofillMetrics::FormInteractionsUkmLogger>
+ form_interactions_ukm_logger_;
+
// Utilities for logging form events.
std::unique_ptr<AutofillMetrics::FormEventLogger> address_form_event_logger_;
std::unique_ptr<AutofillMetrics::FormEventLogger>
@@ -552,6 +561,7 @@ class AutofillManager : public AutofillDownloadManager::Observer,
payments::PaymentsClient::UploadRequestDetails upload_request_;
bool user_did_accept_upload_prompt_;
GURL pending_upload_request_url_;
+ bool should_cvc_be_requested_;
#ifdef ENABLE_FORM_DEBUG_DUMP
// The last few autofilled forms (key/value pairs) submitted, for debugging.
@@ -592,6 +602,7 @@ class AutofillManager : public AutofillDownloadManager::Observer,
FRIEND_TEST_ALL_PREFIXES(AutofillMetricsTest, AddressSubmittedFormEvents);
FRIEND_TEST_ALL_PREFIXES(AutofillMetricsTest, AddressWillSubmitFormEvents);
FRIEND_TEST_ALL_PREFIXES(AutofillMetricsTest, AddressSuggestionsCount);
+ FRIEND_TEST_ALL_PREFIXES(AutofillMetricsTest, AutofillFormSubmittedState);
FRIEND_TEST_ALL_PREFIXES(AutofillMetricsTest, AutofillIsEnabledAtPageLoad);
FRIEND_TEST_ALL_PREFIXES(AutofillMetricsTest, CreditCardSelectedFormEvents);
FRIEND_TEST_ALL_PREFIXES(AutofillMetricsTest, CreditCardFilledFormEvents);
diff --git a/chromium/components/autofill/core/browser/autofill_manager_unittest.cc b/chromium/components/autofill/core/browser/autofill_manager_unittest.cc
index 54643c65a6a..e9d94a48d40 100644
--- a/chromium/components/autofill/core/browser/autofill_manager_unittest.cc
+++ b/chromium/components/autofill/core/browser/autofill_manager_unittest.cc
@@ -8,6 +8,7 @@
#include <algorithm>
#include <memory>
+#include <utility>
#include <vector>
#include "base/command_line.h"
@@ -27,6 +28,7 @@
#include "base/strings/utf_string_conversions.h"
#include "base/test/histogram_tester.h"
#include "base/test/scoped_feature_list.h"
+#include "base/test/scoped_task_environment.h"
#include "base/threading/thread_task_runner_handle.h"
#include "base/time/time.h"
#include "build/build_config.h"
@@ -57,6 +59,7 @@
#include "components/ukm/ukm_entry.h"
#include "components/ukm/ukm_source.h"
#include "components/variations/variations_associated_data.h"
+#include "net/base/url_util.h"
#include "net/url_request/url_request_test_util.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -170,9 +173,11 @@ class TestPersonalDataManager : public PersonalDataManager {
web_profiles_.push_back(std::move(profile));
}
- void AddCreditCard(std::unique_ptr<CreditCard> credit_card) {
- credit_card->set_modification_date(base::Time::Now());
- local_credit_cards_.push_back(std::move(credit_card));
+ void AddCreditCard(const CreditCard& credit_card) override {
+ std::unique_ptr<CreditCard> local_credit_card =
+ base::MakeUnique<CreditCard>(credit_card);
+ local_credit_card->set_modification_date(base::Time::Now());
+ local_credit_cards_.push_back(std::move(local_credit_card));
}
void RecordUseOf(const AutofillDataModel& data_model) override {
@@ -492,18 +497,18 @@ class MockAutocompleteHistoryManager : public AutocompleteHistoryManager {
class MockAutofillDriver : public TestAutofillDriver {
public:
MockAutofillDriver()
- : is_off_the_record_(false), did_interact_with_credit_card_form_(false) {}
+ : is_incognito_(false), did_interact_with_credit_card_form_(false) {}
// Mock methods to enable testability.
MOCK_METHOD3(SendFormDataToRenderer, void(int query_id,
RendererFormDataAction action,
const FormData& data));
- void SetIsOffTheRecord(bool is_off_the_record) {
- is_off_the_record_ = is_off_the_record;
+ void SetIsIncognito(bool is_incognito) {
+ is_incognito_ = is_incognito;
}
- bool IsOffTheRecord() const override { return is_off_the_record_; }
+ bool IsIncognito() const override { return is_incognito_; }
void DidInteractWithCreditCardForm() override {
did_interact_with_credit_card_form_ = true;
@@ -518,7 +523,7 @@ class MockAutofillDriver : public TestAutofillDriver {
}
private:
- bool is_off_the_record_;
+ bool is_incognito_;
bool did_interact_with_credit_card_form_;
DISALLOW_COPY_AND_ASSIGN(MockAutofillDriver);
};
@@ -628,8 +633,8 @@ class TestAutofillManager : public AutofillManager {
personal_data_->AddProfile(std::move(profile));
}
- void AddCreditCard(std::unique_ptr<CreditCard> credit_card) {
- personal_data_->AddCreditCard(std::move(credit_card));
+ void AddCreditCard(const CreditCard& credit_card) {
+ personal_data_->AddCreditCard(credit_card);
}
int GetPackedCreditCardID(int credit_card_id) {
@@ -790,6 +795,15 @@ const ukm::Entry_Metric* FindMetric(
return nullptr;
}
+// Get Ukm sources from the Ukm service.
+std::vector<const ukm::UkmSource*> GetUkmSources(ukm::TestUkmService* service) {
+ std::vector<const ukm::UkmSource*> sources;
+ for (const auto& kv : service->GetSources())
+ sources.push_back(kv.second.get());
+
+ return sources;
+}
+
} // namespace
class AutofillManagerTest : public testing::Test {
@@ -1018,13 +1032,17 @@ class AutofillManagerTest : public testing::Test {
scoped_feature_list_.InitAndEnableFeature(kAutofillUkmLogging);
}
- void ExpectUniqueCardUploadDecisionUkm(
- AutofillMetrics::CardUploadDecisionMetric upload_decision) {
+ void EnableAutofillUpstreamRequestCvcIfMissingExperimentAndUkmLogging() {
+ scoped_feature_list_.InitWithFeatures(
+ {kAutofillUpstreamRequestCvcIfMissing, kAutofillUkmLogging}, {});
+ }
+
+ void ExpectUniqueFillableFormParsedUkm() {
ukm::TestUkmService* ukm_service = autofill_client_.GetTestUkmService();
// Check that one source is logged.
ASSERT_EQ(1U, ukm_service->sources_count());
- const ukm::UkmSource* source = ukm_service->GetSource(0);
+ const ukm::UkmSource* source = GetUkmSources(ukm_service)[0];
// Check that one entry is logged.
EXPECT_EQ(1U, ukm_service->entries_count());
@@ -1035,20 +1053,67 @@ class AutofillManagerTest : public testing::Test {
entry->PopulateProto(&entry_proto);
EXPECT_EQ(source->id(), entry_proto.source_id());
- // Check if there is an entry for card upload decisions.
- EXPECT_EQ(base::HashMetricName(internal::kUKMCardUploadDecisionEntryName),
+ // Check if there is an entry for developer engagement decision.
+ EXPECT_EQ(base::HashMetricName(internal::kUKMDeveloperEngagementEntryName),
entry_proto.event_hash());
EXPECT_EQ(1, entry_proto.metrics_size());
- // Check that the expected upload decision is logged.
+ // Check that the expected developer engagement metric is logged.
const ukm::Entry_Metric* metric = FindMetric(
- internal::kUKMCardUploadDecisionMetricName, entry_proto.metrics());
+ internal::kUKMDeveloperEngagementMetricName, entry_proto.metrics());
ASSERT_NE(nullptr, metric);
- EXPECT_EQ(static_cast<int>(upload_decision), metric->value());
+ EXPECT_EQ(static_cast<int>(
+ AutofillMetrics::FILLABLE_FORM_PARSED_WITHOUT_TYPE_HINTS),
+ metric->value());
+ }
+
+ void ExpectCardUploadDecisionUkm(
+ AutofillMetrics::CardUploadDecisionMetric upload_decision) {
+ ExpectMetric(internal::kUKMCardUploadDecisionMetricName,
+ internal::kUKMCardUploadDecisionEntryName,
+ static_cast<int>(upload_decision),
+ 1 /* expected_num_matching_entries */);
+ }
+
+ void ExpectFillableFormParsedUkm(int num_fillable_forms_parsed) {
+ ExpectMetric(internal::kUKMDeveloperEngagementMetricName,
+ internal::kUKMDeveloperEngagementEntryName,
+ static_cast<int>(
+ AutofillMetrics::FILLABLE_FORM_PARSED_WITHOUT_TYPE_HINTS),
+ num_fillable_forms_parsed);
+ }
+
+ void ExpectMetric(const char* metric_name,
+ const char* entry_name,
+ int metric_value,
+ int expected_num_matching_entries) {
+ ukm::TestUkmService* ukm_service = autofill_client_.GetTestUkmService();
+
+ int num_matching_entries = 0;
+ for (size_t i = 0; i < ukm_service->entries_count(); ++i) {
+ const ukm::UkmEntry* entry = ukm_service->GetEntry(i);
+
+ ukm::Entry entry_proto;
+ entry->PopulateProto(&entry_proto);
+ EXPECT_EQ(entry->source_id(), entry_proto.source_id());
+
+ // Check if there is an entry for |entry_name|.
+ if (entry_proto.event_hash() == base::HashMetricName(entry_name)) {
+ EXPECT_EQ(1, entry_proto.metrics_size());
+
+ // Check that the expected |metric_value| is logged.
+ const ukm::Entry_Metric* metric =
+ FindMetric(metric_name, entry_proto.metrics());
+ ASSERT_NE(nullptr, metric);
+ EXPECT_EQ(metric_value, metric->value());
+ ++num_matching_entries;
+ }
+ }
+ EXPECT_EQ(expected_num_matching_entries, num_matching_entries);
}
protected:
- base::MessageLoop message_loop_;
+ base::test::ScopedTaskEnvironment scoped_task_environment_;
MockAutofillClient autofill_client_;
std::unique_ptr<MockAutofillDriver> autofill_driver_;
std::unique_ptr<TestAutofillManager> autofill_manager_;
@@ -1541,12 +1606,12 @@ TEST_F(AutofillManagerTest, GetCreditCardSuggestions_StopCharsOnly) {
// field has stop characters in it and some input.
TEST_F(AutofillManagerTest, GetCreditCardSuggestions_StopCharsWithInput) {
// Add a credit card with particular numbers that we will attempt to recall.
- std::unique_ptr<CreditCard> credit_card = base::MakeUnique<CreditCard>();
- test::SetCreditCardInfo(credit_card.get(), "John Smith",
+ CreditCard credit_card;
+ test::SetCreditCardInfo(&credit_card, "John Smith",
"5255667890123123", // Mastercard
"08", "2017");
- credit_card->set_guid("00000000-0000-0000-0000-000000000007");
- autofill_manager_->AddCreditCard(std::move(credit_card));
+ credit_card.set_guid("00000000-0000-0000-0000-000000000007");
+ autofill_manager_->AddCreditCard(credit_card);
// Set up our form data.
FormData form;
@@ -1823,13 +1888,13 @@ TEST_F(AutofillManagerTest,
TEST_F(AutofillManagerTest, GetCreditCardSuggestions_RepeatedObfuscatedNumber) {
// Add a credit card with the same obfuscated number as Elvis's.
// |credit_card| will be owned by the mock PersonalDataManager.
- std::unique_ptr<CreditCard> credit_card = base::MakeUnique<CreditCard>();
- test::SetCreditCardInfo(credit_card.get(), "Elvis Presley",
+ CreditCard credit_card;
+ test::SetCreditCardInfo(&credit_card, "Elvis Presley",
"5231567890123456", // Mastercard
"05", "2999");
- credit_card->set_guid("00000000-0000-0000-0000-000000000007");
- credit_card->set_use_date(base::Time::Now() - base::TimeDelta::FromDays(15));
- autofill_manager_->AddCreditCard(std::move(credit_card));
+ credit_card.set_guid("00000000-0000-0000-0000-000000000007");
+ credit_card.set_use_date(base::Time::Now() - base::TimeDelta::FromDays(15));
+ autofill_manager_->AddCreditCard(credit_card);
// Set up our form data.
FormData form;
@@ -3445,7 +3510,7 @@ TEST_F(AutofillManagerTest, OnLoadedServerPredictions) {
// Simulate having seen this form on page load.
// |form_structure| will be owned by |autofill_manager_|.
TestFormStructure* form_structure = new TestFormStructure(form);
- form_structure->DetermineHeuristicTypes();
+ form_structure->DetermineHeuristicTypes(nullptr /* ukm_service */);
autofill_manager_->AddSeenForm(base::WrapUnique(form_structure));
// Similarly, a second form.
@@ -3465,7 +3530,7 @@ TEST_F(AutofillManagerTest, OnLoadedServerPredictions) {
form2.fields.push_back(field);
TestFormStructure* form_structure2 = new TestFormStructure(form2);
- form_structure2->DetermineHeuristicTypes();
+ form_structure2->DetermineHeuristicTypes(nullptr /* ukm_service */);
autofill_manager_->AddSeenForm(base::WrapUnique(form_structure2));
AutofillQueryResponseContents response;
@@ -3518,7 +3583,7 @@ TEST_F(AutofillManagerTest, OnLoadedServerPredictions_ResetManager) {
// Simulate having seen this form on page load.
// |form_structure| will be owned by |autofill_manager_|.
TestFormStructure* form_structure = new TestFormStructure(form);
- form_structure->DetermineHeuristicTypes();
+ form_structure->DetermineHeuristicTypes(nullptr /* ukm_service */);
autofill_manager_->AddSeenForm(base::WrapUnique(form_structure));
AutofillQueryResponseContents response;
@@ -3556,7 +3621,7 @@ TEST_F(AutofillManagerTest, FormSubmittedServerTypes) {
// Simulate having seen this form on page load.
// |form_structure| will be owned by |autofill_manager_|.
TestFormStructure* form_structure = new TestFormStructure(form);
- form_structure->DetermineHeuristicTypes();
+ form_structure->DetermineHeuristicTypes(nullptr /* ukm_service */);
// Clear the heuristic types, and instead set the appropriate server types.
std::vector<ServerFieldType> heuristic_types, server_types;
@@ -4151,10 +4216,10 @@ TEST_F(AutofillManagerTest, RemoveProfile) {
TEST_F(AutofillManagerTest, RemoveCreditCard) {
// Add and remove an Autofill credit card.
- std::unique_ptr<CreditCard> credit_card = base::MakeUnique<CreditCard>();
+ CreditCard credit_card;
const char guid[] = "00000000-0000-0000-0000-000000100007";
- credit_card->set_guid(guid);
- autofill_manager_->AddCreditCard(std::move(credit_card));
+ credit_card.set_guid(guid);
+ autofill_manager_->AddCreditCard(credit_card);
int id = MakeFrontendID(guid, std::string());
@@ -4526,6 +4591,8 @@ TEST_F(AutofillManagerTest, MAYBE_UploadCreditCard) {
FormData address_form;
test::CreateTestAddressFormData(&address_form);
FormsSeen(std::vector<FormData>(1, address_form));
+ ExpectUniqueFillableFormParsedUkm();
+
ManuallyFillAddressForm("Flo", "Master", "77401", "US", &address_form);
FormSubmitted(address_form);
@@ -4533,6 +4600,7 @@ TEST_F(AutofillManagerTest, MAYBE_UploadCreditCard) {
FormData credit_card_form;
CreateTestCreditCardFormData(&credit_card_form, true, false);
FormsSeen(std::vector<FormData>(1, credit_card_form));
+ ExpectFillableFormParsedUkm(2 /* num_fillable_forms_parsed */);
// Edit the data, and submit.
credit_card_form.fields[0].value = ASCIIToUTF16("Flo Master");
@@ -4550,7 +4618,7 @@ TEST_F(AutofillManagerTest, MAYBE_UploadCreditCard) {
histogram_tester.ExpectUniqueSample("Autofill.CardUploadDecisionExpanded",
AutofillMetrics::UPLOAD_OFFERED, 1);
// Verify that the correct UKM was logged.
- ExpectUniqueCardUploadDecisionUkm(AutofillMetrics::UPLOAD_OFFERED);
+ ExpectCardUploadDecisionUkm(AutofillMetrics::UPLOAD_OFFERED);
}
// TODO(crbug.com/666704): Flaky on android_n5x_swarming_rel bot.
@@ -4610,6 +4678,8 @@ TEST_F(AutofillManagerTest, MAYBE_UploadCreditCard_CvcUnavailable) {
FormData address_form;
test::CreateTestAddressFormData(&address_form);
FormsSeen(std::vector<FormData>(1, address_form));
+ ExpectUniqueFillableFormParsedUkm();
+
ManuallyFillAddressForm("Flo", "Master", "77401", "US", &address_form);
FormSubmitted(address_form);
@@ -4617,6 +4687,7 @@ TEST_F(AutofillManagerTest, MAYBE_UploadCreditCard_CvcUnavailable) {
FormData credit_card_form;
CreateTestCreditCardFormData(&credit_card_form, true, false);
FormsSeen(std::vector<FormData>(1, credit_card_form));
+ ExpectFillableFormParsedUkm(2 /* num_fillable_forms_parsed */);
// Edit the data, and submit.
credit_card_form.fields[0].value = ASCIIToUTF16("Flo Master");
@@ -4637,7 +4708,7 @@ TEST_F(AutofillManagerTest, MAYBE_UploadCreditCard_CvcUnavailable) {
"Autofill.CardUploadDecisionExpanded",
AutofillMetrics::UPLOAD_NOT_OFFERED_NO_CVC, 1);
// Verify that the correct UKM was logged.
- ExpectUniqueCardUploadDecisionUkm(AutofillMetrics::UPLOAD_NOT_OFFERED_NO_CVC);
+ ExpectCardUploadDecisionUkm(AutofillMetrics::UPLOAD_NOT_OFFERED_NO_CVC);
rappor::TestRapporServiceImpl* rappor_service =
autofill_client_.test_rappor_service();
@@ -4693,7 +4764,7 @@ TEST_F(AutofillManagerTest, MAYBE_UploadCreditCard_CvcInvalidLength) {
"Autofill.CardUploadDecisionExpanded",
AutofillMetrics::UPLOAD_NOT_OFFERED_NO_CVC, 1);
// Verify that the correct UKM was logged.
- ExpectUniqueCardUploadDecisionUkm(AutofillMetrics::UPLOAD_NOT_OFFERED_NO_CVC);
+ ExpectCardUploadDecisionUkm(AutofillMetrics::UPLOAD_NOT_OFFERED_NO_CVC);
rappor::TestRapporServiceImpl* rappor_service =
autofill_client_.test_rappor_service();
@@ -4771,7 +4842,146 @@ TEST_F(AutofillManagerTest, MAYBE_UploadCreditCard_MultipleCvcFields) {
"Autofill.CardUploadDecisionExpanded",
AutofillMetrics::UPLOAD_OFFERED, 1);
// Verify that the correct UKM was logged.
- ExpectUniqueCardUploadDecisionUkm(AutofillMetrics::UPLOAD_OFFERED);
+ ExpectCardUploadDecisionUkm(AutofillMetrics::UPLOAD_OFFERED);
+}
+
+// TODO(crbug.com/666704): Flaky on android_n5x_swarming_rel bot.
+#if defined(OS_ANDROID)
+#define MAYBE_UploadCreditCard_NoCvcFieldOnForm \
+ DISABLED_UploadCreditCard_NoCvcFieldOnForm
+#else
+#define MAYBE_UploadCreditCard_NoCvcFieldOnForm \
+ UploadCreditCard_NoCvcFieldOnForm
+#endif
+TEST_F(AutofillManagerTest, MAYBE_UploadCreditCard_NoCvcFieldOnForm) {
+ EnableAutofillUpstreamRequestCvcIfMissingExperimentAndUkmLogging();
+ autofill_manager_->set_credit_card_upload_enabled(true);
+
+ // Remove the profiles that were created in the TestPersonalDataManager
+ // constructor because they would result in conflicting names that would
+ // prevent the upload.
+ personal_data_.ClearAutofillProfiles();
+
+ // Create, fill and submit an address form in order to establish a recent
+ // profile which can be selected for the upload request.
+ FormData address_form;
+ test::CreateTestAddressFormData(&address_form);
+ FormsSeen(std::vector<FormData>(1, address_form));
+ ManuallyFillAddressForm("Flo", "Master", "77401", "US", &address_form);
+ FormSubmitted(address_form);
+
+ // Set up our credit card form data. Note that CVC field is missing.
+ FormData credit_card_form;
+ credit_card_form.name = ASCIIToUTF16("MyForm");
+ credit_card_form.origin = GURL("https://myform.com/form.html");
+ credit_card_form.action = GURL("https://myform.com/submit.html");
+
+ FormFieldData field;
+ test::CreateTestFormField("Card Name", "cardname", "", "text", &field);
+ credit_card_form.fields.push_back(field);
+ test::CreateTestFormField("Card Number", "cardnumber", "", "text", &field);
+ credit_card_form.fields.push_back(field);
+ test::CreateTestFormField("Expiration Month", "ccmonth", "", "text", &field);
+ credit_card_form.fields.push_back(field);
+ test::CreateTestFormField("Expiration Year", "ccyear", "", "text", &field);
+ credit_card_form.fields.push_back(field);
+
+ FormsSeen(std::vector<FormData>(1, credit_card_form));
+
+ // Edit the data, and submit.
+ credit_card_form.fields[0].value = ASCIIToUTF16("Flo Master");
+ credit_card_form.fields[1].value = ASCIIToUTF16("4111111111111111");
+ credit_card_form.fields[2].value = ASCIIToUTF16("11");
+ credit_card_form.fields[3].value = ASCIIToUTF16("2017");
+
+ base::HistogramTester histogram_tester;
+
+ // Upload should still happen as long as the user provides CVC in the bubble.
+ EXPECT_CALL(autofill_client_, ConfirmSaveCreditCardLocally(_, _)).Times(0);
+ FormSubmitted(credit_card_form);
+ EXPECT_TRUE(autofill_manager_->credit_card_was_uploaded());
+
+ // Verify that the correct histogram entry (and only that) was logged.
+ histogram_tester.ExpectUniqueSample("Autofill.CardUploadDecisionExpanded",
+ AutofillMetrics::UPLOAD_OFFERED_NO_CVC,
+ 1);
+ // Verify that the correct UKM was logged.
+ ExpectCardUploadDecisionUkm(AutofillMetrics::UPLOAD_OFFERED_NO_CVC);
+}
+
+// TODO(crbug.com/666704): Flaky on android_n5x_swarming_rel bot.
+#if defined(OS_ANDROID)
+#define MAYBE_UploadCreditCard_NoCvcFieldOnFormExperimentOff \
+ DISABLED_UploadCreditCard_NoCvcFieldOnFormExperimentOff
+#else
+#define MAYBE_UploadCreditCard_NoCvcFieldOnFormExperimentOff \
+ UploadCreditCard_NoCvcFieldOnFormExperimentOff
+#endif
+TEST_F(AutofillManagerTest,
+ MAYBE_UploadCreditCard_NoCvcFieldOnFormExperimentOff) {
+ EnableUkmLogging();
+ autofill_manager_->set_credit_card_upload_enabled(true);
+
+ // Remove the profiles that were created in the TestPersonalDataManager
+ // constructor because they would result in conflicting names that would
+ // prevent the upload.
+ personal_data_.ClearAutofillProfiles();
+
+ // Create, fill and submit an address form in order to establish a recent
+ // profile which can be selected for the upload request.
+ FormData address_form;
+ test::CreateTestAddressFormData(&address_form);
+ FormsSeen(std::vector<FormData>(1, address_form));
+ ManuallyFillAddressForm("Flo", "Master", "77401", "US", &address_form);
+ FormSubmitted(address_form);
+
+ // Set up our credit card form data. Note that CVC field is missing.
+ FormData credit_card_form;
+ credit_card_form.name = ASCIIToUTF16("MyForm");
+ credit_card_form.origin = GURL("https://myform.com/form.html");
+ credit_card_form.action = GURL("https://myform.com/submit.html");
+
+ FormFieldData field;
+ test::CreateTestFormField("Card Name", "cardname", "", "text", &field);
+ credit_card_form.fields.push_back(field);
+ test::CreateTestFormField("Card Number", "cardnumber", "", "text", &field);
+ credit_card_form.fields.push_back(field);
+ test::CreateTestFormField("Expiration Month", "ccmonth", "", "text", &field);
+ credit_card_form.fields.push_back(field);
+ test::CreateTestFormField("Expiration Year", "ccyear", "", "text", &field);
+ credit_card_form.fields.push_back(field);
+
+ FormsSeen(std::vector<FormData>(1, credit_card_form));
+
+ // Edit the data, and submit.
+ credit_card_form.fields[0].value = ASCIIToUTF16("Flo Master");
+ credit_card_form.fields[1].value = ASCIIToUTF16("4111111111111111");
+ credit_card_form.fields[2].value = ASCIIToUTF16("11");
+ credit_card_form.fields[3].value = ASCIIToUTF16("2017");
+
+ base::HistogramTester histogram_tester;
+
+ // Neither a local save nor an upload should happen in this case.
+ EXPECT_CALL(autofill_client_, ConfirmSaveCreditCardLocally(_, _)).Times(0);
+ FormSubmitted(credit_card_form);
+ EXPECT_FALSE(autofill_manager_->credit_card_was_uploaded());
+
+ // Verify that the correct histogram entry (and only that) was logged.
+ histogram_tester.ExpectUniqueSample(
+ "Autofill.CardUploadDecisionExpanded",
+ AutofillMetrics::UPLOAD_NOT_OFFERED_NO_CVC, 1);
+ // Verify that the correct UKM was logged.
+ ExpectCardUploadDecisionUkm(AutofillMetrics::UPLOAD_NOT_OFFERED_NO_CVC);
+
+ rappor::TestRapporServiceImpl* rappor_service =
+ autofill_client_.test_rappor_service();
+ EXPECT_EQ(1, rappor_service->GetReportsCount());
+ std::string sample;
+ rappor::RapporType type;
+ EXPECT_TRUE(rappor_service->GetRecordedSampleForMetric(
+ "Autofill.CardUploadNotOfferedNoCvc", &sample, &type));
+ EXPECT_EQ("myform.com", sample);
+ EXPECT_EQ(rappor::ETLD_PLUS_ONE_RAPPOR_TYPE, type);
}
// TODO(crbug.com/666704): Flaky on android_n5x_swarming_rel bot.
@@ -4811,8 +5021,7 @@ TEST_F(AutofillManagerTest, MAYBE_UploadCreditCard_NoProfileAvailable) {
"Autofill.CardUploadDecisionExpanded",
AutofillMetrics::UPLOAD_NOT_OFFERED_NO_ADDRESS, 1);
// Verify that the correct UKM was logged.
- ExpectUniqueCardUploadDecisionUkm(
- AutofillMetrics::UPLOAD_NOT_OFFERED_NO_ADDRESS);
+ ExpectCardUploadDecisionUkm(AutofillMetrics::UPLOAD_NOT_OFFERED_NO_ADDRESS);
rappor::TestRapporServiceImpl* rappor_service =
autofill_client_.test_rappor_service();
@@ -4865,7 +5074,7 @@ TEST_F(AutofillManagerTest,
"Autofill.CardUploadDecisionExpanded",
AutofillMetrics::UPLOAD_NOT_OFFERED_NO_CVC, 1);
// Verify that the correct UKM was logged.
- ExpectUniqueCardUploadDecisionUkm(AutofillMetrics::UPLOAD_NOT_OFFERED_NO_CVC);
+ ExpectCardUploadDecisionUkm(AutofillMetrics::UPLOAD_NOT_OFFERED_NO_CVC);
rappor::TestRapporServiceImpl* rappor_service =
autofill_client_.test_rappor_service();
@@ -4921,8 +5130,7 @@ TEST_F(AutofillManagerTest, MAYBE_UploadCreditCard_NoNameAvailable) {
"Autofill.CardUploadDecisionExpanded",
AutofillMetrics::UPLOAD_NOT_OFFERED_NO_NAME, 1);
// Verify that the correct UKM was logged.
- ExpectUniqueCardUploadDecisionUkm(
- AutofillMetrics::UPLOAD_NOT_OFFERED_NO_NAME);
+ ExpectCardUploadDecisionUkm(AutofillMetrics::UPLOAD_NOT_OFFERED_NO_NAME);
rappor::TestRapporServiceImpl* rappor_service =
autofill_client_.test_rappor_service();
@@ -4955,6 +5163,7 @@ TEST_F(AutofillManagerTest, MAYBE_UploadCreditCard_ZipCodesConflict) {
address_forms.push_back(address_form1);
address_forms.push_back(address_form2);
FormsSeen(address_forms);
+ ExpectFillableFormParsedUkm(2 /* num_fillable_forms_parsed */);
ManuallyFillAddressForm("Flo", "Master", "77401-8294", "US", &address_form1);
FormSubmitted(address_form1);
@@ -4966,6 +5175,7 @@ TEST_F(AutofillManagerTest, MAYBE_UploadCreditCard_ZipCodesConflict) {
FormData credit_card_form;
CreateTestCreditCardFormData(&credit_card_form, true, false);
FormsSeen(std::vector<FormData>(1, credit_card_form));
+ ExpectFillableFormParsedUkm(3 /* num_fillable_forms_parsed */);
// Edit the data, but don't include a name, and submit.
credit_card_form.fields[0].value = ASCIIToUTF16("Flo Master");
@@ -4986,7 +5196,7 @@ TEST_F(AutofillManagerTest, MAYBE_UploadCreditCard_ZipCodesConflict) {
"Autofill.CardUploadDecisionExpanded",
AutofillMetrics::UPLOAD_NOT_OFFERED_CONFLICTING_ZIPS, 1);
// Verify that the correct UKM was logged.
- ExpectUniqueCardUploadDecisionUkm(
+ ExpectCardUploadDecisionUkm(
AutofillMetrics::UPLOAD_NOT_OFFERED_CONFLICTING_ZIPS);
}
@@ -5041,7 +5251,7 @@ TEST_F(AutofillManagerTest, MAYBE_UploadCreditCard_ZipCodesHavePrefixMatch) {
"Autofill.CardUploadDecisionExpanded",
AutofillMetrics::UPLOAD_OFFERED, 1);
// Verify that the correct UKM was logged.
- ExpectUniqueCardUploadDecisionUkm(AutofillMetrics::UPLOAD_OFFERED);
+ ExpectCardUploadDecisionUkm(AutofillMetrics::UPLOAD_OFFERED);
}
// TODO(crbug.com/666704): Flaky on android_n5x_swarming_rel bot.
@@ -5094,8 +5304,7 @@ TEST_F(AutofillManagerTest, MAYBE_UploadCreditCard_NoZipCodeAvailable) {
"Autofill.CardUploadDecisionExpanded",
AutofillMetrics::UPLOAD_NOT_OFFERED_NO_ZIP_CODE, 1);
// Verify that the correct UKM was logged.
- ExpectUniqueCardUploadDecisionUkm(
- AutofillMetrics::UPLOAD_NOT_OFFERED_NO_ZIP_CODE);
+ ExpectCardUploadDecisionUkm(AutofillMetrics::UPLOAD_NOT_OFFERED_NO_ZIP_CODE);
}
// TODO(crbug.com/666704): Flaky on android_n5x_swarming_rel bot.
@@ -5152,7 +5361,7 @@ TEST_F(AutofillManagerTest, MAYBE_UploadCreditCard_NamesMatchLoosely) {
"Autofill.CardUploadDecisionExpanded",
AutofillMetrics::UPLOAD_OFFERED, 1);
// Verify that the correct UKM was logged.
- ExpectUniqueCardUploadDecisionUkm(AutofillMetrics::UPLOAD_OFFERED);
+ ExpectCardUploadDecisionUkm(AutofillMetrics::UPLOAD_OFFERED);
}
// TODO(crbug.com/666704): Flaky on android_n5x_swarming_rel bot.
@@ -5206,7 +5415,7 @@ TEST_F(AutofillManagerTest, MAYBE_UploadCreditCard_NamesHaveToMatch) {
"Autofill.CardUploadDecisionExpanded",
AutofillMetrics::UPLOAD_NOT_OFFERED_CONFLICTING_NAMES, 1);
// Verify that the correct UKM was logged.
- ExpectUniqueCardUploadDecisionUkm(
+ ExpectCardUploadDecisionUkm(
AutofillMetrics::UPLOAD_NOT_OFFERED_CONFLICTING_NAMES);
rappor::TestRapporServiceImpl* rappor_service =
@@ -5267,7 +5476,7 @@ TEST_F(AutofillManagerTest, MAYBE_UploadCreditCard_UploadDetailsFails) {
"Autofill.CardUploadDecisionExpanded",
AutofillMetrics::UPLOAD_NOT_OFFERED_GET_UPLOAD_DETAILS_FAILED, 1);
// Verify that the correct UKM was logged.
- ExpectUniqueCardUploadDecisionUkm(
+ ExpectCardUploadDecisionUkm(
AutofillMetrics::UPLOAD_NOT_OFFERED_GET_UPLOAD_DETAILS_FAILED);
}
@@ -5617,11 +5826,11 @@ TEST_F(AutofillManagerTest, ShouldUploadForm) {
EXPECT_TRUE(autofill_manager_->ShouldUploadForm(form_structure_4));
// Is off the record.
- autofill_driver_->SetIsOffTheRecord(true);
+ autofill_driver_->SetIsIncognito(true);
EXPECT_FALSE(autofill_manager_->ShouldUploadForm(form_structure_4));
// Make sure it's reset for the next test case.
- autofill_driver_->SetIsOffTheRecord(false);
+ autofill_driver_->SetIsIncognito(false);
EXPECT_TRUE(autofill_manager_->ShouldUploadForm(form_structure_4));
// Has one field which is a password field.
@@ -5742,4 +5951,140 @@ TEST_F(AutofillManagerTest, NotifyDriverOfCreditCardInteraction) {
}
}
+// Tests that a form with server only types is still autofillable if the form
+// gets updated in cache.
+TEST_F(AutofillManagerTest, DisplaySuggestionsForUpdatedServerTypedForm) {
+ // Create a form with unknown heuristic fields.
+ FormData form;
+ form.name = ASCIIToUTF16("MyForm");
+ form.origin = GURL("http://myform.com/form.html");
+ form.action = GURL("http://myform.com/submit.html");
+
+ FormFieldData field;
+ test::CreateTestFormField("Field 1", "field1", "", "text", &field);
+ form.fields.push_back(field);
+ test::CreateTestFormField("Field 2", "field2", "", "text", &field);
+ form.fields.push_back(field);
+ test::CreateTestFormField("Field 3", "field3", "", "text", &field);
+ form.fields.push_back(field);
+
+ auto form_structure = base::MakeUnique<TestFormStructure>(form);
+ form_structure->DetermineHeuristicTypes(nullptr /* ukm_service */);
+ // Make sure the form can not be autofilled now.
+ ASSERT_EQ(0u, form_structure->autofill_count());
+ for (size_t idx = 0; idx < form_structure->field_count(); ++idx) {
+ ASSERT_EQ(UNKNOWN_TYPE, form_structure->field(idx)->heuristic_type());
+ }
+
+ // Prepare and set known server fields.
+ const std::vector<ServerFieldType> heuristic_types(form.fields.size(),
+ UNKNOWN_TYPE);
+ const std::vector<ServerFieldType> server_types{NAME_FIRST, NAME_MIDDLE,
+ NAME_LAST};
+ form_structure->SetFieldTypes(heuristic_types, server_types);
+ autofill_manager_->AddSeenForm(std::move(form_structure));
+
+ // Make sure the form can be autofilled.
+ for (const FormFieldData& field : form.fields) {
+ GetAutofillSuggestions(form, field);
+ ASSERT_TRUE(external_delegate_->on_suggestions_returned_seen());
+ }
+
+ // Modify one of the fields in the original form.
+ form.fields[0].css_classes += ASCIIToUTF16("a");
+
+ // Expect the form still can be autofilled.
+ for (const FormFieldData& field : form.fields) {
+ GetAutofillSuggestions(form, field);
+ EXPECT_TRUE(external_delegate_->on_suggestions_returned_seen());
+ }
+
+ // Modify form action URL. This can happen on in-page navitaion if the form
+ // doesn't have an actual action (attribute is empty).
+ form.action = net::AppendQueryParameter(form.action, "arg", "value");
+
+ // Expect the form still can be autofilled.
+ for (const FormFieldData& field : form.fields) {
+ GetAutofillSuggestions(form, field);
+ EXPECT_TRUE(external_delegate_->on_suggestions_returned_seen());
+ }
+}
+
+// Tests that a form with <select> field is accepted if <option> value (not
+// content) is quite long. Some websites use value to propagate long JSON to
+// JS-backed logic.
+TEST_F(AutofillManagerTest, FormWithLongOptionValuesIsAcceptable) {
+ FormData form;
+ form.name = ASCIIToUTF16("MyForm");
+ form.origin = GURL("http://myform.com/form.html");
+ form.action = GURL("http://myform.com/submit.html");
+
+ FormFieldData field;
+ test::CreateTestFormField("First name", "firstname", "", "text", &field);
+ form.fields.push_back(field);
+ test::CreateTestFormField("Last name", "lastname", "", "text", &field);
+ form.fields.push_back(field);
+
+ // Prepare <select> field with long <option> values.
+ const size_t kOptionValueLength = 10240;
+ const std::string long_string(kOptionValueLength, 'a');
+ const std::vector<const char*> values(3, long_string.c_str());
+ const std::vector<const char*> contents{"A", "B", "C"};
+ test::CreateTestSelectField("Country", "country", "", values, contents,
+ values.size(), &field);
+ form.fields.push_back(field);
+
+ FormsSeen({form});
+
+ // Suggestions should be displayed.
+ for (const FormFieldData& field : form.fields) {
+ GetAutofillSuggestions(form, field);
+ EXPECT_TRUE(external_delegate_->on_suggestions_returned_seen());
+ }
+}
+
+// Test that a sign-in form submission sends an upload with types matching the
+// fields.
+TEST_F(AutofillManagerTest, SignInFormSubmission_Upload) {
+ // Set up our form data (it's already filled out with user data).
+ FormData form;
+ form.origin = GURL("http://myform.com/form.html");
+ form.action = GURL("http://myform.com/submit.html");
+
+ std::vector<ServerFieldTypeSet> expected_types;
+ ServerFieldTypeSet types;
+
+ FormFieldData field;
+ test::CreateTestFormField("Email", "email", "theking@gmail.com", "text",
+ &field);
+ form.fields.push_back(field);
+ types.insert(EMAIL_ADDRESS);
+ expected_types.push_back(types);
+
+ test::CreateTestFormField("Password", "pw", "secret", "password", &field);
+ form.fields.push_back(field);
+ types.clear();
+ types.insert(PASSWORD);
+ expected_types.push_back(types);
+
+ // We will expect these types in the upload and no observed submission. (the
+ // callback initiated by WaitForAsyncUploadProcess checks these expectations.)
+ autofill_manager_->set_expected_submitted_field_types(expected_types);
+ autofill_manager_->set_expected_observed_submission(true);
+ autofill_manager_->ResetRunLoop();
+
+ std::unique_ptr<FormStructure> form_structure(new FormStructure(form));
+ form_structure->set_is_signin_upload(true);
+ form_structure->field(1)->set_possible_types({autofill::PASSWORD});
+
+ std::string signature = form_structure->FormSignatureAsStr();
+ autofill_manager_->StartUploadProcess(std::move(form_structure),
+ base::TimeTicks::Now(), true);
+
+ // Wait for upload to complete (will check expected types as well).
+ autofill_manager_->WaitForAsyncUploadProcess();
+
+ EXPECT_EQ(signature, autofill_manager_->GetSubmittedFormSignature());
+}
+
} // namespace autofill
diff --git a/chromium/components/autofill/core/browser/autofill_metrics.cc b/chromium/components/autofill/core/browser/autofill_metrics.cc
index 239334c5e66..77442395f20 100644
--- a/chromium/components/autofill/core/browser/autofill_metrics.cc
+++ b/chromium/components/autofill/core/browser/autofill_metrics.cc
@@ -5,6 +5,8 @@
#include "components/autofill/core/browser/autofill_metrics.h"
#include <algorithm>
+#include <utility>
+#include <vector>
#include "base/logging.h"
#include "base/metrics/histogram_macros.h"
@@ -12,6 +14,7 @@
#include "base/metrics/user_metrics.h"
#include "base/time/time.h"
#include "components/autofill/core/browser/autofill_experiments.h"
+#include "components/autofill/core/browser/autofill_field.h"
#include "components/autofill/core/browser/autofill_type.h"
#include "components/autofill/core/browser/form_structure.h"
#include "components/autofill/core/common/form_data.h"
@@ -20,6 +23,30 @@
namespace internal {
const char kUKMCardUploadDecisionEntryName[] = "Autofill.CardUploadDecision";
const char kUKMCardUploadDecisionMetricName[] = "UploadDecision";
+const char kUKMDeveloperEngagementEntryName[] = "Autofill.DeveloperEngagement";
+const char kUKMDeveloperEngagementMetricName[] = "DeveloperEngagement";
+const char kUKMMillisecondsSinceFormLoadedMetricName[] =
+ "MillisecondsSinceFormLoaded";
+const char kUKMInteractedWithFormEntryName[] = "Autofill.InteractedWithForm";
+const char kUKMIsForCreditCardMetricName[] = "IsForCreditCard";
+const char kUKMLocalRecordTypeCountMetricName[] = "LocalRecordTypeCount";
+const char kUKMServerRecordTypeCountMetricName[] = "ServerRecordTypeCount";
+const char kUKMSuggestionsShownEntryName[] = "Autofill.SuggestionsShown";
+const char kUKMSelectedMaskedServerCardEntryName[] =
+ "Autofill.SelectedMaskedServerCard";
+const char kUKMSuggestionFilledEntryName[] = "Autofill.SuggestionFilled";
+const char kUKMRecordTypeMetricName[] = "RecordType";
+const char kUKMTextFieldDidChangeEntryName[] = "Autofill.TextFieldDidChange";
+const char kUKMFieldTypeGroupMetricName[] = "FieldTypeGroup";
+const char kUKMHeuristicTypeMetricName[] = "HeuristicType";
+const char kUKMServerTypeMetricName[] = "ServerType";
+const char kUKMHtmlFieldTypeMetricName[] = "HtmlFieldType";
+const char kUKMHtmlFieldModeMetricName[] = "HtmlFieldMode";
+const char kUKMIsAutofilledMetricName[] = "IsAutofilled";
+const char kUKMIsEmptyMetricName[] = "IsEmpty";
+const char kUKMFormSubmittedEntryName[] = "Autofill.AutofillFormSubmitted";
+const char kUKMAutofillFormSubmittedStateMetricName[] =
+ "AutofillFormSubmittedState";
} // namespace internal
namespace autofill {
@@ -614,7 +641,8 @@ void AutofillMetrics::LogProfileActionOnFormSubmitted(
// static
void AutofillMetrics::LogAutofillFormSubmittedState(
- AutofillFormSubmittedState state) {
+ AutofillFormSubmittedState state,
+ AutofillMetrics::FormInteractionsUkmLogger* form_interactions_ukm_logger) {
UMA_HISTOGRAM_ENUMERATION("Autofill.FormSubmittedState", state,
AUTOFILL_FORM_SUBMITTED_STATE_ENUM_SIZE);
@@ -648,6 +676,7 @@ void AutofillMetrics::LogAutofillFormSubmittedState(
NOTREACHED();
break;
}
+ form_interactions_ukm_logger->LogFormSubmitted(state);
}
// static
@@ -704,18 +733,32 @@ void AutofillMetrics::LogCardUploadDecisionUkm(
if (upload_decision >= AutofillMetrics::NUM_CARD_UPLOAD_DECISION_METRICS)
return;
- // Set up as a map because the follow-up CL will add more metrics.
- std::map<std::string, int> metrics = {
+ const std::vector<std::pair<const char*, int>> metrics = {
{internal::kUKMCardUploadDecisionMetricName,
static_cast<int>(upload_decision)}};
LogUkm(ukm_service, url, internal::kUKMCardUploadDecisionEntryName, metrics);
}
// static
-bool AutofillMetrics::LogUkm(ukm::UkmService* ukm_service,
- const GURL& url,
- const std::string& ukm_entry_name,
- const std::map<std::string, int>& metrics) {
+void AutofillMetrics::LogDeveloperEngagementUkm(
+ ukm::UkmService* ukm_service,
+ const GURL& url,
+ std::vector<AutofillMetrics::DeveloperEngagementMetric> metrics) {
+ std::vector<std::pair<const char*, int>> form_structure_metrics;
+ for (const auto it : metrics)
+ form_structure_metrics.push_back(
+ {internal::kUKMDeveloperEngagementMetricName, static_cast<int>(it)});
+
+ LogUkm(ukm_service, url, internal::kUKMDeveloperEngagementEntryName,
+ form_structure_metrics);
+}
+
+// static
+bool AutofillMetrics::LogUkm(
+ ukm::UkmService* ukm_service,
+ const GURL& url,
+ const std::string& ukm_entry_name,
+ const std::vector<std::pair<const char*, int>>& metrics) {
if (!IsUkmLoggingEnabled() || !ukm_service || !url.is_valid() ||
metrics.empty()) {
return false;
@@ -727,16 +770,18 @@ bool AutofillMetrics::LogUkm(ukm::UkmService* ukm_service,
ukm_service->GetEntryBuilder(source_id, ukm_entry_name.c_str());
for (auto it = metrics.begin(); it != metrics.end(); ++it) {
- builder->AddMetric(it->first.c_str(), it->second);
+ builder->AddMetric(it->first, it->second);
}
return true;
}
-AutofillMetrics::FormEventLogger::FormEventLogger(bool is_for_credit_card)
+AutofillMetrics::FormEventLogger::FormEventLogger(
+ bool is_for_credit_card,
+ AutofillMetrics::FormInteractionsUkmLogger* form_interactions_ukm_logger)
: is_for_credit_card_(is_for_credit_card),
- is_server_data_available_(false),
- is_local_data_available_(false),
+ server_record_type_count_(0),
+ local_record_type_count_(0),
is_context_secure_(false),
has_logged_interacted_(false),
has_logged_suggestions_shown_(false),
@@ -745,11 +790,15 @@ AutofillMetrics::FormEventLogger::FormEventLogger(bool is_for_credit_card)
has_logged_will_submit_(false),
has_logged_submitted_(false),
logged_suggestion_filled_was_server_data_(false),
- logged_suggestion_filled_was_masked_server_card_(false) {}
+ logged_suggestion_filled_was_masked_server_card_(false),
+ form_interactions_ukm_logger_(form_interactions_ukm_logger) {}
void AutofillMetrics::FormEventLogger::OnDidInteractWithAutofillableForm() {
if (!has_logged_interacted_) {
has_logged_interacted_ = true;
+ form_interactions_ukm_logger_->LogInteractedWithForm(
+ is_for_credit_card_, local_record_type_count_,
+ server_record_type_count_);
Log(AutofillMetrics::FORM_EVENT_INTERACTED_ONCE);
}
}
@@ -774,6 +823,8 @@ void AutofillMetrics::FormEventLogger::OnDidPollSuggestions(
}
void AutofillMetrics::FormEventLogger::OnDidShowSuggestions() {
+ form_interactions_ukm_logger_->LogSuggestionsShown();
+
Log(AutofillMetrics::FORM_EVENT_SUGGESTIONS_SHOWN);
if (!has_logged_suggestions_shown_) {
has_logged_suggestions_shown_ = true;
@@ -791,17 +842,22 @@ void AutofillMetrics::FormEventLogger::OnDidShowSuggestions() {
void AutofillMetrics::FormEventLogger::OnDidSelectMaskedServerCardSuggestion() {
DCHECK(is_for_credit_card_);
+ form_interactions_ukm_logger_->LogSelectedMaskedServerCard();
+
Log(AutofillMetrics::FORM_EVENT_MASKED_SERVER_CARD_SUGGESTION_SELECTED);
if (!has_logged_masked_server_card_suggestion_selected_) {
has_logged_masked_server_card_suggestion_selected_ = true;
- Log(AutofillMetrics
- ::FORM_EVENT_MASKED_SERVER_CARD_SUGGESTION_SELECTED_ONCE);
+ Log(AutofillMetrics::
+ FORM_EVENT_MASKED_SERVER_CARD_SUGGESTION_SELECTED_ONCE);
}
}
void AutofillMetrics::FormEventLogger::OnDidFillSuggestion(
const CreditCard& credit_card) {
DCHECK(is_for_credit_card_);
+ form_interactions_ukm_logger_->LogDidFillSuggestion(
+ static_cast<int>(credit_card.record_type()));
+
if (credit_card.record_type() == CreditCard::MASKED_SERVER_CARD)
Log(AutofillMetrics::FORM_EVENT_MASKED_SERVER_CARD_SUGGESTION_FILLED);
else if (credit_card.record_type() == CreditCard::FULL_SERVER_CARD)
@@ -817,8 +873,8 @@ void AutofillMetrics::FormEventLogger::OnDidFillSuggestion(
logged_suggestion_filled_was_masked_server_card_ =
credit_card.record_type() == CreditCard::MASKED_SERVER_CARD;
if (credit_card.record_type() == CreditCard::MASKED_SERVER_CARD) {
- Log(AutofillMetrics
- ::FORM_EVENT_MASKED_SERVER_CARD_SUGGESTION_FILLED_ONCE);
+ Log(AutofillMetrics::
+ FORM_EVENT_MASKED_SERVER_CARD_SUGGESTION_FILLED_ONCE);
} else if (credit_card.record_type() == CreditCard::FULL_SERVER_CARD) {
Log(AutofillMetrics::FORM_EVENT_SERVER_SUGGESTION_FILLED_ONCE);
} else {
@@ -833,6 +889,9 @@ void AutofillMetrics::FormEventLogger::OnDidFillSuggestion(
void AutofillMetrics::FormEventLogger::OnDidFillSuggestion(
const AutofillProfile& profile) {
DCHECK(!is_for_credit_card_);
+ form_interactions_ukm_logger_->LogDidFillSuggestion(
+ static_cast<int>(profile.record_type()));
+
if (profile.record_type() == AutofillProfile::SERVER_PROFILE)
Log(AutofillMetrics::FORM_EVENT_SERVER_SUGGESTION_FILLED);
else
@@ -843,8 +902,8 @@ void AutofillMetrics::FormEventLogger::OnDidFillSuggestion(
logged_suggestion_filled_was_server_data_ =
profile.record_type() == AutofillProfile::SERVER_PROFILE;
Log(profile.record_type() == AutofillProfile::SERVER_PROFILE
- ? AutofillMetrics::FORM_EVENT_SERVER_SUGGESTION_FILLED_ONCE
- : AutofillMetrics::FORM_EVENT_LOCAL_SUGGESTION_FILLED_ONCE);
+ ? AutofillMetrics::FORM_EVENT_SERVER_SUGGESTION_FILLED_ONCE
+ : AutofillMetrics::FORM_EVENT_LOCAL_SUGGESTION_FILLED_ONCE);
}
base::RecordAction(
@@ -892,8 +951,8 @@ void AutofillMetrics::FormEventLogger::OnFormSubmitted() {
if (!has_logged_suggestion_filled_) {
Log(AutofillMetrics::FORM_EVENT_NO_SUGGESTION_SUBMITTED_ONCE);
} else if (logged_suggestion_filled_was_masked_server_card_) {
- Log(AutofillMetrics
- ::FORM_EVENT_MASKED_SERVER_CARD_SUGGESTION_SUBMITTED_ONCE);
+ Log(AutofillMetrics::
+ FORM_EVENT_MASKED_SERVER_CARD_SUGGESTION_SUBMITTED_ONCE);
} else if (logged_suggestion_filled_was_server_data_) {
Log(AutofillMetrics::FORM_EVENT_SERVER_SUGGESTION_SUBMITTED_ONCE);
} else {
@@ -925,15 +984,154 @@ void AutofillMetrics::FormEventLogger::Log(FormEvent event) const {
// Logging again in a different histogram for segmentation purposes.
// TODO(waltercacau): Re-evaluate if we still need such fine grained
// segmentation. http://crbug.com/454018
- if (!is_server_data_available_ && !is_local_data_available_)
+ if (server_record_type_count_ == 0 && local_record_type_count_ == 0)
name += ".WithNoData";
- else if (is_server_data_available_ && !is_local_data_available_)
+ else if (server_record_type_count_ > 0 && local_record_type_count_ == 0)
name += ".WithOnlyServerData";
- else if (!is_server_data_available_ && is_local_data_available_)
+ else if (server_record_type_count_ == 0 && local_record_type_count_ > 0)
name += ".WithOnlyLocalData";
else
name += ".WithBothServerAndLocalData";
LogUMAHistogramEnumeration(name, event, NUM_FORM_EVENTS);
}
+AutofillMetrics::FormInteractionsUkmLogger::FormInteractionsUkmLogger(
+ ukm::UkmService* ukm_service)
+ : ukm_service_(ukm_service) {}
+
+void AutofillMetrics::FormInteractionsUkmLogger::OnFormsLoaded(
+ const GURL& url) {
+ if (!IsUkmLoggingEnabled() || ukm_service_ == nullptr)
+ return;
+
+ url_ = url;
+ form_loaded_timestamp_ = base::TimeTicks::Now();
+}
+
+void AutofillMetrics::FormInteractionsUkmLogger::LogInteractedWithForm(
+ bool is_for_credit_card,
+ size_t local_record_type_count,
+ size_t server_record_type_count) {
+ if (!CanLog())
+ return;
+
+ if (source_id_ == -1)
+ GetNewSourceID();
+
+ std::unique_ptr<ukm::UkmEntryBuilder> builder = ukm_service_->GetEntryBuilder(
+ source_id_, internal::kUKMInteractedWithFormEntryName);
+ builder->AddMetric(internal::kUKMIsForCreditCardMetricName,
+ is_for_credit_card);
+ builder->AddMetric(internal::kUKMLocalRecordTypeCountMetricName,
+ local_record_type_count);
+ builder->AddMetric(internal::kUKMServerRecordTypeCountMetricName,
+ server_record_type_count);
+}
+
+void AutofillMetrics::FormInteractionsUkmLogger::LogSuggestionsShown() {
+ if (!CanLog())
+ return;
+
+ if (source_id_ == -1)
+ GetNewSourceID();
+
+ std::unique_ptr<ukm::UkmEntryBuilder> builder = ukm_service_->GetEntryBuilder(
+ source_id_, internal::kUKMSuggestionsShownEntryName);
+ builder->AddMetric(internal::kUKMMillisecondsSinceFormLoadedMetricName,
+ MillisecondsSinceFormLoaded());
+}
+
+void AutofillMetrics::FormInteractionsUkmLogger::LogSelectedMaskedServerCard() {
+ if (!CanLog())
+ return;
+
+ if (source_id_ == -1)
+ GetNewSourceID();
+
+ std::unique_ptr<ukm::UkmEntryBuilder> builder = ukm_service_->GetEntryBuilder(
+ source_id_, internal::kUKMSelectedMaskedServerCardEntryName);
+ builder->AddMetric(internal::kUKMMillisecondsSinceFormLoadedMetricName,
+ MillisecondsSinceFormLoaded());
+}
+
+void AutofillMetrics::FormInteractionsUkmLogger::LogDidFillSuggestion(
+ int record_type) {
+ if (!CanLog())
+ return;
+
+ if (source_id_ == -1)
+ GetNewSourceID();
+
+ std::unique_ptr<ukm::UkmEntryBuilder> builder = ukm_service_->GetEntryBuilder(
+ source_id_, internal::kUKMSuggestionFilledEntryName);
+ builder->AddMetric(internal::kUKMRecordTypeMetricName, record_type);
+ builder->AddMetric(internal::kUKMMillisecondsSinceFormLoadedMetricName,
+ MillisecondsSinceFormLoaded());
+}
+
+void AutofillMetrics::FormInteractionsUkmLogger::LogTextFieldDidChange(
+ const AutofillField& field) {
+ if (!CanLog())
+ return;
+
+ if (source_id_ == -1)
+ GetNewSourceID();
+
+ std::unique_ptr<ukm::UkmEntryBuilder> builder = ukm_service_->GetEntryBuilder(
+ source_id_, internal::kUKMTextFieldDidChangeEntryName);
+ builder->AddMetric(internal::kUKMFieldTypeGroupMetricName,
+ static_cast<int>(field.Type().group()));
+ builder->AddMetric(internal::kUKMHeuristicTypeMetricName,
+ static_cast<int>(field.heuristic_type()));
+ builder->AddMetric(internal::kUKMServerTypeMetricName,
+ static_cast<int>(field.server_type()));
+ builder->AddMetric(internal::kUKMHtmlFieldTypeMetricName,
+ static_cast<int>(field.html_type()));
+ builder->AddMetric(internal::kUKMHtmlFieldModeMetricName,
+ static_cast<int>(field.html_mode()));
+ builder->AddMetric(internal::kUKMIsAutofilledMetricName, field.is_autofilled);
+ builder->AddMetric(internal::kUKMIsEmptyMetricName, field.IsEmpty());
+ builder->AddMetric(internal::kUKMMillisecondsSinceFormLoadedMetricName,
+ MillisecondsSinceFormLoaded());
+}
+
+void AutofillMetrics::FormInteractionsUkmLogger::LogFormSubmitted(
+ AutofillFormSubmittedState state) {
+ if (!CanLog())
+ return;
+
+ if (source_id_ == -1)
+ GetNewSourceID();
+
+ std::unique_ptr<ukm::UkmEntryBuilder> builder = ukm_service_->GetEntryBuilder(
+ source_id_, internal::kUKMFormSubmittedEntryName);
+ builder->AddMetric(internal::kUKMAutofillFormSubmittedStateMetricName,
+ static_cast<int>(state));
+ builder->AddMetric(internal::kUKMMillisecondsSinceFormLoadedMetricName,
+ MillisecondsSinceFormLoaded());
+}
+
+void AutofillMetrics::FormInteractionsUkmLogger::UpdateSourceURL(
+ const GURL& url) {
+ url_ = url;
+ if (CanLog())
+ ukm_service_->UpdateSourceURL(source_id_, url_);
+}
+
+bool AutofillMetrics::FormInteractionsUkmLogger::CanLog() const {
+ return IsUkmLoggingEnabled() && ukm_service_ && url_.is_valid();
+}
+
+int64_t
+AutofillMetrics::FormInteractionsUkmLogger::MillisecondsSinceFormLoaded()
+ const {
+ DCHECK(!form_loaded_timestamp_.is_null());
+ return (base::TimeTicks::Now() - form_loaded_timestamp_).InMilliseconds();
+}
+
+void AutofillMetrics::FormInteractionsUkmLogger::GetNewSourceID() {
+ source_id_ = ukm_service_->GetNewSourceID();
+ ukm_service_->UpdateSourceURL(source_id_, url_);
+}
+
} // namespace autofill
diff --git a/chromium/components/autofill/core/browser/autofill_metrics.h b/chromium/components/autofill/core/browser/autofill_metrics.h
index d0aba8221f6..58ab8d26aa0 100644
--- a/chromium/components/autofill/core/browser/autofill_metrics.h
+++ b/chromium/components/autofill/core/browser/autofill_metrics.h
@@ -7,18 +7,17 @@
#include <stddef.h>
#include <string>
+#include <utility>
+#include <vector>
#include "base/macros.h"
+#include "base/time/time.h"
#include "components/autofill/core/browser/autofill_client.h"
#include "components/autofill/core/browser/autofill_profile.h"
#include "components/autofill/core/browser/credit_card.h"
#include "components/autofill/core/browser/field_types.h"
#include "components/autofill/core/common/form_field_data.h"
-namespace base {
-class TimeDelta;
-} // namespace base
-
namespace ukm {
class UkmService;
} // namespace ukm
@@ -27,10 +26,55 @@ namespace internal {
// Name constants are exposed here so they can be referenced from tests.
extern const char kUKMCardUploadDecisionEntryName[];
extern const char kUKMCardUploadDecisionMetricName[];
+extern const char kUKMDeveloperEngagementEntryName[];
+extern const char kUKMDeveloperEngagementMetricName[];
+
+// Each form interaction event has a separate |UkmEntry|.
+
+// The first form event |UkmEntry| contains metrics for metadata that apply
+// to all subsequent events.
+extern const char kUKMInteractedWithFormEntryName[];
+extern const char kUKMIsForCreditCardMetricName[];
+extern const char kUKMLocalRecordTypeCountMetricName[];
+extern const char kUKMServerRecordTypeCountMetricName[];
+
+// |UkmEntry| when we show suggestions.
+extern const char kUKMSuggestionsShownEntryName[];
+
+// |UkmEntry| when user selects a masked server credit card.
+extern const char kUKMSelectedMaskedServerCardEntryName[];
+
+// Each |UkmEntry|, except the first interaction with the form, has a metric for
+// time elapsed, in milliseconds, since we loaded the form.
+extern const char kUKMMillisecondsSinceFormLoadedMetricName[];
+
+// |FormEvent| for FORM_EVENT_*_SUGGESTION_FILLED in credit card forms include a
+// |CreditCard| |record_type()| to indicate if the suggestion was for a local
+// card, masked server card or full server card. Similarly, address/profile
+// forms include a |AutofillProfile| |record_type()| to indicate if the
+// profile was a local profile or server profile.
+extern const char kUKMSuggestionFilledEntryName[];
+extern const char kUKMRecordTypeMetricName[];
+
+// |UkmEntry| for user editing text field. Metrics contain field's attributes.
+extern const char kUKMTextFieldDidChangeEntryName[];
+extern const char kUKMFieldTypeGroupMetricName[];
+extern const char kUKMHeuristicTypeMetricName[];
+extern const char kUKMServerTypeMetricName[];
+extern const char kUKMHtmlFieldTypeMetricName[];
+extern const char kUKMHtmlFieldModeMetricName[];
+extern const char kUKMIsAutofilledMetricName[];
+extern const char kUKMIsEmptyMetricName[];
+
+// |UkmEntry| for |AutofillFormSubmittedState|.
+extern const char kUKMFormSubmittedEntryName[];
+extern const char kUKMAutofillFormSubmittedStateMetricName[];
} // namespace internal
namespace autofill {
+class AutofillField;
+
class AutofillMetrics {
public:
enum AutofillProfileAction {
@@ -80,16 +124,23 @@ class AutofillMetrics {
// were otherwise valid nor whether we would have been able to get upload
// details.
UPLOAD_NOT_OFFERED_CONFLICTING_NAMES,
+ // No CVC was detected, but valid addresses and names were. Upload is still
+ // possible if the user manually enters CVC, so upload was offered.
+ UPLOAD_OFFERED_NO_CVC,
NUM_CARD_UPLOAD_DECISION_METRICS,
};
enum DeveloperEngagementMetric {
- // Parsed a form that is potentially autofillable.
- FILLABLE_FORM_PARSED = 0,
+ // Parsed a form that is potentially autofillable and does not contain any
+ // web developer-specified field type hint.
+ FILLABLE_FORM_PARSED_WITHOUT_TYPE_HINTS = 0,
// Parsed a form that is potentially autofillable and contains at least one
// web developer-specified field type hint, a la
// http://is.gd/whatwg_autocomplete
- FILLABLE_FORM_CONTAINS_TYPE_HINTS,
+ FILLABLE_FORM_PARSED_WITH_TYPE_HINTS,
+ // Parsed a form that is potentially autofillable and contains at least one
+ // UPI Virtual Payment Address hint (upi-vpa)
+ FORM_CONTAINS_UPI_VPA_HINT,
NUM_DEVELOPER_ENGAGEMENT_METRICS,
};
@@ -256,6 +307,7 @@ class AutofillMetrics {
SAVE_CARD_PROMPT_DISMISS_CLICK_LEARN_MORE,
// The prompt was dismissed because the user clicked a legal message link.
SAVE_CARD_PROMPT_DISMISS_CLICK_LEGAL_MESSAGE,
+
NUM_SAVE_CARD_PROMPT_METRICS,
};
@@ -264,9 +316,27 @@ class AutofillMetrics {
// the heuristic prediction, for the crowd-sourced prediction, and for the
// overall prediction.
enum FieldTypeQualityMetric {
- TYPE_UNKNOWN = 0, // Offered no prediction.
- TYPE_MATCH, // Predicted correctly.
- TYPE_MISMATCH, // Predicted incorrectly.
+ // The field was found to be of type T, but autofill made no prediction.
+ TYPE_UNKNOWN = 0,
+ // The field was found to be of type T, which matches the predicted type.
+ TYPE_MATCH,
+ // The field was found to be of type T, autofill predicted some other type.
+ TYPE_MISMATCH,
+ // The field was left empty and autofil predicted that the field type would
+ // be UNKNOWN.
+ TYPE_MATCH_EMPTY,
+ // The field was populated with data that did not match any part of the
+ // user's profile (it's type could not be determined). Autofill predicted
+ // the field's type would be UNKNOWN.
+ TYPE_MATCH_UNKNOWN,
+ // The field was left empty, autofill predicted the user would populate it
+ // with autofillable data.
+ TYPE_MISMATCH_EMPTY,
+ // The field was populated with data that did not match any part of the
+ // user's profile (it's type could not be determined). Autofill predicted
+ // the user would populate it with autofillable data.
+ TYPE_MISMATCH_UNKNOWN,
+ // This must be the last value.
NUM_FIELD_TYPE_QUALITY_METRICS,
};
@@ -345,6 +415,10 @@ class AutofillMetrics {
USER_DID_EDIT_AUTOFILLED_FIELD,
// Same as above, but only logged once per page load.
USER_DID_EDIT_AUTOFILLED_FIELD_ONCE,
+
+ // User entered form data that appears to be a UPI Virtual Payment Address.
+ USER_DID_ENTER_UPI_VPA,
+
NUM_USER_HAPPINESS_METRICS,
};
@@ -537,6 +611,39 @@ class AutofillMetrics {
NUM_CONVERTED_ADDRESS_CONVERSION_TYPES
};
+ // Utility to log URL keyed form interaction events.
+ class FormInteractionsUkmLogger {
+ public:
+ explicit FormInteractionsUkmLogger(ukm::UkmService* ukm_service);
+
+ const GURL& url() const { return url_; }
+
+ void OnFormsLoaded(const GURL& url);
+ void LogInteractedWithForm(bool is_for_credit_card,
+ size_t local_record_type_count,
+ size_t server_record_type_count);
+ void LogSuggestionsShown();
+ void LogSelectedMaskedServerCard();
+ void LogDidFillSuggestion(int record_type);
+ void LogTextFieldDidChange(const AutofillField& field);
+ void LogFormSubmitted(AutofillFormSubmittedState state);
+
+ // We initialize |url_| with the form's URL when we log the first form
+ // interaction. Later, we may update |url_| with the |source_url()| for the
+ // submitted form.
+ void UpdateSourceURL(const GURL& url);
+
+ private:
+ bool CanLog() const;
+ int64_t MillisecondsSinceFormLoaded() const;
+ void GetNewSourceID();
+
+ ukm::UkmService* ukm_service_; // Weak reference.
+ int32_t source_id_ = -1;
+ GURL url_;
+ base::TimeTicks form_loaded_timestamp_;
+ };
+
static void LogCardUploadDecisionMetric(CardUploadDecisionMetric metric);
static void LogCreditCardInfoBarMetric(InfoBarMetric metric,
bool is_uploading);
@@ -663,7 +770,9 @@ class AutofillMetrics {
// This should be called at each form submission to indicate the autofilled
// state of the form.
- static void LogAutofillFormSubmittedState(AutofillFormSubmittedState state);
+ static void LogAutofillFormSubmittedState(
+ AutofillFormSubmittedState state,
+ FormInteractionsUkmLogger* form_interactions_ukm_logger);
// This should be called when determining the heuristic types for a form's
// fields.
@@ -697,25 +806,33 @@ class AutofillMetrics {
const GURL& url,
AutofillMetrics::CardUploadDecisionMetric upload_decision);
+ // Logs the developer engagement ukm for the specified |url| and autofill
+ // fields in the form structure.
+ static void LogDeveloperEngagementUkm(
+ ukm::UkmService* ukm_service,
+ const GURL& url,
+ std::vector<AutofillMetrics::DeveloperEngagementMetric> metrics);
+
// Logs the the |ukm_entry_name| with the specified |url| and the specified
// |metrics|. Returns whether the ukm was sucessfully logged.
static bool LogUkm(ukm::UkmService* ukm_service,
const GURL& url,
const std::string& ukm_entry_name,
- const std::map<std::string, int>& metrics);
+ const std::vector<std::pair<const char*, int>>& metrics);
- // Utility to autofill form events in the relevant histograms depending on
+ // Utility to log autofill form events in the relevant histograms depending on
// the presence of server and/or local data.
class FormEventLogger {
public:
- FormEventLogger(bool is_for_credit_card);
+ FormEventLogger(bool is_for_credit_card,
+ FormInteractionsUkmLogger* form_interactions_ukm_logger);
- inline void set_is_server_data_available(bool is_server_data_available) {
- is_server_data_available_ = is_server_data_available;
+ inline void set_server_record_type_count(size_t server_record_type_count) {
+ server_record_type_count_ = server_record_type_count;
}
- inline void set_is_local_data_available(bool is_local_data_available) {
- is_local_data_available_ = is_local_data_available;
+ inline void set_local_record_type_count(size_t local_record_type_count) {
+ local_record_type_count_ = local_record_type_count;
}
inline void set_is_context_secure(bool is_context_secure) {
@@ -744,8 +861,8 @@ class AutofillMetrics {
void Log(FormEvent event) const;
bool is_for_credit_card_;
- bool is_server_data_available_;
- bool is_local_data_available_;
+ size_t server_record_type_count_;
+ size_t local_record_type_count_;
bool is_context_secure_;
bool has_logged_interacted_;
bool has_logged_suggestions_shown_;
@@ -758,6 +875,9 @@ class AutofillMetrics {
// The last field that was polled for suggestions.
FormFieldData last_polled_field_;
+
+ FormInteractionsUkmLogger*
+ form_interactions_ukm_logger_; // Weak reference.
};
private:
diff --git a/chromium/components/autofill/core/browser/autofill_metrics_unittest.cc b/chromium/components/autofill/core/browser/autofill_metrics_unittest.cc
index 36039f5f382..3372ee37884 100644
--- a/chromium/components/autofill/core/browser/autofill_metrics_unittest.cc
+++ b/chromium/components/autofill/core/browser/autofill_metrics_unittest.cc
@@ -6,8 +6,8 @@
#include <stddef.h>
-#include <map>
#include <memory>
+#include <utility>
#include <vector>
#include "base/feature_list.h"
@@ -19,6 +19,7 @@
#include "base/strings/utf_string_conversions.h"
#include "base/test/histogram_tester.h"
#include "base/test/scoped_feature_list.h"
+#include "base/test/scoped_task_environment.h"
#include "base/test/user_action_tester.h"
#include "base/time/time.h"
#include "components/autofill/core/browser/autofill_experiments.h"
@@ -54,6 +55,8 @@ using base::Bucket;
using base::TimeTicks;
using rappor::TestRapporServiceImpl;
using ::testing::ElementsAre;
+using ::testing::Matcher;
+using ::testing::UnorderedPointwise;
namespace autofill {
namespace {
@@ -263,6 +266,8 @@ class TestAutofillManager : public AutofillManager {
base::MakeUnique<TestFormStructure>(empty_form);
form_structure->SetFieldTypes(heuristic_types, server_types);
form_structures()->push_back(std::move(form_structure));
+
+ form_interactions_ukm_logger()->OnFormsLoaded(form.origin);
}
// Calls AutofillManager::OnWillSubmitForm and waits for it to complete.
@@ -287,9 +292,9 @@ class TestAutofillManager : public AutofillManager {
void RunRunLoop() { run_loop_->Run(); }
void UploadFormDataAsyncCallback(const FormStructure* submitted_form,
- const base::TimeTicks& load_time,
- const base::TimeTicks& interaction_time,
- const base::TimeTicks& submission_time,
+ const TimeTicks& load_time,
+ const TimeTicks& interaction_time,
+ const TimeTicks& submission_time,
bool observed_submission) override {
run_loop_->Quit();
@@ -316,6 +321,83 @@ const ukm::Entry_Metric* FindMetric(
return nullptr;
}
+MATCHER(CompareMetrics, "") {
+ const ukm::Entry_Metric& lhs = ::testing::get<0>(arg);
+ const std::pair<const char*, int64_t>& rhs = ::testing::get<1>(arg);
+ return lhs.metric_hash() == base::HashMetricName(rhs.first) &&
+ lhs.value() == rhs.second;
+}
+
+void VerifyDeveloperEngagementUkm(
+ const FormData& form,
+ const ukm::TestUkmService* ukm_service,
+ const std::vector<int64_t>& expected_metric_values) {
+ const ukm::UkmEntry* entry = ukm_service->GetEntryForEntryName(
+ internal::kUKMDeveloperEngagementEntryName);
+ ASSERT_NE(nullptr, entry);
+ ukm::Entry entry_proto;
+ entry->PopulateProto(&entry_proto);
+
+ const ukm::UkmSource* source =
+ ukm_service->GetSourceForSourceId(entry_proto.source_id());
+ ASSERT_NE(nullptr, source);
+ EXPECT_EQ(form.origin, source->url());
+
+ std::vector<std::pair<const char*, int64_t>> expected_metrics;
+ for (const auto it : expected_metric_values)
+ expected_metrics.push_back(
+ {internal::kUKMDeveloperEngagementMetricName, it});
+
+ EXPECT_THAT(entry_proto.metrics(),
+ UnorderedPointwise(CompareMetrics(), expected_metrics));
+}
+
+MATCHER(CompareMetricsIgnoringMillisecondsSinceFormLoaded, "") {
+ const ukm::Entry_Metric& lhs = ::testing::get<0>(arg);
+ const std::pair<const char*, int64_t>& rhs = ::testing::get<1>(arg);
+ return lhs.metric_hash() == base::HashMetricName(rhs.first) &&
+ (lhs.value() == rhs.second ||
+ (lhs.value() > 0 &&
+ rhs.first == internal::kUKMMillisecondsSinceFormLoadedMetricName));
+}
+
+void VerifyFormInteractionUkm(
+ const FormData& form,
+ const ukm::TestUkmService* ukm_service,
+ const char* event_name,
+ const std::vector<std::vector<std::pair<const char*, int64_t>>>&
+ expected_metrics) {
+ size_t expected_metrics_index = 0;
+ for (size_t i = 0; i < ukm_service->entries_count(); ++i) {
+ const ukm::UkmEntry* entry = ukm_service->GetEntry(i);
+ if (entry->event_hash() != base::HashMetricName(event_name))
+ continue;
+
+ ukm::Entry entry_proto;
+ entry->PopulateProto(&entry_proto);
+
+ const ukm::UkmSource* source =
+ ukm_service->GetSourceForSourceId(entry_proto.source_id());
+ ASSERT_NE(nullptr, source);
+ EXPECT_EQ(form.origin, source->url());
+
+ ASSERT_LT(expected_metrics_index, expected_metrics.size());
+ EXPECT_THAT(
+ entry_proto.metrics(),
+ UnorderedPointwise(CompareMetricsIgnoringMillisecondsSinceFormLoaded(),
+ expected_metrics[expected_metrics_index++]));
+ }
+}
+
+void VerifySubmitFormUkm(const FormData& form,
+ const ukm::TestUkmService* ukm_service,
+ AutofillMetrics::AutofillFormSubmittedState state) {
+ VerifyFormInteractionUkm(
+ form, ukm_service, internal::kUKMFormSubmittedEntryName,
+ {{{internal::kUKMAutofillFormSubmittedStateMetricName, state},
+ {internal::kUKMMillisecondsSinceFormLoadedMetricName, 0}}});
+}
+
} // namespace
// This is defined in the autofill_metrics.cc implementation file.
@@ -333,7 +415,7 @@ class AutofillMetricsTest : public testing::Test {
void EnableWalletSync();
void EnableUkmLogging();
- base::MessageLoop message_loop_;
+ base::test::ScopedTaskEnvironment scoped_task_environment_;
TestAutofillClient autofill_client_;
std::unique_ptr<AccountTrackerService> account_tracker_;
std::unique_ptr<FakeSigninManagerBase> signin_manager_;
@@ -393,6 +475,7 @@ void AutofillMetricsTest::TearDown() {
account_tracker_.reset();
signin_client_.reset();
test::ReenableSystemServices();
+ autofill_client_.GetTestUkmService()->Purge();
}
void AutofillMetricsTest::EnableWalletSync() {
@@ -542,6 +625,129 @@ TEST_F(AutofillMetricsTest, QualityMetrics) {
GetFieldTypeGroupMetric(NAME_FULL, AutofillMetrics::TYPE_MISMATCH), 1);
}
+// Tests the true negatives (empty + no prediction and unknown + no prediction)
+// and false positives (empty + bad prediction and unknown + bad prediction)
+// are counted correctly.
+
+struct UnrecognizedOrEmptyFieldsCase {
+ const ServerFieldType actual_field_type;
+ const bool make_prediction;
+ const AutofillMetrics::FieldTypeQualityMetric metric_to_test;
+};
+
+class UnrecognizedOrEmptyFieldsTest
+ : public AutofillMetricsTest,
+ public testing::WithParamInterface<UnrecognizedOrEmptyFieldsCase> {};
+
+TEST_P(UnrecognizedOrEmptyFieldsTest, QualityMetrics) {
+ // Setup the test parameters.
+ const ServerFieldType actual_field_type = GetParam().actual_field_type;
+ const ServerFieldType heuristic_type =
+ GetParam().make_prediction ? EMAIL_ADDRESS : UNKNOWN_TYPE;
+ const ServerFieldType server_type =
+ GetParam().make_prediction ? EMAIL_ADDRESS : NO_SERVER_DATA;
+ const AutofillMetrics::FieldTypeQualityMetric metric_to_test =
+ GetParam().metric_to_test;
+
+ // Set up our form data.
+ FormData form;
+ form.name = ASCIIToUTF16("TestForm");
+ form.origin = GURL("http://example.com/form.html");
+ form.action = GURL("http://example.com/submit.html");
+
+ std::vector<ServerFieldType> heuristic_types, server_types;
+ AutofillField field;
+
+ // Add a first name field, that is predicted correctly.
+ test::CreateTestFormField("first", "first", "Elvis", "text", &field);
+ field.set_possible_types({NAME_FIRST});
+ form.fields.push_back(field);
+ heuristic_types.push_back(NAME_FIRST);
+ server_types.push_back(NAME_FIRST);
+
+ // Add a last name field, that is predicted correctly.
+ test::CreateTestFormField("last", "last", "Presley", "test", &field);
+ field.set_possible_types({NAME_LAST});
+ form.fields.push_back(field);
+ heuristic_types.push_back(NAME_LAST);
+ server_types.push_back(NAME_LAST);
+
+ // Add an empty or unknown field, that is predicted as per the test params.
+ test::CreateTestFormField("Unknown", "Unknown",
+ (actual_field_type == EMPTY_TYPE ? "" : "unknown"),
+ "text", &field);
+ field.set_possible_types({actual_field_type});
+ form.fields.push_back(field);
+ heuristic_types.push_back(heuristic_type);
+ server_types.push_back(server_type);
+
+ // Simulate having seen this form on page load.
+ autofill_manager_->AddSeenForm(form, heuristic_types, server_types);
+
+ // Run the form submission code while tracking the histograms.
+ base::HistogramTester histogram_tester;
+ autofill_manager_->SubmitForm(form, TimeTicks::Now());
+
+ // Validate the histogram counter values.
+ for (int i = 0; i < AutofillMetrics::NUM_FIELD_TYPE_QUALITY_METRICS; ++i) {
+ // The metric enum value we're currently examining.
+ auto metric = static_cast<AutofillMetrics::FieldTypeQualityMetric>(i);
+
+ // For the overall metric counts...
+ // If the current metric is the metric we're testing, then we expect its
+ // count to be 1. Otherwise, the metric's count should be zero (0) except
+ // for the TYPE_MATCH metric which should be 2 (because of the matching
+ // first and last name fields)
+ int overall_expected_count =
+ (metric == metric_to_test)
+ ? 1
+ : ((metric == AutofillMetrics::TYPE_MATCH) ? 2 : 0);
+
+ histogram_tester.ExpectBucketCount("Autofill.Quality.HeuristicType", metric,
+ overall_expected_count);
+ histogram_tester.ExpectBucketCount("Autofill.Quality.ServerType", metric,
+ overall_expected_count);
+ histogram_tester.ExpectBucketCount("Autofill.Quality.PredictedType", metric,
+ overall_expected_count);
+
+ // For the ByFieldType metric counts...
+ // We only examine the counter for the field_type being tested. If the
+ // current metric is the metric we're testing, then we expect its
+ // count to be 1 otherwise it should be 0.
+ int field_type_expected_count = (metric == metric_to_test) ? 1 : 0;
+
+ histogram_tester.ExpectBucketCount(
+ "Autofill.Quality.HeuristicType.ByFieldType",
+ GetFieldTypeGroupMetric(actual_field_type, metric),
+ field_type_expected_count);
+ histogram_tester.ExpectBucketCount(
+ "Autofill.Quality.ServerType.ByFieldType",
+ GetFieldTypeGroupMetric(actual_field_type, metric),
+ field_type_expected_count);
+ histogram_tester.ExpectBucketCount(
+ "Autofill.Quality.PredictedType.ByFieldType",
+ GetFieldTypeGroupMetric(actual_field_type, metric),
+ field_type_expected_count);
+ }
+}
+
+INSTANTIATE_TEST_CASE_P(
+ AutofillMetricsTest,
+ UnrecognizedOrEmptyFieldsTest,
+ testing::Values(
+ UnrecognizedOrEmptyFieldsCase{EMPTY_TYPE,
+ /* make_prediction = */ false,
+ AutofillMetrics::TYPE_MATCH_EMPTY},
+ UnrecognizedOrEmptyFieldsCase{UNKNOWN_TYPE,
+ /* make_prediction = */ false,
+ AutofillMetrics::TYPE_MATCH_UNKNOWN},
+ UnrecognizedOrEmptyFieldsCase{EMPTY_TYPE,
+ /* make_prediction = */ true,
+ AutofillMetrics::TYPE_MISMATCH_EMPTY},
+ UnrecognizedOrEmptyFieldsCase{UNKNOWN_TYPE,
+ /* make_prediction = */ true,
+ AutofillMetrics::TYPE_MISMATCH_UNKNOWN}));
+
// Ensures that metrics that measure timing some important Autofill functions
// actually are recorded and retrieved.
TEST_F(AutofillMetricsTest, TimingMetrics) {
@@ -570,7 +776,7 @@ TEST_F(AutofillMetricsTest, TimingMetrics) {
// Simulate a OnFormsSeen() call that should trigger the recording.
std::vector<FormData> forms;
forms.push_back(form);
- autofill_manager_->OnFormsSeen(forms, base::TimeTicks::Now());
+ autofill_manager_->OnFormsSeen(forms, TimeTicks::Now());
// 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
@@ -766,7 +972,7 @@ TEST_F(AutofillMetricsTest, QualityMetrics_BasedOnAutocomplete) {
std::unique_ptr<TestFormStructure> form_structure =
base::MakeUnique<TestFormStructure>(form);
TestFormStructure* form_structure_ptr = form_structure.get();
- form_structure->DetermineHeuristicTypes();
+ form_structure->DetermineHeuristicTypes(nullptr /* ukm_service */);
autofill_manager_->form_structures()->push_back(std::move(form_structure));
AutofillQueryResponseContents response;
@@ -851,6 +1057,47 @@ TEST_F(AutofillMetricsTest, QualityMetrics_BasedOnAutocomplete) {
GetFieldTypeGroupMetric(NAME_MIDDLE, AutofillMetrics::TYPE_MISMATCH), 1);
}
+// Test that we log UPI Virtual Payment Address.
+TEST_F(AutofillMetricsTest, UpiVirtualPaymentAddress) {
+ // Set up our form data.
+ FormData form;
+ form.name = ASCIIToUTF16("TestForm");
+ form.origin = GURL("http://example.com/form.html");
+ form.action = GURL("http://example.com/submit.html");
+
+ std::vector<ServerFieldType> heuristic_types, server_types;
+ FormFieldData field;
+
+ // Heuristic value will match with Autocomplete attribute.
+ test::CreateTestFormField("Last Name", "lastname", "", "text", &field);
+ form.fields.push_back(field);
+ heuristic_types.push_back(NAME_LAST);
+ server_types.push_back(NAME_LAST);
+
+ // Heuristic value will NOT match with Autocomplete attribute.
+ test::CreateTestFormField("First Name", "firstname", "", "text", &field);
+ form.fields.push_back(field);
+ heuristic_types.push_back(NAME_FIRST);
+ server_types.push_back(NAME_FIRST);
+
+ // Heuristic value will NOT match with Autocomplete attribute.
+ test::CreateTestFormField("Payment Address", "payment_address", "user@upi",
+ "text", &field);
+ form.fields.push_back(field);
+ heuristic_types.push_back(UNKNOWN_TYPE);
+ server_types.push_back(NO_SERVER_DATA);
+
+ // 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_->SubmitForm(form, TimeTicks::Now());
+
+ histogram_tester.ExpectBucketCount(
+ "Autofill.UserHappiness", AutofillMetrics::USER_DID_ENTER_UPI_VPA, 1);
+}
+
// Test that we do not log RAPPOR metrics when the number of mismatches is not
// high enough.
TEST_F(AutofillMetricsTest, Rappor_LowMismatchRate_NoMetricsReported) {
@@ -1380,6 +1627,11 @@ TEST_F(AutofillMetricsTest, NumberOfEditedAutofilledFields) {
// fields is logged.
histogram_tester.ExpectUniqueSample(
"Autofill.NumberOfEditedAutofilledFieldsAtSubmission", 2, 1);
+
+ // UKM must not be logged unless enabled.
+ ukm::TestUkmService* ukm_service = autofill_client_.GetTestUkmService();
+ EXPECT_EQ(0U, ukm_service->sources_count());
+ EXPECT_EQ(0U, ukm_service->entries_count());
}
// Verify that when resetting the autofill manager (such as during a
@@ -1434,6 +1686,8 @@ TEST_F(AutofillMetricsTest, NumberOfEditedAutofilledFields_NoSubmission) {
// Verify that we correctly log metrics regarding developer engagement.
TEST_F(AutofillMetricsTest, DeveloperEngagement) {
+ ukm::TestUkmService* ukm_service = autofill_client_.GetTestUkmService();
+
// Start with a non-fillable form.
FormData form;
form.name = ASCIIToUTF16("TestForm");
@@ -1454,21 +1708,28 @@ TEST_F(AutofillMetricsTest, DeveloperEngagement) {
autofill_manager_->OnFormsSeen(forms, TimeTicks());
autofill_manager_->Reset();
histogram_tester.ExpectTotalCount("Autofill.DeveloperEngagement", 0);
+
+ // UKM must not be logged unless enabled.
+ EXPECT_EQ(0U, ukm_service->sources_count());
+ EXPECT_EQ(0U, ukm_service->entries_count());
}
// Add another field to the form, so that it becomes fillable.
test::CreateTestFormField("Phone", "phone", "", "text", &field);
forms.back().fields.push_back(field);
- // Expect only the "form parsed" metric to be logged; no metrics about
- // author-specified field type hints.
+ // Expect the "form parsed without hints" metric to be logged.
{
base::HistogramTester histogram_tester;
autofill_manager_->OnFormsSeen(forms, TimeTicks());
autofill_manager_->Reset();
- histogram_tester.ExpectUniqueSample("Autofill.DeveloperEngagement",
- AutofillMetrics::FILLABLE_FORM_PARSED,
- 1);
+ histogram_tester.ExpectUniqueSample(
+ "Autofill.DeveloperEngagement",
+ AutofillMetrics::FILLABLE_FORM_PARSED_WITHOUT_TYPE_HINTS, 1);
+
+ // UKM must not be logged unless enabled.
+ EXPECT_EQ(0U, ukm_service->sources_count());
+ EXPECT_EQ(0U, ukm_service->entries_count());
}
// Add some fields with an author-specified field type to the form.
@@ -1486,18 +1747,193 @@ TEST_F(AutofillMetricsTest, DeveloperEngagement) {
field.autocomplete_attribute = "address-line1";
forms.back().fields.push_back(field);
- // Expect both the "form parsed" metric and the author-specified field type
- // hints metric to be logged.
+ // Expect the "form parsed with field type hints" metric to be logged.
{
base::HistogramTester histogram_tester;
autofill_manager_->OnFormsSeen(forms, TimeTicks());
autofill_manager_->Reset();
- histogram_tester.ExpectBucketCount("Autofill.DeveloperEngagement",
- AutofillMetrics::FILLABLE_FORM_PARSED,
- 1);
histogram_tester.ExpectBucketCount(
"Autofill.DeveloperEngagement",
- AutofillMetrics::FILLABLE_FORM_CONTAINS_TYPE_HINTS, 1);
+ AutofillMetrics::FILLABLE_FORM_PARSED_WITH_TYPE_HINTS, 1);
+
+ // UKM must not be logged unless enabled.
+ EXPECT_EQ(0U, ukm_service->sources_count());
+ EXPECT_EQ(0U, ukm_service->entries_count());
+
+ histogram_tester.ExpectBucketCount(
+ "Autofill.DeveloperEngagement",
+ AutofillMetrics::FORM_CONTAINS_UPI_VPA_HINT, 0);
+ }
+
+ // 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);
+
+ // 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(forms, TimeTicks());
+ autofill_manager_->Reset();
+ histogram_tester.ExpectBucketCount(
+ "Autofill.DeveloperEngagement",
+ AutofillMetrics::FILLABLE_FORM_PARSED_WITH_TYPE_HINTS, 1);
+ histogram_tester.ExpectBucketCount(
+ "Autofill.DeveloperEngagement",
+ AutofillMetrics::FORM_CONTAINS_UPI_VPA_HINT, 1);
+ }
+}
+
+// Verify that we correctly log UKM for form parsed without type hints regarding
+// developer engagement.
+TEST_F(AutofillMetricsTest,
+ UkmDeveloperEngagement_LogFillableFormParsedWithoutTypeHints) {
+ EnableUkmLogging();
+ ukm::TestUkmService* ukm_service = autofill_client_.GetTestUkmService();
+
+ // Start with a non-fillable form.
+ FormData form;
+ form.name = ASCIIToUTF16("TestForm");
+ form.origin = GURL("http://example.com/form.html");
+ form.action = GURL("http://example.com/submit.html");
+
+ FormFieldData field;
+ test::CreateTestFormField("Name", "name", "", "text", &field);
+ form.fields.push_back(field);
+ test::CreateTestFormField("Email", "email", "", "text", &field);
+ form.fields.push_back(field);
+
+ std::vector<FormData> forms(1, form);
+
+ // Ensure no metrics are logged when loading a non-fillable form.
+ {
+ autofill_manager_->OnFormsSeen(forms, TimeTicks::Now());
+ autofill_manager_->Reset();
+
+ EXPECT_EQ(0U, ukm_service->sources_count());
+ EXPECT_EQ(0U, ukm_service->entries_count());
+ }
+
+ // Add another field to the form, so that it becomes fillable.
+ test::CreateTestFormField("Phone", "phone", "", "text", &field);
+ forms.back().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(forms, TimeTicks::Now());
+ autofill_manager_->Reset();
+
+ ASSERT_EQ(1U, ukm_service->entries_count());
+ ASSERT_EQ(1U, ukm_service->sources_count());
+ VerifyDeveloperEngagementUkm(
+ form, ukm_service,
+ {AutofillMetrics::FILLABLE_FORM_PARSED_WITHOUT_TYPE_HINTS});
+ }
+}
+
+// Verify that we correctly log UKM for form parsed with type hints regarding
+// developer engagement.
+TEST_F(AutofillMetricsTest,
+ UkmDeveloperEngagement_LogFillableFormParsedWithTypeHints) {
+ EnableUkmLogging();
+ ukm::TestUkmService* ukm_service = autofill_client_.GetTestUkmService();
+
+ FormData form;
+ form.name = ASCIIToUTF16("TestForm");
+ form.origin = GURL("http://example.com/form.html");
+ form.action = GURL("http://example.com/submit.html");
+
+ FormFieldData field;
+ test::CreateTestFormField("Name", "name", "", "text", &field);
+ form.fields.push_back(field);
+ 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);
+
+ // 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
+ // three fillable fields to be considered to be autofillable; and if at least
+ // one field specifies an explicit type hint, we don't apply any of our usual
+ // 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);
+ test::CreateTestFormField("", "", "", "text", &field);
+ field.autocomplete_attribute = "email";
+ forms.back().fields.push_back(field);
+ test::CreateTestFormField("", "", "", "text", &field);
+ field.autocomplete_attribute = "address-line1";
+ forms.back().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(forms, TimeTicks::Now());
+ autofill_manager_->Reset();
+
+ ASSERT_EQ(1U, ukm_service->entries_count());
+ ASSERT_EQ(1U, ukm_service->sources_count());
+ VerifyDeveloperEngagementUkm(
+ form, ukm_service,
+ {AutofillMetrics::FILLABLE_FORM_PARSED_WITH_TYPE_HINTS});
+ }
+}
+
+// Verify that we correctly log UKM for form parsed with type hints regarding
+// developer engagement.
+TEST_F(AutofillMetricsTest, UkmDeveloperEngagement_LogUpiVpaTypeHint) {
+ EnableUkmLogging();
+ ukm::TestUkmService* ukm_service = autofill_client_.GetTestUkmService();
+
+ FormData form;
+ form.name = ASCIIToUTF16("TestForm");
+ form.origin = GURL("http://example.com/form.html");
+ form.action = GURL("http://example.com/submit.html");
+
+ FormFieldData field;
+ test::CreateTestFormField("Name", "name", "", "text", &field);
+ form.fields.push_back(field);
+ test::CreateTestFormField("Email", "email", "", "text", &field);
+ form.fields.push_back(field);
+ test::CreateTestFormField("Payment", "payment", "", "text", &field);
+ field.autocomplete_attribute = "upi-vpa";
+ form.fields.push_back(field);
+
+ std::vector<FormData> forms(1, form);
+
+ // Expect the "upi-vpa hint" metric to be logged and the "form loaded" form
+ // interaction event to be logged.
+ {
+ autofill_manager_->OnFormsSeen(forms, TimeTicks::Now());
+ autofill_manager_->Reset();
+
+ ASSERT_EQ(1U, ukm_service->entries_count());
+ ASSERT_EQ(1U, ukm_service->sources_count());
+ VerifyDeveloperEngagementUkm(form, ukm_service,
+ {AutofillMetrics::FORM_CONTAINS_UPI_VPA_HINT});
+ ukm_service->Purge();
+ }
+
+ // Add another field with an author-specified field type to the form.
+ test::CreateTestFormField("", "", "", "text", &field);
+ field.autocomplete_attribute = "address-line1";
+ forms.back().fields.push_back(field);
+
+ {
+ autofill_manager_->OnFormsSeen(forms, TimeTicks::Now());
+ autofill_manager_->Reset();
+
+ VerifyDeveloperEngagementUkm(
+ form, ukm_service,
+ {AutofillMetrics::FILLABLE_FORM_PARSED_WITH_TYPE_HINTS,
+ AutofillMetrics::FORM_CONTAINS_UPI_VPA_HINT});
}
}
@@ -1680,6 +2116,9 @@ TEST_F(AutofillMetricsTest, AddressSuggestionsCount) {
// Test that the credit card checkout flow user actions are correctly logged.
TEST_F(AutofillMetricsTest, CreditCardCheckoutFlowUserActions) {
+ EnableUkmLogging();
+ ukm::TestUkmService* ukm_service = autofill_client_.GetTestUkmService();
+
personal_data_->RecreateCreditCards(
true /* include_local_credit_card */,
false /* include_masked_server_credit_card */,
@@ -1755,10 +2194,30 @@ TEST_F(AutofillMetricsTest, CreditCardCheckoutFlowUserActions) {
EXPECT_EQ(1, user_action_tester.GetActionCount(
"Autofill_FormSubmitted_NonFillable"));
}
+
+ VerifyFormInteractionUkm(
+ form, ukm_service, internal::kUKMSuggestionsShownEntryName,
+ {{{internal::kUKMMillisecondsSinceFormLoadedMetricName, 0}}});
+ // Expect 2 |FORM_EVENT_LOCAL_SUGGESTION_FILLED| events. First, from
+ // call to |external_delegate_->DidAcceptSuggestion|. Second, from call to
+ // |autofill_manager_->FillOrPreviewForm|.
+ VerifyFormInteractionUkm(
+ form, ukm_service, internal::kUKMSuggestionFilledEntryName,
+ {{{internal::kUKMRecordTypeMetricName, CreditCard::LOCAL_CARD},
+ {internal::kUKMMillisecondsSinceFormLoadedMetricName, 0}},
+ {{internal::kUKMRecordTypeMetricName, CreditCard::LOCAL_CARD},
+ {internal::kUKMMillisecondsSinceFormLoadedMetricName, 0}}});
+ // Expect |NON_FILLABLE_FORM_OR_NEW_DATA| in |AutofillFormSubmittedState|
+ // because |field.value| is empty in |DeterminePossibleFieldTypesForUpload|.
+ VerifySubmitFormUkm(form, ukm_service,
+ AutofillMetrics::NON_FILLABLE_FORM_OR_NEW_DATA);
}
// Test that the profile checkout flow user actions are correctly logged.
TEST_F(AutofillMetricsTest, ProfileCheckoutFlowUserActions) {
+ EnableUkmLogging();
+ ukm::TestUkmService* ukm_service = autofill_client_.GetTestUkmService();
+
// Create a profile.
personal_data_->RecreateProfile();
@@ -1806,7 +2265,7 @@ TEST_F(AutofillMetricsTest, ProfileCheckoutFlowUserActions) {
std::string guid("00000000-0000-0000-0000-000000000001"); // local profile.
external_delegate_->DidAcceptSuggestion(
ASCIIToUTF16("Test"),
- autofill_manager_->MakeFrontendID(guid, std::string()), 0);
+ autofill_manager_->MakeFrontendID(std::string(), guid), 0);
EXPECT_EQ(1,
user_action_tester.GetActionCount("Autofill_SelectedSuggestion"));
}
@@ -1832,6 +2291,23 @@ TEST_F(AutofillMetricsTest, ProfileCheckoutFlowUserActions) {
EXPECT_EQ(1, user_action_tester.GetActionCount(
"Autofill_FormSubmitted_NonFillable"));
}
+
+ VerifyFormInteractionUkm(
+ form, ukm_service, internal::kUKMSuggestionsShownEntryName,
+ {{{internal::kUKMMillisecondsSinceFormLoadedMetricName, 0}}});
+ // Expect 2 |FORM_EVENT_LOCAL_SUGGESTION_FILLED| events. First, from
+ // call to |external_delegate_->DidAcceptSuggestion|. Second, from call to
+ // |autofill_manager_->FillOrPreviewForm|.
+ VerifyFormInteractionUkm(
+ form, ukm_service, internal::kUKMSuggestionFilledEntryName,
+ {{{internal::kUKMRecordTypeMetricName, AutofillProfile::LOCAL_PROFILE},
+ {internal::kUKMMillisecondsSinceFormLoadedMetricName, 0}},
+ {{internal::kUKMRecordTypeMetricName, AutofillProfile::LOCAL_PROFILE},
+ {internal::kUKMMillisecondsSinceFormLoadedMetricName, 0}}});
+ // Expect |NON_FILLABLE_FORM_OR_NEW_DATA| in |AutofillFormSubmittedState|
+ // because |field.value| is empty in |DeterminePossibleFieldTypesForUpload|.
+ VerifySubmitFormUkm(form, ukm_service,
+ AutofillMetrics::NON_FILLABLE_FORM_OR_NEW_DATA);
}
// Tests that the Autofill_PolledCreditCardSuggestions user action is only
@@ -2121,6 +2597,11 @@ TEST_F(AutofillMetricsTest, CreditCardShownFormEvents) {
"Autofill.FormEvents.CreditCard",
AutofillMetrics::FORM_EVENT_SUGGESTIONS_SHOWN_ONCE, 0);
}
+
+ // UKM must not be logged unless enabled.
+ ukm::TestUkmService* ukm_service = autofill_client_.GetTestUkmService();
+ EXPECT_EQ(0U, ukm_service->sources_count());
+ EXPECT_EQ(0U, ukm_service->entries_count());
}
// Test that we log selected form event for credit cards.
@@ -2253,6 +2734,7 @@ TEST_F(AutofillMetricsTest, CreditCardFilledFormEvents) {
autofill_manager_->MakeFrontendID(guid, std::string()));
autofill_manager_->OnDidGetRealPan(AutofillClient::SUCCESS,
"6011000990139424");
+ autofill_manager_->SubmitForm(form, TimeTicks::Now());
histogram_tester.ExpectBucketCount(
"Autofill.FormEvents.CreditCard",
AutofillMetrics::FORM_EVENT_MASKED_SERVER_CARD_SUGGESTION_FILLED, 1);
@@ -2386,6 +2868,9 @@ TEST_F(AutofillMetricsTest, CreditCardGetRealPanDuration) {
// Test that we log submitted form events for credit cards.
TEST_F(AutofillMetricsTest, CreditCardSubmittedFormEvents) {
+ EnableUkmLogging();
+ ukm::TestUkmService* ukm_service = autofill_client_.GetTestUkmService();
+
EnableWalletSync();
// Creating all kinds of cards.
personal_data_->RecreateCreditCards(
@@ -2425,10 +2910,15 @@ TEST_F(AutofillMetricsTest, CreditCardSubmittedFormEvents) {
histogram_tester.ExpectBucketCount(
"Autofill.FormEvents.CreditCard",
AutofillMetrics::FORM_EVENT_NO_SUGGESTION_SUBMITTED_ONCE, 1);
+
+ VerifySubmitFormUkm(form, ukm_service,
+ AutofillMetrics::NON_FILLABLE_FORM_OR_NEW_DATA);
}
- // Reset the autofill manager state.
+ // Reset the autofill manager state and purge UKM logs.
autofill_manager_->Reset();
+ ukm_service->Purge();
+
autofill_manager_->AddSeenForm(form, field_types, field_types);
{
@@ -2443,10 +2933,18 @@ TEST_F(AutofillMetricsTest, CreditCardSubmittedFormEvents) {
histogram_tester.ExpectBucketCount(
"Autofill.FormEvents.CreditCard",
AutofillMetrics::FORM_EVENT_SUGGESTION_SHOWN_WILL_SUBMIT_ONCE, 1);
+
+ VerifyFormInteractionUkm(
+ form, ukm_service, internal::kUKMSuggestionsShownEntryName,
+ {{{internal::kUKMMillisecondsSinceFormLoadedMetricName, 0}}});
+ VerifySubmitFormUkm(form, ukm_service,
+ AutofillMetrics::NON_FILLABLE_FORM_OR_NEW_DATA);
}
- // Reset the autofill manager state.
+ // Reset the autofill manager state and purge UKM logs.
autofill_manager_->Reset();
+ ukm_service->Purge();
+
autofill_manager_->AddSeenForm(form, field_types, field_types);
{
@@ -2464,10 +2962,19 @@ TEST_F(AutofillMetricsTest, CreditCardSubmittedFormEvents) {
histogram_tester.ExpectBucketCount(
"Autofill.FormEvents.CreditCard",
AutofillMetrics::FORM_EVENT_LOCAL_SUGGESTION_SUBMITTED_ONCE, 1);
+
+ VerifyFormInteractionUkm(
+ form, ukm_service, internal::kUKMSuggestionFilledEntryName,
+ {{{internal::kUKMRecordTypeMetricName, CreditCard::LOCAL_CARD},
+ {internal::kUKMMillisecondsSinceFormLoadedMetricName, 0}}});
+ VerifySubmitFormUkm(form, ukm_service,
+ AutofillMetrics::NON_FILLABLE_FORM_OR_NEW_DATA);
}
- // Reset the autofill manager state.
+ // Reset the autofill manager state and purge UKM logs.
autofill_manager_->Reset();
+ ukm_service->Purge();
+
autofill_manager_->AddSeenForm(form, field_types, field_types);
{
@@ -2486,10 +2993,19 @@ TEST_F(AutofillMetricsTest, CreditCardSubmittedFormEvents) {
histogram_tester.ExpectBucketCount(
"Autofill.FormEvents.CreditCard",
AutofillMetrics::FORM_EVENT_SERVER_SUGGESTION_SUBMITTED_ONCE, 1);
+
+ VerifyFormInteractionUkm(
+ form, ukm_service, internal::kUKMSuggestionFilledEntryName,
+ {{{internal::kUKMRecordTypeMetricName, CreditCard::FULL_SERVER_CARD},
+ {internal::kUKMMillisecondsSinceFormLoadedMetricName, 0}}});
+ VerifySubmitFormUkm(form, ukm_service,
+ AutofillMetrics::NON_FILLABLE_FORM_OR_NEW_DATA);
}
- // Reset the autofill manager state.
+ // Reset the autofill manager state and purge UKM logs.
autofill_manager_->Reset();
+ ukm_service->Purge();
+
autofill_manager_->AddSeenForm(form, field_types, field_types);
{
@@ -2502,6 +3018,7 @@ TEST_F(AutofillMetricsTest, CreditCardSubmittedFormEvents) {
autofill_manager_->MakeFrontendID(guid, std::string()));
autofill_manager_->OnDidGetRealPan(AutofillClient::SUCCESS,
"6011000990139424");
+ autofill_manager_->SubmitForm(form, TimeTicks::Now());
histogram_tester.ExpectBucketCount(
"Autofill.FormEvents.CreditCard",
AutofillMetrics::FORM_EVENT_MASKED_SERVER_CARD_SUGGESTION_FILLED, 1);
@@ -2509,8 +3026,22 @@ TEST_F(AutofillMetricsTest, CreditCardSubmittedFormEvents) {
"Autofill.FormEvents.CreditCard",
AutofillMetrics::FORM_EVENT_MASKED_SERVER_CARD_SUGGESTION_FILLED_ONCE,
1);
+
+ VerifyFormInteractionUkm(
+ form, ukm_service, internal::kUKMSuggestionFilledEntryName,
+ {{{internal::kUKMRecordTypeMetricName, CreditCard::MASKED_SERVER_CARD},
+ {internal::kUKMMillisecondsSinceFormLoadedMetricName, 0}}});
+ VerifyFormInteractionUkm(
+ form, ukm_service, internal::kUKMSelectedMaskedServerCardEntryName,
+ {{{internal::kUKMMillisecondsSinceFormLoadedMetricName, 0}}});
+ VerifySubmitFormUkm(form, ukm_service,
+ AutofillMetrics::NON_FILLABLE_FORM_OR_NEW_DATA);
}
+ // Reset the autofill manager state and purge UKM logs.
+ autofill_manager_->Reset();
+ ukm_service->Purge();
+
// Recreating cards as the previous test should have upgraded the masked
// card to a full card.
personal_data_->RecreateCreditCards(
@@ -2527,7 +3058,24 @@ TEST_F(AutofillMetricsTest, CreditCardSubmittedFormEvents) {
base::HistogramTester histogram_tester;
autofill_manager_->OnQueryFormFieldAutofill(0, form, field, gfx::RectF());
autofill_manager_->SubmitForm(form, TimeTicks::Now());
+
+ VerifyFormInteractionUkm(
+ form, ukm_service, internal::kUKMFormSubmittedEntryName,
+ {{{internal::kUKMAutofillFormSubmittedStateMetricName,
+ AutofillMetrics::NON_FILLABLE_FORM_OR_NEW_DATA},
+ {internal::kUKMMillisecondsSinceFormLoadedMetricName, 0}}});
+
autofill_manager_->SubmitForm(form, TimeTicks::Now());
+
+ VerifyFormInteractionUkm(
+ form, ukm_service, internal::kUKMFormSubmittedEntryName,
+ {{{internal::kUKMAutofillFormSubmittedStateMetricName,
+ AutofillMetrics::NON_FILLABLE_FORM_OR_NEW_DATA},
+ {internal::kUKMMillisecondsSinceFormLoadedMetricName, 0}},
+ {{internal::kUKMAutofillFormSubmittedStateMetricName,
+ AutofillMetrics::NON_FILLABLE_FORM_OR_NEW_DATA},
+ {internal::kUKMMillisecondsSinceFormLoadedMetricName, 0}}});
+
histogram_tester.ExpectBucketCount(
"Autofill.FormEvents.CreditCard",
AutofillMetrics::FORM_EVENT_NO_SUGGESTION_WILL_SUBMIT_ONCE, 1);
@@ -2564,8 +3112,10 @@ TEST_F(AutofillMetricsTest, CreditCardSubmittedFormEvents) {
0);
}
- // Reset the autofill manager state.
+ // Reset the autofill manager state and purge UKM logs.
autofill_manager_->Reset();
+ ukm_service->Purge();
+
autofill_manager_->AddSeenForm(form, field_types, field_types);
{
@@ -2608,6 +3158,12 @@ TEST_F(AutofillMetricsTest, CreditCardSubmittedFormEvents) {
AutofillMetrics::
FORM_EVENT_MASKED_SERVER_CARD_SUGGESTION_WILL_SUBMIT_ONCE,
0);
+
+ VerifyFormInteractionUkm(
+ form, ukm_service, internal::kUKMSuggestionsShownEntryName,
+ {{{internal::kUKMMillisecondsSinceFormLoadedMetricName, 0}}});
+ VerifySubmitFormUkm(form, ukm_service,
+ AutofillMetrics::NON_FILLABLE_FORM_OR_NEW_DATA);
}
}
@@ -3029,6 +3585,9 @@ TEST_F(AutofillMetricsTest, AddressFilledFormEvents) {
// Test that we log submitted form events for address.
TEST_F(AutofillMetricsTest, AddressSubmittedFormEvents) {
+ EnableUkmLogging();
+ ukm::TestUkmService* ukm_service = autofill_client_.GetTestUkmService();
+
EnableWalletSync();
// Create a profile.
personal_data_->RecreateProfile();
@@ -3065,10 +3624,15 @@ TEST_F(AutofillMetricsTest, AddressSubmittedFormEvents) {
histogram_tester.ExpectBucketCount(
"Autofill.FormEvents.Address",
AutofillMetrics::FORM_EVENT_NO_SUGGESTION_SUBMITTED_ONCE, 1);
+
+ VerifySubmitFormUkm(form, ukm_service,
+ AutofillMetrics::NON_FILLABLE_FORM_OR_NEW_DATA);
}
- // Reset the autofill manager state.
+ // Reset the autofill manager state and purge UKM logs.
autofill_manager_->Reset();
+ ukm_service->Purge();
+
autofill_manager_->AddSeenForm(form, field_types, field_types);
{
@@ -3116,6 +3680,7 @@ TEST_F(AutofillMetricsTest, AddressSubmittedFormEvents) {
autofill_manager_->OnQueryFormFieldAutofill(0, form, field, gfx::RectF());
autofill_manager_->SubmitForm(form, TimeTicks::Now());
autofill_manager_->SubmitForm(form, TimeTicks::Now());
+
histogram_tester.ExpectBucketCount(
"Autofill.FormEvents.Address",
AutofillMetrics::FORM_EVENT_NO_SUGGESTION_WILL_SUBMIT_ONCE, 1);
@@ -3152,6 +3717,7 @@ TEST_F(AutofillMetricsTest, AddressSubmittedFormEvents) {
base::HistogramTester histogram_tester;
autofill_manager_->DidShowSuggestions(true /* is_new_popup */, form, field);
autofill_manager_->SubmitForm(form, TimeTicks::Now());
+
histogram_tester.ExpectBucketCount(
"Autofill.FormEvents.Address",
AutofillMetrics::FORM_EVENT_SUGGESTION_SHOWN_WILL_SUBMIT_ONCE, 0);
@@ -3522,7 +4088,6 @@ TEST_F(AutofillMetricsTest, AddressFormEventsAreSegmented) {
}
}
-
// Test that we log that Autofill is enabled when filling a form.
TEST_F(AutofillMetricsTest, AutofillIsEnabledAtPageLoad) {
base::HistogramTester histogram_tester;
@@ -3561,6 +4126,9 @@ TEST_F(AutofillMetricsTest, DaysSinceLastUse_Profile) {
// Verify that we correctly log the submitted form's state.
TEST_F(AutofillMetricsTest, AutofillFormSubmittedState) {
+ EnableUkmLogging();
+ ukm::TestUkmService* ukm_service = autofill_client_.GetTestUkmService();
+
// Start with a form with insufficiently many fields.
FormData form;
form.name = ASCIIToUTF16("TestForm");
@@ -3581,10 +4149,16 @@ TEST_F(AutofillMetricsTest, AutofillFormSubmittedState) {
// Expect no notifications when the form is first seen.
{
base::HistogramTester histogram_tester;
- autofill_manager_->OnFormsSeen(forms, TimeTicks());
+ autofill_manager_->OnFormsSeen(forms, TimeTicks::Now());
histogram_tester.ExpectTotalCount("Autofill.FormSubmittedState", 0);
}
+ std::vector<std::vector<std::pair<const char*, int64_t>>>
+ expected_form_submission_ukm_metrics = {
+ {{internal::kUKMAutofillFormSubmittedStateMetricName,
+ AutofillMetrics::NON_FILLABLE_FORM_OR_NEW_DATA},
+ {internal::kUKMMillisecondsSinceFormLoadedMetricName, 0}}};
+
// No data entered in the form.
{
base::HistogramTester histogram_tester;
@@ -3595,6 +4169,17 @@ TEST_F(AutofillMetricsTest, AutofillFormSubmittedState) {
AutofillMetrics::NON_FILLABLE_FORM_OR_NEW_DATA, 1);
EXPECT_EQ(1, user_action_tester.GetActionCount(
"Autofill_FormSubmitted_NonFillable"));
+
+ // Expect an entry for |DeveloperEngagement| and an entry for form
+ // interactions. Both entries are for the same URL.
+ ASSERT_EQ(2U, ukm_service->entries_count());
+ ASSERT_EQ(2U, ukm_service->sources_count());
+ VerifyDeveloperEngagementUkm(
+ form, ukm_service,
+ {AutofillMetrics::FILLABLE_FORM_PARSED_WITHOUT_TYPE_HINTS});
+ VerifyFormInteractionUkm(form, ukm_service,
+ internal::kUKMFormSubmittedEntryName,
+ expected_form_submission_ukm_metrics);
}
// Non fillable form.
@@ -3611,6 +4196,14 @@ TEST_F(AutofillMetricsTest, AutofillFormSubmittedState) {
AutofillMetrics::NON_FILLABLE_FORM_OR_NEW_DATA, 1);
EXPECT_EQ(1, user_action_tester.GetActionCount(
"Autofill_FormSubmitted_NonFillable"));
+
+ expected_form_submission_ukm_metrics.push_back(
+ {{internal::kUKMAutofillFormSubmittedStateMetricName,
+ AutofillMetrics::NON_FILLABLE_FORM_OR_NEW_DATA},
+ {internal::kUKMMillisecondsSinceFormLoadedMetricName, 0}});
+ VerifyFormInteractionUkm(form, ukm_service,
+ internal::kUKMFormSubmittedEntryName,
+ expected_form_submission_ukm_metrics);
}
// Fill in the third field.
@@ -3628,6 +4221,15 @@ TEST_F(AutofillMetricsTest, AutofillFormSubmittedState) {
1);
EXPECT_EQ(1, user_action_tester.GetActionCount(
"Autofill_FormSubmitted_FilledNone_SuggestionsNotShown"));
+
+ expected_form_submission_ukm_metrics.push_back(
+ {{internal::kUKMAutofillFormSubmittedStateMetricName,
+ AutofillMetrics::
+ FILLABLE_FORM_AUTOFILLED_NONE_DID_NOT_SHOW_SUGGESTIONS},
+ {internal::kUKMMillisecondsSinceFormLoadedMetricName, 0}});
+ VerifyFormInteractionUkm(form, ukm_service,
+ internal::kUKMFormSubmittedEntryName,
+ expected_form_submission_ukm_metrics);
}
// Autofilled none with suggestions shown.
@@ -3641,6 +4243,17 @@ TEST_F(AutofillMetricsTest, AutofillFormSubmittedState) {
AutofillMetrics::FILLABLE_FORM_AUTOFILLED_NONE_DID_SHOW_SUGGESTIONS, 1);
EXPECT_EQ(1, user_action_tester.GetActionCount(
"Autofill_FormSubmitted_FilledNone_SuggestionsShown"));
+
+ VerifyFormInteractionUkm(
+ form, ukm_service, internal::kUKMSuggestionsShownEntryName,
+ {{{internal::kUKMMillisecondsSinceFormLoadedMetricName, 0}}});
+ expected_form_submission_ukm_metrics.push_back(
+ {{internal::kUKMAutofillFormSubmittedStateMetricName,
+ AutofillMetrics::FILLABLE_FORM_AUTOFILLED_NONE_DID_SHOW_SUGGESTIONS},
+ {internal::kUKMMillisecondsSinceFormLoadedMetricName, 0}});
+ VerifyFormInteractionUkm(form, ukm_service,
+ internal::kUKMFormSubmittedEntryName,
+ expected_form_submission_ukm_metrics);
}
// Mark one of the fields as autofilled.
@@ -3657,6 +4270,14 @@ TEST_F(AutofillMetricsTest, AutofillFormSubmittedState) {
AutofillMetrics::FILLABLE_FORM_AUTOFILLED_SOME, 1);
EXPECT_EQ(1, user_action_tester.GetActionCount(
"Autofill_FormSubmitted_FilledSome"));
+
+ expected_form_submission_ukm_metrics.push_back(
+ {{internal::kUKMAutofillFormSubmittedStateMetricName,
+ AutofillMetrics::FILLABLE_FORM_AUTOFILLED_SOME},
+ {internal::kUKMMillisecondsSinceFormLoadedMetricName, 0}});
+ VerifyFormInteractionUkm(form, ukm_service,
+ internal::kUKMFormSubmittedEntryName,
+ expected_form_submission_ukm_metrics);
}
// Mark all of the fillable fields as autofilled.
@@ -3674,6 +4295,14 @@ TEST_F(AutofillMetricsTest, AutofillFormSubmittedState) {
AutofillMetrics::FILLABLE_FORM_AUTOFILLED_ALL, 1);
EXPECT_EQ(1, user_action_tester.GetActionCount(
"Autofill_FormSubmitted_FilledAll"));
+
+ expected_form_submission_ukm_metrics.push_back(
+ {{internal::kUKMAutofillFormSubmittedStateMetricName,
+ AutofillMetrics::FILLABLE_FORM_AUTOFILLED_ALL},
+ {internal::kUKMMillisecondsSinceFormLoadedMetricName, 0}});
+ VerifyFormInteractionUkm(form, ukm_service,
+ internal::kUKMFormSubmittedEntryName,
+ expected_form_submission_ukm_metrics);
}
// Clear out the third field's value.
@@ -3690,12 +4319,23 @@ TEST_F(AutofillMetricsTest, AutofillFormSubmittedState) {
AutofillMetrics::NON_FILLABLE_FORM_OR_NEW_DATA, 1);
EXPECT_EQ(1, user_action_tester.GetActionCount(
"Autofill_FormSubmitted_NonFillable"));
+
+ expected_form_submission_ukm_metrics.push_back(
+ {{internal::kUKMAutofillFormSubmittedStateMetricName,
+ AutofillMetrics::NON_FILLABLE_FORM_OR_NEW_DATA},
+ {internal::kUKMMillisecondsSinceFormLoadedMetricName, 0}});
+ VerifyFormInteractionUkm(form, ukm_service,
+ internal::kUKMFormSubmittedEntryName,
+ expected_form_submission_ukm_metrics);
}
}
// Verify that we correctly log user happiness metrics dealing with form
// interaction.
TEST_F(AutofillMetricsTest, UserHappinessFormInteraction) {
+ EnableUkmLogging();
+ ukm::TestUkmService* ukm_service = autofill_client_.GetTestUkmService();
+
// Load a fillable form.
FormData form;
form.name = ASCIIToUTF16("TestForm");
@@ -3795,6 +4435,50 @@ TEST_F(AutofillMetricsTest, UserHappinessFormInteraction) {
"Autofill.UserHappiness",
AutofillMetrics::USER_DID_EDIT_AUTOFILLED_FIELD, 1);
}
+
+ autofill_manager_->Reset();
+
+ VerifyFormInteractionUkm(
+ form, ukm_service, internal::kUKMInteractedWithFormEntryName,
+ {{{internal::kUKMIsForCreditCardMetricName, false},
+ {internal::kUKMLocalRecordTypeCountMetricName, 0},
+ {internal::kUKMServerRecordTypeCountMetricName, 0}}});
+ VerifyFormInteractionUkm(
+ form, ukm_service, internal::kUKMSuggestionsShownEntryName,
+ {{{internal::kUKMMillisecondsSinceFormLoadedMetricName, 0}},
+ {{internal::kUKMMillisecondsSinceFormLoadedMetricName, 0}}});
+ VerifyFormInteractionUkm(
+ form, ukm_service, internal::kUKMSuggestionFilledEntryName,
+ {{{internal::kUKMRecordTypeMetricName, AutofillProfile::LOCAL_PROFILE},
+ {internal::kUKMMillisecondsSinceFormLoadedMetricName, 0}},
+ {{internal::kUKMRecordTypeMetricName, AutofillProfile::LOCAL_PROFILE},
+ {internal::kUKMMillisecondsSinceFormLoadedMetricName, 0}}});
+ VerifyFormInteractionUkm(
+ form, ukm_service, internal::kUKMTextFieldDidChangeEntryName,
+ {{{internal::kUKMFieldTypeGroupMetricName, NAME},
+ {internal::kUKMHeuristicTypeMetricName, NAME_FULL},
+ {internal::kUKMServerTypeMetricName, NO_SERVER_DATA},
+ {internal::kUKMHtmlFieldTypeMetricName, HTML_TYPE_UNSPECIFIED},
+ {internal::kUKMHtmlFieldModeMetricName, HTML_MODE_NONE},
+ {internal::kUKMIsAutofilledMetricName, false},
+ {internal::kUKMIsEmptyMetricName, true},
+ {internal::kUKMMillisecondsSinceFormLoadedMetricName, 0}},
+ {{internal::kUKMFieldTypeGroupMetricName, NAME},
+ {internal::kUKMHeuristicTypeMetricName, NAME_FULL},
+ {internal::kUKMServerTypeMetricName, NO_SERVER_DATA},
+ {internal::kUKMHtmlFieldTypeMetricName, HTML_TYPE_UNSPECIFIED},
+ {internal::kUKMHtmlFieldModeMetricName, HTML_MODE_NONE},
+ {internal::kUKMIsAutofilledMetricName, true},
+ {internal::kUKMIsEmptyMetricName, true},
+ {internal::kUKMMillisecondsSinceFormLoadedMetricName, 0}},
+ {{internal::kUKMFieldTypeGroupMetricName, EMAIL},
+ {internal::kUKMHeuristicTypeMetricName, EMAIL_ADDRESS},
+ {internal::kUKMServerTypeMetricName, NO_SERVER_DATA},
+ {internal::kUKMHtmlFieldTypeMetricName, HTML_TYPE_UNSPECIFIED},
+ {internal::kUKMHtmlFieldModeMetricName, HTML_MODE_NONE},
+ {internal::kUKMIsAutofilledMetricName, true},
+ {internal::kUKMIsEmptyMetricName, true},
+ {internal::kUKMMillisecondsSinceFormLoadedMetricName, 0}}});
}
// Verify that we correctly log metrics tracking the duration of form fill.
@@ -4366,15 +5050,14 @@ TEST_F(AutofillMetricsTest,
}
}
-// Tests that logging a UKM works as expected.
+// Tests that logging CardUploadDecision UKM works as expected.
TEST_F(AutofillMetricsTest, RecordCardUploadDecisionMetric) {
EnableUkmLogging();
ukm::UkmServiceTestingHarness ukm_service_test_harness;
GURL url("https://www.google.com");
int upload_decision = 1;
- std::map<std::string, int> metrics;
- metrics.insert(std::make_pair(internal::kUKMCardUploadDecisionMetricName,
- upload_decision));
+ std::vector<std::pair<const char*, int>> metrics = {
+ {internal::kUKMCardUploadDecisionMetricName, upload_decision}};
EXPECT_TRUE(AutofillMetrics::LogUkm(
ukm_service_test_harness.test_ukm_service(), url,
@@ -4385,14 +5068,15 @@ TEST_F(AutofillMetricsTest, RecordCardUploadDecisionMetric) {
ukm_service_test_harness.test_ukm_service();
ASSERT_EQ(1U, ukm_service->sources_count());
- const ukm::UkmSource* source = ukm_service->GetSource(0);
+ const ukm::UkmSource* source =
+ ukm_service->GetSourceForUrl(url.spec().c_str());
EXPECT_EQ(url.spec(), source->url().spec());
- EXPECT_EQ(1U, ukm_service->entries_count());
+ ASSERT_EQ(1U, ukm_service->entries_count());
const ukm::UkmEntry* entry = ukm_service->GetEntry(0);
EXPECT_EQ(source->id(), entry->source_id());
- // Make sure that an card upload decision entry was logged.
+ // Make sure that a card upload decision entry was logged.
ukm::Entry entry_proto;
entry->PopulateProto(&entry_proto);
EXPECT_EQ(source->id(), entry_proto.source_id());
@@ -4407,13 +5091,53 @@ TEST_F(AutofillMetricsTest, RecordCardUploadDecisionMetric) {
EXPECT_EQ(upload_decision, metric->value());
}
+// Tests that logging DeveloperEngagement UKM works as expected.
+TEST_F(AutofillMetricsTest, RecordDeveloperEngagementMetric) {
+ EnableUkmLogging();
+ ukm::UkmServiceTestingHarness ukm_service_test_harness;
+ GURL url("https://www.google.com");
+ int form_structure_metric = 1;
+ std::vector<std::pair<const char*, int>> metrics = {
+ {internal::kUKMDeveloperEngagementMetricName, form_structure_metric}};
+
+ EXPECT_TRUE(AutofillMetrics::LogUkm(
+ ukm_service_test_harness.test_ukm_service(), url,
+ internal::kUKMDeveloperEngagementEntryName, metrics));
+
+ // Make sure that the UKM was logged correctly.
+ ukm::TestUkmService* ukm_service =
+ ukm_service_test_harness.test_ukm_service();
+
+ ASSERT_EQ(1U, ukm_service->sources_count());
+ const ukm::UkmSource* source =
+ ukm_service->GetSourceForUrl(url.spec().c_str());
+ EXPECT_EQ(url.spec(), source->url().spec());
+
+ ASSERT_EQ(1U, ukm_service->entries_count());
+ const ukm::UkmEntry* entry = ukm_service->GetEntry(0);
+ EXPECT_EQ(source->id(), entry->source_id());
+
+ // Make sure that a developer engagement entry was logged.
+ ukm::Entry entry_proto;
+ entry->PopulateProto(&entry_proto);
+ EXPECT_EQ(source->id(), entry_proto.source_id());
+ EXPECT_EQ(base::HashMetricName(internal::kUKMDeveloperEngagementEntryName),
+ entry_proto.event_hash());
+ EXPECT_EQ(1, entry_proto.metrics_size());
+
+ // Make sure that the correct developer engagement metric was logged.
+ const ukm::Entry_Metric* metric = FindMetric(
+ internal::kUKMDeveloperEngagementMetricName, entry_proto.metrics());
+ ASSERT_NE(nullptr, metric);
+ EXPECT_EQ(form_structure_metric, metric->value());
+}
+
// Tests that no UKM is logged when the URL is not valid.
TEST_F(AutofillMetricsTest, RecordCardUploadDecisionMetric_InvalidUrl) {
EnableUkmLogging();
ukm::UkmServiceTestingHarness ukm_service_test_harness;
GURL url("");
- std::map<std::string, int> metrics;
- metrics.insert(std::make_pair("metric", 1));
+ std::vector<std::pair<const char*, int>> metrics = {{"metric", 1}};
EXPECT_FALSE(AutofillMetrics::LogUkm(
ukm_service_test_harness.test_ukm_service(), url, "test_ukm", metrics));
@@ -4425,7 +5149,7 @@ TEST_F(AutofillMetricsTest, RecordCardUploadDecisionMetric_NoMetrics) {
EnableUkmLogging();
ukm::UkmServiceTestingHarness ukm_service_test_harness;
GURL url("https://www.google.com");
- std::map<std::string, int> metrics;
+ std::vector<std::pair<const char*, int>> metrics;
EXPECT_FALSE(AutofillMetrics::LogUkm(
ukm_service_test_harness.test_ukm_service(), url, "test_ukm", metrics));
@@ -4437,8 +5161,7 @@ TEST_F(AutofillMetricsTest, RecordCardUploadDecisionMetric_NoUkmService) {
EnableUkmLogging();
ukm::UkmServiceTestingHarness ukm_service_test_harness;
GURL url("https://www.google.com");
- std::map<std::string, int> metrics;
- metrics.insert(std::make_pair("metric", 1));
+ std::vector<std::pair<const char*, int>> metrics = {{"metric", 1}};
EXPECT_FALSE(AutofillMetrics::LogUkm(nullptr, url, "test_ukm", metrics));
ASSERT_EQ(0U, ukm_service_test_harness.test_ukm_service()->sources_count());
@@ -4448,8 +5171,7 @@ TEST_F(AutofillMetricsTest, RecordCardUploadDecisionMetric_NoUkmService) {
TEST_F(AutofillMetricsTest, RecordCardUploadDecisionMetric_FeatureDisabled) {
ukm::UkmServiceTestingHarness ukm_service_test_harness;
GURL url("https://www.google.com");
- std::map<std::string, int> metrics;
- metrics.insert(std::make_pair("metric", 1));
+ std::vector<std::pair<const char*, int>> metrics = {{"metric", 1}};
EXPECT_FALSE(AutofillMetrics::LogUkm(
ukm_service_test_harness.test_ukm_service(), url, "test_ukm", metrics));
diff --git a/chromium/components/autofill/core/browser/autofill_profile.cc b/chromium/components/autofill/core/browser/autofill_profile.cc
index 1828497e688..4ef1222b02a 100644
--- a/chromium/components/autofill/core/browser/autofill_profile.cc
+++ b/chromium/components/autofill/core/browser/autofill_profile.cc
@@ -48,8 +48,8 @@
using base::ASCIIToUTF16;
using base::UTF16ToUTF8;
-using i18n::addressinput::AddressData;
-using i18n::addressinput::AddressField;
+using ::i18n::addressinput::AddressData;
+using ::i18n::addressinput::AddressField;
namespace autofill {
namespace {
diff --git a/chromium/components/autofill/core/browser/autofill_profile_comparator.cc b/chromium/components/autofill/core/browser/autofill_profile_comparator.cc
index c3e8709549b..8bfcd193dd5 100644
--- a/chromium/components/autofill/core/browser/autofill_profile_comparator.cc
+++ b/chromium/components/autofill/core/browser/autofill_profile_comparator.cc
@@ -9,7 +9,7 @@
#include "base/i18n/case_conversion.h"
#include "base/i18n/char_iterator.h"
-#include "base/strings/string_piece.h"
+#include "base/i18n/unicodestring.h"
#include "base/strings/string_split.h"
#include "base/strings/string_util.h"
#include "base/strings/utf_string_conversion_utils.h"
@@ -128,7 +128,7 @@ base::string16 AutofillProfileComparator::NormalizeForComparison(
icu::UnicodeString value = icu::UnicodeString(result.data(), result.length());
transliterator_->transliterate(value);
- return base::string16(value.getBuffer(), value.length());
+ return base::i18n::UnicodeStringToString16(value);
}
bool AutofillProfileComparator::AreMergeable(const AutofillProfile& p1,
@@ -667,7 +667,7 @@ std::set<base::string16> AutofillProfileComparator::GetNamePartVariants(
const base::string16& name_part) {
const size_t kMaxSupportedSubNames = 8;
- std::vector<base::string16> sub_names = base::SplitString(
+ std::vector<base::StringPiece16> sub_names = base::SplitStringPiece(
name_part, kSpace, base::TRIM_WHITESPACE, base::SPLIT_WANT_NONEMPTY);
// Limit the number of sub-names we support (to constrain memory usage);
@@ -680,7 +680,7 @@ std::set<base::string16> AutofillProfileComparator::GetNamePartVariants(
// For each sub-name, add a variant of all the already existing variants that
// appends this sub-name and one that appends the initial of this sub-name.
// Duplicates will be discarded when they're added to the variants set.
- for (const base::string16& sub_name : sub_names) {
+ for (const auto& sub_name : sub_names) {
if (sub_name.empty())
continue;
std::vector<base::string16> new_variants;
@@ -696,7 +696,7 @@ std::set<base::string16> AutofillProfileComparator::GetNamePartVariants(
// As a common case, also add the variant that just concatenates all of the
// initials.
base::string16 initials;
- for (const base::string16& sub_name : sub_names) {
+ for (const auto& sub_name : sub_names) {
if (sub_name.empty())
continue;
initials.push_back(sub_name[0]);
@@ -720,12 +720,12 @@ bool AutofillProfileComparator::IsNameVariantOf(
GetNamePartVariants(name_1_parts.given);
const std::set<base::string16> middle_name_variants =
GetNamePartVariants(name_1_parts.middle);
- const base::string16& family_name = name_1_parts.family;
+ base::StringPiece16 family_name = name_1_parts.family;
// Iterate over all full name variants of profile 2 and see if any of them
// match the full name from profile 1.
- for (const base::string16& given_name : given_name_variants) {
- for (const base::string16& middle_name : middle_name_variants) {
+ for (const auto& given_name : given_name_variants) {
+ for (const auto& middle_name : middle_name_variants) {
base::string16 candidate = base::CollapseWhitespace(
base::JoinString({given_name, middle_name, family_name}, kSpace),
true);
diff --git a/chromium/components/autofill/core/browser/autofill_profile_unittest.cc b/chromium/components/autofill/core/browser/autofill_profile_unittest.cc
index c54f2ae61c4..ee55bc0857b 100644
--- a/chromium/components/autofill/core/browser/autofill_profile_unittest.cc
+++ b/chromium/components/autofill/core/browser/autofill_profile_unittest.cc
@@ -39,39 +39,6 @@ base::string16 GetLabel(AutofillProfile* profile) {
return labels[0];
}
-// Holds the autofill profile |first|, |middle| and |last| names.
-struct NameParts {
- NameParts(const std::string& first,
- const std::string& middle,
- const std::string& last)
- : first(first), middle(middle), last(last) {}
-
- std::string first;
- std::string middle;
- std::string last;
-};
-
-// Test case to be executed to validate OverwriteOrAppendNames.
-struct TestCase {
- TestCase(const NameParts& starting_name,
- const NameParts& additional_name,
- const NameParts& expected_result)
- : starting_names(std::vector<NameParts>(1, starting_name)),
- additional_names(std::vector<NameParts>(1, additional_name)),
- expected_result(std::vector<NameParts>(1, expected_result)) {}
-
- TestCase(const std::vector<NameParts>& starting_names,
- const std::vector<NameParts>& additional_names,
- const std::vector<NameParts>& expected_result)
- : starting_names(starting_names),
- additional_names(additional_names),
- expected_result(expected_result) {}
-
- std::vector<NameParts> starting_names;
- std::vector<NameParts> additional_names;
- std::vector<NameParts> expected_result;
-};
-
void SetupTestProfile(AutofillProfile& profile) {
profile.set_guid(base::GenerateGUID());
profile.set_origin(kSettingsOrigin);
diff --git a/chromium/components/autofill/core/browser/autofill_regex_constants.cc b/chromium/components/autofill/core/browser/autofill_regex_constants.cc
index e5587bea511..57b961df461 100644
--- a/chromium/components/autofill/core/browser/autofill_regex_constants.cc
+++ b/chromium/components/autofill/core/browser/autofill_regex_constants.cc
@@ -309,5 +309,34 @@ const char kPhoneSuffixRe[] =
const char kPhoneExtensionRe[] =
"\\bext|ext\\b|extension"
"|ramal"; // pt-BR, pt-PT
+const char kUPIVirtualPaymentAddressRe[] =
+ "^\\w+@("
+ "upi|" // BHIM Bharat Interface for Money
+ "allbank|" // Allahabad Bank UPI
+ "andb|" // Andhra Bank ONE
+ "axisbank|" // Axis Pay
+ "barodampay|" // Baroda MPay
+ "mahb|" // MAHAUPI
+ "cnrb|" // Canara Bank UPI - Empower
+ "csbpay|" // CSB UPI
+ "dcb|" // DCB Bank
+ "federal|" // Lotza
+ "hdfcbank|" // HDFC Bank MobileBanking
+ "pockets|" // Pockets- ICICI Bank
+ "icici|" // Pockets- ICICI Bank
+ "idfcbank|" // IDFC Bank UPI App
+ "indus|" // Indus Pay
+ "kbl|" // KBL Smartz
+ "kaypay|" // KayPay
+ "pnb|" // PNB UPI
+ "sib|" // SIB M-Pay (UPI Pay)
+ "sbi|" // SBI Pay
+ "tjsp|" // TranZapp
+ "uco|" // UCO UPI
+ "unionbank|" // Union Bank UPI
+ "united|" // United UPI
+ "vijb|" // Vijaya UPI App
+ "ybl" // Yes Pay
+ ")$";
} // namespace autofill
diff --git a/chromium/components/autofill/core/browser/autofill_regex_constants.h b/chromium/components/autofill/core/browser/autofill_regex_constants.h
index db85f540f69..8be7b2c39a6 100644
--- a/chromium/components/autofill/core/browser/autofill_regex_constants.h
+++ b/chromium/components/autofill/core/browser/autofill_regex_constants.h
@@ -56,6 +56,12 @@ extern const char kPhonePrefixRe[];
extern const char kPhoneSuffixRe[];
extern const char kPhoneExtensionRe[];
+// 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 char kUPIVirtualPaymentAddressRe[];
+
} // namespace autofill
#endif // COMPONENTS_AUTOFILL_CORE_BROWSER_AUTOFILL_REGEX_CONSTANTS_H_
diff --git a/chromium/components/autofill/core/browser/autofill_save_card_infobar_delegate_mobile.cc b/chromium/components/autofill/core/browser/autofill_save_card_infobar_delegate_mobile.cc
index fe2e1d3f566..28f7aea7b07 100644
--- a/chromium/components/autofill/core/browser/autofill_save_card_infobar_delegate_mobile.cc
+++ b/chromium/components/autofill/core/browser/autofill_save_card_infobar_delegate_mobile.cc
@@ -17,7 +17,6 @@
#include "components/strings/grit/components_strings.h"
#include "ui/base/l10n/l10n_util.h"
#include "ui/base/window_open_disposition.h"
-#include "ui/gfx/vector_icons_public.h"
#include "url/gurl.h"
namespace autofill {
diff --git a/chromium/components/autofill/core/browser/autofill_test_utils.cc b/chromium/components/autofill/core/browser/autofill_test_utils.cc
index 78b1f0e09ed..10a23dcb2c6 100644
--- a/chromium/components/autofill/core/browser/autofill_test_utils.cc
+++ b/chromium/components/autofill/core/browser/autofill_test_utils.cc
@@ -226,15 +226,15 @@ AutofillProfile GetVerifiedProfile2() {
CreditCard GetCreditCard() {
CreditCard credit_card(base::GenerateGUID(), "http://www.example.com");
- SetCreditCardInfo(
- &credit_card, "Test User", "4111111111111111" /* Visa */, "11", "2017");
+ SetCreditCardInfo(&credit_card, "Test User", "4111111111111111" /* Visa */,
+ "11", "2022");
return credit_card;
}
CreditCard GetCreditCard2() {
CreditCard credit_card(base::GenerateGUID(), "https://www.example.com");
- SetCreditCardInfo(
- &credit_card, "Someone Else", "378282246310005" /* AmEx */, "07", "2019");
+ SetCreditCardInfo(&credit_card, "Someone Else", "378282246310005" /* AmEx */,
+ "07", "2022");
return credit_card;
}
@@ -253,7 +253,7 @@ CreditCard GetVerifiedCreditCard2() {
CreditCard GetMaskedServerCard() {
CreditCard credit_card(CreditCard::MASKED_SERVER_CARD, "a123");
test::SetCreditCardInfo(&credit_card, "Bonnie Parker",
- "2109" /* Mastercard */, "12", "2012");
+ "2109" /* Mastercard */, "12", "2020");
credit_card.SetTypeForMaskedCard(kMasterCard);
return credit_card;
}
diff --git a/chromium/components/autofill/core/browser/autofill_type.cc b/chromium/components/autofill/core/browser/autofill_type.cc
index 8dc9dbc85ad..2b97a2f6eda 100644
--- a/chromium/components/autofill/core/browser/autofill_type.cc
+++ b/chromium/components/autofill/core/browser/autofill_type.cc
@@ -208,6 +208,10 @@ FieldTypeGroup AutofillType::group() const {
case HTML_TYPE_EMAIL:
return EMAIL;
+ case HTML_TYPE_UPI_VPA:
+ // TODO(crbug/702223): Add support for UPI-VPA.
+ break;
+
case HTML_TYPE_UNSPECIFIED:
case HTML_TYPE_UNRECOGNIZED:
break;
@@ -418,6 +422,10 @@ ServerFieldType AutofillType::GetStorableType() const {
case HTML_TYPE_TRANSACTION_CURRENCY:
return UNKNOWN_TYPE;
+ // TODO(crbug/702223): Add autofill support for UPI-VPA.
+ case HTML_TYPE_UPI_VPA:
+ return UNKNOWN_TYPE;
+
case HTML_TYPE_UNRECOGNIZED:
return UNKNOWN_TYPE;
}
@@ -591,6 +599,8 @@ std::string AutofillType::ToString() const {
return "HTML_TRANSACTION_AMOUNT";
case HTML_TYPE_TRANSACTION_CURRENCY:
return "HTML_TRANSACTION_CURRENCY";
+ case HTML_TYPE_UPI_VPA:
+ return "HTML_TYPE_UPI_VPA";
case HTML_TYPE_UNRECOGNIZED:
return "HTML_TYPE_UNRECOGNIZED";
}
diff --git a/chromium/components/autofill/core/browser/contact_info_unittest.cc b/chromium/components/autofill/core/browser/contact_info_unittest.cc
index d501b5d782d..d07dfa041f1 100644
--- a/chromium/components/autofill/core/browser/contact_info_unittest.cc
+++ b/chromium/components/autofill/core/browser/contact_info_unittest.cc
@@ -25,47 +25,53 @@ struct FullNameTestCase {
std::string given_name_output;
std::string middle_name_output;
std::string family_name_output;
-} full_name_test_cases[] = {
- { "", "", "", "" },
- { "John Smith", "John", "", "Smith" },
- { "Julien van der Poel", "Julien", "", "van der Poel" },
- { "John J Johnson", "John", "J", "Johnson" },
- { "John Smith, Jr.", "John", "", "Smith" },
- { "Mr John Smith", "John", "", "Smith" },
- { "Mr. John Smith", "John", "", "Smith" },
- { "Mr. John Smith, M.D.", "John", "", "Smith" },
- { "Mr. John Smith, MD", "John", "", "Smith" },
- { "Mr. John Smith MD", "John", "", "Smith" },
- { "William Hubert J.R.", "William", "Hubert", "J.R." },
- { "John Ma", "John", "", "Ma" },
- { "John Smith, MA", "John", "", "Smith" },
- { "John Jacob Jingleheimer Smith", "John Jacob", "Jingleheimer", "Smith" },
- { "Virgil", "Virgil", "", "" },
- { "Murray Gell-Mann", "Murray", "", "Gell-Mann" },
- { "Mikhail Yevgrafovich Saltykov-Shchedrin", "Mikhail", "Yevgrafovich",
- "Saltykov-Shchedrin" },
- { "Arthur Ignatius Conan Doyle", "Arthur Ignatius", "Conan", "Doyle" },
};
-TEST(NameInfoTest, SetFullName) {
- for (const FullNameTestCase& test_case : full_name_test_cases) {
- SCOPED_TRACE(test_case.full_name_input);
+class SetFullNameTest : public testing::TestWithParam<FullNameTestCase> {};
- NameInfo name;
- name.SetInfo(AutofillType(NAME_FULL),
- ASCIIToUTF16(test_case.full_name_input),
- "en-US");
- EXPECT_EQ(ASCIIToUTF16(test_case.given_name_output),
- name.GetInfo(AutofillType(NAME_FIRST), "en-US"));
- EXPECT_EQ(ASCIIToUTF16(test_case.middle_name_output),
- name.GetInfo(AutofillType(NAME_MIDDLE), "en-US"));
- EXPECT_EQ(ASCIIToUTF16(test_case.family_name_output),
- name.GetInfo(AutofillType(NAME_LAST), "en-US"));
- EXPECT_EQ(ASCIIToUTF16(test_case.full_name_input),
- name.GetInfo(AutofillType(NAME_FULL), "en-US"));
- }
+TEST_P(SetFullNameTest, SetFullName) {
+ auto test_case = GetParam();
+ SCOPED_TRACE(test_case.full_name_input);
+
+ NameInfo name;
+ name.SetInfo(AutofillType(NAME_FULL), ASCIIToUTF16(test_case.full_name_input),
+ "en-US");
+ EXPECT_EQ(ASCIIToUTF16(test_case.given_name_output),
+ name.GetInfo(AutofillType(NAME_FIRST), "en-US"));
+ EXPECT_EQ(ASCIIToUTF16(test_case.middle_name_output),
+ name.GetInfo(AutofillType(NAME_MIDDLE), "en-US"));
+ EXPECT_EQ(ASCIIToUTF16(test_case.family_name_output),
+ name.GetInfo(AutofillType(NAME_LAST), "en-US"));
+ EXPECT_EQ(ASCIIToUTF16(test_case.full_name_input),
+ name.GetInfo(AutofillType(NAME_FULL), "en-US"));
}
+INSTANTIATE_TEST_CASE_P(
+ ContactInfoTest,
+ SetFullNameTest,
+ testing::Values(
+ FullNameTestCase{"", "", "", ""},
+ FullNameTestCase{"John Smith", "John", "", "Smith"},
+ FullNameTestCase{"Julien van der Poel", "Julien", "", "van der Poel"},
+ FullNameTestCase{"John J Johnson", "John", "J", "Johnson"},
+ FullNameTestCase{"John Smith, Jr.", "John", "", "Smith"},
+ FullNameTestCase{"Mr John Smith", "John", "", "Smith"},
+ FullNameTestCase{"Mr. John Smith", "John", "", "Smith"},
+ FullNameTestCase{"Mr. John Smith, M.D.", "John", "", "Smith"},
+ FullNameTestCase{"Mr. John Smith, MD", "John", "", "Smith"},
+ FullNameTestCase{"Mr. John Smith MD", "John", "", "Smith"},
+ FullNameTestCase{"William Hubert J.R.", "William", "Hubert", "J.R."},
+ FullNameTestCase{"John Ma", "John", "", "Ma"},
+ FullNameTestCase{"John Smith, MA", "John", "", "Smith"},
+ FullNameTestCase{"John Jacob Jingleheimer Smith", "John Jacob",
+ "Jingleheimer", "Smith"},
+ FullNameTestCase{"Virgil", "Virgil", "", ""},
+ FullNameTestCase{"Murray Gell-Mann", "Murray", "", "Gell-Mann"},
+ FullNameTestCase{"Mikhail Yevgrafovich Saltykov-Shchedrin", "Mikhail",
+ "Yevgrafovich", "Saltykov-Shchedrin"},
+ FullNameTestCase{"Arthur Ignatius Conan Doyle", "Arthur Ignatius",
+ "Conan", "Doyle"}));
+
TEST(NameInfoTest, GetFullName) {
NameInfo name;
name.SetRawInfo(NAME_FIRST, ASCIIToUTF16("First"));
@@ -174,209 +180,221 @@ TEST(NameInfoTest, GetFullName) {
name.GetInfo(AutofillType(NAME_FULL), "en-US"));
}
-TEST(NameInfoTest, ParsedNamesAreEqual) {
- struct TestCase {
- std::string starting_names[3];
- std::string additional_names[3];
- bool expected_result;
+struct ParsedNamesAreEqualTestCase {
+ std::string starting_names[3];
+ std::string additional_names[3];
+ bool expected_result;
};
- struct TestCase test_cases[] = {
- // Identical name comparison.
- {{"Marion", "Mitchell", "Morrison"},
- {"Marion", "Mitchell", "Morrison"},
- true},
-
- // Case-sensitive comparisons.
- {{"Marion", "Mitchell", "Morrison"},
- {"Marion", "Mitchell", "MORRISON"},
- false},
- {{"Marion", "Mitchell", "Morrison"},
- {"MARION", "Mitchell", "MORRISON"},
- false},
- {{"Marion", "Mitchell", "Morrison"},
- {"MARION", "MITCHELL", "MORRISON"},
- false},
- {{"Marion", "", "Mitchell Morrison"},
- {"MARION", "", "MITCHELL MORRISON"},
- false},
- {{"Marion Mitchell", "", "Morrison"},
- {"MARION MITCHELL", "", "MORRISON"},
- false},
-
- // Identical full names but different canonical forms.
- {{"Marion", "Mitchell", "Morrison"},
- {"Marion", "", "Mitchell Morrison"},
- false},
- {{"Marion", "Mitchell", "Morrison"},
- {"Marion Mitchell", "", "MORRISON"},
- false},
-
- // Different names.
- {{"Marion", "Mitchell", "Morrison"}, {"Marion", "M.", "Morrison"}, false},
- {{"Marion", "Mitchell", "Morrison"}, {"MARION", "M.", "MORRISON"}, false},
- {{"Marion", "Mitchell", "Morrison"},
- {"David", "Mitchell", "Morrison"},
- false},
-
- // Non-ASCII characters.
- {{"M\xc3\xa1rion Mitchell", "", "Morrison"},
- {"M\xc3\xa1rion Mitchell", "", "Morrison"},
- true},
- };
+ class ParsedNamesAreEqualTest
+ : public testing::TestWithParam<ParsedNamesAreEqualTestCase> {};
- for (size_t i = 0; i < arraysize(test_cases); ++i) {
- SCOPED_TRACE(base::StringPrintf("i: %" PRIuS, i));
+ TEST_P(ParsedNamesAreEqualTest, ParsedNamesAreEqual) {
+ auto test_case = GetParam();
// Construct the starting_profile.
NameInfo starting_profile;
starting_profile.SetRawInfo(NAME_FIRST,
- UTF8ToUTF16(test_cases[i].starting_names[0]));
+ UTF8ToUTF16(test_case.starting_names[0]));
starting_profile.SetRawInfo(NAME_MIDDLE,
- UTF8ToUTF16(test_cases[i].starting_names[1]));
+ UTF8ToUTF16(test_case.starting_names[1]));
starting_profile.SetRawInfo(NAME_LAST,
- UTF8ToUTF16(test_cases[i].starting_names[2]));
+ UTF8ToUTF16(test_case.starting_names[2]));
// Construct the additional_profile.
NameInfo additional_profile;
- additional_profile.SetRawInfo(
- NAME_FIRST, UTF8ToUTF16(test_cases[i].additional_names[0]));
- additional_profile.SetRawInfo(
- NAME_MIDDLE, UTF8ToUTF16(test_cases[i].additional_names[1]));
- additional_profile.SetRawInfo(
- NAME_LAST, UTF8ToUTF16(test_cases[i].additional_names[2]));
+ additional_profile.SetRawInfo(NAME_FIRST,
+ UTF8ToUTF16(test_case.additional_names[0]));
+ additional_profile.SetRawInfo(NAME_MIDDLE,
+ UTF8ToUTF16(test_case.additional_names[1]));
+ additional_profile.SetRawInfo(NAME_LAST,
+ UTF8ToUTF16(test_case.additional_names[2]));
// Verify the test expectations.
- EXPECT_EQ(test_cases[i].expected_result,
+ EXPECT_EQ(test_case.expected_result,
starting_profile.ParsedNamesAreEqual(additional_profile));
}
-}
-TEST(NameInfoTest, OverwriteName) {
- struct TestCase {
+ INSTANTIATE_TEST_CASE_P(
+ ContactInfoTest,
+ ParsedNamesAreEqualTest,
+ testing::Values(
+ // Identical name comparison.
+ ParsedNamesAreEqualTestCase{{"Marion", "Mitchell", "Morrison"},
+ {"Marion", "Mitchell", "Morrison"},
+ true},
+
+ // Case-sensitive comparisons.
+ ParsedNamesAreEqualTestCase{{"Marion", "Mitchell", "Morrison"},
+ {"Marion", "Mitchell", "MORRISON"},
+ false},
+ ParsedNamesAreEqualTestCase{{"Marion", "Mitchell", "Morrison"},
+ {"MARION", "Mitchell", "MORRISON"},
+ false},
+ ParsedNamesAreEqualTestCase{{"Marion", "Mitchell", "Morrison"},
+ {"MARION", "MITCHELL", "MORRISON"},
+ false},
+ ParsedNamesAreEqualTestCase{{"Marion", "", "Mitchell Morrison"},
+ {"MARION", "", "MITCHELL MORRISON"},
+ false},
+ ParsedNamesAreEqualTestCase{{"Marion Mitchell", "", "Morrison"},
+ {"MARION MITCHELL", "", "MORRISON"},
+ false},
+
+ // Identical full names but different canonical forms.
+ ParsedNamesAreEqualTestCase{{"Marion", "Mitchell", "Morrison"},
+ {"Marion", "", "Mitchell Morrison"},
+ false},
+ ParsedNamesAreEqualTestCase{{"Marion", "Mitchell", "Morrison"},
+ {"Marion Mitchell", "", "MORRISON"},
+ false},
+
+ // Different names.
+ ParsedNamesAreEqualTestCase{{"Marion", "Mitchell", "Morrison"},
+ {"Marion", "M.", "Morrison"},
+ false},
+ ParsedNamesAreEqualTestCase{{"Marion", "Mitchell", "Morrison"},
+ {"MARION", "M.", "MORRISON"},
+ false},
+ ParsedNamesAreEqualTestCase{{"Marion", "Mitchell", "Morrison"},
+ {"David", "Mitchell", "Morrison"},
+ false},
+
+ // Non-ASCII characters.
+ ParsedNamesAreEqualTestCase{
+ {"M\xc3\xa1rion Mitchell", "", "Morrison"},
+ {"M\xc3\xa1rion Mitchell", "", "Morrison"},
+ true}));
+
+ struct OverwriteNameTestCase {
std::string existing_name[4];
std::string new_name[4];
std::string expected_name[4];
};
- struct TestCase test_cases[] = {
- // Missing information in the original name gets filled with the new
- // name's information.
- {
- {"", "", "", ""},
- {"Marion", "Mitchell", "Morrison", "Marion Mitchell Morrison"},
- {"Marion", "Mitchell", "Morrison", "Marion Mitchell Morrison"},
- },
- // The new name's values overwrite the exsiting name values if they are
- // different
- {
- {"Marion", "Mitchell", "Morrison", "Marion Mitchell Morrison"},
- {"Mario", "Mitchell", "Thompson", "Mario Mitchell Morrison"},
- {"Mario", "Mitchell", "Thompson", "Mario Mitchell Morrison"},
- },
- // An existing name values do not get replaced with empty values.
- {
- {"Marion", "Mitchell", "Morrison", "Marion Mitchell Morrison"},
- {"", "", "", ""},
- {"Marion", "Mitchell", "Morrison", "Marion Mitchell Morrison"},
- },
- // An existing full middle not does not get replaced by a middle name
- // initial.
- {
- {"Marion", "Mitchell", "Morrison", "Marion Mitchell Morrison"},
- {"Marion", "M", "Morrison", "Marion Mitchell Morrison"},
- {"Marion", "Mitchell", "Morrison", "Marion Mitchell Morrison"},
- },
- // An existing middle name initial is overwritten by the new profile's
- // middle name value.
- {
- {"Marion", "M", "Morrison", "Marion Mitchell Morrison"},
- {"Marion", "Mitchell", "Morrison", "Marion Mitchell Morrison"},
- {"Marion", "Mitchell", "Morrison", "Marion Mitchell Morrison"},
- },
- // A NameInfo with only the full name set overwritten with a NameInfo
- // with only the name parts set result in a NameInfo with all the name
- // parts and name full set.
- {
- {"", "", "", "Marion Mitchell Morrison"},
- {"Marion", "Mitchell", "Morrison", ""},
- {"Marion", "Mitchell", "Morrison", "Marion Mitchell Morrison"},
- },
- // A NameInfo with only the name parts set overwritten with a NameInfo
- // with only the full name set result in a NameInfo with all the name
- // parts and name full set.
- {
- {"Marion", "Mitchell", "Morrison", ""},
- {"", "", "", "Marion Mitchell Morrison"},
- {"Marion", "Mitchell", "Morrison", "Marion Mitchell Morrison"},
- },
- };
-
- for (size_t i = 0; i < arraysize(test_cases); ++i) {
- SCOPED_TRACE(base::StringPrintf("i: %" PRIuS, i));
+ class OverwriteNameTest
+ : public testing::TestWithParam<OverwriteNameTestCase> {};
+ TEST_P(OverwriteNameTest, OverwriteName) {
+ auto test_case = GetParam();
// Construct the starting_profile.
NameInfo existing_name;
existing_name.SetRawInfo(NAME_FIRST,
- UTF8ToUTF16(test_cases[i].existing_name[0]));
+ UTF8ToUTF16(test_case.existing_name[0]));
existing_name.SetRawInfo(NAME_MIDDLE,
- UTF8ToUTF16(test_cases[i].existing_name[1]));
+ UTF8ToUTF16(test_case.existing_name[1]));
existing_name.SetRawInfo(NAME_LAST,
- UTF8ToUTF16(test_cases[i].existing_name[2]));
+ UTF8ToUTF16(test_case.existing_name[2]));
existing_name.SetRawInfo(NAME_FULL,
- UTF8ToUTF16(test_cases[i].existing_name[3]));
+ UTF8ToUTF16(test_case.existing_name[3]));
// Construct the additional_profile.
NameInfo new_name;
- new_name.SetRawInfo(NAME_FIRST, UTF8ToUTF16(test_cases[i].new_name[0]));
- new_name.SetRawInfo(NAME_MIDDLE, UTF8ToUTF16(test_cases[i].new_name[1]));
- new_name.SetRawInfo(NAME_LAST, UTF8ToUTF16(test_cases[i].new_name[2]));
- new_name.SetRawInfo(NAME_FULL, UTF8ToUTF16(test_cases[i].new_name[3]));
+ new_name.SetRawInfo(NAME_FIRST, UTF8ToUTF16(test_case.new_name[0]));
+ new_name.SetRawInfo(NAME_MIDDLE, UTF8ToUTF16(test_case.new_name[1]));
+ new_name.SetRawInfo(NAME_LAST, UTF8ToUTF16(test_case.new_name[2]));
+ new_name.SetRawInfo(NAME_FULL, UTF8ToUTF16(test_case.new_name[3]));
existing_name.OverwriteName(new_name);
// Verify the test expectations.
- EXPECT_EQ(UTF8ToUTF16(test_cases[i].expected_name[0]),
+ EXPECT_EQ(UTF8ToUTF16(test_case.expected_name[0]),
existing_name.GetRawInfo(NAME_FIRST));
- EXPECT_EQ(UTF8ToUTF16(test_cases[i].expected_name[1]),
+ EXPECT_EQ(UTF8ToUTF16(test_case.expected_name[1]),
existing_name.GetRawInfo(NAME_MIDDLE));
- EXPECT_EQ(UTF8ToUTF16(test_cases[i].expected_name[2]),
+ EXPECT_EQ(UTF8ToUTF16(test_case.expected_name[2]),
existing_name.GetRawInfo(NAME_LAST));
- EXPECT_EQ(UTF8ToUTF16(test_cases[i].expected_name[3]),
+ EXPECT_EQ(UTF8ToUTF16(test_case.expected_name[3]),
existing_name.GetRawInfo(NAME_FULL));
- }
}
-TEST(NameInfoTest, NamePartsAreEmpty) {
- struct TestCase {
- std::string first;
- std::string middle;
- std::string last;
- std::string full;
- bool expected_result;
+INSTANTIATE_TEST_CASE_P(
+ ContactInfoTest,
+ OverwriteNameTest,
+ testing::Values(
+ // Missing information in the original name gets filled with the new
+ // name's information.
+ OverwriteNameTestCase{
+ {"", "", "", ""},
+ {"Marion", "Mitchell", "Morrison", "Marion Mitchell Morrison"},
+ {"Marion", "Mitchell", "Morrison", "Marion Mitchell Morrison"},
+ },
+ // The new name's values overwrite the exsiting name values if they are
+ // different
+ OverwriteNameTestCase{
+ {"Marion", "Mitchell", "Morrison", "Marion Mitchell Morrison"},
+ {"Mario", "Mitchell", "Thompson", "Mario Mitchell Morrison"},
+ {"Mario", "Mitchell", "Thompson", "Mario Mitchell Morrison"},
+ },
+ // An existing name values do not get replaced with empty values.
+ OverwriteNameTestCase{
+ {"Marion", "Mitchell", "Morrison", "Marion Mitchell Morrison"},
+ {"", "", "", ""},
+ {"Marion", "Mitchell", "Morrison", "Marion Mitchell Morrison"},
+ },
+ // An existing full middle not does not get replaced by a middle name
+ // initial.
+ OverwriteNameTestCase{
+ {"Marion", "Mitchell", "Morrison", "Marion Mitchell Morrison"},
+ {"Marion", "M", "Morrison", "Marion Mitchell Morrison"},
+ {"Marion", "Mitchell", "Morrison", "Marion Mitchell Morrison"},
+ },
+ // An existing middle name initial is overwritten by the new profile's
+ // middle name value.
+ OverwriteNameTestCase{
+ {"Marion", "M", "Morrison", "Marion Mitchell Morrison"},
+ {"Marion", "Mitchell", "Morrison", "Marion Mitchell Morrison"},
+ {"Marion", "Mitchell", "Morrison", "Marion Mitchell Morrison"},
+ },
+ // A NameInfo with only the full name set overwritten with a NameInfo
+ // with only the name parts set result in a NameInfo with all the name
+ // parts and name full set.
+ OverwriteNameTestCase{
+ {"", "", "", "Marion Mitchell Morrison"},
+ {"Marion", "Mitchell", "Morrison", ""},
+ {"Marion", "Mitchell", "Morrison", "Marion Mitchell Morrison"},
+ },
+ // A NameInfo with only the name parts set overwritten with a NameInfo
+ // with only the full name set result in a NameInfo with all the name
+ // parts and name full set.
+ OverwriteNameTestCase{
+ {"Marion", "Mitchell", "Morrison", ""},
+ {"", "", "", "Marion Mitchell Morrison"},
+ {"Marion", "Mitchell", "Morrison", "Marion Mitchell Morrison"},
+ }));
+
+struct NamePartsAreEmptyTestCase {
+ std::string first;
+ std::string middle;
+ std::string last;
+ std::string full;
+ bool expected_result;
};
- struct TestCase test_cases[] = {
- {"", "", "", "", true},
- {"", "", "", "Marion Mitchell Morrison", true},
- {"Marion", "", "", "", false},
- {"", "Mitchell", "", "", false},
- {"", "", "Morrison", "", false},
- };
-
- for (size_t i = 0; i < arraysize(test_cases); ++i) {
- SCOPED_TRACE(base::StringPrintf("i: %" PRIuS, i));
+ class NamePartsAreEmptyTest
+ : public testing::TestWithParam<NamePartsAreEmptyTestCase> {};
+ TEST_P(NamePartsAreEmptyTest, NamePartsAreEmpty) {
+ auto test_case = GetParam();
// Construct the NameInfo.
NameInfo name;
- name.SetRawInfo(NAME_FIRST, UTF8ToUTF16(test_cases[i].first));
- name.SetRawInfo(NAME_MIDDLE, UTF8ToUTF16(test_cases[i].middle));
- name.SetRawInfo(NAME_LAST, UTF8ToUTF16(test_cases[i].last));
- name.SetRawInfo(NAME_FULL, UTF8ToUTF16(test_cases[i].full));
+ name.SetRawInfo(NAME_FIRST, UTF8ToUTF16(test_case.first));
+ name.SetRawInfo(NAME_MIDDLE, UTF8ToUTF16(test_case.middle));
+ name.SetRawInfo(NAME_LAST, UTF8ToUTF16(test_case.last));
+ name.SetRawInfo(NAME_FULL, UTF8ToUTF16(test_case.full));
// Verify the test expectations.
- EXPECT_EQ(test_cases[i].expected_result, name.NamePartsAreEmpty());
- }
+ EXPECT_EQ(test_case.expected_result, name.NamePartsAreEmpty());
}
+INSTANTIATE_TEST_CASE_P(
+ ContactInfoTest,
+ NamePartsAreEmptyTest,
+ testing::Values(NamePartsAreEmptyTestCase{"", "", "", "", true},
+ NamePartsAreEmptyTestCase{"", "", "",
+ "Marion Mitchell Morrison", true},
+ NamePartsAreEmptyTestCase{"Marion", "", "", "", false},
+ NamePartsAreEmptyTestCase{"", "Mitchell", "", "", false},
+ NamePartsAreEmptyTestCase{"", "", "Morrison", "", false}));
+
} // namespace autofill
diff --git a/chromium/components/autofill/core/browser/country_combobox_model.h b/chromium/components/autofill/core/browser/country_combobox_model.h
index b3d90c3abf6..4e36d91ba45 100644
--- a/chromium/components/autofill/core/browser/country_combobox_model.h
+++ b/chromium/components/autofill/core/browser/country_combobox_model.h
@@ -38,6 +38,8 @@ class CountryComboboxModel : public ui::ComboboxModel {
base::string16 GetItemAt(int index) override;
bool IsItemSeparatorAt(int index) override;
+ // The list of countries always has the default country at the top as well as
+ // within the sorted vector.
const CountryVector& countries() const { return countries_; }
// Returns the default country code for this model.
diff --git a/chromium/components/autofill/core/browser/country_names.cc b/chromium/components/autofill/core/browser/country_names.cc
index bbf1fb6c0ae..2f9a022e363 100644
--- a/chromium/components/autofill/core/browser/country_names.cc
+++ b/chromium/components/autofill/core/browser/country_names.cc
@@ -24,7 +24,7 @@ namespace {
// A copy of the application locale string, which should be ready for
// CountryName's construction.
-static base::LazyInstance<std::string> g_application_locale =
+static base::LazyInstance<std::string>::DestructorAtExit g_application_locale =
LAZY_INSTANCE_INITIALIZER;
// Returns the ICU sort key corresponding to |str| for the given |collator|.
diff --git a/chromium/components/autofill/core/browser/credit_card.cc b/chromium/components/autofill/core/browser/credit_card.cc
index bd5110eced3..0e54c44176a 100644
--- a/chromium/components/autofill/core/browser/credit_card.cc
+++ b/chromium/components/autofill/core/browser/credit_card.cc
@@ -13,6 +13,7 @@
#include "base/guid.h"
#include "base/i18n/time_formatting.h"
+#include "base/i18n/unicodestring.h"
#include "base/logging.h"
#include "base/macros.h"
#include "base/metrics/histogram_macros.h"
@@ -870,7 +871,8 @@ bool CreditCard::ConvertMonth(const base::string16& month,
int32_t num_months;
const icu::UnicodeString* months = date_format_symbols.getMonths(num_months);
for (int32_t i = 0; i < num_months; ++i) {
- const base::string16 icu_month(months[i].getBuffer(), months[i].length());
+ const base::string16 icu_month(
+ base::i18n::UnicodeStringToString16(months[i]));
if (compare.StringsEqual(icu_month, month)) {
*num = i + 1; // Adjust from 0-indexed to 1-indexed.
return true;
@@ -883,7 +885,7 @@ bool CreditCard::ConvertMonth(const base::string16& month,
base::string16 trimmed_month;
base::TrimString(month, ASCIIToUTF16("."), &trimmed_month);
for (int32_t i = 0; i < num_months; ++i) {
- base::string16 icu_month(months[i].getBuffer(), months[i].length());
+ base::string16 icu_month(base::i18n::UnicodeStringToString16(months[i]));
base::TrimString(icu_month, ASCIIToUTF16("."), &icu_month);
if (compare.StringsEqual(icu_month, trimmed_month)) {
*num = i + 1; // Adjust from 0-indexed to 1-indexed.
diff --git a/chromium/components/autofill/core/browser/credit_card_field.h b/chromium/components/autofill/core/browser/credit_card_field.h
index a737add0440..3d462507fb7 100644
--- a/chromium/components/autofill/core/browser/credit_card_field.h
+++ b/chromium/components/autofill/core/browser/credit_card_field.h
@@ -27,7 +27,7 @@ class CreditCardField : public FormField {
void AddClassifications(FieldCandidatesMap* field_candidates) const override;
private:
- friend class CreditCardFieldTest;
+ friend class CreditCardFieldTestBase;
// Returns true if |scanner| points to a field that looks like a month
// <select>.
diff --git a/chromium/components/autofill/core/browser/credit_card_field_unittest.cc b/chromium/components/autofill/core/browser/credit_card_field_unittest.cc
index 5b44a651d9c..bb7b6b252d1 100644
--- a/chromium/components/autofill/core/browser/credit_card_field_unittest.cc
+++ b/chromium/components/autofill/core/browser/credit_card_field_unittest.cc
@@ -19,10 +19,10 @@ using base::ASCIIToUTF16;
namespace autofill {
-class CreditCardFieldTest : public testing::Test {
+class CreditCardFieldTestBase {
public:
- CreditCardFieldTest() {}
- ~CreditCardFieldTest() override {}
+ CreditCardFieldTestBase() {}
+ ~CreditCardFieldTestBase() {}
protected:
std::vector<std::unique_ptr<AutofillField>> list_;
@@ -59,6 +59,15 @@ class CreditCardFieldTest : public testing::Test {
}
private:
+ DISALLOW_COPY_AND_ASSIGN(CreditCardFieldTestBase);
+};
+
+class CreditCardFieldTest : public CreditCardFieldTestBase,
+ public testing::Test {
+ public:
+ CreditCardFieldTest() {}
+
+ private:
DISALLOW_COPY_AND_ASSIGN(CreditCardFieldTest);
};
@@ -292,124 +301,144 @@ TEST_F(CreditCardFieldTest, ParseExpMonthYear2) {
field_candidates_map_[ASCIIToUTF16("year4")].BestHeuristicType());
}
-TEST_F(CreditCardFieldTest, ParseExpField) {
- typedef struct {
- const std::string label;
- const int max_length;
- const ServerFieldType expected_prediction;
- } TestCase;
-
- TestCase test_cases[] = {
- // General label, no maxlength.
- {"Expiration Date", 0, CREDIT_CARD_EXP_DATE_4_DIGIT_YEAR},
- // General label, maxlength 4.
- {"Expiration Date", 4, CREDIT_CARD_EXP_DATE_2_DIGIT_YEAR},
- // General label, maxlength 5.
- {"Expiration Date", 5, CREDIT_CARD_EXP_DATE_2_DIGIT_YEAR},
- // General label, maxlength 6.
- {"Expiration Date", 6, CREDIT_CARD_EXP_DATE_4_DIGIT_YEAR},
- // General label, maxlength 7.
- {"Expiration Date", 7, CREDIT_CARD_EXP_DATE_4_DIGIT_YEAR},
- // General label, large maxlength.
- {"Expiration Date", 12, CREDIT_CARD_EXP_DATE_4_DIGIT_YEAR},
-
- // Unsupported maxlength, general label.
- {"Expiration Date", 3, UNKNOWN_TYPE},
- // Unsupported maxlength, two digit year label.
- {"Expiration Date (MM/YY)", 3, UNKNOWN_TYPE},
- // Unsupported maxlength, four digit year label.
- {"Expiration Date (MM/YYYY)", 3, UNKNOWN_TYPE},
-
- // Two digit year, simple label.
- {"MM / YY", 0, CREDIT_CARD_EXP_DATE_2_DIGIT_YEAR},
- // Two digit year, with slash (MM/YY).
- {"Expiration Date (MM/YY)", 0, CREDIT_CARD_EXP_DATE_2_DIGIT_YEAR},
- // Two digit year, no slash (MMYY).
- {"Expiration Date (MMYY)", 4, CREDIT_CARD_EXP_DATE_2_DIGIT_YEAR},
- // Two digit year, with slash and maxlength (MM/YY).
- {"Expiration Date (MM/YY)", 5, CREDIT_CARD_EXP_DATE_2_DIGIT_YEAR},
- // Two digit year, with slash and large maxlength (MM/YY).
- {"Expiration Date (MM/YY)", 12, CREDIT_CARD_EXP_DATE_2_DIGIT_YEAR},
-
- // Four digit year, simple label.
- {"MM / YYYY", 0, CREDIT_CARD_EXP_DATE_4_DIGIT_YEAR},
- // Four digit year, with slash (MM/YYYY).
- {"Expiration Date (MM/YYYY)", 0, CREDIT_CARD_EXP_DATE_4_DIGIT_YEAR},
- // Four digit year, no slash (MMYYYY).
- {"Expiration Date (MMYYYY)", 6, CREDIT_CARD_EXP_DATE_4_DIGIT_YEAR},
- // Four digit year, with slash and maxlength (MM/YYYY).
- {"Expiration Date (MM/YYYY)", 7, CREDIT_CARD_EXP_DATE_4_DIGIT_YEAR},
- // Four digit year, with slash and large maxlength (MM/YYYY).
- {"Expiration Date (MM/YYYY)", 12, CREDIT_CARD_EXP_DATE_4_DIGIT_YEAR},
-
- // Four digit year label with restrictive maxlength (4).
- {"Expiration Date (MM/YYYY)", 4, CREDIT_CARD_EXP_DATE_2_DIGIT_YEAR},
- // Four digit year label with restrictive maxlength (5).
- {"Expiration Date (MM/YYYY)", 5, CREDIT_CARD_EXP_DATE_2_DIGIT_YEAR},
- };
-
- for (const TestCase &test_case : test_cases) {
- // Clean up after previous test cases.
- list_.clear();
- field_.reset();
- field_candidates_map_.clear();
-
- FormFieldData field;
- field.form_control_type = "text";
-
- field.label = ASCIIToUTF16("Name on Card");
- field.name = ASCIIToUTF16("name_on_card");
- list_.push_back(
- base::MakeUnique<AutofillField>(field, ASCIIToUTF16("name1")));
-
- field.label = ASCIIToUTF16("Card Number");
- field.name = ASCIIToUTF16("card_number");
- list_.push_back(
- base::MakeUnique<AutofillField>(field, ASCIIToUTF16("num2")));
-
- field.label = ASCIIToUTF16(test_case.label);
- if (test_case.max_length != 0) {
- field.max_length = test_case.max_length;
- }
- field.name = ASCIIToUTF16("cc_exp");
- list_.push_back(
- base::MakeUnique<AutofillField>(field, ASCIIToUTF16("exp3")));
-
- Parse();
-
- // Assists in identifing which case has failed.
- SCOPED_TRACE(test_case.expected_prediction);
- SCOPED_TRACE(test_case.max_length);
- SCOPED_TRACE(test_case.label);
-
- if (test_case.expected_prediction == UNKNOWN_TYPE) {
- // Expect failure and continue to next test case.
- // The expiry date is a required field for credit card forms, and thus the
- // parse sets |field_| to nullptr.
- EXPECT_EQ(nullptr, field_.get());
- continue;
- }
+typedef struct {
+ const std::string label;
+ const int max_length;
+ const ServerFieldType expected_prediction;
+} ParseExpFieldTestCase;
+
+class ParseExpFieldTest : public CreditCardFieldTestBase,
+ public testing::TestWithParam<ParseExpFieldTestCase> {
+};
+
+TEST_P(ParseExpFieldTest, ParseExpField) {
+ auto test_case = GetParam();
+ // Clean up after previous test cases.
+ list_.clear();
+ field_.reset();
+ field_candidates_map_.clear();
+
+ FormFieldData field;
+ field.form_control_type = "text";
+
+ field.label = ASCIIToUTF16("Name on Card");
+ field.name = ASCIIToUTF16("name_on_card");
+ list_.push_back(
+ base::MakeUnique<AutofillField>(field, ASCIIToUTF16("name1")));
- // Ensure that the form was determined as valid.
- ASSERT_NE(nullptr, field_.get());
- AddClassifications();
- ASSERT_TRUE(field_candidates_map_.find(ASCIIToUTF16("name1")) !=
- field_candidates_map_.end());
- EXPECT_EQ(CREDIT_CARD_NAME_FULL,
- field_candidates_map_[ASCIIToUTF16("name1")].BestHeuristicType());
-
- ASSERT_TRUE(field_candidates_map_.find(ASCIIToUTF16("num2")) !=
- field_candidates_map_.end());
- EXPECT_EQ(CREDIT_CARD_NUMBER,
- field_candidates_map_[ASCIIToUTF16("num2")].BestHeuristicType());
-
- ASSERT_TRUE(field_candidates_map_.find(ASCIIToUTF16("exp3")) !=
- field_candidates_map_.end());
- EXPECT_EQ(test_case.expected_prediction,
- field_candidates_map_[ASCIIToUTF16("exp3")].BestHeuristicType());
+ field.label = ASCIIToUTF16("Card Number");
+ field.name = ASCIIToUTF16("card_number");
+ list_.push_back(base::MakeUnique<AutofillField>(field, ASCIIToUTF16("num2")));
+
+ field.label = ASCIIToUTF16(test_case.label);
+ if (test_case.max_length != 0) {
+ field.max_length = test_case.max_length;
+ }
+ field.name = ASCIIToUTF16("cc_exp");
+ list_.push_back(base::MakeUnique<AutofillField>(field, ASCIIToUTF16("exp3")));
+
+ Parse();
+
+ // Assists in identifing which case has failed.
+ SCOPED_TRACE(test_case.expected_prediction);
+ SCOPED_TRACE(test_case.max_length);
+ SCOPED_TRACE(test_case.label);
+
+ if (test_case.expected_prediction == UNKNOWN_TYPE) {
+ // Expect failure and continue to next test case.
+ // The expiry date is a required field for credit card forms, and thus the
+ // parse sets |field_| to nullptr.
+ EXPECT_EQ(nullptr, field_.get());
+ return;
}
+
+ // Ensure that the form was determined as valid.
+ ASSERT_NE(nullptr, field_.get());
+ AddClassifications();
+ ASSERT_TRUE(field_candidates_map_.find(ASCIIToUTF16("name1")) !=
+ field_candidates_map_.end());
+ EXPECT_EQ(CREDIT_CARD_NAME_FULL,
+ field_candidates_map_[ASCIIToUTF16("name1")].BestHeuristicType());
+
+ ASSERT_TRUE(field_candidates_map_.find(ASCIIToUTF16("num2")) !=
+ field_candidates_map_.end());
+ EXPECT_EQ(CREDIT_CARD_NUMBER,
+ field_candidates_map_[ASCIIToUTF16("num2")].BestHeuristicType());
+
+ ASSERT_TRUE(field_candidates_map_.find(ASCIIToUTF16("exp3")) !=
+ field_candidates_map_.end());
+ EXPECT_EQ(test_case.expected_prediction,
+ field_candidates_map_[ASCIIToUTF16("exp3")].BestHeuristicType());
}
+INSTANTIATE_TEST_CASE_P(
+ CreditCardFieldTest,
+ ParseExpFieldTest,
+ testing::Values(
+ // General label, no maxlength.
+ ParseExpFieldTestCase{"Expiration Date", 0,
+ CREDIT_CARD_EXP_DATE_4_DIGIT_YEAR},
+ // General label, maxlength 4.
+ ParseExpFieldTestCase{"Expiration Date", 4,
+ CREDIT_CARD_EXP_DATE_2_DIGIT_YEAR},
+ // General label, maxlength 5.
+ ParseExpFieldTestCase{"Expiration Date", 5,
+ CREDIT_CARD_EXP_DATE_2_DIGIT_YEAR},
+ // General label, maxlength 6.
+ ParseExpFieldTestCase{"Expiration Date", 6,
+ CREDIT_CARD_EXP_DATE_4_DIGIT_YEAR},
+ // General label, maxlength 7.
+ ParseExpFieldTestCase{"Expiration Date", 7,
+ CREDIT_CARD_EXP_DATE_4_DIGIT_YEAR},
+ // General label, large maxlength.
+ ParseExpFieldTestCase{"Expiration Date", 12,
+ CREDIT_CARD_EXP_DATE_4_DIGIT_YEAR},
+
+ // Unsupported maxlength, general label.
+ ParseExpFieldTestCase{"Expiration Date", 3, UNKNOWN_TYPE},
+ // Unsupported maxlength, two digit year label.
+ ParseExpFieldTestCase{"Expiration Date (MM/YY)", 3, UNKNOWN_TYPE},
+ // Unsupported maxlength, four digit year label.
+ ParseExpFieldTestCase{"Expiration Date (MM/YYYY)", 3, UNKNOWN_TYPE},
+
+ // Two digit year, simple label.
+ ParseExpFieldTestCase{"MM / YY", 0, CREDIT_CARD_EXP_DATE_2_DIGIT_YEAR},
+ // Two digit year, with slash (MM/YY).
+ ParseExpFieldTestCase{"Expiration Date (MM/YY)", 0,
+ CREDIT_CARD_EXP_DATE_2_DIGIT_YEAR},
+ // Two digit year, no slash (MMYY).
+ ParseExpFieldTestCase{"Expiration Date (MMYY)", 4,
+ CREDIT_CARD_EXP_DATE_2_DIGIT_YEAR},
+ // Two digit year, with slash and maxlength (MM/YY).
+ ParseExpFieldTestCase{"Expiration Date (MM/YY)", 5,
+ CREDIT_CARD_EXP_DATE_2_DIGIT_YEAR},
+ // Two digit year, with slash and large maxlength (MM/YY).
+ ParseExpFieldTestCase{"Expiration Date (MM/YY)", 12,
+ CREDIT_CARD_EXP_DATE_2_DIGIT_YEAR},
+
+ // Four digit year, simple label.
+ ParseExpFieldTestCase{"MM / YYYY", 0,
+ CREDIT_CARD_EXP_DATE_4_DIGIT_YEAR},
+ // Four digit year, with slash (MM/YYYY).
+ ParseExpFieldTestCase{"Expiration Date (MM/YYYY)", 0,
+ CREDIT_CARD_EXP_DATE_4_DIGIT_YEAR},
+ // Four digit year, no slash (MMYYYY).
+ ParseExpFieldTestCase{"Expiration Date (MMYYYY)", 6,
+ CREDIT_CARD_EXP_DATE_4_DIGIT_YEAR},
+ // Four digit year, with slash and maxlength (MM/YYYY).
+ ParseExpFieldTestCase{"Expiration Date (MM/YYYY)", 7,
+ CREDIT_CARD_EXP_DATE_4_DIGIT_YEAR},
+ // Four digit year, with slash and large maxlength (MM/YYYY).
+ ParseExpFieldTestCase{"Expiration Date (MM/YYYY)", 12,
+ CREDIT_CARD_EXP_DATE_4_DIGIT_YEAR},
+
+ // Four digit year label with restrictive maxlength (4).
+ ParseExpFieldTestCase{"Expiration Date (MM/YYYY)", 4,
+ CREDIT_CARD_EXP_DATE_2_DIGIT_YEAR},
+ // Four digit year label with restrictive maxlength (5).
+ ParseExpFieldTestCase{"Expiration Date (MM/YYYY)", 5,
+ CREDIT_CARD_EXP_DATE_2_DIGIT_YEAR}));
+
TEST_F(CreditCardFieldTest, ParseCreditCardHolderNameWithCCFullName) {
FormFieldData field;
field.form_control_type = "text";
diff --git a/chromium/components/autofill/core/browser/credit_card_unittest.cc b/chromium/components/autofill/core/browser/credit_card_unittest.cc
index 993862f6d6d..4e371ec4656 100644
--- a/chromium/components/autofill/core/browser/credit_card_unittest.cc
+++ b/chromium/components/autofill/core/browser/credit_card_unittest.cc
@@ -158,77 +158,90 @@ TEST(CreditCardTest, AssignmentOperator) {
EXPECT_TRUE(a == b);
}
-TEST(CreditCardTest, SetExpirationYearFromString) {
- static const struct {
- std::string expiration_year;
- int expected_year;
- } kTestCases[] = {
- // Valid values.
- {"2040", 2040},
- {"45", 2045},
- {"045", 2045},
- {"9", 2009},
-
- // Unrecognized year values.
- {"052045", 0},
- {"123", 0},
- {"y2045", 0},
- };
+struct SetExpirationYearFromStringTestCase {
+ std::string expiration_year;
+ int expected_year;
+};
- for (const auto& test_case : kTestCases) {
- CreditCard card(base::GenerateGUID(), "some origin");
- card.SetExpirationYearFromString(ASCIIToUTF16(test_case.expiration_year));
+class SetExpirationYearFromStringTest
+ : public testing::TestWithParam<SetExpirationYearFromStringTestCase> {};
- EXPECT_EQ(test_case.expected_year, card.expiration_year())
- << test_case.expiration_year << " " << test_case.expected_year;
- }
+TEST_P(SetExpirationYearFromStringTest, SetExpirationYearFromString) {
+ auto test_case = GetParam();
+ CreditCard card(base::GenerateGUID(), "some origin");
+ card.SetExpirationYearFromString(ASCIIToUTF16(test_case.expiration_year));
+
+ EXPECT_EQ(test_case.expected_year, card.expiration_year())
+ << test_case.expiration_year << " " << test_case.expected_year;
}
-TEST(CreditCardTest, SetExpirationDateFromString) {
- static const struct {
- std::string expiration_date;
- int expected_month;
- int expected_year;
- } kTestCases[] = {{"10", 0, 0}, // Too small.
- {"1020451", 0, 0}, // Too long.
-
- // No separators.
- {"105", 0, 0}, // Too ambiguous.
- {"0545", 5, 2045},
- {"52045", 0, 0}, // Too ambiguous.
- {"052045", 5, 2045},
-
- // "/" separator.
- {"05/45", 5, 2045},
- {"5/2045", 5, 2045},
- {"05/2045", 5, 2045},
-
- // "-" separator.
- {"05-45", 5, 2045},
- {"5-2045", 5, 2045},
- {"05-2045", 5, 2045},
-
- // "|" separator.
- {"05|45", 5, 2045},
- {"5|2045", 5, 2045},
- {"05|2045", 5, 2045},
-
- // Invalid values.
- {"13/2016", 0, 2016},
- {"16/13", 0, 2013},
- {"May-2015", 0, 0},
- {"05-/2045", 0, 0},
- {"05_2045", 0, 0}};
+INSTANTIATE_TEST_CASE_P(CreditCardTest,
+ SetExpirationYearFromStringTest,
+ testing::Values(
+ // Valid values.
+ SetExpirationYearFromStringTestCase{"2040", 2040},
+ SetExpirationYearFromStringTestCase{"45", 2045},
+ SetExpirationYearFromStringTestCase{"045", 2045},
+ SetExpirationYearFromStringTestCase{"9", 2009},
+
+ // Unrecognized year values.
+ SetExpirationYearFromStringTestCase{"052045", 0},
+ SetExpirationYearFromStringTestCase{"123", 0},
+ SetExpirationYearFromStringTestCase{"y2045", 0}));
+
+struct SetExpirationDateFromStringTestCase {
+ std::string expiration_date;
+ int expected_month;
+ int expected_year;
+};
- for (const auto& test_case : kTestCases) {
- CreditCard card(base::GenerateGUID(), "some origin");
- card.SetExpirationDateFromString(ASCIIToUTF16(test_case.expiration_date));
+class SetExpirationDateFromStringTest
+ : public testing::TestWithParam<SetExpirationDateFromStringTestCase> {};
- EXPECT_EQ(test_case.expected_month, card.expiration_month());
- EXPECT_EQ(test_case.expected_year, card.expiration_year());
- }
+TEST_P(SetExpirationDateFromStringTest, SetExpirationDateFromString) {
+ auto test_case = GetParam();
+ CreditCard card(base::GenerateGUID(), "some origin");
+ card.SetExpirationDateFromString(ASCIIToUTF16(test_case.expiration_date));
+
+ EXPECT_EQ(test_case.expected_month, card.expiration_month());
+ EXPECT_EQ(test_case.expected_year, card.expiration_year());
}
+INSTANTIATE_TEST_CASE_P(
+ CreditCardTest,
+ SetExpirationDateFromStringTest,
+ testing::Values(
+ SetExpirationDateFromStringTestCase{"10", 0, 0}, // Too small.
+ SetExpirationDateFromStringTestCase{"1020451", 0, 0}, // Too long.
+
+ // No separators.
+ SetExpirationDateFromStringTestCase{"105", 0, 0}, // Too ambiguous.
+ SetExpirationDateFromStringTestCase{"0545", 5, 2045},
+ SetExpirationDateFromStringTestCase{"52045", 0, 0}, // Too ambiguous.
+ SetExpirationDateFromStringTestCase{"052045", 5, 2045},
+
+ // "/" separator.
+ SetExpirationDateFromStringTestCase{"05/45", 5, 2045},
+ SetExpirationDateFromStringTestCase{"5/2045", 5, 2045},
+ SetExpirationDateFromStringTestCase{"05/2045", 5, 2045},
+
+ // "-" separator.
+ SetExpirationDateFromStringTestCase{"05-45", 5, 2045},
+ SetExpirationDateFromStringTestCase{"5-2045", 5, 2045},
+ SetExpirationDateFromStringTestCase{"05-2045", 5, 2045},
+
+ // "|" separator.
+ SetExpirationDateFromStringTestCase{"05|45", 5, 2045},
+ SetExpirationDateFromStringTestCase{"5|2045", 5, 2045},
+ SetExpirationDateFromStringTestCase{"05|2045", 5, 2045},
+
+ // Invalid values.
+ SetExpirationDateFromStringTestCase{"13/2016", 0, 2016},
+ SetExpirationDateFromStringTestCase{"16/13", 0, 2013},
+ SetExpirationDateFromStringTestCase{"May-2015", 0, 0},
+ SetExpirationDateFromStringTestCase{"05-/2045", 0, 0},
+ SetExpirationDateFromStringTestCase{"05_2045", 0, 0}));
+
TEST(CreditCardTest, Copy) {
CreditCard a(base::GenerateGUID(), "https://www.example.com");
test::SetCreditCardInfo(&a, "John Dillinger", "123456789012", "01", "2010");
@@ -238,73 +251,85 @@ TEST(CreditCardTest, Copy) {
EXPECT_TRUE(a == b);
}
-TEST(CreditCardTest, IsLocalDuplicateOfServerCard) {
- struct {
- CreditCard::RecordType first_card_record_type;
- const char* first_card_name;
- const char* first_card_number;
- const char* first_card_exp_mo;
- const char* first_card_exp_yr;
-
- CreditCard::RecordType second_card_record_type;
- const char* second_card_name;
- const char* second_card_number;
- const char* second_card_exp_mo;
- const char* second_card_exp_yr;
- const char* second_card_type;
-
- bool is_local_duplicate;
- } test_cases[] = {
- { LOCAL_CARD, "", "", "", "",
- LOCAL_CARD, "", "", "", "", nullptr, false },
- { LOCAL_CARD, "", "", "", "",
- FULL_SERVER_CARD, "", "", "", "", nullptr, true},
- { FULL_SERVER_CARD, "", "", "", "",
- FULL_SERVER_CARD, "", "", "", "", nullptr, false},
- { LOCAL_CARD, "John Dillinger", "423456789012", "01", "2010",
- FULL_SERVER_CARD, "John Dillinger", "423456789012", "01", "2010", nullptr,
- true },
- { LOCAL_CARD, "J Dillinger", "423456789012", "01", "2010",
- FULL_SERVER_CARD, "John Dillinger", "423456789012", "01", "2010", nullptr,
- false },
- { LOCAL_CARD, "", "423456789012", "01", "2010",
- FULL_SERVER_CARD, "John Dillinger", "423456789012", "01", "2010", nullptr,
- true },
- { LOCAL_CARD, "", "423456789012", "", "",
- FULL_SERVER_CARD, "John Dillinger", "423456789012", "01", "2010", nullptr,
- true },
- { LOCAL_CARD, "", "423456789012", "", "",
- MASKED_SERVER_CARD, "John Dillinger", "9012", "01", "2010", kVisaCard,
- true },
- { LOCAL_CARD, "", "423456789012", "", "",
- MASKED_SERVER_CARD, "John Dillinger", "9012", "01", "2010", kMasterCard,
- false },
- { LOCAL_CARD, "John Dillinger", "4234-5678-9012", "01", "2010",
- FULL_SERVER_CARD, "John Dillinger", "423456789012", "01", "2010", nullptr,
- true },
- };
+struct IsLocalDuplicateOfServerCardTestCase {
+ CreditCard::RecordType first_card_record_type;
+ const char* first_card_name;
+ const char* first_card_number;
+ const char* first_card_exp_mo;
+ const char* first_card_exp_yr;
+
+ CreditCard::RecordType second_card_record_type;
+ const char* second_card_name;
+ const char* second_card_number;
+ const char* second_card_exp_mo;
+ const char* second_card_exp_yr;
+ const char* second_card_type;
+
+ bool is_local_duplicate;
+};
- for (const auto& test_case : test_cases) {
- CreditCard a(base::GenerateGUID(), std::string());
- a.set_record_type(test_case.first_card_record_type);
- test::SetCreditCardInfo(
- &a, test_case.first_card_name, test_case.first_card_number,
- test_case.first_card_exp_mo, test_case.first_card_exp_yr);
+class IsLocalDuplicateOfServerCardTest
+ : public testing::TestWithParam<IsLocalDuplicateOfServerCardTestCase> {};
- CreditCard b(base::GenerateGUID(), std::string());
- b.set_record_type(test_case.second_card_record_type);
- test::SetCreditCardInfo(
- &b, test_case.second_card_name, test_case.second_card_number,
- test_case.second_card_exp_mo, test_case.second_card_exp_yr);
+TEST_P(IsLocalDuplicateOfServerCardTest, IsLocalDuplicateOfServerCard) {
+ auto test_case = GetParam();
+ CreditCard a(base::GenerateGUID(), std::string());
+ a.set_record_type(test_case.first_card_record_type);
+ test::SetCreditCardInfo(
+ &a, test_case.first_card_name, test_case.first_card_number,
+ test_case.first_card_exp_mo, test_case.first_card_exp_yr);
- if (test_case.second_card_record_type == CreditCard::MASKED_SERVER_CARD)
- b.SetTypeForMaskedCard(test_case.second_card_type);
+ CreditCard b(base::GenerateGUID(), std::string());
+ b.set_record_type(test_case.second_card_record_type);
+ test::SetCreditCardInfo(
+ &b, test_case.second_card_name, test_case.second_card_number,
+ test_case.second_card_exp_mo, test_case.second_card_exp_yr);
- EXPECT_EQ(test_case.is_local_duplicate, a.IsLocalDuplicateOfServerCard(b))
- << " when comparing cards " << a.Label() << " and " << b.Label();
- }
+ if (test_case.second_card_record_type == CreditCard::MASKED_SERVER_CARD)
+ b.SetTypeForMaskedCard(test_case.second_card_type);
+
+ EXPECT_EQ(test_case.is_local_duplicate, a.IsLocalDuplicateOfServerCard(b))
+ << " when comparing cards " << a.Label() << " and " << b.Label();
}
+INSTANTIATE_TEST_CASE_P(
+ CreditCardTest,
+ IsLocalDuplicateOfServerCardTest,
+ testing::Values(
+ IsLocalDuplicateOfServerCardTestCase{LOCAL_CARD, "", "", "", "",
+ LOCAL_CARD, "", "", "", "",
+ nullptr, false},
+ IsLocalDuplicateOfServerCardTestCase{LOCAL_CARD, "", "", "", "",
+ FULL_SERVER_CARD, "", "", "", "",
+ nullptr, true},
+ IsLocalDuplicateOfServerCardTestCase{FULL_SERVER_CARD, "", "", "", "",
+ FULL_SERVER_CARD, "", "", "", "",
+ nullptr, false},
+ IsLocalDuplicateOfServerCardTestCase{
+ LOCAL_CARD, "John Dillinger", "423456789012", "01", "2010",
+ FULL_SERVER_CARD, "John Dillinger", "423456789012", "01", "2010",
+ nullptr, true},
+ IsLocalDuplicateOfServerCardTestCase{
+ LOCAL_CARD, "J Dillinger", "423456789012", "01", "2010",
+ FULL_SERVER_CARD, "John Dillinger", "423456789012", "01", "2010",
+ nullptr, false},
+ IsLocalDuplicateOfServerCardTestCase{
+ LOCAL_CARD, "", "423456789012", "01", "2010", FULL_SERVER_CARD,
+ "John Dillinger", "423456789012", "01", "2010", nullptr, true},
+ IsLocalDuplicateOfServerCardTestCase{
+ LOCAL_CARD, "", "423456789012", "", "", FULL_SERVER_CARD,
+ "John Dillinger", "423456789012", "01", "2010", nullptr, true},
+ IsLocalDuplicateOfServerCardTestCase{
+ LOCAL_CARD, "", "423456789012", "", "", MASKED_SERVER_CARD,
+ "John Dillinger", "9012", "01", "2010", kVisaCard, true},
+ IsLocalDuplicateOfServerCardTestCase{
+ LOCAL_CARD, "", "423456789012", "", "", MASKED_SERVER_CARD,
+ "John Dillinger", "9012", "01", "2010", kMasterCard, false},
+ IsLocalDuplicateOfServerCardTestCase{
+ LOCAL_CARD, "John Dillinger", "4234-5678-9012", "01", "2010",
+ FULL_SERVER_CARD, "John Dillinger", "423456789012", "01", "2010",
+ nullptr, true}));
+
TEST(CreditCardTest, HasSameNumberAs) {
CreditCard a(base::GenerateGUID(), std::string());
CreditCard b(base::GenerateGUID(), std::string());
@@ -603,178 +628,223 @@ TEST(CreditCardTest, CreditCardVerificationCode) {
EXPECT_EQ(base::string16(), card.GetRawInfo(CREDIT_CARD_VERIFICATION_CODE));
}
+struct GetCreditCardTypeTestCase {
+ std::string card_number;
+ std::string type;
+ bool is_valid;
+};
-TEST(CreditCardTest, GetCreditCardType) {
- struct {
- std::string card_number;
- std::string type;
- bool is_valid;
- } test_cases[] = {
- // The relevant sample numbers from
- // http://www.paypalobjects.com/en_US/vhelp/paypalmanager_help/credit_card_numbers.htm
- { "378282246310005", kAmericanExpressCard, true },
- { "371449635398431", kAmericanExpressCard, true },
- { "378734493671000", kAmericanExpressCard, true },
- { "30569309025904", kDinersCard, true },
- { "38520000023237", kDinersCard, true },
- { "6011111111111117", kDiscoverCard, true },
- { "6011000990139424", kDiscoverCard, true },
- { "3530111333300000", kJCBCard, true },
- { "3566002020360505", kJCBCard, true },
- { "5555555555554444", kMasterCard, true },
- { "5105105105105100", kMasterCard, true },
- { "4111111111111111", kVisaCard, true },
- { "4012888888881881", kVisaCard, true },
- { "4222222222222", kVisaCard, true },
-
- // The relevant sample numbers from
- // https://www.auricsystems.com/sample-credit-card-numbers/
- { "343434343434343", kAmericanExpressCard, true },
- { "371144371144376", kAmericanExpressCard, true },
- { "341134113411347", kAmericanExpressCard, true },
- { "36438936438936", kDinersCard, true },
- { "36110361103612", kDinersCard, true },
- { "36111111111111", kDinersCard, true },
- { "6011016011016011", kDiscoverCard, true },
- { "6011000990139424", kDiscoverCard, true },
- { "6011000000000004", kDiscoverCard, true },
- { "6011000995500000", kDiscoverCard, true },
- { "6500000000000002", kDiscoverCard, true },
- { "3566002020360505", kJCBCard, true },
- { "3528000000000007", kJCBCard, true },
- { "5500005555555559", kMasterCard, true },
- { "5555555555555557", kMasterCard, true },
- { "5454545454545454", kMasterCard, true },
- { "5555515555555551", kMasterCard, true },
- { "5405222222222226", kMasterCard, true },
- { "5478050000000007", kMasterCard, true },
- { "5111005111051128", kMasterCard, true },
- { "5112345112345114", kMasterCard, true },
- { "5115915115915118", kMasterCard, true },
- { "6247130048162403", kUnionPay, true },
- { "6247130048162403", kUnionPay, true },
- { "622384452162063648", kUnionPay, true },
- { "2204883716636153", kMirCard, true },
- { "2200111234567898", kMirCard, true },
- { "2200481349288130", kMirCard, true },
-
- // Empty string
- { std::string(), kGenericCard, false },
-
- // Non-numeric
- { "garbage", kGenericCard, false },
- { "4garbage", kVisaCard, false },
-
- // Fails Luhn check.
- { "4111111111111112", kVisaCard, false },
- { "6247130048162413", kUnionPay, false },
- { "2204883716636154", kMirCard, false },
-
- // Invalid length.
- { "3434343434343434", kAmericanExpressCard, false },
- { "411111111111116", kVisaCard, false },
- { "220011123456783", kMirCard, false },
-
- // Issuer Identification Numbers (IINs) that Chrome recognizes.
- { "4", kVisaCard, false },
- { "22", kMirCard, false },
- { "34", kAmericanExpressCard, false },
- { "37", kAmericanExpressCard, false },
- { "300", kDinersCard, false },
- { "301", kDinersCard, false },
- { "302", kDinersCard, false },
- { "303", kDinersCard, false },
- { "304", kDinersCard, false },
- { "305", kDinersCard, false },
- { "3095", kDinersCard, false },
- { "36", kDinersCard, false },
- { "38", kDinersCard, false },
- { "39", kDinersCard, false },
- { "6011", kDiscoverCard, false },
- { "644", kDiscoverCard, false },
- { "645", kDiscoverCard, false },
- { "646", kDiscoverCard, false },
- { "647", kDiscoverCard, false },
- { "648", kDiscoverCard, false },
- { "649", kDiscoverCard, false },
- { "65", kDiscoverCard, false },
- { "3528", kJCBCard, false },
- { "3531", kJCBCard, false },
- { "3589", kJCBCard, false },
- { "51", kMasterCard, false },
- { "52", kMasterCard, false },
- { "53", kMasterCard, false },
- { "54", kMasterCard, false },
- { "55", kMasterCard, false },
- { "62", kUnionPay, false },
-
- // Not enough data to determine an IIN uniquely.
- { "2", kGenericCard, false },
- { "3", kGenericCard, false },
- { "30", kGenericCard, false },
- { "309", kGenericCard, false },
- { "35", kGenericCard, false },
- { "5", kGenericCard, false },
- { "6", kGenericCard, false },
- { "60", kGenericCard, false },
- { "601", kGenericCard, false },
- { "64", kGenericCard, false },
-
- // Unknown IINs.
- { "0", kGenericCard, false },
- { "1", kGenericCard, false },
- { "306", kGenericCard, false },
- { "307", kGenericCard, false },
- { "308", kGenericCard, false },
- { "3091", kGenericCard, false },
- { "3094", kGenericCard, false },
- { "3096", kGenericCard, false },
- { "31", kGenericCard, false },
- { "32", kGenericCard, false },
- { "33", kGenericCard, false },
- { "351", kGenericCard, false },
- { "3527", kGenericCard, false },
- { "359", kGenericCard, false },
- { "50", kGenericCard, false },
- { "56", kGenericCard, false },
- { "57", kGenericCard, false },
- { "58", kGenericCard, false },
- { "59", kGenericCard, false },
- { "600", kGenericCard, false },
- { "602", kGenericCard, false },
- { "603", kGenericCard, false },
- { "604", kGenericCard, false },
- { "605", kGenericCard, false },
- { "606", kGenericCard, false },
- { "607", kGenericCard, false },
- { "608", kGenericCard, false },
- { "609", kGenericCard, false },
- { "61", kGenericCard, false },
- { "63", kGenericCard, false },
- { "640", kGenericCard, false },
- { "641", kGenericCard, false },
- { "642", kGenericCard, false },
- { "643", kGenericCard, false },
- { "66", kGenericCard, false },
- { "67", kGenericCard, false },
- { "68", kGenericCard, false },
- { "69", kGenericCard, false },
- { "7", kGenericCard, false },
- { "8", kGenericCard, false },
- { "9", kGenericCard, false },
-
- // Oddball case: Unknown issuer, but valid Luhn check and plausible length.
- { "7000700070007000", kGenericCard, true },
- };
+// We are doing batches here because INSTANTIATE_TEST_CASE_P has a
+// 50 upper limit.
+class GetCreditCardTypeTestBatch1
+ : public testing::TestWithParam<GetCreditCardTypeTestCase> {};
+
+TEST_P(GetCreditCardTypeTestBatch1, GetCreditCardType) {
+ auto test_case = GetParam();
+ base::string16 card_number = ASCIIToUTF16(test_case.card_number);
+ SCOPED_TRACE(card_number);
+ EXPECT_EQ(test_case.type, CreditCard::GetCreditCardType(card_number));
+ EXPECT_EQ(test_case.is_valid, IsValidCreditCardNumber(card_number));
+}
- for (const auto& test_case : test_cases) {
- base::string16 card_number = ASCIIToUTF16(test_case.card_number);
- SCOPED_TRACE(card_number);
- EXPECT_EQ(test_case.type, CreditCard::GetCreditCardType(card_number));
- EXPECT_EQ(test_case.is_valid, IsValidCreditCardNumber(card_number));
- }
+INSTANTIATE_TEST_CASE_P(
+ CreditCardTest,
+ GetCreditCardTypeTestBatch1,
+ testing::Values(
+ // The relevant sample numbers from
+ // http://www.paypalobjects.com/en_US/vhelp/paypalmanager_help/credit_card_numbers.htm
+ GetCreditCardTypeTestCase{"378282246310005", kAmericanExpressCard,
+ true},
+ GetCreditCardTypeTestCase{"371449635398431", kAmericanExpressCard,
+ true},
+ GetCreditCardTypeTestCase{"378734493671000", kAmericanExpressCard,
+ true},
+ GetCreditCardTypeTestCase{"30569309025904", kDinersCard, true},
+ GetCreditCardTypeTestCase{"38520000023237", kDinersCard, true},
+ GetCreditCardTypeTestCase{"6011111111111117", kDiscoverCard, true},
+ GetCreditCardTypeTestCase{"6011000990139424", kDiscoverCard, true},
+ GetCreditCardTypeTestCase{"3530111333300000", kJCBCard, true},
+ GetCreditCardTypeTestCase{"3566002020360505", kJCBCard, true},
+ GetCreditCardTypeTestCase{"5555555555554444", kMasterCard, true},
+ GetCreditCardTypeTestCase{"5105105105105100", kMasterCard, true},
+ GetCreditCardTypeTestCase{"4111111111111111", kVisaCard, true},
+ GetCreditCardTypeTestCase{"4012888888881881", kVisaCard, true},
+ GetCreditCardTypeTestCase{"4222222222222", kVisaCard, true},
+
+ // The relevant sample numbers from
+ // https://www.auricsystems.com/sample-credit-card-numbers/
+ GetCreditCardTypeTestCase{"343434343434343", kAmericanExpressCard,
+ true},
+ GetCreditCardTypeTestCase{"371144371144376", kAmericanExpressCard,
+ true},
+ GetCreditCardTypeTestCase{"341134113411347", kAmericanExpressCard,
+ true},
+ GetCreditCardTypeTestCase{"36438936438936", kDinersCard, true},
+ GetCreditCardTypeTestCase{"36110361103612", kDinersCard, true},
+ GetCreditCardTypeTestCase{"36111111111111", kDinersCard, true},
+ GetCreditCardTypeTestCase{"6011016011016011", kDiscoverCard, true},
+ GetCreditCardTypeTestCase{"6011000990139424", kDiscoverCard, true},
+ GetCreditCardTypeTestCase{"6011000000000004", kDiscoverCard, true},
+ GetCreditCardTypeTestCase{"6011000995500000", kDiscoverCard, true},
+ GetCreditCardTypeTestCase{"6500000000000002", kDiscoverCard, true},
+ GetCreditCardTypeTestCase{"3566002020360505", kJCBCard, true},
+ GetCreditCardTypeTestCase{"3528000000000007", kJCBCard, true},
+ GetCreditCardTypeTestCase{"5500005555555559", kMasterCard, true},
+ GetCreditCardTypeTestCase{"5555555555555557", kMasterCard, true},
+ GetCreditCardTypeTestCase{"5454545454545454", kMasterCard, true},
+ GetCreditCardTypeTestCase{"5555515555555551", kMasterCard, true},
+ GetCreditCardTypeTestCase{"5405222222222226", kMasterCard, true},
+ GetCreditCardTypeTestCase{"5478050000000007", kMasterCard, true},
+ GetCreditCardTypeTestCase{"5111005111051128", kMasterCard, true},
+ GetCreditCardTypeTestCase{"5112345112345114", kMasterCard, true},
+ GetCreditCardTypeTestCase{"5115915115915118", kMasterCard, true},
+ GetCreditCardTypeTestCase{"6247130048162403", kUnionPay, true},
+ GetCreditCardTypeTestCase{"6247130048162403", kUnionPay, true},
+ GetCreditCardTypeTestCase{"622384452162063648", kUnionPay, true},
+ GetCreditCardTypeTestCase{"2204883716636153", kMirCard, true},
+ GetCreditCardTypeTestCase{"2200111234567898", kMirCard, true},
+ GetCreditCardTypeTestCase{"2200481349288130", kMirCard, true},
+
+ // Empty string
+ GetCreditCardTypeTestCase{std::string(), kGenericCard, false},
+
+ // Non-numeric
+ GetCreditCardTypeTestCase{"garbage", kGenericCard, false},
+ GetCreditCardTypeTestCase{"4garbage", kVisaCard, false},
+
+ // Fails Luhn check.
+ GetCreditCardTypeTestCase{"4111111111111112", kVisaCard, false},
+ GetCreditCardTypeTestCase{"6247130048162413", kUnionPay, false},
+ GetCreditCardTypeTestCase{"2204883716636154", kMirCard, false}));
+
+class GetCreditCardTypeTestBatch2
+ : public testing::TestWithParam<GetCreditCardTypeTestCase> {};
+
+TEST_P(GetCreditCardTypeTestBatch2, GetCreditCardType) {
+ auto test_case = GetParam();
+ base::string16 card_number = ASCIIToUTF16(test_case.card_number);
+ SCOPED_TRACE(card_number);
+ EXPECT_EQ(test_case.type, CreditCard::GetCreditCardType(card_number));
+ EXPECT_EQ(test_case.is_valid, IsValidCreditCardNumber(card_number));
+}
+
+INSTANTIATE_TEST_CASE_P(
+ CreditCardTest,
+ GetCreditCardTypeTestBatch2,
+ testing::Values(
+ // Invalid length.
+ GetCreditCardTypeTestCase{"3434343434343434", kAmericanExpressCard,
+ false},
+ GetCreditCardTypeTestCase{"411111111111116", kVisaCard, false},
+ GetCreditCardTypeTestCase{"220011123456783", kMirCard, false},
+
+ // Issuer Identification Numbers (IINs) that Chrome recognizes.
+ GetCreditCardTypeTestCase{"4", kVisaCard, false},
+ GetCreditCardTypeTestCase{"22", kMirCard, false},
+ GetCreditCardTypeTestCase{"34", kAmericanExpressCard, false},
+ GetCreditCardTypeTestCase{"37", kAmericanExpressCard, false},
+ GetCreditCardTypeTestCase{"300", kDinersCard, false},
+ GetCreditCardTypeTestCase{"301", kDinersCard, false},
+ GetCreditCardTypeTestCase{"302", kDinersCard, false},
+ GetCreditCardTypeTestCase{"303", kDinersCard, false},
+ GetCreditCardTypeTestCase{"304", kDinersCard, false},
+ GetCreditCardTypeTestCase{"305", kDinersCard, false},
+ GetCreditCardTypeTestCase{"3095", kDinersCard, false},
+ GetCreditCardTypeTestCase{"36", kDinersCard, false},
+ GetCreditCardTypeTestCase{"38", kDinersCard, false},
+ GetCreditCardTypeTestCase{"39", kDinersCard, false},
+ GetCreditCardTypeTestCase{"6011", kDiscoverCard, false},
+ GetCreditCardTypeTestCase{"644", kDiscoverCard, false},
+ GetCreditCardTypeTestCase{"645", kDiscoverCard, false},
+ GetCreditCardTypeTestCase{"646", kDiscoverCard, false},
+ GetCreditCardTypeTestCase{"647", kDiscoverCard, false},
+ GetCreditCardTypeTestCase{"648", kDiscoverCard, false},
+ GetCreditCardTypeTestCase{"649", kDiscoverCard, false},
+ GetCreditCardTypeTestCase{"65", kDiscoverCard, false},
+ GetCreditCardTypeTestCase{"3528", kJCBCard, false},
+ GetCreditCardTypeTestCase{"3531", kJCBCard, false},
+ GetCreditCardTypeTestCase{"3589", kJCBCard, false},
+ GetCreditCardTypeTestCase{"51", kMasterCard, false},
+ GetCreditCardTypeTestCase{"52", kMasterCard, false},
+ GetCreditCardTypeTestCase{"53", kMasterCard, false},
+ GetCreditCardTypeTestCase{"54", kMasterCard, false},
+ GetCreditCardTypeTestCase{"55", kMasterCard, false},
+ GetCreditCardTypeTestCase{"62", kUnionPay, false},
+
+ // Not enough data to determine an IIN uniquely.
+ GetCreditCardTypeTestCase{"2", kGenericCard, false},
+ GetCreditCardTypeTestCase{"3", kGenericCard, false},
+ GetCreditCardTypeTestCase{"30", kGenericCard, false},
+ GetCreditCardTypeTestCase{"309", kGenericCard, false},
+ GetCreditCardTypeTestCase{"35", kGenericCard, false},
+ GetCreditCardTypeTestCase{"5", kGenericCard, false},
+ GetCreditCardTypeTestCase{"6", kGenericCard, false},
+ GetCreditCardTypeTestCase{"60", kGenericCard, false},
+ GetCreditCardTypeTestCase{"601", kGenericCard, false},
+ GetCreditCardTypeTestCase{"64", kGenericCard, false}));
+
+class GetCreditCardTypeTestBatch3
+ : public testing::TestWithParam<GetCreditCardTypeTestCase> {};
+
+TEST_P(GetCreditCardTypeTestBatch3, GetCreditCardType) {
+ auto test_case = GetParam();
+ base::string16 card_number = ASCIIToUTF16(test_case.card_number);
+ SCOPED_TRACE(card_number);
+ EXPECT_EQ(test_case.type, CreditCard::GetCreditCardType(card_number));
+ EXPECT_EQ(test_case.is_valid, IsValidCreditCardNumber(card_number));
}
+INSTANTIATE_TEST_CASE_P(
+ CreditCardTest,
+ GetCreditCardTypeTestBatch3,
+ testing::Values(
+ // Unknown IINs.
+ GetCreditCardTypeTestCase{"0", kGenericCard, false},
+ GetCreditCardTypeTestCase{"1", kGenericCard, false},
+ GetCreditCardTypeTestCase{"306", kGenericCard, false},
+ GetCreditCardTypeTestCase{"307", kGenericCard, false},
+ GetCreditCardTypeTestCase{"308", kGenericCard, false},
+ GetCreditCardTypeTestCase{"3091", kGenericCard, false},
+ GetCreditCardTypeTestCase{"3094", kGenericCard, false},
+ GetCreditCardTypeTestCase{"3096", kGenericCard, false},
+ GetCreditCardTypeTestCase{"31", kGenericCard, false},
+ GetCreditCardTypeTestCase{"32", kGenericCard, false},
+ GetCreditCardTypeTestCase{"33", kGenericCard, false},
+ GetCreditCardTypeTestCase{"351", kGenericCard, false},
+ GetCreditCardTypeTestCase{"3527", kGenericCard, false},
+ GetCreditCardTypeTestCase{"359", kGenericCard, false},
+ GetCreditCardTypeTestCase{"50", kGenericCard, false},
+ GetCreditCardTypeTestCase{"56", kGenericCard, false},
+ GetCreditCardTypeTestCase{"57", kGenericCard, false},
+ GetCreditCardTypeTestCase{"58", kGenericCard, false},
+ GetCreditCardTypeTestCase{"59", kGenericCard, false},
+ GetCreditCardTypeTestCase{"600", kGenericCard, false},
+ GetCreditCardTypeTestCase{"602", kGenericCard, false},
+ GetCreditCardTypeTestCase{"603", kGenericCard, false},
+ GetCreditCardTypeTestCase{"604", kGenericCard, false},
+ GetCreditCardTypeTestCase{"605", kGenericCard, false},
+ GetCreditCardTypeTestCase{"606", kGenericCard, false},
+ GetCreditCardTypeTestCase{"607", kGenericCard, false},
+ GetCreditCardTypeTestCase{"608", kGenericCard, false},
+ GetCreditCardTypeTestCase{"609", kGenericCard, false},
+ GetCreditCardTypeTestCase{"61", kGenericCard, false},
+ GetCreditCardTypeTestCase{"63", kGenericCard, false},
+ GetCreditCardTypeTestCase{"640", kGenericCard, false},
+ GetCreditCardTypeTestCase{"641", kGenericCard, false},
+ GetCreditCardTypeTestCase{"642", kGenericCard, false},
+ GetCreditCardTypeTestCase{"643", kGenericCard, false},
+ GetCreditCardTypeTestCase{"66", kGenericCard, false},
+ GetCreditCardTypeTestCase{"67", kGenericCard, false},
+ GetCreditCardTypeTestCase{"68", kGenericCard, false},
+ GetCreditCardTypeTestCase{"69", kGenericCard, false},
+ GetCreditCardTypeTestCase{"7", kGenericCard, false},
+ GetCreditCardTypeTestCase{"8", kGenericCard, false},
+ GetCreditCardTypeTestCase{"9", kGenericCard, false},
+
+ // Oddball case: Unknown issuer, but valid Luhn check and plausible
+ // length.
+ GetCreditCardTypeTestCase{"7000700070007000", kGenericCard, true}));
+
TEST(CreditCardTest, LastFourDigits) {
CreditCard card(base::GenerateGUID(), "https://www.example.com/");
ASSERT_EQ(base::string16(), card.LastFourDigits());
@@ -791,104 +861,149 @@ TEST(CreditCardTest, LastFourDigits) {
}
// Verifies that a credit card should be updated.
-TEST(CreditCardTest, ShouldUpdateExpiration) {
- base::Time now = base::Time::Now();
-
- base::Time::Exploded last_year;
- (now - base::TimeDelta::FromDays(365)).LocalExplode(&last_year);
-
- base::Time::Exploded last_month;
- (now - base::TimeDelta::FromDays(31)).LocalExplode(&last_month);
-
- base::Time::Exploded current;
- now.LocalExplode(&current);
-
- base::Time::Exploded next_month;
- (now + base::TimeDelta::FromDays(31)).LocalExplode(&next_month);
+struct ShouldUpdateExpirationTestCase {
+ bool should_update_expiration;
+ int month;
+ int year;
+ CreditCard::RecordType record_type;
+ CreditCard::ServerStatus server_status;
+};
- base::Time::Exploded next_year;
- (now + base::TimeDelta::FromDays(365)).LocalExplode(&next_year);
+class ShouldUpdateExpirationTest
+ : public testing::TestWithParam<ShouldUpdateExpirationTestCase> {};
+
+class TestingTimes {
+ public:
+ TestingTimes() {
+ now_ = base::Time::Now();
+ (now_ - base::TimeDelta::FromDays(365)).LocalExplode(&last_year_);
+ (now_ - base::TimeDelta::FromDays(31)).LocalExplode(&last_month_);
+ now_.LocalExplode(&current_);
+ (now_ + base::TimeDelta::FromDays(31)).LocalExplode(&next_month_);
+ (now_ + base::TimeDelta::FromDays(365)).LocalExplode(&next_year_);
+ }
- static const struct {
- bool should_update_expiration;
- int month;
- int year;
- CreditCard::RecordType record_type;
- CreditCard::ServerStatus server_status;
- } kTestCases[] = {
+ base::Time now_;
+ base::Time::Exploded last_year_;
+ base::Time::Exploded last_month_;
+ base::Time::Exploded current_;
+ base::Time::Exploded next_month_;
+ base::Time::Exploded next_year_;
+};
- // Cards that expired last year should always be updated.
- {true, last_year.month, last_year.year, CreditCard::LOCAL_CARD},
- {true, last_year.month, last_year.year, CreditCard::FULL_SERVER_CARD,
- CreditCard::OK},
- {true, last_year.month, last_year.year, CreditCard::MASKED_SERVER_CARD,
- CreditCard::OK},
- {true, last_year.month, last_year.year, CreditCard::FULL_SERVER_CARD,
- CreditCard::EXPIRED},
- {true, last_year.month, last_year.year, CreditCard::MASKED_SERVER_CARD,
- CreditCard::EXPIRED},
-
- // Cards that expired last month should always be updated.
- {true, last_month.month, last_month.year, CreditCard::LOCAL_CARD},
- {true, last_month.month, last_month.year, CreditCard::FULL_SERVER_CARD,
- CreditCard::OK},
- {true, last_month.month, last_month.year, CreditCard::MASKED_SERVER_CARD,
- CreditCard::OK},
- {true, last_month.month, last_month.year, CreditCard::FULL_SERVER_CARD,
- CreditCard::EXPIRED},
- {true, last_month.month, last_month.year, CreditCard::MASKED_SERVER_CARD,
- CreditCard::EXPIRED},
-
- // Cards that expire this month should be updated only if the server
- // status is EXPIRED.
- {false, current.month, current.year, CreditCard::LOCAL_CARD},
- {false, current.month, current.year, CreditCard::FULL_SERVER_CARD,
- CreditCard::OK},
- {false, current.month, current.year, CreditCard::MASKED_SERVER_CARD,
- CreditCard::OK},
- {true, current.month, current.year, CreditCard::FULL_SERVER_CARD,
- CreditCard::EXPIRED},
- {true, current.month, current.year, CreditCard::MASKED_SERVER_CARD,
- CreditCard::EXPIRED},
-
- // Cards that expire next month should be updated only if the server
- // status is EXPIRED.
- {false, next_month.month, next_month.year, CreditCard::LOCAL_CARD},
- {false, next_month.month, next_month.year, CreditCard::MASKED_SERVER_CARD,
- CreditCard::OK},
- {false, next_month.month, next_month.year, CreditCard::FULL_SERVER_CARD,
- CreditCard::OK},
- {true, next_month.month, next_month.year, CreditCard::MASKED_SERVER_CARD,
- CreditCard::EXPIRED},
- {true, next_month.month, next_month.year, CreditCard::FULL_SERVER_CARD,
- CreditCard::EXPIRED},
-
- // Cards that expire next year should be updated only if the server status
- // is EXPIRED.
- {false, next_year.month, next_year.year, CreditCard::LOCAL_CARD},
- {false, next_year.month, next_year.year, CreditCard::MASKED_SERVER_CARD,
- CreditCard::OK},
- {false, next_year.month, next_year.year, CreditCard::FULL_SERVER_CARD,
- CreditCard::OK},
- {true, next_year.month, next_year.year, CreditCard::MASKED_SERVER_CARD,
- CreditCard::EXPIRED},
- {true, next_year.month, next_year.year, CreditCard::FULL_SERVER_CARD,
- CreditCard::EXPIRED},
- };
+TestingTimes testingTimes;
- for (const auto& test_case : kTestCases) {
- CreditCard card;
- card.SetExpirationMonth(test_case.month);
- card.SetExpirationYear(test_case.year);
- card.set_record_type(test_case.record_type);
- if (card.record_type() != CreditCard::LOCAL_CARD)
- card.SetServerStatus(test_case.server_status);
-
- EXPECT_EQ(test_case.should_update_expiration,
- card.ShouldUpdateExpiration(now));
- }
+TEST_P(ShouldUpdateExpirationTest, ShouldUpdateExpiration) {
+ auto test_case = GetParam();
+ CreditCard card;
+ card.SetExpirationMonth(test_case.month);
+ card.SetExpirationYear(test_case.year);
+ card.set_record_type(test_case.record_type);
+ if (card.record_type() != CreditCard::LOCAL_CARD)
+ card.SetServerStatus(test_case.server_status);
+
+ EXPECT_EQ(test_case.should_update_expiration,
+ card.ShouldUpdateExpiration(testingTimes.now_));
}
+INSTANTIATE_TEST_CASE_P(
+ CreditCardTest,
+ ShouldUpdateExpirationTest,
+ testing::Values(
+ // Cards that expired last year should always be updated.
+ ShouldUpdateExpirationTestCase{true, testingTimes.last_year_.month,
+ testingTimes.last_year_.year,
+ CreditCard::LOCAL_CARD},
+ ShouldUpdateExpirationTestCase{
+ true, testingTimes.last_year_.month, testingTimes.last_year_.year,
+ CreditCard::FULL_SERVER_CARD, CreditCard::OK},
+ ShouldUpdateExpirationTestCase{
+ true, testingTimes.last_year_.month, testingTimes.last_year_.year,
+ CreditCard::MASKED_SERVER_CARD, CreditCard::OK},
+ ShouldUpdateExpirationTestCase{
+ true, testingTimes.last_year_.month, testingTimes.last_year_.year,
+ CreditCard::FULL_SERVER_CARD, CreditCard::EXPIRED},
+ ShouldUpdateExpirationTestCase{
+ true, testingTimes.last_year_.month, testingTimes.last_year_.year,
+ CreditCard::MASKED_SERVER_CARD, CreditCard::EXPIRED},
+
+ // Cards that expired last month should always be updated.
+ ShouldUpdateExpirationTestCase{true, testingTimes.last_month_.month,
+ testingTimes.last_month_.year,
+ CreditCard::LOCAL_CARD},
+ ShouldUpdateExpirationTestCase{
+ true, testingTimes.last_month_.month, testingTimes.last_month_.year,
+ CreditCard::FULL_SERVER_CARD, CreditCard::OK},
+ ShouldUpdateExpirationTestCase{
+ true, testingTimes.last_month_.month, testingTimes.last_month_.year,
+ CreditCard::MASKED_SERVER_CARD, CreditCard::OK},
+ ShouldUpdateExpirationTestCase{
+ true, testingTimes.last_month_.month, testingTimes.last_month_.year,
+ CreditCard::FULL_SERVER_CARD, CreditCard::EXPIRED},
+ ShouldUpdateExpirationTestCase{
+ true, testingTimes.last_month_.month, testingTimes.last_month_.year,
+ CreditCard::MASKED_SERVER_CARD, CreditCard::EXPIRED},
+
+ // Cards that expire this month should be updated only if the server
+ // status is EXPIRED.
+ ShouldUpdateExpirationTestCase{false, testingTimes.current_.month,
+ testingTimes.current_.year,
+ CreditCard::LOCAL_CARD},
+ ShouldUpdateExpirationTestCase{
+ false, testingTimes.current_.month, testingTimes.current_.year,
+ CreditCard::FULL_SERVER_CARD, CreditCard::OK},
+ ShouldUpdateExpirationTestCase{
+ false, testingTimes.current_.month, testingTimes.current_.year,
+ CreditCard::MASKED_SERVER_CARD, CreditCard::OK},
+ ShouldUpdateExpirationTestCase{
+ true, testingTimes.current_.month, testingTimes.current_.year,
+ CreditCard::FULL_SERVER_CARD, CreditCard::EXPIRED},
+ ShouldUpdateExpirationTestCase{
+ true, testingTimes.current_.month, testingTimes.current_.year,
+ CreditCard::MASKED_SERVER_CARD, CreditCard::EXPIRED},
+
+ // Cards that expire next month should be updated only if the server
+ // status is EXPIRED.
+ ShouldUpdateExpirationTestCase{false, testingTimes.next_month_.month,
+ testingTimes.next_month_.year,
+ CreditCard::LOCAL_CARD},
+ ShouldUpdateExpirationTestCase{false, testingTimes.next_month_.month,
+ testingTimes.next_month_.year,
+ CreditCard::MASKED_SERVER_CARD,
+ CreditCard::OK},
+ ShouldUpdateExpirationTestCase{false, testingTimes.next_month_.month,
+ testingTimes.next_month_.year,
+ CreditCard::FULL_SERVER_CARD,
+ CreditCard::OK},
+ ShouldUpdateExpirationTestCase{
+ true, testingTimes.next_month_.month, testingTimes.next_month_.year,
+ CreditCard::MASKED_SERVER_CARD, CreditCard::EXPIRED},
+ ShouldUpdateExpirationTestCase{
+ true, testingTimes.next_month_.month, testingTimes.next_month_.year,
+ CreditCard::FULL_SERVER_CARD, CreditCard::EXPIRED},
+
+ // Cards that expire next year should be updated only if the server
+ // status is EXPIRED.
+ ShouldUpdateExpirationTestCase{false, testingTimes.next_year_.month,
+ testingTimes.next_year_.year,
+ CreditCard::LOCAL_CARD},
+ ShouldUpdateExpirationTestCase{
+ false, testingTimes.next_year_.month, testingTimes.next_year_.year,
+ CreditCard::MASKED_SERVER_CARD, CreditCard::OK},
+ ShouldUpdateExpirationTestCase{
+ false, testingTimes.next_year_.month, testingTimes.next_year_.year,
+ CreditCard::FULL_SERVER_CARD, CreditCard::OK},
+ ShouldUpdateExpirationTestCase{
+ true, testingTimes.next_year_.month, testingTimes.next_year_.year,
+ CreditCard::MASKED_SERVER_CARD, CreditCard::EXPIRED},
+ ShouldUpdateExpirationTestCase{
+ true, testingTimes.next_year_.month, testingTimes.next_year_.year,
+ CreditCard::FULL_SERVER_CARD, CreditCard::EXPIRED}));
+
+// TODO(wuandy): rewriting below test with INSTANTIATE_TEST_CASE_P seems to
+// trigger a complaint on windows compilers. Removing it and revert to
+// original test for now.
+
// Test that credit card last used date suggestion can be generated correctly
// in different variations.
TEST(CreditCardTest, GetLastUsedDateForDisplay) {
diff --git a/chromium/components/autofill/core/browser/field_types.h b/chromium/components/autofill/core/browser/field_types.h
index 6c2aa807752..cee305fcda5 100644
--- a/chromium/components/autofill/core/browser/field_types.h
+++ b/chromium/components/autofill/core/browser/field_types.h
@@ -234,7 +234,10 @@ enum HtmlFieldType {
HTML_TYPE_CREDIT_CARD_EXP_2_DIGIT_YEAR,
HTML_TYPE_CREDIT_CARD_EXP_4_DIGIT_YEAR,
- // Non standard autcomplete types.
+ // Universal Payment Interface - Virtual Payment Address.
+ HTML_TYPE_UPI_VPA,
+
+ // Non-standard autocomplete types.
HTML_TYPE_UNRECOGNIZED,
};
diff --git a/chromium/components/autofill/core/browser/form_group.cc b/chromium/components/autofill/core/browser/form_group.cc
index 417f08a9043..1f248ccf94e 100644
--- a/chromium/components/autofill/core/browser/form_group.cc
+++ b/chromium/components/autofill/core/browser/form_group.cc
@@ -57,4 +57,14 @@ bool FormGroup::SetInfo(const AutofillType& type,
return true;
}
+bool FormGroup::HasInfo(ServerFieldType type) const {
+ return HasInfo(AutofillType(type));
+}
+
+bool FormGroup::HasInfo(const AutofillType& type) const {
+ // Use "en-US" as a placeholder locale. We are only interested in emptiness,
+ // not in the presentation of the string.
+ return !GetInfo(type, "en-US").empty();
+}
+
} // namespace autofill
diff --git a/chromium/components/autofill/core/browser/form_group.h b/chromium/components/autofill/core/browser/form_group.h
index 86bd4531bb1..c3d9cd14e2d 100644
--- a/chromium/components/autofill/core/browser/form_group.h
+++ b/chromium/components/autofill/core/browser/form_group.h
@@ -53,6 +53,10 @@ class FormGroup {
const base::string16& value,
const std::string& app_locale);
+ // Returns true iff the string associated with |type| is nonempty.
+ bool HasInfo(ServerFieldType type) const;
+ bool HasInfo(const AutofillType& type) const;
+
protected:
// AutofillProfile needs to call into GetSupportedTypes() for objects of
// non-AutofillProfile type, for which mere inheritance is insufficient.
diff --git a/chromium/components/autofill/core/browser/form_structure.cc b/chromium/components/autofill/core/browser/form_structure.cc
index addf89f686b..9bff7e2f0bc 100644
--- a/chromium/components/autofill/core/browser/form_structure.cc
+++ b/chromium/components/autofill/core/browser/form_structure.cc
@@ -9,6 +9,7 @@
#include <algorithm>
#include <map>
#include <utility>
+#include <vector>
#include "base/command_line.h"
#include "base/i18n/case_conversion.h"
@@ -27,6 +28,7 @@
#include "components/autofill/core/browser/field_candidates.h"
#include "components/autofill/core/browser/field_types.h"
#include "components/autofill/core/browser/form_field.h"
+#include "components/autofill/core/browser/validation.h"
#include "components/autofill/core/common/autofill_constants.h"
#include "components/autofill/core/common/autofill_util.h"
#include "components/autofill/core/common/form_data.h"
@@ -36,6 +38,7 @@
#include "components/autofill/core/common/signatures_util.h"
#include "components/rappor/public/rappor_utils.h"
#include "components/rappor/rappor_service_impl.h"
+#include "components/ukm/ukm_service.h"
namespace autofill {
namespace {
@@ -268,6 +271,9 @@ HtmlFieldType FieldTypeFromAutocompleteAttributeValue(
if (autocomplete_attribute_value == "email")
return HTML_TYPE_EMAIL;
+ if (autocomplete_attribute_value == "upi-vpa")
+ return HTML_TYPE_UPI_VPA;
+
return HTML_TYPE_UNRECOGNIZED;
}
@@ -300,11 +306,13 @@ FormStructure::FormStructure(const FormData& form)
upload_required_(USE_UPLOAD_RATES),
has_author_specified_types_(false),
has_author_specified_sections_(false),
+ has_author_specified_upi_vpa_hint_(false),
was_parsed_for_autocomplete_attributes_(false),
has_password_field_(false),
is_form_tag_(form.is_form_tag),
is_formless_checkout_(form.is_formless_checkout),
- all_fields_are_passwords_(true) {
+ all_fields_are_passwords_(true),
+ is_signin_upload_(false) {
// Copy the form fields.
std::map<base::string16, size_t> unique_names;
for (const FormFieldData& field : form.fields) {
@@ -332,7 +340,7 @@ FormStructure::FormStructure(const FormData& form)
FormStructure::~FormStructure() {}
-void FormStructure::DetermineHeuristicTypes() {
+void FormStructure::DetermineHeuristicTypes(ukm::UkmService* ukm_service) {
const auto determine_heuristic_types_start_time = base::TimeTicks::Now();
// First, try to detect field types based on each field's |autocomplete|
@@ -357,15 +365,25 @@ void FormStructure::DetermineHeuristicTypes() {
UpdateAutofillCount();
IdentifySections(has_author_specified_sections_);
+ std::vector<AutofillMetrics::DeveloperEngagementMetric> metrics;
if (IsAutofillable()) {
+ AutofillMetrics::DeveloperEngagementMetric metric =
+ has_author_specified_types_
+ ? AutofillMetrics::FILLABLE_FORM_PARSED_WITH_TYPE_HINTS
+ : AutofillMetrics::FILLABLE_FORM_PARSED_WITHOUT_TYPE_HINTS;
+ metrics.push_back(metric);
+ AutofillMetrics::LogDeveloperEngagementMetric(metric);
+ }
+
+ if (has_author_specified_upi_vpa_hint_) {
AutofillMetrics::LogDeveloperEngagementMetric(
- AutofillMetrics::FILLABLE_FORM_PARSED);
- if (has_author_specified_types_) {
- AutofillMetrics::LogDeveloperEngagementMetric(
- AutofillMetrics::FILLABLE_FORM_CONTAINS_TYPE_HINTS);
- }
+ AutofillMetrics::FORM_CONTAINS_UPI_VPA_HINT);
+ metrics.push_back(AutofillMetrics::FORM_CONTAINS_UPI_VPA_HINT);
}
+ AutofillMetrics::LogDeveloperEngagementUkm(ukm_service, source_url(),
+ metrics);
+
AutofillMetrics::LogDetermineHeuristicTypesTiming(
base::TimeTicks::Now() - determine_heuristic_types_start_time);
}
@@ -600,7 +618,7 @@ bool FormStructure::ShouldBeParsed() const {
if (active_field_count() < kRequiredFieldsForPredictionRoutines &&
(!all_fields_are_passwords() ||
active_field_count() < kRequiredFieldsForFormsWithOnlyPasswordFields) &&
- !has_author_specified_types_) {
+ !is_signin_upload_ && !has_author_specified_types_) {
return false;
}
@@ -624,17 +642,16 @@ bool FormStructure::ShouldBeCrowdsourced() const {
ShouldBeParsed();
}
-void FormStructure::UpdateFromCache(const FormStructure& cached_form) {
+void FormStructure::UpdateFromCache(const FormStructure& cached_form,
+ const bool apply_is_autofilled) {
// Map from field signatures to cached fields.
- std::map<std::string, const AutofillField*> cached_fields;
+ std::map<base::string16, const AutofillField*> cached_fields;
for (size_t i = 0; i < cached_form.field_count(); ++i) {
auto* const field = cached_form.field(i);
- cached_fields[field->FieldSignatureAsStr()] = field;
+ cached_fields[field->unique_name()] = field;
}
-
for (auto& field : *this) {
- std::map<std::string, const AutofillField*>::const_iterator cached_field =
- cached_fields.find(field->FieldSignatureAsStr());
+ const auto& cached_field = cached_fields.find(field->unique_name());
if (cached_field != cached_fields.end()) {
if (field->form_control_type != "select-one" &&
field->value == cached_field->second->value) {
@@ -649,6 +666,9 @@ void FormStructure::UpdateFromCache(const FormStructure& cached_form) {
field->set_server_type(cached_field->second->server_type());
field->SetHtmlType(cached_field->second->html_type(),
cached_field->second->html_mode());
+ if (apply_is_autofilled) {
+ field->is_autofilled = cached_field->second->is_autofilled;
+ }
field->set_previously_autofilled(
cached_field->second->previously_autofilled());
field->set_section(cached_field->second->section());
@@ -662,24 +682,30 @@ void FormStructure::UpdateFromCache(const FormStructure& cached_form) {
// rearranged via JavaScript between page load and form submission, so we
// copy over the |form_signature_field_names_| corresponding to the query
// request.
- DCHECK_EQ(cached_form.form_name_, form_name_);
- DCHECK_EQ(cached_form.source_url_, source_url_);
- DCHECK_EQ(cached_form.target_url_, target_url_);
form_signature_ = cached_form.form_signature_;
}
-void FormStructure::LogQualityMetrics(const base::TimeTicks& load_time,
- const base::TimeTicks& interaction_time,
- const base::TimeTicks& submission_time,
- rappor::RapporServiceImpl* rappor_service,
- bool did_show_suggestions,
- bool observed_submission) const {
+void FormStructure::LogQualityMetrics(
+ const base::TimeTicks& load_time,
+ const base::TimeTicks& interaction_time,
+ const base::TimeTicks& submission_time,
+ rappor::RapporServiceImpl* rappor_service,
+ AutofillMetrics::FormInteractionsUkmLogger* form_interactions_ukm_logger,
+ bool did_show_suggestions,
+ bool observed_submission) const {
size_t num_detected_field_types = 0;
size_t num_server_mismatches = 0;
size_t num_heuristic_mismatches = 0;
size_t num_edited_autofilled_fields = 0;
bool did_autofill_all_possible_fields = true;
bool did_autofill_some_possible_fields = false;
+
+ // Determine the correct suffix for the metric, depending on whether or
+ // not a submission was observed.
+ const AutofillMetrics::QualityMetricType metric_type =
+ observed_submission ? AutofillMetrics::TYPE_SUBMISSION
+ : AutofillMetrics::TYPE_NO_SUBMISSION;
+
for (size_t i = 0; i < field_count(); ++i) {
auto* const field = this->field(i);
@@ -689,17 +715,51 @@ void FormStructure::LogQualityMetrics(const base::TimeTicks& load_time,
if (field->form_control_type == "password")
continue;
+ if (IsUPIVirtualPaymentAddress(field->value)) {
+ AutofillMetrics::LogUserHappinessMetric(
+ AutofillMetrics::USER_DID_ENTER_UPI_VPA);
+ }
// We count fields that were autofilled but later modified, regardless of
// whether the data now in the field is recognized.
if (field->previously_autofilled())
num_edited_autofilled_fields++;
- // No further logging for empty fields nor for fields where the entered data
- // does not appear to already exist in the user's stored Autofill data.
+ // Aliases for the field types predicted by heuristics, server and overall.
+ ServerFieldType heuristic_type =
+ AutofillType(field->heuristic_type()).GetStorableType();
+ ServerFieldType server_type =
+ AutofillType(field->server_type()).GetStorableType();
+ ServerFieldType predicted_type = field->Type().GetStorableType();
+
const ServerFieldTypeSet& field_types = field->possible_types();
DCHECK(!field_types.empty());
- if (field_types.count(EMPTY_TYPE) || field_types.count(UNKNOWN_TYPE))
+
+ // If the field data is empty, or unrecognized, log whether or not autofill
+ // predicted that it would be populated with an autofillable data type.
+ bool has_empty_data = field_types.count(EMPTY_TYPE) != 0;
+ bool has_unrecognized_data = field_types.count(UNKNOWN_TYPE) != 0;
+ if (has_empty_data || has_unrecognized_data) {
+ AutofillMetrics::FieldTypeQualityMetric match_empty_or_unknown =
+ has_empty_data ? AutofillMetrics::TYPE_MATCH_EMPTY
+ : AutofillMetrics::TYPE_MATCH_UNKNOWN;
+ AutofillMetrics::FieldTypeQualityMetric mismatch_empty_or_unknown =
+ has_empty_data ? AutofillMetrics::TYPE_MISMATCH_EMPTY
+ : AutofillMetrics::TYPE_MISMATCH_UNKNOWN;
+ ServerFieldType field_type = has_empty_data ? EMPTY_TYPE : UNKNOWN_TYPE;
+ AutofillMetrics::LogHeuristicTypePrediction(
+ (heuristic_type == UNKNOWN_TYPE ? match_empty_or_unknown
+ : mismatch_empty_or_unknown),
+ field_type, metric_type);
+ AutofillMetrics::LogServerTypePrediction(
+ (server_type == NO_SERVER_DATA ? match_empty_or_unknown
+ : mismatch_empty_or_unknown),
+ field_type, metric_type);
+ AutofillMetrics::LogOverallTypePrediction(
+ (predicted_type == UNKNOWN_TYPE ? match_empty_or_unknown
+ : mismatch_empty_or_unknown),
+ field_type, metric_type);
continue;
+ }
++num_detected_field_types;
if (field->is_autofilled)
@@ -726,17 +786,7 @@ void FormStructure::LogQualityMetrics(const base::TimeTicks& load_time,
if (collapsed_field_types.size() == 1)
field_type = *collapsed_field_types.begin();
- ServerFieldType heuristic_type =
- AutofillType(field->heuristic_type()).GetStorableType();
- ServerFieldType server_type =
- AutofillType(field->server_type()).GetStorableType();
- ServerFieldType predicted_type = field->Type().GetStorableType();
-
- // Log heuristic, server, and overall type quality metrics, independently of
- // whether the field was autofilled.
- const AutofillMetrics::QualityMetricType metric_type =
- observed_submission ? AutofillMetrics::TYPE_SUBMISSION
- : AutofillMetrics::TYPE_NO_SUBMISSION;
+ // Log heuristic, server, and overall type quality metrics.
if (heuristic_type == UNKNOWN_TYPE) {
AutofillMetrics::LogHeuristicTypePrediction(AutofillMetrics::TYPE_UNKNOWN,
field_type, metric_type);
@@ -779,24 +829,20 @@ void FormStructure::LogQualityMetrics(const base::TimeTicks& load_time,
// We log "submission" and duration metrics if we are here after observing a
// submission event.
if (observed_submission) {
+ AutofillMetrics::AutofillFormSubmittedState state;
if (num_detected_field_types < kRequiredFieldsForPredictionRoutines) {
- AutofillMetrics::LogAutofillFormSubmittedState(
- AutofillMetrics::NON_FILLABLE_FORM_OR_NEW_DATA);
+ state = AutofillMetrics::NON_FILLABLE_FORM_OR_NEW_DATA;
} else {
if (did_autofill_all_possible_fields) {
- AutofillMetrics::LogAutofillFormSubmittedState(
- AutofillMetrics::FILLABLE_FORM_AUTOFILLED_ALL);
+ state = AutofillMetrics::FILLABLE_FORM_AUTOFILLED_ALL;
} else if (did_autofill_some_possible_fields) {
- AutofillMetrics::LogAutofillFormSubmittedState(
- AutofillMetrics::FILLABLE_FORM_AUTOFILLED_SOME);
+ state = AutofillMetrics::FILLABLE_FORM_AUTOFILLED_SOME;
} else if (!did_show_suggestions) {
- AutofillMetrics::LogAutofillFormSubmittedState(
- AutofillMetrics::
- FILLABLE_FORM_AUTOFILLED_NONE_DID_NOT_SHOW_SUGGESTIONS);
+ state = AutofillMetrics::
+ FILLABLE_FORM_AUTOFILLED_NONE_DID_NOT_SHOW_SUGGESTIONS;
} else {
- AutofillMetrics::LogAutofillFormSubmittedState(
- AutofillMetrics::
- FILLABLE_FORM_AUTOFILLED_NONE_DID_SHOW_SUGGESTIONS);
+ state =
+ AutofillMetrics::FILLABLE_FORM_AUTOFILLED_NONE_DID_SHOW_SUGGESTIONS;
}
// Log some RAPPOR metrics for problematic cases.
@@ -843,6 +889,10 @@ void FormStructure::LogQualityMetrics(const base::TimeTicks& load_time,
}
}
}
+ if (form_interactions_ukm_logger->url() != source_url())
+ form_interactions_ukm_logger->UpdateSourceURL(source_url());
+ AutofillMetrics::LogAutofillFormSubmittedState(
+ state, form_interactions_ukm_logger);
}
}
@@ -888,6 +938,7 @@ void FormStructure::ParseFieldTypesFromAutocompleteAttributes() {
has_author_specified_types_ = false;
has_author_specified_sections_ = false;
+ has_author_specified_upi_vpa_hint_ = false;
for (const auto& field : fields_) {
// To prevent potential section name collisions, add a default suffix for
// other fields. Without this, 'autocomplete' attribute values
@@ -925,6 +976,11 @@ void FormStructure::ParseFieldTypesFromAutocompleteAttributes() {
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/702223): Flesh out support for UPI-VPA.
+ field_type = HTML_TYPE_UNRECOGNIZED;
+ }
if (field_type == HTML_TYPE_UNSPECIFIED)
continue;
diff --git a/chromium/components/autofill/core/browser/form_structure.h b/chromium/components/autofill/core/browser/form_structure.h
index 09c4ee13b89..5365ec17fff 100644
--- a/chromium/components/autofill/core/browser/form_structure.h
+++ b/chromium/components/autofill/core/browser/form_structure.h
@@ -18,6 +18,7 @@
#include "base/strings/string16.h"
#include "base/strings/string_piece.h"
#include "components/autofill/core/browser/autofill_field.h"
+#include "components/autofill/core/browser/autofill_metrics.h"
#include "components/autofill/core/browser/autofill_type.h"
#include "components/autofill/core/browser/field_types.h"
#include "components/autofill/core/browser/proto/server.pb.h"
@@ -37,6 +38,10 @@ namespace rappor {
class RapporServiceImpl;
}
+namespace ukm {
+class UkmService;
+}
+
namespace autofill {
struct FormData;
@@ -50,8 +55,9 @@ class FormStructure {
virtual ~FormStructure();
// Runs several heuristics against the form fields to determine their possible
- // types.
- void DetermineHeuristicTypes();
+ // types. If |ukm_service| is specified, logs UKM for the form structure
+ // corresponding to |source_url_|.
+ void DetermineHeuristicTypes(ukm::UkmService* ukm_service);
// Encodes the proto |upload| request from this FormStructure.
// In some cases, a |login_form_signature| is included as part of the upload.
@@ -116,7 +122,8 @@ class FormStructure {
bool ShouldBeCrowdsourced() const;
// Sets the field types to be those set for |cached_form|.
- void UpdateFromCache(const FormStructure& cached_form);
+ void UpdateFromCache(const FormStructure& cached_form,
+ const bool apply_is_autofilled);
// Logs quality metrics for |this|, which should be a user-submitted form.
// This method should only be called after the possible field types have been
@@ -126,12 +133,16 @@ class FormStructure {
// indicates whether this method is called as a result of observing a
// submission event (otherwise, it may be that an upload was triggered after
// a form was unfocused or a navigation occurred).
- void LogQualityMetrics(const base::TimeTicks& load_time,
- const base::TimeTicks& interaction_time,
- const base::TimeTicks& submission_time,
- rappor::RapporServiceImpl* rappor_service,
- bool did_show_suggestions,
- bool observed_submission) const;
+ // TODO(sebsg): We log more than quality metrics. Maybe rename or split
+ // function?
+ void LogQualityMetrics(
+ const base::TimeTicks& load_time,
+ const base::TimeTicks& interaction_time,
+ const base::TimeTicks& submission_time,
+ rappor::RapporServiceImpl* rappor_service,
+ AutofillMetrics::FormInteractionsUkmLogger* form_interactions_ukm_logger,
+ bool did_show_suggestions,
+ bool observed_submission) const;
// Log the quality of the heuristics and server predictions for this form
// structure, if autocomplete attributes are present on the fields (they are
@@ -201,12 +212,18 @@ class FormStructure {
const GURL& target_url() const { return target_url_; }
- bool has_author_specified_types() { return has_author_specified_types_; }
+ bool has_author_specified_types() const {
+ return has_author_specified_types_;
+ }
- bool has_author_specified_sections() {
+ bool has_author_specified_sections() const {
return has_author_specified_sections_;
}
+ bool has_author_specified_upi_vpa_hint() const {
+ return has_author_specified_upi_vpa_hint_;
+ }
+
void set_upload_required(UploadRequired required) {
upload_required_ = required;
}
@@ -214,6 +231,11 @@ class FormStructure {
bool all_fields_are_passwords() const { return all_fields_are_passwords_; }
+ bool is_signin_upload() const { return is_signin_upload_; }
+ void set_is_signin_upload(bool is_signin_upload) {
+ is_signin_upload_ = is_signin_upload;
+ }
+
FormSignature form_signature() const { return form_signature_; }
// Returns a FormData containing the data this form structure knows about.
@@ -292,6 +314,10 @@ class FormStructure {
// author, via the autocomplete attribute.
bool has_author_specified_sections_;
+ // Whether the form includes a field that explicitly sets it autocomplete
+ // type to "upi-vpa".
+ bool has_author_specified_upi_vpa_hint_;
+
// Whether the form was parsed for autocomplete attribute, thus assigning
// the real values of |has_author_specified_types_| and
// |has_author_specified_sections_|.
@@ -309,6 +335,10 @@ class FormStructure {
// True if all form fields are password fields.
bool all_fields_are_passwords_;
+ // True if the form is submitted and has 2 fields: one text and one password
+ // field.
+ bool is_signin_upload_;
+
// The unique signature for this form, composed of the target url domain,
// the form name, and the form field names in a 64-bit hash.
FormSignature form_signature_;
diff --git a/chromium/components/autofill/core/browser/form_structure_unittest.cc b/chromium/components/autofill/core/browser/form_structure_unittest.cc
index c1ecb59405c..ac809717668 100644
--- a/chromium/components/autofill/core/browser/form_structure_unittest.cc
+++ b/chromium/components/autofill/core/browser/form_structure_unittest.cc
@@ -149,7 +149,7 @@ TEST_F(FormStructureTest, AutofillCount) {
// Only text and select fields that are heuristically matched are counted.
form_structure.reset(new FormStructure(form));
- form_structure->DetermineHeuristicTypes();
+ form_structure->DetermineHeuristicTypes(nullptr /* ukm_service */);
EXPECT_EQ(3U, form_structure->autofill_count());
// Add a field with should_autocomplete=false. This should not be considered a
@@ -161,7 +161,7 @@ TEST_F(FormStructureTest, AutofillCount) {
form.fields.push_back(field);
form_structure.reset(new FormStructure(form));
- form_structure->DetermineHeuristicTypes();
+ form_structure->DetermineHeuristicTypes(nullptr /* ukm_service */);
EXPECT_EQ(4U, form_structure->autofill_count());
}
@@ -196,7 +196,7 @@ TEST_F(FormStructureTest, IsAutofillable) {
form.fields.push_back(field);
form_structure.reset(new FormStructure(form));
- form_structure->DetermineHeuristicTypes();
+ form_structure->DetermineHeuristicTypes(nullptr /* ukm_service */);
EXPECT_FALSE(form_structure->IsAutofillable());
// We now have three text fields, but only two auto-fillable fields.
@@ -211,7 +211,7 @@ TEST_F(FormStructureTest, IsAutofillable) {
form.fields.push_back(field);
form_structure.reset(new FormStructure(form));
- form_structure->DetermineHeuristicTypes();
+ form_structure->DetermineHeuristicTypes(nullptr /* ukm_service */);
EXPECT_FALSE(form_structure->IsAutofillable());
// We now have three auto-fillable fields.
@@ -221,19 +221,19 @@ TEST_F(FormStructureTest, IsAutofillable) {
form.fields.push_back(field);
form_structure.reset(new FormStructure(form));
- form_structure->DetermineHeuristicTypes();
+ form_structure->DetermineHeuristicTypes(nullptr /* ukm_service */);
EXPECT_TRUE(form_structure->IsAutofillable());
// The target cannot include http(s)://*/search...
form.action = GURL("http://google.com/search?q=hello");
form_structure.reset(new FormStructure(form));
- form_structure->DetermineHeuristicTypes();
+ form_structure->DetermineHeuristicTypes(nullptr /* ukm_service */);
EXPECT_FALSE(form_structure->IsAutofillable());
// But search can be in the URL.
form.action = GURL("http://search.com/?q=hello");
form_structure.reset(new FormStructure(form));
- form_structure->DetermineHeuristicTypes();
+ form_structure->DetermineHeuristicTypes(nullptr /* ukm_service */);
EXPECT_TRUE(form_structure->IsAutofillable());
}
@@ -334,6 +334,19 @@ TEST_F(FormStructureTest, ShouldBeParsed) {
form.fields.push_back(field);
form_structure.reset(new FormStructure(form));
EXPECT_TRUE(form_structure->ShouldBeParsed());
+
+ // There are 2 fields, one of which is password, and this is an upload of
+ // a sign-in form submission, should be parsed.
+ form.fields.clear();
+ field.name = ASCIIToUTF16("username");
+ field.form_control_type = "text";
+ form.fields.push_back(field);
+ field.name = ASCIIToUTF16("pw");
+ field.form_control_type = "password";
+ form.fields.push_back(field);
+ form_structure.reset(new FormStructure(form));
+ form_structure->set_is_signin_upload(true);
+ EXPECT_TRUE(form_structure->ShouldBeParsed());
}
// Tests that ShouldBeParsed returns true for a form containing less than three
@@ -405,7 +418,7 @@ TEST_F(FormStructureTest, HeuristicsContactInfo) {
form.fields.push_back(field);
form_structure.reset(new FormStructure(form));
- form_structure->DetermineHeuristicTypes();
+ form_structure->DetermineHeuristicTypes(nullptr /* ukm_service */);
EXPECT_TRUE(form_structure->IsAutofillable());
// Expect the correct number of fields.
@@ -456,20 +469,29 @@ TEST_F(FormStructureTest, HeuristicsAutocompleteAttribute) {
field.autocomplete_attribute = "email";
form.fields.push_back(field);
+ field.label = base::string16();
+ field.name = ASCIIToUTF16("field4");
+ field.autocomplete_attribute = "upi-vpa";
+ form.fields.push_back(field);
+
form_structure.reset(new FormStructure(form));
- form_structure->DetermineHeuristicTypes();
+ form_structure->DetermineHeuristicTypes(nullptr /* ukm_service */);
EXPECT_TRUE(form_structure->IsAutofillable());
+ EXPECT_TRUE(form_structure->has_author_specified_types());
+ EXPECT_TRUE(form_structure->has_author_specified_upi_vpa_hint());
// Expect the correct number of fields.
- ASSERT_EQ(3U, form_structure->field_count());
+ ASSERT_EQ(4U, form_structure->field_count());
ASSERT_EQ(3U, form_structure->autofill_count());
EXPECT_EQ(HTML_TYPE_GIVEN_NAME, form_structure->field(0)->html_type());
EXPECT_EQ(HTML_TYPE_FAMILY_NAME, form_structure->field(1)->html_type());
EXPECT_EQ(HTML_TYPE_EMAIL, form_structure->field(2)->html_type());
+ EXPECT_EQ(HTML_TYPE_UNRECOGNIZED, form_structure->field(3)->html_type());
EXPECT_EQ(UNKNOWN_TYPE, form_structure->field(0)->heuristic_type());
EXPECT_EQ(UNKNOWN_TYPE, form_structure->field(1)->heuristic_type());
EXPECT_EQ(UNKNOWN_TYPE, form_structure->field(2)->heuristic_type());
+ EXPECT_EQ(UNKNOWN_TYPE, form_structure->field(3)->heuristic_type());
}
// Verify that the heuristics are not run for non checkout formless forms.
@@ -496,7 +518,7 @@ TEST_F(FormStructureTest, Heuristics_FormlessNonCheckoutForm) {
form.fields.push_back(field);
form_structure.reset(new FormStructure(form));
- form_structure->DetermineHeuristicTypes();
+ form_structure->DetermineHeuristicTypes(nullptr /* ukm_service */);
EXPECT_TRUE(form_structure->IsAutofillable());
// Expect the correct number of fields.
@@ -512,7 +534,7 @@ TEST_F(FormStructureTest, Heuristics_FormlessNonCheckoutForm) {
form.is_form_tag = false;
form_structure.reset(new FormStructure(form));
- form_structure->DetermineHeuristicTypes();
+ form_structure->DetermineHeuristicTypes(nullptr /* ukm_service */);
EXPECT_TRUE(form_structure->IsAutofillable());
// Expect the correct number of fields.
@@ -553,7 +575,7 @@ TEST_F(FormStructureTest, StripCommonNamePrefix) {
form.fields.push_back(field);
std::unique_ptr<FormStructure> form_structure(new FormStructure(form));
- form_structure->DetermineHeuristicTypes();
+ form_structure->DetermineHeuristicTypes(nullptr /* ukm_service */);
EXPECT_TRUE(form_structure->IsAutofillable());
// Expect the correct number of fields.
@@ -593,7 +615,7 @@ TEST_F(FormStructureTest, StripCommonNamePrefix_SmallPrefix) {
form.fields.push_back(field);
std::unique_ptr<FormStructure> form_structure(new FormStructure(form));
- form_structure->DetermineHeuristicTypes();
+ form_structure->DetermineHeuristicTypes(nullptr /* ukm_service */);
EXPECT_TRUE(form_structure->IsAutofillable());
// Expect the correct number of fields.
@@ -629,7 +651,7 @@ TEST_F(FormStructureTest, IsCompleteCreditCardForm_Minimal) {
form.fields.push_back(field);
form_structure.reset(new FormStructure(form));
- form_structure->DetermineHeuristicTypes();
+ form_structure->DetermineHeuristicTypes(nullptr /* ukm_service */);
EXPECT_TRUE(form_structure->IsCompleteCreditCardForm());
}
@@ -667,7 +689,7 @@ TEST_F(FormStructureTest, IsCompleteCreditCardForm_Full) {
form.fields.push_back(field);
form_structure.reset(new FormStructure(form));
- form_structure->DetermineHeuristicTypes();
+ form_structure->DetermineHeuristicTypes(nullptr /* ukm_service */);
EXPECT_TRUE(form_structure->IsCompleteCreditCardForm());
}
@@ -685,7 +707,7 @@ TEST_F(FormStructureTest, IsCompleteCreditCardForm_OnlyCCNumber) {
form.fields.push_back(field);
form_structure.reset(new FormStructure(form));
- form_structure->DetermineHeuristicTypes();
+ form_structure->DetermineHeuristicTypes(nullptr /* ukm_service */);
EXPECT_FALSE(form_structure->IsCompleteCreditCardForm());
}
@@ -726,7 +748,7 @@ TEST_F(FormStructureTest, IsCompleteCreditCardForm_AddressForm) {
field.name = base::string16();
form.fields.push_back(field);
form_structure.reset(new FormStructure(form));
- form_structure->DetermineHeuristicTypes();
+ form_structure->DetermineHeuristicTypes(nullptr /* ukm_service */);
EXPECT_FALSE(form_structure->IsCompleteCreditCardForm());
}
@@ -756,7 +778,7 @@ TEST_F(FormStructureTest, HeuristicsAutocompleteAttributePhoneTypes) {
form.fields.push_back(field);
form_structure.reset(new FormStructure(form));
- form_structure->DetermineHeuristicTypes();
+ form_structure->DetermineHeuristicTypes(nullptr /* ukm_service */);
EXPECT_TRUE(form_structure->IsAutofillable());
// Expect the correct number of fields.
@@ -796,7 +818,7 @@ TEST_F(FormStructureTest,
form.fields.push_back(field);
form_structure.reset(new FormStructure(form));
- form_structure->DetermineHeuristicTypes();
+ form_structure->DetermineHeuristicTypes(nullptr /* ukm_service */);
EXPECT_TRUE(form_structure->IsAutofillable());
EXPECT_TRUE(form_structure->ShouldBeCrowdsourced());
@@ -834,7 +856,7 @@ TEST_F(FormStructureTest,
form.fields.push_back(field);
form_structure.reset(new FormStructure(form));
- form_structure->DetermineHeuristicTypes();
+ form_structure->DetermineHeuristicTypes(nullptr /* ukm_service */);
EXPECT_TRUE(form_structure->IsAutofillable());
EXPECT_TRUE(form_structure->ShouldBeCrowdsourced());
@@ -877,7 +899,7 @@ TEST_F(FormStructureTest,
form.fields.push_back(field);
form_structure.reset(new FormStructure(form));
- form_structure->DetermineHeuristicTypes();
+ form_structure->DetermineHeuristicTypes(nullptr /* ukm_service */);
EXPECT_TRUE(form_structure->IsAutofillable());
EXPECT_TRUE(form_structure->ShouldBeCrowdsourced());
@@ -909,7 +931,7 @@ TEST_F(FormStructureTest,
form.fields.push_back(field);
form_structure.reset(new FormStructure(form));
- form_structure->DetermineHeuristicTypes();
+ form_structure->DetermineHeuristicTypes(nullptr /* ukm_service */);
EXPECT_FALSE(form_structure->IsAutofillable());
EXPECT_FALSE(form_structure->ShouldBeCrowdsourced());
@@ -944,7 +966,7 @@ TEST_F(FormStructureTest,
form.fields.push_back(field);
form_structure.reset(new FormStructure(form));
- form_structure->DetermineHeuristicTypes();
+ form_structure->DetermineHeuristicTypes(nullptr /* ukm_service */);
EXPECT_FALSE(form_structure->IsAutofillable());
EXPECT_FALSE(form_structure->ShouldBeCrowdsourced());
@@ -987,7 +1009,7 @@ TEST_F(FormStructureTest, PasswordFormShouldBeCrowdsourced) {
form.fields.push_back(field);
FormStructure form_structure(form);
- form_structure.DetermineHeuristicTypes();
+ form_structure.DetermineHeuristicTypes(nullptr /* ukm_service */);
EXPECT_TRUE(form_structure.ShouldBeCrowdsourced());
}
@@ -1038,7 +1060,7 @@ TEST_F(FormStructureTest, HeuristicsAutocompleteAttributeWithSections) {
form.fields.push_back(field);
FormStructure form_structure(form);
- form_structure.DetermineHeuristicTypes();
+ form_structure.DetermineHeuristicTypes(nullptr /* ukm_service */);
EXPECT_TRUE(form_structure.IsAutofillable());
// Expect the correct number of fields.
@@ -1083,7 +1105,7 @@ TEST_F(FormStructureTest,
form.fields.push_back(field);
FormStructure form_structure(form);
- form_structure.DetermineHeuristicTypes();
+ form_structure.DetermineHeuristicTypes(nullptr /* ukm_service */);
// Expect the correct number of fields.
ASSERT_EQ(6U, form_structure.field_count());
@@ -1112,7 +1134,7 @@ TEST_F(FormStructureTest, HeuristicsAutocompleteAttributeWithSectionsRepeated) {
form.fields.push_back(field);
FormStructure form_structure(form);
- form_structure.DetermineHeuristicTypes();
+ form_structure.DetermineHeuristicTypes(nullptr /* ukm_service */);
// Expect the correct number of fields.
ASSERT_EQ(2U, form_structure.field_count());
@@ -1149,7 +1171,7 @@ TEST_F(FormStructureTest, HeuristicsDontOverrideAutocompleteAttributeSections) {
form.fields.push_back(field);
FormStructure form_structure(form);
- form_structure.DetermineHeuristicTypes();
+ form_structure.DetermineHeuristicTypes(nullptr /* ukm_service */);
// Expect the correct number of fields.
ASSERT_EQ(4U, form_structure.field_count());
@@ -1213,7 +1235,7 @@ TEST_F(FormStructureTest, HeuristicsSample8) {
form.fields.push_back(field);
form_structure.reset(new FormStructure(form));
- form_structure->DetermineHeuristicTypes();
+ form_structure->DetermineHeuristicTypes(nullptr /* ukm_service */);
EXPECT_TRUE(form_structure->IsAutofillable());
ASSERT_EQ(10U, form_structure->field_count());
ASSERT_EQ(9U, form_structure->autofill_count());
@@ -1279,7 +1301,7 @@ TEST_F(FormStructureTest, HeuristicsSample6) {
form.fields.push_back(field);
form_structure.reset(new FormStructure(form));
- form_structure->DetermineHeuristicTypes();
+ form_structure->DetermineHeuristicTypes(nullptr /* ukm_service */);
EXPECT_TRUE(form_structure->IsAutofillable());
ASSERT_EQ(7U, form_structure->field_count());
ASSERT_EQ(6U, form_structure->autofill_count());
@@ -1344,7 +1366,7 @@ TEST_F(FormStructureTest, HeuristicsLabelsOnly) {
form.fields.push_back(field);
form_structure.reset(new FormStructure(form));
- form_structure->DetermineHeuristicTypes();
+ form_structure->DetermineHeuristicTypes(nullptr /* ukm_service */);
EXPECT_TRUE(form_structure->IsAutofillable());
ASSERT_EQ(8U, form_structure->field_count());
ASSERT_EQ(7U, form_structure->autofill_count());
@@ -1401,7 +1423,7 @@ TEST_F(FormStructureTest, HeuristicsCreditCardInfo) {
form.fields.push_back(field);
form_structure.reset(new FormStructure(form));
- form_structure->DetermineHeuristicTypes();
+ form_structure->DetermineHeuristicTypes(nullptr /* ukm_service */);
EXPECT_TRUE(form_structure->IsAutofillable());
ASSERT_EQ(6U, form_structure->field_count());
ASSERT_EQ(5U, form_structure->autofill_count());
@@ -1461,7 +1483,7 @@ TEST_F(FormStructureTest, HeuristicsCreditCardInfoWithUnknownCardField) {
form.fields.push_back(field);
form_structure.reset(new FormStructure(form));
- form_structure->DetermineHeuristicTypes();
+ form_structure->DetermineHeuristicTypes(nullptr /* ukm_service */);
EXPECT_TRUE(form_structure->IsAutofillable());
ASSERT_EQ(7U, form_structure->field_count());
ASSERT_EQ(5U, form_structure->autofill_count());
@@ -1508,7 +1530,7 @@ TEST_F(FormStructureTest, ThreeAddressLines) {
form.fields.push_back(field);
form_structure.reset(new FormStructure(form));
- form_structure->DetermineHeuristicTypes();
+ form_structure->DetermineHeuristicTypes(nullptr /* ukm_service */);
EXPECT_TRUE(form_structure->IsAutofillable());
ASSERT_EQ(4U, form_structure->field_count());
ASSERT_EQ(4U, form_structure->autofill_count());
@@ -1548,7 +1570,7 @@ TEST_F(FormStructureTest, SurplusAddressLinesIgnored) {
form.fields.push_back(field);
form_structure.reset(new FormStructure(form));
- form_structure->DetermineHeuristicTypes();
+ form_structure->DetermineHeuristicTypes(nullptr /* ukm_service */);
ASSERT_EQ(4U, form_structure->field_count());
ASSERT_EQ(3U, form_structure->autofill_count());
@@ -1591,7 +1613,7 @@ TEST_F(FormStructureTest, ThreeAddressLinesExpedia) {
form.fields.push_back(field);
form_structure.reset(new FormStructure(form));
- form_structure->DetermineHeuristicTypes();
+ form_structure->DetermineHeuristicTypes(nullptr /* ukm_service */);
EXPECT_TRUE(form_structure->IsAutofillable());
ASSERT_EQ(4U, form_structure->field_count());
EXPECT_EQ(4U, form_structure->autofill_count());
@@ -1629,7 +1651,7 @@ TEST_F(FormStructureTest, TwoAddressLinesEbay) {
form.fields.push_back(field);
form_structure.reset(new FormStructure(form));
- form_structure->DetermineHeuristicTypes();
+ form_structure->DetermineHeuristicTypes(nullptr /* ukm_service */);
EXPECT_TRUE(form_structure->IsAutofillable());
ASSERT_EQ(3U, form_structure->field_count());
ASSERT_EQ(3U, form_structure->autofill_count());
@@ -1662,7 +1684,7 @@ TEST_F(FormStructureTest, HeuristicsStateWithProvince) {
form.fields.push_back(field);
form_structure.reset(new FormStructure(form));
- form_structure->DetermineHeuristicTypes();
+ form_structure->DetermineHeuristicTypes(nullptr /* ukm_service */);
EXPECT_TRUE(form_structure->IsAutofillable());
ASSERT_EQ(3U, form_structure->field_count());
ASSERT_EQ(3U, form_structure->autofill_count());
@@ -1728,7 +1750,7 @@ TEST_F(FormStructureTest, HeuristicsWithBilling) {
form.fields.push_back(field);
form_structure.reset(new FormStructure(form));
- form_structure->DetermineHeuristicTypes();
+ form_structure->DetermineHeuristicTypes(nullptr /* ukm_service */);
EXPECT_TRUE(form_structure->IsAutofillable());
ASSERT_EQ(11U, form_structure->field_count());
ASSERT_EQ(11U, form_structure->autofill_count());
@@ -1777,7 +1799,7 @@ TEST_F(FormStructureTest, ThreePartPhoneNumber) {
form.fields.push_back(field);
form_structure.reset(new FormStructure(form));
- form_structure->DetermineHeuristicTypes();
+ form_structure->DetermineHeuristicTypes(nullptr /* ukm_service */);
EXPECT_TRUE(form_structure->IsAutofillable());
ASSERT_EQ(4U, form_structure->field_count());
ASSERT_EQ(4U, form_structure->autofill_count());
@@ -1822,7 +1844,7 @@ TEST_F(FormStructureTest, HeuristicsInfernoCC) {
form.fields.push_back(field);
form_structure.reset(new FormStructure(form));
- form_structure->DetermineHeuristicTypes();
+ form_structure->DetermineHeuristicTypes(nullptr /* ukm_service */);
EXPECT_TRUE(form_structure->IsAutofillable());
// Expect the correct number of fields.
@@ -1876,7 +1898,7 @@ TEST_F(FormStructureTest, HeuristicsInferCCNames_NamesNotFirst) {
form.fields.push_back(field);
form_structure.reset(new FormStructure(form));
- form_structure->DetermineHeuristicTypes();
+ form_structure->DetermineHeuristicTypes(nullptr /* ukm_service */);
EXPECT_TRUE(form_structure->IsAutofillable());
// Expect the correct number of fields.
@@ -1934,7 +1956,7 @@ TEST_F(FormStructureTest, HeuristicsInferCCNames_NamesFirst) {
form.fields.push_back(field);
form_structure.reset(new FormStructure(form));
- form_structure->DetermineHeuristicTypes();
+ form_structure->DetermineHeuristicTypes(nullptr /* ukm_service */);
EXPECT_TRUE(form_structure->IsAutofillable());
// Expect the correct number of fields.
@@ -2117,7 +2139,7 @@ TEST_F(FormStructureTest, EncodeUploadRequest) {
std::vector<ServerFieldTypeSet> possible_field_types;
FormData form;
form_structure.reset(new FormStructure(form));
- form_structure->DetermineHeuristicTypes();
+ form_structure->DetermineHeuristicTypes(nullptr /* ukm_service */);
FormFieldData field;
field.form_control_type = "text";
@@ -2293,7 +2315,7 @@ TEST_F(FormStructureTest,
std::vector<ServerFieldTypeSet> possible_field_types;
FormData form;
form_structure.reset(new FormStructure(form));
- form_structure->DetermineHeuristicTypes();
+ form_structure->DetermineHeuristicTypes(nullptr /* ukm_service */);
FormFieldData field;
field.label = ASCIIToUTF16("First Name");
@@ -2432,7 +2454,7 @@ TEST_F(FormStructureTest, EncodeUploadRequest_WithAutocomplete) {
std::vector<ServerFieldTypeSet> possible_field_types;
FormData form;
form_structure.reset(new FormStructure(form));
- form_structure->DetermineHeuristicTypes();
+ form_structure->DetermineHeuristicTypes(nullptr /* ukm_service */);
FormFieldData field;
field.form_control_type = "text";
@@ -2503,7 +2525,7 @@ TEST_F(FormStructureTest, EncodeUploadRequest_ObservedSubmissionFalse) {
std::vector<ServerFieldTypeSet> possible_field_types;
FormData form;
form_structure.reset(new FormStructure(form));
- form_structure->DetermineHeuristicTypes();
+ form_structure->DetermineHeuristicTypes(nullptr /* ukm_service */);
FormFieldData field;
field.form_control_type = "text";
@@ -2572,7 +2594,7 @@ TEST_F(FormStructureTest, EncodeUploadRequest_WithLabels) {
std::vector<ServerFieldTypeSet> possible_field_types;
FormData form;
form_structure.reset(new FormStructure(form));
- form_structure->DetermineHeuristicTypes();
+ form_structure->DetermineHeuristicTypes(nullptr /* ukm_service */);
FormFieldData field;
field.form_control_type = "text";
@@ -2709,7 +2731,7 @@ TEST_F(FormStructureTest, EncodeUploadRequest_WithFormName) {
// Setting the form name which we expect to see in the upload.
form.name = ASCIIToUTF16("myform");
form_structure.reset(new FormStructure(form));
- form_structure->DetermineHeuristicTypes();
+ form_structure->DetermineHeuristicTypes(nullptr /* ukm_service */);
FormFieldData field;
field.form_control_type = "text";
@@ -2771,7 +2793,7 @@ TEST_F(FormStructureTest, EncodeUploadRequestPartialMetadata) {
std::vector<ServerFieldTypeSet> possible_field_types;
FormData form;
form_structure.reset(new FormStructure(form));
- form_structure->DetermineHeuristicTypes();
+ form_structure->DetermineHeuristicTypes(nullptr /* ukm_service */);
FormFieldData field;
field.form_control_type = "text";
@@ -2844,7 +2866,7 @@ TEST_F(FormStructureTest, EncodeUploadRequest_DisabledMetadataTrial) {
std::vector<ServerFieldTypeSet> possible_field_types;
FormData form;
form_structure.reset(new FormStructure(form));
- form_structure->DetermineHeuristicTypes();
+ form_structure->DetermineHeuristicTypes(nullptr /* ukm_service */);
FormFieldData field;
field.form_control_type = "text";
@@ -3772,7 +3794,7 @@ TEST_F(FormStructureTest, ParseQueryResponseAuthorDefinedTypes) {
FormStructure form_structure(form);
std::vector<FormStructure*> forms;
forms.push_back(&form_structure);
- forms.front()->DetermineHeuristicTypes();
+ forms.front()->DetermineHeuristicTypes(nullptr /* ukm_service */);
AutofillQueryResponseContents response;
response.add_field()->set_autofill_type(EMAIL_ADDRESS);
diff --git a/chromium/components/autofill/core/browser/payments/full_card_request.cc b/chromium/components/autofill/core/browser/payments/full_card_request.cc
index ee21ebaf829..68177a70329 100644
--- a/chromium/components/autofill/core/browser/payments/full_card_request.cc
+++ b/chromium/components/autofill/core/browser/payments/full_card_request.cc
@@ -16,17 +16,17 @@
namespace autofill {
namespace payments {
-FullCardRequest::FullCardRequest(AutofillClient* autofill_client,
+FullCardRequest::FullCardRequest(RiskDataLoader* risk_data_loader,
payments::PaymentsClient* payments_client,
PersonalDataManager* personal_data_manager)
- : autofill_client_(autofill_client),
+ : risk_data_loader_(risk_data_loader),
payments_client_(payments_client),
personal_data_manager_(personal_data_manager),
result_delegate_(nullptr),
ui_delegate_(nullptr),
should_unmask_card_(false),
weak_ptr_factory_(this) {
- DCHECK(autofill_client_);
+ DCHECK(risk_data_loader_);
DCHECK(payments_client_);
DCHECK(personal_data_manager_);
}
@@ -62,7 +62,7 @@ void FullCardRequest::GetFullCard(const CreditCard& card,
weak_ptr_factory_.GetWeakPtr());
if (should_unmask_card_) {
- autofill_client_->LoadRiskData(
+ risk_data_loader_->LoadRiskData(
base::Bind(&FullCardRequest::OnDidGetUnmaskRiskData,
weak_ptr_factory_.GetWeakPtr()));
}
diff --git a/chromium/components/autofill/core/browser/payments/full_card_request.h b/chromium/components/autofill/core/browser/payments/full_card_request.h
index 263b3c88fe7..9db61fd5ad3 100644
--- a/chromium/components/autofill/core/browser/payments/full_card_request.h
+++ b/chromium/components/autofill/core/browser/payments/full_card_request.h
@@ -48,7 +48,7 @@ class FullCardRequest : public CardUnmaskDelegate {
};
// The parameters should outlive the FullCardRequest.
- FullCardRequest(AutofillClient* autofill_client,
+ FullCardRequest(RiskDataLoader* risk_data_loader,
payments::PaymentsClient* payments_client,
PersonalDataManager* personal_data_manager);
~FullCardRequest();
@@ -83,9 +83,8 @@ class FullCardRequest : public CardUnmaskDelegate {
// Resets the state of the request.
void Reset();
- // Responsible for showing the UI that prompts the user for the CVC and/or the
- // updated expiration date.
- AutofillClient* const autofill_client_;
+ // Used to fetch risk data for this request.
+ RiskDataLoader* const risk_data_loader_;
// Responsible for unmasking a masked server card.
payments::PaymentsClient* const payments_client_;
diff --git a/chromium/components/autofill/core/browser/payments/payments_client.cc b/chromium/components/autofill/core/browser/payments/payments_client.cc
index 5fbeca35005..44e85c2e8d9 100644
--- a/chromium/components/autofill/core/browser/payments/payments_client.cc
+++ b/chromium/components/autofill/core/browser/payments/payments_client.cc
@@ -28,6 +28,7 @@
#include "net/base/escape.h"
#include "net/base/load_flags.h"
#include "net/http/http_status_code.h"
+#include "net/traffic_annotation/network_traffic_annotation.h"
#include "net/url_request/url_fetcher.h"
#include "net/url_request/url_request_context_getter.h"
@@ -415,9 +416,44 @@ void PaymentsClient::IssueRequest(std::unique_ptr<PaymentsRequest> request,
}
void PaymentsClient::InitializeUrlFetcher() {
+ net::NetworkTrafficAnnotationTag traffic_annotation =
+ net::DefineNetworkTrafficAnnotation("payments_sync_cards", R"(
+ semantics {
+ sender: "Payments"
+ description:
+ "This service communicates with Google Payments servers to upload "
+ "(save) or receive the user's credit card info."
+ trigger:
+ "Requests are triggered by a user action, such as selecting a "
+ "masked server card from Chromium's credit card autofill dropdown, "
+ "submitting a form which has credit card information, or accepting "
+ "the prompt to save a credit card to Payments servers."
+ data:
+ "In case of save, a protocol buffer containing relevant address "
+ "and credit card information which should be saved in Google "
+ "Payments servers, along with user credentials. In case of load, a "
+ "protocol buffer containing the id of the credit card to unmask, "
+ "an encrypted cvc value, an optional updated card expiration date, "
+ "and user credentials."
+ destination: GOOGLE_OWNED_SERVICE
+ }
+ policy {
+ cookies_allowed: false
+ setting:
+ "Users can enable or disable this feature in Chromium settings by "
+ "toggling 'Credit cards and addresses using Google Payments', "
+ "under 'Advanced sync settings...'. This feature is enabled by "
+ "default."
+ chrome_policy {
+ AutoFillEnabled {
+ policy_options {mode: MANDATORY}
+ AutoFillEnabled: false
+ }
+ }
+ })");
url_fetcher_ =
net::URLFetcher::Create(0, GetRequestUrl(request_->GetRequestUrlPath()),
- net::URLFetcher::POST, this);
+ net::URLFetcher::POST, this, traffic_annotation);
data_use_measurement::DataUseUserData::AttachToFetcher(
url_fetcher_.get(), data_use_measurement::DataUseUserData::AUTOFILL);
diff --git a/chromium/components/autofill/core/browser/personal_data_manager.cc b/chromium/components/autofill/core/browser/personal_data_manager.cc
index 1ea5a2f555f..e634110a718 100644
--- a/chromium/components/autofill/core/browser/personal_data_manager.cc
+++ b/chromium/components/autofill/core/browser/personal_data_manager.cc
@@ -883,7 +883,11 @@ std::vector<Suggestion> PersonalDataManager::GetProfileSuggestions(
// trial group or SIZE_MAX if no limit is defined.
std::string limit_str = variations::GetVariationParamValue(
kFrecencyFieldTrialName, kFrecencyFieldTrialLimitParam);
- size_t limit = base::StringToSizeT(limit_str, &limit) ? limit : SIZE_MAX;
+ size_t limit = SIZE_MAX;
+ // Reassign SIZE_MAX to |limit| is needed after calling base::StringToSizeT,
+ // as this method can modify |limit| even if it returns false.
+ if (!base::StringToSizeT(limit_str, &limit))
+ limit = SIZE_MAX;
unique_suggestions.resize(std::min(unique_suggestions.size(), limit));
diff --git a/chromium/components/autofill/core/browser/personal_data_manager.h b/chromium/components/autofill/core/browser/personal_data_manager.h
index a7f9808e53a..d8247d526c0 100644
--- a/chromium/components/autofill/core/browser/personal_data_manager.h
+++ b/chromium/components/autofill/core/browser/personal_data_manager.h
@@ -27,9 +27,7 @@
#include "components/keyed_service/core/keyed_service.h"
#include "components/prefs/pref_member.h"
#include "components/webdata/common/web_data_service_consumer.h"
-#if defined(OS_ANDROID)
#include "net/url_request/url_request_context_getter.h"
-#endif
class AccountTrackerService;
class Browser;
@@ -148,7 +146,7 @@ class PersonalDataManager : public KeyedService,
const std::vector<AutofillProfile*>& profiles);
// Adds |credit_card| to the web database.
- void AddCreditCard(const CreditCard& credit_card);
+ virtual void AddCreditCard(const CreditCard& credit_card);
// Updates |credit_card| which already exists in the web database. This
// can only be used on local credit cards.
@@ -274,7 +272,6 @@ class PersonalDataManager : public KeyedService,
NotifyPersonalDataChanged();
}
-#if defined(OS_ANDROID)
// Sets the URL request context getter to be used when normalizing addresses
// with libaddressinput's address validator.
void SetURLRequestContextGetter(
@@ -286,7 +283,6 @@ class PersonalDataManager : public KeyedService,
net::URLRequestContextGetter* GetURLRequestContextGetter() const {
return context_getter_.get();
}
-#endif
protected:
// Only PersonalDataManagerFactory and certain tests can create instances of
@@ -330,17 +326,19 @@ class PersonalDataManager : public KeyedService,
ConvertWalletAddressesAndUpdateWalletCards_MergedProfile);
FRIEND_TEST_ALL_PREFIXES(
PersonalDataManagerTest,
- ConvertWalletAddressesAndUpdateWalletCards_NewCard_AddressAlreadyConverted);
+ ConvertWalletAddressesAndUpdateWalletCards_NewCard_AddressAlreadyConverted); // NOLINT
FRIEND_TEST_ALL_PREFIXES(
PersonalDataManagerTest,
ConvertWalletAddressesAndUpdateWalletCards_AlreadyConverted);
FRIEND_TEST_ALL_PREFIXES(
PersonalDataManagerTest,
- ConvertWalletAddressesAndUpdateWalletCards_MultipleSimilarWalletAddresses);
+ ConvertWalletAddressesAndUpdateWalletCards_MultipleSimilarWalletAddresses); // NOLINT
friend class autofill::AutofillInteractiveTest;
friend class autofill::AutofillTest;
friend class autofill::PersonalDataManagerFactory;
friend class PersonalDataManagerTest;
+ friend class PersonalDataManagerTestBase;
+ friend class SaveImportedProfileTest;
friend class ProfileSyncServiceAutofillTest;
friend class ::RemoveAutofillTester;
friend std::default_delete<PersonalDataManager>;
@@ -600,11 +598,9 @@ class PersonalDataManager : public KeyedService,
// Whether new information was received from the sync server.
bool has_synced_new_data_ = false;
-#if defined(OS_ANDROID)
// The context for the request to be used to fetch libaddressinput's address
// validation rules.
scoped_refptr<net::URLRequestContextGetter> context_getter_;
-#endif
DISALLOW_COPY_AND_ASSIGN(PersonalDataManager);
};
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 6bb7a52b7e0..f5b2aa6d4ce 100644
--- a/chromium/components/autofill/core/browser/personal_data_manager_unittest.cc
+++ b/chromium/components/autofill/core/browser/personal_data_manager_unittest.cc
@@ -119,60 +119,9 @@ void ExpectSameElements(const std::vector<T*>& expectations,
} // anonymous namespace
-class PersonalDataManagerTest : public testing::Test {
+class PersonalDataManagerTestBase {
protected:
- PersonalDataManagerTest() : autofill_table_(nullptr) {}
-
- void SetUp() override {
- OSCryptMocker::SetUpWithSingleton();
- prefs_ = test::PrefServiceForTesting();
- ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
- base::FilePath path = temp_dir_.GetPath().AppendASCII("TestWebDB");
- web_database_ =
- new WebDatabaseService(path, base::ThreadTaskRunnerHandle::Get(),
- base::ThreadTaskRunnerHandle::Get());
-
- // Setup account tracker.
- signin_client_.reset(new TestSigninClient(prefs_.get()));
- account_tracker_.reset(new AccountTrackerService());
- account_tracker_->Initialize(signin_client_.get());
- signin_manager_.reset(new FakeSigninManagerBase(signin_client_.get(),
- account_tracker_.get()));
- signin_manager_->Initialize(prefs_.get());
-
- // Hacky: hold onto a pointer but pass ownership.
- autofill_table_ = new AutofillTable;
- web_database_->AddTable(std::unique_ptr<WebDatabaseTable>(autofill_table_));
- web_database_->LoadDatabase();
- autofill_database_service_ = new AutofillWebDataService(
- web_database_, base::ThreadTaskRunnerHandle::Get(),
- base::ThreadTaskRunnerHandle::Get(),
- WebDataServiceBase::ProfileErrorCallback());
- autofill_database_service_->Init();
-
- test::DisableSystemServices(prefs_.get());
- ResetPersonalDataManager(USER_MODE_NORMAL);
-
- // Reset the deduping pref to its default value.
- personal_data_->pref_service_->SetInteger(
- prefs::kAutofillLastVersionDeduped, 0);
- personal_data_->pref_service_->SetBoolean(
- prefs::kAutofillProfileUseDatesFixed, false);
- }
-
- void TearDown() override {
- // Order of destruction is important as AutofillManager relies on
- // PersonalDataManager to be around when it gets destroyed.
- signin_manager_->Shutdown();
- signin_manager_.reset();
-
- account_tracker_->Shutdown();
- account_tracker_.reset();
- signin_client_.reset();
-
- test::DisableSystemServices(prefs_.get());
- OSCryptMocker::TearDown();
- }
+ PersonalDataManagerTestBase() : autofill_table_(nullptr) {}
void ResetPersonalDataManager(UserMode user_mode) {
bool is_incognito = (user_mode == USER_MODE_INCOGNITO);
@@ -315,7 +264,7 @@ class PersonalDataManagerTest : public testing::Test {
const char* exp_cc_month,
const char* exp_cc_year) {
FormStructure form_structure(form);
- form_structure.DetermineHeuristicTypes();
+ form_structure.DetermineHeuristicTypes(nullptr /* ukm_service */);
std::unique_ptr<CreditCard> imported_credit_card;
EXPECT_TRUE(ImportCreditCard(form_structure, false, &imported_credit_card));
ASSERT_TRUE(imported_credit_card);
@@ -351,6 +300,60 @@ class PersonalDataManagerTest : public testing::Test {
variations::testing::VariationParamsManager variation_params_;
};
+class PersonalDataManagerTest : public PersonalDataManagerTestBase,
+ public testing::Test {
+ void SetUp() override {
+ OSCryptMocker::SetUpWithSingleton();
+ prefs_ = test::PrefServiceForTesting();
+ ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
+ base::FilePath path = temp_dir_.GetPath().AppendASCII("TestWebDB");
+ web_database_ =
+ new WebDatabaseService(path, base::ThreadTaskRunnerHandle::Get(),
+ base::ThreadTaskRunnerHandle::Get());
+
+ // Setup account tracker.
+ signin_client_.reset(new TestSigninClient(prefs_.get()));
+ account_tracker_.reset(new AccountTrackerService());
+ account_tracker_->Initialize(signin_client_.get());
+ signin_manager_.reset(new FakeSigninManagerBase(signin_client_.get(),
+ account_tracker_.get()));
+ signin_manager_->Initialize(prefs_.get());
+
+ // Hacky: hold onto a pointer but pass ownership.
+ autofill_table_ = new AutofillTable;
+ web_database_->AddTable(std::unique_ptr<WebDatabaseTable>(autofill_table_));
+ web_database_->LoadDatabase();
+ autofill_database_service_ = new AutofillWebDataService(
+ web_database_, base::ThreadTaskRunnerHandle::Get(),
+ base::ThreadTaskRunnerHandle::Get(),
+ WebDataServiceBase::ProfileErrorCallback());
+ autofill_database_service_->Init();
+
+ test::DisableSystemServices(prefs_.get());
+ ResetPersonalDataManager(USER_MODE_NORMAL);
+
+ // Reset the deduping pref to its default value.
+ personal_data_->pref_service_->SetInteger(
+ prefs::kAutofillLastVersionDeduped, 0);
+ personal_data_->pref_service_->SetBoolean(
+ prefs::kAutofillProfileUseDatesFixed, false);
+ }
+
+ void TearDown() override {
+ // Order of destruction is important as AutofillManager relies on
+ // PersonalDataManager to be around when it gets destroyed.
+ signin_manager_->Shutdown();
+ signin_manager_.reset();
+
+ account_tracker_->Shutdown();
+ account_tracker_.reset();
+ signin_client_.reset();
+
+ test::DisableSystemServices(prefs_.get());
+ OSCryptMocker::TearDown();
+ }
+};
+
TEST_F(PersonalDataManagerTest, AddProfile) {
// Add profile0 to the database.
AutofillProfile profile0(test::GetFullProfile());
@@ -1030,7 +1033,7 @@ TEST_F(PersonalDataManagerTest, ImportAddressProfiles) {
test::CreateTestFormField("Zip:", "zip", "94102", "text", &field);
form.fields.push_back(field);
FormStructure form_structure(form);
- form_structure.DetermineHeuristicTypes();
+ form_structure.DetermineHeuristicTypes(nullptr /* ukm_service */);
EXPECT_TRUE(ImportAddressProfiles(form_structure));
// Verify that the web database has been updated and the notification sent.
@@ -1068,7 +1071,7 @@ TEST_F(PersonalDataManagerTest, ImportAddressProfiles_BadEmail) {
test::CreateTestFormField("Zip:", "zip", "94102", "text", &field);
form.fields.push_back(field);
FormStructure form_structure(form);
- form_structure.DetermineHeuristicTypes();
+ form_structure.DetermineHeuristicTypes(nullptr /* ukm_service */);
EXPECT_FALSE(ImportAddressProfiles(form_structure));
const std::vector<AutofillProfile*>& results = personal_data_->GetProfiles();
@@ -1098,7 +1101,7 @@ TEST_F(PersonalDataManagerTest, ImportAddressProfiles_TwoEmails) {
"Confirm email:", "confirm_email", "example@example.com", "text", &field);
form.fields.push_back(field);
FormStructure form_structure(form);
- form_structure.DetermineHeuristicTypes();
+ form_structure.DetermineHeuristicTypes(nullptr /* ukm_service */);
EXPECT_TRUE(ImportAddressProfiles(form_structure));
const std::vector<AutofillProfile*>& results = personal_data_->GetProfiles();
ASSERT_EQ(1U, results.size());
@@ -1127,7 +1130,7 @@ TEST_F(PersonalDataManagerTest, ImportAddressProfiles_TwoDifferentEmails) {
"Email:", "email2", "example2@example.com", "text", &field);
form.fields.push_back(field);
FormStructure form_structure(form);
- form_structure.DetermineHeuristicTypes();
+ form_structure.DetermineHeuristicTypes(nullptr /* ukm_service */);
EXPECT_FALSE(ImportAddressProfiles(form_structure));
const std::vector<AutofillProfile*>& results = personal_data_->GetProfiles();
ASSERT_EQ(0U, results.size());
@@ -1147,7 +1150,7 @@ TEST_F(PersonalDataManagerTest, ImportAddressProfiles_NotEnoughFilledFields) {
"Card number:", "card_number", "4111 1111 1111 1111", "text", &field);
form.fields.push_back(field);
FormStructure form_structure(form);
- form_structure.DetermineHeuristicTypes();
+ form_structure.DetermineHeuristicTypes(nullptr /* ukm_service */);
EXPECT_FALSE(ImportAddressProfiles(form_structure));
const std::vector<AutofillProfile*>& profiles = personal_data_->GetProfiles();
@@ -1175,7 +1178,7 @@ TEST_F(PersonalDataManagerTest, ImportAddressProfiles_MinimumAddressUSA) {
test::CreateTestFormField("Country:", "country", "USA", "text", &field);
form.fields.push_back(field);
FormStructure form_structure(form);
- form_structure.DetermineHeuristicTypes();
+ form_structure.DetermineHeuristicTypes(nullptr /* ukm_service */);
EXPECT_TRUE(ImportAddressProfiles(form_structure));
const std::vector<AutofillProfile*>& profiles = personal_data_->GetProfiles();
ASSERT_EQ(1U, profiles.size());
@@ -1200,7 +1203,7 @@ TEST_F(PersonalDataManagerTest, ImportAddressProfiles_MinimumAddressGB) {
"Country:", "country", "United Kingdom", "text", &field);
form.fields.push_back(field);
FormStructure form_structure(form);
- form_structure.DetermineHeuristicTypes();
+ form_structure.DetermineHeuristicTypes(nullptr /* ukm_service */);
EXPECT_TRUE(ImportAddressProfiles(form_structure));
const std::vector<AutofillProfile*>& profiles = personal_data_->GetProfiles();
ASSERT_EQ(1U, profiles.size());
@@ -1220,7 +1223,7 @@ TEST_F(PersonalDataManagerTest, ImportAddressProfiles_MinimumAddressGI) {
test::CreateTestFormField("Country:", "country", "Gibraltar", "text", &field);
form.fields.push_back(field);
FormStructure form_structure(form);
- form_structure.DetermineHeuristicTypes();
+ form_structure.DetermineHeuristicTypes(nullptr /* ukm_service */);
EXPECT_TRUE(ImportAddressProfiles(form_structure));
const std::vector<AutofillProfile*>& profiles = personal_data_->GetProfiles();
ASSERT_EQ(1U, profiles.size());
@@ -1258,7 +1261,7 @@ TEST_F(PersonalDataManagerTest,
test::CreateTestFormField("Zip:", "zip", "94102", "text", &field);
form.fields.push_back(field);
FormStructure form_structure(form);
- form_structure.DetermineHeuristicTypes();
+ form_structure.DetermineHeuristicTypes(nullptr /* ukm_service */);
EXPECT_TRUE(ImportAddressProfiles(form_structure));
// Verify that the web database has been updated and the notification sent.
@@ -1302,7 +1305,7 @@ TEST_F(PersonalDataManagerTest, ImportAddressProfiles_MultilineAddress) {
test::CreateTestFormField("Zip:", "zip", "94102", "text", &field);
form.fields.push_back(field);
FormStructure form_structure(form);
- form_structure.DetermineHeuristicTypes();
+ form_structure.DetermineHeuristicTypes(nullptr /* ukm_service */);
EXPECT_TRUE(ImportAddressProfiles(form_structure));
// Verify that the web database has been updated and the notification sent.
@@ -1343,7 +1346,7 @@ TEST_F(PersonalDataManagerTest,
form1.fields.push_back(field);
FormStructure form_structure1(form1);
- form_structure1.DetermineHeuristicTypes();
+ form_structure1.DetermineHeuristicTypes(nullptr /* ukm_service */);
EXPECT_TRUE(ImportAddressProfiles(form_structure1));
// Verify that the web database has been updated and the notification sent.
@@ -1381,7 +1384,7 @@ TEST_F(PersonalDataManagerTest,
form2.fields.push_back(field);
FormStructure form_structure2(form2);
- form_structure2.DetermineHeuristicTypes();
+ form_structure2.DetermineHeuristicTypes(nullptr /* ukm_service */);
EXPECT_TRUE(ImportAddressProfiles(form_structure2));
// Verify that the web database has been updated and the notification sent.
@@ -1442,7 +1445,7 @@ TEST_F(PersonalDataManagerTest,
form.fields.push_back(field);
FormStructure form_structure(form);
- form_structure.DetermineHeuristicTypes();
+ form_structure.DetermineHeuristicTypes(nullptr /* ukm_service */);
EXPECT_TRUE(ImportAddressProfiles(form_structure));
// Verify that the web database has been updated and the notification sent.
@@ -1520,7 +1523,7 @@ TEST_F(PersonalDataManagerTest,
// Still able to do the import.
FormStructure form_structure(form);
- form_structure.DetermineHeuristicTypes();
+ form_structure.DetermineHeuristicTypes(nullptr /* ukm_service */);
EXPECT_TRUE(ImportAddressProfiles(form_structure));
// Verify that the web database has been updated and the notification sent.
@@ -1604,7 +1607,7 @@ TEST_F(PersonalDataManagerTest,
form.fields.push_back(field);
FormStructure form_structure(form);
- form_structure.DetermineHeuristicTypes();
+ form_structure.DetermineHeuristicTypes(nullptr /* ukm_service */);
EXPECT_TRUE(ImportAddressProfiles(form_structure));
// Verify that the web database has been updated and the notification sent.
@@ -1659,7 +1662,7 @@ TEST_F(PersonalDataManagerTest, ImportAddressProfiles_SameProfileWithConflict) {
form1.fields.push_back(field);
FormStructure form_structure1(form1);
- form_structure1.DetermineHeuristicTypes();
+ form_structure1.DetermineHeuristicTypes(nullptr /* ukm_service */);
EXPECT_TRUE(ImportAddressProfiles(form_structure1));
// Verify that the web database has been updated and the notification sent.
@@ -1707,7 +1710,7 @@ TEST_F(PersonalDataManagerTest, ImportAddressProfiles_SameProfileWithConflict) {
form2.fields.push_back(field);
FormStructure form_structure2(form2);
- form_structure2.DetermineHeuristicTypes();
+ form_structure2.DetermineHeuristicTypes(nullptr /* ukm_service */);
EXPECT_TRUE(ImportAddressProfiles(form_structure2));
// Verify that the web database has been updated and the notification sent.
@@ -1745,7 +1748,7 @@ TEST_F(PersonalDataManagerTest, ImportAddressProfiles_MissingInfoInOld) {
form1.fields.push_back(field);
FormStructure form_structure1(form1);
- form_structure1.DetermineHeuristicTypes();
+ form_structure1.DetermineHeuristicTypes(nullptr /* ukm_service */);
EXPECT_TRUE(ImportAddressProfiles(form_structure1));
// Verify that the web database has been updated and the notification sent.
@@ -1783,7 +1786,7 @@ TEST_F(PersonalDataManagerTest, ImportAddressProfiles_MissingInfoInOld) {
form2.fields.push_back(field);
FormStructure form_structure2(form2);
- form_structure2.DetermineHeuristicTypes();
+ form_structure2.DetermineHeuristicTypes(nullptr /* ukm_service */);
EXPECT_TRUE(ImportAddressProfiles(form_structure2));
// Verify that the web database has been updated and the notification sent.
@@ -1828,7 +1831,7 @@ TEST_F(PersonalDataManagerTest, ImportAddressProfiles_MissingInfoInNew) {
form1.fields.push_back(field);
FormStructure form_structure1(form1);
- form_structure1.DetermineHeuristicTypes();
+ form_structure1.DetermineHeuristicTypes(nullptr /* ukm_service */);
EXPECT_TRUE(ImportAddressProfiles(form_structure1));
// Verify that the web database has been updated and the notification sent.
@@ -1867,7 +1870,7 @@ TEST_F(PersonalDataManagerTest, ImportAddressProfiles_MissingInfoInNew) {
form2.fields.push_back(field);
FormStructure form_structure2(form2);
- form_structure2.DetermineHeuristicTypes();
+ form_structure2.DetermineHeuristicTypes(nullptr /* ukm_service */);
EXPECT_TRUE(ImportAddressProfiles(form_structure2));
// Verify that the web database has been updated and the notification sent.
@@ -1905,7 +1908,7 @@ TEST_F(PersonalDataManagerTest, ImportAddressProfiles_InsufficientAddress) {
form1.fields.push_back(field);
FormStructure form_structure1(form1);
- form_structure1.DetermineHeuristicTypes();
+ form_structure1.DetermineHeuristicTypes(nullptr /* ukm_service */);
EXPECT_FALSE(ImportAddressProfiles(form_structure1));
// Since no refresh is expected, reload the data from the database to make
@@ -1962,7 +1965,7 @@ TEST_F(PersonalDataManagerTest,
form.fields.push_back(field);
FormStructure form_structure(form);
- form_structure.DetermineHeuristicTypes();
+ form_structure.DetermineHeuristicTypes(nullptr /* ukm_service */);
EXPECT_TRUE(ImportAddressProfiles(form_structure));
// Wait for the refresh, which in this case is a no-op.
@@ -1983,7 +1986,7 @@ TEST_F(PersonalDataManagerTest,
form.fields[0] = field;
FormStructure form_structure2(form);
- form_structure2.DetermineHeuristicTypes();
+ form_structure2.DetermineHeuristicTypes(nullptr /* ukm_service */);
EXPECT_TRUE(ImportAddressProfiles(form_structure2));
// Wait for the refresh, which in this case is a no-op.
@@ -2024,7 +2027,7 @@ TEST_F(PersonalDataManagerTest, ImportAddressProfiles_UnrecognizedCountry) {
form.fields.push_back(field);
FormStructure form_structure(form);
- form_structure.DetermineHeuristicTypes();
+ form_structure.DetermineHeuristicTypes(nullptr /* ukm_service */);
EXPECT_FALSE(ImportAddressProfiles(form_structure));
// Since no refresh is expected, reload the data from the database to make
@@ -2065,7 +2068,7 @@ TEST_F(PersonalDataManagerTest,
form.fields.push_back(field);
FormStructure form_structure(form);
- form_structure.DetermineHeuristicTypes();
+ form_structure.DetermineHeuristicTypes(nullptr /* ukm_service */);
EXPECT_TRUE(ImportAddressProfiles(form_structure));
// Verify that the web database has been updated and the notification sent.
@@ -2114,7 +2117,7 @@ TEST_F(PersonalDataManagerTest,
form.fields.push_back(field);
FormStructure form_structure(form);
- form_structure.DetermineHeuristicTypes();
+ form_structure.DetermineHeuristicTypes(nullptr /* ukm_service */);
EXPECT_FALSE(ImportAddressProfiles(form_structure));
// Since no refresh is expected, reload the data from the database to make
@@ -2137,7 +2140,7 @@ TEST_F(PersonalDataManagerTest, ImportCreditCard_Valid) {
"2999");
FormStructure form_structure(form);
- form_structure.DetermineHeuristicTypes();
+ form_structure.DetermineHeuristicTypes(nullptr /* ukm_service */);
std::unique_ptr<CreditCard> imported_credit_card;
EXPECT_TRUE(ImportCreditCard(form_structure, false, &imported_credit_card));
ASSERT_TRUE(imported_credit_card);
@@ -2163,7 +2166,7 @@ TEST_F(PersonalDataManagerTest, ImportCreditCard_Invalid) {
"2999");
FormStructure form_structure(form);
- form_structure.DetermineHeuristicTypes();
+ form_structure.DetermineHeuristicTypes(nullptr /* ukm_service */);
std::unique_ptr<CreditCard> imported_credit_card;
EXPECT_FALSE(ImportCreditCard(form_structure, false, &imported_credit_card));
ASSERT_FALSE(imported_credit_card);
@@ -2197,7 +2200,7 @@ TEST_F(PersonalDataManagerTest, ImportCreditCard_MonthSelectInvalidText) {
form.fields[2].option_contents = contents;
FormStructure form_structure(form);
- form_structure.DetermineHeuristicTypes();
+ form_structure.DetermineHeuristicTypes(nullptr /* ukm_service */);
std::unique_ptr<CreditCard> imported_credit_card;
EXPECT_TRUE(ImportCreditCard(form_structure, false, &imported_credit_card));
ASSERT_TRUE(imported_credit_card);
@@ -2224,7 +2227,7 @@ TEST_F(PersonalDataManagerTest, ImportCreditCard_TwoValidCards) {
"2999");
FormStructure form_structure1(form1);
- form_structure1.DetermineHeuristicTypes();
+ form_structure1.DetermineHeuristicTypes(nullptr /* ukm_service */);
std::unique_ptr<CreditCard> imported_credit_card;
EXPECT_TRUE(ImportCreditCard(form_structure1, false, &imported_credit_card));
ASSERT_TRUE(imported_credit_card);
@@ -2247,7 +2250,7 @@ TEST_F(PersonalDataManagerTest, ImportCreditCard_TwoValidCards) {
AddFullCreditCardForm(&form2, "", "5500 0000 0000 0004", "02", "2999");
FormStructure form_structure2(form2);
- form_structure2.DetermineHeuristicTypes();
+ form_structure2.DetermineHeuristicTypes(nullptr /* ukm_service */);
std::unique_ptr<CreditCard> imported_credit_card2;
EXPECT_TRUE(ImportCreditCard(form_structure2, false, &imported_credit_card2));
ASSERT_TRUE(imported_credit_card2);
@@ -2362,7 +2365,7 @@ TEST_F(PersonalDataManagerTest,
// The card should be offered to be saved locally because it only matches the
// masked server card.
FormStructure form_structure(form);
- form_structure.DetermineHeuristicTypes();
+ form_structure.DetermineHeuristicTypes(nullptr /* ukm_service */);
std::unique_ptr<CreditCard> imported_credit_card;
EXPECT_TRUE(ImportCreditCard(form_structure, false, &imported_credit_card));
ASSERT_TRUE(imported_credit_card);
@@ -2392,7 +2395,7 @@ TEST_F(PersonalDataManagerTest,
// The card should not be offered to be saved locally because it only matches
// the full server card.
FormStructure form_structure(form);
- form_structure.DetermineHeuristicTypes();
+ form_structure.DetermineHeuristicTypes(nullptr /* ukm_service */);
std::unique_ptr<CreditCard> imported_credit_card;
EXPECT_FALSE(ImportCreditCard(form_structure, false, &imported_credit_card));
ASSERT_FALSE(imported_credit_card);
@@ -2405,7 +2408,7 @@ TEST_F(PersonalDataManagerTest, ImportCreditCard_SameCreditCardWithConflict) {
"2998");
FormStructure form_structure1(form1);
- form_structure1.DetermineHeuristicTypes();
+ form_structure1.DetermineHeuristicTypes(nullptr /* ukm_service */);
std::unique_ptr<CreditCard> imported_credit_card;
EXPECT_TRUE(ImportCreditCard(form_structure1, false, &imported_credit_card));
ASSERT_TRUE(imported_credit_card);
@@ -2430,7 +2433,7 @@ TEST_F(PersonalDataManagerTest, ImportCreditCard_SameCreditCardWithConflict) {
/* different year */ "2999");
FormStructure form_structure2(form2);
- form_structure2.DetermineHeuristicTypes();
+ form_structure2.DetermineHeuristicTypes(nullptr /* ukm_service */);
std::unique_ptr<CreditCard> imported_credit_card2;
EXPECT_TRUE(ImportCreditCard(form_structure2, false, &imported_credit_card2));
EXPECT_FALSE(imported_credit_card2);
@@ -2457,7 +2460,7 @@ TEST_F(PersonalDataManagerTest, ImportCreditCard_ShouldReturnLocalCard) {
"2998");
FormStructure form_structure1(form1);
- form_structure1.DetermineHeuristicTypes();
+ form_structure1.DetermineHeuristicTypes(nullptr /* ukm_service */);
std::unique_ptr<CreditCard> imported_credit_card;
EXPECT_TRUE(ImportCreditCard(form_structure1, false, &imported_credit_card));
ASSERT_TRUE(imported_credit_card);
@@ -2482,7 +2485,7 @@ TEST_F(PersonalDataManagerTest, ImportCreditCard_ShouldReturnLocalCard) {
/* different year */ "2999");
FormStructure form_structure2(form2);
- form_structure2.DetermineHeuristicTypes();
+ form_structure2.DetermineHeuristicTypes(nullptr /* ukm_service */);
std::unique_ptr<CreditCard> imported_credit_card2;
EXPECT_TRUE(ImportCreditCard(form_structure2,
/* should_return_local_card= */ true,
@@ -2512,7 +2515,7 @@ TEST_F(PersonalDataManagerTest, ImportCreditCard_EmptyCardWithConflict) {
"2998");
FormStructure form_structure1(form1);
- form_structure1.DetermineHeuristicTypes();
+ form_structure1.DetermineHeuristicTypes(nullptr /* ukm_service */);
std::unique_ptr<CreditCard> imported_credit_card;
EXPECT_TRUE(ImportCreditCard(form_structure1, false, &imported_credit_card));
ASSERT_TRUE(imported_credit_card);
@@ -2536,7 +2539,7 @@ TEST_F(PersonalDataManagerTest, ImportCreditCard_EmptyCardWithConflict) {
"2999");
FormStructure form_structure2(form2);
- form_structure2.DetermineHeuristicTypes();
+ form_structure2.DetermineHeuristicTypes(nullptr /* ukm_service */);
std::unique_ptr<CreditCard> imported_credit_card2;
EXPECT_FALSE(
ImportCreditCard(form_structure2, false, &imported_credit_card2));
@@ -2562,7 +2565,7 @@ TEST_F(PersonalDataManagerTest, ImportCreditCard_MissingInfoInNew) {
"2999");
FormStructure form_structure1(form1);
- form_structure1.DetermineHeuristicTypes();
+ form_structure1.DetermineHeuristicTypes(nullptr /* ukm_service */);
std::unique_ptr<CreditCard> imported_credit_card;
EXPECT_TRUE(ImportCreditCard(form_structure1, false, &imported_credit_card));
ASSERT_TRUE(imported_credit_card);
@@ -2587,7 +2590,7 @@ TEST_F(PersonalDataManagerTest, ImportCreditCard_MissingInfoInNew) {
"4111-1111-1111-1111", "01", "2999");
FormStructure form_structure2(form2);
- form_structure2.DetermineHeuristicTypes();
+ form_structure2.DetermineHeuristicTypes(nullptr /* ukm_service */);
std::unique_ptr<CreditCard> imported_credit_card2;
EXPECT_TRUE(ImportCreditCard(form_structure2, false, &imported_credit_card2));
EXPECT_FALSE(imported_credit_card2);
@@ -2611,7 +2614,7 @@ TEST_F(PersonalDataManagerTest, ImportCreditCard_MissingInfoInNew) {
/* no year */ nullptr);
FormStructure form_structure3(form3);
- form_structure3.DetermineHeuristicTypes();
+ form_structure3.DetermineHeuristicTypes(nullptr /* ukm_service */);
std::unique_ptr<CreditCard> imported_credit_card3;
EXPECT_FALSE(
ImportCreditCard(form_structure3, false, &imported_credit_card3));
@@ -2654,7 +2657,7 @@ TEST_F(PersonalDataManagerTest, ImportCreditCard_MissingInfoInOld) {
/* different year */ "2999");
FormStructure form_structure(form);
- form_structure.DetermineHeuristicTypes();
+ form_structure.DetermineHeuristicTypes(nullptr /* ukm_service */);
std::unique_ptr<CreditCard> imported_credit_card;
EXPECT_TRUE(ImportCreditCard(form_structure, false, &imported_credit_card));
EXPECT_FALSE(imported_credit_card);
@@ -2699,7 +2702,7 @@ TEST_F(PersonalDataManagerTest, ImportCreditCard_SameCardWithSeparators) {
"2999");
FormStructure form_structure(form);
- form_structure.DetermineHeuristicTypes();
+ form_structure.DetermineHeuristicTypes(nullptr /* ukm_service */);
std::unique_ptr<CreditCard> imported_credit_card;
EXPECT_TRUE(ImportCreditCard(form_structure, false, &imported_credit_card));
EXPECT_FALSE(imported_credit_card);
@@ -2738,7 +2741,7 @@ TEST_F(PersonalDataManagerTest,
/* different year */ "2999");
FormStructure form_structure(form);
- form_structure.DetermineHeuristicTypes();
+ form_structure.DetermineHeuristicTypes(nullptr /* ukm_service */);
std::unique_ptr<CreditCard> imported_credit_card;
EXPECT_TRUE(ImportCreditCard(form_structure, false, &imported_credit_card));
ASSERT_FALSE(imported_credit_card);
@@ -2785,7 +2788,7 @@ TEST_F(PersonalDataManagerTest, ImportFormData_OneAddressOneCreditCard) {
"2999");
FormStructure form_structure(form);
- form_structure.DetermineHeuristicTypes();
+ form_structure.DetermineHeuristicTypes(nullptr /* ukm_service */);
std::unique_ptr<CreditCard> imported_credit_card;
EXPECT_TRUE(personal_data_->ImportFormData(form_structure, false,
&imported_credit_card));
@@ -2863,7 +2866,7 @@ TEST_F(PersonalDataManagerTest, ImportFormData_TwoAddressesOneCreditCard) {
"2999");
FormStructure form_structure(form);
- form_structure.DetermineHeuristicTypes();
+ form_structure.DetermineHeuristicTypes(nullptr /* ukm_service */);
std::unique_ptr<CreditCard> imported_credit_card;
// Still returns true because the credit card import was successful.
EXPECT_TRUE(personal_data_->ImportFormData(form_structure, false,
@@ -4139,7 +4142,7 @@ TEST_F(PersonalDataManagerTest, DontDuplicateServerCard) {
form1.fields.push_back(field);
FormStructure form_structure1(form1);
- form_structure1.DetermineHeuristicTypes();
+ form_structure1.DetermineHeuristicTypes(nullptr /* ukm_service */);
std::unique_ptr<CreditCard> imported_credit_card;
EXPECT_FALSE(personal_data_->ImportFormData(form_structure1, false,
&imported_credit_card));
@@ -4161,7 +4164,7 @@ TEST_F(PersonalDataManagerTest, DontDuplicateServerCard) {
form2.fields.push_back(field);
FormStructure form_structure2(form2);
- form_structure2.DetermineHeuristicTypes();
+ form_structure2.DetermineHeuristicTypes(nullptr /* ukm_service */);
std::unique_ptr<CreditCard> imported_credit_card2;
EXPECT_FALSE(personal_data_->ImportFormData(form_structure2, false,
&imported_credit_card2));
@@ -4170,10 +4173,9 @@ TEST_F(PersonalDataManagerTest, DontDuplicateServerCard) {
// Tests the SaveImportedProfile method with different profiles to make sure the
// merge logic works correctly.
-TEST_F(PersonalDataManagerTest, SaveImportedProfile) {
- typedef struct {
- autofill::ServerFieldType field_type;
- std::string field_value;
+typedef struct {
+ autofill::ServerFieldType field_type;
+ std::string field_value;
} ProfileField;
typedef std::vector<ProfileField> ProfileFields;
@@ -4188,254 +4190,72 @@ TEST_F(PersonalDataManagerTest, SaveImportedProfile) {
// For tests with profile merging, makes sure that these fields' values are
// the ones we expect (depending on the test).
ProfileFields changed_field_values;
- } TestCase;
-
- TestCase test_cases[] = {
- // Test that saving an identical profile except for the name results in
- // two profiles being saved.
- {ProfileFields(), {{NAME_FIRST, "Marionette"}}},
-
- // Test that saving an identical profile except with the middle name
- // initial instead of the full middle name results in the profiles
- // getting merged and the full middle name being kept.
- {ProfileFields(),
- {{NAME_MIDDLE, "M"}},
- {{NAME_MIDDLE, "Mitchell"}, {NAME_FULL, "Marion Mitchell Morrison"}}},
-
- // Test that saving an identical profile except with the full middle name
- // instead of the middle name initial results in the profiles getting
- // merged and the full middle name replacing the initial.
- {{{NAME_MIDDLE, "M"}},
- {{NAME_MIDDLE, "Mitchell"}},
- {{NAME_MIDDLE, "Mitchell"}}},
-
- // Test that saving an identical profile except with no middle name
- // results in the profiles getting merged and the full middle name being
- // kept.
- {ProfileFields(), {{NAME_MIDDLE, ""}}, {{NAME_MIDDLE, "Mitchell"}}},
-
- // Test that saving an identical profile except with a middle name initial
- // results in the profiles getting merged and the middle name initial
- // being saved.
- {{{NAME_MIDDLE, ""}}, {{NAME_MIDDLE, "M"}}, {{NAME_MIDDLE, "M"}}},
-
- // Test that saving an identical profile except with a middle name
- // results in the profiles getting merged and the full middle name being
- // saved.
- {{{NAME_MIDDLE, ""}},
- {{NAME_MIDDLE, "Mitchell"}},
- {{NAME_MIDDLE, "Mitchell"}}},
-
- // Test that saving a identical profile except with the full name set
- // instead of the name parts results in the two profiles being merged and
- // all the name parts kept and the full name being added.
- {
- {
- {NAME_FIRST, "Marion"},
- {NAME_MIDDLE, "Mitchell"},
- {NAME_LAST, "Morrison"},
- {NAME_FULL, ""},
- },
- {
- {NAME_FIRST, ""},
- {NAME_MIDDLE, ""},
- {NAME_LAST, ""},
- {NAME_FULL, "Marion Mitchell Morrison"},
- },
- {
- {NAME_FIRST, "Marion"},
- {NAME_MIDDLE, "Mitchell"},
- {NAME_LAST, "Morrison"},
- {NAME_FULL, "Marion Mitchell Morrison"},
- },
- },
-
- // Test that saving a identical profile except with the name parts set
- // instead of the full name results in the two profiles being merged and
- // the full name being kept and all the name parts being added.
- {
- {
- {NAME_FIRST, ""},
- {NAME_MIDDLE, ""},
- {NAME_LAST, ""},
- {NAME_FULL, "Marion Mitchell Morrison"},
- },
- {
- {NAME_FIRST, "Marion"},
- {NAME_MIDDLE, "Mitchell"},
- {NAME_LAST, "Morrison"},
- {NAME_FULL, ""},
- },
- {
- {NAME_FIRST, "Marion"},
- {NAME_MIDDLE, "Mitchell"},
- {NAME_LAST, "Morrison"},
- {NAME_FULL, "Marion Mitchell Morrison"},
- },
- },
-
- // Test that saving a profile that has only a full name set does not get
- // merged with a profile with only the name parts set if the names are
- // different.
- {
- {
- {NAME_FIRST, "Marion"},
- {NAME_MIDDLE, "Mitchell"},
- {NAME_LAST, "Morrison"},
- {NAME_FULL, ""},
- },
- {
- {NAME_FIRST, ""},
- {NAME_MIDDLE, ""},
- {NAME_LAST, ""},
- {NAME_FULL, "John Thompson Smith"},
- },
- },
-
- // Test that saving a profile that has only the name parts set does not
- // get merged with a profile with only the full name set if the names are
- // different.
- {
- {
- {NAME_FIRST, ""},
- {NAME_MIDDLE, ""},
- {NAME_LAST, ""},
- {NAME_FULL, "John Thompson Smith"},
- },
- {
- {NAME_FIRST, "Marion"},
- {NAME_MIDDLE, "Mitchell"},
- {NAME_LAST, "Morrison"},
- {NAME_FULL, ""},
- },
- },
-
- // Test that saving an identical profile except for the first address line
- // results in two profiles being saved.
- {ProfileFields(), {{ADDRESS_HOME_LINE1, "123 Aquarium St."}}},
-
- // Test that saving an identical profile except for the second address
- // line results in two profiles being saved.
- {ProfileFields(), {{ADDRESS_HOME_LINE2, "unit 7"}}},
-
- // Tests that saving an identical profile that has a new piece of
- // information (company name) results in a merge and that the original
- // empty value gets overwritten by the new information.
- {{{COMPANY_NAME, ""}}, ProfileFields(), {{COMPANY_NAME, "Fox"}}},
-
- // Tests that saving an identical profile except a loss of information
- // results in a merge but the original value is not overwritten (no
- // information loss).
- {ProfileFields(), {{COMPANY_NAME, ""}}, {{COMPANY_NAME, "Fox"}}},
-
- // Tests that saving an identical profile except a slightly different
- // postal code results in a merge with the new value kept.
- {{{ADDRESS_HOME_ZIP, "R2C 0A1"}},
- {{ADDRESS_HOME_ZIP, "R2C0A1"}},
- {{ADDRESS_HOME_ZIP, "R2C0A1"}}},
- {{{ADDRESS_HOME_ZIP, "R2C0A1"}},
- {{ADDRESS_HOME_ZIP, "R2C 0A1"}},
- {{ADDRESS_HOME_ZIP, "R2C 0A1"}}},
- {{{ADDRESS_HOME_ZIP, "r2c 0a1"}},
- {{ADDRESS_HOME_ZIP, "R2C0A1"}},
- {{ADDRESS_HOME_ZIP, "R2C0A1"}}},
-
- // Tests that saving an identical profile plus a new piece of information
- // on the address line 2 results in a merge and that the original empty
- // value gets overwritten by the new information.
- {{{ADDRESS_HOME_LINE2, ""}},
- ProfileFields(),
- {{ADDRESS_HOME_LINE2, "unit 5"}}},
-
- // Tests that saving an identical profile except a loss of information on
- // the address line 2 results in a merge but that the original value gets
- // not overwritten (no information loss).
- {ProfileFields(),
- {{ADDRESS_HOME_LINE2, ""}},
- {{ADDRESS_HOME_LINE2, "unit 5"}}},
-
- // Tests that saving an identical except with more punctuation in the fist
- // address line, while the second is empty, results in a merge and that
- // the original address gets overwritten.
- {{{ADDRESS_HOME_LINE2, ""}},
- {{ADDRESS_HOME_LINE2, ""}, {ADDRESS_HOME_LINE1, "123, Zoo St."}},
- {{ADDRESS_HOME_LINE1, "123, Zoo St."}}},
-
- // Tests that saving an identical profile except with less punctuation in
- // the fist address line, while the second is empty, results in a merge
- // and that the longer address is retained.
- {{{ADDRESS_HOME_LINE2, ""}, {ADDRESS_HOME_LINE1, "123, Zoo St."}},
- {{ADDRESS_HOME_LINE2, ""}},
- {{ADDRESS_HOME_LINE1, "123 Zoo St"}}},
-
- // Tests that saving an identical profile except additional punctuation in
- // the two address lines results in a merge and that the newer address
- // is retained.
- {ProfileFields(),
- {{ADDRESS_HOME_LINE1, "123, Zoo St."}, {ADDRESS_HOME_LINE2, "unit. 5"}},
- {{ADDRESS_HOME_LINE1, "123, Zoo St."}, {ADDRESS_HOME_LINE2, "unit. 5"}}},
-
- // Tests that saving an identical profile except less punctuation in the
- // two address lines results in a merge and that the newer address is
- // retained.
- {{{ADDRESS_HOME_LINE1, "123, Zoo St."}, {ADDRESS_HOME_LINE2, "unit. 5"}},
- ProfileFields(),
- {{ADDRESS_HOME_LINE1, "123 Zoo St"}, {ADDRESS_HOME_LINE2, "unit 5"}}},
-
- // Tests that saving an identical profile with accented characters in
- // the two address lines results in a merge and that the newer address
- // is retained.
- {ProfileFields(),
- {{ADDRESS_HOME_LINE1, "123 Zôö St"}, {ADDRESS_HOME_LINE2, "üñìt 5"}},
- {{ADDRESS_HOME_LINE1, "123 Zôö St"}, {ADDRESS_HOME_LINE2, "üñìt 5"}}},
-
- // Tests that saving an identical profile without accented characters in
- // the two address lines results in a merge and that the newer address
- // is retained.
- {{{ADDRESS_HOME_LINE1, "123 Zôö St"}, {ADDRESS_HOME_LINE2, "üñìt 5"}},
- ProfileFields(),
- {{ADDRESS_HOME_LINE1, "123 Zoo St"}, {ADDRESS_HOME_LINE2, "unit 5"}}},
-
- // Tests that saving an identical profile except that the address line 1
- // is in the address line 2 results in a merge and that the multi-lne
- // address is retained.
- {ProfileFields(),
- {{ADDRESS_HOME_LINE1, "123 Zoo St, unit 5"}, {ADDRESS_HOME_LINE2, ""}},
- {{ADDRESS_HOME_LINE1, "123 Zoo St"}, {ADDRESS_HOME_LINE2, "unit 5"}}},
-
- // Tests that saving an identical profile except that the address line 2
- // contains part of the old address line 1 results in a merge and that the
- // original address lines of the reference profile get overwritten.
- {{{ADDRESS_HOME_LINE1, "123 Zoo St, unit 5"}, {ADDRESS_HOME_LINE2, ""}},
- ProfileFields(),
- {{ADDRESS_HOME_LINE1, "123 Zoo St"}, {ADDRESS_HOME_LINE2, "unit 5"}}},
-
- // Tests that saving an identical profile except that the state is the
- // abbreviation instead of the full form results in a merge and that the
- // original state gets overwritten.
- {{{ADDRESS_HOME_STATE, "California"}},
- ProfileFields(),
- {{ADDRESS_HOME_STATE, "CA"}}},
-
- // Tests that saving an identical profile except that the state is the
- // full form instead of the abbreviation results in a merge and that the
- // abbreviated state is retained.
- {ProfileFields(),
- {{ADDRESS_HOME_STATE, "California"}},
- {{ADDRESS_HOME_STATE, "CA"}}},
-
- // Tests that saving and identical profile except that the company name
- // has different punctuation and case results in a merge and that the
- // syntax of the new profile replaces the old one.
- {{{COMPANY_NAME, "Stark inc"}},
- {{COMPANY_NAME, "Stark Inc."}},
- {{COMPANY_NAME, "Stark Inc."}}},
- };
+ } SaveImportedProfileTestCase;
+
+ class SaveImportedProfileTest
+ : public PersonalDataManagerTestBase,
+ public testing::TestWithParam<SaveImportedProfileTestCase> {
+ public:
+ SaveImportedProfileTest() {}
+ ~SaveImportedProfileTest() override {}
+
+ void SetUp() override {
+ OSCryptMocker::SetUpWithSingleton();
+ prefs_ = test::PrefServiceForTesting();
+ ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
+ base::FilePath path = temp_dir_.GetPath().AppendASCII("TestWebDB");
+ web_database_ =
+ new WebDatabaseService(path, base::ThreadTaskRunnerHandle::Get(),
+ base::ThreadTaskRunnerHandle::Get());
+
+ // Setup account tracker.
+ signin_client_.reset(new TestSigninClient(prefs_.get()));
+ account_tracker_.reset(new AccountTrackerService());
+ account_tracker_->Initialize(signin_client_.get());
+ signin_manager_.reset(new FakeSigninManagerBase(signin_client_.get(),
+ account_tracker_.get()));
+ signin_manager_->Initialize(prefs_.get());
+
+ // Hacky: hold onto a pointer but pass ownership.
+ autofill_table_ = new AutofillTable;
+ web_database_->AddTable(
+ std::unique_ptr<WebDatabaseTable>(autofill_table_));
+ web_database_->LoadDatabase();
+ autofill_database_service_ = new AutofillWebDataService(
+ web_database_, base::ThreadTaskRunnerHandle::Get(),
+ base::ThreadTaskRunnerHandle::Get(),
+ WebDataServiceBase::ProfileErrorCallback());
+ autofill_database_service_->Init();
+
+ test::DisableSystemServices(prefs_.get());
+ ResetPersonalDataManager(USER_MODE_NORMAL);
+
+ // Reset the deduping pref to its default value.
+ personal_data_->pref_service_->SetInteger(
+ prefs::kAutofillLastVersionDeduped, 0);
+ personal_data_->pref_service_->SetBoolean(
+ prefs::kAutofillProfileUseDatesFixed, false);
+ }
- // Create the test clock.
- TestAutofillClock test_clock;
+ void TearDown() override {
+ // Order of destruction is important as AutofillManager relies on
+ // PersonalDataManager to be around when it gets destroyed.
+ signin_manager_->Shutdown();
+ signin_manager_.reset();
+
+ account_tracker_->Shutdown();
+ account_tracker_.reset();
+ signin_client_.reset();
+
+ test::DisableSystemServices(prefs_.get());
+ OSCryptMocker::TearDown();
+ }
+ };
- for (TestCase test_case : test_cases) {
+ TEST_P(SaveImportedProfileTest, SaveImportedProfile) {
+ // Create the test clock.
+ TestAutofillClock test_clock;
+ auto test_case = GetParam();
// Set the time to a specific value.
test_clock.SetNow(kArbitraryTime);
@@ -4490,45 +4310,322 @@ TEST_F(PersonalDataManagerTest, SaveImportedProfile) {
// Erase the profiles for the next test.
ResetProfiles();
}
-}
-
-// Tests that MergeProfile tries to merge the imported profile into the
-// existing profile in decreasing order of frecency.
-TEST_F(PersonalDataManagerTest, MergeProfile_Frecency) {
- // Create two very similar profiles except with different company names.
- std::unique_ptr<AutofillProfile> profile1 = base::MakeUnique<AutofillProfile>(
- base::GenerateGUID(), "https://www.example.com");
- test::SetProfileInfo(profile1.get(), "Homer", "Jay", "Simpson",
- "homer.simpson@abc.com", "SNP", "742 Evergreen Terrace",
- "", "Springfield", "IL", "91601", "US", "12345678910");
- AutofillProfile* profile2 =
- new AutofillProfile(base::GenerateGUID(), "https://www.example.com");
- test::SetProfileInfo(profile2, "Homer", "Jay", "Simpson",
- "homer.simpson@abc.com", "Fox", "742 Evergreen Terrace",
- "", "Springfield", "IL", "91601", "US", "12345678910");
- // Give the "Fox" profile a bigger frecency score.
- profile2->set_use_count(15);
+ INSTANTIATE_TEST_CASE_P(
+ PersonalDataManagerTest,
+ SaveImportedProfileTest,
+ testing::Values(
+ // Test that saving an identical profile except for the name results
+ // in two profiles being saved.
+ SaveImportedProfileTestCase{ProfileFields(),
+ {{NAME_FIRST, "Marionette"}}},
+
+ // Test that saving an identical profile except with the middle name
+ // initial instead of the full middle name results in the profiles
+ // getting merged and the full middle name being kept.
+ SaveImportedProfileTestCase{
+ ProfileFields(),
+ {{NAME_MIDDLE, "M"}},
+ {{NAME_MIDDLE, "Mitchell"},
+ {NAME_FULL, "Marion Mitchell Morrison"}}},
+
+ // Test that saving an identical profile except with the full middle
+ // name instead of the middle name initial results in the profiles
+ // getting merged and the full middle name replacing the initial.
+ SaveImportedProfileTestCase{{{NAME_MIDDLE, "M"}},
+ {{NAME_MIDDLE, "Mitchell"}},
+ {{NAME_MIDDLE, "Mitchell"}}},
+
+ // Test that saving an identical profile except with no middle name
+ // results in the profiles getting merged and the full middle name
+ // being kept.
+ SaveImportedProfileTestCase{ProfileFields(),
+ {{NAME_MIDDLE, ""}},
+ {{NAME_MIDDLE, "Mitchell"}}},
+
+ // Test that saving an identical profile except with a middle name
+ // initial results in the profiles getting merged and the middle name
+ // initial being saved.
+ SaveImportedProfileTestCase{{{NAME_MIDDLE, ""}},
+ {{NAME_MIDDLE, "M"}},
+ {{NAME_MIDDLE, "M"}}},
+
+ // Test that saving an identical profile except with a middle name
+ // results in the profiles getting merged and the full middle name
+ // being saved.
+ SaveImportedProfileTestCase{{{NAME_MIDDLE, ""}},
+ {{NAME_MIDDLE, "Mitchell"}},
+ {{NAME_MIDDLE, "Mitchell"}}},
+
+ // Test that saving a identical profile except with the full name set
+ // instead of the name parts results in the two profiles being merged
+ // and all the name parts kept and the full name being added.
+ SaveImportedProfileTestCase{
+ {
+ {NAME_FIRST, "Marion"},
+ {NAME_MIDDLE, "Mitchell"},
+ {NAME_LAST, "Morrison"},
+ {NAME_FULL, ""},
+ },
+ {
+ {NAME_FIRST, ""},
+ {NAME_MIDDLE, ""},
+ {NAME_LAST, ""},
+ {NAME_FULL, "Marion Mitchell Morrison"},
+ },
+ {
+ {NAME_FIRST, "Marion"},
+ {NAME_MIDDLE, "Mitchell"},
+ {NAME_LAST, "Morrison"},
+ {NAME_FULL, "Marion Mitchell Morrison"},
+ },
+ },
- // Create the |existing_profiles| vector.
- std::vector<std::unique_ptr<AutofillProfile>> existing_profiles;
- existing_profiles.push_back(std::move(profile1));
- existing_profiles.push_back(base::WrapUnique(profile2));
+ // Test that saving a identical profile except with the name parts set
+ // instead of the full name results in the two profiles being merged
+ // and the full name being kept and all the name parts being added.
+ SaveImportedProfileTestCase{
+ {
+ {NAME_FIRST, ""},
+ {NAME_MIDDLE, ""},
+ {NAME_LAST, ""},
+ {NAME_FULL, "Marion Mitchell Morrison"},
+ },
+ {
+ {NAME_FIRST, "Marion"},
+ {NAME_MIDDLE, "Mitchell"},
+ {NAME_LAST, "Morrison"},
+ {NAME_FULL, ""},
+ },
+ {
+ {NAME_FIRST, "Marion"},
+ {NAME_MIDDLE, "Mitchell"},
+ {NAME_LAST, "Morrison"},
+ {NAME_FULL, "Marion Mitchell Morrison"},
+ },
+ },
- // Create a new imported profile with no company name.
- AutofillProfile imported_profile(base::GenerateGUID(),
- "https://www.example.com");
- test::SetProfileInfo(&imported_profile, "Homer", "Jay", "Simpson",
- "homer.simpson@abc.com", "", "742 Evergreen Terrace", "",
- "Springfield", "IL", "91601", "US", "12345678910");
+ // Test that saving a profile that has only a full name set does not
+ // get merged with a profile with only the name parts set if the names
+ // are different.
+ SaveImportedProfileTestCase{
+ {
+ {NAME_FIRST, "Marion"},
+ {NAME_MIDDLE, "Mitchell"},
+ {NAME_LAST, "Morrison"},
+ {NAME_FULL, ""},
+ },
+ {
+ {NAME_FIRST, ""},
+ {NAME_MIDDLE, ""},
+ {NAME_LAST, ""},
+ {NAME_FULL, "John Thompson Smith"},
+ },
+ },
- // Merge the imported profile into the existing profiles.
- std::vector<AutofillProfile> profiles;
- std::string guid = personal_data_->MergeProfile(
- imported_profile, &existing_profiles, "US-EN", &profiles);
+ // Test that saving a profile that has only the name parts set does
+ // not get merged with a profile with only the full name set if the
+ // names are different.
+ SaveImportedProfileTestCase{
+ {
+ {NAME_FIRST, ""},
+ {NAME_MIDDLE, ""},
+ {NAME_LAST, ""},
+ {NAME_FULL, "John Thompson Smith"},
+ },
+ {
+ {NAME_FIRST, "Marion"},
+ {NAME_MIDDLE, "Mitchell"},
+ {NAME_LAST, "Morrison"},
+ {NAME_FULL, ""},
+ },
+ },
- // The new profile should be merged into the "fox" profile.
- EXPECT_EQ(profile2->guid(), guid);
+ // Test that saving an identical profile except for the first address
+ // line results in two profiles being saved.
+ SaveImportedProfileTestCase{
+ ProfileFields(),
+ {{ADDRESS_HOME_LINE1, "123 Aquarium St."}}},
+
+ // Test that saving an identical profile except for the second address
+ // line results in two profiles being saved.
+ SaveImportedProfileTestCase{ProfileFields(),
+ {{ADDRESS_HOME_LINE2, "unit 7"}}},
+
+ // Tests that saving an identical profile that has a new piece of
+ // information (company name) results in a merge and that the original
+ // empty value gets overwritten by the new information.
+ SaveImportedProfileTestCase{{{COMPANY_NAME, ""}},
+ ProfileFields(),
+ {{COMPANY_NAME, "Fox"}}},
+
+ // Tests that saving an identical profile except a loss of information
+ // results in a merge but the original value is not overwritten (no
+ // information loss).
+ SaveImportedProfileTestCase{ProfileFields(),
+ {{COMPANY_NAME, ""}},
+ {{COMPANY_NAME, "Fox"}}},
+
+ // Tests that saving an identical profile except a slightly different
+ // postal code results in a merge with the new value kept.
+ SaveImportedProfileTestCase{{{ADDRESS_HOME_ZIP, "R2C 0A1"}},
+ {{ADDRESS_HOME_ZIP, "R2C0A1"}},
+ {{ADDRESS_HOME_ZIP, "R2C0A1"}}},
+ SaveImportedProfileTestCase{{{ADDRESS_HOME_ZIP, "R2C0A1"}},
+ {{ADDRESS_HOME_ZIP, "R2C 0A1"}},
+ {{ADDRESS_HOME_ZIP, "R2C 0A1"}}},
+ SaveImportedProfileTestCase{{{ADDRESS_HOME_ZIP, "r2c 0a1"}},
+ {{ADDRESS_HOME_ZIP, "R2C0A1"}},
+ {{ADDRESS_HOME_ZIP, "R2C0A1"}}},
+
+ // Tests that saving an identical profile plus a new piece of
+ // information on the address line 2 results in a merge and that the
+ // original empty value gets overwritten by the new information.
+ SaveImportedProfileTestCase{{{ADDRESS_HOME_LINE2, ""}},
+ ProfileFields(),
+ {{ADDRESS_HOME_LINE2, "unit 5"}}},
+
+ // Tests that saving an identical profile except a loss of information
+ // on the address line 2 results in a merge but that the original
+ // value gets not overwritten (no information loss).
+ SaveImportedProfileTestCase{ProfileFields(),
+ {{ADDRESS_HOME_LINE2, ""}},
+ {{ADDRESS_HOME_LINE2, "unit 5"}}},
+
+ // Tests that saving an identical except with more punctuation in the
+ // fist address line, while the second is empty, results in a merge
+ // and that the original address gets overwritten.
+ SaveImportedProfileTestCase{
+ {{ADDRESS_HOME_LINE2, ""}},
+ {{ADDRESS_HOME_LINE2, ""}, {ADDRESS_HOME_LINE1, "123, Zoo St."}},
+ {{ADDRESS_HOME_LINE1, "123, Zoo St."}}},
+
+ // Tests that saving an identical profile except with less punctuation
+ // in the fist address line, while the second is empty, results in a
+ // merge and that the longer address is retained.
+ SaveImportedProfileTestCase{
+ {{ADDRESS_HOME_LINE2, ""}, {ADDRESS_HOME_LINE1, "123, Zoo St."}},
+ {{ADDRESS_HOME_LINE2, ""}},
+ {{ADDRESS_HOME_LINE1, "123 Zoo St"}}},
+
+ // Tests that saving an identical profile except additional
+ // punctuation in the two address lines results in a merge and that
+ // the newer address is retained.
+ SaveImportedProfileTestCase{ProfileFields(),
+ {{ADDRESS_HOME_LINE1, "123, Zoo St."},
+ {ADDRESS_HOME_LINE2, "unit. 5"}},
+ {{ADDRESS_HOME_LINE1, "123, Zoo St."},
+ {ADDRESS_HOME_LINE2, "unit. 5"}}},
+
+ // Tests that saving an identical profile except less punctuation in
+ // the two address lines results in a merge and that the newer address
+ // is retained.
+ SaveImportedProfileTestCase{{{ADDRESS_HOME_LINE1, "123, Zoo St."},
+ {ADDRESS_HOME_LINE2, "unit. 5"}},
+ ProfileFields(),
+ {{ADDRESS_HOME_LINE1, "123 Zoo St"},
+ {ADDRESS_HOME_LINE2, "unit 5"}}},
+
+ // Tests that saving an identical profile with accented characters in
+ // the two address lines results in a merge and that the newer address
+ // is retained.
+ SaveImportedProfileTestCase{ProfileFields(),
+ {{ADDRESS_HOME_LINE1, "123 Zôö St"},
+ {ADDRESS_HOME_LINE2, "üñìt 5"}},
+ {{ADDRESS_HOME_LINE1, "123 Zôö St"},
+ {ADDRESS_HOME_LINE2, "üñìt 5"}}},
+
+ // Tests that saving an identical profile without accented characters
+ // in the two address lines results in a merge and that the newer
+ // address is retained.
+ SaveImportedProfileTestCase{{{ADDRESS_HOME_LINE1, "123 Zôö St"},
+ {ADDRESS_HOME_LINE2, "üñìt 5"}},
+ ProfileFields(),
+ {{ADDRESS_HOME_LINE1, "123 Zoo St"},
+ {ADDRESS_HOME_LINE2, "unit 5"}}},
+
+ // Tests that saving an identical profile except that the address line
+ // 1 is in the address line 2 results in a merge and that the
+ // multi-lne address is retained.
+ SaveImportedProfileTestCase{
+ ProfileFields(),
+ {{ADDRESS_HOME_LINE1, "123 Zoo St, unit 5"},
+ {ADDRESS_HOME_LINE2, ""}},
+ {{ADDRESS_HOME_LINE1, "123 Zoo St"},
+ {ADDRESS_HOME_LINE2, "unit 5"}}},
+
+ // Tests that saving an identical profile except that the address line
+ // 2 contains part of the old address line 1 results in a merge and
+ // that the original address lines of the reference profile get
+ // overwritten.
+ SaveImportedProfileTestCase{
+ {{ADDRESS_HOME_LINE1, "123 Zoo St, unit 5"},
+ {ADDRESS_HOME_LINE2, ""}},
+ ProfileFields(),
+ {{ADDRESS_HOME_LINE1, "123 Zoo St"},
+ {ADDRESS_HOME_LINE2, "unit 5"}}},
+
+ // Tests that saving an identical profile except that the state is the
+ // abbreviation instead of the full form results in a merge and that
+ // the original state gets overwritten.
+ SaveImportedProfileTestCase{{{ADDRESS_HOME_STATE, "California"}},
+ ProfileFields(),
+ {{ADDRESS_HOME_STATE, "CA"}}},
+
+ // Tests that saving an identical profile except that the state is the
+ // full form instead of the abbreviation results in a merge and that
+ // the abbreviated state is retained.
+ SaveImportedProfileTestCase{ProfileFields(),
+ {{ADDRESS_HOME_STATE, "California"}},
+ {{ADDRESS_HOME_STATE, "CA"}}},
+
+ // Tests that saving and identical profile except that the company
+ // name has different punctuation and case results in a merge and that
+ // the syntax of the new profile replaces the old one.
+ SaveImportedProfileTestCase{{{COMPANY_NAME, "Stark inc"}},
+ {{COMPANY_NAME, "Stark Inc."}},
+ {{COMPANY_NAME, "Stark Inc."}}}));
+
+ // Tests that MergeProfile tries to merge the imported profile into the
+ // existing profile in decreasing order of frecency.
+ TEST_F(PersonalDataManagerTest, MergeProfile_Frecency) {
+ // Create two very similar profiles except with different company names.
+ std::unique_ptr<AutofillProfile> profile1 =
+ base::MakeUnique<AutofillProfile>(base::GenerateGUID(),
+ "https://www.example.com");
+ test::SetProfileInfo(profile1.get(), "Homer", "Jay", "Simpson",
+ "homer.simpson@abc.com", "SNP",
+ "742 Evergreen Terrace", "", "Springfield", "IL",
+ "91601", "US", "12345678910");
+ AutofillProfile* profile2 =
+ new AutofillProfile(base::GenerateGUID(), "https://www.example.com");
+ test::SetProfileInfo(profile2, "Homer", "Jay", "Simpson",
+ "homer.simpson@abc.com", "Fox",
+ "742 Evergreen Terrace", "", "Springfield", "IL",
+ "91601", "US", "12345678910");
+
+ // Give the "Fox" profile a bigger frecency score.
+ profile2->set_use_count(15);
+
+ // Create the |existing_profiles| vector.
+ std::vector<std::unique_ptr<AutofillProfile>> existing_profiles;
+ existing_profiles.push_back(std::move(profile1));
+ existing_profiles.push_back(base::WrapUnique(profile2));
+
+ // Create a new imported profile with no company name.
+ AutofillProfile imported_profile(base::GenerateGUID(),
+ "https://www.example.com");
+ test::SetProfileInfo(&imported_profile, "Homer", "Jay", "Simpson",
+ "homer.simpson@abc.com", "", "742 Evergreen Terrace",
+ "", "Springfield", "IL", "91601", "US", "12345678910");
+
+ // Merge the imported profile into the existing profiles.
+ std::vector<AutofillProfile> profiles;
+ std::string guid = personal_data_->MergeProfile(
+ imported_profile, &existing_profiles, "US-EN", &profiles);
+
+ // The new profile should be merged into the "fox" profile.
+ EXPECT_EQ(profile2->guid(), guid);
}
// Tests that MergeProfile produces a merged profile with the expected usage
diff --git a/chromium/components/autofill/core/browser/phone_number_i18n_unittest.cc b/chromium/components/autofill/core/browser/phone_number_i18n_unittest.cc
index 240319e1663..17a24311876 100644
--- a/chromium/components/autofill/core/browser/phone_number_i18n_unittest.cc
+++ b/chromium/components/autofill/core/browser/phone_number_i18n_unittest.cc
@@ -46,101 +46,117 @@ TEST(PhoneNumberI18NTest, NormalizePhoneNumber) {
EXPECT_EQ(NormalizePhoneNumber(phone5, "US"), ASCIIToUTF16("6502346789"));
}
-TEST(PhoneNumberI18NTest, ParsePhoneNumber) {
- const struct test_case {
- // Expected parsing result.
- bool valid;
- // Inputs.
- std::string input;
- std::string assumed_region;
- // Further expectations.
- std::string number;
- std::string city_code;
- std::string country_code;
- std::string deduced_region;
- } test_cases[] = {
+struct ParseNumberTestCase {
+ // Expected parsing result.
+ bool valid;
+ // Inputs.
+ std::string input;
+ std::string assumed_region;
+ // Further expectations.
+ std::string number;
+ std::string city_code;
+ std::string country_code;
+ std::string deduced_region;
+};
+
+class ParseNumberTest : public testing::TestWithParam<ParseNumberTestCase> {};
+
+TEST_P(ParseNumberTest, ParsePhoneNumber) {
+ auto test_case = GetParam();
+ SCOPED_TRACE("Testing phone number " + test_case.input);
+
+ base::string16 country_code, city_code, number;
+ std::string deduced_region;
+ ::i18n::phonenumbers::PhoneNumber unused_i18n_number;
+ EXPECT_EQ(
+ test_case.valid,
+ ParsePhoneNumber(ASCIIToUTF16(test_case.input), test_case.assumed_region,
+ &country_code, &city_code, &number, &deduced_region,
+ &unused_i18n_number));
+ EXPECT_EQ(ASCIIToUTF16(test_case.number), number);
+ EXPECT_EQ(ASCIIToUTF16(test_case.city_code), city_code);
+ EXPECT_EQ(ASCIIToUTF16(test_case.country_code), country_code);
+ EXPECT_EQ(test_case.deduced_region, deduced_region);
+}
+
+INSTANTIATE_TEST_CASE_P(
+ PhoneNumberI18NTest,
+ ParseNumberTest,
+ testing::Values(
// Test for empty string. Should give back empty strings.
- {false, "", "US"},
+ ParseNumberTestCase{false, "", "US"},
// Test for string with less than 7 digits. Should give back empty
// strings.
- {false, "1234", "US"},
+ ParseNumberTestCase{false, "1234", "US"},
// Test for string with exactly 7 digits.
// Not a valid number - starts with 1
- {false, "17134567", "US"},
+ ParseNumberTestCase{false, "17134567", "US"},
// Not a valid number - does not have area code.
- {false, "7134567", "US"},
+ ParseNumberTestCase{false, "7134567", "US"},
// Valid Canadian toll-free number.
- {true, "3101234", "US", "3101234", "", "", "CA"},
+ ParseNumberTestCase{true, "3101234", "US", "3101234", "", "", "CA"},
// Test for string with greater than 7 digits but less than 10 digits.
// Should fail parsing in US.
- {false, "123456789", "US"},
+ ParseNumberTestCase{false, "123456789", "US"},
// Test for string with greater than 7 digits but less than 10 digits
// and
// separators.
// Should fail parsing in US.
- {false, "12.345-6789", "US"},
+ ParseNumberTestCase{false, "12.345-6789", "US"},
// Test for string with exactly 10 digits.
// Should give back phone number and city code.
// This one going to fail because of the incorrect area code.
- {false, "1234567890", "US"},
+ ParseNumberTestCase{false, "1234567890", "US"},
// This one going to fail because of the incorrect number (starts with
// 1).
- {false, "6501567890", "US"},
- {true, "6504567890", "US", "4567890", "650", "", "US"},
+ ParseNumberTestCase{false, "6501567890", "US"},
+ ParseNumberTestCase{true, "6504567890", "US", "4567890", "650", "",
+ "US"},
// Test for string with exactly 10 digits and separators.
// Should give back phone number and city code.
- {true, "(650) 456-7890", "US", "4567890", "650", "", "US"},
+ ParseNumberTestCase{true, "(650) 456-7890", "US", "4567890", "650", "",
+ "US"},
// Tests for string with over 10 digits.
// 01 is incorrect prefix in the USA, and if we interpret 011 as prefix,
// the
// rest is too short for international number - the parsing should fail.
- {false, "0116504567890", "US"},
+ ParseNumberTestCase{false, "0116504567890", "US"},
// 011 is a correct "dial out" prefix in the USA - the parsing should
// succeed.
- {true, "01116504567890", "US", "4567890", "650", "1", "US"},
+ ParseNumberTestCase{true, "01116504567890", "US", "4567890", "650", "1",
+ "US"},
// 011 is a correct "dial out" prefix in the USA but the rest of the
// number
// can't parse as a US number.
- {true, "01178124567890", "US", "4567890", "812", "7", "RU"},
+ ParseNumberTestCase{true, "01178124567890", "US", "4567890", "812", "7",
+ "RU"},
// Test for string with over 10 digits with separator characters.
// Should give back phone number, city code, and country code. "011" is
// US "dial out" code, which is discarded.
- {true, "(0111) 650-456.7890", "US", "4567890", "650", "1", "US"},
+ ParseNumberTestCase{true, "(0111) 650-456.7890", "US", "4567890", "650",
+ "1", "US"},
// Now try phone from Czech republic - it has 00 dial out code, 420
// country
// code and variable length area codes.
- {true, "+420 27-89.10.112", "US", "910112", "278", "420", "CZ"},
- {false, "27-89.10.112", "US"},
- {true, "27-89.10.112", "CZ", "910112", "278", "", "CZ"},
- {false, "420 57-89.10.112", "US"},
- {true, "420 57-89.10.112", "CZ", "910112", "578", "420", "CZ"},
+ ParseNumberTestCase{true, "+420 27-89.10.112", "US", "910112", "278",
+ "420", "CZ"},
+ ParseNumberTestCase{false, "27-89.10.112", "US"},
+ ParseNumberTestCase{true, "27-89.10.112", "CZ", "910112", "278", "",
+ "CZ"},
+ ParseNumberTestCase{false, "420 57-89.10.112", "US"},
+ ParseNumberTestCase{true, "420 57-89.10.112", "CZ", "910112", "578",
+ "420", "CZ"},
// Parses vanity numbers.
- {true, "1-650-FLOWERS", "US", "3569377", "650", "1", "US"},
+ ParseNumberTestCase{true, "1-650-FLOWERS", "US", "3569377", "650", "1",
+ "US"},
// 800 is not an area code, but the destination code. In our library
// these
// codes should be treated the same as area codes.
- {true, "1-800-FLOWERS", "US", "3569377", "800", "1", "US"},
+ ParseNumberTestCase{true, "1-800-FLOWERS", "US", "3569377", "800", "1",
+ "US"},
// Don't add a country code where there was none.
- {true, "(08) 450 777 7777", "DE", "7777777", "8450", "", "DE"},
- };
-
- for (const auto& test_case : test_cases) {
- SCOPED_TRACE("Testing phone number " + test_case.input);
-
- base::string16 country_code, city_code, number;
- std::string deduced_region;
- ::i18n::phonenumbers::PhoneNumber unused_i18n_number;
- EXPECT_EQ(
- test_case.valid,
- ParsePhoneNumber(ASCIIToUTF16(test_case.input),
- test_case.assumed_region, &country_code, &city_code,
- &number, &deduced_region, &unused_i18n_number));
- EXPECT_EQ(ASCIIToUTF16(test_case.number), number);
- EXPECT_EQ(ASCIIToUTF16(test_case.city_code), city_code);
- EXPECT_EQ(ASCIIToUTF16(test_case.country_code), country_code);
- EXPECT_EQ(test_case.deduced_region, deduced_region);
- }
-}
+ ParseNumberTestCase{true, "(08) 450 777 7777", "DE", "7777777", "8450",
+ "", "DE"}));
TEST(PhoneNumberI18NTest, ConstructPhoneNumber) {
base::string16 number;
diff --git a/chromium/components/autofill/core/browser/region_combobox_model.cc b/chromium/components/autofill/core/browser/region_combobox_model.cc
new file mode 100644
index 00000000000..509bd596e31
--- /dev/null
+++ b/chromium/components/autofill/core/browser/region_combobox_model.cc
@@ -0,0 +1,117 @@
+// 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.
+
+#include "components/autofill/core/browser/region_combobox_model.h"
+
+#include <utility>
+
+#include "base/callback.h"
+#include "base/logging.h"
+#include "base/strings/utf_string_conversions.h"
+#include "components/strings/grit/components_strings.h"
+#include "third_party/libaddressinput/src/cpp/include/libaddressinput/region_data.h"
+#include "third_party/libaddressinput/src/cpp/include/libaddressinput/region_data_builder.h"
+#include "ui/base/l10n/l10n_util.h"
+#include "ui/base/models/combobox_model_observer.h"
+
+namespace autofill {
+
+RegionComboboxModel::RegionComboboxModel(
+ std::unique_ptr<const ::i18n::addressinput::Source> source,
+ std::unique_ptr<::i18n::addressinput::Storage> storage,
+ const std::string& app_locale,
+ const std::string& country_code)
+ : failed_to_load_data_(false),
+ pending_region_data_load_(false),
+ app_locale_(app_locale),
+ region_data_supplier_(source.release(), storage.release()) {
+ region_data_supplier_callback_.reset(::i18n::addressinput::BuildCallback(
+ this, &RegionComboboxModel::RegionDataLoaded));
+ LoadRegionData(country_code);
+}
+
+RegionComboboxModel::~RegionComboboxModel() {}
+
+int 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();
+}
+
+base::string16 RegionComboboxModel::GetItemAt(int index) {
+ DCHECK_GE(index, 0);
+ // This might happen because of the asynchonous nature of the data.
+ if (static_cast<size_t>(index) >= regions_.size())
+ return l10n_util::GetStringUTF16(IDS_AUTOFILL_LOADING_REGIONS);
+
+ if (!regions_[index].first.empty())
+ return base::UTF8ToUTF16(regions_[index].second);
+
+ // The separator item. Implemented for platforms that don't yet support
+ // IsItemSeparatorAt().
+ return base::ASCIIToUTF16("---");
+}
+
+bool RegionComboboxModel::IsItemSeparatorAt(int index) {
+ // This might happen because of the asynchonous nature of the data.
+ DCHECK_GE(index, 0);
+ if (static_cast<size_t>(index) >= regions_.size())
+ return false;
+ return regions_[index].first.empty();
+}
+
+void RegionComboboxModel::AddObserver(ui::ComboboxModelObserver* observer) {
+ observers_.AddObserver(observer);
+}
+
+void RegionComboboxModel::RemoveObserver(ui::ComboboxModelObserver* observer) {
+ observers_.RemoveObserver(observer);
+}
+
+void RegionComboboxModel::SetFailureModeForTests(bool failed_to_load_data) {
+ failed_to_load_data_ = failed_to_load_data;
+ for (auto& observer : observers_) {
+ observer.OnComboboxModelChanged(this);
+ }
+}
+
+void RegionComboboxModel::LoadRegionData(const std::string& country_code) {
+ pending_region_data_load_ = true;
+ region_data_supplier_.LoadRules(country_code,
+ *region_data_supplier_callback_.get());
+}
+
+void RegionComboboxModel::RegionDataLoaded(bool success,
+ const std::string& country_code,
+ int rule_count) {
+ pending_region_data_load_ = false;
+ if (success) {
+ std::string best_region_tree_language_tag;
+ ::i18n::addressinput::RegionDataBuilder builder(&region_data_supplier_);
+ const std::vector<const ::i18n::addressinput::RegionData*>& regions =
+ builder.Build(country_code, app_locale_, &best_region_tree_language_tag)
+ .sub_regions();
+ // Some countries expose a state field but have not region names available.
+ if (regions.size() > 0) {
+ failed_to_load_data_ = false;
+ for (auto* const region : regions) {
+ regions_.push_back(std::make_pair(region->key(), region->name()));
+ }
+ } else {
+ failed_to_load_data_ = true;
+ }
+ } else {
+ // TODO(mad): Maybe use a static list as is done for countries in
+ // components\autofill\core\browser\country_data.cc
+ failed_to_load_data_ = true;
+ }
+
+ for (auto& observer : observers_) {
+ observer.OnComboboxModelChanged(this);
+ }
+}
+
+} // namespace autofill
diff --git a/chromium/components/autofill/core/browser/region_combobox_model.h b/chromium/components/autofill/core/browser/region_combobox_model.h
new file mode 100644
index 00000000000..aa16bc88e5d
--- /dev/null
+++ b/chromium/components/autofill/core/browser/region_combobox_model.h
@@ -0,0 +1,88 @@
+// 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_REGION_COMBOBOX_MODEL_H_
+#define COMPONENTS_AUTOFILL_CORE_BROWSER_REGION_COMBOBOX_MODEL_H_
+
+#include <memory>
+#include <string>
+#include <utility>
+#include <vector>
+
+#include "base/macros.h"
+#include "base/observer_list.h"
+#include "third_party/libaddressinput/src/cpp/include/libaddressinput/preload_supplier.h"
+#include "third_party/libaddressinput/src/cpp/include/libaddressinput/source.h"
+#include "third_party/libaddressinput/src/cpp/include/libaddressinput/storage.h"
+#include "ui/base/models/combobox_model.h"
+
+namespace autofill {
+
+// A model for country regions (aka state/provinces) to be used to enter
+// addresses. Note that loading these regions can happen asynchronously so a
+// ui::ComboboxModelObserver should be attached to this model to be updated when
+// the regions load is completed.
+class RegionComboboxModel : public ui::ComboboxModel {
+ public:
+ // |source| and |storage| are needed to initialize the
+ // ::i18n::addressinput::PreloadSupplier, |app_locale| is needed for
+ // ::i18n::addressinput::RegionDataBuilder and |country_code| identifies which
+ // country's region to load into the model.
+ RegionComboboxModel(
+ std::unique_ptr<const ::i18n::addressinput::Source> source,
+ std::unique_ptr<::i18n::addressinput::Storage> storage,
+ const std::string& app_locale,
+ const std::string& country_code);
+ ~RegionComboboxModel() override;
+
+ bool pending_region_data_load() const { return pending_region_data_load_; }
+ bool failed_to_load_data() const { return failed_to_load_data_; }
+
+ // ui::ComboboxModel implementation:
+ int GetItemCount() const override;
+ base::string16 GetItemAt(int index) override;
+ bool IsItemSeparatorAt(int index) override;
+ void AddObserver(ui::ComboboxModelObserver* observer) override;
+ void RemoveObserver(ui::ComboboxModelObserver* observer) override;
+
+ // To allow testing failure states.
+ void SetFailureModeForTests(bool failed_to_load_data);
+
+ private:
+ // Start the potentially asynchronous process of loading region data.
+ void LoadRegionData(const std::string& country_code);
+
+ // Callback for ::i18n::addressinput::PreloadSupplier::LoadRules
+ void RegionDataLoaded(bool success, const std::string&, int rule_count);
+
+ // Whether the region data load failed or not.
+ bool failed_to_load_data_;
+
+ // Set to true during region data load, and false otherwise. Whether the load
+ // succeeded or not doesn't affect this value.
+ bool pending_region_data_load_;
+
+ // The application locale.
+ const std::string app_locale_;
+
+ // The callback to give to |region_data_supplier_| for async operations.
+ ::i18n::addressinput::scoped_ptr<
+ ::i18n::addressinput::PreloadSupplier::Callback>
+ region_data_supplier_callback_;
+
+ // A supplier of region data.
+ ::i18n::addressinput::PreloadSupplier region_data_supplier_;
+
+ // List of <code, name> pairs for ADDRESS_HOME_STATE combobox values;
+ std::vector<std::pair<std::string, std::string>> regions_;
+
+ // To be called when the data for the given country code was loaded.
+ base::ObserverList<ui::ComboboxModelObserver> observers_;
+
+ DISALLOW_COPY_AND_ASSIGN(RegionComboboxModel);
+};
+
+} // namespace autofill
+
+#endif // COMPONENTS_AUTOFILL_CORE_BROWSER_REGION_COMBOBOX_MODEL_H_
diff --git a/chromium/components/autofill/core/browser/region_combobox_model_unittest.cc b/chromium/components/autofill/core/browser/region_combobox_model_unittest.cc
new file mode 100644
index 00000000000..52878f0e921
--- /dev/null
+++ b/chromium/components/autofill/core/browser/region_combobox_model_unittest.cc
@@ -0,0 +1,107 @@
+// 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.
+
+#include "components/autofill/core/browser/region_combobox_model.h"
+
+#include <memory>
+
+#include "base/json/json_writer.h"
+#include "base/memory/ptr_util.h"
+#include "base/strings/utf_string_conversions.h"
+#include "base/values.h"
+#include "components/autofill/core/browser/autofill_test_utils.h"
+#include "components/autofill/core/browser/test_personal_data_manager.h"
+#include "components/prefs/pref_service.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/libaddressinput/src/cpp/include/libaddressinput/null_storage.h"
+#include "third_party/libaddressinput/src/cpp/include/libaddressinput/source.h"
+
+namespace autofill {
+
+// Strings used in more than one place and must be the same everywhere.
+const char kTestCountryCode[] = "CA";
+const char kQuebec[] = "Quebec";
+const char kOntario[] = "Ontario";
+
+class RegionComboboxModelTest : public testing::Test {
+ public:
+ RegionComboboxModelTest()
+ : pref_service_(autofill::test::PrefServiceForTesting()) {
+ manager_.SetTestingPrefService(pref_service_.get());
+ manager_.set_timezone_country_code(kTestCountryCode);
+ }
+
+ void SetupCombobox(bool source_failure) {
+ model_.reset(new RegionComboboxModel(
+ base::MakeUnique<TestSource>(source_failure),
+ base::MakeUnique<::i18n::addressinput::NullStorage>(),
+ manager_.app_locale(), kTestCountryCode));
+ }
+
+ void TearDown() override { manager_.SetTestingPrefService(nullptr); }
+
+ RegionComboboxModel* model() { return model_.get(); }
+
+ private:
+ // The source that returns the region data. Using
+ // third_party/libaddressinput/src/cpp/test/testdata_source.h wouldn't help
+ // much since it only implements the Get method overriden below anyway.
+ class TestSource : public ::i18n::addressinput::Source {
+ public:
+ explicit TestSource(bool source_failure)
+ : source_failure_(source_failure) {}
+ ~TestSource() override {}
+
+ void Get(const std::string& key,
+ const ::i18n::addressinput::Source::Callback& data_ready)
+ const override {
+ if (source_failure_) {
+ data_ready(false, key, nullptr);
+ return;
+ }
+ // Only set the fields needed to fill the combobox, since only the
+ // combobox code needs to be tested here.
+ std::string* json = new std::string("{\"data/CA\":{");
+ *json += "\"id\":\"data/CA\",";
+ *json += "\"key\":\"CA\",";
+ *json += "\"sub_keys\":\"QC~ON\"},";
+
+ *json += "\"data/CA/ON\":{";
+ *json += "\"id\":\"data/CA/ON\",";
+ *json += "\"key\":\"ON\",";
+ *json += "\"name\":\"Ontario\"},";
+
+ *json += "\"data/CA/QC\":{";
+ *json += "\"id\":\"data/CA/QC\",";
+ *json += "\"key\":\"QC\",";
+ *json += "\"name\":\"Quebec\"}}";
+ data_ready(true, key, json);
+ }
+
+ private:
+ bool source_failure_{false};
+ };
+ TestPersonalDataManager manager_;
+ std::unique_ptr<PrefService> pref_service_;
+ std::unique_ptr<RegionComboboxModel> model_;
+};
+
+// Make sure the two regions returned by the source are properly set in the
+// model.
+TEST_F(RegionComboboxModelTest, QuebecOntarioRegions) {
+ SetupCombobox(false);
+ EXPECT_EQ(2, model()->GetItemCount());
+ EXPECT_EQ(base::ASCIIToUTF16(kQuebec), model()->GetItemAt(0));
+ EXPECT_EQ(base::ASCIIToUTF16(kOntario), model()->GetItemAt(1));
+ EXPECT_FALSE(model()->failed_to_load_data());
+}
+
+// Make sure the combo box properly support source failures.
+TEST_F(RegionComboboxModelTest, FailingSource) {
+ SetupCombobox(true);
+ EXPECT_EQ(1, model()->GetItemCount());
+ EXPECT_TRUE(model()->failed_to_load_data());
+}
+
+} // namespace autofill
diff --git a/chromium/components/autofill/core/browser/risk_data_loader.h b/chromium/components/autofill/core/browser/risk_data_loader.h
new file mode 100644
index 00000000000..be3def3bdda
--- /dev/null
+++ b/chromium/components/autofill/core/browser/risk_data_loader.h
@@ -0,0 +1,26 @@
+// 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_RISK_DATA_LOADER_H_
+#define COMPONENTS_AUTOFILL_CORE_BROWSER_RISK_DATA_LOADER_H_
+
+#include <string>
+
+#include "base/callback.h"
+
+namespace autofill {
+
+class RiskDataLoader {
+ public:
+ // Gathers risk data and provides it to |callback|.
+ virtual void LoadRiskData(
+ const base::Callback<void(const std::string&)>& callback) = 0;
+
+ protected:
+ virtual ~RiskDataLoader() {}
+};
+
+} // namespace autofill
+
+#endif // COMPONENTS_AUTOFILL_CORE_BROWSER_RISK_DATA_LOADER_H_
diff --git a/chromium/components/autofill/core/browser/test_autofill_client.cc b/chromium/components/autofill/core/browser/test_autofill_client.cc
index 72b2da47cc1..1c67ac60f38 100644
--- a/chromium/components/autofill/core/browser/test_autofill_client.cc
+++ b/chromium/components/autofill/core/browser/test_autofill_client.cc
@@ -3,6 +3,9 @@
// found in the LICENSE file.
#include "components/autofill/core/browser/test_autofill_client.h"
+#if !defined(OS_ANDROID)
+#include "components/autofill/core/browser/ui/mock_save_card_bubble_controller.h"
+#endif
#include "components/autofill/core/browser/webdata/autofill_webdata_service.h"
@@ -12,6 +15,9 @@ TestAutofillClient::TestAutofillClient()
: token_service_(new FakeOAuth2TokenService()),
identity_provider_(new FakeIdentityProvider(token_service_.get())),
rappor_service_(new rappor::TestRapporServiceImpl()),
+#if !defined(OS_ANDROID)
+ save_card_bubble_controller_(new MockSaveCardBubbleController()),
+#endif
form_origin_(GURL("https://example.test")) {}
TestAutofillClient::~TestAutofillClient() {
@@ -45,6 +51,14 @@ ukm::UkmService* TestAutofillClient::GetUkmService() {
return ukm_service_test_harness_.test_ukm_service();
}
+SaveCardBubbleController* TestAutofillClient::GetSaveCardBubbleController() {
+#if defined(OS_ANDROID)
+ return nullptr;
+#else
+ return save_card_bubble_controller_.get();
+#endif
+}
+
void TestAutofillClient::ShowAutofillSettings() {
}
@@ -65,6 +79,7 @@ void TestAutofillClient::ConfirmSaveCreditCardLocally(
void TestAutofillClient::ConfirmSaveCreditCardToCloud(
const CreditCard& card,
std::unique_ptr<base::DictionaryValue> legal_message,
+ bool should_cvc_be_requested,
const base::Closure& callback) {
callback.Run();
}
@@ -117,9 +132,6 @@ void TestAutofillClient::DidFillOrPreviewField(
const base::string16& profile_full_name) {
}
-void TestAutofillClient::OnFirstUserGestureObserved() {
-}
-
bool TestAutofillClient::IsContextSecure() {
// Simplified secure context check for tests.
return form_origin_.SchemeIs("https");
diff --git a/chromium/components/autofill/core/browser/test_autofill_client.h b/chromium/components/autofill/core/browser/test_autofill_client.h
index 5b25ecfabab..a140c772665 100644
--- a/chromium/components/autofill/core/browser/test_autofill_client.h
+++ b/chromium/components/autofill/core/browser/test_autofill_client.h
@@ -36,6 +36,7 @@ class TestAutofillClient : public AutofillClient {
IdentityProvider* GetIdentityProvider() override;
rappor::RapporServiceImpl* GetRapporServiceImpl() override;
ukm::UkmService* GetUkmService() override;
+ SaveCardBubbleController* GetSaveCardBubbleController() override;
void ShowAutofillSettings() override;
void ShowUnmaskPrompt(const CreditCard& card,
UnmaskCardReason reason,
@@ -46,6 +47,7 @@ class TestAutofillClient : public AutofillClient {
void ConfirmSaveCreditCardToCloud(
const CreditCard& card,
std::unique_ptr<base::DictionaryValue> legal_message,
+ bool should_cvc_be_requested,
const base::Closure& callback) override;
void ConfirmCreditCardFillAssist(const CreditCard& card,
const base::Closure& callback) override;
@@ -68,7 +70,6 @@ class TestAutofillClient : public AutofillClient {
const std::vector<autofill::FormStructure*>& forms) override;
void DidFillOrPreviewField(const base::string16& autofilled_value,
const base::string16& profile_full_name) override;
- void OnFirstUserGestureObserved() override;
// By default, TestAutofillClient will report that the context is
// secure. This can be adjusted by calling set_form_origin() with an
// http:// URL.
@@ -98,6 +99,9 @@ class TestAutofillClient : public AutofillClient {
std::unique_ptr<FakeIdentityProvider> identity_provider_;
std::unique_ptr<rappor::TestRapporServiceImpl> rappor_service_;
ukm::UkmServiceTestingHarness ukm_service_test_harness_;
+#if !defined(OS_ANDROID)
+ std::unique_ptr<SaveCardBubbleController> save_card_bubble_controller_;
+#endif
GURL form_origin_;
DISALLOW_COPY_AND_ASSIGN(TestAutofillClient);
diff --git a/chromium/components/autofill/core/browser/test_autofill_driver.cc b/chromium/components/autofill/core/browser/test_autofill_driver.cc
index be3bc7b3fec..51a61ce03d5 100644
--- a/chromium/components/autofill/core/browser/test_autofill_driver.cc
+++ b/chromium/components/autofill/core/browser/test_autofill_driver.cc
@@ -17,7 +17,7 @@ TestAutofillDriver::TestAutofillDriver()
TestAutofillDriver::~TestAutofillDriver() {}
-bool TestAutofillDriver::IsOffTheRecord() const {
+bool TestAutofillDriver::IsIncognito() const {
return false;
}
diff --git a/chromium/components/autofill/core/browser/test_autofill_driver.h b/chromium/components/autofill/core/browser/test_autofill_driver.h
index 6ac0c9ccd02..c1839293b7f 100644
--- a/chromium/components/autofill/core/browser/test_autofill_driver.h
+++ b/chromium/components/autofill/core/browser/test_autofill_driver.h
@@ -25,7 +25,7 @@ class TestAutofillDriver : public AutofillDriver {
~TestAutofillDriver() override;
// AutofillDriver implementation.
- bool IsOffTheRecord() const override;
+ bool IsIncognito() const override;
// Returns the value passed in to the last call to |SetURLRequestContext()|
// or NULL if that method has never been called.
net::URLRequestContextGetter* GetURLRequestContext() override;
diff --git a/chromium/components/autofill/core/browser/ui/card_unmask_prompt_controller.h b/chromium/components/autofill/core/browser/ui/card_unmask_prompt_controller.h
index 98a4fa59d93..6e63936060c 100644
--- a/chromium/components/autofill/core/browser/ui/card_unmask_prompt_controller.h
+++ b/chromium/components/autofill/core/browser/ui/card_unmask_prompt_controller.h
@@ -37,6 +37,7 @@ class CardUnmaskPromptController {
virtual bool InputCvcIsValid(const base::string16& input_text) const = 0;
virtual bool InputExpirationIsValid(const base::string16& month,
const base::string16& year) const = 0;
+ virtual int GetExpectedCvcLength() const = 0;
};
} // namespace autofill
diff --git a/chromium/components/autofill/core/browser/ui/card_unmask_prompt_controller_impl.cc b/chromium/components/autofill/core/browser/ui/card_unmask_prompt_controller_impl.cc
index 38778caf3bd..00c26f4c732 100644
--- a/chromium/components/autofill/core/browser/ui/card_unmask_prompt_controller_impl.cc
+++ b/chromium/components/autofill/core/browser/ui/card_unmask_prompt_controller_impl.cc
@@ -309,6 +309,10 @@ bool CardUnmaskPromptControllerImpl::InputExpirationIsValid(
AutofillClock::Now());
}
+int CardUnmaskPromptControllerImpl::GetExpectedCvcLength() const {
+ return GetCvcLengthForCardType(card_.type());
+}
+
base::TimeDelta CardUnmaskPromptControllerImpl::GetSuccessMessageDuration()
const {
return base::TimeDelta::FromMilliseconds(
diff --git a/chromium/components/autofill/core/browser/ui/card_unmask_prompt_controller_impl.h b/chromium/components/autofill/core/browser/ui/card_unmask_prompt_controller_impl.h
index e6b6af6dc44..f2717397cfd 100644
--- a/chromium/components/autofill/core/browser/ui/card_unmask_prompt_controller_impl.h
+++ b/chromium/components/autofill/core/browser/ui/card_unmask_prompt_controller_impl.h
@@ -52,11 +52,13 @@ class CardUnmaskPromptControllerImpl : public CardUnmaskPromptController {
bool InputCvcIsValid(const base::string16& input_text) const override;
bool InputExpirationIsValid(const base::string16& month,
const base::string16& year) const override;
+ int GetExpectedCvcLength() const override;
base::TimeDelta GetSuccessMessageDuration() const override;
protected:
// Exposed for testing.
CardUnmaskPromptView* view() { return card_unmask_view_; }
+ void SetCreditCardForTesting(CreditCard test_card) { card_ = test_card; }
private:
bool AllowsRetry(AutofillClient::PaymentsRpcResult result);
diff --git a/chromium/components/autofill/core/browser/ui/card_unmask_prompt_controller_impl_unittest.cc b/chromium/components/autofill/core/browser/ui/card_unmask_prompt_controller_impl_unittest.cc
index 7a6ff9f04fc..703b6404fa4 100644
--- a/chromium/components/autofill/core/browser/ui/card_unmask_prompt_controller_impl_unittest.cc
+++ b/chromium/components/autofill/core/browser/ui/card_unmask_prompt_controller_impl_unittest.cc
@@ -15,6 +15,7 @@
#include "components/autofill/core/browser/autofill_client.h"
#include "components/autofill/core/browser/autofill_metrics.h"
#include "components/autofill/core/browser/autofill_test_utils.h"
+#include "components/autofill/core/browser/credit_card.h"
#include "components/autofill/core/browser/ui/card_unmask_prompt_view.h"
#include "components/autofill/core/common/autofill_pref_names.h"
#include "components/prefs/pref_registry_simple.h"
@@ -71,6 +72,10 @@ class TestCardUnmaskPromptController : public CardUnmaskPromptControllerImpl {
void set_can_store_locally(bool can) { can_store_locally_ = can; }
+ void SetCreditCardForTesting(CreditCard card) {
+ CardUnmaskPromptControllerImpl::SetCreditCardForTesting(card);
+ }
+
base::WeakPtr<TestCardUnmaskPromptController> GetWeakPtr() {
return weak_factory_.GetWeakPtr();
}
@@ -82,19 +87,9 @@ class TestCardUnmaskPromptController : public CardUnmaskPromptControllerImpl {
DISALLOW_COPY_AND_ASSIGN(TestCardUnmaskPromptController);
};
-class CardUnmaskPromptControllerImplTest : public testing::Test {
+class CardUnmaskPromptControllerImplGenericTest {
public:
- CardUnmaskPromptControllerImplTest() {}
- ~CardUnmaskPromptControllerImplTest() override {}
-
- void SetUp() override {
- test_unmask_prompt_view_.reset(new TestCardUnmaskPromptView());
- pref_service_.reset(new TestingPrefServiceSimple());
- controller_.reset(new TestCardUnmaskPromptController(pref_service_.get()));
- delegate_.reset(new TestCardUnmaskDelegate());
- pref_service_->registry()->RegisterBooleanPref(
- prefs::kAutofillWalletImportStorageCheckboxState, false);
- }
+ CardUnmaskPromptControllerImplGenericTest() {}
void ShowPrompt() {
controller_->ShowPrompt(test_unmask_prompt_view_.get(),
@@ -134,6 +129,26 @@ class CardUnmaskPromptControllerImplTest : public testing::Test {
std::unique_ptr<TestCardUnmaskDelegate> delegate_;
private:
+ DISALLOW_COPY_AND_ASSIGN(CardUnmaskPromptControllerImplGenericTest);
+};
+
+class CardUnmaskPromptControllerImplTest
+ : public CardUnmaskPromptControllerImplGenericTest,
+ public testing::Test {
+ public:
+ CardUnmaskPromptControllerImplTest() {}
+ ~CardUnmaskPromptControllerImplTest() override {}
+
+ void SetUp() override {
+ test_unmask_prompt_view_.reset(new TestCardUnmaskPromptView());
+ pref_service_.reset(new TestingPrefServiceSimple());
+ controller_.reset(new TestCardUnmaskPromptController(pref_service_.get()));
+ delegate_.reset(new TestCardUnmaskDelegate());
+ pref_service_->registry()->RegisterBooleanPref(
+ prefs::kAutofillWalletImportStorageCheckboxState, false);
+ }
+
+ private:
DISALLOW_COPY_AND_ASSIGN(CardUnmaskPromptControllerImplTest);
};
@@ -433,80 +448,138 @@ TEST_F(CardUnmaskPromptControllerImplTest,
"Autofill.UnmaskPrompt.UnmaskingDuration.Failure", 1);
}
-TEST_F(CardUnmaskPromptControllerImplTest, CvcInputValidation) {
- struct CvcCase {
- const char* input;
- bool valid;
- // null when |valid| is false.
- const char* canonicalized_input;
- };
- CvcCase cvc_cases[] = {
- { "123", true, "123" },
- { "123 ", true, "123" },
- { " 1234 ", false },
- { "IOU", false },
- };
+struct CvcCase {
+ const char* input;
+ bool valid;
+ // null when |valid| is false.
+ const char* canonicalized_input;
+};
- ShowPrompt();
+class CvcInputValidationTest : public CardUnmaskPromptControllerImplGenericTest,
+ public testing::TestWithParam<CvcCase> {
+ public:
+ CvcInputValidationTest() {}
+ ~CvcInputValidationTest() override {}
- for (const CvcCase& cvc_case : cvc_cases) {
- EXPECT_EQ(cvc_case.valid,
- controller_->InputCvcIsValid(ASCIIToUTF16(cvc_case.input)));
- if (!cvc_case.valid)
- continue;
-
- controller_->OnUnmaskResponse(ASCIIToUTF16(cvc_case.input),
- ASCIIToUTF16("1"), ASCIIToUTF16("2050"),
- false);
- EXPECT_EQ(ASCIIToUTF16(cvc_case.canonicalized_input),
- delegate_->response().cvc);
+ void SetUp() override {
+ test_unmask_prompt_view_.reset(new TestCardUnmaskPromptView());
+ pref_service_.reset(new TestingPrefServiceSimple());
+ controller_.reset(new TestCardUnmaskPromptController(pref_service_.get()));
+ delegate_.reset(new TestCardUnmaskDelegate());
+ pref_service_->registry()->RegisterBooleanPref(
+ prefs::kAutofillWalletImportStorageCheckboxState, false);
}
- CvcCase cvc_cases_amex[] = {
- { "123", false },
- { "123 ", false },
- { "1234", true, "1234" },
- { "\t1234 ", true, "1234" },
- { " 1234", true, "1234" },
- { "IOU$", false },
- };
+ private:
+ DISALLOW_COPY_AND_ASSIGN(CvcInputValidationTest);
+};
- ShowPromptAmex();
+TEST_P(CvcInputValidationTest, CvcInputValidation) {
+ auto cvc_case = GetParam();
+ ShowPrompt();
+ EXPECT_EQ(cvc_case.valid,
+ controller_->InputCvcIsValid(ASCIIToUTF16(cvc_case.input)));
+ if (!cvc_case.valid)
+ return;
+
+ controller_->OnUnmaskResponse(ASCIIToUTF16(cvc_case.input), ASCIIToUTF16("1"),
+ ASCIIToUTF16("2050"), false);
+ EXPECT_EQ(ASCIIToUTF16(cvc_case.canonicalized_input),
+ delegate_->response().cvc);
+}
- for (const CvcCase& cvc_case_amex : cvc_cases_amex) {
- EXPECT_EQ(cvc_case_amex.valid,
- controller_->InputCvcIsValid(ASCIIToUTF16(cvc_case_amex.input)));
- if (!cvc_case_amex.valid)
- continue;
+INSTANTIATE_TEST_CASE_P(CardUnmaskPromptControllerImplTest,
+ CvcInputValidationTest,
+ testing::Values(CvcCase{"123", true, "123"},
+ CvcCase{"123 ", true, "123"},
+ CvcCase{" 1234 ", false},
+ CvcCase{"IOU", false}));
- controller_->OnUnmaskResponse(ASCIIToUTF16(cvc_case_amex.input),
- base::string16(), base::string16(), false);
- EXPECT_EQ(ASCIIToUTF16(cvc_case_amex.canonicalized_input),
- delegate_->response().cvc);
+class CvcInputAmexValidationTest
+ : public CardUnmaskPromptControllerImplGenericTest,
+ public testing::TestWithParam<CvcCase> {
+ public:
+ CvcInputAmexValidationTest() {}
+ ~CvcInputAmexValidationTest() override {}
+
+ void SetUp() override {
+ test_unmask_prompt_view_.reset(new TestCardUnmaskPromptView());
+ pref_service_.reset(new TestingPrefServiceSimple());
+ controller_.reset(new TestCardUnmaskPromptController(pref_service_.get()));
+ delegate_.reset(new TestCardUnmaskDelegate());
+ pref_service_->registry()->RegisterBooleanPref(
+ prefs::kAutofillWalletImportStorageCheckboxState, false);
}
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(CvcInputAmexValidationTest);
+};
+
+TEST_P(CvcInputAmexValidationTest, CvcInputValidation) {
+ auto cvc_case_amex = GetParam();
+ ShowPromptAmex();
+ EXPECT_EQ(cvc_case_amex.valid,
+ controller_->InputCvcIsValid(ASCIIToUTF16(cvc_case_amex.input)));
+ if (!cvc_case_amex.valid)
+ return;
+
+ controller_->OnUnmaskResponse(ASCIIToUTF16(cvc_case_amex.input),
+ base::string16(), base::string16(), false);
+ EXPECT_EQ(ASCIIToUTF16(cvc_case_amex.canonicalized_input),
+ delegate_->response().cvc);
}
-TEST_F(CardUnmaskPromptControllerImplTest, ExpirationDateValidation) {
- struct {
- const char* input_month;
- const char* input_year;
- bool valid;
- } exp_cases[] = {
- {"01", "2040", true},
- {"1", "2040", true},
- {"1", "40", true},
- {"10", "40", true},
- {"01", "1940", false},
- {"13", "2040", false},
- };
+INSTANTIATE_TEST_CASE_P(CardUnmaskPromptControllerImplTest,
+ CvcInputAmexValidationTest,
+ testing::Values(CvcCase{"123", false},
+ CvcCase{"123 ", false},
+ CvcCase{"1234", true, "1234"},
+ CvcCase{"\t1234 ", true, "1234"},
+ CvcCase{" 1234", true, "1234"},
+ CvcCase{"IOU$", false}));
+
+struct ExpirationDateTestCase {
+ const char* input_month;
+ const char* input_year;
+ bool valid;
+};
- ShowPrompt();
+class ExpirationDateValidationTest
+ : public CardUnmaskPromptControllerImplGenericTest,
+ public testing::TestWithParam<ExpirationDateTestCase> {
+ public:
+ ExpirationDateValidationTest() {}
+ ~ExpirationDateValidationTest() override {}
- for (const auto& exp_case : exp_cases) {
- EXPECT_EQ(exp_case.valid, controller_->InputExpirationIsValid(
- ASCIIToUTF16(exp_case.input_month),
- ASCIIToUTF16(exp_case.input_year)));
+ void SetUp() override {
+ test_unmask_prompt_view_.reset(new TestCardUnmaskPromptView());
+ pref_service_.reset(new TestingPrefServiceSimple());
+ controller_.reset(new TestCardUnmaskPromptController(pref_service_.get()));
+ delegate_.reset(new TestCardUnmaskDelegate());
+ pref_service_->registry()->RegisterBooleanPref(
+ prefs::kAutofillWalletImportStorageCheckboxState, false);
}
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(ExpirationDateValidationTest);
+};
+
+TEST_P(ExpirationDateValidationTest, ExpirationDateValidation) {
+ auto exp_case = GetParam();
+ ShowPrompt();
+ EXPECT_EQ(exp_case.valid, controller_->InputExpirationIsValid(
+ ASCIIToUTF16(exp_case.input_month),
+ ASCIIToUTF16(exp_case.input_year)));
}
+INSTANTIATE_TEST_CASE_P(
+ CardUnmaskPromptControllerImplTest,
+ ExpirationDateValidationTest,
+ testing::Values(ExpirationDateTestCase{"01", "2040", true},
+ ExpirationDateTestCase{"1", "2040", true},
+ ExpirationDateTestCase{"1", "40", true},
+ ExpirationDateTestCase{"10", "40", true},
+ ExpirationDateTestCase{"01", "1940", false},
+ ExpirationDateTestCase{"13", "2040", false}));
+
} // namespace autofill
diff --git a/chromium/components/autofill/core/browser/ui/mock_save_card_bubble_controller.cc b/chromium/components/autofill/core/browser/ui/mock_save_card_bubble_controller.cc
new file mode 100644
index 00000000000..b0c8d787035
--- /dev/null
+++ b/chromium/components/autofill/core/browser/ui/mock_save_card_bubble_controller.cc
@@ -0,0 +1,22 @@
+// 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.
+
+#include "components/autofill/core/browser/ui/mock_save_card_bubble_controller.h"
+
+namespace autofill {
+
+MockSaveCardBubbleController::MockSaveCardBubbleController() {}
+
+MockSaveCardBubbleController::~MockSaveCardBubbleController() {}
+
+base::string16 MockSaveCardBubbleController::GetCvcEnteredByUser() const {
+ return cvc_entered_by_user_;
+}
+
+void MockSaveCardBubbleController::OnSaveButton(const base::string16& cvc) {
+ if (!cvc.empty())
+ cvc_entered_by_user_ = cvc;
+}
+
+} // namespace autofill
diff --git a/chromium/components/autofill/core/browser/ui/mock_save_card_bubble_controller.h b/chromium/components/autofill/core/browser/ui/mock_save_card_bubble_controller.h
new file mode 100644
index 00000000000..ce040ae2008
--- /dev/null
+++ b/chromium/components/autofill/core/browser/ui/mock_save_card_bubble_controller.h
@@ -0,0 +1,42 @@
+// 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_UI_MOCK_SAVE_CARD_BUBBLE_CONTROLLER_H_
+#define COMPONENTS_AUTOFILL_CORE_BROWSER_UI_MOCK_SAVE_CARD_BUBBLE_CONTROLLER_H_
+
+#include "components/autofill/core/browser/credit_card.h"
+#include "components/autofill/core/browser/ui/save_card_bubble_controller.h"
+#include "testing/gmock/include/gmock/gmock.h"
+
+namespace autofill {
+
+class MockSaveCardBubbleController : public SaveCardBubbleController {
+ public:
+ MockSaveCardBubbleController();
+ ~MockSaveCardBubbleController() override;
+
+ MOCK_CONST_METHOD0(GetWindowTitle, base::string16());
+ MOCK_CONST_METHOD0(GetExplanatoryMessage, base::string16());
+ MOCK_CONST_METHOD0(GetCard, const CreditCard());
+ MOCK_CONST_METHOD0(GetCvcImageResourceId, int());
+ MOCK_CONST_METHOD0(ShouldRequestCvcFromUser, bool());
+ MOCK_METHOD0(OnCancelButton, void());
+ MOCK_METHOD0(OnLearnMoreClicked, void());
+ MOCK_METHOD1(OnLegalMessageLinkClicked, void(const GURL& url));
+ MOCK_METHOD0(OnBubbleClosed, void());
+ MOCK_CONST_METHOD0(GetLegalMessageLines, const LegalMessageLines&());
+ MOCK_CONST_METHOD1(InputCvcIsValid, bool(const base::string16& input_text));
+
+ base::string16 GetCvcEnteredByUser() const override;
+ void OnSaveButton(const base::string16& cvc = base::string16()) override;
+
+ private:
+ base::string16 cvc_entered_by_user_;
+
+ DISALLOW_COPY_AND_ASSIGN(MockSaveCardBubbleController);
+};
+
+} // namespace autofill
+
+#endif // COMPONENTS_AUTOFILL_CORE_BROWSER_UI_MOCK_SAVE_CARD_BUBBLE_CONTROLLER_H_
diff --git a/chromium/components/autofill/core/browser/ui/save_card_bubble_controller.h b/chromium/components/autofill/core/browser/ui/save_card_bubble_controller.h
new file mode 100644
index 00000000000..f01cac3f220
--- /dev/null
+++ b/chromium/components/autofill/core/browser/ui/save_card_bubble_controller.h
@@ -0,0 +1,70 @@
+// 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.
+
+#ifndef COMPONENTS_AUTOFILL_CORE_BROWSER_UI_SAVE_CARD_BUBBLE_CONTROLLER_H_
+#define COMPONENTS_AUTOFILL_CORE_BROWSER_UI_SAVE_CARD_BUBBLE_CONTROLLER_H_
+
+#include <memory>
+#include <vector>
+
+#include "base/macros.h"
+#include "base/strings/string16.h"
+#include "components/autofill/core/browser/legal_message_line.h"
+#include "url/gurl.h"
+
+namespace autofill {
+
+class CreditCard;
+class SaveCardBubbleView;
+
+// Interface that exposes controller functionality to SaveCardBubbleView.
+class SaveCardBubbleController {
+ public:
+ SaveCardBubbleController() {}
+ virtual ~SaveCardBubbleController() {}
+
+ // Returns the title that should be displayed in the bubble.
+ virtual base::string16 GetWindowTitle() const = 0;
+
+ // Returns the explanatory text that should be displayed in the bubble.
+ // Returns an empty string if no message should be displayed.
+ virtual base::string16 GetExplanatoryMessage() const = 0;
+
+ // Returns the card that will be uploaded if the user accepts.
+ virtual const CreditCard GetCard() const = 0;
+
+ // Returns the CVC image icon resource ID.
+ virtual int GetCvcImageResourceId() const = 0;
+
+ // Returns whether the dialog should include a field requesting the card's CVC
+ // from the user.
+ virtual bool ShouldRequestCvcFromUser() const = 0;
+
+ // Returns the CVC provided by the user in the save card bubble.
+ virtual base::string16 GetCvcEnteredByUser() const = 0;
+
+ // Interaction.
+ // OnSaveButton takes in a string value representing the CVC entered by the
+ // user if it was requested, or an empty string otherwise.
+ virtual void OnSaveButton(const base::string16& cvc) = 0;
+ virtual void OnCancelButton() = 0;
+ virtual void OnLearnMoreClicked() = 0;
+ virtual void OnLegalMessageLinkClicked(const GURL& url) = 0;
+ virtual void OnBubbleClosed() = 0;
+
+ // State.
+
+ // Returns empty vector if no legal message should be shown.
+ virtual const LegalMessageLines& GetLegalMessageLines() const = 0;
+
+ // Utilities.
+ virtual bool InputCvcIsValid(const base::string16& input_text) const = 0;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(SaveCardBubbleController);
+};
+
+} // namespace autofill
+
+#endif // COMPONENTS_AUTOFILL_CORE_BROWSER_UI_SAVE_CARD_BUBBLE_CONTROLLER_H_
diff --git a/chromium/components/autofill/core/browser/validation.cc b/chromium/components/autofill/core/browser/validation.cc
index d18ccbab5cf..e7237f7b3b7 100644
--- a/chromium/components/autofill/core/browser/validation.cc
+++ b/chromium/components/autofill/core/browser/validation.cc
@@ -13,7 +13,9 @@
#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/credit_card.h"
+#include "components/autofill/core/browser/phone_number_i18n.h"
#include "components/autofill/core/browser/state_names.h"
#include "components/autofill/core/common/autofill_clock.h"
#include "components/autofill/core/common/autofill_regexes.h"
@@ -94,8 +96,7 @@ bool IsValidCreditCardNumber(const base::string16& text) {
bool IsValidCreditCardSecurityCode(const base::string16& code,
const base::StringPiece card_type) {
- size_t required_length = card_type == kAmericanExpressCard ? 4 : 3;
- return code.length() == required_length &&
+ return code.length() == GetCvcLengthForCardType(card_type) &&
base::ContainsOnlyChars(code, base::ASCIIToUTF16("0123456789"));
}
@@ -137,6 +138,12 @@ bool IsValidState(const base::string16& text) {
!state_names::GetNameForAbbreviation(text).empty();
}
+bool IsValidPhoneNumber(const base::string16& text,
+ const std::string& country_code) {
+ i18n::PhoneObject phone_number(text, country_code);
+ return phone_number.IsValidNumber();
+}
+
bool IsValidZip(const base::string16& text) {
const base::string16 kZipPattern = base::ASCIIToUTF16("^\\d{5}(-\\d{4})?$");
return MatchesPattern(text, kZipPattern);
@@ -308,4 +315,15 @@ bool IsValidForType(const base::string16& value,
return false;
}
+size_t GetCvcLengthForCardType(const base::StringPiece card_type) {
+ if (card_type == kAmericanExpressCard)
+ return AMEX_CVC_LENGTH;
+
+ return GENERAL_CVC_LENGTH;
+}
+
+bool IsUPIVirtualPaymentAddress(const base::string16& value) {
+ return MatchesPattern(value, base::ASCIIToUTF16(kUPIVirtualPaymentAddressRe));
+}
+
} // namespace autofill
diff --git a/chromium/components/autofill/core/browser/validation.h b/chromium/components/autofill/core/browser/validation.h
index 0b496e2b950..93a52e59b4f 100644
--- a/chromium/components/autofill/core/browser/validation.h
+++ b/chromium/components/autofill/core/browser/validation.h
@@ -15,6 +15,10 @@ class Time;
namespace autofill {
+// Constants for the length of a CVC.
+static const size_t GENERAL_CVC_LENGTH = 3;
+static const size_t AMEX_CVC_LENGTH = 4;
+
// Returns true if |year| and |month| describe a date later than |now|.
// |year| must have 4 digits.
bool IsValidCreditCardExpirationDate(int year,
@@ -45,6 +49,11 @@ bool IsValidEmailAddress(const base::string16& text);
// insensitive. Valid for US states only.
bool IsValidState(const base::string16& text);
+// Returns whether the number contained in |text| is valid for the specified
+// |country_code|. Callers should cache the result as the parsing is expensive.
+bool IsValidPhoneNumber(const base::string16& text,
+ const std::string& country_code);
+
// Returns true if |text| looks like a valid zip code.
// Valid for US zip codes only.
bool IsValidZip(const base::string16& text);
@@ -58,6 +67,13 @@ bool IsValidForType(const base::string16& value,
ServerFieldType type,
base::string16* error_message);
+// Returns the expected CVC length based on the |card_type|.
+size_t GetCvcLengthForCardType(const base::StringPiece card_type);
+
+// Returns true if |value| appears to be a UPI Virtual Payment Address.
+// https://upipayments.co.in/virtual-payment-address-vpa/
+bool IsUPIVirtualPaymentAddress(const base::string16& value);
+
} // namespace autofill
#endif // COMPONENTS_AUTOFILL_CORE_BROWSER_VALIDATION_H_
diff --git a/chromium/components/autofill/core/browser/validation_unittest.cc b/chromium/components/autofill/core/browser/validation_unittest.cc
index ec6ff0a346f..ee36fbc4543 100644
--- a/chromium/components/autofill/core/browser/validation_unittest.cc
+++ b/chromium/components/autofill/core/browser/validation_unittest.cc
@@ -412,4 +412,81 @@ INSTANTIATE_TEST_CASE_P(
false,
IDS_PAYMENTS_VALIDATION_UNSUPPORTED_CREDIT_CARD_TYPE)));
+struct GetCvcLengthForCardTypeCase {
+ GetCvcLengthForCardTypeCase(const char* card_type, size_t expected_length)
+ : card_type(card_type), expected_length(expected_length) {}
+ ~GetCvcLengthForCardTypeCase() {}
+
+ const char* const card_type;
+ const size_t expected_length;
+};
+
+class AutofillGetCvcLengthForCardType
+ : public testing::TestWithParam<GetCvcLengthForCardTypeCase> {};
+
+TEST_P(AutofillGetCvcLengthForCardType, GetCvcLengthForCardType) {
+ EXPECT_EQ(GetParam().expected_length,
+ GetCvcLengthForCardType(GetParam().card_type));
+}
+
+INSTANTIATE_TEST_CASE_P(
+ CreditCardCvcLength,
+ AutofillGetCvcLengthForCardType,
+ testing::Values(
+ GetCvcLengthForCardTypeCase{kAmericanExpressCard, AMEX_CVC_LENGTH},
+ GetCvcLengthForCardTypeCase{kDinersCard, GENERAL_CVC_LENGTH},
+ GetCvcLengthForCardTypeCase{kDiscoverCard, GENERAL_CVC_LENGTH},
+ GetCvcLengthForCardTypeCase{kGenericCard, GENERAL_CVC_LENGTH},
+ GetCvcLengthForCardTypeCase{kJCBCard, GENERAL_CVC_LENGTH},
+ GetCvcLengthForCardTypeCase{kMasterCard, GENERAL_CVC_LENGTH},
+ GetCvcLengthForCardTypeCase{kMirCard, GENERAL_CVC_LENGTH},
+ GetCvcLengthForCardTypeCase{kUnionPay, GENERAL_CVC_LENGTH},
+ GetCvcLengthForCardTypeCase{kVisaCard, GENERAL_CVC_LENGTH}));
+
+class AutofillIsUPIVirtualPaymentAddress
+ : public testing::TestWithParam<std::string> {};
+
+TEST_P(AutofillIsUPIVirtualPaymentAddress, IsUPIVirtualPaymentAddress) {
+ // Expected format is user@bank
+ EXPECT_TRUE(IsUPIVirtualPaymentAddress(ASCIIToUTF16("user@" + GetParam())));
+
+ // Deviations should not match: bank, @bank, user@prefixbank, user@banksuffix.
+ EXPECT_FALSE(IsUPIVirtualPaymentAddress(ASCIIToUTF16(GetParam())));
+ EXPECT_FALSE(IsUPIVirtualPaymentAddress(ASCIIToUTF16(GetParam() + "@")));
+ EXPECT_FALSE(IsUPIVirtualPaymentAddress(ASCIIToUTF16("@" + GetParam())));
+ EXPECT_FALSE(
+ IsUPIVirtualPaymentAddress(ASCIIToUTF16("user@invalid" + GetParam())));
+ EXPECT_FALSE(
+ IsUPIVirtualPaymentAddress(ASCIIToUTF16("user@" + GetParam() + ".com")));
+}
+
+INSTANTIATE_TEST_CASE_P(UPIVirtualPaymentAddress,
+ AutofillIsUPIVirtualPaymentAddress,
+ testing::Values("upi",
+ "allbank",
+ "andb",
+ "axisbank",
+ "barodampay",
+ "mahb",
+ "cnrb",
+ "csbpay",
+ "dcb",
+ "federal",
+ "hdfcbank",
+ "pockets",
+ "icici",
+ "idfcbank",
+ "indus",
+ "kbl",
+ "kaypay",
+ "pnb",
+ "sib",
+ "sbi",
+ "tjsp",
+ "uco",
+ "unionbank",
+ "united",
+ "vijb",
+ "ybl"));
+
} // namespace autofill
diff --git a/chromium/components/autofill/core/browser/webdata/autocomplete_sync_bridge.cc b/chromium/components/autofill/core/browser/webdata/autocomplete_sync_bridge.cc
index 589df1628af..9ed91408190 100644
--- a/chromium/components/autofill/core/browser/webdata/autocomplete_sync_bridge.cc
+++ b/chromium/components/autofill/core/browser/webdata/autocomplete_sync_bridge.cc
@@ -458,6 +458,9 @@ void AutocompleteSyncBridge::LoadMetadata() {
std::string AutocompleteSyncBridge::GetClientTag(
const EntityData& entity_data) {
DCHECK(entity_data.specifics.has_autofill());
+ // Must have the format "autofill_entry|$name|$value" where $name and $value
+ // are URL escaped. This is to maintain compatibility with the previous sync
+ // integration (Directory and SyncableService).
return std::string(kAutocompleteEntryNamespaceTag) +
EscapeIdentifiers(entity_data.specifics.autofill());
}
@@ -465,6 +468,9 @@ std::string AutocompleteSyncBridge::GetClientTag(
std::string AutocompleteSyncBridge::GetStorageKey(
const EntityData& entity_data) {
DCHECK(entity_data.specifics.has_autofill());
+ // Marginally more space efficient than GetClientTag() by omitting the
+ // kAutocompleteEntryNamespaceTag prefix and using protobuf serialization
+ // instead of URL escaping for Unicode characters.
const AutofillSpecifics specifics = entity_data.specifics.autofill();
return BuildSerializedStorageKey(specifics.name(), specifics.value());
}
diff --git a/chromium/components/autofill/core/browser/webdata/autocomplete_sync_bridge.h b/chromium/components/autofill/core/browser/webdata/autocomplete_sync_bridge.h
index 2ec41c5ae51..3d3053c6110 100644
--- a/chromium/components/autofill/core/browser/webdata/autocomplete_sync_bridge.h
+++ b/chromium/components/autofill/core/browser/webdata/autocomplete_sync_bridge.h
@@ -54,14 +54,7 @@ class AutocompleteSyncBridge : public base::SupportsUserData::Data,
syncer::EntityChangeList entity_changes) override;
void GetData(StorageKeyList storage_keys, DataCallback callback) override;
void GetAllData(DataCallback callback) override;
- // Generate a tag that uniquely identifies |entity_data| across all data
- // types. This is used to identify the entity on the server. The format, which
- // must remain the same for server compatibility, is:
- // "autofill_entry|$name|$value" where $name and $value are escaped.
std::string GetClientTag(const syncer::EntityData& entity_data) override;
- // Generate a string key uniquely identifying |entity_data| in the context of
- // local storage. The format, which should stay the same, is $name|$value"
- // where $name and $value are escaped.
std::string GetStorageKey(const syncer::EntityData& entity_data) override;
// AutofillWebDataServiceObserverOnDBThread implementation.
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 a4334eaa230..bdb786daa6a 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
@@ -16,6 +16,7 @@
#include "base/run_loop.h"
#include "base/strings/stringprintf.h"
#include "base/strings/utf_string_conversions.h"
+#include "base/test/scoped_task_environment.h"
#include "base/threading/thread_task_runner_handle.h"
#include "base/time/time.h"
#include "components/autofill/core/browser/webdata/autofill_entry.h"
@@ -276,7 +277,7 @@ class AutocompleteSyncBridgeTest : public testing::Test {
}
ScopedTempDir temp_dir_;
- base::MessageLoop message_loop_;
+ base::test::ScopedTaskEnvironment scoped_task_environment_;
FakeAutofillBackend backend_;
AutofillTable table_;
WebDatabase db_;
diff --git a/chromium/components/autofill/core/browser/webdata/autofill_profile_syncable_service_unittest.cc b/chromium/components/autofill/core/browser/webdata/autofill_profile_syncable_service_unittest.cc
index e5bc5b989bf..7c840464cf4 100644
--- a/chromium/components/autofill/core/browser/webdata/autofill_profile_syncable_service_unittest.cc
+++ b/chromium/components/autofill/core/browser/webdata/autofill_profile_syncable_service_unittest.cc
@@ -1191,77 +1191,127 @@ TEST_F(AutofillProfileSyncableServiceTest, NoUsageStatsNoSync) {
autofill_syncable_service_.StopSyncing(syncer::AUTOFILL_PROFILE);
}
-// Usage stats should be updated by sync.
-TEST_F(AutofillProfileSyncableServiceTest, SyncUpdatesUsageStats) {
- typedef struct {
- size_t local_use_count;
- base::Time local_use_date;
- size_t remote_use_count;
- int remote_use_date;
- size_t synced_use_count;
- base::Time synced_use_date;
- } TestCase;
-
- TestCase test_cases[] = {
- // Local profile with default stats.
- {0U, base::Time(), 9U, 4321, 9U, base::Time::FromTimeT(4321)},
- // Local profile has older stats than the server.
- {3U, base::Time::FromTimeT(1234), 9U, 4321, 9U,
- base::Time::FromTimeT(4321)},
- // Local profile has newer stats than the server
- {10U, base::Time::FromTimeT(9999), 9U, 4321, 9U,
- base::Time::FromTimeT(4321)}};
-
- for (const TestCase& test_case : test_cases) {
- SetUp();
- std::vector<std::unique_ptr<AutofillProfile>> profiles_from_web_db;
-
- AutofillProfile profile(kGuid1, kHttpsOrigin);
- profile.set_language_code("en");
- profile.set_use_count(test_case.local_use_count);
- profile.set_use_date(test_case.local_use_date);
- EXPECT_EQ(test_case.local_use_count, profile.use_count());
- EXPECT_EQ(test_case.local_use_date, profile.use_date());
- profiles_from_web_db.push_back(base::MakeUnique<AutofillProfile>(profile));
-
- // Remote data has usage stats.
- sync_pb::EntitySpecifics specifics;
- sync_pb::AutofillProfileSpecifics* autofill_specifics =
- specifics.mutable_autofill_profile();
- autofill_specifics->set_guid(profile.guid());
- autofill_specifics->set_origin(profile.origin());
- autofill_specifics->add_name_first(std::string());
- autofill_specifics->add_name_middle(std::string());
- autofill_specifics->add_name_last(std::string());
- autofill_specifics->add_name_full(std::string());
- autofill_specifics->add_email_address(std::string());
- autofill_specifics->add_phone_home_whole_number(std::string());
- autofill_specifics->set_address_home_language_code("en");
- autofill_specifics->set_use_count(test_case.remote_use_count);
- autofill_specifics->set_use_date(test_case.remote_use_date);
- EXPECT_TRUE(autofill_specifics->has_use_count());
- EXPECT_TRUE(autofill_specifics->has_use_date());
-
- syncer::SyncDataList data_list;
- data_list.push_back(syncer::SyncData::CreateLocalData(
- profile.guid(), profile.guid(), specifics));
-
- // Expect the local autofill profile to have usage stats after sync.
- MockAutofillProfileSyncableService::DataBundle expected_bundle;
- AutofillProfile expected_profile = profile;
- expected_profile.set_use_count(test_case.synced_use_count);
- expected_profile.set_use_date(test_case.synced_use_date);
- expected_bundle.profiles_to_update.push_back(&expected_profile);
-
- // Expect no changes to remote data.
- syncer::SyncChangeList expected_empty_change_list;
-
- MergeDataAndStartSyncing(std::move(profiles_from_web_db), data_list,
- expected_bundle, expected_empty_change_list);
- autofill_syncable_service_.StopSyncing(syncer::AUTOFILL_PROFILE);
+struct SyncUpdatesUsageStatsTestCase {
+ size_t local_use_count;
+ base::Time local_use_date;
+ size_t remote_use_count;
+ int remote_use_date;
+ size_t synced_use_count;
+ base::Time synced_use_date;
+};
+
+class SyncUpdatesUsageStatsTest
+ : public testing::TestWithParam<SyncUpdatesUsageStatsTestCase> {
+ public:
+ SyncUpdatesUsageStatsTest() { CountryNames::SetLocaleString("en-US"); }
+
+ void SetUp() override { sync_processor_.reset(new MockSyncChangeProcessor); }
+
+ // Wrapper around AutofillProfileSyncableService::MergeDataAndStartSyncing()
+ // that also verifies expectations.
+ void MergeDataAndStartSyncing(
+ std::vector<std::unique_ptr<AutofillProfile>> profiles_from_web_db,
+ const syncer::SyncDataList& data_list,
+ const MockAutofillProfileSyncableService::DataBundle& expected_bundle,
+ const syncer::SyncChangeList& expected_change_list) {
+ auto profile_returner = [&profiles_from_web_db]() {
+ return std::move(profiles_from_web_db);
+ };
+ EXPECT_CALL(autofill_syncable_service_, LoadAutofillData(_))
+ .Times(1)
+ .WillOnce(DoAll(LoadAutofillProfiles(profile_returner), Return(true)));
+ EXPECT_CALL(autofill_syncable_service_,
+ SaveChangesToWebData(DataBundleCheck(expected_bundle)))
+ .Times(1)
+ .WillOnce(Return(true));
+ if (expected_change_list.empty()) {
+ EXPECT_CALL(*sync_processor_, ProcessSyncChanges(_, _)).Times(0);
+ } else {
+ ON_CALL(*sync_processor_, ProcessSyncChanges(_, _))
+ .WillByDefault(Return(syncer::SyncError()));
+ EXPECT_CALL(*sync_processor_,
+ ProcessSyncChanges(_, CheckSyncChanges(expected_change_list)))
+ .Times(1)
+ .WillOnce(Return(syncer::SyncError()));
+ }
+
+ // Takes ownership of sync_processor_.
+ autofill_syncable_service_.MergeDataAndStartSyncing(
+ syncer::AUTOFILL_PROFILE, data_list, std::move(sync_processor_),
+ std::unique_ptr<syncer::SyncErrorFactory>(
+ new syncer::SyncErrorFactoryMock()));
}
+
+ protected:
+ base::MessageLoop message_loop_;
+ MockAutofillProfileSyncableService autofill_syncable_service_;
+ std::unique_ptr<MockSyncChangeProcessor> sync_processor_;
+};
+
+TEST_P(SyncUpdatesUsageStatsTest, SyncUpdatesUsageStats) {
+ auto test_case = GetParam();
+ SetUp();
+ std::vector<std::unique_ptr<AutofillProfile>> profiles_from_web_db;
+
+ AutofillProfile profile(kGuid1, kHttpsOrigin);
+ profile.set_language_code("en");
+ profile.set_use_count(test_case.local_use_count);
+ profile.set_use_date(test_case.local_use_date);
+ EXPECT_EQ(test_case.local_use_count, profile.use_count());
+ EXPECT_EQ(test_case.local_use_date, profile.use_date());
+ profiles_from_web_db.push_back(base::MakeUnique<AutofillProfile>(profile));
+
+ // Remote data has usage stats.
+ sync_pb::EntitySpecifics specifics;
+ sync_pb::AutofillProfileSpecifics* autofill_specifics =
+ specifics.mutable_autofill_profile();
+ autofill_specifics->set_guid(profile.guid());
+ autofill_specifics->set_origin(profile.origin());
+ autofill_specifics->add_name_first(std::string());
+ autofill_specifics->add_name_middle(std::string());
+ autofill_specifics->add_name_last(std::string());
+ autofill_specifics->add_name_full(std::string());
+ autofill_specifics->add_email_address(std::string());
+ autofill_specifics->add_phone_home_whole_number(std::string());
+ autofill_specifics->set_address_home_language_code("en");
+ autofill_specifics->set_use_count(test_case.remote_use_count);
+ autofill_specifics->set_use_date(test_case.remote_use_date);
+ EXPECT_TRUE(autofill_specifics->has_use_count());
+ EXPECT_TRUE(autofill_specifics->has_use_date());
+
+ syncer::SyncDataList data_list;
+ data_list.push_back(syncer::SyncData::CreateLocalData(
+ profile.guid(), profile.guid(), specifics));
+
+ // Expect the local autofill profile to have usage stats after sync.
+ MockAutofillProfileSyncableService::DataBundle expected_bundle;
+ AutofillProfile expected_profile = profile;
+ expected_profile.set_use_count(test_case.synced_use_count);
+ expected_profile.set_use_date(test_case.synced_use_date);
+ expected_bundle.profiles_to_update.push_back(&expected_profile);
+
+ // Expect no changes to remote data.
+ syncer::SyncChangeList expected_empty_change_list;
+
+ MergeDataAndStartSyncing(std::move(profiles_from_web_db), data_list,
+ expected_bundle, expected_empty_change_list);
+ autofill_syncable_service_.StopSyncing(syncer::AUTOFILL_PROFILE);
}
+INSTANTIATE_TEST_CASE_P(
+ AutofillProfileSyncableServiceTest,
+ SyncUpdatesUsageStatsTest,
+ testing::Values(
+ // Local profile with default stats.
+ SyncUpdatesUsageStatsTestCase{0U, base::Time(), 9U, 4321, 9U,
+ base::Time::FromTimeT(4321)},
+ // Local profile has older stats than the server.
+ SyncUpdatesUsageStatsTestCase{3U, base::Time::FromTimeT(1234), 9U, 4321,
+ 9U, base::Time::FromTimeT(4321)},
+ // Local profile has newer stats than the server
+ SyncUpdatesUsageStatsTestCase{10U, base::Time::FromTimeT(9999), 9U,
+ 4321, 9U, base::Time::FromTimeT(4321)}));
+
// Usage stats should be updated by the client.
TEST_F(AutofillProfileSyncableServiceTest, ClientOverwritesUsageStats) {
TestSyncChangeProcessor* sync_change_processor = new TestSyncChangeProcessor;
diff --git a/chromium/components/autofill/core/browser/webdata/autofill_table.cc b/chromium/components/autofill/core/browser/webdata/autofill_table.cc
index 72cf35b3c7b..27d1c00d470 100644
--- a/chromium/components/autofill/core/browser/webdata/autofill_table.cc
+++ b/chromium/components/autofill/core/browser/webdata/autofill_table.cc
@@ -1700,13 +1700,8 @@ bool AutofillTable::GetAllSyncMetadata(syncer::ModelType model_type,
syncer::MetadataBatch* metadata_batch) {
DCHECK_EQ(model_type, syncer::AUTOFILL)
<< "Only the AUTOFILL model type is supported";
- syncer::EntityMetadataMap metadata_records;
- if (GetAllSyncEntityMetadata(model_type, &metadata_records)) {
- for (const auto& pair : metadata_records) {
- // TODO(pnoland): Add batch transfer of metadata map.
- metadata_batch->AddMetadata(pair.first, pair.second);
- }
- } else {
+ DCHECK(metadata_batch);
+ if (!GetAllSyncEntityMetadata(model_type, metadata_batch)) {
return false;
}
@@ -1722,9 +1717,10 @@ bool AutofillTable::GetAllSyncMetadata(syncer::ModelType model_type,
bool AutofillTable::GetAllSyncEntityMetadata(
syncer::ModelType model_type,
- syncer::EntityMetadataMap* metadata_records) {
+ syncer::MetadataBatch* metadata_batch) {
DCHECK_EQ(model_type, syncer::AUTOFILL)
<< "Only the AUTOFILL model type is supported";
+ DCHECK(metadata_batch);
sql::Statement s(db_->GetUniqueStatement(
"SELECT storage_key, value FROM autofill_sync_metadata"));
@@ -1732,10 +1728,12 @@ bool AutofillTable::GetAllSyncEntityMetadata(
while (s.Step()) {
std::string storage_key = s.ColumnString(0);
std::string serialized_metadata = s.ColumnString(1);
- sync_pb::EntityMetadata metadata_record;
- if (metadata_record.ParseFromString(serialized_metadata)) {
- metadata_records->insert(std::make_pair(storage_key, metadata_record));
+ sync_pb::EntityMetadata entity_metadata;
+ if (entity_metadata.ParseFromString(serialized_metadata)) {
+ metadata_batch->AddMetadata(storage_key, entity_metadata);
} else {
+ DLOG(WARNING) << "Failed to deserialize AUTOFILL model type "
+ "sync_pb::EntityMetadata.";
return false;
}
}
diff --git a/chromium/components/autofill/core/browser/webdata/autofill_table.h b/chromium/components/autofill/core/browser/webdata/autofill_table.h
index f3f8a14dcc4..872d127b393 100644
--- a/chromium/components/autofill/core/browser/webdata/autofill_table.h
+++ b/chromium/components/autofill/core/browser/webdata/autofill_table.h
@@ -517,7 +517,7 @@ class AutofillTable : public WebDatabaseTable {
base::Time time);
bool GetAllSyncEntityMetadata(syncer::ModelType model_type,
- syncer::EntityMetadataMap* metadata_records);
+ syncer::MetadataBatch* metadata_batch);
bool GetModelTypeState(syncer::ModelType model_type,
sync_pb::ModelTypeState* state);
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 235dd06230b..58439067907 100644
--- a/chromium/components/autofill/core/browser/webdata/autofill_table_unittest.cc
+++ b/chromium/components/autofill/core/browser/webdata/autofill_table_unittest.cc
@@ -1955,61 +1955,112 @@ TEST_F(AutofillTableTest, DeleteUnmaskedCard) {
outputs.clear();
}
-TEST_F(AutofillTableTest, GetFormValuesForElementName_SubstringMatchEnabled) {
+const size_t kMaxCount = 2;
+struct GetFormValuesTestCase {
+ const char* const field_suggestion[kMaxCount];
+ const char* const field_contents;
+ size_t expected_suggestion_count;
+ const char* const expected_suggestion[kMaxCount];
+};
+
+class GetFormValuesTest : public testing::TestWithParam<GetFormValuesTestCase> {
+ public:
+ GetFormValuesTest() {}
+ ~GetFormValuesTest() override {}
+
+ protected:
+ void SetUp() override {
+ OSCryptMocker::SetUpWithSingleton();
+ ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
+ file_ = temp_dir_.GetPath().AppendASCII("TestWebDatabase");
+
+ table_.reset(new AutofillTable);
+ db_.reset(new WebDatabase);
+ db_->AddTable(table_.get());
+ ASSERT_EQ(sql::INIT_OK, db_->Init(file_));
+ }
+
+ void TearDown() override { OSCryptMocker::TearDown(); }
+
+ base::FilePath file_;
+ base::ScopedTempDir temp_dir_;
+ std::unique_ptr<AutofillTable> table_;
+ std::unique_ptr<WebDatabase> db_;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(GetFormValuesTest);
+};
+
+TEST_P(GetFormValuesTest, GetFormValuesForElementName_SubstringMatchEnabled) {
// Token matching is currently behind a flag.
base::CommandLine::ForCurrentProcess()->AppendSwitch(
switches::kEnableSuggestionsWithSubstringMatch);
- const size_t kMaxCount = 2;
- const struct {
- const char* const field_suggestion[kMaxCount];
- const char* const field_contents;
- size_t expected_suggestion_count;
- const char* const expected_suggestion[kMaxCount];
- } kTestCases[] = {
- {{"user.test", "test_user"}, "TEST", 2, {"test_user", "user.test"}},
- {{"user test", "test-user"}, "user", 2, {"user test", "test-user"}},
- {{"user test", "test-rest"}, "user", 1, {"user test", nullptr}},
- {{"user@test", "test_user"}, "user@t", 1, {"user@test", nullptr}},
- {{"user.test", "test_user"}, "er.tes", 0, {nullptr, nullptr}},
- {{"user test", "test_user"}, "_ser", 0, {nullptr, nullptr}},
- {{"user.test", "test_user"}, "%ser", 0, {nullptr, nullptr}},
- {{"user.test", "test_user"},
- "; DROP TABLE autofill;",
- 0,
- {nullptr, nullptr}},
- };
-
- for (const auto& test_case : kTestCases) {
- SCOPED_TRACE(testing::Message()
- << "suggestion = " << test_case.field_suggestion[0]
- << ", contents = " << test_case.field_contents);
-
- Time t1 = Time::Now();
+ auto test_case = GetParam();
+ SCOPED_TRACE(testing::Message()
+ << "suggestion = " << test_case.field_suggestion[0]
+ << ", contents = " << test_case.field_contents);
- // Simulate the submission of a handful of entries in a field called "Name".
- AutofillChangeList changes;
- FormFieldData field;
- for (size_t k = 0; k < kMaxCount; ++k) {
- field.name = ASCIIToUTF16("Name");
- field.value = ASCIIToUTF16(test_case.field_suggestion[k]);
- table_->AddFormFieldValue(field, &changes);
- }
+ Time t1 = Time::Now();
- std::vector<base::string16> v;
- table_->GetFormValuesForElementName(
- ASCIIToUTF16("Name"), ASCIIToUTF16(test_case.field_contents), &v, 6);
+ // Simulate the submission of a handful of entries in a field called "Name".
+ AutofillChangeList changes;
+ FormFieldData field;
+ for (size_t k = 0; k < kMaxCount; ++k) {
+ field.name = ASCIIToUTF16("Name");
+ field.value = ASCIIToUTF16(test_case.field_suggestion[k]);
+ table_->AddFormFieldValue(field, &changes);
+ }
- EXPECT_EQ(test_case.expected_suggestion_count, v.size());
- for (size_t j = 0; j < test_case.expected_suggestion_count; ++j) {
- EXPECT_EQ(ASCIIToUTF16(test_case.expected_suggestion[j]), v[j]);
- }
+ std::vector<base::string16> v;
+ table_->GetFormValuesForElementName(
+ ASCIIToUTF16("Name"), ASCIIToUTF16(test_case.field_contents), &v, 6);
- changes.clear();
- table_->RemoveFormElementsAddedBetween(t1, Time(), &changes);
+ EXPECT_EQ(test_case.expected_suggestion_count, v.size());
+ for (size_t j = 0; j < test_case.expected_suggestion_count; ++j) {
+ EXPECT_EQ(ASCIIToUTF16(test_case.expected_suggestion[j]), v[j]);
}
+
+ changes.clear();
+ table_->RemoveFormElementsAddedBetween(t1, Time(), &changes);
}
+INSTANTIATE_TEST_CASE_P(
+ AutofillTableTest,
+ GetFormValuesTest,
+ testing::Values(GetFormValuesTestCase{{"user.test", "test_user"},
+ "TEST",
+ 2,
+ {"test_user", "user.test"}},
+ GetFormValuesTestCase{{"user test", "test-user"},
+ "user",
+ 2,
+ {"user test", "test-user"}},
+ GetFormValuesTestCase{{"user test", "test-rest"},
+ "user",
+ 1,
+ {"user test", nullptr}},
+ GetFormValuesTestCase{{"user@test", "test_user"},
+ "user@t",
+ 1,
+ {"user@test", nullptr}},
+ GetFormValuesTestCase{{"user.test", "test_user"},
+ "er.tes",
+ 0,
+ {nullptr, nullptr}},
+ GetFormValuesTestCase{{"user test", "test_user"},
+ "_ser",
+ 0,
+ {nullptr, nullptr}},
+ GetFormValuesTestCase{{"user.test", "test_user"},
+ "%ser",
+ 0,
+ {nullptr, nullptr}},
+ GetFormValuesTestCase{{"user.test", "test_user"},
+ "; DROP TABLE autofill;",
+ 0,
+ {nullptr, nullptr}}));
+
TEST_F(AutofillTableTest, AutofillNoMetadata) {
MetadataBatch metadata_batch;
EXPECT_TRUE(table_->GetAllSyncMetadata(syncer::AUTOFILL, &metadata_batch));
diff --git a/chromium/components/autofill/core/browser/webdata/autofill_wallet_syncable_service.cc b/chromium/components/autofill/core/browser/webdata/autofill_wallet_syncable_service.cc
index b43f4fc3ed7..fc6948f1aef 100644
--- a/chromium/components/autofill/core/browser/webdata/autofill_wallet_syncable_service.cc
+++ b/chromium/components/autofill/core/browser/webdata/autofill_wallet_syncable_service.cc
@@ -10,6 +10,7 @@
#include <utility>
#include "base/logging.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/webdata/autofill_table.h"
@@ -86,8 +87,8 @@ AutofillProfile ProfileFromSpecifics(
AutofillProfile profile(AutofillProfile::SERVER_PROFILE, std::string());
// AutofillProfile stores multi-line addresses with newline separators.
- std::vector<std::string> street_address(address.street_address().begin(),
- address.street_address().end());
+ std::vector<base::StringPiece> street_address(
+ address.street_address().begin(), address.street_address().end());
profile.SetRawInfo(ADDRESS_HOME_STREET_ADDRESS,
base::UTF8ToUTF16(base::JoinString(street_address, "\n")));
diff --git a/chromium/components/autofill/core/common/BUILD.gn b/chromium/components/autofill/core/common/BUILD.gn
index f7a34bb28b6..f3b320f0827 100644
--- a/chromium/components/autofill/core/common/BUILD.gn
+++ b/chromium/components/autofill/core/common/BUILD.gn
@@ -33,6 +33,7 @@ static_library("common") {
"password_form_field_prediction_map.h",
"password_form_fill_data.cc",
"password_form_fill_data.h",
+ "password_form_generation_data.cc",
"password_form_generation_data.h",
"password_generation_util.cc",
"password_generation_util.h",
diff --git a/chromium/components/autofill/core/common/autofill_clock.cc b/chromium/components/autofill/core/common/autofill_clock.cc
index 8702403d9e5..20d70c95413 100644
--- a/chromium/components/autofill/core/common/autofill_clock.cc
+++ b/chromium/components/autofill/core/common/autofill_clock.cc
@@ -13,7 +13,7 @@ namespace autofill {
namespace {
-static base::LazyInstance<AutofillClock> g_autofill_clock =
+static base::LazyInstance<AutofillClock>::DestructorAtExit g_autofill_clock =
LAZY_INSTANCE_INITIALIZER;
} // namespace
diff --git a/chromium/components/autofill/core/common/autofill_clock.h b/chromium/components/autofill/core/common/autofill_clock.h
index 45a991211ba..b94ff272ab4 100644
--- a/chromium/components/autofill/core/common/autofill_clock.h
+++ b/chromium/components/autofill/core/common/autofill_clock.h
@@ -26,7 +26,7 @@ class AutofillClock {
private:
friend class TestAutofillClock;
- friend struct base::DefaultLazyInstanceTraits<AutofillClock>;
+ friend struct base::LazyInstanceTraitsBase<AutofillClock>;
// Resets a normal clock.
static void SetClock();
diff --git a/chromium/components/autofill/core/common/autofill_data_validation.cc b/chromium/components/autofill/core/common/autofill_data_validation.cc
index 07c2b9dc9db..f1075dc384d 100644
--- a/chromium/components/autofill/core/common/autofill_data_validation.cc
+++ b/chromium/components/autofill/core/common/autofill_data_validation.cc
@@ -35,7 +35,6 @@ bool IsValidFormFieldData(const FormFieldData& field) {
IsValidString16(field.value) &&
IsValidString(field.form_control_type) &&
IsValidString(field.autocomplete_attribute) &&
- IsValidString16Vector(field.option_values) &&
IsValidString16Vector(field.option_contents);
}
diff --git a/chromium/components/autofill/core/common/autofill_regexes_unittest.cc b/chromium/components/autofill/core/common/autofill_regexes_unittest.cc
index 107830d52d1..a267e414991 100644
--- a/chromium/components/autofill/core/common/autofill_regexes_unittest.cc
+++ b/chromium/components/autofill/core/common/autofill_regexes_unittest.cc
@@ -16,194 +16,217 @@ using base::ASCIIToUTF16;
namespace autofill {
-TEST(AutofillRegexesTest, SampleRegexes) {
- struct TestCase {
- const char* const input;
- const char* const pattern;
+struct InputPatternTestCase {
+ const char* const input;
+ const char* const pattern;
};
- const TestCase kPositiveCases[] = {
- // Empty pattern
- {"", ""},
- {"Look, ma' -- a non-empty string!", ""},
- // Substring
- {"string", "tri"},
- // Substring at beginning
- {"string", "str"},
- {"string", "^str"},
- // Substring at end
- {"string", "ring"},
- {"string", "ring$"},
- // Case-insensitive
- {"StRiNg", "string"},
- };
- for (const auto& test_case : kPositiveCases) {
+ 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(ASCIIToUTF16(test_case.input),
ASCIIToUTF16(test_case.pattern)));
}
- const TestCase kNegativeCases[] = {
- // Empty string
- {"", "Look, ma' -- a non-empty pattern!"},
- // Substring
- {"string", "trn"},
- // Substring at beginning
- {"string", " str"},
- {"string", "^tri"},
- // Substring at end
- {"string", "ring "},
- {"string", "rin$"},
- };
- for (const auto& test_case : kNegativeCases) {
+ INSTANTIATE_TEST_CASE_P(AutofillRegexes,
+ PositiveSampleTest,
+ testing::Values(
+ // Empty pattern
+ InputPatternTestCase{"", ""},
+ InputPatternTestCase{
+ "Look, ma' -- a non-empty string!", ""},
+ // Substring
+ InputPatternTestCase{"string", "tri"},
+ // Substring at beginning
+ InputPatternTestCase{"string", "str"},
+ InputPatternTestCase{"string", "^str"},
+ // Substring at end
+ InputPatternTestCase{"string", "ring"},
+ InputPatternTestCase{"string", "ring$"},
+ // Case-insensitive
+ InputPatternTestCase{"StRiNg", "string"}));
+
+ 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(ASCIIToUTF16(test_case.input),
ASCIIToUTF16(test_case.pattern)));
- }
}
-TEST(AutofillRegexesTest, ExpirationDate2DigitYearRegexes) {
- struct TestCase {
- const char* const input;
+INSTANTIATE_TEST_CASE_P(AutofillRegexes,
+ NegativeSampleTest,
+ testing::Values(
+ // Empty string
+ InputPatternTestCase{
+ "", "Look, ma' -- a non-empty pattern!"},
+ // Substring
+ InputPatternTestCase{"string", "trn"},
+ // Substring at beginning
+ InputPatternTestCase{"string", " str"},
+ InputPatternTestCase{"string", "^tri"},
+ // Substring at end
+ InputPatternTestCase{"string", "ring "},
+ InputPatternTestCase{"string", "rin$"}));
+
+struct InputTestCase {
+ const char* const input;
};
- const base::string16 pattern = ASCIIToUTF16(kExpirationDate2DigitYearRe);
-
- const TestCase kPositiveCases[] = {
- // Simple two year cases
- {"mm / yy"},
- {"mm/ yy"},
- {"mm /yy"},
- {"mm/yy"},
- {"mm - yy"},
- {"mm- yy"},
- {"mm -yy"},
- {"mm-yy"},
- {"mmyy"},
- // Complex two year cases
- {"Expiration Date (MM / YY)"},
- {"Expiration Date (MM/YY)"},
- {"Expiration Date (MM - YY)"},
- {"Expiration Date (MM-YY)"},
- {"Expiration Date MM / YY"},
- {"Expiration Date MM/YY"},
- {"Expiration Date MM - YY"},
- {"Expiration Date MM-YY"},
- {"expiration date yy"},
- {"Exp Date (MM / YY)"},
- };
+ class ExpirationDate2DigitYearPositive
+ : public testing::TestWithParam<InputTestCase> {};
- for (const auto& test_case : kPositiveCases) {
+ TEST_P(ExpirationDate2DigitYearPositive, ExpirationDate2DigitYearRegexes) {
+ auto test_case = GetParam();
SCOPED_TRACE(test_case.input);
- EXPECT_TRUE(MatchesPattern(ASCIIToUTF16(test_case.input),pattern));
+ const base::string16 pattern = ASCIIToUTF16(kExpirationDate2DigitYearRe);
+ EXPECT_TRUE(MatchesPattern(ASCIIToUTF16(test_case.input), pattern));
}
- const TestCase kNegativeCases[] = {
- {""},
- {"Look, ma' -- an invalid string!"},
- {"mmfavouritewordyy"},
- {"mm a yy"},
- {"mm a yyyy"},
- // Simple four year cases
- {"mm / yyyy"},
- {"mm/ yyyy"},
- {"mm /yyyy"},
- {"mm/yyyy"},
- {"mm - yyyy"},
- {"mm- yyyy"},
- {"mm -yyyy"},
- {"mm-yyyy"},
- {"mmyyyy"},
- // Complex four year cases
- {"Expiration Date (MM / YYYY)"},
- {"Expiration Date (MM/YYYY)"},
- {"Expiration Date (MM - YYYY)"},
- {"Expiration Date (MM-YYYY)"},
- {"Expiration Date MM / YYYY"},
- {"Expiration Date MM/YYYY"},
- {"Expiration Date MM - YYYY"},
- {"Expiration Date MM-YYYY"},
- {"expiration date yyyy"},
- {"Exp Date (MM / YYYY)"},
- };
-
- for (const auto& test_case : kNegativeCases) {
+ INSTANTIATE_TEST_CASE_P(
+ AutofillRegexes,
+ ExpirationDate2DigitYearPositive,
+ testing::Values(InputTestCase{"mm / yy"},
+ InputTestCase{"mm/ yy"},
+ InputTestCase{"mm /yy"},
+ InputTestCase{"mm/yy"},
+ InputTestCase{"mm - yy"},
+ InputTestCase{"mm- yy"},
+ InputTestCase{"mm -yy"},
+ InputTestCase{"mm-yy"},
+ InputTestCase{"mmyy"},
+ // Complex two year cases
+ InputTestCase{"Expiration Date (MM / YY)"},
+ InputTestCase{"Expiration Date (MM/YY)"},
+ InputTestCase{"Expiration Date (MM - YY)"},
+ InputTestCase{"Expiration Date (MM-YY)"},
+ InputTestCase{"Expiration Date MM / YY"},
+ InputTestCase{"Expiration Date MM/YY"},
+ InputTestCase{"Expiration Date MM - YY"},
+ InputTestCase{"Expiration Date MM-YY"},
+ InputTestCase{"expiration date yy"},
+ InputTestCase{"Exp Date (MM / YY)"}));
+
+ class ExpirationDate2DigitYearNegative
+ : public testing::TestWithParam<InputTestCase> {};
+
+ TEST_P(ExpirationDate2DigitYearNegative, ExpirationDate2DigitYearRegexes) {
+ auto test_case = GetParam();
SCOPED_TRACE(test_case.input);
+ const base::string16 pattern = ASCIIToUTF16(kExpirationDate2DigitYearRe);
EXPECT_FALSE(MatchesPattern(ASCIIToUTF16(test_case.input), pattern));
}
-}
-TEST(AutofillRegexesTest, ExpirationDate4DigitYearRegexes) {
- struct TestCase {
- const char* const input;
- };
-
- const base::string16 pattern = ASCIIToUTF16(kExpirationDate4DigitYearRe);
-
- const TestCase kPositiveCases[] = {
- // Simple four year cases
- {"mm / yyyy"},
- {"mm/ yyyy"},
- {"mm /yyyy"},
- {"mm/yyyy"},
- {"mm - yyyy"},
- {"mm- yyyy"},
- {"mm -yyyy"},
- {"mm-yyyy"},
- {"mmyyyy"},
- // Complex four year cases
- {"Expiration Date (MM / YYYY)"},
- {"Expiration Date (MM/YYYY)"},
- {"Expiration Date (MM - YYYY)"},
- {"Expiration Date (MM-YYYY)"},
- {"Expiration Date MM / YYYY"},
- {"Expiration Date MM/YYYY"},
- {"Expiration Date MM - YYYY"},
- {"Expiration Date MM-YYYY"},
- {"expiration date yyyy"},
- {"Exp Date (MM / YYYY)"},
- };
-
- for (const auto& test_case : kPositiveCases) {
+ INSTANTIATE_TEST_CASE_P(
+ AutofillRegexes,
+ ExpirationDate2DigitYearNegative,
+ testing::Values(InputTestCase{""},
+ InputTestCase{"Look, ma' -- an invalid string!"},
+ InputTestCase{"mmfavouritewordyy"},
+ InputTestCase{"mm a yy"},
+ InputTestCase{"mm a yyyy"},
+ // Simple four year cases
+ InputTestCase{"mm / yyyy"},
+ InputTestCase{"mm/ yyyy"},
+ InputTestCase{"mm /yyyy"},
+ InputTestCase{"mm/yyyy"},
+ InputTestCase{"mm - yyyy"},
+ InputTestCase{"mm- yyyy"},
+ InputTestCase{"mm -yyyy"},
+ InputTestCase{"mm-yyyy"},
+ InputTestCase{"mmyyyy"},
+ // Complex four year cases
+ InputTestCase{"Expiration Date (MM / YYYY)"},
+ InputTestCase{"Expiration Date (MM/YYYY)"},
+ InputTestCase{"Expiration Date (MM - YYYY)"},
+ InputTestCase{"Expiration Date (MM-YYYY)"},
+ InputTestCase{"Expiration Date MM / YYYY"},
+ InputTestCase{"Expiration Date MM/YYYY"},
+ InputTestCase{"Expiration Date MM - YYYY"},
+ InputTestCase{"Expiration Date MM-YYYY"},
+ InputTestCase{"expiration date yyyy"},
+ InputTestCase{"Exp Date (MM / YYYY)"}));
+
+ class ExpirationDate4DigitYearPositive
+ : public testing::TestWithParam<InputTestCase> {};
+
+ TEST_P(ExpirationDate4DigitYearPositive, ExpirationDate4DigitYearRegexes) {
+ auto test_case = GetParam();
+ const base::string16 pattern = ASCIIToUTF16(kExpirationDate4DigitYearRe);
SCOPED_TRACE(test_case.input);
- EXPECT_TRUE(MatchesPattern(ASCIIToUTF16(test_case.input),pattern));
+ EXPECT_TRUE(MatchesPattern(ASCIIToUTF16(test_case.input), pattern));
}
- const TestCase kNegativeCases[] = {
- {""},
- {"Look, ma' -- an invalid string!"},
- {"mmfavouritewordyy"},
- {"mm a yy"},
- {"mm a yyyy"},
- // Simple two year cases
- {"mm / yy"},
- {"mm/ yy"},
- {"mm /yy"},
- {"mm/yy"},
- {"mm - yy"},
- {"mm- yy"},
- {"mm -yy"},
- {"mm-yy"},
- {"mmyy"},
- // Complex two year cases
- {"Expiration Date (MM / YY)"},
- {"Expiration Date (MM/YY)"},
- {"Expiration Date (MM - YY)"},
- {"Expiration Date (MM-YY)"},
- {"Expiration Date MM / YY"},
- {"Expiration Date MM/YY"},
- {"Expiration Date MM - YY"},
- {"Expiration Date MM-YY"},
- {"expiration date yy"},
- {"Exp Date (MM / YY)"},
- };
-
- for (const auto& test_case : kNegativeCases) {
+ INSTANTIATE_TEST_CASE_P(AutofillRegexes,
+ ExpirationDate4DigitYearPositive,
+ testing::Values(
+ // Simple four year cases
+ InputTestCase{"mm / yyyy"},
+ InputTestCase{"mm/ yyyy"},
+ InputTestCase{"mm /yyyy"},
+ InputTestCase{"mm/yyyy"},
+ InputTestCase{"mm - yyyy"},
+ InputTestCase{"mm- yyyy"},
+ InputTestCase{"mm -yyyy"},
+ InputTestCase{"mm-yyyy"},
+ InputTestCase{"mmyyyy"},
+ // Complex four year cases
+ InputTestCase{"Expiration Date (MM / YYYY)"},
+ InputTestCase{"Expiration Date (MM/YYYY)"},
+ InputTestCase{"Expiration Date (MM - YYYY)"},
+ InputTestCase{"Expiration Date (MM-YYYY)"},
+ InputTestCase{"Expiration Date MM / YYYY"},
+ InputTestCase{"Expiration Date MM/YYYY"},
+ InputTestCase{"Expiration Date MM - YYYY"},
+ InputTestCase{"Expiration Date MM-YYYY"},
+ InputTestCase{"expiration date yyyy"},
+ InputTestCase{"Exp Date (MM / YYYY)"}));
+
+ class ExpirationDate4DigitYearNegative
+ : public testing::TestWithParam<InputTestCase> {};
+
+ TEST_P(ExpirationDate4DigitYearNegative, ExpirationDate4DigitYearRegexes) {
+ auto test_case = GetParam();
+ const base::string16 pattern = ASCIIToUTF16(kExpirationDate4DigitYearRe);
SCOPED_TRACE(test_case.input);
EXPECT_FALSE(MatchesPattern(ASCIIToUTF16(test_case.input), pattern));
- }
}
+INSTANTIATE_TEST_CASE_P(
+ AutofillRegexes,
+ ExpirationDate4DigitYearNegative,
+ testing::Values(InputTestCase{""},
+ InputTestCase{"Look, ma' -- an invalid string!"},
+ InputTestCase{"mmfavouritewordyy"},
+ InputTestCase{"mm a yy"},
+ InputTestCase{"mm a yyyy"},
+ // Simple two year cases
+ InputTestCase{"mm / yy"},
+ InputTestCase{"mm/ yy"},
+ InputTestCase{"mm /yy"},
+ InputTestCase{"mm/yy"},
+ InputTestCase{"mm - yy"},
+ InputTestCase{"mm- yy"},
+ InputTestCase{"mm -yy"},
+ InputTestCase{"mm-yy"},
+ InputTestCase{"mmyy"},
+ // Complex two year cases
+ InputTestCase{"Expiration Date (MM / YY)"},
+ InputTestCase{"Expiration Date (MM/YY)"},
+ InputTestCase{"Expiration Date (MM - YY)"},
+ InputTestCase{"Expiration Date (MM-YY)"},
+ InputTestCase{"Expiration Date MM / YY"},
+ InputTestCase{"Expiration Date MM/YY"},
+ InputTestCase{"Expiration Date MM - YY"},
+ InputTestCase{"Expiration Date MM-YY"},
+ InputTestCase{"expiration date yy"},
+ InputTestCase{"Exp Date (MM / YY)"}));
+
} // namespace autofill
diff --git a/chromium/components/autofill/core/common/autofill_util_unittest.cc b/chromium/components/autofill/core/common/autofill_util_unittest.cc
index 2115b3ed3ab..6e04dc76031 100644
--- a/chromium/components/autofill/core/common/autofill_util_unittest.cc
+++ b/chromium/components/autofill/core/common/autofill_util_unittest.cc
@@ -15,7 +15,18 @@
namespace autofill {
// Tests for FieldIsSuggestionSubstringStartingOnTokenBoundary().
-TEST(AutofillUtilTest, FieldIsSuggestionSubstringStartingOnTokenBoundary) {
+struct FieldIsTokenBoundarySubstringCase {
+ const char* const field_suggestion;
+ const char* const field_contents;
+ const bool case_sensitive;
+ const bool expected_result;
+};
+
+class FieldIsTokenBoundarySubstringCaseTest
+ : public testing::TestWithParam<FieldIsTokenBoundarySubstringCase> {};
+
+TEST_P(FieldIsTokenBoundarySubstringCaseTest,
+ FieldIsSuggestionSubstringStartingOnTokenBoundary) {
// FieldIsSuggestionSubstringStartingOnTokenBoundary should not work yet
// without a flag.
EXPECT_FALSE(FieldIsSuggestionSubstringStartingOnTokenBoundary(
@@ -25,106 +36,124 @@ TEST(AutofillUtilTest, FieldIsSuggestionSubstringStartingOnTokenBoundary) {
base::CommandLine::ForCurrentProcess()->AppendSwitch(
switches::kEnableSuggestionsWithSubstringMatch);
- const struct {
- const char* const field_suggestion;
- const char* const field_contents;
- bool case_sensitive;
- bool expected_result;
- } kTestCases[] = {
- {"ab@cd.b", "a", false, true},
- {"ab@cd.b", "b", false, true},
- {"ab@cd.b", "Ab", false, true},
- {"ab@cd.b", "Ab", true, false},
- {"ab@cd.b", "cd", true, true},
- {"ab@cd.b", "d", false, false},
- {"ab@cd.b", "b@", true, false},
- {"ab@cd.b", "ab", false, true},
- {"ab@cd.b", "cd.b", true, true},
- {"ab@cd.b", "b@cd", false, false},
- {"ab@cd.b", "ab@c", false, true},
- {"ba.a.ab", "a.a", false, true},
- {"", "ab", false, false},
- {"", "ab", true, false},
- {"ab", "", false, true},
- {"ab", "", true, true},
- };
-
- for (const auto& test_case : kTestCases) {
- SCOPED_TRACE(testing::Message()
- << "suggestion = " << test_case.field_suggestion
- << ", contents = " << test_case.field_contents
- << ", case_sensitive = " << test_case.case_sensitive);
-
- EXPECT_EQ(test_case.expected_result,
- FieldIsSuggestionSubstringStartingOnTokenBoundary(
- base::ASCIIToUTF16(test_case.field_suggestion),
- base::ASCIIToUTF16(test_case.field_contents),
- test_case.case_sensitive));
- }
+ auto test_case = GetParam();
+ SCOPED_TRACE(testing::Message()
+ << "suggestion = " << test_case.field_suggestion
+ << ", contents = " << test_case.field_contents
+ << ", case_sensitive = " << test_case.case_sensitive);
+
+ EXPECT_EQ(test_case.expected_result,
+ FieldIsSuggestionSubstringStartingOnTokenBoundary(
+ base::ASCIIToUTF16(test_case.field_suggestion),
+ base::ASCIIToUTF16(test_case.field_contents),
+ test_case.case_sensitive));
}
+INSTANTIATE_TEST_CASE_P(
+ AutofillUtilTest,
+ FieldIsTokenBoundarySubstringCaseTest,
+ testing::Values(
+ FieldIsTokenBoundarySubstringCase{"ab@cd.b", "a", false, true},
+ FieldIsTokenBoundarySubstringCase{"ab@cd.b", "b", false, true},
+ FieldIsTokenBoundarySubstringCase{"ab@cd.b", "Ab", false, true},
+ FieldIsTokenBoundarySubstringCase{"ab@cd.b", "Ab", true, false},
+ FieldIsTokenBoundarySubstringCase{"ab@cd.b", "cd", true, true},
+ FieldIsTokenBoundarySubstringCase{"ab@cd.b", "d", false, false},
+ FieldIsTokenBoundarySubstringCase{"ab@cd.b", "b@", true, false},
+ FieldIsTokenBoundarySubstringCase{"ab@cd.b", "ab", false, true},
+ FieldIsTokenBoundarySubstringCase{"ab@cd.b", "cd.b", true, true},
+ FieldIsTokenBoundarySubstringCase{"ab@cd.b", "b@cd", false, false},
+ FieldIsTokenBoundarySubstringCase{"ab@cd.b", "ab@c", false, true},
+ FieldIsTokenBoundarySubstringCase{"ba.a.ab", "a.a", false, true},
+ FieldIsTokenBoundarySubstringCase{"", "ab", false, false},
+ FieldIsTokenBoundarySubstringCase{"", "ab", true, false},
+ FieldIsTokenBoundarySubstringCase{"ab", "", false, true},
+ FieldIsTokenBoundarySubstringCase{"ab", "", true, true}));
+
// Tests for GetTextSelectionStart().
-TEST(AutofillUtilTest, GetTextSelectionStart) {
- const size_t kInvalid = base::string16::npos;
- const struct {
- const char* const field_suggestion;
- const char* const field_contents;
- bool case_sensitive;
- size_t expected_start;
- } kTestCases[] = {
- {"ab@cd.b", "a", false, 1},
- {"ab@cd.b", "A", true, kInvalid},
- {"ab@cd.b", "Ab", false, 2},
- {"ab@cd.b", "Ab", true, kInvalid},
- {"ab@cd.b", "cd", false, 5},
- {"ab@cd.b", "ab@c", false, 4},
- {"ab@cd.b", "cd.b", false, 7},
- {"ab@cd.b", "b@cd", false, kInvalid},
- {"ab@cd.b", "b", false, 7},
- {"ba.a.ab", "a.a", false, 6},
- {"texample@example.com", "example", false, 16},
- };
-
- for (const auto& test_case : kTestCases) {
- SCOPED_TRACE(testing::Message()
- << "suggestion = " << test_case.field_suggestion
- << ", contents = " << test_case.field_contents
- << ", case_sensitive = " << test_case.case_sensitive);
-
- EXPECT_EQ(
- test_case.expected_start,
- GetTextSelectionStart(base::ASCIIToUTF16(test_case.field_suggestion),
- base::ASCIIToUTF16(test_case.field_contents),
- test_case.case_sensitive));
- }
+struct GetTextSelectionStartCase {
+ const char* const field_suggestion;
+ const char* const field_contents;
+ const bool case_sensitive;
+ const size_t expected_start;
+};
+
+class GetTextSelectionStartTest
+ : public testing::TestWithParam<GetTextSelectionStartCase> {};
+
+TEST_P(GetTextSelectionStartTest, GetTextSelectionStart) {
+ auto test_case = GetParam();
+ SCOPED_TRACE(testing::Message()
+ << "suggestion = " << test_case.field_suggestion
+ << ", contents = " << test_case.field_contents
+ << ", case_sensitive = " << test_case.case_sensitive);
+ EXPECT_EQ(
+ test_case.expected_start,
+ GetTextSelectionStart(base::ASCIIToUTF16(test_case.field_suggestion),
+ base::ASCIIToUTF16(test_case.field_contents),
+ test_case.case_sensitive));
}
+INSTANTIATE_TEST_CASE_P(
+ AutofillUtilTest,
+ GetTextSelectionStartTest,
+ testing::Values(
+ GetTextSelectionStartCase{"ab@cd.b", "a", false, 1},
+ GetTextSelectionStartCase{"ab@cd.b", "A", true, base::string16::npos},
+ GetTextSelectionStartCase{"ab@cd.b", "Ab", false, 2},
+ GetTextSelectionStartCase{"ab@cd.b", "Ab", true, base::string16::npos},
+ GetTextSelectionStartCase{"ab@cd.b", "cd", false, 5},
+ GetTextSelectionStartCase{"ab@cd.b", "ab@c", false, 4},
+ GetTextSelectionStartCase{"ab@cd.b", "cd.b", false, 7},
+ GetTextSelectionStartCase{"ab@cd.b", "b@cd", false,
+ base::string16::npos},
+ GetTextSelectionStartCase{"ab@cd.b", "b", false, 7},
+ GetTextSelectionStartCase{"ba.a.ab", "a.a", false, 6},
+ GetTextSelectionStartCase{"texample@example.com", "example", false,
+ 16}));
+
// Tests for LowercaseAndTokenizeAttributeString
-TEST(AutofillUtilTest, LowercaseAndTokenizeAttributeString) {
- const struct {
- const char* const attribute;
- std::vector<std::string> tokens;
- } kTestCases[] = {
- // Test leading and trailing whitespace, test tabs and newlines
- {"foo bar baz", {"foo", "bar", "baz"}},
- {" foo bar baz ", {"foo", "bar", "baz"}},
- {"foo\tbar baz ", {"foo", "bar", "baz"}},
- {"foo\nbar baz ", {"foo", "bar", "baz"}},
-
- // Test different forms of capitalization
- {"FOO BAR BAZ", {"foo", "bar", "baz"}},
- {"foO baR bAz", {"foo", "bar", "baz"}},
-
- // Test collapsing of multiple whitespace characters in a row
- {" \t\t\n\n ", std::vector<std::string>()},
- {"foO baR bAz", {"foo", "bar", "baz"}},
- };
-
- for (const auto& test_case : kTestCases) {
- SCOPED_TRACE(testing::Message() << "attribute = " << test_case.attribute);
-
- EXPECT_EQ(test_case.tokens,
- LowercaseAndTokenizeAttributeString(test_case.attribute));
- }
+struct LowercaseAndTokenizeAttributeStringCase {
+ const char* const attribute;
+ std::vector<std::string> tokens;
+};
+
+class LowercaseAndTokenizeAttributeStringTest
+ : public testing::TestWithParam<LowercaseAndTokenizeAttributeStringCase> {};
+
+TEST_P(LowercaseAndTokenizeAttributeStringTest,
+ LowercaseAndTokenizeAttributeStringTest) {
+ auto test_case = GetParam();
+ SCOPED_TRACE(testing::Message() << "attribute = " << test_case.attribute);
+
+ EXPECT_EQ(test_case.tokens,
+ LowercaseAndTokenizeAttributeString(test_case.attribute));
}
+
+INSTANTIATE_TEST_CASE_P(
+ AutofillUtilTest,
+ LowercaseAndTokenizeAttributeStringTest,
+ testing::Values(
+ // Test leading and trailing whitespace, test tabs and newlines
+ LowercaseAndTokenizeAttributeStringCase{"foo bar baz",
+ {"foo", "bar", "baz"}},
+ LowercaseAndTokenizeAttributeStringCase{" foo bar baz ",
+ {"foo", "bar", "baz"}},
+ LowercaseAndTokenizeAttributeStringCase{"foo\tbar baz ",
+ {"foo", "bar", "baz"}},
+ LowercaseAndTokenizeAttributeStringCase{"foo\nbar baz ",
+ {"foo", "bar", "baz"}},
+
+ // Test different forms of capitalization
+ LowercaseAndTokenizeAttributeStringCase{"FOO BAR BAZ",
+ {"foo", "bar", "baz"}},
+ LowercaseAndTokenizeAttributeStringCase{"foO baR bAz",
+ {"foo", "bar", "baz"}},
+
+ // Test collapsing of multiple whitespace characters in a row
+ LowercaseAndTokenizeAttributeStringCase{" \t\t\n\n ",
+ std::vector<std::string>()},
+ LowercaseAndTokenizeAttributeStringCase{"foO baR bAz",
+ {"foo", "bar", "baz"}}));
+
} // namespace autofill
diff --git a/chromium/components/autofill/core/common/password_form.cc b/chromium/components/autofill/core/common/password_form.cc
index 3969e1ff4e4..17892915c65 100644
--- a/chromium/components/autofill/core/common/password_form.cc
+++ b/chromium/components/autofill/core/common/password_form.cc
@@ -2,6 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
+#include <algorithm>
#include <ostream>
#include <sstream>
@@ -40,9 +41,9 @@ void PasswordFormToJSON(const PasswordForm& form,
form.new_password_value_is_default);
target->SetBoolean("new_password_marked_by_site",
form.new_password_marked_by_site);
- target->SetString("other_possible_usernames",
- base::JoinString(form.other_possible_usernames,
- base::ASCIIToUTF16("|")));
+ target->SetString(
+ "other_possible_usernames",
+ OtherPossibleUsernamesToString(form.other_possible_usernames));
target->SetBoolean("blacklisted", form.blacklisted_by_user);
target->SetBoolean("preferred", form.preferred);
target->SetDouble("date_created", form.date_created.ToDoubleT());
@@ -167,6 +168,16 @@ bool LessThanUniqueKey::operator()(
return left->origin < right->origin;
}
+base::string16 OtherPossibleUsernamesToString(
+ const PossibleUsernamesVector& possible_usernames) {
+ std::vector<base::string16> pairs(possible_usernames.size());
+ std::transform(possible_usernames.begin(), possible_usernames.end(),
+ pairs.begin(), [](const PossibleUsernamePair& p) {
+ return p.first + base::ASCIIToUTF16("+") + p.second;
+ });
+ return base::JoinString(pairs, base::ASCIIToUTF16(", "));
+}
+
std::ostream& operator<<(std::ostream& os, PasswordForm::Layout layout) {
switch (layout) {
case PasswordForm::Layout::LAYOUT_OTHER:
diff --git a/chromium/components/autofill/core/common/password_form.h b/chromium/components/autofill/core/common/password_form.h
index 74716230236..8bcf44850a8 100644
--- a/chromium/components/autofill/core/common/password_form.h
+++ b/chromium/components/autofill/core/common/password_form.h
@@ -17,6 +17,12 @@
namespace autofill {
+// Pair of possible username value and field name that contained this value.
+using PossibleUsernamePair = std::pair<base::string16, base::string16>;
+
+// Vector of possible username values and corresponding field names.
+using PossibleUsernamesVector = std::vector<PossibleUsernamePair>;
+
// The PasswordForm struct encapsulates information about a login form,
// which can be an HTML form or a dialog with username/password text fields.
//
@@ -141,7 +147,7 @@ struct PasswordForm {
// determining the username are incorrect. Optional.
//
// When parsing an HTML form, this is typically empty.
- std::vector<base::string16> other_possible_usernames;
+ PossibleUsernamesVector other_possible_usernames;
// The name of the input element corresponding to the current password.
// Optional (improves scoring).
@@ -301,6 +307,10 @@ struct LessThanUniqueKey {
const std::unique_ptr<PasswordForm>& right) const;
};
+// Converts a vector of possible usernames to string.
+base::string16 OtherPossibleUsernamesToString(
+ const PossibleUsernamesVector& possible_usernames);
+
// For testing.
std::ostream& operator<<(std::ostream& os, PasswordForm::Layout layout);
std::ostream& operator<<(std::ostream& os, const PasswordForm& form);
diff --git a/chromium/components/autofill/core/common/password_form_fill_data.cc b/chromium/components/autofill/core/common/password_form_fill_data.cc
index 9b1383046e0..e53c160b3be 100644
--- a/chromium/components/autofill/core/common/password_form_fill_data.cc
+++ b/chromium/components/autofill/core/common/password_form_fill_data.cc
@@ -84,10 +84,17 @@ void InitPasswordFormFillData(
if (it.second->is_public_suffix_match ||
it.second->is_affiliation_based_match)
key.realm = it.second->signon_realm;
- result->other_possible_usernames[key] =
- it.second->other_possible_usernames;
}
}
}
+PasswordFormFillData ClearPasswordValues(const PasswordFormFillData& data) {
+ PasswordFormFillData result(data);
+ if (result.wait_for_username)
+ result.password_field.value.clear();
+ for (auto& credentials : result.additional_logins)
+ credentials.second.password.clear();
+ return result;
+}
+
} // namespace autofill
diff --git a/chromium/components/autofill/core/common/password_form_fill_data.h b/chromium/components/autofill/core/common/password_form_fill_data.h
index fd0f64fe84a..b7e8e27c0cd 100644
--- a/chromium/components/autofill/core/common/password_form_fill_data.h
+++ b/chromium/components/autofill/core/common/password_form_fill_data.h
@@ -63,6 +63,7 @@ struct PasswordFormFillData {
// that the original saved username is correct. This data is keyed by the
// saved username/password to ensure uniqueness, though the username is not
// used.
+ // TODO(crbug/188908). Remove |other_possible_usernames| or launch.
UsernamesCollection other_possible_usernames;
// Tells us whether we need to wait for the user to enter a valid username
@@ -96,6 +97,10 @@ void InitPasswordFormFillData(
bool enable_other_possible_usernames,
PasswordFormFillData* result);
+// Renderer needs to have only a password that should be autofilled, all other
+// passwords might be safety erased.
+PasswordFormFillData ClearPasswordValues(const PasswordFormFillData& data);
+
} // namespace autofill
#endif // COMPONENTS_AUTOFILL_CORE_COMMON_PASSWORD_FORM_FILL_DATA_H__
diff --git a/chromium/components/autofill/core/common/password_form_generation_data.cc b/chromium/components/autofill/core/common/password_form_generation_data.cc
new file mode 100644
index 00000000000..521eabc1818
--- /dev/null
+++ b/chromium/components/autofill/core/common/password_form_generation_data.cc
@@ -0,0 +1,21 @@
+// Copyright (c) 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.
+
+#include "components/autofill/core/common/password_form_generation_data.h"
+
+namespace autofill {
+
+PasswordFormGenerationData::PasswordFormGenerationData() = default;
+
+PasswordFormGenerationData::PasswordFormGenerationData(
+ FormSignature form_signature,
+ FieldSignature field_signature)
+ : form_signature(form_signature), field_signature(field_signature) {}
+
+PasswordFormGenerationData::PasswordFormGenerationData(
+ const PasswordFormGenerationData& other) = default;
+
+PasswordFormGenerationData::~PasswordFormGenerationData() = default;
+
+} // namespace autofill
diff --git a/chromium/components/autofill/core/common/password_form_generation_data.h b/chromium/components/autofill/core/common/password_form_generation_data.h
index d010d9a8ddb..f14d2953821 100644
--- a/chromium/components/autofill/core/common/password_form_generation_data.h
+++ b/chromium/components/autofill/core/common/password_form_generation_data.h
@@ -7,6 +7,7 @@
#include <stdint.h>
+#include "base/optional.h"
#include "base/strings/string16.h"
#include "components/autofill/core/common/form_field_data.h"
#include "components/autofill/core/common/signatures_util.h"
@@ -17,6 +18,12 @@ namespace autofill {
// Structure used for sending information from browser to renderer about on
// which fields password should be generated.
struct PasswordFormGenerationData {
+ PasswordFormGenerationData();
+ PasswordFormGenerationData(FormSignature form_signature,
+ FieldSignature field_signature);
+ PasswordFormGenerationData(const PasswordFormGenerationData& other);
+ ~PasswordFormGenerationData();
+
// The unique signature of form where password should be generated
// (see components/autofill/core/browser/form_structure.h).
FormSignature form_signature;
@@ -24,6 +31,10 @@ struct PasswordFormGenerationData {
// The unique signature of field where password should be generated
// (see components/autofill/core/browser/autofill_field.h).
FieldSignature field_signature;
+
+ // The unique signature of the confirmation field where the generated password
+ // should be copied to.
+ base::Optional<FieldSignature> confirmation_field_signature;
};
} // namespace autofill
diff --git a/chromium/components/autofill/core/common/save_password_progress_logger.cc b/chromium/components/autofill/core/common/save_password_progress_logger.cc
index 5fc676c20e9..8a55fdd2b36 100644
--- a/chromium/components/autofill/core/common/save_password_progress_logger.cc
+++ b/chromium/components/autofill/core/common/save_password_progress_logger.cc
@@ -18,7 +18,6 @@
using base::checked_cast;
using base::Value;
using base::DictionaryValue;
-using base::StringValue;
namespace autofill {
@@ -94,7 +93,7 @@ void SavePasswordProgressLogger::LogHTMLForm(
void SavePasswordProgressLogger::LogURL(
SavePasswordProgressLogger::StringID label,
const GURL& url) {
- LogValue(label, StringValue(ScrubURL(url)));
+ LogValue(label, Value(ScrubURL(url)));
}
void SavePasswordProgressLogger::LogBoolean(
@@ -117,7 +116,7 @@ void SavePasswordProgressLogger::LogNumber(
void SavePasswordProgressLogger::LogMessage(
SavePasswordProgressLogger::StringID message) {
- LogValue(STRING_MESSAGE, StringValue(GetStringFromID(message)));
+ LogValue(STRING_MESSAGE, Value(GetStringFromID(message)));
}
// static
@@ -144,7 +143,7 @@ std::string SavePasswordProgressLogger::ScrubElementID(
// static
std::string SavePasswordProgressLogger::ScrubElementID(std::string element_id) {
std::replace_if(element_id.begin(), element_id.end(), IsUnwantedInElementID,
- ' ');
+ '_');
return element_id;
}
@@ -391,6 +390,39 @@ std::string SavePasswordProgressLogger::GetStringFromID(
return "Form votes";
case SavePasswordProgressLogger::STRING_REUSE_FOUND:
return "Password reused from ";
+ case SavePasswordProgressLogger::STRING_GENERATION_DISABLED_SAVING_DISABLED:
+ return "Generation disabled: saving disabled";
+ case SavePasswordProgressLogger::STRING_GENERATION_DISABLED_NO_SYNC:
+ return "Generation disabled: no sync";
+ case SavePasswordProgressLogger::
+ STRING_GENERATION_DISABLED_CUSTOM_PASSPHRASE:
+ return "Generation disabled: custom passphrase";
+ case STRING_GENERATION_RENDERER_ENABLED:
+ return "Generation renderer enabled";
+ case STRING_GENERATION_RENDERER_INVALID_PASSWORD_FORM:
+ return "Generation invalid PasswordForm";
+ case STRING_GENERATION_RENDERER_POSSIBLE_ACCOUNT_CREATION_FORMS:
+ return "Generation possible account creation forms";
+ case STRING_GENERATION_RENDERER_NO_PASSWORD_MANAGER_ACCESS:
+ return "Generation: no PasswordManager access";
+ case STRING_GENERATION_RENDERER_FORM_ALREADY_FOUND:
+ return "Generation: account creation form already found";
+ case STRING_GENERATION_RENDERER_NO_POSSIBLE_CREATION_FORMS:
+ return "Generation: no possible account creation forms";
+ case STRING_GENERATION_RENDERER_NOT_BLACKLISTED:
+ return "Generation: no non-blacklisted confirmation";
+ case STRING_GENERATION_RENDERER_AUTOCOMPLETE_ATTRIBUTE:
+ return "Generation: autocomplete attributes found";
+ case STRING_GENERATION_RENDERER_NO_SERVER_SIGNAL:
+ return "Generation: no server signal";
+ case STRING_GENERATION_RENDERER_ELIGIBLE_FORM_FOUND:
+ return "Generation: eligible form found";
+ case STRING_GENERATION_RENDERER_NO_FIELD_FOUND:
+ return "Generation: fields for generation are not found";
+ case STRING_GENERATION_RENDERER_SHOW_GENERATION_POPUP:
+ return "Show generation popup";
+ case STRING_GENERATION_RENDERER_GENERATED_PASSWORD_ACCEPTED:
+ return "Generated password accepted";
case SavePasswordProgressLogger::STRING_INVALID:
return "INVALID";
// Intentionally no default: clause here -- all IDs need to get covered.
diff --git a/chromium/components/autofill/core/common/save_password_progress_logger.h b/chromium/components/autofill/core/common/save_password_progress_logger.h
index de8a08232b4..19c9e04c0dd 100644
--- a/chromium/components/autofill/core/common/save_password_progress_logger.h
+++ b/chromium/components/autofill/core/common/save_password_progress_logger.h
@@ -150,6 +150,22 @@ class SavePasswordProgressLogger {
STRING_SERVER_PREDICTIONS,
STRING_FORM_VOTES,
STRING_REUSE_FOUND,
+ STRING_GENERATION_DISABLED_SAVING_DISABLED,
+ STRING_GENERATION_DISABLED_NO_SYNC,
+ STRING_GENERATION_DISABLED_CUSTOM_PASSPHRASE,
+ STRING_GENERATION_RENDERER_ENABLED,
+ STRING_GENERATION_RENDERER_INVALID_PASSWORD_FORM,
+ STRING_GENERATION_RENDERER_POSSIBLE_ACCOUNT_CREATION_FORMS,
+ STRING_GENERATION_RENDERER_NO_PASSWORD_MANAGER_ACCESS,
+ STRING_GENERATION_RENDERER_FORM_ALREADY_FOUND,
+ STRING_GENERATION_RENDERER_NO_POSSIBLE_CREATION_FORMS,
+ STRING_GENERATION_RENDERER_NOT_BLACKLISTED,
+ STRING_GENERATION_RENDERER_AUTOCOMPLETE_ATTRIBUTE,
+ STRING_GENERATION_RENDERER_NO_SERVER_SIGNAL,
+ STRING_GENERATION_RENDERER_ELIGIBLE_FORM_FOUND,
+ STRING_GENERATION_RENDERER_NO_FIELD_FOUND,
+ STRING_GENERATION_RENDERER_SHOW_GENERATION_POPUP,
+ STRING_GENERATION_RENDERER_GENERATED_PASSWORD_ACCEPTED,
STRING_INVALID, // Represents a string returned in a case of an error.
STRING_MAX = STRING_INVALID
};
diff --git a/chromium/components/autofill/core/common/save_password_progress_logger_unittest.cc b/chromium/components/autofill/core/common/save_password_progress_logger_unittest.cc
index f047183d414..a20d11946af 100644
--- a/chromium/components/autofill/core/common/save_password_progress_logger_unittest.cc
+++ b/chromium/components/autofill/core/common/save_password_progress_logger_unittest.cc
@@ -63,11 +63,11 @@ TEST(SavePasswordProgressLoggerTest, LogPasswordFormElementID) {
TestLogger logger;
PasswordForm form;
const std::string kHTMLInside("Username <script> element");
- const std::string kHTMLInsideExpected("Username script element");
+ const std::string kHTMLInsideExpected("Username__script__element");
const std::string kIPAddressInside("y128.0.0.1Y");
- const std::string kIPAddressInsideExpected("y128 0 0 1Y");
+ const std::string kIPAddressInsideExpected("y128_0_0_1Y");
const std::string kSpecialCharsInside("X@#a$%B&*c()D;:e+!x");
- const std::string kSpecialCharsInsideExpected("X a B c D e x");
+ const std::string kSpecialCharsInsideExpected("X__a__B__c__D__e__x");
form.username_element = UTF8ToUTF16(kHTMLInside);
form.password_element = UTF8ToUTF16(kIPAddressInside);
form.new_password_element = UTF8ToUTF16(kSpecialCharsInside);