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

net.jqwik.engine.facades.ArbitrariesFacadeImpl Maven / Gradle / Ivy

The newest version!
package net.jqwik.engine.facades;

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

import net.jqwik.api.*;
import net.jqwik.api.arbitraries.*;
import net.jqwik.api.domains.*;
import net.jqwik.api.providers.*;
import net.jqwik.api.stateful.*;
import net.jqwik.api.support.*;
import net.jqwik.engine.execution.lifecycle.*;
import net.jqwik.engine.properties.*;
import net.jqwik.engine.properties.arbitraries.*;
import net.jqwik.engine.properties.arbitraries.randomized.*;
import net.jqwik.engine.properties.stateful.*;

import org.jspecify.annotations.*;

import static net.jqwik.engine.properties.arbitraries.ArbitrariesSupport.*;

/**
 * Is loaded through reflection in api module
 */
public class ArbitrariesFacadeImpl extends Arbitraries.ArbitrariesFacade {

	@Override
	public  Arbitrary just(T value) {
		return new JustArbitrary<>(value);
	}

	@Override
	public  Arbitrary oneOf(Collection> choices) {
		return new OneOfArbitrary<>(choices);
	}

	@Override
	public  ActionSequenceArbitrary sequences(Arbitrary> actionArbitrary) {
		return new DefaultActionSequenceArbitrary<>(actionArbitrary);
	}

	@Override
	public  Arbitrary frequencyOf(List>> frequencies) {
		List>> aboveZeroFrequencies =
			frequencies.stream().filter(f -> f.get1() > 0).collect(Collectors.toList());

		if (aboveZeroFrequencies.size() == 1) {
			return aboveZeroFrequencies.get(0).get2();
		}
		if (aboveZeroFrequencies.isEmpty()) {
			String message = "frequencyOf() must be called with at least one choice with a frequency > 0";
			throw new JqwikException(message);
		}

		return new FrequencyOfArbitrary<>(aboveZeroFrequencies);
	}

	@Override
	public IntegerArbitrary integers() {
		return new DefaultIntegerArbitrary();
	}

	@Override
	public LongArbitrary longs() {
		return new DefaultLongArbitrary();
	}

	@Override
	public BigIntegerArbitrary bigIntegers() {
		return new DefaultBigIntegerArbitrary();
	}

	@Override
	public FloatArbitrary floats() {
		return new DefaultFloatArbitrary();
	}

	@Override
	public BigDecimalArbitrary bigDecimals() {
		return new DefaultBigDecimalArbitrary();
	}

	@Override
	public DoubleArbitrary doubles() {
		return new DefaultDoubleArbitrary();
	}

	@Override
	public ByteArbitrary bytes() {
		return new DefaultByteArbitrary();
	}

	@Override
	public ShortArbitrary shorts() {
		return new DefaultShortArbitrary();
	}

	@Override
	public StringArbitrary strings() {
		return new DefaultStringArbitrary();
	}

	@Override
	public CharacterArbitrary chars() {
		return new DefaultCharacterArbitrary();
	}

	@Override
	public  Arbitrary lazy(Supplier> arbitrarySupplier) {
		return new LazyArbitrary<>(arbitrarySupplier);
	}

	@Override
	public  Arbitrary lazyOf(List>> suppliers) {
		int hashIdentifier = calculateIdentifier(suppliers.size());
		return LazyOfArbitrary.of(hashIdentifier, suppliers);
	}

	@Override
	public  TraverseArbitrary traverse(Class targetType, TraverseArbitrary.Traverser traverser) {
		return new DefaultTraverseArbitrary<>(targetType, traverser);
	}

	@Override
	public Arbitrary of(char[] chars) {
		return new ChooseCharacterArbitrary(chars);
	}

	@Override
	public  Arbitrary of(Collection values) {
		List valueList = values instanceof List ? (List) values : new ArrayList<>(values);
		return new ChooseValueArbitrary<>(valueList);
	}

	@Override
	public  Arbitrary create(Supplier supplier) {
		return new CreateArbitrary<>(supplier);
	}

	@Override
	public  Arbitrary> shuffle(List values) {
		return new ShuffleArbitrary<>(values);
	}

	@Override
	public  Arbitrary fromGenerator(IntFunction> generatorSupplier) {
		return new FromGeneratorWithSizeArbitrary<>(generatorSupplier);
	}

	@Override
	public  Arbitrary frequency(List> frequencies) {
		List> frequenciesAbove0 = frequencies.stream()
																	  .filter(f -> f.get1() > 0)
																	  .collect(Collectors.toList());

		if (frequenciesAbove0.isEmpty()) {
			String message = "frequency() must be called with at least one value with a frequency > 0";
			throw new JqwikException(message);
		}
		if (frequenciesAbove0.size() == 1) {
			return new JustArbitrary<>(frequenciesAbove0.get(0).get2());
		}

		return new FrequencyArbitrary<>(frequenciesAbove0);
	}

	/**
	 * The calculated hash is supposed to be the same for the same callers of Arbitraries.lazyOf()
	 * This is important to have a single instance of LazyOfArbitrary for the same code.
	 */
	private static int calculateIdentifier(int numberOfSuppliers) {
		try {
			throw new RuntimeException();
		} catch (RuntimeException rte) {
			Optional optionalHash =
				Arrays.stream(rte.getStackTrace())
					  .filter(stackTraceElement -> !stackTraceElement.getClassName().equals(ArbitrariesFacadeImpl.class.getName()))
					  .filter(stackTraceElement -> !stackTraceElement.getClassName().equals(Arbitraries.class.getName()))
					  .findFirst()
					  .map(stackTraceElement -> HashCodeSupport.hash(
						  stackTraceElement.getClassName(),
						  stackTraceElement.getMethodName(),
						  stackTraceElement.getLineNumber(),
						  numberOfSuppliers
					  ));
			return optionalHash.orElse(0);
		}
	}

	@Override
	public  Arbitrary defaultFor(Class type, Class[] typeParameters) {
		TypeUsage[] genericTypeParameters =
			Arrays.stream(typeParameters)
				  .map(TypeUsage::of)
				  .toArray(TypeUsage[]::new);
		return defaultFor(TypeUsage.of(type, genericTypeParameters), typeUsage -> {throw new CannotFindArbitraryException(typeUsage);});
	}

	@SuppressWarnings("unchecked")
	@Override
	public  Arbitrary defaultFor(TypeUsage typeUsage, Function> noDefaultResolver) {
		Set> arbitraries = allDefaultsFor(typeUsage, noDefaultResolver);
		if (arbitraries.isEmpty()) {
			return noDefaultResolver.apply(typeUsage);
		}

		List> arbitrariesList = new ArrayList<>();
		arbitraries.forEach(arbitrary -> arbitrariesList.add((Arbitrary) arbitrary));
		return Arbitraries.oneOf(arbitrariesList);
	}

	@Override
	public  TypeArbitrary forType(Class targetType) {
		return new DefaultTypeArbitrary<>(targetType);
	}

	@Override
	public  MapArbitrary maps(Arbitrary keysArbitrary, Arbitrary valuesArbitrary) {
		// The map cannot be larger than the max number of possible keys
		return new DefaultMapArbitrary<>(keysArbitrary, valuesArbitrary)
				   .ofMaxSize(maxNumberOfElements(keysArbitrary, RandomGenerators.DEFAULT_COLLECTION_SIZE));
	}

	@Override
	public  Arbitrary> entries(Arbitrary keysArbitrary, Arbitrary valuesArbitrary) {
		return Combinators.combine(keysArbitrary, valuesArbitrary).as(AbstractMap.SimpleEntry::new);
	}

	private static Set> allDefaultsFor(TypeUsage typeUsage, Function> noDefaultResolver) {
		DomainContext domainContext = CurrentDomainContext.get();
		Set> unconfiguredArbitraries = createDefaultArbitraries(typeUsage, noDefaultResolver, domainContext);
		return configureDefaultArbitraries(typeUsage, domainContext, unconfiguredArbitraries);
	}

	private static Set> configureDefaultArbitraries(
		TypeUsage typeUsage,
		DomainContext domainContext,
		Set> unconfiguredArbitraries
	) {
		RegisteredArbitraryConfigurer defaultArbitraryConfigurer = new RegisteredArbitraryConfigurer(domainContext.getArbitraryConfigurators());
		return unconfiguredArbitraries.stream()
									  .map(arbitrary -> defaultArbitraryConfigurer.configure(arbitrary, typeUsage))
									  .collect(CollectorsSupport.toLinkedHashSet());
	}

	private static Set> createDefaultArbitraries(
		TypeUsage typeUsage,
		Function> noDefaultResolver,
		DomainContext domainContext
	) {
		RegisteredArbitraryResolver defaultArbitraryResolver = new RegisteredArbitraryResolver(domainContext.getArbitraryProviders());
		ArbitraryProvider.SubtypeProvider subtypeProvider = subtypeUsage -> {
			Set> subtypeArbitraries = allDefaultsFor(subtypeUsage, noDefaultResolver);
			if (subtypeArbitraries.isEmpty()) {
				return Collections.singleton(noDefaultResolver.apply(subtypeUsage));
			}
			return subtypeArbitraries;
		};
		return defaultArbitraryResolver.resolve(typeUsage, subtypeProvider);
	}

	@Override
	public  Arbitrary recursive(
		Supplier> base,
		Function, ? extends Arbitrary> recur,
		int minDepth,
		int maxDepth
	) {
		if (minDepth < 0) {
			String message = String.format("minDepth <%s> must be >= 0.", minDepth);
			throw new IllegalArgumentException(message);
		}
		if (minDepth > maxDepth) {
			String message = String.format("minDepth <%s> must not be > maxDepth <%s>", minDepth, maxDepth);
			throw new IllegalArgumentException(message);
		}

		if (minDepth == maxDepth) {
			return recursive(base, recur, minDepth);
		} else {
			Arbitrary depths = Arbitraries.integers().between(minDepth, maxDepth)
												   .withDistribution(RandomDistribution.uniform())
												   .edgeCases(c -> c.includeOnly(minDepth, maxDepth));
			return depths.flatMap(depth -> recursive(base, recur, depth));
		}
	}

	private  Arbitrary recursive(
		Supplier> base,
		Function, ? extends Arbitrary> recur,
		int depth
	) {
		return new RecursiveArbitrary<>(base, recur, depth);
	}
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy