Created a TestData test support class for managing test output files.
[utils] / support / src / test / java / org / wamblee / io / FileSystemUtils.java
1 /*
2  * Copyright 2006 the original author or authors.
3  * 
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  * 
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  * 
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 package org.wamblee.io;
17
18 import java.io.File;
19 import java.io.FileInputStream;
20 import java.io.FileOutputStream;
21 import java.io.IOException;
22 import java.io.InputStream;
23 import java.io.OutputStream;
24 import java.io.UnsupportedEncodingException;
25 import java.net.URL;
26 import java.net.URLDecoder;
27 import java.nio.MappedByteBuffer;
28 import java.nio.channels.FileChannel;
29 import java.security.CodeSource;
30
31 import junit.framework.Assert;
32 import junit.framework.TestCase;
33
34 import org.apache.commons.logging.Log;
35 import org.apache.commons.logging.LogFactory;
36
37 /**
38  * File system utilities.
39  *
40  * @author Erik Brakkee
41  */
42 public final class FileSystemUtils {
43
44     private static final Log LOG = LogFactory.getLog(FileSystemUtils.class);
45
46     /**
47      * Test output directory relative to the sub project.
48      */
49     private static final String TEST_OUTPUT_DIR = "../target/testoutput";
50     
51     /**
52      * Test input directory relative to the sub project. 
53      */
54     private static final String TEST_INPUT_DIR = "../src/test/resources";
55
56     /*
57      * Disabled.
58      * 
59      */
60     private FileSystemUtils() {
61         // Empty
62     }
63
64     /**
65      * Deletes a directory recursively. The test case will fail if the directory
66      * does not exist or if deletion fails.
67      * 
68      * @param aDir
69      *            Directory to delete.
70      */
71     public static void deleteDirRecursively(String aDir) {
72         deleteDirRecursively(new File(aDir));
73     }
74
75     /**
76      * Deletes a directory recursively. See {@link #deleteDirRecursively}.
77      * 
78      * @param aDir
79      *            Directory.
80      */
81     public static void deleteDirRecursively(File aDir) {
82         TestCase.assertTrue(aDir.isDirectory());
83
84         for (File file : aDir.listFiles()) {
85             if (file.isDirectory()) {
86                 deleteDirRecursively(file);
87             } else {
88                 delete(file);
89             }
90         }
91
92         delete(aDir);
93     }
94
95     /**
96      * Deletes a file or directory. The test case will fail if the file or
97      * directory does not exist or if deletion fails. Deletion of a non-empty
98      * directory will always fail.
99      * 
100      * @param aFile
101      *            File or directory to delete.
102      */
103     public static void delete(File aFile) {
104         TestCase.assertTrue(aFile.delete());
105     }
106
107     /**
108      * Gets a path relative to a sub project. This utility should be used to
109      * easily access file paths within a subproject without requiring any
110      * specific Eclipse configuration.
111      * 
112      * @param aRelativePath
113      *            Relative path.
114      * @param aTestClass
115      *            Test class.
116      */
117     public static File getPath(String aRelativePath, Class aTestClass) {
118         CodeSource source = aTestClass.getProtectionDomain().getCodeSource();
119         if (source == null) {
120             LOG.warn("Could not obtain path for '" + aRelativePath
121                     + "' for class " + aTestClass
122                     + ", using relative path as is");
123             return new File(aRelativePath);
124         }
125         URL location = source.getLocation();
126         String protocol = location.getProtocol();
127         if (!protocol.equals("file")) {
128             LOG.warn("protocol is not 'file': " + location);
129             return new File(aRelativePath);
130         }
131
132         String path = location.getPath();
133         try {
134             path = URLDecoder.decode(location.getPath(), "UTF-8");
135         } catch (UnsupportedEncodingException e) {
136             // ignore it.. just don't decode
137             LOG.warn("Decoding path failed: '" + location.getPath() + "'", e );
138         }
139
140         return new File(new File(path).getParentFile(), aRelativePath);
141     }
142
143     /**
144      * Ensures that a directory hierarchy exists (recursively if needed). If it
145      * is not possible to create the directory, then the test case will fail.
146      * 
147      * @param aDir
148      *            Directory to create.
149      */
150     public static void createDir(File aDir) {
151         if (aDir.exists() && !aDir.isDirectory()) {
152             TestCase.fail("'" + aDir
153                     + "' already exists and is not a directory");
154         }
155         if (aDir.exists()) {
156             return;
157         }
158         createDir(aDir.getParentFile());
159         TestCase.assertTrue("Could not create '" + aDir + "'", aDir.mkdir());
160     }
161
162     /**
163      * Gets the test output directory for a specific test class.
164      * 
165      * @param aTestClass
166      *            Test class.
167      * @return Test output directory.
168      */
169     public static File getTestOutputDir(Class aTestClass) {
170         File file = getPath(TEST_OUTPUT_DIR, aTestClass);
171         String packageName = aTestClass.getPackage().getName();
172         String packagePath = packageName.replaceAll("\\.", "/");
173         return new File(file, packagePath);
174     }
175     
176     /**
177      * Gets the test input directory for a specific test class.
178      * 
179      * @param aTestClass
180      *            Test class.
181      * @return Test input directory.
182      */
183     public static File getTestInputDir(Class aTestClass) {
184         File file = getPath(TEST_INPUT_DIR, aTestClass);
185         String packageName = aTestClass.getPackage().getName();
186         String packagePath = packageName.replaceAll("\\.", "/");
187         return new File(file, packagePath);
188     }
189
190     /**
191      * Creates a directory hierarchy for the output directory of a test class if
192      * needed.
193      * 
194      * @param aTestClass
195      *            Test class
196      * @return Test directory.
197      */
198     public static File createTestOutputDir(Class aTestClass) {
199         File file = getTestOutputDir(aTestClass);
200         createDir(file);
201         return file;
202     }
203
204     /**
205      * Gets a test output file name. This returns a File object representing the
206      * output file and ensures that the directory where the file will be created
207      * already exists.
208      * 
209      * @param aName
210      *            Name of the file.
211      * @param aTestClass
212      *            Test class.
213      * @return File.
214      */
215     public static File getTestOutputFile(String aName, Class aTestClass) {
216         File file = new File(getTestOutputDir(aTestClass), aName);
217         createDir(file.getParentFile());
218         return file;
219     }
220
221     public static String read(InputStream aIs) throws IOException {
222         try {
223             StringBuffer buffer = new StringBuffer();
224             int c;
225             while ((c = aIs.read()) != -1) {
226                 buffer.append((char)c);
227             }
228             return buffer.toString();
229         } finally {
230             aIs.close();
231         }
232     }
233     
234     /**
235          * Copies an input stream to an output stream. 
236          * @param aIs Input stream. 
237          * @param aOs Output stream. 
238          */
239         public static void copyStream(InputStream aIs, OutputStream aOs) {
240                 try {
241                         int c;
242                         while ((c = aIs.read()) != -1) {
243                                 aOs.write(c);
244                         }
245                         aIs.close();
246                         aOs.close(); 
247                 } catch (IOException e) {
248                         e.printStackTrace();
249                         Assert.fail(e.getMessage());
250                 }
251         }
252
253         /**
254          * Recursively copy a directory.
255          * 
256          * @param aSrc
257          *            Source directory
258          * @param aTarget
259          *            Target directory.
260          */
261         public static void copyDir(File aSrc, File aTarget) {
262                 Assert.assertTrue(aSrc.isDirectory());
263                 Assert.assertTrue(!aTarget.exists());
264
265                 aTarget.mkdirs();
266
267                 File[] files = aSrc.listFiles();
268                 for (int i = 0; i < files.length; i++) {
269                         File file = files[i];
270                         if (file.isDirectory()) {
271                                 if (!file.getName().equals(".svn")) {
272                                         copyDir(new File(aSrc, file.getName()), new File(aTarget,
273                                                         file.getName()));
274                                 }
275                         } else {
276                                 copyFile(file, new File(aTarget, file.getName()));
277                         }
278                 }
279         }
280
281         /**
282          * Copy a file. If copying fails then the testcase will fail.
283          * 
284          * @param aSrc
285          *            Source file.
286          * @param aTarget
287          *            Target file.
288          */
289         public static void copyFile(File aSrc, File aTarget) {
290
291                 try {
292                         FileInputStream fis = new FileInputStream(aSrc);
293                         FileOutputStream fos = new FileOutputStream(aTarget);
294                         FileChannel fcin = fis.getChannel();
295                         FileChannel fcout = fos.getChannel();
296
297                         // map input file
298
299                         MappedByteBuffer mbb = fcin.map(FileChannel.MapMode.READ_ONLY, 0,
300                                         fcin.size());
301
302                         // do the file copy
303                         fcout.write(mbb);
304
305                         // finish up
306
307                         fcin.close();
308                         fcout.close();
309                         fis.close();
310                         fos.close();
311                 } catch (IOException e) {
312                         Assert.assertTrue("Copying file " + aSrc.getPath() + " to "
313                                         + aTarget.getPath() + " failed.", false);
314                 }
315         }
316         
317         /**
318          * Remove all files within a given directory including the directory itself.
319          * This only attempts to remove regular files and not directories within the
320          * directory. If the directory contains a nested directory, the deletion
321          * will fail. The test case will fail if this fails.
322          * 
323          * @param aDir
324          *            Directory to remove.
325          */
326         public static void deleteDir(File aDir) {
327                 cleanDir(aDir);
328                 delete(aDir);
329         }
330         
331         /**
332          * Remove all regular files within a given directory.
333          * 
334          * @param outputDirName
335          */
336         public static void cleanDir(File aDir) {
337                 if (!aDir.exists()) {
338                         return; // nothing to do.
339                 }
340                 File[] entries = aDir.listFiles();
341                 for (int i = 0; i < entries.length; i++) {
342                         File file = entries[i];
343                         if (file.isFile()) {
344                                 Assert.assertTrue("Could not delete " + entries[i].getPath(),
345                                                 entries[i].delete());
346                         }
347                 }
348         }
349 }