net.jqwik.engine.properties.stateful.ShrinkableActionSequence Maven / Gradle / Ivy
package net.jqwik.engine.properties.stateful;
import java.util.*;
import java.util.stream.*;
import net.jqwik.api.*;
import net.jqwik.api.stateful.*;
import net.jqwik.engine.support.*;
import org.jspecify.annotations.*;
class ShrinkableActionSequence implements Shrinkable> {
private final ActionGenerator actionGenerator;
private final int maxSize;
private final ShrinkingDistance distance;
private @Nullable SequentialActionSequence generatedSequence = null;
ShrinkableActionSequence(ActionGenerator actionGenerator, int maxSize, ShrinkingDistance distance) {
this.actionGenerator = actionGenerator;
this.maxSize = maxSize;
this.distance = distance;
}
@Override
public ActionSequence value() {
// Cannot be recreated on each access because creation takes place on first access and must be preserved for shrinking
if (generatedSequence == null) {
generatedSequence = new SequentialActionSequence<>(actionGenerator, maxSize);
}
return generatedSequence;
}
@Override
public Stream>> shrink() {
if (generatedSequence == null) {
return Stream.empty();
}
return JqwikStreamSupport.concat(
shrinkSequenceOfActions(),
shrinkActionsOneAfterTheOther()
);
}
private Stream>> shrinkSequenceOfActions() {
return new ComprehensiveSizeOfListShrinker()
.shrink(actionGenerator.generated(), 1)
.map(this::createShrinkableActionSequence);
}
private Stream>> shrinkActionsOneAfterTheOther() {
List>> shrinkableActions = actionGenerator.generated();
List>>> shrinkPerElementStreams = new ArrayList<>();
for (int i = 0; i < shrinkableActions.size(); i++) {
int index = i;
Shrinkable> element = shrinkableActions.get(i);
Stream>> shrinkElement = element.shrink().flatMap(shrunkElement -> {
List>> actionsCopy = new ArrayList<>(shrinkableActions);
actionsCopy.set(index, shrunkElement);
return Stream.of(createShrinkableActionSequence(actionsCopy));
});
shrinkPerElementStreams.add(shrinkElement);
}
return JqwikStreamSupport.concat(shrinkPerElementStreams);
}
private ShrinkableActionSequence createShrinkableActionSequence(List>> list) {
ActionGenerator newGenerator = new ShrinkablesActionGenerator<>(list);
ShrinkingDistance newDistance = ShrinkingDistance.forCollection(list);
return new ShrinkableActionSequence<>(newGenerator, list.size(), newDistance);
}
@Override
public ShrinkingDistance distance() {
if (generatedSequence == null) {
return distance;
}
return ShrinkingDistance.forCollection(actionGenerator.generated());
}
}