@@ -391,3 +391,106 @@ Ran 1 test suite [ELAPSED]: 1 tests passed, 0 failed, 0 skipped (1 total tests)
391391
392392"# ] ] ) ;
393393} ) ;
394+
395+ // Test that counterexample is not replayed if test changes.
396+ // <https://github.com/foundry-rs/foundry/issues/11927>
397+ forgetest_init ! ( test_fuzz_replay_with_changed_test, |prj, cmd| {
398+ prj. update_config( |config| config. fuzz. seed = Some ( U256 :: from( 100u32 ) ) ) ;
399+ prj. add_test(
400+ "Counter.t.sol" ,
401+ r#"
402+ import {Test} from "forge-std/Test.sol";
403+
404+ contract CounterTest is Test {
405+ function testFuzz_SetNumber(uint256 x) public pure {
406+ require(x > 200);
407+ }
408+ }
409+ "# ,
410+ ) ;
411+ // Tests should fail and record counterexample with value 2.
412+ cmd. args( [ "test" ] ) . assert_failure( ) . stdout_eq( str ![ [ r#"
413+ ...
414+ Failing tests:
415+ Encountered 1 failing test in test/Counter.t.sol:CounterTest
416+ [FAIL: EvmError: Revert; counterexample: calldata=0x5c7f60d70000000000000000000000000000000000000000000000000000000000000002 args=[2]] testFuzz_SetNumber(uint256) (runs: 19, [AVG_GAS])
417+ ...
418+
419+ "# ] ] ) ;
420+
421+ // Change test to assume counterexample 2 is discarded.
422+ prj. add_test(
423+ "Counter.t.sol" ,
424+ r#"
425+ import {Test} from "forge-std/Test.sol";
426+
427+ contract CounterTest is Test {
428+ function testFuzz_SetNumber(uint256 x) public pure {
429+ vm.assume(x != 2);
430+ }
431+ }
432+ "# ,
433+ ) ;
434+ // Test should pass when replay failure with changed assume logic.
435+ cmd. forge_fuse( ) . args( [ "test" ] ) . assert_success( ) . stdout_eq( str ![ [ r#"
436+ [COMPILING_FILES] with [SOLC_VERSION]
437+ [SOLC_VERSION] [ELAPSED]
438+ Compiler run successful!
439+
440+ Ran 1 test for test/Counter.t.sol:CounterTest
441+ [PASS] testFuzz_SetNumber(uint256) (runs: 256, [AVG_GAS])
442+ Suite result: ok. 1 passed; 0 failed; 0 skipped; [ELAPSED]
443+
444+ Ran 1 test suite [ELAPSED]: 1 tests passed, 0 failed, 0 skipped (1 total tests)
445+
446+ "# ] ] ) ;
447+
448+ // Change test signature.
449+ prj. add_test(
450+ "Counter.t.sol" ,
451+ r#"
452+ import {Test} from "forge-std/Test.sol";
453+
454+ contract CounterTest is Test {
455+ function testFuzz_SetNumber(uint8 x) public pure {
456+ }
457+ }
458+ "# ,
459+ ) ;
460+ // Test should pass when replay failure with changed function signature.
461+ cmd. forge_fuse( ) . args( [ "test" ] ) . assert_success( ) . stdout_eq( str ![ [ r#"
462+ [COMPILING_FILES] with [SOLC_VERSION]
463+ [SOLC_VERSION] [ELAPSED]
464+ Compiler run successful!
465+
466+ Ran 1 test for test/Counter.t.sol:CounterTest
467+ [PASS] testFuzz_SetNumber(uint8) (runs: 256, [AVG_GAS])
468+ Suite result: ok. 1 passed; 0 failed; 0 skipped; [ELAPSED]
469+
470+ Ran 1 test suite [ELAPSED]: 1 tests passed, 0 failed, 0 skipped (1 total tests)
471+
472+ "# ] ] ) ;
473+
474+ // Change test back to the original one that produced the counterexample.
475+ prj. add_test(
476+ "Counter.t.sol" ,
477+ r#"
478+ import {Test} from "forge-std/Test.sol";
479+
480+ contract CounterTest is Test {
481+ function testFuzz_SetNumber(uint256 x) public pure {
482+ require(x > 200);
483+ }
484+ }
485+ "# ,
486+ ) ;
487+ // Test should fail with replayed counterexample 2 (0 runs).
488+ cmd. forge_fuse( ) . args( [ "test" ] ) . assert_failure( ) . stdout_eq( str ![ [ r#"
489+ ...
490+ Failing tests:
491+ Encountered 1 failing test in test/Counter.t.sol:CounterTest
492+ [FAIL: EvmError: Revert; counterexample: calldata=0x5c7f60d70000000000000000000000000000000000000000000000000000000000000002 args=[2]] testFuzz_SetNumber(uint256) (runs: 0, [AVG_GAS])
493+ ...
494+
495+ "# ] ] ) ;
496+ } ) ;
0 commit comments