@@ -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 ) ]
6868pub 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
94100impl 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