Updated on 2026-08-14

This commit is contained in:
Tangem 2026-02-12 11:50:44 +04:00
parent 4c8af6b8e9
commit 1472431435
54 changed files with 370 additions and 352 deletions

View file

@ -1,6 +1,7 @@
package com.tangem.data.account.converter
import com.tangem.domain.common.wallets.UserWalletsListRepository
import com.tangem.domain.common.wallets.getSyncStrict
import com.tangem.domain.models.wallet.UserWalletId
import javax.inject.Inject

View file

@ -5,6 +5,7 @@ import arrow.core.some
import com.tangem.data.account.store.AccountsResponseStoreFactory
import com.tangem.data.common.currency.ResponseCryptoCurrenciesFactory
import com.tangem.domain.common.wallets.UserWalletsListRepository
import com.tangem.domain.common.wallets.getSyncStrict
import com.tangem.domain.core.flow.FlowProducerTools
import com.tangem.domain.models.account.DerivationIndex
import com.tangem.domain.models.currency.CryptoCurrency

View file

@ -5,6 +5,7 @@ import arrow.core.some
import com.tangem.domain.account.models.AccountList
import com.tangem.domain.account.producer.MultiAccountListProducer
import com.tangem.domain.common.wallets.UserWalletsListRepository
import com.tangem.domain.common.wallets.loadAndGet
import com.tangem.domain.core.flow.FlowProducerTools
import com.tangem.domain.models.wallet.UserWallet
import com.tangem.utils.coroutines.CoroutineDispatcherProvider

View file

@ -5,6 +5,7 @@ import arrow.core.some
import com.tangem.data.common.currency.ResponseCryptoCurrenciesFactory
import com.tangem.datasource.local.token.UserTokensResponseStore
import com.tangem.domain.common.wallets.UserWalletsListRepository
import com.tangem.domain.common.wallets.getSyncStrict
import com.tangem.domain.core.flow.FlowProducerTools
import com.tangem.domain.models.account.DerivationIndex
import com.tangem.domain.models.currency.CryptoCurrency

View file

@ -7,6 +7,7 @@ import com.tangem.data.common.currency.CardCryptoCurrencyFactory
import com.tangem.domain.account.models.AccountList
import com.tangem.domain.card.common.util.cardTypesResolver
import com.tangem.domain.common.wallets.UserWalletsListRepository
import com.tangem.domain.common.wallets.getSyncStrict
import com.tangem.domain.models.wallet.UserWallet
import com.tangem.domain.models.wallet.UserWalletId
import com.tangem.domain.models.wallet.isMultiCurrency

View file

@ -8,6 +8,7 @@ import com.tangem.datasource.api.tangemTech.models.account.GetWalletAccountsResp
import com.tangem.datasource.api.tangemTech.models.account.WalletAccountDTO
import com.tangem.domain.account.models.AccountList
import com.tangem.domain.common.wallets.UserWalletsListRepository
import com.tangem.domain.common.wallets.getSyncOrNull
import com.tangem.domain.models.account.Account
import com.tangem.domain.models.account.AccountId
import com.tangem.domain.models.account.DerivationIndex

View file

@ -27,7 +27,7 @@ import org.junit.jupiter.api.TestInstance
@TestInstance(TestInstance.Lifecycle.PER_CLASS)
class DefaultMultiAccountListProducerTest {
private val userWalletsListRepository: UserWalletsListRepository = mockk()
private val userWalletsListRepository: UserWalletsListRepository = mockk(relaxUnitFun = true)
private val walletAccountListFlowFactory: WalletAccountListFlowFactory = mockk()
private val flowProducerTools: FlowProducerTools = mockk()
@ -53,7 +53,7 @@ class DefaultMultiAccountListProducerTest {
fun produce() = runTest {
// Arrange
val userWalletsFlow = MutableStateFlow(value = listOf(userWallet))
every { userWalletsListRepository.loadAndGet() } returns userWalletsFlow
every { userWalletsListRepository.userWallets } returns userWalletsFlow
val accountList = AccountList.empty(userWalletId)
every { walletAccountListFlowFactory.create(userWalletId) } returns flowOf(accountList)
@ -65,8 +65,9 @@ class DefaultMultiAccountListProducerTest {
val expected = listOf(accountList)
Truth.assertThat(actual).containsExactly(expected)
coVerify(ordering = Ordering.SEQUENCE) {
userWalletsListRepository.loadAndGet()
coVerifySequence {
userWalletsListRepository.load()
userWalletsListRepository.userWallets
walletAccountListFlowFactory.create(userWalletId)
}
}
@ -75,7 +76,7 @@ class DefaultMultiAccountListProducerTest {
fun `flow will updated if factoryFlow is updated`() = runTest {
// Arrange
val userWalletsFlow = MutableStateFlow(value = listOf(userWallet))
every { userWalletsListRepository.loadAndGet() } returns userWalletsFlow
every { userWalletsListRepository.userWallets } returns userWalletsFlow
val accountList = AccountList.empty(userWalletId)
val updatedAccountList = AccountList.empty(userWalletId = userWalletId, sortType = TokensSortType.NONE)
@ -97,10 +98,12 @@ class DefaultMultiAccountListProducerTest {
// Assert (second emission)
Truth.assertThat(secondEmission).containsExactly(listOf(updatedAccountList))
coVerify(ordering = Ordering.SEQUENCE) {
userWalletsListRepository.loadAndGet()
coVerifySequence {
userWalletsListRepository.load()
userWalletsListRepository.userWallets
walletAccountListFlowFactory.create(userWalletId)
userWalletsListRepository.loadAndGet()
userWalletsListRepository.load()
userWalletsListRepository.userWallets
walletAccountListFlowFactory.create(userWalletId)
}
}
@ -109,7 +112,7 @@ class DefaultMultiAccountListProducerTest {
fun `flow is filtered the same response`() = runTest {
// Arrange
val userWalletsFlow = MutableStateFlow(value = listOf(userWallet))
every { userWalletsListRepository.loadAndGet() } returns userWalletsFlow
every { userWalletsListRepository.userWallets } returns userWalletsFlow
val accountList = AccountList.empty(userWalletId)
val factoryFlow = MutableStateFlow<AccountList?>(null)
@ -130,10 +133,12 @@ class DefaultMultiAccountListProducerTest {
// Assert (second emission)
Truth.assertThat(secondEmission).containsExactly(listOf(accountList))
coVerify(ordering = Ordering.SEQUENCE) {
userWalletsListRepository.loadAndGet()
coVerifySequence {
userWalletsListRepository.load()
userWalletsListRepository.userWallets
walletAccountListFlowFactory.create(userWalletId)
userWalletsListRepository.loadAndGet()
userWalletsListRepository.load()
userWalletsListRepository.userWallets
walletAccountListFlowFactory.create(userWalletId)
}
}
@ -143,7 +148,7 @@ class DefaultMultiAccountListProducerTest {
fun `flow returns empty list if factory throws exception`() = runTest {
// Arrange
val userWalletsFlow = MutableStateFlow(value = listOf(userWallet))
every { userWalletsListRepository.loadAndGet() } returns userWalletsFlow
every { userWalletsListRepository.userWallets } returns userWalletsFlow
val exception = RuntimeException("Converter error")
every { walletAccountListFlowFactory.create(userWalletId) } throws exception
@ -155,8 +160,9 @@ class DefaultMultiAccountListProducerTest {
val expected = emptyList<AccountList>()
Truth.assertThat(actual).containsExactly(expected)
coVerify(ordering = Ordering.SEQUENCE) {
userWalletsListRepository.loadAndGet()
coVerifySequence {
userWalletsListRepository.load()
userWalletsListRepository.userWallets
walletAccountListFlowFactory.create(userWalletId)
}
}
@ -164,8 +170,8 @@ class DefaultMultiAccountListProducerTest {
@Test
fun `flow is empty if userWalletsFlow returns empty flow`() = runTest {
// Arrange
val userWalletsFlow = emptyFlow<List<UserWallet>>()
every { userWalletsListRepository.loadAndGet() } returns userWalletsFlow
val userWalletsFlow = MutableStateFlow<List<UserWallet>>(emptyList())
every { userWalletsListRepository.userWallets } returns userWalletsFlow
// Act
val actual = producer.produce().let(::getEmittedValues)
@ -173,7 +179,10 @@ class DefaultMultiAccountListProducerTest {
// Assert
Truth.assertThat(actual).isEmpty() // no emissions
coVerify(exactly = 1) { userWalletsListRepository.loadAndGet() }
coVerify(exactly = 1) {
userWalletsListRepository.load()
userWalletsListRepository.userWallets
}
coVerify(inverse = true) { walletAccountListFlowFactory.create(any()) }
}
@ -181,7 +190,7 @@ class DefaultMultiAccountListProducerTest {
fun `flow is empty if factory returns empty flow`() = runTest {
// Arrange
val userWalletsFlow = MutableStateFlow(value = listOf(userWallet))
every { userWalletsListRepository.loadAndGet() } returns userWalletsFlow
every { userWalletsListRepository.userWallets } returns userWalletsFlow
every { walletAccountListFlowFactory.create(userWalletId) } returns emptyFlow()
@ -191,8 +200,9 @@ class DefaultMultiAccountListProducerTest {
// Assert
Truth.assertThat(actual).isEmpty() // no emissions
coVerify(ordering = Ordering.SEQUENCE) {
userWalletsListRepository.loadAndGet()
coVerifySequence {
userWalletsListRepository.load()
userWalletsListRepository.userWallets
walletAccountListFlowFactory.create(userWalletId)
}
}
@ -206,7 +216,7 @@ class DefaultMultiAccountListProducerTest {
}
val userWalletsFlow = MutableStateFlow(listOf(userWallet, userWallet2))
every { userWalletsListRepository.loadAndGet() } returns userWalletsFlow
every { userWalletsListRepository.userWallets } returns userWalletsFlow
val accountList = AccountList.empty(userWalletId)
every { walletAccountListFlowFactory.create(userWalletId) } returns flowOf(accountList)
@ -218,8 +228,9 @@ class DefaultMultiAccountListProducerTest {
// Assert
Truth.assertThat(actual).isEmpty() // no emissions
coVerify(ordering = Ordering.SEQUENCE) {
userWalletsListRepository.loadAndGet()
coVerifySequence {
userWalletsListRepository.load()
userWalletsListRepository.userWallets
walletAccountListFlowFactory.create(userWalletId)
walletAccountListFlowFactory.create(userWalletId2)
}

View file

@ -59,7 +59,9 @@ internal class DefaultMultiWalletCryptoCurrenciesProducerTest {
// Arrange
val userTokensResponseFlow = flowOf<UserTokensResponse?>(null)
every { userWalletsListRepository.getSyncStrict(params.userWalletId) } returns userWallet
val userWalletsFlow = MutableStateFlow(listOf(userWallet))
every { userWalletsListRepository.userWallets } returns userWalletsFlow
every { userTokensResponseStore.get(params.userWalletId) } returns userTokensResponseFlow
// Act
@ -72,7 +74,7 @@ internal class DefaultMultiWalletCryptoCurrenciesProducerTest {
Truth.assertThat(actual.first()).isEqualTo(expected)
verifyOrder {
userWalletsListRepository.getSyncStrict(params.userWalletId)
userWalletsListRepository.userWallets
userTokensResponseStore.get(params.userWalletId)
}
@ -113,7 +115,9 @@ internal class DefaultMultiWalletCryptoCurrenciesProducerTest {
cryptoCurrencyFactory.createCoin(Blockchain.Bitcoin),
)
every { userWalletsListRepository.getSyncStrict(params.userWalletId) } returns userWallet
val userWalletsFlow = MutableStateFlow(listOf(userWallet))
every { userWalletsListRepository.userWallets } returns userWalletsFlow
every { userTokensResponseStore.get(params.userWalletId) } returns userTokensResponseFlow
every {
@ -146,7 +150,7 @@ internal class DefaultMultiWalletCryptoCurrenciesProducerTest {
Truth.assertThat(actual1.first()).isEqualTo(expected1)
verifyOrder {
userWalletsListRepository.getSyncStrict(params.userWalletId)
userWalletsListRepository.userWallets
userTokensResponseStore.get(params.userWalletId)
responseCryptoCurrenciesFactory.createCurrencies(
response = userTokensResponse,
@ -188,7 +192,9 @@ internal class DefaultMultiWalletCryptoCurrenciesProducerTest {
val cryptoCurrencies = emptySet<CryptoCurrency>()
every { userWalletsListRepository.getSyncStrict(params.userWalletId) } returns userWallet
val userWalletsFlow = MutableStateFlow(listOf(userWallet))
every { userWalletsListRepository.userWallets } returns userWalletsFlow
every { userTokensResponseStore.get(params.userWalletId) } returns userTokensResponseFlow
every {
@ -213,7 +219,7 @@ internal class DefaultMultiWalletCryptoCurrenciesProducerTest {
Truth.assertThat(actual1.first()).isEqualTo(expected1)
verifyOrder {
userWalletsListRepository.getSyncStrict(params.userWalletId)
userWalletsListRepository.userWallets
userTokensResponseStore.get(params.userWalletId)
responseCryptoCurrenciesFactory.createCurrencies(
response = userTokensResponse,
@ -257,7 +263,9 @@ internal class DefaultMultiWalletCryptoCurrenciesProducerTest {
}
.buffer(capacity = 5)
every { userWalletsListRepository.getSyncStrict(params.userWalletId) } returns userWallet
val userWalletsFlow = MutableStateFlow(listOf(userWallet))
every { userWalletsListRepository.userWallets } returns userWalletsFlow
every { userTokensResponseStore.get(params.userWalletId) } returns userTokensResponseFlow
every {
@ -279,7 +287,7 @@ internal class DefaultMultiWalletCryptoCurrenciesProducerTest {
Truth.assertThat(actual1.first()).isEqualTo(expected1)
verifyOrder {
userWalletsListRepository.getSyncStrict(params.userWalletId)
userWalletsListRepository.userWallets
userTokensResponseStore.get(params.userWalletId)
}
@ -304,7 +312,9 @@ internal class DefaultMultiWalletCryptoCurrenciesProducerTest {
@Test
fun `flow is empty if store returns empty flow`() = runTest {
// Arrange
every { userWalletsListRepository.getSyncStrict(params.userWalletId) } returns userWallet
val userWalletsFlow = MutableStateFlow(listOf(userWallet))
every { userWalletsListRepository.userWallets } returns userWalletsFlow
every { userTokensResponseStore.get(params.userWalletId) } returns emptyFlow()
// Act
@ -316,7 +326,7 @@ internal class DefaultMultiWalletCryptoCurrenciesProducerTest {
Truth.assertThat(actual.first()).isEqualTo(expected)
verifyOrder {
userWalletsListRepository.getSyncStrict(params.userWalletId)
userWalletsListRepository.userWallets
userTokensResponseStore.get(params.userWalletId)
}
@ -329,10 +339,13 @@ internal class DefaultMultiWalletCryptoCurrenciesProducerTest {
fun `produce throws exception if UserWallet isn't multi-currency wallet`() = runTest {
// Arrange
val mockUserWallet = mockk<UserWallet> {
every { walletId } returns userWallet.walletId
every { isMultiCurrency } returns false
}
every { userWalletsListRepository.getSyncStrict(params.userWalletId) } returns mockUserWallet
val userWalletsFlow = MutableStateFlow(listOf(mockUserWallet))
every { userWalletsListRepository.userWallets } returns userWalletsFlow
// Act
val actual = runCatching { producer.produce() }.exceptionOrNull()
@ -345,7 +358,7 @@ internal class DefaultMultiWalletCryptoCurrenciesProducerTest {
Truth.assertThat(actual).isInstanceOf(expected::class.java)
Truth.assertThat(actual).hasMessageThat().isEqualTo(expected.message)
verifyOrder { userWalletsListRepository.getSyncStrict(params.userWalletId) }
verifyOrder { userWalletsListRepository.userWallets }
verify(inverse = true) {
userTokensResponseStore.get(any())

View file

@ -70,7 +70,9 @@ class WalletAccountListFlowFactoryTest {
every { this@mockk.isMultiCurrency } returns true
}
every { userWalletsListRepository.getSyncStrict(userWalletId) } returns userWallet
val userWalletsFlow = MutableStateFlow(listOf(userWallet))
every { userWalletsListRepository.userWallets } returns userWalletsFlow
val accountsResponse = createGetWalletAccountsResponse(userWalletId)
every { accountsResponseStoreFactory.create(userWalletId) } returns accountsResponseStore
@ -88,7 +90,8 @@ class WalletAccountListFlowFactoryTest {
val expected = accountList
Truth.assertThat(actual).containsExactly(expected)
coVerify(ordering = Ordering.SEQUENCE) {
coVerifySequence {
userWalletsListRepository.userWallets
accountsResponseStoreFactory.create(userWalletId)
accountsResponseStore.data
accountListConverterFactory.create(userWallet)
@ -105,7 +108,9 @@ class WalletAccountListFlowFactoryTest {
fun `create for single wallet`() = runTest {
val userWallet = MockUserWalletFactory.create().copy(isMultiCurrency = false)
every { userWalletsListRepository.getSyncStrict(userWallet.walletId) } returns userWallet
val userWalletsFlow = MutableStateFlow(listOf(userWallet))
every { userWalletsListRepository.userWallets } returns userWalletsFlow
val currency = cryptoCurrencyFactory.ethereum
every { cardCryptoCurrencyFactory.createPrimaryCurrencyForSingleCurrencyCard(userWallet) } returns currency
@ -117,11 +122,12 @@ class WalletAccountListFlowFactoryTest {
val expected = AccountList.empty(userWalletId = userWallet.walletId, cryptoCurrencies = setOf(currency))
Truth.assertThat(actual).containsExactly(expected)
coVerify(ordering = Ordering.SEQUENCE) {
coVerifySequence {
cardCryptoCurrencyFactory.createPrimaryCurrencyForSingleCurrencyCard(userWallet)
}
coVerify(inverse = true) {
userWalletsListRepository.userWallets
cardCryptoCurrencyFactory.createCurrenciesForSingleCurrencyCardWithToken(userWallet = any())
accountsResponseStoreFactory.create(any())
accountsResponseStore.data
@ -134,7 +140,9 @@ class WalletAccountListFlowFactoryTest {
fun `flow is created for single wallet with token`() = runTest {
val nodl = MockUserWalletFactory.createSingleWalletWithToken()
every { userWalletsListRepository.getSyncStrict(nodl.walletId) } returns nodl
val userWalletsFlow = MutableStateFlow(listOf(nodl))
every { userWalletsListRepository.userWallets } returns userWalletsFlow
val currencies = cryptoCurrencyFactory.ethereumAndStellar.toSet()
every {
@ -148,7 +156,8 @@ class WalletAccountListFlowFactoryTest {
val expected = AccountList.empty(userWalletId = nodl.walletId, cryptoCurrencies = currencies)
Truth.assertThat(actual).containsExactly(expected)
coVerify(ordering = Ordering.SEQUENCE) {
coVerifySequence {
userWalletsListRepository.userWallets
cardCryptoCurrencyFactory.createCurrenciesForSingleCurrencyCardWithToken(userWallet = nodl)
}

View file

@ -13,7 +13,11 @@ import com.tangem.domain.common.wallets.UserWalletsListRepository
import com.tangem.domain.models.account.Account
import com.tangem.domain.models.wallet.UserWallet
import com.tangem.domain.models.wallet.UserWalletId
import io.mockk.*
import io.mockk.clearMocks
import io.mockk.coVerifyOrder
import io.mockk.every
import io.mockk.mockk
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.test.runTest
import org.junit.jupiter.api.AfterEach
import org.junit.jupiter.api.BeforeEach
@ -63,7 +67,9 @@ class DefaultWalletAccountsResponseFactoryTest {
tokens = emptyList(),
)
coEvery { userWalletsListRepository.getSyncOrNull(userWalletId) } returns null
val userWalletsFlow = MutableStateFlow<List<UserWallet>?>(null)
every { userWalletsListRepository.userWallets } returns userWalletsFlow
every {
userTokensResponseFactory.createDefaultResponse(
userWallet = null,
@ -89,7 +95,7 @@ class DefaultWalletAccountsResponseFactoryTest {
Truth.assertThat(actual).isEqualTo(expected)
coVerifyOrder {
userWalletsListRepository.getSyncOrNull(userWalletId)
userWalletsListRepository.userWallets
userTokensResponseFactory.createDefaultResponse(
userWallet = null,
networkFactory = networkFactory,
@ -105,7 +111,9 @@ class DefaultWalletAccountsResponseFactoryTest {
every { walletId } returns userWalletId
}
coEvery { userWalletsListRepository.getSyncOrNull(userWalletId) } returns userWallet
val userWalletsFlow = MutableStateFlow(listOf(userWallet))
every { userWalletsListRepository.userWallets } returns userWalletsFlow
val accounts = AccountList.empty(userWallet.walletId).accounts
.filterIsInstance<Account.CryptoPortfolio>()
@ -145,7 +153,7 @@ class DefaultWalletAccountsResponseFactoryTest {
Truth.assertThat(actual).isEqualTo(expected)
coVerifyOrder {
userWalletsListRepository.getSyncOrNull(userWalletId)
userWalletsListRepository.userWallets
cryptoPortfolioConverter.convertListBack(accounts)
userTokensResponseFactory.createDefaultResponse(
userWallet = userWallet,
@ -165,7 +173,9 @@ class DefaultWalletAccountsResponseFactoryTest {
val accounts = AccountList.empty(userWallet.walletId).accounts
.filterIsInstance<Account.CryptoPortfolio>()
coEvery { userWalletsListRepository.getSyncOrNull(userWalletId) } returns userWallet
val userWalletsFlow = MutableStateFlow(listOf(userWallet))
every { userWalletsListRepository.userWallets } returns userWalletsFlow
val defaultResponse = UserTokensResponse(
group = UserTokensResponse.GroupType.NETWORK,
@ -206,7 +216,9 @@ class DefaultWalletAccountsResponseFactoryTest {
val userWallet = mockk<UserWallet>(relaxed = true) {
every { walletId } returns userWalletId
}
coEvery { userWalletsListRepository.getSyncOrNull(userWalletId) } returns userWallet
val userWalletsFlow = MutableStateFlow(listOf(userWallet))
every { userWalletsListRepository.userWallets } returns userWalletsFlow
val userTokensResponse = UserTokensResponse(
group = UserTokensResponse.GroupType.NETWORK,