1 package kotlinx.coroutines.testing.exceptions 2 3 import kotlinx.coroutines.* 4 import java.io.* 5 import java.util.* 6 import kotlin.contracts.* 7 import kotlin.coroutines.* 8 import kotlin.test.* 9 checkExceptionnull10inline fun <reified T : Throwable> checkException(exception: Throwable) { 11 assertIs<T>(exception) 12 assertTrue(exception.suppressed.isEmpty()) 13 assertNull(exception.cause) 14 } 15 checkCyclesnull16fun checkCycles(t: Throwable) { 17 val sw = StringWriter() 18 t.printStackTrace(PrintWriter(sw)) 19 assertFalse(sw.toString().contains("CIRCULAR REFERENCE")) 20 } 21 22 class CapturingHandler : AbstractCoroutineContextElement(CoroutineExceptionHandler), 23 CoroutineExceptionHandler 24 { 25 private var unhandled: ArrayList<Throwable>? = ArrayList() 26 <lambda>null27 override fun handleException(context: CoroutineContext, exception: Throwable) = synchronized<Unit>(this) { 28 unhandled!!.add(exception) 29 } 30 <lambda>null31 fun getException(): Throwable = synchronized(this) { 32 val size = unhandled!!.size 33 assert(size == 1) { "Expected one unhandled exception, but have $size: $unhandled" } 34 return unhandled!![0].also { unhandled = null } 35 } 36 } 37 captureExceptionsRunnull38fun captureExceptionsRun( 39 context: CoroutineContext = EmptyCoroutineContext, 40 block: suspend CoroutineScope.() -> Unit 41 ): Throwable { 42 val handler = CapturingHandler() 43 runBlocking(context + handler, block = block) 44 return handler.getException() 45 } 46 47 @OptIn(ExperimentalContracts::class) assertCallsExceptionHandlerWithnull48suspend inline fun <reified E: Throwable> assertCallsExceptionHandlerWith( 49 crossinline operation: suspend (CoroutineExceptionHandler) -> Unit): E { 50 contract { 51 callsInPlace(operation, InvocationKind.EXACTLY_ONCE) 52 } 53 val handler = CapturingHandler() 54 return withContext(handler) { 55 operation(handler) 56 assertIs<E>(handler.getException()) 57 } 58 } 59