summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/lib.rs86
1 files changed, 73 insertions, 13 deletions
diff --git a/src/lib.rs b/src/lib.rs
index a78a767..6470322 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -1,17 +1,42 @@
-use std::path::{Component, Path, PathBuf};
+use std::{env, path::{Component, Path, PathBuf}};
#[derive(Debug)]
pub enum NormalizeError {
EmptyInput,
+ CwdNotAbsolute,
}
pub fn normalize_path(root: &Path, origin: &Path, input: &Path) -> Result<PathBuf, NormalizeError> {
+ let cwd = env::current_dir().map_err(|_| NormalizeError::CwdNotAbsolute)?;
+ normalize_path_with_preset_cwd(root, origin, input, &cwd)
+}
+
+fn normalize_path_with_preset_cwd(
+ root: &Path,
+ origin: &Path,
+ input: &Path,
+ cwd: &Path,
+) -> Result<PathBuf, NormalizeError> {
if input.as_os_str().is_empty() {
return Err(NormalizeError::EmptyInput);
}
+ if !cwd.is_absolute() {
+ return Err(NormalizeError::CwdNotAbsolute);
+ }
+ let input = if input.is_absolute() {
+ input.to_path_buf()
+ } else if origin.is_absolute() {
+ origin.join(input)
+ } else {
+ cwd.join(origin).join(input)
+ };
+ let root = if root.is_absolute() {
+ root.to_path_buf()
+ } else {
+ cwd.join(root)
+ };
let mut stack = Vec::new();
- let origin_joint_input = origin.join(input);
- for component in origin_joint_input.components() {
+ for component in input.components() {
match component {
Component::CurDir => (),
Component::ParentDir => {
@@ -22,11 +47,11 @@ pub fn normalize_path(root: &Path, origin: &Path, input: &Path) -> Result<PathBu
Component::RootDir => stack.push(component),
}
}
- let normalized_origin_join_input = PathBuf::from_iter(stack);
- Ok(normalize_to_root(&normalized_origin_join_input, root))
+ let normalized_input = PathBuf::from_iter(stack);
+ Ok(normalize_to_root(normalized_input, &root))
}
-fn normalize_to_root(target: &Path, mut root: &Path) -> PathBuf {
+fn normalize_to_root(target: PathBuf, mut root: &Path) -> PathBuf {
let mut prefix = PathBuf::new();
loop {
if let Ok(suffix) = target.strip_prefix(root) {
@@ -36,7 +61,7 @@ fn normalize_to_root(target: &Path, mut root: &Path) -> PathBuf {
prefix.push("..");
root = new_root;
} else {
- return target.to_path_buf();
+ return target;
}
}
}
@@ -45,52 +70,87 @@ fn normalize_to_root(target: &Path, mut root: &Path) -> PathBuf {
mod tests {
use std::path::Path;
- use super::{NormalizeError, normalize_path};
+ use super::{NormalizeError, normalize_path_with_preset_cwd};
#[test]
fn empty_path_returns_error() {
+ let fake_cwd = Path::new("/sandbox");
let root = Path::new("");
let origin_dir = Path::new("");
let input = Path::new("");
- let result = normalize_path(root, origin_dir, input);
+ let result = normalize_path_with_preset_cwd(root, origin_dir, input, fake_cwd);
assert!(matches!(result, Err(NormalizeError::EmptyInput)));
}
#[test]
fn plain_filename_with_root_at_cwd_returns_filename() {
+ let fake_cwd = Path::new("/sandbox");
let root = Path::new("");
let origin_dir = Path::new("");
let input = Path::new("main.rs");
- let result = normalize_path(root, origin_dir, input);
+ let result = normalize_path_with_preset_cwd(root, origin_dir, input, fake_cwd);
assert!(result.is_ok());
assert_eq!(result.unwrap(), Path::new("main.rs"));
}
#[test]
fn relative_path_from_origin_is_resolved() {
+ let fake_cwd = Path::new("/sandbox");
let root = Path::new("");
let origin_dir = Path::new("src");
let input = Path::new("../main.rs");
- let result = normalize_path(root, origin_dir, input);
+ let result = normalize_path_with_preset_cwd(root, origin_dir, input, fake_cwd);
assert!(result.is_ok());
assert_eq!(result.unwrap(), Path::new("main.rs"));
}
#[test]
fn path_is_made_relative_to_root() {
+ let fake_cwd = Path::new("/sandbox");
let root = Path::new("/project");
let origin_dir = Path::new("/project/src");
let input = Path::new("main.rs");
- let result = normalize_path(root, origin_dir, input);
+ let result = normalize_path_with_preset_cwd(root, origin_dir, input, fake_cwd);
assert_eq!(result.unwrap(), Path::new("src/main.rs"));
}
#[test]
fn path_is_made_relative_to_root_from_outside() {
+ let fake_cwd = Path::new("/sandbox");
let root = Path::new("/project");
let origin_dir = Path::new("/outside");
let input = Path::new("main.rs");
- let result = normalize_path(root, origin_dir, input);
+ let result = normalize_path_with_preset_cwd(root, origin_dir, input, fake_cwd);
+ assert_eq!(result.unwrap(), Path::new("../outside/main.rs"));
+ }
+
+ #[test]
+ fn path_is_made_relative_to_root_even_if_root_dir_is_relative() {
+ let fake_cwd = Path::new("/sandbox");
+ let root = Path::new("project");
+ let origin_dir = Path::new("/sandbox/outside");
+ let input = Path::new("main.rs");
+ let result = normalize_path_with_preset_cwd(root, origin_dir, input, fake_cwd);
+ assert_eq!(result.unwrap(), Path::new("../outside/main.rs"));
+ }
+
+ #[test]
+ fn absolute_inputs_work() {
+ let fake_cwd = Path::new("/sandbox");
+ let root = Path::new("project");
+ let origin_dir = Path::new("/sandbox/outside");
+ let input = Path::new("/sandbox/main.rs");
+ let result = normalize_path_with_preset_cwd(root, origin_dir, input, fake_cwd);
+ assert_eq!(result.unwrap(), Path::new("../main.rs"));
+ }
+
+ #[test]
+ fn path_is_made_relative_to_root_even_if_origin_dir_is_relative() {
+ let fake_cwd = Path::new("/sandbox");
+ let root = Path::new("/sandbox/project");
+ let origin_dir = Path::new("outside");
+ let input = Path::new("main.rs");
+ let result = normalize_path_with_preset_cwd(root, origin_dir, input, fake_cwd);
assert_eq!(result.unwrap(), Path::new("../outside/main.rs"));
}
}