chromium/chrome/android/javatests/src/org/chromium/chrome/browser/autofill/settings/AutofillLocalCardEditorTest.java

// Copyright 2020 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

package org.chromium.chrome.browser.autofill.settings;

import static com.google.common.truth.Truth.assertThat;

import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;

import android.graphics.drawable.BitmapDrawable;
import android.os.Bundle;
import android.view.MenuItem;
import android.view.View;
import android.widget.Button;
import android.widget.ImageView;

import androidx.test.filters.MediumTest;
import androidx.test.filters.SmallTest;

import org.junit.After;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;

import org.chromium.base.ContextUtils;
import org.chromium.base.ThreadUtils;
import org.chromium.base.supplier.ObservableSupplierImpl;
import org.chromium.base.test.util.Features.DisableFeatures;
import org.chromium.base.test.util.Features.EnableFeatures;
import org.chromium.base.test.util.HistogramWatcher;
import org.chromium.base.test.util.UserActionTester;
import org.chromium.chrome.browser.autofill.AutofillEditorBase;
import org.chromium.chrome.browser.autofill.AutofillTestHelper;
import org.chromium.chrome.browser.autofill.PersonalDataManager;
import org.chromium.chrome.browser.autofill.PersonalDataManager.CreditCard;
import org.chromium.chrome.browser.autofill.PersonalDataManagerFactory;
import org.chromium.chrome.browser.flags.ChromeFeatureList;
import org.chromium.chrome.browser.settings.SettingsActivity;
import org.chromium.chrome.browser.settings.SettingsActivityTestRule;
import org.chromium.chrome.test.ChromeJUnit4ClassRunner;
import org.chromium.chrome.test.R;
import org.chromium.components.autofill.VirtualCardEnrollmentState;
import org.chromium.ui.modaldialog.ModalDialogManager;
import org.chromium.ui.test.util.modaldialog.FakeModalDialogManager;

/** Instrumentation tests for AutofillLocalCardEditor. */
@RunWith(ChromeJUnit4ClassRunner.class)
public class AutofillLocalCardEditorTest {
    @Rule public final AutofillTestRule rule = new AutofillTestRule();

    @Rule
    public final SettingsActivityTestRule<AutofillLocalCardEditor> mSettingsActivityTestRule =
            new SettingsActivityTestRule<>(AutofillLocalCardEditor.class);

    private static final CreditCard SAMPLE_LOCAL_CARD =
            new CreditCard(
                    /* guid= */ "",
                    /* origin= */ "",
                    /* isLocal= */ true,
                    /* name= */ "John Doe",
                    /* number= */ "4444333322221111",
                    /* obfuscatedNumber= */ "",
                    /* month= */ "5",
                    AutofillTestHelper.nextYear(),
                    /* basicCardIssuerNetwork= */ "visa",
                    /* issuerIconDrawableId= */ 0,
                    /* billingAddressId= */ "",
                    /* serverId= */ "");
    private static final CreditCard SAMPLE_LOCAL_CARD_WITH_CVC =
            new CreditCard(
                    /* guid= */ "",
                    /* origin= */ "",
                    /* isLocal= */ true,
                    /* isVirtual= */ false,
                    /* name= */ "John Doe",
                    /* number= */ "4444111111111111",
                    /* obfuscatedNumber= */ "",
                    /* month= */ "5",
                    AutofillTestHelper.nextYear(),
                    /* basicCardIssuerNetwork= */ "visa",
                    /* issuerIconDrawableId= */ 0,
                    /* billingAddressId= */ "",
                    /* serverId= */ "",
                    /* instrumentId= */ 0,
                    /* cardLabel= */ "",
                    /* nickname= */ "",
                    /* cardArtUrl= */ null,
                    /* virtualCardEnrollmentState= */ VirtualCardEnrollmentState
                            .UNENROLLED_AND_ELIGIBLE,
                    /* productDescription= */ "",
                    /* cardNameForAutofillDisplay= */ "",
                    /* obfuscatedLastFourDigits= */ "",
                    /* cvc= */ "123");
    private static final CreditCard SAMPLE_AMEX_CARD_WITH_CVC =
            new CreditCard(
                    /* guid= */ "",
                    /* origin= */ "",
                    /* isLocal= */ true,
                    /* isVirtual= */ false,
                    /* name= */ "John Doe",
                    /* number= */ "378282246310005",
                    /* obfuscatedNumber= */ "",
                    /* month= */ "5",
                    AutofillTestHelper.nextYear(),
                    /* basicCardIssuerNetwork= */ "amex",
                    /* issuerIconDrawableId= */ 0,
                    /* billingAddressId= */ "",
                    /* serverId= */ "",
                    /* instrumentId= */ 0,
                    /* cardLabel= */ "",
                    /* nickname= */ "",
                    /* cardArtUrl= */ null,
                    /* virtualCardEnrollmentState= */ VirtualCardEnrollmentState
                            .UNENROLLED_AND_ELIGIBLE,
                    /* productDescription= */ "",
                    /* cardNameForAutofillDisplay= */ "",
                    /* obfuscatedLastFourDigits= */ "",
                    /* cvc= */ "1234");

    private static final CreditCard SAMPLE_MASKED_SERVER_CARD =
            new CreditCard(
                    /* guid= */ "1",
                    /* origin= */ "",
                    /* isLocal= */ false,
                    /* isVirtual= */ false,
                    /* name= */ "John Doe",
                    /* number= */ "4444222211111111",
                    /* obfuscatedNumber= */ "",
                    /* month= */ "5",
                    AutofillTestHelper.nextYear(),
                    /* basicCardIssuerNetwork= */ "visa",
                    /* issuerIconDrawableId= */ 0,
                    /* billingAddressId= */ "",
                    /* serverId= */ "",
                    /* instrumentId= */ 123,
                    /* cardLabel= */ "",
                    /* nickname= */ "",
                    /* cardArtUrl= */ null,
                    /* virtualCardEnrollmentState= */ VirtualCardEnrollmentState.ENROLLED,
                    /* productDescription= */ "",
                    /* cardNameForAutofillDisplay= */ "",
                    /* obfuscatedLastFourDigits= */ "• • • • 1111",
                    /* cvc= */ "");

    private static final String AMEX_CARD_NUMBER = "378282246310005";
    private static final String AMEX_CARD_NUMBER_PREFIX = "37";
    private static final String NON_AMEX_CARD_NUMBER = "4111111111111111";
    private static final String NON_AMEX_CARD_NUMBER_PREFIX = "41";

    @Mock private ObservableSupplierImpl<ModalDialogManager> mModalDialogManagerSupplierMock;
    @Mock private PersonalDataManager mPersonalDataManagerMock;
    private AutofillTestHelper mAutofillTestHelper;
    private UserActionTester mActionTester;

    @Before
    public void setUp() {
        MockitoAnnotations.initMocks(this);
        mAutofillTestHelper = new AutofillTestHelper();
        mActionTester = new UserActionTester();
    }

    @After
    public void tearDown() {
        mActionTester.tearDown();
    }

    @Test
    @MediumTest
    public void nicknameFieldEmpty_cardDoesNotHaveNickname() throws Exception {
        String guid = mAutofillTestHelper.setCreditCard(SAMPLE_LOCAL_CARD);

        SettingsActivity activity =
                mSettingsActivityTestRule.startSettingsActivity(fragmentArgs(guid));

        AutofillLocalCardEditor autofillLocalCardEditorFragment =
                (AutofillLocalCardEditor) activity.getMainFragment();
        assertThat(autofillLocalCardEditorFragment.mNicknameText.getText().toString()).isEmpty();
        assertThat(autofillLocalCardEditorFragment.mDoneButton.isEnabled()).isFalse();
    }

    @Test
    @MediumTest
    public void nicknameFieldSet_cardHasNickname() throws Exception {
        String nickname = "test nickname";
        SAMPLE_LOCAL_CARD.setNickname(nickname);
        String guid = mAutofillTestHelper.setCreditCard(SAMPLE_LOCAL_CARD);

        SettingsActivity activity =
                mSettingsActivityTestRule.startSettingsActivity(fragmentArgs(guid));

        AutofillLocalCardEditor autofillLocalCardEditorFragment =
                (AutofillLocalCardEditor) activity.getMainFragment();
        assertThat(autofillLocalCardEditorFragment.mNicknameText.getText().toString())
                .isEqualTo(nickname);
        // If the nickname is not modified the Done button should be disabled.
        assertThat(autofillLocalCardEditorFragment.mDoneButton.isEnabled()).isFalse();
    }

    @Test
    @MediumTest
    public void testNicknameFieldIsShown() throws Exception {
        String guid = mAutofillTestHelper.setCreditCard(SAMPLE_LOCAL_CARD);

        SettingsActivity activity =
                mSettingsActivityTestRule.startSettingsActivity(fragmentArgs(guid));

        AutofillLocalCardEditor autofillLocalCardEditorFragment =
                (AutofillLocalCardEditor) activity.getMainFragment();
        assertThat(autofillLocalCardEditorFragment.mNicknameLabel.getVisibility())
                .isEqualTo(View.VISIBLE);
    }

    @Test
    @MediumTest
    public void testInvalidNicknameShowsErrorMessage() throws Exception {
        String guid = mAutofillTestHelper.setCreditCard(SAMPLE_LOCAL_CARD);
        SettingsActivity activity =
                mSettingsActivityTestRule.startSettingsActivity(fragmentArgs(guid));
        AutofillLocalCardEditor autofillLocalCardEditorFragment =
                (AutofillLocalCardEditor) activity.getMainFragment();

        ThreadUtils.runOnUiThreadBlocking(
                () -> {
                    try {
                        autofillLocalCardEditorFragment.mNicknameText.setText("Nickname 123");
                    } catch (Exception e) {
                        Assert.fail("Failed to set the nickname");
                    }
                });

        assertThat(autofillLocalCardEditorFragment.mNicknameLabel.getError())
                .isEqualTo(
                        activity.getResources()
                                .getString(R.string.autofill_credit_card_editor_invalid_nickname));
        // Since the nickname has an error, the done button should be disabled.
        assertThat(autofillLocalCardEditorFragment.mDoneButton.isEnabled()).isFalse();
    }

    @Test
    @MediumTest
    public void testErrorMessageHiddenAfterNicknameIsEditedFromInvalidToValid() throws Exception {
        String guid = mAutofillTestHelper.setCreditCard(SAMPLE_LOCAL_CARD);
        SettingsActivity activity =
                mSettingsActivityTestRule.startSettingsActivity(fragmentArgs(guid));
        AutofillLocalCardEditor autofillLocalCardEditorFragment =
                (AutofillLocalCardEditor) activity.getMainFragment();
        ThreadUtils.runOnUiThreadBlocking(
                () -> {
                    try {
                        autofillLocalCardEditorFragment.mNicknameText.setText("Nickname 123");
                    } catch (Exception e) {
                        Assert.fail("Failed to set the nickname");
                    }
                });
        assertThat(autofillLocalCardEditorFragment.mNicknameLabel.getError())
                .isEqualTo(
                        activity.getResources()
                                .getString(R.string.autofill_credit_card_editor_invalid_nickname));

        // Set the nickname to valid one.
        ThreadUtils.runOnUiThreadBlocking(
                () -> {
                    try {
                        autofillLocalCardEditorFragment.mNicknameText.setText("Valid Nickname");
                    } catch (Exception e) {
                        Assert.fail("Failed to set the nickname");
                    }
                });

        assertThat(autofillLocalCardEditorFragment.mNicknameLabel.getError()).isNull();
        assertThat(autofillLocalCardEditorFragment.mDoneButton.isEnabled()).isTrue();
    }

    @Test
    @MediumTest
    public void testErrorMessageHiddenAfterNicknameIsEditedFromInvalidToEmpty() throws Exception {
        String guid = mAutofillTestHelper.setCreditCard(SAMPLE_LOCAL_CARD);
        SettingsActivity activity =
                mSettingsActivityTestRule.startSettingsActivity(fragmentArgs(guid));
        AutofillLocalCardEditor autofillLocalCardEditorFragment =
                (AutofillLocalCardEditor) activity.getMainFragment();
        ThreadUtils.runOnUiThreadBlocking(
                () -> {
                    try {
                        autofillLocalCardEditorFragment.mNicknameText.setText("Nickname 123");
                    } catch (Exception e) {
                        Assert.fail("Failed to set the nickname");
                    }
                });
        assertThat(autofillLocalCardEditorFragment.mNicknameLabel.getError())
                .isEqualTo(
                        activity.getResources()
                                .getString(R.string.autofill_credit_card_editor_invalid_nickname));

        // Clear the nickname.
        ThreadUtils.runOnUiThreadBlocking(
                () -> {
                    try {
                        autofillLocalCardEditorFragment.mNicknameText.setText(null);
                    } catch (Exception e) {
                        Assert.fail("Failed to set the nickname");
                    }
                });

        assertThat(autofillLocalCardEditorFragment.mNicknameLabel.getError()).isNull();
        assertThat(autofillLocalCardEditorFragment.mDoneButton.isEnabled()).isTrue();
    }

    @Test
    @MediumTest
    public void testNicknameLengthCappedAt25Characters() throws Exception {
        String veryLongNickname = "This is a very very long nickname";
        String guid = mAutofillTestHelper.setCreditCard(SAMPLE_LOCAL_CARD);

        SettingsActivity activity =
                mSettingsActivityTestRule.startSettingsActivity(fragmentArgs(guid));
        AutofillLocalCardEditor autofillLocalCardEditorFragment =
                (AutofillLocalCardEditor) activity.getMainFragment();

        ThreadUtils.runOnUiThreadBlocking(
                () -> {
                    try {
                        autofillLocalCardEditorFragment.mNicknameText.setText(veryLongNickname);
                    } catch (Exception e) {
                        Assert.fail("Failed to set the nickname");
                    }
                });

        assertThat(autofillLocalCardEditorFragment.mNicknameText.getText().toString())
                .isEqualTo(veryLongNickname.substring(0, 25));
    }

    private Bundle fragmentArgs(String guid) {
        Bundle args = new Bundle();
        args.putString(AutofillEditorBase.AUTOFILL_GUID, guid);
        return args;
    }

    @Test
    @MediumTest
    @DisableFeatures({ChromeFeatureList.AUTOFILL_ENABLE_CVC_STORAGE})
    public void testExpirationDateSpinnerAreShownWhenCvcFlagOff() throws Exception {
        String guid = mAutofillTestHelper.setCreditCard(SAMPLE_LOCAL_CARD_WITH_CVC);

        SettingsActivity activity =
                mSettingsActivityTestRule.startSettingsActivity(fragmentArgs(guid));

        AutofillLocalCardEditor autofillLocalCardEditorFragment =
                (AutofillLocalCardEditor) activity.getMainFragment();
        assertThat(autofillLocalCardEditorFragment.mExpirationMonth.getVisibility())
                .isEqualTo(View.VISIBLE);
        assertThat(autofillLocalCardEditorFragment.mExpirationYear.getVisibility())
                .isEqualTo(View.VISIBLE);
        assertThat(autofillLocalCardEditorFragment.mExpirationDate).isNull();
        assertThat(autofillLocalCardEditorFragment.mCvc).isNull();
    }

    @Test
    @MediumTest
    @EnableFeatures({ChromeFeatureList.AUTOFILL_ENABLE_CVC_STORAGE})
    public void testExpirationDateAndSecurityCodeFieldsAreShown() throws Exception {
        String guid = mAutofillTestHelper.setCreditCard(SAMPLE_LOCAL_CARD_WITH_CVC);

        SettingsActivity activity =
                mSettingsActivityTestRule.startSettingsActivity(fragmentArgs(guid));

        AutofillLocalCardEditor autofillLocalCardEditorFragment =
                (AutofillLocalCardEditor) activity.getMainFragment();
        assertThat(autofillLocalCardEditorFragment.mExpirationDate.getVisibility())
                .isEqualTo(View.VISIBLE);
        assertThat(autofillLocalCardEditorFragment.mCvc.getVisibility()).isEqualTo(View.VISIBLE);
        assertThat(autofillLocalCardEditorFragment.mExpirationMonth).isNull();
        assertThat(autofillLocalCardEditorFragment.mExpirationYear).isNull();
    }

    @Test
    @MediumTest
    @EnableFeatures({ChromeFeatureList.AUTOFILL_ENABLE_CVC_STORAGE})
    public void securityCodeFieldSet_cardHasCvc() throws Exception {
        String cvc = "234";
        SAMPLE_LOCAL_CARD_WITH_CVC.setCvc(cvc);
        String guid = mAutofillTestHelper.setCreditCard(SAMPLE_LOCAL_CARD_WITH_CVC);

        SettingsActivity activity =
                mSettingsActivityTestRule.startSettingsActivity(fragmentArgs(guid));

        AutofillLocalCardEditor autofillLocalCardEditorFragment =
                (AutofillLocalCardEditor) activity.getMainFragment();
        assertThat(autofillLocalCardEditorFragment.mCvc.getText().toString()).isEqualTo(cvc);
        assertThat(autofillLocalCardEditorFragment.mDoneButton.isEnabled()).isFalse();
    }

    @Test
    @MediumTest
    @EnableFeatures({ChromeFeatureList.AUTOFILL_ENABLE_CVC_STORAGE})
    public void testSecurityCode_whenAmExCardIsSet_usesAmExCvcHintImage() throws Exception {
        String guid = mAutofillTestHelper.setCreditCard(SAMPLE_AMEX_CARD_WITH_CVC);

        SettingsActivity activity =
                mSettingsActivityTestRule.startSettingsActivity(fragmentArgs(guid));
        AutofillLocalCardEditor autofillLocalCardEditorFragment =
                (AutofillLocalCardEditor) activity.getMainFragment();

        verifyCvcHintImage(
                autofillLocalCardEditorFragment, /* expectedImage= */ R.drawable.cvc_icon_amex);
    }

    @Test
    @MediumTest
    @EnableFeatures({ChromeFeatureList.AUTOFILL_ENABLE_CVC_STORAGE})
    public void testSecurityCode_whenCardIsNotSet_usesDefaultCvcHintImage() throws Exception {
        SettingsActivity activity = mSettingsActivityTestRule.startSettingsActivity();
        AutofillLocalCardEditor autofillLocalCardEditorFragment =
                (AutofillLocalCardEditor) activity.getMainFragment();

        verifyCvcHintImage(
                autofillLocalCardEditorFragment, /* expectedImage= */ R.drawable.cvc_icon);
    }

    @Test
    @MediumTest
    @EnableFeatures({ChromeFeatureList.AUTOFILL_ENABLE_CVC_STORAGE})
    public void testSecurityCode_whenAmExCardNumberIsEntered_usesAmExCvcHintImage()
            throws Exception {
        String guid = mAutofillTestHelper.setCreditCard(SAMPLE_LOCAL_CARD_WITH_CVC);

        SettingsActivity activity =
                mSettingsActivityTestRule.startSettingsActivity(fragmentArgs(guid));
        AutofillLocalCardEditor autofillLocalCardEditorFragment =
                (AutofillLocalCardEditor) activity.getMainFragment();
        setCardNumberOnEditor(autofillLocalCardEditorFragment, AMEX_CARD_NUMBER);

        verifyCvcHintImage(
                autofillLocalCardEditorFragment, /* expectedImage= */ R.drawable.cvc_icon_amex);
    }

    @Test
    @MediumTest
    @EnableFeatures({ChromeFeatureList.AUTOFILL_ENABLE_CVC_STORAGE})
    public void testSecurityCode_whenNonAmExCardNumberIsEntered_usesDefaultCvcHintImage()
            throws Exception {
        String guid = mAutofillTestHelper.setCreditCard(SAMPLE_LOCAL_CARD_WITH_CVC);

        SettingsActivity activity =
                mSettingsActivityTestRule.startSettingsActivity(fragmentArgs(guid));
        AutofillLocalCardEditor autofillLocalCardEditorFragment =
                (AutofillLocalCardEditor) activity.getMainFragment();
        setCardNumberOnEditor(autofillLocalCardEditorFragment, NON_AMEX_CARD_NUMBER);

        verifyCvcHintImage(
                autofillLocalCardEditorFragment, /* expectedImage= */ R.drawable.cvc_icon);
    }

    @Test
    @MediumTest
    @EnableFeatures({ChromeFeatureList.AUTOFILL_ENABLE_CVC_STORAGE})
    public void testSecurityCode_whenNumberIsChangedFromAmExToNonAmEx_usesDefaultCvcHintImage()
            throws Exception {
        String guid = mAutofillTestHelper.setCreditCard(SAMPLE_AMEX_CARD_WITH_CVC);

        SettingsActivity activity =
                mSettingsActivityTestRule.startSettingsActivity(fragmentArgs(guid));
        AutofillLocalCardEditor autofillLocalCardEditorFragment =
                (AutofillLocalCardEditor) activity.getMainFragment();
        setCardNumberOnEditor(autofillLocalCardEditorFragment, NON_AMEX_CARD_NUMBER);

        verifyCvcHintImage(
                autofillLocalCardEditorFragment, /* expectedImage= */ R.drawable.cvc_icon);
    }

    @Test
    @MediumTest
    @EnableFeatures({ChromeFeatureList.AUTOFILL_ENABLE_CVC_STORAGE})
    public void testSecurityCode_whenNumberIsChangedFromNonAmExToAmEx_usesAmExCvcHintImage()
            throws Exception {
        String guid = mAutofillTestHelper.setCreditCard(SAMPLE_LOCAL_CARD_WITH_CVC);

        SettingsActivity activity =
                mSettingsActivityTestRule.startSettingsActivity(fragmentArgs(guid));
        AutofillLocalCardEditor autofillLocalCardEditorFragment =
                (AutofillLocalCardEditor) activity.getMainFragment();
        setCardNumberOnEditor(autofillLocalCardEditorFragment, AMEX_CARD_NUMBER);

        verifyCvcHintImage(
                autofillLocalCardEditorFragment, /* expectedImage= */ R.drawable.cvc_icon_amex);
    }

    @Test
    @MediumTest
    @EnableFeatures({ChromeFeatureList.AUTOFILL_ENABLE_CVC_STORAGE})
    public void expirationDateFieldSet_cardHasExpirationDate() throws Exception {
        String validExpirationMonth = "12";
        String validExpirationYear = AutofillTestHelper.nextYear();
        SAMPLE_LOCAL_CARD_WITH_CVC.setMonth(validExpirationMonth);
        SAMPLE_LOCAL_CARD_WITH_CVC.setYear(validExpirationYear);
        String guid = mAutofillTestHelper.setCreditCard(SAMPLE_LOCAL_CARD_WITH_CVC);

        SettingsActivity activity =
                mSettingsActivityTestRule.startSettingsActivity(fragmentArgs(guid));

        AutofillLocalCardEditor autofillLocalCardEditorFragment =
                (AutofillLocalCardEditor) activity.getMainFragment();
        assertThat(autofillLocalCardEditorFragment.mExpirationDate.getText().toString())
                .isEqualTo(
                        String.format(
                                "%s/%s", validExpirationMonth, validExpirationYear.substring(2)));
        assertThat(autofillLocalCardEditorFragment.mDoneButton.isEnabled()).isFalse();
    }

    @Test
    @MediumTest
    @EnableFeatures({ChromeFeatureList.AUTOFILL_ENABLE_CVC_STORAGE})
    public void testExpirationDate_whenInvalidDate_showsErrorMessage() throws Exception {
        String invalidExpirationMonth = "14";
        String validExpirationYear = AutofillTestHelper.nextYear();
        String guid = mAutofillTestHelper.setCreditCard(SAMPLE_LOCAL_CARD_WITH_CVC);

        SettingsActivity activity =
                mSettingsActivityTestRule.startSettingsActivity(fragmentArgs(guid));
        AutofillLocalCardEditor autofillLocalCardEditorFragment =
                (AutofillLocalCardEditor) activity.getMainFragment();
        setExpirationDateOnEditor(
                autofillLocalCardEditorFragment,
                String.format("%s/%s", invalidExpirationMonth, validExpirationYear.substring(2)));

        assertThat(autofillLocalCardEditorFragment.mExpirationDate.getError())
                .isEqualTo(
                        activity.getResources()
                                .getString(
                                        R.string
                                                .autofill_credit_card_editor_invalid_expiration_date));
        assertThat(autofillLocalCardEditorFragment.mDoneButton.isEnabled()).isFalse();
    }

    @Test
    @MediumTest
    @EnableFeatures({ChromeFeatureList.AUTOFILL_ENABLE_CVC_STORAGE})
    public void testExpirationDate_whenDateInPast_showsErrorMessage() throws Exception {
        String validExpirationMonth = "12";
        String invalidPastExpirationYear = "2020";
        String guid = mAutofillTestHelper.setCreditCard(SAMPLE_LOCAL_CARD_WITH_CVC);

        SettingsActivity activity =
                mSettingsActivityTestRule.startSettingsActivity(fragmentArgs(guid));
        AutofillLocalCardEditor autofillLocalCardEditorFragment =
                (AutofillLocalCardEditor) activity.getMainFragment();
        setExpirationDateOnEditor(
                autofillLocalCardEditorFragment,
                String.format(
                        "%s/%s", validExpirationMonth, invalidPastExpirationYear.substring(2)));

        assertThat(autofillLocalCardEditorFragment.mExpirationDate.getError())
                .isEqualTo(
                        activity.getResources()
                                .getString(R.string.autofill_credit_card_editor_expired_card));
        assertThat(autofillLocalCardEditorFragment.mDoneButton.isEnabled()).isFalse();
    }

    @Test
    @MediumTest
    @EnableFeatures({ChromeFeatureList.AUTOFILL_ENABLE_CVC_STORAGE})
    public void testExpirationDate_whenDateIsCorrected_removesErrorMessage() throws Exception {
        String validExpirationMonth = "12";
        String invalidPastExpirationYear = "2020";
        String validExpirationYear = AutofillTestHelper.nextYear();
        SAMPLE_LOCAL_CARD_WITH_CVC.setMonth(validExpirationMonth);
        SAMPLE_LOCAL_CARD_WITH_CVC.setYear(invalidPastExpirationYear);
        String guid = mAutofillTestHelper.setCreditCard(SAMPLE_LOCAL_CARD_WITH_CVC);

        SettingsActivity activity =
                mSettingsActivityTestRule.startSettingsActivity(fragmentArgs(guid));

        AutofillLocalCardEditor autofillLocalCardEditorFragment =
                (AutofillLocalCardEditor) activity.getMainFragment();
        assertThat(autofillLocalCardEditorFragment.mExpirationDate.getError())
                .isEqualTo(
                        activity.getResources()
                                .getString(R.string.autofill_credit_card_editor_expired_card));
        assertThat(autofillLocalCardEditorFragment.mDoneButton.isEnabled()).isFalse();

        setExpirationDateOnEditor(
                autofillLocalCardEditorFragment,
                String.format("%s/%s", validExpirationMonth, validExpirationYear.substring(2)));

        assertThat(autofillLocalCardEditorFragment.mExpirationDate.getError()).isNull();
        assertThat(autofillLocalCardEditorFragment.mDoneButton.isEnabled()).isTrue();
    }

    @Test
    @MediumTest
    @EnableFeatures({ChromeFeatureList.AUTOFILL_ENABLE_CVC_STORAGE})
    public void testExpirationDate_whenDateIsEditedFromValidToIncomplete_disablesSaveButton()
            throws Exception {
        String validExpirationMonth = "12";
        String validExpirationYear = AutofillTestHelper.nextYear();
        String guid = mAutofillTestHelper.setCreditCard(SAMPLE_LOCAL_CARD_WITH_CVC);

        SettingsActivity activity =
                mSettingsActivityTestRule.startSettingsActivity(fragmentArgs(guid));
        AutofillLocalCardEditor autofillLocalCardEditorFragment =
                (AutofillLocalCardEditor) activity.getMainFragment();
        setExpirationDateOnEditor(
                autofillLocalCardEditorFragment,
                String.format("%s/%s", validExpirationMonth, validExpirationYear.substring(2)));

        assertThat(autofillLocalCardEditorFragment.mExpirationDate.getError()).isNull();
        assertThat(autofillLocalCardEditorFragment.mDoneButton.isEnabled()).isTrue();

        setExpirationDateOnEditor(
                autofillLocalCardEditorFragment,
                String.format("%s/%s", validExpirationMonth, /* expiration year */ ""));

        assertThat(autofillLocalCardEditorFragment.mDoneButton.isEnabled()).isFalse();
    }

    @Test
    @MediumTest
    @EnableFeatures({ChromeFeatureList.AUTOFILL_ENABLE_CVC_STORAGE})
    public void testExpirationDate_whenDateIsEditedFromValidToEmpty_disablesSaveButton()
            throws Exception {
        String validExpirationMonth = "12";
        String validExpirationYear = AutofillTestHelper.nextYear();
        String guid = mAutofillTestHelper.setCreditCard(SAMPLE_LOCAL_CARD_WITH_CVC);

        SettingsActivity activity =
                mSettingsActivityTestRule.startSettingsActivity(fragmentArgs(guid));
        AutofillLocalCardEditor autofillLocalCardEditorFragment =
                (AutofillLocalCardEditor) activity.getMainFragment();
        setExpirationDateOnEditor(
                autofillLocalCardEditorFragment,
                String.format("%s/%s", validExpirationMonth, validExpirationYear.substring(2)));

        assertThat(autofillLocalCardEditorFragment.mExpirationDate.getError()).isNull();
        assertThat(autofillLocalCardEditorFragment.mDoneButton.isEnabled()).isTrue();

        setExpirationDateOnEditor(autofillLocalCardEditorFragment, /* date= */ "");

        assertThat(autofillLocalCardEditorFragment.mDoneButton.isEnabled()).isFalse();
    }

    @Test
    @MediumTest
    @EnableFeatures({ChromeFeatureList.AUTOFILL_ENABLE_CVC_STORAGE})
    public void
            testExpirationDate_whenCorrectingOnlyNickname_keepsSaveButtonDisabledDueToInvalidDate()
                    throws Exception {
        String validNickname = "valid";
        String invalidNickname = "Invalid 123";
        String invalidPastExpirationYear = "2020";
        String validExpirationMonth = "12";
        String validExpirationYear = AutofillTestHelper.nextYear();
        String guid = mAutofillTestHelper.setCreditCard(SAMPLE_LOCAL_CARD_WITH_CVC);

        SettingsActivity activity =
                mSettingsActivityTestRule.startSettingsActivity(fragmentArgs(guid));
        AutofillLocalCardEditor autofillLocalCardEditorFragment =
                (AutofillLocalCardEditor) activity.getMainFragment();
        setExpirationDateOnEditor(
                autofillLocalCardEditorFragment,
                String.format("%s/%s", validExpirationMonth, validExpirationYear.substring(2)));
        setNicknameOnEditor(autofillLocalCardEditorFragment, validNickname);

        assertThat(autofillLocalCardEditorFragment.mDoneButton.isEnabled()).isTrue();

        setExpirationDateOnEditor(
                autofillLocalCardEditorFragment,
                String.format(
                        "%s/%s", validExpirationMonth, invalidPastExpirationYear.substring(2)));
        setNicknameOnEditor(autofillLocalCardEditorFragment, invalidNickname);

        assertThat(autofillLocalCardEditorFragment.mDoneButton.isEnabled()).isFalse();

        setNicknameOnEditor(autofillLocalCardEditorFragment, validNickname);

        assertThat(autofillLocalCardEditorFragment.mDoneButton.isEnabled()).isFalse();
    }

    @Test
    @MediumTest
    public void deleteCreditCardConfirmationDialog_deleteEntryCanceled_dialogDismissed()
            throws Exception {
        String guid = mAutofillTestHelper.setCreditCard(SAMPLE_LOCAL_CARD);
        SettingsActivity activity =
                mSettingsActivityTestRule.startSettingsActivity(fragmentArgs(guid));
        AutofillLocalCardEditor autofillLocalCardEditorFragment =
                (AutofillLocalCardEditor) activity.getMainFragment();

        PersonalDataManagerFactory.setInstanceForTesting(mPersonalDataManagerMock);

        FakeModalDialogManager fakeModalDialogManager =
                new FakeModalDialogManager(ModalDialogManager.ModalDialogType.APP);
        openDeletePaymentMethodConfirmationDialog(
                autofillLocalCardEditorFragment, fakeModalDialogManager);

        // Verify the dialog is open
        Assert.assertNotNull(fakeModalDialogManager.getShownDialogModel());
        ThreadUtils.runOnUiThreadBlocking(() -> fakeModalDialogManager.clickNegativeButton());

        // Verify the dialog is closed
        Assert.assertNull(fakeModalDialogManager.getShownDialogModel());

        // Verify the card entry is not deleted
        verify(mPersonalDataManagerMock, never()).deleteCreditCard(guid);
    }

    @Test
    @MediumTest
    public void
            deleteCreditCardConfirmationDialog_deleteEntryConfirmed_dialogDismissedAndEntryDeleted()
                    throws Exception {
        String guid = mAutofillTestHelper.setCreditCard(SAMPLE_LOCAL_CARD);
        SettingsActivity activity =
                mSettingsActivityTestRule.startSettingsActivity(fragmentArgs(guid));
        AutofillLocalCardEditor autofillLocalCardEditorFragment =
                (AutofillLocalCardEditor) activity.getMainFragment();

        PersonalDataManagerFactory.setInstanceForTesting(mPersonalDataManagerMock);

        FakeModalDialogManager fakeModalDialogManager =
                new FakeModalDialogManager(ModalDialogManager.ModalDialogType.APP);
        openDeletePaymentMethodConfirmationDialog(
                autofillLocalCardEditorFragment, fakeModalDialogManager);

        // Verify the dialog is open
        Assert.assertNotNull(fakeModalDialogManager.getShownDialogModel());
        ThreadUtils.runOnUiThreadBlocking(() -> fakeModalDialogManager.clickPositiveButton());

        // Verify the dialog is closed
        Assert.assertNull(fakeModalDialogManager.getShownDialogModel());

        // Verify the card entry is deleted
        verify(mPersonalDataManagerMock, times(1)).deleteCreditCard(guid);
    }

    @Test
    @MediumTest
    @DisableFeatures({ChromeFeatureList.AUTOFILL_ENABLE_CVC_STORAGE})
    public void testRecordHistogram_whenNewCreditCardIsAddedWithoutCvc() throws Exception {
        // Set 4 existing cards.
        mAutofillTestHelper.setCreditCard(SAMPLE_LOCAL_CARD);
        mAutofillTestHelper.setCreditCard(SAMPLE_LOCAL_CARD_WITH_CVC);
        mAutofillTestHelper.setCreditCard(SAMPLE_AMEX_CARD_WITH_CVC);
        mAutofillTestHelper.addServerCreditCard(SAMPLE_MASKED_SERVER_CARD);

        // Expect histogram to record 4 for 4 existing cards.
        HistogramWatcher saveCardCountHistogram =
                HistogramWatcher.newBuilder()
                        .expectIntRecord(
                                AutofillLocalCardEditor.CARD_COUNT_BEFORE_ADDING_NEW_CARD_HISTOGRAM,
                                4)
                        .build();

        SettingsActivity activity = mSettingsActivityTestRule.startSettingsActivity();
        AutofillLocalCardEditor autofillLocalCardEditorFragment =
                (AutofillLocalCardEditor) activity.getMainFragment();
        setCardNumberOnEditor(autofillLocalCardEditorFragment, NON_AMEX_CARD_NUMBER);
        setExpirationMonthSelectionOnEditor(
                autofillLocalCardEditorFragment, /* monthSelection= */ 1);
        setExpirationYearSelectionOnEditor(autofillLocalCardEditorFragment, /* yearSelection= */ 1);
        performButtonClickOnEditor(autofillLocalCardEditorFragment.mDoneButton);

        saveCardCountHistogram.assertExpected();
    }

    @Test
    @MediumTest
    @EnableFeatures({ChromeFeatureList.AUTOFILL_ENABLE_CVC_STORAGE})
    public void testRecordHistogram_whenNewCreditCardIsAddedWithCvc() throws Exception {
        // Set 4 existing cards.
        mAutofillTestHelper.setCreditCard(SAMPLE_LOCAL_CARD);
        mAutofillTestHelper.setCreditCard(SAMPLE_LOCAL_CARD_WITH_CVC);
        mAutofillTestHelper.setCreditCard(SAMPLE_AMEX_CARD_WITH_CVC);
        mAutofillTestHelper.addServerCreditCard(SAMPLE_MASKED_SERVER_CARD);

        // Expect histogram to record 4 for 4 existing cards.
        HistogramWatcher saveCardCountHistogram =
                HistogramWatcher.newBuilder()
                        .expectIntRecord(
                                AutofillLocalCardEditor.CARD_COUNT_BEFORE_ADDING_NEW_CARD_HISTOGRAM,
                                4)
                        .build();

        SettingsActivity activity = mSettingsActivityTestRule.startSettingsActivity();
        AutofillLocalCardEditor autofillLocalCardEditorFragment =
                (AutofillLocalCardEditor) activity.getMainFragment();
        setCardNumberOnEditor(autofillLocalCardEditorFragment, NON_AMEX_CARD_NUMBER);
        setExpirationDateOnEditor(
                autofillLocalCardEditorFragment,
                String.format("12/%s", AutofillTestHelper.nextYear().substring(2)));
        setSecurityCodeOnEditor(autofillLocalCardEditorFragment, /* code= */ "321");
        performButtonClickOnEditor(autofillLocalCardEditorFragment.mDoneButton);

        saveCardCountHistogram.assertExpected();
    }

    @Test
    @MediumTest
    @EnableFeatures({ChromeFeatureList.AUTOFILL_ENABLE_CVC_STORAGE})
    public void testRecordUserAction_whenNewCreditCardIsAddedWithCvc() throws Exception {
        String validExpirationYear = AutofillTestHelper.nextYear();
        String validExpirationMonth = "12";

        SettingsActivity activity = mSettingsActivityTestRule.startSettingsActivity();
        AutofillLocalCardEditor autofillLocalCardEditorFragment =
                (AutofillLocalCardEditor) activity.getMainFragment();
        setCardNumberOnEditor(autofillLocalCardEditorFragment, NON_AMEX_CARD_NUMBER);
        setExpirationDateOnEditor(
                autofillLocalCardEditorFragment,
                String.format("%s/%s", validExpirationMonth, validExpirationYear.substring(2)));
        setSecurityCodeOnEditor(autofillLocalCardEditorFragment, /* code= */ "321");
        performButtonClickOnEditor(autofillLocalCardEditorFragment.mDoneButton);

        Assert.assertTrue(
                "User action should be logged.",
                mActionTester.getActions().contains("AutofillCreditCardsAddedWithCvc"));
    }

    @Test
    @MediumTest
    @EnableFeatures({ChromeFeatureList.AUTOFILL_ENABLE_CVC_STORAGE})
    public void testRecordUserAction_whenExistingCreditCardWithoutCvcIsEditedAndCvcIsLeftBlank()
            throws Exception {
        String validExpirationYear = AutofillTestHelper.nextYear();
        String validExpirationMonth = "12";
        String guid = mAutofillTestHelper.setCreditCard(SAMPLE_LOCAL_CARD);

        SettingsActivity activity =
                mSettingsActivityTestRule.startSettingsActivity(fragmentArgs(guid));
        AutofillLocalCardEditor autofillLocalCardEditorFragment =
                (AutofillLocalCardEditor) activity.getMainFragment();
        setExpirationDateOnEditor(
                autofillLocalCardEditorFragment,
                String.format("%s/%s", validExpirationMonth, validExpirationYear.substring(2)));
        performButtonClickOnEditor(autofillLocalCardEditorFragment.mDoneButton);

        Assert.assertTrue(
                "User action should be logged.",
                mActionTester.getActions().contains("AutofillCreditCardsEditedAndCvcWasLeftBlank"));
    }

    @Test
    @MediumTest
    @EnableFeatures({ChromeFeatureList.AUTOFILL_ENABLE_CVC_STORAGE})
    public void testRecordUserAction_whenExistingCreditCardWithoutCvcIsEditedAndCvcIsAdded()
            throws Exception {
        String guid = mAutofillTestHelper.setCreditCard(SAMPLE_LOCAL_CARD);

        SettingsActivity activity =
                mSettingsActivityTestRule.startSettingsActivity(fragmentArgs(guid));
        AutofillLocalCardEditor autofillLocalCardEditorFragment =
                (AutofillLocalCardEditor) activity.getMainFragment();
        setSecurityCodeOnEditor(autofillLocalCardEditorFragment, /* code= */ "321");
        performButtonClickOnEditor(autofillLocalCardEditorFragment.mDoneButton);

        Assert.assertTrue(
                "User action should be logged.",
                mActionTester.getActions().contains("AutofillCreditCardsEditedAndCvcWasAdded"));
    }

    @Test
    @MediumTest
    @EnableFeatures({ChromeFeatureList.AUTOFILL_ENABLE_CVC_STORAGE})
    public void testRecordUserAction_whenExistingCreditCardWithCvcIsEditedAndCvcIsRemoved()
            throws Exception {
        SAMPLE_LOCAL_CARD_WITH_CVC.setNumber(NON_AMEX_CARD_NUMBER);
        String guid = mAutofillTestHelper.setCreditCard(SAMPLE_LOCAL_CARD_WITH_CVC);

        SettingsActivity activity =
                mSettingsActivityTestRule.startSettingsActivity(fragmentArgs(guid));
        AutofillLocalCardEditor autofillLocalCardEditorFragment =
                (AutofillLocalCardEditor) activity.getMainFragment();
        setSecurityCodeOnEditor(autofillLocalCardEditorFragment, /* code= */ "");
        performButtonClickOnEditor(autofillLocalCardEditorFragment.mDoneButton);

        Assert.assertTrue(
                "User action should be logged.",
                mActionTester.getActions().contains("AutofillCreditCardsEditedAndCvcWasRemoved"));
    }

    @Test
    @MediumTest
    @EnableFeatures({ChromeFeatureList.AUTOFILL_ENABLE_CVC_STORAGE})
    public void testRecordUserAction_whenExistingCreditCardWithCvcIsEditedAndCvcIsUpdated()
            throws Exception {
        SAMPLE_LOCAL_CARD_WITH_CVC.setNumber(NON_AMEX_CARD_NUMBER);
        String guid = mAutofillTestHelper.setCreditCard(SAMPLE_LOCAL_CARD_WITH_CVC);

        SettingsActivity activity =
                mSettingsActivityTestRule.startSettingsActivity(fragmentArgs(guid));
        AutofillLocalCardEditor autofillLocalCardEditorFragment =
                (AutofillLocalCardEditor) activity.getMainFragment();
        setSecurityCodeOnEditor(autofillLocalCardEditorFragment, /* code= */ "321");
        performButtonClickOnEditor(autofillLocalCardEditorFragment.mDoneButton);

        Assert.assertTrue(
                "User action should be logged.",
                mActionTester.getActions().contains("AutofillCreditCardsEditedAndCvcWasUpdated"));
    }

    @Test
    @MediumTest
    @EnableFeatures({ChromeFeatureList.AUTOFILL_ENABLE_CVC_STORAGE})
    public void testRecordUserAction_whenExistingCreditCardWithCvcIsEditedAndCvcIsUnchanged()
            throws Exception {
        String validExpirationYear = AutofillTestHelper.nextYear();
        String validExpirationMonth = "12";
        SAMPLE_LOCAL_CARD_WITH_CVC.setNumber(NON_AMEX_CARD_NUMBER);
        String guid = mAutofillTestHelper.setCreditCard(SAMPLE_LOCAL_CARD_WITH_CVC);

        SettingsActivity activity =
                mSettingsActivityTestRule.startSettingsActivity(fragmentArgs(guid));
        AutofillLocalCardEditor autofillLocalCardEditorFragment =
                (AutofillLocalCardEditor) activity.getMainFragment();
        setExpirationDateOnEditor(
                autofillLocalCardEditorFragment,
                String.format("%s/%s", validExpirationMonth, validExpirationYear.substring(2)));
        performButtonClickOnEditor(autofillLocalCardEditorFragment.mDoneButton);

        Assert.assertTrue(
                "User action should be logged.",
                mActionTester.getActions().contains("AutofillCreditCardsEditedAndCvcWasUnchanged"));
    }

    private void openDeletePaymentMethodConfirmationDialog(
            AutofillLocalCardEditor autofillLocalCardEditorFragment,
            ModalDialogManager modalDialogManager) {
        when(mModalDialogManagerSupplierMock.get()).thenReturn(modalDialogManager);
        autofillLocalCardEditorFragment.setModalDialogManagerSupplier(
                mModalDialogManagerSupplierMock);

        MenuItem deleteButton = mock(MenuItem.class);
        when(deleteButton.getItemId()).thenReturn(R.id.delete_menu_id);
        ThreadUtils.runOnUiThreadBlocking(
                () -> {
                    autofillLocalCardEditorFragment.onOptionsItemSelected(deleteButton);
                });
    }

    private void setExpirationMonthSelectionOnEditor(
            AutofillLocalCardEditor autofillLocalCardEditorFragment, int monthSelection) {
        ThreadUtils.runOnUiThreadBlocking(
                () -> {
                    try {
                        autofillLocalCardEditorFragment.mExpirationMonth.setSelection(
                                monthSelection);
                    } catch (Exception e) {
                        Assert.fail("Failed to set the Expiration Month");
                    }
                });
    }

    private void setExpirationYearSelectionOnEditor(
            AutofillLocalCardEditor autofillLocalCardEditorFragment, int yearSelection) {
        ThreadUtils.runOnUiThreadBlocking(
                () -> {
                    try {
                        autofillLocalCardEditorFragment.mExpirationYear.setSelection(yearSelection);
                    } catch (Exception e) {
                        Assert.fail("Failed to set the Expiration Year");
                    }
                });
    }

    private void setExpirationDateOnEditor(
            AutofillLocalCardEditor autofillLocalCardEditorFragment, String date) {
        ThreadUtils.runOnUiThreadBlocking(
                () -> {
                    try {
                        autofillLocalCardEditorFragment.mExpirationDate.setText(date);
                    } catch (Exception e) {
                        Assert.fail("Failed to set the Expiration Date");
                    }
                });
    }

    private void setNicknameOnEditor(
            AutofillLocalCardEditor autofillLocalCardEditorFragment, String nickname) {
        ThreadUtils.runOnUiThreadBlocking(
                () -> {
                    try {
                        autofillLocalCardEditorFragment.mNicknameText.setText(nickname);
                    } catch (Exception e) {
                        Assert.fail("Failed to set the nickname");
                    }
                });
    }

    @Test
    @SmallTest
    public void getExpirationMonth_whenDoubleDigitMonth_returnsMonth() throws Exception {
        assertThat(AutofillLocalCardEditor.getExpirationMonth("12/23")).isEqualTo("12");
    }

    @Test
    @SmallTest
    public void getExpirationMonth_whenSingleDigitMonth_returnsMonthWithoutLeadingZero()
            throws Exception {
        assertThat(AutofillLocalCardEditor.getExpirationMonth("02/23")).isEqualTo("2");
    }

    @Test
    @SmallTest
    public void getExpirationYear_returnsYearWithPrefix() throws Exception {
        assertThat(AutofillLocalCardEditor.getExpirationYear("12/23")).isEqualTo("2023");
    }

    @Test
    @SmallTest
    public void testIsAmExCard_whenAmExCardNumberPrefixIsEntered_returnsTrue() {
        ThreadUtils.runOnUiThreadBlocking(
                () -> {
                    try {
                        assertThat(AutofillLocalCardEditor.isAmExCard(AMEX_CARD_NUMBER_PREFIX))
                                .isTrue();
                    } catch (Exception e) {
                        Assert.fail("Failed to verify AmEx card.");
                    }
                });
    }

    @Test
    @SmallTest
    public void testIsAmExCard_whenNonAmExCardNumberPrefixIsEntered_returnsFalse() {
        ThreadUtils.runOnUiThreadBlocking(
                () -> {
                    try {
                        assertThat(AutofillLocalCardEditor.isAmExCard(NON_AMEX_CARD_NUMBER_PREFIX))
                                .isFalse();
                    } catch (Exception e) {
                        Assert.fail("Failed to verify AmEx card.");
                    }
                });
    }

    private void setCardNumberOnEditor(
            AutofillLocalCardEditor autofillLocalCardEditorFragment, String cardNumber) {
        ThreadUtils.runOnUiThreadBlocking(
                () -> {
                    try {
                        autofillLocalCardEditorFragment.mNumberText.setText(cardNumber);
                    } catch (Exception e) {
                        Assert.fail("Failed to set the card number");
                    }
                });
    }

    private void setSecurityCodeOnEditor(
            AutofillLocalCardEditor autofillLocalCardEditorFragment, String code) {
        ThreadUtils.runOnUiThreadBlocking(
                () -> {
                    try {
                        autofillLocalCardEditorFragment.mCvc.setText(code);
                    } catch (Exception e) {
                        Assert.fail("Failed to set the security code");
                    }
                });
    }

    private void performButtonClickOnEditor(Button button) {
        ThreadUtils.runOnUiThreadBlocking(
                () -> {
                    try {
                        button.performClick();
                    } catch (Exception e) {
                        Assert.fail("Failed to click the button");
                    }
                });
    }

    private void verifyCvcHintImage(
            AutofillLocalCardEditor autofillLocalCardEditorFragment, int expectedImage) {
        ImageView expectedCvcHintImage = new ImageView(ContextUtils.getApplicationContext());
        expectedCvcHintImage.setImageResource(expectedImage);

        BitmapDrawable expectedDrawable = (BitmapDrawable) expectedCvcHintImage.getDrawable();
        BitmapDrawable actualDrawable =
                (BitmapDrawable) autofillLocalCardEditorFragment.mCvcHintImage.getDrawable();
        assertThat(expectedDrawable.getBitmap().sameAs(actualDrawable.getBitmap())).isTrue();
    }
}