/* * Copyright 2005-2010 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.wamblee.io; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.io.UnsupportedEncodingException; import java.net.URL; import java.net.URLDecoder; import java.nio.MappedByteBuffer; import java.nio.channels.FileChannel; import java.security.CodeSource; import java.util.logging.Level; import java.util.logging.Logger; import junit.framework.Assert; import junit.framework.TestCase; /** * File system utilities. * * @author Erik Brakkee */ public final class FileSystemUtils { private static final Logger LOG = Logger.getLogger(FileSystemUtils.class .getName()); /** * Test output directory relative to the sub project. */ private static final String TEST_OUTPUT_DIR = "../target/testoutput"; /** * Test input directory relative to the sub project. */ private static final String TEST_INPUT_DIR = "../src/test/resources"; /* * Disabled. */ private FileSystemUtils() { // Empty } /** * Deletes a directory recursively. The test case will fail if the directory * does not exist or if deletion fails. * * @param aDir * Directory to delete. */ public static void deleteDirRecursively(String aDir) { deleteDirRecursively(new File(aDir)); } /** * Deletes a directory recursively. See {@link #deleteDirRecursively}. * * @param aDir * Directory. */ public static void deleteDirRecursively(File aDir) { TestCase.assertTrue(aDir.isDirectory()); for (File file : aDir.listFiles()) { if (file.isDirectory()) { deleteDirRecursively(file); } else { delete(file); } } delete(aDir); } /** * Deletes a file or directory. The test case will fail if the file or * directory does not exist or if deletion fails. Deletion of a non-empty * directory will always fail. * * @param aFile * File or directory to delete. */ public static void delete(File aFile) { TestCase.assertTrue(aFile.delete()); } /** * Gets a path relative to a sub project. This utility should be used to * easily access file paths within a subproject without requiring any * specific Eclipse configuration. * * @param aRelativePath * Relative path. * @param aTestClass * Test class. */ public static File getPath(String aRelativePath, Class aTestClass) { CodeSource source = aTestClass.getProtectionDomain().getCodeSource(); if (source == null) { LOG.warning("Could not obtain path for '" + aRelativePath + "' for class " + aTestClass + ", using relative path as is"); return new File(aRelativePath); } URL location = source.getLocation(); String protocol = location.getProtocol(); if (!protocol.equals("file")) { LOG.warning("protocol is not 'file': " + location); return new File(aRelativePath); } String path = location.getPath(); try { path = URLDecoder.decode(location.getPath(), "UTF-8"); } catch (UnsupportedEncodingException e) { // ignore it.. just don't decode LOG.log(Level.WARNING, "Decoding path failed: '" + location.getPath() + "'", e); } return new File(new File(path).getParentFile(), aRelativePath); } /** * Ensures that a directory hierarchy exists (recursively if needed). If it * is not possible to create the directory, then the test case will fail. * * @param aDir * Directory to create. */ public static void createDir(File aDir) { if (aDir.exists() && !aDir.isDirectory()) { TestCase.fail("'" + aDir + "' already exists and is not a directory"); } if (aDir.exists()) { return; } createDir(aDir.getParentFile()); TestCase.assertTrue("Could not create '" + aDir + "'", aDir.mkdir()); } /** * Creates a file in a directory. * * @param aDir * Directory path. Will be created if it does not exist. * @param aName * Filename. * @param aContents * Contents. */ public static void createFile(File aDir, String aName, InputStream aContents) { createDir(aDir); try { OutputStream os = new FileOutputStream(new File(aDir, aName)); copyStream(aContents, os); } catch (IOException e) { e.printStackTrace(); TestCase.fail(e.getMessage()); } } /** * Gets the test output directory for a specific test class. * * @param aTestClass * Test class. * @return Test output directory. */ public static File getTestOutputDir(Class aTestClass) { File file = getPath(TEST_OUTPUT_DIR, aTestClass); String className = aTestClass.getName(); String classRelPath = className.replaceAll("\\.", "/"); return new File(file, classRelPath); } /** * Gets the test input directory for a specific test class. * * @param aTestClass * Test class. * @return Test input directory. */ public static File getTestInputDir(Class aTestClass) { File file = getPath(TEST_INPUT_DIR, aTestClass); String packageName = aTestClass.getPackage().getName(); String packagePath = packageName.replaceAll("\\.", "/"); return new File(file, packagePath); } /** * Creates a directory hierarchy for the output directory of a test class if * needed. * * @param aTestClass * Test class * @return Test directory. */ public static File createTestOutputDir(Class aTestClass) { File file = getTestOutputDir(aTestClass); createDir(file); return file; } /** * Gets a test output file name. This returns a File object representing the * output file and ensures that the directory where the file will be created * already exists. * * @param aName * Name of the file. * @param aTestClass * Test class. * @return File. */ public static File getTestOutputFile(String aName, Class aTestClass) { File file = new File(getTestOutputDir(aTestClass), aName); createDir(file.getParentFile()); return file; } public static String read(InputStream aIs) throws IOException { try { StringBuffer buffer = new StringBuffer(); int c; while ((c = aIs.read()) != -1) { buffer.append((char) c); } return buffer.toString(); } finally { aIs.close(); } } /** * Copies an input stream to an output stream. * * @param aIs * Input stream. * @param aOs * Output stream. */ public static void copyStream(InputStream aIs, OutputStream aOs) { try { int c; while ((c = aIs.read()) != -1) { aOs.write(c); } aIs.close(); aOs.close(); } catch (IOException e) { e.printStackTrace(); Assert.fail(e.getMessage()); } } /** * Recursively copy a directory. * * @param aSrc * Source directory * @param aTarget * Target directory. */ public static void copyDir(File aSrc, File aTarget) { Assert.assertTrue(aSrc.isDirectory()); Assert.assertTrue(!aTarget.exists()); if (!aTarget.mkdirs()) { Assert.fail("Could not create target directory '" + aTarget + "'"); } File[] files = aSrc.listFiles(); for (int i = 0; i < files.length; i++) { File file = files[i]; if (file.isDirectory()) { if (!file.getName().equals(".svn")) { copyDir(new File(aSrc, file.getName()), new File(aTarget, file.getName())); } } else { copyFile(file, new File(aTarget, file.getName())); } } } /** * Copy a file. If copying fails then the testcase will fail. * * @param aSrc * Source file. * @param aTarget * Target file. */ public static void copyFile(File aSrc, File aTarget) { try { FileInputStream fis = new FileInputStream(aSrc); FileOutputStream fos = new FileOutputStream(aTarget); FileChannel fcin = fis.getChannel(); FileChannel fcout = fos.getChannel(); // map input file MappedByteBuffer mbb = fcin.map(FileChannel.MapMode.READ_ONLY, 0, fcin.size()); // do the file copy fcout.write(mbb); // finish up fcin.close(); fcout.close(); fis.close(); fos.close(); } catch (IOException e) { Assert.assertTrue("Copying file " + aSrc.getPath() + " to " + aTarget.getPath() + " failed.", false); } } /** * Remove all files within a given directory including the directory itself. * This only attempts to remove regular files and not directories within the * directory. If the directory contains a nested directory, the deletion * will fail. The test case will fail if this fails. * * @param aDir * Directory to remove. */ public static void deleteDir(File aDir) { cleanDir(aDir); delete(aDir); } /** * Remove all regular files within a given directory. * * @param aDir Directory to clean. */ public static void cleanDir(File aDir) { if (!aDir.exists()) { return; // nothing to do. } File[] entries = aDir.listFiles(); for (int i = 0; i < entries.length; i++) { File file = entries[i]; if (file.isFile()) { Assert.assertTrue("Could not delete " + entries[i].getPath(), entries[i].delete()); } } } }