All Downloads are FREE. Search and download functionalities are using the official Maven repository.

jvmTest.com.bkahlert.kommons.test.junit.junit.kt Maven / Gradle / Ivy

There is a newer version: 2.8.0
Show newest version
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()




© 2015 - 2024 Weber Informatics LLC | Privacy Policy