package nl.meg.function.internal;

import nl.meg.AbstractMockitoTest;
import nl.meg.function.FunctionAdapter;
import nl.meg.function.ValidationException;
import nl.meg.validation.ValidationContext;
import nl.meg.validation.Validator;
import org.junit.Before;
import org.junit.Test;
import org.mockito.Mock;

import java.util.EnumMap;
import java.util.List;
import java.util.Map;
import java.util.function.Function;

import static org.hamcrest.CoreMatchers.is;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertThat;
import static org.mockito.Matchers.any;
import static org.mockito.Matchers.eq;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;

public class FunctionAdapterImplTest extends AbstractMockitoTest {

    private enum E {

    }

    private FunctionAdapter<E, String, Integer> adapter;

    @Mock
    private ValidationContext<E, String> context;

    @Mock
    private Validator<E, String> validator;

    @Mock
    private Function<String, Integer> function;

    @Before
    public void setUp() {
        this.adapter = new FunctionAdapterImpl<>();
    }

    @Test
    public void testApply() {
        when(validator.validate(eq("TEST"), any(ValidationContext.class))).thenReturn(context);
        when(context.isValid()).thenReturn(true);
        adapter.preValidate(validator, function).apply("TEST");
        verify(function).apply("TEST");
    }

    @Test
    public void testApply_ThrowsValidationException() {
        when(validator.validate(eq("TEST"), any(ValidationContext.class))).thenReturn(context);
        when(context.isValid()).thenReturn(false);

        final EnumMap<E, List<Map<String, ?>>> errors = new EnumMap<>(E.class);
        when(context.getErrors()).thenReturn(errors);

        try {
            adapter.preValidate(validator, function).apply("TEST");
        } catch (ValidationException e) {
            assertEquals(errors, e.getErrors());
        }
    }

    @Test
    public void testValidate() {
        when(validator.validate(eq("TEST"), any(ValidationContext.class))).thenReturn(context);
        when(context.isValid()).thenReturn(true);
        when(function.apply("TEST")).thenReturn(0);
        assertThat(adapter.preValidate(validator, function).apply("TEST"), is(0));
    }

}

@@ -854,24 +854,82 @@
 %3E adapter;%0A%0A
+    @Mock%0A    private Validator%3CE, String%3E preValidator;%0A%0A
     @Mock%0A  
@@ -967,17 +967,20 @@
 String%3E 
-c
+preC
 ontext;%0A
@@ -1019,25 +1019,96 @@
 %3CE, 
-String%3E validator
+Integer%3E postValidator;%0A%0A    @Mock%0A    private ValidationContext%3CE, Integer%3E postContext
 ;%0A%0A 
@@ -1292,21 +1292,27 @@
 oid test
-Apply
+PreValidate
 () %7B%0A   
@@ -1313,33 +1313,36 @@
  %7B%0A        when(
-v
+preV
 alidator.validat
@@ -1389,33 +1389,36 @@
 s))).thenReturn(
-c
+preC
 ontext);%0A       
@@ -1415,33 +1415,36 @@
 );%0A        when(
-c
+preC
 ontext.isValid()
@@ -1483,33 +1483,36 @@
 ter.preValidate(
-v
+preV
 alidator, functi
@@ -1611,13 +1611,19 @@
 test
-Apply
+PreValidate
 _Thr
@@ -1654,33 +1654,36 @@
  %7B%0A        when(
-v
+preV
 alidator.validat
@@ -1730,33 +1730,36 @@
 s))).thenReturn(
-c
+preC
 ontext);%0A       
@@ -1756,33 +1756,36 @@
 );%0A        when(
-c
+preC
 ontext.isValid()
@@ -1895,25 +1895,28 @@
        when(
-c
+preC
 ontext.getEr
@@ -1982,33 +1982,36 @@
 ter.preValidate(
-v
+preV
 alidator, functi
@@ -2193,17 +2193,20 @@
    when(
-v
+preV
 alidator
@@ -2269,17 +2269,20 @@
 nReturn(
-c
+preC
 ontext);
@@ -2295,17 +2295,20 @@
    when(
-c
+preC
 ontext.i
@@ -2430,28 +2430,672 @@
 ate(
-validator, function)
+preValidator, function).apply(%22TEST%22), is(0));%0A    %7D%0A%0A    @Test%0A    public void testPreAndPostValidate() %7B%0A        when(preValidator.validate(eq(%22TEST%22), any(ValidationContext.class))).thenReturn(preContext);%0A        when(preContext.isValid()).thenReturn(true);%0A        when(postValidator.validate(eq(0), any(ValidationContext.class))).thenReturn(postContext);%0A        when(postContext.isValid()).thenReturn(true);%0A        when(function.apply(%22TEST%22)).thenReturn(0);%0A        final Function%3CString, Integer%3E f1 = adapter.preValidate(preValidator, function);%0A        final Function%3CString, Integer%3E f2 = adapter.postValidate(postValidator, f1);%0A        assertThat(f1
 .app
@@ -3120,11 +3120,10 @@
 ;%0A    %7D%0A
-%0A
 %7D%0A

Test postValidation