net.jqwik.engine.properties.arbitraries.randomized.RandomGenerators Maven / Gradle / Ivy
package net.jqwik.engine.properties.arbitraries.randomized;
import java.math.*;
import java.util.*;
import java.util.concurrent.atomic.*;
import java.util.function.*;
import net.jqwik.api.*;
import net.jqwik.engine.properties.arbitraries.*;
import net.jqwik.engine.properties.shrinking.*;
public class RandomGenerators {
public static final int DEFAULT_COLLECTION_SIZE = 255;
public static RandomGenerator choose(List values) {
if (values.size() == 0) {
return fail("empty set of values");
}
return random -> {
U value = chooseValue(values, random);
return new ChooseValueShrinkable<>(value, values);
};
}
private static U chooseValue(List values, Random random) {
int index = random.nextInt(values.size());
return values.get(index);
}
public static RandomGenerator choose(U[] values) {
return choose(Arrays.asList(values));
}
public static > RandomGenerator choose(Class enumClass) {
return choose(enumClass.getEnumConstants());
}
public static RandomGenerator choose(char[] characters) {
List validCharacters = new ArrayList<>(characters.length);
for (char character : characters) {
validCharacters.add(character);
}
return choose(validCharacters);
}
public static RandomGenerator chars(char min, char max) {
return integers(min, max).map(anInt -> ((char) (int) anInt));
}
public static RandomGenerator bytes(byte min, byte max) {
BigInteger min1 = BigInteger.valueOf(min);
BigInteger max1 = BigInteger.valueOf(max);
return bigIntegers(min1, max1, defaultShrinkingTargetCalculator(min1, max1)).map(BigInteger::byteValueExact);
}
public static RandomGenerator shorts(short min, short max) {
BigInteger min1 = BigInteger.valueOf(min);
BigInteger max1 = BigInteger.valueOf(max);
return bigIntegers(min1, max1, defaultShrinkingTargetCalculator(min1, max1)).map(BigInteger::shortValueExact);
}
public static RandomGenerator integers(int min, int max) {
BigInteger min1 = BigInteger.valueOf(min);
BigInteger max1 = BigInteger.valueOf(max);
return bigIntegers(min1, max1, defaultShrinkingTargetCalculator(min1, max1)).map(BigInteger::intValueExact);
}
public static RandomGenerator longs(long min, long max) {
BigInteger min1 = BigInteger.valueOf(min);
BigInteger max1 = BigInteger.valueOf(max);
return bigIntegers(min1, max1, defaultShrinkingTargetCalculator(min1, max1)).map(BigInteger::longValueExact);
}
public static RandomGenerator bigIntegers(
BigInteger min,
BigInteger max,
Function shrinkingTargetCalculator,
BigInteger... partitionPoints
) {
Range range = Range.of(min, max);
return RandomIntegralGenerators.bigIntegers(range, partitionPoints, shrinkingTargetCalculator);
}
public static RandomGenerator doubles(double min, double max, int scale) {
return bigDecimals(BigDecimal.valueOf(min), BigDecimal.valueOf(max), scale).map(BigDecimal::doubleValue);
}
public static RandomGenerator floats(float min, float max, int scale) {
return bigDecimals(BigDecimal.valueOf((double) min), BigDecimal.valueOf((double) max), scale).map(BigDecimal::floatValue);
}
public static RandomGenerator bigDecimals(BigDecimal min, BigDecimal max, int scale, BigDecimal... partitionPoints) {
return RandomDecimalGenerators.bigDecimals(Range.of(min, max), scale, partitionPoints);
}
public static RandomGenerator> list(RandomGenerator elementGenerator, int minSize, int maxSize) {
int defaultCutoff = defaultCutoffSize(minSize, maxSize);
return list(elementGenerator, minSize, maxSize, defaultCutoff);
}
public static RandomGenerator> list(
RandomGenerator elementGenerator, int minSize, int maxSize, int cutoffSize
) {
Function>, Shrinkable>> createShrinkable = elements -> new ShrinkableList<>(elements, minSize);
return container(elementGenerator, createShrinkable, minSize, maxSize, cutoffSize);
}
public static RandomGenerator oneOf(List> all) {
return choose(all).flatMap(Function.identity());
}
public static RandomGenerator> shuffle(List values) {
return random -> {
List clone = new ArrayList<>(values);
Collections.shuffle(clone, random);
return Shrinkable.unshrinkable(clone);
};
}
public static RandomGenerator strings(
RandomGenerator elementGenerator, int minLength, int maxLength, int cutoffLength
) {
Function>, Shrinkable> createShrinkable = elements -> new ShrinkableString(elements, minLength);
return container(elementGenerator, createShrinkable, minLength, maxLength, cutoffLength);
}
public static RandomGenerator strings(
RandomGenerator elementGenerator, int minLength, int maxLength
) {
int defaultCutoff = defaultCutoffSize(minLength, maxLength);
return strings(elementGenerator, minLength, maxLength, defaultCutoff);
}
private static int defaultCutoffSize(int minSize, int maxSize) {
int range = maxSize - minSize;
int offset = (int) Math.max(Math.round(Math.sqrt(100)), 10);
if (range <= offset)
return maxSize;
return Math.min(offset + minSize, maxSize);
}
private static RandomGenerator container(
RandomGenerator elementGenerator, //
Function>, Shrinkable> createShrinkable,//
int minSize, int maxSize, int cutoffSize
) {
Function sizeGenerator = sizeGenerator(minSize, maxSize, cutoffSize);
return new ContainerGenerator<>(elementGenerator, createShrinkable, sizeGenerator);
}
private static Function sizeGenerator(int minSize, int maxSize, int cutoffSize) {
if (cutoffSize >= maxSize)
return random -> randomSize(random, minSize, maxSize);
// Choose size below cutoffSize with probability of 0.9
return random -> {
if (random.nextDouble() > 0.1)
return randomSize(random, minSize, cutoffSize);
else
return randomSize(random, cutoffSize + 1, maxSize);
};
}
private static int randomSize(Random random, int minSize, int maxSize) {
int range = maxSize - minSize;
return random.nextInt(range + 1) + minSize;
}
public static RandomGenerator> set(RandomGenerator elementGenerator, int minSize, int maxSize) {
int defaultCutoffSize = defaultCutoffSize(minSize, maxSize);
return set(elementGenerator, minSize, maxSize, defaultCutoffSize);
}
public static RandomGenerator> set(
RandomGenerator elementGenerator, int minSize, int maxSize, int cutoffSize
) {
Function sizeGenerator = sizeGenerator(minSize, maxSize, cutoffSize);
return random -> {
int listSize = sizeGenerator.apply(random);
Set> elements = new HashSet<>();
Set values = new HashSet<>();
while (elements.size() < listSize) {
Shrinkable next = elementGenerator.next(random);
if (values.contains(next.value()))
continue;
elements.add(next);
values.add(next.value());
}
return new ShrinkableSet<>(elements, minSize);
};
}
public static RandomGenerator chooseShrinkable(List> shrinkables) {
if (shrinkables.size() == 0) {
return fail("empty set of shrinkables");
}
return random -> chooseValue(shrinkables, random);
}
public static RandomGenerator samplesFromShrinkables(List> samples) {
AtomicInteger tryCount = new AtomicInteger(0);
return ignored -> {
if (tryCount.get() >= samples.size())
tryCount.set(0);
return samples.get(tryCount.getAndIncrement());
};
}
public static RandomGenerator samples(T[] samples) {
List> shrinkables = SampleShrinkable.listOf(samples);
return samplesFromShrinkables(shrinkables);
}
public static RandomGenerator frequency(List> frequencies) {
return new FrequencyGenerator<>(frequencies);
}
public static RandomGenerator withEdgeCases(RandomGenerator self, int genSize, List> edgeCases) {
if (edgeCases.isEmpty()) {
return self;
}
int baseToEdgeCaseRatio =
Math.min(
Math.max(Math.round(genSize / 5), 1),
100 / edgeCases.size()
) + 1;
RandomGenerator edgeCasesGenerator = RandomGenerators.chooseShrinkable(edgeCases);
return random -> {
if (random.nextInt(baseToEdgeCaseRatio) == 0) {
return edgeCasesGenerator.next(random);
} else {
return self.next(random);
}
};
}
public static RandomGenerator fail(String message) {
return ignored -> {
throw new JqwikException(message);
};
}
public static int defaultCutoffSize(int minSize, int maxSize, int genSize) {
int range = maxSize - minSize;
int offset = (int) Math.max(Math.round(Math.sqrt(genSize)), 10);
if (range <= offset)
return maxSize;
return Math.min(offset + minSize, maxSize);
}
public static Function defaultShrinkingTargetCalculator(BigInteger min, BigInteger max) {
return value -> ShrinkableBigInteger.defaultShrinkingTarget(value, Range.of(min, max));
}
// TODO: This could be way more sophisticated
public static BigInteger[] calculateDefaultPartitionPoints(int tries, BigInteger min, BigInteger max) {
int partitionPoint = Math.max(tries / 2, 10);
BigInteger upperPartitionPoint = BigInteger.valueOf(partitionPoint).min(max);
BigInteger lowerPartitionPoint = BigInteger.valueOf(partitionPoint).negate().max(min);
return new BigInteger[]{lowerPartitionPoint, upperPartitionPoint};
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy