Updated on 2026-08-14

This commit is contained in:
Tangem 2025-06-10 12:10:53 +04:00
parent bfd371bc33
commit c9e78f485d
10 changed files with 164 additions and 47 deletions

View file

@ -1,26 +0,0 @@
package com.tangem.data.quotes
import com.tangem.data.quotes.store.QuotesStatusesStore
import com.tangem.domain.models.currency.CryptoCurrency
import com.tangem.domain.quotes.QuotesRepositoryV2
import com.tangem.domain.tokens.model.QuoteStatus
import javax.inject.Inject
/**
* Default implementation of [QuotesRepositoryV2]
*
* @property quotesStore quotes store
*
[REDACTED_AUTHOR]
*/
internal class DefaultQuotesRepositoryV2 @Inject constructor(
private val quotesStore: QuotesStatusesStore,
) : QuotesRepositoryV2 {
override suspend fun getMultiQuoteSyncOrNull(currenciesIds: Set<CryptoCurrency.RawID>): Set<QuoteStatus>? {
return quotesStore.getAllSyncOrNull()?.mapTo(hashSetOf()) {
it.takeIf { it.rawCurrencyId in currenciesIds }
?: QuoteStatus(rawCurrencyId = it.rawCurrencyId)
}
}
}

View file

@ -4,7 +4,7 @@ import android.content.Context
import androidx.datastore.core.DataStoreFactory
import androidx.datastore.dataStoreFile
import com.squareup.moshi.Moshi
import com.tangem.data.quotes.DefaultQuotesRepositoryV2
import com.tangem.data.quotes.repository.DefaultQuotesRepository
import com.tangem.data.quotes.store.DefaultQuotesStatusesStore
import com.tangem.data.quotes.store.QuotesStatusesStore
import com.tangem.datasource.api.tangemTech.models.QuotesResponse
@ -12,7 +12,7 @@ import com.tangem.datasource.di.NetworkMoshi
import com.tangem.datasource.local.datastore.RuntimeSharedStore
import com.tangem.datasource.utils.MoshiDataStoreSerializer
import com.tangem.datasource.utils.mapWithStringKeyTypes
import com.tangem.domain.quotes.QuotesRepositoryV2
import com.tangem.domain.quotes.QuotesRepository
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
import dagger.Module
import dagger.Provides
@ -51,5 +51,5 @@ internal object QuotesDataModule {
@Singleton
@Provides
fun providesQuotesRepositoryV2(impl: DefaultQuotesRepositoryV2): QuotesRepositoryV2 = impl
fun providesQuotesRepository(impl: DefaultQuotesRepository): QuotesRepository = impl
}

View file

@ -0,0 +1,35 @@
package com.tangem.data.quotes.repository
import com.tangem.data.quotes.store.QuotesStatusesStore
import com.tangem.domain.models.currency.CryptoCurrency
import com.tangem.domain.quotes.QuotesRepository
import com.tangem.domain.tokens.model.QuoteStatus
import timber.log.Timber
import javax.inject.Inject
/**
* Default implementation of [QuotesRepository]
*
* @property quotesStatusesStore quotes statuses store
*
[REDACTED_AUTHOR]
*/
internal class DefaultQuotesRepository @Inject constructor(
private val quotesStatusesStore: QuotesStatusesStore,
) : QuotesRepository {
override suspend fun getMultiQuoteSyncOrNull(currenciesIds: Set<CryptoCurrency.RawID>): Set<QuoteStatus> {
if (currenciesIds.isEmpty()) {
Timber.e("currenciesIds are empty")
return emptySet()
}
val storedQuotes = quotesStatusesStore.getAllSyncOrNull()
?.filter { it.rawCurrencyId in currenciesIds }
return currenciesIds.mapTo(hashSetOf()) { currencyId ->
storedQuotes?.firstOrNull { it.rawCurrencyId == currencyId }
?: QuoteStatus(rawCurrencyId = currencyId)
}
}
}

View file

@ -0,0 +1,108 @@
package com.tangem.data.quotes.repository
import com.google.common.truth.Truth
import com.tangem.common.test.utils.ProvideTestModels
import com.tangem.data.quotes.store.QuotesStatusesStore
import com.tangem.domain.models.StatusSource
import com.tangem.domain.models.currency.CryptoCurrency
import com.tangem.domain.quotes.QuotesRepository
import com.tangem.domain.tokens.model.QuoteStatus
import io.mockk.clearMocks
import io.mockk.coEvery
import io.mockk.mockk
import kotlinx.coroutines.test.runTest
import org.junit.jupiter.api.BeforeEach
import org.junit.jupiter.api.Nested
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 DefaultQuotesRepositoryTest {
private val quotesStatusesStore = mockk<QuotesStatusesStore>()
private val repository: QuotesRepository = DefaultQuotesRepository(quotesStatusesStore = quotesStatusesStore)
@BeforeEach
fun resetMocks() {
clearMocks(quotesStatusesStore)
}
@Nested
@TestInstance(TestInstance.Lifecycle.PER_CLASS)
inner class GetMultiQuoteSyncOrNull {
private val btcRawId = CryptoCurrency.RawID(value = "BTC")
private val ethRawId = CryptoCurrency.RawID(value = "ETH")
private val ethQuote = QuoteStatus(
rawCurrencyId = ethRawId,
value = QuoteStatus.Data(
source = StatusSource.ACTUAL,
fiatRate = BigDecimal.ZERO,
priceChange = BigDecimal.ZERO,
),
)
@ParameterizedTest
@ProvideTestModels
fun getMultiQuoteSyncOrNull(model: GetMultiQuoteSyncOrNullModel) = runTest {
// Arrange
coEvery { quotesStatusesStore.getAllSyncOrNull() } returns model.initialStore
// Act
val actual = repository.getMultiQuoteSyncOrNull(currenciesIds = model.currencyIds)
// Assert
val expected = model.expected
Truth.assertThat(actual).isEqualTo(expected)
}
private fun provideTestModels() = listOf(
GetMultiQuoteSyncOrNullModel(
initialStore = null,
currencyIds = emptySet(),
expected = emptySet(),
),
GetMultiQuoteSyncOrNullModel(
initialStore = null,
currencyIds = setOf(ethRawId),
expected = setOf(QuoteStatus(rawCurrencyId = ethRawId)),
),
GetMultiQuoteSyncOrNullModel(
initialStore = emptySet(),
currencyIds = emptySet(),
expected = emptySet(),
),
GetMultiQuoteSyncOrNullModel(
initialStore = emptySet(),
currencyIds = setOf(ethRawId),
expected = setOf(QuoteStatus(rawCurrencyId = ethRawId)),
),
GetMultiQuoteSyncOrNullModel(
initialStore = setOf(ethQuote),
currencyIds = setOf(ethRawId),
expected = setOf(ethQuote),
),
GetMultiQuoteSyncOrNullModel(
initialStore = setOf(QuoteStatus(rawCurrencyId = btcRawId)),
currencyIds = setOf(ethRawId),
expected = setOf(QuoteStatus(rawCurrencyId = ethRawId)),
),
GetMultiQuoteSyncOrNullModel(
initialStore = setOf(ethQuote, QuoteStatus(rawCurrencyId = btcRawId)),
currencyIds = setOf(ethRawId),
expected = setOf(ethQuote),
),
)
}
data class GetMultiQuoteSyncOrNullModel(
val initialStore: Set<QuoteStatus>?,
val currencyIds: Set<CryptoCurrency.RawID>,
val expected: Set<QuoteStatus>?,
)
}