@@ -42,7 +42,7 @@ use nextest_runner::{
4242 show_config:: { ShowNextestVersion , ShowTestGroupSettings , ShowTestGroups , ShowTestGroupsMode } ,
4343 signal:: SignalHandlerKind ,
4444 target_runner:: { PlatformRunner , TargetRunner } ,
45- test_filter:: { FilterBound , RunIgnored , TestFilterBuilder } ,
45+ test_filter:: { FilterBound , RunIgnored , TestFilterBuilder , TestFilterPatterns } ,
4646 write_str:: WriteStr ,
4747 RustcCli ,
4848} ;
@@ -590,11 +590,17 @@ struct TestBuildFilter {
590590 #[ arg( long) ]
591591 ignore_default_filter : bool ,
592592
593- /// Test name filters
593+ /// Test name filters.
594594 #[ arg( help_heading = None , name = "FILTERS" ) ]
595595 pre_double_dash_filters : Vec < String > ,
596596
597- /// Test name filters and emulated test binary arguments (partially supported)
597+ /// Test name filters and emulated test binary arguments.
598+ ///
599+ /// Arguments supported:{n}
600+ /// - --ignored: Only run ignored tests{n}
601+ /// - --include-ignored: Run both ignored and non-ignored tests{n}
602+ /// - --skip PATTERN: Skip tests that match the pattern{n}
603+ /// - --exact PATTERN: Only run tests that exactly match the pattern
598604 #[ arg( help_heading = None , value_name = "FILTERS_AND_ARGS" , last = true ) ]
599605 filters : Vec < String > ,
600606}
@@ -648,53 +654,59 @@ impl TestBuildFilter {
648654 fn make_test_filter_builder ( & self , filter_exprs : Vec < Filterset > ) -> Result < TestFilterBuilder > {
649655 // Merge the test binary args into the patterns.
650656 let mut run_ignored = self . run_ignored . map ( Into :: into) ;
651- let mut patterns = self . pre_double_dash_filters . clone ( ) ;
657+ let mut patterns = TestFilterPatterns :: new ( self . pre_double_dash_filters . clone ( ) ) ;
652658 self . merge_test_binary_args ( & mut run_ignored, & mut patterns) ?;
653659
654660 Ok ( TestFilterBuilder :: new (
655661 run_ignored. unwrap_or_default ( ) ,
656662 self . partition . clone ( ) ,
657- & patterns,
663+ patterns,
658664 filter_exprs,
659665 ) ?)
660666 }
661667
662668 fn merge_test_binary_args (
663669 & self ,
664670 run_ignored : & mut Option < RunIgnored > ,
665- patterns : & mut Vec < String > ,
671+ patterns : & mut TestFilterPatterns ,
666672 ) -> Result < ( ) > {
667673 let mut ignore_filters = Vec :: new ( ) ;
668674 let mut read_trailing_filters = false ;
669675
670- let mut skip_exact = Vec :: new ( ) ;
671676 let mut unsupported_args = Vec :: new ( ) ;
672677
673- patterns. extend (
674- self . filters
675- . iter ( )
676- . filter ( |& s| {
677- if read_trailing_filters || !s. starts_with ( '-' ) {
678- true
679- } else if s == "--include-ignored" {
680- ignore_filters. push ( ( s. clone ( ) , RunIgnored :: All ) ) ;
681- false
682- } else if s == "--ignored" {
683- ignore_filters. push ( ( s. clone ( ) , RunIgnored :: Only ) ) ;
684- false
685- } else if s == "--" {
686- read_trailing_filters = true ;
687- false
688- } else if s == "--skip" || s == "--exact" {
689- skip_exact. push ( s. clone ( ) ) ;
690- false
691- } else {
692- unsupported_args. push ( s. clone ( ) ) ;
693- true
694- }
695- } )
696- . cloned ( ) ,
697- ) ;
678+ let mut it = self . filters . iter ( ) ;
679+ while let Some ( arg) = it. next ( ) {
680+ if read_trailing_filters || !arg. starts_with ( '-' ) {
681+ patterns. add_substring_pattern ( arg. clone ( ) ) ;
682+ } else if arg == "--include-ignored" {
683+ ignore_filters. push ( ( arg. clone ( ) , RunIgnored :: All ) ) ;
684+ } else if arg == "--ignored" {
685+ ignore_filters. push ( ( arg. clone ( ) , RunIgnored :: Only ) ) ;
686+ } else if arg == "--" {
687+ read_trailing_filters = true ;
688+ } else if arg == "--skip" {
689+ let skip_arg = it. next ( ) . ok_or_else ( || {
690+ ExpectedError :: test_binary_args_parse_error (
691+ "missing required argument" ,
692+ vec ! [ arg. clone( ) ] ,
693+ )
694+ } ) ?;
695+
696+ patterns. add_skip_pattern ( skip_arg. clone ( ) ) ;
697+ } else if arg == "--exact" {
698+ let exact_arg = it. next ( ) . ok_or_else ( || {
699+ ExpectedError :: test_binary_args_parse_error (
700+ "missing required argument" ,
701+ vec ! [ arg. clone( ) ] ,
702+ )
703+ } ) ?;
704+
705+ patterns. add_exact_pattern ( exact_arg. clone ( ) ) ;
706+ } else {
707+ unsupported_args. push ( arg. clone ( ) ) ;
708+ }
709+ }
698710
699711 for ( s, f) in ignore_filters {
700712 if let Some ( run_ignored) = run_ignored {
@@ -714,19 +726,13 @@ impl TestBuildFilter {
714726 }
715727 }
716728
717- if !skip_exact. is_empty ( ) {
718- return Err ( ExpectedError :: test_binary_args_parse_error (
719- "unsupported\n (hint: use a filterset instead: <https://nexte.st/docs/filtersets>)" ,
720- skip_exact,
721- ) ) ;
722- }
723-
724729 if !unsupported_args. is_empty ( ) {
725730 return Err ( ExpectedError :: test_binary_args_parse_error (
726731 "unsupported" ,
727732 unsupported_args,
728733 ) ) ;
729734 }
735+
730736 Ok ( ( ) )
731737 }
732738}
@@ -2594,6 +2600,22 @@ mod tests {
25942600 ) ,
25952601 ( "foo -- -- str1 str2 --" , "foo str1 str2 -- -- --" ) ,
25962602 ] ;
2603+ let skip_exact = & [
2604+ // ---
2605+ // skip and exact
2606+ // ---
2607+ (
2608+ "foo -- --skip my-pattern --skip your-pattern --exact exact1 pattern2" ,
2609+ {
2610+ let mut patterns = TestFilterPatterns :: default ( ) ;
2611+ patterns. add_skip_pattern ( "my-pattern" . to_owned ( ) ) ;
2612+ patterns. add_skip_pattern ( "your-pattern" . to_owned ( ) ) ;
2613+ patterns. add_exact_pattern ( "exact1" . to_owned ( ) ) ;
2614+ patterns. add_substring_pattern ( "pattern2" . to_owned ( ) ) ;
2615+ patterns
2616+ } ,
2617+ ) ,
2618+ ] ;
25972619 let invalid = & [
25982620 // ---
25992621 // duplicated
@@ -2606,17 +2628,14 @@ mod tests {
26062628 ( "foo -- --ignored --include-ignored" , "mutually exclusive" ) ,
26072629 ( "foo --run-ignored all -- --ignored" , "mutually exclusive" ) ,
26082630 // ---
2631+ // missing required argument
2632+ // ---
2633+ ( "foo -- --skip" , "missing required argument" ) ,
2634+ ( "foo -- --exact" , "missing required argument" ) ,
2635+ // ---
26092636 // unsupported
26102637 // ---
26112638 ( "foo -- --bar" , "unsupported" ) ,
2612- (
2613- "foo -- --exact" ,
2614- "unsupported\n (hint: use a filterset instead: <https://nexte.st/docs/filtersets>)" ,
2615- ) ,
2616- (
2617- "foo -- --skip" ,
2618- "unsupported\n (hint: use a filterset instead: <https://nexte.st/docs/filtersets>)" ,
2619- ) ,
26202639 ] ;
26212640
26222641 for ( a, b) in valid {
@@ -2631,6 +2650,17 @@ mod tests {
26312650 assert_eq ! ( a_str, b_str) ;
26322651 }
26332652
2653+ for ( args, patterns) in skip_exact {
2654+ let builder =
2655+ get_test_filter_builder ( args) . unwrap_or_else ( |_| panic ! ( "failed to parse {args}" ) ) ;
2656+
2657+ let builder2 =
2658+ TestFilterBuilder :: new ( RunIgnored :: Default , None , patterns. clone ( ) , Vec :: new ( ) )
2659+ . unwrap_or_else ( |_| panic ! ( "failed to build TestFilterBuilder" ) ) ;
2660+
2661+ assert_eq ! ( builder, builder2, "{args} matches expected" ) ;
2662+ }
2663+
26342664 for ( s, r) in invalid {
26352665 let res = get_test_filter_builder ( s) ;
26362666 if let Err ( ExpectedError :: TestBinaryArgsParseError { reason, .. } ) = & res {
0 commit comments