diff --git a/mirai-core/src/commonTest/kotlin/testFramework/DynamicTest.kt b/mirai-core/src/commonTest/kotlin/testFramework/DynamicTest.kt new file mode 100644 index 000000000..469a0ca9d --- /dev/null +++ b/mirai-core/src/commonTest/kotlin/testFramework/DynamicTest.kt @@ -0,0 +1,68 @@ +/* + * Copyright 2019-2022 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 + */ + +@file:JvmName("DynamicTestKt_common") + +package net.mamoe.mirai.internal.testFramework + +import kotlin.jvm.JvmName +import kotlin.test.Test + +/** + * Annotates a function to be a [Test] factory that returns a [DynamicTestsResult]. + * + * On JVM, this delegates to JUnit's `TestFactory`. On Native, test functions are executed in-place. + * + * Tips: To run [TestFactory]s in IDEA, you can press `Ctrl + Shift + R`(for both macOS and Windows) with caret in the test function. + */ +@Target(AnnotationTarget.FUNCTION) +@Retention(AnnotationRetention.RUNTIME) +expect annotation class TestFactory() + +/** + * @see dynamicTest + */ +expect open class DynamicTest // = junit.DynamicTest + +/** + * @see runDynamicTests + */ +expect class DynamicTestsResult + +/** + * Creates a dynamic test + */ +expect fun dynamicTest(displayName: String, action: () -> Unit): DynamicTest + +/** + * The returned value must be returned from the function annotated with [TestFactory], otherwise the tests won't be executed on some platforms. + */ +expect fun runDynamicTests(dynamicTests: List): DynamicTestsResult + +/** + * The returned value must be returned from the function annotated with [TestFactory], otherwise the tests won't be executed on some platforms. + */ +fun runDynamicTests(vararg dynamicTests: Iterable): DynamicTestsResult = + runDynamicTests(dynamicTests = dynamicTests.flatMap { it }) + +/** + * The returned value must be returned from the function annotated with [TestFactory], otherwise the tests won't be executed on some platforms. + */ +fun runDynamicTests(vararg dynamicTests: Sequence): DynamicTestsResult = + runDynamicTests(dynamicTests = dynamicTests.flatMap { it }) + +/** + * The returned value must be returned from the function annotated with [TestFactory], otherwise the tests won't be executed on some platforms. + */ +fun runDynamicTests(vararg dynamicTests: DynamicTest): DynamicTestsResult = runDynamicTests(dynamicTests.toList()) + +/** + * The returned value must be returned from the function annotated with [TestFactory], otherwise the tests won't be executed on some platforms. + */ +fun runDynamicTests(dynamicTests: Sequence): DynamicTestsResult = runDynamicTests(dynamicTests.toList()) diff --git a/mirai-core/src/jvmBaseTest/kotlin/test/AbstractTest.kt b/mirai-core/src/jvmBaseTest/kotlin/test/AbstractTest.kt index 72f70c3c1..acce208a4 100644 --- a/mirai-core/src/jvmBaseTest/kotlin/test/AbstractTest.kt +++ b/mirai-core/src/jvmBaseTest/kotlin/test/AbstractTest.kt @@ -13,15 +13,38 @@ import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.debug.DebugProbes import net.mamoe.mirai.IMirai import net.mamoe.mirai.internal.network.framework.SynchronizedStdoutLogger +import net.mamoe.mirai.internal.testFramework.DynamicTest +import net.mamoe.mirai.internal.testFramework.TestFactory import net.mamoe.mirai.utils.MiraiLogger import net.mamoe.mirai.utils.setSystemProp +import org.junit.jupiter.api.BeforeAll +import org.junit.jupiter.api.TestInfo import org.junit.jupiter.api.Timeout import java.util.concurrent.TimeUnit +import kotlin.jvm.optionals.getOrNull +import kotlin.reflect.full.functions +import kotlin.reflect.full.hasAnnotation @Timeout(value = 7, unit = TimeUnit.MINUTES) internal actual abstract class AbstractTest actual constructor() : CommonAbstractTest() { @OptIn(ExperimentalCoroutinesApi::class) actual companion object { + @OptIn(ExperimentalStdlibApi::class) + @BeforeAll + private fun checkTestFactories(testInfo: TestInfo) { + val clazz = testInfo.testClass.getOrNull()?.kotlin ?: return + for (function in clazz.functions) { + if (function.hasAnnotation()) { + check(function.returnType.classifier == List::class) { + "Illegal TestFactory function. A such function must return DynamicTestsResult." + } + check(function.returnType.arguments.singleOrNull()?.type?.classifier == DynamicTest::class) { + "Illegal TestFactory function. A such function must return DynamicTestsResult." + } + } + } + } + init { initPlatform() diff --git a/mirai-core/src/jvmBaseTest/kotlin/testFramework/DynamicTest.kt b/mirai-core/src/jvmBaseTest/kotlin/testFramework/DynamicTest.kt new file mode 100644 index 000000000..c0af1b4cd --- /dev/null +++ b/mirai-core/src/jvmBaseTest/kotlin/testFramework/DynamicTest.kt @@ -0,0 +1,24 @@ +/* + * Copyright 2019-2022 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.internal.testFramework + +actual typealias TestFactory = org.junit.jupiter.api.TestFactory + +actual typealias DynamicTest = org.junit.jupiter.api.DynamicTest + +@Suppress("ACTUAL_TYPE_ALIAS_TO_CLASS_WITH_DECLARATION_SITE_VARIANCE", "ACTUAL_WITHOUT_EXPECT") +actual typealias DynamicTestsResult = List<*> + +actual fun dynamicTest(displayName: String, action: () -> Unit): DynamicTest { + return DynamicTest.dynamicTest(displayName, action) +} + + +actual fun runDynamicTests(dynamicTests: List): DynamicTestsResult = dynamicTests \ No newline at end of file diff --git a/mirai-core/src/nativeTest/kotlin/testFramework/DynamicTest.kt b/mirai-core/src/nativeTest/kotlin/testFramework/DynamicTest.kt new file mode 100644 index 000000000..60d7da2a9 --- /dev/null +++ b/mirai-core/src/nativeTest/kotlin/testFramework/DynamicTest.kt @@ -0,0 +1,32 @@ +/* + * Copyright 2019-2022 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.internal.testFramework + +import kotlin.test.Test + +actual typealias TestFactory = Test + +actual open class DynamicTest( + val displayName: String, + val action: () -> Unit, +) + +@Suppress("ACTUAL_WITHOUT_EXPECT") +actual typealias DynamicTestsResult = Unit + +actual fun dynamicTest(displayName: String, action: () -> Unit): DynamicTest = DynamicTest(displayName, action) + +actual fun runDynamicTests(dynamicTests: List) { + for (dynamicTest in dynamicTests) { + println("=".repeat(32) + " ${dynamicTest.displayName} " + "=".repeat(32)) + dynamicTest.action.invoke() + println("=".repeat(32) + "=".repeat(dynamicTest.displayName.length + 2) + "=".repeat(32)) + } +} \ No newline at end of file