use anodizer_core::DeterminismReport;
use std::fs;
use std::process::Command;
use tempfile::TempDir;
#[test]
fn check_determinism_help_lists_every_flag() {
let output = Command::new(env!("CARGO_BIN_EXE_anodizer"))
.args(["check", "determinism", "--help"])
.output()
.expect("invoking anodize check determinism --help");
assert!(
output.status.success(),
"--help exited non-zero: stderr={}",
String::from_utf8_lossy(&output.stderr)
);
let stdout = String::from_utf8_lossy(&output.stdout);
for flag in &[
"--runs",
"--stages",
"--report",
"--snapshot",
"--no-snapshot",
"--preserve-dist",
] {
assert!(
stdout.contains(flag),
"--help missing flag {}; full output: {}",
flag,
stdout
);
}
}
#[test]
fn check_determinism_errors_cleanly_outside_git_repo() {
let tmp = TempDir::new().unwrap();
let output = Command::new(env!("CARGO_BIN_EXE_anodizer"))
.args(["check", "determinism", "--runs", "1"])
.current_dir(tmp.path())
.output()
.expect("invoking anodize check determinism");
assert!(
!output.status.success(),
"expected non-zero exit outside a git repo; stdout={} stderr={}",
String::from_utf8_lossy(&output.stdout),
String::from_utf8_lossy(&output.stderr)
);
}
#[test]
fn check_determinism_respects_report_flag_in_error_path() {
let tmp = TempDir::new().unwrap();
let report = tmp.path().join("custom-report.json");
let output = Command::new(env!("CARGO_BIN_EXE_anodizer"))
.args(["check", "determinism", "--runs", "1", "--report"])
.arg(&report)
.current_dir(tmp.path())
.output()
.expect("invoking anodize check determinism");
assert!(!output.status.success());
let stderr = String::from_utf8_lossy(&output.stderr);
assert!(
!stderr.contains("panicked"),
"binary panicked instead of erroring cleanly: {}",
stderr
);
}
#[test]
fn inject_drift_rejected_without_test_harness_env() {
let tmp = TempDir::new().unwrap();
let output = Command::new(env!("CARGO_BIN_EXE_anodizer"))
.args([
"check",
"determinism",
"--runs",
"1",
"--inject-drift",
"archive",
])
.current_dir(tmp.path())
.env_remove("ANODIZE_TEST_HARNESS")
.output()
.expect("invoking anodize check determinism --inject-drift");
assert!(
!output.status.success(),
"expected non-zero exit when --inject-drift is set without ANODIZE_TEST_HARNESS=1"
);
let stderr = String::from_utf8_lossy(&output.stderr);
assert!(
stderr.contains("--inject-drift") && stderr.contains("ANODIZE_TEST_HARNESS"),
"expected error citing both --inject-drift and ANODIZE_TEST_HARNESS; got: {}",
stderr
);
}
#[test]
fn inject_drift_hidden_from_help() {
let output = Command::new(env!("CARGO_BIN_EXE_anodizer"))
.args(["check", "determinism", "--help"])
.output()
.expect("invoking anodize check determinism --help");
let stdout = String::from_utf8_lossy(&output.stdout);
assert!(
!stdout.contains("--inject-drift"),
"--inject-drift must not appear in --help output: {}",
stdout
);
}
mod common;
use common::{bootstrap_minimal_cargo_repo, tool_on_path};
#[test]
fn inject_drift_archive_reports_drift_on_minimal_workspace() {
if !tool_on_path("cargo") || !tool_on_path("git") {
eprintln!(
"SKIP inject_drift_archive_reports_drift_on_minimal_workspace: \
cargo or git missing from PATH"
);
return;
}
let tmp = TempDir::new().unwrap();
let repo = tmp.path();
bootstrap_minimal_cargo_repo(repo, "anodize-det-fixture");
let report_path = repo.join("det.json");
let output = Command::new(env!("CARGO_BIN_EXE_anodizer"))
.args([
"check",
"determinism",
"--runs",
"2",
"--stages",
"build,archive",
"--inject-drift",
"archive",
"--report",
])
.arg(&report_path)
.current_dir(repo)
.env("ANODIZE_TEST_HARNESS", "1")
.output()
.expect("invoking anodize check determinism");
assert!(
!output.status.success(),
"expected non-zero exit on drift; stdout={} stderr={}",
String::from_utf8_lossy(&output.stdout),
String::from_utf8_lossy(&output.stderr)
);
assert!(
report_path.exists(),
"report file missing at {}; stderr was: {}",
report_path.display(),
String::from_utf8_lossy(&output.stderr)
);
let json = fs::read_to_string(&report_path).unwrap();
let report: DeterminismReport =
serde_json::from_str(&json).unwrap_or_else(|e| panic!("parsing report JSON: {e}\n{json}"));
assert_eq!(report.schema_version, 1, "schema_version pinned at 1");
assert_eq!(report.runs, 2, "harness ran exactly --runs=2 times");
assert!(
report.drift_count > 0,
"expected drift_count > 0 after --inject-drift=archive; report: {:?}\nstderr: {}",
report,
String::from_utf8_lossy(&output.stderr)
);
assert!(
!report.drift.is_empty(),
"drift list non-empty alongside drift_count > 0"
);
assert!(
report
.drift
.iter()
.any(|d| d.artifact.ends_with(".tar.gz") || d.artifact.ends_with(".zip")),
"at least one drift row should be an archive artifact; got: {:?}",
report.drift.iter().map(|d| &d.artifact).collect::<Vec<_>>()
);
}