package com.millross.blog.async;

import org.junit.Test;

import java.util.concurrent.CompletableFuture;
import java.util.concurrent.Executor;
import java.util.concurrent.Executors;
import java.util.function.Supplier;

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

/**
 *
 */
public class SimpleCompletableFutureTest {

    // We'll allow a 3-sized thread pool for async execution, rather than using the fork/join pool for asynchronous
    // value generation
    final Executor executor = Executors.newFixedThreadPool(3);

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

    @Test
    public void demoThenApply() throws Exception {
        final CompletableFuture<Integer> future = 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)
                .thenApply(i -> {
                    System.out.println("First future completed, " + i);
                    return i;
                })
                .thenCompose(i -> specifiedDelayFuture(i * 100, 2));
        assertThat(future.get(), is(2));
    }

    public Supplier<Integer> delayedValueSupplier(final int value) {
        return () -> {
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                throw new RuntimeException("Problem while waiting to return value");
            }
            return value;
        };
    }

    public CompletableFuture<Integer> specifiedDelayFuture(final int delay, final int finalValue) {
        final CompletableFuture<Integer> future = new CompletableFuture<>();
        final Thread futureThread = new Thread(() -> {
            try {
                Thread.sleep(delay);
                future.complete(finalValue);
            } catch (Throwable t) {
                future.completeExceptionally(t);
            }

        });
        // Kick off processing
        futureThread.run();
        return future;
    }

}

@@ -1527,38 +1527,61 @@
 -%3E s
-pecifiedDelayFuture(
+upplyAsync(delayedValueSupplier(2, 
 i * 100
+)
 , 
-2
+executor
 ));%0A
@@ -1689,32 +1689,177 @@
 al int value) %7B%0A
+        return delayedValueSupplier(value, 1000);%0A    %7D%0A%0A    public Supplier%3CInteger%3E delayedValueSupplier(final int value, final int delayMs) %7B%0A
         return (
@@ -1912,20 +1912,23 @@
 d.sleep(
-1000
+delayMs
 );%0A     
@@ -2094,16 +2094,16 @@
  value;%0A
+
         
@@ -2116,539 +2116,6 @@
  %7D%0A%0A
-    public CompletableFuture%3CInteger%3E specifiedDelayFuture(final int delay, final int finalValue) %7B%0A        final CompletableFuture%3CInteger%3E future = new CompletableFuture%3C%3E();%0A        final Thread futureThread = new Thread(() -%3E %7B%0A            try %7B%0A                Thread.sleep(delay);%0A                future.complete(finalValue);%0A            %7D catch (Throwable t) %7B%0A                future.completeExceptionally(t);%0A            %7D%0A%0A        %7D);%0A        // Kick off processing%0A        futureThread.run();%0A        return future;%0A    %7D%0A%0A
 %7D%0A

Replace specifiedDelayFuture with use of an existing CompletableFuture factory method. Let's not roll our own futures where we don't need to!