From 8187f024bae57267af514c5dcb730de09e573e41 Mon Sep 17 00:00:00 2001 From: Carlo Zancanaro Date: Mon, 1 Jun 2015 11:41:16 +1000 Subject: Move packages, make lists shrink in size, generate lists instead of arrays as the 'primitive' operation (issues with generics) --- .../java/au/id/zancanaro/javacheck/Generators.java | 135 +++++++++++++++++++++ 1 file changed, 135 insertions(+) create mode 100644 src/main/java/au/id/zancanaro/javacheck/Generators.java (limited to 'src/main/java/au/id/zancanaro/javacheck/Generators.java') diff --git a/src/main/java/au/id/zancanaro/javacheck/Generators.java b/src/main/java/au/id/zancanaro/javacheck/Generators.java new file mode 100644 index 0000000..ec6a329 --- /dev/null +++ b/src/main/java/au/id/zancanaro/javacheck/Generators.java @@ -0,0 +1,135 @@ +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 sized(size -> + integer(0, size).flatMap(count -> { + @SuppressWarnings("unchecked") + Generator[] gens = (Generator[]) new Generator[count]; + Arrays.fill(gens, gen); + return Generator.tuple(gens); + })).fmap(Collections::unmodifiableList); + } + + 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 Generators.listOf(charGen).fmap(list -> { + StringBuilder builder = new StringBuilder(list.size()); + for (Object c : list) { + builder.append(c); + } + return builder.toString(); + }); + } +} -- cgit v1.2.3