#![cfg(not(any(target_os = "windows", feature = "memory-model-checks", feature = "ref-count-return")))]
use std::{
env, fs,
path::{Path, PathBuf},
process::Command,
};
fn cases_dir() -> PathBuf {
Path::new(env!("CARGO_MANIFEST_DIR"))
.join("tests")
.join("heap_reader_compile_fail_cases")
}
fn isolated_target_dir() -> PathBuf {
Path::new(env!("CARGO_MANIFEST_DIR"))
.join("..")
.join("..")
.join("target")
.join("heap_reader_compile_fail")
}
fn normalize_stderr(stderr: &str) -> String {
stderr
.lines()
.filter(|line| {
!line.starts_with("warning:")
&& !line.starts_with(" Compiling")
&& !line.starts_with(" Checking")
&& !line.starts_with(" Finished")
&& !line.starts_with(" Blocking")
&& !line.starts_with("error: could not compile")
&& !line.starts_with("warning: build failed")
&& !line.starts_with("error: process didn't exit successfully:")
&& !line.is_empty()
})
.collect::<Vec<_>>()
.join("\n")
}
fn check_compile_fail(test_name: &str) {
let test_cfg = format!("heap_reader_compile_fail_test_{test_name}");
let stderr_path = cases_dir().join(format!("{test_name}.stderr"));
let target_dir = isolated_target_dir();
let output = Command::new(env!("CARGO"))
.args([
"rustc",
"--package=monty",
"--profile=check",
"--target-dir",
&target_dir.to_string_lossy(),
"--",
"--cfg=heap_reader_compile_fail_tests",
"--cfg",
&test_cfg,
"--diagnostic-width=140",
])
.env("CARGO_TERM_COLOR", "never")
.output()
.expect("failed to run cargo rustc");
assert!(
!output.status.success(),
"{test_name}: expected compilation to fail, but it succeeded",
);
let stderr = String::from_utf8_lossy(&output.stderr);
let actual = normalize_stderr(&stderr);
if env::var("UPDATE_EXPECT").is_ok() {
fs::write(&stderr_path, format!("{actual}\n"))
.unwrap_or_else(|e| panic!("failed to write {}: {e}", stderr_path.display()));
eprintln!("updated {}", stderr_path.display());
return;
}
let expected = fs::read_to_string(&stderr_path)
.unwrap_or_else(|e| panic!("failed to read {}: {e}", stderr_path.display()))
.trim()
.to_owned();
assert!(
actual == expected,
"{test_name}: stderr mismatch (run with UPDATE_EXPECT=1 to update)\n\n--- expected ({}) ---\n{expected}\n\n--- actual ---\n{actual}\n",
stderr_path.display(),
);
}
#[test]
fn heap_mutation_while_reading() {
check_compile_fail("heap_mutation_while_reading");
}
#[test]
fn double_get_mut() {
check_compile_fail("double_get_mut");
}
#[test]
fn dec_ref_while_reading() {
check_compile_fail("dec_ref_while_reading");
}
#[test]
fn smuggle_heap_read() {
check_compile_fail("smuggle_heap_read");
}
#[test]
fn mutation_in_map_closure() {
check_compile_fail("mutation_in_map_closure");
}
#[test]
fn smuggle_vm() {
check_compile_fail("smuggle_vm");
}
#[test]
fn smuggle_and_swap_reader() {
check_compile_fail("smuggle_and_swap_reader");
}