1 use std::fs;
2 use std::path::PathBuf;
3 use std::env;
4 use lazy_static::lazy_static;
5 use std::sync::Mutex;
6 
7 mod util;
8 
9 use jwalk::*;
10 use util::Dir;
11 
12 #[test]
empty()13 fn empty() {
14     let dir = Dir::tmp();
15     let wd = WalkDir::new(dir.path());
16     let r = dir.run_recursive(wd);
17     r.assert_no_errors();
18 
19     assert_eq!(1, r.ents().len());
20     let ent = &r.ents()[0];
21     assert!(ent.file_type().is_dir());
22     assert!(!ent.path_is_symlink());
23     assert_eq!(0, ent.depth());
24     assert_eq!(dir.path(), ent.path());
25     assert_eq!(dir.path().file_name().unwrap(), ent.file_name());
26 }
27 
28 #[test]
empty_follow()29 fn empty_follow() {
30     let dir = Dir::tmp();
31     let wd = WalkDir::new(dir.path()).follow_links(true);
32     let r = dir.run_recursive(wd);
33     r.assert_no_errors();
34 
35     assert_eq!(1, r.ents().len());
36     let ent = &r.ents()[0];
37     assert!(ent.file_type().is_dir());
38     assert!(!ent.path_is_symlink());
39     assert_eq!(0, ent.depth());
40     assert_eq!(dir.path(), ent.path());
41     assert_eq!(dir.path().file_name().unwrap(), ent.file_name());
42 }
43 
44 #[test]
empty_file()45 fn empty_file() {
46     let dir = Dir::tmp();
47     dir.touch("a");
48 
49     let wd = WalkDir::new(dir.path().join("a"));
50     let r = dir.run_recursive(wd);
51     r.assert_no_errors();
52 
53     assert_eq!(1, r.ents().len());
54     let ent = &r.ents()[0];
55     assert!(ent.file_type().is_file());
56     assert!(!ent.path_is_symlink());
57     assert_eq!(0, ent.depth());
58     assert_eq!(dir.join("a"), ent.path());
59     assert_eq!("a", ent.file_name());
60 }
61 
62 #[test]
empty_file_follow()63 fn empty_file_follow() {
64     let dir = Dir::tmp();
65     dir.touch("a");
66 
67     let wd = WalkDir::new(dir.path().join("a")).follow_links(true);
68     let r = dir.run_recursive(wd);
69     r.assert_no_errors();
70 
71     assert_eq!(1, r.ents().len());
72     let ent = &r.ents()[0];
73     assert!(ent.file_type().is_file());
74     assert!(!ent.path_is_symlink());
75     assert_eq!(0, ent.depth());
76     assert_eq!(dir.join("a"), ent.path());
77     assert_eq!("a", ent.file_name());
78 }
79 
80 #[test]
one_dir()81 fn one_dir() {
82     let dir = Dir::tmp();
83     dir.mkdirp("a");
84 
85     let wd = WalkDir::new(dir.path());
86     let r = dir.run_recursive(wd);
87     r.assert_no_errors();
88 
89     let ents = r.ents();
90     assert_eq!(2, ents.len());
91     let ent = &ents[1];
92     assert_eq!(dir.join("a"), ent.path());
93     assert_eq!(1, ent.depth());
94     assert_eq!("a", ent.file_name());
95     assert!(ent.file_type().is_dir());
96 }
97 
98 #[test]
one_file()99 fn one_file() {
100     let dir = Dir::tmp();
101     dir.touch("a");
102 
103     let wd = WalkDir::new(dir.path());
104     let r = dir.run_recursive(wd);
105     r.assert_no_errors();
106 
107     let ents = r.ents();
108     assert_eq!(2, ents.len());
109     let ent = &ents[1];
110     assert_eq!(dir.join("a"), ent.path());
111     assert_eq!(1, ent.depth());
112     assert_eq!("a", ent.file_name());
113     assert!(ent.file_type().is_file());
114 }
115 
116 #[test]
one_dir_one_file()117 fn one_dir_one_file() {
118     let dir = Dir::tmp();
119     dir.mkdirp("foo");
120     dir.touch("foo/a");
121 
122     let wd = WalkDir::new(dir.path()).sort(true);
123     let r = dir.run_recursive(wd);
124     r.assert_no_errors();
125 
126     let expected = vec![
127         dir.path().to_path_buf(),
128         dir.join("foo"),
129         dir.join("foo").join("a"),
130     ];
131     assert_eq!(expected, r.paths());
132 }
133 
134 #[test]
many_files()135 fn many_files() {
136     let dir = Dir::tmp();
137     dir.mkdirp("foo");
138     dir.touch_all(&["foo/a", "foo/b", "foo/c"]);
139 
140     let wd = WalkDir::new(dir.path()).sort(true);
141     let r = dir.run_recursive(wd);
142     r.assert_no_errors();
143 
144     let expected = vec![
145         dir.path().to_path_buf(),
146         dir.join("foo"),
147         dir.join("foo").join("a"),
148         dir.join("foo").join("b"),
149         dir.join("foo").join("c"),
150     ];
151     assert_eq!(expected, r.paths());
152 }
153 
154 #[test]
many_dirs()155 fn many_dirs() {
156     let dir = Dir::tmp();
157     dir.mkdirp("foo/a");
158     dir.mkdirp("foo/b");
159     dir.mkdirp("foo/c");
160 
161     let wd = WalkDir::new(dir.path()).sort(true);
162     let r = dir.run_recursive(wd);
163     r.assert_no_errors();
164 
165     let expected = vec![
166         dir.path().to_path_buf(),
167         dir.join("foo"),
168         dir.join("foo").join("a"),
169         dir.join("foo").join("b"),
170         dir.join("foo").join("c"),
171     ];
172     assert_eq!(expected, r.paths());
173 }
174 
175 #[test]
many_mixed()176 fn many_mixed() {
177     let dir = Dir::tmp();
178     dir.mkdirp("foo/a");
179     dir.mkdirp("foo/c");
180     dir.mkdirp("foo/e");
181     dir.touch_all(&["foo/b", "foo/d", "foo/f"]);
182 
183     let wd = WalkDir::new(dir.path()).sort(true);
184     let r = dir.run_recursive(wd);
185     r.assert_no_errors();
186 
187     let expected = vec![
188         dir.path().to_path_buf(),
189         dir.join("foo"),
190         dir.join("foo").join("a"),
191         dir.join("foo").join("b"),
192         dir.join("foo").join("c"),
193         dir.join("foo").join("d"),
194         dir.join("foo").join("e"),
195         dir.join("foo").join("f"),
196     ];
197     assert_eq!(expected, r.paths());
198 }
199 
200 #[test]
nested()201 fn nested() {
202     let nested = PathBuf::from("a/b/c/d/e/f/g/h/i/j/k/l/m/n/o/p/q/r/s/t/u/v/w/x/y/z");
203     let dir = Dir::tmp();
204     dir.mkdirp(&nested);
205     dir.touch(nested.join("A"));
206 
207     let wd = WalkDir::new(dir.path()).sort(true);
208     let r = dir.run_recursive(wd);
209     r.assert_no_errors();
210 
211     let expected = vec![
212         dir.path().to_path_buf(),
213         dir.join("a"),
214         dir.join("a/b"),
215         dir.join("a/b/c"),
216         dir.join("a/b/c/d"),
217         dir.join("a/b/c/d/e"),
218         dir.join("a/b/c/d/e/f"),
219         dir.join("a/b/c/d/e/f/g"),
220         dir.join("a/b/c/d/e/f/g/h"),
221         dir.join("a/b/c/d/e/f/g/h/i"),
222         dir.join("a/b/c/d/e/f/g/h/i/j"),
223         dir.join("a/b/c/d/e/f/g/h/i/j/k"),
224         dir.join("a/b/c/d/e/f/g/h/i/j/k/l"),
225         dir.join("a/b/c/d/e/f/g/h/i/j/k/l/m"),
226         dir.join("a/b/c/d/e/f/g/h/i/j/k/l/m/n"),
227         dir.join("a/b/c/d/e/f/g/h/i/j/k/l/m/n/o"),
228         dir.join("a/b/c/d/e/f/g/h/i/j/k/l/m/n/o/p"),
229         dir.join("a/b/c/d/e/f/g/h/i/j/k/l/m/n/o/p/q"),
230         dir.join("a/b/c/d/e/f/g/h/i/j/k/l/m/n/o/p/q/r"),
231         dir.join("a/b/c/d/e/f/g/h/i/j/k/l/m/n/o/p/q/r/s"),
232         dir.join("a/b/c/d/e/f/g/h/i/j/k/l/m/n/o/p/q/r/s/t"),
233         dir.join("a/b/c/d/e/f/g/h/i/j/k/l/m/n/o/p/q/r/s/t/u"),
234         dir.join("a/b/c/d/e/f/g/h/i/j/k/l/m/n/o/p/q/r/s/t/u/v"),
235         dir.join("a/b/c/d/e/f/g/h/i/j/k/l/m/n/o/p/q/r/s/t/u/v/w"),
236         dir.join("a/b/c/d/e/f/g/h/i/j/k/l/m/n/o/p/q/r/s/t/u/v/w/x"),
237         dir.join("a/b/c/d/e/f/g/h/i/j/k/l/m/n/o/p/q/r/s/t/u/v/w/x/y"),
238         dir.join("a/b/c/d/e/f/g/h/i/j/k/l/m/n/o/p/q/r/s/t/u/v/w/x/y/z"),
239         dir.join(&nested).join("A"),
240     ];
241     assert_eq!(expected, r.paths());
242 }
243 
244 #[test]
siblings()245 fn siblings() {
246     let dir = Dir::tmp();
247     dir.mkdirp("foo");
248     dir.mkdirp("bar");
249     dir.touch_all(&["foo/a", "foo/b"]);
250     dir.touch_all(&["bar/a", "bar/b"]);
251 
252     let wd = WalkDir::new(dir.path()).sort(true);
253     let r = dir.run_recursive(wd);
254     r.assert_no_errors();
255 
256     let expected = vec![
257         dir.path().to_path_buf(),
258         dir.join("bar"),
259         dir.join("bar").join("a"),
260         dir.join("bar").join("b"),
261         dir.join("foo"),
262         dir.join("foo").join("a"),
263         dir.join("foo").join("b"),
264     ];
265     assert_eq!(expected, r.paths());
266 }
267 
268 #[test]
sym_root_file_nofollow()269 fn sym_root_file_nofollow() {
270     let dir = Dir::tmp();
271     dir.touch("a");
272     dir.symlink_file("a", "a-link");
273 
274     let wd = WalkDir::new(dir.join("a-link")).sort(true);
275     let r = dir.run_recursive(wd);
276     r.assert_no_errors();
277 
278     let ents = r.ents();
279     assert_eq!(1, ents.len());
280     let link = &ents[0];
281 
282     assert_eq!(dir.join("a-link"), link.path());
283 
284     assert!(link.path_is_symlink());
285 
286     assert_eq!(dir.join("a"), fs::read_link(link.path()).unwrap());
287 
288     assert_eq!(0, link.depth());
289 
290     assert!(link.file_type().is_symlink());
291     assert!(!link.file_type().is_file());
292     assert!(!link.file_type().is_dir());
293 
294     assert!(link.metadata().unwrap().file_type().is_symlink());
295     assert!(!link.metadata().unwrap().is_file());
296     assert!(!link.metadata().unwrap().is_dir());
297 }
298 
299 #[test]
sym_root_file_follow()300 fn sym_root_file_follow() {
301     let dir = Dir::tmp();
302     dir.touch("a");
303     dir.symlink_file("a", "a-link");
304 
305     let wd = WalkDir::new(dir.join("a-link"))
306         .sort(true)
307         .follow_links(true);
308     let r = dir.run_recursive(wd);
309     r.assert_no_errors();
310 
311     let ents = r.ents();
312     let link = &ents[0];
313 
314     assert_eq!(dir.join("a-link"), link.path());
315 
316     assert!(link.path_is_symlink());
317 
318     assert_eq!(dir.join("a"), fs::read_link(link.path()).unwrap());
319 
320     assert_eq!(0, link.depth());
321 
322     assert!(!link.file_type().is_symlink());
323     assert!(link.file_type().is_file());
324     assert!(!link.file_type().is_dir());
325 
326     assert!(!link.metadata().unwrap().file_type().is_symlink());
327     assert!(link.metadata().unwrap().is_file());
328     assert!(!link.metadata().unwrap().is_dir());
329 }
330 
331 #[test]
sym_root_dir_nofollow()332 fn sym_root_dir_nofollow() {
333     let dir = Dir::tmp();
334     dir.mkdirp("a");
335     dir.symlink_dir("a", "a-link");
336     dir.touch("a/zzz");
337 
338     let wd = WalkDir::new(dir.join("a-link")).sort(true);
339     let r = dir.run_recursive(wd);
340     r.assert_no_errors();
341 
342     let ents = r.ents();
343     assert_eq!(2, ents.len());
344     let link = &ents[0];
345 
346     assert_eq!(dir.join("a-link"), link.path());
347 
348     assert!(link.path_is_symlink());
349 
350     assert_eq!(dir.join("a"), fs::read_link(link.path()).unwrap());
351 
352     assert_eq!(0, link.depth());
353 
354     assert!(link.file_type().is_symlink());
355     assert!(!link.file_type().is_file());
356     assert!(!link.file_type().is_dir());
357 
358     assert!(link.metadata().unwrap().file_type().is_symlink());
359     assert!(!link.metadata().unwrap().is_file());
360     assert!(!link.metadata().unwrap().is_dir());
361 
362     let link_zzz = &ents[1];
363     assert_eq!(dir.join("a-link").join("zzz"), link_zzz.path());
364     assert!(!link_zzz.path_is_symlink());
365 }
366 
367 #[test]
sym_root_dir_follow()368 fn sym_root_dir_follow() {
369     let dir = Dir::tmp();
370     dir.mkdirp("a");
371     dir.symlink_dir("a", "a-link");
372     dir.touch("a/zzz");
373 
374     let wd = WalkDir::new(dir.join("a-link"))
375         .sort(true)
376         .follow_links(true);
377     let r = dir.run_recursive(wd);
378     r.assert_no_errors();
379 
380     let ents = r.ents();
381     assert_eq!(2, ents.len());
382     let link = &ents[0];
383 
384     assert_eq!(dir.join("a-link"), link.path());
385 
386     assert!(link.path_is_symlink());
387 
388     assert_eq!(dir.join("a"), fs::read_link(link.path()).unwrap());
389 
390     assert_eq!(0, link.depth());
391 
392     assert!(!link.file_type().is_symlink());
393     assert!(!link.file_type().is_file());
394     assert!(link.file_type().is_dir());
395 
396     assert!(!link.metadata().unwrap().file_type().is_symlink());
397     assert!(!link.metadata().unwrap().is_file());
398     assert!(link.metadata().unwrap().is_dir());
399 
400     let link_zzz = &ents[1];
401     assert_eq!(dir.join("a-link").join("zzz"), link_zzz.path());
402     assert!(!link_zzz.path_is_symlink());
403 }
404 
405 #[test]
sym_file_nofollow()406 fn sym_file_nofollow() {
407     let dir = Dir::tmp();
408     dir.touch("a");
409     dir.symlink_file("a", "a-link");
410 
411     let wd = WalkDir::new(dir.path()).sort(true);
412     let r = dir.run_recursive(wd);
413     r.assert_no_errors();
414 
415     let ents = r.ents();
416     assert_eq!(3, ents.len());
417     let (src, link) = (&ents[1], &ents[2]);
418 
419     assert_eq!(dir.join("a"), src.path());
420     assert_eq!(dir.join("a-link"), link.path());
421 
422     assert!(!src.path_is_symlink());
423     assert!(link.path_is_symlink());
424 
425     assert_eq!(dir.join("a"), fs::read_link(link.path()).unwrap());
426 
427     assert_eq!(1, src.depth());
428     assert_eq!(1, link.depth());
429 
430     assert!(src.file_type().is_file());
431     assert!(link.file_type().is_symlink());
432     assert!(!link.file_type().is_file());
433     assert!(!link.file_type().is_dir());
434 
435     assert!(src.metadata().unwrap().is_file());
436     assert!(link.metadata().unwrap().file_type().is_symlink());
437     assert!(!link.metadata().unwrap().is_file());
438     assert!(!link.metadata().unwrap().is_dir());
439 }
440 
441 #[test]
sym_file_follow()442 fn sym_file_follow() {
443     let dir = Dir::tmp();
444     dir.touch("a");
445     dir.symlink_file("a", "a-link");
446 
447     let wd = WalkDir::new(dir.path()).sort(true).follow_links(true);
448     let r = dir.run_recursive(wd);
449     r.assert_no_errors();
450 
451     let ents = r.ents();
452     assert_eq!(3, ents.len());
453     let (src, link) = (&ents[1], &ents[2]);
454 
455     assert_eq!(dir.join("a"), src.path());
456     assert_eq!(dir.join("a-link"), link.path());
457 
458     assert!(!src.path_is_symlink());
459     assert!(link.path_is_symlink());
460 
461     assert_eq!(dir.join("a"), fs::read_link(link.path()).unwrap());
462 
463     assert_eq!(1, src.depth());
464     assert_eq!(1, link.depth());
465 
466     assert!(src.file_type().is_file());
467     assert!(!link.file_type().is_symlink());
468     assert!(link.file_type().is_file());
469     assert!(!link.file_type().is_dir());
470 
471     assert!(src.metadata().unwrap().is_file());
472     assert!(!link.metadata().unwrap().file_type().is_symlink());
473     assert!(link.metadata().unwrap().is_file());
474     assert!(!link.metadata().unwrap().is_dir());
475 }
476 
477 #[test]
sym_dir_nofollow()478 fn sym_dir_nofollow() {
479     let dir = Dir::tmp();
480     dir.mkdirp("a");
481     dir.symlink_dir("a", "a-link");
482     dir.touch("a/zzz");
483 
484     let wd = WalkDir::new(dir.path()).sort(true);
485     let r = dir.run_recursive(wd);
486     r.assert_no_errors();
487 
488     let ents = r.ents();
489     assert_eq!(4, ents.len());
490     let (src, link) = (&ents[1], &ents[3]);
491 
492     assert_eq!(dir.join("a"), src.path());
493     assert_eq!(dir.join("a-link"), link.path());
494 
495     assert!(!src.path_is_symlink());
496     assert!(link.path_is_symlink());
497 
498     assert_eq!(dir.join("a"), fs::read_link(link.path()).unwrap());
499 
500     assert_eq!(1, src.depth());
501     assert_eq!(1, link.depth());
502 
503     assert!(src.file_type().is_dir());
504     assert!(link.file_type().is_symlink());
505     assert!(!link.file_type().is_file());
506     assert!(!link.file_type().is_dir());
507 
508     assert!(src.metadata().unwrap().is_dir());
509     assert!(link.metadata().unwrap().file_type().is_symlink());
510     assert!(!link.metadata().unwrap().is_file());
511     assert!(!link.metadata().unwrap().is_dir());
512 }
513 
514 #[test]
sym_dir_follow()515 fn sym_dir_follow() {
516     let dir = Dir::tmp();
517     dir.mkdirp("a");
518     dir.symlink_dir("a", "a-link");
519     dir.touch("a/zzz");
520 
521     let wd = WalkDir::new(dir.path()).follow_links(true).sort(true);
522     let r = dir.run_recursive(wd);
523     r.assert_no_errors();
524 
525     let ents = r.ents();
526     assert_eq!(5, ents.len());
527     let (src, link) = (&ents[1], &ents[3]);
528 
529     assert_eq!(dir.join("a"), src.path());
530     assert_eq!(dir.join("a-link"), link.path());
531 
532     assert!(!src.path_is_symlink());
533     assert!(link.path_is_symlink());
534 
535     assert_eq!(dir.join("a"), fs::read_link(link.path()).unwrap());
536 
537     assert_eq!(1, src.depth());
538     assert_eq!(1, link.depth());
539 
540     assert!(src.file_type().is_dir());
541     assert!(!link.file_type().is_symlink());
542     assert!(!link.file_type().is_file());
543     assert!(link.file_type().is_dir());
544 
545     assert!(src.metadata().unwrap().is_dir());
546     assert!(!link.metadata().unwrap().file_type().is_symlink());
547     assert!(!link.metadata().unwrap().is_file());
548     assert!(link.metadata().unwrap().is_dir());
549 
550     let (src_zzz, link_zzz) = (&ents[2], &ents[4]);
551     assert_eq!(dir.join("a").join("zzz"), src_zzz.path());
552     assert_eq!(dir.join("a-link").join("zzz"), link_zzz.path());
553     assert!(!src_zzz.path_is_symlink());
554     assert!(!link_zzz.path_is_symlink());
555 }
556 
557 #[test]
sym_noloop()558 fn sym_noloop() {
559     let dir = Dir::tmp();
560     dir.mkdirp("a/b/c");
561     dir.symlink_dir("a", "a/b/c/a-link");
562 
563     let wd = WalkDir::new(dir.path());
564     let r = dir.run_recursive(wd);
565     // There's no loop if we aren't following symlinks.
566     r.assert_no_errors();
567 
568     assert_eq!(5, r.ents().len());
569 }
570 
571 #[test]
sym_loop_detect()572 fn sym_loop_detect() {
573     let dir = Dir::tmp();
574     dir.mkdirp("a/b/c");
575     dir.symlink_dir("a", "a/b/c/a-link");
576 
577     let wd = WalkDir::new(dir.path()).follow_links(true);
578     let r = dir.run_recursive(wd);
579 
580     let (ents, errs) = (r.ents(), r.errs());
581     assert_eq!(4, ents.len());
582     assert_eq!(1, errs.len());
583 
584     let err = &errs[0];
585 
586     let expected = dir.join("a/b/c/a-link");
587     assert_eq!(Some(&*expected), err.path());
588 
589     let expected = dir.join("a");
590     assert_eq!(Some(&*expected), err.loop_ancestor());
591 
592     assert_eq!(4, err.depth());
593     assert!(err.io_error().is_none());
594 }
595 
596 #[test]
sym_self_loop_no_error()597 fn sym_self_loop_no_error() {
598     let dir = Dir::tmp();
599     dir.symlink_file("a", "a");
600 
601     let wd = WalkDir::new(dir.path());
602     let r = dir.run_recursive(wd);
603     // No errors occur because even though the symlink points to nowhere, it
604     // is never followed, and thus no error occurs.
605     r.assert_no_errors();
606     assert_eq!(2, r.ents().len());
607 
608     let ent = &r.ents()[1];
609     assert_eq!(dir.join("a"), ent.path());
610     assert!(ent.path_is_symlink());
611 
612     assert!(ent.file_type().is_symlink());
613     assert!(!ent.file_type().is_file());
614     assert!(!ent.file_type().is_dir());
615 
616     assert!(ent.metadata().unwrap().file_type().is_symlink());
617     assert!(!ent.metadata().unwrap().file_type().is_file());
618     assert!(!ent.metadata().unwrap().file_type().is_dir());
619 }
620 
621 #[test]
sym_file_self_loop_io_error()622 fn sym_file_self_loop_io_error() {
623     let dir = Dir::tmp();
624     dir.symlink_file("a", "a");
625 
626     let wd = WalkDir::new(dir.path()).follow_links(true);
627     let r = dir.run_recursive(wd);
628 
629     let (ents, errs) = (r.ents(), r.errs());
630     assert_eq!(1, ents.len());
631     assert_eq!(1, errs.len());
632 
633     let err = &errs[0];
634 
635     let expected = dir.join("a");
636     assert_eq!(Some(&*expected), err.path());
637     assert_eq!(1, err.depth());
638     assert!(err.loop_ancestor().is_none());
639     assert!(err.io_error().is_some());
640 }
641 
642 #[test]
sym_dir_self_loop_io_error()643 fn sym_dir_self_loop_io_error() {
644     let dir = Dir::tmp();
645     dir.symlink_dir("a", "a");
646 
647     let wd = WalkDir::new(dir.path()).follow_links(true);
648     let r = dir.run_recursive(wd);
649 
650     let (ents, errs) = (r.ents(), r.errs());
651     assert_eq!(1, ents.len());
652     assert_eq!(1, errs.len());
653 
654     let err = &errs[0];
655 
656     let expected = dir.join("a");
657     assert_eq!(Some(&*expected), err.path());
658     assert_eq!(1, err.depth());
659     assert!(err.loop_ancestor().is_none());
660     assert!(err.io_error().is_some());
661 }
662 
663 #[test]
min_depth_1()664 fn min_depth_1() {
665     let dir = Dir::tmp();
666     dir.mkdirp("a/b");
667 
668     let wd = WalkDir::new(dir.path()).min_depth(1).sort(true);
669     let r = dir.run_recursive(wd);
670     r.assert_no_errors();
671 
672     let expected = vec![dir.join("a"), dir.join("a").join("b")];
673     assert_eq!(expected, r.paths());
674 }
675 
676 #[test]
min_depth_2()677 fn min_depth_2() {
678     let dir = Dir::tmp();
679     dir.mkdirp("a/b");
680 
681     let wd = WalkDir::new(dir.path()).min_depth(2).sort(true);
682     let r = dir.run_recursive(wd);
683     r.assert_no_errors();
684 
685     let expected = vec![dir.join("a").join("b")];
686     assert_eq!(expected, r.paths());
687 }
688 
689 #[test]
max_depth_0()690 fn max_depth_0() {
691     let dir = Dir::tmp();
692     dir.mkdirp("a/b");
693 
694     let wd = WalkDir::new(dir.path()).max_depth(0).sort(true);
695     let r = dir.run_recursive(wd);
696     r.assert_no_errors();
697 
698     let expected = vec![dir.path().to_path_buf()];
699     assert_eq!(expected, r.paths());
700 }
701 
702 #[test]
max_depth_1()703 fn max_depth_1() {
704     let dir = Dir::tmp();
705     dir.mkdirp("a/b");
706 
707     let wd = WalkDir::new(dir.path()).max_depth(1).sort(true);
708     let r = dir.run_recursive(wd);
709     r.assert_no_errors();
710 
711     let expected = vec![dir.path().to_path_buf(), dir.join("a")];
712     assert_eq!(expected, r.paths());
713 }
714 
715 #[test]
max_depth_2()716 fn max_depth_2() {
717     let dir = Dir::tmp();
718     dir.mkdirp("a/b");
719 
720     let wd = WalkDir::new(dir.path()).max_depth(2).sort(true);
721     let r = dir.run_recursive(wd);
722     r.assert_no_errors();
723 
724     let expected = vec![
725         dir.path().to_path_buf(),
726         dir.join("a"),
727         dir.join("a").join("b"),
728     ];
729     assert_eq!(expected, r.paths());
730 }
731 
732 /*
733 // FIXME: This test seems wrong. It should return nothing!
734 #[test]
735 fn min_max_depth_diff_nada() {
736     let dir = Dir::tmp();
737     dir.mkdirp("a/b/c");
738 
739     let wd = WalkDir::new(dir.path()).min_depth(3).max_depth(2);
740     let r = dir.run_recursive(wd);
741     r.assert_no_errors();
742 
743     let expected = vec![
744         dir.join("a").join("b").join("c"),
745     ];
746     assert_eq!(expected, r.sorted_paths());
747 }
748 */
749 
750 #[test]
min_max_depth_diff_0()751 fn min_max_depth_diff_0() {
752     let dir = Dir::tmp();
753     dir.mkdirp("a/b/c");
754 
755     let wd = WalkDir::new(dir.path())
756         .min_depth(2)
757         .max_depth(2)
758         .sort(true);
759     let r = dir.run_recursive(wd);
760     r.assert_no_errors();
761 
762     let expected = vec![dir.join("a").join("b")];
763     assert_eq!(expected, r.paths());
764 }
765 
766 #[test]
min_max_depth_diff_1()767 fn min_max_depth_diff_1() {
768     let dir = Dir::tmp();
769     dir.mkdirp("a/b/c");
770 
771     let wd = WalkDir::new(dir.path())
772         .min_depth(1)
773         .max_depth(2)
774         .sort(true);
775     let r = dir.run_recursive(wd);
776     r.assert_no_errors();
777 
778     let expected = vec![dir.join("a"), dir.join("a").join("b")];
779     assert_eq!(expected, r.paths());
780 }
781 
782 /*
783 #[test]
784 fn contents_first() {
785     let dir = Dir::tmp();
786     dir.touch("a");
787 
788     let wd = WalkDir::new(dir.path()).contents_first(true);
789     let r = dir.run_recursive(wd);
790     r.assert_no_errors();
791 
792     let expected = vec![
793         dir.join("a"),
794         dir.path().to_path_buf(),
795     ];
796     assert_eq!(expected, r.paths());
797 }
798 
799 #[test]
800 fn skip_current_dir() {
801     let dir = Dir::tmp();
802     dir.mkdirp("foo/bar/baz");
803     dir.mkdirp("quux");
804 
805     let mut paths = vec![];
806     let mut it = WalkDir::new(dir.path()).into_iter();
807     while let Some(result) = it.next() {
808         let ent = result.unwrap();
809         paths.push(ent.path().to_path_buf());
810         if ent.file_name() == "bar" {
811             it.skip_current_dir();
812         }
813     }
814     paths.sort();
815 
816     let expected = vec![
817         dir.path().to_path_buf(),
818         dir.join("foo"),
819         dir.join("foo").join("bar"),
820         dir.join("quux"),
821     ];
822     assert_eq!(expected, paths);
823 }
824 
825 #[test]
826 fn filter_entry() {
827     let dir = Dir::tmp();
828     dir.mkdirp("foo/bar/baz/abc");
829     dir.mkdirp("quux");
830 
831     let wd = WalkDir::new(dir.path())
832         .into_iter()
833         .filter_entry(|ent| ent.file_name() != "baz");
834     let r = dir.run_recursive(wd);
835     r.assert_no_errors();
836 
837     let expected = vec![
838         dir.path().to_path_buf(),
839         dir.join("foo"),
840         dir.join("foo").join("bar"),
841         dir.join("quux"),
842     ];
843     assert_eq!(expected, r.sorted_paths());
844 }
845 */
846 
847 #[test]
sort()848 fn sort() {
849     let dir = Dir::tmp();
850     dir.mkdirp("foo/bar/baz/abc");
851     dir.mkdirp("quux");
852 
853     let wd = WalkDir::new(dir.path()).sort(true);
854     let r = dir.run_recursive(wd);
855     r.assert_no_errors();
856 
857     let expected = vec![
858         dir.path().to_path_buf(),
859         dir.join("foo"),
860         dir.join("foo").join("bar"),
861         dir.join("foo").join("bar").join("baz"),
862         dir.join("foo").join("bar").join("baz").join("abc"),
863         dir.join("quux"),
864     ];
865     assert_eq!(expected, r.paths());
866 }
867 
868 /*
869 
870 #[cfg(target_os = "linux")]
871 #[test]
872 fn same_file_system() {
873     use std::path::Path;
874 
875     // This test is a little weird since it's not clear whether it's a good
876     // idea to setup a distinct mounted volume in these tests. Instead, we
877     // probe for an existing one.
878     if !Path::new("/sys").is_dir() {
879         return;
880     }
881 
882     let dir = Dir::tmp();
883     dir.touch("a");
884     dir.symlink_dir("/sys", "sys-link");
885 
886     // First, do a sanity check that things work without following symlinks.
887     let wd = WalkDir::new(dir.path());
888     let r = dir.run_recursive(wd);
889     r.assert_no_errors();
890 
891     let expected = vec![
892         dir.path().to_path_buf(),
893         dir.join("a"),
894         dir.join("sys-link"),
895     ];
896     assert_eq!(expected, r.sorted_paths());
897 
898     // ... now follow symlinks and ensure we don't descend into /sys.
899     let wd = WalkDir::new(dir.path())
900         .same_file_system(true)
901         .follow_links(true);
902     let r = dir.run_recursive(wd);
903     r.assert_no_errors();
904 
905     let expected = vec![
906         dir.path().to_path_buf(),
907         dir.join("a"),
908         dir.join("sys-link"),
909     ];
910     assert_eq!(expected, r.sorted_paths());
911 }
912 
913 // Tests that skip_current_dir doesn't destroy internal invariants.
914 //
915 // See: https://github.com/BurntSushi/walkdir/issues/118
916 #[test]
917 fn regression_skip_current_dir() {
918     let dir = Dir::tmp();
919     dir.mkdirp("foo/a/b");
920     dir.mkdirp("foo/1/2");
921 
922     let mut wd = WalkDir::new(dir.path()).max_open(1).into_iter();
923     wd.next();
924     wd.next();
925     wd.next();
926     wd.next();
927 
928     wd.skip_current_dir();
929     wd.skip_current_dir();
930     wd.next();
931 }
932 */
933 
934 use fs_extra;
935 
test_dir() -> (PathBuf, tempfile::TempDir)936 fn test_dir() -> (PathBuf, tempfile::TempDir) {
937     let template = PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("tests/assets/test_dir");
938     let temp_dir = tempfile::tempdir().unwrap();
939     let options = fs_extra::dir::CopyOptions::new();
940     fs_extra::dir::copy(&template, &temp_dir, &options).unwrap();
941     let mut test_dir = temp_dir.path().to_path_buf();
942     test_dir.push(template.file_name().unwrap());
943     (test_dir, temp_dir)
944 }
945 
local_paths(walk_dir: WalkDir) -> Vec<String>946 fn local_paths(walk_dir: WalkDir) -> Vec<String> {
947     let root = walk_dir.root().to_owned();
948     walk_dir
949         .into_iter()
950         .map(|each_result| {
951             let each_entry = each_result.unwrap();
952             let path = each_entry.path().to_path_buf();
953             let path = path.strip_prefix(&root).unwrap().to_path_buf();
954             let mut path_string = path.to_str().unwrap().to_string();
955             path_string.push_str(&format!(" ({})", each_entry.depth));
956             path_string
957         })
958         .collect()
959 }
960 
961 #[test]
walk_serial()962 fn walk_serial() {
963     let (test_dir, _temp_dir) = test_dir();
964 
965     let paths = local_paths(
966         WalkDir::new(test_dir)
967             .parallelism(Parallelism::Serial)
968             .sort(true),
969     );
970     assert!(
971         paths
972             == vec![
973                 " (0)",
974                 "a.txt (1)",
975                 "b.txt (1)",
976                 "c.txt (1)",
977                 "group 1 (1)",
978                 "group 1/d.txt (2)",
979                 "group 2 (1)",
980                 "group 2/e.txt (2)",
981             ]
982     );
983 }
984 
985 #[test]
sort_by_name_rayon_custom_2_threads()986 fn sort_by_name_rayon_custom_2_threads() {
987     let (test_dir, _temp_dir) = test_dir();
988     let paths = local_paths(
989         WalkDir::new(test_dir)
990             .parallelism(Parallelism::RayonNewPool(2))
991             .sort(true),
992     );
993     assert!(
994         paths
995             == vec![
996                 " (0)",
997                 "a.txt (1)",
998                 "b.txt (1)",
999                 "c.txt (1)",
1000                 "group 1 (1)",
1001                 "group 1/d.txt (2)",
1002                 "group 2 (1)",
1003                 "group 2/e.txt (2)",
1004             ]
1005     );
1006 }
1007 
1008 #[test]
walk_rayon_global()1009 fn walk_rayon_global() {
1010     let (test_dir, _temp_dir) = test_dir();
1011     let paths = local_paths(WalkDir::new(test_dir).sort(true));
1012     assert!(
1013         paths
1014             == vec![
1015                 " (0)",
1016                 "a.txt (1)",
1017                 "b.txt (1)",
1018                 "c.txt (1)",
1019                 "group 1 (1)",
1020                 "group 1/d.txt (2)",
1021                 "group 2 (1)",
1022                 "group 2/e.txt (2)",
1023             ]
1024     );
1025 }
1026 
1027 #[test]
walk_rayon_no_lockup()1028 fn walk_rayon_no_lockup() {
1029     // Without jwalk_par_bridge this locks
1030     let pool = std::sync::Arc::new(
1031         rayon::ThreadPoolBuilder::new()
1032             .num_threads(1)
1033             .build()
1034             .unwrap(),
1035     );
1036     let _: Vec<_> = WalkDir::new(PathBuf::from(env!("CARGO_MANIFEST_DIR")))
1037         .parallelism(Parallelism::RayonExistingPool(pool))
1038         .process_read_dir(|_, dir_entry_results| {
1039             for dir_entry_result in dir_entry_results {
1040                 let _ = dir_entry_result
1041                     .as_ref()
1042                     .map(|dir_entry| dir_entry.metadata());
1043             }
1044         })
1045         .sort(true)
1046         .into_iter()
1047         .collect();
1048 }
1049 
1050 #[test]
see_hidden_files()1051 fn see_hidden_files() {
1052     let (test_dir, _temp_dir) = test_dir();
1053     let paths = local_paths(WalkDir::new(test_dir).skip_hidden(false).sort(true));
1054     assert!(paths.contains(&"group 2/.hidden_file.txt (2)".to_string()));
1055 }
1056 
1057 #[test]
walk_file()1058 fn walk_file() {
1059     let (test_dir, _temp_dir) = test_dir();
1060     let walk_dir = WalkDir::new(test_dir.join("a.txt"));
1061     let mut iter = walk_dir.into_iter();
1062     assert!(iter.next().unwrap().unwrap().file_name.to_str().unwrap() == "a.txt");
1063     assert!(iter.next().is_none());
1064 }
1065 
1066 #[test]
walk_file_serial()1067 fn walk_file_serial() {
1068     let (test_dir, _temp_dir) = test_dir();
1069     let walk_dir = WalkDir::new(test_dir.join("a.txt")).parallelism(Parallelism::Serial);
1070     let mut iter = walk_dir.into_iter();
1071     assert!(iter.next().unwrap().unwrap().file_name.to_str().unwrap() == "a.txt");
1072     assert!(iter.next().is_none());
1073 }
1074 
1075 #[test]
error_when_path_does_not_exist()1076 fn error_when_path_does_not_exist() {
1077     let (test_dir, _temp_dir) = test_dir();
1078     let walk_dir = WalkDir::new(test_dir.join("path_does_not_exist"));
1079     let mut iter = walk_dir.into_iter();
1080     assert!(iter.next().unwrap().is_err());
1081     assert!(iter.next().is_none());
1082 }
1083 
1084 #[test]
error_when_path_removed_durring_iteration()1085 fn error_when_path_removed_durring_iteration() {
1086     let (test_dir, _temp_dir) = test_dir();
1087     let walk_dir = WalkDir::new(&test_dir)
1088         .parallelism(Parallelism::Serial)
1089         .sort(true);
1090     let mut iter = walk_dir.into_iter();
1091 
1092     // Read root. read_dir for root is also called since single thread mode.
1093     let _ = iter.next().unwrap().is_ok(); // " (0)",
1094 
1095     // Remove group 2 dir from disk
1096     fs_extra::remove_items(&vec![test_dir.join("group 2")]).unwrap();
1097 
1098     let _ = iter.next().unwrap().is_ok(); // "a.txt (1)",
1099     let _ = iter.next().unwrap().is_ok(); // "b.txt (1)",
1100     let _ = iter.next().unwrap().is_ok(); // "c.txt (1)",
1101     let _ = iter.next().unwrap().is_ok(); // "group 1 (1)",
1102     let _ = iter.next().unwrap().is_ok(); // "group 1/d.txt (2)",
1103 
1104     // group 2 is read correctly, since it was read before path removed.
1105     let group_2 = iter.next().unwrap().unwrap();
1106 
1107     // group 2 content error IS set, since path is removed when try read_dir for
1108     // group 2 path.
1109     let _ = group_2.read_children_error.is_some();
1110 
1111     // done!
1112     assert!(iter.next().is_none());
1113 }
1114 
1115 #[test]
walk_root()1116 fn walk_root() {
1117     let paths: Vec<_> = WalkDir::new("/")
1118         .max_depth(1)
1119         .sort(true)
1120         .into_iter()
1121         .filter_map(|each| Some(each.ok()?.path()))
1122         .collect();
1123     assert!(paths.first().unwrap().to_str().unwrap() == "/");
1124 }
1125 
1126 lazy_static! {
1127     static ref RELATIVE_MUTEX: Mutex<()> = Mutex::new(());
1128 }
1129 
1130 #[test]
walk_relative_1()1131 fn walk_relative_1() {
1132     let _shared = RELATIVE_MUTEX.lock().unwrap();
1133     let (test_dir, _temp_dir) = test_dir();
1134 
1135     env::set_current_dir(&test_dir).unwrap();
1136 
1137     let paths = local_paths(
1138         WalkDir::new(".").sort(true),
1139     );
1140 
1141     assert_eq!(
1142         paths,
1143         vec![
1144             " (0)",
1145             "a.txt (1)",
1146             "b.txt (1)",
1147             "c.txt (1)",
1148             "group 1 (1)",
1149             "group 1/d.txt (2)",
1150             "group 2 (1)",
1151             "group 2/e.txt (2)",
1152         ]
1153     );
1154 
1155     let root_dir_entry = WalkDir::new("..").into_iter().next().unwrap().unwrap();
1156     assert_eq!(&root_dir_entry.file_name, "..");
1157 }
1158 
1159 #[test]
walk_relative_2()1160 fn walk_relative_2() {
1161     let _shared = RELATIVE_MUTEX.lock().unwrap();
1162     let (test_dir, _temp_dir) = test_dir();
1163 
1164     env::set_current_dir(&test_dir.join("group 1")).unwrap();
1165 
1166     let paths = local_paths(
1167         WalkDir::new("..").sort(true),
1168     );
1169 
1170     assert_eq!(
1171         paths,
1172         vec![
1173             " (0)",
1174             "a.txt (1)",
1175             "b.txt (1)",
1176             "c.txt (1)",
1177             "group 1 (1)",
1178             "group 1/d.txt (2)",
1179             "group 2 (1)",
1180             "group 2/e.txt (2)",
1181         ]
1182     );
1183 
1184     let root_dir_entry = WalkDir::new(".").into_iter().next().unwrap().unwrap();
1185     assert_eq!(&root_dir_entry.file_name, ".");
1186 
1187 }
1188 
1189 #[test]
filter_groups_with_process_read_dir()1190 fn filter_groups_with_process_read_dir() {
1191     let (test_dir, _temp_dir) = test_dir();
1192     let paths = local_paths(
1193         WalkDir::new(test_dir)
1194             .sort(true)
1195             // Filter groups out manually
1196             .process_read_dir(|_parent, children| {
1197                 children.retain(|each_result| {
1198                     each_result
1199                         .as_ref()
1200                         .map(|dir_entry| {
1201                             !dir_entry.file_name.to_string_lossy().starts_with("group")
1202                         })
1203                         .unwrap_or(true)
1204                 });
1205             }),
1206     );
1207     assert!(paths == vec![" (0)", "a.txt (1)", "b.txt (1)", "c.txt (1)",]);
1208 }
1209 
1210 #[test]
filter_group_children_with_process_read_dir()1211 fn filter_group_children_with_process_read_dir() {
1212     let (test_dir, _temp_dir) = test_dir();
1213     let paths = local_paths(
1214         WalkDir::new(test_dir)
1215             .sort(true)
1216             // Filter group children
1217             .process_read_dir(|_parent, children| {
1218                 children.iter_mut().for_each(|each_result| {
1219                     if let Ok(each) = each_result {
1220                         if each.file_name.to_string_lossy().starts_with("group") {
1221                             each.read_children_path = None;
1222                         }
1223                     }
1224                 });
1225             }),
1226     );
1227     assert!(
1228         paths
1229             == vec![
1230                 " (0)",
1231                 "a.txt (1)",
1232                 "b.txt (1)",
1233                 "c.txt (1)",
1234                 "group 1 (1)",
1235                 "group 2 (1)",
1236             ]
1237     );
1238 }
1239 
1240 /*
1241 #[test]
1242 fn save_state_with_process_read_dir() {
1243     let (test_dir, _temp_dir) = test_dir();
1244 
1245     // Test that both parent client state and children client state can be set
1246     // from process_read_dir callback.
1247     let mut iter = WalkDirGeneric::<(usize, usize)>::new(test_dir)
1248         .sort(true)
1249         .process_read_dir(|parent_branch_state, children| {
1250             *parent_branch_state += children.len();
1251             children.iter_mut().for_each(|each_result| {
1252                 if let Ok(each) = each_result {
1253                     if each.file_type.is_dir() {
1254                         client_state += 1;
1255                     }
1256                     each.client_state = *parent_branch_state;
1257                     each.client_state = 1;
1258                 }
1259             });
1260         })
1261         .into_iter();
1262 
1263     assert!(iter.next().unwrap().unwrap().client_state == 6); // " (0)"
1264     assert!(iter.next().unwrap().unwrap().client_state == 1); // "a.txt (1)"
1265     assert!(iter.next().unwrap().unwrap().client_state == 1); // "b.txt (1)"
1266     assert!(iter.next().unwrap().unwrap().client_state == 1); // "c.txt (1)"
1267     assert!(iter.next().unwrap().unwrap().client_state == 2); // "group 1 (1)",
1268     assert!(iter.next().unwrap().unwrap().client_state == 1); // "group 1/d.txt (2)",
1269     assert!(iter.next().unwrap().unwrap().client_state == 2); // "group 2 (1)",
1270     assert!(iter.next().unwrap().unwrap().client_state == 1); // "group 2/e.txt (2)",
1271     assert!(iter.next().is_none());
1272 }
1273 */
1274