jetCheck: restart shrinking from beginning: sometimes it helps to shrink more

This commit is contained in:
peter
2018-01-02 10:28:12 +01:00
parent 86f275aed2
commit 5e5c4f24fa
6 changed files with 87 additions and 11 deletions
+22 -7
View File
@@ -76,20 +76,35 @@ class PropertyFailureImpl<T> implements PropertyFailure<T> {
}
private void shrink() {
ShrinkStep step = minimized.data.shrink();
while (step != null) {
step = findSuccessfulShrink(step);
if (step != null) {
step = step.onSuccess(minimized.data);
}
NodeId limit = null;
while (true) {
ShrinkStep lastSuccessfulShrink = shrinkIteration(limit);
if (lastSuccessfulShrink == null) break;
limit = lastSuccessfulShrink.getNodeAfter();
}
}
private ShrinkStep shrinkIteration(NodeId limit) {
ShrinkStep lastSuccessfulShrink = null;
ShrinkStep step = minimized.data.shrink();
while (step != null) {
step = findSuccessfulShrink(step, limit);
if (step != null) {
lastSuccessfulShrink = step;
step = step.onSuccess(minimized.data);
}
}
return lastSuccessfulShrink;
}
@Nullable
private ShrinkStep findSuccessfulShrink(ShrinkStep step) {
private ShrinkStep findSuccessfulShrink(ShrinkStep step, @Nullable NodeId limit) {
List<CustomizedNode> combinatorial = new ArrayList<>();
while (step != null) {
if (limit != null && limit.number <= step.getNodeAfter().number) {
break;
}
StructureNode node = step.apply(minimized.data);
if (node != null && iteration.session.generatedHashes.add(node.hashCode())) {
CombinatorialIntCustomizer customizer = new CombinatorialIntCustomizer();
@@ -3,6 +3,7 @@
*/
package jetCheck;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.ArrayList;
@@ -70,4 +71,20 @@ class RemoveListRange extends ShrinkStep {
int newLength = Math.min(length * 2, start - 1);
return new RemoveListRange(inheritor, start, start - newLength, newLength);
}
@NotNull
@Override
NodeId getNodeAfter() {
return node.id;
}
@Override
public String toString() {
return "RemoveListRange{" +
"last=" + lastSuccessfulRemove +
", start=" + start +
", length=" + length +
", node=" + node.id + ": " + node +
'}';
}
}
+14
View File
@@ -23,6 +23,9 @@ abstract class ShrinkStep {
@Nullable
abstract ShrinkStep onFailure();
@NotNull
abstract NodeId getNodeAfter();
static ShrinkStep create(@NotNull NodeId replaced,
@NotNull StructureElement replacement,
@Nullable Function<StructureNode, ShrinkStep> onSuccess,
@@ -45,6 +48,17 @@ abstract class ShrinkStep {
ShrinkStep onFailure() {
return onFailure == null ? null : onFailure.get();
}
@NotNull
@Override
NodeId getNodeAfter() {
return replacement.id;
}
@Override
public String toString() {
return "replace " + replaced + " with " + replacement;
}
};
}
}
+11
View File
@@ -110,6 +110,17 @@ class StructureNode extends StructureElement {
ShrinkStep onFailure() {
return wrapChildShrink(index, step.onFailure());
}
@NotNull
@Override
NodeId getNodeAfter() {
return step.getNodeAfter();
}
@Override
public String toString() {
return "-" + step.toString();
}
};
}
+3 -3
View File
@@ -20,7 +20,7 @@ public class GeneratorTest extends PropertyCheckerTestCase {
public void testListSumMod() {
checkFalsified(nonEmptyLists(integers()),
l -> l.stream().mapToInt(Integer::intValue).sum() % 10 != 0,
181);
390);
}
public void testListContainsDivisible() {
@@ -44,7 +44,7 @@ public class GeneratorTest extends PropertyCheckerTestCase {
public void testIsSorted() {
PropertyFailure<List<Integer>> failure = checkFalsified(nonEmptyLists(integers()),
l -> l.stream().sorted().collect(Collectors.toList()).equals(l),
20);
22);
List<Integer> value = failure.getMinimalCounterexample().getExampleValue();
assertEquals(2, value.size());
assertTrue(value.toString(), value.stream().allMatch(i -> Math.abs(i) < 2));
@@ -57,7 +57,7 @@ public class GeneratorTest extends PropertyCheckerTestCase {
public void testSortedDoublesNonDescending() {
PropertyFailure<List<Double>> failure = checkFalsified(listsOf(doubles()),
l -> isSorted(l.stream().sorted().collect(Collectors.toList())),
35);
41);
assertEquals(2, failure.getMinimalCounterexample().getExampleValue().size());
}
+20 -1
View File
@@ -3,7 +3,11 @@
*/
package jetCheck;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.function.Predicate;
import static jetCheck.Generator.*;
@@ -17,7 +21,7 @@ public class ShrinkTest extends PropertyCheckerTestCase {
String s = l.toString();
return !"abcdefghijklmnopqrstuvwxyz()[]#!".chars().allMatch(c -> s.indexOf((char)c) >= 0);
},
225);
258);
}
public void testShrinkingNonEmptyList() {
@@ -27,4 +31,19 @@ public class ShrinkTest extends PropertyCheckerTestCase {
assertEquals(1, list.size());
}
public void testWhenEarlyObjectsCannotBeShrunkBeforeLater() {
Generator<String> gen = listsOf(IntDistribution.uniform(0, 2), listsOf(IntDistribution.uniform(0, 2), sampledFrom('a', 'b'))).map(List::toString);
Set<String> failing = new HashSet<>(Arrays.asList("[[a, b], [a, b]]", "[[a, b], [a]]", "[[a], [a]]", "[[a]]", "[]"));
Predicate<String> property = s -> !failing.contains(s);
checkFalsified(gen, property, 0); // prove that it sometimes fails
for (int i = 0; i < 1000; i++) {
try {
PropertyChecker.forAll(gen).shouldHold(property);
}
catch (PropertyFalsified e) {
assertEquals("[]", e.getBreakingValue());
}
}
}
}