From e17b8ad2a4b3373e81c66b5413549b66baa043d2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ivan=20=E2=80=9CCLOVIS=E2=80=9D=20Canet?= Date: Sat, 27 Sep 2025 15:20:28 +0200 Subject: [PATCH 1/4] feat(runner-testBalloon): Align the default timeout to 10s instead of 1m, like the other runners MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit You can increase the timeout by specifying it explicitly: ```kotlin val FooTest by preparedSuite(preparedConfig = CoroutineTimeout(30.seconds)) { test("foo", CoroutineTimeout(5.seconds)) { … } } ``` --- runners/runner-testballoon/src/commonMain/kotlin/Suite.kt | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/runners/runner-testballoon/src/commonMain/kotlin/Suite.kt b/runners/runner-testballoon/src/commonMain/kotlin/Suite.kt index 4c4fe99..4391f62 100644 --- a/runners/runner-testballoon/src/commonMain/kotlin/Suite.kt +++ b/runners/runner-testballoon/src/commonMain/kotlin/Suite.kt @@ -25,7 +25,6 @@ import opensavvy.prepared.suite.config.TestConfig import opensavvy.prepared.suite.runTestDslSuspend import kotlin.coroutines.CoroutineContext import kotlin.coroutines.EmptyCoroutineContext -import kotlin.time.Duration.Companion.seconds import de.infix.testBalloon.framework.TestConfig as BalloonTestConfig @PreparedDslMarker @@ -72,7 +71,7 @@ private class TestBalloonSuite( private fun TestConfig.toBalloon(): BalloonTestConfig { var config = BalloonTestConfig - .testScope(isEnabled = true, timeout = this[CoroutineTimeout]?.duration ?: 60.seconds) + .testScope(isEnabled = true, timeout = this[CoroutineTimeout]?.duration ?: CoroutineTimeout.Default) if (this[Ignored] != null) config = config.disable() -- 2.51.2 From 614e996306078702896876c8b0fac64582787f1e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ivan=20=E2=80=9CCLOVIS=E2=80=9D=20Canet?= Date: Sat, 27 Sep 2025 15:56:34 +0200 Subject: [PATCH 2/4] feat(runner-testBalloon): The TestBalloon runner is now compatible with JDK 11 --- .../src/commonTest/kotlin/EnsureRaisesTest.kt | 4 ++-- runners/runner-testballoon/build.gradle.kts | 20 +++++++++++++++++++ .../kotlin/assertions/ExceptionsTest.kt | 4 ++-- 3 files changed, 24 insertions(+), 4 deletions(-) diff --git a/compat/compat-arrow/src/commonTest/kotlin/EnsureRaisesTest.kt b/compat/compat-arrow/src/commonTest/kotlin/EnsureRaisesTest.kt index c738133..bc7974e 100644 --- a/compat/compat-arrow/src/commonTest/kotlin/EnsureRaisesTest.kt +++ b/compat/compat-arrow/src/commonTest/kotlin/EnsureRaisesTest.kt @@ -34,7 +34,7 @@ val CheckRaisesTest by preparedSuite { 5 } } - check(e.message matches "Expected to fail with .*Any, but the operation was successful and returned 5") + check(e.message matches "Expected to fail with .*(Any|Object).*, but the operation was successful and returned 5") } test("Throws when the wrong thing is raised") { @@ -52,7 +52,7 @@ val CheckRaisesTest by preparedSuite { 5 } } - check(e.message matches "Expected to fail with .*Any, but the operation was successful and returned 5") + check(e.message matches "Expected to fail with .*(Any|Object).*, but the operation was successful and returned 5") } test("Throws when the wrong thing is raised") { diff --git a/runners/runner-testballoon/build.gradle.kts b/runners/runner-testballoon/build.gradle.kts index 0d09300..d81ecbd 100644 --- a/runners/runner-testballoon/build.gradle.kts +++ b/runners/runner-testballoon/build.gradle.kts @@ -1,3 +1,19 @@ +/* + * Copyright (c) 2025, OpenSavvy and contributors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + @file:OptIn(ExperimentalWasmDsl::class) import org.jetbrains.kotlin.gradle.ExperimentalWasmDsl @@ -56,3 +72,7 @@ library { url.set("https://www.apache.org/licenses/LICENSE-2.0.txt") } } + +kotlin { + jvmToolchain(11) +} diff --git a/suite/src/commonTest/kotlin/assertions/ExceptionsTest.kt b/suite/src/commonTest/kotlin/assertions/ExceptionsTest.kt index 9cd9228..72622b1 100644 --- a/suite/src/commonTest/kotlin/assertions/ExceptionsTest.kt +++ b/suite/src/commonTest/kotlin/assertions/ExceptionsTest.kt @@ -32,7 +32,7 @@ val ExceptionAssertionsTest by preparedSuite { error("This should go through the 'checkThrows' call") } } catch (e: AssertionError) { - check(e.message matches "Expected to throw .*IllegalArgumentException, but the operation threw the exception .*IllegalStateException: This should go through the 'checkThrows' call \\(see cause below for details\\)") + check(e.message matches "Expected to throw .*IllegalArgumentException.*, but the operation threw the exception .*IllegalStateException: This should go through the 'checkThrows' call \\(see cause below for details\\)") check(e.cause?.message == "This should go through the 'checkThrows' call") } } @@ -44,7 +44,7 @@ val ExceptionAssertionsTest by preparedSuite { val a = 5 } } catch (e: AssertionError) { - check(e.message matches "Expected to throw .*IllegalArgumentException, but the operation was successful and returned: .*Unit") + check(e.message matches "Expected to throw .*IllegalArgumentException.*, but the operation was successful and returned: .*Unit") } } -- 2.51.2 From bc88c6c8c3a252235568cb9d1463b7d8410deea9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ivan=20=E2=80=9CCLOVIS=E2=80=9D=20Canet?= Date: Sat, 27 Sep 2025 16:04:53 +0200 Subject: [PATCH 3/4] refactor(suite): Allow specifying platform-specific test setup --- suite/src/commonMain/kotlin/RunTest.kt | 4 +++- suite/src/jsMain/kotlin/RunTest.js.kt | 22 +++++++++++++++++++ suite/src/jvmMain/kotlin/RunTest.jvm.kt | 22 +++++++++++++++++++ suite/src/nativeMain/kotlin/RunTest.native.kt | 22 +++++++++++++++++++ suite/src/wasmJsMain/kotlin/RunTest.wasmJs.kt | 22 +++++++++++++++++++ .../wasmWasiMain/kotlin/RunTest.wasmWasi.kt | 22 +++++++++++++++++++ 6 files changed, 113 insertions(+), 1 deletion(-) create mode 100644 suite/src/jsMain/kotlin/RunTest.js.kt create mode 100644 suite/src/jvmMain/kotlin/RunTest.jvm.kt create mode 100644 suite/src/nativeMain/kotlin/RunTest.native.kt create mode 100644 suite/src/wasmJsMain/kotlin/RunTest.wasmJs.kt create mode 100644 suite/src/wasmWasiMain/kotlin/RunTest.wasmWasi.kt diff --git a/suite/src/commonMain/kotlin/RunTest.kt b/suite/src/commonMain/kotlin/RunTest.kt index ec0172a..c5d81e1 100644 --- a/suite/src/commonMain/kotlin/RunTest.kt +++ b/suite/src/commonMain/kotlin/RunTest.kt @@ -55,7 +55,7 @@ suspend fun TestScope.runTestDslSuspend(name: String, config: TestConfig, block: var successful = false try { - test.block() + test.platformSpecificFeatures(block) successful = true } catch (e: Throwable) { println() @@ -66,3 +66,5 @@ suspend fun TestScope.runTestDslSuspend(name: String, config: TestConfig, block: } } } + +internal expect suspend inline fun TestDsl.platformSpecificFeatures(block: suspend TestDsl.() -> Unit) diff --git a/suite/src/jsMain/kotlin/RunTest.js.kt b/suite/src/jsMain/kotlin/RunTest.js.kt new file mode 100644 index 0000000..44c1982 --- /dev/null +++ b/suite/src/jsMain/kotlin/RunTest.js.kt @@ -0,0 +1,22 @@ +/* + * Copyright (c) 2025, OpenSavvy and contributors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package opensavvy.prepared.suite + +internal actual suspend inline fun TestDsl.platformSpecificFeatures(block: suspend TestDsl.() -> Unit) { + // Nothing platform-specific on JS. + block() +} diff --git a/suite/src/jvmMain/kotlin/RunTest.jvm.kt b/suite/src/jvmMain/kotlin/RunTest.jvm.kt new file mode 100644 index 0000000..ef14b47 --- /dev/null +++ b/suite/src/jvmMain/kotlin/RunTest.jvm.kt @@ -0,0 +1,22 @@ +/* + * Copyright (c) 2025, OpenSavvy and contributors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package opensavvy.prepared.suite + +internal actual suspend inline fun TestDsl.platformSpecificFeatures(block: suspend TestDsl.() -> Unit) { + // Nothing platform-specific on the JVM. + block() +} diff --git a/suite/src/nativeMain/kotlin/RunTest.native.kt b/suite/src/nativeMain/kotlin/RunTest.native.kt new file mode 100644 index 0000000..744a961 --- /dev/null +++ b/suite/src/nativeMain/kotlin/RunTest.native.kt @@ -0,0 +1,22 @@ +/* + * Copyright (c) 2025, OpenSavvy and contributors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package opensavvy.prepared.suite + +internal actual suspend inline fun TestDsl.platformSpecificFeatures(block: suspend TestDsl.() -> Unit) { + // Nothing platform-specific on Native. + block() +} diff --git a/suite/src/wasmJsMain/kotlin/RunTest.wasmJs.kt b/suite/src/wasmJsMain/kotlin/RunTest.wasmJs.kt new file mode 100644 index 0000000..57ef91c --- /dev/null +++ b/suite/src/wasmJsMain/kotlin/RunTest.wasmJs.kt @@ -0,0 +1,22 @@ +/* + * Copyright (c) 2025, OpenSavvy and contributors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package opensavvy.prepared.suite + +internal actual suspend inline fun TestDsl.platformSpecificFeatures(block: suspend TestDsl.() -> Unit) { + // Nothing platform-specific on WasmJS. + block() +} diff --git a/suite/src/wasmWasiMain/kotlin/RunTest.wasmWasi.kt b/suite/src/wasmWasiMain/kotlin/RunTest.wasmWasi.kt new file mode 100644 index 0000000..249e0bb --- /dev/null +++ b/suite/src/wasmWasiMain/kotlin/RunTest.wasmWasi.kt @@ -0,0 +1,22 @@ +/* + * Copyright (c) 2025, OpenSavvy and contributors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package opensavvy.prepared.suite + +internal actual suspend inline fun TestDsl.platformSpecificFeatures(block: suspend TestDsl.() -> Unit) { + // Nothing platform-specific on WasmWASI. + block() +} -- 2.51.2 From 29a9b8e6c3bc3ea36f8bf450e8a27df45b3f2285 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ivan=20=E2=80=9CCLOVIS=E2=80=9D=20Canet?= Date: Sat, 27 Sep 2025 16:26:58 +0200 Subject: [PATCH 4/4] feat(suite): On the JVM, install debug probes to running coroutines on test failure --- gradle/libs.versions.toml | 1 + suite/build.gradle.kts | 22 ++++++++++++++++++++++ suite/src/jvmMain/kotlin/RunTest.jvm.kt | 15 ++++++++++++++- 3 files changed, 37 insertions(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 4fe3ef2..cedee96 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -15,6 +15,7 @@ testBalloon = { id = "de.infix.testBalloon", version.ref = "testBalloon" } [libraries] kotlinx-coroutines-core = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-core", version.ref = "kotlinx-coroutines" } +kotlinx-coroutines-debug = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-debug", version.ref = "kotlinx-coroutines" } kotlinx-coroutines-test = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-test", version.ref = "kotlinx-coroutines" } kotlinx-datetime = { module = "org.jetbrains.kotlinx:kotlinx-datetime", version.ref = "kotlinx-datetime" } gradle-testkit = { module = "dev.gradleplugins:gradle-test-kit", version.ref = "gradle-testkit" } diff --git a/suite/build.gradle.kts b/suite/build.gradle.kts index 8fb1274..a95ad7c 100644 --- a/suite/build.gradle.kts +++ b/suite/build.gradle.kts @@ -1,3 +1,19 @@ +/* + * Copyright (c) 2025, OpenSavvy and contributors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + import org.jetbrains.kotlin.gradle.ExperimentalWasmDsl plugins { @@ -43,6 +59,12 @@ kotlin { } } + sourceSets.jvmMain { + dependencies { + implementation(libs.kotlinx.coroutines.debug) + } + } + sourceSets.commonTest { dependencies { implementation(projects.runners.runnerTestballoon) diff --git a/suite/src/jvmMain/kotlin/RunTest.jvm.kt b/suite/src/jvmMain/kotlin/RunTest.jvm.kt index ef14b47..20f392f 100644 --- a/suite/src/jvmMain/kotlin/RunTest.jvm.kt +++ b/suite/src/jvmMain/kotlin/RunTest.jvm.kt @@ -16,7 +16,20 @@ package opensavvy.prepared.suite +import kotlinx.coroutines.ExperimentalCoroutinesApi +import kotlinx.coroutines.debug.DebugProbes + +@OptIn(ExperimentalCoroutinesApi::class) +private val installDebugProbes by shared { + try { + DebugProbes.install() + DebugProbes.enableCreationStackTraces = true + } catch (e: Throwable) { + println("Couldn't install debug probes. Ignoring. Reason: $e") + } +} + internal actual suspend inline fun TestDsl.platformSpecificFeatures(block: suspend TestDsl.() -> Unit) { - // Nothing platform-specific on the JVM. + installDebugProbes() block() } -- 2.51.2