//! Pure path-guard helpers for `service::git_ops`.
//!
//! These functions are free of side effects — they operate on already-resolved
//! `Path` values and perform no filesystem I/O. Path existence checks and
//! canonicalization belong in `io.rs`.

use std::path::Path;

/// Return `true` if `canonical_path` starts with (i.e. is under) `root`.
///
/// Both paths must already be canonicalized so that symlinks, `.`, and `..`
/// components do not cause false negatives.
pub fn is_under_root(canonical_path: &Path, root: &Path) -> bool {
    canonical_path.starts_with(root)
}

// ── Tests ─────────────────────────────────────────────────────────────────────

#[cfg(test)]
mod tests {
    use super::*;
    use std::path::PathBuf;

    #[test]
    fn is_under_root_returns_true_for_child() {
        let root = PathBuf::from("/project/.huskies/worktrees");
        let child = PathBuf::from("/project/.huskies/worktrees/42_story_foo");
        assert!(is_under_root(&child, &root));
    }

    #[test]
    fn is_under_root_returns_false_for_sibling() {
        let root = PathBuf::from("/project/.huskies/worktrees");
        let sibling = PathBuf::from("/project/.huskies/other");
        assert!(!is_under_root(&sibling, &root));
    }

    #[test]
    fn is_under_root_returns_false_for_parent() {
        let root = PathBuf::from("/project/.huskies/worktrees");
        let parent = PathBuf::from("/project/.huskies");
        assert!(!is_under_root(&parent, &root));
    }

    #[test]
    fn is_under_root_returns_true_for_exact_match() {
        let root = PathBuf::from("/project/.huskies/worktrees");
        assert!(is_under_root(&root, &root));
    }

    #[test]
    fn is_under_root_returns_false_for_path_with_shared_prefix_but_not_child() {
        // /foo/bar-extra is NOT under /foo/bar
        let root = PathBuf::from("/foo/bar");
        let other = PathBuf::from("/foo/bar-extra");
        assert!(!is_under_root(&other, &root));
    }
}
