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

net.jqwik.engine.properties.arbitraries.IntegralGeneratingArbitrary Maven / Gradle / Ivy

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

import java.math.*;
import java.util.*;
import java.util.function.*;
import java.util.stream.*;

import net.jqwik.api.*;
import net.jqwik.api.support.*;
import net.jqwik.engine.properties.*;
import net.jqwik.engine.properties.arbitraries.exhaustive.*;
import net.jqwik.engine.properties.arbitraries.randomized.*;
import net.jqwik.engine.properties.shrinking.*;

import static java.math.BigInteger.*;

class IntegralGeneratingArbitrary extends TypedCloneable implements Arbitrary {

	BigInteger min;
	BigInteger max;
	BigInteger shrinkingTarget;
	RandomDistribution distribution = RandomDistribution.biased();

	private Consumer> edgeCasesConfigurator = EdgeCases.Config.noConfig();

	IntegralGeneratingArbitrary(BigInteger defaultMin, BigInteger defaultMax) {
		this.min = defaultMin;
		this.max = defaultMax;
		this.shrinkingTarget = null;
	}

	@Override
	public RandomGenerator generator(int genSize) {
		return RandomGenerators.bigIntegers(min, max, shrinkingTarget(), distribution);
	}

	@Override
	public Optional> exhaustive(long maxNumberOfSamples) {
		BigInteger maxCount = max.subtract(min).add(BigInteger.ONE);

		// Necessary because maxCount could be larger than Long.MAX_VALUE
		if (maxCount.compareTo(valueOf(maxNumberOfSamples)) > 0) {
			return Optional.empty();
		} else {
			return ExhaustiveGenerators.fromIterable(RangeIterator::new, maxCount.longValueExact(), maxNumberOfSamples);
		}
	}

	@Override
	public EdgeCases edgeCases(int maxEdgeCases) {
		Range range = Range.of(min, max);
		BigInteger shrinkingTarget = shrinkingTarget();
		Function> edgeCasesCreator = m -> {
			List> shrinkables =
				streamDefaultEdgeCases()
					.map(value -> new ShrinkableBigInteger(
						value,
						range,
						shrinkingTarget
					))
					.limit(Math.max(0, m))
					.collect(Collectors.toList());
			return EdgeCasesSupport.fromShrinkables(shrinkables);
		};
		IntegralEdgeCasesConfiguration configuration = new IntegralEdgeCasesConfiguration(range, shrinkingTarget);
		return configuration.configure(edgeCasesConfigurator, edgeCasesCreator, maxEdgeCases);
	}

	@Override
	public Arbitrary edgeCases(Consumer> configurator) {
		IntegralGeneratingArbitrary clone = typedClone();
		clone.edgeCasesConfigurator = configurator;
		return clone;
	}

	@Override
	public boolean equals(Object o) {
		if (this == o) return true;
		if (o == null || getClass() != o.getClass()) return false;

		IntegralGeneratingArbitrary that = (IntegralGeneratingArbitrary) o;

		if (!min.equals(that.min)) return false;
		if (!max.equals(that.max)) return false;
		if (!Objects.equals(shrinkingTarget, that.shrinkingTarget)) return false;
		if (!distribution.equals(that.distribution)) return false;
		return LambdaSupport.areEqual(edgeCasesConfigurator, that.edgeCasesConfigurator);
	}

	@Override
	public int hashCode() {
		return HashCodeSupport.hash(min, max, shrinkingTarget);
	}

	private Stream streamDefaultEdgeCases() {
		return streamRawEdgeCases()
			.distinct()
			.filter(aBigInt -> aBigInt.compareTo(min) >= 0 && aBigInt.compareTo(max) <= 0);
	}

	private Stream streamRawEdgeCases() {
		BigInteger[] literalEdgeCases = new BigInteger[]{
			valueOf(-2), valueOf(-1), BigInteger.ZERO, valueOf(2), valueOf(1),
			min, min.add(ONE), max, max.subtract(ONE)
		};
		return shrinkingTarget == null
				   ? Arrays.stream(literalEdgeCases)
				   : Stream.concat(Stream.of(shrinkingTarget), Arrays.stream(literalEdgeCases));
	}

	private BigInteger shrinkingTarget() {
		if (shrinkingTarget == null) {
			return RandomIntegralGenerators.defaultShrinkingTarget(Range.of(min, max));
		} else {
			return shrinkingTarget;
		}
	}

	class RangeIterator implements Iterator {

		BigInteger current = min;

		@Override
		public boolean hasNext() {
			return current.compareTo(max) <= 0;
		}

		@Override
		public BigInteger next() {
			if (!hasNext()) {
				throw new NoSuchElementException();
			}
			BigInteger next = current;
			current = current.add(BigInteger.ONE);
			return next;
		}
	}

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy