use crate::{anchored_canonicalize, soft_canonicalize};
use std::fs;
use tempfile::TempDir;
#[test]
fn clamp_prevents_escape_on_lexical_dotdot() -> std::io::Result<()> {
let td = TempDir::new()?;
let anchor = td.path().join("root");
fs::create_dir_all(&anchor)?;
let base = soft_canonicalize(&anchor)?;
let inputs = [
"../../../../etc/passwd",
"../..",
"..",
"./.././../relative/path",
];
for inp in inputs {
let out = anchored_canonicalize(&base, inp)?;
assert!(
out.starts_with(&base),
"{inp} should be clamped under anchor"
);
}
Ok(())
}
#[cfg(unix)]
#[test]
fn non_existing_anchor_clamp_unix() -> std::io::Result<()> {
let td = TempDir::new()?;
let anchor_missing = td.path().join("non_existing").join("anchor").join("deep");
let base = soft_canonicalize(anchor_missing)?;
let out = anchored_canonicalize(&base, "../../../../etc/passwd")?;
assert!(out.starts_with(&base));
assert!(out.ends_with("etc/passwd"));
Ok(())
}
#[cfg(windows)]
#[test]
fn non_existing_anchor_clamp_windows() -> std::io::Result<()> {
let td = TempDir::new()?;
let anchor_missing = td.path().join("non_existing").join("anchor").join("deep");
let base = soft_canonicalize(anchor_missing)?;
let out = anchored_canonicalize(&base, r"..\..\..\etc\passwd")?;
let expected = std::path::PathBuf::from(format!(r"{}\etc\passwd", base.to_string_lossy()));
assert_eq!(out, expected);
Ok(())
}