name.didier.david.test4j.unit.TestResourceHandler Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of ndd-test4j Show documentation
Show all versions of ndd-test4j Show documentation
Test4J provides testing support.
The newest version!
package name.didier.david.test4j.unit;
import static java.lang.String.format;
import static java.nio.charset.StandardCharsets.UTF_8;
import static name.didier.david.check4j.ConciseCheckers.checkNotNull;
import java.io.Closeable;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.net.URL;
import java.util.List;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.ArrayUtils;
import org.apache.commons.lang3.reflect.FieldUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.google.common.io.Resources;
/**
* Handle {@link TestResource}s and their associated resources.
*
* @author ddidier
*/
public class TestResourceHandler {
/** The supported types of resources that can be injected. */
private static final Class>[] SUPPORTED_TYPES = new Class[] { URL.class, File.class, String.class,
List.class, InputStream.class, InputStreamReader.class, };
/** The associated logger. */
private static final Logger logger = LoggerFactory.getLogger(TestResourceHandler.class);
/** The naming strategy. */
private final TestResourceNamingStrategy namingStrategy;
/** The resolution strategy. */
private final TestResourceResolutionStrategy resolutionStrategy;
/**
* Default constructor using a {@link DefaultTestResourceNamingStrategy} and a
* {@link DefaultTestResourceResolutionStrategy} strategies.
*/
public TestResourceHandler() {
this(new DefaultTestResourceNamingStrategy(), new DefaultTestResourceResolutionStrategy());
}
/**
* Default constructor.
*
* @param namingStrategy the naming strategy.
* @param resolutionStrategy the resolution strategy.
*/
public TestResourceHandler(
final TestResourceNamingStrategy namingStrategy,
final TestResourceResolutionStrategy resolutionStrategy) {
super();
this.namingStrategy = checkNotNull(namingStrategy, "namingStrategy");
this.resolutionStrategy = checkNotNull(resolutionStrategy, "resolutionStrategy");
}
/**
* @return the naming strategy.
*/
public TestResourceNamingStrategy getNamingStrategy() {
return namingStrategy;
}
/**
* @return the resolution strategy.
*/
public TestResourceResolutionStrategy getResolutionStrategy() {
return resolutionStrategy;
}
/**
* Find the resource with the given pattern as a {@link File}.
*
* @param pattern the pattern to search for.
* @param testInstance the instance of the running test.
* @param testMethod the method of the running test.
* @return the file if found.
* @throws TestResourceException if the resource cannot be found.
*/
public File findFile(final String pattern, final Object testInstance, final Method testMethod) {
return new File(findUrl(pattern, testInstance, testMethod).getPath());
}
/**
* Find the resource with the given pattern as a {@link URL}.
*
* @param pattern the pattern to search for.
* @param testInstance the instance of the running test.
* @param testMethod the method of the running test.
* @return the URL if found.
* @throws TestResourceException if the resource cannot be found.
*/
public URL findUrl(final String pattern, final Object testInstance, final Method testMethod) {
Class> testClass = testInstance.getClass();
String resourceName = namingStrategy.resourceName(pattern, testClass, null, testMethod);
URL url = resolutionStrategy.findResource(testClass, resourceName);
if (url == null) {
String message = format("Resource not found for pattern '%s'", pattern);
throw new TestResourceException(message, testInstance, testMethod);
}
return url;
}
/**
* Load the content of the resource with the given pattern.
*
* @param pattern the pattern to search for.
* @param testInstance the instance of the running test.
* @param testMethod the method of the running test.
* @return the content of the resource if found.
* @throws TestResourceException if the resource cannot be found.
*/
public String loadContent(final String pattern, final Object testInstance, final Method testMethod) {
return read(findUrl(pattern, testInstance, testMethod), testInstance, testMethod);
}
/**
* Interpolate the pattern as a relative path. See {@link TestResource} and
* {@link TestResourceNamingStrategy#resourceName(String, Class, Field, Method)}.
*
* @param pattern the pattern to interpolate.
* @param testInstance the instance of the running test.
* @param testMethod the method of the running test.
* @return the interpolated pattern as a relative path.
*/
public String toPath(final String pattern, final Object testInstance, final Method testMethod) {
Class> testClass = testInstance.getClass();
return namingStrategy.resourceName(pattern, testClass, null, testMethod);
}
/**
* Inject all the {@link TestResource}s of the given instance for the given test.
*
* @param testInstance the instance of the running test.
* @param testMethod the method of the running test.
* @throws TestResourceException if a resource cannot be found or read.
*/
public void inject(final Object testInstance, final Method testMethod) {
Class> testClass = testInstance.getClass();
List testFields = FieldUtils.getFieldsListWithAnnotation(testClass, TestResource.class);
for (Field testField : testFields) {
logger.trace("Found field annotated with TestResource: {}", testField);
if (!isInjectionTypeSupported(testField.getType())) {
String message = format("Unsupported resource type for %s", testField);
throw new TestResourceException(message, testInstance, testMethod);
}
TestResource testResource = testField.getAnnotation(TestResource.class);
String[] testPatterns = testResource.value();
List resourceNames = namingStrategy.resourceNames(testPatterns, testClass, testField, testMethod);
URL url = resolutionStrategy.findResource(testClass, resourceNames);
if (url == null) {
if (!testResource.optional()) {
throw new RuntimeException("Resource not found for " + testField);
}
logger.trace("Resource not found for {}", testField);
} else {
logger.trace("Resource found for {}: {}", testField, url);
setResource(testInstance, testMethod, testField, url);
}
}
}
/**
* Clear all the {@link TestResource}s of the given instance for the given test.
*
* @param testInstance the instance of the running test.
* @param testMethod the method of the running test.
*/
public void clear(final Object testInstance, final Method testMethod) {
Class> testClass = testInstance.getClass();
List testFields = FieldUtils.getFieldsListWithAnnotation(testClass, TestResource.class);
for (Field testField : testFields) {
clearResource(testInstance, testMethod, testField);
}
}
/**
* Check that the given resource can be injected, that is its type is supported.
*
* @param resourceClass the class of the resource to check.
* @return true
if the given class is supported, false
otherwise.
*/
protected boolean isInjectionTypeSupported(Class> resourceClass) {
return ArrayUtils.contains(SUPPORTED_TYPES, resourceClass);
}
/**
* Set the given URL on the field of the given instance.
*
* @param testInstance the instance of the running test to set the field on.
* @param testMethod the method of the running test.
* @param testField the field to set.
* @param url the URL to set.
* @throws TestResourceException if the resource cannot be read.
*/
protected void setResource(final Object testInstance, final Method testMethod, final Field testField,
final URL url) {
try {
testField.setAccessible(true);
Class> fieldType = testField.getType();
if (URL.class.isAssignableFrom(fieldType)) {
testField.set(testInstance, url);
} else if (File.class.isAssignableFrom(fieldType)) {
testField.set(testInstance, new File(url.getPath()));
} else if (String.class.isAssignableFrom(fieldType)) {
testField.set(testInstance, read(url, null, null));
} else if (List.class.isAssignableFrom(fieldType)) {
testField.set(testInstance, readLines(url, testInstance, testMethod));
} else if (InputStream.class.isAssignableFrom(fieldType)) {
testField.set(testInstance, open(url, testInstance, testMethod));
} else if (InputStreamReader.class.isAssignableFrom(fieldType)) {
testField.set(testInstance, new InputStreamReader(open(url, testInstance, testMethod), UTF_8));
} else {
String message = format("Unsupported resource type for %s", testField);
throw new TestResourceException(message, testInstance, testMethod);
}
} catch (IllegalArgumentException | IllegalAccessException e) {
throw new TestResourceException("Error while setting resource", e, testInstance, testMethod);
}
}
/**
* Clear the given field of the given instance.
*
* @param testInstance the instance of the running test to clear the field on.
* @param testMethod the method of the running test.
* @param testField the field to clear.
* @throws TestResourceException if the resource cannot be cleared.
*/
protected void clearResource(final Object testInstance, final Method testMethod, final Field testField) {
try {
testField.setAccessible(true);
Class> fieldType = testField.getType();
if (URL.class.isAssignableFrom(fieldType)) {
testField.set(testInstance, null);
} else if (File.class.isAssignableFrom(fieldType)) {
testField.set(testInstance, null);
} else if (String.class.isAssignableFrom(fieldType)) {
testField.set(testInstance, null);
} else if (List.class.isAssignableFrom(fieldType)) {
testField.set(testInstance, null);
} else if (InputStream.class.isAssignableFrom(fieldType)) {
IOUtils.closeQuietly((Closeable) testField.get(testInstance));
testField.set(testInstance, null);
} else if (InputStreamReader.class.isAssignableFrom(fieldType)) {
IOUtils.closeQuietly((Closeable) testField.get(testInstance));
testField.set(testInstance, null);
}
// else {
// no need
// String message = format("Unsupported resource type for %s", testField);
// throw new TestResourceException(message, testInstance, testMethod);
// }
} catch (IllegalArgumentException | IllegalAccessException e) {
throw new TestResourceException("Error while clearing resource", e, testInstance, testMethod);
}
}
/**
* @param url the resource to read.
* @param testInstance the instance of the running test.
* @param testMethod the method of the running test.
* @return the content of the given resource.
* @throws TestResourceException if the resource cannot be read.
*/
private String read(final URL url, final Object testInstance, final Method testMethod) {
try {
return Resources.toString(url, UTF_8);
} catch (IOException e) {
String message = format("Error while reading URL '%s'", url);
throw new TestResourceException(message, e, testInstance, testMethod);
}
}
/**
* @param url the resource to read.
* @param testInstance the instance of the running test.
* @param testMethod the method of the running test.
* @return the content of the given resource.
* @throws TestResourceException if the resource cannot be read.
*/
private List readLines(final URL url, final Object testInstance, final Method testMethod) {
try {
return Resources.readLines(url, UTF_8);
} catch (IOException e) {
String message = format("Error while reading URL '%s'", url);
throw new TestResourceException(message, e, testInstance, testMethod);
}
}
/**
* @param url the resource to open.
* @param testInstance the instance of the running test.
* @param testMethod the method of the running test.
* @return a stream of the given resource.
* @throws TestResourceException if the resource cannot be read.
*/
private InputStream open(final URL url, final Object testInstance, final Method testMethod) {
try {
return url.openStream();
} catch (IOException e) {
String message = format("Error while opening stream from URL '%s'", url);
throw new TestResourceException(message, e, testInstance, testMethod);
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy