summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/main/java/au/id/zancanaro/javacheck/Generator.java5
-rw-r--r--src/main/java/au/id/zancanaro/javacheck/GeneratorSampleIterator.java30
-rw-r--r--src/main/java/au/id/zancanaro/javacheck/Generators.java10
-rw-r--r--src/test/java/au/id/zancanaro/javacheck/ListFunctorRulesTest.java110
-rw-r--r--src/test/java/au/id/zancanaro/javacheck/OptionalFunctorRulesTest.java110
-rw-r--r--src/test/java/au/id/zancanaro/javacheck/SimpleListOperationsTest.java (renamed from src/test/java/au/id/zancanaro/javacheck/junit/SimpleListOperationsTest.java)10
6 files changed, 269 insertions, 6 deletions
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<T> {
default <R> Generator<R> flatMap(Function<T, Generator<R>> action) {
return (random, size) -> RoseTree.join(this.generate(random, size).map(action).map(g -> g.generate(random, size)));
}
+
+ default Iterator<T> 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<T> implements Iterator<T> {
+ private final Generator<T> generator;
+ private final Random random;
+ private final int maxSize;
+ private int size;
+
+ public GeneratorSampleIterator(Generator<T> 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<Integer> 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<Integer> 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<List<Integer>> listOfIntegers = listOf(integer());
+
+ @DataSource
+ public static Generator<Function<Integer, Integer>> integerFunction =
+ oneOf(
+ integer().map(ListFunctorRulesTest::plusI),
+ integer().map(ListFunctorRulesTest::timesI),
+ integer().map(ListFunctorRulesTest::constantlyI));
+
+ @Property(maxSize = maxSize, runs = runs)
+ public void mappingCompositionsWithStreams(
+ List<Integer> list,
+ Function<Integer, Integer> f,
+ Function<Integer, Integer> g) {
+ List<Integer> left = list.stream()
+ .map(g)
+ .map(f)
+ .collect(Collectors.toList());
+
+ List<Integer> 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<Integer> list,
+ Function<Integer, Integer> f,
+ Function<Integer, Integer> g) {
+ List<Integer> intermediate = list.stream().map(g).collect(Collectors.toList());
+ List<Integer> left = intermediate.stream().map(f).collect(Collectors.toList());
+
+ List<Integer> 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<Integer> list) {
+ List<Integer> mapped = list.stream().map(x -> x).collect(Collectors.toList());
+
+ assertEquals(list, mapped);
+ }
+
+ private static Function<Integer,Integer> plusI(final int i) {
+ return new Function<Integer, Integer>() {
+ @Override
+ public Integer apply(Integer integer) {
+ return i + integer;
+ }
+
+ @Override
+ public String toString() {
+ return "x -> x + " + i;
+ }
+ };
+ }
+
+ private static Function<Integer,Integer> timesI(final int i) {
+ return new Function<Integer, Integer>() {
+ @Override
+ public Integer apply(Integer integer) {
+ return i * integer;
+ }
+
+ @Override
+ public String toString() {
+ return "x -> x * " + i;
+ }
+ };
+ }
+ private static Function<Integer,Integer> constantlyI(final int i) {
+ return new Function<Integer, Integer>() {
+ @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<Optional<Integer>> listOfIntegers = oneOf(
+ pure(Optional.empty()),
+ integer().map(Optional::of));
+
+ @DataSource
+ public static Generator<Function<Integer, Integer>> integerFunction =
+ oneOf(
+ integer().map(OptionalFunctorRulesTest::plusI),
+ integer().map(OptionalFunctorRulesTest::timesI),
+ integer().map(OptionalFunctorRulesTest::constantlyI));
+
+ @Property(maxSize = maxSize, runs = runs)
+ public void mappingCompositionsWithStreams(
+ Optional<Integer> optional,
+ Function<Integer, Integer> f,
+ Function<Integer, Integer> g) {
+ Optional<Integer> left = optional
+ .map(g)
+ .map(f);
+
+ Optional<Integer> right = optional
+ .map(x -> f.apply(g.apply(x)));
+
+ assertEquals(left, right);
+ }
+
+ @Property(maxSize = maxSize, runs = runs)
+ public void mappingCompositionsWithIntermediateList(
+ Optional<Integer> optional,
+ Function<Integer, Integer> f,
+ Function<Integer, Integer> g) {
+ Optional<Integer> intermediate = optional.map(g);
+ Optional<Integer> left = intermediate.map(f);
+
+ Optional<Integer> right = optional
+ .map(x -> f.apply(g.apply(x)));
+
+ assertEquals(left, right);
+ }
+
+ @Property(maxSize = maxSize, runs = runs)
+ public void mapIdentityIsIdentity(Optional<Integer> optional) {
+ Optional<Integer> mapped = optional.map(x -> x);
+
+ assertEquals(optional, mapped);
+ }
+
+ private static Function<Integer,Integer> plusI(final int i) {
+ return new Function<Integer, Integer>() {
+ @Override
+ public Integer apply(Integer integer) {
+ return i + integer;
+ }
+
+ @Override
+ public String toString() {
+ return "x -> x + " + i;
+ }
+ };
+ }
+
+ private static Function<Integer,Integer> timesI(final int i) {
+ return new Function<Integer, Integer>() {
+ @Override
+ public Integer apply(Integer integer) {
+ return i * integer;
+ }
+
+ @Override
+ public String toString() {
+ return "x -> x * " + i;
+ }
+ };
+ }
+ private static Function<Integer,Integer> constantlyI(final int i) {
+ return new Function<Integer, Integer>() {
+ @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/junit/SimpleListOperationsTest.java b/src/test/java/au/id/zancanaro/javacheck/SimpleListOperationsTest.java
index 089451e..972b5b6 100644
--- a/src/test/java/au/id/zancanaro/javacheck/junit/SimpleListOperationsTest.java
+++ b/src/test/java/au/id/zancanaro/javacheck/SimpleListOperationsTest.java
@@ -1,8 +1,9 @@
-package au.id.zancanaro.javacheck.junit;
+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;
@@ -15,13 +16,16 @@ 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<List<Integer>> listOfIntegers = listOf(integer());
@DataSource
public static Generator<List<String>> listOfStrings = listOf(stringOf(alphaNumericCharacter()));
- @Property(maxSize = 100, runs = 1000)
+ @Property(maxSize = maxSize, runs = runs)
public void sortingIsIdempotent(List<Integer> list) {
List<Integer> left = new ArrayList<>(list);
Collections.sort(left);
@@ -33,7 +37,7 @@ public class SimpleListOperationsTest {
assertEquals(left, right);
}
- @Property(maxSize = 100, runs = 1000)
+ @Property(maxSize = 100, runs = runs)
public void reverseIsItsOwnInverse(List<String> list) {
List<String> reversed = new ArrayList<>(list);
Collections.reverse(reversed);