ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/jsr166/jsr166/src/test/tck/CompletableFutureTest.java
(Generate patch)

Comparing jsr166/src/test/tck/CompletableFutureTest.java (file contents):
Revision 1.105 by dl, Thu Sep 3 16:30:05 2015 UTC vs.
Revision 1.135 by jsr166, Sun Nov 15 20:03:08 2015 UTC

# Line 7 | Line 7
7  
8   import static java.util.concurrent.TimeUnit.MILLISECONDS;
9   import static java.util.concurrent.TimeUnit.SECONDS;
10 + import static java.util.concurrent.CompletableFuture.completedFuture;
11 + import static java.util.concurrent.CompletableFuture.failedFuture;
12 +
13 + import java.lang.reflect.Method;
14 + import java.lang.reflect.Modifier;
15 +
16 + import java.util.stream.Collectors;
17 + import java.util.stream.Stream;
18  
19   import java.util.ArrayList;
20 + import java.util.Arrays;
21   import java.util.List;
22   import java.util.Objects;
23 + import java.util.Set;
24   import java.util.concurrent.Callable;
25   import java.util.concurrent.CancellationException;
26   import java.util.concurrent.CompletableFuture;
# Line 28 | Line 38 | import java.util.function.BiConsumer;
38   import java.util.function.BiFunction;
39   import java.util.function.Consumer;
40   import java.util.function.Function;
41 + import java.util.function.Predicate;
42   import java.util.function.Supplier;
43  
44 + import junit.framework.AssertionFailedError;
45   import junit.framework.Test;
46   import junit.framework.TestSuite;
47  
# Line 77 | Line 89 | public class CompletableFutureTest exten
89          assertTrue(f.toString().contains("[Completed normally]"));
90      }
91  
92 <    void checkCompletedWithWrappedCFException(CompletableFuture<?> f) {
93 <        long startTime = System.nanoTime();
94 <        long timeoutMillis = LONG_DELAY_MS;
95 <        try {
96 <            f.get(timeoutMillis, MILLISECONDS);
97 <            shouldThrow();
98 <        } catch (ExecutionException success) {
99 <            assertTrue(success.getCause() instanceof CFException);
100 <        } catch (Throwable fail) { threadUnexpectedException(fail); }
101 <        assertTrue(millisElapsedSince(startTime) < timeoutMillis/2);
102 <
103 <        try {
104 <            f.join();
105 <            shouldThrow();
106 <        } catch (CompletionException success) {
107 <            assertTrue(success.getCause() instanceof CFException);
108 <        }
97 <        try {
98 <            f.getNow(null);
99 <            shouldThrow();
100 <        } catch (CompletionException success) {
101 <            assertTrue(success.getCause() instanceof CFException);
92 >    /**
93 >     * Returns the "raw" internal exceptional completion of f,
94 >     * without any additional wrapping with CompletionException.
95 >     */
96 >    <U> Throwable exceptionalCompletion(CompletableFuture<U> f) {
97 >        // handle (and whenComplete) can distinguish between "direct"
98 >        // and "wrapped" exceptional completion
99 >        return f.handle((U u, Throwable t) -> t).join();
100 >    }
101 >
102 >    void checkCompletedExceptionally(CompletableFuture<?> f,
103 >                                     boolean wrapped,
104 >                                     Consumer<Throwable> checker) {
105 >        Throwable cause = exceptionalCompletion(f);
106 >        if (wrapped) {
107 >            assertTrue(cause instanceof CompletionException);
108 >            cause = cause.getCause();
109          }
110 <        try {
104 <            f.get();
105 <            shouldThrow();
106 <        } catch (ExecutionException success) {
107 <            assertTrue(success.getCause() instanceof CFException);
108 <        } catch (Throwable fail) { threadUnexpectedException(fail); }
109 <        assertTrue(f.isDone());
110 <        assertFalse(f.isCancelled());
111 <        assertTrue(f.toString().contains("[Completed exceptionally]"));
112 <    }
110 >        checker.accept(cause);
111  
114    <U> void checkCompletedExceptionallyWithRootCause(CompletableFuture<U> f,
115                                                      Throwable ex) {
112          long startTime = System.nanoTime();
117        long timeoutMillis = LONG_DELAY_MS;
113          try {
114 <            f.get(timeoutMillis, MILLISECONDS);
114 >            f.get(LONG_DELAY_MS, MILLISECONDS);
115              shouldThrow();
116          } catch (ExecutionException success) {
117 <            assertSame(ex, success.getCause());
117 >            assertSame(cause, success.getCause());
118          } catch (Throwable fail) { threadUnexpectedException(fail); }
119 <        assertTrue(millisElapsedSince(startTime) < timeoutMillis/2);
119 >        assertTrue(millisElapsedSince(startTime) < LONG_DELAY_MS / 2);
120  
121          try {
122              f.join();
123              shouldThrow();
124          } catch (CompletionException success) {
125 <            assertSame(ex, success.getCause());
126 <        }
125 >            assertSame(cause, success.getCause());
126 >        } catch (Throwable fail) { threadUnexpectedException(fail); }
127 >
128          try {
129              f.getNow(null);
130              shouldThrow();
131          } catch (CompletionException success) {
132 <            assertSame(ex, success.getCause());
133 <        }
132 >            assertSame(cause, success.getCause());
133 >        } catch (Throwable fail) { threadUnexpectedException(fail); }
134 >
135          try {
136              f.get();
137              shouldThrow();
138          } catch (ExecutionException success) {
139 <            assertSame(ex, success.getCause());
139 >            assertSame(cause, success.getCause());
140          } catch (Throwable fail) { threadUnexpectedException(fail); }
141  
145        assertTrue(f.isDone());
142          assertFalse(f.isCancelled());
143 +        assertTrue(f.isDone());
144 +        assertTrue(f.isCompletedExceptionally());
145          assertTrue(f.toString().contains("[Completed exceptionally]"));
146      }
147  
148 <    <U> void checkCompletedExceptionallyWithTimeout(CompletableFuture<U> f) {
149 <        long startTime = System.nanoTime();
150 <        long timeoutMillis = LONG_DELAY_MS;
151 <        try {
154 <            f.get(timeoutMillis, MILLISECONDS);
155 <            shouldThrow();
156 <        } catch (ExecutionException ex) {
157 <            assertTrue(ex.getCause() instanceof TimeoutException);
158 <        } catch (Throwable fail) { threadUnexpectedException(fail); }
159 <        assertTrue(millisElapsedSince(startTime) < timeoutMillis/2);
160 <
161 <        try {
162 <            f.join();
163 <            shouldThrow();
164 <        } catch (Throwable ex) {
165 <            assertTrue(ex.getCause() instanceof TimeoutException);
166 <        }
167 <
168 <        try {
169 <            f.getNow(null);
170 <            shouldThrow();
171 <        } catch (Throwable ex) {
172 <            assertTrue(ex.getCause() instanceof TimeoutException);
173 <        }
148 >    void checkCompletedWithWrappedCFException(CompletableFuture<?> f) {
149 >        checkCompletedExceptionally(f, true,
150 >            (t) -> assertTrue(t instanceof CFException));
151 >    }
152  
153 <        try {
154 <            f.get();
155 <            shouldThrow();
156 <        } catch (ExecutionException ex) {
179 <            assertTrue(ex.getCause() instanceof TimeoutException);
180 <        } catch (Throwable fail) { threadUnexpectedException(fail); }
153 >    void checkCompletedWithWrappedCancellationException(CompletableFuture<?> f) {
154 >        checkCompletedExceptionally(f, true,
155 >            (t) -> assertTrue(t instanceof CancellationException));
156 >    }
157  
158 <        assertTrue(f.isDone());
159 <        assertFalse(f.isCancelled());
160 <        assertTrue(f.toString().contains("[Completed exceptionally]"));
158 >    void checkCompletedWithTimeoutException(CompletableFuture<?> f) {
159 >        checkCompletedExceptionally(f, false,
160 >            (t) -> assertTrue(t instanceof TimeoutException));
161      }
162  
163 <    <U> void checkCompletedWithWrappedException(CompletableFuture<U> f,
164 <                                                Throwable ex) {
165 <        checkCompletedExceptionallyWithRootCause(f, ex);
190 <        try {
191 <            CompletableFuture<Throwable> spy = f.handle
192 <                ((U u, Throwable t) -> t);
193 <            assertTrue(spy.join() instanceof CompletionException);
194 <            assertSame(ex, spy.join().getCause());
195 <        } catch (Throwable fail) { threadUnexpectedException(fail); }
163 >    void checkCompletedWithWrappedException(CompletableFuture<?> f,
164 >                                            Throwable ex) {
165 >        checkCompletedExceptionally(f, true, (t) -> assertSame(t, ex));
166      }
167  
168 <    <U> void checkCompletedExceptionally(CompletableFuture<U> f, Throwable ex) {
169 <        checkCompletedExceptionallyWithRootCause(f, ex);
200 <        try {
201 <            CompletableFuture<Throwable> spy = f.handle
202 <                ((U u, Throwable t) -> t);
203 <            assertSame(ex, spy.join());
204 <        } catch (Throwable fail) { threadUnexpectedException(fail); }
168 >    void checkCompletedExceptionally(CompletableFuture<?> f, Throwable ex) {
169 >        checkCompletedExceptionally(f, false, (t) -> assertSame(t, ex));
170      }
171  
172      void checkCancelled(CompletableFuture<?> f) {
173          long startTime = System.nanoTime();
209        long timeoutMillis = LONG_DELAY_MS;
174          try {
175 <            f.get(timeoutMillis, MILLISECONDS);
175 >            f.get(LONG_DELAY_MS, MILLISECONDS);
176              shouldThrow();
177          } catch (CancellationException success) {
178          } catch (Throwable fail) { threadUnexpectedException(fail); }
179 <        assertTrue(millisElapsedSince(startTime) < timeoutMillis/2);
179 >        assertTrue(millisElapsedSince(startTime) < LONG_DELAY_MS / 2);
180  
181          try {
182              f.join();
# Line 227 | Line 191 | public class CompletableFutureTest exten
191              shouldThrow();
192          } catch (CancellationException success) {
193          } catch (Throwable fail) { threadUnexpectedException(fail); }
230        assertTrue(f.isDone());
231        assertTrue(f.isCompletedExceptionally());
232        assertTrue(f.isCancelled());
233        assertTrue(f.toString().contains("[Completed exceptionally]"));
234    }
194  
195 <    void checkCompletedWithWrappedCancellationException(CompletableFuture<?> f) {
237 <        long startTime = System.nanoTime();
238 <        long timeoutMillis = LONG_DELAY_MS;
239 <        try {
240 <            f.get(timeoutMillis, MILLISECONDS);
241 <            shouldThrow();
242 <        } catch (ExecutionException success) {
243 <            assertTrue(success.getCause() instanceof CancellationException);
244 <        } catch (Throwable fail) { threadUnexpectedException(fail); }
245 <        assertTrue(millisElapsedSince(startTime) < timeoutMillis/2);
195 >        assertTrue(exceptionalCompletion(f) instanceof CancellationException);
196  
247        try {
248            f.join();
249            shouldThrow();
250        } catch (CompletionException success) {
251            assertTrue(success.getCause() instanceof CancellationException);
252        }
253        try {
254            f.getNow(null);
255            shouldThrow();
256        } catch (CompletionException success) {
257            assertTrue(success.getCause() instanceof CancellationException);
258        }
259        try {
260            f.get();
261            shouldThrow();
262        } catch (ExecutionException success) {
263            assertTrue(success.getCause() instanceof CancellationException);
264        } catch (Throwable fail) { threadUnexpectedException(fail); }
197          assertTrue(f.isDone());
266        assertFalse(f.isCancelled());
198          assertTrue(f.isCompletedExceptionally());
199 +        assertTrue(f.isCancelled());
200          assertTrue(f.toString().contains("[Completed exceptionally]"));
201      }
202  
# Line 908 | Line 840 | public class CompletableFutureTest exten
840          if (!createIncomplete) assertTrue(f.complete(v1));
841          final CompletableFuture<Integer> g = f.exceptionally
842              ((Throwable t) -> {
911                // Should not be called
843                  a.getAndIncrement();
844 <                throw new AssertionError();
844 >                threadFail("should not be called");
845 >                return null;            // unreached
846              });
847          if (createIncomplete) assertTrue(f.complete(v1));
848  
# Line 969 | Line 901 | public class CompletableFutureTest exten
901       * whenComplete action executes on normal completion, propagating
902       * source result.
903       */
904 <    public void testWhenComplete_normalCompletion1() {
904 >    public void testWhenComplete_normalCompletion() {
905          for (ExecutionMode m : ExecutionMode.values())
906          for (boolean createIncomplete : new boolean[] { true, false })
907          for (Integer v1 : new Integer[] { 1, null })
# Line 979 | Line 911 | public class CompletableFutureTest exten
911          if (!createIncomplete) assertTrue(f.complete(v1));
912          final CompletableFuture<Integer> g = m.whenComplete
913              (f,
914 <             (Integer x, Throwable t) -> {
914 >             (Integer result, Throwable t) -> {
915                  m.checkExecutionMode();
916 <                threadAssertSame(x, v1);
916 >                threadAssertSame(result, v1);
917                  threadAssertNull(t);
918                  a.getAndIncrement();
919              });
# Line 1006 | Line 938 | public class CompletableFutureTest exten
938          if (!createIncomplete) f.completeExceptionally(ex);
939          final CompletableFuture<Integer> g = m.whenComplete
940              (f,
941 <             (Integer x, Throwable t) -> {
941 >             (Integer result, Throwable t) -> {
942                  m.checkExecutionMode();
943 <                threadAssertNull(x);
943 >                threadAssertNull(result);
944                  threadAssertSame(t, ex);
945                  a.getAndIncrement();
946              });
# Line 1033 | Line 965 | public class CompletableFutureTest exten
965          if (!createIncomplete) assertTrue(f.cancel(mayInterruptIfRunning));
966          final CompletableFuture<Integer> g = m.whenComplete
967              (f,
968 <             (Integer x, Throwable t) -> {
968 >             (Integer result, Throwable t) -> {
969                  m.checkExecutionMode();
970 <                threadAssertNull(x);
970 >                threadAssertNull(result);
971                  threadAssertTrue(t instanceof CancellationException);
972                  a.getAndIncrement();
973              });
# Line 1050 | Line 982 | public class CompletableFutureTest exten
982       * If a whenComplete action throws an exception when triggered by
983       * a normal completion, it completes exceptionally
984       */
985 <    public void testWhenComplete_actionFailed() {
985 >    public void testWhenComplete_sourceCompletedNormallyActionFailed() {
986          for (boolean createIncomplete : new boolean[] { true, false })
987          for (ExecutionMode m : ExecutionMode.values())
988          for (Integer v1 : new Integer[] { 1, null })
# Line 1061 | Line 993 | public class CompletableFutureTest exten
993          if (!createIncomplete) assertTrue(f.complete(v1));
994          final CompletableFuture<Integer> g = m.whenComplete
995              (f,
996 <             (Integer x, Throwable t) -> {
996 >             (Integer result, Throwable t) -> {
997                  m.checkExecutionMode();
998 <                threadAssertSame(x, v1);
998 >                threadAssertSame(result, v1);
999                  threadAssertNull(t);
1000                  a.getAndIncrement();
1001                  throw ex;
# Line 1078 | Line 1010 | public class CompletableFutureTest exten
1010      /**
1011       * If a whenComplete action throws an exception when triggered by
1012       * a source completion that also throws an exception, the source
1013 <     * exception takes precedence.
1013 >     * exception takes precedence (unlike handle)
1014       */
1015 <    public void testWhenComplete_actionFailedSourceFailed() {
1015 >    public void testWhenComplete_sourceFailedActionFailed() {
1016          for (boolean createIncomplete : new boolean[] { true, false })
1017          for (ExecutionMode m : ExecutionMode.values())
1018      {
# Line 1092 | Line 1024 | public class CompletableFutureTest exten
1024          if (!createIncomplete) f.completeExceptionally(ex1);
1025          final CompletableFuture<Integer> g = m.whenComplete
1026              (f,
1027 <             (Integer x, Throwable t) -> {
1027 >             (Integer result, Throwable t) -> {
1028                  m.checkExecutionMode();
1029                  threadAssertSame(t, ex1);
1030 <                threadAssertNull(x);
1030 >                threadAssertNull(result);
1031                  a.getAndIncrement();
1032                  throw ex2;
1033              });
# Line 1120 | Line 1052 | public class CompletableFutureTest exten
1052          if (!createIncomplete) assertTrue(f.complete(v1));
1053          final CompletableFuture<Integer> g = m.handle
1054              (f,
1055 <             (Integer x, Throwable t) -> {
1055 >             (Integer result, Throwable t) -> {
1056                  m.checkExecutionMode();
1057 <                threadAssertSame(x, v1);
1057 >                threadAssertSame(result, v1);
1058                  threadAssertNull(t);
1059                  a.getAndIncrement();
1060                  return inc(v1);
# Line 1149 | Line 1081 | public class CompletableFutureTest exten
1081          if (!createIncomplete) f.completeExceptionally(ex);
1082          final CompletableFuture<Integer> g = m.handle
1083              (f,
1084 <             (Integer x, Throwable t) -> {
1084 >             (Integer result, Throwable t) -> {
1085                  m.checkExecutionMode();
1086 <                threadAssertNull(x);
1086 >                threadAssertNull(result);
1087                  threadAssertSame(t, ex);
1088                  a.getAndIncrement();
1089                  return v1;
# Line 1178 | Line 1110 | public class CompletableFutureTest exten
1110          if (!createIncomplete) assertTrue(f.cancel(mayInterruptIfRunning));
1111          final CompletableFuture<Integer> g = m.handle
1112              (f,
1113 <             (Integer x, Throwable t) -> {
1113 >             (Integer result, Throwable t) -> {
1114                  m.checkExecutionMode();
1115 <                threadAssertNull(x);
1115 >                threadAssertNull(result);
1116                  threadAssertTrue(t instanceof CancellationException);
1117                  a.getAndIncrement();
1118                  return v1;
# Line 1193 | Line 1125 | public class CompletableFutureTest exten
1125      }}
1126  
1127      /**
1128 <     * handle result completes exceptionally if action does
1128 >     * If a "handle action" throws an exception when triggered by
1129 >     * a normal completion, it completes exceptionally
1130       */
1131 <    public void testHandle_sourceFailedActionFailed() {
1131 >    public void testHandle_sourceCompletedNormallyActionFailed() {
1132          for (ExecutionMode m : ExecutionMode.values())
1133          for (boolean createIncomplete : new boolean[] { true, false })
1134 +        for (Integer v1 : new Integer[] { 1, null })
1135      {
1136          final CompletableFuture<Integer> f = new CompletableFuture<>();
1137          final AtomicInteger a = new AtomicInteger(0);
1138 <        final CFException ex1 = new CFException();
1139 <        final CFException ex2 = new CFException();
1206 <        if (!createIncomplete) f.completeExceptionally(ex1);
1138 >        final CFException ex = new CFException();
1139 >        if (!createIncomplete) assertTrue(f.complete(v1));
1140          final CompletableFuture<Integer> g = m.handle
1141              (f,
1142 <             (Integer x, Throwable t) -> {
1142 >             (Integer result, Throwable t) -> {
1143                  m.checkExecutionMode();
1144 <                threadAssertNull(x);
1145 <                threadAssertSame(ex1, t);
1144 >                threadAssertSame(result, v1);
1145 >                threadAssertNull(t);
1146                  a.getAndIncrement();
1147 <                throw ex2;
1147 >                throw ex;
1148              });
1149 <        if (createIncomplete) f.completeExceptionally(ex1);
1149 >        if (createIncomplete) assertTrue(f.complete(v1));
1150  
1151 <        checkCompletedWithWrappedException(g, ex2);
1152 <        checkCompletedExceptionally(f, ex1);
1151 >        checkCompletedWithWrappedException(g, ex);
1152 >        checkCompletedNormally(f, v1);
1153          assertEquals(1, a.get());
1154      }}
1155  
1156 <    public void testHandle_sourceCompletedNormallyActionFailed() {
1157 <        for (ExecutionMode m : ExecutionMode.values())
1156 >    /**
1157 >     * If a "handle action" throws an exception when triggered by
1158 >     * a source completion that also throws an exception, the action
1159 >     * exception takes precedence (unlike whenComplete)
1160 >     */
1161 >    public void testHandle_sourceFailedActionFailed() {
1162          for (boolean createIncomplete : new boolean[] { true, false })
1163 <        for (Integer v1 : new Integer[] { 1, null })
1163 >        for (ExecutionMode m : ExecutionMode.values())
1164      {
1228        final CompletableFuture<Integer> f = new CompletableFuture<>();
1165          final AtomicInteger a = new AtomicInteger(0);
1166 <        final CFException ex = new CFException();
1167 <        if (!createIncomplete) assertTrue(f.complete(v1));
1166 >        final CFException ex1 = new CFException();
1167 >        final CFException ex2 = new CFException();
1168 >        final CompletableFuture<Integer> f = new CompletableFuture<>();
1169 >
1170 >        if (!createIncomplete) f.completeExceptionally(ex1);
1171          final CompletableFuture<Integer> g = m.handle
1172              (f,
1173 <             (Integer x, Throwable t) -> {
1173 >             (Integer result, Throwable t) -> {
1174                  m.checkExecutionMode();
1175 <                threadAssertSame(x, v1);
1176 <                threadAssertNull(t);
1175 >                threadAssertNull(result);
1176 >                threadAssertSame(ex1, t);
1177                  a.getAndIncrement();
1178 <                throw ex;
1178 >                throw ex2;
1179              });
1180 <        if (createIncomplete) assertTrue(f.complete(v1));
1180 >        if (createIncomplete) f.completeExceptionally(ex1);
1181  
1182 <        checkCompletedWithWrappedException(g, ex);
1183 <        checkCompletedNormally(f, v1);
1182 >        checkCompletedWithWrappedException(g, ex2);
1183 >        checkCompletedExceptionally(f, ex1);
1184          assertEquals(1, a.get());
1185      }}
1186  
# Line 3142 | Line 3081 | public class CompletableFutureTest exten
3081              for (int i = 0; i < k; i++) {
3082                  checkIncomplete(f);
3083                  checkIncomplete(CompletableFuture.allOf(fs));
3084 <                if (i != k/2) {
3084 >                if (i != k / 2) {
3085                      fs[i].complete(i);
3086                      checkCompletedNormally(fs[i], i);
3087                  } else {
# Line 3333 | Line 3272 | public class CompletableFutureTest exten
3272              () -> f.exceptionally(null),
3273  
3274              () -> f.handle(null),
3275 +
3276              () -> CompletableFuture.allOf((CompletableFuture<?>)null),
3277              () -> CompletableFuture.allOf((CompletableFuture<?>[])null),
3278              () -> CompletableFuture.allOf(f, null),
# Line 3344 | Line 3284 | public class CompletableFutureTest exten
3284              () -> CompletableFuture.anyOf(null, f),
3285  
3286              () -> f.obtrudeException(null),
3287 +
3288 +            () -> CompletableFuture.delayedExecutor(1L, SECONDS, null),
3289 +            () -> CompletableFuture.delayedExecutor(1L, null, new ThreadExecutor()),
3290 +            () -> CompletableFuture.delayedExecutor(1L, null),
3291 +
3292 +            () -> f.orTimeout(1L, null),
3293 +            () -> f.completeOnTimeout(42, 1L, null),
3294 +
3295 +            () -> CompletableFuture.failedFuture(null),
3296 +            () -> CompletableFuture.failedStage(null),
3297          };
3298  
3299          assertThrows(NullPointerException.class, throwingActions);
# Line 3364 | Line 3314 | public class CompletableFutureTest exten
3314       * newIncompleteFuture returns an incomplete CompletableFuture
3315       */
3316      public void testNewIncompleteFuture() {
3317 +        for (Integer v1 : new Integer[] { 1, null })
3318 +    {
3319          CompletableFuture<Integer> f = new CompletableFuture<>();
3320          CompletableFuture<Integer> g = f.newIncompleteFuture();
3321          checkIncomplete(f);
3322          checkIncomplete(g);
3323 <    }
3323 >        f.complete(v1);
3324 >        checkCompletedNormally(f, v1);
3325 >        checkIncomplete(g);
3326 >        g.complete(v1);
3327 >        checkCompletedNormally(g, v1);
3328 >        assertSame(g.getClass(), CompletableFuture.class);
3329 >    }}
3330  
3331      /**
3332       * completedStage returns a completed CompletionStage
3333       */
3334      public void testCompletedStage() {
3335 <        AtomicInteger x = new AtomicInteger();
3335 >        AtomicInteger x = new AtomicInteger(0);
3336          AtomicReference<Throwable> r = new AtomicReference<Throwable>();
3337          CompletionStage<Integer> f = CompletableFuture.completedStage(1);
3338          f.whenComplete((v, e) -> {if (e != null) r.set(e); else x.set(v);});
# Line 3384 | Line 3342 | public class CompletableFutureTest exten
3342  
3343      /**
3344       * defaultExecutor by default returns the commonPool if
3345 <     * it supports at least one thread.
3345 >     * it supports more than one thread.
3346       */
3347      public void testDefaultExecutor() {
3348          CompletableFuture<Integer> f = new CompletableFuture<>();
3349          Executor e = f.defaultExecutor();
3350 <        Executor c =  ForkJoinPool.commonPool();
3350 >        Executor c = ForkJoinPool.commonPool();
3351          if (ForkJoinPool.getCommonPoolParallelism() > 1)
3352              assertSame(e, c);
3353 +        else
3354 +            assertNotSame(e, c);
3355      }
3356  
3357      /**
# Line 3401 | Line 3361 | public class CompletableFutureTest exten
3361      public void testFailedFuture() {
3362          CFException ex = new CFException();
3363          CompletableFuture<Integer> f = CompletableFuture.failedFuture(ex);
3364 <        checkCompletedExceptionallyWithRootCause(f, ex);
3364 >        checkCompletedExceptionally(f, ex);
3365      }
3366  
3367      /**
3368       * failedFuture(null) throws NPE
3369       */
3370 <    public void testFailedFuture2() {
3370 >    public void testFailedFuture_null() {
3371          try {
3372              CompletableFuture<Integer> f = CompletableFuture.failedFuture(null);
3373              shouldThrow();
# Line 3440 | Line 3400 | public class CompletableFutureTest exten
3400          CFException ex = new CFException();
3401          f.completeExceptionally(ex);
3402          checkCompletedExceptionally(f, ex);
3403 <        checkCompletedWithWrappedCFException(g);
3403 >        checkCompletedWithWrappedException(g, ex);
3404      }
3405  
3406      /**
# Line 3450 | Line 3410 | public class CompletableFutureTest exten
3410      public void testMinimalCompletionStage() {
3411          CompletableFuture<Integer> f = new CompletableFuture<>();
3412          CompletionStage<Integer> g = f.minimalCompletionStage();
3413 <        AtomicInteger x = new AtomicInteger();
3413 >        AtomicInteger x = new AtomicInteger(0);
3414          AtomicReference<Throwable> r = new AtomicReference<Throwable>();
3415          checkIncomplete(f);
3416          g.whenComplete((v, e) -> {if (e != null) r.set(e); else x.set(v);});
# Line 3467 | Line 3427 | public class CompletableFutureTest exten
3427      public void testMinimalCompletionStage2() {
3428          CompletableFuture<Integer> f = new CompletableFuture<>();
3429          CompletionStage<Integer> g = f.minimalCompletionStage();
3430 <        AtomicInteger x = new AtomicInteger();
3430 >        AtomicInteger x = new AtomicInteger(0);
3431          AtomicReference<Throwable> r = new AtomicReference<Throwable>();
3432          g.whenComplete((v, e) -> {if (e != null) r.set(e); else x.set(v);});
3433          checkIncomplete(f);
# Line 3479 | Line 3439 | public class CompletableFutureTest exten
3439      }
3440  
3441      /**
3442 <     * failedStage returns a Completionstage completed
3442 >     * failedStage returns a CompletionStage completed
3443       * exceptionally with the given Exception
3444       */
3445      public void testFailedStage() {
3446          CFException ex = new CFException();
3447          CompletionStage<Integer> f = CompletableFuture.failedStage(ex);
3448 <        AtomicInteger x = new AtomicInteger();
3448 >        AtomicInteger x = new AtomicInteger(0);
3449          AtomicReference<Throwable> r = new AtomicReference<Throwable>();
3450          f.whenComplete((v, e) -> {if (e != null) r.set(e); else x.set(v);});
3451          assertEquals(x.get(), 0);
3452 <        assertEquals(r.get().getCause(), ex);
3452 >        assertEquals(r.get(), ex);
3453      }
3454  
3455      /**
3456       * completeAsync completes with value of given supplier
3457       */
3458      public void testCompleteAsync() {
3459 +        for (Integer v1 : new Integer[] { 1, null })
3460 +    {
3461          CompletableFuture<Integer> f = new CompletableFuture<>();
3462 <        f.completeAsync(() -> 1);
3462 >        f.completeAsync(() -> v1);
3463          f.join();
3464 <        checkCompletedNormally(f, 1);
3465 <    }
3464 >        checkCompletedNormally(f, v1);
3465 >    }}
3466  
3467      /**
3468       * completeAsync completes exceptionally if given supplier throws
# Line 3512 | Line 3474 | public class CompletableFutureTest exten
3474          try {
3475              f.join();
3476              shouldThrow();
3477 <        } catch (Exception success) {}
3478 <        checkCompletedWithWrappedCFException(f);
3477 >        } catch (CompletionException success) {}
3478 >        checkCompletedWithWrappedException(f, ex);
3479      }
3480  
3481      /**
3482       * completeAsync with given executor completes with value of given supplier
3483       */
3484      public void testCompleteAsync3() {
3485 +        for (Integer v1 : new Integer[] { 1, null })
3486 +    {
3487          CompletableFuture<Integer> f = new CompletableFuture<>();
3488 <        f.completeAsync(() -> 1, new ThreadExecutor());
3489 <        f.join();
3490 <        checkCompletedNormally(f, 1);
3491 <    }
3488 >        ThreadExecutor executor = new ThreadExecutor();
3489 >        f.completeAsync(() -> v1, executor);
3490 >        assertSame(v1, f.join());
3491 >        checkCompletedNormally(f, v1);
3492 >        assertEquals(1, executor.count.get());
3493 >    }}
3494  
3495      /**
3496       * completeAsync with given executor completes exceptionally if
# Line 3533 | Line 3499 | public class CompletableFutureTest exten
3499      public void testCompleteAsync4() {
3500          CompletableFuture<Integer> f = new CompletableFuture<>();
3501          CFException ex = new CFException();
3502 <        f.completeAsync(() -> {if (true) throw ex; return 1;}, new ThreadExecutor());
3502 >        ThreadExecutor executor = new ThreadExecutor();
3503 >        f.completeAsync(() -> {if (true) throw ex; return 1;}, executor);
3504          try {
3505              f.join();
3506              shouldThrow();
3507 <        } catch (Exception success) {}
3508 <        checkCompletedWithWrappedCFException(f);
3507 >        } catch (CompletionException success) {}
3508 >        checkCompletedWithWrappedException(f, ex);
3509 >        assertEquals(1, executor.count.get());
3510      }
3511  
3512      /**
3513 <     *  orTimeout completes with TimeoutException if not complete
3513 >     * orTimeout completes with TimeoutException if not complete
3514       */
3515 <    public void testOrTimeout() {
3515 >    public void testOrTimeout_timesOut() {
3516 >        long timeoutMillis = timeoutMillis();
3517          CompletableFuture<Integer> f = new CompletableFuture<>();
3518 <        f.orTimeout(SHORT_DELAY_MS, TimeUnit.MILLISECONDS);
3519 <        checkCompletedExceptionallyWithTimeout(f);
3518 >        long startTime = System.nanoTime();
3519 >        f.orTimeout(timeoutMillis, MILLISECONDS);
3520 >        checkCompletedWithTimeoutException(f);
3521 >        assertTrue(millisElapsedSince(startTime) >= timeoutMillis);
3522      }
3523  
3524      /**
3525 <     *  orTimeout completes normally if completed before timeout
3525 >     * orTimeout completes normally if completed before timeout
3526       */
3527 <    public void testOrTimeout2() {
3527 >    public void testOrTimeout_completed() {
3528 >        for (Integer v1 : new Integer[] { 1, null })
3529 >    {
3530          CompletableFuture<Integer> f = new CompletableFuture<>();
3531 <        f.complete(1);
3532 <        f.orTimeout(SHORT_DELAY_MS, TimeUnit.MILLISECONDS);
3533 <        checkCompletedNormally(f, 1);
3534 <    }
3531 >        CompletableFuture<Integer> g = new CompletableFuture<>();
3532 >        long startTime = System.nanoTime();
3533 >        f.complete(v1);
3534 >        f.orTimeout(LONG_DELAY_MS, MILLISECONDS);
3535 >        g.orTimeout(LONG_DELAY_MS, MILLISECONDS);
3536 >        g.complete(v1);
3537 >        checkCompletedNormally(f, v1);
3538 >        checkCompletedNormally(g, v1);
3539 >        assertTrue(millisElapsedSince(startTime) < LONG_DELAY_MS / 2);
3540 >    }}
3541  
3542      /**
3543 <     *  completeOnTimeout completes with given value if not complete
3543 >     * completeOnTimeout completes with given value if not complete
3544       */
3545 <    public void testCompleteOnTimeout() {
3545 >    public void testCompleteOnTimeout_timesOut() {
3546 >        testInParallel(() -> testCompleteOnTimeout_timesOut(42),
3547 >                       () -> testCompleteOnTimeout_timesOut(null));
3548 >    }
3549 >
3550 >    public void testCompleteOnTimeout_timesOut(Integer v) {
3551 >        long timeoutMillis = timeoutMillis();
3552          CompletableFuture<Integer> f = new CompletableFuture<>();
3553 <        f.completeOnTimeout(-1, SHORT_DELAY_MS, TimeUnit.MILLISECONDS);
3554 <        f.join();
3555 <        checkCompletedNormally(f, -1);
3553 >        long startTime = System.nanoTime();
3554 >        f.completeOnTimeout(v, timeoutMillis, MILLISECONDS);
3555 >        assertSame(v, f.join());
3556 >        assertTrue(millisElapsedSince(startTime) >= timeoutMillis);
3557 >        f.complete(99);         // should have no effect
3558 >        checkCompletedNormally(f, v);
3559      }
3560  
3561      /**
3562 <     *  completeOnTimeout has no effect if completed within timeout
3562 >     * completeOnTimeout has no effect if completed within timeout
3563       */
3564 <    public void testCompleteOnTimeout2() {
3564 >    public void testCompleteOnTimeout_completed() {
3565 >        for (Integer v1 : new Integer[] { 1, null })
3566 >    {
3567          CompletableFuture<Integer> f = new CompletableFuture<>();
3568 <        f.complete(1);
3569 <        f.completeOnTimeout(-1, SHORT_DELAY_MS, TimeUnit.MILLISECONDS);
3570 <        checkCompletedNormally(f, 1);
3571 <    }
3568 >        CompletableFuture<Integer> g = new CompletableFuture<>();
3569 >        long startTime = System.nanoTime();
3570 >        f.complete(v1);
3571 >        f.completeOnTimeout(-1, LONG_DELAY_MS, MILLISECONDS);
3572 >        g.completeOnTimeout(-1, LONG_DELAY_MS, MILLISECONDS);
3573 >        g.complete(v1);
3574 >        checkCompletedNormally(f, v1);
3575 >        checkCompletedNormally(g, v1);
3576 >        assertTrue(millisElapsedSince(startTime) < LONG_DELAY_MS / 2);
3577 >    }}
3578  
3579      /**
3580       * delayedExecutor returns an executor that delays submission
3581       */
3582      public void testDelayedExecutor() {
3583 <        long timeoutMillis = SMALL_DELAY_MS;
3584 <        Executor d = CompletableFuture.delayedExecutor(timeoutMillis,
3585 <                                                       MILLISECONDS);
3583 >        testInParallel(() -> testDelayedExecutor(null, null),
3584 >                       () -> testDelayedExecutor(null, 1),
3585 >                       () -> testDelayedExecutor(new ThreadExecutor(), 1),
3586 >                       () -> testDelayedExecutor(new ThreadExecutor(), 1));
3587 >    }
3588 >
3589 >    public void testDelayedExecutor(Executor executor, Integer v) throws Exception {
3590 >        long timeoutMillis = timeoutMillis();
3591 >        // Use an "unreasonably long" long timeout to catch lingering threads
3592 >        long longTimeoutMillis = 1000 * 60 * 60 * 24;
3593 >        final Executor delayer, longDelayer;
3594 >        if (executor == null) {
3595 >            delayer = CompletableFuture.delayedExecutor(timeoutMillis, MILLISECONDS);
3596 >            longDelayer = CompletableFuture.delayedExecutor(longTimeoutMillis, MILLISECONDS);
3597 >        } else {
3598 >            delayer = CompletableFuture.delayedExecutor(timeoutMillis, MILLISECONDS, executor);
3599 >            longDelayer = CompletableFuture.delayedExecutor(longTimeoutMillis, MILLISECONDS, executor);
3600 >        }
3601          long startTime = System.nanoTime();
3602 <        CompletableFuture<Integer> f = CompletableFuture.supplyAsync(() -> 1, d);
3603 <        assertNull(f.getNow(null));
3604 <        try {
3605 <            f.get(LONG_DELAY_MS, MILLISECONDS);
3606 <        } catch (Throwable fail) { threadUnexpectedException(fail); }
3607 <        assertTrue(millisElapsedSince(startTime) > timeoutMillis/2);
3608 <        checkCompletedNormally(f, 1);
3609 <    }
3602 >        CompletableFuture<Integer> f =
3603 >            CompletableFuture.supplyAsync(() -> v, delayer);
3604 >        CompletableFuture<Integer> g =
3605 >            CompletableFuture.supplyAsync(() -> v, longDelayer);
3606 >
3607 >        assertNull(g.getNow(null));
3608 >
3609 >        assertSame(v, f.get(LONG_DELAY_MS, MILLISECONDS));
3610 >        long millisElapsed = millisElapsedSince(startTime);
3611 >        assertTrue(millisElapsed >= timeoutMillis);
3612 >        assertTrue(millisElapsed < LONG_DELAY_MS / 2);
3613  
3614 <    /**
3615 <     * delayedExecutor for a given executor returns an executor that
3616 <     * delays submission
3617 <     */
3604 <    public void testDelayedExecutor2() {
3605 <        long timeoutMillis = SMALL_DELAY_MS;
3606 <        Executor d = CompletableFuture.delayedExecutor(timeoutMillis,
3607 <                                                       MILLISECONDS,
3608 <                                                       new ThreadExecutor());
3609 <        long startTime = System.nanoTime();
3610 <        CompletableFuture<Integer> f = CompletableFuture.supplyAsync(() -> 1, d);
3611 <        assertNull(f.getNow(null));
3612 <        try {
3613 <            f.get(LONG_DELAY_MS, MILLISECONDS);
3614 <        } catch (Throwable fail) { threadUnexpectedException(fail); }
3615 <        assertTrue(millisElapsedSince(startTime) > timeoutMillis/2);
3616 <        checkCompletedNormally(f, 1);
3614 >        checkCompletedNormally(f, v);
3615 >
3616 >        checkIncomplete(g);
3617 >        assertTrue(g.cancel(true));
3618      }
3619  
3620      //--- tests of implementation details; not part of official tck ---
# Line 3650 | Line 3651 | public class CompletableFutureTest exten
3651          funs.add((y) -> m.thenAcceptBoth(y, v42, new SubtractAction(m)));
3652          funs.add((y) -> m.thenCombine(y, v42, new SubtractFunction(m)));
3653  
3654 <        funs.add((y) -> m.whenComplete(y, (Integer x, Throwable t) -> {}));
3654 >        funs.add((y) -> m.whenComplete(y, (Integer r, Throwable t) -> {}));
3655  
3656          funs.add((y) -> m.thenCompose(y, new CompletableFutureInc(m)));
3657  
# Line 3706 | Line 3707 | public class CompletableFutureTest exten
3707          }
3708      }}
3709  
3710 +    /**
3711 +     * Minimal completion stages throw UOE for all non-CompletionStage methods
3712 +     */
3713 +    public void testMinimalCompletionStage_minimality() {
3714 +        if (!testImplementationDetails) return;
3715 +        Function<Method, String> toSignature =
3716 +            (method) -> method.getName() + Arrays.toString(method.getParameterTypes());
3717 +        Predicate<Method> isNotStatic =
3718 +            (method) -> (method.getModifiers() & Modifier.STATIC) == 0;
3719 +        List<Method> minimalMethods =
3720 +            Stream.of(Object.class, CompletionStage.class)
3721 +            .flatMap((klazz) -> Stream.of(klazz.getMethods()))
3722 +            .filter(isNotStatic)
3723 +            .collect(Collectors.toList());
3724 +        // Methods from CompletableFuture permitted NOT to throw UOE
3725 +        String[] signatureWhitelist = {
3726 +            "newIncompleteFuture[]",
3727 +            "defaultExecutor[]",
3728 +            "minimalCompletionStage[]",
3729 +            "copy[]",
3730 +        };
3731 +        Set<String> permittedMethodSignatures =
3732 +            Stream.concat(minimalMethods.stream().map(toSignature),
3733 +                          Stream.of(signatureWhitelist))
3734 +            .collect(Collectors.toSet());
3735 +        List<Method> allMethods = Stream.of(CompletableFuture.class.getMethods())
3736 +            .filter(isNotStatic)
3737 +            .filter((method) -> !permittedMethodSignatures.contains(toSignature.apply(method)))
3738 +            .collect(Collectors.toList());
3739 +
3740 +        CompletionStage<Integer> minimalStage =
3741 +            new CompletableFuture<Integer>().minimalCompletionStage();
3742 +
3743 +        List<Method> bugs = new ArrayList<>();
3744 +        for (Method method : allMethods) {
3745 +            Class<?>[] parameterTypes = method.getParameterTypes();
3746 +            Object[] args = new Object[parameterTypes.length];
3747 +            // Manufacture boxed primitives for primitive params
3748 +            for (int i = 0; i < args.length; i++) {
3749 +                Class<?> type = parameterTypes[i];
3750 +                if (parameterTypes[i] == boolean.class)
3751 +                    args[i] = false;
3752 +                else if (parameterTypes[i] == int.class)
3753 +                    args[i] = 0;
3754 +                else if (parameterTypes[i] == long.class)
3755 +                    args[i] = 0L;
3756 +            }
3757 +            try {
3758 +                method.invoke(minimalStage, args);
3759 +                bugs.add(method);
3760 +            }
3761 +            catch (java.lang.reflect.InvocationTargetException expected) {
3762 +                if (! (expected.getCause() instanceof UnsupportedOperationException)) {
3763 +                    bugs.add(method);
3764 +                    // expected.getCause().printStackTrace();
3765 +                }
3766 +            }
3767 +            catch (ReflectiveOperationException bad) { throw new Error(bad); }
3768 +        }
3769 +        if (!bugs.isEmpty())
3770 +            throw new Error("Methods did not throw UOE: " + bugs.toString());
3771 +    }
3772 +
3773 +    static class Monad {
3774 +        static class ZeroException extends RuntimeException {
3775 +            public ZeroException() { super("monadic zero"); }
3776 +        }
3777 +        // "return", "unit"
3778 +        static <T> CompletableFuture<T> unit(T value) {
3779 +            return completedFuture(value);
3780 +        }
3781 +        // monadic zero ?
3782 +        static <T> CompletableFuture<T> zero() {
3783 +            return failedFuture(new ZeroException());
3784 +        }
3785 +        // >=>
3786 +        static <T,U,V> Function<T, CompletableFuture<V>> compose
3787 +            (Function<T, CompletableFuture<U>> f,
3788 +             Function<U, CompletableFuture<V>> g) {
3789 +            return (x) -> f.apply(x).thenCompose(g);
3790 +        }
3791 +
3792 +        static void assertZero(CompletableFuture<?> f) {
3793 +            try {
3794 +                f.getNow(null);
3795 +                throw new AssertionFailedError("should throw");
3796 +            } catch (CompletionException success) {
3797 +                assertTrue(success.getCause() instanceof ZeroException);
3798 +            }
3799 +        }
3800 +
3801 +        static <T> void assertFutureEquals(CompletableFuture<T> f,
3802 +                                           CompletableFuture<T> g) {
3803 +            T fval = null, gval = null;
3804 +            Throwable fex = null, gex = null;
3805 +
3806 +            try { fval = f.get(); }
3807 +            catch (ExecutionException ex) { fex = ex.getCause(); }
3808 +            catch (Throwable ex) { fex = ex; }
3809 +
3810 +            try { gval = g.get(); }
3811 +            catch (ExecutionException ex) { gex = ex.getCause(); }
3812 +            catch (Throwable ex) { gex = ex; }
3813 +
3814 +            if (fex != null || gex != null)
3815 +                assertSame(fex.getClass(), gex.getClass());
3816 +            else
3817 +                assertEquals(fval, gval);
3818 +        }
3819 +
3820 +        static class PlusFuture<T> extends CompletableFuture<T> {
3821 +            AtomicReference<Throwable> firstFailure = new AtomicReference<>(null);
3822 +        }
3823 +
3824 +        // Monadic "plus"
3825 +        static <T> CompletableFuture<T> plus(CompletableFuture<? extends T> f,
3826 +                                             CompletableFuture<? extends T> g) {
3827 +            PlusFuture<T> plus = new PlusFuture<T>();
3828 +            BiConsumer<T, Throwable> action = (T result, Throwable ex) -> {
3829 +                if (ex == null) {
3830 +                    if (plus.complete(result))
3831 +                        if (plus.firstFailure.get() != null)
3832 +                            plus.firstFailure.set(null);
3833 +                }
3834 +                else if (plus.firstFailure.compareAndSet(null, ex)) {
3835 +                    if (plus.isDone())
3836 +                        plus.firstFailure.set(null);
3837 +                }
3838 +                else {
3839 +                    // first failure has precedence
3840 +                    Throwable first = plus.firstFailure.getAndSet(null);
3841 +
3842 +                    // may fail with "Self-suppression not permitted"
3843 +                    try { first.addSuppressed(ex); }
3844 +                    catch (Exception ignored) {}
3845 +
3846 +                    plus.completeExceptionally(first);
3847 +                }
3848 +            };
3849 +            f.whenComplete(action);
3850 +            g.whenComplete(action);
3851 +            return plus;
3852 +        }
3853 +    }
3854 +
3855 +    /**
3856 +     * CompletableFuture is an additive monad - sort of.
3857 +     * https://en.wikipedia.org/wiki/Monad_(functional_programming)#Additive_monads
3858 +     */
3859 +    public void testAdditiveMonad() throws Throwable {
3860 +        Function<Long, CompletableFuture<Long>> unit = Monad::unit;
3861 +        CompletableFuture<Long> zero = Monad.zero();
3862 +
3863 +        // Some mutually non-commutative functions
3864 +        Function<Long, CompletableFuture<Long>> triple
3865 +            = (x) -> Monad.unit(3 * x);
3866 +        Function<Long, CompletableFuture<Long>> inc
3867 +            = (x) -> Monad.unit(x + 1);
3868 +
3869 +        // unit is a right identity: m >>= unit === m
3870 +        Monad.assertFutureEquals(inc.apply(5L).thenCompose(unit),
3871 +                                 inc.apply(5L));
3872 +        // unit is a left identity: (unit x) >>= f === f x
3873 +        Monad.assertFutureEquals(unit.apply(5L).thenCompose(inc),
3874 +                                 inc.apply(5L));
3875 +
3876 +        // associativity: (m >>= f) >>= g === m >>= ( \x -> (f x >>= g) )
3877 +        Monad.assertFutureEquals(
3878 +            unit.apply(5L).thenCompose(inc).thenCompose(triple),
3879 +            unit.apply(5L).thenCompose((x) -> inc.apply(x).thenCompose(triple)));
3880 +
3881 +        // The case for CompletableFuture as an additive monad is weaker...
3882 +
3883 +        // zero is a monadic zero
3884 +        Monad.assertZero(zero);
3885 +
3886 +        // left zero: zero >>= f === zero
3887 +        Monad.assertZero(zero.thenCompose(inc));
3888 +        // right zero: f >>= (\x -> zero) === zero
3889 +        Monad.assertZero(inc.apply(5L).thenCompose((x) -> zero));
3890 +
3891 +        // f plus zero === f
3892 +        Monad.assertFutureEquals(Monad.unit(5L),
3893 +                                 Monad.plus(Monad.unit(5L), zero));
3894 +        // zero plus f === f
3895 +        Monad.assertFutureEquals(Monad.unit(5L),
3896 +                                 Monad.plus(zero, Monad.unit(5L)));
3897 +        // zero plus zero === zero
3898 +        Monad.assertZero(Monad.plus(zero, zero));
3899 +        {
3900 +            CompletableFuture<Long> f = Monad.plus(Monad.unit(5L),
3901 +                                                   Monad.unit(8L));
3902 +            // non-determinism
3903 +            assertTrue(f.get() == 5L || f.get() == 8L);
3904 +        }
3905 +
3906 +        CompletableFuture<Long> godot = new CompletableFuture<>();
3907 +        // f plus godot === f (doesn't wait for godot)
3908 +        Monad.assertFutureEquals(Monad.unit(5L),
3909 +                                 Monad.plus(Monad.unit(5L), godot));
3910 +        // godot plus f === f (doesn't wait for godot)
3911 +        Monad.assertFutureEquals(Monad.unit(5L),
3912 +                                 Monad.plus(godot, Monad.unit(5L)));
3913 +    }
3914 +
3915 + //     static <U> U join(CompletionStage<U> stage) {
3916 + //         CompletableFuture<U> f = new CompletableFuture<>();
3917 + //         stage.whenComplete((v, ex) -> {
3918 + //             if (ex != null) f.completeExceptionally(ex); else f.complete(v);
3919 + //         });
3920 + //         return f.join();
3921 + //     }
3922 +
3923 + //     static <U> boolean isDone(CompletionStage<U> stage) {
3924 + //         CompletableFuture<U> f = new CompletableFuture<>();
3925 + //         stage.whenComplete((v, ex) -> {
3926 + //             if (ex != null) f.completeExceptionally(ex); else f.complete(v);
3927 + //         });
3928 + //         return f.isDone();
3929 + //     }
3930 +
3931 + //     static <U> U join2(CompletionStage<U> stage) {
3932 + //         return stage.toCompletableFuture().copy().join();
3933 + //     }
3934 +
3935 + //     static <U> boolean isDone2(CompletionStage<U> stage) {
3936 + //         return stage.toCompletableFuture().copy().isDone();
3937 + //     }
3938 +
3939   }

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines