package fj.demo.test; import static fj.Bottom.error; import fj.P2; import fj.data.List; import static fj.data.List.list; import static fj.Equal.stringBuilderEqual; import static fj.test.Arbitrary.arbCharacter; import static fj.test.Arbitrary.arbInteger; import static fj.test.Arbitrary.arbIntegerBoundaries; import static fj.test.Arbitrary.arbStringBuilder; import static fj.test.Bool.bool; import fj.function.Effect1; import fj.test.CheckResult; import static fj.test.CheckResult.summary; import fj.test.Property; import static fj.test.Property.prop; import static fj.test.Property.property; import static fj.test.Shrink.shrinkInteger; import fj.test.reflect.Category; import static fj.test.reflect.Check.check; import fj.test.reflect.CheckParams; import fj.test.reflect.Name; import fj.test.reflect.NoCheck; import static java.lang.System.out; /* Performs four test runs of these properties using various test parameters and categories. A test property is any of the following: - a static field of type reductio.Property. - a static no-argument method that returns reductio.Property. - a non-static field of type reductio.Property in a class with a no-argument constructor. - a non-static no-argument method that returns reductio.Property in a class with a no-argument constructor. Any property annotated with reductio.reflect.NoCheck will not be checked. A property's categories are the union of the reduction.reflect.Category values of the enclosing class and itself. Default check parameters can be overridden with the reduction.reflect.CheckParams annotation. A property can have a name associated with it, that is first taken from its reductio.reflect.Name annotation and if it doesn't exist, then the same annotation on the enclosing class. */ @SuppressWarnings({"PackageVisibleField", "MethodMayBeStatic"}) @CheckParams(minSuccessful = 500) @Category("reductio.reflect demo") public final class Reflect { @Name("Integer Addition Commutes") @Category("Passes for demo") @CheckParams(minSuccessful = 20) final Property p1 = property(arbInteger, arbInteger, (a, b) -> prop(a + b == b + a)); @Name("Natural Integer Addition yields Natural Integer") @Category("Fails for demo") final Property p2 = property(arbIntegerBoundaries, arbIntegerBoundaries, shrinkInteger, shrinkInteger, (a, b) -> bool(a > 0 && b > 0).implies(a + b > 0)); @Category("Passes for demo") final Property p3 = property(arbStringBuilder, sb -> prop(stringBuilderEqual.eq(sb, sb.reverse().reverse()))); @Category("Passes for demo") final Property p4 = property(arbCharacter, c -> prop(stringBuilderEqual.eq(new StringBuilder().append(c), new StringBuilder().append(c).reverse()))); @Category("Passes for demo") @CheckParams(minSuccessful = 750, maxSize = 40) final Property p5 = property(arbStringBuilder, arbStringBuilder, (x, y) -> { // copy the string builders before performing updates on x and y. final StringBuilder xx = new StringBuilder(x); final StringBuilder yy = new StringBuilder(y); return prop(stringBuilderEqual.eq(x.append(y).reverse(), yy.reverse().append(xx.reverse()))); }); @Name("Triangulation") @Category("Fails for demo") final Property p6 = property(arbInteger, a -> prop(Triangulation.isPositive(a) == (a != 0 && !Triangulation.isNegative(a)))); @NoCheck Property leave() { throw error("this should not be executed"); } @SuppressWarnings("UnusedDeclaration") Property leave(final int i) { throw error("this should not be executed"); } /* OK, passed 20 tests. (Integer Addition Commutes) Falsified after 22 passed tests with arguments: [2147483646,13] (Natural Integer Addition yields Natural Integer) OK, passed 500 tests. (p3) OK, passed 500 tests. (p4) OK, passed 750 tests. (p5) Falsified after 0 passed tests with argument: 0 (Triangulation) -------------------------------------------------------------------------------- OK, passed 20 tests. (Integer Addition Commutes) OK, passed 500 tests. (p3) OK, passed 500 tests. (p4) OK, passed 750 tests. (p5) -------------------------------------------------------------------------------- Falsified after 0 passed tests with arguments: [2,2147483646] (Natural Integer Addition yields Natural Integer) Falsified after 0 passed tests with argument: 0 (Triangulation) -------------------------------------------------------------------------------- OK, passed 20 tests. (Integer Addition Commutes) Falsified after 0 passed tests with arguments: [2147483647,1] (Natural Integer Addition yields Natural Integer) OK, passed 500 tests. (p3) OK, passed 500 tests. (p4) OK, passed 750 tests. (p5) Falsified after 0 passed tests with arguments: 0 (Triangulation) -------------------------------------------------------------------------------- */ @SuppressWarnings("unchecked") public static void main(final String[] args) { printResults(check(list(Reflect.class))); // execute only those in the given category printResults(check(list(Reflect.class), "Passes for demo")); printResults(check(list(Reflect.class), "Fails for demo")); printResults(check(list(Reflect.class), "reductio.reflect demo")); } private static void printResults(final List<P2<String,CheckResult>> results) { results.foreachDoEffect(result -> { summary.print(result._2()); out.println(" (" + result._1() + ')'); }); out.println("--------------------------------------------------------------------------------"); } }