1 package kotlinx.coroutines 2 3 import kotlinx.coroutines.testing.* 4 import kotlinx.coroutines.channels.* 5 import kotlinx.coroutines.selects.* 6 import kotlin.test.* 7 8 class AtomicCancellationTest : TestBase() { 9 @Test <lambda>null10 fun testSendCancellable() = runBlocking { 11 expect(1) 12 val channel = Channel<Int>() 13 val job = launch(start = CoroutineStart.UNDISPATCHED) { 14 expect(2) 15 channel.send(42) // suspends 16 expectUnreached() // should NOT execute because of cancellation 17 } 18 expect(3) 19 assertEquals(42, channel.receive()) // will schedule sender for further execution 20 job.cancel() // cancel the job next 21 yield() // now yield 22 finish(4) 23 } 24 25 @Suppress("UNUSED_VARIABLE") 26 @Test <lambda>null27 fun testSelectSendCancellable() = runBlocking { 28 expect(1) 29 val channel = Channel<Int>() 30 val job = launch(start = CoroutineStart.UNDISPATCHED) { 31 expect(2) 32 val result = select<String> { // suspends 33 channel.onSend(42) { 34 expect(4) 35 "OK" 36 } 37 } 38 expectUnreached() // should NOT execute because of cancellation 39 } 40 expect(3) 41 assertEquals(42, channel.receive()) // will schedule sender for further execution 42 job.cancel() // cancel the job next 43 yield() // now yield 44 finish(4) 45 } 46 47 @Test <lambda>null48 fun testReceiveCancellable() = runBlocking { 49 expect(1) 50 val channel = Channel<Int>() 51 val job = launch(start = CoroutineStart.UNDISPATCHED) { 52 expect(2) 53 assertEquals(42, channel.receive()) // suspends 54 expectUnreached() // should NOT execute because of cancellation 55 } 56 expect(3) 57 channel.send(42) // will schedule receiver for further execution 58 job.cancel() // cancel the job next 59 yield() // now yield 60 finish(4) 61 } 62 63 @Test <lambda>null64 fun testSelectReceiveCancellable() = runBlocking { 65 expect(1) 66 val channel = Channel<Int>() 67 val job = launch(start = CoroutineStart.UNDISPATCHED) { 68 expect(2) 69 val result = select<String> { // suspends 70 channel.onReceive { 71 assertEquals(42, it) 72 expect(4) 73 "OK" 74 } 75 } 76 expectUnreached() // should NOT execute because of cancellation 77 } 78 expect(3) 79 channel.send(42) // will schedule receiver for further execution 80 job.cancel() // cancel the job next 81 yield() // now yield 82 finish(4) 83 } 84 85 @Test <lambda>null86 fun testSelectDeferredAwaitCancellable() = runBlocking { 87 expect(1) 88 val deferred = async { // deferred, not yet complete 89 expect(4) 90 "OK" 91 } 92 assertEquals(false, deferred.isCompleted) 93 var job: Job? = null 94 launch { // will cancel job as soon as deferred completes 95 expect(5) 96 assertEquals(true, deferred.isCompleted) 97 job!!.cancel() 98 } 99 job = launch(start = CoroutineStart.UNDISPATCHED) { 100 expect(2) 101 try { 102 select<Unit> { // suspends 103 deferred.onAwait { expectUnreached() } 104 } 105 expectUnreached() // will not execute -- cancelled while dispatched 106 } finally { 107 finish(7) // but will execute finally blocks 108 } 109 } 110 expect(3) // continues to execute when the job suspends 111 yield() // to deferred & canceller 112 expect(6) 113 } 114 115 @Test <lambda>null116 fun testSelectJobJoinCancellable() = runBlocking { 117 expect(1) 118 val jobToJoin = launch { // not yet complete 119 expect(4) 120 } 121 assertEquals(false, jobToJoin.isCompleted) 122 var job: Job? = null 123 launch { // will cancel job as soon as jobToJoin completes 124 expect(5) 125 assertEquals(true, jobToJoin.isCompleted) 126 job!!.cancel() 127 } 128 job = launch(start = CoroutineStart.UNDISPATCHED) { 129 expect(2) 130 try { 131 select<Unit> { // suspends 132 jobToJoin.onJoin { expectUnreached() } 133 } 134 expectUnreached() // will not execute -- cancelled while dispatched 135 } finally { 136 finish(7) // but will execute finally blocks 137 } 138 } 139 expect(3) // continues to execute when the job suspends 140 yield() // to jobToJoin & canceller 141 expect(6) 142 } 143 } 144