package kotlinx.coroutines.exceptions import kotlinx.coroutines.testing.* import kotlinx.coroutines.* import org.junit.* import kotlin.coroutines.* class StackTraceRecoveryNestedScopesTest : TestBase() { private val TEST_MACROS = "TEST_NAME" private val expectedTrace = "kotlinx.coroutines.testing.RecoverableTestException\n" + "\tat kotlinx.coroutines.exceptions.StackTraceRecoveryNestedScopesTest.failure(StackTraceRecoveryNestedScopesTest.kt:9)\n" + "\tat kotlinx.coroutines.exceptions.StackTraceRecoveryNestedScopesTest.access\$failure(StackTraceRecoveryNestedScopesTest.kt:7)\n" + "\tat kotlinx.coroutines.exceptions.StackTraceRecoveryNestedScopesTest\$createFailingAsync\$1.invokeSuspend(StackTraceRecoveryNestedScopesTest.kt:12)\n" + "\tat _COROUTINE._BOUNDARY._(CoroutineDebugging.kt)\n" + "\tat kotlinx.coroutines.exceptions.StackTraceRecoveryNestedScopesTest\$callWithTimeout\$2.invokeSuspend(StackTraceRecoveryNestedScopesTest.kt:23)\n" + "\tat kotlinx.coroutines.exceptions.StackTraceRecoveryNestedScopesTest\$callCoroutineScope\$2.invokeSuspend(StackTraceRecoveryNestedScopesTest.kt:29)\n" + "\tat kotlinx.coroutines.exceptions.StackTraceRecoveryNestedScopesTest\$$TEST_MACROS\$1.invokeSuspend(StackTraceRecoveryNestedScopesTest.kt:36)\n" + "Caused by: kotlinx.coroutines.testing.RecoverableTestException\n" + "\tat kotlinx.coroutines.exceptions.StackTraceRecoveryNestedScopesTest.failure(StackTraceRecoveryNestedScopesTest.kt:9)\n" + "\tat kotlinx.coroutines.exceptions.StackTraceRecoveryNestedScopesTest.access\$failure(StackTraceRecoveryNestedScopesTest.kt:7)\n" + "\tat kotlinx.coroutines.exceptions.StackTraceRecoveryNestedScopesTest\$createFailingAsync\$1.invokeSuspend(StackTraceRecoveryNestedScopesTest.kt:12)\n" + "\tat kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:32)" private fun failure(): String = throw RecoverableTestException() private fun CoroutineScope.createFailingAsync() = async { failure() } private suspend fun callWithContext(doYield: Boolean) = withContext(wrapperDispatcher(coroutineContext)) { if (doYield) yield() createFailingAsync().await() yield() } private suspend fun callWithTimeout(doYield: Boolean) = withTimeout(Long.MAX_VALUE) { if (doYield) yield() callWithContext(doYield) yield() } private suspend fun callCoroutineScope(doYield: Boolean) = coroutineScope { if (doYield) yield() callWithTimeout(doYield) yield() } @Test fun testNestedScopes() = runTest { try { callCoroutineScope(false) } catch (e: Exception) { verifyStackTrace(e, expectedTrace.replace(TEST_MACROS, "testNestedScopes")) } } @Test fun testNestedScopesYield() = runTest { try { callCoroutineScope(true) } catch (e: Exception) { verifyStackTrace(e, expectedTrace.replace(TEST_MACROS, "testNestedScopesYield")) } } @Test fun testAwaitNestedScopes() = runTest { val deferred = async(NonCancellable) { callCoroutineScope(false) } verifyAwait(deferred) } private suspend fun verifyAwait(deferred: Deferred) { try { deferred.await() } catch (e: Exception) { verifyStackTrace(e, "kotlinx.coroutines.testing.RecoverableTestException\n" + "\tat kotlinx.coroutines.exceptions.StackTraceRecoveryNestedScopesTest.failure(StackTraceRecoveryNestedScopesTest.kt:23)\n" + "\tat kotlinx.coroutines.exceptions.StackTraceRecoveryNestedScopesTest.access\$failure(StackTraceRecoveryNestedScopesTest.kt:7)\n" + "\tat kotlinx.coroutines.exceptions.StackTraceRecoveryNestedScopesTest\$createFailingAsync\$1.invokeSuspend(StackTraceRecoveryNestedScopesTest.kt:26)\n" + "\tat _COROUTINE._BOUNDARY._(CoroutineDebugging.kt)\n" + "\tat kotlinx.coroutines.exceptions.StackTraceRecoveryNestedScopesTest\$callWithTimeout\$2.invokeSuspend(StackTraceRecoveryNestedScopesTest.kt:37)\n" + "\tat kotlinx.coroutines.exceptions.StackTraceRecoveryNestedScopesTest\$callCoroutineScope\$2.invokeSuspend(StackTraceRecoveryNestedScopesTest.kt:43)\n" + "\tat kotlinx.coroutines.exceptions.StackTraceRecoveryNestedScopesTest\$testAwaitNestedScopes\$1\$deferred\$1.invokeSuspend(StackTraceRecoveryNestedScopesTest.kt:68)\n" + "\tat kotlinx.coroutines.exceptions.StackTraceRecoveryNestedScopesTest.verifyAwait(StackTraceRecoveryNestedScopesTest.kt:76)\n" + "\tat kotlinx.coroutines.exceptions.StackTraceRecoveryNestedScopesTest\$testAwaitNestedScopes\$1.invokeSuspend(StackTraceRecoveryNestedScopesTest.kt:71)\n" + "Caused by: kotlinx.coroutines.testing.RecoverableTestException\n" + "\tat kotlinx.coroutines.exceptions.StackTraceRecoveryNestedScopesTest.failure(StackTraceRecoveryNestedScopesTest.kt:23)\n" + "\tat kotlinx.coroutines.exceptions.StackTraceRecoveryNestedScopesTest.access\$failure(StackTraceRecoveryNestedScopesTest.kt:7)\n" + "\tat kotlinx.coroutines.exceptions.StackTraceRecoveryNestedScopesTest\$createFailingAsync\$1.invokeSuspend(StackTraceRecoveryNestedScopesTest.kt:26)\n" + "\tat kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:32)") } } }