1
Fork 0

Shorter output for rustc --test binaries.

A program created with `rustc --test` prints at least one line per test.
This can be very verbose, especially with [data-driven tests](
https://internals.rust-lang.org/t/test-and-external-test-harnesses/3145)
when hundreds or thousands of tests is not rare.

This adds a `-q` or `--quiet` option that changes the output
to one character instead of one line per test
(except metrics and benchmarks results which have additional data to
show):

```
     Running target/debug/wpt-75c594dc1e6e6187

running 314 tests
..............................................................................
..............................................................................
..............................................................................
..............................................................................
..
test result: ok. 314 passed; 0 failed; 0 ignored; 0 measured
```

This is a breaking change since the `test::TestOpts` struct
now has one more field.
This commit is contained in:
Simon Sapin 2016-02-25 16:14:05 +01:00
parent c116ae35cf
commit bbb45c41df
3 changed files with 42 additions and 17 deletions

View file

@ -155,5 +155,8 @@ pub struct Config {
pub lldb_python_dir: Option<String>, pub lldb_python_dir: Option<String>,
// Explain what's going on // Explain what's going on
pub verbose: bool pub verbose: bool,
// Print one character per test instead of one line
pub quiet: bool,
} }

View file

@ -78,6 +78,7 @@ pub fn parse_config(args: Vec<String> ) -> Config {
optopt("", "host-rustcflags", "flags to pass to rustc for host", "FLAGS"), optopt("", "host-rustcflags", "flags to pass to rustc for host", "FLAGS"),
optopt("", "target-rustcflags", "flags to pass to rustc for target", "FLAGS"), optopt("", "target-rustcflags", "flags to pass to rustc for target", "FLAGS"),
optflag("", "verbose", "run tests verbosely, showing all output"), optflag("", "verbose", "run tests verbosely, showing all output"),
optflag("", "quiet", "print one character per test instead of one line"),
optopt("", "logfile", "file to log test execution to", "FILE"), optopt("", "logfile", "file to log test execution to", "FILE"),
optopt("", "target", "the target to build for", "TARGET"), optopt("", "target", "the target to build for", "TARGET"),
optopt("", "host", "the host to build for", "HOST"), optopt("", "host", "the host to build for", "HOST"),
@ -158,6 +159,7 @@ pub fn parse_config(args: Vec<String> ) -> Config {
!opt_str2(matches.opt_str("adb-test-dir")).is_empty(), !opt_str2(matches.opt_str("adb-test-dir")).is_empty(),
lldb_python_dir: matches.opt_str("lldb-python-dir"), lldb_python_dir: matches.opt_str("lldb-python-dir"),
verbose: matches.opt_present("verbose"), verbose: matches.opt_present("verbose"),
quiet: matches.opt_present("quiet"),
} }
} }
@ -191,6 +193,7 @@ pub fn log_config(config: &Config) {
logv(c, format!("adb_device_status: {}", logv(c, format!("adb_device_status: {}",
config.adb_device_status)); config.adb_device_status));
logv(c, format!("verbose: {}", config.verbose)); logv(c, format!("verbose: {}", config.verbose));
logv(c, format!("quiet: {}", config.quiet));
logv(c, format!("\n")); logv(c, format!("\n"));
} }
@ -257,6 +260,7 @@ pub fn test_opts(config: &Config) -> test::TestOpts {
Some(ref filter) => Some(filter.clone()), Some(ref filter) => Some(filter.clone()),
}, },
run_ignored: config.run_ignored, run_ignored: config.run_ignored,
quiet: config.quiet,
logfile: config.logfile.clone(), logfile: config.logfile.clone(),
run_tests: true, run_tests: true,
bench_benchmarks: true, bench_benchmarks: true,

View file

@ -109,7 +109,7 @@ impl fmt::Display for TestName {
} }
} }
#[derive(Clone, Copy)] #[derive(Clone, Copy, PartialEq, Eq)]
enum NamePadding { enum NamePadding {
PadNone, PadNone,
PadOnRight, PadOnRight,
@ -301,6 +301,7 @@ pub struct TestOpts {
pub logfile: Option<PathBuf>, pub logfile: Option<PathBuf>,
pub nocapture: bool, pub nocapture: bool,
pub color: ColorConfig, pub color: ColorConfig,
pub quiet: bool,
} }
impl TestOpts { impl TestOpts {
@ -314,6 +315,7 @@ impl TestOpts {
logfile: None, logfile: None,
nocapture: false, nocapture: false,
color: AutoColor, color: AutoColor,
quiet: false,
} }
} }
} }
@ -331,6 +333,7 @@ fn optgroups() -> Vec<getopts::OptGroup> {
of stdout", "PATH"), of stdout", "PATH"),
getopts::optflag("", "nocapture", "don't capture stdout/stderr of each \ getopts::optflag("", "nocapture", "don't capture stdout/stderr of each \
task, allow printing directly"), task, allow printing directly"),
getopts::optflag("q", "quiet", "Display one character per test instead of one line"),
getopts::optopt("", "color", "Configure coloring of output: getopts::optopt("", "color", "Configure coloring of output:
auto = colorize if stdout is a tty and tests are run on serially (default); auto = colorize if stdout is a tty and tests are run on serially (default);
always = always colorize output; always = always colorize output;
@ -388,6 +391,7 @@ pub fn parse_opts(args: &[String]) -> Option<OptRes> {
}; };
let run_ignored = matches.opt_present("ignored"); let run_ignored = matches.opt_present("ignored");
let quiet = matches.opt_present("quiet");
let logfile = matches.opt_str("logfile"); let logfile = matches.opt_str("logfile");
let logfile = logfile.map(|s| PathBuf::from(&s)); let logfile = logfile.map(|s| PathBuf::from(&s));
@ -420,6 +424,7 @@ pub fn parse_opts(args: &[String]) -> Option<OptRes> {
logfile: logfile, logfile: logfile,
nocapture: nocapture, nocapture: nocapture,
color: color, color: color,
quiet: quiet,
}; };
Some(Ok(test_opts)) Some(Ok(test_opts))
@ -451,6 +456,7 @@ struct ConsoleTestState<T> {
log_out: Option<File>, log_out: Option<File>,
out: OutputLocation<T>, out: OutputLocation<T>,
use_color: bool, use_color: bool,
quiet: bool,
total: usize, total: usize,
passed: usize, passed: usize,
failed: usize, failed: usize,
@ -476,6 +482,7 @@ impl<T: Write> ConsoleTestState<T> {
out: out, out: out,
log_out: log_out, log_out: log_out,
use_color: use_color(opts), use_color: use_color(opts),
quiet: opts.quiet,
total: 0, total: 0,
passed: 0, passed: 0,
failed: 0, failed: 0,
@ -488,15 +495,15 @@ impl<T: Write> ConsoleTestState<T> {
} }
pub fn write_ok(&mut self) -> io::Result<()> { pub fn write_ok(&mut self) -> io::Result<()> {
self.write_pretty("ok", term::color::GREEN) self.write_short_result("ok", ".", term::color::GREEN)
} }
pub fn write_failed(&mut self) -> io::Result<()> { pub fn write_failed(&mut self) -> io::Result<()> {
self.write_pretty("FAILED", term::color::RED) self.write_short_result("FAILED", "F", term::color::RED)
} }
pub fn write_ignored(&mut self) -> io::Result<()> { pub fn write_ignored(&mut self) -> io::Result<()> {
self.write_pretty("ignored", term::color::YELLOW) self.write_short_result("ignored", "i", term::color::YELLOW)
} }
pub fn write_metric(&mut self) -> io::Result<()> { pub fn write_metric(&mut self) -> io::Result<()> {
@ -507,6 +514,16 @@ impl<T: Write> ConsoleTestState<T> {
self.write_pretty("bench", term::color::CYAN) self.write_pretty("bench", term::color::CYAN)
} }
pub fn write_short_result(&mut self, verbose: &str, quiet: &str, color: term::color::Color)
-> io::Result<()> {
if self.quiet {
self.write_pretty(quiet, color)
} else {
try!(self.write_pretty(verbose, color));
self.write_plain("\n")
}
}
pub fn write_pretty(&mut self, word: &str, color: term::color::Color) -> io::Result<()> { pub fn write_pretty(&mut self, word: &str, color: term::color::Color) -> io::Result<()> {
match self.out { match self.out {
Pretty(ref mut term) => { Pretty(ref mut term) => {
@ -550,28 +567,28 @@ impl<T: Write> ConsoleTestState<T> {
} }
pub fn write_test_start(&mut self, test: &TestDesc, align: NamePadding) -> io::Result<()> { pub fn write_test_start(&mut self, test: &TestDesc, align: NamePadding) -> io::Result<()> {
let name = test.padded_name(self.max_name_len, align); if self.quiet && align != PadOnRight {
self.write_plain(&format!("test {} ... ", name)) Ok(())
} else {
let name = test.padded_name(self.max_name_len, align);
self.write_plain(&format!("test {} ... ", name))
}
} }
pub fn write_result(&mut self, result: &TestResult) -> io::Result<()> { pub fn write_result(&mut self, result: &TestResult) -> io::Result<()> {
try!(match *result { match *result {
TrOk => self.write_ok(), TrOk => self.write_ok(),
TrFailed => self.write_failed(), TrFailed => self.write_failed(),
TrIgnored => self.write_ignored(), TrIgnored => self.write_ignored(),
TrMetrics(ref mm) => { TrMetrics(ref mm) => {
try!(self.write_metric()); try!(self.write_metric());
self.write_plain(&format!(": {}", mm.fmt_metrics())) self.write_plain(&format!(": {}\n", mm.fmt_metrics()))
} }
TrBench(ref bs) => { TrBench(ref bs) => {
try!(self.write_bench()); try!(self.write_bench());
self.write_plain(&format!(": {}\n", fmt_bench_samples(bs)))
try!(self.write_plain(&format!(": {}", fmt_bench_samples(bs))));
Ok(())
} }
}); }
self.write_plain("\n")
} }
pub fn write_log(&mut self, test: &TestDesc, result: &TestResult) -> io::Result<()> { pub fn write_log(&mut self, test: &TestDesc, result: &TestResult) -> io::Result<()> {
@ -629,9 +646,9 @@ impl<T: Write> ConsoleTestState<T> {
try!(self.write_plain("\ntest result: ")); try!(self.write_plain("\ntest result: "));
if success { if success {
// There's no parallelism at this point so it's safe to use color // There's no parallelism at this point so it's safe to use color
try!(self.write_ok()); try!(self.write_pretty("ok", term::color::GREEN));
} else { } else {
try!(self.write_failed()); try!(self.write_pretty("FAILED", term::color::RED));
} }
let s = format!(". {} passed; {} failed; {} ignored; {} measured\n\n", let s = format!(". {} passed; {} failed; {} ignored; {} measured\n\n",
self.passed, self.passed,
@ -758,6 +775,7 @@ fn should_sort_failures_before_printing_them() {
log_out: None, log_out: None,
out: Raw(Vec::new()), out: Raw(Vec::new()),
use_color: false, use_color: false,
quiet: false,
total: 0, total: 0,
passed: 0, passed: 0,
failed: 0, failed: 0,