gitwatch_rs/
util.rs

1use std::path::{Path, PathBuf};
2
3use anyhow::{Context, Result};
4
5pub fn normalize_path(path: &Path) -> Result<PathBuf> {
6    let path_str = path.to_str().context("Invalid path")?;
7    let expanded = shellexpand::full(path_str)?;
8    Ok(PathBuf::from(expanded.as_ref()).canonicalize()?)
9}
10
11#[cfg(test)]
12mod tests {
13    use std::{env, fs};
14
15    use testresult::TestResult;
16
17    use super::*;
18
19    #[test]
20    fn test_normalize_path() -> TestResult {
21        let temp_dir = tempfile::tempdir()?;
22        let home = temp_dir.path();
23        env::set_var("HOME", home.to_str().unwrap());
24
25        let test_path = home.join("path");
26        fs::create_dir_all(&test_path)?;
27
28        let test_cases = vec![
29            // absolute path (should succeed)
30            (home.to_path_buf(), Ok(home.canonicalize()?)),
31            // environment variable expansions (should succeed)
32            (PathBuf::from("$HOME/path"), Ok(test_path.canonicalize()?)),
33            (PathBuf::from("${HOME}/path"), Ok(test_path.canonicalize()?)),
34            // non-existent paths (should fail)
35            (PathBuf::from("~/test"), Err(())),
36            // invalid paths (should fail)
37            (PathBuf::from("\0invalid"), Err(())),
38        ];
39
40        for (input, expected) in test_cases {
41            let result = normalize_path(&input);
42            match expected {
43                Ok(expected_path) => {
44                    assert!(result.is_ok());
45                    assert_eq!(result.unwrap(), expected_path);
46                }
47                Err(_) => {
48                    assert!(result.is_err());
49                }
50            }
51        }
52
53        env::remove_var("HOME");
54        Ok(())
55    }
56}