diff --git a/kotest-framework/kotest-framework-api/api/kotest-framework-api.api b/kotest-framework/kotest-framework-api/api/kotest-framework-api.api index 36864951684..1c7641efd51 100644 --- a/kotest-framework/kotest-framework-api/api/kotest-framework-api.api +++ b/kotest-framework/kotest-framework-api/api/kotest-framework-api.api @@ -87,6 +87,7 @@ public abstract class io/kotest/core/TestConfiguration { public final fun setAssertSoftly (Ljava/lang/Boolean;)V public final fun setAssertions (Lio/kotest/core/test/AssertionMode;)V public final fun setDefaultTestConfig (Lio/kotest/core/test/config/TestCaseConfig;)V + public final fun setParentConfiguration (Lio/kotest/core/TestConfiguration;)V public final fun tags ([Lio/kotest/core/Tag;)V } @@ -1474,16 +1475,18 @@ public final class io/kotest/core/factory/FactoryId$Companion { } public final class io/kotest/core/factory/TestFactory { - public fun (Lio/kotest/core/factory/FactoryId;Ljava/util/List;Ljava/util/Set;Lio/kotest/core/test/AssertionMode;Ljava/util/List;)V + public fun (Lio/kotest/core/factory/FactoryId;Ljava/util/List;Ljava/util/Set;Lio/kotest/core/test/AssertionMode;Ljava/util/List;Lio/kotest/core/factory/TestFactoryConfiguration;)V public final fun component1 ()Lio/kotest/core/factory/FactoryId; public final fun component2 ()Ljava/util/List; public final fun component3 ()Ljava/util/Set; public final fun component4 ()Lio/kotest/core/test/AssertionMode; public final fun component5 ()Ljava/util/List; - public final fun copy (Lio/kotest/core/factory/FactoryId;Ljava/util/List;Ljava/util/Set;Lio/kotest/core/test/AssertionMode;Ljava/util/List;)Lio/kotest/core/factory/TestFactory; - public static synthetic fun copy$default (Lio/kotest/core/factory/TestFactory;Lio/kotest/core/factory/FactoryId;Ljava/util/List;Ljava/util/Set;Lio/kotest/core/test/AssertionMode;Ljava/util/List;ILjava/lang/Object;)Lio/kotest/core/factory/TestFactory; + public final fun component6 ()Lio/kotest/core/factory/TestFactoryConfiguration; + public final fun copy (Lio/kotest/core/factory/FactoryId;Ljava/util/List;Ljava/util/Set;Lio/kotest/core/test/AssertionMode;Ljava/util/List;Lio/kotest/core/factory/TestFactoryConfiguration;)Lio/kotest/core/factory/TestFactory; + public static synthetic fun copy$default (Lio/kotest/core/factory/TestFactory;Lio/kotest/core/factory/FactoryId;Ljava/util/List;Ljava/util/Set;Lio/kotest/core/test/AssertionMode;Ljava/util/List;Lio/kotest/core/factory/TestFactoryConfiguration;ILjava/lang/Object;)Lio/kotest/core/factory/TestFactory; public fun equals (Ljava/lang/Object;)Z public final fun getAssertionMode ()Lio/kotest/core/test/AssertionMode; + public final fun getConfiguration ()Lio/kotest/core/factory/TestFactoryConfiguration; public final fun getExtensions ()Ljava/util/List; public final fun getFactoryId ()Lio/kotest/core/factory/FactoryId; public final fun getTags ()Ljava/util/Set; diff --git a/kotest-framework/kotest-framework-api/src/commonMain/kotlin/io/kotest/core/TestConfiguration.kt b/kotest-framework/kotest-framework-api/src/commonMain/kotlin/io/kotest/core/TestConfiguration.kt index 14bba5a5d32..acaa4752b74 100644 --- a/kotest-framework/kotest-framework-api/src/commonMain/kotlin/io/kotest/core/TestConfiguration.kt +++ b/kotest-framework/kotest-framework-api/src/commonMain/kotlin/io/kotest/core/TestConfiguration.kt @@ -48,6 +48,8 @@ abstract class TestConfiguration { private var _autoCloseables = emptyList>() + private var _parentConfiguration: TestConfiguration? = null + /** * Config applied to each test case if not overridden per test case. * If null, then defaults to the project level default. @@ -165,6 +167,7 @@ abstract class TestConfiguration { * Registers a lazy [AutoCloseable] to be closed when the spec is completed. */ fun autoClose(closeable: Lazy): Lazy { + _parentConfiguration?.autoClose(closeable) _autoCloseables = listOf(closeable) + _autoCloseables return closeable } @@ -370,4 +373,8 @@ abstract class TestConfiguration { fun registeredExtensions(): List { return _extensions.toList() } + + fun setParentConfiguration(configuration: TestConfiguration) { + _parentConfiguration = configuration + } } diff --git a/kotest-framework/kotest-framework-api/src/commonMain/kotlin/io/kotest/core/factory/TestFactory.kt b/kotest-framework/kotest-framework-api/src/commonMain/kotlin/io/kotest/core/factory/TestFactory.kt index 1e03f27be4b..17fdf1a06eb 100644 --- a/kotest-framework/kotest-framework-api/src/commonMain/kotlin/io/kotest/core/factory/TestFactory.kt +++ b/kotest-framework/kotest-framework-api/src/commonMain/kotlin/io/kotest/core/factory/TestFactory.kt @@ -20,4 +20,5 @@ data class TestFactory( val tags: Set, val assertionMode: AssertionMode?, val extensions: List, + val configuration: TestFactoryConfiguration ) diff --git a/kotest-framework/kotest-framework-api/src/commonMain/kotlin/io/kotest/core/factory/TestFactoryConfiguration.kt b/kotest-framework/kotest-framework-api/src/commonMain/kotlin/io/kotest/core/factory/TestFactoryConfiguration.kt index 11c931435a0..b93cc38e376 100644 --- a/kotest-framework/kotest-framework-api/src/commonMain/kotlin/io/kotest/core/factory/TestFactoryConfiguration.kt +++ b/kotest-framework/kotest-framework-api/src/commonMain/kotlin/io/kotest/core/factory/TestFactoryConfiguration.kt @@ -34,5 +34,7 @@ abstract class TestFactoryConfiguration : TestConfiguration(), RootScope { */ fun include(factory: TestFactory) { factory.tests.forEach { add(it) } + factory.configuration.setParentConfiguration(this) + register(factory.extensions) } } diff --git a/kotest-framework/kotest-framework-api/src/commonMain/kotlin/io/kotest/core/factory/build.kt b/kotest-framework/kotest-framework-api/src/commonMain/kotlin/io/kotest/core/factory/build.kt index 73e0c9ca0c5..8520bf503d5 100644 --- a/kotest-framework/kotest-framework-api/src/commonMain/kotlin/io/kotest/core/factory/build.kt +++ b/kotest-framework/kotest-framework-api/src/commonMain/kotlin/io/kotest/core/factory/build.kt @@ -24,6 +24,7 @@ internal fun TestFactoryConfiguration.build(): TestFactory { } }, assertionMode = assertions, - tests = tests + tests = tests, + configuration = this ) } diff --git a/kotest-framework/kotest-framework-api/src/commonMain/kotlin/io/kotest/core/spec/DslDrivenSpec.kt b/kotest-framework/kotest-framework-api/src/commonMain/kotlin/io/kotest/core/spec/DslDrivenSpec.kt index 2cab0128606..6b880a84b09 100644 --- a/kotest-framework/kotest-framework-api/src/commonMain/kotlin/io/kotest/core/spec/DslDrivenSpec.kt +++ b/kotest-framework/kotest-framework-api/src/commonMain/kotlin/io/kotest/core/spec/DslDrivenSpec.kt @@ -53,6 +53,7 @@ abstract class DslDrivenSpec : Spec(), RootScope { */ fun include(factory: TestFactory) { factory.tests.forEach { add(it.copy(factoryId = factory.factoryId)) } + factory.configuration.setParentConfiguration(this) register(factory.extensions) } diff --git a/kotest-framework/kotest-framework-engine/src/jvmTest/kotlin/com/sksamuel/kotest/engine/factory/AutoCloseableTestFactoryTest.kt b/kotest-framework/kotest-framework-engine/src/jvmTest/kotlin/com/sksamuel/kotest/engine/factory/AutoCloseableTestFactoryTest.kt new file mode 100644 index 00000000000..b433844aafd --- /dev/null +++ b/kotest-framework/kotest-framework-engine/src/jvmTest/kotlin/com/sksamuel/kotest/engine/factory/AutoCloseableTestFactoryTest.kt @@ -0,0 +1,57 @@ +package com.sksamuel.kotest.engine.factory + +import io.kotest.core.spec.style.ShouldSpec +import io.kotest.core.spec.style.shouldSpec +import io.kotest.matchers.shouldBe +import java.util.concurrent.atomic.AtomicInteger + +class AutoCloseableTestFactoryTest : ShouldSpec({ + include( + shouldSpec { + include( + shouldSpec { + should("close is called in nested test factory") { + autoClose(FirstAutoClose) + } + } + ) + should("close is called in test factory") { + autoClose(SecondAutoClose) + } + } + ) + should("close is called") { + autoClose(ThirdAutoClose) + } + afterSpec { + FirstAutoClose.closed shouldBe 3 + SecondAutoClose.closed shouldBe 2 + ThirdAutoClose.closed shouldBe 1 + } +}) + +private object FirstAutoClose : AutoCloseable { + var closed = -1 + + override fun close() { + closed = closedNumber.incrementAndGet() + } +} + +private object SecondAutoClose : AutoCloseable { + var closed = -1 + + override fun close() { + closed = closedNumber.incrementAndGet() + } +} + +private object ThirdAutoClose : AutoCloseable { + var closed = -1 + + override fun close() { + closed = closedNumber.incrementAndGet() + } +} + +private var closedNumber = AtomicInteger(0)