mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
slowCheck: shrink faster by remembering previous unsuccessful attempts
This commit is contained in:
@@ -106,8 +106,9 @@ class PropertyFailureImpl<T> implements PropertyFailure<T> {
|
||||
}
|
||||
|
||||
private void shrink(Generator<T> gen, Predicate<T> property) {
|
||||
ShrinkRunner shrinkRunner = new ShrinkRunner();
|
||||
while (true) {
|
||||
CounterExampleImpl<T> shrank = ShrinkRunner.findShrink(minimized.data, node -> {
|
||||
CounterExampleImpl<T> shrank = shrinkRunner.findShrink(minimized.data, node -> {
|
||||
try {
|
||||
T value = gen.generateUnstructured(new ReplayDataStructure(node));
|
||||
totalSteps++;
|
||||
|
||||
@@ -27,7 +27,7 @@ class RemoveListRange implements Shrink.ElementaryShrink {
|
||||
list.addAll(original.subList(1, start + 1));
|
||||
list.addAll(original.subList(end + 1, original.size()));
|
||||
|
||||
return new StructureNode(list, start == end - 1 ? start: 0);
|
||||
return new StructureNode(list);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -42,4 +42,9 @@ class RemoveListRange implements Shrink.ElementaryShrink {
|
||||
public int hashCode() {
|
||||
return Objects.hash(start, end);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "RemoveListRange{" + + start + ", " + end + '}';
|
||||
}
|
||||
}
|
||||
|
||||
@@ -61,14 +61,14 @@ interface Shrink {
|
||||
@NotNull
|
||||
public List<ShrinkAction> expandShrinks(@NotNull StructureNode source) {
|
||||
List<ShrinkAction> result = new ArrayList<>();
|
||||
StructureNode.indices(source.children.size(), source.lastModifiedChild).forEach(i -> {
|
||||
for (int i = 0; i < source.children.size(); i++) {
|
||||
StructureElement child = source.children.get(i);
|
||||
if (child instanceof IntData && !myShrinkInts) return;
|
||||
if (child instanceof IntData && !myShrinkInts) continue;
|
||||
|
||||
for (Shrink shrink : child.shrink()) {
|
||||
result.add(new ShrinkAction(new StructurePath.ChildPath(StructurePath.EMPTY, i), shrink));
|
||||
}
|
||||
});
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
@@ -3,29 +3,43 @@ package slowCheck;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.LinkedList;
|
||||
import java.util.*;
|
||||
import java.util.function.Function;
|
||||
|
||||
/**
|
||||
* @author peter
|
||||
*/
|
||||
class ShrinkRunner {
|
||||
private final Set<ShrinkAction> unsuccessful = new HashSet<>();
|
||||
|
||||
@Nullable
|
||||
static <T> T findShrink(@NotNull StructureNode element, Function<StructureNode, T> shrinkProcessor) {
|
||||
<T> T findShrink(@NotNull StructureNode element, Function<StructureNode, T> shrinkProcessor) {
|
||||
List<ShrinkAction> postponed = new ArrayList<>();
|
||||
|
||||
LinkedList<ShrinkAction> queue = new LinkedList<>();
|
||||
for (Shrink shrink : element.shrink()) {
|
||||
queue.add(new ShrinkAction(StructurePath.EMPTY, shrink));
|
||||
}
|
||||
|
||||
while (true) {
|
||||
if (queue.isEmpty() && postponed != null) {
|
||||
queue.addAll(postponed);
|
||||
postponed = null;
|
||||
}
|
||||
|
||||
ShrinkAction action = queue.poll();
|
||||
if (action == null) return null;
|
||||
|
||||
|
||||
if (action.shrink instanceof Shrink.ElementaryShrink) {
|
||||
if (postponed != null && !unsuccessful.add(action)) {
|
||||
postponed.add(action);
|
||||
continue;
|
||||
}
|
||||
|
||||
StructureNode shrank = action.path.applyShrink(element, (Shrink.ElementaryShrink)action.shrink);
|
||||
T result = shrinkProcessor.apply(shrank);
|
||||
if (result != null) {
|
||||
unsuccessful.remove(action);
|
||||
return result;
|
||||
}
|
||||
} else {
|
||||
|
||||
@@ -4,7 +4,6 @@ import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.IntStream;
|
||||
|
||||
/**
|
||||
* @author peter
|
||||
@@ -15,16 +14,14 @@ interface StructureElement {
|
||||
|
||||
class StructureNode implements StructureElement {
|
||||
final List<StructureElement> children;
|
||||
final int lastModifiedChild;
|
||||
boolean shrinkProhibited;
|
||||
|
||||
StructureNode() {
|
||||
this(new ArrayList<>(), -1);
|
||||
this(new ArrayList<>());
|
||||
}
|
||||
|
||||
StructureNode(List<StructureElement> children, int lastModifiedChild) {
|
||||
StructureNode(List<StructureElement> children) {
|
||||
this.children = children;
|
||||
this.lastModifiedChild = lastModifiedChild;
|
||||
}
|
||||
|
||||
Iterator<StructureElement> childrenIterator() {
|
||||
@@ -48,14 +45,6 @@ class StructureNode implements StructureElement {
|
||||
children.remove(children.size() - 1);
|
||||
}
|
||||
|
||||
static IntStream indices(int size, int lastModified) {
|
||||
if (lastModified > 0) {
|
||||
return IntStream.concat(IntStream.range(lastModified, size), IntStream.range(0, lastModified));
|
||||
}
|
||||
|
||||
return IntStream.range(0, size);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Shrink> shrink() {
|
||||
if (shrinkProhibited) return Collections.emptyList();
|
||||
@@ -63,13 +52,15 @@ class StructureNode implements StructureElement {
|
||||
return isList() ? shrinkList(children.size() - 1) : Collections.singletonList(Shrink.SHRINK_ALL_CHILDREN);
|
||||
}
|
||||
|
||||
private List<Shrink> shrinkList(int size) {
|
||||
private static List<Shrink> shrinkList(int size) {
|
||||
List<Shrink> result = new ArrayList<>();
|
||||
if (size > 4) {
|
||||
result.add(new RemoveListRange(size / 2, size));
|
||||
result.add(new RemoveListRange(0, size / 2));
|
||||
}
|
||||
indices(size, lastModifiedChild - 1).forEach(i -> result.add(new RemoveListRange(i, i + 1)));
|
||||
for (int i = 0; i < size; i++) {
|
||||
result.add(new RemoveListRange(i, i + 1));
|
||||
}
|
||||
result.add(Shrink.SHRINK_LIST_ELEMENTS);
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -58,7 +58,7 @@ abstract class StructurePath {
|
||||
int index = indicesFromRoot.get(depth);
|
||||
List<StructureElement> children = new ArrayList<>(((StructureNode)source).children);
|
||||
children.set(index, expandShrinks(children.get(index), depth + 1));
|
||||
return new StructureNode(children, index);
|
||||
return new StructureNode(children);
|
||||
}
|
||||
}.expandShrinks(source, 0);
|
||||
}
|
||||
|
||||
@@ -50,7 +50,7 @@ public class GeneratorTest extends TestCase {
|
||||
public void testIsSorted() {
|
||||
checkFalsified(nonEmptyListOf(integers()),
|
||||
l -> l.stream().sorted().collect(Collectors.toList()).equals(l),
|
||||
218);
|
||||
99);
|
||||
}
|
||||
|
||||
public void testSuccess() {
|
||||
@@ -61,7 +61,7 @@ public class GeneratorTest extends TestCase {
|
||||
public void testSortedDoublesNonDescending() {
|
||||
checkFalsified(listOf(doubles()),
|
||||
l -> isSorted(l.stream().sorted().collect(Collectors.toList())),
|
||||
399);
|
||||
299);
|
||||
}
|
||||
|
||||
private static boolean isSorted(List<Double> list) {
|
||||
@@ -99,9 +99,9 @@ public class GeneratorTest extends TestCase {
|
||||
}
|
||||
|
||||
public void testLongListsHappen() {
|
||||
checkFalsified(listOf(integers()).noShrink(),
|
||||
checkFalsified(listOf(integers()),
|
||||
l -> l.size() < 200,
|
||||
0);
|
||||
6714);
|
||||
}
|
||||
|
||||
public void testNonEmptyList() {
|
||||
|
||||
Reference in New Issue
Block a user