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