aboutsummaryrefslogtreecommitdiffstats
path: root/kotlinx-coroutines-core/jvm/test/exceptions/ProduceExceptionsTest.kt
diff options
context:
space:
mode:
Diffstat (limited to 'kotlinx-coroutines-core/jvm/test/exceptions/ProduceExceptionsTest.kt')
-rw-r--r--kotlinx-coroutines-core/jvm/test/exceptions/ProduceExceptionsTest.kt169
1 files changed, 169 insertions, 0 deletions
diff --git a/kotlinx-coroutines-core/jvm/test/exceptions/ProduceExceptionsTest.kt b/kotlinx-coroutines-core/jvm/test/exceptions/ProduceExceptionsTest.kt
new file mode 100644
index 00000000..33585f44
--- /dev/null
+++ b/kotlinx-coroutines-core/jvm/test/exceptions/ProduceExceptionsTest.kt
@@ -0,0 +1,169 @@
+/*
+ * Copyright 2016-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ */
+
+package kotlinx.coroutines.exceptions
+
+import kotlinx.coroutines.*
+import kotlinx.coroutines.channels.*
+import org.junit.Test
+import kotlin.test.*
+
+class ProduceExceptionsTest : TestBase() {
+
+ @Test
+ fun testFailingProduce() = runTest(unhandled = listOf({ e -> e is TestException })) {
+ expect(1)
+ val producer = produce<Int>(Job()) {
+ expect(2)
+ try {
+ yield()
+ } finally {
+ expect(3)
+ throw TestException()
+
+ }
+ }
+
+ yield()
+ producer.cancel()
+ yield()
+ finish(4)
+ }
+
+ @Test
+ fun testSuppressedExceptionUncaught() =
+ runTest(unhandled = listOf({ e -> e is TestException && e.suppressed[0] is TestException2 })) {
+ val produce = produce<Int>(Job()) {
+ launch(start = CoroutineStart.ATOMIC) {
+ throw TestException()
+ }
+ try {
+ delay(Long.MAX_VALUE)
+ } finally {
+ throw TestException2()
+ }
+ }
+
+ yield()
+ produce.cancel()
+ }
+
+ @Test
+ fun testSuppressedException() = runTest {
+ val produce = produce<Int>(NonCancellable) {
+ launch(start = CoroutineStart.ATOMIC) {
+ throw TestException() // child coroutine fails
+ }
+ try {
+ delay(Long.MAX_VALUE)
+ } finally {
+ throw TestException2() // but parent throws another exception while cleaning up
+ }
+ }
+ try {
+ produce.receive()
+ expectUnreached()
+ } catch (e: TestException) {
+ assertTrue(e.suppressed[0] is TestException2)
+ }
+ }
+
+ @Test
+ fun testCancelProduceChannel() = runTest {
+ var channel: ReceiveChannel<Int>? = null
+ channel = produce {
+ expect(2)
+ channel!!.cancel()
+ try {
+ send(1)
+ } catch (e: CancellationException) {
+ expect(3)
+ throw e
+ }
+ }
+
+ expect(1)
+ yield()
+ try {
+ channel.receive()
+ } catch (e: CancellationException) {
+ assertTrue(e.suppressed.isEmpty())
+ finish(4)
+ }
+ }
+
+ @Test
+ fun testCancelProduceChannelWithException() = runTest {
+ var channel: ReceiveChannel<Int>? = null
+ channel = produce(NonCancellable) {
+ expect(2)
+ channel!!.cancel(TestCancellationException())
+ try {
+ send(1)
+ // Not a ClosedForSendException
+ } catch (e: TestCancellationException) {
+ expect(3)
+ throw e
+ }
+ }
+
+ expect(1)
+ yield()
+ try {
+ channel.receive()
+ } catch (e: TestCancellationException) {
+ assertTrue(e.suppressed.isEmpty())
+ finish(4)
+ }
+ }
+
+ @Test
+ fun testCancelChannelWithJob() = runTest {
+ val job = Job()
+ val channel = produce(job) {
+ expect(2)
+ job.cancel()
+ try {
+ send(1)
+ } catch (e: CancellationException) {
+ expect(3)
+ throw e
+ }
+ }
+
+ expect(1)
+ yield()
+ try {
+ channel.receive()
+ } catch (e: CancellationException) {
+ assertTrue(e.suppressed.isEmpty())
+ finish(4)
+ }
+ }
+
+ @Test
+ fun testCancelChannelWithJobWithException() = runTest {
+ val job = Job()
+ val channel = produce(job) {
+ expect(2)
+ job.completeExceptionally(TestException2())
+ try {
+ send(1)
+ } catch (e: CancellationException) { // Not a TestException2
+ expect(3)
+ throw e
+ }
+ }
+
+ expect(1)
+ yield()
+ try {
+ channel.receive()
+ } catch (e: CancellationException) {
+ // RECOVER_STACK_TRACES
+ assertTrue(e.cause?.cause is TestException2)
+ finish(4)
+ }
+ }
+}