use ev::store::Store;
use ev::tick::{Ground, Tick};
use std::process::Command;
use std::sync::atomic::{AtomicU64, Ordering};
fn ev() -> Command {
Command::new(env!("CARGO_BIN_EXE_ev"))
}
fn row_label(stdout: &str) -> Option<&str> {
stdout
.lines()
.find(|l| l.contains('\t'))
.and_then(|l| l.split('\t').next())
}
fn git_repo() -> (std::path::PathBuf, String) {
static N: AtomicU64 = AtomicU64::new(0);
let p = std::env::temp_dir().join(format!(
"ev-harvested-{}-{}",
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();
Store::at(&p).init().unwrap();
(p, head)
}
fn write_harvested(repo: &std::path::Path, reference: &str, sha: &str) -> String {
let store = Store::at(repo);
let check = ev::capture::harvested_test_check(
reference.into(),
sha.into(),
vec!["local".into()],
vec!["f".into()],
vec!["s".into()],
)
.expect("full liveness present → well-formed harvested binding");
let mut t = Tick {
id: String::new(),
parent_id: String::new(),
observe: "migrated from gitlog".into(),
decision: "no Redis".into(),
grounds: vec![Ground {
claim: "Argus introduces no Redis".into(),
supports: "chosen".into(),
check: Some(check),
}],
status: "live".into(),
held_since: "".into(),
blame: "Wang Yu".into(),
authority: None,
jurisdiction: None,
round_id: None,
};
t.id = ev::canonical::compute_id(&t);
store.write_tick(&t).unwrap();
t.id
}
#[test]
fn check_should_annotate_a_harvested_row_when_counter_test_is_absent() {
let (r, head) = git_repo();
let id = write_harvested(&r, "true", &head);
let out = ev().arg("check").current_dir(&r).output().unwrap();
let stdout = String::from_utf8_lossy(&out.stdout);
assert!(
stdout.contains("harvested — falsifiability not proven"),
"row not annotated as harvested: {stdout}"
);
assert!(
stdout.contains("harvested-unproven: 1 of 1 test bindings have no counter-test (run ev guard to add one)"),
"missing/incorrect debt line: {stdout}"
);
let log = std::fs::read_to_string(r.join(".evolving/results/events.jsonl")).unwrap();
assert!(
log.lines()
.any(|l| l.contains("\"op\":\"harvested\"") && l.contains(&id)),
"no harvested event for {id}: {log}"
);
}
#[test]
fn check_should_read_a_passing_harvested_test_green_when_run() {
let (r, head) = git_repo();
write_harvested(&r, "true", &head);
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 passing harvested test must not gate: {stdout}"
);
assert!(
row_label(&stdout) == Some("green"),
"expected a green verdict label: {stdout}"
);
assert!(
stdout.contains("harvested — falsifiability not proven"),
"harvested debt must stay visible even when green: {stdout}"
);
}
#[test]
fn check_should_gate_on_a_real_red_harvested_test_when_run() {
let (r, head) = git_repo();
write_harvested(&r, "false", &head);
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 red harvested test must gate: {stdout}"
);
assert!(
row_label(&stdout) == Some("red"),
"expected a red verdict label, not unproven: {stdout}"
);
}