All Downloads are FREE. Search and download functionalities are using the official Maven repository.

net.jqwik.engine.properties.shrinking.ShrunkSampleRecreator Maven / Gradle / Ivy

The newest version!
package net.jqwik.engine.properties.shrinking;

import java.util.*;
import java.util.concurrent.atomic.*;
import java.util.function.*;
import java.util.stream.*;

import net.jqwik.api.*;
import net.jqwik.api.lifecycle.*;
import net.jqwik.engine.properties.*;

public class ShrunkSampleRecreator {

	private final List> shrinkables;

	public ShrunkSampleRecreator(List> shrinkables) {
		this.shrinkables = shrinkables;
	}

	public Optional>> recreateFrom(List shrinkingSequence) {
		List recreatingSequence = new ArrayList<>(shrinkingSequence);
		Falsifier> recreatingFalsifier = falsifier(recreatingSequence);

		FalsifiedSample originalSample = createFalsifiedSample();

		AtomicInteger shrinkingSteps = new AtomicInteger(0);
		FalsifiedSample[] currentBest = new FalsifiedSample[]{originalSample};
		Consumer sampleShrunkConsumer = shrunkSample -> {
			// Remember current best because shrinking can be interrupted with RecreationDone exception
			currentBest[0] = shrunkSample;
			shrinkingSteps.incrementAndGet();
		};
		ShrinkingAlgorithm plainShrinker = new ShrinkingAlgorithm(
			originalSample,
			sampleShrunkConsumer,
			ignore -> {}
		);

		try {
			// Shrunk falsified sample has already been grabbed in sampleShrunkConsumer
			FalsifiedSample ignore = plainShrinker.shrink(recreatingFalsifier);
		} catch (RecreationDone ignore) {}

		if (recreatingSequence.isEmpty()) {
			return Optional.of(currentBest[0].shrinkables());
		} else {
			return Optional.empty();
		}
	}

	private FalsifiedSample createFalsifiedSample() {
		List parameters = shrinkables.stream().map(Shrinkable::value).collect(Collectors.toList());
		return new FalsifiedSampleImpl(
			parameters,
			shrinkables,
			null,
			Collections.emptyList()
		);
	}

	private Falsifier> falsifier(List recreatingSequence) {
		return ignore -> {
			if (!recreatingSequence.isEmpty()) {
				TryExecutionResult.Status next = recreatingSequence.remove(0);
				switch (next) {
					case SATISFIED:
						return TryExecutionResult.satisfied();
					case INVALID:
						return TryExecutionResult.invalid();
					case FALSIFIED:
						return TryExecutionResult.falsified(null);
				}
			}
			throw new RecreationDone();
		};
	}

	private static class RecreationDone extends RuntimeException {}
}