Roman Elizarov | 187eace | 2017-01-31 09:39:58 +0300 | [diff] [blame] | 1 | package kotlinx.coroutines.experimental.channels |
| 2 | |
| 3 | import kotlinx.coroutines.experimental.* |
| 4 | import org.junit.Test |
| 5 | import kotlin.test.assertEquals |
| 6 | import kotlin.test.assertFalse |
| 7 | import kotlin.test.assertTrue |
| 8 | |
| 9 | class RendezvousChannelTest : TestBase() { |
| 10 | @Test |
| 11 | fun testSimple() = runBlocking { |
| 12 | val q = RendezvousChannel<Int>() |
| 13 | check(q.isEmpty && q.isFull) |
| 14 | expect(1) |
| 15 | val sender = launch(context) { |
| 16 | expect(4) |
| 17 | q.send(1) // suspend -- the first to come to rendezvous |
| 18 | expect(7) |
| 19 | q.send(2) // does not suspend -- receiver is there |
| 20 | expect(8) |
| 21 | } |
| 22 | expect(2) |
| 23 | val receiver = launch(context) { |
| 24 | expect(5) |
| 25 | check(q.receive() == 1) // does not suspend -- sender was there |
| 26 | expect(6) |
| 27 | check(q.receive() == 2) // suspends |
| 28 | expect(9) |
| 29 | } |
| 30 | expect(3) |
| 31 | sender.join() |
| 32 | receiver.join() |
| 33 | check(q.isEmpty && q.isFull) |
| 34 | finish(10) |
| 35 | } |
| 36 | |
| 37 | @Test |
| 38 | fun testStress() = runBlocking { |
| 39 | val n = 100_000 |
| 40 | val q = RendezvousChannel<Int>() |
| 41 | val sender = launch(context) { |
| 42 | for (i in 1..n) q.send(i) |
| 43 | expect(2) |
| 44 | } |
| 45 | val receiver = launch(context) { |
| 46 | for (i in 1..n) check(q.receive() == i) |
| 47 | expect(3) |
| 48 | } |
| 49 | expect(1) |
| 50 | sender.join() |
| 51 | receiver.join() |
| 52 | finish(4) |
| 53 | } |
| 54 | |
| 55 | @Test |
| 56 | fun testClosedReceiveOrNull() = runBlocking { |
| 57 | val q = RendezvousChannel<Int>() |
| 58 | check(q.isEmpty && q.isFull && !q.isClosedForSend && !q.isClosedForReceive) |
| 59 | expect(1) |
| 60 | launch(context) { |
| 61 | expect(3) |
| 62 | assertEquals(42, q.receiveOrNull()) |
| 63 | expect(4) |
| 64 | assertEquals(null, q.receiveOrNull()) |
| 65 | expect(6) |
| 66 | } |
| 67 | expect(2) |
| 68 | q.send(42) |
| 69 | expect(5) |
| 70 | q.close() |
| 71 | check(!q.isEmpty && !q.isFull && q.isClosedForSend && q.isClosedForReceive) |
| 72 | yield() |
| 73 | check(!q.isEmpty && !q.isFull && q.isClosedForSend && q.isClosedForReceive) |
| 74 | finish(7) |
| 75 | } |
| 76 | |
| 77 | @Test |
| 78 | fun testClosedExceptions() = runBlocking { |
| 79 | val q = RendezvousChannel<Int>() |
| 80 | expect(1) |
| 81 | launch(context) { |
| 82 | expect(4) |
| 83 | try { q.receive() } |
| 84 | catch (e: ClosedReceiveChannelException) { |
| 85 | expect(5) |
| 86 | } |
| 87 | } |
| 88 | expect(2) |
| 89 | q.close() |
| 90 | expect(3) |
| 91 | yield() |
| 92 | expect(6) |
| 93 | try { q.send(42) } |
| 94 | catch (e: ClosedSendChannelException) { |
| 95 | finish(7) |
| 96 | } |
| 97 | } |
| 98 | |
| 99 | @Test |
| 100 | fun testOfferAndPool() = runBlocking { |
| 101 | val q = RendezvousChannel<Int>() |
| 102 | assertFalse(q.offer(1)) |
| 103 | expect(1) |
| 104 | launch(context) { |
| 105 | expect(3) |
Roman Elizarov | 7b2d8b0 | 2017-02-02 20:09:14 +0300 | [diff] [blame] | 106 | assertEquals(null, q.poll()) |
Roman Elizarov | 187eace | 2017-01-31 09:39:58 +0300 | [diff] [blame] | 107 | expect(4) |
| 108 | assertEquals(2, q.receive()) |
| 109 | expect(7) |
Roman Elizarov | 7b2d8b0 | 2017-02-02 20:09:14 +0300 | [diff] [blame] | 110 | assertEquals(null, q.poll()) |
Roman Elizarov | 187eace | 2017-01-31 09:39:58 +0300 | [diff] [blame] | 111 | yield() |
| 112 | expect(9) |
Roman Elizarov | 7b2d8b0 | 2017-02-02 20:09:14 +0300 | [diff] [blame] | 113 | assertEquals(3, q.poll()) |
Roman Elizarov | 187eace | 2017-01-31 09:39:58 +0300 | [diff] [blame] | 114 | expect(10) |
| 115 | } |
| 116 | expect(2) |
| 117 | yield() |
| 118 | expect(5) |
| 119 | assertTrue(q.offer(2)) |
| 120 | expect(6) |
| 121 | yield() |
| 122 | expect(8) |
| 123 | q.send(3) |
| 124 | finish(11) |
| 125 | } |
Roman Elizarov | 7b2d8b0 | 2017-02-02 20:09:14 +0300 | [diff] [blame] | 126 | |
| 127 | @Test |
| 128 | fun testIteratorClosed() = runBlocking { |
| 129 | val q = RendezvousChannel<Int>() |
| 130 | expect(1) |
| 131 | launch(context) { |
| 132 | expect(3) |
| 133 | q.close() |
| 134 | expect(4) |
| 135 | } |
| 136 | expect(2) |
| 137 | for (x in q) { |
| 138 | expectUnreached() |
| 139 | } |
| 140 | finish(5) |
| 141 | } |
| 142 | |
| 143 | @Test |
| 144 | fun testIteratorOne() = runBlocking { |
| 145 | val q = RendezvousChannel<Int>() |
| 146 | expect(1) |
| 147 | launch(context) { |
| 148 | expect(3) |
| 149 | q.send(1) |
| 150 | expect(4) |
| 151 | q.close() |
| 152 | expect(5) |
| 153 | } |
| 154 | expect(2) |
| 155 | for (x in q) { |
| 156 | expect(6) |
| 157 | assertEquals(1, x) |
| 158 | } |
| 159 | finish(7) |
| 160 | } |
| 161 | |
| 162 | @Test |
| 163 | fun testIteratorOneWithYield() = runBlocking { |
| 164 | val q = RendezvousChannel<Int>() |
| 165 | expect(1) |
| 166 | launch(context) { |
| 167 | expect(3) |
| 168 | q.send(1) // will suspend |
| 169 | expect(6) |
| 170 | q.close() |
| 171 | expect(7) |
| 172 | } |
| 173 | expect(2) |
| 174 | yield() // yield to sender coroutine right before starting for loop |
| 175 | expect(4) |
| 176 | for (x in q) { |
| 177 | expect(5) |
| 178 | assertEquals(1, x) |
| 179 | } |
| 180 | finish(8) |
| 181 | } |
| 182 | |
| 183 | @Test |
| 184 | fun testIteratorTwo() = runBlocking { |
| 185 | val q = RendezvousChannel<Int>() |
| 186 | expect(1) |
| 187 | launch(context) { |
| 188 | expect(3) |
| 189 | q.send(1) |
| 190 | expect(4) |
| 191 | q.send(2) |
| 192 | expect(7) |
| 193 | q.close() |
| 194 | expect(8) |
| 195 | } |
| 196 | expect(2) |
| 197 | for (x in q) { |
| 198 | when (x) { |
| 199 | 1 -> expect(5) |
| 200 | 2 -> expect(6) |
| 201 | else -> expectUnreached() |
| 202 | } |
| 203 | } |
| 204 | finish(9) |
| 205 | } |
| 206 | |
| 207 | @Test |
| 208 | fun testIteratorTwoWithYield() = runBlocking { |
| 209 | val q = RendezvousChannel<Int>() |
| 210 | expect(1) |
| 211 | launch(context) { |
| 212 | expect(3) |
| 213 | q.send(1) // will suspend |
| 214 | expect(6) |
| 215 | q.send(2) |
| 216 | expect(7) |
| 217 | q.close() |
| 218 | expect(8) |
| 219 | } |
| 220 | expect(2) |
| 221 | yield() // yield to sender coroutine right before starting for loop |
| 222 | expect(4) |
| 223 | for (x in q) { |
| 224 | when (x) { |
| 225 | 1 -> expect(5) |
| 226 | 2 -> expect(9) |
| 227 | else -> expectUnreached() |
| 228 | } |
| 229 | } |
| 230 | finish(10) |
| 231 | } |
Roman Elizarov | b6b0125 | 2017-02-06 13:17:40 +0300 | [diff] [blame^] | 232 | |
| 233 | class BadClass { |
| 234 | override fun equals(other: Any?): Boolean = error("equals") |
| 235 | override fun hashCode(): Int = error("hashCode") |
| 236 | override fun toString(): String = error("toString") |
| 237 | } |
| 238 | |
| 239 | @Test |
| 240 | fun testDeferBadClass() = runBlocking { |
| 241 | val bad = BadClass() |
| 242 | val c = buildChannel(context) { |
| 243 | expect(1) |
| 244 | send(bad) |
| 245 | } |
| 246 | assertTrue(c.receive() === bad) |
| 247 | finish(2) |
| 248 | } |
Roman Elizarov | 187eace | 2017-01-31 09:39:58 +0300 | [diff] [blame] | 249 | } |