How to get coverage for tests with CMake and Catch2 - c++

I'm trying to print coverage with lcov on a C++ project that is using Catch2 for tests. I'm able to run my tests and get results. However, I'm unable to get any coverage. This is the error that is shown.
Capturing coverage data from .
Found gcov version: 9.3.0
Using intermediate gcov format
Scanning . for .gcda files ...
geninfo: WARNING: no .gcda files found in . - skipping!
Finished .info-file creation
Combining tracefiles.
Reading tracefile coverage.base
lcov: ERROR: no valid records found in tracefile coverage.base
My current toolchain is WSL. I'm using Conan for dependency management. The solution has the following structure:
my project/
├─ build/
│ ├─ build files
├─ core/
│ ├─ library files
├─ main/
│ ├─ main runtime
├─ tests/
│ ├─ test runtime/
├─ CMakeLists.txt
Each folder has it's CMakeLists.txt file and is identified as a target. I'm also using this CMake Module to register a target for coverage.
My root CMakeLists.txt looks like this:
cmake_minimum_required(VERSION 3.16)
project(my-project)
set(CMAKE_CXX_STANDARD 14)
set(CMAKE_CXX_FLAGS "-O0")
include(build/conanbuildinfo.cmake)
conan_basic_setup()
add_subdirectory(core)
option(BUILD_TESTING "Builds only the test executable." OFF)
option(CODE_COVERAGE "Collect coverage from test library" OFF)
if(BUILD_TESTING)
enable_testing()
add_subdirectory(tests)
add_test(NAME project-tests COMMAND ./bin/tests)
if(CODE_COVERAGE)
include(CodeCoverage.cmake)
append_coverage_compiler_flags()
setup_target_for_coverage_lcov(NAME coverage EXECUTABLE ./bin/tests BASE_DIRECTORY ../coverage)
endif()
else()
add_subdirectory(main)
endif()
To get my coverage, I'm using the following commands (on build/).
cmake .. -DCODE_COVERAGE=ON -DBUILD_TESTING=ON -DCMAKE_BUILD_TYPE=Debug
make
make coverage
From what I understand, it seems to be missing some files necessary for coverage information, but I don't know how to make them. From what I've looked online, I have all the necessary compiler flags. I can't see what is wrong/missing in here.

I believe you forgot to add appropriate flags
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fprofile-arcs -ftest-coverage")
set(CMAKE_CXX_FLAGS " ${CMAKE_CXX_FLAGS} -fprofile-arcs -ftest-coverage")

Related

Why CTest can't find tests with googletest ? Also, can I run a single test function by mouse click in visual studio code like in visual studio? [duplicate]

I have a project with a structure
├── CMakeLists.txt
├── mzl.c
├── mzl.h
└── tests
├── CMakeLists.txt
├── mzl-communication-test.c
├── mzl-setup-test.c
├── mzl-test-errors.c
└── mzl-test-errors.h
Where the top directory CMakeLists.txt file is
project(mzl)
cmake_minimum_required(VERSION 2.8)
add_subdirectory(tests)
# Enable testing for the project
enable_testing()
# Find zmq
find_library(ZMQ_LIB zmq REQUIRED)
message(STATUS "ZMQ Library: ${ZMQ_LIB}")
# Find threading library
set(CMAKE_THREAD_PREFER_PTHREAD ON)
find_package(Threads REQUIRED)
message(STATUS "Threading Library: ${CMAKE_THREAD_LIBS_INIT}")
# Set include directories for headers
set (
MZL_INCLUDE_DIRS
${CMAKE_SOURCE_DIR}
CACHE STRING "MZL Include Directories"
)
include_directories(${MZL_INCLUDE_DIRS})
# Set source files
set (
MZL_SRC_FILES
mzl.c
)
# Add library
add_library(${PROJECT_NAME} STATIC ${MZL_SRC_FILES})
# Link to zmq
target_link_libraries(${PROJECT_NAME} ${ZMQ_LIB} ${CMAKE_THREAD_LIBS_INIT})
and tests/CMakeLists.txt is
# Use MZL Source Directories (mzl headers are in top directory)
include_directories(${CMAKE_SOURCE_DIR})
# Variable from here is empty
message(STATUS "MZL Include Directories: ${MZL_INCLUDE_DIRS}")
# Files common to all tests
set ( TEST_COMMON_SOURCES
mzl-test-errors.c
)
# Library setup/shutdown testing
set(SETUP_TEST_NAME mzl-setup-test)
add_executable(${SETUP_TEST_NAME} ${TEST_COMMON_SOURCES} ${SETUP_TEST_NAME}.c)
target_link_libraries(${SETUP_TEST_NAME} ${PROJECT_NAME} ${ZMQ_LIB})
add_test(${SETUP_TEST_NAME} ${SETUP_TEST_NAME})
# Communcations test
set(COMMUNICATION_TEST_NAME mzl-communication-test)
add_executable(${COMMUNICATION_TEST_NAME} ${TEST_COMMON_SOURCES}
${COMMUNICATION_TEST_NAME}.c)
target_link_libraries(${COMMUNICATION_TEST_NAME} ${PROJECT_NAME}
${CMAKE_THREAD_LIBS_INIT} ${ZMQ_LIB})
add_test(${COMMUNICATION_TEST_NAME} ${COMMUNICATION_TEST_NAME})
Everything worked fine before I added the second test mzl-communication-test. After adding it and the lines in the tests/CMakeLists.txt after # Communications test, running ctest did nothing extra -- it still only ran the first test.
After deleting the build directory and running cmake again, I get no errors for the initial CMake run, but running make runs CMake again, resulting in an error with CMake:
CMake Error: Parse error in cache file build/CMakeCache.txt. Offending entry: include
followed by a Make error:
Makefile:203: recipe for target 'cmake_check_build_system' failed
make: *** [cmake_check_build_system] Error 1
Running make again results in everything being built, including the tests; however, running ctest results in
Test project build
No tests were found!!!
The issue seems to be with something that I am doing with CMake, but can't figure out what to do from here as I can't see anything that I'm doing differently than when it was originally working. Even my last commit to git, which was working when I committed it, is no longer working.
You need to move the enable_testing() call to be before you do add_subdirectory(tests)
# Enable testing for the project
enable_testing()
add_subdirectory(tests)

G++/CMake Profile Guided Optimization cannot find generated .gcda files

I am compiling an application using CMake 3.16.3 and G++ 9.3 on Ubuntu 20.04. This is the current source directory:
. (this is called MyApp)
├── src
│   ├── /* source files */
│   └── CMakeLists.txt
├── tests
│   ├── /* source files */
│   └── CMakeLists.txt
├── build-release
│   └── pgo /* folder for .gcda files */
├── build_release.sh
└── CMakeLists.txt*
I am setting the flags in CMakeLists.txt (the root one also marked with asterisk) as follows:
set(MYAPP_PGO "-fprofile-dir=${MYAPP_PGO} -fprofile-generate=${MYAPP_PGO}")
// apply flags
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DNDEBUG -O3 -march=native -flto ${MYAPP_PGO}")
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} ${MYAPP_PGO}")
set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} ${MYAPP_PGO}")
set(CMAKE_MODULE_LINKER_FLAGS "${CMAKE_MODULE_LINKER_FLAGS} ${MYAPP_PGO}")
add_subdirectory(src)
add_subdirectory(tests)
No flags are being set in src/CMakeLists.txt and tests/CMakeLists.txt.
MYAPP_PGO is set in bash and is the absolute path of build-release/pgo. I have a script (build_release.sh) that builds the program:
# excluded other lines and flags for brevity
cd build-release
cmake -DMYAPP_PGO="$(pwd)/pgo/" ..
make -j1
After the profile run, I see that there are multiple files in build-release/pgo, one for each cpp file in src and test, such as
#home#johndoe#MyApp#build-release#src#CMakeFiles#MYAPPLICATION_myapp.dir#sample_source.cpp.gcda
However, when compiling again with
// this is a multithreaded program
set(MYAPP_PGO "-fprofile-dir=${MYAPP_PGO} -fprofile-use=${MYAPP_PGO} -fprofile-correction")
// apply flags
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DNDEBUG -O3 -march=native -flto ${MYAPP_PGO}")
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} ${MYAPP_PGO}")
set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} ${MYAPP_PGO}")
set(CMAKE_MODULE_LINKER_FLAGS "${CMAKE_MODULE_LINKER_FLAGS} ${MYAPP_PGO}")
add_subdirectory(src)
add_subdirectory(tests)
I get a warning stating that there are missing profile files:
/home/johndoe/MyApp/src/sample_source.cpp: In function ‘_GLOBAL__sub_I_sample_source.cpp’:
/home/johndoe/MyApp/src/sample_source.cpp:215:1: warning: ‘/home/johndoe/MyApp/src/sample_source.cpp/build-release/pgo//#home#johndoe#MyApp#build-release#src#CMakeFiles#MYAPPLICATION_myapp.dir#sample_source.cpp.gcda’ profile count data file not found [-Wmissing-profile]
215:1 refers to the last character in this source file.
I have tested the speed of the program with and without PGO and have seen no improvement. Although PGO is not guaranteed to bring any speed ups, I tend to believe that PGO did not work as expected here. Am I doing something wrong?
For anyone wondering...
I did not write the original build system of the project. I discovered that it compiled one executable and one library from the same source. Whilst the executable was profiled and recompiled successfully (PGO was done flawlessly), the library was not used anywhere. Hence the missing profile files. Because the profiler outputs extremely long names, I thought the error came from the executable. Thank you all for the help.

Unable to link classes in GTest with CMake

I am trying to incorporate GTests in my project using CMake. I followed this instruction and I get following error:
Undefined symbols for architecture x86_64:
"SomeClass::someMethod()", referenced from:
someMethod_TrivialTest_Test::TestBody() in SomeClassTest.cpp.o
ld: symbol(s) not found for architecture x86_64
Here is my CMake file:
cmake_minimum_required(VERSION 3.11)
project (someProject)
set(CMAKE_CXX_STANDARD 17)
#Include headers
include_directories("../include")
#Add source files
file(GLOB SOURCES "src/*.cpp")
add_executable(someProject ${SOURCES})
################################
# GTest
################################
# Download and unpack googletest at configure time
configure_file(CMakeLists.txt.in googletest-download/CMakeLists.txt)
execute_process(COMMAND ${CMAKE_COMMAND} -G "${CMAKE_GENERATOR}" .
RESULT_VARIABLE result
WORKING_DIRECTORY ${CMAKE_BINARY_DIR}/googletest-download )
if(result)
message(FATAL_ERROR "CMake step for googletest failed: ${result}")
endif()
execute_process(COMMAND ${CMAKE_COMMAND} --build .
RESULT_VARIABLE result
WORKING_DIRECTORY ${CMAKE_BINARY_DIR}/googletest-download )
if(result)
message(FATAL_ERROR "Build step for googletest failed: ${result}")
endif()
# Prevent overriding the parent project's compiler/linker
# settings on Windows
set(gtest_force_shared_crt ON CACHE BOOL "" FORCE)
# Add googletest directly to our build. This defines
# the gtest and gtest_main targets.
add_subdirectory(${CMAKE_BINARY_DIR}/googletest-src
${CMAKE_BINARY_DIR}/googletest-build
EXCLUDE_FROM_ALL)
# The gtest/gtest_main targets carry header search path
# dependencies automatically when using CMake 2.8.11 or
# later. Otherwise we have to add them here ourselves.
if (CMAKE_VERSION VERSION_LESS 2.8.11)
include_directories("${gtest_SOURCE_DIR}/include")
endif()
# Add test cpp file
add_executable( someTests ./test/SomeClassTest.cpp)
# Link test executable against gtest & gtest_main
target_link_libraries(someTests gtest gtest_main)
add_test( someTests someTests )
My project structure (CMakeLists.txt.in is used to download the GTest library, added from the instruction mentioned above):
.
├── CMakeLists.txt
├── CMakeLists.txt.in
├── include
│ └──SomeClass.hpp
├── src
│ ├── Main.cpp
│ └── SomeClass.cpp
└── tests
└── SomeClassTest.cpp
If I manually create and link objects, it works.
g++ -c ./src/SomeClass.cpp
g++ -c ./test/SomeClassTest.cpp
g++ SomeClassTest.o SomeClass.o ./build/googletest-build/googlemock/gtest/CMakeFiles/gtest.dir/src/gtest-all.cc.o -o myTests
The object of the test class seems to be there:
./build/CMakeFiles/someTests.dir/test/SomeClassTest.cpp.o
But the directory for the someProject object is empty:
./build/CMakeFiles/someProject.dir/src/
So I am missing something in the CMake file and it is not linking properly. All the answers I could find so far were related to specifying target_link_libraries but I am not sure if that is the problem here. I am new to CMake and linking issues. Would reeeally appreciate any advice!
All the answers I could find so far were related to specifying target_link_libraries but I am not sure if that is the problem here.
You were right on track with this assumption.
Currently, you're telling CMake that there is an executable to be built from some sources and a test to be built from some other sources and linked with gtest. CMake doesn't know that the executable and your test are in any way related, though!
I see two possible solutions:
add the sources of the executable (except the one with the main function) as sources to the test.
build all of the sources from the executable (except the one with the main function) as library and link both the executable and the test to that library.
I prefer the later one, which would - roughly - look like:
add_library(someProgram_lib ${SOURCES})
add_executable(someProgram src/main.cc)
target_link_libraries(someProgram someProgram_lib)
add_executable(someTests ./test/SomeClassTest.cpp)
target_link_libraries(someTests gtest gtest_main someProgram_lib)

Why would google tests compile but not be able to see my project sources?

Why would google tests compile but not be able to see my project sources?
Here's the error that I'm getting:
$ cmake . && make && make test
-- Configuring done
-- Generating done
-- Build files have been written to: mars_rover
Scanning dependencies of target mars_rover
[ 8%] Building CXX object CMakeFiles/mars_rover.dir/src/rover.cpp.o
Linking CXX executable build/bin/mars_rover
[ 33%] Built target mars_rover
[ 41%] Built target gtest
[ 50%] Built target gtest_main
Scanning dependencies of target mars_rover_TEST
[ 58%] Building CXX object CMakeFiles/mars_rover_TEST.dir/test/test_mars_rover.cpp.o
mars_rover/test/test_mars_rover.cpp:2:10: fatal error: 'src/directions.h' file not found
#include "src/directions.h"
^
1 error generated.
make[2]: *** [CMakeFiles/mars_rover_TEST.dir/test/test_mars_rover.cpp.o] Error 1
make[1]: *** [CMakeFiles/mars_rover_TEST.dir/all] Error 2
make: *** [all] Error 2
Here's how I've got my project laid out:
$ tree {src,test,lib} -L 1
src
├── directions.cpp
├── directions.h
├── main.cpp
├── plateau.cpp
├── plateau.h
├── point.h
├── rover.cpp
└── rover.h
test
├── input1
├── output1
├── test_main.cpp
└── test_mars_rover.cpp
lib
├── CMakeLists.txt
└── gtest-1.7.0
And here's my CMakeLists.txt
cmake_minimum_required(VERSION 2.8)
# Options. Turn on with 'cmake -Dtest=ON'.
option(test "Build all tests." ON)
set(PROJECT_NAME mars_rover CXX)
project(${PROJECT_NAME})
set(CMAKE_CXX_FLAGS "-g -Wall -Werror")
file(GLOB_RECURSE PROJECT_SOURCES ${CMAKE_SOURCE_DIR}/src/*.cpp)
add_executable(${PROJECT_NAME} ${PROJECT_SOURCES})
SET(EXECUTABLE_OUTPUT_PATH ${PROJECT_BINARY_DIR}/build/bin)
SET(LIBRARY_OUTPUT_PATH ${PROJECT_BINARY_DIR}/build/lib)
if (test)
add_subdirectory(lib/gtest-1.7.0)
enable_testing()
include_directories(${gtest_SOURCE_DIR}/include ${gtest_SOURCE_DIR})
# finding test sources
file(GLOB_RECURSE TEST_SOURCES ${CMAKE_SOURCE_DIR}/test/*.cpp ${CMAKE_SOURCE_DIR}/src/*.cpp)
add_executable(${PROJECT_NAME}_TEST ${TEST_SOURCES})
# link to gtest
target_link_libraries(${PROJECT_NAME}_TEST gtest gtest_main)
add_test(CardinalDirectionTests ${EXECUTABLE_OUTPUT_PATH}/${PROJECT_NAME}_TEST --gtest_filter=MarsRoverTest.CardinalDirectionTests)
add_test(RelativeDirectionTests ${EXECUTABLE_OUTPUT_PATH}/${PROJECT_NAME}_TEST --gtest_filter=MarsRoverTest.RelativeDirectionTests)
endif()
Your test executable can't find 'src/directions.h' since its parent (${CMAKE_SOURCE_DIR}) hasn't been added to the include_directories call. Just adding it should work.
However, I can see a few other minor points in your setup. Running through your CMakeLists.txt, here are the changes I'd make:
cmake_minimum_required(VERSION 2.8.12)
If you can specify 2.8.12 as the minimum, you have access to the more useful target_include_directories command. Where include_directories is a bit of a blunderbuss approach, target_include_directories allows you to specify search paths just for that specific target. If you specify these as PUBLIC or INTERFACE, then subsequent targets which link to this one will automatically inherit these search paths too.
In a similar vein, you could look at using target_compile_definitions and target_compile_options.
set(PROJECT_NAME mars_rover CXX)
project(${PROJECT_NAME})
project(mars_rover)
The project command sets the variable PROJECT_NAME, so your set command has little use here. And CMake will detect that this is a C++ project by virtue of the source file suffixes.
By including all your sources in two separate targets (the main exe and the test exe), these will all be compiled twice. To avoid this inefficiency, I'd make a library of all your sources in "/src" except "main.cpp" and then have an exe which only has main.cpp and links to this library.
Also, using file(GLOB ...) or file(GLOB_RECURSE ...) is discouraged as a means of gathering source lists.
set(CMAKE_CXX_FLAGS "-g -Wall -Werror")
file(GLOB_RECURSE PROJECT_SOURCES ${CMAKE_SOURCE_DIR}/src/*.cpp)
add_executable(${PROJECT_NAME} ${PROJECT_SOURCES})
# No need to include .h files, but they show up in IDEs like Xcode if you do.
set(libSources
src/directions.cpp src/directions.h
src/plateau.cpp src/plateau.h
src/point.h
src/rover.cpp src/rover.h
)
add_library(${PROJECT_NAME}_LIB ${libSources})
# Anything linking to this will automatically have ${PROJECT_SOURCE_DIR}
# added to the compiler's search paths since it is PUBLIC. Prefer
# ${PROJECT_SOURCE_DIR} to ${CMAKE_SOURCE_DIR} in case this project is not
# the top-level one.
target_include_directories(${PROJECT_NAME}_LIB PUBLIC ${PROJECT_SOURCE_DIR})
# Use generator expressions to conditionally apply the flags to Unix and Debug
# builds. Anything linking to this will automatically have these flags also
# applied since they are PUBLIC.
target_compile_options(${PROJECT_NAME}_LIB PUBLIC
$<$<BOOL:${UNIX}>:-Werror -Wall $<$<CONFIG:Debug>:-g>>)
add_executable(${PROJECT_NAME} src/main.cpp)
target_link_libraries(${PROJECT_NAME} ${PROJECT_NAME}_LIB)
For the test, it looks like you have 2 or maybe 3 main functions - that's going to be a problem :-) gtest_main is a small helper which provides a main function which calls the required gtest functions to invoke the tests. I'm guessing you've also got main in "test/test_main.cpp" and since you're currently including all your "src/" files, I suppose you've also got a main in "src/main.cpp".
By splitting the mars_rover target into a lib and exe, you can just link to the lib and avoid explicitly excluding "src/main.cpp" from the test. I can't tell whether you want to use your own "test_main.cpp" or use gtest's helper - I've assumed the latter:
include_directories(${gtest_SOURCE_DIR}/include ${gtest_SOURCE_DIR})
file(GLOB_RECURSE TEST_SOURCES ...)
add_executable(${PROJECT_NAME}_TEST ${TEST_SOURCES})
target_link_libraries(${PROJECT_NAME}_TEST gtest gtest_main)
add_executable(${PROJECT_NAME}_TEST test/test_mars_rover.cpp)
# Only bring gtest's include path into scope - its src dir is not designed to
# be public
target_include_directories(${PROJECT_NAME}_TEST PRIVATE
${gtest_SOURCE_DIR}/include)
target_link_libraries(${PROJECT_NAME}_TEST ${PROJECT_NAME}_LIB gtest gtest_main)
Finally, there's no need to specify the full path to the test exe if you use the following syntax:
add_test(NAME CardinalDirectionTests
COMMAND ${PROJECT_NAME}_TEST
--gtest_filter=MarsRoverTest.CardinalDirectionTests)
add_test(NAME RelativeDirectionTests
COMMAND ${PROJECT_NAME}_TEST
--gtest_filter=MarsRoverTest.RelativeDirectionTests)

Detailed guide on using gcov with CMake/CDash?

I'm using CMake with my project and set up a cdash server for continuous/nightly building. Everything works well and by setting up a crontab, we have hourly/nightly build/test results uploaded to our cdash server automatically.
My next step is to add test coverage report to the build. I find the document here https://gitlab.kitware.com/cmake/community/-/wikis/doc/ctest/Coverage but frankly it's a bit far from a practical guide.
Currently I've added the required flag (instead of -fprofile-arcs -ftest-coverage, I find --coverage better), the compilation process generates .gcno files. But then I'm stuck. The command
make NightlyCoverage
doesn't seem to do anything. Could anybody tell me what is the next to do? The result that I want, is by doing make NightlyCoverage, coverage reports are generated and uploaded to cdash server.
I've been using https://github.com/bilke/cmake-modules/blob/master/CodeCoverage.cmake successfully.
Just followed the guidelines: added the files to my CMAKE_MODULE_PATH directory, added
set(CMAKE_MODULE_PATH ${PROJECT_SOURCE_DIR}/CMakeModules)
if(CMAKE_COMPILER_IS_GNUCXX)
include(CodeCoverage)
setup_target_for_coverage(${PROJECT_NAME}_coverage ${PROJECT_TEST_NAME} coverage)
endif()
in my CMakeLists.txt. I also added manually gcov as a dependency for my target:
if(CMAKE_COMPILER_IS_GNUCXX)
target_link_libraries(${PROJECT_TEST_NAME} gcov)
endif()
With this, I just type
make my_project_coverage
and I get the html report in the coverage directory of my build tree.
I use gcovr to make a GCC Code Coverage Report without the CodeCoverage.cmake :
$ cd /path/to/your/project
$ mkdir build && cd build && cmake ..
$ make && make test
$ gcovr -r ../ .
I set up my project 'foo' in the following way. Copied the cmake file from the https://github.com/bilke/cmake-modules/blob/master/CodeCoverage.cmake to a subdirectory 'cmake_modules'. In the CMakeLists.txt file after the add_executable(foo ...) I added the following:
if(CMAKE_COMPILER_IS_GNUCXX)
LIST(APPEND CMAKE_MODULE_PATH "${PROJECT_SOURCE_DIR}/cmake_modules")
include(CodeCoverage)
APPEND_COVERAGE_COMPILER_FLAGS()
set(COVERAGE_LCOV_EXCLUDES 'dir1/*' 'dir2/*') // this is optional if you want to exclude some directory from the report
SETUP_TARGET_FOR_COVERAGE_LCOV(NAME foo_coverage
EXECUTABLE foo
DEPENDENCIES foo)
endif()
After cmake, build the target
make
make foo_coverage
And open the report with index.html file in the foo_coverage folder in the build folder
This answer is the same as #rcomblen's answer but its a bit outdated so I'll share my solution. Here's what I did:
created a toy project
(base) ciaran#DESKTOP-K0APGUV:/mnt/d/CoverageTest$ tree -L 2
.
├── CMakeLists.txt
├── cmake
│   └── CodeCoverage.cmake
├── src
│   ├── domath.cpp
│   ├── domath.h
│   └── testdomath.cpp
└── third_party
└── googletest
Where
// src/domath.h
#ifndef COVERAGETEST_DOMATH_H
#define COVERAGETEST_DOMATH_H
class domath {
public:
int add(int a, int b);
};
#endif //COVERAGETEST_DOMATH_H
and
// src/domath.cpp
#include "domath.h"
int domath::add(int a, int b) {
return a + b;
}
and
// src/testdomath.cpp
#include "gtest/gtest.h"
#include "domath.h"
TEST(DoMathTests, testAdd){
domath m;
int actual = m.add(4, 6);
ASSERT_EQ(10, actual);
}
download googletest and put it under third party directory
copy the gist so kindly shared by the other answers on this thread into cmake/CodeCoverage.cmake
install gcovr. This step is vital, because the other answers on this thread no longer work with the version of gcovr that I already had:
(base) ciaran#DESKTOP-K0APGUV:/mnt/d/CoverageTest$ pip install gcovr
(base) ciaran#DESKTOP-K0APGUV:/mnt/d/CoverageTest$ gcovr --version
gcovr 4.2
(base) ciaran#DESKTOP-K0APGUV:/mnt/d/CoverageTest$ which gcovr
/home/ciaran/miniconda3/bin/gcovr
Note, we need the output of which gcovr for the cmake script.
4) Write a cmake script that create a library, a test executable and use the CodeCoverage.cmake module:
cmake_minimum_required(VERSION 3.15)
project(CoverageTest)
set(CMAKE_CXX_STANDARD 14)
# setup googletest
add_subdirectory(third_party/googletest)
# create our library
add_library(DoMath STATIC src/domath.h src/domath.cpp)
add_dependencies(DoMath gtest gtest_main)
# create the test executable
add_executable(TestDoMath src/testdomath.cpp)
target_include_directories(TestDoMath PRIVATE third_party/googletest/googletest)
target_link_libraries(TestDoMath PRIVATE
DoMath gtest gtest_main)
add_dependencies(TestDoMath DoMath gtest gtest_main)
# now for coverage bits
set(CMAKE_MODULE_PATH ${PROJECT_SOURCE_DIR}/cmake)
if (CMAKE_COMPILER_IS_GNUCXX)
include(CodeCoverage)
append_coverage_compiler_flags()
# we need to turn off optimization for non-skewed coverage reports
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -O0")
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -O0")
# optional excludes - None needed here
# set(COVERAGE_EXCLUDES)
# importantly, set the path to the gcovr executable that you downladed
set(GCOVR_PATH "/home/ciaran/miniconda3/bin/gcovr")
# Works
setup_target_for_coverage_gcovr_xml(
NAME TestDoMathCoverageXml
EXECUTABLE TestDoMath
DEPENDENCIES TestDoMath DoMath
)
# Works
setup_target_for_coverage_gcovr_html(
NAME TestDoMathCoverageHtml
EXECUTABLE TestDoMath
DEPENDENCIES TestDoMath DoMath
)
# This one did not work for me:
setup_target_for_coverage_lcov(
NAME TestDoMathCoverageLcov
EXECUTABLE TestDoMath
DEPENDENCIES TestDoMath DoMath
)
endif ()
And thats it. Now just build the new targets.
Good luck.