diff --git a/Modules/CTestCoverageCollectGCOV.cmake b/Modules/CTestCoverageCollectGCOV.cmake index f31e432b1..7df96665f 100644 --- a/Modules/CTestCoverageCollectGCOV.cmake +++ b/Modules/CTestCoverageCollectGCOV.cmake @@ -2,14 +2,19 @@ # CTestCoverageCollectGCOV # ------------------------ # -# This module provides the function ``ctest_coverage_collect_gcov``. -# The function will run gcov on the .gcda files in a binary tree and then -# package all of the .gcov files into a tar file with a data.json that -# contains the source and build directories for CDash to use in parsing -# the coverage data. In addtion the Labels.json files for targets that -# have coverage information are also put in the tar file for CDash to -# asign the correct labels. This file can be sent to a CDash server for -# display with the +# This module provides the ``ctest_coverage_collect_gcov`` function. +# +# This function runs gcov on all .gcda files found in the binary tree +# and packages the resulting .gcov files into a tar file. +# This tarball also contains the following: +# +# * *data.json* defines the source and build directories for use by CDash. +# * *Labels.json* indicates any :prop_sf:`LABELS` that have been set on the +# source files. +# * The *uncovered* directory holds any uncovered files found by +# :variable:`CTEST_EXTRA_COVERAGE_GLOB`. +# +# After generating this tar file, it can be sent to CDash for display with the # :command:`ctest_submit(CDASH_UPLOAD)` command. # # .. command:: cdash_coverage_collect_gcov @@ -172,6 +177,21 @@ function(ctest_coverage_collect_gcov) set(unfiltered_gcov_files) file(GLOB_RECURSE unfiltered_gcov_files RELATIVE ${binary_dir} "${coverage_dir}/*.gcov") + # if CTEST_EXTRA_COVERAGE_GLOB was specified we search for files + # that might be uncovered + if (DEFINED CTEST_EXTRA_COVERAGE_GLOB) + set(uncovered_files) + foreach(search_entry IN LISTS CTEST_EXTRA_COVERAGE_GLOB) + if(NOT GCOV_QUIET) + message("Add coverage glob: ${search_entry}") + endif() + file(GLOB_RECURSE matching_files "${source_dir}/${search_entry}") + if (matching_files) + list(APPEND uncovered_files "${matching_files}") + endif() + endforeach() + endif() + set(gcov_files) foreach(gcov_file ${unfiltered_gcov_files}) file(STRINGS ${binary_dir}/${gcov_file} first_line LIMIT_COUNT 1 ENCODING UTF-8) @@ -195,20 +215,62 @@ function(ctest_coverage_collect_gcov) endif() endforeach() + get_filename_component(resolved_source_file "${source_file}" ABSOLUTE) + foreach(uncovered_file IN LISTS uncovered_files) + get_filename_component(resolved_uncovered_file "${uncovered_file}" ABSOLUTE) + if (resolved_uncovered_file STREQUAL resolved_source_file) + list(REMOVE_ITEM uncovered_files "${uncovered_file}") + endif() + endforeach() + if(NOT is_excluded) list(APPEND gcov_files ${gcov_file}) endif() endforeach() + foreach (uncovered_file ${uncovered_files}) + # Check if this uncovered file should be excluded. + set(is_excluded false) + foreach(exclude_entry IN LISTS CTEST_CUSTOM_COVERAGE_EXCLUDE) + if(uncovered_file MATCHES "${exclude_entry}") + set(is_excluded true) + if(NOT GCOV_QUIET) + message("Excluding coverage for: ${uncovered_file} which matches ${exclude_entry}") + endif() + break() + endif() + endforeach() + if(is_excluded) + continue() + endif() + + # Copy from source to binary dir, preserving any intermediate subdirectories. + get_filename_component(filename "${uncovered_file}" NAME) + get_filename_component(relative_path "${uncovered_file}" DIRECTORY) + string(REPLACE "${source_dir}" "" relative_path "${relative_path}") + if (relative_path) + # Strip leading slash. + string(SUBSTRING "${relative_path}" 1 -1 relative_path) + endif() + file(COPY ${uncovered_file} DESTINATION ${binary_dir}/uncovered/${relative_path}) + if(relative_path) + list(APPEND uncovered_files_for_tar uncovered/${relative_path}/${filename}) + else() + list(APPEND uncovered_files_for_tar uncovered/${filename}) + endif() + endforeach() + # tar up the coverage info with the same date so that the md5 # sum will be the same for the tar file independent of file time # stamps string(REPLACE ";" "\n" gcov_files "${gcov_files}") string(REPLACE ";" "\n" label_files "${label_files}") + string(REPLACE ";" "\n" uncovered_files_for_tar "${uncovered_files_for_tar}") file(WRITE "${coverage_dir}/coverage_file_list.txt" "${gcov_files} ${coverage_dir}/data.json ${label_files} +${uncovered_files_for_tar} ") if (GCOV_QUIET) diff --git a/Tests/CTestCoverageCollectGCOV/TestProject/extra/uncovered1.cpp b/Tests/CTestCoverageCollectGCOV/TestProject/extra/uncovered1.cpp new file mode 100644 index 000000000..e69de29bb diff --git a/Tests/CTestCoverageCollectGCOV/TestProject/uncovered2.cpp b/Tests/CTestCoverageCollectGCOV/TestProject/uncovered2.cpp new file mode 100644 index 000000000..e69de29bb diff --git a/Tests/CTestCoverageCollectGCOV/test.cmake.in b/Tests/CTestCoverageCollectGCOV/test.cmake.in index b2e6d6dfe..d48ef6130 100644 --- a/Tests/CTestCoverageCollectGCOV/test.cmake.in +++ b/Tests/CTestCoverageCollectGCOV/test.cmake.in @@ -15,7 +15,9 @@ list(APPEND CTEST_CUSTOM_COVERAGE_EXCLUDE "/foo/something" "/3rdparty/" "/bar/somethingelse" + "/CMakeFiles/" ) +list(APPEND CTEST_EXTRA_COVERAGE_GLOB "*.cpp") include(CTestCoverageCollectGCOV) set(tar_file ${CTEST_BINARY_DIRECTORY}/gcov.tar) @@ -41,6 +43,8 @@ set(expected_out Testing/CoverageInfo/data.json Testing/CoverageInfo/extra.cpp.gcov Testing/CoverageInfo/main.cpp.gcov + uncovered/extra/uncovered1.cpp + uncovered/uncovered2.cpp ) if("${out}" STREQUAL "${expected_out}")