Skip to content

Commit 833b03a

Browse files
committed
Auto merge of #38185 - jsgf:test-list, r=alexcrichton
libtest: add --list option to list tests and benchmarks This option lists all the tests and benchmarks a binary provides without running any of them. By default the listing is sent to stdout (intended for human consumption), but if `--logfile` is also specified, it is also written there in an easily parsable form. If filters are specified, they're applied before the output is emitted. The human output will also include a summary unless `-q` is specified.
2 parents cfa668f + 516d105 commit 833b03a

File tree

2 files changed

+79
-20
lines changed

2 files changed

+79
-20
lines changed

src/libtest/lib.rs

+78-20
Original file line numberDiff line numberDiff line change
@@ -254,10 +254,16 @@ pub fn test_main(args: &[String], tests: Vec<TestDescAndFn>) {
254254
Some(Err(msg)) => panic!("{:?}", msg),
255255
None => return,
256256
};
257-
match run_tests_console(&opts, tests) {
258-
Ok(true) => {}
259-
Ok(false) => std::process::exit(101),
260-
Err(e) => panic!("io error when running tests: {:?}", e),
257+
if opts.list {
258+
if let Err(e) = list_tests_console(&opts, tests) {
259+
panic!("io error when listing tests: {:?}", e);
260+
}
261+
} else {
262+
match run_tests_console(&opts, tests) {
263+
Ok(true) => {}
264+
Ok(false) => std::process::exit(101),
265+
Err(e) => panic!("io error when running tests: {:?}", e),
266+
}
261267
}
262268
}
263269

@@ -300,6 +306,7 @@ pub enum ColorConfig {
300306
}
301307

302308
pub struct TestOpts {
309+
pub list: bool,
303310
pub filter: Option<String>,
304311
pub filter_exact: bool,
305312
pub run_ignored: bool,
@@ -317,6 +324,7 @@ impl TestOpts {
317324
#[cfg(test)]
318325
fn new() -> TestOpts {
319326
TestOpts {
327+
list: false,
320328
filter: None,
321329
filter_exact: false,
322330
run_ignored: false,
@@ -340,6 +348,7 @@ fn optgroups() -> Vec<getopts::OptGroup> {
340348
vec![getopts::optflag("", "ignored", "Run ignored tests"),
341349
getopts::optflag("", "test", "Run tests and not benchmarks"),
342350
getopts::optflag("", "bench", "Run benchmarks instead of tests"),
351+
getopts::optflag("", "list", "List all tests and benchmarks"),
343352
getopts::optflag("h", "help", "Display this message (longer with --help)"),
344353
getopts::optopt("", "logfile", "Write logs to the specified file instead \
345354
of stdout", "PATH"),
@@ -411,6 +420,7 @@ pub fn parse_opts(args: &[String]) -> Option<OptRes> {
411420
let run_ignored = matches.opt_present("ignored");
412421
let quiet = matches.opt_present("quiet");
413422
let exact = matches.opt_present("exact");
423+
let list = matches.opt_present("list");
414424

415425
let logfile = matches.opt_str("logfile");
416426
let logfile = logfile.map(|s| PathBuf::from(&s));
@@ -451,6 +461,7 @@ pub fn parse_opts(args: &[String]) -> Option<OptRes> {
451461
};
452462

453463
let test_opts = TestOpts {
464+
list: list,
454465
filter: filter,
455466
filter_exact: exact,
456467
run_ignored: run_ignored,
@@ -581,7 +592,8 @@ impl<T: Write> ConsoleTestState<T> {
581592
}
582593
}
583594

584-
pub fn write_plain(&mut self, s: &str) -> io::Result<()> {
595+
pub fn write_plain<S: AsRef<str>>(&mut self, s: S) -> io::Result<()> {
596+
let s = s.as_ref();
585597
match self.out {
586598
Pretty(ref mut term) => {
587599
term.write_all(s.as_bytes())?;
@@ -635,25 +647,28 @@ impl<T: Write> ConsoleTestState<T> {
635647
TEST_WARN_TIMEOUT_S))
636648
}
637649

638-
pub fn write_log(&mut self, test: &TestDesc, result: &TestResult) -> io::Result<()> {
650+
pub fn write_log<S: AsRef<str>>(&mut self, msg: S) -> io::Result<()> {
651+
let msg = msg.as_ref();
639652
match self.log_out {
640653
None => Ok(()),
641-
Some(ref mut o) => {
642-
let s = format!("{} {}\n",
643-
match *result {
644-
TrOk => "ok".to_owned(),
645-
TrFailed => "failed".to_owned(),
646-
TrFailedMsg(ref msg) => format!("failed: {}", msg),
647-
TrIgnored => "ignored".to_owned(),
648-
TrMetrics(ref mm) => mm.fmt_metrics(),
649-
TrBench(ref bs) => fmt_bench_samples(bs),
650-
},
651-
test.name);
652-
o.write_all(s.as_bytes())
653-
}
654+
Some(ref mut o) => o.write_all(msg.as_bytes()),
654655
}
655656
}
656657

658+
pub fn write_log_result(&mut self, test: &TestDesc, result: &TestResult) -> io::Result<()> {
659+
self.write_log(
660+
format!("{} {}\n",
661+
match *result {
662+
TrOk => "ok".to_owned(),
663+
TrFailed => "failed".to_owned(),
664+
TrFailedMsg(ref msg) => format!("failed: {}", msg),
665+
TrIgnored => "ignored".to_owned(),
666+
TrMetrics(ref mm) => mm.fmt_metrics(),
667+
TrBench(ref bs) => fmt_bench_samples(bs),
668+
},
669+
test.name))
670+
}
671+
657672
pub fn write_failures(&mut self) -> io::Result<()> {
658673
self.write_plain("\nfailures:\n")?;
659674
let mut failures = Vec::new();
@@ -746,6 +761,49 @@ pub fn fmt_bench_samples(bs: &BenchSamples) -> String {
746761
output
747762
}
748763

764+
// List the tests to console, and optionally to logfile. Filters are honored.
765+
pub fn list_tests_console(opts: &TestOpts, tests: Vec<TestDescAndFn>) -> io::Result<()> {
766+
let mut st = ConsoleTestState::new(opts, None::<io::Stdout>)?;
767+
768+
let mut ntest = 0;
769+
let mut nbench = 0;
770+
let mut nmetric = 0;
771+
772+
for test in filter_tests(&opts, tests) {
773+
use TestFn::*;
774+
775+
let TestDescAndFn { desc: TestDesc { name, .. }, testfn } = test;
776+
777+
let fntype = match testfn {
778+
StaticTestFn(..) | DynTestFn(..) => { ntest += 1; "test" },
779+
StaticBenchFn(..) | DynBenchFn(..) => { nbench += 1; "benchmark" },
780+
StaticMetricFn(..) | DynMetricFn(..) => { nmetric += 1; "metric" },
781+
};
782+
783+
st.write_plain(format!("{}: {}\n", name, fntype))?;
784+
st.write_log(format!("{} {}\n", fntype, name))?;
785+
}
786+
787+
fn plural(count: u32, s: &str) -> String {
788+
match count {
789+
1 => format!("{} {}", 1, s),
790+
n => format!("{} {}s", n, s),
791+
}
792+
}
793+
794+
if !opts.quiet {
795+
if ntest != 0 || nbench != 0 || nmetric != 0 {
796+
st.write_plain("\n")?;
797+
}
798+
st.write_plain(format!("{}, {}, {}\n",
799+
plural(ntest, "test"),
800+
plural(nbench, "benchmark"),
801+
plural(nmetric, "metric")))?;
802+
}
803+
804+
Ok(())
805+
}
806+
749807
// A simple console test runner
750808
pub fn run_tests_console(opts: &TestOpts, tests: Vec<TestDescAndFn>) -> io::Result<bool> {
751809

@@ -755,7 +813,7 @@ pub fn run_tests_console(opts: &TestOpts, tests: Vec<TestDescAndFn>) -> io::Resu
755813
TeWait(ref test, padding) => st.write_test_start(test, padding),
756814
TeTimeout(ref test) => st.write_timeout(test),
757815
TeResult(test, result, stdout) => {
758-
st.write_log(&test, &result)?;
816+
st.write_log_result(&test, &result)?;
759817
st.write_result(&result)?;
760818
match result {
761819
TrOk => st.passed += 1,

src/tools/compiletest/src/main.rs

+1
Original file line numberDiff line numberDiff line change
@@ -325,6 +325,7 @@ pub fn test_opts(config: &Config) -> test::TestOpts {
325325
color: test::AutoColor,
326326
test_threads: None,
327327
skip: vec![],
328+
list: false,
328329
}
329330
}
330331

0 commit comments

Comments
 (0)