| 1 |  |  | /* | 
            
                                                                                                            
                            
            
                                    
            
            
                | 2 |  |  |  * Licensed to the Apache Software Foundation (ASF) under one or more | 
            
                                                                                                            
                            
            
                                    
            
            
                | 3 |  |  |  * contributor license agreements.  See the NOTICE file distributed with | 
            
                                                                                                            
                            
            
                                    
            
            
                | 4 |  |  |  * this work for additional information regarding copyright ownership. | 
            
                                                                                                            
                            
            
                                    
            
            
                | 5 |  |  |  * The ASF licenses this file to You under the Apache License, Version 2.0 | 
            
                                                                                                            
                            
            
                                    
            
            
                | 6 |  |  |  * (the "License"); you may not use this file except in compliance with | 
            
                                                                                                            
                            
            
                                    
            
            
                | 7 |  |  |  * the License.  You may obtain a copy of the License at | 
            
                                                                                                            
                            
            
                                    
            
            
                | 8 |  |  |  * | 
            
                                                                                                            
                            
            
                                    
            
            
                | 9 |  |  |  *      http://www.apache.org/licenses/LICENSE-2.0 | 
            
                                                                                                            
                            
            
                                    
            
            
                | 10 |  |  |  * | 
            
                                                                                                            
                            
            
                                    
            
            
                | 11 |  |  |  * Unless required by applicable law or agreed to in writing, software | 
            
                                                                                                            
                            
            
                                    
            
            
                | 12 |  |  |  * distributed under the License is distributed on an "AS IS" BASIS, | 
            
                                                                                                            
                            
            
                                    
            
            
                | 13 |  |  |  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | 
            
                                                                                                            
                            
            
                                    
            
            
                | 14 |  |  |  * See the License for the specific language governing permissions and | 
            
                                                                                                            
                            
            
                                    
            
            
                | 15 |  |  |  * limitations under the License. | 
            
                                                                                                            
                            
            
                                    
            
            
                | 16 |  |  |  */ | 
            
                                                                                                            
                            
            
                                    
            
            
                | 17 |  |  | package io.github.glytching.junit.extension.folder; | 
            
                                                                                                            
                            
            
                                    
            
            
                | 18 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 19 |  |  | import org.junit.jupiter.api.extension.ExtensionContext.Store.CloseableResource; | 
            
                                                                                                            
                            
            
                                    
            
            
                | 20 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 21 |  |  | import java.io.File; | 
            
                                                                                                            
                            
            
                                    
            
            
                | 22 |  |  | import java.io.IOException; | 
            
                                                                                                            
                            
            
                                    
            
            
                | 23 |  |  | import java.nio.file.*; | 
            
                                                                                                            
                            
            
                                    
            
            
                | 24 |  |  | import java.nio.file.attribute.BasicFileAttributes; | 
            
                                                                                                            
                            
            
                                    
            
            
                | 25 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 26 |  |  | import static java.nio.file.FileVisitResult.CONTINUE; | 
            
                                                                                                            
                            
            
                                    
            
            
                | 27 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 28 |  |  | /** | 
            
                                                                                                            
                            
            
                                    
            
            
                | 29 |  |  |  * Encapsulates the {@link #rootFolder} within which any files or directories will be created along | 
            
                                                                                                            
                            
            
                                    
            
            
                | 30 |  |  |  * with the operations which a tester may wish to invoke ({@link #createFile(String)}, {@link | 
            
                                                                                                            
                            
            
                                    
            
            
                | 31 |  |  |  * #createDirectory(String)}) and post test invocations which the associated extension will invoke. | 
            
                                                                                                            
                            
            
                                    
            
            
                | 32 |  |  |  */ | 
            
                                                                                                            
                            
            
                                    
            
            
                | 33 |  |  | @SuppressWarnings({"ResultOfMethodCallIgnored", "nls"}) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 34 |  |  | public class TemporaryFolder implements CloseableResource { | 
            
                                                                                                            
                            
            
                                    
            
            
                | 35 |  |  |   private static final String FILE_PREFIX = "junit"; | 
            
                                                                                                            
                            
            
                                    
            
            
                | 36 |  |  |   private static final String FILE_SUFFIX = ".tmp"; | 
            
                                                                                                            
                            
            
                                    
            
            
                | 37 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 38 |  |  |   /** | 
            
                                                                                                            
                            
            
                                    
            
            
                | 39 |  |  |    * The root folder within which any files or directories will be created, on {@link #destroy()} | 
            
                                                                                                            
                            
            
                                    
            
            
                | 40 |  |  |    * this folder and all of its contents will be silently deleted. | 
            
                                                                                                            
                            
            
                                    
            
            
                | 41 |  |  |    */ | 
            
                                                                                                            
                            
            
                                    
            
            
                | 42 |  |  |   private final File rootFolder; | 
            
                                                                                                            
                            
            
                                    
            
            
                | 43 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 44 |  |  |   /** | 
            
                                                                                                            
                            
            
                                    
            
            
                | 45 |  |  |    * Package protected since a {@link TemporaryFolder}'s lifecycle is expected to be controlled by | 
            
                                                                                                            
                            
            
                                    
            
            
                | 46 |  |  |    * its associated extension. | 
            
                                                                                                            
                            
            
                                    
            
            
                | 47 |  |  |    */ | 
            
                                                                                                            
                            
            
                                    
            
            
                | 48 |  |  |   TemporaryFolder() { | 
            
                                                                                                            
                            
            
                                    
            
            
                | 49 |  |  |     try { | 
            
                                                                                                            
                            
            
                                    
            
            
                | 50 |  |  |       rootFolder = File.createTempFile(FILE_PREFIX, FILE_SUFFIX); | 
            
                                                                                                            
                            
            
                                    
            
            
                | 51 |  |  |       Files.delete(rootFolder.toPath()); | 
            
                                                                                                            
                            
            
                                    
            
            
                | 52 |  |  |       Files.createDirectory(rootFolder.toPath()); | 
            
                                                                                                            
                            
            
                                    
            
            
                | 53 |  |  |     } catch (IOException ex) { | 
            
                                                                                                            
                            
            
                                    
            
            
                | 54 |  |  |       throw new TemporaryFolderException("Failed to prepare root folder!", ex); | 
            
                                                                                                            
                            
            
                                    
            
            
                | 55 |  |  |     } | 
            
                                                                                                            
                            
            
                                    
            
            
                | 56 |  |  |   } | 
            
                                                                                                            
                            
            
                                    
            
            
                | 57 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 58 |  |  |   @Override | 
            
                                                                                                            
                            
            
                                    
            
            
                | 59 |  |  |   public void close() throws Throwable { | 
            
                                                                                                            
                            
            
                                    
            
            
                | 60 |  |  |     destroy(); | 
            
                                                                                                            
                            
            
                                    
            
            
                | 61 |  |  |   } | 
            
                                                                                                            
                            
            
                                    
            
            
                | 62 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 63 |  |  |   /** | 
            
                                                                                                            
                            
            
                                    
            
            
                | 64 |  |  |    * Returns the root folder. Exposing this offers some back compatability with JUnit4's {@code | 
            
                                                                                                            
                            
            
                                    
            
            
                | 65 |  |  |    * TemporaryFolder} so test cases which are used to invoking {@code getRoot()} on a JUnit4 rule | 
            
                                                                                                            
                            
            
                                    
            
            
                | 66 |  |  |    * can adopt the same approach with this {@code TemporaryFolder}. In addition, this may be useful | 
            
                                                                                                            
                            
            
                                    
            
            
                | 67 |  |  |    * where you want to use the root folder itself without creating files or directories within it. | 
            
                                                                                                            
                            
            
                                    
            
            
                | 68 |  |  |    * | 
            
                                                                                                            
                            
            
                                    
            
            
                | 69 |  |  |    * <p><b>Note:</b> the extension is responsible for creating/managing/destroying the root folder | 
            
                                                                                                            
                            
            
                                    
            
            
                | 70 |  |  |    * so don't bother trying to clean it up yourself and don't expect that anything you do to it will | 
            
                                                                                                            
                            
            
                                    
            
            
                | 71 |  |  |    * survive post-test-cleanup. | 
            
                                                                                                            
                            
            
                                    
            
            
                | 72 |  |  |    * | 
            
                                                                                                            
                            
            
                                    
            
            
                | 73 |  |  |    * @see <a href="https://github.com/glytching/junit-extensions/issues/8">Issue 8</a> | 
            
                                                                                                            
                            
            
                                    
            
            
                | 74 |  |  |    * @return the root folder | 
            
                                                                                                            
                            
            
                                    
            
            
                | 75 |  |  |    */ | 
            
                                                                                                            
                            
            
                                    
            
            
                | 76 |  |  |   public File getRoot() { | 
            
                                                                                                            
                            
            
                                    
            
            
                | 77 |  |  |     return rootFolder; | 
            
                                                                                                            
                            
            
                                    
            
            
                | 78 |  |  |   } | 
            
                                                                                                            
                            
            
                                    
            
            
                | 79 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 80 |  |  |   /** | 
            
                                                                                                            
                            
            
                                    
            
            
                | 81 |  |  |    * Create a file within the temporary folder root. | 
            
                                                                                                            
                            
            
                                    
            
            
                | 82 |  |  |    * | 
            
                                                                                                            
                            
            
                                    
            
            
                | 83 |  |  |    * @param fileName the name of the file to be created | 
            
                                                                                                            
                            
            
                                    
            
            
                | 84 |  |  |    * @return the newly created file instance | 
            
                                                                                                            
                            
            
                                    
            
            
                | 85 |  |  |    * @throws IOException in case the file creation call fails | 
            
                                                                                                            
                            
            
                                    
            
            
                | 86 |  |  |    */ | 
            
                                                                                                            
                            
            
                                    
            
            
                | 87 |  |  |   public File createFile(String fileName) throws IOException { | 
            
                                                                                                            
                            
            
                                    
            
            
                | 88 |  |  |     Path path = Paths.get(rootFolder.getPath(), fileName); | 
            
                                                                                                            
                            
            
                                    
            
            
                | 89 |  |  |     return Files.createFile(path).toFile(); | 
            
                                                                                                            
                            
            
                                    
            
            
                | 90 |  |  |   } | 
            
                                                                                                            
                            
            
                                    
            
            
                | 91 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 92 |  |  |   /** | 
            
                                                                                                            
                            
            
                                    
            
            
                | 93 |  |  |    * Create a directory within the temporary folder root. | 
            
                                                                                                            
                            
            
                                    
            
            
                | 94 |  |  |    * | 
            
                                                                                                            
                            
            
                                    
            
            
                | 95 |  |  |    * @param directoryName the name of the directory to be created | 
            
                                                                                                            
                            
            
                                    
            
            
                | 96 |  |  |    * @return the directory instance | 
            
                                                                                                            
                                                                
            
                                    
            
            
                | 97 |  |  |    */ | 
            
                                                                        
                            
            
                                    
            
            
                | 98 |  |  |   public File createDirectory(String directoryName) { | 
            
                                                                        
                            
            
                                    
            
            
                | 99 |  |  |     Path path = Paths.get(rootFolder.getPath(), directoryName); | 
            
                                                                        
                            
            
                                    
            
            
                | 100 |  |  |     try { | 
            
                                                                        
                            
            
                                    
            
            
                | 101 |  |  |       return Files.createDirectory(path).toFile(); | 
            
                                                                        
                            
            
                                    
            
            
                | 102 |  |  |     } catch (IOException ex) { | 
            
                                                                        
                            
            
                                    
            
            
                | 103 |  |  |       throw new TemporaryFolderException( | 
            
                                                                        
                            
            
                                    
            
            
                | 104 |  |  |           String.format("Failed to create directory: '%s'", path.toString()), ex); | 
            
                                                                                                            
                            
            
                                    
            
            
                | 105 |  |  |     } | 
            
                                                                                                            
                            
            
                                    
            
            
                | 106 |  |  |   } | 
            
                                                                                                            
                            
            
                                    
            
            
                | 107 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 108 |  |  |   /** | 
            
                                                                                                            
                            
            
                                    
            
            
                | 109 |  |  |    * Deletes the {@link #rootFolder} and all of its contents. This is package protected because a | 
            
                                                                                                            
                            
            
                                    
            
            
                | 110 |  |  |    * {@link TemporaryFolder}'s lifecycle is expected to be controlled by its associated extension. | 
            
                                                                                                            
                            
            
                                    
            
            
                | 111 |  |  |    * | 
            
                                                                                                            
                            
            
                                    
            
            
                | 112 |  |  |    * <p><b>Note</b>: any exception encountered during deletion will be swallowed. | 
            
                                                                                                            
                            
            
                                    
            
            
                | 113 |  |  |    */ | 
            
                                                                                                            
                            
            
                                    
            
            
                | 114 |  |  |   void destroy() throws IOException { | 
            
                                                                                                            
                            
            
                                    
            
            
                | 115 |  |  |     if (rootFolder.exists()) { | 
            
                                                                                                            
                            
            
                                    
            
            
                | 116 |  |  |       // walk the contents deleting each | 
            
                                                                                                            
                            
            
                                    
            
            
                | 117 |  |  |       Files.walkFileTree( | 
            
                                                                                                            
                            
            
                                    
            
            
                | 118 |  |  |           rootFolder.toPath(), | 
            
                                                                                                            
                            
            
                                    
            
            
                | 119 |  |  |           new SimpleFileVisitor<Path>() { | 
            
                                                                                                            
                            
            
                                    
            
            
                | 120 |  |  |             @Override | 
            
                                                                                                            
                            
            
                                    
            
            
                | 121 |  |  |             public FileVisitResult visitFile(Path file, BasicFileAttributes attributes) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 122 |  |  |                 throws IOException { | 
            
                                                                                                            
                            
            
                                    
            
            
                | 123 |  |  |               return delete(file); | 
            
                                                                                                            
                            
            
                                    
            
            
                | 124 |  |  |             } | 
            
                                                                                                            
                            
            
                                    
            
            
                | 125 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 126 |  |  |             @Override | 
            
                                                                                                            
                            
            
                                    
            
            
                | 127 |  |  |             public FileVisitResult postVisitDirectory(Path directory, IOException exception) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 128 |  |  |                 throws IOException { | 
            
                                                                                                            
                            
            
                                    
            
            
                | 129 |  |  |               return delete(directory); | 
            
                                                                                                            
                            
            
                                    
            
            
                | 130 |  |  |             } | 
            
                                                                                                            
                            
            
                                    
            
            
                | 131 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 132 |  |  |             @SuppressWarnings("SameReturnValue") | 
            
                                                                                                            
                            
            
                                    
            
            
                | 133 |  |  |             private FileVisitResult delete(Path file) throws IOException { | 
            
                                                                                                            
                            
            
                                    
            
            
                | 134 |  |  |               Files.delete(file); | 
            
                                                                                                            
                            
            
                                    
            
            
                | 135 |  |  |               return CONTINUE; | 
            
                                                                                                            
                            
            
                                    
            
            
                | 136 |  |  |             } | 
            
                                                                                                            
                            
            
                                    
            
            
                | 137 |  |  |           }); | 
            
                                                                                                            
                            
            
                                    
            
            
                | 138 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 139 |  |  |       if (rootFolder.exists()) { | 
            
                                                                                                            
                            
            
                                    
            
            
                | 140 |  |  |         // delete the parent, if it still exists | 
            
                                                                                                            
                            
            
                                    
            
            
                | 141 |  |  |         Files.delete(rootFolder.toPath()); | 
            
                                                                                                            
                            
            
                                    
            
            
                | 142 |  |  |       } | 
            
                                                                                                            
                            
            
                                    
            
            
                | 143 |  |  |     } | 
            
                                                                                                            
                            
            
                                    
            
            
                | 144 |  |  |   } | 
            
                                                                                                            
                                                                
            
                                    
            
            
                | 145 |  |  | } | 
            
                                                        
            
                                    
            
            
                | 146 |  |  |  |