package de.gessnerfl.fakesmtp.controller;

import de.gessnerfl.fakesmtp.model.Email;
import de.gessnerfl.fakesmtp.repository.EmailRepository;
import org.hamcrest.BaseMatcher;
import org.hamcrest.Description;
import org.hamcrest.Matcher;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.runners.MockitoJUnitRunner;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.ui.Model;

import static org.junit.Assert.*;
import static org.mockito.Matchers.any;
import static org.mockito.Mockito.*;

@RunWith(MockitoJUnitRunner.class)
public class EmailControllerTest {
    @Mock
    private Model model;
    @Mock
    private EmailRepository emailRepository;
    @InjectMocks
    private EmailController sut;

    @Test
    public void shouldReturnEmailsPaged() {
        final Page<Email> page = createFirstPageEmail();
        when(emailRepository.findAll(any(Pageable.class))).thenReturn(page);

        String result = sut.getAll(0, 5, model);

        assertEquals(EmailController.EMAIL_LIST_VIEW, result);

        verify(emailRepository).findAll(argThat(matchPageable(0, 5)));
        verifyNoMoreInteractions(emailRepository);
        verify(model).addAttribute(EmailController.EMAIL_LIST_MODEL_NAME, page);
    }

    @Test
    public void shouldReturnRedirectToFirstPageWhenRequestedPageIsOutOfRange() {
        final Page<Email> page = mock(Page.class);
        when(page.getTotalElements()).thenReturn(8L);
        when(page.getTotalPages()).thenReturn(2);
        when(page.getNumber()).thenReturn(3, 0);
        when(page.getNumberOfElements()).thenReturn(0, 5);
        when(emailRepository.findAll(any(Pageable.class))).thenReturn(page);

        String result = sut.getAll(2, 5, model);

        assertEquals(EmailController.REDIRECT_EMAIL_LIST_VIEW, result);

        verify(emailRepository).findAll(argThat(matchPageable(2, 5)));
        verifyNoMoreInteractions(emailRepository);
    }

    @Test
    public void shouldRedirectToFirstPageWhenPageNumberIsBelowNull() {
        String result = sut.getAll(-1, 5, model);

        assertEquals(EmailController.REDIRECT_EMAIL_LIST_VIEW, result);
        verifyZeroInteractions(emailRepository);
    }

    @Test
    public void shouldRedirectToFirstPageWhenPageSizeIsNull() {
        String result = sut.getAll(0, 0, model);

        assertEquals(EmailController.REDIRECT_EMAIL_LIST_VIEW, result);
        verifyZeroInteractions(emailRepository);
    }

    @Test
    public void shouldRedirectToFirstPageWhenPageSizeIsBelowNull() {
        String result = sut.getAll(0, -1, model);

        assertEquals(EmailController.REDIRECT_EMAIL_LIST_VIEW, result);
        verifyZeroInteractions(emailRepository);
    }

    @Test
    public void shouldReturnSingleEmailWhenIdIsValid() {
        final long id = 12L;
        final Email mail = mock(Email.class);
        when(emailRepository.findOne(id)).thenReturn(mail);

        String result = sut.getEmailById(id, model);

        assertEquals(EmailController.SINGLE_EMAIL_VIEW, result);

        verify(emailRepository).findOne(id);
        verify(model).addAttribute(EmailController.SINGLE_EMAIL_MODEL_NAME, mail);
    }

    @Test
    public void shouldReturnRedirectToListPageWhenIdIsNotValid() {
        final long id = 12L;
        final Page<Email> page = createFirstPageEmail();
        when(emailRepository.findOne(id)).thenReturn(null);
        when(emailRepository.findAll(any(Pageable.class))).thenReturn(page);

        String result = sut.getEmailById(id, model);

        assertEquals(EmailController.REDIRECT_EMAIL_LIST_VIEW, result);

        verify(emailRepository).findOne(id);
    }

    private Page<Email> createFirstPageEmail() {
        Page<Email> page = mock(Page.class);
        when(page.getTotalElements()).thenReturn(8L);
        when(page.getTotalPages()).thenReturn(2);
        when(page.getNumber()).thenReturn(0);
        when(page.getNumberOfElements()).thenReturn(5);
        return page;
    }


    private Matcher<Pageable> matchPageable(int page, int size) {
        return new BaseMatcher<Pageable>() {

            @Override
            public void describeTo(Description description) {
                description.appendText("Pagable should have pageNumber ").appendValue(page).appendText(" and pageSize ").appendValue(size);
            }

            @Override
            public boolean matches(Object item) {
                if (item instanceof Pageable) {
                    Pageable p = (Pageable) item;
                    return p.getPageNumber() == page && p.getPageSize() == size;
                }
                return false;
            }
        };
    }
}
@@ -1647,19 +1647,16 @@
 Return(3
-, 0
 );%0A     
@@ -1702,19 +1702,16 @@
 nReturn(
-0, 
 5);%0A    
@@ -1819,17 +1819,17 @@
 .getAll(
-2
+3
 , 5, mod
@@ -1969,17 +1969,675 @@
 ageable(
-2
+3, 5)));%0A        verifyNoMoreInteractions(emailRepository);%0A    %7D%0A%0A    @Test%0A    public void shouldNotRedirectToFirstPageWhenNoDataIsAvailable() %7B%0A        final Page%3CEmail%3E page = mock(Page.class);%0A        when(page.getTotalElements()).thenReturn(0L);%0A        when(page.getTotalPages()).thenReturn(0);%0A        when(page.getNumber()).thenReturn(0);%0A        when(page.getNumberOfElements()).thenReturn(0);%0A        when(emailRepository.findAll(any(Pageable.class))).thenReturn(page);%0A%0A        String result = sut.getAll(0, 5, model);%0A%0A        assertEquals(EmailController.EMAIL_LIST_VIEW, result);%0A%0A        verify(emailRepository).findAll(argThat(matchPageable(0
 , 5)));%0A

fix broken unit test