Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

bug(coverage): missing hits when two contracts from different files have the same name #5342

Closed
2 tasks done
spockP opened this issue Jul 9, 2023 · 2 comments
Closed
2 tasks done
Labels
T-bug Type: bug

Comments

@spockP
Copy link
Contributor

spockP commented Jul 9, 2023

Component

Forge

Have you ensured that all of these are up to date?

  • Foundry
  • Foundryup

What version of Foundry are you on?

commit 8c48932

What command(s) is the bug in?

coverage

Operating System

macOS (Intel)

Describe the bug

Issue

This is a bug that I encountered when I was tracking the test coverage of a rather complicated solidity project.
However, here is a simple project to replicate the same bug:

There are two simple libraries: LibA and LibB:

  • LibA from file LibA.sol
  • LibB from file LibB.sol
// file LibA.sol 

// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.13;


library LibA {
    
    function getLibValue() external view returns(uint256 v){

        v++;

    }
}
// file:  LibB.sol 
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.13;


library LibB {
    
    function getLibValue() external view returns(uint256 v){

        v++;
    }
}

And there are two contracts with the same name (UseLib) but defined in different files:

  • UseLib defined in file UseLib0.sol depends on LibA
  • UseLib defined in file UseLib1.sol depends on LibB
// UseLib0.sol 
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.13;

import "./LibA.sol";


contract UseLib {

    mapping (uint => uint) numbers;
    
    function getValue() external view returns(uint256){

        // Note: The code of the two "UseLib" contracts must be different
        // If the difference score between them is too low,
        // the hits of the two contracts may be accidently merged into one: 
        // https://github.com/foundry-rs/foundry/blob/8c4893233c7d54de3787227577cd0e3a4faa8945/common/src/contracts.rs#L25

        uint seed = LibA.getLibValue();
        
        uint sum = 0;
        // do more stuffs to make the code more distinctive from the other  
        for(uint i=0; i < seed; ++i){
            sum += numbers[i];
        }

        return sum;
    }
}
// UseLib1.sol 
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.13;

import "./LibB.sol";


contract UseLib {


    uint256 a; 

    function getValue() external view returns(uint256){
        uint b = LibB.getLibValue() + a;
        return b;
    }
}

And the test script is as follows:

// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.13;

import "forge-std/Test.sol";
import {UseLib as UseLibFrom0} from "../src/UseLib0.sol";
import {UseLib as UseLibFrom1} from "../src/UseLib1.sol";


contract TestA is Test {

   UseLibFrom0 sut0;
   UseLibFrom1 sut1;
   
   function setUp() external{
        sut0 = new UseLibFrom0();
        sut1 = new UseLibFrom1();
   }

    function test_GetA() external {
        uint256 result = sut0.getValue();
        assertEq(result, 0);

        result = sut1.getValue();
        assertEq(result, 1);
    }
}

Okay, Let's see the summary & debug coverage report:


| File            | % Lines       | % Statements  | % Branches    | % Funcs       |
|-----------------|---------------|---------------|---------------|---------------|
| src/LibA.sol    | 100.00% (1/1) | 100.00% (1/1) | 100.00% (0/0) | 100.00% (1/1) |
| src/LibB.sol    | 100.00% (1/1) | 100.00% (1/1) | 100.00% (0/0) | 100.00% (1/1) |
| src/UseLib0.sol | 0.00% (0/5)   | 0.00% (0/8)   | 100.00% (0/0) | 0.00% (0/1)   |
| src/UseLib1.sol | 100.00% (2/2) | 100.00% (3/3) | 100.00% (0/0) | 100.00% (1/1) |
| Total           | 44.44% (4/9)  | 38.46% (5/13) | 100.00% (0/0) | 75.00% (3/4)  |

Uncovered for src/LibA.sol:

Uncovered for src/LibB.sol:

Uncovered for src/UseLib0.sol:
- Function "getValue" (location: source ID 19, line 11, chars 152-457, hits: 0)
- Line (location: source ID 19, line 12, chars 212-242, hits: 0)
- Statement (location: source ID 19, line 12, chars 212-242, hits: 0)
- Statement (location: source ID 19, line 12, chars 224-242, hits: 0)
- Line (location: source ID 19, line 14, chars 261-273, hits: 0)
- Statement (location: source ID 19, line 14, chars 261-273, hits: 0)
- Line (location: source ID 19, line 16, chars 364-372, hits: 0)
- Statement (location: source ID 19, line 16, chars 364-372, hits: 0)
- Statement (location: source ID 19, line 16, chars 374-382, hits: 0)
- Statement (location: source ID 19, line 16, chars 384-387, hits: 0)
- Line (location: source ID 19, line 17, chars 402-419, hits: 0)
- Statement (location: source ID 19, line 17, chars 402-419, hits: 0)
- Line (location: source ID 19, line 20, chars 440-450, hits: 0)
- Statement (location: source ID 19, line 20, chars 440-450, hits: 0)

Uncovered for src/UseLib1.sol:

Anchors for Contract "LibA" (solc 0.8.20+commit.a1b79de6.Darwin.appleclang, source ID 17):
- IC 58 -> Item 23
  - Refers to item: Function "getLibValue" (location: source ID 17, line 7, chars 90-167, hits: 1)
- IC 91 -> Item 24
  - Refers to item: Line (location: source ID 17, line 9, chars 156-159, hits: 1)
- IC 91 -> Item 25
  - Refers to item: Statement (location: source ID 17, line 9, chars 156-159, hits: 1)

Anchors for Contract "LibB" (solc 0.8.20+commit.a1b79de6.Darwin.appleclang, source ID 18):
- IC 58 -> Item 20
  - Refers to item: Function "getLibValue" (location: source ID 18, line 7, chars 90-166, hits: 1)
- IC 91 -> Item 21
  - Refers to item: Line (location: source ID 18, line 9, chars 156-159, hits: 1)
- IC 91 -> Item 22
  - Refers to item: Statement (location: source ID 18, line 9, chars 156-159, hits: 1)

Anchors for Contract "UseLib" (solc 0.8.20+commit.a1b79de6.Darwin.appleclang, source ID 20):
- IC 48 -> Item 14
  - Refers to item: Function "getValue" (location: source ID 20, line 12, chars 129-245, hits: 1)
- IC 81 -> Item 15
  - Refers to item: Line (location: source ID 20, line 13, chars 189-220, hits: 1)
- IC 81 -> Item 16
  - Refers to item: Statement (location: source ID 20, line 13, chars 189-220, hits: 1)
- IC 82 -> Item 17
  - Refers to item: Statement (location: source ID 20, line 13, chars 198-220, hits: 1)
- IC 206 -> Item 18
  - Refers to item: Line (location: source ID 20, line 14, chars 230-238, hits: 1)
- IC 206 -> Item 19
  - Refers to item: Statement (location: source ID 20, line 14, chars 230-238, hits: 1)

Anchors for Contract "UseLib" (solc 0.8.20+commit.a1b79de6.Darwin.appleclang, source ID 19):
- IC 48 -> Item 0
  - Refers to item: Function "getValue" (location: source ID 19, line 11, chars 152-457, hits: 0)
- IC 81 -> Item 1
  - Refers to item: Line (location: source ID 19, line 12, chars 212-242, hits: 0)
- IC 81 -> Item 2
  - Refers to item: Statement (location: source ID 19, line 12, chars 212-242, hits: 0)
- IC 82 -> Item 3
  - Refers to item: Statement (location: source ID 19, line 12, chars 224-242, hits: 0)
- IC 193 -> Item 4
  - Refers to item: Line (location: source ID 19, line 14, chars 261-273, hits: 0)
- IC 193 -> Item 5
  - Refers to item: Statement (location: source ID 19, line 14, chars 261-273, hits: 0)
- IC 195 -> Item 6
  - Refers to item: Line (location: source ID 19, line 16, chars 364-372, hits: 0)
- IC 195 -> Item 7
  - Refers to item: Statement (location: source ID 19, line 16, chars 364-372, hits: 0)
- IC 197 -> Item 8
  - Refers to item: Statement (location: source ID 19, line 16, chars 374-382, hits: 0)
- IC 237 -> Item 9
  - Refers to item: Statement (location: source ID 19, line 16, chars 384-387, hits: 0)
- IC 205 -> Item 10
  - Refers to item: Line (location: source ID 19, line 17, chars 402-419, hits: 0)
- IC 205 -> Item 11
  - Refers to item: Statement (location: source ID 19, line 17, chars 402-419, hits: 0)
- IC 255 -> Item 12
  - Refers to item: Line (location: source ID 19, line 20, chars 440-450, hits: 0)
- IC 255 -> Item 13
  - Refers to item: Statement (location: source ID 19, line 20, chars 440-450, hits: 0)



Note that hits of the UseLib contract from UseLib0.sol are missing.

And let's do some magics. If we change the name of the UseLib contract in UseLib0.sol to UseLibRenamed, the resulting coverage report correctly includes all the hits:


| File            | % Lines       | % Statements    | % Branches    | % Funcs       |
|-----------------|---------------|-----------------|---------------|---------------|
| src/LibA.sol    | 100.00% (1/1) | 100.00% (1/1)   | 100.00% (0/0) | 100.00% (1/1) |
| src/LibB.sol    | 100.00% (1/1) | 100.00% (1/1)   | 100.00% (0/0) | 100.00% (1/1) |
| src/UseLib0.sol | 100.00% (5/5) | 100.00% (8/8)   | 100.00% (0/0) | 100.00% (1/1) |
| src/UseLib1.sol | 100.00% (2/2) | 100.00% (3/3)   | 100.00% (0/0) | 100.00% (1/1) |
| Total           | 100.00% (9/9) | 100.00% (13/13) | 100.00% (0/0) | 100.00% (4/4) |


Uncovered for src/LibA.sol:

Uncovered for src/LibB.sol:

Uncovered for src/UseLib0.sol:

Uncovered for src/UseLib1.sol:

Anchors for Contract "UseLib" (solc 0.8.20+commit.a1b79de6.Darwin.appleclang, source ID 20):
- IC 48 -> Item 20
  - Refers to item: Function "getValue" (location: source ID 20, line 12, chars 129-245, hits: 1)
- IC 81 -> Item 21
  - Refers to item: Line (location: source ID 20, line 13, chars 189-220, hits: 1)
- IC 81 -> Item 22
  - Refers to item: Statement (location: source ID 20, line 13, chars 189-220, hits: 1)
- IC 82 -> Item 23
  - Refers to item: Statement (location: source ID 20, line 13, chars 198-220, hits: 1)
- IC 206 -> Item 24
  - Refers to item: Line (location: source ID 20, line 14, chars 230-238, hits: 1)
- IC 206 -> Item 25
  - Refers to item: Statement (location: source ID 20, line 14, chars 230-238, hits: 1)

Anchors for Contract "UseLibRenamed" (solc 0.8.20+commit.a1b79de6.Darwin.appleclang, source ID 19):
- IC 48 -> Item 0
  - Refers to item: Function "getValue" (location: source ID 19, line 11, chars 159-799, hits: 1)
- IC 81 -> Item 1
  - Refers to item: Line (location: source ID 19, line 18, chars 554-584, hits: 1)
- IC 81 -> Item 2
  - Refers to item: Statement (location: source ID 19, line 18, chars 554-584, hits: 1)
- IC 82 -> Item 3
  - Refers to item: Statement (location: source ID 19, line 18, chars 566-584, hits: 1)
- IC 193 -> Item 4
  - Refers to item: Line (location: source ID 19, line 20, chars 603-615, hits: 1)
- IC 193 -> Item 5
  - Refers to item: Statement (location: source ID 19, line 20, chars 603-615, hits: 1)
- IC 195 -> Item 6
  - Refers to item: Line (location: source ID 19, line 22, chars 706-714, hits: 1)
- IC 195 -> Item 7
  - Refers to item: Statement (location: source ID 19, line 22, chars 706-714, hits: 1)
- IC 197 -> Item 8
  - Refers to item: Statement (location: source ID 19, line 22, chars 716-724, hits: 2)
- IC 237 -> Item 9
  - Refers to item: Statement (location: source ID 19, line 22, chars 726-729, hits: 1)
- IC 205 -> Item 10
  - Refers to item: Line (location: source ID 19, line 23, chars 744-761, hits: 1)
- IC 205 -> Item 11
  - Refers to item: Statement (location: source ID 19, line 23, chars 744-761, hits: 1)
- IC 255 -> Item 12
  - Refers to item: Line (location: source ID 19, line 26, chars 782-792, hits: 1)
- IC 255 -> Item 13
  - Refers to item: Statement (location: source ID 19, line 26, chars 782-792, hits: 1)

Anchors for Contract "LibA" (solc 0.8.20+commit.a1b79de6.Darwin.appleclang, source ID 17):
- IC 58 -> Item 17
  - Refers to item: Function "getLibValue" (location: source ID 17, line 7, chars 90-167, hits: 1)
- IC 91 -> Item 18
  - Refers to item: Line (location: source ID 17, line 9, chars 156-159, hits: 1)
- IC 91 -> Item 19
  - Refers to item: Statement (location: source ID 17, line 9, chars 156-159, hits: 1)

Anchors for Contract "LibB" (solc 0.8.20+commit.a1b79de6.Darwin.appleclang, source ID 18):
- IC 58 -> Item 14
  - Refers to item: Function "getLibValue" (location: source ID 18, line 7, chars 90-166, hits: 1)
- IC 91 -> Item 15
  - Refers to item: Line (location: source ID 18, line 9, chars 156-159, hits: 1)
- IC 91 -> Item 16
  - Refers to item: Statement (location: source ID 18, line 9, chars 156-159, hits: 1)


Possible Cause ?

Two contracts with the same from different files will have the same slug.

let key = id.slug();

@spockP spockP added the T-bug Type: bug label Jul 9, 2023
@spockP
Copy link
Contributor Author

spockP commented Jul 9, 2023

Just edited codes in the above description. If the difference between my two UseLib contracts is too small, the matcher will fail to distinguish between them (? possibly another issue? )

@grandizzy
Copy link
Collaborator

confirmed fixed with #8214

image

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
T-bug Type: bug
Projects
Status: Completed
Development

No branches or pull requests

2 participants