@@ -588,3 +588,116 @@ contract AContractTest is DSTest {
588
588
589
589
"# ] ] ) ;
590
590
} ) ;
591
+
592
+ forgetest ! ( test_try_catch_coverage, |prj, cmd| {
593
+ prj. insert_ds_test( ) ;
594
+ prj. add_source(
595
+ "Foo.sol" ,
596
+ r#"
597
+ contract Foo {
598
+ address public owner;
599
+
600
+ constructor(address _owner) {
601
+ require(_owner != address(0), "invalid address");
602
+ assert(_owner != 0x0000000000000000000000000000000000000001);
603
+ owner = _owner;
604
+ }
605
+
606
+ function myFunc(uint256 x) public pure returns (string memory) {
607
+ require(x != 0, "require failed");
608
+ return "my func was called";
609
+ }
610
+ }
611
+
612
+ contract Bar {
613
+ event Log(string message);
614
+ event LogBytes(bytes data);
615
+
616
+ Foo public foo;
617
+
618
+ constructor() {
619
+ foo = new Foo(msg.sender);
620
+ }
621
+
622
+ function tryCatchExternalCall(uint256 _i) public {
623
+ try foo.myFunc(_i) returns (string memory result) {
624
+ emit Log(result);
625
+ } catch {
626
+ emit Log("external call failed");
627
+ }
628
+ }
629
+
630
+ function tryCatchNewContract(address _owner) public {
631
+ try new Foo(_owner) returns (Foo foo_) {
632
+ emit Log("Foo created");
633
+ } catch Error(string memory reason) {
634
+ emit Log(reason);
635
+ } catch (bytes memory reason) {}
636
+ }
637
+ }
638
+ "# ,
639
+ )
640
+ . unwrap( ) ;
641
+
642
+ prj. add_source(
643
+ "FooTest.sol" ,
644
+ r#"
645
+ import "./test.sol";
646
+ import {Bar, Foo} from "./Foo.sol";
647
+
648
+ interface Vm {
649
+ function expectRevert() external;
650
+ }
651
+
652
+ contract FooTest is DSTest {
653
+ Vm constant vm = Vm(HEVM_ADDRESS);
654
+
655
+ function test_happy_foo_coverage() external {
656
+ vm.expectRevert();
657
+ Foo foo = new Foo(address(0));
658
+ vm.expectRevert();
659
+ foo = new Foo(address(1));
660
+ foo = new Foo(address(2));
661
+ }
662
+
663
+ function test_happy_path_coverage() external {
664
+ Bar bar = new Bar();
665
+ bar.tryCatchNewContract(0x0000000000000000000000000000000000000002);
666
+ bar.tryCatchExternalCall(1);
667
+ }
668
+
669
+ function test_coverage() external {
670
+ Bar bar = new Bar();
671
+ bar.tryCatchNewContract(0x0000000000000000000000000000000000000000);
672
+ bar.tryCatchNewContract(0x0000000000000000000000000000000000000001);
673
+ bar.tryCatchExternalCall(0);
674
+ }
675
+ }
676
+ "# ,
677
+ )
678
+ . unwrap( ) ;
679
+
680
+ // Assert coverage not 100% for happy paths only.
681
+ cmd. arg( "coverage" ) . args( [ "--mt" . to_string( ) , "happy" . to_string( ) ] ) . assert_success( ) . stdout_eq(
682
+ str ![ [ r#"
683
+ ...
684
+ | File | % Lines | % Statements | % Branches | % Funcs |
685
+ |-------------|----------------|----------------|---------------|---------------|
686
+ | src/Foo.sol | 66.67% (10/15) | 66.67% (14/21) | 100.00% (4/4) | 100.00% (5/5) |
687
+ | Total | 66.67% (10/15) | 66.67% (14/21) | 100.00% (4/4) | 100.00% (5/5) |
688
+
689
+ "# ] ] ,
690
+ ) ;
691
+
692
+ // Assert 100% branch coverage (including clauses without body).
693
+ cmd. forge_fuse( ) . arg( "coverage" ) . args( [ "--summary" . to_string( ) ] ) . assert_success( ) . stdout_eq(
694
+ str ![ [ r#"
695
+ ...
696
+ | File | % Lines | % Statements | % Branches | % Funcs |
697
+ |-------------|-----------------|-----------------|---------------|---------------|
698
+ | src/Foo.sol | 100.00% (15/15) | 100.00% (21/21) | 100.00% (4/4) | 100.00% (5/5) |
699
+ | Total | 100.00% (15/15) | 100.00% (21/21) | 100.00% (4/4) | 100.00% (5/5) |
700
+
701
+ "# ] ] ,
702
+ ) ;
703
+ } ) ;
0 commit comments