summaryrefslogtreecommitdiff
path: root/src/main/java/au/id/zancanaro/javacheck/Generator.java
diff options
context:
space:
mode:
authorCarlo Zancanaro <carlo@zancanaro.id.au>2015-06-03 19:43:14 +1000
committerCarlo Zancanaro <carlo@zancanaro.id.au>2015-06-03 19:43:14 +1000
commite0fc94269698982d937b80ff5fd5b1ef8ef28cf4 (patch)
tree22c335361971363d6856a59ef0c54242f92e74e1 /src/main/java/au/id/zancanaro/javacheck/Generator.java
parent7b1a783b749ab04ab8219ef28f9b1abb0ded6ca4 (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.java32
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);
}