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