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