Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 8d36df62 authored by Marcello Galhardo's avatar Marcello Galhardo
Browse files

Allow `collectLastValue` to be used as a delegate

Test: manual

Fixes: b/267486825

Change-Id: Ib5d733f77892ce2d01fdc6683621f5f51f87c4f4
parent fcdc3d43
Loading
Loading
Loading
Loading
+24 −0
Original line number Diff line number Diff line
package com.android.systemui.coroutines

import android.testing.AndroidTestingRunner
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.google.common.truth.Truth.assertThat
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.flow.flowOf
import kotlinx.coroutines.test.runTest
import org.junit.Test
import org.junit.runner.RunWith

@OptIn(ExperimentalCoroutinesApi::class)
@SmallTest
@RunWith(AndroidTestingRunner::class)
class FlowTest : SysuiTestCase() {

    @Test
    fun collectLastValue() = runTest {
        val flow = flowOf(0, 1, 2)
        val lastValue by collectLastValue(flow)
        assertThat(lastValue).isEqualTo(2)
    }
}
+24 −3
Original line number Diff line number Diff line
@@ -18,6 +18,8 @@ package com.android.systemui.coroutines

import kotlin.coroutines.CoroutineContext
import kotlin.coroutines.EmptyCoroutineContext
import kotlin.properties.ReadOnlyProperty
import kotlin.reflect.KProperty
import kotlinx.coroutines.CoroutineStart
import kotlinx.coroutines.Job
import kotlinx.coroutines.flow.Flow
@@ -25,16 +27,35 @@ import kotlinx.coroutines.launch
import kotlinx.coroutines.test.TestScope
import kotlinx.coroutines.test.runCurrent

/** Collect [flow] in a new [Job] and return a getter for the last collected value. */
/**
 * Collect [flow] in a new [Job] and return a getter for the last collected value.
 * ```
 * fun myTest() = runTest {
 *   // ...
 *   val actual by collectLastValue(underTest.flow)
 *   assertThat(actual).isEqualTo(expected)
 * }
 * ```
 */
fun <T> TestScope.collectLastValue(
    flow: Flow<T>,
    context: CoroutineContext = EmptyCoroutineContext,
    start: CoroutineStart = CoroutineStart.DEFAULT,
): () -> T? {
): FlowValue<T?> {
    var lastValue: T? = null
    backgroundScope.launch(context, start) { flow.collect { lastValue = it } }
    return {
    return FlowValueImpl {
        runCurrent()
        lastValue
    }
}

/** @see collectLastValue */
interface FlowValue<T> : ReadOnlyProperty<Any?, T?> {
    operator fun invoke(): T?
}

private class FlowValueImpl<T>(private val block: () -> T?) : FlowValue<T> {
    override operator fun invoke(): T? = block()
    override fun getValue(thisRef: Any?, property: KProperty<*>): T? = invoke()
}