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