From 745904b1deb1097b2c6bb5f56c24558831b00a6a Mon Sep 17 00:00:00 2001 From: Emil Kantis Date: Sat, 29 Oct 2022 00:08:54 +0200 Subject: [PATCH 1/2] Adding JVM SpecInterceptor reclassifying aborted tests as Ignored --- .../io/kotest/engine/SpecInterceptors.kt | 10 +++++ .../io/kotest/engine/spec/SpecExecutor.kt | 3 +- ...tEngineInterceptors.kt => interceptors.kt} | 5 +++ .../kotlin/io/kotest/engine/interceptors.kt | 5 +++ .../kotlin/io/kotest/engine/interceptors.kt | 6 +++ ...ortedExceptionsAsSkippedTestInterceptor.kt | 34 ++++++++++++++++ .../interceptors/AbortedExceptionTest.kt | 39 +++++++++++++++++++ 7 files changed, 101 insertions(+), 1 deletion(-) create mode 100644 kotest-framework/kotest-framework-engine/src/commonMain/kotlin/io/kotest/engine/SpecInterceptors.kt rename kotest-framework/kotest-framework-engine/src/desktopMain/kotlin/io/kotest/engine/{TestEngineInterceptors.kt => interceptors.kt} (87%) create mode 100644 kotest-framework/kotest-framework-engine/src/jvmMain/kotlin/io/kotest/engine/interceptors/MarkAbortedExceptionsAsSkippedTestInterceptor.kt create mode 100644 kotest-framework/kotest-framework-engine/src/jvmTest/kotlin/com/sksamuel/kotest/engine/interceptors/AbortedExceptionTest.kt diff --git a/kotest-framework/kotest-framework-engine/src/commonMain/kotlin/io/kotest/engine/SpecInterceptors.kt b/kotest-framework/kotest-framework-engine/src/commonMain/kotlin/io/kotest/engine/SpecInterceptors.kt new file mode 100644 index 00000000000..29cd252ec72 --- /dev/null +++ b/kotest-framework/kotest-framework-engine/src/commonMain/kotlin/io/kotest/engine/SpecInterceptors.kt @@ -0,0 +1,10 @@ +package io.kotest.engine + +import io.kotest.common.KotestInternal +import io.kotest.engine.spec.interceptor.SpecInterceptor + +/** + * Returns the [SpecInterceptor]s that should be used for this platform. + */ +@KotestInternal +internal expect fun specInterceptorsForPlatform(): List diff --git a/kotest-framework/kotest-framework-engine/src/commonMain/kotlin/io/kotest/engine/spec/SpecExecutor.kt b/kotest-framework/kotest-framework-engine/src/commonMain/kotlin/io/kotest/engine/spec/SpecExecutor.kt index 7045e99f7c5..68428b2a4e7 100644 --- a/kotest-framework/kotest-framework-engine/src/commonMain/kotlin/io/kotest/engine/spec/SpecExecutor.kt +++ b/kotest-framework/kotest-framework-engine/src/commonMain/kotlin/io/kotest/engine/spec/SpecExecutor.kt @@ -31,6 +31,7 @@ import io.kotest.engine.spec.interceptor.SpecRefInterceptor import io.kotest.engine.spec.interceptor.SpecStartedInterceptor import io.kotest.engine.spec.interceptor.SystemPropertySpecFilterInterceptor import io.kotest.engine.spec.interceptor.TagsExcludedSpecInterceptor +import io.kotest.engine.specInterceptorsForPlatform import io.kotest.mpp.Logger import io.kotest.mpp.bestName import kotlin.reflect.KClass @@ -98,7 +99,7 @@ class SpecExecutor( ProjectContextInterceptor(context.toProjectContext()), SpecExtensionInterceptor(context.configuration.registry), ConfigurationInContextInterceptor(context.configuration), - ) + ) + specInterceptorsForPlatform() val initial: suspend (Spec) -> Result> = { try { diff --git a/kotest-framework/kotest-framework-engine/src/desktopMain/kotlin/io/kotest/engine/TestEngineInterceptors.kt b/kotest-framework/kotest-framework-engine/src/desktopMain/kotlin/io/kotest/engine/interceptors.kt similarity index 87% rename from kotest-framework/kotest-framework-engine/src/desktopMain/kotlin/io/kotest/engine/TestEngineInterceptors.kt rename to kotest-framework/kotest-framework-engine/src/desktopMain/kotlin/io/kotest/engine/interceptors.kt index b0aa565ab66..fe6227d1a2b 100644 --- a/kotest-framework/kotest-framework-engine/src/desktopMain/kotlin/io/kotest/engine/TestEngineInterceptors.kt +++ b/kotest-framework/kotest-framework-engine/src/desktopMain/kotlin/io/kotest/engine/interceptors.kt @@ -10,6 +10,7 @@ import io.kotest.engine.interceptors.SpecSortEngineInterceptor import io.kotest.engine.interceptors.TestDslStateInterceptor import io.kotest.engine.interceptors.TestEngineInitializedInterceptor import io.kotest.engine.interceptors.TestEngineStartedFinishedInterceptor +import io.kotest.engine.spec.interceptor.SpecInterceptor @KotestInternal internal actual fun testEngineInterceptors(): List { @@ -24,3 +25,7 @@ internal actual fun testEngineInterceptors(): List { TestEngineInitializedInterceptor, ) } + +@KotestInternal +internal actual fun specInterceptorsForPlatform(): List = + listOf() diff --git a/kotest-framework/kotest-framework-engine/src/jsMain/kotlin/io/kotest/engine/interceptors.kt b/kotest-framework/kotest-framework-engine/src/jsMain/kotlin/io/kotest/engine/interceptors.kt index b0aa565ab66..fe6227d1a2b 100644 --- a/kotest-framework/kotest-framework-engine/src/jsMain/kotlin/io/kotest/engine/interceptors.kt +++ b/kotest-framework/kotest-framework-engine/src/jsMain/kotlin/io/kotest/engine/interceptors.kt @@ -10,6 +10,7 @@ import io.kotest.engine.interceptors.SpecSortEngineInterceptor import io.kotest.engine.interceptors.TestDslStateInterceptor import io.kotest.engine.interceptors.TestEngineInitializedInterceptor import io.kotest.engine.interceptors.TestEngineStartedFinishedInterceptor +import io.kotest.engine.spec.interceptor.SpecInterceptor @KotestInternal internal actual fun testEngineInterceptors(): List { @@ -24,3 +25,7 @@ internal actual fun testEngineInterceptors(): List { TestEngineInitializedInterceptor, ) } + +@KotestInternal +internal actual fun specInterceptorsForPlatform(): List = + listOf() diff --git a/kotest-framework/kotest-framework-engine/src/jvmMain/kotlin/io/kotest/engine/interceptors.kt b/kotest-framework/kotest-framework-engine/src/jvmMain/kotlin/io/kotest/engine/interceptors.kt index 0c050abbb70..50feeed29e1 100644 --- a/kotest-framework/kotest-framework-engine/src/jvmMain/kotlin/io/kotest/engine/interceptors.kt +++ b/kotest-framework/kotest-framework-engine/src/jvmMain/kotlin/io/kotest/engine/interceptors.kt @@ -4,6 +4,7 @@ import io.kotest.common.KotestInternal import io.kotest.engine.interceptors.DumpConfigInterceptor import io.kotest.engine.interceptors.EmptyTestSuiteInterceptor import io.kotest.engine.interceptors.EngineInterceptor +import io.kotest.engine.interceptors.MarkAbortedExceptionsAsSkippedTestInterceptor import io.kotest.engine.interceptors.ProjectExtensionEngineInterceptor import io.kotest.engine.interceptors.ProjectListenerEngineInterceptor import io.kotest.engine.interceptors.ProjectTimeoutEngineInterceptor @@ -12,6 +13,7 @@ import io.kotest.engine.interceptors.TestDslStateInterceptor import io.kotest.engine.interceptors.TestEngineInitializedInterceptor import io.kotest.engine.interceptors.TestEngineStartedFinishedInterceptor import io.kotest.engine.interceptors.WriteFailuresInterceptor +import io.kotest.engine.spec.interceptor.SpecInterceptor @KotestInternal actual fun testEngineInterceptors(): List { @@ -28,3 +30,7 @@ actual fun testEngineInterceptors(): List { TestEngineInitializedInterceptor, ) } + +@KotestInternal +internal actual fun specInterceptorsForPlatform(): List = + listOf(MarkAbortedExceptionsAsSkippedTestInterceptor) diff --git a/kotest-framework/kotest-framework-engine/src/jvmMain/kotlin/io/kotest/engine/interceptors/MarkAbortedExceptionsAsSkippedTestInterceptor.kt b/kotest-framework/kotest-framework-engine/src/jvmMain/kotlin/io/kotest/engine/interceptors/MarkAbortedExceptionsAsSkippedTestInterceptor.kt new file mode 100644 index 00000000000..77661bbb5ca --- /dev/null +++ b/kotest-framework/kotest-framework-engine/src/jvmMain/kotlin/io/kotest/engine/interceptors/MarkAbortedExceptionsAsSkippedTestInterceptor.kt @@ -0,0 +1,34 @@ +package io.kotest.engine.interceptors + +import io.kotest.common.JVMOnly +import io.kotest.common.KotestInternal +import io.kotest.core.spec.Spec +import io.kotest.core.test.TestCase +import io.kotest.core.test.TestResult +import io.kotest.engine.spec.interceptor.SpecInterceptor +import org.opentest4j.TestAbortedException + +/** + * Writes failed specs to a file so that the [io.kotest.engine.spec.FailureFirstSorter] + * can use the file to run failed specs first. + * + * Note: This is a JVM only feature. + */ +@JVMOnly +internal object MarkAbortedExceptionsAsSkippedTestInterceptor : SpecInterceptor { + + override suspend fun intercept( + spec: Spec, + fn: suspend (Spec) -> Result> + ): Result> { + return fn(spec).map { success -> + success.mapValues { (_, result) -> + if (result.errorOrNull is TestAbortedException) { + TestResult.Ignored + } else { + result + } + } + } + } +} diff --git a/kotest-framework/kotest-framework-engine/src/jvmTest/kotlin/com/sksamuel/kotest/engine/interceptors/AbortedExceptionTest.kt b/kotest-framework/kotest-framework-engine/src/jvmTest/kotlin/com/sksamuel/kotest/engine/interceptors/AbortedExceptionTest.kt new file mode 100644 index 00000000000..9989b108538 --- /dev/null +++ b/kotest-framework/kotest-framework-engine/src/jvmTest/kotlin/com/sksamuel/kotest/engine/interceptors/AbortedExceptionTest.kt @@ -0,0 +1,39 @@ +package com.sksamuel.kotest.engine.interceptors + +import io.kotest.core.descriptors.Descriptor +import io.kotest.core.descriptors.DescriptorId +import io.kotest.core.names.TestName +import io.kotest.core.spec.style.FreeSpec +import io.kotest.core.test.TestCase +import io.kotest.core.test.TestResult +import io.kotest.core.test.TestType +import io.kotest.engine.interceptors.MarkAbortedExceptionsAsSkippedTestInterceptor +import io.kotest.matchers.collections.shouldContainExactly +import io.kotest.matchers.result.shouldBeSuccess +import org.opentest4j.TestAbortedException +import kotlin.time.Duration.Companion.milliseconds + +class AbortedExceptionTest : FreeSpec({ + + val fakeTestCase = TestCase( + Descriptor.TestDescriptor( + Descriptor.SpecDescriptor(DescriptorId("dummy"), DummySpec::class), + DescriptorId("test") + ), TestName("dummy"), DummySpec(), {}, type = TestType.Test + ) + + "Test should be marked as Ignored" { + val result = MarkAbortedExceptionsAsSkippedTestInterceptor.intercept(DummySpec()) { + Result.success( + mapOf(fakeTestCase to TestResult.Error(1.milliseconds, TestAbortedException())) + ) + } + + result.shouldBeSuccess() + .values + .shouldContainExactly(TestResult.Ignored) + } +}) + +private class DummySpec : FreeSpec() + From dd96c52543b70a5af72433c513225c6253e7dc60 Mon Sep 17 00:00:00 2001 From: Emil Kantis Date: Sat, 29 Oct 2022 00:13:47 +0200 Subject: [PATCH 2/2] Adding tests for TestResult.Success and TestResult.Failure --- .../interceptors/AbortedExceptionTest.kt | 25 +++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/kotest-framework/kotest-framework-engine/src/jvmTest/kotlin/com/sksamuel/kotest/engine/interceptors/AbortedExceptionTest.kt b/kotest-framework/kotest-framework-engine/src/jvmTest/kotlin/com/sksamuel/kotest/engine/interceptors/AbortedExceptionTest.kt index 9989b108538..9f7cdf63e8a 100644 --- a/kotest-framework/kotest-framework-engine/src/jvmTest/kotlin/com/sksamuel/kotest/engine/interceptors/AbortedExceptionTest.kt +++ b/kotest-framework/kotest-framework-engine/src/jvmTest/kotlin/com/sksamuel/kotest/engine/interceptors/AbortedExceptionTest.kt @@ -33,6 +33,31 @@ class AbortedExceptionTest : FreeSpec({ .values .shouldContainExactly(TestResult.Ignored) } + + "Failure is not reclassified" { + val assertionError = AssertionError("blah") + val result = MarkAbortedExceptionsAsSkippedTestInterceptor.intercept(DummySpec()) { + Result.success( + mapOf(fakeTestCase to TestResult.Failure(1.milliseconds, assertionError)) + ) + } + + result.shouldBeSuccess() + .values + .shouldContainExactly(TestResult.Failure(1.milliseconds, assertionError)) + } + + "Successful test is not reclassified" { + val result = MarkAbortedExceptionsAsSkippedTestInterceptor.intercept(DummySpec()) { + Result.success( + mapOf(fakeTestCase to TestResult.Success(1.milliseconds)) + ) + } + + result.shouldBeSuccess() + .values + .shouldContainExactly(TestResult.Success(1.milliseconds)) + } }) private class DummySpec : FreeSpec()