Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Tags defined in spec should be applied before listeners #3189

Merged
merged 9 commits into from
Mar 23, 2023
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import io.kotest.core.project.TestSuite
import io.kotest.engine.interceptors.EngineContext
import io.kotest.engine.interceptors.EngineInterceptor
import io.kotest.engine.listener.TestEngineListener
import io.kotest.engine.tags.runtimeTags
import io.kotest.engine.tags.runtimeTagExpression
import io.kotest.mpp.Logger

data class EngineResult(val errors: List<Throwable>) {
Expand Down Expand Up @@ -68,7 +68,7 @@ class TestEngine(private val config: TestEngineConfig) {
{ context -> extension.intercept(context, next) }
}

val tags = config.configuration.runtimeTags()
val tags = config.configuration.runtimeTagExpression()
logger.log { Pair(null, "TestEngine: Active tags: ${tags.expression}") }

return execute(EngineContext(suite, config.listener, tags, config.configuration))
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
package io.kotest.engine.config

import io.kotest.core.config.ProjectConfiguration
import io.kotest.engine.tags.runtimeTags
import io.kotest.engine.tags.runtimeTagExpression
import io.kotest.mpp.bestName

fun ProjectConfiguration.createConfigSummary(): String {
Expand Down Expand Up @@ -48,7 +48,7 @@ fun ProjectConfiguration.createConfigSummary(): String {
}
}

runtimeTags().expression?.let { sb.buildOutput("Tags", it) }
runtimeTagExpression().expression?.let { sb.buildOutput("Tags", it) }
return sb.toString()
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,23 +14,24 @@ import io.kotest.core.test.TestResult
import io.kotest.engine.interceptors.EngineContext
import io.kotest.engine.interceptors.toProjectContext
import io.kotest.engine.listener.TestEngineListener
import io.kotest.engine.spec.interceptor.ApplyExtensionsInterceptor
import io.kotest.engine.spec.interceptor.ConfigurationInContextInterceptor
import io.kotest.engine.spec.interceptor.EnabledIfSpecInterceptor
import io.kotest.engine.spec.interceptor.FinalizeSpecInterceptor
import io.kotest.engine.spec.interceptor.ref.ApplyExtensionsInterceptor
import io.kotest.engine.spec.interceptor.ConfigurationInContextSpecInterceptor
import io.kotest.engine.spec.interceptor.ref.EnabledIfInterceptor
import io.kotest.engine.spec.interceptor.ref.FinalizeSpecInterceptor
import io.kotest.engine.spec.interceptor.IgnoreNestedSpecStylesInterceptor
import io.kotest.engine.spec.interceptor.IgnoredSpecInterceptor
import io.kotest.engine.spec.interceptor.PrepareSpecInterceptor
import io.kotest.engine.spec.interceptor.ref.IgnoredSpecInterceptor
import io.kotest.engine.spec.interceptor.InlineTagSpecInterceptor
import io.kotest.engine.spec.interceptor.ref.PrepareSpecInterceptor
import io.kotest.engine.spec.interceptor.ProjectContextInterceptor
import io.kotest.engine.spec.interceptor.RequiresTagSpecInterceptor
import io.kotest.engine.spec.interceptor.ref.RequiresTagInterceptor
import io.kotest.engine.spec.interceptor.SpecExtensionInterceptor
import io.kotest.engine.spec.interceptor.SpecFilterInterceptor
import io.kotest.engine.spec.interceptor.SpecFinishedInterceptor
import io.kotest.engine.spec.interceptor.SpecRefExtensionInterceptor
import io.kotest.engine.spec.interceptor.ref.SpecFilterInterceptor
import io.kotest.engine.spec.interceptor.ref.SpecFinishedInterceptor
import io.kotest.engine.spec.interceptor.ref.SpecRefExtensionInterceptor
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.spec.interceptor.ref.SpecStartedInterceptor
import io.kotest.engine.spec.interceptor.ref.SystemPropertySpecFilterInterceptor
import io.kotest.engine.spec.interceptor.ref.TagsInterceptor
import io.kotest.mpp.Logger
import io.kotest.mpp.bestName
import kotlin.reflect.KClass
Expand Down Expand Up @@ -67,12 +68,12 @@ class SpecExecutor(
private suspend fun referenceInterceptors(ref: SpecRef) {

val interceptors = listOfNotNull(
if (platform == Platform.JVM) EnabledIfSpecInterceptor(listener, context.configuration.registry) else null,
if (platform == Platform.JVM) EnabledIfInterceptor(listener, context.configuration.registry) else null,
IgnoredSpecInterceptor(listener, context.configuration.registry),
SpecFilterInterceptor(listener, context.configuration.registry),
SystemPropertySpecFilterInterceptor(listener, context.configuration.registry),
TagsExcludedSpecInterceptor(listener, context.configuration),
if (platform == Platform.JVM) RequiresTagSpecInterceptor(listener, context.configuration, context.configuration.registry) else null,
TagsInterceptor(listener, context.configuration),
if (platform == Platform.JVM) RequiresTagInterceptor(listener, context.configuration, context.configuration.registry) else null,
SpecRefExtensionInterceptor(context.configuration.registry),
SpecStartedInterceptor(listener),
SpecFinishedInterceptor(listener),
Expand All @@ -97,7 +98,8 @@ class SpecExecutor(
if (platform == Platform.JS) IgnoreNestedSpecStylesInterceptor(listener, context.configuration.registry) else null,
ProjectContextInterceptor(context.toProjectContext()),
SpecExtensionInterceptor(context.configuration.registry),
ConfigurationInContextInterceptor(context.configuration),
ConfigurationInContextSpecInterceptor(context.configuration),
InlineTagSpecInterceptor(listener, context.configuration),
)

val initial: suspend (Spec) -> Result<Map<TestCase, TestResult>> = {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import kotlinx.coroutines.withContext
* A [SpecInterceptor] that injects the [ProjectConfiguration] into the coroutine context
* so it can be extracted in specs and tests.
*/
class ConfigurationInContextInterceptor(
class ConfigurationInContextSpecInterceptor(
private val projectConfiguration: ProjectConfiguration
) : SpecInterceptor {

Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package io.kotest.engine.spec.interceptor

import io.kotest.common.KotestInternal
import io.kotest.common.flatMap
import io.kotest.core.config.ExtensionRegistry
import io.kotest.core.spec.Spec
Expand All @@ -18,11 +19,15 @@ import io.kotest.mpp.log
/**
* Filters [Spec]'s that are not compatible on platforms that disallow nested tests.
*/
@KotestInternal
internal class IgnoreNestedSpecStylesInterceptor(
private val listener: TestEngineListener,
registry: ExtensionRegistry,
) : SpecInterceptor {

// note: this must be a spec interceptor until js / native have the ability to poke into the class hierarchy
// using some equivalent of reflection

private val extensions = SpecExtensions(registry)

override suspend fun intercept(
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
package io.kotest.engine.spec.interceptor

import io.kotest.common.flatMap
import io.kotest.core.config.ProjectConfiguration
import io.kotest.core.spec.Spec
import io.kotest.core.test.TestCase
import io.kotest.core.test.TestResult
import io.kotest.engine.listener.TestEngineListener
import io.kotest.engine.spec.SpecExtensions
import io.kotest.engine.tags.isPotentiallyActive
import io.kotest.engine.tags.parse
import io.kotest.engine.tags.runtimeTagExpression

/**
* A [SpecInterceptor] that skips this [Spec] if it contains inline tags which don't satisfy
* the current tag expression.
*/
class InlineTagSpecInterceptor(
private val listener: TestEngineListener,
private val projectConfiguration: ProjectConfiguration,
) : SpecInterceptor {

private val extensions = SpecExtensions(projectConfiguration.registry)

override suspend fun intercept(
spec: Spec,
fn: suspend (Spec) -> Result<Map<TestCase, TestResult>>
): Result<Map<TestCase, TestResult>> {
val alltags = spec.tags() + spec.appliedTags()
val active = projectConfiguration.runtimeTagExpression().parse().isPotentiallyActive(alltags)
return if (active) fn(spec) else {
val reason = "Ignored due to tags in spec: ${alltags.joinToString(", ")}"
runCatching { listener.specIgnored(spec::class, reason) }
.flatMap { extensions.ignored(spec::class, reason) }
.map { emptyMap() }
}
}
}

Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package io.kotest.engine.spec.interceptor
package io.kotest.engine.spec.interceptor.ref

import io.kotest.common.flatMap
import io.kotest.core.config.ExtensionRegistry
Expand All @@ -8,6 +8,7 @@ import io.kotest.core.spec.SpecRef
import io.kotest.core.test.TestCase
import io.kotest.core.test.TestResult
import io.kotest.engine.extensions.SpecWrapperExtension
import io.kotest.engine.spec.interceptor.SpecRefInterceptor
import io.kotest.mpp.annotation
import io.kotest.mpp.newInstanceNoArgConstructorOrObjectInstance

Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package io.kotest.engine.spec.interceptor
package io.kotest.engine.spec.interceptor.ref

import io.kotest.common.flatMap
import io.kotest.core.annotation.EnabledIf
Expand All @@ -9,6 +9,7 @@ import io.kotest.core.test.TestCase
import io.kotest.core.test.TestResult
import io.kotest.engine.listener.TestEngineListener
import io.kotest.engine.spec.SpecExtensions
import io.kotest.engine.spec.interceptor.SpecRefInterceptor
import io.kotest.mpp.annotation
import io.kotest.mpp.newInstanceNoArgConstructor

Expand All @@ -18,7 +19,7 @@ import io.kotest.mpp.newInstanceNoArgConstructor
*
* Note: annotations are only available on the JVM.
*/
internal class EnabledIfSpecInterceptor(
internal class EnabledIfInterceptor(
private val listener: TestEngineListener,
registry: ExtensionRegistry,
) : SpecRefInterceptor {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,16 @@
package io.kotest.engine.spec.interceptor
package io.kotest.engine.spec.interceptor.ref

import io.kotest.core.config.ExtensionRegistry
import io.kotest.core.listeners.FinalizeSpecListener
import io.kotest.core.spec.SpecRef
import io.kotest.core.test.TestCase
import io.kotest.core.test.TestResult
import io.kotest.engine.spec.SpecExtensions
import io.kotest.engine.spec.interceptor.SpecRefInterceptor

/**
* A [SpecRefInterceptor] that invokes any [FinalizeSpecListener.finalizeSpec] callbacks.
*/
internal class FinalizeSpecInterceptor(
registry: ExtensionRegistry,
) : SpecRefInterceptor {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package io.kotest.engine.spec.interceptor
package io.kotest.engine.spec.interceptor.ref

import io.kotest.common.KotestInternal
import io.kotest.common.flatMap
Expand All @@ -9,6 +9,7 @@ import io.kotest.core.test.TestCase
import io.kotest.core.test.TestResult
import io.kotest.engine.listener.TestEngineListener
import io.kotest.engine.spec.SpecExtensions
import io.kotest.engine.spec.interceptor.SpecRefInterceptor
import io.kotest.mpp.Logger
import io.kotest.mpp.annotation
import io.kotest.mpp.bestName
Expand Down
Original file line number Diff line number Diff line change
@@ -1,12 +1,17 @@
package io.kotest.engine.spec.interceptor
package io.kotest.engine.spec.interceptor.ref

import io.kotest.common.flatMap
import io.kotest.core.config.ExtensionRegistry
import io.kotest.core.listeners.PrepareSpecListener
import io.kotest.core.spec.SpecRef
import io.kotest.core.test.TestCase
import io.kotest.core.test.TestResult
import io.kotest.engine.spec.SpecExtensions
import io.kotest.engine.spec.interceptor.SpecRefInterceptor

/**
* A [SpecRefInterceptor] that invokes any [PrepareSpecListener.prepareSpec] callbacks.
*/
class PrepareSpecInterceptor(registry: ExtensionRegistry) : SpecRefInterceptor {

private val extensions = SpecExtensions(registry)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package io.kotest.engine.spec.interceptor
package io.kotest.engine.spec.interceptor.ref

import io.kotest.common.flatMap
import io.kotest.core.NamedTag
Expand All @@ -12,16 +12,17 @@ import io.kotest.core.test.TestCase
import io.kotest.core.test.TestResult
import io.kotest.engine.listener.TestEngineListener
import io.kotest.engine.spec.SpecExtensions
import io.kotest.engine.spec.interceptor.SpecRefInterceptor
import io.kotest.engine.tags.isActive
import io.kotest.engine.tags.parse
import io.kotest.engine.tags.runtimeTags
import io.kotest.engine.tags.runtimeTagExpression
import io.kotest.mpp.annotation

/**
* A [SpecFilter] which will ignore specs if they are annotated with @[RequiresTag]
* and those tags are not present in the runtime tags.
*/
internal class RequiresTagSpecInterceptor(
internal class RequiresTagInterceptor(
private val listener: TestEngineListener,
private val configuration: ProjectConfiguration,
private val registry: ExtensionRegistry,
Expand All @@ -35,7 +36,7 @@ internal class RequiresTagSpecInterceptor(
null -> fn(ref)
else -> {
val requiredTags = annotation.wrapper.map { NamedTag(it) }.toSet()
val expr = configuration.runtimeTags().parse()
val expr = configuration.runtimeTagExpression().parse()
if (requiredTags.isEmpty() || expr.isActive(requiredTags)) {
fn(ref)
} else {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package io.kotest.engine.spec.interceptor
package io.kotest.engine.spec.interceptor.ref

import io.kotest.core.config.ExtensionRegistry
import io.kotest.core.filter.SpecFilter
Expand All @@ -8,6 +8,7 @@ import io.kotest.core.test.TestCase
import io.kotest.core.test.TestResult
import io.kotest.engine.listener.TestEngineListener
import io.kotest.engine.spec.SpecExtensions
import io.kotest.engine.spec.interceptor.SpecRefInterceptor
import io.kotest.mpp.Logger
import io.kotest.mpp.bestName

Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
package io.kotest.engine.spec.interceptor
package io.kotest.engine.spec.interceptor.ref

import io.kotest.core.spec.SpecRef
import io.kotest.core.test.TestCase
import io.kotest.core.test.TestResult
import io.kotest.engine.listener.TestEngineListener
import io.kotest.engine.spec.interceptor.SpecRefInterceptor
import io.kotest.mpp.timeInMillis
import kotlin.time.Duration

Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
package io.kotest.engine.spec.interceptor
package io.kotest.engine.spec.interceptor.ref

import io.kotest.core.config.ExtensionRegistry
import io.kotest.core.extensions.SpecRefExtension
import io.kotest.core.spec.SpecRef
import io.kotest.core.test.TestCase
import io.kotest.core.test.TestResult
import io.kotest.engine.spec.interceptor.SpecRefInterceptor
import io.kotest.mpp.Logger
import io.kotest.mpp.bestName

Expand Down
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
package io.kotest.engine.spec.interceptor
package io.kotest.engine.spec.interceptor.ref

import io.kotest.common.flatMap
import io.kotest.core.spec.SpecRef
import io.kotest.core.test.TestCase
import io.kotest.core.test.TestResult
import io.kotest.engine.listener.TestEngineListener
import io.kotest.engine.spec.interceptor.SpecRefInterceptor

/**
* A [SpecRefInterceptor] that invokes the [specStarted] test engine listener callbacks.
* A [SpecRefInterceptor] that invokes the [TestEngineListener.specStarted] callbacks.
*/
internal class SpecStartedInterceptor(private val listener: TestEngineListener) : SpecRefInterceptor {

Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package io.kotest.engine.spec.interceptor
package io.kotest.engine.spec.interceptor.ref

import io.kotest.common.KotestInternal
import io.kotest.common.flatMap
Expand All @@ -11,6 +11,7 @@ import io.kotest.core.test.TestCase
import io.kotest.core.test.TestResult
import io.kotest.engine.listener.TestEngineListener
import io.kotest.engine.spec.SpecExtensions
import io.kotest.engine.spec.interceptor.SpecRefInterceptor
import io.kotest.mpp.Logger
import io.kotest.mpp.bestName
import io.kotest.mpp.syspropOrEnv
Expand Down Expand Up @@ -48,8 +49,12 @@ internal class SystemPropertySpecFilterInterceptor(
return if (included) {
fn(ref)
} else {
runCatching { listener.specIgnored(ref.kclass, "Filtered by ${KotestEngineProperties.filterSpecs} spec filter") }
.flatMap { extensions.ignored(ref.kclass, "Filtered by ${KotestEngineProperties.filterSpecs} spec filter") }
runCatching {
listener.specIgnored(
ref.kclass,
"Filtered by ${KotestEngineProperties.filterSpecs} spec filter"
)
}.flatMap { extensions.ignored(ref.kclass, "Filtered by ${KotestEngineProperties.filterSpecs} spec filter") }
.map { emptyMap() }
}
}
Expand Down
Loading