Skip to content

Commit 409a41d

Browse files
author
Paul Emmerich
committed
libtest: support display_output in JSON formatter
1 parent 1add949 commit 409a41d

File tree

9 files changed

+77
-40
lines changed

9 files changed

+77
-40
lines changed

src/libtest/formatters/json.rs

+40-31
Original file line numberDiff line numberDiff line change
@@ -9,44 +9,57 @@ impl<T: Write> JsonFormatter<T> {
99
Self { out }
1010
}
1111

12-
fn write_message(&mut self, s: &str) -> io::Result<()> {
12+
fn writeln_message(&mut self, s: &str) -> io::Result<()> {
1313
assert!(!s.contains('\n'));
1414

1515
self.out.write_all(s.as_ref())?;
1616
self.out.write_all(b"\n")
1717
}
1818

19+
fn write_message(&mut self, s: &str) -> io::Result<()> {
20+
assert!(!s.contains('\n'));
21+
22+
self.out.write_all(s.as_ref())
23+
}
24+
1925
fn write_event(
2026
&mut self,
2127
ty: &str,
2228
name: &str,
2329
evt: &str,
24-
extra: Option<String>,
30+
stdout: Option<Cow<'_, str>>,
31+
extra: Option<&str>,
2532
) -> io::Result<()> {
26-
if let Some(extras) = extra {
33+
self.write_message(&*format!(
34+
r#"{{ "type": "{}", "name": "{}", "event": "{}""#,
35+
ty, name, evt
36+
))?;
37+
if let Some(stdout) = stdout {
2738
self.write_message(&*format!(
28-
r#"{{ "type": "{}", "name": "{}", "event": "{}", {} }}"#,
29-
ty, name, evt, extras
30-
))
31-
} else {
39+
r#", "stdout": "{}""#,
40+
EscapedString(stdout)
41+
))?;
42+
}
43+
if let Some(extra) = extra {
3244
self.write_message(&*format!(
33-
r#"{{ "type": "{}", "name": "{}", "event": "{}" }}"#,
34-
ty, name, evt
35-
))
45+
r#", {}"#,
46+
extra
47+
))?;
3648
}
49+
self.writeln_message(" }")
3750
}
3851
}
3952

4053
impl<T: Write> OutputFormatter for JsonFormatter<T> {
4154
fn write_run_start(&mut self, test_count: usize) -> io::Result<()> {
42-
self.write_message(&*format!(
55+
self.writeln_message(&*format!(
4356
r#"{{ "type": "suite", "event": "started", "test_count": {} }}"#,
4457
test_count
4558
))
4659
}
4760

4861
fn write_test_start(&mut self, desc: &TestDesc) -> io::Result<()> {
49-
self.write_message(&*format!(
62+
self.writeln_message(&*format!(
5063
r#"{{ "type": "test", "event": "started", "name": "{}" }}"#,
5164
desc.name
5265
))
@@ -57,34 +70,30 @@ impl<T: Write> OutputFormatter for JsonFormatter<T> {
5770
desc: &TestDesc,
5871
result: &TestResult,
5972
stdout: &[u8],
73+
state: &ConsoleTestState,
6074
) -> io::Result<()> {
75+
let stdout = if (state.options.display_output || *result != TrOk) && stdout.len() > 0 {
76+
Some(String::from_utf8_lossy(stdout))
77+
} else {
78+
None
79+
};
6180
match *result {
62-
TrOk => self.write_event("test", desc.name.as_slice(), "ok", None),
63-
64-
TrFailed => {
65-
let extra_data = if stdout.len() > 0 {
66-
Some(format!(
67-
r#""stdout": "{}""#,
68-
EscapedString(String::from_utf8_lossy(stdout))
69-
))
70-
} else {
71-
None
72-
};
81+
TrOk => self.write_event("test", desc.name.as_slice(), "ok", stdout, None),
7382

74-
self.write_event("test", desc.name.as_slice(), "failed", extra_data)
75-
}
83+
TrFailed => self.write_event("test", desc.name.as_slice(), "failed", stdout, None),
7684

7785
TrFailedMsg(ref m) => self.write_event(
7886
"test",
7987
desc.name.as_slice(),
8088
"failed",
81-
Some(format!(r#""message": "{}""#, EscapedString(m))),
89+
stdout,
90+
Some(&*format!(r#""message": "{}""#, EscapedString(m))),
8291
),
8392

84-
TrIgnored => self.write_event("test", desc.name.as_slice(), "ignored", None),
93+
TrIgnored => self.write_event("test", desc.name.as_slice(), "ignored", stdout, None),
8594

8695
TrAllowedFail => {
87-
self.write_event("test", desc.name.as_slice(), "allowed_failure", None)
96+
self.write_event("test", desc.name.as_slice(), "allowed_failure", stdout, None)
8897
}
8998

9099
TrBench(ref bs) => {
@@ -105,20 +114,20 @@ impl<T: Write> OutputFormatter for JsonFormatter<T> {
105114
desc.name, median, deviation, mbps
106115
);
107116

108-
self.write_message(&*line)
117+
self.writeln_message(&*line)
109118
}
110119
}
111120
}
112121

113122
fn write_timeout(&mut self, desc: &TestDesc) -> io::Result<()> {
114-
self.write_message(&*format!(
123+
self.writeln_message(&*format!(
115124
r#"{{ "type": "test", "event": "timeout", "name": "{}" }}"#,
116125
desc.name
117126
))
118127
}
119128

120129
fn write_run_finish(&mut self, state: &ConsoleTestState) -> io::Result<bool> {
121-
self.write_message(&*format!(
130+
self.writeln_message(&*format!(
122131
"{{ \"type\": \"suite\", \
123132
\"event\": \"{}\", \
124133
\"passed\": {}, \

src/libtest/formatters/mod.rs

+1
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ pub(crate) trait OutputFormatter {
1717
desc: &TestDesc,
1818
result: &TestResult,
1919
stdout: &[u8],
20+
state: &ConsoleTestState,
2021
) -> io::Result<()>;
2122
fn write_run_finish(&mut self, state: &ConsoleTestState) -> io::Result<bool>;
2223
}

src/libtest/formatters/pretty.rs

+7-1
Original file line numberDiff line numberDiff line change
@@ -162,7 +162,13 @@ impl<T: Write> OutputFormatter for PrettyFormatter<T> {
162162
Ok(())
163163
}
164164

165-
fn write_result(&mut self, desc: &TestDesc, result: &TestResult, _: &[u8]) -> io::Result<()> {
165+
fn write_result(
166+
&mut self,
167+
desc: &TestDesc,
168+
result: &TestResult,
169+
_: &[u8],
170+
_: &ConsoleTestState,
171+
) -> io::Result<()> {
166172
if self.is_multithreaded {
167173
self.write_test_name(desc)?;
168174
}

src/libtest/formatters/terse.rs

+7-1
Original file line numberDiff line numberDiff line change
@@ -170,7 +170,13 @@ impl<T: Write> OutputFormatter for TerseFormatter<T> {
170170
Ok(())
171171
}
172172

173-
fn write_result(&mut self, desc: &TestDesc, result: &TestResult, _: &[u8]) -> io::Result<()> {
173+
fn write_result(
174+
&mut self,
175+
desc: &TestDesc,
176+
result: &TestResult,
177+
_: &[u8],
178+
_: &ConsoleTestState,
179+
) -> io::Result<()> {
174180
match *result {
175181
TrOk => self.write_ok(),
176182
TrFailed | TrFailedMsg(_) => self.write_failed(),

src/libtest/lib.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -906,7 +906,7 @@ pub fn run_tests_console(opts: &TestOpts, tests: Vec<TestDescAndFn>) -> io::Resu
906906
TeTimeout(ref test) => out.write_timeout(test),
907907
TeResult(test, result, stdout) => {
908908
st.write_log_result(&test, &result)?;
909-
out.write_result(&test, &result, &*stdout)?;
909+
out.write_result(&test, &result, &*stdout, &st)?;
910910
match result {
911911
TrOk => {
912912
st.passed += 1;

src/test/run-make-fulldeps/libtest-json/Makefile

+8-4
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,17 @@
22

33
# Test expected libtest's JSON output
44

5-
OUTPUT_FILE := $(TMPDIR)/libtest-json-output.json
5+
OUTPUT_FILE_DEFAULT := $(TMPDIR)/libtest-json-output-default.json
6+
OUTPUT_FILE_STDOUT_SUCCESS := $(TMPDIR)/libtest-json-output-stdout-success.json
67

78
all:
89
$(RUSTC) --test f.rs
9-
RUST_BACKTRACE=0 $(call RUN,f) -Z unstable-options --test-threads=1 --format=json > $(OUTPUT_FILE) || true
10+
RUST_BACKTRACE=0 $(call RUN,f) -Z unstable-options --test-threads=1 --format=json > $(OUTPUT_FILE_DEFAULT) || true
11+
RUST_BACKTRACE=0 $(call RUN,f) -Z unstable-options --test-threads=1 --format=json --show-output > $(OUTPUT_FILE_STDOUT_SUCCESS) || true
1012

11-
cat $(OUTPUT_FILE) | "$(PYTHON)" validate_json.py
13+
cat $(OUTPUT_FILE_DEFAULT) | "$(PYTHON)" validate_json.py
14+
cat $(OUTPUT_FILE_STDOUT_SUCCESS) | "$(PYTHON)" validate_json.py
1215

1316
# Compare to output file
14-
diff output.json $(OUTPUT_FILE)
17+
diff output-default.json $(OUTPUT_FILE_DEFAULT)
18+
diff output-stdout-success.json $(OUTPUT_FILE_STDOUT_SUCCESS)

src/test/run-make-fulldeps/libtest-json/f.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,12 @@
11
#[test]
22
fn a() {
3+
println!("print from successful test");
34
// Should pass
45
}
56

67
#[test]
78
fn b() {
8-
assert!(false)
9+
assert!(false);
910
}
1011

1112
#[test]

src/test/run-make-fulldeps/libtest-json/output.json src/test/run-make-fulldeps/libtest-json/output-default.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
{ "type": "test", "event": "started", "name": "a" }
33
{ "type": "test", "name": "a", "event": "ok" }
44
{ "type": "test", "event": "started", "name": "b" }
5-
{ "type": "test", "name": "b", "event": "failed", "stdout": "thread 'main' panicked at 'assertion failed: false', f.rs:8:5\nnote: run with `RUST_BACKTRACE=1` environment variable to display a backtrace.\n" }
5+
{ "type": "test", "name": "b", "event": "failed", "stdout": "thread 'main' panicked at 'assertion failed: false', f.rs:9:5\nnote: run with `RUST_BACKTRACE=1` environment variable to display a backtrace.\n" }
66
{ "type": "test", "event": "started", "name": "c" }
77
{ "type": "test", "name": "c", "event": "ok" }
88
{ "type": "test", "event": "started", "name": "d" }
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
{ "type": "suite", "event": "started", "test_count": 4 }
2+
{ "type": "test", "event": "started", "name": "a" }
3+
{ "type": "test", "name": "a", "event": "ok", "stdout": "print from successful test\n" }
4+
{ "type": "test", "event": "started", "name": "b" }
5+
{ "type": "test", "name": "b", "event": "failed", "stdout": "thread 'main' panicked at 'assertion failed: false', f.rs:9:5\nnote: run with `RUST_BACKTRACE=1` environment variable to display a backtrace.\n" }
6+
{ "type": "test", "event": "started", "name": "c" }
7+
{ "type": "test", "name": "c", "event": "ok", "stdout": "thread 'main' panicked at 'assertion failed: false', f.rs:15:5\n" }
8+
{ "type": "test", "event": "started", "name": "d" }
9+
{ "type": "test", "name": "d", "event": "ignored" }
10+
{ "type": "suite", "event": "failed", "passed": 2, "failed": 1, "allowed_fail": 0, "ignored": 1, "measured": 0, "filtered_out": 0 }

0 commit comments

Comments
 (0)