package com.biglakesystems.scamp.impl.spring;

import com.biglakesystems.scamp.source.Source;
import com.biglakesystems.scamp.source.SourceLocator;
import org.junit.Before;
import org.junit.Test;
import org.springframework.core.io.Resource;
import org.springframework.core.io.support.ResourcePatternResolver;

import java.util.Arrays;

import static org.easymock.EasyMock.*;
import static org.junit.Assert.*;

/**
 * {@link TestSpringSourceLocator} provides unit test coverage for {@link SpringSourceLocator}.
 * <p/>
 * Copyright (c) 2014 Big Lake Systems, LLC. All rights reserved.
 */
public class TestSpringSourceLocator
{
    private final ResourcePatternResolver m_mockResolver;

    /**
     * Construct a {@link TestSpringSourceLocator} instance.
     */
    public TestSpringSourceLocator()
    {
        super();
        m_mockResolver = createMock(ResourcePatternResolver.class);
    }

    @Before
    public void resetCommonMocks()
    {
        reset(m_mockResolver);
    }

    /**
     * Test the implementation of {@link SourceLocator#locate(String)} when the resource is found.
     */
    @Test
    public void testLocate_found()
    {
        final Resource mockResource2 = createMock(Resource.class);
        final Resource mockResource3 = createMock(Resource.class);
        final Resource mockResource4 = createMock(Resource.class);

        /* Should check each configured prefix until found. */
        expect(m_mockResolver.getResource(eq("prefix1/testName"))).andReturn(null).atLeastOnce();
        expect(m_mockResolver.getResource(eq("prefix2/testName"))).andReturn(mockResource2).atLeastOnce();
        expect(m_mockResolver.getResource(eq("prefix3/testName"))).andReturn(mockResource3).atLeastOnce();
        expect(m_mockResolver.getResource(eq("prefix4/testName"))).andReturn(mockResource4).atLeastOnce();

        /* Should verify that each resource exists and is readable. */
        expect(mockResource2.exists()).andReturn(false).atLeastOnce();
        expect(mockResource3.exists()).andReturn(true).atLeastOnce();
        expect(mockResource3.isReadable()).andReturn(false).atLeastOnce();
        expect(mockResource4.exists()).andReturn(true).atLeastOnce();
        expect(mockResource4.isReadable()).andReturn(true).atLeastOnce();

        /* Run the test and verify expectations. */
        replayCommonMocks();
        replay(mockResource2, mockResource3, mockResource4);
        final SourceLocator instance = new SpringSourceLocator(m_mockResolver, Arrays.asList("prefix1/", "prefix2/",
                "prefix3/", "prefix4/", "prefix5/"));
        final ResourceSource source = (ResourceSource) instance.locate("testName");
        assertNotNull(source);
        assertSame(mockResource4, source.getResource());
        verifyCommonMocks();
        verify(mockResource2, mockResource3, mockResource4);
    }

    /**
     * Test the implementation of {@link SourceLocator#locate(String)} when the resource is not found.
     */
    @Test
    public void testLocate_notFound()
    {
        final Resource mockResource2 = createMock(Resource.class);
        final Resource mockResource3 = createMock(Resource.class);

        /* Should check each configured prefix until found. */
        expect(m_mockResolver.getResource(eq("prefix1/testName"))).andReturn(null).atLeastOnce();
        expect(m_mockResolver.getResource(eq("prefix2/testName"))).andReturn(mockResource2).atLeastOnce();
        expect(m_mockResolver.getResource(eq("prefix3/testName"))).andReturn(mockResource3).atLeastOnce();

        /* Should verify that each resource exists and is readable. */
        expect(mockResource2.exists()).andReturn(false).atLeastOnce();
        expect(mockResource3.exists()).andReturn(true).atLeastOnce();
        expect(mockResource3.isReadable()).andReturn(false).atLeastOnce();

        /* Run the test and verify expectations. */
        replayCommonMocks();
        replay(mockResource2, mockResource3);
        final SourceLocator instance = new SpringSourceLocator(m_mockResolver, Arrays.asList("prefix1/", "prefix2/",
                "prefix3/"));
        assertNull(instance.locate("testName"));
        verifyCommonMocks();
        verify(mockResource2, mockResource3);
    }

    private void replayCommonMocks()
    {
        replay(m_mockResolver);
    }

    private void verifyCommonMocks()
    {
        verify(m_mockResolver);
    }
}
