From 718c8c4360b5c42d1c0bcd97d7348908d915212e Mon Sep 17 00:00:00 2001 From: Nayeem Rahman Date: Sat, 7 Sep 2019 19:13:09 +0100 Subject: [PATCH] Fix path normalization in resolve_from_cwd() (#2875) --- cli/fs.rs | 48 ++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 42 insertions(+), 6 deletions(-) diff --git a/cli/fs.rs b/cli/fs.rs index 8b8693fcda..d831d44c0d 100644 --- a/cli/fs.rs +++ b/cli/fs.rs @@ -139,20 +139,56 @@ pub fn resolve_from_cwd(path: &str) -> Result<(PathBuf, String), ErrBox> { cwd.join(path) }; - // HACK: `Url::from_directory_path` is used here because it normalizes the path. + // HACK: `Url::parse` is used here because it normalizes the path. // Joining `/dev/deno/" with "./tests" using `PathBuf` yields `/deno/dev/./tests/`. // On the other hand joining `/dev/deno/" with "./tests" using `Url` yields "/dev/deno/tests" // - and that's what we want. // There exists similar method on `PathBuf` - `PathBuf.canonicalize`, but the problem // is `canonicalize` resolves symlinks and we don't want that. - // We just want o normalize the path... - let resolved_url = Url::from_file_path(resolved_path) - .expect("PathBuf should be parseable URL"); - let normalized_path = resolved_url + // We just want to normalize the path... + // This only works on absolute paths - not worth extracting as a public utility. + let resolved_url = + Url::from_file_path(resolved_path).expect("Path should be absolute"); + let normalized_url = Url::parse(resolved_url.as_str()) + .expect("String from a URL should parse to a URL"); + let normalized_path = normalized_url .to_file_path() - .expect("URL from PathBuf should be valid path"); + .expect("URL from a path should contain a valid path"); let path_string = normalized_path.to_str().unwrap().to_string(); Ok((normalized_path, path_string)) } + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn resolve_from_cwd_child() { + let cwd = std::env::current_dir().unwrap(); + assert_eq!(resolve_from_cwd("a").unwrap().0, cwd.join("a")); + } + + #[test] + fn resolve_from_cwd_dot() { + let cwd = std::env::current_dir().unwrap(); + assert_eq!(resolve_from_cwd(".").unwrap().0, cwd); + } + + #[test] + fn resolve_from_cwd_parent() { + let cwd = std::env::current_dir().unwrap(); + assert_eq!(resolve_from_cwd("a/..").unwrap().0, cwd); + } + + #[test] + fn resolve_from_cwd_absolute() { + let expected = if cfg!(windows) { + Path::new("C:\\a") + } else { + Path::new("/a") + }; + assert_eq!(resolve_from_cwd("/a").unwrap().0, expected); + } +}