Fix syncFromEvent, add Tests

This commit is contained in:
Him188 2020-04-21 14:51:50 +08:00
parent 422e8a9b4b
commit ca216bc492
2 changed files with 78 additions and 15 deletions

View File

@ -15,7 +15,6 @@ import kotlinx.coroutines.*
import net.mamoe.mirai.utils.SinceMirai
import kotlin.coroutines.CoroutineContext
import kotlin.coroutines.EmptyCoroutineContext
import kotlin.coroutines.suspendCoroutine
import kotlin.jvm.JvmSynthetic
import kotlin.reflect.KClass
@ -37,7 +36,16 @@ suspend inline fun <reified E : Event, R : Any> syncFromEvent(
noinline mapper: suspend E.(E) -> R? // 不要 crossinline: crossinline 后 stacktrace 会不正常
): R {
require(timeoutMillis == -1L || timeoutMillis > 0) { "timeoutMillis must be -1 or > 0" }
return syncFromEventOrNull(timeoutMillis, mapper) ?: error("timeout $timeoutMillis ms asyncFromEvent")
return if (timeoutMillis == -1L) {
coroutineScope {
syncFromEventImpl<E, R>(E::class, this, mapper)
}
} else {
withTimeout(timeoutMillis) {
syncFromEventImpl<E, R>(E::class, this, mapper)
}
}
}
/**
@ -54,19 +62,13 @@ suspend inline fun <reified E : Event, R : Any> syncFromEvent(
@JvmSynthetic
@SinceMirai("0.38.0")
suspend inline fun <reified E : Event, R : Any> syncFromEventOrNull(
timeoutMillis: Long = -1,
timeoutMillis: Long,
noinline mapper: suspend E.(E) -> R? // 不要 crossinline: crossinline 后 stacktrace 会不正常
): R? {
require(timeoutMillis == -1L || timeoutMillis > 0) { "timeoutMillis must be -1 or > 0" }
require(timeoutMillis > 0) { "timeoutMillis must be > 0" }
return if (timeoutMillis == -1L) {
coroutineScope {
syncFromEventOrNullImpl<E, R>(E::class, this, mapper)
}
} else {
withTimeoutOrNull(timeoutMillis) {
syncFromEventOrNullImpl<E, R>(E::class, this, mapper)
}
return withTimeoutOrNull(timeoutMillis) {
syncFromEventImpl<E, R>(E::class, this, mapper)
}
}
@ -83,7 +85,7 @@ suspend inline fun <reified E : Event, R : Any> syncFromEventOrNull(
@Suppress("DeferredIsResult")
@SinceMirai("0.38.0")
inline fun <reified E : Event, R : Any> CoroutineScope.asyncFromEventOrNull(
timeoutMillis: Long = -1,
timeoutMillis: Long,
coroutineContext: CoroutineContext = EmptyCoroutineContext,
noinline mapper: suspend E.(E) -> R? // 不要 crossinline: crossinline 后 stacktrace 会不正常
): Deferred<R?> {
@ -123,11 +125,11 @@ inline fun <reified E : Event, R : Any> CoroutineScope.asyncFromEvent(
//////////////
@PublishedApi
internal suspend fun <E : Event, R> syncFromEventOrNullImpl(
internal suspend fun <E : Event, R> syncFromEventImpl(
eventClass: KClass<E>,
coroutineScope: CoroutineScope,
mapper: suspend E.(E) -> R?
): R? = suspendCoroutine { cont ->
): R = suspendCancellableCoroutine { cont ->
coroutineScope.subscribe(eventClass) {
cont.resumeWith(kotlin.runCatching {
mapper.invoke(this, it) ?: return@subscribe ListeningStatus.LISTENING

View File

@ -0,0 +1,61 @@
/*
* Copyright 2020 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/master/LICENSE
*/
package net.mamoe.mirai.message
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.TimeoutCancellationException
import kotlinx.coroutines.launch
import kotlinx.coroutines.withTimeout
import net.mamoe.mirai.event.TestEvent
import net.mamoe.mirai.event.broadcast
import net.mamoe.mirai.event.syncFromEvent
import net.mamoe.mirai.test.runBlocking
import kotlin.coroutines.CoroutineContext
import kotlin.coroutines.EmptyCoroutineContext
import kotlin.coroutines.resume
import kotlin.coroutines.suspendCoroutine
import kotlin.test.Test
import kotlin.test.assertFailsWith
internal class SubscribingGetTest {
@Test
fun testSyncFromEvent(): Unit = runBlocking {
withTimeout(500) {
suspendCoroutine<Unit> { cont ->
launch {
syncFromEvent(5000) { _: TestEvent ->
cont.resume(Unit)
}
}
launch {
TestEvent().broadcast()
}
}
}
}
@Test
fun testSyncFromEventTimeout() {
runBlockingWithTimeout(500) {
assertFailsWith<TimeoutCancellationException> {
syncFromEvent(100) { _: TestEvent -> }
}
}
}
}
internal fun <R> runBlockingWithTimeout(
millis: Long,
context: CoroutineContext = EmptyCoroutineContext,
block: suspend CoroutineScope.() -> R
): R = runBlocking(context) {
withTimeout(millis, block)
}