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.128 by jsr166, Sun Nov 15 00:37:50 2015 UTC vs.
Revision 1.135 by jsr166, Sun Nov 15 20:03:08 2015 UTC

# Line 911 | 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 938 | 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 965 | 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 982 | 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 993 | 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 1010 | 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 1024 | 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 1052 | 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 1081 | 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 1110 | 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 1125 | 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();
1138 <        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      {
1160        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 3644 | 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 3764 | Line 3771 | public class CompletableFutureTest exten
3771      }
3772  
3773      static class Monad {
3774 <        static class MonadError extends Error {
3775 <            public MonadError() { super("monadic zero"); }
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(T value) {
3783 <            return failedFuture(new MonadError());
3782 >        static <T> CompletableFuture<T> zero() {
3783 >            return failedFuture(new ZeroException());
3784          }
3785          // >=>
3786          static <T,U,V> Function<T, CompletableFuture<V>> compose
# Line 3787 | Line 3794 | public class CompletableFutureTest exten
3794                  f.getNow(null);
3795                  throw new AssertionFailedError("should throw");
3796              } catch (CompletionException success) {
3797 <                assertTrue(success.getCause() instanceof MonadError);
3797 >                assertTrue(success.getCause() instanceof ZeroException);
3798              }
3799          }
3800  
# Line 3818 | Line 3825 | public class CompletableFutureTest exten
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 fail) -> {
3829 <                if (result != null) {
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, fail)) {
3834 >                else if (plus.firstFailure.compareAndSet(null, ex)) {
3835                      if (plus.isDone())
3836                          plus.firstFailure.set(null);
3837 <                } else {
3838 <                    if (plus.completeExceptionally(fail))
3839 <                        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);
# Line 3843 | Line 3857 | public class CompletableFutureTest exten
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) -> completedFuture(3 * x);
3865 >            = (x) -> Monad.unit(3 * x);
3866          Function<Long, CompletableFuture<Long>> inc
3867 <            = (x) -> completedFuture(x + 1);
3851 <
3852 <        Function<Long, CompletableFuture<Long>> unit = Monad::unit;
3853 <        Function<Long, CompletableFuture<Long>> zero = Monad::zero;
3867 >            = (x) -> Monad.unit(x + 1);
3868  
3869          // unit is a right identity: m >>= unit === m
3870 <        Monad.assertFutureEquals(
3871 <            inc.apply(5L).thenCompose(unit),
3858 <            inc.apply(5L));
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(
3874 <            unit.apply(5L).thenCompose(inc),
3875 <            inc.apply(5L));
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.apply(5L));
3870 <        // left zero: zero >>= f === zero
3871 <        Monad.assertZero(zero.apply(5L).thenCompose(inc));
3872 <        // right zero: f >>= zero === zero
3873 <        Monad.assertZero(inc.apply(5L).thenCompose(zero));
3884 >        Monad.assertZero(zero);
3885  
3886 <        // inc plus zero === inc
3887 <        Monad.assertFutureEquals(
3888 <            inc.apply(5L),
3889 <            Monad.plus(inc.apply(5L), zero.apply(5L)));
3890 <        // zero plus inc === inc
3891 <        Monad.assertFutureEquals(
3892 <            inc.apply(5L),
3893 <            Monad.plus(zero.apply(5L), inc.apply(5L)));
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.apply(5L), zero.apply(5L)));
3898 >        Monad.assertZero(Monad.plus(zero, zero));
3899          {
3900 <            CompletableFuture<Long> f = Monad.plus(inc.apply(5L), inc.apply(8L));
3901 <            assertTrue(f.get() == 6L || f.get() == 9L);
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 <        // inc plus godot === inc (doesn't wait for godot)
3908 <        Monad.assertFutureEquals(
3909 <            inc.apply(5L),
3910 <            Monad.plus(inc.apply(5L), godot));
3911 <        // godot plus inc === inc (doesn't wait for godot)
3912 <        Monad.assertFutureEquals(
3897 <            inc.apply(5L),
3898 <            Monad.plus(godot, inc.apply(5L)));
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) {

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines