/* __ __ __ __ __ ___ * \ \ / / \ \ / / __/ * \ \/ / /\ \ \/ / / * \____/__/ \__\____/__/.ɪᴏ * ᶜᵒᵖʸʳᶦᵍʰᵗ ᵇʸ ᵛᵃᵛʳ ⁻ ˡᶦᶜᵉⁿˢᵉᵈ ᵘⁿᵈᵉʳ ᵗʰᵉ ᵃᵖᵃᶜʰᵉ ˡᶦᶜᵉⁿˢᵉ ᵛᵉʳˢᶦᵒⁿ ᵗʷᵒ ᵈᵒᵗ ᶻᵉʳᵒ */ package io.vavr.test; /*-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-*\ G E N E R A T O R C R A F T E D \*-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-*/ import io.vavr.*; import io.vavr.control.Option; import io.vavr.control.Try; import java.util.Objects; import java.util.Random; /** * A property builder which provides a fluent API to build checkable properties. * * @author Daniel Dietrich */ public class Property { private final String name; private Property(String name) { this.name = name; } /** * Defines a new Property. * * @param name property name * @return a new {@code Property} * @throws NullPointerException if name is null. * @throws IllegalArgumentException if name is empty or consists of whitespace only */ public static Property def(String name) { Objects.requireNonNull(name, "name is null"); if (name.trim().isEmpty()) { throw new IllegalArgumentException("name is empty"); } return new Property(name); } private static void logSatisfied(String name, int tries, long millis, boolean exhausted) { if (exhausted) { log(String.format("%s: Exhausted after %s tests in %s ms.", name, tries, millis)); } else { log(String.format("%s: OK, passed %s tests in %s ms.", name, tries, millis)); } } private static void logFalsified(String name, int currentTry, long millis) { log(String.format("%s: Falsified after %s passed tests in %s ms.", name, currentTry - 1, millis)); } private static void logErroneous(String name, int currentTry, long millis, String errorMessage) { log(String.format("%s: Errored after %s passed tests in %s ms with message: %s", name, Math.max(0, currentTry - 1), millis, errorMessage)); } private static void log(String msg) { System.out.println(msg); } /** * Creates a CheckError caused by an exception when obtaining a generator. * * @param position The position of the argument within the argument list of the property, starting with 1. * @param size The size hint passed to the {@linkplain Arbitrary} which caused the error. * @param cause The error which occurred when the {@linkplain Arbitrary} tried to obtain the generator {@linkplain Gen}. * @return a new CheckError instance. */ private static CheckError arbitraryError(int position, int size, Throwable cause) { return new CheckError(String.format("Arbitrary %s of size %s: %s", position, size, cause.getMessage()), cause); } /** * Creates a CheckError caused by an exception when generating a value. * * @param position The position of the argument within the argument list of the property, starting with 1. * @param size The size hint of the arbitrary which called the generator {@linkplain Gen} which caused the error. * @param cause The error which occurred when the {@linkplain Gen} tried to generate a random value. * @return a new CheckError instance. */ private static CheckError genError(int position, int size, Throwable cause) { return new CheckError(String.format("Gen %s of size %s: %s", position, size, cause.getMessage()), cause); } /** * Creates a CheckError caused by an exception when testing a Predicate. * * @param cause The error which occurred when applying the {@linkplain java.util.function.Predicate}. * @return a new CheckError instance. */ private static CheckError predicateError(Throwable cause) { return new CheckError("Applying predicate: " + cause.getMessage(), cause); } /** * Returns a logical for all quantor of 1 given variables. * * @param <T1> 1st variable type of this for all quantor * @param a1 1st variable of this for all quantor * @return a new {@code ForAll1} instance of 1 variables */ public <T1> ForAll1<T1> forAll(Arbitrary<T1> a1) { return new ForAll1<>(name, a1); } /** * Returns a logical for all quantor of 2 given variables. * * @param <T1> 1st variable type of this for all quantor * @param <T2> 2nd variable type of this for all quantor * @param a1 1st variable of this for all quantor * @param a2 2nd variable of this for all quantor * @return a new {@code ForAll2} instance of 2 variables */ public <T1, T2> ForAll2<T1, T2> forAll(Arbitrary<T1> a1, Arbitrary<T2> a2) { return new ForAll2<>(name, a1, a2); } /** * Returns a logical for all quantor of 3 given variables. * * @param <T1> 1st variable type of this for all quantor * @param <T2> 2nd variable type of this for all quantor * @param <T3> 3rd variable type of this for all quantor * @param a1 1st variable of this for all quantor * @param a2 2nd variable of this for all quantor * @param a3 3rd variable of this for all quantor * @return a new {@code ForAll3} instance of 3 variables */ public <T1, T2, T3> ForAll3<T1, T2, T3> forAll(Arbitrary<T1> a1, Arbitrary<T2> a2, Arbitrary<T3> a3) { return new ForAll3<>(name, a1, a2, a3); } /** * Returns a logical for all quantor of 4 given variables. * * @param <T1> 1st variable type of this for all quantor * @param <T2> 2nd variable type of this for all quantor * @param <T3> 3rd variable type of this for all quantor * @param <T4> 4th variable type of this for all quantor * @param a1 1st variable of this for all quantor * @param a2 2nd variable of this for all quantor * @param a3 3rd variable of this for all quantor * @param a4 4th variable of this for all quantor * @return a new {@code ForAll4} instance of 4 variables */ public <T1, T2, T3, T4> ForAll4<T1, T2, T3, T4> forAll(Arbitrary<T1> a1, Arbitrary<T2> a2, Arbitrary<T3> a3, Arbitrary<T4> a4) { return new ForAll4<>(name, a1, a2, a3, a4); } /** * Returns a logical for all quantor of 5 given variables. * * @param <T1> 1st variable type of this for all quantor * @param <T2> 2nd variable type of this for all quantor * @param <T3> 3rd variable type of this for all quantor * @param <T4> 4th variable type of this for all quantor * @param <T5> 5th variable type of this for all quantor * @param a1 1st variable of this for all quantor * @param a2 2nd variable of this for all quantor * @param a3 3rd variable of this for all quantor * @param a4 4th variable of this for all quantor * @param a5 5th variable of this for all quantor * @return a new {@code ForAll5} instance of 5 variables */ public <T1, T2, T3, T4, T5> ForAll5<T1, T2, T3, T4, T5> forAll(Arbitrary<T1> a1, Arbitrary<T2> a2, Arbitrary<T3> a3, Arbitrary<T4> a4, Arbitrary<T5> a5) { return new ForAll5<>(name, a1, a2, a3, a4, a5); } /** * Returns a logical for all quantor of 6 given variables. * * @param <T1> 1st variable type of this for all quantor * @param <T2> 2nd variable type of this for all quantor * @param <T3> 3rd variable type of this for all quantor * @param <T4> 4th variable type of this for all quantor * @param <T5> 5th variable type of this for all quantor * @param <T6> 6th variable type of this for all quantor * @param a1 1st variable of this for all quantor * @param a2 2nd variable of this for all quantor * @param a3 3rd variable of this for all quantor * @param a4 4th variable of this for all quantor * @param a5 5th variable of this for all quantor * @param a6 6th variable of this for all quantor * @return a new {@code ForAll6} instance of 6 variables */ public <T1, T2, T3, T4, T5, T6> ForAll6<T1, T2, T3, T4, T5, T6> forAll(Arbitrary<T1> a1, Arbitrary<T2> a2, Arbitrary<T3> a3, Arbitrary<T4> a4, Arbitrary<T5> a5, Arbitrary<T6> a6) { return new ForAll6<>(name, a1, a2, a3, a4, a5, a6); } /** * Returns a logical for all quantor of 7 given variables. * * @param <T1> 1st variable type of this for all quantor * @param <T2> 2nd variable type of this for all quantor * @param <T3> 3rd variable type of this for all quantor * @param <T4> 4th variable type of this for all quantor * @param <T5> 5th variable type of this for all quantor * @param <T6> 6th variable type of this for all quantor * @param <T7> 7th variable type of this for all quantor * @param a1 1st variable of this for all quantor * @param a2 2nd variable of this for all quantor * @param a3 3rd variable of this for all quantor * @param a4 4th variable of this for all quantor * @param a5 5th variable of this for all quantor * @param a6 6th variable of this for all quantor * @param a7 7th variable of this for all quantor * @return a new {@code ForAll7} instance of 7 variables */ public <T1, T2, T3, T4, T5, T6, T7> ForAll7<T1, T2, T3, T4, T5, T6, T7> forAll(Arbitrary<T1> a1, Arbitrary<T2> a2, Arbitrary<T3> a3, Arbitrary<T4> a4, Arbitrary<T5> a5, Arbitrary<T6> a6, Arbitrary<T7> a7) { return new ForAll7<>(name, a1, a2, a3, a4, a5, a6, a7); } /** * Returns a logical for all quantor of 8 given variables. * * @param <T1> 1st variable type of this for all quantor * @param <T2> 2nd variable type of this for all quantor * @param <T3> 3rd variable type of this for all quantor * @param <T4> 4th variable type of this for all quantor * @param <T5> 5th variable type of this for all quantor * @param <T6> 6th variable type of this for all quantor * @param <T7> 7th variable type of this for all quantor * @param <T8> 8th variable type of this for all quantor * @param a1 1st variable of this for all quantor * @param a2 2nd variable of this for all quantor * @param a3 3rd variable of this for all quantor * @param a4 4th variable of this for all quantor * @param a5 5th variable of this for all quantor * @param a6 6th variable of this for all quantor * @param a7 7th variable of this for all quantor * @param a8 8th variable of this for all quantor * @return a new {@code ForAll8} instance of 8 variables */ public <T1, T2, T3, T4, T5, T6, T7, T8> ForAll8<T1, T2, T3, T4, T5, T6, T7, T8> forAll(Arbitrary<T1> a1, Arbitrary<T2> a2, Arbitrary<T3> a3, Arbitrary<T4> a4, Arbitrary<T5> a5, Arbitrary<T6> a6, Arbitrary<T7> a7, Arbitrary<T8> a8) { return new ForAll8<>(name, a1, a2, a3, a4, a5, a6, a7, a8); } /** * Represents a logical for all quantor. * * @param <T1> 1st variable type of this for all quantor * @author Daniel Dietrich */ public static class ForAll1<T1> { private final String name; private final Arbitrary<T1> a1; ForAll1(String name, Arbitrary<T1> a1) { this.name = name; this.a1 = a1; } /** * Returns a checkable property that checks values of the 1 variables of this {@code ForAll} quantor. * * @param predicate A 1-ary predicate * @return a new {@code Property1} of 1 variables. */ public Property1<T1> suchThat(CheckedFunction1<T1, Boolean> predicate) { final CheckedFunction1<T1, Condition> proposition = (t1) -> new Condition(true, predicate.apply(t1)); return new Property1<>(name, a1, proposition); } } /** * Represents a logical for all quantor. * * @param <T1> 1st variable type of this for all quantor * @param <T2> 2nd variable type of this for all quantor * @author Daniel Dietrich */ public static class ForAll2<T1, T2> { private final String name; private final Arbitrary<T1> a1; private final Arbitrary<T2> a2; ForAll2(String name, Arbitrary<T1> a1, Arbitrary<T2> a2) { this.name = name; this.a1 = a1; this.a2 = a2; } /** * Returns a checkable property that checks values of the 2 variables of this {@code ForAll} quantor. * * @param predicate A 2-ary predicate * @return a new {@code Property2} of 2 variables. */ public Property2<T1, T2> suchThat(CheckedFunction2<T1, T2, Boolean> predicate) { final CheckedFunction2<T1, T2, Condition> proposition = (t1, t2) -> new Condition(true, predicate.apply(t1, t2)); return new Property2<>(name, a1, a2, proposition); } } /** * Represents a logical for all quantor. * * @param <T1> 1st variable type of this for all quantor * @param <T2> 2nd variable type of this for all quantor * @param <T3> 3rd variable type of this for all quantor * @author Daniel Dietrich */ public static class ForAll3<T1, T2, T3> { private final String name; private final Arbitrary<T1> a1; private final Arbitrary<T2> a2; private final Arbitrary<T3> a3; ForAll3(String name, Arbitrary<T1> a1, Arbitrary<T2> a2, Arbitrary<T3> a3) { this.name = name; this.a1 = a1; this.a2 = a2; this.a3 = a3; } /** * Returns a checkable property that checks values of the 3 variables of this {@code ForAll} quantor. * * @param predicate A 3-ary predicate * @return a new {@code Property3} of 3 variables. */ public Property3<T1, T2, T3> suchThat(CheckedFunction3<T1, T2, T3, Boolean> predicate) { final CheckedFunction3<T1, T2, T3, Condition> proposition = (t1, t2, t3) -> new Condition(true, predicate.apply(t1, t2, t3)); return new Property3<>(name, a1, a2, a3, proposition); } } /** * Represents a logical for all quantor. * * @param <T1> 1st variable type of this for all quantor * @param <T2> 2nd variable type of this for all quantor * @param <T3> 3rd variable type of this for all quantor * @param <T4> 4th variable type of this for all quantor * @author Daniel Dietrich */ public static class ForAll4<T1, T2, T3, T4> { private final String name; private final Arbitrary<T1> a1; private final Arbitrary<T2> a2; private final Arbitrary<T3> a3; private final Arbitrary<T4> a4; ForAll4(String name, Arbitrary<T1> a1, Arbitrary<T2> a2, Arbitrary<T3> a3, Arbitrary<T4> a4) { this.name = name; this.a1 = a1; this.a2 = a2; this.a3 = a3; this.a4 = a4; } /** * Returns a checkable property that checks values of the 4 variables of this {@code ForAll} quantor. * * @param predicate A 4-ary predicate * @return a new {@code Property4} of 4 variables. */ public Property4<T1, T2, T3, T4> suchThat(CheckedFunction4<T1, T2, T3, T4, Boolean> predicate) { final CheckedFunction4<T1, T2, T3, T4, Condition> proposition = (t1, t2, t3, t4) -> new Condition(true, predicate.apply(t1, t2, t3, t4)); return new Property4<>(name, a1, a2, a3, a4, proposition); } } /** * Represents a logical for all quantor. * * @param <T1> 1st variable type of this for all quantor * @param <T2> 2nd variable type of this for all quantor * @param <T3> 3rd variable type of this for all quantor * @param <T4> 4th variable type of this for all quantor * @param <T5> 5th variable type of this for all quantor * @author Daniel Dietrich */ public static class ForAll5<T1, T2, T3, T4, T5> { private final String name; private final Arbitrary<T1> a1; private final Arbitrary<T2> a2; private final Arbitrary<T3> a3; private final Arbitrary<T4> a4; private final Arbitrary<T5> a5; ForAll5(String name, Arbitrary<T1> a1, Arbitrary<T2> a2, Arbitrary<T3> a3, Arbitrary<T4> a4, Arbitrary<T5> a5) { this.name = name; this.a1 = a1; this.a2 = a2; this.a3 = a3; this.a4 = a4; this.a5 = a5; } /** * Returns a checkable property that checks values of the 5 variables of this {@code ForAll} quantor. * * @param predicate A 5-ary predicate * @return a new {@code Property5} of 5 variables. */ public Property5<T1, T2, T3, T4, T5> suchThat(CheckedFunction5<T1, T2, T3, T4, T5, Boolean> predicate) { final CheckedFunction5<T1, T2, T3, T4, T5, Condition> proposition = (t1, t2, t3, t4, t5) -> new Condition(true, predicate.apply(t1, t2, t3, t4, t5)); return new Property5<>(name, a1, a2, a3, a4, a5, proposition); } } /** * Represents a logical for all quantor. * * @param <T1> 1st variable type of this for all quantor * @param <T2> 2nd variable type of this for all quantor * @param <T3> 3rd variable type of this for all quantor * @param <T4> 4th variable type of this for all quantor * @param <T5> 5th variable type of this for all quantor * @param <T6> 6th variable type of this for all quantor * @author Daniel Dietrich */ public static class ForAll6<T1, T2, T3, T4, T5, T6> { private final String name; private final Arbitrary<T1> a1; private final Arbitrary<T2> a2; private final Arbitrary<T3> a3; private final Arbitrary<T4> a4; private final Arbitrary<T5> a5; private final Arbitrary<T6> a6; ForAll6(String name, Arbitrary<T1> a1, Arbitrary<T2> a2, Arbitrary<T3> a3, Arbitrary<T4> a4, Arbitrary<T5> a5, Arbitrary<T6> a6) { this.name = name; this.a1 = a1; this.a2 = a2; this.a3 = a3; this.a4 = a4; this.a5 = a5; this.a6 = a6; } /** * Returns a checkable property that checks values of the 6 variables of this {@code ForAll} quantor. * * @param predicate A 6-ary predicate * @return a new {@code Property6} of 6 variables. */ public Property6<T1, T2, T3, T4, T5, T6> suchThat(CheckedFunction6<T1, T2, T3, T4, T5, T6, Boolean> predicate) { final CheckedFunction6<T1, T2, T3, T4, T5, T6, Condition> proposition = (t1, t2, t3, t4, t5, t6) -> new Condition(true, predicate.apply(t1, t2, t3, t4, t5, t6)); return new Property6<>(name, a1, a2, a3, a4, a5, a6, proposition); } } /** * Represents a logical for all quantor. * * @param <T1> 1st variable type of this for all quantor * @param <T2> 2nd variable type of this for all quantor * @param <T3> 3rd variable type of this for all quantor * @param <T4> 4th variable type of this for all quantor * @param <T5> 5th variable type of this for all quantor * @param <T6> 6th variable type of this for all quantor * @param <T7> 7th variable type of this for all quantor * @author Daniel Dietrich */ public static class ForAll7<T1, T2, T3, T4, T5, T6, T7> { private final String name; private final Arbitrary<T1> a1; private final Arbitrary<T2> a2; private final Arbitrary<T3> a3; private final Arbitrary<T4> a4; private final Arbitrary<T5> a5; private final Arbitrary<T6> a6; private final Arbitrary<T7> a7; ForAll7(String name, Arbitrary<T1> a1, Arbitrary<T2> a2, Arbitrary<T3> a3, Arbitrary<T4> a4, Arbitrary<T5> a5, Arbitrary<T6> a6, Arbitrary<T7> a7) { this.name = name; this.a1 = a1; this.a2 = a2; this.a3 = a3; this.a4 = a4; this.a5 = a5; this.a6 = a6; this.a7 = a7; } /** * Returns a checkable property that checks values of the 7 variables of this {@code ForAll} quantor. * * @param predicate A 7-ary predicate * @return a new {@code Property7} of 7 variables. */ public Property7<T1, T2, T3, T4, T5, T6, T7> suchThat(CheckedFunction7<T1, T2, T3, T4, T5, T6, T7, Boolean> predicate) { final CheckedFunction7<T1, T2, T3, T4, T5, T6, T7, Condition> proposition = (t1, t2, t3, t4, t5, t6, t7) -> new Condition(true, predicate.apply(t1, t2, t3, t4, t5, t6, t7)); return new Property7<>(name, a1, a2, a3, a4, a5, a6, a7, proposition); } } /** * Represents a logical for all quantor. * * @param <T1> 1st variable type of this for all quantor * @param <T2> 2nd variable type of this for all quantor * @param <T3> 3rd variable type of this for all quantor * @param <T4> 4th variable type of this for all quantor * @param <T5> 5th variable type of this for all quantor * @param <T6> 6th variable type of this for all quantor * @param <T7> 7th variable type of this for all quantor * @param <T8> 8th variable type of this for all quantor * @author Daniel Dietrich */ public static class ForAll8<T1, T2, T3, T4, T5, T6, T7, T8> { private final String name; private final Arbitrary<T1> a1; private final Arbitrary<T2> a2; private final Arbitrary<T3> a3; private final Arbitrary<T4> a4; private final Arbitrary<T5> a5; private final Arbitrary<T6> a6; private final Arbitrary<T7> a7; private final Arbitrary<T8> a8; ForAll8(String name, Arbitrary<T1> a1, Arbitrary<T2> a2, Arbitrary<T3> a3, Arbitrary<T4> a4, Arbitrary<T5> a5, Arbitrary<T6> a6, Arbitrary<T7> a7, Arbitrary<T8> a8) { this.name = name; this.a1 = a1; this.a2 = a2; this.a3 = a3; this.a4 = a4; this.a5 = a5; this.a6 = a6; this.a7 = a7; this.a8 = a8; } /** * Returns a checkable property that checks values of the 8 variables of this {@code ForAll} quantor. * * @param predicate A 8-ary predicate * @return a new {@code Property8} of 8 variables. */ public Property8<T1, T2, T3, T4, T5, T6, T7, T8> suchThat(CheckedFunction8<T1, T2, T3, T4, T5, T6, T7, T8, Boolean> predicate) { final CheckedFunction8<T1, T2, T3, T4, T5, T6, T7, T8, Condition> proposition = (t1, t2, t3, t4, t5, t6, t7, t8) -> new Condition(true, predicate.apply(t1, t2, t3, t4, t5, t6, t7, t8)); return new Property8<>(name, a1, a2, a3, a4, a5, a6, a7, a8, proposition); } } /** * Represents a 1-ary checkable property. * * @author Daniel Dietrich */ public static class Property1<T1> implements Checkable { private final String name; private final Arbitrary<T1> a1; private final CheckedFunction1<T1, Condition> predicate; Property1(String name, Arbitrary<T1> a1, CheckedFunction1<T1, Condition> predicate) { this.name = name; this.a1 = a1; this.predicate = predicate; } /** * Returns an implication which composes this Property as pre-condition and a given post-condition. * * @param postcondition The postcondition of this implication * @return A new Checkable implication */ public Checkable implies(CheckedFunction1<T1, Boolean> postcondition) { final CheckedFunction1<T1, Condition> implication = (t1) -> { final Condition precondition = predicate.apply(t1); if (precondition.isFalse()) { return Condition.EX_FALSO_QUODLIBET; } else { return new Condition(true, postcondition.apply(t1)); } }; return new Property1<>(name, a1, implication); } @Override public CheckResult check(Random random, int size, int tries) { Objects.requireNonNull(random, "random is null"); if (tries < 0) { throw new IllegalArgumentException("tries < 0"); } final long startTime = System.currentTimeMillis(); try { final Gen<T1> gen1 = Try.of(() -> a1.apply(size)).recover(x -> { throw arbitraryError(1, size, x); }).get(); boolean exhausted = true; for (int i = 1; i <= tries; i++) { try { final T1 val1 = Try.of(() -> gen1.apply(random)).recover(x -> { throw genError(1, size, x); }).get(); try { final Condition condition = Try.of(() -> predicate.apply(val1)).recover(x -> { throw predicateError(x); }).get(); if (condition.precondition) { exhausted = false; if (!condition.postcondition) { logFalsified(name, i, System.currentTimeMillis() - startTime); return new CheckResult.Falsified(name, i, Tuple.of(val1)); } } } catch(CheckError err) { logErroneous(name, i, System.currentTimeMillis() - startTime, err.getMessage()); return new CheckResult.Erroneous(name, i, err, Option.some(Tuple.of(val1))); } } catch(CheckError err) { logErroneous(name, i, System.currentTimeMillis() - startTime, err.getMessage()); return new CheckResult.Erroneous(name, i, err, Option.none()); } } logSatisfied(name, tries, System.currentTimeMillis() - startTime, exhausted); return new CheckResult.Satisfied(name, tries, exhausted); } catch(CheckError err) { logErroneous(name, 0, System.currentTimeMillis() - startTime, err.getMessage()); return new CheckResult.Erroneous(name, 0, err, Option.none()); } } } /** * Represents a 2-ary checkable property. * * @author Daniel Dietrich */ public static class Property2<T1, T2> implements Checkable { private final String name; private final Arbitrary<T1> a1; private final Arbitrary<T2> a2; private final CheckedFunction2<T1, T2, Condition> predicate; Property2(String name, Arbitrary<T1> a1, Arbitrary<T2> a2, CheckedFunction2<T1, T2, Condition> predicate) { this.name = name; this.a1 = a1; this.a2 = a2; this.predicate = predicate; } /** * Returns an implication which composes this Property as pre-condition and a given post-condition. * * @param postcondition The postcondition of this implication * @return A new Checkable implication */ public Checkable implies(CheckedFunction2<T1, T2, Boolean> postcondition) { final CheckedFunction2<T1, T2, Condition> implication = (t1, t2) -> { final Condition precondition = predicate.apply(t1, t2); if (precondition.isFalse()) { return Condition.EX_FALSO_QUODLIBET; } else { return new Condition(true, postcondition.apply(t1, t2)); } }; return new Property2<>(name, a1, a2, implication); } @Override public CheckResult check(Random random, int size, int tries) { Objects.requireNonNull(random, "random is null"); if (tries < 0) { throw new IllegalArgumentException("tries < 0"); } final long startTime = System.currentTimeMillis(); try { final Gen<T1> gen1 = Try.of(() -> a1.apply(size)).recover(x -> { throw arbitraryError(1, size, x); }).get(); final Gen<T2> gen2 = Try.of(() -> a2.apply(size)).recover(x -> { throw arbitraryError(2, size, x); }).get(); boolean exhausted = true; for (int i = 1; i <= tries; i++) { try { final T1 val1 = Try.of(() -> gen1.apply(random)).recover(x -> { throw genError(1, size, x); }).get(); final T2 val2 = Try.of(() -> gen2.apply(random)).recover(x -> { throw genError(2, size, x); }).get(); try { final Condition condition = Try.of(() -> predicate.apply(val1, val2)).recover(x -> { throw predicateError(x); }).get(); if (condition.precondition) { exhausted = false; if (!condition.postcondition) { logFalsified(name, i, System.currentTimeMillis() - startTime); return new CheckResult.Falsified(name, i, Tuple.of(val1, val2)); } } } catch(CheckError err) { logErroneous(name, i, System.currentTimeMillis() - startTime, err.getMessage()); return new CheckResult.Erroneous(name, i, err, Option.some(Tuple.of(val1, val2))); } } catch(CheckError err) { logErroneous(name, i, System.currentTimeMillis() - startTime, err.getMessage()); return new CheckResult.Erroneous(name, i, err, Option.none()); } } logSatisfied(name, tries, System.currentTimeMillis() - startTime, exhausted); return new CheckResult.Satisfied(name, tries, exhausted); } catch(CheckError err) { logErroneous(name, 0, System.currentTimeMillis() - startTime, err.getMessage()); return new CheckResult.Erroneous(name, 0, err, Option.none()); } } } /** * Represents a 3-ary checkable property. * * @author Daniel Dietrich */ public static class Property3<T1, T2, T3> implements Checkable { private final String name; private final Arbitrary<T1> a1; private final Arbitrary<T2> a2; private final Arbitrary<T3> a3; private final CheckedFunction3<T1, T2, T3, Condition> predicate; Property3(String name, Arbitrary<T1> a1, Arbitrary<T2> a2, Arbitrary<T3> a3, CheckedFunction3<T1, T2, T3, Condition> predicate) { this.name = name; this.a1 = a1; this.a2 = a2; this.a3 = a3; this.predicate = predicate; } /** * Returns an implication which composes this Property as pre-condition and a given post-condition. * * @param postcondition The postcondition of this implication * @return A new Checkable implication */ public Checkable implies(CheckedFunction3<T1, T2, T3, Boolean> postcondition) { final CheckedFunction3<T1, T2, T3, Condition> implication = (t1, t2, t3) -> { final Condition precondition = predicate.apply(t1, t2, t3); if (precondition.isFalse()) { return Condition.EX_FALSO_QUODLIBET; } else { return new Condition(true, postcondition.apply(t1, t2, t3)); } }; return new Property3<>(name, a1, a2, a3, implication); } @Override public CheckResult check(Random random, int size, int tries) { Objects.requireNonNull(random, "random is null"); if (tries < 0) { throw new IllegalArgumentException("tries < 0"); } final long startTime = System.currentTimeMillis(); try { final Gen<T1> gen1 = Try.of(() -> a1.apply(size)).recover(x -> { throw arbitraryError(1, size, x); }).get(); final Gen<T2> gen2 = Try.of(() -> a2.apply(size)).recover(x -> { throw arbitraryError(2, size, x); }).get(); final Gen<T3> gen3 = Try.of(() -> a3.apply(size)).recover(x -> { throw arbitraryError(3, size, x); }).get(); boolean exhausted = true; for (int i = 1; i <= tries; i++) { try { final T1 val1 = Try.of(() -> gen1.apply(random)).recover(x -> { throw genError(1, size, x); }).get(); final T2 val2 = Try.of(() -> gen2.apply(random)).recover(x -> { throw genError(2, size, x); }).get(); final T3 val3 = Try.of(() -> gen3.apply(random)).recover(x -> { throw genError(3, size, x); }).get(); try { final Condition condition = Try.of(() -> predicate.apply(val1, val2, val3)).recover(x -> { throw predicateError(x); }).get(); if (condition.precondition) { exhausted = false; if (!condition.postcondition) { logFalsified(name, i, System.currentTimeMillis() - startTime); return new CheckResult.Falsified(name, i, Tuple.of(val1, val2, val3)); } } } catch(CheckError err) { logErroneous(name, i, System.currentTimeMillis() - startTime, err.getMessage()); return new CheckResult.Erroneous(name, i, err, Option.some(Tuple.of(val1, val2, val3))); } } catch(CheckError err) { logErroneous(name, i, System.currentTimeMillis() - startTime, err.getMessage()); return new CheckResult.Erroneous(name, i, err, Option.none()); } } logSatisfied(name, tries, System.currentTimeMillis() - startTime, exhausted); return new CheckResult.Satisfied(name, tries, exhausted); } catch(CheckError err) { logErroneous(name, 0, System.currentTimeMillis() - startTime, err.getMessage()); return new CheckResult.Erroneous(name, 0, err, Option.none()); } } } /** * Represents a 4-ary checkable property. * * @author Daniel Dietrich */ public static class Property4<T1, T2, T3, T4> implements Checkable { private final String name; private final Arbitrary<T1> a1; private final Arbitrary<T2> a2; private final Arbitrary<T3> a3; private final Arbitrary<T4> a4; private final CheckedFunction4<T1, T2, T3, T4, Condition> predicate; Property4(String name, Arbitrary<T1> a1, Arbitrary<T2> a2, Arbitrary<T3> a3, Arbitrary<T4> a4, CheckedFunction4<T1, T2, T3, T4, Condition> predicate) { this.name = name; this.a1 = a1; this.a2 = a2; this.a3 = a3; this.a4 = a4; this.predicate = predicate; } /** * Returns an implication which composes this Property as pre-condition and a given post-condition. * * @param postcondition The postcondition of this implication * @return A new Checkable implication */ public Checkable implies(CheckedFunction4<T1, T2, T3, T4, Boolean> postcondition) { final CheckedFunction4<T1, T2, T3, T4, Condition> implication = (t1, t2, t3, t4) -> { final Condition precondition = predicate.apply(t1, t2, t3, t4); if (precondition.isFalse()) { return Condition.EX_FALSO_QUODLIBET; } else { return new Condition(true, postcondition.apply(t1, t2, t3, t4)); } }; return new Property4<>(name, a1, a2, a3, a4, implication); } @Override public CheckResult check(Random random, int size, int tries) { Objects.requireNonNull(random, "random is null"); if (tries < 0) { throw new IllegalArgumentException("tries < 0"); } final long startTime = System.currentTimeMillis(); try { final Gen<T1> gen1 = Try.of(() -> a1.apply(size)).recover(x -> { throw arbitraryError(1, size, x); }).get(); final Gen<T2> gen2 = Try.of(() -> a2.apply(size)).recover(x -> { throw arbitraryError(2, size, x); }).get(); final Gen<T3> gen3 = Try.of(() -> a3.apply(size)).recover(x -> { throw arbitraryError(3, size, x); }).get(); final Gen<T4> gen4 = Try.of(() -> a4.apply(size)).recover(x -> { throw arbitraryError(4, size, x); }).get(); boolean exhausted = true; for (int i = 1; i <= tries; i++) { try { final T1 val1 = Try.of(() -> gen1.apply(random)).recover(x -> { throw genError(1, size, x); }).get(); final T2 val2 = Try.of(() -> gen2.apply(random)).recover(x -> { throw genError(2, size, x); }).get(); final T3 val3 = Try.of(() -> gen3.apply(random)).recover(x -> { throw genError(3, size, x); }).get(); final T4 val4 = Try.of(() -> gen4.apply(random)).recover(x -> { throw genError(4, size, x); }).get(); try { final Condition condition = Try.of(() -> predicate.apply(val1, val2, val3, val4)).recover(x -> { throw predicateError(x); }).get(); if (condition.precondition) { exhausted = false; if (!condition.postcondition) { logFalsified(name, i, System.currentTimeMillis() - startTime); return new CheckResult.Falsified(name, i, Tuple.of(val1, val2, val3, val4)); } } } catch(CheckError err) { logErroneous(name, i, System.currentTimeMillis() - startTime, err.getMessage()); return new CheckResult.Erroneous(name, i, err, Option.some(Tuple.of(val1, val2, val3, val4))); } } catch(CheckError err) { logErroneous(name, i, System.currentTimeMillis() - startTime, err.getMessage()); return new CheckResult.Erroneous(name, i, err, Option.none()); } } logSatisfied(name, tries, System.currentTimeMillis() - startTime, exhausted); return new CheckResult.Satisfied(name, tries, exhausted); } catch(CheckError err) { logErroneous(name, 0, System.currentTimeMillis() - startTime, err.getMessage()); return new CheckResult.Erroneous(name, 0, err, Option.none()); } } } /** * Represents a 5-ary checkable property. * * @author Daniel Dietrich */ public static class Property5<T1, T2, T3, T4, T5> implements Checkable { private final String name; private final Arbitrary<T1> a1; private final Arbitrary<T2> a2; private final Arbitrary<T3> a3; private final Arbitrary<T4> a4; private final Arbitrary<T5> a5; private final CheckedFunction5<T1, T2, T3, T4, T5, Condition> predicate; Property5(String name, Arbitrary<T1> a1, Arbitrary<T2> a2, Arbitrary<T3> a3, Arbitrary<T4> a4, Arbitrary<T5> a5, CheckedFunction5<T1, T2, T3, T4, T5, Condition> predicate) { this.name = name; this.a1 = a1; this.a2 = a2; this.a3 = a3; this.a4 = a4; this.a5 = a5; this.predicate = predicate; } /** * Returns an implication which composes this Property as pre-condition and a given post-condition. * * @param postcondition The postcondition of this implication * @return A new Checkable implication */ public Checkable implies(CheckedFunction5<T1, T2, T3, T4, T5, Boolean> postcondition) { final CheckedFunction5<T1, T2, T3, T4, T5, Condition> implication = (t1, t2, t3, t4, t5) -> { final Condition precondition = predicate.apply(t1, t2, t3, t4, t5); if (precondition.isFalse()) { return Condition.EX_FALSO_QUODLIBET; } else { return new Condition(true, postcondition.apply(t1, t2, t3, t4, t5)); } }; return new Property5<>(name, a1, a2, a3, a4, a5, implication); } @Override public CheckResult check(Random random, int size, int tries) { Objects.requireNonNull(random, "random is null"); if (tries < 0) { throw new IllegalArgumentException("tries < 0"); } final long startTime = System.currentTimeMillis(); try { final Gen<T1> gen1 = Try.of(() -> a1.apply(size)).recover(x -> { throw arbitraryError(1, size, x); }).get(); final Gen<T2> gen2 = Try.of(() -> a2.apply(size)).recover(x -> { throw arbitraryError(2, size, x); }).get(); final Gen<T3> gen3 = Try.of(() -> a3.apply(size)).recover(x -> { throw arbitraryError(3, size, x); }).get(); final Gen<T4> gen4 = Try.of(() -> a4.apply(size)).recover(x -> { throw arbitraryError(4, size, x); }).get(); final Gen<T5> gen5 = Try.of(() -> a5.apply(size)).recover(x -> { throw arbitraryError(5, size, x); }).get(); boolean exhausted = true; for (int i = 1; i <= tries; i++) { try { final T1 val1 = Try.of(() -> gen1.apply(random)).recover(x -> { throw genError(1, size, x); }).get(); final T2 val2 = Try.of(() -> gen2.apply(random)).recover(x -> { throw genError(2, size, x); }).get(); final T3 val3 = Try.of(() -> gen3.apply(random)).recover(x -> { throw genError(3, size, x); }).get(); final T4 val4 = Try.of(() -> gen4.apply(random)).recover(x -> { throw genError(4, size, x); }).get(); final T5 val5 = Try.of(() -> gen5.apply(random)).recover(x -> { throw genError(5, size, x); }).get(); try { final Condition condition = Try.of(() -> predicate.apply(val1, val2, val3, val4, val5)).recover(x -> { throw predicateError(x); }).get(); if (condition.precondition) { exhausted = false; if (!condition.postcondition) { logFalsified(name, i, System.currentTimeMillis() - startTime); return new CheckResult.Falsified(name, i, Tuple.of(val1, val2, val3, val4, val5)); } } } catch(CheckError err) { logErroneous(name, i, System.currentTimeMillis() - startTime, err.getMessage()); return new CheckResult.Erroneous(name, i, err, Option.some(Tuple.of(val1, val2, val3, val4, val5))); } } catch(CheckError err) { logErroneous(name, i, System.currentTimeMillis() - startTime, err.getMessage()); return new CheckResult.Erroneous(name, i, err, Option.none()); } } logSatisfied(name, tries, System.currentTimeMillis() - startTime, exhausted); return new CheckResult.Satisfied(name, tries, exhausted); } catch(CheckError err) { logErroneous(name, 0, System.currentTimeMillis() - startTime, err.getMessage()); return new CheckResult.Erroneous(name, 0, err, Option.none()); } } } /** * Represents a 6-ary checkable property. * * @author Daniel Dietrich */ public static class Property6<T1, T2, T3, T4, T5, T6> implements Checkable { private final String name; private final Arbitrary<T1> a1; private final Arbitrary<T2> a2; private final Arbitrary<T3> a3; private final Arbitrary<T4> a4; private final Arbitrary<T5> a5; private final Arbitrary<T6> a6; private final CheckedFunction6<T1, T2, T3, T4, T5, T6, Condition> predicate; Property6(String name, Arbitrary<T1> a1, Arbitrary<T2> a2, Arbitrary<T3> a3, Arbitrary<T4> a4, Arbitrary<T5> a5, Arbitrary<T6> a6, CheckedFunction6<T1, T2, T3, T4, T5, T6, Condition> predicate) { this.name = name; this.a1 = a1; this.a2 = a2; this.a3 = a3; this.a4 = a4; this.a5 = a5; this.a6 = a6; this.predicate = predicate; } /** * Returns an implication which composes this Property as pre-condition and a given post-condition. * * @param postcondition The postcondition of this implication * @return A new Checkable implication */ public Checkable implies(CheckedFunction6<T1, T2, T3, T4, T5, T6, Boolean> postcondition) { final CheckedFunction6<T1, T2, T3, T4, T5, T6, Condition> implication = (t1, t2, t3, t4, t5, t6) -> { final Condition precondition = predicate.apply(t1, t2, t3, t4, t5, t6); if (precondition.isFalse()) { return Condition.EX_FALSO_QUODLIBET; } else { return new Condition(true, postcondition.apply(t1, t2, t3, t4, t5, t6)); } }; return new Property6<>(name, a1, a2, a3, a4, a5, a6, implication); } @Override public CheckResult check(Random random, int size, int tries) { Objects.requireNonNull(random, "random is null"); if (tries < 0) { throw new IllegalArgumentException("tries < 0"); } final long startTime = System.currentTimeMillis(); try { final Gen<T1> gen1 = Try.of(() -> a1.apply(size)).recover(x -> { throw arbitraryError(1, size, x); }).get(); final Gen<T2> gen2 = Try.of(() -> a2.apply(size)).recover(x -> { throw arbitraryError(2, size, x); }).get(); final Gen<T3> gen3 = Try.of(() -> a3.apply(size)).recover(x -> { throw arbitraryError(3, size, x); }).get(); final Gen<T4> gen4 = Try.of(() -> a4.apply(size)).recover(x -> { throw arbitraryError(4, size, x); }).get(); final Gen<T5> gen5 = Try.of(() -> a5.apply(size)).recover(x -> { throw arbitraryError(5, size, x); }).get(); final Gen<T6> gen6 = Try.of(() -> a6.apply(size)).recover(x -> { throw arbitraryError(6, size, x); }).get(); boolean exhausted = true; for (int i = 1; i <= tries; i++) { try { final T1 val1 = Try.of(() -> gen1.apply(random)).recover(x -> { throw genError(1, size, x); }).get(); final T2 val2 = Try.of(() -> gen2.apply(random)).recover(x -> { throw genError(2, size, x); }).get(); final T3 val3 = Try.of(() -> gen3.apply(random)).recover(x -> { throw genError(3, size, x); }).get(); final T4 val4 = Try.of(() -> gen4.apply(random)).recover(x -> { throw genError(4, size, x); }).get(); final T5 val5 = Try.of(() -> gen5.apply(random)).recover(x -> { throw genError(5, size, x); }).get(); final T6 val6 = Try.of(() -> gen6.apply(random)).recover(x -> { throw genError(6, size, x); }).get(); try { final Condition condition = Try.of(() -> predicate.apply(val1, val2, val3, val4, val5, val6)).recover(x -> { throw predicateError(x); }).get(); if (condition.precondition) { exhausted = false; if (!condition.postcondition) { logFalsified(name, i, System.currentTimeMillis() - startTime); return new CheckResult.Falsified(name, i, Tuple.of(val1, val2, val3, val4, val5, val6)); } } } catch(CheckError err) { logErroneous(name, i, System.currentTimeMillis() - startTime, err.getMessage()); return new CheckResult.Erroneous(name, i, err, Option.some(Tuple.of(val1, val2, val3, val4, val5, val6))); } } catch(CheckError err) { logErroneous(name, i, System.currentTimeMillis() - startTime, err.getMessage()); return new CheckResult.Erroneous(name, i, err, Option.none()); } } logSatisfied(name, tries, System.currentTimeMillis() - startTime, exhausted); return new CheckResult.Satisfied(name, tries, exhausted); } catch(CheckError err) { logErroneous(name, 0, System.currentTimeMillis() - startTime, err.getMessage()); return new CheckResult.Erroneous(name, 0, err, Option.none()); } } } /** * Represents a 7-ary checkable property. * * @author Daniel Dietrich */ public static class Property7<T1, T2, T3, T4, T5, T6, T7> implements Checkable { private final String name; private final Arbitrary<T1> a1; private final Arbitrary<T2> a2; private final Arbitrary<T3> a3; private final Arbitrary<T4> a4; private final Arbitrary<T5> a5; private final Arbitrary<T6> a6; private final Arbitrary<T7> a7; private final CheckedFunction7<T1, T2, T3, T4, T5, T6, T7, Condition> predicate; Property7(String name, Arbitrary<T1> a1, Arbitrary<T2> a2, Arbitrary<T3> a3, Arbitrary<T4> a4, Arbitrary<T5> a5, Arbitrary<T6> a6, Arbitrary<T7> a7, CheckedFunction7<T1, T2, T3, T4, T5, T6, T7, Condition> predicate) { this.name = name; this.a1 = a1; this.a2 = a2; this.a3 = a3; this.a4 = a4; this.a5 = a5; this.a6 = a6; this.a7 = a7; this.predicate = predicate; } /** * Returns an implication which composes this Property as pre-condition and a given post-condition. * * @param postcondition The postcondition of this implication * @return A new Checkable implication */ public Checkable implies(CheckedFunction7<T1, T2, T3, T4, T5, T6, T7, Boolean> postcondition) { final CheckedFunction7<T1, T2, T3, T4, T5, T6, T7, Condition> implication = (t1, t2, t3, t4, t5, t6, t7) -> { final Condition precondition = predicate.apply(t1, t2, t3, t4, t5, t6, t7); if (precondition.isFalse()) { return Condition.EX_FALSO_QUODLIBET; } else { return new Condition(true, postcondition.apply(t1, t2, t3, t4, t5, t6, t7)); } }; return new Property7<>(name, a1, a2, a3, a4, a5, a6, a7, implication); } @Override public CheckResult check(Random random, int size, int tries) { Objects.requireNonNull(random, "random is null"); if (tries < 0) { throw new IllegalArgumentException("tries < 0"); } final long startTime = System.currentTimeMillis(); try { final Gen<T1> gen1 = Try.of(() -> a1.apply(size)).recover(x -> { throw arbitraryError(1, size, x); }).get(); final Gen<T2> gen2 = Try.of(() -> a2.apply(size)).recover(x -> { throw arbitraryError(2, size, x); }).get(); final Gen<T3> gen3 = Try.of(() -> a3.apply(size)).recover(x -> { throw arbitraryError(3, size, x); }).get(); final Gen<T4> gen4 = Try.of(() -> a4.apply(size)).recover(x -> { throw arbitraryError(4, size, x); }).get(); final Gen<T5> gen5 = Try.of(() -> a5.apply(size)).recover(x -> { throw arbitraryError(5, size, x); }).get(); final Gen<T6> gen6 = Try.of(() -> a6.apply(size)).recover(x -> { throw arbitraryError(6, size, x); }).get(); final Gen<T7> gen7 = Try.of(() -> a7.apply(size)).recover(x -> { throw arbitraryError(7, size, x); }).get(); boolean exhausted = true; for (int i = 1; i <= tries; i++) { try { final T1 val1 = Try.of(() -> gen1.apply(random)).recover(x -> { throw genError(1, size, x); }).get(); final T2 val2 = Try.of(() -> gen2.apply(random)).recover(x -> { throw genError(2, size, x); }).get(); final T3 val3 = Try.of(() -> gen3.apply(random)).recover(x -> { throw genError(3, size, x); }).get(); final T4 val4 = Try.of(() -> gen4.apply(random)).recover(x -> { throw genError(4, size, x); }).get(); final T5 val5 = Try.of(() -> gen5.apply(random)).recover(x -> { throw genError(5, size, x); }).get(); final T6 val6 = Try.of(() -> gen6.apply(random)).recover(x -> { throw genError(6, size, x); }).get(); final T7 val7 = Try.of(() -> gen7.apply(random)).recover(x -> { throw genError(7, size, x); }).get(); try { final Condition condition = Try.of(() -> predicate.apply(val1, val2, val3, val4, val5, val6, val7)).recover(x -> { throw predicateError(x); }).get(); if (condition.precondition) { exhausted = false; if (!condition.postcondition) { logFalsified(name, i, System.currentTimeMillis() - startTime); return new CheckResult.Falsified(name, i, Tuple.of(val1, val2, val3, val4, val5, val6, val7)); } } } catch(CheckError err) { logErroneous(name, i, System.currentTimeMillis() - startTime, err.getMessage()); return new CheckResult.Erroneous(name, i, err, Option.some(Tuple.of(val1, val2, val3, val4, val5, val6, val7))); } } catch(CheckError err) { logErroneous(name, i, System.currentTimeMillis() - startTime, err.getMessage()); return new CheckResult.Erroneous(name, i, err, Option.none()); } } logSatisfied(name, tries, System.currentTimeMillis() - startTime, exhausted); return new CheckResult.Satisfied(name, tries, exhausted); } catch(CheckError err) { logErroneous(name, 0, System.currentTimeMillis() - startTime, err.getMessage()); return new CheckResult.Erroneous(name, 0, err, Option.none()); } } } /** * Represents a 8-ary checkable property. * * @author Daniel Dietrich */ public static class Property8<T1, T2, T3, T4, T5, T6, T7, T8> implements Checkable { private final String name; private final Arbitrary<T1> a1; private final Arbitrary<T2> a2; private final Arbitrary<T3> a3; private final Arbitrary<T4> a4; private final Arbitrary<T5> a5; private final Arbitrary<T6> a6; private final Arbitrary<T7> a7; private final Arbitrary<T8> a8; private final CheckedFunction8<T1, T2, T3, T4, T5, T6, T7, T8, Condition> predicate; Property8(String name, Arbitrary<T1> a1, Arbitrary<T2> a2, Arbitrary<T3> a3, Arbitrary<T4> a4, Arbitrary<T5> a5, Arbitrary<T6> a6, Arbitrary<T7> a7, Arbitrary<T8> a8, CheckedFunction8<T1, T2, T3, T4, T5, T6, T7, T8, Condition> predicate) { this.name = name; this.a1 = a1; this.a2 = a2; this.a3 = a3; this.a4 = a4; this.a5 = a5; this.a6 = a6; this.a7 = a7; this.a8 = a8; this.predicate = predicate; } /** * Returns an implication which composes this Property as pre-condition and a given post-condition. * * @param postcondition The postcondition of this implication * @return A new Checkable implication */ public Checkable implies(CheckedFunction8<T1, T2, T3, T4, T5, T6, T7, T8, Boolean> postcondition) { final CheckedFunction8<T1, T2, T3, T4, T5, T6, T7, T8, Condition> implication = (t1, t2, t3, t4, t5, t6, t7, t8) -> { final Condition precondition = predicate.apply(t1, t2, t3, t4, t5, t6, t7, t8); if (precondition.isFalse()) { return Condition.EX_FALSO_QUODLIBET; } else { return new Condition(true, postcondition.apply(t1, t2, t3, t4, t5, t6, t7, t8)); } }; return new Property8<>(name, a1, a2, a3, a4, a5, a6, a7, a8, implication); } @Override public CheckResult check(Random random, int size, int tries) { Objects.requireNonNull(random, "random is null"); if (tries < 0) { throw new IllegalArgumentException("tries < 0"); } final long startTime = System.currentTimeMillis(); try { final Gen<T1> gen1 = Try.of(() -> a1.apply(size)).recover(x -> { throw arbitraryError(1, size, x); }).get(); final Gen<T2> gen2 = Try.of(() -> a2.apply(size)).recover(x -> { throw arbitraryError(2, size, x); }).get(); final Gen<T3> gen3 = Try.of(() -> a3.apply(size)).recover(x -> { throw arbitraryError(3, size, x); }).get(); final Gen<T4> gen4 = Try.of(() -> a4.apply(size)).recover(x -> { throw arbitraryError(4, size, x); }).get(); final Gen<T5> gen5 = Try.of(() -> a5.apply(size)).recover(x -> { throw arbitraryError(5, size, x); }).get(); final Gen<T6> gen6 = Try.of(() -> a6.apply(size)).recover(x -> { throw arbitraryError(6, size, x); }).get(); final Gen<T7> gen7 = Try.of(() -> a7.apply(size)).recover(x -> { throw arbitraryError(7, size, x); }).get(); final Gen<T8> gen8 = Try.of(() -> a8.apply(size)).recover(x -> { throw arbitraryError(8, size, x); }).get(); boolean exhausted = true; for (int i = 1; i <= tries; i++) { try { final T1 val1 = Try.of(() -> gen1.apply(random)).recover(x -> { throw genError(1, size, x); }).get(); final T2 val2 = Try.of(() -> gen2.apply(random)).recover(x -> { throw genError(2, size, x); }).get(); final T3 val3 = Try.of(() -> gen3.apply(random)).recover(x -> { throw genError(3, size, x); }).get(); final T4 val4 = Try.of(() -> gen4.apply(random)).recover(x -> { throw genError(4, size, x); }).get(); final T5 val5 = Try.of(() -> gen5.apply(random)).recover(x -> { throw genError(5, size, x); }).get(); final T6 val6 = Try.of(() -> gen6.apply(random)).recover(x -> { throw genError(6, size, x); }).get(); final T7 val7 = Try.of(() -> gen7.apply(random)).recover(x -> { throw genError(7, size, x); }).get(); final T8 val8 = Try.of(() -> gen8.apply(random)).recover(x -> { throw genError(8, size, x); }).get(); try { final Condition condition = Try.of(() -> predicate.apply(val1, val2, val3, val4, val5, val6, val7, val8)).recover(x -> { throw predicateError(x); }).get(); if (condition.precondition) { exhausted = false; if (!condition.postcondition) { logFalsified(name, i, System.currentTimeMillis() - startTime); return new CheckResult.Falsified(name, i, Tuple.of(val1, val2, val3, val4, val5, val6, val7, val8)); } } } catch(CheckError err) { logErroneous(name, i, System.currentTimeMillis() - startTime, err.getMessage()); return new CheckResult.Erroneous(name, i, err, Option.some(Tuple.of(val1, val2, val3, val4, val5, val6, val7, val8))); } } catch(CheckError err) { logErroneous(name, i, System.currentTimeMillis() - startTime, err.getMessage()); return new CheckResult.Erroneous(name, i, err, Option.none()); } } logSatisfied(name, tries, System.currentTimeMillis() - startTime, exhausted); return new CheckResult.Satisfied(name, tries, exhausted); } catch(CheckError err) { logErroneous(name, 0, System.currentTimeMillis() - startTime, err.getMessage()); return new CheckResult.Erroneous(name, 0, err, Option.none()); } } } /** * Internally used to model conditions composed of pre- and post-condition. */ static class Condition { static final Condition EX_FALSO_QUODLIBET = new Condition(false, true); final boolean precondition; final boolean postcondition; Condition(boolean precondition, boolean postcondition) { this.precondition = precondition; this.postcondition = postcondition; } // ¬(p => q) ≡ ¬(¬p ∨ q) ≡ p ∧ ¬q boolean isFalse() { return precondition && !postcondition; } } /** * Internally used to provide more specific error messages. */ static class CheckError extends Error { private static final long serialVersionUID = 1L; CheckError(String message, Throwable cause) { super(message, cause); } } }