net.jqwik.api.Arbitraries Maven / Gradle / Ivy
package net.jqwik.api;
import java.util.*;
import java.util.function.*;
import java.util.stream.*;
import org.apiguardian.api.*;
import net.jqwik.api.Tuple.*;
import net.jqwik.api.arbitraries.*;
import net.jqwik.api.providers.*;
import net.jqwik.api.stateful.*;
import static org.apiguardian.api.API.Status.*;
@API(status = STABLE, since = "1.0")
public class Arbitraries {
@API(status = INTERNAL)
public static abstract class ArbitrariesFacade {
private static final ArbitrariesFacade implementation;
static {
implementation = FacadeLoader.load(ArbitrariesFacade.class);
}
public abstract EdgeCases edgeCasesChoose(List values, int maxEdgeCases);
public abstract EdgeCases edgeCasesChoose(char[] validChars, int maxEdgeCases);
public abstract Optional> exhaustiveChoose(List values, long maxNumberOfSamples);
public abstract Optional> exhaustiveCreate(Supplier supplier, long maxNumberOfSamples);
public abstract Optional> exhaustiveChoose(char[] values, long maxNumberOfSamples);
public abstract Optional>> exhaustiveShuffle(List values, long maxNumberOfSamples);
public abstract RandomGenerator randomChoose(List values);
public abstract RandomGenerator randomChoose(char[] values);
public abstract Arbitrary oneOf(List> all);
public abstract RandomGenerator randomFrequency(List> frequencies);
public abstract RandomGenerator randomSamples(T[] samples);
public abstract RandomGenerator> randomShuffle(List values);
public abstract ActionSequenceArbitrary sequences(Arbitrary extends Action> actionArbitrary);
public abstract Arbitrary frequencyOf(List>> frequencies);
public abstract IntegerArbitrary integers();
public abstract LongArbitrary longs();
public abstract BigIntegerArbitrary bigIntegers();
public abstract FloatArbitrary floats();
public abstract BigDecimalArbitrary bigDecimals();
public abstract DoubleArbitrary doubles();
public abstract ByteArbitrary bytes();
public abstract ShortArbitrary shorts();
public abstract StringArbitrary strings();
public abstract CharacterArbitrary chars();
public abstract Arbitrary defaultFor(Class type, Class>[] typeParameters);
public abstract Arbitrary defaultFor(TypeUsage typeUsage);
public abstract Arbitrary lazy(Supplier> arbitrarySupplier);
public abstract TypeArbitrary forType(Class targetType);
public abstract MapArbitrary maps(Arbitrary keysArbitrary, Arbitrary valuesArbitrary);
public abstract Arbitrary> entries(Arbitrary keysArbitrary, Arbitrary valuesArbitrary);
public abstract Arbitrary recursive(Supplier> base, Function, Arbitrary> recur, int depth);
public abstract Arbitrary lazyOf(List>> suppliers);
}
private Arbitraries() {
}
/**
* Create an arbitrary of type T from a corresponding generator of type T.
*
* @param generator The generator to be used for generating the values
* @param The type of values to generate
* @return a new arbitrary instance
*/
public static Arbitrary fromGenerator(RandomGenerator generator) {
return new Arbitrary() {
@Override
public RandomGenerator generator(final int genSize) {
return generator;
}
@Override
public EdgeCases edgeCases(int maxEdgeCases) {
return EdgeCases.none();
}
};
}
/**
* Create an arbitrary that will generate values of type T using a generator function.
* The generated values are unshrinkable.
*
* @param generator The generator function to be used for generating the values
* @param The type of values to generate
* @return a new arbitrary instance
*/
public static Arbitrary randomValue(Function generator) {
return fromGenerator(random -> Shrinkable.unshrinkable(generator.apply(random)));
}
/**
* Create an arbitrary for Random objects.
*
* @return a new arbitrary instance
*/
public static Arbitrary randoms() {
return randomValue(random -> new Random(random.nextLong()));
}
/**
* Create an arbitrary that will randomly choose from a given array of values.
* A generated value will be shrunk towards the start of the array.
*
*
* Use this method only for immutable values, because changing the value will change
* subsequent generated values as well.
* For mutable values use {@linkplain #ofSuppliers(Supplier[])} instead.
*
* @param values The array of values to choose from
* @param The type of values to generate
* @return a new arbitrary instance
*/
@SafeVarargs
public static Arbitrary of(T... values) {
return of(Arrays.asList(values));
}
/**
* Create an arbitrary that will randomly choose from a given collection of values.
* A generated value will be shrunk towards the start of the collection.
*
*
* Use this method only for immutable values, because changing the value will change
* subsequent generated values as well.
* For mutable values use {@linkplain #ofSuppliers(Collection)} instead.
*
* @param values The collection of values to choose from
* @param The type of values to generate
* @return a new arbitrary instance
*/
@API(status = MAINTAINED, since = "1.3.1")
public static Arbitrary of(Collection values) {
List valueList = values instanceof List ? (List) values : new ArrayList<>(values);
return fromGenerators(
ArbitrariesFacade.implementation.randomChoose(valueList),
max -> ArbitrariesFacade.implementation.exhaustiveChoose(valueList, max),
maxEdgeCases -> ArbitrariesFacade.implementation.edgeCasesChoose(valueList, maxEdgeCases)
);
}
/**
* Create an arbitrary that will randomly choose from a given array of value suppliers
* and then get the value from the supplier.
* A generated value will be shrunk towards the start of the array.
*
*
* Use this method instead of {@linkplain #of(Object[])} for mutable objects
* to make sure that changing a generated object will not influence other generated
* objects.
*
* @param valueSuppliers The array of values to choose from
* @param The type of values to generate
* @return a new arbitrary instance
*/
@API(status = MAINTAINED, since = "1.3.0")
@SafeVarargs
public static Arbitrary ofSuppliers(Supplier... valueSuppliers) {
return of(valueSuppliers).map(Supplier::get);
}
/**
* Create an arbitrary that will randomly choose from a given collection of value suppliers
* and then get the value from the supplier.
* A generated value will be shrunk towards the start of the collection.
*
*
* Use this method instead of {@linkplain #of(Collection)} for mutable objects
* to make sure that changing a generated object will not influence other generated
* objects.
*
* @param valueSuppliers The collection of values to choose from
* @param The type of values to generate
* @return a new arbitrary instance
*/
@API(status = MAINTAINED, since = "1.3.1")
public static Arbitrary ofSuppliers(Collection> valueSuppliers) {
return of(valueSuppliers).map(Supplier::get);
}
/**
* Create an arbitrary of character values.
*
* @param values The array of characters to choose from.
* @return a new arbitrary instance
*/
public static Arbitrary of(char[] values) {
return fromGenerators(
ArbitrariesFacade.implementation.randomChoose(values),
max -> ArbitrariesFacade.implementation.exhaustiveChoose(values, max),
maxEdgeCases -> ArbitrariesFacade.implementation.edgeCasesChoose(values, maxEdgeCases)
);
}
/**
* Create an arbitrary for enum values of type T.
*
* @param enumClass The enum class.
* @param The type of values to generate
* @return a new arbitrary instance
*/
public static > Arbitrary of(Class enumClass) {
List values = Arrays.asList(enumClass.getEnumConstants());
return of(values);
}
/**
* Create an arbitrary that will randomly choose between all given arbitraries of the same type T.
*
* @param first The first arbitrary to choose form
* @param rest An array of arbitraries to choose from
* @param The type of values to generate
* @return a new arbitrary instance
*/
@SuppressWarnings("unchecked")
@SafeVarargs
public static Arbitrary oneOf(Arbitrary extends T> first, Arbitrary extends T>... rest) {
List> all = new ArrayList<>();
all.add((Arbitrary) first);
for (Arbitrary> arbitrary : rest) {
all.add((Arbitrary) arbitrary);
}
return oneOf(all);
}
/**
* Create an arbitrary that will randomly choose between all given arbitraries of the same type T.
*
* @param all A list of arbitraries to choose from
* @param The type of values to generate
* @return a new arbitrary instance
*/
public static Arbitrary oneOf(List> all) {
if (all.size() == 1) {
return all.get(0);
}
// Simple flatMapping is not enough because of configurations
return ArbitrariesFacade.implementation.oneOf(all);
}
/**
* Create an arbitrary that will randomly choose between all given values of the same type T.
* The probability distribution is weighted with the first parameter of the tuple.
*
* @param frequencies An array of tuples of which the first parameter gives the weight and the second the value.
* @param The type of values to generate
* @return a new arbitrary instance
*/
@SafeVarargs
public static Arbitrary frequency(Tuple2... frequencies) {
return frequency(Arrays.asList(frequencies));
}
/**
* Create an arbitrary that will randomly choose between all given values of the same type T.
* The probability distribution is weighted with the first parameter of the tuple.
*
* @param frequencies A list of tuples of which the first parameter gives the weight and the second the value.
* @param The type of values to generate
* @return a new arbitrary instance
*/
public static Arbitrary frequency(List> frequencies) {
List values = frequencies.stream()
.filter(f -> f.get1() > 0)
.map(Tuple2::get2)
.collect(Collectors.toList());
return fromGenerators(
ArbitrariesFacade.implementation.randomFrequency(frequencies),
max -> ArbitrariesFacade.implementation.exhaustiveChoose(values, max),
maxEdgeCases -> ArbitrariesFacade.implementation.edgeCasesChoose(values, maxEdgeCases)
);
}
/**
* Create an arbitrary that will randomly choose between all given arbitraries of the same type T.
* The probability distribution is weighted with the first parameter of the tuple.
*
* @param frequencies An array of tuples of which the first parameter gives the weight and the second the arbitrary.
* @param The type of values to generate
* @return a new arbitrary instance
*/
@SuppressWarnings("unchecked")
@SafeVarargs
public static Arbitrary frequencyOf(Tuple2>... frequencies) {
List>> all = new ArrayList<>();
for (Tuple2> frequency : frequencies) {
all.add(Tuple.of(frequency.get1(), (Arbitrary) frequency.get2()));
}
return frequencyOf(all);
}
/**
* Create an arbitrary that will randomly choose between all given arbitraries of the same type T.
* The probability distribution is weighted with the first parameter of the tuple.
*
* @param frequencies A list of tuples of which the first parameter gives the weight and the second the arbitrary.
* @param The type of values to generate
* @return a new arbitrary instance
*/
public static Arbitrary frequencyOf(List>> frequencies) {
// Simple flatMapping is not enough because of configurations
return ArbitrariesFacade.implementation.frequencyOf(frequencies);
}
/**
* Create an arbitrary that generates values of type Integer.
*
* @return a new arbitrary instance
*/
public static IntegerArbitrary integers() {
return ArbitrariesFacade.implementation.integers();
}
/**
* Create an arbitrary that generates values of type Long.
*
* @return a new arbitrary instance
*/
public static LongArbitrary longs() {
return ArbitrariesFacade.implementation.longs();
}
/**
* Create an arbitrary that generates values of type BigInteger.
*
* @return a new arbitrary instance
*/
public static BigIntegerArbitrary bigIntegers() {
return ArbitrariesFacade.implementation.bigIntegers();
}
/**
* Create an arbitrary that generates values of type Float.
*
* @return a new arbitrary instance
*/
public static FloatArbitrary floats() {
return ArbitrariesFacade.implementation.floats();
}
/**
* Create an arbitrary that generates values of type BigDecimal.
*
* @return a new arbitrary instance
*/
public static BigDecimalArbitrary bigDecimals() {
return ArbitrariesFacade.implementation.bigDecimals();
}
/**
* Create an arbitrary that generates values of type Double.
*
* @return a new arbitrary instance
*/
public static DoubleArbitrary doubles() {
return ArbitrariesFacade.implementation.doubles();
}
/**
* Create an arbitrary that generates values of type Byte.
*
* @return a new arbitrary instance
*/
public static ByteArbitrary bytes() {
return ArbitrariesFacade.implementation.bytes();
}
/**
* Create an arbitrary that generates values of type Short.
*
* @return a new arbitrary instance
*/
public static ShortArbitrary shorts() {
return ArbitrariesFacade.implementation.shorts();
}
/**
* Create an arbitrary that generates values of type String.
*
* @return a new arbitrary instance
*/
public static StringArbitrary strings() {
return ArbitrariesFacade.implementation.strings();
}
/**
* Create an arbitrary that generates values of type Character.
*
* @return a new arbitrary instance
*/
public static CharacterArbitrary chars() {
return ArbitrariesFacade.implementation.chars();
}
/**
* Create an arbitrary that will always generate the same value.
*
* @param value The value to "generate"
* @param The type of the value
* @return a new arbitrary instance
*/
@API(status = MAINTAINED, since = "1.3.2")
public static Arbitrary just(T value) {
return fromGenerators(
random -> Shrinkable.unshrinkable(value),
max -> ArbitrariesFacade.implementation.exhaustiveChoose(Arrays.asList(value), max),
maxEdgeCases -> EdgeCases.fromSupplier(() -> Shrinkable.unshrinkable(value))
);
}
/**
* Create an arbitrary that will use a supplier to generate a value.
* The difference to {@linkplain Arbitraries#just(Object)} is that the value
* is freshly generated for each try of a property.
*
* For exhaustive shrinking all generated values are supposed to have identical behaviour,
* i.e. that means that only one value is generated per combination.
*
* @param supplier The supplier use to generate a value
* @param The type of values to generate
* @return a new arbitrary instance
*/
@API(status = MAINTAINED, since = "1.1.1")
public static Arbitrary create(Supplier supplier) {
return fromGenerators(
random -> Shrinkable.supplyUnshrinkable(supplier, true),
max -> ArbitrariesFacade.implementation.exhaustiveCreate(supplier, max),
maxEdgeCases -> EdgeCases.fromSupplier(() -> Shrinkable.supplyUnshrinkable(supplier, true))
);
}
/**
* Create an arbitrary that will always generate a list which is a
* permutation of the values handed to it. Permutations will
* not be shrunk.
*
* @param values The values to permute
* @param The type of values to generate
* @return a new arbitrary instance
*/
@SafeVarargs
public static Arbitrary> shuffle(T... values) {
return shuffle(Arrays.asList(values));
}
/**
* Create an arbitrary that will always generate a list which is a
* permutation of the values handed to it. Permutations will
* not be shrunk.
*
* @param values The values to permute
* @param The type of values to generate
* @return a new arbitrary instance
*/
public static Arbitrary> shuffle(List values) {
return fromGenerators(
ArbitrariesFacade.implementation.randomShuffle(values),
max -> ArbitrariesFacade.implementation.exhaustiveShuffle(values, max),
maxEdgeCases -> EdgeCases.fromSupplier(() -> Shrinkable.unshrinkable(values))
);
}
/**
* Find a registered arbitrary that will be used to generate values of type T.
* All default arbitrary providers and all registered arbitrary providers are considered.
* This is more or less the same mechanism that jqwik uses to find arbitraries for
* property method parameters.
*
* @param type The type of the value to find an arbitrary for
* @param typeParameters The type parameters if type is a generic type
* @param The type of values to generate
* @return a new arbitrary instance
* @throws CannotFindArbitraryException if there is no registered arbitrary provider to serve this type
*/
public static Arbitrary defaultFor(Class type, Class>... typeParameters) {
return ArbitrariesFacade.implementation.defaultFor(type, typeParameters);
}
/**
* Find a registered arbitrary that will be used to generate values of type T.
* All default arbitrary providers and all registered arbitrary providers are considered.
* This is more or less the same mechanism that jqwik uses to find arbitraries for
* property method parameters.
*
* @param typeUsage The type of the value to find an arbitrary for
* @param The type of values to generate
* @return a new arbitrary instance
* @throws CannotFindArbitraryException if there is no registered arbitrary provider to serve this type
*/
@API(status = MAINTAINED, since = "1.1")
public static Arbitrary defaultFor(TypeUsage typeUsage) {
return ArbitrariesFacade.implementation.defaultFor(typeUsage);
}
/**
* Create an arbitrary for type {@code T} that will by default use the type's
* public constructors and public factory methods.
*
* @param targetType The class of the type to create an arbitrary for
* @param The type of values to generate
* @return a new arbitrary instance
* @see TypeArbitrary
*/
@API(status = MAINTAINED, since = "1.2.0")
public static TypeArbitrary forType(Class targetType) {
return ArbitrariesFacade.implementation.forType(targetType);
}
private static Arbitrary fromGenerators(
final RandomGenerator randomGenerator,
final Function>> exhaustiveGeneratorFunction,
final Function> edgeCasesSupplier
) {
return new Arbitrary() {
@Override
public RandomGenerator generator(int tries) {
return randomGenerator;
}
@Override
public Optional> exhaustive(long maxNumberOfSamples) {
return exhaustiveGeneratorFunction.apply(maxNumberOfSamples);
}
@Override
public EdgeCases edgeCases(int maxEdgeCases) {
return edgeCasesSupplier.apply(maxEdgeCases);
}
};
}
/**
* Create an arbitrary that will evaluate arbitrarySupplier as soon as it is used for generating values.
*
* This is useful (and necessary) when arbitrary providing functions use other arbitrary providing functions
* in a recursive way. Without the use of lazy() this would result in a stack overflow.
* Most of the time, however, using {@linkplain #lazyOf(Supplier, Supplier[])} is the better choice
* because it has significantly better shrinking behaviour.
*
* @param arbitrarySupplier The supplier function being used to generate an arbitrary
* @param The type of values to generate
* @return a new arbitrary instance
* @see #recursive(Supplier, Function, int)
* @see #lazyOf(Supplier, Supplier[])
*/
public static Arbitrary lazy(Supplier> arbitrarySupplier) {
return ArbitrariesFacade.implementation.lazy(arbitrarySupplier);
}
/**
* Create an arbitrary by deterministic recursion.
*
* Mind that the arbitrary will be created by invoking recursion at arbitrary creation time.
* Using {@linkplain #lazyOf(Supplier, Supplier[])} or {@linkplain #lazy(Supplier)} instead
* will recur at value generation time.
*
* @param base The supplier returning the recursion's base case
* @param recur The function to extend the base case
* @param depth The number of times to invoke recursion
* @param The type of values to generate
* @return a new arbitrary instance
* @see #lazy(Supplier)
*/
public static Arbitrary recursive(
Supplier> base,
Function, Arbitrary> recur,
int depth
) {
return ArbitrariesFacade.implementation.recursive(base, recur, depth);
}
/**
* Create an arbitrary by lazy supplying one of several arbitraries.
* The main use of this function is to allow recursive generation of structured
* values without overflowing the stack.
*
*
* One alternative is to use {@linkplain #lazy(Supplier)} combined with
* {@linkplain Arbitraries#oneOf(Arbitrary, Arbitrary[])}
* or {@linkplain Arbitraries#frequencyOf(Tuple.Tuple2[])}.
* But {@code lazyOf()} has considerably better shrinking behaviour with recursion.
*
*
*
* Caveat:
* Never use this construct if suppliers make use of variable state
* like method parameters or changing instance members.
* In those cases use {@linkplain #lazy(Supplier)} instead.
*
*
* @param first The first supplier to choose from
* @param rest The rest of suppliers to choose from
* @param The type of values to generate
* @return a (potentially cached) arbitrary instance
* @see #lazy(Supplier)
* @see #recursive(Supplier, Function, int)
*/
@SuppressWarnings("unchecked")
@SafeVarargs
@API(status = EXPERIMENTAL, since = "1.3.4")
public static Arbitrary lazyOf(Supplier> first, Supplier>... rest) {
List>> all = new ArrayList<>();
all.add(() -> (Arbitrary) first.get());
for (Supplier> arbitrarySupplier : rest) {
all.add(() -> (Arbitrary) arbitrarySupplier.get());
}
return ArbitrariesFacade.implementation.lazyOf(all);
}
/**
* Create an arbitrary to create a sequence of actions. Useful for stateful testing.
*
* @param actionArbitrary The arbitrary to generate individual actions.
* @param The type of actions to generate
* @return a new arbitrary instance
*/
@API(status = MAINTAINED, since = "1.0")
public static ActionSequenceArbitrary sequences(Arbitrary extends Action> actionArbitrary) {
return ArbitrariesFacade.implementation.sequences(actionArbitrary);
}
/**
* Create an arbitrary to create instances of {@linkplain Map}.
* The generated maps are mutable.
*
* @param keysArbitrary The arbitrary to generate the keys
* @param valuesArbitrary The arbitrary to generate the values
* @param type of keys
* @param type of values
* @return a new arbitrary instance
*/
@API(status = MAINTAINED, since = "1.1.6")
public static MapArbitrary maps(Arbitrary keysArbitrary, Arbitrary valuesArbitrary) {
return ArbitrariesFacade.implementation.maps(keysArbitrary, valuesArbitrary);
}
/**
* Create an arbitrary to create instances of {@linkplain java.util.Map.Entry}.
* The generated entries are mutable.
*
* @param keysArbitrary The arbitrary to generate the keys
* @param valuesArbitrary The arbitrary to generate the values
* @param type of keys
* @param type of values
* @return a new arbitrary instance
*/
@API(status = MAINTAINED, since = "1.2.0")
public static Arbitrary> entries(Arbitrary keysArbitrary, Arbitrary valuesArbitrary) {
return ArbitrariesFacade.implementation.entries(keysArbitrary, valuesArbitrary);
}
/**
* Create an arbitrary that never creates anything. Sometimes useful
* when generating arbitraries of "functions" that have void as return type.
*
* @return arbitrary instance that will generate nothing
*/
@API(status = MAINTAINED, since = "1.3.0")
public static Arbitrary nothing() {
return just(null);
}
}