1 /* 2 * Copyright 2016-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license. 3 */ 4 5 package kotlinx.coroutines.exceptions 6 7 import kotlinx.coroutines.* 8 import java.io.* 9 import java.util.* 10 import kotlin.coroutines.* 11 import kotlin.test.* 12 13 /** 14 * Proxy for [Throwable.getSuppressed] for tests, which are compiled for both JDK 1.6 and JDK 1.8, 15 * but run only under JDK 1.8 16 */ 17 @Suppress("ConflictingExtensionProperty") 18 actual val Throwable.suppressed: Array<Throwable> get() { 19 val method = this::class.java.getMethod("getSuppressed") ?: error("This test can only be run using JDK 1.7") 20 @Suppress("UNCHECKED_CAST") 21 return method.invoke(this) as Array<Throwable> 22 } 23 checkExceptionnull24internal inline fun <reified T : Throwable> checkException(exception: Throwable): Boolean { 25 assertTrue(exception is T) 26 assertTrue(exception.suppressed.isEmpty()) 27 assertNull(exception.cause) 28 return true 29 } 30 checkCyclesnull31internal fun checkCycles(t: Throwable) { 32 val sw = StringWriter() 33 t.printStackTrace(PrintWriter(sw)) 34 assertFalse(sw.toString().contains("CIRCULAR REFERENCE")) 35 } 36 37 class CapturingHandler : AbstractCoroutineContextElement(CoroutineExceptionHandler), 38 CoroutineExceptionHandler 39 { 40 private var unhandled: ArrayList<Throwable>? = ArrayList() 41 <lambda>null42 override fun handleException(context: CoroutineContext, exception: Throwable) = synchronized<Unit>(this) { 43 unhandled!!.add(exception) 44 } 45 getExceptionsnull46 fun getExceptions(): List<Throwable> = synchronized(this) { 47 return unhandled!!.also { unhandled = null } 48 } 49 <lambda>null50 fun getException(): Throwable = synchronized(this) { 51 val size = unhandled!!.size 52 assert(size == 1) { "Expected one unhandled exception, but have $size: $unhandled" } 53 return unhandled!![0].also { unhandled = null } 54 } 55 } 56 captureExceptionsRunnull57internal fun captureExceptionsRun( 58 context: CoroutineContext = EmptyCoroutineContext, 59 block: suspend CoroutineScope.() -> Unit 60 ): Throwable { 61 val handler = CapturingHandler() 62 runBlocking(context + handler, block = block) 63 return handler.getException() 64 } 65 captureMultipleExceptionsRunnull66internal fun captureMultipleExceptionsRun( 67 context: CoroutineContext = EmptyCoroutineContext, 68 block: suspend CoroutineScope.() -> Unit 69 ): List<Throwable> { 70 val handler = CapturingHandler() 71 runBlocking(context + handler, block = block) 72 return handler.getExceptions() 73 } 74