doubov
01/24/2024, 10:42 PMfun <T> Flow<T>.throttleLatest(throttlePeriodInMillis: Int) = flow {
coroutineScope {
val context = coroutineContext
var nextMillis = TimeSource.Monotonic.markNow()
var delayPost: Deferred<Unit>? = null
collect {
val current = TimeSource.Monotonic.markNow()
if (nextMillis < current) {
nextMillis = current.plus(throttlePeriodInMillis.milliseconds)
emit(it)
delayPost?.cancel()
} else {
val delayNext = nextMillis
delayPost?.cancel()
delayPost = async(Dispatchers.Default) {
delay(nextMillis - current)
if (delayNext == nextMillis) {
nextMillis = TimeSource.Monotonic.markNow().plus(throttlePeriodInMillis.milliseconds)
withContext(context) {
emit(it)
}
}
}
}
}
}
}
And the corresponding unit test:
@Test
fun test() = runTest {
val count = AtomicInt(0)
val expectedResults = mapOf(
1 to 1,
2 to 7,
3 to 10
)
channelFlow {
withContext(<http://Dispatchers.IO|Dispatchers.IO>) {
for (i in 1..10) {
send(i)
delay(75)
}
}
}
.throttleLatest(500)
// 1 2 3 4 5 6 7 8 9 10
// __0 _75 150 225 300 375 450 525 600 675 750 825 900 975 1050
// 1 7 10
.onEach { count.incrementAndGet() }
.test {
for (i in 1..3) {
assertEquals(expectedResults[i], awaitItem())
}
awaitComplete()
assertEquals(3, count.get())
}
}
Which works fine on Android/jvm, but fails on Native (iOS).
Error
kotlin.AssertionError: Expected <7>, actual <4>.
Does time move faster on iOS? 😂
Can anyone give me pointers as to why this might be happening/what I'm doing wrong?doubov
01/24/2024, 10:43 PMephemient
01/25/2024, 12:28 AMephemient
01/25/2024, 12:30 AMtestScheduler.timeSource
doubov
01/25/2024, 5:41 PMdoubov
01/25/2024, 5:46 PMTimeSource
into the extension function as a parameter. Is there a better way of injecting it? 🤔doubov
01/25/2024, 6:19 PMrunTest { ... }
with runBlocking { ... }
results in the same failure on iOS:
Error
kotlin.AssertionError: Expected <7>, actual <4>.
doubov
01/25/2024, 9:41 PMiosX64Test
task fails but iosSimulatorArm64Test
passes