summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGilad Naaman <gilad.naaman@gmail.com>2017-12-15 17:25:44 +0200
committerGilad Naaman <gilad.naaman@gmail.com>2018-01-26 19:46:04 +0200
commit94bd1216bb735514118670878d28081f8493d1ac (patch)
tree6d1027a8425a720aa527592fb3591ce718b1ab04
parente570e9e79aa4ebfa5c1f9f9b2345dfb3525e42e7 (diff)
downloadrust-94bd1216bb735514118670878d28081f8493d1ac.tar.gz
libtest: Fixed pretty-printing of test names in single-threaded code.
-rw-r--r--src/libtest/formatters.rs83
-rw-r--r--src/libtest/lib.rs22
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)?;