-
Notifications
You must be signed in to change notification settings - Fork 1.9k
/
Copy pathStackTraceRecoveryNestedTest.kt
87 lines (73 loc) · 2.39 KB
/
StackTraceRecoveryNestedTest.kt
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
/*
* Copyright 2016-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
@file:Suppress("DeferredResultUnused")
package kotlinx.coroutines.exceptions
import kotlinx.coroutines.*
import org.junit.Test
import kotlin.test.*
class StackTraceRecoveryNestedTest : TestBase() {
@Test
fun testNestedAsync() = runTest {
val rootAsync = async(NonCancellable) {
expect(1)
// Just a noise for unwrapping
async {
expect(2)
delay(Long.MAX_VALUE)
}
// Do not catch, fail on cancellation
async {
expect(3)
async {
expect(4)
delay(Long.MAX_VALUE)
}
async {
expect(5)
// 1) await(), catch, verify and rethrow
try {
val nested = async {
expect(6)
throw RecoverableTestException()
}
nested.awaitNested()
} catch (e: RecoverableTestException) {
expect(7)
e.verifyException(
"await\$suspendImpl",
"awaitNested",
"\$testNestedAsync\$1\$rootAsync\$1\$2\$2.invokeSuspend"
)
// Just rethrow it
throw e
}
}
}
}
try {
rootAsync.awaitRootLevel()
} catch (e: RecoverableTestException) {
e.verifyException("awaitRootLevel")
finish(8)
}
}
private suspend fun Deferred<*>.awaitRootLevel() {
await()
assertTrue(true)
}
private suspend fun Deferred<*>.awaitNested() {
await()
assertTrue(true)
}
private fun RecoverableTestException.verifyException(vararg expectedTraceElements: String) {
// It is "recovered" only once
assertEquals(1, depth())
val stacktrace = stackTrace.map { it.methodName }.toSet()
assertTrue(expectedTraceElements.all { stacktrace.contains(it) })
}
private fun Throwable.depth(): Int {
val cause = cause ?: return 0
return 1 + cause.depth()
}
}