use std::path::PathBuf;
use std::process::{Command, Output};
fn fixture_bundle() -> PathBuf {
PathBuf::from(env!("CARGO_MANIFEST_DIR"))
.join("../../tests/fixtures/evidence/test-bundle.tar.gz")
}
fn lint_with(fail_on: &str) -> Output {
Command::new(env!("CARGO_BIN_EXE_assay"))
.args(["evidence", "lint"])
.arg(fixture_bundle())
.args(["--format", "json", "--fail-on", fail_on])
.output()
.expect("failed to run assay")
}
fn lint_pack(pack: &str, fail_on: &str) -> Output {
Command::new(env!("CARGO_BIN_EXE_assay"))
.args(["evidence", "lint"])
.arg(fixture_bundle())
.args(["--pack", pack, "--format", "json", "--fail-on", fail_on])
.output()
.expect("failed to run assay")
}
const WARNING_PACK: &str = "eu-ai-act-baseline";
const ERROR_PACK: &str = "soc2-baseline";
#[test]
fn none_does_not_gate_an_error_finding() {
assert_eq!(
lint_pack(ERROR_PACK, "error").status.code(),
Some(1),
"fixture no longer yields an error finding under {ERROR_PACK}, so the next assertion proves nothing"
);
assert_eq!(
lint_pack(ERROR_PACK, "none").status.code(),
Some(0),
"--fail-on none gated an error finding, which is the defect this file exists for"
);
}
#[test]
fn a_threshold_changes_the_outcome_on_the_same_bundle() {
assert_eq!(
lint_pack(WARNING_PACK, "warn").status.code(),
Some(1),
"a warning finding did not gate at --fail-on warn"
);
assert_eq!(
lint_pack(WARNING_PACK, "none").status.code(),
Some(0),
"--fail-on none gated a run it was asked not to gate"
);
assert_eq!(
lint_pack(WARNING_PACK, "error").status.code(),
Some(0),
"a warning finding gated at --fail-on error, which fires only on errors"
);
}
#[test]
fn a_warning_bundle_does_not_pass_with_an_unrecognized_threshold() {
let out = lint_pack(WARNING_PACK, "warnings");
assert_eq!(
out.status.code(),
Some(2),
"expected clap's usage error, got {:?}: {}",
out.status.code(),
String::from_utf8_lossy(&out.stderr)
);
}
#[test]
fn the_fixture_exits_zero_so_a_failure_below_means_the_argument() {
assert!(
fixture_bundle().exists(),
"fixture missing at {}",
fixture_bundle().display()
);
let out = lint_with("error");
assert_eq!(
out.status.code(),
Some(0),
"fixture no longer lints clean: {}",
String::from_utf8_lossy(&out.stderr)
);
}
#[test]
fn a_run_that_would_pass_does_not_pass_with_an_unrecognized_threshold() {
let out = lint_with("nope");
assert_ne!(
out.status.code(),
Some(0),
"an unrecognized --fail-on was accepted"
);
let stderr = String::from_utf8_lossy(&out.stderr);
assert!(
stderr.contains("nope"),
"the error does not name the rejected value: {stderr}"
);
assert!(
stderr.contains("possible values"),
"the error does not name the accepted set: {stderr}"
);
assert!(
out.stdout.is_empty(),
"a rejected run still wrote to stdout, where the report would go"
);
}
#[test]
fn a_near_miss_spelling_is_rejected_rather_than_guessed() {
let out = lint_with("warnings");
assert_ne!(out.status.code(), Some(0), "`warnings` was accepted");
}
#[test]
fn every_advertised_spelling_is_accepted() {
for value in ["error", "warn", "warning", "info", "none"] {
let out = lint_with(value);
let stderr = String::from_utf8_lossy(&out.stderr);
assert!(
!stderr.contains("invalid value"),
"`--fail-on {value}` is advertised but rejected: {stderr}"
);
assert_eq!(
out.status.code(),
Some(0),
"`--fail-on {value}` gated a bundle with no findings: {stderr}"
);
}
}
#[test]
fn warning_gates_the_same_findings_as_warn() {
let warn = lint_pack(WARNING_PACK, "warn").status.code();
let warning = lint_pack(WARNING_PACK, "warning").status.code();
let error = lint_pack(WARNING_PACK, "error").status.code();
assert_eq!(
warn,
Some(1),
"fixture no longer yields a warning finding under {WARNING_PACK}, so the rest proves nothing"
);
assert_eq!(
warning, warn,
"`warning` is not the alias of `warn` its callers rely on"
);
assert_ne!(
warning, error,
"`warning` decides what `error` decides, so the alias distinguishes nothing"
);
}