From 5c5bee371d847e994f2453ee0e50e284b88729a8 Mon Sep 17 00:00:00 2001 From: Mark LeMoine Date: Sat, 11 Nov 2017 01:29:40 -0800 Subject: [PATCH 01/10] Added normalize, and working on tests --- src/libstd/path.rs | 147 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 147 insertions(+) diff --git a/src/libstd/path.rs b/src/libstd/path.rs index 270878dc029c3..93603c718b37b 100644 --- a/src/libstd/path.rs +++ b/src/libstd/path.rs @@ -2174,6 +2174,90 @@ impl Path { fs::canonicalize(self) } + /// Returns the normalized (or "cleaned") form of the path with all current + /// dir (.) and parent dir (..) references resolved. + /// + /// This is a purely logical calculation; the file system is not used. Namely, + /// this leaves symlinks intact and does not check to see if the target exists. + /// + /// This may change the meaning of a path involving symlinks and parent dir + /// references. + /// + /// # Examples + /// + /// ```no_run + /// use std::path::{Path, PathBuf}; + /// + /// let path = Path::new("/recipes/./snacks/../desserts/banana_creme_pie.txt"); + /// assert_eq!(path.normalize(), PathBuf::from("/recipes/desserts/banana_creme_pie.txt")); + /// let path = Path::new("../.././lots///of////./separators/"); + /// assert_eq!(path.normalize(), PathBuf::from("../../lots/of/separators")); + /// let path = Path::new("/../../../cannot_go_above_root"); + /// assert_eq!(path.normalize(), PathBuf::from("/cannot_go_above_root")); + /// ``` + #[stable(feature = "path_ext", since = "1.24.0")] + pub fn normalize(&self) -> PathBuf { + let mut stack: Vec = vec![]; + + // We assume .components() removes redundant consecutive path separators. + // Note that .components() also does some normalization of '.' on its own anyways. + // This '.' normalization happens to be compatible with the approach below. + for component in self.components() { + match component { + // Drop CurDir components, do not even push onto the stack. + Component::CurDir => {}, + + // For ParentDir components, we need to use the contents of the stack. + Component::ParentDir => { + // Look at the top element of stack, if any. + let top = stack.last().cloned(); + + match top { + // A component is on the stack, need more pattern matching. + Some(c) => { + match c { + // Push the ParentDir on the stack. + Component::Prefix(_) => { stack.push(component); }, + + // The parent of a RootDir is itself, so drop the ParentDir (no-op). + Component::RootDir => {}, + + // A CurDir should never be found on the stack, since they are dropped when seen. + Component::CurDir => { unreachable!(); }, + + // If a ParentDir is found, it must be due to it piling up at the start of a path. + // Push the new ParentDir onto the stack. + Component::ParentDir => { stack.push(component); }, + + // If a Normal is found, pop it off. + Component::Normal(_) => { let _ = stack.pop(); } + } + }, + + // Stack is empty, so path is empty, just push. + None => { stack.push(component); } + } + }, + + // All others, simply push onto the stack. + _ => { stack.push(component); }, + } + } + + // If an empty PathBuf would be returned, instead return CurDir ('.'). + if stack.is_empty() { + return PathBuf::from(Component::CurDir.as_ref()); + } + + let mut norm_path = PathBuf::new(); + + for item in &stack { + norm_path.push(item.as_ref()); + } + + norm_path + } + /// Reads a symbolic link, returning the file that the link points to. /// /// This is an alias to [`fs::read_link`]. @@ -3970,4 +4054,67 @@ mod tests { assert_eq!(format!("a{:#<5}b", Path::new("").display()), "a#####b"); assert_eq!(format!("a{:#<5}b", Path::new("a").display()), "aa####b"); } + + #[test] + pub fn test_normalize() { + macro_rules! tn( + ($path:expr, $expected:expr) => ( { + let mut actual = PathBuf::from($path); + let mut actual = actual.normalize(); + assert!(actual.to_str() == Some($expected), + "normalizing {:?}: Expected {:?}, got {:?}", + $path, $expected, + actual.to_str().unwrap()); + }); + ); + + tn!("", "."); + tn!("/", "/"); + tn!("foo", "foo"); + tn!(".", "."); + tn!("..", ".."); + tn!("/foo", "/foo"); + tn!("/foo/", "/foo"); + tn!("/foo/bar", "/foo/bar"); + tn!("foo/bar", "foo/bar"); + tn!("foo/.", "foo"); + tn!("foo//bar", "foo/bar"); + + // TODO: CONTINUE HERE!!!!! + if cfg!(windows) { + tn!("a\\b\\c", "a\\b"); + tn!("\\a", "\\"); + tn!("\\", "\\"); + + tn!("C:\\a\\b", "C:\\a"); + tn!("C:\\a", "C:\\"); + tn!("C:\\", "C:\\"); + tn!("C:a\\b", "C:a"); + tn!("C:a", "C:"); + tn!("C:", "C:"); + tn!("\\\\server\\share\\a\\b", "\\\\server\\share\\a"); + tn!("\\\\server\\share\\a", "\\\\server\\share\\"); + tn!("\\\\server\\share", "\\\\server\\share"); + tn!("\\\\?\\a\\b\\c", "\\\\?\\a\\b"); + tn!("\\\\?\\a\\b", "\\\\?\\a\\"); + tn!("\\\\?\\a", "\\\\?\\a"); + tn!("\\\\?\\C:\\a\\b", "\\\\?\\C:\\a"); + tn!("\\\\?\\C:\\a", "\\\\?\\C:\\"); + tn!("\\\\?\\C:\\", "\\\\?\\C:\\"); + tn!("\\\\?\\UNC\\server\\share\\a\\b", + "\\\\?\\UNC\\server\\share\\a", + true); + tn!("\\\\?\\UNC\\server\\share\\a", + "\\\\?\\UNC\\server\\share\\", + true); + tn!("\\\\?\\UNC\\server\\share", + "\\\\?\\UNC\\server\\share", + false); + tn!("\\\\.\\a\\b\\c", "\\\\.\\a\\b"); + tn!("\\\\.\\a\\b", "\\\\.\\a\\"); + tn!("\\\\.\\a", "\\\\.\\a"); + + tn!("\\\\?\\a\\b\\", "\\\\?\\a\\"); + } + } } From 856fa1457d9d85753f6e293fce92c690fd431a92 Mon Sep 17 00:00:00 2001 From: Mark LeMoine Date: Thu, 11 Jan 2018 12:16:47 -0800 Subject: [PATCH 02/10] About to catch up from upstream --- src/libstd/path.rs | 118 +++++++++++++++++++++++++-------------------- 1 file changed, 65 insertions(+), 53 deletions(-) diff --git a/src/libstd/path.rs b/src/libstd/path.rs index 93603c718b37b..4809f278d02df 100644 --- a/src/libstd/path.rs +++ b/src/libstd/path.rs @@ -2175,12 +2175,12 @@ impl Path { } /// Returns the normalized (or "cleaned") form of the path with all current - /// dir (.) and parent dir (..) references resolved. + /// directory (.) and parent directory (..) references resolved. /// - /// This is a purely logical calculation; the file system is not used. Namely, - /// this leaves symlinks intact and does not check to see if the target exists. + /// This is a purely logical calculation; the file system is not accessed. Namely, + /// this leaves symbolic links intact and does not validate that the target exists. /// - /// This may change the meaning of a path involving symlinks and parent dir + /// This may change the meaning of a path involving symbolic links and parent directory /// references. /// /// # Examples @@ -4059,8 +4059,7 @@ mod tests { pub fn test_normalize() { macro_rules! tn( ($path:expr, $expected:expr) => ( { - let mut actual = PathBuf::from($path); - let mut actual = actual.normalize(); + let mut actual = PathBuf::from($path).normalize(); assert!(actual.to_str() == Some($expected), "normalizing {:?}: Expected {:?}, got {:?}", $path, $expected, @@ -4068,53 +4067,66 @@ mod tests { }); ); - tn!("", "."); - tn!("/", "/"); - tn!("foo", "foo"); - tn!(".", "."); - tn!("..", ".."); - tn!("/foo", "/foo"); - tn!("/foo/", "/foo"); - tn!("/foo/bar", "/foo/bar"); - tn!("foo/bar", "foo/bar"); - tn!("foo/.", "foo"); - tn!("foo//bar", "foo/bar"); - - // TODO: CONTINUE HERE!!!!! - if cfg!(windows) { - tn!("a\\b\\c", "a\\b"); - tn!("\\a", "\\"); - tn!("\\", "\\"); - - tn!("C:\\a\\b", "C:\\a"); - tn!("C:\\a", "C:\\"); - tn!("C:\\", "C:\\"); - tn!("C:a\\b", "C:a"); - tn!("C:a", "C:"); - tn!("C:", "C:"); - tn!("\\\\server\\share\\a\\b", "\\\\server\\share\\a"); - tn!("\\\\server\\share\\a", "\\\\server\\share\\"); - tn!("\\\\server\\share", "\\\\server\\share"); - tn!("\\\\?\\a\\b\\c", "\\\\?\\a\\b"); - tn!("\\\\?\\a\\b", "\\\\?\\a\\"); - tn!("\\\\?\\a", "\\\\?\\a"); - tn!("\\\\?\\C:\\a\\b", "\\\\?\\C:\\a"); - tn!("\\\\?\\C:\\a", "\\\\?\\C:\\"); - tn!("\\\\?\\C:\\", "\\\\?\\C:\\"); - tn!("\\\\?\\UNC\\server\\share\\a\\b", - "\\\\?\\UNC\\server\\share\\a", - true); - tn!("\\\\?\\UNC\\server\\share\\a", - "\\\\?\\UNC\\server\\share\\", - true); - tn!("\\\\?\\UNC\\server\\share", - "\\\\?\\UNC\\server\\share", - false); - tn!("\\\\.\\a\\b\\c", "\\\\.\\a\\b"); - tn!("\\\\.\\a\\b", "\\\\.\\a\\"); - tn!("\\\\.\\a", "\\\\.\\a"); - - tn!("\\\\?\\a\\b\\", "\\\\?\\a\\"); + if cfg!(unix) { + tn!("", "."); + tn!("/", "/"); + tn!("//", "/"); /* Double-slash root is a separate entity in POSIX, + but in Rust we treat it as a normal root slash. */ + tn!("foo", "foo"); + tn!(".", "."); + tn!("..", ".."); + tn!(".foo", ".foo"); + tn!("..foo", "..foo"); + tn!("/foo", "/foo"); + tn!("//foo", "/foo"); + tn!("./foo/", "foo"); + tn!("../foo/", "../foo"); + tn!("/foo/bar", "/foo/bar"); + tn!("foo/bar", "foo/bar"); + tn!("foo/.", "foo"); + tn!("foo//bar", "foo/bar"); + tn!("./foo//bar//", "foo/bar"); + + tn!("foo/bar/baz/..", "foo/bar"); + tn!("foo/bar/baz/../", "foo/bar"); + tn!("foo/bar/baz/../..", "foo"); + tn!("foo/bar/baz/../../..", "."); + tn!("foo/bar/baz/../../../..", ".."); + tn!("foo/bar/baz/../../../../..", "../.."); + tn!("/foo/bar/baz/../../../../..", "/"); + tn!("foo/../bar/../baz/../", "."); + tn!("/.", "/"); + tn!("/..", "/"); + tn!("/../../", "/"); + } else { + tn!(r#"a\b\c"#, r#"a\b\c"#); + tn!(r#"a/b\c"#, r#"a\b\c"#); + tn!(r#"a/b\c\"#, r#"a\b\c"#); + tn!(r#"a/b\c/"#, r#"a\b\c"#); + tn!(r#"\"#, r#"\"#); + tn!(r#"\\"#, r#"\"#); + tn!(r#"/"#, r#"\"#); + tn!(r#"//"#, r#"\"#); + + tn!(r#"C:\a\b"#, r#"C:\a\b"#); + tn!(r#"C:\"#, r#"C:\"#); + tn!(r#"C:\."#, r#"C:\"#); + tn!(r#"C:\.."#, r#"C:\"#); + tn!(r#"C:a"#, r#"C:a"#); + tn!(r#"C:."#, r#"C:."#); + tn!(r#"C:.."#, r#"C:.."#); + + // Should these not have a trailing slash? + tn!(r#"\\server\share"#, r#"\\server\share\"#); + tn!(r#"\\server\share\a\b"#, r#"\\server\share\a\b"#); + tn!(r#"\\server\share\a\.\b"#, r#"\\server\share\a\b"#); + tn!(r#"\\server\share\a\..\b"#, r#"\\server\share\b"#); + tn!(r#"\\server\share\a\b\"#, r#"\\server\share\a\b"#); + + tn!(r#"\\?\a\b"#, r#"\\?\a\b"#); + tn!(r#"\\?\a/\\b\"#, r#"\\?\a/\\b"#); + tn!(r#"\\?\a/\\b/"#, r#"\\?\a/\\b/"#); + tn!(r#"\\?\a\b"#, r#"\\?\a\b"#); } } } From 4d8302eb03d682d7332b2a26dc1456e6bf0a2c28 Mon Sep 17 00:00:00 2001 From: Mark LeMoine Date: Thu, 11 Jan 2018 12:22:05 -0800 Subject: [PATCH 03/10] Marking as unstable --- src/libstd/path.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libstd/path.rs b/src/libstd/path.rs index 4809f278d02df..9dada540be82a 100644 --- a/src/libstd/path.rs +++ b/src/libstd/path.rs @@ -2195,7 +2195,7 @@ impl Path { /// let path = Path::new("/../../../cannot_go_above_root"); /// assert_eq!(path.normalize(), PathBuf::from("/cannot_go_above_root")); /// ``` - #[stable(feature = "path_ext", since = "1.24.0")] + #[unstable] pub fn normalize(&self) -> PathBuf { let mut stack: Vec = vec![]; From 2dd8a81cc534cb1c83fff32c86458e6ef3317a09 Mon Sep 17 00:00:00 2001 From: Mark LeMoine Date: Fri, 12 Jan 2018 20:09:58 -0800 Subject: [PATCH 04/10] Fixing incorrect braces, unstable flag, and too-long comment lines --- src/libstd/path.rs | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/libstd/path.rs b/src/libstd/path.rs index 8872ea4ae7c20..de2d630810950 100644 --- a/src/libstd/path.rs +++ b/src/libstd/path.rs @@ -2233,7 +2233,7 @@ impl Path { /// let path = Path::new("/../../../cannot_go_above_root"); /// assert_eq!(path.normalize(), PathBuf::from("/cannot_go_above_root")); /// ``` - #[unstable] + #[unstable(feature = "path normalize", issue = "47402")] pub fn normalize(&self) -> PathBuf { let mut stack: Vec = vec![]; @@ -2260,10 +2260,12 @@ impl Path { // The parent of a RootDir is itself, so drop the ParentDir (no-op). Component::RootDir => {}, - // A CurDir should never be found on the stack, since they are dropped when seen. + // A CurDir should never be found on the stack, + // since they are dropped when seen. Component::CurDir => { unreachable!(); }, - // If a ParentDir is found, it must be due to it piling up at the start of a path. + // If a ParentDir is found, it must be due to it + // piling up at the start of a path. // Push the new ParentDir onto the stack. Component::ParentDir => { stack.push(component); }, @@ -4169,6 +4171,7 @@ mod tests { tn!(r#"\\?\a/\\b/"#, r#"\\?\a/\\b/"#); tn!(r#"\\?\a\b"#, r#"\\?\a\b"#); } + } fn into_rc() { let orig = "hello/world"; From 46b9ba326d2fe6fc679948cc88a1816bfb19660d Mon Sep 17 00:00:00 2001 From: Mark LeMoine Date: Sat, 13 Jan 2018 23:31:36 -0800 Subject: [PATCH 05/10] Removing `mut` and changing `.as_ref()` calls to `.as_os_str()` --- src/libstd/path.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/libstd/path.rs b/src/libstd/path.rs index 85aaf0f43c0ef..878a8cc9cb0ac 100644 --- a/src/libstd/path.rs +++ b/src/libstd/path.rs @@ -2293,13 +2293,13 @@ impl Path { // If an empty PathBuf would be returned, instead return CurDir ('.'). if stack.is_empty() { - return PathBuf::from(Component::CurDir.as_ref()); + return PathBuf::from(Component::CurDir.as_os_str()); } let mut norm_path = PathBuf::new(); for item in &stack { - norm_path.push(item.as_ref()); + norm_path.push(item.as_os_str()); } norm_path @@ -4109,7 +4109,7 @@ mod tests { fn test_normalize() { macro_rules! tn( ($path:expr, $expected:expr) => ( { - let mut actual = PathBuf::from($path).normalize(); + let actual = PathBuf::from($path).normalize(); assert!(actual.to_str() == Some($expected), "normalizing {:?}: Expected {:?}, got {:?}", $path, $expected, From 9f66ba47ea185bf86f3e788dae9071e62fe28a34 Mon Sep 17 00:00:00 2001 From: Mark LeMoine Date: Tue, 16 Jan 2018 10:20:29 -0800 Subject: [PATCH 06/10] Adding missing (?) "test" attribute to `into_rc` --- src/libstd/path.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/libstd/path.rs b/src/libstd/path.rs index 112743db99ab7..1be42eeb2b2d7 100644 --- a/src/libstd/path.rs +++ b/src/libstd/path.rs @@ -4181,6 +4181,7 @@ mod tests { } } + #[test] fn into_rc() { let orig = "hello/world"; let path = Path::new(orig); From 3ee1f8beba43d11194e6875da17ca6073c6a7c56 Mon Sep 17 00:00:00 2001 From: Mark LeMoine Date: Tue, 6 Feb 2018 12:48:57 -0800 Subject: [PATCH 07/10] Renaming `normalize` to `clean`, and updating comments and docs to reflect --- src/libstd/path.rs | 128 ++++++++++++++++++++++----------------------- 1 file changed, 64 insertions(+), 64 deletions(-) diff --git a/src/libstd/path.rs b/src/libstd/path.rs index 9dada540be82a..a43c4cf4930f4 100644 --- a/src/libstd/path.rs +++ b/src/libstd/path.rs @@ -2174,7 +2174,7 @@ impl Path { fs::canonicalize(self) } - /// Returns the normalized (or "cleaned") form of the path with all current + /// Returns a cleaned representation of the path with all current /// directory (.) and parent directory (..) references resolved. /// /// This is a purely logical calculation; the file system is not accessed. Namely, @@ -2189,14 +2189,14 @@ impl Path { /// use std::path::{Path, PathBuf}; /// /// let path = Path::new("/recipes/./snacks/../desserts/banana_creme_pie.txt"); - /// assert_eq!(path.normalize(), PathBuf::from("/recipes/desserts/banana_creme_pie.txt")); + /// assert_eq!(path.clean(), PathBuf::from("/recipes/desserts/banana_creme_pie.txt")); /// let path = Path::new("../.././lots///of////./separators/"); - /// assert_eq!(path.normalize(), PathBuf::from("../../lots/of/separators")); + /// assert_eq!(path.clean(), PathBuf::from("../../lots/of/separators")); /// let path = Path::new("/../../../cannot_go_above_root"); - /// assert_eq!(path.normalize(), PathBuf::from("/cannot_go_above_root")); + /// assert_eq!(path.clean(), PathBuf::from("/cannot_go_above_root")); /// ``` #[unstable] - pub fn normalize(&self) -> PathBuf { + pub fn clean(&self) -> PathBuf { let mut stack: Vec = vec![]; // We assume .components() removes redundant consecutive path separators. @@ -4056,77 +4056,77 @@ mod tests { } #[test] - pub fn test_normalize() { - macro_rules! tn( + pub fn test_clean() { + macro_rules! tc( ($path:expr, $expected:expr) => ( { - let mut actual = PathBuf::from($path).normalize(); + let mut actual = PathBuf::from($path).clean(); assert!(actual.to_str() == Some($expected), - "normalizing {:?}: Expected {:?}, got {:?}", + "cleaning {:?}: Expected {:?}, got {:?}", $path, $expected, actual.to_str().unwrap()); }); ); if cfg!(unix) { - tn!("", "."); - tn!("/", "/"); - tn!("//", "/"); /* Double-slash root is a separate entity in POSIX, + tc!("", "."); + tc!("/", "/"); + tc!("//", "/"); /* Double-slash root is a separate entity in POSIX, but in Rust we treat it as a normal root slash. */ - tn!("foo", "foo"); - tn!(".", "."); - tn!("..", ".."); - tn!(".foo", ".foo"); - tn!("..foo", "..foo"); - tn!("/foo", "/foo"); - tn!("//foo", "/foo"); - tn!("./foo/", "foo"); - tn!("../foo/", "../foo"); - tn!("/foo/bar", "/foo/bar"); - tn!("foo/bar", "foo/bar"); - tn!("foo/.", "foo"); - tn!("foo//bar", "foo/bar"); - tn!("./foo//bar//", "foo/bar"); - - tn!("foo/bar/baz/..", "foo/bar"); - tn!("foo/bar/baz/../", "foo/bar"); - tn!("foo/bar/baz/../..", "foo"); - tn!("foo/bar/baz/../../..", "."); - tn!("foo/bar/baz/../../../..", ".."); - tn!("foo/bar/baz/../../../../..", "../.."); - tn!("/foo/bar/baz/../../../../..", "/"); - tn!("foo/../bar/../baz/../", "."); - tn!("/.", "/"); - tn!("/..", "/"); - tn!("/../../", "/"); + tc!("foo", "foo"); + tc!(".", "."); + tc!("..", ".."); + tc!(".foo", ".foo"); + tc!("..foo", "..foo"); + tc!("/foo", "/foo"); + tc!("//foo", "/foo"); + tc!("./foo/", "foo"); + tc!("../foo/", "../foo"); + tc!("/foo/bar", "/foo/bar"); + tc!("foo/bar", "foo/bar"); + tc!("foo/.", "foo"); + tc!("foo//bar", "foo/bar"); + tc!("./foo//bar//", "foo/bar"); + + tc!("foo/bar/baz/..", "foo/bar"); + tc!("foo/bar/baz/../", "foo/bar"); + tc!("foo/bar/baz/../..", "foo"); + tc!("foo/bar/baz/../../..", "."); + tc!("foo/bar/baz/../../../..", ".."); + tc!("foo/bar/baz/../../../../..", "../.."); + tc!("/foo/bar/baz/../../../../..", "/"); + tc!("foo/../bar/../baz/../", "."); + tc!("/.", "/"); + tc!("/..", "/"); + tc!("/../../", "/"); } else { - tn!(r#"a\b\c"#, r#"a\b\c"#); - tn!(r#"a/b\c"#, r#"a\b\c"#); - tn!(r#"a/b\c\"#, r#"a\b\c"#); - tn!(r#"a/b\c/"#, r#"a\b\c"#); - tn!(r#"\"#, r#"\"#); - tn!(r#"\\"#, r#"\"#); - tn!(r#"/"#, r#"\"#); - tn!(r#"//"#, r#"\"#); - - tn!(r#"C:\a\b"#, r#"C:\a\b"#); - tn!(r#"C:\"#, r#"C:\"#); - tn!(r#"C:\."#, r#"C:\"#); - tn!(r#"C:\.."#, r#"C:\"#); - tn!(r#"C:a"#, r#"C:a"#); - tn!(r#"C:."#, r#"C:."#); - tn!(r#"C:.."#, r#"C:.."#); + tc!(r#"a\b\c"#, r#"a\b\c"#); + tc!(r#"a/b\c"#, r#"a\b\c"#); + tc!(r#"a/b\c\"#, r#"a\b\c"#); + tc!(r#"a/b\c/"#, r#"a\b\c"#); + tc!(r#"\"#, r#"\"#); + tc!(r#"\\"#, r#"\"#); + tc!(r#"/"#, r#"\"#); + tc!(r#"//"#, r#"\"#); + + tc!(r#"C:\a\b"#, r#"C:\a\b"#); + tc!(r#"C:\"#, r#"C:\"#); + tc!(r#"C:\."#, r#"C:\"#); + tc!(r#"C:\.."#, r#"C:\"#); + tc!(r#"C:a"#, r#"C:a"#); + tc!(r#"C:."#, r#"C:."#); + tc!(r#"C:.."#, r#"C:.."#); // Should these not have a trailing slash? - tn!(r#"\\server\share"#, r#"\\server\share\"#); - tn!(r#"\\server\share\a\b"#, r#"\\server\share\a\b"#); - tn!(r#"\\server\share\a\.\b"#, r#"\\server\share\a\b"#); - tn!(r#"\\server\share\a\..\b"#, r#"\\server\share\b"#); - tn!(r#"\\server\share\a\b\"#, r#"\\server\share\a\b"#); - - tn!(r#"\\?\a\b"#, r#"\\?\a\b"#); - tn!(r#"\\?\a/\\b\"#, r#"\\?\a/\\b"#); - tn!(r#"\\?\a/\\b/"#, r#"\\?\a/\\b/"#); - tn!(r#"\\?\a\b"#, r#"\\?\a\b"#); + tc!(r#"\\server\share"#, r#"\\server\share\"#); + tc!(r#"\\server\share\a\b"#, r#"\\server\share\a\b"#); + tc!(r#"\\server\share\a\.\b"#, r#"\\server\share\a\b"#); + tc!(r#"\\server\share\a\..\b"#, r#"\\server\share\b"#); + tc!(r#"\\server\share\a\b\"#, r#"\\server\share\a\b"#); + + tc!(r#"\\?\a\b"#, r#"\\?\a\b"#); + tc!(r#"\\?\a/\\b\"#, r#"\\?\a/\\b"#); + tc!(r#"\\?\a/\\b/"#, r#"\\?\a/\\b/"#); + tc!(r#"\\?\a\b"#, r#"\\?\a\b"#); } } } From 5cebcca1fafb9f70fed430d38fbf69ff530d5baa Mon Sep 17 00:00:00 2001 From: Mark LeMoine Date: Tue, 6 Feb 2018 12:56:55 -0800 Subject: [PATCH 08/10] Renamed feature name to remove spaces --- src/libstd/path.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libstd/path.rs b/src/libstd/path.rs index ddd9dacd5a883..f0c796825941a 100644 --- a/src/libstd/path.rs +++ b/src/libstd/path.rs @@ -2241,7 +2241,7 @@ impl Path { /// let path = Path::new("/../../../cannot_go_above_root"); /// assert_eq!(path.clean(), PathBuf::from("/cannot_go_above_root")); /// ``` - #[unstable(feature = "path cleaning", issue = "47402")] + #[unstable(feature = "path_clean", issue = "47402")] pub fn clean(&self) -> PathBuf { let mut stack: Vec = vec![]; From ab1ed7ae09fbe596e32d7ae492fd3ab8adee400d Mon Sep 17 00:00:00 2001 From: Mark LeMoine Date: Tue, 6 Feb 2018 13:01:29 -0800 Subject: [PATCH 09/10] Adding Windows-specific tests --- src/libstd/path.rs | 84 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 84 insertions(+) diff --git a/src/libstd/path.rs b/src/libstd/path.rs index 1be42eeb2b2d7..0f39ae922cb6d 100644 --- a/src/libstd/path.rs +++ b/src/libstd/path.rs @@ -4150,6 +4150,90 @@ mod tests { tn!("/..", "/"); tn!("/../../", "/"); } else { + // Drive-absolute paths. + tc!(r#"X:\ABC\DEF"#, r#"X:\ABC\DEF"#); + tc!(r#"X:\"#, r#"X:\"#); + tc!(r#"X:\ABC\"#, r#"X:\ABC"#); + // tc!(r#"X:\ABC\DEF. ."#, r#"X:\ABC\DEF"#); + tc!(r#"X:/ABC/DEF"#, r#"X:\ABC\DEF"#); + tc!(r#"X:\ABC\..\XYZ"#, r#"X:\XYZ"#); + tc!(r#"X:\ABC\..\..\.."#, r#"X:\"#); + + // Drive-relative paths. + tc!(r#"X:DEF\GHI"#, r#"X:DEF\GHI"#); + tc!(r#"X:"#, r#"X:"#); + // tc!(r#"X:DEF. ."#, r#"X:DEF"#); + tc!(r#"Y:"#, r#"Y:"#); + tc!(r#"Z:"#, r#"Z:"#); + tc!(r#"X:ABC\..\XYZ"#, r#"X:XYZ"#); + tc!(r#"X:ABC\..\..\.."#, r#"X:..\.."#); + + // Rooted paths. + tc!(r#"\ABC\DEF"#, r#"\ABC\DEF"#); + tc!(r#"\"#, r#"\"#); + // tc!(r#"\ABC\DEF. ."#, r#"\ABC\DEF"#); + tc!(r#"/ABC/DEF"#, r#"\ABC\DEF"#); + tc!(r#"\ABC\..\XYZ"#, r#"\XYZ"#); + tc!(r#"\ABC\..\..\.."#, r#"\"#); + + // Relative paths. + tc!(r#"ABC\DEF"#, r#"ABC\DEF"#); + tc!(r#"."#, r#"."#); + // tc!(r#"ABC\DEF. ."#, r#"ABC\DEF"#); + tc!(r#"ABC/DEF"#, r#"ABC\DEF"#); + tc!(r#"..\ABC"#, r#"..\ABC"#); + tc!(r#"ABC\..\..\.."#, r#"..\.."#); + + // UNC absolute paths. + tc!(r#"\\server\share\ABC\DEF"#, r#"\\server\share\ABC\DEF"#); + tc!(r#"\\server"#, r#"\\server\"#); + tc!(r#"\\server\share"#, r#"\\server\share\"#); + // tc!(r#"\\server\share\ABC. ."#, r#"\\server\share\ABC"#); + // tc!(r#"//server/share/ABC/DEF"#, r#"\\server\share\ABC\DEF"#); + tc!(r#"\\server\share\ABC\..\XYZ"#, r#"\\server\share\XYZ"#); + tc!(r#"\\server\share\ABC\..\..\.."#, r#"\\server\share\"#); + + // Local device paths. + tc!(r#"\\.\COM20"#, r#"\\.\COM20\"#); + tc!(r#"\\.\pipe\mypipe"#, r#"\\.\pipe\mypipe"#); + // tc!(r#"\\.\X:\ABC\DEF. ."#, r#"\\.\X:\ABC\DEF"#); + // tc!(r#"\\.\X:/ABC/DEF"#, r#"\\.\X:\ABC\DEF"#); + tc!(r#"\\.\X:\ABC\..\XYZ"#, r#"\\.\X:\XYZ"#); + // tc!(r#"\\.\X:\ABC\..\..\C:\"#, r#"\\.\C:\"#); + tc!(r#"\\.\pipe\mypipe\..\notmine"#, r#"\\.\pipe\notmine"#); + + // More local device paths. + // tc!(r#"COM1"#, r#"\\.\COM1"#); + // tc!(r#"X:\COM1"#, r#"\\.\COM1"#); + // tc!(r#"X:COM1"#, r#"\\.\COM1"#); + // tc!(r#"valid\COM1"#, r#"\\.\COM1"#); + // tc!(r#"X:\notvalid\COM1"#, r#"\\.\COM1"#); + // tc!(r#"X:\COM1.blah"#, r#"\\.\COM1"#); + // tc!(r#"X:\COM1:blah"#, r#"\\.\COM1"#); + // tc!(r#"X:\COM1 .blah"#, r#"\\.\COM1"#); + // tc!(r#"\\.\X:\COM1"#, r#"\\.\X:\COM1"#); + // tc!(r#"\\abc\xyz\COM1"#, r#"\\abc\xyz\COM1"#); + + // Root local device paths. + tc!(r#"\\?\X:\ABC\DEF"#, r#"\\?\X:\ABC\DEF"#); + tc!(r#"\\?\X:\"#, r#"\\?\X:\"#); + tc!(r#"\\?\X:"#, r#"\\?\X:"#); + tc!(r#"\\?\X:\COM1"#, r#"\\?\X:\COM1"#); + // tc!(r#"\\?\X:\ABC\DEF. ."#, r#"\\?\X:\ABC\DEF"#); + // tc!(r#"\\?\X:/ABC/DEF"#, r#"\\?\X:\ABC\DEF"#); + tc!(r#"\\?\X:\ABC\..\XYZ"#, r#"\\?\X:\XYZ"#); + tc!(r#"\\?\X:\ABC\..\..\.."#, r#"\\?\X:\"#); + + // More root local device paths. + // tc!(r#"\??\X:\ABC\DEF"#, r#"X:\??\X:\ABC\DEF"#); + // tc!(r#"\??\X:\"#, r#"X:\??\X:\"#); + // tc!(r#"\??\X:"#, r#"X:\??\X:"#); + // tc!(r#"\??\X:\COM1"#, r#"X:\??\X:\COM1"#); + // tc!(r#"\??\X:\ABC\DEF. ."#, r#"X:\??\X:\ABC\DEF"#); + // tc!(r#"\??\X:/ABC/DEF"#, r#"X:\??\X:\ABC\DEF"#); + // tc!(r#"\??\X:\ABC\..\XYZ"#, r#"X:\??\X:\XYZ"#); + // tc!(r#"\??\X:\ABC\..\..\.."#, r#"X:\"#); + tn!(r#"a\b\c"#, r#"a\b\c"#); tn!(r#"a/b\c"#, r#"a\b\c"#); tn!(r#"a/b\c\"#, r#"a\b\c"#); From 9942a0f2a11f68bdf6331b001360ec43ba8cfcdb Mon Sep 17 00:00:00 2001 From: Mark LeMoine Date: Tue, 6 Feb 2018 13:05:17 -0800 Subject: [PATCH 10/10] Missed some `tn` -> `tc` renames --- src/libstd/path.rs | 32 ++++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/src/libstd/path.rs b/src/libstd/path.rs index 74fcbd6823f57..bb655c0aa1673 100644 --- a/src/libstd/path.rs +++ b/src/libstd/path.rs @@ -4234,22 +4234,22 @@ mod tests { // tc!(r#"\??\X:\ABC\..\XYZ"#, r#"X:\??\X:\XYZ"#); // tc!(r#"\??\X:\ABC\..\..\.."#, r#"X:\"#); - tn!(r#"a\b\c"#, r#"a\b\c"#); - tn!(r#"a/b\c"#, r#"a\b\c"#); - tn!(r#"a/b\c\"#, r#"a\b\c"#); - tn!(r#"a/b\c/"#, r#"a\b\c"#); - tn!(r#"\"#, r#"\"#); - tn!(r#"\\"#, r#"\"#); - tn!(r#"/"#, r#"\"#); - tn!(r#"//"#, r#"\"#); - - tn!(r#"C:\a\b"#, r#"C:\a\b"#); - tn!(r#"C:\"#, r#"C:\"#); - tn!(r#"C:\."#, r#"C:\"#); - tn!(r#"C:\.."#, r#"C:\"#); - tn!(r#"C:a"#, r#"C:a"#); - tn!(r#"C:."#, r#"C:."#); - tn!(r#"C:.."#, r#"C:.."#); + tc!(r#"a\b\c"#, r#"a\b\c"#); + tc!(r#"a/b\c"#, r#"a\b\c"#); + tc!(r#"a/b\c\"#, r#"a\b\c"#); + tc!(r#"a/b\c/"#, r#"a\b\c"#); + tc!(r#"\"#, r#"\"#); + tc!(r#"\\"#, r#"\"#); + tc!(r#"/"#, r#"\"#); + tc!(r#"//"#, r#"\"#); + + tc!(r#"C:\a\b"#, r#"C:\a\b"#); + tc!(r#"C:\"#, r#"C:\"#); + tc!(r#"C:\."#, r#"C:\"#); + tc!(r#"C:\.."#, r#"C:\"#); + tc!(r#"C:a"#, r#"C:a"#); + tc!(r#"C:."#, r#"C:."#); + tc!(r#"C:.."#, r#"C:.."#); // Should these not have a trailing slash? tc!(r#"\\server\share"#, r#"\\server\share\"#);