use std::path::{Path, PathBuf};
use std::process::Command;
use tempfile::TempDir;
fn repo_root() -> PathBuf {
let crate_dir = PathBuf::from(env!("CARGO_MANIFEST_DIR"));
crate_dir
.parent()
.expect("crate directory should have a parent")
.parent()
.expect("crates directory should have a parent repo root")
.to_path_buf()
}
fn write_file(path: &Path, content: &str) {
if let Some(parent) = path.parent() {
std::fs::create_dir_all(parent).expect("create parent directories");
}
std::fs::write(path, content).unwrap_or_else(|err| panic!("write {}: {err}", path.display()));
}
fn copy_repo_file(repo_root: &Path, temp_repo: &Path, relative_path: &str) {
let src = repo_root.join(relative_path);
let dest = temp_repo.join(relative_path);
let content =
std::fs::read_to_string(&src).unwrap_or_else(|err| panic!("read {}: {err}", src.display()));
write_file(&dest, &content);
}
fn script_path(repo_root: &Path) -> PathBuf {
repo_root.join("scripts/check-rust-toolchain.sh")
}
#[test]
fn rust_toolchain_script_help_documents_operator_contract() {
let repo_root = repo_root();
let output = Command::new("bash")
.arg(script_path(&repo_root))
.arg("--help")
.current_dir(&repo_root)
.output()
.expect("run toolchain script help");
assert!(
output.status.success(),
"help failed\nstdout:\n{}\nstderr:\n{}",
String::from_utf8_lossy(&output.stdout),
String::from_utf8_lossy(&output.stderr)
);
let stdout = String::from_utf8_lossy(&output.stdout);
assert!(stdout.contains("--fail-on-global-stable-drift"));
assert!(stdout.contains("make rust-toolchain-check"));
assert!(stdout.contains("make rust-toolchain-drift-check"));
assert!(stdout.contains("Exit codes:"));
}
#[test]
fn rust_toolchain_script_passes_for_checked_in_baseline() {
let repo_root = repo_root();
let output = Command::new("bash")
.arg(script_path(&repo_root))
.current_dir(&repo_root)
.output()
.expect("run toolchain script");
assert!(
output.status.success(),
"toolchain script failed\nstdout:\n{}\nstderr:\n{}",
String::from_utf8_lossy(&output.stdout),
String::from_utf8_lossy(&output.stderr)
);
let stdout = String::from_utf8_lossy(&output.stdout);
assert!(stdout.contains("Repo Rust baseline is internally consistent"));
assert!(stdout.contains("Skipped global stable drift check"));
}
#[test]
fn rust_toolchain_script_fails_when_crate_rust_version_drifts() {
let repo_root = repo_root();
let temp_repo = TempDir::new().expect("create temp repo");
let fixture = temp_repo.path();
copy_repo_file(&repo_root, fixture, "scripts/check-rust-toolchain.sh");
copy_repo_file(&repo_root, fixture, "scripts/lib/cueloop-shell.sh");
write_file(
&fixture.join("rust-toolchain.toml"),
"[toolchain]\nchannel = \"1.95.0\"\ncomponents = [\"rustfmt\", \"clippy\"]\nprofile = \"minimal\"\n",
);
write_file(
&fixture.join("crates/cueloop/Cargo.toml"),
"[package]\nname = \"cueloop\"\nrust-version = \"1.94\"\n",
);
let output = Command::new("bash")
.arg(fixture.join("scripts/check-rust-toolchain.sh"))
.current_dir(fixture)
.output()
.expect("run toolchain script against fixture");
assert!(
!output.status.success(),
"drifted fixture should fail\nstdout:\n{}\nstderr:\n{}",
String::from_utf8_lossy(&output.stdout),
String::from_utf8_lossy(&output.stderr)
);
assert!(
String::from_utf8_lossy(&output.stderr).contains("crate rust-version drifted"),
"expected rust-version drift diagnostic\nstderr:\n{}",
String::from_utf8_lossy(&output.stderr)
);
}