@@ -6,7 +6,11 @@ import kotlinx.coroutines.channels.Channel
6
6
import kotlinx.coroutines.flow.MutableStateFlow
7
7
import kotlinx.coroutines.flow.consumeAsFlow
8
8
import kotlinx.coroutines.launch
9
- import kotlinx.coroutines.test.runBlockingTest
9
+ import kotlinx.coroutines.test.StandardTestDispatcher
10
+ import kotlinx.coroutines.test.UnconfinedTestDispatcher
11
+ import kotlinx.coroutines.test.advanceUntilIdle
12
+ import kotlinx.coroutines.test.runTest
13
+ import kotlinx.coroutines.withContext
10
14
import java.util.concurrent.atomic.AtomicInteger
11
15
import kotlin.test.Test
12
16
import kotlin.test.assertEquals
@@ -23,40 +27,38 @@ internal class SinkTest {
23
27
24
28
private val sink = RecordingSink ()
25
29
26
- @Test fun `collectToSink sends action` () {
27
- runBlockingTest {
28
- val flow = MutableStateFlow (1 )
29
- val collector = launch {
30
- flow.collectToSink(sink) {
31
- action {
32
- state = " $props $state $it "
33
- setOutput(" output: $it " )
34
- }
30
+ @Test fun `collectToSink sends action` () = runTest {
31
+ val flow = MutableStateFlow (1 )
32
+ val collector = launch {
33
+ flow.collectToSink(sink) {
34
+ action {
35
+ state = " $props $state $it "
36
+ setOutput(" output: $it " )
35
37
}
36
38
}
39
+ }
37
40
38
- advanceUntilIdle()
39
- assertEquals(1 , sink.actions.size)
40
- sink.actions.removeFirst()
41
- .let { action ->
42
- val (newState, output) = action.applyTo(" props" , " state" )
43
- assertEquals(" props state 1" , newState)
44
- assertEquals(" output: 1" , output?.value)
45
- }
46
- assertTrue(sink.actions.isEmpty())
47
-
48
- flow.value = 2
49
- advanceUntilIdle()
50
- assertEquals(1 , sink.actions.size)
51
- sink.actions.removeFirst()
52
- .let { action ->
53
- val (newState, output) = action.applyTo(" props" , " state" )
54
- assertEquals(" props state 2" , newState)
55
- assertEquals(" output: 2" , output?.value)
56
- }
41
+ advanceUntilIdle()
42
+ assertEquals(1 , sink.actions.size)
43
+ sink.actions.removeFirst()
44
+ .let { action ->
45
+ val (newState, output) = action.applyTo(" props" , " state" )
46
+ assertEquals(" props state 1" , newState)
47
+ assertEquals(" output: 1" , output?.value)
48
+ }
49
+ assertTrue(sink.actions.isEmpty())
50
+
51
+ flow.value = 2
52
+ advanceUntilIdle()
53
+ assertEquals(1 , sink.actions.size)
54
+ sink.actions.removeFirst()
55
+ .let { action ->
56
+ val (newState, output) = action.applyTo(" props" , " state" )
57
+ assertEquals(" props state 2" , newState)
58
+ assertEquals(" output: 2" , output?.value)
59
+ }
57
60
58
- collector.cancel()
59
- }
61
+ collector.cancel()
60
62
}
61
63
62
64
@Test fun `collectToSink propagates backpressure` () {
@@ -69,7 +71,7 @@ internal class SinkTest {
69
71
sentActions + = it
70
72
}
71
73
72
- runBlockingTest {
74
+ runTest( UnconfinedTestDispatcher ()) {
73
75
val collectJob = launch {
74
76
flow.collectToSink(sink) { action { setOutput(it) } }
75
77
}
@@ -118,7 +120,7 @@ internal class SinkTest {
118
120
setOutput(" output" )
119
121
}
120
122
121
- runBlockingTest {
123
+ runTest {
122
124
launch { sink.sendAndAwaitApplication(action) }
123
125
advanceUntilIdle()
124
126
@@ -130,33 +132,32 @@ internal class SinkTest {
130
132
}
131
133
}
132
134
133
- @Test fun `sendAndAwaitApplication suspends until after applied` () {
134
- runBlockingTest {
135
- var resumed = false
136
- val action = action<String , String , String > {
137
- assertFalse(resumed)
138
- }
139
- launch {
140
- sink.sendAndAwaitApplication(action)
141
- resumed = true
142
- }
143
- advanceUntilIdle()
135
+ @Test fun `sendAndAwaitApplication suspends until after applied` () = runTest {
136
+ var resumed = false
137
+ val action = action<String , String , String > {
144
138
assertFalse(resumed)
145
- assertEquals(1 , sink.actions.size)
139
+ }
140
+ launch {
141
+ sink.sendAndAwaitApplication(action)
142
+ resumed = true
143
+ }
144
+ advanceUntilIdle()
145
+ assertFalse(resumed)
146
+ assertEquals(1 , sink.actions.size)
146
147
147
- val enqueuedAction = sink.actions.removeFirst()
148
- pauseDispatcher()
149
- enqueuedAction.applyTo(" props" , " state" )
148
+ val enqueuedAction = sink.actions.removeFirst()
150
149
150
+ withContext(StandardTestDispatcher (testScheduler)) {
151
+ enqueuedAction.applyTo(" props" , " state" )
151
152
assertFalse(resumed)
152
- resumeDispatcher()
153
- advanceUntilIdle()
154
- assertTrue(resumed)
155
153
}
154
+
155
+ advanceUntilIdle()
156
+ assertTrue(resumed)
156
157
}
157
158
158
- @Test fun `sendAndAwaitApplication doesn't apply action when cancelled while suspended` () {
159
- runBlockingTest {
159
+ @Test fun `sendAndAwaitApplication doesn't apply action when cancelled while suspended` () =
160
+ runTest {
160
161
var applied = false
161
162
val action = action<String , String , String > {
162
163
applied = true
@@ -176,7 +177,6 @@ internal class SinkTest {
176
177
assertEquals(" state" , newState)
177
178
assertNull(output)
178
179
}
179
- }
180
180
181
181
private class RecordingSink : Sink <WorkflowAction <String , String , String >> {
182
182
val actions = mutableListOf<WorkflowAction <String , String , String >>()
0 commit comments