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