package org.rocket.network.props;

import com.google.common.collect.ImmutableList;
import org.junit.Test;
import org.mockito.InOrder;
import org.rocket.network.MutProp;
import org.rocket.network.NetworkClient;
import org.rocket.network.PropId;
import org.rocket.network.PropValidator;

import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.reflect.AnnotatedElement;
import java.util.List;

import static org.hamcrest.CoreMatchers.equalTo;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.junit.Assert.fail;
import static org.mockito.Mockito.inOrder;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;

public class PropValidationsTest {
    @Retention(RetentionPolicy.RUNTIME)
    @PropPresence(String.class)
    @interface FooBar {}

    @SuppressWarnings("UnusedDeclaration")
    @FooBar
    @PropPresence(Integer.class)
    private static void annotated() {}

    @Test
    public void testFetchValidators() throws Exception {
        // given
        AnnotatedElement target = PropValidationsTest.class.getDeclaredMethod("annotated");
        PropValidatorInstantiator ins = PropValidations::reflectiveInstantiator;

        // when
        List<PropValidator> validators = PropValidations.fetchValidators(target, ins);

        // then
        assertThat(validators.size(), equalTo(2));
    }

    @Test
    public void testValidateSuccess() throws Exception {
        // given
        NetworkClient client = mock(NetworkClient.class);
        AnnotatedElement target = PropValidationsTest.class.getDeclaredMethod("annotated");
        List<PropValidator> validators = PropValidations.fetchValidators(target, PropValidations::reflectiveInstantiator);
        PropValidator validator = PropValidator.aggregate(ImmutableList.copyOf(validators));

        @SuppressWarnings("unchecked")
        MutProp<Object> strProp = mock(MutProp.class),
                intProp = mock(MutProp.class);
        PropId strpid = PropIds.type(String.class),
                intpid = PropIds.type(Integer.class);

        // when
        when(strProp.isDefined()).thenReturn(true);
        when(intProp.isDefined()).thenReturn(true);

        when(client.getProp(strpid)).thenReturn(strProp);
        when(client.getProp(intpid)).thenReturn(intProp);

        validator.validate(client);

        // then
        InOrder o = inOrder(client, strProp, intProp);
        o.verify(client).getProp(strpid);
        o.verify(strProp).isDefined();
        o.verify(client).getProp(intpid);
        o.verify(intProp).isDefined();
        o.verifyNoMoreInteractions();
    }

    @Test(expected = AssertionError.class)
    public void testValidateFailure() throws Exception {
        // given
        NetworkClient client = mock(NetworkClient.class);
        AnnotatedElement target = PropValidationsTest.class.getDeclaredMethod("annotated");
        List<PropValidator> validators = PropValidations.fetchValidators(target, PropValidations::reflectiveInstantiator);
        PropValidator validator = PropValidator.aggregate(ImmutableList.copyOf(validators));

        @SuppressWarnings("unchecked")
        MutProp<Object> strProp = mock(MutProp.class),
                intProp = mock(MutProp.class);

        // when
        when(strProp.isDefined()).thenReturn(true);
        when(intProp.isDefined()).thenReturn(false);

        when(client.getProp(PropIds.type(String.class))).thenReturn(strProp);
        when(client.getProp(PropIds.type(Integer.class))).thenReturn(intProp);

        validator.validate(client);

        // then
        fail();

    }
}
@@ -91,18 +91,21 @@
 org.
-junit.Test
+fungsi.Either
 ;%0Aim
@@ -117,98 +117,66 @@
 org.
-mockito.InOrder;%0Aimport org.rocket.network.MutProp;%0Aimport org.rocket.network.NetworkClien
+fungsi.Unit;%0Aimport org.junit.Before;%0Aimport org.junit.Tes
 t;%0Ai
@@ -189,29 +189,23 @@
 org.
-rocket.network.PropId
+mockito.InOrder
 ;%0Aim
@@ -228,29 +228,17 @@
 network.
-PropValidator
+*
 ;%0A%0Aimpor
@@ -381,16 +381,57 @@
 il.List;
+%0Aimport java.util.NoSuchElementException;
 %0A%0Aimport
@@ -601,95 +601,9 @@
 ito.
-inOrder;%0Aimport static org.mockito.Mockito.mock;%0Aimport static org.mockito.Mockito.when
+*
 ;%0A%0Ap
@@ -636,16 +636,17 @@
 sTest %7B%0A
+%0A
     @Ret
@@ -863,24 +863,606 @@
 d() %7B%7D%0A%0A    
+private static final class BadValidator implements PropValidator %7B%0A        public BadValidator(String yo, String lo) %7B%7D%0A        public BadValidator(PropPresence notInStack) %7B%7D%0A%0A        @Override%0A        public Either%3CUnit, Throwable%3E validate(NetworkClient client) %7B%0A            return Unit.left();%0A        %7D%0A    %7D%0A    @PropValidate(BadValidator.class)%0A    private static void badlyValidated() %7B%7D%0A%0A%0A    private PropValidatorInstantiator instantiator;%0A%0A    @Before%0A    public void setUp() throws Exception %7B%0A        instantiator = PropValidations::reflectiveInstantiator;%0A    %7D%0A%0A    
 @Test%0A    pu
@@ -1623,89 +1623,8 @@
 ed%22)
-;%0A        PropValidatorInstantiator ins = PropValidations::reflectiveInstantiator
 ;%0A%0A 
@@ -1722,16 +1722,25 @@
 get, ins
+tantiator
 );%0A%0A    
@@ -2128,36 +2128,9 @@
 et, 
-PropValidations::reflectiveI
+i
 nsta
@@ -3386,36 +3386,9 @@
 et, 
-PropValidations::reflectiveI
+i
 nsta
@@ -3988,10 +3988,351 @@
 ;%0A%0A    %7D
+%0A%0A    @Test%0A    public void testBadValidation() throws Exception %7B%0A        try %7B%0A            PropValidations.fetchValidators(PropValidationsTest.class.getDeclaredMethod(%22badlyValidated%22), instantiator);%0A            fail();%0A        %7D catch (NoSuchElementException ignored) %7B%0A        %7D catch (Exception e) %7B%0A            fail();%0A        %7D%0A    %7D
 %0A%7D

Test bad validator