1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173
//! Batch Run //! ========= //! //! [![Latest Version](https://img.shields.io/crates/v/batch_run.svg)](https://crates.io/crates/batch_run) //! [![Rust Documentation](https://img.shields.io/badge/api-rustdoc-blue.svg)](https://docs.rs/batch_run) //! //! `batch_run` is a runner for a set of Rust source files, based on [dtolnay's `trybuild`](https://github.com/dtolnay/trybuild). //! It can be useful when you have a bunch of Rust sources which are not complex enough to be //! packed into dedicated crates, but which are (by their meaning) not just integration test cases. //! It also checks for output correctness, either on compile-time (for `compile_fail` cases) //! or at runtime (for `run_pass` cases). //! //! ```toml //! [dependencies] //! batch_run = "1.0" //! ``` //! //! *Compiler support: requires rustc 1.31+* //! //! <br> //! //! ## Compile-fail cases //! //! A minimal batch_run setup looks like this: //! //! ```rust //! fn main() { //! let b = batch_run::Batch::new(); //! b.compile_fail("batches/ui/*.rs"); //! match b.run() { //! Ok(()) => {}, //! Err(err) => println!("{:?}", err) //! }; //! } //! ``` //! //! This program will individually compile each of the //! source files matching the glob pattern, expect them to fail to compile, and //! assert that the compiler's error message matches an adjacently named _*.stderr_ //! file containing the expected output (same file name as the test except with a //! different extension). If it doesn't match, the program will print the error message //! with expected vs actual compiler output. //! //! Dependencies listed under `[dependencies]` in the project's Cargo.toml are //! accessible from within the batch. //! //! A compile\_fail case that fails to fail to compile is also a failure. //! //! <br> //! //! ## Run-pass cases //! //! In the run_pass cases, we not only check that the code compiles, but also actually run it //! and match the stdout/stderr output with the corresponding _*.stdout_/_*.stderr_ files. //! //! You can mix compile_fail and run_pass cases in one batch: //! //! ```rust //! fn main() { //! let t = batch_run::Batch::new(); //! t.run_pass("batches/01-parse-header.rs"); //! t.run_pass("batches/02-parse-body.rs"); //! t.compile_fail("batches/03-expand-four-errors.rs"); //! t.run_pass("batches/04-paste-ident.rs"); //! t.run_pass("batches/05-repeat-section.rs"); //! } //! ``` //! //! <br> //! //! ## Details //! //! That's the entire API for now. //! //! <br> //! //! ## Workflow //! //! (TODO) //! #[macro_use] mod term; mod binary; mod cargo_rustc; mod dependencies; mod env; mod error; mod features; mod message; mod normalize; mod run; mod rustflags; use std::cell::RefCell; use std::path::{Path, PathBuf}; // use std::thread; #[derive(Debug)] pub struct Batch { runner: RefCell<Runner>, } #[derive(Debug)] struct Runner { entries: Vec<Entry>, } #[derive(Clone, Debug)] struct Entry { path: PathBuf, expected: Expected, } #[derive(Copy, Clone, Debug)] enum Expected { RunPass, CompileFail, } impl Expected { pub fn is_run_pass(&self) -> bool { use Expected::*; match self { RunPass => true, CompileFail => false, } } } impl Batch { #[allow(clippy::new_without_default)] pub fn new() -> Self { Batch { runner: RefCell::new(Runner { entries: Vec::new(), }), } } pub fn run_pass<P: AsRef<Path>>(&self, path: P) { self.runner.borrow_mut().entries.push(Entry { path: path.as_ref().to_owned(), expected: Expected::RunPass, }); } pub fn compile_fail<P: AsRef<Path>>(&self, path: P) { self.runner.borrow_mut().entries.push(Entry { path: path.as_ref().to_owned(), expected: Expected::CompileFail, }); } // TODO error type pub fn run(self) -> Result<(), error::Error> { self.runner.borrow_mut().run() } } // #[doc(hidden)] // impl Drop for Batch { // fn drop(&mut self) { // if !thread::panicking() { // self.runner // .borrow_mut() // .run() // .unwrap_or_else(|err| println!("{}", err)); // } // } // }