libtest: Fixed pretty-printing of test names in single-threaded code.
This commit is contained in:
parent
e570e9e79a
commit
94bd1216bb
2 changed files with 69 additions and 36 deletions
|
@ -11,8 +11,8 @@
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
pub(crate) trait OutputFormatter {
|
pub(crate) trait OutputFormatter {
|
||||||
fn write_run_start(&mut self, len: usize) -> io::Result<()>;
|
fn write_run_start(&mut self, test_count: usize) -> io::Result<()>;
|
||||||
fn write_test_start(&mut self, test: &TestDesc) -> io::Result<()>;
|
fn write_test_start(&mut self, desc: &TestDesc) -> io::Result<()>;
|
||||||
fn write_timeout(&mut self, desc: &TestDesc) -> io::Result<()>;
|
fn write_timeout(&mut self, desc: &TestDesc) -> io::Result<()>;
|
||||||
fn write_result(&mut self,
|
fn write_result(&mut self,
|
||||||
desc: &TestDesc,
|
desc: &TestDesc,
|
||||||
|
@ -26,17 +26,26 @@ pub(crate) struct HumanFormatter<T> {
|
||||||
terse: bool,
|
terse: bool,
|
||||||
use_color: bool,
|
use_color: bool,
|
||||||
test_count: usize,
|
test_count: usize,
|
||||||
max_name_len: usize, // number of columns to fill when aligning names
|
|
||||||
|
/// Number of columns to fill when aligning names
|
||||||
|
max_name_len: usize,
|
||||||
|
|
||||||
|
is_multithreaded: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: Write> HumanFormatter<T> {
|
impl<T: Write> HumanFormatter<T> {
|
||||||
pub fn new(out: OutputLocation<T>, use_color: bool, terse: bool, max_name_len: usize) -> Self {
|
pub fn new(out: OutputLocation<T>,
|
||||||
|
use_color: bool,
|
||||||
|
terse: bool,
|
||||||
|
max_name_len: usize,
|
||||||
|
is_multithreaded: bool) -> Self {
|
||||||
HumanFormatter {
|
HumanFormatter {
|
||||||
out,
|
out,
|
||||||
terse,
|
terse,
|
||||||
use_color,
|
use_color,
|
||||||
test_count: 0,
|
test_count: 0,
|
||||||
max_name_len,
|
max_name_len,
|
||||||
|
is_multithreaded,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -160,28 +169,42 @@ impl<T: Write> HumanFormatter<T> {
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn write_test_name(&mut self, desc: &TestDesc) -> io::Result<()> {
|
||||||
|
if !(self.terse && desc.name.padding() != PadOnRight) {
|
||||||
|
let name = desc.padded_name(self.max_name_len, desc.name.padding());
|
||||||
|
self.write_plain(&format!("test {} ... ", name))?;
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: Write> OutputFormatter for HumanFormatter<T> {
|
impl<T: Write> OutputFormatter for HumanFormatter<T> {
|
||||||
fn write_run_start(&mut self, len: usize) -> io::Result<()> {
|
fn write_run_start(&mut self, test_count: usize) -> io::Result<()> {
|
||||||
let noun = if len != 1 {
|
let noun = if test_count != 1 {
|
||||||
"tests"
|
"tests"
|
||||||
} else {
|
} else {
|
||||||
"test"
|
"test"
|
||||||
};
|
};
|
||||||
self.write_plain(&format!("\nrunning {} {}\n", len, noun))
|
self.write_plain(&format!("\nrunning {} {}\n", test_count, noun))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn write_test_start(&mut self, _desc: &TestDesc) -> io::Result<()> {
|
fn write_test_start(&mut self, desc: &TestDesc) -> io::Result<()> {
|
||||||
// Do not print header, as priting it at this point will result in
|
// When running tests concurrently, we should not print
|
||||||
// an unreadable output when running tests concurrently.
|
// the test's name as the result will be mis-aligned.
|
||||||
|
// When running the tests serially, we print the name here so
|
||||||
|
// that the user can see which test hangs.
|
||||||
|
if !self.is_multithreaded {
|
||||||
|
self.write_test_name(desc)?;
|
||||||
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn write_result(&mut self, desc: &TestDesc, result: &TestResult, _: &[u8]) -> io::Result<()> {
|
fn write_result(&mut self, desc: &TestDesc, result: &TestResult, _: &[u8]) -> io::Result<()> {
|
||||||
if !(self.terse && desc.name.padding() != PadOnRight) {
|
if self.is_multithreaded {
|
||||||
let name = desc.padded_name(self.max_name_len, desc.name.padding());
|
self.write_test_name(desc)?;
|
||||||
self.write_plain(&format!("test {} ... ", name))?;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
match *result {
|
match *result {
|
||||||
|
@ -197,6 +220,10 @@ impl<T: Write> OutputFormatter for HumanFormatter<T> {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn write_timeout(&mut self, desc: &TestDesc) -> io::Result<()> {
|
fn write_timeout(&mut self, desc: &TestDesc) -> io::Result<()> {
|
||||||
|
if self.is_multithreaded {
|
||||||
|
self.write_test_name(desc)?;
|
||||||
|
}
|
||||||
|
|
||||||
self.write_plain(&format!("test {} has been running for over {} seconds\n",
|
self.write_plain(&format!("test {} has been running for over {} seconds\n",
|
||||||
desc.name,
|
desc.name,
|
||||||
TEST_WARN_TIMEOUT_S))
|
TEST_WARN_TIMEOUT_S))
|
||||||
|
@ -251,13 +278,14 @@ pub(crate) struct JsonFormatter<T> {
|
||||||
|
|
||||||
impl<T: Write> JsonFormatter<T> {
|
impl<T: Write> JsonFormatter<T> {
|
||||||
pub fn new(out: OutputLocation<T>) -> Self {
|
pub fn new(out: OutputLocation<T>) -> Self {
|
||||||
Self {
|
Self { out }
|
||||||
out, }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn write_str<S: AsRef<str>>(&mut self, s: S) -> io::Result<()> {
|
fn write_message(&mut self, s: &str) -> io::Result<()> {
|
||||||
self.out.write_all(s.as_ref().as_ref())?;
|
assert!(!s.contains('\n'));
|
||||||
self.out.write_all("\n".as_ref())
|
|
||||||
|
self.out.write_all(s.as_ref())?;
|
||||||
|
self.out.write_all(b"\n")
|
||||||
}
|
}
|
||||||
|
|
||||||
fn write_event(&mut self,
|
fn write_event(&mut self,
|
||||||
|
@ -266,14 +294,14 @@ impl<T: Write> JsonFormatter<T> {
|
||||||
evt: &str,
|
evt: &str,
|
||||||
extra: Option<String>) -> io::Result<()> {
|
extra: Option<String>) -> io::Result<()> {
|
||||||
if let Some(extras) = extra {
|
if let Some(extras) = extra {
|
||||||
self.write_str(&*format!(r#"{{ "type": "{}", "name": "{}", "event": "{}", {} }}"#,
|
self.write_message(&*format!(r#"{{ "type": "{}", "name": "{}", "event": "{}", {} }}"#,
|
||||||
ty,
|
ty,
|
||||||
name,
|
name,
|
||||||
evt,
|
evt,
|
||||||
extras))
|
extras))
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
self.write_str(&*format!(r#"{{ "type": "{}", "name": "{}", "event": "{}" }}"#,
|
self.write_message(&*format!(r#"{{ "type": "{}", "name": "{}", "event": "{}" }}"#,
|
||||||
ty,
|
ty,
|
||||||
name,
|
name,
|
||||||
evt))
|
evt))
|
||||||
|
@ -282,13 +310,14 @@ impl<T: Write> JsonFormatter<T> {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: Write> OutputFormatter for JsonFormatter<T> {
|
impl<T: Write> OutputFormatter for JsonFormatter<T> {
|
||||||
fn write_run_start(&mut self, len: usize) -> io::Result<()> {
|
fn write_run_start(&mut self, test_count: usize) -> io::Result<()> {
|
||||||
self.write_str(
|
self.write_message(
|
||||||
&*format!(r#"{{ "type": "suite", "event": "started", "test_count": "{}" }}"#, len))
|
&*format!(r#"{{ "type": "suite", "event": "started", "test_count": "{}" }}"#,
|
||||||
|
test_count))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn write_test_start(&mut self, desc: &TestDesc) -> io::Result<()> {
|
fn write_test_start(&mut self, desc: &TestDesc) -> io::Result<()> {
|
||||||
self.write_str(&*format!(r#"{{ "type": "test", "event": "started", "name": "{}" }}"#,
|
self.write_message(&*format!(r#"{{ "type": "test", "event": "started", "name": "{}" }}"#,
|
||||||
desc.name))
|
desc.name))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -348,19 +377,19 @@ impl<T: Write> OutputFormatter for JsonFormatter<T> {
|
||||||
deviation,
|
deviation,
|
||||||
mbps);
|
mbps);
|
||||||
|
|
||||||
self.write_str(&*line)
|
self.write_message(&*line)
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn write_timeout(&mut self, desc: &TestDesc) -> io::Result<()> {
|
fn write_timeout(&mut self, desc: &TestDesc) -> io::Result<()> {
|
||||||
self.write_str(&*format!(r#"{{ "type": "test", "event": "timeout", "name": "{}" }}"#,
|
self.write_message(&*format!(r#"{{ "type": "test", "event": "timeout", "name": "{}" }}"#,
|
||||||
desc.name))
|
desc.name))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn write_run_finish(&mut self, state: &ConsoleTestState) -> io::Result<bool> {
|
fn write_run_finish(&mut self, state: &ConsoleTestState) -> io::Result<bool> {
|
||||||
|
|
||||||
self.write_str(&*format!("{{ \"type\": \"suite\", \
|
self.write_message(&*format!("{{ \"type\": \"suite\", \
|
||||||
\"event\": \"{}\", \
|
\"event\": \"{}\", \
|
||||||
\"passed\": {}, \
|
\"passed\": {}, \
|
||||||
\"failed\": {}, \
|
\"failed\": {}, \
|
||||||
|
|
|
@ -719,7 +719,7 @@ pub fn list_tests_console(opts: &TestOpts, tests: Vec<TestDescAndFn>) -> io::Res
|
||||||
};
|
};
|
||||||
|
|
||||||
let quiet = opts.format == OutputFormat::Terse;
|
let quiet = opts.format == OutputFormat::Terse;
|
||||||
let mut out = HumanFormatter::new(output, use_color(opts), quiet, 0);
|
let mut out = HumanFormatter::new(output, use_color(opts), quiet, 0, false);
|
||||||
let mut st = ConsoleTestState::new(opts)?;
|
let mut st = ConsoleTestState::new(opts)?;
|
||||||
|
|
||||||
let mut ntest = 0;
|
let mut ntest = 0;
|
||||||
|
@ -820,23 +820,27 @@ pub fn run_tests_console(opts: &TestOpts, tests: Vec<TestDescAndFn>) -> io::Resu
|
||||||
Some(t) => Pretty(t),
|
Some(t) => Pretty(t),
|
||||||
};
|
};
|
||||||
|
|
||||||
let max_name_len = if let Some(t) = tests.iter().max_by_key(|t| len_if_padded(*t)) {
|
let max_name_len = tests.iter()
|
||||||
let n = t.desc.name.as_slice();
|
.max_by_key(|t| len_if_padded(*t))
|
||||||
n.len()
|
.map(|t| t.desc.name.as_slice().len())
|
||||||
}
|
.unwrap_or(0);
|
||||||
else {
|
|
||||||
0
|
let is_multithreaded = match opts.test_threads {
|
||||||
|
Some(n) => n > 1,
|
||||||
|
None => get_concurrency() > 1,
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut out: Box<OutputFormatter> = match opts.format {
|
let mut out: Box<OutputFormatter> = match opts.format {
|
||||||
OutputFormat::Pretty => Box::new(HumanFormatter::new(output,
|
OutputFormat::Pretty => Box::new(HumanFormatter::new(output,
|
||||||
use_color(opts),
|
use_color(opts),
|
||||||
false,
|
false,
|
||||||
max_name_len)),
|
max_name_len,
|
||||||
|
is_multithreaded)),
|
||||||
OutputFormat::Terse => Box::new(HumanFormatter::new(output,
|
OutputFormat::Terse => Box::new(HumanFormatter::new(output,
|
||||||
use_color(opts),
|
use_color(opts),
|
||||||
true,
|
true,
|
||||||
max_name_len)),
|
max_name_len,
|
||||||
|
is_multithreaded)),
|
||||||
OutputFormat::Json => Box::new(JsonFormatter::new(output)),
|
OutputFormat::Json => Box::new(JsonFormatter::new(output)),
|
||||||
};
|
};
|
||||||
let mut st = ConsoleTestState::new(opts)?;
|
let mut st = ConsoleTestState::new(opts)?;
|
||||||
|
|
Loading…
Reference in a new issue