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.assertThrows;
22 import static org.junit.jupiter.api.Assertions.assertTrue;
23 import static org.junit.jupiter.api.Assertions.fail;
24
25 import java.io.File;
26 import java.io.FileFilter;
27 import java.io.IOException;
28 import java.util.ArrayList;
29 import java.util.Collection;
30 import java.util.List;
31
32 import org.apache.commons.io.filefilter.FileFilterUtils;
33 import org.apache.commons.io.filefilter.IOFileFilter;
34 import org.apache.commons.io.filefilter.NameFileFilter;
35 import org.junit.jupiter.api.Test;
36
37
38
39
40 public class DirectoryWalkerTest {
41
42
43
44
45
46 static class TestCancelWalker extends DirectoryWalker<File> {
47 private final String cancelFileName;
48 private final boolean suppressCancel;
49
50 TestCancelWalker(final String cancelFileName, final boolean suppressCancel) {
51 this.cancelFileName = cancelFileName;
52 this.suppressCancel = suppressCancel;
53 }
54
55
56 protected List<File> find(final File startDirectory) throws IOException {
57 final List<File> results = new ArrayList<>();
58 walk(startDirectory, results);
59 return results;
60 }
61
62
63 @Override
64 protected void handleCancelled(final File startDirectory, final Collection<File> results, final CancelException cancel) throws IOException {
65 if (!suppressCancel) {
66 super.handleCancelled(startDirectory, results, cancel);
67 }
68 }
69
70
71 @Override
72 protected void handleDirectoryEnd(final File directory, final int depth, final Collection<File> results) throws IOException {
73 results.add(directory);
74 if (cancelFileName.equals(directory.getName())) {
75 throw new CancelException(directory, depth);
76 }
77 }
78
79
80 @Override
81 protected void handleFile(final File file, final int depth, final Collection<File> results) throws IOException {
82 results.add(file);
83 if (cancelFileName.equals(file.getName())) {
84 throw new CancelException(file, depth);
85 }
86 }
87 }
88
89
90
91
92 private static final class TestFalseFileFinder extends TestFileFinder {
93
94 protected TestFalseFileFinder(final FileFilter filter, final int depthLimit) {
95 super(filter, depthLimit);
96 }
97
98
99 @Override
100 protected boolean handleDirectory(final File directory, final int depth, final Collection<File> results) {
101 return false;
102 }
103 }
104
105
106
107
108 private static class TestFileFinder extends DirectoryWalker<File> {
109
110 protected TestFileFinder(final FileFilter filter, final int depthLimit) {
111 super(filter, depthLimit);
112 }
113
114 protected TestFileFinder(final IOFileFilter dirFilter, final IOFileFilter fileFilter, final int depthLimit) {
115 super(dirFilter, fileFilter, depthLimit);
116 }
117
118
119 protected List<File> find(final File startDirectory) {
120 final List<File> results = new ArrayList<>();
121 try {
122 walk(startDirectory, results);
123 } catch (final IOException ex) {
124 fail(ex.toString());
125 }
126 return results;
127 }
128
129
130 @Override
131 protected void handleDirectoryEnd(final File directory, final int depth, final Collection<File> results) {
132 results.add(directory);
133 }
134
135
136 @Override
137 protected void handleFile(final File file, final int depth, final Collection<File> results) {
138 results.add(file);
139 }
140 }
141
142
143
144
145 private static final class TestFileFinderString extends DirectoryWalker<String> {
146
147 protected TestFileFinderString(final FileFilter filter, final int depthLimit) {
148 super(filter, depthLimit);
149 }
150
151
152 protected List<String> find(final File startDirectory) {
153 final List<String> results = new ArrayList<>();
154 try {
155 walk(startDirectory, results);
156 } catch (final IOException ex) {
157 fail(ex.toString());
158 }
159 return results;
160 }
161
162
163 @Override
164 protected void handleFile(final File file, final int depth, final Collection<String> results) {
165 results.add(file.toString());
166 }
167 }
168
169
170
171
172 static class TestMultiThreadCancelWalker extends DirectoryWalker<File> {
173 private final String cancelFileName;
174 private final boolean suppressCancel;
175 private boolean cancelled;
176 public List<File> results;
177
178 TestMultiThreadCancelWalker(final String cancelFileName, final boolean suppressCancel) {
179 this.cancelFileName = cancelFileName;
180 this.suppressCancel = suppressCancel;
181 }
182
183
184 protected List<File> find(final File startDirectory) throws IOException {
185 results = new ArrayList<>();
186 walk(startDirectory, results);
187 return results;
188 }
189
190
191 @Override
192 protected void handleCancelled(final File startDirectory, final Collection<File> results, final CancelException cancel) throws IOException {
193 if (!suppressCancel) {
194 super.handleCancelled(startDirectory, results, cancel);
195 }
196 }
197
198
199 @Override
200 protected void handleDirectoryEnd(final File directory, final int depth, final Collection<File> results) throws IOException {
201 results.add(directory);
202 assertFalse(cancelled);
203 if (cancelFileName.equals(directory.getName())) {
204 cancelled = true;
205 }
206 }
207
208
209 @Override
210 protected void handleFile(final File file, final int depth, final Collection<File> results) throws IOException {
211 results.add(file);
212 assertFalse(cancelled);
213 if (cancelFileName.equals(file.getName())) {
214 cancelled = true;
215 }
216 }
217
218
219 @Override
220 protected boolean handleIsCancelled(final File file, final int depth, final Collection<File> results) throws IOException {
221 return cancelled;
222 }
223 }
224
225 private static final File current = FileUtils.current();
226 private static final File javaDir = new File("src/main/java");
227 private static final File orgDir = new File(javaDir, "org");
228
229 private static final File apacheDir = new File(orgDir, "apache");
230 private static final File commonsDir = new File(apacheDir, "commons");
231 private static final File ioDir = new File(commonsDir, "io");
232 private static final File outputDir = new File(ioDir, "output");
233 private static final File[] dirs = {orgDir, apacheDir, commonsDir, ioDir, outputDir};
234
235 private static final File fileNameUtils = new File(ioDir, "FilenameUtils.java");
236
237 private static final File ioUtils = new File(ioDir, "IOUtils.java");
238 private static final File proxyWriter = new File(outputDir, "ProxyWriter.java");
239 private static final File nullStream = new File(outputDir, "NullOutputStream.java");
240 private static final File[] ioFiles = {fileNameUtils, ioUtils};
241 private static final File[] outputFiles = {proxyWriter, nullStream};
242
243
244 private static final IOFileFilter dirsFilter = createNameFilter(dirs);
245
246 private static final IOFileFilter ioFilesFilter = createNameFilter(ioFiles);
247
248 private static final IOFileFilter outputFilesFilter = createNameFilter(outputFiles);
249
250 private static final IOFileFilter ioDirAndFilesFilter = dirsFilter.or(ioFilesFilter);
251
252 private static final IOFileFilter dirsAndFilesFilter = ioDirAndFilesFilter.or(outputFilesFilter);
253
254
255 private static final IOFileFilter NOT_SVN = FileFilterUtils.makeSVNAware(null);
256
257
258
259
260
261 private static IOFileFilter createNameFilter(final File[] files) {
262 final String[] names = new String[files.length];
263 for (int i = 0; i < files.length; i++) {
264 names[i] = files[i].getName();
265 }
266 return new NameFileFilter(names);
267 }
268
269
270
271
272 private void checkContainsFiles(final String prefix, final File[] files, final Collection<File> results) {
273 for (int i = 0; i < files.length; i++) {
274 assertTrue(results.contains(files[i]), prefix + "[" + i + "] " + files[i]);
275 }
276 }
277
278 private void checkContainsString(final String prefix, final File[] files, final Collection<String> results) {
279 for (int i = 0; i < files.length; i++) {
280 assertTrue(results.contains(files[i].toString()), prefix + "[" + i + "] " + files[i]);
281 }
282 }
283
284
285
286
287 private List<File> directoriesOnly(final Collection<File> results) {
288 final List<File> list = new ArrayList<>(results.size());
289 for (final File file : results) {
290 if (file.isDirectory()) {
291 list.add(file);
292 }
293 }
294 return list;
295 }
296
297
298
299
300 private List<File> filesOnly(final Collection<File> results) {
301 final List<File> list = new ArrayList<>(results.size());
302 for (final File file : results) {
303 if (file.isFile()) {
304 list.add(file);
305 }
306 }
307 return list;
308 }
309
310
311
312
313 @Test
314 public void testCancel() {
315 String cancelName = null;
316
317
318 try {
319 cancelName = "DirectoryWalker.java";
320 new TestCancelWalker(cancelName, false).find(javaDir);
321 fail("CancelException not thrown for '" + cancelName + "'");
322 } catch (final DirectoryWalker.CancelException cancel) {
323 assertEquals(cancelName, cancel.getFile().getName(), "File: " + cancelName);
324 assertEquals(5, cancel.getDepth(), "Depth: " + cancelName);
325 } catch (final IOException ex) {
326 fail("IOException: " + cancelName + " " + ex);
327 }
328
329
330 try {
331 cancelName = "commons";
332 new TestCancelWalker(cancelName, false).find(javaDir);
333 fail("CancelException not thrown for '" + cancelName + "'");
334 } catch (final DirectoryWalker.CancelException cancel) {
335 assertEquals(cancelName, cancel.getFile().getName(), "File: " + cancelName);
336 assertEquals(3, cancel.getDepth(), "Depth: " + cancelName);
337 } catch (final IOException ex) {
338 fail("IOException: " + cancelName + " " + ex);
339 }
340
341
342 try {
343 final List<File> results = new TestCancelWalker(cancelName, true).find(javaDir);
344 final File lastFile = results.get(results.size() - 1);
345 assertEquals(cancelName, lastFile.getName(), "Suppress: " + cancelName);
346 } catch (final IOException ex) {
347 fail("Suppress threw " + ex);
348 }
349
350 }
351
352
353
354
355 @Test
356 public void testFilter() {
357 final List<File> results = new TestFileFinder(dirsAndFilesFilter, -1).find(javaDir);
358 assertEquals(1 + dirs.length + ioFiles.length + outputFiles.length, results.size(), "Result Size");
359 assertTrue(results.contains(javaDir), "Start Dir");
360 checkContainsFiles("Dir", dirs, results);
361 checkContainsFiles("IO File", ioFiles, results);
362 checkContainsFiles("Output File", outputFiles, results);
363 }
364
365
366
367
368 @Test
369 public void testFilterAndLimitA() {
370 final List<File> results = new TestFileFinder(NOT_SVN, 0).find(javaDir);
371 assertEquals(1, results.size(), "[A] Result Size");
372 assertTrue(results.contains(javaDir), "[A] Start Dir");
373 }
374
375
376
377
378 @Test
379 public void testFilterAndLimitB() {
380 final List<File> results = new TestFileFinder(NOT_SVN, 1).find(javaDir);
381 assertEquals(2, results.size(), "[B] Result Size");
382 assertTrue(results.contains(javaDir), "[B] Start Dir");
383 assertTrue(results.contains(orgDir), "[B] Org Dir");
384 }
385
386
387
388
389 @Test
390 public void testFilterAndLimitC() {
391 final List<File> results = new TestFileFinder(NOT_SVN, 3).find(javaDir);
392 assertEquals(4, results.size(), "[C] Result Size");
393 assertTrue(results.contains(javaDir), "[C] Start Dir");
394 assertTrue(results.contains(orgDir), "[C] Org Dir");
395 assertTrue(results.contains(apacheDir), "[C] Apache Dir");
396 assertTrue(results.contains(commonsDir), "[C] Commons Dir");
397 }
398
399
400
401
402 @Test
403 public void testFilterAndLimitD() {
404 final List<File> results = new TestFileFinder(dirsAndFilesFilter, 5).find(javaDir);
405 assertEquals(1 + dirs.length + ioFiles.length, results.size(), "[D] Result Size");
406 assertTrue(results.contains(javaDir), "[D] Start Dir");
407 checkContainsFiles("[D] Dir", dirs, results);
408 checkContainsFiles("[D] File", ioFiles, results);
409 }
410
411
412
413
414 @Test
415 public void testFilterDirAndFile1() {
416 final List<File> results = new TestFileFinder(dirsFilter, ioFilesFilter, -1).find(javaDir);
417 assertEquals(1 + dirs.length + ioFiles.length, results.size(), "[DirAndFile1] Result Size");
418 assertTrue(results.contains(javaDir), "[DirAndFile1] Start Dir");
419 checkContainsFiles("[DirAndFile1] Dir", dirs, results);
420 checkContainsFiles("[DirAndFile1] File", ioFiles, results);
421 }
422
423
424
425
426 @Test
427 public void testFilterDirAndFile2() {
428 final List<File> results = new TestFileFinder(null, null, -1).find(javaDir);
429 assertTrue(results.size() > 1 + dirs.length + ioFiles.length, "[DirAndFile2] Result Size");
430 assertTrue(results.contains(javaDir), "[DirAndFile2] Start Dir");
431 checkContainsFiles("[DirAndFile2] Dir", dirs, results);
432 checkContainsFiles("[DirAndFile2] File", ioFiles, results);
433 }
434
435
436
437
438 @Test
439 public void testFilterDirAndFile3() {
440 final List<File> results = new TestFileFinder(dirsFilter, null, -1).find(javaDir);
441 final List<File> resultDirs = directoriesOnly(results);
442 assertEquals(1 + dirs.length, resultDirs.size(), "[DirAndFile3] Result Size");
443 assertTrue(results.contains(javaDir), "[DirAndFile3] Start Dir");
444 checkContainsFiles("[DirAndFile3] Dir", dirs, resultDirs);
445 }
446
447
448
449
450 @Test
451 public void testFilterDirAndFile4() {
452 final List<File> results = new TestFileFinder(null, ioFilesFilter, -1).find(javaDir);
453 final List<File> resultFiles = filesOnly(results);
454 assertEquals(ioFiles.length, resultFiles.size(), "[DirAndFile4] Result Size");
455 assertTrue(results.contains(javaDir), "[DirAndFile4] Start Dir");
456 checkContainsFiles("[DirAndFile4] File", ioFiles, resultFiles);
457 }
458
459
460
461
462 @Test
463 public void testFilterString() {
464 final List<String> results = new TestFileFinderString(dirsAndFilesFilter, -1).find(javaDir);
465 assertEquals(results.size(), outputFiles.length + ioFiles.length, "Result Size");
466 checkContainsString("IO File", ioFiles, results);
467 checkContainsString("Output File", outputFiles, results);
468 }
469
470
471
472
473 @Test
474 public void testHandleStartDirectoryFalse() {
475
476 final List<File> results = new TestFalseFileFinder(null, -1).find(current);
477 assertEquals(0, results.size(), "Result Size");
478
479 }
480
481
482
483
484 @Test
485 public void testLimitToCurrent() {
486 final List<File> results = new TestFileFinder(null, 0).find(current);
487 assertEquals(1, results.size(), "Result Size");
488 assertTrue(results.contains(FileUtils.current()), "Current Dir");
489 }
490
491
492
493
494 @Test
495 public void testMissingStartDirectory() {
496
497
498 final File invalidDir = new File("invalid-dir");
499 final List<File> results = new TestFileFinder(null, -1).find(invalidDir);
500 assertEquals(1, results.size(), "Result Size");
501 assertTrue(results.contains(invalidDir), "Current Dir");
502
503 assertThrows(NullPointerException.class, () -> new TestFileFinder(null, -1).find(null));
504 }
505
506
507
508
509 @Test
510 public void testMultiThreadCancel() {
511 String cancelName = "DirectoryWalker.java";
512 TestMultiThreadCancelWalker walker = new TestMultiThreadCancelWalker(cancelName, false);
513
514 try {
515 walker.find(javaDir);
516 fail("CancelException not thrown for '" + cancelName + "'");
517 } catch (final DirectoryWalker.CancelException cancel) {
518 final File last = walker.results.get(walker.results.size() - 1);
519 assertEquals(cancelName, last.getName());
520 assertEquals(5, cancel.getDepth(), "Depth: " + cancelName);
521 } catch (final IOException ex) {
522 fail("IOException: " + cancelName + " " + ex);
523 }
524
525
526 try {
527 cancelName = "commons";
528 walker = new TestMultiThreadCancelWalker(cancelName, false);
529 walker.find(javaDir);
530 fail("CancelException not thrown for '" + cancelName + "'");
531 } catch (final DirectoryWalker.CancelException cancel) {
532 assertEquals(cancelName, cancel.getFile().getName(), "File: " + cancelName);
533 assertEquals(3, cancel.getDepth(), "Depth: " + cancelName);
534 } catch (final IOException ex) {
535 fail("IOException: " + cancelName + " " + ex);
536 }
537
538
539 try {
540 walker = new TestMultiThreadCancelWalker(cancelName, true);
541 final List<File> results = walker.find(javaDir);
542 final File lastFile = results.get(results.size() - 1);
543 assertEquals(cancelName, lastFile.getName(), "Suppress: " + cancelName);
544 } catch (final IOException ex) {
545 fail("Suppress threw " + ex);
546 }
547
548 }
549
550 }