Roman Elizarov | 9d5abcd | 2017-12-21 16:54:30 +0300 | [diff] [blame] | 1 | |
Roman Elizarov | a7db8ec | 2017-12-21 22:45:12 +0300 | [diff] [blame] | 2 | /* |
Roman Elizarov | 1f74a2d | 2018-06-29 19:19:45 +0300 | [diff] [blame] | 3 | * Copyright 2016-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license. |
Roman Elizarov | a7db8ec | 2017-12-21 22:45:12 +0300 | [diff] [blame] | 4 | */ |
| 5 | |
Louis CAD | 919284b | 2019-02-19 16:17:56 +0100 | [diff] [blame] | 6 | @file:Suppress("NAMED_ARGUMENTS_NOT_ALLOWED") // KT-22237 |
Roman Elizarov | 4fe1801 | 2017-03-07 17:32:48 +0300 | [diff] [blame] | 7 | |
Roman Elizarov | 0950dfa | 2018-07-13 10:33:25 +0300 | [diff] [blame] | 8 | package kotlinx.coroutines |
Roman Elizarov | 4fe1801 | 2017-03-07 17:32:48 +0300 | [diff] [blame] | 9 | |
Roman Elizarov | 9d5abcd | 2017-12-21 16:54:30 +0300 | [diff] [blame] | 10 | import kotlin.test.* |
Roman Elizarov | 4fe1801 | 2017-03-07 17:32:48 +0300 | [diff] [blame] | 11 | |
Roman Elizarov | aa461cf | 2018-04-11 13:20:29 +0300 | [diff] [blame] | 12 | class WithContextTest : TestBase() { |
Vsevolod Tolstopyatov | 931587a | 2018-04-16 17:51:12 +0300 | [diff] [blame] | 13 | |
Roman Elizarov | 4fe1801 | 2017-03-07 17:32:48 +0300 | [diff] [blame] | 14 | @Test |
Vsevolod Tolstopyatov | 06f57aa | 2018-07-24 19:51:21 +0300 | [diff] [blame] | 15 | fun testThrowException() = runTest { |
| 16 | expect(1) |
| 17 | try { |
Vsevolod Tolstopyatov | c022ab6 | 2019-05-14 15:10:09 +0300 | [diff] [blame^] | 18 | withContext<Unit>(coroutineContext) { |
Vsevolod Tolstopyatov | 06f57aa | 2018-07-24 19:51:21 +0300 | [diff] [blame] | 19 | expect(2) |
| 20 | throw AssertionError() |
| 21 | } |
| 22 | } catch (e: AssertionError) { |
| 23 | expect(3) |
| 24 | } |
| 25 | |
| 26 | yield() |
| 27 | finish(4) |
| 28 | } |
| 29 | |
| 30 | @Test |
| 31 | fun testThrowExceptionFromWrappedContext() = runTest { |
| 32 | expect(1) |
| 33 | try { |
Vsevolod Tolstopyatov | c022ab6 | 2019-05-14 15:10:09 +0300 | [diff] [blame^] | 34 | withContext<Unit>(wrapperDispatcher(coroutineContext)) { |
Vsevolod Tolstopyatov | 06f57aa | 2018-07-24 19:51:21 +0300 | [diff] [blame] | 35 | expect(2) |
| 36 | throw AssertionError() |
| 37 | } |
| 38 | } catch (e: AssertionError) { |
| 39 | expect(3) |
| 40 | } |
| 41 | |
| 42 | yield() |
| 43 | finish(4) |
| 44 | } |
| 45 | |
| 46 | @Test |
Roman Elizarov | 8b38fa2 | 2017-09-27 17:44:31 +0300 | [diff] [blame] | 47 | fun testSameContextNoSuspend() = runTest { |
Roman Elizarov | 4fe1801 | 2017-03-07 17:32:48 +0300 | [diff] [blame] | 48 | expect(1) |
Roman Elizarov | 43e3af7 | 2017-07-21 16:01:31 +0300 | [diff] [blame] | 49 | launch(coroutineContext) { // make sure there is not early dispatch here |
Roman Elizarov | 8b38fa2 | 2017-09-27 17:44:31 +0300 | [diff] [blame] | 50 | finish(5) // after main exits |
Roman Elizarov | 4fe1801 | 2017-03-07 17:32:48 +0300 | [diff] [blame] | 51 | } |
| 52 | expect(2) |
Roman Elizarov | f9e13f5 | 2017-12-21 12:23:15 +0300 | [diff] [blame] | 53 | val result = withContext(coroutineContext) { // same context! |
Roman Elizarov | 4fe1801 | 2017-03-07 17:32:48 +0300 | [diff] [blame] | 54 | expect(3) // still here |
Vsevolod Tolstopyatov | ecfd227 | 2018-11-14 19:47:52 +0300 | [diff] [blame] | 55 | "OK".wrap() |
| 56 | }.unwrap() |
Roman Elizarov | 9d5abcd | 2017-12-21 16:54:30 +0300 | [diff] [blame] | 57 | assertEquals("OK", result) |
Roman Elizarov | 8b38fa2 | 2017-09-27 17:44:31 +0300 | [diff] [blame] | 58 | expect(4) |
| 59 | // will wait for the first coroutine |
Roman Elizarov | 4fe1801 | 2017-03-07 17:32:48 +0300 | [diff] [blame] | 60 | } |
| 61 | |
| 62 | @Test |
Roman Elizarov | 8b38fa2 | 2017-09-27 17:44:31 +0300 | [diff] [blame] | 63 | fun testSameContextWithSuspend() = runTest { |
Roman Elizarov | 4fe1801 | 2017-03-07 17:32:48 +0300 | [diff] [blame] | 64 | expect(1) |
Roman Elizarov | 43e3af7 | 2017-07-21 16:01:31 +0300 | [diff] [blame] | 65 | launch(coroutineContext) { // make sure there is not early dispatch here |
Roman Elizarov | 4fe1801 | 2017-03-07 17:32:48 +0300 | [diff] [blame] | 66 | expect(4) |
| 67 | } |
| 68 | expect(2) |
Roman Elizarov | f9e13f5 | 2017-12-21 12:23:15 +0300 | [diff] [blame] | 69 | val result = withContext(coroutineContext) { // same context! |
Roman Elizarov | 4fe1801 | 2017-03-07 17:32:48 +0300 | [diff] [blame] | 70 | expect(3) // still here |
| 71 | yield() // now yields to launch! |
| 72 | expect(5) |
Vsevolod Tolstopyatov | ecfd227 | 2018-11-14 19:47:52 +0300 | [diff] [blame] | 73 | "OK".wrap() |
| 74 | }.unwrap() |
Roman Elizarov | 9d5abcd | 2017-12-21 16:54:30 +0300 | [diff] [blame] | 75 | assertEquals("OK", result) |
Roman Elizarov | 4fe1801 | 2017-03-07 17:32:48 +0300 | [diff] [blame] | 76 | finish(6) |
| 77 | } |
| 78 | |
| 79 | @Test |
Roman Elizarov | 8b38fa2 | 2017-09-27 17:44:31 +0300 | [diff] [blame] | 80 | fun testCancelWithJobNoSuspend() = runTest { |
Roman Elizarov | 4fe1801 | 2017-03-07 17:32:48 +0300 | [diff] [blame] | 81 | expect(1) |
Roman Elizarov | 43e3af7 | 2017-07-21 16:01:31 +0300 | [diff] [blame] | 82 | launch(coroutineContext) { // make sure there is not early dispatch to here |
Roman Elizarov | 8b38fa2 | 2017-09-27 17:44:31 +0300 | [diff] [blame] | 83 | finish(6) // after main exits |
Roman Elizarov | 4fe1801 | 2017-03-07 17:32:48 +0300 | [diff] [blame] | 84 | } |
| 85 | expect(2) |
| 86 | val job = Job() |
Vsevolod Tolstopyatov | 78832e3 | 2018-11-04 15:32:34 +0300 | [diff] [blame] | 87 | try { |
| 88 | withContext(coroutineContext + job) { |
| 89 | // same context + new job |
| 90 | expect(3) // still here |
| 91 | job.cancel() // cancel out job! |
| 92 | try { |
| 93 | yield() // shall throw CancellationException |
| 94 | expectUnreached() |
| 95 | } catch (e: CancellationException) { |
| 96 | expect(4) |
| 97 | } |
Vsevolod Tolstopyatov | ecfd227 | 2018-11-14 19:47:52 +0300 | [diff] [blame] | 98 | "OK".wrap() |
Roman Elizarov | 4fe1801 | 2017-03-07 17:32:48 +0300 | [diff] [blame] | 99 | } |
Vsevolod Tolstopyatov | 78832e3 | 2018-11-04 15:32:34 +0300 | [diff] [blame] | 100 | |
| 101 | expectUnreached() |
| 102 | } catch (e: CancellationException) { |
| 103 | expect(5) |
| 104 | // will wait for the first coroutine |
Roman Elizarov | 4fe1801 | 2017-03-07 17:32:48 +0300 | [diff] [blame] | 105 | } |
Roman Elizarov | 4fe1801 | 2017-03-07 17:32:48 +0300 | [diff] [blame] | 106 | } |
| 107 | |
| 108 | @Test |
Roman Elizarov | 0a656ff | 2018-09-25 16:33:42 +0300 | [diff] [blame] | 109 | fun testCancelWithJobWithSuspend() = runTest( |
| 110 | expected = { it is CancellationException } |
| 111 | ) { |
Roman Elizarov | 4fe1801 | 2017-03-07 17:32:48 +0300 | [diff] [blame] | 112 | expect(1) |
Roman Elizarov | 43e3af7 | 2017-07-21 16:01:31 +0300 | [diff] [blame] | 113 | launch(coroutineContext) { // make sure there is not early dispatch to here |
Roman Elizarov | 4fe1801 | 2017-03-07 17:32:48 +0300 | [diff] [blame] | 114 | expect(4) |
| 115 | } |
| 116 | expect(2) |
| 117 | val job = Job() |
Roman Elizarov | 0a656ff | 2018-09-25 16:33:42 +0300 | [diff] [blame] | 118 | withContext(coroutineContext + job) { // same context + new job |
Roman Elizarov | 4fe1801 | 2017-03-07 17:32:48 +0300 | [diff] [blame] | 119 | expect(3) // still here |
| 120 | yield() // now yields to launch! |
| 121 | expect(5) |
| 122 | job.cancel() // cancel out job! |
| 123 | try { |
Roman Elizarov | 9d5abcd | 2017-12-21 16:54:30 +0300 | [diff] [blame] | 124 | yield() // shall throw CancellationException |
Roman Elizarov | 4fe1801 | 2017-03-07 17:32:48 +0300 | [diff] [blame] | 125 | expectUnreached() |
| 126 | } catch (e: CancellationException) { |
Roman Elizarov | 0a656ff | 2018-09-25 16:33:42 +0300 | [diff] [blame] | 127 | finish(6) |
Roman Elizarov | 4fe1801 | 2017-03-07 17:32:48 +0300 | [diff] [blame] | 128 | } |
Vsevolod Tolstopyatov | ecfd227 | 2018-11-14 19:47:52 +0300 | [diff] [blame] | 129 | "OK".wrap() |
Roman Elizarov | 4fe1801 | 2017-03-07 17:32:48 +0300 | [diff] [blame] | 130 | } |
Roman Elizarov | 0a656ff | 2018-09-25 16:33:42 +0300 | [diff] [blame] | 131 | // still fails, because parent job was cancelled |
| 132 | expectUnreached() |
Roman Elizarov | 4fe1801 | 2017-03-07 17:32:48 +0300 | [diff] [blame] | 133 | } |
| 134 | |
| 135 | @Test |
Roman Elizarov | 8b38fa2 | 2017-09-27 17:44:31 +0300 | [diff] [blame] | 136 | fun testRunCancellableDefault() = runTest( |
Vsevolod Tolstopyatov | a2d8088 | 2018-09-24 19:51:49 +0300 | [diff] [blame] | 137 | expected = { it is CancellationException } |
Roman Elizarov | 8b38fa2 | 2017-09-27 17:44:31 +0300 | [diff] [blame] | 138 | ) { |
Roman Elizarov | 4eae2a8 | 2017-05-17 20:55:27 +0300 | [diff] [blame] | 139 | val job = Job() |
| 140 | job.cancel() // cancel before it has a chance to run |
Roman Elizarov | f9e13f5 | 2017-12-21 12:23:15 +0300 | [diff] [blame] | 141 | withContext(job + wrapperDispatcher(coroutineContext)) { |
Roman Elizarov | 4eae2a8 | 2017-05-17 20:55:27 +0300 | [diff] [blame] | 142 | expectUnreached() // will get cancelled |
| 143 | } |
| 144 | } |
| 145 | |
Roman Elizarov | 8b38fa2 | 2017-09-27 17:44:31 +0300 | [diff] [blame] | 146 | @Test |
Roman Elizarov | 0f94304 | 2018-10-08 16:13:01 +0300 | [diff] [blame] | 147 | fun testRunCancellationUndispatchedVsException() = runTest { |
| 148 | expect(1) |
| 149 | var job: Job? = null |
| 150 | job = launch(start = CoroutineStart.UNDISPATCHED) { |
| 151 | expect(2) |
| 152 | try { |
| 153 | // Same dispatcher, different context |
Vsevolod Tolstopyatov | c022ab6 | 2019-05-14 15:10:09 +0300 | [diff] [blame^] | 154 | withContext<Unit>(CoroutineName("testRunCancellationUndispatchedVsException")) { |
Roman Elizarov | 0f94304 | 2018-10-08 16:13:01 +0300 | [diff] [blame] | 155 | expect(3) |
| 156 | yield() // must suspend |
| 157 | expect(5) |
| 158 | job!!.cancel() // cancel this job _before_ it throws |
| 159 | throw TestException() |
| 160 | } |
| 161 | } catch (e: TestException) { |
| 162 | // must have caught TextException |
| 163 | expect(6) |
| 164 | } |
| 165 | } |
| 166 | expect(4) |
| 167 | yield() // to coroutineScope |
| 168 | finish(7) |
| 169 | } |
| 170 | |
| 171 | @Test |
| 172 | fun testRunCancellationDispatchedVsException() = runTest { |
| 173 | expect(1) |
| 174 | var job: Job? = null |
| 175 | job = launch(start = CoroutineStart.UNDISPATCHED) { |
| 176 | expect(2) |
| 177 | try { |
| 178 | // "Different" dispatcher (schedules execution back and forth) |
Vsevolod Tolstopyatov | c022ab6 | 2019-05-14 15:10:09 +0300 | [diff] [blame^] | 179 | withContext<Unit>(wrapperDispatcher(coroutineContext)) { |
Roman Elizarov | 0f94304 | 2018-10-08 16:13:01 +0300 | [diff] [blame] | 180 | expect(4) |
| 181 | yield() // must suspend |
| 182 | expect(6) |
| 183 | job!!.cancel() // cancel this job _before_ it throws |
| 184 | throw TestException() |
| 185 | } |
| 186 | } catch (e: TestException) { |
| 187 | // must have caught TextException |
| 188 | expect(8) |
| 189 | } |
| 190 | } |
| 191 | expect(3) |
| 192 | yield() // withContext is next |
| 193 | expect(5) |
| 194 | yield() // withContext again |
| 195 | expect(7) |
| 196 | yield() // to catch block |
| 197 | finish(9) |
| 198 | } |
| 199 | |
| 200 | @Test |
Roman Elizarov | 0aad8f1 | 2019-03-01 12:08:43 +0300 | [diff] [blame] | 201 | fun testRunSelfCancellationWithException() = runTest { |
Roman Elizarov | bcdd8e1 | 2017-10-20 16:42:06 +0800 | [diff] [blame] | 202 | expect(1) |
| 203 | var job: Job? = null |
Roman Elizarov | c32579e | 2018-09-09 19:21:43 +0300 | [diff] [blame] | 204 | job = launch(Job()) { |
Roman Elizarov | bcdd8e1 | 2017-10-20 16:42:06 +0800 | [diff] [blame] | 205 | try { |
| 206 | expect(3) |
Vsevolod Tolstopyatov | c022ab6 | 2019-05-14 15:10:09 +0300 | [diff] [blame^] | 207 | withContext<Unit>(wrapperDispatcher(coroutineContext)) { |
Vsevolod Tolstopyatov | f3a5013 | 2018-04-16 19:41:20 +0300 | [diff] [blame] | 208 | require(isActive) |
Roman Elizarov | bcdd8e1 | 2017-10-20 16:42:06 +0800 | [diff] [blame] | 209 | expect(5) |
Vsevolod Tolstopyatov | b058ba1 | 2018-10-17 15:15:17 +0300 | [diff] [blame] | 210 | job!!.cancel() |
Vsevolod Tolstopyatov | 4aa18aa | 2018-04-17 15:43:12 +0300 | [diff] [blame] | 211 | require(!isActive) |
Roman Elizarov | 0aad8f1 | 2019-03-01 12:08:43 +0300 | [diff] [blame] | 212 | throw TestException() // but throw an exception |
Roman Elizarov | bcdd8e1 | 2017-10-20 16:42:06 +0800 | [diff] [blame] | 213 | } |
| 214 | } catch (e: Throwable) { |
| 215 | expect(7) |
Roman Elizarov | 0aad8f1 | 2019-03-01 12:08:43 +0300 | [diff] [blame] | 216 | // make sure TestException, not CancellationException is thrown |
Roman Elizarov | 0d7323a | 2018-01-29 20:59:15 +0300 | [diff] [blame] | 217 | assertTrue(e is TestException, "Caught $e") |
Roman Elizarov | bcdd8e1 | 2017-10-20 16:42:06 +0800 | [diff] [blame] | 218 | } |
| 219 | } |
| 220 | expect(2) |
| 221 | yield() // to the launched job |
| 222 | expect(4) |
| 223 | yield() // again to the job |
| 224 | expect(6) |
| 225 | yield() // again to exception handler |
| 226 | finish(8) |
| 227 | } |
| 228 | |
Vsevolod Tolstopyatov | 931587a | 2018-04-16 17:51:12 +0300 | [diff] [blame] | 229 | @Test |
Roman Elizarov | 0aad8f1 | 2019-03-01 12:08:43 +0300 | [diff] [blame] | 230 | fun testRunSelfCancellation() = runTest { |
Vsevolod Tolstopyatov | 931587a | 2018-04-16 17:51:12 +0300 | [diff] [blame] | 231 | expect(1) |
| 232 | var job: Job? = null |
Roman Elizarov | c32579e | 2018-09-09 19:21:43 +0300 | [diff] [blame] | 233 | job = launch(Job()) { |
Vsevolod Tolstopyatov | 931587a | 2018-04-16 17:51:12 +0300 | [diff] [blame] | 234 | try { |
| 235 | expect(3) |
| 236 | withContext(wrapperDispatcher(coroutineContext)) { |
Vsevolod Tolstopyatov | 4aa18aa | 2018-04-17 15:43:12 +0300 | [diff] [blame] | 237 | require(isActive) |
Vsevolod Tolstopyatov | 931587a | 2018-04-16 17:51:12 +0300 | [diff] [blame] | 238 | expect(5) |
Vsevolod Tolstopyatov | b058ba1 | 2018-10-17 15:15:17 +0300 | [diff] [blame] | 239 | job!!.cancel() // cancel itself |
Vsevolod Tolstopyatov | 4aa18aa | 2018-04-17 15:43:12 +0300 | [diff] [blame] | 240 | require(!isActive) |
Vsevolod Tolstopyatov | ecfd227 | 2018-11-14 19:47:52 +0300 | [diff] [blame] | 241 | "OK".wrap() |
Vsevolod Tolstopyatov | 931587a | 2018-04-16 17:51:12 +0300 | [diff] [blame] | 242 | } |
Vsevolod Tolstopyatov | ecfd227 | 2018-11-14 19:47:52 +0300 | [diff] [blame] | 243 | expectUnreached() |
Vsevolod Tolstopyatov | 931587a | 2018-04-16 17:51:12 +0300 | [diff] [blame] | 244 | } catch (e: Throwable) { |
Vsevolod Tolstopyatov | f3a5013 | 2018-04-16 19:41:20 +0300 | [diff] [blame] | 245 | expect(7) |
Roman Elizarov | 0aad8f1 | 2019-03-01 12:08:43 +0300 | [diff] [blame] | 246 | // make sure CancellationException is thrown |
Vsevolod Tolstopyatov | a2d8088 | 2018-09-24 19:51:49 +0300 | [diff] [blame] | 247 | assertTrue(e is CancellationException, "Caught $e") |
Vsevolod Tolstopyatov | 931587a | 2018-04-16 17:51:12 +0300 | [diff] [blame] | 248 | } |
| 249 | } |
| 250 | |
| 251 | expect(2) |
| 252 | yield() // to the launched job |
| 253 | expect(4) |
| 254 | yield() // again to the job |
| 255 | expect(6) |
| 256 | yield() // again to exception handler |
| 257 | finish(8) |
| 258 | } |
| 259 | |
Roman Elizarov | 0a656ff | 2018-09-25 16:33:42 +0300 | [diff] [blame] | 260 | @Test |
| 261 | fun testWithContextScopeFailure() = runTest { |
| 262 | expect(1) |
| 263 | try { |
| 264 | withContext(wrapperDispatcher(coroutineContext)) { |
| 265 | expect(2) |
| 266 | // launch a child that fails |
| 267 | launch { |
| 268 | expect(4) |
| 269 | throw TestException() |
| 270 | } |
| 271 | expect(3) |
Vsevolod Tolstopyatov | ecfd227 | 2018-11-14 19:47:52 +0300 | [diff] [blame] | 272 | "OK".wrap() |
Roman Elizarov | 0a656ff | 2018-09-25 16:33:42 +0300 | [diff] [blame] | 273 | } |
Vsevolod Tolstopyatov | ecfd227 | 2018-11-14 19:47:52 +0300 | [diff] [blame] | 274 | expectUnreached() |
Roman Elizarov | 0a656ff | 2018-09-25 16:33:42 +0300 | [diff] [blame] | 275 | } catch (e: TestException) { |
| 276 | // ensure that we can catch exception outside of the scope |
| 277 | expect(5) |
| 278 | } |
| 279 | finish(6) |
| 280 | } |
| 281 | |
| 282 | @Test |
| 283 | fun testWithContextChildWaitSameContext() = runTest { |
| 284 | expect(1) |
| 285 | withContext(coroutineContext) { |
| 286 | expect(2) |
| 287 | launch { |
| 288 | // ^^^ schedules to main thread |
| 289 | expect(4) // waits before return |
| 290 | } |
| 291 | expect(3) |
Vsevolod Tolstopyatov | ecfd227 | 2018-11-14 19:47:52 +0300 | [diff] [blame] | 292 | "OK".wrap() |
| 293 | }.unwrap() |
Roman Elizarov | 0a656ff | 2018-09-25 16:33:42 +0300 | [diff] [blame] | 294 | finish(5) |
| 295 | } |
| 296 | |
| 297 | @Test |
| 298 | fun testWithContextChildWaitWrappedContext() = runTest { |
| 299 | expect(1) |
| 300 | withContext(wrapperDispatcher(coroutineContext)) { |
| 301 | expect(2) |
| 302 | launch { |
| 303 | // ^^^ schedules to main thread |
| 304 | expect(4) // waits before return |
| 305 | } |
| 306 | expect(3) |
Vsevolod Tolstopyatov | ecfd227 | 2018-11-14 19:47:52 +0300 | [diff] [blame] | 307 | "OK".wrap() |
| 308 | }.unwrap() |
Roman Elizarov | 0a656ff | 2018-09-25 16:33:42 +0300 | [diff] [blame] | 309 | finish(5) |
| 310 | } |
Vsevolod Tolstopyatov | ecfd227 | 2018-11-14 19:47:52 +0300 | [diff] [blame] | 311 | |
| 312 | @Test |
| 313 | fun testIncompleteWithContextState() = runTest { |
| 314 | lateinit var ctxJob: Job |
| 315 | withContext(wrapperDispatcher(coroutineContext)) { |
| 316 | ctxJob = coroutineContext[Job]!! |
| 317 | ctxJob.invokeOnCompletion { } |
| 318 | } |
| 319 | |
| 320 | ctxJob.join() |
| 321 | assertTrue(ctxJob.isCompleted) |
| 322 | assertFalse(ctxJob.isActive) |
| 323 | assertFalse(ctxJob.isCancelled) |
| 324 | } |
| 325 | |
Roman Elizarov | 4451d72 | 2019-02-22 14:27:20 +0300 | [diff] [blame] | 326 | @Test |
| 327 | fun testWithContextCancelledJob() = runTest { |
| 328 | expect(1) |
| 329 | val job = Job() |
| 330 | job.cancel() |
| 331 | try { |
| 332 | withContext(job) { |
| 333 | expectUnreached() |
| 334 | } |
| 335 | } catch (e: CancellationException) { |
| 336 | expect(2) |
| 337 | } |
| 338 | finish(3) |
| 339 | } |
| 340 | |
| 341 | @Test |
| 342 | fun testWithContextCancelledThisJob() = runTest( |
| 343 | expected = { it is CancellationException } |
| 344 | ) { |
| 345 | coroutineContext.cancel() |
| 346 | withContext(wrapperDispatcher(coroutineContext)) { |
| 347 | expectUnreached() |
| 348 | } |
| 349 | expectUnreached() |
| 350 | } |
| 351 | |
Vsevolod Tolstopyatov | c022ab6 | 2019-05-14 15:10:09 +0300 | [diff] [blame^] | 352 | @Test |
| 353 | fun testSequentialCancellation() = runTest { |
| 354 | val job = launch { |
| 355 | expect(1) |
| 356 | withContext(wrapperDispatcher()) { |
| 357 | expect(2) |
| 358 | } |
| 359 | expectUnreached() |
| 360 | } |
| 361 | |
| 362 | yield() |
| 363 | val job2 = launch { |
| 364 | expect(3) |
| 365 | job.cancel() |
| 366 | } |
| 367 | |
| 368 | joinAll(job, job2) |
| 369 | finish(4) |
| 370 | } |
| 371 | |
Vsevolod Tolstopyatov | ecfd227 | 2018-11-14 19:47:52 +0300 | [diff] [blame] | 372 | private class Wrapper(val value: String) : Incomplete { |
| 373 | override val isActive: Boolean |
| 374 | get() = error("") |
| 375 | override val list: NodeList? |
| 376 | get() = error("") |
| 377 | } |
| 378 | |
| 379 | private fun String.wrap() = Wrapper(this) |
| 380 | private fun Wrapper.unwrap() = value |
Vsevolod Tolstopyatov | 931587a | 2018-04-16 17:51:12 +0300 | [diff] [blame] | 381 | } |