Skip to content

Commit 6b99ade

Browse files
committed
Auto merge of #46450 - Gilnaa:libtest_json_output, r=nrc
Libtest json output A revisit to my [last PR](#45923). Events are now more atomic, printed in a flat hierarchy. For the normal test output: ``` running 1 test test f ... FAILED failures: ---- f stdout ---- thread 'f' panicked at 'assertion failed: `(left == right)` left: `3`, right: `4`', f.rs:3:1 note: Run with `RUST_BACKTRACE=1` for a backtrace. failures: f test result: FAILED. 0 passed; 1 failed; 0 ignored; 0 measured; 0 filtered out ``` The JSON equivalent is: ``` { "type": "suite", "event": "started", "test_count": "1" } { "type": "test", "event": "started", "name": "f" } { "type": "test", "event": "failed", "name": "f" } { "type": "suite", "event": "failed", "passed": 0, "failed": 1, "allowed_fail": 0, "ignored": 0, "measured": 0, "filtered_out": "0" } { "type": "test_output", "name": "f", "output": "thread 'f' panicked at 'assertion failed: `(left == right)` left: `3`, right: `4`', f.rs:3:1 note: Run with `RUST_BACKTRACE=1` for a backtrace. " } ```
2 parents 6272b60 + 8b7f1d0 commit 6b99ade

File tree

12 files changed

+1711
-754
lines changed

12 files changed

+1711
-754
lines changed

src/libtest/formatters/json.rs

+229
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,229 @@
1+
// Copyright 2012-2017 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) struct JsonFormatter<T> {
14+
out: OutputLocation<T>,
15+
}
16+
17+
impl<T: Write> JsonFormatter<T> {
18+
pub fn new(out: OutputLocation<T>) -> Self {
19+
Self { out }
20+
}
21+
22+
fn write_message(&mut self, s: &str) -> io::Result<()> {
23+
assert!(!s.contains('\n'));
24+
25+
self.out.write_all(s.as_ref())?;
26+
self.out.write_all(b"\n")
27+
}
28+
29+
fn write_event(
30+
&mut self,
31+
ty: &str,
32+
name: &str,
33+
evt: &str,
34+
extra: Option<String>,
35+
) -> io::Result<()> {
36+
if let Some(extras) = extra {
37+
self.write_message(&*format!(
38+
r#"{{ "type": "{}", "name": "{}", "event": "{}", {} }}"#,
39+
ty,
40+
name,
41+
evt,
42+
extras
43+
))
44+
} else {
45+
self.write_message(&*format!(
46+
r#"{{ "type": "{}", "name": "{}", "event": "{}" }}"#,
47+
ty,
48+
name,
49+
evt
50+
))
51+
}
52+
}
53+
}
54+
55+
impl<T: Write> OutputFormatter for JsonFormatter<T> {
56+
fn write_run_start(&mut self, test_count: usize) -> io::Result<()> {
57+
self.write_message(&*format!(
58+
r#"{{ "type": "suite", "event": "started", "test_count": "{}" }}"#,
59+
test_count
60+
))
61+
}
62+
63+
fn write_test_start(&mut self, desc: &TestDesc) -> io::Result<()> {
64+
self.write_message(&*format!(
65+
r#"{{ "type": "test", "event": "started", "name": "{}" }}"#,
66+
desc.name
67+
))
68+
}
69+
70+
fn write_result(
71+
&mut self,
72+
desc: &TestDesc,
73+
result: &TestResult,
74+
stdout: &[u8],
75+
) -> io::Result<()> {
76+
match *result {
77+
TrOk => self.write_event("test", desc.name.as_slice(), "ok", None),
78+
79+
TrFailed => {
80+
let extra_data = if stdout.len() > 0 {
81+
Some(format!(
82+
r#""stdout": "{}""#,
83+
EscapedString(String::from_utf8_lossy(stdout))
84+
))
85+
} else {
86+
None
87+
};
88+
89+
self.write_event("test", desc.name.as_slice(), "failed", extra_data)
90+
}
91+
92+
TrFailedMsg(ref m) => {
93+
self.write_event(
94+
"test",
95+
desc.name.as_slice(),
96+
"failed",
97+
Some(format!(r#""message": "{}""#, EscapedString(m))),
98+
)
99+
}
100+
101+
TrIgnored => self.write_event("test", desc.name.as_slice(), "ignored", None),
102+
103+
TrAllowedFail => {
104+
self.write_event("test", desc.name.as_slice(), "allowed_failure", None)
105+
}
106+
107+
TrBench(ref bs) => {
108+
let median = bs.ns_iter_summ.median as usize;
109+
let deviation = (bs.ns_iter_summ.max - bs.ns_iter_summ.min) as usize;
110+
111+
let mbps = if bs.mb_s == 0 {
112+
"".into()
113+
} else {
114+
format!(r#", "mib_per_second": {}"#, bs.mb_s)
115+
};
116+
117+
let line = format!(
118+
"{{ \"type\": \"bench\", \
119+
\"name\": \"{}\", \
120+
\"median\": {}, \
121+
\"deviation\": {}{} }}",
122+
desc.name,
123+
median,
124+
deviation,
125+
mbps
126+
);
127+
128+
self.write_message(&*line)
129+
}
130+
}
131+
}
132+
133+
fn write_timeout(&mut self, desc: &TestDesc) -> io::Result<()> {
134+
self.write_message(&*format!(
135+
r#"{{ "type": "test", "event": "timeout", "name": "{}" }}"#,
136+
desc.name
137+
))
138+
}
139+
140+
fn write_run_finish(&mut self, state: &ConsoleTestState) -> io::Result<bool> {
141+
142+
self.write_message(&*format!(
143+
"{{ \"type\": \"suite\", \
144+
\"event\": \"{}\", \
145+
\"passed\": {}, \
146+
\"failed\": {}, \
147+
\"allowed_fail\": {}, \
148+
\"ignored\": {}, \
149+
\"measured\": {}, \
150+
\"filtered_out\": \"{}\" }}",
151+
if state.failed == 0 { "ok" } else { "failed" },
152+
state.passed,
153+
state.failed + state.allowed_fail,
154+
state.allowed_fail,
155+
state.ignored,
156+
state.measured,
157+
state.filtered_out
158+
))?;
159+
160+
Ok(state.failed == 0)
161+
}
162+
}
163+
164+
/// A formatting utility used to print strings with characters in need of escaping.
165+
/// Base code taken form `libserialize::json::escape_str`
166+
struct EscapedString<S: AsRef<str>>(S);
167+
168+
impl<S: AsRef<str>> ::std::fmt::Display for EscapedString<S> {
169+
fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
170+
let mut start = 0;
171+
172+
for (i, byte) in self.0.as_ref().bytes().enumerate() {
173+
let escaped = match byte {
174+
b'"' => "\\\"",
175+
b'\\' => "\\\\",
176+
b'\x00' => "\\u0000",
177+
b'\x01' => "\\u0001",
178+
b'\x02' => "\\u0002",
179+
b'\x03' => "\\u0003",
180+
b'\x04' => "\\u0004",
181+
b'\x05' => "\\u0005",
182+
b'\x06' => "\\u0006",
183+
b'\x07' => "\\u0007",
184+
b'\x08' => "\\b",
185+
b'\t' => "\\t",
186+
b'\n' => "\\n",
187+
b'\x0b' => "\\u000b",
188+
b'\x0c' => "\\f",
189+
b'\r' => "\\r",
190+
b'\x0e' => "\\u000e",
191+
b'\x0f' => "\\u000f",
192+
b'\x10' => "\\u0010",
193+
b'\x11' => "\\u0011",
194+
b'\x12' => "\\u0012",
195+
b'\x13' => "\\u0013",
196+
b'\x14' => "\\u0014",
197+
b'\x15' => "\\u0015",
198+
b'\x16' => "\\u0016",
199+
b'\x17' => "\\u0017",
200+
b'\x18' => "\\u0018",
201+
b'\x19' => "\\u0019",
202+
b'\x1a' => "\\u001a",
203+
b'\x1b' => "\\u001b",
204+
b'\x1c' => "\\u001c",
205+
b'\x1d' => "\\u001d",
206+
b'\x1e' => "\\u001e",
207+
b'\x1f' => "\\u001f",
208+
b'\x7f' => "\\u007f",
209+
_ => {
210+
continue;
211+
}
212+
};
213+
214+
if start < i {
215+
f.write_str(&self.0.as_ref()[start..i])?;
216+
}
217+
218+
f.write_str(escaped)?;
219+
220+
start = i + 1;
221+
}
222+
223+
if start != self.0.as_ref().len() {
224+
f.write_str(&self.0.as_ref()[start..])?;
225+
}
226+
227+
Ok(())
228+
}
229+
}

src/libtest/formatters/mod.rs

+32
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
// Copyright 2012-2017 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+
mod pretty;
14+
mod json;
15+
mod terse;
16+
17+
pub(crate) use self::pretty::PrettyFormatter;
18+
pub(crate) use self::json::JsonFormatter;
19+
pub(crate) use self::terse::TerseFormatter;
20+
21+
pub(crate) trait OutputFormatter {
22+
fn write_run_start(&mut self, test_count: usize) -> io::Result<()>;
23+
fn write_test_start(&mut self, desc: &TestDesc) -> io::Result<()>;
24+
fn write_timeout(&mut self, desc: &TestDesc) -> io::Result<()>;
25+
fn write_result(
26+
&mut self,
27+
desc: &TestDesc,
28+
result: &TestResult,
29+
stdout: &[u8],
30+
) -> io::Result<()>;
31+
fn write_run_finish(&mut self, state: &ConsoleTestState) -> io::Result<bool>;
32+
}

0 commit comments

Comments
 (0)