1 package kotlinx.coroutines 2 3 import kotlinx.coroutines.testing.* 4 import kotlin.coroutines.* 5 import kotlin.test.* 6 7 /** 8 * When using [suspendCoroutine] from the standard library the continuation must be dispatched atomically, 9 * without checking for cancellation at any point in time. 10 */ 11 class DispatchedContinuationTest : TestBase() { 12 private lateinit var cont: Continuation<String> 13 14 @Test testCancelThenResumenull15 fun testCancelThenResume() = runTest { 16 expect(1) 17 launch(start = CoroutineStart.UNDISPATCHED) { 18 expect(2) 19 coroutineContext[Job]!!.cancel() 20 // a regular suspendCoroutine will still suspend despite the fact that coroutine was cancelled 21 val value = suspendCoroutine<String> { 22 expect(3) 23 cont = it 24 } 25 expect(6) 26 assertEquals("OK", value) 27 } 28 expect(4) 29 cont.resume("OK") 30 expect(5) 31 yield() // to the launched job 32 finish(7) 33 } 34 35 @Test <lambda>null36 fun testCancelThenResumeUnconfined() = runTest { 37 expect(1) 38 launch(Dispatchers.Unconfined) { 39 expect(2) 40 coroutineContext[Job]!!.cancel() 41 // a regular suspendCoroutine will still suspend despite the fact that coroutine was cancelled 42 val value = suspendCoroutine<String> { 43 expect(3) 44 cont = it 45 } 46 expect(5) 47 assertEquals("OK", value) 48 } 49 expect(4) 50 cont.resume("OK") // immediately resumes -- because unconfined 51 finish(6) 52 } 53 54 @Test <lambda>null55 fun testResumeThenCancel() = runTest { 56 expect(1) 57 val job = launch(start = CoroutineStart.UNDISPATCHED) { 58 expect(2) 59 val value = suspendCoroutine<String> { 60 expect(3) 61 cont = it 62 } 63 expect(7) 64 assertEquals("OK", value) 65 } 66 expect(4) 67 cont.resume("OK") 68 expect(5) 69 // now cancel the job, which the coroutine is waiting to be dispatched 70 job.cancel() 71 expect(6) 72 yield() // to the launched job 73 finish(8) 74 } 75 }