package scotch.test;
import static java.util.Arrays.asList;
import static scotch.data.unit.Unit.unit;
import static scotch.runtime.RuntimeSupport.applicable;
import static scotch.runtime.RuntimeSupport.box;
import static scotch.runtime.RuntimeSupport.flatCallable;
import static scotch.symbol.type.TypeDescriptors.fn;
import static scotch.symbol.type.TypeDescriptors.var;
import static scotch.test.ExpectationResult.failedExpectation;
import static scotch.test.ExpectationResult.successfulExpectation;
import java.util.function.Supplier;
import scotch.data.eq.Eq;
import scotch.data.string.String_;
import scotch.data.unit.Unit;
import scotch.runtime.Applicable;
import scotch.runtime.Callable;
import scotch.runtime.RaisedException;
import scotch.symbol.Value;
import scotch.symbol.ValueType;
import scotch.symbol.type.TypeDescriptor;
import scotch.symbol.type.VariableTypeDescriptor;
import scotch.test.ExpectationResult.FailedExpectation;
import scotch.test.ExpectationResult.SuccessfulExpectation;
import scotch.text.show.Show;
@SuppressWarnings("unused")
public class Expectations {
@Value(memberName = "expect")
public static <A> Applicable<A, Applicable<Applicable<A, Applicable<A, ExpectationResult>>, Applicable<A, Unit>>> expect() {
return applicable(
test -> applicable(
tester -> applicable(
expectation -> flatCallable(
() -> tester
.call().apply(test)
.call().apply(expectation)
.call().accept(new ExpectationResult.Visitor<Unit>() {
@Override
public Callable<Unit> visit(SuccessfulExpectation successfulExpectation) {
return unit();
}
@Override
public Callable<Unit> visit(FailedExpectation failedExpectation) {
throw new RaisedException(failedExpectation.getMessage().call());
}
})))));
}
@ValueType(forMember = "expect")
public static TypeDescriptor expect$type() {
return fn(var("a"), fn(fn(var("a"), fn(var("b"), ExpectationResult.TYPE)), fn(var("b"), Unit.TYPE)));
}
@SuppressWarnings("unchecked")
@Value(memberName = "toBe")
public static <A> Applicable<Eq<A>, Applicable<Show<A>, Applicable<A, Applicable<A, ExpectationResult>>>> toBe() {
return applicable(eq -> applicable(show -> applicable(test -> applicable(expectation -> flatCallable((Supplier) () -> {
if (eq.call().eq(test, expectation).call()) {
return successfulExpectation();
} else {
return failedExpectation().apply(box("Failed expectation: wanted <" + show.call().show(expectation) + "> but got <" + show.call().show(test) + ">"));
}
})))));
}
@ValueType(forMember = "toBe")
public static TypeDescriptor toBe$type() {
VariableTypeDescriptor a = var("a", asList("scotch.data.eq.Eq", "scotch.text.show.Show"));
return fn(a, fn(a, ExpectationResult.TYPE));
}
@SuppressWarnings("unchecked")
@Value(memberName = "toRaise")
public static <A> Applicable<A, Applicable<String, ExpectationResult>> toRaise() {
return applicable(test -> applicable(expectation -> flatCallable((Supplier) () -> {
try {
test.call();
} catch (RaisedException exception) {
if (expectation.call().equals(exception.getMessage())) {
return successfulExpectation();
} else {
return failedExpectation().apply(box("Expected raised exception with message <" + expectation + "> but got <" + exception.getMessage() + ">"));
}
}
return failedExpectation().apply(box("Expected raised exception with message <" + expectation + ">"));
})));
}
@ValueType(forMember = "toRaise")
public static TypeDescriptor toRaise$type() {
return fn(var("a"), fn(String_.TYPE, ExpectationResult.TYPE));
}
}