package eu.toolchain.async;

import com.google.common.collect.ImmutableList;
import org.junit.Before;
import org.junit.Test;

import java.util.List;
import java.util.concurrent.Callable;

import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;

public class DelayedCollectCoordinatorTest {
    private AsyncCaller caller;
    private StreamCollector<Object, Object> collector;
    private ResolvableFuture<Object> future;
    private Callable<AsyncFuture<Object>> callable;
    private Callable<AsyncFuture<Object>> callable2;
    private AsyncFuture<Object> f;
    private AsyncFuture<Object> f2;

    @SuppressWarnings("unchecked")
    @Before
    public void setup() throws Exception {
        caller = mock(AsyncCaller.class);
        collector = mock(StreamCollector.class);
        future = mock(ResolvableFuture.class);
        callable = mock(Callable.class);
        callable2 = mock(Callable.class);

        f = mock(AsyncFuture.class);
        f2 = mock(AsyncFuture.class);

        when(callable.call()).thenReturn(f);
        when(callable2.call()).thenReturn(f2);
    }

    @Test
    public void testCallFutureDoneMethods() throws Exception {
        final List<Callable<AsyncFuture<Object>>> callables = ImmutableList.of();

        final DelayedCollectCoordinator<Object, Object> coordinator =
            new DelayedCollectCoordinator<Object, Object>(caller, callables, collector, future, 1);

        final Object result = new Object();
        final Throwable cause = new Throwable();

        coordinator.cancelled();
        coordinator.resolved(result);
        coordinator.failed(cause);

        verify(caller).cancel(collector);
        verify(caller).resolve(collector, result);
        verify(caller).fail(collector, cause);
    }

    @Test
    public void testBasic() throws Exception {
        final List<Callable<AsyncFuture<Object>>> callables = ImmutableList.of(callable, callable2);

        final DelayedCollectCoordinator<Object, Object> coordinator =
            new DelayedCollectCoordinator<Object, Object>(caller, callables, collector, future, 1);

        final Object result = new Object();
        final Throwable cause = new Throwable();

        coordinator.run();

        coordinator.resolved(result);
        verify(collector, never()).end(2, 0, 0);

        coordinator.resolved(result);
        verify(collector).end(2, 0, 0);

        verify(caller, never()).cancel(collector);
        verify(caller, times(2)).resolve(collector, result);
        verify(caller, never()).fail(collector, cause);
    }
}

@@ -181,16 +181,56 @@
 lable;%0A%0A
+import static org.mockito.Matchers.any;%0A
 import s
@@ -724,65 +724,243 @@
 ate 
-AsyncFuture%3CObject%3E f;%0A    private AsyncFuture%3CObject%3E f2
+Callable%3CAsyncFuture%3CObject%3E%3E callable3;%0A    private Callable%3CAsyncFuture%3CObject%3E%3E callable4;%0A    private AsyncFuture%3CObject%3E f;%0A    private AsyncFuture%3CObject%3E f2;%0A    private AsyncFuture%3CObject%3E f3;%0A    private AsyncFuture%3CObject%3E f4
 ;%0A%0A 
@@ -1273,174 +1273,428 @@
 s);%0A
-%0A        f = mock(AsyncFuture.class);%0A        f2 = mock(AsyncFuture.class);%0A%0A        when(callable.call()).thenReturn(f);%0A        when(callable2.call()).thenReturn(f2
+        callable3 = mock(Callable.class);%0A        callable4 = mock(Callable.class);%0A%0A        f = mock(AsyncFuture.class);%0A        f2 = mock(AsyncFuture.class);%0A        f3 = mock(AsyncFuture.class);%0A        f4 = mock(AsyncFuture.class);%0A%0A        when(callable.call()).thenReturn(f);%0A        when(callable2.call()).thenReturn(f2);%0A        when(callable3.call()).thenReturn(f3);%0A        when(callable4.call()).thenReturn(f4
 );%0A 
@@ -3167,10 +3167,887 @@
 ;%0A    %7D%0A
+%0A    @Test%0A    public void testCancel() throws Exception %7B%0A        final List%3CCallable%3CAsyncFuture%3CObject%3E%3E%3E callables =%0A            ImmutableList.of(callable, callable2, callable3, callable4);%0A%0A        final DelayedCollectCoordinator%3CObject, Object%3E coordinator =%0A            new DelayedCollectCoordinator%3CObject, Object%3E(caller, callables, collector, future, 1);%0A%0A        final Object result = new Object();%0A        final Throwable cause = new Throwable();%0A%0A        coordinator.run();%0A%0A        coordinator.resolved(result);%0A        verify(collector, never()).end(any(Integer.class), any(Integer.class), any(Integer.class));%0A%0A        coordinator.cancelled();%0A        verify(collector).end(1, 0, 3);%0A%0A        verify(caller, times(3)).cancel(collector);%0A        verify(caller, times(1)).resolve(collector, result);%0A        verify(caller, never()).fail(collector, cause);%0A    %7D%0A%0A
 %7D%0A

Add test for cancellation in DelayedCollectCoordinatorTest