use std::process::Command;
use std::sync::atomic::{AtomicU64, Ordering};
fn ev() -> Command {
Command::new(env!("CARGO_BIN_EXE_ev"))
}
fn repo() -> std::path::PathBuf {
static N: AtomicU64 = AtomicU64::new(0);
let p = std::env::temp_dir().join(format!(
"ev-brief-{}-{}",
std::process::id(),
N.fetch_add(1, Ordering::Relaxed)
));
let _ = std::fs::remove_dir_all(&p);
std::fs::create_dir_all(&p).unwrap();
assert!(ev()
.arg("init")
.current_dir(&p)
.output()
.unwrap()
.status
.success());
p
}
fn decide(repo: &std::path::Path, text: &str, extra: &[&str]) -> String {
let mut args: Vec<&str> = vec!["decide", text, "--assume", "a reason", "--blame", "Wang Yu"];
args.extend_from_slice(extra);
let out = ev().args(&args).current_dir(repo).output().unwrap();
assert!(
out.status.success(),
"decide: {}",
String::from_utf8_lossy(&out.stderr)
);
String::from_utf8_lossy(&out.stdout)
.split_whitespace()
.nth(1)
.unwrap()
.to_string()
}
#[test]
fn brief_should_show_a_user_ruled_decision_and_its_rejected_road_when_one_is_recorded() {
let r = repo();
decide(
&r,
"keep the slice locked",
&[
"--authority",
"user-ruled",
"--reject",
"v1.9: re-milestoned without sign-off",
],
);
let out = ev().arg("brief").current_dir(&r).output().unwrap();
assert!(out.status.success());
let stdout = String::from_utf8_lossy(&out.stdout);
assert!(stdout.contains("keep the slice locked"));
assert!(stdout.contains("[user-ruled]"));
assert!(stdout.contains("rejected v1.9"));
}
#[test]
fn brief_should_omit_a_decision_that_is_not_user_ruled_when_briefing() {
let r = repo();
decide(&r, "a disposable decision", &[]);
let out = ev().arg("brief").current_dir(&r).output().unwrap();
assert!(out.status.success());
let stdout = String::from_utf8_lossy(&out.stdout);
assert!(!stdout.contains("a disposable decision"));
assert!(stdout.contains("no user-ruled decisions"));
}
#[test]
fn brief_should_accept_a_limit_flag_when_one_is_passed() {
let r = repo();
decide(&r, "keep the slice locked", &["--authority", "user-ruled"]);
let out = ev()
.args(["brief", "--limit", "1"])
.current_dir(&r)
.output()
.unwrap();
assert!(out.status.success());
let stdout = String::from_utf8_lossy(&out.stdout);
assert!(stdout.contains("keep the slice locked"));
}
#[test]
fn brief_should_order_user_ruled_decisions_most_recent_first_when_multiple_exist() {
let r = repo();
decide(&r, "decision A", &["--authority", "user-ruled"]);
decide(&r, "decision B", &["--authority", "user-ruled"]);
let out = ev().arg("brief").current_dir(&r).output().unwrap();
assert!(out.status.success());
let stdout = String::from_utf8_lossy(&out.stdout);
let b = stdout.find("decision B").expect("B shown");
let a = stdout.find("decision A").expect("A shown");
assert!(b < a, "B should appear before A:\n{stdout}");
}
#[test]
fn brief_should_cap_and_note_the_remainder_when_over_the_limit() {
let r = repo();
decide(&r, "decision one", &["--authority", "user-ruled"]);
decide(&r, "decision two", &["--authority", "user-ruled"]);
decide(&r, "decision three", &["--authority", "user-ruled"]);
let out = ev()
.args(["brief", "--limit", "2"])
.current_dir(&r)
.output()
.unwrap();
assert!(out.status.success());
let stdout = String::from_utf8_lossy(&out.stdout);
let shown = ["decision one", "decision two", "decision three"]
.iter()
.filter(|d| stdout.contains(**d))
.count();
assert_eq!(shown, 2, "exactly two decisions shown:\n{stdout}");
assert!(stdout.contains("1 more"), "remainder count:\n{stdout}");
assert!(stdout.contains("ev list"), "points at ev list:\n{stdout}");
}
#[test]
fn brief_should_show_all_when_limit_is_zero() {
let r = repo();
decide(&r, "decision one", &["--authority", "user-ruled"]);
decide(&r, "decision two", &["--authority", "user-ruled"]);
decide(&r, "decision three", &["--authority", "user-ruled"]);
let out = ev()
.args(["brief", "--limit", "0"])
.current_dir(&r)
.output()
.unwrap();
assert!(out.status.success());
let stdout = String::from_utf8_lossy(&out.stdout);
let shown = ["decision one", "decision two", "decision three"]
.iter()
.filter(|d| stdout.contains(**d))
.count();
assert_eq!(shown, 3, "all three shown:\n{stdout}");
assert!(!stdout.contains("more user-ruled"), "no footer:\n{stdout}");
}
#[test]
fn brief_should_fail_when_there_is_no_store() {
let p = std::env::temp_dir().join(format!("ev-brief-nostore-{}", std::process::id()));
let _ = std::fs::remove_dir_all(&p);
std::fs::create_dir_all(&p).unwrap();
let out = ev().arg("brief").current_dir(&p).output().unwrap();
assert!(!out.status.success());
}
#[test]
fn brief_should_pin_a_rejected_road_ruling_above_the_cap_over_newer_plain_rulings() {
let r = repo();
decide(
&r,
"the closed road",
&["--authority", "user-ruled", "--reject", "x: closed"],
);
decide(&r, "newer plain one", &["--authority", "user-ruled"]);
decide(&r, "newer plain two", &["--authority", "user-ruled"]);
decide(&r, "newer plain three", &["--authority", "user-ruled"]);
let out = ev()
.args(["brief", "--limit", "2"])
.current_dir(&r)
.output()
.unwrap();
assert!(out.status.success());
let stdout = String::from_utf8_lossy(&out.stdout);
assert!(
stdout.contains("the closed road"),
"load-bearing ruling must be pinned above the cap:\n{stdout}"
);
}
#[test]
fn brief_should_count_hidden_load_bearing_rulings_in_the_footer_when_they_exceed_the_cap() {
let r = repo();
decide(
&r,
"closed road one",
&["--authority", "user-ruled", "--reject", "a: one"],
);
decide(
&r,
"closed road two",
&["--authority", "user-ruled", "--reject", "b: two"],
);
decide(
&r,
"closed road three",
&["--authority", "user-ruled", "--reject", "c: three"],
);
let out = ev()
.args(["brief", "--limit", "1"])
.current_dir(&r)
.output()
.unwrap();
assert!(out.status.success());
let stdout = String::from_utf8_lossy(&out.stdout);
assert!(
stdout.contains("2 with rejected roads"),
"footer must count hidden load-bearing rulings:\n{stdout}"
);
}
#[test]
fn brief_should_not_mention_rejected_roads_in_the_footer_when_none_are_hidden() {
let r = repo();
decide(
&r,
"the closed road",
&["--authority", "user-ruled", "--reject", "x: closed"],
);
decide(&r, "plain one", &["--authority", "user-ruled"]);
decide(&r, "plain two", &["--authority", "user-ruled"]);
decide(&r, "plain three", &["--authority", "user-ruled"]);
let out = ev()
.args(["brief", "--limit", "2"])
.current_dir(&r)
.output()
.unwrap();
assert!(out.status.success());
let stdout = String::from_utf8_lossy(&out.stdout);
assert!(
stdout.contains("… 2 more user-ruled decision(s) — `ev list` for all"),
"footer must read exactly without rejected-roads clause:\n{stdout}"
);
assert!(
!stdout.contains("with rejected roads"),
"no hidden load-bearing ruling, so no rejected-roads clause:\n{stdout}"
);
}