001    package org.junit.rules;
002    
003    import java.io.File;
004    import java.io.IOException;
005    
006    import org.junit.Rule;
007    
008    /**
009     * The TemporaryFolder Rule allows creation of files and folders that should
010     * be deleted when the test method finishes (whether it passes or
011     * fails). Whether the deletion is successful or not is not checked by this rule.
012     * No exception will be thrown in case the deletion fails.
013     *
014     * <p>Example of usage:
015     * <pre>
016     * public static class HasTempFolder {
017     *  &#064;Rule
018     *  public TemporaryFolder folder= new TemporaryFolder();
019     *
020     *  &#064;Test
021     *  public void testUsingTempFolder() throws IOException {
022     *      File createdFile= folder.newFile(&quot;myfile.txt&quot;);
023     *      File createdFolder= folder.newFolder(&quot;subfolder&quot;);
024     *      // ...
025     *     }
026     * }
027     * </pre>
028     *
029     * @since 4.7
030     */
031    public class TemporaryFolder extends ExternalResource {
032        private final File parentFolder;
033        private File folder;
034    
035        public TemporaryFolder() {
036            this(null);
037        }
038    
039        public TemporaryFolder(File parentFolder) {
040            this.parentFolder = parentFolder;
041        }
042    
043        @Override
044        protected void before() throws Throwable {
045            create();
046        }
047    
048        @Override
049        protected void after() {
050            delete();
051        }
052    
053        // testing purposes only
054    
055        /**
056         * for testing purposes only. Do not use.
057         */
058        public void create() throws IOException {
059            folder = createTemporaryFolderIn(parentFolder);
060        }
061    
062        /**
063         * Returns a new fresh file with the given name under the temporary folder.
064         */
065        public File newFile(String fileName) throws IOException {
066            File file = new File(getRoot(), fileName);
067            if (!file.createNewFile()) {
068                throw new IOException(
069                        "a file with the name \'" + fileName + "\' already exists in the test folder");
070            }
071            return file;
072        }
073    
074        /**
075         * Returns a new fresh file with a random name under the temporary folder.
076         */
077        public File newFile() throws IOException {
078            return File.createTempFile("junit", null, getRoot());
079        }
080    
081        /**
082         * Returns a new fresh folder with the given name under the temporary
083         * folder.
084         */
085        public File newFolder(String folder) throws IOException {
086            return newFolder(new String[]{folder});
087        }
088    
089        /**
090         * Returns a new fresh folder with the given name(s) under the temporary
091         * folder.
092         */
093        public File newFolder(String... folderNames) throws IOException {
094            File file = getRoot();
095            for (int i = 0; i < folderNames.length; i++) {
096                String folderName = folderNames[i];
097                validateFolderName(folderName);
098                file = new File(file, folderName);
099                if (!file.mkdir() && isLastElementInArray(i, folderNames)) {
100                    throw new IOException(
101                            "a folder with the name \'" + folderName + "\' already exists");
102                }
103            }
104            return file;
105        }
106        
107        /**
108         * Validates if multiple path components were used while creating a folder.
109         * 
110         * @param folderName
111         *            Name of the folder being created
112         */
113        private void validateFolderName(String folderName) throws IOException {
114            File tempFile = new File(folderName);
115            if (tempFile.getParent() != null) {
116                String errorMsg = "Folder name cannot consist of multiple path components separated by a file separator."
117                        + " Please use newFolder('MyParentFolder','MyFolder') to create hierarchies of folders";
118                throw new IOException(errorMsg);
119            }
120        }
121    
122        private boolean isLastElementInArray(int index, String[] array) {
123            return index == array.length - 1;
124        }
125    
126        /**
127         * Returns a new fresh folder with a random name under the temporary folder.
128         */
129        public File newFolder() throws IOException {
130            return createTemporaryFolderIn(getRoot());
131        }
132    
133        private File createTemporaryFolderIn(File parentFolder) throws IOException {
134            File createdFolder = File.createTempFile("junit", "", parentFolder);
135            createdFolder.delete();
136            createdFolder.mkdir();
137            return createdFolder;
138        }
139    
140        /**
141         * @return the location of this temporary folder.
142         */
143        public File getRoot() {
144            if (folder == null) {
145                throw new IllegalStateException(
146                        "the temporary folder has not yet been created");
147            }
148            return folder;
149        }
150    
151        /**
152         * Delete all files and folders under the temporary folder. Usually not
153         * called directly, since it is automatically applied by the {@link Rule}
154         */
155        public void delete() {
156            if (folder != null) {
157                recursiveDelete(folder);
158            }
159        }
160    
161        private void recursiveDelete(File file) {
162            File[] files = file.listFiles();
163            if (files != null) {
164                for (File each : files) {
165                    recursiveDelete(each);
166                }
167            }
168            file.delete();
169        }
170    }