Skip to content

Commit 4ab3e29

Browse files
committed
[cargo-nextest] also fix --skip with --exact
If both `--skip` and `--exact` are passed in at the same time, then `--skip` also matches filters exactly.
1 parent 75c7b07 commit 4ab3e29

File tree

3 files changed

+109
-19
lines changed

3 files changed

+109
-19
lines changed

cargo-nextest/src/dispatch.rs

Lines changed: 23 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -715,7 +715,11 @@ impl TestBuildFilter {
715715
)
716716
})?;
717717

718-
patterns.add_skip_pattern(skip_arg.clone());
718+
if is_exact {
719+
patterns.add_skip_exact_pattern(skip_arg.clone());
720+
} else {
721+
patterns.add_skip_pattern(skip_arg.clone());
722+
}
719723
} else if arg == "--exact" {
720724
// Already handled above.
721725
} else {
@@ -2616,15 +2620,31 @@ mod tests {
26162620
("foo -- -- str1 str2 --", "foo str1 str2 -- -- --"),
26172621
];
26182622
let skip_exact = &[
2623+
// ---
2624+
// skip
2625+
// ---
2626+
("foo -- --skip my-pattern --skip your-pattern", {
2627+
let mut patterns = TestFilterPatterns::default();
2628+
patterns.add_skip_pattern("my-pattern".to_owned());
2629+
patterns.add_skip_pattern("your-pattern".to_owned());
2630+
patterns
2631+
}),
2632+
("foo -- pattern1 --skip my-pattern --skip your-pattern", {
2633+
let mut patterns = TestFilterPatterns::default();
2634+
patterns.add_substring_pattern("pattern1".to_owned());
2635+
patterns.add_skip_pattern("my-pattern".to_owned());
2636+
patterns.add_skip_pattern("your-pattern".to_owned());
2637+
patterns
2638+
}),
26192639
// ---
26202640
// skip and exact
26212641
// ---
26222642
(
26232643
"foo -- --skip my-pattern --skip your-pattern exact1 --exact pattern2",
26242644
{
26252645
let mut patterns = TestFilterPatterns::default();
2626-
patterns.add_skip_pattern("my-pattern".to_owned());
2627-
patterns.add_skip_pattern("your-pattern".to_owned());
2646+
patterns.add_skip_exact_pattern("my-pattern".to_owned());
2647+
patterns.add_skip_exact_pattern("your-pattern".to_owned());
26282648
patterns.add_exact_pattern("exact1".to_owned());
26292649
patterns.add_exact_pattern("pattern2".to_owned());
26302650
patterns

integration-tests/tests/integration/main.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -510,9 +510,9 @@ fn test_run() {
510510
"--exact",
511511
"tests::test_multiply_two_cdylib",
512512
"--skip",
513-
"cdylib",
513+
"tests::test_multiply_two_cdylib",
514514
])
515-
// This should only select the two test_multiply_two tests, which pass. So don't pass in
515+
// This should only select the one test_multiply_two test, which pass. So don't pass in
516516
// unchecked(true) here.
517517
.output();
518518
check_run_output(
@@ -529,7 +529,7 @@ fn test_run() {
529529
"--workspace",
530530
"--all-targets",
531531
"-E",
532-
"(test(=test_multiply_two) | test(=tests::test_multiply_two_cdylib)) & not test(cdylib)",
532+
"(test(=test_multiply_two) | test(=tests::test_multiply_two_cdylib)) & not test(=tests::test_multiply_two_cdylib)",
533533
])
534534
// This should only select the test_multiply_two test, which passes. So don't pass in
535535
// unchecked(true) here.
@@ -576,7 +576,7 @@ fn test_run() {
576576
"--exact",
577577
"tests::test_multiply_two_cdylib",
578578
])
579-
// This should only select the two test_multiply_two tests, which pass. So don't pass in
579+
// This should only select the test_multiply_two test, which passes. So don't pass in
580580
// unchecked(true) here.
581581
.output();
582582
check_run_output(

nextest-runner/src/test_filter.rs

Lines changed: 82 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -63,14 +63,17 @@ enum TestFilterExprs {
6363
Sets(Vec<Filterset>),
6464
}
6565

66-
/// A set of patterns for test filters.
66+
/// A set of string-based patterns for test filters.
6767
#[derive(Clone, Debug, Eq, PartialEq)]
6868
pub enum TestFilterPatterns {
6969
/// The only patterns specified (if any) are skip patterns: match the default set of tests minus
7070
/// the skip patterns.
7171
SkipOnly {
7272
/// Skip patterns.
7373
skip_patterns: Vec<String>,
74+
75+
/// Skip patterns to match exactly.
76+
skip_exact_patterns: HashSet<String>,
7477
},
7578

7679
/// At least one substring or exact pattern is specified.
@@ -83,18 +86,22 @@ pub enum TestFilterPatterns {
8386
/// Substring patterns.
8487
patterns: Vec<String>,
8588

86-
/// Patterns passed in via `--exact`.
89+
/// Patterns to match exactly.
8790
exact_patterns: HashSet<String>,
8891

8992
/// Patterns passed in via `--skip`.
9093
skip_patterns: Vec<String>,
94+
95+
/// Skip patterns to match exactly.
96+
skip_exact_patterns: HashSet<String>,
9197
},
9298
}
9399

94100
impl Default for TestFilterPatterns {
95101
fn default() -> Self {
96102
Self::SkipOnly {
97103
skip_patterns: Vec::new(),
104+
skip_exact_patterns: HashSet::new(),
98105
}
99106
}
100107
}
@@ -112,18 +119,23 @@ impl TestFilterPatterns {
112119
patterns: substring_patterns,
113120
exact_patterns: HashSet::new(),
114121
skip_patterns: Vec::new(),
122+
skip_exact_patterns: HashSet::new(),
115123
}
116124
}
117125
}
118126

119127
/// Adds a regular pattern to the set of patterns.
120128
pub fn add_substring_pattern(&mut self, pattern: String) {
121129
match self {
122-
Self::SkipOnly { skip_patterns } => {
130+
Self::SkipOnly {
131+
skip_patterns,
132+
skip_exact_patterns,
133+
} => {
123134
*self = Self::Patterns {
124135
patterns: vec![pattern],
125136
exact_patterns: HashSet::new(),
126137
skip_patterns: mem::take(skip_patterns),
138+
skip_exact_patterns: mem::take(skip_exact_patterns),
127139
};
128140
}
129141
Self::Patterns { patterns, .. } => {
@@ -135,11 +147,15 @@ impl TestFilterPatterns {
135147
/// Adds an exact pattern to the set of patterns.
136148
pub fn add_exact_pattern(&mut self, pattern: String) {
137149
match self {
138-
Self::SkipOnly { skip_patterns } => {
150+
Self::SkipOnly {
151+
skip_patterns,
152+
skip_exact_patterns,
153+
} => {
139154
*self = Self::Patterns {
140155
patterns: Vec::new(),
141156
exact_patterns: [pattern].into_iter().collect(),
142157
skip_patterns: mem::take(skip_patterns),
158+
skip_exact_patterns: mem::take(skip_exact_patterns),
143159
};
144160
}
145161
Self::Patterns { exact_patterns, .. } => {
@@ -151,7 +167,7 @@ impl TestFilterPatterns {
151167
/// Adds a skip pattern to the set of patterns.
152168
pub fn add_skip_pattern(&mut self, pattern: String) {
153169
match self {
154-
Self::SkipOnly { skip_patterns } => {
170+
Self::SkipOnly { skip_patterns, .. } => {
155171
skip_patterns.push(pattern);
156172
}
157173
Self::Patterns { skip_patterns, .. } => {
@@ -160,9 +176,30 @@ impl TestFilterPatterns {
160176
}
161177
}
162178

179+
/// Adds a skip pattern to match exactly.
180+
pub fn add_skip_exact_pattern(&mut self, pattern: String) {
181+
match self {
182+
Self::SkipOnly {
183+
skip_exact_patterns,
184+
..
185+
} => {
186+
skip_exact_patterns.insert(pattern);
187+
}
188+
Self::Patterns {
189+
skip_exact_patterns,
190+
..
191+
} => {
192+
skip_exact_patterns.insert(pattern);
193+
}
194+
}
195+
}
196+
163197
fn resolve(self) -> Result<ResolvedFilterPatterns, TestFilterBuilderError> {
164198
match self {
165-
Self::SkipOnly { mut skip_patterns } => {
199+
Self::SkipOnly {
200+
mut skip_patterns,
201+
skip_exact_patterns,
202+
} => {
166203
if skip_patterns.is_empty() {
167204
Ok(ResolvedFilterPatterns::All)
168205
} else {
@@ -172,13 +209,15 @@ impl TestFilterPatterns {
172209
Ok(ResolvedFilterPatterns::SkipOnly {
173210
skip_patterns,
174211
skip_pattern_matcher,
212+
skip_exact_patterns,
175213
})
176214
}
177215
}
178216
Self::Patterns {
179217
mut patterns,
180218
exact_patterns,
181219
mut skip_patterns,
220+
skip_exact_patterns,
182221
} => {
183222
// sort_unstable allows the PartialEq implementation to work correctly.
184223
patterns.sort_unstable();
@@ -191,6 +230,7 @@ impl TestFilterPatterns {
191230
patterns,
192231
exact_patterns,
193232
skip_patterns,
233+
skip_exact_patterns,
194234
pattern_matcher,
195235
skip_pattern_matcher,
196236
})
@@ -211,13 +251,15 @@ enum ResolvedFilterPatterns {
211251
SkipOnly {
212252
skip_patterns: Vec<String>,
213253
skip_pattern_matcher: Box<AhoCorasick>,
254+
skip_exact_patterns: HashSet<String>,
214255
},
215256

216257
/// Match tests that match the patterns and don't match the skip patterns.
217258
Patterns {
218259
patterns: Vec<String>,
219260
exact_patterns: HashSet<String>,
220261
skip_patterns: Vec<String>,
262+
skip_exact_patterns: HashSet<String>,
221263
pattern_matcher: Box<AhoCorasick>,
222264
skip_pattern_matcher: Box<AhoCorasick>,
223265
},
@@ -236,9 +278,12 @@ impl ResolvedFilterPatterns {
236278
Self::SkipOnly {
237279
// skip_patterns is covered by the matcher.
238280
skip_patterns: _,
281+
skip_exact_patterns,
239282
skip_pattern_matcher,
240283
} => {
241-
if skip_pattern_matcher.is_match(test_name) {
284+
if skip_exact_patterns.contains(test_name)
285+
|| skip_pattern_matcher.is_match(test_name)
286+
{
242287
FilterNameMatch::Mismatch(MismatchReason::String)
243288
} else {
244289
FilterNameMatch::MatchWithPatterns
@@ -250,11 +295,14 @@ impl ResolvedFilterPatterns {
250295
exact_patterns,
251296
// skip_patterns is covered by the matcher.
252297
skip_patterns: _,
298+
skip_exact_patterns,
253299
pattern_matcher,
254300
skip_pattern_matcher,
255301
} => {
256302
// skip overrides all other patterns.
257-
if skip_pattern_matcher.is_match(test_name) {
303+
if skip_exact_patterns.contains(test_name)
304+
|| skip_pattern_matcher.is_match(test_name)
305+
{
258306
FilterNameMatch::Mismatch(MismatchReason::String)
259307
} else if exact_patterns.contains(test_name) || pattern_matcher.is_match(test_name)
260308
{
@@ -274,19 +322,25 @@ impl PartialEq for ResolvedFilterPatterns {
274322
(
275323
Self::SkipOnly {
276324
skip_patterns,
325+
skip_exact_patterns,
277326
// The matcher is derived from `skip_patterns`, so it can be ignored.
278327
skip_pattern_matcher: _,
279328
},
280329
Self::SkipOnly {
281330
skip_patterns: other_skip_patterns,
331+
skip_exact_patterns: other_skip_exact_patterns,
282332
skip_pattern_matcher: _,
283333
},
284-
) => skip_patterns == other_skip_patterns,
334+
) => {
335+
skip_patterns == other_skip_patterns
336+
&& skip_exact_patterns == other_skip_exact_patterns
337+
}
285338
(
286339
Self::Patterns {
287340
patterns,
288341
exact_patterns,
289342
skip_patterns,
343+
skip_exact_patterns,
290344
// The matchers are derived from `patterns` and `skip_patterns`, so they can be
291345
// ignored.
292346
pattern_matcher: _,
@@ -296,13 +350,15 @@ impl PartialEq for ResolvedFilterPatterns {
296350
patterns: other_patterns,
297351
exact_patterns: other_exact_patterns,
298352
skip_patterns: other_skip_patterns,
353+
skip_exact_patterns: other_skip_exact_patterns,
299354
pattern_matcher: _,
300355
skip_pattern_matcher: _,
301356
},
302357
) => {
303358
patterns == other_patterns
304359
&& exact_patterns == other_exact_patterns
305360
&& skip_patterns == other_skip_patterns
361+
&& skip_exact_patterns == other_skip_exact_patterns
306362
}
307363
_ => false,
308364
}
@@ -739,6 +795,7 @@ mod tests {
739795
patterns.add_substring_pattern("bar".to_string());
740796
patterns.add_exact_pattern("baz".to_string());
741797
patterns.add_skip_pattern("quux".to_string());
798+
patterns.add_skip_exact_pattern("quuz".to_string());
742799

743800
let resolved = patterns.clone().resolve().unwrap();
744801

@@ -792,7 +849,13 @@ mod tests {
792849
FilterNameMatch::Mismatch(MismatchReason::String),
793850
);
794851

795-
// Skip and exact patterns -- in this case, add `baz` to the skip list.
852+
// Skip-exact patterns.
853+
assert_eq!(
854+
resolved.name_match("quuz"),
855+
FilterNameMatch::Mismatch(MismatchReason::String),
856+
);
857+
858+
// Skip overrides regular patterns -- in this case, add `baz` to the skip list.
796859
patterns.add_skip_pattern("baz".to_string());
797860
let resolved = patterns.resolve().unwrap();
798861
assert_eq!(
@@ -806,6 +869,7 @@ mod tests {
806869
let mut patterns = TestFilterPatterns::default();
807870
patterns.add_skip_pattern("foo".to_string());
808871
patterns.add_skip_pattern("bar".to_string());
872+
patterns.add_skip_exact_pattern("baz".to_string());
809873

810874
let resolved = patterns.clone().resolve().unwrap();
811875

@@ -827,15 +891,21 @@ mod tests {
827891
FilterNameMatch::Mismatch(MismatchReason::String),
828892
);
829893

830-
// Anything that doesn't match the skip filter should match.
894+
// Test exact matches.
831895
assert_eq!(
832896
resolved.name_match("baz"),
833-
FilterNameMatch::MatchWithPatterns,
897+
FilterNameMatch::Mismatch(MismatchReason::String),
834898
);
835899
assert_eq!(
836900
resolved.name_match("abazb"),
837901
FilterNameMatch::MatchWithPatterns,
838902
);
903+
904+
// Anything that doesn't match the skip filter should match.
905+
assert_eq!(
906+
resolved.name_match("quux"),
907+
FilterNameMatch::MatchWithPatterns,
908+
);
839909
}
840910

841911
#[test]

0 commit comments

Comments
 (0)