Skip to content

Commit c239356

Browse files
author
Gilad Naaman
committed
Refactoring needed in order to have test json output.
1 parent a35a3ab commit c239356

File tree

2 files changed

+318
-242
lines changed

2 files changed

+318
-242
lines changed

src/libtest/formatters.rs

+254
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,254 @@
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_metric(&mut self) -> io::Result<()> {
63+
self.write_pretty("metric", term::color::CYAN)
64+
}
65+
66+
pub fn write_bench(&mut self) -> io::Result<()> {
67+
self.write_pretty("bench", term::color::CYAN)
68+
}
69+
70+
pub fn write_short_result(&mut self, verbose: &str, quiet: &str, color: term::color::Color)
71+
-> io::Result<()> {
72+
if self.terse {
73+
self.write_pretty(quiet, color)?;
74+
if self.test_count % QUIET_MODE_MAX_COLUMN == QUIET_MODE_MAX_COLUMN - 1 {
75+
// we insert a new line every 100 dots in order to flush the
76+
// screen when dealing with line-buffered output (e.g. piping to
77+
// `stamp` in the rust CI).
78+
self.write_plain("\n")?;
79+
}
80+
81+
self.test_count += 1;
82+
Ok(())
83+
} else {
84+
self.write_pretty(verbose, color)?;
85+
self.write_plain("\n")
86+
}
87+
}
88+
89+
pub fn write_pretty(&mut self, word: &str, color: term::color::Color) -> io::Result<()> {
90+
match self.out {
91+
Pretty(ref mut term) => {
92+
if self.use_color {
93+
term.fg(color)?;
94+
}
95+
term.write_all(word.as_bytes())?;
96+
if self.use_color {
97+
term.reset()?;
98+
}
99+
term.flush()
100+
}
101+
Raw(ref mut stdout) => {
102+
stdout.write_all(word.as_bytes())?;
103+
stdout.flush()
104+
}
105+
}
106+
}
107+
108+
pub fn write_plain<S: AsRef<str>>(&mut self, s: S) -> io::Result<()> {
109+
let s = s.as_ref();
110+
self.out.write_all(s.as_bytes())?;
111+
self.out.flush()
112+
}
113+
114+
pub fn write_outputs(&mut self, state: &ConsoleTestState) -> io::Result<()> {
115+
self.write_plain("\nsuccesses:\n")?;
116+
let mut successes = Vec::new();
117+
let mut stdouts = String::new();
118+
for &(ref f, ref stdout) in &state.not_failures {
119+
successes.push(f.name.to_string());
120+
if !stdout.is_empty() {
121+
stdouts.push_str(&format!("---- {} stdout ----\n\t", f.name));
122+
let output = String::from_utf8_lossy(stdout);
123+
stdouts.push_str(&output);
124+
stdouts.push_str("\n");
125+
}
126+
}
127+
if !stdouts.is_empty() {
128+
self.write_plain("\n")?;
129+
self.write_plain(&stdouts)?;
130+
}
131+
132+
self.write_plain("\nsuccesses:\n")?;
133+
successes.sort();
134+
for name in &successes {
135+
self.write_plain(&format!(" {}\n", name))?;
136+
}
137+
Ok(())
138+
}
139+
140+
pub fn write_failures(&mut self, state: &ConsoleTestState) -> io::Result<()> {
141+
self.write_plain("\nfailures:\n")?;
142+
let mut failures = Vec::new();
143+
let mut fail_out = String::new();
144+
for &(ref f, ref stdout) in &state.failures {
145+
failures.push(f.name.to_string());
146+
if !stdout.is_empty() {
147+
fail_out.push_str(&format!("---- {} stdout ----\n\t", f.name));
148+
let output = String::from_utf8_lossy(stdout);
149+
fail_out.push_str(&output);
150+
fail_out.push_str("\n");
151+
}
152+
}
153+
if !fail_out.is_empty() {
154+
self.write_plain("\n")?;
155+
self.write_plain(&fail_out)?;
156+
}
157+
158+
self.write_plain("\nfailures:\n")?;
159+
failures.sort();
160+
for name in &failures {
161+
self.write_plain(&format!(" {}\n", name))?;
162+
}
163+
Ok(())
164+
}
165+
}
166+
167+
impl<T: Write> OutputFormatter for HumanFormatter<T> {
168+
fn write_run_start(&mut self, len: usize) -> io::Result<()> {
169+
let noun = if len != 1 {
170+
"tests"
171+
} else {
172+
"test"
173+
};
174+
self.write_plain(&format!("\nrunning {} {}\n", len, noun))
175+
}
176+
177+
fn write_test_start(&mut self,
178+
test: &TestDesc,
179+
align: NamePadding,
180+
max_name_len: usize) -> io::Result<()> {
181+
if self.terse && align != PadOnRight {
182+
Ok(())
183+
}
184+
else {
185+
let name = test.padded_name(max_name_len, align);
186+
self.write_plain(&format!("test {} ... ", name))
187+
}
188+
}
189+
190+
fn write_result(&mut self, result: &TestResult) -> io::Result<()> {
191+
match *result {
192+
TrOk => self.write_ok(),
193+
TrFailed | TrFailedMsg(_) => self.write_failed(),
194+
TrIgnored => self.write_ignored(),
195+
TrAllowedFail => self.write_allowed_fail(),
196+
TrMetrics(ref mm) => {
197+
self.write_metric()?;
198+
self.write_plain(&format!(": {}\n", mm.fmt_metrics()))
199+
}
200+
TrBench(ref bs) => {
201+
self.write_bench()?;
202+
self.write_plain(&format!(": {}\n", fmt_bench_samples(bs)))
203+
}
204+
}
205+
}
206+
207+
fn write_timeout(&mut self, desc: &TestDesc) -> io::Result<()> {
208+
self.write_plain(&format!("test {} has been running for over {} seconds\n",
209+
desc.name,
210+
TEST_WARN_TIMEOUT_S))
211+
}
212+
213+
fn write_run_finish(&mut self, state: &ConsoleTestState) -> io::Result<bool> {
214+
if state.options.display_output {
215+
self.write_outputs(state)?;
216+
}
217+
let success = state.failed == 0;
218+
if !success {
219+
self.write_failures(state)?;
220+
}
221+
222+
self.write_plain("\ntest result: ")?;
223+
224+
if success {
225+
// There's no parallelism at this point so it's safe to use color
226+
self.write_pretty("ok", term::color::GREEN)?;
227+
} else {
228+
self.write_pretty("FAILED", term::color::RED)?;
229+
}
230+
231+
let s = if state.allowed_fail > 0 {
232+
format!(
233+
". {} passed; {} failed ({} allowed); {} ignored; {} measured; {} filtered out\n\n",
234+
state.passed,
235+
state.failed + state.allowed_fail,
236+
state.allowed_fail,
237+
state.ignored,
238+
state.measured,
239+
state.filtered_out)
240+
} else {
241+
format!(
242+
". {} passed; {} failed; {} ignored; {} measured; {} filtered out\n\n",
243+
state.passed,
244+
state.failed,
245+
state.ignored,
246+
state.measured,
247+
state.filtered_out)
248+
};
249+
250+
self.write_plain(&s)?;
251+
252+
Ok(success)
253+
}
254+
}

0 commit comments

Comments
 (0)