Skip to content

Instantly share code, notes, and snippets.

@mkempka
Created March 6, 2015 12:46
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save mkempka/7adedaa460fb9146b50a to your computer and use it in GitHub Desktop.
Save mkempka/7adedaa460fb9146b50a to your computer and use it in GitHub Desktop.
A Rule that eases working with files during test execution in OSGi environments. See http://eclipsesource.com/blogs/?p=22765
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.text.MessageFormat;
import org.apache.commons.io.IOUtils;
import org.jdom.input.DOMBuilder;
import org.junit.rules.ExternalResource;
import org.junit.rules.TemporaryFolder;
import org.w3c.dom.Document;
import org.xml.sax.SAXException;
/**
* Class FileResource helps setting up input test files for unit tests. The motivation and usage
* hints are given at http://eclipsesource.com/blogs/?p=22765 Feel free to use and adjust this class
* to your needs, but keep the author information in its place.
*
* @author Matthias Kempka (mkempka@eclipsesource.com)
*/
@SuppressWarnings("nls")
public class FileResource extends ExternalResource {
public static class ExternalFolder extends TemporaryFolder {
private boolean initialized;
public void teardown() {
if (initialized) {
delete();
super.after();
initialized = false;
}
}
public synchronized void setup() throws Throwable {
if (!initialized) {
super.before();
initialized = true;
}
}
}
private final String resourceName;
private File file;
private final ClassLoader classLoader;
private final ExternalFolder folder;
/**
* @param loader the classloader of the source file
* @param resourceName the resource name of the source file. Must be in the root directory of
* the class loader.
*/
public FileResource(final ClassLoader loader, final String resourceName) {
this(new ExternalFolder(), loader, resourceName);
}
/**
* The use of an external folder allows to copy multiple files next to each other. Intended use:
*
* <pre>
* private ExternalFolder folder = new ExternalFolder();
* &#064;Rule
* public FileResource xml = new FileResource(folder, getClass().getClassLoader(), &quot;myfile.xml&quot;);
* &#064;Rule
* public FileResource dtd = new FileResource(folder, getClass().getClassLoader(), &quot;mydtd.dtd&quot;);
* </pre>
*
* @param folder an instance of {@link ExternalFolder} that defines the parent folder of a file
* @param loader the classloader of the source file
* @param resourceName the resource name of the source file. Must be in the root directory of
* the class loader.
*/
public FileResource(ExternalFolder folder, final ClassLoader loader, final String resourceName) {
this.classLoader = loader;
this.resourceName = resourceName;
this.folder = folder;
}
public String getContent() {
try {
return getContent("UTF-8");
} catch (IOException e) {
throw new IllegalStateException("Couldn't get test content from file: " + file + "");
}
}
public String getContent(final String charSet) throws IOException {
FileInputStream input = new FileInputStream(file);
try {
return IOUtils.toString(input, charSet);
} finally {
IOUtils.closeQuietly(input);
}
}
public File getFile() {
return file;
}
public String getName() {
return file.getName();
}
@Override
protected void before() throws Throwable {
super.before();
folder.setup();
InputStream stream = classLoader.getResourceAsStream(resourceName);
if (stream == null) {
throw new IllegalStateException(MessageFormat.format("Can''t open ''{0}''", resourceName));
}
file = folder.newFile(resourceName);
FileOutputStream outputStream = new FileOutputStream(file);
IOUtils.copy(stream, outputStream);
IOUtils.closeQuietly(stream);
IOUtils.closeQuietly(outputStream);
}
@Override
protected void after() {
file.delete();
folder.teardown();
super.after();
}
public Document getContentAsW3CDocument() {
javax.xml.parsers.DocumentBuilderFactory factory = javax.xml.parsers.DocumentBuilderFactory.newInstance();
factory.setNamespaceAware(true);
javax.xml.parsers.DocumentBuilder builder = null;
try {
builder = factory.newDocumentBuilder();
} catch (javax.xml.parsers.ParserConfigurationException ex) {
}
FileInputStream is = null;
try {
is = new FileInputStream(file);
org.w3c.dom.Document doc = builder.parse(is);
return doc;
} catch (FileNotFoundException e) {
throw new IllegalArgumentException("Can't create input stream from resource.", e);
} catch (SAXException e) {
throw new IllegalArgumentException("Can't parse input stream from resource.", e);
} catch (IOException e) {
throw new IllegalArgumentException("Can't create input stream from resource.", e);
} finally {
IOUtils.closeQuietly(is);
}
}
public byte[] getBytes() {
try {
return IOUtils.toByteArray(new FileInputStream(getFile()));
} catch (FileNotFoundException e) {
throw new IllegalArgumentException("Can't create input stream from resource.", e);
} catch (IOException e) {
throw new IllegalArgumentException("Can't create input stream from resource.", e);
}
}
public org.jdom.Document getContentAsJDomDocument() {
return new DOMBuilder().build(getContentAsW3CDocument());
}
}
@wcomnisky
Copy link

Thanks for sharing the code!

If you use @RunWith(PowerMockRunner.class) annotation in your test class and if you have more than one FileResource (even using the same instance of ExternalFolder with private ExternalFolder folder = new ExternalFolder();) you'll get an exception for the first FileResource declared.

I'll need to check later but the tearDown() method from the ExternalFolder class is being called earlier when using PowerMockRunner.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment