package net.dryanhild.resources;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.testng.Assert.assertEquals;
import static org.testng.Assert.assertFalse;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.Reader;
import java.nio.charset.StandardCharsets;
import net.dryanhild.resources.impl.ResourceServiceImpl;
import net.dryanhild.resources.impl.UserLocalSettingsImpl;
import net.dryanhild.resources.impl.loaders.URLLoader;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.test.annotation.DirtiesContext;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.support.AnnotationConfigContextLoader;
import org.springframework.test.context.testng.AbstractTestNGSpringContextTests;
import org.testng.annotations.Test;
@ContextConfiguration(loader = AnnotationConfigContextLoader.class)
public class ResourceServiceImplTest extends AbstractTestNGSpringContextTests {
@Configuration
static class ContextConfiguration {
@Bean
public ResourceLoader urlLoader() {
return new URLLoader();
}
@Bean
public UserLocalSettings userSettings() {
UserLocalSettings settings = new UserLocalSettingsImpl();
settings.setAppName("test-app");
return settings;
}
@Bean
public ResourceService resourceService() {
return new ResourceServiceImpl();
}
}
private static final String NON_EXISTANT_RESOURCE = "foobarbaz.txt";
private static final String GUARANTEED_RESOURCE_NAME = "my/resource/guaranteed.dat";
private static final String GUARANTEED_INPUT_STRING = "This is the test content\n\nYep it is!";
private static final byte[] GUARANTEED_INPUT_BYTES = GUARANTEED_INPUT_STRING.getBytes(StandardCharsets.UTF_8);
@Autowired
private ResourceService resourceService;
@DirtiesContext
@Test
public void addLoaderThenUsesLoader() throws Exception {
ResourceLoader dummyLoader = mock(ResourceLoader.class);
resourceService.addLoader(dummyLoader);
try {
resourceService.getResource(NON_EXISTANT_RESOURCE);
} catch (ResourceNotFoundException e) {
// Ignore. We are only testing that the dummy loader gets used.
}
verify(dummyLoader, times(1)).getResource(NON_EXISTANT_RESOURCE);
}
@DirtiesContext
@Test
public void getResourceGetsCorrectStream() throws IOException {
resourceService.addLoader(new GuaranteedGoodLoader());
InputStream input = resourceService.getResource(GUARANTEED_RESOURCE_NAME);
assertGuaranteedInput(input);
}
@DirtiesContext
@Test
public void getResourceReaderGetsCorrectReader() throws IOException {
resourceService.addLoader(new GuaranteedGoodLoader());
Reader input = resourceService.getResourceReader(GUARANTEED_RESOURCE_NAME);
assertGuaranteedInput(input);
}
@DirtiesContext
@Test(expectedExceptions = ResourceNotFoundException.class)
public void getResourceReaderWithNoLoadersFails() throws IOException {
Reader input = resourceService.getResourceReader(GUARANTEED_RESOURCE_NAME);
assertGuaranteedInput(input);
}
@DirtiesContext
@Test(expectedExceptions = ResourceNotFoundException.class)
public void getResourceReaderWithNonexistantNameFails() throws IOException {
resourceService.addLoader(new GuaranteedGoodLoader());
Reader input = resourceService.getResourceReader(NON_EXISTANT_RESOURCE);
assertGuaranteedInput(input);
}
private static class GuaranteedGoodLoader implements ResourceLoader {
@Override
public InputStream getResource(String path) throws Exception {
if (GUARANTEED_RESOURCE_NAME.equals(path)) {
return new ByteArrayInputStream(GUARANTEED_INPUT_BYTES);
}
return null;
}
}
private static void assertGuaranteedInput(Reader reader) throws IOException {
char[] chars = new char[GUARANTEED_INPUT_STRING.length()];
assertEquals(reader.read(chars), GUARANTEED_INPUT_STRING.length());
assertEquals(chars, GUARANTEED_INPUT_STRING.toCharArray());
assertFalse(reader.ready());
assertEquals(reader.read(), -1);
}
private static void assertGuaranteedInput(InputStream stream) throws IOException {
byte[] bytes = new byte[GUARANTEED_INPUT_BYTES.length];
assertEquals(stream.read(bytes), GUARANTEED_INPUT_BYTES.length);
assertEquals(bytes, GUARANTEED_INPUT_BYTES);
assertEquals(stream.available(), 0);
assertEquals(stream.read(), -1);
}
}