@@ -39,12 +39,15 @@ use foundry_config::{
39
39
filter:: GlobMatcher ,
40
40
} ;
41
41
use foundry_debugger:: Debugger ;
42
- use foundry_evm:: traces:: { backtrace:: BacktraceBuilder , identifier:: TraceIdentifiers } ;
42
+ use foundry_evm:: {
43
+ opts:: EvmOpts ,
44
+ traces:: { backtrace:: BacktraceBuilder , identifier:: TraceIdentifiers } ,
45
+ } ;
43
46
use regex:: Regex ;
44
47
use std:: {
45
48
collections:: { BTreeMap , BTreeSet } ,
46
49
fmt:: Write ,
47
- path:: PathBuf ,
50
+ path:: { Path , PathBuf } ,
48
51
sync:: { Arc , mpsc:: channel} ,
49
52
time:: { Duration , Instant } ,
50
53
} ;
@@ -199,9 +202,9 @@ pub struct TestArgs {
199
202
}
200
203
201
204
impl TestArgs {
202
- pub async fn run ( self ) -> Result < TestOutcome > {
205
+ pub async fn run ( mut self ) -> Result < TestOutcome > {
203
206
trace ! ( target: "forge::test" , "executing test command" ) ;
204
- self . execute_tests ( ) . await
207
+ self . compile_and_run ( ) . await
205
208
}
206
209
207
210
/// Returns a list of files that need to be compiled in order to run all the tests that match
@@ -250,18 +253,9 @@ impl TestArgs {
250
253
/// configured filter will be executed
251
254
///
252
255
/// Returns the test results for all matching tests.
253
- pub async fn execute_tests ( mut self ) -> Result < TestOutcome > {
256
+ pub async fn compile_and_run ( & mut self ) -> Result < TestOutcome > {
254
257
// Merge all configs.
255
- let ( mut config, mut evm_opts) = self . load_config_and_evm_opts ( ) ?;
256
-
257
- // Explicitly enable isolation for gas reports for more correct gas accounting.
258
- if self . gas_report {
259
- evm_opts. isolate = true ;
260
- } else {
261
- // Do not collect gas report traces if gas report is not enabled.
262
- config. fuzz . gas_report_samples = 0 ;
263
- config. invariant . gas_report_samples = 0 ;
264
- }
258
+ let ( mut config, evm_opts) = self . load_config_and_evm_opts ( ) ?;
265
259
266
260
// Install missing dependencies.
267
261
if install:: install_missing_dependencies ( & mut config) && config. auto_detect_remappings {
@@ -281,9 +275,31 @@ impl TestArgs {
281
275
. files ( self . get_sources_to_compile ( & config, & filter) ?) ;
282
276
let output = compiler. compile ( & project) ?;
283
277
284
- // Create test options from general project settings and compiler output.
285
- let project_root = & project . paths . root ;
278
+ self . run_tests ( & project. paths . root , config , evm_opts , & output, & filter , false ) . await
279
+ }
286
280
281
+ /// Executes all the tests in the project.
282
+ ///
283
+ /// See [`Self::compile_and_run`] for more details.
284
+ pub async fn run_tests (
285
+ & mut self ,
286
+ project_root : & Path ,
287
+ mut config : Config ,
288
+ mut evm_opts : EvmOpts ,
289
+ output : & ProjectCompileOutput ,
290
+ filter : & ProjectPathsAwareFilter ,
291
+ coverage : bool ,
292
+ ) -> Result < TestOutcome > {
293
+ // Explicitly enable isolation for gas reports for more correct gas accounting.
294
+ if self . gas_report {
295
+ evm_opts. isolate = true ;
296
+ } else {
297
+ // Do not collect gas report traces if gas report is not enabled.
298
+ config. fuzz . gas_report_samples = 0 ;
299
+ config. invariant . gas_report_samples = 0 ;
300
+ }
301
+
302
+ // Create test options from general project settings and compiler output.
287
303
let should_debug = self . debug ;
288
304
let should_draw = self . flamegraph || self . flamechart ;
289
305
@@ -321,10 +337,11 @@ impl TestArgs {
321
337
. enable_isolation ( evm_opts. isolate )
322
338
. networks ( evm_opts. networks )
323
339
. fail_fast ( self . fail_fast )
324
- . build :: < MultiCompiler > ( project_root, & output, env, evm_opts) ?;
340
+ . set_coverage ( coverage)
341
+ . build :: < MultiCompiler > ( project_root, output, env, evm_opts) ?;
325
342
326
343
let libraries = runner. libraries . clone ( ) ;
327
- let mut outcome = self . run_tests ( runner, config, verbosity, & filter, & output) . await ?;
344
+ let mut outcome = self . run_tests_inner ( runner, config, verbosity, filter, output) . await ?;
328
345
329
346
if should_draw {
330
347
let ( suite_name, test_name, mut test_result) =
@@ -373,7 +390,7 @@ impl TestArgs {
373
390
outcome. remove_first ( ) . ok_or_eyre ( "no tests were executed" ) ?;
374
391
375
392
let sources =
376
- ContractSources :: from_project_output ( & output, project . root ( ) , Some ( & libraries) ) ?;
393
+ ContractSources :: from_project_output ( output, project_root , Some ( & libraries) ) ?;
377
394
378
395
// Run the debugger.
379
396
let mut builder = Debugger :: builder ( )
@@ -388,8 +405,8 @@ impl TestArgs {
388
405
}
389
406
390
407
let mut debugger = builder. build ( ) ;
391
- if let Some ( dump_path) = self . dump {
392
- debugger. dump_to_file ( & dump_path) ?;
408
+ if let Some ( dump_path) = & self . dump {
409
+ debugger. dump_to_file ( dump_path) ?;
393
410
} else {
394
411
debugger. try_run_tui ( ) ?;
395
412
}
@@ -399,7 +416,7 @@ impl TestArgs {
399
416
}
400
417
401
418
/// Run all tests that matches the filter predicate from a test runner
402
- pub async fn run_tests (
419
+ async fn run_tests_inner (
403
420
& self ,
404
421
mut runner : MultiContractRunner ,
405
422
config : Arc < Config > ,
@@ -440,7 +457,7 @@ impl TestArgs {
440
457
}
441
458
sh_warn ! ( "{msg}" ) ?;
442
459
}
443
- return Ok ( TestOutcome :: empty ( false ) ) ;
460
+ return Ok ( TestOutcome :: empty ( Some ( runner ) , false ) ) ;
444
461
}
445
462
446
463
if num_filtered != 1 && ( self . debug || self . flamegraph || self . flamechart ) {
@@ -482,13 +499,13 @@ impl TestArgs {
482
499
}
483
500
} ) ;
484
501
sh_println ! ( "{}" , serde_json:: to_string( & results) ?) ?;
485
- return Ok ( TestOutcome :: new ( results, self . allow_failure ) ) ;
502
+ return Ok ( TestOutcome :: new ( Some ( runner ) , results, self . allow_failure ) ) ;
486
503
}
487
504
488
505
if self . junit {
489
506
let results = runner. test_collect ( filter) ?;
490
507
sh_println ! ( "{}" , junit_xml_report( & results, verbosity) . to_string( ) ?) ?;
491
- return Ok ( TestOutcome :: new ( results, self . allow_failure ) ) ;
508
+ return Ok ( TestOutcome :: new ( Some ( runner ) , results, self . allow_failure ) ) ;
492
509
}
493
510
494
511
let remote_chain_id = runner. evm_opts . get_remote_chain_id ( ) . await ;
@@ -502,7 +519,7 @@ impl TestArgs {
502
519
let show_progress = config. show_progress ;
503
520
let handle = tokio:: task:: spawn_blocking ( {
504
521
let filter = filter. clone ( ) ;
505
- move || runner. test ( & filter, tx, show_progress)
522
+ move || runner. test ( & filter, tx, show_progress) . map ( | ( ) | runner )
506
523
} ) ;
507
524
508
525
// Set up trace identifiers.
@@ -542,7 +559,7 @@ impl TestArgs {
542
559
543
560
let mut gas_snapshots = BTreeMap :: < String , BTreeMap < String , String > > :: new ( ) ;
544
561
545
- let mut outcome = TestOutcome :: empty ( self . allow_failure ) ;
562
+ let mut outcome = TestOutcome :: empty ( None , self . allow_failure ) ;
546
563
547
564
let mut any_test_failed = false ;
548
565
let mut backtrace_builder = None ;
@@ -823,11 +840,12 @@ impl TestArgs {
823
840
}
824
841
825
842
// Reattach the task.
826
- if let Err ( e) = handle. await {
827
- match e. try_into_panic ( ) {
843
+ match handle. await {
844
+ Ok ( result) => outcome. runner = Some ( result?) ,
845
+ Err ( e) => match e. try_into_panic ( ) {
828
846
Ok ( payload) => std:: panic:: resume_unwind ( payload) ,
829
847
Err ( e) => return Err ( e. into ( ) ) ,
830
- }
848
+ } ,
831
849
}
832
850
833
851
// Persist test run failures to enable replaying.
@@ -919,7 +937,7 @@ fn list(runner: MultiContractRunner, filter: &ProjectPathsAwareFilter) -> Result
919
937
}
920
938
}
921
939
}
922
- Ok ( TestOutcome :: empty ( false ) )
940
+ Ok ( TestOutcome :: empty ( Some ( runner ) , false ) )
923
941
}
924
942
925
943
/// Load persisted filter (with last test run failures) from file.
0 commit comments