Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,9 @@ import com.flipcash.app.session.SettledClaim
import com.flipcash.app.session.internal.SessionStateHolder
import com.flipcash.app.tokens.TokenCoordinator
import com.flipcash.services.user.UserManager
import com.flipcash.core.R
import com.getcode.manager.BottomBarManager
import com.getcode.opencode.internal.transactors.ReceiveGiftTransactorError
import com.getcode.opencode.model.accounts.AccountCluster
import com.getcode.opencode.model.financial.LocalFiat
import com.getcode.opencode.model.financial.CurrencyCode
Expand Down Expand Up @@ -267,6 +269,28 @@ class CashLinkDelegateTest {
)
}

@Test
fun `a claim rejected as already claimed shows the already collected alert`() = runTest {
every { resources.getString(R.string.error_title_alreadyCollected) } returns "Already Collected"
val delegate = createDelegate()

val onError = slot<(Throwable) -> Unit>()
delegate.openCashLink("validEntropy123")
verify {
billController.receiveGiftCard(
entropy = any(),
owner = any(),
claimIfOwned = any(),
onReceived = any(),
onError = capture(onError),
)
}
onError.captured.invoke(ReceiveGiftTransactorError.AlreadyClaimed())
runCurrent()

assertEquals("Already Collected", BottomBarManager.messages.value.single().title)
}

@Test
fun `openCashLink clears bottom bar before processing`() = runTest {
// Add a message to BottomBarManager first
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -154,10 +154,15 @@ internal class ReceiveGiftCardTransactor(
},
onFailure = { error ->
onStep("intent")
if (error is SubmitIntentError.StaleState && error.isGiftCardAlreadyClaimed) {
Result.failure(error)
} else {
logAndFail(error)
// The account query can report NOT_CLAIMED after another claim
// has been accepted, so the pre-claim checks pass and the server
// rejects at submit. Map those to the same errors the checks use.
when {
error is SubmitIntentError.StaleState && error.isGiftCardAlreadyClaimed ->
Result.failure(ReceiveGiftTransactorError.AlreadyClaimed())
error is SubmitIntentError.StaleState && error.isGiftCardExpired ->
Result.failure(ReceiveGiftTransactorError.Expired())
else -> logAndFail(error)
}
}
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import io.mockk.mockk
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.test.runTest
import org.junit.Test
import kotlin.test.assertIs
import kotlin.test.assertSame
import kotlin.test.assertTrue

Expand Down Expand Up @@ -70,20 +71,47 @@ class ReceiveGiftCardTransactorTest {
// region intent submission

@Test
fun `start fails with the stale state when the gift card was already claimed`() = runTest {
fun `start fails with AlreadyClaimed when the intent is rejected as already claimed`() = runTest {
// The account query can still report NOT_CLAIMED when another claim has
// just been accepted, so the pre-claim check passes and submit is rejected.
setupWithOwner()
setupClaimableGiftCard()
val alreadyClaimed = SubmitIntentError.StaleState(
listOf("gift card balance has already been claimed")
coEvery {
transactionController.receiveRemotely(any(), any(), any(), any())
} returns Result.failure(
SubmitIntentError.StaleState(listOf("gift card balance has already been claimed"))
)

val result = transactor.start(claimIfOwned = false)

assertIs<ReceiveGiftTransactorError.AlreadyClaimed>(result.exceptionOrNull())
}

@Test
fun `start fails with Expired when the intent is rejected as expired`() = runTest {
setupWithOwner()
setupClaimableGiftCard()
coEvery {
transactionController.receiveRemotely(any(), any(), any(), any())
} returns Result.failure(alreadyClaimed)
} returns Result.failure(SubmitIntentError.StaleState(listOf("gift card is expired")))

val result = transactor.start(claimIfOwned = false)

assertTrue(result.isFailure)
assertSame(alreadyClaimed, result.exceptionOrNull())
assertIs<ReceiveGiftTransactorError.Expired>(result.exceptionOrNull())
}

@Test
fun `start passes through other stale state rejections`() = runTest {
setupWithOwner()
setupClaimableGiftCard()
val raced = SubmitIntentError.StaleState(listOf("race detected: nonce"))
coEvery {
transactionController.receiveRemotely(any(), any(), any(), any())
} returns Result.failure(raced)

val result = transactor.start(claimIfOwned = false)

assertSame(raced, result.exceptionOrNull())
}

@Test
Expand Down
Loading