From 1e170960b6cdcf535aa98210a080e002265a5e2e Mon Sep 17 00:00:00 2001 From: peter Date: Tue, 10 Jul 2018 07:12:44 +0200 Subject: [PATCH] remove jetCheck source now it lives separately on https://github.com/JetBrains/jetCheck --- .idea/modules.xml | 2 - jetCheck/intellij.tools.jetCheck.iml | 15 - .../jetCheck/AbstractDataStructure.java | 39 --- .../jetCheck/BoundedIntDistribution.java | 49 --- .../jetCheck/CannotRestoreValue.java | 13 - .../jetCheck/CannotSatisfyCondition.java | 23 -- .../jetCheck/CounterExampleImpl.java | 61 ---- .../jetbrains/jetCheck/DataSerializer.java | 81 ----- .../org/jetbrains/jetCheck/DataStructure.java | 21 -- .../jetCheck/FrequencyGenerator.java | 60 ---- .../jetCheck/GenerativeDataStructure.java | 92 ------ .../src/org/jetbrains/jetCheck/Generator.java | 307 ------------------ .../jetCheck/GeneratorException.java | 11 - .../jetbrains/jetCheck/ImperativeCommand.java | 91 ------ .../org/jetbrains/jetCheck/IntCustomizer.java | 133 -------- .../jetbrains/jetCheck/IntDistribution.java | 64 ---- .../src/org/jetbrains/jetCheck/IntSource.java | 9 - .../src/org/jetbrains/jetCheck/Iteration.java | 143 -------- .../src/org/jetbrains/jetCheck/NodeId.java | 35 -- .../jetbrains/jetCheck/PropertyChecker.java | 161 --------- .../jetbrains/jetCheck/PropertyFailure.java | 64 ---- .../jetCheck/PropertyFailureImpl.java | 169 ---------- .../jetbrains/jetCheck/PropertyFalsified.java | 131 -------- .../jetbrains/jetCheck/RemoveListRange.java | 94 ------ .../jetCheck/ReplayDataStructure.java | 60 ---- .../src/org/jetbrains/jetCheck/Scenario.java | 152 --------- .../org/jetbrains/jetCheck/ShrinkStep.java | 75 ----- .../jetbrains/jetCheck/StatusNotifier.java | 104 ------ .../org/jetbrains/jetCheck/StructureNode.java | 306 ----------------- .../org/jetbrains/jetCheck/ExceptionTest.java | 84 ----- .../org/jetbrains/jetCheck/GeneratorTest.java | 187 ----------- .../jetCheck/PropertyCheckerTestCase.java | 55 ---- .../jetCheck/RecursiveGeneratorTest.java | 48 --- .../org/jetbrains/jetCheck/ShrinkTest.java | 49 --- .../jetCheck/StatefulGeneratorTest.java | 221 ------------- .../jetbrains/jetCheck/SubSequenceTest.java | 63 ---- 36 files changed, 3272 deletions(-) delete mode 100644 jetCheck/intellij.tools.jetCheck.iml delete mode 100644 jetCheck/src/org/jetbrains/jetCheck/AbstractDataStructure.java delete mode 100644 jetCheck/src/org/jetbrains/jetCheck/BoundedIntDistribution.java delete mode 100644 jetCheck/src/org/jetbrains/jetCheck/CannotRestoreValue.java delete mode 100644 jetCheck/src/org/jetbrains/jetCheck/CannotSatisfyCondition.java delete mode 100644 jetCheck/src/org/jetbrains/jetCheck/CounterExampleImpl.java delete mode 100644 jetCheck/src/org/jetbrains/jetCheck/DataSerializer.java delete mode 100644 jetCheck/src/org/jetbrains/jetCheck/DataStructure.java delete mode 100644 jetCheck/src/org/jetbrains/jetCheck/FrequencyGenerator.java delete mode 100644 jetCheck/src/org/jetbrains/jetCheck/GenerativeDataStructure.java delete mode 100644 jetCheck/src/org/jetbrains/jetCheck/Generator.java delete mode 100644 jetCheck/src/org/jetbrains/jetCheck/GeneratorException.java delete mode 100644 jetCheck/src/org/jetbrains/jetCheck/ImperativeCommand.java delete mode 100644 jetCheck/src/org/jetbrains/jetCheck/IntCustomizer.java delete mode 100644 jetCheck/src/org/jetbrains/jetCheck/IntDistribution.java delete mode 100644 jetCheck/src/org/jetbrains/jetCheck/IntSource.java delete mode 100644 jetCheck/src/org/jetbrains/jetCheck/Iteration.java delete mode 100644 jetCheck/src/org/jetbrains/jetCheck/NodeId.java delete mode 100644 jetCheck/src/org/jetbrains/jetCheck/PropertyChecker.java delete mode 100644 jetCheck/src/org/jetbrains/jetCheck/PropertyFailure.java delete mode 100644 jetCheck/src/org/jetbrains/jetCheck/PropertyFailureImpl.java delete mode 100644 jetCheck/src/org/jetbrains/jetCheck/PropertyFalsified.java delete mode 100644 jetCheck/src/org/jetbrains/jetCheck/RemoveListRange.java delete mode 100644 jetCheck/src/org/jetbrains/jetCheck/ReplayDataStructure.java delete mode 100644 jetCheck/src/org/jetbrains/jetCheck/Scenario.java delete mode 100644 jetCheck/src/org/jetbrains/jetCheck/ShrinkStep.java delete mode 100644 jetCheck/src/org/jetbrains/jetCheck/StatusNotifier.java delete mode 100644 jetCheck/src/org/jetbrains/jetCheck/StructureNode.java delete mode 100644 jetCheck/test/org/jetbrains/jetCheck/ExceptionTest.java delete mode 100644 jetCheck/test/org/jetbrains/jetCheck/GeneratorTest.java delete mode 100644 jetCheck/test/org/jetbrains/jetCheck/PropertyCheckerTestCase.java delete mode 100644 jetCheck/test/org/jetbrains/jetCheck/RecursiveGeneratorTest.java delete mode 100644 jetCheck/test/org/jetbrains/jetCheck/ShrinkTest.java delete mode 100644 jetCheck/test/org/jetbrains/jetCheck/StatefulGeneratorTest.java delete mode 100644 jetCheck/test/org/jetbrains/jetCheck/SubSequenceTest.java diff --git a/.idea/modules.xml b/.idea/modules.xml index 4367f0800f00..f567b239dfd3 100644 --- a/.idea/modules.xml +++ b/.idea/modules.xml @@ -164,7 +164,6 @@ - @@ -692,7 +691,6 @@ - diff --git a/jetCheck/intellij.tools.jetCheck.iml b/jetCheck/intellij.tools.jetCheck.iml deleted file mode 100644 index d97c29bedf1e..000000000000 --- a/jetCheck/intellij.tools.jetCheck.iml +++ /dev/null @@ -1,15 +0,0 @@ - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/jetCheck/src/org/jetbrains/jetCheck/AbstractDataStructure.java b/jetCheck/src/org/jetbrains/jetCheck/AbstractDataStructure.java deleted file mode 100644 index 437f96e2d5ea..000000000000 --- a/jetCheck/src/org/jetbrains/jetCheck/AbstractDataStructure.java +++ /dev/null @@ -1,39 +0,0 @@ -package org.jetbrains.jetCheck; - -import org.jetbrains.annotations.NotNull; - -import java.util.function.Predicate; - -/** - * @author peter - */ -abstract class AbstractDataStructure implements DataStructure { - protected final StructureNode node; - protected final int sizeHint; - - AbstractDataStructure(StructureNode node, int sizeHint) { - this.node = node; - this.sizeHint = sizeHint; - } - - int childSizeHint() { - return Math.max(1, sizeHint - 1); - } - - @Override - public int getSizeHint() { - return sizeHint; - } - - abstract int drawInt(@NotNull IntDistribution distribution); - - int suggestCollectionSize() { - return drawInt(IntDistribution.uniform(0, getSizeHint())); - } - - abstract T generateNonShrinkable(@NotNull Generator generator); - - abstract T generateConditional(@NotNull Generator generator, @NotNull Predicate condition); - - abstract void changeKind(StructureKind kind); -} diff --git a/jetCheck/src/org/jetbrains/jetCheck/BoundedIntDistribution.java b/jetCheck/src/org/jetbrains/jetCheck/BoundedIntDistribution.java deleted file mode 100644 index 532963dbcd3f..000000000000 --- a/jetCheck/src/org/jetbrains/jetCheck/BoundedIntDistribution.java +++ /dev/null @@ -1,49 +0,0 @@ -package org.jetbrains.jetCheck; - -import java.util.Random; -import java.util.function.ToIntFunction; - -public class BoundedIntDistribution implements IntDistribution { - public static final IntDistribution ALL_INTS = IntDistribution.uniform(Integer.MIN_VALUE, Integer.MAX_VALUE); - private final int min; - private final int max; - private final ToIntFunction producer; - - BoundedIntDistribution(int min, int max, ToIntFunction producer) { - if (min > max) throw new IllegalArgumentException(min + ">" + max); - this.min = min; - this.max = max; - this.producer = producer; - } - - int getMin() { - return min; - } - - int getMax() { - return max; - } - - @Override - public int generateInt(Random random) { - int i = producer.applyAsInt(random); - if (i < min || i > max) { - throw new IllegalStateException("Int out of bounds produced by " + producer + ": " + i + " not in [" + min + ", " + max + "]"); - } - return i; - } - - @Override - public boolean isValidValue(int i) { - return i >= min && i <= max; - } - - public static BoundedIntDistribution bound(int min, int max, IntDistribution distribution) { - return new BoundedIntDistribution(min, max, random -> Math.min(Math.max(distribution.generateInt(random), min), max)) { - @Override - public boolean isValidValue(int i) { - return super.isValidValue(i) && distribution.isValidValue(i); - } - }; - } -} \ No newline at end of file diff --git a/jetCheck/src/org/jetbrains/jetCheck/CannotRestoreValue.java b/jetCheck/src/org/jetbrains/jetCheck/CannotRestoreValue.java deleted file mode 100644 index 22979ea172eb..000000000000 --- a/jetCheck/src/org/jetbrains/jetCheck/CannotRestoreValue.java +++ /dev/null @@ -1,13 +0,0 @@ -package org.jetbrains.jetCheck; - -/** - * @author peter - */ -class CannotRestoreValue extends RuntimeException { - CannotRestoreValue() { - } - - CannotRestoreValue(String message) { - super(message); - } -} diff --git a/jetCheck/src/org/jetbrains/jetCheck/CannotSatisfyCondition.java b/jetCheck/src/org/jetbrains/jetCheck/CannotSatisfyCondition.java deleted file mode 100644 index ea65eba05411..000000000000 --- a/jetCheck/src/org/jetbrains/jetCheck/CannotSatisfyCondition.java +++ /dev/null @@ -1,23 +0,0 @@ -package org.jetbrains.jetCheck; - -import org.jetbrains.annotations.NotNull; - -import java.util.function.Predicate; - -/** - * @author peter - */ -@SuppressWarnings("ExceptionClassNameDoesntEndWithException") -public class CannotSatisfyCondition extends RuntimeException { - private final Predicate condition; - - CannotSatisfyCondition(@NotNull Predicate condition) { - super("Cannot satisfy condition " + condition); - this.condition = condition; - } - - @NotNull - public Predicate getCondition() { - return condition; - } -} diff --git a/jetCheck/src/org/jetbrains/jetCheck/CounterExampleImpl.java b/jetCheck/src/org/jetbrains/jetCheck/CounterExampleImpl.java deleted file mode 100644 index ba8d2858f065..000000000000 --- a/jetCheck/src/org/jetbrains/jetCheck/CounterExampleImpl.java +++ /dev/null @@ -1,61 +0,0 @@ -package org.jetbrains.jetCheck; - -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -class CounterExampleImpl implements PropertyFailure.CounterExample { - final StructureNode data; - private final T value; - @Nullable private final Throwable exception; - private final Iteration iteration; - - private CounterExampleImpl(StructureNode data, T value, @Nullable Throwable exception, Iteration iteration) { - this.data = data; - this.value = value; - this.exception = exception; - this.iteration = iteration; - } - - @Override - public T getExampleValue() { - return value; - } - - @Nullable - @Override - public Throwable getExceptionCause() { - return exception; - } - - @NotNull - @Override - public CounterExampleImpl replay() { - T value = iteration.generateValue(createReplayData()); - CounterExampleImpl example = checkProperty(iteration, value, data); - return example != null ? example : - new CounterExampleImpl<>(data, value, new IllegalStateException("Replaying failure is unexpectedly successful!"), iteration); - } - - @NotNull - @Override - public String getSerializedData() { - return DataSerializer.serialize(iteration, data); - } - - ReplayDataStructure createReplayData() { - return new ReplayDataStructure(data, iteration.sizeHint, IntCustomizer::checkValidInt); - } - - static CounterExampleImpl checkProperty(Iteration iteration, T value, StructureNode node) { - try { - if (!iteration.session.property.test(value)) { - return new CounterExampleImpl<>(node, value, null, iteration); - } - } - catch (Throwable e) { - return new CounterExampleImpl<>(node, value, e, iteration); - } - return null; - } - -} \ No newline at end of file diff --git a/jetCheck/src/org/jetbrains/jetCheck/DataSerializer.java b/jetCheck/src/org/jetbrains/jetCheck/DataSerializer.java deleted file mode 100644 index 4c1dffc50998..000000000000 --- a/jetCheck/src/org/jetbrains/jetCheck/DataSerializer.java +++ /dev/null @@ -1,81 +0,0 @@ -// Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. -package org.jetbrains.jetCheck; - -import java.io.*; -import java.util.Base64; - -/** - * @author peter - */ -class DataSerializer { - - private static int readINT(ByteArrayInputStream record) { - int val = readWithEof(record); - if (val < 192) { - return val; - } - - int res = val - 192; - for (int sh = 6; ; sh += 7) { - int next = readWithEof(record); - res |= (next & 0x7F) << sh; - if ((next & 0x80) == 0) { - return res; - } - } - } - - private static int readWithEof(ByteArrayInputStream record) { - if (record.available() <= 0) { - throw new EOFException(); - } - return record.read(); - } - - static void writeINT(DataOutput record, int val) throws IOException { - if (0 > val || val >= 192) { - record.writeByte(192 + (val & 0x3F)); - val >>>= 6; - while (val >= 128) { - record.writeByte((val & 0x7F) | 0x80); - val >>>= 7; - } - } - record.writeByte(val); - } - - static String serialize(Iteration iteration, StructureElement node) { - ByteArrayOutputStream stream = new ByteArrayOutputStream(); - try (DataOutputStream data = new DataOutputStream(stream)) { - writeINT(data, (int)(iteration.iterationSeed >> 32)); - writeINT(data, (int)iteration.iterationSeed); - writeINT(data, iteration.sizeHint); - node.serialize(data); - } - catch (IOException e) { - throw new RuntimeException(e); - } - return Base64.getEncoder().encodeToString(stream.toByteArray()); - } - - static void deserializeInto(String data, PropertyChecker.Parameters parameters) { - ByteArrayInputStream stream = new ByteArrayInputStream(Base64.getDecoder().decode(data)); - - int seedHigh = readINT(stream); - int seedLow = readINT(stream); - parameters.globalSeed = (long)seedHigh << 32 | seedLow & 0xFFFFFFFFL; - - int hint = readINT(stream); - parameters.sizeHintFun = __ -> hint; - - parameters.serializedData = (IntDistribution dist) -> { - int i = readINT(stream); - if (!dist.isValidValue(i)) { - throw new CannotRestoreValue("Error restoring from serialized \"rechecking\" data. Possible cause: either the test or the environment it depends on has changed."); - } - return i; - }; - } - - static class EOFException extends RuntimeException {} -} diff --git a/jetCheck/src/org/jetbrains/jetCheck/DataStructure.java b/jetCheck/src/org/jetbrains/jetCheck/DataStructure.java deleted file mode 100644 index 24b597b1cd7e..000000000000 --- a/jetCheck/src/org/jetbrains/jetCheck/DataStructure.java +++ /dev/null @@ -1,21 +0,0 @@ -package org.jetbrains.jetCheck; - -import org.jetbrains.annotations.NotNull; - -/** - * A context for {@link Generator}s. Primitive generators (e.g. {@link Generator#integers} know how to obtain - * random data from it, other generators build more complex values on top of that, by running {@link #generate(Generator)} recursively. - */ -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, the size hint of the structure used by called generators is - * generally less than the original one's. - */ - int getSizeHint(); - - /** Runs the given generator on a data sub-structure of this structure and returns the result */ - T generate(@NotNull Generator generator); - -} diff --git a/jetCheck/src/org/jetbrains/jetCheck/FrequencyGenerator.java b/jetCheck/src/org/jetbrains/jetCheck/FrequencyGenerator.java deleted file mode 100644 index 74f8608a07de..000000000000 --- a/jetCheck/src/org/jetbrains/jetCheck/FrequencyGenerator.java +++ /dev/null @@ -1,60 +0,0 @@ -package org.jetbrains.jetCheck; - -import org.jetbrains.annotations.NotNull; - -import java.util.ArrayList; -import java.util.List; -import java.util.function.Function; -import java.util.stream.Collectors; - -/** - * @author peter - */ -public class FrequencyGenerator extends Generator { - private final List> alternatives; - - FrequencyGenerator(int weight1, Generator alternative1, - int weight2, Generator alternative2) { - this(weightedGenerators(weight1, alternative1, weight2, alternative2)); - } - - private FrequencyGenerator(List> alternatives) { - super(frequencyFunction(alternatives)); - this.alternatives = alternatives; - } - - FrequencyGenerator with(int weight, Generator alternative) { - List> alternatives = new ArrayList<>(this.alternatives); - alternatives.add(new WeightedGenerator<>(weight, alternative)); - return new FrequencyGenerator<>(alternatives); - } - - @NotNull - private static Function frequencyFunction(List> alternatives) { - List weights = alternatives.stream().map(w -> w.weight).collect(Collectors.toList()); - IntDistribution distribution = IntDistribution.frequencyDistribution(weights); - return data -> { - ((AbstractDataStructure) data).changeKind(StructureKind.CHOICE); - return data.generate(alternatives.get(((AbstractDataStructure)data).drawInt(distribution)).generator); - }; - } - - @NotNull - 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)); - return alternatives; - } - - private static class WeightedGenerator { - final int weight; - final Generator generator; - - WeightedGenerator(int weight, Generator generator) { - this.weight = weight; - this.generator = generator; - } - } -} diff --git a/jetCheck/src/org/jetbrains/jetCheck/GenerativeDataStructure.java b/jetCheck/src/org/jetbrains/jetCheck/GenerativeDataStructure.java deleted file mode 100644 index b176874b4293..000000000000 --- a/jetCheck/src/org/jetbrains/jetCheck/GenerativeDataStructure.java +++ /dev/null @@ -1,92 +0,0 @@ -package org.jetbrains.jetCheck; - -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -import java.util.function.Predicate; - - -/** - * @author peter - */ -class GenerativeDataStructure extends AbstractDataStructure { - private final CurrentData dataTracker; - private final IntSource random; - - GenerativeDataStructure(IntSource random, StructureNode node, int sizeHint) { - this(null, random, node, sizeHint); - } - - private GenerativeDataStructure(@Nullable CurrentData dataTracker, IntSource random, StructureNode node, int sizeHint) { - super(node, sizeHint); - this.random = random; - this.dataTracker = dataTracker != null ? dataTracker : new CurrentData(); - } - - @Override - int drawInt(@NotNull IntDistribution distribution) { - dataTracker.checkContext(this); - int i = random.drawInt(distribution); - node.addChild(new IntData(node.id.childId(null), i, distribution)); - return i; - } - - @Override - public T generate(@NotNull Generator generator) { - return dataTracker.generateOn(generator, subStructure(generator, childSizeHint()), this); - } - - @NotNull - private GenerativeDataStructure subStructure(@NotNull Generator generator, int childSizeHint) { - return new GenerativeDataStructure(dataTracker, random, node.subStructure(generator), childSizeHint); - } - - @Override - T generateNonShrinkable(@NotNull Generator generator) { - GenerativeDataStructure data = subStructure(generator, sizeHint); - data.node.shrinkProhibited = true; - return dataTracker.generateOn(generator, data, this); - } - - @Override - T generateConditional(@NotNull Generator generator, @NotNull Predicate condition) { - for (int i = 0; i < 100; i++) { - GenerativeDataStructure structure = subStructure(generator, childSizeHint()); - T value = dataTracker.generateOn(generator, structure, this); - if (condition.test(value)) return value; - - node.removeLastChild(structure.node); - } - throw new CannotSatisfyCondition(condition); - } - - @Override - void changeKind(StructureKind kind) { - node.kind = kind; - } - - private class CurrentData { - DataStructure current = GenerativeDataStructure.this; - - T generateOn(Generator gen, GenerativeDataStructure data, GenerativeDataStructure parent) { - checkContext(parent); - current = data; - try { - return gen.getGeneratorFunction().apply(data); - } - finally { - current = parent; - } - } - - void checkContext(GenerativeDataStructure data) { - if (current != data) throw new WrongDataStructure(); - } - } -} - -class WrongDataStructure extends IllegalStateException { - WrongDataStructure() { - super("You're calling methods on wrong DataStructure, confusing nested lambda arguments?"); - } -} \ No newline at end of file diff --git a/jetCheck/src/org/jetbrains/jetCheck/Generator.java b/jetCheck/src/org/jetbrains/jetCheck/Generator.java deleted file mode 100644 index 3876fe2e6c19..000000000000 --- a/jetCheck/src/org/jetbrains/jetCheck/Generator.java +++ /dev/null @@ -1,307 +0,0 @@ -package org.jetbrains.jetCheck; - -import org.jetbrains.annotations.NotNull; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collections; -import java.util.List; -import java.util.concurrent.atomic.AtomicReference; -import java.util.function.BiFunction; -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}.

- * - * A generator is a function that takes a source of random data (which is DataStructure) and, using that random data - * (e.g. by calling more primitive generators and reinterpreting their results), constructs a value of type {@code T}. - * For data structures returning the same data, generators should produce equivalent values.

- * - * Generators for standard types can be obtained using static methods of this class (e.g. {@link #integers}, {@link #listsOf} etc). - * Generators for custom types can be created by deriving them from standard types (e.g. via {@link #map}, {@link #flatMap}, {@link #zipWith}) - * or by writing your own from scratch ({@link #from(Function)}). - */ -public class Generator { - private final Function myFunction; - - Generator(Function function) { - myFunction = function; - } - - /** - * Creates a generator from a custom function, that creates objects of the given type based on the data from {@link DataStructure}. - * The generator may invoke other, more primitive, 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.

- * - * To ensure test reproducibility during re-run or minimization phase, - * the result of the generators should only depend on the DataStructure. Generators should not have any side effects - * or depend on the outside world. Generators may have internal mutable state accessible to other (nested) generators, - * but that's error-prone, difficult and computationally expensive to minimize. If you still think you need that, - * please see {@link ImperativeCommand} for potentially more convenient way of testing stateful systems. - */ - @NotNull - public static Generator from(@NotNull Function function) { - return new Generator<>(function); - } - - Function getGeneratorFunction() { - return myFunction; - } - - /** - * Invokes "this" generator, and then applies the given function to transform the generated value in any way. - * The function should not depend on anything besides its argument. - */ - public Generator map(@NotNull Function fun) { - return from(data -> fun.apply(myFunction.apply(data))); - } - - /** - * Invokes "this" generator, and then applies the given function to provide a new generator that additionally - * depends on the generated value. - * The function should not depend on anything besides its argument. - */ - public Generator flatMap(@NotNull Function> fun) { - return from(data -> { - T value = data.generate(this); - Generator result = fun.apply(value); - if (result == null) throw new NullPointerException(fun + " returned null on " + value); - return data.generate(result); - }); - } - - /** - * Turns off automatic minimization for the data produced by this generator (and its components, if any). - * This can be useful to speed up minimization by not wasting time on shrinking objects where it makes no sense. - * It's especially useful when using stateful generators (e.g. {@link ImperativeCommand}), because - * shrinkable values there can lead to doubling of the shrinking time. - */ - public Generator noShrink() { - return from(data -> ((AbstractDataStructure)data).generateNonShrinkable(this)); - } - - /** - * Attempts to generate the value several times, until one comes out that satisfies the given condition. That value is returned as generator result. - * Results of all previous attempts are discarded. During shrinking, the underlying data structures from those attempts - * won't be used for re-running generation, so be careful that those attempts don't leave any traces of themselves - * (e.g. side effects, even ones internal to an outer generator).

- * - * If the condition still fails after a large number of attempts, data generation is stopped prematurely and {@link CannotSatisfyCondition} exception is thrown.

- * - * This method is useful to avoid infrequent corner cases (e.g. {@code integers().suchThat(i -> i != 0)}). - * To eliminate large portions of search space, this strategy might prove ineffective - * and result in generator failure due to inability to come up with satisfying examples - * (e.g. {@code integers().suchThat(i -> i > 0 && i <= 10)} - * where the condition would be {@code true} in just 10 of about 4 billion times). In such cases, please consider changing the generator instead of using {@code suchThat}. - */ - public Generator suchThat(@NotNull Predicate condition) { - return from(data -> ((AbstractDataStructure)data).generateConditional(this, condition)); - } - - // ------------------------------------ - // common generators - // ------------------------------------ - - /** A generator that always returns the same value */ - public static Generator constant(T value) { - return from(data -> value); - } - - /** A generator that returns one of the given values with equal probability */ - @SafeVarargs - public static Generator sampledFrom(T... values) { - return sampledFrom(Arrays.asList(values)); - } - - /** A generator that returns one of the given values with equal probability */ - public static Generator sampledFrom(List values) { - return anyOf(values.stream().map(Generator::constant).collect(Collectors.toList())); - } - - /** Delegates to one of the given generators with equal probability */ - @SafeVarargs - public static Generator anyOf(Generator... alternatives) { - return anyOf(Arrays.asList(alternatives)); - } - - /** Delegates to one of the given generators with equal probability */ - public static Generator anyOf(List> alternatives) { - if (alternatives.isEmpty()) throw new IllegalArgumentException("No alternatives to choose from"); - return from(data -> { - ((AbstractDataStructure) data).changeKind(StructureKind.CHOICE); - int index = ((AbstractDataStructure)data).drawInt(IntDistribution.uniform(0, alternatives.size() - 1)); - return data.generate(alternatives.get(index)); - }); - } - - /** Delegates one of the two generators with probability corresponding to their weights */ - public static FrequencyGenerator frequency(int weight1, Generator alternative1, - int weight2, Generator alternative2) { - return new FrequencyGenerator<>(weight1, alternative1, weight2, alternative2); - } - - /** Delegates one of the three generators with probability corresponding to their weights */ - public static Generator frequency(int weight1, Generator alternative1, - int weight2, Generator alternative2, - int weight3, Generator alternative3) { - return frequency(weight1, alternative1, weight2, alternative2).with(weight3, alternative3); - } - - /** 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(data.generate(gen1), data.generate(gen2))); - } - - /** - * A fixed-point combinator to easily create recursive generators by giving a name to the whole generator and allowing to reuse it inside itself. For example, a recursive tree generator could be defined as follows by binding itself to the name {@code nodes}: - *

-   * Generator gen = Generator.recursive(nodes -> Generator.anyOf(
-   *   Generator.constant(new Leaf()),
-   *   Generator.listsOf(nodes).map(children -> new Composite(children))))  
-   * 
- * @return the generator returned from the passed function - */ - @NotNull - public static Generator recursive(@NotNull Function, ? extends Generator> createGenerator) { - AtomicReference> ref = new AtomicReference<>(); - Generator result = from(data -> ref.get().getGeneratorFunction().apply(data)); - ref.set(createGenerator.apply(result)); - return result; - } - - /** A generator that returns 'true' or 'false' */ - public static Generator booleans() { - return integers(0, 1).map(i -> i == 1); - } - - // char generators - - /** Generates characters in the given range (both ends inclusive) */ - public static Generator charsInRange(char min, char max) { - return integers(min, max).map(i -> (char)i.intValue()); - } - - /** Generates characters that occur in the given string */ - public static Generator charsFrom(String possibleChars) { - return sampledFrom(IntStream.range(0, possibleChars.length()).mapToObj(possibleChars::charAt).collect(Collectors.toList())); - } - - /** Generates ASCII characters excluding the system ones (lower than 32) */ - public static Generator asciiPrintableChars() { - return charsInRange((char)32, (char)126); - } - - /** Generates uppercase latin letters */ - public static Generator asciiUppercaseChars() { - return charsInRange('A', 'Z'); - } - - /** Generates lowercase latin letters */ - public static Generator asciiLowercaseChars() { - return charsInRange('a', 'z'); - } - - /** Generates latin letters, with a preference for lowercase ones */ - public static Generator asciiLetters() { - return frequency(9, asciiLowercaseChars(), 1, asciiUppercaseChars()).noShrink(); - } - - /** Generates decimal digits */ - public static Generator digits() { - return charsInRange('0', '9'); - } - - // strings - - /** Generates (possibly empty) random strings consisting of the given characters (provided as a string) */ - public static Generator stringsOf(@NotNull String possibleChars) { - return stringsOf(charsFrom(possibleChars)); - } - - /** Generates (possibly empty) random strings consisting of characters provided by the given generator */ - public static Generator stringsOf(@NotNull Generator charGen) { - return listsOf(charGen).map(Generator::charsToString); - } - - /** Generates (possibly empty) random strings of length in the given distribution, consisting of characters provided by the given generator */ - public static Generator stringsOf(@NotNull IntDistribution length, @NotNull Generator charGen) { - return listsOf(length, charGen).map(Generator::charsToString); - } - - @NotNull - private static String charsToString(List chars) { - StringBuilder sb = new StringBuilder(); - chars.forEach(sb::append); - return sb.toString(); - } - - /** Generates random strings consisting ASCII letters and digit and starting with a letter */ - public static Generator asciiIdentifiers() { - return stringsOf(frequency(50, asciiLetters(), - 5, digits(), - 1, constant('_'))) - .suchThat(s -> s.length() > 0 && !Character.isDigit(s.charAt(0))); - } - - - // numbers - - /** Generates any integers */ - public static Generator integers() { - return integers(BoundedIntDistribution.ALL_INTS); - } - - public static Generator naturals() { - return integers(0, Integer.MAX_VALUE); - } - - /** Generates integers uniformly distributed in the given range (both ends inclusive) */ - public static Generator integers(int min, int max) { - return integers(IntDistribution.uniform(min, max)); - } - - /** Generates integers with the given distribution */ - public static Generator integers(@NotNull IntDistribution distribution) { - return from(data -> ((AbstractDataStructure)data).drawInt(distribution)); - } - - /** Generates any doubles, including infinities and NaN */ - public static Generator doubles() { - return from(data -> { - long i1 = data.generate(integers(BoundedIntDistribution.ALL_INTS)); - long i2 = data.generate(integers(BoundedIntDistribution.ALL_INTS)); - return Double.longBitsToDouble((i1 << 32) + (i2 & 0xffffffffL)); - }); - } - - // lists - - /** Generates (possibly empty) lists of values produced by the given generator */ - public static Generator> listsOf(Generator itemGenerator) { - return from(data -> generateList(itemGenerator, data, ((AbstractDataStructure)data).suggestCollectionSize())); - } - - /** Generates non-empty lists of values produced by the given generator */ - public static Generator> nonEmptyLists(Generator itemGenerator) { - return listsOf(itemGenerator).suchThat(l -> !l.isEmpty()); - } - - /** Generates lists of values produced by the given generator. The list length is determined by the given distribution. */ - public static Generator> listsOf(IntDistribution length, Generator itemGenerator) { - return from(data -> generateList(itemGenerator, data, ((AbstractDataStructure)data).drawInt(length))); - } - - private static List generateList(Generator itemGenerator, DataStructure data, int size) { - ((AbstractDataStructure) data).changeKind(StructureKind.LIST); - List list = new ArrayList<>(size); - for (int i = 0; i < size; i++) { - list.add(data.generate(itemGenerator)); - } - return Collections.unmodifiableList(list); - } -} diff --git a/jetCheck/src/org/jetbrains/jetCheck/GeneratorException.java b/jetCheck/src/org/jetbrains/jetCheck/GeneratorException.java deleted file mode 100644 index 2fdccfdbfc2c..000000000000 --- a/jetCheck/src/org/jetbrains/jetCheck/GeneratorException.java +++ /dev/null @@ -1,11 +0,0 @@ -package org.jetbrains.jetCheck; - -/** - * @author peter - */ -public class GeneratorException extends RuntimeException { - - GeneratorException(Iteration iteration, Throwable cause) { - super("Exception while generating data, " + iteration.printSeeds(), cause); - } -} diff --git a/jetCheck/src/org/jetbrains/jetCheck/ImperativeCommand.java b/jetCheck/src/org/jetbrains/jetCheck/ImperativeCommand.java deleted file mode 100644 index eaf9fb571130..000000000000 --- a/jetCheck/src/org/jetbrains/jetCheck/ImperativeCommand.java +++ /dev/null @@ -1,91 +0,0 @@ -/* - * Copyright 2000-2017 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. - */ -package org.jetbrains.jetCheck; - -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -/** - * Represents an action with potential side effects, for single-threaded property-based testing of stateful systems. - * The engine executes a top-level command, which should prepare the system-under-test and run the sequence of nested (actual) commands - * that change the system, check the needed invariants, and log all activity to allow to reproduce failing scenarios.

- * - * A typical way to test with imperative commands looks like this: - *

- *   PropertyChecker.checkScenarios(() -> env -> {
- *     System sys = setUpSystem();
- *     try {
- *       // run a random sequence of commands
- *       env.performCommands(Generator.sampledFrom(new Command1(sys), new Command2(sys), ...))
- *       assertPropertyHolds(sys); // optional; fail with an exception if some invariant is broken 
- *     } finally {
- *       tearDownSystem(); // if any resources should be freed
- *     }
- *   })
- *   ...
- *   class Command1 implements ImperativeCommand {
- *     System sys;
- *     Command1(System sys) {
- *       this.sys = sys;
- *     }
- *     
- *     public void performCommand(Environment env) {
- *       env.logMessage("Performing command1");
- *       // do some actions on 'sys' using environment to generate random data (and log it) on the way, e.g.:
- *       Item item = env.generateData(Generator.sampledFrom(sys.currentItems), "working on %s item");
- *       modifyItemInTheSystem(sys, item); // may change the system and the items within it
- *     }
- *   }
- *   ...
- * 
- * - * If any command fails with an exception, the property being checked is considered to be falsified and the test fails. - * In the error message, the causing exception is printed together with command log. - * Commands can and should log what they're doing using - * {@link Environment#logMessage(String)} and {@link Environment#generateValue(Generator, String)} so that you - * can restore the order of events that leads to the failure.

- * - * Top-level command should not have any side effects on the outside world, - * otherwise proper test case separation and minimization will be impossible. - * The supplier that creates the top-level command should - * return a "fresh" object each time, as it's invoked on each testing and minimization iterations. - * Nested commands may have side effects, provided that those effects are fully contained within the system-under-test, - * which is set up and disposed inside the top-level command on each iteration.

- * - * Test case minimization is complicated, when commands make random choices based on the current state of the system - * (which can change even after removing irrelevant commands during minimization). - * The engine tries to account for that heuristically. Rule of thumb: whenever your command generates an index into some list, - * or uses {@link Generator#sampledFrom} on system elements, try to ensure that these elements have some predictable ordering. - * It's ideal if each command effect on these elements is either adding or removing a contiguous range in that list. - */ -public interface ImperativeCommand { - /** Perform the actual change on the system-under-test, using {@code env} to generate random data and log the progress */ - void performCommand(@NotNull Environment env); - - /** A helper object passed into {@link #performCommand} to allow for logging and ad hoc random data generation */ - interface Environment { - - /** Add a log message. The whole execution log would be printed if the command fails */ - void logMessage(@NotNull String message); - - /** Generate a pseudo-random value using the given generator. - * Optionally log a message, so that when a test fails, you'd know the value was generated. - * The message is a Java format string, so you can use it to include the generated value, e.g. - * {@code String s = generateValue(stringsOf(asciiLetters(), "Generated %s")}.

- * If you don't want to generate message, or would like to show the generated value in a custom way, pass {@code null}. - * You can use {@link #logMessage} later to still leave a trace of this value generation in the log.

- * - * Consider making generators non-shrinkable (by invoking {@link Generator#noShrink()}) where possible - * because it can speed up overall failing scenario minimization significantly. - */ - T generateValue(@NotNull Generator generator, @Nullable String logMessage); - - /** Executes a sequence (of length with the given distribution) of random nested commands (produced by the given generator) */ - void executeCommands(IntDistribution count, Generator cmdGen); - - /** Executes a non-empty sequence of random nested commands (produced by the given generator) */ - void executeCommands(Generator cmdGen); - } -} - diff --git a/jetCheck/src/org/jetbrains/jetCheck/IntCustomizer.java b/jetCheck/src/org/jetbrains/jetCheck/IntCustomizer.java deleted file mode 100644 index bc9021fa9436..000000000000 --- a/jetCheck/src/org/jetbrains/jetCheck/IntCustomizer.java +++ /dev/null @@ -1,133 +0,0 @@ -// Copyright 2000-2017 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. -package org.jetbrains.jetCheck; - -import org.jetbrains.annotations.Nullable; - -import java.util.*; -import java.util.stream.Collectors; - -/** - * @author peter - */ - -interface IntCustomizer { - int suggestInt(IntData data, IntDistribution currentDistribution); - - static int checkValidInt(IntData data, IntDistribution currentDistribution) { - int value = data.value; - if (!currentDistribution.isValidValue(value)) throw new CannotRestoreValue(); - return value; - } - -} - -class CombinatorialIntCustomizer implements IntCustomizer { - private final LinkedHashMap> valuesToTry; - private final Map currentCombination; - private final Map changedDistributions = new HashMap<>(); - - CombinatorialIntCustomizer() { - this(new LinkedHashMap<>(), new HashMap<>()); - } - - private CombinatorialIntCustomizer(LinkedHashMap> valuesToTry, Map currentCombination) { - this.valuesToTry = valuesToTry; - this.currentCombination = currentCombination; - } - - public int suggestInt(IntData data, IntDistribution currentDistribution) { - if (data.distribution instanceof BoundedIntDistribution && - currentDistribution instanceof BoundedIntDistribution && - registerDifferentRange(data, (BoundedIntDistribution)currentDistribution, (BoundedIntDistribution)data.distribution)) { - return suggestCombinatorialVariant(data, currentDistribution); - } - return IntCustomizer.checkValidInt(data, currentDistribution); - } - - private int suggestCombinatorialVariant(IntData data, IntDistribution currentDistribution) { - int value = currentCombination.computeIfAbsent(data.id, __ -> valuesToTry.get(data.id).iterator().next()); - if (currentDistribution.isValidValue(value)) { - return value; - } - - throw new CannotRestoreValue(); - } - - private boolean registerDifferentRange(IntData data, BoundedIntDistribution current, BoundedIntDistribution original) { - if (currentCombination.containsKey(data.id)) { - changedDistributions.put(data.id, current); - return true; - } - - if (original.getMax() != current.getMax() || original.getMin() != current.getMin()) { - LinkedHashSet possibleValues = getPossibleValues(data, current, original); - if (!possibleValues.isEmpty()) { - assert !valuesToTry.containsKey(data.id); - valuesToTry.put(data.id, possibleValues); - changedDistributions.put(data.id, current); - return true; - } - } - return false; - } - - private LinkedHashSet getPossibleValues(IntData data, BoundedIntDistribution current, BoundedIntDistribution original) { - List possibleValues = new ArrayList<>(); - int fromStart = data.value - original.getMin(); - int fromEnd = original.getMax() - data.value; - - int sameDistanceFromStart = current.getMin() + fromStart; - int sameDistanceFromEnd = current.getMax() - fromEnd; - - if (!tooManyCombinations()) { - if (fromStart < fromEnd) { - possibleValues.add(sameDistanceFromStart); - possibleValues.add(sameDistanceFromEnd); - } else { - possibleValues.add(sameDistanceFromEnd); - possibleValues.add(sameDistanceFromStart); - } - } - possibleValues.add(data.value); - - return possibleValues.stream() - .map(value -> Math.min(Math.max(value, current.getMin()), current.getMax())) - .filter(current::isValidValue) - .collect(Collectors.toCollection(LinkedHashSet::new)); - } - - private boolean tooManyCombinations() { - return valuesToTry.values().stream().filter(s -> s.size() > 1).count() > 3; - } - - @Nullable - CombinatorialIntCustomizer nextAttempt() { - Map nextCombination = new HashMap<>(currentCombination); - for (Map.Entry> entry : valuesToTry.entrySet()) { - List possibleValues = new ArrayList<>(entry.getValue()); - Integer usedValue = currentCombination.get(entry.getKey()); - int index = possibleValues.indexOf(usedValue); - if (index < possibleValues.size() - 1) { - // found a position which can be incremented by 1 - nextCombination.put(entry.getKey(), possibleValues.get(index + 1)); - return new CombinatorialIntCustomizer(valuesToTry, nextCombination); - } - // digit overflow in this position, so zero it and try incrementing the next one - nextCombination.put(entry.getKey(), possibleValues.get(0)); - } - return null; - } - - StructureNode writeChanges(StructureNode node) { - StructureNode result = node; - for (Map.Entry entry : changedDistributions.entrySet()) { - NodeId id = entry.getKey(); - result = result.replace(id, new IntData(id, currentCombination.get(id), entry.getValue())); - } - return result; - } - - int countVariants() { - return valuesToTry.values().stream().mapToInt(Set::size).reduce(1, (a, b) -> a*b); - } -} \ No newline at end of file diff --git a/jetCheck/src/org/jetbrains/jetCheck/IntDistribution.java b/jetCheck/src/org/jetbrains/jetCheck/IntDistribution.java deleted file mode 100644 index 0c675680153a..000000000000 --- a/jetCheck/src/org/jetbrains/jetCheck/IntDistribution.java +++ /dev/null @@ -1,64 +0,0 @@ -package org.jetbrains.jetCheck; - -import java.util.List; -import java.util.Random; - -/** - * Used for generating random int values with custom distribution, and ensuring that minimized integer values don't violate that distribution. - */ -public interface IntDistribution { - /** Returns an int value distributed in the needed fashion using the given Random */ - int generateInt(Random random); - - /** @return true if the given value is valid for this distribution */ - boolean isValidValue(int i); - - /** - * This distribution returns an integer uniformly distributed between {@code min} and {@code max} (both ends inclusive). - */ - static IntDistribution uniform(int min, int max) { - return new BoundedIntDistribution(min, max, r -> { - if (min == max) return min; - - int i = r.nextInt(); - return i >= min && i <= max ? i : Math.abs(i) % (max - min + 1) + min; - }); - } - - /** - * Geometric distribution ("number of failures until first success") with a given mean - */ - static IntDistribution geometric(int mean) { - double p = 1.0 / (mean + 1); - return new IntDistribution() { - @Override - public int generateInt(Random random) { - double u = random.nextDouble(); - return (int) (Math.log(u) / Math.log(1 - p)); - } - - @Override - public boolean isValidValue(int i) { - return i >= 0; - } - }; - } - - /** - * The distribution for numbers in {@code [0, ..., weights.size()-1]} range, where the probability of {@code i} - * is equal to {@code weights.get(i)/sum(weights)}. - */ - static IntDistribution frequencyDistribution(List weights) { - if (weights.isEmpty()) throw new IllegalArgumentException("No alternatives to choose from"); - - int sum = weights.stream().reduce(0, (a, b) -> a + b); - return new BoundedIntDistribution(0, weights.size() - 1, r -> { - int value = r.nextInt(sum); - for (int i = 0; i < weights.size(); i++) { - value -= weights.get(i); - if (value < 0) return i; - } - throw new IllegalArgumentException(); - }); - } -} diff --git a/jetCheck/src/org/jetbrains/jetCheck/IntSource.java b/jetCheck/src/org/jetbrains/jetCheck/IntSource.java deleted file mode 100644 index 773de4ec3120..000000000000 --- a/jetCheck/src/org/jetbrains/jetCheck/IntSource.java +++ /dev/null @@ -1,9 +0,0 @@ -// Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. -package org.jetbrains.jetCheck; - -/** - * @author peter - */ -interface IntSource { - int drawInt(IntDistribution distribution); -} diff --git a/jetCheck/src/org/jetbrains/jetCheck/Iteration.java b/jetCheck/src/org/jetbrains/jetCheck/Iteration.java deleted file mode 100644 index b23c34e28f94..000000000000 --- a/jetCheck/src/org/jetbrains/jetCheck/Iteration.java +++ /dev/null @@ -1,143 +0,0 @@ -package org.jetbrains.jetCheck; - -import org.jetbrains.annotations.Nullable; - -import java.util.*; -import java.util.function.Predicate; - -class Iteration { - - private static final Predicate DATA_IS_DIFFERENT = new Predicate() { - @Override - public boolean test(Object o) { - return false; - } - - @Override - public String toString() { - return ": cannot generate enough sufficiently different values"; - } - }; - - final CheckSession session; - long iterationSeed; - final int sizeHint; - final int iterationNumber; - private Random random; - - Iteration(CheckSession session, long iterationSeed, int iterationNumber) { - this.session = session; - this.sizeHint = session.parameters.sizeHintFun.applyAsInt(iterationNumber); - this.iterationNumber = iterationNumber; - if (sizeHint < 0) { - throw new IllegalArgumentException("Size hint should be non-negative, found " + sizeHint); - } - initSeed(iterationSeed); - } - - private void initSeed(long seed) { - iterationSeed = seed; - random = new Random(seed); - } - - @Nullable - private CounterExampleImpl findCounterExample() { - for (int i = 0; i < 100; i++) { - if (i > 0) { - initSeed(random.nextLong()); - } - StructureNode node = new StructureNode(new NodeId(session.generator)); - T value; - try { - IntSource source = session.parameters.serializedData != null ? session.parameters.serializedData : d -> d.generateInt(random); - value = session.generator.getGeneratorFunction().apply(new GenerativeDataStructure(source, node, sizeHint)); - } - catch (CannotSatisfyCondition e) { - continue; - } - catch (DataSerializer.EOFException e) { - session.notifier.eofException(); - return null; - } - catch (WrongDataStructure e) { - throw e; - } - catch (Throwable e) { - //noinspection InstanceofCatchParameter - if (e instanceof CannotRestoreValue && session.parameters.serializedData != null) { - throw e; - } - throw new GeneratorException(this, e); - } - if (!session.addGeneratedNode(node)) continue; - - return CounterExampleImpl.checkProperty(this, value, node); - } - throw new GeneratorException(this, new CannotSatisfyCondition(DATA_IS_DIFFERENT)); - } - - String printToReproduce(@Nullable Throwable failureReason, CounterExampleImpl minimalCounterExample) { - String data = minimalCounterExample.getSerializedData(); - boolean scenarios = - failureReason != null && StatusNotifier.printStackTrace(failureReason).contains("PropertyChecker$Parameters.checkScenarios"); - String rechecking = "PropertyChecker.customized().rechecking(\"" + data + "\")\n ." + - (scenarios ? "checkScenarios" : "forAll") + "(...)\n"; - return "To reproduce the minimal failing case, run\n " + rechecking + - "To re-run the test with all intermediate minimization steps, use `recheckingIteration(" + iterationSeed + "L, " + sizeHint + ")` instead for last iteration, or `withSeed(" + session.parameters.globalSeed + "L)` for all iterations"; - } - - String printSeeds() { - return "iteration seed=" + iterationSeed + "L, " + - "size hint=" + sizeHint + ", " + - "global seed=" + session.parameters.globalSeed + "L"; - } - - @Nullable - Iteration performIteration() { - session.notifier.iterationStarted(iterationNumber); - - CounterExampleImpl example = findCounterExample(); - if (example != null) { - session.notifier.counterExampleFound(this); - throw new PropertyFalsified(new PropertyFailureImpl<>(example, this)); - } - - if (iterationNumber >= session.parameters.iterationCount) { - return null; - } - - return new Iteration<>(session, random.nextLong(), iterationNumber + 1); - } - - T generateValue(ReplayDataStructure data) { - return session.generator.getGeneratorFunction().apply(data); - } -} - -class CheckSession { - final Generator generator; - final Predicate property; - final PropertyChecker.Parameters parameters; - final StatusNotifier notifier; - private final Set generatedNodes = Collections.newSetFromMap(new LinkedHashMap() { - @Override - protected boolean removeEldestEntry(Map.Entry eldest) { - return size() > 1_000; - } - }); - - CheckSession(Generator generator, Predicate property, PropertyChecker.Parameters parameters) { - this.generator = generator; - this.property = property; - this.parameters = parameters; - notifier = parameters.silent ? StatusNotifier.SILENT : new StatusNotifier(parameters.iterationCount); - } - - boolean addGeneratedNode(StructureNode node) { - return generatedNodes.add(node); - } - - Iteration firstIteration() { - return new Iteration<>(this, parameters.globalSeed, 1); - } -} diff --git a/jetCheck/src/org/jetbrains/jetCheck/NodeId.java b/jetCheck/src/org/jetbrains/jetCheck/NodeId.java deleted file mode 100644 index ac39bcb8378f..000000000000 --- a/jetCheck/src/org/jetbrains/jetCheck/NodeId.java +++ /dev/null @@ -1,35 +0,0 @@ -// Copyright 2000-2017 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. -package org.jetbrains.jetCheck; - -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -import java.util.concurrent.atomic.AtomicInteger; - -/** - * @author peter - */ -class NodeId { - private final AtomicInteger counter; - final int number; - @Nullable final Integer generatorHash; - - NodeId(@NotNull Generator generator) { - this(new AtomicInteger(), generator); - } - - private NodeId(AtomicInteger counter, @Nullable Generator generator) { - this.counter = counter; - this.generatorHash = generator == null ? null : generator.getGeneratorFunction().hashCode(); - number = counter.getAndIncrement(); - } - - NodeId childId(@Nullable Generator generator) { - return new NodeId(counter, generator); - } - - @Override - public String toString() { - return String.valueOf(number); - } -} diff --git a/jetCheck/src/org/jetbrains/jetCheck/PropertyChecker.java b/jetCheck/src/org/jetbrains/jetCheck/PropertyChecker.java deleted file mode 100644 index e4cdf7985ffb..000000000000 --- a/jetCheck/src/org/jetbrains/jetCheck/PropertyChecker.java +++ /dev/null @@ -1,161 +0,0 @@ -package org.jetbrains.jetCheck; - -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -import java.util.Random; -import java.util.function.IntUnaryOperator; -import java.util.function.Predicate; -import java.util.function.Supplier; - -/** - * An entry point to property-based testing. The main usage pattern: {@code PropertyChecker.forAll(generator, property)}. - */ -public class PropertyChecker { - static final int DEFAULT_MAX_SIZE_HINT = 100; - - /** - * Checks that the given property returns {@code true} and doesn't throw exceptions by running the generator and the property - * on random data repeatedly for some number of times. To customize the settings, invoke {@link #customized()} first. - */ - public static void forAll(Generator generator, @NotNull Predicate property) { - customized().forAll(generator, property); - } - - /** - * Performs a check that the scenarios generated by the given command are successful. Default {@link PropertyChecker} settings are used. To customize the settings, invoke {@link #customized()} first. - * @param command a supplier for a top-level command. This supplier should not have any side effects. - */ - public static void checkScenarios(@NotNull Supplier command) { - customized().checkScenarios(command); - } - - /** - * @return a "parameters" object that where some checker settings can be changed - */ - public static Parameters customized() { - return new Parameters(); - } - - @SuppressWarnings("UseOfSystemOutOrSystemErr") - public static class Parameters { - long globalSeed = new Random().nextLong(); - @Nullable IntSource serializedData; - IntUnaryOperator sizeHintFun = iteration -> (iteration - 1) % DEFAULT_MAX_SIZE_HINT + 1; - int iterationCount = 100; - boolean silent; - - private Parameters() { - } - - /** - * This function allows to start the test with a fixed random seed. It's useful to reproduce some previous test run and debug it. - * @param seed A random seed to use for the first iteration. - * The following iterations will use other, pseudo-random seeds, but still derived from this one. - * @return this PropertyChecker - * @deprecated To catch your attention. It's fine to call this method during test debugging, but it should not be committed to version control - * and used in regression tests, because any changes in the test itself or the framework can render the passed argument obsolete. - * For regression testing, it's recommended to code the failing scenario explicitly. - */ - @Deprecated - @SuppressWarnings("DeprecatedIsStillUsed") - public Parameters withSeed(long seed) { - if (serializedData != null) { - System.err.println("withSeed ignored, because 'rechecking' is used"); - return this; - } - - globalSeed = seed; - return this; - } - - /** - * @param iterationCount the number of iterations to try. By default it's 100. - * @return this PropertyChecker - */ - public Parameters withIterationCount(int iterationCount) { - if (serializedData != null) { - System.err.println("withIterationCount ignored, because 'rechecking' is used"); - return this; - } - this.iterationCount = iterationCount; - return this; - } - - /** - * @param sizeHintFun a function determining how size hint should be distributed depending on the iteration number. - * By default the size hint will be 1 in the first iteration, 2 in the second one, and so on until 100, - * then again 1,...,100,1,...,100, etc. - * @return this PropertyChecker - * @see DataStructure#getSizeHint() - */ - public Parameters withSizeHint(@NotNull IntUnaryOperator sizeHintFun) { - if (serializedData != null) { - System.err.println("withSizeHint ignored, because 'rechecking' is used"); - return this; - } - - this.sizeHintFun = sizeHintFun; - return this; - } - - /** - * Suppresses all output from the testing infrastructure during property check and shrinking - * @return this PropertyChecker - */ - public Parameters silent() { - this.silent = true; - return this; - } - - /** - * Checks the property within a single iteration by using specified seed and size hint. Useful to debug the test after it's failed, if {@link #rechecking} isn't enough (e.g. due to unforeseen side effects). - * @deprecated To catch your attention. It's fine to call this method during test debugging, but it should not be committed to version control - * and used in regression tests, because any changes in the test itself or the framework can render the passed arguments obsolete. - * For regression testing, it's recommended to code the failing scenario explicitly. - */ - @Deprecated - @SuppressWarnings("DeprecatedIsStillUsed") - public Parameters recheckingIteration(long seed, int sizeHint) { - return withSeed(seed).withSizeHint(whatever -> sizeHint).withIterationCount(1); - } - - /** - * Checks the property within a single iteration by using specified underlying data. Useful to debug the test after it's failed. - * @param serializedData the data used for running generators in serialized form, as printed by {@link PropertyFailure} exception. - * @deprecated To catch your attention. It's fine to call this method during test debugging, but it should not be committed to version control - * and used in regression tests, because any changes in the test itself or the framework can render the passed argument obsolete. - * For regression testing, it's recommended to code the failing scenario explicitly. - */ - @Deprecated - @SuppressWarnings("DeprecatedIsStillUsed") - public Parameters rechecking(@NotNull String serializedData) { - this.iterationCount = 1; - DataSerializer.deserializeInto(serializedData, this); - return this; - } - - /** - * Checks that the given property returns {@code true} and doesn't throw exceptions by running the given generator and the property - * on random data repeatedly for some number of times (see {@link #withIterationCount(int)}). - */ - public void forAll(Generator generator, Predicate property) { - Iteration iteration = new CheckSession<>(serializedData == null ? generator : generator.noShrink(), - property, this).firstIteration(); - while (iteration != null) { - iteration = iteration.performIteration(); - } - } - - /** - * Performs a check that the scenarios generated by the given command are successful. Default {@link PropertyChecker} settings are used. - * @param command a supplier for a top-level command. This supplier should not have any side effects. - */ - public void checkScenarios(@NotNull Supplier command) { - forAll(Scenario.scenarios(command), Scenario::ensureSuccessful); - } - - } - -} - diff --git a/jetCheck/src/org/jetbrains/jetCheck/PropertyFailure.java b/jetCheck/src/org/jetbrains/jetCheck/PropertyFailure.java deleted file mode 100644 index b2239b8256ae..000000000000 --- a/jetCheck/src/org/jetbrains/jetCheck/PropertyFailure.java +++ /dev/null @@ -1,64 +0,0 @@ -package org.jetbrains.jetCheck; - -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -import java.util.function.Supplier; - -/** - * @author peter - */ -public interface PropertyFailure { - @NotNull - CounterExample getFirstCounterExample(); - - @NotNull - CounterExample getMinimalCounterexample(); - - @Nullable - Throwable getStoppingReason(); - - int getTotalMinimizationExampleCount(); - - int getMinimizationStageCount(); - - int getIterationNumber(); - - long getIterationSeed(); - - long getGlobalSeed(); - - int getSizeHint(); - - interface CounterExample { - /** - * @return the value produced by the generator, on which the property check has failed - */ - T getExampleValue(); - - /** - * @return the exception, if property check has failed with one - */ - @Nullable - Throwable getExceptionCause(); - - /** - * Re-run the generator and the property on the {@link DataStructure} corresponding to this counter-example.

- * - * This can be useful for debugging, when this example fails after some previous runs and shrinking, but doesn't fail - * by itself. This can indicate unnoticed side effects in the generators and properties. Catching {@link PropertyFalsified} - * exception, calling {@code replay} and putting some breakpoints might shed some light on the reasons involved. - * @return a CounterExample with the results from the re-run. If re-run is successful (which also indicates some unaccounted side effects), a CounterExample is returned with an exception cause indicating that fact. - */ - @NotNull - CounterExample replay(); - - /** - * @return the data used for generator to produce this counterexample, serialized into Base64. - * To be used with {@link PropertyChecker#rechecking} or {@link ImperativeCommand#checkScenario} - */ - @NotNull - String getSerializedData(); - } - -} diff --git a/jetCheck/src/org/jetbrains/jetCheck/PropertyFailureImpl.java b/jetCheck/src/org/jetbrains/jetCheck/PropertyFailureImpl.java deleted file mode 100644 index 343ee6c67a6c..000000000000 --- a/jetCheck/src/org/jetbrains/jetCheck/PropertyFailureImpl.java +++ /dev/null @@ -1,169 +0,0 @@ -package org.jetbrains.jetCheck; - -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; - -class PropertyFailureImpl implements PropertyFailure { - private final CounterExampleImpl initial; - private CounterExampleImpl minimized; - private int totalSteps; - private int successfulSteps; - final Iteration iteration; - private Throwable stoppingReason; - - PropertyFailureImpl(@NotNull CounterExampleImpl initial, Iteration iteration) { - this.initial = initial; - this.minimized = initial; - this.iteration = iteration; - try { - shrink(); - } - catch (Throwable e) { - stoppingReason = e; - } - } - - @NotNull - @Override - public CounterExampleImpl getFirstCounterExample() { - return initial; - } - - @NotNull - @Override - public CounterExampleImpl getMinimalCounterexample() { - return minimized; - } - - @Nullable - @Override - public Throwable getStoppingReason() { - return stoppingReason; - } - - @Override - public int getTotalMinimizationExampleCount() { - return totalSteps; - } - - @Override - public int getMinimizationStageCount() { - return successfulSteps; - } - - @Override - public int getIterationNumber() { - return iteration.iterationNumber; - } - - @Override - public long getIterationSeed() { - return iteration.iterationSeed; - } - - @Override - public long getGlobalSeed() { - return iteration.session.parameters.globalSeed; - } - - @Override - public int getSizeHint() { - return iteration.sizeHint; - } - - private void shrink() { - ShrinkStep lastSuccessfulShrink = null; - do { - lastSuccessfulShrink = shrinkIteration(lastSuccessfulShrink); - } - while (lastSuccessfulShrink != null); - } - - private ShrinkStep shrinkIteration(ShrinkStep 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, @Nullable ShrinkStep limit) { - List combinatorial = new ArrayList<>(); - - while (step != null && !step.equals(limit)) { - StructureNode node = step.apply(minimized.data); - if (node != null && iteration.session.addGeneratedNode(node)) { - CombinatorialIntCustomizer customizer = new CombinatorialIntCustomizer(); - if (tryStep(node, customizer)) { - return step; - } - CombinatorialIntCustomizer next = customizer.nextAttempt(); - if (next != null) { - combinatorial.add(new CustomizedNode(next, step)); - } - } - - step = step.onFailure(); - } - return processDelayedCombinations(combinatorial); - } - - @Nullable - private ShrinkStep processDelayedCombinations(List delayed) { - Collections.sort(delayed); - - for (CustomizedNode customizedNode : delayed) { - CombinatorialIntCustomizer customizer = customizedNode.customizer; - while (customizer != null) { - if (tryStep(customizedNode.step.apply(minimized.data), customizer)) { - return customizedNode.step; - } - customizer = customizer.nextAttempt(); - } - } - return null; - } - - private boolean tryStep(StructureNode node, CombinatorialIntCustomizer customizer) { - try { - iteration.session.notifier.shrinkAttempt(this, iteration); - - totalSteps++; - T value = iteration.generateValue(new ReplayDataStructure(node, iteration.sizeHint, customizer)); - CounterExampleImpl example = CounterExampleImpl.checkProperty(iteration, value, customizer.writeChanges(node)); - if (example != null) { - minimized = example; - successfulSteps++; - return true; - } - } - catch (CannotRestoreValue ignored) { - } - return false; - } - - private static class CustomizedNode implements Comparable { - final CombinatorialIntCustomizer customizer; - final ShrinkStep step; - - CustomizedNode(CombinatorialIntCustomizer customizer, ShrinkStep step) { - this.customizer = customizer; - this.step = step; - } - - @Override - public int compareTo(@NotNull CustomizedNode o) { - return Integer.compare(customizer.countVariants(), o.customizer.countVariants()); - } - } -} diff --git a/jetCheck/src/org/jetbrains/jetCheck/PropertyFalsified.java b/jetCheck/src/org/jetbrains/jetCheck/PropertyFalsified.java deleted file mode 100644 index 65aef91f04f5..000000000000 --- a/jetCheck/src/org/jetbrains/jetCheck/PropertyFalsified.java +++ /dev/null @@ -1,131 +0,0 @@ -package org.jetbrains.jetCheck; - -import java.util.ArrayList; -import java.util.List; - -/** - * @author peter - */ -@SuppressWarnings("ExceptionClassNameDoesntEndWithException") -public class PropertyFalsified extends RuntimeException { - static final String FAILURE_REASON_HAS_CHANGED_DURING_MINIMIZATION = "Failure reason has changed during minimization, see initial failing example below"; - private static final String SEPARATOR = "\n==========================\n"; - private final PropertyFailureImpl failure; - private final String message; - - PropertyFalsified(PropertyFailureImpl failure) { - super(failure.getMinimalCounterexample().getExceptionCause()); - this.failure = failure; - this.message = calcMessage(); - } - - @Override - public String getMessage() { - return message; - } - - private String calcMessage() { - StringBuilder traceBuilder = new StringBuilder(); - - String exampleString = valueToString(failure.getMinimalCounterexample(), traceBuilder); - - Throwable failureReason = failure.getMinimalCounterexample().getExceptionCause(); - Throwable rootCause = failureReason == null ? null : getRootCause(failureReason); - String msg = rootCause != null && !rootCause.toString().contains("ComparisonFailure") // otherwise IDEA replaces the whole message (including example and rechecking information) with a diff - ? "Failed with " + rootCause + "\nOn " + exampleString - : "Falsified on " + exampleString; - - msg += "\n" + - getMinimizationStats() + - "\n" + failure.iteration.printToReproduce(failureReason, failure.getMinimalCounterexample()) + "\n"; - - if (failureReason != null) { - appendTrace(traceBuilder, - rootCause == failureReason ? "Property failure reason: " : "Property failure reason, innermost exception (see full trace below): ", - rootCause); - } - - if (failure.getStoppingReason() != null) { - msg += "\n Minimization stopped prematurely, see the reason below."; - appendTrace(traceBuilder, "An unexpected exception happened during minimization: ", failure.getStoppingReason()); - } - - Throwable first = failure.getFirstCounterExample().getExceptionCause(); - if (exceptionsDiffer(first, failure.getMinimalCounterexample().getExceptionCause())) { - msg += "\n " + FAILURE_REASON_HAS_CHANGED_DURING_MINIMIZATION; - StringBuilder secondaryTrace = new StringBuilder(); - traceBuilder.append("\n Initial value: ").append(valueToString(failure.getFirstCounterExample(), secondaryTrace)); - if (first == null) { - traceBuilder.append("\n Initially property was falsified without exceptions"); - traceBuilder.append(secondaryTrace); - } else { - traceBuilder.append(secondaryTrace); - appendTrace(traceBuilder, "Initially failed because of ", first); - } - } - return msg + traceBuilder; - } - - private static Throwable getRootCause(Throwable t) { - while (t.getCause() != null) { - t = t.getCause(); - } - return t; - } - - private static void appendTrace(StringBuilder traceBuilder, String prefix, Throwable e) { - traceBuilder.append("\n ").append(prefix).append(StatusNotifier.printStackTrace(e)).append(SEPARATOR); - } - - private static String valueToString(CounterExampleImpl example, StringBuilder traceBuilder) { - try { - return String.valueOf(example.getExampleValue()); - } - catch (Throwable e) { - appendTrace(traceBuilder, "Exception during toString evaluation: ", e); - return ""; - } - } - - private String getMinimizationStats() { - int exampleCount = failure.getTotalMinimizationExampleCount(); - if (exampleCount == 0) return ""; - String examples = exampleCount == 1 ? "example" : "examples"; - - int stageCount = failure.getMinimizationStageCount(); - if (stageCount == 0) return "Couldn't minimize, tried " + exampleCount + " " + examples + "\n"; - - String stages = stageCount == 1 ? "stage" : "stages"; - return "Minimized in " + stageCount + " " + stages + ", by trying " + exampleCount + " " + examples + "\n"; - } - - private static boolean exceptionsDiffer(Throwable e1, Throwable e2) { - if (e1 == null && e2 == null) return false; - if ((e1 == null) != (e2 == null)) return true; - if (!e1.getClass().equals(e2.getClass())) return true; - if (e1 instanceof StackOverflowError) return false; - - return !getUserTrace(e1).equals(getUserTrace(e2)); - } - - private static List getUserTrace(Throwable e) { - List result = new ArrayList<>(); - for (StackTraceElement element : e.getStackTrace()) { - String s = element.toString(); - if (s.startsWith("org.jetbrains.jetCheck.") && !s.contains("Test.")) { - break; - } - result.add(s); - } - return result; - } - - public PropertyFailure getFailure() { - return failure; - } - - public Object getBreakingValue() { - return failure.getMinimalCounterexample().getExampleValue(); - } - -} diff --git a/jetCheck/src/org/jetbrains/jetCheck/RemoveListRange.java b/jetCheck/src/org/jetbrains/jetCheck/RemoveListRange.java deleted file mode 100644 index 13923a07bb4a..000000000000 --- a/jetCheck/src/org/jetbrains/jetCheck/RemoveListRange.java +++ /dev/null @@ -1,94 +0,0 @@ -/* - * Copyright 2000-2017 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. - */ -package org.jetbrains.jetCheck; - -import org.jetbrains.annotations.Nullable; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; -import java.util.Objects; - -/** - * @author peter - */ -class RemoveListRange extends ShrinkStep { - private final StructureNode node; - private final int lastSuccessfulRemove; - private final int start; - private final int length; - - static RemoveListRange fromEnd(StructureNode node) { - int likelyFailingSuffix = node.isIncompleteList() && node.children.size() > 2 ? 1 : 0; - return new RemoveListRange(node, - node.children.size() - likelyFailingSuffix, - node.children.size() - likelyFailingSuffix - 1, 1); - } - - private RemoveListRange(StructureNode node, int lastSuccessfulRemove, int start, int length) { - this.node = node; - this.lastSuccessfulRemove = lastSuccessfulRemove; - this.start = start; - this.length = length; - assert start > 0; - assert start + length <= node.children.size(); - assert lastSuccessfulRemove > 0; - assert lastSuccessfulRemove <= node.children.size(); - } - - @Override - List getEqualityObjects() { - return Arrays.asList(node.id, start, length); - } - - @Nullable - @Override - StructureNode apply(StructureNode root) { - int newSize = node.children.size() - length - 1; - IntDistribution lengthDistribution = ((IntData)node.children.get(0)).distribution; - if (!lengthDistribution.isValidValue(newSize)) return null; - - List lessItems = new ArrayList<>(newSize + 1); - lessItems.add(node.isIncompleteList() ? node.children.get(0) : new IntData(node.children.get(0).id, newSize, lengthDistribution)); - lessItems.addAll(node.children.subList(1, start)); - lessItems.addAll(node.children.subList(start + length, node.children.size())); - StructureNode replacement = new StructureNode(node.id, lessItems); - replacement.kind = StructureKind.LIST; - return root.replace(node.id, replacement); - } - - @Override - ShrinkStep onFailure() { - if (length > 1) { - int end = start + length; - return new RemoveListRange(node, lastSuccessfulRemove, end - (length / 2), length / 2); - } - - int newEnd = start == 1 ? node.children.size() : start; - if (newEnd == lastSuccessfulRemove) return node.shrinkChild(node.children.size() - 1); - return new RemoveListRange(node, lastSuccessfulRemove, newEnd - 1, 1); - } - - @Nullable - @Override - ShrinkStep onSuccess(StructureNode smallerRoot) { - if (length == node.children.size() - 1) return null; - - StructureNode inheritor = (StructureNode)Objects.requireNonNull(smallerRoot.findChildById(node.id)); - if (start == 1) return fromEnd(inheritor); - - int newLength = Math.min(length * 2, start - 1); - return new RemoveListRange(inheritor, start, start - newLength, newLength); - } - - @Override - public String toString() { - return "RemoveListRange{" + - "last=" + lastSuccessfulRemove + - ", start=" + start + - ", length=" + length + - ", node=" + node.id + ": " + node + - '}'; - } -} diff --git a/jetCheck/src/org/jetbrains/jetCheck/ReplayDataStructure.java b/jetCheck/src/org/jetbrains/jetCheck/ReplayDataStructure.java deleted file mode 100644 index 00b73b4678d7..000000000000 --- a/jetCheck/src/org/jetbrains/jetCheck/ReplayDataStructure.java +++ /dev/null @@ -1,60 +0,0 @@ -package org.jetbrains.jetCheck; - -import org.jetbrains.annotations.NotNull; - -import java.util.Iterator; -import java.util.function.Predicate; - -class ReplayDataStructure extends AbstractDataStructure { - private final Iterator iterator; - private final IntCustomizer customizer; - - ReplayDataStructure(StructureNode node, int sizeHint, IntCustomizer customizer) { - super(node, sizeHint); - this.iterator = node.childrenIterator(); - this.customizer = customizer; - } - - @Override - int drawInt(@NotNull IntDistribution distribution) { - return customizer.suggestInt(nextChild(IntData.class), distribution); - } - - @NotNull - private E nextChild(Class required) { - if (!iterator.hasNext()) throw new CannotRestoreValue(); - Object next = iterator.next(); - if (!required.isInstance(next)) throw new CannotRestoreValue(); - //noinspection unchecked - return (E)next; - } - - @Override - public T generate(@NotNull Generator generator) { - return generator.getGeneratorFunction().apply(new ReplayDataStructure(nextChild(StructureNode.class), childSizeHint(), customizer)); - } - - @Override - T generateNonShrinkable(@NotNull Generator generator) { - return generate(generator); - } - - @Override - T generateConditional(@NotNull Generator generator, @NotNull Predicate condition) { - T value = generate(generator); - if (!condition.test(value)) throw new CannotRestoreValue(); - return value; - } - - @Override - void changeKind(StructureKind kind) { - if (node.kind != kind) { - throw new CannotRestoreValue(); - } - } - - @Override - public String toString() { - return node.toString(); - } -} \ No newline at end of file diff --git a/jetCheck/src/org/jetbrains/jetCheck/Scenario.java b/jetCheck/src/org/jetbrains/jetCheck/Scenario.java deleted file mode 100644 index e87841e71b12..000000000000 --- a/jetCheck/src/org/jetbrains/jetCheck/Scenario.java +++ /dev/null @@ -1,152 +0,0 @@ -/* - * Copyright 2000-2017 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. - */ -package org.jetbrains.jetCheck; - -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -import java.util.ArrayList; -import java.util.List; -import java.util.function.Function; -import java.util.function.Supplier; - -class Scenario { - private final List log = new ArrayList<>(); - private Throwable failure; - - Scenario(@NotNull ImperativeCommand cmd, @NotNull DataStructure data) { - try { - performCommand(cmd, data, log); - } - catch (DataSerializer.EOFException e) { - throw e; - } - catch (Throwable e) { - addFailure(e); - } - if (failure instanceof CannotRestoreValue) { - throw (CannotRestoreValue)failure; - } - } - - private void addFailure(Throwable e) { - if (failure == null) { - failure = e; - } - } - - private void performCommand(ImperativeCommand command, DataStructure data, List log) { - command.performCommand(new ImperativeCommand.Environment() { - @Override - public void logMessage(@NotNull String message) { - log.add(message); - } - - @Override - public T generateValue(@NotNull Generator generator, @Nullable String logMessage) { - T value = safeGenerate(data, generator); - if (logMessage != null) { - logMessage(String.format(logMessage, value)); - } - return value; - } - - @Override - public void executeCommands(IntDistribution count, Generator cmdGen) { - innerCommandLists(Generator.listsOf(count, innerCommands(cmdGen))); - } - - @Override - public void executeCommands(Generator cmdGen) { - innerCommandLists(Generator.nonEmptyLists(innerCommands(cmdGen))); - } - - private void innerCommandLists(final Generator> listGen) { - data.generate(Generator.from(new EquivalentGenerator>() { - @Override - public List apply(DataStructure data) { - return listGen.getGeneratorFunction().apply(data); - } - })); - } - - @NotNull - private Generator innerCommands(Generator cmdGen) { - return Generator.from(new EquivalentGenerator() { - @Override - public Object apply(DataStructure cmdData) { - List localLog = new ArrayList<>(); - log.add(localLog); - performCommand(safeGenerate(cmdData, cmdGen), cmdData, localLog); - return null; - } - }); - } - }); - } - - private T safeGenerate(DataStructure data, Generator generator) { - try { - return data.generate(generator); - } - catch (CannotRestoreValue e) { //todo test for evil intermediate code hiding this exception, also CannotSatisfyCondition - addFailure(e); - throw e; - } - } - - - @Override - public boolean equals(Object o) { - return this == o || o instanceof Scenario && log.equals(((Scenario)o).log); - } - - @Override - public int hashCode() { - return log.hashCode(); - } - - @Override - public String toString() { - StringBuilder sb = new StringBuilder(); - printLog(sb, "", log); - return "commands:" + (sb.length() == 0 ? "" : sb.toString()); - } - - private static void printLog(StringBuilder sb, String indent, List log) { - for (Object o : log) { - if (o instanceof String) { - sb.append("\n").append(indent).append(o); - } else { - //noinspection unchecked - printLog(sb, indent + " ", (List)o); - } - } - } - - boolean ensureSuccessful() { - if (failure instanceof Error) throw (Error)failure; - if (failure instanceof RuntimeException) throw (RuntimeException)failure; - if (failure != null) throw new RuntimeException(failure); - return true; - } - - static Generator scenarios(@NotNull Supplier command) { - return Generator.from(data -> new Scenario(command.get(), data)); - } - - private static abstract class EquivalentGenerator implements Function { - @Override - public boolean equals(Object obj) { - return getClass() == obj.getClass(); // for recursive shrinking to work - } - - @Override - public int hashCode() { - return getClass().hashCode(); - } - - } - -} diff --git a/jetCheck/src/org/jetbrains/jetCheck/ShrinkStep.java b/jetCheck/src/org/jetbrains/jetCheck/ShrinkStep.java deleted file mode 100644 index b06f5b8e8030..000000000000 --- a/jetCheck/src/org/jetbrains/jetCheck/ShrinkStep.java +++ /dev/null @@ -1,75 +0,0 @@ -/* - * Copyright 2000-2017 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. - */ -package org.jetbrains.jetCheck; - -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -import java.util.Arrays; -import java.util.List; -import java.util.function.Function; -import java.util.function.Supplier; - -/** - * @author peter - */ -abstract class ShrinkStep { - - @Nullable - abstract StructureNode apply(StructureNode root); - - @Nullable - abstract ShrinkStep onSuccess(StructureNode smallerRoot); - - @Nullable - abstract ShrinkStep onFailure(); - - abstract List getEqualityObjects(); - - @Override - public boolean equals(Object obj) { - return obj != null && obj.getClass().equals(getClass()) && getEqualityObjects().equals(((ShrinkStep)obj).getEqualityObjects()); - } - - @Override - public int hashCode() { - return getEqualityObjects().hashCode(); - } - - static ShrinkStep create(@NotNull NodeId replaced, - @NotNull StructureElement replacement, - @Nullable Function onSuccess, - @Nullable Supplier onFailure) { - return new ShrinkStep() { - - @Override - StructureNode apply(StructureNode root) { - return root.replace(replaced, replacement); - } - - @Nullable - @Override - ShrinkStep onSuccess(StructureNode smallerRoot) { - return onSuccess == null ? null : onSuccess.apply(smallerRoot); - } - - @Nullable - @Override - ShrinkStep onFailure() { - return onFailure == null ? null : onFailure.get(); - } - - @Override - public String toString() { - return "replace " + replaced + " with " + replacement; - } - - @Override - List getEqualityObjects() { - return Arrays.asList(replaced, replacement); - } - }; - } -} - diff --git a/jetCheck/src/org/jetbrains/jetCheck/StatusNotifier.java b/jetCheck/src/org/jetbrains/jetCheck/StatusNotifier.java deleted file mode 100644 index 804b8d00721c..000000000000 --- a/jetCheck/src/org/jetbrains/jetCheck/StatusNotifier.java +++ /dev/null @@ -1,104 +0,0 @@ -package org.jetbrains.jetCheck; - -import org.jetbrains.annotations.NotNull; - -import java.io.PrintWriter; -import java.io.StringWriter; -import java.time.LocalTime; -import java.time.format.DateTimeFormatter; -import java.time.format.FormatStyle; -import java.util.Locale; - -/** - * @author peter - */ -@SuppressWarnings("UseOfSystemOutOrSystemErr") -class StatusNotifier { - static final StatusNotifier SILENT = new StatusNotifier(0) { - @Override - boolean shouldPrint() { - return false; - } - - @Override - void counterExampleFound(Iteration iteration) {} - - @Override - void eofException() {} - }; - - private final int iterationCount; - private int currentIteration; - private long lastPrinted = System.currentTimeMillis(); - - StatusNotifier(int iterationCount) { - this.iterationCount = iterationCount; - } - - void iterationStarted(int iteration) { - currentIteration = iteration; - if (shouldPrint()) { - System.out.println(formatCurrentTime() + ": iteration " + currentIteration + " of " + iterationCount + "..."); - } - } - - void counterExampleFound(Iteration iteration) { - lastPrinted = System.currentTimeMillis(); - System.err.println(formatCurrentTime() + ": failed on iteration " + currentIteration + " (" + iteration.printSeeds() + "), shrinking..."); - } - - boolean shouldPrint() { - if (System.currentTimeMillis() - lastPrinted > 5_000) { - lastPrinted = System.currentTimeMillis(); - return true; - } - return false; - } - - private int lastReportedStage = -1; - private String lastReportedTrace = null; - void shrinkAttempt(PropertyFailure failure, Iteration iteration) { - if (shouldPrint()) { - int stage = failure.getMinimizationStageCount(); - System.out.println(formatCurrentTime() + ": still shrinking (" + iteration.printSeeds() + "). " + - "Examples tried: " + failure.getTotalMinimizationExampleCount() + - ", successful minimizations: " + stage); - if (lastReportedStage != stage) { - lastReportedStage = stage; - - System.err.println(" Current minimal example: " + failure.getMinimalCounterexample().getExampleValue()); - - Throwable exceptionCause = failure.getMinimalCounterexample().getExceptionCause(); - if (exceptionCause != null) { - String trace = shortenStackTrace(exceptionCause); - if (!trace.equals(lastReportedTrace)) { - lastReportedTrace = trace; - System.err.println(" Reason: " + trace); - } - } - System.err.println(); - } - } - } - - void eofException() { - System.out.println("Generator tried to read past the end of serialized data, so it seems the failure isn't reproducible anymore"); - } - - private static String shortenStackTrace(Throwable e) { - String trace = printStackTrace(e); - return trace.length() > 1000 ? trace.substring(0, 1000) + "..." : trace; - } - - @NotNull - private static String formatCurrentTime() { - return LocalTime.now().format(DateTimeFormatter.ofLocalizedTime(FormatStyle.MEDIUM).withLocale(Locale.getDefault())); - } - - static String printStackTrace(Throwable e) { - StringWriter stringWriter = new StringWriter(); - PrintWriter writer = new PrintWriter(stringWriter); - e.printStackTrace(writer); - return stringWriter.getBuffer().toString(); - } -} diff --git a/jetCheck/src/org/jetbrains/jetCheck/StructureNode.java b/jetCheck/src/org/jetbrains/jetCheck/StructureNode.java deleted file mode 100644 index baa7ecaf8539..000000000000 --- a/jetCheck/src/org/jetbrains/jetCheck/StructureNode.java +++ /dev/null @@ -1,306 +0,0 @@ -package org.jetbrains.jetCheck; - -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -import java.io.DataOutputStream; -import java.io.IOException; -import java.util.*; -import java.util.function.Supplier; -import java.util.stream.Collectors; - -/** - * @author peter - */ -abstract class StructureElement { - final NodeId id; - - StructureElement(@NotNull NodeId id) { - this.id = id; - } - - @Nullable - abstract ShrinkStep shrink(); - - @NotNull - abstract StructureElement replace(NodeId id, StructureElement replacement); - - @Nullable - abstract StructureElement findChildById(NodeId id); - - abstract void serialize(DataOutputStream out) throws IOException; -} - -class StructureNode extends StructureElement { - final List children; - @NotNull StructureKind kind = StructureKind.GENERIC; - boolean shrinkProhibited; - - StructureNode(NodeId id) { - this(id, new ArrayList<>()); - } - - StructureNode(NodeId id, List children) { - super(id); - this.children = children; - } - - Iterator childrenIterator() { - return children.iterator(); - } - - void addChild(StructureElement child) { - children.add(child); - } - - StructureNode subStructure(@NotNull Generator generator) { - StructureNode e = new StructureNode(id.childId(generator)); - addChild(e); - return e; - } - - void removeLastChild(StructureNode node) { - if (children.isEmpty() || children.get(children.size() - 1) != node) { - throw new IllegalStateException("Last sub-structure changed"); - } - children.remove(children.size() - 1); - } - - @Nullable - @Override - ShrinkStep shrink() { - if (shrinkProhibited) return null; - - return kind == StructureKind.LIST && children.size() > 1 ? RemoveListRange.fromEnd(this) : shrinkChild(children.size() - 1); - } - - @Nullable - ShrinkStep shrinkChild(int index) { - int minIndex = kind == StructureKind.GENERIC ? 0 : 1; - for (; index >= minIndex; index--) { - ShrinkStep childShrink = children.get(index).shrink(); - if (childShrink != null) return wrapChildShrink(index, childShrink); - } - - return shrinkRecursion(); - } - - @Nullable - private ShrinkStep wrapChildShrink(int index, @Nullable ShrinkStep step) { - if (step == null) return shrinkChild(index - 1); - - NodeId oldChild = children.get(index).id; - - return new ShrinkStep() { - - @Override - List getEqualityObjects() { - return Collections.singletonList(step); - } - - @Nullable - @Override - StructureNode apply(StructureNode root) { - return step.apply(root); - } - - @Override - ShrinkStep onSuccess(StructureNode smallerRoot) { - StructureNode inheritor = (StructureNode)Objects.requireNonNull(smallerRoot.findChildById(id)); - assert inheritor.children.size() == children.size(); - if (inheritor.children.get(index).id != oldChild) { - return inheritor.shrink(); - } - - return inheritor.wrapChildShrink(index, step.onSuccess(smallerRoot)); - } - - @Override - ShrinkStep onFailure() { - return wrapChildShrink(index, step.onFailure()); - } - - @Override - public String toString() { - return "-" + step.toString(); - } - }; - } - - boolean isIncompleteList() { - return ((IntData)children.get(0)).value > children.size() - 1; - } - - private void findChildrenWithGenerator(int generatorHash, List result) { - for (StructureElement child : children) { - if (child instanceof StructureNode) { - Integer childGen = child.id.generatorHash; - if (childGen != null && generatorHash == childGen.intValue()) { - result.add((StructureNode)child); - } else { - ((StructureNode)child).findChildrenWithGenerator(generatorHash, result); - } - } - } - } - - @Nullable - private ShrinkStep shrinkRecursion() { - if (id.generatorHash != null) { - List sameGeneratorChildren = new ArrayList<>(); - findChildrenWithGenerator(id.generatorHash, sameGeneratorChildren); - return tryReplacing(sameGeneratorChildren, 0); - } - - return null; - } - - @Nullable - private ShrinkStep tryReplacing(List candidates, int index) { - if (index < candidates.size()) { - StructureNode replacement = candidates.get(index); - return ShrinkStep.create(id, replacement, __ -> replacement.shrink(), () -> tryReplacing(candidates, index + 1)); - } - return null; - } - - @NotNull - @Override - StructureNode replace(NodeId id, StructureElement replacement) { - if (id == this.id) { - return (StructureNode)replacement; - } - - if (children.isEmpty()) return this; - - int index = indexOfChildContaining(id); - StructureElement oldChild = children.get(index); - StructureElement newChild = oldChild.replace(id, replacement); - if (oldChild == newChild) return this; - - List newChildren = new ArrayList<>(this.children); - newChildren.set(index, newChild); - StructureNode copy = new StructureNode(this.id, newChildren); - copy.shrinkProhibited = this.shrinkProhibited; - copy.kind = this.kind; - return copy; - } - - @Nullable - @Override - StructureElement findChildById(NodeId id) { - if (id == this.id) return this; - int index = indexOfChildContaining(id); - return index < 0 ? null : children.get(index).findChildById(id); - } - - @Override - void serialize(DataOutputStream out) throws IOException { - for (StructureElement child : children) { - child.serialize(out); - } - } - - private int indexOfChildContaining(NodeId id) { - int i = 0; - while (i < children.size() && children.get(i).id.number <= id.number) i++; - return i - 1; - } - - @Override - public boolean equals(Object obj) { - return obj instanceof StructureNode && children.equals(((StructureNode)obj).children); - } - - @Override - public int hashCode() { - return children.hashCode(); - } - - @Override - public String toString() { - String inner = children.stream().map(Object::toString).collect(Collectors.joining(", ")); - switch (kind) { - case LIST: return "[" + inner + "]"; - case CHOICE: return "?(" + inner + ")"; - default: return "(" + inner + ")"; - } - } - -} - -class IntData extends StructureElement { - final int value; - final IntDistribution distribution; - - IntData(NodeId id, int value, IntDistribution distribution) { - super(id); - this.value = value; - this.distribution = distribution; - } - - @Nullable - @Override - ShrinkStep shrink() { - if (value == 0) return null; - - int minValue = 0; - if (distribution instanceof BoundedIntDistribution) { - minValue = Math.max(minValue, ((BoundedIntDistribution)distribution).getMin()); - } - return tryInt(minValue, () -> null, this::tryNegation); - } - - private ShrinkStep tryNegation() { - if (value < 0) { - return tryInt(-value, () -> divisionLoop(-value), () -> divisionLoop(value)); - } - return divisionLoop(value); - } - - private ShrinkStep divisionLoop(int value) { - if (value == 0) return null; - int divided = value / 2; - return tryInt(divided, () -> divisionLoop(divided), null); - } - - private ShrinkStep tryInt(int value, @NotNull Supplier success, @Nullable Supplier fail) { - return distribution.isValidValue(value) ? ShrinkStep.create(id, new IntData(id, value, distribution), __ -> success.get(), fail) : null; - } - - @NotNull - @Override - IntData replace(NodeId id, StructureElement replacement) { - return this.id == id ? (IntData)replacement : this; - } - - @Nullable - @Override - StructureElement findChildById(NodeId id) { - return id == this.id ? this : null; - } - - @Override - void serialize(DataOutputStream out) throws IOException { - DataSerializer.writeINT(out, value); - } - - @Override - public String toString() { - return String.valueOf(value); - } - - @Override - public boolean equals(Object obj) { - return obj instanceof IntData && value == ((IntData)obj).value; - } - - @Override - public int hashCode() { - return value; - } -} - -enum StructureKind { - GENERIC, LIST, CHOICE -} \ No newline at end of file diff --git a/jetCheck/test/org/jetbrains/jetCheck/ExceptionTest.java b/jetCheck/test/org/jetbrains/jetCheck/ExceptionTest.java deleted file mode 100644 index ae337b40266f..000000000000 --- a/jetCheck/test/org/jetbrains/jetCheck/ExceptionTest.java +++ /dev/null @@ -1,84 +0,0 @@ -/* - * Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. - */ -package org.jetbrains.jetCheck; - -import static org.jetbrains.jetCheck.Generator.*; - -/** - * @author peter - */ -public class ExceptionTest extends PropertyCheckerTestCase { - - public void testFailureReasonUnchanged() { - PropertyFalsified e = checkFails(STABLE, integers(), i -> { - throw new AssertionError("fail"); - }); - - assertFalse(e.getMessage().contains(PropertyFalsified.FAILURE_REASON_HAS_CHANGED_DURING_MINIMIZATION)); - } - - public void testFailureReasonChangedExceptionClass() { - PropertyFalsified e = checkFails(STABLE, integers(), i -> { - throw (i == 0 ? new RuntimeException("fail") : new IllegalArgumentException("fail")); - }); - assertTrue(e.getMessage().contains(PropertyFalsified.FAILURE_REASON_HAS_CHANGED_DURING_MINIMIZATION)); - } - - public void testFailureReasonChangedExceptionTrace() { - PropertyFalsified e = checkFails(STABLE, integers(), i -> { - if (i == 0) { - throw new AssertionError("fail"); - } - else { - throw new AssertionError("fail2"); - } - }); - assertTrue(e.getMessage().contains(PropertyFalsified.FAILURE_REASON_HAS_CHANGED_DURING_MINIMIZATION)); - } - - public void testExceptionWhileGeneratingValue() { - try { - STABLE.forAll(from(data -> { - throw new AssertionError("fail"); - }), i -> true); - fail(); - } - catch (GeneratorException ignore) { - } - } - - public void testExceptionWhileShrinkingValue() { - PropertyFalsified e = checkFails(PropertyChecker.customized(), listsOf(integers()).suchThat(l -> { - if (l.size() == 1 && l.get(0) == 0) throw new RuntimeException("my exception"); - return true; - }), l -> l.stream().allMatch(i -> i > 0)); - - assertEquals("my exception", e.getFailure().getStoppingReason().getMessage()); - assertTrue(StatusNotifier.printStackTrace(e).contains("my exception")); - } - - public void testUnsatisfiableSuchThat() { - try { - PropertyChecker.forAll(integers(-1, 1).suchThat(i -> i > 2), i -> i == 0); - fail(); - } - catch (GeneratorException e) { - assertTrue(e.getCause() instanceof CannotSatisfyCondition); - } - } - - public void testUsingWrongDataStructure() { - Generator gen = from(data1 -> { - int i1 = data1.generate(naturals()); - int i2 = data1.generate(from(data2 -> data1.generate(integers()))); - return i1 + i2; - }); - try { - PropertyChecker.forAll(gen, i -> true); - fail(); - } - catch (WrongDataStructure expected) { - } - } -} diff --git a/jetCheck/test/org/jetbrains/jetCheck/GeneratorTest.java b/jetCheck/test/org/jetbrains/jetCheck/GeneratorTest.java deleted file mode 100644 index 961006d47128..000000000000 --- a/jetCheck/test/org/jetbrains/jetCheck/GeneratorTest.java +++ /dev/null @@ -1,187 +0,0 @@ -/* - * Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. - */ -package org.jetbrains.jetCheck; - -import java.util.*; -import java.util.function.Predicate; -import java.util.stream.Collectors; - -import static org.jetbrains.jetCheck.Generator.*; - -/** - * @author peter - */ -public class GeneratorTest extends PropertyCheckerTestCase { - - public void testMod() { - checkFalsified(integers(), - i -> i % 12 != 0, - 1); - } - - public void testListSumMod() { - checkFalsified(nonEmptyLists(integers()), - l -> l.stream().mapToInt(Integer::intValue).sum() % 10 != 0, - 301); - } - - public void testListContainsDivisible() { - checkGeneratesExample(nonEmptyLists(integers()), - l -> l.stream().anyMatch(i -> i % 10 == 0), - 4); - } - - public void testStringContains() { - assertEquals("a", checkGeneratesExample(stringsOf(asciiPrintableChars()), - s -> s.contains("a"), - 10)); - - String aWithB = checkGeneratesExample(stringsOf(IntDistribution.uniform(2, 100), asciiPrintableChars()), - s -> s.contains("a") && s.contains("b"), - 27); - assertTrue(aWithB, "ab".equals(aWithB) || "ba".equals(aWithB)); - } - - public void testLetterStringContains() { - checkFalsified(stringsOf(asciiLetters()), - s -> !s.contains("a"), - 1); - } - - public void testIsSorted() { - PropertyFailure> failure = checkFalsified(nonEmptyLists(integers()), - l -> l.stream().sorted().collect(Collectors.toList()).equals(l), - 36); - List value = failure.getMinimalCounterexample().getExampleValue(); - assertEquals(2, value.size()); - assertTrue(value.toString(), value.stream().allMatch(i -> Math.abs(i) < 2)); - } - - public void testSuccess() { - PropertyChecker.forAll(listsOf(integers(-1, 1)), l -> l.stream().allMatch(i -> Math.abs(i) <= 1)); - } - - public void testSortedDoublesNonDescending() { - PropertyFailure> failure = checkFalsified(listsOf(doubles()), - l -> isSorted(l.stream().sorted().collect(Collectors.toList())), - 23); - assertEquals(2, failure.getMinimalCounterexample().getExampleValue().size()); - } - - private static boolean isSorted(List list) { - for (int i = 0; i < list.size() - 1; i++) { - double d1 = list.get(i); - double d2 = list.get(i + 1); - if (!(d1 <= d2)) return false; - } - return true; - } - - public void testSuchThat() { - PropertyChecker.forAll(integers().suchThat(i -> i < 0), i -> i < 0); - } - - public void testNestedSometimesVeryRareSuchThat() { - STABLE.forAll(frequency(50, constant(0), 1, integers(1, 1000)).suchThat(i -> i > 0), i -> i > 0); - } - - public void testStringOfStringChecksAllChars() { - checkFalsified(stringsOf("abc "), - s -> !s.contains(" "), - 0); - } - - public void testListNotLongerThanMaxDefaultSize() { - PropertyChecker.customized().withIterationCount(100_000).forAll(listsOf(integers()), l -> l.size() <= PropertyChecker.DEFAULT_MAX_SIZE_HINT); - } - - public void testNonEmptyList() { - PropertyChecker.forAll(nonEmptyLists(integers()), l -> !l.isEmpty()); - } - - public void testNoDuplicateData() { - Set> visited = new HashSet<>(); - PropertyChecker.forAll(listsOf(integers()), l -> visited.add(l)); - } - - public void testOneOf() { - List values = new ArrayList<>(); - 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(asciiIdentifiers(), - s -> Character.isJavaIdentifierStart(s.charAt(0)) && s.chars().allMatch(Character::isJavaIdentifierPart)); - checkGeneratesExample(asciiIdentifiers(), - s -> s.contains("_"), - 9); - } - - public void testBoolean() { - List list = checkGeneratesExample(listsOf(booleans()), - l -> l.contains(true) && l.contains(false), - 4); - assertEquals(2, list.size()); - } - - @SuppressWarnings("deprecation") - public void testRecheckWithGivenSeeds() { - Generator> gen = nonEmptyLists(integers(0, 100)); - Predicate> property = l -> !l.contains(42); - - PropertyFailure failure = checkFails(PropertyChecker.customized().withSeed(1), gen, property).getFailure(); - assertTrue(failure.getIterationNumber() > 1); - - PropertyFalsified e; - - e = checkFails(PropertyChecker.customized().recheckingIteration(failure.getIterationSeed(), failure.getSizeHint()), gen, property); - assertEquals(1, e.getFailure().getIterationNumber()); - - e = checkFails(PropertyChecker.customized().withSeed(failure.getGlobalSeed()), gen, property); - assertEquals(failure.getIterationNumber(), e.getFailure().getIterationNumber()); - } - - public void testSameFrequency() { - checkFalsified(listsOf(frequency(1, constant(1), 1, constant(2))), - l -> !l.contains(1) || !l.contains(2), - 2); - - checkFalsified(listsOf(frequency(1, constant(1), 1, constant(2)).with(1, constant(3))), - l -> !l.contains(1) || !l.contains(2) || !l.contains(3), - 5); - } - - public void testReplay() { - List log = new ArrayList<>(); - PropertyFailure> failure = checkFalsified(listsOf(integers(0, 100)), l -> { - log.add(l); - return !l.contains(42); - }, 9); - List goldMin = Collections.singletonList(42); - - PropertyFailure.CounterExample> first = failure.getFirstCounterExample(); - PropertyFailure.CounterExample> min = failure.getMinimalCounterexample(); - assertEquals(goldMin, min.getExampleValue()); - assertTrue(log.contains(first.getExampleValue())); - assertTrue(log.contains(min.getExampleValue())); - - log.clear(); - PropertyFailure.CounterExample> first2 = first.replay(); - assertEquals(first.getExampleValue(), first2.getExampleValue()); - assertEquals(log, Collections.singletonList(first2.getExampleValue())); - - log.clear(); - PropertyFailure.CounterExample> min2 = min.replay(); - assertEquals(goldMin, min2.getExampleValue()); - assertEquals(log, Collections.singletonList(goldMin)); - } - - public void testShrinkToRangeStart() { - PropertyFailure failure = checkFalsified(stringsOf(asciiUppercaseChars()), s -> s.length() < 5, 11); - assertEquals("AAAAA", failure.getMinimalCounterexample().getExampleValue()); - } - -} diff --git a/jetCheck/test/org/jetbrains/jetCheck/PropertyCheckerTestCase.java b/jetCheck/test/org/jetbrains/jetCheck/PropertyCheckerTestCase.java deleted file mode 100644 index 74b4406886ab..000000000000 --- a/jetCheck/test/org/jetbrains/jetCheck/PropertyCheckerTestCase.java +++ /dev/null @@ -1,55 +0,0 @@ -/* - * Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. - */ -package org.jetbrains.jetCheck; - -import junit.framework.TestCase; - -import java.util.function.Predicate; - -/** - * @author peter - */ -abstract class PropertyCheckerTestCase extends TestCase { - @SuppressWarnings("deprecation") - static final PropertyChecker.Parameters STABLE = PropertyChecker.customized().withSeed(0); - - protected PropertyFalsified checkFails(PropertyChecker.Parameters parameters, Generator checker, Predicate predicate) { - try { - parameters.silent().forAll(checker, predicate); - throw new AssertionError("Can't falsify " + getName()); - } - catch (PropertyFalsified e) { - return e; - } - } - - protected T checkGeneratesExample(Generator generator, Predicate predicate, int minimizationSteps) { - return checkFalsified(generator, predicate.negate(), minimizationSteps).getMinimalCounterexample().getExampleValue(); - } - - protected PropertyFailure checkFalsified(Generator generator, Predicate predicate, int minimizationSteps) { - PropertyFalsified e = checkFails(STABLE, generator, predicate); - //noinspection unchecked - PropertyFailure failure = (PropertyFailure)e.getFailure(); - - if (failure.getStoppingReason() != null) { - throw new RuntimeException(failure.getStoppingReason()); - } - - /* - System.out.println(" " + getName()); - System.out.println("Value: " + e.getBreakingValue()); - System.out.println("Data: " + e.getData()); - */ - assertEquals(minimizationSteps, failure.getTotalMinimizationExampleCount()); // to track that framework changes don't increase shrinking time significantly on average - assertEquals(e.getBreakingValue(), generator.getGeneratorFunction().apply(((CounterExampleImpl)failure.getMinimalCounterexample()).createReplayData())); - - String strData = failure.getMinimalCounterexample().getSerializedData(); - //noinspection deprecation - assertNotNull(checkFails(PropertyChecker.customized().rechecking(strData), generator, predicate)); - - return failure; - } - -} diff --git a/jetCheck/test/org/jetbrains/jetCheck/RecursiveGeneratorTest.java b/jetCheck/test/org/jetbrains/jetCheck/RecursiveGeneratorTest.java deleted file mode 100644 index 60c54a1d4790..000000000000 --- a/jetCheck/test/org/jetbrains/jetCheck/RecursiveGeneratorTest.java +++ /dev/null @@ -1,48 +0,0 @@ -/* - * Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. - */ -package org.jetbrains.jetCheck; - -import java.util.List; -import java.util.stream.Collectors; - -/** - * @author peter - */ -public class RecursiveGeneratorTest extends PropertyCheckerTestCase { - private static final Generator leaves = Generator.asciiLetters().map(Leaf::new); - - private void checkShrinksToLeaf(Generator nodes) { - PropertyFailure failure = checkFails(STABLE, nodes, tree -> !tree.toString().contains("a")).getFailure(); - assertTrue(failure.getMinimalCounterexample().getExampleValue() instanceof Leaf); - } - - public void testShrinksToLeafWithFrequency() { - checkShrinksToLeaf(Generator.recursive(nodes -> Generator.frequency(2, leaves, - 1, Generator.listsOf(nodes).map(Composite::new)))); - } - - public void testShrinksToLeafWithAnyOf() { - checkShrinksToLeaf(Generator.recursive(nodes -> Generator.anyOf(leaves, - Generator.listsOf(nodes).map(Composite::new)))); - } - - public void testShrinksToLeafDespiteWrapping() { - checkShrinksToLeaf(Generator.recursive(nodes -> Generator.frequency(2, leaves, - 1, Generator.from(data -> data.generate(Generator.listsOf(nodes).map(Composite::new)))))); - } - - private interface Node {} - - private static class Leaf implements Node { - final char c; - Leaf(char c) { this.c = c;} - public String toString() { return String.valueOf(c);} - } - - private static class Composite implements Node { - final List children; - Composite(List children) { this.children = children;} - public String toString() { return "[" + children.stream().map(Object::toString).collect(Collectors.joining("")) + "]";} - } -} diff --git a/jetCheck/test/org/jetbrains/jetCheck/ShrinkTest.java b/jetCheck/test/org/jetbrains/jetCheck/ShrinkTest.java deleted file mode 100644 index 01b5a4829883..000000000000 --- a/jetCheck/test/org/jetbrains/jetCheck/ShrinkTest.java +++ /dev/null @@ -1,49 +0,0 @@ -/* - * Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. - */ -package org.jetbrains.jetCheck; - -import java.util.Arrays; -import java.util.HashSet; -import java.util.List; -import java.util.Set; -import java.util.function.Predicate; - -import static org.jetbrains.jetCheck.Generator.*; - -/** - * @author peter - */ -public class ShrinkTest extends PropertyCheckerTestCase { - public void testShrinkingComplexString() { - checkFalsified(listsOf(stringsOf(asciiPrintableChars())), - l -> { - String s = l.toString(); - return !"abcdefghijklmnopqrstuvwxyz()[]#!".chars().allMatch(c -> s.indexOf((char)c) >= 0); - }, - 371); - } - - public void testShrinkingNonEmptyList() { - List list = checkGeneratesExample(nonEmptyLists(integers(0, 100)), - l -> l.contains(42), - 12); - assertEquals(1, list.size()); - } - - public void testWhenEarlyObjectsCannotBeShrunkBeforeLater() { - Generator gen = listsOf(IntDistribution.uniform(0, 2), listsOf(IntDistribution.uniform(0, 2), sampledFrom('a', 'b'))).map(List::toString); - Set failing = new HashSet<>(Arrays.asList("[[a, b], [a, b]]", "[[a, b], [a]]", "[[a], [a]]", "[[a]]", "[]")); - Predicate property = s -> !failing.contains(s); - checkFalsified(gen, property, 0); // prove that it sometimes fails - for (int i = 0; i < 1000; i++) { - try { - PropertyChecker.customized().silent().forAll(gen, property); - } - catch (PropertyFalsified e) { - assertEquals("[]", e.getBreakingValue()); - } - } - } - -} diff --git a/jetCheck/test/org/jetbrains/jetCheck/StatefulGeneratorTest.java b/jetCheck/test/org/jetbrains/jetCheck/StatefulGeneratorTest.java deleted file mode 100644 index 8404789f9a3c..000000000000 --- a/jetCheck/test/org/jetbrains/jetCheck/StatefulGeneratorTest.java +++ /dev/null @@ -1,221 +0,0 @@ -/* - * Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. - */ -package org.jetbrains.jetCheck; - -import org.jetbrains.annotations.NotNull; - -import java.util.Arrays; -import java.util.List; -import java.util.Objects; -import java.util.concurrent.atomic.AtomicBoolean; -import java.util.concurrent.atomic.AtomicInteger; -import java.util.function.Supplier; - -import static org.jetbrains.jetCheck.Generator.*; - -/** - * @author peter - */ -public class StatefulGeneratorTest extends PropertyCheckerTestCase { - static final String DELETING = "deleting"; - - public void testShrinkingIntsWithDistributionsDependingOnListSize() { - Generator> gen = from(data -> { - AtomicInteger modelLength = new AtomicInteger(0); - Generator> cmds = listsOf(from(cmdData -> { - int index = cmdData.generate(integers(0, modelLength.getAndIncrement())); - char c = cmdData.generate(asciiLetters()); - return new InsertChar(c, index); - })); - return data.generate(cmds); - }); - List minCmds = checkGeneratesExample(gen, - cmds -> InsertChar.performOperations(cmds).contains("ab"), - 17); - assertEquals(minCmds.toString(), 2, minCmds.size()); - } - - public void testImperativeInsertDeleteCheckCommands() { - Scenario minHistory = checkFalsified(Scenario.scenarios(() -> env -> { - StringBuilder sb = new StringBuilder(); - env.executeCommands(withRecursion(insertStringCmd(sb), deleteStringCmd(sb), checkDoesNotContain(sb, "A"))); - }), Scenario::ensureSuccessful, 29).getMinimalCounterexample().getExampleValue(); - - assertEquals("commands:\n" + - " insert A at 0\n" + - " check", - minHistory.toString()); - } - - public void testImperativeInsertReplaceDeleteCommands() { - Scenario minHistory = checkFalsified(Scenario.scenarios(() -> env -> { - StringBuilder sb = new StringBuilder(); - ImperativeCommand replace = env1 -> { - if (sb.length() == 0) return; - int index = env1.generateValue(integers(0, sb.length() - 1), null); - char toReplace = env1.generateValue(asciiLetters().suchThat(c -> c != 'A'), "replace " + sb.charAt(index) + " with %s at " + index); - sb.setCharAt(index, toReplace); - }; - - env.executeCommands(withRecursion(insertStringCmd(sb), replace, deleteStringCmd(sb), checkDoesNotContain(sb, "A"))); - }), Scenario::ensureSuccessful, 52).getMinimalCounterexample().getExampleValue(); - - assertEquals("commands:\n" + - " insert A at 0\n" + - " check", - minHistory.toString()); - } - - public void testImperativeCommandRechecking() { - AtomicInteger counter = new AtomicInteger(); - Supplier command = () -> env -> { - List list = env.generateValue(listsOf(integers()), "%s"); - if (list.size() > 5 || counter.incrementAndGet() > 50) { - throw new AssertionError(); - } - }; - try { - PropertyChecker.customized().silent().checkScenarios(command); - fail(); - } - catch (PropertyFalsified e) { - assertFalse(e.getMessage(), e.getMessage().contains("forAll(...")); - assertTrue(e.getMessage(), e.getMessage().contains("rechecking(")); - assertTrue(e.getMessage(), e.getMessage().contains("checkScenarios(...")); - - PropertyFailure failure = e.getFailure(); - try { - //noinspection deprecation - PropertyChecker.customized().silent().rechecking(failure.getMinimalCounterexample().getSerializedData()).checkScenarios(command); - fail(); - } - catch (PropertyFalsified fromRecheck) { - assertEquals(e.getBreakingValue(), fromRecheck.getBreakingValue()); - } - } - } - - // we shouldn't fail on incomplete data - // because the test might have failed in the middle of some command execution, - // and after we fixed the reason of test failure, the command might just want to continue working, - // but there's no saved data for that - public void testRecheckingOnIncompleteData() { - AtomicBoolean shouldFail = new AtomicBoolean(true); - Supplier command = () -> env -> { - for (int i = 0; i < 100; i++) { - env.generateValue(integers(0, 100), null); - if (shouldFail.get()) { - throw new AssertionError(); - } - } - }; - - try { - PropertyChecker.customized().silent().checkScenarios(command); - fail(); - } - catch (PropertyFalsified e) { - shouldFail.set(false); - - //noinspection deprecation - PropertyChecker.customized().silent().rechecking(e.getFailure().getMinimalCounterexample().getSerializedData()).checkScenarios(command); - } - } - - @NotNull - static Generator withRecursion(ImperativeCommand... commands) { - return recursive(rec -> { - ImperativeCommand group = env -> { - env.logMessage("Group"); - env.executeCommands(rec); - }; - return frequency(2, constant(group), 3, sampledFrom(commands)); - }); - } - - @SuppressWarnings("SameParameterValue") - @NotNull - private static ImperativeCommand checkDoesNotContain(StringBuilder sb, String infix) { - return env -> { - env.logMessage("check"); - if (sb.indexOf(infix) >= 0) throw new AssertionError(); - }; - } - - @NotNull - static ImperativeCommand insertStringCmd(StringBuilder sb) { - return env -> { - int index = env.generateValue(integers(0, sb.length()), null); - String toInsert = env.generateValue(stringsOf(asciiLetters()), "insert %s at " + index); - sb.insert(index, toInsert); - }; - } - - @NotNull - static ImperativeCommand deleteStringCmd(StringBuilder sb) { - return env -> { - int start = env.generateValue(integers(0, sb.length()), null); - int end = env.generateValue(integers(start, sb.length()), DELETING + " (" + start + ", %s)"); - sb.delete(start, end); - }; - } - - private ImperativeCommand heavyCommand() { - Object[] heavyObject = new Object[100_000]; - heavyObject[42] = new Object(); - return new ImperativeCommand() { - @Override - public void performCommand(@NotNull Environment env) {} - - @Override - public String toString() { - return super.toString() + Arrays.toString(heavyObject); - } - }; - } - - public void testDontFailByOutOfMemoryDueToLeakingObjectsPassedIntoGenerators() { - PropertyChecker.customized().checkScenarios(() -> env -> - env.executeCommands(from(data -> data.generate(sampledFrom(heavyCommand(), heavyCommand(), heavyCommand()))))); - } - -} - -class InsertChar { - private final char c; - private final int index; - - InsertChar(char c, int index) { - this.c = c; - this.index = index; - } - - public void performOperation(StringBuilder sb) { - sb.insert(index, c); - } - - @Override - public String toString() { - return "insert " + c + " at " + index; - } - - @Override - public boolean equals(Object o) { - if (this == o) return true; - if (!(o instanceof InsertChar)) return false; - InsertChar aChar = (InsertChar)o; - return c == aChar.c && index == aChar.index; - } - - @Override - public int hashCode() { - return Objects.hash(c, index); - } - - static String performOperations(List cmds) { - StringBuilder sb = new StringBuilder(); - cmds.forEach(cmd -> cmd.performOperation(sb)); - return sb.toString(); - } -} \ No newline at end of file diff --git a/jetCheck/test/org/jetbrains/jetCheck/SubSequenceTest.java b/jetCheck/test/org/jetbrains/jetCheck/SubSequenceTest.java deleted file mode 100644 index fa5c08b0eccf..000000000000 --- a/jetCheck/test/org/jetbrains/jetCheck/SubSequenceTest.java +++ /dev/null @@ -1,63 +0,0 @@ -// Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. -package org.jetbrains.jetCheck; - -import org.junit.Test; -import org.junit.runner.RunWith; -import org.junit.runners.Parameterized; - -import java.util.Arrays; -import java.util.Collection; - -import static org.jetbrains.jetCheck.StatefulGeneratorTest.*; - -/** - * @author peter - */ -@RunWith(Parameterized.class) -public class SubSequenceTest extends PropertyCheckerTestCase{ - private final String subSequence; - private final int expectedMinimizations; - - @SuppressWarnings("JUnitTestCaseWithNonTrivialConstructors") - public SubSequenceTest(String subSequence, int expectedMinimizations) { - this.subSequence = subSequence; - this.expectedMinimizations = expectedMinimizations; - } - - @Parameterized.Parameters(name = "{0}") - public static Collection data() { - return Arrays.asList( - new Object[]{"abcde", 399}, - new Object[]{"abcdef", 420}, - new Object[]{"sadf", 107}, - new Object[]{"asdf", 118}, - new Object[]{"xxx", 81}, - new Object[]{"AA", 47} - ); - } - - @Test - public void checkGeneratesSubSequence() { - PropertyFailure.CounterExample example = checkFalsified(Scenario.scenarios(() -> env -> { - StringBuilder sb = new StringBuilder(); - env.executeCommands(withRecursion(insertStringCmd(sb), deleteStringCmd(sb), e -> { - if (containsSubSequence(sb.toString(), subSequence)) { - throw new AssertionError("Found " + sb.toString()); - } - })); - }), Scenario::ensureSuccessful, expectedMinimizations).getMinimalCounterexample(); - String log = example.getExampleValue().toString(); - assertEquals(log, "Found " + subSequence, example.getExceptionCause().getMessage()); - assertFalse(log, log.contains(DELETING)); - } - - private static boolean containsSubSequence(String string, String subSequence) { - int pos = -1; - for (int i = 0; i < subSequence.length(); i++) { - pos = string.indexOf(subSequence.charAt(i), pos + 1); - if (pos < 0) return false; - } - return true; - } - -} \ No newline at end of file