mod bounded_path;
mod error;
#[cfg(test)]
mod tests;
mod validated_root;
pub(crate) use bounded_path::{BoundedPath, normalize_bounded_relative_path};
pub(crate) use error::{PathViolation, RootViolation};
pub(crate) use validated_root::ValidatedRoot;
#[must_use]
pub fn normalize_slashes(path: &str) -> String {
if path.contains('\\') {
path.replace('\\', "/")
} else {
path.to_string()
}
}
#[must_use]
pub fn normalize_rel_path(path: &str) -> String {
let normalized = normalize_slashes(path);
let mut s = normalized.as_str();
while let Some(rest) = s.strip_prefix("./") {
s = rest;
}
s.to_string()
}
#[cfg(test)]
mod normalization_tests {
use super::*;
use proptest::prelude::*;
#[test]
fn normalize_slashes_replaces_backslash() {
assert_eq!(normalize_slashes(r"foo\bar\baz.rs"), "foo/bar/baz.rs");
}
#[test]
fn normalize_rel_path_strips_dot_slash() {
assert_eq!(normalize_rel_path("./src/main.rs"), "src/main.rs");
}
#[test]
fn normalize_rel_path_strips_dot_backslash() {
assert_eq!(normalize_rel_path(r".\src\main.rs"), "src/main.rs");
}
#[test]
fn normalize_rel_path_preserves_non_relative_prefix() {
assert_eq!(normalize_rel_path("../src/main.rs"), "../src/main.rs");
}
proptest! {
#[test]
fn normalize_slashes_no_backslashes(path in "\\PC*") {
let normalized = normalize_slashes(&path);
prop_assert!(!normalized.contains('\\'));
}
#[test]
fn normalize_slashes_idempotent(path in "\\PC*") {
let once = normalize_slashes(&path);
let twice = normalize_slashes(&once);
prop_assert_eq!(once, twice);
}
#[test]
fn normalize_rel_path_no_backslashes(path in "\\PC*") {
let normalized = normalize_rel_path(&path);
prop_assert!(!normalized.contains('\\'));
}
#[test]
fn normalize_rel_path_idempotent(path in "\\PC*") {
let once = normalize_rel_path(&path);
let twice = normalize_rel_path(&once);
prop_assert_eq!(once, twice);
}
}
}