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
use std::io::{stderr, Write}; use std::path::{Path, PathBuf}; use std::sync::Mutex; use tempfile::tempdir; use walkdir::WalkDir; use config::{Config, Mode}; use error::Result; use formatting; use steps::{build::BuildStepFactory, check_errors::CheckErrorsStepFactory, TestStepFactory}; lazy_static! { static ref TESTING_MUTEX: Mutex<()> = Mutex::new(()); } pub fn run_tests(config: Config) { if let Err(error) = run_tests_with_writer(config, stderr()) { panic!("{}", error); } } pub fn run_tests_with_writer<W: Write>(config: Config, writer: W) -> Result<()> { TestPlan::new(config).execute(writer) } struct TestPlan { config: Config, steps: Vec<Box<TestStepFactory>>, crates: Vec<PathBuf>, } impl TestPlan { pub fn new(mut config: Config) -> Self { let crates = WalkDir::new(&config.base_dir) .max_depth(1) .min_depth(1) .into_iter() .filter_map(|entry| entry.ok()) .filter(|entry| entry.path().is_dir()) .map(|entry| entry.path().into()) .collect(); let mut steps: Vec<Box<TestStepFactory>> = match config.mode { Mode::BuildFail => vec![Box::new(CheckErrorsStepFactory::new())], Mode::BuildSuccess => vec![Box::new(BuildStepFactory::new())], Mode::Expand => vec![Box::new(BuildStepFactory::new())], }; if config.additional_steps.len() > 0 { steps.append(&mut config.additional_steps); } TestPlan { config, crates, steps, } } pub fn execute<W: Write>(self, mut writer: W) -> Result<()> { let _lock = TESTING_MUTEX.lock().unwrap(); let mut successful: usize = 0; let mut failed: usize = 0; let results: Vec<_> = self.crates .iter() .map(|ref crate_path| { if !(self.config.crates_filter)(crate_path) { writeln!( writer, "testing crate {} ... IGNORED", crate_path.to_string_lossy() )?; return Ok(()); } match self.execute_steps(&crate_path) { Ok(result) => { writeln!( writer, "testing crate {} ... OK", crate_path.to_string_lossy() )?; successful += 1; Ok(result) } Err(error) => { writeln!( writer, "testing crate {} ... FAILED", crate_path.to_string_lossy() )?; failed += 1; Err(error) } } }) .collect(); for result in self.crates.iter().zip(results) { if let Err(error) = result.1 { writeln!(writer, "\n{}:", result.0.to_string_lossy())?; writeln!( writer, "{}", formatting::prefix_each_line(error.to_string(), " ") )?; } } if failed > 0 { bail!("{} tests failed", failed); } else { Ok(()) } } fn execute_steps(&self, crate_path: &Path) -> Result<()> { let build_path = tempdir()?; let local_steps: Vec<_> = self.steps .iter() .map(|factory| factory.initialize(&self.config, crate_path)) .collect(); for step in local_steps { step?.execute(&self.config, build_path.as_ref())?; } Ok(()) } }