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