about summary refs log tree commit diff
path: root/library/std/src/path
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2021-08-22 05:19:48 +0000
committerbors <bors@rust-lang.org>2021-08-22 05:19:48 +0000
commit2ad56d5c9031636c1509f4417e88099a49405b4e (patch)
tree365f66542bcc32a01533bd522669f0dd0dc2b87a /library/std/src/path
parent50731df24e584e8ebc0097497169b431c005bf86 (diff)
parent51cf318dbcdd38d6a7478413513a72097d9622c3 (diff)
downloadrust-2ad56d5c9031636c1509f4417e88099a49405b4e.tar.gz
rust-2ad56d5c9031636c1509f4417e88099a49405b4e.zip
Auto merge of #85166 - mbhall88:file-prefix, r=dtolnay
add file_prefix method to std::path

This is an initial implementation of `std::path::Path::file_prefix`. It is effectively a "left" variant of the existing [`file_stem`](https://doc.rust-lang.org/std/path/struct.Path.html#method.file_stem) method. An illustration of the difference is

```rust
use std::path::Path;

let path = Path::new("foo.tar.gz");
assert_eq!(path.file_stem(), Some("foo.tar"));
assert_eq!(path.file_prefix(), Some("foo"));
```

In my own development, I generally find I almost always want the prefix, rather than the stem, so I thought it might be best to suggest it's addition to libstd.

Of course, as this is my first contribution, I expect there is probably more work that needs to be done. Additionally, if the libstd team feel this isn't appropriate then so be it.

There has been some [discussion about this on Zulip](https://rust-lang.zulipchat.com/#narrow/stream/219381-t-libs/topic/file_lstem/near/238076313) and a user there suggested I open a PR to see whether someone in the libstd team thinks it is worth pursuing.
Diffstat (limited to 'library/std/src/path')
-rw-r--r--library/std/src/path/tests.rs397
1 files changed, 310 insertions, 87 deletions
diff --git a/library/std/src/path/tests.rs b/library/std/src/path/tests.rs
index c10ded08f2c..ce23cf6cd21 100644
--- a/library/std/src/path/tests.rs
+++ b/library/std/src/path/tests.rs
@@ -5,7 +5,7 @@ use crate::rc::Rc;
 use crate::sync::Arc;
 use core::hint::black_box;
 
-macro_rules! t(
+macro_rules! t (
     ($path:expr, iter: $iter:expr) => (
         {
             let path = Path::new($path);
@@ -75,15 +75,33 @@ macro_rules! t(
         }
     );
 
+    ($path:expr, file_prefix: $file_prefix:expr, extension: $extension:expr) => (
+        {
+            let path = Path::new($path);
+
+            let prefix = path.file_prefix().map(|p| p.to_str().unwrap());
+            let exp_prefix: Option<&str> = $file_prefix;
+            assert!(prefix == exp_prefix, "file_prefix: Expected {:?}, found {:?}",
+                    exp_prefix, prefix);
+
+            let ext = path.extension().map(|p| p.to_str().unwrap());
+            let exp_ext: Option<&str> = $extension;
+            assert!(ext == exp_ext, "extension: Expected {:?}, found {:?}",
+                    exp_ext, ext);
+        }
+    );
+
     ($path:expr, iter: $iter:expr,
                  has_root: $has_root:expr, is_absolute: $is_absolute:expr,
                  parent: $parent:expr, file_name: $file:expr,
-                 file_stem: $file_stem:expr, extension: $extension:expr) => (
+                 file_stem: $file_stem:expr, extension: $extension:expr,
+                 file_prefix: $file_prefix:expr) => (
         {
             t!($path, iter: $iter);
             t!($path, has_root: $has_root, is_absolute: $is_absolute);
             t!($path, parent: $parent, file_name: $file);
             t!($path, file_stem: $file_stem, extension: $extension);
+            t!($path, file_prefix: $file_prefix, extension: $extension);
         }
     );
 );
@@ -118,7 +136,8 @@ pub fn test_decompositions_unix() {
     parent: None,
     file_name: None,
     file_stem: None,
-    extension: None
+    extension: None,
+    file_prefix: None
     );
 
     t!("foo",
@@ -128,7 +147,8 @@ pub fn test_decompositions_unix() {
     parent: Some(""),
     file_name: Some("foo"),
     file_stem: Some("foo"),
-    extension: None
+    extension: None,
+    file_prefix: Some("foo")
     );
 
     t!("/",
@@ -138,7 +158,8 @@ pub fn test_decompositions_unix() {
     parent: None,
     file_name: None,
     file_stem: None,
-    extension: None
+    extension: None,
+    file_prefix: None
     );
 
     t!("/foo",
@@ -148,7 +169,8 @@ pub fn test_decompositions_unix() {
     parent: Some("/"),
     file_name: Some("foo"),
     file_stem: Some("foo"),
-    extension: None
+    extension: None,
+    file_prefix: Some("foo")
     );
 
     t!("foo/",
@@ -158,7 +180,8 @@ pub fn test_decompositions_unix() {
     parent: Some(""),
     file_name: Some("foo"),
     file_stem: Some("foo"),
-    extension: None
+    extension: None,
+    file_prefix: Some("foo")
     );
 
     t!("/foo/",
@@ -168,7 +191,8 @@ pub fn test_decompositions_unix() {
     parent: Some("/"),
     file_name: Some("foo"),
     file_stem: Some("foo"),
-    extension: None
+    extension: None,
+    file_prefix: Some("foo")
     );
 
     t!("foo/bar",
@@ -178,7 +202,8 @@ pub fn test_decompositions_unix() {
     parent: Some("foo"),
     file_name: Some("bar"),
     file_stem: Some("bar"),
-    extension: None
+    extension: None,
+    file_prefix: Some("bar")
     );
 
     t!("/foo/bar",
@@ -188,7 +213,8 @@ pub fn test_decompositions_unix() {
     parent: Some("/foo"),
     file_name: Some("bar"),
     file_stem: Some("bar"),
-    extension: None
+    extension: None,
+    file_prefix: Some("bar")
     );
 
     t!("///foo///",
@@ -198,7 +224,8 @@ pub fn test_decompositions_unix() {
     parent: Some("/"),
     file_name: Some("foo"),
     file_stem: Some("foo"),
-    extension: None
+    extension: None,
+    file_prefix: Some("foo")
     );
 
     t!("///foo///bar",
@@ -208,7 +235,8 @@ pub fn test_decompositions_unix() {
     parent: Some("///foo"),
     file_name: Some("bar"),
     file_stem: Some("bar"),
-    extension: None
+    extension: None,
+    file_prefix: Some("bar")
     );
 
     t!("./.",
@@ -218,7 +246,8 @@ pub fn test_decompositions_unix() {
     parent: Some(""),
     file_name: None,
     file_stem: None,
-    extension: None
+    extension: None,
+    file_prefix: None
     );
 
     t!("/..",
@@ -228,7 +257,8 @@ pub fn test_decompositions_unix() {
     parent: Some("/"),
     file_name: None,
     file_stem: None,
-    extension: None
+    extension: None,
+    file_prefix: None
     );
 
     t!("../",
@@ -238,7 +268,8 @@ pub fn test_decompositions_unix() {
     parent: Some(""),
     file_name: None,
     file_stem: None,
-    extension: None
+    extension: None,
+    file_prefix: None
     );
 
     t!("foo/.",
@@ -248,7 +279,8 @@ pub fn test_decompositions_unix() {
     parent: Some(""),
     file_name: Some("foo"),
     file_stem: Some("foo"),
-    extension: None
+    extension: None,
+    file_prefix: Some("foo")
     );
 
     t!("foo/..",
@@ -258,7 +290,8 @@ pub fn test_decompositions_unix() {
     parent: Some("foo"),
     file_name: None,
     file_stem: None,
-    extension: None
+    extension: None,
+    file_prefix: None
     );
 
     t!("foo/./",
@@ -268,7 +301,8 @@ pub fn test_decompositions_unix() {
     parent: Some(""),
     file_name: Some("foo"),
     file_stem: Some("foo"),
-    extension: None
+    extension: None,
+    file_prefix: Some("foo")
     );
 
     t!("foo/./bar",
@@ -278,7 +312,8 @@ pub fn test_decompositions_unix() {
     parent: Some("foo"),
     file_name: Some("bar"),
     file_stem: Some("bar"),
-    extension: None
+    extension: None,
+    file_prefix: Some("bar")
     );
 
     t!("foo/../",
@@ -288,7 +323,8 @@ pub fn test_decompositions_unix() {
     parent: Some("foo"),
     file_name: None,
     file_stem: None,
-    extension: None
+    extension: None,
+    file_prefix: None
     );
 
     t!("foo/../bar",
@@ -298,7 +334,8 @@ pub fn test_decompositions_unix() {
     parent: Some("foo/.."),
     file_name: Some("bar"),
     file_stem: Some("bar"),
-    extension: None
+    extension: None,
+    file_prefix: Some("bar")
     );
 
     t!("./a",
@@ -308,7 +345,8 @@ pub fn test_decompositions_unix() {
     parent: Some("."),
     file_name: Some("a"),
     file_stem: Some("a"),
-    extension: None
+    extension: None,
+    file_prefix: Some("a")
     );
 
     t!(".",
@@ -318,7 +356,8 @@ pub fn test_decompositions_unix() {
     parent: Some(""),
     file_name: None,
     file_stem: None,
-    extension: None
+    extension: None,
+    file_prefix: None
     );
 
     t!("./",
@@ -328,7 +367,8 @@ pub fn test_decompositions_unix() {
     parent: Some(""),
     file_name: None,
     file_stem: None,
-    extension: None
+    extension: None,
+    file_prefix: None
     );
 
     t!("a/b",
@@ -338,7 +378,8 @@ pub fn test_decompositions_unix() {
     parent: Some("a"),
     file_name: Some("b"),
     file_stem: Some("b"),
-    extension: None
+    extension: None,
+    file_prefix: Some("b")
     );
 
     t!("a//b",
@@ -348,7 +389,8 @@ pub fn test_decompositions_unix() {
     parent: Some("a"),
     file_name: Some("b"),
     file_stem: Some("b"),
-    extension: None
+    extension: None,
+    file_prefix: Some("b")
     );
 
     t!("a/./b",
@@ -358,7 +400,8 @@ pub fn test_decompositions_unix() {
     parent: Some("a"),
     file_name: Some("b"),
     file_stem: Some("b"),
-    extension: None
+    extension: None,
+    file_prefix: Some("b")
     );
 
     t!("a/b/c",
@@ -368,7 +411,8 @@ pub fn test_decompositions_unix() {
     parent: Some("a/b"),
     file_name: Some("c"),
     file_stem: Some("c"),
-    extension: None
+    extension: None,
+    file_prefix: Some("c")
     );
 
     t!(".foo",
@@ -378,7 +422,41 @@ pub fn test_decompositions_unix() {
     parent: Some(""),
     file_name: Some(".foo"),
     file_stem: Some(".foo"),
-    extension: None
+    extension: None,
+    file_prefix: Some(".foo")
+    );
+
+    t!("a/.foo",
+    iter: ["a", ".foo"],
+    has_root: false,
+    is_absolute: false,
+    parent: Some("a"),
+    file_name: Some(".foo"),
+    file_stem: Some(".foo"),
+    extension: None,
+    file_prefix: Some(".foo")
+    );
+
+    t!("a/.rustfmt.toml",
+    iter: ["a", ".rustfmt.toml"],
+    has_root: false,
+    is_absolute: false,
+    parent: Some("a"),
+    file_name: Some(".rustfmt.toml"),
+    file_stem: Some(".rustfmt"),
+    extension: Some("toml"),
+    file_prefix: Some(".rustfmt")
+    );
+
+    t!("a/.x.y.z",
+    iter: ["a", ".x.y.z"],
+    has_root: false,
+    is_absolute: false,
+    parent: Some("a"),
+    file_name: Some(".x.y.z"),
+    file_stem: Some(".x.y"),
+    extension: Some("z"),
+    file_prefix: Some(".x")
     );
 }
 
@@ -392,7 +470,8 @@ pub fn test_decompositions_windows() {
     parent: None,
     file_name: None,
     file_stem: None,
-    extension: None
+    extension: None,
+    file_prefix: None
     );
 
     t!("foo",
@@ -402,7 +481,8 @@ pub fn test_decompositions_windows() {
     parent: Some(""),
     file_name: Some("foo"),
     file_stem: Some("foo"),
-    extension: None
+    extension: None,
+    file_prefix: Some("foo")
     );
 
     t!("/",
@@ -412,7 +492,8 @@ pub fn test_decompositions_windows() {
     parent: None,
     file_name: None,
     file_stem: None,
-    extension: None
+    extension: None,
+    file_prefix: None
     );
 
     t!("\\",
@@ -422,7 +503,8 @@ pub fn test_decompositions_windows() {
     parent: None,
     file_name: None,
     file_stem: None,
-    extension: None
+    extension: None,
+    file_prefix: None
     );
 
     t!("c:",
@@ -432,7 +514,8 @@ pub fn test_decompositions_windows() {
     parent: None,
     file_name: None,
     file_stem: None,
-    extension: None
+    extension: None,
+    file_prefix: None
     );
 
     t!("c:\\",
@@ -442,7 +525,8 @@ pub fn test_decompositions_windows() {
     parent: None,
     file_name: None,
     file_stem: None,
-    extension: None
+    extension: None,
+    file_prefix: None
     );
 
     t!("c:/",
@@ -452,7 +536,8 @@ pub fn test_decompositions_windows() {
     parent: None,
     file_name: None,
     file_stem: None,
-    extension: None
+    extension: None,
+    file_prefix: None
     );
 
     t!("/foo",
@@ -462,7 +547,8 @@ pub fn test_decompositions_windows() {
     parent: Some("/"),
     file_name: Some("foo"),
     file_stem: Some("foo"),
-    extension: None
+    extension: None,
+    file_prefix: Some("foo")
     );
 
     t!("foo/",
@@ -472,7 +558,8 @@ pub fn test_decompositions_windows() {
     parent: Some(""),
     file_name: Some("foo"),
     file_stem: Some("foo"),
-    extension: None
+    extension: None,
+    file_prefix: Some("foo")
     );
 
     t!("/foo/",
@@ -482,7 +569,8 @@ pub fn test_decompositions_windows() {
     parent: Some("/"),
     file_name: Some("foo"),
     file_stem: Some("foo"),
-    extension: None
+    extension: None,
+    file_prefix: Some("foo")
     );
 
     t!("foo/bar",
@@ -492,7 +580,8 @@ pub fn test_decompositions_windows() {
     parent: Some("foo"),
     file_name: Some("bar"),
     file_stem: Some("bar"),
-    extension: None
+    extension: None,
+    file_prefix: Some("bar")
     );
 
     t!("/foo/bar",
@@ -502,7 +591,8 @@ pub fn test_decompositions_windows() {
     parent: Some("/foo"),
     file_name: Some("bar"),
     file_stem: Some("bar"),
-    extension: None
+    extension: None,
+    file_prefix: Some("bar")
     );
 
     t!("///foo///",
@@ -512,7 +602,8 @@ pub fn test_decompositions_windows() {
     parent: Some("/"),
     file_name: Some("foo"),
     file_stem: Some("foo"),
-    extension: None
+    extension: None,
+    file_prefix: Some("foo")
     );
 
     t!("///foo///bar",
@@ -522,7 +613,8 @@ pub fn test_decompositions_windows() {
     parent: Some("///foo"),
     file_name: Some("bar"),
     file_stem: Some("bar"),
-    extension: None
+    extension: None,
+    file_prefix: Some("bar")
     );
 
     t!("./.",
@@ -532,7 +624,8 @@ pub fn test_decompositions_windows() {
     parent: Some(""),
     file_name: None,
     file_stem: None,
-    extension: None
+    extension: None,
+    file_prefix: None
     );
 
     t!("/..",
@@ -542,7 +635,8 @@ pub fn test_decompositions_windows() {
     parent: Some("/"),
     file_name: None,
     file_stem: None,
-    extension: None
+    extension: None,
+    file_prefix: None
     );
 
     t!("../",
@@ -552,7 +646,8 @@ pub fn test_decompositions_windows() {
     parent: Some(""),
     file_name: None,
     file_stem: None,
-    extension: None
+    extension: None,
+    file_prefix: None
     );
 
     t!("foo/.",
@@ -562,7 +657,8 @@ pub fn test_decompositions_windows() {
     parent: Some(""),
     file_name: Some("foo"),
     file_stem: Some("foo"),
-    extension: None
+    extension: None,
+    file_prefix: Some("foo")
     );
 
     t!("foo/..",
@@ -572,7 +668,8 @@ pub fn test_decompositions_windows() {
     parent: Some("foo"),
     file_name: None,
     file_stem: None,
-    extension: None
+    extension: None,
+    file_prefix: None
     );
 
     t!("foo/./",
@@ -582,7 +679,8 @@ pub fn test_decompositions_windows() {
     parent: Some(""),
     file_name: Some("foo"),
     file_stem: Some("foo"),
-    extension: None
+    extension: None,
+    file_prefix: Some("foo")
     );
 
     t!("foo/./bar",
@@ -592,7 +690,8 @@ pub fn test_decompositions_windows() {
     parent: Some("foo"),
     file_name: Some("bar"),
     file_stem: Some("bar"),
-    extension: None
+    extension: None,
+    file_prefix: Some("bar")
     );
 
     t!("foo/../",
@@ -602,7 +701,8 @@ pub fn test_decompositions_windows() {
     parent: Some("foo"),
     file_name: None,
     file_stem: None,
-    extension: None
+    extension: None,
+    file_prefix: None
     );
 
     t!("foo/../bar",
@@ -612,7 +712,8 @@ pub fn test_decompositions_windows() {
     parent: Some("foo/.."),
     file_name: Some("bar"),
     file_stem: Some("bar"),
-    extension: None
+    extension: None,
+    file_prefix: Some("bar")
     );
 
     t!("./a",
@@ -622,7 +723,8 @@ pub fn test_decompositions_windows() {
     parent: Some("."),
     file_name: Some("a"),
     file_stem: Some("a"),
-    extension: None
+    extension: None,
+    file_prefix: Some("a")
     );
 
     t!(".",
@@ -632,7 +734,8 @@ pub fn test_decompositions_windows() {
     parent: Some(""),
     file_name: None,
     file_stem: None,
-    extension: None
+    extension: None,
+    file_prefix: None
     );
 
     t!("./",
@@ -642,7 +745,8 @@ pub fn test_decompositions_windows() {
     parent: Some(""),
     file_name: None,
     file_stem: None,
-    extension: None
+    extension: None,
+    file_prefix: None
     );
 
     t!("a/b",
@@ -652,7 +756,8 @@ pub fn test_decompositions_windows() {
     parent: Some("a"),
     file_name: Some("b"),
     file_stem: Some("b"),
-    extension: None
+    extension: None,
+    file_prefix: Some("b")
     );
 
     t!("a//b",
@@ -662,7 +767,8 @@ pub fn test_decompositions_windows() {
     parent: Some("a"),
     file_name: Some("b"),
     file_stem: Some("b"),
-    extension: None
+    extension: None,
+    file_prefix: Some("b")
     );
 
     t!("a/./b",
@@ -672,7 +778,8 @@ pub fn test_decompositions_windows() {
     parent: Some("a"),
     file_name: Some("b"),
     file_stem: Some("b"),
-    extension: None
+    extension: None,
+    file_prefix: Some("b")
     );
 
     t!("a/b/c",
@@ -682,7 +789,9 @@ pub fn test_decompositions_windows() {
        parent: Some("a/b"),
        file_name: Some("c"),
        file_stem: Some("c"),
-       extension: None);
+       extension: None,
+       file_prefix: Some("c")
+    );
 
     t!("a\\b\\c",
     iter: ["a", "b", "c"],
@@ -691,7 +800,8 @@ pub fn test_decompositions_windows() {
     parent: Some("a\\b"),
     file_name: Some("c"),
     file_stem: Some("c"),
-    extension: None
+    extension: None,
+    file_prefix: Some("c")
     );
 
     t!("\\a",
@@ -701,7 +811,8 @@ pub fn test_decompositions_windows() {
     parent: Some("\\"),
     file_name: Some("a"),
     file_stem: Some("a"),
-    extension: None
+    extension: None,
+    file_prefix: Some("a")
     );
 
     t!("c:\\foo.txt",
@@ -711,7 +822,8 @@ pub fn test_decompositions_windows() {
     parent: Some("c:\\"),
     file_name: Some("foo.txt"),
     file_stem: Some("foo"),
-    extension: Some("txt")
+    extension: Some("txt"),
+    file_prefix: Some("foo")
     );
 
     t!("\\\\server\\share\\foo.txt",
@@ -721,7 +833,8 @@ pub fn test_decompositions_windows() {
     parent: Some("\\\\server\\share\\"),
     file_name: Some("foo.txt"),
     file_stem: Some("foo"),
-    extension: Some("txt")
+    extension: Some("txt"),
+    file_prefix: Some("foo")
     );
 
     t!("\\\\server\\share",
@@ -731,7 +844,8 @@ pub fn test_decompositions_windows() {
     parent: None,
     file_name: None,
     file_stem: None,
-    extension: None
+    extension: None,
+    file_prefix: None
     );
 
     t!("\\\\server",
@@ -741,7 +855,8 @@ pub fn test_decompositions_windows() {
     parent: Some("\\"),
     file_name: Some("server"),
     file_stem: Some("server"),
-    extension: None
+    extension: None,
+    file_prefix: Some("server")
     );
 
     t!("\\\\?\\bar\\foo.txt",
@@ -751,7 +866,8 @@ pub fn test_decompositions_windows() {
     parent: Some("\\\\?\\bar\\"),
     file_name: Some("foo.txt"),
     file_stem: Some("foo"),
-    extension: Some("txt")
+    extension: Some("txt"),
+    file_prefix: Some("foo")
     );
 
     t!("\\\\?\\bar",
@@ -761,7 +877,8 @@ pub fn test_decompositions_windows() {
     parent: None,
     file_name: None,
     file_stem: None,
-    extension: None
+    extension: None,
+    file_prefix: None
     );
 
     t!("\\\\?\\",
@@ -771,7 +888,8 @@ pub fn test_decompositions_windows() {
     parent: None,
     file_name: None,
     file_stem: None,
-    extension: None
+    extension: None,
+    file_prefix: None
     );
 
     t!("\\\\?\\UNC\\server\\share\\foo.txt",
@@ -781,7 +899,8 @@ pub fn test_decompositions_windows() {
     parent: Some("\\\\?\\UNC\\server\\share\\"),
     file_name: Some("foo.txt"),
     file_stem: Some("foo"),
-    extension: Some("txt")
+    extension: Some("txt"),
+    file_prefix: Some("foo")
     );
 
     t!("\\\\?\\UNC\\server",
@@ -791,7 +910,8 @@ pub fn test_decompositions_windows() {
     parent: None,
     file_name: None,
     file_stem: None,
-    extension: None
+    extension: None,
+    file_prefix: None
     );
 
     t!("\\\\?\\UNC\\",
@@ -801,7 +921,8 @@ pub fn test_decompositions_windows() {
     parent: None,
     file_name: None,
     file_stem: None,
-    extension: None
+    extension: None,
+    file_prefix: None
     );
 
     t!("\\\\?\\C:\\foo.txt",
@@ -811,7 +932,8 @@ pub fn test_decompositions_windows() {
     parent: Some("\\\\?\\C:\\"),
     file_name: Some("foo.txt"),
     file_stem: Some("foo"),
-    extension: Some("txt")
+    extension: Some("txt"),
+    file_prefix: Some("foo")
     );
 
     t!("\\\\?\\C:\\",
@@ -821,7 +943,8 @@ pub fn test_decompositions_windows() {
     parent: None,
     file_name: None,
     file_stem: None,
-    extension: None
+    extension: None,
+    file_prefix: None
     );
 
     t!("\\\\?\\C:",
@@ -831,7 +954,8 @@ pub fn test_decompositions_windows() {
     parent: None,
     file_name: None,
     file_stem: None,
-    extension: None
+    extension: None,
+    file_prefix: None
     );
 
     t!("\\\\?\\foo/bar",
@@ -841,7 +965,8 @@ pub fn test_decompositions_windows() {
     parent: None,
     file_name: None,
     file_stem: None,
-    extension: None
+    extension: None,
+    file_prefix: None
     );
 
     t!("\\\\?\\C:/foo",
@@ -851,7 +976,8 @@ pub fn test_decompositions_windows() {
     parent: None,
     file_name: None,
     file_stem: None,
-    extension: None
+    extension: None,
+    file_prefix: None
     );
 
     t!("\\\\.\\foo\\bar",
@@ -861,7 +987,8 @@ pub fn test_decompositions_windows() {
     parent: Some("\\\\.\\foo\\"),
     file_name: Some("bar"),
     file_stem: Some("bar"),
-    extension: None
+    extension: None,
+    file_prefix: Some("bar")
     );
 
     t!("\\\\.\\foo",
@@ -871,7 +998,8 @@ pub fn test_decompositions_windows() {
     parent: None,
     file_name: None,
     file_stem: None,
-    extension: None
+    extension: None,
+    file_prefix: None
     );
 
     t!("\\\\.\\foo/bar",
@@ -881,7 +1009,8 @@ pub fn test_decompositions_windows() {
     parent: Some("\\\\.\\foo/"),
     file_name: Some("bar"),
     file_stem: Some("bar"),
-    extension: None
+    extension: None,
+    file_prefix: Some("bar")
     );
 
     t!("\\\\.\\foo\\bar/baz",
@@ -891,7 +1020,8 @@ pub fn test_decompositions_windows() {
     parent: Some("\\\\.\\foo\\bar"),
     file_name: Some("baz"),
     file_stem: Some("baz"),
-    extension: None
+    extension: None,
+    file_prefix: Some("baz")
     );
 
     t!("\\\\.\\",
@@ -901,7 +1031,8 @@ pub fn test_decompositions_windows() {
     parent: None,
     file_name: None,
     file_stem: None,
-    extension: None
+    extension: None,
+    file_prefix: None
     );
 
     t!("\\\\?\\a\\b\\",
@@ -911,7 +1042,52 @@ pub fn test_decompositions_windows() {
     parent: Some("\\\\?\\a\\"),
     file_name: Some("b"),
     file_stem: Some("b"),
-    extension: None
+    extension: None,
+    file_prefix: Some("b")
+    );
+
+    t!("\\\\?\\C:\\foo.txt.zip",
+    iter: ["\\\\?\\C:", "\\", "foo.txt.zip"],
+    has_root: true,
+    is_absolute: true,
+    parent: Some("\\\\?\\C:\\"),
+    file_name: Some("foo.txt.zip"),
+    file_stem: Some("foo.txt"),
+    extension: Some("zip"),
+    file_prefix: Some("foo")
+    );
+
+    t!("\\\\?\\C:\\.foo.txt.zip",
+    iter: ["\\\\?\\C:", "\\", ".foo.txt.zip"],
+    has_root: true,
+    is_absolute: true,
+    parent: Some("\\\\?\\C:\\"),
+    file_name: Some(".foo.txt.zip"),
+    file_stem: Some(".foo.txt"),
+    extension: Some("zip"),
+    file_prefix: Some(".foo")
+    );
+
+    t!("\\\\?\\C:\\.foo",
+    iter: ["\\\\?\\C:", "\\", ".foo"],
+    has_root: true,
+    is_absolute: true,
+    parent: Some("\\\\?\\C:\\"),
+    file_name: Some(".foo"),
+    file_stem: Some(".foo"),
+    extension: None,
+    file_prefix: Some(".foo")
+    );
+
+    t!("a/.x.y.z",
+    iter: ["a", ".x.y.z"],
+    has_root: false,
+    is_absolute: false,
+    parent: Some("a"),
+    file_name: Some(".x.y.z"),
+    file_stem: Some(".x.y"),
+    extension: Some("z"),
+    file_prefix: Some(".x")
     );
 }
 
@@ -951,12 +1127,59 @@ pub fn test_stem_ext() {
 
     t!("..", file_stem: None, extension: None);
 
+    t!(".x.y.z", file_stem: Some(".x.y"), extension: Some("z"));
+
+    t!("..x.y.z", file_stem: Some("..x.y"), extension: Some("z"));
+
     t!("", file_stem: None, extension: None);
 }
 
 #[test]
+pub fn test_prefix_ext() {
+    t!("foo",
+    file_prefix: Some("foo"),
+    extension: None
+    );
+
+    t!("foo.",
+    file_prefix: Some("foo"),
+    extension: Some("")
+    );
+
+    t!(".foo",
+    file_prefix: Some(".foo"),
+    extension: None
+    );
+
+    t!("foo.txt",
+    file_prefix: Some("foo"),
+    extension: Some("txt")
+    );
+
+    t!("foo.bar.txt",
+    file_prefix: Some("foo"),
+    extension: Some("txt")
+    );
+
+    t!("foo.bar.",
+    file_prefix: Some("foo"),
+    extension: Some("")
+    );
+
+    t!(".", file_prefix: None, extension: None);
+
+    t!("..", file_prefix: None, extension: None);
+
+    t!(".x.y.z", file_prefix: Some(".x"), extension: Some("z"));
+
+    t!("..x.y.z", file_prefix: Some("."), extension: Some("z"));
+
+    t!("", file_prefix: None, extension: None);
+}
+
+#[test]
 pub fn test_push() {
-    macro_rules! tp(
+    macro_rules! tp (
         ($path:expr, $push:expr, $expected:expr) => ( {
             let mut actual = PathBuf::from($path);
             actual.push($push);
@@ -1044,7 +1267,7 @@ pub fn test_push() {
 
 #[test]
 pub fn test_pop() {
-    macro_rules! tp(
+    macro_rules! tp (
         ($path:expr, $expected:expr, $output:expr) => ( {
             let mut actual = PathBuf::from($path);
             let output = actual.pop();
@@ -1098,7 +1321,7 @@ pub fn test_pop() {
 
 #[test]
 pub fn test_set_file_name() {
-    macro_rules! tfn(
+    macro_rules! tfn (
             ($path:expr, $file:expr, $expected:expr) => ( {
             let mut p = PathBuf::from($path);
             p.set_file_name($file);
@@ -1132,7 +1355,7 @@ pub fn test_set_file_name() {
 
 #[test]
 pub fn test_set_extension() {
-    macro_rules! tfe(
+    macro_rules! tfe (
             ($path:expr, $ext:expr, $expected:expr, $output:expr) => ( {
             let mut p = PathBuf::from($path);
             let output = p.set_extension($ext);
@@ -1194,7 +1417,7 @@ pub fn test_compare() {
         s.finish()
     }
 
-    macro_rules! tc(
+    macro_rules! tc (
         ($path1:expr, $path2:expr, eq: $eq:expr,
          starts_with: $starts_with:expr, ends_with: $ends_with:expr,
          relative_from: $relative_from:expr) => ({