:wave: Not sure if this question is better suited ...
# flow
d
👋 Not sure if this question is better suited to #multiplatform channel, but I'll ask here first:
Copy code
fun <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:
Copy code
@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).
Copy code
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?
I'm using the Turbine library for testing Flows
e
you should inject a TimeSource. Monotonic does not follow the virtual clock in runTest
e.g.
testScheduler.timeSource
d
Oh interesting, thanks! Let me try that
Ideally I wouldn't have to pass a
TimeSource
into the extension function as a parameter. Is there a better way of injecting it? 🤔
replacing
runTest { ... }
with
runBlocking { ... }
results in the same failure on iOS:
Copy code
Error
kotlin.AssertionError: Expected <7>, actual <4>.
okay, the weird part is that the
iosX64Test
task fails but
iosSimulatorArm64Test
passes