diff options
author | Gilad Naaman <gilad.naaman@gmail.com> | 2017-12-15 17:25:44 +0200 |
---|---|---|
committer | Gilad Naaman <gilad.naaman@gmail.com> | 2018-01-26 19:46:04 +0200 |
commit | 94bd1216bb735514118670878d28081f8493d1ac (patch) | |
tree | 6d1027a8425a720aa527592fb3591ce718b1ab04 | |
parent | e570e9e79aa4ebfa5c1f9f9b2345dfb3525e42e7 (diff) | |
download | rust-94bd1216bb735514118670878d28081f8493d1ac.tar.gz |
libtest: Fixed pretty-printing of test names in single-threaded code.
-rw-r--r-- | src/libtest/formatters.rs | 83 | ||||
-rw-r--r-- | src/libtest/lib.rs | 22 |
2 files changed, 69 insertions, 36 deletions
diff --git a/src/libtest/formatters.rs b/src/libtest/formatters.rs index 08d87b90978..f45ae3a7c2c 100644 --- a/src/libtest/formatters.rs +++ b/src/libtest/formatters.rs @@ -11,8 +11,8 @@ use super::*; pub(crate) trait OutputFormatter { - fn write_run_start(&mut self, len: usize) -> io::Result<()>; - fn write_test_start(&mut self, test: &TestDesc) -> io::Result<()>; + fn write_run_start(&mut self, test_count: usize) -> io::Result<()>; + fn write_test_start(&mut self, desc: &TestDesc) -> io::Result<()>; fn write_timeout(&mut self, desc: &TestDesc) -> io::Result<()>; fn write_result(&mut self, desc: &TestDesc, @@ -26,17 +26,26 @@ pub(crate) struct HumanFormatter<T> { terse: bool, use_color: bool, 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> { - 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 { out, terse, use_color, test_count: 0, max_name_len, + is_multithreaded, } } @@ -160,28 +169,42 @@ impl<T: Write> HumanFormatter<T> { } 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> { - fn write_run_start(&mut self, len: usize) -> io::Result<()> { - let noun = if len != 1 { + fn write_run_start(&mut self, test_count: usize) -> io::Result<()> { + let noun = if test_count != 1 { "tests" } else { "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<()> { - // Do not print header, as priting it at this point will result in - // an unreadable output when running tests concurrently. + fn write_test_start(&mut self, desc: &TestDesc) -> io::Result<()> { + // When running tests concurrently, we should not print + // 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(()) } fn write_result(&mut self, desc: &TestDesc, result: &TestResult, _: &[u8]) -> 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))?; + if self.is_multithreaded { + self.write_test_name(desc)?; } match *result { @@ -197,6 +220,10 @@ impl<T: Write> OutputFormatter for HumanFormatter<T> { } 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", desc.name, TEST_WARN_TIMEOUT_S)) @@ -251,13 +278,14 @@ pub(crate) struct JsonFormatter<T> { impl<T: Write> JsonFormatter<T> { pub fn new(out: OutputLocation<T>) -> Self { - Self { - out, } + Self { out } } - fn write_str<S: AsRef<str>>(&mut self, s: S) -> io::Result<()> { - self.out.write_all(s.as_ref().as_ref())?; - self.out.write_all("\n".as_ref()) + fn write_message(&mut self, s: &str) -> io::Result<()> { + assert!(!s.contains('\n')); + + self.out.write_all(s.as_ref())?; + self.out.write_all(b"\n") } fn write_event(&mut self, @@ -266,14 +294,14 @@ impl<T: Write> JsonFormatter<T> { evt: &str, extra: Option<String>) -> io::Result<()> { if let Some(extras) = extra { - self.write_str(&*format!(r#"{{ "type": "{}", "name": "{}", "event": "{}", {} }}"#, + self.write_message(&*format!(r#"{{ "type": "{}", "name": "{}", "event": "{}", {} }}"#, ty, name, evt, extras)) } else { - self.write_str(&*format!(r#"{{ "type": "{}", "name": "{}", "event": "{}" }}"#, + self.write_message(&*format!(r#"{{ "type": "{}", "name": "{}", "event": "{}" }}"#, ty, name, evt)) @@ -282,13 +310,14 @@ impl<T: Write> JsonFormatter<T> { } impl<T: Write> OutputFormatter for JsonFormatter<T> { - fn write_run_start(&mut self, len: usize) -> io::Result<()> { - self.write_str( - &*format!(r#"{{ "type": "suite", "event": "started", "test_count": "{}" }}"#, len)) + fn write_run_start(&mut self, test_count: usize) -> io::Result<()> { + self.write_message( + &*format!(r#"{{ "type": "suite", "event": "started", "test_count": "{}" }}"#, + test_count)) } 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)) } @@ -348,19 +377,19 @@ impl<T: Write> OutputFormatter for JsonFormatter<T> { deviation, mbps); - self.write_str(&*line) + self.write_message(&*line) }, } } 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)) } fn write_run_finish(&mut self, state: &ConsoleTestState) -> io::Result<bool> { - self.write_str(&*format!("{{ \"type\": \"suite\", \ + self.write_message(&*format!("{{ \"type\": \"suite\", \ \"event\": \"{}\", \ \"passed\": {}, \ \"failed\": {}, \ diff --git a/src/libtest/lib.rs b/src/libtest/lib.rs index caaa4f7e2b7..04c0734b524 100644 --- a/src/libtest/lib.rs +++ b/src/libtest/lib.rs @@ -719,7 +719,7 @@ pub fn list_tests_console(opts: &TestOpts, tests: Vec<TestDescAndFn>) -> io::Res }; 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 ntest = 0; @@ -820,23 +820,27 @@ pub fn run_tests_console(opts: &TestOpts, tests: Vec<TestDescAndFn>) -> io::Resu Some(t) => Pretty(t), }; - let max_name_len = if let Some(t) = tests.iter().max_by_key(|t| len_if_padded(*t)) { - let n = t.desc.name.as_slice(); - n.len() - } - else { - 0 + let max_name_len = tests.iter() + .max_by_key(|t| len_if_padded(*t)) + .map(|t| t.desc.name.as_slice().len()) + .unwrap_or(0); + + let is_multithreaded = match opts.test_threads { + Some(n) => n > 1, + None => get_concurrency() > 1, }; let mut out: Box<OutputFormatter> = match opts.format { OutputFormat::Pretty => Box::new(HumanFormatter::new(output, use_color(opts), false, - max_name_len)), + max_name_len, + is_multithreaded)), OutputFormat::Terse => Box::new(HumanFormatter::new(output, use_color(opts), true, - max_name_len)), + max_name_len, + is_multithreaded)), OutputFormat::Json => Box::new(JsonFormatter::new(output)), }; let mut st = ConsoleTestState::new(opts)?; |