package com.test.spring;

import java.lang.reflect.Field;

import org.jmock.Expectations;
import org.jmock.Mockery;
import org.jmock.integration.junit4.JUnit4Mockery;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import org.springframework.core.io.Resource;

public class EhCacheManagerFactoryBeanTest {

    private static final Resource[] configLocations = new Resource[2];

    private Mockery mockContext;

    private EhCacheManagerFactoryBean bean;

    @Before
    public void before() throws Exception {
        mockContext = new JUnit4Mockery();

        configLocations[0] = mockContext.mock(Resource.class, "Resource_0");
        configLocations[1] = mockContext.mock(Resource.class, "Resource_1");

        bean = new EhCacheManagerFactoryBean();
    }

    @Test
    public void testSetConfigLocations_Fallback() throws Exception {

        mockContext.checking(new Expectations() {
            {
                one(configLocations[0]).exists();
                will(returnValue(false));

                one(configLocations[1]).exists();
                will(returnValue(true));
            }
        });

        bean.setConfigLocations(configLocations);

        // first one doesn't exist
        validateConfigLocation(configLocations[1]);
    }

    @Test
    public void testSetConfigLocations_FallbackFails() throws Exception {

        configLocations[0] = null;

        mockContext.checking(new Expectations() {
            {
                one(configLocations[1]).exists();
                will(returnValue(false));
            }
        });

        bean.setConfigLocations(configLocations);

        // first one doesn't exist, neither does the second one, should be null
        validateConfigLocation(null);
    }

    @Test
    public void testSetConfigLocations_NoFallbackNeeded() throws Exception {

        mockContext.checking(new Expectations() {
            {
                one(configLocations[0]).exists();
                will(returnValue(true));

                one(configLocations[1]).exists();
                will(returnValue(false));
            }
        });

        bean.setConfigLocations(configLocations);

        // first one does exist, use that
        validateConfigLocation(configLocations[0]);
    }

    @Test
    public void testSetConfigLocations_NoneProvided() throws Exception {
        // nothing was provided, should still be null
        bean.setConfigLocations(null);
        validateConfigLocation(null);

        // empty list provided, should still be null
        bean.setConfigLocations(new Resource[0]);
        validateConfigLocation(null);
    }

    @Test
    public void testSetConfigLocations_NullEntry() throws Exception {
        configLocations[0] = null;

        mockContext.checking(new Expectations() {
            {
                one(configLocations[1]).exists();
                will(returnValue(true));
            }
        });

        bean.setConfigLocations(configLocations);

        // first one is null, should fallback to second one
        validateConfigLocation(configLocations[1]);
    }

    private void validateConfigLocation(final Resource expectedConfigLocation)
            throws Exception {

        Field field =
                org.springframework.cache.ehcache.EhCacheManagerFactoryBean.class.getDeclaredField("configLocation");
        field.setAccessible(true);
        Resource configLocation = (Resource) field.get(bean);

        Assert.assertEquals(expectedConfigLocation, configLocation);
    }
}
