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

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

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

import java.util.ArrayList;
import java.util.*;
import java.util.function.*;

import net.jqwik.api.*;
import net.jqwik.api.arbitraries.*;
import net.jqwik.engine.properties.*;
import net.jqwik.engine.properties.arbitraries.randomized.*;

import static java.util.Arrays.*;

import static net.jqwik.engine.properties.UniquenessChecker.*;

abstract class MultivalueArbitraryBase extends TypedCloneable implements StreamableArbitrary {

	protected Arbitrary elementArbitrary;

	protected int minSize = 0;
	protected int maxSize = RandomGenerators.DEFAULT_COLLECTION_SIZE;
	protected Set> uniquenessExtractors = new HashSet<>();
	protected RandomDistribution sizeDistribution = null;

	protected MultivalueArbitraryBase(Arbitrary elementArbitrary) {
		this.elementArbitrary = elementArbitrary;
	}

	@Override
	public StreamableArbitrary ofMinSize(int minSize) {
		if (minSize < 0) {
			String message = String.format("minSize (%s) must be between 0 and 2147483647", minSize);
			throw new IllegalArgumentException(message);
		}

		MultivalueArbitraryBase clone = typedClone();
		clone.minSize = minSize;
		return clone;
	}

	@Override
	public StreamableArbitrary ofMaxSize(int maxSize) {
		if (maxSize < 0) {
			String message = String.format("maxSize (%s) must be between 0 and 2147483647", maxSize);
			throw new IllegalArgumentException(message);
		}
		if (maxSize < minSize) {
			String message = String.format("minSize (%s) must not be larger than maxSize (%s)", minSize, maxSize);
			throw new IllegalArgumentException(message);
		}

		MultivalueArbitraryBase clone = typedClone();
		clone.maxSize = maxSize;
		return clone;
	}

	@Override
	public StreamableArbitrary withSizeDistribution(RandomDistribution distribution) {
		MultivalueArbitraryBase clone = typedClone();
		clone.sizeDistribution = distribution;
		return clone;
	}

	@Override
	public  Arbitrary reduce(R initial, BiFunction accumulator) {
		return this.map(streamable -> {
			// Couldn't find a way to use Stream.reduce since it requires a combinator
			@SuppressWarnings("unchecked")
			R[] result = (R[]) new Object[]{initial};
			Iterable iterable = toIterable(streamable);
			for (T each : iterable) {
				result[0] = accumulator.apply(result[0], each);
			}
			return result[0];
		});
	}

	protected abstract Iterable toIterable(U streamable);

	protected StreamableArbitrary uniqueElements(FeatureExtractor by) {
		MultivalueArbitraryBase clone = typedClone();
		clone.uniquenessExtractors = new HashSet<>(uniquenessExtractors);
		clone.uniquenessExtractors.add(by);
		return clone;
	}

	protected RandomGenerator> createListGenerator(int genSize, boolean withEmbeddedEdgeCases) {
		RandomGenerator elementGenerator = elementGenerator(elementArbitrary, genSize, withEmbeddedEdgeCases);
		return RandomGenerators.list(elementGenerator, minSize, maxSize, genSize, sizeDistribution, uniquenessExtractors);
	}

	protected RandomGenerator elementGenerator(Arbitrary elementArbitrary, int genSize, boolean withEdgeCases) {
		return elementArbitrary.generator(genSize, withEdgeCases);
	}

	protected > EdgeCases edgeCases(
			BiFunction>, Integer, Shrinkable> shrinkableCreator,
			int maxEdgeCases
	) {
		// Optimization. Already handled by EdgeCases.concat(..)
		if (maxEdgeCases <= 0) {
			return EdgeCases.none();
		}

		EdgeCases emptyListEdgeCase = (minSize == 0) ? emptyListEdgeCase(shrinkableCreator) : EdgeCases.none();

		int effectiveMaxEdgeCases = maxEdgeCases - emptyListEdgeCase.size();
		EdgeCases singleElementEdgeCases = (minSize <= 1 && maxSize >= 1)
													  ? fixedSizeEdgeCases(1, shrinkableCreator, effectiveMaxEdgeCases)
													  : EdgeCases.none();

		effectiveMaxEdgeCases = maxEdgeCases - singleElementEdgeCases.size();
		EdgeCases fixedSizeEdgeCases = generateFixedSizeEdgeCases()
												  ? fixedSizeEdgeCases(minSize, shrinkableCreator, effectiveMaxEdgeCases)
												  : EdgeCases.none();

		return EdgeCasesSupport.concat(asList(emptyListEdgeCase, singleElementEdgeCases, fixedSizeEdgeCases), maxEdgeCases);
	}

	private boolean generateFixedSizeEdgeCases() {
		return minSize == maxSize && minSize > 1;
	}

	private > EdgeCases fixedSizeEdgeCases(
			final int fixedSize,
			final BiFunction>, Integer, Shrinkable> shrinkableCreator,
			int maxEdgeCases
	) {
		return EdgeCasesSupport.mapShrinkable(
				elementArbitrary.edgeCases(maxEdgeCases),
				shrinkableT -> {
					List> elements = new ArrayList<>(Collections.nCopies(fixedSize, shrinkableT));
					if (!checkUniquenessOfShrinkables(uniquenessExtractors, elements)) {
						return null;
					}
					return shrinkableCreator.apply(elements, minSize);
				}
		);
	}

	private > EdgeCases emptyListEdgeCase(BiFunction>, Integer, Shrinkable> shrinkableCreator) {
		return EdgeCases.fromSupplier(
				() -> shrinkableCreator.apply(Collections.emptyList(), minSize)
		);
	}

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy