From a683b2d2e40cb157d4016c83ce0152add94ef6c6 Mon Sep 17 00:00:00 2001 From: Jacob Hughes Date: Fri, 14 Feb 2020 22:45:22 +0000 Subject: [PATCH] Add lang_tester framework for Miri tests Unfortunately this is a bit brittle because of limitations of the cargo-miri binary [1]. To mitigate this, we create a temp directory and rsync over the src files to compile a separate gcmalloc target with miri flags. We then copy over the tests one at a time in order to run them under Miri. [1]: https://github.com/rust-lang/miri/issues/1173 --- Cargo.toml | 5 ++ gc_tests/miri_test_setup.sh | 20 ++++++++ gc_tests/run_miri_tests.rs | 78 ++++++++++++++++++++++++++++++ gc_tests/tests/miri_hello_world.rs | 11 +++++ 4 files changed, 114 insertions(+) create mode 100755 gc_tests/miri_test_setup.sh create mode 100644 gc_tests/run_miri_tests.rs create mode 100644 gc_tests/tests/miri_hello_world.rs diff --git a/Cargo.toml b/Cargo.toml index fdc7896..6a6c426 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -25,4 +25,9 @@ name = "gc_tests" path = "gc_tests/run_tests.rs" harness = false +[[test]] +name = "miri_tests" +path = "gc_tests/run_miri_tests.rs" +harness = false + [workspace] diff --git a/gc_tests/miri_test_setup.sh b/gc_tests/miri_test_setup.sh new file mode 100755 index 0000000..8a9f4f9 --- /dev/null +++ b/gc_tests/miri_test_setup.sh @@ -0,0 +1,20 @@ +#!/bin/sh +set -e; + +PROJECTDIR=$1 +TMPDIR=$2 + +# Miri deps cause breakages when used with non-miri targets. So we copy gcmalloc +# sources over to a tempdir to compile with miri flags so we can nuke it +# afterwards. +rsync -a --partial --info=progress2 --exclude .git --exclude target --exclude gc_tests $PROJECTDIR/ $TMPDIR + +mkdir -p "$TMPDIR/src/bin/" + +# Running this dummy binary forces cargo-miri to compile gcmalloc with miri +# flags as a dependency. +echo "extern crate gcmalloc; fn main() {}" > $TMPDIR/src/bin/miri.rs +(cd $TMPDIR && cargo-miri miri setup) +(cd $TMPDIR && cargo-miri miri run -- -Zmiri-ignore-leaks) + +rm $TMPDIR/src/bin/miri.rs diff --git a/gc_tests/run_miri_tests.rs b/gc_tests/run_miri_tests.rs new file mode 100644 index 0000000..2b2549b --- /dev/null +++ b/gc_tests/run_miri_tests.rs @@ -0,0 +1,78 @@ +use std::{ + env, + path::{Path, PathBuf}, + process::Command, +}; + +use lang_tester::LangTester; +use tempdir::TempDir; + +fn proj_dir() -> Box { + let mut p = PathBuf::new(); + p.push(env::var("CARGO_MANIFEST_DIR").unwrap()); + p.into_boxed_path() +} + +fn test_dir() -> Box { + let mut p = PathBuf::new(); + p.push(env::var("CARGO_MANIFEST_DIR").unwrap()); + p.push("gc_tests"); + p.push("tests"); + p.push("."); + p.into_boxed_path() +} + +fn main() { + let projd = proj_dir(); + let testsd = test_dir(); + + let tmpd = TempDir::new("miri_tests").unwrap(); + let mut binsd = PathBuf::new(); + binsd.push(tmpd.path()); + binsd.push("src"); + binsd.push("bin"); + + let mut setup = Command::new("./gc_tests/miri_test_setup.sh") + .args(&[&*projd, tmpd.path()]) + .spawn() + .unwrap(); + + if !setup.wait().unwrap().success() { + panic!("Miri setup failed"); + } + + ::std::env::set_current_dir(&tmpd).expect("Couldn't change dir"); + + LangTester::new() + .test_dir(testsd.to_str().unwrap()) + .test_file_filter(|p| { + p.extension().unwrap().to_str().unwrap() == "rs" + && p.file_stem().unwrap().to_str().unwrap().starts_with("miri") + }) + .test_extract(|s| { + Some( + s.lines() + .take_while(|l| l.starts_with("//")) + .map(|l| &l[2..]) + .collect::>() + .join("\n"), + ) + }) + .test_cmds(move |p| { + let mut cp = Command::new("cp"); + cp.args(&[p, binsd.as_path()]); + + let mut runtime = Command::new("cargo-miri"); + runtime.args(&["miri", "run", "--", "-Zmiri-ignore-leaks"]); + + let mut rm_path = PathBuf::new(); + rm_path.push(&binsd); + rm_path.push(p.file_name().unwrap().to_str().unwrap()); + + let mut rm = Command::new("rm"); + rm.args(&[rm_path.to_str().unwrap()]); + + vec![("cp", cp), ("Miri", runtime), ("rm", rm)] + }) + .run(); +} diff --git a/gc_tests/tests/miri_hello_world.rs b/gc_tests/tests/miri_hello_world.rs new file mode 100644 index 0000000..a59e24d --- /dev/null +++ b/gc_tests/tests/miri_hello_world.rs @@ -0,0 +1,11 @@ +// Miri: +// status: success + +extern crate gcmalloc; + +use gcmalloc::Gc; + +fn main() { + let hello = Gc::new("Hello World"); + println!("{}", hello) +}