Updated on 2026-08-14
This commit is contained in:
parent
35fd75485c
commit
3e01845203
21 changed files with 1330 additions and 2 deletions
|
|
@ -9,9 +9,14 @@ android {
|
|||
namespace = "com.tangem.data.account"
|
||||
}
|
||||
|
||||
tasks.withType<Test>().configureEach {
|
||||
useJUnitPlatform()
|
||||
}
|
||||
|
||||
dependencies {
|
||||
|
||||
// region Project - Core
|
||||
implementation(projects.core.datasource)
|
||||
api(projects.core.utils)
|
||||
// endregion
|
||||
|
||||
|
|
@ -21,7 +26,7 @@ dependencies {
|
|||
// endregion
|
||||
|
||||
// Project - Data
|
||||
implementation(projects.core.datasource)
|
||||
implementation(projects.data.common)
|
||||
// endregion
|
||||
|
||||
// region DI
|
||||
|
|
@ -34,4 +39,13 @@ dependencies {
|
|||
implementation(deps.kotlin.coroutines)
|
||||
implementation(deps.timber)
|
||||
// endregion
|
||||
|
||||
// region Test
|
||||
testImplementation(deps.test.coroutine)
|
||||
testImplementation(deps.test.junit5)
|
||||
testRuntimeOnly(deps.test.junit5.engine)
|
||||
testImplementation(deps.test.mockk)
|
||||
testImplementation(deps.test.truth)
|
||||
testImplementation(projects.common.test)
|
||||
// endregion
|
||||
}
|
||||
|
|
@ -0,0 +1,33 @@
|
|||
package com.tangem.data.account.converter
|
||||
|
||||
import arrow.core.getOrElse
|
||||
import com.tangem.datasource.api.tangemTech.models.account.WalletAccountDTO
|
||||
import com.tangem.domain.models.account.AccountId
|
||||
import com.tangem.domain.models.account.AccountName
|
||||
import com.tangem.domain.models.account.CryptoPortfolioIcon
|
||||
import com.tangem.domain.models.account.DerivationIndex
|
||||
import com.tangem.domain.models.wallet.UserWalletId
|
||||
|
||||
internal fun String.toAccountId(userWalletId: UserWalletId): AccountId {
|
||||
return AccountId.forCryptoPortfolio(value = this, userWalletId = userWalletId).getOrElse {
|
||||
error("Unable to create AccountId from value: $this. Cause: $it")
|
||||
}
|
||||
}
|
||||
|
||||
internal fun String.toAccountName(): AccountName {
|
||||
return AccountName(value = this).getOrElse {
|
||||
error("Unable to create AccountName from value: $this. Cause: $it")
|
||||
}
|
||||
}
|
||||
|
||||
internal fun WalletAccountDTO.toIcon(): CryptoPortfolioIcon {
|
||||
return CryptoPortfolioIconConverter.convert(
|
||||
value = CryptoPortfolioIconConverter.DataModel(icon = icon, color = iconColor),
|
||||
)
|
||||
}
|
||||
|
||||
internal fun Int.toDerivationIndex(): DerivationIndex {
|
||||
return DerivationIndex(value = this).getOrElse {
|
||||
error("Unable to create DerivationIndex from value: $this. Cause: $it")
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,46 @@
|
|||
package com.tangem.data.account.converter
|
||||
|
||||
import arrow.core.getOrElse
|
||||
import com.tangem.datasource.api.tangemTech.models.account.GetWalletAccountsResponse
|
||||
import com.tangem.domain.account.models.AccountList
|
||||
import com.tangem.domain.models.wallet.UserWallet
|
||||
import com.tangem.utils.converter.Converter
|
||||
import dagger.assisted.Assisted
|
||||
import dagger.assisted.AssistedFactory
|
||||
import dagger.assisted.AssistedInject
|
||||
|
||||
/**
|
||||
* Converts a [GetWalletAccountsResponse] to an [AccountList] and vice versa
|
||||
*
|
||||
* @property userWallet the user wallet associated with the account list
|
||||
* @param cryptoPortfolioConverterFactory factory to create [CryptoPortfolioConverter] instances
|
||||
*
|
||||
[REDACTED_AUTHOR]
|
||||
*/
|
||||
internal class AccountListConverter @AssistedInject constructor(
|
||||
@Assisted private val userWallet: UserWallet,
|
||||
cryptoPortfolioConverterFactory: CryptoPortfolioConverter.Factory,
|
||||
) : Converter<GetWalletAccountsResponse, AccountList> {
|
||||
|
||||
private val cryptoPortfolioConverter: CryptoPortfolioConverter by lazy {
|
||||
cryptoPortfolioConverterFactory.create(userWallet)
|
||||
}
|
||||
|
||||
override fun convert(value: GetWalletAccountsResponse): AccountList {
|
||||
return AccountList(
|
||||
userWallet = userWallet,
|
||||
accounts = value.accounts.map(cryptoPortfolioConverter::convert).toSet(),
|
||||
totalAccounts = value.wallet.totalAccounts,
|
||||
sortType = TokensSortTypeConverter.convert(value.wallet.sort),
|
||||
groupType = TokensGroupTypeConverter.convert(value.wallet.group),
|
||||
)
|
||||
.getOrElse {
|
||||
error("Failed to convert GetWalletAccountsResponse to AccountList: $it")
|
||||
}
|
||||
}
|
||||
|
||||
@AssistedFactory
|
||||
interface Factory {
|
||||
fun create(userWallet: UserWallet): AccountListConverter
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,29 @@
|
|||
package com.tangem.data.account.converter
|
||||
|
||||
import com.tangem.datasource.api.tangemTech.models.account.WalletAccountDTO
|
||||
import com.tangem.domain.account.models.ArchivedAccount
|
||||
import com.tangem.domain.models.wallet.UserWalletId
|
||||
import com.tangem.utils.converter.Converter
|
||||
|
||||
/**
|
||||
* Converts a [WalletAccountDTO] to an [ArchivedAccount]
|
||||
*
|
||||
* @param userWalletId the ID of the user wallet associated with the account
|
||||
*
|
||||
[REDACTED_AUTHOR]
|
||||
*/
|
||||
internal class ArchivedAccountConverter(
|
||||
private val userWalletId: UserWalletId,
|
||||
) : Converter<WalletAccountDTO, ArchivedAccount> {
|
||||
|
||||
override fun convert(value: WalletAccountDTO): ArchivedAccount {
|
||||
return ArchivedAccount(
|
||||
accountId = value.id.toAccountId(userWalletId = userWalletId),
|
||||
name = value.name.toAccountName(),
|
||||
icon = value.toIcon(),
|
||||
derivationIndex = value.derivationIndex.toDerivationIndex(),
|
||||
tokensCount = value.totalTokens ?: error("Total tokens should not be null"),
|
||||
networksCount = value.totalNetworks ?: error("Total networks should not be null"),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,61 @@
|
|||
package com.tangem.data.account.converter
|
||||
|
||||
import com.tangem.data.common.currency.ResponseCryptoCurrenciesFactory
|
||||
import com.tangem.data.common.currency.UserTokensResponseFactory
|
||||
import com.tangem.datasource.api.tangemTech.models.account.WalletAccountDTO
|
||||
import com.tangem.domain.models.account.Account
|
||||
import com.tangem.domain.models.wallet.UserWallet
|
||||
import com.tangem.utils.converter.TwoWayConverter
|
||||
import dagger.assisted.Assisted
|
||||
import dagger.assisted.AssistedFactory
|
||||
import dagger.assisted.AssistedInject
|
||||
|
||||
/**
|
||||
* Converts a [WalletAccountDTO] to an [Account.CryptoPortfolio] and vise versa
|
||||
*
|
||||
* @property userWallet the user wallet associated with the account list
|
||||
* @property responseCryptoCurrenciesFactory factory to create crypto currencies from response tokens
|
||||
*
|
||||
[REDACTED_AUTHOR]
|
||||
*/
|
||||
internal class CryptoPortfolioConverter @AssistedInject constructor(
|
||||
@Assisted private val userWallet: UserWallet,
|
||||
private val responseCryptoCurrenciesFactory: ResponseCryptoCurrenciesFactory,
|
||||
private val userTokensResponseFactory: UserTokensResponseFactory,
|
||||
) : TwoWayConverter<WalletAccountDTO, Account.CryptoPortfolio> {
|
||||
|
||||
override fun convert(value: WalletAccountDTO): Account.CryptoPortfolio {
|
||||
val tokens = value.tokens ?: error("Tokens should not be null")
|
||||
|
||||
return Account.CryptoPortfolio(
|
||||
accountId = value.id.toAccountId(userWallet.walletId),
|
||||
accountName = value.name.toAccountName(),
|
||||
icon = value.toIcon(),
|
||||
derivationIndex = value.derivationIndex.toDerivationIndex(),
|
||||
cryptoCurrencies = if (tokens.isNotEmpty()) {
|
||||
responseCryptoCurrenciesFactory.createCurrencies(
|
||||
tokens = tokens,
|
||||
userWallet = userWallet,
|
||||
).toSet()
|
||||
} else {
|
||||
emptySet()
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
override fun convertBack(value: Account.CryptoPortfolio): WalletAccountDTO {
|
||||
return WalletAccountDTO(
|
||||
id = value.accountId.value,
|
||||
name = value.accountName.value,
|
||||
derivationIndex = value.derivationIndex.value,
|
||||
icon = value.icon.value.name,
|
||||
iconColor = value.icon.color.name,
|
||||
tokens = value.cryptoCurrencies.map(userTokensResponseFactory::createResponseToken),
|
||||
)
|
||||
}
|
||||
|
||||
@AssistedFactory
|
||||
interface Factory {
|
||||
fun create(userWallet: UserWallet): CryptoPortfolioConverter
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,21 @@
|
|||
package com.tangem.data.account.converter
|
||||
|
||||
import com.tangem.domain.models.account.CryptoPortfolioIcon
|
||||
import com.tangem.utils.converter.Converter
|
||||
|
||||
/**
|
||||
* Converts a [CryptoPortfolioIconConverter.DataModel] to a [CryptoPortfolioIcon]
|
||||
*
|
||||
[REDACTED_AUTHOR]
|
||||
*/
|
||||
internal object CryptoPortfolioIconConverter : Converter<CryptoPortfolioIconConverter.DataModel, CryptoPortfolioIcon> {
|
||||
|
||||
override fun convert(value: DataModel): CryptoPortfolioIcon {
|
||||
return CryptoPortfolioIcon.ofCustomAccount(
|
||||
value = CryptoPortfolioIcon.Icon.valueOf(value.icon),
|
||||
color = CryptoPortfolioIcon.Color.valueOf(value.color),
|
||||
)
|
||||
}
|
||||
|
||||
data class DataModel(val icon: String, val color: String)
|
||||
}
|
||||
|
|
@ -0,0 +1,44 @@
|
|||
package com.tangem.data.account.converter
|
||||
|
||||
import com.tangem.datasource.api.tangemTech.models.account.GetWalletAccountsResponse
|
||||
import com.tangem.domain.account.models.AccountList
|
||||
import com.tangem.domain.models.account.Account
|
||||
import com.tangem.domain.models.wallet.UserWallet
|
||||
import com.tangem.utils.converter.Converter
|
||||
import dagger.assisted.Assisted
|
||||
import dagger.assisted.AssistedFactory
|
||||
import dagger.assisted.AssistedInject
|
||||
|
||||
/**
|
||||
[REDACTED_AUTHOR]
|
||||
*/
|
||||
internal class GetWalletAccountsResponseConverter @AssistedInject constructor(
|
||||
@Assisted private val userWallet: UserWallet,
|
||||
@Assisted val version: Int,
|
||||
cryptoPortfolioConverterFactory: CryptoPortfolioConverter.Factory,
|
||||
) : Converter<AccountList, GetWalletAccountsResponse> {
|
||||
|
||||
private val cryptoPortfolioConverter: CryptoPortfolioConverter by lazy {
|
||||
cryptoPortfolioConverterFactory.create(userWallet)
|
||||
}
|
||||
|
||||
override fun convert(value: AccountList): GetWalletAccountsResponse {
|
||||
return GetWalletAccountsResponse(
|
||||
wallet = GetWalletAccountsResponse.Wallet(
|
||||
version = version,
|
||||
group = TokensGroupTypeConverter.convertBack(value.groupType),
|
||||
sort = TokensSortTypeConverter.convertBack(value.sortType),
|
||||
totalAccounts = value.totalAccounts,
|
||||
),
|
||||
accounts = value.accounts
|
||||
.filterIsInstance<Account.CryptoPortfolio>()
|
||||
.map(cryptoPortfolioConverter::convertBack),
|
||||
unassignedTokens = emptyList(),
|
||||
)
|
||||
}
|
||||
|
||||
@AssistedFactory
|
||||
interface Factory {
|
||||
fun create(userWallet: UserWallet, version: Int): GetWalletAccountsResponseConverter
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,33 @@
|
|||
package com.tangem.data.account.converter
|
||||
|
||||
import com.tangem.datasource.api.tangemTech.models.account.SaveWalletAccountsResponse
|
||||
import com.tangem.datasource.api.tangemTech.models.account.WalletAccountDTO
|
||||
import com.tangem.domain.account.models.AccountList
|
||||
import com.tangem.domain.models.account.Account
|
||||
import com.tangem.utils.converter.Converter
|
||||
|
||||
/**
|
||||
* Converts an [AccountList] to a [SaveWalletAccountsResponse]
|
||||
*
|
||||
[REDACTED_AUTHOR]
|
||||
*/
|
||||
internal object SaveWalletAccountsResponseConverter : Converter<AccountList, SaveWalletAccountsResponse> {
|
||||
|
||||
override fun convert(value: AccountList): SaveWalletAccountsResponse {
|
||||
return SaveWalletAccountsResponse(
|
||||
accounts = value.accounts
|
||||
.filterIsInstance<Account.CryptoPortfolio>()
|
||||
.map(::toDTO),
|
||||
)
|
||||
}
|
||||
|
||||
private fun toDTO(account: Account.CryptoPortfolio): WalletAccountDTO {
|
||||
return WalletAccountDTO(
|
||||
id = account.accountId.value,
|
||||
name = account.accountName.value,
|
||||
derivationIndex = account.derivationIndex.value,
|
||||
icon = account.icon.value.name,
|
||||
iconColor = account.icon.color.name,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,29 @@
|
|||
package com.tangem.data.account.converter
|
||||
|
||||
import com.tangem.datasource.api.tangemTech.models.UserTokensResponse
|
||||
import com.tangem.domain.models.TokensGroupType
|
||||
import com.tangem.utils.converter.TwoWayConverter
|
||||
|
||||
/**
|
||||
* Converts a [UserTokensResponse.GroupType] to a [TokensGroupType] and vice versa
|
||||
*
|
||||
[REDACTED_AUTHOR]
|
||||
*/
|
||||
internal object TokensGroupTypeConverter : TwoWayConverter<UserTokensResponse.GroupType, TokensGroupType> {
|
||||
|
||||
override fun convert(value: UserTokensResponse.GroupType): TokensGroupType {
|
||||
return when (value) {
|
||||
UserTokensResponse.GroupType.NETWORK -> TokensGroupType.NETWORK
|
||||
UserTokensResponse.GroupType.NONE,
|
||||
UserTokensResponse.GroupType.TOKEN,
|
||||
-> TokensGroupType.NONE
|
||||
}
|
||||
}
|
||||
|
||||
override fun convertBack(value: TokensGroupType): UserTokensResponse.GroupType {
|
||||
return when (value) {
|
||||
TokensGroupType.NONE -> UserTokensResponse.GroupType.NONE
|
||||
TokensGroupType.NETWORK -> UserTokensResponse.GroupType.NETWORK
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,29 @@
|
|||
package com.tangem.data.account.converter
|
||||
|
||||
import com.tangem.datasource.api.tangemTech.models.UserTokensResponse
|
||||
import com.tangem.domain.models.TokensSortType
|
||||
import com.tangem.utils.converter.TwoWayConverter
|
||||
|
||||
/**
|
||||
* Converts a [UserTokensResponse.SortType] to a [TokensSortType] and vice versa
|
||||
*
|
||||
[REDACTED_AUTHOR]
|
||||
*/
|
||||
internal object TokensSortTypeConverter : TwoWayConverter<UserTokensResponse.SortType, TokensSortType> {
|
||||
|
||||
override fun convert(value: UserTokensResponse.SortType): TokensSortType {
|
||||
return when (value) {
|
||||
UserTokensResponse.SortType.BALANCE -> TokensSortType.BALANCE
|
||||
UserTokensResponse.SortType.MANUAL,
|
||||
UserTokensResponse.SortType.MARKETCAP,
|
||||
-> TokensSortType.NONE
|
||||
}
|
||||
}
|
||||
|
||||
override fun convertBack(value: TokensSortType): UserTokensResponse.SortType {
|
||||
return when (value) {
|
||||
TokensSortType.NONE -> UserTokensResponse.SortType.MANUAL
|
||||
TokensSortType.BALANCE -> UserTokensResponse.SortType.BALANCE
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,85 @@
|
|||
package com.tangem.data.account.converter
|
||||
|
||||
import com.tangem.datasource.api.tangemTech.models.UserTokensResponse
|
||||
import com.tangem.datasource.api.tangemTech.models.account.GetWalletAccountsResponse
|
||||
import com.tangem.datasource.api.tangemTech.models.account.WalletAccountDTO
|
||||
import com.tangem.domain.account.models.AccountList
|
||||
import com.tangem.domain.models.TokensGroupType
|
||||
import com.tangem.domain.models.TokensSortType
|
||||
import com.tangem.domain.models.account.Account
|
||||
import com.tangem.domain.models.wallet.UserWallet
|
||||
import com.tangem.domain.models.wallet.UserWalletId
|
||||
|
||||
internal fun createWalletAccountDTO(
|
||||
userWalletId: UserWalletId,
|
||||
accountId: String? = null,
|
||||
accountName: String? = null,
|
||||
icon: String? = null,
|
||||
iconColor: String? = null,
|
||||
derivationIndex: Int? = null,
|
||||
tokens: List<UserTokensResponse.Token>? = emptyList(),
|
||||
): WalletAccountDTO {
|
||||
val mainAccount = Account.CryptoPortfolio.createMainAccount(userWalletId = userWalletId)
|
||||
|
||||
return WalletAccountDTO(
|
||||
id = accountId ?: mainAccount.accountId.value,
|
||||
name = accountName ?: mainAccount.accountName.value,
|
||||
derivationIndex = derivationIndex ?: mainAccount.derivationIndex.value,
|
||||
icon = icon ?: mainAccount.icon.value.name,
|
||||
iconColor = iconColor ?: mainAccount.icon.color.name,
|
||||
tokens = tokens,
|
||||
)
|
||||
}
|
||||
|
||||
internal fun createCryptoPortfolio(userWalletId: UserWalletId): Account.CryptoPortfolio {
|
||||
return Account.CryptoPortfolio.createMainAccount(userWalletId = userWalletId)
|
||||
}
|
||||
|
||||
internal fun createGetWalletAccountsResponse(
|
||||
userWalletId: UserWalletId,
|
||||
groupType: UserTokensResponse.GroupType = UserTokensResponse.GroupType.NETWORK,
|
||||
sortType: UserTokensResponse.SortType = UserTokensResponse.SortType.BALANCE,
|
||||
accountId: String? = null,
|
||||
accountName: String? = null,
|
||||
icon: String? = null,
|
||||
iconColor: String? = null,
|
||||
derivationIndex: Int? = null,
|
||||
tokens: List<UserTokensResponse.Token>? = emptyList(),
|
||||
): GetWalletAccountsResponse {
|
||||
return GetWalletAccountsResponse(
|
||||
wallet = GetWalletAccountsResponse.Wallet(
|
||||
version = 0,
|
||||
group = groupType,
|
||||
sort = sortType,
|
||||
totalAccounts = 1,
|
||||
),
|
||||
accounts = buildList {
|
||||
createWalletAccountDTO(
|
||||
userWalletId = userWalletId,
|
||||
accountId = accountId,
|
||||
accountName = accountName,
|
||||
icon = icon,
|
||||
iconColor = iconColor,
|
||||
derivationIndex = derivationIndex,
|
||||
tokens = tokens,
|
||||
)
|
||||
.let(::add)
|
||||
},
|
||||
unassignedTokens = emptyList(),
|
||||
)
|
||||
}
|
||||
|
||||
internal fun createAccountList(
|
||||
userWallet: UserWallet,
|
||||
sortType: TokensSortType = TokensSortType.BALANCE,
|
||||
groupType: TokensGroupType = TokensGroupType.NETWORK,
|
||||
): AccountList {
|
||||
return AccountList(
|
||||
userWallet = userWallet,
|
||||
accounts = setOf(createCryptoPortfolio(userWallet.walletId)),
|
||||
totalAccounts = 1,
|
||||
sortType = sortType,
|
||||
groupType = groupType,
|
||||
)
|
||||
.getOrNull()!!
|
||||
}
|
||||
|
|
@ -0,0 +1,159 @@
|
|||
package com.tangem.data.account.converter
|
||||
|
||||
import com.google.common.truth.Truth
|
||||
import com.tangem.common.test.utils.ProvideTestModels
|
||||
import com.tangem.datasource.api.tangemTech.models.UserTokensResponse
|
||||
import com.tangem.datasource.api.tangemTech.models.account.GetWalletAccountsResponse
|
||||
import com.tangem.domain.account.models.AccountList
|
||||
import com.tangem.domain.models.TokensGroupType
|
||||
import com.tangem.domain.models.TokensSortType
|
||||
import com.tangem.domain.models.account.Account
|
||||
import com.tangem.domain.models.wallet.UserWallet
|
||||
import com.tangem.domain.models.wallet.UserWalletId
|
||||
import io.mockk.clearMocks
|
||||
import io.mockk.every
|
||||
import io.mockk.mockk
|
||||
import org.junit.jupiter.api.*
|
||||
import org.junit.jupiter.params.ParameterizedTest
|
||||
|
||||
@TestInstance(TestInstance.Lifecycle.PER_CLASS)
|
||||
class AccountListConverterTest {
|
||||
|
||||
private val userWallet = mockk<UserWallet> {
|
||||
every { walletId } returns UserWalletId("011")
|
||||
}
|
||||
private val cryptoPortfolioConverterFactory = mockk<CryptoPortfolioConverter.Factory>()
|
||||
private val cryptoPortfolioConverter = mockk<CryptoPortfolioConverter>()
|
||||
private val converter = AccountListConverter(userWallet, cryptoPortfolioConverterFactory)
|
||||
|
||||
@BeforeAll
|
||||
fun setupAll() {
|
||||
every { cryptoPortfolioConverterFactory.create(userWallet) } returns cryptoPortfolioConverter
|
||||
}
|
||||
|
||||
@BeforeEach
|
||||
fun setupEach() {
|
||||
clearMocks(cryptoPortfolioConverter)
|
||||
}
|
||||
|
||||
@Nested
|
||||
@TestInstance(TestInstance.Lifecycle.PER_CLASS)
|
||||
inner class Convert {
|
||||
|
||||
@Test
|
||||
fun `cryptoPortfolioConverter throws exception`() {
|
||||
// Arrange
|
||||
val dto = createGetWalletAccountsResponse(userWallet.walletId)
|
||||
val exception = IllegalStateException("Test exception")
|
||||
|
||||
every { cryptoPortfolioConverter.convert(any()) } throws exception
|
||||
|
||||
// Act
|
||||
val actual = runCatching { converter.convert(dto) }.exceptionOrNull()!!
|
||||
|
||||
// Asset
|
||||
val expected = exception
|
||||
Truth.assertThat(actual).isInstanceOf(expected::class.java)
|
||||
Truth.assertThat(actual.message).isEqualTo(expected.message)
|
||||
}
|
||||
|
||||
@ParameterizedTest
|
||||
@ProvideTestModels
|
||||
fun convert(model: ConvertModel) {
|
||||
// Arrange
|
||||
if (model.expected.isSuccess) {
|
||||
model.value.accounts.forEach { dto ->
|
||||
val account = model.expected.getOrNull()!!.accounts
|
||||
.firstOrNull { it.accountId.value == dto.id } as? Account.CryptoPortfolio
|
||||
|
||||
every { cryptoPortfolioConverter.convert(dto) } returns account!!
|
||||
}
|
||||
}
|
||||
|
||||
// Act
|
||||
val actual = runCatching { converter.convert(model.value) }
|
||||
|
||||
// Asset
|
||||
actual
|
||||
.onSuccess {
|
||||
val expected = model.expected.getOrNull()
|
||||
Truth.assertThat(it).isEqualTo(expected)
|
||||
}
|
||||
.onFailure {
|
||||
val expected = model.expected.exceptionOrNull() ?: throw it
|
||||
Truth.assertThat(it).isInstanceOf(expected::class.java)
|
||||
Truth.assertThat(it.message).isEqualTo(expected.message)
|
||||
}
|
||||
}
|
||||
|
||||
private fun provideTestModels(): List<ConvertModel> {
|
||||
return listOf(
|
||||
ConvertModel(
|
||||
value = createGetWalletAccountsResponse(
|
||||
userWalletId = userWallet.walletId,
|
||||
sortType = UserTokensResponse.SortType.BALANCE,
|
||||
groupType = UserTokensResponse.GroupType.NETWORK,
|
||||
),
|
||||
expected = Result.success(
|
||||
createAccountList(
|
||||
userWallet = userWallet,
|
||||
sortType = TokensSortType.BALANCE,
|
||||
groupType = TokensGroupType.NETWORK,
|
||||
),
|
||||
),
|
||||
),
|
||||
ConvertModel(
|
||||
value = createGetWalletAccountsResponse(
|
||||
userWalletId = userWallet.walletId,
|
||||
sortType = UserTokensResponse.SortType.MANUAL,
|
||||
groupType = UserTokensResponse.GroupType.TOKEN,
|
||||
),
|
||||
expected = Result.success(
|
||||
createAccountList(
|
||||
userWallet = userWallet,
|
||||
sortType = TokensSortType.NONE,
|
||||
groupType = TokensGroupType.NONE,
|
||||
),
|
||||
),
|
||||
),
|
||||
ConvertModel(
|
||||
value = createGetWalletAccountsResponse(
|
||||
userWalletId = userWallet.walletId,
|
||||
sortType = UserTokensResponse.SortType.MARKETCAP,
|
||||
groupType = UserTokensResponse.GroupType.NONE,
|
||||
),
|
||||
expected = Result.success(
|
||||
createAccountList(
|
||||
userWallet = userWallet,
|
||||
sortType = TokensSortType.NONE,
|
||||
groupType = TokensGroupType.NONE,
|
||||
),
|
||||
),
|
||||
),
|
||||
ConvertModel(
|
||||
value = GetWalletAccountsResponse(
|
||||
wallet = GetWalletAccountsResponse.Wallet(
|
||||
version = 0,
|
||||
group = UserTokensResponse.GroupType.NETWORK,
|
||||
sort = UserTokensResponse.SortType.BALANCE,
|
||||
totalAccounts = 1,
|
||||
),
|
||||
accounts = emptyList(),
|
||||
unassignedTokens = emptyList(),
|
||||
),
|
||||
expected = Result.failure(
|
||||
IllegalStateException(
|
||||
"Failed to convert GetWalletAccountsResponse to AccountList: EmptyAccountsList: " +
|
||||
"The accounts list cannot be empty",
|
||||
),
|
||||
),
|
||||
),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
data class ConvertModel(
|
||||
val value: GetWalletAccountsResponse,
|
||||
val expected: Result<AccountList>,
|
||||
)
|
||||
}
|
||||
|
|
@ -0,0 +1,144 @@
|
|||
package com.tangem.data.account.converter
|
||||
|
||||
import com.google.common.truth.Truth
|
||||
import com.tangem.common.test.utils.ProvideTestModels
|
||||
import com.tangem.datasource.api.tangemTech.models.account.WalletAccountDTO
|
||||
import com.tangem.domain.account.models.ArchivedAccount
|
||||
import com.tangem.domain.models.account.AccountId
|
||||
import com.tangem.domain.models.account.AccountName
|
||||
import com.tangem.domain.models.account.CryptoPortfolioIcon
|
||||
import com.tangem.domain.models.account.DerivationIndex
|
||||
import com.tangem.domain.models.wallet.UserWalletId
|
||||
import org.junit.jupiter.api.TestInstance
|
||||
import org.junit.jupiter.params.ParameterizedTest
|
||||
|
||||
/**
|
||||
[REDACTED_AUTHOR]
|
||||
*/
|
||||
@TestInstance(TestInstance.Lifecycle.PER_CLASS)
|
||||
class ArchivedAccountConverterTest {
|
||||
|
||||
private val userWalletId = UserWalletId("011")
|
||||
private val converter = ArchivedAccountConverter(userWalletId = userWalletId)
|
||||
|
||||
@ParameterizedTest
|
||||
@ProvideTestModels
|
||||
fun convert(model: TestModel) {
|
||||
// Act
|
||||
val actual = runCatching { converter.convert(value = model.value) }
|
||||
|
||||
// Assert
|
||||
actual
|
||||
.onSuccess {
|
||||
val expected = model.expected.getOrNull()!!
|
||||
Truth.assertThat(it).isEqualTo(expected)
|
||||
}
|
||||
.onFailure {
|
||||
val expected = model.expected.exceptionOrNull()!!
|
||||
Truth.assertThat(it).isInstanceOf(expected::class.java)
|
||||
Truth.assertThat(it.message).isEqualTo(expected.message)
|
||||
}
|
||||
}
|
||||
|
||||
private fun provideTestModels(): List<TestModel> {
|
||||
return listOf(
|
||||
TestModel(
|
||||
value = createDTO(),
|
||||
expected = Result.success(createDomain()),
|
||||
),
|
||||
TestModel(
|
||||
value = createDTO(accountId = "123"),
|
||||
expected = Result.failure(
|
||||
IllegalStateException(
|
||||
"Unable to create AccountId from value: 123. Cause: ${AccountId.Error.InvalidFormat}",
|
||||
),
|
||||
),
|
||||
),
|
||||
TestModel(
|
||||
value = createDTO(name = ""),
|
||||
expected = Result.failure(
|
||||
IllegalStateException(
|
||||
"Unable to create AccountName from value: . Cause: ${AccountName.Error.Empty}",
|
||||
),
|
||||
),
|
||||
),
|
||||
TestModel(
|
||||
value = createDTO(icon = "INVALID_ICON"),
|
||||
expected = Result.failure(
|
||||
IllegalArgumentException(
|
||||
"No enum constant com.tangem.domain.models.account.CryptoPortfolioIcon.Icon.INVALID_ICON",
|
||||
),
|
||||
),
|
||||
),
|
||||
TestModel(
|
||||
value = createDTO(iconColor = "INVALID_COLOR"),
|
||||
expected = Result.failure(
|
||||
IllegalArgumentException(
|
||||
"No enum constant com.tangem.domain.models.account.CryptoPortfolioIcon.Color.INVALID_COLOR",
|
||||
),
|
||||
),
|
||||
),
|
||||
TestModel(
|
||||
value = createDTO(derivationIndex = -1),
|
||||
expected = Result.failure(
|
||||
IllegalStateException(
|
||||
"Unable to create DerivationIndex from value: -1. " +
|
||||
"Cause: NegativeDerivationIndex: Derivation index cannot be negative: -1",
|
||||
),
|
||||
),
|
||||
),
|
||||
TestModel(
|
||||
value = createDTO(totalTokens = null),
|
||||
expected = Result.failure(
|
||||
IllegalStateException("Total tokens should not be null"),
|
||||
),
|
||||
),
|
||||
TestModel(
|
||||
value = createDTO(totalNetworks = null),
|
||||
expected = Result.failure(
|
||||
IllegalStateException("Total networks should not be null"),
|
||||
),
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
private fun createDTO(
|
||||
accountId: String = "957B88B12730E646E0F33D3618B77DFA579E8231E3C59C7104BE7165611C8027",
|
||||
name: String = "Test Account",
|
||||
icon: String = "Letter",
|
||||
iconColor: String = "Azure",
|
||||
derivationIndex: Int = 0,
|
||||
totalTokens: Int? = 1,
|
||||
totalNetworks: Int? = 1,
|
||||
): WalletAccountDTO {
|
||||
return WalletAccountDTO(
|
||||
id = accountId,
|
||||
name = name,
|
||||
derivationIndex = derivationIndex,
|
||||
icon = icon,
|
||||
iconColor = iconColor,
|
||||
tokens = null,
|
||||
totalTokens = totalTokens,
|
||||
totalNetworks = totalNetworks,
|
||||
)
|
||||
}
|
||||
|
||||
private fun createDomain(): ArchivedAccount {
|
||||
return ArchivedAccount(
|
||||
accountId = AccountId.forCryptoPortfolio(userWalletId, DerivationIndex(0).getOrNull()!!),
|
||||
name = "Test Account".toAccountName(),
|
||||
derivationIndex = 0.toDerivationIndex(),
|
||||
icon = CryptoPortfolioIcon.ofCustomAccount(
|
||||
value = CryptoPortfolioIcon.Icon.Letter,
|
||||
color = CryptoPortfolioIcon.Color.Azure,
|
||||
),
|
||||
tokensCount = 1,
|
||||
networksCount = 1,
|
||||
)
|
||||
}
|
||||
|
||||
data class TestModel(
|
||||
val value: WalletAccountDTO,
|
||||
val expected: Result<ArchivedAccount>,
|
||||
)
|
||||
}
|
||||
|
|
@ -0,0 +1,155 @@
|
|||
package com.tangem.data.account.converter
|
||||
|
||||
import com.google.common.truth.Truth
|
||||
import com.tangem.common.test.utils.ProvideTestModels
|
||||
import com.tangem.data.common.currency.ResponseCryptoCurrenciesFactory
|
||||
import com.tangem.data.common.currency.UserTokensResponseFactory
|
||||
import com.tangem.datasource.api.tangemTech.models.account.WalletAccountDTO
|
||||
import com.tangem.domain.models.account.Account
|
||||
import com.tangem.domain.models.account.AccountId
|
||||
import com.tangem.domain.models.account.AccountName
|
||||
import com.tangem.domain.models.wallet.UserWallet
|
||||
import com.tangem.domain.models.wallet.UserWalletId
|
||||
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
|
||||
|
||||
@TestInstance(TestInstance.Lifecycle.PER_CLASS)
|
||||
class CryptoPortfolioConverterTest {
|
||||
|
||||
private val userWallet = mockk<UserWallet> {
|
||||
every { walletId } returns UserWalletId("011")
|
||||
}
|
||||
|
||||
private val responseCryptoCurrenciesFactory: ResponseCryptoCurrenciesFactory = mockk()
|
||||
private val userTokensResponseFactory: UserTokensResponseFactory = mockk()
|
||||
private val converter = CryptoPortfolioConverter(
|
||||
userWallet = userWallet,
|
||||
responseCryptoCurrenciesFactory = responseCryptoCurrenciesFactory,
|
||||
userTokensResponseFactory = userTokensResponseFactory,
|
||||
)
|
||||
|
||||
@BeforeEach
|
||||
fun setupEach() {
|
||||
clearMocks(responseCryptoCurrenciesFactory, userTokensResponseFactory)
|
||||
}
|
||||
|
||||
@Nested
|
||||
@TestInstance(TestInstance.Lifecycle.PER_CLASS)
|
||||
inner class Convert {
|
||||
|
||||
@ParameterizedTest
|
||||
@ProvideTestModels
|
||||
fun convert(model: ConvertModel) {
|
||||
// Act
|
||||
val actual = runCatching { converter.convert(model.value) }
|
||||
|
||||
// Asset
|
||||
actual
|
||||
.onSuccess {
|
||||
val expected = model.expected.getOrNull()
|
||||
Truth.assertThat(it).isEqualTo(expected)
|
||||
}
|
||||
.onFailure {
|
||||
val expected = model.expected.exceptionOrNull() ?: throw it
|
||||
Truth.assertThat(it).isInstanceOf(expected::class.java)
|
||||
Truth.assertThat(it.message).isEqualTo(expected.message)
|
||||
}
|
||||
}
|
||||
|
||||
private fun provideTestModels(): List<ConvertModel> {
|
||||
return listOf(
|
||||
ConvertModel(
|
||||
value = createWalletAccountDTO(userWalletId = userWallet.walletId),
|
||||
expected = Result.success(createCryptoPortfolio(userWalletId = userWallet.walletId)),
|
||||
),
|
||||
ConvertModel(
|
||||
value = createWalletAccountDTO(userWalletId = userWallet.walletId, accountId = "123"),
|
||||
expected = Result.failure(
|
||||
IllegalStateException(
|
||||
"Unable to create AccountId from value: 123. Cause: ${AccountId.Error.InvalidFormat}",
|
||||
),
|
||||
),
|
||||
),
|
||||
ConvertModel(
|
||||
value = createWalletAccountDTO(userWalletId = userWallet.walletId, accountName = ""),
|
||||
expected = Result.failure(
|
||||
IllegalStateException(
|
||||
"Unable to create AccountName from value: . Cause: ${AccountName.Error.Empty}",
|
||||
),
|
||||
),
|
||||
),
|
||||
ConvertModel(
|
||||
value = createWalletAccountDTO(userWalletId = userWallet.walletId, icon = "INVALID_ICON"),
|
||||
expected = Result.failure(
|
||||
IllegalArgumentException(
|
||||
"No enum constant com.tangem.domain.models.account.CryptoPortfolioIcon.Icon.INVALID_ICON",
|
||||
),
|
||||
),
|
||||
),
|
||||
ConvertModel(
|
||||
value = createWalletAccountDTO(userWalletId = userWallet.walletId, iconColor = "INVALID_COLOR"),
|
||||
expected = Result.failure(
|
||||
IllegalArgumentException(
|
||||
"No enum constant com.tangem.domain.models.account.CryptoPortfolioIcon.Color.INVALID_COLOR",
|
||||
),
|
||||
),
|
||||
),
|
||||
ConvertModel(
|
||||
value = createWalletAccountDTO(userWalletId = userWallet.walletId, derivationIndex = -1),
|
||||
expected = Result.failure(
|
||||
IllegalStateException(
|
||||
"Unable to create DerivationIndex from value: -1. " +
|
||||
"Cause: NegativeDerivationIndex: Derivation index cannot be negative: -1",
|
||||
),
|
||||
),
|
||||
),
|
||||
ConvertModel(
|
||||
value = createWalletAccountDTO(userWalletId = userWallet.walletId, tokens = null),
|
||||
expected = Result.failure(
|
||||
IllegalStateException("Tokens should not be null"),
|
||||
),
|
||||
),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
data class ConvertModel(
|
||||
val value: WalletAccountDTO,
|
||||
val expected: Result<Account.CryptoPortfolio>,
|
||||
)
|
||||
|
||||
@Nested
|
||||
@TestInstance(TestInstance.Lifecycle.PER_CLASS)
|
||||
inner class ConvertBack {
|
||||
|
||||
@ParameterizedTest
|
||||
@ProvideTestModels
|
||||
fun convertBack(model: ConvertBackModel) {
|
||||
// Act
|
||||
val actual = converter.convertBack(model.value)
|
||||
|
||||
// Assert
|
||||
val expected = model.expected
|
||||
Truth.assertThat(actual).isEqualTo(expected)
|
||||
}
|
||||
|
||||
private fun provideTestModels(): List<ConvertBackModel> {
|
||||
return listOf(
|
||||
ConvertBackModel(
|
||||
value = createCryptoPortfolio(userWalletId = userWallet.walletId),
|
||||
expected = createWalletAccountDTO(userWalletId = userWallet.walletId),
|
||||
),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
data class ConvertBackModel(
|
||||
val value: Account.CryptoPortfolio,
|
||||
val expected: WalletAccountDTO,
|
||||
)
|
||||
}
|
||||
|
|
@ -0,0 +1,66 @@
|
|||
package com.tangem.data.account.converter
|
||||
|
||||
import com.google.common.truth.Truth
|
||||
import com.tangem.common.test.utils.ProvideTestModels
|
||||
import com.tangem.data.account.converter.CryptoPortfolioIconConverter.DataModel
|
||||
import com.tangem.domain.models.account.CryptoPortfolioIcon
|
||||
import org.junit.jupiter.api.TestInstance
|
||||
import org.junit.jupiter.params.ParameterizedTest
|
||||
|
||||
@TestInstance(TestInstance.Lifecycle.PER_CLASS)
|
||||
internal class CryptoPortfolioIconConverterTest {
|
||||
|
||||
@ParameterizedTest
|
||||
@ProvideTestModels
|
||||
fun convert(model: TestModel) {
|
||||
// Act
|
||||
val actual = runCatching { CryptoPortfolioIconConverter.convert(model.value) }
|
||||
|
||||
// Assert
|
||||
actual
|
||||
.onSuccess {
|
||||
val expected = model.expected.getOrNull()!!
|
||||
Truth.assertThat(it).isEqualTo(expected)
|
||||
}
|
||||
.onFailure {
|
||||
val expected = model.expected.exceptionOrNull()!!
|
||||
Truth.assertThat(it).isInstanceOf(expected::class.java)
|
||||
Truth.assertThat(it.message).isEqualTo(expected.message)
|
||||
}
|
||||
}
|
||||
|
||||
private fun provideTestModels(): List<TestModel> {
|
||||
return listOf(
|
||||
TestModel(
|
||||
value = DataModel(icon = "Letter", color = "Azure"),
|
||||
expected = Result.success(
|
||||
CryptoPortfolioIcon.ofCustomAccount(
|
||||
value = CryptoPortfolioIcon.Icon.Letter,
|
||||
color = CryptoPortfolioIcon.Color.Azure,
|
||||
),
|
||||
),
|
||||
),
|
||||
TestModel(
|
||||
value = DataModel(icon = "INVALID_ICON", color = "Azure"),
|
||||
expected = Result.failure(
|
||||
IllegalArgumentException(
|
||||
"No enum constant com.tangem.domain.models.account.CryptoPortfolioIcon.Icon.INVALID_ICON",
|
||||
),
|
||||
),
|
||||
),
|
||||
TestModel(
|
||||
value = DataModel(icon = "Letter", color = "INVALID_COLOR"),
|
||||
expected = Result.failure(
|
||||
IllegalArgumentException(
|
||||
"No enum constant com.tangem.domain.models.account.CryptoPortfolioIcon.Color.INVALID_COLOR",
|
||||
),
|
||||
),
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
data class TestModel(
|
||||
val value: DataModel,
|
||||
val expected: Result<CryptoPortfolioIcon>,
|
||||
)
|
||||
}
|
||||
|
|
@ -0,0 +1,130 @@
|
|||
package com.tangem.data.account.converter
|
||||
|
||||
import com.google.common.truth.Truth
|
||||
import com.tangem.common.test.utils.ProvideTestModels
|
||||
import com.tangem.datasource.api.tangemTech.models.UserTokensResponse
|
||||
import com.tangem.datasource.api.tangemTech.models.account.GetWalletAccountsResponse
|
||||
import com.tangem.domain.account.models.AccountList
|
||||
import com.tangem.domain.models.TokensGroupType
|
||||
import com.tangem.domain.models.TokensSortType
|
||||
import com.tangem.domain.models.account.Account
|
||||
import com.tangem.domain.models.wallet.UserWallet
|
||||
import com.tangem.domain.models.wallet.UserWalletId
|
||||
import io.mockk.clearMocks
|
||||
import io.mockk.every
|
||||
import io.mockk.mockk
|
||||
import org.junit.jupiter.api.*
|
||||
import org.junit.jupiter.params.ParameterizedTest
|
||||
|
||||
@TestInstance(TestInstance.Lifecycle.PER_CLASS)
|
||||
class GetWalletAccountsResponseConverterTest {
|
||||
|
||||
private val userWallet = mockk<UserWallet> {
|
||||
every { walletId } returns UserWalletId("011")
|
||||
}
|
||||
private val cryptoPortfolioConverterFactory = mockk<CryptoPortfolioConverter.Factory>()
|
||||
private val cryptoPortfolioConverter = mockk<CryptoPortfolioConverter>()
|
||||
private val converter = GetWalletAccountsResponseConverter(
|
||||
userWallet = userWallet,
|
||||
version = 0,
|
||||
cryptoPortfolioConverterFactory = cryptoPortfolioConverterFactory,
|
||||
)
|
||||
|
||||
@BeforeAll
|
||||
fun setupAll() {
|
||||
every { cryptoPortfolioConverterFactory.create(userWallet) } returns cryptoPortfolioConverter
|
||||
}
|
||||
|
||||
@BeforeEach
|
||||
fun setupEach() {
|
||||
clearMocks(cryptoPortfolioConverter)
|
||||
}
|
||||
|
||||
@Nested
|
||||
@TestInstance(TestInstance.Lifecycle.PER_CLASS)
|
||||
inner class Convert {
|
||||
|
||||
@Test
|
||||
fun `cryptoPortfolioConverter throws exception`() {
|
||||
// Arrange
|
||||
val domain = createAccountList(userWallet = userWallet)
|
||||
val exception = IllegalStateException("Test exception")
|
||||
|
||||
every { cryptoPortfolioConverter.convertBack(any()) } throws exception
|
||||
|
||||
// Act
|
||||
val actual = runCatching { converter.convert(domain) }.exceptionOrNull()!!
|
||||
|
||||
// Asset
|
||||
val expected = exception
|
||||
Truth.assertThat(actual).isInstanceOf(expected::class.java)
|
||||
Truth.assertThat(actual.message).isEqualTo(expected.message)
|
||||
}
|
||||
|
||||
@ParameterizedTest
|
||||
@ProvideTestModels
|
||||
fun convert(model: ConvertModel) {
|
||||
// Arrange
|
||||
if (model.expected.isSuccess) {
|
||||
model.value.accounts.forEach { domain ->
|
||||
val dto = model.expected.getOrNull()!!.accounts.firstOrNull { it.id == domain.accountId.value }
|
||||
|
||||
every { cryptoPortfolioConverter.convertBack(domain as Account.CryptoPortfolio) } returns dto!!
|
||||
}
|
||||
}
|
||||
|
||||
// Act
|
||||
val actual = runCatching { converter.convert(model.value) }
|
||||
|
||||
// Asset
|
||||
actual
|
||||
.onSuccess {
|
||||
val expected = model.expected.getOrNull()
|
||||
Truth.assertThat(it).isEqualTo(expected)
|
||||
}
|
||||
.onFailure {
|
||||
val expected = model.expected.exceptionOrNull() ?: throw it
|
||||
Truth.assertThat(it).isInstanceOf(expected::class.java)
|
||||
Truth.assertThat(it.message).isEqualTo(expected.message)
|
||||
}
|
||||
}
|
||||
|
||||
private fun provideTestModels(): List<ConvertModel> {
|
||||
return listOf(
|
||||
ConvertModel(
|
||||
value = createAccountList(
|
||||
userWallet = userWallet,
|
||||
sortType = TokensSortType.BALANCE,
|
||||
groupType = TokensGroupType.NETWORK,
|
||||
),
|
||||
expected = Result.success(
|
||||
createGetWalletAccountsResponse(
|
||||
userWalletId = userWallet.walletId,
|
||||
sortType = UserTokensResponse.SortType.BALANCE,
|
||||
groupType = UserTokensResponse.GroupType.NETWORK,
|
||||
),
|
||||
),
|
||||
),
|
||||
ConvertModel(
|
||||
value = createAccountList(
|
||||
userWallet = userWallet,
|
||||
sortType = TokensSortType.NONE,
|
||||
groupType = TokensGroupType.NONE,
|
||||
),
|
||||
expected = Result.success(
|
||||
createGetWalletAccountsResponse(
|
||||
userWalletId = userWallet.walletId,
|
||||
sortType = UserTokensResponse.SortType.MANUAL,
|
||||
groupType = UserTokensResponse.GroupType.NONE,
|
||||
),
|
||||
),
|
||||
),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
data class ConvertModel(
|
||||
val value: AccountList,
|
||||
val expected: Result<GetWalletAccountsResponse>,
|
||||
)
|
||||
}
|
||||
|
|
@ -0,0 +1,50 @@
|
|||
package com.tangem.data.account.converter
|
||||
|
||||
import com.google.common.truth.Truth
|
||||
import com.tangem.datasource.api.tangemTech.models.account.SaveWalletAccountsResponse
|
||||
import com.tangem.datasource.api.tangemTech.models.account.WalletAccountDTO
|
||||
import com.tangem.domain.account.models.AccountList
|
||||
import com.tangem.domain.models.account.Account
|
||||
import com.tangem.domain.models.wallet.UserWallet
|
||||
import com.tangem.domain.models.wallet.UserWalletId
|
||||
import io.mockk.every
|
||||
import io.mockk.mockk
|
||||
import org.junit.jupiter.api.Test
|
||||
import org.junit.jupiter.api.TestInstance
|
||||
|
||||
@TestInstance(TestInstance.Lifecycle.PER_CLASS)
|
||||
class SaveWalletAccountsResponseConverterTest {
|
||||
|
||||
@Test
|
||||
fun convert() {
|
||||
// Arrange
|
||||
val userWallet = mockk<UserWallet> {
|
||||
every { this@mockk.walletId } returns UserWalletId("011")
|
||||
}
|
||||
|
||||
val accountList = AccountList(
|
||||
userWallet = userWallet,
|
||||
accounts = setOf(Account.CryptoPortfolio.createMainAccount(userWalletId = userWallet.walletId)),
|
||||
totalAccounts = 1,
|
||||
)
|
||||
.getOrNull()!!
|
||||
|
||||
// Act
|
||||
val actual = SaveWalletAccountsResponseConverter.convert(value = accountList)
|
||||
|
||||
// Assert
|
||||
val expected = SaveWalletAccountsResponse(
|
||||
accounts = listOf(
|
||||
WalletAccountDTO(
|
||||
id = accountList.mainAccount.accountId.value,
|
||||
name = accountList.mainAccount.accountName.value,
|
||||
derivationIndex = accountList.mainAccount.derivationIndex.value,
|
||||
icon = accountList.mainAccount.icon.value.name,
|
||||
iconColor = accountList.mainAccount.icon.color.name,
|
||||
),
|
||||
),
|
||||
)
|
||||
|
||||
Truth.assertThat(actual).isEqualTo(expected)
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,85 @@
|
|||
package com.tangem.data.account.converter
|
||||
|
||||
import com.google.common.truth.Truth
|
||||
import com.tangem.common.test.utils.ProvideTestModels
|
||||
import com.tangem.datasource.api.tangemTech.models.UserTokensResponse
|
||||
import com.tangem.domain.models.TokensGroupType
|
||||
import org.junit.jupiter.api.Nested
|
||||
import org.junit.jupiter.api.TestInstance
|
||||
import org.junit.jupiter.params.ParameterizedTest
|
||||
|
||||
@TestInstance(TestInstance.Lifecycle.PER_CLASS)
|
||||
class TokensGroupTypeConverterTest {
|
||||
|
||||
@Nested
|
||||
@TestInstance(TestInstance.Lifecycle.PER_CLASS)
|
||||
inner class Convert {
|
||||
|
||||
@ParameterizedTest
|
||||
@ProvideTestModels
|
||||
fun convert(model: ConvertModel) {
|
||||
// Act
|
||||
val actual = TokensGroupTypeConverter.convert(model.value)
|
||||
|
||||
// Assert
|
||||
val expected = model.expected
|
||||
Truth.assertThat(actual).isEqualTo(expected)
|
||||
}
|
||||
|
||||
private fun provideTestModels(): List<ConvertModel> {
|
||||
return listOf(
|
||||
ConvertModel(
|
||||
value = UserTokensResponse.GroupType.NETWORK,
|
||||
expected = TokensGroupType.NETWORK,
|
||||
),
|
||||
ConvertModel(
|
||||
value = UserTokensResponse.GroupType.NONE,
|
||||
expected = TokensGroupType.NONE,
|
||||
),
|
||||
ConvertModel(
|
||||
value = UserTokensResponse.GroupType.TOKEN,
|
||||
expected = TokensGroupType.NONE,
|
||||
),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
data class ConvertModel(
|
||||
val value: UserTokensResponse.GroupType,
|
||||
val expected: TokensGroupType,
|
||||
)
|
||||
|
||||
@Nested
|
||||
@TestInstance(TestInstance.Lifecycle.PER_CLASS)
|
||||
inner class ConvertBack {
|
||||
|
||||
@ParameterizedTest
|
||||
@ProvideTestModels
|
||||
fun convertBack(model: ConvertBackModel) {
|
||||
// Act
|
||||
val actual = TokensGroupTypeConverter.convertBack(model.value)
|
||||
|
||||
// Assert
|
||||
val expected = model.expected
|
||||
Truth.assertThat(actual).isEqualTo(expected)
|
||||
}
|
||||
|
||||
private fun provideTestModels(): List<ConvertBackModel> {
|
||||
return listOf(
|
||||
ConvertBackModel(
|
||||
value = TokensGroupType.NETWORK,
|
||||
expected = UserTokensResponse.GroupType.NETWORK,
|
||||
),
|
||||
ConvertBackModel(
|
||||
value = TokensGroupType.NONE,
|
||||
expected = UserTokensResponse.GroupType.NONE,
|
||||
),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
data class ConvertBackModel(
|
||||
val value: TokensGroupType,
|
||||
val expected: UserTokensResponse.GroupType,
|
||||
)
|
||||
}
|
||||
|
|
@ -0,0 +1,81 @@
|
|||
package com.tangem.data.account.converter
|
||||
|
||||
import com.google.common.truth.Truth
|
||||
import com.tangem.common.test.utils.ProvideTestModels
|
||||
import com.tangem.datasource.api.tangemTech.models.UserTokensResponse
|
||||
import com.tangem.domain.models.TokensSortType
|
||||
import org.junit.jupiter.api.Nested
|
||||
import org.junit.jupiter.api.TestInstance
|
||||
import org.junit.jupiter.params.ParameterizedTest
|
||||
|
||||
@TestInstance(TestInstance.Lifecycle.PER_CLASS)
|
||||
class TokensSortTypeConverterTest {
|
||||
|
||||
@Nested
|
||||
@TestInstance(TestInstance.Lifecycle.PER_CLASS)
|
||||
inner class Convert {
|
||||
|
||||
@ParameterizedTest
|
||||
@ProvideTestModels
|
||||
fun convert(model: ConvertModel) {
|
||||
// Act
|
||||
val actual = TokensSortTypeConverter.convert(model.value)
|
||||
|
||||
// Assert
|
||||
val expected = model.expected
|
||||
Truth.assertThat(actual).isEqualTo(expected)
|
||||
}
|
||||
|
||||
fun provideTestModels() = listOf(
|
||||
ConvertModel(
|
||||
value = UserTokensResponse.SortType.BALANCE,
|
||||
expected = TokensSortType.BALANCE,
|
||||
),
|
||||
ConvertModel(
|
||||
value = UserTokensResponse.SortType.MANUAL,
|
||||
expected = TokensSortType.NONE,
|
||||
),
|
||||
ConvertModel(
|
||||
value = UserTokensResponse.SortType.MARKETCAP,
|
||||
expected = TokensSortType.NONE,
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
data class ConvertModel(
|
||||
val value: UserTokensResponse.SortType,
|
||||
val expected: TokensSortType,
|
||||
)
|
||||
|
||||
@Nested
|
||||
@TestInstance(TestInstance.Lifecycle.PER_CLASS)
|
||||
inner class ConvertBack {
|
||||
|
||||
@ParameterizedTest
|
||||
@ProvideTestModels
|
||||
fun convertBack(model: ConvertBackModel) {
|
||||
// Act
|
||||
val actual = TokensSortTypeConverter.convertBack(model.value)
|
||||
|
||||
// Assert
|
||||
val expected = model.expected
|
||||
Truth.assertThat(actual).isEqualTo(expected)
|
||||
}
|
||||
|
||||
fun provideTestModels() = listOf(
|
||||
ConvertBackModel(
|
||||
value = TokensSortType.BALANCE,
|
||||
expected = UserTokensResponse.SortType.BALANCE,
|
||||
),
|
||||
ConvertBackModel(
|
||||
value = TokensSortType.NONE,
|
||||
expected = UserTokensResponse.SortType.MANUAL,
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
data class ConvertBackModel(
|
||||
val value: TokensSortType,
|
||||
val expected: UserTokensResponse.SortType,
|
||||
)
|
||||
}
|
||||
|
|
@ -2,8 +2,9 @@ package com.tangem.data.common.currency
|
|||
|
||||
import com.tangem.datasource.api.tangemTech.models.UserTokensResponse
|
||||
import com.tangem.domain.models.currency.CryptoCurrency
|
||||
import javax.inject.Inject
|
||||
|
||||
class UserTokensResponseFactory {
|
||||
class UserTokensResponseFactory @Inject constructor() {
|
||||
|
||||
fun createUserTokensResponse(
|
||||
currencies: List<CryptoCurrency>,
|
||||
|
|
|
|||
|
|
@ -1,5 +1,8 @@
|
|||
package com.tangem.domain.models.account
|
||||
|
||||
import arrow.core.Either
|
||||
import arrow.core.raise.either
|
||||
import arrow.core.raise.ensure
|
||||
import com.tangem.common.extensions.toByteArray
|
||||
import com.tangem.domain.models.wallet.UserWalletId
|
||||
import com.tangem.utils.extensions.toHexString
|
||||
|
|
@ -18,9 +21,39 @@ data class AccountId private constructor(
|
|||
val userWalletId: UserWalletId,
|
||||
) {
|
||||
|
||||
sealed interface Error {
|
||||
|
||||
val tag: String
|
||||
get() = this::class.simpleName ?: "AccountId.Error"
|
||||
|
||||
data object Empty : Error {
|
||||
override fun toString(): String = "$tag: Account ID cannot be blank"
|
||||
}
|
||||
|
||||
data object InvalidFormat : Error {
|
||||
override fun toString(): String = "$tag: Account ID must be a 64-character hexadecimal string"
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
|
||||
private val sha256Digest: MessageDigest by lazy { MessageDigest.getInstance("SHA-256") }
|
||||
private val hexRegex = Regex("^[a-fA-F0-9]{64}$")
|
||||
|
||||
/**
|
||||
* Creates a unique account identifier for a crypto portfolio
|
||||
*
|
||||
* @param userWalletId the identifier of the user wallet
|
||||
* @param value the unique string value representing the account
|
||||
*
|
||||
* @return an [Either] containing the [AccountId] on success, or an [Error] on failure
|
||||
*/
|
||||
fun forCryptoPortfolio(userWalletId: UserWalletId, value: String): Either<Error, AccountId> = either {
|
||||
ensure(value.isNotBlank()) { Error.Empty }
|
||||
ensure(value.matches(hexRegex)) { Error.InvalidFormat }
|
||||
|
||||
AccountId(value = value, userWalletId = userWalletId)
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a unique account identifier for a crypto portfolio
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue