jvmTest.com.bkahlert.kommons.test.junit.junit.kt Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of kommons-test Show documentation
Show all versions of kommons-test Show documentation
Kommons Test is a Kotlin Multiplatform Library to ease testing.
package com.bkahlert.kommons.test.junit
import io.kotest.assertions.throwables.shouldThrow
import org.junit.jupiter.api.DynamicContainer
import org.junit.jupiter.api.DynamicNode
import org.junit.jupiter.api.DynamicTest
import org.junit.jupiter.api.function.Executable
import java.net.URI
import java.util.stream.Stream
import kotlin.streams.asSequence
import kotlin.streams.asStream
// PROPERTIES
/** The custom test source URI of this [DynamicNode]. */
internal inline val DynamicNode.testSource: URI? get() = testSourceUri.orElse(null)
/** The custom test source URI of this [DynamicNode] as a [String]. */
internal inline val DynamicNode.testSourceString: String? get() = testSource?.toString()
// TRANSFORM
/** Deeply transforms tests in this test hierarchy using the specified [transform]. */
internal fun Stream.transform(transform: (DynamicTest) -> (DynamicTest)): Stream =
asSequence().transform(transform).asStream()
/** Deeply transforms tests in this test hierarchy using the specified [transform]. */
internal fun Iterable.transform(transform: (DynamicTest) -> (DynamicTest)): Iterable =
asSequence().transform(transform).asIterable()
/** Deeply transforms tests in this test hierarchy using the specified [transform]. */
internal fun Sequence.transform(transform: (DynamicTest) -> (DynamicTest)): Sequence =
map { it.transform(transform) }
/** Deeply transforms tests in potential test hierarchy using the specified [transform]. */
internal fun DynamicNode.transform(transform: (DynamicTest) -> (DynamicTest)): DynamicNode = when (this) {
is DynamicContainer -> transform(transform)
is DynamicTest -> transform.invoke(this)
else -> error("Unknown ${DynamicNode::class.simpleName} type ${this::class}")
}
/** Deeply transforms tests in this test container using the specified [transform]. */
internal fun DynamicContainer.transform(transform: (DynamicTest) -> (DynamicTest)): DynamicContainer =
testSourceUri.map { DynamicContainer.dynamicContainer(displayName, it, children.transform(transform)) }
.orElseGet { DynamicContainer.dynamicContainer(displayName, children.transform(transform)) }
/**
* Returns a new [DynamicTest] with
* - its [DynamicTest.displayName] generated by applying the specified [displayName] to the current [DynamicTest.displayName],
* - its [DynamicTest.testSourceUri] generated by applying the specified [testSourceUri] to the current [DynamicTest.testSourceUri],
* - and its [DynamicTest.executable] generated by applying the specified [executable] to the current [DynamicTest.executable]. */
internal fun DynamicTest.transform(
displayName: (String) -> String = { it },
testSourceUri: (URI?) -> URI? = { it },
executable: (() -> Unit) -> Unit = { it() },
): DynamicTest {
val transformedDisplayName = displayName(this.displayName)
val transformedTestSourceUri = this.testSourceUri.map { testSourceUri(it) }.orElseGet { testSourceUri(null) }
val transformedExecutable = Executable { executable { this.executable.execute() } }
return transformedTestSourceUri
?.let { DynamicTest.dynamicTest(transformedDisplayName, it, transformedExecutable) }
?: DynamicTest.dynamicTest(transformedDisplayName, transformedExecutable)
}
internal inline fun DynamicTest.toExceptionExpectingTest(): DynamicTest =
transform(
displayName = { "expect to fail → $it" },
executable = {
shouldThrow { it() }
},
)
// EXECUTE
/** Runs this test. */
internal fun DynamicTest.execute() {
executable.execute()
}
/** Runs all tests in this test hierarchy as a flat sequence of tests. */
internal fun Stream.execute() {
flatten().forEach { test: DynamicTest -> test.execute() }
}
/** Runs all tests in this test hierarchy and returns the messages of failed assertions. */
internal fun Stream.collectingMessagesExecute(): List =
flatten().mapNotNull { test: DynamicTest -> kotlin.runCatching { test.execute() }.exceptionOrNull() }
.map { it.message }
.toList()
// FLATTEN
/** Converts this test hierarchy to a flat sequence of tests. */
private fun Stream.flatten(): Sequence = asSequence().flatten()
/** Converts this test hierarchy to a flat sequence of tests. */
private fun Sequence.flatten(): Sequence = flatMap { it.flatten() }
/** Converts this test hierarchy to a flat sequence of tests. */
private fun DynamicNode.flatten(): Sequence = when (this) {
is DynamicContainer -> flatten()
is DynamicTest -> flatten()
else -> error("Unknown ${DynamicNode::class.simpleName} type ${this::class}")
}
/** Converts this test to a sequence containing this test. */
private fun DynamicTest.flatten(): Sequence = sequenceOf(this)
/** Converts this test container to a flat sequence containing all contained tests. */
private fun DynamicContainer.flatten(): Sequence = children.asSequence().flatten()