• 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.test.*
7 
8 /**
9  * Test for [CancellableContinuation.resume] with `onCancellation` parameter.
10  */
11 @Suppress("DEPRECATION")
12 class CancellableResumeOldTest : TestBase() {
13     @Test
14     fun testResumeImmediateNormally() = runTest {
15         expect(1)
16         val ok = suspendCancellableCoroutine<String> { cont ->
17             expect(2)
18             cont.invokeOnCancellation { expectUnreached() }
19             cont.resume("OK") { expectUnreached() }
20             expect(3)
21         }
22         assertEquals("OK", ok)
23         finish(4)
24     }
25 
26     @Test
27     fun testResumeImmediateAfterCancel() = runTest(
28         expected = { it is TestException }
29     ) {
30         expect(1)
31         suspendCancellableCoroutine<String> { cont ->
32             expect(2)
33             cont.invokeOnCancellation { expect(3) }
34             cont.cancel(TestException("FAIL"))
35             expect(4)
36             cont.resume("OK") { cause ->
37                 expect(5)
38                 assertIs<TestException>(cause)
39             }
40             finish(6)
41         }
42         expectUnreached()
43     }
44 
45     @Test
46     fun testResumeImmediateAfterCancelWithHandlerFailure() = runTest(
47         expected = { it is TestException },
48         unhandled = listOf(
49             { it is CompletionHandlerException && it.cause is TestException2 },
50             { it is CompletionHandlerException && it.cause is TestException3 }
51         )
52     ) {
53         expect(1)
54         suspendCancellableCoroutine<String> { cont ->
55             expect(2)
56             cont.invokeOnCancellation {
57                 expect(3)
58                 throw TestException2("FAIL") // invokeOnCancellation handler fails with exception
59             }
60             cont.cancel(TestException("FAIL"))
61             expect(4)
62             cont.resume("OK") { cause ->
63                 expect(5)
64                 assertIs<TestException>(cause)
65                 throw TestException3("FAIL") // onCancellation block fails with exception
66             }
67             finish(6)
68         }
69         expectUnreached()
70     }
71 
72     @Test
73     fun testResumeImmediateAfterIndirectCancel() = runTest(
74         expected = { it is CancellationException }
75     ) {
76         expect(1)
77         val ctx = coroutineContext
78         suspendCancellableCoroutine<String> { cont ->
79             expect(2)
80             cont.invokeOnCancellation { expect(3) }
81             ctx.cancel()
82             expect(4)
83             cont.resume("OK") {
84                 expect(5)
85             }
86             finish(6)
87         }
88         expectUnreached()
89     }
90 
91     @Test
92     fun testResumeImmediateAfterIndirectCancelWithHandlerFailure() = runTest(
93         expected = { it is CancellationException },
94         unhandled = listOf(
95             { it is CompletionHandlerException && it.cause is TestException2 },
96             { it is CompletionHandlerException && it.cause is TestException3 }
97         )
98     ) {
99         expect(1)
100         val ctx = coroutineContext
101         suspendCancellableCoroutine<String> { cont ->
102             expect(2)
103             cont.invokeOnCancellation {
104                 expect(3)
105                 throw TestException2("FAIL") // invokeOnCancellation handler fails with exception
106             }
107             ctx.cancel()
108             expect(4)
109             cont.resume("OK") {
110                 expect(5)
111                 throw TestException3("FAIL") // onCancellation block fails with exception
112             }
113             finish(6)
114         }
115         expectUnreached()
116     }
117 
118     @Test
119     fun testResumeLaterNormally() = runTest {
120         expect(1)
121         lateinit var cc: CancellableContinuation<String>
122         launch(start = CoroutineStart.UNDISPATCHED) {
123             expect(2)
124             val ok = suspendCancellableCoroutine<String> { cont ->
125                 expect(3)
126                 cont.invokeOnCancellation { expectUnreached() }
127                 cc = cont
128             }
129             assertEquals("OK", ok)
130             finish(6)
131         }
132         expect(4)
133         cc.resume("OK") { expectUnreached() }
134         expect(5)
135     }
136 
137     @Test
138     fun testResumeLaterAfterCancel() = runTest {
139         expect(1)
140         lateinit var cc: CancellableContinuation<String>
141         val job = launch(start = CoroutineStart.UNDISPATCHED) {
142             expect(2)
143             try {
144                 suspendCancellableCoroutine<String> { cont ->
145                     expect(3)
146                     cont.invokeOnCancellation { expect(5) }
147                     cc = cont
148                 }
149                 expectUnreached()
150             } catch (e: CancellationException) {
151                 finish(9)
152             }
153         }
154         expect(4)
155         job.cancel(TestCancellationException())
156         expect(6)
157         cc.resume("OK") { cause ->
158             expect(7)
159             assertIs<TestCancellationException>(cause)
160         }
161         expect(8)
162     }
163 
164     @Test
165     fun testResumeLaterAfterCancelWithHandlerFailure() = runTest(
166         unhandled = listOf(
167             { it is CompletionHandlerException && it.cause is TestException2 },
168             { it is CompletionHandlerException && it.cause is TestException3 }
169         )
170     ) {
171         expect(1)
172         lateinit var cc: CancellableContinuation<String>
173         val job = launch(start = CoroutineStart.UNDISPATCHED) {
174             expect(2)
175             try {
176                 suspendCancellableCoroutine<String> { cont ->
177                     expect(3)
178                     cont.invokeOnCancellation {
179                         expect(5)
180                         throw TestException2("FAIL") // invokeOnCancellation handler fails with exception
181                     }
182                     cc = cont
183                 }
184                 expectUnreached()
185             } catch (e: CancellationException) {
186                 finish(9)
187             }
188         }
189         expect(4)
190         job.cancel(TestCancellationException())
191         expect(6)
192         cc.resume("OK") { cause ->
193             expect(7)
194             assertIs<TestCancellationException>(cause)
195             throw TestException3("FAIL") // onCancellation block fails with exception
196         }
197         expect(8)
198     }
199 
200     @Test
201     fun testResumeCancelWhileDispatched() = runTest {
202         expect(1)
203         lateinit var cc: CancellableContinuation<String>
204         val job = launch(start = CoroutineStart.UNDISPATCHED) {
205             expect(2)
206             try {
207                 suspendCancellableCoroutine<String> { cont ->
208                     expect(3)
209                     // resumed first, dispatched, then cancelled, but still got invokeOnCancellation call
210                     cont.invokeOnCancellation { cause ->
211                         // Note: invokeOnCancellation is called before cc.resume(value) { ... } handler
212                         expect(7)
213                         assertIs<TestCancellationException>(cause)
214                     }
215                     cc = cont
216                 }
217                 expectUnreached()
218             } catch (e: CancellationException) {
219                 expect(9)
220             }
221         }
222         expect(4)
223         cc.resume("OK") { cause ->
224             // Note: this handler is called after invokeOnCancellation handler
225             expect(8)
226             assertIs<TestCancellationException>(cause)
227         }
228         expect(5)
229         job.cancel(TestCancellationException()) // cancel while execution is dispatched
230         expect(6)
231         yield() // to coroutine -- throws cancellation exception
232         finish(10)
233     }
234 
235     @Test
236     fun testResumeCancelWhileDispatchedWithHandlerFailure() = runTest(
237         unhandled = listOf(
238             { it is CompletionHandlerException && it.cause is TestException2 },
239             { it is CompletionHandlerException && it.cause is TestException3 }
240         )
241     ) {
242         expect(1)
243         lateinit var cc: CancellableContinuation<String>
244         val job = launch(start = CoroutineStart.UNDISPATCHED) {
245             expect(2)
246             try {
247                 suspendCancellableCoroutine<String> { cont ->
248                     expect(3)
249                     // resumed first, dispatched, then cancelled, but still got invokeOnCancellation call
250                     cont.invokeOnCancellation { cause ->
251                         // Note: invokeOnCancellation is called before cc.resume(value) { ... } handler
252                         expect(7)
253                         assertIs<TestCancellationException>(cause)
254                         throw TestException2("FAIL") // invokeOnCancellation handler fails with exception
255                     }
256                     cc = cont
257                 }
258                 expectUnreached()
259             } catch (e: CancellationException) {
260                 expect(9)
261             }
262         }
263         expect(4)
264         cc.resume("OK") { cause ->
265             // Note: this handler is called after invokeOnCancellation handler
266             expect(8)
267             assertIs<TestCancellationException>(cause)
268             throw TestException3("FAIL") // onCancellation block fails with exception
269         }
270         expect(5)
271         job.cancel(TestCancellationException()) // cancel while execution is dispatched
272         expect(6)
273         yield() // to coroutine -- throws cancellation exception
274         finish(10)
275     }
276 
277     @Test
278     fun testResumeUnconfined() = runTest {
279         val outerScope = this
280         withContext(Dispatchers.Unconfined) {
281             val result = suspendCancellableCoroutine<String> {
282                 outerScope.launch {
283                     it.resume("OK") {
284                         expectUnreached()
285                     }
286                 }
287             }
288             assertEquals("OK", result)
289         }
290     }
291 }
292