3 pub(crate) struct PrettyFormatter<T> {
4 out: OutputLocation<T>,
7 /// Number of columns to fill when aligning names
10 is_multithreaded: bool,
13 impl<T: Write> PrettyFormatter<T> {
15 out: OutputLocation<T>,
18 is_multithreaded: bool,
29 pub fn output_location(&self) -> &OutputLocation<T> {
33 pub fn write_ok(&mut self, exec_time: Option<&TestExecTime>) -> io::Result<()> {
34 self.write_short_result("ok", term::color::GREEN, exec_time)
37 pub fn write_failed(&mut self, exec_time: Option<&TestExecTime>) -> io::Result<()> {
38 self.write_short_result("FAILED", term::color::RED, exec_time)
41 pub fn write_ignored(&mut self, exec_time: Option<&TestExecTime>) -> io::Result<()> {
42 self.write_short_result("ignored", term::color::YELLOW, exec_time)
45 pub fn write_allowed_fail(&mut self, exec_time: Option<&TestExecTime>) -> io::Result<()> {
46 self.write_short_result("FAILED (allowed)", term::color::YELLOW, exec_time)
49 pub fn write_bench(&mut self) -> io::Result<()> {
50 self.write_pretty("bench", term::color::CYAN)
53 pub fn write_short_result(
56 color: term::color::Color,
57 exec_time: Option<&TestExecTime>,
59 self.write_pretty(result, color)?;
60 if let Some(exec_time) = exec_time {
61 self.write_plain(format!(" {}", exec_time))?;
63 self.write_plain("\n")
66 pub fn write_pretty(&mut self, word: &str, color: term::color::Color) -> io::Result<()> {
68 Pretty(ref mut term) => {
72 term.write_all(word.as_bytes())?;
78 Raw(ref mut stdout) => {
79 stdout.write_all(word.as_bytes())?;
85 pub fn write_plain<S: AsRef<str>>(&mut self, s: S) -> io::Result<()> {
87 self.out.write_all(s.as_bytes())?;
91 pub fn write_successes(&mut self, state: &ConsoleTestState) -> io::Result<()> {
92 self.write_plain("\nsuccesses:\n")?;
93 let mut successes = Vec::new();
94 let mut stdouts = String::new();
95 for &(ref f, ref stdout) in &state.not_failures {
96 successes.push(f.name.to_string());
97 if !stdout.is_empty() {
98 stdouts.push_str(&format!("---- {} stdout ----\n", f.name));
99 let output = String::from_utf8_lossy(stdout);
100 stdouts.push_str(&output);
101 stdouts.push_str("\n");
104 if !stdouts.is_empty() {
105 self.write_plain("\n")?;
106 self.write_plain(&stdouts)?;
109 self.write_plain("\nsuccesses:\n")?;
111 for name in &successes {
112 self.write_plain(&format!(" {}\n", name))?;
117 pub fn write_failures(&mut self, state: &ConsoleTestState) -> io::Result<()> {
118 self.write_plain("\nfailures:\n")?;
119 let mut failures = Vec::new();
120 let mut fail_out = String::new();
121 for &(ref f, ref stdout) in &state.failures {
122 failures.push(f.name.to_string());
123 if !stdout.is_empty() {
124 fail_out.push_str(&format!("---- {} stdout ----\n", f.name));
125 let output = String::from_utf8_lossy(stdout);
126 fail_out.push_str(&output);
127 fail_out.push_str("\n");
130 if !fail_out.is_empty() {
131 self.write_plain("\n")?;
132 self.write_plain(&fail_out)?;
135 self.write_plain("\nfailures:\n")?;
137 for name in &failures {
138 self.write_plain(&format!(" {}\n", name))?;
143 fn write_test_name(&mut self, desc: &TestDesc) -> io::Result<()> {
144 let name = desc.padded_name(self.max_name_len, desc.name.padding());
145 self.write_plain(&format!("test {} ... ", name))?;
151 impl<T: Write> OutputFormatter for PrettyFormatter<T> {
152 fn write_run_start(&mut self, test_count: usize) -> io::Result<()> {
153 let noun = if test_count != 1 { "tests" } else { "test" };
154 self.write_plain(&format!("\nrunning {} {}\n", test_count, noun))
157 fn write_test_start(&mut self, desc: &TestDesc) -> io::Result<()> {
158 // When running tests concurrently, we should not print
159 // the test's name as the result will be mis-aligned.
160 // When running the tests serially, we print the name here so
161 // that the user can see which test hangs.
162 if !self.is_multithreaded {
163 self.write_test_name(desc)?;
173 exec_time: Option<&TestExecTime>,
175 _: &ConsoleTestState,
176 ) -> io::Result<()> {
177 if self.is_multithreaded {
178 self.write_test_name(desc)?;
182 TrOk => self.write_ok(exec_time),
183 TrFailed | TrFailedMsg(_) => self.write_failed(exec_time),
184 TrIgnored => self.write_ignored(exec_time),
185 TrAllowedFail => self.write_allowed_fail(exec_time),
188 self.write_plain(&format!(": {}\n", fmt_bench_samples(bs)))
193 fn write_timeout(&mut self, desc: &TestDesc) -> io::Result<()> {
194 if self.is_multithreaded {
195 self.write_test_name(desc)?;
198 self.write_plain(&format!(
199 "test {} has been running for over {} seconds\n",
200 desc.name, TEST_WARN_TIMEOUT_S
204 fn write_run_finish(&mut self, state: &ConsoleTestState) -> io::Result<bool> {
205 if state.options.display_output {
206 self.write_successes(state)?;
208 let success = state.failed == 0;
210 self.write_failures(state)?;
213 self.write_plain("\ntest result: ")?;
216 // There's no parallelism at this point so it's safe to use color
217 self.write_pretty("ok", term::color::GREEN)?;
219 self.write_pretty("FAILED", term::color::RED)?;
222 let s = if state.allowed_fail > 0 {
224 ". {} passed; {} failed ({} allowed); {} ignored; {} measured; {} filtered out\n\n",
226 state.failed + state.allowed_fail,
234 ". {} passed; {} failed; {} ignored; {} measured; {} filtered out\n\n",
235 state.passed, state.failed, state.ignored, state.measured, state.filtered_out
239 self.write_plain(&s)?;