]> git.lizzy.rs Git - rust.git/blob - src/libtest/formatters/pretty.rs
Rollup merge of #61389 - Zoxc:arena-cleanup, r=eddyb
[rust.git] / src / libtest / formatters / pretty.rs
1 use super::*;
2
3 pub(crate) struct PrettyFormatter<T> {
4     out: OutputLocation<T>,
5     use_color: bool,
6
7     /// Number of columns to fill when aligning names
8     max_name_len: usize,
9
10     is_multithreaded: bool,
11 }
12
13 impl<T: Write> PrettyFormatter<T> {
14     pub fn new(
15         out: OutputLocation<T>,
16         use_color: bool,
17         max_name_len: usize,
18         is_multithreaded: bool,
19     ) -> Self {
20         PrettyFormatter {
21             out,
22             use_color,
23             max_name_len,
24             is_multithreaded,
25         }
26     }
27
28     #[cfg(test)]
29     pub fn output_location(&self) -> &OutputLocation<T> {
30         &self.out
31     }
32
33     pub fn write_ok(&mut self) -> io::Result<()> {
34         self.write_short_result("ok", term::color::GREEN)
35     }
36
37     pub fn write_failed(&mut self) -> io::Result<()> {
38         self.write_short_result("FAILED", term::color::RED)
39     }
40
41     pub fn write_ignored(&mut self) -> io::Result<()> {
42         self.write_short_result("ignored", term::color::YELLOW)
43     }
44
45     pub fn write_allowed_fail(&mut self) -> io::Result<()> {
46         self.write_short_result("FAILED (allowed)", term::color::YELLOW)
47     }
48
49     pub fn write_bench(&mut self) -> io::Result<()> {
50         self.write_pretty("bench", term::color::CYAN)
51     }
52
53     pub fn write_short_result(
54         &mut self,
55         result: &str,
56         color: term::color::Color,
57     ) -> io::Result<()> {
58         self.write_pretty(result, color)?;
59         self.write_plain("\n")
60     }
61
62     pub fn write_pretty(&mut self, word: &str, color: term::color::Color) -> io::Result<()> {
63         match self.out {
64             Pretty(ref mut term) => {
65                 if self.use_color {
66                     term.fg(color)?;
67                 }
68                 term.write_all(word.as_bytes())?;
69                 if self.use_color {
70                     term.reset()?;
71                 }
72                 term.flush()
73             }
74             Raw(ref mut stdout) => {
75                 stdout.write_all(word.as_bytes())?;
76                 stdout.flush()
77             }
78         }
79     }
80
81     pub fn write_plain<S: AsRef<str>>(&mut self, s: S) -> io::Result<()> {
82         let s = s.as_ref();
83         self.out.write_all(s.as_bytes())?;
84         self.out.flush()
85     }
86
87     pub fn write_successes(&mut self, state: &ConsoleTestState) -> io::Result<()> {
88         self.write_plain("\nsuccesses:\n")?;
89         let mut successes = Vec::new();
90         let mut stdouts = String::new();
91         for &(ref f, ref stdout) in &state.not_failures {
92             successes.push(f.name.to_string());
93             if !stdout.is_empty() {
94                 stdouts.push_str(&format!("---- {} stdout ----\n", f.name));
95                 let output = String::from_utf8_lossy(stdout);
96                 stdouts.push_str(&output);
97                 stdouts.push_str("\n");
98             }
99         }
100         if !stdouts.is_empty() {
101             self.write_plain("\n")?;
102             self.write_plain(&stdouts)?;
103         }
104
105         self.write_plain("\nsuccesses:\n")?;
106         successes.sort();
107         for name in &successes {
108             self.write_plain(&format!("    {}\n", name))?;
109         }
110         Ok(())
111     }
112
113     pub fn write_failures(&mut self, state: &ConsoleTestState) -> io::Result<()> {
114         self.write_plain("\nfailures:\n")?;
115         let mut failures = Vec::new();
116         let mut fail_out = String::new();
117         for &(ref f, ref stdout) in &state.failures {
118             failures.push(f.name.to_string());
119             if !stdout.is_empty() {
120                 fail_out.push_str(&format!("---- {} stdout ----\n", f.name));
121                 let output = String::from_utf8_lossy(stdout);
122                 fail_out.push_str(&output);
123                 fail_out.push_str("\n");
124             }
125         }
126         if !fail_out.is_empty() {
127             self.write_plain("\n")?;
128             self.write_plain(&fail_out)?;
129         }
130
131         self.write_plain("\nfailures:\n")?;
132         failures.sort();
133         for name in &failures {
134             self.write_plain(&format!("    {}\n", name))?;
135         }
136         Ok(())
137     }
138
139     fn write_test_name(&mut self, desc: &TestDesc) -> io::Result<()> {
140         let name = desc.padded_name(self.max_name_len, desc.name.padding());
141         self.write_plain(&format!("test {} ... ", name))?;
142
143         Ok(())
144     }
145 }
146
147 impl<T: Write> OutputFormatter for PrettyFormatter<T> {
148     fn write_run_start(&mut self, test_count: usize) -> io::Result<()> {
149         let noun = if test_count != 1 { "tests" } else { "test" };
150         self.write_plain(&format!("\nrunning {} {}\n", test_count, noun))
151     }
152
153     fn write_test_start(&mut self, desc: &TestDesc) -> io::Result<()> {
154         // When running tests concurrently, we should not print
155         // the test's name as the result will be mis-aligned.
156         // When running the tests serially, we print the name here so
157         // that the user can see which test hangs.
158         if !self.is_multithreaded {
159             self.write_test_name(desc)?;
160         }
161
162         Ok(())
163     }
164
165     fn write_result(&mut self, desc: &TestDesc, result: &TestResult, _: &[u8]) -> io::Result<()> {
166         if self.is_multithreaded {
167             self.write_test_name(desc)?;
168         }
169
170         match *result {
171             TrOk => self.write_ok(),
172             TrFailed | TrFailedMsg(_) => self.write_failed(),
173             TrIgnored => self.write_ignored(),
174             TrAllowedFail => self.write_allowed_fail(),
175             TrBench(ref bs) => {
176                 self.write_bench()?;
177                 self.write_plain(&format!(": {}\n", fmt_bench_samples(bs)))
178             }
179         }
180     }
181
182     fn write_timeout(&mut self, desc: &TestDesc) -> io::Result<()> {
183         if self.is_multithreaded {
184             self.write_test_name(desc)?;
185         }
186
187         self.write_plain(&format!(
188             "test {} has been running for over {} seconds\n",
189             desc.name, TEST_WARN_TIMEOUT_S
190         ))
191     }
192
193     fn write_run_finish(&mut self, state: &ConsoleTestState) -> io::Result<bool> {
194         if state.options.display_output {
195             self.write_successes(state)?;
196         }
197         let success = state.failed == 0;
198         if !success {
199             self.write_failures(state)?;
200         }
201
202         self.write_plain("\ntest result: ")?;
203
204         if success {
205             // There's no parallelism at this point so it's safe to use color
206             self.write_pretty("ok", term::color::GREEN)?;
207         } else {
208             self.write_pretty("FAILED", term::color::RED)?;
209         }
210
211         let s = if state.allowed_fail > 0 {
212             format!(
213                 ". {} passed; {} failed ({} allowed); {} ignored; {} measured; {} filtered out\n\n",
214                 state.passed,
215                 state.failed + state.allowed_fail,
216                 state.allowed_fail,
217                 state.ignored,
218                 state.measured,
219                 state.filtered_out
220             )
221         } else {
222             format!(
223                 ". {} passed; {} failed; {} ignored; {} measured; {} filtered out\n\n",
224                 state.passed, state.failed, state.ignored, state.measured, state.filtered_out
225             )
226         };
227
228         self.write_plain(&s)?;
229
230         Ok(success)
231     }
232 }