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

net.jqwik.engine.properties.PropertyCheckResult Maven / Gradle / Ivy

There is a newer version: 1.9.1
Show newest version
package net.jqwik.engine.properties;

import java.util.*;

import org.jspecify.annotations.*;
import org.opentest4j.*;

import net.jqwik.api.*;
import net.jqwik.api.lifecycle.*;
import net.jqwik.engine.execution.*;
import net.jqwik.engine.execution.lifecycle.*;
import net.jqwik.engine.execution.reporting.*;

public class PropertyCheckResult implements ExtendedPropertyExecutionResult {

	enum CheckStatus {
		SUCCESSFUL,
		FAILED,
		EXHAUSTED,
		ABORTED
	}

	public static PropertyCheckResult successful(
		String stereotype,
		String propertyName,
		int tries,
		int checks,
		String randomSeed,
		GenerationMode generation,
		EdgeCasesMode edgeCasesMode,
		int edgeCasesTotal,
		int edgeCasesTried
	) {
		return new PropertyCheckResult(
			CheckStatus.SUCCESSFUL, stereotype,
			propertyName,
			tries,
			checks,
			new GenerationInfo(randomSeed),
			generation,
			edgeCasesMode,
			edgeCasesTotal,
			edgeCasesTried,
			null,
			null,
			null
		);
	}

	public static PropertyCheckResult failed(
		String stereotype,
		String propertyName,
		int tries,
		int checks,
		GenerationInfo generationInfo,
		GenerationMode generation,
		EdgeCasesMode edgeCasesMode,
		int edgeCasesTotal,
		int edgeCasesTried,
		@Nullable FalsifiedSample originalSample,
		@Nullable ShrunkFalsifiedSample shrunkSample,
		@Nullable Throwable throwable
	) {
		// If no shrinking was possible, report only original sample
		if (shrunkSample != null && areEquivalent(originalSample, shrunkSample)) {
			shrunkSample = null;
		}
		return new PropertyCheckResult(
			CheckStatus.FAILED,
			stereotype,
			propertyName,
			tries,
			checks,
			generationInfo,
			generation,
			edgeCasesMode,
			edgeCasesTotal,
			edgeCasesTried,
			originalSample,
			shrunkSample,
			throwable
		);
	}

	private static boolean areEquivalent(FalsifiedSample originalSample, ShrunkFalsifiedSample shrunkSample) {
		return originalSample.equals(shrunkSample) && shrunkSample.countShrinkingSteps() == 0;
	}

	public static PropertyCheckResult skipExample(
		String stereotype,
		String propertyName,
		String randomSeed,
		GenerationMode generation,
		EdgeCasesMode edgeCasesMode,
		int edgeCasesTotal,
		int edgeCasesTried,
		Throwable throwable
	) {
		return new PropertyCheckResult(
			CheckStatus.ABORTED,
			stereotype,
			propertyName,
			1,
			0,
			new GenerationInfo(randomSeed),
			generation,
			edgeCasesMode,
			edgeCasesTotal,
			edgeCasesTried,
			null,
			null,
			throwable
		);
	}

	public static PropertyCheckResult exhausted(
		String stereotype,
		String propertyName,
		int tries,
		int checks,
		String randomSeed,
		GenerationMode generation,
		EdgeCasesMode edgeCasesMode,
		int edgeCasesTotal,
		int edgeCasesTried,
		Throwable throwable
	) {
		return new PropertyCheckResult(
			CheckStatus.EXHAUSTED,
			stereotype,
			propertyName,
			tries,
			checks,
			new GenerationInfo(randomSeed),
			generation,
			edgeCasesMode,
			edgeCasesTotal,
			edgeCasesTried,
			null,
			null,
			throwable
		);
	}

	private final String stereotype;
	private final CheckStatus status;
	private final String propertyName;
	private final int tries;
	private final int checks;
	private final GenerationInfo generationInfo;
	private final GenerationMode generation;
	private final EdgeCasesMode edgeCasesMode;
	private final int edgeCasesTotal;
	private final int edgeCasesTried;
	private final @Nullable FalsifiedSample originalSample;
	private final @Nullable ShrunkFalsifiedSample shrunkSample;
	private final @Nullable Throwable throwable;

	private PropertyCheckResult(
		CheckStatus status, String stereotype,
		String propertyName,
		int tries,
		int checks,
		GenerationInfo generationInfo,
		GenerationMode generation,
		EdgeCasesMode edgeCasesMode,
		int edgeCasesTotal,
		int edgeCasesTried,
		@Nullable FalsifiedSample originalSample,
		@Nullable ShrunkFalsifiedSample shrunkSample,
		@Nullable Throwable throwable
	) {
		this.stereotype = stereotype;
		this.status = status;
		this.propertyName = propertyName;
		this.tries = tries;
		this.checks = checks;
		this.generationInfo = generationInfo;
		this.generation = generation;
		this.edgeCasesMode = edgeCasesMode;
		this.edgeCasesTotal = edgeCasesTotal;
		this.edgeCasesTried = edgeCasesTried;
		this.shrunkSample = shrunkSample;
		this.originalSample = originalSample;
		this.throwable = determineThrowable(status, throwable);
	}

	private @Nullable Throwable determineThrowable(CheckStatus status, @Nullable Throwable throwable) {
		if (status == CheckStatus.SUCCESSFUL) {
			return null;
		} else {
			return throwable == null
					   ? new AssertionFailedError(this.toString())
					   : throwable;
		}
	}

	@Override
	public Optional> falsifiedParameters() {
		if (shrunkSample != null) {
			return Optional.of(shrunkSample.parameters());
		} else {
			return Optional.ofNullable(originalSample).map(FalsifiedSample::parameters);
		}
	}

	@Override
	public Status status() {
		switch (checkStatus()) {
			case SUCCESSFUL: return Status.SUCCESSFUL;
			case ABORTED: return Status.ABORTED;
			default: return Status.FAILED;
		}
	}

	@Override
	public Optional throwable() {
		return Optional.ofNullable(throwable);
	}

	@Override
	public PropertyExecutionResult mapTo(Status newStatus, @Nullable Throwable throwable) {
		switch (newStatus) {
			case ABORTED:
				return PlainExecutionResult.aborted(throwable, generationInfo);
			case FAILED:
				return new PropertyCheckResult(
					CheckStatus.FAILED,
					stereotype,
					propertyName,
					tries,
					checks,
					generationInfo,
					generation,
					edgeCasesMode,
					edgeCasesTotal,
					edgeCasesTried,
					originalSample,
					shrunkSample,
					throwable
				);
			case SUCCESSFUL:
				return new PropertyCheckResult(
					CheckStatus.SUCCESSFUL,
					stereotype,
					propertyName,
					tries,
					checks,
					generationInfo,
					generation,
					edgeCasesMode,
					edgeCasesTotal,
					edgeCasesTried,
					null,
					null,
					throwable
				);
			default:
				throw new IllegalStateException(String.format("Unknown state: %s", newStatus.name()));
		}
	}

	@Override
	public boolean isExtended() {
		return true;
	}

	public String propertyName() {
		return propertyName;
	}

	public CheckStatus checkStatus() {
		return status;
	}

	public int countChecks() {
		return checks;
	}

	public int countTries() {
		return tries;
	}

	public GenerationInfo generationInfo() {
		return generationInfo;
	}

	public Optional originalSample() {
		return Optional.ofNullable(originalSample);
	}

	public Optional shrunkSample() {
		return Optional.ofNullable(shrunkSample);
	}

	public GenerationMode generation() {
		return generation;
	}

	@Override
	public EdgeCasesExecutionResult edgeCases() {
		return new EdgeCasesExecutionResult(edgeCasesMode, edgeCasesTotal, edgeCasesTried);
	}

	@Override
	public String toString() {
		String header = String.format("%s [%s]", stereotype, propertyName);
		switch (checkStatus()) {
			case FAILED:
				String failedMessage = falsifiedParameters().map(sampleParams -> {
					Map sampleMap = new LinkedHashMap<>();
					for (int i = 0; i < sampleParams.size(); i++) {
						Object parameter = sampleParams.get(i);
						sampleMap.put(i, parameter);
					}

					Collection reportingFormats = SampleReportingFormats.getReportingFormats();
					String sampleString = ValueReport.of(sampleMap, reportingFormats).singleLineReport();
					return sampleParams.isEmpty() ? "" : String.format(" with sample %s", sampleString);
				}).orElse("");
				return String.format("%s failed%s", header, failedMessage);
			case EXHAUSTED:
				int rejections = tries - checks;
				return String.format("%s exhausted after [%d] tries and [%d] rejections", header, tries, rejections);
			default:
				return header;
		}
	}

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy