//! The common code for `tests/lang_tests_*.rs` use std::{ env::{self, current_dir}, path::{Path, PathBuf}, process::Command, }; use lang_tester::LangTester; use tempfile::TempDir; /// Controls the compile options (e.g., optimization level) used to compile /// test code. #[allow(dead_code)] // Each test crate picks one variant pub enum Profile { Debug, Release, } pub fn main_inner(profile: Profile) { let tempdir = TempDir::new().expect("temp dir"); let current_dir = current_dir().expect("current dir"); let current_dir = current_dir.to_str().expect("current dir").to_string(); let gcc_path = include_str!("../gcc_path"); let gcc_path = gcc_path.trim(); env::set_var("LD_LIBRARY_PATH", gcc_path); fn rust_filter(filename: &Path) -> bool { filename.extension().expect("extension").to_str().expect("to_str") == "rs" } #[cfg(feature="master")] fn filter(filename: &Path) -> bool { rust_filter(filename) } #[cfg(not(feature="master"))] fn filter(filename: &Path) -> bool { if let Some(filename) = filename.to_str() { if filename.ends_with("gep.rs") { return false; } } rust_filter(filename) } LangTester::new() .test_dir("tests/run") .test_file_filter(filter) .test_extract(|source| { let lines = source.lines() .skip_while(|l| !l.starts_with("//")) .take_while(|l| l.starts_with("//")) .map(|l| &l[2..]) .collect::>() .join("\n"); Some(lines) }) .test_cmds(move |path| { // Test command 1: Compile `x.rs` into `tempdir/x`. let mut exe = PathBuf::new(); exe.push(&tempdir); exe.push(path.file_stem().expect("file_stem")); let mut compiler = Command::new("rustc"); compiler.args(&[ &format!("-Zcodegen-backend={}/target/debug/librustc_codegen_gcc.so", current_dir), "--sysroot", &format!("{}/build_sysroot/sysroot/", current_dir), "-Zno-parallel-llvm", "-C", "link-arg=-lc", "-o", exe.to_str().expect("to_str"), path.to_str().expect("to_str"), ]); // TODO(antoyo): find a way to send this via a cli argument. let test_target = std::env::var("CG_GCC_TEST_TARGET"); if let Ok(ref target) = test_target { compiler.args(&["--target", &target]); let linker = format!("{}-gcc", target); compiler.args(&[format!("-Clinker={}", linker)]); let mut env_path = std::env::var("PATH").unwrap_or_default(); // TODO(antoyo): find a better way to add the PATH necessary locally. env_path = format!("/opt/m68k-unknown-linux-gnu/bin:{}", env_path); compiler.env("PATH", env_path); } if let Some(flags) = option_env!("TEST_FLAGS") { for flag in flags.split_whitespace() { compiler.arg(&flag); } } match profile { Profile::Debug => {} Profile::Release => { compiler.args(&[ "-C", "opt-level=3", "-C", "lto=no", ]); } } // Test command 2: run `tempdir/x`. if test_target.is_ok() { let vm_parent_dir = std::env::var("CG_GCC_VM_DIR") .map(|dir| PathBuf::from(dir)) .unwrap_or_else(|_| std::env::current_dir().unwrap()); let vm_dir = "vm"; let exe_filename = exe.file_name().unwrap(); let vm_home_dir = vm_parent_dir.join(vm_dir).join("home"); let vm_exe_path = vm_home_dir.join(exe_filename); // FIXME(antoyo): panicking here makes the test pass. let inside_vm_exe_path = PathBuf::from("/home").join(&exe_filename); let mut copy = Command::new("sudo"); copy.arg("cp"); copy.args(&[&exe, &vm_exe_path]); let mut runtime = Command::new("sudo"); runtime.args(&["chroot", vm_dir, "qemu-m68k-static"]); runtime.arg(inside_vm_exe_path); runtime.current_dir(vm_parent_dir); vec![ ("Compiler", compiler), ("Copy", copy), ("Run-time", runtime), ] } else { let runtime = Command::new(exe); vec![ ("Compiler", compiler), ("Run-time", runtime), ] } }) .run(); }