Updated on 2026-08-14

This commit is contained in:
Tangem 2025-06-13 12:24:35 +04:00
parent 45bd51c738
commit 717b8e2df2
4 changed files with 134 additions and 17 deletions

View file

@ -1,14 +1,22 @@
package com.tangem.common.test.data.quote
import com.tangem.datasource.api.tangemTech.models.QuotesResponse
import com.tangem.datasource.local.quote.converter.QuoteStatusConverter
import com.tangem.domain.models.StatusSource
import com.tangem.domain.models.currency.CryptoCurrency
import com.tangem.domain.models.quote.QuoteStatus
import com.tangem.utils.extensions.orZero
fun QuotesResponse.Quote.toDomain(rawCurrencyId: String, source: StatusSource = StatusSource.ACTUAL): QuoteStatus {
return QuoteStatusConverter(source = source).convert(value = mapOf(rawCurrencyId to this).entries.first())
return QuoteStatus(
rawCurrencyId = CryptoCurrency.RawID(rawCurrencyId),
value = QuoteStatus.Data(
source = source,
fiatRate = price.orZero(),
priceChange = priceChange24h.orZero().movePointLeft(2),
),
)
}
fun Pair<String, QuotesResponse.Quote>.toDomain(source: StatusSource = StatusSource.ACTUAL): QuoteStatus {
return QuoteStatusConverter(source = source).convert(value = mapOf(this).entries.first())
return second.toDomain(rawCurrencyId = first, source = source)
}

View file

@ -1,4 +1,4 @@
package com.tangem.datasource.local.quote.converter
package com.tangem.data.quotes.converter
import com.tangem.datasource.api.tangemTech.models.QuotesResponse
import com.tangem.domain.models.StatusSource
@ -14,19 +14,10 @@ import com.tangem.utils.extensions.orZero
*
[REDACTED_AUTHOR]
*/
class QuoteStatusConverter(
internal class QuoteStatusConverter(
private val source: StatusSource,
) : Converter<Map.Entry<String, QuotesResponse.Quote>, QuoteStatus> {
/**
* Secondary constructor
*
* @param isCached flag that determines whether the quote is a cache
*/
constructor(isCached: Boolean) : this(
source = if (isCached) StatusSource.CACHE else StatusSource.ACTUAL,
)
override fun convert(value: Map.Entry<String, QuotesResponse.Quote>): QuoteStatus {
val (currencyId, quote) = value

View file

@ -1,9 +1,9 @@
package com.tangem.data.quotes.store
import androidx.datastore.core.DataStore
import com.tangem.data.quotes.converter.QuoteStatusConverter
import com.tangem.datasource.api.tangemTech.models.QuotesResponse
import com.tangem.datasource.local.datastore.RuntimeSharedStore
import com.tangem.datasource.local.quote.converter.QuoteStatusConverter
import com.tangem.domain.models.StatusSource
import com.tangem.domain.models.currency.CryptoCurrency
import com.tangem.domain.models.quote.QuoteStatus
@ -41,7 +41,7 @@ internal class DefaultQuotesStatusesStore(
if (cachedStatuses.isNullOrEmpty()) return@launch
runtimeStore.store(
value = QuoteStatusConverter(isCached = true).convertSet(input = cachedStatuses.entries),
value = QuoteStatusConverter(source = StatusSource.CACHE).convertSet(input = cachedStatuses.entries),
)
}
}
@ -95,7 +95,7 @@ internal class DefaultQuotesStatusesStore(
}
private suspend fun storeInRuntime(values: CurrencyIdWithQuote) {
val quotes = QuoteStatusConverter(isCached = false).convertSet(input = values.entries)
val quotes = QuoteStatusConverter(source = StatusSource.ACTUAL).convertSet(input = values.entries)
runtimeStore.update(default = emptySet()) { saved ->
saved.addOrReplace(items = quotes) { prev, new -> prev.rawCurrencyId == new.rawCurrencyId }

View file

@ -0,0 +1,118 @@
package com.tangem.data.quotes.converter
import com.google.common.truth.Truth
import com.tangem.common.test.data.quote.MockQuoteResponseFactory
import com.tangem.common.test.data.quote.toDomain
import com.tangem.common.test.utils.ProvideTestModels
import com.tangem.datasource.api.tangemTech.models.QuotesResponse
import com.tangem.domain.models.StatusSource
import com.tangem.domain.models.currency.CryptoCurrency
import com.tangem.domain.models.quote.QuoteStatus
import org.junit.jupiter.api.TestInstance
import org.junit.jupiter.params.ParameterizedTest
import java.math.BigDecimal
/**
[REDACTED_AUTHOR]
*/
@TestInstance(TestInstance.Lifecycle.PER_CLASS)
internal class QuoteStatusConverterTest {
private val ethQuoteDM = "ETH" to MockQuoteResponseFactory.createSinglePrice(value = BigDecimal.ONE)
@ParameterizedTest
@ProvideTestModels
fun convert(model: ConvertTestModel) {
// Act
val actual = QuoteStatusConverter(source = model.source).convert(value = model.value)
// Assert
val expected = model.expected
Truth.assertThat(actual).isEqualTo(expected)
}
private fun provideTestModels() = listOf(
ConvertTestModel(
source = StatusSource.CACHE,
value = createEntry(value = ethQuoteDM),
expected = ethQuoteDM.toDomain(source = StatusSource.CACHE),
),
ConvertTestModel(
source = StatusSource.ONLY_CACHE,
value = createEntry(value = ethQuoteDM),
expected = ethQuoteDM.toDomain(source = StatusSource.ONLY_CACHE),
),
ConvertTestModel(
source = StatusSource.ACTUAL,
value = createEntry(value = ethQuoteDM),
expected = ethQuoteDM.toDomain(source = StatusSource.ACTUAL),
),
ConvertTestModel(
source = StatusSource.ACTUAL,
value = createEntry(
value = "ETH" to QuotesResponse.Quote(
price = null,
priceChange24h = null,
priceChange1w = null,
priceChange30d = null,
),
),
expected = QuoteStatus(
rawCurrencyId = CryptoCurrency.RawID("ETH"),
value = QuoteStatus.Data(
source = StatusSource.ACTUAL,
fiatRate = BigDecimal.ZERO,
priceChange = BigDecimal("0.00"),
),
),
),
ConvertTestModel(
source = StatusSource.ACTUAL,
value = createEntry(
value = "ETH" to QuotesResponse.Quote(
price = null,
priceChange24h = null,
priceChange1w = BigDecimal.ZERO,
priceChange30d = BigDecimal.ZERO,
),
),
expected = QuoteStatus(
rawCurrencyId = CryptoCurrency.RawID("ETH"),
value = QuoteStatus.Data(
source = StatusSource.ACTUAL,
fiatRate = BigDecimal.ZERO,
priceChange = BigDecimal("0.00"),
),
),
),
ConvertTestModel(
source = StatusSource.ACTUAL,
value = createEntry(
value = "ETH" to QuotesResponse.Quote(
price = BigDecimal.ONE,
priceChange24h = BigDecimal.ONE,
priceChange1w = null,
priceChange30d = null,
),
),
expected = QuoteStatus(
rawCurrencyId = CryptoCurrency.RawID("ETH"),
value = QuoteStatus.Data(
source = StatusSource.ACTUAL,
fiatRate = BigDecimal.ONE,
priceChange = BigDecimal("0.01"),
),
),
),
)
private fun createEntry(value: Pair<String, QuotesResponse.Quote>): Map.Entry<String, QuotesResponse.Quote> {
return mapOf(value).entries.first()
}
data class ConvertTestModel(
val source: StatusSource,
val value: Map.Entry<String, QuotesResponse.Quote>,
val expected: QuoteStatus,
)
}