@@ -113,6 +113,15 @@ fn try_main() -> Result<()> {
113113 create_dirs ( cx) ?;
114114 archive_nextest ( cx) ?;
115115 }
116+ Subcommand :: FuzzCoverage => {
117+ let cx = & Context :: new ( args) ?;
118+ clean:: clean_partial ( cx) ?;
119+ create_dirs ( cx) ?;
120+ run_fuzz_coverage ( cx) ?;
121+ if !cx. args . cov . no_report {
122+ generate_report ( cx) ?;
123+ }
124+ }
116125 Subcommand :: None | Subcommand :: Test => {
117126 let cx = & Context :: new ( args) ?;
118127 clean:: clean_partial ( cx) ?;
@@ -439,6 +448,41 @@ fn archive_nextest(cx: &Context) -> Result<()> {
439448 Ok ( ( ) )
440449}
441450
451+ fn run_fuzz_coverage ( cx : & Context ) -> Result < ( ) > {
452+ let mut cargo = cx. cargo ( ) ;
453+
454+ set_env ( cx, & mut cargo, IsNextest ( false ) ) ?;
455+
456+ cargo. arg ( "fuzz" ) . arg ( "coverage" ) ;
457+
458+ if let Some ( target) = & cx. args . target {
459+ cargo. arg ( "--target" ) ;
460+ cargo. arg ( target) ;
461+ }
462+ if cx. args . release {
463+ cargo. arg ( "--release" ) ;
464+ }
465+
466+ cargo. arg ( "--target-dir" ) ;
467+ cargo. arg ( cx. ws . target_dir . as_str ( ) ) ;
468+
469+ for cargo_arg in & cx. args . cargo_args {
470+ cargo. arg ( cargo_arg) ;
471+ }
472+
473+ if !cx. args . rest . is_empty ( ) {
474+ cargo. args ( & cx. args . rest ) ;
475+ }
476+
477+ if term:: verbose ( ) {
478+ status ! ( "Running" , "{cargo}" ) ;
479+ }
480+ stdout_to_stderr ( cx, & mut cargo) ;
481+ cargo. run ( ) ?;
482+
483+ Ok ( ( ) )
484+ }
485+
442486fn run_nextest ( cx : & Context ) -> Result < ( ) > {
443487 let mut cargo = cx. cargo ( ) ;
444488
@@ -533,7 +577,15 @@ fn stdout_to_stderr(cx: &Context, cargo: &mut ProcessBuilder) {
533577}
534578
535579fn generate_report ( cx : & Context ) -> Result < ( ) > {
536- merge_profraw ( cx) . context ( "failed to merge profile data" ) ?;
580+ let profraw_path = match cx. args . subcommand {
581+ Subcommand :: FuzzCoverage => {
582+ let fuzz_target = cx. args . rest . iter ( ) . find ( |s| !s. starts_with ( "--" ) ) . unwrap ( ) ;
583+ let path = std:: env:: current_dir ( ) ?. join ( format ! ( "coverage/{fuzz_target}/raw" ) ) ;
584+ Utf8PathBuf :: from ( path. to_string_lossy ( ) . as_ref ( ) )
585+ }
586+ _ => cx. ws . target_dir . clone ( ) ,
587+ } ;
588+ merge_profraw ( cx, & profraw_path) . context ( "failed to merge profile data" ) ?;
537589
538590 let object_files = object_files ( cx) . context ( "failed to collect object files" ) ?;
539591 let ignore_filename_regex = ignore_filename_regex ( cx, & object_files) ?;
@@ -650,21 +702,22 @@ fn open_report(cx: &Context, path: &Utf8Path) -> Result<()> {
650702 Ok ( ( ) )
651703}
652704
653- fn merge_profraw ( cx : & Context ) -> Result < ( ) > {
705+ fn merge_profraw ( cx : & Context , profraw_path : & Utf8Path ) -> Result < ( ) > {
654706 // Convert raw profile data.
655707 let profraw_files = glob:: glob (
656- Utf8Path :: new ( & glob:: Pattern :: escape ( cx . ws . target_dir . as_str ( ) ) ) . join ( "*.profraw" ) . as_str ( ) ,
708+ Utf8Path :: new ( & glob:: Pattern :: escape ( profraw_path . as_str ( ) ) ) . join ( "*.profraw" ) . as_str ( ) ,
657709 ) ?
658710 . filter_map ( Result :: ok)
659711 . collect :: < Vec < _ > > ( ) ;
712+
660713 if profraw_files. is_empty ( ) {
661714 if cx. ws . profdata_file . exists ( ) {
662715 return Ok ( ( ) ) ;
663716 }
664717 warn ! (
665718 "not found *.profraw files in {}; this may occur if target directory is accidentally \
666719 cleared, or running report subcommand without running any tests or binaries",
667- cx . ws . target_dir
720+ profraw_path
668721 ) ;
669722 }
670723 let mut input_files = String :: new ( ) ;
0 commit comments