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

// Copyright 2023 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/autofill_save_card_ui_info.h"

#include <string>

#include "base/strings/string_number_conversions.h"
#include "base/strings/utf_string_conversions.h"
#include "build/branding_buildflags.h"
#include "components/autofill/core/browser/autofill_client.h"
#include "components/autofill/core/browser/autofill_test_utils.h"
#include "components/autofill/core/browser/payments/payments_autofill_client.h"
#include "components/autofill/core/browser/payments/test_legal_message_line.h"
#include "components/autofill/core/common/autofill_payments_features.h"
#include "components/autofill/core/common/credit_card_network_identifiers.h"
#include "components/grit/components_scaled_resources.h"
#include "components/signin/public/identity_manager/account_info.h"
#include "components/strings/grit/components_strings.h"
#include "testing/gmock/include/gmock/gmock-matchers.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/skia/include/core/SkBitmap.h"
#include "ui/base/l10n/l10n_util.h"
#include "ui/gfx/image/image_unittest_util.h"

namespace autofill {

using CardSaveType = payments::PaymentsAutofillClient::CardSaveType;

MATCHER_P(HasLegalMessageLineText, text, "A LegalMessageLine that has text.") {
  return base::UTF16ToUTF8(arg.text()) == text;
}

namespace {

// The different representations of a year needed by tests here.
struct Year {
  int integer;
  std::string string;
  std::u16string u16string;
  std::string last2_string;
};

Year SetUpNextYear() {
  std::string next_year = test::NextYear();
  int integer;
  EXPECT_TRUE(base::StringToInt(next_year, &integer));
  return Year{
      .integer = integer,
      .string = next_year,
      .u16string = base::ASCIIToUTF16(next_year),
      .last2_string = next_year.substr(next_year.length() - 2, 2),
  };
}

}  // namespace

AutofillSaveCardUiInfo AutofillSaveCardUiInfoForUploadSaveForTest(
    payments::PaymentsAutofillClient::SaveCreditCardOptions options,
    bool is_gpay_branded = false) {
  return AutofillSaveCardUiInfo::CreateForUploadSave(
      options, test::GetMaskedServerCard(), LegalMessageLines(), AccountInfo(),
      is_gpay_branded);
}

// Verify that the AutofillSaveCardUiInfo attributes for local save that are
// common across all prompts for are correctly set.
TEST(AutofillSaveCardUiInfoTestForLocalSave, VerifyCommonAttributes) {
  const Year next_year = SetUpNextYear();
  CreditCard card = test::GetCreditCard();
  test::SetCreditCardInfo(&card, "Chromium Dev", "4111111111111111", "3",
                          next_year.string.c_str(), "");
  card.SetNickname(u"My Card");
  auto ui_info =
      AutofillSaveCardUiInfo::CreateForLocalSave(/*options=*/{}, card);
  EXPECT_EQ(ui_info.issuer_icon_id,
            base::FeatureList::IsEnabled(
                features::kAutofillEnableNewCardArtAndNetworkImages)
                ? IDR_AUTOFILL_METADATA_CC_VISA
                : IDR_AUTOFILL_CC_VISA);
  EXPECT_THAT(base::UTF16ToUTF8(ui_info.card_label),
              testing::AllOf(testing::HasSubstr("My Card"),
                             testing::HasSubstr("1111")));
  EXPECT_THAT(base::UTF16ToUTF8(ui_info.card_sub_label),
              testing::AllOf(testing::HasSubstr(next_year.last2_string),
                             testing::HasSubstr("03")));
  EXPECT_EQ(ui_info.card_last_four_digits, u"1111");
  EXPECT_EQ(ui_info.cardholder_name, u"Chromium Dev");
  EXPECT_EQ(ui_info.expiration_date_month, u"03");
  EXPECT_EQ(ui_info.expiration_date_year, next_year.u16string);
  EXPECT_EQ(ui_info.card_description,
            u"My Card, Visa, 1111, expires 03/" + next_year.u16string);
  EXPECT_EQ(ui_info.is_for_upload, false);
  EXPECT_THAT(ui_info.legal_message_lines, testing::ElementsAre());
  EXPECT_EQ(ui_info.displayed_target_account_email, u"");
  EXPECT_TRUE(ui_info.displayed_target_account_avatar.IsEmpty());
  EXPECT_EQ(ui_info.cancel_text, l10n_util::GetStringUTF16(
                                     IDS_AUTOFILL_NO_THANKS_MOBILE_LOCAL_SAVE));
  EXPECT_EQ(ui_info.is_google_pay_branding_enabled, false);
}

// Verify that AutofillSaveCardUiInfo attributes are correctly set for the
// local-card-only-save infobar.
TEST(AutofillSaveCardUiInfoTestForLocalSave,
     VerifyAttributesForCardSaveOnlyInfobar) {
  auto ui_info = AutofillSaveCardUiInfo::CreateForLocalSave(
      /*options=*/{.card_save_type = CardSaveType::kCardSaveOnly},
      test::GetCreditCard());

  EXPECT_EQ(ui_info.logo_icon_id, IDR_INFOBAR_AUTOFILL_CC);
  EXPECT_EQ(ui_info.title_text, l10n_util::GetStringUTF16(
                                    IDS_AUTOFILL_SAVE_CARD_PROMPT_TITLE_LOCAL));
  EXPECT_EQ(ui_info.description_text, u"");
  EXPECT_EQ(ui_info.confirm_text,
            l10n_util::GetStringUTF16(IDS_AUTOFILL_SAVE_CARD_INFOBAR_ACCEPT));
}

#if BUILDFLAG(IS_ANDROID)
// Verify that AutofillSaveCardUiInfo attributes are correctly set for the
// local-card-only-save bottom sheet.
TEST(AutofillSaveCardUiInfoTestForLocalSave,
     VerifyAttributesForCardSaveOnlyBottomSheet) {
  base::test::ScopedFeatureList features(
      features::kAutofillEnableCvcStorageAndFilling);

  auto ui_info = AutofillSaveCardUiInfo::CreateForLocalSave(
      /*options=*/{.card_save_type = CardSaveType::kCardSaveOnly},
      test::GetCreditCard());

  EXPECT_EQ(ui_info.logo_icon_id, IDR_INFOBAR_AUTOFILL_CC);
  EXPECT_EQ(ui_info.title_text, l10n_util::GetStringUTF16(
                                    IDS_AUTOFILL_SAVE_CARD_PROMPT_TITLE_LOCAL));
  EXPECT_EQ(ui_info.description_text,
            l10n_util::GetStringUTF16(
                IDS_AUTOFILL_SAVE_CARD_ONLY_PROMPT_EXPLANATION_LOCAL));
  EXPECT_EQ(ui_info.confirm_text,
            l10n_util::GetStringUTF16(IDS_AUTOFILL_SAVE_CARD_INFOBAR_ACCEPT));
}

// Verify that AutofillSaveCardUiInfo attributes are correctly set for the
// local-card-save-with-CVC bottom sheet.
TEST(AutofillSaveCardUiInfoTestForLocalSave,
     VerifyAttributesForCardSaveWithCvcBottomSheet) {
  base::test::ScopedFeatureList features(
      features::kAutofillEnableCvcStorageAndFilling);

  auto ui_info = AutofillSaveCardUiInfo::CreateForLocalSave(
      /*options=*/{.card_save_type = CardSaveType::kCardSaveWithCvc},
      test::GetCreditCard());

  EXPECT_EQ(ui_info.logo_icon_id, IDR_INFOBAR_AUTOFILL_CC);
  EXPECT_EQ(ui_info.title_text, l10n_util::GetStringUTF16(
                                    IDS_AUTOFILL_SAVE_CARD_PROMPT_TITLE_LOCAL));
  EXPECT_EQ(ui_info.description_text,
            l10n_util::GetStringUTF16(
                IDS_AUTOFILL_SAVE_CARD_WITH_CVC_PROMPT_EXPLANATION_LOCAL));
  EXPECT_EQ(ui_info.confirm_text,
            l10n_util::GetStringUTF16(IDS_AUTOFILL_SAVE_CARD_INFOBAR_ACCEPT));
}

// Verify that AutofillSaveCardUiInfo attributes are correctly set for the
// local-CVC-only-save Message.
TEST(AutofillSaveCardUiInfoTestForLocalSave,
     VerifyAttributesForCvcSaveOnlyMessage) {
  auto ui_info = AutofillSaveCardUiInfo::CreateForLocalSave(
      /*options=*/{.card_save_type = CardSaveType::kCvcSaveOnly},
      test::GetCreditCard());

  EXPECT_EQ(ui_info.logo_icon_id, IDR_AUTOFILL_CC_GENERIC_PRIMARY);
  EXPECT_EQ(ui_info.title_text, l10n_util::GetStringUTF16(
                                    IDS_AUTOFILL_SAVE_CVC_PROMPT_TITLE_LOCAL));
  EXPECT_EQ(ui_info.description_text,
            l10n_util::GetStringUTF16(
                IDS_AUTOFILL_SAVE_CVC_PROMPT_EXPLANATION_LOCAL));
  EXPECT_EQ(
      ui_info.confirm_text,
      l10n_util::GetStringUTF16(IDS_AUTOFILL_SAVE_CVC_MESSAGE_SAVE_ACCEPT));
}
#endif  // #BUILDFLAG(IS_ANDROID)

// Test class for testing the upload save card prompts. Parametrized tests are
// run with GPay branding enabled/disabled.
class AutofillSaveCardUiInfoTestForUploadSave
    : public testing::Test,
      public testing::WithParamInterface<bool> {
 public:
  AutofillSaveCardUiInfoTestForUploadSave() = default;

  ~AutofillSaveCardUiInfoTestForUploadSave() override = default;

  bool is_gpay_branded() const { return GetParam(); }

 private:
  base::test::ScopedFeatureList features_;
};

INSTANTIATE_TEST_SUITE_P(All,
                         AutofillSaveCardUiInfoTestForUploadSave,
                         testing::Bool());

// Verify that the AutofillSaveCardUiInfo attributes for upload save that are
// common across all prompts for are correctly set.
TEST_P(AutofillSaveCardUiInfoTestForUploadSave, VerifyCommonAttributes) {
  const Year next_year = SetUpNextYear();
  CreditCard card = test::GetMaskedServerCard();
  card.SetNetworkForMaskedCard(kVisaCard);
  test::SetCreditCardInfo(&card, "Chromium Dev", "4111111111111111", "3",
                          next_year.string.c_str(), "");
  card.SetNickname(u"My Card");
  LegalMessageLines legal_message_lines(
      {TestLegalMessageLine("example message")});
  AccountInfo account_info;
  account_info.account_image = gfx::test::CreateImage(11, 17);
  account_info.email = "example email";

  auto ui_info = AutofillSaveCardUiInfo::CreateForUploadSave(
      /*options=*/{}, card, legal_message_lines, account_info,
      /*is_google_pay_branding_enabled=*/is_gpay_branded());
  EXPECT_EQ(ui_info.issuer_icon_id,
            base::FeatureList::IsEnabled(
                features::kAutofillEnableNewCardArtAndNetworkImages)
                ? IDR_AUTOFILL_METADATA_CC_VISA
                : IDR_AUTOFILL_CC_VISA);
  EXPECT_THAT(base::UTF16ToUTF8(ui_info.card_label),
              testing::AllOf(testing::HasSubstr("My Card"),
                             testing::HasSubstr("1111")));
  EXPECT_THAT(base::UTF16ToUTF8(ui_info.card_sub_label),
              testing::AllOf(testing::HasSubstr(next_year.last2_string),
                             testing::HasSubstr("03")));
  EXPECT_EQ(ui_info.card_last_four_digits, u"1111");
  EXPECT_EQ(ui_info.cardholder_name, u"Chromium Dev");
  EXPECT_EQ(ui_info.expiration_date_month, u"03");
  EXPECT_EQ(ui_info.expiration_date_year, next_year.u16string);
  EXPECT_EQ(ui_info.card_description,
            u"My Card, Visa, 1111, expires 03/" + next_year.u16string);
  EXPECT_EQ(ui_info.is_for_upload, true);
  EXPECT_THAT(ui_info.legal_message_lines,
              testing::ElementsAre(HasLegalMessageLineText("example message")));
  EXPECT_EQ(ui_info.displayed_target_account_email, u"example email");
  EXPECT_EQ(ui_info.displayed_target_account_avatar.Size(), gfx::Size(11, 17));
  EXPECT_EQ(
      ui_info.cancel_text,
      l10n_util::GetStringUTF16(IDS_AUTOFILL_NO_THANKS_MOBILE_UPLOAD_SAVE));
  EXPECT_EQ(ui_info.is_google_pay_branding_enabled, is_gpay_branded());
}

// Verify that AutofillSaveCardUiInfo attributes are correctly set for the
// upload-card-only-save infobar.
TEST_P(AutofillSaveCardUiInfoTestForUploadSave,
       VerifyAttributesForCardSaveOnlyInfobar) {
  auto ui_info = AutofillSaveCardUiInfoForUploadSaveForTest(
      /*options=*/{.card_save_type = CardSaveType::kCardSaveOnly},
      is_gpay_branded());

  EXPECT_EQ(ui_info.logo_icon_id, is_gpay_branded() ? IDR_AUTOFILL_GOOGLE_PAY
                                                    : IDR_INFOBAR_AUTOFILL_CC);
  EXPECT_EQ(
      ui_info.title_text,
      l10n_util::GetStringUTF16(
          is_gpay_branded() ? IDS_AUTOFILL_SAVE_CARD_PROMPT_TITLE_TO_CLOUD_V3
                            : IDS_AUTOFILL_SAVE_CARD_PROMPT_TITLE_TO_CLOUD));
  EXPECT_EQ(ui_info.description_text,
            is_gpay_branded()
                ? l10n_util::GetStringUTF16(
                      IDS_AUTOFILL_SAVE_CARD_PROMPT_UPLOAD_EXPLANATION_V3)
                : u"");
  EXPECT_EQ(ui_info.confirm_text,
            l10n_util::GetStringUTF16(IDS_AUTOFILL_SAVE_CARD_INFOBAR_ACCEPT));
}

#if BUILDFLAG(IS_ANDROID)
// Verify that AutofillSaveCardUiInfo attributes are correctly set for the
// upload-card-only-save bottom sheet.
TEST_P(AutofillSaveCardUiInfoTestForUploadSave,
       VerifyAttributesForCardSaveOnlyBottomSheet) {
  base::test::ScopedFeatureList features(
      features::kAutofillEnableCvcStorageAndFilling);

  auto ui_info = AutofillSaveCardUiInfoForUploadSaveForTest(
      /*options=*/{.card_save_type = CardSaveType::kCardSaveOnly},
      is_gpay_branded());

  EXPECT_EQ(ui_info.logo_icon_id, is_gpay_branded() ? IDR_AUTOFILL_GOOGLE_PAY
                                                    : IDR_INFOBAR_AUTOFILL_CC);
  EXPECT_EQ(
      ui_info.title_text,
      l10n_util::GetStringUTF16(
          is_gpay_branded() ? IDS_AUTOFILL_SAVE_CARD_PROMPT_TITLE_TO_CLOUD_V3
                            : IDS_AUTOFILL_SAVE_CARD_PROMPT_TITLE_TO_CLOUD));
  EXPECT_EQ(ui_info.description_text,
            is_gpay_branded()
                ? l10n_util::GetStringUTF16(
                      IDS_AUTOFILL_SAVE_CARD_PROMPT_UPLOAD_EXPLANATION_V3)
                : u"");
  EXPECT_EQ(ui_info.confirm_text,
            l10n_util::GetStringUTF16(IDS_AUTOFILL_SAVE_CARD_INFOBAR_ACCEPT));
}

// Verify that AutofillSaveCardUiInfo attributes are correctly set for the
// upload-card-save-with-CVC bottom sheet.
TEST_P(AutofillSaveCardUiInfoTestForUploadSave,
       VerifyAttributesForCardSaveWithCvcBottomSheet) {
  base::test::ScopedFeatureList features(
      features::kAutofillEnableCvcStorageAndFilling);

  auto ui_info = AutofillSaveCardUiInfoForUploadSaveForTest(
      /*options=*/{.card_save_type = CardSaveType::kCardSaveWithCvc},
      is_gpay_branded());

  EXPECT_EQ(ui_info.logo_icon_id, is_gpay_branded() ? IDR_AUTOFILL_GOOGLE_PAY
                                                    : IDR_INFOBAR_AUTOFILL_CC);
  EXPECT_EQ(
      ui_info.title_text,
      l10n_util::GetStringUTF16(
          is_gpay_branded() ? IDS_AUTOFILL_SAVE_CARD_PROMPT_TITLE_TO_CLOUD_V3
                            : IDS_AUTOFILL_SAVE_CARD_PROMPT_TITLE_TO_CLOUD));
  EXPECT_EQ(ui_info.description_text,
            is_gpay_branded()
                ? l10n_util::GetStringUTF16(
                      IDS_AUTOFILL_SAVE_CARD_WITH_CVC_PROMPT_EXPLANATION_UPLOAD)
                : u"");
  EXPECT_EQ(ui_info.confirm_text,
            l10n_util::GetStringUTF16(IDS_AUTOFILL_SAVE_CARD_INFOBAR_ACCEPT));
}

// Verify that AutofillSaveCardUiInfo attributes are correctly set for the
// upload-CVC-only-save message.
TEST_P(AutofillSaveCardUiInfoTestForUploadSave,
       VerifyAttributesForCvcSaveOnlyMessage) {
  auto ui_info = AutofillSaveCardUiInfoForUploadSaveForTest(
      /*options=*/{.card_save_type = CardSaveType::kCvcSaveOnly},
      is_gpay_branded());

  EXPECT_EQ(ui_info.logo_icon_id, IDR_AUTOFILL_CC_GENERIC_PRIMARY);
  EXPECT_EQ(
      ui_info.title_text,
      l10n_util::GetStringUTF16(IDS_AUTOFILL_SAVE_CVC_PROMPT_TITLE_TO_CLOUD));
  EXPECT_EQ(ui_info.description_text,
            l10n_util::GetStringUTF16(
                IDS_AUTOFILL_SAVE_CVC_PROMPT_EXPLANATION_UPLOAD));
  EXPECT_EQ(
      ui_info.confirm_text,
      l10n_util::GetStringUTF16(IDS_AUTOFILL_SAVE_CVC_MESSAGE_SAVE_ACCEPT));
}
#endif  // BUILDFLAG(IS_ANDROID)

// Tests that the card description is set correctly when there is no nickname.
TEST(AutofillSaveCardUiInfoTestForUploadSave,
     CreateForUploadSaveSetsCardDescriptionWithoutNickname) {
  const Year next_year = SetUpNextYear();
  CreditCard card = test::GetMaskedServerCard();
  card.SetNumber(u"4444333322221111");
  card.SetNetworkForMaskedCard(kVisaCard);
  card.SetExpirationMonth(3);
  card.SetExpirationYear(next_year.integer);

  auto ui_info = AutofillSaveCardUiInfo::CreateForUploadSave(
      /*options=*/{}, card, LegalMessageLines(), AccountInfo(),
      /*is_google_pay_branding_enabled=*/false);

  EXPECT_EQ(ui_info.card_description,
            u"Visa, 1111, expires 03/" + next_year.u16string);
}

// Tests that CreateForUploadSave() sets confirm text to "accept" when nothing
// more is requested from the user.
TEST(AutofillSaveCardUiInfoTestForUploadSave,
     CreateForUploadSaveSetsConfirmTextWhenNoPrompt) {
  auto ui_info = AutofillSaveCardUiInfoForUploadSaveForTest(
      /*options=*/{.card_save_type = CardSaveType::kCardSaveOnly});

  EXPECT_EQ(ui_info.confirm_text,
            l10n_util::GetStringUTF16(IDS_AUTOFILL_SAVE_CARD_INFOBAR_ACCEPT));
}

// Tests that CreateForUploadSave() sets confirm text to "continue" when the
// expiration is requested from the user.
TEST(AutofillSaveCardUiInfoTestForUploadSave,
     CreateForUploadSaveSetsConfirmTextWhenRequestingExpirationFromUser) {
  auto ui_info = AutofillSaveCardUiInfoForUploadSaveForTest(
      /*options=*/
      {
          .should_request_expiration_date_from_user = true,
      });

  EXPECT_EQ(ui_info.confirm_text,
            l10n_util::GetStringUTF16(IDS_AUTOFILL_SAVE_CARD_PROMPT_CONTINUE));
}

// Tests that CreateForUploadSave() sets confirm text to "continue" when the
// name is requested from the user.
TEST(AutofillSaveCardUiInfoTestForUploadSave,
     CreateForUploadSaveSetsConfirmTextWhenRequestingNameFromUser) {
  auto ui_info = AutofillSaveCardUiInfoForUploadSaveForTest(
      /*options=*/
      {
          .should_request_name_from_user = true,
      });

  EXPECT_EQ(ui_info.confirm_text,
            l10n_util::GetStringUTF16(IDS_AUTOFILL_SAVE_CARD_PROMPT_CONTINUE));
}

}  // namespace autofill