Updated on 2026-08-14
This commit is contained in:
commit
531eb86ac5
1243 changed files with 49302 additions and 12422 deletions
|
|
@ -28,7 +28,6 @@
|
|||
<ID>MultilineLambdaItParameter:UpdateWalletUseCase.kt$UpdateWalletUseCase${ when (it) { is SaveWalletError.DataError -> DataError( IllegalStateException("Failed to update wallet: ${it.messageId}"), ) is SaveWalletError.WalletAlreadySaved -> UpdateWalletError.NameAlreadyExists } }</ID>
|
||||
<ID>NestedScopeFunctions:ColdUserWalletBuilder.kt$ColdUserWalletBuilder$let { UserWallet.Cold( walletId = it, name = generateWalletNameUseCase( card = card, productType = productType, isStartToCoin = cardTypesResolver.isStart2Coin(), ), cardsInWallet = backupCardsIds.plus(card.cardId), scanResponse = this, isMultiCurrency = cardTypesResolver.isMultiwalletAllowed(), hasBackupError = hasBackupError, ) }</ID>
|
||||
<ID>NoNameShadowing:SaveWalletUseCase.kt$SaveWalletUseCase$userWallet</ID>
|
||||
<ID>NullableToStringCall:GenerateBuyTangemCardLinkUseCase.kt$GenerateBuyTangemCardLinkUseCase$$id</ID>
|
||||
<ID>NullableToStringCall:UpdateWalletUseCase.kt$UpdateWalletUseCase$${it.messageId}</ID>
|
||||
<ID>ObjectExtendsThrowable:UserWalletsListError.kt$UserWalletsListError$AllKeysInvalidated : UserWalletsListError</ID>
|
||||
<ID>ObjectExtendsThrowable:UserWalletsListError.kt$UserWalletsListError$BiometricsAuthenticationDisabled : UserWalletsListError</ID>
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ package com.tangem.domain.wallets.models
|
|||
|
||||
import com.tangem.domain.models.wallet.UserWalletId
|
||||
|
||||
class UserWalletRemoteInfo(
|
||||
data class UserWalletRemoteInfo(
|
||||
val walletId: UserWalletId,
|
||||
val name: String,
|
||||
val isNotificationsEnabled: Boolean,
|
||||
|
|
|
|||
|
|
@ -36,7 +36,7 @@ val UserWallet.isAccountsSupported
|
|||
is UserWallet.Hot -> true
|
||||
is UserWallet.Cold -> {
|
||||
with(this.cardTypesResolver) {
|
||||
isMultiwalletAllowed() && !isWhiteWallet()
|
||||
isMultiwalletAllowed() && scanResponse.card.settings.isHDWalletAllowed
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -75,5 +75,9 @@ interface WalletsRepository {
|
|||
@Throws
|
||||
suspend fun associateWallets(applicationId: String, wallets: List<UserWallet>)
|
||||
|
||||
suspend fun activatePromoCode(promoCode: String, bitcoinAddress: String): Either<ActivatePromoCodeError, String>
|
||||
suspend fun activatePromoCode(
|
||||
userWalletId: UserWalletId,
|
||||
promoCode: String,
|
||||
bitcoinAddress: String,
|
||||
): Either<ActivatePromoCodeError, String>
|
||||
}
|
||||
|
|
@ -1,6 +1,7 @@
|
|||
package com.tangem.domain.wallets.usecase
|
||||
|
||||
import arrow.core.Either
|
||||
import com.tangem.domain.models.wallet.UserWalletId
|
||||
import com.tangem.domain.wallets.models.errors.ActivatePromoCodeError
|
||||
import com.tangem.domain.wallets.repository.WalletsRepository
|
||||
import javax.inject.Inject
|
||||
|
|
@ -9,6 +10,13 @@ class ActivateBitcoinPromocodeUseCase @Inject constructor(
|
|||
private val walletsRepository: WalletsRepository,
|
||||
) {
|
||||
|
||||
suspend operator fun invoke(address: String, promoCode: String): Either<ActivatePromoCodeError, String> =
|
||||
walletsRepository.activatePromoCode(promoCode = promoCode, bitcoinAddress = address)
|
||||
suspend operator fun invoke(
|
||||
userWalletId: UserWalletId,
|
||||
address: String,
|
||||
promoCode: String,
|
||||
): Either<ActivatePromoCodeError, String> = walletsRepository.activatePromoCode(
|
||||
userWalletId = userWalletId,
|
||||
promoCode = promoCode,
|
||||
bitcoinAddress = address,
|
||||
)
|
||||
}
|
||||
|
|
@ -1,6 +1,10 @@
|
|||
package com.tangem.domain.wallets.usecase
|
||||
|
||||
import arrow.core.Either
|
||||
import com.tangem.domain.card.common.util.cardTypesResolver
|
||||
import com.tangem.domain.common.wallets.UserWalletsListRepository
|
||||
import com.tangem.domain.models.wallet.UserWallet
|
||||
import com.tangem.domain.models.wallet.UserWalletId
|
||||
import com.tangem.domain.notifications.models.ApplicationId
|
||||
import com.tangem.domain.wallets.delegate.UserWalletsSyncDelegate
|
||||
import com.tangem.domain.wallets.repository.WalletsRepository
|
||||
|
|
@ -8,10 +12,34 @@ import com.tangem.domain.wallets.repository.WalletsRepository
|
|||
class UpdateRemoteWalletsInfoUseCase(
|
||||
private val walletsRepository: WalletsRepository,
|
||||
private val userWalletsSyncDelegate: UserWalletsSyncDelegate,
|
||||
private val userWalletsListRepository: UserWalletsListRepository,
|
||||
private val generateWalletNameUseCase: GenerateWalletNameUseCase,
|
||||
) {
|
||||
|
||||
suspend operator fun invoke(applicationId: ApplicationId): Either<Throwable, Unit> = Either.catch {
|
||||
val walletsInfo = walletsRepository.getWalletsInfo(applicationId.value)
|
||||
val userWalletsMap = userWalletsListRepository.userWallets.value?.associateBy { it.walletId }.orEmpty()
|
||||
val remoteData = walletsRepository.getWalletsInfo(applicationId.value)
|
||||
|
||||
val walletsInfo = remoteData.map { walletRemoteInfo ->
|
||||
if (walletRemoteInfo.name.isBlank()) {
|
||||
walletRemoteInfo.copy(name = generateName(walletRemoteInfo.walletId, userWalletsMap))
|
||||
} else {
|
||||
walletRemoteInfo
|
||||
}
|
||||
}.filter { it.name.isNotBlank() }
|
||||
|
||||
userWalletsSyncDelegate.syncWallets(walletsInfo)
|
||||
}
|
||||
|
||||
private fun generateName(userWalletId: UserWalletId, userWalletsMap: Map<UserWalletId, UserWallet>): String {
|
||||
val userWallet = userWalletsMap[userWalletId] ?: return ""
|
||||
return when (userWallet) {
|
||||
is UserWallet.Hot -> generateWalletNameUseCase.invokeForHot()
|
||||
is UserWallet.Cold -> generateWalletNameUseCase(
|
||||
userWallet.scanResponse.productType,
|
||||
card = userWallet.scanResponse.card,
|
||||
isStartToCoin = userWallet.scanResponse.cardTypesResolver.isStart2Coin(),
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,245 @@
|
|||
package com.tangem.domain.wallets.usecase
|
||||
|
||||
import arrow.core.right
|
||||
import com.google.common.truth.Truth.assertThat
|
||||
import com.tangem.domain.common.wallets.UserWalletsListRepository
|
||||
import com.tangem.domain.models.scan.ProductType
|
||||
import com.tangem.domain.models.scan.ScanResponse
|
||||
import com.tangem.domain.models.wallet.UserWallet
|
||||
import com.tangem.domain.models.wallet.UserWalletId
|
||||
import com.tangem.domain.notifications.models.ApplicationId
|
||||
import com.tangem.domain.wallets.delegate.UserWalletsSyncDelegate
|
||||
import com.tangem.domain.wallets.models.UserWalletRemoteInfo
|
||||
import com.tangem.domain.wallets.repository.WalletsRepository
|
||||
import io.mockk.coEvery
|
||||
import io.mockk.coVerify
|
||||
import io.mockk.every
|
||||
import io.mockk.mockk
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.test.runTest
|
||||
import org.junit.Before
|
||||
import org.junit.Test
|
||||
|
||||
class UpdateRemoteWalletsInfoUseCaseTest {
|
||||
|
||||
private lateinit var useCase: UpdateRemoteWalletsInfoUseCase
|
||||
private lateinit var walletsRepository: WalletsRepository
|
||||
private lateinit var userWalletsSyncDelegate: UserWalletsSyncDelegate
|
||||
private lateinit var userWalletListRepository: UserWalletsListRepository
|
||||
private lateinit var generateWalletNameUseCase: GenerateWalletNameUseCase
|
||||
|
||||
@Before
|
||||
fun setup() {
|
||||
walletsRepository = mockk()
|
||||
userWalletsSyncDelegate = mockk()
|
||||
userWalletListRepository = mockk {
|
||||
every { userWallets } returns MutableStateFlow<List<UserWallet>?>(emptyList())
|
||||
}
|
||||
generateWalletNameUseCase = mockk()
|
||||
useCase = UpdateRemoteWalletsInfoUseCase(
|
||||
walletsRepository = walletsRepository,
|
||||
userWalletsSyncDelegate = userWalletsSyncDelegate,
|
||||
userWalletsListRepository = userWalletListRepository,
|
||||
generateWalletNameUseCase = generateWalletNameUseCase,
|
||||
)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `GIVEN wallets with non-empty names WHEN invoke THEN return Right with Unit`() = runTest {
|
||||
// GIVEN
|
||||
val applicationId = ApplicationId("test-app-id")
|
||||
val walletsInfo = listOf(
|
||||
UserWalletRemoteInfo(UserWalletId("0A0B0C0D"), "Wallet 1", true),
|
||||
UserWalletRemoteInfo(UserWalletId("0E0F1011"), "Wallet 2", true),
|
||||
)
|
||||
coEvery { walletsRepository.getWalletsInfo(applicationId.value) } returns walletsInfo
|
||||
coEvery { userWalletsSyncDelegate.syncWallets(walletsInfo) } returns Unit.right()
|
||||
|
||||
// WHEN
|
||||
val result = useCase(applicationId)
|
||||
|
||||
// THEN
|
||||
assertThat(result.isRight()).isTrue()
|
||||
coVerify { walletsRepository.getWalletsInfo(applicationId.value) }
|
||||
coVerify { userWalletsSyncDelegate.syncWallets(walletsInfo) }
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `GIVEN wallets with empty names WHEN invoke THEN filter out wallets with empty names`() = runTest {
|
||||
// GIVEN
|
||||
val applicationId = ApplicationId("test-app-id")
|
||||
val walletWithName = UserWalletRemoteInfo(UserWalletId("0A0B0C0D"), "Wallet 1", true)
|
||||
val walletWithEmptyName = UserWalletRemoteInfo(UserWalletId("0E0F1011"), "", true)
|
||||
val walletsInfo = listOf(walletWithName, walletWithEmptyName)
|
||||
val filteredWallets = listOf(walletWithName)
|
||||
coEvery { walletsRepository.getWalletsInfo(applicationId.value) } returns walletsInfo
|
||||
coEvery { userWalletsSyncDelegate.syncWallets(filteredWallets) } returns Unit.right()
|
||||
|
||||
// WHEN
|
||||
val result = useCase(applicationId)
|
||||
|
||||
// THEN
|
||||
assertThat(result.isRight()).isTrue()
|
||||
coVerify { userWalletsSyncDelegate.syncWallets(filteredWallets) }
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `GIVEN empty wallets list WHEN invoke THEN sync with empty list`() = runTest {
|
||||
// GIVEN
|
||||
val applicationId = ApplicationId("test-app-id")
|
||||
val walletsInfo = emptyList<UserWalletRemoteInfo>()
|
||||
coEvery { walletsRepository.getWalletsInfo(applicationId.value) } returns walletsInfo
|
||||
coEvery { userWalletsSyncDelegate.syncWallets(walletsInfo) } returns Unit.right()
|
||||
|
||||
// WHEN
|
||||
val result = useCase(applicationId)
|
||||
|
||||
// THEN
|
||||
assertThat(result.isRight()).isTrue()
|
||||
coVerify { userWalletsSyncDelegate.syncWallets(emptyList()) }
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `GIVEN repository throws exception WHEN invoke THEN return Left with Throwable`() = runTest {
|
||||
// GIVEN
|
||||
val applicationId = ApplicationId("test-app-id")
|
||||
val exception = RuntimeException("Network error")
|
||||
coEvery { walletsRepository.getWalletsInfo(applicationId.value) } throws exception
|
||||
|
||||
// WHEN
|
||||
val result = useCase(applicationId)
|
||||
|
||||
// THEN
|
||||
assertThat(result.isLeft()).isTrue()
|
||||
result.onLeft { throwable ->
|
||||
assertThat(throwable).isEqualTo(exception)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `GIVEN syncWallets throws exception WHEN invoke THEN return Left with Throwable`() = runTest {
|
||||
// GIVEN
|
||||
val applicationId = ApplicationId("test-app-id")
|
||||
val walletsInfo = listOf(
|
||||
UserWalletRemoteInfo(UserWalletId("0A0B0C0D"), "Wallet 1", true),
|
||||
)
|
||||
val exception = RuntimeException("Sync error")
|
||||
coEvery { walletsRepository.getWalletsInfo(applicationId.value) } returns walletsInfo
|
||||
coEvery { userWalletsSyncDelegate.syncWallets(walletsInfo) } throws exception
|
||||
|
||||
// WHEN
|
||||
val result = useCase(applicationId)
|
||||
|
||||
// THEN
|
||||
assertThat(result.isLeft()).isTrue()
|
||||
result.onLeft { throwable ->
|
||||
assertThat(throwable).isEqualTo(exception)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `GIVEN all wallets have empty names WHEN invoke THEN sync with empty list`() = runTest {
|
||||
// GIVEN
|
||||
val applicationId = ApplicationId("test-app-id")
|
||||
val walletsInfo = listOf(
|
||||
UserWalletRemoteInfo(UserWalletId("0A0B0C0D"), "", true),
|
||||
UserWalletRemoteInfo(UserWalletId("0E0F1011"), "", true),
|
||||
)
|
||||
coEvery { walletsRepository.getWalletsInfo(applicationId.value) } returns walletsInfo
|
||||
coEvery { userWalletsSyncDelegate.syncWallets(emptyList()) } returns Unit.right()
|
||||
|
||||
// WHEN
|
||||
val result = useCase(applicationId)
|
||||
|
||||
// THEN
|
||||
assertThat(result.isRight()).isTrue()
|
||||
coVerify { userWalletsSyncDelegate.syncWallets(emptyList()) }
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `GIVEN hot wallet with blank name WHEN invoke THEN generate name using invokeForHot`() = runTest {
|
||||
// GIVEN
|
||||
val applicationId = ApplicationId("test-app-id")
|
||||
val walletId = UserWalletId("0A0B0C0D")
|
||||
val hotWallet = mockk<UserWallet.Hot> {
|
||||
every { this@mockk.walletId } returns walletId
|
||||
}
|
||||
every { userWalletListRepository.userWallets } returns MutableStateFlow(listOf(hotWallet))
|
||||
|
||||
val remoteWalletWithBlankName = UserWalletRemoteInfo(walletId, "", true)
|
||||
val generatedName = "Wallet"
|
||||
every { generateWalletNameUseCase.invokeForHot() } returns generatedName
|
||||
|
||||
val expectedWallet = UserWalletRemoteInfo(walletId, generatedName, true)
|
||||
coEvery { walletsRepository.getWalletsInfo(applicationId.value) } returns listOf(remoteWalletWithBlankName)
|
||||
coEvery { userWalletsSyncDelegate.syncWallets(listOf(expectedWallet)) } returns Unit.right()
|
||||
|
||||
// WHEN
|
||||
val result = useCase(applicationId)
|
||||
|
||||
// THEN
|
||||
assertThat(result.isRight()).isTrue()
|
||||
coVerify { generateWalletNameUseCase.invokeForHot() }
|
||||
coVerify { userWalletsSyncDelegate.syncWallets(listOf(expectedWallet)) }
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `GIVEN cold wallet with blank name WHEN invoke THEN generate name using productType`() = runTest {
|
||||
// GIVEN
|
||||
val applicationId = ApplicationId("test-app-id")
|
||||
val walletId = UserWalletId("0A0B0C0D")
|
||||
val mockScanResponse = mockk<ScanResponse>(relaxed = true) {
|
||||
every { productType } returns ProductType.Wallet2
|
||||
every { card } returns mockk(relaxed = true)
|
||||
}
|
||||
val coldWallet = mockk<UserWallet.Cold> {
|
||||
every { this@mockk.walletId } returns walletId
|
||||
every { scanResponse } returns mockScanResponse
|
||||
}
|
||||
every { userWalletListRepository.userWallets } returns MutableStateFlow(listOf(coldWallet))
|
||||
|
||||
val remoteWalletWithBlankName = UserWalletRemoteInfo(walletId, "", true)
|
||||
val generatedName = "Wallet"
|
||||
every { generateWalletNameUseCase.invoke(any(), any(), any()) } returns generatedName
|
||||
|
||||
val expectedWallet = UserWalletRemoteInfo(walletId, generatedName, true)
|
||||
coEvery { walletsRepository.getWalletsInfo(applicationId.value) } returns listOf(remoteWalletWithBlankName)
|
||||
coEvery { userWalletsSyncDelegate.syncWallets(listOf(expectedWallet)) } returns Unit.right()
|
||||
|
||||
// WHEN
|
||||
val result = useCase(applicationId)
|
||||
|
||||
// THEN
|
||||
assertThat(result.isRight()).isTrue()
|
||||
coVerify { generateWalletNameUseCase.invoke(any(), any(), any()) }
|
||||
coVerify { userWalletsSyncDelegate.syncWallets(listOf(expectedWallet)) }
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `GIVEN wallet with blank name not in repository WHEN invoke THEN filter it out`() = runTest {
|
||||
// GIVEN
|
||||
val applicationId = ApplicationId("test-app-id")
|
||||
val knownWalletId = UserWalletId("0A0B0C0D")
|
||||
val unknownWalletId = UserWalletId("0E0F1011")
|
||||
|
||||
val hotWallet = mockk<UserWallet.Hot> {
|
||||
every { this@mockk.walletId } returns knownWalletId
|
||||
}
|
||||
every { userWalletListRepository.userWallets } returns MutableStateFlow(listOf(hotWallet))
|
||||
every { generateWalletNameUseCase.invokeForHot() } returns "Wallet"
|
||||
|
||||
val knownWalletRemote = UserWalletRemoteInfo(knownWalletId, "", true)
|
||||
val unknownWalletRemote = UserWalletRemoteInfo(unknownWalletId, "", true)
|
||||
val expectedWallet = UserWalletRemoteInfo(knownWalletId, "Wallet", true)
|
||||
|
||||
coEvery { walletsRepository.getWalletsInfo(applicationId.value) } returns listOf(knownWalletRemote, unknownWalletRemote)
|
||||
coEvery { userWalletsSyncDelegate.syncWallets(listOf(expectedWallet)) } returns Unit.right()
|
||||
|
||||
// WHEN
|
||||
val result = useCase(applicationId)
|
||||
|
||||
// THEN
|
||||
assertThat(result.isRight()).isTrue()
|
||||
coVerify { userWalletsSyncDelegate.syncWallets(listOf(expectedWallet)) }
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue