Skip to content

Commit 22fc649

Browse files
author
Gilad Naaman
committed
Refactoring needed in order to have test json output.
1 parent 707d070 commit 22fc649

File tree

2 files changed

+308
-232
lines changed

2 files changed

+308
-232
lines changed

src/libtest/formatters.rs

Lines changed: 246 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,246 @@
1+
// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
use super::*;
12+
13+
pub(crate) trait OutputFormatter {
14+
fn write_run_start(&mut self, len: usize) -> io::Result<()>;
15+
fn write_test_start(&mut self,
16+
test: &TestDesc,
17+
align: NamePadding,
18+
max_name_len: usize) -> io::Result<()>;
19+
fn write_timeout(&mut self, desc: &TestDesc) -> io::Result<()>;
20+
fn write_result(&mut self, result: &TestResult) -> io::Result<()>;
21+
fn write_run_finish(&mut self, state: &ConsoleTestState) -> io::Result<bool>;
22+
}
23+
24+
pub(crate) struct HumanFormatter<T> {
25+
out: OutputLocation<T>,
26+
terse: bool,
27+
use_color: bool,
28+
test_count: usize,
29+
}
30+
31+
impl<T: Write> HumanFormatter<T> {
32+
pub fn new(out: OutputLocation<T>, use_color: bool, terse: bool) -> Self {
33+
HumanFormatter {
34+
out,
35+
terse,
36+
use_color,
37+
test_count: 0,
38+
}
39+
}
40+
41+
#[cfg(test)]
42+
pub fn output_location(&self) -> &OutputLocation<T> {
43+
&self.out
44+
}
45+
46+
pub fn write_ok(&mut self) -> io::Result<()> {
47+
self.write_short_result("ok", ".", term::color::GREEN)
48+
}
49+
50+
pub fn write_failed(&mut self) -> io::Result<()> {
51+
self.write_short_result("FAILED", "F", term::color::RED)
52+
}
53+
54+
pub fn write_ignored(&mut self) -> io::Result<()> {
55+
self.write_short_result("ignored", "i", term::color::YELLOW)
56+
}
57+
58+
pub fn write_allowed_fail(&mut self) -> io::Result<()> {
59+
self.write_short_result("FAILED (allowed)", "a", term::color::YELLOW)
60+
}
61+
62+
pub fn write_bench(&mut self) -> io::Result<()> {
63+
self.write_pretty("bench", term::color::CYAN)
64+
}
65+
66+
pub fn write_short_result(&mut self, verbose: &str, quiet: &str, color: term::color::Color)
67+
-> io::Result<()> {
68+
if self.terse {
69+
self.write_pretty(quiet, color)?;
70+
if self.test_count % QUIET_MODE_MAX_COLUMN == QUIET_MODE_MAX_COLUMN - 1 {
71+
// we insert a new line every 100 dots in order to flush the
72+
// screen when dealing with line-buffered output (e.g. piping to
73+
// `stamp` in the rust CI).
74+
self.write_plain("\n")?;
75+
}
76+
77+
self.test_count += 1;
78+
Ok(())
79+
} else {
80+
self.write_pretty(verbose, color)?;
81+
self.write_plain("\n")
82+
}
83+
}
84+
85+
pub fn write_pretty(&mut self, word: &str, color: term::color::Color) -> io::Result<()> {
86+
match self.out {
87+
Pretty(ref mut term) => {
88+
if self.use_color {
89+
term.fg(color)?;
90+
}
91+
term.write_all(word.as_bytes())?;
92+
if self.use_color {
93+
term.reset()?;
94+
}
95+
term.flush()
96+
}
97+
Raw(ref mut stdout) => {
98+
stdout.write_all(word.as_bytes())?;
99+
stdout.flush()
100+
}
101+
}
102+
}
103+
104+
pub fn write_plain<S: AsRef<str>>(&mut self, s: S) -> io::Result<()> {
105+
let s = s.as_ref();
106+
self.out.write_all(s.as_bytes())?;
107+
self.out.flush()
108+
}
109+
110+
pub fn write_outputs(&mut self, state: &ConsoleTestState) -> io::Result<()> {
111+
self.write_plain("\nsuccesses:\n")?;
112+
let mut successes = Vec::new();
113+
let mut stdouts = String::new();
114+
for &(ref f, ref stdout) in &state.not_failures {
115+
successes.push(f.name.to_string());
116+
if !stdout.is_empty() {
117+
stdouts.push_str(&format!("---- {} stdout ----\n\t", f.name));
118+
let output = String::from_utf8_lossy(stdout);
119+
stdouts.push_str(&output);
120+
stdouts.push_str("\n");
121+
}
122+
}
123+
if !stdouts.is_empty() {
124+
self.write_plain("\n")?;
125+
self.write_plain(&stdouts)?;
126+
}
127+
128+
self.write_plain("\nsuccesses:\n")?;
129+
successes.sort();
130+
for name in &successes {
131+
self.write_plain(&format!(" {}\n", name))?;
132+
}
133+
Ok(())
134+
}
135+
136+
pub fn write_failures(&mut self, state: &ConsoleTestState) -> io::Result<()> {
137+
self.write_plain("\nfailures:\n")?;
138+
let mut failures = Vec::new();
139+
let mut fail_out = String::new();
140+
for &(ref f, ref stdout) in &state.failures {
141+
failures.push(f.name.to_string());
142+
if !stdout.is_empty() {
143+
fail_out.push_str(&format!("---- {} stdout ----\n\t", f.name));
144+
let output = String::from_utf8_lossy(stdout);
145+
fail_out.push_str(&output);
146+
fail_out.push_str("\n");
147+
}
148+
}
149+
if !fail_out.is_empty() {
150+
self.write_plain("\n")?;
151+
self.write_plain(&fail_out)?;
152+
}
153+
154+
self.write_plain("\nfailures:\n")?;
155+
failures.sort();
156+
for name in &failures {
157+
self.write_plain(&format!(" {}\n", name))?;
158+
}
159+
Ok(())
160+
}
161+
}
162+
163+
impl<T: Write> OutputFormatter for HumanFormatter<T> {
164+
fn write_run_start(&mut self, len: usize) -> io::Result<()> {
165+
let noun = if len != 1 {
166+
"tests"
167+
} else {
168+
"test"
169+
};
170+
self.write_plain(&format!("\nrunning {} {}\n", len, noun))
171+
}
172+
173+
fn write_test_start(&mut self,
174+
test: &TestDesc,
175+
align: NamePadding,
176+
max_name_len: usize) -> io::Result<()> {
177+
if self.terse && align != PadOnRight {
178+
Ok(())
179+
}
180+
else {
181+
let name = test.padded_name(max_name_len, align);
182+
self.write_plain(&format!("test {} ... ", name))
183+
}
184+
}
185+
186+
fn write_result(&mut self, result: &TestResult) -> io::Result<()> {
187+
match *result {
188+
TrOk => self.write_ok(),
189+
TrFailed | TrFailedMsg(_) => self.write_failed(),
190+
TrIgnored => self.write_ignored(),
191+
TrAllowedFail => self.write_allowed_fail(),
192+
TrBench(ref bs) => {
193+
self.write_bench()?;
194+
self.write_plain(&format!(": {}\n", fmt_bench_samples(bs)))
195+
}
196+
}
197+
}
198+
199+
fn write_timeout(&mut self, desc: &TestDesc) -> io::Result<()> {
200+
self.write_plain(&format!("test {} has been running for over {} seconds\n",
201+
desc.name,
202+
TEST_WARN_TIMEOUT_S))
203+
}
204+
205+
fn write_run_finish(&mut self, state: &ConsoleTestState) -> io::Result<bool> {
206+
if state.options.display_output {
207+
self.write_outputs(state)?;
208+
}
209+
let success = state.failed == 0;
210+
if !success {
211+
self.write_failures(state)?;
212+
}
213+
214+
self.write_plain("\ntest result: ")?;
215+
216+
if success {
217+
// There's no parallelism at this point so it's safe to use color
218+
self.write_pretty("ok", term::color::GREEN)?;
219+
} else {
220+
self.write_pretty("FAILED", term::color::RED)?;
221+
}
222+
223+
let s = if state.allowed_fail > 0 {
224+
format!(
225+
". {} passed; {} failed ({} allowed); {} ignored; {} measured; {} filtered out\n\n",
226+
state.passed,
227+
state.failed + state.allowed_fail,
228+
state.allowed_fail,
229+
state.ignored,
230+
state.measured,
231+
state.filtered_out)
232+
} else {
233+
format!(
234+
". {} passed; {} failed; {} ignored; {} measured; {} filtered out\n\n",
235+
state.passed,
236+
state.failed,
237+
state.ignored,
238+
state.measured,
239+
state.filtered_out)
240+
};
241+
242+
self.write_plain(&s)?;
243+
244+
Ok(success)
245+
}
246+
}

0 commit comments

Comments
 (0)