1 package io.atlassian.fugue;
2
3 import org.junit.Test;
4
5 import java.io.IOException;
6 import java.util.Arrays;
7 import java.util.NoSuchElementException;
8 import java.util.Set;
9 import java.util.concurrent.atomic.AtomicInteger;
10 import java.util.function.Function;
11 import java.util.stream.IntStream;
12
13 import static io.atlassian.fugue.Functions.identity;
14 import static java.util.stream.Collectors.toList;
15 import static java.util.stream.Collectors.toSet;
16 import static org.hamcrest.CoreMatchers.instanceOf;
17 import static org.hamcrest.Matchers.contains;
18 import static org.hamcrest.core.Is.is;
19 import static org.junit.Assert.assertThat;
20
21 public class TryTest {
22
23 private static final Integer STARTING_VALUE = 1;
24 private static final String EXCEPTION_MESSAGE = "exception message";
25 private Try<Integer> successT = Checked.now(() -> STARTING_VALUE);
26 private Try<Integer> failT = Checked.now(() -> {
27 throw new IOException(EXCEPTION_MESSAGE);
28 });
29 private Function<Integer, Try<String>> f = n -> Checked.now(n::toString);
30 private Function<String, Try<String>> g = s -> Checked.now(s::toUpperCase);
31 private Function<Integer, Try<Integer>> unit = (Integer x) -> Checked.now(() -> x);
32
33 @Test public void leftIdentity() throws Throwable {
34 assertThat(unit.apply(STARTING_VALUE).flatMap(f), is(f.apply(STARTING_VALUE)));
35 }
36
37 @Test public void rightIdentity() {
38 assertThat(successT.flatMap(x -> unit.apply(x)), is(successT));
39 assertThat(failT.flatMap(x -> unit.apply(x)), is(failT));
40 }
41
42 @Test public void associativitySuccessCase() {
43 Try<String> lhs = successT.flatMap(f).flatMap(g);
44 Try<String> rhs = successT.flatMap(x -> f.apply(x).flatMap(g));
45
46 assertThat(lhs, is(rhs));
47 }
48
49 @Test public void associativityFailureCase() {
50 Try<String> lhs = failT.flatMap(f).flatMap(g);
51 Try<String> rhs = failT.flatMap(x -> f.apply(x).flatMap(g));
52
53 assertThat(lhs, is(rhs));
54 }
55
56 @Test public void sequenceReturnsFirstFailure() {
57 Try<String> failed1 = Checked.now(() -> {
58 throw new RuntimeException("FIRST");
59 });
60 Try<String> failed2 = Checked.now(() -> {
61 throw new RuntimeException("SECOND");
62 });
63 Try<String> failed3 = Checked.now(() -> {
64 throw new RuntimeException("THIRD");
65 });
66
67 Try<Iterable<String>> result = Try.sequence(Arrays.asList(failed1, failed2, failed3));
68
69 assertThat(result.isFailure(), is(true));
70
71 final Exception e = result.fold(identity(), x -> {
72 throw new NoSuchElementException();
73 });
74 assertThat(e, instanceOf(RuntimeException.class));
75 assertThat(e.getMessage(), is("FIRST"));
76 }
77
78 @Test public void sequenceReturnsValuesFromAllSuccesses() {
79 Try<Iterable<Integer>> result = Try.sequence(IntStream.range(0, 10).mapToObj(i -> Checked.now(() -> i))::iterator);
80
81 assertThat(result.isSuccess(), is(true));
82 Iterable<Integer> vals = result.fold(f -> {
83 throw new NoSuchElementException();
84 }, identity());
85 assertThat(vals, is(IntStream.range(0, 10).boxed().collect(toList())));
86 }
87
88 @Test public void delayedSequenceEvaluatesFirstFailure() {
89 AtomicInteger called = new AtomicInteger(0);
90 Try<String> failed1 = Checked.delay(() -> {
91 throw new RuntimeException("FIRST " + called.addAndGet(1));
92 });
93 Try<String> failed2 = Checked.delay(() -> {
94 throw new RuntimeException("SECOND " + called.addAndGet(10));
95 });
96 Try<String> failed3 = Checked.delay(() -> {
97 throw new RuntimeException("THIRD " + called.addAndGet(100));
98 });
99
100 Try<Iterable<String>> result = Try.sequence(Arrays.asList(failed1, failed2, failed3));
101
102 assertThat(result.isFailure(), is(true));
103
104 final Exception e = result.fold(identity(), x -> {
105 throw new NoSuchElementException();
106 });
107 assertThat(e, instanceOf(RuntimeException.class));
108 assertThat(e.getMessage(), is("FIRST 1"));
109
110 assertThat(called.get(), is(1));
111 }
112
113 @Test public void delayedSequenceReturnsValuesFromAllSuccesses() {
114 Try<Iterable<Integer>> result = Try.sequence(IntStream.range(0, 10).mapToObj(i -> Checked.delay(() -> i))::iterator);
115
116 assertThat(result.isSuccess(), is(true));
117 Iterable<Integer> vals = result.fold(f -> {
118 throw new NoSuchElementException();
119 }, identity());
120 assertThat(vals, is(IntStream.range(0, 10).boxed().collect(toList())));
121 }
122
123 @Test public void sequenceReturnsValuesFromAllSuccessesWithCustomCollector() {
124 Try<Set<Integer>> result = Try.sequence(IntStream.range(0, 10).map(i -> i % 4).mapToObj(i -> Checked.now(() -> i)).collect(toList()), toSet());
125
126 assertThat(result.isSuccess(), is(true));
127 Set<Integer> vals = result.fold(f -> {
128 throw new NoSuchElementException();
129 }, identity());
130 assertThat(vals, contains(0, 1, 2, 3));
131 }
132
133 @Test public void flattenNestedSuccess() {
134 Try<Try<Integer>> nested = Checked.now(() -> successT);
135
136 Try<Integer> flattened = Try.flatten(nested);
137
138 assertThat(flattened, is(successT));
139 }
140
141 @Test public void flattenNestedFailure() {
142 Try<Try<Integer>> nested = Checked.now(() -> failT);
143
144 Try<Integer> flattened = Try.flatten(nested);
145
146 assertThat(flattened.isFailure(), is(true));
147 final Exception e = flattened.fold(identity(), x -> {
148 throw new NoSuchElementException();
149 });
150 assertThat(e, instanceOf(IOException.class));
151 assertThat(e.getMessage(), is(EXCEPTION_MESSAGE));
152 }
153
154 }