Commit 89975e51e766954d7044f0af1ed99f0256654c24

Authored by Henry Fredrick Schreiner
Committed by Henry Schreiner
1 parent 952f2913

Updating coverage

.codecov.yml
1 1  
2 2 ignore:
3 3 - "tests"
  4 + - "examples"
... ...
CMakeLists.txt
... ... @@ -61,11 +61,6 @@ include(CMakeDependentOption)
61 61 # Allow IDE's to group targets into folders
62 62 set_property(GLOBAL PROPERTY USE_FOLDERS ON)
63 63  
64   -if(CMAKE_BUILD_TYPE STREQUAL Coverage)
65   - include(CodeCoverage)
66   - setup_target_for_coverage(CLI11_coverage ctest coverage)
67   -endif()
68   -
69 64 file(GLOB CLI11_headers "${CMAKE_CURRENT_SOURCE_DIR}/include/CLI/*")
70 65 # To see in IDE, must be listed for target
71 66  
... ...
cmake/CodeCoverage.cmake
1   -# Copyright (c) 2012 - 2015, Lars Bilke
  1 +# Copyright (c) 2012 - 2017, Lars Bilke
2 2 # All rights reserved.
3 3 #
4 4 # Redistribution and use in source and binary forms, with or without modification,
... ... @@ -26,7 +26,7 @@
26 26 # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
27 27 # SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 28 #
29   -#
  29 +# CHANGES:
30 30 #
31 31 # 2012-01-31, Lars Bilke
32 32 # - Enable Code Coverage
... ... @@ -35,164 +35,210 @@
35 35 # - Added support for Clang.
36 36 # - Some additional usage instructions.
37 37 #
  38 +# 2016-02-03, Lars Bilke
  39 +# - Refactored functions to use named parameters
  40 +#
  41 +# 2017-06-02, Lars Bilke
  42 +# - Merged with modified version from github.com/ufz/ogs
  43 +#
  44 +#
38 45 # USAGE:
39   -
40   -# 0. (Mac only) If you use Xcode 5.1 make sure to patch geninfo as described here:
41   -# http://stackoverflow.com/a/22404544/80480
42 46 #
43 47 # 1. Copy this file into your cmake modules path.
44 48 #
45 49 # 2. Add the following line to your CMakeLists.txt:
46   -# INCLUDE(CodeCoverage)
  50 +# include(CodeCoverage)
47 51 #
48   -# 3. Set compiler flags to turn off optimization and enable coverage:
49   -# SET(CMAKE_CXX_FLAGS "-g -O0 -fprofile-arcs -ftest-coverage")
50   -# SET(CMAKE_C_FLAGS "-g -O0 -fprofile-arcs -ftest-coverage")
  52 +# 3. Append necessary compiler flags:
  53 +# APPEND_COVERAGE_COMPILER_FLAGS()
51 54 #
52   -# 3. Use the function SETUP_TARGET_FOR_COVERAGE to create a custom make target
53   -# which runs your test executable and produces a lcov code coverage report:
  55 +# 4. If you need to exclude additional directories from the report, specify them
  56 +# using the COVERAGE_EXCLUDES variable before calling SETUP_TARGET_FOR_COVERAGE.
54 57 # Example:
55   -# SETUP_TARGET_FOR_COVERAGE(
56   -# my_coverage_target # Name for custom target.
57   -# test_driver # Name of the test driver executable that runs the tests.
58   -# # NOTE! This should always have a ZERO as exit code
59   -# # otherwise the coverage generation will not complete.
60   -# coverage # Name of output directory.
61   -# )
  58 +# set(COVERAGE_EXCLUDES 'dir1/*' 'dir2/*')
62 59 #
63   -# 4. Build a Debug build:
64   -# cmake -DCMAKE_BUILD_TYPE=Debug ..
65   -# make
66   -# make my_coverage_target
  60 +# 5. Use the functions described below to create a custom make target which
  61 +# runs your test executable and produces a code coverage report.
67 62 #
  63 +# 6. Build a Debug build:
  64 +# cmake -DCMAKE_BUILD_TYPE=Debug ..
  65 +# make
  66 +# make my_coverage_target
68 67 #
69 68  
70   -# Check prereqs
  69 +include(CMakeParseArguments)
71 70  
72   -FIND_PROGRAM( GCOV_PATH gcov)
73   -FIND_PROGRAM( LCOV_PATH lcov )
74   -FIND_PROGRAM( GENHTML_PATH genhtml )
75   -FIND_PROGRAM( GCOVR_PATH gcovr PATHS ${CMAKE_SOURCE_DIR}/tests)
76   -
77   -IF(NOT GCOV_PATH)
78   - MESSAGE(FATAL_ERROR "gcov not found! Aborting...")
79   -ENDIF() # NOT GCOV_PATH
80   -
81   -IF("${CMAKE_CXX_COMPILER_ID}" MATCHES "(Apple)?[Cc]lang")
82   - IF("${CMAKE_CXX_COMPILER_VERSION}" VERSION_LESS 3)
83   - MESSAGE(FATAL_ERROR "Clang version must be 3.0.0 or greater! Aborting...")
84   - ENDIF()
85   -ELSEIF(NOT CMAKE_COMPILER_IS_GNUCXX)
86   - MESSAGE(FATAL_ERROR "Compiler is not GNU gcc! Aborting...")
87   -ENDIF() # CHECK VALID COMPILER
88   -
89   -SET(CMAKE_CXX_FLAGS_COVERAGE
90   - "-g -O0 --coverage"
  71 +# Check prereqs
  72 +find_program( GCOV_PATH gcov )
  73 +find_program( LCOV_PATH NAMES lcov lcov.bat lcov.exe lcov.perl)
  74 +find_program( GENHTML_PATH NAMES genhtml genhtml.perl genhtml.bat )
  75 +find_program( GCOVR_PATH gcovr PATHS ${CMAKE_SOURCE_DIR}/scripts/test)
  76 +find_program( SIMPLE_PYTHON_EXECUTABLE python )
  77 +
  78 +if(NOT GCOV_PATH)
  79 + message(FATAL_ERROR "gcov not found! Aborting...")
  80 +endif() # NOT GCOV_PATH
  81 +
  82 +if("${CMAKE_CXX_COMPILER_ID}" MATCHES "(Apple)?[Cc]lang")
  83 + if("${CMAKE_CXX_COMPILER_VERSION}" VERSION_LESS 3)
  84 + message(FATAL_ERROR "Clang version must be 3.0.0 or greater! Aborting...")
  85 + endif()
  86 +elseif(NOT CMAKE_COMPILER_IS_GNUCXX)
  87 + message(FATAL_ERROR "Compiler is not GNU gcc! Aborting...")
  88 +endif()
  89 +
  90 +set(COVERAGE_COMPILER_FLAGS "-g -O0 --coverage -fprofile-arcs -ftest-coverage"
  91 + CACHE INTERNAL "")
  92 +
  93 +set(CMAKE_CXX_FLAGS_COVERAGE
  94 + ${COVERAGE_COMPILER_FLAGS}
91 95 CACHE STRING "Flags used by the C++ compiler during coverage builds."
92 96 FORCE )
93   -SET(CMAKE_C_FLAGS_COVERAGE
94   - "-g -O0 --coverage"
  97 +set(CMAKE_C_FLAGS_COVERAGE
  98 + ${COVERAGE_COMPILER_FLAGS}
95 99 CACHE STRING "Flags used by the C compiler during coverage builds."
96 100 FORCE )
97   -SET(CMAKE_EXE_LINKER_FLAGS_COVERAGE
98   - "--coverage"
  101 +set(CMAKE_EXE_LINKER_FLAGS_COVERAGE
  102 + ""
99 103 CACHE STRING "Flags used for linking binaries during coverage builds."
100 104 FORCE )
101   -SET(CMAKE_SHARED_LINKER_FLAGS_COVERAGE
102   - "--coverage"
  105 +set(CMAKE_SHARED_LINKER_FLAGS_COVERAGE
  106 + ""
103 107 CACHE STRING "Flags used by the shared libraries linker during coverage builds."
104 108 FORCE )
105   -MARK_AS_ADVANCED(
  109 +mark_as_advanced(
106 110 CMAKE_CXX_FLAGS_COVERAGE
107 111 CMAKE_C_FLAGS_COVERAGE
108 112 CMAKE_EXE_LINKER_FLAGS_COVERAGE
109 113 CMAKE_SHARED_LINKER_FLAGS_COVERAGE )
110 114  
111   -IF ( NOT (CMAKE_BUILD_TYPE STREQUAL "Debug" OR CMAKE_BUILD_TYPE STREQUAL "Coverage"))
112   - MESSAGE( WARNING "Code coverage results with an optimized (non-Debug) build may be misleading" )
113   -ENDIF() # NOT CMAKE_BUILD_TYPE STREQUAL "Debug"
114   -
115   -
116   -# Param _targetname The name of new the custom make target
117   -# Param _testrunner The name of the target which runs the tests.
118   -# MUST return ZERO always, even on errors.
119   -# If not, no coverage report will be created!
120   -# Param _outputname lcov output is generated as _outputname.info
121   -# HTML report is generated in _outputname/index.html
122   -# Optional fourth parameter is passed as arguments to _testrunner
123   -# Pass them in list form, e.g.: "-j;2" for -j 2
124   -FUNCTION(SETUP_TARGET_FOR_COVERAGE _targetname _testrunner _outputname)
125   -
126   - IF(NOT LCOV_PATH)
127   - MESSAGE(FATAL_ERROR "lcov not found! Aborting...")
128   - ENDIF() # NOT LCOV_PATH
129   -
130   - IF(NOT GENHTML_PATH)
131   - MESSAGE(FATAL_ERROR "genhtml not found! Aborting...")
132   - ENDIF() # NOT GENHTML_PATH
133   -
134   - SET(coverage_info "${CMAKE_BINARY_DIR}/${_outputname}.info")
135   - SET(coverage_cleaned "${coverage_info}.cleaned")
136   -
137   - SEPARATE_ARGUMENTS(test_command UNIX_COMMAND "${_testrunner}")
138   -
139   - # Setup target
140   - ADD_CUSTOM_TARGET(${_targetname}
141   -
142   - # Cleanup lcov
143   - ${LCOV_PATH} --directory . --zerocounters
144   -
145   - # Run tests
146   - COMMAND ${test_command} ${ARGV3}
147   -
148   - # Capturing lcov counters and generating report
149   - COMMAND ${LCOV_PATH} --directory . --capture --output-file ${coverage_info}
150   - COMMAND ${LCOV_PATH} --remove ${coverage_info} '*/tests/*' '*gtest*' '*gmock*' '/usr/*' --output-file ${coverage_cleaned}
151   - COMMAND ${GENHTML_PATH} -o ${_outputname} ${coverage_cleaned}
152   - COMMAND ${CMAKE_COMMAND} -E remove ${coverage_info} ${coverage_cleaned}
153   -
154   - WORKING_DIRECTORY ${CMAKE_BINARY_DIR}
155   - COMMENT "Resetting code coverage counters to zero.\nProcessing code coverage counters and generating report."
156   - )
157   -
158   - # Show info where to find the report
159   - ADD_CUSTOM_COMMAND(TARGET ${_targetname} POST_BUILD
160   - COMMAND ;
161   - COMMENT "Open ./${_outputname}/index.html in your browser to view the coverage report."
162   - )
163   -
164   -ENDFUNCTION() # SETUP_TARGET_FOR_COVERAGE
165   -
166   -# Param _targetname The name of new the custom make target
167   -# Param _testrunner The name of the target which runs the tests
168   -# Param _outputname cobertura output is generated as _outputname.xml
169   -# Optional fourth parameter is passed as arguments to _testrunner
170   -# Pass them in list form, e.g.: "-j;2" for -j 2
171   -FUNCTION(SETUP_TARGET_FOR_COVERAGE_COBERTURA _targetname _testrunner _outputname)
172   -
173   - IF(NOT PYTHON_EXECUTABLE)
174   - MESSAGE(FATAL_ERROR "Python not found! Aborting...")
175   - ENDIF() # NOT PYTHON_EXECUTABLE
176   -
177   - IF(NOT GCOVR_PATH)
178   - MESSAGE(FATAL_ERROR "gcovr not found! Aborting...")
179   - ENDIF() # NOT GCOVR_PATH
180   -
181   - ADD_CUSTOM_TARGET(${_targetname}
182   -
183   - # Run tests
184   - ${_testrunner} ${ARGV3}
185   -
186   - # Running gcovr
187   - COMMAND ${GCOVR_PATH} -x -r ${CMAKE_SOURCE_DIR} -e '${CMAKE_SOURCE_DIR}/tests/' -o ${_outputname}.xml
188   - WORKING_DIRECTORY ${CMAKE_BINARY_DIR}
189   - COMMENT "Running gcovr to produce Cobertura code coverage report."
190   - )
191   -
192   - # Show info where to find the report
193   - ADD_CUSTOM_COMMAND(TARGET ${_targetname} POST_BUILD
194   - COMMAND ;
195   - COMMENT "Cobertura code coverage report saved in ${_outputname}.xml."
196   - )
197   -
198   -ENDFUNCTION() # SETUP_TARGET_FOR_COVERAGE_COBERTURA
  115 +if(NOT CMAKE_BUILD_TYPE STREQUAL "Debug")
  116 + message(WARNING "Code coverage results with an optimised (non-Debug) build may be misleading")
  117 +endif() # NOT CMAKE_BUILD_TYPE STREQUAL "Debug"
  118 +
  119 +if(CMAKE_C_COMPILER_ID STREQUAL "GNU")
  120 + link_libraries(gcov)
  121 +else()
  122 + set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} --coverage")
  123 +endif()
  124 +
  125 +# Defines a target for running and collection code coverage information
  126 +# Builds dependencies, runs the given executable and outputs reports.
  127 +# NOTE! The executable should always have a ZERO as exit code otherwise
  128 +# the coverage generation will not complete.
  129 +#
  130 +# SETUP_TARGET_FOR_COVERAGE(
  131 +# NAME testrunner_coverage # New target name
  132 +# EXECUTABLE testrunner -j ${PROCESSOR_COUNT} # Executable in PROJECT_BINARY_DIR
  133 +# DEPENDENCIES testrunner # Dependencies to build first
  134 +# )
  135 +function(SETUP_TARGET_FOR_COVERAGE)
  136 +
  137 + set(options NONE)
  138 + set(oneValueArgs NAME)
  139 + set(multiValueArgs EXECUTABLE EXECUTABLE_ARGS DEPENDENCIES)
  140 + cmake_parse_arguments(Coverage "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN})
  141 +
  142 + if(NOT LCOV_PATH)
  143 + message(FATAL_ERROR "lcov not found! Aborting...")
  144 + endif() # NOT LCOV_PATH
  145 +
  146 + if(NOT GENHTML_PATH)
  147 + message(FATAL_ERROR "genhtml not found! Aborting...")
  148 + endif() # NOT GENHTML_PATH
  149 +
  150 + # Setup target
  151 + add_custom_target(${Coverage_NAME}
  152 +
  153 + # Cleanup lcov
  154 + COMMAND ${LCOV_PATH} --directory . --zerocounters
  155 + # Create baseline to make sure untouched files show up in the report
  156 + COMMAND ${LCOV_PATH} -c -i -d . -o ${Coverage_NAME}.base
  157 +
  158 + # Run tests
  159 + COMMAND ${Coverage_EXECUTABLE}
  160 +
  161 + # Capturing lcov counters and generating report
  162 + COMMAND ${LCOV_PATH} --directory . --capture --output-file ${Coverage_NAME}.info
  163 + # add baseline counters
  164 + COMMAND ${LCOV_PATH} -a ${Coverage_NAME}.base -a ${Coverage_NAME}.info --output-file ${Coverage_NAME}.total
  165 + COMMAND ${LCOV_PATH} --remove ${Coverage_NAME}.total ${COVERAGE_EXCLUDES} --output-file ${PROJECT_BINARY_DIR}/${Coverage_NAME}.info.cleaned
  166 + COMMAND ${GENHTML_PATH} -o ${Coverage_NAME} ${PROJECT_BINARY_DIR}/${Coverage_NAME}.info.cleaned
  167 + COMMAND ${CMAKE_COMMAND} -E remove ${Coverage_NAME}.base ${Coverage_NAME}.total ${PROJECT_BINARY_DIR}/${Coverage_NAME}.info.cleaned
  168 +
  169 + WORKING_DIRECTORY ${PROJECT_BINARY_DIR}
  170 + DEPENDS ${Coverage_DEPENDENCIES}
  171 + COMMENT "Resetting code coverage counters to zero.\nProcessing code coverage counters and generating report."
  172 + )
  173 +
  174 + # Show where to find the lcov info report
  175 + add_custom_command(TARGET ${Coverage_NAME} POST_BUILD
  176 + COMMAND ;
  177 + COMMENT "Lcov code coverage info report saved in ${Coverage_NAME}.info."
  178 + )
  179 +
  180 + # Show info where to find the report
  181 + add_custom_command(TARGET ${Coverage_NAME} POST_BUILD
  182 + COMMAND ;
  183 + COMMENT "Open ./${Coverage_NAME}/index.html in your browser to view the coverage report."
  184 + )
  185 +
  186 +endfunction() # SETUP_TARGET_FOR_COVERAGE
  187 +
  188 +# Defines a target for running and collection code coverage information
  189 +# Builds dependencies, runs the given executable and outputs reports.
  190 +# NOTE! The executable should always have a ZERO as exit code otherwise
  191 +# the coverage generation will not complete.
  192 +#
  193 +# SETUP_TARGET_FOR_COVERAGE_COBERTURA(
  194 +# NAME ctest_coverage # New target name
  195 +# EXECUTABLE ctest -j ${PROCESSOR_COUNT} # Executable in PROJECT_BINARY_DIR
  196 +# DEPENDENCIES executable_target # Dependencies to build first
  197 +# )
  198 +function(SETUP_TARGET_FOR_COVERAGE_COBERTURA)
  199 +
  200 + set(options NONE)
  201 + set(oneValueArgs NAME)
  202 + set(multiValueArgs EXECUTABLE EXECUTABLE_ARGS DEPENDENCIES)
  203 + cmake_parse_arguments(Coverage "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN})
  204 +
  205 + if(NOT SIMPLE_PYTHON_EXECUTABLE)
  206 + message(FATAL_ERROR "python not found! Aborting...")
  207 + endif() # NOT SIMPLE_PYTHON_EXECUTABLE
  208 +
  209 + if(NOT GCOVR_PATH)
  210 + message(FATAL_ERROR "gcovr not found! Aborting...")
  211 + endif() # NOT GCOVR_PATH
  212 +
  213 + # Combine excludes to several -e arguments
  214 + set(COBERTURA_EXCLUDES "")
  215 + foreach(EXCLUDE ${COVERAGE_EXCLUDES})
  216 + set(COBERTURA_EXCLUDES "-e ${EXCLUDE} ${COBERTURA_EXCLUDES}")
  217 + endforeach()
  218 +
  219 + add_custom_target(${Coverage_NAME}
  220 +
  221 + # Run tests
  222 + ${Coverage_EXECUTABLE}
  223 +
  224 + # Running gcovr
  225 + COMMAND ${GCOVR_PATH} -x -r ${CMAKE_SOURCE_DIR} ${COBERTURA_EXCLUDES}
  226 + -o ${Coverage_NAME}.xml
  227 + WORKING_DIRECTORY ${PROJECT_BINARY_DIR}
  228 + DEPENDS ${Coverage_DEPENDENCIES}
  229 + COMMENT "Running gcovr to produce Cobertura code coverage report."
  230 + )
  231 +
  232 + # Show info where to find the report
  233 + add_custom_command(TARGET ${Coverage_NAME} POST_BUILD
  234 + COMMAND ;
  235 + COMMENT "Cobertura code coverage report saved in ${Coverage_NAME}.xml."
  236 + )
  237 +
  238 +endfunction() # SETUP_TARGET_FOR_COVERAGE_COBERTURA
  239 +
  240 +function(APPEND_COVERAGE_COMPILER_FLAGS)
  241 + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${COVERAGE_COMPILER_FLAGS}" PARENT_SCOPE)
  242 + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${COVERAGE_COMPILER_FLAGS}" PARENT_SCOPE)
  243 + message(STATUS "Appending code coverage compiler flags: ${COVERAGE_COMPILER_FLAGS}")
  244 +endfunction() # APPEND_COVERAGE_COMPILER_FLAGS
... ...
tests/CMakeLists.txt
... ... @@ -103,3 +103,13 @@ if(Boost_FOUND)
103 103 target_compile_definitions(OptionalTest PUBLIC CLI11_BOOST_OPTIONAL)
104 104 endif()
105 105  
  106 +if(CMAKE_BUILD_TYPE STREQUAL Coverage)
  107 + include(CodeCoverage)
  108 + setup_target_for_coverage(
  109 + NAME CLI11_coverage
  110 + EXECUTABLE ctest
  111 + DEPENDENCIES
  112 + ${CLI11_TESTS}
  113 + ${CLI11_MULTIONLY_TESTS})
  114 +endif()
  115 +
... ...