diff --git a/java/java-tests/testSrc/com/intellij/java/propertyBased/AbstractApplyAndRevertTestCase.java b/java/java-tests/testSrc/com/intellij/java/propertyBased/AbstractApplyAndRevertTestCase.java index 84720ac43b64..c35d19e89445 100644 --- a/java/java-tests/testSrc/com/intellij/java/propertyBased/AbstractApplyAndRevertTestCase.java +++ b/java/java-tests/testSrc/com/intellij/java/propertyBased/AbstractApplyAndRevertTestCase.java @@ -70,7 +70,7 @@ public abstract class AbstractApplyAndRevertTestCase extends PlatformTestCase { protected Generator javaFiles() { GlobalSearchScope projectScope = GlobalSearchScope.projectScope(myProject); List allFiles = new ArrayList<>(FilenameIndex.getAllFilesByExt(myProject, "java", projectScope)); - return Generator.anyValue(allFiles); + return Generator.sampledFrom(allFiles); } protected static void restrictChangesToDocument(Document document, Runnable r) { diff --git a/java/java-tests/testSrc/com/intellij/java/propertyBased/ApplyRandomIntentionsTest.java b/java/java-tests/testSrc/com/intellij/java/propertyBased/ApplyRandomIntentionsTest.java index f9e6607b0760..a4e646a1106b 100644 --- a/java/java-tests/testSrc/com/intellij/java/propertyBased/ApplyRandomIntentionsTest.java +++ b/java/java-tests/testSrc/com/intellij/java/propertyBased/ApplyRandomIntentionsTest.java @@ -96,7 +96,7 @@ public class ApplyRandomIntentionsTest extends AbstractApplyAndRevertTestCase { if (psiFile == null) return false; Generator genInvocation = Generator.from(data -> InvokeIntention.generate(psiFile, data)).noShrink(); - PropertyChecker.forAll(settings.withIterationCount(20), GenCollection.nonEmptyListOf(genInvocation), list -> { + PropertyChecker.forAll(settings.withIterationCount(20), Generator.nonEmptyLists(genInvocation), list -> { PsiDocumentManager documentManager = PsiDocumentManager.getInstance(myProject); changeAndRevert(() -> { if (mutation != null) { @@ -135,7 +135,7 @@ public class ApplyRandomIntentionsTest extends AbstractApplyAndRevertTestCase { Generator genIntention = Generator.from(data -> InvokeIntention.generate(psiManager.findFile(javaFiles().generateValue(data)), data)); - PropertyChecker.forAll(settings, GenCollection.listOf(genIntention.noShrink()), list -> { + PropertyChecker.forAll(settings, Generator.listsOf(genIntention.noShrink()), list -> { long startModCount = tracker.getModificationCount(); if (rebuildStamp.getAndSet(startModCount) != startModCount) { checkCompiles(myCompilerTester.rebuild()); diff --git a/java/java-tests/testSrc/com/intellij/java/propertyBased/CompletionConsistencyTest.java b/java/java-tests/testSrc/com/intellij/java/propertyBased/CompletionConsistencyTest.java index d44ff8318bca..bef9a8a25e14 100644 --- a/java/java-tests/testSrc/com/intellij/java/propertyBased/CompletionConsistencyTest.java +++ b/java/java-tests/testSrc/com/intellij/java/propertyBased/CompletionConsistencyTest.java @@ -79,10 +79,10 @@ public class CompletionConsistencyTest extends AbstractApplyAndRevertTestCase { Generator genInvocation = Generator.from(data -> { int offset = data.drawInt(IntDistribution.uniform(0, textLength)); int itemIndex = data.drawInt(IntDistribution.uniform(0, 100)); - char c = Generator.anyValue('\n', '\t', '\r', ' ', '.', '(').generateUnstructured(data); + char c = Generator.sampledFrom('\n', '\t', '\r', ' ', '.', '(').generateUnstructured(data); return new CompletionInvocation(document, offset, itemIndex, c); }); - PropertyChecker.forAll(settings.withIterationCount(10), GenCollection.listOf(genInvocation), list -> { + PropertyChecker.forAll(settings.withIterationCount(10), Generator.listsOf(genInvocation), list -> { changeAndRevert(() -> restrictChangesToDocument(document, () -> { for (int i = 0; i < list.size(); i++) { PsiDocumentManager.getInstance(myProject).commitAllDocuments(); diff --git a/java/java-tests/testSrc/com/intellij/java/propertyBased/InvokeIntention.java b/java/java-tests/testSrc/com/intellij/java/propertyBased/InvokeIntention.java index ebc7448d54f4..e3bff0849fb3 100644 --- a/java/java-tests/testSrc/com/intellij/java/propertyBased/InvokeIntention.java +++ b/java/java-tests/testSrc/com/intellij/java/propertyBased/InvokeIntention.java @@ -29,7 +29,7 @@ import com.intellij.util.containers.ContainerUtil; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import slowCheck.DataStructure; -import slowCheck.GenNumber; +import slowCheck.Generator; import java.util.List; @@ -47,8 +47,8 @@ class InvokeIntention extends ActionOnRange { @NotNull static InvokeIntention generate(@NotNull PsiFile psiFile, @NotNull DataStructure data) { return new InvokeIntention(psiFile, - GenNumber.integers(0, psiFile.getTextLength()).generateValue(data), - GenNumber.integers(0, 100).generateValue(data)); + Generator.integers(0, psiFile.getTextLength()).generateValue(data), + Generator.integers(0, 100).generateValue(data)); } @Override diff --git a/java/java-tests/testSrc/com/intellij/java/propertyBased/PsiIndexConsistencyTest.kt b/java/java-tests/testSrc/com/intellij/java/propertyBased/PsiIndexConsistencyTest.kt index 1b1e386571e7..c6403e603d38 100644 --- a/java/java-tests/testSrc/com/intellij/java/propertyBased/PsiIndexConsistencyTest.kt +++ b/java/java-tests/testSrc/com/intellij/java/propertyBased/PsiIndexConsistencyTest.kt @@ -30,7 +30,9 @@ import com.intellij.testFramework.PlatformTestUtil import com.intellij.testFramework.fixtures.CodeInsightTestFixture import com.intellij.testFramework.fixtures.LightCodeInsightFixtureTestCase import com.intellij.util.FileContentUtilCore -import slowCheck.* +import slowCheck.CheckerSettings +import slowCheck.Generator +import slowCheck.PropertyChecker /** * @author peter @@ -40,24 +42,24 @@ class PsiIndexConsistencyTest: LightCodeInsightFixtureTestCase() { fun testFuzzActions() { val genAction: Generator = Generator.frequency(mapOf( 1 to Generator.constant(Gc), - 50 to Generator.anyValue(Commit, - AddImport, - AddEnum, - ForceReloadPsi, - Reformat, - InvisiblePsiChange, - PostponedFormatting, - RenamePsiFile, - RenameVirtualFile, - Save), - 10 to Generator.anyValue(*RefKind.values()).map { LoadRef(it) }, - 10 to Generator.anyValue(*RefKind.values()).map { ClearRef(it) }, - 5 to GenBoolean.bool().map { ChangeLanguageLevel(if (it) LanguageLevel.HIGHEST else LanguageLevel.JDK_1_3) }, - 5 to Generator.from { data -> TextChange(GenString.asciiIdentifier().generateValue(data), - GenBoolean.bool().generateValue(data), - GenBoolean.bool().generateValue(data)) } + 50 to Generator.sampledFrom(Commit, + AddImport, + AddEnum, + ForceReloadPsi, + Reformat, + InvisiblePsiChange, + PostponedFormatting, + RenamePsiFile, + RenameVirtualFile, + Save), + 10 to Generator.sampledFrom(*RefKind.values()).map { LoadRef(it) }, + 10 to Generator.sampledFrom(*RefKind.values()).map { ClearRef(it) }, + 5 to Generator.booleans().map { ChangeLanguageLevel(if (it) LanguageLevel.HIGHEST else LanguageLevel.JDK_1_3) }, + 5 to Generator.from { data -> TextChange(Generator.asciiIdentifiers().generateValue(data), + Generator.booleans().generateValue(data), + Generator.booleans().generateValue(data)) } )) - PropertyChecker.forAll(CheckerSettings.DEFAULT_SETTINGS.withIterationCount(20), GenCollection.listOf (genAction)) { actions -> + PropertyChecker.forAll(CheckerSettings.DEFAULT_SETTINGS.withIterationCount(20), Generator.listsOf(genAction)) { actions -> runActions(*actions.toTypedArray()) true } diff --git a/platform/util/testSrc/com/intellij/util/text/StringUtilTest.java b/platform/util/testSrc/com/intellij/util/text/StringUtilTest.java index ee24be42710d..7a6669f1961e 100644 --- a/platform/util/testSrc/com/intellij/util/text/StringUtilTest.java +++ b/platform/util/testSrc/com/intellij/util/text/StringUtilTest.java @@ -24,8 +24,7 @@ import com.intellij.xml.util.XmlStringUtil; import org.jdom.Verifier; import org.jetbrains.annotations.NotNull; import org.junit.Test; -import slowCheck.GenCollection; -import slowCheck.GenString; +import slowCheck.Generator; import slowCheck.PropertyChecker; import java.nio.CharBuffer; @@ -187,7 +186,7 @@ public class StringUtilTest { @Test public void testNaturalCompareTransitivityProperty() { - PropertyChecker.forAll(GenCollection.listOf(GenString.stringOf("ab01()_# ")), l -> { + PropertyChecker.forAll(Generator.listsOf(Generator.stringsOf("ab01()_# ")), l -> { List sorted = ContainerUtil.sorted(l, StringUtil::naturalCompare); for (int i = 0; i < sorted.size(); i++) { for (int j = i + 1; j < sorted.size(); j++) { diff --git a/slowCheck/src/slowCheck/DoubleGenerator.java b/slowCheck/src/slowCheck/DoubleGenerator.java deleted file mode 100644 index f30220c06642..000000000000 --- a/slowCheck/src/slowCheck/DoubleGenerator.java +++ /dev/null @@ -1,19 +0,0 @@ -package slowCheck; - -import java.util.function.Function; - -class DoubleGenerator implements Function { - - private static double calcEdgeCaseProbability(double fraction) { - double atStart = 0.9; - double atEnd = 0.001; - return atStart * Math.pow(atEnd / atStart, fraction); - } - - @Override - public Double apply(DataStructure data) { - long i1 = data.drawInt(); - long i2 = data.drawInt(); - return Double.longBitsToDouble((i1 << 32) + i2); - } -} diff --git a/slowCheck/src/slowCheck/GenBoolean.java b/slowCheck/src/slowCheck/GenBoolean.java deleted file mode 100644 index f75353d737fe..000000000000 --- a/slowCheck/src/slowCheck/GenBoolean.java +++ /dev/null @@ -1,12 +0,0 @@ -package slowCheck; - -/** - * @author peter - */ -public class GenBoolean { - - public static Generator bool() { - return GenNumber.integers(0, 1).map(i -> i == 1); - } - -} diff --git a/slowCheck/src/slowCheck/GenChar.java b/slowCheck/src/slowCheck/GenChar.java deleted file mode 100644 index f27941acf80a..000000000000 --- a/slowCheck/src/slowCheck/GenChar.java +++ /dev/null @@ -1,30 +0,0 @@ -package slowCheck; - -/** - * @author peter - */ -public class GenChar { - public static Generator range(char min, char max) { - return GenNumber.integers(min, max).map(i -> (char)i.intValue()).noShrink(); - } - - public static Generator asciiPrintable() { - return range((char)32, (char)126); - } - - public static Generator asciiUppercase() { - return range('A', 'Z'); - } - - public static Generator asciiLowercase() { - return range('a', 'z'); - } - - public static Generator asciiLetter() { - return Generator.frequency(9, asciiLowercase(), 1, asciiUppercase()).noShrink(); - } - - public static Generator digit() { - return range('0', '9'); - } -} diff --git a/slowCheck/src/slowCheck/GenCollection.java b/slowCheck/src/slowCheck/GenCollection.java deleted file mode 100644 index 5224a43461cc..000000000000 --- a/slowCheck/src/slowCheck/GenCollection.java +++ /dev/null @@ -1,28 +0,0 @@ -package slowCheck; - -import java.util.*; - -/** - * @author peter - */ -public class GenCollection { - public static Generator> listOf(Generator itemGenerator) { - return Generator.from(data -> generateList(itemGenerator, data, data.suggestCollectionSize())); - } - - public static Generator> nonEmptyListOf(Generator itemGenerator) { - return listOf(itemGenerator).suchThat(l -> !l.isEmpty()); - } - - public static Generator> listOf(IntDistribution length, Generator itemGenerator) { - return Generator.from(data -> generateList(itemGenerator, data, data.drawInt(length))); - } - - 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)); - } - return Collections.unmodifiableList(list); - } -} diff --git a/slowCheck/src/slowCheck/GenNumber.java b/slowCheck/src/slowCheck/GenNumber.java deleted file mode 100644 index 525dff209b0f..000000000000 --- a/slowCheck/src/slowCheck/GenNumber.java +++ /dev/null @@ -1,19 +0,0 @@ -package slowCheck; - -/** - * @author peter - */ -public class GenNumber { - public static Generator integers() { - return Generator.from(data -> data.drawInt()); - } - - public static Generator integers(int min, int max) { - IntDistribution distribution = IntDistribution.uniform(min, max); - return Generator.from(data -> data.drawInt(distribution)); - } - - public static Generator doubles() { - return Generator.from(new DoubleGenerator()); - } -} diff --git a/slowCheck/src/slowCheck/GenString.java b/slowCheck/src/slowCheck/GenString.java deleted file mode 100644 index b1f240519637..000000000000 --- a/slowCheck/src/slowCheck/GenString.java +++ /dev/null @@ -1,32 +0,0 @@ -package slowCheck; - -import org.jetbrains.annotations.NotNull; - -import java.util.List; -import java.util.stream.Collectors; -import java.util.stream.IntStream; - -/** - * @author peter - */ -public class GenString { - public static Generator stringOf(@NotNull String possibleChars) { - List chars = IntStream.range(0, possibleChars.length()).mapToObj(possibleChars::charAt).collect(Collectors.toList()); - return stringOf(Generator.anyValue(chars)); - } - - public static Generator stringOf(@NotNull Generator charGen) { - return GenCollection.listOf(charGen).map(chars -> { - StringBuilder sb = new StringBuilder(); - chars.forEach(sb::append); - return sb.toString(); - }); - } - - public static Generator asciiIdentifier() { - return stringOf(Generator.frequency(50, GenChar.asciiLetter(), - 5, GenChar.digit(), - 1, Generator.constant('_'))) - .suchThat(s -> s.length() > 0 && !Character.isDigit(s.charAt(0))); - } -} diff --git a/slowCheck/src/slowCheck/Generator.java b/slowCheck/src/slowCheck/Generator.java index 856707e4bdf2..d11922d9d021 100644 --- a/slowCheck/src/slowCheck/Generator.java +++ b/slowCheck/src/slowCheck/Generator.java @@ -6,14 +6,11 @@ import java.util.*; import java.util.function.Function; import java.util.function.Predicate; import java.util.stream.Collectors; +import java.util.stream.IntStream; /** * A generator for objects based on random data from {@link DataStructure}. * - * @see GenNumber - * @see GenChar - * @see GenString - * @see GenCollection * @author peter */ public final class Generator { @@ -48,28 +45,32 @@ public final class Generator { return from(data -> data.generateConditional(this, condition)); } + // ------------------------------------ + // common generators + // ------------------------------------ + public static Generator constant(T value) { return from(data -> value); } @SafeVarargs - public static Generator anyValue(T... values) { - return anyValue(Arrays.asList(values)); + public static Generator sampledFrom(T... values) { + return sampledFrom(Arrays.asList(values)); } - public static Generator anyValue(List values) { - return oneOf(values.stream().map(Generator::constant).collect(Collectors.toList())); + public static Generator sampledFrom(List values) { + return anyOf(values.stream().map(Generator::constant).collect(Collectors.toList())); } @SafeVarargs - public static Generator oneOf(Generator... alternatives) { - return oneOf(Arrays.asList(alternatives)); + public static Generator anyOf(Generator... alternatives) { + return anyOf(Arrays.asList(alternatives)); } - public static Generator oneOf(List> alternatives) { + public static Generator anyOf(List> alternatives) { if (alternatives.isEmpty()) throw new IllegalArgumentException("No alternatives to choose from"); return from(data -> { - int index = data.generateNonShrinkable(GenNumber.integers(0, alternatives.size() - 1)); + int index = data.generateNonShrinkable(integers(0, alternatives.size() - 1)); return alternatives.get(index).generateValue(data); }); } @@ -98,4 +99,97 @@ public final class Generator { return from(data -> alternatives.get(weights.get(data.drawInt(distribution))).generateValue(data)); } + public static Generator booleans() { + return integers(0, 1).map(i -> i == 1); + } + + // char generators + + public static Generator charsInRange(char min, char max) { + return integers(min, max).map(i -> (char)i.intValue()).noShrink(); + } + + public static Generator asciiPrintableChars() { + return charsInRange((char)32, (char)126); + } + + public static Generator asciiUppercaseChars() { + return charsInRange('A', 'Z'); + } + + public static Generator asciiLowercaseChars() { + return charsInRange('a', 'z'); + } + + public static Generator asciiLetters() { + return frequency(9, asciiLowercaseChars(), 1, asciiUppercaseChars()).noShrink(); + } + + public static Generator digits() { + return charsInRange('0', '9'); + } + + // strings + + public static Generator stringsOf(@NotNull String possibleChars) { + List chars = IntStream.range(0, possibleChars.length()).mapToObj(possibleChars::charAt).collect(Collectors.toList()); + return stringsOf(sampledFrom(chars)); + } + + public static Generator stringsOf(@NotNull Generator charGen) { + return listsOf(charGen).map(chars -> { + StringBuilder sb = new StringBuilder(); + chars.forEach(sb::append); + return sb.toString(); + }); + } + + public static Generator asciiIdentifiers() { + return stringsOf(frequency(50, asciiLetters(), + 5, digits(), + 1, constant('_'))) + .suchThat(s -> s.length() > 0 && !Character.isDigit(s.charAt(0))); + } + + + // numbers + + public static Generator integers() { + return from(data -> data.drawInt()); + } + + public static Generator integers(int min, int max) { + IntDistribution distribution = IntDistribution.uniform(min, max); + return from(data -> data.drawInt(distribution)); + } + + public static Generator doubles() { + return from(data -> { + long i1 = data.drawInt(); + long i2 = data.drawInt(); + return Double.longBitsToDouble((i1 << 32) + i2); + }); + } + + // lists + + public static Generator> listsOf(Generator itemGenerator) { + return from(data -> generateList(itemGenerator, data, data.suggestCollectionSize())); + } + + public static Generator> nonEmptyLists(Generator itemGenerator) { + return listsOf(itemGenerator).suchThat(l -> !l.isEmpty()); + } + + public static Generator> listsOf(IntDistribution length, Generator itemGenerator) { + return from(data -> generateList(itemGenerator, data, data.drawInt(length))); + } + + 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)); + } + return Collections.unmodifiableList(list); + } } diff --git a/slowCheck/test/slowCheck/GeneratorTest.java b/slowCheck/test/slowCheck/GeneratorTest.java index 1131e4b8cd89..beca7deede24 100644 --- a/slowCheck/test/slowCheck/GeneratorTest.java +++ b/slowCheck/test/slowCheck/GeneratorTest.java @@ -9,14 +9,7 @@ import java.util.Set; import java.util.function.Predicate; import java.util.stream.Collectors; -import static slowCheck.GenBoolean.bool; -import static slowCheck.GenChar.asciiLetter; -import static slowCheck.GenChar.asciiPrintable; -import static slowCheck.GenCollection.listOf; -import static slowCheck.GenCollection.nonEmptyListOf; -import static slowCheck.GenNumber.doubles; -import static slowCheck.GenNumber.integers; -import static slowCheck.GenString.stringOf; +import static slowCheck.Generator.*; /** * @author peter @@ -31,43 +24,43 @@ public class GeneratorTest extends TestCase { } public void testListSumMod() { - checkFalsified(nonEmptyListOf(integers()), + checkFalsified(nonEmptyLists(integers()), l -> l.stream().mapToInt(Integer::intValue).sum() % 10 != 0, 7); } public void testListContainsDivisible() { - checkFalsified(nonEmptyListOf(integers()), + checkFalsified(nonEmptyLists(integers()), l -> l.stream().allMatch(i -> i % 10 != 0), 9); } public void testStringContains() { - checkFalsified(stringOf(asciiPrintable()), + checkFalsified(stringsOf(asciiPrintableChars()), s -> !s.contains("a"), 10); } public void testLetterStringContains() { - checkFalsified(stringOf(asciiLetter()), + checkFalsified(stringsOf(asciiLetters()), s -> !s.contains("a"), 5); } public void testIsSorted() { - PropertyFailure> failure = checkFalsified(nonEmptyListOf(integers()), + PropertyFailure> failure = checkFalsified(nonEmptyLists(integers()), l -> l.stream().sorted().collect(Collectors.toList()).equals(l), 69); assertEquals(2, failure.getMinimalCounterexample().getExampleValue().size()); } public void testSuccess() { - PropertyChecker.forAll(listOf(integers(-1, 1)), + PropertyChecker.forAll(listsOf(integers(-1, 1)), l -> l.stream().allMatch(i -> Math.abs(i) <= 1)); } public void testSortedDoublesNonDescending() { - PropertyFailure> failure = checkFalsified(listOf(doubles()), + PropertyFailure> failure = checkFalsified(listsOf(doubles()), l -> isSorted(l.stream().sorted().collect(Collectors.toList())), 141); assertEquals(2, failure.getMinimalCounterexample().getExampleValue().size()); @@ -102,51 +95,51 @@ public class GeneratorTest extends TestCase { } public void testStringOfStringChecksAllChars() { - checkFalsified(stringOf("abc "), + checkFalsified(stringsOf("abc "), s -> !s.contains(" "), 3); } public void testLongListsHappen() { - PropertyFailure> failure = checkFalsified(listOf(integers()), + PropertyFailure> failure = checkFalsified(listsOf(integers()), l -> l.size() < 200, 631); assertEquals(200, failure.getMinimalCounterexample().getExampleValue().size()); } public void testNonEmptyList() { - PropertyChecker.forAll(nonEmptyListOf(integers()), l -> !l.isEmpty()); + PropertyChecker.forAll(nonEmptyLists(integers()), l -> !l.isEmpty()); } public void testNoDuplicateData() { Set> visited = new HashSet<>(); - PropertyChecker.forAll(listOf(integers()), l -> visited.add(l)); + PropertyChecker.forAll(listsOf(integers()), l -> visited.add(l)); } public void testOneOf() { List values = new ArrayList<>(); - PropertyChecker.forAll(Generator.oneOf(integers(0, 1), integers(10, 1100)), i -> values.add(i)); + PropertyChecker.forAll(anyOf(integers(0, 1), integers(10, 1100)), i -> values.add(i)); assertTrue(values.stream().anyMatch(i -> i < 2)); assertTrue(values.stream().anyMatch(i -> i > 5)); } public void testAsciiIdentifier() { - PropertyChecker.forAll(GenString.asciiIdentifier(), + PropertyChecker.forAll(asciiIdentifiers(), s -> Character.isJavaIdentifierStart(s.charAt(0)) && s.chars().allMatch(Character::isJavaIdentifierPart)); - checkFalsified(GenString.asciiIdentifier(), + checkFalsified(asciiIdentifiers(), s -> !s.contains("_"), 1); } public void testBoolean() { - PropertyFailure> failure = checkFalsified(listOf(bool()), + PropertyFailure> failure = checkFalsified(listsOf(booleans()), l -> !l.contains(true) || !l.contains(false), 4); assertEquals(2, failure.getMinimalCounterexample().getExampleValue().size()); } public void testShrinkingNonEmptyList() { - PropertyFailure> failure = checkFalsified(nonEmptyListOf(integers(0, 100)), + PropertyFailure> failure = checkFalsified(nonEmptyLists(integers(0, 100)), l -> !l.contains(42), 10); assertEquals(1, failure.getMinimalCounterexample().getExampleValue().size());