Allow collectLastValue to be used as a delegate

Test: manual

Fixes: b/267486825

Change-Id: Ib5d733f77892ce2d01fdc6683621f5f51f87c4f4
This commit is contained in:
Marcello Galhardo
2023-02-01 18:00:33 +00:00
parent fcdc3d4355
commit 8d36df62d8
2 changed files with 48 additions and 3 deletions

View File

@@ -0,0 +1,24 @@
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)
}
}

View File

@@ -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()
}