use crate::error::AppError;
pub use vta_sdk::context_path::{
MAX_CONTEXT_DEPTH, SEPARATOR, depth, is_ancestor_or_self, parent_path,
};
pub fn validate_context_path(value: &str) -> Result<(), AppError> {
vta_sdk::context_path::validate_context_path(value).map_err(|e| AppError::Validation(e.0))
}
pub fn child_path(parent: &str, segment: &str) -> Result<String, AppError> {
vta_sdk::context_path::child_path(parent, segment).map_err(|e| AppError::Validation(e.0))
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn validates_good_paths() {
for p in ["acme", "acme/eng", "acme/eng/team-a", "a.b_c/d-e", "x/y/z"] {
assert!(validate_context_path(p).is_ok(), "{p} should be valid");
}
}
#[test]
fn rejects_malformed_paths() {
assert!(validate_context_path("").is_err()); assert!(validate_context_path("/acme").is_err()); assert!(validate_context_path("acme/").is_err()); assert!(validate_context_path("acme//eng").is_err()); assert!(validate_context_path("acme/ev il").is_err()); assert!(validate_context_path("acme/..").is_ok());
}
#[test]
fn enforces_max_depth() {
let deep = (0..=MAX_CONTEXT_DEPTH)
.map(|i| format!("s{i}"))
.collect::<Vec<_>>()
.join("/");
assert!(
validate_context_path(&deep).is_err(),
"{deep} exceeds max depth"
);
let ok = (0..MAX_CONTEXT_DEPTH)
.map(|i| format!("s{i}"))
.collect::<Vec<_>>()
.join("/");
assert!(validate_context_path(&ok).is_ok());
}
#[test]
fn ancestry_is_segment_aware_not_string_prefix() {
assert!(is_ancestor_or_self("acme", "acme"));
assert!(is_ancestor_or_self("acme/eng", "acme/eng"));
assert!(is_ancestor_or_self("acme", "acme/eng"));
assert!(is_ancestor_or_self("acme", "acme/eng/team-a"));
assert!(is_ancestor_or_self("acme/eng", "acme/eng/team-a"));
assert!(!is_ancestor_or_self("acme", "acme-evil"));
assert!(!is_ancestor_or_self("acme/eng", "acme/engineering"));
assert!(!is_ancestor_or_self("ac", "acme"));
assert!(!is_ancestor_or_self("acme/eng", "acme"));
assert!(!is_ancestor_or_self("acme/eng", "acme/ops"));
assert!(!is_ancestor_or_self("", "acme"));
assert!(!is_ancestor_or_self("acme", ""));
}
#[test]
fn parent_and_depth() {
assert_eq!(parent_path("acme"), None);
assert_eq!(parent_path("acme/eng"), Some("acme"));
assert_eq!(parent_path("acme/eng/team-a"), Some("acme/eng"));
assert_eq!(depth("acme"), 1);
assert_eq!(depth("acme/eng/team-a"), 3);
assert_eq!(depth(""), 0);
}
#[test]
fn child_path_builds_and_validates() {
assert_eq!(child_path("acme", "eng").unwrap(), "acme/eng");
assert!(child_path("acme", "ev/il").is_err()); assert!(child_path("acme", "").is_err()); }
}