Updated on 2026-08-14

This commit is contained in:
Tangem 2025-03-27 21:21:17 +04:00
parent 229a2d7236
commit e9fac0e50e
10 changed files with 101 additions and 39 deletions

1
common/test/.gitignore vendored Normal file
View file

@ -0,0 +1 @@
/build

View file

@ -0,0 +1,25 @@
plugins {
alias(deps.plugins.android.library)
alias(deps.plugins.kotlin.android)
id("configuration")
}
android {
namespace = "com.tangem.common.test"
}
dependencies {
implementation(projects.data.common)
implementation(projects.domain.legacy)
implementation(projects.domain.models)
implementation(projects.domain.tokens.models)
implementation(projects.libs.blockchainSdk)
implementation(deps.androidx.datastore)
implementation(deps.test.coroutine)
implementation(tangemDeps.blockchain)
implementation(tangemDeps.card.core)
}

View file

@ -0,0 +1,107 @@
package com.tangem.common.test.domain.card
import com.tangem.common.card.CardWallet
import com.tangem.common.card.FirmwareVersion
import com.tangem.domain.common.configs.*
import com.tangem.domain.models.scan.CardDTO
import com.tangem.domain.models.scan.KeyWalletPublicKey
import com.tangem.domain.models.scan.ProductType
import com.tangem.domain.models.scan.ScanResponse
import com.tangem.operations.attestation.Attestation
import com.tangem.operations.derivation.ExtendedPublicKeysMap
import java.util.Date
/**
[REDACTED_AUTHOR]
*/
object MockScanResponseFactory {
private val genericFirmwareVersion = CardDTO.FirmwareVersion(
major = 3,
minor = 29,
patch = 0,
type = FirmwareVersion.FirmwareType.Release,
)
private val walletFirmwareVersion = CardDTO.FirmwareVersion(
major = 4,
minor = 0,
patch = 0,
type = FirmwareVersion.FirmwareType.Release,
)
private val wallet2FirmwareVersion = CardDTO.FirmwareVersion(
major = 6,
minor = 33,
patch = 0,
type = FirmwareVersion.FirmwareType.Release,
)
fun create(cardConfig: CardConfig, derivedKeys: Map<KeyWalletPublicKey, ExtendedPublicKeysMap>): ScanResponse {
return ScanResponse(
card = CardDTO(
cardId = "NEVER-MIND",
batchId = "NEVER-MIND",
cardPublicKey = ByteArray(0),
firmwareVersion = when (cardConfig) {
is GenericCardConfig -> genericFirmwareVersion
MultiWalletCardConfig -> walletFirmwareVersion
Wallet2CardConfig -> wallet2FirmwareVersion
EdSingleCurrencyCardConfig -> genericFirmwareVersion
},
manufacturer = CardDTO.Manufacturer(name = "NEVER-MIND", manufactureDate = Date(), signature = null),
issuer = CardDTO.Issuer(name = "NEVER-MIND", publicKey = ByteArray(0)),
settings = CardDTO.Settings(
securityDelay = 0,
maxWalletsCount = 0,
isSettingAccessCodeAllowed = false,
isSettingPasscodeAllowed = false,
isResettingUserCodesAllowed = false,
isLinkedTerminalEnabled = false,
isBackupAllowed = cardConfig is MultiWalletCardConfig,
supportedEncryptionModes = listOf(),
isFilesAllowed = true,
isHDWalletAllowed = cardConfig is MultiWalletCardConfig,
isKeysImportAllowed = true,
),
userSettings = null,
linkedTerminalStatus = CardDTO.LinkedTerminalStatus.Current,
isAccessCodeSet = false,
isPasscodeSet = null,
supportedCurves = listOf(),
wallets = cardConfig.mandatoryCurves.map {
CardDTO.Wallet(
CardWallet(
publicKey = it.name.toByteArray(), // IMPORTANT: public key must equal to curve name
chainCode = null,
curve = it,
settings = createSettings(),
totalSignedHashes = null,
remainingSignatures = null,
index = 0,
isImported = true,
hasBackup = true,
derivedKeys = mapOf(),
),
)
},
attestation = Attestation(
cardKeyAttestation = Attestation.Status.Skipped,
walletKeysAttestation = Attestation.Status.Skipped,
firmwareAttestation = Attestation.Status.Skipped,
cardUniquenessAttestation = Attestation.Status.Skipped,
),
backupStatus = null,
),
productType = ProductType.Wallet2,
walletData = null,
derivedKeys = derivedKeys,
)
}
private fun createSettings(): CardWallet.Settings {
val constructor = CardWallet.Settings::class.java.declaredConstructors[0]
constructor.isAccessible = true
return constructor.newInstance(false) as CardWallet.Settings
}
}

View file

@ -0,0 +1,119 @@
package com.tangem.common.test.domain.token
import com.tangem.blockchain.common.Blockchain
import com.tangem.blockchain.common.FeePaidCurrency
import com.tangem.blockchain.common.Token
import com.tangem.blockchainsdk.utils.ExcludedBlockchains
import com.tangem.blockchainsdk.utils.toNetworkId
import com.tangem.common.test.domain.card.MockScanResponseFactory
import com.tangem.data.common.currency.CryptoCurrencyFactory
import com.tangem.data.common.currency.getNetworkDerivationPath
import com.tangem.data.common.currency.getNetworkStandardType
import com.tangem.domain.common.configs.GenericCardConfig
import com.tangem.domain.common.util.derivationStyleProvider
import com.tangem.domain.models.scan.ScanResponse
import com.tangem.domain.tokens.model.CryptoCurrency
import com.tangem.domain.tokens.model.Network
/**
[REDACTED_AUTHOR]
*/
class MockCryptoCurrencyFactory(private val scanResponse: ScanResponse = defaultScanResponse) {
private val factory = CryptoCurrencyFactory(excludedBlockchains = ExcludedBlockchains())
val cardano by lazy { createCoin(blockchain = Blockchain.Cardano) }
val chia by lazy { createCoin(Blockchain.Chia) }
val ethereum by lazy { createCoin(Blockchain.Ethereum) }
val chiaAndEthereum by lazy {
listOf(
createCoin(blockchain = Blockchain.Chia),
createCoin(blockchain = Blockchain.Ethereum),
)
}
val ethereumAndStellar by lazy {
listOf(
createCoin(blockchain = Blockchain.Ethereum),
createCoin(blockchain = Blockchain.Stellar),
)
}
val ethereumTokenWithBinanceDerivation by lazy {
listOf(
createCustomToken(blockchain = Blockchain.Ethereum, derivationBlockchain = Blockchain.Binance),
)
}
fun createCoin(blockchain: Blockchain): CryptoCurrency {
val network = Network(
id = Network.ID(blockchain.id),
backendId = blockchain.toNetworkId(),
name = blockchain.fullName,
isTestnet = blockchain.isTestnet(),
derivationPath = getNetworkDerivationPath(
blockchain = blockchain,
extraDerivationPath = null,
cardDerivationStyleProvider = scanResponse.derivationStyleProvider,
),
currencySymbol = blockchain.currency,
standardType = getNetworkStandardType(blockchain),
hasFiatFeeRate = blockchain.feePaidCurrency() !is FeePaidCurrency.FeeResource,
canHandleTokens = false,
transactionExtrasType = Network.TransactionExtrasType.NONE,
)
return factory.createCoin(network = network)
}
// Impossible to create custom token by CryptoCurrencyFactory because it works with URI under the hood
fun createCustomToken(blockchain: Blockchain, derivationBlockchain: Blockchain): CryptoCurrency {
return CryptoCurrency.Token(
id = CryptoCurrency.ID(
prefix = CryptoCurrency.ID.Prefix.TOKEN_PREFIX,
body = CryptoCurrency.ID.Body.NetworkId(blockchain.id),
suffix = CryptoCurrency.ID.Suffix.RawID(blockchain.id),
),
network = Network(
id = Network.ID(value = blockchain.id),
backendId = "NEVER-MIND",
name = blockchain.fullName,
currencySymbol = "NEVER-MIND",
derivationPath = Network.DerivationPath.Custom(
value = derivationBlockchain.derivationPath(
scanResponse.derivationStyleProvider.getDerivationStyle(),
)!!.rawPath,
),
isTestnet = false,
standardType = Network.StandardType.ERC20,
hasFiatFeeRate = true,
canHandleTokens = true,
transactionExtrasType = Network.TransactionExtrasType.NONE,
),
name = "NEVER-MIND",
symbol = "NEVER-MIND",
decimals = 8,
iconUrl = null,
isCustom = false,
contractAddress = "NEVER-MIND",
)
}
fun createToken(blockchain: Blockchain): CryptoCurrency {
return factory.createToken(
sdkToken = Token(symbol = "NEVER-MIND", contractAddress = "NEVER-MIND", decimals = 8),
blockchain = blockchain,
extraDerivationPath = null,
scanResponse = scanResponse,
)!!
}
private companion object {
val defaultScanResponse = MockScanResponseFactory.create(
cardConfig = GenericCardConfig(2),
derivedKeys = emptyMap(),
)
}
}

View file

@ -0,0 +1,20 @@
package com.tangem.common.test.utils
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.toList
import kotlinx.coroutines.launch
import kotlinx.coroutines.test.TestCoroutineScheduler
import kotlinx.coroutines.test.UnconfinedTestDispatcher
@OptIn(ExperimentalCoroutinesApi::class)
fun <T> CoroutineScope.getEmittedValues(testScheduler: TestCoroutineScheduler, actual: Flow<T>): List<T> {
val values = mutableListOf<T>()
launch(UnconfinedTestDispatcher(testScheduler)) {
actual.toList(values)
}
return values
}