diff options
author | Carlo Zancanaro <carlo@zancanaro.id.au> | 2015-05-31 23:47:38 +1000 |
---|---|---|
committer | Carlo Zancanaro <carlo@zancanaro.id.au> | 2015-05-31 23:47:38 +1000 |
commit | a4b5a5f904fe9f21697cd8fc8998c7e6e86306af (patch) | |
tree | b5f66d8825219f05c4e1903434a121eb40e48cbe | |
parent | 199037f9c80afd885f1f536d91b40a8397cd6bf2 (diff) |
Lots more updates
+ add a list generator, and some more number generators.
+ bugfix the assumption checking stuff: if it failed once it would pretty
likely continue to fail!
+ write some simple actualy properties:
- reverse . reverse = id
- sort . sort = sort
-rw-r--r-- | src/main/java/au/id/zancanaro/Generators.java | 37 | ||||
-rw-r--r-- | src/main/java/au/id/zancanaro/PropertyTestRunner.java | 27 | ||||
-rw-r--r-- | src/main/java/au/id/zancanaro/RoseTree.java | 1 | ||||
-rw-r--r-- | src/test/java/au/id/zancanaro/PropertyTests.java | 43 |
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); } } |