• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
3  */
4 
5 package kotlinx.coroutines.test
6 
7 import kotlinx.coroutines.*
8 import kotlin.coroutines.*
9 
10 /**
11  * Access uncaught coroutine exceptions captured during test execution.
12  */
13 @ExperimentalCoroutinesApi // Since 1.2.1, tentatively till 1.3.0
14 public interface UncaughtExceptionCaptor {
15     /**
16      * List of uncaught coroutine exceptions.
17      *
18      * The returned list is a copy of the currently caught exceptions.
19      * During [cleanupTestCoroutines] the first element of this list is rethrown if it is not empty.
20      */
21     public val uncaughtExceptions: List<Throwable>
22 
23     /**
24      * Call after the test completes to ensure that there were no uncaught exceptions.
25      *
26      * The first exception in uncaughtExceptions is rethrown. All other exceptions are
27      * printed using [Throwable.printStackTrace].
28      *
29      * @throws Throwable the first uncaught exception, if there are any uncaught exceptions.
30      */
cleanupTestCoroutinesnull31     public fun cleanupTestCoroutines()
32 }
33 
34 /**
35  * An exception handler that captures uncaught exceptions in tests.
36  */
37 @ExperimentalCoroutinesApi // Since 1.2.1, tentatively till 1.3.0
38 public class TestCoroutineExceptionHandler :
39     AbstractCoroutineContextElement(CoroutineExceptionHandler), UncaughtExceptionCaptor, CoroutineExceptionHandler
40 {
41     private val _exceptions = mutableListOf<Throwable>()
42 
43     /** @suppress **/
44     override fun handleException(context: CoroutineContext, exception: Throwable) {
45         synchronized(_exceptions) {
46             _exceptions += exception
47         }
48     }
49 
50     /** @suppress **/
51     override val uncaughtExceptions: List<Throwable>
52         get() = synchronized(_exceptions) { _exceptions.toList() }
53 
54     /** @suppress **/
55     override fun cleanupTestCoroutines() {
56         synchronized(_exceptions) {
57             val exception = _exceptions.firstOrNull() ?: return
58             // log the rest
59             _exceptions.drop(1).forEach { it.printStackTrace() }
60             throw exception
61         }
62     }
63 }
64