package com.millross.blog.async;

import org.junit.Test;

import java.util.concurrent.CompletableFuture;
import java.util.concurrent.CompletionException;

import static java.util.concurrent.CompletableFuture.supplyAsync;
import static org.hamcrest.CoreMatchers.is;
import static org.hamcrest.MatcherAssert.assertThat;

/**
 *
 */
public class SimpleCompletableFutureTest extends CompletableFutureTestBase {

    @Test
    public void testSimpleFutureCompletion() throws Exception {
        final CompletableFuture<Integer> future = supplyAsync(delayedValueSupplier(1), executor);
        assertThat(future.get(), is(1));
    }

    @Test(expected = IntentionalException.class)
    public void testExceptionalCompletion() throws Throwable {
        final CompletableFuture<Integer> future = delayedExceptionalCompletion(new IntentionalException());
        try {
            future.join();
        } catch (CompletionException ex) {
            throw (ex.getCause());
        }
    }

    @Test
    public void demoThenApply() throws Exception {
        final CompletableFuture<Integer> future = CompletableFuture.supplyAsync(delayedValueSupplier(1), executor)
                .thenApply(i -> i + 3);
        assertThat(future.get(), is(4));
    }

    @Test
    public void demoThenCompose() throws Exception {
        // We'll use one future to specify how long a subsequent future will take
        final CompletableFuture<Integer> future = supplyAsync(delayedValueSupplier(3), executor)
                .thenCompose(i -> supplyAsync(delayedValueSupplier(2, i * 100), executor));
        assertThat(future.get(), is(2));
    }

    @Test
    public void demoMultiStagePipeline() throws Exception {
        // We'll use one future to specify how long a subsequent future will take
        final CompletableFuture<Integer> future = supplyAsync(delayedValueSupplier(3), executor)
                .thenApply(i -> {
                    System.out.println("First fut`ure completed, " + i);
                    return i + 1;
                })
                .thenCompose(i -> supplyAsync(delayedValueSupplier(i + 2, i * 100), executor));
        assertThat(future.get(), is(6));
    }


}

@@ -51,16 +51,43 @@
 .Test;%0A%0A
+import java.util.Optional;%0A
 import j
@@ -173,16 +173,68 @@
 ception;
+%0Aimport java.util.concurrent.atomic.AtomicReference;
 %0A%0Aimport
@@ -1048,32 +1048,775 @@
        %7D%0A    %7D%0A%0A
+    @Test(expected = IntentionalException.class)%0A    public void exceptionCompletionAsSeenFromNextStage() throws Throwable %7B%0A%0A        // This is where we'll store the exception seen in the next stage%0A        final AtomicReference%3CThrowable%3E thrownException = new AtomicReference%3C%3E(null);%0A%0A        final CompletableFuture%3CInteger%3E future = delayedExceptionalCompletion(new IntentionalException())%0A                .whenComplete((v, t) -%3E %7B%0A                    if (t != null) %7B%0A                        thrownException.set(t);%0A                    %7D%0A                %7D);%0A%0A        try %7B%0A            future.join();%0A        %7D catch (CompletionException ex) %7B%0A            throw (Optional.ofNullable(thrownException.get()).orElse(ex));%0A        %7D%0A%0A    %7D%0A%0A
     @Test%0A    pu

Add async completeExceptionally demo