use assert_cmd::Command;
use std::fs;
use std::path::Path;
type TestResult = Result<(), Box<dyn std::error::Error>>;
const BASE: &str = r#"
version = 1
canonical = "json-schema-2020-12"
authoring = "zod"
[gates]
"#;
fn repo(floor: &str) -> Result<tempfile::TempDir, Box<dyn std::error::Error>> {
let dir = tempfile::tempdir()?;
fs::write(dir.path().join("pushkin.toml"), format!("{BASE}{floor}"))?;
Ok(dir)
}
struct Run {
code: i32,
out: String,
}
fn floor(dir: &Path, args: &[&str]) -> Result<Run, Box<dyn std::error::Error>> {
let output = Command::cargo_bin("pushkin")?
.current_dir(dir)
.arg("floor")
.args(args)
.output()?;
Ok(Run {
code: output.status.code().unwrap_or(-1),
out: format!(
"{}{}",
String::from_utf8_lossy(&output.stdout),
String::from_utf8_lossy(&output.stderr)
),
})
}
const GREEN_ONLY: &str = r#"
[[floor.commands]]
name = "version"
run = ["git", "--version"]
scope = "whole_repo"
inputs = "toolchain"
"#;
#[test]
fn all_green_exits_zero_and_says_so() -> TestResult {
let dir = repo(GREEN_ONLY)?;
let run = floor(dir.path(), &[])?;
assert_eq!(run.code, 0, "all-green must exit 0; output:\n{}", run.out);
assert!(
run.out.contains("FLOOR: green"),
"output must state the verdict, got:\n{}",
run.out
);
Ok(())
}
#[test]
fn a_failing_command_exits_two() -> TestResult {
let dir = repo(
r#"
[[floor.commands]]
name = "broken"
run = ["git", "definitely-not-a-verb"]
scope = "whole_repo"
inputs = "repo"
"#,
)?;
let run = floor(dir.path(), &[])?;
assert_eq!(
run.code, 2,
"a finding must exit 2, not 1; output:\n{}",
run.out
);
assert!(
run.out.contains("FLOOR: RED"),
"output must state the verdict, got:\n{}",
run.out
);
Ok(())
}
#[test]
fn every_command_runs_even_after_one_goes_red() -> TestResult {
let dir = repo(
r#"
[[floor.commands]]
name = "broken"
run = ["git", "definitely-not-a-verb"]
scope = "whole_repo"
inputs = "repo"
[[floor.commands]]
name = "after"
run = ["git", "--version"]
scope = "whole_repo"
inputs = "toolchain"
"#,
)?;
let run = floor(dir.path(), &[])?;
assert_eq!(run.code, 2);
assert!(
run.out.contains("after"),
"the command after the red one must still have run, got:\n{}",
run.out
);
Ok(())
}
#[test]
fn a_missing_binary_exits_one_carrying_its_install_hint() -> TestResult {
let dir = repo(
r#"
[[floor.commands]]
name = "absent"
run = ["pushkin-floor-test-no-such-binary"]
scope = "whole_repo"
inputs = "toolchain"
install = "brew install the-thing"
"#,
)?;
let run = floor(dir.path(), &[])?;
assert_eq!(
run.code, 1,
"a missing tool must exit 1, not 2; output:\n{}",
run.out
);
assert!(
run.out.contains("brew install the-thing"),
"the error must carry the declared install hint, got:\n{}",
run.out
);
assert!(
run.out.contains("pushkin-floor-test-no-such-binary"),
"the error must name the missing binary, got:\n{}",
run.out
);
Ok(())
}
#[test]
fn a_missing_binary_reports_what_already_ran_before_it() -> TestResult {
let dir = repo(
r#"
[[floor.commands]]
name = "first"
run = ["git", "--version"]
scope = "whole_repo"
inputs = "toolchain"
[[floor.commands]]
name = "absent"
run = ["pushkin-floor-test-no-such-binary"]
scope = "whole_repo"
inputs = "toolchain"
"#,
)?;
let run = floor(dir.path(), &[])?;
assert_eq!(run.code, 1);
assert!(
run.out.contains("first"),
"the commands that already ran must be reported, got:\n{}",
run.out
);
Ok(())
}
#[test]
fn a_missing_binary_without_a_declared_hint_still_names_itself() -> TestResult {
let dir = repo(
r#"
[[floor.commands]]
name = "absent"
run = ["pushkin-floor-test-no-such-binary"]
scope = "whole_repo"
inputs = "toolchain"
"#,
)?;
let run = floor(dir.path(), &[])?;
assert_eq!(run.code, 1);
assert!(
run.out.contains("pushkin-floor-test-no-such-binary"),
"the error must name the missing binary, got:\n{}",
run.out
);
Ok(())
}
#[test]
fn no_floor_table_is_a_named_refusal_not_a_green_run() -> TestResult {
let dir = repo("")?;
let run = floor(dir.path(), &[])?;
assert_eq!(
run.code, 1,
"an undeclared floor is could-not-run, not clean; output:\n{}",
run.out
);
assert!(
run.out.contains("[floor]") && run.out.contains("pushkin.toml"),
"the refusal must name the table and the file, got:\n{}",
run.out
);
assert!(
!run.out.contains("FLOOR: green"),
"a refusal must never render as a green floor, got:\n{}",
run.out
);
Ok(())
}
#[test]
fn an_empty_command_list_is_also_a_refusal() -> TestResult {
let dir = repo("[floor]\ncommands = []\n")?;
let run = floor(dir.path(), &[])?;
assert_eq!(run.code, 1, "output:\n{}", run.out);
assert!(
!run.out.contains("FLOOR: green"),
"zero commands must not render green, got:\n{}",
run.out
);
Ok(())
}
#[test]
fn commands_run_and_report_in_declared_order() -> TestResult {
let dir = repo(
r#"
[[floor.commands]]
name = "alpha"
run = ["git", "--version"]
scope = "per_file"
inputs = "repo"
[[floor.commands]]
name = "bravo"
run = ["git", "--version"]
scope = "per_crate"
inputs = "toolchain"
[[floor.commands]]
name = "charlie"
run = ["git", "--version"]
scope = "whole_repo"
inputs = "repo"
"#,
)?;
let run = floor(dir.path(), &[])?;
assert_eq!(run.code, 0, "output:\n{}", run.out);
let alpha = run.out.find("alpha").expect("alpha must be reported");
let bravo = run.out.find("bravo").expect("bravo must be reported");
let charlie = run.out.find("charlie").expect("charlie must be reported");
assert!(
alpha < bravo && bravo < charlie,
"declared order must be preserved in the report, got:\n{}",
run.out
);
Ok(())
}
#[test]
fn each_command_reports_its_scope_and_inputs_class() -> TestResult {
let dir = repo(GREEN_ONLY)?;
let run = floor(dir.path(), &[])?;
assert!(
run.out.contains("whole_repo") && run.out.contains("toolchain"),
"scope and inputs must appear in the report, got:\n{}",
run.out
);
Ok(())
}
#[test]
fn a_network_inputs_command_prints_the_time_variance_disclosure() -> TestResult {
let dir = repo(
r#"
[[floor.commands]]
name = "advisories"
run = ["git", "--version"]
scope = "whole_repo"
inputs = "network"
"#,
)?;
let run = floor(dir.path(), &[])?;
assert_eq!(run.code, 0, "output:\n{}", run.out);
assert!(
run.out.contains("advisories"),
"the disclosure must name the network-dependent command, got:\n{}",
run.out
);
assert!(
run.out.to_lowercase().contains("unchanged commit"),
"the disclosure must say what the dependency means, got:\n{}",
run.out
);
Ok(())
}
#[test]
fn a_floor_with_no_network_command_prints_no_disclosure() -> TestResult {
let dir = repo(GREEN_ONLY)?;
let run = floor(dir.path(), &[])?;
assert!(
!run.out.to_lowercase().contains("unchanged commit"),
"no network inputs means no disclosure, got:\n{}",
run.out
);
Ok(())
}
#[test]
fn skip_omits_the_command_and_says_so_loudly() -> TestResult {
let dir = repo(
r#"
[[floor.commands]]
name = "kept"
run = ["git", "--version"]
scope = "whole_repo"
inputs = "toolchain"
[[floor.commands]]
name = "dropped"
run = ["git", "definitely-not-a-verb"]
scope = "whole_repo"
inputs = "repo"
"#,
)?;
let run = floor(dir.path(), &["--skip", "dropped"])?;
assert_eq!(
run.code, 0,
"skipping the only red command leaves a green run; output:\n{}",
run.out
);
assert!(
run.out.contains("EXCLUDED") && run.out.contains("dropped"),
"a skip must be disclosed by name, got:\n{}",
run.out
);
Ok(())
}
#[test]
fn a_skipped_floor_never_prints_bare_green() -> TestResult {
let dir = repo(
r#"
[[floor.commands]]
name = "kept"
run = ["git", "--version"]
scope = "whole_repo"
inputs = "toolchain"
[[floor.commands]]
name = "dropped"
run = ["git", "--version"]
scope = "whole_repo"
inputs = "toolchain"
"#,
)?;
let run = floor(dir.path(), &["--skip", "dropped"])?;
assert!(
run.out.contains("FLOOR: green (EXCLUDED"),
"a partial floor must qualify its own verdict, got:\n{}",
run.out
);
Ok(())
}
#[test]
fn skip_is_repeatable_and_names_every_omission() -> TestResult {
let dir = repo(
r#"
[[floor.commands]]
name = "kept"
run = ["git", "--version"]
scope = "whole_repo"
inputs = "toolchain"
[[floor.commands]]
name = "one"
run = ["git", "--version"]
scope = "whole_repo"
inputs = "toolchain"
[[floor.commands]]
name = "two"
run = ["git", "--version"]
scope = "whole_repo"
inputs = "toolchain"
"#,
)?;
let run = floor(dir.path(), &["--skip", "one", "--skip", "two"])?;
assert_eq!(run.code, 0, "output:\n{}", run.out);
assert!(
run.out.contains("one") && run.out.contains("two"),
"every omission must be named, got:\n{}",
run.out
);
Ok(())
}
#[test]
fn skipping_an_undeclared_name_is_a_named_error_not_a_silent_no_op() -> TestResult {
let dir = repo(GREEN_ONLY)?;
let run = floor(dir.path(), &["--skip", "no-such-command"])?;
assert_eq!(
run.code, 1,
"an unknown --skip target must be could-not-run; output:\n{}",
run.out
);
assert!(
run.out.contains("no-such-command"),
"the error must name the unmatched skip, got:\n{}",
run.out
);
Ok(())
}
#[test]
fn skipping_every_command_is_a_refusal_not_a_green_floor() -> TestResult {
let dir = repo(GREEN_ONLY)?;
let run = floor(dir.path(), &["--skip", "version"])?;
assert_eq!(
run.code, 1,
"an empty run must not report a verdict; output:\n{}",
run.out
);
assert!(
!run.out.contains("FLOOR: green"),
"skipping everything must not render green, got:\n{}",
run.out
);
Ok(())
}
#[test]
fn the_report_carries_a_header_and_per_command_timing() -> TestResult {
let dir = repo(GREEN_ONLY)?;
let run = floor(dir.path(), &[])?;
assert!(
run.out.contains("pushkin floor"),
"the report needs a header, got:\n{}",
run.out
);
assert!(
run.out.contains("ms"),
"per-command wall duration must be reported, got:\n{}",
run.out
);
Ok(())
}
#[test]
fn help_discloses_the_inverted_exit_contract() -> TestResult {
let output = Command::cargo_bin("pushkin")?
.args(["floor", "--help"])
.output()?;
let help = String::from_utf8_lossy(&output.stdout).into_owned();
assert!(
help.contains('0') && help.contains('1') && help.contains('2'),
"--help must spell out the exit contract, got:\n{help}"
);
Ok(())
}
const RECONCILE_PAIR: &str = r#"
[[floor.commands]]
name = "suite"
run = ["git", "--version"]
scope = "whole_repo"
inputs = "repo"
reconcile_ignored = true
[[floor.commands]]
name = "coverer"
run = ["git", "--version"]
scope = "whole_repo"
inputs = "toolchain"
covers_ignored_of = "suite"
"#;
#[test]
fn skipping_a_declared_coverer_is_disclosed_but_not_red() -> TestResult {
let dir = repo(RECONCILE_PAIR)?;
let run = floor(dir.path(), &["--skip", "coverer"])?;
assert_eq!(
run.code, 0,
"skipping a declared coverer must not turn the floor RED; output:\n{}",
run.out
);
assert!(
run.out.contains("EXCLUDED") && run.out.contains("coverer"),
"the omission must still be named, got:\n{}",
run.out
);
assert!(
run.out.contains("NOT A FULL FLOOR"),
"the run must still disclaim completeness, got:\n{}",
run.out
);
Ok(())
}
#[test]
fn an_undeclared_coverer_stays_red_however_the_run_was_invoked() -> TestResult {
let dir = repo(
r#"
[[floor.commands]]
name = "suite"
run = ["git", "--version"]
scope = "whole_repo"
inputs = "repo"
reconcile_ignored = true
[[floor.commands]]
name = "unrelated"
run = ["git", "--version"]
scope = "whole_repo"
inputs = "toolchain"
"#,
)?;
let run = floor(dir.path(), &["--skip", "unrelated"])?;
assert_eq!(run.code, 0, "output:\n{}", run.out);
assert!(
!run.out.contains("was excluded by --skip"),
"skipping an unrelated command must not excuse anything, got:\n{}",
run.out
);
Ok(())
}