main.net.jqwik.kotlin.internal.KotlinUniqueElementsConfigurator.kt Maven / Gradle / Ivy
package net.jqwik.kotlin.internal
import net.jqwik.api.Arbitrary
import net.jqwik.api.configurators.ArbitraryConfigurator
import net.jqwik.api.constraints.UniqueElements
import net.jqwik.api.constraints.UniqueElements.NOT_SET
import net.jqwik.api.facades.ReflectionSupportFacade
import net.jqwik.api.providers.TypeUsage
import net.jqwik.kotlin.api.SequenceArbitrary
import net.jqwik.kotlin.api.isAssignableFrom
import java.util.function.Function
class KotlinUniqueElementsConfigurator : ArbitraryConfigurator {
@Suppress("UNCHECKED_CAST", "WRONG_NULLABILITY_FOR_JAVA_OVERRIDE")
override fun configure(arbitrary: Arbitrary, targetType: TypeUsage): Arbitrary {
return targetType.findAnnotation(UniqueElements::class.java).map { uniqueness ->
return@map when {
arbitrary is SequenceArbitrary<*> -> configureSequenceArbitrary(arbitrary, uniqueness)
targetType.isAssignableFrom(Sequence::class) -> {
val sequenceArbitrary = arbitrary as Arbitrary>
sequenceArbitrary.filter {
isUnique(
it.toList(),
extractor(uniqueness) as Function
)
}
}
else -> arbitrary
} as Arbitrary
}.orElse(arbitrary)
}
private fun isUnique(list: Collection<*>, extractor: Function): Boolean {
val set = list.map { extractor.apply(it) }.toSet()
return set.size == list.size
}
@Suppress("UNCHECKED_CAST")
private fun configureSequenceArbitrary(
arbitrary: SequenceArbitrary,
uniqueness: UniqueElements
): SequenceArbitrary {
val extractor = extractor(uniqueness) as Function
return arbitrary.uniqueElements(extractor)
}
private fun extractor(uniqueElements: UniqueElements): Function<*, *> {
val extractorClass: Class> = uniqueElements.by.java
return if (extractorClass == NOT_SET::class.java) Function.identity()
// TODO: Create instance in context of test instance.
// This requires an extension of ArbitraryConfiguration interface
// to provide access to PropertyLifecycleContext
else ReflectionSupportFacade.implementation.newInstanceWithDefaultConstructor(extractorClass)
}
}