net.jqwik.engine.execution.GenerationInfo Maven / Gradle / Ivy
The newest version!
package net.jqwik.engine.execution;
import java.io.*;
import java.util.*;
import java.util.stream.*;
import net.jqwik.api.*;
import net.jqwik.api.lifecycle.*;
import net.jqwik.engine.properties.shrinking.*;
import org.jspecify.annotations.*;
public class GenerationInfo implements Serializable {
public final static GenerationInfo NULL = new GenerationInfo(null);
private final @Nullable String randomSeed;
private final int generationIndex;
// Store ordinals instead of enum objects so that serialization
// in jqwik.database uses less disk space
private final List> byteSequences;
public GenerationInfo(@Nullable String randomSeed) {
this(randomSeed, 0);
}
public GenerationInfo(@Nullable String randomSeed, int generationIndex) {
this(randomSeed, generationIndex, Collections.emptyList());
}
private GenerationInfo(@Nullable String randomSeed, int generationIndex, List> byteSequences) {
this.randomSeed = randomSeed != null ? (randomSeed.isEmpty() ? null : randomSeed) : null;
this.generationIndex = generationIndex;
this.byteSequences = byteSequences;
}
private List toByteSequence(List shrinkingSequence) {
return shrinkingSequence.stream().map(status -> (byte) status.ordinal()).collect(Collectors.toList());
}
public GenerationInfo appendShrinkingSequence(List toAppend) {
if (toAppend.isEmpty()) {
return this;
}
List> newByteSequences = new ArrayList<>(byteSequences);
newByteSequences.add(toByteSequence(toAppend));
return new GenerationInfo(randomSeed, generationIndex, newByteSequences);
}
public Optional randomSeed() {
return Optional.ofNullable(randomSeed);
}
public int generationIndex() {
return generationIndex;
}
public Optional>> generateOn(ParametersGenerator generator, TryLifecycleContext context) {
List> sample = useGenerationIndex(generator, context);
return useShrinkingSequences(sample);
}
private Optional>> useShrinkingSequences(@Nullable List> sample) {
Optional>> shrunkSample = Optional.ofNullable(sample);
for (List shrinkingSequence : shrinkingSequences()) {
if (!shrunkSample.isPresent()) {
break;
}
shrunkSample = shrink(shrunkSample.get(), shrinkingSequence);
}
return shrunkSample;
}
private Optional>> shrink(
List> sample,
List shrinkingSequence
) {
ShrunkSampleRecreator recreator = new ShrunkSampleRecreator(sample);
return recreator.recreateFrom(shrinkingSequence);
}
private @Nullable List> useGenerationIndex(ParametersGenerator generator, TryLifecycleContext context) {
List> sample = null;
for (int i = 0; i < generationIndex; i++) {
if (generator.hasNext()) {
sample = generator.next(context);
} else {
return null;
}
}
return sample;
}
public List> shrinkingSequences() {
return byteSequences.stream()
.map(this::toShrinkingSequence)
.collect(Collectors.toList());
}
private List toShrinkingSequence(List sequence) {
return sequence.stream().map(ordinal -> TryExecutionResult.Status.values()[ordinal]).collect(Collectors.toList());
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
GenerationInfo that = (GenerationInfo) o;
if (generationIndex != that.generationIndex) return false;
if (!Objects.equals(randomSeed, that.randomSeed)) return false;
return byteSequences.equals(that.byteSequences);
}
@Override
public int hashCode() {
int result = randomSeed != null ? randomSeed.hashCode() : 0;
result = 31 * result + generationIndex;
return result;
}
@Override
public String toString() {
List sizes = byteSequences.stream().map(bytes -> "size=" + bytes.size()).collect(Collectors.toList());
Tuple.Tuple3> tuple = Tuple.of(randomSeed, generationIndex, sizes);
return String.format("GenerationInfo%s", tuple);
}
}