slowCheck: print iteration seed, customize size hint, add "rechecking"

This commit is contained in:
peter
2017-07-24 15:21:00 +02:00
parent 1e469a9a00
commit 48d5e58c53
12 changed files with 390 additions and 246 deletions
@@ -0,0 +1,41 @@
package slowCheck;
import org.jetbrains.annotations.Nullable;
import java.util.function.Predicate;
class CounterExampleImpl<T> implements PropertyFailure.CounterExample<T> {
final StructureNode data;
private final T value;
@Nullable private final Throwable exception;
private CounterExampleImpl(StructureNode data, T value, @Nullable Throwable exception) {
this.data = data;
this.value = value;
this.exception = exception;
}
@Override
public T getExampleValue() {
return value;
}
@Nullable
@Override
public Throwable getExceptionCause() {
return exception;
}
static <T> CounterExampleImpl<T> checkProperty(Predicate<T> property, T value, StructureNode node) {
try {
if (!property.test(value)) {
return new CounterExampleImpl<>(node, value, null);
}
}
catch (Throwable e) {
return new CounterExampleImpl<>(node, value, e);
}
return null;
}
}
+6 -1
View File
@@ -14,7 +14,12 @@ public interface DataStructure {
}
int drawInt(@NotNull IntDistribution distribution);
/**
* @return a non-negative number used by various generators to guide the sizes of structures (e.g. collections) they create.
* The sizes need not be exactly equal to this hint, but in average bigger hints should in average correspond to bigger structures. When generators invoke other generators using {@link #subStructure}, the size hint of the sub-structure is
* generally less than the parent's one.
*/
int getSizeHint();
default int suggestCollectionSize() {
@@ -5,7 +5,7 @@ package slowCheck;
*/
public class GeneratorException extends RuntimeException {
GeneratorException(long seed, Throwable cause) {
super("Exception while generating data, seed=" + seed, cause);
GeneratorException(Iteration<?> iteration, Throwable cause) {
super("Exception while generating data, " + iteration.printSeeds(), cause);
}
}
+110
View File
@@ -0,0 +1,110 @@
package slowCheck;
import org.jetbrains.annotations.Nullable;
import java.util.HashSet;
import java.util.Random;
import java.util.Set;
import java.util.function.IntUnaryOperator;
import java.util.function.Predicate;
class Iteration<T> {
private static final Predicate<Object> DATA_IS_DIFFERENT = new Predicate<Object>() {
@Override
public boolean test(Object o) {
return false;
}
@Override
public String toString() {
return ": cannot generate enough sufficiently different values";
}
};
final CheckSession<T> session;
final long iterationSeed;
final int sizeHint;
final int iterationNumber;
Iteration(CheckSession<T> session, long iterationSeed, int iterationNumber) {
this.session = session;
this.iterationSeed = iterationSeed;
this.sizeHint = session.sizeHintFun.applyAsInt(iterationNumber);
this.iterationNumber = iterationNumber;
if (sizeHint < 0) {
throw new IllegalArgumentException("Size hint should be non-negative, found " + sizeHint);
}
}
@Nullable
private CounterExampleImpl<T> findCounterExample(Random random) {
for (int i = 0; i < 100; i++) {
StructureNode node = new StructureNode();
T value;
try {
value = session.generator.getGeneratorFunction().apply(new GenerativeDataStructure(random, node, sizeHint));
}
catch (Throwable e) {
throw new GeneratorException(this, e);
}
if (!session.generatedHashes.add(node.hashCode())) continue;
return CounterExampleImpl.checkProperty(session.property, value, node);
}
throw new CannotSatisfyCondition(DATA_IS_DIFFERENT);
}
String printToReproduce() {
return "To reproduce the last iteration, run PropertyChecker.forAll(...).rechecking(" + iterationSeed + "L, " + sizeHint + ").shouldHold(...)\n" +
"Global seed: " + session.globalSeed + "L";
}
String printSeeds() {
return "iteration seed=" + iterationSeed + "L, " +
"size hint=" + sizeHint + ", " +
"global seed=" + session.globalSeed + "L";
}
@Nullable
Iteration<T> performIteration() {
session.notifier.iterationStarted(iterationNumber);
Random random = new Random(iterationSeed);
CounterExampleImpl<T> example = findCounterExample(random);
if (example != null) {
session.notifier.counterExampleFound(this);
PropertyFailureImpl<T> failure = new PropertyFailureImpl<>(example, this);
throw new PropertyFalsified(failure, () -> new ReplayDataStructure(failure.getMinimalCounterexample().data, sizeHint));
}
if (iterationNumber >= session.iterationCount) {
return null;
}
return new Iteration<>(session, random.nextLong(), iterationNumber + 1);
}
}
class CheckSession<T> {
final Generator<T> generator;
final Predicate<T> property;
final long globalSeed;
final Set<Integer> generatedHashes = new HashSet<>();
final StatusNotifier notifier;
final int iterationCount;
final IntUnaryOperator sizeHintFun;
CheckSession(Generator<T> generator, Predicate<T> property, long globalSeed, int iterationCount, IntUnaryOperator sizeHintFun) {
this.generator = generator;
this.property = property;
this.globalSeed = globalSeed;
this.iterationCount = iterationCount;
this.sizeHintFun = sizeHintFun;
notifier = new StatusNotifier(iterationCount);
}
Iteration<T> firstIteration() {
return new Iteration<>(this, globalSeed, 1);
}
}
+46 -166
View File
@@ -1,201 +1,81 @@
package slowCheck;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.HashSet;
import java.util.Random;
import java.util.Set;
import java.util.function.IntUnaryOperator;
import java.util.function.Predicate;
/**
* @author peter
* An entry point to property-based testing. The main usage pattern: {@code PropertyChecker.forAll(generator).shouldHold(property)}.
*/
public class PropertyChecker<T> {
private static final Predicate<Object> DATA_IS_DIFFERENT = new Predicate<Object>() {
@Override
public boolean test(Object o) {
return false;
}
@Override
public String toString() {
return ": cannot generate enough sufficiently different values";
}
};
private final Generator<T> generator;
private Predicate<T> property;
private final Set<Integer> generatedHashes = new HashSet<>();
private long seed = new Random().nextLong();
private long globalSeed = new Random().nextLong();
private IntUnaryOperator sizeHintFun = iteration -> (iteration - 1) % 100 + 1;
private int iterationCount = 100;
private StatusNotifier notifier;
private PropertyChecker(Generator<T> generator) {
this.generator = generator;
}
/**
* Creates a property checker for the given generator. It can be further customized using {@code with*}-methods,
* and should finally used for property to check via {@link #shouldHold(Predicate)} call.
*/
public static <T> PropertyChecker<T> forAll(Generator<T> generator) {
return new PropertyChecker<>(generator);
}
/**
* This function allows to start the test with a fixed random seed. It's useful to reproduce some previous test run and debug it.
* @param seed A random seed to use for the first iteration.
* The following iterations will use other, pseudo-random seeds, but still derived from this one.
* @return this PropertyChecker
*/
public PropertyChecker<T> withSeed(long seed) {
this.seed = seed;
globalSeed = seed;
return this;
}
/**
* @param iterationCount the number of iterations to try. By default it's 100.
* @return this PropertyChecker
*/
public PropertyChecker<T> withIterationCount(int iterationCount) {
this.iterationCount = iterationCount;
return this;
}
/**
* @param sizeHintFun a function determining how size hint should be distributed depending on the iteration number.
* By default the size hint will be 1 in the first iteration, 2 in the second one, and so on until 100,
* then again 1,...,100,1,...,100, etc.
* @return this PropertyChecker
* @see DataStructure#getSizeHint()
*/
public PropertyChecker<T> withSizeHint(@NotNull IntUnaryOperator sizeHintFun) {
this.sizeHintFun = sizeHintFun;
return this;
}
/**
* Checks the property within a single iteration by using specified seed and size hint. Useful to debug the test after it's failed.
*/
public PropertyChecker<T> rechecking(long seed, int sizeHint) {
return withSeed(seed).withSizeHint(whatever -> sizeHint).withIterationCount(1);
}
/**
* Checks that the given property returns {@code true} and doesn't throw exceptions by running the generator and the property
* given number of times (see {@link #withIterationCount(int)}).
*/
public void shouldHold(@NotNull Predicate<T> property) {
if (this.property != null) throw new IllegalArgumentException("Property " + property + " already checked");
this.property = property;
notifier = new StatusNotifier(iterationCount, this.seed);
Random random = new Random(seed);
for (int i = 1; i <= iterationCount; i++) {
notifier.iterationStarted(i);
CounterExampleImpl<T> example = findCounterExample(i, random);
if (example != null) {
notifier.counterExampleFound();
PropertyFailureImpl failure = new PropertyFailureImpl(example, i);
throw new PropertyFalsified(seed, failure, () -> new ReplayDataStructure(failure.getMinimalCounterexample().data, failure.sizeHint));
}
Iteration<T> iteration = new CheckSession<>(generator, property, globalSeed, iterationCount, sizeHintFun).firstIteration();
while (iteration != null) {
iteration = iteration.performIteration();
}
}
@Nullable
private CounterExampleImpl<T> findCounterExample(int sizeHint, Random random) {
for (int i = 0; i < 100; i++) {
StructureNode node = new StructureNode();
T value;
try {
value = generator.getGeneratorFunction().apply(new GenerativeDataStructure(random, node, sizeHint));
}
catch (Throwable e) {
throw new GeneratorException(seed, e);
}
if (!generatedHashes.add(node.hashCode())) continue;
return CounterExampleImpl.checkProperty(property, value, node);
}
throw new CannotSatisfyCondition(DATA_IS_DIFFERENT);
}
private class PropertyFailureImpl implements PropertyFailure<T> {
private final CounterExampleImpl<T> initial;
private CounterExampleImpl<T> minimized;
private int totalSteps;
private int successfulSteps;
private int sizeHint;
private Throwable stoppingReason;
PropertyFailureImpl(@NotNull CounterExampleImpl<T> initial, int sizeHint) {
this.initial = initial;
this.minimized = initial;
this.sizeHint = sizeHint;
try {
shrink();
}
catch (Throwable e) {
stoppingReason = e;
}
}
@NotNull
@Override
public CounterExampleImpl<T> getFirstCounterExample() {
return initial;
}
@NotNull
@Override
public CounterExampleImpl<T> getMinimalCounterexample() {
return minimized;
}
@Nullable
@Override
public Throwable getStoppingReason() {
return stoppingReason;
}
@Override
public int getTotalMinimizationExampleCount() {
return totalSteps;
}
@Override
public int getMinimizationStageCount() {
return successfulSteps;
}
private void shrink() {
ShrinkRunner shrinkRunner = new ShrinkRunner();
while (true) {
CounterExampleImpl<T> shrank = shrinkRunner.findShrink(minimized.data, node -> {
if (!generatedHashes.add(node.hashCode())) return null;
notifier.shrinkAttempt(this);
try {
T value = generator.getGeneratorFunction().apply(new ReplayDataStructure(node, sizeHint));
totalSteps++;
return CounterExampleImpl.checkProperty(property, value, node);
}
catch (CannotRestoreValue e) {
return null;
}
});
if (shrank != null) {
minimized = shrank;
successfulSteps++;
} else {
break;
}
}
}
}
}
class CounterExampleImpl<T> implements PropertyFailure.CounterExample<T> {
final StructureNode data;
private final T value;
@Nullable private final Throwable exception;
private CounterExampleImpl(StructureNode data, T value, @Nullable Throwable exception) {
this.data = data;
this.value = value;
this.exception = exception;
}
@Override
public T getExampleValue() {
return value;
}
@Nullable
@Override
public Throwable getExceptionCause() {
return exception;
}
static <T> CounterExampleImpl<T> checkProperty(Predicate<T> property, T value, StructureNode node) {
try {
if (!property.test(value)) {
return new CounterExampleImpl<>(node, value, null);
}
}
catch (Throwable e) {
return new CounterExampleImpl<>(node, value, e);
}
return null;
}
}
@@ -19,6 +19,14 @@ public interface PropertyFailure<T> {
int getTotalMinimizationExampleCount();
int getMinimizationStageCount();
int getIterationNumber();
long getIterationSeed();
long getGlobalSeed();
int getSizeHint();
interface CounterExample<T> {
T getExampleValue();
@@ -0,0 +1,100 @@
package slowCheck;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
class PropertyFailureImpl<T> implements PropertyFailure<T> {
private final CounterExampleImpl<T> initial;
private CounterExampleImpl<T> minimized;
private int totalSteps;
private int successfulSteps;
final Iteration<T> iteration;
private Throwable stoppingReason;
PropertyFailureImpl(@NotNull CounterExampleImpl<T> initial, Iteration<T> iteration) {
this.initial = initial;
this.minimized = initial;
this.iteration = iteration;
try {
shrink();
}
catch (Throwable e) {
stoppingReason = e;
}
}
@NotNull
@Override
public CounterExampleImpl<T> getFirstCounterExample() {
return initial;
}
@NotNull
@Override
public CounterExampleImpl<T> getMinimalCounterexample() {
return minimized;
}
@Nullable
@Override
public Throwable getStoppingReason() {
return stoppingReason;
}
@Override
public int getTotalMinimizationExampleCount() {
return totalSteps;
}
@Override
public int getMinimizationStageCount() {
return successfulSteps;
}
@Override
public int getIterationNumber() {
return iteration.iterationNumber;
}
@Override
public long getIterationSeed() {
return iteration.iterationSeed;
}
@Override
public long getGlobalSeed() {
return iteration.session.globalSeed;
}
@Override
public int getSizeHint() {
return iteration.sizeHint;
}
private void shrink() {
ShrinkRunner shrinkRunner = new ShrinkRunner();
while (true) {
CounterExampleImpl<T> shrank = shrinkRunner.findShrink(minimized.data, node -> {
if (!iteration.session.generatedHashes.add(node.hashCode())) return null;
iteration.session.notifier.shrinkAttempt(this, iteration);
try {
T value = iteration.session.generator.getGeneratorFunction().apply(new ReplayDataStructure(node, iteration.sizeHint));
totalSteps++;
return CounterExampleImpl.checkProperty(iteration.session.property, value, node);
}
catch (CannotRestoreValue e) {
return null;
}
});
if (shrank != null) {
minimized = shrank;
successfulSteps++;
}
else {
break;
}
}
}
}
@@ -11,13 +11,11 @@ import java.util.function.Supplier;
public class PropertyFalsified extends RuntimeException {
static final String FAILURE_REASON_HAS_CHANGED_DURING_MINIMIZATION = "!!! FAILURE REASON HAS CHANGED DURING MINIMIZATION !!!";
private static final String SEPARATOR = "\n==========================\n";
private final long seed;
private final PropertyFailure<?> failure;
private final PropertyFailureImpl<?> failure;
private final Supplier<DataStructure> data;
PropertyFalsified(long seed, PropertyFailure<?> failure, Supplier<DataStructure> data) {
PropertyFalsified(PropertyFailureImpl<?> failure, Supplier<DataStructure> data) {
super(failure.getMinimalCounterexample().getExceptionCause());
this.seed = seed;
this.failure = failure;
this.data = data;
}
@@ -26,7 +24,7 @@ public class PropertyFalsified extends RuntimeException {
public String getMessage() {
String msg = "Falsified on " + failure.getMinimalCounterexample().getExampleValue() + "\n" +
getMinimizationStats() +
"Seed=" + seed;
failure.iteration.printToReproduce();
if (failure.getStoppingReason() != null) {
msg += "\n Shrinking stopped because of " + StatusNotifier.printStackTrace(failure.getStoppingReason());
+6 -8
View File
@@ -15,13 +15,11 @@ import java.util.Locale;
@SuppressWarnings("UseOfSystemOutOrSystemErr")
class StatusNotifier {
private final int iterationCount;
private final long seed;
private int currentIteration;
private long lastPrinted = System.currentTimeMillis();
StatusNotifier(int iterationCount, long seed) {
StatusNotifier(int iterationCount) {
this.iterationCount = iterationCount;
this.seed = seed;
}
void iterationStarted(int iteration) {
@@ -31,9 +29,9 @@ class StatusNotifier {
}
}
void counterExampleFound() {
void counterExampleFound(Iteration<?> iteration) {
lastPrinted = System.currentTimeMillis();
System.err.println(formatCurrentTime() + ": failed on iteration " + currentIteration + " (seed=" + seed + "), shrinking...");
System.err.println(formatCurrentTime() + ": failed on iteration " + currentIteration + " (" + iteration.printSeeds() + "), shrinking...");
}
private boolean shouldPrint() {
@@ -46,11 +44,11 @@ class StatusNotifier {
private int lastReportedStage = -1;
private String lastReportedTrace = null;
void shrinkAttempt(PropertyFailure<?> failure) {
<T> void shrinkAttempt(PropertyFailure<T> failure, Iteration<T> iteration) {
if (shouldPrint()) {
int stage = failure.getMinimizationStageCount();
System.err.println(formatCurrentTime() + ": still shrinking (seed=" + seed + "). " +
"Examples tried: " + failure.getTotalMinimizationExampleCount() +
System.out.println(formatCurrentTime() + ": still shrinking (" + iteration.printSeeds() + "). " +
"Examples tried: " + failure.getTotalMinimizationExampleCount() +
", successful minimizations: " + stage);
if (lastReportedStage != stage) {
lastReportedStage = stage;
+25 -43
View File
@@ -8,44 +8,30 @@ import static slowCheck.Generator.*;
public class ExceptionTest extends PropertyCheckerTestCase {
public void testFailureReasonUnchanged() {
try {
forAllStable(integers()).shouldHold(i -> {
throw new AssertionError("fail");
});
fail();
}
catch (PropertyFalsified e) {
assertFalse(e.getMessage().contains(PropertyFalsified.FAILURE_REASON_HAS_CHANGED_DURING_MINIMIZATION));
}
PropertyFalsified e = checkFails(forAllStable(integers()), i -> {
throw new AssertionError("fail");
});
assertFalse(e.getMessage().contains(PropertyFalsified.FAILURE_REASON_HAS_CHANGED_DURING_MINIMIZATION));
}
public void testFailureReasonChangedExceptionClass() {
try {
forAllStable(integers()).shouldHold(i -> {
throw (i == 0 ? new RuntimeException("fail") : new IllegalArgumentException("fail"));
});
fail();
}
catch (PropertyFalsified e) {
assertTrue(e.getMessage().contains(PropertyFalsified.FAILURE_REASON_HAS_CHANGED_DURING_MINIMIZATION));
}
PropertyFalsified e = checkFails(forAllStable(integers()), i -> {
throw (i == 0 ? new RuntimeException("fail") : new IllegalArgumentException("fail"));
});
assertTrue(e.getMessage().contains(PropertyFalsified.FAILURE_REASON_HAS_CHANGED_DURING_MINIMIZATION));
}
public void testFailureReasonChangedExceptionTrace() {
try {
forAllStable(integers()).shouldHold(i -> {
if (i == 0) {
throw new AssertionError("fail");
}
else {
throw new AssertionError("fail2");
}
});
fail();
}
catch (PropertyFalsified e) {
assertTrue(e.getMessage().contains(PropertyFalsified.FAILURE_REASON_HAS_CHANGED_DURING_MINIMIZATION));
}
PropertyFalsified e = checkFails(forAllStable(integers()), i -> {
if (i == 0) {
throw new AssertionError("fail");
}
else {
throw new AssertionError("fail2");
}
});
assertTrue(e.getMessage().contains(PropertyFalsified.FAILURE_REASON_HAS_CHANGED_DURING_MINIMIZATION));
}
public void testExceptionWhileGeneratingValue() {
@@ -60,17 +46,13 @@ public class ExceptionTest extends PropertyCheckerTestCase {
}
public void testExceptionWhileShrinkingValue() {
try {
forAllStable(listsOf(integers()).suchThat(l -> {
if (l.size() == 1 && l.get(0) == 0) throw new RuntimeException("my exception");
return true;
})).shouldHold(l -> l.stream().allMatch(i -> i > 0));
fail();
}
catch (PropertyFalsified e) {
assertEquals("my exception", e.getFailure().getStoppingReason().getMessage());
assertTrue(StatusNotifier.printStackTrace(e).contains("my exception"));
}
PropertyFalsified e = checkFails(PropertyChecker.forAll(listsOf(integers()).suchThat(l -> {
if (l.size() == 1 && l.get(0) == 0) throw new RuntimeException("my exception");
return true;
})), l -> l.stream().allMatch(i -> i > 0));
assertEquals("my exception", e.getFailure().getStoppingReason().getMessage());
assertTrue(StatusNotifier.printStackTrace(e).contains("my exception"));
}
public void testUnsatisfiableSuchThat() {
+26 -9
View File
@@ -4,6 +4,7 @@ import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.function.Predicate;
import java.util.stream.Collectors;
import static slowCheck.Generator.*;
@@ -28,25 +29,25 @@ public class GeneratorTest extends PropertyCheckerTestCase {
public void testListContainsDivisible() {
checkFalsified(nonEmptyLists(integers()),
l -> l.stream().allMatch(i -> i % 10 != 0),
9);
3);
}
public void testStringContains() {
checkFalsified(stringsOf(asciiPrintableChars()),
s -> !s.contains("a"),
10);
7);
}
public void testLetterStringContains() {
checkFalsified(stringsOf(asciiLetters()),
s -> !s.contains("a"),
5);
3);
}
public void testIsSorted() {
PropertyFailure<List<Integer>> failure = checkFalsified(nonEmptyLists(integers()),
l -> l.stream().sorted().collect(Collectors.toList()).equals(l),
69);
67);
assertEquals(2, failure.getMinimalCounterexample().getExampleValue().size());
}
@@ -57,7 +58,7 @@ public class GeneratorTest extends PropertyCheckerTestCase {
public void testSortedDoublesNonDescending() {
PropertyFailure<List<Double>> failure = checkFalsified(listsOf(doubles()),
l -> isSorted(l.stream().sorted().collect(Collectors.toList())),
141);
76);
assertEquals(2, failure.getMinimalCounterexample().getExampleValue().size());
}
@@ -77,13 +78,13 @@ public class GeneratorTest extends PropertyCheckerTestCase {
public void testStringOfStringChecksAllChars() {
checkFalsified(stringsOf("abc "),
s -> !s.contains(" "),
3);
4);
}
public void testLongListsHappen() {
PropertyFailure<List<Integer>> failure = checkFalsified(listsOf(integers()),
l -> l.size() < 200,
631);
504);
assertEquals(200, failure.getMinimalCounterexample().getExampleValue().size());
}
@@ -114,15 +115,31 @@ public class GeneratorTest extends PropertyCheckerTestCase {
public void testBoolean() {
PropertyFailure<List<Boolean>> failure = checkFalsified(listsOf(booleans()),
l -> !l.contains(true) || !l.contains(false),
4);
3);
assertEquals(2, failure.getMinimalCounterexample().getExampleValue().size());
}
public void testShrinkingNonEmptyList() {
PropertyFailure<List<Integer>> failure = checkFalsified(nonEmptyLists(integers(0, 100)),
l -> !l.contains(42),
10);
4);
assertEquals(1, failure.getMinimalCounterexample().getExampleValue().size());
}
public void testRecheckWithGivenSeeds() {
Generator<List<Integer>> gen = nonEmptyLists(integers(0, 100));
Predicate<List<Integer>> property = l -> !l.contains(42);
PropertyFailure<?> failure = checkFails(PropertyChecker.forAll(gen), property).getFailure();
assertTrue(failure.getIterationNumber() > 1);
PropertyFalsified e;
e = checkFails(PropertyChecker.forAll(gen).rechecking(failure.getIterationSeed(), failure.getSizeHint()), property);
assertEquals(1, e.getFailure().getIterationNumber());
e = checkFails(PropertyChecker.forAll(gen).withSeed(failure.getGlobalSeed()), property);
assertEquals(failure.getIterationNumber(), e.getFailure().getIterationNumber());
}
}
@@ -9,25 +9,30 @@ import java.util.function.Predicate;
*/
abstract class PropertyCheckerTestCase extends TestCase {
protected <T> PropertyFailure<T> checkFalsified(Generator<T> generator, Predicate<T> predicate, int minimizationSteps) {
protected <T> PropertyFalsified checkFails(PropertyChecker<T> checker, Predicate<T> predicate) {
try {
forAllStable(generator).shouldHold(predicate);
checker.shouldHold(predicate);
throw new AssertionError("Can't falsify " + getName());
}
catch (PropertyFalsified e) {
//noinspection unchecked
PropertyFailure<T> failure = (PropertyFailure<T>)e.getFailure();
System.out.println(" " + getName());
System.out.println("Value: " + e.getBreakingValue());
System.out.println("Data: " + e.getData());
assertEquals(minimizationSteps, failure.getTotalMinimizationExampleCount());
assertEquals(e.getBreakingValue(), generator.getGeneratorFunction().apply(e.getData()));
return failure;
return e;
}
}
protected <T> PropertyFailure<T> checkFalsified(Generator<T> generator, Predicate<T> predicate, int minimizationSteps) {
PropertyFalsified e = checkFails(forAllStable(generator), predicate);
//noinspection unchecked
PropertyFailure<T> failure = (PropertyFailure<T>)e.getFailure();
System.out.println(" " + getName());
System.out.println("Value: " + e.getBreakingValue());
System.out.println("Data: " + e.getData());
assertEquals(minimizationSteps, failure.getTotalMinimizationExampleCount());
assertEquals(e.getBreakingValue(), generator.getGeneratorFunction().apply(e.getData()));
return failure;
}
protected static <T> PropertyChecker<T> forAllStable(Generator<T> generator) {
return PropertyChecker.forAll(generator).withSeed(0);
}