package fj.test;
import static fj.Bottom.decons;
import fj.F;
import fj.Show;
import fj.data.List;
import fj.data.Option;
import fj.function.Strings;
import static fj.data.Option.some;
import static fj.Show.listShow;
import static fj.Show.showS;
import static fj.test.Arg.argShow;
import java.io.StringWriter;
import java.io.PrintWriter;
/**
* An enumeration of the possible results after checking a property. A <code>CheckResult</code> may
* be in one of six states:
* <ol>
* <li>Passed</li>
* <li>Proven</li>
* <li>Falsified</li>
* <li>Exhausted</li>
* <li>Exception executing the property</li>
* <li>Exception generating values to check the property</li>
* </ol>
*
* @version %build.number%
*/
public final class CheckResult {
private final R r;
private final Option<List<Arg<?>>> args;
private final Option<Throwable> ex;
private final int succeeded;
private final int discarded;
private enum R {
Passed, Proven, Falsified, Exhausted, PropException, GenException
}
private CheckResult(final R r, final Option<List<Arg<?>>> args, final Option<Throwable> ex, final int succeeded,
final int discarded) {
this.r = r;
this.args = args;
this.ex = ex;
this.succeeded = succeeded;
this.discarded = discarded;
}
/**
* Returns a result that the property has passed.
*
* @param succeeded The number of checks that succeeded.
* @param discarded The number of checks that were discarded.
* @return A result that the property has passed.
*/
public static CheckResult passed(final int succeeded, final int discarded) {
return new CheckResult(R.Passed, Option.none(), Option.none(), succeeded, discarded);
}
/**
* Returns a result that the property has been proven.
*
* @param args The arguments used to prove the property.
* @param succeeded The number of checks that succeeded.
* @param discarded The number of checks that were discarded.
* @return A result that the property has been proven.
*/
public static CheckResult proven(final List<Arg<?>> args, final int succeeded, final int discarded) {
return new CheckResult(R.Proven, some(args), Option.none(), succeeded, discarded);
}
/**
* Returns a result that the property has been falsified.
*
* @param args The arguments used to falsify the property.
* @param succeeded The number of checks that succeeded.
* @param discarded The number of checks that were discarded.
* @return A result that the property has been falsified.
*/
public static CheckResult falsified(final List<Arg<?>> args, final int succeeded, final int discarded) {
return new CheckResult(R.Falsified, some(args), Option.none(), succeeded, discarded);
}
/**
* Returns a result that the property been exhausted in checking.
*
* @param succeeded The number of checks that succeeded.
* @param discarded The number of checks that were discarded.
* @return A result that the property has been exhausted in checking.
*/
public static CheckResult exhausted(final int succeeded, final int discarded) {
return new CheckResult(R.Exhausted, Option.none(), Option.none(), succeeded, discarded);
}
/**
* Returns a result that checking the property threw an exception.
*
* @param args The arguments used when the exception was thrown.
* @param ex The exception that was thrown.
* @param succeeded The number of checks that succeeded.
* @param discarded The number of checks that were discarded.
* @return A result that checking the property threw an exception.
*/
public static CheckResult propException(final List<Arg<?>> args, final Throwable ex, final int succeeded,
final int discarded) {
return new CheckResult(R.PropException, some(args), some(ex), succeeded, discarded);
}
/**
* Returns a result that generating values to check the property threw an exception.
*
* @param ex The exception that was thrown.
* @param succeeded The number of checks that succeeded.
* @param discarded The number of checks that were discarded.
* @return A result that generating values to check the property threw an exception.
*/
public static CheckResult genException(final Throwable ex, final int succeeded, final int discarded) {
return new CheckResult(R.GenException, Option.none(), some(ex), succeeded, discarded);
}
/**
* Returns <code>true</code> if this result is passed, <code>false</code> otherwise.
*
* @return <code>true</code> if this result is passed, <code>false</code> otherwise.
*/
public boolean isPassed() {
return r == R.Passed;
}
/**
* Returns <code>true</code> if this result is proven, <code>false</code> otherwise.
*
* @return <code>true</code> if this result is proven, <code>false</code> otherwise.
*/
public boolean isProven() {
return r == R.Proven;
}
/**
* Returns <code>true</code> if this result is falsified, <code>false</code> otherwise.
*
* @return <code>true</code> if this result is falsified, <code>false</code> otherwise.
*/
public boolean isFalsified() {
return r == R.Falsified;
}
/**
* Returns <code>true</code> if this result is exhausted, <code>false</code> otherwise.
*
* @return <code>true</code> if this result is exhausted, <code>false</code> otherwise.
*/
public boolean isExhausted() {
return r == R.Exhausted;
}
/**
* Returns <code>true</code> if this result is an exception during property execution,
* <code>false</code> otherwise.
*
* @return <code>true</code> if this result is an exception during property execution,
* <code>false</code> otherwise.
*/
public boolean isPropException() {
return r == R.PropException;
}
/**
* Returns <code>true</code> if this result is an exception during generating of values for
* property checking, <code>false</code> otherwise.
*
* @return <code>true</code> if this result is an exception during generating of values for
* property checking, <code>false</code> otherwise.
*/
public boolean isGenException() {
return r == R.GenException;
}
/**
* Returns the arguments if the result is one of; proven, falsified or exception during property
* execution, otherwise, no arguments are returned.
*
* @return The arguments if the result is one of; proven, falsified or exception during property
* execution, otherwise, no arguments are returned.
*/
public Option<List<Arg<?>>> args() {
return args;
}
/**
* Returns the execption if the result is one of; exception during property execution or exception
* during argument value generation, otherwise, no exception are returned.
*
* @return The execption if the result is one of; exception during property execution or exception
* during argument value generation, otherwise, no exception are returned.
*/
public Option<Throwable> exception() {
return ex;
}
/**
* Returns the number of succeeded checks of the property in this result.
*
* @return The number of succeeded checks of the property in this result.
*/
public int succeeded() {
return succeeded;
}
/**
* Returns the number of discarded checks of the property in this result.
*
* @return The number of discarded checks of the property in this result.
*/
public int discarded() {
return discarded;
}
/**
* A rendering of a check result that summarises in one line.
*
* @param sa The rendering of arguments.
* @return A rendering of a check result that summarises in one line.
*/
public static Show<CheckResult> summary(final Show<Arg<?>> sa) {
return showS(new F<CheckResult, String>() {
private String test(final CheckResult r) {
return r.succeeded() == 1 ? "test" : "tests";
}
private String arguments(final CheckResult r) {
final List<Arg<?>> args = r.args().some();
return args.length() == 1 ? "argument: " + sa.showS(args.head()) : "arguments: " + listShow(sa).showS(args);
}
@SuppressWarnings("ThrowableResultOfMethodCallIgnored")
public String f(final CheckResult r) {
if (r.isProven())
return "OK, property proven with " + arguments(r);
else if (r.isPassed())
return "OK, passed " + r.succeeded() + ' ' + test(r) +
(r.discarded() > 0 ? " (" + r.discarded() + " discarded)" : "") + '.';
else if (r.isFalsified())
return "Falsified after " + r.succeeded() + " passed " + test(r) + " with " + arguments(r);
else if (r.isExhausted())
return "Gave up after " + r.succeeded() + " passed " + test(r) + " and " + r.discarded() +
" discarded tests.";
else if (r.isPropException()) {
final StringWriter sw = new StringWriter();
final PrintWriter pw = new PrintWriter(sw);
r.exception().some().printStackTrace(pw);
return "Exception on property evaluation with " + arguments(r) + Strings.lineSeparator + sw;
} else if (r.isGenException()) {
final StringWriter sw = new StringWriter();
final PrintWriter pw = new PrintWriter(sw);
r.exception().some().printStackTrace(pw);
return "Exception on argument generation " + Strings.lineSeparator + sw;
} else
throw decons(r.getClass());
}
});
}
/**
* A rendering of a check result that summarises in one line.
*/
public static final Show<CheckResult> summary = summary(argShow);
/**
* A rendering of a check result that summarises in one line but throws an exception in the result
* is a failure (falsified, property exception or generator exception).
*/
public static final Show<CheckResult> summaryEx = summaryEx(argShow);
/**
* A rendering of a check result that summarises in one line but throws an exception in the result
* is a failure (falsified, property exception or generator exception).
*
* @param sa The rendering of arguments.
* @return A rendering of a check result that summarises in one line but throws an exception in
* the result is a failure (falsified, property exception or generator exception).
*/
public static Show<CheckResult> summaryEx(final Show<Arg<?>> sa) {
return showS(new F<CheckResult, String>() {
public String f(final CheckResult r) {
final String s = summary(sa).showS(r);
if (r.isProven() || r.isPassed() || r.isExhausted())
return s;
else if (r.isFalsified() || r.isPropException() || r.isGenException())
throw new Error(s);
else
throw decons(r.getClass());
}
});
}
}