use super::tests::{AGENT, repo_with};
use super::*;
use crate::template::RealGit;
use std::cell::RefCell;
pub(super) fn commit_side_effect(wt: &std::path::Path) {
let g = RealGit::new();
g.run(wt, &["add", "-A"]).unwrap();
g.run(wt, &["commit", "-m", "tool: write_summary"]).unwrap();
}
pub(super) fn nothing_staged(wt: &std::path::Path) {
let staged = RealGit::new()
.run_capture(wt, &["diff", "--cached", "--name-status"])
.unwrap();
assert!(staged.trim().is_empty(), "nothing staged: {staged:?}");
}
#[test]
fn the_summary_this_pass_just_wrote_is_declined() {
let dir = repo_with("messages/002-user.md");
let wt = dir.path();
let rel = write_summary(wt, "the parser port is underway\n").unwrap();
assert_eq!(rel, "summary/001.md");
commit_side_effect(wt);
let err = mark_for_deletion(wt, AGENT, &rel, &RealGit::new()).unwrap_err();
assert!(
matches!(&err, Error::NotCompactionEligible { path, .. } if *path == rel),
"{err:?}"
);
let text = err.to_string();
assert!(text.contains("summary/001.md"), "{text}");
assert!(
text.contains("this compaction pass's own product"),
"{text}"
);
assert!(text.contains("not compaction-eligible"), "{text}");
assert!(wt.join(&rel).exists(), "the summary is still on disk");
nothing_staged(wt);
}
#[test]
fn a_staged_but_uncommitted_summary_is_already_this_passs_product() {
let dir = repo_with("messages/002-user.md");
let wt = dir.path();
let rel = write_summary(wt, "body\n").unwrap();
RealGit::new().run(wt, &["add", "-A"]).unwrap();
let err = mark_for_deletion(wt, AGENT, &rel, &RealGit::new()).unwrap_err();
assert!(
matches!(&err, Error::NotCompactionEligible { path, .. } if *path == rel),
"{err:?}"
);
assert!(wt.join(&rel).exists());
}
#[test]
fn an_untracked_summary_is_taken_by_the_existence_decline_and_survives() {
let dir = repo_with("messages/002-user.md");
let wt = dir.path();
let rel = write_summary(wt, "body\n").unwrap();
let err = mark_for_deletion(wt, AGENT, &rel, &RealGit::new()).unwrap_err();
assert!(
matches!(
err,
Error::Git {
op: "mark_for_deletion rm",
..
}
),
"{err:?}"
);
assert!(wt.join(&rel).exists(), "the summary is still on disk");
nothing_staged(wt);
}
#[test]
fn an_earlier_passs_summary_is_still_nominable() {
let dir = repo_with("summary/001.md");
let wt = dir.path();
mark_for_deletion(wt, AGENT, "summary/001.md", &RealGit::new()).unwrap();
assert!(!wt.join("summary/001.md").exists());
let staged = RealGit::new()
.run_capture(wt, &["diff", "--cached", "--name-status"])
.unwrap();
assert!(staged.starts_with('D'), "staged deletion: {staged:?}");
}
#[test]
fn a_summary_seq_this_pass_rewrote_is_this_passs_product() {
let dir = repo_with("summary/001.md");
let wt = dir.path();
mark_for_deletion(wt, AGENT, "summary/001.md", &RealGit::new()).unwrap();
let rel = write_summary(wt, "this pass's view\n").unwrap();
assert_eq!(rel, "summary/001.md");
commit_side_effect(wt);
let err = mark_for_deletion(wt, AGENT, &rel, &RealGit::new()).unwrap_err();
assert!(
matches!(&err, Error::NotCompactionEligible { path, .. } if *path == rel),
"{err:?}"
);
assert_eq!(
std::fs::read_to_string(wt.join(&rel)).unwrap(),
"this pass's view\n"
);
}
#[test]
fn a_tree_with_no_dispatch_commit_has_no_product_of_its_own() {
let dir = tempfile::TempDir::new().unwrap();
let (wt, git) = (dir.path(), RealGit::new());
git.run(wt, &["init", "-b", "agents/p1"]).unwrap();
git.run(wt, &["config", "user.email", "t@t"]).unwrap();
git.run(wt, &["config", "core.hooksPath", "/dev/null"])
.unwrap();
git.run(wt, &["config", "user.name", "t"]).unwrap();
std::fs::write(wt.join("keep.txt"), "x").unwrap();
git.run(wt, &["add", "-A"]).unwrap();
git.run(wt, &["commit", "-m", "unfounded"]).unwrap();
let rel = write_summary(wt, "body\n").unwrap();
assert!(
not_compaction_eligible(wt, AGENT, &rel, &git)
.unwrap()
.is_none()
);
}
pub(super) struct OneCallFails {
pub(super) fails: &'static str,
pub(super) founding: String,
pub(super) seen: RefCell<Vec<String>>,
}
impl GitRunner for OneCallFails {
fn run(&self, _dir: &std::path::Path, _args: &[&str]) -> std::io::Result<()> {
unreachable!("the decline precedes every write")
}
fn run_capture(&self, _dir: &std::path::Path, args: &[&str]) -> std::io::Result<String> {
self.seen.borrow_mut().push(args.join(" "));
match args.first() {
Some(v) if *v == self.fails => Err(std::io::Error::other("boom")),
Some(&"log") => Ok(self.founding.clone()),
_ => Ok(String::new()),
}
}
}
#[test]
fn a_failed_own_product_diff_surfaces_as_a_git_error() {
let git = OneCallFails {
fails: "diff",
founding: "cafe1234\n".into(),
seen: RefCell::new(Vec::new()),
};
let err = mark_for_deletion(
std::path::Path::new("/nowhere"),
AGENT,
"summary/001.md",
&git,
)
.unwrap_err();
assert!(
matches!(
err,
Error::Git {
op: "mark_for_deletion own-product diff",
..
}
),
"{err:?}"
);
let seen = git.seen.borrow();
assert!(seen.iter().any(|a| a.contains("cafe1234")), "{seen:?}");
}