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

net.jqwik.engine.properties.shrinking.CombinedShrinkable Maven / Gradle / Ivy

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

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

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

public class CombinedShrinkable implements Shrinkable {
	private final List> shrinkables;
	private final Function, T> combinator;
	private final T value;

	public CombinedShrinkable(List> shrinkables, Function, T> combinator) {
		this.shrinkables = shrinkables;
		this.combinator = combinator;
		this.value = combinator.apply(toValues(shrinkables));
	}

	@Override
	public T value() {
		return value;
	}

	private List toValues(List> shrinkables) {
		return shrinkables.stream().map(Shrinkable::value).collect(Collectors.toList());
	}

	@Override
	public ShrinkingSequence shrink(Falsifier falsifier) {
		return new CombinedShrinkingSequence(falsifier);
	}

	@Override
	public ShrinkingDistance distance() {
		return ShrinkingDistance.combine(shrinkables);
	}

	private class CombinedShrinkingSequence implements ShrinkingSequence {

		final private ElementsShrinkingSequence elementsSequence;

		private CombinedShrinkingSequence(Falsifier falsifier) {
			Falsifier> combinedFalsifier = elements -> {
				try {
					T value = combinator.apply(elements);
					return falsifier.test(value);
				} catch (GenerationError generationError) {
					// Ignore Generation errors
					return true;
				}
			};
			elementsSequence = new ElementsShrinkingSequence<>(
				shrinkables,
				combinedFalsifier,
				ShrinkingDistance::combine
			);
		}

		@Override
		public void init(FalsificationResult initialCurrent) {
			// Only throwable is used in elementsSequence
			elementsSequence.init(FalsificationResult.falsified(
				Shrinkable.unshrinkable(new ArrayList<>()),
				initialCurrent.throwable().orElse(null)
			));
		}

		@Override
		public boolean next(Runnable count, Consumer> falsifiedReporter) {
			Consumer>> combinedReporter =
				result -> falsifiedReporter.accept(result.map(shrinkable -> shrinkable.map(combinator)));
			return elementsSequence.next(count, combinedReporter);
		}

		@Override
		public FalsificationResult current() {
			return elementsSequence.current().map(shrinkable -> shrinkable.map(combinator));
		}
	}
}