summaryrefslogtreecommitdiff
path: root/src/main/java/au/id/zancanaro/javacheck/Generator.java
diff options
context:
space:
mode:
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);
}