diff options
author | Allan Sandfeld Jensen <allan.jensen@qt.io> | 2017-11-20 15:06:40 +0100 |
---|---|---|
committer | Allan Sandfeld Jensen <allan.jensen@qt.io> | 2017-11-22 11:48:58 +0000 |
commit | daa093eea7c773db06799a13bd7e4e2e2a9f8f14 (patch) | |
tree | 96cc5e7b9194c1b29eab927730bfa419e7111c25 /chromium/components/autofill/core | |
parent | be59a35641616a4cf23c4a13fa0632624b021c1b (diff) | |
download | qtwebengine-chromium-daa093eea7c773db06799a13bd7e4e2e2a9f8f14.tar.gz |
BASELINE: Update Chromium to 63.0.3239.58
Change-Id: Ia93b322a00ba4dd4004f3bcf1254063ba90e1605
Reviewed-by: Alexandru Croitor <alexandru.croitor@qt.io>
Diffstat (limited to 'chromium/components/autofill/core')
77 files changed, 6456 insertions, 1272 deletions
diff --git a/chromium/components/autofill/core/browser/BUILD.gn b/chromium/components/autofill/core/browser/BUILD.gn index efd501528ef..73e59c10804 100644 --- a/chromium/components/autofill/core/browser/BUILD.gn +++ b/chromium/components/autofill/core/browser/BUILD.gn @@ -14,6 +14,11 @@ static_library("browser") { "address_field.h", "address_i18n.cc", "address_i18n.h", + "address_normalization_manager.cc", + "address_normalization_manager.h", + "address_normalizer.h", + "address_normalizer_impl.cc", + "address_normalizer_impl.h", "address_rewriter.cc", "address_rewriter.h", "address_rewriter_rules.cc", @@ -93,6 +98,8 @@ static_library("browser") { "form_group.h", "form_structure.cc", "form_structure.h", + "form_types.cc", + "form_types.h", "legal_message_line.cc", "legal_message_line.h", "name_field.cc", @@ -126,6 +133,8 @@ static_library("browser") { "risk_data_loader.h", "state_names.cc", "state_names.h", + "subkey_requester.cc", + "subkey_requester.h", "suggestion.cc", "suggestion.h", "ui/card_unmask_prompt_controller.h", @@ -250,6 +259,8 @@ static_library("test_support") { "data_driven_test.cc", "data_driven_test.h", "suggestion_test_helpers.h", + "test_address_normalizer.cc", + "test_address_normalizer.h", "test_autofill_client.cc", "test_autofill_client.h", "test_autofill_clock.cc", @@ -326,6 +337,8 @@ source_set("unit_tests") { "address_combobox_model_unittest.cc", "address_field_unittest.cc", "address_i18n_unittest.cc", + "address_normalization_manager_unittest.cc", + "address_normalizer_impl_unittest.cc", "address_rewriter_unittest.cc", "address_unittest.cc", "address_validation_util_unittest.cc", @@ -335,6 +348,7 @@ source_set("unit_tests") { "autofill_data_util_unittest.cc", "autofill_download_manager_unittest.cc", "autofill_driver_factory_unittest.cc", + "autofill_experiments_unittest.cc", "autofill_external_delegate_unittest.cc", "autofill_field_unittest.cc", "autofill_ie_toolbar_import_win_unittest.cc", @@ -365,6 +379,7 @@ source_set("unit_tests") { "phone_number_i18n_unittest.cc", "phone_number_unittest.cc", "region_combobox_model_unittest.cc", + "subkey_requester_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_normalization_manager.cc b/chromium/components/autofill/core/browser/address_normalization_manager.cc new file mode 100644 index 00000000000..3cd73cec2f1 --- /dev/null +++ b/chromium/components/autofill/core/browser/address_normalization_manager.cc @@ -0,0 +1,106 @@ +// 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/address_normalization_manager.h" + +#include <utility> + +#include "base/memory/ptr_util.h" +#include "base/strings/utf_string_conversions.h" +#include "components/autofill/core/browser/autofill_data_util.h" +#include "components/autofill/core/browser/autofill_profile.h" +#include "components/autofill/core/browser/field_types.h" + +namespace autofill { + +namespace { +constexpr int kAddressNormalizationTimeoutSeconds = 5; +} // namespace + +AddressNormalizationManager::AddressNormalizationManager( + AddressNormalizer* address_normalizer, + const std::string& default_country_code) + : default_country_code_(default_country_code), + address_normalizer_(address_normalizer) { + DCHECK(autofill::data_util::IsValidCountryCode(default_country_code)); + DCHECK(address_normalizer_); +} + +AddressNormalizationManager::~AddressNormalizationManager() {} + +void AddressNormalizationManager::FinalizePendingRequestsWithCompletionCallback( + base::OnceClosure completion_callback) { + DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); + DCHECK(!completion_callback_); + completion_callback_ = std::move(completion_callback); + accepting_requests_ = false; + MaybeRunCompletionCallback(); +} + +void AddressNormalizationManager::StartNormalizingAddress( + AutofillProfile* profile) { + DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); + DCHECK(accepting_requests_) << "FinalizeWithCompletionCallback has been " + "called, cannot normalize more addresses"; + + delegates_.push_back( + base::MakeUnique<NormalizerDelegate>(this, address_normalizer_, profile)); +} + +void AddressNormalizationManager::MaybeRunCompletionCallback() { + if (accepting_requests_ || !completion_callback_) + return; + + for (const auto& delegate : delegates_) { + if (!delegate->has_completed()) + return; + } + + // We're no longer accepting requests, and all the delegates have completed. + // Now's the time to run the completion callback. + std::move(completion_callback_).Run(); + + // Start accepting requests after the completion callback has run. + delegates_.clear(); + accepting_requests_ = true; +} + +AddressNormalizationManager::NormalizerDelegate::NormalizerDelegate( + AddressNormalizationManager* owner, + AddressNormalizer* address_normalizer, + AutofillProfile* profile) + : owner_(owner), profile_(profile) { + DCHECK(owner_); + DCHECK(profile_); + + std::string country_code = + base::UTF16ToUTF8(profile_->GetRawInfo(ADDRESS_HOME_COUNTRY)); + if (!autofill::data_util::IsValidCountryCode(country_code)) + country_code = owner_->default_country_code_; + + address_normalizer->StartAddressNormalization( + *profile_, country_code, kAddressNormalizationTimeoutSeconds, this); +} + +void AddressNormalizationManager::NormalizerDelegate::OnAddressNormalized( + const AutofillProfile& normalized_profile) { + OnCompletion(normalized_profile); +} + +void AddressNormalizationManager::NormalizerDelegate::OnCouldNotNormalize( + const AutofillProfile& profile) { + // Since the phone number is formatted in either case, this profile should + // be used. + OnCompletion(profile); +} + +void AddressNormalizationManager::NormalizerDelegate::OnCompletion( + const AutofillProfile& profile) { + DCHECK(!has_completed_); + has_completed_ = true; + *profile_ = profile; + owner_->MaybeRunCompletionCallback(); +} + +} // namespace autofill diff --git a/chromium/components/autofill/core/browser/address_normalization_manager.h b/chromium/components/autofill/core/browser/address_normalization_manager.h new file mode 100644 index 00000000000..f4be49831d6 --- /dev/null +++ b/chromium/components/autofill/core/browser/address_normalization_manager.h @@ -0,0 +1,104 @@ +// 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_ADDRESS_NORMALIZATION_MANAGER_H_ +#define COMPONENTS_AUTOFILL_CORE_BROWSER_ADDRESS_NORMALIZATION_MANAGER_H_ + +#include <memory> +#include <string> +#include <vector> + +#include "base/callback.h" +#include "base/threading/thread_checker.h" +#include "components/autofill/core/browser/address_normalizer.h" + +namespace autofill { + +class AddressNormalizer; +class AutofillProfile; + +// Class to handle multiple concurrent address normalization requests. This +// class is not thread-safe. +class AddressNormalizationManager { + public: + // Initializes an AddressNormalizationManager. |default_country_code| will be + // used if the country code in an AutofillProfile to normalize is not valid. + // The AddressNormalizationManager does not own |address_normalizer|. + AddressNormalizationManager(AddressNormalizer* address_normalizer, + const std::string& default_country_code); + + ~AddressNormalizationManager(); + + // Stops accepting normalization requests until all pending requests complete. + // If all the address normalization requests have already completed, + // |completion_callback| will be called before this method returns. Otherwise, + // it will be called as soon as the last pending request completes. + void FinalizePendingRequestsWithCompletionCallback( + base::OnceClosure completion_callback); + + // Normalizes the address in |profile|. This may or may not happen + // asynchronously. On completion, the address in |profile| will be updated + // with the normalized address. + void StartNormalizingAddress(AutofillProfile* profile); + + private: + // Implements the payments::AddressNormalizer::Delegate interface, and + // notifies its parent AddressNormalizationManager when normalization has + // completed. + class NormalizerDelegate : public autofill::AddressNormalizer::Delegate { + public: + // |owner| is the parent AddressNormalizationManager, |address_normalizer| + // is a pointer to an instance of AddressNormalizer which will handle + // normalization of |profile|. |profile| will be updated when normalization + // is complete. + NormalizerDelegate(AddressNormalizationManager* owner, + AddressNormalizer* address_normalizer, + AutofillProfile* profile); + + // Returns whether this delegate has completed or not. + bool has_completed() const { return has_completed_; } + + // AddressNormalizer::Delegate: + void OnAddressNormalized( + const AutofillProfile& normalized_profile) override; + void OnCouldNotNormalize(const AutofillProfile& profile) override; + + private: + // Helper method that handles when normalization has completed. + void OnCompletion(const AutofillProfile& profile); + + bool has_completed_ = false; + AddressNormalizationManager* owner_ = nullptr; + autofill::AutofillProfile* profile_ = nullptr; + + DISALLOW_COPY_AND_ASSIGN(NormalizerDelegate); + }; + + friend class NormalizerDelegate; + + // Runs the completion callback if all the delegates have completed. + void MaybeRunCompletionCallback(); + + // Whether the AddressNormalizationManager is still accepting requests or not. + bool accepting_requests_ = true; + + // The default country code to use if a profile does not have a valid country. + const std::string default_country_code_; + + // The callback to execute when all addresses have been normalized. + base::OnceClosure completion_callback_; + + // Storage for all the delegates that handle the normalization requests. + std::vector<std::unique_ptr<NormalizerDelegate>> delegates_; + + // An unowned raw pointer to the AddressNormalizer to use. + AddressNormalizer* address_normalizer_; + + THREAD_CHECKER(thread_checker_); + DISALLOW_COPY_AND_ASSIGN(AddressNormalizationManager); +}; + +} // namespace autofill + +#endif // COMPONENTS_AUTOFILL_CORE_BROWSER_ADDRESS_NORMALIZATION_MANAGER_H_ diff --git a/chromium/components/autofill/core/browser/address_normalization_manager_unittest.cc b/chromium/components/autofill/core/browser/address_normalization_manager_unittest.cc new file mode 100644 index 00000000000..ffef4787500 --- /dev/null +++ b/chromium/components/autofill/core/browser/address_normalization_manager_unittest.cc @@ -0,0 +1,63 @@ +// 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/address_normalization_manager.h" + +#include <memory> + +#include "base/bind.h" +#include "base/bind_helpers.h" +#include "components/autofill/core/browser/test_address_normalizer.h" +#include "testing/gtest/include/gtest/gtest.h" + +namespace autofill { + +class AddressNormalizationManagerTest : public testing::Test { + protected: + AddressNormalizationManagerTest() {} + + void Initialize(const std::string& country_code) { + manager_ = std::make_unique<AddressNormalizationManager>( + &address_normalizer_, country_code); + } + + void Finalize() { + manager_->FinalizePendingRequestsWithCompletionCallback( + base::BindOnce(&AddressNormalizationManagerTest::CompletionCallback, + base::Unretained(this))); + } + + void CompletionCallback() { completion_callback_called_ = true; } + + TestAddressNormalizer address_normalizer_; + std::unique_ptr<AddressNormalizationManager> manager_; + bool completion_callback_called_ = false; +}; + +TEST_F(AddressNormalizationManagerTest, SynchronousResult) { + Initialize("US"); + + AutofillProfile profile_to_normalize; + manager_->StartNormalizingAddress(&profile_to_normalize); + + EXPECT_FALSE(completion_callback_called_); + Finalize(); + EXPECT_TRUE(completion_callback_called_); +} + +TEST_F(AddressNormalizationManagerTest, AsynchronousResult) { + Initialize("US"); + address_normalizer_.DelayNormalization(); + + AutofillProfile profile_to_normalize; + manager_->StartNormalizingAddress(&profile_to_normalize); + + EXPECT_FALSE(completion_callback_called_); + Finalize(); + EXPECT_FALSE(completion_callback_called_); + address_normalizer_.CompleteAddressNormalization(); + EXPECT_TRUE(completion_callback_called_); +} + +} // namespace autofill diff --git a/chromium/components/autofill/core/browser/address_normalizer.h b/chromium/components/autofill/core/browser/address_normalizer.h new file mode 100644 index 00000000000..81010da2cd2 --- /dev/null +++ b/chromium/components/autofill/core/browser/address_normalizer.h @@ -0,0 +1,54 @@ +// 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_ADDRESS_NORMALIZER_H_ +#define COMPONENTS_AUTOFILL_CORE_BROWSER_ADDRESS_NORMALIZER_H_ + +#include <string> + +#include "third_party/libaddressinput/chromium/chrome_address_validator.h" + +namespace autofill { + +class AutofillProfile; + +// A class used to normalize addresses. +class AddressNormalizer : public autofill::LoadRulesListener { + public: + // The interface for the normalization delegates. + class Delegate { + public: + virtual void OnAddressNormalized( + const AutofillProfile& normalized_profile) = 0; + + virtual void OnCouldNotNormalize(const AutofillProfile& profile) = 0; + + protected: + virtual ~Delegate() {} + }; + + // Start loading the validation rules for the specified |region_code|. + virtual void LoadRulesForRegion(const std::string& region_code) = 0; + + // Returns whether the rules for the specified |region_code| have finished + // loading. + virtual bool AreRulesLoadedForRegion(const std::string& region_code) = 0; + + // Starts the normalization of the |profile| based on the |region_code|. The + // normalized profile will be returned to the |requester| possibly + // asynchronously. If the normalization is not completed in |timeout_seconds| + // the requester will be informed and the request cancelled. This value should + // be greater or equal to 0, for which it means that the normalization should + // happen synchronously, or not at all if the rules are not already loaded. + // Will start loading the rules for the |region_code| if they had not started + // loading. + virtual void StartAddressNormalization(const AutofillProfile& profile, + const std::string& region_code, + int timeout_seconds, + Delegate* requester) = 0; +}; + +} // namespace autofill + +#endif // COMPONENTS_AUTOFILL_CORE_BROWSER_ADDRESS_NORMALIZER_H_ diff --git a/chromium/components/autofill/core/browser/address_normalizer_impl.cc b/chromium/components/autofill/core/browser/address_normalizer_impl.cc new file mode 100644 index 00000000000..d7240126b28 --- /dev/null +++ b/chromium/components/autofill/core/browser/address_normalizer_impl.cc @@ -0,0 +1,189 @@ +// 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/address_normalizer_impl.h" + +#include <stddef.h> +#include <utility> + +#include "base/bind.h" +#include "base/bind_helpers.h" +#include "base/cancelable_callback.h" +#include "base/location.h" +#include "base/logging.h" +#include "base/strings/utf_string_conversions.h" +#include "base/threading/sequenced_task_runner_handle.h" +#include "base/time/time.h" +#include "components/autofill/core/browser/address_i18n.h" +#include "components/autofill/core/browser/autofill_profile.h" +#include "components/autofill/core/browser/phone_number_i18n.h" +#include "third_party/libaddressinput/chromium/chrome_address_validator.h" +#include "third_party/libaddressinput/src/cpp/include/libaddressinput/address_data.h" +#include "third_party/libaddressinput/src/cpp/include/libaddressinput/source.h" +#include "third_party/libaddressinput/src/cpp/include/libaddressinput/storage.h" + +namespace autofill { + +namespace { + +using ::i18n::addressinput::Source; +using ::i18n::addressinput::Storage; + +} // namespace + +class AddressNormalizerImpl::NormalizationRequest { + public: + // The |delegate| and |address_validator| need to outlive this Request. + NormalizationRequest(const AutofillProfile& profile, + const std::string& region_code, + int timeout_seconds, + AddressNormalizer::Delegate* delegate, + AddressValidator* address_validator) + : profile_(profile), + region_code_(region_code), + delegate_(delegate), + address_validator_(address_validator), + has_responded_(false), + on_timeout_(base::Bind(&NormalizationRequest::OnRulesLoaded, + base::Unretained(this), + false)) { + base::SequencedTaskRunnerHandle::Get()->PostDelayedTask( + FROM_HERE, on_timeout_.callback(), + base::TimeDelta::FromSeconds(timeout_seconds)); + } + + ~NormalizationRequest() {} + + void OnRulesLoaded(bool success) { + on_timeout_.Cancel(); + + // Check if the timeout happened before the rules were loaded. + if (has_responded_) + return; + has_responded_ = true; + + // In either case, format the phone number. + FormatPhoneNumberForResponse(); + + if (!success) { + delegate_->OnCouldNotNormalize(profile_); + return; + } + + // The rules should be loaded. + DCHECK(address_validator_->AreRulesLoadedForRegion(region_code_)); + + // Create the AddressData from the profile. + ::i18n::addressinput::AddressData address_data = + *autofill::i18n::CreateAddressDataFromAutofillProfile(profile_, + region_code_); + + // Normalize the address. + if (address_validator_ && + address_validator_->NormalizeAddress(&address_data)) { + profile_.SetRawInfo(ADDRESS_HOME_STATE, + base::UTF8ToUTF16(address_data.administrative_area)); + profile_.SetRawInfo(ADDRESS_HOME_CITY, + base::UTF8ToUTF16(address_data.locality)); + profile_.SetRawInfo(ADDRESS_HOME_DEPENDENT_LOCALITY, + base::UTF8ToUTF16(address_data.dependent_locality)); + } + + delegate_->OnAddressNormalized(profile_); + } + + private: + // Tries to format the phone number to the E.164 format to send in the Payment + // Response, as defined in the Payment Request spec. Keeps the original + // if it cannot be formatted. More info at: + // https://w3c.github.io/browser-payment-api/#paymentrequest-updated-algorithm + void FormatPhoneNumberForResponse() { + const std::string original_number = base::UTF16ToUTF8( + profile_.GetInfo(AutofillType(PHONE_HOME_WHOLE_NUMBER), region_code_)); + + std::string formatted_number = + autofill::i18n::FormatPhoneForResponse(original_number, region_code_); + + profile_.SetRawInfo(PHONE_HOME_WHOLE_NUMBER, + base::UTF8ToUTF16(formatted_number)); + } + + AutofillProfile profile_; + std::string region_code_; + AddressNormalizer::Delegate* delegate_; + AddressValidator* address_validator_; + + bool has_responded_; + base::CancelableCallback<void()> on_timeout_; + + DISALLOW_COPY_AND_ASSIGN(NormalizationRequest); +}; + +AddressNormalizerImpl::AddressNormalizerImpl(std::unique_ptr<Source> source, + std::unique_ptr<Storage> storage) + : address_validator_(std::move(source), std::move(storage), this) {} + +AddressNormalizerImpl::~AddressNormalizerImpl() {} + +void AddressNormalizerImpl::LoadRulesForRegion(const std::string& region_code) { + address_validator_.LoadRules(region_code); +} + +bool AddressNormalizerImpl::AreRulesLoadedForRegion( + const std::string& region_code) { + return address_validator_.AreRulesLoadedForRegion(region_code); +} + +void AddressNormalizerImpl::StartAddressNormalization( + const AutofillProfile& profile, + const std::string& region_code, + int timeout_seconds, + AddressNormalizer::Delegate* requester) { + DCHECK_GE(timeout_seconds, 0); + + std::unique_ptr<NormalizationRequest> request = + std::make_unique<NormalizationRequest>(profile, region_code, + timeout_seconds, requester, + &address_validator_); + + // If the rules are already loaded for |region_code|, the |request| will call + // back to the delegate (|requester|) synchronously. + if (AreRulesLoadedForRegion(region_code)) { + request->OnRulesLoaded(true); + return; + } + + // Setup the variables so the profile gets normalized when the rules have + // finished loading. + auto it = pending_normalization_.find(region_code); + if (it == pending_normalization_.end()) { + // If no entry exists yet, create the entry and assign it to |it|. + it = pending_normalization_ + .insert(std::make_pair( + region_code, + std::vector<std::unique_ptr<NormalizationRequest>>())) + .first; + } + + it->second.push_back(std::move(request)); + + // Start loading the rules for that region. If the rules were already in the + // process of being loaded, this call will do nothing. + LoadRulesForRegion(region_code); +} + +void AddressNormalizerImpl::OnAddressValidationRulesLoaded( + const std::string& region_code, + bool success) { + // Check if an address normalization is pending. + auto it = pending_normalization_.find(region_code); + if (it != pending_normalization_.end()) { + for (size_t i = 0; i < it->second.size(); ++i) { + it->second[i]->OnRulesLoaded(success); + } + pending_normalization_.erase(it); + } +} + +} // namespace autofill diff --git a/chromium/components/autofill/core/browser/address_normalizer_impl.h b/chromium/components/autofill/core/browser/address_normalizer_impl.h new file mode 100644 index 00000000000..3d40ea04823 --- /dev/null +++ b/chromium/components/autofill/core/browser/address_normalizer_impl.h @@ -0,0 +1,61 @@ +// 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_ADDRESS_NORMALIZER_IMPL_H_ +#define COMPONENTS_AUTOFILL_CORE_BROWSER_ADDRESS_NORMALIZER_IMPL_H_ + +#include <map> +#include <memory> +#include <string> +#include <vector> + +#include "base/macros.h" +#include "components/autofill/core/browser/address_normalizer.h" + +namespace i18n { +namespace addressinput { +class Source; +class Storage; +} // namespace addressinput +} // namespace i18n + +namespace autofill { + +class AutofillProfile; + +// A class used to normalize addresses. +class AddressNormalizerImpl : public AddressNormalizer { + public: + AddressNormalizerImpl(std::unique_ptr<::i18n::addressinput::Source> source, + std::unique_ptr<::i18n::addressinput::Storage> storage); + ~AddressNormalizerImpl() override; + + // AddressNormalizer implementation. + void LoadRulesForRegion(const std::string& region_code) override; + bool AreRulesLoadedForRegion(const std::string& region_code) override; + void StartAddressNormalization(const AutofillProfile& profile, + const std::string& region_code, + int timeout_seconds, + Delegate* requester) override; + + private: + // Called when the validation rules for the |region_code| have finished + // loading. Implementation of the LoadRulesListener interface. + void OnAddressValidationRulesLoaded(const std::string& region_code, + bool success) override; + + // Map associating a region code to pending normalizations. + class NormalizationRequest; + std::map<std::string, std::vector<std::unique_ptr<NormalizationRequest>>> + pending_normalization_; + + // The address validator used to normalize addresses. + AddressValidator address_validator_; + + DISALLOW_COPY_AND_ASSIGN(AddressNormalizerImpl); +}; + +} // namespace autofill + +#endif // COMPONENTS_AUTOFILL_CORE_BROWSER_ADDRESS_NORMALIZER_IMPL_H_ diff --git a/chromium/components/autofill/core/browser/address_normalizer_impl_unittest.cc b/chromium/components/autofill/core/browser/address_normalizer_impl_unittest.cc new file mode 100644 index 00000000000..7ec31cab1ca --- /dev/null +++ b/chromium/components/autofill/core/browser/address_normalizer_impl_unittest.cc @@ -0,0 +1,245 @@ +// 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/address_normalizer_impl.h" + +#include <utility> + +#include "base/strings/utf_string_conversions.h" +#include "base/test/scoped_task_environment.h" +#include "components/autofill/core/browser/autofill_profile.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" +#include "third_party/libaddressinput/src/cpp/include/libaddressinput/storage.h" +#include "third_party/libaddressinput/src/cpp/test/testdata_source.h" + +namespace autofill { +namespace { + +using ::i18n::addressinput::NullStorage; +using ::i18n::addressinput::Source; +using ::i18n::addressinput::Storage; +using ::i18n::addressinput::TestdataSource; + +const char kLocale[] = "US"; + +// The requester of normalization for this test. +class NormalizationDelegate : public AddressNormalizer::Delegate { + public: + NormalizationDelegate() + : normalized_called_(false), not_normalized_called_(false) {} + + ~NormalizationDelegate() override {} + + void OnAddressNormalized(const AutofillProfile& profile) override { + normalized_called_ = true; + profile_ = profile; + } + + void OnCouldNotNormalize(const AutofillProfile& profile) override { + not_normalized_called_ = true; + profile_ = profile; + } + + bool normalized_called() const { return normalized_called_; } + + bool not_normalized_called() const { return not_normalized_called_; } + + const AutofillProfile& profile() const { return profile_; } + + private: + bool normalized_called_; + bool not_normalized_called_; + AutofillProfile profile_; + + DISALLOW_COPY_AND_ASSIGN(NormalizationDelegate); +}; + +// Used to load region rules for this test. +class ChromiumTestdataSource : public TestdataSource { + public: + ChromiumTestdataSource() : TestdataSource(true) {} + + ~ChromiumTestdataSource() override {} + + // For this test, only load the rules for the kLocale. + void Get(const std::string& key, const Callback& data_ready) const override { + data_ready( + true, key, + new std::string("{\"data/US\": " + "{\"id\":\"data/US\",\"key\":\"US\",\"name\":\"UNITED " + "STATES\",\"lang\":\"en\",\"languages\":\"en\"}}")); + } + + private: + DISALLOW_COPY_AND_ASSIGN(ChromiumTestdataSource); +}; + +// A test subclass of the AddressNormalizerImpl. Used to simulate rules not +// being loaded. +class TestAddressNormalizer : public AddressNormalizerImpl { + public: + TestAddressNormalizer(std::unique_ptr<::i18n::addressinput::Source> source, + std::unique_ptr<::i18n::addressinput::Storage> storage) + : AddressNormalizerImpl(std::move(source), std::move(storage)), + should_load_rules_(true) {} + + ~TestAddressNormalizer() override {} + + void ShouldLoadRules(bool should_load_rules) { + should_load_rules_ = should_load_rules; + } + + void LoadRulesForRegion(const std::string& region_code) override { + if (should_load_rules_) { + AddressNormalizerImpl::LoadRulesForRegion(region_code); + } + } + + private: + bool should_load_rules_; + + DISALLOW_COPY_AND_ASSIGN(TestAddressNormalizer); +}; + +} // namespace + +class AddressNormalizerTest : public testing::Test { + protected: + AddressNormalizerTest() + : normalizer_(new TestAddressNormalizer( + std::unique_ptr<Source>(new ChromiumTestdataSource), + std::unique_ptr<Storage>(new NullStorage))) {} + + ~AddressNormalizerTest() override {} + + const std::unique_ptr<TestAddressNormalizer> normalizer_; + + base::test::ScopedTaskEnvironment scoped_task_environment_; + + private: + DISALLOW_COPY_AND_ASSIGN(AddressNormalizerTest); +}; + +// Tests that rules are not loaded by default. +TEST_F(AddressNormalizerTest, AreRulesLoadedForRegion_NotLoaded) { + EXPECT_FALSE(normalizer_->AreRulesLoadedForRegion(kLocale)); +} + +// Tests that the rules are loaded correctly. +TEST_F(AddressNormalizerTest, AreRulesLoadedForRegion_Loaded) { + normalizer_->LoadRulesForRegion(kLocale); + EXPECT_TRUE(normalizer_->AreRulesLoadedForRegion(kLocale)); +} + +// Tests that if the rules are loaded before the normalization is started, the +// normalized profile will be returned to the delegate synchronously. +TEST_F(AddressNormalizerTest, StartNormalization_RulesLoaded) { + NormalizationDelegate delegate; + AutofillProfile profile; + + // Load the rules. + normalizer_->LoadRulesForRegion(kLocale); + EXPECT_TRUE(normalizer_->AreRulesLoadedForRegion(kLocale)); + + // Start the normalization. + normalizer_->StartAddressNormalization(profile, kLocale, 0, &delegate); + + // Since the rules are already loaded, the address should be normalized + // synchronously. + EXPECT_TRUE(delegate.normalized_called()); + EXPECT_FALSE(delegate.not_normalized_called()); +} + +// Tests that if the rules are not loaded before the normalization and cannot be +// loaded after, the address will not be normalized and the delegate will be +// notified. +TEST_F(AddressNormalizerTest, StartNormalization_RulesNotLoaded_WillNotLoad) { + NormalizationDelegate delegate; + AutofillProfile profile; + + // Make sure the rules will not be loaded in the StartAddressNormalization + // call. + normalizer_->ShouldLoadRules(false); + + // Start the normalization. + normalizer_->StartAddressNormalization(profile, kLocale, 0, &delegate); + + // Let the timeout execute. + scoped_task_environment_.RunUntilIdle(); + + // Since the rules are never loaded and the timeout is 0, the delegate should + // get notified that the address could not be normalized. + EXPECT_FALSE(delegate.normalized_called()); + EXPECT_TRUE(delegate.not_normalized_called()); +} + +// Tests that if the rules are not loaded before the call to +// StartAddressNormalization, they will be loaded in the call. +TEST_F(AddressNormalizerTest, StartNormalization_RulesNotLoaded_WillLoad) { + NormalizationDelegate delegate; + AutofillProfile profile; + + // Start the normalization. + normalizer_->StartAddressNormalization(profile, kLocale, 0, &delegate); + + // Even if the rules are not loaded before the call to + // StartAddressNormalization, they should get loaded in the call. Since our + // test source is synchronous, the normalization will happen synchronously + // too. + EXPECT_TRUE(normalizer_->AreRulesLoadedForRegion(kLocale)); + EXPECT_TRUE(delegate.normalized_called()); + EXPECT_FALSE(delegate.not_normalized_called()); +} + +// Tests that the phone number is formatted when the address is normalized. +TEST_F(AddressNormalizerTest, FormatPhone_AddressNormalized) { + NormalizationDelegate delegate; + AutofillProfile profile; + profile.SetRawInfo(PHONE_HOME_WHOLE_NUMBER, + base::UTF8ToUTF16("(515) 123-1234")); + + // Load the rules. + normalizer_->LoadRulesForRegion(kLocale); + EXPECT_TRUE(normalizer_->AreRulesLoadedForRegion(kLocale)); + + // Start the normalization. + normalizer_->StartAddressNormalization(profile, kLocale, 0, &delegate); + + // Make sure the address was normalized. + EXPECT_TRUE(delegate.normalized_called()); + + // Expect that the phone number was formatted. + EXPECT_EQ("+15151231234", base::UTF16ToUTF8(delegate.profile().GetRawInfo( + PHONE_HOME_WHOLE_NUMBER))); +} + +// Tests that the phone number is formatted even when the address is not +// normalized. +TEST_F(AddressNormalizerTest, FormatPhone_AddressNotNormalized) { + NormalizationDelegate delegate; + AutofillProfile profile; + profile.SetRawInfo(PHONE_HOME_WHOLE_NUMBER, + base::UTF8ToUTF16("515-123-1234")); + + // Make sure the rules will not be loaded in the StartAddressNormalization + // call. + normalizer_->ShouldLoadRules(false); + + // Start the normalization. + normalizer_->StartAddressNormalization(profile, kLocale, 0, &delegate); + + // Let the timeout execute. + scoped_task_environment_.RunUntilIdle(); + + // Make sure the address was not normalized. + EXPECT_TRUE(delegate.not_normalized_called()); + + // Expect that the phone number was formatted. + EXPECT_EQ("+15151231234", base::UTF16ToUTF8(delegate.profile().GetRawInfo( + PHONE_HOME_WHOLE_NUMBER))); +} + +} // namespace autofill diff --git a/chromium/components/autofill/core/browser/address_validation_util.cc b/chromium/components/autofill/core/browser/address_validation_util.cc index 76b056dc178..0f1a01eadab 100644 --- a/chromium/components/autofill/core/browser/address_validation_util.cc +++ b/chromium/components/autofill/core/browser/address_validation_util.cc @@ -97,6 +97,15 @@ void InitializeAddressFromProfile(const AutofillProfile& profile, base::UTF16ToUTF8(profile.GetRawInfo(ADDRESS_HOME_ZIP)); } +void SetEmptyValidityIfEmpty(AutofillProfile* profile) { + if (profile->GetRawInfo(ADDRESS_HOME_COUNTRY).empty()) + profile->SetValidityState(ADDRESS_HOME_COUNTRY, AutofillProfile::EMPTY); + if (profile->GetRawInfo(ADDRESS_HOME_STATE).empty()) + profile->SetValidityState(ADDRESS_HOME_STATE, AutofillProfile::EMPTY); + if (profile->GetRawInfo(ADDRESS_HOME_ZIP).empty()) + profile->SetValidityState(ADDRESS_HOME_ZIP, AutofillProfile::EMPTY); +} + } // namespace namespace address_validation_util { @@ -116,6 +125,7 @@ AutofillProfile::ValidityState ValidateAddress( // unclear which, if any, rule should apply. SetAllValidityStates(profile, AutofillProfile::UNVALIDATED); SetValidityStateForAddressField(profile, COUNTRY, AutofillProfile::INVALID); + SetEmptyValidityIfEmpty(profile); return AutofillProfile::INVALID; } @@ -148,6 +158,9 @@ AutofillProfile::ValidityState ValidateAddress( profile_validity = AutofillProfile::INVALID; } } + + SetEmptyValidityIfEmpty(profile); + return profile_validity; } diff --git a/chromium/components/autofill/core/browser/address_validation_util_unittest.cc b/chromium/components/autofill/core/browser/address_validation_util_unittest.cc index 604995c8124..172b7f899eb 100644 --- a/chromium/components/autofill/core/browser/address_validation_util_unittest.cc +++ b/chromium/components/autofill/core/browser/address_validation_util_unittest.cc @@ -127,6 +127,20 @@ TEST_F(AutofillAddressValidationTest, ValidateFullProfile_CountryCodeNotExist) { profile.GetValidityState(ADDRESS_HOME_ZIP)); } +TEST_F(AutofillAddressValidationTest, ValidateFullProfile_EmptyCountryCode) { + // This is a profile with no country code, therefore it cannot be validated + // according to ValidationTestDataSource. + AutofillProfile profile(autofill::test::GetFullValidProfile()); + profile.SetRawInfo(ADDRESS_HOME_COUNTRY, base::UTF8ToUTF16("")); + EXPECT_EQ(AutofillProfile::INVALID, ValidateAddressTest(&profile)); + EXPECT_EQ(AutofillProfile::EMPTY, + profile.GetValidityState(ADDRESS_HOME_COUNTRY)); + EXPECT_EQ(AutofillProfile::UNVALIDATED, + profile.GetValidityState(ADDRESS_HOME_STATE)); + EXPECT_EQ(AutofillProfile::UNVALIDATED, + profile.GetValidityState(ADDRESS_HOME_ZIP)); +} + TEST_F(AutofillAddressValidationTest, ValidateFullProfile_RuleNotAvailable) { // This is a profile with valid country code, but the rule is not available in // the ValidationTestDataSource. @@ -155,6 +169,18 @@ TEST_F(AutofillAddressValidationTest, ValidateAddress_AdminAreaNotExists) { EXPECT_EQ(AutofillProfile::VALID, profile.GetValidityState(ADDRESS_HOME_ZIP)); } +TEST_F(AutofillAddressValidationTest, ValidateAddress_EmptyAdminArea) { + AutofillProfile profile(autofill::test::GetFullValidProfile()); + profile.SetRawInfo(ADDRESS_HOME_STATE, base::UTF8ToUTF16("")); + + EXPECT_EQ(AutofillProfile::INVALID, ValidateAddressTest(&profile)); + EXPECT_EQ(AutofillProfile::VALID, + profile.GetValidityState(ADDRESS_HOME_COUNTRY)); + EXPECT_EQ(AutofillProfile::EMPTY, + profile.GetValidityState(ADDRESS_HOME_STATE)); + EXPECT_EQ(AutofillProfile::VALID, profile.GetValidityState(ADDRESS_HOME_ZIP)); +} + TEST_F(AutofillAddressValidationTest, ValidateAddress_AdminAreaFullName) { const std::string admin_area = "Quebec"; AutofillProfile profile(autofill::test::GetFullValidProfile()); @@ -223,6 +249,32 @@ TEST_F(AutofillAddressValidationTest, ValidateAddress_InvalidZip) { profile.GetValidityState(ADDRESS_HOME_ZIP)); } +TEST_F(AutofillAddressValidationTest, ValidateAddress_EmptyZip) { + AutofillProfile profile(autofill::test::GetFullValidProfile()); + profile.SetRawInfo(ADDRESS_HOME_ZIP, base::UTF8ToUTF16("")); + + EXPECT_EQ(AutofillProfile::INVALID, ValidateAddressTest(&profile)); + EXPECT_EQ(AutofillProfile::VALID, + profile.GetValidityState(ADDRESS_HOME_COUNTRY)); + EXPECT_EQ(AutofillProfile::VALID, + profile.GetValidityState(ADDRESS_HOME_STATE)); + EXPECT_EQ(AutofillProfile::EMPTY, profile.GetValidityState(ADDRESS_HOME_ZIP)); +} + +TEST_F(AutofillAddressValidationTest, + ValidateFullProfile_EmptyCountryCodeAreaAndZip) { + AutofillProfile profile(autofill::test::GetFullValidProfile()); + profile.SetRawInfo(ADDRESS_HOME_COUNTRY, base::UTF8ToUTF16("")); + profile.SetRawInfo(ADDRESS_HOME_STATE, base::UTF8ToUTF16("")); + profile.SetRawInfo(ADDRESS_HOME_ZIP, base::UTF8ToUTF16("")); + EXPECT_EQ(AutofillProfile::INVALID, ValidateAddressTest(&profile)); + EXPECT_EQ(AutofillProfile::EMPTY, + profile.GetValidityState(ADDRESS_HOME_COUNTRY)); + EXPECT_EQ(AutofillProfile::EMPTY, + profile.GetValidityState(ADDRESS_HOME_STATE)); + EXPECT_EQ(AutofillProfile::EMPTY, profile.GetValidityState(ADDRESS_HOME_ZIP)); +} + // TODO(crbug/754727): add tests for a non-default language. // Ex: Nouveau-Brunswick for Canada. diff --git a/chromium/components/autofill/core/browser/autocomplete_history_manager.cc b/chromium/components/autofill/core/browser/autocomplete_history_manager.cc index ec5738c43a5..6683d0ea077 100644 --- a/chromium/components/autofill/core/browser/autocomplete_history_manager.cc +++ b/chromium/components/autofill/core/browser/autocomplete_history_manager.cc @@ -6,7 +6,6 @@ #include <vector> -#include "base/profiler/scoped_tracker.h" #include "base/strings/string16.h" #include "base/strings/utf_string_conversions.h" #include "components/autofill/core/browser/autofill_client.h" @@ -141,12 +140,6 @@ void AutocompleteHistoryManager::SendSuggestions( void AutocompleteHistoryManager::OnWebDataServiceRequestDone( WebDataServiceBase::Handle h, std::unique_ptr<WDTypedResult> result) { - // TODO(robliao): Remove ScopedTracker below once https://crbug.com/422460 is - // fixed. - tracked_objects::ScopedTracker tracking_profile( - FROM_HERE_WITH_EXPLICIT_FUNCTION( - "422460 AutocompleteHistoryManager::OnWebDataServiceRequestDone")); - DCHECK(pending_query_handle_); pending_query_handle_ = 0; diff --git a/chromium/components/autofill/core/browser/autofill_data_util.cc b/chromium/components/autofill/core/browser/autofill_data_util.cc index 784409dd086..7e0f53bba64 100644 --- a/chromium/components/autofill/core/browser/autofill_data_util.cc +++ b/chromium/components/autofill/core/browser/autofill_data_util.cc @@ -12,6 +12,8 @@ #include "base/strings/string_split.h" #include "base/strings/string_util.h" #include "base/strings/utf_string_conversions.h" +#include "components/autofill/core/browser/autofill_country.h" +#include "components/autofill/core/browser/autofill_profile.h" #include "components/autofill/core/browser/credit_card.h" #include "components/autofill/core/browser/field_types.h" #include "components/grit/components_scaled_resources.h" @@ -442,5 +444,14 @@ bool IsValidCountryCode(const base::string16& country_code) { return IsValidCountryCode(base::UTF16ToUTF8(country_code)); } +std::string GetCountryCodeWithFallback(const autofill::AutofillProfile* profile, + const std::string& app_locale) { + std::string country_code = + base::UTF16ToUTF8(profile->GetRawInfo(autofill::ADDRESS_HOME_COUNTRY)); + if (!IsValidCountryCode(country_code)) + country_code = AutofillCountry::CountryCodeForLocale(app_locale); + return country_code; +} + } // namespace data_util } // namespace autofill diff --git a/chromium/components/autofill/core/browser/autofill_data_util.h b/chromium/components/autofill/core/browser/autofill_data_util.h index 2e3d6fcb1a5..74c972ecdfc 100644 --- a/chromium/components/autofill/core/browser/autofill_data_util.h +++ b/chromium/components/autofill/core/browser/autofill_data_util.h @@ -9,9 +9,11 @@ #include "base/strings/string16.h" #include "base/strings/string_piece_forward.h" -#include "components/autofill/core/browser/autofill_profile.h" namespace autofill { + +class AutofillProfile; + namespace data_util { struct NameParts { @@ -66,6 +68,12 @@ const char* GetIssuerNetworkForBasicCardIssuerNetwork( bool IsValidCountryCode(const std::string& country_code); bool IsValidCountryCode(const base::string16& country_code); +// Returns a country code to be used when validating this profile. If the +// profile has a valid country code set, it is returned. If not, a country code +// associated with |app_locale| is used as a fallback. +std::string GetCountryCodeWithFallback(const autofill::AutofillProfile* profile, + const std::string& app_locale); + } // namespace data_util } // 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 1a66f8e59a4..d2de5151ec8 100644 --- a/chromium/components/autofill/core/browser/autofill_data_util_unittest.cc +++ b/chromium/components/autofill/core/browser/autofill_data_util_unittest.cc @@ -5,6 +5,7 @@ #include "components/autofill/core/browser/autofill_data_util.h" #include "base/strings/utf_string_conversions.h" +#include "components/autofill/core/browser/autofill_profile.h" #include "components/autofill/core/browser/autofill_test_utils.h" #include "testing/gtest/include/gtest/gtest.h" diff --git a/chromium/components/autofill/core/browser/autofill_experiments.cc b/chromium/components/autofill/core/browser/autofill_experiments.cc index e727dd6159e..33ce68a6b77 100644 --- a/chromium/components/autofill/core/browser/autofill_experiments.cc +++ b/chromium/components/autofill/core/browser/autofill_experiments.cc @@ -11,7 +11,6 @@ #include "base/strings/string_number_conversions.h" #include "base/strings/string_util.h" #include "base/strings/utf_string_conversions.h" -#include "base/time/time.h" #include "build/build_config.h" #include "components/autofill/core/browser/suggestion.h" #include "components/autofill/core/common/autofill_pref_names.h" @@ -25,16 +24,26 @@ namespace autofill { +const base::Feature kAutofillAlwaysFillAddresses{ + "AlwaysFillAddresses", base::FEATURE_ENABLED_BY_DEFAULT}; +const base::Feature kAutofillCreateDataForTest{ + "AutofillCreateDataForTest", base::FEATURE_DISABLED_BY_DEFAULT}; const base::Feature kAutofillCreditCardAssist{ "AutofillCreditCardAssist", base::FEATURE_DISABLED_BY_DEFAULT}; const base::Feature kAutofillScanCardholderName{ "AutofillScanCardholderName", base::FEATURE_DISABLED_BY_DEFAULT}; const base::Feature kAutofillCreditCardBankNameDisplay{ "AutofillCreditCardBankNameDisplay", base::FEATURE_DISABLED_BY_DEFAULT}; +const base::Feature kAutofillCreditCardAblationExperiment{ + "AutofillCreditCardAblationExperiment", base::FEATURE_DISABLED_BY_DEFAULT}; const base::Feature kAutofillCreditCardPopupLayout{ "AutofillCreditCardPopupLayout", base::FEATURE_DISABLED_BY_DEFAULT}; const base::Feature kAutofillCreditCardLastUsedDateDisplay{ "AutofillCreditCardLastUsedDateDisplay", base::FEATURE_DISABLED_BY_DEFAULT}; +const base::Feature kAutofillDeleteDisusedAddresses{ + "AutofillDeleteDisusedAddresses", base::FEATURE_DISABLED_BY_DEFAULT}; +const base::Feature kAutofillDeleteDisusedCreditCards{ + "AutofillDeleteDisusedCreditCards", base::FEATURE_DISABLED_BY_DEFAULT}; const base::Feature kAutofillOfferLocalSaveIfServerCardManuallyEntered{ "AutofillOfferLocalSaveIfServerCardManuallyEntered", base::FEATURE_DISABLED_BY_DEFAULT}; @@ -43,6 +52,10 @@ const base::Feature kAutofillRationalizeFieldTypePredictions{ base::FEATURE_ENABLED_BY_DEFAULT}; const base::Feature kAutofillSuppressDisusedAddresses{ "AutofillSuppressDisusedAddresses", base::FEATURE_DISABLED_BY_DEFAULT}; +const base::Feature kAutofillSuppressDisusedCreditCards{ + "AutofillSuppressDisusedCreditCards", base::FEATURE_DISABLED_BY_DEFAULT}; +const base::Feature kAutofillUpstreamAllowAllEmailDomains{ + "AutofillUpstreamAllowAllEmailDomains", base::FEATURE_DISABLED_BY_DEFAULT}; const base::Feature kAutofillUpstreamRequestCvcIfMissing{ "AutofillUpstreamRequestCvcIfMissing", base::FEATURE_DISABLED_BY_DEFAULT}; const base::Feature kAutofillUpstreamShowGoogleLogo{ @@ -51,9 +64,6 @@ const base::Feature kAutofillUpstreamShowNewUi{ "AutofillUpstreamShowNewUi", base::FEATURE_DISABLED_BY_DEFAULT}; const base::Feature kAutofillUpstreamUseAutofillProfileComparator{ "AutofillUpstreamUseAutofillProfileComparator", - base::FEATURE_ENABLED_BY_DEFAULT}; -const base::Feature kAutofillUpstreamUseNotRecentlyUsedAutofillProfile{ - "AutofillUpstreamUseNotRecentlyUsedAutofillProfile", base::FEATURE_DISABLED_BY_DEFAULT}; const char kCreditCardSigninPromoImpressionLimitParamKey[] = "impression_limit"; const char kAutofillCreditCardPopupBackgroundColorKey[] = "background_color"; @@ -67,8 +77,6 @@ const char kAutofillCreditCardPopupIsIconAtStartKey[] = const char kAutofillPopupMarginKey[] = "margin"; const char kAutofillCreditCardLastUsedDateShowExpirationDateKey[] = "show_expiration_date"; -const char kAutofillUpstreamMaxMinutesSinceAutofillProfileUseKey[] = - "max_minutes_since_autofill_profile_use"; #if defined(OS_MACOSX) const base::Feature kCreditCardAutofillTouchBar{ @@ -238,8 +246,12 @@ bool IsCreditCardUploadEnabled(const PrefService* pref_service, if (user_email.empty()) return false; std::string domain = gaia::ExtractDomainName(user_email); - if (!(domain == "googlemail.com" || domain == "gmail.com" || - domain == "google.com")) { + // If the "allow all email domains" flag is off, restrict credit card upload + // only to Google Accounts with @googlemail, @gmail, @google, or @chromium + // domains. + if (!base::FeatureList::IsEnabled(kAutofillUpstreamAllowAllEmailDomains) && + !(domain == "googlemail.com" || domain == "gmail.com" || + domain == "google.com" || domain == "chromium.org")) { return false; } @@ -286,16 +298,6 @@ bool IsAutofillUpstreamShowNewUiExperimentEnabled() { #endif } -base::TimeDelta GetMaxTimeSinceAutofillProfileUseForCardUpload() { - int value; - const std::string param_value = variations::GetVariationParamValueByFeature( - kAutofillUpstreamUseNotRecentlyUsedAutofillProfile, - kAutofillUpstreamMaxMinutesSinceAutofillProfileUseKey); - if (!param_value.empty() && base::StringToInt(param_value, &value)) - return base::TimeDelta::FromMinutes(value); - return base::TimeDelta(); -} - #if defined(OS_MACOSX) bool IsCreditCardAutofillTouchBarExperimentEnabled() { return base::FeatureList::IsEnabled(kCreditCardAutofillTouchBar); diff --git a/chromium/components/autofill/core/browser/autofill_experiments.h b/chromium/components/autofill/core/browser/autofill_experiments.h index 6fcc5168320..d00394042c9 100644 --- a/chromium/components/autofill/core/browser/autofill_experiments.h +++ b/chromium/components/autofill/core/browser/autofill_experiments.h @@ -8,7 +8,6 @@ #include <string> #include "base/strings/string16.h" -#include "base/time/time.h" #include "build/build_config.h" #include "third_party/skia/include/core/SkColor.h" @@ -26,19 +25,25 @@ namespace autofill { struct Suggestion; +extern const base::Feature kAutofillAlwaysFillAddresses; +extern const base::Feature kAutofillCreateDataForTest; extern const base::Feature kAutofillCreditCardAssist; extern const base::Feature kAutofillScanCardholderName; +extern const base::Feature kAutofillCreditCardAblationExperiment; extern const base::Feature kAutofillCreditCardBankNameDisplay; extern const base::Feature kAutofillCreditCardPopupLayout; extern const base::Feature kAutofillCreditCardLastUsedDateDisplay; +extern const base::Feature kAutofillDeleteDisusedAddresses; +extern const base::Feature kAutofillDeleteDisusedCreditCards; extern const base::Feature kAutofillOfferLocalSaveIfServerCardManuallyEntered; extern const base::Feature kAutofillRationalizeFieldTypePredictions; extern const base::Feature kAutofillSuppressDisusedAddresses; +extern const base::Feature kAutofillSuppressDisusedCreditCards; +extern const base::Feature kAutofillUpstreamAllowAllEmailDomains; extern const base::Feature kAutofillUpstreamRequestCvcIfMissing; extern const base::Feature kAutofillUpstreamShowGoogleLogo; extern const base::Feature kAutofillUpstreamShowNewUi; extern const base::Feature kAutofillUpstreamUseAutofillProfileComparator; -extern const base::Feature kAutofillUpstreamUseNotRecentlyUsedAutofillProfile; extern const char kCreditCardSigninPromoImpressionLimitParamKey[]; extern const char kAutofillCreditCardLastUsedDateShowExpirationDateKey[]; extern const char kAutofillUpstreamMaxMinutesSinceAutofillProfileUseKey[]; @@ -136,11 +141,6 @@ bool IsAutofillUpstreamShowGoogleLogoExperimentEnabled(); // new save card bubble/infobar design. bool IsAutofillUpstreamShowNewUiExperimentEnabled(); -// Returns the maximum time that could have elapsed since an address profile's -// most recent use for the adress profile to be included in the candidate set -// for card upload. Returns 0 if the experiment is not enabled. -base::TimeDelta GetMaxTimeSinceAutofillProfileUseForCardUpload(); - #if defined(OS_MACOSX) // Returns whether the Credit Card Autofill Touch Bar experiment is enabled. bool IsCreditCardAutofillTouchBarExperimentEnabled(); diff --git a/chromium/components/autofill/core/browser/autofill_experiments_unittest.cc b/chromium/components/autofill/core/browser/autofill_experiments_unittest.cc new file mode 100644 index 00000000000..ef45b490b98 --- /dev/null +++ b/chromium/components/autofill/core/browser/autofill_experiments_unittest.cc @@ -0,0 +1,181 @@ +// 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_experiments.h" + +#include "base/test/scoped_command_line.h" +#include "base/test/scoped_feature_list.h" +#include "components/autofill/core/common/autofill_pref_names.h" +#include "components/autofill/core/common/autofill_switches.h" +#include "components/prefs/pref_registry_simple.h" +#include "components/prefs/testing_pref_service.h" +#include "components/sync/driver/fake_sync_service.h" +#include "testing/gtest/include/gtest/gtest.h" + +namespace autofill { + +namespace { + +class TestSyncService : public syncer::FakeSyncService { + public: + TestSyncService() + : can_sync_start_(true), + preferred_data_types_(syncer::ModelTypeSet::All()), + is_engine_initialized_(true), + is_using_secondary_passphrase_(false) {} + + bool CanSyncStart() const override { return can_sync_start_; } + + syncer::ModelTypeSet GetPreferredDataTypes() const override { + return preferred_data_types_; + } + + bool IsEngineInitialized() const override { return is_engine_initialized_; } + + bool IsUsingSecondaryPassphrase() const override { + return is_using_secondary_passphrase_; + } + + void SetCanSyncStart(bool can_sync_start) { + can_sync_start_ = can_sync_start; + } + + void SetPreferredDataTypes(syncer::ModelTypeSet preferred_data_types) { + preferred_data_types_ = preferred_data_types; + } + + void SetIsEngineInitialized(bool is_engine_initialized) { + is_engine_initialized_ = is_engine_initialized; + } + + void SetIsUsingSecondaryPassphrase(bool is_using_secondary_passphrase) { + is_using_secondary_passphrase_ = is_using_secondary_passphrase; + } + + private: + bool can_sync_start_; + syncer::ModelTypeSet preferred_data_types_; + bool is_engine_initialized_; + bool is_using_secondary_passphrase_; +}; + +} // namespace + +class AutofillExperimentsTest : public testing::Test { + public: + AutofillExperimentsTest() {} + + protected: + void SetUp() override { + pref_service_.registry()->RegisterBooleanPref( + prefs::kAutofillWalletImportEnabled, true); + } + + bool IsCreditCardUploadEnabled() { + return IsCreditCardUploadEnabled("john.smith@gmail.com", "Default"); + } + + bool IsCreditCardUploadEnabled(const std::string& user_email) { + return IsCreditCardUploadEnabled(user_email, "Default"); + } + + bool IsCreditCardUploadEnabled(const std::string& user_email, + const std::string& field_trial_value) { + base::FieldTrialList field_trial_list(nullptr); + base::FieldTrialList::CreateFieldTrial("OfferUploadCreditCards", + field_trial_value); + + return autofill::IsCreditCardUploadEnabled(&pref_service_, &sync_service_, + user_email); + } + + base::test::ScopedFeatureList scoped_feature_list_; + TestingPrefServiceSimple pref_service_; + TestSyncService sync_service_; +}; + +TEST_F(AutofillExperimentsTest, DenyUpload_SyncServiceCannotStart) { + sync_service_.SetCanSyncStart(false); + EXPECT_FALSE(IsCreditCardUploadEnabled()); +} + +TEST_F(AutofillExperimentsTest, + DenyUpload_SyncServiceDoesNotHaveAutofillProfilePreferredDataType) { + sync_service_.SetPreferredDataTypes(syncer::ModelTypeSet()); + EXPECT_FALSE(IsCreditCardUploadEnabled()); +} + +TEST_F(AutofillExperimentsTest, DenyUpload_SyncServiceEngineNotInitialized) { + sync_service_.SetIsEngineInitialized(false); + EXPECT_FALSE(IsCreditCardUploadEnabled()); +} + +TEST_F(AutofillExperimentsTest, + DenyUpload_SyncServiceUsingSecondaryPassphrase) { + sync_service_.SetIsUsingSecondaryPassphrase(true); + EXPECT_FALSE(IsCreditCardUploadEnabled()); +} + +TEST_F(AutofillExperimentsTest, + DenyUpload_AutofillWalletImportEnabledPrefIsDisabled) { + pref_service_.SetBoolean(prefs::kAutofillWalletImportEnabled, false); + EXPECT_FALSE(IsCreditCardUploadEnabled()); +} + +TEST_F(AutofillExperimentsTest, DenyUpload_EmptyUserEmail) { + EXPECT_FALSE(IsCreditCardUploadEnabled("")); +} + +TEST_F(AutofillExperimentsTest, AllowUpload_UserEmailWithGoogleDomain) { + EXPECT_TRUE(IsCreditCardUploadEnabled("john.smith@gmail.com")); + EXPECT_TRUE(IsCreditCardUploadEnabled("googler@google.com")); + EXPECT_TRUE(IsCreditCardUploadEnabled("old.school@googlemail.com")); + EXPECT_TRUE(IsCreditCardUploadEnabled("code.committer@chromium.org")); +} + +TEST_F(AutofillExperimentsTest, DenyUpload_UserEmailWithNonGoogleDomain) { + EXPECT_FALSE(IsCreditCardUploadEnabled("cool.user@hotmail.com")); + EXPECT_FALSE(IsCreditCardUploadEnabled("john.smith@johnsmith.com")); + EXPECT_FALSE(IsCreditCardUploadEnabled("fake.googler@google.net")); + EXPECT_FALSE(IsCreditCardUploadEnabled("fake.committer@chromium.com")); +} + +TEST_F(AutofillExperimentsTest, + AllowUpload_UserEmailWithNonGoogleDomainIfExperimentEnabled) { + scoped_feature_list_.InitAndEnableFeature( + kAutofillUpstreamAllowAllEmailDomains); + EXPECT_TRUE(IsCreditCardUploadEnabled("cool.user@hotmail.com")); + EXPECT_TRUE(IsCreditCardUploadEnabled("john.smith@johnsmith.com")); + EXPECT_TRUE(IsCreditCardUploadEnabled("fake.googler@google.net")); + EXPECT_TRUE(IsCreditCardUploadEnabled("fake.committer@chromium.com")); +} + +TEST_F(AutofillExperimentsTest, + AllowUpload_CommandLineSwitchOnEvenIfGroupDisabled) { + base::test::ScopedCommandLine scoped_command_line; + scoped_command_line.GetProcessCommandLine()->AppendSwitch( + switches::kEnableOfferUploadCreditCards); + EXPECT_TRUE(IsCreditCardUploadEnabled("john.smith@gmail.com", "Disabled")); +} + +TEST_F(AutofillExperimentsTest, DenyUpload_CommandLineSwitchOff) { + base::test::ScopedCommandLine scoped_command_line; + scoped_command_line.GetProcessCommandLine()->AppendSwitch( + switches::kDisableOfferUploadCreditCards); + EXPECT_FALSE(IsCreditCardUploadEnabled()); +} + +TEST_F(AutofillExperimentsTest, DenyUpload_GroupNameEmpty) { + EXPECT_FALSE(IsCreditCardUploadEnabled("john.smith@gmail.com", "")); +} + +TEST_F(AutofillExperimentsTest, DenyUpload_GroupNameDisabled) { + EXPECT_FALSE(IsCreditCardUploadEnabled("john.smith@gmail.com", "Disabled")); +} + +TEST_F(AutofillExperimentsTest, DenyUpload_GroupNameAnythingButDisabled) { + EXPECT_TRUE(IsCreditCardUploadEnabled("john.smith@gmail.com", "Enabled")); +} + +} // namespace autofill diff --git a/chromium/components/autofill/core/browser/autofill_field.cc b/chromium/components/autofill/core/browser/autofill_field.cc index af0cddb0fea..eaab80bf791 100644 --- a/chromium/components/autofill/core/browser/autofill_field.cc +++ b/chromium/components/autofill/core/browser/autofill_field.cc @@ -7,6 +7,7 @@ #include <stdint.h> #include "base/command_line.h" +#include "base/feature_list.h" #include "base/i18n/case_conversion.h" #include "base/i18n/string_search.h" #include "base/logging.h" @@ -16,6 +17,7 @@ #include "base/strings/string_util.h" #include "base/strings/utf_string_conversions.h" #include "components/autofill/core/browser/autofill_country.h" +#include "components/autofill/core/browser/autofill_experiments.h" #include "components/autofill/core/browser/autofill_type.h" #include "components/autofill/core/browser/country_names.h" #include "components/autofill/core/browser/credit_card.h" @@ -198,15 +200,18 @@ bool FillExpirationMonthSelectControl(const base::string16& value, if (!StringToInt(value, &month) || month <= 0 || month > 12) return false; - // We trim the whitespace and a specific prefix used in AngularJS from the + // Trim the whitespace and specific prefixes used in AngularJS from the // select values before attempting to convert them to months. std::vector<base::string16> trimmed_values(field->option_values.size()); const base::string16 kNumberPrefix = ASCIIToUTF16("number:"); + const base::string16 kStringPrefix = ASCIIToUTF16("string:"); for (size_t i = 0; i < field->option_values.size(); ++i) { base::TrimWhitespace(field->option_values[i], base::TRIM_ALL, &trimmed_values[i]); base::ReplaceFirstSubstringAfterOffset(&trimmed_values[i], 0, kNumberPrefix, ASCIIToUTF16("")); + base::ReplaceFirstSubstringAfterOffset(&trimmed_values[i], 0, kStringPrefix, + ASCIIToUTF16("")); } if (trimmed_values.size() == 12) { @@ -535,7 +540,7 @@ base::string16 RemoveWhitespace(const base::string16& value) { } // namespace AutofillField::AutofillField() - : server_type_(NO_SERVER_DATA), + : overall_server_type_(NO_SERVER_DATA), heuristic_type_(UNKNOWN_TYPE), html_type_(HTML_TYPE_UNSPECIFIED), html_mode_(HTML_MODE_NONE), @@ -551,7 +556,7 @@ AutofillField::AutofillField(const FormFieldData& field, const base::string16& unique_name) : FormFieldData(field), unique_name_(unique_name), - server_type_(NO_SERVER_DATA), + overall_server_type_(NO_SERVER_DATA), heuristic_type_(UNKNOWN_TYPE), html_type_(HTML_TYPE_UNSPECIFIED), html_mode_(HTML_MODE_NONE), @@ -578,12 +583,12 @@ void AutofillField::set_heuristic_type(ServerFieldType type) { } } -void AutofillField::set_server_type(ServerFieldType type) { +void AutofillField::set_overall_server_type(ServerFieldType type) { // Chrome no longer supports fax numbers, but the server still does. if (type >= PHONE_FAX_NUMBER && type <= PHONE_FAX_WHOLE_NUMBER) return; - server_type_ = type; + overall_server_type_ = type; } void AutofillField::SetHtmlType(HtmlFieldType type, HtmlFieldMode mode) { @@ -601,11 +606,11 @@ void AutofillField::SetHtmlType(HtmlFieldType type, HtmlFieldMode mode) { void AutofillField::SetTypeTo(ServerFieldType type) { if (type == UNKNOWN_TYPE || type == NO_SERVER_DATA) { heuristic_type_ = UNKNOWN_TYPE; - server_type_ = NO_SERVER_DATA; - } else if (server_type_ == NO_SERVER_DATA) { + overall_server_type_ = NO_SERVER_DATA; + } else if (overall_server_type_ == NO_SERVER_DATA) { heuristic_type_ = type; } else { - server_type_ = type; + overall_server_type_ = type; } } @@ -617,26 +622,26 @@ AutofillType AutofillField::Type() const { return AutofillType(html_type_, html_mode_); } - if (server_type_ != NO_SERVER_DATA) { + if (overall_server_type_ != NO_SERVER_DATA) { // See http://crbug.com/429236 for background on why we might not always // believe the server. // TODO(http://crbug.com/589129) investigate how well the server is doing in // regard to credit card predictions. bool believe_server = - !(server_type_ == NAME_FULL && + !(overall_server_type_ == NAME_FULL && heuristic_type_ == CREDIT_CARD_NAME_FULL) && - !(server_type_ == CREDIT_CARD_NAME_FULL && + !(overall_server_type_ == CREDIT_CARD_NAME_FULL && heuristic_type_ == NAME_FULL) && - !(server_type_ == NAME_FIRST && + !(overall_server_type_ == NAME_FIRST && heuristic_type_ == CREDIT_CARD_NAME_FIRST) && - !(server_type_ == NAME_LAST && + !(overall_server_type_ == NAME_LAST && heuristic_type_ == CREDIT_CARD_NAME_LAST) && // CVC is sometimes type="password", which tricks the server. // See http://crbug.com/469007 - !(AutofillType(server_type_).group() == PASSWORD_FIELD && + !(AutofillType(overall_server_type_).group() == PASSWORD_FIELD && heuristic_type_ == CREDIT_CARD_VERIFICATION_CODE); if (believe_server) - return AutofillType(server_type_); + return AutofillType(overall_server_type_); } return AutofillType(heuristic_type_); @@ -668,7 +673,8 @@ bool AutofillField::FillFormField(const AutofillField& field, // Don't fill if autocomplete=off is set on |field| on desktop for non credit // card related fields. - if (!field.should_autocomplete && IsDesktopPlatform() && + if (!base::FeatureList::IsEnabled(kAutofillAlwaysFillAddresses) && + !field.should_autocomplete && IsDesktopPlatform() && (type.group() != CREDIT_CARD)) { return false; } @@ -778,7 +784,7 @@ int AutofillField::FindShortestSubstringMatchInSelect( } bool AutofillField::IsCreditCardPrediction() const { - return AutofillType(server_type_).group() == CREDIT_CARD || + return AutofillType(overall_server_type_).group() == CREDIT_CARD || AutofillType(heuristic_type_).group() == CREDIT_CARD; } diff --git a/chromium/components/autofill/core/browser/autofill_field.h b/chromium/components/autofill/core/browser/autofill_field.h index edfb606627b..8d4438ace13 100644 --- a/chromium/components/autofill/core/browser/autofill_field.h +++ b/chromium/components/autofill/core/browser/autofill_field.h @@ -36,7 +36,11 @@ class AutofillField : public FormFieldData { const std::string& section() const { return section_; } ServerFieldType heuristic_type() const { return heuristic_type_; } - ServerFieldType server_type() const { return server_type_; } + ServerFieldType overall_server_type() const { return overall_server_type_; } + const std::vector<AutofillQueryResponseContents::Field::FieldPrediction>& + server_predictions() const { + return server_predictions_; + } HtmlFieldType html_type() const { return html_type_; } HtmlFieldMode html_mode() const { return html_mode_; } const ServerFieldTypeSet& possible_types() const { return possible_types_; } @@ -47,7 +51,12 @@ class AutofillField : public FormFieldData { // Setters for the detected type and section for this field. void set_section(const std::string& section) { section_ = section; } void set_heuristic_type(ServerFieldType type); - void set_server_type(ServerFieldType type); + void set_overall_server_type(ServerFieldType type); + void set_server_predictions( + const std::vector<AutofillQueryResponseContents::Field::FieldPrediction> + predictions) { + server_predictions_ = std::move(predictions); + } void set_possible_types(const ServerFieldTypeSet& possible_types) { possible_types_ = possible_types; } @@ -159,7 +168,12 @@ class AutofillField : public FormFieldData { std::string section_; // The type of the field, as determined by the Autofill server. - ServerFieldType server_type_; + ServerFieldType overall_server_type_; + + // The possible types of the field, as determined by the Autofill server, + // including |overall_server_type_| as the first item. + std::vector<AutofillQueryResponseContents::Field::FieldPrediction> + server_predictions_; // The type of the field, as determined by the local heuristics. ServerFieldType heuristic_type_; diff --git a/chromium/components/autofill/core/browser/autofill_field_unittest.cc b/chromium/components/autofill/core/browser/autofill_field_unittest.cc index ef6b2e87bea..1d30b269d7e 100644 --- a/chromium/components/autofill/core/browser/autofill_field_unittest.cc +++ b/chromium/components/autofill/core/browser/autofill_field_unittest.cc @@ -10,6 +10,8 @@ #include "base/strings/string_number_conversions.h" #include "base/strings/string_util.h" #include "base/strings/utf_string_conversions.h" +#include "base/test/scoped_feature_list.h" +#include "components/autofill/core/browser/autofill_experiments.h" #include "components/autofill/core/browser/autofill_test_utils.h" #include "components/autofill/core/browser/autofill_type.h" #include "components/autofill/core/browser/country_names.h" @@ -118,7 +120,7 @@ class AutofillFieldTest : public testing::Test { TEST_F(AutofillFieldTest, Type) { AutofillField field; - ASSERT_EQ(NO_SERVER_DATA, field.server_type()); + ASSERT_EQ(NO_SERVER_DATA, field.overall_server_type()); ASSERT_EQ(UNKNOWN_TYPE, field.heuristic_type()); // |server_type_| is NO_SERVER_DATA, so |heuristic_type_| is returned. @@ -130,12 +132,12 @@ TEST_F(AutofillFieldTest, Type) { EXPECT_EQ(NAME, field.Type().group()); // Set the server type and check it. - field.set_server_type(ADDRESS_BILLING_LINE1); + field.set_overall_server_type(ADDRESS_BILLING_LINE1); EXPECT_EQ(ADDRESS_HOME_LINE1, field.Type().GetStorableType()); EXPECT_EQ(ADDRESS_BILLING, field.Type().group()); // Remove the server type to make sure the heuristic type is preserved. - field.set_server_type(NO_SERVER_DATA); + field.set_overall_server_type(NO_SERVER_DATA); EXPECT_EQ(NAME_FIRST, field.Type().GetStorableType()); EXPECT_EQ(NAME, field.Type().group()); } @@ -171,18 +173,18 @@ TEST_F(AutofillFieldTest, Type_CreditCardOverrideHtml_ServerPredicitons) { field.SetHtmlType(HTML_TYPE_UNRECOGNIZED, HTML_MODE_NONE); // A credit card server prediction overrides the unrecognized type. - field.set_server_type(CREDIT_CARD_NUMBER); + field.set_overall_server_type(CREDIT_CARD_NUMBER); EXPECT_EQ(CREDIT_CARD_NUMBER, field.Type().GetStorableType()); // A non credit card server prediction doesn't override the unrecognized // type. - field.set_server_type(NAME_FIRST); + field.set_overall_server_type(NAME_FIRST); EXPECT_EQ(UNKNOWN_TYPE, field.Type().GetStorableType()); // A credit card server prediction doesn't override a known specified html // type. field.SetHtmlType(HTML_TYPE_NAME, HTML_MODE_NONE); - field.set_server_type(CREDIT_CARD_NUMBER); + field.set_overall_server_type(CREDIT_CARD_NUMBER); EXPECT_EQ(NAME_FULL, field.Type().GetStorableType()); } @@ -219,7 +221,7 @@ TEST_F(AutofillFieldTest, FieldSignatureAsStr) { EXPECT_EQ("502192749", field.FieldSignatureAsStr()); // Server type does not affect FieldSignature. - field.set_server_type(NAME_LAST); + field.set_overall_server_type(NAME_LAST); EXPECT_EQ("502192749", field.FieldSignatureAsStr()); } @@ -236,12 +238,12 @@ TEST_F(AutofillFieldTest, IsFieldFillable) { // Only server type is set. field.set_heuristic_type(UNKNOWN_TYPE); - field.set_server_type(NAME_LAST); + field.set_overall_server_type(NAME_LAST); EXPECT_TRUE(field.IsFieldFillable()); // Both types set. field.set_heuristic_type(NAME_FIRST); - field.set_server_type(NAME_LAST); + field.set_overall_server_type(NAME_LAST); EXPECT_TRUE(field.IsFieldFillable()); // Field has autocomplete="off" set. Since autofill was able to make a @@ -251,8 +253,12 @@ TEST_F(AutofillFieldTest, IsFieldFillable) { } // Verify that non credit card related fields with the autocomplete attribute -// set to off don't get filled on desktop. -TEST_F(AutofillFieldTest, FillFormField_AutocompleteOff_AddressField) { +// set to off don't get filled on desktop when the feature to Autofill all +// addresses is disabled. +TEST_F(AutofillFieldTest, FillFormField_AutocompleteOffRespected_AddressField) { + base::test::ScopedFeatureList feature_list; + feature_list.InitAndDisableFeature(kAutofillAlwaysFillAddresses); + AutofillField field; field.should_autocomplete = false; @@ -260,7 +266,7 @@ TEST_F(AutofillFieldTest, FillFormField_AutocompleteOff_AddressField) { AutofillField::FillFormField(field, ASCIIToUTF16("Test"), "en-US", "en-US", &field); - // Verifiy that the field is filled on mobile but not on desktop. + // Verify that the field is filled on mobile but not on desktop. if (IsDesktopPlatform()) { EXPECT_EQ(base::string16(), field.value); } else { @@ -268,6 +274,22 @@ TEST_F(AutofillFieldTest, FillFormField_AutocompleteOff_AddressField) { } } +// Verify that non credit card related fields with the autocomplete attribute +// set to off are filled on desktop when the feature to Autofill all +// addresses is enabled (default). +TEST_F(AutofillFieldTest, + FillFormField_AutocompleteOffNotRespected_AddressField) { + AutofillField field; + field.should_autocomplete = false; + + // Non credit card related field. + AutofillField::FillFormField(field, ASCIIToUTF16("Test"), "en-US", "en-US", + &field); + + // Verify that the field is filled in all circumstances. + EXPECT_EQ(ASCIIToUTF16("Test"), field.value); +} + // Verify that credit card related fields with the autocomplete attribute // set to off get filled. TEST_F(AutofillFieldTest, FillFormField_AutocompleteOff_CreditCardField) { @@ -683,13 +705,18 @@ INSTANTIATE_TEST_CASE_P( {"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. + // The AngularJS framework can add a "number:" prefix to select values. 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()}, + // The AngularJS framework can add a "string:" prefix to select values. + FillWithExpirationMonthTestCase{ + {"string:1", "string:2", "string:3", "string:4", "string:5", + "string:6", "string:7", "string:8", "string:9", "string:10", + "string:11", "string: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", @@ -739,7 +766,7 @@ TEST_F(AutofillFieldTest, FillSelectControlWithAbbreviatedMonthName) { EXPECT_EQ(ASCIIToUTF16("Apr"), field.value); } -TEST_F(AutofillFieldTest, FillSelectControlWithFullMonthName) { +TEST_F(AutofillFieldTest, FillSelectControlWithMonthName) { std::vector<const char*> kMonthsFull = { "January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December", @@ -753,7 +780,49 @@ TEST_F(AutofillFieldTest, FillSelectControlWithFullMonthName) { EXPECT_EQ(ASCIIToUTF16("April"), field.value); } -TEST_F(AutofillFieldTest, FillSelectControlWithFrenchMonthName) { +TEST_F(AutofillFieldTest, FillSelectControlWithMonthNameAndDigits) { + std::vector<const char*> kMonthsFullWithDigits = { + "January (01)", "February (02)", "March (03)", "April (04)", + "May (05)", "June (06)", "July (07)", "August (08)", + "September (09)", "October (10)", "November (11)", "December (12)", + }; + AutofillField field; + test::CreateTestSelectField(kMonthsFullWithDigits, &field); + field.set_heuristic_type(CREDIT_CARD_EXP_MONTH); + + AutofillField::FillFormField(field, ASCIIToUTF16("04"), "en-US", "en-US", + &field); + EXPECT_EQ(ASCIIToUTF16("April (04)"), field.value); +} + +TEST_F(AutofillFieldTest, FillSelectControlWithMonthNameAndDigits_French) { + std::vector<const char*> kMonthsFullWithDigits = { + "01 - JANVIER", + "02 - FÉVRIER", + "03 - MARS", + "04 - AVRIL", + "05 - MAI", + "06 - JUIN", + "07 - JUILLET", + "08 - AOÛT", + "09 - SEPTEMBRE", + "10 - OCTOBRE", + "11 - NOVEMBRE", + "12 - DECEMBRE" /* Intentionally not including accent in DÉCEMBRE */, + }; + AutofillField field; + test::CreateTestSelectField(kMonthsFullWithDigits, &field); + field.set_heuristic_type(CREDIT_CARD_EXP_MONTH); + + AutofillField::FillFormField(field, ASCIIToUTF16("08"), "fr-FR", "fr-FR", + &field); + EXPECT_EQ(UTF8ToUTF16("08 - AOÛT"), field.value); + AutofillField::FillFormField(field, ASCIIToUTF16("12"), "fr-FR", "fr-FR", + &field); + EXPECT_EQ(UTF8ToUTF16("12 - DECEMBRE"), field.value); +} + +TEST_F(AutofillFieldTest, FillSelectControlWithMonthName_French) { std::vector<const char*> kMonthsFrench = {"JANV", "FÉVR.", "MARS", "décembre"}; AutofillField field; @@ -873,7 +942,7 @@ TEST_F(AutofillFieldTest, FillStreetAddressTextArea) { TEST_F(AutofillFieldTest, FillStreetAddressTextField) { AutofillField field; field.form_control_type = "text"; - field.set_server_type(ADDRESS_HOME_STREET_ADDRESS); + field.set_overall_server_type(ADDRESS_HOME_STREET_ADDRESS); base::string16 value = ASCIIToUTF16("123 Fake St.\n" "Apt. 42"); diff --git a/chromium/components/autofill/core/browser/autofill_manager.cc b/chromium/components/autofill/core/browser/autofill_manager.cc index 31143c2309a..01583656d21 100644 --- a/chromium/components/autofill/core/browser/autofill_manager.cc +++ b/chromium/components/autofill/core/browser/autofill_manager.cc @@ -33,7 +33,6 @@ #include "base/strings/utf_string_conversions.h" #include "base/task_scheduler/post_task.h" #include "base/threading/thread_restrictions.h" -#include "base/time/time.h" #include "build/build_config.h" #include "components/autofill/core/browser/autocomplete_history_manager.h" #include "components/autofill/core/browser/autofill_client.h" @@ -248,6 +247,7 @@ AutofillManager::AutofillManager( found_cvc_field_(false), found_value_in_cvc_field_(false), found_cvc_value_in_non_cvc_field_(false), + enable_ablation_logging_(false), external_delegate_(NULL), test_delegate_(NULL), #if defined(OS_ANDROID) || defined(OS_IOS) @@ -275,8 +275,7 @@ void AutofillManager::RegisterProfilePrefs( registry->RegisterIntegerPref( prefs::kAutofillCreditCardSigninPromoImpressionCount, 0); registry->RegisterBooleanPref( - prefs::kAutofillEnabled, - true, + prefs::kAutofillEnabled, true, user_prefs::PrefRegistrySyncable::SYNCABLE_PREF); registry->RegisterBooleanPref( prefs::kAutofillProfileUseDatesFixed, false, @@ -284,6 +283,9 @@ void AutofillManager::RegisterProfilePrefs( registry->RegisterIntegerPref( prefs::kAutofillLastVersionDeduped, 0, user_prefs::PrefRegistrySyncable::SYNCABLE_PREF); + registry->RegisterIntegerPref( + prefs::kAutofillLastVersionDisusedAddressesDeleted, 0, + user_prefs::PrefRegistrySyncable::SYNCABLE_PREF); // These choices are made on a per-device basis, so they're not syncable. registry->RegisterBooleanPref(prefs::kAutofillWalletImportEnabled, true); registry->RegisterBooleanPref( @@ -291,6 +293,9 @@ void AutofillManager::RegisterProfilePrefs( registry->RegisterIntegerPref( prefs::kAutofillAcceptSaveCreditCardPromptState, prefs::PREVIOUS_SAVE_CREDIT_CARD_PROMPT_USER_DECISION_NONE); + registry->RegisterIntegerPref( + prefs::kAutofillLastVersionDisusedCreditCardsDeleted, 0); + registry->RegisterBooleanPref(prefs::kAutofillCreditCardEnabled, true); } void AutofillManager::SetExternalDelegate(AutofillExternalDelegate* delegate) { @@ -411,7 +416,8 @@ bool AutofillManager::OnWillSubmitFormImpl(const FormData& form, autocomplete_history_manager_->OnWillSubmitForm(form_for_autocomplete); address_form_event_logger_->OnWillSubmitForm(); - credit_card_form_event_logger_->OnWillSubmitForm(); + if (IsCreditCardAutofillEnabled()) + credit_card_form_event_logger_->OnWillSubmitForm(); StartUploadProcess(std::move(submitted_form), timestamp, true); @@ -428,8 +434,18 @@ bool AutofillManager::OnFormSubmitted(const FormData& form) { return false; } - address_form_event_logger_->OnFormSubmitted(); - credit_card_form_event_logger_->OnFormSubmitted(); + CreditCard credit_card = + personal_data_->ExtractCreditCardFromForm(*submitted_form); + if (IsValidCreditCardNumber(credit_card.number())) { + credit_card_form_event_logger_->DetectedCardInSubmittedForm(); + if (personal_data_->IsKnownCard(credit_card)) { + credit_card_form_event_logger_->SubmittedKnownCard(); + } + } + + address_form_event_logger_->OnFormSubmitted(/*force_logging=*/false); + if (IsCreditCardAutofillEnabled()) + credit_card_form_event_logger_->OnFormSubmitted(enable_ablation_logging_); // Update Personal Data with the form's submitted data. if (submitted_form->IsAutofillable()) @@ -531,19 +547,22 @@ void AutofillManager::OnTextFieldDidChangeImpl(const FormData& form, if (!user_did_type_) { user_did_type_ = true; - AutofillMetrics::LogUserHappinessMetric(AutofillMetrics::USER_DID_TYPE); + AutofillMetrics::LogUserHappinessMetric(AutofillMetrics::USER_DID_TYPE, + autofill_field->Type().group()); } if (autofill_field->is_autofilled) { autofill_field->is_autofilled = false; autofill_field->set_previously_autofilled(true); AutofillMetrics::LogUserHappinessMetric( - AutofillMetrics::USER_DID_EDIT_AUTOFILLED_FIELD); + AutofillMetrics::USER_DID_EDIT_AUTOFILLED_FIELD, + autofill_field->Type().group()); if (!user_did_edit_autofilled_field_) { user_did_edit_autofilled_field_ = true; AutofillMetrics::LogUserHappinessMetric( - AutofillMetrics::USER_DID_EDIT_AUTOFILLED_FIELD_ONCE); + AutofillMetrics::USER_DID_EDIT_AUTOFILLED_FIELD_ONCE, + autofill_field->Type().group()); } } @@ -597,8 +616,10 @@ void AutofillManager::OnQueryFormFieldAutofillImpl( if (is_autofill_possible && driver()->RendererIsAvailable() && got_autofillable_form) { // On desktop, don't return non credit card related suggestions for forms or - // fields that have the "autocomplete" attribute set to off. - if (IsDesktopPlatform() && !is_filling_credit_card && + // fields that have the "autocomplete" attribute set to off, only if the + // feature to always fill addresses is off. + if (!base::FeatureList::IsEnabled(kAutofillAlwaysFillAddresses) && + IsDesktopPlatform() && !is_filling_credit_card && !field.should_autocomplete) { return; } @@ -609,6 +630,16 @@ void AutofillManager::OnQueryFormFieldAutofillImpl( GetProfileSuggestions(*form_structure, field, *autofill_field); } + // Logic for disabling/ablating credit card autofill. + if (base::FeatureList::IsEnabled(kAutofillCreditCardAblationExperiment) && + is_filling_credit_card && !suggestions.empty()) { + suggestions.clear(); + autocomplete_history_manager_->CancelPendingQuery(); + external_delegate_->OnSuggestionsReturned(query_id, suggestions); + enable_ablation_logging_ = true; + return; + } + if (!suggestions.empty()) { if (is_filling_credit_card) AutofillMetrics::LogIsQueriedCreditCardFormSecure(is_context_secure); @@ -840,11 +871,19 @@ void AutofillManager::OnDidFillAutofillFormData(const FormData& form, UpdatePendingForm(form); - AutofillMetrics::LogUserHappinessMetric(AutofillMetrics::USER_DID_AUTOFILL); + FormStructure* form_structure = NULL; + std::set<FormType> form_types; + // Find the FormStructure that corresponds to |form|. Use default form type if + // form is not present in our cache, which will happen rarely. + if (FindCachedForm(form, &form_structure)) { + form_types = form_structure->GetFormTypes(); + } + AutofillMetrics::LogUserHappinessMetric(AutofillMetrics::USER_DID_AUTOFILL, + form_types); if (!user_did_autofill_) { user_did_autofill_ = true; AutofillMetrics::LogUserHappinessMetric( - AutofillMetrics::USER_DID_AUTOFILL_ONCE); + AutofillMetrics::USER_DID_AUTOFILL_ONCE, form_types); } UpdateInitialInteractionTimestamp(timestamp); @@ -861,12 +900,14 @@ void AutofillManager::DidShowSuggestions(bool is_new_popup, return; if (is_new_popup) { - AutofillMetrics::LogUserHappinessMetric(AutofillMetrics::SUGGESTIONS_SHOWN); + AutofillMetrics::LogUserHappinessMetric(AutofillMetrics::SUGGESTIONS_SHOWN, + autofill_field->Type().group()); if (!did_show_suggestions_) { did_show_suggestions_ = true; AutofillMetrics::LogUserHappinessMetric( - AutofillMetrics::SUGGESTIONS_SHOWN_ONCE); + AutofillMetrics::SUGGESTIONS_SHOWN_ONCE, + autofill_field->Type().group()); } if (autofill_field->Type().group() == CREDIT_CARD) { @@ -1000,8 +1041,7 @@ void AutofillManager::SetTestDelegate(AutofillManagerTestDelegate* delegate) { void AutofillManager::OnSetDataList(const std::vector<base::string16>& values, const std::vector<base::string16>& labels) { - if (!IsValidString16Vector(values) || - !IsValidString16Vector(labels) || + if (!IsValidString16Vector(values) || !IsValidString16Vector(labels) || values.size() != labels.size()) return; @@ -1197,6 +1237,11 @@ bool AutofillManager::IsCreditCardUploadEnabled() { GetIdentityProvider()->GetActiveUsername()); } +bool AutofillManager::IsCreditCardAutofillEnabled() { + return client_->GetPrefs()->GetBoolean(prefs::kAutofillCreditCardEnabled) && + client_->IsAutofillSupported(); +} + bool AutofillManager::ShouldUploadForm(const FormStructure& form) { return IsAutofillEnabled() && !driver()->IsIncognito() && form.ShouldBeParsed() && @@ -1210,15 +1255,16 @@ void AutofillManager::ImportFormData(const FormStructure& submitted_form) { std::unique_ptr<CreditCard> imported_credit_card; bool imported_credit_card_matches_masked_server_credit_card; if (!personal_data_->ImportFormData( - submitted_form, IsCreditCardUploadEnabled(), &imported_credit_card, + submitted_form, IsCreditCardAutofillEnabled(), + IsCreditCardUploadEnabled(), &imported_credit_card, &imported_credit_card_matches_masked_server_credit_card)) return; #ifdef ENABLE_FORM_DEBUG_DUMP // Debug code for research on what autofill Chrome extracts from the last few // forms when submitting credit card data. See DumpAutofillData(). - bool dump_data = base::CommandLine::ForCurrentProcess()->HasSwitch( - "dump-autofill-data"); + bool dump_data = + base::CommandLine::ForCurrentProcess()->HasSwitch("dump-autofill-data"); // Save the form data for future dumping. if (dump_data) { @@ -1377,23 +1423,6 @@ int AutofillManager::SetProfilesForCreditCardUpload( AutofillMetrics::LogHasModifiedProfileOnCreditCardFormSubmission( has_modified_profile); - // If there are no recently used or modified profiles and experiment to use - // profiles that were not recently used is enabled, collect the profiles that - // used within the maximum time specified in the experiment. - if (candidate_profiles.empty()) { - const base::TimeDelta max_time_since_use = - GetMaxTimeSinceAutofillProfileUseForCardUpload(); - if (!max_time_since_use.is_zero()) { - for (AutofillProfile* profile : personal_data_->GetProfiles()) - if ((now - profile->modification_date()) < max_time_since_use || - (now - profile->use_date()) < max_time_since_use) - candidate_profiles.push_back(*profile); - if (!candidate_profiles.empty()) - upload_request->active_experiments.push_back( - kAutofillUpstreamUseNotRecentlyUsedAutofillProfile.name); - } - } - if (candidate_profiles.empty()) { upload_decision_metrics |= has_profile @@ -1591,6 +1620,7 @@ void AutofillManager::Reset() { user_did_type_ = false; user_did_autofill_ = false; user_did_edit_autofilled_field_ = false; + enable_ablation_logging_ = false; masked_card_ = CreditCard(); unmasking_query_id_ = -1; unmasking_form_ = FormData(); @@ -1646,8 +1676,7 @@ bool AutofillManager::RefreshDataModels() { return false; // No autofill data to return if the profiles are empty. - const std::vector<AutofillProfile*>& profiles = - personal_data_->GetProfiles(); + const std::vector<AutofillProfile*>& profiles = personal_data_->GetProfiles(); const std::vector<CreditCard*>& credit_cards = personal_data_->GetCreditCards(); @@ -1748,8 +1777,8 @@ void AutofillManager::FillOrPreviewDataModelForm( base::string16 profile_full_name; std::string profile_language_code; if (!is_credit_card) { - profile_full_name = data_model.GetInfo( - AutofillType(NAME_FULL), app_locale_); + profile_full_name = + data_model.GetInfo(AutofillType(NAME_FULL), app_locale_); profile_language_code = static_cast<const AutofillProfile*>(&data_model)->language_code(); } @@ -1761,10 +1790,8 @@ void AutofillManager::FillOrPreviewDataModelForm( if (iter.SameFieldAs(field)) { base::string16 value = data_model.GetInfo(autofill_field->Type(), app_locale_); - if (AutofillField::FillFormField(*autofill_field, - value, - profile_language_code, - app_locale_, + if (AutofillField::FillFormField(*autofill_field, value, + profile_language_code, app_locale_, &iter)) { // Mark the cached field as autofilled, so that we can detect when a // user edits an autofilled field (for metrics). @@ -1806,12 +1833,12 @@ void AutofillManager::FillOrPreviewDataModelForm( base::string16 value = data_model.GetInfo(cached_field->Type(), app_locale_); - if (is_credit_card && - cached_field->Type().GetStorableType() == - CREDIT_CARD_VERIFICATION_CODE) { + if (is_credit_card && cached_field->Type().GetStorableType() == + CREDIT_CARD_VERIFICATION_CODE) { value = cvc; - } else if (is_credit_card && IsCreditCardExpirationType( - cached_field->Type().GetStorableType()) && + } else if (is_credit_card && + IsCreditCardExpirationType( + cached_field->Type().GetStorableType()) && static_cast<const CreditCard*>(&data_model) ->IsExpired(AutofillClock::Now())) { // Don't fill expired cards expiration date. @@ -1822,16 +1849,12 @@ void AutofillManager::FillOrPreviewDataModelForm( // Only notify autofilling of empty fields and the field that initiated // the filling (note that "select-one" controls may not be empty but will // still be autofilled). - bool should_notify = - !is_credit_card && - !value.empty() && - (result.fields[i].SameFieldAs(field) || - result.fields[i].form_control_type == "select-one" || - result.fields[i].value.empty()); - if (AutofillField::FillFormField(*cached_field, - value, - profile_language_code, - app_locale_, + bool should_notify = !is_credit_card && !value.empty() && + (result.fields[i].SameFieldAs(field) || + result.fields[i].form_control_type == "select-one" || + result.fields[i].value.empty()); + if (AutofillField::FillFormField(*cached_field, value, + profile_language_code, app_locale_, &result.fields[i])) { // Mark the cached field as autofilled, so that we can detect when a // user edits an autofilled field (for metrics). @@ -1963,8 +1986,7 @@ bool AutofillManager::UpdateCachedForm(const FormData& live_form, const FormStructure* cached_form, FormStructure** updated_form) { bool needs_update = - (!cached_form || - live_form.fields.size() != cached_form->field_count()); + (!cached_form || live_form.fields.size() != cached_form->field_count()); for (size_t i = 0; !needs_update && i < cached_form->field_count(); ++i) needs_update = !cached_form->field(i)->SameFieldAs(live_form.fields[i]); @@ -2050,6 +2072,7 @@ void AutofillManager::ParseForms(const std::vector<FormData>& forms) { std::vector<FormStructure*> non_queryable_forms; std::vector<FormStructure*> queryable_forms; + std::set<FormType> form_types; for (const FormData& form : forms) { const auto parse_form_start_time = TimeTicks::Now(); @@ -2058,6 +2081,8 @@ void AutofillManager::ParseForms(const std::vector<FormData>& forms) { continue; DCHECK(form_structure); + std::set<FormType> current_form_types = form_structure->GetFormTypes(); + form_types.insert(current_form_types.begin(), current_form_types.end()); // 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()) @@ -2070,7 +2095,8 @@ void AutofillManager::ParseForms(const std::vector<FormData>& forms) { } if (!queryable_forms.empty() || !non_queryable_forms.empty()) { - AutofillMetrics::LogUserHappinessMetric(AutofillMetrics::FORMS_LOADED); + AutofillMetrics::LogUserHappinessMetric(AutofillMetrics::FORMS_LOADED, + form_types); #if defined(OS_IOS) // Log this from same location as AutofillMetrics::FORMS_LOADED to ensure @@ -2181,7 +2207,7 @@ void AutofillManager::SplitFrontendID(int frontend_id, std::string* cc_backend_id, std::string* profile_backend_id) const { int cc_int_id = (frontend_id >> std::numeric_limits<uint16_t>::digits) & - std::numeric_limits<uint16_t>::max(); + std::numeric_limits<uint16_t>::max(); int profile_int_id = frontend_id & std::numeric_limits<uint16_t>::max(); *cc_backend_id = IntToBackendID(cc_int_id); @@ -2387,8 +2413,8 @@ void AutofillManager::DumpAutofillData(bool imported_cc) const { fputs("Got a new credit card on CC form:\n", file); else fputs("Submitted form:\n", file); - for (int i = static_cast<int>(recently_autofilled_forms_.size()) - 1; - i >= 0; i--) { + for (int i = static_cast<int>(recently_autofilled_forms_.size()) - 1; i >= 0; + i--) { for (const auto& pair : recently_autofilled_forms_[i]) { fputs(" ", file); fputs(pair.first.c_str(), file); diff --git a/chromium/components/autofill/core/browser/autofill_manager.h b/chromium/components/autofill/core/browser/autofill_manager.h index ededde78f65..b8c8ecf2619 100644 --- a/chromium/components/autofill/core/browser/autofill_manager.h +++ b/chromium/components/autofill/core/browser/autofill_manager.h @@ -27,6 +27,7 @@ #include "components/autofill/core/browser/autofill_metrics.h" #include "components/autofill/core/browser/card_unmask_delegate.h" #include "components/autofill/core/browser/form_structure.h" +#include "components/autofill/core/browser/form_types.h" #include "components/autofill/core/browser/payments/full_card_request.h" #include "components/autofill/core/browser/payments/payments_client.h" #include "components/autofill/core/browser/personal_data_manager.h" @@ -201,6 +202,10 @@ class AutofillManager : public AutofillHandler, // are satisfied. virtual bool IsCreditCardUploadEnabled(); + // Returns true if the value of the AutofillCreditCardEnabled pref is true and + // the client supports Autofill. + virtual bool IsCreditCardAutofillEnabled(); + // Shared code to determine if |form| should be uploaded to the Autofill // server. It verifies that uploading is allowed and |form| meets conditions // to be uploadable. Exposed for testing. @@ -582,6 +587,10 @@ class AutofillManager : public AutofillHandler, // determined to be a CVC field via heuristics has a valid CVC |value|. bool found_cvc_value_in_non_cvc_field_; + // Ablation experiment turns off autofill, but logging still has to be kept + // for metrics analysis. + bool enable_ablation_logging_; + GURL pending_upload_request_url_; #ifdef ENABLE_FORM_DEBUG_DUMP @@ -632,6 +641,18 @@ class AutofillManager : public AutofillHandler, FRIEND_TEST_ALL_PREFIXES(AutofillMetricsTest, CreditCardSubmittedFormEvents); FRIEND_TEST_ALL_PREFIXES(AutofillMetricsTest, CreditCardCheckoutFlowUserActions); + FRIEND_TEST_ALL_PREFIXES( + AutofillMetricsTest, + CreditCardSubmittedWithoutSelectingSuggestionsNoCard); + FRIEND_TEST_ALL_PREFIXES( + AutofillMetricsTest, + CreditCardSubmittedWithoutSelectingSuggestionsUnknownCard); + FRIEND_TEST_ALL_PREFIXES( + AutofillMetricsTest, + CreditCardSubmittedWithoutSelectingSuggestionsKnownCard); + FRIEND_TEST_ALL_PREFIXES( + AutofillMetricsTest, + ShouldNotLogSubmitWithoutSelectingSuggestionsIfSuggestionFilled); FRIEND_TEST_ALL_PREFIXES(AutofillMetricsTest, ProfileCheckoutFlowUserActions); FRIEND_TEST_ALL_PREFIXES(AutofillMetricsTest, DeveloperEngagement); FRIEND_TEST_ALL_PREFIXES(AutofillMetricsTest, FormFillDuration); @@ -646,7 +667,10 @@ class AutofillManager : public AutofillHandler, TestTabContentsWithExternalDelegate); FRIEND_TEST_ALL_PREFIXES(AutofillMetricsTest, UserHappinessFormLoadAndSubmission); - FRIEND_TEST_ALL_PREFIXES(AutofillMetricsTest, UserHappinessFormInteraction); + FRIEND_TEST_ALL_PREFIXES(AutofillMetricsTest, + UserHappinessFormInteraction_AddressForm); + FRIEND_TEST_ALL_PREFIXES(AutofillMetricsTest, + UserHappinessFormInteraction_CreditCardForm); FRIEND_TEST_ALL_PREFIXES(AutofillManagerTest, OnLoadedServerPredictions); FRIEND_TEST_ALL_PREFIXES(AutofillManagerTest, diff --git a/chromium/components/autofill/core/browser/autofill_manager_unittest.cc b/chromium/components/autofill/core/browser/autofill_manager_unittest.cc index 1280500a66e..74d41a7f88f 100644 --- a/chromium/components/autofill/core/browser/autofill_manager_unittest.cc +++ b/chromium/components/autofill/core/browser/autofill_manager_unittest.cc @@ -572,6 +572,7 @@ class TestAutofillManager : public AutofillManager { context_getter_(driver->GetURLRequestContext()), test_payments_client_(new TestPaymentsClient(context_getter_, this)), autofill_enabled_(true), + credit_card_enabled_(true), credit_card_upload_enabled_(false), credit_card_was_uploaded_(false), expected_observed_submission_(true), @@ -594,6 +595,15 @@ class TestAutofillManager : public AutofillManager { credit_card_upload_enabled_ = credit_card_upload_enabled; } + bool IsCreditCardAutofillEnabled() override { return credit_card_enabled_; } + + void set_credit_card_enabled(bool credit_card_enabled) { + credit_card_enabled_ = credit_card_enabled; + if (!credit_card_enabled_) + // Credit card data is refreshed when this pref is changed. + personal_data_->ClearCreditCards(); + } + bool credit_card_was_uploaded() { return credit_card_was_uploaded_; } void set_expected_submitted_field_types( @@ -675,7 +685,7 @@ class TestAutofillManager : public AutofillManager { return personal_data_->GetLocalCreditCards(); } - const std::vector<CreditCard*>& GetCreditCards() const { + std::vector<CreditCard*> GetCreditCards() const { return personal_data_->GetCreditCards(); } @@ -723,6 +733,7 @@ class TestAutofillManager : public AutofillManager { net::URLRequestContextGetter* context_getter_; // Weak reference. TestPaymentsClient* test_payments_client_; // Weak reference. bool autofill_enabled_; + bool credit_card_enabled_; bool credit_card_upload_enabled_; bool credit_card_was_uploaded_; bool expected_observed_submission_; @@ -1096,11 +1107,16 @@ class AutofillManagerTest : public testing::Test { scoped_feature_list_.InitAndEnableFeature(kAutofillUpstreamShowNewUi); } - void DisableAutofillUpstreamUseAutofillProfileComparator() { - scoped_feature_list_.InitAndDisableFeature( + void EnableAutofillUpstreamUseAutofillProfileComparator() { + scoped_feature_list_.InitAndEnableFeature( kAutofillUpstreamUseAutofillProfileComparator); } + void DisableCreditCardAutofill() { + scoped_feature_list_.InitAndEnableFeature( + kAutofillCreditCardAblationExperiment); + } + void ExpectUniqueFillableFormParsedUkm() { // Check that one source is logged. ASSERT_EQ(1U, test_ukm_recorder_.sources_count()); @@ -1215,7 +1231,7 @@ class TestFormStructure : public FormStructure { AutofillField* form_field = field(i); ASSERT_TRUE(form_field); form_field->set_heuristic_type(heuristic_types[i]); - form_field->set_server_type(server_types[i]); + form_field->set_overall_server_type(server_types[i]); } UpdateAutofillCount(); @@ -2088,6 +2104,62 @@ TEST_F(AutofillManagerTest, GetAddressAndCreditCardSuggestionsNonHttps) { external_delegate_->CheckNoSuggestions(kDefaultPageID); } +TEST_F(AutofillManagerTest, + ShouldShowAddressSuggestionsIfCreditCardAutofillDisabled) { + DisableCreditCardAutofill(); + + // Set up our form data. + FormData form; + test::CreateTestAddressFormData(&form); + std::vector<FormData> forms(1, form); + FormsSeen(forms); + + FormFieldData field = form.fields[0]; + GetAutofillSuggestions(form, field); + + // Check that address suggestions will still be available. + external_delegate_->CheckSuggestions( + kDefaultPageID, Suggestion("Charles", "123 Apple St.", "", 1), + Suggestion("Elvis", "3734 Elvis Presley Blvd.", "", 2)); +} + +TEST_F(AutofillManagerTest, + ShouldNotShowCreditCardsSuggestionsIfCreditCardAutofillDisabled) { + DisableCreditCardAutofill(); + + // Set up our form data. + FormData form; + CreateTestCreditCardFormData(&form, true, false); + std::vector<FormData> forms(1, form); + FormsSeen(forms); + + FormFieldData field = form.fields[0]; + GetAutofillSuggestions(form, field); + + // Check that credit card suggestions will not be available. + external_delegate_->CheckNoSuggestions(kDefaultPageID); +} + +TEST_F(AutofillManagerTest, + ShouldLogFormSubmitEventIfCreditCardAutofillDisabled) { + DisableCreditCardAutofill(); + + // Set up our form data. + FormData form; + CreateTestCreditCardFormData(&form, true, false); + std::vector<FormData> forms(1, form); + FormsSeen(forms); + + FormFieldData field = form.fields[0]; + GetAutofillSuggestions(form, field); + + base::HistogramTester histogram_tester; + FormSubmitted(form); + histogram_tester.ExpectBucketCount( + "Autofill.FormEvents.CreditCard", + AutofillMetrics::FORM_EVENT_SUGGESTION_SHOWN_SUBMITTED_ONCE, 1); +} + // Test that we return autocomplete-like suggestions when trying to autofill // already filled forms. TEST_F(AutofillManagerTest, GetFieldSuggestionsWhenFormIsAutofilled) { @@ -2566,8 +2638,12 @@ TEST_F(AutofillManagerTest, FillAddressForm_UnrecognizedAttribute) { } // Test that non credit card related fields with the autocomplete attribute set -// to off are not filled on desktop. -TEST_F(AutofillManagerTest, FillAddressForm_AutocompleteOff) { +// to off are not filled on desktop when the feature to autofill all addresses +// is disabled. +TEST_F(AutofillManagerTest, FillAddressForm_AutocompleteOffRespected) { + base::test::ScopedFeatureList feature_list; + feature_list.InitAndDisableFeature(kAutofillAlwaysFillAddresses); + FormData address_form; address_form.name = ASCIIToUTF16("MyForm"); address_form.origin = GURL("https://myform.com/form.html"); @@ -2622,6 +2698,48 @@ TEST_F(AutofillManagerTest, FillAddressForm_AutocompleteOff) { } } +// Test that non credit card related fields with the autocomplete attribute set +// to off are filled on all platforms when the feature to autofill all addresses +// is enabled (default). +TEST_F(AutofillManagerTest, FillAddressForm_AutocompleteOffNotRespected) { + FormData address_form; + address_form.name = ASCIIToUTF16("MyForm"); + address_form.origin = GURL("https://myform.com/form.html"); + address_form.action = GURL("https://myform.com/submit.html"); + FormFieldData field; + test::CreateTestFormField("First name", "firstname", "", "text", &field); + address_form.fields.push_back(field); + test::CreateTestFormField("Middle name", "middle", "", "text", &field); + field.should_autocomplete = false; + address_form.fields.push_back(field); + test::CreateTestFormField("Last name", "lastname", "", "text", &field); + field.should_autocomplete = true; + address_form.fields.push_back(field); + test::CreateTestFormField("Address Line 1", "addr1", "", "text", &field); + field.should_autocomplete = false; + address_form.fields.push_back(field); + std::vector<FormData> address_forms(1, address_form); + FormsSeen(address_forms); + + // Fill the address form. + const char guid[] = "00000000-0000-0000-0000-000000000001"; + int response_page_id = 0; + FormData response_data; + FillAutofillFormDataAndSaveResults( + kDefaultPageID, address_form, address_form.fields[0], + MakeFrontendID(std::string(), guid), &response_page_id, &response_data); + + // All fields should be filled. + ExpectFilledField("First name", "firstname", "Elvis", "text", + response_data.fields[0]); + ExpectFilledField("Middle name", "middle", "Aaron", "text", + response_data.fields[1]); + ExpectFilledField("Last name", "lastname", "Presley", "text", + response_data.fields[2]); + ExpectFilledField("Address Line 1", "addr1", "3734 Elvis Presley Blvd.", + "text", response_data.fields[3]); +} + // Test that a field with a value equal to it's placeholder attribute is filled. TEST_F(AutofillManagerTest, FillAddressForm_PlaceholderEqualsValue) { FormData address_form; @@ -3628,16 +3746,16 @@ TEST_F(AutofillManagerTest, OnLoadedServerPredictions) { autofill_manager_->AddSeenForm(base::WrapUnique(form_structure2)); AutofillQueryResponseContents response; - response.add_field()->set_autofill_type(3); + response.add_field()->set_overall_type_prediction(3); for (int i = 0; i < 7; ++i) { - response.add_field()->set_autofill_type(0); + response.add_field()->set_overall_type_prediction(0); } - response.add_field()->set_autofill_type(3); - response.add_field()->set_autofill_type(2); - response.add_field()->set_autofill_type(61); - response.add_field()->set_autofill_type(5); - response.add_field()->set_autofill_type(4); - response.add_field()->set_autofill_type(35); + response.add_field()->set_overall_type_prediction(3); + response.add_field()->set_overall_type_prediction(2); + response.add_field()->set_overall_type_prediction(61); + response.add_field()->set_overall_type_prediction(5); + response.add_field()->set_overall_type_prediction(4); + response.add_field()->set_overall_type_prediction(35); std::string response_string; ASSERT_TRUE(response.SerializeToString(&response_string)); @@ -3680,13 +3798,13 @@ TEST_F(AutofillManagerTest, OnLoadedServerPredictions_ResetManager) { autofill_manager_->AddSeenForm(base::WrapUnique(form_structure)); AutofillQueryResponseContents response; - response.add_field()->set_autofill_type(3); + response.add_field()->set_overall_type_prediction(3); for (int i = 0; i < 7; ++i) { - response.add_field()->set_autofill_type(0); + response.add_field()->set_overall_type_prediction(0); } - response.add_field()->set_autofill_type(3); - response.add_field()->set_autofill_type(2); - response.add_field()->set_autofill_type(61); + response.add_field()->set_overall_type_prediction(3); + response.add_field()->set_overall_type_prediction(2); + response.add_field()->set_overall_type_prediction(61); std::string response_string; ASSERT_TRUE(response.SerializeToString(&response_string)); @@ -4272,7 +4390,8 @@ TEST_F(AutofillManagerTest, DisambiguateUploadTypes) { // Assign the specified predicted type for each field in the test case. FormStructure form_structure(form); for (size_t i = 0; i < test_fields.size(); ++i) { - form_structure.field(i)->set_server_type(test_fields[i].predicted_type); + form_structure.field(i)->set_overall_server_type( + test_fields[i].predicted_type); } AutofillManager::DeterminePossibleFieldTypesForUpload( @@ -4670,6 +4789,78 @@ TEST_F(AutofillManagerTest, FillInUpdatedExpirationDate) { "4012888888881881"); } +TEST_F(AutofillManagerTest, CreditCardDisabledDoesNotSave) { + personal_data_.ClearAutofillProfiles(); + autofill_manager_->set_credit_card_enabled(false); + + // Create, fill and submit an address form in order to establish a recent + // profile which can be selected for the upload request. + FormData address_form; + test::CreateTestAddressFormData(&address_form); + FormsSeen(std::vector<FormData>(1, address_form)); + ManuallyFillAddressForm("Flo", "Master", "77401", "US", &address_form); + FormSubmitted(address_form); + + // Set up our credit card form data. + FormData credit_card_form; + CreateTestCreditCardFormData(&credit_card_form, true, false); + 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"); + credit_card_form.fields[4].value = ASCIIToUTF16("123"); + + base::HistogramTester histogram_tester; + + // The credit card should neither be saved locally or uploaded. + EXPECT_CALL(autofill_client_, ConfirmSaveCreditCardLocally(_, _)).Times(0); + FormSubmitted(credit_card_form); + EXPECT_FALSE(autofill_manager_->credit_card_was_uploaded()); + + // Verify that no histogram entry was logged. + histogram_tester.ExpectTotalCount("Autofill.CardUploadDecisionMetric", 0); +} + +TEST_F(AutofillManagerTest, CreditCardDisabledDoesNotFillFormData) { + autofill_manager_->set_credit_card_enabled(false); + + // Set up our form data. + FormData form; + CreateTestCreditCardFormData(&form, true, false); + std::vector<FormData> forms(1, form); + FormsSeen(forms); + + const char guid[] = "00000000-0000-0000-0000-000000000004"; + + // Expect no fields filled, no form data sent to renderer. + EXPECT_CALL(*autofill_driver_, SendFormDataToRenderer(_, _, _)).Times(0); + + FillAutofillFormData(kDefaultPageID, form, *form.fields.begin(), + MakeFrontendID(guid, std::string())); +} + +TEST_F(AutofillManagerTest, CreditCardDisabledDoesNotSuggest) { + autofill_manager_->set_credit_card_enabled(false); + + // Set up our form data. + FormData form; + CreateTestCreditCardFormData(&form, true, false); + std::vector<FormData> forms(1, form); + EXPECT_CALL(autofill_client_, ShouldShowSigninPromo()); + FormsSeen(forms); + + FormFieldData field; + test::CreateTestFormField("Name on Card", "nameoncard", "pres", "text", + &field); + GetAutofillSuggestions(form, field); + // Expect no suggestions as autofill and autocomplete are disabled for credit + // cards. + EXPECT_FALSE(external_delegate_->on_suggestions_returned_seen()); +} + TEST_F(AutofillManagerTest, UploadCreditCard) { personal_data_.ClearCreditCards(); personal_data_.ClearAutofillProfiles(); @@ -4703,9 +4894,7 @@ TEST_F(AutofillManagerTest, UploadCreditCard) { EXPECT_CALL(autofill_client_, ConfirmSaveCreditCardLocally(_, _)).Times(0); FormSubmitted(credit_card_form); EXPECT_TRUE(autofill_manager_->credit_card_was_uploaded()); - EXPECT_THAT( - autofill_manager_->GetActiveExperiments(), - UnorderedElementsAre(kAutofillUpstreamUseAutofillProfileComparator.name)); + EXPECT_TRUE(autofill_manager_->GetActiveExperiments().empty()); // Server did not send a server_id, expect copy of card is not stored. EXPECT_TRUE(autofill_manager_->GetCreditCards().empty()); @@ -4755,9 +4944,7 @@ TEST_F(AutofillManagerTest, UploadCreditCard_RequestCVCEnabled_DoesNotTrigger) { FormSubmitted(credit_card_form); EXPECT_TRUE(autofill_manager_->credit_card_was_uploaded()); // Submitted form included CVC, so user did not need to enter CVC. - EXPECT_THAT( - autofill_manager_->GetActiveExperiments(), - UnorderedElementsAre(kAutofillUpstreamUseAutofillProfileComparator.name)); + EXPECT_TRUE(autofill_manager_->GetActiveExperiments().empty()); } TEST_F(AutofillManagerTest, UploadCreditCardAndSaveCopy) { @@ -5271,10 +5458,8 @@ TEST_F(AutofillManagerTest, EXPECT_CALL(autofill_client_, ConfirmSaveCreditCardLocally(_, _)).Times(0); FormSubmitted(credit_card_form); EXPECT_TRUE(autofill_manager_->credit_card_was_uploaded()); - EXPECT_THAT( - autofill_manager_->GetActiveExperiments(), - UnorderedElementsAre(kAutofillUpstreamUseAutofillProfileComparator.name, - kAutofillUpstreamRequestCvcIfMissing.name)); + EXPECT_THAT(autofill_manager_->GetActiveExperiments(), + UnorderedElementsAre(kAutofillUpstreamRequestCvcIfMissing.name)); // Verify that the correct histogram entries were logged. ExpectCardUploadDecision(histogram_tester, AutofillMetrics::UPLOAD_OFFERED); @@ -5371,16 +5556,12 @@ TEST_F(AutofillManagerTest, credit_card_form.fields[3].value = ASCIIToUTF16("2017"); credit_card_form.fields[4].value = ASCIIToUTF16("123"); - base::HistogramTester histogram_tester; - // Confirm upload happened and the new UI flag was sent in the request. EXPECT_CALL(autofill_client_, ConfirmSaveCreditCardLocally(_, _)).Times(0); FormSubmitted(credit_card_form); EXPECT_TRUE(autofill_manager_->credit_card_was_uploaded()); - EXPECT_THAT( - autofill_manager_->GetActiveExperiments(), - UnorderedElementsAre(kAutofillUpstreamUseAutofillProfileComparator.name, - kAutofillUpstreamShowNewUi.name)); + EXPECT_THAT(autofill_manager_->GetActiveExperiments(), + UnorderedElementsAre(kAutofillUpstreamShowNewUi.name)); } TEST_F(AutofillManagerTest, @@ -5408,15 +5589,11 @@ TEST_F(AutofillManagerTest, credit_card_form.fields[3].value = ASCIIToUTF16("2017"); credit_card_form.fields[4].value = ASCIIToUTF16("123"); - base::HistogramTester histogram_tester; - - // Confirm upload happened and the new UI flag was sent in the request. + // Confirm upload happened and the new UI flag was not sent in the request. EXPECT_CALL(autofill_client_, ConfirmSaveCreditCardLocally(_, _)).Times(0); FormSubmitted(credit_card_form); EXPECT_TRUE(autofill_manager_->credit_card_was_uploaded()); - EXPECT_THAT( - autofill_manager_->GetActiveExperiments(), - UnorderedElementsAre(kAutofillUpstreamUseAutofillProfileComparator.name)); + EXPECT_TRUE(autofill_manager_->GetActiveExperiments().empty()); } TEST_F(AutofillManagerTest, @@ -5445,17 +5622,13 @@ TEST_F(AutofillManagerTest, credit_card_form.fields[3].value = ASCIIToUTF16("2017"); credit_card_form.fields[4].value = ASCIIToUTF16("123"); - base::HistogramTester histogram_tester; - // Confirm upload happened and the show Google logo flag was sent in the // request. EXPECT_CALL(autofill_client_, ConfirmSaveCreditCardLocally(_, _)).Times(0); FormSubmitted(credit_card_form); EXPECT_TRUE(autofill_manager_->credit_card_was_uploaded()); - EXPECT_THAT( - autofill_manager_->GetActiveExperiments(), - UnorderedElementsAre(kAutofillUpstreamUseAutofillProfileComparator.name, - kAutofillUpstreamShowGoogleLogo.name)); + EXPECT_THAT(autofill_manager_->GetActiveExperiments(), + UnorderedElementsAre(kAutofillUpstreamShowGoogleLogo.name)); } TEST_F(AutofillManagerTest, @@ -5483,16 +5656,12 @@ TEST_F(AutofillManagerTest, credit_card_form.fields[3].value = ASCIIToUTF16("2017"); credit_card_form.fields[4].value = ASCIIToUTF16("123"); - base::HistogramTester histogram_tester; - - // Confirm upload happened and the show Google logo flag was sent in the + // Confirm upload happened and the show Google logo flag was not sent in the // request. EXPECT_CALL(autofill_client_, ConfirmSaveCreditCardLocally(_, _)).Times(0); FormSubmitted(credit_card_form); EXPECT_TRUE(autofill_manager_->credit_card_was_uploaded()); - EXPECT_THAT( - autofill_manager_->GetActiveExperiments(), - UnorderedElementsAre(kAutofillUpstreamUseAutofillProfileComparator.name)); + EXPECT_TRUE(autofill_manager_->GetActiveExperiments().empty()); } #endif @@ -5580,63 +5749,6 @@ TEST_F(AutofillManagerTest, UploadCreditCard_NoRecentlyUsedProfile) { } TEST_F(AutofillManagerTest, - UploadCreditCard_NoRecentlyUsedProfile_CanUseOldProfile) { - variation_params_.SetVariationParamsWithFeatureAssociations( - kAutofillUpstreamUseNotRecentlyUsedAutofillProfile.name, - {{kAutofillUpstreamMaxMinutesSinceAutofillProfileUseKey, - base::IntToString((kMuchLaterTime - kArbitraryTime).InMinutes() + 1)}}, - {kAutofillUpstreamUseNotRecentlyUsedAutofillProfile.name}); - - // Create the test clock and set the time to a specific value. - TestAutofillClock test_clock; - test_clock.SetNow(kArbitraryTime); - - personal_data_.ClearAutofillProfiles(); - autofill_manager_->set_credit_card_upload_enabled(true); - - // Create, fill and submit an address form in order to establish a profile. - FormData address_form; - test::CreateTestAddressFormData(&address_form); - FormsSeen({address_form}); - - ManuallyFillAddressForm("Flo", "Master", "77401", "US", &address_form); - FormSubmitted(address_form); - - // Advance the current time. Although |address_form| is not a recently used - // address profile, we will include it in the candidate profiles because - // there are no recently used address profiles and the feature to use older - // profiles is enabled. - test_clock.SetNow(kMuchLaterTime); - - // Set up our credit card form data. - FormData credit_card_form; - CreateTestCreditCardFormData(&credit_card_form, true, false); - FormsSeen(std::vector<FormData>(1, credit_card_form)); - - // 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"); - credit_card_form.fields[4].value = ASCIIToUTF16("123"); - - base::HistogramTester histogram_tester; - - // Upload should be offered. - EXPECT_CALL(autofill_client_, ConfirmSaveCreditCardLocally(_, _)).Times(0); - FormSubmitted(credit_card_form); - EXPECT_TRUE(autofill_manager_->credit_card_was_uploaded()); - EXPECT_THAT(autofill_manager_->GetActiveExperiments(), - UnorderedElementsAre( - kAutofillUpstreamUseAutofillProfileComparator.name, - kAutofillUpstreamUseNotRecentlyUsedAutofillProfile.name)); - - // Verify that the correct histogram entry (and only that) was logged. - ExpectUniqueCardUploadDecision(histogram_tester, - AutofillMetrics::UPLOAD_OFFERED); -} - -TEST_F(AutofillManagerTest, UploadCreditCard_CvcUnavailableAndNoProfileAvailable) { personal_data_.ClearAutofillProfiles(); autofill_manager_->set_credit_card_upload_enabled(true); @@ -5795,19 +5907,20 @@ TEST_F(AutofillManagerTest, UploadCreditCard_ZipCodesDiscardWhitespace) { base::HistogramTester histogram_tester; - // Zips match because we discard whitespace before comparison. + // Neither a local save nor an upload should happen in this case. EXPECT_CALL(autofill_client_, ConfirmSaveCreditCardLocally(_, _)).Times(0); FormSubmitted(credit_card_form); - EXPECT_TRUE(autofill_manager_->credit_card_was_uploaded()); + EXPECT_FALSE(autofill_manager_->credit_card_was_uploaded()); + EXPECT_TRUE(autofill_manager_->GetActiveExperiments().empty()); // Verify that the correct histogram entry (and only that) was logged. - ExpectUniqueCardUploadDecision(histogram_tester, - AutofillMetrics::UPLOAD_OFFERED); + ExpectUniqueCardUploadDecision( + histogram_tester, AutofillMetrics::UPLOAD_NOT_OFFERED_CONFLICTING_ZIPS); } TEST_F(AutofillManagerTest, - UploadCreditCard_ZipCodesDiscardWhitespace_DisableComparator) { - DisableAutofillUpstreamUseAutofillProfileComparator(); + UploadCreditCard_ZipCodesDiscardWhitespace_ComparatorEnabled) { + EnableAutofillUpstreamUseAutofillProfileComparator(); personal_data_.ClearAutofillProfiles(); autofill_manager_->set_credit_card_upload_enabled(true); @@ -5838,14 +5951,17 @@ TEST_F(AutofillManagerTest, base::HistogramTester histogram_tester; - // Neither a local save nor an upload should happen in this case. + // Zips match because we discard whitespace before comparison. EXPECT_CALL(autofill_client_, ConfirmSaveCreditCardLocally(_, _)).Times(0); FormSubmitted(credit_card_form); - EXPECT_FALSE(autofill_manager_->credit_card_was_uploaded()); + EXPECT_TRUE(autofill_manager_->credit_card_was_uploaded()); + EXPECT_THAT( + autofill_manager_->GetActiveExperiments(), + UnorderedElementsAre(kAutofillUpstreamUseAutofillProfileComparator.name)); // Verify that the correct histogram entry (and only that) was logged. - ExpectUniqueCardUploadDecision( - histogram_tester, AutofillMetrics::UPLOAD_NOT_OFFERED_CONFLICTING_ZIPS); + ExpectUniqueCardUploadDecision(histogram_tester, + AutofillMetrics::UPLOAD_OFFERED); } TEST_F(AutofillManagerTest, UploadCreditCard_ZipCodesHavePrefixMatch) { @@ -5976,6 +6092,7 @@ TEST_F(AutofillManagerTest, UploadCreditCard_CCFormHasMiddleInitial) { EXPECT_CALL(autofill_client_, ConfirmSaveCreditCardLocally(_, _)).Times(0); FormSubmitted(credit_card_form); EXPECT_TRUE(autofill_manager_->credit_card_was_uploaded()); + EXPECT_TRUE(autofill_manager_->GetActiveExperiments().empty()); // Verify that the correct histogram entry (and only that) was logged. ExpectUniqueCardUploadDecision(histogram_tester, @@ -5985,8 +6102,8 @@ TEST_F(AutofillManagerTest, UploadCreditCard_CCFormHasMiddleInitial) { } TEST_F(AutofillManagerTest, - UploadCreditCard_CCFormHasMiddleInitial_DisableComparator) { - DisableAutofillUpstreamUseAutofillProfileComparator(); + UploadCreditCard_CCFormHasMiddleInitial_ComparatorEnabled) { + EnableAutofillUpstreamUseAutofillProfileComparator(); personal_data_.ClearAutofillProfiles(); autofill_manager_->set_credit_card_upload_enabled(true); @@ -6023,11 +6140,15 @@ TEST_F(AutofillManagerTest, EXPECT_CALL(autofill_client_, ConfirmSaveCreditCardLocally(_, _)).Times(0); FormSubmitted(credit_card_form); EXPECT_TRUE(autofill_manager_->credit_card_was_uploaded()); - EXPECT_TRUE(autofill_manager_->GetActiveExperiments().empty()); + EXPECT_THAT( + autofill_manager_->GetActiveExperiments(), + UnorderedElementsAre(kAutofillUpstreamUseAutofillProfileComparator.name)); // Verify that the correct histogram entry (and only that) was logged. ExpectUniqueCardUploadDecision(histogram_tester, AutofillMetrics::UPLOAD_OFFERED); + // Verify that the correct UKM was logged. + ExpectCardUploadDecisionUkm(AutofillMetrics::UPLOAD_OFFERED); } TEST_F(AutofillManagerTest, UploadCreditCard_NoMiddleInitialInCCForm) { @@ -6073,8 +6194,8 @@ TEST_F(AutofillManagerTest, UploadCreditCard_NoMiddleInitialInCCForm) { } TEST_F(AutofillManagerTest, - UploadCreditCard_NoMiddleInitialInCCForm_DisableComparator) { - DisableAutofillUpstreamUseAutofillProfileComparator(); + UploadCreditCard_NoMiddleInitialInCCForm_ComparatorEnabled) { + EnableAutofillUpstreamUseAutofillProfileComparator(); personal_data_.ClearAutofillProfiles(); autofill_manager_->set_credit_card_upload_enabled(true); @@ -6112,6 +6233,8 @@ TEST_F(AutofillManagerTest, // Verify that the correct histogram entry (and only that) was logged. ExpectUniqueCardUploadDecision(histogram_tester, AutofillMetrics::UPLOAD_OFFERED); + // Verify that the correct UKM was logged. + ExpectCardUploadDecisionUkm(AutofillMetrics::UPLOAD_OFFERED); } TEST_F(AutofillManagerTest, UploadCreditCard_CCFormHasMiddleName) { @@ -6139,10 +6262,52 @@ TEST_F(AutofillManagerTest, UploadCreditCard_CCFormHasMiddleName) { base::HistogramTester histogram_tester; + // Names match loosely but we have disabled comparator. Upload should not + // happen. + EXPECT_CALL(autofill_client_, ConfirmSaveCreditCardLocally(_, _)).Times(0); + FormSubmitted(credit_card_form); + EXPECT_FALSE(autofill_manager_->credit_card_was_uploaded()); + EXPECT_TRUE(autofill_manager_->GetActiveExperiments().empty()); + + // Verify that the correct histogram entry (and only that) was logged. + ExpectUniqueCardUploadDecision( + histogram_tester, AutofillMetrics::UPLOAD_NOT_OFFERED_CONFLICTING_NAMES); +} + +TEST_F(AutofillManagerTest, + UploadCreditCard_CCFormHasMiddleName_ComparatorEnabled) { + EnableAutofillUpstreamUseAutofillProfileComparator(); + personal_data_.ClearAutofillProfiles(); + autofill_manager_->set_credit_card_upload_enabled(true); + + // Create, fill and submit address form without middle name. + FormData address_form; + test::CreateTestAddressFormData(&address_form); + FormsSeen({address_form}); + ManuallyFillAddressForm("John", "Adams", "77401", "US", &address_form); + FormSubmitted(address_form); + + // Set up our credit card form data. + FormData credit_card_form; + CreateTestCreditCardFormData(&credit_card_form, true, false); + FormsSeen({credit_card_form}); + + // Edit the name by adding a middle name. + credit_card_form.fields[0].value = ASCIIToUTF16("John Quincy Adams"); + credit_card_form.fields[1].value = ASCIIToUTF16("4111111111111111"); + credit_card_form.fields[2].value = ASCIIToUTF16("11"); + credit_card_form.fields[3].value = ASCIIToUTF16("2017"); + credit_card_form.fields[4].value = ASCIIToUTF16("123"); + + base::HistogramTester histogram_tester; + // Names match loosely, upload should happen. EXPECT_CALL(autofill_client_, ConfirmSaveCreditCardLocally(_, _)).Times(0); FormSubmitted(credit_card_form); EXPECT_TRUE(autofill_manager_->credit_card_was_uploaded()); + EXPECT_THAT( + autofill_manager_->GetActiveExperiments(), + UnorderedElementsAre(kAutofillUpstreamUseAutofillProfileComparator.name)); // Verify that the correct histogram entry (and only that) was logged. ExpectUniqueCardUploadDecision(histogram_tester, @@ -6151,17 +6316,15 @@ TEST_F(AutofillManagerTest, UploadCreditCard_CCFormHasMiddleName) { ExpectCardUploadDecisionUkm(AutofillMetrics::UPLOAD_OFFERED); } -TEST_F(AutofillManagerTest, - UploadCreditCard_CCFormHasMiddleName_DisableComparator) { - DisableAutofillUpstreamUseAutofillProfileComparator(); +TEST_F(AutofillManagerTest, UploadCreditCard_CCFormRemovesMiddleName) { personal_data_.ClearAutofillProfiles(); autofill_manager_->set_credit_card_upload_enabled(true); - // Create, fill and submit address form without middle name. + // Create, fill and submit address form with middle name. FormData address_form; test::CreateTestAddressFormData(&address_form); FormsSeen({address_form}); - ManuallyFillAddressForm("John", "Adams", "77401", "US", &address_form); + ManuallyFillAddressForm("John Quincy", "Adams", "77401", "US", &address_form); FormSubmitted(address_form); // Set up our credit card form data. @@ -6169,8 +6332,8 @@ TEST_F(AutofillManagerTest, CreateTestCreditCardFormData(&credit_card_form, true, false); FormsSeen({credit_card_form}); - // Edit the name by adding a middle name. - credit_card_form.fields[0].value = ASCIIToUTF16("John Quincy Adams"); + // Edit the name by removing middle name. + credit_card_form.fields[0].value = ASCIIToUTF16("John Adams"); credit_card_form.fields[1].value = ASCIIToUTF16("4111111111111111"); credit_card_form.fields[2].value = ASCIIToUTF16("11"); credit_card_form.fields[3].value = ASCIIToUTF16("2017"); @@ -6178,18 +6341,23 @@ TEST_F(AutofillManagerTest, base::HistogramTester histogram_tester; - // Names match loosely but we have disabled comparator. Upload should not - // happen. + // With the comparator disabled, names do not match; upload should not happen. EXPECT_CALL(autofill_client_, ConfirmSaveCreditCardLocally(_, _)).Times(0); FormSubmitted(credit_card_form); EXPECT_FALSE(autofill_manager_->credit_card_was_uploaded()); + EXPECT_TRUE(autofill_manager_->GetActiveExperiments().empty()); // Verify that the correct histogram entry (and only that) was logged. ExpectUniqueCardUploadDecision( histogram_tester, AutofillMetrics::UPLOAD_NOT_OFFERED_CONFLICTING_NAMES); + // Verify that the correct UKM was logged. + ExpectCardUploadDecisionUkm( + AutofillMetrics::UPLOAD_NOT_OFFERED_CONFLICTING_NAMES); } -TEST_F(AutofillManagerTest, UploadCreditCard_CCFormRemovesMiddleName) { +TEST_F(AutofillManagerTest, + UploadCreditCard_CCFormRemovesMiddleName_ComparatorEnabled) { + EnableAutofillUpstreamUseAutofillProfileComparator(); personal_data_.ClearAutofillProfiles(); autofill_manager_->set_credit_card_upload_enabled(true); @@ -6218,6 +6386,9 @@ TEST_F(AutofillManagerTest, UploadCreditCard_CCFormRemovesMiddleName) { EXPECT_CALL(autofill_client_, ConfirmSaveCreditCardLocally(_, _)).Times(0); FormSubmitted(credit_card_form); EXPECT_TRUE(autofill_manager_->credit_card_was_uploaded()); + EXPECT_THAT( + autofill_manager_->GetActiveExperiments(), + UnorderedElementsAre(kAutofillUpstreamUseAutofillProfileComparator.name)); // Verify that the correct histogram entry (and only that) was logged. ExpectUniqueCardUploadDecision(histogram_tester, @@ -6264,6 +6435,7 @@ TEST_F(AutofillManagerTest, UploadCreditCard_NamesHaveToMatch) { EXPECT_CALL(autofill_client_, ConfirmSaveCreditCardLocally(_, _)).Times(0); FormSubmitted(credit_card_form); EXPECT_FALSE(autofill_manager_->credit_card_was_uploaded()); + EXPECT_TRUE(autofill_manager_->GetActiveExperiments().empty()); // Verify that the correct histogram entry (and only that) was logged. ExpectUniqueCardUploadDecision( @@ -6321,116 +6493,6 @@ TEST_F(AutofillManagerTest, UploadCreditCard_IgnoreOldProfiles) { AutofillMetrics::UPLOAD_OFFERED); } -TEST_F(AutofillManagerTest, - UploadCreditCard_IgnoreOldProfiles_CanUseOldProfiles) { - variation_params_.SetVariationParamsWithFeatureAssociations( - kAutofillUpstreamUseNotRecentlyUsedAutofillProfile.name, - {{kAutofillUpstreamMaxMinutesSinceAutofillProfileUseKey, - base::IntToString((kMuchLaterTime - kArbitraryTime).InMinutes() + 1)}}, - {kAutofillUpstreamUseNotRecentlyUsedAutofillProfile.name}); - - // Create the test clock and set the time to a specific value. - TestAutofillClock test_clock; - test_clock.SetNow(kArbitraryTime); - - personal_data_.ClearAutofillProfiles(); - autofill_manager_->set_credit_card_upload_enabled(true); - - // Create, fill and submit two address forms with different names. - FormData address_form1, address_form2; - test::CreateTestAddressFormData(&address_form1); - test::CreateTestAddressFormData(&address_form2); - FormsSeen({address_form1, address_form2}); - - ManuallyFillAddressForm("Flo", "Master", "77401", "US", &address_form1); - FormSubmitted(address_form1); - - // Advance the current time. Since |address_form1| will not be a recently - // used address profile, we will not include it in the candidate profiles - // because we have a recently used address. - test_clock.SetNow(kMuchLaterTime); - - ManuallyFillAddressForm("Master", "Blaster", "77401", "US", &address_form2); - FormSubmitted(address_form2); - - // Set up our credit card form data. - FormData credit_card_form; - CreateTestCreditCardFormData(&credit_card_form, true, false); - FormsSeen(std::vector<FormData>(1, credit_card_form)); - - // Edit the data, but use yet another name, and submit. - credit_card_form.fields[0].value = ASCIIToUTF16("Master Blaster"); - credit_card_form.fields[1].value = ASCIIToUTF16("4111111111111111"); - credit_card_form.fields[2].value = ASCIIToUTF16("11"); - credit_card_form.fields[3].value = ASCIIToUTF16("2017"); - credit_card_form.fields[4].value = ASCIIToUTF16("123"); - - base::HistogramTester histogram_tester; - - // Name matches recently used profile, should offer upload. - EXPECT_CALL(autofill_client_, ConfirmSaveCreditCardLocally(_, _)).Times(0); - FormSubmitted(credit_card_form); - EXPECT_TRUE(autofill_manager_->credit_card_was_uploaded()); - // Recently used profile was available, so did not need to use old profile. - EXPECT_THAT( - autofill_manager_->GetActiveExperiments(), - UnorderedElementsAre(kAutofillUpstreamUseAutofillProfileComparator.name)); - - // Verify that the correct histogram entry (and only that) was logged. - ExpectUniqueCardUploadDecision(histogram_tester, - AutofillMetrics::UPLOAD_OFFERED); -} - -TEST_F(AutofillManagerTest, - UploadCreditCard_NamesHaveToMatch_DisableComparator) { - DisableAutofillUpstreamUseAutofillProfileComparator(); - personal_data_.ClearAutofillProfiles(); - autofill_manager_->set_credit_card_upload_enabled(true); - - // Create, fill and submit two address forms with different names. - FormData address_form1, address_form2; - test::CreateTestAddressFormData(&address_form1); - test::CreateTestAddressFormData(&address_form2); - - std::vector<FormData> address_forms; - address_forms.push_back(address_form1); - address_forms.push_back(address_form2); - FormsSeen(address_forms); - - ManuallyFillAddressForm("Flo", "Master", "77401", "US", &address_form1); - FormSubmitted(address_form1); - - ManuallyFillAddressForm("Master", "Blaster", "77401", "US", &address_form2); - FormSubmitted(address_form2); - - // Set up our credit card form data. - FormData credit_card_form; - CreateTestCreditCardFormData(&credit_card_form, true, false); - FormsSeen({credit_card_form}); - - // Edit the data, but use yet another name, and submit. - credit_card_form.fields[0].value = ASCIIToUTF16("Bob Master"); - FormsSeen({credit_card_form}); - - // Edit the credit card form 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"); - credit_card_form.fields[4].value = ASCIIToUTF16("123"); - - base::HistogramTester histogram_tester; - - // Names are required to match, upload should not happen. - 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. - ExpectUniqueCardUploadDecision( - histogram_tester, AutofillMetrics::UPLOAD_NOT_OFFERED_CONFLICTING_NAMES); -} - TEST_F(AutofillManagerTest, UploadCreditCard_LogPreviousUseDate) { // Create the test clock and set the time to a specific value. TestAutofillClock test_clock; @@ -6974,7 +7036,46 @@ TEST_F(AutofillManagerTest, ShouldUploadForm) { // Verify that no suggestions are shown on desktop for non credit card related // fields if the initiating field has the "autocomplete" attribute set to off. -TEST_F(AutofillManagerTest, DisplaySuggestions_AutocompleteOff_AddressField) { +TEST_F(AutofillManagerTest, + DisplaySuggestions_AutocompleteOffNotRespected_AddressField) { + // Set up an address form. + FormData mixed_form; + mixed_form.name = ASCIIToUTF16("MyForm"); + mixed_form.origin = GURL("https://myform.com/form.html"); + mixed_form.action = GURL("https://myform.com/submit.html"); + FormFieldData field; + test::CreateTestFormField("First name", "firstname", "", "text", &field); + field.should_autocomplete = false; + mixed_form.fields.push_back(field); + test::CreateTestFormField("Last name", "lastname", "", "text", &field); + field.should_autocomplete = true; + mixed_form.fields.push_back(field); + test::CreateTestFormField("Address", "address", "", "text", &field); + field.should_autocomplete = true; + mixed_form.fields.push_back(field); + std::vector<FormData> mixed_forms(1, mixed_form); + FormsSeen(mixed_forms); + + // Suggestions should be displayed on desktop for this field in all + // circumstances. + GetAutofillSuggestions(mixed_form, mixed_form.fields[0]); + EXPECT_TRUE(external_delegate_->on_suggestions_returned_seen()); + + // Suggestions should always be displayed for all the other fields. + for (size_t i = 1U; i < mixed_form.fields.size(); ++i) { + GetAutofillSuggestions(mixed_form, mixed_form.fields[i]); + EXPECT_TRUE(external_delegate_->on_suggestions_returned_seen()); + } +} + +// Verify that no suggestions are shown on desktop for non credit card related +// fields if the initiating field has the "autocomplete" attribute set to off +// and the feature to autofill all addresses is also off. +TEST_F(AutofillManagerTest, + DisplaySuggestions_AutocompleteOffRespected_AddressField) { + base::test::ScopedFeatureList feature_list; + feature_list.InitAndDisableFeature(kAutofillAlwaysFillAddresses); + // Set up an address form. FormData mixed_form; mixed_form.name = ASCIIToUTF16("MyForm"); diff --git a/chromium/components/autofill/core/browser/autofill_merge_unittest.cc b/chromium/components/autofill/core/browser/autofill_merge_unittest.cc index d04acca02c4..cd1b3ba0636 100644 --- a/chromium/components/autofill/core/browser/autofill_merge_unittest.cc +++ b/chromium/components/autofill/core/browser/autofill_merge_unittest.cc @@ -117,7 +117,7 @@ class PersonalDataManagerMock : public PersonalDataManager { // PersonalDataManager: std::string SaveImportedProfile(const AutofillProfile& profile) override; - std::vector<AutofillProfile*> web_profiles() const override; + std::vector<AutofillProfile*> GetProfiles() const override; private: std::vector<std::unique_ptr<AutofillProfile>> profiles_; @@ -146,7 +146,7 @@ std::string PersonalDataManagerMock::SaveImportedProfile( return merged_guid; } -std::vector<AutofillProfile*> PersonalDataManagerMock::web_profiles() const { +std::vector<AutofillProfile*> PersonalDataManagerMock::GetProfiles() const { std::vector<AutofillProfile*> result; for (const auto& profile : profiles_) result.push_back(profile.get()); @@ -273,7 +273,10 @@ void AutofillMergeTest::MergeProfiles(const std::string& profiles, std::unique_ptr<CreditCard> imported_credit_card; bool imported_credit_card_matches_masked_server_credit_card; personal_data_.ImportFormData( - form_structure, false, &imported_credit_card, + form_structure, + true, // credit card autofill enabled + false, // should return local card + &imported_credit_card, &imported_credit_card_matches_masked_server_credit_card); EXPECT_FALSE(imported_credit_card); @@ -282,7 +285,7 @@ void AutofillMergeTest::MergeProfiles(const std::string& profiles, } } - *merged_profiles = SerializeProfiles(personal_data_.web_profiles()); + *merged_profiles = SerializeProfiles(personal_data_.GetProfiles()); } ServerFieldType AutofillMergeTest::StringToFieldType(const std::string& str) { diff --git a/chromium/components/autofill/core/browser/autofill_metrics.cc b/chromium/components/autofill/core/browser/autofill_metrics.cc index 3499f11478a..694016c5f95 100644 --- a/chromium/components/autofill/core/browser/autofill_metrics.cc +++ b/chromium/components/autofill/core/browser/autofill_metrics.cc @@ -9,6 +9,7 @@ #include <vector> #include "base/logging.h" +#include "base/metrics/histogram_functions.h" #include "base/metrics/histogram_macros.h" #include "base/metrics/sparse_histogram.h" #include "base/metrics/user_metrics.h" @@ -18,6 +19,7 @@ #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/credit_card.h" #include "components/autofill/core/browser/form_structure.h" #include "components/autofill/core/common/autofill_clock.h" #include "components/autofill/core/common/form_data.h" @@ -232,13 +234,9 @@ void LogUMAHistogramEnumeration(const std::string& name, DCHECK_LT(sample, boundary_value); // Note: This leaks memory, which is expected behavior. - base::HistogramBase* histogram = - base::LinearHistogram::FactoryGet( - name, - 1, - boundary_value, - boundary_value + 1, - base::HistogramBase::kUmaTargetedHistogramFlag); + base::HistogramBase* histogram = base::LinearHistogram::FactoryGet( + name, 1, boundary_value, boundary_value + 1, + base::HistogramBase::kUmaTargetedHistogramFlag); histogram->Add(sample); } @@ -247,13 +245,9 @@ void LogUMAHistogramEnumeration(const std::string& name, void LogUMAHistogramLongTimes(const std::string& name, const base::TimeDelta& duration) { // Note: This leaks memory, which is expected behavior. - base::HistogramBase* histogram = - base::Histogram::FactoryTimeGet( - name, - base::TimeDelta::FromMilliseconds(1), - base::TimeDelta::FromHours(1), - 50, - base::HistogramBase::kUmaTargetedHistogramFlag); + base::HistogramBase* histogram = base::Histogram::FactoryTimeGet( + name, base::TimeDelta::FromMilliseconds(1), base::TimeDelta::FromHours(1), + 50, base::HistogramBase::kUmaTargetedHistogramFlag); histogram->AddTime(duration); } @@ -701,7 +695,7 @@ void AutofillMetrics::LogServerPredictionQualityMetrics( QualityMetricType metric_type) { LogPredictionQualityMetrics( PREDICTION_SOURCE_SERVER, - AutofillType(field.server_type()).GetStorableType(), + AutofillType(field.overall_server_type()).GetStorableType(), form_interactions_ukm_logger, form, field, metric_type); } @@ -723,52 +717,82 @@ void AutofillMetrics::LogServerQueryMetric(ServerQueryMetric metric) { } // static -void AutofillMetrics::LogUserHappinessMetric(UserHappinessMetric metric) { +void AutofillMetrics::LogUserHappinessMetric(UserHappinessMetric metric, + FieldTypeGroup field_type_group) { + LogUserHappinessMetric( + metric, {FormTypes::FieldTypeGroupToFormType(field_type_group)}); +} + +// static +void AutofillMetrics::LogUserHappinessMetric( + UserHappinessMetric metric, + const std::set<FormType>& form_types) { DCHECK_LT(metric, NUM_USER_HAPPINESS_METRICS); UMA_HISTOGRAM_ENUMERATION("Autofill.UserHappiness", metric, NUM_USER_HAPPINESS_METRICS); + if (base::ContainsKey(form_types, CREDIT_CARD_FORM)) { + UMA_HISTOGRAM_ENUMERATION("Autofill.UserHappiness.CreditCard", metric, + NUM_USER_HAPPINESS_METRICS); + } + if (base::ContainsKey(form_types, ADDRESS_FORM)) { + UMA_HISTOGRAM_ENUMERATION("Autofill.UserHappiness.Address", metric, + NUM_USER_HAPPINESS_METRICS); + } + if (base::ContainsKey(form_types, PASSWORD_FORM)) { + UMA_HISTOGRAM_ENUMERATION("Autofill.UserHappiness.Password", metric, + NUM_USER_HAPPINESS_METRICS); + } + if (base::ContainsKey(form_types, UNKNOWN_FORM_TYPE)) { + UMA_HISTOGRAM_ENUMERATION("Autofill.UserHappiness.Unknown", metric, + NUM_USER_HAPPINESS_METRICS); + } } // static void AutofillMetrics::LogFormFillDurationFromLoadWithAutofill( const base::TimeDelta& duration) { - UMA_HISTOGRAM_CUSTOM_TIMES("Autofill.FillDuration.FromLoad.WithAutofill", - duration, - base::TimeDelta::FromMilliseconds(100), - base::TimeDelta::FromMinutes(10), - 50); + LogFormFillDuration("Autofill.FillDuration.FromLoad.WithAutofill", duration); } // static void AutofillMetrics::LogFormFillDurationFromLoadWithoutAutofill( const base::TimeDelta& duration) { - UMA_HISTOGRAM_CUSTOM_TIMES("Autofill.FillDuration.FromLoad.WithoutAutofill", - duration, - base::TimeDelta::FromMilliseconds(100), - base::TimeDelta::FromMinutes(10), - 50); + LogFormFillDuration("Autofill.FillDuration.FromLoad.WithoutAutofill", + duration); } // static -void AutofillMetrics::LogFormFillDurationFromInteractionWithAutofill( +void AutofillMetrics::LogFormFillDurationFromInteraction( + const std::set<FormType>& form_types, + bool used_autofill, const base::TimeDelta& duration) { - UMA_HISTOGRAM_CUSTOM_TIMES( - "Autofill.FillDuration.FromInteraction.WithAutofill", - duration, - base::TimeDelta::FromMilliseconds(100), - base::TimeDelta::FromMinutes(10), - 50); + std::string parent_metric; + if (used_autofill) { + parent_metric = "Autofill.FillDuration.FromInteraction.WithAutofill"; + } else { + parent_metric = "Autofill.FillDuration.FromInteraction.WithoutAutofill"; + } + LogFormFillDuration(parent_metric, duration); + if (base::ContainsKey(form_types, CREDIT_CARD_FORM)) { + LogFormFillDuration(parent_metric + ".CreditCard", duration); + } + if (base::ContainsKey(form_types, ADDRESS_FORM)) { + LogFormFillDuration(parent_metric + ".Address", duration); + } + if (base::ContainsKey(form_types, PASSWORD_FORM)) { + LogFormFillDuration(parent_metric + ".Password", duration); + } + if (base::ContainsKey(form_types, UNKNOWN_FORM_TYPE)) { + LogFormFillDuration(parent_metric + ".Unknown", duration); + } } // static -void AutofillMetrics::LogFormFillDurationFromInteractionWithoutAutofill( - const base::TimeDelta& duration) { - UMA_HISTOGRAM_CUSTOM_TIMES( - "Autofill.FillDuration.FromInteraction.WithoutAutofill", - duration, - base::TimeDelta::FromMilliseconds(100), - base::TimeDelta::FromMinutes(10), - 50); +void AutofillMetrics::LogFormFillDuration(const std::string& metric, + const base::TimeDelta& duration) { + base::UmaHistogramCustomTimes(metric, duration, + base::TimeDelta::FromMilliseconds(100), + base::TimeDelta::FromMinutes(10), 50); } // static @@ -797,14 +821,118 @@ void AutofillMetrics::LogStoredProfileDaysSinceLastUse(size_t days) { } // static -void AutofillMetrics::LogStoredLocalCreditCardCount(size_t num_local_cards) { - UMA_HISTOGRAM_COUNTS("Autofill.StoredLocalCreditCardCount", num_local_cards); -} +void AutofillMetrics::LogStoredCreditCardMetrics( + const std::vector<std::unique_ptr<CreditCard>>& local_cards, + const std::vector<std::unique_ptr<CreditCard>>& server_cards, + base::TimeDelta disused_data_threshold) { + size_t num_local_cards = 0; + size_t num_masked_cards = 0; + size_t num_unmasked_cards = 0; + size_t num_disused_local_cards = 0; + size_t num_disused_masked_cards = 0; + size_t num_disused_unmasked_cards = 0; + + // Concatenate the local and server cards into one big collection of raw + // CreditCard pointers. + std::vector<const CreditCard*> credit_cards; + credit_cards.reserve(local_cards.size() + server_cards.size()); + for (const auto* collection : {&local_cards, &server_cards}) { + for (const auto& card : *collection) { + credit_cards.push_back(card.get()); + } + } -// static -void AutofillMetrics::LogStoredServerCreditCardCounts( - size_t num_masked_cards, - size_t num_unmasked_cards) { + // Iterate over all of the cards and gather metrics. + const base::Time now = AutofillClock::Now(); + for (const CreditCard* card : credit_cards) { + const base::TimeDelta time_since_last_use = now - card->use_date(); + const int days_since_last_use = time_since_last_use.InDays(); + const int disused_delta = + (time_since_last_use > disused_data_threshold) ? 1 : 0; + UMA_HISTOGRAM_COUNTS_1000("Autofill.DaysSinceLastUse.StoredCreditCard", + days_since_last_use); + switch (card->record_type()) { + case CreditCard::LOCAL_CARD: + UMA_HISTOGRAM_COUNTS_1000( + "Autofill.DaysSinceLastUse.StoredCreditCard.Local", + days_since_last_use); + num_local_cards += 1; + num_disused_local_cards += disused_delta; + break; + case CreditCard::MASKED_SERVER_CARD: + UMA_HISTOGRAM_COUNTS_1000( + "Autofill.DaysSinceLastUse.StoredCreditCard.Server", + days_since_last_use); + UMA_HISTOGRAM_COUNTS_1000( + "Autofill.DaysSinceLastUse.StoredCreditCard.Server.Masked", + days_since_last_use); + num_masked_cards += 1; + num_disused_masked_cards += disused_delta; + break; + case CreditCard::FULL_SERVER_CARD: + UMA_HISTOGRAM_COUNTS_1000( + "Autofill.DaysSinceLastUse.StoredCreditCard.Server", + days_since_last_use); + UMA_HISTOGRAM_COUNTS_1000( + "Autofill.DaysSinceLastUse.StoredCreditCard.Server.Unmasked", + days_since_last_use); + num_unmasked_cards += 1; + num_disused_unmasked_cards += disused_delta; + break; + } + } + + // Calculate some summary info. + const size_t num_server_cards = num_masked_cards + num_unmasked_cards; + const size_t num_cards = num_local_cards + num_server_cards; + const size_t num_disused_server_cards = + num_disused_masked_cards + num_disused_unmasked_cards; + const size_t num_disused_cards = + num_disused_local_cards + num_disused_server_cards; + + // Log the overall counts. + UMA_HISTOGRAM_COUNTS_1000("Autofill.StoredCreditCardCount", num_cards); + UMA_HISTOGRAM_COUNTS_1000("Autofill.StoredCreditCardCount.Local", + num_local_cards); + UMA_HISTOGRAM_COUNTS_1000("Autofill.StoredCreditCardCount.Server", + num_server_cards); + UMA_HISTOGRAM_COUNTS_1000("Autofill.StoredCreditCardCount.Server.Masked", + num_masked_cards); + UMA_HISTOGRAM_COUNTS_1000("Autofill.StoredCreditCardCount.Server.Unmasked", + num_unmasked_cards); + + // For card types held by the user, log how many are disused. + if (num_cards) { + UMA_HISTOGRAM_COUNTS_1000("Autofill.StoredCreditCardDisusedCount", + num_disused_cards); + } + if (num_local_cards) { + UMA_HISTOGRAM_COUNTS_1000("Autofill.StoredCreditCardDisusedCount.Local", + num_disused_local_cards); + } + if (num_server_cards) { + UMA_HISTOGRAM_COUNTS_1000("Autofill.StoredCreditCardDisusedCount.Server", + num_disused_server_cards); + } + if (num_masked_cards) { + UMA_HISTOGRAM_COUNTS_1000( + "Autofill.StoredCreditCardDisusedCount.Server.Masked", + num_disused_masked_cards); + } + if (num_unmasked_cards) { + UMA_HISTOGRAM_COUNTS_1000( + "Autofill.StoredCreditCardDisusedCount.Server.Unmasked", + num_disused_unmasked_cards); + } + + // Legacy histogram names. + // Validated by: + // AutofillMetricsTest.StoredLocalCreditCardCount + // AutofillMetricsTest.StoredServerCreditCardCount_Masked + // AutofillMetricsTest.StoredServerCreditCardCount_Unmasked + // TODO(crbug/762131): Delete these in 2018/Q2 once enough UMA history is + // established for the new names. + UMA_HISTOGRAM_COUNTS("Autofill.StoredLocalCreditCardCount", num_local_cards); UMA_HISTOGRAM_COUNTS_1000("Autofill.StoredServerCreditCardCount.Masked", num_masked_cards); UMA_HISTOGRAM_COUNTS_1000("Autofill.StoredServerCreditCardCount.Unmasked", @@ -812,6 +940,18 @@ void AutofillMetrics::LogStoredServerCreditCardCounts( } // static +void AutofillMetrics::LogNumberOfCreditCardsSuppressedForDisuse( + size_t num_cards) { + UMA_HISTOGRAM_COUNTS_1000("Autofill.CreditCardsSuppressedForDisuse", + num_cards); +} + +// static +void AutofillMetrics::LogNumberOfCreditCardsDeletedForDisuse(size_t num_cards) { + UMA_HISTOGRAM_COUNTS_1000("Autofill.CreditCardsDeletedForDisuse", num_cards); +} + +// static void AutofillMetrics::LogNumberOfProfilesAtAutofillableFormSubmission( size_t num_profiles) { UMA_HISTOGRAM_COUNTS( @@ -833,6 +973,12 @@ void AutofillMetrics::LogNumberOfAddressesSuppressedForDisuse( } // static +void AutofillMetrics::LogNumberOfAddressesDeletedForDisuse( + size_t num_profiles) { + UMA_HISTOGRAM_COUNTS_1000("Autofill.AddressesDeletedForDisuse", num_profiles); +} + +// static void AutofillMetrics::LogAddressSuggestionsCount(size_t num_suggestions) { UMA_HISTOGRAM_COUNTS("Autofill.AddressSuggestionsCount", num_suggestions); } @@ -1011,6 +1157,8 @@ AutofillMetrics::FormEventLogger::FormEventLogger( has_logged_will_submit_(false), has_logged_submitted_(false), has_logged_bank_name_available_(false), + has_logged_detected_card_in_submitted_form_(false), + has_logged_submitted_known_card(false), logged_suggestion_filled_was_server_data_(false), logged_suggestion_filled_was_masked_server_card_(false), form_interactions_ukm_logger_(form_interactions_ukm_logger) {} @@ -1175,7 +1323,7 @@ void AutofillMetrics::FormEventLogger::OnWillSubmitForm() { base::RecordAction(base::UserMetricsAction("Autofill_OnWillSubmitForm")); } -void AutofillMetrics::FormEventLogger::OnFormSubmitted() { +void AutofillMetrics::FormEventLogger::OnFormSubmitted(bool force_logging) { // Not logging this kind of form if we haven't logged a user interaction. if (!has_logged_interacted_) return; @@ -1196,8 +1344,20 @@ void AutofillMetrics::FormEventLogger::OnFormSubmitted() { Log(AutofillMetrics::FORM_EVENT_LOCAL_SUGGESTION_SUBMITTED_ONCE); } - if (has_logged_suggestions_shown_) { + if (has_logged_suggestions_shown_ || force_logging) { Log(AutofillMetrics::FORM_EVENT_SUGGESTION_SHOWN_SUBMITTED_ONCE); + if (is_for_credit_card_ && !has_logged_suggestion_filled_) { + if (!has_logged_detected_card_in_submitted_form_) { + Log(AutofillMetrics:: + FORM_EVENT_SUBMIT_WITHOUT_SELECTING_SUGGESTIONS_NO_CARD); + } else if (has_logged_submitted_known_card) { + Log(AutofillMetrics:: + FORM_EVENT_SUBMIT_WITHOUT_SELECTING_SUGGESTIONS_KNOWN_CARD); + } else { + Log(AutofillMetrics:: + FORM_EVENT_SUBMIT_WITHOUT_SELECTING_SUGGESTIONS_UNKNOWN_CARD); + } + } } } @@ -1205,6 +1365,14 @@ void AutofillMetrics::FormEventLogger::SetBankNameAvailable() { has_logged_bank_name_available_ = true; } +void AutofillMetrics::FormEventLogger::DetectedCardInSubmittedForm() { + has_logged_detected_card_in_submitted_form_ = true; +} + +void AutofillMetrics::FormEventLogger::SubmittedKnownCard() { + has_logged_submitted_known_card = true; +} + void AutofillMetrics::FormEventLogger::Log(FormEvent event) const { DCHECK_LT(event, NUM_FORM_EVENTS); std::string name("Autofill.FormEvents."); @@ -1284,7 +1452,7 @@ void AutofillMetrics::FormInteractionsUkmLogger::LogSuggestionsShown( ukm::builders::Autofill_SuggestionsShown(source_id_) .SetHeuristicType(static_cast<int>(field.heuristic_type())) .SetHtmlFieldType(static_cast<int>(field.html_type())) - .SetServerType(static_cast<int>(field.server_type())) + .SetServerType(static_cast<int>(field.overall_server_type())) .SetMillisecondsSinceFormParsed( MillisecondsSinceFormParsed(form_parsed_timestamp)) .Record(ukm_recorder_); @@ -1332,7 +1500,7 @@ void AutofillMetrics::FormInteractionsUkmLogger::LogTextFieldDidChange( ukm::builders::Autofill_TextFieldDidChange(source_id_) .SetFieldTypeGroup(static_cast<int>(field.Type().group())) .SetHeuristicType(static_cast<int>(field.heuristic_type())) - .SetServerType(static_cast<int>(field.server_type())) + .SetServerType(static_cast<int>(field.overall_server_type())) .SetHtmlFieldType(static_cast<int>(field.html_type())) .SetHtmlFieldMode(static_cast<int>(field.html_mode())) .SetIsAutofilled(field.is_autofilled) diff --git a/chromium/components/autofill/core/browser/autofill_metrics.h b/chromium/components/autofill/core/browser/autofill_metrics.h index 3d5f9bafd11..7f0dae9c231 100644 --- a/chromium/components/autofill/core/browser/autofill_metrics.h +++ b/chromium/components/autofill/core/browser/autofill_metrics.h @@ -16,6 +16,7 @@ #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/browser/form_types.h" #include "components/autofill/core/common/autofill_pref_names.h" #include "components/autofill/core/common/form_field_data.h" #include "components/autofill/core/common/signatures_util.h" @@ -24,6 +25,7 @@ namespace autofill { class AutofillField; +class CreditCard; class AutofillMetrics { public: @@ -424,6 +426,16 @@ class AutofillMetrics { // submitted. If the submission is not interrupted by JavaScript, the "form // submitted" event above will also be logged. FORM_EVENT_SUGGESTION_SHOWN_WILL_SUBMIT_ONCE, + // A dropdown with credit card suggestions was shown, but they were not used + // to fill the form. Depending on the user submitting a card known by the + // browser, submitting a card that the browser does not know about, + // or Autofill failing to detect the card, one of the following will be + // triggered. Only one of the following three metrics will be triggered per + // page load. + FORM_EVENT_SUBMIT_WITHOUT_SELECTING_SUGGESTIONS_KNOWN_CARD, + FORM_EVENT_SUBMIT_WITHOUT_SELECTING_SUGGESTIONS_UNKNOWN_CARD, + FORM_EVENT_SUBMIT_WITHOUT_SELECTING_SUGGESTIONS_NO_CARD, + NUM_FORM_EVENTS, }; @@ -683,7 +695,11 @@ class AutofillMetrics { static void LogServerQueryMetric(ServerQueryMetric metric); - static void LogUserHappinessMetric(UserHappinessMetric metric); + static void LogUserHappinessMetric(UserHappinessMetric metric, + FieldTypeGroup field_type_group); + + static void LogUserHappinessMetric(UserHappinessMetric metric, + const std::set<FormType>& form_types); // Logs |event| to the unmask prompt events histogram. static void LogUnmaskPromptEvent(UnmaskPromptEvent event); @@ -720,17 +736,16 @@ class AutofillMetrics { static void LogFormFillDurationFromLoadWithoutAutofill( const base::TimeDelta& duration); - // This should be called when a form that has been Autofilled is submitted. - // |duration| should be the time elapsed between the initial form interaction - // and submission. - static void LogFormFillDurationFromInteractionWithAutofill( + // This should be called when a form is submitted. |duration| should be the + // time elapsed between the initial form interaction and submission. This + // metric is sliced by |form_type| and |used_autofill|. + static void LogFormFillDurationFromInteraction( + const std::set<FormType>& form_types, + bool used_autofill, const base::TimeDelta& duration); - // This should be called when a fillable form that has not been Autofilled is - // submitted. |duration| should be the time elapsed between the initial form - // interaction and submission. - static void LogFormFillDurationFromInteractionWithoutAutofill( - const base::TimeDelta& duration); + static void LogFormFillDuration(const std::string& metric, + const base::TimeDelta& duration); // This should be called each time a page containing forms is loaded. static void LogIsAutofillEnabledAtPageLoad(bool enabled); @@ -750,12 +765,24 @@ class AutofillMetrics { // called once per address profile each time a new chrome profile is launched. static void LogStoredProfileDaysSinceLastUse(size_t days); - // This should be called each time a new chrome profile is launched. - static void LogStoredLocalCreditCardCount(size_t num_local_cards); - - // This should be called each time a new chrome profile is launched. - static void LogStoredServerCreditCardCounts(size_t num_masked_cards, - size_t num_unmasked_cards); + // Logs various metrics about the local and server cards associated with a + // profile. This should be called each time a new chrome profile is launched. + static void LogStoredCreditCardMetrics( + const std::vector<std::unique_ptr<CreditCard>>& local_cards, + const std::vector<std::unique_ptr<CreditCard>>& server_cards, + base::TimeDelta disused_data_threshold); + + // Log the number of autofill credit card suggestions suppressed because they + // have not been used for a long time and are expired. Note that these cards + // are only suppressed when the user has not typed any data into the field + // from which autofill is triggered. Credit cards matching something the user + // has types are always offered, regardless of how recently they have been + // used. + static void LogNumberOfCreditCardsSuppressedForDisuse(size_t num_cards); + + // Log the number of autofill credit card deleted during major version upgrade + // because they have not been used for a long time and are expired. + static void LogNumberOfCreditCardsDeletedForDisuse(size_t num_cards); // Log the number of profiles available when an autofillable form is // submitted. @@ -774,6 +801,12 @@ class AutofillMetrics { // always offered, regardless of how recently they have been used. static void LogNumberOfAddressesSuppressedForDisuse(size_t num_profiles); + // Log the number of unverified autofill addresses deleted because they have + // not been used for a long time, and are not used as billing addresses of + // valid credit cards. Note the deletion only happens once per major version + // upgrade. + static void LogNumberOfAddressesDeletedForDisuse(size_t num_profiles); + // Log the number of Autofill address suggestions presented to the user when // filling a form. static void LogAddressSuggestionsCount(size_t num_suggestions); @@ -889,10 +922,14 @@ class AutofillMetrics { void OnWillSubmitForm(); - void OnFormSubmitted(); + void OnFormSubmitted(bool force_logging); void SetBankNameAvailable(); + void DetectedCardInSubmittedForm(); + + void SubmittedKnownCard(); + private: void Log(FormEvent event) const; void Log(BankNameDisplayedFormEvent event) const; @@ -908,6 +945,8 @@ class AutofillMetrics { bool has_logged_will_submit_; bool has_logged_submitted_; bool has_logged_bank_name_available_; + bool has_logged_detected_card_in_submitted_form_; + bool has_logged_submitted_known_card; bool logged_suggestion_filled_was_server_data_; bool logged_suggestion_filled_was_masked_server_card_; diff --git a/chromium/components/autofill/core/browser/autofill_metrics_unittest.cc b/chromium/components/autofill/core/browser/autofill_metrics_unittest.cc index 86aec540f46..9bb357a69b4 100644 --- a/chromium/components/autofill/core/browser/autofill_metrics_unittest.cc +++ b/chromium/components/autofill/core/browser/autofill_metrics_unittest.cc @@ -32,6 +32,7 @@ #include "components/autofill/core/browser/test_autofill_client.h" #include "components/autofill/core/browser/test_autofill_driver.h" #include "components/autofill/core/browser/webdata/autofill_webdata_service.h" +#include "components/autofill/core/common/autofill_clock.h" #include "components/autofill/core/common/form_data.h" #include "components/autofill/core/common/form_field_data.h" #include "components/prefs/pref_service.h" @@ -89,13 +90,14 @@ class TestPersonalDataManager : public PersonalDataManager { // Overridden to avoid a trip to the database. This should be a no-op except // for the side-effect of logging the profile count. void LoadProfiles() override { + pending_profiles_query_ = 123; + pending_server_profiles_query_ = 124; { std::vector<std::unique_ptr<AutofillProfile>> profiles; web_profiles_.swap(profiles); std::unique_ptr<WDTypedResult> result = base::MakeUnique< WDResult<std::vector<std::unique_ptr<AutofillProfile>>>>( AUTOFILL_PROFILES_RESULT, std::move(profiles)); - pending_profiles_query_ = 123; OnWebDataServiceRequestDone(pending_profiles_query_, std::move(result)); } { @@ -104,7 +106,6 @@ class TestPersonalDataManager : public PersonalDataManager { std::unique_ptr<WDTypedResult> result = base::MakeUnique< WDResult<std::vector<std::unique_ptr<AutofillProfile>>>>( AUTOFILL_PROFILES_RESULT, std::move(profiles)); - pending_server_profiles_query_ = 124; OnWebDataServiceRequestDone(pending_server_profiles_query_, std::move(result)); } @@ -112,13 +113,14 @@ class TestPersonalDataManager : public PersonalDataManager { // Overridden to avoid a trip to the database. void LoadCreditCards() override { + pending_creditcards_query_ = 125; + pending_server_creditcards_query_ = 126; { std::vector<std::unique_ptr<CreditCard>> credit_cards; local_credit_cards_.swap(credit_cards); std::unique_ptr<WDTypedResult> result = base::MakeUnique<WDResult<std::vector<std::unique_ptr<CreditCard>>>>( AUTOFILL_CREDITCARDS_RESULT, std::move(credit_cards)); - pending_creditcards_query_ = 125; OnWebDataServiceRequestDone(pending_creditcards_query_, std::move(result)); } @@ -128,7 +130,6 @@ class TestPersonalDataManager : public PersonalDataManager { std::unique_ptr<WDTypedResult> result = base::MakeUnique<WDResult<std::vector<std::unique_ptr<CreditCard>>>>( AUTOFILL_CREDITCARDS_RESULT, std::move(credit_cards)); - pending_server_creditcards_query_ = 126; OnWebDataServiceRequestDone(pending_server_creditcards_query_, std::move(result)); } @@ -269,7 +270,7 @@ class TestFormStructure : public FormStructure { AutofillField* form_field = field(i); ASSERT_TRUE(form_field); form_field->set_heuristic_type(heuristic_types[i]); - form_field->set_server_type(server_types[i]); + form_field->set_overall_server_type(server_types[i]); } UpdateAutofillCount(); @@ -1308,13 +1309,13 @@ TEST_F(AutofillMetricsTest, QualityMetrics_BasedOnAutocomplete) { AutofillQueryResponseContents response; // Server response will match with autocomplete. - response.add_field()->set_autofill_type(NAME_LAST); + response.add_field()->set_overall_type_prediction(NAME_LAST); // Server response will NOT match with autocomplete. - response.add_field()->set_autofill_type(NAME_FIRST); + response.add_field()->set_overall_type_prediction(NAME_FIRST); // Server response will have no data. - response.add_field()->set_autofill_type(NO_SERVER_DATA); + response.add_field()->set_overall_type_prediction(NO_SERVER_DATA); // Not logged. - response.add_field()->set_autofill_type(NAME_MIDDLE); + response.add_field()->set_overall_type_prediction(NAME_MIDDLE); std::string response_string; ASSERT_TRUE(response.SerializeToString(&response_string)); @@ -1408,8 +1409,8 @@ TEST_F(AutofillMetricsTest, UpiVirtualPaymentAddress) { 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); + heuristic_types.push_back(ADDRESS_HOME_LINE1); + server_types.push_back(ADDRESS_HOME_LINE1); // Simulate having seen this form on page load. autofill_manager_->AddSeenForm(form, heuristic_types, server_types); @@ -1420,6 +1421,12 @@ TEST_F(AutofillMetricsTest, UpiVirtualPaymentAddress) { histogram_tester.ExpectBucketCount( "Autofill.UserHappiness", AutofillMetrics::USER_DID_ENTER_UPI_VPA, 1); + histogram_tester.ExpectBucketCount("Autofill.UserHappiness.Address", + AutofillMetrics::USER_DID_ENTER_UPI_VPA, + 1); + histogram_tester.ExpectTotalCount("Autofill.UserHappiness.CreditCard", 0); + histogram_tester.ExpectTotalCount("Autofill.UserHappiness.Password", 0); + histogram_tester.ExpectTotalCount("Autofill.UserHappiness.Unknown", 0); } // Verify that when a field is annotated with the autocomplete attribute, its @@ -1978,6 +1985,126 @@ TEST_F(AutofillMetricsTest, UkmDeveloperEngagement_LogUpiVpaTypeHint) { } } +TEST_F(AutofillMetricsTest, LogStoredCreditCardMetrics) { + // Helper timestamps for setting up the test data. + base::Time now = AutofillClock::Now(); + base::Time one_month_ago = now - base::TimeDelta::FromDays(30); + base::Time::Exploded now_exploded; + base::Time::Exploded one_month_ago_exploded; + now.LocalExplode(&now_exploded); + one_month_ago.LocalExplode(&one_month_ago_exploded); + + std::vector<std::unique_ptr<CreditCard>> local_cards; + std::vector<std::unique_ptr<CreditCard>> server_cards; + local_cards.reserve(2); + server_cards.reserve(10); + + // Create in-use and in-disuse cards of each record type: 1 of each for local, + // 2 of each for masked, and 3 of each for unmasked. + const std::vector<CreditCard::RecordType> record_types{ + CreditCard::LOCAL_CARD, CreditCard::MASKED_SERVER_CARD, + CreditCard::FULL_SERVER_CARD}; + int num_cards_of_type = 0; + for (auto record_type : record_types) { + num_cards_of_type += 1; + for (int i = 0; i < num_cards_of_type; ++i) { + // Create a card that's still in active use. + CreditCard card_in_use = test::GetRandomCreditCard(record_type); + card_in_use.set_use_date(now - base::TimeDelta::FromDays(30)); + card_in_use.set_use_count(10); + + // Create a card that's not in active use. + CreditCard card_in_disuse = test::GetRandomCreditCard(record_type); + card_in_disuse.SetExpirationYear(one_month_ago_exploded.year); + card_in_disuse.SetExpirationMonth(one_month_ago_exploded.month); + card_in_disuse.set_use_date(now - base::TimeDelta::FromDays(200)); + card_in_disuse.set_use_count(10); + + // Add the cards to the personal data manager in the appropriate way. + auto& repo = + (record_type == CreditCard::LOCAL_CARD) ? local_cards : server_cards; + repo.push_back(base::MakeUnique<CreditCard>(std::move(card_in_use))); + repo.push_back(base::MakeUnique<CreditCard>(std::move(card_in_disuse))); + } + } + + // Log the stored credit card metrics for the cards configured above. + base::HistogramTester histogram_tester; + AutofillMetrics::LogStoredCreditCardMetrics(local_cards, server_cards, + base::TimeDelta::FromDays(180)); + + // Validate the basic count metrics. + histogram_tester.ExpectTotalCount("Autofill.StoredCreditCardCount", 1); + histogram_tester.ExpectTotalCount("Autofill.StoredCreditCardCount.Local", 1); + histogram_tester.ExpectTotalCount("Autofill.StoredCreditCardCount.Server", 1); + histogram_tester.ExpectTotalCount( + "Autofill.StoredCreditCardCount.Server.Masked", 1); + histogram_tester.ExpectTotalCount( + "Autofill.StoredCreditCardCount.Server.Unmasked", 1); + histogram_tester.ExpectBucketCount("Autofill.StoredCreditCardCount", 12, 1); + histogram_tester.ExpectBucketCount("Autofill.StoredCreditCardCount.Local", 2, + 1); + histogram_tester.ExpectBucketCount("Autofill.StoredCreditCardCount.Server", + 10, 1); + histogram_tester.ExpectBucketCount( + "Autofill.StoredCreditCardCount.Server.Masked", 4, 1); + histogram_tester.ExpectBucketCount( + "Autofill.StoredCreditCardCount.Server.Unmasked", 6, 1); + + // Validate the disused count metrics. + histogram_tester.ExpectTotalCount("Autofill.StoredCreditCardDisusedCount", 1); + histogram_tester.ExpectTotalCount( + "Autofill.StoredCreditCardDisusedCount.Local", 1); + histogram_tester.ExpectTotalCount( + "Autofill.StoredCreditCardDisusedCount.Server", 1); + histogram_tester.ExpectTotalCount( + "Autofill.StoredCreditCardDisusedCount.Server.Masked", 1); + histogram_tester.ExpectTotalCount( + "Autofill.StoredCreditCardDisusedCount.Server.Unmasked", 1); + histogram_tester.ExpectBucketCount("Autofill.StoredCreditCardDisusedCount", 6, + 1); + histogram_tester.ExpectBucketCount( + "Autofill.StoredCreditCardDisusedCount.Local", 1, 1); + histogram_tester.ExpectBucketCount( + "Autofill.StoredCreditCardDisusedCount.Server", 5, 1); + histogram_tester.ExpectBucketCount( + "Autofill.StoredCreditCardDisusedCount.Server.Masked", 2, 1); + histogram_tester.ExpectBucketCount( + "Autofill.StoredCreditCardDisusedCount.Server.Unmasked", 3, 1); + + // Validate the days-since-last-use metrics. + histogram_tester.ExpectTotalCount( + "Autofill.DaysSinceLastUse.StoredCreditCard", 12); + histogram_tester.ExpectTotalCount( + "Autofill.DaysSinceLastUse.StoredCreditCard.Local", 2); + histogram_tester.ExpectTotalCount( + "Autofill.DaysSinceLastUse.StoredCreditCard.Server", 10); + histogram_tester.ExpectTotalCount( + "Autofill.DaysSinceLastUse.StoredCreditCard.Server.Masked", 4); + histogram_tester.ExpectTotalCount( + "Autofill.DaysSinceLastUse.StoredCreditCard.Server.Unmasked", 6); + histogram_tester.ExpectBucketCount( + "Autofill.DaysSinceLastUse.StoredCreditCard", 30, 6); + histogram_tester.ExpectBucketCount( + "Autofill.DaysSinceLastUse.StoredCreditCard", 200, 6); + histogram_tester.ExpectBucketCount( + "Autofill.DaysSinceLastUse.StoredCreditCard.Local", 30, 1); + histogram_tester.ExpectBucketCount( + "Autofill.DaysSinceLastUse.StoredCreditCard.Local", 200, 1); + histogram_tester.ExpectBucketCount( + "Autofill.DaysSinceLastUse.StoredCreditCard.Server", 30, 5); + histogram_tester.ExpectBucketCount( + "Autofill.DaysSinceLastUse.StoredCreditCard.Server", 200, 5); + histogram_tester.ExpectBucketCount( + "Autofill.DaysSinceLastUse.StoredCreditCard.Server.Masked", 30, 2); + histogram_tester.ExpectBucketCount( + "Autofill.DaysSinceLastUse.StoredCreditCard.Server.Masked", 200, 2); + histogram_tester.ExpectBucketCount( + "Autofill.DaysSinceLastUse.StoredCreditCard.Server.Unmasked", 30, 3); + histogram_tester.ExpectBucketCount( + "Autofill.DaysSinceLastUse.StoredCreditCard.Server.Unmasked", 200, 3); +} + // Test that the profile count is logged correctly. TEST_F(AutofillMetricsTest, StoredProfileCount) { // The metric should be logged when the profiles are first loaded. @@ -3047,6 +3174,231 @@ TEST_F(AutofillMetricsTest, CreditCardGetRealPanDuration) { } } +TEST_F(AutofillMetricsTest, + CreditCardSubmittedWithoutSelectingSuggestionsNoCard) { + EnableWalletSync(); + // Create a local card for testing, card number is 4111111111111111. + personal_data_->RecreateCreditCards( + true /* include_local_credit_card */, + false /* include_masked_server_credit_card */, + false /* include_full_server_credit_card */); + + // 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"); + + FormFieldData field; + std::vector<ServerFieldType> field_types; + test::CreateTestFormField("Month", "card_month", "", "text", &field); + form.fields.push_back(field); + field_types.push_back(CREDIT_CARD_EXP_MONTH); + test::CreateTestFormField("Year", "card_year", "", "text", &field); + form.fields.push_back(field); + field_types.push_back(CREDIT_CARD_EXP_2_DIGIT_YEAR); + test::CreateTestFormField("Credit card", "card", "", "text", &field); + form.fields.push_back(field); + field_types.push_back(CREDIT_CARD_NUMBER); + + // Simulate having seen this form on page load. + // |form_structure| will be owned by |autofill_manager_|. + autofill_manager_->AddSeenForm(form, field_types, field_types); + + // Simulating submission with suggestion shown, but not selected. + base::HistogramTester histogram_tester; + autofill_manager_->DidShowSuggestions(true /* is_new_popup */, form, field); + autofill_manager_->OnQueryFormFieldAutofill(0, form, field, gfx::RectF()); + autofill_manager_->SubmitForm(form, TimeTicks::Now()); + histogram_tester.ExpectBucketCount( + "Autofill.FormEvents.CreditCard", + AutofillMetrics::FORM_EVENT_SUBMIT_WITHOUT_SELECTING_SUGGESTIONS_NO_CARD, + 1); +} + +TEST_F(AutofillMetricsTest, + CreditCardSubmittedWithoutSelectingSuggestionsUnknownCard) { + EnableWalletSync(); + // Create a local card for testing, card number is 4111111111111111. + personal_data_->RecreateCreditCards( + true /* include_local_credit_card */, + false /* include_masked_server_credit_card */, + false /* include_full_server_credit_card */); + + // 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"); + + FormFieldData field; + std::vector<ServerFieldType> field_types; + test::CreateTestFormField("Month", "card_month", "", "text", &field); + form.fields.push_back(field); + field_types.push_back(CREDIT_CARD_EXP_MONTH); + test::CreateTestFormField("Year", "card_year", "", "text", &field); + form.fields.push_back(field); + field_types.push_back(CREDIT_CARD_EXP_2_DIGIT_YEAR); + test::CreateTestFormField("Credit card", "card", "5105105105105100", "text", + &field); + form.fields.push_back(field); + field_types.push_back(CREDIT_CARD_NUMBER); + + // Simulate having seen this form on page load. + // |form_structure| will be owned by |autofill_manager_|. + autofill_manager_->AddSeenForm(form, field_types, field_types); + + // Simulating submission with suggestion shown, but not selected. + base::HistogramTester histogram_tester; + autofill_manager_->DidShowSuggestions(true /* is_new_popup */, form, field); + autofill_manager_->OnQueryFormFieldAutofill(0, form, field, gfx::RectF()); + autofill_manager_->SubmitForm(form, TimeTicks::Now()); + histogram_tester.ExpectBucketCount( + "Autofill.FormEvents.CreditCard", + AutofillMetrics:: + FORM_EVENT_SUBMIT_WITHOUT_SELECTING_SUGGESTIONS_UNKNOWN_CARD, + 1); +} + +TEST_F(AutofillMetricsTest, + CreditCardSubmittedWithoutSelectingSuggestionsKnownCard) { + EnableWalletSync(); + // Create a local card for testing, card number is 4111111111111111. + personal_data_->RecreateCreditCards( + true /* include_local_credit_card */, + false /* include_masked_server_credit_card */, + false /* include_full_server_credit_card */); + + // 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"); + + FormFieldData field; + std::vector<ServerFieldType> field_types; + test::CreateTestFormField("Month", "card_month", "", "text", &field); + form.fields.push_back(field); + field_types.push_back(CREDIT_CARD_EXP_MONTH); + test::CreateTestFormField("Year", "card_year", "", "text", &field); + form.fields.push_back(field); + field_types.push_back(CREDIT_CARD_EXP_2_DIGIT_YEAR); + test::CreateTestFormField("Credit card", "card", "4111111111111111", "text", + &field); + form.fields.push_back(field); + field_types.push_back(CREDIT_CARD_NUMBER); + + // Simulate having seen this form on page load. + // |form_structure| will be owned by |autofill_manager_|. + autofill_manager_->AddSeenForm(form, field_types, field_types); + + // Simulating submission with suggestion shown, but not selected. + base::HistogramTester histogram_tester; + autofill_manager_->DidShowSuggestions(true /* is_new_popup */, form, field); + autofill_manager_->OnQueryFormFieldAutofill(0, form, field, gfx::RectF()); + autofill_manager_->SubmitForm(form, TimeTicks::Now()); + histogram_tester.ExpectBucketCount( + "Autofill.FormEvents.CreditCard", + AutofillMetrics:: + FORM_EVENT_SUBMIT_WITHOUT_SELECTING_SUGGESTIONS_KNOWN_CARD, + 1); +} + +TEST_F(AutofillMetricsTest, + ShouldNotLogSubmitWithoutSelectingSuggestionsIfSuggestionFilled) { + EnableWalletSync(); + // Create a local card for testing, card number is 4111111111111111. + personal_data_->RecreateCreditCards( + true /* include_local_credit_card */, + false /* include_masked_server_credit_card */, + false /* include_full_server_credit_card */); + + // 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"); + + FormFieldData field; + std::vector<ServerFieldType> field_types; + test::CreateTestFormField("Month", "card_month", "", "text", &field); + form.fields.push_back(field); + field_types.push_back(CREDIT_CARD_EXP_MONTH); + test::CreateTestFormField("Year", "card_year", "", "text", &field); + form.fields.push_back(field); + field_types.push_back(CREDIT_CARD_EXP_2_DIGIT_YEAR); + test::CreateTestFormField("Credit card", "card", "4111111111111111", "text", + &field); + form.fields.push_back(field); + field_types.push_back(CREDIT_CARD_NUMBER); + + // Simulate having seen this form on page load. + // |form_structure| will be owned by |autofill_manager_|. + autofill_manager_->AddSeenForm(form, field_types, field_types); + + // Simulating submission with suggestion shown and selected. + base::HistogramTester histogram_tester; + autofill_manager_->DidShowSuggestions(true /* is_new_popup */, form, field); + autofill_manager_->OnQueryFormFieldAutofill(0, form, field, gfx::RectF()); + std::string guid("10000000-0000-0000-0000-000000000001"); + autofill_manager_->FillOrPreviewForm( + AutofillDriver::FORM_DATA_ACTION_FILL, 0, form, form.fields.back(), + autofill_manager_->MakeFrontendID(guid, std::string())); + + autofill_manager_->SubmitForm(form, TimeTicks::Now()); + histogram_tester.ExpectBucketCount( + "Autofill.FormEvents.CreditCard", + AutofillMetrics:: + FORM_EVENT_SUBMIT_WITHOUT_SELECTING_SUGGESTIONS_KNOWN_CARD, + 0); + histogram_tester.ExpectBucketCount( + "Autofill.FormEvents.CreditCard", + AutofillMetrics:: + FORM_EVENT_SUBMIT_WITHOUT_SELECTING_SUGGESTIONS_UNKNOWN_CARD, + 0); + histogram_tester.ExpectBucketCount( + "Autofill.FormEvents.CreditCard", + AutofillMetrics::FORM_EVENT_SUBMIT_WITHOUT_SELECTING_SUGGESTIONS_NO_CARD, + 0); +} + +TEST_F(AutofillMetricsTest, ShouldNotLogFormEventNoCardForAddressForm) { + EnableWalletSync(); + // Create a profile. + personal_data_->RecreateProfile(); + // 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"); + + FormFieldData field; + std::vector<ServerFieldType> field_types; + test::CreateTestFormField("State", "state", "", "text", &field); + form.fields.push_back(field); + field_types.push_back(ADDRESS_HOME_STATE); + test::CreateTestFormField("City", "city", "", "text", &field); + form.fields.push_back(field); + field_types.push_back(ADDRESS_HOME_CITY); + test::CreateTestFormField("Street", "street", "", "text", &field); + form.fields.push_back(field); + field_types.push_back(ADDRESS_HOME_STREET_ADDRESS); + + // Simulate having seen this form on page load. + // |form_structure| will be owned by |autofill_manager_|. + autofill_manager_->AddSeenForm(form, field_types, field_types); + + // Simulating submission with no filled data. + base::HistogramTester histogram_tester; + autofill_manager_->DidShowSuggestions(true /* is_new_popup */, form, field); + autofill_manager_->OnQueryFormFieldAutofill(0, form, field, gfx::RectF()); + autofill_manager_->SubmitForm(form, TimeTicks::Now()); + histogram_tester.ExpectBucketCount( + "Autofill.FormEvents.Address", + AutofillMetrics::FORM_EVENT_SUBMIT_WITHOUT_SELECTING_SUGGESTIONS_NO_CARD, + 0); +} + // Test that we log submitted form events for credit cards. TEST_F(AutofillMetricsTest, CreditCardSubmittedFormEvents) { EnableWalletSync(); @@ -4636,9 +4988,244 @@ TEST_F(AutofillMetricsTest, AutofillFormSubmittedState) { } } +TEST_F(AutofillMetricsTest, LogUserHappinessMetric_PasswordForm) { + { + base::HistogramTester histogram_tester; + AutofillMetrics::LogUserHappinessMetric(AutofillMetrics::USER_DID_AUTOFILL, + PASSWORD_FIELD); + histogram_tester.ExpectBucketCount("Autofill.UserHappiness", + AutofillMetrics::USER_DID_AUTOFILL, 1); + histogram_tester.ExpectBucketCount("Autofill.UserHappiness.Password", + AutofillMetrics::USER_DID_AUTOFILL, 1); + histogram_tester.ExpectTotalCount("Autofill.UserHappiness.CreditCard", 0); + histogram_tester.ExpectTotalCount("Autofill.UserHappiness.Address", 0); + histogram_tester.ExpectTotalCount("Autofill.UserHappiness.Unknown", 0); + } + + { + base::HistogramTester histogram_tester; + AutofillMetrics::LogUserHappinessMetric(AutofillMetrics::USER_DID_AUTOFILL, + USERNAME_FIELD); + histogram_tester.ExpectBucketCount("Autofill.UserHappiness", + AutofillMetrics::USER_DID_AUTOFILL, 1); + histogram_tester.ExpectBucketCount("Autofill.UserHappiness.Password", + AutofillMetrics::USER_DID_AUTOFILL, 1); + histogram_tester.ExpectTotalCount("Autofill.UserHappiness.CreditCard", 0); + histogram_tester.ExpectTotalCount("Autofill.UserHappiness.Address", 0); + histogram_tester.ExpectTotalCount("Autofill.UserHappiness.Unknown", 0); + } +} + +TEST_F(AutofillMetricsTest, LogUserHappinessMetric_UnknownForm) { + { + base::HistogramTester histogram_tester; + AutofillMetrics::LogUserHappinessMetric(AutofillMetrics::USER_DID_AUTOFILL, + NO_GROUP); + histogram_tester.ExpectBucketCount("Autofill.UserHappiness", + AutofillMetrics::USER_DID_AUTOFILL, 1); + histogram_tester.ExpectBucketCount("Autofill.UserHappiness.Unknown", + AutofillMetrics::USER_DID_AUTOFILL, 1); + histogram_tester.ExpectTotalCount("Autofill.UserHappiness.CreditCard", 0); + histogram_tester.ExpectTotalCount("Autofill.UserHappiness.Address", 0); + histogram_tester.ExpectTotalCount("Autofill.UserHappiness.Password", 0); + } + + { + base::HistogramTester histogram_tester; + AutofillMetrics::LogUserHappinessMetric(AutofillMetrics::USER_DID_AUTOFILL, + TRANSACTION); + histogram_tester.ExpectBucketCount("Autofill.UserHappiness", + AutofillMetrics::USER_DID_AUTOFILL, 1); + histogram_tester.ExpectBucketCount("Autofill.UserHappiness.Unknown", + AutofillMetrics::USER_DID_AUTOFILL, 1); + histogram_tester.ExpectTotalCount("Autofill.UserHappiness.CreditCard", 0); + histogram_tester.ExpectTotalCount("Autofill.UserHappiness.Address", 0); + histogram_tester.ExpectTotalCount("Autofill.UserHappiness.Password", 0); + } +} + +// Verify that nothing is logging in happiness metrics if no fields in form. +TEST_F(AutofillMetricsTest, UserHappinessFormInteraction_EmptyForm) { + // Load a fillable form. + FormData form; + form.name = ASCIIToUTF16("TestForm"); + form.origin = GURL("http://example.com/form.html"); + form.action = GURL("http://example.com/submit.html"); + + std::vector<FormData> forms(1, form); + + // Expect a notification when the form is first seen. + { + base::HistogramTester histogram_tester; + autofill_manager_->OnFormsSeen(forms, TimeTicks()); + histogram_tester.ExpectTotalCount("Autofill.UserHappiness", 0); + histogram_tester.ExpectTotalCount("Autofill.UserHappiness.CreditCard", 0); + histogram_tester.ExpectTotalCount("Autofill.UserHappiness.Address", 0); + } +} + // Verify that we correctly log user happiness metrics dealing with form // interaction. -TEST_F(AutofillMetricsTest, UserHappinessFormInteraction) { +TEST_F(AutofillMetricsTest, UserHappinessFormInteraction_CreditCardForm) { + // Load a fillable form. + FormData form; + form.name = ASCIIToUTF16("TestForm"); + form.origin = GURL("http://example.com/form.html"); + form.action = GURL("http://example.com/submit.html"); + + // Construct a valid credit card form with minimal fields. + FormFieldData field; + std::vector<ServerFieldType> field_types; + test::CreateTestFormField("Card Number", "card_number", "", "text", &field); + form.fields.push_back(field); + field_types.push_back(CREDIT_CARD_NAME_FULL); + test::CreateTestFormField("Expiration", "cc_exp", "", "text", &field); + form.fields.push_back(field); + field_types.push_back(CREDIT_CARD_EXP_MONTH); + test::CreateTestFormField("Verification", "verification", "", "text", &field); + form.fields.push_back(field); + field_types.push_back(CREDIT_CARD_VERIFICATION_CODE); + + std::vector<FormData> forms(1, form); + + // Expect a notification when the form is first seen. + { + base::HistogramTester histogram_tester; + autofill_manager_->OnFormsSeen(forms, TimeTicks()); + histogram_tester.ExpectUniqueSample("Autofill.UserHappiness", + AutofillMetrics::FORMS_LOADED, 1); + histogram_tester.ExpectUniqueSample("Autofill.UserHappiness.CreditCard", + AutofillMetrics::FORMS_LOADED, 1); + } + + // Simulate typing. + { + base::HistogramTester histogram_tester; + autofill_manager_->OnTextFieldDidChange(form, form.fields.front(), + gfx::RectF(), TimeTicks()); + histogram_tester.ExpectUniqueSample("Autofill.UserHappiness", + AutofillMetrics::USER_DID_TYPE, 1); + histogram_tester.ExpectUniqueSample("Autofill.UserHappiness.CreditCard", + AutofillMetrics::USER_DID_TYPE, 1); + } + + autofill_manager_->Reset(); + autofill_manager_->AddSeenForm(form, field_types, field_types); + + // Simulate suggestions shown twice with separate popups. + { + base::HistogramTester histogram_tester; + autofill_manager_->DidShowSuggestions(true, form, field); + autofill_manager_->DidShowSuggestions(true, form, field); + histogram_tester.ExpectBucketCount("Autofill.UserHappiness", + AutofillMetrics::SUGGESTIONS_SHOWN, 2); + histogram_tester.ExpectBucketCount( + "Autofill.UserHappiness", AutofillMetrics::SUGGESTIONS_SHOWN_ONCE, 1); + histogram_tester.ExpectBucketCount("Autofill.UserHappiness.CreditCard", + AutofillMetrics::SUGGESTIONS_SHOWN, 2); + histogram_tester.ExpectBucketCount("Autofill.UserHappiness.CreditCard", + AutofillMetrics::SUGGESTIONS_SHOWN_ONCE, + 1); + } + + autofill_manager_->Reset(); + autofill_manager_->AddSeenForm(form, field_types, field_types); + + // Simulate suggestions shown twice for a single edit (i.e. multiple + // keystrokes in a single field). + { + base::HistogramTester histogram_tester; + autofill_manager_->DidShowSuggestions(true, form, field); + autofill_manager_->DidShowSuggestions(false, form, field); + histogram_tester.ExpectBucketCount("Autofill.UserHappiness", + AutofillMetrics::SUGGESTIONS_SHOWN, 1); + histogram_tester.ExpectBucketCount( + "Autofill.UserHappiness", AutofillMetrics::SUGGESTIONS_SHOWN_ONCE, 1); + histogram_tester.ExpectBucketCount("Autofill.UserHappiness.CreditCard", + AutofillMetrics::SUGGESTIONS_SHOWN, 1); + histogram_tester.ExpectBucketCount("Autofill.UserHappiness.CreditCard", + AutofillMetrics::SUGGESTIONS_SHOWN_ONCE, + 1); + } + + // Simulate suggestions shown for a different field. + { + base::HistogramTester histogram_tester; + autofill_manager_->DidShowSuggestions(true, form, form.fields[1]); + histogram_tester.ExpectUniqueSample("Autofill.UserHappiness", + AutofillMetrics::SUGGESTIONS_SHOWN, 1); + histogram_tester.ExpectUniqueSample("Autofill.UserHappiness.CreditCard", + AutofillMetrics::SUGGESTIONS_SHOWN, 1); + } + + // Simulate invoking autofill. + { + base::HistogramTester histogram_tester; + autofill_manager_->OnDidFillAutofillFormData(form, TimeTicks()); + histogram_tester.ExpectBucketCount("Autofill.UserHappiness", + AutofillMetrics::USER_DID_AUTOFILL, 1); + histogram_tester.ExpectBucketCount( + "Autofill.UserHappiness", AutofillMetrics::USER_DID_AUTOFILL_ONCE, 1); + histogram_tester.ExpectBucketCount("Autofill.UserHappiness.CreditCard", + AutofillMetrics::USER_DID_AUTOFILL, 1); + histogram_tester.ExpectBucketCount("Autofill.UserHappiness.CreditCard", + AutofillMetrics::USER_DID_AUTOFILL_ONCE, + 1); + } + + // Simulate editing an autofilled field. + { + base::HistogramTester histogram_tester; + std::string guid("00000000-0000-0000-0000-000000000001"); + autofill_manager_->FillOrPreviewForm( + AutofillDriver::FORM_DATA_ACTION_FILL, 0, form, form.fields.front(), + autofill_manager_->MakeFrontendID(std::string(), guid)); + autofill_manager_->OnTextFieldDidChange(form, form.fields.front(), + gfx::RectF(), TimeTicks()); + // Simulate a second keystroke; make sure we don't log the metric twice. + autofill_manager_->OnTextFieldDidChange(form, form.fields.front(), + gfx::RectF(), TimeTicks()); + histogram_tester.ExpectBucketCount( + "Autofill.UserHappiness", + AutofillMetrics::USER_DID_EDIT_AUTOFILLED_FIELD, 1); + histogram_tester.ExpectBucketCount( + "Autofill.UserHappiness", + AutofillMetrics::USER_DID_EDIT_AUTOFILLED_FIELD_ONCE, 1); + histogram_tester.ExpectBucketCount( + "Autofill.UserHappiness.CreditCard", + AutofillMetrics::USER_DID_EDIT_AUTOFILLED_FIELD, 1); + histogram_tester.ExpectBucketCount( + "Autofill.UserHappiness.CreditCard", + AutofillMetrics::USER_DID_EDIT_AUTOFILLED_FIELD_ONCE, 1); + } + + // Simulate invoking autofill again. + { + base::HistogramTester histogram_tester; + autofill_manager_->OnDidFillAutofillFormData(form, TimeTicks()); + histogram_tester.ExpectUniqueSample("Autofill.UserHappiness", + AutofillMetrics::USER_DID_AUTOFILL, 1); + histogram_tester.ExpectUniqueSample("Autofill.UserHappiness.CreditCard", + AutofillMetrics::USER_DID_AUTOFILL, 1); + } + + // Simulate editing another autofilled field. + { + base::HistogramTester histogram_tester; + autofill_manager_->OnTextFieldDidChange(form, form.fields[1], gfx::RectF(), + TimeTicks()); + histogram_tester.ExpectUniqueSample( + "Autofill.UserHappiness", + AutofillMetrics::USER_DID_EDIT_AUTOFILLED_FIELD, 1); + histogram_tester.ExpectUniqueSample( + "Autofill.UserHappiness.CreditCard", + AutofillMetrics::USER_DID_EDIT_AUTOFILLED_FIELD, 1); + } +} + +// Verify that we correctly log user happiness metrics dealing with form +// interaction. +TEST_F(AutofillMetricsTest, UserHappinessFormInteraction_AddressForm) { // Load a fillable form. FormData form; form.name = ASCIIToUTF16("TestForm"); @@ -4661,6 +5248,8 @@ TEST_F(AutofillMetricsTest, UserHappinessFormInteraction) { autofill_manager_->OnFormsSeen(forms, TimeTicks()); histogram_tester.ExpectUniqueSample("Autofill.UserHappiness", AutofillMetrics::FORMS_LOADED, 1); + histogram_tester.ExpectUniqueSample("Autofill.UserHappiness.Address", + AutofillMetrics::FORMS_LOADED, 1); } // Simulate typing. @@ -4670,8 +5259,28 @@ TEST_F(AutofillMetricsTest, UserHappinessFormInteraction) { gfx::RectF(), TimeTicks()); histogram_tester.ExpectUniqueSample("Autofill.UserHappiness", AutofillMetrics::USER_DID_TYPE, 1); + histogram_tester.ExpectUniqueSample("Autofill.UserHappiness.Address", + AutofillMetrics::USER_DID_TYPE, 1); } + // Simulate suggestions shown twice with separate popups. + { + base::HistogramTester histogram_tester; + autofill_manager_->DidShowSuggestions(true, form, field); + autofill_manager_->DidShowSuggestions(true, form, field); + histogram_tester.ExpectBucketCount("Autofill.UserHappiness", + AutofillMetrics::SUGGESTIONS_SHOWN, 2); + histogram_tester.ExpectBucketCount( + "Autofill.UserHappiness", AutofillMetrics::SUGGESTIONS_SHOWN_ONCE, 1); + histogram_tester.ExpectBucketCount("Autofill.UserHappiness.Address", + AutofillMetrics::SUGGESTIONS_SHOWN, 2); + histogram_tester.ExpectBucketCount("Autofill.UserHappiness.Address", + AutofillMetrics::SUGGESTIONS_SHOWN_ONCE, + 1); + } + + autofill_manager_->Reset(); + autofill_manager_->OnFormsSeen(forms, TimeTicks()); // Simulate suggestions shown twice for a single edit (i.e. multiple // keystrokes in a single field). { @@ -4682,6 +5291,11 @@ TEST_F(AutofillMetricsTest, UserHappinessFormInteraction) { AutofillMetrics::SUGGESTIONS_SHOWN, 1); histogram_tester.ExpectBucketCount( "Autofill.UserHappiness", AutofillMetrics::SUGGESTIONS_SHOWN_ONCE, 1); + histogram_tester.ExpectBucketCount("Autofill.UserHappiness.Address", + AutofillMetrics::SUGGESTIONS_SHOWN, 1); + histogram_tester.ExpectBucketCount("Autofill.UserHappiness.Address", + AutofillMetrics::SUGGESTIONS_SHOWN_ONCE, + 1); } // Simulate suggestions shown for a different field. @@ -4690,6 +5304,8 @@ TEST_F(AutofillMetricsTest, UserHappinessFormInteraction) { autofill_manager_->DidShowSuggestions(true, form, form.fields[1]); histogram_tester.ExpectUniqueSample("Autofill.UserHappiness", AutofillMetrics::SUGGESTIONS_SHOWN, 1); + histogram_tester.ExpectUniqueSample("Autofill.UserHappiness.Address", + AutofillMetrics::SUGGESTIONS_SHOWN, 1); } // Simulate invoking autofill. @@ -4700,6 +5316,11 @@ TEST_F(AutofillMetricsTest, UserHappinessFormInteraction) { AutofillMetrics::USER_DID_AUTOFILL, 1); histogram_tester.ExpectBucketCount( "Autofill.UserHappiness", AutofillMetrics::USER_DID_AUTOFILL_ONCE, 1); + histogram_tester.ExpectBucketCount("Autofill.UserHappiness.Address", + AutofillMetrics::USER_DID_AUTOFILL, 1); + histogram_tester.ExpectBucketCount("Autofill.UserHappiness.Address", + AutofillMetrics::USER_DID_AUTOFILL_ONCE, + 1); } // Simulate editing an autofilled field. @@ -4720,6 +5341,12 @@ TEST_F(AutofillMetricsTest, UserHappinessFormInteraction) { histogram_tester.ExpectBucketCount( "Autofill.UserHappiness", AutofillMetrics::USER_DID_EDIT_AUTOFILLED_FIELD_ONCE, 1); + histogram_tester.ExpectBucketCount( + "Autofill.UserHappiness.Address", + AutofillMetrics::USER_DID_EDIT_AUTOFILLED_FIELD, 1); + histogram_tester.ExpectBucketCount( + "Autofill.UserHappiness.Address", + AutofillMetrics::USER_DID_EDIT_AUTOFILLED_FIELD_ONCE, 1); } // Simulate invoking autofill again. @@ -4728,6 +5355,8 @@ TEST_F(AutofillMetricsTest, UserHappinessFormInteraction) { autofill_manager_->OnDidFillAutofillFormData(form, TimeTicks()); histogram_tester.ExpectUniqueSample("Autofill.UserHappiness", AutofillMetrics::USER_DID_AUTOFILL, 1); + histogram_tester.ExpectUniqueSample("Autofill.UserHappiness.Address", + AutofillMetrics::USER_DID_AUTOFILL, 1); } // Simulate editing another autofilled field. @@ -4738,6 +5367,9 @@ TEST_F(AutofillMetricsTest, UserHappinessFormInteraction) { histogram_tester.ExpectUniqueSample( "Autofill.UserHappiness", AutofillMetrics::USER_DID_EDIT_AUTOFILLED_FIELD, 1); + histogram_tester.ExpectUniqueSample( + "Autofill.UserHappiness.Address", + AutofillMetrics::USER_DID_EDIT_AUTOFILLED_FIELD, 1); } autofill_manager_->Reset(); @@ -4755,6 +5387,16 @@ TEST_F(AutofillMetricsTest, UserHappinessFormInteraction) { {UkmTextFieldDidChangeType::kHtmlFieldTypeName, HTML_TYPE_UNSPECIFIED}, {UkmTextFieldDidChangeType::kServerTypeName, NO_SERVER_DATA}}, {{UkmSuggestionFilledType::kMillisecondsSinceFormParsedName, 0}, + {UkmTextFieldDidChangeType::kHeuristicTypeName, + PHONE_HOME_WHOLE_NUMBER}, + {UkmTextFieldDidChangeType::kHtmlFieldTypeName, HTML_TYPE_UNSPECIFIED}, + {UkmTextFieldDidChangeType::kServerTypeName, NO_SERVER_DATA}}, + {{UkmSuggestionFilledType::kMillisecondsSinceFormParsedName, 0}, + {UkmTextFieldDidChangeType::kHeuristicTypeName, + PHONE_HOME_WHOLE_NUMBER}, + {UkmTextFieldDidChangeType::kHtmlFieldTypeName, HTML_TYPE_UNSPECIFIED}, + {UkmTextFieldDidChangeType::kServerTypeName, NO_SERVER_DATA}}, + {{UkmSuggestionFilledType::kMillisecondsSinceFormParsedName, 0}, {UkmTextFieldDidChangeType::kHeuristicTypeName, EMAIL_ADDRESS}, {UkmTextFieldDidChangeType::kHtmlFieldTypeName, HTML_TYPE_UNSPECIFIED}, {UkmTextFieldDidChangeType::kServerTypeName, NO_SERVER_DATA}}}); @@ -4829,7 +5471,6 @@ TEST_F(AutofillMetricsTest, FormFillDuration) { second_form.fields[1].value = ASCIIToUTF16("theking@gmail.com"); second_form.fields[2].value = ASCIIToUTF16("12345678901"); second_form.fields[3].value = ASCIIToUTF16("51512345678"); - // Expect only form load metrics to be logged if the form is submitted without // user interaction. { @@ -4978,6 +5619,212 @@ TEST_F(AutofillMetricsTest, FormFillDuration) { } } +TEST_F(AutofillMetricsTest, FormFillDurationFromInteraction_CreditCardForm) { + // Should log time duration with autofill for credit card form. + { + base::HistogramTester histogram_tester; + AutofillMetrics::LogFormFillDurationFromInteraction( + {CREDIT_CARD_FORM}, true /* used_autofill */, + base::TimeDelta::FromMilliseconds(2000)); + histogram_tester.ExpectTimeBucketCount( + "Autofill.FillDuration.FromInteraction.WithAutofill.CreditCard", + base::TimeDelta::FromMilliseconds(2000), 1); + histogram_tester.ExpectTotalCount( + "Autofill.FillDuration.FromInteraction.WithoutAutofill.CreditCard", 0); + } + + // Should log time duration without autofill for credit card form. + { + base::HistogramTester histogram_tester; + AutofillMetrics::LogFormFillDurationFromInteraction( + {CREDIT_CARD_FORM}, false /* used_autofill */, + base::TimeDelta::FromMilliseconds(2000)); + histogram_tester.ExpectTimeBucketCount( + "Autofill.FillDuration.FromInteraction.WithoutAutofill.CreditCard", + base::TimeDelta::FromMilliseconds(2000), 1); + histogram_tester.ExpectTotalCount( + "Autofill.FillDuration.FromInteraction.WithAutofill.CreditCard", 0); + } + + // Should not log time duration for credit card form if credit card form is + // not detected. + { + base::HistogramTester histogram_tester; + AutofillMetrics::LogFormFillDurationFromInteraction( + {UNKNOWN_FORM_TYPE}, false /* used_autofill */, + base::TimeDelta::FromMilliseconds(2000)); + histogram_tester.ExpectTotalCount( + "Autofill.FillDuration.FromInteraction.WithAutofill.CreditCard", 0); + histogram_tester.ExpectTotalCount( + "Autofill.FillDuration.FromInteraction.WithoutAutofill.CreditCard", 0); + } +} + +TEST_F(AutofillMetricsTest, FormFillDurationFromInteraction_AddressForm) { + // Should log time duration with autofill for address form. + { + base::HistogramTester histogram_tester; + AutofillMetrics::LogFormFillDurationFromInteraction( + {ADDRESS_FORM}, true /* used_autofill */, + base::TimeDelta::FromMilliseconds(2000)); + histogram_tester.ExpectTimeBucketCount( + "Autofill.FillDuration.FromInteraction.WithAutofill.Address", + base::TimeDelta::FromMilliseconds(2000), 1); + histogram_tester.ExpectTotalCount( + "Autofill.FillDuration.FromInteraction.WithoutAutofill.Address", 0); + } + + // Should log time duration without autofill for address form. + { + base::HistogramTester histogram_tester; + AutofillMetrics::LogFormFillDurationFromInteraction( + {ADDRESS_FORM}, false /* used_autofill */, + base::TimeDelta::FromMilliseconds(2000)); + histogram_tester.ExpectTimeBucketCount( + "Autofill.FillDuration.FromInteraction.WithoutAutofill.Address", + base::TimeDelta::FromMilliseconds(2000), 1); + histogram_tester.ExpectTotalCount( + "Autofill.FillDuration.FromInteraction.WithAutofill.Address", 0); + } + + // Should not log time duration for address form if address form is not + // detected. + { + base::HistogramTester histogram_tester; + AutofillMetrics::LogFormFillDurationFromInteraction( + {UNKNOWN_FORM_TYPE}, false /* used_autofill */, + base::TimeDelta::FromMilliseconds(2000)); + histogram_tester.ExpectTotalCount( + "Autofill.FillDuration.FromInteraction.WithAutofill.Address", 0); + histogram_tester.ExpectTotalCount( + "Autofill.FillDuration.FromInteraction.WithoutAutofill.Address", 0); + } +} + +TEST_F(AutofillMetricsTest, FormFillDurationFromInteraction_PasswordForm) { + // Should log time duration with autofill for password form. + { + base::HistogramTester histogram_tester; + AutofillMetrics::LogFormFillDurationFromInteraction( + {PASSWORD_FORM}, true /* used_autofill */, + base::TimeDelta::FromMilliseconds(2000)); + histogram_tester.ExpectTimeBucketCount( + "Autofill.FillDuration.FromInteraction.WithAutofill.Password", + base::TimeDelta::FromMilliseconds(2000), 1); + histogram_tester.ExpectTotalCount( + "Autofill.FillDuration.FromInteraction.WithoutAutofill.Password", 0); + } + + // Should log time duration without autofill for password form. + { + base::HistogramTester histogram_tester; + AutofillMetrics::LogFormFillDurationFromInteraction( + {PASSWORD_FORM}, false /* used_autofill */, + base::TimeDelta::FromMilliseconds(2000)); + histogram_tester.ExpectTimeBucketCount( + "Autofill.FillDuration.FromInteraction.WithoutAutofill.Password", + base::TimeDelta::FromMilliseconds(2000), 1); + histogram_tester.ExpectTotalCount( + "Autofill.FillDuration.FromInteraction.WithAutofill.Password", 0); + } + + // Should not log time duration for password form if password form is not + // detected. + { + base::HistogramTester histogram_tester; + AutofillMetrics::LogFormFillDurationFromInteraction( + {UNKNOWN_FORM_TYPE}, false /* used_autofill */, + base::TimeDelta::FromMilliseconds(2000)); + histogram_tester.ExpectTotalCount( + "Autofill.FillDuration.FromInteraction.WithAutofill.Password", 0); + histogram_tester.ExpectTotalCount( + "Autofill.FillDuration.FromInteraction.WithoutAutofill.Password", 0); + } +} + +TEST_F(AutofillMetricsTest, FormFillDurationFromInteraction_UnknownForm) { + // Should log time duration with autofill for unknown form. + { + base::HistogramTester histogram_tester; + AutofillMetrics::LogFormFillDurationFromInteraction( + {UNKNOWN_FORM_TYPE}, true /* used_autofill */, + base::TimeDelta::FromMilliseconds(2000)); + histogram_tester.ExpectTimeBucketCount( + "Autofill.FillDuration.FromInteraction.WithAutofill.Unknown", + base::TimeDelta::FromMilliseconds(2000), 1); + histogram_tester.ExpectTotalCount( + "Autofill.FillDuration.FromInteraction.WithoutAutofill.Unknown", 0); + } + + // Should log time duration without autofill for unknown form. + { + base::HistogramTester histogram_tester; + AutofillMetrics::LogFormFillDurationFromInteraction( + {UNKNOWN_FORM_TYPE}, false /* used_autofill */, + base::TimeDelta::FromMilliseconds(2000)); + histogram_tester.ExpectTimeBucketCount( + "Autofill.FillDuration.FromInteraction.WithoutAutofill.Unknown", + base::TimeDelta::FromMilliseconds(2000), 1); + histogram_tester.ExpectTotalCount( + "Autofill.FillDuration.FromInteraction.WithAutofill.Unknown", 0); + } + + // Should not log time duration for unknown form if unknown form is not + // detected. + { + base::HistogramTester histogram_tester; + AutofillMetrics::LogFormFillDurationFromInteraction( + {ADDRESS_FORM}, false /* used_autofill */, + base::TimeDelta::FromMilliseconds(2000)); + histogram_tester.ExpectTotalCount( + "Autofill.FillDuration.FromInteraction.WithAutofill.Unknown", 0); + histogram_tester.ExpectTotalCount( + "Autofill.FillDuration.FromInteraction.WithoutAutofill.Unknown", 0); + } +} + +TEST_F(AutofillMetricsTest, FormFillDurationFromInteraction_MultipleForms) { + // Should log time duration with autofill for all forms. + { + base::HistogramTester histogram_tester; + AutofillMetrics::LogFormFillDurationFromInteraction( + {CREDIT_CARD_FORM, ADDRESS_FORM, PASSWORD_FORM, UNKNOWN_FORM_TYPE}, + true /* used_autofill */, base::TimeDelta::FromMilliseconds(2000)); + histogram_tester.ExpectTimeBucketCount( + "Autofill.FillDuration.FromInteraction.WithAutofill.CreditCard", + base::TimeDelta::FromMilliseconds(2000), 1); + histogram_tester.ExpectTimeBucketCount( + "Autofill.FillDuration.FromInteraction.WithAutofill.Address", + base::TimeDelta::FromMilliseconds(2000), 1); + histogram_tester.ExpectTimeBucketCount( + "Autofill.FillDuration.FromInteraction.WithAutofill.Password", + base::TimeDelta::FromMilliseconds(2000), 1); + histogram_tester.ExpectTimeBucketCount( + "Autofill.FillDuration.FromInteraction.WithAutofill.Unknown", + base::TimeDelta::FromMilliseconds(2000), 1); + } + + // Should log time duration without autofill for all forms. + { + base::HistogramTester histogram_tester; + AutofillMetrics::LogFormFillDurationFromInteraction( + {CREDIT_CARD_FORM, ADDRESS_FORM, PASSWORD_FORM, UNKNOWN_FORM_TYPE}, + false /* used_autofill */, base::TimeDelta::FromMilliseconds(2000)); + histogram_tester.ExpectTimeBucketCount( + "Autofill.FillDuration.FromInteraction.WithoutAutofill.CreditCard", + base::TimeDelta::FromMilliseconds(2000), 1); + histogram_tester.ExpectTimeBucketCount( + "Autofill.FillDuration.FromInteraction.WithoutAutofill.Address", + base::TimeDelta::FromMilliseconds(2000), 1); + histogram_tester.ExpectTimeBucketCount( + "Autofill.FillDuration.FromInteraction.WithoutAutofill.Password", + base::TimeDelta::FromMilliseconds(2000), 1); + histogram_tester.ExpectTimeBucketCount( + "Autofill.FillDuration.FromInteraction.WithoutAutofill.Unknown", + base::TimeDelta::FromMilliseconds(2000), 1); + } +} + // Verify that we correctly log metrics for profile action on form submission. TEST_F(AutofillMetricsTest, ProfileActionOnFormSubmitted) { base::HistogramTester histogram_tester; @@ -5147,10 +5994,10 @@ class AutofillMetricsParseQueryResponseTest : public testing::Test { TEST_F(AutofillMetricsParseQueryResponseTest, ServerHasData) { AutofillQueryResponseContents response; - response.add_field()->set_autofill_type(7); - response.add_field()->set_autofill_type(30); - response.add_field()->set_autofill_type(9); - response.add_field()->set_autofill_type(0); + response.add_field()->set_overall_type_prediction(7); + response.add_field()->set_overall_type_prediction(30); + response.add_field()->set_overall_type_prediction(9); + response.add_field()->set_overall_type_prediction(0); std::string response_string; ASSERT_TRUE(response.SerializeToString(&response_string)); @@ -5166,10 +6013,10 @@ TEST_F(AutofillMetricsParseQueryResponseTest, ServerHasData) { // logging. TEST_F(AutofillMetricsParseQueryResponseTest, OneFormNoServerData) { AutofillQueryResponseContents response; - response.add_field()->set_autofill_type(0); - response.add_field()->set_autofill_type(0); - response.add_field()->set_autofill_type(9); - response.add_field()->set_autofill_type(0); + response.add_field()->set_overall_type_prediction(0); + response.add_field()->set_overall_type_prediction(0); + response.add_field()->set_overall_type_prediction(9); + response.add_field()->set_overall_type_prediction(0); std::string response_string; ASSERT_TRUE(response.SerializeToString(&response_string)); @@ -5186,7 +6033,7 @@ TEST_F(AutofillMetricsParseQueryResponseTest, OneFormNoServerData) { TEST_F(AutofillMetricsParseQueryResponseTest, AllFormsNoServerData) { AutofillQueryResponseContents response; for (int i = 0; i < 4; ++i) { - response.add_field()->set_autofill_type(0); + response.add_field()->set_overall_type_prediction(0); } std::string response_string; @@ -5203,10 +6050,10 @@ TEST_F(AutofillMetricsParseQueryResponseTest, AllFormsNoServerData) { // UMA metric to say there is data. TEST_F(AutofillMetricsParseQueryResponseTest, PartialNoServerData) { AutofillQueryResponseContents response; - response.add_field()->set_autofill_type(0); - response.add_field()->set_autofill_type(10); - response.add_field()->set_autofill_type(0); - response.add_field()->set_autofill_type(11); + response.add_field()->set_overall_type_prediction(0); + response.add_field()->set_overall_type_prediction(10); + response.add_field()->set_overall_type_prediction(0); + response.add_field()->set_overall_type_prediction(11); std::string response_string; ASSERT_TRUE(response.SerializeToString(&response_string)); diff --git a/chromium/components/autofill/core/browser/autofill_profile.cc b/chromium/components/autofill/core/browser/autofill_profile.cc index 0ad521f08f2..43b79bab2a9 100644 --- a/chromium/components/autofill/core/browser/autofill_profile.cc +++ b/chromium/components/autofill/core/browser/autofill_profile.cc @@ -192,19 +192,24 @@ void GetFieldsForDistinguishingProfiles( } // Constants for the validity bitfield. -static const size_t validity_bits_per_type = 2; -static const size_t number_supported_types_for_validation = 7; +static const size_t kValidityBitsPerType = 2; // The order is important to ensure a consistent bitfield value. New values // should be added at the end NOT at the start or middle. -static const ServerFieldType - supported_types_for_validation[number_supported_types_for_validation] = { - ADDRESS_HOME_COUNTRY, - ADDRESS_HOME_STATE, - ADDRESS_HOME_ZIP, - ADDRESS_HOME_CITY, - ADDRESS_HOME_DEPENDENT_LOCALITY, - EMAIL_ADDRESS, - PHONE_HOME_WHOLE_NUMBER}; +static const ServerFieldType kSupportedTypesForValidation[] = { + ADDRESS_HOME_COUNTRY, + ADDRESS_HOME_STATE, + ADDRESS_HOME_ZIP, + ADDRESS_HOME_CITY, + ADDRESS_HOME_DEPENDENT_LOCALITY, + EMAIL_ADDRESS, + PHONE_HOME_WHOLE_NUMBER}; + +static const size_t kNumSupportedTypesForValidation = + sizeof(kSupportedTypesForValidation) / + sizeof(kSupportedTypesForValidation[0]); + +static_assert(kNumSupportedTypesForValidation * kValidityBitsPerType <= 64, + "Not enough bits to encode profile validity information!"); } // namespace @@ -263,6 +268,7 @@ AutofillProfile& AutofillProfile::operator=(const AutofillProfile& profile) { server_id_ = profile.server_id(); has_converted_ = profile.has_converted(); + SetValidityFromBitfieldValue(profile.GetValidityBitfieldValue()); return *this; } @@ -363,6 +369,7 @@ int AutofillProfile::Compare(const AutofillProfile& profile) const { bool AutofillProfile::EqualsSansOrigin(const AutofillProfile& profile) const { return guid() == profile.guid() && language_code() == profile.language_code() && + GetValidityBitfieldValue() == profile.GetValidityBitfieldValue() && Compare(profile) == 0; } @@ -702,15 +709,13 @@ void AutofillProfile::RecordAndLogUse() { } AutofillProfile::ValidityState AutofillProfile::GetValidityState( - ServerFieldType type) { - // Return valid for types that autofill does not validate. + ServerFieldType type) const { + // Return UNSUPPORTED for types that autofill does not validate. if (!IsValidationSupportedForType(type)) return UNSUPPORTED; - if (!base::ContainsKey(validity_states_, type)) - return UNVALIDATED; - - return validity_states_[type]; + auto it = validity_states_.find(type); + return (it == validity_states_.end()) ? UNVALIDATED : it->second; } void AutofillProfile::SetValidityState(ServerFieldType type, @@ -719,36 +724,54 @@ void AutofillProfile::SetValidityState(ServerFieldType type, if (!IsValidationSupportedForType(type)) return; - std::map<ServerFieldType, ValidityState>::iterator it = - validity_states_.find(type); - - if (it != validity_states_.end()) { - it->second = validity; - } else { - validity_states_.insert(std::make_pair(type, validity)); - } + validity_states_[type] = validity; } -bool AutofillProfile::IsValidationSupportedForType(ServerFieldType type) { - return std::find(supported_types_for_validation, - supported_types_for_validation + - number_supported_types_for_validation, - type) != - supported_types_for_validation + number_supported_types_for_validation; +bool AutofillProfile::IsValidationSupportedForType(ServerFieldType type) const { + for (auto supported_type : kSupportedTypesForValidation) { + if (type == supported_type) + return true; + } + return false; } -int AutofillProfile::GetValidityBitfieldValue() { +int AutofillProfile::GetValidityBitfieldValue() const { int validity_value = 0; size_t field_type_shift = 0; - for (ServerFieldType supported_type : supported_types_for_validation) { + for (ServerFieldType supported_type : kSupportedTypesForValidation) { DCHECK(GetValidityState(supported_type) != UNSUPPORTED); validity_value |= GetValidityState(supported_type) << field_type_shift; - field_type_shift += validity_bits_per_type; + field_type_shift += kValidityBitsPerType; } + // Check the the shift is still in range. + DCHECK_LE(field_type_shift, 64U); + return validity_value; } +void AutofillProfile::SetValidityFromBitfieldValue(int bitfield_value) { + // Compute the bitmask based on the number a bits per type. For example, this + // could be the two least significant bits (0b11). + const int kBitmask = (1 << kValidityBitsPerType) - 1; + + for (ServerFieldType supported_type : kSupportedTypesForValidation) { + // Apply the bitmask to the bitfield value to get the validity value of the + // current |supported_type|. + int validity_value = bitfield_value & kBitmask; + if (validity_value < 0 || validity_value >= UNSUPPORTED) { + NOTREACHED(); + continue; + } + + SetValidityState(supported_type, + static_cast<ValidityState>(validity_value)); + + // Shift the bitfield value to access the validity of the next field type. + bitfield_value = bitfield_value >> kValidityBitsPerType; + } +} + base::string16 AutofillProfile::GetInfoImpl( const AutofillType& type, const std::string& app_locale) const { @@ -908,6 +931,7 @@ FormGroup* AutofillProfile::MutableFormGroupForType(const AutofillType& type) { bool AutofillProfile::EqualsSansGuid(const AutofillProfile& profile) const { return origin() == profile.origin() && language_code() == profile.language_code() && + GetValidityBitfieldValue() == profile.GetValidityBitfieldValue() && Compare(profile) == 0; } @@ -928,7 +952,8 @@ std::ostream& operator<<(std::ostream& os, const AutofillProfile& profile) { << UTF16ToUTF8(profile.GetRawInfo(ADDRESS_HOME_SORTING_CODE)) << " " << UTF16ToUTF8(profile.GetRawInfo(ADDRESS_HOME_COUNTRY)) << " " << profile.language_code() << " " - << UTF16ToUTF8(profile.GetRawInfo(PHONE_HOME_WHOLE_NUMBER)); + << UTF16ToUTF8(profile.GetRawInfo(PHONE_HOME_WHOLE_NUMBER)) << " " + << profile.GetValidityBitfieldValue(); } } // namespace autofill diff --git a/chromium/components/autofill/core/browser/autofill_profile.h b/chromium/components/autofill/core/browser/autofill_profile.h index e9f7f803dfd..6cde979ce02 100644 --- a/chromium/components/autofill/core/browser/autofill_profile.h +++ b/chromium/components/autofill/core/browser/autofill_profile.h @@ -99,7 +99,7 @@ class AutofillProfile : public AutofillDataModel { bool EqualsSansOrigin(const AutofillProfile& profile) const; // Same as operator==, but ignores differences in guid and cares about - // differences in usage stats. + // differences in usage stats and validity state. bool EqualsForSyncPurposes(const AutofillProfile& profile) const; // Equality operators compare GUIDs, origins, language code, and the contents @@ -197,16 +197,20 @@ class AutofillProfile : public AutofillDataModel { void set_has_converted(bool has_converted) { has_converted_ = has_converted; } // Returns the validity state of the specified autofill type. - ValidityState GetValidityState(ServerFieldType type); + ValidityState GetValidityState(ServerFieldType type) const; // Sets the validity state of the specified autofill type. void SetValidityState(ServerFieldType type, ValidityState validity); // Returns whether autofill does the validation of the specified |type|. - bool IsValidationSupportedForType(ServerFieldType type); + bool IsValidationSupportedForType(ServerFieldType type) const; // Returns the bitfield value representing the validity state of this profile. - int GetValidityBitfieldValue(); + int GetValidityBitfieldValue() const; + + // Sets the validity state of the profile based on the specified + // |bitfield_value|. + void SetValidityFromBitfieldValue(int bitfield_value); private: typedef std::vector<const FormGroup*> FormGroupList; diff --git a/chromium/components/autofill/core/browser/autofill_profile_unittest.cc b/chromium/components/autofill/core/browser/autofill_profile_unittest.cc index 07883a8ed51..56f5143c3ce 100644 --- a/chromium/components/autofill/core/browser/autofill_profile_unittest.cc +++ b/chromium/components/autofill/core/browser/autofill_profile_unittest.cc @@ -1302,4 +1302,199 @@ TEST(AutofillProfileTest, GetValidityBitfieldValue_Mixed) { EXPECT_EQ(13229, profile.GetValidityBitfieldValue()); } +TEST(AutofillProfileTest, SetValidityFromBitfieldValue_Country) { + AutofillProfile profile; + + // By default all validity statuses should be set to UNVALIDATED, thus the + // bitfield value should be empty. + EXPECT_EQ(0, profile.GetValidityBitfieldValue()); + + // 0b01 + profile.SetValidityFromBitfieldValue(1); + EXPECT_EQ(AutofillProfile::EMPTY, + profile.GetValidityState(ADDRESS_HOME_COUNTRY)); + + // 0b10 + profile.SetValidityFromBitfieldValue(2); + EXPECT_EQ(AutofillProfile::VALID, + profile.GetValidityState(ADDRESS_HOME_COUNTRY)); + + // 0b11 + profile.SetValidityFromBitfieldValue(3); + EXPECT_EQ(AutofillProfile::INVALID, + profile.GetValidityState(ADDRESS_HOME_COUNTRY)); +} + +TEST(AutofillProfileTest, SetValidityFromBitfieldValue_State) { + AutofillProfile profile; + + // By default all validity statuses should be set to UNVALIDATED, thus the + // bitfield value should be empty. + EXPECT_EQ(0, profile.GetValidityBitfieldValue()); + + // 0b0100 + profile.SetValidityFromBitfieldValue(4); + EXPECT_EQ(AutofillProfile::EMPTY, + profile.GetValidityState(ADDRESS_HOME_STATE)); + + // 0b1000 + profile.SetValidityFromBitfieldValue(8); + EXPECT_EQ(AutofillProfile::VALID, + profile.GetValidityState(ADDRESS_HOME_STATE)); + + // 0b1100 + profile.SetValidityFromBitfieldValue(12); + EXPECT_EQ(AutofillProfile::INVALID, + profile.GetValidityState(ADDRESS_HOME_STATE)); +} + +TEST(AutofillProfileTest, SetValidityFromBitfieldValue_Zip) { + AutofillProfile profile; + + // By default all validity statuses should be set to UNVALIDATED, thus the + // bitfield value should be empty. + EXPECT_EQ(0, profile.GetValidityBitfieldValue()); + + // 0b010000 + profile.SetValidityFromBitfieldValue(16); + EXPECT_EQ(AutofillProfile::EMPTY, profile.GetValidityState(ADDRESS_HOME_ZIP)); + + // 0b100000 + profile.SetValidityFromBitfieldValue(32); + EXPECT_EQ(AutofillProfile::VALID, profile.GetValidityState(ADDRESS_HOME_ZIP)); + + // 0b110000 + profile.SetValidityFromBitfieldValue(48); + EXPECT_EQ(AutofillProfile::INVALID, + profile.GetValidityState(ADDRESS_HOME_ZIP)); +} + +TEST(AutofillProfileTest, SetValidityFromBitfieldValue_City) { + AutofillProfile profile; + + // By default all validity statuses should be set to UNVALIDATED, thus the + // bitfield value should be empty. + EXPECT_EQ(0, profile.GetValidityBitfieldValue()); + + // 0b01000000 + profile.SetValidityFromBitfieldValue(64); + EXPECT_EQ(AutofillProfile::EMPTY, + profile.GetValidityState(ADDRESS_HOME_CITY)); + + // 0b10000000 + profile.SetValidityFromBitfieldValue(128); + EXPECT_EQ(AutofillProfile::VALID, + profile.GetValidityState(ADDRESS_HOME_CITY)); + + // 0b11000000 + profile.SetValidityFromBitfieldValue(192); + EXPECT_EQ(AutofillProfile::INVALID, + profile.GetValidityState(ADDRESS_HOME_CITY)); +} + +TEST(AutofillProfileTest, SetValidityFromBitfieldValue_DependentLocality) { + AutofillProfile profile; + + // By default all validity statuses should be set to UNVALIDATED, thus the + // bitfield value should be empty. + EXPECT_EQ(0, profile.GetValidityBitfieldValue()); + + // 0b0100000000 + profile.SetValidityFromBitfieldValue(256); + EXPECT_EQ(AutofillProfile::EMPTY, + profile.GetValidityState(ADDRESS_HOME_DEPENDENT_LOCALITY)); + + // 0b1000000000 + profile.SetValidityFromBitfieldValue(512); + EXPECT_EQ(AutofillProfile::VALID, + profile.GetValidityState(ADDRESS_HOME_DEPENDENT_LOCALITY)); + + // 0b1100000000 + profile.SetValidityFromBitfieldValue(768); + EXPECT_EQ(AutofillProfile::INVALID, + profile.GetValidityState(ADDRESS_HOME_DEPENDENT_LOCALITY)); +} + +TEST(AutofillProfileTest, SetValidityFromBitfieldValue_Email) { + AutofillProfile profile; + + // By default all validity statuses should be set to UNVALIDATED, thus the + // bitfield value should be empty. + EXPECT_EQ(0, profile.GetValidityBitfieldValue()); + + // 0b010000000000 + profile.SetValidityFromBitfieldValue(1024); + EXPECT_EQ(AutofillProfile::EMPTY, profile.GetValidityState(EMAIL_ADDRESS)); + + // 0b100000000000 + profile.SetValidityFromBitfieldValue(2048); + EXPECT_EQ(AutofillProfile::VALID, profile.GetValidityState(EMAIL_ADDRESS)); + + // 0b110000000000 + profile.SetValidityFromBitfieldValue(3072); + EXPECT_EQ(AutofillProfile::INVALID, profile.GetValidityState(EMAIL_ADDRESS)); +} + +TEST(AutofillProfileTest, SetValidityFromBitfieldValue_Phone) { + AutofillProfile profile; + + // By default all validity statuses should be set to UNVALIDATED, thus the + // bitfield value should be empty. + EXPECT_EQ(0, profile.GetValidityBitfieldValue()); + + // 0b01000000000000 + profile.SetValidityFromBitfieldValue(4096); + EXPECT_EQ(AutofillProfile::EMPTY, + profile.GetValidityState(PHONE_HOME_WHOLE_NUMBER)); + + // 0b10000000000000 + profile.SetValidityFromBitfieldValue(8192); + EXPECT_EQ(AutofillProfile::VALID, + profile.GetValidityState(PHONE_HOME_WHOLE_NUMBER)); + + // 0b11000000000000 + profile.SetValidityFromBitfieldValue(12288); + EXPECT_EQ(AutofillProfile::INVALID, + profile.GetValidityState(PHONE_HOME_WHOLE_NUMBER)); +} + +TEST(AutofillProfileTest, SetValidityFromBitfieldValue_Mixed) { + AutofillProfile profile; + + // By default all validity statuses should be set to UNVALIDATED, thus the + // bitfield value should be empty. + EXPECT_EQ(0, profile.GetValidityBitfieldValue()); + + // 0b01110011010010 + profile.SetValidityFromBitfieldValue(7378); + EXPECT_EQ(AutofillProfile::VALID, + profile.GetValidityState(ADDRESS_HOME_COUNTRY)); + EXPECT_EQ(AutofillProfile::UNVALIDATED, + profile.GetValidityState(ADDRESS_HOME_STATE)); + EXPECT_EQ(AutofillProfile::EMPTY, profile.GetValidityState(ADDRESS_HOME_ZIP)); + EXPECT_EQ(AutofillProfile::INVALID, + profile.GetValidityState(ADDRESS_HOME_CITY)); + EXPECT_EQ(AutofillProfile::UNVALIDATED, + profile.GetValidityState(ADDRESS_HOME_DEPENDENT_LOCALITY)); + EXPECT_EQ(AutofillProfile::INVALID, profile.GetValidityState(EMAIL_ADDRESS)); + EXPECT_EQ(AutofillProfile::EMPTY, + profile.GetValidityState(PHONE_HOME_WHOLE_NUMBER)); + + // 0b11001110101101 + profile.SetValidityFromBitfieldValue(13229); + EXPECT_EQ(AutofillProfile::EMPTY, + profile.GetValidityState(ADDRESS_HOME_COUNTRY)); + EXPECT_EQ(AutofillProfile::INVALID, + profile.GetValidityState(ADDRESS_HOME_STATE)); + EXPECT_EQ(AutofillProfile::VALID, profile.GetValidityState(ADDRESS_HOME_ZIP)); + EXPECT_EQ(AutofillProfile::VALID, + profile.GetValidityState(ADDRESS_HOME_CITY)); + EXPECT_EQ(AutofillProfile::INVALID, + profile.GetValidityState(ADDRESS_HOME_DEPENDENT_LOCALITY)); + EXPECT_EQ(AutofillProfile::UNVALIDATED, + profile.GetValidityState(EMAIL_ADDRESS)); + EXPECT_EQ(AutofillProfile::INVALID, + profile.GetValidityState(PHONE_HOME_WHOLE_NUMBER)); +} + } // namespace autofill diff --git a/chromium/components/autofill/core/browser/autofill_profile_validator_unittest.cc b/chromium/components/autofill/core/browser/autofill_profile_validator_unittest.cc index 52328bd1f6e..456920617a2 100644 --- a/chromium/components/autofill/core/browser/autofill_profile_validator_unittest.cc +++ b/chromium/components/autofill/core/browser/autofill_profile_validator_unittest.cc @@ -223,7 +223,7 @@ TEST_F(AutofillProfileValidatorTest, ValidateProfile_InvalidEmail) { AutofillProfile profile(autofill::test::GetFullValidProfile()); profile.SetRawInfo(EMAIL_ADDRESS, base::ASCIIToUTF16("Invalid Email.")); - set_expected_status(AutofillProfile::VALID); + set_expected_status(AutofillProfile::INVALID); validator_->ValidateProfile(&profile, std::move(onvalidated_cb_)); } diff --git a/chromium/components/autofill/core/browser/autofill_test_utils.cc b/chromium/components/autofill/core/browser/autofill_test_utils.cc index aa3b5952e4b..e0543b1eaf8 100644 --- a/chromium/components/autofill/core/browser/autofill_test_utils.cc +++ b/chromium/components/autofill/core/browser/autofill_test_utils.cc @@ -7,6 +7,8 @@ #include <string> #include "base/guid.h" +#include "base/rand_util.h" +#include "base/strings/stringprintf.h" #include "base/strings/utf_string_conversions.h" #include "build/build_config.h" #include "components/autofill/core/browser/autofill_manager.h" @@ -26,12 +28,26 @@ #include "components/signin/core/browser/account_fetcher_service.h" #include "components/signin/core/browser/account_tracker_service.h" #include "components/signin/core/common/signin_pref_names.h" +#include "testing/gtest/include/gtest/gtest.h" using base::ASCIIToUTF16; namespace autofill { namespace test { +namespace { + +std::string GetRandomCardNumber() { + const size_t length = 16; + std::string value; + value.reserve(length); + for (size_t i = 0; i < length; ++i) + value.push_back(static_cast<char>(base::RandInt('0', '9'))); + return value; +} + +} // namespace + std::unique_ptr<PrefService> PrefServiceForTesting() { scoped_refptr<user_prefs::PrefRegistrySyncable> registry( new user_prefs::PrefRegistrySyncable()); @@ -63,7 +79,7 @@ std::unique_ptr<PrefService> PrefServiceForTesting( registry->RegisterInt64Pref(AccountFetcherService::kLastUpdatePref, 0); PrefServiceFactory factory; - factory.set_user_prefs(make_scoped_refptr(new TestingPrefStore())); + factory.set_user_prefs(base::MakeRefCounted<TestingPrefStore>()); return factory.Create(registry); } @@ -294,6 +310,39 @@ CreditCard GetMaskedServerCardAmex() { return credit_card; } +CreditCard GetRandomCreditCard(CreditCard::RecordType record_type) { + static const char* const kNetworks[] = { + kAmericanExpressCard, + kDinersCard, + kDiscoverCard, + kEloCard, + kGenericCard, + kJCBCard, + kMasterCard, + kMirCard, + kUnionPay, + kVisaCard, + }; + constexpr size_t kNumNetworks = sizeof(kNetworks) / sizeof(kNetworks[0]); + base::Time::Exploded now; + base::Time::Now().LocalExplode(&now); + + CreditCard credit_card = + (record_type == CreditCard::LOCAL_CARD) + ? CreditCard(base::GenerateGUID(), "http://www.example.com") + : CreditCard(record_type, base::GenerateGUID().substr(24)); + test::SetCreditCardInfo( + &credit_card, "Justin Thyme", GetRandomCardNumber().c_str(), + base::StringPrintf("%d", base::RandInt(1, 12)).c_str(), + base::StringPrintf("%d", now.year + base::RandInt(1, 4)).c_str(), "1"); + if (record_type == CreditCard::MASKED_SERVER_CARD) { + credit_card.SetNetworkForMaskedCard( + kNetworks[base::RandInt(0, kNumNetworks - 1)]); + } + + return credit_card; +} + void SetProfileInfo(AutofillProfile* profile, const char* first_name, const char* middle_name, const char* last_name, const char* email, const char* company, @@ -362,8 +411,7 @@ void SetServerCreditCards(AutofillTable* table, for (const CreditCard& card : cards) { if (card.record_type() != CreditCard::FULL_SERVER_CARD) continue; - - table->UnmaskServerCreditCard(card, card.number()); + ASSERT_TRUE(table->UnmaskServerCreditCard(card, card.number())); } } diff --git a/chromium/components/autofill/core/browser/autofill_test_utils.h b/chromium/components/autofill/core/browser/autofill_test_utils.h index 708f3a640be..9bb13adcb24 100644 --- a/chromium/components/autofill/core/browser/autofill_test_utils.h +++ b/chromium/components/autofill/core/browser/autofill_test_utils.h @@ -9,6 +9,7 @@ #include <string> #include <vector> +#include "components/autofill/core/browser/credit_card.h" #include "components/autofill/core/browser/field_types.h" #include "components/autofill/core/browser/proto/server.pb.h" @@ -22,7 +23,6 @@ namespace autofill { class AutofillProfile; class AutofillTable; -class CreditCard; struct FormData; struct FormFieldData; @@ -102,6 +102,10 @@ CreditCard GetVerifiedCreditCard2(); CreditCard GetMaskedServerCard(); CreditCard GetMaskedServerCardAmex(); +// Returns a randomly generated credit card of |record_type|. Note that the +// card is not guaranteed to be valid/sane from a card validation standpoint. +CreditCard GetRandomCreditCard(CreditCard::RecordType record_Type); + // A unit testing utility that is common to a number of the Autofill unit // tests. |SetProfileInfo| provides a quick way to populate a profile with // c-strings. diff --git a/chromium/components/autofill/core/browser/credit_card.cc b/chromium/components/autofill/core/browser/credit_card.cc index 76ea54a319f..66de467ae8a 100644 --- a/chromium/components/autofill/core/browser/credit_card.cc +++ b/chromium/components/autofill/core/browser/credit_card.cc @@ -12,6 +12,7 @@ #include <string> #include "base/guid.h" +#include "base/i18n/string_search.h" #include "base/i18n/time_formatting.h" #include "base/i18n/unicodestring.h" #include "base/logging.h" @@ -31,7 +32,6 @@ #include "components/autofill/core/browser/autofill_type.h" #include "components/autofill/core/browser/validation.h" #include "components/autofill/core/common/autofill_clock.h" -#include "components/autofill/core/common/autofill_l10n_util.h" #include "components/autofill/core/common/autofill_regexes.h" #include "components/autofill/core/common/form_field_data.h" #include "components/grit/components_scaled_resources.h" @@ -916,34 +916,36 @@ bool CreditCard::ConvertMonth(const base::string16& month, return false; // Otherwise, try parsing the |month| as a named month, e.g. "January" or - // "Jan". - l10n::CaseInsensitiveCompare compare; + // "Jan" in the user's locale. UErrorCode status = U_ZERO_ERROR; icu::Locale locale(app_locale.c_str()); icu::DateFormatSymbols date_format_symbols(locale, status); DCHECK(status == U_ZERO_ERROR || status == U_USING_FALLBACK_WARNING || status == U_USING_DEFAULT_WARNING); - + // Full months (January, Janvier, etc.) 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( base::i18n::UnicodeStringToString16(months[i])); - if (compare.StringsEqual(icu_month, month)) { + // We look for the ICU-defined month in |month|. + if (base::i18n::StringSearchIgnoringCaseAndAccents(icu_month, month, + nullptr, nullptr)) { *num = i + 1; // Adjust from 0-indexed to 1-indexed. return true; } } - + // Abbreviated months (jan., janv., fév.) Some abbreviations have . at the end + // (e.g., "janv." in French). The period is removed. months = date_format_symbols.getShortMonths(num_months); - // Some abbreviations have . at the end (e.g., "janv." in French). We don't - // care about matching that. base::string16 trimmed_month; base::TrimString(month, ASCIIToUTF16("."), &trimmed_month); for (int32_t i = 0; i < num_months; ++i) { base::string16 icu_month(base::i18n::UnicodeStringToString16(months[i])); base::TrimString(icu_month, ASCIIToUTF16("."), &icu_month); - if (compare.StringsEqual(icu_month, trimmed_month)) { + // We look for the ICU-defined month in |trimmed_month|. + if (base::i18n::StringSearchIgnoringCaseAndAccents(icu_month, trimmed_month, + nullptr, nullptr)) { *num = i + 1; // Adjust from 0-indexed to 1-indexed. return true; } diff --git a/chromium/components/autofill/core/browser/form_structure.cc b/chromium/components/autofill/core/browser/form_structure.cc index 531a20758c1..98393571074 100644 --- a/chromium/components/autofill/core/browser/form_structure.cc +++ b/chromium/components/autofill/core/browser/form_structure.cc @@ -277,7 +277,7 @@ std::ostream& operator<<( const autofill::AutofillQueryResponseContents& response) { out << "upload_required: " << response.upload_required(); for (const auto& field : response.field()) { - out << "\nautofill_type: " << field.autofill_type(); + out << "\nautofill_type: " << field.overall_type_prediction(); } return out; } @@ -500,8 +500,8 @@ void FormStructure::ParseQueryResponse( if (current_field == response.field().end()) break; - ServerFieldType field_type = - static_cast<ServerFieldType>(current_field->autofill_type()); + ServerFieldType field_type = static_cast<ServerFieldType>( + current_field->overall_type_prediction()); query_response_has_no_server_data &= field_type == NO_SERVER_DATA; // UNKNOWN_TYPE is reserved for use by the client. @@ -511,7 +511,19 @@ void FormStructure::ParseQueryResponse( if (heuristic_type != UNKNOWN_TYPE) heuristics_detected_fillable_field = true; - field->set_server_type(field_type); + field->set_overall_server_type(field_type); + std::vector<AutofillQueryResponseContents::Field::FieldPrediction> + server_predictions; + if (current_field->predictions_size() == 0) { + AutofillQueryResponseContents::Field::FieldPrediction field_prediction; + field_prediction.set_type(field_type); + server_predictions.push_back(field_prediction); + } else { + server_predictions.assign(current_field->predictions().begin(), + current_field->predictions().end()); + } + field->set_server_predictions(std::move(server_predictions)); + if (heuristic_type != field->Type().GetStorableType()) query_response_overrode_heuristics = true; @@ -552,6 +564,7 @@ std::vector<FormDataPredictions> FormStructure::GetFieldTypePredictions( form.data.origin = form_structure->source_url_; form.data.action = form_structure->target_url_; form.data.is_form_tag = form_structure->is_form_tag_; + form.data.is_formless_checkout = form_structure->is_formless_checkout_; form.signature = form_structure->FormSignatureAsStr(); for (const auto& field : form_structure->fields_) { @@ -562,7 +575,7 @@ std::vector<FormDataPredictions> FormStructure::GetFieldTypePredictions( annotated_field.heuristic_type = AutofillType(field->heuristic_type()).ToString(); annotated_field.server_type = - AutofillType(field->server_type()).ToString(); + AutofillType(field->overall_server_type()).ToString(); annotated_field.overall_type = field->Type().ToString(); annotated_field.parseable_name = base::UTF16ToUTF8(field->parseable_name()); @@ -665,7 +678,8 @@ void FormStructure::UpdateFromCache(const FormStructure& cached_form, // Transfer attributes of the cached AutofillField to the newly created // AutofillField. field->set_heuristic_type(cached_field->second->heuristic_type()); - field->set_server_type(cached_field->second->server_type()); + field->set_overall_server_type( + cached_field->second->overall_server_type()); field->SetHtmlType(cached_field->second->html_type(), cached_field->second->html_mode()); if (apply_is_autofilled) { @@ -713,10 +727,9 @@ void FormStructure::LogQualityMetrics( for (size_t i = 0; i < field_count(); ++i) { auto* const field = this->field(i); - if (IsUPIVirtualPaymentAddress(field->value)) { AutofillMetrics::LogUserHappinessMetric( - AutofillMetrics::USER_DID_ENTER_UPI_VPA); + AutofillMetrics::USER_DID_ENTER_UPI_VPA, field->Type().group()); } form_interactions_ukm_logger->LogFieldFillStatus(*this, *field, @@ -774,8 +787,7 @@ void FormStructure::LogQualityMetrics( DCHECK(!submission_time.is_null()); // The |load_time| might be unset, in the case that the form was - // dynamically - // added to the DOM. + // dynamically added to the DOM. if (!load_time.is_null()) { // Submission should always chronologically follow form load. DCHECK(submission_time > load_time); @@ -792,13 +804,8 @@ void FormStructure::LogQualityMetrics( // Submission should always chronologically follow interaction. DCHECK(submission_time > interaction_time); base::TimeDelta elapsed = submission_time - interaction_time; - if (did_autofill_some_possible_fields) { - AutofillMetrics::LogFormFillDurationFromInteractionWithAutofill( - elapsed); - } else { - AutofillMetrics::LogFormFillDurationFromInteractionWithoutAutofill( - elapsed); - } + AutofillMetrics::LogFormFillDurationFromInteraction( + GetFormTypes(), did_autofill_some_possible_fields, elapsed); } } if (form_interactions_ukm_logger->url() != source_url()) @@ -1421,4 +1428,13 @@ base::string16 FormStructure::FindLongestCommonPrefix( return filtered_strings[0]; } +std::set<FormType> FormStructure::GetFormTypes() const { + std::set<FormType> form_types; + for (const auto& field : fields_) { + form_types.insert( + FormTypes::FieldTypeGroupToFormType(field->Type().group())); + } + return form_types; +} + } // namespace autofill diff --git a/chromium/components/autofill/core/browser/form_structure.h b/chromium/components/autofill/core/browser/form_structure.h index a1094eb7d95..d02b31beeab 100644 --- a/chromium/components/autofill/core/browser/form_structure.h +++ b/chromium/components/autofill/core/browser/form_structure.h @@ -21,6 +21,7 @@ #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/form_types.h" #include "components/autofill/core/browser/proto/server.pb.h" #include "url/gurl.h" @@ -243,6 +244,9 @@ class FormStructure { // Returns a FormData containing the data this form structure knows about. FormData ToFormData() const; + // Returns the possible form types. + std::set<FormType> GetFormTypes() const; + bool operator==(const FormData& form) const; bool operator!=(const FormData& form) const; diff --git a/chromium/components/autofill/core/browser/form_structure_unittest.cc b/chromium/components/autofill/core/browser/form_structure_unittest.cc index ff6cd263868..3548474f66b 100644 --- a/chromium/components/autofill/core/browser/form_structure_unittest.cc +++ b/chromium/components/autofill/core/browser/form_structure_unittest.cc @@ -943,8 +943,8 @@ TEST_F(FormStructureTest, EXPECT_EQ(UNKNOWN_TYPE, form_structure->field(0)->heuristic_type()); EXPECT_EQ(UNKNOWN_TYPE, form_structure->field(1)->heuristic_type()); - EXPECT_EQ(NO_SERVER_DATA, form_structure->field(0)->server_type()); - EXPECT_EQ(NO_SERVER_DATA, form_structure->field(1)->server_type()); + EXPECT_EQ(NO_SERVER_DATA, form_structure->field(0)->overall_server_type()); + EXPECT_EQ(NO_SERVER_DATA, form_structure->field(1)->overall_server_type()); } // Tests the heuristics and server predictions are not run for forms with less @@ -978,8 +978,8 @@ TEST_F(FormStructureTest, EXPECT_EQ(UNKNOWN_TYPE, form_structure->field(0)->heuristic_type()); EXPECT_EQ(UNKNOWN_TYPE, form_structure->field(1)->heuristic_type()); - EXPECT_EQ(NO_SERVER_DATA, form_structure->field(0)->server_type()); - EXPECT_EQ(NO_SERVER_DATA, form_structure->field(1)->server_type()); + EXPECT_EQ(NO_SERVER_DATA, form_structure->field(0)->overall_server_type()); + EXPECT_EQ(NO_SERVER_DATA, form_structure->field(1)->overall_server_type()); } // Even with an 'autocomplete' attribute set, ShouldBeCrowdsourced() should @@ -3768,10 +3768,17 @@ TEST_F(FormStructureTest, ParseQueryResponse) { forms.push_back(&form_structure2); AutofillQueryResponseContents response; - response.add_field()->set_autofill_type(7); - response.add_field()->set_autofill_type(30); - response.add_field()->set_autofill_type(9); - response.add_field()->set_autofill_type(0); + AutofillQueryResponseContents_Field* field0 = response.add_field(); + field0->set_overall_type_prediction(7); + AutofillQueryResponseContents_Field_FieldPrediction* field_prediction0 = + field0->add_predictions(); + field_prediction0->set_type(7); + AutofillQueryResponseContents_Field_FieldPrediction* field_prediction1 = + field0->add_predictions(); + field_prediction1->set_type(22); + response.add_field()->set_overall_type_prediction(30); + response.add_field()->set_overall_type_prediction(9); + response.add_field()->set_overall_type_prediction(0); std::string response_string; ASSERT_TRUE(response.SerializeToString(&response_string)); @@ -3779,10 +3786,19 @@ TEST_F(FormStructureTest, ParseQueryResponse) { ASSERT_GE(forms[0]->field_count(), 2U); ASSERT_GE(forms[1]->field_count(), 2U); - EXPECT_EQ(7, forms[0]->field(0)->server_type()); - EXPECT_EQ(30, forms[0]->field(1)->server_type()); - EXPECT_EQ(9, forms[1]->field(0)->server_type()); - EXPECT_EQ(0, forms[1]->field(1)->server_type()); + EXPECT_EQ(7, forms[0]->field(0)->overall_server_type()); + ASSERT_EQ(2U, forms[0]->field(0)->server_predictions().size()); + EXPECT_EQ(7U, forms[0]->field(0)->server_predictions()[0].type()); + EXPECT_EQ(22U, forms[0]->field(0)->server_predictions()[1].type()); + EXPECT_EQ(30, forms[0]->field(1)->overall_server_type()); + ASSERT_EQ(1U, forms[0]->field(1)->server_predictions().size()); + EXPECT_EQ(30U, forms[0]->field(1)->server_predictions()[0].type()); + EXPECT_EQ(9, forms[1]->field(0)->overall_server_type()); + ASSERT_EQ(1U, forms[1]->field(0)->server_predictions().size()); + EXPECT_EQ(9U, forms[1]->field(0)->server_predictions()[0].type()); + EXPECT_EQ(0, forms[1]->field(1)->overall_server_type()); + ASSERT_EQ(1U, forms[1]->field(1)->server_predictions().size()); + EXPECT_EQ(0U, forms[1]->field(1)->server_predictions()[0].type()); } TEST_F(FormStructureTest, ParseQueryResponseAuthorDefinedTypes) { @@ -3808,8 +3824,8 @@ TEST_F(FormStructureTest, ParseQueryResponseAuthorDefinedTypes) { forms.front()->DetermineHeuristicTypes(nullptr /* ukm_service */); AutofillQueryResponseContents response; - response.add_field()->set_autofill_type(EMAIL_ADDRESS); - response.add_field()->set_autofill_type(ACCOUNT_CREATION_PASSWORD); + response.add_field()->set_overall_type_prediction(EMAIL_ADDRESS); + response.add_field()->set_overall_type_prediction(ACCOUNT_CREATION_PASSWORD); std::string response_string; ASSERT_TRUE(response.SerializeToString(&response_string)); @@ -3817,9 +3833,10 @@ TEST_F(FormStructureTest, ParseQueryResponseAuthorDefinedTypes) { ASSERT_GE(forms[0]->field_count(), 2U); // Server type is parsed from the response and is the end result type. - EXPECT_EQ(EMAIL_ADDRESS, forms[0]->field(0)->server_type()); + EXPECT_EQ(EMAIL_ADDRESS, forms[0]->field(0)->overall_server_type()); EXPECT_EQ(EMAIL_ADDRESS, forms[0]->field(0)->Type().GetStorableType()); - EXPECT_EQ(ACCOUNT_CREATION_PASSWORD, forms[0]->field(1)->server_type()); + EXPECT_EQ(ACCOUNT_CREATION_PASSWORD, + forms[0]->field(1)->overall_server_type()); // TODO(crbug.com/613666): Should be a properly defined type, and not // UNKNOWN_TYPE. EXPECT_EQ(UNKNOWN_TYPE, forms[0]->field(1)->Type().GetStorableType()); @@ -3852,10 +3869,11 @@ TEST_F(FormStructureTest, ParseQueryResponse_RationalizeLoneField) { forms.push_back(&form_structure); AutofillQueryResponseContents response; - response.add_field()->set_autofill_type(NAME_FULL); - response.add_field()->set_autofill_type(ADDRESS_HOME_LINE1); - response.add_field()->set_autofill_type(CREDIT_CARD_EXP_MONTH); // Uh-oh! - response.add_field()->set_autofill_type(EMAIL_ADDRESS); + response.add_field()->set_overall_type_prediction(NAME_FULL); + response.add_field()->set_overall_type_prediction(ADDRESS_HOME_LINE1); + response.add_field()->set_overall_type_prediction( + CREDIT_CARD_EXP_MONTH); // Uh-oh! + response.add_field()->set_overall_type_prediction(EMAIL_ADDRESS); std::string response_string; ASSERT_TRUE(response.SerializeToString(&response_string)); @@ -3869,10 +3887,10 @@ TEST_F(FormStructureTest, ParseQueryResponse_RationalizeLoneField) { FormStructure::ParseQueryResponse(response_string, forms); ASSERT_EQ(1U, forms.size()); ASSERT_EQ(4U, forms[0]->field_count()); - EXPECT_EQ(NAME_FULL, forms[0]->field(0)->server_type()); - EXPECT_EQ(ADDRESS_HOME_LINE1, forms[0]->field(1)->server_type()); - EXPECT_EQ(NO_SERVER_DATA, forms[0]->field(2)->server_type()); - EXPECT_EQ(EMAIL_ADDRESS, forms[0]->field(3)->server_type()); + EXPECT_EQ(NAME_FULL, forms[0]->field(0)->overall_server_type()); + EXPECT_EQ(ADDRESS_HOME_LINE1, forms[0]->field(1)->overall_server_type()); + EXPECT_EQ(NO_SERVER_DATA, forms[0]->field(2)->overall_server_type()); + EXPECT_EQ(EMAIL_ADDRESS, forms[0]->field(3)->overall_server_type()); } // Sanity check that the enable/disabled works. @@ -3884,10 +3902,10 @@ TEST_F(FormStructureTest, ParseQueryResponse_RationalizeLoneField) { FormStructure::ParseQueryResponse(response_string, forms); ASSERT_EQ(1U, forms.size()); ASSERT_EQ(4U, forms[0]->field_count()); - EXPECT_EQ(NAME_FULL, forms[0]->field(0)->server_type()); - EXPECT_EQ(ADDRESS_HOME_LINE1, forms[0]->field(1)->server_type()); - EXPECT_EQ(CREDIT_CARD_EXP_MONTH, forms[0]->field(2)->server_type()); - EXPECT_EQ(EMAIL_ADDRESS, forms[0]->field(3)->server_type()); + EXPECT_EQ(NAME_FULL, forms[0]->field(0)->overall_server_type()); + EXPECT_EQ(ADDRESS_HOME_LINE1, forms[0]->field(1)->overall_server_type()); + EXPECT_EQ(CREDIT_CARD_EXP_MONTH, forms[0]->field(2)->overall_server_type()); + EXPECT_EQ(EMAIL_ADDRESS, forms[0]->field(3)->overall_server_type()); } } @@ -3914,9 +3932,9 @@ TEST_F(FormStructureTest, ParseQueryResponse_RationalizeCCName) { forms.push_back(&form_structure); AutofillQueryResponseContents response; - response.add_field()->set_autofill_type(CREDIT_CARD_NAME_FIRST); - response.add_field()->set_autofill_type(CREDIT_CARD_NAME_LAST); - response.add_field()->set_autofill_type(EMAIL_ADDRESS); + response.add_field()->set_overall_type_prediction(CREDIT_CARD_NAME_FIRST); + response.add_field()->set_overall_type_prediction(CREDIT_CARD_NAME_LAST); + response.add_field()->set_overall_type_prediction(EMAIL_ADDRESS); std::string response_string; ASSERT_TRUE(response.SerializeToString(&response_string)); @@ -3930,9 +3948,9 @@ TEST_F(FormStructureTest, ParseQueryResponse_RationalizeCCName) { FormStructure::ParseQueryResponse(response_string, forms); ASSERT_EQ(1U, forms.size()); ASSERT_EQ(3U, forms[0]->field_count()); - EXPECT_EQ(NAME_FIRST, forms[0]->field(0)->server_type()); - EXPECT_EQ(NAME_LAST, forms[0]->field(1)->server_type()); - EXPECT_EQ(EMAIL_ADDRESS, forms[0]->field(2)->server_type()); + EXPECT_EQ(NAME_FIRST, forms[0]->field(0)->overall_server_type()); + EXPECT_EQ(NAME_LAST, forms[0]->field(1)->overall_server_type()); + EXPECT_EQ(EMAIL_ADDRESS, forms[0]->field(2)->overall_server_type()); } // Sanity check that the enable/disabled works. @@ -3944,9 +3962,10 @@ TEST_F(FormStructureTest, ParseQueryResponse_RationalizeCCName) { FormStructure::ParseQueryResponse(response_string, forms); ASSERT_EQ(1U, forms.size()); ASSERT_EQ(3U, forms[0]->field_count()); - EXPECT_EQ(CREDIT_CARD_NAME_FIRST, forms[0]->field(0)->server_type()); - EXPECT_EQ(CREDIT_CARD_NAME_LAST, forms[0]->field(1)->server_type()); - EXPECT_EQ(EMAIL_ADDRESS, forms[0]->field(2)->server_type()); + EXPECT_EQ(CREDIT_CARD_NAME_FIRST, + forms[0]->field(0)->overall_server_type()); + EXPECT_EQ(CREDIT_CARD_NAME_LAST, forms[0]->field(1)->overall_server_type()); + EXPECT_EQ(EMAIL_ADDRESS, forms[0]->field(2)->overall_server_type()); } } @@ -3981,11 +4000,13 @@ TEST_F(FormStructureTest, ParseQueryResponse_RationalizeMultiMonth_1) { forms.push_back(&form_structure); AutofillQueryResponseContents response; - response.add_field()->set_autofill_type(CREDIT_CARD_NAME_FULL); - response.add_field()->set_autofill_type(CREDIT_CARD_NUMBER); - response.add_field()->set_autofill_type(CREDIT_CARD_EXP_MONTH); - response.add_field()->set_autofill_type(CREDIT_CARD_EXP_2_DIGIT_YEAR); - response.add_field()->set_autofill_type(CREDIT_CARD_EXP_MONTH); // Uh-oh! + response.add_field()->set_overall_type_prediction(CREDIT_CARD_NAME_FULL); + response.add_field()->set_overall_type_prediction(CREDIT_CARD_NUMBER); + response.add_field()->set_overall_type_prediction(CREDIT_CARD_EXP_MONTH); + response.add_field()->set_overall_type_prediction( + CREDIT_CARD_EXP_2_DIGIT_YEAR); + response.add_field()->set_overall_type_prediction( + CREDIT_CARD_EXP_MONTH); // Uh-oh! std::string response_string; ASSERT_TRUE(response.SerializeToString(&response_string)); @@ -3999,11 +4020,12 @@ TEST_F(FormStructureTest, ParseQueryResponse_RationalizeMultiMonth_1) { FormStructure::ParseQueryResponse(response_string, forms); ASSERT_EQ(1U, forms.size()); ASSERT_EQ(5U, forms[0]->field_count()); - EXPECT_EQ(CREDIT_CARD_NAME_FULL, forms[0]->field(0)->server_type()); - EXPECT_EQ(CREDIT_CARD_NUMBER, forms[0]->field(1)->server_type()); - EXPECT_EQ(CREDIT_CARD_EXP_MONTH, forms[0]->field(2)->server_type()); - EXPECT_EQ(CREDIT_CARD_EXP_2_DIGIT_YEAR, forms[0]->field(3)->server_type()); - EXPECT_EQ(NO_SERVER_DATA, forms[0]->field(4)->server_type()); + EXPECT_EQ(CREDIT_CARD_NAME_FULL, forms[0]->field(0)->overall_server_type()); + EXPECT_EQ(CREDIT_CARD_NUMBER, forms[0]->field(1)->overall_server_type()); + EXPECT_EQ(CREDIT_CARD_EXP_MONTH, forms[0]->field(2)->overall_server_type()); + EXPECT_EQ(CREDIT_CARD_EXP_2_DIGIT_YEAR, + forms[0]->field(3)->overall_server_type()); + EXPECT_EQ(NO_SERVER_DATA, forms[0]->field(4)->overall_server_type()); } // Sanity check that the enable/disabled works. @@ -4015,11 +4037,12 @@ TEST_F(FormStructureTest, ParseQueryResponse_RationalizeMultiMonth_1) { FormStructure::ParseQueryResponse(response_string, forms); ASSERT_EQ(1U, forms.size()); ASSERT_EQ(5U, forms[0]->field_count()); - EXPECT_EQ(CREDIT_CARD_NAME_FULL, forms[0]->field(0)->server_type()); - EXPECT_EQ(CREDIT_CARD_NUMBER, forms[0]->field(1)->server_type()); - EXPECT_EQ(CREDIT_CARD_EXP_MONTH, forms[0]->field(2)->server_type()); - EXPECT_EQ(CREDIT_CARD_EXP_2_DIGIT_YEAR, forms[0]->field(3)->server_type()); - EXPECT_EQ(CREDIT_CARD_EXP_MONTH, forms[0]->field(4)->server_type()); + EXPECT_EQ(CREDIT_CARD_NAME_FULL, forms[0]->field(0)->overall_server_type()); + EXPECT_EQ(CREDIT_CARD_NUMBER, forms[0]->field(1)->overall_server_type()); + EXPECT_EQ(CREDIT_CARD_EXP_MONTH, forms[0]->field(2)->overall_server_type()); + EXPECT_EQ(CREDIT_CARD_EXP_2_DIGIT_YEAR, + forms[0]->field(3)->overall_server_type()); + EXPECT_EQ(CREDIT_CARD_EXP_MONTH, forms[0]->field(4)->overall_server_type()); } } @@ -4050,10 +4073,12 @@ TEST_F(FormStructureTest, ParseQueryResponse_RationalizeMultiMonth_2) { forms.push_back(&form_structure); AutofillQueryResponseContents response; - response.add_field()->set_autofill_type(CREDIT_CARD_NAME_FULL); - response.add_field()->set_autofill_type(CREDIT_CARD_NUMBER); - response.add_field()->set_autofill_type(CREDIT_CARD_EXP_DATE_2_DIGIT_YEAR); - response.add_field()->set_autofill_type(CREDIT_CARD_EXP_MONTH); // Uh-oh! + response.add_field()->set_overall_type_prediction(CREDIT_CARD_NAME_FULL); + response.add_field()->set_overall_type_prediction(CREDIT_CARD_NUMBER); + response.add_field()->set_overall_type_prediction( + CREDIT_CARD_EXP_DATE_2_DIGIT_YEAR); + response.add_field()->set_overall_type_prediction( + CREDIT_CARD_EXP_MONTH); // Uh-oh! std::string response_string; ASSERT_TRUE(response.SerializeToString(&response_string)); @@ -4066,11 +4091,11 @@ TEST_F(FormStructureTest, ParseQueryResponse_RationalizeMultiMonth_2) { FormStructure::ParseQueryResponse(response_string, forms); ASSERT_EQ(1U, forms.size()); ASSERT_EQ(4U, forms[0]->field_count()); - EXPECT_EQ(CREDIT_CARD_NAME_FULL, forms[0]->field(0)->server_type()); - EXPECT_EQ(CREDIT_CARD_NUMBER, forms[0]->field(1)->server_type()); + EXPECT_EQ(CREDIT_CARD_NAME_FULL, forms[0]->field(0)->overall_server_type()); + EXPECT_EQ(CREDIT_CARD_NUMBER, forms[0]->field(1)->overall_server_type()); EXPECT_EQ(CREDIT_CARD_EXP_DATE_2_DIGIT_YEAR, - forms[0]->field(2)->server_type()); - EXPECT_EQ(NO_SERVER_DATA, forms[0]->field(3)->server_type()); + forms[0]->field(2)->overall_server_type()); + EXPECT_EQ(NO_SERVER_DATA, forms[0]->field(3)->overall_server_type()); } // Sanity check that the enable/disabled works. @@ -4081,11 +4106,11 @@ TEST_F(FormStructureTest, ParseQueryResponse_RationalizeMultiMonth_2) { FormStructure::ParseQueryResponse(response_string, forms); ASSERT_EQ(1U, forms.size()); ASSERT_EQ(4U, forms[0]->field_count()); - EXPECT_EQ(CREDIT_CARD_NAME_FULL, forms[0]->field(0)->server_type()); - EXPECT_EQ(CREDIT_CARD_NUMBER, forms[0]->field(1)->server_type()); + EXPECT_EQ(CREDIT_CARD_NAME_FULL, forms[0]->field(0)->overall_server_type()); + EXPECT_EQ(CREDIT_CARD_NUMBER, forms[0]->field(1)->overall_server_type()); EXPECT_EQ(CREDIT_CARD_EXP_DATE_2_DIGIT_YEAR, - forms[0]->field(2)->server_type()); - EXPECT_EQ(CREDIT_CARD_EXP_MONTH, forms[0]->field(3)->server_type()); + forms[0]->field(2)->overall_server_type()); + EXPECT_EQ(CREDIT_CARD_EXP_MONTH, forms[0]->field(3)->overall_server_type()); } } diff --git a/chromium/components/autofill/core/browser/form_types.cc b/chromium/components/autofill/core/browser/form_types.cc new file mode 100644 index 00000000000..86f694cc7f7 --- /dev/null +++ b/chromium/components/autofill/core/browser/form_types.cc @@ -0,0 +1,26 @@ +// Copyright 2013 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "components/autofill/core/browser/form_types.h" +#include "components/autofill/core/browser/field_types.h" + +namespace autofill { + +// static +FormType FormTypes::FieldTypeGroupToFormType(FieldTypeGroup field_type_group) { + switch (field_type_group) { + case CREDIT_CARD: + return CREDIT_CARD_FORM; + case USERNAME_FIELD: + case PASSWORD_FIELD: + return PASSWORD_FORM; + case NO_GROUP: + case TRANSACTION: + return UNKNOWN_FORM_TYPE; + default: + // Assuming it's an address form by process of elimination. + return ADDRESS_FORM; + } +} +} // namespace autofill diff --git a/chromium/components/autofill/core/browser/form_types.h b/chromium/components/autofill/core/browser/form_types.h new file mode 100644 index 00000000000..2c36914c826 --- /dev/null +++ b/chromium/components/autofill/core/browser/form_types.h @@ -0,0 +1,26 @@ +// Copyright 2013 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef COMPONENTS_AUTOFILL_CORE_BROWSER_FORM_TYPES_H_ +#define COMPONENTS_AUTOFILL_CORE_BROWSER_FORM_TYPES_H_ + +#include "components/autofill/core/browser/field_types.h" + +namespace autofill { + +enum FormType : int { + UNKNOWN_FORM_TYPE, + ADDRESS_FORM, + CREDIT_CARD_FORM, + PASSWORD_FORM +}; + +class FormTypes { + public: + static FormType FieldTypeGroupToFormType(FieldTypeGroup field_type_group); +}; + +} // namespace autofill + +#endif // COMPONENTS_AUTOFILL_CORE_BROWSER_FORM_TYPES_H_ diff --git a/chromium/components/autofill/core/browser/personal_data_manager.cc b/chromium/components/autofill/core/browser/personal_data_manager.cc index f2af614cd3c..4916d3a18ab 100644 --- a/chromium/components/autofill/core/browser/personal_data_manager.cc +++ b/chromium/components/autofill/core/browser/personal_data_manager.cc @@ -16,10 +16,10 @@ #include "base/i18n/case_conversion.h" #include "base/i18n/timezone.h" #include "base/memory/ptr_util.h" -#include "base/profiler/scoped_tracker.h" #include "base/stl_util.h" #include "base/strings/string_number_conversions.h" #include "base/strings/string_util.h" +#include "base/strings/stringprintf.h" #include "base/strings/utf_string_conversions.h" #include "build/build_config.h" #include "components/autofill/core/browser/address_i18n.h" @@ -63,21 +63,34 @@ const int LOCAL_GUID_LENGTH = 36; constexpr base::TimeDelta kDisusedProfileTimeDelta = base::TimeDelta::FromDays(180); +constexpr base::TimeDelta kDisusedCreditCardTimeDelta = + base::TimeDelta::FromDays(180); +constexpr base::TimeDelta kDisusedCreditCardDeletionTimeDelta = + base::TimeDelta::FromDays(395); +constexpr base::TimeDelta kDisusedAddressDeletionTimeDelta = + base::TimeDelta::FromDays(395); + +// Time delta to create test data. +base::TimeDelta DeletableUseDateDelta() { + static base::TimeDelta delta = + kDisusedCreditCardDeletionTimeDelta + base::TimeDelta::FromDays(5); + return delta; +} +base::TimeDelta DeletableExpiryDateDelta() { + static base::TimeDelta delta = + kDisusedCreditCardDeletionTimeDelta + base::TimeDelta::FromDays(45); + return delta; +} -template<typename T> +template <typename T> class FormGroupMatchesByGUIDFunctor { public: explicit FormGroupMatchesByGUIDFunctor(const std::string& guid) - : guid_(guid) { - } + : guid_(guid) {} - bool operator()(const T& form_group) { - return form_group.guid() == guid_; - } + bool operator()(const T& form_group) { return form_group.guid() == guid_; } - bool operator()(const T* form_group) { - return form_group->guid() == guid_; - } + bool operator()(const T* form_group) { return form_group->guid() == guid_; } bool operator()(const std::unique_ptr<T>& form_group) { return form_group->guid() == guid_; @@ -87,25 +100,23 @@ class FormGroupMatchesByGUIDFunctor { const std::string guid_; }; -template<typename T, typename C> +template <typename T, typename C> typename C::const_iterator FindElementByGUID(const C& container, const std::string& guid) { - return std::find_if(container.begin(), - container.end(), + return std::find_if(container.begin(), container.end(), FormGroupMatchesByGUIDFunctor<T>(guid)); } -template<typename T, typename C> +template <typename T, typename C> bool FindByGUID(const C& container, const std::string& guid) { return FindElementByGUID<T>(container, guid) != container.end(); } -template<typename T> +template <typename T> class IsEmptyFunctor { public: explicit IsEmptyFunctor(const std::string& app_locale) - : app_locale_(app_locale) { - } + : app_locale_(app_locale) {} bool operator()(const T& form_group) { return form_group.IsEmpty(app_locale_); @@ -115,6 +126,12 @@ class IsEmptyFunctor { const std::string app_locale_; }; +bool IsSyncEnabledFor(const syncer::SyncService* sync_service, + syncer::ModelType model_type) { + return sync_service != nullptr && sync_service->CanSyncStart() && + sync_service->GetPreferredDataTypes().Has(model_type); +} + // Returns true if minimum requirements for import of a given |profile| have // been met. An address submitted via a form must have at least the fields // required as determined by its country code. @@ -156,8 +173,7 @@ bool IsValidFieldTypeAndValue(const std::set<ServerFieldType>& types_seen, // Make an exception for PHONE_HOME_NUMBER however as both prefix and // suffix are stored against this type, and for EMAIL_ADDRESS because it is // common to see second 'confirm email address' fields on forms. - if (types_seen.count(field_type) && - field_type != PHONE_HOME_NUMBER && + if (types_seen.count(field_type) && field_type != PHONE_HOME_NUMBER && field_type != EMAIL_ADDRESS) return false; @@ -258,6 +274,129 @@ bool IsValidSuggestionForFieldContents(base::string16 suggestion_canon, return false; } +AutofillProfile CreateBasicTestAddress(const std::string& locale) { + const base::Time use_date = + AutofillClock::Now() - base::TimeDelta::FromDays(20); + AutofillProfile profile; + profile.SetInfo(NAME_FULL, base::UTF8ToUTF16("John McTester"), locale); + profile.SetInfo(COMPANY_NAME, base::UTF8ToUTF16("Test Inc."), locale); + profile.SetInfo(EMAIL_ADDRESS, + base::UTF8ToUTF16("jmctester@fake.chromium.org"), locale); + profile.SetInfo(ADDRESS_HOME_LINE1, base::UTF8ToUTF16("123 Invented Street"), + locale); + profile.SetInfo(ADDRESS_HOME_LINE2, base::UTF8ToUTF16("Suite A"), locale); + profile.SetInfo(ADDRESS_HOME_CITY, base::UTF8ToUTF16("Mountain View"), + locale); + profile.SetInfo(ADDRESS_HOME_STATE, base::UTF8ToUTF16("California"), locale); + profile.SetInfo(ADDRESS_HOME_ZIP, base::UTF8ToUTF16("94043"), locale); + profile.SetInfo(ADDRESS_HOME_COUNTRY, base::UTF8ToUTF16("US"), locale); + profile.SetInfo(PHONE_HOME_WHOLE_NUMBER, base::UTF8ToUTF16("844-555-0173"), + locale); + profile.set_use_date(use_date); + return profile; +} + +AutofillProfile CreateDisusedTestAddress(const std::string& locale) { + const base::Time use_date = + AutofillClock::Now() - base::TimeDelta::FromDays(185); + AutofillProfile profile; + profile.SetInfo(NAME_FULL, base::UTF8ToUTF16("Polly Disused"), locale); + profile.SetInfo(COMPANY_NAME, + base::UTF8ToUTF16(base::StringPrintf( + "%lld Inc.", static_cast<long long>(use_date.ToTimeT()))), + locale); + profile.SetInfo(EMAIL_ADDRESS, + base::UTF8ToUTF16("polly.disused@fake.chromium.org"), locale); + profile.SetInfo(ADDRESS_HOME_LINE1, base::UTF8ToUTF16("456 Disused Lane"), + locale); + profile.SetInfo(ADDRESS_HOME_LINE2, base::UTF8ToUTF16("Apt. B"), locale); + profile.SetInfo(ADDRESS_HOME_CITY, base::UTF8ToUTF16("Austin"), locale); + profile.SetInfo(ADDRESS_HOME_STATE, base::UTF8ToUTF16("Texas"), locale); + profile.SetInfo(ADDRESS_HOME_ZIP, base::UTF8ToUTF16("73301"), locale); + profile.SetInfo(ADDRESS_HOME_COUNTRY, base::UTF8ToUTF16("US"), locale); + profile.SetInfo(PHONE_HOME_WHOLE_NUMBER, base::UTF8ToUTF16("844-555-0174"), + locale); + profile.set_use_date(use_date); + return profile; +} + +AutofillProfile CreateDisusedDeletableTestAddress(const std::string& locale) { + const base::Time use_date = + AutofillClock::Now() - base::TimeDelta::FromDays(400); + AutofillProfile profile; + profile.SetInfo(NAME_FULL, base::UTF8ToUTF16("Polly Deletable"), locale); + profile.SetInfo(COMPANY_NAME, + base::UTF8ToUTF16(base::StringPrintf( + "%lld Inc.", static_cast<long long>(use_date.ToTimeT()))), + locale); + profile.SetInfo(EMAIL_ADDRESS, + base::UTF8ToUTF16("polly.deletable@fake.chromium.org"), + locale); + profile.SetInfo(ADDRESS_HOME_LINE1, base::UTF8ToUTF16("459 Deletable Lane"), + locale); + profile.SetInfo(ADDRESS_HOME_LINE2, base::UTF8ToUTF16("Apt. B"), locale); + profile.SetInfo(ADDRESS_HOME_CITY, base::UTF8ToUTF16("Austin"), locale); + profile.SetInfo(ADDRESS_HOME_STATE, base::UTF8ToUTF16("Texas"), locale); + profile.SetInfo(ADDRESS_HOME_ZIP, base::UTF8ToUTF16("73301"), locale); + profile.SetInfo(ADDRESS_HOME_COUNTRY, base::UTF8ToUTF16("US"), locale); + profile.SetInfo(PHONE_HOME_WHOLE_NUMBER, base::UTF8ToUTF16("844-555-0274"), + locale); + profile.set_use_date(use_date); + return profile; +} + +// Create a card expiring 500 days from now which was last used 10 days ago. +CreditCard CreateBasicTestCreditCard(const std::string& locale) { + const base::Time now = AutofillClock::Now(); + const base::Time use_date = now - base::TimeDelta::FromDays(10); + base::Time::Exploded expiry_date; + (now + base::TimeDelta::FromDays(500)).LocalExplode(&expiry_date); + + CreditCard credit_card; + credit_card.SetInfo(CREDIT_CARD_NAME_FULL, + base::UTF8ToUTF16("Alice Testerson"), locale); + credit_card.SetInfo(CREDIT_CARD_NUMBER, base::UTF8ToUTF16("4545454545454545"), + locale); + credit_card.SetExpirationMonth(expiry_date.month); + credit_card.SetExpirationYear(expiry_date.year); + credit_card.set_use_date(use_date); + return credit_card; +} + +CreditCard CreateDisusedTestCreditCard(const std::string& locale) { + const base::Time now = AutofillClock::Now(); + const base::Time use_date = now - base::TimeDelta::FromDays(185); + base::Time::Exploded expiry_date; + (now - base::TimeDelta::FromDays(200)).LocalExplode(&expiry_date); + + CreditCard credit_card; + credit_card.SetInfo(CREDIT_CARD_NAME_FULL, base::UTF8ToUTF16("Bob Disused"), + locale); + credit_card.SetInfo(CREDIT_CARD_NUMBER, base::UTF8ToUTF16("4111111111111111"), + locale); + credit_card.SetExpirationMonth(expiry_date.month); + credit_card.SetExpirationYear(expiry_date.year); + credit_card.set_use_date(use_date); + return credit_card; +} + +CreditCard CreateDisusedDeletableTestCreditCard(const std::string& locale) { + const base::Time now = AutofillClock::Now(); + const base::Time use_date = now - DeletableUseDateDelta(); + base::Time::Exploded expiry_date; + (now - DeletableExpiryDateDelta()).LocalExplode(&expiry_date); + + CreditCard credit_card; + credit_card.SetInfo(CREDIT_CARD_NAME_FULL, + base::UTF8ToUTF16("Charlie Deletable"), locale); + credit_card.SetInfo(CREDIT_CARD_NUMBER, base::UTF8ToUTF16("378282246310005"), + locale); + credit_card.SetExpirationMonth(expiry_date.month); + credit_card.SetExpirationYear(expiry_date.year); + credit_card.set_use_date(use_date); + return credit_card; +} + } // namespace const char kFrecencyFieldTrialName[] = "AutofillProfileOrderByFrecency"; @@ -275,8 +414,7 @@ PersonalDataManager::PersonalDataManager(const std::string& app_locale) account_tracker_(nullptr), is_off_the_record_(false), has_logged_stored_profile_metrics_(false), - has_logged_local_credit_card_count_(false), - has_logged_server_credit_card_counts_(false) {} + has_logged_stored_credit_card_metrics_(false) {} void PersonalDataManager::Init(scoped_refptr<AutofillWebDataService> database, PrefService* pref_service, @@ -325,28 +463,23 @@ PersonalDataManager::~PersonalDataManager() { void PersonalDataManager::OnSyncServiceInitialized( syncer::SyncService* sync_service) { - // We want to know when, if at all, we need to run autofill profile de- - // duplication: now or after waiting until sync has started. - if (!is_autofill_profile_cleanup_pending_) { - // De-duplication isn't enabled. - return; + // If the sync service is not enabled for autofill address profiles then run + // address cleanup/startup code here. Otherwise, defer until after sync has + // started. + if (!IsSyncEnabledFor(sync_service, syncer::AUTOFILL_PROFILE)) { + ApplyProfileUseDatesFix(); // One-time fix, otherwise NOP. + ApplyDedupingRoutine(); // Once per major version, otherwise NOP. + DeleteDisusedAddresses(); // Once per major version, otherwise NOP. + CreateTestAddresses(); // Once per user profile startup. } - // If the sync service is configured to start and to sync autofill profiles, - // then we can just let the notification that sync has started trigger the - // de-duplication. - if (sync_service && sync_service->CanSyncStart() && - sync_service->GetPreferredDataTypes().Has(syncer::AUTOFILL_PROFILE)) { - return; + // Similarly, if the sync service is not enabled for autofill credit cards + // then run credit card address cleanup/startup code here. Otherwise, defer + // until after sync has started. + if (!IsSyncEnabledFor(sync_service, syncer::AUTOFILL_WALLET_DATA)) { + DeleteDisusedCreditCards(); // Once per major version, otherwise NOP. + CreateTestCreditCards(); // Once per user profile startup. } - - // This runs as a one-time fix, tracked in syncable prefs. If it has already - // run, it is a NOP (other than checking the pref). - ApplyProfileUseDatesFix(); - - // This runs at most once per major version, tracked in syncable prefs. If it - // has already run for this version, it's a NOP, other than checking the pref. - ApplyDedupingRoutine(); } void PersonalDataManager::OnWebDataServiceRequestDone( @@ -355,12 +488,6 @@ void PersonalDataManager::OnWebDataServiceRequestDone( DCHECK(pending_profiles_query_ || pending_server_profiles_query_ || pending_creditcards_query_ || pending_server_creditcards_query_); - // TODO(robliao): Remove ScopedTracker below once https://crbug.com/422460 is - // fixed. - tracked_objects::ScopedTracker tracking_profile( - FROM_HERE_WITH_EXPLICIT_FUNCTION( - "422460 PersonalDataManager::OnWebDataServiceRequestDone")); - if (!result) { // Error from the web database. if (h == pending_creditcards_query_) @@ -371,48 +498,45 @@ void PersonalDataManager::OnWebDataServiceRequestDone( pending_server_creditcards_query_ = 0; else if (h == pending_server_profiles_query_) pending_server_profiles_query_ = 0; - return; - } - - switch (result->GetType()) { - case AUTOFILL_PROFILES_RESULT: - if (h == pending_profiles_query_) { - ReceiveLoadedDbValues(h, result.get(), &pending_profiles_query_, - &web_profiles_); - LogStoredProfileMetrics(); // This only logs local profiles. - } else { - ReceiveLoadedDbValues(h, result.get(), &pending_server_profiles_query_, - &server_profiles_); - } - break; - case AUTOFILL_CREDITCARDS_RESULT: - if (h == pending_creditcards_query_) { - ReceiveLoadedDbValues(h, result.get(), &pending_creditcards_query_, - &local_credit_cards_); - LogLocalCreditCardCount(); - } else { - ReceiveLoadedDbValues(h, result.get(), - &pending_server_creditcards_query_, - &server_credit_cards_); - - // If the user has a saved unmasked server card and the experiment is - // disabled, force mask all cards back to the unsaved state. - if (!OfferStoreUnmaskedCards()) - ResetFullServerCards(); - - LogServerCreditCardCounts(); - } - break; - default: - NOTREACHED(); + } else { + switch (result->GetType()) { + case AUTOFILL_PROFILES_RESULT: + if (h == pending_profiles_query_) { + ReceiveLoadedDbValues(h, result.get(), &pending_profiles_query_, + &web_profiles_); + } else { + ReceiveLoadedDbValues(h, result.get(), + &pending_server_profiles_query_, + &server_profiles_); + } + break; + case AUTOFILL_CREDITCARDS_RESULT: + if (h == pending_creditcards_query_) { + ReceiveLoadedDbValues(h, result.get(), &pending_creditcards_query_, + &local_credit_cards_); + } else { + ReceiveLoadedDbValues(h, result.get(), + &pending_server_creditcards_query_, + &server_credit_cards_); + + // If the user has a saved unmasked server card and the experiment is + // disabled, force mask all cards back to the unsaved state. + if (!OfferStoreUnmaskedCards()) + ResetFullServerCards(); + } + break; + default: + NOTREACHED(); + } } // If all requests have responded, then all personal data is loaded. - if (pending_profiles_query_ == 0 && - pending_creditcards_query_ == 0 && + if (pending_profiles_query_ == 0 && pending_creditcards_query_ == 0 && pending_server_profiles_query_ == 0 && pending_server_creditcards_query_ == 0) { is_data_loaded_ = true; + LogStoredProfileMetrics(); + LogStoredCreditCardMetrics(); NotifyPersonalDataChanged(); } } @@ -423,16 +547,20 @@ void PersonalDataManager::AutofillMultipleChanged() { } void PersonalDataManager::SyncStarted(syncer::ModelType model_type) { - if (model_type == syncer::AUTOFILL_PROFILE && - is_autofill_profile_cleanup_pending_) { - // This runs as a one-time fix, tracked in syncable prefs. If it has already - // run, it is a NOP (other than checking the pref). - ApplyProfileUseDatesFix(); + // Run deferred autofill address profile startup code. + // See: OnSyncServiceInitialized + if (model_type == syncer::AUTOFILL_PROFILE) { + ApplyProfileUseDatesFix(); // One-time fix, otherwise NOP. + ApplyDedupingRoutine(); // Once per major version, otherwise NOP. + DeleteDisusedAddresses(); // Once per major version, otherwise NOP. + CreateTestAddresses(); // Once per user profile startup. + } - // This runs at most once per major version, tracked in syncable prefs. If - // it has already run for this version, it's a NOP, other than checking the - // pref. - ApplyDedupingRoutine(); + // Run deferred credit card startup code. + // See: OnSyncServiceInitialized + if (model_type == syncer::AUTOFILL_WALLET_DATA) { + DeleteDisusedCreditCards(); // Once per major version, otherwise NOP. + CreateTestCreditCards(); // Once per user profile startup. } } @@ -447,6 +575,7 @@ void PersonalDataManager::RemoveObserver( bool PersonalDataManager::ImportFormData( const FormStructure& form, + bool credit_card_enabled, bool should_return_local_card, std::unique_ptr<CreditCard>* imported_credit_card, bool* imported_credit_card_matches_masked_server_credit_card) { @@ -455,9 +584,12 @@ bool PersonalDataManager::ImportFormData( // |imported_credit_card| with an extracted card. See .h for details of // |should_return_local_card| and // |imported_credit_card_matches_masked_server_credit_card|. - bool cc_import = - ImportCreditCard(form, should_return_local_card, imported_credit_card, - imported_credit_card_matches_masked_server_credit_card); + bool cc_import = false; + if (credit_card_enabled) { + cc_import = ImportCreditCard( + form, should_return_local_card, imported_credit_card, + imported_credit_card_matches_masked_server_credit_card); + } // - ImportAddressProfiles may eventually save or update one or more address // profiles. bool address_import = ImportAddressProfiles(form); @@ -662,8 +794,7 @@ void PersonalDataManager::UpdateServerCreditCard( DCHECK_NE(existing_credit_card->record_type(), credit_card.record_type()); DCHECK_EQ(existing_credit_card->Label(), credit_card.Label()); if (existing_credit_card->record_type() == CreditCard::MASKED_SERVER_CARD) { - database_->UnmaskServerCreditCard(credit_card, - credit_card.number()); + database_->UnmaskServerCreditCard(credit_card, credit_card.number()); } else { database_->MaskServerCreditCard(credit_card.server_id()); } @@ -726,13 +857,31 @@ void PersonalDataManager::AddServerCreditCardForTest( server_credit_cards_.push_back(std::move(credit_card)); } +void PersonalDataManager:: + RemoveAutofillProfileByGUIDAndBlankCreditCardReferecne( + const std::string& guid) { + database_->RemoveAutofillProfile(guid); + + // Reset the billing_address_id of any card that refered to this profile. + for (CreditCard* credit_card : GetCreditCards()) { + if (credit_card->billing_address_id() == guid) { + credit_card->set_billing_address_id(""); + + if (credit_card->record_type() == CreditCard::LOCAL_CARD) + database_->UpdateCreditCard(*credit_card); + else + database_->UpdateServerCardMetadata(*credit_card); + } + } +} + void PersonalDataManager::RemoveByGUID(const std::string& guid) { if (is_off_the_record_) return; bool is_credit_card = FindByGUID<CreditCard>(local_credit_cards_, guid); - bool is_profile = !is_credit_card && - FindByGUID<AutofillProfile>(web_profiles_, guid); + bool is_profile = + !is_credit_card && FindByGUID<AutofillProfile>(web_profiles_, guid); if (!is_credit_card && !is_profile) return; @@ -742,19 +891,7 @@ void PersonalDataManager::RemoveByGUID(const std::string& guid) { if (is_credit_card) { database_->RemoveCreditCard(guid); } else { - database_->RemoveAutofillProfile(guid); - - // Reset the billing_address_id of any card that refered to this profile. - for (CreditCard* credit_card : GetCreditCards()) { - if (credit_card->billing_address_id() == guid) { - credit_card->set_billing_address_id(""); - - if (credit_card->record_type() == CreditCard::LOCAL_CARD) - database_->UpdateCreditCard(*credit_card); - else - database_->UpdateServerCardMetadata(*credit_card); - } - } + RemoveAutofillProfileByGUIDAndBlankCreditCardReferecne(guid); } // Refresh our local cache and send notifications to observers. @@ -792,12 +929,9 @@ bool PersonalDataManager::IsDataLoaded() const { return is_data_loaded_; } -const std::vector<AutofillProfile*>& PersonalDataManager::GetProfiles() const { - return GetProfiles(false); -} - -std::vector<AutofillProfile*> PersonalDataManager::web_profiles() const { +std::vector<AutofillProfile*> PersonalDataManager::GetProfiles() const { std::vector<AutofillProfile*> result; + result.reserve(web_profiles_.size()); for (const auto& profile : web_profiles_) result.push_back(profile.get()); return result; @@ -805,6 +939,7 @@ std::vector<AutofillProfile*> PersonalDataManager::web_profiles() const { std::vector<AutofillProfile*> PersonalDataManager::GetServerProfiles() const { std::vector<AutofillProfile*> result; + result.reserve(server_profiles_.size()); for (const auto& profile : server_profiles_) result.push_back(profile.get()); return result; @@ -812,20 +947,24 @@ std::vector<AutofillProfile*> PersonalDataManager::GetServerProfiles() const { std::vector<CreditCard*> PersonalDataManager::GetLocalCreditCards() const { std::vector<CreditCard*> result; + result.reserve(local_credit_cards_.size()); for (const auto& card : local_credit_cards_) result.push_back(card.get()); return result; } -const std::vector<CreditCard*>& PersonalDataManager::GetCreditCards() const { - credit_cards_.clear(); - for (const auto& card : local_credit_cards_) - credit_cards_.push_back(card.get()); - if (pref_service_->GetBoolean(prefs::kAutofillWalletImportEnabled)) { - for (const auto& card : server_credit_cards_) - credit_cards_.push_back(card.get()); +std::vector<CreditCard*> PersonalDataManager::GetCreditCards() const { + std::vector<CreditCard*> result; + result.reserve(local_credit_cards_.size() + server_credit_cards_.size()); + if (pref_service_->GetBoolean(prefs::kAutofillCreditCardEnabled)) { + for (const auto& card : local_credit_cards_) + result.push_back(card.get()); + if (pref_service_->GetBoolean(prefs::kAutofillWalletImportEnabled)) { + for (const auto& card : server_credit_cards_) + result.push_back(card.get()); + } } - return credit_cards_; + return result; } void PersonalDataManager::Refresh() { @@ -835,7 +974,7 @@ void PersonalDataManager::Refresh() { std::vector<AutofillProfile*> PersonalDataManager::GetProfilesToSuggest() const { - std::vector<AutofillProfile*> profiles = GetProfiles(true); + std::vector<AutofillProfile*> profiles = GetProfiles(); // Rank the suggestions by frecency (see AutofillDataModel for details). const base::Time comparison_time = AutofillClock::Now(); @@ -1004,14 +1143,43 @@ const std::vector<CreditCard*> PersonalDataManager::GetCreditCardsToSuggest() return cards_to_suggest; } +// static +void PersonalDataManager::RemoveExpiredCreditCardsNotUsedSinceTimestamp( + base::Time comparison_time, + base::Time min_last_used, + std::vector<CreditCard*>* cards) { + const size_t original_size = cards->size(); + // Split the vector into [unexpired-or-expired-but-after-timestamp, + // expired-and-before-timestamp], then delete the latter. + cards->erase(std::stable_partition( + cards->begin(), cards->end(), + [comparison_time, min_last_used](const CreditCard* c) { + return !c->IsExpired(comparison_time) || + c->use_date() > min_last_used; + }), + cards->end()); + const size_t num_cards_supressed = original_size - cards->size(); + AutofillMetrics::LogNumberOfCreditCardsSuppressedForDisuse( + num_cards_supressed); +} + std::vector<Suggestion> PersonalDataManager::GetCreditCardSuggestions( const AutofillType& type, const base::string16& field_contents) { if (IsInAutofillSuggestionsDisabledExperiment()) return std::vector<Suggestion>(); + std::vector<CreditCard*> cards = GetCreditCardsToSuggest(); + // If enabled, suppress disused address profiles when triggered from an empty + // field. + if (field_contents.empty() && + base::FeatureList::IsEnabled(kAutofillSuppressDisusedCreditCards)) { + const base::Time min_last_used = + AutofillClock::Now() - kDisusedCreditCardTimeDelta; + RemoveExpiredCreditCardsNotUsedSinceTimestamp(AutofillClock::Now(), + min_last_used, &cards); + } - return GetSuggestionsForCards(type, field_contents, - GetCreditCardsToSuggest()); + return GetSuggestionsForCards(type, field_contents, cards); } bool PersonalDataManager::IsAutofillEnabled() const { @@ -1025,14 +1193,18 @@ std::string PersonalDataManager::CountryCodeForCurrentTimezone() const { void PersonalDataManager::SetPrefService(PrefService* pref_service) { enabled_pref_.reset(new BooleanPrefMember); wallet_enabled_pref_.reset(new BooleanPrefMember); + credit_card_enabled_pref_.reset(new BooleanPrefMember); pref_service_ = pref_service; // |pref_service_| can be nullptr in tests. if (pref_service_) { + credit_card_enabled_pref_->Init( + prefs::kAutofillCreditCardEnabled, pref_service_, + base::Bind(&PersonalDataManager::Refresh, base::Unretained(this))); enabled_pref_->Init(prefs::kAutofillEnabled, pref_service_, - base::Bind(&PersonalDataManager::EnabledPrefChanged, - base::Unretained(this))); - wallet_enabled_pref_->Init(prefs::kAutofillWalletImportEnabled, - pref_service_, + base::Bind(&PersonalDataManager::EnabledPrefChanged, + base::Unretained(this))); + wallet_enabled_pref_->Init( + prefs::kAutofillWalletImportEnabled, pref_service_, base::Bind(&PersonalDataManager::EnabledPrefChanged, base::Unretained(this))); } @@ -1125,15 +1297,15 @@ std::string PersonalDataManager::MergeProfile( return guid; } -bool PersonalDataManager::IsCountryOfInterest(const std::string& country_code) - const { +bool PersonalDataManager::IsCountryOfInterest( + const std::string& country_code) const { DCHECK_EQ(2U, country_code.size()); - const std::vector<AutofillProfile*>& profiles = web_profiles(); + const std::vector<AutofillProfile*>& profiles = GetProfiles(); std::list<std::string> country_codes; for (size_t i = 0; i < profiles.size(); ++i) { - country_codes.push_back(base::ToLowerASCII(base::UTF16ToASCII( - profiles[i]->GetRawInfo(ADDRESS_HOME_COUNTRY)))); + country_codes.push_back(base::ToLowerASCII( + base::UTF16ToASCII(profiles[i]->GetRawInfo(ADDRESS_HOME_COUNTRY)))); } std::string timezone_country = CountryCodeForCurrentTimezone(); @@ -1394,26 +1566,13 @@ void PersonalDataManager::LogStoredProfileMetrics() const { } } -void PersonalDataManager::LogLocalCreditCardCount() const { - if (!has_logged_local_credit_card_count_) { - AutofillMetrics::LogStoredLocalCreditCardCount(local_credit_cards_.size()); - has_logged_local_credit_card_count_ = true; - } -} +void PersonalDataManager::LogStoredCreditCardMetrics() const { + if (!has_logged_stored_credit_card_metrics_) { + AutofillMetrics::LogStoredCreditCardMetrics( + local_credit_cards_, server_credit_cards_, kDisusedProfileTimeDelta); -void PersonalDataManager::LogServerCreditCardCounts() const { - if (!has_logged_server_credit_card_counts_) { - size_t unmasked_cards = 0, masked_cards = 0; - for (const auto& card : server_credit_cards_) { - if (card->record_type() == CreditCard::MASKED_SERVER_CARD) { - masked_cards++; - } else if (card->record_type() == CreditCard::FULL_SERVER_CARD) { - unmasked_cards++; - } - } - AutofillMetrics::LogStoredServerCreditCardCounts(masked_cards, - unmasked_cards); - has_logged_server_credit_card_counts_ = true; + // Only log this info once per chrome user profile load. + has_logged_stored_credit_card_metrics_ = true; } } @@ -1425,12 +1584,12 @@ std::string PersonalDataManager::MostCommonCountryCodeFromProfiles() const { std::map<std::string, int> votes; // TODO(estade): can we make this GetProfiles() instead? It seems to cause // errors in tests on mac trybots. See http://crbug.com/57221 - const std::vector<AutofillProfile*>& profiles = web_profiles(); + const std::vector<AutofillProfile*>& profiles = GetProfiles(); const std::vector<std::string>& country_codes = CountryDataMap::GetInstance()->country_codes(); for (size_t i = 0; i < profiles.size(); ++i) { - std::string country_code = base::ToUpperASCII(base::UTF16ToASCII( - profiles[i]->GetRawInfo(ADDRESS_HOME_COUNTRY))); + std::string country_code = base::ToUpperASCII( + base::UTF16ToASCII(profiles[i]->GetRawInfo(ADDRESS_HOME_COUNTRY))); if (base::ContainsValue(country_codes, country_code)) { // Verified profiles count 100x more than unverified ones. @@ -1569,16 +1728,17 @@ bool PersonalDataManager::ImportAddressProfileForSection( return true; } -bool PersonalDataManager::ImportCreditCard( +CreditCard PersonalDataManager::ExtractCreditCardFromForm( + const FormStructure& form) { + bool has_duplicate_field_type; + return ExtractCreditCardFromForm(form, &has_duplicate_field_type); +} + +CreditCard PersonalDataManager::ExtractCreditCardFromForm( const FormStructure& form, - bool should_return_local_card, - std::unique_ptr<CreditCard>* imported_credit_card, - bool* imported_credit_card_matches_masked_server_credit_card) { - DCHECK(!imported_credit_card->get()); - *imported_credit_card_matches_masked_server_credit_card = false; + bool* has_duplicate_field_type) { + *has_duplicate_field_type = false; - // The candidate for credit card import. There are many ways for the candidate - // to be rejected (see everywhere this function returns false, below). CreditCard candidate_credit_card; candidate_credit_card.set_origin(form.source_url().spec()); @@ -1599,12 +1759,13 @@ bool PersonalDataManager::ImportCreditCard( continue; // If we've seen the same credit card field type twice in the same form, - // abort credit card import/update. + // set |has_duplicate_field_type| to true. ServerFieldType server_field_type = field_type.GetStorableType(); - if (types_seen.count(server_field_type)) - return false; - types_seen.insert(server_field_type); - + if (types_seen.count(server_field_type)) { + *has_duplicate_field_type = true; + } else { + types_seen.insert(server_field_type); + } // If |field| is an HTML5 month input, handle it as a special case. if (base::LowerCaseEqualsASCII(field->form_control_type, "month")) { DCHECK_EQ(CREDIT_CARD_EXP_DATE_4_DIGIT_YEAR, server_field_type); @@ -1629,6 +1790,28 @@ bool PersonalDataManager::ImportCreditCard( } } + return candidate_credit_card; +} + +bool PersonalDataManager::ImportCreditCard( + const FormStructure& form, + bool should_return_local_card, + std::unique_ptr<CreditCard>* imported_credit_card, + bool* imported_credit_card_matches_masked_server_credit_card) { + DCHECK(!imported_credit_card->get()); + *imported_credit_card_matches_masked_server_credit_card = false; + + // The candidate for credit card import. There are many ways for the candidate + // to be rejected (see everywhere this function returns false, below). + bool has_duplicate_field_type; + CreditCard candidate_credit_card = + ExtractCreditCardFromForm(form, &has_duplicate_field_type); + + // If we've seen the same credit card field type twice in the same form, + // abort credit card import/update. + if (has_duplicate_field_type) + return false; + // Reject the credit card if we did not detect enough filled credit card // fields (such as valid number, month, year). if (!candidate_credit_card.IsValid()) @@ -1644,8 +1827,7 @@ bool PersonalDataManager::ImportCreditCard( // Make a local copy so that the data in |local_credit_cards_| isn't // modified directly by the UpdateFromImportedCard() call. CreditCard card_copy(*card); - if (card_copy.UpdateFromImportedCard(candidate_credit_card, - app_locale_)) { + if (card_copy.UpdateFromImportedCard(candidate_credit_card, app_locale_)) { UpdateCreditCard(card_copy); // If we should not return the local card, return that we merged it, // without setting |imported_credit_card|. @@ -1699,12 +1881,30 @@ bool PersonalDataManager::ImportCreditCard( return true; } -const std::vector<AutofillProfile*>& PersonalDataManager::GetProfiles( - bool record_metrics) const { - profiles_.clear(); - for (const auto& profile : web_profiles_) - profiles_.push_back(profile.get()); - return profiles_; +bool PersonalDataManager::IsKnownCard(const CreditCard& credit_card) { + const auto stripped_pan = CreditCard::StripSeparators(credit_card.number()); + for (const auto& card : local_credit_cards_) { + if (stripped_pan == CreditCard::StripSeparators(card->number())) + return true; + } + + const auto masked_info = credit_card.NetworkAndLastFourDigits(); + for (const auto& card : server_credit_cards_) { + switch (card->record_type()) { + case CreditCard::FULL_SERVER_CARD: + if (stripped_pan == CreditCard::StripSeparators(card->number())) + return true; + break; + case CreditCard::MASKED_SERVER_CARD: + if (masked_info == card->NetworkAndLastFourDigits()) + return true; + break; + default: + NOTREACHED(); + } + } + + return false; } std::vector<Suggestion> PersonalDataManager::GetSuggestionsForCards( @@ -1794,7 +1994,7 @@ void PersonalDataManager::ApplyProfileUseDatesFix() { std::vector<AutofillProfile> profiles; bool has_changed_data = false; - for (AutofillProfile* profile : web_profiles()) { + for (AutofillProfile* profile : GetProfiles()) { if (profile->use_date() == base::Time()) { profile->set_use_date(AutofillClock::Now() - base::TimeDelta::FromDays(14)); @@ -2155,4 +2355,155 @@ std::string PersonalDataManager::MergeServerAddressesIntoProfiles( return guid; } +void PersonalDataManager::CreateTestAddresses() { + if (has_created_test_addresses_) + return; + + has_created_test_addresses_ = true; + if (!base::FeatureList::IsEnabled(kAutofillCreateDataForTest)) + return; + + AddProfile(CreateBasicTestAddress(app_locale_)); + AddProfile(CreateDisusedTestAddress(app_locale_)); + AddProfile(CreateDisusedDeletableTestAddress(app_locale_)); +} + +void PersonalDataManager::CreateTestCreditCards() { + if (has_created_test_credit_cards_) + return; + + has_created_test_credit_cards_ = true; + if (!base::FeatureList::IsEnabled(kAutofillCreateDataForTest)) + return; + + AddCreditCard(CreateBasicTestCreditCard(app_locale_)); + AddCreditCard(CreateDisusedTestCreditCard(app_locale_)); + AddCreditCard(CreateDisusedDeletableTestCreditCard(app_locale_)); +} + +bool PersonalDataManager::IsCreditCardDeletable(CreditCard* card) { + const base::Time deletion_threshold = + AutofillClock::Now() - kDisusedCreditCardDeletionTimeDelta; + + return card->use_date() < deletion_threshold && + card->IsExpired(deletion_threshold); +} + +bool PersonalDataManager::DeleteDisusedCreditCards() { + if (!base::FeatureList::IsEnabled(kAutofillDeleteDisusedCreditCards)) { + return false; + } + + // Check if credit cards deletion has already been performed this major + // version. + int current_major_version = atoi(version_info::GetVersionNumber().c_str()); + if (pref_service_->GetInteger( + prefs::kAutofillLastVersionDisusedCreditCardsDeleted) >= + current_major_version) { + DVLOG(1) + << "Autofill credit cards deletion already performed for this version"; + return false; + } + + // Set the pref to the current major version. + pref_service_->SetInteger( + prefs::kAutofillLastVersionDisusedCreditCardsDeleted, + current_major_version); + + // Only delete local cards, as server cards are managed by Payments. + auto cards = GetLocalCreditCards(); + + // Early exit when there is no local cards. + if (cards.empty()) { + return true; + } + + std::vector<std::string> guid_to_delete; + for (CreditCard* card : cards) { + if (IsCreditCardDeletable(card)) { + guid_to_delete.push_back(card->guid()); + } + } + + size_t num_deleted_cards = guid_to_delete.size(); + + for (auto const guid : guid_to_delete) { + database_->RemoveCreditCard(guid); + } + + if (num_deleted_cards > 0) { + Refresh(); + } + + AutofillMetrics::LogNumberOfCreditCardsDeletedForDisuse(num_deleted_cards); + + return true; +} + +bool PersonalDataManager::IsAddressDeletable( + AutofillProfile* profile, + std::unordered_set<std::string> const& used_billing_address_guids) { + const base::Time deletion_threshold = + AutofillClock::Now() - kDisusedAddressDeletionTimeDelta; + + return profile->use_date() < deletion_threshold && !profile->IsVerified() && + used_billing_address_guids.find(profile->guid()) == + used_billing_address_guids.end(); +} + +bool PersonalDataManager::DeleteDisusedAddresses() { + if (!base::FeatureList::IsEnabled(kAutofillDeleteDisusedAddresses)) { + return false; + } + + // Check if address deletion has already been performed this major version. + int current_major_version = atoi(version_info::GetVersionNumber().c_str()); + if (pref_service_->GetInteger( + prefs::kAutofillLastVersionDisusedAddressesDeleted) >= + current_major_version) { + DVLOG(1) + << "Autofill addresses deletion already performed for this version"; + return false; + } + + // Set the pref to the current major version. + pref_service_->SetInteger(prefs::kAutofillLastVersionDisusedAddressesDeleted, + current_major_version); + + const std::vector<AutofillProfile*>& profiles = GetProfiles(); + + // Early exit when there are no profiles. + if (profiles.empty()) { + return true; + } + + std::unordered_set<std::string> used_billing_address_guids; + for (CreditCard* card : GetCreditCards()) { + if (!IsCreditCardDeletable(card)) { + used_billing_address_guids.insert(card->billing_address_id()); + } + } + + std::vector<std::string> guids_to_delete; + for (AutofillProfile* profile : profiles) { + if (IsAddressDeletable(profile, used_billing_address_guids)) { + guids_to_delete.push_back(profile->guid()); + } + } + + size_t num_deleted_addresses = guids_to_delete.size(); + + for (auto const guid : guids_to_delete) { + RemoveAutofillProfileByGUIDAndBlankCreditCardReferecne(guid); + } + + if (num_deleted_addresses > 0) { + Refresh(); + } + + AutofillMetrics::LogNumberOfAddressesDeletedForDisuse(num_deleted_addresses); + + return true; +} + } // namespace autofill diff --git a/chromium/components/autofill/core/browser/personal_data_manager.h b/chromium/components/autofill/core/browser/personal_data_manager.h index a28c4f24a2f..a259c802d42 100644 --- a/chromium/components/autofill/core/browser/personal_data_manager.h +++ b/chromium/components/autofill/core/browser/personal_data_manager.h @@ -25,6 +25,7 @@ #include "components/autofill/core/browser/webdata/autofill_webdata_service.h" #include "components/autofill/core/browser/webdata/autofill_webdata_service_observer.h" #include "components/keyed_service/core/keyed_service.h" +#include "components/prefs/pref_change_registrar.h" #include "components/prefs/pref_member.h" #include "components/webdata/common/web_data_service_consumer.h" #include "net/url_request/url_request_context_getter.h" @@ -99,18 +100,19 @@ class PersonalDataManager : public KeyedService, // Scans the given |form| for importable Autofill data. If the form includes // sufficient address data for a new profile, it is immediately imported. If - // the form includes sufficient credit card data for a new credit card, it is + // the form includes sufficient credit card data for a new credit card and + // |credit_card_enabled| is set to |true|, it is stored into + // |imported_credit_card| so that we can prompt the user whether to save this + // data. If the form contains credit card data already present in a local + // credit card entry *and* |should_return_local_card| is true, the data is // stored into |imported_credit_card| so that we can prompt the user whether - // to save this data. If the form contains credit card data already present in - // a local credit card entry *and* |should_return_local_card| is true, the - // data is stored into |imported_credit_card| so that we can prompt the user - // whether to upload it. - // |imported_credit_card_matches_masked_server_credit_card| is set to |true| - // if the |TypeAndLastFourDigits| in |imported_credit_card| matches the - // |TypeAndLastFourDigits| in a saved masked server card. Returns |true| if - // sufficient address or credit card data was found. + // to upload it. |imported_credit_card_matches_masked_server_credit_card| is + // set to |true| if the |TypeAndLastFourDigits| in |imported_credit_card| + // matches the |TypeAndLastFourDigits| in a saved masked server card. Returns + // |true| if sufficient address or credit card data was found. bool ImportFormData( const FormStructure& form, + bool credit_card_enabled, bool should_return_local_card, std::unique_ptr<CreditCard>* imported_credit_card, bool* imported_credit_card_matches_masked_server_credit_card); @@ -200,16 +202,13 @@ class PersonalDataManager : public KeyedService, // This PersonalDataManager owns these profiles and credit cards. Their // lifetime is until the web database is updated with new profile and credit // card information, respectively. - // TODO(crbug.com/687352): Remove one of these since they do the same thing. - // |GetProfiles()| and |web_profiles()| returns only local profiles. - virtual const std::vector<AutofillProfile*>& GetProfiles() const; - virtual std::vector<AutofillProfile*> web_profiles() const; + virtual std::vector<AutofillProfile*> GetProfiles() const; // Returns just SERVER_PROFILES. virtual std::vector<AutofillProfile*> GetServerProfiles() const; // Returns just LOCAL_CARD cards. virtual std::vector<CreditCard*> GetLocalCreditCards() const; // Returns all credit cards, server and local. - virtual const std::vector<CreditCard*>& GetCreditCards() const; + virtual std::vector<CreditCard*> GetCreditCards() const; // Returns the profiles to suggest to the user, ordered by frecency. std::vector<AutofillProfile*> GetProfilesToSuggest() const; @@ -230,11 +229,23 @@ class PersonalDataManager : public KeyedService, bool field_is_autofilled, const std::vector<ServerFieldType>& other_field_types); + // Tries to delete disused addresses once per major version if the + // feature is enabled. + bool DeleteDisusedAddresses(); + // Returns the credit cards to suggest to the user. Those have been deduped // and ordered by frecency with the expired cards put at the end of the // vector. const std::vector<CreditCard*> GetCreditCardsToSuggest() const; + // Remove credit cards that are expired at |comparison_time| and not used + // since |min_last_used| from |cards|. The relative ordering of |cards| is + // maintained. + static void RemoveExpiredCreditCardsNotUsedSinceTimestamp( + base::Time comparison_time, + base::Time min_last_used, + std::vector<CreditCard*>* cards); + // Gets credit cards that can suggest data for |type|. See // GetProfileSuggestions for argument descriptions. The variant in each // GUID pair should be ignored. @@ -242,6 +253,10 @@ class PersonalDataManager : public KeyedService, const AutofillType& type, const base::string16& field_contents); + // Tries to delete disused credit cards once per major version if the + // feature is enabled. + bool DeleteDisusedCreditCards(); + // Re-loads profiles and credit cards from the WebDatabase asynchronously. // In the general case, this is a no-op and will re-create the same // in-memory model as existed prior to the call. If any change occurred to @@ -286,9 +301,7 @@ class PersonalDataManager : public KeyedService, std::list<CreditCard*>* cards_to_suggest); // Notifies test observers that personal data has changed. - void NotifyPersonalDataChangedForTest() { - NotifyPersonalDataChanged(); - } + void NotifyPersonalDataChangedForTest() { NotifyPersonalDataChanged(); } // Sets the URL request context getter to be used when normalizing addresses // with libaddressinput's address validator. @@ -302,6 +315,16 @@ class PersonalDataManager : public KeyedService, return context_getter_.get(); } + // Extract credit card from the form structure. This function allows for + // duplicated field types in the form. + CreditCard ExtractCreditCardFromForm(const FormStructure& form); + + // This function assumes |credit_card| contains the full PAN. Returns |true| + // if the card number of |credit_card| is equal to any local card or any + // unmasked server card known by the browser, or |TypeAndLastFourDigits| of + // |credit_card| is equal to any masked server card known by the browser. + bool IsKnownCard(const CreditCard& credit_card); + protected: // Only PersonalDataManagerFactory and certain tests can create instances of // PersonalDataManager. @@ -351,6 +374,16 @@ class PersonalDataManager : public KeyedService, FRIEND_TEST_ALL_PREFIXES( PersonalDataManagerTest, ConvertWalletAddressesAndUpdateWalletCards_MultipleSimilarWalletAddresses); // NOLINT + FRIEND_TEST_ALL_PREFIXES(PersonalDataManagerTest, + DeleteDisusedCreditCards_OncePerVersion); + FRIEND_TEST_ALL_PREFIXES(PersonalDataManagerTest, + DeleteDisusedCreditCards_DoNothingWhenDisabled); + FRIEND_TEST_ALL_PREFIXES( + PersonalDataManagerTest, + DeleteDisusedCreditCards_OnlyDeleteExpiredDisusedLocalCards); + FRIEND_TEST_ALL_PREFIXES(PersonalDataManagerTest, + GetCreditCardSuggestions_CreditCardAutofillDisabled); + friend class autofill::AutofillInteractiveTest; friend class autofill::AutofillTest; friend class autofill::PersonalDataManagerFactory; @@ -361,11 +394,13 @@ class PersonalDataManager : public KeyedService, friend class ::RemoveAutofillTester; friend std::default_delete<PersonalDataManager>; friend void autofill_helper::SetProfiles( - int, std::vector<autofill::AutofillProfile>*); + int, + std::vector<autofill::AutofillProfile>*); friend void autofill_helper::SetCreditCards( - int, std::vector<autofill::CreditCard>*); - friend void SetTestProfiles( - Browser* browser, std::vector<AutofillProfile>* profiles); + int, + std::vector<autofill::CreditCard>*); + friend void SetTestProfiles(Browser* browser, + std::vector<AutofillProfile>* profiles); // Sets |web_profiles_| to the contents of |profiles| and updates the web // database by adding, updating and removing profiles. @@ -396,18 +431,13 @@ class PersonalDataManager : public KeyedService, // Notifies observers that personal data has changed. void NotifyPersonalDataChanged(); - // The first time this is called, logs a UMA metrics about the user's profile. - // On subsequent calls, does nothing. + // The first time this is called, logs a UMA metrics about the user's autofill + // addresses. On subsequent calls, does nothing. void LogStoredProfileMetrics() const; - // The first time this is called, logs an UMA metric for the number of local - // credit cards the user has. On subsequent calls, does nothing. - void LogLocalCreditCardCount() const; - - // The first time this is called, logs an UMA metric for the number of server - // credit cards the user has (both masked and unmasked). On subsequent calls, - // does nothing. - void LogServerCreditCardCounts() const; + // The first time this is called, logs an UMA metric about the user's autofill + // credit cardss. On subsequent calls, does nothing. + void LogStoredCreditCardMetrics() const; // Returns the value of the AutofillEnabled pref. virtual bool IsAutofillEnabled() const; @@ -452,10 +482,6 @@ class PersonalDataManager : public KeyedService, std::vector<std::unique_ptr<CreditCard>> local_credit_cards_; std::vector<std::unique_ptr<CreditCard>> server_credit_cards_; - // A combination of local and server credit cards. The pointers are owned - // by the local/server_credit_cards_ vectors. - mutable std::vector<CreditCard*> credit_cards_; - // When the manager makes a request from WebDataServiceBase, the database // is queried on another sequence, we record the query handle until we // get called back. We store handles for both profile and credit card queries @@ -501,11 +527,10 @@ class PersonalDataManager : public KeyedService, std::unique_ptr<CreditCard>* imported_credit_card, bool* imported_credit_card_matches_masked_server_credit_card); - // Functionally equivalent to GetProfiles(), but also records metrics if - // |record_metrics| is true. Metrics should be recorded when the returned - // profiles will be used to populate the fields shown in an Autofill popup. - virtual const std::vector<AutofillProfile*>& GetProfiles( - bool record_metrics) const; + // Extracts credit card from the form structure. |hasDuplicateFieldType| will + // be set as true if there are duplicated field types in the form. + CreditCard ExtractCreditCardFromForm(const FormStructure& form, + bool* hasDuplicateFieldType); // Returns credit card suggestions based on the |cards_to_suggest| and the // |type| and |field_contents| of the credit card field. @@ -514,6 +539,10 @@ class PersonalDataManager : public KeyedService, const base::string16& field_contents, const std::vector<CreditCard*>& cards_to_suggest) const; + // Returns true if the given credit card can be deleted in a major version + // upgrade. The card will need to be local and disused, to be deletable. + bool IsCreditCardDeletable(CreditCard* card); + // Runs the Autofill use date fix routine if it's never been done. Returns // whether the routine was run. void ApplyProfileUseDatesFix(); @@ -579,6 +608,30 @@ class PersonalDataManager : public KeyedService, const AutofillProfile& server_address, std::vector<AutofillProfile>* existing_profiles); + // Removes profile from web database according to |guid| and resets credit + // card's billing address if that address is used by any credit cards. + // The method does not refresh, this allows multiple removal with one + // refreshing in the end. + void RemoveAutofillProfileByGUIDAndBlankCreditCardReferecne( + const std::string& guid); + + // Returns true if an address can be deleted in a major version upgrade. + // An address is deletable if it is unverified, and not used by a valid + // credit card as billing address, and not used for a long time(13 months). + bool IsAddressDeletable( + AutofillProfile* profile, + const std::unordered_set<std::string>& used_billing_address_guids); + + // If the AutofillCreateDataForTest feature is enabled, this helper creates + // autofill address data that would otherwise be difficult to create + // manually using the UI. + void CreateTestAddresses(); + + // If the AutofillCreateDataForTest feature is enabled, this helper creates + // autofill credit card data that would otherwise be difficult to create + // manually using the UI. + void CreateTestCreditCards(); + const std::string app_locale_; // The default country code for new addresses. @@ -601,13 +654,11 @@ class PersonalDataManager : public KeyedService, // Whether we have already logged the stored profile metrics this session. mutable bool has_logged_stored_profile_metrics_; - // Whether we have already logged the number of local credit cards this - // session. - mutable bool has_logged_local_credit_card_count_; + // Whether we have already logged the stored credit card metrics this session. + mutable bool has_logged_stored_credit_card_metrics_; - // Whether we have already logged the number of server credit cards this - // session. - mutable bool has_logged_server_credit_card_counts_; + // An observer to listen for changes to prefs::kAutofillCreditCardEnabled. + std::unique_ptr<BooleanPrefMember> credit_card_enabled_pref_; // An observer to listen for changes to prefs::kAutofillEnabled. std::unique_ptr<BooleanPrefMember> enabled_pref_; @@ -621,6 +672,10 @@ class PersonalDataManager : public KeyedService, // Whether new information was received from the sync server. bool has_synced_new_data_ = false; + // True if test data has been created this session. + bool has_created_test_addresses_ = false; + bool has_created_test_credit_cards_ = false; + // The context for the request to be used to fetch libaddressinput's address // validation rules. scoped_refptr<net::URLRequestContextGetter> context_getter_; 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 3974e1e5678..c3b2060d630 100644 --- a/chromium/components/autofill/core/browser/personal_data_manager_unittest.cc +++ b/chromium/components/autofill/core/browser/personal_data_manager_unittest.cc @@ -104,15 +104,14 @@ void ExpectSameElements(const std::vector<T*>& expectations, ASSERT_EQ(expectations.size(), results.size()); std::vector<T*> expectations_copy = expectations; - std::sort( - expectations_copy.begin(), expectations_copy.end(), CompareElements<T>); + std::sort(expectations_copy.begin(), expectations_copy.end(), + CompareElements<T>); std::vector<T*> results_copy = results; std::sort(results_copy.begin(), results_copy.end(), CompareElements<T>); - EXPECT_EQ(std::mismatch(results_copy.begin(), - results_copy.end(), - expectations_copy.begin(), - ElementsEqual<T>).first, + EXPECT_EQ(std::mismatch(results_copy.begin(), results_copy.end(), + expectations_copy.begin(), ElementsEqual<T>) + .first, results_copy.end()); } @@ -127,9 +126,7 @@ class PersonalDataManagerTestBase { personal_data_.reset(new PersonalDataManager("en")); personal_data_->Init( scoped_refptr<AutofillWebDataService>(autofill_database_service_), - prefs_.get(), - account_tracker_.get(), - signin_manager_.get(), + prefs_.get(), account_tracker_.get(), signin_manager_.get(), is_incognito); personal_data_->AddObserver(&personal_data_observer_); personal_data_->OnSyncServiceInitialized(nullptr); @@ -245,6 +242,35 @@ class PersonalDataManagerTestBase { ASSERT_EQ(3U, personal_data_->GetCreditCards().size()); } + // Helper method to create a local card that was expired 400 days ago, + // and has not been used in last 400 days. This card is supposed to be + // deleted during a major version upgrade. + void CreateDeletableExpiredAndDisusedCreditCard() { + CreditCard credit_card1(base::GenerateGUID(), "https://www.example.com"); + test::SetCreditCardInfo(&credit_card1, "Clyde Barrow", + "378282246310005" /* American Express */, "04", + "1999", "1"); + credit_card1.set_use_date(AutofillClock::Now() - + base::TimeDelta::FromDays(400)); + + personal_data_->AddCreditCard(credit_card1); + + WaitForOnPersonalDataChanged(); + EXPECT_EQ(1U, personal_data_->GetCreditCards().size()); + } + + // Helper method to create a profile that was last used 400 days ago. + // This profile is supposed to be deleted during a major version upgrade. + void CreateDeletableDisusedProfile() { + AutofillProfile profile0(test::GetFullProfile()); + profile0.set_use_date(AutofillClock::Now() - + base::TimeDelta::FromDays(400)); + personal_data_->AddProfile(profile0); + + WaitForOnPersonalDataChanged(); + EXPECT_EQ(1U, personal_data_->GetProfiles().size()); + } + // Helper methods that simply forward the call to the private member (to avoid // having to friend every test that needs to access the private // PersonalDataManager::ImportAddressProfile or ImportCreditCard). @@ -455,22 +481,19 @@ TEST_F(PersonalDataManagerTest, SaveImportedProfileSetModificationDate) { TEST_F(PersonalDataManagerTest, AddUpdateRemoveProfiles) { AutofillProfile profile0(base::GenerateGUID(), "https://www.example.com"); - test::SetProfileInfo(&profile0, - "Marion", "Mitchell", "Morrison", - "johnwayne@me.xyz", "Fox", "123 Zoo St.", "unit 5", "Hollywood", "CA", - "91601", "US", "12345678910"); + test::SetProfileInfo(&profile0, "Marion", "Mitchell", "Morrison", + "johnwayne@me.xyz", "Fox", "123 Zoo St.", "unit 5", + "Hollywood", "CA", "91601", "US", "12345678910"); AutofillProfile profile1(base::GenerateGUID(), "https://www.example.com"); - test::SetProfileInfo(&profile1, - "Josephine", "Alicia", "Saenz", - "joewayne@me.xyz", "Fox", "903 Apple Ct.", NULL, "Orlando", "FL", "32801", - "US", "19482937549"); + test::SetProfileInfo(&profile1, "Josephine", "Alicia", "Saenz", + "joewayne@me.xyz", "Fox", "903 Apple Ct.", NULL, + "Orlando", "FL", "32801", "US", "19482937549"); AutofillProfile profile2(base::GenerateGUID(), "https://www.example.com"); - test::SetProfileInfo(&profile2, - "Josephine", "Alicia", "Saenz", - "joewayne@me.xyz", "Fox", "1212 Center.", "Bld. 5", "Orlando", "FL", - "32801", "US", "19482937549"); + test::SetProfileInfo(&profile2, "Josephine", "Alicia", "Saenz", + "joewayne@me.xyz", "Fox", "1212 Center.", "Bld. 5", + "Orlando", "FL", "32801", "US", "19482937549"); // Add two test profiles to the database. personal_data_->AddProfile(profile0); @@ -621,10 +644,9 @@ TEST_F(PersonalDataManagerTest, AddCreditCard_BasicInformation) { TEST_F(PersonalDataManagerTest, UpdateUnverifiedProfilesAndCreditCards) { // Start with unverified data. AutofillProfile profile(base::GenerateGUID(), "https://www.example.com/"); - test::SetProfileInfo(&profile, - "Marion", "Mitchell", "Morrison", - "johnwayne@me.xyz", "Fox", "123 Zoo St.", "unit 5", "Hollywood", "CA", - "91601", "US", "12345678910"); + test::SetProfileInfo(&profile, "Marion", "Mitchell", "Morrison", + "johnwayne@me.xyz", "Fox", "123 Zoo St.", "unit 5", + "Hollywood", "CA", "91601", "US", "12345678910"); EXPECT_FALSE(profile.IsVerified()); CreditCard credit_card(base::GenerateGUID(), "https://www.example.com/"); @@ -692,8 +714,8 @@ TEST_F(PersonalDataManagerTest, UpdateUnverifiedProfilesAndCreditCards) { // Makes sure that full cards are re-masked when full PAN storage is off. TEST_F(PersonalDataManagerTest, RefuseToStoreFullCard) { - // On Linux this should be disabled automatically. Elsewhere, only if the - // flag is passed. +// On Linux this should be disabled automatically. Elsewhere, only if the +// flag is passed. #if defined(OS_LINUX) && !defined(OS_CHROMEOS) EXPECT_FALSE(base::CommandLine::ForCurrentProcess()->HasSwitch( switches::kDisableOfferStoreUnmaskedWalletCards)); @@ -844,16 +866,14 @@ TEST_F(PersonalDataManagerTest, SavesServerCardType) { TEST_F(PersonalDataManagerTest, AddProfilesAndCreditCards) { AutofillProfile profile0(base::GenerateGUID(), "https://www.example.com"); - test::SetProfileInfo(&profile0, - "Marion", "Mitchell", "Morrison", - "johnwayne@me.xyz", "Fox", "123 Zoo St.", "unit 5", "Hollywood", "CA", - "91601", "US", "12345678910"); + test::SetProfileInfo(&profile0, "Marion", "Mitchell", "Morrison", + "johnwayne@me.xyz", "Fox", "123 Zoo St.", "unit 5", + "Hollywood", "CA", "91601", "US", "12345678910"); AutofillProfile profile1(base::GenerateGUID(), "https://www.example.com"); - test::SetProfileInfo(&profile1, - "Josephine", "Alicia", "Saenz", - "joewayne@me.xyz", "Fox", "903 Apple Ct.", NULL, "Orlando", "FL", "32801", - "US", "19482937549"); + test::SetProfileInfo(&profile1, "Josephine", "Alicia", "Saenz", + "joewayne@me.xyz", "Fox", "903 Apple Ct.", NULL, + "Orlando", "FL", "32801", "US", "19482937549"); CreditCard credit_card0(base::GenerateGUID(), "https://www.example.com"); test::SetCreditCardInfo(&credit_card0, "John Dillinger", @@ -900,8 +920,8 @@ TEST_F(PersonalDataManagerTest, AddProfilesAndCreditCards) { // correctly on load. TEST_F(PersonalDataManagerTest, PopulateUniqueIDsOnLoad) { AutofillProfile profile0(base::GenerateGUID(), "https://www.example.com"); - test::SetProfileInfo(&profile0, - "y", "", "", "", "", "", "", "", "", "", "", ""); + test::SetProfileInfo(&profile0, "y", "", "", "", "", "", "", "", "", "", "", + ""); // Add the profile0 to the db. personal_data_->AddProfile(profile0); @@ -915,8 +935,8 @@ TEST_F(PersonalDataManagerTest, PopulateUniqueIDsOnLoad) { // Add a new profile. AutofillProfile profile1(base::GenerateGUID(), "https://www.example.com"); - test::SetProfileInfo(&profile1, - "z", "", "", "", "", "", "", "", "", "", "", ""); + test::SetProfileInfo(&profile1, "z", "", "", "", "", "", "", "", "", "", "", + ""); personal_data_->AddProfile(profile1); WaitForOnPersonalDataChanged(); @@ -968,8 +988,8 @@ TEST_F(PersonalDataManagerTest, SetUniqueCreditCardLabels) { TEST_F(PersonalDataManagerTest, SetEmptyProfile) { AutofillProfile profile0(base::GenerateGUID(), "https://www.example.com"); - test::SetProfileInfo(&profile0, - "", "", "", "", "", "", "", "", "", "", "", ""); + test::SetProfileInfo(&profile0, "", "", "", "", "", "", "", "", "", "", "", + ""); // Add the empty profile to the database. personal_data_->AddProfile(profile0); @@ -1005,16 +1025,14 @@ TEST_F(PersonalDataManagerTest, SetEmptyCreditCard) { TEST_F(PersonalDataManagerTest, Refresh) { AutofillProfile profile0(base::GenerateGUID(), "https://www.example.com"); - test::SetProfileInfo(&profile0, - "Marion", "Mitchell", "Morrison", - "johnwayne@me.xyz", "Fox", "123 Zoo St.", "unit 5", "Hollywood", "CA", - "91601", "US", "12345678910"); + test::SetProfileInfo(&profile0, "Marion", "Mitchell", "Morrison", + "johnwayne@me.xyz", "Fox", "123 Zoo St.", "unit 5", + "Hollywood", "CA", "91601", "US", "12345678910"); AutofillProfile profile1(base::GenerateGUID(), "https://www.example.com"); - test::SetProfileInfo(&profile1, - "Josephine", "Alicia", "Saenz", - "joewayne@me.xyz", "Fox", "903 Apple Ct.", NULL, "Orlando", "FL", "32801", - "US", "19482937549"); + test::SetProfileInfo(&profile1, "Josephine", "Alicia", "Saenz", + "joewayne@me.xyz", "Fox", "903 Apple Ct.", NULL, + "Orlando", "FL", "32801", "US", "19482937549"); // Add the test profiles to the database. personal_data_->AddProfile(profile0); @@ -1028,10 +1046,9 @@ TEST_F(PersonalDataManagerTest, Refresh) { ExpectSameElements(profiles, personal_data_->GetProfiles()); AutofillProfile profile2(base::GenerateGUID(), "https://www.example.com"); - test::SetProfileInfo(&profile2, - "Josephine", "Alicia", "Saenz", - "joewayne@me.xyz", "Fox", "1212 Center.", "Bld. 5", "Orlando", "FL", - "32801", "US", "19482937549"); + test::SetProfileInfo(&profile2, "Josephine", "Alicia", "Saenz", + "joewayne@me.xyz", "Fox", "1212 Center.", "Bld. 5", + "Orlando", "FL", "32801", "US", "19482937549"); autofill_database_service_->AddAutofillProfile(profile2); @@ -1071,17 +1088,17 @@ TEST_F(PersonalDataManagerTest, Refresh) { TEST_F(PersonalDataManagerTest, ImportAddressProfiles) { FormData form; FormFieldData field; - test::CreateTestFormField( - "First name:", "first_name", "George", "text", &field); + test::CreateTestFormField("First name:", "first_name", "George", "text", + &field); form.fields.push_back(field); - test::CreateTestFormField( - "Last name:", "last_name", "Washington", "text", &field); + test::CreateTestFormField("Last name:", "last_name", "Washington", "text", + &field); form.fields.push_back(field); - test::CreateTestFormField( - "Email:", "email", "theprez@gmail.com", "text", &field); + test::CreateTestFormField("Email:", "email", "theprez@gmail.com", "text", + &field); form.fields.push_back(field); - test::CreateTestFormField( - "Address:", "address1", "21 Laussat St", "text", &field); + test::CreateTestFormField("Address:", "address1", "21 Laussat St", "text", + &field); form.fields.push_back(field); test::CreateTestFormField("City:", "city", "San Francisco", "text", &field); form.fields.push_back(field); @@ -1096,9 +1113,9 @@ TEST_F(PersonalDataManagerTest, ImportAddressProfiles) { WaitForOnPersonalDataChanged(); AutofillProfile expected(base::GenerateGUID(), "https://www.example.com"); - test::SetProfileInfo(&expected, "George", NULL, - "Washington", "theprez@gmail.com", NULL, "21 Laussat St", NULL, - "San Francisco", "California", "94102", NULL, NULL); + test::SetProfileInfo(&expected, "George", NULL, "Washington", + "theprez@gmail.com", NULL, "21 Laussat St", NULL, + "San Francisco", "California", "94102", NULL, NULL); const std::vector<AutofillProfile*>& results = personal_data_->GetProfiles(); ASSERT_EQ(1U, results.size()); EXPECT_EQ(0, expected.Compare(*results[0])); @@ -1107,16 +1124,16 @@ TEST_F(PersonalDataManagerTest, ImportAddressProfiles) { TEST_F(PersonalDataManagerTest, ImportAddressProfiles_BadEmail) { FormData form; FormFieldData field; - test::CreateTestFormField( - "First name:", "first_name", "George", "text", &field); + test::CreateTestFormField("First name:", "first_name", "George", "text", + &field); form.fields.push_back(field); - test::CreateTestFormField( - "Last name:", "last_name", "Washington", "text", &field); + test::CreateTestFormField("Last name:", "last_name", "Washington", "text", + &field); form.fields.push_back(field); test::CreateTestFormField("Email:", "email", "bogus", "text", &field); form.fields.push_back(field); - test::CreateTestFormField( - "Address:", "address1", "21 Laussat St", "text", &field); + test::CreateTestFormField("Address:", "address1", "21 Laussat St", "text", + &field); form.fields.push_back(field); test::CreateTestFormField("City:", "city", "San Francisco", "text", &field); form.fields.push_back(field); @@ -1135,11 +1152,11 @@ TEST_F(PersonalDataManagerTest, ImportAddressProfiles_BadEmail) { TEST_F(PersonalDataManagerTest, ImportAddressProfiles_TwoEmails) { FormData form; FormFieldData field; - test::CreateTestFormField( - "Name:", "name", "George Washington", "text", &field); + test::CreateTestFormField("Name:", "name", "George Washington", "text", + &field); form.fields.push_back(field); - test::CreateTestFormField( - "Address:", "address1", "21 Laussat St", "text", &field); + test::CreateTestFormField("Address:", "address1", "21 Laussat St", "text", + &field); form.fields.push_back(field); test::CreateTestFormField("City:", "city", "San Francisco", "text", &field); form.fields.push_back(field); @@ -1147,11 +1164,11 @@ TEST_F(PersonalDataManagerTest, ImportAddressProfiles_TwoEmails) { form.fields.push_back(field); test::CreateTestFormField("Zip:", "zip", "94102", "text", &field); form.fields.push_back(field); - test::CreateTestFormField( - "Email:", "email", "example@example.com", "text", &field); + test::CreateTestFormField("Email:", "email", "example@example.com", "text", + &field); form.fields.push_back(field); - test::CreateTestFormField( - "Confirm email:", "confirm_email", "example@example.com", "text", &field); + test::CreateTestFormField("Confirm email:", "confirm_email", + "example@example.com", "text", &field); form.fields.push_back(field); FormStructure form_structure(form); form_structure.DetermineHeuristicTypes(nullptr /* ukm_service */); @@ -1166,11 +1183,11 @@ TEST_F(PersonalDataManagerTest, ImportAddressProfiles_TwoEmails) { TEST_F(PersonalDataManagerTest, ImportAddressProfiles_TwoDifferentEmails) { FormData form; FormFieldData field; - test::CreateTestFormField( - "Name:", "name", "George Washington", "text", &field); + test::CreateTestFormField("Name:", "name", "George Washington", "text", + &field); form.fields.push_back(field); - test::CreateTestFormField( - "Address:", "address1", "21 Laussat St", "text", &field); + test::CreateTestFormField("Address:", "address1", "21 Laussat St", "text", + &field); form.fields.push_back(field); test::CreateTestFormField("City:", "city", "San Francisco", "text", &field); form.fields.push_back(field); @@ -1178,11 +1195,11 @@ TEST_F(PersonalDataManagerTest, ImportAddressProfiles_TwoDifferentEmails) { form.fields.push_back(field); test::CreateTestFormField("Zip:", "zip", "94102", "text", &field); form.fields.push_back(field); - test::CreateTestFormField( - "Email:", "email", "example@example.com", "text", &field); + test::CreateTestFormField("Email:", "email", "example@example.com", "text", + &field); form.fields.push_back(field); - test::CreateTestFormField( - "Email:", "email2", "example2@example.com", "text", &field); + test::CreateTestFormField("Email:", "email2", "example2@example.com", "text", + &field); form.fields.push_back(field); FormStructure form_structure(form); form_structure.DetermineHeuristicTypes(nullptr /* ukm_service */); @@ -1195,14 +1212,14 @@ TEST_F(PersonalDataManagerTest, ImportAddressProfiles_TwoDifferentEmails) { TEST_F(PersonalDataManagerTest, ImportAddressProfiles_NotEnoughFilledFields) { FormData form; FormFieldData field; - test::CreateTestFormField( - "First name:", "first_name", "George", "text", &field); + test::CreateTestFormField("First name:", "first_name", "George", "text", + &field); form.fields.push_back(field); - test::CreateTestFormField( - "Last name:", "last_name", "Washington", "text", &field); + test::CreateTestFormField("Last name:", "last_name", "Washington", "text", + &field); form.fields.push_back(field); - test::CreateTestFormField( - "Card number:", "card_number", "4111 1111 1111 1111", "text", &field); + test::CreateTestFormField("Card number:", "card_number", + "4111 1111 1111 1111", "text", &field); form.fields.push_back(field); FormStructure form_structure(form); form_structure.DetermineHeuristicTypes(nullptr /* ukm_service */); @@ -1219,8 +1236,8 @@ TEST_F(PersonalDataManagerTest, ImportAddressProfiles_MinimumAddressUSA) { FormFieldData field; test::CreateTestFormField("Name:", "name", "Barack Obama", "text", &field); form.fields.push_back(field); - test::CreateTestFormField( - "Address:", "address", "1600 Pennsylvania Avenue", "text", &field); + test::CreateTestFormField("Address:", "address", "1600 Pennsylvania Avenue", + "text", &field); form.fields.push_back(field); test::CreateTestFormField("City:", "city", "Washington", "text", &field); form.fields.push_back(field); @@ -1246,16 +1263,16 @@ TEST_F(PersonalDataManagerTest, ImportAddressProfiles_MinimumAddressGB) { FormFieldData field; test::CreateTestFormField("Name:", "name", "David Cameron", "text", &field); form.fields.push_back(field); - test::CreateTestFormField( - "Address:", "address", "10 Downing Street", "text", &field); + test::CreateTestFormField("Address:", "address", "10 Downing Street", "text", + &field); form.fields.push_back(field); test::CreateTestFormField("City:", "city", "London", "text", &field); form.fields.push_back(field); - test::CreateTestFormField( - "Postcode:", "postcode", "SW1A 2AA", "text", &field); + test::CreateTestFormField("Postcode:", "postcode", "SW1A 2AA", "text", + &field); form.fields.push_back(field); - test::CreateTestFormField( - "Country:", "country", "United Kingdom", "text", &field); + test::CreateTestFormField("Country:", "country", "United Kingdom", "text", + &field); form.fields.push_back(field); FormStructure form_structure(form); form_structure.DetermineHeuristicTypes(nullptr /* ukm_service */); @@ -1271,11 +1288,11 @@ TEST_F(PersonalDataManagerTest, ImportAddressProfiles_MinimumAddressGI) { // There are no cities or provinces and no postal/zip code system. FormData form; FormFieldData field; - test::CreateTestFormField( - "Name:", "name", "Sir Adrian Johns", "text", &field); + test::CreateTestFormField("Name:", "name", "Sir Adrian Johns", "text", + &field); form.fields.push_back(field); - test::CreateTestFormField( - "Address:", "address", "The Convent, Main Street", "text", &field); + test::CreateTestFormField("Address:", "address", "The Convent, Main Street", + "text", &field); form.fields.push_back(field); test::CreateTestFormField("Country:", "country", "Gibraltar", "text", &field); form.fields.push_back(field); @@ -1292,26 +1309,26 @@ TEST_F(PersonalDataManagerTest, ImportAddressProfiles_PhoneNumberSplitAcrossMultipleFields) { FormData form; FormFieldData field; - test::CreateTestFormField( - "First name:", "first_name", "George", "text", &field); + test::CreateTestFormField("First name:", "first_name", "George", "text", + &field); form.fields.push_back(field); - test::CreateTestFormField( - "Last name:", "last_name", "Washington", "text", &field); + test::CreateTestFormField("Last name:", "last_name", "Washington", "text", + &field); form.fields.push_back(field); - test::CreateTestFormField( - "Phone #:", "home_phone_area_code", "650", "text", &field); + test::CreateTestFormField("Phone #:", "home_phone_area_code", "650", "text", + &field); field.max_length = 3; form.fields.push_back(field); - test::CreateTestFormField( - "Phone #:", "home_phone_prefix", "555", "text", &field); + test::CreateTestFormField("Phone #:", "home_phone_prefix", "555", "text", + &field); field.max_length = 3; form.fields.push_back(field); - test::CreateTestFormField( - "Phone #:", "home_phone_suffix", "0000", "text", &field); + test::CreateTestFormField("Phone #:", "home_phone_suffix", "0000", "text", + &field); field.max_length = 4; form.fields.push_back(field); - test::CreateTestFormField( - "Address:", "address1", "21 Laussat St", "text", &field); + test::CreateTestFormField("Address:", "address1", "21 Laussat St", "text", + &field); form.fields.push_back(field); test::CreateTestFormField("City:", "city", "San Francisco", "text", &field); form.fields.push_back(field); @@ -1326,9 +1343,9 @@ TEST_F(PersonalDataManagerTest, WaitForOnPersonalDataChanged(); AutofillProfile expected(base::GenerateGUID(), "https://www.example.com"); - test::SetProfileInfo(&expected, "George", NULL, - "Washington", NULL, NULL, "21 Laussat St", NULL, - "San Francisco", "California", "94102", NULL, "(650) 555-0000"); + test::SetProfileInfo(&expected, "George", NULL, "Washington", NULL, NULL, + "21 Laussat St", NULL, "San Francisco", "California", + "94102", NULL, "(650) 555-0000"); const std::vector<AutofillProfile*>& results = personal_data_->GetProfiles(); ASSERT_EQ(1U, results.size()); EXPECT_EQ(0, expected.Compare(*results[0])); @@ -1337,22 +1354,19 @@ TEST_F(PersonalDataManagerTest, TEST_F(PersonalDataManagerTest, ImportAddressProfiles_MultilineAddress) { FormData form; FormFieldData field; - test::CreateTestFormField( - "First name:", "first_name", "George", "text", &field); + test::CreateTestFormField("First name:", "first_name", "George", "text", + &field); form.fields.push_back(field); - test::CreateTestFormField( - "Last name:", "last_name", "Washington", "text", &field); + test::CreateTestFormField("Last name:", "last_name", "Washington", "text", + &field); form.fields.push_back(field); - test::CreateTestFormField( - "Email:", "email", "theprez@gmail.com", "text", &field); + test::CreateTestFormField("Email:", "email", "theprez@gmail.com", "text", + &field); form.fields.push_back(field); - test::CreateTestFormField( - "Address:", - "street_address", - "21 Laussat St\n" - "Apt. #42", - "textarea", - &field); + test::CreateTestFormField("Address:", "street_address", + "21 Laussat St\n" + "Apt. #42", + "textarea", &field); form.fields.push_back(field); test::CreateTestFormField("City:", "city", "San Francisco", "text", &field); form.fields.push_back(field); @@ -1367,9 +1381,9 @@ TEST_F(PersonalDataManagerTest, ImportAddressProfiles_MultilineAddress) { WaitForOnPersonalDataChanged(); AutofillProfile expected(base::GenerateGUID(), "https://www.example.com"); - test::SetProfileInfo(&expected, "George", NULL, - "Washington", "theprez@gmail.com", NULL, "21 Laussat St", "Apt. #42", - "San Francisco", "California", "94102", NULL, NULL); + test::SetProfileInfo(&expected, "George", NULL, "Washington", + "theprez@gmail.com", NULL, "21 Laussat St", "Apt. #42", + "San Francisco", "California", "94102", NULL, NULL); const std::vector<AutofillProfile*>& results = personal_data_->GetProfiles(); ASSERT_EQ(1U, results.size()); EXPECT_EQ(0, expected.Compare(*results[0])); @@ -1379,17 +1393,17 @@ TEST_F(PersonalDataManagerTest, ImportAddressProfiles_TwoValidProfilesDifferentForms) { FormData form1; FormFieldData field; - test::CreateTestFormField( - "First name:", "first_name", "George", "text", &field); + test::CreateTestFormField("First name:", "first_name", "George", "text", + &field); form1.fields.push_back(field); - test::CreateTestFormField( - "Last name:", "last_name", "Washington", "text", &field); + test::CreateTestFormField("Last name:", "last_name", "Washington", "text", + &field); form1.fields.push_back(field); - test::CreateTestFormField( - "Email:", "email", "theprez@gmail.com", "text", &field); + test::CreateTestFormField("Email:", "email", "theprez@gmail.com", "text", + &field); form1.fields.push_back(field); - test::CreateTestFormField( - "Address:", "address1", "21 Laussat St", "text", &field); + test::CreateTestFormField("Address:", "address1", "21 Laussat St", "text", + &field); form1.fields.push_back(field); test::CreateTestFormField("City:", "city", "San Francisco", "text", &field); form1.fields.push_back(field); @@ -1405,26 +1419,25 @@ TEST_F(PersonalDataManagerTest, WaitForOnPersonalDataChanged(); AutofillProfile expected(base::GenerateGUID(), "https://www.example.com"); - test::SetProfileInfo(&expected, "George", NULL, - "Washington", "theprez@gmail.com", NULL, "21 Laussat St", NULL, - "San Francisco", "California", "94102", NULL, NULL); + test::SetProfileInfo(&expected, "George", NULL, "Washington", + "theprez@gmail.com", NULL, "21 Laussat St", NULL, + "San Francisco", "California", "94102", NULL, NULL); const std::vector<AutofillProfile*>& results1 = personal_data_->GetProfiles(); ASSERT_EQ(1U, results1.size()); EXPECT_EQ(0, expected.Compare(*results1[0])); // Now create a completely different profile. FormData form2; - test::CreateTestFormField( - "First name:", "first_name", "John", "text", &field); + test::CreateTestFormField("First name:", "first_name", "John", "text", + &field); form2.fields.push_back(field); - test::CreateTestFormField( - "Last name:", "last_name", "Adams", "text", &field); + test::CreateTestFormField("Last name:", "last_name", "Adams", "text", &field); form2.fields.push_back(field); - test::CreateTestFormField( - "Email:", "email", "second@gmail.com", "text", &field); + test::CreateTestFormField("Email:", "email", "second@gmail.com", "text", + &field); form2.fields.push_back(field); - test::CreateTestFormField( - "Address:", "address1", "22 Laussat St", "text", &field); + test::CreateTestFormField("Address:", "address1", "22 Laussat St", "text", + &field); form2.fields.push_back(field); test::CreateTestFormField("City:", "city", "San Francisco", "text", &field); form2.fields.push_back(field); @@ -1440,9 +1453,9 @@ TEST_F(PersonalDataManagerTest, WaitForOnPersonalDataChanged(); AutofillProfile expected2(base::GenerateGUID(), "https://www.example.com"); - test::SetProfileInfo(&expected2, "John", NULL, - "Adams", "second@gmail.com", NULL, "22 Laussat St", NULL, - "San Francisco", "California", "94102", NULL, NULL); + test::SetProfileInfo(&expected2, "John", NULL, "Adams", "second@gmail.com", + NULL, "22 Laussat St", NULL, "San Francisco", + "California", "94102", NULL, NULL); std::vector<AutofillProfile*> profiles; profiles.push_back(&expected); profiles.push_back(&expected2); @@ -1540,8 +1553,7 @@ TEST_F(PersonalDataManagerTest, // There is an empty but hidden form section (this has been observed on sites // where users can choose which form section they choose by unhiding it). - test::CreateTestFormField("First name:", "first_name", "", "text", - &field); + test::CreateTestFormField("First name:", "first_name", "", "text", &field); field.is_focusable = false; form.fields.push_back(field); test::CreateTestFormField("Last name:", "last_name", "", "text", &field); @@ -1673,17 +1685,17 @@ TEST_F(PersonalDataManagerTest, TEST_F(PersonalDataManagerTest, ImportAddressProfiles_SameProfileWithConflict) { FormData form1; FormFieldData field; - test::CreateTestFormField( - "First name:", "first_name", "George", "text", &field); + test::CreateTestFormField("First name:", "first_name", "George", "text", + &field); form1.fields.push_back(field); - test::CreateTestFormField( - "Last name:", "last_name", "Washington", "text", &field); + test::CreateTestFormField("Last name:", "last_name", "Washington", "text", + &field); form1.fields.push_back(field); - test::CreateTestFormField( - "Address:", "address", "1600 Pennsylvania Avenue", "text", &field); + test::CreateTestFormField("Address:", "address", "1600 Pennsylvania Avenue", + "text", &field); form1.fields.push_back(field); - test::CreateTestFormField( - "Address Line 2:", "address2", "Suite A", "text", &field); + test::CreateTestFormField("Address Line 2:", "address2", "Suite A", "text", + &field); form1.fields.push_back(field); test::CreateTestFormField("City:", "city", "San Francisco", "text", &field); form1.fields.push_back(field); @@ -1691,8 +1703,8 @@ TEST_F(PersonalDataManagerTest, ImportAddressProfiles_SameProfileWithConflict) { form1.fields.push_back(field); test::CreateTestFormField("Zip:", "zip", "94102", "text", &field); form1.fields.push_back(field); - test::CreateTestFormField( - "Email:", "email", "theprez@gmail.com", "text", &field); + test::CreateTestFormField("Email:", "email", "theprez@gmail.com", "text", + &field); form1.fields.push_back(field); test::CreateTestFormField("Phone:", "phone", "6505556666", "text", &field); form1.fields.push_back(field); @@ -1714,17 +1726,17 @@ TEST_F(PersonalDataManagerTest, ImportAddressProfiles_SameProfileWithConflict) { // Now create an updated profile. FormData form2; - test::CreateTestFormField( - "First name:", "first_name", "George", "text", &field); + test::CreateTestFormField("First name:", "first_name", "George", "text", + &field); form2.fields.push_back(field); - test::CreateTestFormField( - "Last name:", "last_name", "Washington", "text", &field); + test::CreateTestFormField("Last name:", "last_name", "Washington", "text", + &field); form2.fields.push_back(field); - test::CreateTestFormField( - "Address:", "address", "1600 Pennsylvania Avenue", "text", &field); + test::CreateTestFormField("Address:", "address", "1600 Pennsylvania Avenue", + "text", &field); form2.fields.push_back(field); - test::CreateTestFormField( - "Address Line 2:", "address2", "Suite A", "text", &field); + test::CreateTestFormField("Address Line 2:", "address2", "Suite A", "text", + &field); form2.fields.push_back(field); test::CreateTestFormField("City:", "city", "San Francisco", "text", &field); form2.fields.push_back(field); @@ -1732,8 +1744,8 @@ TEST_F(PersonalDataManagerTest, ImportAddressProfiles_SameProfileWithConflict) { form2.fields.push_back(field); test::CreateTestFormField("Zip:", "zip", "94102", "text", &field); form2.fields.push_back(field); - test::CreateTestFormField( - "Email:", "email", "theprez@gmail.com", "text", &field); + test::CreateTestFormField("Email:", "email", "theprez@gmail.com", "text", + &field); form2.fields.push_back(field); // Country gets added. test::CreateTestFormField("Country:", "country", "USA", "text", &field); @@ -1762,14 +1774,14 @@ TEST_F(PersonalDataManagerTest, ImportAddressProfiles_SameProfileWithConflict) { TEST_F(PersonalDataManagerTest, ImportAddressProfiles_MissingInfoInOld) { FormData form1; FormFieldData field; - test::CreateTestFormField( - "First name:", "first_name", "George", "text", &field); + test::CreateTestFormField("First name:", "first_name", "George", "text", + &field); form1.fields.push_back(field); - test::CreateTestFormField( - "Last name:", "last_name", "Washington", "text", &field); + test::CreateTestFormField("Last name:", "last_name", "Washington", "text", + &field); form1.fields.push_back(field); - test::CreateTestFormField( - "Address Line 1:", "address", "190 High Street", "text", &field); + test::CreateTestFormField("Address Line 1:", "address", "190 High Street", + "text", &field); form1.fields.push_back(field); test::CreateTestFormField("City:", "city", "Philadelphia", "text", &field); form1.fields.push_back(field); @@ -1785,26 +1797,26 @@ TEST_F(PersonalDataManagerTest, ImportAddressProfiles_MissingInfoInOld) { WaitForOnPersonalDataChanged(); AutofillProfile expected(base::GenerateGUID(), "https://www.example.com"); - test::SetProfileInfo(&expected, "George", NULL, - "Washington", NULL, NULL, "190 High Street", NULL, - "Philadelphia", "Pennsylvania", "19106", NULL, NULL); + test::SetProfileInfo(&expected, "George", NULL, "Washington", NULL, NULL, + "190 High Street", NULL, "Philadelphia", "Pennsylvania", + "19106", NULL, NULL); const std::vector<AutofillProfile*>& results1 = personal_data_->GetProfiles(); ASSERT_EQ(1U, results1.size()); EXPECT_EQ(0, expected.Compare(*results1[0])); // Submit a form with new data for the first profile. FormData form2; - test::CreateTestFormField( - "First name:", "first_name", "George", "text", &field); + test::CreateTestFormField("First name:", "first_name", "George", "text", + &field); form2.fields.push_back(field); - test::CreateTestFormField( - "Last name:", "last_name", "Washington", "text", &field); + test::CreateTestFormField("Last name:", "last_name", "Washington", "text", + &field); form2.fields.push_back(field); - test::CreateTestFormField( - "Email:", "email", "theprez@gmail.com", "text", &field); + test::CreateTestFormField("Email:", "email", "theprez@gmail.com", "text", + &field); form2.fields.push_back(field); - test::CreateTestFormField( - "Address Line 1:", "address", "190 High Street", "text", &field); + test::CreateTestFormField("Address Line 1:", "address", "190 High Street", + "text", &field); form2.fields.push_back(field); test::CreateTestFormField("City:", "city", "Philadelphia", "text", &field); form2.fields.push_back(field); @@ -1822,9 +1834,9 @@ TEST_F(PersonalDataManagerTest, ImportAddressProfiles_MissingInfoInOld) { const std::vector<AutofillProfile*>& results2 = personal_data_->GetProfiles(); AutofillProfile expected2(base::GenerateGUID(), "https://www.example.com"); - test::SetProfileInfo(&expected2, "George", NULL, - "Washington", "theprez@gmail.com", NULL, "190 High Street", NULL, - "Philadelphia", "Pennsylvania", "19106", NULL, NULL); + test::SetProfileInfo(&expected2, "George", NULL, "Washington", + "theprez@gmail.com", NULL, "190 High Street", NULL, + "Philadelphia", "Pennsylvania", "19106", NULL, NULL); expected2.SetRawInfo(NAME_FULL, base::ASCIIToUTF16("George Washington")); ASSERT_EQ(1U, results2.size()); EXPECT_EQ(0, expected2.Compare(*results2[0])); @@ -1833,20 +1845,20 @@ TEST_F(PersonalDataManagerTest, ImportAddressProfiles_MissingInfoInOld) { TEST_F(PersonalDataManagerTest, ImportAddressProfiles_MissingInfoInNew) { FormData form1; FormFieldData field; - test::CreateTestFormField( - "First name:", "first_name", "George", "text", &field); + test::CreateTestFormField("First name:", "first_name", "George", "text", + &field); form1.fields.push_back(field); - test::CreateTestFormField( - "Last name:", "last_name", "Washington", "text", &field); + test::CreateTestFormField("Last name:", "last_name", "Washington", "text", + &field); form1.fields.push_back(field); - test::CreateTestFormField( - "Company:", "company", "Government", "text", &field); + test::CreateTestFormField("Company:", "company", "Government", "text", + &field); form1.fields.push_back(field); - test::CreateTestFormField( - "Email:", "email", "theprez@gmail.com", "text", &field); + test::CreateTestFormField("Email:", "email", "theprez@gmail.com", "text", + &field); form1.fields.push_back(field); - test::CreateTestFormField( - "Address Line 1:", "address", "190 High Street", "text", &field); + test::CreateTestFormField("Address Line 1:", "address", "190 High Street", + "text", &field); form1.fields.push_back(field); test::CreateTestFormField("City:", "city", "Philadelphia", "text", &field); form1.fields.push_back(field); @@ -1862,27 +1874,28 @@ TEST_F(PersonalDataManagerTest, ImportAddressProfiles_MissingInfoInNew) { WaitForOnPersonalDataChanged(); AutofillProfile expected(base::GenerateGUID(), "https://www.example.com"); - test::SetProfileInfo(&expected, "George", NULL, - "Washington", "theprez@gmail.com", "Government", "190 High Street", NULL, - "Philadelphia", "Pennsylvania", "19106", NULL, NULL); + test::SetProfileInfo(&expected, "George", NULL, "Washington", + "theprez@gmail.com", "Government", "190 High Street", + NULL, "Philadelphia", "Pennsylvania", "19106", NULL, + NULL); const std::vector<AutofillProfile*>& results1 = personal_data_->GetProfiles(); ASSERT_EQ(1U, results1.size()); EXPECT_EQ(0, expected.Compare(*results1[0])); // Submit a form with new data for the first profile. FormData form2; - test::CreateTestFormField( - "First name:", "first_name", "George", "text", &field); + test::CreateTestFormField("First name:", "first_name", "George", "text", + &field); form2.fields.push_back(field); - test::CreateTestFormField( - "Last name:", "last_name", "Washington", "text", &field); + test::CreateTestFormField("Last name:", "last_name", "Washington", "text", + &field); form2.fields.push_back(field); // Note missing Company field. - test::CreateTestFormField( - "Email:", "email", "theprez@gmail.com", "text", &field); + test::CreateTestFormField("Email:", "email", "theprez@gmail.com", "text", + &field); form2.fields.push_back(field); - test::CreateTestFormField( - "Address Line 1:", "address", "190 High Street", "text", &field); + test::CreateTestFormField("Address Line 1:", "address", "190 High Street", + "text", &field); form2.fields.push_back(field); test::CreateTestFormField("City:", "city", "Philadelphia", "text", &field); form2.fields.push_back(field); @@ -1908,20 +1921,20 @@ TEST_F(PersonalDataManagerTest, ImportAddressProfiles_MissingInfoInNew) { TEST_F(PersonalDataManagerTest, ImportAddressProfiles_InsufficientAddress) { FormData form1; FormFieldData field; - test::CreateTestFormField( - "First name:", "first_name", "George", "text", &field); + test::CreateTestFormField("First name:", "first_name", "George", "text", + &field); form1.fields.push_back(field); - test::CreateTestFormField( - "Last name:", "last_name", "Washington", "text", &field); + test::CreateTestFormField("Last name:", "last_name", "Washington", "text", + &field); form1.fields.push_back(field); - test::CreateTestFormField( - "Company:", "company", "Government", "text", &field); + test::CreateTestFormField("Company:", "company", "Government", "text", + &field); form1.fields.push_back(field); - test::CreateTestFormField( - "Email:", "email", "theprez@gmail.com", "text", &field); + test::CreateTestFormField("Email:", "email", "theprez@gmail.com", "text", + &field); form1.fields.push_back(field); - test::CreateTestFormField( - "Address Line 1:", "address", "190 High Street", "text", &field); + test::CreateTestFormField("Address Line 1:", "address", "190 High Street", + "text", &field); form1.fields.push_back(field); test::CreateTestFormField("City:", "city", "Philadelphia", "text", &field); form1.fields.push_back(field); @@ -2868,7 +2881,7 @@ TEST_F(PersonalDataManagerTest, ImportFormData_OneAddressOneCreditCard) { std::unique_ptr<CreditCard> imported_credit_card; bool imported_credit_card_matches_masked_server_credit_card; EXPECT_TRUE(personal_data_->ImportFormData( - form_structure, false, &imported_credit_card, + form_structure, true, false, &imported_credit_card, &imported_credit_card_matches_masked_server_credit_card)); ASSERT_TRUE(imported_credit_card); EXPECT_FALSE(imported_credit_card_matches_masked_server_credit_card); @@ -2947,7 +2960,7 @@ TEST_F(PersonalDataManagerTest, ImportFormData_TwoAddressesOneCreditCard) { bool imported_credit_card_matches_masked_server_credit_card; // Still returns true because the credit card import was successful. EXPECT_TRUE(personal_data_->ImportFormData( - form_structure, false, &imported_credit_card, + form_structure, true, false, &imported_credit_card, &imported_credit_card_matches_masked_server_credit_card)); ASSERT_TRUE(imported_credit_card); EXPECT_FALSE(imported_credit_card_matches_masked_server_credit_card); @@ -2967,15 +2980,69 @@ TEST_F(PersonalDataManagerTest, ImportFormData_TwoAddressesOneCreditCard) { EXPECT_EQ(0, expected_card.Compare(*results[0])); } +TEST_F(PersonalDataManagerTest, ImportFormData_OneAddressCreditCardDisabled) { + FormData form; + FormFieldData field; + // Address section. + test::CreateTestFormField("First name:", "first_name", "George", "text", + &field); + form.fields.push_back(field); + test::CreateTestFormField("Last name:", "last_name", "Washington", "text", + &field); + form.fields.push_back(field); + test::CreateTestFormField("Email:", "email", "theprez@gmail.com", "text", + &field); + form.fields.push_back(field); + test::CreateTestFormField("Address:", "address1", "21 Laussat St", "text", + &field); + form.fields.push_back(field); + test::CreateTestFormField("City:", "city", "San Francisco", "text", &field); + form.fields.push_back(field); + test::CreateTestFormField("State:", "state", "California", "text", &field); + form.fields.push_back(field); + test::CreateTestFormField("Zip:", "zip", "94102", "text", &field); + form.fields.push_back(field); + + // Credit card section. + AddFullCreditCardForm(&form, "Biggie Smalls", "4111-1111-1111-1111", "01", + "2999"); + + FormStructure form_structure(form); + form_structure.DetermineHeuristicTypes(nullptr /* ukm_service */); + std::unique_ptr<CreditCard> imported_credit_card; + bool imported_credit_card_matches_masked_server_credit_card; + EXPECT_TRUE(personal_data_->ImportFormData( + form_structure, false, false, &imported_credit_card, + &imported_credit_card_matches_masked_server_credit_card)); + ASSERT_FALSE(imported_credit_card); + + WaitForOnPersonalDataChanged(); + + // Test that the address has been saved. + AutofillProfile expected_address(base::GenerateGUID(), + "https://www.example.com"); + test::SetProfileInfo(&expected_address, "George", NULL, "Washington", + "theprez@gmail.com", NULL, "21 Laussat St", NULL, + "San Francisco", "California", "94102", NULL, NULL); + const std::vector<AutofillProfile*>& results_addr = + personal_data_->GetProfiles(); + ASSERT_EQ(1U, results_addr.size()); + EXPECT_EQ(0, expected_address.Compare(*results_addr[0])); + + // Test that the credit card was not saved. + const std::vector<CreditCard*>& results_cards = + personal_data_->GetCreditCards(); + ASSERT_EQ(0U, results_cards.size()); +} + // Ensure that verified profiles can be saved via SaveImportedProfile, // overwriting existing unverified profiles. TEST_F(PersonalDataManagerTest, SaveImportedProfileWithVerifiedData) { // Start with an unverified profile. AutofillProfile profile(base::GenerateGUID(), "https://www.example.com"); - test::SetProfileInfo(&profile, - "Marion", "Mitchell", "Morrison", - "johnwayne@me.xyz", "Fox", "123 Zoo St.", "unit 5", "Hollywood", "CA", - "91601", "US", "12345678910"); + test::SetProfileInfo(&profile, "Marion", "Mitchell", "Morrison", + "johnwayne@me.xyz", "Fox", "123 Zoo St.", "unit 5", + "Hollywood", "CA", "91601", "US", "12345678910"); EXPECT_FALSE(profile.IsVerified()); // Add the profile to the database. @@ -3048,10 +3115,9 @@ TEST_F(PersonalDataManagerTest, GetNonEmptyTypes) { // Test with one profile stored. AutofillProfile profile0(base::GenerateGUID(), "https://www.example.com"); - test::SetProfileInfo(&profile0, - "Marion", NULL, "Morrison", - "johnwayne@me.xyz", NULL, "123 Zoo St.", NULL, "Hollywood", "CA", - "91601", "US", "14155678910"); + test::SetProfileInfo(&profile0, "Marion", NULL, "Morrison", + "johnwayne@me.xyz", NULL, "123 Zoo St.", NULL, + "Hollywood", "CA", "91601", "US", "14155678910"); personal_data_->AddProfile(profile0); @@ -3079,16 +3145,14 @@ TEST_F(PersonalDataManagerTest, GetNonEmptyTypes) { // Test with multiple profiles stored. AutofillProfile profile1(base::GenerateGUID(), "https://www.example.com"); - test::SetProfileInfo(&profile1, - "Josephine", "Alicia", "Saenz", - "joewayne@me.xyz", "Fox", "903 Apple Ct.", NULL, "Orlando", "FL", "32801", - "US", "16502937549"); + test::SetProfileInfo(&profile1, "Josephine", "Alicia", "Saenz", + "joewayne@me.xyz", "Fox", "903 Apple Ct.", NULL, + "Orlando", "FL", "32801", "US", "16502937549"); AutofillProfile profile2(base::GenerateGUID(), "https://www.example.com"); - test::SetProfileInfo(&profile2, - "Josephine", "Alicia", "Saenz", - "joewayne@me.xyz", "Fox", "1212 Center.", "Bld. 5", "Orlando", "FL", - "32801", "US", "16502937549"); + test::SetProfileInfo(&profile2, "Josephine", "Alicia", "Saenz", + "joewayne@me.xyz", "Fox", "1212 Center.", "Bld. 5", + "Orlando", "FL", "32801", "US", "16502937549"); personal_data_->AddProfile(profile1); personal_data_->AddProfile(profile2); @@ -3166,8 +3230,8 @@ TEST_F(PersonalDataManagerTest, IncognitoReadOnly) { AutofillProfile steve_jobs(base::GenerateGUID(), "https://www.example.com"); test::SetProfileInfo(&steve_jobs, "Steven", "Paul", "Jobs", "sjobs@apple.com", - "Apple Computer, Inc.", "1 Infinite Loop", "", "Cupertino", "CA", "95014", - "US", "(800) 275-2273"); + "Apple Computer, Inc.", "1 Infinite Loop", "", + "Cupertino", "CA", "95014", "US", "(800) 275-2273"); personal_data_->AddProfile(steve_jobs); CreditCard bill_gates(base::GenerateGUID(), "https://www.example.com"); @@ -3242,9 +3306,9 @@ TEST_F(PersonalDataManagerTest, DefaultCountryCodeIsCached) { EXPECT_EQ(2U, default_country.size()); AutofillProfile moose(base::GenerateGUID(), kSettingsOrigin); - test::SetProfileInfo(&moose, "Moose", "P", "McMahon", "mpm@example.com", - "", "1 Taiga TKTR", "", "Calgary", "AB", "T2B 2K2", - "CA", "(800) 555-9000"); + test::SetProfileInfo(&moose, "Moose", "P", "McMahon", "mpm@example.com", "", + "1 Taiga TKTR", "", "Calgary", "AB", "T2B 2K2", "CA", + "(800) 555-9000"); personal_data_->AddProfile(moose); // Make sure everything is set up correctly. @@ -3272,22 +3336,22 @@ TEST_F(PersonalDataManagerTest, DefaultCountryCodeIsCached) { TEST_F(PersonalDataManagerTest, DefaultCountryCodeComesFromProfiles) { AutofillProfile moose(base::GenerateGUID(), kSettingsOrigin); - test::SetProfileInfo(&moose, "Moose", "P", "McMahon", "mpm@example.com", - "", "1 Taiga TKTR", "", "Calgary", "AB", "T2B 2K2", - "CA", "(800) 555-9000"); + test::SetProfileInfo(&moose, "Moose", "P", "McMahon", "mpm@example.com", "", + "1 Taiga TKTR", "", "Calgary", "AB", "T2B 2K2", "CA", + "(800) 555-9000"); personal_data_->AddProfile(moose); ResetPersonalDataManager(USER_MODE_NORMAL); EXPECT_EQ("CA", personal_data_->GetDefaultCountryCodeForNewAddress()); // Multiple profiles cast votes. AutofillProfile armadillo(base::GenerateGUID(), kSettingsOrigin); - test::SetProfileInfo(&armadillo, "Armin", "Dill", "Oh", "ado@example.com", - "", "1 Speed Bump", "", "Lubbock", "TX", "77500", - "MX", "(800) 555-9000"); + test::SetProfileInfo(&armadillo, "Armin", "Dill", "Oh", "ado@example.com", "", + "1 Speed Bump", "", "Lubbock", "TX", "77500", "MX", + "(800) 555-9000"); AutofillProfile armadillo2(base::GenerateGUID(), kSettingsOrigin); test::SetProfileInfo(&armadillo2, "Armin", "Dill", "Oh", "ado@example.com", - "", "2 Speed Bump", "", "Lubbock", "TX", "77500", - "MX", "(800) 555-9000"); + "", "2 Speed Bump", "", "Lubbock", "TX", "77500", "MX", + "(800) 555-9000"); personal_data_->AddProfile(armadillo); personal_data_->AddProfile(armadillo2); ResetPersonalDataManager(USER_MODE_NORMAL); @@ -3316,9 +3380,9 @@ TEST_F(PersonalDataManagerTest, DefaultCountryCodeComesFromProfiles) { personal_data_->RemoveByGUID(armadillo.guid()); personal_data_->RemoveByGUID(moose.guid()); AutofillProfile space_invader(base::GenerateGUID(), kSettingsOrigin); - test::SetProfileInfo(&space_invader, "Marty", "", "Martian", - "mm@example.com", "", "1 Flying Object", "", "Valles Marineris", "", - "", "XX", ""); + test::SetProfileInfo(&space_invader, "Marty", "", "Martian", "mm@example.com", + "", "1 Flying Object", "", "Valles Marineris", "", "", + "XX", ""); personal_data_->AddProfile(moose); ResetPersonalDataManager(USER_MODE_NORMAL); EXPECT_EQ("MX", personal_data_->GetDefaultCountryCodeForNewAddress()); @@ -3326,15 +3390,14 @@ TEST_F(PersonalDataManagerTest, DefaultCountryCodeComesFromProfiles) { TEST_F(PersonalDataManagerTest, UpdateLanguageCodeInProfile) { AutofillProfile profile(base::GenerateGUID(), "https://www.example.com"); - test::SetProfileInfo(&profile, - "Marion", "Mitchell", "Morrison", - "johnwayne@me.xyz", "Fox", "123 Zoo St.", "unit 5", "Hollywood", "CA", - "91601", "US", "12345678910"); + test::SetProfileInfo(&profile, "Marion", "Mitchell", "Morrison", + "johnwayne@me.xyz", "Fox", "123 Zoo St.", "unit 5", + "Hollywood", "CA", "91601", "US", "12345678910"); personal_data_->AddProfile(profile); // Make sure everything is set up correctly. WaitForOnPersonalDataChanged(); - EXPECT_EQ(1U, personal_data_->web_profiles().size()); + EXPECT_EQ(1U, personal_data_->GetProfiles().size()); EXPECT_EQ(1U, personal_data_->GetProfiles().size()); profile.set_language_code("en"); @@ -3350,11 +3413,10 @@ TEST_F(PersonalDataManagerTest, UpdateLanguageCodeInProfile) { TEST_F(PersonalDataManagerTest, GetProfileSuggestions) { AutofillProfile profile(base::GenerateGUID(), "https://www.example.com"); - test::SetProfileInfo(&profile, - "Marion", "Mitchell", "Morrison", - "johnwayne@me.xyz", "Fox", - "123 Zoo St.\nSecond Line\nThird line", "unit 5", "Hollywood", "CA", - "91601", "US", "12345678910"); + test::SetProfileInfo(&profile, "Marion", "Mitchell", "Morrison", + "johnwayne@me.xyz", "Fox", + "123 Zoo St.\nSecond Line\nThird line", "unit 5", + "Hollywood", "CA", "91601", "US", "12345678910"); personal_data_->AddProfile(profile); ResetPersonalDataManager(USER_MODE_NORMAL); @@ -3605,6 +3667,103 @@ TEST_F(PersonalDataManagerTest, } } +TEST_F(PersonalDataManagerTest, IsKnownCard_MatchesMaskedServerCard) { + // Add a masked server card. + std::vector<CreditCard> server_cards; + server_cards.push_back(CreditCard(CreditCard::MASKED_SERVER_CARD, "b459")); + test::SetCreditCardInfo(&server_cards.back(), "Emmet Dalton", + "2110" /* last 4 digits */, "12", "2999", "1"); + server_cards.back().SetNetworkForMaskedCard(kVisaCard); + + test::SetServerCreditCards(autofill_table_, server_cards); + + // Make sure everything is set up correctly. + personal_data_->Refresh(); + WaitForOnPersonalDataChanged(); + EXPECT_EQ(1U, personal_data_->GetCreditCards().size()); + + CreditCard cardToCompare; + cardToCompare.SetNumber(base::ASCIIToUTF16("4234 5678 9012 2110") /* Visa */); + ASSERT_TRUE(personal_data_->IsKnownCard(cardToCompare)); +} + +TEST_F(PersonalDataManagerTest, IsKnownCard_MatchesFullServerCard) { + // Add a full server card. + std::vector<CreditCard> server_cards; + server_cards.push_back(CreditCard(CreditCard::FULL_SERVER_CARD, "b459")); + test::SetCreditCardInfo(&server_cards.back(), "Emmet Dalton", + "4234567890122110" /* Visa */, "12", "2999", "1"); + + test::SetServerCreditCards(autofill_table_, server_cards); + + // Make sure everything is set up correctly. + personal_data_->Refresh(); + WaitForOnPersonalDataChanged(); + EXPECT_EQ(1U, personal_data_->GetCreditCards().size()); + + CreditCard cardToCompare; + cardToCompare.SetNumber(base::ASCIIToUTF16("4234 5678 9012 2110") /* Visa */); + ASSERT_TRUE(personal_data_->IsKnownCard(cardToCompare)); +} + +TEST_F(PersonalDataManagerTest, IsKnownCard_MatchesLocalCard) { + EnableWalletCardImport(); + // Add a local card. + CreditCard credit_card0("287151C8-6AB1-487C-9095-28E80BE5DA15", + "https://www.example.com"); + test::SetCreditCardInfo(&credit_card0, "Clyde Barrow", + "4234 5678 9012 2110" /* Visa */, "04", "2999", "1"); + personal_data_->AddCreditCard(credit_card0); + + // Make sure everything is set up correctly. + personal_data_->Refresh(); + WaitForOnPersonalDataChanged(); + EXPECT_EQ(1U, personal_data_->GetCreditCards().size()); + + CreditCard cardToCompare; + cardToCompare.SetNumber(base::ASCIIToUTF16("4234567890122110") /* Visa */); + ASSERT_TRUE(personal_data_->IsKnownCard(cardToCompare)); +} + +TEST_F(PersonalDataManagerTest, IsKnownCard_TypeDoesNotMatch) { + EnableWalletCardImport(); + // Add a local card. + CreditCard credit_card0("287151C8-6AB1-487C-9095-28E80BE5DA15", + "https://www.example.com"); + test::SetCreditCardInfo(&credit_card0, "Clyde Barrow", + "4234 5678 9012 2110" /* Visa */, "04", "2999", "1"); + personal_data_->AddCreditCard(credit_card0); + + // Make sure everything is set up correctly. + personal_data_->Refresh(); + WaitForOnPersonalDataChanged(); + EXPECT_EQ(1U, personal_data_->GetCreditCards().size()); + + CreditCard cardToCompare; + cardToCompare.SetNumber( + base::ASCIIToUTF16("5105 1051 0510 2110") /* American Express */); + ASSERT_FALSE(personal_data_->IsKnownCard(cardToCompare)); +} + +TEST_F(PersonalDataManagerTest, IsKnownCard_LastFourDoesNotMatch) { + EnableWalletCardImport(); + // Add a local card. + CreditCard credit_card0("287151C8-6AB1-487C-9095-28E80BE5DA15", + "https://www.example.com"); + test::SetCreditCardInfo(&credit_card0, "Clyde Barrow", + "4234 5678 9012 2110" /* Visa */, "04", "2999", "1"); + personal_data_->AddCreditCard(credit_card0); + + // Make sure everything is set up correctly. + personal_data_->Refresh(); + WaitForOnPersonalDataChanged(); + EXPECT_EQ(1U, personal_data_->GetCreditCards().size()); + + CreditCard cardToCompare; + cardToCompare.SetNumber(base::ASCIIToUTF16("4234 5678 9012 0000") /* Visa */); + ASSERT_FALSE(personal_data_->IsKnownCard(cardToCompare)); +} + // Test that a masked server card is not suggested if more that six numbers have // been typed in the field. TEST_F(PersonalDataManagerTest, @@ -3701,6 +3860,48 @@ TEST_F(PersonalDataManagerTest, EXPECT_EQ(base::ASCIIToUTF16("Bonnie Parker"), suggestions[4].value); } +// Test that local and server cards are not shown if +// |kAutofillCreditCardEnabled| is set to |false|. +TEST_F(PersonalDataManagerTest, + GetCreditCardSuggestions_CreditCardAutofillDisabled) { + EnableWalletCardImport(); + SetUpReferenceLocalCreditCards(); + + // Add some server cards. + std::vector<CreditCard> server_cards; + server_cards.push_back(CreditCard(CreditCard::MASKED_SERVER_CARD, "b459")); + test::SetCreditCardInfo(&server_cards.back(), "Emmet Dalton", "2110", "12", + "2999", "1"); + server_cards.back().set_use_count(2); + server_cards.back().set_use_date(AutofillClock::Now() - + base::TimeDelta::FromDays(1)); + server_cards.back().SetNetworkForMaskedCard(kVisaCard); + + server_cards.push_back(CreditCard(CreditCard::FULL_SERVER_CARD, "b460")); + test::SetCreditCardInfo(&server_cards.back(), "Jesse James", "2109", "12", + "2999", "1"); + server_cards.back().set_use_count(6); + server_cards.back().set_use_date(AutofillClock::Now() - + base::TimeDelta::FromDays(1)); + + test::SetServerCreditCards(autofill_table_, server_cards); + + // Disable Credit card autofill. + personal_data_->pref_service_->SetBoolean(prefs::kAutofillCreditCardEnabled, + false); + personal_data_->Refresh(); + WaitForOnPersonalDataChanged(); + + // Expect no autofilled values or suggestions. + EXPECT_EQ(0U, personal_data_->GetCreditCards().size()); + + std::vector<Suggestion> suggestions = + personal_data_->GetCreditCardSuggestions( + AutofillType(CREDIT_CARD_NAME_FULL), + /* field_contents= */ base::string16()); + ASSERT_EQ(0U, suggestions.size()); +} + // Test that expired cards are ordered by frecency and are always suggested // after non expired cards even if they have a higher frecency score. TEST_F(PersonalDataManagerTest, GetCreditCardSuggestions_ExpiredCards) { @@ -3753,6 +3954,139 @@ TEST_F(PersonalDataManagerTest, GetCreditCardSuggestions_ExpiredCards) { EXPECT_EQ(base::ASCIIToUTF16("John Dillinger"), suggestions[2].value); } +// Test cards that are expired AND disused are suppressed when supression is +// enabled and the input field is empty. +TEST_F(PersonalDataManagerTest, + GetCreditCardSuggestions_SuppressDisusedCreditCardsOnEmptyField) { + ASSERT_EQ(0U, personal_data_->GetCreditCards().size()); + + // Add a never used non expired local credit card. + CreditCard credit_card0("002149C1-EE28-4213-A3B9-DA243FFF021B", + "https://www.example.com"); + test::SetCreditCardInfo(&credit_card0, "Bonnie Parker", + "5105105105105100" /* Mastercard */, "04", "2999", + "1"); + personal_data_->AddCreditCard(credit_card0); + + auto now = AutofillClock::Now(); + + // Add an expired unmasked card last used 10 days ago + CreditCard credit_card1(CreditCard::FULL_SERVER_CARD, "c789"); + test::SetCreditCardInfo(&credit_card1, "Clyde Barrow", + "4234567890123456" /* Visa */, "04", "1999", "1"); + credit_card1.set_use_date(now - base::TimeDelta::FromDays(10)); + + // Add an expired masked card last used 180 days ago. + CreditCard credit_card2(CreditCard::MASKED_SERVER_CARD, "c987"); + test::SetCreditCardInfo(&credit_card2, "Jane Doe", "6543", "01", "1998", "1"); + credit_card2.set_use_date(now - base::TimeDelta::FromDays(181)); + credit_card2.SetNetworkForMaskedCard(kVisaCard); + + // Save the server cards and set used_date to desired dates. + std::vector<CreditCard> server_cards; + server_cards.push_back(credit_card1); + server_cards.push_back(credit_card2); + test::SetServerCreditCards(autofill_table_, server_cards); + personal_data_->UpdateServerCardMetadata(credit_card1); + personal_data_->UpdateServerCardMetadata(credit_card2); + + // Add an expired local card last used 180 days ago. + CreditCard credit_card3("1141084B-72D7-4B73-90CF-3D6AC154673B", + "https://www.example.com"); + credit_card3.set_use_date(now - base::TimeDelta::FromDays(182)); + test::SetCreditCardInfo(&credit_card3, "John Dillinger", + "378282246310005" /* American Express */, "01", + "1998", "1"); + personal_data_->AddCreditCard(credit_card3); + + // Make sure everything is set up correctly. + personal_data_->Refresh(); + WaitForOnPersonalDataChanged(); + ASSERT_EQ(4U, personal_data_->GetCreditCards().size()); + + // Verify credit card suppression is disabled by default. + { + ASSERT_FALSE( + base::FeatureList::IsEnabled(kAutofillSuppressDisusedCreditCards)); + } + + // Verify no suppression if feature is disabled. + { + base::test::ScopedFeatureList scoped_features; + scoped_features.InitAndDisableFeature(kAutofillSuppressDisusedCreditCards); + + std::vector<Suggestion> suggestions = + personal_data_->GetCreditCardSuggestions( + AutofillType(CREDIT_CARD_NAME_FULL), base::string16()); + EXPECT_EQ(4U, suggestions.size()); + EXPECT_EQ(base::ASCIIToUTF16("Bonnie Parker"), suggestions[0].value); + EXPECT_EQ(base::ASCIIToUTF16("Clyde Barrow"), suggestions[1].value); + EXPECT_EQ(base::ASCIIToUTF16("Jane Doe"), suggestions[2].value); + EXPECT_EQ(base::ASCIIToUTF16("John Dillinger"), suggestions[3].value); + } + + base::test::ScopedFeatureList scoped_features; + scoped_features.InitAndEnableFeature(kAutofillSuppressDisusedCreditCards); + + // Query with empty string only returns card0 and card1. Note expired + // masked card2 is not suggested on empty fields. + { + std::vector<Suggestion> suggestions = + personal_data_->GetCreditCardSuggestions( + AutofillType(CREDIT_CARD_NAME_FULL), base::string16()); + EXPECT_EQ(2U, suggestions.size()); + EXPECT_EQ(base::ASCIIToUTF16("Bonnie Parker"), suggestions[0].value); + EXPECT_EQ(base::ASCIIToUTF16("Clyde Barrow"), suggestions[1].value); + } + + // Query with name prefix for card0 returns card0. + { + std::vector<Suggestion> suggestions = + personal_data_->GetCreditCardSuggestions( + AutofillType(CREDIT_CARD_NAME_FULL), base::ASCIIToUTF16("B")); + + ASSERT_EQ(1U, suggestions.size()); + EXPECT_EQ(base::ASCIIToUTF16("Bonnie Parker"), suggestions[0].value); + } + + // Query with name prefix for card1 returns card1. + { + std::vector<Suggestion> suggestions = + personal_data_->GetCreditCardSuggestions( + AutofillType(CREDIT_CARD_NAME_FULL), base::ASCIIToUTF16("Cl")); + + ASSERT_EQ(1U, suggestions.size()); + EXPECT_EQ(base::ASCIIToUTF16("Clyde Barrow"), suggestions[0].value); + } + + // Query with name prefix for card2 returns card2. + { + std::vector<Suggestion> suggestions = + personal_data_->GetCreditCardSuggestions( + AutofillType(CREDIT_CARD_NAME_FULL), base::ASCIIToUTF16("Jo")); + + ASSERT_EQ(1U, suggestions.size()); + EXPECT_EQ(base::ASCIIToUTF16("John Dillinger"), suggestions[0].value); + } + + // Query with card number prefix for card1 returns card1 and card2. + // Expired masked card2 is shown when user starts to type credit card + // number because we are not sure if it is the masked card that they want. + { + std::vector<Suggestion> suggestions = + personal_data_->GetCreditCardSuggestions( + AutofillType(CREDIT_CARD_NUMBER), base::ASCIIToUTF16("4234")); + + ASSERT_EQ(2U, suggestions.size()); + EXPECT_EQ( + base::UTF8ToUTF16(std::string("Visa") + kUTF8MidlineEllipsis + "3456"), + suggestions[0].value); + EXPECT_EQ( + base::UTF8ToUTF16(std::string("Visa") + kUTF8MidlineEllipsis + "6543"), + suggestions[1].value); + } +} + // Test that a card that doesn't have a number is not shown in the suggestions // when querying credit cards by their number. TEST_F(PersonalDataManagerTest, GetCreditCardSuggestions_NumberMissing) { @@ -4215,8 +4549,8 @@ TEST_F(PersonalDataManagerTest, UpdateServerCreditCardUsageStats) { CreditCard* unmasked_card = &server_cards.front(); unmasked_card->set_record_type(CreditCard::FULL_SERVER_CARD); unmasked_card->SetNumber(base::ASCIIToUTF16("4234567890123456")); - EXPECT_NE(0, unmasked_card->Compare( - *personal_data_->GetCreditCards().front())); + EXPECT_NE(0, + unmasked_card->Compare(*personal_data_->GetCreditCards().front())); personal_data_->UpdateServerCreditCard(*unmasked_card); WaitForOnPersonalDataChanged(); @@ -4355,7 +4689,7 @@ TEST_F(PersonalDataManagerTest, AllowDuplicateMaskedServerCardIfFlagEnabled) { std::unique_ptr<CreditCard> imported_credit_card; bool imported_credit_card_matches_masked_server_credit_card; EXPECT_TRUE(personal_data_->ImportFormData( - form_structure, false, &imported_credit_card, + form_structure, true, false, &imported_credit_card, &imported_credit_card_matches_masked_server_credit_card)); ASSERT_TRUE(imported_credit_card); EXPECT_TRUE(imported_credit_card_matches_masked_server_credit_card); @@ -4415,7 +4749,7 @@ TEST_F(PersonalDataManagerTest, DontDuplicateMaskedServerCard) { std::unique_ptr<CreditCard> imported_credit_card; bool imported_credit_card_matches_masked_server_credit_card; EXPECT_FALSE(personal_data_->ImportFormData( - form_structure, false, &imported_credit_card, + form_structure, true, false, &imported_credit_card, &imported_credit_card_matches_masked_server_credit_card)); ASSERT_FALSE(imported_credit_card); EXPECT_FALSE(imported_credit_card_matches_masked_server_credit_card); @@ -4463,7 +4797,7 @@ TEST_F(PersonalDataManagerTest, DontDuplicateFullServerCard) { std::unique_ptr<CreditCard> imported_credit_card; bool imported_credit_card_matches_masked_server_credit_card; EXPECT_FALSE(personal_data_->ImportFormData( - form_structure, false, &imported_credit_card, + form_structure, true, false, &imported_credit_card, &imported_credit_card_matches_masked_server_credit_card)); EXPECT_FALSE(imported_credit_card); EXPECT_FALSE(imported_credit_card_matches_masked_server_credit_card); @@ -4506,7 +4840,7 @@ TEST_F(PersonalDataManagerTest, std::unique_ptr<CreditCard> imported_credit_card; bool imported_credit_card_matches_masked_server_credit_card; EXPECT_FALSE(personal_data_->ImportFormData( - form_structure, false, &imported_credit_card, + form_structure, true, false, &imported_credit_card, &imported_credit_card_matches_masked_server_credit_card)); EXPECT_FALSE(imported_credit_card); EXPECT_FALSE(imported_credit_card_matches_masked_server_credit_card); @@ -4553,7 +4887,7 @@ TEST_F(PersonalDataManagerTest, std::unique_ptr<CreditCard> imported_credit_card; bool imported_credit_card_matches_masked_server_credit_card; EXPECT_FALSE(personal_data_->ImportFormData( - form_structure, false, &imported_credit_card, + form_structure, true, false, &imported_credit_card, &imported_credit_card_matches_masked_server_credit_card)); EXPECT_FALSE(imported_credit_card); EXPECT_FALSE(imported_credit_card_matches_masked_server_credit_card); @@ -4600,7 +4934,7 @@ TEST_F(PersonalDataManagerTest, std::unique_ptr<CreditCard> imported_credit_card; bool imported_credit_card_matches_masked_server_credit_card; EXPECT_FALSE(personal_data_->ImportFormData( - form_structure, false, &imported_credit_card, + form_structure, true, false, &imported_credit_card, &imported_credit_card_matches_masked_server_credit_card)); EXPECT_FALSE(imported_credit_card); EXPECT_FALSE(imported_credit_card_matches_masked_server_credit_card); @@ -4648,7 +4982,7 @@ TEST_F(PersonalDataManagerTest, std::unique_ptr<CreditCard> imported_credit_card; bool imported_credit_card_matches_masked_server_credit_card; EXPECT_FALSE(personal_data_->ImportFormData( - form_structure, false, &imported_credit_card, + form_structure, true, false, &imported_credit_card, &imported_credit_card_matches_masked_server_credit_card)); EXPECT_FALSE(imported_credit_card); EXPECT_FALSE(imported_credit_card_matches_masked_server_credit_card); @@ -6163,6 +6497,268 @@ TEST_F(PersonalDataManagerTest, ApplyDedupingRoutine_OncePerVersion) { EXPECT_EQ(2U, personal_data_->GetProfiles().size()); } +// Tests that DeleteDisusedAddresses is not run if the feature is disabled. +TEST_F(PersonalDataManagerTest, DeleteDisusedAddresses_DoNothingWhenDisabled) { + // Make sure feature is disabled by default. + EXPECT_FALSE(base::FeatureList::IsEnabled(kAutofillDeleteDisusedAddresses)); + + CreateDeletableDisusedProfile(); + + // DeleteDisusedCreditCards should return false to indicate it was not run. + EXPECT_FALSE(personal_data_->DeleteDisusedAddresses()); + + personal_data_->Refresh(); + + EXPECT_EQ(1U, personal_data_->GetProfiles().size()); +} + +// Tests that DeleteDisusedAddresses is not run a second time on the same +// major version. +TEST_F(PersonalDataManagerTest, DeleteDisusedAddresses_OncePerVersion) { + // Enable the feature. + base::test::ScopedFeatureList scoped_features; + scoped_features.InitAndEnableFeature(kAutofillDeleteDisusedAddresses); + + CreateDeletableDisusedProfile(); + + EXPECT_TRUE(personal_data_->DeleteDisusedAddresses()); + WaitForOnPersonalDataChanged(); + + EXPECT_EQ(0U, personal_data_->GetProfiles().size()); + + // Add the profile back. + CreateDeletableDisusedProfile(); + + // DeleteDisusedAddresses should return false to indicate it was not run. + EXPECT_FALSE(personal_data_->DeleteDisusedAddresses()); + + personal_data_->Refresh(); + + EXPECT_EQ(1U, personal_data_->GetProfiles().size()); +} + +// Tests that DeleteDisusedAddresses only deletes the addresses that are +// supposed to be deleted. +TEST_F(PersonalDataManagerTest, + DeleteDisusedAddresses_DeleteDesiredAddressesOnly) { + // Enable the feature. + base::test::ScopedFeatureList scoped_features; + scoped_features.InitAndEnableFeature(kAutofillDeleteDisusedAddresses); + + auto now = AutofillClock::Now(); + + // Create unverified/disused/not-used-by-valid-credit-card + // address(deletable). + AutofillProfile profile0(base::GenerateGUID(), "https://www.example.com"); + test::SetProfileInfo(&profile0, "Alice", "", "Delete", "", "ACME", + "1234 Evergreen Terrace", "Bld. 6", "Springfield", "IL", + "32801", "US", "15151231234"); + profile0.set_use_date(now - base::TimeDelta::FromDays(400)); + personal_data_->AddProfile(profile0); + + // Create unverified/disused/used-by-expired-credit-card address(deletable). + AutofillProfile profile1(base::GenerateGUID(), "https://www.example.com"); + test::SetProfileInfo(&profile1, "Bob", "", "Delete", "", "ACME", + "1234 Evergreen Terrace", "Bld. 7", "Springfield", "IL", + "32801", "US", "15151231234"); + profile1.set_use_date(now - base::TimeDelta::FromDays(400)); + CreditCard credit_card0(base::GenerateGUID(), "https://www.example.com"); + test::SetCreditCardInfo(&credit_card0, "Bob", + "5105105105105100" /* Mastercard */, "04", "1999", + "1"); + credit_card0.set_use_date(now - base::TimeDelta::FromDays(400)); + credit_card0.set_billing_address_id(profile1.guid()); + personal_data_->AddProfile(profile1); + personal_data_->AddCreditCard(credit_card0); + + // Create verified/disused/not-used-by-valid-credit-card address(not + // deletable). + AutofillProfile profile2(base::GenerateGUID(), "https://www.example.com"); + test::SetProfileInfo(&profile2, "Charlie", "", "Keep", "", "ACME", + "1234 Evergreen Terrace", "Bld. 8", "Springfield", "IL", + "32801", "US", "15151231234"); + profile2.set_origin(kSettingsOrigin); + profile2.set_use_date(now - base::TimeDelta::FromDays(400)); + personal_data_->AddProfile(profile2); + + // Create unverified/recently-used/not-used-by-valid-credit-card address(not + // deletable). + AutofillProfile profile3(base::GenerateGUID(), "https://www.example.com"); + test::SetProfileInfo(&profile3, "Dave", "", "Keep", "", "ACME", + "1234 Evergreen Terrace", "Bld. 9", "Springfield", "IL", + "32801", "US", "15151231234"); + profile3.set_use_date(now - base::TimeDelta::FromDays(4)); + personal_data_->AddProfile(profile3); + + // Create unverified/disused/used-by-valid-credit-card address(not deletable). + AutofillProfile profile4(base::GenerateGUID(), "https://www.example.com"); + test::SetProfileInfo(&profile4, "Emma", "", "Keep", "", "ACME", + "1234 Evergreen Terrace", "Bld. 10", "Springfield", "IL", + "32801", "US", "15151231234"); + profile4.set_use_date(now - base::TimeDelta::FromDays(400)); + CreditCard credit_card1(CreditCard::MASKED_SERVER_CARD, "c987"); + test::SetCreditCardInfo(&credit_card1, "Emma", "6543", "01", "2999", "1"); + credit_card1.SetNetworkForMaskedCard(kVisaCard); + credit_card1.set_billing_address_id(profile4.guid()); + credit_card1.set_use_date(now - base::TimeDelta::FromDays(1)); + personal_data_->AddProfile(profile4); + personal_data_->AddCreditCard(credit_card1); + + WaitForOnPersonalDataChanged(); + + EXPECT_EQ(5U, personal_data_->GetProfiles().size()); + EXPECT_EQ(2U, personal_data_->GetCreditCards().size()); + + // DeleteDisusedAddresses should return true. + EXPECT_TRUE(personal_data_->DeleteDisusedAddresses()); + WaitForOnPersonalDataChanged(); + + EXPECT_EQ(3U, personal_data_->GetProfiles().size()); + EXPECT_EQ(2U, personal_data_->GetCreditCards().size()); + EXPECT_EQ(base::UTF8ToUTF16("Keep"), + personal_data_->GetProfiles()[0]->GetRawInfo(NAME_LAST)); + EXPECT_EQ(base::UTF8ToUTF16("Keep"), + personal_data_->GetProfiles()[1]->GetRawInfo(NAME_LAST)); + EXPECT_EQ(base::UTF8ToUTF16("Keep"), + personal_data_->GetProfiles()[2]->GetRawInfo(NAME_LAST)); +} + +// Tests that DeleteDisusedCreditCards is not run if the feature is disabled. +TEST_F(PersonalDataManagerTest, + DeleteDisusedCreditCards_DoNothingWhenDisabled) { + // Make sure feature is disabled by default. + EXPECT_FALSE(base::FeatureList::IsEnabled(kAutofillDeleteDisusedCreditCards)); + + CreateDeletableExpiredAndDisusedCreditCard(); + + // DeleteDisusedCreditCards should return false to indicate it was not run. + EXPECT_FALSE(personal_data_->DeleteDisusedCreditCards()); + + personal_data_->Refresh(); + + EXPECT_EQ(1U, personal_data_->GetCreditCards().size()); +} + +// Tests that DeleteDisusedCreditCards is not run a second time on the same +// major version. +TEST_F(PersonalDataManagerTest, DeleteDisusedCreditCards_OncePerVersion) { + // Enable the feature. + base::test::ScopedFeatureList scoped_features; + scoped_features.InitAndEnableFeature(kAutofillDeleteDisusedCreditCards); + + CreateDeletableExpiredAndDisusedCreditCard(); + + // The deletion should be run a first time. + EXPECT_TRUE(personal_data_->DeleteDisusedCreditCards()); + WaitForOnPersonalDataChanged(); + + // The profiles should have been deleted. + EXPECT_EQ(0U, personal_data_->GetCreditCards().size()); + + // Add the card back. + CreateDeletableExpiredAndDisusedCreditCard(); + + // The cleanup should not be run. + EXPECT_FALSE(personal_data_->DeleteDisusedCreditCards()); + + // The card should still be present. + EXPECT_EQ(1U, personal_data_->GetCreditCards().size()); +} + +// Tests that DeleteDisusedCreditCards deletes desired credit cards only. +TEST_F(PersonalDataManagerTest, + DeleteDisusedCreditCards_OnlyDeleteExpiredDisusedLocalCards) { + // Enable the feature. + base::test::ScopedFeatureList scoped_features; + scoped_features.InitAndEnableFeature(kAutofillDeleteDisusedCreditCards); + + const char kHistogramName[] = "Autofill.CreditCardsDeletedForDisuse"; + auto now = AutofillClock::Now(); + + // Create a recently used local card, it is expected to remain. + CreditCard credit_card1(base::GenerateGUID(), "https://www.example.com"); + test::SetCreditCardInfo(&credit_card1, "Alice", + "378282246310005" /* American Express */, "04", + "2999", "1"); + credit_card1.set_use_date(now - base::TimeDelta::FromDays(4)); + + // Create a local card that was expired 400 days ago, but recently used. + // It is expected to remain. + CreditCard credit_card2(base::GenerateGUID(), "https://www.example.com"); + test::SetCreditCardInfo(&credit_card2, "Bob", + "378282246310006" /* American Express */, "04", + "1999", "1"); + credit_card2.set_use_date(now - base::TimeDelta::FromDays(4)); + + // Create a local card expired recently, and last used 400 days ago. + // It is expected to remain. + CreditCard credit_card3(base::GenerateGUID(), "https://www.example.com"); + test::SetCreditCardInfo(&credit_card3, "Clyde", "4111111111111111" /* Visa */, + "04", "2017", "1"); + credit_card3.set_use_date(now - base::TimeDelta::FromDays(400)); + + // Create a local card expired 400 days ago, and last used 400 days ago. + // It is expected to be deleted. + CreditCard credit_card4(base::GenerateGUID(), "https://www.example.com"); + test::SetCreditCardInfo(&credit_card4, "David", + "5105105105105100" /* Mastercard */, "04", "1999", + "1"); + credit_card4.set_use_date(now - base::TimeDelta::FromDays(400)); + personal_data_->AddCreditCard(credit_card1); + personal_data_->AddCreditCard(credit_card2); + personal_data_->AddCreditCard(credit_card3); + personal_data_->AddCreditCard(credit_card4); + + // Create a unmasked server card expired 400 days ago, and last used 400 + // days ago. + // It is expected to remain because we do not delete server cards. + CreditCard credit_card5(CreditCard::FULL_SERVER_CARD, "c789"); + test::SetCreditCardInfo(&credit_card5, "Emma", "4234567890123456" /* Visa */, + "04", "1999", "1"); + credit_card5.set_use_date(now - base::TimeDelta::FromDays(400)); + + // Create masked server card expired 400 days ago, and last used 400 days ago. + // It is expected to remain because we do not delete server cards. + CreditCard credit_card6(CreditCard::MASKED_SERVER_CARD, "c987"); + test::SetCreditCardInfo(&credit_card6, "Frank", "6543", "01", "1998", "1"); + credit_card6.set_use_date(now - base::TimeDelta::FromDays(400)); + credit_card6.SetNetworkForMaskedCard(kVisaCard); + + // Save the server cards and set used_date to desired dates. + std::vector<CreditCard> server_cards; + server_cards.push_back(credit_card5); + server_cards.push_back(credit_card6); + test::SetServerCreditCards(autofill_table_, server_cards); + personal_data_->UpdateServerCardMetadata(credit_card5); + personal_data_->UpdateServerCardMetadata(credit_card6); + + WaitForOnPersonalDataChanged(); + EXPECT_EQ(6U, personal_data_->GetCreditCards().size()); + + // Setup histograms capturing. + base::HistogramTester histogram_tester; + + // DeleteDisusedCreditCards should return true to indicate it was run. + EXPECT_TRUE(personal_data_->DeleteDisusedCreditCards()); + + // Wait for the data to be refreshed. + WaitForOnPersonalDataChanged(); + + EXPECT_EQ(5U, personal_data_->GetCreditCards().size()); + std::unordered_set<base::string16> expectedToRemain = { + base::UTF8ToUTF16("Alice"), base::UTF8ToUTF16("Bob"), + base::UTF8ToUTF16("Clyde"), base::UTF8ToUTF16("Emma"), + base::UTF8ToUTF16("Frank")}; + for (auto* card : personal_data_->GetCreditCards()) { + EXPECT_NE(expectedToRemain.end(), + expectedToRemain.find(card->GetRawInfo(CREDIT_CARD_NAME_FULL))); + } + + // Verify histograms are logged. + histogram_tester.ExpectTotalCount(kHistogramName, 1); + histogram_tester.ExpectBucketCount(kHistogramName, 1, 1); +} + // Tests that a new local profile is created if no existing one is a duplicate // of the server address. Also tests that the billing address relationship was // transferred to the converted address. @@ -6222,7 +6818,7 @@ TEST_F(PersonalDataManagerTest, // Make sure everything is set up correctly. personal_data_->Refresh(); WaitForOnPersonalDataChanged(); - EXPECT_EQ(1U, personal_data_->web_profiles().size()); + EXPECT_EQ(1U, personal_data_->GetProfiles().size()); EXPECT_EQ(1U, personal_data_->GetServerProfiles().size()); EXPECT_EQ(2U, personal_data_->GetCreditCards().size()); @@ -6237,7 +6833,7 @@ TEST_F(PersonalDataManagerTest, WaitForOnPersonalDataChanged(); // The Wallet address should have been added as a new local profile. - EXPECT_EQ(2U, personal_data_->web_profiles().size()); + EXPECT_EQ(2U, personal_data_->GetProfiles().size()); EXPECT_EQ(1U, personal_data_->GetServerProfiles().size()); histogram_tester.ExpectUniqueSample("Autofill.WalletAddressConversionType", AutofillMetrics::CONVERTED_ADDRESS_ADDED, @@ -6327,7 +6923,7 @@ TEST_F(PersonalDataManagerTest, // Make sure everything is set up correctly. personal_data_->Refresh(); WaitForOnPersonalDataChanged(); - EXPECT_EQ(1U, personal_data_->web_profiles().size()); + EXPECT_EQ(1U, personal_data_->GetProfiles().size()); EXPECT_EQ(1U, personal_data_->GetServerProfiles().size()); EXPECT_EQ(2U, personal_data_->GetCreditCards().size()); @@ -6342,7 +6938,7 @@ TEST_F(PersonalDataManagerTest, WaitForOnPersonalDataChanged(); // The Wallet address should have been merged with the existing local profile. - EXPECT_EQ(1U, personal_data_->web_profiles().size()); + EXPECT_EQ(1U, personal_data_->GetProfiles().size()); EXPECT_EQ(1U, personal_data_->GetServerProfiles().size()); histogram_tester.ExpectUniqueSample("Autofill.WalletAddressConversionType", AutofillMetrics::CONVERTED_ADDRESS_MERGED, @@ -6399,7 +6995,7 @@ TEST_F(PersonalDataManagerTest, // Make sure everything is set up correctly. personal_data_->Refresh(); WaitForOnPersonalDataChanged(); - EXPECT_EQ(0U, personal_data_->web_profiles().size()); + EXPECT_EQ(0U, personal_data_->GetProfiles().size()); EXPECT_EQ(1U, personal_data_->GetServerProfiles().size()); /////////////////////////////////////////////////////////////////////// @@ -6418,7 +7014,7 @@ TEST_F(PersonalDataManagerTest, WaitForOnPersonalDataChanged(); // There should be no local profiles added. - EXPECT_EQ(0U, personal_data_->web_profiles().size()); + EXPECT_EQ(0U, personal_data_->GetProfiles().size()); EXPECT_EQ(1U, personal_data_->GetServerProfiles().size()); } @@ -6495,7 +7091,7 @@ TEST_F( // Make sure everything is set up correctly. personal_data_->Refresh(); WaitForOnPersonalDataChanged(); - EXPECT_EQ(1U, personal_data_->web_profiles().size()); + EXPECT_EQ(1U, personal_data_->GetProfiles().size()); EXPECT_EQ(2U, personal_data_->GetServerProfiles().size()); EXPECT_EQ(2U, personal_data_->GetCreditCards().size()); @@ -6511,7 +7107,7 @@ TEST_F( // The first Wallet address should have been added as a new local profile and // the second one should have merged with the first. - EXPECT_EQ(2U, personal_data_->web_profiles().size()); + EXPECT_EQ(2U, personal_data_->GetProfiles().size()); EXPECT_EQ(2U, personal_data_->GetServerProfiles().size()); histogram_tester.ExpectBucketCount("Autofill.WalletAddressConversionType", AutofillMetrics::CONVERTED_ADDRESS_ADDED, @@ -6597,7 +7193,7 @@ TEST_F( WaitForOnPersonalDataChanged(); // The Wallet address should have been converted to a new local profile. - EXPECT_EQ(1U, personal_data_->web_profiles().size()); + EXPECT_EQ(1U, personal_data_->GetProfiles().size()); // The conversion should be recorded in the Wallet address. EXPECT_TRUE(personal_data_->GetServerProfiles().back()->has_converted()); @@ -6622,7 +7218,7 @@ TEST_F( // Make sure everything is set up correctly. personal_data_->Refresh(); WaitForOnPersonalDataChanged(); - EXPECT_EQ(1U, personal_data_->web_profiles().size()); + EXPECT_EQ(1U, personal_data_->GetProfiles().size()); EXPECT_EQ(2U, personal_data_->GetCreditCards().size()); /////////////////////////////////////////////////////////////////////// @@ -6924,4 +7520,335 @@ TEST_F(PersonalDataManagerTest, RemoveProfilesNotUsedSinceTimestamp) { } } +TEST_F(PersonalDataManagerTest, LogStoredCreditCardMetrics) { + EnableWalletCardImport(); + ASSERT_EQ(0U, personal_data_->GetCreditCards().size()); + + // Helper timestamps for setting up the test data. + base::Time now = AutofillClock::Now(); + base::Time one_month_ago = now - base::TimeDelta::FromDays(30); + base::Time::Exploded now_exploded; + base::Time::Exploded one_month_ago_exploded; + now.LocalExplode(&now_exploded); + one_month_ago.LocalExplode(&one_month_ago_exploded); + + std::vector<CreditCard> server_cards; + server_cards.reserve(10); + + // Create in-use and in-disuse cards of each record type. + const std::vector<CreditCard::RecordType> record_types{ + CreditCard::LOCAL_CARD, CreditCard::MASKED_SERVER_CARD, + CreditCard::FULL_SERVER_CARD}; + for (auto record_type : record_types) { + // Create a card that's still in active use. + CreditCard card_in_use = test::GetRandomCreditCard(record_type); + card_in_use.set_use_date(now - base::TimeDelta::FromDays(30)); + card_in_use.set_use_count(10); + + // Create a card that's not in active use. + CreditCard card_in_disuse = test::GetRandomCreditCard(record_type); + card_in_disuse.SetExpirationYear(one_month_ago_exploded.year); + card_in_disuse.SetExpirationMonth(one_month_ago_exploded.month); + card_in_disuse.set_use_date(now - base::TimeDelta::FromDays(200)); + card_in_disuse.set_use_count(10); + + // Add the cards to the personal data manager in the appropriate way. + if (record_type == CreditCard::LOCAL_CARD) { + personal_data_->AddCreditCard(card_in_use); + personal_data_->AddCreditCard(card_in_disuse); + } else { + server_cards.push_back(std::move(card_in_use)); + server_cards.push_back(std::move(card_in_disuse)); + } + } + + test::SetServerCreditCards(autofill_table_, server_cards); + + // test::SetServerCreditCards modifies the metadata (use_count and use_date) + // of unmasked cards. Reset the server card metadata to match the data set + // up above. + for (const auto& card : server_cards) + autofill_table_->UpdateServerCardMetadata(card); + + personal_data_->Refresh(); + WaitForOnPersonalDataChanged(); + + ASSERT_EQ(6U, personal_data_->GetCreditCards().size()); + + // Reload the database, which will log the stored profile counts. + base::HistogramTester histogram_tester; + ResetPersonalDataManager(USER_MODE_NORMAL); + + ASSERT_EQ(6U, personal_data_->GetCreditCards().size()); + + // Validate the basic count metrics for both local and server cards. Deep + // validation of the metrics is done in: + // AutofillMetricsTest::LogStoredCreditCardMetrics + histogram_tester.ExpectTotalCount("Autofill.StoredCreditCardCount", 1); + histogram_tester.ExpectTotalCount("Autofill.StoredCreditCardCount.Local", 1); + histogram_tester.ExpectTotalCount("Autofill.StoredCreditCardCount.Server", 1); + histogram_tester.ExpectTotalCount( + "Autofill.StoredCreditCardCount.Server.Masked", 1); + histogram_tester.ExpectTotalCount( + "Autofill.StoredCreditCardCount.Server.Unmasked", 1); + histogram_tester.ExpectBucketCount("Autofill.StoredCreditCardCount", 6, 1); + histogram_tester.ExpectBucketCount("Autofill.StoredCreditCardCount.Local", 2, + 1); + histogram_tester.ExpectBucketCount("Autofill.StoredCreditCardCount.Server", 4, + 1); + histogram_tester.ExpectBucketCount( + "Autofill.StoredCreditCardCount.Server.Masked", 2, 1); + histogram_tester.ExpectBucketCount( + "Autofill.StoredCreditCardCount.Server.Unmasked", 2, 1); +} + +TEST_F(PersonalDataManagerTest, RemoveExpiredCreditCardsNotUsedSinceTimestamp) { + const char kHistogramName[] = "Autofill.CreditCardsSuppressedForDisuse"; + const base::Time kNow = AutofillClock::Now(); + constexpr size_t kNumCards = 10; + + // We construct a card vector as below, number indicate days of last used + // from |kNow|: + // [30, 90, 150, 210, 270, 0, 60, 120, 180, 240] + // |expires at 2999 |, |expired at 2001 | + std::vector<CreditCard> all_card_data; + std::vector<CreditCard*> all_card_ptrs; + all_card_data.reserve(kNumCards); + all_card_ptrs.reserve(kNumCards); + for (size_t i = 0; i < kNumCards; ++i) { + constexpr base::TimeDelta k30Days = base::TimeDelta::FromDays(30); + all_card_data.emplace_back(base::GenerateGUID(), "https://example.com"); + if (i < 5) { + all_card_data.back().set_use_date(kNow - (i + i + 1) * k30Days); + test::SetCreditCardInfo(&all_card_data.back(), "Clyde Barrow", + "378282246310005" /* American Express */, "04", + "2999", "1"); + } else { + all_card_data.back().set_use_date(kNow - (i + i - 10) * k30Days); + test::SetCreditCardInfo(&all_card_data.back(), "John Dillinger", + "4234567890123456" /* Visa */, "04", "2001", "1"); + } + all_card_ptrs.push_back(&all_card_data.back()); + } + + // Verify that only expired disused card are removed. Note that only the last + // two cards have use dates more than 175 days ago and are expired. + { + // Create a working copy of the card pointers. + std::vector<CreditCard*> cards(all_card_ptrs); + + // The first 8 are either not expired or having use dates more recent + // than 175 days ago. + std::vector<CreditCard*> expected_cards(cards.begin(), cards.begin() + 8); + + // Filter the cards while capturing histograms. + base::HistogramTester histogram_tester; + PersonalDataManager::RemoveExpiredCreditCardsNotUsedSinceTimestamp( + kNow, kNow - base::TimeDelta::FromDays(175), &cards); + + // Validate that we get the expected filtered cards and histograms. + EXPECT_EQ(expected_cards, cards); + histogram_tester.ExpectTotalCount(kHistogramName, 1); + histogram_tester.ExpectBucketCount(kHistogramName, 2, 1); + } + + // Reverse the card order and verify that only expired and disused cards + // are removed. Note that the first three cards, post reversal, + // have use dates more then 115 days ago. + { + // Create a reversed working copy of the card pointers. + std::vector<CreditCard*> cards(all_card_ptrs.rbegin(), + all_card_ptrs.rend()); + + // The last 7 cards have use dates more recent than 115 days ago. + std::vector<CreditCard*> expected_cards(cards.begin() + 3, cards.end()); + + // Filter the cards while capturing histograms. + base::HistogramTester histogram_tester; + PersonalDataManager::RemoveExpiredCreditCardsNotUsedSinceTimestamp( + kNow, kNow - base::TimeDelta::FromDays(115), &cards); + + // Validate that we get the expected filtered cards and histograms. + EXPECT_EQ(expected_cards, cards); + histogram_tester.ExpectTotalCount(kHistogramName, 1); + histogram_tester.ExpectBucketCount(kHistogramName, 3, 1); + } + // Randomize the card order and validate that the filtered list retains + // that order. Note that the three cards have use dates more then 115 + // days ago and are expired. + { + // A handy constant. + const base::Time k115DaysAgo = kNow - base::TimeDelta::FromDays(115); + + // Created a shuffled master copy of the card pointers. + std::vector<CreditCard*> shuffled_cards(all_card_ptrs); + std::random_shuffle(shuffled_cards.begin(), shuffled_cards.end()); + + // Copy the shuffled card pointer collections to use as the working + // set. + std::vector<CreditCard*> cards(shuffled_cards); + + // Filter the cards while capturing histograms. + base::HistogramTester histogram_tester; + PersonalDataManager::RemoveExpiredCreditCardsNotUsedSinceTimestamp( + kNow, k115DaysAgo, &cards); + + // Validate that we have the right cards. Iterate of the the shuffled + // master copy and the filtered copy at the same time. making sure that + // the elements in the filtered copy occur in the same order as the shuffled + // master. Along the way, validate that the elements in and out of the + // filtered copy have appropriate use dates and expiration states. + EXPECT_EQ(7u, cards.size()); + auto it = shuffled_cards.begin(); + for (const CreditCard* card : cards) { + for (; it != shuffled_cards.end() && (*it) != card; ++it) { + EXPECT_LT((*it)->use_date(), k115DaysAgo); + ASSERT_TRUE((*it)->IsExpired(kNow)); + } + ASSERT_TRUE(it != shuffled_cards.end()); + ASSERT_TRUE(card->use_date() > k115DaysAgo || !card->IsExpired(kNow)); + ++it; + } + for (; it != shuffled_cards.end(); ++it) { + EXPECT_LT((*it)->use_date(), k115DaysAgo); + ASSERT_TRUE((*it)->IsExpired(kNow)); + } + + // Validate the histograms. + histogram_tester.ExpectTotalCount(kHistogramName, 1); + histogram_tester.ExpectBucketCount(kHistogramName, 3, 1); + } + + // Verify all cards are retained if they're sufficiently recently + // used. + { + // Create a working copy of the card pointers. + std::vector<CreditCard*> cards(all_card_ptrs); + + // Filter the cards while capturing histograms. + base::HistogramTester histogram_tester; + PersonalDataManager::RemoveExpiredCreditCardsNotUsedSinceTimestamp( + kNow, kNow - base::TimeDelta::FromDays(720), &cards); + + // Validate that we get the expected filtered cards and histograms. + EXPECT_EQ(all_card_ptrs, cards); + histogram_tester.ExpectTotalCount(kHistogramName, 1); + histogram_tester.ExpectBucketCount(kHistogramName, 0, 1); + } + + // Verify all cards are removed if they're all disused and expired. + { + // Create a working copy of the card pointers. + std::vector<CreditCard*> cards(all_card_ptrs); + for (auto it = all_card_ptrs.begin(); it < all_card_ptrs.end(); it++) { + (*it)->SetExpirationYear(2001); + } + + // Filter the cards while capturing histograms. + base::HistogramTester histogram_tester; + PersonalDataManager::RemoveExpiredCreditCardsNotUsedSinceTimestamp( + kNow, kNow + base::TimeDelta::FromDays(1), &cards); + + // Validate that we get the expected filtered cards and histograms. + EXPECT_TRUE(cards.empty()); + histogram_tester.ExpectTotalCount(kHistogramName, 1); + histogram_tester.ExpectBucketCount(kHistogramName, kNumCards, 1); + } +} + +TEST_F(PersonalDataManagerTest, CreateDataForTest) { + // By default, the creation of test data is disabled. + ResetPersonalDataManager(USER_MODE_NORMAL); + ASSERT_EQ(0U, personal_data_->GetProfiles().size()); + ASSERT_EQ(0U, personal_data_->GetCreditCards().size()); + + // Turn on test data creation for the rest of this scope. + base::test::ScopedFeatureList enabled; + enabled.InitAndEnableFeature(kAutofillCreateDataForTest); + + // Reloading the test profile should result in test data being created. + ResetPersonalDataManager(USER_MODE_NORMAL); + const std::vector<AutofillProfile*> addresses = personal_data_->GetProfiles(); + const std::vector<CreditCard*> credit_cards = + personal_data_->GetCreditCards(); + ASSERT_EQ(3U, addresses.size()); + ASSERT_EQ(3U, credit_cards.size()); + + const base::Time disused_threshold = + AutofillClock::Now() - base::TimeDelta::FromDays(180); + const base::Time deletion_threshold = + AutofillClock::Now() - base::TimeDelta::FromDays(395); + + // Verify that there was a valid address created. + { + auto it = std::find_if( + addresses.begin(), addresses.end(), [this](const AutofillProfile* p) { + return p->GetInfo(NAME_FULL, this->personal_data_->app_locale()) == + base::UTF8ToUTF16("John McTester"); + }); + ASSERT_TRUE(it != addresses.end()); + EXPECT_GT((*it)->use_date(), disused_threshold); + } + + // Verify that there was a disused address created. + { + auto it = std::find_if( + addresses.begin(), addresses.end(), [this](const AutofillProfile* p) { + return p->GetInfo(NAME_FULL, this->personal_data_->app_locale()) == + base::UTF8ToUTF16("Polly Disused"); + }); + ASSERT_TRUE(it != addresses.end()); + EXPECT_LT((*it)->use_date(), disused_threshold); + } + + // Verify that there was a disused deletable address created. + { + auto it = std::find_if( + addresses.begin(), addresses.end(), [this](const AutofillProfile* p) { + return p->GetInfo(NAME_FULL, this->personal_data_->app_locale()) == + base::UTF8ToUTF16("Polly Deletable"); + }); + ASSERT_TRUE(it != addresses.end()); + EXPECT_LT((*it)->use_date(), deletion_threshold); + EXPECT_FALSE((*it)->IsVerified()); + } + + // Verify that there was a valid credit card created. + { + auto it = std::find_if( + credit_cards.begin(), credit_cards.end(), [this](const CreditCard* cc) { + return cc->GetInfo(CREDIT_CARD_NAME_FULL, + this->personal_data_->app_locale()) == + base::UTF8ToUTF16("Alice Testerson"); + }); + ASSERT_TRUE(it != credit_cards.end()); + EXPECT_GT((*it)->use_date(), disused_threshold); + } + + // Verify that there was a disused credit card created. + { + auto it = std::find_if( + credit_cards.begin(), credit_cards.end(), [this](const CreditCard* cc) { + return cc->GetInfo(CREDIT_CARD_NAME_FULL, + this->personal_data_->app_locale()) == + base::UTF8ToUTF16("Bob Disused"); + }); + ASSERT_TRUE(it != credit_cards.end()); + EXPECT_LT((*it)->use_date(), disused_threshold); + } + + // Verify that there was a disused deletable credit card created. + { + auto it = std::find_if( + credit_cards.begin(), credit_cards.end(), [this](const CreditCard* cc) { + return cc->GetInfo(CREDIT_CARD_NAME_FULL, + this->personal_data_->app_locale()) == + base::UTF8ToUTF16("Charlie Deletable"); + }); + ASSERT_TRUE(it != credit_cards.end()); + EXPECT_LT((*it)->use_date(), deletion_threshold); + EXPECT_TRUE((*it)->IsExpired(deletion_threshold)); + } +} + } // namespace autofill diff --git a/chromium/components/autofill/core/browser/phone_email_validation_util.cc b/chromium/components/autofill/core/browser/phone_email_validation_util.cc index 72d0b2781ac..ab81829b22f 100644 --- a/chromium/components/autofill/core/browser/phone_email_validation_util.cc +++ b/chromium/components/autofill/core/browser/phone_email_validation_util.cc @@ -23,10 +23,9 @@ namespace phone_email_validation_util { AutofillProfile::ValidityState ValidateEmailAddress( const base::string16& email) { - if (email.empty()) { - // Not every profile needs an email address. - return AutofillProfile::VALID; - } + if (email.empty()) + return AutofillProfile::EMPTY; + return (autofill::IsValidEmailAddress(email) ? AutofillProfile::VALID : AutofillProfile::INVALID); } @@ -34,10 +33,9 @@ AutofillProfile::ValidityState ValidateEmailAddress( AutofillProfile::ValidityState ValidatePhoneNumber( const std::string& phone_number, const std::string& country_code) { - if (phone_number.empty()) { - // Every profile needs a phone number. - return AutofillProfile::INVALID; - } + if (phone_number.empty()) + return AutofillProfile::EMPTY; + if (!base::ContainsValue(CountryDataMap::GetInstance()->country_codes(), country_code)) { // If the country code is not in the database, the phone number cannot be @@ -51,19 +49,22 @@ AutofillProfile::ValidityState ValidatePhoneNumber( } AutofillProfile::ValidityState ValidatePhoneAndEmail(AutofillProfile* profile) { - if (!profile) - return AutofillProfile::UNVALIDATED; + DCHECK(profile); AutofillProfile::ValidityState phone_validity = ValidatePhoneNumber( base::UTF16ToUTF8(profile->GetRawInfo(PHONE_HOME_WHOLE_NUMBER)), base::UTF16ToUTF8(profile->GetRawInfo(ADDRESS_HOME_COUNTRY))); - profile->SetValidityState(PHONE_HOME_WHOLE_NUMBER, phone_validity); - profile->SetValidityState( - EMAIL_ADDRESS, ValidateEmailAddress(profile->GetRawInfo(EMAIL_ADDRESS))); + AutofillProfile::ValidityState email_validity = + ValidateEmailAddress(profile->GetRawInfo(EMAIL_ADDRESS)); + profile->SetValidityState(EMAIL_ADDRESS, email_validity); - return phone_validity; // payment request doesn't care about email1 validity. + if (phone_validity == AutofillProfile::VALID && + email_validity == AutofillProfile::VALID) { + return AutofillProfile::VALID; + } + return AutofillProfile::INVALID; } } // namespace phone_email_validation_util diff --git a/chromium/components/autofill/core/browser/phone_email_validation_util_unittest.cc b/chromium/components/autofill/core/browser/phone_email_validation_util_unittest.cc index 0060acc79c3..9340519eaa0 100644 --- a/chromium/components/autofill/core/browser/phone_email_validation_util_unittest.cc +++ b/chromium/components/autofill/core/browser/phone_email_validation_util_unittest.cc @@ -27,10 +27,6 @@ class AutofillPhoneValidationTest : public testing::Test { DISALLOW_COPY_AND_ASSIGN(AutofillPhoneValidationTest); }; -TEST_F(AutofillPhoneValidationTest, ValidateNULLProfile) { - EXPECT_EQ(AutofillProfile::UNVALIDATED, ValidatePhoneAndEmailTest(nullptr)); -} - TEST_F(AutofillPhoneValidationTest, ValidateFullValidProfile) { // This is a full valid profile: // Country Code: "CA", Phone Number: "15141112233", @@ -43,12 +39,10 @@ TEST_F(AutofillPhoneValidationTest, ValidateFullValidProfile) { } TEST_F(AutofillPhoneValidationTest, ValidateEmptyPhoneNumber) { - // This is a profile with empty phone number. Since phone number field is - // always required, it is considered as invalid. AutofillProfile profile(autofill::test::GetFullValidProfile()); profile.SetRawInfo(PHONE_HOME_WHOLE_NUMBER, base::string16()); EXPECT_EQ(AutofillProfile::INVALID, ValidatePhoneAndEmailTest(&profile)); - EXPECT_EQ(AutofillProfile::INVALID, + EXPECT_EQ(AutofillProfile::EMPTY, profile.GetValidityState(PHONE_HOME_WHOLE_NUMBER)); EXPECT_EQ(AutofillProfile::VALID, profile.GetValidityState(EMAIL_ADDRESS)); } @@ -59,7 +53,7 @@ TEST_F(AutofillPhoneValidationTest, ValidateValidPhone_CountryCodeNotExist) { const std::string country_code = "PP"; AutofillProfile profile(autofill::test::GetFullValidProfile()); profile.SetRawInfo(ADDRESS_HOME_COUNTRY, base::UTF8ToUTF16(country_code)); - EXPECT_EQ(AutofillProfile::UNVALIDATED, ValidatePhoneAndEmailTest(&profile)); + EXPECT_EQ(AutofillProfile::INVALID, ValidatePhoneAndEmailTest(&profile)); EXPECT_EQ(AutofillProfile::UNVALIDATED, profile.GetValidityState(PHONE_HOME_WHOLE_NUMBER)); EXPECT_EQ(AutofillProfile::VALID, profile.GetValidityState(EMAIL_ADDRESS)); @@ -73,7 +67,7 @@ TEST_F(AutofillPhoneValidationTest, ValidateEmptyPhone_CountryCodeNotExist) { profile.SetRawInfo(ADDRESS_HOME_COUNTRY, base::UTF8ToUTF16(country_code)); profile.SetRawInfo(PHONE_HOME_WHOLE_NUMBER, base::string16()); EXPECT_EQ(AutofillProfile::INVALID, ValidatePhoneAndEmailTest(&profile)); - EXPECT_EQ(AutofillProfile::INVALID, + EXPECT_EQ(AutofillProfile::EMPTY, profile.GetValidityState(PHONE_HOME_WHOLE_NUMBER)); EXPECT_EQ(AutofillProfile::VALID, profile.GetValidityState(EMAIL_ADDRESS)); } @@ -160,33 +154,31 @@ TEST_F(AutofillPhoneValidationTest, ValidateValidPhoneNumber) { } TEST_F(AutofillPhoneValidationTest, ValidateEmptyEmailAddress) { - // This is a profile with empty email address. Since email field is - // not required, it is considered as valid. AutofillProfile profile(autofill::test::GetFullValidProfile()); profile.SetRawInfo(EMAIL_ADDRESS, base::string16()); - EXPECT_EQ(AutofillProfile::VALID, ValidatePhoneAndEmailTest(&profile)); + EXPECT_EQ(AutofillProfile::INVALID, ValidatePhoneAndEmailTest(&profile)); EXPECT_EQ(AutofillProfile::VALID, profile.GetValidityState(PHONE_HOME_WHOLE_NUMBER)); - EXPECT_EQ(AutofillProfile::VALID, profile.GetValidityState(EMAIL_ADDRESS)); + EXPECT_EQ(AutofillProfile::EMPTY, profile.GetValidityState(EMAIL_ADDRESS)); } TEST_F(AutofillPhoneValidationTest, ValidateInvalidEmailAddress) { AutofillProfile profile(autofill::test::GetFullValidProfile()); profile.SetRawInfo(EMAIL_ADDRESS, base::ASCIIToUTF16("Hello!")); - EXPECT_EQ(AutofillProfile::VALID, ValidatePhoneAndEmailTest(&profile)); + EXPECT_EQ(AutofillProfile::INVALID, ValidatePhoneAndEmailTest(&profile)); EXPECT_EQ(AutofillProfile::INVALID, profile.GetValidityState(EMAIL_ADDRESS)); profile.SetRawInfo(EMAIL_ADDRESS, base::ASCIIToUTF16("alice.wonderland")); - EXPECT_EQ(AutofillProfile::VALID, ValidatePhoneAndEmailTest(&profile)); + EXPECT_EQ(AutofillProfile::INVALID, ValidatePhoneAndEmailTest(&profile)); EXPECT_EQ(AutofillProfile::INVALID, profile.GetValidityState(EMAIL_ADDRESS)); profile.SetRawInfo(EMAIL_ADDRESS, base::ASCIIToUTF16("alice@")); - EXPECT_EQ(AutofillProfile::VALID, ValidatePhoneAndEmailTest(&profile)); + EXPECT_EQ(AutofillProfile::INVALID, ValidatePhoneAndEmailTest(&profile)); EXPECT_EQ(AutofillProfile::INVALID, profile.GetValidityState(EMAIL_ADDRESS)); profile.SetRawInfo(EMAIL_ADDRESS, base::ASCIIToUTF16("alice@=wonderland.com")); - EXPECT_EQ(AutofillProfile::VALID, ValidatePhoneAndEmailTest(&profile)); + EXPECT_EQ(AutofillProfile::INVALID, ValidatePhoneAndEmailTest(&profile)); EXPECT_EQ(AutofillProfile::INVALID, profile.GetValidityState(EMAIL_ADDRESS)); } diff --git a/chromium/components/autofill/core/browser/phone_number_i18n.cc b/chromium/components/autofill/core/browser/phone_number_i18n.cc index 66fe9faac56..63954a0235a 100644 --- a/chromium/components/autofill/core/browser/phone_number_i18n.cc +++ b/chromium/components/autofill/core/browser/phone_number_i18n.cc @@ -11,15 +11,34 @@ #include "base/strings/string_util.h" #include "base/strings/utf_string_conversions.h" #include "components/autofill/core/browser/autofill_country.h" +#include "components/autofill/core/browser/autofill_data_util.h" +#include "components/autofill/core/browser/autofill_profile.h" +#include "components/autofill/core/browser/validation.h" #include "third_party/libphonenumber/phonenumber_api.h" -using i18n::phonenumbers::PhoneNumber; -using i18n::phonenumbers::PhoneNumberUtil; - namespace autofill { namespace { +using ::i18n::phonenumbers::PhoneNumberUtil; + +// Formats the |phone_number| to the specified |format|. Returns the original +// number if the operation is not possible. +std::string FormatPhoneNumber(const std::string& phone_number, + const std::string& country_code, + PhoneNumberUtil::PhoneNumberFormat format) { + ::i18n::phonenumbers::PhoneNumber parsed_number; + PhoneNumberUtil* phone_number_util = PhoneNumberUtil::GetInstance(); + if (phone_number_util->Parse(phone_number, country_code, &parsed_number) != + PhoneNumberUtil::NO_PARSING_ERROR) { + return phone_number; + } + + std::string formatted_number; + phone_number_util->Format(parsed_number, format, &formatted_number); + return formatted_number; +} + std::string SanitizeRegion(const std::string& region, const std::string& app_locale) { if (region.length() == 2) @@ -29,7 +48,7 @@ std::string SanitizeRegion(const std::string& region, } // Returns true if |phone_number| is valid. -bool IsValidPhoneNumber(const PhoneNumber& phone_number) { +bool IsValidPhoneNumber(const ::i18n::phonenumbers::PhoneNumber& phone_number) { PhoneNumberUtil* phone_util = PhoneNumberUtil::GetInstance(); if (!phone_util->IsPossibleNumber(phone_number)) return false; @@ -52,7 +71,7 @@ bool IsValidPhoneNumber(const PhoneNumber& phone_number) { // whether to format in the national or in the international format, is passed // in explicitly, as |number| might have an implicit country code set, even // though the original input lacked a country code. -void FormatValidatedNumber(const PhoneNumber& number, +void FormatValidatedNumber(const ::i18n::phonenumbers::PhoneNumber& number, const base::string16& country_code, base::string16* formatted_number, base::string16* normalized_number) { @@ -101,11 +120,11 @@ bool ParsePhoneNumber(const base::string16& value, base::string16* city_code, base::string16* number, std::string* inferred_region, - PhoneNumber* i18n_number) { + ::i18n::phonenumbers::PhoneNumber* i18n_number) { country_code->clear(); city_code->clear(); number->clear(); - *i18n_number = PhoneNumber(); + *i18n_number = ::i18n::phonenumbers::PhoneNumber(); std::string number_text(base::UTF16ToUTF8(value)); @@ -150,7 +169,8 @@ bool ParsePhoneNumber(const base::string16& value, // Check if parsed number has a country code that was not inferred from the // region. if (i18n_number->has_country_code() && - i18n_number->country_code_source() != PhoneNumber::FROM_DEFAULT_COUNTRY) { + i18n_number->country_code_source() != + ::i18n::phonenumbers::PhoneNumber::FROM_DEFAULT_COUNTRY) { *country_code = base::UTF8ToUTF16( base::IntToString(i18n_number->country_code())); } @@ -166,7 +186,7 @@ base::string16 NormalizePhoneNumber(const base::string16& value, DCHECK_EQ(2u, region.size()); base::string16 country_code, unused_city_code, unused_number; std::string unused_region; - PhoneNumber phone_number; + ::i18n::phonenumbers::PhoneNumber phone_number; if (!ParsePhoneNumber(value, region, &country_code, &unused_city_code, &unused_number, &unused_region, &phone_number)) { return base::string16(); // Parsing failed - do not store phone. @@ -187,7 +207,7 @@ bool ConstructPhoneNumber(const base::string16& country_code, base::string16 unused_country_code, unused_city_code, unused_number; std::string unused_region; - PhoneNumber phone_number; + ::i18n::phonenumbers::PhoneNumber phone_number; if (!ParsePhoneNumber(country_code + city_code + number, region, &unused_country_code, &unused_city_code, &unused_number, &unused_region, &phone_number)) { @@ -208,14 +228,14 @@ bool PhoneNumbersMatch(const base::string16& number_a, PhoneNumberUtil* phone_util = PhoneNumberUtil::GetInstance(); // Parse phone numbers based on the region - PhoneNumber i18n_number1; + ::i18n::phonenumbers::PhoneNumber i18n_number1; if (phone_util->Parse( base::UTF16ToUTF8(number_a), region.c_str(), &i18n_number1) != PhoneNumberUtil::NO_PARSING_ERROR) { return false; } - PhoneNumber i18n_number2; + ::i18n::phonenumbers::PhoneNumber i18n_number2; if (phone_util->Parse( base::UTF16ToUTF8(number_b), region.c_str(), &i18n_number2) != PhoneNumberUtil::NO_PARSING_ERROR) { @@ -237,6 +257,45 @@ bool PhoneNumbersMatch(const base::string16& number_a, return false; } +base::string16 GetFormattedPhoneNumberForDisplay(const AutofillProfile& profile, + const std::string& locale) { + // Since the "+" is removed for some country's phone numbers, try to add a "+" + // and see if it is a valid phone number for a country. + // Having two "+" in front of a number has no effect on the formatted number. + // The reason for this is international phone numbers for another country. For + // example, without adding a "+", the US number 1-415-123-1234 for an AU + // address would be wrongly formatted as +61 1-415-123-1234 which is invalid. + std::string phone = base::UTF16ToUTF8( + profile.GetInfo(AutofillType(PHONE_HOME_WHOLE_NUMBER), locale)); + std::string tentative_intl_phone = "+" + phone; + + // Always favor the tentative international phone number if it's determined as + // being a valid number. + if (IsValidPhoneNumber( + base::UTF8ToUTF16(tentative_intl_phone), + autofill::data_util::GetCountryCodeWithFallback(&profile, locale))) { + return base::UTF8ToUTF16(FormatPhoneForDisplay( + tentative_intl_phone, + autofill::data_util::GetCountryCodeWithFallback(&profile, locale))); + } + + return base::UTF8ToUTF16(FormatPhoneForDisplay( + phone, + autofill::data_util::GetCountryCodeWithFallback(&profile, locale))); +} + +std::string FormatPhoneForDisplay(const std::string& phone_number, + const std::string& country_code) { + return FormatPhoneNumber(phone_number, country_code, + PhoneNumberUtil::PhoneNumberFormat::INTERNATIONAL); +} + +std::string FormatPhoneForResponse(const std::string& phone_number, + const std::string& country_code) { + return FormatPhoneNumber(phone_number, country_code, + PhoneNumberUtil::PhoneNumberFormat::E164); +} + PhoneObject::PhoneObject(const base::string16& number, const std::string& region) { DCHECK_EQ(2u, region.size()); @@ -246,7 +305,8 @@ PhoneObject::PhoneObject(const base::string16& number, // [ http://crbug.com/100845 ]. Once the bug is fixed, add a DCHECK here to // verify. - std::unique_ptr<PhoneNumber> i18n_number(new PhoneNumber); + std::unique_ptr<::i18n::phonenumbers::PhoneNumber> i18n_number( + new ::i18n::phonenumbers::PhoneNumber); if (ParsePhoneNumber(number, region, &country_code_, &city_code_, &number_, ®ion_, i18n_number.get())) { // The phone number was successfully parsed, so store the parsed version. @@ -298,7 +358,8 @@ PhoneObject& PhoneObject::operator=(const PhoneObject& other) { region_ = other.region_; if (other.i18n_number_.get()) - i18n_number_.reset(new PhoneNumber(*other.i18n_number_)); + i18n_number_.reset( + new ::i18n::phonenumbers::PhoneNumber(*other.i18n_number_)); else i18n_number_.reset(); diff --git a/chromium/components/autofill/core/browser/phone_number_i18n.h b/chromium/components/autofill/core/browser/phone_number_i18n.h index 26e2a1b7f13..5baa44ac031 100644 --- a/chromium/components/autofill/core/browser/phone_number_i18n.h +++ b/chromium/components/autofill/core/browser/phone_number_i18n.h @@ -20,6 +20,8 @@ class PhoneNumber; namespace autofill { +class AutofillProfile; + // Utilities to process, normalize and compare international phone numbers. namespace i18n { @@ -68,6 +70,24 @@ bool PhoneNumbersMatch(const base::string16& number_a, const std::string& region, const std::string& app_locale); +// Returns the phone number from the given |profile| formatted for display. +base::string16 GetFormattedPhoneNumberForDisplay(const AutofillProfile& profile, + const std::string& locale); + +// Formats the given number |phone_number| to +// i18n::phonenumbers::PhoneNumberUtil::PhoneNumberFormat::INTERNATIONAL format +// by using i18n::phonenumbers::PhoneNumberUtil::Format. +std::string FormatPhoneForDisplay(const std::string& phone_number, + const std::string& country_code); + +// Formats the given number |phone_number| to +// i18n::phonenumbers::PhoneNumberUtil::PhoneNumberFormat::E164 format by using +// i18n::phonenumbers::PhoneNumberUtil::Format, as defined in the Payment +// Request spec +// (https://w3c.github.io/browser-payment-api/#paymentrequest-updated-algorithm) +std::string FormatPhoneForResponse(const std::string& phone_number, + const std::string& country_code); + // The cached phone number, does parsing only once, improves performance. class PhoneObject { public: 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 17a24311876..ac791074aca 100644 --- a/chromium/components/autofill/core/browser/phone_number_i18n_unittest.cc +++ b/chromium/components/autofill/core/browser/phone_number_i18n_unittest.cc @@ -2,13 +2,15 @@ // 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/phone_number_i18n.h" + #include <stddef.h> #include "base/macros.h" -#include "base/message_loop/message_loop.h" #include "base/strings/string16.h" #include "base/strings/utf_string_conversions.h" -#include "components/autofill/core/browser/phone_number_i18n.h" +#include "components/autofill/core/browser/autofill_profile.h" +#include "components/autofill/core/browser/field_types.h" #include "testing/gtest/include/gtest/gtest.h" #include "third_party/libphonenumber/phonenumber_api.h" @@ -272,4 +274,189 @@ TEST(PhoneNumberI18NTest, PhoneNumbersMatch) { "en-US")); } +// Tests that the phone numbers are correctly formatted for the Payment +// Response. +TEST(PhoneNumberUtilTest, FormatPhoneForResponse) { + EXPECT_EQ("+15151231234", + i18n::FormatPhoneForResponse("(515) 123-1234", "US")); + EXPECT_EQ("+15151231234", + i18n::FormatPhoneForResponse("(1) 515-123-1234", "US")); + EXPECT_EQ("+33142685300", + i18n::FormatPhoneForResponse("1 42 68 53 00", "FR")); +} + +// Tests that the phone numbers are correctly formatted to display to the user. +TEST(PhoneNumberUtilTest, FormatPhoneForDisplay) { + EXPECT_EQ("+1 515-123-1234", i18n::FormatPhoneForDisplay("5151231234", "US")); + EXPECT_EQ("+33 1 42 68 53 00", + i18n::FormatPhoneForDisplay("142685300", "FR")); +} + +// Test for the GetFormattedPhoneNumberForDisplay method. +struct PhoneNumberFormatCase { + PhoneNumberFormatCase(const char* phone, + const char* country, + const char* expected_format, + const char* locale = "") + : phone(phone), + country(country), + expected_format(expected_format), + locale(locale) {} + + const char* phone; + const char* country; + const char* expected_format; + const char* locale; +}; + +class GetFormattedPhoneNumberForDisplayTest + : public testing::TestWithParam<PhoneNumberFormatCase> {}; + +TEST_P(GetFormattedPhoneNumberForDisplayTest, + GetFormattedPhoneNumberForDisplay) { + AutofillProfile profile; + profile.SetRawInfo(PHONE_HOME_WHOLE_NUMBER, + base::UTF8ToUTF16(GetParam().phone)); + profile.SetRawInfo(ADDRESS_HOME_COUNTRY, + base::UTF8ToUTF16(GetParam().country)); + EXPECT_EQ(GetParam().expected_format, + base::UTF16ToUTF8(i18n::GetFormattedPhoneNumberForDisplay( + profile, GetParam().locale))); +} + +INSTANTIATE_TEST_CASE_P( + GetFormattedPhoneNumberForDisplay, + GetFormattedPhoneNumberForDisplayTest, + testing::Values( + ////////////////////////// + // US phone in US. + ////////////////////////// + // Formatted phone numbers. + PhoneNumberFormatCase("+1 415-555-5555", "US", "+1 415-555-5555"), + PhoneNumberFormatCase("1 415-555-5555", "US", "+1 415-555-5555"), + PhoneNumberFormatCase("415-555-5555", "US", "+1 415-555-5555"), + // Raw phone numbers. + PhoneNumberFormatCase("+14155555555", "US", "+1 415-555-5555"), + PhoneNumberFormatCase("14155555555", "US", "+1 415-555-5555"), + PhoneNumberFormatCase("4155555555", "US", "+1 415-555-5555"), + + ////////////////////////// + // US phone in CA. + ////////////////////////// + // Formatted phone numbers. + PhoneNumberFormatCase("+1 415-555-5555", "CA", "+1 415-555-5555"), + PhoneNumberFormatCase("1 415-555-5555", "CA", "+1 415-555-5555"), + PhoneNumberFormatCase("415-555-5555", "CA", "+1 415-555-5555"), + // Raw phone numbers. + PhoneNumberFormatCase("+14155555555", "CA", "+1 415-555-5555"), + PhoneNumberFormatCase("14155555555", "CA", "+1 415-555-5555"), + PhoneNumberFormatCase("4155555555", "CA", "+1 415-555-5555"), + + ////////////////////////// + // US phone in AU. + ////////////////////////// + // A US phone with the country code is correctly formatted as an US + // number. + PhoneNumberFormatCase("+1 415-555-5555", "AU", "+1 415-555-5555"), + PhoneNumberFormatCase("1 415-555-5555", "AU", "+1 415-555-5555"), + // Without a country code, the phone is formatted for the profile's + // country, even if it's invalid. + PhoneNumberFormatCase("415-555-5555", "AU", "+61 4155555555"), + + ////////////////////////// + // US phone in MX. + ////////////////////////// + // A US phone with the country code is correctly formatted as an US + // number. + PhoneNumberFormatCase("+1 415-555-5555", "MX", "+1 415-555-5555"), + // "+52 1 415 555 5555" is a valid number for Mexico, + PhoneNumberFormatCase("1 415-555-5555", "MX", "+52 1 415 555 5555"), + // Without a country code, the phone is formatted for the profile's + // country. + PhoneNumberFormatCase("415-555-5555", "MX", "+52 415 555 5555"), + + ////////////////////////// + // AU phone in AU. + ////////////////////////// + // Formatted phone numbers. + PhoneNumberFormatCase("+61 2 9374 4000", "AU", "+61 2 9374 4000"), + PhoneNumberFormatCase("61 2 9374 4000", "AU", "+61 2 9374 4000"), + PhoneNumberFormatCase("02 9374 4000", "AU", "+61 2 9374 4000"), + PhoneNumberFormatCase("2 9374 4000", "AU", "+61 2 9374 4000"), + // Raw phone numbers. + PhoneNumberFormatCase("+61293744000", "AU", "+61 2 9374 4000"), + PhoneNumberFormatCase("61293744000", "AU", "+61 2 9374 4000"), + PhoneNumberFormatCase("0293744000", "AU", "+61 2 9374 4000"), + PhoneNumberFormatCase("293744000", "AU", "+61 2 9374 4000"), + + ////////////////////////// + // AU phone in US. + ////////////////////////// + // An AU phone with the country code is correctly formatted as an AU + // number. + PhoneNumberFormatCase("+61 2 9374 4000", "US", "+61 2 9374 4000"), + PhoneNumberFormatCase("61 2 9374 4000", "US", "+61 2 9374 4000"), + // Without a country code, the phone is formatted for the profile's + // country. + // This local AU number fits the length of a US number, so it's + // formatted for US. + PhoneNumberFormatCase("02 9374 4000", "US", "+1 029-374-4000"), + // This local AU number is formatted as an US number, even if it's + // invlaid. + PhoneNumberFormatCase("2 9374 4000", "US", "+1 293744000"), + + ////////////////////////// + // MX phone in MX. + ////////////////////////// + // Formatted phone numbers. + PhoneNumberFormatCase("+52 55 5342 8400", "MX", "+52 55 5342 8400"), + PhoneNumberFormatCase("52 55 5342 8400", "MX", "+52 55 5342 8400"), + PhoneNumberFormatCase("55 5342 8400", "MX", "+52 55 5342 8400"), + // Raw phone numbers. + PhoneNumberFormatCase("+525553428400", "MX", "+52 55 5342 8400"), + PhoneNumberFormatCase("525553428400", "MX", "+52 55 5342 8400"), + PhoneNumberFormatCase("5553428400", "MX", "+52 55 5342 8400"), + + ////////////////////////// + // MX phone in US. + ////////////////////////// + // A MX phone with the country code is correctly formatted as a MX + // number. + PhoneNumberFormatCase("+52 55 5342 8400", "US", "+52 55 5342 8400"), + PhoneNumberFormatCase("52 55 5342 8400", "US", "+52 55 5342 8400"), + // This local MX number fits the length of a US number, so it's + // formatted for US. + PhoneNumberFormatCase("55 5342 8400", "US", "+1 555-342-8400"))); + +INSTANTIATE_TEST_CASE_P( + GetFormattedPhoneNumberForDisplay_EdgeCases, + GetFormattedPhoneNumberForDisplayTest, + testing::Values( + ////////////////////////// + // No country. + ////////////////////////// + // Fallback to locale if no country is set. + PhoneNumberFormatCase("52 55 5342 8400", + "", + "+52 55 5342 8400", + "es_MX"), + PhoneNumberFormatCase("55 5342 8400", "", "+52 55 5342 8400", "es_MX"), + PhoneNumberFormatCase("55 5342 8400", "", "+1 555-342-8400", "en_US"), + PhoneNumberFormatCase("61 2 9374 4000", "", "+61 2 9374 4000", "en_AU"), + PhoneNumberFormatCase("02 9374 4000", "", "+61 2 9374 4000", "en_AU"), + + ////////////////////////// + // No country or locale. + ////////////////////////// + // Format according to the country code. + PhoneNumberFormatCase("61 2 9374 4000", "", "+61 2 9374 4000"), + PhoneNumberFormatCase("52 55 5342 8400", "", "+52 55 5342 8400"), + PhoneNumberFormatCase("1 415 555 5555", "", "+1 415-555-5555"), + // If no country code is found, formats for US. + PhoneNumberFormatCase("02 9374 4000", "", "+1 029-374-4000"), + PhoneNumberFormatCase("2 9374 4000", "", "+1 293744000"), + PhoneNumberFormatCase("55 5342 8400", "", "+1 555-342-8400"), + PhoneNumberFormatCase("52 55 5342 8400", "", "+52 55 5342 8400"), + PhoneNumberFormatCase("415-555-5555", "", "+1 415-555-5555"))); + } // namespace autofill diff --git a/chromium/components/autofill/core/browser/popup_item_ids.h b/chromium/components/autofill/core/browser/popup_item_ids.h index 4859fa266a8..4b79d2cffab 100644 --- a/chromium/components/autofill/core/browser/popup_item_ids.h +++ b/chromium/components/autofill/core/browser/popup_item_ids.h @@ -24,6 +24,7 @@ enum PopupItemId { POPUP_ITEM_ID_USERNAME_ENTRY = -11, POPUP_ITEM_ID_CREATE_HINT = -12, POPUP_ITEM_ID_ALL_SAVED_PASSWORDS_ENTRY = -13, + POPUP_ITEM_ID_GENERATE_PASSWORD_ENTRY = -14, }; } // namespace autofill diff --git a/chromium/components/autofill/core/browser/proto/server.proto b/chromium/components/autofill/core/browser/proto/server.proto index ad92f3768df..8156146c450 100644 --- a/chromium/components/autofill/core/browser/proto/server.proto +++ b/chromium/components/autofill/core/browser/proto/server.proto @@ -25,10 +25,16 @@ message AutofillQueryContents { // This message is the result of an Autofill query. It holds the field type // information. -// Next available id: 7 +// Next available id: 8 message AutofillQueryResponseContents { optional bool upload_required = 1; - repeated group Field = 2 { required fixed32 autofill_type = 3; } + repeated group Field = 2 { + required fixed32 overall_type_prediction = 3; + // Detailed list of all possible predictions (including + // |overall_type_prediction| as the first item). + message FieldPrediction { optional fixed32 type = 1; } + repeated FieldPrediction predictions = 7; + } } // This message contains information about the field types in a single form. diff --git a/chromium/components/autofill/core/browser/region_data_loader_impl.h b/chromium/components/autofill/core/browser/region_data_loader_impl.h index 8113473e2db..b7a780d4bdb 100644 --- a/chromium/components/autofill/core/browser/region_data_loader_impl.h +++ b/chromium/components/autofill/core/browser/region_data_loader_impl.h @@ -7,15 +7,14 @@ #include "components/autofill/core/browser/region_data_loader.h" +#include <memory> #include <string> #include "base/timer/timer.h" #include "third_party/libaddressinput/src/cpp/include/libaddressinput/preload_supplier.h" -#include "third_party/libaddressinput/src/cpp/include/libaddressinput/util/scoped_ptr.h" namespace i18n { namespace addressinput { -class PreloadSupplier; class Source; class Storage; } // namespace addressinput @@ -51,8 +50,7 @@ class RegionDataLoaderImpl : public RegionDataLoader { void DeleteThis(); // The callback to give to |region_data_supplier_| for async operations. - ::i18n::addressinput::scoped_ptr< - ::i18n::addressinput::PreloadSupplier::Callback> + std::unique_ptr<::i18n::addressinput::PreloadSupplier::Callback> region_data_supplier_callback_; // A supplier of region data. diff --git a/chromium/components/autofill/core/browser/subkey_requester.cc b/chromium/components/autofill/core/browser/subkey_requester.cc new file mode 100644 index 00000000000..ff90378903d --- /dev/null +++ b/chromium/components/autofill/core/browser/subkey_requester.cc @@ -0,0 +1,143 @@ +// 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/subkey_requester.h" + +#include <memory> +#include <utility> + +#include "base/bind.h" +#include "base/bind_helpers.h" +#include "base/cancelable_callback.h" +#include "base/memory/ptr_util.h" +#include "base/strings/utf_string_conversions.h" +#include "base/threading/sequenced_task_runner_handle.h" +#include "base/time/time.h" +#include "third_party/libaddressinput/chromium/chrome_address_validator.h" +#include "third_party/libaddressinput/src/cpp/include/libaddressinput/address_data.h" +#include "third_party/libaddressinput/src/cpp/include/libaddressinput/source.h" +#include "third_party/libaddressinput/src/cpp/include/libaddressinput/storage.h" + +namespace autofill { + +namespace { + +using ::i18n::addressinput::Source; +using ::i18n::addressinput::Storage; + +class SubKeyRequest : public SubKeyRequester::Request { + public: + // The |delegate| and |address_validator| need to outlive this Request. + SubKeyRequest(const std::string& region_code, + const std::string& language, + int timeout_seconds, + AddressValidator* address_validator, + SubKeyReceiverCallback on_subkeys_received) + : region_code_(region_code), + language_(language), + address_validator_(address_validator), + on_subkeys_received_(std::move(on_subkeys_received)), + has_responded_(false), + on_timeout_( + base::Bind(&SubKeyRequest::OnRulesLoaded, base::Unretained(this))) { + base::SequencedTaskRunnerHandle::Get()->PostDelayedTask( + FROM_HERE, on_timeout_.callback(), + base::TimeDelta::FromSeconds(timeout_seconds)); + } + + ~SubKeyRequest() override { on_timeout_.Cancel(); } + + void OnRulesLoaded() override { + on_timeout_.Cancel(); + // Check if the timeout happened before the rules were loaded. + if (has_responded_) + return; + has_responded_ = true; + + auto subkeys = + address_validator_->GetRegionSubKeys(region_code_, language_); + std::vector<std::string> subkeys_codes; + std::vector<std::string> subkeys_names; + for (auto s : subkeys) { + subkeys_codes.push_back(s.first); + subkeys_names.push_back(s.second); + } + std::move(on_subkeys_received_).Run(subkeys_codes, subkeys_names); + } + + private: + std::string region_code_; + std::string language_; + // Not owned. Never null. Outlive this object. + AddressValidator* address_validator_; + + SubKeyReceiverCallback on_subkeys_received_; + + bool has_responded_; + base::CancelableCallback<void()> on_timeout_; + + DISALLOW_COPY_AND_ASSIGN(SubKeyRequest); +}; + +} // namespace + +SubKeyRequester::SubKeyRequester(std::unique_ptr<Source> source, + std::unique_ptr<Storage> storage) + : address_validator_(std::move(source), std::move(storage), this) {} + +SubKeyRequester::~SubKeyRequester() {} + +void SubKeyRequester::StartRegionSubKeysRequest(const std::string& region_code, + const std::string& language, + int timeout_seconds, + SubKeyReceiverCallback cb) { + DCHECK(timeout_seconds >= 0); + + std::unique_ptr<SubKeyRequest> request( + base::MakeUnique<SubKeyRequest>(region_code, language, timeout_seconds, + &address_validator_, std::move(cb))); + + if (AreRulesLoadedForRegion(region_code)) { + request->OnRulesLoaded(); + } else { + // Setup the variables so that the subkeys request is sent, when the rules + // are loaded. + pending_subkey_region_code_ = region_code; + pending_subkey_request_ = std::move(request); + + // Start loading the rules for that region. If the rules were already in the + // process of being loaded, this call will do nothing. + LoadRulesForRegion(region_code); + } +} + +bool SubKeyRequester::AreRulesLoadedForRegion(const std::string& region_code) { + return address_validator_.AreRulesLoadedForRegion(region_code); +} + +void SubKeyRequester::LoadRulesForRegion(const std::string& region_code) { + address_validator_.LoadRules(region_code); +} + +void SubKeyRequester::OnAddressValidationRulesLoaded( + const std::string& region_code, + bool success) { + // The case for |success| == false is already handled. if |success| == false, + // AddressValidator::GetRegionSubKeys will return an empty list of subkeys. + // Therefore, here, we can ignore the value of |success|. + // Check if there is any subkey request for that region code. + if (pending_subkey_request_ && + !pending_subkey_region_code_.compare(region_code)) { + pending_subkey_request_->OnRulesLoaded(); + } + pending_subkey_region_code_.clear(); + pending_subkey_request_.reset(); +} + +void SubKeyRequester::CancelPendingGetSubKeys() { + pending_subkey_region_code_.clear(); + pending_subkey_request_.reset(); +} + +} // namespace autofill diff --git a/chromium/components/autofill/core/browser/subkey_requester.h b/chromium/components/autofill/core/browser/subkey_requester.h new file mode 100644 index 00000000000..164857c3134 --- /dev/null +++ b/chromium/components/autofill/core/browser/subkey_requester.h @@ -0,0 +1,76 @@ +// 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_SUBKEY_REQUESTER_H_ +#define COMPONENTS_AUTOFILL_CORE_BROWSER_SUBKEY_REQUESTER_H_ + +#include "base/macros.h" +#include "third_party/libaddressinput/chromium/chrome_address_validator.h" + +namespace autofill { + +// This receives a region code and the device's language. +using SubKeyReceiverCallback = + base::OnceCallback<void(const std::vector<std::string>&, + const std::vector<std::string>&)>; + +// SubKeyRequester Loads Rules from the server and extracts the subkeys. +// For a given key (region code for a country, such as US), the list of its +// corresponding subkeys is the list of that countries admin areas (states, +// provinces, ..). +class SubKeyRequester : public LoadRulesListener { + public: + // The interface for the subkey request. + class Request { + public: + virtual void OnRulesLoaded() = 0; + virtual ~Request() {} + }; + + SubKeyRequester(std::unique_ptr<::i18n::addressinput::Source> source, + std::unique_ptr<::i18n::addressinput::Storage> storage); + ~SubKeyRequester() override; + + // If the rules for |region_code| are loaded, this gets the subkeys for the + // |region_code|, synchronously. If they are not loaded yet, it sets up a + // task to get the subkeys when the rules are loaded (asynchronous). If the + // loading has not yet started, it will also start loading the rules for the + // |region_code|. The received subkeys will be returned to the |requester|. If + // the subkeys are not received in |timeout_seconds|, then the requester will + // be informed and the request will be canceled. |requester| should never be + // null. The requesting device language is set to |language|, ex:"fr". + void StartRegionSubKeysRequest(const std::string& region_code, + const std::string& language, + int timeout_seconds, + SubKeyReceiverCallback cb); + + // Returns whether the rules for the specified |region_code| have finished + // loading. + bool AreRulesLoadedForRegion(const std::string& region_code); + + // Start loading the rules for the specified |region_code|. + virtual void LoadRulesForRegion(const std::string& region_code); + + // Cancels the pending subkey request task. + void CancelPendingGetSubKeys(); + + private: + // Called when the address rules for the |region_code| have finished + // loading. Implementation of the LoadRulesListener interface. + void OnAddressValidationRulesLoaded(const std::string& region_code, + bool success) override; + + // The region code and the request for the pending subkey request. + std::unique_ptr<Request> pending_subkey_request_; + std::string pending_subkey_region_code_; + + // The address validator used to load subkeys. + AddressValidator address_validator_; + + DISALLOW_COPY_AND_ASSIGN(SubKeyRequester); +}; + +} // namespace autofill + +#endif // COMPONENTS_AUTOFILL_CORE_BROWSER_SUBKEY_REQUESTER_H_ diff --git a/chromium/components/autofill/core/browser/subkey_requester_unittest.cc b/chromium/components/autofill/core/browser/subkey_requester_unittest.cc new file mode 100644 index 00000000000..eafb829dc25 --- /dev/null +++ b/chromium/components/autofill/core/browser/subkey_requester_unittest.cc @@ -0,0 +1,202 @@ +// 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/subkey_requester.h" + +#include <utility> + +#include "base/bind.h" +#include "base/strings/utf_string_conversions.h" +#include "base/test/scoped_task_environment.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" +#include "third_party/libaddressinput/src/cpp/include/libaddressinput/storage.h" +#include "third_party/libaddressinput/src/cpp/test/testdata_source.h" + +namespace autofill { + +namespace { + +using ::i18n::addressinput::NullStorage; +using ::i18n::addressinput::Source; +using ::i18n::addressinput::Storage; +using ::i18n::addressinput::TestdataSource; + +const char kLocale[] = "OZ"; +const char kLanguage[] = "en"; +const int kInvalidSize = -1; +const int kCorrectSize = 2; // for subkeys = Do, Re +const int kEmptySize = 0; + +class SubKeyReceiver : public base::RefCountedThreadSafe<SubKeyReceiver> { + public: + SubKeyReceiver() : subkeys_size_(kInvalidSize) {} + + void OnSubKeysReceived(const std::vector<std::string>& subkeys_codes, + const std::vector<std::string>& subkeys_names) { + subkeys_size_ = subkeys_codes.size(); + } + + int subkeys_size() const { return subkeys_size_; } + + private: + friend class base::RefCountedThreadSafe<SubKeyReceiver>; + ~SubKeyReceiver() {} + + int subkeys_size_; + + DISALLOW_COPY_AND_ASSIGN(SubKeyReceiver); +}; + +// Used to load region rules for this test. +class ChromiumTestdataSource : public TestdataSource { + public: + ChromiumTestdataSource() : TestdataSource(true) {} + + ~ChromiumTestdataSource() override {} + + // For this test, only load the rules for the kLocale. + void Get(const std::string& key, const Callback& data_ready) const override { + data_ready( + true, key, + new std::string( + "{\"data/OZ\": " + "{\"id\":\"data/OZ\",\"key\":\"OZ\",\"name\":\"Oz \", " + "\"lang\":\"en\",\"sub_keys\":\"DO~RE\", \"sub_names\":\"Do~Re\"}," + "\"data/OZ/DO\": " + "{\"id\":\"data/OZ/DO\",\"key\":\"DO\",\"name\":\"Do \", " + "\"lang\":\"en\"}," + "\"data/OZ/RE\": " + "{\"id\":\"data/OZ/RE\",\"key\":\"RE\",\"name\":\"Re \", " + "\"lang\":\"en\"}}")); + } + + private: + DISALLOW_COPY_AND_ASSIGN(ChromiumTestdataSource); +}; + +// A test subclass of the SubKeyRequesterImpl. Used to simulate rules not +// being loaded. +class TestSubKeyRequester : public SubKeyRequester { + public: + TestSubKeyRequester(std::unique_ptr<::i18n::addressinput::Source> source, + std::unique_ptr<::i18n::addressinput::Storage> storage) + : SubKeyRequester(std::move(source), std::move(storage)), + should_load_rules_(true) {} + + ~TestSubKeyRequester() override {} + + void ShouldLoadRules(bool should_load_rules) { + should_load_rules_ = should_load_rules; + } + + void LoadRulesForRegion(const std::string& region_code) override { + if (should_load_rules_) { + SubKeyRequester::LoadRulesForRegion(region_code); + } + } + + private: + bool should_load_rules_; + + DISALLOW_COPY_AND_ASSIGN(TestSubKeyRequester); +}; + +} // namespace + +class SubKeyRequesterTest : public testing::Test { + protected: + SubKeyRequesterTest() + : requester_(new TestSubKeyRequester( + std::unique_ptr<Source>(new ChromiumTestdataSource), + std::unique_ptr<Storage>(new NullStorage))) {} + + ~SubKeyRequesterTest() override {} + + base::test::ScopedTaskEnvironment scoped_task_environment_; + const std::unique_ptr<TestSubKeyRequester> requester_; + + private: + DISALLOW_COPY_AND_ASSIGN(SubKeyRequesterTest); +}; + +// Tests that rules are not loaded by default. +TEST_F(SubKeyRequesterTest, AreRulesLoadedForRegion_NotLoaded) { + EXPECT_FALSE(requester_->AreRulesLoadedForRegion(kLocale)); +} + +// Tests that the rules are loaded correctly. +TEST_F(SubKeyRequesterTest, AreRulesLoadedForRegion_Loaded) { + requester_->LoadRulesForRegion(kLocale); + EXPECT_TRUE(requester_->AreRulesLoadedForRegion(kLocale)); +} + +// Tests that if the rules are loaded before the subkey request is started, the +// received subkeys will be returned to the delegate synchronously. +TEST_F(SubKeyRequesterTest, StartRequest_RulesLoaded) { + scoped_refptr<SubKeyReceiver> subkey_receiver_ = new SubKeyReceiver(); + + SubKeyReceiverCallback cb = + base::BindOnce(&SubKeyReceiver::OnSubKeysReceived, subkey_receiver_); + + // Load the rules. + requester_->LoadRulesForRegion(kLocale); + EXPECT_TRUE(requester_->AreRulesLoadedForRegion(kLocale)); + + // Start the request. + requester_->StartRegionSubKeysRequest(kLocale, kLanguage, 0, std::move(cb)); + + // Since the rules are already loaded, the subkeys should be received + // synchronously. + EXPECT_EQ(subkey_receiver_->subkeys_size(), kCorrectSize); +} + +// Tests that if the rules are not loaded before the request and cannot be +// loaded after, the subkeys will not be received and the delegate will be +// notified. +TEST_F(SubKeyRequesterTest, StartRequest_RulesNotLoaded_WillNotLoad) { + scoped_refptr<SubKeyReceiver> subkey_receiver_ = new SubKeyReceiver(); + + SubKeyReceiverCallback cb = + base::BindOnce(&SubKeyReceiver::OnSubKeysReceived, subkey_receiver_); + + // Make sure the rules will not be loaded in the StartRegionSubKeysRequest + // call. + requester_->ShouldLoadRules(false); + + // Start the normalization. + requester_->StartRegionSubKeysRequest(kLocale, kLanguage, 0, std::move(cb)); + + // Let the timeout execute. + scoped_task_environment_.RunUntilIdle(); + + // Since the rules are never loaded and the timeout is 0, the delegate should + // get notified that the subkeys could not be received. + EXPECT_EQ(subkey_receiver_->subkeys_size(), kEmptySize); +} + +// Tests that if the rules are not loaded before the call to +// StartRegionSubKeysRequest, they will be loaded in the call. +TEST_F(SubKeyRequesterTest, StartRequest_RulesNotLoaded_WillLoad) { + scoped_refptr<SubKeyReceiver> subkey_receiver_ = new SubKeyReceiver(); + + SubKeyReceiverCallback cb = + base::BindOnce(&SubKeyReceiver::OnSubKeysReceived, subkey_receiver_); + + // Make sure the rules will not be loaded in the StartRegionSubKeysRequest + // call. + requester_->ShouldLoadRules(true); + // Start the request. + requester_->StartRegionSubKeysRequest(kLocale, kLanguage, 0, std::move(cb)); + + // Even if the rules are not loaded before the call to + // StartRegionSubKeysRequest, they should get loaded in the call. Since our + // test source is synchronous, the request will happen synchronously + // too. + EXPECT_TRUE(requester_->AreRulesLoadedForRegion(kLocale)); + EXPECT_EQ(subkey_receiver_->subkeys_size(), kCorrectSize); +} + +} // namespace autofill diff --git a/chromium/components/autofill/core/browser/test_address_normalizer.cc b/chromium/components/autofill/core/browser/test_address_normalizer.cc new file mode 100644 index 00000000000..1ec6324e028 --- /dev/null +++ b/chromium/components/autofill/core/browser/test_address_normalizer.cc @@ -0,0 +1,38 @@ +// 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/test_address_normalizer.h" + +namespace autofill { + +bool TestAddressNormalizer::AreRulesLoadedForRegion( + const std::string& region_code) { + return true; +} + +void TestAddressNormalizer::StartAddressNormalization( + const AutofillProfile& profile, + const std::string& region_code, + int timeout_seconds, + AddressNormalizer::Delegate* requester) { + if (instantaneous_normalization_) { + requester->OnAddressNormalized(profile); + return; + } + + // Setup the necessary variables for the delayed normalization. + profile_ = profile; + requester_ = requester; +} + +void TestAddressNormalizer::DelayNormalization() { + instantaneous_normalization_ = false; +} + +void TestAddressNormalizer::CompleteAddressNormalization() { + DCHECK(instantaneous_normalization_ == false); + requester_->OnAddressNormalized(profile_); +} + +} // namespace autofill diff --git a/chromium/components/autofill/core/browser/test_address_normalizer.h b/chromium/components/autofill/core/browser/test_address_normalizer.h new file mode 100644 index 00000000000..d9dbbd8863f --- /dev/null +++ b/chromium/components/autofill/core/browser/test_address_normalizer.h @@ -0,0 +1,47 @@ +// Copyright 2017 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef COMPONENTS_AUTOFILL_CORE_BROWSER_TEST_ADDRESS_NORMALIZER_H_ +#define COMPONENTS_AUTOFILL_CORE_BROWSER_TEST_ADDRESS_NORMALIZER_H_ + +#include <string> + +#include "components/autofill/core/browser/address_normalizer.h" +#include "components/autofill/core/browser/autofill_profile.h" + +namespace autofill { + +// A simpler version of the address normalizer to be used in tests. Can be set +// to normalize instantaneously or to wait for a call. +class TestAddressNormalizer : public AddressNormalizer { + public: + TestAddressNormalizer() {} + + void LoadRulesForRegion(const std::string& region_code) override {} + + bool AreRulesLoadedForRegion(const std::string& region_code) override; + + void StartAddressNormalization( + const AutofillProfile& profile, + const std::string& region_code, + int timeout_seconds, + AddressNormalizer::Delegate* requester) override; + + void OnAddressValidationRulesLoaded(const std::string& region_code, + bool success) override {} + + void DelayNormalization(); + + void CompleteAddressNormalization(); + + private: + AutofillProfile profile_; + AddressNormalizer::Delegate* requester_; + + bool instantaneous_normalization_ = true; +}; + +} // namespace autofill + +#endif // COMPONENTS_AUTOFILL_CORE_BROWSER_TEST_ADDRESS_NORMALIZER_H_ diff --git a/chromium/components/autofill/core/browser/test_personal_data_manager.cc b/chromium/components/autofill/core/browser/test_personal_data_manager.cc index d663cdefe55..18413eec03f 100644 --- a/chromium/components/autofill/core/browser/test_personal_data_manager.cc +++ b/chromium/components/autofill/core/browser/test_personal_data_manager.cc @@ -33,17 +33,11 @@ void TestPersonalDataManager::AddTestingServerCreditCard( server_credit_cards_.push_back(base::MakeUnique<CreditCard>(credit_card)); } -const std::vector<AutofillProfile*>& TestPersonalDataManager::GetProfiles() - const { - return GetProfiles(false); -} - -std::vector<AutofillProfile*> TestPersonalDataManager::web_profiles() const { +std::vector<AutofillProfile*> TestPersonalDataManager::GetProfiles() const { return profiles_; } -const std::vector<CreditCard*>& TestPersonalDataManager::GetCreditCards() - const { +std::vector<CreditCard*> TestPersonalDataManager::GetCreditCards() const { return credit_cards_; } @@ -72,9 +66,4 @@ const std::string& TestPersonalDataManager::GetDefaultCountryCodeForNewAddress() return default_country_code_; } -const std::vector<AutofillProfile*>& TestPersonalDataManager::GetProfiles( - bool record_metrics) const { - return profiles_; -} - } // namespace autofill diff --git a/chromium/components/autofill/core/browser/test_personal_data_manager.h b/chromium/components/autofill/core/browser/test_personal_data_manager.h index 71e06180cbe..d9868d8cfb1 100644 --- a/chromium/components/autofill/core/browser/test_personal_data_manager.h +++ b/chromium/components/autofill/core/browser/test_personal_data_manager.h @@ -33,9 +33,8 @@ class TestPersonalDataManager : public PersonalDataManager { // Adds |credit_card| to |server_credit_cards_| by copying. void AddTestingServerCreditCard(const CreditCard& credit_card); - const std::vector<AutofillProfile*>& GetProfiles() const override; - std::vector<AutofillProfile*> web_profiles() const override; - const std::vector<CreditCard*>& GetCreditCards() const override; + std::vector<AutofillProfile*> GetProfiles() const override; + std::vector<CreditCard*> GetCreditCards() const override; std::string SaveImportedProfile( const AutofillProfile& imported_profile) override; @@ -56,9 +55,6 @@ class TestPersonalDataManager : public PersonalDataManager { const CreditCard& imported_credit_card() { return imported_credit_card_; } private: - const std::vector<AutofillProfile*>& GetProfiles( - bool record_metrics) const override; - std::vector<AutofillProfile*> profiles_; std::vector<CreditCard*> credit_cards_; AutofillProfile imported_profile_; diff --git a/chromium/components/autofill/core/browser/webdata/autocomplete_syncable_service.cc b/chromium/components/autofill/core/browser/webdata/autocomplete_syncable_service.cc index c0e86025a21..6053afa3be3 100644 --- a/chromium/components/autofill/core/browser/webdata/autocomplete_syncable_service.cc +++ b/chromium/components/autofill/core/browser/webdata/autocomplete_syncable_service.cc @@ -193,7 +193,7 @@ syncer::SyncDataList AutocompleteSyncableService::GetAllSyncData( } syncer::SyncError AutocompleteSyncableService::ProcessSyncChanges( - const tracked_objects::Location& from_here, + const base::Location& from_here, const syncer::SyncChangeList& change_list) { DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); DCHECK(sync_processor_); diff --git a/chromium/components/autofill/core/browser/webdata/autocomplete_syncable_service.h b/chromium/components/autofill/core/browser/webdata/autocomplete_syncable_service.h index 9d603cc19d2..72a22f778d9 100644 --- a/chromium/components/autofill/core/browser/webdata/autocomplete_syncable_service.h +++ b/chromium/components/autofill/core/browser/webdata/autocomplete_syncable_service.h @@ -74,7 +74,7 @@ class AutocompleteSyncableService void StopSyncing(syncer::ModelType type) override; syncer::SyncDataList GetAllSyncData(syncer::ModelType type) const override; syncer::SyncError ProcessSyncChanges( - const tracked_objects::Location& from_here, + const base::Location& from_here, const syncer::SyncChangeList& change_list) override; // AutofillWebDataServiceObserverOnDBSequence: diff --git a/chromium/components/autofill/core/browser/webdata/autofill_profile_syncable_service.cc b/chromium/components/autofill/core/browser/webdata/autofill_profile_syncable_service.cc index e67793de69c..03e16fefd1b 100644 --- a/chromium/components/autofill/core/browser/webdata/autofill_profile_syncable_service.cc +++ b/chromium/components/autofill/core/browser/webdata/autofill_profile_syncable_service.cc @@ -227,7 +227,7 @@ syncer::SyncDataList AutofillProfileSyncableService::GetAllSyncData( } syncer::SyncError AutofillProfileSyncableService::ProcessSyncChanges( - const tracked_objects::Location& from_here, + const base::Location& from_here, const syncer::SyncChangeList& change_list) { DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); if (!sync_processor_.get()) { @@ -407,6 +407,14 @@ bool AutofillProfileSyncableService::OverwriteProfileWithServerData( diff = true; } + // Update the validity state bitfield. + if (specifics.has_validity_state_bitfield() && + specifics.validity_state_bitfield() != + profile->GetValidityBitfieldValue()) { + profile->SetValidityFromBitfieldValue(specifics.validity_state_bitfield()); + diff = true; + } + if (static_cast<size_t>(specifics.use_count()) != profile->use_count()) { profile->set_use_count(specifics.use_count()); diff = true; @@ -471,6 +479,7 @@ void AutofillProfileSyncableService::WriteAutofillProfile( LimitData( UTF16ToUTF8(profile.GetRawInfo(ADDRESS_HOME_DEPENDENT_LOCALITY)))); specifics->set_address_home_language_code(LimitData(profile.language_code())); + specifics->set_validity_state_bitfield(profile.GetValidityBitfieldValue()); // TODO(estade): this should be set_email_address. specifics->add_email_address( diff --git a/chromium/components/autofill/core/browser/webdata/autofill_profile_syncable_service.h b/chromium/components/autofill/core/browser/webdata/autofill_profile_syncable_service.h index 9ab95866032..8566101b710 100644 --- a/chromium/components/autofill/core/browser/webdata/autofill_profile_syncable_service.h +++ b/chromium/components/autofill/core/browser/webdata/autofill_profile_syncable_service.h @@ -75,7 +75,7 @@ class AutofillProfileSyncableService void StopSyncing(syncer::ModelType type) override; syncer::SyncDataList GetAllSyncData(syncer::ModelType type) const override; syncer::SyncError ProcessSyncChanges( - const tracked_objects::Location& from_here, + const base::Location& from_here, const syncer::SyncChangeList& change_list) override; // AutofillWebDataServiceObserverOnDBSequence implementation. 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 7c840464cf4..d1ec72bf0e0 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 @@ -40,6 +40,7 @@ const char kGuid3[] = "EDC609ED-7EEE-4F27-B00C-423242A9C44D"; const char kGuid4[] = "EDC609ED-7EEE-4F27-B00C-423242A9C44E"; const char kHttpOrigin[] = "http://www.example.com/"; const char kHttpsOrigin[] = "https://www.example.com/"; +const int kValidityStateBitfield = 1984; class MockAutofillProfileSyncableService : public AutofillProfileSyncableService { @@ -107,7 +108,7 @@ class MockSyncChangeProcessor : public syncer::SyncChangeProcessor { ~MockSyncChangeProcessor() override {} MOCK_METHOD2(ProcessSyncChanges, - syncer::SyncError(const tracked_objects::Location&, + syncer::SyncError(const base::Location&, const syncer::SyncChangeList&)); syncer::SyncDataList GetAllSyncData(syncer::ModelType type) const override { return syncer::SyncDataList(); @@ -120,7 +121,7 @@ class TestSyncChangeProcessor : public syncer::SyncChangeProcessor { ~TestSyncChangeProcessor() override {} syncer::SyncError ProcessSyncChanges( - const tracked_objects::Location& location, + const base::Location& location, const syncer::SyncChangeList& changes) override { changes_ = changes; return syncer::SyncError(); @@ -169,6 +170,7 @@ std::unique_ptr<AutofillProfile> ConstructCompleteProfile() { profile->SetRawInfo(ADDRESS_HOME_DEPENDENT_LOCALITY, ASCIIToUTF16("Santa Clara")); profile->set_language_code("en"); + profile->SetValidityFromBitfieldValue(kValidityStateBitfield); return profile; } @@ -206,6 +208,7 @@ syncer::SyncData ConstructCompleteSyncData() { specifics->set_address_home_sorting_code("CEDEX"); specifics->set_address_home_dependent_locality("Santa Clara"); specifics->set_address_home_language_code("en"); + specifics->set_validity_state_bitfield(kValidityStateBitfield); return syncer::SyncData::CreateLocalData(kGuid1, kGuid1, entity_specifics); } @@ -1072,6 +1075,196 @@ TEST_F(AutofillProfileSyncableServiceTest, LanguageCodePropagates) { EXPECT_EQ("en", specifics.address_home_language_code()); } +// Missing validity state bitifield should not generate sync events. +TEST_F(AutofillProfileSyncableServiceTest, DefaultValidityStateNoSync) { + std::vector<std::unique_ptr<AutofillProfile>> profiles_from_web_db; + + // Local autofill profile has a default validity state bitfield. + AutofillProfile profile(kGuid1, kHttpsOrigin); + EXPECT_EQ(0, profile.GetValidityBitfieldValue()); + profiles_from_web_db.push_back(base::MakeUnique<AutofillProfile>(profile)); + + // Remote data does not have a validity state bitfield value. + 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_use_count(profile.use_count()); + autofill_specifics->set_use_date(profile.use_date().ToTimeT()); + EXPECT_FALSE(autofill_specifics->has_validity_state_bitfield()); + + syncer::SyncDataList data_list; + data_list.push_back(syncer::SyncData::CreateLocalData( + profile.guid(), profile.guid(), specifics)); + + // Expect no changes to local and remote data. + MockAutofillProfileSyncableService::DataBundle expected_empty_bundle; + syncer::SyncChangeList expected_empty_change_list; + + MergeDataAndStartSyncing(std::move(profiles_from_web_db), data_list, + expected_empty_bundle, expected_empty_change_list); + autofill_syncable_service_.StopSyncing(syncer::AUTOFILL_PROFILE); +} + +// Default validity state bitfield should be overwritten by sync. +TEST_F(AutofillProfileSyncableServiceTest, SyncUpdatesDefaultValidityBitfield) { + std::vector<std::unique_ptr<AutofillProfile>> profiles_from_web_db; + + // Local autofill profile has a default validity state. + AutofillProfile profile(kGuid1, kHttpsOrigin); + EXPECT_EQ(0, profile.GetValidityBitfieldValue()); + profiles_from_web_db.push_back(base::MakeUnique<AutofillProfile>(profile)); + + // Remote data has a non default validity state bitfield value. + 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_validity_state_bitfield(kValidityStateBitfield); + EXPECT_TRUE(autofill_specifics->has_validity_state_bitfield()); + + syncer::SyncDataList data_list; + data_list.push_back(syncer::SyncData::CreateLocalData( + profile.guid(), profile.guid(), specifics)); + + // Expect the local autofill profile to have the non default validity state + // bitfield after sync. + MockAutofillProfileSyncableService::DataBundle expected_bundle; + AutofillProfile expected_profile(kGuid1, kHttpsOrigin); + expected_profile.SetValidityFromBitfieldValue(kValidityStateBitfield); + 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); +} + +// Local validity state bitfield should be overwritten by sync. +TEST_F(AutofillProfileSyncableServiceTest, SyncUpdatesLocalValidityBitfield) { + std::vector<std::unique_ptr<AutofillProfile>> profiles_from_web_db; + + // Local autofill profile has a non default validity state bitfield value. + AutofillProfile profile(kGuid1, kHttpsOrigin); + profile.SetValidityFromBitfieldValue(kValidityStateBitfield + 1); + profiles_from_web_db.push_back(base::MakeUnique<AutofillProfile>(profile)); + + // Remote data has a different non default validity state bitfield value. + 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_validity_state_bitfield(kValidityStateBitfield); + EXPECT_TRUE(autofill_specifics->has_validity_state_bitfield()); + + syncer::SyncDataList data_list; + data_list.push_back(syncer::SyncData::CreateLocalData( + profile.guid(), profile.guid(), specifics)); + + // Expect the local autofill profile to have the remote validity state + // bitfield value after sync. + MockAutofillProfileSyncableService::DataBundle expected_bundle; + AutofillProfile expected_profile(kGuid1, kHttpsOrigin); + expected_profile.SetValidityFromBitfieldValue(kValidityStateBitfield); + 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); +} + +// Sync data without a default validity state bitfield should not overwrite +// an existing validity state bitfield in local autofill profile. +TEST_F(AutofillProfileSyncableServiceTest, + DefaultSyncPreservesLocalValidityBitfield) { + std::vector<std::unique_ptr<AutofillProfile>> profiles_from_web_db; + + // Local autofill profile has a non default validity state bitfield value. + AutofillProfile profile(kGuid1, kHttpsOrigin); + profile.SetValidityFromBitfieldValue(kValidityStateBitfield); + profiles_from_web_db.push_back(base::MakeUnique<AutofillProfile>(profile)); + + // Remote data does not has no validity state bitfield value. + 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("John"); + 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()); + EXPECT_FALSE(autofill_specifics->has_validity_state_bitfield()); + + syncer::SyncDataList data_list; + data_list.push_back(syncer::SyncData::CreateLocalData( + profile.guid(), profile.guid(), specifics)); + + // Expect local autofill profile to still have the kValidityStateBitfield + // language code after sync. + MockAutofillProfileSyncableService::DataBundle expected_bundle; + AutofillProfile expected_profile(profile.guid(), profile.origin()); + expected_profile.SetValidityFromBitfieldValue(kValidityStateBitfield); + expected_profile.SetRawInfo(NAME_FIRST, ASCIIToUTF16("John")); + 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); +} + +// Validity state bitfield in autofill profiles should be synced to the server. +TEST_F(AutofillProfileSyncableServiceTest, LocalValidityBitfieldPropagates) { + TestSyncChangeProcessor* sync_change_processor = new TestSyncChangeProcessor; + autofill_syncable_service_.set_sync_processor(sync_change_processor); + + AutofillProfile profile(kGuid1, kHttpsOrigin); + profile.SetValidityFromBitfieldValue(kValidityStateBitfield); + AutofillProfileChange change(AutofillProfileChange::ADD, kGuid1, &profile); + autofill_syncable_service_.AutofillProfileChanged(change); + + ASSERT_EQ(1U, sync_change_processor->changes().size()); + syncer::SyncChange result = sync_change_processor->changes()[0]; + EXPECT_EQ(syncer::SyncChange::ACTION_ADD, result.change_type()); + + sync_pb::AutofillProfileSpecifics specifics = + result.sync_data().GetSpecifics().autofill_profile(); + EXPECT_EQ(kGuid1, specifics.guid()); + EXPECT_EQ(kHttpsOrigin, specifics.origin()); + EXPECT_EQ(kValidityStateBitfield, specifics.validity_state_bitfield()); +} + // Missing full name field should not generate sync events. TEST_F(AutofillProfileSyncableServiceTest, NoFullNameNoSync) { std::vector<std::unique_ptr<AutofillProfile>> profiles_from_web_db; diff --git a/chromium/components/autofill/core/browser/webdata/autofill_table.cc b/chromium/components/autofill/core/browser/webdata/autofill_table.cc index 92ce2201c1a..2c64d1f66fb 100644 --- a/chromium/components/autofill/core/browser/webdata/autofill_table.cc +++ b/chromium/components/autofill/core/browser/webdata/autofill_table.cc @@ -7,7 +7,6 @@ #include <stdint.h> #include <algorithm> -#include <cmath> #include <limits> #include <map> #include <set> @@ -43,6 +42,7 @@ #include "sql/statement.h" #include "sql/transaction.h" #include "ui/base/l10n/l10n_util.h" +#include "ui/gfx/geometry/safe_integer_conversions.h" #include "url/gurl.h" namespace autofill { @@ -61,12 +61,6 @@ struct AutofillUpdate { int count; }; -// Rounds a positive floating point number to the nearest integer. -int Round(float f) { - DCHECK_GE(f, 0.f); - return base::checked_cast<int>(std::floor(f + 0.5f)); -} - // Returns the |data_model|'s value corresponding to the |type|, trimmed to the // maximum length that can be stored in a column of the Autofill database. base::string16 GetInfo(const AutofillDataModel& data_model, @@ -98,6 +92,7 @@ void BindAutofillProfileToStatement(const AutofillProfile& profile, s->BindInt64(index++, modification_date.ToTimeT()); s->BindString(index++, profile.origin()); s->BindString(index++, profile.language_code()); + s->BindInt64(index++, profile.GetValidityBitfieldValue()); } std::unique_ptr<AutofillProfile> AutofillProfileFromStatement( @@ -121,6 +116,7 @@ std::unique_ptr<AutofillProfile> AutofillProfileFromStatement( profile->set_modification_date(base::Time::FromTimeT(s.ColumnInt64(index++))); profile->set_origin(s.ColumnString(index++)); profile->set_language_code(s.ColumnString(index++)); + profile->SetValidityFromBitfieldValue(s.ColumnInt64(index++)); return profile; } @@ -479,6 +475,9 @@ bool AutofillTable::MigrateToVersion(int version, case 74: *update_compatible_version = false; return MigrateToVersion74AddServerCardTypeColumn(); + case 75: + *update_compatible_version = false; + return MigrateToVersion75AddProfileValidityBitfieldColumn(); } return true; } @@ -631,10 +630,10 @@ bool AutofillTable::RemoveFormElementsAddedBetween( ? date_last_used_time_t : delete_begin_time_t - 1; updated_entry.count = - 1 + - Round(1.0 * (count - 1) * - (updated_entry.date_last_used - updated_entry.date_created) / - (date_last_used_time_t - date_created_time_t)); + 1 + gfx::ToRoundedInt( + 1.0 * (count - 1) * + (updated_entry.date_last_used - updated_entry.date_created) / + (date_last_used_time_t - date_created_time_t)); updates.push_back(updated_entry); } @@ -884,8 +883,8 @@ bool AutofillTable::AddAutofillProfile(const AutofillProfile& profile) { "INSERT INTO autofill_profiles" "(guid, company_name, street_address, dependent_locality, city, state," " zipcode, sorting_code, country_code, use_count, use_date, " - " date_modified, origin, language_code)" - "VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?)")); + " date_modified, origin, language_code, validity_bitfield)" + "VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)")); BindAutofillProfileToStatement(profile, AutofillClock::Now(), &s); if (!s.Run()) @@ -900,7 +899,7 @@ std::unique_ptr<AutofillProfile> AutofillTable::GetAutofillProfile( sql::Statement s(db_->GetUniqueStatement( "SELECT guid, company_name, street_address, dependent_locality, city," " state, zipcode, sorting_code, country_code, use_count, use_date," - " date_modified, origin, language_code " + " date_modified, origin, language_code, validity_bitfield " "FROM autofill_profiles " "WHERE guid=?")); s.BindString(0, guid); @@ -1088,14 +1087,15 @@ bool AutofillTable::UpdateAutofillProfile(const AutofillProfile& profile) { "UPDATE autofill_profiles " "SET guid=?, company_name=?, street_address=?, dependent_locality=?, " " city=?, state=?, zipcode=?, sorting_code=?, country_code=?, " - " use_count=?, use_date=?, date_modified=?, origin=?, language_code=? " + " use_count=?, use_date=?, date_modified=?, origin=?, " + " language_code=?, validity_bitfield=? " "WHERE guid=?")); BindAutofillProfileToStatement(profile, update_modification_date ? AutofillClock::Now() : old_profile->modification_date(), &s); - s.BindString(14, profile.guid()); + s.BindString(15, profile.guid()); bool result = s.Run(); DCHECK_GT(db_->GetLastChangeCount(), 0); @@ -1907,7 +1907,8 @@ bool AutofillTable::InitProfilesTable() { "origin VARCHAR DEFAULT '', " "language_code VARCHAR, " "use_count INTEGER NOT NULL DEFAULT 0, " - "use_date INTEGER NOT NULL DEFAULT 0) ")) { + "use_date INTEGER NOT NULL DEFAULT 0, " + "validity_bitfield UNSIGNED NOT NULL DEFAULT 0) ")) { NOTREACHED(); return false; } @@ -2642,4 +2643,11 @@ bool AutofillTable::MigrateToVersion74AddServerCardTypeColumn() { "COLUMN type INTEGER DEFAULT 0"); } +bool AutofillTable::MigrateToVersion75AddProfileValidityBitfieldColumn() { + // Add the new valdity_bitfield column to the autofill_profiles table. + return db_->Execute( + "ALTER TABLE autofill_profiles ADD COLUMN validity_bitfield UNSIGNED NOT " + "NULL DEFAULT 0"); +} + } // namespace autofill diff --git a/chromium/components/autofill/core/browser/webdata/autofill_table.h b/chromium/components/autofill/core/browser/webdata/autofill_table.h index 95634417a01..bc498b96805 100644 --- a/chromium/components/autofill/core/browser/webdata/autofill_table.h +++ b/chromium/components/autofill/core/browser/webdata/autofill_table.h @@ -87,6 +87,9 @@ struct FormFieldData; // code starts with the postal code, but a JP address with // "ja-latn" language code starts with the recipient name. // Added in version 56. +// validity_bitfield A bitfield representing the validity state of different +// fields in the profile. +// Added in version 75. // // autofill_profile_names // This table contains the multi-valued name fields @@ -469,6 +472,7 @@ class AutofillTable : public WebDatabaseTable, bool MigrateToVersion72RenameCardTypeToIssuerNetwork(); bool MigrateToVersion73AddMaskedCardBankName(); bool MigrateToVersion74AddServerCardTypeColumn(); + bool MigrateToVersion75AddProfileValidityBitfieldColumn(); // Max data length saved in the table, AKA the maximum length allowed for // form data. 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 298a2c3c422..5df7e968873 100644 --- a/chromium/components/autofill/core/browser/webdata/autofill_table_unittest.cc +++ b/chromium/components/autofill/core/browser/webdata/autofill_table_unittest.cc @@ -735,7 +735,8 @@ TEST_F(AutofillTableTest, } TEST_F(AutofillTableTest, AutofillProfile) { - // Add a 'Home' profile. + // Add a 'Home' profile with non-default data. The specific values are not + // important. AutofillProfile home_profile; home_profile.set_origin(std::string()); home_profile.SetRawInfo(NAME_FIRST, ASCIIToUTF16("John")); @@ -754,6 +755,7 @@ TEST_F(AutofillTableTest, AutofillProfile) { home_profile.SetRawInfo(ADDRESS_HOME_COUNTRY, ASCIIToUTF16("US")); home_profile.SetRawInfo(PHONE_HOME_WHOLE_NUMBER, ASCIIToUTF16("18181234567")); home_profile.set_language_code("en"); + home_profile.SetValidityFromBitfieldValue(6); Time pre_creation_time = Time::Now(); EXPECT_TRUE(table_->AddAutofillProfile(home_profile)); @@ -818,7 +820,8 @@ TEST_F(AutofillTableTest, AutofillProfile) { post_modification_time.ToTimeT()); EXPECT_FALSE(s_billing_updated.Step()); - // Update the 'Billing' profile. + // Update the 'Billing' profile with non-default data. The specific values are + // not important. billing_profile.set_origin(kSettingsOrigin); billing_profile.SetRawInfo(NAME_FIRST, ASCIIToUTF16("Janice")); billing_profile.SetRawInfo(NAME_MIDDLE, ASCIIToUTF16("C.")); @@ -836,6 +839,7 @@ TEST_F(AutofillTableTest, AutofillProfile) { billing_profile.SetRawInfo(ADDRESS_HOME_COUNTRY, ASCIIToUTF16("US")); billing_profile.SetRawInfo(PHONE_HOME_WHOLE_NUMBER, ASCIIToUTF16("18181230000")); + billing_profile.SetValidityFromBitfieldValue(54); Time pre_modification_time_2 = Time::Now(); EXPECT_TRUE(table_->UpdateAutofillProfile(billing_profile)); Time post_modification_time_2 = Time::Now(); @@ -1612,6 +1616,40 @@ TEST_F(AutofillTableTest, Autofill_GetAllAutofillEntries_TwoSame) { CompareAutofillEntrySets(entry_set, expected_entries); } +TEST_F(AutofillTableTest, AutofillProfileValidityBitfield) { + // Add an autofill profile with a non default validity state. The value itself + // is insignificant for this test since only the serialization and + // deserialization are tested. + const int kValidityBitfieldValue = 1984; + AutofillProfile profile; + profile.set_origin(std::string()); + profile.SetRawInfo(NAME_FIRST, ASCIIToUTF16("John")); + profile.SetRawInfo(NAME_LAST, ASCIIToUTF16("Smith")); + profile.SetValidityFromBitfieldValue(kValidityBitfieldValue); + + // Add the profile to the table. + EXPECT_TRUE(table_->AddAutofillProfile(profile)); + + // Get the profile from the table and make sure the validity was set. + std::unique_ptr<AutofillProfile> db_profile = + table_->GetAutofillProfile(profile.guid()); + ASSERT_TRUE(db_profile); + EXPECT_EQ(kValidityBitfieldValue, db_profile->GetValidityBitfieldValue()); + + // Modify the validity of the profile. + const int kOtherValidityBitfieldValue = 1999; + profile.SetValidityFromBitfieldValue(kOtherValidityBitfieldValue); + + // Update the profile in the table. + EXPECT_TRUE(table_->UpdateAutofillProfile(profile)); + + // Get the profile from the table and make sure the validity was updated. + db_profile = table_->GetAutofillProfile(profile.guid()); + ASSERT_TRUE(db_profile); + EXPECT_EQ(kOtherValidityBitfieldValue, + db_profile->GetValidityBitfieldValue()); +} + TEST_F(AutofillTableTest, SetGetServerCards) { std::vector<CreditCard> inputs; inputs.push_back(CreditCard(CreditCard::FULL_SERVER_CARD, "a123")); diff --git a/chromium/components/autofill/core/browser/webdata/autofill_wallet_metadata_syncable_service.cc b/chromium/components/autofill/core/browser/webdata/autofill_wallet_metadata_syncable_service.cc index 7d47212f84f..a1720b4f461 100644 --- a/chromium/components/autofill/core/browser/webdata/autofill_wallet_metadata_syncable_service.cc +++ b/chromium/components/autofill/core/browser/webdata/autofill_wallet_metadata_syncable_service.cc @@ -387,7 +387,7 @@ syncer::SyncDataList AutofillWalletMetadataSyncableService::GetAllSyncData( } syncer::SyncError AutofillWalletMetadataSyncableService::ProcessSyncChanges( - const tracked_objects::Location& from_here, + const base::Location& from_here, const syncer::SyncChangeList& changes_from_sync) { DCHECK(thread_checker_.CalledOnValidThread()); diff --git a/chromium/components/autofill/core/browser/webdata/autofill_wallet_metadata_syncable_service.h b/chromium/components/autofill/core/browser/webdata/autofill_wallet_metadata_syncable_service.h index 5e16997bdf3..23da67cc634 100644 --- a/chromium/components/autofill/core/browser/webdata/autofill_wallet_metadata_syncable_service.h +++ b/chromium/components/autofill/core/browser/webdata/autofill_wallet_metadata_syncable_service.h @@ -21,15 +21,15 @@ #include "components/sync/model/syncable_service.h" #include "components/sync/protocol/autofill_specifics.pb.h" +namespace base { +class Location; +} + namespace syncer { class SyncChangeProcessor; class SyncErrorFactory; } -namespace tracked_objects { -class Location; -} - namespace autofill { class AutofillProfile; @@ -60,7 +60,7 @@ class AutofillWalletMetadataSyncableService void StopSyncing(syncer::ModelType type) override; syncer::SyncDataList GetAllSyncData(syncer::ModelType type) const override; syncer::SyncError ProcessSyncChanges( - const tracked_objects::Location& from_here, + const base::Location& from_here, const syncer::SyncChangeList& changes_from_sync) override; // AutofillWebDataServiceObserverOnDBSequence implementation. 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 39382970d7a..90d6408695e 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 @@ -238,7 +238,7 @@ syncer::SyncDataList AutofillWalletSyncableService::GetAllSyncData( } syncer::SyncError AutofillWalletSyncableService::ProcessSyncChanges( - const tracked_objects::Location& from_here, + const base::Location& from_here, const syncer::SyncChangeList& change_list) { DCHECK(thread_checker_.CalledOnValidThread()); // Don't bother handling incremental updates. Wallet data changes very rarely diff --git a/chromium/components/autofill/core/browser/webdata/autofill_wallet_syncable_service.h b/chromium/components/autofill/core/browser/webdata/autofill_wallet_syncable_service.h index 4156f6cd644..9e823ae952f 100644 --- a/chromium/components/autofill/core/browser/webdata/autofill_wallet_syncable_service.h +++ b/chromium/components/autofill/core/browser/webdata/autofill_wallet_syncable_service.h @@ -39,7 +39,7 @@ class AutofillWalletSyncableService void StopSyncing(syncer::ModelType type) override; syncer::SyncDataList GetAllSyncData(syncer::ModelType type) const override; syncer::SyncError ProcessSyncChanges( - const tracked_objects::Location& from_here, + const base::Location& from_here, const syncer::SyncChangeList& change_list) override; // Creates a new AutofillWalletSyncableService and hangs it off of diff --git a/chromium/components/autofill/core/common/autofill_pref_names.cc b/chromium/components/autofill/core/common/autofill_pref_names.cc index 4f3b11dc6cf..c52ffb9a7cf 100644 --- a/chromium/components/autofill/core/common/autofill_pref_names.cc +++ b/chromium/components/autofill/core/common/autofill_pref_names.cc @@ -26,6 +26,16 @@ const char kAutofillWalletImportEnabled[] = "autofill.wallet_import_enabled"; // was run. This routine will be run once per version. const char kAutofillLastVersionDeduped[] = "autofill.last_version_deduped"; +// Integer that is set to the last version where disused addresses were +// deleted. This deletion will be run once per version. +const char kAutofillLastVersionDisusedAddressesDeleted[] = + "autofill.last_version_disused_addresses_deleted"; + +// Integer that is set to the last version where disused credit cards were +// deleted. This deletion will be run once per version. +const char kAutofillLastVersionDisusedCreditCardsDeleted[] = + "autofill.last_version_disused_credit_cards_deleted"; + // Boolean that is set to the last choice user made when prompted for saving an // unmasked server card locally. const char kAutofillWalletImportStorageCheckboxState[] = @@ -38,5 +48,9 @@ const char kAutofillWalletImportStorageCheckboxState[] = const char kAutofillAcceptSaveCreditCardPromptState[] = "autofill.accept_save_credit_card_prompt_state"; +// Boolean that is true if Autofill is enabled and allowed to save credit card +// data. +const char kAutofillCreditCardEnabled[] = "autofill.credit_card_enabled"; + } // namespace prefs } // namespace autofill diff --git a/chromium/components/autofill/core/common/autofill_pref_names.h b/chromium/components/autofill/core/common/autofill_pref_names.h index e18a77abdb8..de57761997c 100644 --- a/chromium/components/autofill/core/common/autofill_pref_names.h +++ b/chromium/components/autofill/core/common/autofill_pref_names.h @@ -12,10 +12,13 @@ namespace prefs { // component. Keep alphabetized, and document each in the .cc file. extern const char kAutofillAcceptSaveCreditCardPromptState[]; +extern const char kAutofillCreditCardEnabled[]; extern const char kAutofillCreditCardSigninPromoImpressionCount[]; extern const char kAutofillEnabled[]; -extern const char kAutofillProfileUseDatesFixed[]; extern const char kAutofillLastVersionDeduped[]; +extern const char kAutofillLastVersionDisusedAddressesDeleted[]; +extern const char kAutofillLastVersionDisusedCreditCardsDeleted[]; +extern const char kAutofillProfileUseDatesFixed[]; extern const char kAutofillWalletImportEnabled[]; extern const char kAutofillWalletImportStorageCheckboxState[]; diff --git a/chromium/components/autofill/core/common/autofill_regex_constants.cc b/chromium/components/autofill/core/common/autofill_regex_constants.cc index 47c9883b857..81463c16b0c 100644 --- a/chromium/components/autofill/core/common/autofill_regex_constants.cc +++ b/chromium/components/autofill/core/common/autofill_regex_constants.cc @@ -299,32 +299,53 @@ const char kPhoneExtensionRe[] = "|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 + "allbank|" // Allahabad Bank UPI + "andb|" // Andhra Bank ONE + "axisbank|" // Axis Pay + "barodampay|" // Baroda MPay + "centralbank|" // Cent UPI + "cnrb|" // Canara Bank UPI - Empower + "csbpay|" // CSB UPI + "dbs|" // digibank by DBS + "dcb|" // DCB Bank + "denabank|" // Dena Bank E-UPI + "fbl|" // Cointab + "federal|" // Lotza + "hdfcbank|" // HDFC Bank MobileBanking + "hsbc|" // HSBC Simply Pay + "icici|" // Pockets- ICICI Bank + "idbi|" // PayWiz + "idfcbank|" // IDFC Bank UPI App + "indianbank|" // Indian Bank UPI + "indus|" // Indus Pay + "iob|" // IOB UPI + "kaypay|" // KayPay + "kbl|" // KBL Smartz + "kotak|" // kotak Mahindra Bank + "kvb|" // KVB Upay + "lvb|" // LVB UPay + "mahb|" // MAHAUPI + "obc|" // Oriental BHIM UPI + "pingpay|" // Samsung Pay + "pnb|" // PNB UPI + "pockets|" // Pockets- ICICI Bank + "psb|" // PSB UPI App + "rbl|" // RBL Pay + "sbi|" // SBI Pay + "scb|" // Standard Chartered + "sib|" // SIB M-Pay (UPI Pay) + "syndicate|" // Synd UPI + "tjsp|" // TranZapp + "ubi|" // United UPI + "uboi|" // Union Bank UPI + "uco|" // UCO UPI + "unionbank|" // Union Bank UPI + "united|" // United UPI + "upi|" // BHIM Bharat Interface for Money + "utbi|" // United UPI + "vijb|" // Vijaya UPI App + "ybl|" // Yes Pay + "yesbank" // NuPay ")$"; } // namespace autofill diff --git a/chromium/components/autofill/core/common/password_form.cc b/chromium/components/autofill/core/common/password_form.cc index cc44dd7f494..5039ca95d53 100644 --- a/chromium/components/autofill/core/common/password_form.cc +++ b/chromium/components/autofill/core/common/password_form.cc @@ -44,6 +44,8 @@ void PasswordFormToJSON(const PasswordForm& form, target->SetString( "other_possible_usernames", OtherPossibleUsernamesToString(form.other_possible_usernames)); + target->SetString("all_possible_passwords", + AllPossiblePasswordsToString(form.all_possible_passwords)); target->SetBoolean("blacklisted", form.blacklisted_by_user); target->SetBoolean("preferred", form.preferred); target->SetDouble("date_created", form.date_created.ToDoubleT()); @@ -78,6 +80,7 @@ void PasswordFormToJSON(const PasswordForm& form, PasswordForm::PasswordForm() : scheme(SCHEME_HTML), username_marked_by_site(false), + form_has_autofilled_value(false), password_value_is_default(false), new_password_value_is_default(false), new_password_marked_by_site(false), @@ -96,8 +99,14 @@ PasswordForm::PasswordForm() PasswordForm::PasswordForm(const PasswordForm& other) = default; +PasswordForm::PasswordForm(PasswordForm&& other) = default; + PasswordForm::~PasswordForm() = default; +PasswordForm& PasswordForm::operator=(const PasswordForm& form) = default; + +PasswordForm& PasswordForm::operator=(PasswordForm&& form) = default; + bool PasswordForm::IsPossibleChangePasswordForm() const { return !new_password_element.empty() && layout != PasswordForm::Layout::LAYOUT_LOGIN_AND_SIGNUP; @@ -115,6 +124,8 @@ bool PasswordForm::operator==(const PasswordForm& form) const { username_marked_by_site == form.username_marked_by_site && username_value == form.username_value && other_possible_usernames == form.other_possible_usernames && + all_possible_passwords == form.all_possible_passwords && + form_has_autofilled_value == form.form_has_autofilled_value && password_element == form.password_element && password_value == form.password_value && new_password_element == form.new_password_element && @@ -187,6 +198,11 @@ base::string16 OtherPossibleUsernamesToString( return base::JoinString(pairs, base::ASCIIToUTF16(", ")); } +base::string16 AllPossiblePasswordsToString( + const std::vector<base::string16>& possible_passwords) { + return base::JoinString(possible_passwords, 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 825fdabcda6..c1931c4f9df 100644 --- a/chromium/components/autofill/core/common/password_form.h +++ b/chromium/components/autofill/core/common/password_form.h @@ -183,6 +183,14 @@ struct PasswordForm { // When parsing an HTML form, this is typically empty. PossibleUsernamesVector other_possible_usernames; + // This member is populated in cases where we there are multiple posssible + // password values. Used in pending password state, to populate a dropdown + // for possible passwords. Contains all possible passwords. Optional. + std::vector<base::string16> all_possible_passwords; + + // True if |all_possible_passwords| have autofilled value or its part. + bool form_has_autofilled_value; + // The name of the input element corresponding to the current password. // Optional (improves scoring). // @@ -332,7 +340,11 @@ struct PasswordForm { PasswordForm(); PasswordForm(const PasswordForm& other); + PasswordForm(PasswordForm&& other); ~PasswordForm(); + + PasswordForm& operator=(const PasswordForm& form); + PasswordForm& operator=(PasswordForm&& form); }; // True if the unique keys for the forms are the same. The unique key is @@ -350,6 +362,10 @@ struct LessThanUniqueKey { base::string16 OtherPossibleUsernamesToString( const PossibleUsernamesVector& possible_usernames); +// Converts a vector of possible passwords to string. +base::string16 AllPossiblePasswordsToString( + const std::vector<base::string16>& possible_passwords); + // 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_generation_util.h b/chromium/components/autofill/core/common/password_generation_util.h index af37a9e29ba..0d1547a779d 100644 --- a/chromium/components/autofill/core/common/password_generation_util.h +++ b/chromium/components/autofill/core/common/password_generation_util.h @@ -62,6 +62,12 @@ enum PasswordGenerationEvent { // new-password are set. AUTOCOMPLETE_ATTRIBUTES_ENABLED_GENERATION, + // Generation is triggered by the user from the context menu. + PASSWORD_GENERATION_CONTEXT_MENU_PRESSED, + + // Context menu with generation item was shown. + PASSWORD_GENERATION_CONTEXT_MENU_SHOWN, + // Number of enum entries, used for UMA histogram reporting macros. EVENT_ENUM_COUNT }; 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 19b46a8368d..3eb32852cc5 100644 --- a/chromium/components/autofill/core/common/save_password_progress_logger.cc +++ b/chromium/components/autofill/core/common/save_password_progress_logger.cc @@ -394,9 +394,6 @@ std::string SavePasswordProgressLogger::GetStringFromID( 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: 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 d55b04f5119..e2770ac9d3a 100644 --- a/chromium/components/autofill/core/common/save_password_progress_logger.h +++ b/chromium/components/autofill/core/common/save_password_progress_logger.h @@ -152,7 +152,6 @@ class SavePasswordProgressLogger { 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, |