Updated on 2026-08-14
This commit is contained in:
parent
e6530aa1ee
commit
584be65dd2
7 changed files with 118 additions and 354 deletions
|
|
@ -20,7 +20,18 @@ interface CardCryptoCurrencyFactory {
|
|||
* @param network network
|
||||
*/
|
||||
@Throws
|
||||
suspend fun create(userWalletId: UserWalletId, network: Network): List<CryptoCurrency>
|
||||
suspend fun create(userWalletId: UserWalletId, network: Network): List<CryptoCurrency> {
|
||||
return create(userWalletId = userWalletId, networks = setOf(network))[network].orEmpty()
|
||||
}
|
||||
|
||||
/**
|
||||
* Universal method for creating list of [CryptoCurrency] in [networks] for any card
|
||||
*
|
||||
* @param userWalletId user wallet id that determines type of card
|
||||
* @param networks networks
|
||||
*/
|
||||
@Throws
|
||||
suspend fun create(userWalletId: UserWalletId, networks: Set<Network>): Map<Network, List<CryptoCurrency>>
|
||||
|
||||
/**
|
||||
* Universal method for creating list of [CryptoCurrency] in [network] for any card
|
||||
|
|
|
|||
|
|
@ -2,7 +2,6 @@ package com.tangem.data.common.currency
|
|||
|
||||
import com.tangem.blockchain.common.Blockchain
|
||||
import com.tangem.blockchainsdk.utils.ExcludedBlockchains
|
||||
import com.tangem.blockchainsdk.utils.fromNetworkId
|
||||
import com.tangem.blockchainsdk.utils.toBlockchain
|
||||
import com.tangem.blockchainsdk.utils.toNetworkId
|
||||
import com.tangem.datasource.local.token.UserTokensResponseStore
|
||||
|
|
@ -36,40 +35,45 @@ internal class DefaultCardCryptoCurrencyFactory(
|
|||
|
||||
private val cryptoCurrencyFactory by lazy { CryptoCurrencyFactory(excludedBlockchains) }
|
||||
|
||||
override suspend fun create(userWalletId: UserWalletId, network: Network): List<CryptoCurrency> {
|
||||
override suspend fun create(
|
||||
userWalletId: UserWalletId,
|
||||
networks: Set<Network>,
|
||||
): Map<Network, List<CryptoCurrency>> {
|
||||
val userWallet = userWalletsStore.getSyncStrict(key = userWalletId)
|
||||
|
||||
val blockchain = Blockchain.fromNetworkId(networkId = network.backendId)
|
||||
|
||||
// multi-currency wallet
|
||||
if (userWallet !is UserWallet.Cold || userWallet.isMultiCurrency) {
|
||||
return getMultiWalletCurrencies(userWallet = userWallet, networks = setOf(network))[network].orEmpty()
|
||||
return getMultiWalletCurrencies(userWallet = userWallet, networks = networks)
|
||||
}
|
||||
|
||||
// check if the blockchain of single-currency wallet is the same as network
|
||||
val cardBlockchain = userWallet.scanResponse.cardTypesResolver.getBlockchain()
|
||||
if (cardBlockchain != blockchain) return emptyList()
|
||||
val cardNetworkId = userWallet.scanResponse.cardTypesResolver.getBlockchain().toNetworkId()
|
||||
val cardNetwork = networks.firstOrNull { it.backendId == cardNetworkId }
|
||||
|
||||
if (cardNetwork == null) return emptyMap()
|
||||
|
||||
// single-currency wallet with token (NODL)
|
||||
if (userWallet.scanResponse.cardTypesResolver.isSingleWalletWithToken()) {
|
||||
return createCurrenciesForSingleCurrencyCardWithToken(userWallet.scanResponse)
|
||||
val currencies = createCurrenciesForSingleCurrencyCardWithToken(userWallet.scanResponse)
|
||||
return mapOf(cardNetwork to currencies)
|
||||
}
|
||||
|
||||
// single-currency wallet
|
||||
return createPrimaryCurrencyForSingleCurrencyCard(userWallet.scanResponse).let(::listOf)
|
||||
val primaryCurrency = createPrimaryCurrencyForSingleCurrencyCard(userWallet.scanResponse)
|
||||
return mapOf(cardNetwork to listOf(primaryCurrency))
|
||||
}
|
||||
|
||||
override suspend fun createByRawId(userWalletId: UserWalletId, networkRawId: Network.RawID): List<CryptoCurrency> {
|
||||
override suspend fun createByRawId(userWalletId: UserWalletId, network: Network.RawID): List<CryptoCurrency> {
|
||||
val userWallet = userWalletsStore.getSyncStrict(key = userWalletId)
|
||||
|
||||
val blockchain = networkRawId.toBlockchain()
|
||||
val blockchain = network.toBlockchain()
|
||||
|
||||
// multi-currency wallet
|
||||
if (userWallet.isMultiCurrency || userWallet !is UserWallet.Cold) {
|
||||
return getMultiWalletCurrenciesByRawId(
|
||||
userWallet = userWallet,
|
||||
rawIds = setOf(networkRawId),
|
||||
)[networkRawId].orEmpty()
|
||||
rawIds = setOf(network),
|
||||
)[network].orEmpty()
|
||||
}
|
||||
|
||||
// check if the blockchain of single-currency wallet is the same as network
|
||||
|
|
@ -143,13 +147,15 @@ internal class DefaultCardCryptoCurrencyFactory(
|
|||
val response = userTokensResponseStore.getSyncOrNull(userWalletId = userWallet.walletId)
|
||||
?: return emptyMap()
|
||||
|
||||
return responseCryptoCurrenciesFactory.createCurrencies(
|
||||
val existingNetworkWithCurrencies = responseCryptoCurrenciesFactory.createCurrencies(
|
||||
tokens = response.tokens.filter { token ->
|
||||
networks.any { it.backendId == token.networkId && it.derivationPath.value == token.derivationPath }
|
||||
},
|
||||
scanResponse = userWallet.requireColdWallet().scanResponse, // TODO [REDACTED_TASK_KEY]
|
||||
)
|
||||
.groupBy(CryptoCurrency::network)
|
||||
|
||||
return networks.associateWith { emptyList<CryptoCurrency>() } + existingNetworkWithCurrencies
|
||||
}
|
||||
|
||||
private suspend fun getMultiWalletCurrenciesByRawId(
|
||||
|
|
|
|||
|
|
@ -266,7 +266,9 @@ internal class DefaultCardCryptoCurrencyFactoryTest {
|
|||
CreateCurrenciesForMultiWalletModel(
|
||||
multiWallet = createMultiWallet(),
|
||||
userTokensResponse = createUserTokensResponse(),
|
||||
expected = Result.success(emptyMap()),
|
||||
expected = Result.success(
|
||||
setOf(ethereum.network, bitcoin.network).associateWith { emptyList() },
|
||||
),
|
||||
),
|
||||
CreateCurrenciesForMultiWalletModel(
|
||||
multiWallet = createMultiWallet(),
|
||||
|
|
|
|||
|
|
@ -7,11 +7,10 @@ import com.tangem.data.networks.fetcher.CommonNetworkStatusFetcher
|
|||
import com.tangem.data.networks.store.NetworksStatusesStore
|
||||
import com.tangem.data.networks.store.setSourceAsCache
|
||||
import com.tangem.data.networks.store.setSourceAsOnlyCache
|
||||
import com.tangem.datasource.local.userwallet.UserWalletsStore
|
||||
import com.tangem.domain.common.util.cardTypesResolver
|
||||
import com.tangem.domain.core.utils.eitherOn
|
||||
import com.tangem.domain.models.currency.CryptoCurrency
|
||||
import com.tangem.domain.models.network.Network
|
||||
import com.tangem.domain.networks.multi.MultiNetworkStatusFetcher
|
||||
import com.tangem.domain.wallets.models.requireColdWallet
|
||||
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
|
||||
import kotlinx.coroutines.async
|
||||
import kotlinx.coroutines.awaitAll
|
||||
|
|
@ -22,7 +21,6 @@ import javax.inject.Inject
|
|||
* Default implementation of [MultiNetworkStatusFetcher]
|
||||
*
|
||||
* @property networksStatusesStore networks statuses store
|
||||
* @property userWalletsStore user wallets store
|
||||
* @property cardCryptoCurrencyFactory card crypto currency factory
|
||||
* @property commonNetworkStatusFetcher common network status fetcher
|
||||
* @property dispatchers dispatchers
|
||||
|
|
@ -32,7 +30,6 @@ import javax.inject.Inject
|
|||
@Suppress("LongParameterList")
|
||||
internal class DefaultMultiNetworkStatusFetcher @Inject constructor(
|
||||
private val networksStatusesStore: NetworksStatusesStore,
|
||||
private val userWalletsStore: UserWalletsStore,
|
||||
private val cardCryptoCurrencyFactory: CardCryptoCurrencyFactory,
|
||||
private val commonNetworkStatusFetcher: CommonNetworkStatusFetcher,
|
||||
private val dispatchers: CoroutineDispatcherProvider,
|
||||
|
|
@ -41,8 +38,8 @@ internal class DefaultMultiNetworkStatusFetcher @Inject constructor(
|
|||
override suspend fun invoke(params: MultiNetworkStatusFetcher.Params) = eitherOn(dispatchers.default) {
|
||||
networksStatusesStore.setSourceAsCache(userWalletId = params.userWalletId, networks = params.networks)
|
||||
|
||||
val userWallet = catch(
|
||||
block = { userWalletsStore.getSyncStrict(key = params.userWalletId) },
|
||||
val networksCurrencies = catch(
|
||||
block = { createNetworksCurrenciesMap(params) },
|
||||
catch = {
|
||||
networksStatusesStore.setSourceAsOnlyCache(
|
||||
userWalletId = params.userWalletId,
|
||||
|
|
@ -53,31 +50,6 @@ internal class DefaultMultiNetworkStatusFetcher @Inject constructor(
|
|||
},
|
||||
)
|
||||
|
||||
val cardTypesResolver = userWallet.requireColdWallet().cardTypesResolver // TODO [REDACTED_TASK_KEY]
|
||||
val isWalletSupported = with(cardTypesResolver) {
|
||||
isMultiwalletAllowed() || isSingleWalletWithToken()
|
||||
}
|
||||
|
||||
ensure(isWalletSupported) {
|
||||
networksStatusesStore.setSourceAsOnlyCache(
|
||||
userWalletId = params.userWalletId,
|
||||
networks = params.networks,
|
||||
)
|
||||
IllegalStateException("User wallet is not multi-currency")
|
||||
}
|
||||
|
||||
val networksCurrencies = if (cardTypesResolver.isMultiwalletAllowed()) {
|
||||
cardCryptoCurrencyFactory.createCurrenciesForMultiCurrencyCard(
|
||||
userWallet = userWallet,
|
||||
networks = params.networks,
|
||||
)
|
||||
} else {
|
||||
cardCryptoCurrencyFactory.createCurrenciesForSingleCurrencyCardWithToken(
|
||||
scanResponse = userWallet.scanResponse,
|
||||
)
|
||||
.groupBy { it.network }
|
||||
}
|
||||
|
||||
val result = coroutineScope {
|
||||
params.networks
|
||||
.map { network ->
|
||||
|
|
@ -98,4 +70,13 @@ internal class DefaultMultiNetworkStatusFetcher @Inject constructor(
|
|||
IllegalStateException("Failed to fetch network statuses")
|
||||
}
|
||||
}
|
||||
|
||||
private suspend fun createNetworksCurrenciesMap(
|
||||
params: MultiNetworkStatusFetcher.Params,
|
||||
): Map<Network, List<CryptoCurrency>> {
|
||||
return cardCryptoCurrencyFactory.create(
|
||||
userWalletId = params.userWalletId,
|
||||
networks = params.networks,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -1,47 +1,27 @@
|
|||
package com.tangem.data.networks.single
|
||||
|
||||
import arrow.core.Either
|
||||
import com.tangem.data.common.currency.CardCryptoCurrencyFactory
|
||||
import com.tangem.data.networks.fetcher.CommonNetworkStatusFetcher
|
||||
import com.tangem.data.networks.store.NetworksStatusesStore
|
||||
import com.tangem.data.networks.store.setSourceAsCache
|
||||
import com.tangem.domain.core.utils.catchOn
|
||||
import com.tangem.domain.networks.multi.MultiNetworkStatusFetcher
|
||||
import com.tangem.domain.networks.single.SingleNetworkStatusFetcher
|
||||
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
|
||||
import javax.inject.Inject
|
||||
|
||||
/**
|
||||
* Default implementation of [SingleNetworkStatusFetcher]
|
||||
*
|
||||
* @property commonNetworkStatusFetcher common network status fetcher
|
||||
* @property networksStatusesStore networks statuses store
|
||||
* @property cardCryptoCurrencyFactory card crypto currency factory
|
||||
* @property dispatchers dispatchers
|
||||
* @property multiNetworkStatusFetcher multi network status fetcher
|
||||
*
|
||||
[REDACTED_AUTHOR]
|
||||
*/
|
||||
internal class DefaultSingleNetworkStatusFetcher @Inject constructor(
|
||||
private val commonNetworkStatusFetcher: CommonNetworkStatusFetcher,
|
||||
private val networksStatusesStore: NetworksStatusesStore,
|
||||
private val cardCryptoCurrencyFactory: CardCryptoCurrencyFactory,
|
||||
private val dispatchers: CoroutineDispatcherProvider,
|
||||
private val multiNetworkStatusFetcher: MultiNetworkStatusFetcher,
|
||||
) : SingleNetworkStatusFetcher {
|
||||
|
||||
override suspend fun invoke(params: SingleNetworkStatusFetcher.Params): Either<Throwable, Unit> {
|
||||
return Either.catchOn(dispatchers.default) {
|
||||
networksStatusesStore.setSourceAsCache(userWalletId = params.userWalletId, network = params.network)
|
||||
|
||||
val networkCurrencies = cardCryptoCurrencyFactory.create(
|
||||
return multiNetworkStatusFetcher(
|
||||
params = MultiNetworkStatusFetcher.Params(
|
||||
userWalletId = params.userWalletId,
|
||||
network = params.network,
|
||||
)
|
||||
|
||||
commonNetworkStatusFetcher.fetch(
|
||||
userWalletId = params.userWalletId,
|
||||
network = params.network,
|
||||
networkCurrencies = networkCurrencies.toSet(),
|
||||
)
|
||||
.onLeft { throw it }
|
||||
}
|
||||
networks = setOf(params.network),
|
||||
),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -1,19 +1,15 @@
|
|||
package com.tangem.data.networks.multi
|
||||
|
||||
import arrow.core.Either
|
||||
import com.google.common.truth.Truth
|
||||
import arrow.core.left
|
||||
import com.tangem.common.test.domain.token.MockCryptoCurrencyFactory
|
||||
import com.tangem.common.test.domain.wallet.MockUserWalletFactory
|
||||
import com.tangem.common.test.utils.assertEither
|
||||
import com.tangem.data.common.currency.CardCryptoCurrencyFactory
|
||||
import com.tangem.data.networks.fetcher.CommonNetworkStatusFetcher
|
||||
import com.tangem.data.networks.store.NetworksStatusesStore
|
||||
import com.tangem.data.networks.store.setSourceAsCache
|
||||
import com.tangem.data.networks.store.setSourceAsOnlyCache
|
||||
import com.tangem.datasource.local.userwallet.UserWalletsStore
|
||||
import com.tangem.domain.common.CardTypesResolver
|
||||
import com.tangem.domain.common.util.cardTypesResolver
|
||||
import com.tangem.domain.networks.multi.MultiNetworkStatusFetcher
|
||||
import com.tangem.domain.wallets.models.UserWallet
|
||||
import com.tangem.domain.wallets.models.UserWalletId
|
||||
import com.tangem.utils.coroutines.TestingCoroutineDispatcherProvider
|
||||
import io.mockk.*
|
||||
|
|
@ -29,13 +25,11 @@ import org.junit.jupiter.api.TestInstance
|
|||
internal class DefaultMultiNetworkStatusFetcherTest {
|
||||
|
||||
private val networksStatusesStore: NetworksStatusesStore = mockk(relaxUnitFun = true)
|
||||
private val userWalletsStore: UserWalletsStore = mockk()
|
||||
private val cardCryptoCurrencyFactory: CardCryptoCurrencyFactory = mockk()
|
||||
private val commonNetworkStatusFetcher: CommonNetworkStatusFetcher = mockk()
|
||||
|
||||
private val fetcher = DefaultMultiNetworkStatusFetcher(
|
||||
networksStatusesStore = networksStatusesStore,
|
||||
userWalletsStore = userWalletsStore,
|
||||
cardCryptoCurrencyFactory = cardCryptoCurrencyFactory,
|
||||
commonNetworkStatusFetcher = commonNetworkStatusFetcher,
|
||||
dispatchers = TestingCoroutineDispatcherProvider(),
|
||||
|
|
@ -43,16 +37,17 @@ internal class DefaultMultiNetworkStatusFetcherTest {
|
|||
|
||||
@BeforeEach
|
||||
fun resetMocks() {
|
||||
clearMocks(networksStatusesStore, userWalletsStore, cardCryptoCurrencyFactory, commonNetworkStatusFetcher)
|
||||
clearMocks(networksStatusesStore, cardCryptoCurrencyFactory, commonNetworkStatusFetcher)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `fetch successfully for multi-currency card`() = runTest {
|
||||
fun `fetch successfully`() = runTest {
|
||||
// Arrange
|
||||
val networks = setOf(ethereum.network, cardano.network)
|
||||
val params = MultiNetworkStatusFetcher.Params(userWalletId = userWalletId, networks = networks)
|
||||
val userWallet = MockUserWalletFactory.create()
|
||||
val cardTypesResolver = mockk<CardTypesResolver>()
|
||||
val params = MultiNetworkStatusFetcher.Params(
|
||||
userWalletId = userWalletId,
|
||||
networks = setOf(ethereum.network, cardano.network),
|
||||
)
|
||||
|
||||
val networksCurrencies = mapOf(
|
||||
ethereum.network to listOf(ethereum),
|
||||
cardano.network to listOf(cardano),
|
||||
|
|
@ -60,16 +55,7 @@ internal class DefaultMultiNetworkStatusFetcherTest {
|
|||
val ethereumFetcherResult = Either.Right(Unit)
|
||||
val cardanoFetcherResult = Either.Right(Unit)
|
||||
|
||||
coEvery { networksStatusesStore.setSourceAsCache(params.userWalletId, params.networks) } returns Unit
|
||||
every { userWalletsStore.getSyncStrict(key = userWalletId) } returns userWallet
|
||||
|
||||
mockkStatic(UserWallet.Cold::cardTypesResolver)
|
||||
every { userWallet.cardTypesResolver } returns cardTypesResolver
|
||||
coEvery { cardTypesResolver.isMultiwalletAllowed() } returns true
|
||||
|
||||
coEvery {
|
||||
cardCryptoCurrencyFactory.createCurrenciesForMultiCurrencyCard(userWallet, params.networks)
|
||||
} returns networksCurrencies
|
||||
coEvery { cardCryptoCurrencyFactory.create(params.userWalletId, params.networks) } returns networksCurrencies
|
||||
|
||||
coEvery {
|
||||
commonNetworkStatusFetcher.fetch(
|
||||
|
|
@ -92,14 +78,11 @@ internal class DefaultMultiNetworkStatusFetcherTest {
|
|||
|
||||
// Assert
|
||||
val expected = Either.Right(Unit)
|
||||
|
||||
Truth.assertThat(actual).isEqualTo(expected)
|
||||
assertEither(actual, expected)
|
||||
|
||||
coVerifyOrder {
|
||||
networksStatusesStore.setSourceAsCache(params.userWalletId, params.networks)
|
||||
userWalletsStore.getSyncStrict(key = userWalletId)
|
||||
cardTypesResolver.isMultiwalletAllowed()
|
||||
cardCryptoCurrencyFactory.createCurrenciesForMultiCurrencyCard(userWallet, params.networks)
|
||||
cardCryptoCurrencyFactory.create(params.userWalletId, params.networks)
|
||||
commonNetworkStatusFetcher.fetch(
|
||||
userWalletId = params.userWalletId,
|
||||
network = ethereum.network,
|
||||
|
|
@ -114,75 +97,17 @@ internal class DefaultMultiNetworkStatusFetcherTest {
|
|||
|
||||
coVerify(inverse = true) {
|
||||
networksStatusesStore.setSourceAsOnlyCache(userWalletId = any(), networks = any())
|
||||
cardTypesResolver.isSingleWalletWithToken()
|
||||
cardCryptoCurrencyFactory.createCurrenciesForSingleCurrencyCardWithToken(scanResponse = any())
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `fetch successfully for single-currency card with token`() = runTest {
|
||||
// Arrange
|
||||
val networks = setOf(ethereum.network)
|
||||
val params = MultiNetworkStatusFetcher.Params(userWalletId = userWalletId, networks = networks)
|
||||
val userWallet = MockUserWalletFactory.create()
|
||||
val cardTypesResolver = mockk<CardTypesResolver>()
|
||||
val networksCurrencies = listOf(ethereum)
|
||||
val ethereumFetcherResult = Either.Right(Unit)
|
||||
|
||||
coEvery { networksStatusesStore.setSourceAsCache(params.userWalletId, params.networks) } returns Unit
|
||||
every { userWalletsStore.getSyncStrict(key = userWalletId) } returns userWallet
|
||||
|
||||
mockkStatic(UserWallet.Cold::cardTypesResolver)
|
||||
every { userWallet.cardTypesResolver } returns cardTypesResolver
|
||||
coEvery { cardTypesResolver.isMultiwalletAllowed() } returns false
|
||||
coEvery { cardTypesResolver.isSingleWalletWithToken() } returns true
|
||||
|
||||
coEvery {
|
||||
cardCryptoCurrencyFactory.createCurrenciesForSingleCurrencyCardWithToken(userWallet.scanResponse)
|
||||
} returns networksCurrencies
|
||||
|
||||
coEvery {
|
||||
commonNetworkStatusFetcher.fetch(
|
||||
userWalletId = params.userWalletId,
|
||||
network = ethereum.network,
|
||||
networkCurrencies = setOf(ethereum),
|
||||
)
|
||||
} returns ethereumFetcherResult
|
||||
|
||||
// Act
|
||||
val actual = fetcher(params)
|
||||
|
||||
// Assert
|
||||
val expected = Either.Right(Unit)
|
||||
|
||||
Truth.assertThat(actual).isEqualTo(expected)
|
||||
|
||||
coVerifyOrder {
|
||||
networksStatusesStore.setSourceAsCache(params.userWalletId, params.networks)
|
||||
userWalletsStore.getSyncStrict(key = userWalletId)
|
||||
cardTypesResolver.isMultiwalletAllowed()
|
||||
cardTypesResolver.isSingleWalletWithToken()
|
||||
cardCryptoCurrencyFactory.createCurrenciesForSingleCurrencyCardWithToken(userWallet.scanResponse)
|
||||
commonNetworkStatusFetcher.fetch(
|
||||
userWalletId = params.userWalletId,
|
||||
network = ethereum.network,
|
||||
networkCurrencies = setOf(ethereum),
|
||||
)
|
||||
}
|
||||
|
||||
coVerify(inverse = true) {
|
||||
networksStatusesStore.setSourceAsOnlyCache(userWalletId = any(), networks = any())
|
||||
cardCryptoCurrencyFactory.createCurrenciesForMultiCurrencyCard(any(), any())
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `fetch failure if one of them fails`() = runTest {
|
||||
// Arrange
|
||||
val networks = setOf(ethereum.network, cardano.network)
|
||||
val params = MultiNetworkStatusFetcher.Params(userWalletId = userWalletId, networks = networks)
|
||||
val userWallet = MockUserWalletFactory.create()
|
||||
val cardTypesResolver = mockk<CardTypesResolver>()
|
||||
val params = MultiNetworkStatusFetcher.Params(
|
||||
userWalletId = userWalletId,
|
||||
networks = setOf(ethereum.network, cardano.network),
|
||||
)
|
||||
|
||||
val networksCurrencies = mapOf(
|
||||
ethereum.network to listOf(ethereum),
|
||||
cardano.network to listOf(cardano),
|
||||
|
|
@ -190,16 +115,7 @@ internal class DefaultMultiNetworkStatusFetcherTest {
|
|||
val ethereumFetcherResult = Either.Left(IllegalStateException())
|
||||
val cardanoFetcherResult = Either.Right(Unit)
|
||||
|
||||
coEvery { networksStatusesStore.setSourceAsCache(params.userWalletId, params.networks) } returns Unit
|
||||
every { userWalletsStore.getSyncStrict(key = userWalletId) } returns userWallet
|
||||
|
||||
mockkStatic(UserWallet.Cold::cardTypesResolver)
|
||||
every { userWallet.cardTypesResolver } returns cardTypesResolver
|
||||
coEvery { cardTypesResolver.isMultiwalletAllowed() } returns true
|
||||
|
||||
coEvery {
|
||||
cardCryptoCurrencyFactory.createCurrenciesForMultiCurrencyCard(userWallet, params.networks)
|
||||
} returns networksCurrencies
|
||||
coEvery { cardCryptoCurrencyFactory.create(params.userWalletId, params.networks) } returns networksCurrencies
|
||||
|
||||
coEvery {
|
||||
commonNetworkStatusFetcher.fetch(
|
||||
|
|
@ -222,15 +138,11 @@ internal class DefaultMultiNetworkStatusFetcherTest {
|
|||
|
||||
// Assert
|
||||
val expected = Either.Left(IllegalStateException("Failed to fetch network statuses"))
|
||||
Truth.assertThat(actual.isLeft()).isTrue()
|
||||
Truth.assertThat(actual.leftOrNull()).isInstanceOf(expected.leftOrNull()!!::class.java)
|
||||
Truth.assertThat(actual.leftOrNull()).hasMessageThat().isEqualTo(expected.leftOrNull()!!.message)
|
||||
assertEither(actual, expected)
|
||||
|
||||
coVerifyOrder {
|
||||
networksStatusesStore.setSourceAsCache(params.userWalletId, params.networks)
|
||||
userWalletsStore.getSyncStrict(key = userWalletId)
|
||||
cardTypesResolver.isMultiwalletAllowed()
|
||||
cardCryptoCurrencyFactory.createCurrenciesForMultiCurrencyCard(userWallet, params.networks)
|
||||
cardCryptoCurrencyFactory.create(params.userWalletId, params.networks)
|
||||
commonNetworkStatusFetcher.fetch(
|
||||
userWalletId = params.userWalletId,
|
||||
network = ethereum.network,
|
||||
|
|
@ -245,18 +157,17 @@ internal class DefaultMultiNetworkStatusFetcherTest {
|
|||
|
||||
coVerify(inverse = true) {
|
||||
networksStatusesStore.setSourceAsOnlyCache(userWalletId = any(), networks = any())
|
||||
cardTypesResolver.isSingleWalletWithToken()
|
||||
cardCryptoCurrencyFactory.createCurrenciesForSingleCurrencyCardWithToken(scanResponse = any())
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `fetch failure if all of them fails`() = runTest {
|
||||
// Arrange
|
||||
val networks = setOf(ethereum.network, cardano.network)
|
||||
val params = MultiNetworkStatusFetcher.Params(userWalletId = userWalletId, networks = networks)
|
||||
val userWallet = MockUserWalletFactory.create()
|
||||
val cardTypesResolver = mockk<CardTypesResolver>()
|
||||
val params = MultiNetworkStatusFetcher.Params(
|
||||
userWalletId = userWalletId,
|
||||
networks = setOf(ethereum.network, cardano.network),
|
||||
)
|
||||
|
||||
val networksCurrencies = mapOf(
|
||||
ethereum.network to listOf(ethereum),
|
||||
cardano.network to listOf(cardano),
|
||||
|
|
@ -264,16 +175,7 @@ internal class DefaultMultiNetworkStatusFetcherTest {
|
|||
val ethereumFetcherResult = Either.Left(IllegalStateException("ethereum"))
|
||||
val cardanoFetcherResult = Either.Left(IllegalStateException("cardano"))
|
||||
|
||||
coEvery { networksStatusesStore.setSourceAsCache(params.userWalletId, params.networks) } returns Unit
|
||||
every { userWalletsStore.getSyncStrict(key = userWalletId) } returns userWallet
|
||||
|
||||
mockkStatic(UserWallet.Cold::cardTypesResolver)
|
||||
every { userWallet.cardTypesResolver } returns cardTypesResolver
|
||||
coEvery { cardTypesResolver.isMultiwalletAllowed() } returns true
|
||||
|
||||
coEvery {
|
||||
cardCryptoCurrencyFactory.createCurrenciesForMultiCurrencyCard(userWallet, params.networks)
|
||||
} returns networksCurrencies
|
||||
coEvery { cardCryptoCurrencyFactory.create(params.userWalletId, params.networks) } returns networksCurrencies
|
||||
|
||||
coEvery {
|
||||
commonNetworkStatusFetcher.fetch(
|
||||
|
|
@ -296,15 +198,11 @@ internal class DefaultMultiNetworkStatusFetcherTest {
|
|||
|
||||
// Assert
|
||||
val expected = Either.Left(IllegalStateException("Failed to fetch network statuses"))
|
||||
Truth.assertThat(actual.isLeft()).isTrue()
|
||||
Truth.assertThat(actual.leftOrNull()).isInstanceOf(expected.leftOrNull()!!::class.java)
|
||||
Truth.assertThat(actual.leftOrNull()).hasMessageThat().isEqualTo(expected.leftOrNull()!!.message)
|
||||
assertEither(actual, expected)
|
||||
|
||||
coVerifyOrder {
|
||||
networksStatusesStore.setSourceAsCache(params.userWalletId, params.networks)
|
||||
userWalletsStore.getSyncStrict(key = userWalletId)
|
||||
cardTypesResolver.isMultiwalletAllowed()
|
||||
cardCryptoCurrencyFactory.createCurrenciesForMultiCurrencyCard(userWallet, params.networks)
|
||||
cardCryptoCurrencyFactory.create(params.userWalletId, params.networks)
|
||||
commonNetworkStatusFetcher.fetch(
|
||||
userWalletId = params.userWalletId,
|
||||
network = ethereum.network,
|
||||
|
|
@ -319,85 +217,35 @@ internal class DefaultMultiNetworkStatusFetcherTest {
|
|||
|
||||
coVerify(inverse = true) {
|
||||
networksStatusesStore.setSourceAsOnlyCache(userWalletId = any(), networks = any())
|
||||
cardTypesResolver.isSingleWalletWithToken()
|
||||
cardCryptoCurrencyFactory.createCurrenciesForSingleCurrencyCardWithToken(scanResponse = any())
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `fetch failure if userWalletsStore throws exception`() = runTest {
|
||||
fun `fetch failure if cardCryptoCurrencyFactory throws exception`() = runTest {
|
||||
// Arrange
|
||||
val networks = setOf(ethereum.network, cardano.network)
|
||||
val params = MultiNetworkStatusFetcher.Params(userWalletId = userWalletId, networks = networks)
|
||||
val userWalletStoreException = IllegalStateException()
|
||||
val params = MultiNetworkStatusFetcher.Params(
|
||||
userWalletId = userWalletId,
|
||||
networks = setOf(ethereum.network, cardano.network),
|
||||
)
|
||||
|
||||
coEvery { networksStatusesStore.setSourceAsCache(params.userWalletId, params.networks) } returns Unit
|
||||
every { userWalletsStore.getSyncStrict(key = userWalletId) } throws userWalletStoreException
|
||||
coEvery { networksStatusesStore.setSourceAsOnlyCache(params.userWalletId, params.networks) } returns Unit
|
||||
val factoryException = IllegalStateException()
|
||||
|
||||
coEvery { cardCryptoCurrencyFactory.create(params.userWalletId, params.networks) } throws factoryException
|
||||
|
||||
// Act
|
||||
val actual = fetcher(params)
|
||||
|
||||
// Assert
|
||||
val expected = Either.Left(userWalletStoreException)
|
||||
|
||||
Truth.assertThat(actual).isEqualTo(expected)
|
||||
val expected = factoryException.left()
|
||||
assertEither(actual, expected)
|
||||
|
||||
coVerifyOrder {
|
||||
networksStatusesStore.setSourceAsCache(params.userWalletId, params.networks)
|
||||
userWalletsStore.getSyncStrict(key = userWalletId)
|
||||
cardCryptoCurrencyFactory.create(params.userWalletId, params.networks)
|
||||
networksStatusesStore.setSourceAsOnlyCache(params.userWalletId, params.networks)
|
||||
}
|
||||
|
||||
coVerify(inverse = true) {
|
||||
cardCryptoCurrencyFactory.createCurrenciesForMultiCurrencyCard(any(), any())
|
||||
cardCryptoCurrencyFactory.createCurrenciesForSingleCurrencyCardWithToken(scanResponse = any())
|
||||
commonNetworkStatusFetcher.fetch(any(), any(), any())
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `fetch failure if card is single-currency`() = runTest {
|
||||
// Arrange
|
||||
val networks = setOf(ethereum.network, cardano.network)
|
||||
val params = MultiNetworkStatusFetcher.Params(userWalletId = userWalletId, networks = networks)
|
||||
val userWallet = MockUserWalletFactory.create()
|
||||
val cardTypesResolver = mockk<CardTypesResolver>()
|
||||
|
||||
coEvery { networksStatusesStore.setSourceAsCache(params.userWalletId, params.networks) } returns Unit
|
||||
every { userWalletsStore.getSyncStrict(key = userWalletId) } returns userWallet
|
||||
|
||||
mockkStatic(UserWallet.Cold::cardTypesResolver)
|
||||
every { userWallet.cardTypesResolver } returns cardTypesResolver
|
||||
coEvery { cardTypesResolver.isMultiwalletAllowed() } returns false
|
||||
coEvery { cardTypesResolver.isSingleWalletWithToken() } returns false
|
||||
|
||||
coEvery { networksStatusesStore.setSourceAsOnlyCache(params.userWalletId, params.networks) } returns Unit
|
||||
|
||||
// Act
|
||||
val actual = fetcher(params)
|
||||
|
||||
// Assert
|
||||
val expected = Either.Left(IllegalStateException("User wallet is not multi-currency"))
|
||||
|
||||
Truth.assertThat(actual.isLeft()).isTrue()
|
||||
Truth.assertThat(actual.leftOrNull()).isInstanceOf(expected.leftOrNull()!!::class.java)
|
||||
Truth.assertThat(actual.leftOrNull()).hasMessageThat().isEqualTo(expected.leftOrNull()!!.message)
|
||||
|
||||
coVerifyOrder {
|
||||
networksStatusesStore.setSourceAsCache(params.userWalletId, params.networks)
|
||||
userWalletsStore.getSyncStrict(key = userWalletId)
|
||||
cardTypesResolver.isMultiwalletAllowed()
|
||||
cardTypesResolver.isSingleWalletWithToken()
|
||||
networksStatusesStore.setSourceAsOnlyCache(params.userWalletId, params.networks)
|
||||
}
|
||||
|
||||
coVerify(inverse = true) {
|
||||
networksStatusesStore.setSourceAsOnlyCache(userWalletId = any(), networks = any())
|
||||
cardCryptoCurrencyFactory.createCurrenciesForMultiCurrencyCard(any(), any())
|
||||
cardCryptoCurrencyFactory.createCurrenciesForSingleCurrencyCardWithToken(scanResponse = any())
|
||||
commonNetworkStatusFetcher.fetch(any(), any(), any())
|
||||
}
|
||||
coVerify(inverse = true) { commonNetworkStatusFetcher.fetch(any(), any(), any()) }
|
||||
}
|
||||
|
||||
private companion object {
|
||||
|
|
|
|||
|
|
@ -2,16 +2,15 @@ package com.tangem.data.networks.single
|
|||
|
||||
import arrow.core.Either
|
||||
import arrow.core.left
|
||||
import com.google.common.truth.Truth
|
||||
import com.tangem.common.test.domain.token.MockCryptoCurrencyFactory
|
||||
import com.tangem.data.common.currency.CardCryptoCurrencyFactory
|
||||
import com.tangem.data.networks.fetcher.CommonNetworkStatusFetcher
|
||||
import com.tangem.data.networks.store.NetworksStatusesStore
|
||||
import com.tangem.data.networks.store.setSourceAsCache
|
||||
import com.tangem.common.test.utils.assertEither
|
||||
import com.tangem.domain.networks.multi.MultiNetworkStatusFetcher
|
||||
import com.tangem.domain.networks.single.SingleNetworkStatusFetcher
|
||||
import com.tangem.domain.wallets.models.UserWalletId
|
||||
import com.tangem.utils.coroutines.TestingCoroutineDispatcherProvider
|
||||
import io.mockk.*
|
||||
import io.mockk.clearMocks
|
||||
import io.mockk.coEvery
|
||||
import io.mockk.coVerify
|
||||
import io.mockk.mockk
|
||||
import kotlinx.coroutines.test.runTest
|
||||
import org.junit.jupiter.api.BeforeEach
|
||||
import org.junit.jupiter.api.Test
|
||||
|
|
@ -23,114 +22,51 @@ import org.junit.jupiter.api.TestInstance
|
|||
@TestInstance(TestInstance.Lifecycle.PER_CLASS)
|
||||
internal class DefaultSingleNetworkStatusFetcherTest {
|
||||
|
||||
private val commonNetworkStatusFetcher: CommonNetworkStatusFetcher = mockk()
|
||||
private val networksStatusesStore: NetworksStatusesStore = mockk(relaxUnitFun = true)
|
||||
private val cardCryptoCurrencyFactory: CardCryptoCurrencyFactory = mockk()
|
||||
private val multiNetworkStatusFetcher: MultiNetworkStatusFetcher = mockk()
|
||||
|
||||
private val fetcher = DefaultSingleNetworkStatusFetcher(
|
||||
commonNetworkStatusFetcher = commonNetworkStatusFetcher,
|
||||
networksStatusesStore = networksStatusesStore,
|
||||
cardCryptoCurrencyFactory = cardCryptoCurrencyFactory,
|
||||
dispatchers = TestingCoroutineDispatcherProvider(),
|
||||
)
|
||||
private val fetcher = DefaultSingleNetworkStatusFetcher(multiNetworkStatusFetcher = multiNetworkStatusFetcher)
|
||||
|
||||
@BeforeEach
|
||||
fun resetMocks() {
|
||||
clearMocks(commonNetworkStatusFetcher, networksStatusesStore, cardCryptoCurrencyFactory)
|
||||
clearMocks(multiNetworkStatusFetcher)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `fetch successfully`() = runTest {
|
||||
// Arrange
|
||||
val params = SingleNetworkStatusFetcher.Params(userWalletId = userWalletId, network = ethereum.network)
|
||||
val networkCurrencies = listOf(ethereum)
|
||||
val commonFetcherResult = Either.Right(Unit)
|
||||
val multiParams = MultiNetworkStatusFetcher.Params(userWalletId, setOf(params.network))
|
||||
val multiFetcherResult = Either.Right(Unit)
|
||||
|
||||
coEvery { networksStatusesStore.setSourceAsCache(params.userWalletId, params.network) } returns Unit
|
||||
coEvery { cardCryptoCurrencyFactory.create(params.userWalletId, params.network) } returns networkCurrencies
|
||||
coEvery {
|
||||
commonNetworkStatusFetcher.fetch(
|
||||
userWalletId = params.userWalletId,
|
||||
network = params.network,
|
||||
networkCurrencies = networkCurrencies.toSet(),
|
||||
)
|
||||
} returns commonFetcherResult
|
||||
coEvery { multiNetworkStatusFetcher(params = multiParams) } returns multiFetcherResult
|
||||
|
||||
// Act
|
||||
val actual = fetcher(params)
|
||||
|
||||
// Assert
|
||||
val expected = commonFetcherResult
|
||||
val expected = multiFetcherResult
|
||||
assertEither(actual, expected)
|
||||
|
||||
Truth.assertThat(actual).isEqualTo(expected)
|
||||
|
||||
coVerifyOrder {
|
||||
networksStatusesStore.setSourceAsCache(params.userWalletId, params.network)
|
||||
cardCryptoCurrencyFactory.create(params.userWalletId, params.network)
|
||||
commonNetworkStatusFetcher.fetch(params.userWalletId, params.network, setOf(ethereum))
|
||||
}
|
||||
coVerify(exactly = 1) { multiNetworkStatusFetcher(params = multiParams) }
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `fetch failure if cardCryptoCurrencyFactory throws exception`() = runTest {
|
||||
fun `fetch failure`() = runTest {
|
||||
// Arrange
|
||||
val params = SingleNetworkStatusFetcher.Params(userWalletId = userWalletId, network = ethereum.network)
|
||||
val factoryException = IllegalStateException()
|
||||
val multiParams = MultiNetworkStatusFetcher.Params(userWalletId, setOf(params.network))
|
||||
val multiFetcherResult = IllegalStateException("Error").left()
|
||||
|
||||
coEvery { networksStatusesStore.setSourceAsCache(params.userWalletId, params.network) } returns Unit
|
||||
coEvery { cardCryptoCurrencyFactory.create(params.userWalletId, params.network) } throws factoryException
|
||||
coEvery { multiNetworkStatusFetcher(params = multiParams) } returns multiFetcherResult
|
||||
|
||||
// Act
|
||||
val actual = fetcher(params)
|
||||
|
||||
// Arrange
|
||||
val expected = Either.Left(factoryException)
|
||||
Truth.assertThat(actual).isEqualTo(expected)
|
||||
val expected = multiFetcherResult
|
||||
assertEither(actual, expected)
|
||||
|
||||
coVerifyOrder {
|
||||
networksStatusesStore.setSourceAsCache(userWalletId = params.userWalletId, network = params.network)
|
||||
cardCryptoCurrencyFactory.create(userWalletId = params.userWalletId, network = params.network)
|
||||
}
|
||||
|
||||
coVerify(inverse = true) {
|
||||
commonNetworkStatusFetcher.fetch(userWalletId = any(), network = any(), networkCurrencies = any())
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `fetch failure if commonNetworkStatusFetcher returns exception`() = runTest {
|
||||
// Arrange
|
||||
val params = SingleNetworkStatusFetcher.Params(userWalletId = userWalletId, network = ethereum.network)
|
||||
val networkCurrencies = listOf(ethereum)
|
||||
val commonFetcherResult = IllegalStateException().left()
|
||||
|
||||
coEvery { networksStatusesStore.setSourceAsCache(params.userWalletId, params.network) } returns Unit
|
||||
coEvery { cardCryptoCurrencyFactory.create(params.userWalletId, params.network) } returns networkCurrencies
|
||||
coEvery {
|
||||
commonNetworkStatusFetcher.fetch(
|
||||
userWalletId = params.userWalletId,
|
||||
network = params.network,
|
||||
networkCurrencies = networkCurrencies.toSet(),
|
||||
)
|
||||
} returns commonFetcherResult
|
||||
|
||||
// Act
|
||||
val actual = fetcher(params)
|
||||
|
||||
// Arrange
|
||||
val expected = commonFetcherResult
|
||||
|
||||
Truth.assertThat(actual).isEqualTo(expected)
|
||||
|
||||
coVerifyOrder {
|
||||
networksStatusesStore.setSourceAsCache(userWalletId = params.userWalletId, network = params.network)
|
||||
cardCryptoCurrencyFactory.create(userWalletId = params.userWalletId, network = params.network)
|
||||
commonNetworkStatusFetcher.fetch(
|
||||
userWalletId = params.userWalletId,
|
||||
network = params.network,
|
||||
networkCurrencies = setOf(ethereum),
|
||||
)
|
||||
}
|
||||
coVerify(exactly = 1) { multiNetworkStatusFetcher(params = multiParams) }
|
||||
}
|
||||
|
||||
private companion object {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue