From 7eabc41ad41e0da58fff2a6bb04212ea0cd3baa2 Mon Sep 17 00:00:00 2001 From: Carlo Zancanaro Date: Wed, 3 Jun 2015 12:39:14 +1000 Subject: Add some more interesting tests --- .../java/au/id/zancanaro/javacheck/Generator.java | 5 + .../javacheck/GeneratorSampleIterator.java | 30 ++++++ .../java/au/id/zancanaro/javacheck/Generators.java | 10 +- .../zancanaro/javacheck/ListFunctorRulesTest.java | 110 +++++++++++++++++++++ .../javacheck/OptionalFunctorRulesTest.java | 110 +++++++++++++++++++++ .../javacheck/SimpleListOperationsTest.java | 48 +++++++++ .../javacheck/junit/SimpleListOperationsTest.java | 44 --------- 7 files changed, 310 insertions(+), 47 deletions(-) create mode 100644 src/main/java/au/id/zancanaro/javacheck/GeneratorSampleIterator.java create mode 100644 src/test/java/au/id/zancanaro/javacheck/ListFunctorRulesTest.java create mode 100644 src/test/java/au/id/zancanaro/javacheck/OptionalFunctorRulesTest.java create mode 100644 src/test/java/au/id/zancanaro/javacheck/SimpleListOperationsTest.java delete mode 100644 src/test/java/au/id/zancanaro/javacheck/junit/SimpleListOperationsTest.java diff --git a/src/main/java/au/id/zancanaro/javacheck/Generator.java b/src/main/java/au/id/zancanaro/javacheck/Generator.java index c28d967..557cf97 100644 --- a/src/main/java/au/id/zancanaro/javacheck/Generator.java +++ b/src/main/java/au/id/zancanaro/javacheck/Generator.java @@ -1,5 +1,6 @@ package au.id.zancanaro.javacheck; +import java.util.Iterator; import java.util.List; import java.util.Random; import java.util.function.Function; @@ -128,4 +129,8 @@ public interface Generator { default Generator flatMap(Function> action) { return (random, size) -> RoseTree.join(this.generate(random, size).map(action).map(g -> g.generate(random, size))); } + + default Iterator sample(Random random, int maxSize) { + return new GeneratorSampleIterator<>(this, random, maxSize); + } } diff --git a/src/main/java/au/id/zancanaro/javacheck/GeneratorSampleIterator.java b/src/main/java/au/id/zancanaro/javacheck/GeneratorSampleIterator.java new file mode 100644 index 0000000..f7d8e17 --- /dev/null +++ b/src/main/java/au/id/zancanaro/javacheck/GeneratorSampleIterator.java @@ -0,0 +1,30 @@ +package au.id.zancanaro.javacheck; + +import java.util.Iterator; +import java.util.Random; + +public class GeneratorSampleIterator implements Iterator { + private final Generator generator; + private final Random random; + private final int maxSize; + private int size; + + public GeneratorSampleIterator(Generator generator, Random random, int maxSize) { + this.generator = generator; + this.random = random; + this.maxSize = maxSize; + this.size = 0; + } + + @Override + public boolean hasNext() { + return true; + } + + @Override + public T next() { + return generator + .generate(random, Math.min(size++, maxSize)) + .getValue(); + } +} diff --git a/src/main/java/au/id/zancanaro/javacheck/Generators.java b/src/main/java/au/id/zancanaro/javacheck/Generators.java index 548bd29..4049149 100644 --- a/src/main/java/au/id/zancanaro/javacheck/Generators.java +++ b/src/main/java/au/id/zancanaro/javacheck/Generators.java @@ -91,10 +91,12 @@ public final class Generators { return (random, size) -> { Generator countGen = sized(s -> integer(minElements, maxElements)); int count = countGen.generate(random, size).getValue(); - return Generator.list(count, gen).generate(random, size) + return Generator.list(count, gen) + .generate(random, size) .filter(list -> minElements <= list.size() - && list.size() < maxElements); + && list.size() < maxElements) + .map(Collections::unmodifiableList); }; } @@ -102,7 +104,9 @@ public final class Generators { return (random, size) -> { Generator countGen = sized(s -> integer(0, s)); int count = countGen.generate(random, size).getValue(); - return Generator.list(count, gen).generate(random, size); + return Generator.list(count, gen) + .generate(random, size) + .map(Collections::unmodifiableList); }; } diff --git a/src/test/java/au/id/zancanaro/javacheck/ListFunctorRulesTest.java b/src/test/java/au/id/zancanaro/javacheck/ListFunctorRulesTest.java new file mode 100644 index 0000000..4e516a2 --- /dev/null +++ b/src/test/java/au/id/zancanaro/javacheck/ListFunctorRulesTest.java @@ -0,0 +1,110 @@ +package au.id.zancanaro.javacheck; + +import au.id.zancanaro.javacheck.annotations.DataSource; +import au.id.zancanaro.javacheck.annotations.Property; +import au.id.zancanaro.javacheck.junit.Properties; +import org.junit.runner.RunWith; + +import java.util.List; +import java.util.function.Function; +import java.util.stream.Collectors; + +import static au.id.zancanaro.javacheck.Generators.*; +import static org.junit.Assert.assertEquals; + +@RunWith(Properties.class) +public class ListFunctorRulesTest { + + private final static int runs = 1000; + private final static int maxSize = 1000; + + @DataSource + public static Generator> listOfIntegers = listOf(integer()); + + @DataSource + public static Generator> integerFunction = + oneOf( + integer().map(ListFunctorRulesTest::plusI), + integer().map(ListFunctorRulesTest::timesI), + integer().map(ListFunctorRulesTest::constantlyI)); + + @Property(maxSize = maxSize, runs = runs) + public void mappingCompositionsWithStreams( + List list, + Function f, + Function g) { + List left = list.stream() + .map(g) + .map(f) + .collect(Collectors.toList()); + + List right = list.stream() + .map(x -> f.apply(g.apply(x))) + .collect(Collectors.toList()); + + assertEquals(left, right); + } + + @Property(maxSize = maxSize, runs = runs) + public void mappingCompositionsWithIntermediateList( + List list, + Function f, + Function g) { + List intermediate = list.stream().map(g).collect(Collectors.toList()); + List left = intermediate.stream().map(f).collect(Collectors.toList()); + + List right = list.stream() + .map(x -> f.apply(g.apply(x))) + .collect(Collectors.toList()); + + assertEquals(left, right); + } + + @Property(maxSize = maxSize, runs = runs) + public void mapIdentityIsIdentity(List list) { + List mapped = list.stream().map(x -> x).collect(Collectors.toList()); + + assertEquals(list, mapped); + } + + private static Function plusI(final int i) { + return new Function() { + @Override + public Integer apply(Integer integer) { + return i + integer; + } + + @Override + public String toString() { + return "x -> x + " + i; + } + }; + } + + private static Function timesI(final int i) { + return new Function() { + @Override + public Integer apply(Integer integer) { + return i * integer; + } + + @Override + public String toString() { + return "x -> x * " + i; + } + }; + } + private static Function constantlyI(final int i) { + return new Function() { + @Override + public Integer apply(Integer integer) { + return i; + } + + @Override + public String toString() { + return "x -> " + i; + } + }; + } +} diff --git a/src/test/java/au/id/zancanaro/javacheck/OptionalFunctorRulesTest.java b/src/test/java/au/id/zancanaro/javacheck/OptionalFunctorRulesTest.java new file mode 100644 index 0000000..b13fb8b --- /dev/null +++ b/src/test/java/au/id/zancanaro/javacheck/OptionalFunctorRulesTest.java @@ -0,0 +1,110 @@ +package au.id.zancanaro.javacheck; + +import au.id.zancanaro.javacheck.annotations.DataSource; +import au.id.zancanaro.javacheck.annotations.Property; +import au.id.zancanaro.javacheck.junit.Properties; +import org.junit.runner.RunWith; + +import java.util.Optional; +import java.util.function.Function; + +import static au.id.zancanaro.javacheck.Generator.pure; +import static au.id.zancanaro.javacheck.Generators.integer; +import static au.id.zancanaro.javacheck.Generators.oneOf; +import static org.junit.Assert.assertEquals; + +@RunWith(Properties.class) +public class OptionalFunctorRulesTest { + + private final static int runs = 1000; + private final static int maxSize = 1000; + + @DataSource + public static Generator> listOfIntegers = oneOf( + pure(Optional.empty()), + integer().map(Optional::of)); + + @DataSource + public static Generator> integerFunction = + oneOf( + integer().map(OptionalFunctorRulesTest::plusI), + integer().map(OptionalFunctorRulesTest::timesI), + integer().map(OptionalFunctorRulesTest::constantlyI)); + + @Property(maxSize = maxSize, runs = runs) + public void mappingCompositionsWithStreams( + Optional optional, + Function f, + Function g) { + Optional left = optional + .map(g) + .map(f); + + Optional right = optional + .map(x -> f.apply(g.apply(x))); + + assertEquals(left, right); + } + + @Property(maxSize = maxSize, runs = runs) + public void mappingCompositionsWithIntermediateList( + Optional optional, + Function f, + Function g) { + Optional intermediate = optional.map(g); + Optional left = intermediate.map(f); + + Optional right = optional + .map(x -> f.apply(g.apply(x))); + + assertEquals(left, right); + } + + @Property(maxSize = maxSize, runs = runs) + public void mapIdentityIsIdentity(Optional optional) { + Optional mapped = optional.map(x -> x); + + assertEquals(optional, mapped); + } + + private static Function plusI(final int i) { + return new Function() { + @Override + public Integer apply(Integer integer) { + return i + integer; + } + + @Override + public String toString() { + return "x -> x + " + i; + } + }; + } + + private static Function timesI(final int i) { + return new Function() { + @Override + public Integer apply(Integer integer) { + return i * integer; + } + + @Override + public String toString() { + return "x -> x * " + i; + } + }; + } + private static Function constantlyI(final int i) { + return new Function() { + @Override + public Integer apply(Integer integer) { + return i; + } + + @Override + public String toString() { + return "x -> " + i; + } + }; + } +} diff --git a/src/test/java/au/id/zancanaro/javacheck/SimpleListOperationsTest.java b/src/test/java/au/id/zancanaro/javacheck/SimpleListOperationsTest.java new file mode 100644 index 0000000..972b5b6 --- /dev/null +++ b/src/test/java/au/id/zancanaro/javacheck/SimpleListOperationsTest.java @@ -0,0 +1,48 @@ +package au.id.zancanaro.javacheck; + +import au.id.zancanaro.javacheck.Generator; +import au.id.zancanaro.javacheck.annotations.DataSource; +import au.id.zancanaro.javacheck.annotations.Property; +import au.id.zancanaro.javacheck.junit.Properties; +import org.junit.runner.RunWith; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +import static au.id.zancanaro.javacheck.Generators.*; +import static org.junit.Assert.assertEquals; + +@RunWith(Properties.class) +public class SimpleListOperationsTest { + + private final static int runs = 1000; + private final static int maxSize = 1000; + + @DataSource + public static Generator> listOfIntegers = listOf(integer()); + + @DataSource + public static Generator> listOfStrings = listOf(stringOf(alphaNumericCharacter())); + + @Property(maxSize = maxSize, runs = runs) + public void sortingIsIdempotent(List list) { + List left = new ArrayList<>(list); + Collections.sort(left); + + List right = new ArrayList<>(list); + Collections.sort(right); + Collections.sort(right); + + assertEquals(left, right); + } + + @Property(maxSize = 100, runs = runs) + public void reverseIsItsOwnInverse(List list) { + List reversed = new ArrayList<>(list); + Collections.reverse(reversed); + Collections.reverse(reversed); + + assertEquals(list, reversed); + } +} diff --git a/src/test/java/au/id/zancanaro/javacheck/junit/SimpleListOperationsTest.java b/src/test/java/au/id/zancanaro/javacheck/junit/SimpleListOperationsTest.java deleted file mode 100644 index 089451e..0000000 --- a/src/test/java/au/id/zancanaro/javacheck/junit/SimpleListOperationsTest.java +++ /dev/null @@ -1,44 +0,0 @@ -package au.id.zancanaro.javacheck.junit; - -import au.id.zancanaro.javacheck.Generator; -import au.id.zancanaro.javacheck.annotations.DataSource; -import au.id.zancanaro.javacheck.annotations.Property; -import org.junit.runner.RunWith; - -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; - -import static au.id.zancanaro.javacheck.Generators.*; -import static org.junit.Assert.assertEquals; - -@RunWith(Properties.class) -public class SimpleListOperationsTest { - - @DataSource - public static Generator> listOfIntegers = listOf(integer()); - - @DataSource - public static Generator> listOfStrings = listOf(stringOf(alphaNumericCharacter())); - - @Property(maxSize = 100, runs = 1000) - public void sortingIsIdempotent(List list) { - List left = new ArrayList<>(list); - Collections.sort(left); - - List right = new ArrayList<>(list); - Collections.sort(right); - Collections.sort(right); - - assertEquals(left, right); - } - - @Property(maxSize = 100, runs = 1000) - public void reverseIsItsOwnInverse(List list) { - List reversed = new ArrayList<>(list); - Collections.reverse(reversed); - Collections.reverse(reversed); - - assertEquals(list, reversed); - } -} -- cgit v1.2.3