diff --git a/documentation/src/docs/latest/changes.adoc b/documentation/src/docs/latest/changes.adoc new file mode 100644 index 000000000..5d1358076 --- /dev/null +++ b/documentation/src/docs/latest/changes.adoc @@ -0,0 +1,11 @@ +== Changelog + +Releases:: + 1.1.0::: + * Renamed `Dsl` to `SpecBody`. + * Added support for extensions. + * Reworked subjects as an extension. + * Support specs defined as objects. + + 1.0.0::: + * Initial release of Spek. diff --git a/documentation/src/docs/latest/index.adoc b/documentation/src/docs/latest/index.adoc index e4a0b0ac1..5d33e678b 100644 --- a/documentation/src/docs/latest/index.adoc +++ b/documentation/src/docs/latest/index.adoc @@ -12,6 +12,8 @@ include::writing-specifications.adoc[] include::faq.adoc[] +include::changes.adoc[] + include::contributors.adoc[] include::other.adoc[] diff --git a/junit-platform-engine-test-support/src/main/kotlin/org/jetbrains/spek/engine/test/ExecutionEventRecorder.kt b/junit-platform-engine-test-support/src/main/kotlin/org/jetbrains/spek/engine/test/ExecutionEventRecorder.kt index 404d32718..d21aa46c6 100644 --- a/junit-platform-engine-test-support/src/main/kotlin/org/jetbrains/spek/engine/test/ExecutionEventRecorder.kt +++ b/junit-platform-engine-test-support/src/main/kotlin/org/jetbrains/spek/engine/test/ExecutionEventRecorder.kt @@ -5,7 +5,7 @@ import org.junit.platform.engine.EngineExecutionListener import org.junit.platform.engine.TestDescriptor import org.junit.platform.engine.TestExecutionResult import org.junit.platform.engine.reporting.ReportEntry -import java.util.* +import java.util.LinkedList /** * @author Ranie Jade Ramiso diff --git a/settings.gradle b/settings.gradle index d4295d989..402abe483 100644 --- a/settings.gradle +++ b/settings.gradle @@ -1,6 +1,7 @@ rootProject.name = 'spek' include 'spek-api' +include 'spek-subject-extension' include 'junit-platform-engine-test-support' include 'spek-junit-platform-engine' include 'spek-dist' diff --git a/spek-api/src/main/kotlin/org/jetbrains/spek/api/CreateWith.kt b/spek-api/src/main/kotlin/org/jetbrains/spek/api/CreateWith.kt new file mode 100644 index 000000000..681df605c --- /dev/null +++ b/spek-api/src/main/kotlin/org/jetbrains/spek/api/CreateWith.kt @@ -0,0 +1,14 @@ +package org.jetbrains.spek.api + +import org.jetbrains.spek.api.lifecycle.InstanceFactory +import java.lang.annotation.Inherited +import kotlin.reflect.KClass + +/** + * @author Ranie Jade Ramiso + * @since 1.1 + */ +@Target(AnnotationTarget.CLASS) +@Retention(AnnotationRetention.RUNTIME) +@Inherited +annotation class CreateWith(val factory: KClass) diff --git a/spek-api/src/main/kotlin/org/jetbrains/spek/api/SubjectSpek.kt b/spek-api/src/main/kotlin/org/jetbrains/spek/api/Shared.kt similarity index 53% rename from spek-api/src/main/kotlin/org/jetbrains/spek/api/SubjectSpek.kt rename to spek-api/src/main/kotlin/org/jetbrains/spek/api/Shared.kt index a08b754e5..25c31fe64 100644 --- a/spek-api/src/main/kotlin/org/jetbrains/spek/api/SubjectSpek.kt +++ b/spek-api/src/main/kotlin/org/jetbrains/spek/api/Shared.kt @@ -1,10 +1,13 @@ package org.jetbrains.spek.api -import org.jetbrains.spek.api.dsl.SubjectDsl +import org.jetbrains.spek.api.dsl.Spec import org.jetbrains.spek.meta.Experimental /** * @author Ranie Jade Ramiso + * @since 1.1 */ @Experimental -abstract class SubjectSpek(val spec: SubjectDsl.() -> Unit) +fun Spec.include(spec: Spek) { + spec.spec(this) +} diff --git a/spek-api/src/main/kotlin/org/jetbrains/spek/api/Spek.kt b/spek-api/src/main/kotlin/org/jetbrains/spek/api/Spek.kt index 43673c114..7e0f573ae 100644 --- a/spek-api/src/main/kotlin/org/jetbrains/spek/api/Spek.kt +++ b/spek-api/src/main/kotlin/org/jetbrains/spek/api/Spek.kt @@ -1,9 +1,13 @@ package org.jetbrains.spek.api -import org.jetbrains.spek.api.dsl.Dsl +import org.jetbrains.spek.api.dsl.Spec /** * @author Ranie Jade Ramiso * @since 1.0 */ -abstract class Spek(val spec: Dsl.() -> Unit) +abstract class Spek(val spec: Spec.() -> Unit) { + companion object { + fun wrap(spec: Spec.() -> Unit) = object: Spek(spec) {} + } +} diff --git a/spek-api/src/main/kotlin/org/jetbrains/spek/api/dsl/ActionBody.kt b/spek-api/src/main/kotlin/org/jetbrains/spek/api/dsl/ActionBody.kt new file mode 100644 index 000000000..c2e811421 --- /dev/null +++ b/spek-api/src/main/kotlin/org/jetbrains/spek/api/dsl/ActionBody.kt @@ -0,0 +1,9 @@ +package org.jetbrains.spek.api.dsl + +import org.jetbrains.spek.meta.SpekDsl + +/** + * @author Ranie Jade Ramiso + */ +@SpekDsl +interface ActionBody: TestContainer diff --git a/spek-api/src/main/kotlin/org/jetbrains/spek/api/dsl/Dsl.kt b/spek-api/src/main/kotlin/org/jetbrains/spek/api/dsl/Dsl.kt deleted file mode 100644 index c1974e5d9..000000000 --- a/spek-api/src/main/kotlin/org/jetbrains/spek/api/dsl/Dsl.kt +++ /dev/null @@ -1,14 +0,0 @@ -package org.jetbrains.spek.api.dsl - -/** - * @author Ranie Jade Ramiso - * @since 1.0 - */ -interface Dsl { - fun group(description: String, pending: Pending = Pending.No, lazy: Boolean = false, body: Dsl.() -> Unit) - fun test(description: String, pending: Pending = Pending.No, body: () -> Unit) - - fun beforeEachTest(callback: () -> Unit) - fun afterEachTest(callback: () -> Unit) - // fun includeSpec(spec: KClass) -} diff --git a/spek-api/src/main/kotlin/org/jetbrains/spek/api/dsl/Pending.kt b/spek-api/src/main/kotlin/org/jetbrains/spek/api/dsl/Pending.kt index f04abec9c..8ef16a869 100644 --- a/spek-api/src/main/kotlin/org/jetbrains/spek/api/dsl/Pending.kt +++ b/spek-api/src/main/kotlin/org/jetbrains/spek/api/dsl/Pending.kt @@ -2,8 +2,9 @@ package org.jetbrains.spek.api.dsl /** * @author Ranie Jade Ramiso + * @since 1.0 */ -sealed class Pending private constructor(val pending: Boolean) { +sealed class Pending constructor(val pending: Boolean) { class Yes(val reason: String? = null): Pending(true) object No: Pending(false) } diff --git a/spek-api/src/main/kotlin/org/jetbrains/spek/api/dsl/Spec.kt b/spek-api/src/main/kotlin/org/jetbrains/spek/api/dsl/Spec.kt new file mode 100644 index 000000000..9f4b8446b --- /dev/null +++ b/spek-api/src/main/kotlin/org/jetbrains/spek/api/dsl/Spec.kt @@ -0,0 +1,13 @@ +package org.jetbrains.spek.api.dsl + +import org.jetbrains.spek.api.lifecycle.LifecycleListener +import org.jetbrains.spek.meta.Experimental + +/** + * @author Ranie Jade Ramiso + * @since 1.1 + */ +@Experimental +interface Spec: SpecBody { + fun registerListener(listener: LifecycleListener) +} diff --git a/spek-api/src/main/kotlin/org/jetbrains/spek/api/dsl/SpecBody.kt b/spek-api/src/main/kotlin/org/jetbrains/spek/api/dsl/SpecBody.kt new file mode 100644 index 000000000..a10eb70e4 --- /dev/null +++ b/spek-api/src/main/kotlin/org/jetbrains/spek/api/dsl/SpecBody.kt @@ -0,0 +1,19 @@ +package org.jetbrains.spek.api.dsl + +import org.jetbrains.spek.api.lifecycle.CachingMode +import org.jetbrains.spek.api.lifecycle.LifecycleAware +import org.jetbrains.spek.meta.SpekDsl + +/** + * @author Ranie Jade Ramiso + * @since 1.0 + */ +@SpekDsl +interface SpecBody: TestContainer { + fun group(description: String, pending: Pending = Pending.No, body: SpecBody.() -> Unit) + fun action(description: String, pending: Pending = Pending.No, body: ActionBody.() -> Unit) + fun memoized(mode: CachingMode = CachingMode.TEST, factory: () -> T): LifecycleAware + + fun beforeEachTest(callback: () -> Unit) + fun afterEachTest(callback: () -> Unit) +} diff --git a/spek-api/src/main/kotlin/org/jetbrains/spek/api/dsl/Standard.kt b/spek-api/src/main/kotlin/org/jetbrains/spek/api/dsl/Standard.kt index dd2ed6fbf..f57106ae3 100644 --- a/spek-api/src/main/kotlin/org/jetbrains/spek/api/dsl/Standard.kt +++ b/spek-api/src/main/kotlin/org/jetbrains/spek/api/dsl/Standard.kt @@ -1,114 +1,101 @@ package org.jetbrains.spek.api.dsl -import org.jetbrains.spek.api.SubjectSpek -import kotlin.reflect.KClass - /** - * Creates a [group][Dsl.group]. + * Creates a [group][SpecBody.group]. * * @author Ranie Jade Ramiso * @since 1.0 */ -fun Dsl.describe(description: String, body: Dsl.() -> Unit) { +fun SpecBody.describe(description: String, body: SpecBody.() -> Unit) { group("describe $description", body = body) } /** - * Creates a [group][Dsl.group]. + * Creates a [group][SpecBody.group]. * * @author Ranie Jade Ramiso * @since 1.0 */ -fun Dsl.context(description: String, body: Dsl.() -> Unit) { +fun SpecBody.context(description: String, body: SpecBody.() -> Unit) { group("context $description", body = body) } /** - * Creates a [group][Dsl.group]. + * Creates a [group][SpecBody.group]. * * @author Ranie Jade Ramiso * @since 1.0 */ -fun Dsl.given(description: String, body: Dsl.() -> Unit) { +fun SpecBody.given(description: String, body: SpecBody.() -> Unit) { group("given $description", body = body) } /** - * Creates a [group][Dsl.group]. + * Creates a [group][SpecBody.group]. * * @author Ranie Jade Ramiso * @since 1.0 */ -fun Dsl.on(description: String, body: Dsl.() -> Unit) { - group("on $description", lazy = true, body = body) +fun SpecBody.on(description: String, body: ActionBody.() -> Unit) { + action("on $description", body = body) } /** - * Creates a [test][Dsl.test]. + * Creates a [test][SpecBody.test]. * * @author Ranie Jade Ramiso * @since 1.0 */ -fun Dsl.it(description: String, body: () -> Unit) { +fun TestContainer.it(description: String, body: TestBody.() -> Unit) { test("it $description", body = body) } /** - * Creates a [group][Dsl.group]. + * Creates a [group][SpecBody.group]. * * @author Ranie Jade Ramiso * @since 1.0 */ -fun Dsl.xdescribe(description: String, reason: String? = null, body: Dsl.() -> Unit) { +fun SpecBody.xdescribe(description: String, reason: String? = null, body: SpecBody.() -> Unit) { group("describe $description", Pending.Yes(reason), body = body) } /** - * Creates a [group][Dsl.group]. + * Creates a [group][SpecBody.group]. * * @author Ranie Jade Ramiso * @since 1.0 */ -fun Dsl.xcontext(description: String, reason: String? = null, body: Dsl.() -> Unit) { +fun SpecBody.xcontext(description: String, reason: String? = null, body: SpecBody.() -> Unit) { group("context $description", Pending.Yes(reason), body = body) } /** - * Creates a [group][Dsl.group]. + * Creates a [group][SpecBody.group]. * * @author Ranie Jade Ramiso * @since 1.0 */ -fun Dsl.xgiven(description: String, reason: String? = null, body: Dsl.() -> Unit) { +fun SpecBody.xgiven(description: String, reason: String? = null, body: SpecBody.() -> Unit) { group("given $description", Pending.Yes(reason), body = body) } /** - * Creates a pending [group][Dsl.group]. + * Creates a pending [group][SpecBody.group]. * * @author Ranie Jade Ramiso * @since 1.0 */ -fun Dsl.xon(description: String, reason: String? = null, body: Dsl.() -> Unit = {}) { - group("on $description", Pending.Yes(reason), lazy = true, body = body) +fun SpecBody.xon(description: String, reason: String? = null, body: ActionBody.() -> Unit = {}) { + action("on $description", Pending.Yes(reason), body = body) } /** - * Creates a pending [test][Dsl.test]. + * Creates a pending [test][SpecBody.test]. * * @author Ranie Jade Ramiso * @since 1.0 */ -fun Dsl.xit(description: String, reason: String? = null, body: () -> Unit = {}) { +fun TestContainer.xit(description: String, reason: String? = null, body: TestBody.() -> Unit = {}) { test("it $description", Pending.Yes(reason), body) } - -/** - * Alias for [SubjectDsl.includeSubjectSpec]. - * - * @author Ranie Jade Ramiso - * @since 1.0 - */ -fun > SubjectDsl<*>.itBehavesLike(spec: KClass) { - includeSubjectSpec(spec) -} diff --git a/spek-api/src/main/kotlin/org/jetbrains/spek/api/dsl/SubjectDsl.kt b/spek-api/src/main/kotlin/org/jetbrains/spek/api/dsl/SubjectDsl.kt deleted file mode 100644 index f9a9def09..000000000 --- a/spek-api/src/main/kotlin/org/jetbrains/spek/api/dsl/SubjectDsl.kt +++ /dev/null @@ -1,19 +0,0 @@ -package org.jetbrains.spek.api.dsl - -import org.jetbrains.spek.api.SubjectSpek -import org.jetbrains.spek.api.memoized.CachingMode -import org.jetbrains.spek.api.memoized.Subject -import org.jetbrains.spek.meta.Experimental -import kotlin.reflect.KClass - -/** - * @author Ranie Jade Ramiso - * @since 1.0 - */ -@Experimental -interface SubjectDsl: Dsl { - fun subject(mode: CachingMode = CachingMode.TEST, factory: () -> T): Subject - val subject: T - - fun > includeSubjectSpec(spec: KClass) -} diff --git a/spek-api/src/main/kotlin/org/jetbrains/spek/api/dsl/TestBody.kt b/spek-api/src/main/kotlin/org/jetbrains/spek/api/dsl/TestBody.kt new file mode 100644 index 000000000..e48be57c8 --- /dev/null +++ b/spek-api/src/main/kotlin/org/jetbrains/spek/api/dsl/TestBody.kt @@ -0,0 +1,9 @@ +package org.jetbrains.spek.api.dsl + +import org.jetbrains.spek.meta.SpekDsl + +/** + * @author Ranie Jade Ramiso + */ +@SpekDsl +interface TestBody diff --git a/spek-api/src/main/kotlin/org/jetbrains/spek/api/dsl/TestContainer.kt b/spek-api/src/main/kotlin/org/jetbrains/spek/api/dsl/TestContainer.kt new file mode 100644 index 000000000..010910d54 --- /dev/null +++ b/spek-api/src/main/kotlin/org/jetbrains/spek/api/dsl/TestContainer.kt @@ -0,0 +1,11 @@ +package org.jetbrains.spek.api.dsl + +import org.jetbrains.spek.meta.SpekDsl + +/** + * @author Ranie Jade Ramiso + */ +@SpekDsl +interface TestContainer { + fun test(description: String, pending: Pending = Pending.No, body: TestBody.() -> Unit) +} diff --git a/spek-api/src/main/kotlin/org/jetbrains/spek/api/lifecycle/ActionScope.kt b/spek-api/src/main/kotlin/org/jetbrains/spek/api/lifecycle/ActionScope.kt new file mode 100644 index 000000000..50a368cde --- /dev/null +++ b/spek-api/src/main/kotlin/org/jetbrains/spek/api/lifecycle/ActionScope.kt @@ -0,0 +1,6 @@ +package org.jetbrains.spek.api.lifecycle + +/** + * @author Ranie Jade Ramiso + */ +interface ActionScope: GroupScope diff --git a/spek-api/src/main/kotlin/org/jetbrains/spek/api/memoized/CachingMode.kt b/spek-api/src/main/kotlin/org/jetbrains/spek/api/lifecycle/CachingMode.kt similarity index 56% rename from spek-api/src/main/kotlin/org/jetbrains/spek/api/memoized/CachingMode.kt rename to spek-api/src/main/kotlin/org/jetbrains/spek/api/lifecycle/CachingMode.kt index 315718633..f24ae65af 100644 --- a/spek-api/src/main/kotlin/org/jetbrains/spek/api/memoized/CachingMode.kt +++ b/spek-api/src/main/kotlin/org/jetbrains/spek/api/lifecycle/CachingMode.kt @@ -1,17 +1,16 @@ -package org.jetbrains.spek.api.memoized +package org.jetbrains.spek.api.lifecycle import org.jetbrains.spek.meta.Experimental /** - * Specifies how [subjects][Subject] are cached. + * Specifies how [lifecycle aware objects][LifecycleAware] are cached. * * @author Ranie Jade Ramiso - * @since 1.0 */ @Experimental enum class CachingMode { /** - * Subjects will be shared throughout the group which it was declared. + * Instance will be shared within the group it was declared. */ GROUP, /** diff --git a/spek-junit-platform-engine/src/main/kotlin/org/jetbrains/spek/extension/ExtensionContext.kt b/spek-api/src/main/kotlin/org/jetbrains/spek/api/lifecycle/GroupScope.kt similarity index 53% rename from spek-junit-platform-engine/src/main/kotlin/org/jetbrains/spek/extension/ExtensionContext.kt rename to spek-api/src/main/kotlin/org/jetbrains/spek/api/lifecycle/GroupScope.kt index 8b2bc19d1..5387db9f8 100644 --- a/spek-junit-platform-engine/src/main/kotlin/org/jetbrains/spek/extension/ExtensionContext.kt +++ b/spek-api/src/main/kotlin/org/jetbrains/spek/api/lifecycle/GroupScope.kt @@ -1,10 +1,10 @@ -package org.jetbrains.spek.extension +package org.jetbrains.spek.api.lifecycle import org.jetbrains.spek.meta.Experimental /** * @author Ranie Jade Ramiso + * @since 1.1 */ @Experimental -interface ExtensionContext { -} +interface GroupScope: Scope diff --git a/spek-api/src/main/kotlin/org/jetbrains/spek/api/lifecycle/InstanceFactory.kt b/spek-api/src/main/kotlin/org/jetbrains/spek/api/lifecycle/InstanceFactory.kt new file mode 100644 index 000000000..a1e94d588 --- /dev/null +++ b/spek-api/src/main/kotlin/org/jetbrains/spek/api/lifecycle/InstanceFactory.kt @@ -0,0 +1,14 @@ +package org.jetbrains.spek.api.lifecycle + +import org.jetbrains.spek.api.Spek +import org.jetbrains.spek.meta.Experimental +import kotlin.reflect.KClass + +/** + * @author Ranie Jade Ramiso + * @since 1.1 + */ +@Experimental +interface InstanceFactory { + fun create(spek: KClass): T +} diff --git a/spek-api/src/main/kotlin/org/jetbrains/spek/api/lifecycle/LifecycleAware.kt b/spek-api/src/main/kotlin/org/jetbrains/spek/api/lifecycle/LifecycleAware.kt new file mode 100644 index 000000000..f0bda1f48 --- /dev/null +++ b/spek-api/src/main/kotlin/org/jetbrains/spek/api/lifecycle/LifecycleAware.kt @@ -0,0 +1,13 @@ +package org.jetbrains.spek.api.lifecycle + +import org.jetbrains.spek.meta.Experimental +import kotlin.properties.ReadOnlyProperty + +/** + * @author Ranie Jade Ramiso + * @since 1.1 + */ +@Experimental +interface LifecycleAware: ReadOnlyProperty, T> { + operator fun invoke(): T +} diff --git a/spek-api/src/main/kotlin/org/jetbrains/spek/api/lifecycle/LifecycleListener.kt b/spek-api/src/main/kotlin/org/jetbrains/spek/api/lifecycle/LifecycleListener.kt new file mode 100644 index 000000000..ec2516c33 --- /dev/null +++ b/spek-api/src/main/kotlin/org/jetbrains/spek/api/lifecycle/LifecycleListener.kt @@ -0,0 +1,17 @@ +package org.jetbrains.spek.api.lifecycle + +import org.jetbrains.spek.meta.Experimental + +/** + * @author Ranie Jade Ramiso + * @since 1.1 + */ +@Experimental +interface LifecycleListener { + fun beforeExecuteTest(test: TestScope) { } + fun afterExecuteTest(test: TestScope) { } + fun beforeExecuteGroup(group: GroupScope) { } + fun afterExecuteGroup(group: GroupScope) { } + fun beforeExecuteAction(action: ActionScope) { } + fun afterExecuteAction(action: ActionScope) { } +} diff --git a/spek-api/src/main/kotlin/org/jetbrains/spek/api/lifecycle/Scope.kt b/spek-api/src/main/kotlin/org/jetbrains/spek/api/lifecycle/Scope.kt new file mode 100644 index 000000000..e2228bcdf --- /dev/null +++ b/spek-api/src/main/kotlin/org/jetbrains/spek/api/lifecycle/Scope.kt @@ -0,0 +1,12 @@ +package org.jetbrains.spek.api.lifecycle + +import org.jetbrains.spek.meta.Experimental + +/** + * @author Ranie Jade Ramiso + * @since 1.1 + */ +@Experimental +interface Scope { + val parent: GroupScope? +} diff --git a/spek-api/src/main/kotlin/org/jetbrains/spek/api/lifecycle/TestScope.kt b/spek-api/src/main/kotlin/org/jetbrains/spek/api/lifecycle/TestScope.kt new file mode 100644 index 000000000..f2607da29 --- /dev/null +++ b/spek-api/src/main/kotlin/org/jetbrains/spek/api/lifecycle/TestScope.kt @@ -0,0 +1,12 @@ +package org.jetbrains.spek.api.lifecycle + +import org.jetbrains.spek.meta.Experimental + +/** + * @author Ranie Jade Ramiso + * @since 1.1 + */ +@Experimental +interface TestScope: Scope { + override val parent: GroupScope +} diff --git a/spek-api/src/main/kotlin/org/jetbrains/spek/api/memoized/MemoizedValue.kt b/spek-api/src/main/kotlin/org/jetbrains/spek/api/memoized/MemoizedValue.kt deleted file mode 100644 index 5d1fcdd13..000000000 --- a/spek-api/src/main/kotlin/org/jetbrains/spek/api/memoized/MemoizedValue.kt +++ /dev/null @@ -1,12 +0,0 @@ -package org.jetbrains.spek.api.memoized - -import org.jetbrains.spek.meta.Experimental -import kotlin.reflect.KProperty - -/** - * @author Ranie Jade Ramiso - */ -@Experimental -interface MemoizedValue { - operator fun getValue(ref: Any?, property: KProperty<*>): T -} diff --git a/spek-api/src/main/kotlin/org/jetbrains/spek/api/memoized/Subject.kt b/spek-api/src/main/kotlin/org/jetbrains/spek/api/memoized/Subject.kt deleted file mode 100644 index 856883437..000000000 --- a/spek-api/src/main/kotlin/org/jetbrains/spek/api/memoized/Subject.kt +++ /dev/null @@ -1,11 +0,0 @@ -package org.jetbrains.spek.api.memoized - -import org.jetbrains.spek.meta.Experimental - -/** - * @author Ranie Jade Ramiso - * @since 1.0 - */ -@Experimental -interface Subject: MemoizedValue { -} diff --git a/spek-api/src/main/kotlin/org/jetbrains/spek/meta/Experimental.kt b/spek-api/src/main/kotlin/org/jetbrains/spek/meta/Experimental.kt index eac661cb0..8cc407165 100644 --- a/spek-api/src/main/kotlin/org/jetbrains/spek/meta/Experimental.kt +++ b/spek-api/src/main/kotlin/org/jetbrains/spek/meta/Experimental.kt @@ -8,5 +8,8 @@ package org.jetbrains.spek.meta * @since 1.0 */ @Retention(AnnotationRetention.SOURCE) -@Target(AnnotationTarget.CLASS, AnnotationTarget.FUNCTION, AnnotationTarget.PROPERTY) +@Target( + AnnotationTarget.ANNOTATION_CLASS, AnnotationTarget.CLASS, + AnnotationTarget.FUNCTION, AnnotationTarget.PROPERTY +) annotation class Experimental diff --git a/spek-api/src/main/kotlin/org/jetbrains/spek/meta/SpekDsl.kt b/spek-api/src/main/kotlin/org/jetbrains/spek/meta/SpekDsl.kt new file mode 100644 index 000000000..5cffe95cb --- /dev/null +++ b/spek-api/src/main/kotlin/org/jetbrains/spek/meta/SpekDsl.kt @@ -0,0 +1,13 @@ +package org.jetbrains.spek.meta + +import java.lang.annotation.Inherited + +/** + * @author Ranie Jade Ramiso + * @since 1.1 + */ +@Target(AnnotationTarget.CLASS) +@Retention(AnnotationRetention.RUNTIME) +@Inherited +@Experimental +annotation class SpekDsl diff --git a/spek-junit-platform-engine/build.gradle b/spek-junit-platform-engine/build.gradle index 0ab3163a1..738119349 100644 --- a/spek-junit-platform-engine/build.gradle +++ b/spek-junit-platform-engine/build.gradle @@ -14,12 +14,13 @@ junitPlatform { dependencies { compile project(':spek-api') + compile project(':spek-subject-extension') + compile 'org.jetbrains.kotlin:kotlin-stdlib' compile 'org.jetbrains.kotlin:kotlin-reflect' - compileOnly 'org.junit.platform:junit-platform-engine' + compile 'org.junit.platform:junit-platform-engine' testCompile 'org.junit.jupiter:junit-jupiter-api' - testCompile 'org.junit.platform:junit-platform-runner' testCompile project(':junit-platform-engine-test-support') testRuntime 'org.junit.jupiter:junit-jupiter-engine' } diff --git a/spek-junit-platform-engine/src/main/kotlin/org/jetbrains/spek/engine/FixturesAdapter.kt b/spek-junit-platform-engine/src/main/kotlin/org/jetbrains/spek/engine/FixturesAdapter.kt index 6c50e226e..6dbf054cf 100644 --- a/spek-junit-platform-engine/src/main/kotlin/org/jetbrains/spek/engine/FixturesAdapter.kt +++ b/spek-junit-platform-engine/src/main/kotlin/org/jetbrains/spek/engine/FixturesAdapter.kt @@ -1,51 +1,58 @@ package org.jetbrains.spek.engine -import org.jetbrains.spek.extension.Extension -import org.jetbrains.spek.extension.GroupExtensionContext -import org.jetbrains.spek.extension.TestExtensionContext -import java.util.* +import org.jetbrains.spek.api.lifecycle.ActionScope +import org.jetbrains.spek.api.lifecycle.GroupScope +import org.jetbrains.spek.api.lifecycle.LifecycleListener +import org.jetbrains.spek.api.lifecycle.TestScope +import java.util.LinkedList +import java.util.WeakHashMap /** - * Adapter for fixtures as a pseudo-extension. * * @author Ranie Jade Ramiso */ -class FixturesAdapter: Extension { - private val beforeEach: MutableMap Unit>> = WeakHashMap() - private val afterEach: MutableMap Unit>> = WeakHashMap() +class FixturesAdapter: LifecycleListener { + private val beforeEach: MutableMap Unit>> = WeakHashMap() - fun beforeExecuteTest(test: TestExtensionContext) { - invokeAllBeforeEach(test.parent) + private val afterEach: MutableMap Unit>> = WeakHashMap() + + override fun beforeExecuteTest(test: TestScope) { + if (test.parent !is ActionScope) { + invokeAllBeforeEach(test.parent) + } } - fun afterExecuteTest(test: TestExtensionContext) { - invokeAllAfterEach(test.parent) + override fun afterExecuteTest(test: TestScope) { + if (test.parent !is ActionScope) { + invokeAllAfterEach(test.parent) + } } - fun beforeExecuteGroup(test: GroupExtensionContext) { - invokeAllBeforeEach(test) + override fun beforeExecuteAction(action: ActionScope) { + invokeAllBeforeEach(action) } - fun afterExecuteGroup(test: GroupExtensionContext) { - invokeAllAfterEach(test) + override fun afterExecuteAction(action: ActionScope) { + invokeAllAfterEach(action) } - fun registerBeforeEach(group: GroupExtensionContext, callback: () -> Unit) { + + fun registerBeforeEach(group: GroupScope, callback: () -> Unit) { beforeEach.getOrPut(group, { LinkedList() }).add(callback) } - fun registerAfterEach(group: GroupExtensionContext, callback: () -> Unit) { + fun registerAfterEach(group: GroupScope, callback: () -> Unit) { afterEach.getOrPut(group, { LinkedList() }).add(callback) } - private fun invokeAllBeforeEach(group: GroupExtensionContext) { + private fun invokeAllBeforeEach(group: GroupScope) { if (group.parent != null) { invokeAllBeforeEach(group.parent!!) } beforeEach[group]?.forEach { it.invoke() } } - private fun invokeAllAfterEach(group: GroupExtensionContext) { + private fun invokeAllAfterEach(group: GroupScope) { afterEach[group]?.forEach { it.invoke() } if (group.parent != null) { invokeAllAfterEach(group.parent!!) diff --git a/spek-junit-platform-engine/src/main/kotlin/org/jetbrains/spek/engine/Scope.kt b/spek-junit-platform-engine/src/main/kotlin/org/jetbrains/spek/engine/Scope.kt index 78976c59b..3820ea13a 100644 --- a/spek-junit-platform-engine/src/main/kotlin/org/jetbrains/spek/engine/Scope.kt +++ b/spek-junit-platform-engine/src/main/kotlin/org/jetbrains/spek/engine/Scope.kt @@ -1,11 +1,11 @@ package org.jetbrains.spek.engine import org.jetbrains.spek.api.dsl.Pending -import org.jetbrains.spek.engine.extension.ExtensionRegistryImpl -import org.jetbrains.spek.extension.ExtensionContext -import org.jetbrains.spek.extension.GroupExtensionContext -import org.jetbrains.spek.extension.TestExtensionContext -import org.jetbrains.spek.extension.execution.* +import org.jetbrains.spek.api.dsl.TestBody +import org.jetbrains.spek.api.lifecycle.ActionScope +import org.jetbrains.spek.api.lifecycle.GroupScope +import org.jetbrains.spek.api.lifecycle.TestScope +import org.jetbrains.spek.engine.lifecycle.LifecycleManager import org.junit.platform.engine.TestSource import org.junit.platform.engine.UniqueId import org.junit.platform.engine.support.descriptor.AbstractTestDescriptor @@ -14,8 +14,10 @@ import org.junit.platform.engine.support.hierarchical.Node /** * @author Ranie Jade Ramiso */ -sealed class Scope(uniqueId: UniqueId, val pending: Pending, val source: TestSource?) - : AbstractTestDescriptor(uniqueId, uniqueId.segments.last().value), Node, ExtensionContext { +sealed class Scope(uniqueId: UniqueId, val pending: Pending, val source: TestSource?, + val lifecycleManager: LifecycleManager) + : AbstractTestDescriptor(uniqueId, uniqueId.segments.last().value), Node, + org.jetbrains.spek.api.lifecycle.Scope { init { if (source != null) { @@ -23,150 +25,90 @@ sealed class Scope(uniqueId: UniqueId, val pending: Pending, val source: TestSou } } - open class Group(uniqueId: UniqueId, pending: Pending, - source: TestSource?, - override val lazy: Boolean, - val body: Group.(SpekExecutionContext) -> Unit) - : Scope(uniqueId, pending, source), GroupExtensionContext { - override val parent: GroupExtensionContext? by lazy { - return@lazy if (getParent().isPresent) { - getParent().get() as GroupExtensionContext - } else { - null - } + override val parent: GroupScope? by lazy { + return@lazy if (getParent().isPresent) { + getParent().get() as GroupScope + } else { + null } + } + class Action(uniqueId: UniqueId, pending: Pending, + source: TestSource?, + lifecycleManager: LifecycleManager, + private val body: Action.(SpekExecutionContext) -> Unit) + : Scope(uniqueId, pending, source, lifecycleManager), ActionScope { override fun isTest() = false override fun isContainer() = true - - override fun hasTests(): Boolean { - return if (lazy) { - true - } else { - super.hasTests() - } - } + override fun hasTests() = true override fun before(context: SpekExecutionContext): SpekExecutionContext { - return super.before(context).apply { - context.registry.extensions() - .filterIsInstance(BeforeExecuteGroup::class.java) - .forEach { it.beforeExecuteGroup(this@Group) } - } + lifecycleManager.beforeExecuteAction(this) + return context } override fun execute(context: SpekExecutionContext): SpekExecutionContext { val collector = ThrowableCollector() - if (lazy) { - context.registry.extensions() - .filterIsInstance(FixturesAdapter::class.java) - .forEach { - collector.executeSafely { it.beforeExecuteGroup(this) } - } - } - if (collector.isEmpty()) { collector.executeSafely { body.invoke(this, context) } } - if (lazy) { - context.registry.extensions() - .filterIsInstance(FixturesAdapter::class.java) - .forEach { - collector.executeSafely { it.afterExecuteGroup(this) } - } - } - collector.assertEmpty() return context } override fun after(context: SpekExecutionContext) { - context.registry.extensions() - .filterIsInstance(AfterExecuteGroup::class.java) - .forEach { it.afterExecuteGroup(this@Group) } - - super.after(context) + lifecycleManager.afterExecuteAction(this) } } - class Spec(uniqueId: UniqueId, source: TestSource?, val registry: ExtensionRegistryImpl, val nested: Boolean) - : Group(uniqueId, Pending.No, source, false, {}) { - override fun prepare(context: SpekExecutionContext): SpekExecutionContext { - return SpekExecutionContext(registry, context.executionRequest) - } + open class Group(uniqueId: UniqueId, pending: Pending, + source: TestSource?, + lifecycleManager: LifecycleManager) + : Scope(uniqueId, pending, source, lifecycleManager), GroupScope { + + override fun isTest() = false + override fun isContainer() = true override fun before(context: SpekExecutionContext): SpekExecutionContext { - if (!nested) { - context.registry.extensions() - .filterIsInstance(BeforeExecuteSpec::class.java) - .forEach { it.beforeExecuteSpec(this@Spec) } - } else { - return super.before(context) - } + lifecycleManager.beforeExecuteGroup(this@Group) return context } override fun after(context: SpekExecutionContext) { - if (!nested) { - context.registry.extensions() - .filterIsInstance(AfterExecuteSpec::class.java) - .forEach { it.afterExecuteSpec(this@Spec) } - } else { - super.after(context) - } + lifecycleManager.afterExecuteGroup(this@Group) } } - class Test(uniqueId: UniqueId, pending: Pending, source: TestSource?, val body: () -> Unit) - : Scope(uniqueId, pending, source), TestExtensionContext { - override val parent: GroupExtensionContext by lazy { - getParent().get() as GroupExtensionContext + class Test(uniqueId: UniqueId, pending: Pending, source: TestSource?, lifecycleManager: LifecycleManager, val body: TestBody.() -> Unit) + : Scope(uniqueId, pending, source, lifecycleManager), TestScope { + override val parent: GroupScope by lazy { + getParent().get() as GroupScope } override fun isTest() = true override fun isContainer() = false override fun isLeaf() = true - override fun execute(context: SpekExecutionContext): SpekExecutionContext { - val collector = ThrowableCollector() + override fun before(context: SpekExecutionContext): SpekExecutionContext { + lifecycleManager.beforeExecuteTest(this) + return context + } - context.registry.extensions() - .filterIsInstance(BeforeExecuteTest::class.java) - .forEach { - collector.executeSafely { it.beforeExecuteTest(this@Test) } - } + override fun after(context: SpekExecutionContext) { + lifecycleManager.afterExecuteTest(this) + } + override fun execute(context: SpekExecutionContext): SpekExecutionContext { + val collector = ThrowableCollector() if (collector.isEmpty()) { - if (!parent.lazy) { - context.registry.extensions() - .filterIsInstance(FixturesAdapter::class.java) - .forEach { - collector.executeSafely { it.beforeExecuteTest(this@Test) } - } - } if (collector.isEmpty()) { - collector.executeSafely { body.invoke() } + collector.executeSafely { body.invoke(object: TestBody {}) } } } - - if (!parent.lazy) { - context.registry.extensions() - .filterIsInstance(FixturesAdapter::class.java) - .forEach { - collector.executeSafely { it.afterExecuteTest(this@Test) } - } - } - - context.registry.extensions() - .filterIsInstance(AfterExecuteTest::class.java) - .forEach { - collector.executeSafely { it.afterExecuteTest(this) } - } - collector.assertEmpty() return context diff --git a/spek-junit-platform-engine/src/main/kotlin/org/jetbrains/spek/engine/SpekEngineDescriptor.kt b/spek-junit-platform-engine/src/main/kotlin/org/jetbrains/spek/engine/SpekEngineDescriptor.kt index 21de76d69..872e236b0 100644 --- a/spek-junit-platform-engine/src/main/kotlin/org/jetbrains/spek/engine/SpekEngineDescriptor.kt +++ b/spek-junit-platform-engine/src/main/kotlin/org/jetbrains/spek/engine/SpekEngineDescriptor.kt @@ -1,6 +1,6 @@ package org.jetbrains.spek.engine -import org.jetbrains.spek.extension.GroupExtensionContext +import org.jetbrains.spek.api.lifecycle.GroupScope import org.junit.platform.engine.UniqueId import org.junit.platform.engine.support.descriptor.EngineDescriptor import org.junit.platform.engine.support.hierarchical.Node @@ -9,8 +9,6 @@ import org.junit.platform.engine.support.hierarchical.Node * @author Ranie Jade Ramiso */ class SpekEngineDescriptor(uniqueId: UniqueId) - : EngineDescriptor(uniqueId, "Spek"), Node, GroupExtensionContext { - override val parent: GroupExtensionContext? = null - - override val lazy: Boolean = false + : EngineDescriptor(uniqueId, "Spek"), Node, GroupScope { + override val parent = null } diff --git a/spek-junit-platform-engine/src/main/kotlin/org/jetbrains/spek/engine/SpekExecutionContext.kt b/spek-junit-platform-engine/src/main/kotlin/org/jetbrains/spek/engine/SpekExecutionContext.kt index c7557df82..dba159b77 100644 --- a/spek-junit-platform-engine/src/main/kotlin/org/jetbrains/spek/engine/SpekExecutionContext.kt +++ b/spek-junit-platform-engine/src/main/kotlin/org/jetbrains/spek/engine/SpekExecutionContext.kt @@ -1,6 +1,5 @@ package org.jetbrains.spek.engine -import org.jetbrains.spek.engine.extension.ExtensionRegistryImpl import org.junit.platform.engine.EngineExecutionListener import org.junit.platform.engine.ExecutionRequest import org.junit.platform.engine.support.hierarchical.EngineExecutionContext @@ -8,8 +7,7 @@ import org.junit.platform.engine.support.hierarchical.EngineExecutionContext /** * @author Ranie Jade Ramiso */ -class SpekExecutionContext(val registry: ExtensionRegistryImpl, - val executionRequest: ExecutionRequest): EngineExecutionContext { +class SpekExecutionContext(val executionRequest: ExecutionRequest): EngineExecutionContext { val engineExecutionListener: EngineExecutionListener get() = executionRequest.engineExecutionListener } diff --git a/spek-junit-platform-engine/src/main/kotlin/org/jetbrains/spek/engine/SpekTestEngine.kt b/spek-junit-platform-engine/src/main/kotlin/org/jetbrains/spek/engine/SpekTestEngine.kt index 95553aaeb..822a78c8a 100644 --- a/spek-junit-platform-engine/src/main/kotlin/org/jetbrains/spek/engine/SpekTestEngine.kt +++ b/spek-junit-platform-engine/src/main/kotlin/org/jetbrains/spek/engine/SpekTestEngine.kt @@ -1,19 +1,24 @@ package org.jetbrains.spek.engine +import org.jetbrains.spek.api.CreateWith import org.jetbrains.spek.api.Spek -import org.jetbrains.spek.api.SubjectSpek -import org.jetbrains.spek.api.dsl.Dsl +import org.jetbrains.spek.api.dsl.ActionBody import org.jetbrains.spek.api.dsl.Pending -import org.jetbrains.spek.api.dsl.SubjectDsl -import org.jetbrains.spek.api.memoized.CachingMode -import org.jetbrains.spek.api.memoized.Subject -import org.jetbrains.spek.engine.extension.ExtensionRegistryImpl -import org.jetbrains.spek.engine.memoized.SubjectAdapter -import org.jetbrains.spek.engine.memoized.SubjectImpl -import org.jetbrains.spek.extension.Extension -import org.jetbrains.spek.extension.SpekExtension +import org.jetbrains.spek.api.dsl.Spec +import org.jetbrains.spek.api.dsl.SpecBody +import org.jetbrains.spek.api.dsl.TestBody +import org.jetbrains.spek.api.lifecycle.CachingMode +import org.jetbrains.spek.api.lifecycle.InstanceFactory +import org.jetbrains.spek.api.lifecycle.LifecycleAware +import org.jetbrains.spek.api.lifecycle.LifecycleListener +import org.jetbrains.spek.engine.lifecycle.LifecycleAwareAdapter +import org.jetbrains.spek.engine.lifecycle.LifecycleManager import org.junit.platform.commons.util.ReflectionUtils -import org.junit.platform.engine.* +import org.junit.platform.engine.EngineDiscoveryRequest +import org.junit.platform.engine.ExecutionRequest +import org.junit.platform.engine.TestDescriptor +import org.junit.platform.engine.TestSource +import org.junit.platform.engine.UniqueId import org.junit.platform.engine.discovery.ClassSelector import org.junit.platform.engine.discovery.ClasspathRootSelector import org.junit.platform.engine.discovery.PackageSelector @@ -22,16 +27,22 @@ import org.junit.platform.engine.support.descriptor.ClassSource import org.junit.platform.engine.support.descriptor.EngineDescriptor import org.junit.platform.engine.support.hierarchical.HierarchicalTestEngine import java.nio.file.Paths -import java.util.* +import java.util.LinkedList import java.util.function.Consumer import kotlin.reflect.KClass -import kotlin.reflect.KProperty import kotlin.reflect.primaryConstructor /** * @author Ranie Jade Ramiso */ class SpekTestEngine: HierarchicalTestEngine() { + + val defaultInstanceFactory = object: InstanceFactory { + override fun create(spek: KClass): T { + return spek.objectInstance ?: spek.primaryConstructor!!.call() + } + } + override fun discover(discoveryRequest: EngineDiscoveryRequest, uniqueId: UniqueId): TestDescriptor { val engineDescriptor = SpekEngineDescriptor(uniqueId) resolveSpecs(discoveryRequest, engineDescriptor) @@ -41,15 +52,13 @@ class SpekTestEngine: HierarchicalTestEngine() { override fun getId(): String = "spek" override fun createExecutionContext(request: ExecutionRequest) - = SpekExecutionContext(ExtensionRegistryImpl(), request) + = SpekExecutionContext(request) private fun resolveSpecs(discoveryRequest: EngineDiscoveryRequest, engineDescriptor: EngineDescriptor) { val isSpec = java.util.function.Predicate> { - Spek::class.java.isAssignableFrom(it) || SubjectSpek::class.java.isAssignableFrom(it) - } - val isSpecClass = java.util.function.Predicate { className -> - className.isNotEmpty() + Spek::class.java.isAssignableFrom(it) } + val isSpecClass = java.util.function.Predicate(String::isNotEmpty) discoveryRequest.getSelectorsByType(ClasspathRootSelector::class.java).forEach { ReflectionUtils.findAllClassesInClasspathRoot(Paths.get(it.classpathRoot), isSpec, isSpecClass).forEach { resolveSpec(engineDescriptor, it) @@ -91,160 +100,102 @@ class SpekTestEngine: HierarchicalTestEngine() { } private fun resolveSpec(engineDescriptor: EngineDescriptor, klass: Class<*>) { - val registry = ExtensionRegistryImpl().apply { - registerExtension(FixturesAdapter()) - registerExtension(SubjectAdapter()) - } - - getSpekExtensions(klass.kotlin) - .forEach { registry.registerExtension(it) } + val lifecycleManager = LifecycleManager() - val instance = klass.kotlin.primaryConstructor!!.call() - val root = Scope.Spec( + val kotlinClass = klass.kotlin + val instance = instanceFactoryFor(kotlinClass).create(kotlinClass as KClass) + val root = Scope.Group( engineDescriptor.uniqueId.append(SPEC_SEGMENT_TYPE, klass.name), - ClassSource(klass), registry, false + Pending.No, + ClassSource(klass), lifecycleManager ) engineDescriptor.addChild(root) - when(instance) { - is SubjectSpek<*> -> (instance as SubjectSpek).spec.invoke( - SubjectCollector(root, root.registry) - ) - is Spek -> instance.spec.invoke(Collector(root, root.registry)) - } + instance.spec.invoke(Collector(root, lifecycleManager)) } - open class Collector(val root: Scope.Group, val registry: ExtensionRegistryImpl): Dsl { - override fun group(description: String, pending: Pending, lazy: Boolean, body: Dsl.() -> Unit) { - val action: Scope.Group.(SpekExecutionContext) -> Unit = if (lazy) { - { - body.invoke(LazyGroupCollector(this, registry, it)) - } - } else { - { } - } - - val group = Scope.Group( - root.uniqueId.append(GROUP_SEGMENT_TYPE, description), pending, getSource(), lazy, action - ) - - root.addChild(group) + private fun instanceFactoryFor(spek: KClass<*>): InstanceFactory { + val factory = spek.annotations.filterIsInstance() + .map { it.factory } + .map { it.objectInstance ?: it.primaryConstructor!!.call() } + .firstOrNull() ?: defaultInstanceFactory + return factory + } - if (!lazy) { - body.invoke(Collector(group, registry)) - } + open class Collector(val root: Scope.Group, + val lifecycleManager: LifecycleManager): Spec { + val fixtures = FixturesAdapter().apply { + lifecycleManager.addListener(this) } - override fun test(description: String, pending: Pending, body: () -> Unit) { - val test = Scope.Test(root.uniqueId.append(TEST_SEGMENT_TYPE, description), pending, getSource(), body) - root.addChild(test) + override fun memoized(mode: CachingMode, factory: () -> T): LifecycleAware { + return LifecycleAwareAdapter(mode, factory).apply { + registerListener(this) + } } - override fun beforeEachTest(callback: () -> Unit) { - registry.getExtension(FixturesAdapter::class)!!.registerBeforeEach(root, callback) + override fun registerListener(listener: LifecycleListener) { + lifecycleManager.addListener(listener) } - override fun afterEachTest(callback: () -> Unit) { - registry.getExtension(FixturesAdapter::class)!!.registerAfterEach(root, callback) - } - } + override fun group(description: String, pending: Pending, body: SpecBody.() -> Unit) { + val group = Scope.Group( + root.uniqueId.append(GROUP_SEGMENT_TYPE, description), + pending, getSource(), lifecycleManager + ) + root.addChild(group) + body.invoke(Collector(group, lifecycleManager)) - class LazyGroupCollector(root: Scope.Group, registry: ExtensionRegistryImpl, - val context: SpekExecutionContext): Collector(root, registry) { - override fun group(description: String, pending: Pending, lazy: Boolean, body: Dsl.() -> Unit) { - fail() } - override fun beforeEachTest(callback: () -> Unit) { - fail() - } + override fun action(description: String, pending: Pending, body: ActionBody.() -> Unit) { + val action = Scope.Action( + root.uniqueId.append(GROUP_SEGMENT_TYPE, description), + pending, getSource(), lifecycleManager, { + body.invoke(ActionCollector(this, lifecycleManager, it)) + } + ) - override fun afterEachTest(callback: () -> Unit) { - fail() + root.addChild(action) } - override fun test(description: String, pending: Pending, body: () -> Unit) { - val test = Scope.Test(root.uniqueId.append(TEST_SEGMENT_TYPE, description), pending, getSource(), body) + override fun test(description: String, pending: Pending, body: TestBody.() -> Unit) { + val test = Scope.Test( + root.uniqueId.append(TEST_SEGMENT_TYPE, description), + pending, getSource(), lifecycleManager, body + ) root.addChild(test) - context.engineExecutionListener.dynamicTestRegistered(test) } - private inline fun fail() { - throw SpekException("You're not allowed to do this") + override fun beforeEachTest(callback: () -> Unit) { + fixtures.registerBeforeEach(root, callback) } - } - open class SubjectCollector(root: Scope.Group, registry: ExtensionRegistryImpl) - : Collector(root, registry), SubjectDsl { - var _subject: SubjectImpl? = null - - override fun subject(mode: CachingMode, factory: () -> T): Subject { - return registry.getExtension(SubjectAdapter::class)!! - .registerSubject(mode, root, factory).apply { _subject = this } + override fun afterEachTest(callback: () -> Unit) { + fixtures.registerAfterEach(root, callback) } + } - override val subject: T - get() { - if (_subject != null) { - return _subject!!.get() - } - throw SpekException("Subject not configured.") - } - - override fun > includeSubjectSpec(spec: KClass) { - val instance = spec.primaryConstructor!!.call() - val nestedRegistry = ExtensionRegistryImpl() - - registry.extensions().forEach { nestedRegistry.registerExtension(it) } - getSpekExtensions(spec) - .forEach { nestedRegistry.registerExtension(it) } + class ActionCollector(val root: Scope.Action, val lifecycleManager: LifecycleManager, + val context: SpekExecutionContext): ActionBody { - val scope = Scope.Spec( - root.uniqueId.append(SPEC_SEGMENT_TYPE, spec.java.name), - ClassSource(spec.java), nestedRegistry, true + override fun test(description: String, pending: Pending, body: TestBody.() -> Unit) { + val test = Scope.Test( + root.uniqueId.append(TEST_SEGMENT_TYPE, description), pending, getSource(), lifecycleManager, body ) - root.addChild(scope) - instance.spec.invoke(NestedSubjectCollector(scope, nestedRegistry, this as SubjectCollector)) - } - } - - class NestedSubjectCollector(root: Scope.Group, registry: ExtensionRegistryImpl, val parent: SubjectCollector) - : SubjectCollector(root, registry) { - override fun subject(mode: CachingMode, factory: () -> T): Subject { - return object: Subject { - override fun getValue(ref: Any?, property: KProperty<*>): T { - return parent.subject - } - } + root.addChild(test) + context.engineExecutionListener.dynamicTestRegistered(test) } - override val subject: T - get() = parent.subject } companion object { - const val SPEC_SEGMENT_TYPE = "spec"; - const val GROUP_SEGMENT_TYPE = "group"; - const val TEST_SEGMENT_TYPE = "test"; + const val SPEC_SEGMENT_TYPE = "spec" + const val GROUP_SEGMENT_TYPE = "group" + const val TEST_SEGMENT_TYPE = "test" // TODO: fix me fun getSource(): TestSource? = null - - fun getSpekExtensions(spec: KClass<*>): List { - return spec.annotations - .map { - if (it is SpekExtension) { - it - } else { - it.annotationClass.annotations.find { - it.annotationClass == SpekExtension::class - } as SpekExtension? - } - - } - .filter { it != null } - .map { it!!.extension.primaryConstructor!!.call() } - } } } diff --git a/spek-junit-platform-engine/src/main/kotlin/org/jetbrains/spek/engine/extension/ExtensionRegistryImpl.kt b/spek-junit-platform-engine/src/main/kotlin/org/jetbrains/spek/engine/extension/ExtensionRegistryImpl.kt deleted file mode 100644 index c1907d4cd..000000000 --- a/spek-junit-platform-engine/src/main/kotlin/org/jetbrains/spek/engine/extension/ExtensionRegistryImpl.kt +++ /dev/null @@ -1,25 +0,0 @@ -package org.jetbrains.spek.engine.extension - -import org.jetbrains.spek.extension.Extension -import org.jetbrains.spek.extension.ExtensionRegistry -import java.util.* -import kotlin.reflect.KClass - -/** - * @author Ranie Jade Ramiso - */ -class ExtensionRegistryImpl: ExtensionRegistry { - private val extensions: MutableMap, Extension> = HashMap() - - override fun getExtension(extension: KClass): T? { - return extensions[extension] as T? - } - - fun registerExtension(extension: T) { - if (!extensions.containsKey(extension.javaClass.kotlin)) { - extensions.put(extension.javaClass.kotlin, extension) - } - } - - fun extensions(): Sequence = extensions.values.asSequence() -} diff --git a/spek-junit-platform-engine/src/main/kotlin/org/jetbrains/spek/engine/lifecycle/LifecycleAwareAdapter.kt b/spek-junit-platform-engine/src/main/kotlin/org/jetbrains/spek/engine/lifecycle/LifecycleAwareAdapter.kt new file mode 100644 index 000000000..c84619c7e --- /dev/null +++ b/spek-junit-platform-engine/src/main/kotlin/org/jetbrains/spek/engine/lifecycle/LifecycleAwareAdapter.kt @@ -0,0 +1,43 @@ +package org.jetbrains.spek.engine.lifecycle + +import org.jetbrains.spek.api.lifecycle.ActionScope +import org.jetbrains.spek.api.lifecycle.CachingMode +import org.jetbrains.spek.api.lifecycle.GroupScope +import org.jetbrains.spek.api.lifecycle.LifecycleAware +import org.jetbrains.spek.api.lifecycle.LifecycleListener +import org.jetbrains.spek.api.lifecycle.TestScope +import kotlin.reflect.KProperty + +/** + * @author Ranie Jade Ramiso + */ +class LifecycleAwareAdapter(val mode: CachingMode, val factory: () -> T): LifecycleAware, LifecycleListener { + var cached: T? = null + + override fun getValue(thisRef: LifecycleAware, property: KProperty<*>) = invoke() + + override fun invoke(): T { + if (cached == null) { + cached = factory() + } + return cached!! + } + + override fun afterExecuteTest(test: TestScope) { + if (test.parent !is ActionScope) { + if (mode == CachingMode.TEST) { + cached = null + } + } + } + + override fun afterExecuteGroup(group: GroupScope) { + if (mode == CachingMode.GROUP) { + cached = null + } + } + + override fun afterExecuteAction(action: ActionScope) { + cached = null + } +} diff --git a/spek-junit-platform-engine/src/main/kotlin/org/jetbrains/spek/engine/lifecycle/LifecycleManager.kt b/spek-junit-platform-engine/src/main/kotlin/org/jetbrains/spek/engine/lifecycle/LifecycleManager.kt new file mode 100644 index 000000000..06b28eaa7 --- /dev/null +++ b/spek-junit-platform-engine/src/main/kotlin/org/jetbrains/spek/engine/lifecycle/LifecycleManager.kt @@ -0,0 +1,46 @@ +package org.jetbrains.spek.engine.lifecycle + +import org.jetbrains.spek.api.lifecycle.ActionScope +import org.jetbrains.spek.api.lifecycle.GroupScope +import org.jetbrains.spek.api.lifecycle.LifecycleListener +import org.jetbrains.spek.api.lifecycle.TestScope +import java.util.HashSet + +/** + * @author Ranie Jade Ramiso + */ +class LifecycleManager { + private val listeners = HashSet() + + fun addListener(listener: LifecycleListener) { + listeners.add(listener) + } + + fun removeListener(listener: LifecycleListener) { + listeners.remove(listener) + } + + fun beforeExecuteTest(test: TestScope) { + listeners.forEach { it.beforeExecuteTest(test) } + } + + fun afterExecuteTest(test: TestScope) { + listeners.forEach { it.afterExecuteTest(test) } + } + + fun beforeExecuteGroup(group: GroupScope) { + listeners.forEach { it.beforeExecuteGroup(group) } + } + + fun afterExecuteGroup(group: GroupScope) { + listeners.forEach { it.afterExecuteGroup(group) } + } + + fun beforeExecuteAction(action: ActionScope) { + listeners.forEach { it.beforeExecuteAction(action) } + } + + fun afterExecuteAction(action: ActionScope) { + listeners.forEach { it.afterExecuteAction(action) } + } +} diff --git a/spek-junit-platform-engine/src/main/kotlin/org/jetbrains/spek/engine/memoized/MemoizedValueImpl.kt b/spek-junit-platform-engine/src/main/kotlin/org/jetbrains/spek/engine/memoized/MemoizedValueImpl.kt deleted file mode 100644 index ab25d6fe1..000000000 --- a/spek-junit-platform-engine/src/main/kotlin/org/jetbrains/spek/engine/memoized/MemoizedValueImpl.kt +++ /dev/null @@ -1,25 +0,0 @@ -package org.jetbrains.spek.engine.memoized - -import org.jetbrains.spek.api.memoized.CachingMode -import org.jetbrains.spek.api.memoized.MemoizedValue -import kotlin.reflect.KProperty - -/** - * @author Ranie Jade Ramiso - */ -open class MemoizedValueImpl(val mode: CachingMode, val factory: () -> T): MemoizedValue { - private var instance: T? = null - - fun get(): T { - if (instance == null) { - instance = factory() - } - return instance!! - } - - override operator fun getValue(ref: Any?, property: KProperty<*>) = get() - - fun reset() { - instance = null - } -} diff --git a/spek-junit-platform-engine/src/main/kotlin/org/jetbrains/spek/engine/memoized/SubjectAdapter.kt b/spek-junit-platform-engine/src/main/kotlin/org/jetbrains/spek/engine/memoized/SubjectAdapter.kt deleted file mode 100644 index 77ee05ab9..000000000 --- a/spek-junit-platform-engine/src/main/kotlin/org/jetbrains/spek/engine/memoized/SubjectAdapter.kt +++ /dev/null @@ -1,49 +0,0 @@ -package org.jetbrains.spek.engine.memoized - -import org.jetbrains.spek.api.memoized.CachingMode -import org.jetbrains.spek.extension.GroupExtensionContext -import org.jetbrains.spek.extension.TestExtensionContext -import org.jetbrains.spek.extension.execution.AfterExecuteGroup -import org.jetbrains.spek.extension.execution.AfterExecuteTest -import java.util.* - -/** - * Adapter for [subjects][Subject] as a pseudo-extension. - * - * @author Ranie Jade Ramiso - */ -class SubjectAdapter: AfterExecuteGroup, AfterExecuteTest { - private val subjectMap: MutableMap> = WeakHashMap() - - override fun afterExecuteGroup(group: GroupExtensionContext) { - val subject = subjectMap[group] - - if (subject != null && subject.mode == CachingMode.GROUP) { - subject.reset() - } - } - - override fun afterExecuteTest(test: TestExtensionContext) { - if (!test.parent.lazy) { - resetSubjects(test.parent) - } - } - - fun registerSubject(mode: CachingMode, group: GroupExtensionContext, factory: () -> T): SubjectImpl { - val subject = SubjectImpl(mode, factory) - subjectMap.put(group, subject) - return subject - } - - fun resetSubjects(group: GroupExtensionContext) { - val subject = subjectMap[group] - - if (subject != null && subject.mode == CachingMode.TEST) { - subject.reset() - } - - if (group.parent != null) { - resetSubjects(group.parent!!) - } - } -} diff --git a/spek-junit-platform-engine/src/main/kotlin/org/jetbrains/spek/engine/memoized/SubjectImpl.kt b/spek-junit-platform-engine/src/main/kotlin/org/jetbrains/spek/engine/memoized/SubjectImpl.kt deleted file mode 100644 index 197317e73..000000000 --- a/spek-junit-platform-engine/src/main/kotlin/org/jetbrains/spek/engine/memoized/SubjectImpl.kt +++ /dev/null @@ -1,9 +0,0 @@ -package org.jetbrains.spek.engine.memoized - -import org.jetbrains.spek.api.memoized.CachingMode -import org.jetbrains.spek.api.memoized.Subject - -/** - * @author Ranie Jade Ramiso - */ -class SubjectImpl(mode: CachingMode, factory: () -> T): Subject, MemoizedValueImpl(mode, factory) diff --git a/spek-junit-platform-engine/src/main/kotlin/org/jetbrains/spek/extension/Extension.kt b/spek-junit-platform-engine/src/main/kotlin/org/jetbrains/spek/extension/Extension.kt deleted file mode 100644 index 3881fdc96..000000000 --- a/spek-junit-platform-engine/src/main/kotlin/org/jetbrains/spek/extension/Extension.kt +++ /dev/null @@ -1,10 +0,0 @@ -package org.jetbrains.spek.extension - -import org.jetbrains.spek.meta.Experimental - -/** - * @author Ranie Jade Ramiso - */ -@Experimental -interface Extension { -} diff --git a/spek-junit-platform-engine/src/main/kotlin/org/jetbrains/spek/extension/ExtensionRegistry.kt b/spek-junit-platform-engine/src/main/kotlin/org/jetbrains/spek/extension/ExtensionRegistry.kt deleted file mode 100644 index eede2a19c..000000000 --- a/spek-junit-platform-engine/src/main/kotlin/org/jetbrains/spek/extension/ExtensionRegistry.kt +++ /dev/null @@ -1,12 +0,0 @@ -package org.jetbrains.spek.extension - -import org.jetbrains.spek.meta.Experimental -import kotlin.reflect.KClass - -/** - * @author Ranie Jade Ramiso - */ -@Experimental -interface ExtensionRegistry { - fun getExtension(extension: KClass): T? -} diff --git a/spek-junit-platform-engine/src/main/kotlin/org/jetbrains/spek/extension/GroupExtensionContext.kt b/spek-junit-platform-engine/src/main/kotlin/org/jetbrains/spek/extension/GroupExtensionContext.kt deleted file mode 100644 index 81ca90f4f..000000000 --- a/spek-junit-platform-engine/src/main/kotlin/org/jetbrains/spek/extension/GroupExtensionContext.kt +++ /dev/null @@ -1,12 +0,0 @@ -package org.jetbrains.spek.extension - -import org.jetbrains.spek.meta.Experimental - -/** - * @author Ranie Jade Ramiso - */ -@Experimental -interface GroupExtensionContext: ExtensionContext { - val parent: GroupExtensionContext? - val lazy: Boolean -} diff --git a/spek-junit-platform-engine/src/main/kotlin/org/jetbrains/spek/extension/SpekExtension.kt b/spek-junit-platform-engine/src/main/kotlin/org/jetbrains/spek/extension/SpekExtension.kt deleted file mode 100644 index fc1cc13f9..000000000 --- a/spek-junit-platform-engine/src/main/kotlin/org/jetbrains/spek/extension/SpekExtension.kt +++ /dev/null @@ -1,11 +0,0 @@ -package org.jetbrains.spek.extension - -import org.jetbrains.spek.meta.Experimental -import kotlin.reflect.KClass - -/** - * @author Ranie Jade Ramiso - */ -@Experimental -@Target(AnnotationTarget.ANNOTATION_CLASS, AnnotationTarget.CLASS) -annotation class SpekExtension(val extension: KClass) diff --git a/spek-junit-platform-engine/src/main/kotlin/org/jetbrains/spek/extension/TestExtensionContext.kt b/spek-junit-platform-engine/src/main/kotlin/org/jetbrains/spek/extension/TestExtensionContext.kt deleted file mode 100644 index cbabe350e..000000000 --- a/spek-junit-platform-engine/src/main/kotlin/org/jetbrains/spek/extension/TestExtensionContext.kt +++ /dev/null @@ -1,11 +0,0 @@ -package org.jetbrains.spek.extension - -import org.jetbrains.spek.meta.Experimental - -/** - * @author Ranie Jade Ramiso - */ -@Experimental -interface TestExtensionContext: ExtensionContext { - val parent: GroupExtensionContext -} diff --git a/spek-junit-platform-engine/src/main/kotlin/org/jetbrains/spek/extension/execution/AfterExecuteGroup.kt b/spek-junit-platform-engine/src/main/kotlin/org/jetbrains/spek/extension/execution/AfterExecuteGroup.kt deleted file mode 100644 index 49b15c1ce..000000000 --- a/spek-junit-platform-engine/src/main/kotlin/org/jetbrains/spek/extension/execution/AfterExecuteGroup.kt +++ /dev/null @@ -1,13 +0,0 @@ -package org.jetbrains.spek.extension.execution - -import org.jetbrains.spek.extension.Extension -import org.jetbrains.spek.extension.GroupExtensionContext -import org.jetbrains.spek.meta.Experimental - -/** - * @author Ranie Jade Ramiso - */ -@Experimental -interface AfterExecuteGroup: Extension { - fun afterExecuteGroup(group: GroupExtensionContext) -} diff --git a/spek-junit-platform-engine/src/main/kotlin/org/jetbrains/spek/extension/execution/AfterExecuteSpec.kt b/spek-junit-platform-engine/src/main/kotlin/org/jetbrains/spek/extension/execution/AfterExecuteSpec.kt deleted file mode 100644 index 22b49fdf1..000000000 --- a/spek-junit-platform-engine/src/main/kotlin/org/jetbrains/spek/extension/execution/AfterExecuteSpec.kt +++ /dev/null @@ -1,10 +0,0 @@ -package org.jetbrains.spek.extension.execution - -import org.jetbrains.spek.extension.GroupExtensionContext - -/** - * @author Ranie Jade Ramiso - */ -interface AfterExecuteSpec { - fun afterExecuteSpec(spec: GroupExtensionContext) -} diff --git a/spek-junit-platform-engine/src/main/kotlin/org/jetbrains/spek/extension/execution/AfterExecuteTest.kt b/spek-junit-platform-engine/src/main/kotlin/org/jetbrains/spek/extension/execution/AfterExecuteTest.kt deleted file mode 100644 index e764eee55..000000000 --- a/spek-junit-platform-engine/src/main/kotlin/org/jetbrains/spek/extension/execution/AfterExecuteTest.kt +++ /dev/null @@ -1,13 +0,0 @@ -package org.jetbrains.spek.extension.execution - -import org.jetbrains.spek.extension.Extension -import org.jetbrains.spek.extension.TestExtensionContext -import org.jetbrains.spek.meta.Experimental - -/** - * @author Ranie Jade Ramiso - */ -@Experimental -interface AfterExecuteTest: Extension { - fun afterExecuteTest(test: TestExtensionContext) -} diff --git a/spek-junit-platform-engine/src/main/kotlin/org/jetbrains/spek/extension/execution/BeforeExecuteGroup.kt b/spek-junit-platform-engine/src/main/kotlin/org/jetbrains/spek/extension/execution/BeforeExecuteGroup.kt deleted file mode 100644 index 849c95683..000000000 --- a/spek-junit-platform-engine/src/main/kotlin/org/jetbrains/spek/extension/execution/BeforeExecuteGroup.kt +++ /dev/null @@ -1,13 +0,0 @@ -package org.jetbrains.spek.extension.execution - -import org.jetbrains.spek.extension.Extension -import org.jetbrains.spek.extension.GroupExtensionContext -import org.jetbrains.spek.meta.Experimental - -/** - * @author Ranie Jade Ramiso - */ -@Experimental -interface BeforeExecuteGroup: Extension { - fun beforeExecuteGroup(group: GroupExtensionContext) -} diff --git a/spek-junit-platform-engine/src/main/kotlin/org/jetbrains/spek/extension/execution/BeforeExecuteSpec.kt b/spek-junit-platform-engine/src/main/kotlin/org/jetbrains/spek/extension/execution/BeforeExecuteSpec.kt deleted file mode 100644 index 6bc308c61..000000000 --- a/spek-junit-platform-engine/src/main/kotlin/org/jetbrains/spek/extension/execution/BeforeExecuteSpec.kt +++ /dev/null @@ -1,10 +0,0 @@ -package org.jetbrains.spek.extension.execution - -import org.jetbrains.spek.extension.GroupExtensionContext - -/** - * @author Ranie Jade Ramiso - */ -interface BeforeExecuteSpec { - fun beforeExecuteSpec(spec: GroupExtensionContext) -} diff --git a/spek-junit-platform-engine/src/main/kotlin/org/jetbrains/spek/extension/execution/BeforeExecuteTest.kt b/spek-junit-platform-engine/src/main/kotlin/org/jetbrains/spek/extension/execution/BeforeExecuteTest.kt deleted file mode 100644 index 2d410b5c4..000000000 --- a/spek-junit-platform-engine/src/main/kotlin/org/jetbrains/spek/extension/execution/BeforeExecuteTest.kt +++ /dev/null @@ -1,13 +0,0 @@ -package org.jetbrains.spek.extension.execution - -import org.jetbrains.spek.extension.Extension -import org.jetbrains.spek.extension.TestExtensionContext -import org.jetbrains.spek.meta.Experimental - -/** - * @author Ranie Jade Ramiso - */ -@Experimental -interface BeforeExecuteTest: Extension { - fun beforeExecuteTest(test: TestExtensionContext) -} diff --git a/spek-junit-platform-engine/src/test/kotlin/org/jetbrains/spek/engine/ActionTest.kt b/spek-junit-platform-engine/src/test/kotlin/org/jetbrains/spek/engine/ActionTest.kt new file mode 100644 index 000000000..71e046416 --- /dev/null +++ b/spek-junit-platform-engine/src/test/kotlin/org/jetbrains/spek/engine/ActionTest.kt @@ -0,0 +1,40 @@ +package org.jetbrains.spek.engine + +import com.natpryce.hamkrest.assertion.assertThat +import com.natpryce.hamkrest.equalTo +import org.jetbrains.spek.api.Spek +import org.jetbrains.spek.api.dsl.it +import org.jetbrains.spek.api.dsl.on +import org.jetbrains.spek.engine.support.AbstractSpekTestEngineTest +import org.junit.jupiter.api.Test + +/** + * @author Ranie Jade Ramiso + */ +class ActionTest: AbstractSpekTestEngineTest() { + @Test + fun testOn() { + class TestSpek: Spek({ + var count = 0 + on("something") { + count++ + + it("do this") { + assertThat(count, equalTo(1)) + } + + count++ + + it("do that") { + assertThat(count, equalTo(2)) + } + } + }) + + val recorder = executeTestsForClass(TestSpek::class) + + assertThat(recorder.dynamicTestRegisteredCount, equalTo(2)) + assertThat(recorder.testSuccessfulCount, equalTo(1)) + assertThat(recorder.testFailureCount, equalTo(1)) + } +} diff --git a/spek-junit-platform-engine/src/test/kotlin/org/jetbrains/spek/engine/AfterEachTest.kt b/spek-junit-platform-engine/src/test/kotlin/org/jetbrains/spek/engine/AfterEachTest.kt index 1bcf1016f..ab90fc38d 100644 --- a/spek-junit-platform-engine/src/test/kotlin/org/jetbrains/spek/engine/AfterEachTest.kt +++ b/spek-junit-platform-engine/src/test/kotlin/org/jetbrains/spek/engine/AfterEachTest.kt @@ -28,10 +28,10 @@ class AfterEachTest: AbstractSpekTestEngineTest() { } @Test - fun testAfterEachLazyGroup() { + fun testAfterEachAction() { counter = 0 class TestSpek: Spek({ - group("group", lazy = true) { + action("group") { test("test") { } test("another test") { } } diff --git a/spek-junit-platform-engine/src/test/kotlin/org/jetbrains/spek/engine/BeforeEachTest.kt b/spek-junit-platform-engine/src/test/kotlin/org/jetbrains/spek/engine/BeforeEachTest.kt index 18c5bd14b..bddadbdf4 100644 --- a/spek-junit-platform-engine/src/test/kotlin/org/jetbrains/spek/engine/BeforeEachTest.kt +++ b/spek-junit-platform-engine/src/test/kotlin/org/jetbrains/spek/engine/BeforeEachTest.kt @@ -27,11 +27,11 @@ class BeforeEachTest: AbstractSpekTestEngineTest() { } @Test - fun testBeforeEachLazyGroup() { + fun testBeforeEachLazyAction() { counter = 0 class TestSpek: Spek({ beforeEachTest { counter++ } - group("group", lazy = true) { + action("group") { test("test") { } test("another test") { } } diff --git a/spek-junit-platform-engine/src/test/kotlin/org/jetbrains/spek/engine/ExtensionTest.kt b/spek-junit-platform-engine/src/test/kotlin/org/jetbrains/spek/engine/ExtensionTest.kt deleted file mode 100644 index a807f35d4..000000000 --- a/spek-junit-platform-engine/src/test/kotlin/org/jetbrains/spek/engine/ExtensionTest.kt +++ /dev/null @@ -1,252 +0,0 @@ -package org.jetbrains.spek.engine - -import com.natpryce.hamkrest.anything -import com.natpryce.hamkrest.assertion.assertThat -import com.natpryce.hamkrest.equalTo -import com.natpryce.hamkrest.present -import org.jetbrains.spek.api.Spek -import org.jetbrains.spek.api.SubjectSpek -import org.jetbrains.spek.engine.support.AbstractSpekTestEngineTest -import org.jetbrains.spek.extension.GroupExtensionContext -import org.jetbrains.spek.extension.SpekExtension -import org.jetbrains.spek.extension.TestExtensionContext -import org.jetbrains.spek.extension.execution.* -import org.junit.jupiter.api.Test -import org.junit.platform.runner.JUnitPlatform -import org.junit.runner.RunWith - -/** - * @author Ranie Jade Ramiso - */ -@RunWith(JUnitPlatform::class) -class ExtensionTest: AbstractSpekTestEngineTest() { - class SpekSimpleExtension - : BeforeExecuteTest, AfterExecuteTest, - BeforeExecuteGroup, AfterExecuteGroup, BeforeExecuteSpec, AfterExecuteSpec { - override fun beforeExecuteSpec(spec: GroupExtensionContext) { - builder.appendln("${" ".repeat(indent)}beforeExecuteSpec") - indent++ - } - - override fun afterExecuteSpec(spec: GroupExtensionContext) { - indent-- - builder.appendln("${" ".repeat(indent)}afterExecuteSpec") - } - - var indent = 0 - - override fun beforeExecuteTest(test: TestExtensionContext) { - builder.appendln("${" ".repeat(indent)}beforeExecuteTest") - indent++ - } - - override fun afterExecuteTest(test: TestExtensionContext) { - indent-- - builder.appendln("${" ".repeat(indent)}afterExecuteTest") - } - - override fun beforeExecuteGroup(group: GroupExtensionContext) { - builder.appendln("${" ".repeat(indent)}beforeExecuteGroup") - indent++ - } - - override fun afterExecuteGroup(group: GroupExtensionContext) { - indent-- - builder.appendln("${" ".repeat(indent)}afterExecuteGroup") - } - - companion object { - var builder = StringBuilder() - } - } - - @SpekExtension(SpekSimpleExtension::class) - annotation class SimpleExtension - - @Test - fun testDiscoveryCustomAnnotation() { - @SimpleExtension - class SomeSpek: Spek({ - test("SimpleExtension should be present") { - assertThat( - (this as SpekTestEngine.Collector) - .registry.getExtension(SpekSimpleExtension::class), present(anything) - ) - } - }) - - val recorder = executeTestsForClass(SomeSpek::class) - - assertThat(recorder.testFailureCount, equalTo(0)) - } - - @Test - fun testDiscovery() { - @SpekExtension(SpekSimpleExtension::class) - class SomeSpek: Spek({ - test("SimpleExtension should be present") { - assertThat( - (this as SpekTestEngine.Collector) - .registry.getExtension(SpekSimpleExtension::class), present(anything) - ) - } - }) - - val recorder = executeTestsForClass(SomeSpek::class) - - assertThat(recorder.testFailureCount, equalTo(0)) - } - - @Test - fun testLifeCycleExtensionPoints() { - @SimpleExtension - class SomeSpek: Spek({ - group("some group") { - group("another group") { - test("test") { } - test("another test") { } - } - - test("yet another test") { } - } - }) - - SpekSimpleExtension.builder = StringBuilder() - - executeTestsForClass(SomeSpek::class) - - assertThat(SpekSimpleExtension.builder.trim().toString(), equalTo(""" - beforeExecuteSpec - beforeExecuteGroup - beforeExecuteGroup - beforeExecuteTest - afterExecuteTest - beforeExecuteTest - afterExecuteTest - afterExecuteGroup - beforeExecuteTest - afterExecuteTest - afterExecuteGroup - afterExecuteSpec - """.trimIndent())) - } - - @Test - fun testSubjectSpekLifeCycleExtensionPoints() { - @SimpleExtension - class SomeSpek: SubjectSpek>({ - subject { emptyList() } - group("some group") { - group("another group") { - test("test") { } - test("another test") { } - } - - test("yet another test") { } - } - }) - - SpekSimpleExtension.builder = StringBuilder() - - executeTestsForClass(SomeSpek::class) - - assertThat(SpekSimpleExtension.builder.trim().toString(), equalTo(""" - beforeExecuteSpec - beforeExecuteGroup - beforeExecuteGroup - beforeExecuteTest - afterExecuteTest - beforeExecuteTest - afterExecuteTest - afterExecuteGroup - beforeExecuteTest - afterExecuteTest - afterExecuteGroup - afterExecuteSpec - """.trimIndent())) - } - - @Test - fun testSubjectSpekLifeCycleExtensionPointsInherited() { - class AnotherSpec: SubjectSpek>({ - group("another nested group") { - test("another nested test") { } - } - }) - - @SimpleExtension - class SomeSpek: SubjectSpek>({ - subject { emptyList() } - includeSubjectSpec(AnotherSpec::class) - group("some group") { - group("another group") { - test("test") { } - test("another test") { } - } - - test("yet another test") { } - } - }) - - SpekSimpleExtension.builder = StringBuilder() - - executeTestsForClass(SomeSpek::class) - - assertThat(SpekSimpleExtension.builder.trim().toString(), equalTo(""" - beforeExecuteSpec - beforeExecuteGroup - beforeExecuteGroup - beforeExecuteTest - afterExecuteTest - afterExecuteGroup - afterExecuteGroup - beforeExecuteGroup - beforeExecuteGroup - beforeExecuteTest - afterExecuteTest - beforeExecuteTest - afterExecuteTest - afterExecuteGroup - beforeExecuteTest - afterExecuteTest - afterExecuteGroup - afterExecuteSpec - """.trimIndent())) - } - - @Test - fun testSubjectSpekLifeCycleExtensionPointsIsolation() { - @SimpleExtension - class AnotherSpec: SubjectSpek>({ - group("another nested group") { - test("another nested test") { } - } - }) - - class SomeSpek: SubjectSpek>({ - subject { emptyList() } - includeSubjectSpec(AnotherSpec::class) - group("some group") { - group("another group") { - test("test") { } - test("another test") { } - } - - test("yet another test") { } - } - }) - - SpekSimpleExtension.builder = StringBuilder() - - executeTestsForClass(SomeSpek::class) - - assertThat(SpekSimpleExtension.builder.trim().toString(), equalTo(""" - beforeExecuteGroup - beforeExecuteGroup - beforeExecuteTest - afterExecuteTest - afterExecuteGroup - afterExecuteGroup - """.trimIndent())) - } -} diff --git a/spek-junit-platform-engine/src/test/kotlin/org/jetbrains/spek/engine/InstanceFactoryTest.kt b/spek-junit-platform-engine/src/test/kotlin/org/jetbrains/spek/engine/InstanceFactoryTest.kt new file mode 100644 index 000000000..d56a6cd3c --- /dev/null +++ b/spek-junit-platform-engine/src/test/kotlin/org/jetbrains/spek/engine/InstanceFactoryTest.kt @@ -0,0 +1,55 @@ +package org.jetbrains.spek.engine + +import com.natpryce.hamkrest.assertion.assertThat +import com.natpryce.hamkrest.equalTo +import org.jetbrains.spek.api.CreateWith +import org.jetbrains.spek.api.Spek +import org.jetbrains.spek.api.dsl.it +import org.jetbrains.spek.api.lifecycle.InstanceFactory +import org.jetbrains.spek.engine.support.AbstractSpekTestEngineTest +import org.junit.jupiter.api.Test +import kotlin.reflect.KClass +import kotlin.reflect.primaryConstructor + +/** + * @author Ranie Jade Ramiso + */ +class InstanceFactoryTest: AbstractSpekTestEngineTest() { + object SimpleFactoryAsAnObject: InstanceFactory { + override fun create(spek: KClass): T { + return spek.objectInstance ?: spek.primaryConstructor!!.call() + } + } + + class SimpleFactoryAsAClass: InstanceFactory { + override fun create(spek: KClass): T { + return spek.objectInstance ?: spek.primaryConstructor!!.call() + } + } + + @Test + fun testUsingObject() { + @CreateWith(SimpleFactoryAsAnObject::class) + class SomeSpec: Spek({ + it("should work") { + + } + }) + + val recorder = executeTestsForClass(SomeSpec::class) + assertThat(recorder.testSuccessfulCount, equalTo(1)) + } + + @Test + fun testUsingClass() { + @CreateWith(SimpleFactoryAsAClass::class) + class SomeSpec: Spek({ + it("should work") { + + } + }) + + val recorder = executeTestsForClass(SomeSpec::class) + assertThat(recorder.testSuccessfulCount, equalTo(1)) + } +} diff --git a/spek-junit-platform-engine/src/test/kotlin/org/jetbrains/spek/engine/LazyGroupTest.kt b/spek-junit-platform-engine/src/test/kotlin/org/jetbrains/spek/engine/LazyGroupTest.kt deleted file mode 100644 index d1049ac86..000000000 --- a/spek-junit-platform-engine/src/test/kotlin/org/jetbrains/spek/engine/LazyGroupTest.kt +++ /dev/null @@ -1,120 +0,0 @@ -package org.jetbrains.spek.engine - -import com.natpryce.hamkrest.assertion.assertThat -import com.natpryce.hamkrest.equalTo -import org.jetbrains.spek.api.Spek -import org.jetbrains.spek.api.dsl.describe -import org.jetbrains.spek.api.dsl.it -import org.jetbrains.spek.api.dsl.on -import org.jetbrains.spek.engine.support.AbstractSpekTestEngineTest -import org.junit.Test - -/** - * @author Ranie Jade Ramiso - */ -class LazyGroupTest: AbstractSpekTestEngineTest() { - @Test - fun testBeforeEachShouldFail() { - class TestSpek: Spek({ - on("fail") { - beforeEachTest { - println() - } - - it("will not show") { - - } - } - }) - - val recorder = executeTestsForClass(TestSpek::class) - - assertThat(recorder.containerFailureCount, equalTo(1)) - assertThat(recorder.testStartedCount, equalTo(0)) - } - - @Test - fun testAfterEachShouldFail() { - class TestSpek: Spek({ - on("fail") { - it("will not show") { - - } - - afterEachTest { - println() - } - } - }) - - val recorder = executeTestsForClass(TestSpek::class) - - assertThat(recorder.containerFailureCount, equalTo(1)) - assertThat(recorder.testStartedCount, equalTo(0)) - } - - @Test - fun testGroupCreationFail() { - class TestSpek: Spek({ - on("fail") { - group("foo") { - - } - - it("will not show") { - - } - } - }) - - val recorder = executeTestsForClass(TestSpek::class) - - assertThat(recorder.containerFailureCount, equalTo(1)) - assertThat(recorder.testStartedCount, equalTo(0)) - } - - @Test - fun testOn() { - class TestSpek: Spek({ - var count = 0 - on("something") { - count++ - - it("do this") { - assertThat(count, equalTo(1)) - } - - count++ - - it("do that") { - assertThat(count, equalTo(2)) - } - } - }) - - val recorder = executeTestsForClass(TestSpek::class) - - assertThat(recorder.dynamicTestRegisteredCount, equalTo(2)) - assertThat(recorder.testSuccessfulCount, equalTo(1)) - assertThat(recorder.testFailureCount, equalTo(1)) - - class SomeSpec: Spek({ - describe("something") { - beforeEachTest { - println("hello") - } - - on("this") { - println("world") - it("do this") { - println("foo") - } - - it("do that") { - println("bar") - } - } - } - }) - } -} diff --git a/spek-junit-platform-engine/src/test/kotlin/org/jetbrains/spek/engine/MemoizedTest.kt b/spek-junit-platform-engine/src/test/kotlin/org/jetbrains/spek/engine/MemoizedTest.kt new file mode 100644 index 000000000..1f6b0964a --- /dev/null +++ b/spek-junit-platform-engine/src/test/kotlin/org/jetbrains/spek/engine/MemoizedTest.kt @@ -0,0 +1,102 @@ +package org.jetbrains.spek.engine + +import com.natpryce.hamkrest.assertion.assertThat +import com.natpryce.hamkrest.equalTo +import com.natpryce.hamkrest.sameInstance +import org.jetbrains.spek.api.Spek +import org.jetbrains.spek.api.lifecycle.CachingMode +import org.jetbrains.spek.engine.support.AbstractSpekTestEngineTest +import org.junit.jupiter.api.Test + +/** + * @author Ranie Jade Ramiso + */ +class MemoizedTest: AbstractSpekTestEngineTest() { + @Test + fun testMemoizedTestCaching() { + class MemoizedSpec: Spek({ + val foo = memoized { + listOf(1) + } + + var memoized1: List? = null + var memoized2: List? = null + + test("first pass") { + memoized1 = foo() + } + + test("second pass") { + memoized2 = foo() + } + + test("check") { + assertThat(memoized1, !sameInstance(memoized2)) + } + }) + + val recorder = executeTestsForClass(MemoizedSpec::class) + + assertThat(recorder.testFailureCount, equalTo(0)) + } + + @Test + fun testMemoizedGroupCaching() { + class MemoizedSpec: Spek({ + val foo = memoized(CachingMode.GROUP) { + listOf(1) + } + + var memoized1: List? = null + var memoized2: List? = null + + test("first pass") { + memoized1 = foo() + } + + test("second pass") { + memoized2 = foo() + } + + test("check") { + assertThat(memoized1, sameInstance(memoized2)) + } + }) + + val recorder = executeTestsForClass(MemoizedSpec::class) + + assertThat(recorder.testFailureCount, equalTo(0)) + } + + @Test + fun testMemoizedActionCaching() { + class MemoizedSpec: Spek({ + val foo = memoized { + listOf(1) + } + + var memoized1: List? = null + var memoized2: List? = null + + action("some action") { + test("first pass") { + memoized1 = foo() + } + + test("second pass") { + memoized2 = foo() + } + + test("check") { + assertThat(memoized1, sameInstance(memoized2)) + } + } + + + }) + + val recorder = executeTestsForClass(MemoizedSpec::class) + + assertThat(recorder.testFailureCount, equalTo(0)) + } +} diff --git a/spek-junit-platform-engine/src/test/kotlin/org/jetbrains/spek/engine/memoized/SubjectTest.kt b/spek-junit-platform-engine/src/test/kotlin/org/jetbrains/spek/engine/memoized/SubjectTest.kt deleted file mode 100644 index af16e8dcb..000000000 --- a/spek-junit-platform-engine/src/test/kotlin/org/jetbrains/spek/engine/memoized/SubjectTest.kt +++ /dev/null @@ -1,165 +0,0 @@ -package org.jetbrains.spek.engine.memoized - -import com.natpryce.hamkrest.assertion.assertThat -import com.natpryce.hamkrest.equalTo -import com.natpryce.hamkrest.sameInstance -import org.jetbrains.spek.api.SubjectSpek -import org.jetbrains.spek.api.memoized.CachingMode -import org.jetbrains.spek.engine.SpekException -import org.jetbrains.spek.engine.support.AbstractSpekTestEngineTest -import org.junit.jupiter.api.Test - -/** - * @author Ranie Jade Ramiso - */ -class SubjectTest: AbstractSpekTestEngineTest() { - open class Foo { - fun bar() { } - } - - // companion objects not allowed on local classes - class FooSpec: SubjectSpek({ - subject { Foo() } - test("test #1") { - subject1 = subject - } - - test("test #2") { - subject2 = subject - } - }) { - companion object { - lateinit var subject1: Foo - lateinit var subject2: Foo - } - } - - // companion objects not allowed on local classes - class Foo2Spec: SubjectSpek({ - subject(CachingMode.GROUP) { Foo() } - test("test #1") { - subject1 = subject - } - - test("test #2") { - subject2 = subject - } - }) { - companion object { - lateinit var subject1: Foo - lateinit var subject2: Foo - } - } - - class Foo3Spec: SubjectSpek({ - subject { Foo() } - - group("lazy", lazy = true) { - test("test #1") { - subject1 = subject - } - - test("test #2") { - subject2 = subject - } - } - }) { - companion object { - lateinit var subject1: Foo - lateinit var subject2: Foo - } - } - - @Test - fun testDifferentInstancePerTest() { - executeTestsForClass(FooSpec::class) - assertThat(FooSpec.subject1, !sameInstance(FooSpec.subject2)) - } - - @Test - fun testSameInstancePerTest() { - executeTestsForClass(Foo2Spec::class) - assertThat(Foo2Spec.subject1, sameInstance(Foo2Spec.subject2)) - } - - @Test - fun testSubjectOnLazyGroups() { - executeTestsForClass(Foo3Spec::class) - assertThat(Foo3Spec.subject1, sameInstance(Foo3Spec.subject2)) - } - - @Test - fun testNotConfiguredSubject() { - class SubjectSpec: SubjectSpek({ - test("this should fail") { - subject.bar() - } - }) - - val recorder = executeTestsForClass(SubjectSpec::class) - - assertThat(recorder.testFailureCount, equalTo(1)) - val throwable = recorder.getFailingTestEvents().first().result.throwable - fun isSpekException(throwable: Throwable) = throwable is SpekException - assertThat(throwable.get(), ::isSpekException) - } - - @Test - fun testIncludeSubjectSpecInstance() { - class Bar: Foo() - - class BarSpec: SubjectSpek({ - subject { Bar() } - includeSubjectSpec(FooSpec::class) - }) - - executeTestsForClass(BarSpec::class) - fun isBar(foo: Foo) = foo is Bar - assertThat(FooSpec.subject1, ::isBar) - assertThat(FooSpec.subject2, ::isBar) - } - - @Test - fun testIncludeSubjectSpec() { - open class Foo - class Bar: Foo() - - class FooSpec: SubjectSpek({ - test("a foo test") { } - test("another foo test") { } - }) - - class BarSpec: SubjectSpek({ - subject { Bar() } - includeSubjectSpec(FooSpec::class) - - test("a bar test") { } - }) - - val recorder = executeTestsForClass(BarSpec::class) - - assertThat(recorder.testSuccessfulCount, equalTo(3)) - - } - - @Test - fun tesIncludeSubjectNotConfigured() { - class Bar: Foo() - class SubjectSpec: SubjectSpek({ - test("this should fail") { - subject.bar() - } - }) - - class IncludedSubjectSpec: SubjectSpek({ - includeSubjectSpec(SubjectSpec::class) - }) - - val recorder = executeTestsForClass(IncludedSubjectSpec::class) - - assertThat(recorder.testFailureCount, equalTo(1)) - val throwable = recorder.getFailingTestEvents().first().result.throwable - fun isSpekException(throwable: Throwable) = throwable is SpekException - assertThat(throwable.get(), ::isSpekException) - } -} diff --git a/spek-samples/build.gradle b/spek-samples/build.gradle index 924739598..dc0a9b794 100644 --- a/spek-samples/build.gradle +++ b/spek-samples/build.gradle @@ -16,6 +16,8 @@ description = 'Spek Samples' dependencies { compile project(':spek-api') + compile project(':spek-subject-extension') + compile "org.jetbrains.kotlin:kotlin-test" testCompile "org.junit.platform:junit-platform-runner" testRuntime project(':spek-junit-platform-engine') diff --git a/spek-samples/src/test/kotlin/org/jetbrains/spek/samples/Calculator.kt b/spek-samples/src/main/kotlin/org/jetbrains/samples/Calculator.kt similarity index 91% rename from spek-samples/src/test/kotlin/org/jetbrains/spek/samples/Calculator.kt rename to spek-samples/src/main/kotlin/org/jetbrains/samples/Calculator.kt index 72aa0b717..1e8e9009f 100644 --- a/spek-samples/src/test/kotlin/org/jetbrains/spek/samples/Calculator.kt +++ b/spek-samples/src/main/kotlin/org/jetbrains/samples/Calculator.kt @@ -1,4 +1,4 @@ -package org.jetbrains.spek.samples +package org.jetbrains.samples open class Calculator { fun add(x: Int, y: Int) = x + y diff --git a/spek-samples/src/test/kotlin/org/jetbrains/spek/samples/ContextGivenOnSpec.kt b/spek-samples/src/test/kotlin/org/jetbrains/spek/samples/ContextGivenOnSpec.kt index 855d46b3e..06d9a7941 100644 --- a/spek-samples/src/test/kotlin/org/jetbrains/spek/samples/ContextGivenOnSpec.kt +++ b/spek-samples/src/test/kotlin/org/jetbrains/spek/samples/ContextGivenOnSpec.kt @@ -1,7 +1,7 @@ package org.jetbrains.spek.samples +import org.jetbrains.samples.Calculator import org.jetbrains.spek.api.Spek -import org.jetbrains.spek.api.dsl.context import org.jetbrains.spek.api.dsl.given import org.jetbrains.spek.api.dsl.it import org.jetbrains.spek.api.dsl.on @@ -10,12 +10,10 @@ import kotlin.test.assertEquals class ContextGivenOnSpec : Spek({ given("a calculator") { val calculator = Calculator() - var result = 0 + var result: Int - context("addition") { - beforeEachTest { - result = calculator.add(2, 4) - } + on("addition") { + result = calculator.add(2, 4) it("should return the result of adding the first number to the second number") { assertEquals(6, result) diff --git a/spek-samples/src/test/kotlin/org/jetbrains/spek/samples/NestedDescribesSpec.kt b/spek-samples/src/test/kotlin/org/jetbrains/spek/samples/NestedDescribesSpec.kt index 0c5615b43..df9f83f96 100644 --- a/spek-samples/src/test/kotlin/org/jetbrains/spek/samples/NestedDescribesSpec.kt +++ b/spek-samples/src/test/kotlin/org/jetbrains/spek/samples/NestedDescribesSpec.kt @@ -1,5 +1,6 @@ package org.jetbrains.spek.samples +import org.jetbrains.samples.Calculator import org.jetbrains.spek.api.Spek import org.jetbrains.spek.api.dsl.describe import org.jetbrains.spek.api.dsl.it diff --git a/spek-samples/src/test/kotlin/org/jetbrains/spek/samples/ObjectSampleSpec.kt b/spek-samples/src/test/kotlin/org/jetbrains/spek/samples/ObjectSampleSpec.kt new file mode 100644 index 000000000..56a9aa833 --- /dev/null +++ b/spek-samples/src/test/kotlin/org/jetbrains/spek/samples/ObjectSampleSpec.kt @@ -0,0 +1,16 @@ +package org.jetbrains.spek.samples + +import org.jetbrains.spek.api.Spek +import org.jetbrains.spek.api.dsl.describe +import org.jetbrains.spek.api.dsl.it + +/** + * @author Ranie Jade Ramiso + */ +object ObjectSampleSpec: Spek({ + describe("something") { + it("should do this") { + + } + } +}) diff --git a/spek-samples/src/test/kotlin/org/jetbrains/spek/samples/SharedSpec.kt b/spek-samples/src/test/kotlin/org/jetbrains/spek/samples/SharedSpec.kt new file mode 100644 index 000000000..93f40e0ad --- /dev/null +++ b/spek-samples/src/test/kotlin/org/jetbrains/spek/samples/SharedSpec.kt @@ -0,0 +1,19 @@ +package org.jetbrains.spek.samples + +import org.jetbrains.spek.api.Spek +import org.jetbrains.spek.api.dsl.describe +import org.jetbrains.spek.api.dsl.it +import org.jetbrains.spek.api.include + +object SharedSpec: Spek({ + describe("foo") { + it("should be okay") { + + } + } +}) + + +class SomeSpek: Spek({ + include(SharedSpec) +}) diff --git a/spek-samples/src/test/kotlin/org/jetbrains/spek/samples/SkipSampleSpec.kt b/spek-samples/src/test/kotlin/org/jetbrains/spek/samples/SkipSampleSpec.kt index 5cc5bc1ef..b56c94673 100644 --- a/spek-samples/src/test/kotlin/org/jetbrains/spek/samples/SkipSampleSpec.kt +++ b/spek-samples/src/test/kotlin/org/jetbrains/spek/samples/SkipSampleSpec.kt @@ -1,7 +1,12 @@ package org.jetbrains.spek.samples import org.jetbrains.spek.api.Spek -import org.jetbrains.spek.api.dsl.* +import org.jetbrains.spek.api.dsl.it +import org.jetbrains.spek.api.dsl.xcontext +import org.jetbrains.spek.api.dsl.xdescribe +import org.jetbrains.spek.api.dsl.xgiven +import org.jetbrains.spek.api.dsl.xit +import org.jetbrains.spek.api.dsl.xon import kotlin.test.assertEquals class SkipSampleSpec : Spek({ diff --git a/spek-samples/src/test/kotlin/org/jetbrains/spek/samples/AdvancedCalculatorSpec.kt b/spek-samples/src/test/kotlin/org/jetbrains/spek/samples/subject/AdvancedCalculatorSpec.kt similarity index 52% rename from spek-samples/src/test/kotlin/org/jetbrains/spek/samples/AdvancedCalculatorSpec.kt rename to spek-samples/src/test/kotlin/org/jetbrains/spek/samples/subject/AdvancedCalculatorSpec.kt index ca7f9b1c2..b1617dac9 100644 --- a/spek-samples/src/test/kotlin/org/jetbrains/spek/samples/AdvancedCalculatorSpec.kt +++ b/spek-samples/src/test/kotlin/org/jetbrains/spek/samples/subject/AdvancedCalculatorSpec.kt @@ -1,18 +1,15 @@ -package org.jetbrains.spek.samples +package org.jetbrains.spek.samples.subject -import org.jetbrains.spek.api.SubjectSpek +import org.jetbrains.samples.AdvancedCalculator import org.jetbrains.spek.api.dsl.describe import org.jetbrains.spek.api.dsl.it -import org.jetbrains.spek.api.dsl.itBehavesLike +import org.jetbrains.spek.subject.SubjectSpek +import org.jetbrains.spek.subject.itBehavesLike import kotlin.test.assertEquals -/** - * @author Ranie Jade Ramiso - */ -class AdvancedCalculatorSpec : SubjectSpek({ +object AdvancedCalculatorSpec: SubjectSpek({ subject { AdvancedCalculator() } - - itBehavesLike(CalculatorSpec::class) + itBehavesLike(CalculatorSpec) describe("pow") { it("should return the power of base raise to exponent") { diff --git a/spek-samples/src/test/kotlin/org/jetbrains/spek/samples/CalculatorSpec.kt b/spek-samples/src/test/kotlin/org/jetbrains/spek/samples/subject/CalculatorSpec.kt similarity index 86% rename from spek-samples/src/test/kotlin/org/jetbrains/spek/samples/CalculatorSpec.kt rename to spek-samples/src/test/kotlin/org/jetbrains/spek/samples/subject/CalculatorSpec.kt index 99df23914..60ae9e270 100644 --- a/spek-samples/src/test/kotlin/org/jetbrains/spek/samples/CalculatorSpec.kt +++ b/spek-samples/src/test/kotlin/org/jetbrains/spek/samples/subject/CalculatorSpec.kt @@ -1,14 +1,15 @@ -package org.jetbrains.spek.samples +package org.jetbrains.spek.samples.subject import com.natpryce.hamkrest.assertion.assertThat import com.natpryce.hamkrest.throws -import org.jetbrains.spek.api.SubjectSpek import org.jetbrains.spek.api.dsl.context import org.jetbrains.spek.api.dsl.describe import org.jetbrains.spek.api.dsl.it +import org.jetbrains.samples.Calculator +import org.jetbrains.spek.subject.SubjectSpek import kotlin.test.assertEquals -class CalculatorSpec : SubjectSpek({ +object CalculatorSpec: SubjectSpek({ subject { Calculator() } describe("addition") { diff --git a/spek-subject-extension/build.gradle b/spek-subject-extension/build.gradle new file mode 100644 index 000000000..7ad82e5e9 --- /dev/null +++ b/spek-subject-extension/build.gradle @@ -0,0 +1,34 @@ +apply from: "$rootDir/gradle/common/dependencies.gradle" +apply from: "$rootDir/gradle/common/kotlin.gradle" +apply plugin: 'org.junit.platform.gradle.plugin' +apply plugin: 'org.jetbrains.dokka' + +junitPlatform { + platformVersion '1.0.0-M3' + filters { + engines { + exclude 'spek' + } + } +} + +dependencies { + compile project(':spek-api') + compile 'org.jetbrains.kotlin:kotlin-stdlib' + compile 'org.jetbrains.kotlin:kotlin-reflect' + + testCompile 'org.junit.jupiter:junit-jupiter-api' + testCompile project(':junit-platform-engine-test-support') + + testRuntime 'org.junit.jupiter:junit-jupiter-engine' +} + +task sourceJar(type: Jar) { + from project.sourceSets.main.allSource + classifier "sources" +} + +task javadocJar(type: Jar, dependsOn: dokka) { + from dokka.outputDirectory + classifier = 'javadoc' +} diff --git a/spek-subject-extension/src/main/kotlin/org/jetbrains/spek/subject/Shared.kt b/spek-subject-extension/src/main/kotlin/org/jetbrains/spek/subject/Shared.kt new file mode 100644 index 000000000..fe135115f --- /dev/null +++ b/spek-subject-extension/src/main/kotlin/org/jetbrains/spek/subject/Shared.kt @@ -0,0 +1,36 @@ +package org.jetbrains.spek.subject + +import org.jetbrains.spek.api.Spek +import org.jetbrains.spek.api.dsl.Spec +import org.jetbrains.spek.api.include +import org.jetbrains.spek.api.lifecycle.CachingMode +import org.jetbrains.spek.api.lifecycle.LifecycleAware +import org.jetbrains.spek.meta.Experimental +import org.jetbrains.spek.subject.dsl.SubjectDsl +import org.jetbrains.spek.subject.dsl.SubjectProviderDsl +import kotlin.reflect.KProperty + +@Experimental +infix fun SubjectDsl.itBehavesLike(spec: SubjectSpek) { + include(Spek.wrap { + val value: SubjectProviderDsl = object: SubjectProviderDsl, Spec by this { + val adapter = object: LifecycleAware { + override fun getValue(thisRef: LifecycleAware, property: KProperty<*>): T { + return this() + } + + override fun invoke(): T { + return this@itBehavesLike.subject().invoke() + } + + } + + override fun subject() = adapter + override fun subject(mode: CachingMode, factory: () -> T) = adapter + override val subject: T + get() = adapter() + + } + spec.spec(value) + }) +} diff --git a/spek-subject-extension/src/main/kotlin/org/jetbrains/spek/subject/SubjectSpek.kt b/spek-subject-extension/src/main/kotlin/org/jetbrains/spek/subject/SubjectSpek.kt new file mode 100644 index 000000000..838d57c6e --- /dev/null +++ b/spek-subject-extension/src/main/kotlin/org/jetbrains/spek/subject/SubjectSpek.kt @@ -0,0 +1,14 @@ +package org.jetbrains.spek.subject + +import org.jetbrains.spek.api.Spek +import org.jetbrains.spek.meta.Experimental +import org.jetbrains.spek.subject.core.SubjectProviderDslImpl +import org.jetbrains.spek.subject.dsl.SubjectProviderDsl + +/** + * @author Ranie Jade Ramiso + */ +@Experimental +abstract class SubjectSpek(val subjectSpec: SubjectProviderDsl.() -> Unit): Spek({ + subjectSpec.invoke(SubjectProviderDslImpl(this)) +}) diff --git a/spek-subject-extension/src/main/kotlin/org/jetbrains/spek/subject/core/SubjectDslImpl.kt b/spek-subject-extension/src/main/kotlin/org/jetbrains/spek/subject/core/SubjectDslImpl.kt new file mode 100644 index 000000000..609bf8768 --- /dev/null +++ b/spek-subject-extension/src/main/kotlin/org/jetbrains/spek/subject/core/SubjectDslImpl.kt @@ -0,0 +1,9 @@ +package org.jetbrains.spek.subject.core + +import org.jetbrains.spek.api.dsl.Spec +import org.jetbrains.spek.subject.dsl.SubjectDsl + +/** + * @author Ranie Jade Ramiso + */ +internal abstract class SubjectDslImpl(val root: Spec): SubjectDsl, Spec by root diff --git a/spek-subject-extension/src/main/kotlin/org/jetbrains/spek/subject/core/SubjectProviderDslImpl.kt b/spek-subject-extension/src/main/kotlin/org/jetbrains/spek/subject/core/SubjectProviderDslImpl.kt new file mode 100644 index 000000000..a9dd214ec --- /dev/null +++ b/spek-subject-extension/src/main/kotlin/org/jetbrains/spek/subject/core/SubjectProviderDslImpl.kt @@ -0,0 +1,24 @@ +package org.jetbrains.spek.subject.core + +import org.jetbrains.spek.api.dsl.Spec +import org.jetbrains.spek.api.lifecycle.CachingMode +import org.jetbrains.spek.api.lifecycle.LifecycleAware +import org.jetbrains.spek.subject.dsl.SubjectProviderDsl +import kotlin.properties.Delegates + +/** + * @author Ranie Jade Ramiso + */ +internal class SubjectProviderDslImpl(spec: Spec): SubjectDslImpl(spec), SubjectProviderDsl { + var adapter: LifecycleAware by Delegates.notNull() + override val subject: T + get() = adapter() + + override fun subject(): LifecycleAware = adapter + + override fun subject(mode: CachingMode, factory: () -> T): LifecycleAware { + return memoized(mode, factory).apply { + adapter = this + } + } +} diff --git a/spek-subject-extension/src/main/kotlin/org/jetbrains/spek/subject/dsl/SubjectDsl.kt b/spek-subject-extension/src/main/kotlin/org/jetbrains/spek/subject/dsl/SubjectDsl.kt new file mode 100644 index 000000000..05203d6ed --- /dev/null +++ b/spek-subject-extension/src/main/kotlin/org/jetbrains/spek/subject/dsl/SubjectDsl.kt @@ -0,0 +1,15 @@ +package org.jetbrains.spek.subject.dsl + +import org.jetbrains.spek.api.dsl.Spec +import org.jetbrains.spek.api.lifecycle.LifecycleAware +import org.jetbrains.spek.meta.Experimental + +/** + * @author Ranie Jade Ramiso + */ +@Experimental +interface SubjectDsl: Spec { + val subject: T + + fun subject(): LifecycleAware +} diff --git a/spek-subject-extension/src/main/kotlin/org/jetbrains/spek/subject/dsl/SubjectProviderDsl.kt b/spek-subject-extension/src/main/kotlin/org/jetbrains/spek/subject/dsl/SubjectProviderDsl.kt new file mode 100644 index 000000000..987952dc4 --- /dev/null +++ b/spek-subject-extension/src/main/kotlin/org/jetbrains/spek/subject/dsl/SubjectProviderDsl.kt @@ -0,0 +1,13 @@ +package org.jetbrains.spek.subject.dsl + +import org.jetbrains.spek.api.lifecycle.CachingMode +import org.jetbrains.spek.api.lifecycle.LifecycleAware +import org.jetbrains.spek.meta.Experimental + +/** + * @author Ranie Jade Ramiso + */ +@Experimental +interface SubjectProviderDsl: SubjectDsl { + fun subject(mode: CachingMode = CachingMode.TEST, factory: () -> T): LifecycleAware +}