package org.rocket.network.acara;

import com.github.blackrush.acara.Listener;
import com.google.common.util.concurrent.MoreExecutors;
import org.fungsi.concurrent.Future;
import org.fungsi.concurrent.Worker;
import org.fungsi.concurrent.Workers;
import org.junit.Before;
import org.junit.Test;
import org.rocket.MoreCollectors;
import org.rocket.network.*;
import org.rocket.network.event.ConnectEvent;
import org.rocket.network.event.ReceiveEvent;
import org.rocket.network.event.SuperviseEvent;

import static org.hamcrest.core.IsEqual.equalTo;
import static org.junit.Assert.*;
import static org.mockito.Mockito.mock;

public class RocketListenerBuilderTest {

    private RocketListenerBuilder b;
    private NetworkClient client;
    private Worker worker;

    @Before
    public void setUp() throws Exception {
        b = new RocketListenerBuilder();
        client = mock(NetworkClient.class);
        worker = Workers.wrap(MoreExecutors.directExecutor());
    }

    static class WithConnect {
        @Connect public void method(){}
    }
    static class WithDisconnect {
        @Disconnect public void method() {}
    }
    static class WithReceive {
        @Receive public void method(String foobar) {}
    }
    static class WithSupervise {
        @Supervise public void method(NullPointerException e) {}
    }
    static class Invalids {
        @Connect public void toomuch1(String arguments) {}
        @Disconnect public void toomuch2(String arguments) {}

        @Receive public void toofew1() {}
        @Supervise public void toofew2() {}
    }

    @Test
    public void testScanConnect() throws Exception {
        Listener l = b.build(new WithConnect()).collect(MoreCollectors.uniq());
        Events.ConnectEventMetadata meta = (Events.ConnectEventMetadata) l.getHandledEvent();

        Future<Object> resp = l.dispatch(new ConnectEvent(client, false), worker);

        assertFalse("disconnecting", meta.disconnecting);
        assertTrue("dispatch response is success", resp.isSuccess());
    }

    @Test
    public void testScanDisconnect() throws Exception {
        Listener l = b.build(new WithDisconnect()).collect(MoreCollectors.uniq());
        Events.ConnectEventMetadata meta = (Events.ConnectEventMetadata) l.getHandledEvent();

        Future<Object> resp = l.dispatch(new ConnectEvent(client, true), worker);

        assertTrue("disconnecting", meta.disconnecting);
        assertTrue("dispatch response is success", resp.isSuccess());
    }

    @Test
    public void testScanReceive() throws Exception {
        Listener l = b.build(new WithReceive()).collect(MoreCollectors.uniq());
        Events.ComponentWiseEventMetadata meta = (Events.ComponentWiseEventMetadata) l.getHandledEvent();

        Future<Object> resp = l.dispatch(new ReceiveEvent(client, "foobar"), worker);

        assertThat("component class", meta.componentClass, equalTo(String.class));
        assertTrue("dispatch response is success", resp.isSuccess());
    }

    @Test
    public void testScanSupervise() throws Exception {
        Listener l = b.build(new WithSupervise()).collect(MoreCollectors.uniq());
        Events.ComponentWiseEventMetadata meta = (Events.ComponentWiseEventMetadata) l.getHandledEvent();

        Future<Object> resp = l.dispatch(new SuperviseEvent(client, new NullPointerException()), worker);

        assertThat("component class", meta.componentClass, equalTo(NullPointerException.class));
        assertTrue("dispatch response is success", resp.isSuccess());
    }

    @Test
    public void testScanError() throws Exception {
        long count = b.build(new Invalids()).count();

        assertThat("scanned listeners", count, equalTo(0L));
    }
}
@@ -490,16 +490,103 @@
 seEvent;
+%0Aimport org.rocket.network.props.PropIds;%0Aimport org.rocket.network.props.PropPresence;
 %0A%0Aimport
@@ -701,16 +701,56 @@
 to.mock;
+%0Aimport static org.mockito.Mockito.when;
 %0A%0Apublic
@@ -1442,32 +1442,282 @@
 ion e) %7B%7D%0A    %7D%0A
+    static class WithValidation %7B%0A        @PropPresence(String.class)%0A        @Receive%0A        public void hard(Object msg) %7B%7D%0A%0A        @PropPresence(String.class)%0A        @Receive(softValidation = true)%0A        public void soft(Object msg) %7B%7D%0A    %7D%0A
     static class
@@ -4075,10 +4075,747 @@
 );%0A    %7D
+%0A%0A    @Test%0A    public void testScanValidated() throws Exception %7B%0A        @SuppressWarnings(%22unchecked%22)%0A        MutProp%3CObject%3E prop = mock(MutProp.class);%0A        PropId pid = PropIds.type(String.class);%0A        when(client.getProp(pid)).thenReturn(prop);%0A%0A        Object%5B%5D tmp = b.build(new WithValidation()).toArray();%0A        Listener hard = (Listener) tmp%5B0%5D;%0A        Listener soft = (Listener) tmp%5B1%5D;%0A%0A        Future%3CObject%3E hardResp = hard.dispatch(new ReceiveEvent(client, %22foo%22), worker);%0A        Future%3CObject%3E softResp = soft.dispatch(new ReceiveEvent(client, %22bar%22), worker);%0A%0A        assertTrue(%22hard response is failure%22, hardResp.isFailure());%0A        assertTrue(%22soft response is success%22, softResp.isSuccess());%0A    %7D
 %0A%7D

Test listener's validation