1
0
mirror of https://github.com/mamoe/mirai.git synced 2025-04-25 13:03:35 +08:00

[core/testFramework] Add assertNoCoroutineSuspension

This commit is contained in:
Him188 2023-04-23 11:37:04 +01:00
parent 9995a2136c
commit 0ea5503f3b
No known key found for this signature in database
GPG Key ID: BA439CDDCF652375

View File

@ -0,0 +1,92 @@
/*
* Copyright 2019-2023 Mamoe Technologies and contributors.
*
* 此源代码的使用受 GNU AFFERO GENERAL PUBLIC LICENSE version 3 许可证的约束, 可以在以下链接找到该许可证.
* Use of this source code is governed by the GNU AGPLv3 license that can be found through the following link.
*
* https://github.com/mamoe/mirai/blob/dev/LICENSE
*/
package net.mamoe.mirai.utils.testFramework
import kotlinx.coroutines.*
import kotlinx.coroutines.test.runTest
import kotlin.contracts.InvocationKind
import kotlin.contracts.contract
import kotlin.coroutines.resume
import kotlin.test.Test
import kotlin.test.assertEquals
import kotlin.test.assertFails
import kotlin.test.fail
suspend inline fun <R> assertNoCoroutineSuspension(
crossinline block: suspend () -> R,
): R {
contract { callsInPlace(block, InvocationKind.EXACTLY_ONCE) }
return withContext(Dispatchers.Default.limitedParallelism(1)) {
val job = launch(start = CoroutineStart.UNDISPATCHED) {
yield()
fail("Expected no coroutine suspension")
}
val ret = block()
job.cancel()
ret
}
}
suspend inline fun <R> assertCoroutineSuspends(
crossinline block: suspend () -> R,
): R {
contract { callsInPlace(block, InvocationKind.EXACTLY_ONCE) }
return withContext(Dispatchers.Default.limitedParallelism(1)) {
val job = launch(start = CoroutineStart.UNDISPATCHED) {
yield() // goto block
}
val ret = block()
kotlin.test.assertTrue("Expected coroutine suspension") { job.isCompleted }
job.cancel()
ret
}
}
class AssertCoroutineSuspensionTest {
@Test
fun `assertNoCoroutineSuspension no suspension`() = runTest {
assertNoCoroutineSuspension {}
}
@Test
fun `assertNoCoroutineSuspension suspend cancellable`() = runTest {
assertFails {
assertNoCoroutineSuspension {
suspendCancellableCoroutine<Unit> { }
}
}.run {
assertEquals("Expected no coroutine suspension", message)
}
}
@Test
fun `assertCoroutineSuspends suspend`() = runTest {
assertCoroutineSuspends {
suspendCancellableCoroutine {
// resume after suspendCancellableCoroutine returns to create a suspension
launch(start = CoroutineStart.UNDISPATCHED) {
yield()
it.resume(Unit)
}
}
}
}
@Test
fun `assertCoroutineSuspends no suspension`() = runTest {
assertFails {
assertCoroutineSuspends {}
}.run {
assertEquals("Expected coroutine suspension", message)
}
}
}