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

[Feature]: Investigate & Increase Test Coverage #426

Open
5 of 15 tasks
0xNeshi opened this issue Nov 29, 2024 · 1 comment
Open
5 of 15 tasks

[Feature]: Investigate & Increase Test Coverage #426

0xNeshi opened this issue Nov 29, 2024 · 1 comment
Labels
effort: high Large or difficult task. priority: 3 We will resolve this first before everything else. tracking Umbrella issue that tracks some work. type: ref A code update that doesn't meaningfully change functionality. type: test Changes to the testing suite.

Comments

@0xNeshi
Copy link
Collaborator

0xNeshi commented Nov 29, 2024

What is the feature you would like to see?

  • Find out why our test coverage suddenly fell from ~80% to ~65%
  • Add additional tests to increase this % as close to 95% as possible

Problems and Recommendations on Increasing Coverage %

NOTE: for more details on each point, see #426 (comment). The below checklist is taken and updated from there.

  • Solidity code used in sol! macros (events, errors, storage) is included in test coverage. feat: improve code coverage #438
  • Missing unit tests:
    • functions that interact with other contracts.
    • ./lib/motsu/, ./lib/motsu-proc/, ./lib/e2e/, and ./lib/e2e-proc/. feat: improve code coverage #438
    • re-exported functions.
    • certain flows, and even whole functions in certain contracts and in contracts/src/utils.
  • Using internal functions instead of public ones (e.g. IErc20::transfer is tested by calling _update, causing code coverage to register transfer as "unconvered").
  • IErc165-related tests exist verifying the generated INTERFACE_ID value is correct, but no tests exist that call <ContractName>::supports_interface.
  • MethodError impls uncovered.
  • #[public] attr is included in coverage. feat: improve code coverage #438
  • #[cfg(test)] mod tests (unit tests) are included in coverage.
    • #[motsu::test] attributes included in test coverage.

Contribution Guidelines

  • I agree to follow this project's Contribution Guidelines
@0xNeshi 0xNeshi added priority: 3 We will resolve this first before everything else. type: feature New feature request. type: test Changes to the testing suite. effort: high Large or difficult task. labels Nov 29, 2024
@0xNeshi 0xNeshi self-assigned this Nov 29, 2024
@0xNeshi
Copy link
Collaborator Author

0xNeshi commented Dec 9, 2024

Pasting the findings here for future reference.

Reason for Coverage % Nosedive

Codecov shows that the % drop happened somewhere between October 28th and November 4th. Further investigation shows that the "problematic" commit was introduced by PR #379 (the commit is not actually "problematic", read further).

Below is the link to all the files for which coverage was affected in this commit:
https://app.codecov.io/github/OpenZeppelin/rust-contracts-stylus/commit/9c2b1b4b23145acddafb7b888e9e69a09fa6134c/indirect-changes

Explaining the coverage file diff on Codecov in case it helps (link above): the image below shows the coverage change for contracts/src/token/erc20/extensions/capped.rs - it shows that previously this motsu test was included in the coverage report (the highlighted left column shows line numbers included in previous coverage, while the non-highlighted right column shows line numbers now excluded from coverage).

image

In short, it seems that up until this commit, all motsu tests were included in the coverage %! This wrongly increased our coverage %. After this commit, the motsu tests were excluded from coverage. That means that the sudden 12% drop in coverage was not an anomaly, but a correction.

The commit did not manually change anything to affect coverage in this way. The reason why tests were magically excluded is not yet absolutely clear, but it seems most likely that this motsu::test implementation change, which no longer made the fn block wrapped by with_context, made llvm-cov (our coverage tool) aware that this is in fact test code, and that it shouldn't be a part of the coverage report.
There were also some changes to the llvm-cov dependencies in this period, which could've affected the coverage step in our CI, but this is much less likely imo.

Problems and Recommendations on Increasing Coverage %

Below is a list of problems affecting our test coverage and possible mitigation steps:

  1. Solidity code used in sol! macros (events, errors, storage) is included in test coverage (effect: high).
    • Mitigation 1: group Solidity code in an internal module annotated with #[cfg_attr(coverage, coverage(off))] (see example, and pseudo code is below).
    #[cfg_attr(coverage, coverage(off))]
    mod sol_defs {
        sol! {
            event SomeEvent();
            // ...
        }
    
        sol! {
            error SomeError();
            // ...
        }
    
        // NOTE: has to be included, as `SolidityError` affects coverage,
        // so has to be ignored
        #[derive(SolidityError, Debug)]
        pub enum Error {
            // ...
        }
    
        sol_storage! {
            pub struct State {
                // ...
            }
        }
    }
    
    // use in the contract and also reexport
    pub use sol_defs::{State, Error, SomeError, SomeEvent};
    The effect of this single change on VestingWallet is a ~6% increased coverage.
    • Mitigation 2: we kindly ask the alloy and stylus teams to update their macros to figure out a way to apply attributes to the generated code, and once they do, we annotate each of the problematic macros with coverage(off).
    • NOTE: I did just recommend we increase our code coverage by... ignoring code. The irony is not lost on me :kek:
  2. Missing unit tests for functions that interact with other contracts (effect: high).
  3. Missing tests for ./lib/motsu/, ./lib/motsu-proc/, ./lib/e2e/, and ./lib/e2e-proc/ (effect: high).
    • NOTE: only ./lib/e2e/ is not included in the coverage report, and the reason is that it is not included in Cargo.toml > default-members and we do not include it explicitly in our coverage command. This should be addressed.
    • Mitigation 1: add missing tests.
    • Mitigation 2: exclude ./lib/ from coverage.
  4. Re-exported functions missing unit tests (effect: medium/high).
    • Mitigation 1: duplicate missing unit tests.
    • Mitigation 2: annotate relevant functions with #[cfg_attr(coverage, coverage(off))].
  5. Missing unit tests for certain flows, and even whole functions in certain contracts and in contracts/src/utils (effect: medium).
    • Mitigation: add missing unit tests.
  6. Using internal functions instead of public ones (e.g. IErc20::transfer is tested by calling _update, causing code coverage to register transfer as "unconvered") (effect: medium).
    • Mitigation: test publicly exposed fns, not the internal ones.
  7. IErc165-related tests exist verifying the generated INTERFACE_ID value is correct, but no tests exist that call <ContractName>::supports_interface (effect: low).
    • Mitigation: add missing supports_interface tests.
  8. MethodError impls uncovered (effect: low).
    • Mitigation: annotate with #[cfg_attr(coverage, coverage(off))].
  9. #[public] attr is included in coverage (effect: low). - this PR solves this
  10. #[cfg(test)] mod tests (unit tests) are included in coverage (effect: none). NOTE: technically not a problem atm, as the effect of this is positive or neutral. If we still wanted to exclude them, see mitigation steps below.
  11. #[motsu::test] attributes included in test coverage (effect: unknown). - this PR solves this
    • Explanation: nothing from mod tests should be included in coverage (see previous point). However, since ./lib/motsu/, and ./lib/motsu-proc/ do not have their own tests (already covered in previous points), we are inadvertently covering those in this roundabout way. I think this is a bug though, and not a feature.
    • Mitigation: see previous point about ignoring mod tests.
    • NOTE: it seems switching llvm-cov to nightly in this PR removed this from coverage (e.g. see nonces.rs) 👀 But for some reason, motsu-proc crate code is still "covered".

Took the liberty to investigate why the number of ignored integration tests jumped 2->10, namely in Erc721 and Erc1155 contracts. The reason for this is that e2e does not support asserting that a call reverted with stylus_sdk::call::Error, which these tests are trying to assert.
This issue is already known and is being tracked here: #228

qalisander added a commit that referenced this issue Dec 12, 2024
Disable code coverage for `sol!` and `sol_interface!` macros.
Enforce `#[storage]` macro instead of `sol_storage!`. (`#[storage]`
struct is recognized by codecov)
Add missing tests to code coverage.

Towards #426

---------

Co-authored-by: Daniel Bigos <[email protected]>
@0xNeshi 0xNeshi removed their assignment Dec 16, 2024
@0xNeshi 0xNeshi added tracking Umbrella issue that tracks some work. type: ref A code update that doesn't meaningfully change functionality. and removed type: feature New feature request. labels Dec 16, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
effort: high Large or difficult task. priority: 3 We will resolve this first before everything else. tracking Umbrella issue that tracks some work. type: ref A code update that doesn't meaningfully change functionality. type: test Changes to the testing suite.
Projects
Status: Todo
Development

No branches or pull requests

1 participant