5
5
package kotlinx.coroutines.flow
6
6
7
7
import kotlinx.coroutines.*
8
+ import kotlinx.coroutines.internal.*
8
9
import org.junit.*
9
10
10
11
/* *
@@ -15,6 +16,15 @@ import org.junit.*
15
16
class SharingReferenceTest : TestBase () {
16
17
private val token = object {}
17
18
19
+ /*
20
+ * Single-threaded executor that we are using to ensure that the flow being sharing actually
21
+ * suspended (spilled its locals, attached to parent), so we can verify reachability.
22
+ * Without that, it's possible to have a situation where target flow is still
23
+ * being strongly referenced (by its dispatcher), but the test already tries to test reachability and fails.
24
+ */
25
+ @get:Rule
26
+ val executor = ExecutorRule (1 )
27
+
18
28
private val weakEmitter = flow {
19
29
emit(null )
20
30
// suspend forever without keeping a strong reference to continuation -- this is a model of
@@ -26,19 +36,26 @@ class SharingReferenceTest : TestBase() {
26
36
27
37
@Test
28
38
fun testShareInReference () {
29
- val flow = weakEmitter.shareIn(GlobalScope , SharingStarted .Eagerly , 0 )
39
+ val flow = weakEmitter.shareIn(ContextScope (executor), SharingStarted .Eagerly , 0 )
40
+ linearize()
30
41
FieldWalker .assertReachableCount(1 , flow) { it == = token }
31
42
}
32
43
33
44
@Test
34
45
fun testStateInReference () {
35
- val flow = weakEmitter.stateIn(GlobalScope , SharingStarted .Eagerly , null )
46
+ val flow = weakEmitter.stateIn(ContextScope (executor), SharingStarted .Eagerly , null )
47
+ linearize()
36
48
FieldWalker .assertReachableCount(1 , flow) { it == = token }
37
49
}
38
50
39
51
@Test
40
52
fun testStateInSuspendingReference () = runTest {
41
53
val flow = weakEmitter.stateIn(GlobalScope )
54
+ linearize()
42
55
FieldWalker .assertReachableCount(1 , flow) { it == = token }
43
56
}
44
- }
57
+
58
+ private fun linearize () {
59
+ runBlocking(executor) { }
60
+ }
61
+ }
0 commit comments