package au.id.zancanaro; import java.util.Arrays; import java.util.Iterator; import java.util.List; import java.util.function.Predicate; public class Generators { public static Generator suchThat(Generator gen, Predicate pred) { return (random, size) -> { RoseTree result = gen.generate(random, size); if (pred.test(result.getValue())) { return result.filter(pred); } else { return suchThat(gen, pred).generate(random, size); } }; } @SafeVarargs public static Generator oneOf(Generator... gens) { return integer(0, gens.length).flatMap(index -> gens[index]); } public static Generator integer(int lower, int upper) { return (random, size) -> { int value = lower + random.nextInt(upper - lower); int bound = lower > 0 ? lower : (upper < 0 ? upper : 0); return new RoseTree<>(value, intShrinkingIterable(value, bound)); }; } public static Generator integer() { return (random, size) -> integer(-size, size).generate(random, size); } public static Generator natural() { return (random, size) -> integer(0, size).generate(random, size); } private static Iterable> intShrinkingIterable(final int value, final int bound) { return () -> new Iterator>() { int curr = value - bound; @Override public boolean hasNext() { return curr != 0; } @Override public RoseTree next() { int prevCurr = curr; curr = curr / 2; return new RoseTree<>(value - prevCurr, intShrinkingIterable(value - prevCurr, bound)); } }; } public static Generator> listOf(Generator gen) { return (random, size) -> integer(0, size).flatMap(count -> { @SuppressWarnings("unchecked") Generator[] gens = (Generator[]) new Generator[count]; Arrays.fill(gens, gen); return Generator.tuple(gens).fmap(Arrays::asList); }).generate(random, size); } }