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