Skip to content

Commit

Permalink
Fixing TestAbortedException not being marked as Ignored (#3587)
Browse files Browse the repository at this point in the history
Co-authored-by: Sam <sam@sksamuel.com>
  • Loading branch information
Kantis and sksamuel committed Jul 29, 2023
1 parent 07c3d8a commit b277f0f
Show file tree
Hide file tree
Showing 7 changed files with 72 additions and 52 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,16 @@ package io.kotest.engine

import io.kotest.common.KotestInternal
import io.kotest.engine.spec.interceptor.SpecInterceptor
import io.kotest.engine.test.interceptors.TestExecutionInterceptor

/**
* Returns the [SpecInterceptor]s that should be used for this platform.
*/
@KotestInternal
internal expect fun specInterceptorsForPlatform(): List<SpecInterceptor>

/**
* Returns the [TestExecutionInterceptor]s that should be used for this platform.
*/
@KotestInternal
internal expect fun testInterceptorsForPlatform(): List<TestExecutionInterceptor>
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ import io.kotest.engine.test.interceptors.TimeoutInterceptor
import io.kotest.engine.test.interceptors.blockedThreadTimeoutInterceptor
import io.kotest.engine.test.interceptors.coroutineDispatcherFactoryInterceptor
import io.kotest.engine.test.interceptors.coroutineErrorCollectorInterceptor
import io.kotest.engine.testInterceptorsForPlatform
import io.kotest.mpp.Logger
import kotlin.time.Duration

Expand Down Expand Up @@ -71,6 +72,7 @@ class TestCaseExecutor(
CoroutineLoggingInterceptor(configuration),
if (platform == Platform.JVM) blockedThreadTimeoutInterceptor(configuration, timeMark) else null,
TimeoutInterceptor(timeMark),
*testInterceptorsForPlatform().toTypedArray(),
TestInvocationInterceptor(
configuration.registry,
timeMark,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ 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
import io.kotest.engine.test.interceptors.TestExecutionInterceptor

@KotestInternal
internal actual fun testEngineInterceptors(): List<EngineInterceptor> {
Expand All @@ -29,3 +30,7 @@ internal actual fun testEngineInterceptors(): List<EngineInterceptor> {
@KotestInternal
internal actual fun specInterceptorsForPlatform(): List<SpecInterceptor> =
listOf()

@KotestInternal
internal actual fun testInterceptorsForPlatform(): List<TestExecutionInterceptor> =
listOf()
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ 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
import io.kotest.engine.test.interceptors.TestExecutionInterceptor

@KotestInternal
internal actual fun testEngineInterceptors(): List<EngineInterceptor> {
Expand All @@ -29,3 +30,7 @@ internal actual fun testEngineInterceptors(): List<EngineInterceptor> {
@KotestInternal
internal actual fun specInterceptorsForPlatform(): List<SpecInterceptor> =
listOf()

@KotestInternal
internal actual fun testInterceptorsForPlatform(): List<TestExecutionInterceptor> =
listOf()
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ 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
import io.kotest.engine.test.interceptors.TestExecutionInterceptor

@KotestInternal
actual fun testEngineInterceptors(): List<EngineInterceptor> {
Expand All @@ -33,4 +34,8 @@ actual fun testEngineInterceptors(): List<EngineInterceptor> {

@KotestInternal
internal actual fun specInterceptorsForPlatform(): List<SpecInterceptor> =
listOf()

@KotestInternal
internal actual fun testInterceptorsForPlatform(): List<TestExecutionInterceptor> =
listOf(MarkAbortedExceptionsAsSkippedTestInterceptor)
Original file line number Diff line number Diff line change
@@ -1,11 +1,10 @@
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 io.kotest.core.test.TestScope
import io.kotest.engine.test.interceptors.TestExecutionInterceptor
import org.opentest4j.TestAbortedException

/**
Expand All @@ -15,19 +14,17 @@ import org.opentest4j.TestAbortedException
* Note: This is a JVM only feature.
*/
@JVMOnly
internal object MarkAbortedExceptionsAsSkippedTestInterceptor : SpecInterceptor {

internal object MarkAbortedExceptionsAsSkippedTestInterceptor : TestExecutionInterceptor {
override suspend fun intercept(
spec: Spec,
fn: suspend (Spec) -> Result<Map<TestCase, TestResult>>
): Result<Map<TestCase, TestResult>> {
return fn(spec).map { success ->
success.mapValues { (_, result) ->
if (result.errorOrNull is TestAbortedException) {
TestResult.Ignored
} else {
result
}
testCase: TestCase,
scope: TestScope,
test: suspend (TestCase, TestScope) -> TestResult
): TestResult {
return test(testCase, scope).let { testResult ->
if (testResult.errorOrNull is TestAbortedException) {
TestResult.Ignored
} else {
testResult
}
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,64 +1,63 @@
package com.sksamuel.kotest.engine.interceptors

import io.kotest.assertions.fail
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.TestEngineLauncher
import io.kotest.engine.interceptors.MarkAbortedExceptionsAsSkippedTestInterceptor
import io.kotest.engine.listener.CollectingTestEngineListener
import io.kotest.inspectors.forOne
import io.kotest.matchers.booleans.shouldBeTrue
import io.kotest.matchers.collections.shouldContainExactly
import io.kotest.matchers.collections.shouldMatchEach
import io.kotest.matchers.maps.shouldContainAll
import io.kotest.matchers.maps.shouldMatchAll
import io.kotest.matchers.result.shouldBeSuccess
import io.kotest.matchers.shouldBe
import io.kotest.matchers.types.shouldBeInstanceOf
import org.opentest4j.TestAbortedException
import kotlin.time.Duration.Companion.milliseconds

class AbortedExceptionTest : FreeSpec({
"TestAbortedException is handled" {
val collector = CollectingTestEngineListener()

TestEngineLauncher(collector)
.withClasses(DummySpec::class)
.launch()

collector.tests.toList().shouldMatchEach(
{
it.first.name.testName shouldBe "Test should be marked as Ignored"
it.second.isIgnored.shouldBeTrue()
},
{
it.first.name.testName shouldBe "Failure is not reclassified"
it.second.isFailure.shouldBeTrue()
},
{
it.first.name.testName shouldBe "Successful test is not reclassified"
it.second.isSuccess.shouldBeTrue()
}
)
}
})

val fakeTestCase = TestCase(
Descriptor.TestDescriptor(
Descriptor.SpecDescriptor(DescriptorId("dummy"), DummySpec::class),
DescriptorId("test")
), TestName("dummy"), DummySpec(), {}, type = TestType.Test
)

private class DummySpec : FreeSpec({
"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)
throw TestAbortedException()
}

"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))
fail("should not be ignored")
}

"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()

0 comments on commit b277f0f

Please sign in to comment.