use std::path::{Path, PathBuf};
use std::process::Command;
use std::sync::atomic::{AtomicU64, Ordering};
struct TempRepo(PathBuf);
impl TempRepo {
fn new() -> Self {
static COUNTER: AtomicU64 = AtomicU64::new(0);
let root = std::env::temp_dir().join(format!(
"tc-e2e-verify-e2e-{}-{}",
std::process::id(),
COUNTER.fetch_add(1, Ordering::Relaxed),
));
std::fs::create_dir_all(&root).unwrap();
git(&root, &["init", "-q"]);
git(&root, &["config", "user.email", "test@example.com"]);
git(&root, &["config", "user.name", "Test"]);
git(&root, &["config", "commit.gpgsign", "false"]);
std::fs::write(root.join("README.md"), "seed\n").unwrap();
git(&root, &["add", "."]);
git(
&root,
&["-c", "commit.gpgsign=false", "commit", "-q", "-m", "seed"],
);
git(&root, &["checkout", "-q", "-b", "work"]);
TempRepo(root)
}
fn commit_code(&self, name: &str, contents: &str) {
let full = self.0.join(name);
std::fs::create_dir_all(full.parent().unwrap()).unwrap();
std::fs::write(&full, contents).unwrap();
git(&self.0, &["add", name]);
git(
&self.0,
&["-c", "commit.gpgsign=false", "commit", "-q", "-m", "code"],
);
}
fn head(&self) -> String {
let out = Command::new("git")
.args(["rev-parse", "HEAD"])
.current_dir(&self.0)
.output()
.expect("git rev-parse should run");
String::from_utf8(out.stdout).unwrap().trim().to_string()
}
}
impl Drop for TempRepo {
fn drop(&mut self) {
let _ = std::fs::remove_dir_all(&self.0);
}
}
fn git(dir: &Path, args: &[&str]) {
let status = Command::new("git")
.args(args)
.current_dir(dir)
.status()
.expect("git should run");
assert!(status.success(), "git {args:?} failed");
}
fn run_cli(cwd: &Path, args: &[&str]) -> (i32, String) {
let out = Command::new(env!("CARGO_BIN_EXE_testing-conventions"))
.args(args)
.current_dir(cwd)
.output()
.expect("the built binary should run");
let text = format!(
"{}{}",
String::from_utf8_lossy(&out.stdout),
String::from_utf8_lossy(&out.stderr)
);
(out.status.code().expect("an exit code"), text)
}
#[test]
fn verify_exits_zero_on_a_committed_receipt() {
let repo = TempRepo::new();
let (code, _) = run_cli(&repo.0, &["e2e", "attest", "true"]);
assert_eq!(code, 0);
let (code, text) = run_cli(&repo.0, &["e2e", "verify"]);
assert_eq!(code, 0, "a committed receipt should pass: {text}");
}
#[test]
fn verify_exits_nonzero_with_the_attest_hint_when_missing() {
let repo = TempRepo::new();
let (code, text) = run_cli(&repo.0, &["e2e", "verify"]);
assert_eq!(code, 1, "no receipt should fail");
assert!(
text.contains("e2e attest"),
"the failure names the fix: {text}"
);
}
#[test]
fn verify_with_path_argument_reads_the_package_receipts() {
let repo = TempRepo::new();
let package = repo.0.join("packages/widget");
std::fs::create_dir_all(&package).unwrap();
repo.commit_code("packages/widget/widget.rs", "pub fn widget() {}\n");
let (code, _) = run_cli(&package, &["e2e", "attest", "true"]);
assert_eq!(code, 0);
let (code, text) = run_cli(&repo.0, &["e2e", "verify", "packages/widget"]);
assert_eq!(code, 0, "the package's receipt should pass: {text}");
let (code, _) = run_cli(&repo.0, &["e2e", "verify"]);
assert_eq!(code, 1, "discovery is scoped to the path argument");
}
#[test]
fn verify_with_base_and_scope_ignores_a_change_outside_the_scope() {
let repo = TempRepo::new();
let package = repo.0.join("packages/widget");
std::fs::create_dir_all(package.join("src")).unwrap();
repo.commit_code("packages/widget/src/widget.rs", "pub fn widget() {}\n");
let (code, _) = run_cli(&package, &["e2e", "attest", "true"]);
assert_eq!(code, 0);
let base = repo.head();
repo.commit_code("packages/widget/tests/widget_test.rs", "// test\n");
let (code, text) = run_cli(
&repo.0,
&[
"e2e",
"verify",
"packages/widget",
"--scope",
"packages/widget/src",
"--base",
&base,
],
);
assert_eq!(code, 0, "a change outside --scope owes no decision: {text}");
}
#[test]
fn verify_with_base_demands_a_receipt_for_a_scoped_change() {
let repo = TempRepo::new();
let package = repo.0.join("packages/widget");
std::fs::create_dir_all(package.join("src")).unwrap();
repo.commit_code("packages/widget/src/widget.rs", "pub fn widget() {}\n");
let (code, _) = run_cli(&package, &["e2e", "attest", "true"]);
assert_eq!(code, 0);
let base = repo.head();
repo.commit_code(
"packages/widget/src/widget.rs",
"pub fn widget() { /* v2 */ }\n",
);
let (code, text) = run_cli(
&repo.0,
&["e2e", "verify", "packages/widget", "--base", &base],
);
assert_eq!(code, 1, "an unanswered scoped change fails");
assert!(
text.contains("e2e attest"),
"the failure names the fix: {text}"
);
let (code, _) = run_cli(&package, &["e2e", "attest", "true"]);
assert_eq!(code, 0);
let (code, text) = run_cli(
&repo.0,
&["e2e", "verify", "packages/widget", "--base", &base],
);
assert_eq!(code, 0, "the branch's receipt answers the nudge: {text}");
}
#[test]
fn verify_with_extra_scope_demands_a_receipt_for_a_core_change() {
let repo = TempRepo::new();
let package = repo.0.join("packages/python");
std::fs::create_dir_all(package.join("src")).unwrap();
repo.commit_code("packages/python/src/lib.rs", "pub fn binding() {}\n");
repo.commit_code("packages/rust/src/core.rs", "pub fn core() {}\n");
repo.commit_code("packages/rust/src/cli/main.rs", "pub fn cli() {}\n");
let (code, _) = run_cli(&package, &["e2e", "attest", "true"]);
assert_eq!(code, 0);
let base = repo.head();
repo.commit_code("packages/rust/src/core.rs", "pub fn core() { /* v2 */ }\n");
let (code, _) = run_cli(
&repo.0,
&[
"e2e",
"verify",
"packages/python",
"--base",
&base,
"--extra-scope",
"packages/rust/src",
"--exclude",
"packages/rust/src/cli",
],
);
assert_eq!(
code, 1,
"a non-excluded core change owes the binding a decision"
);
}
#[test]
fn verify_with_extra_scope_exits_zero_on_an_excluded_change() {
let repo = TempRepo::new();
let package = repo.0.join("packages/python");
std::fs::create_dir_all(package.join("src")).unwrap();
repo.commit_code("packages/python/src/lib.rs", "pub fn binding() {}\n");
repo.commit_code("packages/rust/src/cli/main.rs", "pub fn cli() {}\n");
let (code, _) = run_cli(&package, &["e2e", "attest", "true"]);
assert_eq!(code, 0);
let base = repo.head();
repo.commit_code(
"packages/rust/src/cli/main.rs",
"pub fn cli() { /* v2 */ }\n",
);
let (code, text) = run_cli(
&repo.0,
&[
"e2e",
"verify",
"packages/python",
"--base",
&base,
"--extra-scope",
"packages/rust/src",
"--exclude",
"packages/rust/src/cli",
],
);
assert_eq!(code, 0, "an excluded change owes no decision: {text}");
}
#[test]
fn verify_with_a_scope_matching_no_tracked_path_errors_loudly() {
let repo = TempRepo::new();
let package = repo.0.join("packages/widget");
std::fs::create_dir_all(package.join("src")).unwrap();
repo.commit_code("packages/widget/src/widget.rs", "pub fn widget() {}\n");
let (code, _) = run_cli(&package, &["e2e", "attest", "true"]);
assert_eq!(code, 0);
let base = repo.head();
repo.commit_code(
"packages/widget/src/widget.rs",
"pub fn widget() { /* v2 */ }\n",
);
let (code, text) = run_cli(
&repo.0,
&[
"e2e",
"verify",
"packages/widget",
"--scope",
"packages/widget/ghost",
"--base",
&base,
],
);
assert_ne!(code, 0, "a bogus --scope must fail");
assert!(
text.contains("scope"),
"the error should name the bad scope: {text}"
);
}