1 use std::fs;
2 use std::path::PathBuf;
3 
4 use crate::tests::util::Dir;
5 use crate::WalkDir;
6 
7 #[test]
send_sync_traits()8 fn send_sync_traits() {
9     use crate::{FilterEntry, IntoIter};
10 
11     fn assert_send<T: Send>() {}
12     fn assert_sync<T: Sync>() {}
13 
14     assert_send::<WalkDir>();
15     assert_sync::<WalkDir>();
16     assert_send::<IntoIter>();
17     assert_sync::<IntoIter>();
18     assert_send::<FilterEntry<IntoIter, u8>>();
19     assert_sync::<FilterEntry<IntoIter, u8>>();
20 }
21 
22 #[test]
empty()23 fn empty() {
24     let dir = Dir::tmp();
25     let wd = WalkDir::new(dir.path());
26     let r = dir.run_recursive(wd);
27     r.assert_no_errors();
28 
29     assert_eq!(1, r.ents().len());
30     let ent = &r.ents()[0];
31     assert!(ent.file_type().is_dir());
32     assert!(!ent.path_is_symlink());
33     assert_eq!(0, ent.depth());
34     assert_eq!(dir.path(), ent.path());
35     assert_eq!(dir.path().file_name().unwrap(), ent.file_name());
36 }
37 
38 #[test]
empty_follow()39 fn empty_follow() {
40     let dir = Dir::tmp();
41     let wd = WalkDir::new(dir.path()).follow_links(true);
42     let r = dir.run_recursive(wd);
43     r.assert_no_errors();
44 
45     assert_eq!(1, r.ents().len());
46     let ent = &r.ents()[0];
47     assert!(ent.file_type().is_dir());
48     assert!(!ent.path_is_symlink());
49     assert_eq!(0, ent.depth());
50     assert_eq!(dir.path(), ent.path());
51     assert_eq!(dir.path().file_name().unwrap(), ent.file_name());
52 }
53 
54 #[test]
empty_file()55 fn empty_file() {
56     let dir = Dir::tmp();
57     dir.touch("a");
58 
59     let wd = WalkDir::new(dir.path().join("a"));
60     let r = dir.run_recursive(wd);
61     r.assert_no_errors();
62 
63     assert_eq!(1, r.ents().len());
64     let ent = &r.ents()[0];
65     assert!(ent.file_type().is_file());
66     assert!(!ent.path_is_symlink());
67     assert_eq!(0, ent.depth());
68     assert_eq!(dir.join("a"), ent.path());
69     assert_eq!("a", ent.file_name());
70 }
71 
72 #[test]
empty_file_follow()73 fn empty_file_follow() {
74     let dir = Dir::tmp();
75     dir.touch("a");
76 
77     let wd = WalkDir::new(dir.path().join("a")).follow_links(true);
78     let r = dir.run_recursive(wd);
79     r.assert_no_errors();
80 
81     assert_eq!(1, r.ents().len());
82     let ent = &r.ents()[0];
83     assert!(ent.file_type().is_file());
84     assert!(!ent.path_is_symlink());
85     assert_eq!(0, ent.depth());
86     assert_eq!(dir.join("a"), ent.path());
87     assert_eq!("a", ent.file_name());
88 }
89 
90 #[test]
one_dir()91 fn one_dir() {
92     let dir = Dir::tmp();
93     dir.mkdirp("a");
94 
95     let wd = WalkDir::new(dir.path());
96     let r = dir.run_recursive(wd);
97     r.assert_no_errors();
98 
99     let ents = r.ents();
100     assert_eq!(2, ents.len());
101     let ent = &ents[1];
102     assert_eq!(dir.join("a"), ent.path());
103     assert_eq!(1, ent.depth());
104     assert_eq!("a", ent.file_name());
105     assert!(ent.file_type().is_dir());
106 }
107 
108 #[test]
one_file()109 fn one_file() {
110     let dir = Dir::tmp();
111     dir.touch("a");
112 
113     let wd = WalkDir::new(dir.path());
114     let r = dir.run_recursive(wd);
115     r.assert_no_errors();
116 
117     let ents = r.ents();
118     assert_eq!(2, ents.len());
119     let ent = &ents[1];
120     assert_eq!(dir.join("a"), ent.path());
121     assert_eq!(1, ent.depth());
122     assert_eq!("a", ent.file_name());
123     assert!(ent.file_type().is_file());
124 }
125 
126 #[test]
one_dir_one_file()127 fn one_dir_one_file() {
128     let dir = Dir::tmp();
129     dir.mkdirp("foo");
130     dir.touch("foo/a");
131 
132     let wd = WalkDir::new(dir.path());
133     let r = dir.run_recursive(wd);
134     r.assert_no_errors();
135 
136     let expected = vec![
137         dir.path().to_path_buf(),
138         dir.join("foo"),
139         dir.join("foo").join("a"),
140     ];
141     assert_eq!(expected, r.sorted_paths());
142 }
143 
144 #[test]
many_files()145 fn many_files() {
146     let dir = Dir::tmp();
147     dir.mkdirp("foo");
148     dir.touch_all(&["foo/a", "foo/b", "foo/c"]);
149 
150     let wd = WalkDir::new(dir.path());
151     let r = dir.run_recursive(wd);
152     r.assert_no_errors();
153 
154     let expected = vec![
155         dir.path().to_path_buf(),
156         dir.join("foo"),
157         dir.join("foo").join("a"),
158         dir.join("foo").join("b"),
159         dir.join("foo").join("c"),
160     ];
161     assert_eq!(expected, r.sorted_paths());
162 }
163 
164 #[test]
many_dirs()165 fn many_dirs() {
166     let dir = Dir::tmp();
167     dir.mkdirp("foo/a");
168     dir.mkdirp("foo/b");
169     dir.mkdirp("foo/c");
170 
171     let wd = WalkDir::new(dir.path());
172     let r = dir.run_recursive(wd);
173     r.assert_no_errors();
174 
175     let expected = vec![
176         dir.path().to_path_buf(),
177         dir.join("foo"),
178         dir.join("foo").join("a"),
179         dir.join("foo").join("b"),
180         dir.join("foo").join("c"),
181     ];
182     assert_eq!(expected, r.sorted_paths());
183 }
184 
185 #[test]
many_mixed()186 fn many_mixed() {
187     let dir = Dir::tmp();
188     dir.mkdirp("foo/a");
189     dir.mkdirp("foo/c");
190     dir.mkdirp("foo/e");
191     dir.touch_all(&["foo/b", "foo/d", "foo/f"]);
192 
193     let wd = WalkDir::new(dir.path());
194     let r = dir.run_recursive(wd);
195     r.assert_no_errors();
196 
197     let expected = vec![
198         dir.path().to_path_buf(),
199         dir.join("foo"),
200         dir.join("foo").join("a"),
201         dir.join("foo").join("b"),
202         dir.join("foo").join("c"),
203         dir.join("foo").join("d"),
204         dir.join("foo").join("e"),
205         dir.join("foo").join("f"),
206     ];
207     assert_eq!(expected, r.sorted_paths());
208 }
209 
210 #[test]
nested()211 fn nested() {
212     let nested =
213         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");
214     let dir = Dir::tmp();
215     dir.mkdirp(&nested);
216     dir.touch(nested.join("A"));
217 
218     let wd = WalkDir::new(dir.path());
219     let r = dir.run_recursive(wd);
220     r.assert_no_errors();
221 
222     let expected = vec![
223         dir.path().to_path_buf(),
224         dir.join("a"),
225         dir.join("a/b"),
226         dir.join("a/b/c"),
227         dir.join("a/b/c/d"),
228         dir.join("a/b/c/d/e"),
229         dir.join("a/b/c/d/e/f"),
230         dir.join("a/b/c/d/e/f/g"),
231         dir.join("a/b/c/d/e/f/g/h"),
232         dir.join("a/b/c/d/e/f/g/h/i"),
233         dir.join("a/b/c/d/e/f/g/h/i/j"),
234         dir.join("a/b/c/d/e/f/g/h/i/j/k"),
235         dir.join("a/b/c/d/e/f/g/h/i/j/k/l"),
236         dir.join("a/b/c/d/e/f/g/h/i/j/k/l/m"),
237         dir.join("a/b/c/d/e/f/g/h/i/j/k/l/m/n"),
238         dir.join("a/b/c/d/e/f/g/h/i/j/k/l/m/n/o"),
239         dir.join("a/b/c/d/e/f/g/h/i/j/k/l/m/n/o/p"),
240         dir.join("a/b/c/d/e/f/g/h/i/j/k/l/m/n/o/p/q"),
241         dir.join("a/b/c/d/e/f/g/h/i/j/k/l/m/n/o/p/q/r"),
242         dir.join("a/b/c/d/e/f/g/h/i/j/k/l/m/n/o/p/q/r/s"),
243         dir.join("a/b/c/d/e/f/g/h/i/j/k/l/m/n/o/p/q/r/s/t"),
244         dir.join("a/b/c/d/e/f/g/h/i/j/k/l/m/n/o/p/q/r/s/t/u"),
245         dir.join("a/b/c/d/e/f/g/h/i/j/k/l/m/n/o/p/q/r/s/t/u/v"),
246         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"),
247         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"),
248         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"),
249         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"),
250         dir.join(&nested).join("A"),
251     ];
252     assert_eq!(expected, r.sorted_paths());
253 }
254 
255 #[test]
nested_small_max_open()256 fn nested_small_max_open() {
257     let nested =
258         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");
259     let dir = Dir::tmp();
260     dir.mkdirp(&nested);
261     dir.touch(nested.join("A"));
262 
263     let wd = WalkDir::new(dir.path()).max_open(1);
264     let r = dir.run_recursive(wd);
265     r.assert_no_errors();
266 
267     let expected = vec![
268         dir.path().to_path_buf(),
269         dir.join("a"),
270         dir.join("a/b"),
271         dir.join("a/b/c"),
272         dir.join("a/b/c/d"),
273         dir.join("a/b/c/d/e"),
274         dir.join("a/b/c/d/e/f"),
275         dir.join("a/b/c/d/e/f/g"),
276         dir.join("a/b/c/d/e/f/g/h"),
277         dir.join("a/b/c/d/e/f/g/h/i"),
278         dir.join("a/b/c/d/e/f/g/h/i/j"),
279         dir.join("a/b/c/d/e/f/g/h/i/j/k"),
280         dir.join("a/b/c/d/e/f/g/h/i/j/k/l"),
281         dir.join("a/b/c/d/e/f/g/h/i/j/k/l/m"),
282         dir.join("a/b/c/d/e/f/g/h/i/j/k/l/m/n"),
283         dir.join("a/b/c/d/e/f/g/h/i/j/k/l/m/n/o"),
284         dir.join("a/b/c/d/e/f/g/h/i/j/k/l/m/n/o/p"),
285         dir.join("a/b/c/d/e/f/g/h/i/j/k/l/m/n/o/p/q"),
286         dir.join("a/b/c/d/e/f/g/h/i/j/k/l/m/n/o/p/q/r"),
287         dir.join("a/b/c/d/e/f/g/h/i/j/k/l/m/n/o/p/q/r/s"),
288         dir.join("a/b/c/d/e/f/g/h/i/j/k/l/m/n/o/p/q/r/s/t"),
289         dir.join("a/b/c/d/e/f/g/h/i/j/k/l/m/n/o/p/q/r/s/t/u"),
290         dir.join("a/b/c/d/e/f/g/h/i/j/k/l/m/n/o/p/q/r/s/t/u/v"),
291         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"),
292         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"),
293         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"),
294         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"),
295         dir.join(&nested).join("A"),
296     ];
297     assert_eq!(expected, r.sorted_paths());
298 }
299 
300 #[test]
siblings()301 fn siblings() {
302     let dir = Dir::tmp();
303     dir.mkdirp("foo");
304     dir.mkdirp("bar");
305     dir.touch_all(&["foo/a", "foo/b"]);
306     dir.touch_all(&["bar/a", "bar/b"]);
307 
308     let wd = WalkDir::new(dir.path());
309     let r = dir.run_recursive(wd);
310     r.assert_no_errors();
311 
312     let expected = vec![
313         dir.path().to_path_buf(),
314         dir.join("bar"),
315         dir.join("bar").join("a"),
316         dir.join("bar").join("b"),
317         dir.join("foo"),
318         dir.join("foo").join("a"),
319         dir.join("foo").join("b"),
320     ];
321     assert_eq!(expected, r.sorted_paths());
322 }
323 
324 #[test]
sym_root_file_nofollow()325 fn sym_root_file_nofollow() {
326     let dir = Dir::tmp();
327     dir.touch("a");
328     dir.symlink_file("a", "a-link");
329 
330     let wd = WalkDir::new(dir.join("a-link"));
331     let r = dir.run_recursive(wd);
332     r.assert_no_errors();
333 
334     let ents = r.sorted_ents();
335     assert_eq!(1, ents.len());
336     let link = &ents[0];
337 
338     assert_eq!(dir.join("a-link"), link.path());
339 
340     assert!(link.path_is_symlink());
341 
342     assert_eq!(dir.join("a"), fs::read_link(link.path()).unwrap());
343 
344     assert_eq!(0, link.depth());
345 
346     assert!(link.file_type().is_symlink());
347     assert!(!link.file_type().is_file());
348     assert!(!link.file_type().is_dir());
349 
350     assert!(link.metadata().unwrap().file_type().is_symlink());
351     assert!(!link.metadata().unwrap().is_file());
352     assert!(!link.metadata().unwrap().is_dir());
353 }
354 
355 #[test]
sym_root_file_follow()356 fn sym_root_file_follow() {
357     let dir = Dir::tmp();
358     dir.touch("a");
359     dir.symlink_file("a", "a-link");
360 
361     let wd = WalkDir::new(dir.join("a-link")).follow_links(true);
362     let r = dir.run_recursive(wd);
363     r.assert_no_errors();
364 
365     let ents = r.sorted_ents();
366     let link = &ents[0];
367 
368     assert_eq!(dir.join("a-link"), link.path());
369 
370     assert!(link.path_is_symlink());
371 
372     assert_eq!(dir.join("a"), fs::read_link(link.path()).unwrap());
373 
374     assert_eq!(0, link.depth());
375 
376     assert!(!link.file_type().is_symlink());
377     assert!(link.file_type().is_file());
378     assert!(!link.file_type().is_dir());
379 
380     assert!(!link.metadata().unwrap().file_type().is_symlink());
381     assert!(link.metadata().unwrap().is_file());
382     assert!(!link.metadata().unwrap().is_dir());
383 }
384 
385 #[test]
broken_sym_root_dir_nofollow_and_root_nofollow()386 fn broken_sym_root_dir_nofollow_and_root_nofollow() {
387     let dir = Dir::tmp();
388     dir.symlink_dir("broken", "a-link");
389 
390     let wd = WalkDir::new(dir.join("a-link"))
391         .follow_links(false)
392         .follow_root_links(false);
393     let r = dir.run_recursive(wd);
394     let ents = r.sorted_ents();
395     assert_eq!(ents.len(), 1);
396     let link = &ents[0];
397     assert_eq!(dir.join("a-link"), link.path());
398     assert!(link.path_is_symlink());
399 }
400 
401 #[test]
broken_sym_root_dir_follow_and_root_nofollow()402 fn broken_sym_root_dir_follow_and_root_nofollow() {
403     let dir = Dir::tmp();
404     dir.symlink_dir("broken", "a-link");
405 
406     let wd = WalkDir::new(dir.join("a-link"))
407         .follow_links(true)
408         .follow_root_links(false);
409     let r = dir.run_recursive(wd);
410     assert!(r.sorted_ents().is_empty());
411     assert_eq!(
412         r.errs().len(),
413         1,
414         "broken symlink cannot be traversed - they are followed if symlinks are followed"
415     );
416 }
417 
418 #[test]
broken_sym_root_dir_root_is_always_followed()419 fn broken_sym_root_dir_root_is_always_followed() {
420     let dir = Dir::tmp();
421     dir.symlink_dir("broken", "a-link");
422 
423     for follow_symlinks in &[true, false] {
424         let wd =
425             WalkDir::new(dir.join("a-link")).follow_links(*follow_symlinks);
426         let r = dir.run_recursive(wd);
427         assert!(r.sorted_ents().is_empty());
428         assert_eq!(
429             r.errs().len(),
430             1,
431             "broken symlink in roots cannot be traversed, they are always followed"
432         );
433     }
434 }
435 
436 #[test]
sym_root_dir_nofollow_root_nofollow()437 fn sym_root_dir_nofollow_root_nofollow() {
438     let dir = Dir::tmp();
439     dir.mkdirp("a");
440     dir.symlink_dir("a", "a-link");
441     dir.touch("a/zzz");
442 
443     let wd = WalkDir::new(dir.join("a-link")).follow_root_links(false);
444     let r = dir.run_recursive(wd);
445     r.assert_no_errors();
446 
447     let ents = r.sorted_ents();
448     assert_eq!(1, ents.len());
449     let link = &ents[0];
450     assert_eq!(dir.join("a-link"), link.path());
451     assert_eq!(0, link.depth());
452 }
453 
454 #[test]
sym_root_dir_nofollow_root_follow()455 fn sym_root_dir_nofollow_root_follow() {
456     let dir = Dir::tmp();
457     dir.mkdirp("a");
458     dir.symlink_dir("a", "a-link");
459     dir.touch("a/zzz");
460 
461     let wd = WalkDir::new(dir.join("a-link"));
462     let r = dir.run_recursive(wd);
463     r.assert_no_errors();
464 
465     let ents = r.sorted_ents();
466     assert_eq!(2, ents.len());
467     let link = &ents[0];
468 
469     assert_eq!(dir.join("a-link"), link.path());
470 
471     assert!(link.path_is_symlink());
472 
473     assert_eq!(dir.join("a"), fs::read_link(link.path()).unwrap());
474 
475     assert_eq!(0, link.depth());
476 
477     assert!(link.file_type().is_symlink());
478     assert!(!link.file_type().is_file());
479     assert!(!link.file_type().is_dir());
480 
481     assert!(link.metadata().unwrap().file_type().is_symlink());
482     assert!(!link.metadata().unwrap().is_file());
483     assert!(!link.metadata().unwrap().is_dir());
484 
485     let link_zzz = &ents[1];
486     assert_eq!(dir.join("a-link").join("zzz"), link_zzz.path());
487     assert!(!link_zzz.path_is_symlink());
488 }
489 
490 #[test]
sym_root_dir_follow()491 fn sym_root_dir_follow() {
492     let dir = Dir::tmp();
493     dir.mkdirp("a");
494     dir.symlink_dir("a", "a-link");
495     dir.touch("a/zzz");
496 
497     let wd = WalkDir::new(dir.join("a-link")).follow_links(true);
498     let r = dir.run_recursive(wd);
499     r.assert_no_errors();
500 
501     let ents = r.sorted_ents();
502     assert_eq!(2, ents.len());
503     let link = &ents[0];
504 
505     assert_eq!(dir.join("a-link"), link.path());
506 
507     assert!(link.path_is_symlink());
508 
509     assert_eq!(dir.join("a"), fs::read_link(link.path()).unwrap());
510 
511     assert_eq!(0, link.depth());
512 
513     assert!(!link.file_type().is_symlink());
514     assert!(!link.file_type().is_file());
515     assert!(link.file_type().is_dir());
516 
517     assert!(!link.metadata().unwrap().file_type().is_symlink());
518     assert!(!link.metadata().unwrap().is_file());
519     assert!(link.metadata().unwrap().is_dir());
520 
521     let link_zzz = &ents[1];
522     assert_eq!(dir.join("a-link").join("zzz"), link_zzz.path());
523     assert!(!link_zzz.path_is_symlink());
524 }
525 
526 #[test]
sym_file_nofollow()527 fn sym_file_nofollow() {
528     let dir = Dir::tmp();
529     dir.touch("a");
530     dir.symlink_file("a", "a-link");
531 
532     let wd = WalkDir::new(dir.path());
533     let r = dir.run_recursive(wd);
534     r.assert_no_errors();
535 
536     let ents = r.sorted_ents();
537     assert_eq!(3, ents.len());
538     let (src, link) = (&ents[1], &ents[2]);
539 
540     assert_eq!(dir.join("a"), src.path());
541     assert_eq!(dir.join("a-link"), link.path());
542 
543     assert!(!src.path_is_symlink());
544     assert!(link.path_is_symlink());
545 
546     assert_eq!(dir.join("a"), fs::read_link(link.path()).unwrap());
547 
548     assert_eq!(1, src.depth());
549     assert_eq!(1, link.depth());
550 
551     assert!(src.file_type().is_file());
552     assert!(link.file_type().is_symlink());
553     assert!(!link.file_type().is_file());
554     assert!(!link.file_type().is_dir());
555 
556     assert!(src.metadata().unwrap().is_file());
557     assert!(link.metadata().unwrap().file_type().is_symlink());
558     assert!(!link.metadata().unwrap().is_file());
559     assert!(!link.metadata().unwrap().is_dir());
560 }
561 
562 #[test]
sym_file_follow()563 fn sym_file_follow() {
564     let dir = Dir::tmp();
565     dir.touch("a");
566     dir.symlink_file("a", "a-link");
567 
568     let wd = WalkDir::new(dir.path()).follow_links(true);
569     let r = dir.run_recursive(wd);
570     r.assert_no_errors();
571 
572     let ents = r.sorted_ents();
573     assert_eq!(3, ents.len());
574     let (src, link) = (&ents[1], &ents[2]);
575 
576     assert_eq!(dir.join("a"), src.path());
577     assert_eq!(dir.join("a-link"), link.path());
578 
579     assert!(!src.path_is_symlink());
580     assert!(link.path_is_symlink());
581 
582     assert_eq!(dir.join("a"), fs::read_link(link.path()).unwrap());
583 
584     assert_eq!(1, src.depth());
585     assert_eq!(1, link.depth());
586 
587     assert!(src.file_type().is_file());
588     assert!(!link.file_type().is_symlink());
589     assert!(link.file_type().is_file());
590     assert!(!link.file_type().is_dir());
591 
592     assert!(src.metadata().unwrap().is_file());
593     assert!(!link.metadata().unwrap().file_type().is_symlink());
594     assert!(link.metadata().unwrap().is_file());
595     assert!(!link.metadata().unwrap().is_dir());
596 }
597 
598 #[test]
sym_dir_nofollow()599 fn sym_dir_nofollow() {
600     let dir = Dir::tmp();
601     dir.mkdirp("a");
602     dir.symlink_dir("a", "a-link");
603     dir.touch("a/zzz");
604 
605     let wd = WalkDir::new(dir.path());
606     let r = dir.run_recursive(wd);
607     r.assert_no_errors();
608 
609     let ents = r.sorted_ents();
610     assert_eq!(4, ents.len());
611     let (src, link) = (&ents[1], &ents[3]);
612 
613     assert_eq!(dir.join("a"), src.path());
614     assert_eq!(dir.join("a-link"), link.path());
615 
616     assert!(!src.path_is_symlink());
617     assert!(link.path_is_symlink());
618 
619     assert_eq!(dir.join("a"), fs::read_link(link.path()).unwrap());
620 
621     assert_eq!(1, src.depth());
622     assert_eq!(1, link.depth());
623 
624     assert!(src.file_type().is_dir());
625     assert!(link.file_type().is_symlink());
626     assert!(!link.file_type().is_file());
627     assert!(!link.file_type().is_dir());
628 
629     assert!(src.metadata().unwrap().is_dir());
630     assert!(link.metadata().unwrap().file_type().is_symlink());
631     assert!(!link.metadata().unwrap().is_file());
632     assert!(!link.metadata().unwrap().is_dir());
633 }
634 
635 #[test]
sym_dir_follow()636 fn sym_dir_follow() {
637     let dir = Dir::tmp();
638     dir.mkdirp("a");
639     dir.symlink_dir("a", "a-link");
640     dir.touch("a/zzz");
641 
642     let wd = WalkDir::new(dir.path()).follow_links(true);
643     let r = dir.run_recursive(wd);
644     r.assert_no_errors();
645 
646     let ents = r.sorted_ents();
647     assert_eq!(5, ents.len());
648     let (src, link) = (&ents[1], &ents[3]);
649 
650     assert_eq!(dir.join("a"), src.path());
651     assert_eq!(dir.join("a-link"), link.path());
652 
653     assert!(!src.path_is_symlink());
654     assert!(link.path_is_symlink());
655 
656     assert_eq!(dir.join("a"), fs::read_link(link.path()).unwrap());
657 
658     assert_eq!(1, src.depth());
659     assert_eq!(1, link.depth());
660 
661     assert!(src.file_type().is_dir());
662     assert!(!link.file_type().is_symlink());
663     assert!(!link.file_type().is_file());
664     assert!(link.file_type().is_dir());
665 
666     assert!(src.metadata().unwrap().is_dir());
667     assert!(!link.metadata().unwrap().file_type().is_symlink());
668     assert!(!link.metadata().unwrap().is_file());
669     assert!(link.metadata().unwrap().is_dir());
670 
671     let (src_zzz, link_zzz) = (&ents[2], &ents[4]);
672     assert_eq!(dir.join("a").join("zzz"), src_zzz.path());
673     assert_eq!(dir.join("a-link").join("zzz"), link_zzz.path());
674     assert!(!src_zzz.path_is_symlink());
675     assert!(!link_zzz.path_is_symlink());
676 }
677 
678 #[test]
sym_noloop()679 fn sym_noloop() {
680     let dir = Dir::tmp();
681     dir.mkdirp("a/b/c");
682     dir.symlink_dir("a", "a/b/c/a-link");
683 
684     let wd = WalkDir::new(dir.path());
685     let r = dir.run_recursive(wd);
686     // There's no loop if we aren't following symlinks.
687     r.assert_no_errors();
688 
689     assert_eq!(5, r.ents().len());
690 }
691 
692 #[test]
sym_loop_detect()693 fn sym_loop_detect() {
694     let dir = Dir::tmp();
695     dir.mkdirp("a/b/c");
696     dir.symlink_dir("a", "a/b/c/a-link");
697 
698     let wd = WalkDir::new(dir.path()).follow_links(true);
699     let r = dir.run_recursive(wd);
700 
701     let (ents, errs) = (r.sorted_ents(), r.errs());
702     assert_eq!(4, ents.len());
703     assert_eq!(1, errs.len());
704 
705     let err = &errs[0];
706 
707     let expected = dir.join("a/b/c/a-link");
708     assert_eq!(Some(&*expected), err.path());
709 
710     let expected = dir.join("a");
711     assert_eq!(Some(&*expected), err.loop_ancestor());
712 
713     assert_eq!(4, err.depth());
714     assert!(err.io_error().is_none());
715 }
716 
717 #[test]
sym_self_loop_no_error()718 fn sym_self_loop_no_error() {
719     let dir = Dir::tmp();
720     dir.symlink_file("a", "a");
721 
722     let wd = WalkDir::new(dir.path());
723     let r = dir.run_recursive(wd);
724     // No errors occur because even though the symlink points to nowhere, it
725     // is never followed, and thus no error occurs.
726     r.assert_no_errors();
727     assert_eq!(2, r.ents().len());
728 
729     let ent = &r.ents()[1];
730     assert_eq!(dir.join("a"), ent.path());
731     assert!(ent.path_is_symlink());
732 
733     assert!(ent.file_type().is_symlink());
734     assert!(!ent.file_type().is_file());
735     assert!(!ent.file_type().is_dir());
736 
737     assert!(ent.metadata().unwrap().file_type().is_symlink());
738     assert!(!ent.metadata().unwrap().file_type().is_file());
739     assert!(!ent.metadata().unwrap().file_type().is_dir());
740 }
741 
742 #[test]
sym_file_self_loop_io_error()743 fn sym_file_self_loop_io_error() {
744     let dir = Dir::tmp();
745     dir.symlink_file("a", "a");
746 
747     let wd = WalkDir::new(dir.path()).follow_links(true);
748     let r = dir.run_recursive(wd);
749 
750     let (ents, errs) = (r.sorted_ents(), r.errs());
751     assert_eq!(1, ents.len());
752     assert_eq!(1, errs.len());
753 
754     let err = &errs[0];
755 
756     let expected = dir.join("a");
757     assert_eq!(Some(&*expected), err.path());
758     assert_eq!(1, err.depth());
759     assert!(err.loop_ancestor().is_none());
760     assert!(err.io_error().is_some());
761 }
762 
763 #[test]
sym_dir_self_loop_io_error()764 fn sym_dir_self_loop_io_error() {
765     let dir = Dir::tmp();
766     dir.symlink_dir("a", "a");
767 
768     let wd = WalkDir::new(dir.path()).follow_links(true);
769     let r = dir.run_recursive(wd);
770 
771     let (ents, errs) = (r.sorted_ents(), r.errs());
772     assert_eq!(1, ents.len());
773     assert_eq!(1, errs.len());
774 
775     let err = &errs[0];
776 
777     let expected = dir.join("a");
778     assert_eq!(Some(&*expected), err.path());
779     assert_eq!(1, err.depth());
780     assert!(err.loop_ancestor().is_none());
781     assert!(err.io_error().is_some());
782 }
783 
784 #[test]
min_depth_1()785 fn min_depth_1() {
786     let dir = Dir::tmp();
787     dir.mkdirp("a/b");
788 
789     let wd = WalkDir::new(dir.path()).min_depth(1);
790     let r = dir.run_recursive(wd);
791     r.assert_no_errors();
792 
793     let expected = vec![dir.join("a"), dir.join("a").join("b")];
794     assert_eq!(expected, r.sorted_paths());
795 }
796 
797 #[test]
min_depth_2()798 fn min_depth_2() {
799     let dir = Dir::tmp();
800     dir.mkdirp("a/b");
801 
802     let wd = WalkDir::new(dir.path()).min_depth(2);
803     let r = dir.run_recursive(wd);
804     r.assert_no_errors();
805 
806     let expected = vec![dir.join("a").join("b")];
807     assert_eq!(expected, r.sorted_paths());
808 }
809 
810 #[test]
max_depth_0()811 fn max_depth_0() {
812     let dir = Dir::tmp();
813     dir.mkdirp("a/b");
814 
815     let wd = WalkDir::new(dir.path()).max_depth(0);
816     let r = dir.run_recursive(wd);
817     r.assert_no_errors();
818 
819     let expected = vec![dir.path().to_path_buf()];
820     assert_eq!(expected, r.sorted_paths());
821 }
822 
823 #[test]
max_depth_1()824 fn max_depth_1() {
825     let dir = Dir::tmp();
826     dir.mkdirp("a/b");
827 
828     let wd = WalkDir::new(dir.path()).max_depth(1);
829     let r = dir.run_recursive(wd);
830     r.assert_no_errors();
831 
832     let expected = vec![dir.path().to_path_buf(), dir.join("a")];
833     assert_eq!(expected, r.sorted_paths());
834 }
835 
836 #[test]
max_depth_2()837 fn max_depth_2() {
838     let dir = Dir::tmp();
839     dir.mkdirp("a/b");
840 
841     let wd = WalkDir::new(dir.path()).max_depth(2);
842     let r = dir.run_recursive(wd);
843     r.assert_no_errors();
844 
845     let expected =
846         vec![dir.path().to_path_buf(), dir.join("a"), dir.join("a").join("b")];
847     assert_eq!(expected, r.sorted_paths());
848 }
849 
850 // FIXME: This test seems wrong. It should return nothing!
851 #[test]
min_max_depth_diff_nada()852 fn min_max_depth_diff_nada() {
853     let dir = Dir::tmp();
854     dir.mkdirp("a/b/c");
855 
856     let wd = WalkDir::new(dir.path()).min_depth(3).max_depth(2);
857     let r = dir.run_recursive(wd);
858     r.assert_no_errors();
859 
860     let expected = vec![dir.join("a").join("b").join("c")];
861     assert_eq!(expected, r.sorted_paths());
862 }
863 
864 #[test]
min_max_depth_diff_0()865 fn min_max_depth_diff_0() {
866     let dir = Dir::tmp();
867     dir.mkdirp("a/b/c");
868 
869     let wd = WalkDir::new(dir.path()).min_depth(2).max_depth(2);
870     let r = dir.run_recursive(wd);
871     r.assert_no_errors();
872 
873     let expected = vec![dir.join("a").join("b")];
874     assert_eq!(expected, r.sorted_paths());
875 }
876 
877 #[test]
min_max_depth_diff_1()878 fn min_max_depth_diff_1() {
879     let dir = Dir::tmp();
880     dir.mkdirp("a/b/c");
881 
882     let wd = WalkDir::new(dir.path()).min_depth(1).max_depth(2);
883     let r = dir.run_recursive(wd);
884     r.assert_no_errors();
885 
886     let expected = vec![dir.join("a"), dir.join("a").join("b")];
887     assert_eq!(expected, r.sorted_paths());
888 }
889 
890 #[test]
contents_first()891 fn contents_first() {
892     let dir = Dir::tmp();
893     dir.touch("a");
894 
895     let wd = WalkDir::new(dir.path()).contents_first(true);
896     let r = dir.run_recursive(wd);
897     r.assert_no_errors();
898 
899     let expected = vec![dir.join("a"), dir.path().to_path_buf()];
900     assert_eq!(expected, r.paths());
901 }
902 
903 #[test]
skip_current_dir()904 fn skip_current_dir() {
905     let dir = Dir::tmp();
906     dir.mkdirp("foo/bar/baz");
907     dir.mkdirp("quux");
908 
909     let mut paths = vec![];
910     let mut it = WalkDir::new(dir.path()).into_iter();
911     while let Some(result) = it.next() {
912         let ent = result.unwrap();
913         paths.push(ent.path().to_path_buf());
914         if ent.file_name() == "bar" {
915             it.skip_current_dir();
916         }
917     }
918     paths.sort();
919 
920     let expected = vec![
921         dir.path().to_path_buf(),
922         dir.join("foo"),
923         dir.join("foo").join("bar"),
924         dir.join("quux"),
925     ];
926     assert_eq!(expected, paths);
927 }
928 
929 #[test]
filter_entry()930 fn filter_entry() {
931     let dir = Dir::tmp();
932     dir.mkdirp("foo/bar/baz/abc");
933     dir.mkdirp("quux");
934 
935     let wd = WalkDir::new(dir.path())
936         .into_iter()
937         .filter_entry(|ent| ent.file_name() != "baz");
938     let r = dir.run_recursive(wd);
939     r.assert_no_errors();
940 
941     let expected = vec![
942         dir.path().to_path_buf(),
943         dir.join("foo"),
944         dir.join("foo").join("bar"),
945         dir.join("quux"),
946     ];
947     assert_eq!(expected, r.sorted_paths());
948 }
949 
950 #[test]
sort_by()951 fn sort_by() {
952     let dir = Dir::tmp();
953     dir.mkdirp("foo/bar/baz/abc");
954     dir.mkdirp("quux");
955 
956     let wd = WalkDir::new(dir.path())
957         .sort_by(|a, b| a.file_name().cmp(b.file_name()).reverse());
958     let r = dir.run_recursive(wd);
959     r.assert_no_errors();
960 
961     let expected = vec![
962         dir.path().to_path_buf(),
963         dir.join("quux"),
964         dir.join("foo"),
965         dir.join("foo").join("bar"),
966         dir.join("foo").join("bar").join("baz"),
967         dir.join("foo").join("bar").join("baz").join("abc"),
968     ];
969     assert_eq!(expected, r.paths());
970 }
971 
972 #[test]
sort_by_key()973 fn sort_by_key() {
974     let dir = Dir::tmp();
975     dir.mkdirp("foo/bar/baz/abc");
976     dir.mkdirp("quux");
977 
978     let wd =
979         WalkDir::new(dir.path()).sort_by_key(|a| a.file_name().to_owned());
980     let r = dir.run_recursive(wd);
981     r.assert_no_errors();
982 
983     let expected = vec![
984         dir.path().to_path_buf(),
985         dir.join("foo"),
986         dir.join("foo").join("bar"),
987         dir.join("foo").join("bar").join("baz"),
988         dir.join("foo").join("bar").join("baz").join("abc"),
989         dir.join("quux"),
990     ];
991     assert_eq!(expected, r.paths());
992 }
993 
994 #[test]
sort_by_file_name()995 fn sort_by_file_name() {
996     let dir = Dir::tmp();
997     dir.mkdirp("foo/bar/baz/abc");
998     dir.mkdirp("quux");
999 
1000     let wd = WalkDir::new(dir.path()).sort_by_file_name();
1001     let r = dir.run_recursive(wd);
1002     r.assert_no_errors();
1003 
1004     let expected = vec![
1005         dir.path().to_path_buf(),
1006         dir.join("foo"),
1007         dir.join("foo").join("bar"),
1008         dir.join("foo").join("bar").join("baz"),
1009         dir.join("foo").join("bar").join("baz").join("abc"),
1010         dir.join("quux"),
1011     ];
1012     assert_eq!(expected, r.paths());
1013 }
1014 
1015 #[test]
sort_max_open()1016 fn sort_max_open() {
1017     let dir = Dir::tmp();
1018     dir.mkdirp("foo/bar/baz/abc");
1019     dir.mkdirp("quux");
1020 
1021     let wd = WalkDir::new(dir.path())
1022         .max_open(1)
1023         .sort_by(|a, b| a.file_name().cmp(b.file_name()).reverse());
1024     let r = dir.run_recursive(wd);
1025     r.assert_no_errors();
1026 
1027     let expected = vec![
1028         dir.path().to_path_buf(),
1029         dir.join("quux"),
1030         dir.join("foo"),
1031         dir.join("foo").join("bar"),
1032         dir.join("foo").join("bar").join("baz"),
1033         dir.join("foo").join("bar").join("baz").join("abc"),
1034     ];
1035     assert_eq!(expected, r.paths());
1036 }
1037 
1038 #[cfg(target_os = "linux")]
1039 #[test]
same_file_system()1040 fn same_file_system() {
1041     use std::path::Path;
1042 
1043     // This test is a little weird since it's not clear whether it's a good
1044     // idea to setup a distinct mounted volume in these tests. Instead, we
1045     // probe for an existing one.
1046     if !Path::new("/sys").is_dir() {
1047         return;
1048     }
1049 
1050     let dir = Dir::tmp();
1051     dir.touch("a");
1052     dir.symlink_dir("/sys", "sys-link");
1053 
1054     // First, do a sanity check that things work without following symlinks.
1055     let wd = WalkDir::new(dir.path());
1056     let r = dir.run_recursive(wd);
1057     r.assert_no_errors();
1058 
1059     let expected =
1060         vec![dir.path().to_path_buf(), dir.join("a"), dir.join("sys-link")];
1061     assert_eq!(expected, r.sorted_paths());
1062 
1063     // ... now follow symlinks and ensure we don't descend into /sys.
1064     let wd =
1065         WalkDir::new(dir.path()).same_file_system(true).follow_links(true);
1066     let r = dir.run_recursive(wd);
1067     r.assert_no_errors();
1068 
1069     let expected =
1070         vec![dir.path().to_path_buf(), dir.join("a"), dir.join("sys-link")];
1071     assert_eq!(expected, r.sorted_paths());
1072 }
1073 
1074 // Tests that skip_current_dir doesn't destroy internal invariants.
1075 //
1076 // See: https://github.com/BurntSushi/walkdir/issues/118
1077 #[test]
regression_skip_current_dir()1078 fn regression_skip_current_dir() {
1079     let dir = Dir::tmp();
1080     dir.mkdirp("foo/a/b");
1081     dir.mkdirp("foo/1/2");
1082 
1083     let mut wd = WalkDir::new(dir.path()).max_open(1).into_iter();
1084     wd.next();
1085     wd.next();
1086     wd.next();
1087     wd.next();
1088 
1089     wd.skip_current_dir();
1090     wd.skip_current_dir();
1091     wd.next();
1092 }
1093