Add helper to convert a kotlin flow to a Condition

This extension function makes it easier to convert a kotlin flow to a
Condition for interoperability between the repository pattern which
utilizes flows and the Monitor framework.

Bug: 277762120
Test: atest ConditionExtensionsTest
Change-Id: I1e0b137ff87f489eaaa94799df48fcb86e882358
This commit is contained in:
Lucas Silva
2023-04-13 16:15:50 -04:00
parent d2d746ce5a
commit d0eba9956e
2 changed files with 158 additions and 0 deletions

View File

@@ -0,0 +1,23 @@
package com.android.systemui.shared.condition
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Job
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.launch
/** Converts a boolean flow to a [Condition] object which can be used with a [Monitor] */
@JvmOverloads
fun Flow<Boolean>.toCondition(scope: CoroutineScope, initialValue: Boolean? = null): Condition {
return object : Condition(initialValue, false) {
var job: Job? = null
override fun start() {
job = scope.launch { collect { updateCondition(it) } }
}
override fun stop() {
job?.cancel()
job = null
}
}
}

View File

@@ -0,0 +1,135 @@
package com.android.systemui.shared.condition
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.MutableSharedFlow
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.emptyFlow
import kotlinx.coroutines.flow.flowOf
import kotlinx.coroutines.test.StandardTestDispatcher
import kotlinx.coroutines.test.TestScope
import kotlinx.coroutines.test.runCurrent
import kotlinx.coroutines.test.runTest
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
@OptIn(ExperimentalCoroutinesApi::class)
@SmallTest
@RunWith(AndroidTestingRunner::class)
class ConditionExtensionsTest : SysuiTestCase() {
private lateinit var testScope: TestScope
@Before
fun setUp() {
testScope = TestScope(StandardTestDispatcher())
}
@Test
fun flowInitiallyTrue() =
testScope.runTest {
val flow = flowOf(true)
val condition = flow.toCondition(this)
runCurrent()
assertThat(condition.isConditionSet).isFalse()
condition.start()
runCurrent()
assertThat(condition.isConditionSet).isTrue()
assertThat(condition.isConditionMet).isTrue()
}
@Test
fun flowInitiallyFalse() =
testScope.runTest {
val flow = flowOf(false)
val condition = flow.toCondition(this)
runCurrent()
assertThat(condition.isConditionSet).isFalse()
condition.start()
runCurrent()
assertThat(condition.isConditionSet).isTrue()
assertThat(condition.isConditionMet).isFalse()
}
@Test
fun emptyFlowWithNoInitialValue() =
testScope.runTest {
val flow = emptyFlow<Boolean>()
val condition = flow.toCondition(this)
condition.start()
runCurrent()
assertThat(condition.isConditionSet).isFalse()
assertThat(condition.isConditionMet).isFalse()
}
@Test
fun emptyFlowWithInitialValueOfTrue() =
testScope.runTest {
val flow = emptyFlow<Boolean>()
val condition = flow.toCondition(scope = this, initialValue = true)
condition.start()
runCurrent()
assertThat(condition.isConditionSet).isTrue()
assertThat(condition.isConditionMet).isTrue()
}
@Test
fun emptyFlowWithInitialValueOfFalse() =
testScope.runTest {
val flow = emptyFlow<Boolean>()
val condition = flow.toCondition(scope = this, initialValue = false)
condition.start()
runCurrent()
assertThat(condition.isConditionSet).isTrue()
assertThat(condition.isConditionMet).isFalse()
}
@Test
fun conditionUpdatesWhenFlowEmitsNewValue() =
testScope.runTest {
val flow = MutableStateFlow(false)
val condition = flow.toCondition(this)
condition.start()
runCurrent()
assertThat(condition.isConditionSet).isTrue()
assertThat(condition.isConditionMet).isFalse()
flow.value = true
runCurrent()
assertThat(condition.isConditionMet).isTrue()
flow.value = false
runCurrent()
assertThat(condition.isConditionMet).isFalse()
condition.stop()
}
@Test
fun stoppingConditionUnsubscribesFromFlow() =
testScope.runTest {
val flow = MutableSharedFlow<Boolean>()
val condition = flow.toCondition(this)
runCurrent()
assertThat(flow.subscriptionCount.value).isEqualTo(0)
condition.start()
runCurrent()
assertThat(flow.subscriptionCount.value).isEqualTo(1)
condition.stop()
runCurrent()
assertThat(flow.subscriptionCount.value).isEqualTo(0)
}
}