Skip to content

Commit

Permalink
Use test instances to invoke arbitrary provider methods
Browse files Browse the repository at this point in the history
  • Loading branch information
jlink committed Nov 11, 2023
1 parent e0120bc commit 645ad7b
Show file tree
Hide file tree
Showing 9 changed files with 49 additions and 47 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ public CheckedProperty fromDescriptor(
List<MethodParameter> propertyParameters = extractParameters(propertyMethod, propertyMethodDescriptor.getContainerClass());

PropertyMethodArbitraryResolver arbitraryResolver = new PropertyMethodArbitraryResolver(
propertyLifecycleContext.testInstance(),
propertyLifecycleContext.testInstances(),
CurrentDomainContext.get()
);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,9 @@
import net.jqwik.api.providers.ArbitraryProvider.*;
import net.jqwik.engine.support.*;

import static java.util.Collections.*;

import static net.jqwik.engine.support.JqwikReflectionSupport.*;
import static net.jqwik.engine.support.OverriddenMethodAnnotationSupport.*;

public class DomainContextBaseProviders {

Expand Down Expand Up @@ -146,7 +147,7 @@ private static class DomainContextBaseSubtypeProvider extends InstanceBasedSubty
private final SubtypeProvider baseProvider;

protected DomainContextBaseSubtypeProvider(Object base, SubtypeProvider baseProvider) {
super(base);
super(Collections.singletonList(base));
this.baseProvider = baseProvider;
}

Expand Down Expand Up @@ -182,7 +183,7 @@ public boolean canProvideFor(TypeUsage targetType) {
@Override
public Set<Arbitrary<?>> provideFor(TypeUsage targetType, SubtypeProvider subtypeProvider) {
SubtypeProvider domainSubtypeProvider = new net.jqwik.engine.properties.DomainContextBaseProviders.DomainContextBaseSubtypeProvider(base, subtypeProvider);
return ProviderMethod.forMethod(method, targetType, base, domainSubtypeProvider).invoke();
return ProviderMethod.forMethod(method, targetType, singletonList(base), domainSubtypeProvider).invoke();
}

@Override
Expand Down
Original file line number Diff line number Diff line change
@@ -1,29 +1,23 @@
package net.jqwik.engine.properties;

import java.lang.reflect.*;
import java.util.*;
import java.util.function.*;
import java.util.stream.*;

import net.jqwik.api.*;
import net.jqwik.api.providers.ArbitraryProvider;
import net.jqwik.api.providers.TypeUsage;
import net.jqwik.api.stateful.ActionSequence;
import net.jqwik.api.support.CollectorsSupport;

import java.lang.reflect.Method;
import java.util.Collections;
import java.util.Objects;
import java.util.Optional;
import java.util.Set;
import java.util.function.Function;
import java.util.stream.Stream;

import static net.jqwik.engine.support.JqwikReflectionSupport.findGeneratorMethod;
import static net.jqwik.engine.support.JqwikReflectionSupport.newInstanceInTestContext;
import static net.jqwik.engine.support.OverriddenMethodAnnotationSupport.findDeclaredOrInheritedAnnotation;
import net.jqwik.api.providers.*;
import net.jqwik.api.support.*;

import static net.jqwik.engine.support.JqwikReflectionSupport.*;
import static net.jqwik.engine.support.OverriddenMethodAnnotationSupport.*;

abstract class InstanceBasedSubtypeProvider implements ArbitraryProvider.SubtypeProvider {

private final Object instance;
private final List<Object> instances;

protected InstanceBasedSubtypeProvider(Object instance) {
this.instance = instance;
protected InstanceBasedSubtypeProvider(List<Object> instances) {
this.instances = instances;
}

@Override
Expand Down Expand Up @@ -85,7 +79,7 @@ private Set<Arbitrary<?>> resolveFromSupplier(
) {
Class<? extends ArbitrarySupplier<?>> supplierClass =
optionalForAllSupplier.orElseGet(() -> optionalFromSupplier.orElseThrow(() -> new JqwikException("Should never happen")));
ArbitrarySupplier<?> supplier = newInstanceInTestContext(supplierClass, instance);
ArbitrarySupplier<?> supplier = newInstanceInTestContext(supplierClass, contextInstance());
Arbitrary<?> arbitrary = supplier.supplyFor(targetType);
if (arbitrary == null) {
String message = String.format(
Expand All @@ -98,14 +92,18 @@ private Set<Arbitrary<?>> resolveFromSupplier(
return Collections.singleton(arbitrary);
}

private Object contextInstance() {
return instances.get(instances.size() - 1);
}

private Set<Arbitrary<?>> resolveFromGeneratorName(
TypeUsage targetType,
Optional<String> optionalForAllValue,
Optional<String> optionalFromValue
) {
String generatorName = optionalForAllValue.orElseGet(() -> optionalFromValue.orElseThrow(() -> new JqwikException("Should never happen")));
return findProviderMethodByName(generatorName, targetType)
.map(method -> ProviderMethod.forMethod(method, targetType, instance, this).invoke())
.map(method -> ProviderMethod.forMethod(method, targetType, instances, this).invoke())
.orElse(Collections.emptySet());
}

Expand Down Expand Up @@ -133,7 +131,7 @@ private Optional<Method> findProviderMethodByName(String generatorToFind, TypeUs
effectiveTargetType
);

return findGeneratorMethod(generatorToFind, this.instance.getClass(), Provide.class, generatorNameSupplier, expectedReturnType);
return findGeneratorMethod(generatorToFind, contextInstance().getClass(), Provide.class, generatorNameSupplier, expectedReturnType);
}

protected abstract Set<Arbitrary<?>> resolve(TypeUsage parameterType);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,20 +13,20 @@ public class PropertyMethodArbitraryResolver extends InstanceBasedSubtypeProvide
private final RegisteredArbitraryResolver registeredArbitraryResolver;
private final RegisteredArbitraryConfigurer registeredArbitraryConfigurer;

public PropertyMethodArbitraryResolver(Object testInstance, DomainContext domainContext) {
public PropertyMethodArbitraryResolver(List<Object> testInstances, DomainContext domainContext) {
this(
testInstance,
testInstances,
new RegisteredArbitraryResolver(domainContext.getArbitraryProviders()),
new RegisteredArbitraryConfigurer(domainContext.getArbitraryConfigurators())
);
}

PropertyMethodArbitraryResolver(
Object testInstance,
List<Object> testInstances,
RegisteredArbitraryResolver registeredArbitraryResolver,
RegisteredArbitraryConfigurer registeredArbitraryConfigurer
) {
super(testInstance);
super(testInstances);
this.registeredArbitraryResolver = registeredArbitraryResolver;
this.registeredArbitraryConfigurer = registeredArbitraryConfigurer;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,43 +20,47 @@ class ProviderMethod {
static ProviderMethod forMethod(
Method method,
TypeUsage targetType,
Object instance,
List<Object> instances,
ArbitraryProvider.SubtypeProvider subtypeProvider
) {
Class<? extends Throwable>[] ignoreExceptions = findDeclaredOrInheritedAnnotation(method, Provide.class)
.map(Provide::ignoreExceptions)
.orElse(new Class[0]);
return new ProviderMethod(method, targetType, instance, subtypeProvider, ignoreExceptions);
return new ProviderMethod(method, targetType, instances, subtypeProvider, ignoreExceptions);
}

private final Class<? extends Throwable>[] ignoreExceptions;

private ProviderMethod(
Method underlyingMethod, TypeUsage targetType, Object instance, SubtypeProvider subtypeProvider,
Method underlyingMethod, TypeUsage targetType, List<Object> instances, SubtypeProvider subtypeProvider,
Class<? extends Throwable>[] ignoreExceptions
) {
this.method = underlyingMethod;
this.targetType = targetType;
this.instance = instance;
this.instances = instances;
this.subtypeProvider = subtypeProvider;
this.ignoreExceptions = ignoreExceptions;
}

private final Method method;
private final TypeUsage targetType;
private final Object instance;
private final List<Object> instances;
private final SubtypeProvider subtypeProvider;

Set<Arbitrary<?>> invoke() {
List<MethodParameter> parameters = JqwikReflectionSupport.getMethodParameters(method, instance.getClass());
Class<?> containerClass = contextInstance().getClass();
List<MethodParameter> parameters = JqwikReflectionSupport.getMethodParameters(method, containerClass);
Set<Function<List<Object>, Arbitrary<?>>> baseInvoker = Collections.singleton(this::invokeProviderMethod);
Set<Supplier<Arbitrary<?>>> 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<Object> argList) {
// TODO: Hand in all test instances instead of just target
return (Arbitrary<?>) invokeMethodPotentiallyOuter(method, instance, argList.toArray());
return (Arbitrary<?>) invokeMethodOnContainer(method, instances, argList.toArray());
}

private Set<Supplier<Arbitrary<?>>> arbitrarySuppliers(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,6 @@ public static List<Object> newInstancesWithDefaultConstructor(Class<?> clazz) {
* @param context The potential context instance
* @return the newly created instance
*/
// TODO: Require all instances to be passed in instead of just the most inner one
public static <T> T newInstanceInTestContext(Class<T> clazz, Object context) {
if (!isInnerClass(clazz)) {
return ReflectionSupport.newInstance(clazz);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ void noExhaustiveGenerator() {

private ExhaustiveShrinkablesGenerator createGenerator(String methodName) {
PropertyMethodArbitraryResolver arbitraryResolver = new PropertyMethodArbitraryResolver(
new MyProperties(),
asList(new MyProperties()),
DomainContext.global()
);
return createGenerator(methodName, arbitraryResolver);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ void useNextRegisteredProviderIfFirstDoesNotProvideAnArbitrary() {
createProvider(String.class, secondArbitrary)
);
PropertyMethodArbitraryResolver resolver = new PropertyMethodArbitraryResolver(
new DefaultParams(),
asList(new DefaultParams()),
new RegisteredArbitraryResolver(registeredProviders),
new RegisteredArbitraryConfigurer(Collections.emptyList())
);
Expand All @@ -83,7 +83,7 @@ void resolveSeveralFittingArbitraries() {
createProvider(String.class, thirdFit)
);
PropertyMethodArbitraryResolver resolver = new PropertyMethodArbitraryResolver(
new DefaultParams(),
asList(new DefaultParams()),
new RegisteredArbitraryResolver(registeredProviders),
new RegisteredArbitraryConfigurer(Collections.emptyList())
);
Expand All @@ -109,7 +109,7 @@ public Arbitrary<?> configure(Arbitrary<?> arbitrary, TypeUsage targetType) {
createProvider(String.class, secondFit)
);
PropertyMethodArbitraryResolver resolver = new PropertyMethodArbitraryResolver(
new DefaultParams(),
asList(new DefaultParams()),
new RegisteredArbitraryResolver(registeredProviders),
configurer
);
Expand Down Expand Up @@ -143,7 +143,7 @@ public Arbitrary<?> configure(Arbitrary<?> arbitrary, TypeUsage targetType) {
);

PropertyMethodArbitraryResolver resolver = new PropertyMethodArbitraryResolver(
new DefaultParams(),
asList(new DefaultParams()),
new RegisteredArbitraryResolver(registeredProviders),
configurer
);
Expand Down Expand Up @@ -293,7 +293,7 @@ public Arbitrary<?> configure(Arbitrary<?> arbitrary, TypeUsage targetType) {
};

PropertyMethodArbitraryResolver provider = new PropertyMethodArbitraryResolver(
new WithNamedProviders(),
asList(new WithNamedProviders()),
new RegisteredArbitraryResolver(Collections.emptyList()),
configurer
);
Expand Down Expand Up @@ -546,7 +546,7 @@ Arbitrary<Integer> integerDivisibleBy3() {

private static PropertyMethodArbitraryResolver getResolver(Class<?> container) {
return new PropertyMethodArbitraryResolver(
JqwikReflectionSupport.newInstanceWithDefaultConstructor(container),
JqwikReflectionSupport.newInstancesWithDefaultConstructor(container),
DomainContext.global()
);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -142,7 +142,7 @@ private List<Object> values(List<Shrinkable<Object>> shrinkables) {

private RandomizedShrinkablesGenerator createGenerator(Random random, String methodName) {
PropertyMethodArbitraryResolver arbitraryResolver = new PropertyMethodArbitraryResolver(
new MyProperties(),
asList(new MyProperties()),
DomainContext.global()
);
return createGenerator(random, methodName, arbitraryResolver);
Expand Down

0 comments on commit 645ad7b

Please sign in to comment.