ad3b4e208d27e51960b18c41ed93c939353da2a9
[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          * Creates a file in a directory.  
164          * @param aDir Directory path. Will be created if it does not exist. 
165          * @param aName Filename. 
166          * @param aContents Contents.
167          */
168         public static void createFile(File aDir, String aName, InputStream aContents) {
169                 createDir(aDir);
170                 try {
171                         OutputStream os = new FileOutputStream(new File(aDir, aName));
172                         copyStream(aContents, os);
173                 } catch (IOException e) {
174                         e.printStackTrace();
175                         TestCase.fail(e.getMessage());
176                 }
177         }
178
179         /**
180          * Gets the test output directory for a specific test class.
181          * 
182          * @param aTestClass
183          *            Test class.
184          * @return Test output directory.
185          */
186         public static File getTestOutputDir(Class aTestClass) {
187                 File file = getPath(TEST_OUTPUT_DIR, aTestClass);
188                 String className = aTestClass.getName();
189                 String classRelPath = className.replaceAll("\\.", "/");
190                 return new File(file, classRelPath);
191         }
192
193         /**
194          * Gets the test input directory for a specific test class.
195          * 
196          * @param aTestClass
197          *            Test class.
198          * @return Test input directory.
199          */
200         public static File getTestInputDir(Class aTestClass) {
201                 File file = getPath(TEST_INPUT_DIR, aTestClass);
202                 String packageName = aTestClass.getPackage().getName();
203                 String packagePath = packageName.replaceAll("\\.", "/");
204                 return new File(file, packagePath);
205         }
206
207         /**
208          * Creates a directory hierarchy for the output directory of a test class if
209          * needed.
210          * 
211          * @param aTestClass
212          *            Test class
213          * @return Test directory.
214          */
215         public static File createTestOutputDir(Class aTestClass) {
216                 File file = getTestOutputDir(aTestClass);
217                 createDir(file);
218                 return file;
219         }
220
221         /**
222          * Gets a test output file name. This returns a File object representing the
223          * output file and ensures that the directory where the file will be created
224          * already exists.
225          * 
226          * @param aName
227          *            Name of the file.
228          * @param aTestClass
229          *            Test class.
230          * @return File.
231          */
232         public static File getTestOutputFile(String aName, Class aTestClass) {
233                 File file = new File(getTestOutputDir(aTestClass), aName);
234                 createDir(file.getParentFile());
235                 return file;
236         }
237
238         public static String read(InputStream aIs) throws IOException {
239                 try {
240                         StringBuffer buffer = new StringBuffer();
241                         int c;
242                         while ((c = aIs.read()) != -1) {
243                                 buffer.append((char) c);
244                         }
245                         return buffer.toString();
246                 } finally {
247                         aIs.close();
248                 }
249         }
250
251         /**
252          * Copies an input stream to an output stream.
253          * 
254          * @param aIs
255          *            Input stream.
256          * @param aOs
257          *            Output stream.
258          */
259         public static void copyStream(InputStream aIs, OutputStream aOs) {
260                 try {
261                         int c;
262                         while ((c = aIs.read()) != -1) {
263                                 aOs.write(c);
264                         }
265                         aIs.close();
266                         aOs.close();
267                 } catch (IOException e) {
268                         e.printStackTrace();
269                         Assert.fail(e.getMessage());
270                 }
271         }
272
273         /**
274          * Recursively copy a directory.
275          * 
276          * @param aSrc
277          *            Source directory
278          * @param aTarget
279          *            Target directory.
280          */
281         public static void copyDir(File aSrc, File aTarget) {
282                 Assert.assertTrue(aSrc.isDirectory());
283                 Assert.assertTrue(!aTarget.exists());
284
285                 aTarget.mkdirs();
286
287                 File[] files = aSrc.listFiles();
288                 for (int i = 0; i < files.length; i++) {
289                         File file = files[i];
290                         if (file.isDirectory()) {
291                                 if (!file.getName().equals(".svn")) {
292                                         copyDir(new File(aSrc, file.getName()), new File(aTarget,
293                                                         file.getName()));
294                                 }
295                         } else {
296                                 copyFile(file, new File(aTarget, file.getName()));
297                         }
298                 }
299         }
300
301         /**
302          * Copy a file. If copying fails then the testcase will fail.
303          * 
304          * @param aSrc
305          *            Source file.
306          * @param aTarget
307          *            Target file.
308          */
309         public static void copyFile(File aSrc, File aTarget) {
310
311                 try {
312                         FileInputStream fis = new FileInputStream(aSrc);
313                         FileOutputStream fos = new FileOutputStream(aTarget);
314                         FileChannel fcin = fis.getChannel();
315                         FileChannel fcout = fos.getChannel();
316
317                         // map input file
318
319                         MappedByteBuffer mbb = fcin.map(FileChannel.MapMode.READ_ONLY, 0,
320                                         fcin.size());
321
322                         // do the file copy
323                         fcout.write(mbb);
324
325                         // finish up
326
327                         fcin.close();
328                         fcout.close();
329                         fis.close();
330                         fos.close();
331                 } catch (IOException e) {
332                         Assert.assertTrue("Copying file " + aSrc.getPath() + " to "
333                                         + aTarget.getPath() + " failed.", false);
334                 }
335         }
336
337         /**
338          * Remove all files within a given directory including the directory itself.
339          * This only attempts to remove regular files and not directories within the
340          * directory. If the directory contains a nested directory, the deletion
341          * will fail. The test case will fail if this fails.
342          * 
343          * @param aDir
344          *            Directory to remove.
345          */
346         public static void deleteDir(File aDir) {
347                 cleanDir(aDir);
348                 delete(aDir);
349         }
350
351         /**
352          * Remove all regular files within a given directory.
353          * 
354          * @param outputDirName
355          */
356         public static void cleanDir(File aDir) {
357                 if (!aDir.exists()) {
358                         return; // nothing to do.
359                 }
360                 File[] entries = aDir.listFiles();
361                 for (int i = 0; i < entries.length; i++) {
362                         File file = entries[i];
363                         if (file.isFile()) {
364                                 Assert.assertTrue("Could not delete " + entries[i].getPath(),
365                                                 entries[i].delete());
366                         }
367                 }
368         }
369 }