main.net.jqwik.kotlin.api.JqwikGlobals.kt Maven / Gradle / Ivy
package net.jqwik.kotlin.api
import kotlinx.coroutines.*
import net.jqwik.api.Arbitraries
import net.jqwik.api.Arbitrary
import net.jqwik.api.Functions
import net.jqwik.api.Tuple
import net.jqwik.api.arbitraries.FunctionArbitrary
import net.jqwik.api.arbitraries.TypeArbitrary
import org.apiguardian.api.API
import kotlin.coroutines.CoroutineContext
import kotlin.coroutines.EmptyCoroutineContext
import kotlin.reflect.KClass
/**
* Function to create an arbitrary for [Pair][Pair].
*/
@API(status = API.Status.EXPERIMENTAL, since = "1.6.0")
fun anyPair(firstArbitrary: Arbitrary, secondArbitrary: Arbitrary) =
combine(firstArbitrary, secondArbitrary) { a, b -> Pair(a, b) }
/**
* Function to create an arbitrary for [Triple][Triple].
*/
@API(status = API.Status.EXPERIMENTAL, since = "1.6.0")
fun anyTriple(firstArbitrary: Arbitrary, secondArbitrary: Arbitrary, thirdArbitrary: Arbitrary) =
combine(firstArbitrary, secondArbitrary, thirdArbitrary) { a, b, c -> Triple(a, b, c) }
/**
* Function to create a [Functions.FunctionWrapper].
*
* This is a Kotlin convenience for [Functions.function] which requires a Java class instead.
*/
@API(status = API.Status.EXPERIMENTAL, since = "1.6.0")
fun anyFunction(kClass: KClass<*>): Functions.FunctionWrapper {
return Functions.function(kClass.java)
}
/**
* Create a [FunctionArbitrary] for Kotlin function without parameters.
*/
@API(status = API.Status.EXPERIMENTAL, since = "1.6.0")
fun anyFunction0(returning: Arbitrary): FunctionArbitrary, out R> {
return anyFunction(Function0::class).returning(returning)
}
/**
* Create a [FunctionArbitrary] for Kotlin function with 1 parameter.
*/
@API(status = API.Status.EXPERIMENTAL, since = "1.6.0")
fun anyFunction1(returning: Arbitrary): FunctionArbitrary, out R> {
return anyFunction(Function1::class).returning(returning)
}
/**
* Create a [FunctionArbitrary] for Kotlin function with 2 parameters.
*/
@API(status = API.Status.EXPERIMENTAL, since = "1.6.0")
fun anyFunction2(returning: Arbitrary): FunctionArbitrary, out R> {
return anyFunction(Function2::class).returning(returning)
}
/**
* Create a [FunctionArbitrary] for Kotlin function with 3 parameters.
*/
@API(status = API.Status.EXPERIMENTAL, since = "1.6.0")
fun anyFunction3(returning: Arbitrary): FunctionArbitrary, out R> {
return anyFunction(Function3::class).returning(returning)
}
/**
* Create a [FunctionArbitrary] for Kotlin function with 4 parameters.
*/
@API(status = API.Status.EXPERIMENTAL, since = "1.6.0")
fun anyFunction4(returning: Arbitrary): FunctionArbitrary, out R> {
return anyFunction(Function4::class).returning(returning)
}
/**
* Wrap a property so that it can use asynchronous functions within.
*
* @param block Code block that should return a [Boolean] or [Unit].
*/
@API(status = API.Status.EXPERIMENTAL, since = "1.6.0")
fun runBlockingProperty(
context: CoroutineContext = EmptyCoroutineContext,
block: suspend CoroutineScope.() -> T
): T {
return runBlocking(context, block)
}
/**
* Function to create a [TypeArbitrary].
*
* This is a Kotlin convenience for [Arbitraries.forType] which requires a Java class instead.
*/
@API(status = API.Status.EXPERIMENTAL, since = "1.6.0")
inline fun anyForType(): TypeArbitrary
where T : Any {
return Arbitraries.forType(T::class.java)
}
/**
* Creates [Arbitrary] with subtypes of a sealed class or interface [T].
* If a subtype is a sealed class or interface, its subtypes are used to create [Arbitrary]. This is done recursively.
* [TypeArbitrary] are created by default under the hood, but this can be customized, for each subtype, with [SubtypeScope.provide] .
* ```kotlin
* anyForSubtypeOf {
* provide { customArbitrary1() }
* provide { customArbitrary2() }
* }
* ```
* @param enableArbitraryRecursion is applied to all created [TypeArbitrary].
*/
@API(status = API.Status.EXPERIMENTAL, since = "1.8.4")
inline fun anyForSubtypeOf(
enableArbitraryRecursion: Boolean = false,
crossinline subtypeScope: SubtypeScope.() -> Unit = {}
): Arbitrary where T : Any {
val scope = SubtypeScope().apply(subtypeScope)
return Arbitraries.of(T::class.allSealedSubclasses).flatMap {
scope.getProviderFor(it)
?: Arbitraries.forType(it.java).run {
if (enableArbitraryRecursion) {
enableRecursion()
} else {
this
}
}
}.map { obj -> obj }
}
/**
* Function to create arbitrary that generates one of the provided values with a given frequency.
*
* This is a Kotlin convenience for [Arbitraries.frequency] which takes [Pair]s instead of jqwik tuples.
*/
@Suppress("NULLABILITY_MISMATCH_BASED_ON_JAVA_ANNOTATIONS")
@API(status = API.Status.EXPERIMENTAL, since = "1.6.2")
fun frequency(vararg frequencies: Pair): Arbitrary {
val listOfFrequencies: List> = frequencies
.map { pair -> Tuple.of(pair.first, pair.second) }
.toList()
return Arbitraries.frequency(listOfFrequencies) as Arbitrary
}
/**
* Function to choose from one of the provided arbitraries with a given frequency.
*
* This is a Kotlin convenience for [Arbitraries.frequencyOf] which takes [Pair]s instead of jqwik tuples.
*/
@API(status = API.Status.EXPERIMENTAL, since = "1.6.2")
fun frequencyOf(vararg frequencies: Pair>): Arbitrary {
val listOfFrequencies: List>> = frequencies
.map { pair -> Tuple.of(pair.first, pair.second) }
.toList()
return Arbitraries.frequencyOf(listOfFrequencies) as Arbitrary
}