summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/main/java/au/id/zancanaro/Generators.java37
-rw-r--r--src/main/java/au/id/zancanaro/PropertyTestRunner.java27
-rw-r--r--src/main/java/au/id/zancanaro/RoseTree.java1
-rw-r--r--src/test/java/au/id/zancanaro/PropertyTests.java43
4 files changed, 80 insertions, 28 deletions
diff --git a/src/main/java/au/id/zancanaro/Generators.java b/src/main/java/au/id/zancanaro/Generators.java
index 5b025fa..852a290 100644
--- a/src/main/java/au/id/zancanaro/Generators.java
+++ b/src/main/java/au/id/zancanaro/Generators.java
@@ -1,6 +1,8 @@
package au.id.zancanaro;
+import java.util.Arrays;
import java.util.Iterator;
+import java.util.List;
import java.util.function.Predicate;
public class Generators {
@@ -15,28 +17,51 @@ public class Generators {
};
}
+ @SafeVarargs
+ public static <T> Generator<T> oneOf(Generator<T>... gens) {
+ return integer(0, gens.length).flatMap(index -> gens[index]);
+ }
+
public static Generator<Integer> integer() {
+ return (random, size) -> integer(-size, size).generate(random, size);
+ }
+
+ public static Generator<Integer> natural() {
+ return (random, size) -> integer(0, size).generate(random, size);
+ }
+
+ public static Generator<Integer> integer(int lower, int upper) {
return (random, size) -> {
- int value = random.nextInt(size);
- return new RoseTree<>(value, intShrinkingIterable(value));
+ int value = lower + random.nextInt(upper - lower);
+ int bound = lower > 0 ? lower : (upper < 0 ? upper : 0);
+ return new RoseTree<>(value, intShrinkingIterable(value, bound));
};
}
- private static Iterable<RoseTree<Integer>> intShrinkingIterable(final int value) {
+ private static Iterable<RoseTree<Integer>> intShrinkingIterable(final int value, final int bound) {
return () -> new Iterator<RoseTree<Integer>>() {
- int curr = value;
+ int curr = value - bound;
@Override
public boolean hasNext() {
- return curr > 0;
+ return curr != 0;
}
@Override
public RoseTree<Integer> next() {
int prevCurr = curr;
curr = curr / 2;
- return new RoseTree<>(value - prevCurr, intShrinkingIterable(value - prevCurr));
+ return new RoseTree<>(value - prevCurr, intShrinkingIterable(value - prevCurr, bound));
}
};
}
+
+ public static <T> Generator<List<T>> listOf(Generator<T> gen) {
+ return (random, size) -> integer(0, size).flatMap(count -> {
+ @SuppressWarnings("unchecked")
+ Generator<T>[] gens = (Generator<T>[]) new Generator[count];
+ Arrays.fill(gens, gen);
+ return Generator.tuple(gens).fmap(Arrays::asList);
+ }).generate(random, size);
+ }
}
diff --git a/src/main/java/au/id/zancanaro/PropertyTestRunner.java b/src/main/java/au/id/zancanaro/PropertyTestRunner.java
index b3563ff..ea36341 100644
--- a/src/main/java/au/id/zancanaro/PropertyTestRunner.java
+++ b/src/main/java/au/id/zancanaro/PropertyTestRunner.java
@@ -178,7 +178,7 @@ public class PropertyTestRunner extends BlockJUnit4ClassRunner {
runTest(tree.getValue());
assumptionsViolated = 0;
} catch (AssumptionViolatedException ex) {
- i--;
+ numTests++;
if (assumptionsViolated++ == 50) {
throw new Error("Violated 50 assumptions in a row: failing test");
}
@@ -193,19 +193,22 @@ public class PropertyTestRunner extends BlockJUnit4ClassRunner {
private ShrinkResult shrink(RoseTree<Object[]> failed, Throwable originalEx) {
ShrinkResult smallest = new ShrinkResult(failed.getValue(), originalEx);
Iterator<RoseTree<Object[]>> trees = failed.getChildren();
+ Set<List<Object>> seenArgs = new HashSet<>();
while (trees.hasNext()) {
RoseTree<Object[]> tree = trees.next();
- try {
- runTest(tree.getValue());
- } catch (AssumptionViolatedException ex) {
- // ignore, because it's not useful
- } catch (Throwable ex) {
- smallest = new ShrinkResult(tree.getValue(), ex);
- Iterator<RoseTree<Object[]>> children = tree.getChildren();
- if (children.hasNext()) {
- trees = children;
- } else {
- break;
+ if (seenArgs.add(Arrays.asList(tree.getValue()))) {
+ try {
+ runTest(tree.getValue());
+ } catch (AssumptionViolatedException ex) {
+ // ignore, because it's not useful
+ } catch (Throwable ex) {
+ smallest = new ShrinkResult(tree.getValue(), ex);
+ Iterator<RoseTree<Object[]>> children = tree.getChildren();
+ if (children.hasNext()) {
+ trees = children;
+ } else {
+ break;
+ }
}
}
}
diff --git a/src/main/java/au/id/zancanaro/RoseTree.java b/src/main/java/au/id/zancanaro/RoseTree.java
index bbcb949..6ba5c1c 100644
--- a/src/main/java/au/id/zancanaro/RoseTree.java
+++ b/src/main/java/au/id/zancanaro/RoseTree.java
@@ -1,5 +1,6 @@
package au.id.zancanaro;
+import java.io.OutputStream;
import java.util.Arrays;
import java.util.Collections;
import java.util.Iterator;
diff --git a/src/test/java/au/id/zancanaro/PropertyTests.java b/src/test/java/au/id/zancanaro/PropertyTests.java
index 374a974..dd595e1 100644
--- a/src/test/java/au/id/zancanaro/PropertyTests.java
+++ b/src/test/java/au/id/zancanaro/PropertyTests.java
@@ -1,35 +1,58 @@
package au.id.zancanaro;
import au.id.zancanaro.annotations.Property;
+import au.id.zancanaro.annotations.Seed;
+import org.hamcrest.CoreMatchers;
import org.junit.*;
import org.junit.experimental.theories.DataPoint;
+import org.junit.matchers.JUnitMatchers;
import org.junit.runner.RunWith;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
@RunWith(PropertyTestRunner.class)
public class PropertyTests {
public static Generator<Integer> gen = Generators.integer();
+ public static Generator<List<Integer>> list = Generators.listOf(Generators.integer());
- @Test
- public void testblah() throws Exception {
- Assert.assertEquals(10, 11);
-
- }
-
+ @Ignore
@Property
public void aIsNotOdd(int a, int b) {
- Assume.assumeFalse(a % 2 == 1);
Assert.assertFalse(a % 2 == 1);
}
+ @Ignore
@Property
public void aIsNotLessThanB(int a, int b) {
- Assume.assumeFalse(a < b);
Assert.assertFalse(a < b);
}
+ @Ignore
@Property
public void aPlusBLessThanOneHundred(int a, int b) {
- Assert.assertTrue("a plus b is five", a + b == 5);
- Assert.assertEquals(a + b, 5);
+ Assert.assertTrue(a + b < 100);
+ }
+
+ @Property
+ public void sortingIsIdempotent(List<Integer> list) {
+ List<Integer> left = new ArrayList<>(list);
+ Collections.sort(left);
+
+ List<Integer> right = new ArrayList<>(list);
+ Collections.sort(right);
+ Collections.sort(right);
+
+ Assert.assertEquals(left, right);
+ }
+
+ @Property
+ public void reverseIsItsOwnInverse(List<Integer> list) {
+ List<Integer> reversed = new ArrayList<>(list);
+ Collections.reverse(reversed);
+ Collections.reverse(reversed);
+
+ Assert.assertEquals(list, reversed);
}
}