@@ -24,7 +24,7 @@ use foundry_evm::{
24
24
invariant:: {
25
25
check_sequence, replay_error, replay_run, InvariantExecutor , InvariantFuzzError ,
26
26
} ,
27
- CallResult , EvmError , ExecutionErr , Executor , RawCallResult ,
27
+ CallResult , EvmError , ExecutionErr , Executor , ITest , RawCallResult ,
28
28
} ,
29
29
fuzz:: {
30
30
fixture_name,
@@ -36,6 +36,7 @@ use foundry_evm::{
36
36
use proptest:: test_runner:: TestRunner ;
37
37
use rayon:: prelude:: * ;
38
38
use std:: {
39
+ borrow:: Cow ,
39
40
cmp:: min,
40
41
collections:: { BTreeMap , HashMap } ,
41
42
time:: Instant ,
@@ -270,6 +271,7 @@ impl<'a> ContractRunner<'a> {
270
271
) ) ;
271
272
}
272
273
}
274
+
273
275
// There are multiple setUp function, so we return a single test result for `setUp`
274
276
if setup_fns. len ( ) > 1 {
275
277
return SuiteResult :: new (
@@ -412,21 +414,26 @@ impl<'a> ContractRunner<'a> {
412
414
413
415
/// Runs a single unit test.
414
416
///
415
- /// Calls the given functions and returns the `TestResult`.
417
+ /// Applies before test txes (if any), runs current test and returns the `TestResult`.
416
418
///
417
- /// State modifications are not committed to the evm database but discarded after the call,
418
- /// similar to `eth_call`.
419
+ /// Before test txes are applied in order and state modifications committed to the EVM database
420
+ /// (therefore the unit test call will be made on modified state).
421
+ /// State modifications of before test txes and unit test function call are discarded after
422
+ /// test ends, similar to `eth_call`.
419
423
pub fn run_unit_test (
420
424
& self ,
421
425
func : & Function ,
422
426
should_fail : bool ,
423
427
setup : TestSetup ,
424
428
) -> TestResult {
425
- let address = setup. address ;
426
- let test_result = TestResult :: new ( setup) ;
429
+ // Prepare unit test execution.
430
+ let ( executor, test_result, address) = match self . prepare_test ( func, setup) {
431
+ Ok ( res) => res,
432
+ Err ( res) => return res,
433
+ } ;
427
434
428
- // Run unit test
429
- let ( mut raw_call_result, reason) = match self . executor . call (
435
+ // Run current unit test.
436
+ let ( mut raw_call_result, reason) = match executor. call (
430
437
self . sender ,
431
438
address,
432
439
func,
@@ -437,11 +444,10 @@ impl<'a> ContractRunner<'a> {
437
444
Ok ( res) => ( res. raw , None ) ,
438
445
Err ( EvmError :: Execution ( err) ) => ( err. raw , Some ( err. reason ) ) ,
439
446
Err ( EvmError :: SkipError ) => return test_result. single_skip ( ) ,
440
- Err ( err) => return test_result. single_fail ( err) ,
447
+ Err ( err) => return test_result. single_fail ( Some ( err. to_string ( ) ) ) ,
441
448
} ;
442
449
443
- let success =
444
- self . executor . is_raw_call_mut_success ( address, & mut raw_call_result, should_fail) ;
450
+ let success = executor. is_raw_call_mut_success ( address, & mut raw_call_result, should_fail) ;
445
451
test_result. single_result ( success, reason, raw_call_result)
446
452
}
447
453
@@ -618,6 +624,15 @@ impl<'a> ContractRunner<'a> {
618
624
)
619
625
}
620
626
627
+ /// Runs a fuzzed test.
628
+ ///
629
+ /// Applies the before test txes (if any), fuzzes the current function and returns the
630
+ /// `TestResult`.
631
+ ///
632
+ /// Before test txes are applied in order and state modifications committed to the EVM database
633
+ /// (therefore the fuzz test will use the modified state).
634
+ /// State modifications of before test txes and fuzz test are discarded after test ends,
635
+ /// similar to `eth_call`.
621
636
pub fn run_fuzz_test (
622
637
& self ,
623
638
func : & Function ,
@@ -626,14 +641,18 @@ impl<'a> ContractRunner<'a> {
626
641
setup : TestSetup ,
627
642
fuzz_config : FuzzConfig ,
628
643
) -> TestResult {
629
- let address = setup. address ;
644
+ let progress = start_fuzz_progress ( self . progress , self . name , & func. name , fuzz_config. runs ) ;
645
+
646
+ // Prepare fuzz test execution.
630
647
let fuzz_fixtures = setup. fuzz_fixtures . clone ( ) ;
631
- let test_result = TestResult :: new ( setup) ;
648
+ let ( executor, test_result, address) = match self . prepare_test ( func, setup) {
649
+ Ok ( res) => res,
650
+ Err ( res) => return res,
651
+ } ;
632
652
633
- // Run fuzz test
634
- let progress = start_fuzz_progress ( self . progress , self . name , & func. name , fuzz_config. runs ) ;
653
+ // Run fuzz test.
635
654
let fuzzed_executor =
636
- FuzzedExecutor :: new ( self . executor . clone ( ) , runner, self . sender , fuzz_config) ;
655
+ FuzzedExecutor :: new ( executor. into_owned ( ) , runner, self . sender , fuzz_config) ;
637
656
let result = fuzzed_executor. fuzz (
638
657
func,
639
658
& fuzz_fixtures,
@@ -650,4 +669,51 @@ impl<'a> ContractRunner<'a> {
650
669
}
651
670
test_result. fuzz_result ( result)
652
671
}
672
+
673
+ /// Prepares single unit test and fuzz test execution:
674
+ /// - set up the test result and executor
675
+ /// - check if before test txes are configured and apply them in order
676
+ ///
677
+ /// Before test txes are arrays of arbitrary calldata obtained by calling the `beforeTest`
678
+ /// function with test selector as a parameter.
679
+ ///
680
+ /// Unit tests within same contract (or even current test) are valid options for before test tx
681
+ /// configuration. Test execution stops if any of before test txes fails.
682
+ fn prepare_test (
683
+ & self ,
684
+ func : & Function ,
685
+ setup : TestSetup ,
686
+ ) -> Result < ( Cow < ' _ , Executor > , TestResult , Address ) , TestResult > {
687
+ let address = setup. address ;
688
+ let mut executor = Cow :: Borrowed ( & self . executor ) ;
689
+ let mut test_result = TestResult :: new ( setup) ;
690
+
691
+ // Apply before test configured functions (if any).
692
+ if self . contract . abi . functions ( ) . filter ( |func| func. name . is_before_test_setup ( ) ) . count ( ) ==
693
+ 1
694
+ {
695
+ for calldata in executor
696
+ . call_sol_default (
697
+ address,
698
+ & ITest :: beforeTestSetupCall { testSelector : func. selector ( ) } ,
699
+ )
700
+ . beforeTestCalldata
701
+ {
702
+ // Apply before test configured calldata.
703
+ match executor. to_mut ( ) . transact_raw ( self . sender , address, calldata, U256 :: ZERO ) {
704
+ Ok ( call_result) => {
705
+ // Merge tx result traces in unit test result.
706
+ test_result. merge_call_result ( & call_result) ;
707
+
708
+ // To continue unit test execution the call should not revert.
709
+ if call_result. reverted {
710
+ return Err ( test_result. single_fail ( None ) )
711
+ }
712
+ }
713
+ Err ( _) => return Err ( test_result. single_fail ( None ) ) ,
714
+ }
715
+ }
716
+ }
717
+ Ok ( ( executor, test_result, address) )
718
+ }
653
719
}
0 commit comments