Skip to content

Commit 385881d

Browse files
committed
Added test for stack-trace recovery in JobCancellationException
Fixes #950
1 parent 73b456b commit 385881d

File tree

2 files changed

+45
-7
lines changed

2 files changed

+45
-7
lines changed

kotlinx-coroutines-core/jvm/test/exceptions/StackTraceRecoveryNestedChannelsTest.kt

+36
Original file line numberDiff line numberDiff line change
@@ -133,4 +133,40 @@ class StackTraceRecoveryNestedChannelsTest : TestBase() {
133133
finish(3)
134134
deferred.await()
135135
}
136+
137+
// See https://github.com/Kotlin/kotlinx.coroutines/issues/950
138+
@Test
139+
fun testCancelledOffer() = runTest {
140+
expect(1)
141+
val job = Job()
142+
val actor = actor<Int>(job, Channel.UNLIMITED) {
143+
consumeEach {
144+
expectUnreached() // is cancelled before offer
145+
}
146+
}
147+
job.cancel()
148+
try {
149+
actor.offer(1)
150+
} catch (e: Exception) {
151+
verifyStackTrace(e,
152+
"kotlinx.coroutines.JobCancellationException: Job was cancelled; job=JobImpl{Cancelling}@3af42ad0\n" +
153+
"\t(Coroutine boundary)\n" +
154+
"\tat kotlinx.coroutines.channels.AbstractSendChannel.offer(AbstractChannel.kt:186)\n" +
155+
"\tat kotlinx.coroutines.channels.ChannelCoroutine.offer(ChannelCoroutine.kt)\n" +
156+
"\tat kotlinx.coroutines.exceptions.StackTraceRecoveryNestedChannelsTest\$testCancelledOffer\$1.invokeSuspend(StackTraceRecoveryNestedChannelsTest.kt:150)\n" +
157+
"Caused by: kotlinx.coroutines.JobCancellationException: Job was cancelled; job=JobImpl{Cancelling}@3af42ad0\n",
158+
// ... java.lang.* stuff snipped here ...
159+
"\tat kotlinx.coroutines.JobCancellationException.<init>(Exceptions.kt:44)\n" +
160+
"\tat kotlinx.coroutines.JobSupport.createJobCancellationException(JobSupport.kt:631)\n" +
161+
"\tat kotlinx.coroutines.JobSupport.createCauseException(JobSupport.kt:656)\n" +
162+
"\tat kotlinx.coroutines.JobSupport.cancelMakeCompleting(JobSupport.kt:620)\n" +
163+
"\tat kotlinx.coroutines.JobSupport.cancelImpl(JobSupport.kt:608)\n" +
164+
"\tat kotlinx.coroutines.JobSupport.cancelInternal(JobSupport.kt:583)\n" +
165+
"\tat kotlinx.coroutines.JobSupport.cancel(JobSupport.kt:571)\n" +
166+
"\tat kotlinx.coroutines.Job\$DefaultImpls.cancel\$default(Job.kt:164)\n" +
167+
"\tat kotlinx.coroutines.exceptions.StackTraceRecoveryNestedChannelsTest\$testCancelledOffer\$1.invokeSuspend(StackTraceRecoveryNestedChannelsTest.kt:148)"
168+
)
169+
finish(2)
170+
}
171+
}
136172
}

kotlinx-coroutines-core/jvm/test/exceptions/Stacktraces.kt

+9-7
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,12 @@ import kotlin.test.*
66
public fun verifyStackTrace(e: Throwable, vararg traces: String) {
77
val stacktrace = toStackTrace(e)
88
traces.forEach {
9-
assertTrue(
10-
stacktrace.trimStackTrace().contains(it.trimStackTrace()),
11-
"\nExpected trace element:\n$it\n\nActual stacktrace:\n$stacktrace"
12-
)
9+
val actual = stacktrace.trimStackTrace()
10+
val expected = it.trimStackTrace()
11+
if (!actual.contains(expected)) {
12+
// A more readable error message would be produced by assertEquals
13+
assertEquals(expected, actual, "Actual trace does not contain expected one")
14+
}
1315
}
1416

1517
val causes = stacktrace.count("Caused by")
@@ -23,11 +25,11 @@ public fun toStackTrace(t: Throwable): String {
2325
return sw.toString()
2426
}
2527

26-
public fun String.trimStackTrace(): String {
27-
return applyBackspace(trimIndent().replace(Regex(":[0-9]+"), "")
28+
public fun String.trimStackTrace(): String =
29+
applyBackspace(replace(Regex(":[0-9]+"), "")
2830
.replace("kotlinx_coroutines_core_main", "") // yay source sets
2931
.replace("kotlinx_coroutines_core", ""))
30-
}
32+
.replace(Regex("@[0-9a-f]+"), "") // hex addresses in debug toStrings
3133

3234
public fun applyBackspace(line: String): String {
3335
val array = line.toCharArray()

0 commit comments

Comments
 (0)