use std::path::Path;
use std::process::Command;
const BIN: &str = env!("CARGO_BIN_EXE_roteiro");
fn git(dir: &Path, args: &[&str]) {
let status = Command::new("git")
.args([
"-c",
"user.name=Test",
"-c",
"user.email=test@example.com",
"-c",
"commit.gpgsign=false",
"-c",
"init.defaultBranch=main",
])
.args(args)
.current_dir(dir)
.status()
.expect("run git");
assert!(status.success(), "git {args:?} failed");
}
fn roteiro(dir: &Path, args: &[&str]) -> std::process::Output {
Command::new(BIN)
.args(args)
.current_dir(dir)
.output()
.expect("run roteiro")
}
fn json(out: &std::process::Output) -> serde_json::Value {
assert!(out.status.success(), "command failed: {out:?}");
serde_json::from_slice(&out.stdout).expect("valid JSON")
}
#[test]
fn dependency_change_invalidates_dependent_context() {
let dir = std::env::temp_dir().join(format!("roteiro-ctx-cli-{}", std::process::id()));
std::fs::remove_dir_all(&dir).ok();
std::fs::create_dir_all(dir.join("src")).expect("mkdir");
std::fs::write(dir.join("src/callee.rs"), "pub fn callee() -> u32 { 1 }\n").expect("write");
std::fs::write(
dir.join("src/caller.rs"),
"use crate::callee::callee;\npub fn caller() -> u32 { callee() }\n",
)
.expect("write");
std::fs::write(dir.join("src/lib.rs"), "pub mod callee;\npub mod caller;\n").expect("write");
git(&dir, &["init", "-q"]);
git(&dir, &["add", "."]);
git(&dir, &["commit", "-q", "-m", "init"]);
let caller_key = "sym:rust:src/caller.rs#caller";
let first = json(&roteiro(&dir, &["context", caller_key, "--json"]));
let fp_before = first["fingerprint"]
.as_str()
.expect("fingerprint")
.to_owned();
let calls_callee = first["outgoing"]
.as_array()
.into_iter()
.flatten()
.any(|e| e["node"].as_str().is_some_and(|n| n.contains("#callee")));
assert!(calls_callee, "caller should call callee: {first}");
let clean = json(&roteiro(&dir, &["context", "--refresh", "--json"]));
assert_eq!(clean["rebuilt"], 0, "nothing changed yet: {clean}");
assert!(clean["reused"].as_u64().expect("reused") >= 1);
std::fs::write(dir.join("src/callee.rs"), "pub fn callee() -> u32 { 42 }\n").expect("write");
git(&dir, &["add", "."]);
git(&dir, &["commit", "-q", "-m", "change callee"]);
let after = json(&roteiro(&dir, &["context", "--refresh", "--json"]));
assert!(
after["rebuilt"].as_u64().expect("rebuilt") >= 1,
"the dependent's context must be rebuilt: {after}",
);
let refetched = json(&roteiro(&dir, &["context", caller_key, "--json"]));
assert_ne!(
fp_before,
refetched["fingerprint"].as_str().expect("fingerprint"),
"dependent fingerprint must change when its dependency changes",
);
std::fs::remove_dir_all(&dir).ok();
}