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

fix: various coverage fixes #2504

Merged
merged 6 commits into from
Aug 3, 2022
Merged

fix: various coverage fixes #2504

merged 6 commits into from
Aug 3, 2022

Conversation

onbjerg
Copy link
Member

@onbjerg onbjerg commented Jul 28, 2022

Now accounts for inheritance and abstract contracts, however it seems there are still some issues with internal functions and libraries. For internal functions, no instructions can be found, which is pretty weird considering Godbolt does display a range of bytecode that matches internal functions when I test on there. For libraries, my suspicion is that it is related to unlinked bytecode

Opening up a draft to get a sanity check on the way I find matching instructions, perhaps it is wrong in some cases and that is why internal functions don't work

This also relaxes the coverage analysis part a bit, so instead of panicking when we can't find anchors, items will now just show up as uncovered, and RUST_LOG=warn will show more info. I think this is ok; we fail irrecoverably and we don't end up showing things as covered if they aren't. This is possible because finding anchors and coverage items is two separate stages now

Still want to fix these before merge, but we can also merge before that if it makes more sense:

  • Functions that only return something seem to not be covered for some reason
  • Internal functions are not covered

I will also do a bit of clean up before merge (some stuff should be in other modules, some stuff is missing docs)

@onbjerg
Copy link
Member Author

onbjerg commented Jul 28, 2022

Interestingly enough internal functions and return-only functions are covered sometimes. Not entirely sure what makes or breaks it right now. See e.g. my example in #2194

Edit: Ok, it seems for internal functions, we can't find anchors if they are not called... Makes sense - if they are not called, there is no reason to emit bytecode for them

As for return-only functions, I can't really seem to reproduce them not working

@gigamesh
Copy link

Great to see this! Just tried it.

My repo has a contracts directory, but when I try forge coverage -c contracts or forge coverage -c contracts/, it still includes our tests directory. Is my command wrong or is that an issue with forge?

@onbjerg
Copy link
Member Author

onbjerg commented Jul 30, 2022

@gigamesh The -c option just specifies where the contract sources are, it does not affect where the tests are. It's a flag from forge build, so the behavior you describe is consistent across all forge commands.

Your test contracts should only be included in the output if there are contracts in there that do not have functions starting with test, though - is that the case (e.g. mocks)?

@onbjerg
Copy link
Member Author

onbjerg commented Jul 30, 2022

Should be good to review, the only unsupported contract now should be libraries that have internal functions - currently figuring out what the best way is to detect those without having to walk the entire AST. Will start work on fuzz testing support

@onbjerg onbjerg marked this pull request as ready for review July 30, 2022 23:06
let mut report = CoverageReport::default();

// Collect ASTs and sources
let mut versioned_asts: HashMap<Version, HashMap<usize, Ast>> = HashMap::new();
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

type hints required here?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes

Comment on lines 143 to 146
// Filter out dependencies
// NOTE(onbjerg): For some reason this only returns Some for non-library imports... Is
// there a better way?
if project_paths.resolve_library_import(std::path::Path::new(&path)).is_none() {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is path here absolute or relative to project dir?

I can add a util function that checks if a path is part of libs

Copy link
Member Author

@onbjerg onbjerg Aug 1, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It seems to be relative to the project dir, and after remappings are applied.

A function to check if it is a part of libs would be nice

@gakonst
Copy link
Member

gakonst commented Aug 1, 2022

Should we consider merging anyway and maybe filter out libraries from the terminal output, until we get coverage for them?

@onbjerg
Copy link
Member Author

onbjerg commented Aug 1, 2022

We could

@gakonst
Copy link
Member

gakonst commented Aug 2, 2022

@onbjerg LGTM as well. The latest ethers has the helpers requested, if you want to use them

@onbjerg onbjerg merged commit 251bad1 into master Aug 3, 2022
@onbjerg onbjerg deleted the onbjerg/coverage-fixes branch August 3, 2022 10:21
iFrostizz pushed a commit to iFrostizz/foundry that referenced this pull request Nov 9, 2022
* fix: account for inheritance in coverage

* refactor: move stuff around

* docs: add some docs

* fix: dummy link contracts using libs for analysis

* build: bump ethers

* refactor: use lib detection helper
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
T-bug Type: bug
Projects
None yet
4 participants