]> git.lizzy.rs Git - rust.git/blob - library/std/src/path/tests.rs
std: add tracking issue for `RawOsError`
[rust.git] / library / std / src / path / tests.rs
1 use super::*;
2
3 use crate::collections::hash_map::DefaultHasher;
4 use crate::collections::{BTreeSet, HashSet};
5 use crate::hash::Hasher;
6 use crate::rc::Rc;
7 use crate::sync::Arc;
8 use core::hint::black_box;
9
10 #[allow(unknown_lints, unused_macro_rules)]
11 macro_rules! t (
12     ($path:expr, iter: $iter:expr) => (
13         {
14             let path = Path::new($path);
15
16             // Forward iteration
17             let comps = path.iter()
18                 .map(|p| p.to_string_lossy().into_owned())
19                 .collect::<Vec<String>>();
20             let exp: &[&str] = &$iter;
21             let exps = exp.iter().map(|s| s.to_string()).collect::<Vec<String>>();
22             assert!(comps == exps, "iter: Expected {:?}, found {:?}",
23                     exps, comps);
24
25             // Reverse iteration
26             let comps = Path::new($path).iter().rev()
27                 .map(|p| p.to_string_lossy().into_owned())
28                 .collect::<Vec<String>>();
29             let exps = exps.into_iter().rev().collect::<Vec<String>>();
30             assert!(comps == exps, "iter().rev(): Expected {:?}, found {:?}",
31                     exps, comps);
32         }
33     );
34
35     ($path:expr, has_root: $has_root:expr, is_absolute: $is_absolute:expr) => (
36         {
37             let path = Path::new($path);
38
39             let act_root = path.has_root();
40             assert!(act_root == $has_root, "has_root: Expected {:?}, found {:?}",
41                     $has_root, act_root);
42
43             let act_abs = path.is_absolute();
44             assert!(act_abs == $is_absolute, "is_absolute: Expected {:?}, found {:?}",
45                     $is_absolute, act_abs);
46         }
47     );
48
49     ($path:expr, parent: $parent:expr, file_name: $file:expr) => (
50         {
51             let path = Path::new($path);
52
53             let parent = path.parent().map(|p| p.to_str().unwrap());
54             let exp_parent: Option<&str> = $parent;
55             assert!(parent == exp_parent, "parent: Expected {:?}, found {:?}",
56                     exp_parent, parent);
57
58             let file = path.file_name().map(|p| p.to_str().unwrap());
59             let exp_file: Option<&str> = $file;
60             assert!(file == exp_file, "file_name: Expected {:?}, found {:?}",
61                     exp_file, file);
62         }
63     );
64
65     ($path:expr, file_stem: $file_stem:expr, extension: $extension:expr) => (
66         {
67             let path = Path::new($path);
68
69             let stem = path.file_stem().map(|p| p.to_str().unwrap());
70             let exp_stem: Option<&str> = $file_stem;
71             assert!(stem == exp_stem, "file_stem: Expected {:?}, found {:?}",
72                     exp_stem, stem);
73
74             let ext = path.extension().map(|p| p.to_str().unwrap());
75             let exp_ext: Option<&str> = $extension;
76             assert!(ext == exp_ext, "extension: Expected {:?}, found {:?}",
77                     exp_ext, ext);
78         }
79     );
80
81     ($path:expr, file_prefix: $file_prefix:expr, extension: $extension:expr) => (
82         {
83             let path = Path::new($path);
84
85             let prefix = path.file_prefix().map(|p| p.to_str().unwrap());
86             let exp_prefix: Option<&str> = $file_prefix;
87             assert!(prefix == exp_prefix, "file_prefix: Expected {:?}, found {:?}",
88                     exp_prefix, prefix);
89
90             let ext = path.extension().map(|p| p.to_str().unwrap());
91             let exp_ext: Option<&str> = $extension;
92             assert!(ext == exp_ext, "extension: Expected {:?}, found {:?}",
93                     exp_ext, ext);
94         }
95     );
96
97     ($path:expr, iter: $iter:expr,
98                  has_root: $has_root:expr, is_absolute: $is_absolute:expr,
99                  parent: $parent:expr, file_name: $file:expr,
100                  file_stem: $file_stem:expr, extension: $extension:expr,
101                  file_prefix: $file_prefix:expr) => (
102         {
103             t!($path, iter: $iter);
104             t!($path, has_root: $has_root, is_absolute: $is_absolute);
105             t!($path, parent: $parent, file_name: $file);
106             t!($path, file_stem: $file_stem, extension: $extension);
107             t!($path, file_prefix: $file_prefix, extension: $extension);
108         }
109     );
110 );
111
112 #[test]
113 fn into() {
114     use crate::borrow::Cow;
115
116     let static_path = Path::new("/home/foo");
117     let static_cow_path: Cow<'static, Path> = static_path.into();
118     let pathbuf = PathBuf::from("/home/foo");
119
120     {
121         let path: &Path = &pathbuf;
122         let borrowed_cow_path: Cow<'_, Path> = path.into();
123
124         assert_eq!(static_cow_path, borrowed_cow_path);
125     }
126
127     let owned_cow_path: Cow<'static, Path> = pathbuf.into();
128
129     assert_eq!(static_cow_path, owned_cow_path);
130 }
131
132 #[test]
133 #[cfg(unix)]
134 pub fn test_decompositions_unix() {
135     t!("",
136     iter: [],
137     has_root: false,
138     is_absolute: false,
139     parent: None,
140     file_name: None,
141     file_stem: None,
142     extension: None,
143     file_prefix: None
144     );
145
146     t!("foo",
147     iter: ["foo"],
148     has_root: false,
149     is_absolute: false,
150     parent: Some(""),
151     file_name: Some("foo"),
152     file_stem: Some("foo"),
153     extension: None,
154     file_prefix: Some("foo")
155     );
156
157     t!("/",
158     iter: ["/"],
159     has_root: true,
160     is_absolute: true,
161     parent: None,
162     file_name: None,
163     file_stem: None,
164     extension: None,
165     file_prefix: None
166     );
167
168     t!("/foo",
169     iter: ["/", "foo"],
170     has_root: true,
171     is_absolute: true,
172     parent: Some("/"),
173     file_name: Some("foo"),
174     file_stem: Some("foo"),
175     extension: None,
176     file_prefix: Some("foo")
177     );
178
179     t!("foo/",
180     iter: ["foo"],
181     has_root: false,
182     is_absolute: false,
183     parent: Some(""),
184     file_name: Some("foo"),
185     file_stem: Some("foo"),
186     extension: None,
187     file_prefix: Some("foo")
188     );
189
190     t!("/foo/",
191     iter: ["/", "foo"],
192     has_root: true,
193     is_absolute: true,
194     parent: Some("/"),
195     file_name: Some("foo"),
196     file_stem: Some("foo"),
197     extension: None,
198     file_prefix: Some("foo")
199     );
200
201     t!("foo/bar",
202     iter: ["foo", "bar"],
203     has_root: false,
204     is_absolute: false,
205     parent: Some("foo"),
206     file_name: Some("bar"),
207     file_stem: Some("bar"),
208     extension: None,
209     file_prefix: Some("bar")
210     );
211
212     t!("/foo/bar",
213     iter: ["/", "foo", "bar"],
214     has_root: true,
215     is_absolute: true,
216     parent: Some("/foo"),
217     file_name: Some("bar"),
218     file_stem: Some("bar"),
219     extension: None,
220     file_prefix: Some("bar")
221     );
222
223     t!("///foo///",
224     iter: ["/", "foo"],
225     has_root: true,
226     is_absolute: true,
227     parent: Some("/"),
228     file_name: Some("foo"),
229     file_stem: Some("foo"),
230     extension: None,
231     file_prefix: Some("foo")
232     );
233
234     t!("///foo///bar",
235     iter: ["/", "foo", "bar"],
236     has_root: true,
237     is_absolute: true,
238     parent: Some("///foo"),
239     file_name: Some("bar"),
240     file_stem: Some("bar"),
241     extension: None,
242     file_prefix: Some("bar")
243     );
244
245     t!("./.",
246     iter: ["."],
247     has_root: false,
248     is_absolute: false,
249     parent: Some(""),
250     file_name: None,
251     file_stem: None,
252     extension: None,
253     file_prefix: None
254     );
255
256     t!("/..",
257     iter: ["/", ".."],
258     has_root: true,
259     is_absolute: true,
260     parent: Some("/"),
261     file_name: None,
262     file_stem: None,
263     extension: None,
264     file_prefix: None
265     );
266
267     t!("../",
268     iter: [".."],
269     has_root: false,
270     is_absolute: false,
271     parent: Some(""),
272     file_name: None,
273     file_stem: None,
274     extension: None,
275     file_prefix: None
276     );
277
278     t!("foo/.",
279     iter: ["foo"],
280     has_root: false,
281     is_absolute: false,
282     parent: Some(""),
283     file_name: Some("foo"),
284     file_stem: Some("foo"),
285     extension: None,
286     file_prefix: Some("foo")
287     );
288
289     t!("foo/..",
290     iter: ["foo", ".."],
291     has_root: false,
292     is_absolute: false,
293     parent: Some("foo"),
294     file_name: None,
295     file_stem: None,
296     extension: None,
297     file_prefix: None
298     );
299
300     t!("foo/./",
301     iter: ["foo"],
302     has_root: false,
303     is_absolute: false,
304     parent: Some(""),
305     file_name: Some("foo"),
306     file_stem: Some("foo"),
307     extension: None,
308     file_prefix: Some("foo")
309     );
310
311     t!("foo/./bar",
312     iter: ["foo", "bar"],
313     has_root: false,
314     is_absolute: false,
315     parent: Some("foo"),
316     file_name: Some("bar"),
317     file_stem: Some("bar"),
318     extension: None,
319     file_prefix: Some("bar")
320     );
321
322     t!("foo/../",
323     iter: ["foo", ".."],
324     has_root: false,
325     is_absolute: false,
326     parent: Some("foo"),
327     file_name: None,
328     file_stem: None,
329     extension: None,
330     file_prefix: None
331     );
332
333     t!("foo/../bar",
334     iter: ["foo", "..", "bar"],
335     has_root: false,
336     is_absolute: false,
337     parent: Some("foo/.."),
338     file_name: Some("bar"),
339     file_stem: Some("bar"),
340     extension: None,
341     file_prefix: Some("bar")
342     );
343
344     t!("./a",
345     iter: [".", "a"],
346     has_root: false,
347     is_absolute: false,
348     parent: Some("."),
349     file_name: Some("a"),
350     file_stem: Some("a"),
351     extension: None,
352     file_prefix: Some("a")
353     );
354
355     t!(".",
356     iter: ["."],
357     has_root: false,
358     is_absolute: false,
359     parent: Some(""),
360     file_name: None,
361     file_stem: None,
362     extension: None,
363     file_prefix: None
364     );
365
366     t!("./",
367     iter: ["."],
368     has_root: false,
369     is_absolute: false,
370     parent: Some(""),
371     file_name: None,
372     file_stem: None,
373     extension: None,
374     file_prefix: None
375     );
376
377     t!("a/b",
378     iter: ["a", "b"],
379     has_root: false,
380     is_absolute: false,
381     parent: Some("a"),
382     file_name: Some("b"),
383     file_stem: Some("b"),
384     extension: None,
385     file_prefix: Some("b")
386     );
387
388     t!("a//b",
389     iter: ["a", "b"],
390     has_root: false,
391     is_absolute: false,
392     parent: Some("a"),
393     file_name: Some("b"),
394     file_stem: Some("b"),
395     extension: None,
396     file_prefix: Some("b")
397     );
398
399     t!("a/./b",
400     iter: ["a", "b"],
401     has_root: false,
402     is_absolute: false,
403     parent: Some("a"),
404     file_name: Some("b"),
405     file_stem: Some("b"),
406     extension: None,
407     file_prefix: Some("b")
408     );
409
410     t!("a/b/c",
411     iter: ["a", "b", "c"],
412     has_root: false,
413     is_absolute: false,
414     parent: Some("a/b"),
415     file_name: Some("c"),
416     file_stem: Some("c"),
417     extension: None,
418     file_prefix: Some("c")
419     );
420
421     t!(".foo",
422     iter: [".foo"],
423     has_root: false,
424     is_absolute: false,
425     parent: Some(""),
426     file_name: Some(".foo"),
427     file_stem: Some(".foo"),
428     extension: None,
429     file_prefix: Some(".foo")
430     );
431
432     t!("a/.foo",
433     iter: ["a", ".foo"],
434     has_root: false,
435     is_absolute: false,
436     parent: Some("a"),
437     file_name: Some(".foo"),
438     file_stem: Some(".foo"),
439     extension: None,
440     file_prefix: Some(".foo")
441     );
442
443     t!("a/.rustfmt.toml",
444     iter: ["a", ".rustfmt.toml"],
445     has_root: false,
446     is_absolute: false,
447     parent: Some("a"),
448     file_name: Some(".rustfmt.toml"),
449     file_stem: Some(".rustfmt"),
450     extension: Some("toml"),
451     file_prefix: Some(".rustfmt")
452     );
453
454     t!("a/.x.y.z",
455     iter: ["a", ".x.y.z"],
456     has_root: false,
457     is_absolute: false,
458     parent: Some("a"),
459     file_name: Some(".x.y.z"),
460     file_stem: Some(".x.y"),
461     extension: Some("z"),
462     file_prefix: Some(".x")
463     );
464 }
465
466 #[test]
467 #[cfg(windows)]
468 pub fn test_decompositions_windows() {
469     t!("",
470     iter: [],
471     has_root: false,
472     is_absolute: false,
473     parent: None,
474     file_name: None,
475     file_stem: None,
476     extension: None,
477     file_prefix: None
478     );
479
480     t!("foo",
481     iter: ["foo"],
482     has_root: false,
483     is_absolute: false,
484     parent: Some(""),
485     file_name: Some("foo"),
486     file_stem: Some("foo"),
487     extension: None,
488     file_prefix: Some("foo")
489     );
490
491     t!("/",
492     iter: ["\\"],
493     has_root: true,
494     is_absolute: false,
495     parent: None,
496     file_name: None,
497     file_stem: None,
498     extension: None,
499     file_prefix: None
500     );
501
502     t!("\\",
503     iter: ["\\"],
504     has_root: true,
505     is_absolute: false,
506     parent: None,
507     file_name: None,
508     file_stem: None,
509     extension: None,
510     file_prefix: None
511     );
512
513     t!("c:",
514     iter: ["c:"],
515     has_root: false,
516     is_absolute: false,
517     parent: None,
518     file_name: None,
519     file_stem: None,
520     extension: None,
521     file_prefix: None
522     );
523
524     t!("c:\\",
525     iter: ["c:", "\\"],
526     has_root: true,
527     is_absolute: true,
528     parent: None,
529     file_name: None,
530     file_stem: None,
531     extension: None,
532     file_prefix: None
533     );
534
535     t!("c:/",
536     iter: ["c:", "\\"],
537     has_root: true,
538     is_absolute: true,
539     parent: None,
540     file_name: None,
541     file_stem: None,
542     extension: None,
543     file_prefix: None
544     );
545
546     t!("/foo",
547     iter: ["\\", "foo"],
548     has_root: true,
549     is_absolute: false,
550     parent: Some("/"),
551     file_name: Some("foo"),
552     file_stem: Some("foo"),
553     extension: None,
554     file_prefix: Some("foo")
555     );
556
557     t!("foo/",
558     iter: ["foo"],
559     has_root: false,
560     is_absolute: false,
561     parent: Some(""),
562     file_name: Some("foo"),
563     file_stem: Some("foo"),
564     extension: None,
565     file_prefix: Some("foo")
566     );
567
568     t!("/foo/",
569     iter: ["\\", "foo"],
570     has_root: true,
571     is_absolute: false,
572     parent: Some("/"),
573     file_name: Some("foo"),
574     file_stem: Some("foo"),
575     extension: None,
576     file_prefix: Some("foo")
577     );
578
579     t!("foo/bar",
580     iter: ["foo", "bar"],
581     has_root: false,
582     is_absolute: false,
583     parent: Some("foo"),
584     file_name: Some("bar"),
585     file_stem: Some("bar"),
586     extension: None,
587     file_prefix: Some("bar")
588     );
589
590     t!("/foo/bar",
591     iter: ["\\", "foo", "bar"],
592     has_root: true,
593     is_absolute: false,
594     parent: Some("/foo"),
595     file_name: Some("bar"),
596     file_stem: Some("bar"),
597     extension: None,
598     file_prefix: Some("bar")
599     );
600
601     t!("///foo///",
602     iter: ["\\", "foo"],
603     has_root: true,
604     is_absolute: false,
605     parent: Some("/"),
606     file_name: Some("foo"),
607     file_stem: Some("foo"),
608     extension: None,
609     file_prefix: Some("foo")
610     );
611
612     t!("///foo///bar",
613     iter: ["\\", "foo", "bar"],
614     has_root: true,
615     is_absolute: false,
616     parent: Some("///foo"),
617     file_name: Some("bar"),
618     file_stem: Some("bar"),
619     extension: None,
620     file_prefix: Some("bar")
621     );
622
623     t!("./.",
624     iter: ["."],
625     has_root: false,
626     is_absolute: false,
627     parent: Some(""),
628     file_name: None,
629     file_stem: None,
630     extension: None,
631     file_prefix: None
632     );
633
634     t!("/..",
635     iter: ["\\", ".."],
636     has_root: true,
637     is_absolute: false,
638     parent: Some("/"),
639     file_name: None,
640     file_stem: None,
641     extension: None,
642     file_prefix: None
643     );
644
645     t!("../",
646     iter: [".."],
647     has_root: false,
648     is_absolute: false,
649     parent: Some(""),
650     file_name: None,
651     file_stem: None,
652     extension: None,
653     file_prefix: None
654     );
655
656     t!("foo/.",
657     iter: ["foo"],
658     has_root: false,
659     is_absolute: false,
660     parent: Some(""),
661     file_name: Some("foo"),
662     file_stem: Some("foo"),
663     extension: None,
664     file_prefix: Some("foo")
665     );
666
667     t!("foo/..",
668     iter: ["foo", ".."],
669     has_root: false,
670     is_absolute: false,
671     parent: Some("foo"),
672     file_name: None,
673     file_stem: None,
674     extension: None,
675     file_prefix: None
676     );
677
678     t!("foo/./",
679     iter: ["foo"],
680     has_root: false,
681     is_absolute: false,
682     parent: Some(""),
683     file_name: Some("foo"),
684     file_stem: Some("foo"),
685     extension: None,
686     file_prefix: Some("foo")
687     );
688
689     t!("foo/./bar",
690     iter: ["foo", "bar"],
691     has_root: false,
692     is_absolute: false,
693     parent: Some("foo"),
694     file_name: Some("bar"),
695     file_stem: Some("bar"),
696     extension: None,
697     file_prefix: Some("bar")
698     );
699
700     t!("foo/../",
701     iter: ["foo", ".."],
702     has_root: false,
703     is_absolute: false,
704     parent: Some("foo"),
705     file_name: None,
706     file_stem: None,
707     extension: None,
708     file_prefix: None
709     );
710
711     t!("foo/../bar",
712     iter: ["foo", "..", "bar"],
713     has_root: false,
714     is_absolute: false,
715     parent: Some("foo/.."),
716     file_name: Some("bar"),
717     file_stem: Some("bar"),
718     extension: None,
719     file_prefix: Some("bar")
720     );
721
722     t!("./a",
723     iter: [".", "a"],
724     has_root: false,
725     is_absolute: false,
726     parent: Some("."),
727     file_name: Some("a"),
728     file_stem: Some("a"),
729     extension: None,
730     file_prefix: Some("a")
731     );
732
733     t!(".",
734     iter: ["."],
735     has_root: false,
736     is_absolute: false,
737     parent: Some(""),
738     file_name: None,
739     file_stem: None,
740     extension: None,
741     file_prefix: None
742     );
743
744     t!("./",
745     iter: ["."],
746     has_root: false,
747     is_absolute: false,
748     parent: Some(""),
749     file_name: None,
750     file_stem: None,
751     extension: None,
752     file_prefix: None
753     );
754
755     t!("a/b",
756     iter: ["a", "b"],
757     has_root: false,
758     is_absolute: false,
759     parent: Some("a"),
760     file_name: Some("b"),
761     file_stem: Some("b"),
762     extension: None,
763     file_prefix: Some("b")
764     );
765
766     t!("a//b",
767     iter: ["a", "b"],
768     has_root: false,
769     is_absolute: false,
770     parent: Some("a"),
771     file_name: Some("b"),
772     file_stem: Some("b"),
773     extension: None,
774     file_prefix: Some("b")
775     );
776
777     t!("a/./b",
778     iter: ["a", "b"],
779     has_root: false,
780     is_absolute: false,
781     parent: Some("a"),
782     file_name: Some("b"),
783     file_stem: Some("b"),
784     extension: None,
785     file_prefix: Some("b")
786     );
787
788     t!("a/b/c",
789        iter: ["a", "b", "c"],
790        has_root: false,
791        is_absolute: false,
792        parent: Some("a/b"),
793        file_name: Some("c"),
794        file_stem: Some("c"),
795        extension: None,
796        file_prefix: Some("c")
797     );
798
799     t!("a\\b\\c",
800     iter: ["a", "b", "c"],
801     has_root: false,
802     is_absolute: false,
803     parent: Some("a\\b"),
804     file_name: Some("c"),
805     file_stem: Some("c"),
806     extension: None,
807     file_prefix: Some("c")
808     );
809
810     t!("\\a",
811     iter: ["\\", "a"],
812     has_root: true,
813     is_absolute: false,
814     parent: Some("\\"),
815     file_name: Some("a"),
816     file_stem: Some("a"),
817     extension: None,
818     file_prefix: Some("a")
819     );
820
821     t!("c:\\foo.txt",
822     iter: ["c:", "\\", "foo.txt"],
823     has_root: true,
824     is_absolute: true,
825     parent: Some("c:\\"),
826     file_name: Some("foo.txt"),
827     file_stem: Some("foo"),
828     extension: Some("txt"),
829     file_prefix: Some("foo")
830     );
831
832     t!("\\\\server\\share\\foo.txt",
833     iter: ["\\\\server\\share", "\\", "foo.txt"],
834     has_root: true,
835     is_absolute: true,
836     parent: Some("\\\\server\\share\\"),
837     file_name: Some("foo.txt"),
838     file_stem: Some("foo"),
839     extension: Some("txt"),
840     file_prefix: Some("foo")
841     );
842
843     t!("\\\\server\\share",
844     iter: ["\\\\server\\share", "\\"],
845     has_root: true,
846     is_absolute: true,
847     parent: None,
848     file_name: None,
849     file_stem: None,
850     extension: None,
851     file_prefix: None
852     );
853
854     t!("\\\\server",
855     iter: ["\\", "server"],
856     has_root: true,
857     is_absolute: false,
858     parent: Some("\\"),
859     file_name: Some("server"),
860     file_stem: Some("server"),
861     extension: None,
862     file_prefix: Some("server")
863     );
864
865     t!("\\\\?\\bar\\foo.txt",
866     iter: ["\\\\?\\bar", "\\", "foo.txt"],
867     has_root: true,
868     is_absolute: true,
869     parent: Some("\\\\?\\bar\\"),
870     file_name: Some("foo.txt"),
871     file_stem: Some("foo"),
872     extension: Some("txt"),
873     file_prefix: Some("foo")
874     );
875
876     t!("\\\\?\\bar",
877     iter: ["\\\\?\\bar"],
878     has_root: true,
879     is_absolute: true,
880     parent: None,
881     file_name: None,
882     file_stem: None,
883     extension: None,
884     file_prefix: None
885     );
886
887     t!("\\\\?\\",
888     iter: ["\\\\?\\"],
889     has_root: true,
890     is_absolute: true,
891     parent: None,
892     file_name: None,
893     file_stem: None,
894     extension: None,
895     file_prefix: None
896     );
897
898     t!("\\\\?\\UNC\\server\\share\\foo.txt",
899     iter: ["\\\\?\\UNC\\server\\share", "\\", "foo.txt"],
900     has_root: true,
901     is_absolute: true,
902     parent: Some("\\\\?\\UNC\\server\\share\\"),
903     file_name: Some("foo.txt"),
904     file_stem: Some("foo"),
905     extension: Some("txt"),
906     file_prefix: Some("foo")
907     );
908
909     t!("\\\\?\\UNC\\server",
910     iter: ["\\\\?\\UNC\\server"],
911     has_root: true,
912     is_absolute: true,
913     parent: None,
914     file_name: None,
915     file_stem: None,
916     extension: None,
917     file_prefix: None
918     );
919
920     t!("\\\\?\\UNC\\",
921     iter: ["\\\\?\\UNC\\"],
922     has_root: true,
923     is_absolute: true,
924     parent: None,
925     file_name: None,
926     file_stem: None,
927     extension: None,
928     file_prefix: None
929     );
930
931     t!("\\\\?\\C:\\foo.txt",
932     iter: ["\\\\?\\C:", "\\", "foo.txt"],
933     has_root: true,
934     is_absolute: true,
935     parent: Some("\\\\?\\C:\\"),
936     file_name: Some("foo.txt"),
937     file_stem: Some("foo"),
938     extension: Some("txt"),
939     file_prefix: Some("foo")
940     );
941
942     t!("\\\\?\\C:\\",
943     iter: ["\\\\?\\C:", "\\"],
944     has_root: true,
945     is_absolute: true,
946     parent: None,
947     file_name: None,
948     file_stem: None,
949     extension: None,
950     file_prefix: None
951     );
952
953     t!("\\\\?\\C:",
954     iter: ["\\\\?\\C:"],
955     has_root: true,
956     is_absolute: true,
957     parent: None,
958     file_name: None,
959     file_stem: None,
960     extension: None,
961     file_prefix: None
962     );
963
964     t!("\\\\?\\foo/bar",
965     iter: ["\\\\?\\foo/bar"],
966     has_root: true,
967     is_absolute: true,
968     parent: None,
969     file_name: None,
970     file_stem: None,
971     extension: None,
972     file_prefix: None
973     );
974
975     t!("\\\\?\\C:/foo/bar",
976     iter: ["\\\\?\\C:", "\\", "foo/bar"],
977     has_root: true,
978     is_absolute: true,
979     parent: Some("\\\\?\\C:/"),
980     file_name: Some("foo/bar"),
981     file_stem: Some("foo/bar"),
982     extension: None,
983     file_prefix: Some("foo/bar")
984     );
985
986     t!("\\\\.\\foo\\bar",
987     iter: ["\\\\.\\foo", "\\", "bar"],
988     has_root: true,
989     is_absolute: true,
990     parent: Some("\\\\.\\foo\\"),
991     file_name: Some("bar"),
992     file_stem: Some("bar"),
993     extension: None,
994     file_prefix: Some("bar")
995     );
996
997     t!("\\\\.\\foo",
998     iter: ["\\\\.\\foo", "\\"],
999     has_root: true,
1000     is_absolute: true,
1001     parent: None,
1002     file_name: None,
1003     file_stem: None,
1004     extension: None,
1005     file_prefix: None
1006     );
1007
1008     t!("\\\\.\\foo/bar",
1009     iter: ["\\\\.\\foo", "\\", "bar"],
1010     has_root: true,
1011     is_absolute: true,
1012     parent: Some("\\\\.\\foo/"),
1013     file_name: Some("bar"),
1014     file_stem: Some("bar"),
1015     extension: None,
1016     file_prefix: Some("bar")
1017     );
1018
1019     t!("\\\\.\\foo\\bar/baz",
1020     iter: ["\\\\.\\foo", "\\", "bar", "baz"],
1021     has_root: true,
1022     is_absolute: true,
1023     parent: Some("\\\\.\\foo\\bar"),
1024     file_name: Some("baz"),
1025     file_stem: Some("baz"),
1026     extension: None,
1027     file_prefix: Some("baz")
1028     );
1029
1030     t!("\\\\.\\",
1031     iter: ["\\\\.\\", "\\"],
1032     has_root: true,
1033     is_absolute: true,
1034     parent: None,
1035     file_name: None,
1036     file_stem: None,
1037     extension: None,
1038     file_prefix: None
1039     );
1040
1041     t!("\\\\?\\a\\b\\",
1042     iter: ["\\\\?\\a", "\\", "b"],
1043     has_root: true,
1044     is_absolute: true,
1045     parent: Some("\\\\?\\a\\"),
1046     file_name: Some("b"),
1047     file_stem: Some("b"),
1048     extension: None,
1049     file_prefix: Some("b")
1050     );
1051
1052     t!("\\\\?\\C:\\foo.txt.zip",
1053     iter: ["\\\\?\\C:", "\\", "foo.txt.zip"],
1054     has_root: true,
1055     is_absolute: true,
1056     parent: Some("\\\\?\\C:\\"),
1057     file_name: Some("foo.txt.zip"),
1058     file_stem: Some("foo.txt"),
1059     extension: Some("zip"),
1060     file_prefix: Some("foo")
1061     );
1062
1063     t!("\\\\?\\C:\\.foo.txt.zip",
1064     iter: ["\\\\?\\C:", "\\", ".foo.txt.zip"],
1065     has_root: true,
1066     is_absolute: true,
1067     parent: Some("\\\\?\\C:\\"),
1068     file_name: Some(".foo.txt.zip"),
1069     file_stem: Some(".foo.txt"),
1070     extension: Some("zip"),
1071     file_prefix: Some(".foo")
1072     );
1073
1074     t!("\\\\?\\C:\\.foo",
1075     iter: ["\\\\?\\C:", "\\", ".foo"],
1076     has_root: true,
1077     is_absolute: true,
1078     parent: Some("\\\\?\\C:\\"),
1079     file_name: Some(".foo"),
1080     file_stem: Some(".foo"),
1081     extension: None,
1082     file_prefix: Some(".foo")
1083     );
1084
1085     t!("a/.x.y.z",
1086     iter: ["a", ".x.y.z"],
1087     has_root: false,
1088     is_absolute: false,
1089     parent: Some("a"),
1090     file_name: Some(".x.y.z"),
1091     file_stem: Some(".x.y"),
1092     extension: Some("z"),
1093     file_prefix: Some(".x")
1094     );
1095 }
1096
1097 #[test]
1098 pub fn test_stem_ext() {
1099     t!("foo",
1100     file_stem: Some("foo"),
1101     extension: None
1102     );
1103
1104     t!("foo.",
1105     file_stem: Some("foo"),
1106     extension: Some("")
1107     );
1108
1109     t!(".foo",
1110     file_stem: Some(".foo"),
1111     extension: None
1112     );
1113
1114     t!("foo.txt",
1115     file_stem: Some("foo"),
1116     extension: Some("txt")
1117     );
1118
1119     t!("foo.bar.txt",
1120     file_stem: Some("foo.bar"),
1121     extension: Some("txt")
1122     );
1123
1124     t!("foo.bar.",
1125     file_stem: Some("foo.bar"),
1126     extension: Some("")
1127     );
1128
1129     t!(".", file_stem: None, extension: None);
1130
1131     t!("..", file_stem: None, extension: None);
1132
1133     t!(".x.y.z", file_stem: Some(".x.y"), extension: Some("z"));
1134
1135     t!("..x.y.z", file_stem: Some("..x.y"), extension: Some("z"));
1136
1137     t!("", file_stem: None, extension: None);
1138 }
1139
1140 #[test]
1141 pub fn test_prefix_ext() {
1142     t!("foo",
1143     file_prefix: Some("foo"),
1144     extension: None
1145     );
1146
1147     t!("foo.",
1148     file_prefix: Some("foo"),
1149     extension: Some("")
1150     );
1151
1152     t!(".foo",
1153     file_prefix: Some(".foo"),
1154     extension: None
1155     );
1156
1157     t!("foo.txt",
1158     file_prefix: Some("foo"),
1159     extension: Some("txt")
1160     );
1161
1162     t!("foo.bar.txt",
1163     file_prefix: Some("foo"),
1164     extension: Some("txt")
1165     );
1166
1167     t!("foo.bar.",
1168     file_prefix: Some("foo"),
1169     extension: Some("")
1170     );
1171
1172     t!(".", file_prefix: None, extension: None);
1173
1174     t!("..", file_prefix: None, extension: None);
1175
1176     t!(".x.y.z", file_prefix: Some(".x"), extension: Some("z"));
1177
1178     t!("..x.y.z", file_prefix: Some("."), extension: Some("z"));
1179
1180     t!("", file_prefix: None, extension: None);
1181 }
1182
1183 #[test]
1184 pub fn test_push() {
1185     macro_rules! tp (
1186         ($path:expr, $push:expr, $expected:expr) => ( {
1187             let mut actual = PathBuf::from($path);
1188             actual.push($push);
1189             assert!(actual.to_str() == Some($expected),
1190                     "pushing {:?} onto {:?}: Expected {:?}, got {:?}",
1191                     $push, $path, $expected, actual.to_str().unwrap());
1192         });
1193     );
1194
1195     if cfg!(unix) || cfg!(all(target_env = "sgx", target_vendor = "fortanix")) {
1196         tp!("", "foo", "foo");
1197         tp!("foo", "bar", "foo/bar");
1198         tp!("foo/", "bar", "foo/bar");
1199         tp!("foo//", "bar", "foo//bar");
1200         tp!("foo/.", "bar", "foo/./bar");
1201         tp!("foo./.", "bar", "foo././bar");
1202         tp!("foo", "", "foo/");
1203         tp!("foo", ".", "foo/.");
1204         tp!("foo", "..", "foo/..");
1205         tp!("foo", "/", "/");
1206         tp!("/foo/bar", "/", "/");
1207         tp!("/foo/bar", "/baz", "/baz");
1208         tp!("/foo/bar", "./baz", "/foo/bar/./baz");
1209     } else {
1210         tp!("", "foo", "foo");
1211         tp!("foo", "bar", r"foo\bar");
1212         tp!("foo/", "bar", r"foo/bar");
1213         tp!(r"foo\", "bar", r"foo\bar");
1214         tp!("foo//", "bar", r"foo//bar");
1215         tp!(r"foo\\", "bar", r"foo\\bar");
1216         tp!("foo/.", "bar", r"foo/.\bar");
1217         tp!("foo./.", "bar", r"foo./.\bar");
1218         tp!(r"foo\.", "bar", r"foo\.\bar");
1219         tp!(r"foo.\.", "bar", r"foo.\.\bar");
1220         tp!("foo", "", "foo\\");
1221         tp!("foo", ".", r"foo\.");
1222         tp!("foo", "..", r"foo\..");
1223         tp!("foo", "/", "/");
1224         tp!("foo", r"\", r"\");
1225         tp!("/foo/bar", "/", "/");
1226         tp!(r"\foo\bar", r"\", r"\");
1227         tp!("/foo/bar", "/baz", "/baz");
1228         tp!("/foo/bar", r"\baz", r"\baz");
1229         tp!("/foo/bar", "./baz", r"/foo/bar\./baz");
1230         tp!("/foo/bar", r".\baz", r"/foo/bar\.\baz");
1231
1232         tp!("c:\\", "windows", "c:\\windows");
1233         tp!("c:", "windows", "c:windows");
1234
1235         tp!("a\\b\\c", "d", "a\\b\\c\\d");
1236         tp!("\\a\\b\\c", "d", "\\a\\b\\c\\d");
1237         tp!("a\\b", "c\\d", "a\\b\\c\\d");
1238         tp!("a\\b", "\\c\\d", "\\c\\d");
1239         tp!("a\\b", ".", "a\\b\\.");
1240         tp!("a\\b", "..\\c", "a\\b\\..\\c");
1241         tp!("a\\b", "C:a.txt", "C:a.txt");
1242         tp!("a\\b", "C:\\a.txt", "C:\\a.txt");
1243         tp!("C:\\a", "C:\\b.txt", "C:\\b.txt");
1244         tp!("C:\\a\\b\\c", "C:d", "C:d");
1245         tp!("C:a\\b\\c", "C:d", "C:d");
1246         tp!("C:", r"a\b\c", r"C:a\b\c");
1247         tp!("C:", r"..\a", r"C:..\a");
1248         tp!("\\\\server\\share\\foo", "bar", "\\\\server\\share\\foo\\bar");
1249         tp!("\\\\server\\share\\foo", "C:baz", "C:baz");
1250         tp!("\\\\?\\C:\\a\\b", "C:c\\d", "C:c\\d");
1251         tp!("\\\\?\\C:a\\b", "C:c\\d", "C:c\\d");
1252         tp!("\\\\?\\C:\\a\\b", "C:\\c\\d", "C:\\c\\d");
1253         tp!("\\\\?\\foo\\bar", "baz", "\\\\?\\foo\\bar\\baz");
1254         tp!("\\\\?\\UNC\\server\\share\\foo", "bar", "\\\\?\\UNC\\server\\share\\foo\\bar");
1255         tp!("\\\\?\\UNC\\server\\share", "C:\\a", "C:\\a");
1256         tp!("\\\\?\\UNC\\server\\share", "C:a", "C:a");
1257
1258         // Note: modified from old path API
1259         tp!("\\\\?\\UNC\\server", "foo", "\\\\?\\UNC\\server\\foo");
1260
1261         tp!("C:\\a", "\\\\?\\UNC\\server\\share", "\\\\?\\UNC\\server\\share");
1262         tp!("\\\\.\\foo\\bar", "baz", "\\\\.\\foo\\bar\\baz");
1263         tp!("\\\\.\\foo\\bar", "C:a", "C:a");
1264         // again, not sure about the following, but I'm assuming \\.\ should be verbatim
1265         tp!("\\\\.\\foo", "..\\bar", "\\\\.\\foo\\..\\bar");
1266
1267         tp!("\\\\?\\C:", "foo", "\\\\?\\C:\\foo"); // this is a weird one
1268
1269         tp!(r"\\?\C:\bar", "../foo", r"\\?\C:\foo");
1270         tp!(r"\\?\C:\bar", "../../foo", r"\\?\C:\foo");
1271         tp!(r"\\?\C:\", "../foo", r"\\?\C:\foo");
1272         tp!(r"\\?\C:", r"D:\foo/./", r"D:\foo/./");
1273         tp!(r"\\?\C:", r"\\?\D:\foo\.\", r"\\?\D:\foo\.\");
1274         tp!(r"\\?\A:\x\y", "/foo", r"\\?\A:\foo");
1275         tp!(r"\\?\A:", r"..\foo\.", r"\\?\A:\foo");
1276         tp!(r"\\?\A:\x\y", r".\foo\.", r"\\?\A:\x\y\foo");
1277         tp!(r"\\?\A:\x\y", r"", r"\\?\A:\x\y\");
1278     }
1279 }
1280
1281 #[test]
1282 pub fn test_pop() {
1283     macro_rules! tp (
1284         ($path:expr, $expected:expr, $output:expr) => ( {
1285             let mut actual = PathBuf::from($path);
1286             let output = actual.pop();
1287             assert!(actual.to_str() == Some($expected) && output == $output,
1288                     "popping from {:?}: Expected {:?}/{:?}, got {:?}/{:?}",
1289                     $path, $expected, $output,
1290                     actual.to_str().unwrap(), output);
1291         });
1292     );
1293
1294     tp!("", "", false);
1295     tp!("/", "/", false);
1296     tp!("foo", "", true);
1297     tp!(".", "", true);
1298     tp!("/foo", "/", true);
1299     tp!("/foo/bar", "/foo", true);
1300     tp!("foo/bar", "foo", true);
1301     tp!("foo/.", "", true);
1302     tp!("foo//bar", "foo", true);
1303
1304     if cfg!(windows) {
1305         tp!("a\\b\\c", "a\\b", true);
1306         tp!("\\a", "\\", true);
1307         tp!("\\", "\\", false);
1308
1309         tp!("C:\\a\\b", "C:\\a", true);
1310         tp!("C:\\a", "C:\\", true);
1311         tp!("C:\\", "C:\\", false);
1312         tp!("C:a\\b", "C:a", true);
1313         tp!("C:a", "C:", true);
1314         tp!("C:", "C:", false);
1315         tp!("\\\\server\\share\\a\\b", "\\\\server\\share\\a", true);
1316         tp!("\\\\server\\share\\a", "\\\\server\\share\\", true);
1317         tp!("\\\\server\\share", "\\\\server\\share", false);
1318         tp!("\\\\?\\a\\b\\c", "\\\\?\\a\\b", true);
1319         tp!("\\\\?\\a\\b", "\\\\?\\a\\", true);
1320         tp!("\\\\?\\a", "\\\\?\\a", false);
1321         tp!("\\\\?\\C:\\a\\b", "\\\\?\\C:\\a", true);
1322         tp!("\\\\?\\C:\\a", "\\\\?\\C:\\", true);
1323         tp!("\\\\?\\C:\\", "\\\\?\\C:\\", false);
1324         tp!("\\\\?\\UNC\\server\\share\\a\\b", "\\\\?\\UNC\\server\\share\\a", true);
1325         tp!("\\\\?\\UNC\\server\\share\\a", "\\\\?\\UNC\\server\\share\\", true);
1326         tp!("\\\\?\\UNC\\server\\share", "\\\\?\\UNC\\server\\share", false);
1327         tp!("\\\\.\\a\\b\\c", "\\\\.\\a\\b", true);
1328         tp!("\\\\.\\a\\b", "\\\\.\\a\\", true);
1329         tp!("\\\\.\\a", "\\\\.\\a", false);
1330
1331         tp!("\\\\?\\a\\b\\", "\\\\?\\a\\", true);
1332     }
1333 }
1334
1335 #[test]
1336 pub fn test_set_file_name() {
1337     macro_rules! tfn (
1338             ($path:expr, $file:expr, $expected:expr) => ( {
1339             let mut p = PathBuf::from($path);
1340             p.set_file_name($file);
1341             assert!(p.to_str() == Some($expected),
1342                     "setting file name of {:?} to {:?}: Expected {:?}, got {:?}",
1343                     $path, $file, $expected,
1344                     p.to_str().unwrap());
1345         });
1346     );
1347
1348     tfn!("foo", "foo", "foo");
1349     tfn!("foo", "bar", "bar");
1350     tfn!("foo", "", "");
1351     tfn!("", "foo", "foo");
1352     if cfg!(unix) || cfg!(all(target_env = "sgx", target_vendor = "fortanix")) {
1353         tfn!(".", "foo", "./foo");
1354         tfn!("foo/", "bar", "bar");
1355         tfn!("foo/.", "bar", "bar");
1356         tfn!("..", "foo", "../foo");
1357         tfn!("foo/..", "bar", "foo/../bar");
1358         tfn!("/", "foo", "/foo");
1359     } else {
1360         tfn!(".", "foo", r".\foo");
1361         tfn!(r"foo\", "bar", r"bar");
1362         tfn!(r"foo\.", "bar", r"bar");
1363         tfn!("..", "foo", r"..\foo");
1364         tfn!(r"foo\..", "bar", r"foo\..\bar");
1365         tfn!(r"\", "foo", r"\foo");
1366     }
1367 }
1368
1369 #[test]
1370 pub fn test_set_extension() {
1371     macro_rules! tfe (
1372             ($path:expr, $ext:expr, $expected:expr, $output:expr) => ( {
1373             let mut p = PathBuf::from($path);
1374             let output = p.set_extension($ext);
1375             assert!(p.to_str() == Some($expected) && output == $output,
1376                     "setting extension of {:?} to {:?}: Expected {:?}/{:?}, got {:?}/{:?}",
1377                     $path, $ext, $expected, $output,
1378                     p.to_str().unwrap(), output);
1379         });
1380     );
1381
1382     tfe!("foo", "txt", "foo.txt", true);
1383     tfe!("foo.bar", "txt", "foo.txt", true);
1384     tfe!("foo.bar.baz", "txt", "foo.bar.txt", true);
1385     tfe!(".test", "txt", ".test.txt", true);
1386     tfe!("foo.txt", "", "foo", true);
1387     tfe!("foo", "", "foo", true);
1388     tfe!("", "foo", "", false);
1389     tfe!(".", "foo", ".", false);
1390     tfe!("foo/", "bar", "foo.bar", true);
1391     tfe!("foo/.", "bar", "foo.bar", true);
1392     tfe!("..", "foo", "..", false);
1393     tfe!("foo/..", "bar", "foo/..", false);
1394     tfe!("/", "foo", "/", false);
1395 }
1396
1397 #[test]
1398 fn test_eq_receivers() {
1399     use crate::borrow::Cow;
1400
1401     let borrowed: &Path = Path::new("foo/bar");
1402     let mut owned: PathBuf = PathBuf::new();
1403     owned.push("foo");
1404     owned.push("bar");
1405     let borrowed_cow: Cow<'_, Path> = borrowed.into();
1406     let owned_cow: Cow<'_, Path> = owned.clone().into();
1407
1408     macro_rules! t {
1409         ($($current:expr),+) => {
1410             $(
1411                 assert_eq!($current, borrowed);
1412                 assert_eq!($current, owned);
1413                 assert_eq!($current, borrowed_cow);
1414                 assert_eq!($current, owned_cow);
1415             )+
1416         }
1417     }
1418
1419     t!(borrowed, owned, borrowed_cow, owned_cow);
1420 }
1421
1422 #[test]
1423 pub fn test_compare() {
1424     use crate::collections::hash_map::DefaultHasher;
1425     use crate::hash::{Hash, Hasher};
1426
1427     fn hash<T: Hash>(t: T) -> u64 {
1428         let mut s = DefaultHasher::new();
1429         t.hash(&mut s);
1430         s.finish()
1431     }
1432
1433     macro_rules! tc (
1434         ($path1:expr, $path2:expr, eq: $eq:expr,
1435          starts_with: $starts_with:expr, ends_with: $ends_with:expr,
1436          relative_from: $relative_from:expr) => ({
1437              let path1 = Path::new($path1);
1438              let path2 = Path::new($path2);
1439
1440              let eq = path1 == path2;
1441              assert!(eq == $eq, "{:?} == {:?}, expected {:?}, got {:?}",
1442                      $path1, $path2, $eq, eq);
1443              assert!($eq == (hash(path1) == hash(path2)),
1444                      "{:?} == {:?}, expected {:?}, got {} and {}",
1445                      $path1, $path2, $eq, hash(path1), hash(path2));
1446
1447              let starts_with = path1.starts_with(path2);
1448              assert!(starts_with == $starts_with,
1449                      "{:?}.starts_with({:?}), expected {:?}, got {:?}", $path1, $path2,
1450                      $starts_with, starts_with);
1451
1452              let ends_with = path1.ends_with(path2);
1453              assert!(ends_with == $ends_with,
1454                      "{:?}.ends_with({:?}), expected {:?}, got {:?}", $path1, $path2,
1455                      $ends_with, ends_with);
1456
1457              let relative_from = path1.strip_prefix(path2)
1458                                       .map(|p| p.to_str().unwrap())
1459                                       .ok();
1460              let exp: Option<&str> = $relative_from;
1461              assert!(relative_from == exp,
1462                      "{:?}.strip_prefix({:?}), expected {:?}, got {:?}",
1463                      $path1, $path2, exp, relative_from);
1464         });
1465     );
1466
1467     tc!("", "",
1468     eq: true,
1469     starts_with: true,
1470     ends_with: true,
1471     relative_from: Some("")
1472     );
1473
1474     tc!("foo", "",
1475     eq: false,
1476     starts_with: true,
1477     ends_with: true,
1478     relative_from: Some("foo")
1479     );
1480
1481     tc!("", "foo",
1482     eq: false,
1483     starts_with: false,
1484     ends_with: false,
1485     relative_from: None
1486     );
1487
1488     tc!("foo", "foo",
1489     eq: true,
1490     starts_with: true,
1491     ends_with: true,
1492     relative_from: Some("")
1493     );
1494
1495     tc!("foo/", "foo",
1496     eq: true,
1497     starts_with: true,
1498     ends_with: true,
1499     relative_from: Some("")
1500     );
1501
1502     tc!("foo/.", "foo",
1503     eq: true,
1504     starts_with: true,
1505     ends_with: true,
1506     relative_from: Some("")
1507     );
1508
1509     tc!("foo/./bar", "foo/bar",
1510     eq: true,
1511     starts_with: true,
1512     ends_with: true,
1513     relative_from: Some("")
1514     );
1515
1516     tc!("foo/bar", "foo",
1517     eq: false,
1518     starts_with: true,
1519     ends_with: false,
1520     relative_from: Some("bar")
1521     );
1522
1523     tc!("foo/bar/baz", "foo/bar",
1524     eq: false,
1525     starts_with: true,
1526     ends_with: false,
1527     relative_from: Some("baz")
1528     );
1529
1530     tc!("foo/bar", "foo/bar/baz",
1531     eq: false,
1532     starts_with: false,
1533     ends_with: false,
1534     relative_from: None
1535     );
1536
1537     tc!("./foo/bar/", ".",
1538     eq: false,
1539     starts_with: true,
1540     ends_with: false,
1541     relative_from: Some("foo/bar")
1542     );
1543
1544     if cfg!(windows) {
1545         tc!(r"C:\src\rust\cargo-test\test\Cargo.toml",
1546         r"c:\src\rust\cargo-test\test",
1547         eq: false,
1548         starts_with: true,
1549         ends_with: false,
1550         relative_from: Some("Cargo.toml")
1551         );
1552
1553         tc!(r"c:\foo", r"C:\foo",
1554         eq: true,
1555         starts_with: true,
1556         ends_with: true,
1557         relative_from: Some("")
1558         );
1559
1560         tc!(r"C:\foo\.\bar.txt", r"C:\foo\bar.txt",
1561         eq: true,
1562         starts_with: true,
1563         ends_with: true,
1564         relative_from: Some("")
1565         );
1566
1567         tc!(r"C:\foo\.", r"C:\foo",
1568         eq: true,
1569         starts_with: true,
1570         ends_with: true,
1571         relative_from: Some("")
1572         );
1573
1574         tc!(r"\\?\C:\foo\.\bar.txt", r"\\?\C:\foo\bar.txt",
1575         eq: false,
1576         starts_with: false,
1577         ends_with: false,
1578         relative_from: None
1579         );
1580     }
1581 }
1582
1583 #[test]
1584 fn test_components_debug() {
1585     let path = Path::new("/tmp");
1586
1587     let mut components = path.components();
1588
1589     let expected = "Components([RootDir, Normal(\"tmp\")])";
1590     let actual = format!("{components:?}");
1591     assert_eq!(expected, actual);
1592
1593     let _ = components.next().unwrap();
1594     let expected = "Components([Normal(\"tmp\")])";
1595     let actual = format!("{components:?}");
1596     assert_eq!(expected, actual);
1597
1598     let _ = components.next().unwrap();
1599     let expected = "Components([])";
1600     let actual = format!("{components:?}");
1601     assert_eq!(expected, actual);
1602 }
1603
1604 #[cfg(unix)]
1605 #[test]
1606 fn test_iter_debug() {
1607     let path = Path::new("/tmp");
1608
1609     let mut iter = path.iter();
1610
1611     let expected = "Iter([\"/\", \"tmp\"])";
1612     let actual = format!("{iter:?}");
1613     assert_eq!(expected, actual);
1614
1615     let _ = iter.next().unwrap();
1616     let expected = "Iter([\"tmp\"])";
1617     let actual = format!("{iter:?}");
1618     assert_eq!(expected, actual);
1619
1620     let _ = iter.next().unwrap();
1621     let expected = "Iter([])";
1622     let actual = format!("{iter:?}");
1623     assert_eq!(expected, actual);
1624 }
1625
1626 #[test]
1627 fn into_boxed() {
1628     let orig: &str = "some/sort/of/path";
1629     let path = Path::new(orig);
1630     let boxed: Box<Path> = Box::from(path);
1631     let path_buf = path.to_owned().into_boxed_path().into_path_buf();
1632     assert_eq!(path, &*boxed);
1633     assert_eq!(&*boxed, &*path_buf);
1634     assert_eq!(&*path_buf, path);
1635 }
1636
1637 #[test]
1638 fn test_clone_into() {
1639     let mut path_buf = PathBuf::from("supercalifragilisticexpialidocious");
1640     let path = Path::new("short");
1641     path.clone_into(&mut path_buf);
1642     assert_eq!(path, path_buf);
1643     assert!(path_buf.into_os_string().capacity() >= 15);
1644 }
1645
1646 #[test]
1647 fn display_format_flags() {
1648     assert_eq!(format!("a{:#<5}b", Path::new("").display()), "a#####b");
1649     assert_eq!(format!("a{:#<5}b", Path::new("a").display()), "aa####b");
1650 }
1651
1652 #[test]
1653 fn into_rc() {
1654     let orig = "hello/world";
1655     let path = Path::new(orig);
1656     let rc: Rc<Path> = Rc::from(path);
1657     let arc: Arc<Path> = Arc::from(path);
1658
1659     assert_eq!(&*rc, path);
1660     assert_eq!(&*arc, path);
1661
1662     let rc2: Rc<Path> = Rc::from(path.to_owned());
1663     let arc2: Arc<Path> = Arc::from(path.to_owned());
1664
1665     assert_eq!(&*rc2, path);
1666     assert_eq!(&*arc2, path);
1667 }
1668
1669 #[test]
1670 fn test_ord() {
1671     macro_rules! ord(
1672         ($ord:ident, $left:expr, $right:expr) => ( {
1673             use core::cmp::Ordering;
1674
1675             let left = Path::new($left);
1676             let right = Path::new($right);
1677             assert_eq!(left.cmp(&right), Ordering::$ord);
1678             if (core::cmp::Ordering::$ord == Ordering::Equal) {
1679                 assert_eq!(left, right);
1680
1681                 let mut hasher = DefaultHasher::new();
1682                 left.hash(&mut hasher);
1683                 let left_hash = hasher.finish();
1684                 hasher = DefaultHasher::new();
1685                 right.hash(&mut hasher);
1686                 let right_hash = hasher.finish();
1687
1688                 assert_eq!(left_hash, right_hash, "hashes for {:?} and {:?} must match", left, right);
1689             } else {
1690                 assert_ne!(left, right);
1691             }
1692         });
1693     );
1694
1695     ord!(Less, "1", "2");
1696     ord!(Less, "/foo/bar", "/foo./bar");
1697     ord!(Less, "foo/bar", "foo/bar.");
1698     ord!(Equal, "foo/./bar", "foo/bar/");
1699     ord!(Equal, "foo/bar", "foo/bar/");
1700     ord!(Equal, "foo/bar", "foo/bar/.");
1701     ord!(Equal, "foo/bar", "foo/bar//");
1702 }
1703
1704 #[test]
1705 #[cfg(unix)]
1706 fn test_unix_absolute() {
1707     use crate::path::absolute;
1708
1709     assert!(absolute("").is_err());
1710
1711     let relative = "a/b";
1712     let mut expected = crate::env::current_dir().unwrap();
1713     expected.push(relative);
1714     assert_eq!(absolute(relative).unwrap().as_os_str(), expected.as_os_str());
1715
1716     // Test how components are collected.
1717     assert_eq!(absolute("/a/b/c").unwrap().as_os_str(), Path::new("/a/b/c").as_os_str());
1718     assert_eq!(absolute("/a//b/c").unwrap().as_os_str(), Path::new("/a/b/c").as_os_str());
1719     assert_eq!(absolute("//a/b/c").unwrap().as_os_str(), Path::new("//a/b/c").as_os_str());
1720     assert_eq!(absolute("///a/b/c").unwrap().as_os_str(), Path::new("/a/b/c").as_os_str());
1721     assert_eq!(absolute("/a/b/c/").unwrap().as_os_str(), Path::new("/a/b/c/").as_os_str());
1722     assert_eq!(
1723         absolute("/a/./b/../c/.././..").unwrap().as_os_str(),
1724         Path::new("/a/b/../c/../..").as_os_str()
1725     );
1726
1727     // Test leading `.` and `..` components
1728     let curdir = crate::env::current_dir().unwrap();
1729     assert_eq!(absolute("./a").unwrap().as_os_str(), curdir.join("a").as_os_str());
1730     assert_eq!(absolute("../a").unwrap().as_os_str(), curdir.join("../a").as_os_str()); // return /pwd/../a
1731 }
1732
1733 #[test]
1734 #[cfg(windows)]
1735 fn test_windows_absolute() {
1736     use crate::path::absolute;
1737     // An empty path is an error.
1738     assert!(absolute("").is_err());
1739
1740     let relative = r"a\b";
1741     let mut expected = crate::env::current_dir().unwrap();
1742     expected.push(relative);
1743     assert_eq!(absolute(relative).unwrap().as_os_str(), expected.as_os_str());
1744
1745     macro_rules! unchanged(
1746         ($path:expr) => {
1747             assert_eq!(absolute($path).unwrap().as_os_str(), Path::new($path).as_os_str());
1748         }
1749     );
1750
1751     unchanged!(r"C:\path\to\file");
1752     unchanged!(r"C:\path\to\file\");
1753     unchanged!(r"\\server\share\to\file");
1754     unchanged!(r"\\server.\share.\to\file");
1755     unchanged!(r"\\.\PIPE\name");
1756     unchanged!(r"\\.\C:\path\to\COM1");
1757     unchanged!(r"\\?\C:\path\to\file");
1758     unchanged!(r"\\?\UNC\server\share\to\file");
1759     unchanged!(r"\\?\PIPE\name");
1760     // Verbatim paths are always unchanged, no matter what.
1761     unchanged!(r"\\?\path.\to/file..");
1762
1763     assert_eq!(
1764         absolute(r"C:\path..\to.\file.").unwrap().as_os_str(),
1765         Path::new(r"C:\path..\to\file").as_os_str()
1766     );
1767     assert_eq!(absolute(r"COM1").unwrap().as_os_str(), Path::new(r"\\.\COM1").as_os_str());
1768 }
1769
1770 #[bench]
1771 #[cfg_attr(miri, ignore)] // Miri isn't fast...
1772 fn bench_path_cmp_fast_path_buf_sort(b: &mut test::Bencher) {
1773     let prefix = "my/home";
1774     let mut paths: Vec<_> =
1775         (0..1000).map(|num| PathBuf::from(prefix).join(format!("file {num}.rs"))).collect();
1776
1777     paths.sort();
1778
1779     b.iter(|| {
1780         black_box(paths.as_mut_slice()).sort_unstable();
1781     });
1782 }
1783
1784 #[bench]
1785 #[cfg_attr(miri, ignore)] // Miri isn't fast...
1786 fn bench_path_cmp_fast_path_long(b: &mut test::Bencher) {
1787     let prefix = "/my/home/is/my/castle/and/my/castle/has/a/rusty/workbench/";
1788     let paths: Vec<_> =
1789         (0..1000).map(|num| PathBuf::from(prefix).join(format!("file {num}.rs"))).collect();
1790
1791     let mut set = BTreeSet::new();
1792
1793     paths.iter().for_each(|p| {
1794         set.insert(p.as_path());
1795     });
1796
1797     b.iter(|| {
1798         set.remove(paths[500].as_path());
1799         set.insert(paths[500].as_path());
1800     });
1801 }
1802
1803 #[bench]
1804 #[cfg_attr(miri, ignore)] // Miri isn't fast...
1805 fn bench_path_cmp_fast_path_short(b: &mut test::Bencher) {
1806     let prefix = "my/home";
1807     let paths: Vec<_> =
1808         (0..1000).map(|num| PathBuf::from(prefix).join(format!("file {num}.rs"))).collect();
1809
1810     let mut set = BTreeSet::new();
1811
1812     paths.iter().for_each(|p| {
1813         set.insert(p.as_path());
1814     });
1815
1816     b.iter(|| {
1817         set.remove(paths[500].as_path());
1818         set.insert(paths[500].as_path());
1819     });
1820 }
1821
1822 #[bench]
1823 #[cfg_attr(miri, ignore)] // Miri isn't fast...
1824 fn bench_path_hashset(b: &mut test::Bencher) {
1825     let prefix = "/my/home/is/my/castle/and/my/castle/has/a/rusty/workbench/";
1826     let paths: Vec<_> =
1827         (0..1000).map(|num| PathBuf::from(prefix).join(format!("file {num}.rs"))).collect();
1828
1829     let mut set = HashSet::new();
1830
1831     paths.iter().for_each(|p| {
1832         set.insert(p.as_path());
1833     });
1834
1835     b.iter(|| {
1836         set.remove(paths[500].as_path());
1837         set.insert(black_box(paths[500].as_path()))
1838     });
1839 }
1840
1841 #[bench]
1842 #[cfg_attr(miri, ignore)] // Miri isn't fast...
1843 fn bench_path_hashset_miss(b: &mut test::Bencher) {
1844     let prefix = "/my/home/is/my/castle/and/my/castle/has/a/rusty/workbench/";
1845     let paths: Vec<_> =
1846         (0..1000).map(|num| PathBuf::from(prefix).join(format!("file {num}.rs"))).collect();
1847
1848     let mut set = HashSet::new();
1849
1850     paths.iter().for_each(|p| {
1851         set.insert(p.as_path());
1852     });
1853
1854     let probe = PathBuf::from(prefix).join("other");
1855
1856     b.iter(|| set.remove(black_box(probe.as_path())));
1857 }
1858
1859 #[bench]
1860 fn bench_hash_path_short(b: &mut test::Bencher) {
1861     let mut hasher = DefaultHasher::new();
1862     let path = Path::new("explorer.exe");
1863
1864     b.iter(|| black_box(path).hash(&mut hasher));
1865
1866     black_box(hasher.finish());
1867 }
1868
1869 #[bench]
1870 fn bench_hash_path_long(b: &mut test::Bencher) {
1871     let mut hasher = DefaultHasher::new();
1872     let path =
1873         Path::new("/aaaaa/aaaaaa/./../aaaaaaaa/bbbbbbbbbbbbb/ccccccccccc/ddddddddd/eeeeeee.fff");
1874
1875     b.iter(|| black_box(path).hash(&mut hasher));
1876
1877     black_box(hasher.finish());
1878 }