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

@ -0,0 +1,33 @@
package com.tangem.data.quotes.converter
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 com.tangem.utils.converter.Converter
import com.tangem.utils.extensions.orZero
/**
* Converter from [QuotesResponse.Quote] to [QuoteStatus]
*
* @property source status source
*
[REDACTED_AUTHOR]
*/
internal class QuoteStatusConverter(
private val source: StatusSource,
) : Converter<Map.Entry<String, QuotesResponse.Quote>, QuoteStatus> {
override fun convert(value: Map.Entry<String, QuotesResponse.Quote>): QuoteStatus {
val (currencyId, quote) = value
return QuoteStatus(
rawCurrencyId = CryptoCurrency.RawID(currencyId),
value = QuoteStatus.Data(
source = source,
fiatRate = quote.price.orZero(),
priceChange = quote.priceChange24h.orZero().movePointLeft(2),
),
)
}
}

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,
)
}