blob: 1bed8cc44490da0bc08bad668229431d1dffc0be [file] [log] [blame]
Vsevolod Tolstopyatov91ecee82018-08-07 18:24:00 +03001/*
2 * Copyright 2016-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
3 */
4
Vsevolod Tolstopyatov06f57aa2018-07-24 19:51:21 +03005package kotlinx.coroutines.experimental.exceptions
6
7import kotlinx.coroutines.experimental.*
8import org.junit.Test
9import java.io.*
Vsevolod Tolstopyatov06f57aa2018-07-24 19:51:21 +030010import kotlin.test.*
11
12class JobNestedExceptionsTest : TestBase() {
13
14 @Test
15 fun testExceptionUnwrapping() {
16 val exception = runBlock {
17 val job = Job()
18 launch(coroutineContext, parent = job) {
19 expect(2)
20 launch(coroutineContext) {
21 launch(coroutineContext) {
22 launch(coroutineContext) {
23 throw IllegalStateException()
24 }
25 }
26 }
27 }
28
29 expect(1)
30 job.join()
31 finish(3)
32 }
33
34 checkException<IllegalStateException>(exception)
35 checkCycles(exception)
36 }
37
38 @Test
39 fun testExceptionUnwrappingWithSuspensions() {
40 val exception = runBlock {
41 val job = Job()
42 launch(coroutineContext, parent = job) {
43 expect(2)
44 launch(coroutineContext) {
45 launch(coroutineContext) {
46 launch(coroutineContext) {
47 launch(coroutineContext) {
48 throw IOException()
49 }
50 yield()
51 }
52 delay(Long.MAX_VALUE)
53 }
54 delay(Long.MAX_VALUE)
55 }
56 delay(Long.MAX_VALUE)
57 }
58
59 expect(1)
60 job.join()
61 finish(3)
62 }
63
64 assertTrue(exception is IOException)
65 }
66
67 @Test
68 fun testNestedAtomicThrow() {
69 val exception = runBlock {
70 expect(1)
Vsevolod Tolstopyatov79414ec2018-08-30 16:50:56 +030071 val job = GlobalScope.launch(coroutineContext.minusKey(Job), CoroutineStart.ATOMIC) {
Vsevolod Tolstopyatov06f57aa2018-07-24 19:51:21 +030072 expect(2)
73
Vsevolod Tolstopyatov79414ec2018-08-30 16:50:56 +030074 GlobalScope.launch(coroutineContext, CoroutineStart.ATOMIC) {
Vsevolod Tolstopyatov06f57aa2018-07-24 19:51:21 +030075 expect(3)
76 throw IOException()
77 }
78
79 throw ArithmeticException()
80 }
81
82 job.join()
83 finish(4)
84 }
85
86 assertTrue(exception is ArithmeticException)
87 checkException<IOException>(exception.suppressed()[0])
88 }
89
90 @Test
91 fun testChildThrowsDuringCompletion() {
92 val exceptions = runBlockForMultipleExceptions {
93 expect(1)
Vsevolod Tolstopyatov79414ec2018-08-30 16:50:56 +030094 val job = GlobalScope.launch(coroutineContext.minusKey(Job), CoroutineStart.ATOMIC) {
Vsevolod Tolstopyatov06f57aa2018-07-24 19:51:21 +030095 expect(2)
96
Vsevolod Tolstopyatov79414ec2018-08-30 16:50:56 +030097 GlobalScope.launch(coroutineContext, CoroutineStart.ATOMIC) {
Vsevolod Tolstopyatov06f57aa2018-07-24 19:51:21 +030098 expect(3)
Vsevolod Tolstopyatov79414ec2018-08-30 16:50:56 +030099 GlobalScope.launch(coroutineContext, CoroutineStart.ATOMIC) {
Vsevolod Tolstopyatov06f57aa2018-07-24 19:51:21 +0300100 // This child attaches to the parent and throws after parent completion
101 expect(4)
102 throw NullPointerException()
103 }
104
105 throw IOException()
106 }
107
108 throw ArithmeticException()
109 }
110
111 job.join()
112 finish(5)
113 }
114
Vsevolod Tolstopyatov91ecee82018-08-07 18:24:00 +0300115 assertEquals(1, exceptions.size)
Vsevolod Tolstopyatov06f57aa2018-07-24 19:51:21 +0300116 val exception = exceptions[0]
117 val suppressed = exception.suppressed()
118 checkException<IOException>(suppressed[0])
119 checkException<NullPointerException>(suppressed[1])
120 checkCycles(exception)
121 }
122}