Search code examples
c++code-coveragegcovr

How to get correct code coverage for member functions in header files


When I run gcovr after running my unit test suite I get wrong number for coverage of header files where some inline member function definitions are placed. For example:

----------------------------------------------------------------------------  
File                                       Lines    Exec  Cover   Missing  
------------------------------------------------------------------------------   
include/analysis/dataobjects/DetailedHit.h     6       2    33%   41-43,45
include/analysis/dataobjects/Hit.h            19       0     0%   31-33,35-36,42-43,50-51,58-59,74-75,82-83,90-91,98-99

For Hit.h the reported coverage is 0%, but I'm sure that at least some code from that header is executed during the unit test run since if I place a cout in it then I see it in the console ouptut. On the web it is often suggested that it is a problem coming from the fact that the compiler inlines the member function code, so that no function call is generated and thus the coverage tools do not track the execution. So I added the flags:

-fno-inline -fno-inline-small-functions -fno-default-inline

to the invocation of the compiler (gcc 8.2.1) but I get the same coverage report. So I don't understand what's happening.

The thing that mostly puzzles me is why gcovr reports 2 covered lines in DetailedHit.h. This header is very similar to Hit.h so I'd expect the same behavior with 0% reported coverage, but this member function:

const std::vector<Herd::ParticleHit> ParticleHits() const {
  return _particleHits;
}

results to be executed 10 times. It is a simple function so it should be inlined as the ones in Hit.h, still it results to be covered. In case it matters, Hit is a concrete base class for DetailedHit, and both do not have virtual methods.

I think I'm missing some important piece of knowledge about how gcov and gcovr work, but I couldn't find a relevant clue on the web so I'd appreciate any help on this. Thanks.


Solution

  • The methods with 0% coverage were inline methods in a header.

    I did compile the library I was testing with gcc --coverage which instruments the machine code to collect coverage. However, I did not instrument the test executable since I am not interested in the coverage of the tests themselves. So the test executable contained code for the inline methods without instrumenting them.

    As a result, the methods were known to gcov but no coverage was collected (only the non-instrumented inline version was executed).

    The solution:

    • also instrument the tests by using the --coverage compiler flag
    • filter out the unwanted coverage data of the tests with the -e/--exclude gcovr option