use std::process::Command;
use std::sync::atomic::{AtomicU64, Ordering};
fn ev() -> Command {
Command::new(env!("CARGO_BIN_EXE_ev"))
}
fn repo_with_commit(subject: &str, body: &str) -> std::path::PathBuf {
static N: AtomicU64 = AtomicU64::new(0);
let p = std::env::temp_dir().join(format!(
"ev-fromgit-{}-{}",
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(),
] {
assert!(Command::new("git")
.args(args)
.current_dir(&p)
.output()
.unwrap()
.status
.success());
}
let message = format!("{subject}\n\n{body}");
assert!(Command::new("git")
.args(["commit", "--allow-empty", "-m", &message])
.current_dir(&p)
.output()
.unwrap()
.status
.success());
assert!(ev()
.arg("init")
.current_dir(&p)
.output()
.unwrap()
.status
.success());
p
}
fn recorded_id(out: &std::process::Output) -> String {
String::from_utf8_lossy(&out.stdout)
.split_whitespace()
.nth(1)
.unwrap()
.to_string()
}
fn git_repo_with_subject(subject: &str) -> (std::path::PathBuf, String) {
let p = repo_with_commit(subject, "");
let head = String::from_utf8_lossy(
&Command::new("git")
.args(["rev-parse", "HEAD"])
.current_dir(&p)
.output()
.unwrap()
.stdout,
)
.trim()
.to_string();
(p, head)
}
fn decide_from_git(repo: &std::path::Path, commit: &str, extra: &[&str]) -> String {
let mut args = vec!["decide", "--from-git", commit];
args.extend_from_slice(extra);
let out = ev().args(&args).current_dir(repo).output().unwrap();
assert!(
out.status.success(),
"stderr: {}",
String::from_utf8_lossy(&out.stderr)
);
recorded_id(&out)
}
fn read_tick_json(repo: &std::path::Path, id: &str) -> serde_json::Value {
let raw = std::fs::read_to_string(repo.join(".evolving/ticks").join(id)).unwrap();
serde_json::from_str(&raw).unwrap()
}
#[test]
fn decide_should_take_the_decision_from_the_commit_subject_when_from_git_is_used() {
let r = repo_with_commit("freeze v1.8; reject v1.9", "Refs #1194");
let out = ev()
.args([
"decide",
"--from-git",
"HEAD",
"--assume",
"team agreed",
"--reject",
"v1.9: re-milestoned without sign-off",
"--authority",
"user-ruled",
"--blame",
"Wang Yu",
])
.current_dir(&r)
.output()
.unwrap();
assert!(
out.status.success(),
"stderr: {}",
String::from_utf8_lossy(&out.stderr)
);
let id = recorded_id(&out);
let raw = std::fs::read_to_string(r.join(".evolving/ticks").join(&id)).unwrap();
let v: serde_json::Value = serde_json::from_str(&raw).unwrap();
assert_eq!(v["decision"], "freeze v1.8; reject v1.9");
assert!(
v["observe"].as_str().unwrap().contains("Refs #1194"),
"observe was {:?}",
v["observe"]
);
}
#[test]
fn decide_should_still_take_an_explicit_positional_decision_when_from_git_is_absent() {
let r = repo_with_commit("ignored subject", "Refs #9");
let out = ev()
.args([
"decide",
"explicit text",
"--assume",
"y",
"--revisit",
"Q3",
"--blame",
"Z",
])
.current_dir(&r)
.output()
.unwrap();
assert!(
out.status.success(),
"stderr: {}",
String::from_utf8_lossy(&out.stderr)
);
let id = recorded_id(&out);
let raw = std::fs::read_to_string(r.join(".evolving/ticks").join(&id)).unwrap();
let v: serde_json::Value = serde_json::from_str(&raw).unwrap();
assert_eq!(v["decision"], "explicit text");
}
#[test]
fn decide_should_fail_when_both_a_positional_decision_and_from_git_are_given() {
let r = repo_with_commit("subject", "Refs #1");
let out = ev()
.args([
"decide",
"explicit text",
"--from-git",
"HEAD",
"--assume",
"y",
"--blame",
"Z",
])
.current_dir(&r)
.output()
.unwrap();
assert!(!out.status.success());
}
#[test]
fn decide_should_fail_when_the_commit_cannot_be_read() {
let r = repo_with_commit("subject", "Refs #1");
let out = ev()
.args([
"decide",
"--from-git",
"deadbeef",
"--assume",
"y",
"--blame",
"Z",
])
.current_dir(&r)
.output()
.unwrap();
assert!(!out.status.success());
}
#[test]
fn from_git_should_take_blame_from_a_role_prefix_when_the_subject_has_one() {
let (r, _head) = git_repo_with_subject("Product: re-milestone #1194 R2415");
let id = decide_from_git(&r, "HEAD", &["--assume", "x"]);
let v = read_tick_json(&r, &id);
assert_eq!(v["blame"], "Product");
assert!(v["observe"].as_str().unwrap().contains("#1194"));
assert!(v["observe"].as_str().unwrap().contains("R2415"));
}