net.jqwik.api.Shrinkable Maven / Gradle / Ivy
package net.jqwik.api;
import java.util.*;
import java.util.function.*;
import java.util.stream.*;
import org.apiguardian.api.*;
import org.jspecify.annotations.*;
import static org.apiguardian.api.API.Status.*;
@API(status = STABLE, since = "1.0")
public interface Shrinkable extends Comparable> {
@API(status = INTERNAL)
abstract class ShrinkableFacade {
private static final ShrinkableFacade implementation;
static {
implementation = FacadeLoader.load(ShrinkableFacade.class);
}
public abstract Shrinkable unshrinkable(Supplier extends T> valueSupplier, ShrinkingDistance distance);
public abstract Shrinkable map(Shrinkable self, Function super T, ? extends U> mapper);
public abstract Shrinkable filter(Shrinkable self, Predicate super T> filter);
public abstract Shrinkable flatMap(Shrinkable self, Function super T, ? extends Arbitrary> flatMapper, int tries, long randomSeed);
}
static Shrinkable unshrinkable(T value) {
return unshrinkable(value, ShrinkingDistance.MIN);
}
static Shrinkable unshrinkable(T value, ShrinkingDistance distance) {
return ShrinkableFacade.implementation.unshrinkable(() -> value, distance);
}
@API(status = INTERNAL)
static Shrinkable supplyUnshrinkable(Supplier extends T> supplier) {
return ShrinkableFacade.implementation.unshrinkable(supplier, ShrinkingDistance.MIN);
}
/**
* Create value freshly, so that in case of mutable objects shrinking (and reporting)
* can rely on untouched values.
*
* @return An un-changed instance of the value represented by this shrinkable
*/
T value();
/**
* Create a new and finite stream of smaller or same size shrinkables; size is measured by {@linkplain #distance()}.
*
* Same size shrinkables are allowed but they have to iterate towards a single value to prevent endless shrinking.
* This also means that a shrinkable must never be in its own shrink stream!
*
* @return a finite stream of shrinking options
*/
@API(status = INTERNAL, since = "1.3.3")
Stream> shrink();
/**
* To be able to "move" values towards the end of collections while keeping some constraint constant
* it's necessary to grow a shrinkable by what another has been shrunk.
* One example is keeping a sum of values and still shrinking to the same resulting list.
*
* @param before The other shrinkable before shrinking
* @param after The other shrinkable after shrinking
* @return this shrinkable grown by the difference of before and after
*/
@API(status = INTERNAL, since = "1.3.3")
default Optional> grow(Shrinkable> before, Shrinkable> after) {
return Optional.empty();
}
/**
* Grow a shrinkable to allow broader searching in flat mapped shrinkables
*
* @return a finite stream of grown values
*/
@API(status = INTERNAL, since = "1.3.3")
default Stream> grow() {
return Stream.empty();
}
ShrinkingDistance distance();
/**
* Sometimes simplifies test writing
*
* @return generic version of a shrinkable
*/
@SuppressWarnings("unchecked")
@API(status = INTERNAL, since = "1.2.4")
default Shrinkable