From 0adc8ffb4938cfc95279b3123d84a642d8a8566d Mon Sep 17 00:00:00 2001 From: Tangem Date: Mon, 26 May 2025 17:42:58 +0400 Subject: [PATCH] Updated on 2026-08-14 --- .../MockUpdateWalletManagerResultFactory.kt | 2 +- domain/legacy/build.gradle.kts | 9 +- .../utils/UpdateWalletManagerResultFactory.kt | 95 ++- .../UpdateWalletManagerResultFactoryTest.kt | 786 ++++++++++++++++++ 4 files changed, 854 insertions(+), 38 deletions(-) create mode 100644 domain/legacy/src/test/java/com/tangem/domain/walletmanager/utils/UpdateWalletManagerResultFactoryTest.kt diff --git a/common/test/src/main/java/com/tangem/common/test/domain/walletmanager/MockUpdateWalletManagerResultFactory.kt b/common/test/src/main/java/com/tangem/common/test/domain/walletmanager/MockUpdateWalletManagerResultFactory.kt index 3d08fc3d6a..482cb7c1f6 100644 --- a/common/test/src/main/java/com/tangem/common/test/domain/walletmanager/MockUpdateWalletManagerResultFactory.kt +++ b/common/test/src/main/java/com/tangem/common/test/domain/walletmanager/MockUpdateWalletManagerResultFactory.kt @@ -30,7 +30,7 @@ class MockUpdateWalletManagerResultFactory { ) } - fun createVerified(): UpdateWalletManagerResult { + fun createVerified(): Verified { return Verified( selectedAddress = "0x1", addresses = setOf(Address(value = "0x1", type = Address.Type.Primary)), diff --git a/domain/legacy/build.gradle.kts b/domain/legacy/build.gradle.kts index fc7fa7889b..e109af45b0 100644 --- a/domain/legacy/build.gradle.kts +++ b/domain/legacy/build.gradle.kts @@ -9,6 +9,10 @@ android { namespace = "com.tangem.domain.features" } +tasks.withType().configureEach { + useJUnitPlatform() +} + dependencies { implementation(projects.core.datasource) implementation(projects.core.utils) @@ -43,8 +47,11 @@ dependencies { ksp(deps.moshi.kotlin.codegen) /** Testing libraries */ - testImplementation(deps.test.junit) + testImplementation(deps.test.junit5) + testRuntimeOnly(deps.test.junit5.engine) + testImplementation(deps.test.mockk) testImplementation(deps.test.truth) + testImplementation(projects.common.test) androidTestImplementation(deps.test.junit.android) androidTestImplementation(deps.test.espresso) } \ No newline at end of file diff --git a/domain/legacy/src/main/java/com/tangem/domain/walletmanager/utils/UpdateWalletManagerResultFactory.kt b/domain/legacy/src/main/java/com/tangem/domain/walletmanager/utils/UpdateWalletManagerResultFactory.kt index 95c6edd158..4a129303ad 100644 --- a/domain/legacy/src/main/java/com/tangem/domain/walletmanager/utils/UpdateWalletManagerResultFactory.kt +++ b/domain/legacy/src/main/java/com/tangem/domain/walletmanager/utils/UpdateWalletManagerResultFactory.kt @@ -9,8 +9,10 @@ import timber.log.Timber import java.math.BigDecimal import com.tangem.blockchain.common.address.Address as SdkAddress +/** Factory for creating [UpdateWalletManagerResult] */ internal class UpdateWalletManagerResultFactory { + /** Get [Verified] result for [walletManager] */ fun getResult(walletManager: WalletManager): Verified { val wallet = walletManager.wallet val addresses = getAvailableAddresses(wallet.addresses) @@ -25,6 +27,12 @@ internal class UpdateWalletManagerResultFactory { ) } + /** + * Get demo [Verified] result + * + * @param walletManager wallet manager + * @param demoAmount amount that will be used for demo result + */ fun getDemoResult(walletManager: WalletManager, demoAmount: Amount): Verified { val wallet = walletManager.wallet val addresses = getAvailableAddresses(wallet.addresses) @@ -39,6 +47,14 @@ internal class UpdateWalletManagerResultFactory { ) } + /** + * Get [NoAccount] result. + * If unable to get required amount for creating account, [Unreachable] result will be returned. + * + * @param walletManager wallet manager + * @param customMessage custom error message + * @param amountToCreateAccount amount to create account + */ fun getNoAccountResult( walletManager: WalletManager, customMessage: String, @@ -65,7 +81,8 @@ internal class UpdateWalletManagerResultFactory { } } - fun getUnreachableResult(walletManager: WalletManager): UpdateWalletManagerResult { + /** Get [Unreachable] result for [walletManager] */ + fun getUnreachableResult(walletManager: WalletManager): Unreachable { val wallet = walletManager.wallet return Unreachable( @@ -74,10 +91,46 @@ internal class UpdateWalletManagerResultFactory { ) } + private fun getAvailableAddresses(addresses: Set): Set
{ + return SdkAddressToAddressConverter.convertList(addresses).toSet() + } + private fun getTokensAmounts(amounts: Set): Set { return amounts.mapNotNullTo(hashSetOf(), ::createCurrencyAmount) } + private fun createCurrencyAmount(amount: Amount): CryptoCurrencyAmount? { + return when (val type = amount.type) { + is AmountType.Token -> { + val value = getCurrencyAmountValue(amount) ?: return null + + CryptoCurrencyAmount.Token( + currencyRawId = type.token.id?.let(CryptoCurrency::RawID), + contractAddress = type.token.contractAddress, + value = value, + ) + } + is AmountType.Coin -> { + val value = getCurrencyAmountValue(amount) ?: return null + + CryptoCurrencyAmount.Coin(value = value) + } + is AmountType.FeeResource, + is AmountType.Reserve, + -> null + } + } + + private fun getCurrencyAmountValue(amount: Amount): BigDecimal? { + val value = amount.value + + if (value == null) { + Timber.w("Currency amount must not be null: ${amount.currencySymbol}") + } + + return value + } + private fun getDemoTokensAmounts(demoAmount: Amount, tokens: Set): Set { val amountValue = demoAmount.value ?: BigDecimal.ZERO val demoAmounts = hashSetOf(CryptoCurrencyAmount.Coin(amountValue)) @@ -95,9 +148,7 @@ internal class UpdateWalletManagerResultFactory { txHistoryItemConverter: TransactionDataToTxHistoryItemConverter, recentTransactions: Set, ): Set { - val unconfirmedTransactions = recentTransactions.filter { - it.status == TransactionStatus.Unconfirmed - } + val unconfirmedTransactions = recentTransactions.filter { it.status == TransactionStatus.Unconfirmed } return unconfirmedTransactions.mapNotNullTo(hashSetOf()) { createCurrencyTransaction( @@ -107,22 +158,6 @@ internal class UpdateWalletManagerResultFactory { } } - private fun createCurrencyAmount(amount: Amount): CryptoCurrencyAmount? { - return when (val type = amount.type) { - is AmountType.Token -> CryptoCurrencyAmount.Token( - currencyRawId = type.token.id?.let(CryptoCurrency::RawID), - contractAddress = type.token.contractAddress, - value = getCurrencyAmountValue(amount) ?: return null, - ) - is AmountType.Coin -> CryptoCurrencyAmount.Coin( - value = getCurrencyAmountValue(amount) ?: return null, - ) - is AmountType.FeeResource, - AmountType.Reserve, - -> null - } - } - private fun createCurrencyTransaction( txHistoryItemConverter: TransactionDataToTxHistoryItemConverter, data: TransactionData.Uncompiled, @@ -130,10 +165,12 @@ internal class UpdateWalletManagerResultFactory { return when (val type = data.amount.type) { is AmountType.Coin -> { val txHistoryItem = txHistoryItemConverter.convert(data) ?: return null - CryptoCurrencyTransaction.Coin(txHistoryItem) + + CryptoCurrencyTransaction.Coin(txInfo = txHistoryItem) } is AmountType.Token -> { val txHistoryItem = txHistoryItemConverter.convert(data) ?: return null + CryptoCurrencyTransaction.Token( tokenId = type.token.id, contractAddress = type.token.contractAddress, @@ -141,22 +178,8 @@ internal class UpdateWalletManagerResultFactory { ) } is AmountType.FeeResource, - AmountType.Reserve, + is AmountType.Reserve, -> null } } - - private fun getAvailableAddresses(addresses: Set): Set
{ - return SdkAddressToAddressConverter.convertList(addresses).toSet() - } - - private fun getCurrencyAmountValue(amount: Amount): BigDecimal? { - val value = amount.value - - if (value == null) { - Timber.w("Currency amount must not be null: ${amount.currencySymbol}") - } - - return value - } } \ No newline at end of file diff --git a/domain/legacy/src/test/java/com/tangem/domain/walletmanager/utils/UpdateWalletManagerResultFactoryTest.kt b/domain/legacy/src/test/java/com/tangem/domain/walletmanager/utils/UpdateWalletManagerResultFactoryTest.kt new file mode 100644 index 0000000000..5b6b9271d5 --- /dev/null +++ b/domain/legacy/src/test/java/com/tangem/domain/walletmanager/utils/UpdateWalletManagerResultFactoryTest.kt @@ -0,0 +1,786 @@ +package com.tangem.domain.walletmanager.utils + +import com.google.common.truth.Truth +import com.tangem.blockchain.common.* +import com.tangem.blockchain.common.address.Address +import com.tangem.blockchain.common.address.AddressType +import com.tangem.blockchainsdk.models.UpdateWalletManagerResult +import com.tangem.blockchainsdk.models.UpdateWalletManagerResult.* +import com.tangem.blockchainsdk.models.UpdateWalletManagerResult.Address.Type +import com.tangem.common.test.domain.walletmanager.MockUpdateWalletManagerResultFactory +import com.tangem.common.test.utils.ProvideTestModels +import com.tangem.domain.models.currency.CryptoCurrency +import com.tangem.domain.models.network.TxInfo +import io.mockk.clearMocks +import io.mockk.every +import io.mockk.mockk +import org.junit.jupiter.api.BeforeEach +import org.junit.jupiter.api.Nested +import org.junit.jupiter.api.TestInstance +import org.junit.jupiter.params.ParameterizedTest +import java.math.BigDecimal +import java.util.Calendar + +/** +[REDACTED_AUTHOR] + */ +@TestInstance(TestInstance.Lifecycle.PER_CLASS) +internal class UpdateWalletManagerResultFactoryTest { + + private val factory = UpdateWalletManagerResultFactory() + private val mockFactory = MockUpdateWalletManagerResultFactory() + + private val walletManager = mockk() + + @BeforeEach + fun resetMocks() { + clearMocks(walletManager) + } + + @Nested + @TestInstance(TestInstance.Lifecycle.PER_CLASS) + inner class GetResult { + + @ParameterizedTest + @ProvideTestModels + fun getResult(model: GetResultTestModel) { + // Arrange + every { walletManager.wallet } returns model.wallet + + // Act + val actual = factory.getResult(walletManager = walletManager) + + // Assert + Truth.assertThat(actual).isEqualTo(model.expected) + } + + private fun provideTestModels(): List = listOf( + // region Wallet without amount and transactions + GetResultTestModel( + wallet = createWallet( + coinValue = null, + addresses = setOf(Address(value = "0x1", type = AddressType.Default)), + transactions = emptyList(), + ), + expected = Verified( + selectedAddress = "0x1", + addresses = setOf(Address(value = "0x1", type = Type.Primary)), + currenciesAmounts = emptySet(), + currentTransactions = emptySet(), + ), + ), + // endregion + + // region Wallet with coin amount and without transactions + GetResultTestModel( + wallet = createWallet( + coinValue = BigDecimal.ONE, + addresses = setOf( + Address(value = "0x1", type = AddressType.Default), + ), + transactions = emptyList(), + ), + expected = Verified( + selectedAddress = "0x1", + addresses = setOf(Address(value = "0x1", type = Type.Primary)), + currenciesAmounts = setOf(CryptoCurrencyAmount.Coin(value = BigDecimal.ONE)), + currentTransactions = emptySet(), + ), + ), + // endregion + + // region Wallet with coin amount and coin transaction + GetResultTestModel( + wallet = createWallet( + coinValue = BigDecimal.ONE, + addresses = setOf( + Address(value = "0x1", type = AddressType.Default), + ), + transactions = listOf( + createRecentTransaction( + amount = Amount( + blockchain = Blockchain.Ethereum, + value = BigDecimal.ONE, + ), + status = TransactionStatus.Unconfirmed, + ), + ), + ), + expected = Verified( + selectedAddress = "0x1", + addresses = setOf(Address(value = "0x1", type = Type.Primary)), + currenciesAmounts = setOf(CryptoCurrencyAmount.Coin(value = BigDecimal.ONE)), + currentTransactions = setOf( + CryptoCurrencyTransaction.Coin( + txInfo = createTxInfo( + status = TxInfo.TransactionStatus.Unconfirmed, + amount = BigDecimal.ONE, + ), + ), + ), + ), + ), + // endregion + + // region Wallet with amounts and transactions (coin and token) + GetResultTestModel( + wallet = createWallet( + coinValue = BigDecimal.ONE, + tokensAmount = mapOf(usdtToken to BigDecimal.ZERO), + addresses = setOf( + Address(value = "0x1", type = AddressType.Default), + Address(value = "0x11", type = AddressType.Legacy), + ), + transactions = listOf( + createRecentTransaction( + amount = Amount( + blockchain = Blockchain.Ethereum, + value = BigDecimal.ONE, + ), + status = TransactionStatus.Confirmed, + ), + createRecentTransaction( + amount = Amount( + value = BigDecimal.TEN, + blockchain = Blockchain.Ethereum, + type = AmountType.Token(token = usdtToken), + currencySymbol = "USDT", + ), + status = TransactionStatus.Unconfirmed, + ), + ), + ), + expected = Verified( + selectedAddress = "0x1", + addresses = setOf( + Address(value = "0x1", type = Type.Primary), + Address(value = "0x11", type = Type.Secondary), + ), + currenciesAmounts = setOf( + CryptoCurrencyAmount.Coin(value = BigDecimal.ONE), + CryptoCurrencyAmount.Token( + value = BigDecimal.ZERO, + currencyRawId = usdtToken.id?.let(CryptoCurrency::RawID), + contractAddress = usdtToken.contractAddress, + ), + ), + currentTransactions = setOf( + CryptoCurrencyTransaction.Token( + txInfo = createTxInfo( + status = TxInfo.TransactionStatus.Unconfirmed, + amount = BigDecimal.TEN, + ), + tokenId = "0x3", + contractAddress = "0x4", + ), + ), + ), + ), + // endregion + ) + } + + data class GetResultTestModel(val wallet: Wallet, val expected: Verified) + + @Nested + @TestInstance(TestInstance.Lifecycle.PER_CLASS) + inner class GetDemoResult { + + @ParameterizedTest + @ProvideTestModels + fun getDemoResult(model: GetDemoResultTestModel) { + // Arrange + every { walletManager.wallet } returns model.wallet + every { walletManager.cardTokens } returns model.cardTokens.toMutableSet() + + // Act + val actual = factory.getDemoResult(walletManager = walletManager, demoAmount = model.demoAmount) + + // Assert + Truth.assertThat(actual).isEqualTo(model.expected) + } + + private fun provideTestModels(): List { + return listOf( + // region Wallet without amount and transactions + GetDemoResultTestModel( + wallet = createWallet( + coinValue = null, + addresses = setOf(Address(value = "0x1", type = AddressType.Default)), + transactions = emptyList(), + ), + demoAmount = Amount(value = null, blockchain = Blockchain.Ethereum), + cardTokens = emptySet(), + expected = Verified( + selectedAddress = "0x1", + addresses = setOf( + Address(value = "0x1", type = Type.Primary), + ), + currenciesAmounts = setOf( + CryptoCurrencyAmount.Coin(value = BigDecimal.ZERO), // default for demo + ), + currentTransactions = emptySet(), + ), + ), + GetDemoResultTestModel( + wallet = createWallet( + coinValue = null, + addresses = setOf(Address(value = "0x1", type = AddressType.Default)), + transactions = emptyList(), + ), + demoAmount = Amount(value = BigDecimal.ONE, blockchain = Blockchain.Ethereum), + cardTokens = emptySet(), + expected = Verified( + selectedAddress = "0x1", + addresses = setOf( + Address(value = "0x1", type = Type.Primary), + ), + currenciesAmounts = setOf( + CryptoCurrencyAmount.Coin(value = BigDecimal.ONE), // used demo amount + ), + currentTransactions = emptySet(), + ), + ), + // endregion + + // region Wallet with coin amount and without transactions + GetDemoResultTestModel( + wallet = createWallet( + coinValue = BigDecimal.ONE, + addresses = setOf( + Address(value = "0x1", type = AddressType.Default), + ), + transactions = emptyList(), + ), + demoAmount = Amount(value = null, blockchain = Blockchain.Ethereum), + cardTokens = emptySet(), + expected = Verified( + selectedAddress = "0x1", + addresses = setOf( + Address( + value = "0x1", + type = Type.Primary, + ), + ), + currenciesAmounts = setOf(CryptoCurrencyAmount.Coin(value = BigDecimal.ZERO)), + currentTransactions = emptySet(), + ), + ), + GetDemoResultTestModel( + wallet = createWallet( + coinValue = BigDecimal.ONE, + addresses = setOf( + Address(value = "0x1", type = AddressType.Default), + ), + transactions = emptyList(), + ), + demoAmount = Amount(value = BigDecimal.TEN, blockchain = Blockchain.Ethereum), + cardTokens = emptySet(), + expected = Verified( + selectedAddress = "0x1", + addresses = setOf( + Address( + value = "0x1", + type = Type.Primary, + ), + ), + currenciesAmounts = setOf(CryptoCurrencyAmount.Coin(value = BigDecimal.TEN)), + currentTransactions = emptySet(), + ), + ), + // endregion + + // region Wallet with coin amount and coin transaction + GetDemoResultTestModel( + wallet = createWallet( + coinValue = BigDecimal.ONE, + addresses = setOf( + Address(value = "0x1", type = AddressType.Default), + ), + transactions = listOf( + createRecentTransaction( + amount = Amount( + blockchain = Blockchain.Ethereum, + value = BigDecimal.ONE, + ), + status = TransactionStatus.Unconfirmed, + ), + ), + ), + demoAmount = Amount(value = BigDecimal.TEN, blockchain = Blockchain.Ethereum), + cardTokens = emptySet(), + expected = Verified( + selectedAddress = "0x1", + addresses = setOf( + Address(value = "0x1", type = Type.Primary), + ), + currenciesAmounts = setOf(CryptoCurrencyAmount.Coin(value = BigDecimal.TEN)), + currentTransactions = setOf( + CryptoCurrencyTransaction.Coin( + txInfo = createTxInfo( + status = TxInfo.TransactionStatus.Unconfirmed, + amount = BigDecimal.ONE, + ), + ), + ), + ), + ), + // endregion + + // region Wallet with amounts and transactions (coin and token) + GetDemoResultTestModel( + wallet = createWallet( + coinValue = BigDecimal.TEN, + tokensAmount = mapOf(usdtToken to BigDecimal.TEN), + addresses = setOf( + Address(value = "0x1", type = AddressType.Default), + Address(value = "0x11", type = AddressType.Legacy), + ), + transactions = listOf( + createRecentTransaction( + amount = Amount( + blockchain = Blockchain.Ethereum, + value = BigDecimal.ONE, + ), + status = TransactionStatus.Confirmed, + ), + createRecentTransaction( + amount = Amount( + value = BigDecimal.TEN, + blockchain = Blockchain.Ethereum, + type = AmountType.Token(token = usdtToken), + currencySymbol = "USDT", + ), + status = TransactionStatus.Unconfirmed, + ), + ), + ), + demoAmount = Amount(value = null, blockchain = Blockchain.Ethereum), + cardTokens = setOf(usdtToken), + expected = Verified( + selectedAddress = "0x1", + addresses = setOf( + Address(value = "0x1", type = Type.Primary), + Address(value = "0x11", type = Type.Secondary), + ), + currenciesAmounts = setOf( + CryptoCurrencyAmount.Coin(value = BigDecimal.ZERO), + CryptoCurrencyAmount.Token( + value = BigDecimal.ZERO, + currencyRawId = usdtToken.id?.let(CryptoCurrency::RawID), + contractAddress = usdtToken.contractAddress, + ), + ), + currentTransactions = setOf( + CryptoCurrencyTransaction.Token( + txInfo = createTxInfo( + status = TxInfo.TransactionStatus.Unconfirmed, + amount = BigDecimal.TEN, + ), + tokenId = "0x3", + contractAddress = "0x4", + ), + ), + ), + ), + GetDemoResultTestModel( + wallet = createWallet( + coinValue = BigDecimal.ONE, + tokensAmount = mapOf(usdtToken to BigDecimal.ZERO), + addresses = setOf( + Address(value = "0x1", type = AddressType.Default), + Address(value = "0x11", type = AddressType.Legacy), + ), + transactions = listOf( + createRecentTransaction( + amount = Amount( + blockchain = Blockchain.Ethereum, + value = BigDecimal.ONE, + ), + status = TransactionStatus.Unconfirmed, + ), + createRecentTransaction( + amount = Amount( + value = BigDecimal.TEN, + blockchain = Blockchain.Ethereum, + type = AmountType.Token(token = usdtToken), + currencySymbol = "USDT", + ), + status = TransactionStatus.Unconfirmed, + ), + ), + ), + demoAmount = Amount(value = BigDecimal.TEN, blockchain = Blockchain.Ethereum), + cardTokens = setOf(usdtToken), + expected = Verified( + selectedAddress = "0x1", + addresses = setOf( + Address(value = "0x1", type = Type.Primary), + Address(value = "0x11", type = Type.Secondary), + ), + currenciesAmounts = setOf( + CryptoCurrencyAmount.Coin(value = BigDecimal.TEN), + CryptoCurrencyAmount.Token( + value = BigDecimal.TEN, + currencyRawId = usdtToken.id?.let(CryptoCurrency::RawID), + contractAddress = usdtToken.contractAddress, + ), + ), + currentTransactions = setOf( + CryptoCurrencyTransaction.Token( + txInfo = createTxInfo( + status = TxInfo.TransactionStatus.Unconfirmed, + amount = BigDecimal.TEN, + ), + tokenId = "0x3", + contractAddress = "0x4", + ), + CryptoCurrencyTransaction.Coin( + txInfo = createTxInfo( + status = TxInfo.TransactionStatus.Unconfirmed, + amount = BigDecimal.ONE, + ), + ), + ), + ), + ), + // endregion + ) + } + } + + data class GetDemoResultTestModel( + val wallet: Wallet, + val demoAmount: Amount, + val cardTokens: Set, + val expected: Verified, + ) + + @Nested + @TestInstance(TestInstance.Lifecycle.PER_CLASS) + inner class GetNoAccountResult { + + @ParameterizedTest + @ProvideTestModels + fun getNoAccountResult(model: GetNoAccountResultModel) { + // Arrange + every { walletManager.wallet } returns model.wallet + + // Act + val actual = factory.getNoAccountResult( + walletManager = walletManager, + customMessage = model.customMessage, + amountToCreateAccount = model.amountToCreateAccount, + ) + + // Assert + Truth.assertThat(actual).isEqualTo(model.expected) + } + + private fun provideTestModels() = listOf( + // region amountToCreateAccount is null + GetNoAccountResultModel( + wallet = createWallet( + coinValue = null, + addresses = setOf(Address(value = "0x1", type = AddressType.Default)), + transactions = emptyList(), + ), + customMessage = "", + amountToCreateAccount = null, + expected = Unreachable( + selectedAddress = "0x1", + addresses = setOf(Address(value = "0x1", type = Type.Primary)), + ), + ), + // endregion + + // region Wallet without amount and transactions + GetNoAccountResultModel( + wallet = createWallet( + coinValue = null, + addresses = setOf(Address(value = "0x1", type = AddressType.Default)), + transactions = emptyList(), + ), + customMessage = "", + amountToCreateAccount = BigDecimal.ONE, + expected = mockFactory.createNoAccount(), + ), + // endregion + + // region Wallet with coin amount and without transactions + GetNoAccountResultModel( + wallet = createWallet( + coinValue = BigDecimal.ONE, + addresses = setOf( + Address(value = "0x1", type = AddressType.Default), + ), + transactions = emptyList(), + ), + customMessage = "custom message", + amountToCreateAccount = BigDecimal.ONE, + expected = NoAccount( + selectedAddress = "0x1", + addresses = setOf(Address(value = "0x1", type = Type.Primary)), + amountToCreateAccount = BigDecimal.ONE, + errorMessage = "custom message", + ), + ), + // endregion + + // region Wallet with coin amount and coin transaction + GetNoAccountResultModel( + wallet = createWallet( + coinValue = BigDecimal.ONE, + addresses = setOf( + Address(value = "0x1", type = AddressType.Default), + ), + transactions = listOf( + createRecentTransaction( + amount = Amount( + blockchain = Blockchain.Ethereum, + value = BigDecimal.ONE, + ), + status = TransactionStatus.Unconfirmed, + ), + ), + ), + customMessage = "", + amountToCreateAccount = BigDecimal.ZERO, + expected = NoAccount( + selectedAddress = "0x1", + addresses = setOf(Address(value = "0x1", type = Type.Primary)), + amountToCreateAccount = BigDecimal.ZERO, + errorMessage = "", + ), + ), + // endregion + + // region Wallet with amounts and transactions (coin and token) + GetNoAccountResultModel( + wallet = createWallet( + coinValue = BigDecimal.ONE, + tokensAmount = mapOf(usdtToken to BigDecimal.ZERO), + addresses = setOf( + Address(value = "0x1", type = AddressType.Default), + Address(value = "0x11", type = AddressType.Legacy), + ), + transactions = listOf( + createRecentTransaction( + amount = Amount( + blockchain = Blockchain.Ethereum, + value = BigDecimal.ONE, + ), + status = TransactionStatus.Unconfirmed, + ), + createRecentTransaction( + amount = Amount( + value = BigDecimal.TEN, + blockchain = Blockchain.Ethereum, + type = AmountType.Token(token = usdtToken), + currencySymbol = "USDT", + ), + status = TransactionStatus.Unconfirmed, + ), + ), + ), + customMessage = "", + amountToCreateAccount = BigDecimal.ZERO, + expected = NoAccount( + selectedAddress = "0x1", + addresses = setOf( + Address(value = "0x1", type = Type.Primary), + Address(value = "0x11", type = Type.Secondary), + ), + amountToCreateAccount = BigDecimal.ZERO, + errorMessage = "", + ), + ), + // endregion + ) + } + + data class GetNoAccountResultModel( + val wallet: Wallet, + val customMessage: String, + val amountToCreateAccount: BigDecimal?, + val expected: UpdateWalletManagerResult, + ) + + @Nested + @TestInstance(TestInstance.Lifecycle.PER_CLASS) + inner class GetUnreachableResult { + + @ParameterizedTest + @ProvideTestModels + fun getUnreachableResult(model: GetUnreachableResultModel) { + // Arrange + every { walletManager.wallet } returns model.wallet + + // Act + val actual = factory.getUnreachableResult(walletManager = walletManager) + + // Assert + Truth.assertThat(actual).isEqualTo(model.expected) + } + + private fun provideTestModels() = listOf( + // region Wallet without amount and transactions + GetUnreachableResultModel( + wallet = createWallet( + coinValue = null, + addresses = setOf(Address(value = "0x1", type = AddressType.Default)), + transactions = emptyList(), + ), + expected = Unreachable( + selectedAddress = "0x1", + addresses = setOf(Address(value = "0x1", type = Type.Primary)), + ), + ), + // endregion + + // region Wallet with coin amount and without transactions + GetUnreachableResultModel( + wallet = createWallet( + coinValue = BigDecimal.ONE, + addresses = setOf( + Address(value = "0x1", type = AddressType.Default), + ), + transactions = emptyList(), + ), + expected = Unreachable( + selectedAddress = "0x1", + addresses = setOf(Address(value = "0x1", type = Type.Primary)), + ), + ), + // endregion + + // region Wallet with coin amount and coin transaction + GetUnreachableResultModel( + wallet = createWallet( + coinValue = BigDecimal.ONE, + addresses = setOf( + Address(value = "0x1", type = AddressType.Default), + ), + transactions = listOf( + createRecentTransaction( + amount = Amount( + blockchain = Blockchain.Ethereum, + value = BigDecimal.ONE, + ), + status = TransactionStatus.Unconfirmed, + ), + ), + ), + expected = Unreachable( + selectedAddress = "0x1", + addresses = setOf(Address(value = "0x1", type = Type.Primary)), + ), + ), + // endregion + + // region Wallet with amounts and transactions (coin and token) + GetUnreachableResultModel( + wallet = createWallet( + coinValue = BigDecimal.ONE, + tokensAmount = mapOf(usdtToken to BigDecimal.ZERO), + addresses = setOf( + Address(value = "0x1", type = AddressType.Default), + Address(value = "0x11", type = AddressType.Legacy), + ), + transactions = listOf( + createRecentTransaction( + amount = Amount( + blockchain = Blockchain.Ethereum, + value = BigDecimal.ONE, + ), + status = TransactionStatus.Unconfirmed, + ), + createRecentTransaction( + amount = Amount( + value = BigDecimal.TEN, + blockchain = Blockchain.Ethereum, + type = AmountType.Token(token = usdtToken), + currencySymbol = "USDT", + ), + status = TransactionStatus.Unconfirmed, + ), + ), + ), + expected = Unreachable( + selectedAddress = "0x1", + addresses = setOf( + Address(value = "0x1", type = Type.Primary), + Address(value = "0x11", type = Type.Secondary), + ), + ), + ), + // endregion + ) + } + + data class GetUnreachableResultModel( + val wallet: Wallet, + val expected: UpdateWalletManagerResult, + ) + + private fun createWallet( + coinValue: BigDecimal?, + tokensAmount: Map = emptyMap(), + addresses: Set
, + transactions: List, + ): Wallet { + return Wallet( + blockchain = Blockchain.Ethereum, + addresses = addresses, + publicKey = mockk(), + tokens = setOf(), + ).apply { + coinValue?.let(::setCoinValue) + tokensAmount.forEach { (token, amount) -> addTokenValue(value = amount, token = token) } + recentTransactions += transactions + } + } + + private fun createRecentTransaction(amount: Amount, status: TransactionStatus): TransactionData.Uncompiled { + return TransactionData.Uncompiled( + amount = amount, + fee = null, + sourceAddress = "0x1", + destinationAddress = "0x2", + status = status, + hash = "hash", + date = Calendar.getInstance().apply { + timeInMillis = 1748251839317 + }, + extras = null, + contractAddress = null, + ) + } + + private fun createTxInfo(status: TxInfo.TransactionStatus, amount: BigDecimal): TxInfo { + return TxInfo( + txHash = "hash", + timestampInMillis = 1748251839317, + isOutgoing = true, + destinationType = TxInfo.DestinationType.Single( + addressType = TxInfo.AddressType.User(address = "0x2"), + ), + sourceType = TxInfo.SourceType.Single(address = "0x1"), + interactionAddressType = TxInfo.InteractionAddressType.User(address = "0x2"), + status = status, + type = TxInfo.TransactionType.Transfer, + amount = amount, + ) + } + + private companion object { + + val usdtToken = Token( + id = "0x3", + contractAddress = "0x4", + symbol = "USDT", + decimals = 6, + name = "Tether", + ) + } +} \ No newline at end of file