Search code examples
jenkinsgoogletestgooglemockgcovgcovr

gcov is invoking gtest sources and unit-tests. how can I avoid this?


I am working on creating a Jenkins pipeline for unit-testing maybe with GTest. My plan is to use the following tools: GTest for Unit-Testing, gcov for generating gcda and gcno Files and gcovr for xml or Html outputs of the unit-testing results. It's working well till now with the help from the internet and particularly stack overflow.

But I am struggling with 3 issues.

  1. gcov is creating gcda and gcno files for gtest sources and my unit-tests. Because gcovr is invoking them and I see them in the HTML files. how can I avoid this? I only want my production code in the HTML files.
  2. I can only see code coverage for template classes if gcov is generating gcda and gcno files for my unit-tests. So I need a simple idea for 1) Maybe can I use an exclude flag in gcovr?
  3. Unused functions in template classes (inline functions) are not covered. Code coverage is always 100% but I tried with different flags, and nothing helped. -fprofile-abs-path --coverage -fno-inline -fno-inline-small-functions -fno-default-inline -fkeep-inline-functions

enter image description here

I added a picture to show, what I am talking about. UnitTests and GTests covering results should not appear in gcovr HTML...


Solution

  • You can filter out unwanted coverage data, but you can't create data that doesn't exist.

    1. gcov is creating gcda and gcno files for gtest sources and my unit-tests. Because gcovr is invoking them and I see them in the HTML files. how can I avoid this? I only want my production code in the HTML files.

    Use gcovr --exclude GoogleTest/ --exclude UnitTests/

    Gcovr has a per-file filtering system that allows you to specify which source code files to include/exclude. For a file to be included in the coverage report,

    • any --filter pattern must match, and
    • no --exclude pattern must match.

    Or phrased in reverse: a file is excluded if it doesn't match any --filter or if it matches any --exclude pattern.

    If you don't provide an explicit --filter, then the default filter is the --root directory, which in turn defaults to the current working directory.

    These patterns are regexes. Usually, these are used to match paths relative to the current working directory. For example, you can limit the reports to a src/ directory with gcovr --filter src/. Or you can exclude the GoogleTest/ directory with gcovr --exclude GoogleTest/.

    Gcovr also has a way to filter gcda/gcno files (search_paths and --gcov-filter), but that is mostly useful as a performance optimization.

    2. I can only see code coverage for template classes if gcov is generating gcda and gcno files for my unit-tests. So I need a simple idea for 1) Maybe can I use an exclude flag in gcovr?

    This is by design. As explained above, you can solve this via gcovr's exclude flag.

    You get a gcda/gcno file per compilation unit. Header files are included into multiple compilation units, so their coverage information is essentially split across all compilation units that include it.

    So, if you want coverage for code in header files, and you include these headers into your unit tests, then gcovr must also process the gcda/gcno files from those unit tests.

    3. Unused functions in template classes (inline functions) are not covered. Code coverage is always 100% but I tried with different flags, and nothing helped. -fprofile-abs-path --coverage -fno-inline -fno-inline-small-functions -fno-default-inline -fkeep-inline-functions

    The gcov coverage data model works on an assembly-code level. Counters are inserted by the compiler itself, but only for functions for which the compiler actually generates machine code. Thus, as far as gcov is concerned, inline functions, optimized-out code, and non-instantiated templates simply do not exist.

    This is quite annoying, but it's potentially difficult to work around.

    This can most clearly be avoided by making sure that all functions for which you want coverage data are referenced via your unit tests. It is not necessary to actually invoke that function, merely referencing it should be sufficient. For example, I'd write a function to ignore() arbitrary values despite optimizations, then:

    ignore(&some_inline_function);
    

    Possible implementation: template<class T> void ignore(T const& t) { volatile T sinkhole = t; }

    Your suggested options like -fno-inline do not work because the code for these functions isn't generated in the first place.

    With GCC and when using C++ (but not C), the -fkeep-inline-functions should work, but only for non-templated inline functions.

    If a non-templated inline function is only used within one file and isn't provided in a header to multiple files, then it should instead be declared static (in C) or in an anonymous namespace (in C++11 or later), so that -Wunused-function or -Wall notify you if it isn't referenced.

    Templates are more tricky in general. Each distinct instantiation of a template results in separate functions. Gcovr does aggregate coverage data across them, but in order for the template to appear in the coverage data it must be instantiated at least once. You will have to do this manually.