forked from palatable/lambda
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathLensAssert.java
More file actions
53 lines (47 loc) · 2.88 KB
/
LensAssert.java
File metadata and controls
53 lines (47 loc) · 2.88 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
package testsupport.assertion;
import com.jnape.palatable.lambda.adt.Maybe;
import com.jnape.palatable.lambda.adt.hlist.Tuple2;
import com.jnape.palatable.lambda.functions.Fn1;
import com.jnape.palatable.lambda.functions.Fn2;
import com.jnape.palatable.lambda.functions.builtin.fn2.Map;
import com.jnape.palatable.lambda.functor.Functor;
import com.jnape.palatable.lambda.io.IO;
import com.jnape.palatable.lambda.monoid.builtin.Present;
import com.jnape.palatable.lambda.optics.Optic;
import java.util.Objects;
import static com.jnape.palatable.lambda.adt.Maybe.just;
import static com.jnape.palatable.lambda.adt.Maybe.nothing;
import static com.jnape.palatable.lambda.functions.builtin.fn1.CatMaybes.catMaybes;
import static com.jnape.palatable.lambda.functions.builtin.fn2.CartesianProduct.cartesianProduct;
import static com.jnape.palatable.lambda.functions.builtin.fn2.Into.into;
import static com.jnape.palatable.lambda.functions.builtin.fn2.ReduceLeft.reduceLeft;
import static com.jnape.palatable.lambda.optics.functions.Set.set;
import static com.jnape.palatable.lambda.optics.functions.View.view;
import static java.lang.String.format;
import static java.lang.String.join;
import static java.util.Arrays.asList;
public final class LensAssert {
public static <S, A> void assertLensLawfulness(Optic<? super Fn1<?, ?>, Functor<?, ?>, S, S, A, A> lens,
Iterable<S> ss,
Iterable<A> bs) {
Iterable<Tuple2<S, A>> cases = cartesianProduct(ss, bs);
Present.<String>present((x, y) -> join("\n\n", x, y))
.reduceLeft(asList(falsify("You get back what you put in", (s, b) -> view(lens, set(lens, b, s)), (s, b) -> b, cases),
falsify("Putting back what you got changes nothing", (s, b) -> set(lens, view(lens, s), s), (s, b) -> s, cases),
falsify("Setting twice is equivalent to setting once", (s, b) -> set(lens, b, set(lens, b, s)), (s, b) -> set(lens, b, s), cases)))
.match(IO::io, failures -> IO.throwing(new AssertionError("Lens law failures\n\n" + failures)))
.unsafePerformIO();
}
private static <S, A, X> Maybe<String> falsify(String label, Fn2<S, A, X> l, Fn2<S, A, X> r,
Iterable<Tuple2<S, A>> cases) {
return Map.<Tuple2<S, A>, Maybe<String>>map(into((s, b) -> {
X x = l.apply(s, b);
X y = r.apply(s, b);
return Objects.equals(x, y) ? nothing() : just(format("S <%s>, B <%s> (%s != %s)", s, b, x, y));
}))
.fmap(catMaybes())
.fmap(reduceLeft((x, y) -> x + "\n\t - " + y))
.fmap(maybeFailures -> maybeFailures.fmap(failures -> "\"" + label + "\" failed for the following cases:\n\n\t - " + failures))
.apply(cases);
}
}