1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.apache.commons.io;
18
19 import static org.junit.jupiter.api.Assertions.assertEquals;
20 import static org.junit.jupiter.api.Assertions.assertFalse;
21 import static org.junit.jupiter.api.Assertions.assertNotNull;
22 import static org.junit.jupiter.api.Assertions.assertThrows;
23 import static org.junit.jupiter.api.Assertions.assertTrue;
24 import static org.junit.jupiter.api.Assertions.fail;
25
26 import java.io.File;
27 import java.io.IOException;
28 import java.nio.charset.StandardCharsets;
29 import java.nio.file.Files;
30 import java.nio.file.Path;
31 import java.util.ArrayList;
32 import java.util.Collection;
33 import java.util.Iterator;
34 import java.util.List;
35 import java.util.UUID;
36 import java.util.concurrent.CompletableFuture;
37 import java.util.concurrent.ExecutionException;
38 import java.util.stream.Collectors;
39 import java.util.stream.Stream;
40
41 import org.apache.commons.io.file.PathUtils;
42 import org.apache.commons.io.filefilter.FileFilterUtils;
43 import org.apache.commons.io.filefilter.IOFileFilter;
44 import org.apache.commons.io.function.Uncheck;
45 import org.apache.commons.lang3.function.Consumers;
46 import org.junit.jupiter.api.BeforeEach;
47 import org.junit.jupiter.api.Test;
48 import org.junit.jupiter.api.io.TempDir;
49
50
51
52
53 class FileUtilsListFilesTest {
54
55 @TempDir
56 public File temporaryFolder;
57
58 @SuppressWarnings("ResultOfMethodCallIgnored")
59 @BeforeEach
60 public void setUp() throws Exception {
61 File dir = temporaryFolder;
62 File file = new File(dir, "dummy-build.xml");
63 FileUtils.touch(file);
64 file = new File(dir, "README");
65 FileUtils.touch(file);
66
67 dir = new File(dir, "subdir1");
68 dir.mkdirs();
69 file = new File(dir, "dummy-build.xml");
70 FileUtils.touch(file);
71 file = new File(dir, "dummy-readme.txt");
72 FileUtils.touch(file);
73
74 dir = new File(dir, "subsubdir1");
75 dir.mkdirs();
76 file = new File(dir, "dummy-file.txt");
77 FileUtils.touch(file);
78 file = new File(dir, "dummy-index.html");
79 FileUtils.touch(file);
80 file = new File(dir, "dummy-indexhtml");
81 FileUtils.touch(file);
82
83 dir = dir.getParentFile();
84 dir = new File(dir, "CVS");
85 dir.mkdirs();
86 file = new File(dir, "Entries");
87 FileUtils.touch(file);
88 file = new File(dir, "Repository");
89 FileUtils.touch(file);
90 }
91
92 @Test
93 void testIterateFilesByExtension() {
94 final String[] extensions = { "xml", "txt" };
95
96 Iterator<File> files = FileUtils.iterateFiles(temporaryFolder, extensions, false);
97 try {
98 final Collection<String> fileNames = toFileNames(files);
99 assertEquals(1, fileNames.size());
100 assertTrue(fileNames.contains("dummy-build.xml"));
101 assertFalse(fileNames.contains("README"));
102 assertFalse(fileNames.contains("dummy-file.txt"));
103 } finally {
104
105 files.forEachRemaining(Consumers.nop());
106 }
107
108 try {
109 files = FileUtils.iterateFiles(temporaryFolder, extensions, true);
110 final Collection<String> fileNames = toFileNames(files);
111 assertEquals(4, fileNames.size());
112 assertTrue(fileNames.contains("dummy-file.txt"));
113 assertFalse(fileNames.contains("dummy-index.html"));
114 } finally {
115
116 files.forEachRemaining(Consumers.nop());
117 }
118
119 files = FileUtils.iterateFiles(temporaryFolder, null, false);
120 try {
121 final Collection<String> fileNames = toFileNames(files);
122 assertEquals(2, fileNames.size());
123 assertTrue(fileNames.contains("dummy-build.xml"));
124 assertTrue(fileNames.contains("README"));
125 assertFalse(fileNames.contains("dummy-file.txt"));
126 } finally {
127
128 files.forEachRemaining(Consumers.nop());
129 }
130 }
131
132 @Test
133 void testListFiles() {
134 Collection<File> files;
135 Collection<String> fileNames;
136 IOFileFilter fileFilter;
137 IOFileFilter dirFilter;
138
139
140 fileFilter = FileFilterUtils.trueFileFilter();
141 files = FileUtils.listFiles(temporaryFolder, fileFilter, null);
142 fileNames = toFileNames(files);
143 assertTrue(fileNames.contains("dummy-build.xml"), "'dummy-build.xml' is missing");
144 assertFalse(fileNames.contains("dummy-index.html"), "'dummy-index.html' shouldn't be found");
145 assertFalse(fileNames.contains("Entries"), "'Entries' shouldn't be found");
146
147
148 fileFilter = FileFilterUtils.trueFileFilter();
149 dirFilter = FileFilterUtils.notFileFilter(FileFilterUtils.nameFileFilter("CVS"));
150 files = FileUtils.listFiles(temporaryFolder, fileFilter, dirFilter);
151 fileNames = toFileNames(files);
152 assertTrue(fileNames.contains("dummy-build.xml"), "'dummy-build.xml' is missing");
153 assertTrue(fileNames.contains("dummy-index.html"), "'dummy-index.html' is missing");
154 assertFalse(fileNames.contains("Entries"), "'Entries' shouldn't be found");
155
156
157 fileFilter = FileFilterUtils.trueFileFilter();
158 dirFilter = FileFilterUtils.makeCVSAware(null);
159 files = FileUtils.listFiles(temporaryFolder, fileFilter, dirFilter);
160 fileNames = toFileNames(files);
161 assertTrue(fileNames.contains("dummy-build.xml"), "'dummy-build.xml' is missing");
162 assertTrue(fileNames.contains("dummy-index.html"), "'dummy-index.html' is missing");
163 assertFalse(fileNames.contains("Entries"), "'Entries' shouldn't be found");
164
165
166 fileFilter = FileFilterUtils.trueFileFilter();
167 dirFilter = FileFilterUtils.prefixFileFilter("sub");
168 dirFilter = FileFilterUtils.makeCVSAware(dirFilter);
169 files = FileUtils.listFiles(temporaryFolder, fileFilter, dirFilter);
170 fileNames = toFileNames(files);
171 assertTrue(fileNames.contains("dummy-build.xml"), "'dummy-build.xml' is missing");
172 assertTrue(fileNames.contains("dummy-index.html"), "'dummy-index.html' is missing");
173 assertFalse(fileNames.contains("Entries"), "'Entries' shouldn't be found");
174
175 assertThrows(NullPointerException.class, () -> FileUtils.listFiles(temporaryFolder, null, null));
176 }
177
178 @Test
179 void testListFilesByExtension() {
180 final String[] extensions = {"xml", "txt"};
181
182 Collection<File> files = FileUtils.listFiles(temporaryFolder, extensions, false);
183 assertEquals(1, files.size());
184 Collection<String> fileNames = toFileNames(files);
185 assertTrue(fileNames.contains("dummy-build.xml"));
186 assertFalse(fileNames.contains("README"));
187 assertFalse(fileNames.contains("dummy-file.txt"));
188
189 files = FileUtils.listFiles(temporaryFolder, extensions, true);
190 fileNames = toFileNames(files);
191 assertEquals(4, fileNames.size(), fileNames::toString);
192 assertTrue(fileNames.contains("dummy-file.txt"));
193 assertFalse(fileNames.contains("dummy-index.html"));
194
195 files = FileUtils.listFiles(temporaryFolder, null, false);
196 assertEquals(2, files.size(), files::toString);
197 fileNames = toFileNames(files);
198 assertTrue(fileNames.contains("dummy-build.xml"));
199 assertTrue(fileNames.contains("README"));
200 assertFalse(fileNames.contains("dummy-file.txt"));
201
202 final File directory = new File(temporaryFolder, "subdir1/subsubdir1");
203 files = FileUtils.listFiles(directory, new String[] { "html" }, false);
204 fileNames = toFileNames(files);
205 assertFalse(files.isEmpty(), directory::toString);
206 assertTrue(fileNames.contains("dummy-index.html"));
207 assertFalse(fileNames.contains("dummy-indexhtml"));
208 files = FileUtils.listFiles(temporaryFolder, new String[] { "html" }, true);
209 fileNames = toFileNames(files);
210 assertFalse(files.isEmpty(), temporaryFolder::toString);
211 assertTrue(fileNames.contains("dummy-index.html"));
212 assertFalse(fileNames.contains("dummy-indexhtml"));
213 }
214
215 @Test
216 void testListFilesMissing() {
217 assertTrue(FileUtils.listFiles(new File(temporaryFolder, "dir/does/not/exist/at/all"), null, false).isEmpty());
218 }
219
220 @Test
221 void testListFilesWithDeletion() throws IOException {
222 final String[] extensions = {"xml", "txt"};
223 final List<File> list;
224 final File xFile = new File(temporaryFolder, "x.xml");
225 if (!xFile.createNewFile()) {
226 fail("could not create test file: " + xFile);
227 }
228 final Collection<File> files = FileUtils.listFiles(temporaryFolder, extensions, true);
229 assertEquals(5, files.size());
230 try (Stream<File> stream = Uncheck.get(() -> FileUtils.streamFiles(temporaryFolder, true, extensions))) {
231 assertTrue(xFile.delete());
232 list = stream.collect(Collectors.toList());
233 assertFalse(list.contains(xFile), list::toString);
234 }
235 assertEquals(4, list.size());
236 }
237
238
239
240
241 @Test
242 void testListFilesWithDeletionThreaded() throws ExecutionException, InterruptedException {
243
244
245 final Path tempPath = PathUtils.getTempDirectory().resolve("IO-856");
246 final File tempDir = tempPath.toFile();
247 if (!tempDir.exists() && !tempDir.mkdirs()) {
248 fail("Could not create file path: " + tempDir.getAbsolutePath());
249 }
250 final int waitTime = 10_000;
251 final int maxFiles = 500;
252 final byte[] bytes = "TEST".getBytes(StandardCharsets.UTF_8);
253 final CompletableFuture<Void> c1 = CompletableFuture.runAsync(() -> {
254 final long endTime = System.currentTimeMillis() + waitTime;
255 int count = 0;
256 while (System.currentTimeMillis() < endTime && count < maxFiles) {
257 final File file = new File(tempDir.getAbsolutePath(), UUID.randomUUID() + ".deletetester");
258 file.deleteOnExit();
259 try {
260 Files.write(file.toPath(), bytes);
261 count++;
262 } catch (final Exception e) {
263 fail("Could not create test file: '" + file.getAbsolutePath() + "': " + e, e);
264 }
265 if (!file.delete()) {
266 fail("Could not delete test file: '" + file.getAbsolutePath() + "'");
267 }
268 }
269
270 });
271 final CompletableFuture<Void> c2 = CompletableFuture.runAsync(() -> {
272 final long endTime = System.currentTimeMillis() + waitTime;
273 int max = 0;
274 try {
275 while (System.currentTimeMillis() < endTime) {
276 final Collection<File> files = FileUtils.listFiles(tempDir, new String[] { ".deletetester" }, false);
277 assertNotNull(files);
278 max = Math.max(max, files.size());
279 }
280 } catch (final Exception e) {
281 System.out.printf("List size max %,d%n", max);
282 fail("IO-856 test failure: " + e, e);
283
284 e.printStackTrace();
285 }
286
287 });
288
289 c1.get();
290 c2.get();
291 }
292
293 private Collection<String> toFileNames(final Collection<File> files) {
294 return files.stream().map(File::getName).collect(Collectors.toList());
295 }
296
297
298
299
300
301
302
303 private Collection<String> toFileNames(final Iterator<File> files) {
304 final Collection<String> fileNames = new ArrayList<>();
305
306 files.forEachRemaining(f -> fileNames.add(f.getName()));
307 return fileNames;
308 }
309
310 }