//! Provides a simple way to set up compiletest sample testsuites used in testing. //! //! Inspired by cargo's `cargo-test-support` crate: //! https://github.com/rust-lang/cargo/tree/master/crates/cargo-test-support use std::cell::RefCell; use std::env; use std::fs; use std::path::{Path, PathBuf}; use std::sync::atomic::{AtomicUsize, Ordering}; static COMPILETEST_INTEGRATION_TEST_DIR: &str = "cit"; thread_local! { static TEST_ID: RefCell> = RefCell::new(None); } lazy_static::lazy_static! { pub static ref GLOBAL_ROOT: PathBuf = { let mut path = env::current_exe().unwrap(); path.pop(); // chop off exe name path.pop(); // chop off 'deps' part path.pop(); // chop off 'debug' path.push(COMPILETEST_INTEGRATION_TEST_DIR); path.mkdir_p(); path }; } pub fn testsuite(mode: &str) -> TestsuiteBuilder { let builder = TestsuiteBuilder::new(mode); builder.build(); builder } pub struct TestsuiteBuilder { pub root: PathBuf, } impl TestsuiteBuilder { pub fn new(mode: &str) -> Self { static NEXT_ID: AtomicUsize = AtomicUsize::new(0); let id = NEXT_ID.fetch_add(1, Ordering::Relaxed); TEST_ID.with(|n| *n.borrow_mut() = Some(id)); let root = GLOBAL_ROOT .join(format!("id{}", TEST_ID.with(|n| n.borrow().unwrap()))) .join(mode); root.mkdir_p(); Self { root } } /// Creates a new file to be used for the integration test pub fn mk_file(&self, path: &str, body: &str) { self.root.mkdir_p(); fs::write(self.root.join(&path), &body) .unwrap_or_else(|e| panic!("could not create file {}: {}", path, e)); } /// Returns the contents of the file pub fn file_contents(&self, name: &str) -> String { fs::read_to_string(self.root.join(name)).expect("Unable to read file") } // Sets up a new testsuite root directory fn build(&self) { // Cleanup before we run the next test self.rm_root(); // Create the new directory self.root.mkdir_p(); } /// Deletes the root directory and all its contents fn rm_root(&self) { self.root.rm_rf(); } } pub trait PathExt { fn rm_rf(&self); fn mkdir_p(&self); } impl PathExt for Path { fn rm_rf(&self) { if self.is_dir() { if let Err(e) = fs::remove_dir_all(self) { panic!("failed to remove {:?}: {:?}", self, e) } } else { if let Err(e) = fs::remove_file(self) { panic!("failed to remove {:?}: {:?}", self, e) } } } fn mkdir_p(&self) { fs::create_dir_all(self) .unwrap_or_else(|e| panic!("failed to mkdir_p {}: {}", self.display(), e)) } }