]> git.lizzy.rs Git - rust.git/blob - src/libstd/path/posix.rs
auto merge of #13600 : brandonw/rust/master, r=brson
[rust.git] / src / libstd / path / posix.rs
1 // Copyright 2013 The Rust Project Developers. See the COPYRIGHT
2 // file at the top-level directory of this distribution and at
3 // http://rust-lang.org/COPYRIGHT.
4 //
5 // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6 // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8 // option. This file may not be copied, modified, or distributed
9 // except according to those terms.
10
11 //! POSIX file path handling
12
13 use container::Container;
14 use c_str::{CString, ToCStr};
15 use clone::Clone;
16 use cmp::{Eq, TotalEq};
17 use from_str::FromStr;
18 use io::Writer;
19 use iter::{AdditiveIterator, Extendable, Iterator, Map};
20 use option::{Option, None, Some};
21 use str;
22 use str::Str;
23 use slice::{CloneableVector, RevSplits, Splits, Vector, VectorVector,
24             ImmutableEqVector, OwnedVector, ImmutableVector};
25 use vec::Vec;
26
27 use super::{BytesContainer, GenericPath, GenericPathUnsafe};
28
29 /// Iterator that yields successive components of a Path as &[u8]
30 pub type Components<'a> = Splits<'a, u8>;
31 /// Iterator that yields components of a Path in reverse as &[u8]
32 pub type RevComponents<'a> = RevSplits<'a, u8>;
33
34 /// Iterator that yields successive components of a Path as Option<&str>
35 pub type StrComponents<'a> = Map<'a, &'a [u8], Option<&'a str>,
36                                        Components<'a>>;
37 /// Iterator that yields components of a Path in reverse as Option<&str>
38 pub type RevStrComponents<'a> = Map<'a, &'a [u8], Option<&'a str>,
39                                           RevComponents<'a>>;
40
41 /// Represents a POSIX file path
42 #[deriving(Clone)]
43 pub struct Path {
44     repr: Vec<u8>, // assumed to never be empty or contain NULs
45     sepidx: Option<uint> // index of the final separator in repr
46 }
47
48 /// The standard path separator character
49 pub static SEP: char = '/';
50
51 /// The standard path separator byte
52 pub static SEP_BYTE: u8 = SEP as u8;
53
54 /// Returns whether the given byte is a path separator
55 #[inline]
56 pub fn is_sep_byte(u: &u8) -> bool {
57     *u as char == SEP
58 }
59
60 /// Returns whether the given char is a path separator
61 #[inline]
62 pub fn is_sep(c: char) -> bool {
63     c == SEP
64 }
65
66 impl Eq for Path {
67     #[inline]
68     fn eq(&self, other: &Path) -> bool {
69         self.repr == other.repr
70     }
71 }
72
73 impl TotalEq for Path {}
74
75 impl FromStr for Path {
76     fn from_str(s: &str) -> Option<Path> {
77         Path::new_opt(s)
78     }
79 }
80
81 impl ToCStr for Path {
82     #[inline]
83     fn to_c_str(&self) -> CString {
84         // The Path impl guarantees no internal NUL
85         unsafe { self.as_vec().to_c_str_unchecked() }
86     }
87
88     #[inline]
89     unsafe fn to_c_str_unchecked(&self) -> CString {
90         self.as_vec().to_c_str_unchecked()
91     }
92 }
93
94 impl<S: Writer> ::hash::Hash<S> for Path {
95     #[inline]
96     fn hash(&self, state: &mut S) {
97         self.repr.hash(state)
98     }
99 }
100
101 impl BytesContainer for Path {
102     #[inline]
103     fn container_as_bytes<'a>(&'a self) -> &'a [u8] {
104         self.as_vec()
105     }
106     #[inline]
107     fn container_into_owned_bytes(self) -> Vec<u8> {
108         self.into_vec()
109     }
110 }
111
112 impl<'a> BytesContainer for &'a Path {
113     #[inline]
114     fn container_as_bytes<'a>(&'a self) -> &'a [u8] {
115         self.as_vec()
116     }
117 }
118
119 impl GenericPathUnsafe for Path {
120     unsafe fn new_unchecked<T: BytesContainer>(path: T) -> Path {
121         let path = Path::normalize(path.container_as_bytes());
122         assert!(!path.is_empty());
123         let idx = path.as_slice().rposition_elem(&SEP_BYTE);
124         Path{ repr: path, sepidx: idx }
125     }
126
127     unsafe fn set_filename_unchecked<T: BytesContainer>(&mut self, filename: T) {
128         let filename = filename.container_as_bytes();
129         match self.sepidx {
130             None if bytes!("..") == self.repr.as_slice() => {
131                 let mut v = Vec::with_capacity(3 + filename.len());
132                 v.push_all(dot_dot_static);
133                 v.push(SEP_BYTE);
134                 v.push_all(filename);
135                 // FIXME: this is slow
136                 self.repr = Path::normalize(v.as_slice());
137             }
138             None => {
139                 self.repr = Path::normalize(filename);
140             }
141             Some(idx) if self.repr.slice_from(idx+1) == bytes!("..") => {
142                 let mut v = Vec::with_capacity(self.repr.len() + 1 + filename.len());
143                 v.push_all(self.repr.as_slice());
144                 v.push(SEP_BYTE);
145                 v.push_all(filename);
146                 // FIXME: this is slow
147                 self.repr = Path::normalize(v.as_slice());
148             }
149             Some(idx) => {
150                 let mut v = Vec::with_capacity(idx + 1 + filename.len());
151                 v.push_all(self.repr.slice_to(idx+1));
152                 v.push_all(filename);
153                 // FIXME: this is slow
154                 self.repr = Path::normalize(v.as_slice());
155             }
156         }
157         self.sepidx = self.repr.as_slice().rposition_elem(&SEP_BYTE);
158     }
159
160     unsafe fn push_unchecked<T: BytesContainer>(&mut self, path: T) {
161         let path = path.container_as_bytes();
162         if !path.is_empty() {
163             if path[0] == SEP_BYTE {
164                 self.repr = Path::normalize(path);
165             }  else {
166                 let mut v = Vec::with_capacity(self.repr.len() + path.len() + 1);
167                 v.push_all(self.repr.as_slice());
168                 v.push(SEP_BYTE);
169                 v.push_all(path);
170                 // FIXME: this is slow
171                 self.repr = Path::normalize(v.as_slice());
172             }
173             self.sepidx = self.repr.as_slice().rposition_elem(&SEP_BYTE);
174         }
175     }
176 }
177
178 impl GenericPath for Path {
179     #[inline]
180     fn as_vec<'a>(&'a self) -> &'a [u8] {
181         self.repr.as_slice()
182     }
183
184     fn into_vec(self) -> Vec<u8> {
185         self.repr
186     }
187
188     fn dirname<'a>(&'a self) -> &'a [u8] {
189         match self.sepidx {
190             None if bytes!("..") == self.repr.as_slice() => self.repr.as_slice(),
191             None => dot_static,
192             Some(0) => self.repr.slice_to(1),
193             Some(idx) if self.repr.slice_from(idx+1) == bytes!("..") => self.repr.as_slice(),
194             Some(idx) => self.repr.slice_to(idx)
195         }
196     }
197
198     fn filename<'a>(&'a self) -> Option<&'a [u8]> {
199         match self.sepidx {
200             None if bytes!(".") == self.repr.as_slice() ||
201                 bytes!("..") == self.repr.as_slice() => None,
202             None => Some(self.repr.as_slice()),
203             Some(idx) if self.repr.slice_from(idx+1) == bytes!("..") => None,
204             Some(0) if self.repr.slice_from(1).is_empty() => None,
205             Some(idx) => Some(self.repr.slice_from(idx+1))
206         }
207     }
208
209     fn pop(&mut self) -> bool {
210         match self.sepidx {
211             None if bytes!(".") == self.repr.as_slice() => false,
212             None => {
213                 self.repr = vec!['.' as u8];
214                 self.sepidx = None;
215                 true
216             }
217             Some(0) if bytes!("/") == self.repr.as_slice() => false,
218             Some(idx) => {
219                 if idx == 0 {
220                     self.repr.truncate(idx+1);
221                 } else {
222                     self.repr.truncate(idx);
223                 }
224                 self.sepidx = self.repr.as_slice().rposition_elem(&SEP_BYTE);
225                 true
226             }
227         }
228     }
229
230     fn root_path(&self) -> Option<Path> {
231         if self.is_absolute() {
232             Some(Path::new("/"))
233         } else {
234             None
235         }
236     }
237
238     #[inline]
239     fn is_absolute(&self) -> bool {
240         *self.repr.get(0) == SEP_BYTE
241     }
242
243     fn is_ancestor_of(&self, other: &Path) -> bool {
244         if self.is_absolute() != other.is_absolute() {
245             false
246         } else {
247             let mut ita = self.components();
248             let mut itb = other.components();
249             if bytes!(".") == self.repr.as_slice() {
250                 return match itb.next() {
251                     None => true,
252                     Some(b) => b != bytes!("..")
253                 };
254             }
255             loop {
256                 match (ita.next(), itb.next()) {
257                     (None, _) => break,
258                     (Some(a), Some(b)) if a == b => { continue },
259                     (Some(a), _) if a == bytes!("..") => {
260                         // if ita contains only .. components, it's an ancestor
261                         return ita.all(|x| x == bytes!(".."));
262                     }
263                     _ => return false
264                 }
265             }
266             true
267         }
268     }
269
270     #[allow(deprecated_owned_vector)]
271     fn path_relative_from(&self, base: &Path) -> Option<Path> {
272         if self.is_absolute() != base.is_absolute() {
273             if self.is_absolute() {
274                 Some(self.clone())
275             } else {
276                 None
277             }
278         } else {
279             let mut ita = self.components();
280             let mut itb = base.components();
281             let mut comps = vec![];
282             loop {
283                 match (ita.next(), itb.next()) {
284                     (None, None) => break,
285                     (Some(a), None) => {
286                         comps.push(a);
287                         comps.extend(ita.by_ref());
288                         break;
289                     }
290                     (None, _) => comps.push(dot_dot_static),
291                     (Some(a), Some(b)) if comps.is_empty() && a == b => (),
292                     (Some(a), Some(b)) if b == bytes!(".") => comps.push(a),
293                     (Some(_), Some(b)) if b == bytes!("..") => return None,
294                     (Some(a), Some(_)) => {
295                         comps.push(dot_dot_static);
296                         for _ in itb {
297                             comps.push(dot_dot_static);
298                         }
299                         comps.push(a);
300                         comps.extend(ita.by_ref());
301                         break;
302                     }
303                 }
304             }
305             Some(Path::new(comps.as_slice().connect_vec(&SEP_BYTE)))
306         }
307     }
308
309     fn ends_with_path(&self, child: &Path) -> bool {
310         if !child.is_relative() { return false; }
311         let mut selfit = self.rev_components();
312         let mut childit = child.rev_components();
313         loop {
314             match (selfit.next(), childit.next()) {
315                 (Some(a), Some(b)) => if a != b { return false; },
316                 (Some(_), None) => break,
317                 (None, Some(_)) => return false,
318                 (None, None) => break
319             }
320         }
321         true
322     }
323 }
324
325 impl Path {
326     /// Returns a new Path from a byte vector or string
327     ///
328     /// # Failure
329     ///
330     /// Fails the task if the vector contains a NUL.
331     #[inline]
332     pub fn new<T: BytesContainer>(path: T) -> Path {
333         GenericPath::new(path)
334     }
335
336     /// Returns a new Path from a byte vector or string, if possible
337     #[inline]
338     pub fn new_opt<T: BytesContainer>(path: T) -> Option<Path> {
339         GenericPath::new_opt(path)
340     }
341
342     /// Returns a normalized byte vector representation of a path, by removing all empty
343     /// components, and unnecessary . and .. components.
344     fn normalize<V: Vector<u8>+CloneableVector<u8>>(v: V) -> Vec<u8> {
345         // borrowck is being very picky
346         let val = {
347             let is_abs = !v.as_slice().is_empty() && v.as_slice()[0] == SEP_BYTE;
348             let v_ = if is_abs { v.as_slice().slice_from(1) } else { v.as_slice() };
349             let comps = normalize_helper(v_, is_abs);
350             match comps {
351                 None => None,
352                 Some(comps) => {
353                     if is_abs && comps.is_empty() {
354                         Some(vec![SEP_BYTE])
355                     } else {
356                         let n = if is_abs { comps.len() } else { comps.len() - 1} +
357                                 comps.iter().map(|v| v.len()).sum();
358                         let mut v = Vec::with_capacity(n);
359                         let mut it = comps.move_iter();
360                         if !is_abs {
361                             match it.next() {
362                                 None => (),
363                                 Some(comp) => v.push_all(comp)
364                             }
365                         }
366                         for comp in it {
367                             v.push(SEP_BYTE);
368                             v.push_all(comp);
369                         }
370                         Some(v)
371                     }
372                 }
373             }
374         };
375         match val {
376             None => Vec::from_slice(v.as_slice()),
377             Some(val) => val
378         }
379     }
380
381     /// Returns an iterator that yields each component of the path in turn.
382     /// Does not distinguish between absolute and relative paths, e.g.
383     /// /a/b/c and a/b/c yield the same set of components.
384     /// A path of "/" yields no components. A path of "." yields one component.
385     pub fn components<'a>(&'a self) -> Components<'a> {
386         let v = if *self.repr.get(0) == SEP_BYTE {
387             self.repr.slice_from(1)
388         } else { self.repr.as_slice() };
389         let mut ret = v.split(is_sep_byte);
390         if v.is_empty() {
391             // consume the empty "" component
392             ret.next();
393         }
394         ret
395     }
396
397     /// Returns an iterator that yields each component of the path in reverse.
398     /// See components() for details.
399     pub fn rev_components<'a>(&'a self) -> RevComponents<'a> {
400         let v = if *self.repr.get(0) == SEP_BYTE {
401             self.repr.slice_from(1)
402         } else { self.repr.as_slice() };
403         let mut ret = v.rsplit(is_sep_byte);
404         if v.is_empty() {
405             // consume the empty "" component
406             ret.next();
407         }
408         ret
409     }
410
411     /// Returns an iterator that yields each component of the path as Option<&str>.
412     /// See components() for details.
413     pub fn str_components<'a>(&'a self) -> StrComponents<'a> {
414         self.components().map(str::from_utf8)
415     }
416
417     /// Returns an iterator that yields each component of the path in reverse as Option<&str>.
418     /// See components() for details.
419     pub fn rev_str_components<'a>(&'a self) -> RevStrComponents<'a> {
420         self.rev_components().map(str::from_utf8)
421     }
422 }
423
424 // None result means the byte vector didn't need normalizing
425 fn normalize_helper<'a>(v: &'a [u8], is_abs: bool) -> Option<Vec<&'a [u8]>> {
426     if is_abs && v.as_slice().is_empty() {
427         return None;
428     }
429     let mut comps: Vec<&'a [u8]> = vec![];
430     let mut n_up = 0u;
431     let mut changed = false;
432     for comp in v.split(is_sep_byte) {
433         if comp.is_empty() { changed = true }
434         else if comp == bytes!(".") { changed = true }
435         else if comp == bytes!("..") {
436             if is_abs && comps.is_empty() { changed = true }
437             else if comps.len() == n_up { comps.push(dot_dot_static); n_up += 1 }
438             else { comps.pop().unwrap(); changed = true }
439         } else { comps.push(comp) }
440     }
441     if changed {
442         if comps.is_empty() && !is_abs {
443             if v == bytes!(".") {
444                 return None;
445             }
446             comps.push(dot_static);
447         }
448         Some(comps)
449     } else {
450         None
451     }
452 }
453
454 static dot_static: &'static [u8] = bytes!(".");
455 static dot_dot_static: &'static [u8] = bytes!("..");
456
457 #[cfg(test)]
458 mod tests {
459     use prelude::*;
460     use super::*;
461     use str;
462
463     macro_rules! t(
464         (s: $path:expr, $exp:expr) => (
465             {
466                 let path = $path;
467                 assert!(path.as_str() == Some($exp));
468             }
469         );
470         (v: $path:expr, $exp:expr) => (
471             {
472                 let path = $path;
473                 assert!(path.as_vec() == $exp);
474             }
475         )
476     )
477
478     macro_rules! b(
479         ($($arg:expr),+) => (
480             {
481                 static the_bytes: &'static [u8] = bytes!($($arg),+);
482                 the_bytes
483             }
484         )
485     )
486
487     #[test]
488     fn test_paths() {
489         let empty: &[u8] = [];
490         t!(v: Path::new(empty), b!("."));
491         t!(v: Path::new(b!("/")), b!("/"));
492         t!(v: Path::new(b!("a/b/c")), b!("a/b/c"));
493         t!(v: Path::new(b!("a/b/c", 0xff)), b!("a/b/c", 0xff));
494         t!(v: Path::new(b!(0xff, "/../foo", 0x80)), b!("foo", 0x80));
495         let p = Path::new(b!("a/b/c", 0xff));
496         assert!(p.as_str() == None);
497
498         t!(s: Path::new(""), ".");
499         t!(s: Path::new("/"), "/");
500         t!(s: Path::new("hi"), "hi");
501         t!(s: Path::new("hi/"), "hi");
502         t!(s: Path::new("/lib"), "/lib");
503         t!(s: Path::new("/lib/"), "/lib");
504         t!(s: Path::new("hi/there"), "hi/there");
505         t!(s: Path::new("hi/there.txt"), "hi/there.txt");
506
507         t!(s: Path::new("hi/there/"), "hi/there");
508         t!(s: Path::new("hi/../there"), "there");
509         t!(s: Path::new("../hi/there"), "../hi/there");
510         t!(s: Path::new("/../hi/there"), "/hi/there");
511         t!(s: Path::new("foo/.."), ".");
512         t!(s: Path::new("/foo/.."), "/");
513         t!(s: Path::new("/foo/../.."), "/");
514         t!(s: Path::new("/foo/../../bar"), "/bar");
515         t!(s: Path::new("/./hi/./there/."), "/hi/there");
516         t!(s: Path::new("/./hi/./there/./.."), "/hi");
517         t!(s: Path::new("foo/../.."), "..");
518         t!(s: Path::new("foo/../../.."), "../..");
519         t!(s: Path::new("foo/../../bar"), "../bar");
520
521         assert_eq!(Path::new(b!("foo/bar")).into_vec().as_slice(), b!("foo/bar"));
522         assert_eq!(Path::new(b!("/foo/../../bar")).into_vec().as_slice(),
523                    b!("/bar"));
524
525         let p = Path::new(b!("foo/bar", 0x80));
526         assert!(p.as_str() == None);
527     }
528
529     #[test]
530     fn test_opt_paths() {
531         assert!(Path::new_opt(b!("foo/bar", 0)) == None);
532         t!(v: Path::new_opt(b!("foo/bar")).unwrap(), b!("foo/bar"));
533         assert!(Path::new_opt("foo/bar\0") == None);
534         t!(s: Path::new_opt("foo/bar").unwrap(), "foo/bar");
535     }
536
537     #[test]
538     fn test_null_byte() {
539         use task;
540         let result = task::try(proc() {
541             Path::new(b!("foo/bar", 0))
542         });
543         assert!(result.is_err());
544
545         let result = task::try(proc() {
546             Path::new("test").set_filename(b!("f", 0, "o"))
547         });
548         assert!(result.is_err());
549
550         let result = task::try(proc() {
551             Path::new("test").push(b!("f", 0, "o"));
552         });
553         assert!(result.is_err());
554     }
555
556     #[test]
557     fn test_display_str() {
558         macro_rules! t(
559             ($path:expr, $disp:ident, $exp:expr) => (
560                 {
561                     let path = Path::new($path);
562                     assert!(path.$disp().to_str() == ~$exp);
563                 }
564             )
565         )
566         t!("foo", display, "foo");
567         t!(b!("foo", 0x80), display, "foo\uFFFD");
568         t!(b!("foo", 0xff, "bar"), display, "foo\uFFFDbar");
569         t!(b!("foo", 0xff, "/bar"), filename_display, "bar");
570         t!(b!("foo/", 0xff, "bar"), filename_display, "\uFFFDbar");
571         t!(b!("/"), filename_display, "");
572
573         macro_rules! t(
574             ($path:expr, $exp:expr) => (
575                 {
576                     let path = Path::new($path);
577                     let mo = path.display().as_maybe_owned();
578                     assert!(mo.as_slice() == $exp);
579                 }
580             );
581             ($path:expr, $exp:expr, filename) => (
582                 {
583                     let path = Path::new($path);
584                     let mo = path.filename_display().as_maybe_owned();
585                     assert!(mo.as_slice() == $exp);
586                 }
587             )
588         )
589
590         t!("foo", "foo");
591         t!(b!("foo", 0x80), "foo\uFFFD");
592         t!(b!("foo", 0xff, "bar"), "foo\uFFFDbar");
593         t!(b!("foo", 0xff, "/bar"), "bar", filename);
594         t!(b!("foo/", 0xff, "bar"), "\uFFFDbar", filename);
595         t!(b!("/"), "", filename);
596     }
597
598     #[test]
599     fn test_display() {
600         macro_rules! t(
601             ($path:expr, $exp:expr, $expf:expr) => (
602                 {
603                     let path = Path::new($path);
604                     let f = format!("{}", path.display());
605                     assert!(f.as_slice() == $exp);
606                     let f = format!("{}", path.filename_display());
607                     assert!(f.as_slice() == $expf);
608                 }
609             )
610         )
611
612         t!(b!("foo"), "foo", "foo");
613         t!(b!("foo/bar"), "foo/bar", "bar");
614         t!(b!("/"), "/", "");
615         t!(b!("foo", 0xff), "foo\uFFFD", "foo\uFFFD");
616         t!(b!("foo", 0xff, "/bar"), "foo\uFFFD/bar", "bar");
617         t!(b!("foo/", 0xff, "bar"), "foo/\uFFFDbar", "\uFFFDbar");
618         t!(b!(0xff, "foo/bar", 0xff), "\uFFFDfoo/bar\uFFFD", "bar\uFFFD");
619     }
620
621     #[test]
622     fn test_components() {
623         macro_rules! t(
624             (s: $path:expr, $op:ident, $exp:expr) => (
625                 {
626                     let path = Path::new($path);
627                     assert!(path.$op() == ($exp).as_bytes());
628                 }
629             );
630             (s: $path:expr, $op:ident, $exp:expr, opt) => (
631                 {
632                     let path = Path::new($path);
633                     let left = path.$op().map(|x| str::from_utf8(x).unwrap());
634                     assert!(left == $exp);
635                 }
636             );
637             (v: $path:expr, $op:ident, $exp:expr) => (
638                 {
639                     let arg = $path;
640                     let path = Path::new(arg);
641                     assert!(path.$op() == $exp);
642                 }
643             );
644         )
645
646         t!(v: b!("a/b/c"), filename, Some(b!("c")));
647         t!(v: b!("a/b/c", 0xff), filename, Some(b!("c", 0xff)));
648         t!(v: b!("a/b", 0xff, "/c"), filename, Some(b!("c")));
649         t!(s: "a/b/c", filename, Some("c"), opt);
650         t!(s: "/a/b/c", filename, Some("c"), opt);
651         t!(s: "a", filename, Some("a"), opt);
652         t!(s: "/a", filename, Some("a"), opt);
653         t!(s: ".", filename, None, opt);
654         t!(s: "/", filename, None, opt);
655         t!(s: "..", filename, None, opt);
656         t!(s: "../..", filename, None, opt);
657
658         t!(v: b!("a/b/c"), dirname, b!("a/b"));
659         t!(v: b!("a/b/c", 0xff), dirname, b!("a/b"));
660         t!(v: b!("a/b", 0xff, "/c"), dirname, b!("a/b", 0xff));
661         t!(s: "a/b/c", dirname, "a/b");
662         t!(s: "/a/b/c", dirname, "/a/b");
663         t!(s: "a", dirname, ".");
664         t!(s: "/a", dirname, "/");
665         t!(s: ".", dirname, ".");
666         t!(s: "/", dirname, "/");
667         t!(s: "..", dirname, "..");
668         t!(s: "../..", dirname, "../..");
669
670         t!(v: b!("hi/there.txt"), filestem, Some(b!("there")));
671         t!(v: b!("hi/there", 0x80, ".txt"), filestem, Some(b!("there", 0x80)));
672         t!(v: b!("hi/there.t", 0x80, "xt"), filestem, Some(b!("there")));
673         t!(s: "hi/there.txt", filestem, Some("there"), opt);
674         t!(s: "hi/there", filestem, Some("there"), opt);
675         t!(s: "there.txt", filestem, Some("there"), opt);
676         t!(s: "there", filestem, Some("there"), opt);
677         t!(s: ".", filestem, None, opt);
678         t!(s: "/", filestem, None, opt);
679         t!(s: "foo/.bar", filestem, Some(".bar"), opt);
680         t!(s: ".bar", filestem, Some(".bar"), opt);
681         t!(s: "..bar", filestem, Some("."), opt);
682         t!(s: "hi/there..txt", filestem, Some("there."), opt);
683         t!(s: "..", filestem, None, opt);
684         t!(s: "../..", filestem, None, opt);
685
686         t!(v: b!("hi/there.txt"), extension, Some(b!("txt")));
687         t!(v: b!("hi/there", 0x80, ".txt"), extension, Some(b!("txt")));
688         t!(v: b!("hi/there.t", 0x80, "xt"), extension, Some(b!("t", 0x80, "xt")));
689         t!(v: b!("hi/there"), extension, None);
690         t!(v: b!("hi/there", 0x80), extension, None);
691         t!(s: "hi/there.txt", extension, Some("txt"), opt);
692         t!(s: "hi/there", extension, None, opt);
693         t!(s: "there.txt", extension, Some("txt"), opt);
694         t!(s: "there", extension, None, opt);
695         t!(s: ".", extension, None, opt);
696         t!(s: "/", extension, None, opt);
697         t!(s: "foo/.bar", extension, None, opt);
698         t!(s: ".bar", extension, None, opt);
699         t!(s: "..bar", extension, Some("bar"), opt);
700         t!(s: "hi/there..txt", extension, Some("txt"), opt);
701         t!(s: "..", extension, None, opt);
702         t!(s: "../..", extension, None, opt);
703     }
704
705     #[test]
706     fn test_push() {
707         macro_rules! t(
708             (s: $path:expr, $join:expr) => (
709                 {
710                     let path = $path;
711                     let join = $join;
712                     let mut p1 = Path::new(path);
713                     let p2 = p1.clone();
714                     p1.push(join);
715                     assert!(p1 == p2.join(join));
716                 }
717             )
718         )
719
720         t!(s: "a/b/c", "..");
721         t!(s: "/a/b/c", "d");
722         t!(s: "a/b", "c/d");
723         t!(s: "a/b", "/c/d");
724     }
725
726     #[test]
727     fn test_push_path() {
728         macro_rules! t(
729             (s: $path:expr, $push:expr, $exp:expr) => (
730                 {
731                     let mut p = Path::new($path);
732                     let push = Path::new($push);
733                     p.push(&push);
734                     assert!(p.as_str() == Some($exp));
735                 }
736             )
737         )
738
739         t!(s: "a/b/c", "d", "a/b/c/d");
740         t!(s: "/a/b/c", "d", "/a/b/c/d");
741         t!(s: "a/b", "c/d", "a/b/c/d");
742         t!(s: "a/b", "/c/d", "/c/d");
743         t!(s: "a/b", ".", "a/b");
744         t!(s: "a/b", "../c", "a/c");
745     }
746
747     #[test]
748     fn test_push_many() {
749         macro_rules! t(
750             (s: $path:expr, $push:expr, $exp:expr) => (
751                 {
752                     let mut p = Path::new($path);
753                     p.push_many($push);
754                     assert!(p.as_str() == Some($exp));
755                 }
756             );
757             (v: $path:expr, $push:expr, $exp:expr) => (
758                 {
759                     let mut p = Path::new($path);
760                     p.push_many($push);
761                     assert!(p.as_vec() == $exp);
762                 }
763             )
764         )
765
766         t!(s: "a/b/c", ["d", "e"], "a/b/c/d/e");
767         t!(s: "a/b/c", ["d", "/e"], "/e");
768         t!(s: "a/b/c", ["d", "/e", "f"], "/e/f");
769         t!(s: "a/b/c", [~"d", ~"e"], "a/b/c/d/e");
770         t!(v: b!("a/b/c"), [b!("d"), b!("e")], b!("a/b/c/d/e"));
771         t!(v: b!("a/b/c"), [b!("d"), b!("/e"), b!("f")], b!("/e/f"));
772         t!(v: b!("a/b/c"), [Vec::from_slice(b!("d")), Vec::from_slice(b!("e"))], b!("a/b/c/d/e"));
773     }
774
775     #[test]
776     fn test_pop() {
777         macro_rules! t(
778             (s: $path:expr, $left:expr, $right:expr) => (
779                 {
780                     let mut p = Path::new($path);
781                     let result = p.pop();
782                     assert!(p.as_str() == Some($left));
783                     assert!(result == $right);
784                 }
785             );
786             (v: [$($path:expr),+], [$($left:expr),+], $right:expr) => (
787                 {
788                     let mut p = Path::new(b!($($path),+));
789                     let result = p.pop();
790                     assert!(p.as_vec() == b!($($left),+));
791                     assert!(result == $right);
792                 }
793             )
794         )
795
796         t!(v: ["a/b/c"], ["a/b"], true);
797         t!(v: ["a"], ["."], true);
798         t!(v: ["."], ["."], false);
799         t!(v: ["/a"], ["/"], true);
800         t!(v: ["/"], ["/"], false);
801         t!(v: ["a/b/c", 0x80], ["a/b"], true);
802         t!(v: ["a/b", 0x80, "/c"], ["a/b", 0x80], true);
803         t!(v: [0xff], ["."], true);
804         t!(v: ["/", 0xff], ["/"], true);
805         t!(s: "a/b/c", "a/b", true);
806         t!(s: "a", ".", true);
807         t!(s: ".", ".", false);
808         t!(s: "/a", "/", true);
809         t!(s: "/", "/", false);
810     }
811
812     #[test]
813     fn test_root_path() {
814         assert!(Path::new(b!("a/b/c")).root_path() == None);
815         assert!(Path::new(b!("/a/b/c")).root_path() == Some(Path::new("/")));
816     }
817
818     #[test]
819     fn test_join() {
820         t!(v: Path::new(b!("a/b/c")).join(b!("..")), b!("a/b"));
821         t!(v: Path::new(b!("/a/b/c")).join(b!("d")), b!("/a/b/c/d"));
822         t!(v: Path::new(b!("a/", 0x80, "/c")).join(b!(0xff)), b!("a/", 0x80, "/c/", 0xff));
823         t!(s: Path::new("a/b/c").join(".."), "a/b");
824         t!(s: Path::new("/a/b/c").join("d"), "/a/b/c/d");
825         t!(s: Path::new("a/b").join("c/d"), "a/b/c/d");
826         t!(s: Path::new("a/b").join("/c/d"), "/c/d");
827         t!(s: Path::new(".").join("a/b"), "a/b");
828         t!(s: Path::new("/").join("a/b"), "/a/b");
829     }
830
831     #[test]
832     fn test_join_path() {
833         macro_rules! t(
834             (s: $path:expr, $join:expr, $exp:expr) => (
835                 {
836                     let path = Path::new($path);
837                     let join = Path::new($join);
838                     let res = path.join(&join);
839                     assert!(res.as_str() == Some($exp));
840                 }
841             )
842         )
843
844         t!(s: "a/b/c", "..", "a/b");
845         t!(s: "/a/b/c", "d", "/a/b/c/d");
846         t!(s: "a/b", "c/d", "a/b/c/d");
847         t!(s: "a/b", "/c/d", "/c/d");
848         t!(s: ".", "a/b", "a/b");
849         t!(s: "/", "a/b", "/a/b");
850     }
851
852     #[test]
853     fn test_join_many() {
854         macro_rules! t(
855             (s: $path:expr, $join:expr, $exp:expr) => (
856                 {
857                     let path = Path::new($path);
858                     let res = path.join_many($join);
859                     assert!(res.as_str() == Some($exp));
860                 }
861             );
862             (v: $path:expr, $join:expr, $exp:expr) => (
863                 {
864                     let path = Path::new($path);
865                     let res = path.join_many($join);
866                     assert!(res.as_vec() == $exp);
867                 }
868             )
869         )
870
871         t!(s: "a/b/c", ["d", "e"], "a/b/c/d/e");
872         t!(s: "a/b/c", ["..", "d"], "a/b/d");
873         t!(s: "a/b/c", ["d", "/e", "f"], "/e/f");
874         t!(s: "a/b/c", [~"d", ~"e"], "a/b/c/d/e");
875         t!(v: b!("a/b/c"), [b!("d"), b!("e")], b!("a/b/c/d/e"));
876         t!(v: b!("a/b/c"), [Vec::from_slice(b!("d")), Vec::from_slice(b!("e"))], b!("a/b/c/d/e"));
877     }
878
879     #[test]
880     fn test_with_helpers() {
881         let empty: &[u8] = [];
882
883         t!(v: Path::new(b!("a/b/c")).with_filename(b!("d")), b!("a/b/d"));
884         t!(v: Path::new(b!("a/b/c", 0xff)).with_filename(b!(0x80)), b!("a/b/", 0x80));
885         t!(v: Path::new(b!("/", 0xff, "/foo")).with_filename(b!(0xcd)),
886               b!("/", 0xff, "/", 0xcd));
887         t!(s: Path::new("a/b/c").with_filename("d"), "a/b/d");
888         t!(s: Path::new(".").with_filename("foo"), "foo");
889         t!(s: Path::new("/a/b/c").with_filename("d"), "/a/b/d");
890         t!(s: Path::new("/").with_filename("foo"), "/foo");
891         t!(s: Path::new("/a").with_filename("foo"), "/foo");
892         t!(s: Path::new("foo").with_filename("bar"), "bar");
893         t!(s: Path::new("/").with_filename("foo/"), "/foo");
894         t!(s: Path::new("/a").with_filename("foo/"), "/foo");
895         t!(s: Path::new("a/b/c").with_filename(""), "a/b");
896         t!(s: Path::new("a/b/c").with_filename("."), "a/b");
897         t!(s: Path::new("a/b/c").with_filename(".."), "a");
898         t!(s: Path::new("/a").with_filename(""), "/");
899         t!(s: Path::new("foo").with_filename(""), ".");
900         t!(s: Path::new("a/b/c").with_filename("d/e"), "a/b/d/e");
901         t!(s: Path::new("a/b/c").with_filename("/d"), "a/b/d");
902         t!(s: Path::new("..").with_filename("foo"), "../foo");
903         t!(s: Path::new("../..").with_filename("foo"), "../../foo");
904         t!(s: Path::new("..").with_filename(""), "..");
905         t!(s: Path::new("../..").with_filename(""), "../..");
906
907         t!(v: Path::new(b!("hi/there", 0x80, ".txt")).with_extension(b!("exe")),
908               b!("hi/there", 0x80, ".exe"));
909         t!(v: Path::new(b!("hi/there.txt", 0x80)).with_extension(b!(0xff)),
910               b!("hi/there.", 0xff));
911         t!(v: Path::new(b!("hi/there", 0x80)).with_extension(b!(0xff)),
912               b!("hi/there", 0x80, ".", 0xff));
913         t!(v: Path::new(b!("hi/there.", 0xff)).with_extension(empty), b!("hi/there"));
914         t!(s: Path::new("hi/there.txt").with_extension("exe"), "hi/there.exe");
915         t!(s: Path::new("hi/there.txt").with_extension(""), "hi/there");
916         t!(s: Path::new("hi/there.txt").with_extension("."), "hi/there..");
917         t!(s: Path::new("hi/there.txt").with_extension(".."), "hi/there...");
918         t!(s: Path::new("hi/there").with_extension("txt"), "hi/there.txt");
919         t!(s: Path::new("hi/there").with_extension("."), "hi/there..");
920         t!(s: Path::new("hi/there").with_extension(".."), "hi/there...");
921         t!(s: Path::new("hi/there.").with_extension("txt"), "hi/there.txt");
922         t!(s: Path::new("hi/.foo").with_extension("txt"), "hi/.foo.txt");
923         t!(s: Path::new("hi/there.txt").with_extension(".foo"), "hi/there..foo");
924         t!(s: Path::new("/").with_extension("txt"), "/");
925         t!(s: Path::new("/").with_extension("."), "/");
926         t!(s: Path::new("/").with_extension(".."), "/");
927         t!(s: Path::new(".").with_extension("txt"), ".");
928     }
929
930     #[test]
931     fn test_setters() {
932         macro_rules! t(
933             (s: $path:expr, $set:ident, $with:ident, $arg:expr) => (
934                 {
935                     let path = $path;
936                     let arg = $arg;
937                     let mut p1 = Path::new(path);
938                     p1.$set(arg);
939                     let p2 = Path::new(path);
940                     assert!(p1 == p2.$with(arg));
941                 }
942             );
943             (v: $path:expr, $set:ident, $with:ident, $arg:expr) => (
944                 {
945                     let path = $path;
946                     let arg = $arg;
947                     let mut p1 = Path::new(path);
948                     p1.$set(arg);
949                     let p2 = Path::new(path);
950                     assert!(p1 == p2.$with(arg));
951                 }
952             )
953         )
954
955         t!(v: b!("a/b/c"), set_filename, with_filename, b!("d"));
956         t!(v: b!("/"), set_filename, with_filename, b!("foo"));
957         t!(v: b!(0x80), set_filename, with_filename, b!(0xff));
958         t!(s: "a/b/c", set_filename, with_filename, "d");
959         t!(s: "/", set_filename, with_filename, "foo");
960         t!(s: ".", set_filename, with_filename, "foo");
961         t!(s: "a/b", set_filename, with_filename, "");
962         t!(s: "a", set_filename, with_filename, "");
963
964         t!(v: b!("hi/there.txt"), set_extension, with_extension, b!("exe"));
965         t!(v: b!("hi/there.t", 0x80, "xt"), set_extension, with_extension, b!("exe", 0xff));
966         t!(s: "hi/there.txt", set_extension, with_extension, "exe");
967         t!(s: "hi/there.", set_extension, with_extension, "txt");
968         t!(s: "hi/there", set_extension, with_extension, "txt");
969         t!(s: "hi/there.txt", set_extension, with_extension, "");
970         t!(s: "hi/there", set_extension, with_extension, "");
971         t!(s: ".", set_extension, with_extension, "txt");
972     }
973
974     #[test]
975     fn test_getters() {
976         macro_rules! t(
977             (s: $path:expr, $filename:expr, $dirname:expr, $filestem:expr, $ext:expr) => (
978                 {
979                     let path = $path;
980                     let filename = $filename;
981                     assert!(path.filename_str() == filename,
982                             "{}.filename_str(): Expected `{:?}`, found {:?}",
983                             path.as_str().unwrap(), filename, path.filename_str());
984                     let dirname = $dirname;
985                     assert!(path.dirname_str() == dirname,
986                             "`{}`.dirname_str(): Expected `{:?}`, found `{:?}`",
987                             path.as_str().unwrap(), dirname, path.dirname_str());
988                     let filestem = $filestem;
989                     assert!(path.filestem_str() == filestem,
990                             "`{}`.filestem_str(): Expected `{:?}`, found `{:?}`",
991                             path.as_str().unwrap(), filestem, path.filestem_str());
992                     let ext = $ext;
993                     assert!(path.extension_str() == ext,
994                             "`{}`.extension_str(): Expected `{:?}`, found `{:?}`",
995                             path.as_str().unwrap(), ext, path.extension_str());
996                 }
997             );
998             (v: $path:expr, $filename:expr, $dirname:expr, $filestem:expr, $ext:expr) => (
999                 {
1000                     let path = $path;
1001                     assert!(path.filename() == $filename);
1002                     assert!(path.dirname() == $dirname);
1003                     assert!(path.filestem() == $filestem);
1004                     assert!(path.extension() == $ext);
1005                 }
1006             )
1007         )
1008
1009         t!(v: Path::new(b!("a/b/c")), Some(b!("c")), b!("a/b"), Some(b!("c")), None);
1010         t!(v: Path::new(b!("a/b/", 0xff)), Some(b!(0xff)), b!("a/b"), Some(b!(0xff)), None);
1011         t!(v: Path::new(b!("hi/there.", 0xff)), Some(b!("there.", 0xff)), b!("hi"),
1012               Some(b!("there")), Some(b!(0xff)));
1013         t!(s: Path::new("a/b/c"), Some("c"), Some("a/b"), Some("c"), None);
1014         t!(s: Path::new("."), None, Some("."), None, None);
1015         t!(s: Path::new("/"), None, Some("/"), None, None);
1016         t!(s: Path::new(".."), None, Some(".."), None, None);
1017         t!(s: Path::new("../.."), None, Some("../.."), None, None);
1018         t!(s: Path::new("hi/there.txt"), Some("there.txt"), Some("hi"),
1019               Some("there"), Some("txt"));
1020         t!(s: Path::new("hi/there"), Some("there"), Some("hi"), Some("there"), None);
1021         t!(s: Path::new("hi/there."), Some("there."), Some("hi"),
1022               Some("there"), Some(""));
1023         t!(s: Path::new("hi/.there"), Some(".there"), Some("hi"), Some(".there"), None);
1024         t!(s: Path::new("hi/..there"), Some("..there"), Some("hi"),
1025               Some("."), Some("there"));
1026         t!(s: Path::new(b!("a/b/", 0xff)), None, Some("a/b"), None, None);
1027         t!(s: Path::new(b!("a/b/", 0xff, ".txt")), None, Some("a/b"), None, Some("txt"));
1028         t!(s: Path::new(b!("a/b/c.", 0x80)), None, Some("a/b"), Some("c"), None);
1029         t!(s: Path::new(b!(0xff, "/b")), Some("b"), None, Some("b"), None);
1030     }
1031
1032     #[test]
1033     fn test_dir_path() {
1034         t!(v: Path::new(b!("hi/there", 0x80)).dir_path(), b!("hi"));
1035         t!(v: Path::new(b!("hi", 0xff, "/there")).dir_path(), b!("hi", 0xff));
1036         t!(s: Path::new("hi/there").dir_path(), "hi");
1037         t!(s: Path::new("hi").dir_path(), ".");
1038         t!(s: Path::new("/hi").dir_path(), "/");
1039         t!(s: Path::new("/").dir_path(), "/");
1040         t!(s: Path::new("..").dir_path(), "..");
1041         t!(s: Path::new("../..").dir_path(), "../..");
1042     }
1043
1044     #[test]
1045     fn test_is_absolute() {
1046         macro_rules! t(
1047             (s: $path:expr, $abs:expr, $rel:expr) => (
1048                 {
1049                     let path = Path::new($path);
1050                     assert_eq!(path.is_absolute(), $abs);
1051                     assert_eq!(path.is_relative(), $rel);
1052                 }
1053             )
1054         )
1055         t!(s: "a/b/c", false, true);
1056         t!(s: "/a/b/c", true, false);
1057         t!(s: "a", false, true);
1058         t!(s: "/a", true, false);
1059         t!(s: ".", false, true);
1060         t!(s: "/", true, false);
1061         t!(s: "..", false, true);
1062         t!(s: "../..", false, true);
1063     }
1064
1065     #[test]
1066     fn test_is_ancestor_of() {
1067         macro_rules! t(
1068             (s: $path:expr, $dest:expr, $exp:expr) => (
1069                 {
1070                     let path = Path::new($path);
1071                     let dest = Path::new($dest);
1072                     assert_eq!(path.is_ancestor_of(&dest), $exp);
1073                 }
1074             )
1075         )
1076
1077         t!(s: "a/b/c", "a/b/c/d", true);
1078         t!(s: "a/b/c", "a/b/c", true);
1079         t!(s: "a/b/c", "a/b", false);
1080         t!(s: "/a/b/c", "/a/b/c", true);
1081         t!(s: "/a/b", "/a/b/c", true);
1082         t!(s: "/a/b/c/d", "/a/b/c", false);
1083         t!(s: "/a/b", "a/b/c", false);
1084         t!(s: "a/b", "/a/b/c", false);
1085         t!(s: "a/b/c", "a/b/d", false);
1086         t!(s: "../a/b/c", "a/b/c", false);
1087         t!(s: "a/b/c", "../a/b/c", false);
1088         t!(s: "a/b/c", "a/b/cd", false);
1089         t!(s: "a/b/cd", "a/b/c", false);
1090         t!(s: "../a/b", "../a/b/c", true);
1091         t!(s: ".", "a/b", true);
1092         t!(s: ".", ".", true);
1093         t!(s: "/", "/", true);
1094         t!(s: "/", "/a/b", true);
1095         t!(s: "..", "a/b", true);
1096         t!(s: "../..", "a/b", true);
1097     }
1098
1099     #[test]
1100     fn test_ends_with_path() {
1101         macro_rules! t(
1102             (s: $path:expr, $child:expr, $exp:expr) => (
1103                 {
1104                     let path = Path::new($path);
1105                     let child = Path::new($child);
1106                     assert_eq!(path.ends_with_path(&child), $exp);
1107                 }
1108             );
1109             (v: $path:expr, $child:expr, $exp:expr) => (
1110                 {
1111                     let path = Path::new($path);
1112                     let child = Path::new($child);
1113                     assert_eq!(path.ends_with_path(&child), $exp);
1114                 }
1115             )
1116         )
1117
1118         t!(s: "a/b/c", "c", true);
1119         t!(s: "a/b/c", "d", false);
1120         t!(s: "foo/bar/quux", "bar", false);
1121         t!(s: "foo/bar/quux", "barquux", false);
1122         t!(s: "a/b/c", "b/c", true);
1123         t!(s: "a/b/c", "a/b/c", true);
1124         t!(s: "a/b/c", "foo/a/b/c", false);
1125         t!(s: "/a/b/c", "a/b/c", true);
1126         t!(s: "/a/b/c", "/a/b/c", false); // child must be relative
1127         t!(s: "/a/b/c", "foo/a/b/c", false);
1128         t!(s: "a/b/c", "", false);
1129         t!(s: "", "", true);
1130         t!(s: "/a/b/c", "d/e/f", false);
1131         t!(s: "a/b/c", "a/b", false);
1132         t!(s: "a/b/c", "b", false);
1133         t!(v: b!("a/b/c"), b!("b/c"), true);
1134         t!(v: b!("a/b/", 0xff), b!(0xff), true);
1135         t!(v: b!("a/b/", 0xff), b!("b/", 0xff), true);
1136     }
1137
1138     #[test]
1139     fn test_path_relative_from() {
1140         macro_rules! t(
1141             (s: $path:expr, $other:expr, $exp:expr) => (
1142                 {
1143                     let path = Path::new($path);
1144                     let other = Path::new($other);
1145                     let res = path.path_relative_from(&other);
1146                     assert_eq!(res.as_ref().and_then(|x| x.as_str()), $exp);
1147                 }
1148             )
1149         )
1150
1151         t!(s: "a/b/c", "a/b", Some("c"));
1152         t!(s: "a/b/c", "a/b/d", Some("../c"));
1153         t!(s: "a/b/c", "a/b/c/d", Some(".."));
1154         t!(s: "a/b/c", "a/b/c", Some("."));
1155         t!(s: "a/b/c", "a/b/c/d/e", Some("../.."));
1156         t!(s: "a/b/c", "a/d/e", Some("../../b/c"));
1157         t!(s: "a/b/c", "d/e/f", Some("../../../a/b/c"));
1158         t!(s: "a/b/c", "/a/b/c", None);
1159         t!(s: "/a/b/c", "a/b/c", Some("/a/b/c"));
1160         t!(s: "/a/b/c", "/a/b/c/d", Some(".."));
1161         t!(s: "/a/b/c", "/a/b", Some("c"));
1162         t!(s: "/a/b/c", "/a/b/c/d/e", Some("../.."));
1163         t!(s: "/a/b/c", "/a/d/e", Some("../../b/c"));
1164         t!(s: "/a/b/c", "/d/e/f", Some("../../../a/b/c"));
1165         t!(s: "hi/there.txt", "hi/there", Some("../there.txt"));
1166         t!(s: ".", "a", Some(".."));
1167         t!(s: ".", "a/b", Some("../.."));
1168         t!(s: ".", ".", Some("."));
1169         t!(s: "a", ".", Some("a"));
1170         t!(s: "a/b", ".", Some("a/b"));
1171         t!(s: "..", ".", Some(".."));
1172         t!(s: "a/b/c", "a/b/c", Some("."));
1173         t!(s: "/a/b/c", "/a/b/c", Some("."));
1174         t!(s: "/", "/", Some("."));
1175         t!(s: "/", ".", Some("/"));
1176         t!(s: "../../a", "b", Some("../../../a"));
1177         t!(s: "a", "../../b", None);
1178         t!(s: "../../a", "../../b", Some("../a"));
1179         t!(s: "../../a", "../../a/b", Some(".."));
1180         t!(s: "../../a/b", "../../a", Some("b"));
1181     }
1182
1183     #[test]
1184     fn test_components_iter() {
1185         macro_rules! t(
1186             (s: $path:expr, $exp:expr) => (
1187                 {
1188                     let path = Path::new($path);
1189                     let comps = path.components().collect::<Vec<&[u8]>>();
1190                     let exp: &[&str] = $exp;
1191                     let exps = exp.iter().map(|x| x.as_bytes()).collect::<Vec<&[u8]>>();
1192                     assert!(comps == exps, "components: Expected {:?}, found {:?}",
1193                             comps, exps);
1194                     let comps = path.rev_components().collect::<Vec<&[u8]>>();
1195                     let exps = exps.move_iter().rev().collect::<Vec<&[u8]>>();
1196                     assert!(comps == exps, "rev_components: Expected {:?}, found {:?}",
1197                             comps, exps);
1198                 }
1199             );
1200             (v: [$($arg:expr),+], [$([$($exp:expr),*]),*]) => (
1201                 {
1202                     let path = Path::new(b!($($arg),+));
1203                     let comps = path.components().collect::<Vec<&[u8]>>();
1204                     let exp: &[&[u8]] = [$(b!($($exp),*)),*];
1205                     assert_eq!(comps.as_slice(), exp);
1206                     let comps = path.rev_components().collect::<Vec<&[u8]>>();
1207                     let exp = exp.rev_iter().map(|&x|x).collect::<Vec<&[u8]>>();
1208                     assert_eq!(comps, exp)
1209                 }
1210             )
1211         )
1212
1213         t!(v: ["a/b/c"], [["a"], ["b"], ["c"]]);
1214         t!(v: ["/", 0xff, "/a/", 0x80], [[0xff], ["a"], [0x80]]);
1215         t!(v: ["../../foo", 0xcd, "bar"], [[".."], [".."], ["foo", 0xcd, "bar"]]);
1216         t!(s: "a/b/c", ["a", "b", "c"]);
1217         t!(s: "a/b/d", ["a", "b", "d"]);
1218         t!(s: "a/b/cd", ["a", "b", "cd"]);
1219         t!(s: "/a/b/c", ["a", "b", "c"]);
1220         t!(s: "a", ["a"]);
1221         t!(s: "/a", ["a"]);
1222         t!(s: "/", []);
1223         t!(s: ".", ["."]);
1224         t!(s: "..", [".."]);
1225         t!(s: "../..", ["..", ".."]);
1226         t!(s: "../../foo", ["..", "..", "foo"]);
1227     }
1228
1229     #[test]
1230     fn test_str_components() {
1231         macro_rules! t(
1232             (v: [$($arg:expr),+], $exp:expr) => (
1233                 {
1234                     let path = Path::new(b!($($arg),+));
1235                     let comps = path.str_components().collect::<Vec<Option<&str>>>();
1236                     let exp: &[Option<&str>] = $exp;
1237                     assert_eq!(comps.as_slice(), exp);
1238                     let comps = path.rev_str_components().collect::<Vec<Option<&str>>>();
1239                     let exp = exp.rev_iter().map(|&x|x).collect::<Vec<Option<&str>>>();
1240                     assert_eq!(comps, exp);
1241                 }
1242             )
1243         )
1244
1245         t!(v: ["a/b/c"], [Some("a"), Some("b"), Some("c")]);
1246         t!(v: ["/", 0xff, "/a/", 0x80], [None, Some("a"), None]);
1247         t!(v: ["../../foo", 0xcd, "bar"], [Some(".."), Some(".."), None]);
1248         // str_components is a wrapper around components, so no need to do
1249         // the full set of tests
1250     }
1251 }
1252
1253 #[cfg(test)]
1254 mod bench {
1255     extern crate test;
1256     use self::test::Bencher;
1257     use super::*;
1258     use prelude::*;
1259
1260     #[bench]
1261     fn join_home_dir(b: &mut Bencher) {
1262         let posix_path = Path::new("/");
1263         b.iter(|| {
1264             posix_path.join("home");
1265         });
1266     }
1267
1268     #[bench]
1269     fn join_abs_path_home_dir(b: &mut Bencher) {
1270         let posix_path = Path::new("/");
1271         b.iter(|| {
1272             posix_path.join("/home");
1273         });
1274     }
1275
1276     #[bench]
1277     fn join_many_home_dir(b: &mut Bencher) {
1278         let posix_path = Path::new("/");
1279         b.iter(|| {
1280             posix_path.join_many(&["home"]);
1281         });
1282     }
1283
1284     #[bench]
1285     fn join_many_abs_path_home_dir(b: &mut Bencher) {
1286         let posix_path = Path::new("/");
1287         b.iter(|| {
1288             posix_path.join_many(&["/home"]);
1289         });
1290     }
1291
1292     #[bench]
1293     fn push_home_dir(b: &mut Bencher) {
1294         let mut posix_path = Path::new("/");
1295         b.iter(|| {
1296             posix_path.push("home");
1297         });
1298     }
1299
1300     #[bench]
1301     fn push_abs_path_home_dir(b: &mut Bencher) {
1302         let mut posix_path = Path::new("/");
1303         b.iter(|| {
1304             posix_path.push("/home");
1305         });
1306     }
1307
1308     #[bench]
1309     fn push_many_home_dir(b: &mut Bencher) {
1310         let mut posix_path = Path::new("/");
1311         b.iter(|| {
1312             posix_path.push_many(&["home"]);
1313         });
1314     }
1315
1316     #[bench]
1317     fn push_many_abs_path_home_dir(b: &mut Bencher) {
1318         let mut posix_path = Path::new("/");
1319         b.iter(|| {
1320             posix_path.push_many(&["/home"]);
1321         });
1322     }
1323
1324     #[bench]
1325     fn ends_with_path_home_dir(b: &mut Bencher) {
1326         let posix_home_path = Path::new("/home");
1327         b.iter(|| {
1328             posix_home_path.ends_with_path(&Path::new("home"));
1329         });
1330     }
1331
1332     #[bench]
1333     fn ends_with_path_missmatch_jome_home(b: &mut Bencher) {
1334         let posix_home_path = Path::new("/home");
1335         b.iter(|| {
1336             posix_home_path.ends_with_path(&Path::new("jome"));
1337         });
1338     }
1339
1340     #[bench]
1341     fn is_ancestor_of_path_with_10_dirs(b: &mut Bencher) {
1342         let path = Path::new("/home/1/2/3/4/5/6/7/8/9");
1343         let mut sub = path.clone();
1344         sub.pop();
1345         b.iter(|| {
1346             path.is_ancestor_of(&sub);
1347         });
1348     }
1349
1350     #[bench]
1351     fn path_relative_from_forward(b: &mut Bencher) {
1352         let path = Path::new("/a/b/c");
1353         let mut other = path.clone();
1354         other.pop();
1355         b.iter(|| {
1356             path.path_relative_from(&other);
1357         });
1358     }
1359
1360     #[bench]
1361     fn path_relative_from_same_level(b: &mut Bencher) {
1362         let path = Path::new("/a/b/c");
1363         let mut other = path.clone();
1364         other.pop();
1365         other.push("d");
1366         b.iter(|| {
1367             path.path_relative_from(&other);
1368         });
1369     }
1370
1371     #[bench]
1372     fn path_relative_from_backward(b: &mut Bencher) {
1373         let path = Path::new("/a/b");
1374         let mut other = path.clone();
1375         other.push("c");
1376         b.iter(|| {
1377             path.path_relative_from(&other);
1378         });
1379     }
1380 }