Add statement/condition coverage measurement for the test suite.

We're using gcov+lcov, since these tools appear to be the only
usable ones that use the SC/CC metric; and measuring just the line
coverage would be practically criminal negligence.

gcov only works with GCC and Clang, and MSVC's own coverage
measurement tools are not up to the task; so MSVC is out of luck.
pull/33/head
whitequark 2016-07-25 22:09:58 +00:00
parent 5e63d8301e
commit 2fdbabc13c
6 changed files with 80 additions and 8 deletions

View File

@ -4,5 +4,6 @@ if echo $TRAVIS_TAG | grep ^v; then BUILD_TYPE=RelWithDebInfo; else BUILD_TYPE=D
mkdir build mkdir build
cd build cd build
cmake -DCMAKE_C_COMPILER=gcc-5 -DCMAKE_CXX_COMPILER=g++-5 -DCMAKE_BUILD_TYPE=$BUILD_TYPE .. cmake -DCMAKE_C_COMPILER=gcc-5 -DCMAKE_CXX_COMPILER=g++-5 \
-DCMAKE_BUILD_TYPE=$BUILD_TYPE -DENABLE_COVERAGE=ON ..
make VERBOSE=1 make VERBOSE=1

View File

@ -5,4 +5,4 @@ sudo apt-get update -qq
sudo apt-get install -q -y \ sudo apt-get install -q -y \
cmake cmake-data libpng12-dev zlib1g-dev libjson0-dev libfontconfig1-dev \ cmake cmake-data libpng12-dev zlib1g-dev libjson0-dev libfontconfig1-dev \
libgtkmm-2.4-dev libpangomm-1.4-dev libcairo2-dev libgl1-mesa-dev libglu-dev \ libgtkmm-2.4-dev libpangomm-1.4-dev libcairo2-dev libgl1-mesa-dev libglu-dev \
libfreetype6-dev dpkg-dev gcc-5 g++-5 libfreetype6-dev dpkg-dev gcc-5 g++-5 lcov

View File

@ -27,7 +27,10 @@ set(solvespace_VERSION_MAJOR 3)
set(solvespace_VERSION_MINOR 0) set(solvespace_VERSION_MINOR 0)
string(SUBSTRING "${GIT_COMMIT_HASH}" 0 8 solvespace_GIT_HASH) string(SUBSTRING "${GIT_COMMIT_HASH}" 0 8 solvespace_GIT_HASH)
set(ENABLE_TESTS ON CACHE BOOL "Whether the test suite will be built and run") set(ENABLE_TESTS ON CACHE BOOL
"Whether the test suite will be built and run")
set(ENABLE_COVERAGE OFF CACHE BOOL
"Whether code coverage information will be collected")
if(NOT WIN32 AND NOT APPLE) if(NOT WIN32 AND NOT APPLE)
set(GUI gtk2 CACHE STRING "GUI toolkit to use (one of: gtk2 gtk3)") set(GUI gtk2 CACHE STRING "GUI toolkit to use (one of: gtk2 gtk3)")
@ -56,7 +59,7 @@ if(CMAKE_SYSTEM_NAME STREQUAL "Linux" OR CMAKE_SYSTEM_NAME STREQUAL "FreeBSD")
endif() endif()
if(SANITIZE) if(SANITIZE)
if(NOT (CMAKE_C_COMPILER_ID STREQUAL "Clang" AND CMAKE_CXX_COMPILER_ID STREQUAL "Clang")) if(NOT (CMAKE_C_COMPILER_ID MATCHES "Clang" AND CMAKE_CXX_COMPILER_ID MATCHES "Clang"))
message(ERROR "Sanitizers are only available in Clang/Clang++") message(ERROR "Sanitizers are only available in Clang/Clang++")
endif() endif()
set(SANITIZE_FLAGS "-O1 -fno-omit-frame-pointer -fno-optimize-sibling-calls") set(SANITIZE_FLAGS "-O1 -fno-omit-frame-pointer -fno-optimize-sibling-calls")
@ -162,6 +165,14 @@ else() # Linux and compatible systems
endif() endif()
endif() endif()
if(ENABLE_COVERAGE)
find_program(LCOV lcov)
find_program(GENHTML genhtml)
if(NOT LCOV OR NOT GENHTML)
message(FATAL_ERROR "lcov is required for producing coverage reports")
endif()
endif()
# solvespace-only compiler flags # solvespace-only compiler flags
if(WIN32) if(WIN32)
@ -193,9 +204,9 @@ if(MSVC)
set(WARNING_FLAGS "${WARNING_FLAGS} /we4062") set(WARNING_FLAGS "${WARNING_FLAGS} /we4062")
endif() endif()
if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU" OR CMAKE_CXX_COMPILER_ID STREQUAL "Clang") if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU" OR CMAKE_CXX_COMPILER_ID MATCHES "Clang")
set(WARNING_FLAGS "-Wall -Wextra -Wno-unused-parameter") set(WARNING_FLAGS "-Wall -Wextra -Wno-unused-parameter")
if(CMAKE_CXX_COMPILER_ID STREQUAL "Clang") if(CMAKE_CXX_COMPILER_ID MATCHES "Clang")
set(WARNING_FLAGS "${WARNING_FLAGS} -Wfloat-conversion") set(WARNING_FLAGS "${WARNING_FLAGS} -Wfloat-conversion")
endif() endif()
# We rely on these -Werror flags. # We rely on these -Werror flags.
@ -209,6 +220,22 @@ if(WIN32)
set(CMAKE_RC_FLAGS "${CMAKE_RC_FLAGS} -l0") set(CMAKE_RC_FLAGS "${CMAKE_RC_FLAGS} -l0")
endif() endif()
if(ENABLE_COVERAGE)
if(NOT (CMAKE_CXX_COMPILER_ID STREQUAL "GNU" OR
CMAKE_CXX_COMPILER_ID MATCHES "Clang"))
message(FATAL_ERROR "Code coverage is only available on GCC and Clang")
endif()
if(NOT CMAKE_BUILD_TYPE STREQUAL "Debug")
message(FATAL_ERROR "Code coverage produces reliable results only on Debug builds")
endif()
# With -fexceptions, every call becomes a branch. While technically accurate,
# this is not useful for us.
set(COVERAGE_FLAGS -fno-exceptions --coverage)
set(COVERAGE_LIBRARY --coverage)
endif()
# components # components
add_subdirectory(res) add_subdirectory(res)

View File

@ -184,6 +184,9 @@ target_link_libraries(solvespace_cad
${FREETYPE_LIBRARY} ${FREETYPE_LIBRARY}
${Backtrace_LIBRARIES}) ${Backtrace_LIBRARIES})
target_compile_options(solvespace_cad
PRIVATE ${COVERAGE_FLAGS})
# solvespace gui executable # solvespace gui executable
add_executable(solvespace WIN32 MACOSX_BUNDLE add_executable(solvespace WIN32 MACOSX_BUNDLE
@ -197,7 +200,8 @@ add_dependencies(solvespace
target_link_libraries(solvespace target_link_libraries(solvespace
solvespace_cad solvespace_cad
${OPENGL_LIBRARIES} ${OPENGL_LIBRARIES}
${platform_LIBRARIES}) ${platform_LIBRARIES}
${COVERAGE_LIBRARY})
if(WIN32 AND NOT MINGW) if(WIN32 AND NOT MINGW)
set_target_properties(solvespace PROPERTIES set_target_properties(solvespace PROPERTIES
@ -256,3 +260,6 @@ target_include_directories(solvespace_headless
target_link_libraries(solvespace_headless target_link_libraries(solvespace_headless
solvespace_cad solvespace_cad
${CAIRO_LIBRARIES}) ${CAIRO_LIBRARIES})
target_compile_options(solvespace_headless
PRIVATE ${COVERAGE_FLAGS})

View File

@ -14,6 +14,7 @@
#include <stdio.h> #include <stdio.h>
#include <stddef.h> #include <stddef.h>
#include <stdarg.h> #include <stdarg.h>
#include <setjmp.h>
#include <math.h> #include <math.h>
#include <setjmp.h> #include <setjmp.h>
#include <limits.h> #include <limits.h>

View File

@ -1,3 +1,5 @@
# test suite
include_directories( include_directories(
${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_SOURCE_DIR}
${CMAKE_CURRENT_BINARY_DIR}) ${CMAKE_CURRENT_BINARY_DIR})
@ -10,9 +12,43 @@ add_executable(solvespace_testsuite
${testsuite_SOURCES}) ${testsuite_SOURCES})
target_link_libraries(solvespace_testsuite target_link_libraries(solvespace_testsuite
solvespace_headless) solvespace_headless
${COVERAGE_LIBRARY})
add_custom_target(solvespace-test ALL add_custom_target(solvespace-test ALL
COMMAND $<TARGET_FILE:solvespace_testsuite> COMMAND $<TARGET_FILE:solvespace_testsuite>
COMMENT "Testing SolveSpace" COMMENT "Testing SolveSpace"
VERBATIM) VERBATIM)
# coverage reports
if(ENABLE_COVERAGE)
set(LCOV_FLAGS -q --rc lcov_branch_coverage=1 --rc lcov_excl_line=ssassert)
set(LCOV_COLLECT -c -b ${CMAKE_SOURCE_DIR}/src -d ${CMAKE_BINARY_DIR}/src --no-external)
add_custom_command(
OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/coverage_base.info
COMMAND ${LCOV} ${LCOV_FLAGS} ${LCOV_COLLECT}
-o ${CMAKE_BINARY_DIR}/coverage_base.info -i
DEPENDS solvespace_testsuite
COMMENT "Importing baseline coverage data"
VERBATIM)
add_custom_target(solvespace-coverage ALL
COMMAND ${LCOV} ${LCOV_FLAGS} ${LCOV_COLLECT}
-o ${CMAKE_BINARY_DIR}/coverage_test.info
COMMAND ${LCOV} ${LCOV_FLAGS}
-o ${CMAKE_BINARY_DIR}/coverage_full.info
-a ${CMAKE_BINARY_DIR}/coverage_base.info
-a ${CMAKE_BINARY_DIR}/coverage_test.info
COMMAND ${LCOV} ${LCOV_FLAGS} --summary
${CMAKE_BINARY_DIR}/coverage_full.info
COMMAND ${GENHTML} -q --branch-coverage --demangle-cpp --legend
${CMAKE_BINARY_DIR}/coverage_full.info
-o ${CMAKE_BINARY_DIR}/coverage/
-t "SolveSpace testbench"
DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/coverage_base.info
DEPENDS solvespace-test
COMMENT "Generating coverage report"
VERBATIM)
endif()