diff --git a/src/lib.rs b/src/lib.rs index 8aac39d..3016046 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -71,7 +71,7 @@ #![forbid(unsafe_code)] -use std::{process, sync::mpsc, fmt, time::Instant}; +use std::{process, sync::mpsc, fmt, time::Instant, borrow::Cow}; mod args; mod printer; @@ -240,6 +240,16 @@ struct TestInfo { is_bench: bool, } +impl TestInfo { + fn test_name_with_kind(&self) -> Cow<'_, str> { + if self.kind.is_empty() { + Cow::Borrowed(&self.name) + } else { + Cow::Owned(format!("[{}] {}", self.kind, self.name)) + } + } +} + /// Output of a benchmark. #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub struct Measurement { @@ -364,13 +374,23 @@ impl Arguments { } fn is_filtered_out(&self, test: &Trial) -> bool { - let test_name = &test.info.name; + let test_name = test.name(); + // Match against the full test name, including the kind. This upholds the invariant that if + // --list prints out: + // + // : test + // + // then "--exact " runs exactly that test. + let test_name_with_kind = test.info.test_name_with_kind(); // If a filter was specified, apply this if let Some(filter) = &self.filter { match self.exact { - true if test_name != filter => return true, - false if !test_name.contains(filter) => return true, + // For exact matches, we want to match against either the test name (to maintain + // backwards compatibility with older versions of libtest-mimic), or the test kind + // (technically more correct with respect to matching against the output of --list.) + true if test_name != filter && &test_name_with_kind != filter => return true, + false if !test_name_with_kind.contains(filter) => return true, _ => {} }; } @@ -378,8 +398,13 @@ impl Arguments { // If any skip pattern were specified, test for all patterns. for skip_filter in &self.skip { match self.exact { - true if test_name == skip_filter => return true, - false if test_name.contains(skip_filter) => return true, + // For exact matches, we want to match against either the test name (to maintain + // backwards compatibility with older versions of libtest-mimic), or the test kind + // (technically more correct with respect to matching against the output of --list.) + true if test_name == skip_filter || &test_name_with_kind == skip_filter => { + return true + } + false if test_name_with_kind.contains(skip_filter) => return true, _ => {} } } diff --git a/tests/mixed_bag.rs b/tests/mixed_bag.rs index a6fe52f..c27557a 100644 --- a/tests/mixed_bag.rs +++ b/tests/mixed_bag.rs @@ -227,11 +227,16 @@ fn list_ignored() { #[test] fn list_with_filter() { let (c, out) = common::do_run(args(["--list", "a"]), tests()); + // Matches all tests that contain "a" in either the name or the kind. assert_log!(out, " cat: test + [apple] fox: test + [apple] bunny: test + [banana] fly: test [banana] bear: test cyan: bench [banana] orange: bench + [banana] pink: bench "); assert_eq!(c, Conclusion { num_filtered_out: 0, @@ -242,6 +247,71 @@ fn list_with_filter() { }); } +#[test] +fn list_with_filter_exact() { + // --exact matches the test name either with or without the kind. + let (c, out) = common::do_run(args(["--list", "--exact", "[apple] fox"]), tests()); + assert_log!(out, " + [apple] fox: test + "); + assert_eq!(c, Conclusion { + num_filtered_out: 0, + num_passed: 0, + num_failed: 0, + num_ignored: 0, + num_measured: 0, + }); + let (c, out) = common::do_run(args(["--list", "--exact", "fly"]), tests()); + assert_log!(out, " + [banana] fly: test + "); + assert_eq!(c, Conclusion { + num_filtered_out: 0, + num_passed: 0, + num_failed: 0, + num_ignored: 0, + num_measured: 0, + }); + + // --skip --exact can be used to exclude tests. + let (c, out) = common::do_run( + args([ + "--list", + "--exact", + "--skip", + "[apple] fox", + "--skip", + "fly", + ]), + tests(), + ); + assert_log!(out, " + cat: test + dog: test + [apple] bunny: test + frog: test + owl: test + [banana] bear: test + red: bench + blue: bench + [kiwi] yellow: bench + [kiwi] green: bench + purple: bench + cyan: bench + [banana] orange: bench + [banana] pink: bench + "); + assert_eq!(c, Conclusion { + num_filtered_out: 0, + num_passed: 0, + num_failed: 0, + num_ignored: 0, + num_measured: 0, + }); + + // --skip --exact matches test names without the kind as well. +} + #[test] fn filter_c() { check(args(["c"]), tests, 2,