Skip to content

Commit

Permalink
Add more tests for 'runTest'
Browse files Browse the repository at this point in the history
  • Loading branch information
dkhalanskyjb committed Oct 14, 2021
1 parent 42a345e commit 19ed1f0
Show file tree
Hide file tree
Showing 6 changed files with 132 additions and 4 deletions.
9 changes: 7 additions & 2 deletions kotlinx-coroutines-test/common/src/TestBuilders.kt
Expand Up @@ -170,9 +170,9 @@ public fun runTest(
): TestResult {
if (context[RunningInRunTest] != null)
throw IllegalStateException("Calls to `runTest` can't be nested. Please read the docs on `TestResult` for details.")
val testScope = TestCoroutineScope(context + RunningInRunTest())
val scheduler = testScope.testScheduler
return createTestResult {
val testScope = TestCoroutineScope(context + RunningInRunTest())
val scheduler = testScope.testScheduler
val deferred = testScope.async {
testScope.testBody()
}
Expand All @@ -197,6 +197,11 @@ public fun runTest(
}
}
} catch (e: TimeoutCancellationException) {
try {
testScope.cleanupTestCoroutines()
} catch (e: UncompletedCoroutinesError) {
// we expect these and will instead throw a more informative exception just below.
}
throw UncompletedCoroutinesError("The test coroutine was not completed after waiting for $dispatchTimeoutMs ms")
}
}
Expand Down
10 changes: 10 additions & 0 deletions kotlinx-coroutines-test/common/test/Helpers.kt
@@ -0,0 +1,10 @@
/*
* Copyright 2016-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/

package kotlinx.coroutines.test

/**
* Passes [test] as an argument to [block], but as a function returning not a [TestResult] but [Unit].
*/
expect fun testResultMap(block: (() -> Unit) -> Unit, test: () -> TestResult): TestResult
72 changes: 70 additions & 2 deletions kotlinx-coroutines-test/common/test/RunTestTest.kt
Expand Up @@ -5,10 +5,8 @@
package kotlinx.coroutines.test

import kotlinx.coroutines.*
import kotlinx.coroutines.flow.*
import kotlin.coroutines.*
import kotlin.test.*
import kotlin.time.*

class RunTestTest {

Expand Down Expand Up @@ -50,4 +48,74 @@ class RunTestTest {
}
}

/** Tests that even the dispatch timeout of `0` is fine if all the dispatches go through the same scheduler. */
@Test
fun testRunTestWithZeroTimeoutWithControlledDispatches() = runTest(dispatchTimeoutMs = 0) {
// below is some arbitrary concurrent code where all dispatches go through the same scheduler.
launch {
delay(2000)
}
val deferred = async {
val job = launch(TestCoroutineDispatcher(testScheduler)) {
launch {
delay(500)
}
delay(1000)
}
job.join()
}
deferred.await()
}

/** Tests that a dispatch timeout of `0` will fail the test if there are some dispatches outside the scheduler. */
@Test
fun testRunTestWithZeroTimeoutWithUncontrolledDispatches() = testResultMap({ fn ->
assertFailsWith<UncompletedCoroutinesError> { fn() }
}) {
runTest(dispatchTimeoutMs = 0) {
withContext(Dispatchers.Default) {
delay(10)
3
}
throw IllegalStateException("shouldn't be reached")
}
}

/** Tests that too low of a dispatch timeout causes crashes. */
@Test
fun testRunTestWithSmallTimeout() = testResultMap({ fn ->
assertFailsWith<UncompletedCoroutinesError> { fn() }
}) {
runTest(dispatchTimeoutMs = 100) {
withContext(Dispatchers.Default) {
delay(10000)
3
}
throw RuntimeException("shouldn't be reached")
}
}

/** Tests that too low of a dispatch timeout causes crashes. */
@Test
fun testRunTestWithLargeTimeout() = runTest(dispatchTimeoutMs = 5000) {
withContext(Dispatchers.Default) {
delay(50)
}
}

/** Tests uncaught exceptions taking priority over dispatch timeout in error reports. */
@Test
fun testRunTestTimingOutAndThrowing() = testResultMap({ fn ->
assertFailsWith<IllegalArgumentException> { fn() }
}) {
runTest(dispatchTimeoutMs = 1) {
coroutineContext[CoroutineExceptionHandler]!!.handleException(coroutineContext, IllegalArgumentException())
withContext(Dispatchers.Default) {
delay(10000)
3
}
throw RuntimeException("shouldn't be reached")
}
}

}
21 changes: 21 additions & 0 deletions kotlinx-coroutines-test/js/test/Helpers.kt
@@ -0,0 +1,21 @@
/*
* Copyright 2016-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/

package kotlinx.coroutines.test

import kotlinx.coroutines.*

actual fun testResultMap(block: (() -> Unit) -> Unit, test: () -> TestResult): TestResult =
GlobalScope.promise {
val promise = test()
promise.then(
{
block {
}
}, {
block {
throw it
}
})
}
12 changes: 12 additions & 0 deletions kotlinx-coroutines-test/jvm/test/Helpers.kt
@@ -0,0 +1,12 @@
/*
* Copyright 2016-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
package kotlinx.coroutines.test

import kotlinx.coroutines.*

actual fun testResultMap(block: (() -> Unit) -> Unit, test: () -> TestResult) {
block {
test()
}
}
12 changes: 12 additions & 0 deletions kotlinx-coroutines-test/native/test/Helpers.kt
@@ -0,0 +1,12 @@
/*
* Copyright 2016-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
package kotlinx.coroutines.test

import kotlinx.coroutines.*

actual fun testResultMap(block: (() -> Unit) -> Unit, test: () -> TestResult) {
block {
test()
}
}

0 comments on commit 19ed1f0

Please sign in to comment.