@@ -391,3 +391,106 @@ Ran 1 test suite [ELAPSED]: 1 tests passed, 0 failed, 0 skipped (1 total tests)
391
391
392
392
"# ] ] ) ;
393
393
} ) ;
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