package com.bellini.recipecatalog.test.repository.ingredient;

import static org.hamcrest.CoreMatchers.notNullValue;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.allOf;
import static org.hamcrest.Matchers.comparesEqualTo;
import static org.hamcrest.Matchers.empty;
import static org.hamcrest.Matchers.emptyIterable;
import static org.hamcrest.Matchers.greaterThan;
import static org.hamcrest.Matchers.hasItem;
import static org.hamcrest.Matchers.hasProperty;
import static org.hamcrest.Matchers.hasSize;
import static org.hamcrest.Matchers.is;
import static org.hamcrest.Matchers.not;

import java.util.ArrayList;
import java.util.Collection;
import java.util.List;

import org.hamcrest.Matchers;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.test.context.jdbc.Sql;
import org.springframework.test.context.jdbc.Sql.ExecutionPhase;
import org.springframework.test.context.junit4.SpringRunner;
import org.springframework.transaction.annotation.Transactional;

import com.bellini.recipecatalog.dao.v1.ingredient.IngredientRepository;
import com.bellini.recipecatalog.model.v1.Ingredient;

@SpringBootTest
@RunWith(SpringRunner.class)
@Transactional
@Sql(executionPhase = ExecutionPhase.BEFORE_TEST_METHOD, scripts = { "classpath:db_seed/ingredient/data.sql" })
@Sql(executionPhase = ExecutionPhase.AFTER_TEST_METHOD, scripts = { "classpath:db_seed/ingredient/clean-data.sql" })
public class IngredientRepositoryTest {

    @Autowired
    private IngredientRepository repo;

    @Test
    public void findAll_shouldReturnNotNull() {
        Page<Ingredient> result = repo.findAll(PageRequest.of(0, Integer.MAX_VALUE)); // retrieve all elements
        assertThat(result, notNullValue());
    }

    @Test
    public void findAll_shouldReturnNotEmptyAndCorrectPageSize() {
        Page<Ingredient> result = repo.findAll(PageRequest.of(0, 5)); // retrieve half of the elements
        final List<Ingredient> content = result.getContent();
        assertThat(result, not(emptyIterable()));
        assertThat(content, hasSize(5));
    }

    @Test
    public void findAll_shouldReturnEmptyForIncorrectPageSize() {
        Page<Ingredient> result = repo.findAll(PageRequest.of(50, 5)); // this page does not exist
        assertThat(result, emptyIterable());
    }

    @Test
    public void findAll_shouldHandlePaginationCorrectly() {
        final List<Ingredient> content = repo.findAll(PageRequest.of(0, Integer.MAX_VALUE)).getContent(); // retrieve all elements
        // fetch two items each time until no results are available
        int startFrom = 0, fetch = 2, total = 0;
        List<Ingredient> contentToCheck = new ArrayList<>();
        List<Ingredient> tmpContent = null;
        do {
            tmpContent = repo.findAll(PageRequest.of(startFrom, fetch)).getContent();
            total += tmpContent.size();
            contentToCheck.addAll(tmpContent);
            ++startFrom;
        } while (!tmpContent.isEmpty());

        // check for matching number of elements
        assertThat(total, comparesEqualTo(10));

        // check that the lists are equal
        assertThat(contentToCheck, is(content));
    }

    @Test
    public void findByNameIgnoreCase_shouldReturnTheSameResult() {
        Collection<Ingredient> resultUpperCase = repo.findByNameIgnoreCase("Chicken");
        Collection<Ingredient> resultLowerCase = repo.findByNameIgnoreCase("chicken");

        // collections should be equal
        assertThat(resultUpperCase, is(resultLowerCase));
    }

    @Test
    public void findByNameIgnoreCase_shouldReturnNotNullAndEmptyWhenNoMatch() {
        Collection<Ingredient> result = repo.findByNameIgnoreCase("UnknownIngredient");

        assertThat(result, notNullValue());
        assertThat(result, empty());
    }

    @Test
    public void findByNameIgnoreCaseContaining_shouldReturnCorrectResults() {
        Page<Ingredient> result = repo.findByNameIgnoreCaseContaining("ic", PageRequest.of(0, 10));

        assertThat(result, notNullValue());
        assertThat(result, allOf(
                hasItem(Matchers.<Ingredient>hasProperty("name", is("Rice"))),
                hasItem(Matchers.<Ingredient>hasProperty("name", is("Chicken"))),
                hasItem(Matchers.<Ingredient>hasProperty("name", is("Artichoke"))),
                hasItem(Matchers.<Ingredient>hasProperty("name", is("Ricotta")))));
    }

    @Test
    public void findByNameIgnoreCaseContaining_shouldHandlePaginationCorrectly() {
        final List<Ingredient> content = repo.findByNameIgnoreCaseContaining("ic", PageRequest.of(0, Integer.MAX_VALUE)).getContent(); // retrieve all elements
        // fetch two items each time until no results are available
        int startFrom = 0, fetch = 1, total = 0;
        List<Ingredient> contentToCheck = new ArrayList<>();
        List<Ingredient> tmpContent = null;
        do {
            tmpContent = repo.findByNameIgnoreCaseContaining("ic", PageRequest.of(startFrom, fetch)).getContent();
            total += tmpContent.size();
            contentToCheck.addAll(tmpContent);
            ++startFrom;
        } while (!tmpContent.isEmpty());

        // check for matching number of elements
        assertThat(total, comparesEqualTo(4));

        // check that the lists are equal
        assertThat(contentToCheck, is(content));
    }
    
    @Test
    public void save_shouldStoreElement() {
        Ingredient ingr = testDishType();
        Ingredient stored = repo.save(ingr);

        assertThat(stored, hasProperty("id", allOf(notNullValue(), greaterThan((long) 0))));
    }

    private Ingredient testDishType() {
        Ingredient ingr = new Ingredient();
        ingr.setName("Tuna");
        return ingr;
    }
}

@@ -621,16 +621,103 @@
 ers.not;
+%0Aimport static org.junit.Assert.assertFalse;%0Aimport static org.junit.Assert.assertTrue;
 %0A%0Aimport
@@ -789,16 +789,43 @@
 il.List;
+%0Aimport java.util.Optional;
 %0A%0Aimport
@@ -5720,13 +5720,9 @@
   %7D%0A
-    
 %0A
+
     
@@ -6069,24 +6069,24 @@
 me(%22Tuna%22);%0A
-
         retu
@@ -6099,11 +6099,545 @@
 r;%0A    %7D
+%0A%0A    @Test%0A    public void findById_shouldReturnCorrectElement() %7B%0A        Optional%3CIngredient%3E dtOpt = repo.findById((long) 6);%0A        assertThat(dtOpt, notNullValue());%0A        assertTrue(dtOpt.isPresent());%0A        assertThat(dtOpt.get().getId(), comparesEqualTo((long) 6));%0A    %7D%0A%0A    @Test%0A    public void findById_shouldReturnEmptyOptionalWhenNotFound() %7B%0A        Optional%3CIngredient%3E dtOpt = repo.findById((long) 11); // not existent id%0A        assertThat(dtOpt, notNullValue());%0A        assertFalse(dtOpt.isPresent());%0A    %7D
 %0A%7D%0A

Add tests for findById - ingredient