net.jqwik.api.configurators.ArbitraryConfiguratorBase Maven / Gradle / Ivy
package net.jqwik.api.configurators;
import java.lang.annotation.*;
import java.lang.reflect.*;
import java.util.*;
import java.util.stream.*;
import org.apiguardian.api.*;
import org.junit.platform.commons.support.*;
import net.jqwik.api.*;
import net.jqwik.api.providers.*;
import static org.apiguardian.api.API.Status.*;
import static org.junit.platform.commons.support.ReflectionSupport.*;
/**
* Using this base class is the easiest way to make use of the configuration mechanism
* described in {@linkplain ArbitraryConfigurator}
*
*
* Implementations must be registered in /META-INF/services/net.jqwik.api.configurators.ArbitraryConfigurator
* so that they will be automatically considered for arbitrary configuration.
*
*
* Some examples that come with jqwik:
*
*
* - net.jqwik.engine.properties.configurators.CharsConfigurator
* - net.jqwik.engine.properties.configurators.SizeConfigurator
*
*/
@API(status = MAINTAINED, since = "1.0")
public abstract class ArbitraryConfiguratorBase implements ArbitraryConfigurator {
private final static String CONFIG_METHOD_NAME = "configure";
@Override
public Arbitrary configure(Arbitrary arbitrary, TypeUsage targetType) {
if (!acceptTargetType(targetType)) {
return arbitrary;
}
List annotations = configurationAnnotations(targetType);
for (Annotation annotation : annotations) {
List configurationMethods = findConfigurationMethods(arbitrary, annotation);
for (Method configurationMethod : configurationMethods) {
arbitrary = configureWithMethod(arbitrary, annotation, configurationMethod);
}
}
return arbitrary;
}
/**
* Override if configurator only works for certain types of domain objects
*
* @param targetType The concrete domain type to be generated
*/
protected boolean acceptTargetType(TypeUsage targetType) {
return true;
}
private List configurationAnnotations(TypeUsage parameter) {
return parameter.getAnnotations().stream() //
.filter(annotation -> !annotation.annotationType().equals(ForAll.class)) //
.collect(Collectors.toList());
}
@SuppressWarnings("unchecked")
private Arbitrary configureWithMethod(Arbitrary arbitrary, Annotation annotation, Method configurationMethod) {
Object configurationResult = invokeMethod(configurationMethod, this, arbitrary, annotation);
if (configurationResult == null) {
return arbitrary;
}
if (!(configurationResult instanceof Arbitrary)) {
throw new ArbitraryConfigurationException(configurationMethod);
}
return (Arbitrary) configurationResult;
}
@SuppressWarnings("unchecked")
private List findConfigurationMethods(Arbitrary arbitrary, Annotation annotation) {
Class extends Arbitrary> arbitraryClass = (Class extends Arbitrary>) arbitrary.getClass();
return findMethods(getClass(),
method -> hasCompatibleConfigurationSignature(method, arbitraryClass, annotation), HierarchyTraversalMode.BOTTOM_UP);
}
private static boolean hasCompatibleConfigurationSignature(
Method candidate,
Class extends Arbitrary>> arbitraryClass,
Annotation annotation
) {
if (!CONFIG_METHOD_NAME.equals(candidate.getName())) {
return false;
}
if (!Arbitrary.class.isAssignableFrom(candidate.getReturnType())) {
return false;
}
if (candidate.getParameterCount() != 2) {
return false;
}
if (candidate.getParameterTypes()[1] != annotation.annotationType()) {
return false;
}
Class> upperArbitraryType = candidate.getParameterTypes()[0];
return upperArbitraryType.isAssignableFrom(arbitraryClass);
}
}
© 2015 - 2024 Weber Informatics LLC | Privacy Policy