1

I have the following CMakeLists.txt file:


cmake_minimum_required(VERSION 3.16)
project(first_coverage)

set(CXX_STANDARD 20)
set(CXX_STANDARD_REQUIRED True)
set(CMAKE_BUILD_TYPE Debug)
set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
set(CMAKE_CXX_OUTPUT_EXTENSION_REPLACE ON)

include (FetchContent)

enable_testing()

set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} --coverage -O0 -fprofile-arcs -fprofile-abs-path -ftest-coverage -fno-inline -fno-inline-small-functions -fno-default-inline")

file(GLOB_RECURSE sources "src/**.cpp")

file(GLOB_RECURSE test_cases "test/**.cpp")

message(flags: ${CMAKE_CXX_FLAGS})

add_library(first_coverage_deps INTERFACE)
target_link_libraries(first_coverage_deps INTERFACE
    ${CONAN_LIBS}
)

target_compile_options(first_coverage_deps INTERFACE
    -Werror=return-type
    -Werror=unused
    -Werror=pessimizing-move
    -Werror=redundant-move
)

target_include_directories(first_coverage_deps
    INTERFACE src
    INTERFACE external
)

add_library(first_coverage
    ${sources}
)

set(FETCHCONTENT_BASE_DIR "${CMAKE_SOURCE_DIR}/external/")

FetchContent_Declare(
    googletest
    URL https://github.com/google/googletest/archive/609281088cfefc76f9d0ce82e1ff6c30cc3591e5.zip
)

FetchContent_MakeAvailable(googletest)

add_executable(first_coverage_test
    ${test_cases}
)

target_link_libraries(first_coverage first_coverage_deps)
target_link_libraries(first_coverage_test first_coverage gtest_main)

include(GoogleTest)
gtest_discover_tests(first_coverage_test)

and a src folder with a header and a source file: QuickMaths.hpp:

#include <cstdint>

using size_t = std::size_t;

size_t
multiply(size_t a, size_t b);

inline size_t
add(size_t a, size_t b)
{
  return a + b;
}

class QuickMaths
{
public:
  size_t operator*() const;
  friend QuickMaths operator+(QuickMaths const&, QuickMaths const&);

  QuickMaths(size_t x);

private:
  size_t x;
};

and

#include "QuickMaths.hpp"

size_t
multiply(size_t a, size_t b)
{
  return a * b;
}

size_t
QuickMaths::operator*() const
{
  return x;
}

QuickMaths::QuickMaths(size_t x)
  : x(x)
{}

QuickMaths
operator+(QuickMaths const& a, QuickMaths const& b)
{
  return a.x + b.x;
}

I have a test folder with a QuickMaths.cpp file:

#include <gtest/gtest.h>

#include <QuickMaths.hpp>

TEST(AddTest, shouldAdd)
{
  EXPECT_EQ(add(1UL, 1UL), 2UL);
}

TEST(MultiplyTest, shouldMultiply)
{
  EXPECT_EQ(multiply(2UL, 4UL), 8UL);
}

TEST(QuickMathTest, haveValue)
{
  auto v = QuickMaths{ 4UL };
  EXPECT_EQ(*v, 4UL);
}

Steps I use to build the project, run test, generate coverage are as following:

mkdir external && mkdir build && cd build

cmake ../

make && make test

gcovr -r ../ .

It successfully creates coverage output, however the coverage only shows executed lines for the external/gtest as well as the file in test, but shows 0 lines executed for the files that I really want to test, which are the header and the source-file in the src directory.

The output of make test is as follows:

Running tests...
Test project /home/pete/dev/sandbox/coverage_sbs/first_coverage/build
    Start 1: AddTest.shouldAdd
1/3 Test #1: AddTest.shouldAdd ................   Passed    0.01 sec
    Start 2: MultiplyTest.shouldMultiply
2/3 Test #2: MultiplyTest.shouldMultiply ......   Passed    0.00 sec
    Start 3: QuickMathTest.haveValue
3/3 Test #3: QuickMathTest.haveValue ..........   Passed    0.00 sec

100% tests passed, 0 tests failed out of 3

Total Test time (real) =   0.03 sec

And here's the output of gcovr -r ../ .

------------------------------------------------------------------------------
                           GCC Code Coverage Report
Directory: ../
------------------------------------------------------------------------------
File                                       Lines    Exec  Cover   Missing
------------------------------------------------------------------------------
external/googletest-src/googletest/include/gtest/gtest-printers.h
                                              20       0     0%   212,215,306,312,333-334,413,415,440-441,665,674,833-834,902,906,942-945
external/googletest-src/googletest/include/gtest/gtest.h
                                              17       0     0%   324,333-334,337,427,435,440-441,522,1522,1529,1541,1545-1546,1549,1561,1564
external/googletest-src/googletest/include/gtest/internal/gtest-internal.h
                                              19       1     5%   454,461,493-494,506,508,521,525,527,529,532,534,542,546,548,550,553,555
external/googletest-src/googletest/include/gtest/internal/gtest-port.h
                                               1       0     0%   970
src/QuickMaths.cpp                             8       0     0%   4,6,10,12,15-16,20,22
src/QuickMaths.hpp                             2       0     0%   9,11
test/QuickMaths.cpp                            7       3    42%   7,12,17-18
------------------------------------------------------------------------------
TOTAL                                         74       4     5%
------------------------------------------------------------------------------

How do I get the coverage to be correctly recognized for these files?

  • 2
    The coverage results indicate that the test cases were not executed (this is easier to see with gcovr's HTML output format). Thus, no code in your source files could be covered. The three covered lines probably relate to test registration during static initialization. Have your confirmed that the tests run successfully with `make test`? – amon Mar 22 '22 at 23:29
  • @amon I added the output of `make test` which looks very much like the tests did execute to me. – LeonTheProfessional Mar 23 '22 at 05:56
  • 1
    See [related thread](https://stackoverflow.com/questions/71582876/gcov-coverage-limited-to-test-files-in-minimal-g-project) for my attempt without cmake, with g++ directly. – LeonTheProfessional Mar 23 '22 at 06:50

1 Answers1

1

In my case this turned out to be a version-mismatch between gcc and gcov (See comment under answer to related-thread )

If the default gcov does not match the compiler you used, you must tell gcovr. You can do this either via a command line flag gcovr --gcov-executable gcov-11 -r ../ or via an environment variable GCOV=gcov-11 gcovr -r ../

  • 1
    That was tricky to debug but glad it got all sorted out! – amon Mar 23 '22 at 20:58
  • @amon Thanks for all the help! Sorry that I didn't mention the versions of gcc and gcov earlier, but had I known beforehand that those would be important I wouldn't have had to ask ;) – LeonTheProfessional Mar 23 '22 at 21:13