• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download

<lambda>null1 package kotlinx.coroutines.test
2 
3 import kotlinx.coroutines.*
4 import kotlinx.coroutines.channels.*
5 import kotlinx.coroutines.flow.*
6 import kotlinx.coroutines.testing.*
7 import kotlin.test.*
8 import kotlin.test.assertFailsWith
9 
10 /** Copy of [RunTestTest], but for [runBlockingTestOnTestScope], where applicable. */
11 @Suppress("DEPRECATION", "DEPRECATION_ERROR")
12 class RunBlockingTestOnTestScopeTest {
13 
14     @Test
15     fun testRunTestWithIllegalContext() {
16         for (ctx in TestScopeTest.invalidContexts) {
17             assertFailsWith<IllegalArgumentException> {
18                 runBlockingTestOnTestScope(ctx) { }
19             }
20         }
21     }
22 
23     @Test
24     fun testThrowingInRunTestBody() {
25         assertFailsWith<RuntimeException> {
26             runBlockingTestOnTestScope {
27                 throw RuntimeException()
28             }
29         }
30     }
31 
32     @Test
33     fun testThrowingInRunTestPendingTask() {
34         assertFailsWith<RuntimeException> {
35             runBlockingTestOnTestScope {
36                 launch {
37                     delay(SLOW)
38                     throw RuntimeException()
39                 }
40             }
41         }
42     }
43 
44     @Test
45     fun reproducer2405() = runBlockingTestOnTestScope {
46         val dispatcher = StandardTestDispatcher(testScheduler)
47         var collectedError = false
48         withContext(dispatcher) {
49             flow { emit(1) }
50                 .combine(
51                     flow<String> { throw IllegalArgumentException() }
52                 ) { int, string -> int.toString() + string }
53                 .catch { emit("error") }
54                 .collect {
55                     assertEquals("error", it)
56                     collectedError = true
57                 }
58         }
59         assertTrue(collectedError)
60     }
61 
62     @Test
63     fun testChildrenCancellationOnTestBodyFailure() {
64         var job: Job? = null
65         assertFailsWith<AssertionError> {
66             runBlockingTestOnTestScope {
67                 job = launch {
68                     while (true) {
69                         delay(1000)
70                     }
71                 }
72                 throw AssertionError()
73             }
74         }
75         assertTrue(job!!.isCancelled)
76     }
77 
78     @Test
79     fun testTimeout() {
80         assertFailsWith<TimeoutCancellationException> {
81             runBlockingTestOnTestScope {
82                 withTimeout(50) {
83                     launch {
84                         delay(1000)
85                     }
86                 }
87             }
88         }
89     }
90 
91     @Test
92     fun testRunTestThrowsRootCause() {
93         assertFailsWith<TestException> {
94             runBlockingTestOnTestScope {
95                 launch {
96                     throw TestException()
97                 }
98             }
99         }
100     }
101 
102     @Test
103     fun testCompletesOwnJob() {
104         var handlerCalled = false
105         runBlockingTestOnTestScope {
106             coroutineContext.job.invokeOnCompletion {
107                 handlerCalled = true
108             }
109         }
110         assertTrue(handlerCalled)
111     }
112 
113     @Test
114     fun testDoesNotCompleteGivenJob() {
115         var handlerCalled = false
116         val job = Job()
117         job.invokeOnCompletion {
118             handlerCalled = true
119         }
120         runBlockingTestOnTestScope(job) {
121             assertTrue(coroutineContext.job in job.children)
122         }
123         assertFalse(handlerCalled)
124         assertEquals(0, job.children.filter { it.isActive }.count())
125     }
126 
127     @Test
128     fun testSuppressedExceptions() {
129         try {
130             runBlockingTestOnTestScope {
131                 launch(SupervisorJob()) { throw TestException("x") }
132                 launch(SupervisorJob()) { throw TestException("y") }
133                 launch(SupervisorJob()) { throw TestException("z") }
134                 throw TestException("w")
135             }
136             fail("should not be reached")
137         } catch (e: TestException) {
138             assertEquals("w", e.message)
139             val suppressed = e.suppressedExceptions +
140                 (e.suppressedExceptions.firstOrNull()?.suppressedExceptions ?: emptyList())
141             assertEquals(3, suppressed.size)
142             assertEquals("x", suppressed[0].message)
143             assertEquals("y", suppressed[1].message)
144             assertEquals("z", suppressed[2].message)
145         }
146     }
147 
148     @Test
149     fun testScopeRunTestExceptionHandler(): TestResult {
150         val scope = TestCoroutineScope()
151         return testResultMap({
152             try {
153                 it()
154                 fail("should not be reached")
155             } catch (e: TestException) {
156                 // expected
157             }
158         }) {
159             scope.runTest {
160                 launch(SupervisorJob()) { throw TestException("x") }
161             }
162         }
163     }
164 
165     @Test
166     fun testBackgroundWorkBeingRun() = runBlockingTestOnTestScope {
167         var i = 0
168         var j = 0
169         backgroundScope.launch {
170             yield()
171             ++i
172         }
173         backgroundScope.launch {
174             yield()
175             delay(10)
176             ++j
177         }
178         assertEquals(0, i)
179         assertEquals(0, j)
180         delay(1)
181         assertEquals(1, i)
182         assertEquals(0, j)
183         delay(10)
184         assertEquals(1, i)
185         assertEquals(1, j)
186     }
187 
188     @Test
189     fun testBackgroundWorkCancelled() {
190         var cancelled = false
191         runBlockingTestOnTestScope {
192             var i = 0
193             backgroundScope.launch {
194                 yield()
195                 try {
196                     while (isActive) {
197                         ++i
198                         yield()
199                     }
200                 } catch (e: CancellationException) {
201                     cancelled = true
202                 }
203             }
204             repeat(5) {
205                 assertEquals(i, it)
206                 yield()
207             }
208         }
209         assertTrue(cancelled)
210     }
211 
212     @Test
213     fun testBackgroundWorkTimeControl(): TestResult = runBlockingTestOnTestScope {
214         var i = 0
215         var j = 0
216         backgroundScope.launch {
217             yield()
218             while (true) {
219                 ++i
220                 delay(100)
221             }
222         }
223         backgroundScope.launch {
224             yield()
225             while (true) {
226                 ++j
227                 delay(50)
228             }
229         }
230         advanceUntilIdle() // should do nothing, as only background work is left.
231         assertEquals(0, i)
232         assertEquals(0, j)
233         val job = launch {
234             delay(1)
235             // the background work scheduled for earlier gets executed before the normal work scheduled for later does
236             assertEquals(1, i)
237             assertEquals(1, j)
238         }
239         job.join()
240         advanceTimeBy(199) // should work the same for the background tasks
241         assertEquals(2, i)
242         assertEquals(4, j)
243         advanceUntilIdle() // once again, should do nothing
244         assertEquals(2, i)
245         assertEquals(4, j)
246         runCurrent() // should behave the same way as for the normal work
247         assertEquals(3, i)
248         assertEquals(5, j)
249         launch {
250             delay(1001)
251             assertEquals(13, i)
252             assertEquals(25, j)
253         }
254         advanceUntilIdle() // should execute the normal work, and with that, the background one, too
255     }
256 
257     @Test
258     fun testBackgroundWorkErrorReporting() {
259         var testFinished = false
260         val exception = RuntimeException("x")
261         try {
262             runBlockingTestOnTestScope {
263                 backgroundScope.launch {
264                     throw exception
265                 }
266                 delay(1000)
267                 testFinished = true
268             }
269             fail("unreached")
270         } catch (e: Throwable) {
271             assertSame(e, exception)
272             assertTrue(testFinished)
273         }
274     }
275 
276     @Test
277     fun testBackgroundWorkFinalizing() {
278         var taskEnded = 0
279         val nTasks = 10
280         try {
281             runBlockingTestOnTestScope {
282                 repeat(nTasks) {
283                     backgroundScope.launch {
284                         try {
285                             while (true) {
286                                 delay(1)
287                             }
288                         } finally {
289                             ++taskEnded
290                             if (taskEnded <= 2)
291                                 throw TestException()
292                         }
293                     }
294                 }
295                 delay(100)
296                 throw TestException()
297             }
298             fail("unreached")
299         } catch (e: TestException) {
300             assertEquals(2, e.suppressedExceptions.size)
301             assertEquals(nTasks, taskEnded)
302         }
303     }
304 
305     @Test
306     fun testExampleBackgroundJob1() = runBlockingTestOnTestScope {
307         val myFlow = flow {
308             yield()
309             var i = 0
310             while (true) {
311                 emit(++i)
312                 delay(1)
313             }
314         }
315         val stateFlow = myFlow.stateIn(backgroundScope, SharingStarted.Eagerly, 0)
316         var j = 0
317         repeat(100) {
318             assertEquals(j++, stateFlow.value)
319             delay(1)
320         }
321     }
322 
323     @Test
324     fun testExampleBackgroundJob2() = runBlockingTestOnTestScope {
325         val channel = Channel<Int>()
326         backgroundScope.launch {
327             var i = 0
328             while (true) {
329                 channel.send(i++)
330             }
331         }
332         repeat(100) {
333             assertEquals(it, channel.receive())
334         }
335     }
336 
337     @Test
338     fun testAsyncFailureInBackgroundReported() =
339         try {
340             runBlockingTestOnTestScope {
341                 backgroundScope.async {
342                     throw TestException("x")
343                 }
344                 backgroundScope.produce<Unit> {
345                     throw TestException("y")
346                 }
347                 delay(1)
348                 throw TestException("z")
349             }
350             fail("unreached")
351         } catch (e: TestException) {
352             assertEquals("z", e.message)
353             assertEquals(setOf("x", "y"), e.suppressedExceptions.map { it.message }.toSet())
354         }
355 
356     @Test
357     fun testNoDuplicateExceptions() =
358         try {
359             runBlockingTestOnTestScope {
360                 backgroundScope.launch {
361                     throw TestException("x")
362                 }
363                 delay(1)
364                 throw TestException("y")
365             }
366             fail("unreached")
367         } catch (e: TestException) {
368             assertEquals("y", e.message)
369             assertEquals(listOf("x"), e.suppressedExceptions.map { it.message })
370         }
371 }
372