@@ -2,6 +2,8 @@ package com.flipcash.app.tokens.ui
22
33import com.flipcash.app.core.tokens.SwapPurpose
44import com.getcode.opencode.exchange.VerifiedFiat
5+ import com.getcode.opencode.internal.solana.model.SwapId
6+ import com.getcode.opencode.model.financial.Currency
57import com.getcode.opencode.model.financial.CurrencyCode
68import com.getcode.opencode.model.financial.Fiat
79import com.getcode.opencode.model.financial.LocalFiat
@@ -11,6 +13,7 @@ import com.getcode.view.LoadingSuccessState
1113import kotlin.test.Test
1214import kotlin.test.assertEquals
1315import kotlin.test.assertFalse
16+ import kotlin.test.assertNotNull
1417import kotlin.test.assertNull
1518import kotlin.test.assertTrue
1619
@@ -113,6 +116,26 @@ class SwapViewModelStateTest {
113116 assertNull(updated.amountEntryState.limits)
114117 }
115118
119+ @Test
120+ fun `OnCurrencyChanged sets currencyModel in entry state` () {
121+ val currency = Currency (code = " GBP" , name = " British Pound" , symbol = " £" , rate = 0.79 )
122+ val updated = reduce(
123+ SwapViewModel .Event .OnCurrencyChanged (currency)
124+ )(SwapViewModel .State ())
125+ assertNotNull(updated.amountEntryState.currencyModel.selected)
126+ assertEquals(" GBP" , updated.amountEntryState.currencyModel.selected?.code)
127+ assertEquals(CurrencyCode .GBP , updated.amountEntryState.currencyModel.code)
128+ }
129+
130+ @Test
131+ fun `OnSwapIdChanged sets swapId` () {
132+ val swapId = SwapId (ByteArray (32 ) { 2 }.toList())
133+ val updated = reduce(
134+ SwapViewModel .Event .OnSwapIdChanged (swapId)
135+ )(SwapViewModel .State ())
136+ assertEquals(swapId, updated.swapId)
137+ }
138+
116139 // --- No-op events ---
117140
118141 @Test
@@ -211,6 +234,68 @@ class SwapViewModelStateTest {
211234 assertEquals(confirmed, state.netTransferAmount)
212235 }
213236
237+ // --- Computed: netTransferAmount ---
238+
239+ @Test
240+ fun `netTransferAmount falls back to enteredAmount for BalanceIncrease purpose` () {
241+ // Buy is a BalanceIncrease, so netTransferAmount = enteredAmount when confirmedNetTransferAmount is null
242+ val state = SwapViewModel .State (purpose = SwapPurpose .Buy (mint()))
243+ // Default enteredAmount is Fiat(0.0, CurrencyCode.USD) since tokenBalance is Zero
244+ assertEquals(state.enteredAmount, state.netTransferAmount)
245+ }
246+
247+ @Test
248+ fun `netTransferAmount subtracts fee for non-BalanceIncrease purpose` () {
249+ // Sell is BalanceDecrease, so netTransferAmount = enteredAmount - feeAmount
250+ // With no tokenWithBalance, sellFee is null, feeAmount = Zero, so net = entered - 0 = entered
251+ val state = SwapViewModel .State (purpose = SwapPurpose .Sell (mint()))
252+ assertEquals(state.enteredAmount.decimalValue - state.feeAmount.decimalValue, state.netTransferAmount.decimalValue, 0.001 )
253+ }
254+
255+ // --- Computed: enteredAmount ---
256+
257+ @Test
258+ fun `enteredAmount defaults to zero with USD currency` () {
259+ val state = SwapViewModel .State ()
260+ assertEquals(0.0 , state.enteredAmount.decimalValue, 0.001 )
261+ assertEquals(CurrencyCode .USD , state.enteredAmount.currencyCode)
262+ }
263+
264+ // --- Computed: feeAmount ---
265+
266+ @Test
267+ fun `feeAmount is Zero when sellFee is null` () {
268+ assertEquals(Fiat .Zero , SwapViewModel .State ().feeAmount)
269+ }
270+
271+ // --- Computed: maxAvailableToSwap per purpose ---
272+
273+ @Test
274+ fun `maxAvailableToSwap for Buy uses maxToAdd` () {
275+ val state = SwapViewModel .State (
276+ purpose = SwapPurpose .Buy (mint()),
277+ amountEntryState = AmountEntryState (maxToAdd = 200.0 to CurrencyCode .USD )
278+ )
279+ assertTrue(state.maxAvailableToSwap.isNotEmpty())
280+ }
281+
282+ @Test
283+ fun `maxAvailableToSwap for Buy is empty when maxToAdd is null` () {
284+ val state = SwapViewModel .State (
285+ purpose = SwapPurpose .Buy (mint()),
286+ )
287+ assertEquals(" " , state.maxAvailableToSwap)
288+ }
289+
290+ // --- Computed: transactionLimit per purpose ---
291+
292+ @Test
293+ fun `transactionLimit for Sell is tokenBalance` () {
294+ val state = SwapViewModel .State (purpose = SwapPurpose .Sell (mint()))
295+ // tokenWithBalance is null → tokenBalance = Fiat.Zero
296+ assertEquals(Fiat .Zero , state.transactionLimit)
297+ }
298+
214299 // --- Computed: isError ---
215300
216301 @Test
0 commit comments