crate_compile_test/
runner.rs1use std::io::Write;
2use std::sync::Mutex;
3
4use colored::*;
5use failure::Error;
6
7use config::Config;
8use error::{Result, TestingError};
9use plan::TestPlan;
10
11pub struct TestRunner<'a> {
12 tests: Vec<Test>,
13 output: Mutex<&'a mut Write>,
14}
15
16pub struct TestResult {
17 success: bool,
18}
19
20struct Test {
21 name: &'static str,
22 config: Box<Fn() -> Config>,
23}
24
25impl<'a> TestRunner<'a> {
26 pub fn new(output: &'a mut Write) -> Self {
27 TestRunner {
28 output: Mutex::new(output),
29 tests: vec![],
30 }
31 }
32
33 pub fn add<F: Fn() -> Config + 'static>(&mut self, name: &'static str, config: F) {
34 self.tests.push(Test {
35 name,
36 config: Box::new(config),
37 });
38 }
39
40 pub fn start(self) -> Result<TestResult> {
41 let mut overall_successful: usize = 0;
42 let mut overall_failed: usize = 0;
43 let mut overall_ignored: usize = 0;
44
45 for test in &self.tests {
46 writeln!(
47 self.output.lock().unwrap(),
48 "{}",
49 format!(r#"Running "{}""#, test.name).underline()
50 )?;
51
52 let plan = TestPlan::new((test.config)());
53
54 let mut successful: usize = 0;
55 let mut failed: usize = 0;
56 let mut ignored: usize = 0;
57
58 let errors: Vec<Error> = plan.crates()
59 .iter()
60 .map(|crate_path| -> Result<()> {
61 if plan.is_crate_filtered_out(crate_path) {
62 writeln!(
63 self.output.lock().unwrap(),
64 " testing crate {} ... {}",
65 crate_path.to_string_lossy().bold(),
66 "IGNORED".yellow(),
67 )?;
68
69 ignored += 1;
70 return Ok(());
71 }
72
73 match plan.execute_steps(&crate_path) {
74 Ok(()) => {
75 writeln!(
76 self.output.lock().unwrap(),
77 " testing crate {} ... {}",
78 crate_path.to_string_lossy().bold(),
79 "OK".bright_green(),
80 )?;
81
82 successful += 1;
83 Ok(())
84 }
85
86 Err(error) => {
87 writeln!(
88 self.output.lock().unwrap(),
89 " testing crate {} ... {}",
90 crate_path.to_string_lossy().bold(),
91 "FAILED".red()
92 )?;
93
94 failed += 1;
95 bail!(TestingError::TestFailed {
96 path: crate_path.clone(),
97 error,
98 });
99 }
100 }
101 })
102 .filter_map(|item| item.err())
103 .collect();
104
105 for error in errors {
106 writeln!(self.output.lock().unwrap(), "\n{}", error)?;
107 }
108
109 writeln!(self.output.lock().unwrap(), "")?;
110
111 overall_successful += successful;
112 overall_failed += failed;
113 overall_ignored += ignored;
114 }
115
116 writeln!(
117 self.output.lock().unwrap(),
118 "Summary: {} successful, {} failed, {} ignored.",
119 overall_successful.to_string().bright_green(),
120 overall_failed.to_string().red(),
121 overall_ignored.to_string().yellow(),
122 )?;
123
124 Ok(TestResult {
125 success: overall_failed == 0,
126 })
127 }
128}
129
130impl TestResult {
131 pub fn is_success(&self) -> bool {
132 self.success
133 }
134}