]> git.lizzy.rs Git - rust.git/blob - src/libstd/path/posix.rs
Replace all ~"" with "".to_owned()
[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     use str::StrSlice;
463
464     macro_rules! t(
465         (s: $path:expr, $exp:expr) => (
466             {
467                 let path = $path;
468                 assert!(path.as_str() == Some($exp));
469             }
470         );
471         (v: $path:expr, $exp:expr) => (
472             {
473                 let path = $path;
474                 assert!(path.as_vec() == $exp);
475             }
476         )
477     )
478
479     macro_rules! b(
480         ($($arg:expr),+) => (
481             {
482                 static the_bytes: &'static [u8] = bytes!($($arg),+);
483                 the_bytes
484             }
485         )
486     )
487
488     #[test]
489     fn test_paths() {
490         let empty: &[u8] = [];
491         t!(v: Path::new(empty), b!("."));
492         t!(v: Path::new(b!("/")), b!("/"));
493         t!(v: Path::new(b!("a/b/c")), b!("a/b/c"));
494         t!(v: Path::new(b!("a/b/c", 0xff)), b!("a/b/c", 0xff));
495         t!(v: Path::new(b!(0xff, "/../foo", 0x80)), b!("foo", 0x80));
496         let p = Path::new(b!("a/b/c", 0xff));
497         assert!(p.as_str() == None);
498
499         t!(s: Path::new(""), ".");
500         t!(s: Path::new("/"), "/");
501         t!(s: Path::new("hi"), "hi");
502         t!(s: Path::new("hi/"), "hi");
503         t!(s: Path::new("/lib"), "/lib");
504         t!(s: Path::new("/lib/"), "/lib");
505         t!(s: Path::new("hi/there"), "hi/there");
506         t!(s: Path::new("hi/there.txt"), "hi/there.txt");
507
508         t!(s: Path::new("hi/there/"), "hi/there");
509         t!(s: Path::new("hi/../there"), "there");
510         t!(s: Path::new("../hi/there"), "../hi/there");
511         t!(s: Path::new("/../hi/there"), "/hi/there");
512         t!(s: Path::new("foo/.."), ".");
513         t!(s: Path::new("/foo/.."), "/");
514         t!(s: Path::new("/foo/../.."), "/");
515         t!(s: Path::new("/foo/../../bar"), "/bar");
516         t!(s: Path::new("/./hi/./there/."), "/hi/there");
517         t!(s: Path::new("/./hi/./there/./.."), "/hi");
518         t!(s: Path::new("foo/../.."), "..");
519         t!(s: Path::new("foo/../../.."), "../..");
520         t!(s: Path::new("foo/../../bar"), "../bar");
521
522         assert_eq!(Path::new(b!("foo/bar")).into_vec().as_slice(), b!("foo/bar"));
523         assert_eq!(Path::new(b!("/foo/../../bar")).into_vec().as_slice(),
524                    b!("/bar"));
525
526         let p = Path::new(b!("foo/bar", 0x80));
527         assert!(p.as_str() == None);
528     }
529
530     #[test]
531     fn test_opt_paths() {
532         assert!(Path::new_opt(b!("foo/bar", 0)) == None);
533         t!(v: Path::new_opt(b!("foo/bar")).unwrap(), b!("foo/bar"));
534         assert!(Path::new_opt("foo/bar\0") == None);
535         t!(s: Path::new_opt("foo/bar").unwrap(), "foo/bar");
536     }
537
538     #[test]
539     fn test_null_byte() {
540         use task;
541         let result = task::try(proc() {
542             Path::new(b!("foo/bar", 0))
543         });
544         assert!(result.is_err());
545
546         let result = task::try(proc() {
547             Path::new("test").set_filename(b!("f", 0, "o"))
548         });
549         assert!(result.is_err());
550
551         let result = task::try(proc() {
552             Path::new("test").push(b!("f", 0, "o"));
553         });
554         assert!(result.is_err());
555     }
556
557     #[test]
558     fn test_display_str() {
559         macro_rules! t(
560             ($path:expr, $disp:ident, $exp:expr) => (
561                 {
562                     let path = Path::new($path);
563                     assert!(path.$disp().to_str() == ~$exp);
564                 }
565             )
566         )
567         t!("foo", display, "foo");
568         t!(b!("foo", 0x80), display, "foo\uFFFD");
569         t!(b!("foo", 0xff, "bar"), display, "foo\uFFFDbar");
570         t!(b!("foo", 0xff, "/bar"), filename_display, "bar");
571         t!(b!("foo/", 0xff, "bar"), filename_display, "\uFFFDbar");
572         t!(b!("/"), filename_display, "");
573
574         macro_rules! t(
575             ($path:expr, $exp:expr) => (
576                 {
577                     let path = Path::new($path);
578                     let mo = path.display().as_maybe_owned();
579                     assert!(mo.as_slice() == $exp);
580                 }
581             );
582             ($path:expr, $exp:expr, filename) => (
583                 {
584                     let path = Path::new($path);
585                     let mo = path.filename_display().as_maybe_owned();
586                     assert!(mo.as_slice() == $exp);
587                 }
588             )
589         )
590
591         t!("foo", "foo");
592         t!(b!("foo", 0x80), "foo\uFFFD");
593         t!(b!("foo", 0xff, "bar"), "foo\uFFFDbar");
594         t!(b!("foo", 0xff, "/bar"), "bar", filename);
595         t!(b!("foo/", 0xff, "bar"), "\uFFFDbar", filename);
596         t!(b!("/"), "", filename);
597     }
598
599     #[test]
600     fn test_display() {
601         macro_rules! t(
602             ($path:expr, $exp:expr, $expf:expr) => (
603                 {
604                     let path = Path::new($path);
605                     let f = format!("{}", path.display());
606                     assert!(f.as_slice() == $exp);
607                     let f = format!("{}", path.filename_display());
608                     assert!(f.as_slice() == $expf);
609                 }
610             )
611         )
612
613         t!(b!("foo"), "foo", "foo");
614         t!(b!("foo/bar"), "foo/bar", "bar");
615         t!(b!("/"), "/", "");
616         t!(b!("foo", 0xff), "foo\uFFFD", "foo\uFFFD");
617         t!(b!("foo", 0xff, "/bar"), "foo\uFFFD/bar", "bar");
618         t!(b!("foo/", 0xff, "bar"), "foo/\uFFFDbar", "\uFFFDbar");
619         t!(b!(0xff, "foo/bar", 0xff), "\uFFFDfoo/bar\uFFFD", "bar\uFFFD");
620     }
621
622     #[test]
623     fn test_components() {
624         macro_rules! t(
625             (s: $path:expr, $op:ident, $exp:expr) => (
626                 {
627                     let path = Path::new($path);
628                     assert!(path.$op() == ($exp).as_bytes());
629                 }
630             );
631             (s: $path:expr, $op:ident, $exp:expr, opt) => (
632                 {
633                     let path = Path::new($path);
634                     let left = path.$op().map(|x| str::from_utf8(x).unwrap());
635                     assert!(left == $exp);
636                 }
637             );
638             (v: $path:expr, $op:ident, $exp:expr) => (
639                 {
640                     let arg = $path;
641                     let path = Path::new(arg);
642                     assert!(path.$op() == $exp);
643                 }
644             );
645         )
646
647         t!(v: b!("a/b/c"), filename, Some(b!("c")));
648         t!(v: b!("a/b/c", 0xff), filename, Some(b!("c", 0xff)));
649         t!(v: b!("a/b", 0xff, "/c"), filename, Some(b!("c")));
650         t!(s: "a/b/c", filename, Some("c"), opt);
651         t!(s: "/a/b/c", filename, Some("c"), opt);
652         t!(s: "a", filename, Some("a"), opt);
653         t!(s: "/a", filename, Some("a"), opt);
654         t!(s: ".", filename, None, opt);
655         t!(s: "/", filename, None, opt);
656         t!(s: "..", filename, None, opt);
657         t!(s: "../..", filename, None, opt);
658
659         t!(v: b!("a/b/c"), dirname, b!("a/b"));
660         t!(v: b!("a/b/c", 0xff), dirname, b!("a/b"));
661         t!(v: b!("a/b", 0xff, "/c"), dirname, b!("a/b", 0xff));
662         t!(s: "a/b/c", dirname, "a/b");
663         t!(s: "/a/b/c", dirname, "/a/b");
664         t!(s: "a", dirname, ".");
665         t!(s: "/a", dirname, "/");
666         t!(s: ".", dirname, ".");
667         t!(s: "/", dirname, "/");
668         t!(s: "..", dirname, "..");
669         t!(s: "../..", dirname, "../..");
670
671         t!(v: b!("hi/there.txt"), filestem, Some(b!("there")));
672         t!(v: b!("hi/there", 0x80, ".txt"), filestem, Some(b!("there", 0x80)));
673         t!(v: b!("hi/there.t", 0x80, "xt"), filestem, Some(b!("there")));
674         t!(s: "hi/there.txt", filestem, Some("there"), opt);
675         t!(s: "hi/there", filestem, Some("there"), opt);
676         t!(s: "there.txt", filestem, Some("there"), opt);
677         t!(s: "there", filestem, Some("there"), opt);
678         t!(s: ".", filestem, None, opt);
679         t!(s: "/", filestem, None, opt);
680         t!(s: "foo/.bar", filestem, Some(".bar"), opt);
681         t!(s: ".bar", filestem, Some(".bar"), opt);
682         t!(s: "..bar", filestem, Some("."), opt);
683         t!(s: "hi/there..txt", filestem, Some("there."), opt);
684         t!(s: "..", filestem, None, opt);
685         t!(s: "../..", filestem, None, opt);
686
687         t!(v: b!("hi/there.txt"), extension, Some(b!("txt")));
688         t!(v: b!("hi/there", 0x80, ".txt"), extension, Some(b!("txt")));
689         t!(v: b!("hi/there.t", 0x80, "xt"), extension, Some(b!("t", 0x80, "xt")));
690         t!(v: b!("hi/there"), extension, None);
691         t!(v: b!("hi/there", 0x80), extension, None);
692         t!(s: "hi/there.txt", extension, Some("txt"), opt);
693         t!(s: "hi/there", extension, None, opt);
694         t!(s: "there.txt", extension, Some("txt"), opt);
695         t!(s: "there", extension, None, opt);
696         t!(s: ".", extension, None, opt);
697         t!(s: "/", extension, None, opt);
698         t!(s: "foo/.bar", extension, None, opt);
699         t!(s: ".bar", extension, None, opt);
700         t!(s: "..bar", extension, Some("bar"), opt);
701         t!(s: "hi/there..txt", extension, Some("txt"), opt);
702         t!(s: "..", extension, None, opt);
703         t!(s: "../..", extension, None, opt);
704     }
705
706     #[test]
707     fn test_push() {
708         macro_rules! t(
709             (s: $path:expr, $join:expr) => (
710                 {
711                     let path = $path;
712                     let join = $join;
713                     let mut p1 = Path::new(path);
714                     let p2 = p1.clone();
715                     p1.push(join);
716                     assert!(p1 == p2.join(join));
717                 }
718             )
719         )
720
721         t!(s: "a/b/c", "..");
722         t!(s: "/a/b/c", "d");
723         t!(s: "a/b", "c/d");
724         t!(s: "a/b", "/c/d");
725     }
726
727     #[test]
728     fn test_push_path() {
729         macro_rules! t(
730             (s: $path:expr, $push:expr, $exp:expr) => (
731                 {
732                     let mut p = Path::new($path);
733                     let push = Path::new($push);
734                     p.push(&push);
735                     assert!(p.as_str() == Some($exp));
736                 }
737             )
738         )
739
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", "a/b/c/d");
743         t!(s: "a/b", "/c/d", "/c/d");
744         t!(s: "a/b", ".", "a/b");
745         t!(s: "a/b", "../c", "a/c");
746     }
747
748     #[test]
749     fn test_push_many() {
750         macro_rules! t(
751             (s: $path:expr, $push:expr, $exp:expr) => (
752                 {
753                     let mut p = Path::new($path);
754                     p.push_many($push);
755                     assert!(p.as_str() == Some($exp));
756                 }
757             );
758             (v: $path:expr, $push:expr, $exp:expr) => (
759                 {
760                     let mut p = Path::new($path);
761                     p.push_many($push);
762                     assert!(p.as_vec() == $exp);
763                 }
764             )
765         )
766
767         t!(s: "a/b/c", ["d", "e"], "a/b/c/d/e");
768         t!(s: "a/b/c", ["d", "/e"], "/e");
769         t!(s: "a/b/c", ["d", "/e", "f"], "/e/f");
770         t!(s: "a/b/c", ["d".to_owned(), "e".to_owned()], "a/b/c/d/e");
771         t!(v: b!("a/b/c"), [b!("d"), b!("e")], b!("a/b/c/d/e"));
772         t!(v: b!("a/b/c"), [b!("d"), b!("/e"), b!("f")], b!("/e/f"));
773         t!(v: b!("a/b/c"), [Vec::from_slice(b!("d")), Vec::from_slice(b!("e"))], b!("a/b/c/d/e"));
774     }
775
776     #[test]
777     fn test_pop() {
778         macro_rules! t(
779             (s: $path:expr, $left:expr, $right:expr) => (
780                 {
781                     let mut p = Path::new($path);
782                     let result = p.pop();
783                     assert!(p.as_str() == Some($left));
784                     assert!(result == $right);
785                 }
786             );
787             (v: [$($path:expr),+], [$($left:expr),+], $right:expr) => (
788                 {
789                     let mut p = Path::new(b!($($path),+));
790                     let result = p.pop();
791                     assert!(p.as_vec() == b!($($left),+));
792                     assert!(result == $right);
793                 }
794             )
795         )
796
797         t!(v: ["a/b/c"], ["a/b"], true);
798         t!(v: ["a"], ["."], true);
799         t!(v: ["."], ["."], false);
800         t!(v: ["/a"], ["/"], true);
801         t!(v: ["/"], ["/"], false);
802         t!(v: ["a/b/c", 0x80], ["a/b"], true);
803         t!(v: ["a/b", 0x80, "/c"], ["a/b", 0x80], true);
804         t!(v: [0xff], ["."], true);
805         t!(v: ["/", 0xff], ["/"], true);
806         t!(s: "a/b/c", "a/b", true);
807         t!(s: "a", ".", true);
808         t!(s: ".", ".", false);
809         t!(s: "/a", "/", true);
810         t!(s: "/", "/", false);
811     }
812
813     #[test]
814     fn test_root_path() {
815         assert!(Path::new(b!("a/b/c")).root_path() == None);
816         assert!(Path::new(b!("/a/b/c")).root_path() == Some(Path::new("/")));
817     }
818
819     #[test]
820     fn test_join() {
821         t!(v: Path::new(b!("a/b/c")).join(b!("..")), b!("a/b"));
822         t!(v: Path::new(b!("/a/b/c")).join(b!("d")), b!("/a/b/c/d"));
823         t!(v: Path::new(b!("a/", 0x80, "/c")).join(b!(0xff)), b!("a/", 0x80, "/c/", 0xff));
824         t!(s: Path::new("a/b/c").join(".."), "a/b");
825         t!(s: Path::new("/a/b/c").join("d"), "/a/b/c/d");
826         t!(s: Path::new("a/b").join("c/d"), "a/b/c/d");
827         t!(s: Path::new("a/b").join("/c/d"), "/c/d");
828         t!(s: Path::new(".").join("a/b"), "a/b");
829         t!(s: Path::new("/").join("a/b"), "/a/b");
830     }
831
832     #[test]
833     fn test_join_path() {
834         macro_rules! t(
835             (s: $path:expr, $join:expr, $exp:expr) => (
836                 {
837                     let path = Path::new($path);
838                     let join = Path::new($join);
839                     let res = path.join(&join);
840                     assert!(res.as_str() == Some($exp));
841                 }
842             )
843         )
844
845         t!(s: "a/b/c", "..", "a/b");
846         t!(s: "/a/b/c", "d", "/a/b/c/d");
847         t!(s: "a/b", "c/d", "a/b/c/d");
848         t!(s: "a/b", "/c/d", "/c/d");
849         t!(s: ".", "a/b", "a/b");
850         t!(s: "/", "a/b", "/a/b");
851     }
852
853     #[test]
854     fn test_join_many() {
855         macro_rules! t(
856             (s: $path:expr, $join:expr, $exp:expr) => (
857                 {
858                     let path = Path::new($path);
859                     let res = path.join_many($join);
860                     assert!(res.as_str() == Some($exp));
861                 }
862             );
863             (v: $path:expr, $join:expr, $exp:expr) => (
864                 {
865                     let path = Path::new($path);
866                     let res = path.join_many($join);
867                     assert!(res.as_vec() == $exp);
868                 }
869             )
870         )
871
872         t!(s: "a/b/c", ["d", "e"], "a/b/c/d/e");
873         t!(s: "a/b/c", ["..", "d"], "a/b/d");
874         t!(s: "a/b/c", ["d", "/e", "f"], "/e/f");
875         t!(s: "a/b/c", ["d".to_owned(), "e".to_owned()], "a/b/c/d/e");
876         t!(v: b!("a/b/c"), [b!("d"), b!("e")], b!("a/b/c/d/e"));
877         t!(v: b!("a/b/c"), [Vec::from_slice(b!("d")), Vec::from_slice(b!("e"))], b!("a/b/c/d/e"));
878     }
879
880     #[test]
881     fn test_with_helpers() {
882         let empty: &[u8] = [];
883
884         t!(v: Path::new(b!("a/b/c")).with_filename(b!("d")), b!("a/b/d"));
885         t!(v: Path::new(b!("a/b/c", 0xff)).with_filename(b!(0x80)), b!("a/b/", 0x80));
886         t!(v: Path::new(b!("/", 0xff, "/foo")).with_filename(b!(0xcd)),
887               b!("/", 0xff, "/", 0xcd));
888         t!(s: Path::new("a/b/c").with_filename("d"), "a/b/d");
889         t!(s: Path::new(".").with_filename("foo"), "foo");
890         t!(s: Path::new("/a/b/c").with_filename("d"), "/a/b/d");
891         t!(s: Path::new("/").with_filename("foo"), "/foo");
892         t!(s: Path::new("/a").with_filename("foo"), "/foo");
893         t!(s: Path::new("foo").with_filename("bar"), "bar");
894         t!(s: Path::new("/").with_filename("foo/"), "/foo");
895         t!(s: Path::new("/a").with_filename("foo/"), "/foo");
896         t!(s: Path::new("a/b/c").with_filename(""), "a/b");
897         t!(s: Path::new("a/b/c").with_filename("."), "a/b");
898         t!(s: Path::new("a/b/c").with_filename(".."), "a");
899         t!(s: Path::new("/a").with_filename(""), "/");
900         t!(s: Path::new("foo").with_filename(""), ".");
901         t!(s: Path::new("a/b/c").with_filename("d/e"), "a/b/d/e");
902         t!(s: Path::new("a/b/c").with_filename("/d"), "a/b/d");
903         t!(s: Path::new("..").with_filename("foo"), "../foo");
904         t!(s: Path::new("../..").with_filename("foo"), "../../foo");
905         t!(s: Path::new("..").with_filename(""), "..");
906         t!(s: Path::new("../..").with_filename(""), "../..");
907
908         t!(v: Path::new(b!("hi/there", 0x80, ".txt")).with_extension(b!("exe")),
909               b!("hi/there", 0x80, ".exe"));
910         t!(v: Path::new(b!("hi/there.txt", 0x80)).with_extension(b!(0xff)),
911               b!("hi/there.", 0xff));
912         t!(v: Path::new(b!("hi/there", 0x80)).with_extension(b!(0xff)),
913               b!("hi/there", 0x80, ".", 0xff));
914         t!(v: Path::new(b!("hi/there.", 0xff)).with_extension(empty), b!("hi/there"));
915         t!(s: Path::new("hi/there.txt").with_extension("exe"), "hi/there.exe");
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.txt").with_extension(".."), "hi/there...");
919         t!(s: Path::new("hi/there").with_extension("txt"), "hi/there.txt");
920         t!(s: Path::new("hi/there").with_extension("."), "hi/there..");
921         t!(s: Path::new("hi/there").with_extension(".."), "hi/there...");
922         t!(s: Path::new("hi/there.").with_extension("txt"), "hi/there.txt");
923         t!(s: Path::new("hi/.foo").with_extension("txt"), "hi/.foo.txt");
924         t!(s: Path::new("hi/there.txt").with_extension(".foo"), "hi/there..foo");
925         t!(s: Path::new("/").with_extension("txt"), "/");
926         t!(s: Path::new("/").with_extension("."), "/");
927         t!(s: Path::new("/").with_extension(".."), "/");
928         t!(s: Path::new(".").with_extension("txt"), ".");
929     }
930
931     #[test]
932     fn test_setters() {
933         macro_rules! t(
934             (s: $path:expr, $set:ident, $with:ident, $arg:expr) => (
935                 {
936                     let path = $path;
937                     let arg = $arg;
938                     let mut p1 = Path::new(path);
939                     p1.$set(arg);
940                     let p2 = Path::new(path);
941                     assert!(p1 == p2.$with(arg));
942                 }
943             );
944             (v: $path:expr, $set:ident, $with:ident, $arg:expr) => (
945                 {
946                     let path = $path;
947                     let arg = $arg;
948                     let mut p1 = Path::new(path);
949                     p1.$set(arg);
950                     let p2 = Path::new(path);
951                     assert!(p1 == p2.$with(arg));
952                 }
953             )
954         )
955
956         t!(v: b!("a/b/c"), set_filename, with_filename, b!("d"));
957         t!(v: b!("/"), set_filename, with_filename, b!("foo"));
958         t!(v: b!(0x80), set_filename, with_filename, b!(0xff));
959         t!(s: "a/b/c", set_filename, with_filename, "d");
960         t!(s: "/", set_filename, with_filename, "foo");
961         t!(s: ".", set_filename, with_filename, "foo");
962         t!(s: "a/b", set_filename, with_filename, "");
963         t!(s: "a", set_filename, with_filename, "");
964
965         t!(v: b!("hi/there.txt"), set_extension, with_extension, b!("exe"));
966         t!(v: b!("hi/there.t", 0x80, "xt"), set_extension, with_extension, b!("exe", 0xff));
967         t!(s: "hi/there.txt", set_extension, with_extension, "exe");
968         t!(s: "hi/there.", set_extension, with_extension, "txt");
969         t!(s: "hi/there", set_extension, with_extension, "txt");
970         t!(s: "hi/there.txt", set_extension, with_extension, "");
971         t!(s: "hi/there", set_extension, with_extension, "");
972         t!(s: ".", set_extension, with_extension, "txt");
973     }
974
975     #[test]
976     fn test_getters() {
977         macro_rules! t(
978             (s: $path:expr, $filename:expr, $dirname:expr, $filestem:expr, $ext:expr) => (
979                 {
980                     let path = $path;
981                     let filename = $filename;
982                     assert!(path.filename_str() == filename,
983                             "{}.filename_str(): Expected `{:?}`, found {:?}",
984                             path.as_str().unwrap(), filename, path.filename_str());
985                     let dirname = $dirname;
986                     assert!(path.dirname_str() == dirname,
987                             "`{}`.dirname_str(): Expected `{:?}`, found `{:?}`",
988                             path.as_str().unwrap(), dirname, path.dirname_str());
989                     let filestem = $filestem;
990                     assert!(path.filestem_str() == filestem,
991                             "`{}`.filestem_str(): Expected `{:?}`, found `{:?}`",
992                             path.as_str().unwrap(), filestem, path.filestem_str());
993                     let ext = $ext;
994                     assert!(path.extension_str() == ext,
995                             "`{}`.extension_str(): Expected `{:?}`, found `{:?}`",
996                             path.as_str().unwrap(), ext, path.extension_str());
997                 }
998             );
999             (v: $path:expr, $filename:expr, $dirname:expr, $filestem:expr, $ext:expr) => (
1000                 {
1001                     let path = $path;
1002                     assert!(path.filename() == $filename);
1003                     assert!(path.dirname() == $dirname);
1004                     assert!(path.filestem() == $filestem);
1005                     assert!(path.extension() == $ext);
1006                 }
1007             )
1008         )
1009
1010         t!(v: Path::new(b!("a/b/c")), Some(b!("c")), b!("a/b"), Some(b!("c")), None);
1011         t!(v: Path::new(b!("a/b/", 0xff)), Some(b!(0xff)), b!("a/b"), Some(b!(0xff)), None);
1012         t!(v: Path::new(b!("hi/there.", 0xff)), Some(b!("there.", 0xff)), b!("hi"),
1013               Some(b!("there")), Some(b!(0xff)));
1014         t!(s: Path::new("a/b/c"), Some("c"), Some("a/b"), Some("c"), 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("../.."), None, Some("../.."), None, None);
1019         t!(s: Path::new("hi/there.txt"), Some("there.txt"), Some("hi"),
1020               Some("there"), Some("txt"));
1021         t!(s: Path::new("hi/there"), Some("there"), Some("hi"), Some("there"), None);
1022         t!(s: Path::new("hi/there."), Some("there."), Some("hi"),
1023               Some("there"), Some(""));
1024         t!(s: Path::new("hi/.there"), Some(".there"), Some("hi"), Some(".there"), None);
1025         t!(s: Path::new("hi/..there"), Some("..there"), Some("hi"),
1026               Some("."), Some("there"));
1027         t!(s: Path::new(b!("a/b/", 0xff)), None, Some("a/b"), None, None);
1028         t!(s: Path::new(b!("a/b/", 0xff, ".txt")), None, Some("a/b"), None, Some("txt"));
1029         t!(s: Path::new(b!("a/b/c.", 0x80)), None, Some("a/b"), Some("c"), None);
1030         t!(s: Path::new(b!(0xff, "/b")), Some("b"), None, Some("b"), None);
1031     }
1032
1033     #[test]
1034     fn test_dir_path() {
1035         t!(v: Path::new(b!("hi/there", 0x80)).dir_path(), b!("hi"));
1036         t!(v: Path::new(b!("hi", 0xff, "/there")).dir_path(), b!("hi", 0xff));
1037         t!(s: Path::new("hi/there").dir_path(), "hi");
1038         t!(s: Path::new("hi").dir_path(), ".");
1039         t!(s: Path::new("/hi").dir_path(), "/");
1040         t!(s: Path::new("/").dir_path(), "/");
1041         t!(s: Path::new("..").dir_path(), "..");
1042         t!(s: Path::new("../..").dir_path(), "../..");
1043     }
1044
1045     #[test]
1046     fn test_is_absolute() {
1047         macro_rules! t(
1048             (s: $path:expr, $abs:expr, $rel:expr) => (
1049                 {
1050                     let path = Path::new($path);
1051                     assert_eq!(path.is_absolute(), $abs);
1052                     assert_eq!(path.is_relative(), $rel);
1053                 }
1054             )
1055         )
1056         t!(s: "a/b/c", false, true);
1057         t!(s: "/a/b/c", true, false);
1058         t!(s: "a", false, true);
1059         t!(s: "/a", true, false);
1060         t!(s: ".", false, true);
1061         t!(s: "/", true, false);
1062         t!(s: "..", false, true);
1063         t!(s: "../..", false, true);
1064     }
1065
1066     #[test]
1067     fn test_is_ancestor_of() {
1068         macro_rules! t(
1069             (s: $path:expr, $dest:expr, $exp:expr) => (
1070                 {
1071                     let path = Path::new($path);
1072                     let dest = Path::new($dest);
1073                     assert_eq!(path.is_ancestor_of(&dest), $exp);
1074                 }
1075             )
1076         )
1077
1078         t!(s: "a/b/c", "a/b/c/d", true);
1079         t!(s: "a/b/c", "a/b/c", true);
1080         t!(s: "a/b/c", "a/b", false);
1081         t!(s: "/a/b/c", "/a/b/c", true);
1082         t!(s: "/a/b", "/a/b/c", true);
1083         t!(s: "/a/b/c/d", "/a/b/c", false);
1084         t!(s: "/a/b", "a/b/c", false);
1085         t!(s: "a/b", "/a/b/c", false);
1086         t!(s: "a/b/c", "a/b/d", false);
1087         t!(s: "../a/b/c", "a/b/c", false);
1088         t!(s: "a/b/c", "../a/b/c", false);
1089         t!(s: "a/b/c", "a/b/cd", false);
1090         t!(s: "a/b/cd", "a/b/c", false);
1091         t!(s: "../a/b", "../a/b/c", true);
1092         t!(s: ".", "a/b", true);
1093         t!(s: ".", ".", true);
1094         t!(s: "/", "/", true);
1095         t!(s: "/", "/a/b", true);
1096         t!(s: "..", "a/b", true);
1097         t!(s: "../..", "a/b", true);
1098     }
1099
1100     #[test]
1101     fn test_ends_with_path() {
1102         macro_rules! t(
1103             (s: $path:expr, $child:expr, $exp:expr) => (
1104                 {
1105                     let path = Path::new($path);
1106                     let child = Path::new($child);
1107                     assert_eq!(path.ends_with_path(&child), $exp);
1108                 }
1109             );
1110             (v: $path:expr, $child:expr, $exp:expr) => (
1111                 {
1112                     let path = Path::new($path);
1113                     let child = Path::new($child);
1114                     assert_eq!(path.ends_with_path(&child), $exp);
1115                 }
1116             )
1117         )
1118
1119         t!(s: "a/b/c", "c", true);
1120         t!(s: "a/b/c", "d", false);
1121         t!(s: "foo/bar/quux", "bar", false);
1122         t!(s: "foo/bar/quux", "barquux", false);
1123         t!(s: "a/b/c", "b/c", true);
1124         t!(s: "a/b/c", "a/b/c", true);
1125         t!(s: "a/b/c", "foo/a/b/c", false);
1126         t!(s: "/a/b/c", "a/b/c", true);
1127         t!(s: "/a/b/c", "/a/b/c", false); // child must be relative
1128         t!(s: "/a/b/c", "foo/a/b/c", false);
1129         t!(s: "a/b/c", "", false);
1130         t!(s: "", "", true);
1131         t!(s: "/a/b/c", "d/e/f", false);
1132         t!(s: "a/b/c", "a/b", false);
1133         t!(s: "a/b/c", "b", false);
1134         t!(v: b!("a/b/c"), b!("b/c"), true);
1135         t!(v: b!("a/b/", 0xff), b!(0xff), true);
1136         t!(v: b!("a/b/", 0xff), b!("b/", 0xff), true);
1137     }
1138
1139     #[test]
1140     fn test_path_relative_from() {
1141         macro_rules! t(
1142             (s: $path:expr, $other:expr, $exp:expr) => (
1143                 {
1144                     let path = Path::new($path);
1145                     let other = Path::new($other);
1146                     let res = path.path_relative_from(&other);
1147                     assert_eq!(res.as_ref().and_then(|x| x.as_str()), $exp);
1148                 }
1149             )
1150         )
1151
1152         t!(s: "a/b/c", "a/b", Some("c"));
1153         t!(s: "a/b/c", "a/b/d", Some("../c"));
1154         t!(s: "a/b/c", "a/b/c/d", Some(".."));
1155         t!(s: "a/b/c", "a/b/c", Some("."));
1156         t!(s: "a/b/c", "a/b/c/d/e", Some("../.."));
1157         t!(s: "a/b/c", "a/d/e", Some("../../b/c"));
1158         t!(s: "a/b/c", "d/e/f", Some("../../../a/b/c"));
1159         t!(s: "a/b/c", "/a/b/c", None);
1160         t!(s: "/a/b/c", "a/b/c", Some("/a/b/c"));
1161         t!(s: "/a/b/c", "/a/b/c/d", Some(".."));
1162         t!(s: "/a/b/c", "/a/b", Some("c"));
1163         t!(s: "/a/b/c", "/a/b/c/d/e", Some("../.."));
1164         t!(s: "/a/b/c", "/a/d/e", Some("../../b/c"));
1165         t!(s: "/a/b/c", "/d/e/f", Some("../../../a/b/c"));
1166         t!(s: "hi/there.txt", "hi/there", Some("../there.txt"));
1167         t!(s: ".", "a", Some(".."));
1168         t!(s: ".", "a/b", Some("../.."));
1169         t!(s: ".", ".", Some("."));
1170         t!(s: "a", ".", Some("a"));
1171         t!(s: "a/b", ".", Some("a/b"));
1172         t!(s: "..", ".", Some(".."));
1173         t!(s: "a/b/c", "a/b/c", Some("."));
1174         t!(s: "/a/b/c", "/a/b/c", Some("."));
1175         t!(s: "/", "/", Some("."));
1176         t!(s: "/", ".", Some("/"));
1177         t!(s: "../../a", "b", Some("../../../a"));
1178         t!(s: "a", "../../b", None);
1179         t!(s: "../../a", "../../b", Some("../a"));
1180         t!(s: "../../a", "../../a/b", Some(".."));
1181         t!(s: "../../a/b", "../../a", Some("b"));
1182     }
1183
1184     #[test]
1185     fn test_components_iter() {
1186         macro_rules! t(
1187             (s: $path:expr, $exp:expr) => (
1188                 {
1189                     let path = Path::new($path);
1190                     let comps = path.components().collect::<Vec<&[u8]>>();
1191                     let exp: &[&str] = $exp;
1192                     let exps = exp.iter().map(|x| x.as_bytes()).collect::<Vec<&[u8]>>();
1193                     assert!(comps == exps, "components: Expected {:?}, found {:?}",
1194                             comps, exps);
1195                     let comps = path.rev_components().collect::<Vec<&[u8]>>();
1196                     let exps = exps.move_iter().rev().collect::<Vec<&[u8]>>();
1197                     assert!(comps == exps, "rev_components: Expected {:?}, found {:?}",
1198                             comps, exps);
1199                 }
1200             );
1201             (v: [$($arg:expr),+], [$([$($exp:expr),*]),*]) => (
1202                 {
1203                     let path = Path::new(b!($($arg),+));
1204                     let comps = path.components().collect::<Vec<&[u8]>>();
1205                     let exp: &[&[u8]] = [$(b!($($exp),*)),*];
1206                     assert_eq!(comps.as_slice(), exp);
1207                     let comps = path.rev_components().collect::<Vec<&[u8]>>();
1208                     let exp = exp.rev_iter().map(|&x|x).collect::<Vec<&[u8]>>();
1209                     assert_eq!(comps, exp)
1210                 }
1211             )
1212         )
1213
1214         t!(v: ["a/b/c"], [["a"], ["b"], ["c"]]);
1215         t!(v: ["/", 0xff, "/a/", 0x80], [[0xff], ["a"], [0x80]]);
1216         t!(v: ["../../foo", 0xcd, "bar"], [[".."], [".."], ["foo", 0xcd, "bar"]]);
1217         t!(s: "a/b/c", ["a", "b", "c"]);
1218         t!(s: "a/b/d", ["a", "b", "d"]);
1219         t!(s: "a/b/cd", ["a", "b", "cd"]);
1220         t!(s: "/a/b/c", ["a", "b", "c"]);
1221         t!(s: "a", ["a"]);
1222         t!(s: "/a", ["a"]);
1223         t!(s: "/", []);
1224         t!(s: ".", ["."]);
1225         t!(s: "..", [".."]);
1226         t!(s: "../..", ["..", ".."]);
1227         t!(s: "../../foo", ["..", "..", "foo"]);
1228     }
1229
1230     #[test]
1231     fn test_str_components() {
1232         macro_rules! t(
1233             (v: [$($arg:expr),+], $exp:expr) => (
1234                 {
1235                     let path = Path::new(b!($($arg),+));
1236                     let comps = path.str_components().collect::<Vec<Option<&str>>>();
1237                     let exp: &[Option<&str>] = $exp;
1238                     assert_eq!(comps.as_slice(), exp);
1239                     let comps = path.rev_str_components().collect::<Vec<Option<&str>>>();
1240                     let exp = exp.rev_iter().map(|&x|x).collect::<Vec<Option<&str>>>();
1241                     assert_eq!(comps, exp);
1242                 }
1243             )
1244         )
1245
1246         t!(v: ["a/b/c"], [Some("a"), Some("b"), Some("c")]);
1247         t!(v: ["/", 0xff, "/a/", 0x80], [None, Some("a"), None]);
1248         t!(v: ["../../foo", 0xcd, "bar"], [Some(".."), Some(".."), None]);
1249         // str_components is a wrapper around components, so no need to do
1250         // the full set of tests
1251     }
1252 }
1253
1254 #[cfg(test)]
1255 mod bench {
1256     extern crate test;
1257     use self::test::Bencher;
1258     use super::*;
1259     use prelude::*;
1260
1261     #[bench]
1262     fn join_home_dir(b: &mut Bencher) {
1263         let posix_path = Path::new("/");
1264         b.iter(|| {
1265             posix_path.join("home");
1266         });
1267     }
1268
1269     #[bench]
1270     fn join_abs_path_home_dir(b: &mut Bencher) {
1271         let posix_path = Path::new("/");
1272         b.iter(|| {
1273             posix_path.join("/home");
1274         });
1275     }
1276
1277     #[bench]
1278     fn join_many_home_dir(b: &mut Bencher) {
1279         let posix_path = Path::new("/");
1280         b.iter(|| {
1281             posix_path.join_many(&["home"]);
1282         });
1283     }
1284
1285     #[bench]
1286     fn join_many_abs_path_home_dir(b: &mut Bencher) {
1287         let posix_path = Path::new("/");
1288         b.iter(|| {
1289             posix_path.join_many(&["/home"]);
1290         });
1291     }
1292
1293     #[bench]
1294     fn push_home_dir(b: &mut Bencher) {
1295         let mut posix_path = Path::new("/");
1296         b.iter(|| {
1297             posix_path.push("home");
1298         });
1299     }
1300
1301     #[bench]
1302     fn push_abs_path_home_dir(b: &mut Bencher) {
1303         let mut posix_path = Path::new("/");
1304         b.iter(|| {
1305             posix_path.push("/home");
1306         });
1307     }
1308
1309     #[bench]
1310     fn push_many_home_dir(b: &mut Bencher) {
1311         let mut posix_path = Path::new("/");
1312         b.iter(|| {
1313             posix_path.push_many(&["home"]);
1314         });
1315     }
1316
1317     #[bench]
1318     fn push_many_abs_path_home_dir(b: &mut Bencher) {
1319         let mut posix_path = Path::new("/");
1320         b.iter(|| {
1321             posix_path.push_many(&["/home"]);
1322         });
1323     }
1324
1325     #[bench]
1326     fn ends_with_path_home_dir(b: &mut Bencher) {
1327         let posix_home_path = Path::new("/home");
1328         b.iter(|| {
1329             posix_home_path.ends_with_path(&Path::new("home"));
1330         });
1331     }
1332
1333     #[bench]
1334     fn ends_with_path_missmatch_jome_home(b: &mut Bencher) {
1335         let posix_home_path = Path::new("/home");
1336         b.iter(|| {
1337             posix_home_path.ends_with_path(&Path::new("jome"));
1338         });
1339     }
1340
1341     #[bench]
1342     fn is_ancestor_of_path_with_10_dirs(b: &mut Bencher) {
1343         let path = Path::new("/home/1/2/3/4/5/6/7/8/9");
1344         let mut sub = path.clone();
1345         sub.pop();
1346         b.iter(|| {
1347             path.is_ancestor_of(&sub);
1348         });
1349     }
1350
1351     #[bench]
1352     fn path_relative_from_forward(b: &mut Bencher) {
1353         let path = Path::new("/a/b/c");
1354         let mut other = path.clone();
1355         other.pop();
1356         b.iter(|| {
1357             path.path_relative_from(&other);
1358         });
1359     }
1360
1361     #[bench]
1362     fn path_relative_from_same_level(b: &mut Bencher) {
1363         let path = Path::new("/a/b/c");
1364         let mut other = path.clone();
1365         other.pop();
1366         other.push("d");
1367         b.iter(|| {
1368             path.path_relative_from(&other);
1369         });
1370     }
1371
1372     #[bench]
1373     fn path_relative_from_backward(b: &mut Bencher) {
1374         let path = Path::new("/a/b");
1375         let mut other = path.clone();
1376         other.push("c");
1377         b.iter(|| {
1378             path.path_relative_from(&other);
1379         });
1380     }
1381 }