Skip to content

Commit 548975d

Browse files
author
Gilad Naaman
committed
libtest: Test start event is printed on time
1 parent 266f26d commit 548975d

File tree

2 files changed

+130
-78
lines changed

2 files changed

+130
-78
lines changed

src/libtest/formatters.rs

+75-56
Original file line numberDiff line numberDiff line change
@@ -12,12 +12,12 @@ use super::*;
1212

1313
pub(crate) trait OutputFormatter {
1414
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<()>;
15+
fn write_test_start(&mut self, test: &TestDesc) -> io::Result<()>;
1916
fn write_timeout(&mut self, desc: &TestDesc) -> io::Result<()>;
20-
fn write_result(&mut self, desc: &TestDesc, result: &TestResult) -> io::Result<()>;
17+
fn write_result(&mut self,
18+
desc: &TestDesc,
19+
result: &TestResult,
20+
stdout: &[u8]) -> io::Result<()>;
2121
fn write_run_finish(&mut self, state: &ConsoleTestState) -> io::Result<bool>;
2222
}
2323

@@ -26,15 +26,17 @@ pub(crate) struct HumanFormatter<T> {
2626
terse: bool,
2727
use_color: bool,
2828
test_count: usize,
29+
max_name_len: usize, // number of columns to fill when aligning names
2930
}
3031

3132
impl<T: Write> HumanFormatter<T> {
32-
pub fn new(out: OutputLocation<T>, use_color: bool, terse: bool) -> Self {
33+
pub fn new(out: OutputLocation<T>, use_color: bool, terse: bool, max_name_len: usize) -> Self {
3334
HumanFormatter {
3435
out,
3536
terse,
3637
use_color,
3738
test_count: 0,
39+
max_name_len,
3840
}
3941
}
4042

@@ -170,20 +172,18 @@ impl<T: Write> OutputFormatter for HumanFormatter<T> {
170172
self.write_plain(&format!("\nrunning {} {}\n", len, noun))
171173
}
172174

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-
}
175+
fn write_test_start(&mut self, _desc: &TestDesc) -> io::Result<()> {
176+
// Do not print header, as priting it at this point will result in
177+
// an unreadable output when running tests concurrently.
178+
Ok(())
184179
}
185180

186-
fn write_result(&mut self, _desc: &TestDesc, result: &TestResult) -> io::Result<()> {
181+
fn write_result(&mut self, desc: &TestDesc, result: &TestResult, _: &[u8]) -> io::Result<()> {
182+
if !(self.terse && desc.name.padding() != PadOnRight) {
183+
let name = desc.padded_name(self.max_name_len, desc.name.padding());
184+
self.write_plain(&format!("test {} ... ", name))?;
185+
}
186+
187187
match *result {
188188
TrOk => self.write_ok(),
189189
TrFailed | TrFailedMsg(_) => self.write_failed(),
@@ -259,6 +259,26 @@ impl<T: Write> JsonFormatter<T> {
259259
self.out.write_all(s.as_ref().as_ref())?;
260260
self.out.write_all("\n".as_ref())
261261
}
262+
263+
fn write_event(&mut self,
264+
ty: &str,
265+
name: &str,
266+
evt: &str,
267+
extra: Option<String>) -> io::Result<()> {
268+
if let Some(extras) = extra {
269+
self.write_str(&*format!(r#"{{ "type": "{}", "name": "{}", "event": "{}", {} }}"#,
270+
ty,
271+
name,
272+
evt,
273+
extras))
274+
}
275+
else {
276+
self.write_str(&*format!(r#"{{ "type": "{}", "name": "{}", "event": "{}" }}"#,
277+
ty,
278+
name,
279+
evt))
280+
}
281+
}
262282
}
263283

264284
impl<T: Write> OutputFormatter for JsonFormatter<T> {
@@ -267,40 +287,45 @@ impl<T: Write> OutputFormatter for JsonFormatter<T> {
267287
&*format!(r#"{{ "type": "suite", "event": "started", "test_count": "{}" }}"#, len))
268288
}
269289

270-
fn write_test_start(&mut self,
271-
desc: &TestDesc,
272-
_align: NamePadding,
273-
_max_name_len: usize) -> io::Result<()> {
290+
fn write_test_start(&mut self, desc: &TestDesc) -> io::Result<()> {
274291
self.write_str(&*format!(r#"{{ "type": "test", "event": "started", "name": "{}" }}"#,
275292
desc.name))
276293
}
277294

278-
fn write_result(&mut self, desc: &TestDesc, result: &TestResult) -> io::Result<()> {
279-
let output = match *result {
295+
fn write_result(&mut self,
296+
desc: &TestDesc,
297+
result: &TestResult,
298+
stdout: &[u8]) -> io::Result<()> {
299+
match *result {
280300
TrOk => {
281-
format!(r#"{{ "type": "test", "event": "ok", "name": "{}" }}"#,
282-
desc.name)
301+
self.write_event("test", desc.name.as_slice(), "ok", None)
283302
},
284303

285304
TrFailed => {
286-
format!(r#"{{ "type": "test", "event": "failed", "name": "{}" }}"#,
287-
desc.name)
305+
let extra_data = if stdout.len() > 0 {
306+
Some(format!(r#""stdout": "{}""#,
307+
EscapedString(String::from_utf8_lossy(stdout))))
308+
}
309+
else {
310+
None
311+
};
312+
313+
self.write_event("test", desc.name.as_slice(), "failed", extra_data)
288314
},
289315

290316
TrFailedMsg(ref m) => {
291-
format!(r#"{{ "type": "test", "event": "failed", "name": "{}", "message": "{}" }}"#,
292-
desc.name,
293-
EscapedString(m))
317+
self.write_event("test",
318+
desc.name.as_slice(),
319+
"failed",
320+
Some(format!(r#""message": "{}""#, EscapedString(m))))
294321
},
295322

296323
TrIgnored => {
297-
format!(r#"{{ "type": "test", "event": "ignored", "name": "{}" }}"#,
298-
desc.name)
324+
self.write_event("test", desc.name.as_slice(), "ignored", None)
299325
},
300326

301327
TrAllowedFail => {
302-
format!(r#"{{ "type": "test", "event": "allowed_failure", "name": "{}" }}"#,
303-
desc.name)
328+
self.write_event("test", desc.name.as_slice(), "allowed_failure", None)
304329
},
305330

306331
TrBench(ref bs) => {
@@ -314,15 +339,18 @@ impl<T: Write> OutputFormatter for JsonFormatter<T> {
314339
format!(r#", "mib_per_second": {}"#, bs.mb_s)
315340
};
316341

317-
format!(r#"{{ "type": "bench", "name": "{}", "median": {}, "deviation": {}{} }}"#,
342+
let line = format!("{{ \"type\": \"bench\", \
343+
\"name\": \"{}\", \
344+
\"median\": {}, \
345+
\"deviation\": {}{} }}",
318346
desc.name,
319347
median,
320348
deviation,
321-
mbps)
322-
},
323-
};
349+
mbps);
324350

325-
self.write_str(&*output)
351+
self.write_str(&*line)
352+
},
353+
}
326354
}
327355

328356
fn write_timeout(&mut self, desc: &TestDesc) -> io::Result<()> {
@@ -348,28 +376,19 @@ impl<T: Write> OutputFormatter for JsonFormatter<T> {
348376
state.measured,
349377
state.filtered_out))?;
350378

351-
for &(ref f, ref stdout) in &state.failures {
352-
if !stdout.is_empty() {
353-
self.write_str(
354-
&*format!(r#"{{ "type": "test_output", "name": "{}", "output": "{}" }}"#,
355-
f.name,
356-
EscapedString(&*String::from_utf8_lossy(stdout))))?;
357-
}
358-
}
359-
360379
Ok(state.failed == 0)
361380
}
362381
}
363382

364383
/// A formatting utility used to print strings with characters in need of escaping.
365384
/// Base code taken form `libserialize::json::escape_str`
366-
struct EscapedString<'a>(&'a str);
385+
struct EscapedString<S: AsRef<str>>(S);
367386

368-
impl<'a> ::std::fmt::Display for EscapedString<'a> {
387+
impl<S: AsRef<str>> ::std::fmt::Display for EscapedString<S> {
369388
fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
370389
let mut start = 0;
371390

372-
for (i, byte) in self.0.bytes().enumerate() {
391+
for (i, byte) in self.0.as_ref().bytes().enumerate() {
373392
let escaped = match byte {
374393
b'"' => "\\\"",
375394
b'\\' => "\\\\",
@@ -410,18 +429,18 @@ impl<'a> ::std::fmt::Display for EscapedString<'a> {
410429
};
411430

412431
if start < i {
413-
f.write_str(&self.0[start..i])?;
432+
f.write_str(&self.0.as_ref()[start..i])?;
414433
}
415434

416435
f.write_str(escaped)?;
417436

418437
start = i + 1;
419438
}
420439

421-
if start != self.0.len() {
422-
f.write_str(&self.0[start..])?;
440+
if start != self.0.as_ref().len() {
441+
f.write_str(&self.0.as_ref()[start..])?;
423442
}
424443

425444
Ok(())
426445
}
427-
}
446+
}

0 commit comments

Comments
 (0)