Skip to content

Commit 22f9d67

Browse files
nomicfluxjnape
authored andcommitted
Added StateT and State matchers
1 parent 80ff4db commit 22f9d67

File tree

5 files changed

+331
-48
lines changed

5 files changed

+331
-48
lines changed
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
package com.jnape.palatable.lambda.matchers;
2+
3+
import com.jnape.palatable.lambda.adt.Either;
4+
import org.junit.Test;
5+
6+
import static com.jnape.palatable.lambda.adt.Either.left;
7+
import static com.jnape.palatable.lambda.functor.builtin.State.state;
8+
import static org.hamcrest.MatcherAssert.assertThat;
9+
import static org.hamcrest.core.IsEqual.equalTo;
10+
import static testsupport.matchers.LeftMatcher.isLeftThat;
11+
import static testsupport.matchers.RightMatcher.isRightThat;
12+
import static testsupport.matchers.StateMatcher.*;
13+
14+
public class StateMatcherTest {
15+
16+
@Test
17+
public void whenEvalWithMatcher() {
18+
assertThat(state(Either.right(1)),
19+
whenEvaluatedWith("0", isRightThat(equalTo(1))));
20+
}
21+
22+
@Test
23+
public void whenExecWithMatcher() {
24+
assertThat(state(Either.right(1)),
25+
whenExecutedWith(left("0"), isLeftThat(equalTo("0"))));
26+
}
27+
28+
@Test
29+
public void whenRunWithMatcher() {
30+
assertThat(state(Either.right(1)),
31+
whenRunWith(left("0"), isRightThat(equalTo(1)), isLeftThat(equalTo("0"))));
32+
}
33+
34+
}
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
package com.jnape.palatable.lambda.matchers;
2+
3+
import com.jnape.palatable.lambda.adt.Either;
4+
import com.jnape.palatable.lambda.monad.transformer.builtin.StateT;
5+
import org.junit.Test;
6+
import testsupport.matchers.StateTMatcher;
7+
8+
import java.util.concurrent.atomic.AtomicInteger;
9+
10+
import static com.jnape.palatable.lambda.adt.Either.left;
11+
import static com.jnape.palatable.lambda.adt.hlist.HList.tuple;
12+
import static com.jnape.palatable.lambda.io.IO.io;
13+
import static com.jnape.palatable.lambda.monad.transformer.builtin.StateT.stateT;
14+
import static org.hamcrest.MatcherAssert.assertThat;
15+
import static org.hamcrest.core.IsEqual.equalTo;
16+
import static org.junit.Assert.assertEquals;
17+
import static testsupport.matchers.IOMatcher.yieldsValue;
18+
import static testsupport.matchers.LeftMatcher.isLeftThat;
19+
import static testsupport.matchers.RightMatcher.isRightThat;
20+
import static testsupport.matchers.StateTMatcher.*;
21+
22+
public class StateTMatcherTest {
23+
24+
@Test
25+
public void whenEvalWithMatcher() {
26+
assertThat(stateT(Either.right(1)),
27+
StateTMatcher.whenEvaluatedWith("0", isRightThat(equalTo(1))));
28+
}
29+
30+
@Test
31+
public void whenExecWithMatcher() {
32+
assertThat(stateT(Either.right(1)),
33+
whenExecutedWith(left("0"), isRightThat(isLeftThat(equalTo("0")))));
34+
}
35+
36+
@Test
37+
public void whenRunWithUsingTwoMatchers() {
38+
assertThat(stateT(Either.right(1)),
39+
whenRunWith(left("0"), isRightThat(equalTo(1)), isRightThat(isLeftThat(equalTo("0")))));
40+
}
41+
42+
@Test
43+
public void whenRunWithUsingOneTupleMatcher() {
44+
assertThat(stateT(Either.right(1)),
45+
whenRunWith(left("0"), isRightThat(equalTo(tuple(1, left("0"))))));
46+
}
47+
48+
@Test
49+
public void onlyRunsStateOnceWithTupleMatcher() {
50+
AtomicInteger count = new AtomicInteger(0);
51+
52+
assertThat(StateT.gets(s -> io(count::incrementAndGet)),
53+
whenRunWith(0, yieldsValue(equalTo(tuple(1, 0)))));
54+
assertEquals(1, count.get());
55+
}
56+
}
Lines changed: 37 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,13 @@
11
package com.jnape.palatable.lambda.monad.transformer.builtin;
22

3-
import com.jnape.palatable.lambda.adt.Maybe;
43
import com.jnape.palatable.lambda.adt.Unit;
54
import com.jnape.palatable.lambda.adt.hlist.Tuple2;
65
import com.jnape.palatable.lambda.functor.builtin.Identity;
76
import com.jnape.palatable.traitor.annotations.TestTraits;
87
import com.jnape.palatable.traitor.runners.Traits;
98
import org.junit.Test;
109
import org.junit.runner.RunWith;
11-
import testsupport.traits.ApplicativeLaws;
12-
import testsupport.traits.Equivalence;
13-
import testsupport.traits.FunctorLaws;
14-
import testsupport.traits.MonadLaws;
15-
import testsupport.traits.MonadReaderLaws;
16-
import testsupport.traits.MonadRecLaws;
17-
import testsupport.traits.MonadWriterLaws;
10+
import testsupport.traits.*;
1811

1912
import java.util.ArrayList;
2013
import java.util.List;
@@ -26,18 +19,19 @@
2619
import static com.jnape.palatable.lambda.optics.functions.Set.set;
2720
import static com.jnape.palatable.lambda.optics.lenses.ListLens.elementAt;
2821
import static java.util.Arrays.asList;
29-
import static org.junit.Assert.assertEquals;
22+
import static org.hamcrest.MatcherAssert.assertThat;
23+
import static testsupport.matchers.StateTMatcher.*;
3024
import static testsupport.traits.Equivalence.equivalence;
3125

3226
@RunWith(Traits.class)
3327
public class StateTTest {
3428

3529
@TestTraits({FunctorLaws.class,
36-
ApplicativeLaws.class,
37-
MonadLaws.class,
38-
MonadRecLaws.class,
39-
MonadReaderLaws.class,
40-
MonadWriterLaws.class})
30+
ApplicativeLaws.class,
31+
MonadLaws.class,
32+
MonadRecLaws.class,
33+
MonadReaderLaws.class,
34+
MonadWriterLaws.class})
4135
public Equivalence<StateT<String, Identity<?>, Integer>> testReader() {
4236
return equivalence(StateT.gets(s -> new Identity<>(s.length())), s -> s.runStateT("foo"));
4337
}
@@ -47,85 +41,80 @@ public void evalAndExec() {
4741
StateT<String, Identity<?>, Integer> stateT =
4842
StateT.stateT(str -> new Identity<>(tuple(str.length(), str + "_")));
4943

50-
assertEquals(new Identity<>("__"), stateT.execT("_"));
51-
assertEquals(new Identity<>(1), stateT.evalT("_"));
44+
assertThat(stateT, whenExecuted("_", new Identity<>("__")));
45+
assertThat(stateT, whenEvaluated("_", new Identity<>(1)));
5246
}
5347

5448
@Test
5549
public void mapStateT() {
5650
StateT<String, Identity<?>, Integer> stateT =
5751
StateT.stateT(str -> new Identity<>(tuple(str.length(), str + "_")));
58-
assertEquals(just(tuple(4, "ABC_")),
59-
stateT.mapStateT(id -> id.<Identity<Tuple2<Integer, String>>>coerce()
60-
.runIdentity()
61-
.into((x, str) -> just(tuple(x + 1, str.toUpperCase()))))
62-
.<Maybe<Tuple2<Integer, String>>>runStateT("abc"));
52+
53+
assertThat(stateT.mapStateT(id -> id.<Identity<Tuple2<Integer, String>>>coerce()
54+
.runIdentity()
55+
.into((x, str) -> just(tuple(x + 1, str.toUpperCase())))),
56+
whenRun("abc", just(tuple(4, "ABC_"))));
6357
}
6458

6559
@Test
6660
public void zipping() {
67-
Tuple2<Unit, List<String>> result = StateT.<List<String>, Identity<?>>modify(
61+
StateT<List<String>, Identity<?>, Unit> result = StateT.<List<String>, Identity<?>>modify(
6862
s -> new Identity<>(set(elementAt(s.size()), just("one"), s)))
69-
.discardL(StateT.modify(s -> new Identity<>(set(elementAt(s.size()), just("two"), s))))
70-
.<Identity<Tuple2<Unit, List<String>>>>runStateT(new ArrayList<>())
71-
.runIdentity();
63+
.discardL(StateT.modify(s -> new Identity<>(set(elementAt(s.size()), just("two"), s))));
7264

73-
assertEquals(tuple(UNIT, asList("one", "two")),
74-
result);
65+
assertThat(result,
66+
whenRun(new ArrayList<>(), new Identity<>(tuple(UNIT, asList("one", "two")))));
7567
}
7668

7769
@Test
7870
public void withStateT() {
7971
StateT<String, Identity<?>, Integer> stateT =
8072
StateT.stateT(str -> new Identity<>(tuple(str.length(), str + "_")));
81-
assertEquals(new Identity<>(tuple(3, "ABC_")),
82-
stateT.withStateT(str -> new Identity<>(str.toUpperCase())).runStateT("abc"));
73+
assertThat(stateT.withStateT(str -> new Identity<>(str.toUpperCase())),
74+
whenRun("abc", new Identity<>(tuple(3, "ABC_"))));
8375
}
8476

8577
@Test
8678
public void get() {
87-
assertEquals(new Identity<>(tuple("state", "state")),
88-
StateT.<String, Identity<?>>get(pureIdentity()).runStateT("state"));
79+
assertThat(StateT.get(pureIdentity()),
80+
whenRun("state", new Identity<>(tuple("state", "state"))));
8981
}
9082

9183
@Test
9284
public void gets() {
93-
assertEquals(new Identity<>(tuple(5, "state")),
94-
StateT.<String, Identity<?>, Integer>gets(s -> new Identity<>(s.length())).runStateT("state"));
85+
assertThat(StateT.gets(s -> new Identity<>(s.length())),
86+
whenRun("state", new Identity<>(tuple(5, "state"))));
9587
}
9688

9789
@Test
9890
public void put() {
99-
assertEquals(new Identity<>(tuple(UNIT, 1)), StateT.put(new Identity<>(1)).runStateT(0));
91+
assertThat(StateT.put(new Identity<>(1)),
92+
whenRun(0, new Identity<>(tuple(UNIT, 1))));
10093
}
10194

10295
@Test
10396
public void modify() {
104-
assertEquals(new Identity<>(tuple(UNIT, 1)),
105-
StateT.<Integer, Identity<?>>modify(x -> new Identity<>(x + 1)).runStateT(0));
97+
assertThat(StateT.modify(x -> new Identity<>(x + 1)),
98+
whenRun(0, new Identity<>(tuple(UNIT, 1))));
10699
}
107100

108101
@Test
109102
public void stateT() {
110-
assertEquals(new Identity<>(tuple(0, "_")),
111-
StateT.<String, Identity<?>, Integer>stateT(new Identity<>(0)).runStateT("_"));
112-
assertEquals(new Identity<>(tuple(1, "_1")),
113-
StateT.<String, Identity<?>, Integer>stateT(s -> new Identity<>(tuple(s.length(), s + "1")))
114-
.runStateT("_"));
103+
assertThat(StateT.stateT(new Identity<>(0)),
104+
whenRun("_", new Identity<>(tuple(0, "_"))));
105+
assertThat(StateT.stateT(s -> new Identity<>(tuple(s.length(), s + "1"))),
106+
whenRun("_", new Identity<>(tuple(1, "_1"))));
115107
}
116108

117109
@Test
118110
public void staticPure() {
119-
assertEquals(new Identity<>(tuple(1, "foo")),
120-
StateT.<String, Identity<?>>pureStateT(pureIdentity())
121-
.<Integer, StateT<String, Identity<?>, Integer>>apply(1)
122-
.<Identity<Tuple2<Integer, String>>>runStateT("foo"));
111+
assertThat(StateT.<String, Identity<?>>pureStateT(pureIdentity()).apply(1),
112+
whenRun("foo", new Identity<>(tuple(1, "foo"))));
123113
}
124114

125115
@Test
126116
public void staticLift() {
127-
assertEquals(new Identity<>(tuple(1, "foo")),
128-
StateT.<String>liftStateT().<Integer, Identity<?>, StateT<String, Identity<?>, Integer>>apply(new Identity<>(1))
129-
.<Identity<Tuple2<Integer, String>>>runStateT("foo"));
117+
assertThat(StateT.<String>liftStateT().apply(new Identity<>(1)),
118+
whenRun("foo", new Identity<>(tuple(1, "foo"))));
130119
}
131120
}
Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
package testsupport.matchers;
2+
3+
import com.jnape.palatable.lambda.adt.These;
4+
import com.jnape.palatable.lambda.adt.hlist.Tuple2;
5+
import com.jnape.palatable.lambda.functor.builtin.State;
6+
import org.hamcrest.Description;
7+
import org.hamcrest.Matcher;
8+
import org.hamcrest.TypeSafeMatcher;
9+
10+
import static com.jnape.palatable.lambda.adt.These.*;
11+
import static com.jnape.palatable.lambda.io.IO.io;
12+
import static org.hamcrest.Matchers.equalTo;
13+
14+
public class StateMatcher<S, A> extends TypeSafeMatcher<State<S, A>> {
15+
private final S initialState;
16+
private final These<Matcher<? super A>, Matcher<? super S>> matchers;
17+
18+
private StateMatcher(S initialState, These<Matcher<? super A>, Matcher<? super S>> matchers) {
19+
this.initialState = initialState;
20+
this.matchers = matchers;
21+
}
22+
23+
@Override
24+
protected boolean matchesSafely(State<S, A> item) {
25+
Tuple2<A, S> ran = item.run(initialState);
26+
return matchers.match(a -> a.matches(ran._1()),
27+
b -> b.matches(ran._2()),
28+
ab -> ab._1().matches(ran._1()) && ab._2().matches(ran._2()));
29+
}
30+
31+
@Override
32+
public void describeTo(Description description) {
33+
matchers.match(a -> io(() -> a.describeTo(description.appendText("Value matching "))),
34+
b -> io(() -> b.describeTo(description.appendText("State matching "))),
35+
ab -> io(() -> {
36+
description.appendText("Value matching: ");
37+
ab._1().describeTo(description);
38+
description.appendText(" and state matching: ");
39+
ab._2().describeTo(description);
40+
}))
41+
.unsafePerformIO();
42+
}
43+
44+
@Override
45+
protected void describeMismatchSafely(State<S, A> item, Description mismatchDescription) {
46+
Tuple2<A, S> ran = item.run(initialState);
47+
matchers.match(a -> io(() -> {
48+
mismatchDescription.appendText("value matching ");
49+
a.describeMismatch(ran._1(), mismatchDescription);
50+
}),
51+
b -> io(() -> {
52+
mismatchDescription.appendText("state matching ");
53+
b.describeMismatch(ran._2(), mismatchDescription);
54+
}),
55+
ab -> io(() -> {
56+
mismatchDescription.appendText("value matching: ");
57+
ab._1().describeMismatch(ran._1(), mismatchDescription);
58+
mismatchDescription.appendText(" and state matching: ");
59+
ab._2().describeMismatch(ran._2(), mismatchDescription);
60+
}))
61+
.unsafePerformIO();
62+
}
63+
64+
public static <S, A> StateMatcher<S, A> whenRunWith(S initialState, Matcher<? super A> valueMatcher, Matcher<? super S> stateMatcher) {
65+
return new StateMatcher<>(initialState, both(valueMatcher, stateMatcher));
66+
}
67+
68+
@SuppressWarnings("unused")
69+
public static <S, A> StateMatcher<S, A> whenRun(S initialState, A value, S state) {
70+
return whenRunWith(initialState, equalTo(value), equalTo(state));
71+
}
72+
73+
public static <S, A> StateMatcher<S, A> whenExecutedWith(S initialState, Matcher<? super S> stateMatcher) {
74+
return new StateMatcher<>(initialState, b(stateMatcher));
75+
}
76+
77+
@SuppressWarnings("unused")
78+
public static <S, A> StateMatcher<S, A> whenExecuted(S initialState, S state) {
79+
return whenExecutedWith(initialState, equalTo(state));
80+
}
81+
82+
public static <S, A> StateMatcher<S, A> whenEvaluatedWith(S initialState, Matcher<? super A> valueMatcher) {
83+
return new StateMatcher<>(initialState, a(valueMatcher));
84+
}
85+
86+
@SuppressWarnings("unused")
87+
public static <S, A> StateMatcher<S, A> whenEvaluated(S initialState, A value) {
88+
return whenEvaluatedWith(initialState, equalTo(value));
89+
}
90+
}

0 commit comments

Comments
 (0)