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)); } }