Skip to content

Commit e3cc40a

Browse files
committed
Add tests
1 parent c5fce8e commit e3cc40a

File tree

5 files changed

+97
-16
lines changed

5 files changed

+97
-16
lines changed

kotlinx-coroutines-test/common/test/Helpers.kt

Lines changed: 25 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -31,9 +31,32 @@ inline fun <T> assertRunsFast(timeout: Duration, block: () -> T): T {
3131
inline fun <T> assertRunsFast(block: () -> T): T = assertRunsFast(2.seconds, block)
3232

3333
/**
34-
* Passes [test] as an argument to [block], but as a function returning not a [TestResult] but [Unit].
34+
* Runs [test], and then invokes [block], passing to it the lambda that functionally behaves
35+
* the same way [test] does.
3536
*/
36-
expect fun testResultMap(block: (() -> Unit) -> Unit, test: () -> TestResult): TestResult
37+
fun testResultMap(block: (() -> Unit) -> Unit, test: () -> TestResult): TestResult = testResultChain(
38+
block = test,
39+
after = {
40+
block { it.getOrThrow() }
41+
createTestResult { }
42+
}
43+
)
44+
45+
/**
46+
* Chains together [block] and [after], passing the result of [block] to [after].
47+
*/
48+
expect fun testResultChain(block: () -> TestResult, after: (Result<Unit>) -> TestResult): TestResult
49+
50+
fun testResultChain(vararg chained: (Result<Unit>) -> TestResult): TestResult =
51+
if (chained.isEmpty()) {
52+
createTestResult { }
53+
} else {
54+
testResultChain(block = {
55+
chained[0](Result.success(Unit))
56+
}) {
57+
testResultChain(*chained.drop(1).toTypedArray())
58+
}
59+
}
3760

3861
class TestException(message: String? = null): Exception(message)
3962

kotlinx-coroutines-test/common/test/TestScopeTest.kt

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -489,6 +489,61 @@ class TestScopeTest {
489489
} catch (e: TimeoutCancellationException) {
490490
assertContains(e.message!!, "virtual")
491491
}
492+
493+
/*
494+
* Tests that the [TestScope] exception reporting mechanism will report the exceptions that happen between
495+
* different tests.
496+
*
497+
* This test must be ran manually, because such exceptions still go through the global exception handler
498+
* (as there's no guarantee that another test will happen), and the global exception handler will
499+
* log the exceptions or, on Native, crash the test suite.
500+
*/
501+
@Test
502+
@Ignore
503+
fun testReportingStrayUncaughtExceptionsBetweenTests() {
504+
val thrown = TestException("x")
505+
testResultChain({
506+
// register a handler for uncaught exceptions
507+
runTest { }
508+
}, {
509+
GlobalScope.launch(start = CoroutineStart.UNDISPATCHED) {
510+
throw thrown
511+
}
512+
runTest {
513+
fail("unreached")
514+
}
515+
}, {
516+
// this `runTest` will not report the exception
517+
runTest {
518+
when (val exception = it.exceptionOrNull()) {
519+
is UncaughtExceptionsBeforeTest -> {
520+
assertEquals(1, exception.suppressedExceptions.size)
521+
assertSame(exception.suppressedExceptions[0], thrown)
522+
}
523+
else -> fail("unexpected exception: $exception")
524+
}
525+
}
526+
})
527+
}
528+
529+
/**
530+
* Tests that the uncaught exceptions that happen during the test are reported.
531+
*/
532+
@Test
533+
fun testReportingStrayUncaughtExceptionsDuringTest(): TestResult {
534+
val thrown = TestException("x")
535+
return testResultChain({ _ ->
536+
runTest {
537+
val job = launch(Dispatchers.Default + NonCancellable) {
538+
throw thrown
539+
}
540+
job.join()
541+
}
542+
}, {
543+
runTest {
544+
assertEquals(thrown, it.exceptionOrNull())
545+
}
546+
})
492547
}
493548

494549
companion object {
Lines changed: 5 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,17 @@
11
/*
2-
* Copyright 2016-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
2+
* Copyright 2016-2022 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
33
*/
44

55
package kotlinx.coroutines.test
66

77
import kotlin.test.*
88

9-
actual fun testResultMap(block: (() -> Unit) -> Unit, test: () -> TestResult): TestResult =
10-
test().then(
9+
actual fun testResultChain(block: () -> TestResult, after: (Result<Unit>) -> TestResult): TestResult =
10+
block().then(
1111
{
12-
block {
13-
}
12+
after(Result.success(Unit))
1413
}, {
15-
block {
16-
throw it
17-
}
14+
after(Result.failure(it))
1815
})
1916

2017
actual typealias NoJs = Ignore

kotlinx-coroutines-test/jvm/test/HelpersJvm.kt

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,11 @@
33
*/
44
package kotlinx.coroutines.test
55

6-
actual fun testResultMap(block: (() -> Unit) -> Unit, test: () -> TestResult) {
7-
block {
8-
test()
6+
actual fun testResultChain(block: () -> TestResult, after: (Result<Unit>) -> TestResult): TestResult {
7+
try {
8+
block()
9+
after(Result.success(Unit))
10+
} catch (e: Throwable) {
11+
after(Result.failure(e))
912
}
1013
}

kotlinx-coroutines-test/native/test/Helpers.kt

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,12 @@ package kotlinx.coroutines.test
55

66
import kotlin.test.*
77

8-
actual fun testResultMap(block: (() -> Unit) -> Unit, test: () -> TestResult) {
9-
block {
10-
test()
8+
actual fun testResultChain(block: () -> TestResult, after: (Result<Unit>) -> TestResult): TestResult {
9+
try {
10+
block()
11+
after(Result.success(Unit))
12+
} catch (e: Throwable) {
13+
after(Result.failure(e))
1114
}
1215
}
1316

0 commit comments

Comments
 (0)