Roman Elizarov | f16fd27 | 2017-02-07 11:26:00 +0300 | [diff] [blame] | 1 | /* |
| 2 | * Copyright 2016-2017 JetBrains s.r.o. |
| 3 | * |
| 4 | * Licensed under the Apache License, Version 2.0 (the "License"); |
| 5 | * you may not use this file except in compliance with the License. |
| 6 | * You may obtain a copy of the License at |
| 7 | * |
| 8 | * http://www.apache.org/licenses/LICENSE-2.0 |
| 9 | * |
| 10 | * Unless required by applicable law or agreed to in writing, software |
| 11 | * distributed under the License is distributed on an "AS IS" BASIS, |
| 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| 13 | * See the License for the specific language governing permissions and |
| 14 | * limitations under the License. |
| 15 | */ |
| 16 | |
Roman Elizarov | e3f2884 | 2017-12-21 19:15:40 +0300 | [diff] [blame] | 17 | @file:Suppress("NAMED_ARGUMENTS_NOT_ALLOWED") // KT-21913 |
| 18 | |
Roman Elizarov | 41c5c8b | 2017-01-25 13:37:15 +0300 | [diff] [blame] | 19 | package kotlinx.coroutines.experimental |
| 20 | |
Roman Elizarov | 9fe5f46 | 2018-02-21 19:05:52 +0300 | [diff] [blame] | 21 | import kotlin.coroutines.experimental.* |
Roman Elizarov | e3f2884 | 2017-12-21 19:15:40 +0300 | [diff] [blame] | 22 | import kotlin.test.* |
Roman Elizarov | 41c5c8b | 2017-01-25 13:37:15 +0300 | [diff] [blame] | 23 | |
Roman Elizarov | aa461cf | 2018-04-11 13:20:29 +0300 | [diff] [blame] | 24 | class AsyncLazyTest : TestBase() { |
Roman Elizarov | 41c5c8b | 2017-01-25 13:37:15 +0300 | [diff] [blame] | 25 | @Test |
Roman Elizarov | e3f2884 | 2017-12-21 19:15:40 +0300 | [diff] [blame] | 26 | fun testSimple() = runTest { |
Roman Elizarov | 41c5c8b | 2017-01-25 13:37:15 +0300 | [diff] [blame] | 27 | expect(1) |
Roman Elizarov | 43e3af7 | 2017-07-21 16:01:31 +0300 | [diff] [blame] | 28 | val d = async(coroutineContext, CoroutineStart.LAZY) { |
Roman Elizarov | 41c5c8b | 2017-01-25 13:37:15 +0300 | [diff] [blame] | 29 | expect(3) |
| 30 | 42 |
| 31 | } |
| 32 | expect(2) |
Roman Elizarov | c0d71dc | 2017-12-21 22:12:43 +0300 | [diff] [blame] | 33 | assertTrue(!d.isActive && !d.isCompleted) |
| 34 | assertTrue(d.await() == 42) |
| 35 | assertTrue(!d.isActive && d.isCompleted && !d.isCompletedExceptionally) |
Roman Elizarov | 41c5c8b | 2017-01-25 13:37:15 +0300 | [diff] [blame] | 36 | expect(4) |
Roman Elizarov | c0d71dc | 2017-12-21 22:12:43 +0300 | [diff] [blame] | 37 | assertTrue(d.await() == 42) // second await -- same result |
Roman Elizarov | 41c5c8b | 2017-01-25 13:37:15 +0300 | [diff] [blame] | 38 | finish(5) |
| 39 | } |
| 40 | |
| 41 | @Test |
Roman Elizarov | e3f2884 | 2017-12-21 19:15:40 +0300 | [diff] [blame] | 42 | fun testLazyDeferAndYield() = runTest { |
Roman Elizarov | 41c5c8b | 2017-01-25 13:37:15 +0300 | [diff] [blame] | 43 | expect(1) |
Roman Elizarov | 43e3af7 | 2017-07-21 16:01:31 +0300 | [diff] [blame] | 44 | val d = async(coroutineContext, CoroutineStart.LAZY) { |
Roman Elizarov | 41c5c8b | 2017-01-25 13:37:15 +0300 | [diff] [blame] | 45 | expect(3) |
| 46 | yield() // this has not effect, because parent coroutine is waiting |
| 47 | expect(4) |
| 48 | 42 |
| 49 | } |
| 50 | expect(2) |
Roman Elizarov | c0d71dc | 2017-12-21 22:12:43 +0300 | [diff] [blame] | 51 | assertTrue(!d.isActive && !d.isCompleted) |
| 52 | assertTrue(d.await() == 42) |
| 53 | assertTrue(!d.isActive && d.isCompleted && !d.isCompletedExceptionally) |
Roman Elizarov | 41c5c8b | 2017-01-25 13:37:15 +0300 | [diff] [blame] | 54 | expect(5) |
Roman Elizarov | c0d71dc | 2017-12-21 22:12:43 +0300 | [diff] [blame] | 55 | assertTrue(d.await() == 42) // second await -- same result |
Roman Elizarov | 41c5c8b | 2017-01-25 13:37:15 +0300 | [diff] [blame] | 56 | finish(6) |
| 57 | } |
| 58 | |
| 59 | @Test |
Roman Elizarov | e3f2884 | 2017-12-21 19:15:40 +0300 | [diff] [blame] | 60 | fun testLazyDeferAndYield2() = runTest { |
Roman Elizarov | 41c5c8b | 2017-01-25 13:37:15 +0300 | [diff] [blame] | 61 | expect(1) |
Roman Elizarov | 43e3af7 | 2017-07-21 16:01:31 +0300 | [diff] [blame] | 62 | val d = async(coroutineContext, CoroutineStart.LAZY) { |
Roman Elizarov | 41c5c8b | 2017-01-25 13:37:15 +0300 | [diff] [blame] | 63 | expect(7) |
| 64 | 42 |
| 65 | } |
| 66 | expect(2) |
Roman Elizarov | c0d71dc | 2017-12-21 22:12:43 +0300 | [diff] [blame] | 67 | assertTrue(!d.isActive && !d.isCompleted) |
Roman Elizarov | 43e3af7 | 2017-07-21 16:01:31 +0300 | [diff] [blame] | 68 | launch(coroutineContext) { // see how it looks from another coroutine |
Roman Elizarov | 7cf452e | 2017-01-29 21:58:33 +0300 | [diff] [blame] | 69 | expect(4) |
Roman Elizarov | c0d71dc | 2017-12-21 22:12:43 +0300 | [diff] [blame] | 70 | assertTrue(!d.isActive && !d.isCompleted) |
Roman Elizarov | 7cf452e | 2017-01-29 21:58:33 +0300 | [diff] [blame] | 71 | yield() // yield back to main |
Roman Elizarov | 41c5c8b | 2017-01-25 13:37:15 +0300 | [diff] [blame] | 72 | expect(6) |
Roman Elizarov | c0d71dc | 2017-12-21 22:12:43 +0300 | [diff] [blame] | 73 | assertTrue(d.isActive && !d.isCompleted) // implicitly started by main's await |
Roman Elizarov | 7cf452e | 2017-01-29 21:58:33 +0300 | [diff] [blame] | 74 | yield() // yield to d |
Roman Elizarov | 41c5c8b | 2017-01-25 13:37:15 +0300 | [diff] [blame] | 75 | } |
Roman Elizarov | 7cf452e | 2017-01-29 21:58:33 +0300 | [diff] [blame] | 76 | expect(3) |
Roman Elizarov | c0d71dc | 2017-12-21 22:12:43 +0300 | [diff] [blame] | 77 | assertTrue(!d.isActive && !d.isCompleted) |
Roman Elizarov | 32d9532 | 2017-02-09 15:57:31 +0300 | [diff] [blame] | 78 | yield() // yield to second child (lazy async is not computing yet) |
Roman Elizarov | 7cf452e | 2017-01-29 21:58:33 +0300 | [diff] [blame] | 79 | expect(5) |
Roman Elizarov | c0d71dc | 2017-12-21 22:12:43 +0300 | [diff] [blame] | 80 | assertTrue(!d.isActive && !d.isCompleted) |
| 81 | assertTrue(d.await() == 42) // starts computing |
| 82 | assertTrue(!d.isActive && d.isCompleted && !d.isCompletedExceptionally) |
Roman Elizarov | 41c5c8b | 2017-01-25 13:37:15 +0300 | [diff] [blame] | 83 | finish(8) |
| 84 | } |
| 85 | |
Roman Elizarov | e3f2884 | 2017-12-21 19:15:40 +0300 | [diff] [blame] | 86 | @Test |
| 87 | fun testSimpleException() = runTest( |
| 88 | expected = { it is TestException } |
| 89 | ) { |
Roman Elizarov | 41c5c8b | 2017-01-25 13:37:15 +0300 | [diff] [blame] | 90 | expect(1) |
Roman Elizarov | 43e3af7 | 2017-07-21 16:01:31 +0300 | [diff] [blame] | 91 | val d = async(coroutineContext, CoroutineStart.LAZY) { |
Roman Elizarov | 41c5c8b | 2017-01-25 13:37:15 +0300 | [diff] [blame] | 92 | finish(3) |
Roman Elizarov | e3f2884 | 2017-12-21 19:15:40 +0300 | [diff] [blame] | 93 | throw TestException() |
Roman Elizarov | 41c5c8b | 2017-01-25 13:37:15 +0300 | [diff] [blame] | 94 | } |
| 95 | expect(2) |
Roman Elizarov | c0d71dc | 2017-12-21 22:12:43 +0300 | [diff] [blame] | 96 | assertTrue(!d.isActive && !d.isCompleted) |
Roman Elizarov | 41c5c8b | 2017-01-25 13:37:15 +0300 | [diff] [blame] | 97 | d.await() // will throw IOException |
| 98 | } |
| 99 | |
| 100 | @Test |
Roman Elizarov | e3f2884 | 2017-12-21 19:15:40 +0300 | [diff] [blame] | 101 | fun testLazyDeferAndYieldException() = runTest( |
| 102 | expected = { it is TestException } |
| 103 | ) { |
Roman Elizarov | 41c5c8b | 2017-01-25 13:37:15 +0300 | [diff] [blame] | 104 | expect(1) |
Roman Elizarov | 43e3af7 | 2017-07-21 16:01:31 +0300 | [diff] [blame] | 105 | val d = async(coroutineContext, CoroutineStart.LAZY) { |
Roman Elizarov | 41c5c8b | 2017-01-25 13:37:15 +0300 | [diff] [blame] | 106 | expect(3) |
Roman Elizarov | e3f2884 | 2017-12-21 19:15:40 +0300 | [diff] [blame] | 107 | yield() // this has not effect, because parent coroutine is waiting |
| 108 | finish(4) |
| 109 | throw TestException() |
| 110 | } |
| 111 | expect(2) |
Roman Elizarov | c0d71dc | 2017-12-21 22:12:43 +0300 | [diff] [blame] | 112 | assertTrue(!d.isActive && !d.isCompleted) |
Roman Elizarov | e3f2884 | 2017-12-21 19:15:40 +0300 | [diff] [blame] | 113 | d.await() // will throw IOException |
| 114 | } |
| 115 | |
| 116 | @Test |
| 117 | fun testCatchException() = runTest { |
| 118 | expect(1) |
| 119 | val d = async(coroutineContext, CoroutineStart.LAZY) { |
| 120 | expect(3) |
| 121 | throw TestException() |
Roman Elizarov | 41c5c8b | 2017-01-25 13:37:15 +0300 | [diff] [blame] | 122 | } |
| 123 | expect(2) |
Roman Elizarov | c0d71dc | 2017-12-21 22:12:43 +0300 | [diff] [blame] | 124 | assertTrue(!d.isActive && !d.isCompleted) |
Roman Elizarov | 41c5c8b | 2017-01-25 13:37:15 +0300 | [diff] [blame] | 125 | try { |
| 126 | d.await() // will throw IOException |
Roman Elizarov | e3f2884 | 2017-12-21 19:15:40 +0300 | [diff] [blame] | 127 | } catch (e: TestException) { |
Roman Elizarov | c0d71dc | 2017-12-21 22:12:43 +0300 | [diff] [blame] | 128 | assertTrue(!d.isActive && d.isCompleted && d.isCompletedExceptionally && !d.isCancelled) |
Roman Elizarov | 41c5c8b | 2017-01-25 13:37:15 +0300 | [diff] [blame] | 129 | expect(4) |
| 130 | } |
| 131 | finish(5) |
| 132 | } |
| 133 | |
| 134 | @Test |
Roman Elizarov | e3f2884 | 2017-12-21 19:15:40 +0300 | [diff] [blame] | 135 | fun testStart() = runTest { |
Roman Elizarov | 41c5c8b | 2017-01-25 13:37:15 +0300 | [diff] [blame] | 136 | expect(1) |
Roman Elizarov | 43e3af7 | 2017-07-21 16:01:31 +0300 | [diff] [blame] | 137 | val d = async(coroutineContext, CoroutineStart.LAZY) { |
Roman Elizarov | 7cf452e | 2017-01-29 21:58:33 +0300 | [diff] [blame] | 138 | expect(4) |
Roman Elizarov | 41c5c8b | 2017-01-25 13:37:15 +0300 | [diff] [blame] | 139 | 42 |
| 140 | } |
| 141 | expect(2) |
Roman Elizarov | c0d71dc | 2017-12-21 22:12:43 +0300 | [diff] [blame] | 142 | assertTrue(!d.isActive && !d.isCompleted) |
| 143 | assertTrue(d.start()) |
| 144 | assertTrue(d.isActive && !d.isCompleted) |
Roman Elizarov | 7cf452e | 2017-01-29 21:58:33 +0300 | [diff] [blame] | 145 | expect(3) |
Roman Elizarov | c0d71dc | 2017-12-21 22:12:43 +0300 | [diff] [blame] | 146 | assertTrue(!d.start()) |
Roman Elizarov | 7cf452e | 2017-01-29 21:58:33 +0300 | [diff] [blame] | 147 | yield() // yield to started coroutine |
Roman Elizarov | c0d71dc | 2017-12-21 22:12:43 +0300 | [diff] [blame] | 148 | assertTrue(!d.isActive && d.isCompleted && !d.isCompletedExceptionally) // and it finishes |
Roman Elizarov | 7cf452e | 2017-01-29 21:58:33 +0300 | [diff] [blame] | 149 | expect(5) |
Roman Elizarov | c0d71dc | 2017-12-21 22:12:43 +0300 | [diff] [blame] | 150 | assertTrue(d.await() == 42) // await sees result |
Roman Elizarov | 7cf452e | 2017-01-29 21:58:33 +0300 | [diff] [blame] | 151 | finish(6) |
Roman Elizarov | 41c5c8b | 2017-01-25 13:37:15 +0300 | [diff] [blame] | 152 | } |
| 153 | |
Roman Elizarov | e3f2884 | 2017-12-21 19:15:40 +0300 | [diff] [blame] | 154 | @Test |
| 155 | fun testCancelBeforeStart() = runTest( |
| 156 | expected = { it is JobCancellationException } |
| 157 | ) { |
Roman Elizarov | 41c5c8b | 2017-01-25 13:37:15 +0300 | [diff] [blame] | 158 | expect(1) |
Roman Elizarov | 43e3af7 | 2017-07-21 16:01:31 +0300 | [diff] [blame] | 159 | val d = async(coroutineContext, CoroutineStart.LAZY) { |
Roman Elizarov | 41c5c8b | 2017-01-25 13:37:15 +0300 | [diff] [blame] | 160 | expectUnreached() |
| 161 | 42 |
| 162 | } |
| 163 | expect(2) |
Roman Elizarov | c0d71dc | 2017-12-21 22:12:43 +0300 | [diff] [blame] | 164 | assertTrue(!d.isActive && !d.isCompleted) |
| 165 | assertTrue(d.cancel()) |
| 166 | assertTrue(!d.isActive && d.isCompleted && d.isCompletedExceptionally && d.isCancelled) |
| 167 | assertTrue(!d.cancel()) |
| 168 | assertTrue(!d.start()) |
Roman Elizarov | 41c5c8b | 2017-01-25 13:37:15 +0300 | [diff] [blame] | 169 | finish(3) |
Roman Elizarov | c0d71dc | 2017-12-21 22:12:43 +0300 | [diff] [blame] | 170 | assertTrue(d.await() == 42) // await shall throw CancellationException |
Roman Elizarov | 41c5c8b | 2017-01-25 13:37:15 +0300 | [diff] [blame] | 171 | expectUnreached() |
| 172 | } |
| 173 | |
Roman Elizarov | e3f2884 | 2017-12-21 19:15:40 +0300 | [diff] [blame] | 174 | @Test |
| 175 | fun testCancelWhileComputing() = runTest( |
| 176 | expected = { it is CancellationException } |
| 177 | ) { |
Roman Elizarov | 41c5c8b | 2017-01-25 13:37:15 +0300 | [diff] [blame] | 178 | expect(1) |
Roman Elizarov | 43e3af7 | 2017-07-21 16:01:31 +0300 | [diff] [blame] | 179 | val d = async(coroutineContext, CoroutineStart.LAZY) { |
Roman Elizarov | 7cf452e | 2017-01-29 21:58:33 +0300 | [diff] [blame] | 180 | expect(4) |
| 181 | yield() // yield to main, that is going to cancel us |
Roman Elizarov | 41c5c8b | 2017-01-25 13:37:15 +0300 | [diff] [blame] | 182 | expectUnreached() |
| 183 | 42 |
| 184 | } |
| 185 | expect(2) |
Roman Elizarov | c0d71dc | 2017-12-21 22:12:43 +0300 | [diff] [blame] | 186 | assertTrue(!d.isActive && !d.isCompleted && !d.isCancelled) |
| 187 | assertTrue(d.start()) |
| 188 | assertTrue(d.isActive && !d.isCompleted && !d.isCancelled) |
Roman Elizarov | 7cf452e | 2017-01-29 21:58:33 +0300 | [diff] [blame] | 189 | expect(3) |
| 190 | yield() // yield to d |
| 191 | expect(5) |
Roman Elizarov | c0d71dc | 2017-12-21 22:12:43 +0300 | [diff] [blame] | 192 | assertTrue(d.isActive && !d.isCompleted && !d.isCancelled) |
| 193 | assertTrue(d.cancel()) |
| 194 | assertTrue(!d.isActive && !d.isCompletedExceptionally && d.isCancelled) // cancelling ! |
| 195 | assertTrue(!d.cancel()) |
| 196 | assertTrue(!d.isActive && !d.isCompletedExceptionally && d.isCancelled) // still cancelling |
Roman Elizarov | 7cf452e | 2017-01-29 21:58:33 +0300 | [diff] [blame] | 197 | finish(6) |
Roman Elizarov | c0d71dc | 2017-12-21 22:12:43 +0300 | [diff] [blame] | 198 | assertTrue(d.await() == 42) // await shall throw CancellationException |
Roman Elizarov | 41c5c8b | 2017-01-25 13:37:15 +0300 | [diff] [blame] | 199 | expectUnreached() |
| 200 | } |
Roman Elizarov | e3f2884 | 2017-12-21 19:15:40 +0300 | [diff] [blame] | 201 | |
| 202 | private class TestException : Exception() |
Roman Elizarov | 41c5c8b | 2017-01-25 13:37:15 +0300 | [diff] [blame] | 203 | } |