chromium/components/autofill/core/browser/payments/credit_card_save_manager_unittest.cc

// Copyright 2017 The Chromium Authors
// 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/payments/credit_card_save_manager.h"

#include <stddef.h>

#include <algorithm>
#include <list>
#include <map>
#include <memory>
#include <optional>
#include <string>
#include <utility>
#include <vector>

#include "base/memory/raw_ptr.h"
#include "base/metrics/metrics_hashes.h"
#include "base/strings/string_number_conversions.h"
#include "base/strings/utf_string_conversions.h"
#include "base/test/metrics/histogram_tester.h"
#include "base/test/scoped_feature_list.h"
#include "base/test/task_environment.h"
#include "base/time/time.h"
#include "build/build_config.h"
#include "components/autofill/core/browser/address_data_manager.h"
#include "components/autofill/core/browser/address_data_manager_test_api.h"
#include "components/autofill/core/browser/autofill_experiments.h"
#include "components/autofill/core/browser/autofill_test_utils.h"
#include "components/autofill/core/browser/data_model/autofill_profile.h"
#include "components/autofill/core/browser/data_model/credit_card.h"
#include "components/autofill/core/browser/form_data_importer.h"
#include "components/autofill/core/browser/metrics/autofill_metrics.h"
#include "components/autofill/core/browser/metrics/payments/credit_card_save_metrics.h"
#include "components/autofill/core/browser/payments/client_behavior_constants.h"
#include "components/autofill/core/browser/payments/iban_save_manager.h"
#include "components/autofill/core/browser/payments/payments_autofill_client.h"
#include "components/autofill/core/browser/payments/payments_customer_data.h"
#include "components/autofill/core/browser/payments/payments_util.h"
#include "components/autofill/core/browser/payments/test_credit_card_save_manager.h"
#include "components/autofill/core/browser/payments/test_legal_message_line.h"
#include "components/autofill/core/browser/payments/test_payments_autofill_client.h"
#include "components/autofill/core/browser/payments/test_payments_network_interface.h"
#include "components/autofill/core/browser/payments/test_virtual_card_enrollment_manager.h"
#include "components/autofill/core/browser/payments_data_manager.h"
#include "components/autofill/core/browser/personal_data_manager.h"
#include "components/autofill/core/browser/strike_databases/payments/test_credit_card_save_strike_database.h"
#include "components/autofill/core/browser/strike_databases/payments/test_strike_database.h"
#include "components/autofill/core/browser/test_autofill_client.h"
#include "components/autofill/core/browser/test_autofill_driver.h"
#include "components/autofill/core/browser/test_browser_autofill_manager.h"
#include "components/autofill/core/browser/test_form_data_importer.h"
#include "components/autofill/core/browser/test_payments_data_manager.h"
#include "components/autofill/core/browser/test_personal_data_manager.h"
#include "components/autofill/core/browser/webdata/autofill_webdata_service.h"
#include "components/autofill/core/common/autocomplete_parsing_util.h"
#include "components/autofill/core/common/autofill_features.h"
#include "components/autofill/core/common/autofill_payments_features.h"
#include "components/autofill/core/common/autofill_prefs.h"
#include "components/autofill/core/common/autofill_test_utils.h"
#include "components/autofill/core/common/credit_card_network_identifiers.h"
#include "components/autofill/core/common/credit_card_number_validation.h"
#include "components/autofill/core/common/form_data.h"
#include "components/autofill/core/common/form_data_test_api.h"
#include "components/autofill/core/common/form_field_data.h"
#include "components/prefs/pref_service.h"
#include "components/sync/test/test_sync_service.h"
#include "components/ukm/test_ukm_recorder.h"
#include "services/metrics/public/cpp/ukm_builders.h"
#include "services/metrics/public/cpp/ukm_source.h"
#include "services/network/public/cpp/shared_url_loader_factory.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "url/gurl.h"

namespace autofill {
namespace {

ASCIIToUTF16;
CreateTestAddressFormData;
CreateTestFormField;
_;
A;
AtLeast;
DoAll;
ElementsAre;
Field;
NiceMock;
Return;
SaveArg;
UnorderedElementsAre;

UkmCardUploadDecisionType;
UkmDeveloperEngagementType;
SaveCreditCardOptions;
SaveCardOfferUserDecision;

#if !BUILDFLAG(IS_IOS)
base::TimeDelta kVeryLargeDelta =;
#endif

// Used to configure form for |CreateTestCreditCardFormData|.
struct CreditCardFormOptions {};

}  // anonymous namespace

class MockPaymentsDataManager : public TestPaymentsDataManager {};

class MockPaymentsAutofillClient : public payments::TestPaymentsAutofillClient {};

// A mock AutofillClient using the `MockPaymentsDataManager` and
// `MockPaymentsAutofillClient`.
class MockAutofillClient : public TestAutofillClient {};

class MockVirtualCardEnrollmentManager
    : public TestVirtualCardEnrollmentManager {};

class CreditCardSaveManagerTest : public testing::Test {};

// Tests that credit card data are saved for forms on https
// TODO(crbug.com/40494359): Flaky on android_n5x_swarming_rel bot.
#if BUILDFLAG(IS_ANDROID)
#define MAYBE_ImportFormDataCreditCardHTTPS
#else
#define MAYBE_ImportFormDataCreditCardHTTPS
#endif
TEST_F(CreditCardSaveManagerTest, MAYBE_ImportFormDataCreditCardHTTPS) {}

// Tests that credit card data are saved for forms on http
// TODO(crbug.com/40494359): Flaky on android_n5x_swarming_rel bot.
#if BUILDFLAG(IS_ANDROID)
#define MAYBE_ImportFormDataCreditCardHTTP
#else
#define MAYBE_ImportFormDataCreditCardHTTP
#endif
TEST_F(CreditCardSaveManagerTest, MAYBE_ImportFormDataCreditCardHTTP) {}

// Tests that credit card data are saved when autocomplete=off for CC field.
// TODO(crbug.com/40494359): Flaky on android_n5x_swarming_rel bot.
#if BUILDFLAG(IS_ANDROID)
#define MAYBE_CreditCardSavedWhenAutocompleteOff
#else
#define MAYBE_CreditCardSavedWhenAutocompleteOff
#endif
TEST_F(CreditCardSaveManagerTest, MAYBE_CreditCardSavedWhenAutocompleteOff) {}

// Tests that credit card data are not saved when CC number does not pass the
// Luhn test.
TEST_F(CreditCardSaveManagerTest, InvalidCreditCardNumberIsNotSaved) {}

TEST_F(CreditCardSaveManagerTest, CreditCardDisabledDoesNotSave) {}

// TODO(crbug.com/40710040): Create an equivalent test for iOS, or skip
// permanently if the test doesn't apply to iOS flow.
#if !BUILDFLAG(IS_IOS)
TEST_F(CreditCardSaveManagerTest, UploadCreditCard_OnlyCountryInAddresses) {}
#endif

// Tests that local save is not called when expiration date is missing.
TEST_F(CreditCardSaveManagerTest, LocalCreditCard_ExpirationDateMissing) {}

// Tests local card save will still work as usual when supporting unfocused card
// form feature is already on.
TEST_F(CreditCardSaveManagerTest, LocalCreditCard_WithNonFocusableField) {}

// TODO(crbug.com/40947875): Remove duplicate code present between server and
// local CVC test suites below. Tests that when triggering
// AttemptToOfferCvcLocalSave function, SaveCard dialog will be triggered with
// `kCvcSaveOnly` option.
TEST_F(CreditCardSaveManagerTest,
       AttemptToOfferCvcLocalSave_ShouldShowSaveCardLocallyWithCvcSaveOnly) {}

// Tests that when triggering AttemptToOfferCvcUploadSave function, SaveCard
// dialog will be triggered with `kCvcSaveOnly` option.
TEST_F(CreditCardSaveManagerTest,
       AttemptToOfferCvcUploadSave_ShouldShowSaveCardWithCvcSaveOnly) {}

// Tests that when triggering AttemptToOfferCvcLocalSave function and user
// accept, UpdateCreditCard function will be triggered.
TEST_F(CreditCardSaveManagerTest,
       AttemptToOfferCvcLocalSave_ShouldUpdateCreditCardWhenUserAccept) {}

// Tests that adding a CVC clears all strikes for that card.
TEST_F(CreditCardSaveManagerTest,
       AttemptToOfferCvcLocalSave_ClearStrikesOnAdd) {}

// Tests that a CVC with max strikes does not offer save at all.
TEST_F(CreditCardSaveManagerTest,
       AttemptToOfferCvcLocalSave_NotOfferSaveWithMaxStrikes) {}

// Tests that max strikes will be added if user declines the save CVC
// offer.
TEST_F(CreditCardSaveManagerTest,
       AttemptToOfferCvcLocalSave_AddMaxStrikesIfDeclined) {}

// Tests that 1 strike will be added every time, the user ignores the save CVC
// offer.
TEST_F(CreditCardSaveManagerTest,
       AttemptToOfferCvcLocalSave_AddStrikeIfIgnored) {}

// Tests that 1 strike will be added if user ignores the save CVC offer and then
// max strikes for the next offer when the user declines it.
TEST_F(CreditCardSaveManagerTest,
       AttemptToOfferCvcLocalSave_AddCorrectStrikesForIgnoredAndDeclined) {}

// Tests that adding a CVC clears all strikes for that card.
TEST_F(CreditCardSaveManagerTest,
       AttemptToOfferCvcUploadSave_ClearStrikesOnAdd) {}

// Tests that a CVC with max strikes does not offer save at all.
TEST_F(CreditCardSaveManagerTest,
       AttemptToOfferCvcUploadSave_NotOfferSaveWithMaxStrikes) {}

// Tests that if the required delay has not passed, CVC save will not be offered
// even if the strike limit has not yet been reached.
TEST_F(CreditCardSaveManagerTest,
       AttemptToOfferCvcUploadSave_NotOfferSaveWithoutRequiredDelay) {}

// Tests that max strikes will be added if the user declines the save CVC
// offer.
TEST_F(CreditCardSaveManagerTest,
       AttemptToOfferCvcUploadSave_AddMaxStrikesIfDeclined) {}

// Tests that 1 strike will be added every time, the user ignores the save CVC
// offer.
TEST_F(CreditCardSaveManagerTest,
       AttemptToOfferCvcUploadSave_AddStrikeIfIgnored) {}

// Tests that 1 strike will be added if user ignores the save CVC offer and then
// max strikes for the next offer when the user declines it.
TEST_F(CreditCardSaveManagerTest,
       AttemptToOfferCvcUploadSave_AddCorrectStrikesForIgnoredAndDeclined) {}

// Tests that when triggering AttemptToOfferCvcUploadSave function and user
// accept, AddServerCvc function will be triggered with old empty CVC.
TEST_F(
    CreditCardSaveManagerTest,
    AttemptToOfferCvcUploadSave_UserAccept_ShouldAddServerCvcWithOldEmptyCvc) {}

// Tests that when triggering AttemptToOfferCvcUploadSave function and user
// accept, UpdateServerCvc function will be triggered with different non-empty
// CVC.
TEST_F(
    CreditCardSaveManagerTest,
    AttemptToOfferCvcUploadSave_UserAccept_ShouldUpdateServerCvcWithDifferentCvc) {}

class CvcStorageMetricTest
    : public CreditCardSaveManagerTest,
      public testing::WithParamInterface<CreditCard::RecordType> {};

// Tests that CVC save is not offered if the max strikes limit is reached.
TEST_P(CvcStorageMetricTest, AttemptToOfferCvcSave_NotOfferSaveWithMaxStrikes) {}

// Tests that if the required delay has not passed, CVC save will not be offered
// even if the strike limit has not yet been reached.
TEST_P(CvcStorageMetricTest,
       AttemptToOfferCvcSave_NotOfferSaveWithoutRequiredDelay) {}

INSTANTIATE_TEST_SUITE_P();

TEST_F(CreditCardSaveManagerTest, UploadCreditCard_NotSavedLocally) {}

TEST_F(CreditCardSaveManagerTest, UploadCreditCard_FeatureNotEnabled) {}

// TODO(crbug.com/40710040): Create an equivalent test for iOS, or skip
// permanently if the test doesn't apply to iOS flow.
#if !BUILDFLAG(IS_IOS)
TEST_F(CreditCardSaveManagerTest, UploadCreditCard_CvcUnavailable) {}
#endif

// TODO(crbug.com/40710040): Create an equivalent test for iOS, or skip
// permanently if the test doesn't apply to iOS flow.
#if !BUILDFLAG(IS_IOS)
TEST_F(CreditCardSaveManagerTest, UploadCreditCard_CvcInvalidLength) {}
#endif

// TODO(crbug.com/40710040): Create an equivalent test for iOS, or skip
// permanently if the test doesn't apply to iOS flow.
#if !BUILDFLAG(IS_IOS)
TEST_F(CreditCardSaveManagerTest, UploadCreditCard_MultipleCvcFields) {}
#endif

// TODO(crbug.com/40710040): Create an equivalent test for iOS, or skip
// permanently if the test doesn't apply to iOS flow.
#if !BUILDFLAG(IS_IOS)
TEST_F(CreditCardSaveManagerTest, UploadCreditCard_NoCvcFieldOnForm) {}
#endif

// TODO(crbug.com/40710040): Create an equivalent test for iOS, or skip
// permanently if the test doesn't apply to iOS flow.
#if !BUILDFLAG(IS_IOS)
TEST_F(CreditCardSaveManagerTest,
       UploadCreditCard_NoCvcFieldOnForm_InvalidCvcInNonCvcField) {}
#endif

// TODO(crbug.com/40710040): Create an equivalent test for iOS, or skip
// permanently if the test doesn't apply to iOS flow.
#if !BUILDFLAG(IS_IOS)
TEST_F(CreditCardSaveManagerTest,
       UploadCreditCard_NoCvcFieldOnForm_CvcInNonCvcField) {}
#endif

// TODO(crbug.com/40710040): Create an equivalent test for iOS, or skip
// permanently if the test doesn't apply to iOS flow.
#if !BUILDFLAG(IS_IOS)
TEST_F(CreditCardSaveManagerTest,
       UploadCreditCard_NoCvcFieldOnForm_CvcInAddressField) {}
#endif

// TODO(crbug.com/40710040): Create an equivalent test for iOS, or skip
// permanently if the test doesn't apply to iOS flow.
#if !BUILDFLAG(IS_IOS)
TEST_F(CreditCardSaveManagerTest, UploadCreditCard_NoProfileAvailable) {}
#endif

// TODO(crbug.com/40710040): Create an equivalent test for iOS, or skip
// permanently if the test doesn't apply to iOS flow.
#if !BUILDFLAG(IS_IOS)
TEST_F(CreditCardSaveManagerTest, UploadCreditCard_NoRecentlyUsedProfile) {}
#endif

// TODO(crbug.com/40710040): Create an equivalent test for iOS, or skip
// permanently if the test doesn't apply to iOS flow.
#if !BUILDFLAG(IS_IOS)
TEST_F(CreditCardSaveManagerTest,
       UploadCreditCard_CvcUnavailableAndNoProfileAvailable) {}
#endif

// TODO(crbug.com/40710040): Create an equivalent test for iOS, or skip
// permanently if the test doesn't apply to iOS flow.
#if !BUILDFLAG(IS_IOS)
TEST_F(CreditCardSaveManagerTest, UploadCreditCard_NoNameAvailable) {}
#endif

#if BUILDFLAG(IS_ANDROID)
TEST_F(CreditCardSaveManagerTest,
       AttemptToOfferCardUploadSave_AutofillEnableBottomSheetAccountEmail) {
  // Set up our credit card form data.
  FormData credit_card_form = CreateTestCreditCardFormData();
  FormsSeen(std::vector<FormData>(1, credit_card_form));

  // Edit the data, and submit.
  test_api(credit_card_form).field(0).set_value(u"Jane Doe");
  test_api(credit_card_form).field(1).set_value(u"4111111111111111");
  test_api(credit_card_form)
      .field(2)
      .set_value(ASCIIToUTF16(test::NextMonth()));
  test_api(credit_card_form).field(3).set_value(ASCIIToUTF16(test::NextYear()));
  test_api(credit_card_form).field(4).set_value(u"123");

  EXPECT_CALL(payments_client(), ConfirmSaveCreditCardLocally).Times(0);

  FormSubmitted(credit_card_form);

  EXPECT_TRUE(credit_card_save_manager_->CreditCardWasUploaded());

  // Confirm that client_behavior_signals vector does contain the
  // kShowAccountEmailInLegalMessage signal.
  std::vector<ClientBehaviorConstants> client_behavior_signals_in_request =
      payments_network_interface().client_behavior_signals_in_request();
  EXPECT_THAT(client_behavior_signals_in_request,
              testing::Contains(
                  ClientBehaviorConstants::kShowAccountEmailInLegalMessage));
}
#endif  // BUILDFLAG(IS_ANDROID)

TEST_F(CreditCardSaveManagerTest,
       AttemptToOfferCardUploadSave_SendSaveCvcSignalIfOfferingToSaveCvc) {}

TEST_F(CreditCardSaveManagerTest,
       AttemptToOfferCardUploadSave_DoNotSendSaveCvcSignalIfCvcEmpty) {}

TEST_F(
    CreditCardSaveManagerTest,
    AttemptToOfferCardUploadSave_DoNotSendSaveCvcSignalIfSaveCvvFeatureDisabled) {}

TEST_F(CreditCardSaveManagerTest,
       AttemptToOfferCardUploadSave_DoNotSendSaveCvcSignalIfSaveCvcPrefOff) {}

// TODO(crbug.com/40710040): Create an equivalent test for iOS, or skip
// permanently if the test doesn't apply to iOS flow.
#if !BUILDFLAG(IS_IOS)
TEST_F(CreditCardSaveManagerTest,
       UploadCreditCard_NoNameAvailableAndNoProfileAvailable) {}
#endif

// TODO(crbug.com/40710040): Create an equivalent test for iOS, or skip
// permanently if the test doesn't apply to iOS flow.
#if !BUILDFLAG(IS_IOS)
TEST_F(CreditCardSaveManagerTest, UploadCreditCard_ZipCodesConflict) {}
#endif

// TODO(crbug.com/40710040): Create an equivalent test for iOS, or skip
// permanently if the test doesn't apply to iOS flow.
#if !BUILDFLAG(IS_IOS)
TEST_F(CreditCardSaveManagerTest,
       UploadCreditCard_ZipCodesDoNotDiscardWhitespace) {}
#endif

// TODO(crbug.com/40710040): Create an equivalent test for iOS, or skip
// permanently if the test doesn't apply to iOS flow.
#if !BUILDFLAG(IS_IOS)
TEST_F(CreditCardSaveManagerTest, UploadCreditCard_ZipCodesHavePrefixMatch) {}
#endif

// TODO(crbug.com/40710040): Create an equivalent test for iOS, or skip
// permanently if the test doesn't apply to iOS flow.
#if !BUILDFLAG(IS_IOS)
TEST_F(CreditCardSaveManagerTest, UploadCreditCard_NoZipCodeAvailable) {}
#endif

// TODO(crbug.com/40710040): Create an equivalent test for iOS, or skip
// permanently if the test doesn't apply to iOS flow.
#if !BUILDFLAG(IS_IOS)
TEST_F(CreditCardSaveManagerTest, UploadCreditCard_CCFormHasMiddleInitial) {}
#endif

// TODO(crbug.com/40710040): Create an equivalent test for iOS, or skip
// permanently if the test doesn't apply to iOS flow.
#if !BUILDFLAG(IS_IOS)
TEST_F(CreditCardSaveManagerTest, UploadCreditCard_NoMiddleInitialInCCForm) {}
#endif

// TODO(crbug.com/40710040): Create an equivalent test for iOS, or skip
// permanently if the test doesn't apply to iOS flow.
#if !BUILDFLAG(IS_IOS)
TEST_F(CreditCardSaveManagerTest,
       UploadCreditCard_CCFormHasCardholderMiddleName) {}
#endif

// TODO(crbug.com/40710040): Create an equivalent test for iOS, or skip
// permanently if the test doesn't apply to iOS flow.
#if !BUILDFLAG(IS_IOS)
TEST_F(CreditCardSaveManagerTest, UploadCreditCard_CCFormHasAddressMiddleName) {}
#endif

// TODO(crbug.com/40710040): Create an equivalent test for iOS, or skip
// permanently if the test doesn't apply to iOS flow.
#if !BUILDFLAG(IS_IOS)
TEST_F(CreditCardSaveManagerTest, UploadCreditCard_NamesCanMismatch) {}
#endif

// TODO(crbug.com/40710040): Create an equivalent test for iOS, or skip
// permanently if the test doesn't apply to iOS flow.
#if !BUILDFLAG(IS_IOS)
TEST_F(CreditCardSaveManagerTest, UploadCreditCard_IgnoreOldProfiles) {}
#endif

TEST_F(
    CreditCardSaveManagerTest,
    UploadCreditCard_RequestCardholderNameIfNameMissingAndNoPaymentsCustomer) {}

TEST_F(
    CreditCardSaveManagerTest,
    UploadCreditCard_RequestCardholderNameIfNameConflictingAndNoPaymentsCustomer) {}

TEST_F(CreditCardSaveManagerTest,
       GoogleHostSite_ShouldNotOfferSaveIfUploadEnabled) {}

TEST_F(CreditCardSaveManagerTest,
       GoogleHostSite_ShouldOfferSaveIfUploadDisabled) {}

TEST_F(
    CreditCardSaveManagerTest,
    UploadCreditCard_DoNotRequestCardholderNameIfNameExistsAndNoPaymentsCustomer) {}

TEST_F(
    CreditCardSaveManagerTest,
    UploadCreditCard_DoNotRequestCardholderNameIfNameMissingAndPaymentsCustomer) {}

TEST_F(
    CreditCardSaveManagerTest,
    UploadCreditCard_DoNotRequestCardholderNameIfNameConflictingAndPaymentsCustomer) {}

// This test ensures |should_request_name_from_user_| is reset between offers to
// save.
TEST_F(
    CreditCardSaveManagerTest,
    UploadCreditCard_ShouldRequestCardholderName_ResetBetweenConsecutiveSaves) {}

// This test ensures |should_request_expiration_date_from_user_|
// is reset between offers to save.
TEST_F(
    CreditCardSaveManagerTest,
    UploadCreditCard_ShouldRequestExpirationDate_ResetBetweenConsecutiveSaves) {}

// This test ensures |should_request_expiration_date_from_user_|
// is false when Wallet Sync Transport is enabled.
TEST_F(
    CreditCardSaveManagerTest,
    UploadCreditCard_WalletSyncTransportEnabled_ShouldNotRequestExpirationDate) {}

// This test ensures |should_request_expiration_date_from_user_|
// is true when Wallet Sync Transport is not enabled.
TEST_F(
    CreditCardSaveManagerTest,
    UploadCreditCard_WalletSyncTransportNotEnabled_ShouldRequestExpirationDate) {}

TEST_F(
    CreditCardSaveManagerTest,
    UploadCreditCard_DoNotRequestExpirationDateIfMissingNameAndExpirationDate) {}

// iOS should always provide a valid expiration date when attempting to
// upload a Saved Card due to the Messages SaveCard modal.
TEST_F(CreditCardSaveManagerTest,
       UploadCreditCard_AlwaysRequestCardholderNameAndExpirationDateOnIOS) {}

// iOS should always provide a valid expiration date when attempting to
// upload a Saved Card due to the Messages SaveCard modal. The manager
// shouldn't handle expired dates.
#if !BUILDFLAG(IS_IOS)

TEST_F(CreditCardSaveManagerTest,
       UploadCreditCard_RequestExpirationDateViaExpDateFixFlow) {}

TEST_F(CreditCardSaveManagerTest,
       UploadCreditCard_RequestExpirationDateIfOnlyMonthMissing) {}

TEST_F(CreditCardSaveManagerTest,
       UploadCreditCard_RequestExpirationDateIfOnlyYearMissing) {}

TEST_F(CreditCardSaveManagerTest,
       UploadCreditCard_RequestExpirationDateIfExpirationDateInputIsExpired) {}

TEST_F(
    CreditCardSaveManagerTest,
    UploadCreditCard_RequestExpirationDateIfExpirationDateInputIsTwoDigitAndExpired) {}

// TODO(crbug.com/40710040): Create an equivalent test for iOS, or skip
// permanently if the test doesn't apply to iOS flow.
TEST_F(CreditCardSaveManagerTest, UploadCreditCard_UploadDetailsFails) {}

#endif  // !BUILDFLAG(IS_IOS)

TEST_F(CreditCardSaveManagerTest, DuplicateMaskedCreditCard_NoUpload) {}

TEST_F(CreditCardSaveManagerTest, NothingIfNothingFound) {}

TEST_F(CreditCardSaveManagerTest, DetectCvc) {}

TEST_F(CreditCardSaveManagerTest, DetectCardholderName) {}

TEST_F(CreditCardSaveManagerTest, DetectAddressName) {}

TEST_F(CreditCardSaveManagerTest, DetectCardholderAndAddressNameIfMatching) {}

TEST_F(CreditCardSaveManagerTest, DetectNoUniqueNameIfNamesConflict) {}

TEST_F(CreditCardSaveManagerTest, DetectPostalCode) {}

TEST_F(CreditCardSaveManagerTest, DetectNoUniquePostalCodeIfZipsConflict) {}

TEST_F(CreditCardSaveManagerTest, DetectAddressLine) {}

TEST_F(CreditCardSaveManagerTest, DetectLocality) {}

TEST_F(CreditCardSaveManagerTest, DetectAdministrativeArea) {}

TEST_F(CreditCardSaveManagerTest, DetectCountryCode) {}

TEST_F(CreditCardSaveManagerTest, DetectHasGooglePaymentAccount) {}

TEST_F(CreditCardSaveManagerTest, DetectEverythingAtOnce) {}

TEST_F(CreditCardSaveManagerTest, DetectSubsetOfPossibleFields) {}

// This test checks that ADDRESS_LINE, LOCALITY, ADMINISTRATIVE_AREA, and
// COUNTRY_CODE don't care about possible conflicts or consistency and are
// populated if even one address profile contains it.
TEST_F(CreditCardSaveManagerTest, DetectAddressComponentsAcrossProfiles) {}

// TODO(crbug.com/40710040): Create an equivalent test for iOS, or skip
// permanently if the test doesn't apply to iOS flow.
#if !BUILDFLAG(IS_IOS)
TEST_F(CreditCardSaveManagerTest,
       UploadCreditCard_LogAdditionalErrorsWithUploadDetailsFailure) {}
#endif

TEST_F(
    CreditCardSaveManagerTest,
    UploadCreditCard_ShouldOfferLocalSaveIfEverythingDetectedAndPaymentsDeclines) {}

TEST_F(
    CreditCardSaveManagerTest,
    UploadCreditCard_ShouldNotOfferLocalSaveIfSomethingNotDetectedAndPaymentsDeclines) {}

// TODO(crbug.com/40710040): Create an equivalent test for iOS, or skip
// permanently if the test doesn't apply to iOS flow.
#if !BUILDFLAG(IS_IOS)
TEST_F(CreditCardSaveManagerTest,
       UploadCreditCard_PaymentsDecidesOfferToSaveIfNoCvc) {}
#endif

// TODO(crbug.com/40710040): Create an equivalent test for iOS, or skip
// permanently if the test doesn't apply to iOS flow.
#if !BUILDFLAG(IS_IOS)
TEST_F(CreditCardSaveManagerTest,
       UploadCreditCard_PaymentsDecidesOfferToSaveIfNoName) {}
#endif

// TODO(crbug.com/40710040): Create an equivalent test for iOS, or skip
// permanently if the test doesn't apply to iOS flow.
#if !BUILDFLAG(IS_IOS)
TEST_F(CreditCardSaveManagerTest,
       UploadCreditCard_PaymentsDecidesOfferToSaveIfConflictingNames) {}
#endif

// TODO(crbug.com/40710040): Create an equivalent test for iOS, or skip
// permanently if the test doesn't apply to iOS flow.
#if !BUILDFLAG(IS_IOS)
TEST_F(CreditCardSaveManagerTest,
       UploadCreditCard_PaymentsDecidesOfferToSaveIfNoZip) {}
#endif

// TODO(crbug.com/40710040): Create an equivalent test for iOS, or skip
// permanently if the test doesn't apply to iOS flow.
#if !BUILDFLAG(IS_IOS)
TEST_F(CreditCardSaveManagerTest,
       UploadCreditCard_PaymentsDecidesOfferToSaveIfConflictingZips) {}
#endif

// TODO(crbug.com/40710040): Create an equivalent test for iOS, or skip
// permanently if the test doesn't apply to iOS flow.
#if !BUILDFLAG(IS_IOS)
TEST_F(CreditCardSaveManagerTest,
       UploadCreditCard_PaymentsDecidesOfferToSaveIfNothingFound) {}
#endif

TEST_F(CreditCardSaveManagerTest, UploadCreditCard_UploadOfLocalCard) {}

TEST_F(CreditCardSaveManagerTest, UploadCreditCard_UploadOfNewCard) {}

// This test ensures that if offer-to-upload is denied by Google Payments, local
// save is not offered if the card is already a local card.
TEST_F(CreditCardSaveManagerTest,
       UploadCreditCard_DenyingUploadOfLocalCardShouldNotOfferLocalSave) {}

#if !BUILDFLAG(IS_ANDROID)
// Android is skipped because the show email client behavior signal is always
// sent.
TEST_F(
    CreditCardSaveManagerTest,
    UploadCreditCard_DoNotAddAnyClientBehaviorSignalsToRequestIfExperimentsOff) {}
#endif  // !BUILDFLAG(IS_ANDROID)

TEST_F(CreditCardSaveManagerTest,
       UploadCreditCard_ShouldAddBillableServiceNumberInRequest) {}

TEST_F(CreditCardSaveManagerTest,
       UploadCreditCard_ShouldAddBillingCustomerNumberInRequest) {}

TEST_F(CreditCardSaveManagerTest,
       UploadCreditCard_ShouldAddUploadCardSourceInRequest) {}

// Tests that a card with some strikes (but not max strikes) should still show
// the save bubble/infobar.
TEST_F(CreditCardSaveManagerTest,
       LocallySaveCreditCard_NotEnoughStrikesStillShowsOfferToSave) {}

// Tests that a card with some strikes (but not max strikes) should still show
// the save bubble/infobar.
TEST_F(CreditCardSaveManagerTest,
       UploadCreditCard_NotEnoughStrikesStillShowsOfferToSave) {}

#if BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_IOS)
// Tests that a card with max strikes does not offer save on mobile at all.
TEST_F(CreditCardSaveManagerTest,
       LocallySaveCreditCard_MaxStrikesDisallowsSave) {
  credit_card_save_manager_->SetCreditCardUploadEnabled(false);
  TestCreditCardSaveStrikeDatabase credit_card_save_strike_database =
      TestCreditCardSaveStrikeDatabase(&strike_database());

  // Max out strikes for the card to be added.
  credit_card_save_strike_database.AddStrike("1111");
  credit_card_save_strike_database.AddStrike("1111");
  credit_card_save_strike_database.AddStrike("1111");
  EXPECT_EQ(3, credit_card_save_strike_database.GetStrikes("1111"));

  // Set up our credit card form data.
  FormData credit_card_form = CreateTestCreditCardFormData();
  FormsSeen(std::vector<FormData>(1, credit_card_form));
  ExpectFillableFormParsedUkm(1 /* num_fillable_forms_parsed */);

  // Edit the data, and submit.
  test_api(credit_card_form).field(0).set_value(u"Jane Doe");
  test_api(credit_card_form).field(1).set_value(u"4111111111111111");
  test_api(credit_card_form)
      .field(2)
      .set_value(ASCIIToUTF16(test::NextMonth()));
  test_api(credit_card_form).field(3).set_value(ASCIIToUTF16(test::NextYear()));
  test_api(credit_card_form).field(4).set_value(u"123");

  base::HistogramTester histogram_tester;

  // No form of credit card save should be shown.
  EXPECT_CALL(payments_client(), ConfirmSaveCreditCardLocally).Times(0);

  FormSubmitted(credit_card_form);

  EXPECT_FALSE(credit_card_save_manager_->CreditCardWasUploaded());

  // Verify that the correct histogram entry was logged.
  histogram_tester.ExpectBucketCount(
      "Autofill.StrikeDatabase.CreditCardSaveNotOfferedDueToMaxStrikes",
      AutofillMetrics::SaveTypeMetric::LOCAL, 1);
}

// TODO(crbug.com/40710040): Create an equivalent test for iOS, or skip
// permanently if the test doesn't apply to iOS flow.
#if !BUILDFLAG(IS_IOS)
// Tests that a card with max strikes does not offer save on mobile at all.
TEST_F(CreditCardSaveManagerTest, UploadCreditCard_MaxStrikesDisallowsSave) {
  TestCreditCardSaveStrikeDatabase credit_card_save_strike_database =
      TestCreditCardSaveStrikeDatabase(&strike_database());

  // Max out strikes for the card to be added.
  credit_card_save_strike_database.AddStrike("1111");
  credit_card_save_strike_database.AddStrike("1111");
  credit_card_save_strike_database.AddStrike("1111");
  EXPECT_EQ(3, credit_card_save_strike_database.GetStrikes("1111"));

  // 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 = CreateTestAddressFormData();
  FormsSeen(std::vector<FormData>(1, address_form));
  ExpectUniqueFillableFormParsedUkm();

  ManuallyFillAddressForm("Jane", "Doe", "77401", "US", &address_form);
  FormSubmitted(address_form);

  // Set up our credit card form data.
  FormData credit_card_form = CreateTestCreditCardFormData();
  FormsSeen(std::vector<FormData>(1, credit_card_form));
  ExpectFillableFormParsedUkm(2 /* num_fillable_forms_parsed */);

  // Edit the data, and submit.
  test_api(credit_card_form).field(0).set_value(u"Jane Doe");
  test_api(credit_card_form).field(1).set_value(u"4111111111111111");
  test_api(credit_card_form)
      .field(2)
      .set_value(ASCIIToUTF16(test::NextMonth()));
  test_api(credit_card_form).field(3).set_value(ASCIIToUTF16(test::NextYear()));
  test_api(credit_card_form).field(4).set_value(u"123");

  base::HistogramTester histogram_tester;

  // No form of credit card save should be shown.
  EXPECT_CALL(payments_client(), ConfirmSaveCreditCardLocally).Times(0);

  FormSubmitted(credit_card_form);

  EXPECT_FALSE(credit_card_save_manager_->CreditCardWasUploaded());

  // Verify that the correct histogram entries were logged.
  ExpectCardUploadDecision(
      histogram_tester,
      autofill_metrics::UPLOAD_NOT_OFFERED_MAX_STRIKES_ON_MOBILE);
  histogram_tester.ExpectBucketCount(
      "Autofill.StrikeDatabase.CreditCardSaveNotOfferedDueToMaxStrikes",
      AutofillMetrics::SaveTypeMetric::SERVER, 1);
  // Verify that the correct UKM was logged.
  ExpectCardUploadDecisionUkm(
      autofill_metrics::UPLOAD_NOT_OFFERED_MAX_STRIKES_ON_MOBILE);
}
#endif

#else  // !BUILDFLAG(IS_ANDROID) && !BUILDFLAG(IS_IOS)
// Tests that a card with max strikes should still offer to save on Desktop via
// the omnibox icon, but that the offer-to-save bubble itself is not shown.
TEST_F(CreditCardSaveManagerTest,
       LocallySaveCreditCard_MaxStrikesStillAllowsSave) {}

// Tests that a card with max strikes should still offer to save on Desktop via
// the omnibox icon, but that the offer-to-save bubble itself is not shown.
TEST_F(CreditCardSaveManagerTest, UploadCreditCard_MaxStrikesStillAllowsSave) {}

// Tests that 2 LocalCardMigrationStrikes are removed when cards are saved
// locally.
TEST_F(CreditCardSaveManagerTest,
       LocalCreditCard_LocalCardMigrationStrikesRemovedOnLocalSave) {}

// Tests that no LocalCardMigrationStrikes get removed due to cards being
// uploaded.
TEST_F(CreditCardSaveManagerTest,
       UploadCreditCard_NoLocalSaveMigrationStrikesRemovedOnUpload) {}
#endif

// Tests that adding a card clears all strikes for that card.
TEST_F(CreditCardSaveManagerTest, LocallySaveCreditCard_ClearStrikesOnAdd) {}

// Tests that adding a card clears all strikes for that card.
TEST_F(CreditCardSaveManagerTest, UploadCreditCard_ClearStrikesOnAdd) {}

// Tests that adding a card clears all strikes for that card.
TEST_F(CreditCardSaveManagerTest, LocallySaveCreditCard_NumStrikesLoggedOnAdd) {}

// Tests that adding a card clears all strikes for that card.
TEST_F(CreditCardSaveManagerTest, UploadCreditCard_NumStrikesLoggedOnAdd) {}

// Tests that one strike is added when upload failed and
// bubble is shown.
TEST_F(CreditCardSaveManagerTest,
       UploadCreditCard_NumStrikesLoggedOnUploadNotSuccess) {}

// Tests that one strike is added when upload times out on client-side and
// bubble is shown.
TEST_F(CreditCardSaveManagerTest,
       UploadCreditCard_NumStrikesLoggedOnUploadClientSideTimeout) {}

// Make sure that the PersonalDataManager gets notified when the user accepts
// an upload offer.
TEST_F(CreditCardSaveManagerTest, OnUserDidAcceptUpload_NotifiesPDM) {}

// Tests that if a card doesn't fall in any of the supported bin ranges, local
// save is offered rather than upload save.
TEST_F(CreditCardSaveManagerTest, UploadSaveNotOfferedForUnsupportedCard) {}

// Tests that if a card doesn't fall in any of the supported bin ranges, but is
// already saved, then local save is not offered.
TEST_F(CreditCardSaveManagerTest, LocalSaveNotOfferedForSavedUnsupportedCard) {}

// Tests that if a card falls in one of the supported bin ranges, upload save
// is offered.
TEST_F(CreditCardSaveManagerTest, UploadSaveOfferedForSupportedCard) {}

// Tests that if the PaymentsNetworkInterface returns an invalid legal message,
// upload should not be offered.
TEST_F(CreditCardSaveManagerTest, InvalidLegalMessageInOnDidGetUploadDetails) {}

// Tests that has_multiple_legal_lines is set correctly in
// SaveCreditCardOptions.
TEST_F(CreditCardSaveManagerTest, LegalMessageInOnDidGetUploadDetails) {}

// Tests that `has_same_last_four_as_server_card_but_different_expiration_date`
// is set correctly in SaveCreditCardOptions.
TEST_F(CreditCardSaveManagerTest, ExistingServerCard_DifferentExpiration) {}

class SaveCvcTest
    : public CreditCardSaveManagerTest,
      public testing::WithParamInterface<
          std::
              tuple<bool, bool, FormDataImporter::CreditCardImportType, bool>> {};

// Tests that server CVC is added to PaymentsAutofillTable during credit card
// upload save.
TEST_P(SaveCvcTest, OnDidUploadCard_SaveServerCvc) {}

// Tests that we should not offer CVC Save if the user entered empty CVC
// during checkout.
TEST_P(SaveCvcTest, ShouldNotOfferCvcSaveWithEmptyCvc) {}

// Tests that we should only offer CVC Save if we have an existing
// card that matches the card in the form.
TEST_P(SaveCvcTest, ShouldNotOfferCvcSaveWithoutExistingCard) {}

// Tests that we should not offer CVC save with same CVC.
TEST_P(SaveCvcTest, ShouldNotOfferCvcSaveWithSameCvc) {}

// Tests that we should OfferCvcLocalSave with expected input.
TEST_P(SaveCvcTest, ShouldOfferCvcLocalSave) {}

// Tests that we should OfferCvcUploadSave with expected input.
TEST_P(SaveCvcTest, ShouldOfferCvcUploadSave) {}

INSTANTIATE_TEST_SUITE_P();

class ProceedWithSavingIfApplicableTest
    : public CreditCardSaveManagerTest,
      public testing::WithParamInterface<
          std::
              tuple<bool, bool, FormDataImporter::CreditCardImportType, bool>> {};

// Tests that the correct SaveCardOption is passed.
TEST_P(ProceedWithSavingIfApplicableTest, CardWithCorrectSaveCardOption) {}

// Tests that ProceedWithSavingIfApplicable should initiate card save or upload
// flow with expected input.
TEST_P(ProceedWithSavingIfApplicableTest, ProceedWithSavingIfApplicable_Card) {}

// Tests that ProceedWithSavingIfApplicable should initiate CVC save or upload
// flow with expected input.
TEST_P(ProceedWithSavingIfApplicableTest, ProceedWithSavingIfApplicable_Cvc) {}

// Tests that ProceedWithSavingIfApplicable should initiate CVC save flow with
// expected input with duplicate case.
TEST_P(ProceedWithSavingIfApplicableTest,
       ProceedWithSavingIfApplicable_Cvc_Duplicate_Local) {}

// Tests that ProceedWithSavingIfApplicable should initiate CVC upload flow with
// expected input with duplicate case.
TEST_P(ProceedWithSavingIfApplicableTest,
       ProceedWithSavingIfApplicable_Cvc_Duplicate_Server) {}

INSTANTIATE_TEST_SUITE_P();

// Tests that server CVC is not added to PaymentsAutofillTable during credit
// card upload save if CVC was empty.
TEST_F(CreditCardSaveManagerTest,
       OnDidUploadCard_DoNotAddServerCvcIfCvcIsEmpty) {}

// Tests that server CVC is not added to PaymentsAutofillTable during credit
// card upload save if instrument_id was empty.
TEST_F(CreditCardSaveManagerTest,
       OnDidUploadCard_DoNotAddServerCvcIfInstrumentIdIsEmpty) {}

// Tests that `InitVirtualCardEnroll` hides the save card prompt before calling
// `VirtualCardEnrollmentManager::InitVirtualCardEnroll`.
TEST_F(CreditCardSaveManagerTest, InitVirtualCardEnroll) {}

class CreditCardSaveManagerWithLocalSaveFallbackTest
    : public CreditCardSaveManagerTest {};

// Tests that if server card upload fails, we fallback to a local card save.
TEST_F(CreditCardSaveManagerWithLocalSaveFallbackTest,
       OnDidUploadCard_FallbackToLocalSaveOnServerUploadFailure) {}

// Tests that the local card save is skipped if the card is missing the
// expiration date.
TEST_F(CreditCardSaveManagerWithLocalSaveFallbackTest,
       OnDidUploadCard_SkipLocalSaveIfMissingExpirationDate) {}

// Tests that the `RanLocalSaveFallback` metric records that a new local card
// was saved when a new local card is added during the local card save fallback
// for a server upload failure.
TEST_F(CreditCardSaveManagerWithLocalSaveFallbackTest,
       Metrics_OnDidUploadCard_FallbackToLocalSave_CardAdded) {}

// Tests that the `RanLocalSaveFallback` metric records that a new local card
// was not saved when the local card already exists during the local card save
// fallback for a server upload failure.
TEST_F(CreditCardSaveManagerWithLocalSaveFallbackTest,
       Metrics_OnDidUploadCard_FallbackToLocalSave_CardExists) {}

class CreditCardSaveManagerWithLoadingAndConfirmation
    : public CreditCardSaveManagerTest,
      public testing::WithParamInterface<bool> {};

INSTANTIATE_TEST_SUITE_P();

// Tests that `CreditCardSaveManager` directly calls `InitVirtualCardEnroll`
// for uploaded card that is eligible for enrollment when loading and
// confirmation is disabled.
TEST_P(CreditCardSaveManagerWithLoadingAndConfirmation,
       InitVirtualCardEnroll_LoadingAndConfirmation) {}

class CreditCardSaveManagerWithVirtualCardEnrollTestParameterized
    : public CreditCardSaveManagerTest,
      public testing::WithParamInterface<
          std::tuple<CreditCard::VirtualCardEnrollmentState, bool>> {};

// Tests that the fields in the card to be enrolled as virtual card are set
// correctly only when a card becomes eligible after upload.
TEST_P(CreditCardSaveManagerWithVirtualCardEnrollTestParameterized,
       PrepareUploadedCardForVirtualCardEnrollment) {}

INSTANTIATE_TEST_SUITE_P();

}  // namespace autofill