1 /* 2 * Copyright (C) 2022 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 @file:Suppress("OPT_IN_USAGE") 18 19 package com.android.systemui.coroutines 20 21 import kotlin.coroutines.CoroutineContext 22 import kotlin.coroutines.EmptyCoroutineContext 23 import kotlin.properties.ReadOnlyProperty 24 import kotlin.reflect.KProperty 25 import kotlinx.coroutines.CoroutineStart 26 import kotlinx.coroutines.Job 27 import kotlinx.coroutines.flow.Flow 28 import kotlinx.coroutines.launch 29 import kotlinx.coroutines.test.TestScope 30 import kotlinx.coroutines.test.runCurrent 31 32 /** 33 * Collect [flow] in a new [Job] and return a getter for the last collected value. 34 * 35 * ``` 36 * fun myTest() = runTest { 37 * // ... 38 * val actual by collectLastValue(underTest.flow) 39 * assertThat(actual).isEqualTo(expected) 40 * } 41 * ``` 42 */ 43 fun <T> TestScope.collectLastValue( 44 flow: Flow<T>, 45 context: CoroutineContext = EmptyCoroutineContext, 46 start: CoroutineStart = CoroutineStart.DEFAULT, 47 ): FlowValue<T?> { 48 val values by 49 collectValues( 50 flow = flow, 51 context = context, 52 start = start, 53 ) 54 return FlowValueImpl { values.lastOrNull() } 55 } 56 57 /** 58 * Collect [flow] in a new [Job] and return a getter for the collection of values collected. 59 * 60 * ``` 61 * fun myTest() = runTest { 62 * // ... 63 * val values by collectValues(underTest.flow) 64 * assertThat(values).isEqualTo(listOf(expected1, expected2, ...)) 65 * } 66 * ``` 67 */ 68 fun <T> TestScope.collectValues( 69 flow: Flow<T>, 70 context: CoroutineContext = EmptyCoroutineContext, 71 start: CoroutineStart = CoroutineStart.DEFAULT, 72 ): FlowValue<List<T>> { 73 val values = mutableListOf<T>() 74 backgroundScope.launch(context, start) { flow.collect(values::add) } 75 return FlowValueImpl { 76 runCurrent() 77 values.toList() 78 } 79 } 80 81 /** @see collectLastValue */ 82 interface FlowValue<T> : ReadOnlyProperty<Any?, T> { 83 operator fun invoke(): T 84 } 85 86 private class FlowValueImpl<T>(private val block: () -> T) : FlowValue<T> { 87 override operator fun invoke(): T = block() 88 override fun getValue(thisRef: Any?, property: KProperty<*>): T = invoke() 89 } 90