All Downloads are FREE. Search and download functionalities are using the official Maven repository.
Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
net.jqwik.engine.properties.ProviderMethod Maven / Gradle / Ivy
package net.jqwik.engine.properties;
import java.lang.reflect.*;
import java.util.*;
import java.util.function.*;
import net.jqwik.api.*;
import net.jqwik.api.providers.*;
import net.jqwik.api.providers.ArbitraryProvider.*;
import net.jqwik.api.support.*;
import net.jqwik.engine.support.*;
import net.jqwik.engine.support.types.*;
import static net.jqwik.engine.support.JqwikReflectionSupport.*;
import static net.jqwik.engine.support.OverriddenMethodAnnotationSupport.*;
class ProviderMethod {
@SuppressWarnings("unchecked")
static ProviderMethod forMethod(
Method method,
TypeUsage targetType,
List instances,
ArbitraryProvider.SubtypeProvider subtypeProvider
) {
Class extends Throwable>[] ignoreExceptions = findDeclaredOrInheritedAnnotation(method, Provide.class)
.map(Provide::ignoreExceptions)
.orElse(new Class[0]);
return new ProviderMethod(method, targetType, instances, subtypeProvider, ignoreExceptions);
}
private final Class extends Throwable>[] ignoreExceptions;
private ProviderMethod(
Method underlyingMethod, TypeUsage targetType, List instances, SubtypeProvider subtypeProvider,
Class extends Throwable>[] ignoreExceptions
) {
this.method = underlyingMethod;
this.targetType = targetType;
this.instances = instances;
this.subtypeProvider = subtypeProvider;
this.ignoreExceptions = ignoreExceptions;
}
private final Method method;
private final TypeUsage targetType;
private final List instances;
private final SubtypeProvider subtypeProvider;
Set> invoke() {
Class> containerClass = contextInstance().getClass();
List parameters = JqwikReflectionSupport.getMethodParameters(method, containerClass);
Set, Arbitrary>>> baseInvoker = Collections.singleton(this::invokeProviderMethod);
Set>> suppliers = arbitrarySuppliers(baseInvoker, parameters, Collections.emptyList());
return mapSet(suppliers, arbitrarySupplier -> arbitrarySupplier.get().ignoreExceptions(ignoreExceptions));
}
private Object contextInstance() {
return instances.get(instances.size() - 1);
}
private Arbitrary> invokeProviderMethod(List argList) {
return (Arbitrary>) invokeMethodOnContainer(method, instances, argList.toArray());
}
private Set>> arbitrarySuppliers(
Set, Arbitrary>>> invokers,
List unresolvedParameters,
List args
) {
if (unresolvedParameters.isEmpty()) {
return mapSet(invokers, invoker -> () -> invoker.apply(args));
}
List newUnresolvedParameters = new ArrayList<>(unresolvedParameters);
MethodParameter toResolve = newUnresolvedParameters.remove(0);
if (isForAllParameter(toResolve)) {
List newArgs = new ArrayList<>(args);
newArgs.add(arbitraryFor(toResolve)); // Arbitrary is now in position toResolve.getIndex()
Set, Arbitrary>>> newInvokers = flatMapArbitraryInInvocations(invokers, toResolve.getIndex());
return arbitrarySuppliers(newInvokers, newUnresolvedParameters, newArgs);
} else {
List newArgs = new ArrayList<>(args);
newArgs.add(resolvePlainParameter(toResolve.getRawParameter()));
return arbitrarySuppliers(invokers, newUnresolvedParameters, newArgs);
}
}
private Set, Arbitrary>>> flatMapArbitraryInInvocations(
Set, Arbitrary>>> invokers,
int position
) {
Function, Arbitrary>>, Function, Arbitrary>>> mapper = invoker -> arguments -> {
Arbitrary> a = (Arbitrary>) arguments.get(position);
return a.flatMap(argument -> {
List resolved = new ArrayList<>(arguments);
resolved.set(position, argument);
return invoker.apply(resolved);
});
};
return mapSet(invokers, mapper);
}
private Arbitrary> arbitraryFor(MethodParameter toResolve) {
TypeUsage parameterType = TypeUsageImpl.forParameter(toResolve);
Optional> optionalArbitrary = subtypeProvider.provideOneFor(parameterType);
return optionalArbitrary.orElseThrow(
() ->
new CannotFindArbitraryException(
parameterType,
parameterType.findAnnotation(ForAll.class).orElse(null),
method
)
);
}
private Set mapSet(Set invokers, Function mapper) {
return invokers.stream().map(mapper).collect(CollectorsSupport.toLinkedHashSet());
}
private boolean isForAllParameter(MethodParameter parameter) {
return parameter.isAnnotated(ForAll.class);
}
protected Object resolvePlainParameter(Parameter parameter) {
if (parameter.getType().isAssignableFrom(TypeUsage.class)) {
return targetType;
} else {
String message = String.format(
"Parameter [%s] cannot be resolved in @Provide method [%s]." +
"%nMaybe you want to add annotation `@ForAll`?",
parameter,
method
);
throw new JqwikException(message);
}
}
}