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

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

There is a newer version: 1.9.1
Show 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 org.junit.platform.engine.reporting.*;

import net.jqwik.api.*;
import net.jqwik.engine.support.*;

public class PropertyShrinker {

	private final static int BOUNDED_SHRINK_STEPS = 1000;

	private final List parameters;
	private final ShrinkingMode shrinkingMode;
	private final Consumer reporter;
	private final Reporting[] reporting;

	public PropertyShrinker(List parameters, ShrinkingMode shrinkingMode, Consumer reporter, Reporting[] reporting) {
		this.parameters = parameters;
		this.shrinkingMode = shrinkingMode;
		this.reporter = reporter;
		this.reporting = reporting;
	}

	@SuppressWarnings("unchecked")
	public PropertyShrinkingResult shrink(Falsifier forAllFalsifier, Throwable originalError) {
		if (shrinkingMode == ShrinkingMode.OFF) {
			return new PropertyShrinkingResult(toValues(parameters), 0 , originalError);
		}

		Function>, ShrinkingDistance> distanceFunction = ShrinkingDistance::combine;
		ElementsShrinkingSequence sequence = new ElementsShrinkingSequence(parameters, forAllFalsifier, distanceFunction);
		sequence.init(FalsificationResult.falsified(Shrinkable.unshrinkable(toValues(parameters)), originalError));

		Consumer falsifiedReporter = isFalsifiedReportingOn() ? this::reportFalsifiedParams : ignore -> {};

		AtomicInteger shrinkingStepsCounter = new AtomicInteger(0);
		while (sequence.next(shrinkingStepsCounter::incrementAndGet, falsifiedReporter)) {
			if (shrinkingMode == ShrinkingMode.BOUNDED && shrinkingStepsCounter.get() >= BOUNDED_SHRINK_STEPS) {
				reportShrinkingBoundReached(shrinkingStepsCounter.get(), toValues(parameters), sequence.current().value());
				break;
			}
		}
		FalsificationResult current = sequence.current();
		return new PropertyShrinkingResult(current.value(), shrinkingStepsCounter.get(), current.throwable().orElse(null));
	}

	private boolean isFalsifiedReportingOn() {
		return Reporting.FALSIFIED.containedIn(reporting);
	}

	private List toValues(List shrinkables) {
		return shrinkables.stream().map(Shrinkable::value).collect(Collectors.toList());
	}

	private void reportFalsifiedParams(FalsificationResult result) {
		ReportEntry falsifiedEntry = ReportEntry.from("falsified", JqwikStringSupport.displayString(result.value()));
		reporter.accept(falsifiedEntry);
	}

	private void reportShrinkingBoundReached(int steps, Object originalValue, Object bestShrunkValue) {
		String value = String.format(
			"%n    steps : %s" +
				"%n    original parameters : %s" +
				"%n    shrunk parameters   : %s" +
				"%nYou can switch on full shrinking with '@Property(shrinking = ShrinkingMode.FULL)'",
			steps,
			JqwikStringSupport.displayString(originalValue),
			JqwikStringSupport.displayString(bestShrunkValue)
		);
		reporter.accept(ReportEntry.from("shrinking bound reached", value));
	}

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy