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

net.jqwik.engine.properties.arbitraries.randomized.ContainerGenerator Maven / Gradle / Ivy

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

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

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

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

class ContainerGenerator implements RandomGenerator {
	private final RandomGenerator elementGenerator;
	private final Function>, Shrinkable> createShrinkable;
	private final int minSize;
	private final int genSize;
	private final RandomDistribution sizeDistribution;
	private final Collection> uniquenessExtractors;

	private boolean noDuplicatesHadToBeSwitchedOff = false;

	private Function sizeGenerator;

	private static Function sizeGenerator(
		int minSize,
		int maxSize,
		int genSize,
		RandomDistribution sizeDistribution
	) {
		return SizeGenerator.create(minSize, maxSize, genSize, sizeDistribution);
	}

	ContainerGenerator(
		RandomGenerator elementGenerator,
		Function>, Shrinkable> createShrinkable,
		int minSize,
		int maxSize,
		int genSize,
		RandomDistribution sizeDistribution,
		Collection> uniquenessExtractors
	) {
		this.elementGenerator = elementGenerator;
		this.createShrinkable = createShrinkable;
		this.minSize = minSize;
		this.genSize = genSize;
		this.sizeDistribution = sizeDistribution;
		this.uniquenessExtractors = uniquenessExtractors;
		this.sizeGenerator = sizeGenerator(minSize, maxSize, genSize, sizeDistribution);
	}

	@Override
	public Shrinkable next(Random random) {
		int listSize = sizeGenerator.apply(random);
		List> listOfShrinkables = new ArrayList<>();

		// Raise probability for no duplicates even in large containers to approx 2 percent
		// boolean noDuplicates = false;
		boolean noDuplicates = !noDuplicatesHadToBeSwitchedOff
								   && listSize >= 2
								   && uniquenessExtractors.isEmpty()
								   && random.nextInt(100) <= 2;

		boolean canUseSetForValues = uniquenessExtractors.isEmpty() || uniquenessExtractors.contains(FeatureExtractor.identity());
		Collection existingValues = canUseSetForValues ? new HashSet<>() : new ArrayList<>();

		while (listOfShrinkables.size() < listSize) {
			try {
				Shrinkable next = nextUntilAccepted(random, existingValues, elementGenerator::next, noDuplicates);
				listOfShrinkables.add(next);
			} catch (TooManyFilterMissesException tooManyFilterMissesException) {
				// Switch off noDuplicates
				if (noDuplicates) {
					noDuplicates = false;
					noDuplicatesHadToBeSwitchedOff = true;
				} else {
					// Ignore if list.size() >= minSize, because uniqueness constraints influence possible max size
					if (listOfShrinkables.size() < minSize) {
						throw tooManyFilterMissesException;
					} else {
						listSize = listOfShrinkables.size();
						sizeGenerator = sizeGenerator(minSize, listSize, genSize, sizeDistribution);
					}
				}
			}

		}
		return createShrinkable.apply(listOfShrinkables);
	}

	private Shrinkable nextUntilAccepted(
		Random random,
		Collection existingValues,
		Function> fetchShrinkable,
		boolean noDuplicates
	) {
		return MaxTriesLoop.loop(
			() -> true,
			next -> {
				next = fetchShrinkable.apply(random);
				T value = next.value();
				if (noDuplicates && existingValues.contains(value)) {
					return Tuple.of(false, next);
				}
				if (!checkSpecifiedUniqueness(existingValues, value)) {
					return Tuple.of(false, next);
				}
				existingValues.add(value);
				return Tuple.of(true, next);
			},
			(maxMisses) -> {
				String message = String.format("Trying to fulfill uniqueness constraint missed more than %s times.", maxMisses);
				return new TooManyFilterMissesException(message);
			},
                10000);
	}

	private boolean checkSpecifiedUniqueness(Collection elements, T value) {
		return checkValueUniqueIn(uniquenessExtractors, value, elements);
	}

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy