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

net.jqwik.engine.properties.configurators.UniqueElementsConfigurator Maven / Gradle / Ivy

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

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

import net.jqwik.api.*;
import net.jqwik.api.arbitraries.*;
import net.jqwik.api.configurators.*;
import net.jqwik.api.constraints.*;
import net.jqwik.api.providers.*;
import net.jqwik.engine.support.*;

@SuppressWarnings("unchecked")
public class UniqueElementsConfigurator implements ArbitraryConfigurator {

	@SuppressWarnings("OverlyComplexMethod")
	@Override
	public  Arbitrary configure(Arbitrary arbitrary, TypeUsage targetType) {
		return targetType.findAnnotation(UniqueElements.class).map(uniqueness -> {
			if (arbitrary instanceof ListArbitrary) {
				return (Arbitrary) configureListArbitrary((ListArbitrary) arbitrary, uniqueness);
			}
			if (arbitrary instanceof SetArbitrary) {
				return (Arbitrary) configureSetArbitrary((SetArbitrary) arbitrary, uniqueness);
			}
			if (arbitrary instanceof ArrayArbitrary) {
				return (Arbitrary) configureArrayArbitrary((ArrayArbitrary) arbitrary, uniqueness);
			}
			if (arbitrary instanceof StreamArbitrary) {
				return (Arbitrary) configureStreamArbitrary((StreamArbitrary) arbitrary, uniqueness);
			}
			if (arbitrary instanceof IteratorArbitrary) {
				return (Arbitrary) configureIteratorArbitrary((IteratorArbitrary) arbitrary, uniqueness);
			}
			if (targetType.isAssignableFrom(List.class)) {
				Arbitrary> listArbitrary = (Arbitrary>) arbitrary;
				return (Arbitrary) listArbitrary.filter(l -> isUnique(l, (Function) extractor(uniqueness)));
			}
			if (targetType.isAssignableFrom(Set.class)) {
				Arbitrary> setArbitrary = (Arbitrary>) arbitrary;
				return (Arbitrary) setArbitrary.filter(l -> isUnique(l, (Function) extractor(uniqueness)));
			}
			if (targetType.isArray()) {
				Arbitrary arrayArbitrary = (Arbitrary) arbitrary;
				return (Arbitrary) arrayArbitrary.filter(array -> isUnique(Arrays.asList(array), (Function) extractor(uniqueness)));
			}
			if (targetType.isAssignableFrom(Stream.class)) {
				Arbitrary> streamArbitrary = (Arbitrary>) arbitrary;
				// Since a stream can only be consumed once this is more involved than seems necessary at first glance
				return (Arbitrary) streamArbitrary.map(s -> s.collect(Collectors.toList()))
													 .filter(l -> isUnique(l, (Function) extractor(uniqueness)))
													 .map(Collection::stream);
			}
			if (targetType.isAssignableFrom(Iterator.class)) {
				Arbitrary> iteratorArbitrary = (Arbitrary>) arbitrary;
				// Since an iterator can only be iterated once this is more involved than seems necessary at first glance
				Arbitrary> listArbitrary = iteratorArbitrary.map(this::toList);
				return (Arbitrary) listArbitrary.filter(l -> isUnique(l, (Function) extractor(uniqueness))).map(List::iterator);
			}
			return arbitrary;
		}).orElse(arbitrary);
	}

	private  List toList(Iterator i) {
		List list = new ArrayList<>();
		while (i.hasNext()) {
			list.add(i.next());
		}
		return list;
	}

	private boolean isUnique(Collection list, Function extractor) {
		Set set = list.stream().map(extractor).collect(Collectors.toSet());
		return set.size() == list.size();
	}

	private  Arbitrary configureListArbitrary(ListArbitrary arbitrary, UniqueElements uniqueness) {
		Function extractor = (Function) extractor(uniqueness);
		return arbitrary.uniqueElements(extractor);
	}

	private  Arbitrary configureSetArbitrary(SetArbitrary arbitrary, UniqueElements uniqueness) {
		Function extractor = (Function) extractor(uniqueness);
		return arbitrary.uniqueElements(extractor);
	}

	private  Arbitrary configureArrayArbitrary(ArrayArbitrary arbitrary, UniqueElements uniqueness) {
		Function extractor = (Function) extractor(uniqueness);
		return arbitrary.uniqueElements(extractor);
	}

	private  Arbitrary configureStreamArbitrary(StreamArbitrary arbitrary, UniqueElements uniqueness) {
		Function extractor = (Function) extractor(uniqueness);
		return arbitrary.uniqueElements(extractor);
	}

	private  Arbitrary configureIteratorArbitrary(IteratorArbitrary arbitrary, UniqueElements uniqueness) {
		Function extractor = (Function) extractor(uniqueness);
		return arbitrary.uniqueElements(extractor);
	}

	private Function extractor(UniqueElements uniqueness) {
		Class> extractorClass = uniqueness.by();
		return extractorClass.equals(UniqueElements.NOT_SET.class)
				? Function.identity()
				// TODO: Create instance in context of test instance.
				//       This requires an extension of ArbitraryConfiguration interface
				//       to provide access to PropertyLifecycleContext
				: JqwikReflectionSupport.newInstanceWithDefaultConstructor(extractorClass);
	}

}