commit fdf492bdd079c37419a36b07abd37fdaa83ac7d3
parent f40847365ade1cfb875f3798bfaa8edd103bcbd3
Author: Segun Famisa <sfamisa@mozilla.com>
Date: Mon, 24 Nov 2025 13:17:17 +0000
Bug 1998196 - Add tests for the state management logic for the Credit Card Editor r=android-reviewers,boek
This patch introduces unit tests for the `CreditCardEditorStore`.
The new tests cover:
- Reducer logic for state updates in `CreditCardEditorReducerTest`.
- Middleware logic for handling side effects like saving, deleting, and initialization in `CreditCardEditorStoreTest`.
To support these tests, the following test fakes and helpers have been added:
- `FakeCreditCardsStorage`: A fake implementation of `CreditCardsAddressesStorage`.
- `FakeCalendarDataProvider`: A fake for providing month and year data.
- `CreditCardEditorStateTestHelper`: A helper function to create instances of `CreditCardEditorState` for testing.
Differential Revision: https://phabricator.services.mozilla.com/D271089
Diffstat:
5 files changed, 730 insertions(+), 0 deletions(-)
diff --git a/mobile/android/fenix/app/src/test/java/org/mozilla/fenix/settings/creditcards/ui/CreditCardEditorReducerTest.kt b/mobile/android/fenix/app/src/test/java/org/mozilla/fenix/settings/creditcards/ui/CreditCardEditorReducerTest.kt
@@ -0,0 +1,241 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+package org.mozilla.fenix.settings.creditcards.ui
+
+import org.junit.Assert.assertEquals
+import org.junit.Assert.assertFalse
+import org.junit.Assert.assertTrue
+import org.junit.Test
+import org.mozilla.fenix.settings.creditcards.ui.CreditCardEditorAction.DeleteDialogAction
+import org.mozilla.fenix.settings.creditcards.ui.CreditCardEditorAction.FieldChanged
+
+class CreditCardEditorReducerTest {
+
+ @Test
+ fun `GIVEN a state, WHEN a CardNumberChanged action is received, then the card number is updated`() {
+ val state = createState()
+
+ val result = creditCardEditorReducer(
+ state = state,
+ action = FieldChanged.CardNumberChanged("55554444"),
+ )
+
+ assertEquals(
+ "Expected card number to be updated",
+ "55554444",
+ result.cardNumber,
+ )
+ }
+
+ @Test
+ fun `GIVEN a state, WHEN a MonthSelected action is received, then the month is updated`() {
+ val state = createState(
+ expiryMonths = listOf("January", "February", "March"),
+ selectedExpiryMonthIndex = 1,
+ )
+
+ val result = creditCardEditorReducer(
+ state = state,
+ action = FieldChanged.MonthSelected(index = 2),
+ )
+
+ assertEquals(
+ "Expected month index is updated",
+ 2,
+ result.selectedExpiryMonthIndex,
+ )
+ }
+
+ @Test
+ fun `GIVEN a state, WHEN a YearSelected action is received, then the year is updated`() {
+ val state = createState(
+ expiryYears = listOf("2025", "2026", "2027"),
+ selectedExpiryYearIndex = 0,
+ )
+
+ val result = creditCardEditorReducer(
+ state = state,
+ action = FieldChanged.YearSelected(index = 1),
+ )
+
+ assertEquals(
+ "Expected year index is updated",
+ 1,
+ result.selectedExpiryYearIndex,
+ )
+ }
+
+ @Test
+ fun `GIVEN a state, WHEN a NameOnCardChanged action is received, then the name on card is updated`() {
+ val state = createState(nameOnCard = "Jane Doe")
+
+ val result = creditCardEditorReducer(
+ state = state,
+ action = FieldChanged.NameOnCardChanged("Janey Doe"),
+ )
+
+ assertEquals(
+ "Expected name on card to be updated",
+ "Janey Doe",
+ result.nameOnCard,
+ )
+ }
+
+ @Test
+ fun `GIVEN a state with name error, WHEN the name changes, then an error is cleared on the name field`() {
+ val state = createState(nameOnCard = "", showNameOnCardError = true)
+
+ val result = creditCardEditorReducer(
+ state = state,
+ action = FieldChanged.NameOnCardChanged("Janey Doe"),
+ )
+
+ assertFalse(
+ "Expected name on card error to be cleared",
+ result.showNameOnCardError,
+ )
+ }
+
+ @Test
+ fun `GIVEN a state with card number error, WHEN the card number changes, then an error is cleared on the name field`() {
+ val state = createState(cardNumber = "5555", showCardNumberError = true)
+
+ val result = creditCardEditorReducer(
+ state = state,
+ action = FieldChanged.CardNumberChanged("55554"),
+ )
+
+ assertFalse(
+ "Expected name on card error to be cleared",
+ result.showCardNumberError,
+ )
+ }
+
+ @Test
+ fun `GIVEN a state, WHEN a delete dialog cancel action is received, then the dialog is hidden`() {
+ val state = createState(showDeleteDialog = true)
+
+ val result = creditCardEditorReducer(
+ state = state,
+ action = DeleteDialogAction.Cancel,
+ )
+
+ assertFalse(
+ "Expected delete dialog to be hidden",
+ result.showDeleteDialog,
+ )
+ }
+
+ @Test
+ fun `GIVEN a state, WHEN a delete dialog confirm action is received, then the dialog is hidden`() {
+ val state = createState(showDeleteDialog = true)
+
+ val result = creditCardEditorReducer(
+ state = state,
+ action = DeleteDialogAction.Confirm,
+ )
+
+ assertFalse(
+ "Expected delete dialog to be hidden",
+ result.showDeleteDialog,
+ )
+ }
+
+ @Test
+ fun `GIVEN a state, WHEN a DeleteClicked action is received, then the dialog is shown`() {
+ val state = createState(showDeleteDialog = false)
+
+ val result = creditCardEditorReducer(
+ state = state,
+ action = CreditCardEditorAction.DeleteClicked,
+ )
+
+ assertTrue(
+ "Expected delete dialog to be shown",
+ result.showDeleteDialog,
+ )
+ }
+
+ @Test
+ fun `GIVEN a state with invalid card number, WHEN save action is received, then the error is shown`() {
+ val state = createState(cardNumber = "3333")
+
+ val result = creditCardEditorReducer(
+ state = state,
+ action = CreditCardEditorAction.Save,
+ )
+
+ assertTrue(
+ "Expected card number error to be shown",
+ result.showCardNumberError,
+ )
+ }
+
+ @Test
+ fun `GIVEN state with card number error, WHEN card number field is changed, then the error is cleared`() {
+ val state = createState(showCardNumberError = true)
+
+ val result = creditCardEditorReducer(
+ state = state,
+ action = FieldChanged.CardNumberChanged(cardNumber = "5555"),
+ )
+
+ assertFalse(
+ "Expected card number error to no longer be shown",
+ result.showCardNumberError,
+ )
+ }
+
+ @Test
+ fun `GIVEN state with empty name on card, WHEN a save action is received, then the error is shown`() {
+ val state = createState(nameOnCard = "")
+
+ val result = creditCardEditorReducer(
+ state = state,
+ action = CreditCardEditorAction.Save,
+ )
+
+ assertTrue(
+ "Expected name on card error to be shown",
+ result.showNameOnCardError,
+ )
+ }
+
+ @Test
+ fun `GIVEN a state with name on card error, WHEN the name field changes, then the error is cleared`() {
+ val state = createState(showNameOnCardError = true)
+
+ val result = creditCardEditorReducer(
+ state = state,
+ action = FieldChanged.NameOnCardChanged(nameOnCard = "John"),
+ )
+
+ assertFalse(
+ "Expected name on card error to no longer be shown",
+ result.showNameOnCardError,
+ )
+ }
+
+ @Test
+ fun `GIVEN a state, WHEN initialization is completed, then the state is updated accordingly`() {
+ val oldState = createState()
+
+ val newState = createState(
+ nameOnCard = "New Name",
+ cardNumber = "1234556789900",
+ )
+
+ val result = creditCardEditorReducer(
+ state = oldState,
+ action = CreditCardEditorAction.Initialization.InitCompleted(state = newState),
+ )
+
+ assertEquals(
+ "Expected the state to be what was received in the action",
+ newState,
+ result,
+ )
+ }
+}
diff --git a/mobile/android/fenix/app/src/test/java/org/mozilla/fenix/settings/creditcards/ui/CreditCardEditorStateTestHelper.kt b/mobile/android/fenix/app/src/test/java/org/mozilla/fenix/settings/creditcards/ui/CreditCardEditorStateTestHelper.kt
@@ -0,0 +1,36 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+package org.mozilla.fenix.settings.creditcards.ui
+
+/**
+ * Creates a [CreditCardEditorState] with the given parameters for use in tests.
+ */
+internal fun createState(
+ guid: String = "",
+ cardNumber: String = "5555444433331111",
+ showCardNumberError: Boolean = false,
+ nameOnCard: String = "Jane Doe",
+ showNameOnCardError: Boolean = false,
+ expiryMonths: List<String> = listOf("January", "February", "March"),
+ selectedExpiryMonthIndex: Int = 0,
+ expiryYears: List<String> = listOf("2025", "2026", "2027"),
+ selectedExpiryYearIndex: Int = 1,
+ inEditMode: Boolean = false,
+ showDeleteDialog: Boolean = false,
+): CreditCardEditorState {
+ return CreditCardEditorState(
+ guid = guid,
+ cardNumber = cardNumber,
+ showCardNumberError = showCardNumberError,
+ nameOnCard = nameOnCard,
+ showNameOnCardError = showNameOnCardError,
+ expiryMonths = expiryMonths,
+ selectedExpiryMonthIndex = selectedExpiryMonthIndex,
+ expiryYears = expiryYears,
+ selectedExpiryYearIndex = selectedExpiryYearIndex,
+ inEditMode = inEditMode,
+ showDeleteDialog = showDeleteDialog,
+ )
+}
diff --git a/mobile/android/fenix/app/src/test/java/org/mozilla/fenix/settings/creditcards/ui/CreditCardEditorStoreTest.kt b/mobile/android/fenix/app/src/test/java/org/mozilla/fenix/settings/creditcards/ui/CreditCardEditorStoreTest.kt
@@ -0,0 +1,325 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+package org.mozilla.fenix.settings.creditcards.ui
+
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import kotlinx.coroutines.CoroutineDispatcher
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.test.runTest
+import mozilla.components.concept.storage.CreditCard
+import mozilla.components.concept.storage.CreditCardNumber
+import mozilla.components.concept.storage.CreditCardsAddressesStorage
+import mozilla.components.concept.storage.NewCreditCardFields
+import mozilla.components.concept.storage.UpdatableCreditCardFields
+import mozilla.components.support.test.rule.MainCoroutineRule
+import mozilla.components.support.utils.CreditCardNetworkType
+import org.junit.Assert.assertEquals
+import org.junit.Assert.assertFalse
+import org.junit.Assert.assertTrue
+import org.junit.Rule
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@RunWith(AndroidJUnit4::class)
+class CreditCardEditorStoreTest {
+
+ @get:Rule
+ val coroutinesTestRule = MainCoroutineRule()
+ private val creditCardsStorage = FakeCreditCardsStorage()
+ private val calendarDataProvider = FakeCalendarDataProvider(
+ expectedMonths = listOf("January", "February", "March"),
+ expectedYears = listOf("2025", "2026", "2027"),
+ )
+
+ @Test
+ fun `WHEN DeleteClicked event is received, delete confirmation dialog is shown`() = runTest {
+ val store = makeStore()
+
+ store.dispatch(CreditCardEditorAction.DeleteClicked)
+
+ assertTrue(
+ "Delete confirmation dialog is not shown",
+ store.state.showDeleteDialog,
+ )
+ }
+
+ @Test
+ fun `WHEN delete confirmation is cancelled, the dialog is hidden`() = runTest {
+ val store = makeStore()
+
+ store.dispatch(CreditCardEditorAction.DeleteClicked)
+ store.dispatch(CreditCardEditorAction.DeleteDialogAction.Cancel)
+
+ assertFalse(
+ "Expected delete confirmation dialog to be hidden",
+ store.state.showDeleteDialog,
+ )
+ }
+
+ @Test
+ fun `WHEN delete confirmation is confirmed, the card is deleted`() = runTest {
+ val store = makeStore(
+ state = createState(guid = "card-id"),
+ )
+
+ store.dispatch(CreditCardEditorAction.DeleteDialogAction.Confirm)
+
+ assertEquals(
+ "Expected that the deleted card has guid 'card-id'",
+ "card-id",
+ creditCardsStorage.deletedCard,
+ )
+ }
+
+ @Test
+ fun `GIVEN valid form in 'edit' mode, WHEN save action is received, the card is saved`() {
+ val validMasterCard = "5555444433331111"
+ val store = makeStore(
+ state = createState(
+ guid = "1234",
+ inEditMode = true,
+ nameOnCard = "Jane Doe",
+ cardNumber = validMasterCard,
+ expiryYears = listOf("2025", "2026", "2027"),
+ selectedExpiryYearIndex = 1,
+ expiryMonths = listOf("January", "February", "March"),
+ selectedExpiryMonthIndex = 0,
+ ),
+ )
+
+ store.dispatch(CreditCardEditorAction.Save)
+
+ val updatedCardGuid = creditCardsStorage.updatedCard?.first
+ val updatedCardFields = creditCardsStorage.updatedCard?.second
+ assertEquals(
+ "Expected that a card is updated with the guid is 1234",
+ "1234",
+ updatedCardGuid,
+ )
+ assertEquals(
+ "Expected that a card is updated with the right fields",
+ UpdatableCreditCardFields(
+ billingName = "Jane Doe",
+ cardNumber = CreditCardNumber.Plaintext(validMasterCard),
+ cardNumberLast4 = "1111",
+ expiryMonth = 1,
+ expiryYear = 2026L,
+ cardType = "mastercard",
+ ),
+ updatedCardFields,
+ )
+ }
+
+ @Test
+ fun `GIVEN valid form in 'create' mode, WHEN save action is received, the card is saved`() {
+ val validMasterCard = "5555444433331111"
+ val store = makeStore(
+ state = createState(
+ nameOnCard = "Jane Doe",
+ cardNumber = validMasterCard,
+ expiryYears = listOf("2025", "2026", "2027"),
+ selectedExpiryYearIndex = 1,
+ expiryMonths = listOf("January", "February", "March"),
+ selectedExpiryMonthIndex = 0,
+ ),
+ )
+
+ store.dispatch(CreditCardEditorAction.Save)
+
+ assertEquals(
+ "Expected that a card is successfully saved with the right values",
+ NewCreditCardFields(
+ billingName = "Jane Doe",
+ plaintextCardNumber = CreditCardNumber.Plaintext(validMasterCard),
+ cardNumberLast4 = "1111",
+ expiryMonth = 1,
+ expiryYear = 2026L,
+ cardType = "mastercard",
+ ),
+ creditCardsStorage.newAddedCard,
+ )
+ }
+
+ @Test
+ fun `GIVEN invalid card number, WHEN save action is received, an error is shown on the card field`() {
+ val americanExpressCardInvalid = "371449635398432"
+ val store = makeStore(
+ state = createState(cardNumber = americanExpressCardInvalid),
+ )
+
+ store.dispatch(CreditCardEditorAction.Save)
+
+ assertTrue(
+ "Expected that an error is shown on the card number field",
+ store.state.showCardNumberError,
+ )
+ }
+
+ @Test
+ fun `GIVEN empty card number, WHEN save action is received, an error is shown on the card field`() {
+ val store = makeStore(
+ state = createState(cardNumber = ""),
+ )
+
+ store.dispatch(CreditCardEditorAction.Save)
+
+ assertTrue(
+ "Expected that an error is shown on the card number field",
+ store.state.showCardNumberError,
+ )
+ }
+
+ @Test
+ fun `GIVEN an empty name on card, WHEN save action is received, an error is shown on the name field`() {
+ val store = makeStore(
+ state = createState(nameOnCard = ""),
+ )
+
+ store.dispatch(CreditCardEditorAction.Save)
+
+ assertTrue(
+ "Expected that an error is shown on the name field",
+ store.state.showNameOnCardError,
+ )
+ }
+
+ @Test
+ fun `WHEN cancel action is received, user is navigated back`() {
+ var navigatedBack = false
+ val store = makeStore(
+ environment = CreditCardEditorEnvironment.Default.copy(
+ navigateBack = {
+ navigatedBack = true
+ },
+ ),
+ )
+
+ store.dispatch(CreditCardEditorAction.Cancel)
+
+ assertTrue(
+ "Expected that we navigate back",
+ navigatedBack,
+ )
+ }
+
+ @Test
+ fun `WHEN 'navigate back' action is received, user is navigated back`() {
+ var navigatedBack = false
+ val store = makeStore(
+ environment = CreditCardEditorEnvironment.Default.copy(
+ navigateBack = {
+ navigatedBack = true
+ },
+ ),
+ )
+
+ store.dispatch(CreditCardEditorAction.NavigateBack)
+
+ assertTrue(
+ "Expected that we navigate back",
+ navigatedBack,
+ )
+ }
+
+ @Test
+ fun `WHEN Initializing without a credit card, the state is correct`() = runTest {
+ calendarDataProvider.expectedMonths = listOf("January", "February")
+ calendarDataProvider.expectedYears = listOf("2025", "2026")
+
+ val initialState = CreditCardEditorState.Default
+ val store = makeStore(state = initialState)
+
+ store.dispatch(CreditCardEditorAction.Initialization.InitStarted(creditCard = null))
+
+ assertEquals(
+ "Expected that the state is loaded with everything empty",
+ CreditCardEditorState(
+ guid = "",
+ cardNumber = "",
+ showCardNumberError = false,
+ nameOnCard = "",
+ showNameOnCardError = false,
+ expiryMonths = listOf("January", "February"),
+ selectedExpiryMonthIndex = 0,
+ expiryYears = listOf("2025", "2026"),
+ selectedExpiryYearIndex = 0,
+ inEditMode = false,
+ showDeleteDialog = false,
+ ),
+ store.state,
+ )
+ }
+
+ @Test
+ fun `WHEN Initializing with a credit card, the state is initialized with the card details`() =
+ runTest {
+ calendarDataProvider.expectedMonths = listOf("January", "February", "March")
+ calendarDataProvider.expectedYears = listOf("2025", "2026")
+ val expectedEncryptedCardNumber = "encryptedCard"
+ val expectedPlainCardNumber = "5555444433331111"
+
+ creditCardsStorage.expectedPlainCardNumber = expectedPlainCardNumber
+ creditCardsStorage.expectedEncryptedCardNumber = expectedEncryptedCardNumber
+
+ val creditCard = CreditCard(
+ guid = "id",
+ billingName = "Banana Apple",
+ encryptedCardNumber = CreditCardNumber.Encrypted(expectedEncryptedCardNumber),
+ cardNumberLast4 = "1111",
+ expiryMonth = 2,
+ expiryYear = 2025,
+ cardType = CreditCardNetworkType.MASTERCARD.cardName,
+ timeCreated = 1L,
+ timeLastUsed = 1L,
+ timeLastModified = 1L,
+ timesUsed = 1L,
+ )
+
+ val store = makeStore(state = CreditCardEditorState.Default)
+
+ store.dispatch(CreditCardEditorAction.Initialization.InitStarted(creditCard = creditCard))
+
+ assertEquals(
+ "Expected that the state is initialized with the card details",
+ CreditCardEditorState(
+ guid = "id",
+ cardNumber = expectedPlainCardNumber,
+ showCardNumberError = false,
+ nameOnCard = "Banana Apple",
+ showNameOnCardError = false,
+ expiryMonths = listOf("January", "February", "March"),
+ selectedExpiryMonthIndex = 1,
+ expiryYears = listOf("2025", "2026"),
+ selectedExpiryYearIndex = 0,
+ inEditMode = true,
+ showDeleteDialog = false,
+ ),
+ store.state,
+ )
+ }
+
+ private fun makeStore(
+ state: CreditCardEditorState = createState(),
+ monthsProvider: CalendarDataProvider = calendarDataProvider,
+ storage: CreditCardsAddressesStorage = creditCardsStorage,
+ scope: CoroutineScope = coroutinesTestRule.scope,
+ dispatcher: CoroutineDispatcher = coroutinesTestRule.testDispatcher,
+ environment: CreditCardEditorEnvironment = CreditCardEditorEnvironment.Default,
+ ): CreditCardEditorStore {
+ return CreditCardEditorStore(
+ initialState = state,
+ middleware = listOf(
+ CreditCardEditorMiddleware(
+ environment = environment,
+ calendarDataProvider = monthsProvider,
+ storage = storage,
+ coroutineScope = scope,
+ ioDispatcher = dispatcher,
+ mainDispatcher = dispatcher,
+ ),
+ ),
+ )
+ }
+}
diff --git a/mobile/android/fenix/app/src/test/java/org/mozilla/fenix/settings/creditcards/ui/FakeCalendarDataProvider.kt b/mobile/android/fenix/app/src/test/java/org/mozilla/fenix/settings/creditcards/ui/FakeCalendarDataProvider.kt
@@ -0,0 +1,22 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+package org.mozilla.fenix.settings.creditcards.ui
+
+class FakeCalendarDataProvider(
+ var expectedMonths: List<String> = emptyList(),
+ var expectedYears: List<String> = emptyList(),
+) : CalendarDataProvider {
+ override fun months(): List<String> {
+ return expectedMonths
+ }
+
+ override fun years(): List<String> {
+ return expectedYears
+ }
+
+ override fun years(startYear: Long): List<String> {
+ return expectedYears
+ }
+}
diff --git a/mobile/android/fenix/app/src/test/java/org/mozilla/fenix/settings/creditcards/ui/FakeCreditCardsStorage.kt b/mobile/android/fenix/app/src/test/java/org/mozilla/fenix/settings/creditcards/ui/FakeCreditCardsStorage.kt
@@ -0,0 +1,106 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+package org.mozilla.fenix.settings.creditcards.ui
+
+import mozilla.components.concept.storage.Address
+import mozilla.components.concept.storage.CreditCard
+import mozilla.components.concept.storage.CreditCardCrypto
+import mozilla.components.concept.storage.CreditCardNumber
+import mozilla.components.concept.storage.CreditCardsAddressesStorage
+import mozilla.components.concept.storage.ManagedKey
+import mozilla.components.concept.storage.NewCreditCardFields
+import mozilla.components.concept.storage.UpdatableAddressFields
+import mozilla.components.concept.storage.UpdatableCreditCardFields
+
+/**
+ * Fake implementation of [CreditCardsAddressesStorage] that is used for testing credit cards feature
+ */
+class FakeCreditCardsStorage(
+ var deletedCard: String? = null,
+ var newAddedCard: NewCreditCardFields? = null,
+ var updatedCard: Pair<String, UpdatableCreditCardFields>? = null,
+) : CreditCardsAddressesStorage {
+
+ /**
+ * Plain card number
+ */
+ var expectedPlainCardNumber: String = ""
+
+ /**
+ * Encrypted card number
+ */
+ var expectedEncryptedCardNumber: String = "encrypted"
+
+ override suspend fun addCreditCard(creditCardFields: NewCreditCardFields): CreditCard {
+ newAddedCard = creditCardFields
+ return CreditCard(
+ guid = "new-card-id",
+ billingName = creditCardFields.billingName,
+ encryptedCardNumber = CreditCardNumber.Encrypted(data = expectedEncryptedCardNumber),
+ cardNumberLast4 = creditCardFields.cardNumberLast4,
+ expiryMonth = creditCardFields.expiryMonth,
+ expiryYear = creditCardFields.expiryYear,
+ cardType = creditCardFields.cardType,
+ )
+ }
+
+ override suspend fun updateCreditCard(
+ guid: String,
+ creditCardFields: UpdatableCreditCardFields,
+ ) {
+ updatedCard = Pair(guid, creditCardFields)
+ }
+
+ override suspend fun getCreditCard(guid: String): CreditCard? = null
+
+ override suspend fun getAllCreditCards(): List<CreditCard> = emptyList()
+
+ override suspend fun deleteCreditCard(guid: String): Boolean {
+ deletedCard = guid
+ return true
+ }
+
+ override suspend fun touchCreditCard(guid: String) = Unit
+
+ override fun getCreditCardCrypto(): CreditCardCrypto {
+ return object : CreditCardCrypto {
+ override fun encrypt(
+ key: ManagedKey,
+ plaintextCardNumber: CreditCardNumber.Plaintext,
+ ): CreditCardNumber.Encrypted {
+ return CreditCardNumber.Encrypted(data = expectedEncryptedCardNumber)
+ }
+
+ override fun decrypt(
+ key: ManagedKey,
+ encryptedCardNumber: CreditCardNumber.Encrypted,
+ ): CreditCardNumber.Plaintext {
+ return CreditCardNumber.Plaintext(data = expectedPlainCardNumber)
+ }
+
+ override suspend fun getOrGenerateKey(): ManagedKey {
+ return ManagedKey(key = "key")
+ }
+ }
+ }
+
+ override suspend fun scrubEncryptedData() {
+ error("Not yet implemented")
+ }
+
+ override suspend fun addAddress(addressFields: UpdatableAddressFields): Address {
+ throw NotImplementedError("Address features are not used in this test")
+ }
+
+ override suspend fun getAddress(guid: String): Address? = null
+
+ override suspend fun getAllAddresses(): List<Address> = emptyList()
+
+ override suspend fun updateAddress(guid: String, address: UpdatableAddressFields) = Unit
+
+ override suspend fun deleteAddress(guid: String): Boolean = false
+
+ override suspend fun touchAddress(guid: String) = Unit
+}