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 }) |
1152 |
|
assertEquals(1, a.get()); |
1153 |
|
}} |
1154 |
|
|
1155 |
+ |
/** |
1156 |
+ |
* If a "handle action" throws an exception when triggered by |
1157 |
+ |
* a normal completion, it completes exceptionally |
1158 |
+ |
*/ |
1159 |
|
public void testHandle_sourceCompletedNormallyActionFailed() { |
1160 |
|
for (ExecutionMode m : ExecutionMode.values()) |
1161 |
|
for (boolean createIncomplete : new boolean[] { true, false }) |
3768 |
|
} |
3769 |
|
|
3770 |
|
static class Monad { |
3771 |
< |
static class MonadError extends Error { |
3772 |
< |
public MonadError() { super("monadic zero"); } |
3771 |
> |
static class ZeroException extends RuntimeException { |
3772 |
> |
public ZeroException() { super("monadic zero"); } |
3773 |
|
} |
3774 |
|
// "return", "unit" |
3775 |
|
static <T> CompletableFuture<T> unit(T value) { |
3777 |
|
} |
3778 |
|
// monadic zero ? |
3779 |
|
static <T> CompletableFuture<T> zero() { |
3780 |
< |
return failedFuture(new MonadError()); |
3780 |
> |
return failedFuture(new ZeroException()); |
3781 |
|
} |
3782 |
|
// >=> |
3783 |
|
static <T,U,V> Function<T, CompletableFuture<V>> compose |
3791 |
|
f.getNow(null); |
3792 |
|
throw new AssertionFailedError("should throw"); |
3793 |
|
} catch (CompletionException success) { |
3794 |
< |
assertTrue(success.getCause() instanceof MonadError); |
3794 |
> |
assertTrue(success.getCause() instanceof ZeroException); |
3795 |
|
} |
3796 |
|
} |
3797 |
|
|
3831 |
|
else if (plus.firstFailure.compareAndSet(null, ex)) { |
3832 |
|
if (plus.isDone()) |
3833 |
|
plus.firstFailure.set(null); |
3834 |
< |
} else { |
3835 |
< |
// prefer failing with first failure |
3836 |
< |
plus.completeExceptionally(plus.firstFailure.getAndSet(null)); |
3834 |
> |
} |
3835 |
> |
else { |
3836 |
> |
// first failure has precedence |
3837 |
> |
Throwable first = plus.firstFailure.getAndSet(null); |
3838 |
> |
|
3839 |
> |
// may fail with "Self-suppression not permitted" |
3840 |
> |
try { first.addSuppressed(ex); } |
3841 |
> |
catch (Exception ignored) {} |
3842 |
> |
|
3843 |
> |
plus.completeExceptionally(first); |
3844 |
|
} |
3845 |
|
}; |
3846 |
|
f.whenComplete(action); |