#![cfg_attr(coverage_nightly, coverage(off))]
pub(crate) const PMAT_OWNED_DIRS: &[&str] = &[
".pmat",
".pmat-work",
".pmat-metrics",
".pmat-qa",
];
pub(crate) const PMAT_OWNED_SUFFIXES: &[&str] = &[".yaml.lock"];
pub(crate) fn is_pmat_owned_state(porcelain_line: &str) -> bool {
let Some(after_status) = porcelain_line.get(3..) else {
return false;
};
let path = after_status
.rsplit(" -> ")
.next()
.unwrap_or(after_status)
.trim();
let path = unquote_porcelain_path(path);
is_pmat_owned_path(path)
}
pub(crate) fn is_pmat_owned_path(path: &str) -> bool {
if PMAT_OWNED_SUFFIXES.iter().any(|s| path.ends_with(s)) {
return true;
}
path.split('/')
.any(|segment| PMAT_OWNED_DIRS.contains(&segment))
&& path.contains('/')
}
pub(crate) fn unquote_porcelain_path(path: &str) -> &str {
path.strip_prefix('"')
.and_then(|p| p.strip_suffix('"'))
.unwrap_or(path)
}
#[cfg(test)]
mod tests {
use super::is_pmat_owned_state;
#[test]
fn matches_owned_dirs() {
assert!(is_pmat_owned_state(" M .pmat/context.db"));
assert!(is_pmat_owned_state(" M .pmat/context.idx/manifest.json"));
assert!(is_pmat_owned_state(" M .pmat/project.toml"));
assert!(is_pmat_owned_state("M .pmat-work/ledger.jsonl"));
assert!(is_pmat_owned_state("?? .pmat-work/PMAT-154/evidence.json"));
assert!(is_pmat_owned_state(
"A .pmat-metrics/commit-abc123-meta.json"
));
}
#[test]
fn skips_user_files() {
assert!(!is_pmat_owned_state(" M src/lib.rs"));
assert!(!is_pmat_owned_state("M docs/roadmaps/roadmap.yaml"));
assert!(!is_pmat_owned_state(" M Cargo.toml"));
assert!(!is_pmat_owned_state(" M .pmat-baseline.json"));
assert!(!is_pmat_owned_state(" M pmat/context.db"));
}
#[test]
fn rename_destination() {
assert!(is_pmat_owned_state(
"R src/old.rs -> .pmat-work/archived.rs"
));
assert!(!is_pmat_owned_state("R .pmat-work/old.rs -> src/new.rs"));
}
#[test]
fn nested_and_qa_state_is_owned() {
assert!(is_pmat_owned_state(" M sub/.pmat/context.db"));
assert!(is_pmat_owned_state(
" M a/b/.pmat-metrics/commit-x-meta.json"
));
assert!(is_pmat_owned_state("?? .pmat-qa/GH-102/checklist.yaml"));
assert!(is_pmat_owned_state(" M docs/roadmaps/roadmap.yaml.lock"));
}
#[test]
fn lookalikes_in_nested_paths_stay_user_owned() {
assert!(!is_pmat_owned_state(" M sub/pmat/context.db"));
assert!(!is_pmat_owned_state(" M sub/.pmat-baseline.json"));
assert!(!is_pmat_owned_state(" M docs/roadmaps/roadmap.yaml"));
}
#[test]
fn quoted_paths_are_still_recognised() {
assert!(is_pmat_owned_state(" M \".pmat/we ird.db\""));
assert!(is_pmat_owned_state("?? \".pmat-work/PMAT-1/a b.json\""));
assert!(is_pmat_owned_state(
"R \"src/o ld.rs\" -> \".pmat-work/n ew.rs\""
));
assert!(!is_pmat_owned_state(" M \"src/we ird.rs\""));
}
#[test]
fn short_line_defense() {
assert!(!is_pmat_owned_state(""));
assert!(!is_pmat_owned_state("XY"));
assert!(!is_pmat_owned_state("XY "));
}
#[test]
fn full_github_sync_scenario() {
let status = concat!(
"## master...origin/master\n",
"M .pmat-work/ledger.jsonl\n",
" M .pmat/context.db\n",
" M .pmat/context.idx/manifest.json\n",
"A .pmat-metrics/commit-abc123-meta.json\n",
" M src/lib.rs\n",
"?? untracked.txt"
);
let dirty_count = status
.lines()
.skip(1)
.filter(|l| !l.is_empty() && !l.starts_with("??"))
.filter(|l| !is_pmat_owned_state(l))
.count();
assert_eq!(
dirty_count, 1,
"Only user-owned src/lib.rs should count; pmat state excluded"
);
}
}