net.jqwik.engine.facades.ArbitrariesFacadeImpl Maven / Gradle / Ivy
package net.jqwik.engine.facades;
import java.util.*;
import java.util.function.*;
import java.util.stream.*;
import net.jqwik.api.*;
import net.jqwik.api.arbitraries.*;
import net.jqwik.api.domains.*;
import net.jqwik.api.providers.*;
import net.jqwik.api.stateful.*;
import net.jqwik.engine.execution.lifecycle.*;
import net.jqwik.engine.properties.*;
import net.jqwik.engine.properties.arbitraries.*;
import net.jqwik.engine.properties.arbitraries.exhaustive.*;
import net.jqwik.engine.properties.arbitraries.randomized.*;
import net.jqwik.engine.properties.stateful.*;
import static net.jqwik.engine.properties.arbitraries.ArbitrariesSupport.*;
/**
* Is loaded through reflection in api module
*/
public class ArbitrariesFacadeImpl extends Arbitraries.ArbitrariesFacade {
@Override
public RandomGenerator randomChoose(List values) {
return RandomGenerators.choose(values);
}
@Override
public EdgeCases edgeCasesChoose(List values, int maxEdgeCases) {
return EdgeCasesSupport.choose(values, maxEdgeCases);
}
@Override
public EdgeCases edgeCasesChoose(char[] characters, int maxEdgeCases) {
List validCharacters = new ArrayList<>(characters.length);
for (char character : characters) {
validCharacters.add(character);
}
return edgeCasesChoose(validCharacters, maxEdgeCases);
}
@Override
public Optional> exhaustiveChoose(List values, long maxNumberOfSamples) {
return ExhaustiveGenerators.choose(values, maxNumberOfSamples);
}
@Override
public RandomGenerator randomChoose(char[] values) {
return RandomGenerators.choose(values);
}
@Override
public Optional> exhaustiveChoose(char[] values, long maxNumberOfSamples) {
return ExhaustiveGenerators.choose(values, maxNumberOfSamples);
}
@Override
public Optional> exhaustiveCreate(Supplier supplier, long maxNumberOfSamples) {
return ExhaustiveGenerators.create(supplier, maxNumberOfSamples);
}
@Override
public Arbitrary just(T value) {
return new Arbitrary() {
// Optimization: just(value).flatMap(mapper) -> mapper(value)
@Override
public Arbitrary flatMap(Function> mapper) {
return mapper.apply(value);
}
// Optimization: just(value).map(mapper) -> just(mapper(value))
@Override
public Arbitrary map(Function mapper) {
return just(mapper.apply(value));
}
@Override
public RandomGenerator generator(int tries) {
return random -> Shrinkable.unshrinkable(value);
}
@Override
public Optional> exhaustive(long maxNumberOfSamples) {
return exhaustiveChoose(Arrays.asList(value), maxNumberOfSamples);
}
@Override
public EdgeCases edgeCases(int maxEdgeCases1) {
return maxEdgeCases1 <= 0
? EdgeCases.none()
: EdgeCases.fromSupplier(() -> Shrinkable.unshrinkable(value));
}
};
}
@Override
public Arbitrary oneOf(Collection> choices) {
return new OneOfArbitrary<>(choices);
}
@Override
public RandomGenerator randomFrequency(List> frequencies) {
return RandomGenerators.frequency(frequencies);
}
@Override
public RandomGenerator> randomShuffle(List values) {
return RandomGenerators.shuffle(values);
}
@Override
public Optional>> exhaustiveShuffle(List values, long maxNumberOfSamples) {
return ExhaustiveGenerators.shuffle(values, maxNumberOfSamples);
}
@Override
public ActionSequenceArbitrary sequences(Arbitrary extends Action> actionArbitrary) {
return new DefaultActionSequenceArbitrary<>(actionArbitrary);
}
@Override
public Arbitrary frequencyOf(List>> frequencies) {
List>> aboveZeroFrequencies =
frequencies.stream().filter(f -> f.get1() > 0).collect(Collectors.toList());
if (aboveZeroFrequencies.size() == 1) {
return aboveZeroFrequencies.get(0).get2();
}
return new FrequencyOfArbitrary<>(aboveZeroFrequencies);
}
@Override
public IntegerArbitrary integers() {
return new DefaultIntegerArbitrary();
}
@Override
public LongArbitrary longs() {
return new DefaultLongArbitrary();
}
@Override
public BigIntegerArbitrary bigIntegers() {
return new DefaultBigIntegerArbitrary();
}
@Override
public FloatArbitrary floats() {
return new DefaultFloatArbitrary();
}
@Override
public BigDecimalArbitrary bigDecimals() {
return new DefaultBigDecimalArbitrary();
}
@Override
public DoubleArbitrary doubles() {
return new DefaultDoubleArbitrary();
}
@Override
public ByteArbitrary bytes() {
return new DefaultByteArbitrary();
}
@Override
public ShortArbitrary shorts() {
return new DefaultShortArbitrary();
}
@Override
public StringArbitrary strings() {
return new DefaultStringArbitrary();
}
@Override
public CharacterArbitrary chars() {
return new DefaultCharacterArbitrary();
}
@Override
public Arbitrary lazy(Supplier> arbitrarySupplier) {
return new LazyArbitrary<>(arbitrarySupplier);
}
@Override
public Arbitrary lazyOf(List>> suppliers) {
int hashIdentifier = calculateIdentifier(suppliers.size());
return LazyOfArbitrary.of(hashIdentifier, suppliers);
}
@Override
public TraverseArbitrary traverse(Class targetType, TraverseArbitrary.Traverser traverser) {
return new DefaultTraverseArbitrary<>(targetType, traverser);
}
/**
* The calculated cash is supposed to be the same for the same callers of Arbitraries.lazyOf()
* This is important to have a single instance of LazyOfArbitrary for the same code.
*/
private static int calculateIdentifier(int numberOfSuppliers) {
try {
throw new RuntimeException();
} catch (RuntimeException rte) {
Optional optionalHash =
Arrays.stream(rte.getStackTrace())
.filter(stackTraceElement -> !stackTraceElement.getClassName().equals(ArbitrariesFacadeImpl.class.getName()))
.filter(stackTraceElement -> !stackTraceElement.getClassName().equals(Arbitraries.class.getName()))
.findFirst()
.map(stackTraceElement -> Objects.hash(
stackTraceElement.getClassName(),
stackTraceElement.getMethodName(),
stackTraceElement.getLineNumber(),
numberOfSuppliers
));
return optionalHash.orElse(0);
}
}
@Override
public Arbitrary defaultFor(Class type, Class>[] typeParameters) {
TypeUsage[] genericTypeParameters =
Arrays.stream(typeParameters)
.map(TypeUsage::of)
.toArray(TypeUsage[]::new);
return defaultFor(TypeUsage.of(type, genericTypeParameters), typeUsage -> {throw new CannotFindArbitraryException(typeUsage);});
}
@SuppressWarnings("unchecked")
@Override
public Arbitrary defaultFor(TypeUsage typeUsage, Function> noDefaultResolver) {
Set> arbitraries = allDefaultsFor(typeUsage, noDefaultResolver);
if (arbitraries.isEmpty()) {
return (Arbitrary) noDefaultResolver.apply(typeUsage);
}
List> arbitrariesList = new ArrayList<>();
arbitraries.forEach(arbitrary -> arbitrariesList.add((Arbitrary extends T>) arbitrary));
return Arbitraries.oneOf(arbitrariesList);
}
@Override
public TypeArbitrary forType(Class targetType) {
return new DefaultTypeArbitrary<>(targetType);
}
@Override
public MapArbitrary maps(Arbitrary keysArbitrary, Arbitrary valuesArbitrary) {
// The map cannot be larger than the max number of possible keys
return new DefaultMapArbitrary<>(keysArbitrary, valuesArbitrary)
.ofMaxSize(maxNumberOfElements(keysArbitrary, RandomGenerators.DEFAULT_COLLECTION_SIZE));
}
@Override
public Arbitrary> entries(Arbitrary keysArbitrary, Arbitrary valuesArbitrary) {
return Combinators.combine(keysArbitrary, valuesArbitrary).as(AbstractMap.SimpleEntry::new);
}
private static Set> allDefaultsFor(TypeUsage typeUsage, Function> noDefaultResolver) {
DomainContext domainContext = CurrentDomainContext.get();
Set> unconfiguredArbitraries = createDefaultArbitraries(typeUsage, noDefaultResolver, domainContext);
return configureDefaultArbitraries(typeUsage, domainContext, unconfiguredArbitraries);
}
private static Set> configureDefaultArbitraries(
TypeUsage typeUsage,
DomainContext domainContext,
Set> unconfiguredArbitraries
) {
RegisteredArbitraryConfigurer defaultArbitraryConfigurer = new RegisteredArbitraryConfigurer(domainContext.getArbitraryConfigurators());
return unconfiguredArbitraries.stream()
.map(arbitrary -> defaultArbitraryConfigurer.configure(arbitrary, typeUsage))
.collect(Collectors.toSet());
}
private static Set> createDefaultArbitraries(
TypeUsage typeUsage,
Function> noDefaultResolver,
DomainContext domainContext
) {
RegisteredArbitraryResolver defaultArbitraryResolver = new RegisteredArbitraryResolver(domainContext.getArbitraryProviders());
ArbitraryProvider.SubtypeProvider subtypeProvider = subtypeUsage -> {
Set> subtypeArbitraries = allDefaultsFor(subtypeUsage, noDefaultResolver);
if (subtypeArbitraries.isEmpty()) {
return Collections.singleton(noDefaultResolver.apply(subtypeUsage));
}
return subtypeArbitraries;
};
return defaultArbitraryResolver.resolve(typeUsage, subtypeProvider);
}
@Override
public Arbitrary recursive(
Supplier> base,
Function, Arbitrary> recur,
int minDepth,
int maxDepth
) {
if (minDepth < 0) {
String message = String.format("minDepth <%s> must be >= 0.", minDepth);
throw new IllegalArgumentException(message);
}
if (minDepth > maxDepth) {
String message = String.format("minDepth <%s> must not be > maxDepth <%s>", minDepth, maxDepth);
throw new IllegalArgumentException(message);
}
Arbitrary depths = Arbitraries.integers().between(minDepth, maxDepth)
.withDistribution(RandomDistribution.uniform())
.edgeCases(c -> c.includeOnly(minDepth, maxDepth));
return depths.flatMap(depth -> recursive(base, recur, depth));
}
private Arbitrary recursive(
Supplier> base,
Function, Arbitrary> recur,
int depth
) {
return new RecursiveArbitrary<>(base, recur, depth);
}
}
© 2015 - 2024 Weber Informatics LLC | Privacy Policy