//! Nightly report and verdict through the real binary (`SMH-SPEC-SPEC0001`, testing acceptance). #![cfg(unix)] use std::{fs, os::unix::fs::PermissionsExt, time::Duration}; #[test] fn e2e_nightly_report_publishes_evidence_before_verdict_reports_findings() { let root = std::env::temp_dir().join(format!("smith-nightly-binary-{}", std::process::id())); let _ = fs::remove_dir_all(&root); let bin = root.join("bin"); fs::create_dir_all(&bin).unwrap(); // Script only external coverage machinery; report assembly and verdict // still run through the built xtask with real shard files. fs::write( bin.join("cargo"), r#"#!/bin/sh set -eu if [ "$1" = llvm-cov ] && [ "$2" = report ]; then while [ "$#" -gt 0 ]; do case "$1" in --output-path) shift; mkdir -p "$(dirname "$1")"; printf 'coverage\n' > "$1" ;; --output-dir) shift; mkdir -p "$1"; printf 'coverage\n' > "$1/index.html" ;; --summary-only) printf 'coverage summary\n' ;; esac shift done fi "#, ) .unwrap(); fs::write(bin.join("hyperfine"), "#!/bin/sh\nexit 1\n").unwrap(); fs::write(bin.join("rustup"), "#!/bin/sh\nexit 0\n").unwrap(); for tool in ["cargo", "hyperfine", "rustup"] { fs::set_permissions(bin.join(tool), fs::Permissions::from_mode(0o700)).unwrap(); } for shard in 0..8 { let evidence = root .join("nightly") .join(shard.to_string()) .join("mutants.out"); fs::create_dir_all(&evidence).unwrap(); for name in ["caught.txt", "missed.txt", "timeout.txt", "unviable.txt"] { fs::write(evidence.join(name), "").unwrap(); } fs::write(evidence.join("outcomes.json"), "{}").unwrap(); } let report = root.join("nightly/report"); let path = std::env::join_paths(std::iter::once(bin).chain(std::env::split_paths( &std::env::var_os("PATH").unwrap_or_default(), ))) .unwrap(); let command = || { let mut command = assert_cmd::Command::new(env!("CARGO_BIN_EXE_xtask")); command .env("CARGO_TARGET_DIR", &root) .env("PATH", &path) .timeout(Duration::from_secs(10)); command }; command().args(["nightly", "report"]).assert().success(); assert!( fs::read_to_string(report.join("index.md")) .unwrap() .contains("## Mutation") ); command().args(["nightly", "verdict"]).assert().success(); assert!(root.join("nightly/verdict/index.md").is_file()); for name in ["missed.txt", "timeout.txt"] { fs::write(report.join(name), "finding\n").unwrap(); let assertion = command().args(["nightly", "verdict"]).assert().code(1); assert!( String::from_utf8_lossy(&assertion.get_output().stderr) .contains("nightly mutation findings") ); fs::write(report.join(name), "").unwrap(); } fs::remove_file(report.join("index.md")).unwrap(); command().args(["nightly", "verdict"]).assert().code(1); command().args(["nightly", "../escape"]).assert().code(1); command().arg("nightly").assert().code(1); assert!(!root.join("escape").exists()); fs::remove_dir_all(root).unwrap(); }