package kotlinx.coroutines.exceptions import kotlinx.coroutines.* import java.io.* import kotlin.test.* public fun verifyStackTrace(e: Throwable, vararg traces: String) { val stacktrace = toStackTrace(e) val normalizedActual = stacktrace.normalizeStackTrace() traces.forEach { val normalizedExpected = it.normalizeStackTrace() if (!normalizedActual.contains(normalizedExpected)) { // A more readable error message would be produced by assertEquals assertEquals(normalizedExpected, normalizedActual, "Actual trace does not contain expected one") } } // Check "Caused by" counts val causes = stacktrace.count("Caused by") assertNotEquals(0, causes) assertEquals(traces.map { it.count("Caused by") }.sum(), causes) } public fun verifyStackTrace(path: String, e: Throwable) { val resource = Job::class.java.classLoader.getResourceAsStream("stacktraces/$path.txt") val lines = resource.reader().readLines() verifyStackTrace(e, *lines.toTypedArray()) } public fun toStackTrace(t: Throwable): String { val sw = StringWriter() as Writer t.printStackTrace(PrintWriter(sw)) return sw.toString() } public fun String.normalizeStackTrace(): String = replace(Regex(":[0-9]+"), "") // remove line numbers .replace("kotlinx_coroutines_core_main", "") // yay source sets .replace("kotlinx_coroutines_core", "") .replace(Regex("@[0-9a-f]+"), "") // remove hex addresses in debug toStrings .lines().joinToString("\n") // normalize line separators public fun String.count(substring: String): Int = split(substring).size - 1