package kotlinx.coroutines import kotlinx.coroutines.testing.* import kotlin.coroutines.* import kotlin.test.* class CancellableContinuationJvmTest : TestBase() { @Test fun testToString() = runTest { checkToString() } private suspend fun checkToString() { suspendCancellableCoroutine { it.resume(Unit) assertTrue(it.toString().contains("kotlinx.coroutines.CancellableContinuationJvmTest.checkToString(CancellableContinuationJvmTest.kt")) } suspend {}() // Eliminate tail-call optimization } @Test fun testExceptionIsNotReported() = runTest({ it is CancellationException }) { val ctx = coroutineContext suspendCancellableCoroutine { ctx.cancel() it.resumeWith(Result.failure(TestException())) } } @Test fun testBlockingIntegration() = runTest { val source = BlockingSource() val job = launch(Dispatchers.Default) { source.await() } source.cancelAndJoin(job) } @Test fun testBlockingIntegrationAlreadyCancelled() = runTest { val source = BlockingSource() val job = launch(Dispatchers.Default) { cancel() source.await() } source.cancelAndJoin(job) } private suspend fun BlockingSource.cancelAndJoin(job: Job) { while (!hasSubscriber) { Thread.sleep(10) } job.cancelAndJoin() } private suspend fun BlockingSource.await() = suspendCancellableCoroutine { it.invokeOnCancellation { this.cancel() } subscribe() } private class BlockingSource { @Volatile private var isCancelled = false @Volatile public var hasSubscriber = false public fun subscribe() { hasSubscriber = true while (!isCancelled) { Thread.sleep(10) } } public fun cancel() { isCancelled = true } } }