package au.id.zancanaro.javacheck; import java.util.Arrays; import java.util.Collections; import java.util.Iterator; import java.util.List; import java.util.function.Function; import java.util.function.Predicate; public final class Generators { private Generators() { } public static Generator sized(Function> makeGenerator) { return (random, size) -> makeGenerator.apply(size).generate(random, size); } 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 elements(T[] elements) { return elements(Arrays.asList(elements)); } public static Generator elements(List elements) { return integer(0, elements.size()).fmap(elements::get); } public static Generator bool() { return (random, size) -> random.nextBoolean() ? new RoseTree<>(true, Collections.singletonList(new RoseTree<>(false, Collections.emptyList()))) : new RoseTree<>(false, Collections.emptyList()); } 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 sized(size -> integer(-size, size)); } public static Generator natural() { return sized(size -> integer(0, 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) -> { Generator countGen = sized(s -> integer(0, s)); int count = countGen.generate(random, size).getValue(); return Generator.list(count, gen).generate(random, size); }; } public static Generator character() { return integer(0, 256).fmap(i -> (char) i.intValue()); } public static Generator asciiCharacter() { return integer(32, 127).fmap(i -> (char) i.intValue()); } public static Generator alphaNumericCharacter() { return oneOf( integer(48, 58), integer(65, 91), integer(97, 123)).fmap(i -> (char) i.intValue()); } public static Generator alphaCharacter() { return oneOf( integer(65, 91), integer(97, 123)).fmap(i -> (char) i.intValue()); } private static String makeString(Character[] arr) { StringBuilder builder = new StringBuilder(arr.length); for (Character c : arr) { builder.append(c); } return builder.toString(); } public static Generator string() { return stringOf(character()); } public static Generator stringOf(Generator charGen) { return listOf(charGen).fmap(list -> { char[] chars = new char[list.size()]; int i = 0; for (Character c : list) { chars[i++] = c; } return String.valueOf(chars); // return new String(chars); }); } }