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.RandomizedShrinkablesGenerator Maven / Gradle / Ivy
package net.jqwik.engine.properties;
import java.util.*;
import java.util.logging.*;
import java.util.stream.*;
import net.jqwik.api.*;
import net.jqwik.engine.*;
import net.jqwik.engine.properties.arbitraries.*;
import net.jqwik.engine.support.*;
import net.jqwik.engine.support.types.*;
import static java.lang.Math.*;
public class RandomizedShrinkablesGenerator implements ForAllParametersGenerator {
private static final Logger LOG = Logger.getLogger(RandomizedShrinkablesGenerator.class.getName());
public static RandomizedShrinkablesGenerator forParameters(
List parameters,
ArbitraryResolver arbitraryResolver,
Random random,
int genSize,
EdgeCasesMode edgeCasesMode
) {
List> listOfEdgeCases = listOfEdgeCases(parameters, arbitraryResolver, edgeCasesMode, genSize);
int edgeCasesTotal = calculateEdgeCasesTotal(listOfEdgeCases);
logEdgeCasesOutnumberTriesIfApplicable(genSize, edgeCasesTotal);
return new RandomizedShrinkablesGenerator(
randomShrinkablesGenerator(parameters, arbitraryResolver, genSize, edgeCasesMode.activated()),
new EdgeCasesGenerator(listOfEdgeCases),
edgeCasesMode,
edgeCasesTotal,
calculateBaseToEdgeCaseRatio(listOfEdgeCases, genSize),
random.nextLong()
);
}
private static void logEdgeCasesOutnumberTriesIfApplicable(int genSize, int edgeCasesTotal) {
int logEdgeCasesExceedTriesLimit = max(genSize, 100);
if (edgeCasesTotal >= logEdgeCasesExceedTriesLimit && genSize > 1) {
String message = String.format(
"Edge case generation exceeds number of tries. Stopped after %s generated cases.",
edgeCasesTotal
);
LOG.log(Level.INFO, message);
}
}
private static int calculateEdgeCasesTotal(final List> listOfEdgeCases) {
if (listOfEdgeCases.isEmpty()) {
return 0;
}
return listOfEdgeCases.stream().mapToInt(EdgeCases::size).reduce(1, (a, b) -> a * b);
}
private static PurelyRandomShrinkablesGenerator randomShrinkablesGenerator(
List parameters,
ArbitraryResolver arbitraryResolver,
int genSize,
boolean withEdgeCases
) {
List parameterGenerators = parameterGenerators(parameters, arbitraryResolver, genSize, withEdgeCases);
return new PurelyRandomShrinkablesGenerator(parameterGenerators);
}
private static List parameterGenerators(
List parameters,
ArbitraryResolver arbitraryResolver,
int genSize,
boolean withEdgeCases
) {
return parameters.stream()
.map(parameter -> resolveParameter(arbitraryResolver, parameter, genSize, withEdgeCases))
.collect(Collectors.toList());
}
private static List> listOfEdgeCases(
List parameters,
ArbitraryResolver arbitraryResolver,
EdgeCasesMode edgeCasesMode,
int genSize
) {
List> listOfEdgeCases = new ArrayList<>();
if (edgeCasesMode.activated() && !parameters.isEmpty()) {
int maxEdgeCasesNextParameter = genSize;
for (MethodParameter parameter : parameters) {
EdgeCases edgeCases = resolveEdgeCases(arbitraryResolver, parameter, maxEdgeCasesNextParameter);
// If a single parameter has no edge cases the combination of parameters have no edge cases
if (edgeCases.isEmpty()) {
return Collections.emptyList();
}
listOfEdgeCases.add(edgeCases);
maxEdgeCasesNextParameter = calculateNextParamMaxEdgeCases(maxEdgeCasesNextParameter, edgeCases.size());
}
}
return listOfEdgeCases;
}
private static int calculateNextParamMaxEdgeCases(int maxEdgeCases, int baseCasesSize) {
int maxDerivedEdgeCases = Math.max(1, maxEdgeCases / baseCasesSize);
// When in doubt generate a few more edge cases
if (maxEdgeCases % baseCasesSize > 0) {
maxDerivedEdgeCases += 1;
}
return maxDerivedEdgeCases;
}
private static int calculateBaseToEdgeCaseRatio(List> edgeCases, int genSize) {
int countEdgeCases = edgeCases.stream().mapToInt(EdgeCases::size).reduce(1, (a, b) -> max(a * b, 1));
return EdgeCasesGenerator.calculateBaseToEdgeCaseRatio(genSize, countEdgeCases);
}
private static EdgeCases resolveEdgeCases(
ArbitraryResolver arbitraryResolver,
MethodParameter parameter,
int maxEdgeCases
) {
List> edgeCases = resolveArbitraries(arbitraryResolver, parameter)
.stream()
.map(objectArbitrary -> objectArbitrary.edgeCases(maxEdgeCases))
.collect(Collectors.toList());
return EdgeCasesSupport.concat(edgeCases, maxEdgeCases);
}
private static RandomizedParameterGenerator resolveParameter(
ArbitraryResolver arbitraryResolver,
MethodParameter parameter,
int genSize,
boolean withEdgeCases
) {
Set> arbitraries = resolveArbitraries(arbitraryResolver, parameter);
// This logging only makes sense if arbitraries get the capability to describe themselves
// Supplier message = () -> String.format("Parameter %s generated by arbitraries %s", parameter.getRawParameter(), arbitraries);
// LOG.log(Level.INFO, message);
return new RandomizedParameterGenerator(parameter, arbitraries, genSize, withEdgeCases);
}
private static Set> resolveArbitraries(ArbitraryResolver arbitraryResolver, MethodParameter parameter) {
Set> arbitraries =
arbitraryResolver.forParameter(parameter).stream()
.map(Arbitrary::asGeneric)
.collect(Collectors.toSet());
if (arbitraries.isEmpty()) {
throw new CannotFindArbitraryException(TypeUsageImpl.forParameter(parameter), parameter.getAnnotation(ForAll.class));
}
return arbitraries;
}
private final PurelyRandomShrinkablesGenerator randomGenerator;
private final EdgeCasesGenerator edgeCasesGenerator;
private final EdgeCasesMode edgeCasesMode;
private final int edgeCasesTotal;
private final int baseToEdgeCaseRatio;
private final long baseRandomSeed;
private Random random;
private boolean allEdgeCasesGenerated = false;
private int edgeCasesTried = 0;
private RandomizedShrinkablesGenerator(
PurelyRandomShrinkablesGenerator randomGenerator,
EdgeCasesGenerator edgeCasesGenerator,
EdgeCasesMode edgeCasesMode,
int edgeCasesTotal,
int baseToEdgeCaseRatio,
long baseRandomSeed
) {
this.randomGenerator = randomGenerator;
this.edgeCasesGenerator = edgeCasesGenerator;
this.edgeCasesMode = edgeCasesMode;
this.edgeCasesTotal = edgeCasesTotal;
this.baseToEdgeCaseRatio = baseToEdgeCaseRatio;
this.baseRandomSeed = baseRandomSeed;
this.random = SourceOfRandomness.newRandom(baseRandomSeed);
}
@Override
public boolean hasNext() {
// Randomized generation should always be able to generate a next set of values
return true;
}
@Override
public List> next() {
if (!allEdgeCasesGenerated) {
if (edgeCasesMode.generateFirst()) {
if (edgeCasesGenerator.hasNext()) {
edgeCasesTried++;
return edgeCasesGenerator.next();
} else {
allEdgeCasesGenerated = true;
}
}
if (edgeCasesMode.mixIn()) {
if (shouldGenerateEdgeCase(random)) {
if (edgeCasesGenerator.hasNext()) {
edgeCasesTried++;
return edgeCasesGenerator.next();
} else {
allEdgeCasesGenerated = true;
}
}
}
}
return randomGenerator.generateNext(random);
}
@Override
public int edgeCasesTotal() {
return edgeCasesTotal;
}
@Override
public int edgeCasesTried() {
return edgeCasesTried;
}
@Override
public void reset() {
random = SourceOfRandomness.newRandom(baseRandomSeed);
}
private boolean shouldGenerateEdgeCase(Random localRandom) {
return localRandom.nextInt(baseToEdgeCaseRatio + 1) == 0;
}
}