1 package io.atlassian.fugue.hamcrest;
2
3 import io.atlassian.fugue.Either;
4 import org.hamcrest.Description;
5 import org.hamcrest.Matcher;
6 import org.hamcrest.TypeSafeMatcher;
7
8 import static io.atlassian.fugue.Unit.Unit;
9 import static java.util.Objects.requireNonNull;
10
11 public final class EitherMatchers {
12
13 private EitherMatchers() {
14 throw new UnsupportedOperationException();
15 }
16
17 public static <L> Matcher<Either<L, ?>> isLeft(Matcher<? super L> subMatcher) {
18 return new LeftMatcher<>(requireNonNull(subMatcher, "subMatcher"));
19 }
20
21 public static <R> Matcher<Either<?, R>> isRight(Matcher<? super R> subMatcher) {
22 return new RightMatcher<>(requireNonNull(subMatcher, "subMatcher"));
23 }
24
25 private static class LeftMatcher<L> extends TypeSafeMatcher<Either<L, ?>> {
26
27 private final Matcher<? super L> subMatcher;
28
29 private LeftMatcher(Matcher<? super L> subMatcher) {
30 this.subMatcher = subMatcher;
31 }
32
33 @Override protected boolean matchesSafely(Either<L, ?> actual) {
34 return actual.left().exists(subMatcher::matches);
35 }
36
37 @Override public void describeTo(Description description) {
38 description.appendText("left that ");
39 subMatcher.describeTo(description);
40 }
41
42 @Override protected void describeMismatchSafely(Either<L, ?> actual, Description mismatchDescription) {
43 actual.fold(left -> {
44 mismatchDescription.appendText("was left that ");
45 subMatcher.describeMismatch(left, mismatchDescription);
46 return Unit();
47 }, right -> {
48 mismatchDescription.appendText("was right");
49 return Unit();
50 });
51 }
52 }
53
54 private static class RightMatcher<R> extends TypeSafeMatcher<Either<?, R>> {
55
56 private final Matcher<? super R> subMatcher;
57
58 private RightMatcher(Matcher<? super R> subMatcher) {
59 this.subMatcher = subMatcher;
60 }
61
62 @Override protected boolean matchesSafely(Either<?, R> actual) {
63 return actual.right().exists(subMatcher::matches);
64 }
65
66 @Override public void describeTo(Description description) {
67 description.appendText("right that ");
68 subMatcher.describeTo(description);
69 }
70
71 @Override protected void describeMismatchSafely(Either<?, R> actual, Description mismatchDescription) {
72 actual.fold(left -> {
73 mismatchDescription.appendText("was left");
74 return Unit();
75 }, right -> {
76 mismatchDescription.appendText("was right that ");
77 subMatcher.describeMismatch(right, mismatchDescription);
78 return Unit();
79 });
80 }
81 }
82 }