slowCheck: use plural names for generators

This commit is contained in:
peter
2017-06-26 18:13:08 +02:00
parent f1c924fa17
commit 7835d244c4
14 changed files with 153 additions and 205 deletions
@@ -70,7 +70,7 @@ public abstract class AbstractApplyAndRevertTestCase extends PlatformTestCase {
protected Generator<VirtualFile> javaFiles() {
GlobalSearchScope projectScope = GlobalSearchScope.projectScope(myProject);
List<VirtualFile> allFiles = new ArrayList<>(FilenameIndex.getAllFilesByExt(myProject, "java", projectScope));
return Generator.anyValue(allFiles);
return Generator.sampledFrom(allFiles);
}
protected static void restrictChangesToDocument(Document document, Runnable r) {
@@ -96,7 +96,7 @@ public class ApplyRandomIntentionsTest extends AbstractApplyAndRevertTestCase {
if (psiFile == null) return false;
Generator<InvokeIntention> 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<InvokeIntention> 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());
@@ -79,10 +79,10 @@ public class CompletionConsistencyTest extends AbstractApplyAndRevertTestCase {
Generator<CompletionInvocation> 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();
@@ -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
@@ -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<Action> = 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
}
@@ -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<String> sorted = ContainerUtil.sorted(l, StringUtil::naturalCompare);
for (int i = 0; i < sorted.size(); i++) {
for (int j = i + 1; j < sorted.size(); j++) {
@@ -1,19 +0,0 @@
package slowCheck;
import java.util.function.Function;
class DoubleGenerator implements Function<DataStructure, Double> {
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);
}
}
-12
View File
@@ -1,12 +0,0 @@
package slowCheck;
/**
* @author peter
*/
public class GenBoolean {
public static Generator<Boolean> bool() {
return GenNumber.integers(0, 1).map(i -> i == 1);
}
}
-30
View File
@@ -1,30 +0,0 @@
package slowCheck;
/**
* @author peter
*/
public class GenChar {
public static Generator<Character> range(char min, char max) {
return GenNumber.integers(min, max).map(i -> (char)i.intValue()).noShrink();
}
public static Generator<Character> asciiPrintable() {
return range((char)32, (char)126);
}
public static Generator<Character> asciiUppercase() {
return range('A', 'Z');
}
public static Generator<Character> asciiLowercase() {
return range('a', 'z');
}
public static Generator<Character> asciiLetter() {
return Generator.frequency(9, asciiLowercase(), 1, asciiUppercase()).noShrink();
}
public static Generator<Character> digit() {
return range('0', '9');
}
}
@@ -1,28 +0,0 @@
package slowCheck;
import java.util.*;
/**
* @author peter
*/
public class GenCollection {
public static <T> Generator<List<T>> listOf(Generator<T> itemGenerator) {
return Generator.from(data -> generateList(itemGenerator, data, data.suggestCollectionSize()));
}
public static <T> Generator<List<T>> nonEmptyListOf(Generator<T> itemGenerator) {
return listOf(itemGenerator).suchThat(l -> !l.isEmpty());
}
public static <T> Generator<List<T>> listOf(IntDistribution length, Generator<T> itemGenerator) {
return Generator.from(data -> generateList(itemGenerator, data, data.drawInt(length)));
}
private static <T> List<T> generateList(Generator<T> itemGenerator, DataStructure data, int size) {
List<T> list = new ArrayList<>(size);
for (int i = 0; i < size; i++) {
list.add(itemGenerator.generateValue(data));
}
return Collections.unmodifiableList(list);
}
}
-19
View File
@@ -1,19 +0,0 @@
package slowCheck;
/**
* @author peter
*/
public class GenNumber {
public static Generator<Integer> integers() {
return Generator.from(data -> data.drawInt());
}
public static Generator<Integer> integers(int min, int max) {
IntDistribution distribution = IntDistribution.uniform(min, max);
return Generator.from(data -> data.drawInt(distribution));
}
public static Generator<Double> doubles() {
return Generator.from(new DoubleGenerator());
}
}
-32
View File
@@ -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<String> stringOf(@NotNull String possibleChars) {
List<Character> chars = IntStream.range(0, possibleChars.length()).mapToObj(possibleChars::charAt).collect(Collectors.toList());
return stringOf(Generator.anyValue(chars));
}
public static Generator<String> stringOf(@NotNull Generator<Character> charGen) {
return GenCollection.listOf(charGen).map(chars -> {
StringBuilder sb = new StringBuilder();
chars.forEach(sb::append);
return sb.toString();
});
}
public static Generator<String> asciiIdentifier() {
return stringOf(Generator.frequency(50, GenChar.asciiLetter(),
5, GenChar.digit(),
1, Generator.constant('_')))
.suchThat(s -> s.length() > 0 && !Character.isDigit(s.charAt(0)));
}
}
+106 -12
View File
@@ -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<T> {
@@ -48,28 +45,32 @@ public final class Generator<T> {
return from(data -> data.generateConditional(this, condition));
}
// ------------------------------------
// common generators
// ------------------------------------
public static <T> Generator<T> constant(T value) {
return from(data -> value);
}
@SafeVarargs
public static <T> Generator<T> anyValue(T... values) {
return anyValue(Arrays.asList(values));
public static <T> Generator<T> sampledFrom(T... values) {
return sampledFrom(Arrays.asList(values));
}
public static <T> Generator<T> anyValue(List<T> values) {
return oneOf(values.stream().map(Generator::constant).collect(Collectors.toList()));
public static <T> Generator<T> sampledFrom(List<T> values) {
return anyOf(values.stream().map(Generator::constant).collect(Collectors.toList()));
}
@SafeVarargs
public static <T> Generator<T> oneOf(Generator<? extends T>... alternatives) {
return oneOf(Arrays.asList(alternatives));
public static <T> Generator<T> anyOf(Generator<? extends T>... alternatives) {
return anyOf(Arrays.asList(alternatives));
}
public static <T> Generator<T> oneOf(List<Generator<? extends T>> alternatives) {
public static <T> Generator<T> anyOf(List<Generator<? extends T>> 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<T> {
return from(data -> alternatives.get(weights.get(data.drawInt(distribution))).generateValue(data));
}
public static Generator<Boolean> booleans() {
return integers(0, 1).map(i -> i == 1);
}
// char generators
public static Generator<Character> charsInRange(char min, char max) {
return integers(min, max).map(i -> (char)i.intValue()).noShrink();
}
public static Generator<Character> asciiPrintableChars() {
return charsInRange((char)32, (char)126);
}
public static Generator<Character> asciiUppercaseChars() {
return charsInRange('A', 'Z');
}
public static Generator<Character> asciiLowercaseChars() {
return charsInRange('a', 'z');
}
public static Generator<Character> asciiLetters() {
return frequency(9, asciiLowercaseChars(), 1, asciiUppercaseChars()).noShrink();
}
public static Generator<Character> digits() {
return charsInRange('0', '9');
}
// strings
public static Generator<String> stringsOf(@NotNull String possibleChars) {
List<Character> chars = IntStream.range(0, possibleChars.length()).mapToObj(possibleChars::charAt).collect(Collectors.toList());
return stringsOf(sampledFrom(chars));
}
public static Generator<String> stringsOf(@NotNull Generator<Character> charGen) {
return listsOf(charGen).map(chars -> {
StringBuilder sb = new StringBuilder();
chars.forEach(sb::append);
return sb.toString();
});
}
public static Generator<String> asciiIdentifiers() {
return stringsOf(frequency(50, asciiLetters(),
5, digits(),
1, constant('_')))
.suchThat(s -> s.length() > 0 && !Character.isDigit(s.charAt(0)));
}
// numbers
public static Generator<Integer> integers() {
return from(data -> data.drawInt());
}
public static Generator<Integer> integers(int min, int max) {
IntDistribution distribution = IntDistribution.uniform(min, max);
return from(data -> data.drawInt(distribution));
}
public static Generator<Double> doubles() {
return from(data -> {
long i1 = data.drawInt();
long i2 = data.drawInt();
return Double.longBitsToDouble((i1 << 32) + i2);
});
}
// lists
public static <T> Generator<List<T>> listsOf(Generator<T> itemGenerator) {
return from(data -> generateList(itemGenerator, data, data.suggestCollectionSize()));
}
public static <T> Generator<List<T>> nonEmptyLists(Generator<T> itemGenerator) {
return listsOf(itemGenerator).suchThat(l -> !l.isEmpty());
}
public static <T> Generator<List<T>> listsOf(IntDistribution length, Generator<T> itemGenerator) {
return from(data -> generateList(itemGenerator, data, data.drawInt(length)));
}
private static <T> List<T> generateList(Generator<T> itemGenerator, DataStructure data, int size) {
List<T> list = new ArrayList<>(size);
for (int i = 0; i < size; i++) {
list.add(itemGenerator.generateValue(data));
}
return Collections.unmodifiableList(list);
}
}
+17 -24
View File
@@ -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<List<Integer>> failure = checkFalsified(nonEmptyListOf(integers()),
PropertyFailure<List<Integer>> 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<List<Double>> failure = checkFalsified(listOf(doubles()),
PropertyFailure<List<Double>> 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<List<Integer>> failure = checkFalsified(listOf(integers()),
PropertyFailure<List<Integer>> 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<List<Integer>> visited = new HashSet<>();
PropertyChecker.forAll(listOf(integers()), l -> visited.add(l));
PropertyChecker.forAll(listsOf(integers()), l -> visited.add(l));
}
public void testOneOf() {
List<Integer> 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<List<Boolean>> failure = checkFalsified(listOf(bool()),
PropertyFailure<List<Boolean>> failure = checkFalsified(listsOf(booleans()),
l -> !l.contains(true) || !l.contains(false),
4);
assertEquals(2, failure.getMinimalCounterexample().getExampleValue().size());
}
public void testShrinkingNonEmptyList() {
PropertyFailure<List<Integer>> failure = checkFalsified(nonEmptyListOf(integers(0, 100)),
PropertyFailure<List<Integer>> failure = checkFalsified(nonEmptyLists(integers(0, 100)),
l -> !l.contains(42),
10);
assertEquals(1, failure.getMinimalCounterexample().getExampleValue().size());