net.jqwik.engine.properties.arbitraries.MultivalueArbitraryBase Maven / Gradle / Ivy
package net.jqwik.engine.properties.arbitraries;
import java.util.ArrayList;
import java.util.*;
import java.util.function.*;
import net.jqwik.api.*;
import net.jqwik.api.arbitraries.*;
import net.jqwik.engine.properties.*;
import net.jqwik.engine.properties.arbitraries.randomized.*;
import static java.util.Arrays.*;
import static net.jqwik.engine.properties.UniquenessChecker.*;
abstract class MultivalueArbitraryBase extends TypedCloneable implements StreamableArbitrary {
protected Arbitrary elementArbitrary;
protected int minSize = 0;
protected int maxSize = RandomGenerators.DEFAULT_COLLECTION_SIZE;
protected Set> uniquenessExtractors = new HashSet<>();
protected RandomDistribution sizeDistribution = null;
protected MultivalueArbitraryBase(Arbitrary elementArbitrary) {
this.elementArbitrary = elementArbitrary;
}
@Override
public StreamableArbitrary ofMinSize(int minSize) {
if (minSize < 0) {
String message = String.format("minSize (%s) must be between 0 and 2147483647", minSize);
throw new IllegalArgumentException(message);
}
MultivalueArbitraryBase clone = typedClone();
clone.minSize = minSize;
return clone;
}
@Override
public StreamableArbitrary ofMaxSize(int maxSize) {
if (maxSize < 0) {
String message = String.format("maxSize (%s) must be between 0 and 2147483647", maxSize);
throw new IllegalArgumentException(message);
}
if (maxSize < minSize) {
String message = String.format("minSize (%s) must not be larger than maxSize (%s)", minSize, maxSize);
throw new IllegalArgumentException(message);
}
MultivalueArbitraryBase clone = typedClone();
clone.maxSize = maxSize;
return clone;
}
@Override
public StreamableArbitrary withSizeDistribution(RandomDistribution distribution) {
MultivalueArbitraryBase clone = typedClone();
clone.sizeDistribution = distribution;
return clone;
}
@Override
public Arbitrary reduce(R initial, BiFunction accumulator) {
return this.map(streamable -> {
// Couldn't find a way to use Stream.reduce since it requires a combinator
@SuppressWarnings("unchecked")
R[] result = (R[]) new Object[]{initial};
Iterable iterable = toIterable(streamable);
for (T each : iterable) {
result[0] = accumulator.apply(result[0], each);
}
return result[0];
});
}
protected abstract Iterable toIterable(U streamable);
protected StreamableArbitrary uniqueElements(FeatureExtractor by) {
MultivalueArbitraryBase clone = typedClone();
clone.uniquenessExtractors = new HashSet<>(uniquenessExtractors);
clone.uniquenessExtractors.add(by);
return clone;
}
protected RandomGenerator> createListGenerator(int genSize, boolean withEmbeddedEdgeCases) {
RandomGenerator elementGenerator = elementGenerator(elementArbitrary, genSize, withEmbeddedEdgeCases);
return RandomGenerators.list(elementGenerator, minSize, maxSize, genSize, sizeDistribution, uniquenessExtractors);
}
protected RandomGenerator elementGenerator(Arbitrary elementArbitrary, int genSize, boolean withEdgeCases) {
return elementArbitrary.generator(genSize, withEdgeCases);
}
protected > EdgeCases edgeCases(
BiFunction>, Integer, Shrinkable> shrinkableCreator,
int maxEdgeCases
) {
// Optimization. Already handled by EdgeCases.concat(..)
if (maxEdgeCases <= 0) {
return EdgeCases.none();
}
EdgeCases emptyListEdgeCase = (minSize == 0) ? emptyListEdgeCase(shrinkableCreator) : EdgeCases.none();
int effectiveMaxEdgeCases = maxEdgeCases - emptyListEdgeCase.size();
EdgeCases singleElementEdgeCases = (minSize <= 1 && maxSize >= 1)
? fixedSizeEdgeCases(1, shrinkableCreator, effectiveMaxEdgeCases)
: EdgeCases.none();
effectiveMaxEdgeCases = maxEdgeCases - singleElementEdgeCases.size();
EdgeCases fixedSizeEdgeCases = generateFixedSizeEdgeCases()
? fixedSizeEdgeCases(minSize, shrinkableCreator, effectiveMaxEdgeCases)
: EdgeCases.none();
return EdgeCasesSupport.concat(asList(emptyListEdgeCase, singleElementEdgeCases, fixedSizeEdgeCases), maxEdgeCases);
}
private boolean generateFixedSizeEdgeCases() {
return minSize == maxSize && minSize > 1;
}
private > EdgeCases fixedSizeEdgeCases(
final int fixedSize,
final BiFunction>, Integer, Shrinkable> shrinkableCreator,
int maxEdgeCases
) {
return EdgeCasesSupport.mapShrinkable(
elementArbitrary.edgeCases(maxEdgeCases),
shrinkableT -> {
List> elements = new ArrayList<>(Collections.nCopies(fixedSize, shrinkableT));
if (!checkUniquenessOfShrinkables(uniquenessExtractors, elements)) {
return null;
}
return shrinkableCreator.apply(elements, minSize);
}
);
}
private > EdgeCases emptyListEdgeCase(BiFunction>, Integer, Shrinkable> shrinkableCreator) {
return EdgeCases.fromSupplier(
() -> shrinkableCreator.apply(Collections.emptyList(), minSize)
);
}
}
© 2015 - 2024 Weber Informatics LLC | Privacy Policy