• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download

<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 }