<lambda>null1@file:Suppress("NAMED_ARGUMENTS_NOT_ALLOWED") // KT-21913 2 3 package kotlinx.coroutines 4 5 import kotlinx.coroutines.testing.* 6 import kotlin.coroutines.* 7 import kotlin.test.* 8 9 class CancellableContinuationTest : TestBase() { 10 @Test 11 fun testResumeWithExceptionAndResumeWithException() = runTest { 12 var continuation: Continuation<Unit>? = null 13 val job = launch { 14 try { 15 expect(2) 16 suspendCancellableCoroutine<Unit> { c -> 17 continuation = c 18 } 19 } catch (e: TestException) { 20 expect(3) 21 } 22 } 23 expect(1) 24 yield() 25 continuation!!.resumeWithException(TestException()) 26 yield() 27 assertFailsWith<IllegalStateException> { continuation!!.resumeWithException(TestException()) } 28 job.join() 29 finish(4) 30 } 31 32 @Test 33 fun testResumeAndResumeWithException() = runTest { 34 var continuation: Continuation<Unit>? = null 35 val job = launch { 36 expect(2) 37 suspendCancellableCoroutine<Unit> { c -> 38 continuation = c 39 } 40 expect(3) 41 } 42 expect(1) 43 yield() 44 continuation!!.resume(Unit) 45 job.join() 46 assertFailsWith<IllegalStateException> { continuation!!.resumeWithException(TestException()) } 47 finish(4) 48 } 49 50 @Test 51 fun testResumeAndResume() = runTest { 52 var continuation: Continuation<Unit>? = null 53 val job = launch { 54 expect(2) 55 suspendCancellableCoroutine<Unit> { c -> 56 continuation = c 57 } 58 expect(3) 59 } 60 expect(1) 61 yield() 62 continuation!!.resume(Unit) 63 job.join() 64 assertFailsWith<IllegalStateException> { continuation!!.resume(Unit) } 65 finish(4) 66 } 67 68 /** 69 * Cancelling outer job may, in practise, race with attempt to resume continuation and resumes 70 * should be ignored. Here suspended coroutine is cancelled but then resumed with exception. 71 */ 72 @Test 73 fun testCancelAndResumeWithException() = runTest { 74 var continuation: Continuation<Unit>? = null 75 val job = launch { 76 try { 77 expect(2) 78 suspendCancellableCoroutine<Unit> { c -> 79 continuation = c 80 } 81 } catch (e: CancellationException) { 82 expect(3) 83 } 84 } 85 expect(1) 86 yield() 87 job.cancel() // Cancel job 88 yield() 89 continuation!!.resumeWithException(TestException()) // Should not fail 90 finish(4) 91 } 92 93 /** 94 * Cancelling outer job may, in practise, race with attempt to resume continuation and resumes 95 * should be ignored. Here suspended coroutine is cancelled but then resumed with exception. 96 */ 97 @Test 98 fun testCancelAndResume() = runTest { 99 var continuation: Continuation<Unit>? = null 100 val job = launch { 101 try { 102 expect(2) 103 suspendCancellableCoroutine<Unit> { c -> 104 continuation = c 105 } 106 } catch (e: CancellationException) { 107 expect(3) 108 } 109 } 110 expect(1) 111 yield() 112 job.cancel() // Cancel job 113 yield() 114 continuation!!.resume(Unit) // Should not fail 115 finish(4) 116 } 117 118 @Test 119 fun testCompleteJobWhileSuspended() = runTest { 120 expect(1) 121 val completableJob = Job() 122 val coroutineBlock = suspend { 123 assertFailsWith<CancellationException> { 124 suspendCancellableCoroutine<Unit> { cont -> 125 expect(2) 126 assertSame(completableJob, cont.context[Job]) 127 completableJob.complete() 128 } 129 expectUnreached() 130 } 131 expect(3) 132 } 133 coroutineBlock.startCoroutine(Continuation(completableJob) { 134 assertEquals(Unit, it.getOrNull()) 135 expect(4) 136 }) 137 finish(5) 138 } 139 }