chromium/components/autofill/core/browser/autofill_save_update_address_profile_delegate_ios_unittest.cc

// Copyright 2021 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/autofill_save_update_address_profile_delegate_ios.h"

#include <memory>

#include "base/test/mock_callback.h"
#include "base/test/scoped_feature_list.h"
#include "components/autofill/core/browser/autofill_client.h"
#include "components/autofill/core/browser/autofill_test_utils.h"
#include "components/autofill/core/browser/data_model/autofill_profile_test_api.h"
#include "components/autofill/ios/common/features.h"
#include "components/strings/grit/components_strings.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "ui/base/l10n/l10n_util.h"
namespace autofill {

namespace {

constexpr char16_t kTestEmail[] = u"[email protected]";
using ::testing::Property;
using profile_ref = base::optional_ref<const AutofillProfile>;
constexpr int kNavEntryId = 10;

}  // namespace

class AutofillSaveUpdateAddressProfileDelegateIOSTest : public testing::Test {
 protected:
  AutofillSaveUpdateAddressProfileDelegateIOSTest() = default;
  ~AutofillSaveUpdateAddressProfileDelegateIOSTest() override {}

  void SetUp() override {
    delegate_ = CreateAutofillSaveUpdateAddressProfileDelegate();
  }

  std::unique_ptr<AutofillSaveUpdateAddressProfileDelegateIOS>
  CreateAutofillSaveUpdateAddressProfileDelegate(
      AutofillProfile* original_profile = nullptr,
      std::optional<std::u16string> email = std::nullopt,
      bool is_migration_to_account = false,
      bool is_account_profile = false) {
    profile_ = std::make_unique<AutofillProfile>(test::GetFullProfile());
    if (is_account_profile) {
      test_api(*profile_).set_record_type(
          autofill::AutofillProfile::RecordType::kAccount);
    }
    return std::make_unique<AutofillSaveUpdateAddressProfileDelegateIOS>(
        *profile_, original_profile, email,
        /*locale=*/"en-US", is_migration_to_account, callback_.Get());
  }

  std::unique_ptr<AutofillProfile> profile_;
  base::MockCallback<AutofillClient::AddressProfileSavePromptCallback>
      callback_;
  infobars::InfoBarDelegate::NavigationDetails nav_details_that_expire_{
      .entry_id = kNavEntryId,
      .is_navigation_to_different_page = true,
      .did_replace_entry = false,
      .is_reload = true,
      .is_redirect = false,
      .is_form_submission = false,
      .has_user_gesture = true};
  std::unique_ptr<AutofillSaveUpdateAddressProfileDelegateIOS> delegate_ =
      CreateAutofillSaveUpdateAddressProfileDelegate();
};

// Tests that the callback is run with kAccepted on Accepted.
TEST_F(AutofillSaveUpdateAddressProfileDelegateIOSTest,
       HandleUserAction_Accepted) {
  EXPECT_CALL(callback_,
              Run(AutofillClient::AddressPromptUserDecision::kAccepted,
                  Property(&profile_ref::has_value, false)));
  delegate_->Accept();
}

// Tests that the callback is run with kDeclined on destruction.
TEST_F(AutofillSaveUpdateAddressProfileDelegateIOSTest,
       TestCallbackOnDestruction) {
  delegate_->Cancel();
  EXPECT_CALL(callback_,
              Run(AutofillClient::AddressPromptUserDecision::kDeclined,
                  Property(&profile_ref::has_value, false)));
  // The callback should run in the destructor.
  delegate_.reset();
}

// Tests that the callback is run with kAccepted on Accept.
TEST_F(AutofillSaveUpdateAddressProfileDelegateIOSTest, TestCallbackOnSave) {
  EXPECT_CALL(callback_,
              Run(AutofillClient::AddressPromptUserDecision::kAccepted,
                  Property(&profile_ref::has_value, false)));
  delegate_->Accept();
}

// Tests that the callback is run with kEditAccepted on EditAccepted.
TEST_F(AutofillSaveUpdateAddressProfileDelegateIOSTest,
       TestCallbackOnEditAccepted) {
  EXPECT_CALL(callback_,
              Run(AutofillClient::AddressPromptUserDecision::kEditAccepted,
                  testing::_));
  delegate_->EditAccepted();
}

// Tests that the callback is run with kNever on Never.
TEST_F(AutofillSaveUpdateAddressProfileDelegateIOSTest,
       HandleUserAction_NoThanks) {
  EXPECT_CALL(callback_, Run(AutofillClient::AddressPromptUserDecision::kNever,
                             Property(&profile_ref::has_value, false)));
  delegate_->Never();
}

// Tests that the infobar expires when reloading the page.
TEST_F(AutofillSaveUpdateAddressProfileDelegateIOSTest,
       ShouldExpire_True_WhenReload) {
  nav_details_that_expire_.is_reload = true;
  nav_details_that_expire_.entry_id = kNavEntryId;
  delegate_->set_nav_entry_id(kNavEntryId);
  EXPECT_TRUE(delegate_->ShouldExpire(nav_details_that_expire_));
}

// Tests that the infobar expires when new navigation ID.
TEST_F(AutofillSaveUpdateAddressProfileDelegateIOSTest,
       ShouldExpire_True_WhenDifferentNavEntryId) {
  nav_details_that_expire_.is_reload = false;
  nav_details_that_expire_.entry_id = kNavEntryId;
  const int different_nav_id = kNavEntryId - 1;
  delegate_->set_nav_entry_id(different_nav_id);

  EXPECT_TRUE(delegate_->ShouldExpire(nav_details_that_expire_));
}

// Tests that when the sticky infobar is disabled, having a user gesture isn't
// used as a condition to expire the infobar, hence setting the user gesture bit
// to false shouldn't change the returned value.
TEST_F(AutofillSaveUpdateAddressProfileDelegateIOSTest,
       ShouldExpire_True_WhenNoStickyInfobarAndNoUserGesture) {
  base::test::ScopedFeatureList feature_list;
  feature_list.InitAndDisableFeature(kAutofillStickyInfobarIos);

  nav_details_that_expire_.has_user_gesture = false;

  EXPECT_TRUE(delegate_->ShouldExpire(nav_details_that_expire_));
}

// Tests that when the sticky infobar is enabled, having a user gesture is
// used as a condition to expire the infobar, hence setting the user gesture bit
// to true should return true.
TEST_F(AutofillSaveUpdateAddressProfileDelegateIOSTest,
       ShouldExpire_True_WhenStickyInfobarAndUserGesture) {
  nav_details_that_expire_.has_user_gesture = true;
  EXPECT_TRUE(delegate_->ShouldExpire(nav_details_that_expire_));
}

// Tests that the infobar doesn't expire when the page is the same.
TEST_F(AutofillSaveUpdateAddressProfileDelegateIOSTest,
       ShouldExpire_False_WhenNoDifferentPage) {
  nav_details_that_expire_.is_navigation_to_different_page = false;
  EXPECT_FALSE(delegate_->ShouldExpire(nav_details_that_expire_));
}

// Tests that the infobar doesn't expire when only the history entry is
// replaced.
TEST_F(AutofillSaveUpdateAddressProfileDelegateIOSTest,
       ShouldExpire_False_WhenDidReplaceEntry) {
  nav_details_that_expire_.did_replace_entry = true;
  EXPECT_FALSE(delegate_->ShouldExpire(nav_details_that_expire_));
}

// Tests that the infobar doesn't expire when redirect.
TEST_F(AutofillSaveUpdateAddressProfileDelegateIOSTest,
       ShouldExpire_False_WhenRedirect) {
  nav_details_that_expire_.is_redirect = true;
  EXPECT_FALSE(delegate_->ShouldExpire(nav_details_that_expire_));
}

// Tests that the infobar doesn't expire when form submission.
TEST_F(AutofillSaveUpdateAddressProfileDelegateIOSTest,
       ShouldExpire_False_WhenFormSubmission) {
  nav_details_that_expire_.is_form_submission = true;
  EXPECT_FALSE(delegate_->ShouldExpire(nav_details_that_expire_));
}

// Tests that the infobar expires when no reload and the navigation entry ID
// didn't change.
TEST_F(AutofillSaveUpdateAddressProfileDelegateIOSTest,
       ShouldExpire_False_WhenNoReloadAndSameNavEntryId) {
  nav_details_that_expire_.is_reload = false;
  nav_details_that_expire_.entry_id = kNavEntryId;
  delegate_->set_nav_entry_id(kNavEntryId);
  EXPECT_FALSE(delegate_->ShouldExpire(nav_details_that_expire_));
}

// Tests that when the sticky infobar is enabled, having a user gesture is
// used as a condition to expire the infobar, hence setting the user gesture bit
// to false should return false.
TEST_F(AutofillSaveUpdateAddressProfileDelegateIOSTest,
       ShouldExpire_False_WhenStickyInfobar) {
  nav_details_that_expire_.has_user_gesture = false;
  EXPECT_FALSE(delegate_->ShouldExpire(nav_details_that_expire_));
}

struct DelegateStringsTestCase {
  bool is_migration;
  bool is_update;
  bool is_account_profile;
  int expected_message_action_text_id;
  int expected_message_text_id;
  absl::variant<int, std::u16string> expected_description_or_id;
};

class DelegateStringsTest
    : public AutofillSaveUpdateAddressProfileDelegateIOSTest,
      public ::testing::WithParamInterface<DelegateStringsTestCase> {
 protected:
  bool is_migration() const { return GetParam().is_migration; }
  bool is_update() const { return GetParam().is_update; }
  bool is_account_profile() const { return GetParam().is_account_profile; }
};

// Tests the message title, subtitle and action text strings.
TEST_P(DelegateStringsTest, TestStrings) {
  AutofillProfile original_profile = test::GetFullProfile();
  original_profile.SetInfo(NAME_FULL, u"John Doe", "en-US");

  delegate_ = CreateAutofillSaveUpdateAddressProfileDelegate(
      is_update() ? &original_profile : nullptr, kTestEmail, is_migration(),
      is_account_profile());

  const DelegateStringsTestCase& test_case = GetParam();
  EXPECT_EQ(
      delegate_->GetMessageActionText(),
      l10n_util::GetStringUTF16(test_case.expected_message_action_text_id));
  EXPECT_EQ(delegate_->GetMessageText(),
            l10n_util::GetStringUTF16(test_case.expected_message_text_id));
  if (absl::holds_alternative<int>(test_case.expected_description_or_id)) {
    EXPECT_EQ(
        delegate_->GetDescription(),
        l10n_util::GetStringFUTF16(
            absl::get<int>(test_case.expected_description_or_id), kTestEmail));
  } else {
    EXPECT_EQ(delegate_->GetDescription(),
              absl::get<std::u16string>(test_case.expected_description_or_id));
  }
}

INSTANTIATE_TEST_SUITE_P(
    AutofillSaveUpdateAddressProfileDelegateIOSTest,
    DelegateStringsTest,
    testing::Values(
        // Tests strings for the save profile views.
        DelegateStringsTestCase{
            false, false, false,
            IDS_IOS_AUTOFILL_SAVE_ADDRESS_MESSAGE_PRIMARY_ACTION,
            IDS_IOS_AUTOFILL_SAVE_ADDRESS_MESSAGE_TITLE,
            u"John H. Doe, 666 Erebus St."},
        // Tests strings for the save profile in Google Account views.
        DelegateStringsTestCase{
            false, false, true,
            IDS_IOS_AUTOFILL_SAVE_ADDRESS_MESSAGE_PRIMARY_ACTION,
            IDS_IOS_AUTOFILL_SAVE_ADDRESS_MESSAGE_TITLE,
            IDS_IOS_AUTOFILL_SAVE_ADDRESS_IN_ACCOUNT_MESSAGE_SUBTITLE},
        // Test strings for the migration view.
        DelegateStringsTestCase{
            true, false, false,
            IDS_IOS_AUTOFILL_SAVE_ADDRESS_MESSAGE_PRIMARY_ACTION,
            IDS_IOS_AUTOFILL_SAVE_ADDRESS_IN_ACCOUNT_MESSAGE_TITLE,
            u"You can use it across Google products"},
        // Test strings for the update views.
        DelegateStringsTestCase{
            false, true, false,
            IDS_IOS_AUTOFILL_UPDATE_ADDRESS_MESSAGE_PRIMARY_ACTION,
            IDS_IOS_AUTOFILL_UPDATE_ADDRESS_MESSAGE_TITLE,
            u"John Doe, 666 Erebus St."},
        // Test strings for the update in Google Account views.
        DelegateStringsTestCase{
            false, true, true,
            IDS_IOS_AUTOFILL_UPDATE_ADDRESS_MESSAGE_PRIMARY_ACTION,
            IDS_IOS_AUTOFILL_UPDATE_ADDRESS_MESSAGE_TITLE,
            u"John Doe, 666 Erebus St."}));

}  // namespace autofill