#![cfg(feature = "alloc")]
use shepherd_core::dispatch::{PathAuthority, path_in_write_scope};
#[test]
fn exact_repository_scopes_accept_canonical_mixed_case_file_names() {
for path in [
"Cargo.toml",
"Cargo.lock",
"README.md",
"crates/cli/Cargo.toml",
"docs/ApiContract.md",
] {
let authority = PathAuthority::exact(path).expect("case-preserving repository path");
assert_eq!(authority.as_str(), path);
assert!(authority.contains(path).expect("exact path match"));
assert!(
!authority
.contains(&path.to_ascii_lowercase())
.expect("different case stays distinct")
);
}
}
#[test]
fn repository_globs_match_case_exactly_and_keep_segment_boundaries() {
let authority = PathAuthority::new("Docs/*.md").expect("case-preserving bounded glob");
assert!(
authority
.contains("Docs/README.md")
.expect("matching parent and extension")
);
assert!(
!authority
.contains("docs/README.md")
.expect("parent case is not folded")
);
assert!(
!authority
.contains("Docs/README.MD")
.expect("extension case is not folded")
);
assert!(
!authority
.contains("Docs/nested/README.md")
.expect("one segment is not recursive")
);
assert!(
!path_in_write_scope("Cargo.toml", &["cargo.toml".into()]).expect("exact case comparison")
);
}
#[test]
fn mixed_case_paths_do_not_relax_windows_or_traversal_denials() {
for path in [
"",
"*",
"**",
"/Cargo.toml",
"../Cargo.toml",
"docs/../Cargo.toml",
"./Cargo.toml",
"docs//Cargo.toml",
"C:/repo/Cargo.toml",
"C:\\repo\\Cargo.toml",
"\\\\host\\share\\Cargo.toml",
"Cargo.toml:stream",
"Cargo.toml.",
"Cargo.toml ",
"DOCS~1/Cargo.toml",
"Docs/Cargo.toml\0",
"Docs/Cargo.toml\n",
"Döcs/Cargo.toml",
] {
assert!(
PathAuthority::new(path).is_err(),
"unsafe authority must remain denied: {path:?}"
);
}
}