use std::process::Command;
use std::sync::atomic::{AtomicU64, Ordering};
fn ev() -> Command {
Command::new(env!("CARGO_BIN_EXE_ev"))
}
fn git_repo() -> (std::path::PathBuf, String) {
static N: AtomicU64 = AtomicU64::new(0);
let p = std::env::temp_dir().join(format!(
"ev-checkrun-{}-{}",
std::process::id(),
N.fetch_add(1, Ordering::Relaxed)
));
let _ = std::fs::remove_dir_all(&p);
std::fs::create_dir_all(&p).unwrap();
for args in [
["init"].as_slice(),
["config", "user.email", "t@e.st"].as_slice(),
["config", "user.name", "Tester"].as_slice(),
["commit", "--allow-empty", "-m", "init"].as_slice(),
] {
Command::new("git")
.args(args)
.current_dir(&p)
.output()
.unwrap();
}
let head = String::from_utf8(
Command::new("git")
.args(["rev-parse", "HEAD"])
.current_dir(&p)
.output()
.unwrap()
.stdout,
)
.unwrap()
.trim()
.to_string();
assert!(ev()
.arg("init")
.current_dir(&p)
.output()
.unwrap()
.status
.success());
(p, head)
}
fn decide_bound(repo: &std::path::Path, cmd: &str, counter: &str, sha: &str) {
let out = ev()
.args([
"decide",
"d",
"--assume",
"c",
"--assume-test",
cmd,
"--counter-test",
counter,
"--on-platform",
"local",
"--triggered-by",
"f",
"--surface",
"s",
"--verified-at-sha",
sha,
"--blame",
"Wang Yu",
])
.current_dir(repo)
.output()
.unwrap();
assert!(
out.status.success(),
"decide failed: {}",
String::from_utf8_lossy(&out.stderr)
);
}
#[test]
fn check_run_should_record_green_and_pass_when_the_bound_test_succeeds() {
let (r, head) = git_repo();
decide_bound(&r, "true", "false", &head);
let out = ev()
.args(["check", "--run", "--platform", "local", "--exit-on-red"])
.current_dir(&r)
.output()
.unwrap();
assert!(
out.status.success(),
"stdout: {}",
String::from_utf8_lossy(&out.stdout)
);
assert!(String::from_utf8_lossy(&out.stdout).contains("green"));
}
#[test]
fn check_run_should_record_red_and_gate_when_the_bound_test_fails() {
let (r, head) = git_repo();
decide_bound(&r, "false", "true", &head);
let out = ev()
.args(["check", "--run", "--platform", "local", "--exit-on-red"])
.current_dir(&r)
.output()
.unwrap();
assert!(!out.status.success());
assert!(String::from_utf8_lossy(&out.stdout).contains("red"));
}
fn canonical_red_check(provenance: &str) -> String {
format!(
"{{\"kind\":\"ev-decision-intake\",\"decision\":\"a ruling\",\
\"grounds\":[{{\"claim\":\"holds\",\"supports\":\"chosen\",\
\"check\":{{\"by\":\"test\",\"ref\":\"false\",\
\"verified_at_sha\":\"d308afac1b2c3d4e5f60718293a4b5c6d7e8f901\",\"counter_test\":\"true\",\
\"liveness\":{{\"platforms\":[\"local\"],\"triggered_by\":[\"f\"],\"surfaces\":[\"s\"]}}}}}}],\
\"blame\":\"agent-runner\",\"provenance\":\"{provenance}\",\"source_ref\":\"R-ap1\"}}\n"
)
}
fn migrate_canonical(repo: &std::path::Path, body: &str) {
let path = repo.join("intake.jsonl");
std::fs::write(&path, body).unwrap();
let out = ev()
.args([
"migrate",
"--source",
&format!("canonical:{}", path.display()),
])
.current_dir(repo)
.output()
.unwrap();
assert!(
out.status.success(),
"migrate failed: {}",
String::from_utf8_lossy(&out.stderr)
);
}
#[test]
fn check_should_not_flip_exit_on_red_when_the_tick_is_agent_proposed_even_if_red() {
let (r, _head) = git_repo();
migrate_canonical(&r, &canonical_red_check("agent-proposed"));
let out = ev()
.args(["check", "--run", "--platform", "local", "--exit-on-red"])
.current_dir(&r)
.output()
.unwrap();
let stdout = String::from_utf8_lossy(&out.stdout);
assert!(
out.status.success(),
"an agent-proposed red must not gate; stdout: {stdout}"
);
assert!(
stdout.contains("memo"),
"the agent-proposed red must surface as memo, not vanish; stdout: {stdout}"
);
}
#[test]
fn check_should_still_flip_exit_on_red_when_the_tick_is_human_authored() {
let (r, _head) = git_repo();
migrate_canonical(&r, &canonical_red_check("imported"));
let out = ev()
.args(["check", "--run", "--platform", "local", "--exit-on-red"])
.current_dir(&r)
.output()
.unwrap();
let stdout = String::from_utf8_lossy(&out.stdout);
assert!(
!out.status.success(),
"a human-authored red must gate; stdout: {stdout}"
);
assert!(stdout.contains("red"), "stdout: {stdout}");
}
#[test]
fn check_run_should_leave_other_platforms_not_run_when_only_local_is_run() {
let (r, head) = git_repo();
decide_bound(&r, "true", "false", &head);
let out = ev()
.args([
"check",
"--run",
"--platform",
"ship-image",
"--exit-on-red",
])
.current_dir(&r)
.output()
.unwrap();
assert!(!out.status.success());
assert!(String::from_utf8_lossy(&out.stdout).contains("not-run"));
}