diff options
author | Carlo Zancanaro <carlo@zancanaro.id.au> | 2015-06-03 19:43:14 +1000 |
---|---|---|
committer | Carlo Zancanaro <carlo@zancanaro.id.au> | 2015-06-03 19:43:14 +1000 |
commit | e0fc94269698982d937b80ff5fd5b1ef8ef28cf4 (patch) | |
tree | 22c335361971363d6856a59ef0c54242f92e74e1 /src/main/java/au/id/zancanaro/javacheck/Generator.java | |
parent | 7b1a783b749ab04ab8219ef28f9b1abb0ded6ca4 (diff) |
Change shrinking a bit, add more generators, fix some types, moved suchThat
Shrinking is now done using a "ShrinkStrategy". It's pretty similar to what it
used to be in the end, but instead of generating new ShrinkTree<T>s yourself,
you just generate smaller <T>s, and the generator framework will re-call your
strategy to shrink smaller elements. (So, essentially, ShrinkStrategy.shrink(T
obj) returns an Iterator<T> which then has smaller trees calculated from it.)
Added some more generators. In particular: longs and doubles.
Fixed some types, so now Generator.tuple(integer(), string()) will work. Yay!
Move suchThat to Generator, so now integer().suchThat(x -> x < 10) will work
instead of the old Generators.suchThat(x -> x < 10, integer()), which felt a
bit weird.
Diffstat (limited to 'src/main/java/au/id/zancanaro/javacheck/Generator.java')
-rw-r--r-- | src/main/java/au/id/zancanaro/javacheck/Generator.java | 32 |
1 files changed, 29 insertions, 3 deletions
diff --git a/src/main/java/au/id/zancanaro/javacheck/Generator.java b/src/main/java/au/id/zancanaro/javacheck/Generator.java index 9d88020..103bc69 100644 --- a/src/main/java/au/id/zancanaro/javacheck/Generator.java +++ b/src/main/java/au/id/zancanaro/javacheck/Generator.java @@ -4,6 +4,7 @@ import java.util.Iterator; import java.util.List; import java.util.Random; import java.util.function.Function; +import java.util.function.Predicate; /** * Generators are a way of producing random objects and their associated shrink @@ -63,13 +64,13 @@ public interface Generator<T> { * @return A {@link Generator} returning a {@link List} */ @SafeVarargs - static <T> Generator<List<T>> tuple(Generator<T>... generators) { + static <T> Generator<List<T>> tuple(Generator<? extends T>... generators) { return (random, size) -> { @SuppressWarnings("unchecked") ShrinkTree<T>[] result = (ShrinkTree<T>[]) new ShrinkTree[generators.length]; int index = 0; - for (Generator<T> generator : generators) { - result[index++] = generator.generate(random, size); + for (Generator<? extends T> generator : generators) { + result[index++] = generator.generate(random, size).map(x -> (T) x); } return ShrinkTree.zip(Function.identity(), result); }; @@ -130,6 +131,31 @@ public interface Generator<T> { return (random, size) -> ShrinkTree.join(this.generate(random, size).map(action).map(g -> g.generate(random, size))); } + /** + * Filter the results of this generator to only those matching a given + * predicate. + * + * suchThat will keep trying the generator until either it provides a valid + * value, or a stack overflow error occurs. + * + * <b>Only use this method with predicates which are very likely to + * match.</b> + * + * @param predicate The predicate to match + * @return A new generator resulting from filtering this generator to only + * terms which match the given predicate + */ + default Generator<T> suchThat(Predicate<T> predicate) { + return (random, size) -> { + ShrinkTree<T> result = this.generate(random, size); + if (predicate.test(result.getValue())) { + return result.filter(predicate); + } else { + return this.suchThat(predicate).generate(random, size); + } + }; + } + default Iterator<T> sample(Random random, int maxSize) { return new GeneratorSampleIterator<>(this, random, maxSize); } |