From 409da53e9f30e698e50987ed5ccbec3788c68759 Mon Sep 17 00:00:00 2001 From: peter Date: Fri, 1 Dec 2017 23:36:28 +0100 Subject: [PATCH] jetCheck: remove subStructure from API, invoke generators in more completion-friendly way --- .../JavaPsiIndexConsistencyTest.kt | 6 +++--- .../src/jetCheck/AbstractDataStructure.java | 9 +++++++++ jetCheck/src/jetCheck/DataStructure.java | 7 +++---- jetCheck/src/jetCheck/FrequencyGenerator.java | 6 +++--- .../src/jetCheck/GenerativeDataStructure.java | 2 +- jetCheck/src/jetCheck/Generator.java | 19 ++++++------------- .../src/jetCheck/ReplayDataStructure.java | 6 +++--- .../test/jetCheck/RecursiveGeneratorTest.java | 2 +- .../test/jetCheck/StatefulGeneratorTest.java | 4 ++-- .../psi/impl/PsiEventConsistencyTest.kt | 8 ++++---- .../propertyBased/DeleteRange.java | 2 +- 11 files changed, 36 insertions(+), 35 deletions(-) diff --git a/java/java-tests/testSrc/com/intellij/java/propertyBased/JavaPsiIndexConsistencyTest.kt b/java/java-tests/testSrc/com/intellij/java/propertyBased/JavaPsiIndexConsistencyTest.kt index 97aaa2d14808..87623a781908 100644 --- a/java/java-tests/testSrc/com/intellij/java/propertyBased/JavaPsiIndexConsistencyTest.kt +++ b/java/java-tests/testSrc/com/intellij/java/propertyBased/JavaPsiIndexConsistencyTest.kt @@ -47,9 +47,9 @@ class JavaPsiIndexConsistencyTest : LightCodeInsightFixtureTestCase() { PsiIndexConsistencyTester.commonActions(PsiIndexConsistencyTester.commonRefs + listOf(ClassRef)), Generator.sampledFrom(AddImport, AddEnum, InvisiblePsiChange), Generator.booleans().map { ChangeLanguageLevel(if (it) LanguageLevel.HIGHEST else LanguageLevel.JDK_1_3) }, - Generator.from { data -> TextChange(Generator.asciiIdentifiers().suchThat { !JavaLexer.isKeyword(it, LanguageLevel.HIGHEST) }.generateValue(data), - Generator.booleans().generateValue(data), - Generator.booleans().generateValue(data)) } + Generator.from { data -> TextChange(data.generateConditional(Generator.asciiIdentifiers()) { !JavaLexer.isKeyword(it, LanguageLevel.HIGHEST) }, + data.generate(Generator.booleans()), + data.generate(Generator.booleans())) } ) PropertyChecker.forAll(Generator.listsOf(genAction)).withIterationCount(20).shouldHold { actions -> val prevLevel = LanguageLevelModuleExtensionImpl.getInstance(myFixture.module).languageLevel diff --git a/jetCheck/src/jetCheck/AbstractDataStructure.java b/jetCheck/src/jetCheck/AbstractDataStructure.java index 665e011c6713..6e0abb3be39a 100644 --- a/jetCheck/src/jetCheck/AbstractDataStructure.java +++ b/jetCheck/src/jetCheck/AbstractDataStructure.java @@ -1,5 +1,7 @@ package jetCheck; +import org.jetbrains.annotations.NotNull; + /** * @author peter */ @@ -21,4 +23,11 @@ abstract class AbstractDataStructure implements DataStructure { return sizeHint; } + @Override + public T generate(@NotNull Generator generator) { + return generator.getGeneratorFunction().apply(subStructure()); + } + + @NotNull + abstract DataStructure subStructure(); } diff --git a/jetCheck/src/jetCheck/DataStructure.java b/jetCheck/src/jetCheck/DataStructure.java index c5f13cfa9d4b..30aad21b8248 100644 --- a/jetCheck/src/jetCheck/DataStructure.java +++ b/jetCheck/src/jetCheck/DataStructure.java @@ -17,8 +17,8 @@ public interface DataStructure { /** * @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. + * 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, the size hint of the structure used by called generators is + * generally less than the original one's. */ int getSizeHint(); @@ -26,8 +26,7 @@ public interface DataStructure { return drawInt(IntDistribution.uniform(0, getSizeHint())); } - @NotNull - DataStructure subStructure(); + T generate(@NotNull Generator generator); T generateNonShrinkable(@NotNull Generator generator); diff --git a/jetCheck/src/jetCheck/FrequencyGenerator.java b/jetCheck/src/jetCheck/FrequencyGenerator.java index a781910e7b92..3c0068c33e4a 100644 --- a/jetCheck/src/jetCheck/FrequencyGenerator.java +++ b/jetCheck/src/jetCheck/FrequencyGenerator.java @@ -33,12 +33,12 @@ public class FrequencyGenerator extends Generator { private static Function frequencyFunction(List> alternatives) { List weights = alternatives.stream().map(w -> w.weight).collect(Collectors.toList()); IntDistribution distribution = IntDistribution.frequencyDistribution(weights); - return data -> alternatives.get(data.drawInt(distribution)).generator.generateValue(data); + return data -> data.generate(alternatives.get(data.drawInt(distribution)).generator); } @NotNull - private static List> weightedGenerators(int weight1, Generator alternative1, - int weight2, Generator alternative2) { + private static List> weightedGenerators(int weight1, Generator alternative1, + int weight2, Generator alternative2) { List> alternatives = new ArrayList<>(); alternatives.add(new WeightedGenerator<>(weight1, alternative1)); alternatives.add(new WeightedGenerator<>(weight2, alternative2)); diff --git a/jetCheck/src/jetCheck/GenerativeDataStructure.java b/jetCheck/src/jetCheck/GenerativeDataStructure.java index 6bf9f67b99a0..c0d5930e6b7b 100644 --- a/jetCheck/src/jetCheck/GenerativeDataStructure.java +++ b/jetCheck/src/jetCheck/GenerativeDataStructure.java @@ -26,7 +26,7 @@ class GenerativeDataStructure extends AbstractDataStructure { @NotNull @Override - public GenerativeDataStructure subStructure() { + GenerativeDataStructure subStructure() { return new GenerativeDataStructure(random, node.subStructure(), childSizeHint()); } diff --git a/jetCheck/src/jetCheck/Generator.java b/jetCheck/src/jetCheck/Generator.java index 62a064b74ae7..bef721c21c1a 100644 --- a/jetCheck/src/jetCheck/Generator.java +++ b/jetCheck/src/jetCheck/Generator.java @@ -26,7 +26,7 @@ public class Generator { /** * Creates a generator from a custom function, that creates objects of the given type based on the data from {@link DataStructure}. * The generator may call {@link DataStructure#drawInt} methods directly (and interpret those ints in any way it wishes), - * or invoke other generators using {@link #generateValue(DataStructure)}.

+ * or invoke other generators using {@link DataStructure#generate(Generator)}.

* * When a property is falsified, the DataStructure is attempted to be minimized, and the generator will be run on * ever "smaller" versions of it, this enables automatic minimization on all kinds of generated types.

@@ -39,13 +39,6 @@ public class Generator { return new Generator<>(function); } - /** - * Generates a value inside the given data structure. - */ - public T generateValue(@NotNull DataStructure data) { - return myFunction.apply(data.subStructure()); - } - Function getGeneratorFunction() { return myFunction; } @@ -65,10 +58,10 @@ public class Generator { */ public Generator flatMap(@NotNull Function> fun) { return from(data -> { - T value = generateValue(data); + T value = data.generate(this); Generator result = fun.apply(value); if (result == null) throw new NullPointerException(fun + " returned null on " + value); - return result.generateValue(data); + return data.generate(result); }); } @@ -121,7 +114,7 @@ public class Generator { if (alternatives.isEmpty()) throw new IllegalArgumentException("No alternatives to choose from"); return from(data -> { int index = data.generateNonShrinkable(integers(0, alternatives.size() - 1)); - return alternatives.get(index).generateValue(data); + return data.generate(alternatives.get(index)); }); } @@ -140,7 +133,7 @@ public class Generator { /** Gets the data from two generators and invokes the given function to produce a result based on the two generated values. */ public static Generator zipWith(Generator gen1, Generator gen2, BiFunction zip) { - return from(data -> zip.apply(gen1.generateValue(data), gen2.generateValue(data))); + return from(data -> zip.apply(data.generate(gen1), data.generate(gen2))); } /** @@ -269,7 +262,7 @@ public class Generator { private static List generateList(Generator itemGenerator, DataStructure data, int size) { List list = new ArrayList<>(size); for (int i = 0; i < size; i++) { - list.add(itemGenerator.generateValue(data)); + list.add(data.generate(itemGenerator)); } return Collections.unmodifiableList(list); } diff --git a/jetCheck/src/jetCheck/ReplayDataStructure.java b/jetCheck/src/jetCheck/ReplayDataStructure.java index c042efa09617..a0f3b37ed5ba 100644 --- a/jetCheck/src/jetCheck/ReplayDataStructure.java +++ b/jetCheck/src/jetCheck/ReplayDataStructure.java @@ -31,18 +31,18 @@ class ReplayDataStructure extends AbstractDataStructure { @NotNull @Override - public DataStructure subStructure() { + DataStructure subStructure() { return new ReplayDataStructure(nextChild(StructureNode.class), childSizeHint(), customizer); } @Override public T generateNonShrinkable(@NotNull Generator generator) { - return generator.generateValue(this); + return generate(generator); } @Override public T generateConditional(@NotNull Generator generator, @NotNull Predicate condition) { - T value = generator.generateValue(this); + T value = generate(generator); if (!condition.test(value)) throw new CannotRestoreValue(); return value; } diff --git a/jetCheck/test/jetCheck/RecursiveGeneratorTest.java b/jetCheck/test/jetCheck/RecursiveGeneratorTest.java index 6169673d888b..8dd2bbfb8c7d 100644 --- a/jetCheck/test/jetCheck/RecursiveGeneratorTest.java +++ b/jetCheck/test/jetCheck/RecursiveGeneratorTest.java @@ -26,7 +26,7 @@ public class RecursiveGeneratorTest extends PropertyCheckerTestCase { public void testShrinksToLeafDespiteWrapping() { checkShrinksToLeaf(Generator.recursive(nodes -> Generator.frequency(2, leaves, - 1, Generator.from(data -> Generator.listsOf(nodes).map(Composite::new).generateValue(data))))); + 1, Generator.from(data -> data.generate(Generator.listsOf(nodes).map(Composite::new)))))); } private interface Node {} diff --git a/jetCheck/test/jetCheck/StatefulGeneratorTest.java b/jetCheck/test/jetCheck/StatefulGeneratorTest.java index a32c2453dc59..252b1673c186 100644 --- a/jetCheck/test/jetCheck/StatefulGeneratorTest.java +++ b/jetCheck/test/jetCheck/StatefulGeneratorTest.java @@ -15,10 +15,10 @@ public class StatefulGeneratorTest extends PropertyCheckerTestCase { AtomicInteger modelLength = new AtomicInteger(0); Generator> cmds = Generator.listsOf(Generator.from(cmdData -> { int index = cmdData.drawInt(IntDistribution.uniform(0, modelLength.getAndIncrement())); - char c = Generator.asciiLetters().generateValue(cmdData); + char c = cmdData.generate(Generator.asciiLetters()); return new InsertChar(c, index); })); - return cmds.generateValue(data); + return data.generate(cmds); }); List minCmds = checkGeneratesExample(gen, cmds -> InsertChar.performOperations(cmds).contains("ab"), diff --git a/platform/platform-tests/testSrc/com/intellij/psi/impl/PsiEventConsistencyTest.kt b/platform/platform-tests/testSrc/com/intellij/psi/impl/PsiEventConsistencyTest.kt index 954f38d248d6..5e6e5b3e1ed7 100644 --- a/platform/platform-tests/testSrc/com/intellij/psi/impl/PsiEventConsistencyTest.kt +++ b/platform/platform-tests/testSrc/com/intellij/psi/impl/PsiEventConsistencyTest.kt @@ -23,7 +23,7 @@ import one.util.streamex.IntStreamEx class PsiEventConsistencyTest : LightPlatformCodeInsightFixtureTestCase() { fun testPsiDocSynchronization() { - PropertyChecker.forAll(commands()).shouldHold { cmd -> + PropertyChecker.forAll(commands).shouldHold { cmd -> runCommand(cmd) true } @@ -91,14 +91,14 @@ class PsiEventConsistencyTest : LightPlatformCodeInsightFixtureTestCase() { } private val genCoords = Generator.zipWith(Generator.naturals(), Generator.integers(0, 5), ::NodeCoordinates) - private fun commands(): Generator = Generator.frequency( - 1, Generator.from { CommandGroup(Generator.listsOf(IntDistribution.uniform(1, 5), commands()).generateValue(it)) }, + private val commands: Generator = Generator.recursive { rec -> Generator.frequency( + 1, Generator.listsOf(IntDistribution.uniform(1, 5), rec).map(::CommandGroup), 5, genCoords.flatMap { coords -> Generator.anyOf( Generator.constant(DeleteElement(coords)), nodes.map { ReplaceElement(coords, it) }, Generator.zipWith(nodes, Generator.naturals()) { n, i -> AddElement(coords, i, n) } - ) }) + ) }) } private val leafTypes = IntStreamEx.range(1, 5).mapToObj { i -> IElementType("Leaf" + i, null) }.toList() private val compositeTypes = IntStreamEx.range(1, 5).mapToObj { i -> IElementType("Composite" + i, null) }.toList() diff --git a/platform/testFramework/testSrc/com/intellij/testFramework/propertyBased/DeleteRange.java b/platform/testFramework/testSrc/com/intellij/testFramework/propertyBased/DeleteRange.java index da0a9ee3a6be..b0128cdfcfe2 100644 --- a/platform/testFramework/testSrc/com/intellij/testFramework/propertyBased/DeleteRange.java +++ b/platform/testFramework/testSrc/com/intellij/testFramework/propertyBased/DeleteRange.java @@ -36,7 +36,7 @@ public class DeleteRange extends ActionOnRange { return Generator.from(data -> { if (psiFile.getTextLength() == 0) return new DeleteRange(psiFile, 0, 0); - int startOffset = Generator.integers(0, psiFile.getTextLength() - 1).generateValue(data); + int startOffset = data.generate(Generator.integers(0, psiFile.getTextLength() - 1)); PsiElement start = psiFile.findElementAt(startOffset); PsiElement end = psiFile.findElementAt(startOffset + data.drawInt(IntDistribution.geometric(10))); if (start == null || end == null) return null;