Updated on 2026-08-14
This commit is contained in:
parent
774898f560
commit
4e05219c25
11 changed files with 579 additions and 243 deletions
|
|
@ -8,22 +8,27 @@ import com.tangem.domain.core.flow.FlowProducerTools
|
|||
import com.tangem.domain.models.TokensSortType
|
||||
import com.tangem.domain.models.wallet.UserWallet
|
||||
import com.tangem.domain.models.wallet.UserWalletId
|
||||
import app.cash.turbine.test
|
||||
import com.tangem.test.core.TestFlowProducerTools
|
||||
import com.tangem.test.core.getEmittedValues
|
||||
import com.tangem.utils.coroutines.TestingCoroutineDispatcherProvider
|
||||
import io.mockk.*
|
||||
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.flow.emptyFlow
|
||||
import kotlinx.coroutines.flow.filterNotNull
|
||||
import kotlinx.coroutines.flow.flowOf
|
||||
import kotlinx.coroutines.test.TestScope
|
||||
import kotlinx.coroutines.test.UnconfinedTestDispatcher
|
||||
import kotlinx.coroutines.test.runTest
|
||||
import org.junit.jupiter.api.AfterEach
|
||||
import org.junit.jupiter.api.Disabled
|
||||
import org.junit.jupiter.api.Test
|
||||
import org.junit.jupiter.api.TestInstance
|
||||
|
||||
/**
|
||||
[REDACTED_AUTHOR]
|
||||
*/
|
||||
@OptIn(ExperimentalCoroutinesApi::class)
|
||||
@Suppress("UnusedFlow")
|
||||
@TestInstance(TestInstance.Lifecycle.PER_CLASS)
|
||||
class DefaultMultiAccountListProducerTest {
|
||||
|
|
@ -40,6 +45,23 @@ class DefaultMultiAccountListProducerTest {
|
|||
dispatchers = TestingCoroutineDispatcherProvider(),
|
||||
)
|
||||
|
||||
private fun TestScope.createProducer(): DefaultMultiAccountListProducer {
|
||||
val testDispatcher = UnconfinedTestDispatcher(testScheduler)
|
||||
return DefaultMultiAccountListProducer(
|
||||
params = Unit,
|
||||
flowProducerTools = TestFlowProducerTools(scope = backgroundScope, dispatcher = testDispatcher),
|
||||
userWalletsListRepository = userWalletsListRepository,
|
||||
singleAccountListSupplier = singleAccountListSupplier,
|
||||
dispatchers = TestingCoroutineDispatcherProvider(
|
||||
main = testDispatcher,
|
||||
mainImmediate = testDispatcher,
|
||||
io = testDispatcher,
|
||||
default = testDispatcher,
|
||||
single = testDispatcher,
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
private val userWalletId = UserWalletId("011")
|
||||
private val userWallet = mockk<UserWallet> {
|
||||
every { this@mockk.walletId } returns userWalletId
|
||||
|
|
@ -144,7 +166,6 @@ class DefaultMultiAccountListProducerTest {
|
|||
}
|
||||
}
|
||||
|
||||
@Disabled
|
||||
@Test
|
||||
fun `flow returns empty list if factory throws exception`() = runTest {
|
||||
// Arrange
|
||||
|
|
@ -154,12 +175,12 @@ class DefaultMultiAccountListProducerTest {
|
|||
val exception = RuntimeException("Converter error")
|
||||
every { singleAccountListSupplier.invoke(userWalletId) } throws exception
|
||||
|
||||
// Act
|
||||
val actual = producer.produceWithFallback().let(::getEmittedValues)
|
||||
|
||||
// Assert
|
||||
val expected = emptyList<AccountList>()
|
||||
Truth.assertThat(actual).containsExactly(expected)
|
||||
// Act / Assert: the factory throws -> retryWhen emits the empty fallback.
|
||||
// Stop before the 2s retry fires so the upstream is collected exactly once.
|
||||
createProducer().produceWithFallback().test {
|
||||
Truth.assertThat(awaitItem()).isEqualTo(emptyList<AccountList>())
|
||||
cancelAndIgnoreRemainingEvents()
|
||||
}
|
||||
|
||||
coVerifySequence {
|
||||
userWalletsListRepository.load()
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
package com.tangem.data.networks.multi
|
||||
|
||||
import app.cash.turbine.test
|
||||
import com.google.common.truth.Truth
|
||||
import com.tangem.common.test.domain.card.MockScanResponseFactory
|
||||
import com.tangem.common.test.domain.network.MockNetworkStatusFactory
|
||||
|
|
@ -11,23 +12,28 @@ import com.tangem.data.networks.store.NetworksStatusesStore
|
|||
import com.tangem.data.networks.toSimple
|
||||
import com.tangem.domain.card.configs.GenericCardConfig
|
||||
import com.tangem.domain.common.wallets.UserWalletsListRepository
|
||||
import com.tangem.domain.common.wallets.getSyncOrNull
|
||||
import com.tangem.domain.core.flow.FlowProducerTools
|
||||
import com.tangem.domain.models.network.NetworkStatus
|
||||
import com.tangem.domain.networks.multi.MultiNetworkStatusProducer
|
||||
import com.tangem.test.core.TestFlowProducerTools
|
||||
import com.tangem.test.core.getEmittedValues
|
||||
import com.tangem.utils.coroutines.TestingCoroutineDispatcherProvider
|
||||
import io.mockk.*
|
||||
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
||||
import kotlinx.coroutines.flow.*
|
||||
import kotlinx.coroutines.test.TestScope
|
||||
import kotlinx.coroutines.test.UnconfinedTestDispatcher
|
||||
import kotlinx.coroutines.test.advanceTimeBy
|
||||
import kotlinx.coroutines.test.runCurrent
|
||||
import kotlinx.coroutines.test.runTest
|
||||
import org.junit.jupiter.api.BeforeEach
|
||||
import org.junit.jupiter.api.Disabled
|
||||
import org.junit.jupiter.api.Test
|
||||
import org.junit.jupiter.api.TestInstance
|
||||
|
||||
/**
|
||||
[REDACTED_AUTHOR]
|
||||
*/
|
||||
@OptIn(ExperimentalCoroutinesApi::class)
|
||||
@TestInstance(TestInstance.Lifecycle.PER_CLASS)
|
||||
internal class DefaultMultiNetworkStatusProducerTest {
|
||||
|
||||
|
|
@ -48,6 +54,24 @@ internal class DefaultMultiNetworkStatusProducerTest {
|
|||
flowProducerTools = flowProducerTools,
|
||||
)
|
||||
|
||||
private fun TestScope.createProducer(): DefaultMultiNetworkStatusProducer {
|
||||
val testDispatcher = UnconfinedTestDispatcher(testScheduler)
|
||||
return DefaultMultiNetworkStatusProducer(
|
||||
params = params,
|
||||
networksStatusesStore = networksStatusesStore,
|
||||
userWalletsListRepository = userWalletsListRepository,
|
||||
networkFactory = networkFactory,
|
||||
dispatchers = TestingCoroutineDispatcherProvider(
|
||||
main = testDispatcher,
|
||||
mainImmediate = testDispatcher,
|
||||
io = testDispatcher,
|
||||
default = testDispatcher,
|
||||
single = testDispatcher,
|
||||
),
|
||||
flowProducerTools = TestFlowProducerTools(scope = backgroundScope, dispatcher = testDispatcher),
|
||||
)
|
||||
}
|
||||
|
||||
@BeforeEach
|
||||
fun resetMocks() {
|
||||
clearMocks(networksStatusesStore, userWalletsListRepository, networkFactory)
|
||||
|
|
@ -294,7 +318,6 @@ internal class DefaultMultiNetworkStatusProducerTest {
|
|||
Truth.assertThat(actual2.first()).isEqualTo(expected2)
|
||||
}
|
||||
|
||||
@Disabled
|
||||
@Test
|
||||
fun `flow throws exception`() = runTest {
|
||||
// Arrange
|
||||
|
|
@ -338,30 +361,26 @@ internal class DefaultMultiNetworkStatusProducerTest {
|
|||
} returns statuses.last().network
|
||||
// endregion
|
||||
|
||||
val producerFlow = producer.produceWithFallback()
|
||||
val producerFlow = createProducer().produceWithFallback()
|
||||
|
||||
// Act 1 (fallback)
|
||||
val actual1 = getEmittedValues(flow = producerFlow)
|
||||
producerFlow.test {
|
||||
// first collection throws -> retryWhen emits the empty fallback, then waits 2s
|
||||
Truth.assertThat(awaitItem()).isEqualTo(emptySet<NetworkStatus>())
|
||||
|
||||
// Assert
|
||||
val expected1 = emptySet<NetworkStatus>()
|
||||
Truth.assertThat(actual1.size).isEqualTo(1)
|
||||
Truth.assertThat(actual1.first()).isEqualTo(expected1)
|
||||
verify(inverse = true) {
|
||||
networkFactory.create(networkId = any(), derivationPath = any(), userWallet = any())
|
||||
}
|
||||
|
||||
verifyOrder(inverse = true) {
|
||||
userWalletsListRepository.getSyncOrNull(any())
|
||||
networkFactory.create(networkId = any(), derivationPath = any(), userWallet = any())
|
||||
// recover the upstream and let the retry fire
|
||||
innerFlow.value = true
|
||||
advanceTimeBy(delayTimeMillis = 2001)
|
||||
runCurrent()
|
||||
|
||||
Truth.assertThat(awaitItem()).isEqualTo(statuses)
|
||||
|
||||
cancelAndIgnoreRemainingEvents()
|
||||
}
|
||||
|
||||
// Act 2 (emit)
|
||||
innerFlow.emit(value = true)
|
||||
val actual2 = getEmittedValues(flow = producerFlow)
|
||||
|
||||
// Assert
|
||||
val expected2 = statuses
|
||||
Truth.assertThat(actual2.size).isEqualTo(1)
|
||||
Truth.assertThat(actual2.first()).isEqualTo(expected2)
|
||||
|
||||
verifyOrder {
|
||||
userWalletsListRepository.userWallets
|
||||
networkFactory.create(
|
||||
|
|
|
|||
|
|
@ -1,27 +1,33 @@
|
|||
package com.tangem.data.networks.single
|
||||
|
||||
import app.cash.turbine.test
|
||||
import com.google.common.truth.Truth
|
||||
import com.tangem.common.test.domain.network.MockNetworkStatusFactory
|
||||
import com.tangem.common.test.domain.token.MockCryptoCurrencyFactory
|
||||
import com.tangem.domain.core.flow.FlowProducerTools
|
||||
import com.tangem.domain.models.network.NetworkStatus
|
||||
import com.tangem.domain.models.wallet.UserWalletId
|
||||
import com.tangem.domain.networks.multi.MultiNetworkStatusProducer
|
||||
import com.tangem.domain.networks.multi.MultiNetworkStatusSupplier
|
||||
import com.tangem.domain.networks.single.SingleNetworkStatusProducer
|
||||
import com.tangem.test.core.TestFlowProducerTools
|
||||
import com.tangem.test.core.getEmittedValues
|
||||
import com.tangem.utils.coroutines.TestingCoroutineDispatcherProvider
|
||||
import io.mockk.every
|
||||
import io.mockk.mockk
|
||||
import io.mockk.verify
|
||||
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
||||
import kotlinx.coroutines.flow.*
|
||||
import kotlinx.coroutines.test.TestScope
|
||||
import kotlinx.coroutines.test.UnconfinedTestDispatcher
|
||||
import kotlinx.coroutines.test.advanceTimeBy
|
||||
import kotlinx.coroutines.test.runCurrent
|
||||
import kotlinx.coroutines.test.runTest
|
||||
import org.junit.jupiter.api.Disabled
|
||||
import org.junit.jupiter.api.Test
|
||||
|
||||
/**
|
||||
[REDACTED_AUTHOR]
|
||||
*/
|
||||
@OptIn(ExperimentalCoroutinesApi::class)
|
||||
internal class DefaultSingleNetworkStatusProducerTest {
|
||||
|
||||
private val params = SingleNetworkStatusProducer.Params(
|
||||
|
|
@ -30,15 +36,22 @@ internal class DefaultSingleNetworkStatusProducerTest {
|
|||
)
|
||||
|
||||
private val multiNetworkStatusSupplier = mockk<MultiNetworkStatusSupplier>()
|
||||
private val dispatchers = TestingCoroutineDispatcherProvider()
|
||||
private val flowProducerTools: FlowProducerTools = mockk()
|
||||
|
||||
private val producer = DefaultSingleNetworkStatusProducer(
|
||||
params = params,
|
||||
multiNetworkStatusSupplier = multiNetworkStatusSupplier,
|
||||
dispatchers = dispatchers,
|
||||
flowProducerTools = flowProducerTools,
|
||||
)
|
||||
private fun TestScope.createProducer(): DefaultSingleNetworkStatusProducer {
|
||||
val testDispatcher = UnconfinedTestDispatcher(testScheduler)
|
||||
return DefaultSingleNetworkStatusProducer(
|
||||
params = params,
|
||||
multiNetworkStatusSupplier = multiNetworkStatusSupplier,
|
||||
dispatchers = TestingCoroutineDispatcherProvider(
|
||||
main = testDispatcher,
|
||||
mainImmediate = testDispatcher,
|
||||
io = testDispatcher,
|
||||
default = testDispatcher,
|
||||
single = testDispatcher,
|
||||
),
|
||||
flowProducerTools = TestFlowProducerTools(scope = backgroundScope, dispatcher = testDispatcher),
|
||||
)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `test that flow is mapped for network from params`() = runTest {
|
||||
|
|
@ -53,7 +66,7 @@ internal class DefaultSingleNetworkStatusProducerTest {
|
|||
val multiParams = MultiNetworkStatusProducer.Params(userWalletId = params.userWalletId)
|
||||
every { multiNetworkStatusSupplier(multiParams) } returns expected
|
||||
|
||||
val actual = producer.produce()
|
||||
val actual = createProducer().produce()
|
||||
|
||||
verify { multiNetworkStatusSupplier(multiParams) }
|
||||
|
||||
|
|
@ -63,11 +76,6 @@ internal class DefaultSingleNetworkStatusProducerTest {
|
|||
Truth.assertThat(values).isEqualTo(listOf(status))
|
||||
}
|
||||
|
||||
// TODO: rework for produceWithFallback() hot-SharedFlow semantics. These tests assert against
|
||||
// multiple cold collections, which is incompatible with shareIn(replay = 1) used in production.
|
||||
// Dormant under JUnit 4 (useJUnitPlatform without vintage); disabled to match
|
||||
// DefaultMultiNetworkStatusProducerTest.
|
||||
@Disabled("Needs rework for produceWithFallback() hot-SharedFlow semantics")
|
||||
@Test
|
||||
fun `test that flow is updated if network status is updated`() = runTest {
|
||||
val expected = MutableSharedFlow<Set<NetworkStatus>>(replay = 2, extraBufferCapacity = 1)
|
||||
|
|
@ -75,30 +83,23 @@ internal class DefaultSingleNetworkStatusProducerTest {
|
|||
val multiParams = MultiNetworkStatusProducer.Params(userWalletId = params.userWalletId)
|
||||
every { multiNetworkStatusSupplier(multiParams) } returns expected
|
||||
|
||||
val actual = producer.produceWithFallback()
|
||||
val actual = createProducer().produceWithFallback()
|
||||
|
||||
verify { multiNetworkStatusSupplier(multiParams) }
|
||||
|
||||
// first emit
|
||||
val status = MockNetworkStatusFactory.createMissedDerivation(params.network)
|
||||
expected.emit(value = setOf(status))
|
||||
actual.test {
|
||||
val status = MockNetworkStatusFactory.createMissedDerivation(params.network)
|
||||
expected.emit(value = setOf(status))
|
||||
Truth.assertThat(awaitItem()).isEqualTo(status)
|
||||
|
||||
val values1 = getEmittedValues(flow = actual)
|
||||
val updatedStatus = status.copy(value = NetworkStatus.Unreachable(null))
|
||||
expected.emit(value = setOf(updatedStatus))
|
||||
Truth.assertThat(awaitItem()).isEqualTo(updatedStatus)
|
||||
|
||||
Truth.assertThat(values1.size).isEqualTo(1)
|
||||
Truth.assertThat(values1).isEqualTo(listOf(status))
|
||||
|
||||
// second emit
|
||||
val updatedStatus = status.copy(value = NetworkStatus.Unreachable(null))
|
||||
expected.emit(value = setOf(updatedStatus))
|
||||
|
||||
val values2 = getEmittedValues(flow = actual)
|
||||
|
||||
Truth.assertThat(values2.size).isEqualTo(2)
|
||||
Truth.assertThat(values2).isEqualTo(listOf(status, updatedStatus))
|
||||
cancelAndIgnoreRemainingEvents()
|
||||
}
|
||||
}
|
||||
|
||||
@Disabled("Needs rework for produceWithFallback() hot-SharedFlow semantics")
|
||||
@Test
|
||||
fun `test that flow is filtered the same status`() = runTest {
|
||||
val expected = MutableSharedFlow<Set<NetworkStatus>>(replay = 2, extraBufferCapacity = 1)
|
||||
|
|
@ -106,29 +107,23 @@ internal class DefaultSingleNetworkStatusProducerTest {
|
|||
val multiParams = MultiNetworkStatusProducer.Params(userWalletId = params.userWalletId)
|
||||
every { multiNetworkStatusSupplier(multiParams) } returns expected
|
||||
|
||||
val actual = producer.produceWithFallback()
|
||||
val actual = createProducer().produceWithFallback()
|
||||
|
||||
verify { multiNetworkStatusSupplier(multiParams) }
|
||||
|
||||
// first emit
|
||||
val status = MockNetworkStatusFactory.createMissedDerivation(params.network)
|
||||
expected.emit(value = setOf(status))
|
||||
actual.test {
|
||||
val status = MockNetworkStatusFactory.createMissedDerivation(params.network)
|
||||
expected.emit(value = setOf(status))
|
||||
Truth.assertThat(awaitItem()).isEqualTo(status)
|
||||
|
||||
val values1 = getEmittedValues(flow = actual)
|
||||
// same status again -> filtered out by distinctUntilChanged
|
||||
expected.emit(value = setOf(status))
|
||||
expectNoEvents()
|
||||
|
||||
Truth.assertThat(values1.size).isEqualTo(1)
|
||||
Truth.assertThat(values1).isEqualTo(listOf(status))
|
||||
|
||||
// second emit
|
||||
expected.emit(value = setOf(status))
|
||||
|
||||
val values2 = getEmittedValues(flow = actual)
|
||||
|
||||
Truth.assertThat(values2.size).isEqualTo(1)
|
||||
Truth.assertThat(values2).isEqualTo(listOf(status))
|
||||
cancelAndIgnoreRemainingEvents()
|
||||
}
|
||||
}
|
||||
|
||||
@Disabled("Needs rework for produceWithFallback() infinite retryWhen + delay under virtual time")
|
||||
@Test
|
||||
fun `test if flow throws exception`() = runTest {
|
||||
val exception = IllegalStateException()
|
||||
|
|
@ -147,21 +142,24 @@ internal class DefaultSingleNetworkStatusProducerTest {
|
|||
val multiParams = MultiNetworkStatusProducer.Params(userWalletId = params.userWalletId)
|
||||
every { multiNetworkStatusSupplier(multiParams) } returns expected
|
||||
|
||||
val actual = producer.produceWithFallback()
|
||||
val actual = createProducer().produceWithFallback()
|
||||
|
||||
verify { multiNetworkStatusSupplier(multiParams) }
|
||||
|
||||
val values1 = getEmittedValues(flow = actual)
|
||||
actual.test {
|
||||
// first collection throws -> retryWhen emits the fallback, then waits 2s before retrying
|
||||
val fallbackStatus = MockNetworkStatusFactory.createUnreachable(params.network)
|
||||
Truth.assertThat(awaitItem()).isEqualTo(fallbackStatus)
|
||||
|
||||
Truth.assertThat(values1.size).isEqualTo(1)
|
||||
val fallbackStatus = MockNetworkStatusFactory.createUnreachable(params.network)
|
||||
Truth.assertThat(values1).isEqualTo(listOf(fallbackStatus))
|
||||
// recover the upstream and let the retry fire
|
||||
innerFlow.value = true
|
||||
advanceTimeBy(delayTimeMillis = 2001)
|
||||
runCurrent()
|
||||
|
||||
innerFlow.emit(value = true)
|
||||
Truth.assertThat(awaitItem()).isEqualTo(status)
|
||||
|
||||
val values2 = getEmittedValues(flow = actual)
|
||||
Truth.assertThat(values2.size).isEqualTo(1)
|
||||
Truth.assertThat(values2).isEqualTo(listOf(status))
|
||||
cancelAndIgnoreRemainingEvents()
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
|
|
@ -173,7 +171,7 @@ internal class DefaultSingleNetworkStatusProducerTest {
|
|||
val multiParams = MultiNetworkStatusProducer.Params(userWalletId = params.userWalletId)
|
||||
every { multiNetworkStatusSupplier(multiParams) } returns expected
|
||||
|
||||
val actual = producer.produce()
|
||||
val actual = createProducer().produce()
|
||||
|
||||
verify { multiNetworkStatusSupplier(multiParams) }
|
||||
|
||||
|
|
|
|||
|
|
@ -1,26 +1,32 @@
|
|||
package com.tangem.data.quotes.single
|
||||
|
||||
import app.cash.turbine.test
|
||||
import com.google.common.truth.Truth
|
||||
import com.tangem.data.quotes.store.QuotesStatusesStore
|
||||
import com.tangem.domain.core.flow.FlowProducerTools
|
||||
import com.tangem.domain.models.StatusSource
|
||||
import com.tangem.domain.models.currency.CryptoCurrency
|
||||
import com.tangem.domain.models.quote.QuoteStatus
|
||||
import com.tangem.domain.quotes.single.SingleQuoteStatusProducer
|
||||
import com.tangem.test.core.TestFlowProducerTools
|
||||
import com.tangem.test.core.getEmittedValues
|
||||
import com.tangem.utils.coroutines.TestingCoroutineDispatcherProvider
|
||||
import io.mockk.every
|
||||
import io.mockk.mockk
|
||||
import io.mockk.verify
|
||||
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
||||
import kotlinx.coroutines.flow.*
|
||||
import kotlinx.coroutines.test.TestScope
|
||||
import kotlinx.coroutines.test.UnconfinedTestDispatcher
|
||||
import kotlinx.coroutines.test.advanceTimeBy
|
||||
import kotlinx.coroutines.test.runCurrent
|
||||
import kotlinx.coroutines.test.runTest
|
||||
import org.junit.jupiter.api.Disabled
|
||||
import org.junit.jupiter.api.Test
|
||||
import java.math.BigDecimal
|
||||
|
||||
/**
|
||||
[REDACTED_AUTHOR]
|
||||
*/
|
||||
@OptIn(ExperimentalCoroutinesApi::class)
|
||||
internal class DefaultSingleQuoteStatusProducerTest {
|
||||
|
||||
private val params = SingleQuoteStatusProducer.Params(
|
||||
|
|
@ -28,14 +34,22 @@ internal class DefaultSingleQuoteStatusProducerTest {
|
|||
)
|
||||
|
||||
private val quotesStore = mockk<QuotesStatusesStore>()
|
||||
private val flowProducerTools: FlowProducerTools = mockk()
|
||||
|
||||
private val producer = DefaultSingleQuoteStatusProducer(
|
||||
params = params,
|
||||
quotesStatusesStore = quotesStore,
|
||||
flowProducerTools = flowProducerTools,
|
||||
dispatchers = TestingCoroutineDispatcherProvider(),
|
||||
)
|
||||
private fun TestScope.createProducer(): DefaultSingleQuoteStatusProducer {
|
||||
val testDispatcher = UnconfinedTestDispatcher(testScheduler)
|
||||
return DefaultSingleQuoteStatusProducer(
|
||||
params = params,
|
||||
quotesStatusesStore = quotesStore,
|
||||
flowProducerTools = TestFlowProducerTools(scope = backgroundScope, dispatcher = testDispatcher),
|
||||
dispatchers = TestingCoroutineDispatcherProvider(
|
||||
main = testDispatcher,
|
||||
mainImmediate = testDispatcher,
|
||||
io = testDispatcher,
|
||||
default = testDispatcher,
|
||||
single = testDispatcher,
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `test that flow is mapped for network from params`() = runTest {
|
||||
|
|
@ -49,7 +63,7 @@ internal class DefaultSingleQuoteStatusProducerTest {
|
|||
|
||||
every { quotesStore.get() } returns storeQuote
|
||||
|
||||
val actual = producer.produce()
|
||||
val actual = createProducer().produce()
|
||||
|
||||
verify { quotesStore.get() }
|
||||
|
||||
|
|
@ -59,74 +73,60 @@ internal class DefaultSingleQuoteStatusProducerTest {
|
|||
Truth.assertThat(values).isEqualTo(listOf(status))
|
||||
}
|
||||
|
||||
@Disabled("Needs rework for produceWithFallback() hot-SharedFlow semantics")
|
||||
@Test
|
||||
fun `test that flow is updated if quote is updated`() = runTest {
|
||||
val storeQuote = MutableSharedFlow<Set<QuoteStatus>>(replay = 2, extraBufferCapacity = 1)
|
||||
|
||||
every { quotesStore.get() } returns storeQuote
|
||||
|
||||
val actual = producer.produceWithFallback()
|
||||
val actual = createProducer().produceWithFallback()
|
||||
|
||||
verify { quotesStore.get() }
|
||||
|
||||
// first emit
|
||||
val status = QuoteStatus(rawCurrencyId = params.rawCurrencyId)
|
||||
storeQuote.emit(value = setOf(status))
|
||||
actual.test {
|
||||
val status = QuoteStatus(rawCurrencyId = params.rawCurrencyId)
|
||||
storeQuote.emit(value = setOf(status))
|
||||
Truth.assertThat(awaitItem()).isEqualTo(status)
|
||||
|
||||
val values1 = getEmittedValues(flow = actual)
|
||||
val updatedStatus = QuoteStatus(
|
||||
rawCurrencyId = params.rawCurrencyId,
|
||||
value = QuoteStatus.Data(
|
||||
fiatRate = BigDecimal.ONE,
|
||||
priceChange = BigDecimal.ZERO,
|
||||
fiatRateUSD = BigDecimal.ZERO,
|
||||
source = StatusSource.ACTUAL,
|
||||
),
|
||||
)
|
||||
storeQuote.emit(value = setOf(updatedStatus))
|
||||
Truth.assertThat(awaitItem()).isEqualTo(updatedStatus)
|
||||
|
||||
Truth.assertThat(values1.size).isEqualTo(1)
|
||||
Truth.assertThat(values1).isEqualTo(listOf(status))
|
||||
|
||||
// second emit
|
||||
val updatedStatus = QuoteStatus(
|
||||
rawCurrencyId = params.rawCurrencyId,
|
||||
value = QuoteStatus.Data(
|
||||
fiatRate = BigDecimal.ONE,
|
||||
priceChange = BigDecimal.ZERO,
|
||||
fiatRateUSD = BigDecimal.ZERO,
|
||||
source = StatusSource.ACTUAL,
|
||||
),
|
||||
)
|
||||
storeQuote.emit(value = setOf(updatedStatus))
|
||||
|
||||
val values2 = getEmittedValues(flow = actual)
|
||||
|
||||
Truth.assertThat(values2.size).isEqualTo(2)
|
||||
Truth.assertThat(values2).isEqualTo(listOf(status, updatedStatus))
|
||||
cancelAndIgnoreRemainingEvents()
|
||||
}
|
||||
}
|
||||
|
||||
@Disabled("Needs rework for produceWithFallback() hot-SharedFlow semantics")
|
||||
@Test
|
||||
fun `test that flow is filtered the same status`() = runTest {
|
||||
val storeQuote = MutableSharedFlow<Set<QuoteStatus>>(replay = 2, extraBufferCapacity = 1)
|
||||
|
||||
every { quotesStore.get() } returns storeQuote
|
||||
|
||||
val actual = producer.produceWithFallback()
|
||||
val actual = createProducer().produceWithFallback()
|
||||
|
||||
verify { quotesStore.get() }
|
||||
|
||||
// first emit
|
||||
val status = QuoteStatus(rawCurrencyId = params.rawCurrencyId)
|
||||
storeQuote.emit(value = setOf(status))
|
||||
actual.test {
|
||||
val status = QuoteStatus(rawCurrencyId = params.rawCurrencyId)
|
||||
storeQuote.emit(value = setOf(status))
|
||||
Truth.assertThat(awaitItem()).isEqualTo(status)
|
||||
|
||||
val values1 = getEmittedValues(flow = actual)
|
||||
// same status again -> filtered out by distinctUntilChanged
|
||||
storeQuote.emit(value = setOf(status))
|
||||
expectNoEvents()
|
||||
|
||||
Truth.assertThat(values1.size).isEqualTo(1)
|
||||
Truth.assertThat(values1).isEqualTo(listOf(status))
|
||||
|
||||
// second emit
|
||||
storeQuote.emit(value = setOf(status))
|
||||
|
||||
val values2 = getEmittedValues(flow = actual)
|
||||
|
||||
Truth.assertThat(values2.size).isEqualTo(1)
|
||||
Truth.assertThat(values2).isEqualTo(listOf(status))
|
||||
cancelAndIgnoreRemainingEvents()
|
||||
}
|
||||
}
|
||||
|
||||
@Disabled("Needs rework for produceWithFallback() infinite retryWhen + delay under virtual time")
|
||||
@Test
|
||||
fun `test if flow throws exception`() = runTest {
|
||||
val exception = IllegalStateException()
|
||||
|
|
@ -152,24 +152,24 @@ internal class DefaultSingleQuoteStatusProducerTest {
|
|||
|
||||
every { quotesStore.get() } returns storeQuote
|
||||
|
||||
val actual = producer.produceWithFallback()
|
||||
val actual = createProducer().produceWithFallback()
|
||||
|
||||
verify { quotesStore.get() }
|
||||
|
||||
val values1 = getEmittedValues(flow = actual)
|
||||
actual.test {
|
||||
val fallbackStatus = QuoteStatus(rawCurrencyId = params.rawCurrencyId)
|
||||
Truth.assertThat(awaitItem()).isEqualTo(fallbackStatus)
|
||||
|
||||
Truth.assertThat(values1.size).isEqualTo(1)
|
||||
val fallbackStatus = QuoteStatus(rawCurrencyId = params.rawCurrencyId)
|
||||
Truth.assertThat(values1).isEqualTo(listOf(fallbackStatus))
|
||||
innerFlow.value = true
|
||||
advanceTimeBy(delayTimeMillis = 2001)
|
||||
runCurrent()
|
||||
|
||||
innerFlow.emit(value = true)
|
||||
Truth.assertThat(awaitItem()).isEqualTo(status)
|
||||
|
||||
val values2 = getEmittedValues(flow = actual)
|
||||
Truth.assertThat(values2.size).isEqualTo(1)
|
||||
Truth.assertThat(values2).isEqualTo(listOf(status))
|
||||
cancelAndIgnoreRemainingEvents()
|
||||
}
|
||||
}
|
||||
|
||||
@Disabled("Needs rework for produceWithFallback() hot-SharedFlow semantics")
|
||||
@Test
|
||||
fun `test if flow doesn't contain network from params`() = runTest {
|
||||
val storeFlow = flowOf(
|
||||
|
|
@ -180,12 +180,14 @@ internal class DefaultSingleQuoteStatusProducerTest {
|
|||
|
||||
every { quotesStore.get() } returns storeFlow
|
||||
|
||||
val actual = producer.produceWithFallback()
|
||||
val actual = createProducer().produceWithFallback()
|
||||
|
||||
verify { quotesStore.get() }
|
||||
|
||||
val values = getEmittedValues(flow = actual)
|
||||
|
||||
Truth.assertThat(values.size).isEqualTo(0)
|
||||
actual.test {
|
||||
// params currency (BTC) is not in the store -> nothing is emitted
|
||||
expectNoEvents()
|
||||
cancelAndIgnoreRemainingEvents()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -12,19 +12,26 @@ import com.tangem.domain.models.staking.*
|
|||
import com.tangem.domain.models.wallet.UserWalletId
|
||||
import com.tangem.domain.staking.model.StakingIntegrationID
|
||||
import com.tangem.domain.staking.multi.MultiStakingBalanceProducer
|
||||
import app.cash.turbine.test
|
||||
import com.tangem.test.core.TestFlowProducerTools
|
||||
import com.tangem.test.core.getEmittedValues
|
||||
import com.tangem.utils.coroutines.TestingCoroutineDispatcherProvider
|
||||
import io.mockk.every
|
||||
import io.mockk.mockk
|
||||
import io.mockk.verify
|
||||
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
||||
import kotlinx.coroutines.flow.*
|
||||
import kotlinx.coroutines.test.TestScope
|
||||
import kotlinx.coroutines.test.UnconfinedTestDispatcher
|
||||
import kotlinx.coroutines.test.advanceTimeBy
|
||||
import kotlinx.coroutines.test.runCurrent
|
||||
import kotlinx.coroutines.test.runTest
|
||||
import org.junit.jupiter.api.Disabled
|
||||
import org.junit.jupiter.api.Test
|
||||
|
||||
/**
|
||||
[REDACTED_AUTHOR]
|
||||
*/
|
||||
@OptIn(ExperimentalCoroutinesApi::class)
|
||||
internal class DefaultMultiStakingBalanceProducerTest {
|
||||
|
||||
private val params = MultiStakingBalanceProducer.Params(userWalletId = UserWalletId("011"))
|
||||
|
|
@ -42,6 +49,25 @@ internal class DefaultMultiStakingBalanceProducerTest {
|
|||
dispatchers = dispatchers,
|
||||
)
|
||||
|
||||
// Producer wired with a real test FlowProducerTools (shareIn + retry + distinctUntilChanged)
|
||||
// for produceWithFallback() cases.
|
||||
private fun TestScope.createProducer(): DefaultMultiStakingBalanceProducer {
|
||||
val testDispatcher = UnconfinedTestDispatcher(testScheduler)
|
||||
return DefaultMultiStakingBalanceProducer(
|
||||
params = params,
|
||||
stakeKitBalancesStore = stakeKitBalancesStore,
|
||||
p2PEthPoolBalancesStore = p2PEthPoolBalancesStore,
|
||||
flowProducerTools = TestFlowProducerTools(scope = backgroundScope, dispatcher = testDispatcher),
|
||||
dispatchers = TestingCoroutineDispatcherProvider(
|
||||
main = testDispatcher,
|
||||
mainImmediate = testDispatcher,
|
||||
io = testDispatcher,
|
||||
default = testDispatcher,
|
||||
single = testDispatcher,
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `test that flow is mapped for user wallet id from params`() = runTest {
|
||||
val balances = setOf(
|
||||
|
|
@ -107,7 +133,6 @@ internal class DefaultMultiStakingBalanceProducerTest {
|
|||
Truth.assertThat(values2).isEqualTo(expected)
|
||||
}
|
||||
|
||||
@Disabled("Needs rework: distinctUntilChanged moved into produceWithFallback()/shareInProducer")
|
||||
@Test
|
||||
fun `test that flow is filtered the same balance`() = runTest {
|
||||
val networksStatusesFlow = MutableSharedFlow<Set<StakingBalance>>(replay = 2)
|
||||
|
|
@ -115,35 +140,28 @@ internal class DefaultMultiStakingBalanceProducerTest {
|
|||
every { stakeKitBalancesStore.get(params.userWalletId) } returns networksStatusesFlow
|
||||
every { p2PEthPoolBalancesStore.get(params.userWalletId) } returns flowOf(emptySet())
|
||||
|
||||
val actual = producer.produce()
|
||||
val actual = createProducer().produceWithFallback()
|
||||
|
||||
// check after producer.produce()
|
||||
verify { stakeKitBalancesStore.get(params.userWalletId) }
|
||||
verify { p2PEthPoolBalancesStore.get(params.userWalletId) }
|
||||
|
||||
// first emit
|
||||
val wrappers = setOf(
|
||||
MockYieldBalanceWrapperDTOFactory.createWithEmptyBalance(tonId).toDomain(),
|
||||
MockYieldBalanceWrapperDTOFactory.createWithEmptyBalance(solanaId).toDomain(),
|
||||
)
|
||||
actual.test {
|
||||
val wrappers = setOf(
|
||||
MockYieldBalanceWrapperDTOFactory.createWithEmptyBalance(tonId).toDomain(),
|
||||
MockYieldBalanceWrapperDTOFactory.createWithEmptyBalance(solanaId).toDomain(),
|
||||
)
|
||||
|
||||
networksStatusesFlow.emit(wrappers)
|
||||
networksStatusesFlow.emit(wrappers)
|
||||
Truth.assertThat(awaitItem()).isEqualTo(wrappers)
|
||||
|
||||
val values1 = getEmittedValues(flow = actual)
|
||||
// same balances again -> filtered out by distinctUntilChanged
|
||||
networksStatusesFlow.emit(wrappers)
|
||||
expectNoEvents()
|
||||
|
||||
Truth.assertThat(values1.size).isEqualTo(1)
|
||||
Truth.assertThat(values1.first()).isEqualTo(wrappers)
|
||||
|
||||
// second emit
|
||||
networksStatusesFlow.emit(wrappers)
|
||||
|
||||
val values2 = getEmittedValues(flow = actual)
|
||||
|
||||
Truth.assertThat(values2.size).isEqualTo(1)
|
||||
Truth.assertThat(values2.first()).isEqualTo(wrappers)
|
||||
cancelAndIgnoreRemainingEvents()
|
||||
}
|
||||
}
|
||||
|
||||
@Disabled("Needs rework for produceWithFallback() infinite retryWhen + delay under virtual time")
|
||||
@Test
|
||||
fun `test if flow throws exception`() = runTest {
|
||||
val exception = IllegalStateException()
|
||||
|
|
@ -165,23 +183,24 @@ internal class DefaultMultiStakingBalanceProducerTest {
|
|||
every { stakeKitBalancesStore.get(params.userWalletId) } returns networksStatusesFlow
|
||||
every { p2PEthPoolBalancesStore.get(params.userWalletId) } returns flowOf(emptySet())
|
||||
|
||||
val actual = producer.produceWithFallback()
|
||||
val actual = createProducer().produceWithFallback()
|
||||
|
||||
// check after producer.produce()
|
||||
verify { stakeKitBalancesStore.get(params.userWalletId) }
|
||||
verify { p2PEthPoolBalancesStore.get(params.userWalletId) }
|
||||
|
||||
val values1 = getEmittedValues(flow = actual)
|
||||
actual.test {
|
||||
// first collection throws -> retryWhen emits the empty fallback, then waits 2s
|
||||
Truth.assertThat(awaitItem()).isEqualTo(emptySet<StakingBalance>())
|
||||
|
||||
Truth.assertThat(values1.size).isEqualTo(1)
|
||||
Truth.assertThat(values1).isEqualTo(listOf(emptySet<StakingBalance>()))
|
||||
// recover the upstream and let the retry fire
|
||||
innerFlow.value = true
|
||||
advanceTimeBy(delayTimeMillis = 2001)
|
||||
runCurrent()
|
||||
|
||||
innerFlow.emit(value = true)
|
||||
Truth.assertThat(awaitItem()).isEqualTo(balances)
|
||||
|
||||
val values2 = getEmittedValues(flow = actual)
|
||||
|
||||
Truth.assertThat(values2.size).isEqualTo(1)
|
||||
Truth.assertThat(values2).isEqualTo(listOf(balances))
|
||||
cancelAndIgnoreRemainingEvents()
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
|
|
|
|||
|
|
@ -11,22 +11,29 @@ import com.tangem.domain.models.wallet.UserWalletId
|
|||
import com.tangem.domain.staking.multi.MultiStakingBalanceProducer
|
||||
import com.tangem.domain.staking.multi.MultiStakingBalanceSupplier
|
||||
import com.tangem.domain.staking.single.SingleStakingBalanceProducer
|
||||
import app.cash.turbine.test
|
||||
import com.tangem.test.core.TestFlowProducerTools
|
||||
import com.tangem.test.core.getEmittedValues
|
||||
import com.tangem.utils.coroutines.TestingCoroutineDispatcherProvider
|
||||
import io.mockk.clearMocks
|
||||
import io.mockk.every
|
||||
import io.mockk.mockk
|
||||
import io.mockk.verify
|
||||
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
||||
import kotlinx.coroutines.flow.*
|
||||
import kotlinx.coroutines.test.TestScope
|
||||
import kotlinx.coroutines.test.UnconfinedTestDispatcher
|
||||
import kotlinx.coroutines.test.advanceTimeBy
|
||||
import kotlinx.coroutines.test.runCurrent
|
||||
import kotlinx.coroutines.test.runTest
|
||||
import org.junit.jupiter.api.BeforeEach
|
||||
import org.junit.jupiter.api.Disabled
|
||||
import org.junit.jupiter.api.Test
|
||||
import org.junit.jupiter.api.TestInstance
|
||||
|
||||
/**
|
||||
[REDACTED_AUTHOR]
|
||||
*/
|
||||
@OptIn(ExperimentalCoroutinesApi::class)
|
||||
@TestInstance(TestInstance.Lifecycle.PER_CLASS)
|
||||
internal class DefaultSingleStakingBalanceProducerTest {
|
||||
|
||||
|
|
@ -48,6 +55,23 @@ internal class DefaultSingleStakingBalanceProducerTest {
|
|||
flowProducerTools = flowProducerTools,
|
||||
)
|
||||
|
||||
private fun TestScope.createProducer(): DefaultSingleStakingBalanceProducer {
|
||||
val testDispatcher = UnconfinedTestDispatcher(testScheduler)
|
||||
return DefaultSingleStakingBalanceProducer(
|
||||
params = params,
|
||||
multiStakingBalanceSupplier = multiNetworkStatusSupplier,
|
||||
analyticsExceptionHandler = analyticsExceptionHandler,
|
||||
dispatchers = TestingCoroutineDispatcherProvider(
|
||||
main = testDispatcher,
|
||||
mainImmediate = testDispatcher,
|
||||
io = testDispatcher,
|
||||
default = testDispatcher,
|
||||
single = testDispatcher,
|
||||
),
|
||||
flowProducerTools = TestFlowProducerTools(scope = backgroundScope, dispatcher = testDispatcher),
|
||||
)
|
||||
}
|
||||
|
||||
@BeforeEach
|
||||
fun resetMocks() {
|
||||
clearMocks(multiNetworkStatusSupplier, analyticsExceptionHandler)
|
||||
|
|
@ -77,7 +101,6 @@ internal class DefaultSingleStakingBalanceProducerTest {
|
|||
verify(exactly = 1) { multiNetworkStatusSupplier(multiParams) }
|
||||
}
|
||||
|
||||
@Disabled
|
||||
@Test
|
||||
fun `flow is updated if staking balance is updated`() = runTest {
|
||||
// Arrange
|
||||
|
|
@ -86,31 +109,23 @@ internal class DefaultSingleStakingBalanceProducerTest {
|
|||
val multiParams = MultiStakingBalanceProducer.Params(userWalletId = params.userWalletId)
|
||||
every { multiNetworkStatusSupplier(multiParams) } returns multiFlow
|
||||
|
||||
val producerFlow = producer.produceWithFallback()
|
||||
val producerFlow = createProducer().produceWithFallback()
|
||||
|
||||
val balance = MockYieldBalanceWrapperDTOFactory.createWithBalance(tonId).toDomain()
|
||||
val updatedBalance = StakingBalance.Error(stakingId = tonId)
|
||||
producerFlow.test {
|
||||
val balance = MockYieldBalanceWrapperDTOFactory.createWithBalance(tonId).toDomain()
|
||||
multiFlow.emit(value = setOf(balance))
|
||||
Truth.assertThat(awaitItem()).isEqualTo(balance)
|
||||
|
||||
// Act (first emit)
|
||||
multiFlow.emit(value = setOf(balance))
|
||||
val actual1 = getEmittedValues(flow = producerFlow)
|
||||
val updatedBalance = StakingBalance.Error(stakingId = tonId)
|
||||
multiFlow.emit(value = setOf(updatedBalance))
|
||||
Truth.assertThat(awaitItem()).isEqualTo(updatedBalance)
|
||||
|
||||
// Assert (first emit)
|
||||
Truth.assertThat(actual1).hasSize(1)
|
||||
Truth.assertThat(actual1).containsExactly(balance)
|
||||
|
||||
// Act (second emit)
|
||||
multiFlow.emit(value = setOf(updatedBalance))
|
||||
val actual2 = getEmittedValues(flow = producerFlow)
|
||||
|
||||
// Assert (second emit)
|
||||
Truth.assertThat(actual2).hasSize(2)
|
||||
Truth.assertThat(actual2).containsExactly(balance, updatedBalance)
|
||||
cancelAndIgnoreRemainingEvents()
|
||||
}
|
||||
|
||||
verify(exactly = 1) { multiNetworkStatusSupplier(multiParams) }
|
||||
}
|
||||
|
||||
@Disabled
|
||||
@Test
|
||||
fun `flow is filtered the same status`() = runTest {
|
||||
// Arrange
|
||||
|
|
@ -119,30 +134,23 @@ internal class DefaultSingleStakingBalanceProducerTest {
|
|||
val multiParams = MultiStakingBalanceProducer.Params(userWalletId = params.userWalletId)
|
||||
every { multiNetworkStatusSupplier(multiParams) } returns multiFlow
|
||||
|
||||
val producerFlow = producer.produceWithFallback()
|
||||
val producerFlow = createProducer().produceWithFallback()
|
||||
|
||||
val balance = MockYieldBalanceWrapperDTOFactory.createWithBalance(tonId).toDomain()
|
||||
producerFlow.test {
|
||||
val balance = MockYieldBalanceWrapperDTOFactory.createWithBalance(tonId).toDomain()
|
||||
multiFlow.emit(value = setOf(balance))
|
||||
Truth.assertThat(awaitItem()).isEqualTo(balance)
|
||||
|
||||
// Act (first emit)
|
||||
multiFlow.emit(value = setOf(balance))
|
||||
val actual1 = getEmittedValues(flow = producerFlow)
|
||||
// same balance again -> filtered out by distinctUntilChanged
|
||||
multiFlow.emit(value = setOf(balance))
|
||||
expectNoEvents()
|
||||
|
||||
// Assert (first emit)
|
||||
Truth.assertThat(actual1).hasSize(1)
|
||||
Truth.assertThat(actual1).containsExactly(balance)
|
||||
|
||||
// Act (second emit)
|
||||
multiFlow.emit(value = setOf(balance))
|
||||
val actual2 = getEmittedValues(flow = producerFlow)
|
||||
|
||||
// Assert (second emit)
|
||||
Truth.assertThat(actual2).hasSize(1)
|
||||
Truth.assertThat(actual2).containsExactly(balance)
|
||||
cancelAndIgnoreRemainingEvents()
|
||||
}
|
||||
|
||||
verify(exactly = 1) { multiNetworkStatusSupplier(multiParams) }
|
||||
}
|
||||
|
||||
@Disabled
|
||||
@Test
|
||||
fun `flow throws exception`() = runTest {
|
||||
// Arrange
|
||||
|
|
@ -163,23 +171,22 @@ internal class DefaultSingleStakingBalanceProducerTest {
|
|||
val multiParams = MultiStakingBalanceProducer.Params(userWalletId = params.userWalletId)
|
||||
every { multiNetworkStatusSupplier(multiParams) } returns multiFlow
|
||||
|
||||
val producerFlow = producer.produceWithFallback()
|
||||
val producerFlow = createProducer().produceWithFallback()
|
||||
|
||||
// Act (first emit)
|
||||
val actual1 = getEmittedValues(flow = producerFlow)
|
||||
producerFlow.test {
|
||||
// first collection throws -> retryWhen emits the fallback, then waits 2s
|
||||
val fallbackStatus = StakingBalance.Error(stakingId = tonId.copy(address = "0x1"))
|
||||
Truth.assertThat(awaitItem()).isEqualTo(fallbackStatus)
|
||||
|
||||
// Assert (first emit)
|
||||
val fallbackStatus = StakingBalance.Error(stakingId = tonId.copy(address = "0x1"))
|
||||
// recover the upstream and let the retry fire
|
||||
innerFlow.value = true
|
||||
advanceTimeBy(delayTimeMillis = 2001)
|
||||
runCurrent()
|
||||
|
||||
Truth.assertThat(actual1).hasSize(1)
|
||||
Truth.assertThat(actual1).containsExactly(fallbackStatus)
|
||||
Truth.assertThat(awaitItem()).isEqualTo(balance)
|
||||
|
||||
// Act (second emit)
|
||||
innerFlow.emit(value = true)
|
||||
val actual2 = getEmittedValues(flow = producerFlow)
|
||||
|
||||
Truth.assertThat(actual2).hasSize(1)
|
||||
Truth.assertThat(actual2).containsExactly(balance)
|
||||
cancelAndIgnoreRemainingEvents()
|
||||
}
|
||||
|
||||
verify(exactly = 1) { multiNetworkStatusSupplier(multiParams) }
|
||||
}
|
||||
|
|
|
|||
|
|
@ -13,7 +13,6 @@ import com.tangem.domain.models.staking.StakingID
|
|||
import com.tangem.domain.models.wallet.UserWalletId
|
||||
import kotlinx.coroutines.flow.firstOrNull
|
||||
import kotlinx.coroutines.test.runTest
|
||||
import org.junit.jupiter.api.Disabled
|
||||
import org.junit.jupiter.api.Test
|
||||
|
||||
/**
|
||||
|
|
@ -137,9 +136,6 @@ internal class StakingBalancesStoreUpdateMethodsTest {
|
|||
Truth.assertThat(persistenceStore.data.firstOrNull()).isEqualTo(emptyMap<String, Set<YieldBalanceWrapperDTO>>())
|
||||
}
|
||||
|
||||
// TODO: revisit — expected is built via wrapper.toDomain(ONLY_CACHE) but that yields source=ACTUAL,
|
||||
// while storeError() applies ONLY_CACHE. Mock/toDomain vs production source handling needs review.
|
||||
@Disabled("Source-mismatch between toDomain() expectation and storeError() output; needs domain review")
|
||||
@Test
|
||||
fun `store error if runtime store contains balance with this id`() = runTest {
|
||||
val wrapper = MockYieldBalanceWrapperDTOFactory.createWithBalance(stakingId)
|
||||
|
|
@ -152,8 +148,10 @@ internal class StakingBalancesStoreUpdateMethodsTest {
|
|||
|
||||
store.storeError(userWalletId = userWalletId, stakingIds = setOf(stakingId))
|
||||
|
||||
// storeError keeps the existing (CACHE) balance and downgrades its source to ONLY_CACHE.
|
||||
// toDomain(ONLY_CACHE) can't express this: the converter maps any non-CACHE source to ACTUAL.
|
||||
val runtimeExpected = mapOf(
|
||||
userWalletId to setOf(wrapper.toDomain(source = StatusSource.ONLY_CACHE)),
|
||||
userWalletId to setOf(wrapper.toDomain(source = StatusSource.CACHE).copySealed(source = StatusSource.ONLY_CACHE)),
|
||||
)
|
||||
|
||||
Truth.assertThat(runtimeStore.getSyncOrNull()).isEqualTo(runtimeExpected)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue