Skip to content

Commit d202ed9

Browse files
committed
Restore all state in TestBase even when test fails
And also make sure only the first detected error gets reported
1 parent c7cfc39 commit d202ed9

File tree

1 file changed

+31
-10
lines changed

1 file changed

+31
-10
lines changed

kotlinx-coroutines-core/jvm/test/TestBase.kt

+31-10
Original file line numberDiff line numberDiff line change
@@ -62,13 +62,20 @@ public actual open class TestBase actual constructor() {
6262
*/
6363
@Suppress("ACTUAL_FUNCTION_WITH_DEFAULT_ARGUMENTS")
6464
public actual fun error(message: Any, cause: Throwable? = null): Nothing {
65-
val exception = IllegalStateException(message.toString(), cause)
65+
throw makeError(message, cause)
66+
}
67+
68+
private fun makeError(message: Any, cause: Throwable? = null): IllegalStateException =
69+
IllegalStateException(message.toString(), cause).also {
70+
setError(it)
71+
}
72+
73+
private fun setError(exception: Throwable) {
6674
error.compareAndSet(null, exception)
67-
throw exception
6875
}
6976

7077
private fun printError(message: String, cause: Throwable) {
71-
error.compareAndSet(null, cause)
78+
setError(cause)
7279
println("$message: $cause")
7380
cause.printStackTrace(System.out)
7481
println("--- Detected at ---")
@@ -118,21 +125,35 @@ public actual open class TestBase actual constructor() {
118125
initPoolsBeforeTest()
119126
threadsBefore = currentThreads()
120127
originalUncaughtExceptionHandler = Thread.getDefaultUncaughtExceptionHandler()
121-
Thread.setDefaultUncaughtExceptionHandler({ t, e ->
122-
println("Uncaught exception in thread $t: $e")
128+
Thread.setDefaultUncaughtExceptionHandler { t, e ->
129+
println("Exception in thread $t: $e") // The same message as in default handler
123130
e.printStackTrace()
124131
uncaughtExceptions.add(e)
125-
})
132+
}
126133
}
127134

128135
@After
129136
fun onCompletion() {
130-
error.get()?.let { throw it }
131-
check(actionIndex.get() == 0 || finished.get()) { "Expecting that 'finish(...)' was invoked, but it was not" }
137+
// onCompletion should not throw exceptions before it finishes all cleanup, so that other tests always
138+
// start in a clear, restored state
139+
if (actionIndex.get() != 0 && !finished.get()) {
140+
makeError("Expecting that 'finish(...)' was invoked, but it was not")
141+
}
142+
// Shutdown all thread pools
132143
shutdownPoolsAfterTest()
133-
checkTestThreads(threadsBefore)
144+
// Check that that are now leftover threads
145+
runCatching {
146+
checkTestThreads(threadsBefore)
147+
}.onFailure {
148+
setError(it)
149+
}
150+
// Restore original uncaught exception handler
134151
Thread.setDefaultUncaughtExceptionHandler(originalUncaughtExceptionHandler)
135-
assertTrue(uncaughtExceptions.isEmpty(), "Expected no uncaught exceptions, but got $uncaughtExceptions")
152+
if (uncaughtExceptions.isNotEmpty()) {
153+
makeError("Expected no uncaught exceptions, but got $uncaughtExceptions")
154+
}
155+
// The very last action -- throw error if any was detected
156+
error.get()?.let { throw it }
136157
}
137158

138159
fun initPoolsBeforeTest() {

0 commit comments

Comments
 (0)