Code coverage analysis using CodeCoverage.cmake with multiple targets
Asked Answered
O

4

6

I have unit-test in my project implemented using Boost Unit Test Framework and organized into several modules, i.e.:

#define BOOST_TEST_MODULE Connection_test

#ifndef BOOST_TEST_DYN_LINK
#define BOOST_TEST_DYN_LINK
#endif

#ifndef BOOST_TEST_NO_MAIN
#define BOOST_TEST_NO_MAIN
#endif

#include <boost/test/unit_test.hpp>
#include <boost/test/output_test_stream.hpp>

#define BOOST_TEST_MODULE Connection_test


BOOST_AUTO_TEST_SUITE(Connection_test)

    BOOST_AUTO_TEST_CASE(Connection_construction__test) {

       ***
    }

BOOST_AUTO_TEST_SUITE_END()

And I'm compiling every module as a single executable.

I wanted to use CodeCoverage.cmake module to run code-coverage analysis, but I ran into a problem. I'm supposed to specify a test executable by SETUP_TARGET_FOR_COVERAGE_LCOV, but I don't have only one.

Is there any way to setup multiple test executables at once with CodeCoverage.cmake?


EDIT

I've added tests by add_test() into my root CMakeLists.txt and modified my coverage target like this

include(CTest)
add_test(NAME constant_neuron_test COMMAND constant_neuron_test)
add_test(NAME binary_neuron_test COMMAND binary_neuron_test)
add_test(NAME logistic_neuron_test COMMAND logistic_neuron_test)
add_test(NAME connectionFunctionGeneral_test COMMAND connectionFunctionGeneral_test)
add_test(NAME connection_Function_identity_test COMMAND connection_Function_identity_test)
add_test(NAME neural_network_test COMMAND neural_network_test)
add_test(NAME dataset_test COMMAND dataset_test)
add_test(NAME particle_swarm_test COMMAND particle_swarm_test)
add_test(NAME particle_test COMMAND particle_test)
add_test(NAME NeuralNetworkSum_test COMMAND NeuralNetworkSum_test)
add_test(NAME errorfunction_test COMMAND errorfunction_test)
add_test(NAME DESolver_test COMMAND DESolver_test)

include(CodeCoverage.cmake)
APPEND_COVERAGE_COMPILER_FLAGS()
SETUP_TARGET_FOR_COVERAGE_LCOV(
        NAME coverage                 # New target name
        EXECUTABLE ctest -C ${ROOT_DIR}/CTestTestfile.cmake # Executable in PROJECT_BINARY_DIR
        DEPENDENCIES ${Boost_LIBRARIES}         # Dependencies to build first
)

ctest itself runs correctly:

Test project /home/martin/4Neuro
      Start  1: constant_neuron_test
 1/12 Test  #1: constant_neuron_test ................   Passed    0.04 sec
      Start  2: binary_neuron_test
 2/12 Test  #2: binary_neuron_test ..................   Passed    0.04 sec
      Start  3: logistic_neuron_test
 3/12 Test  #3: logistic_neuron_test ................   Passed    0.05 sec
      Start  4: connectionFunctionGeneral_test
 4/12 Test  #4: connectionFunctionGeneral_test ......   Passed    0.04 sec
      Start  5: connection_Function_identity_test
 5/12 Test  #5: connection_Function_identity_test ...   Passed    0.04 sec
      Start  6: neural_network_test
 6/12 Test  #6: neural_network_test .................   Passed    0.04 sec
      Start  7: dataset_test
 7/12 Test  #7: dataset_test ........................   Passed    0.04 sec
      Start  8: particle_swarm_test
 8/12 Test  #8: particle_swarm_test .................   Passed    0.04 sec
      Start  9: particle_test
 9/12 Test  #9: particle_test .......................   Passed    0.04 sec
      Start 10: NeuralNetworkSum_test
10/12 Test #10: NeuralNetworkSum_test ...............   Passed    0.05 sec
      Start 11: errorfunction_test
11/12 Test #11: errorfunction_test ..................   Passed    0.04 sec
      Start 12: DESolver_test
12/12 Test #12: DESolver_test .......................   Passed    0.05 sec

100% tests passed, 0 tests failed out of 12

Total Test time (real) =   0.53 sec

But when I try to create my coverage report by make coverage, I get this error:

Processing code coverage counters and generating report.
cd /home/martin/4Neuro/build && /usr/bin/lcov --gcov-tool /usr/bin/gcov -directory . --zerocounters
Deleting all .da files in . and subdirectories
Done.
cd /home/martin/4Neuro/build && /usr/bin/lcov --gcov-tool /usr/bin/gcov -c -i -d . -o coverage.base
Capturing coverage data from .
Found gcov version: 7.3.0
Scanning . for .gcno files ...
geninfo: WARNING: no .gcno files found in . - skipping!
Finished .info-file creation
cd /home/martin/4Neuro/build && ctest -C /home/martin/4Neuro/CTestTestfile.cmake
Test project /home/martin/4Neuro/build
No tests were found!!!
cd /home/martin/4Neuro/build && /usr/bin/lcov --gcov-tool /usr/bin/gcov --directory . --capture --output-file coverage.info
Capturing coverage data from .
Found gcov version: 7.3.0
Scanning . for .gcda files ...
geninfo: WARNING: no .gcda files found in . - skipping!
Finished .info-file creation
cd /home/martin/4Neuro/build && /usr/bin/lcov --gcov-tool /usr/bin/gcov -a coverage.base -a coverage.info --output-file coverage.total
Combining tracefiles.
Reading tracefile coverage.base
lcov: ERROR: no valid records found in tracefile coverage.base
CMakeFiles/coverage.dir/build.make:62: recipe for target 'CMakeFiles/coverage' failed
make[3]: *** [CMakeFiles/coverage] Error 255
make[3]: Leaving directory '/home/martin/4Neuro'
CMakeFiles/Makefile2:70: recipe for target 'CMakeFiles/coverage.dir/all' failed
make[2]: *** [CMakeFiles/coverage.dir/all] Error 2
make[2]: Leaving directory '/home/martin/4Neuro'
CMakeFiles/Makefile2:77: recipe for target 'CMakeFiles/coverage.dir/rule' failed
make[1]: *** [CMakeFiles/coverage.dir/rule] Error 2
make[1]: Leaving directory '/home/martin/4Neuro'
Makefile:132: recipe for target 'coverage' failed
make: *** [coverage] Error 2

EDIT 2

I've modified my CMakeLists.txt like this

include(CTest)
enable_testing()
add_subdirectory(${SRC_DIR} ${PROJECT_BINARY_DIR})

# Adding Unit-tests
add_test(NAME constant_neuron_test COMMAND constant_neuron_test)
add_test(NAME binary_neuron_test COMMAND binary_neuron_test)
add_test(NAME logistic_neuron_test COMMAND logistic_neuron_test)
add_test(NAME connectionFunctionGeneral_test COMMAND connectionFunctionGeneral_test)
add_test(NAME connection_Function_identity_test COMMAND connection_Function_identity_test)
add_test(NAME neural_network_test COMMAND neural_network_test)
add_test(NAME dataset_test COMMAND dataset_test)
add_test(NAME particle_swarm_test COMMAND particle_swarm_test)
add_test(NAME particle_test COMMAND particle_test)
add_test(NAME NeuralNetworkSum_test COMMAND NeuralNetworkSum_test)
add_test(NAME errorfunction_test COMMAND errorfunction_test)
add_test(NAME DESolver_test COMMAND DESolver_test)

include(CodeCoverage.cmake)
APPEND_COVERAGE_COMPILER_FLAGS()
SETUP_TARGET_FOR_COVERAGE_LCOV(
        NAME coverage                 # New target name
        EXECUTABLE ctest -j ${n_cores} # Executable in PROJECT_BINARY_DIR
        DEPENDENCIES
            constant_neuron_test
            binary_neuron_test
            logistic_neuron_test
            connectionFunctionGeneral_test
            connection_Function_identity_test
            neural_network_test
            dataset_test
            particle_swarm_test
            particle_test
            NeuralNetworkSum_test
            errorfunction_test
            DESolver_test         # Dependencies to build first
)
set(COVERAGE_EXCLUDES 'external_dependencies/*')

But, unfortunately, the error persists

cd /home/martin/4Neuro/build && /usr/bin/lcov --gcov-tool /usr/bin/gcov -c -i -d . -o coverage.base
Capturing coverage data from .
Found gcov version: 7.3.0
Scanning . for .gcno files ...
geninfo: WARNING: no .gcno files found in . - skipping!
Finished .info-file creation
cd /home/martin/4Neuro/build && ctest -j 3
Test project /home/martin/4Neuro/build
No tests were found!!!
cd /home/martin/4Neuro/build && /usr/bin/lcov --gcov-tool /usr/bin/gcov --directory . --capture --output-file coverage.info
Capturing coverage data from .
Found gcov version: 7.3.0
Scanning . for .gcda files ...
geninfo: WARNING: no .gcda files found in . - skipping!
Finished .info-file creation
cd /home/martin/4Neuro/build && /usr/bin/lcov --gcov-tool /usr/bin/gcov -a coverage.base -a coverage.info --output-file coverage.total
Combining tracefiles.
Reading tracefile coverage.base
lcov: ERROR: no valid records found in tracefile coverage.base
CMakeFiles/coverage.dir/build.make:71: recipe for target 'CMakeFiles/coverage' failed
make[3]: *** [CMakeFiles/coverage] Error 255
make[3]: Leaving directory '/home/martin/4Neuro'
CMakeFiles/Makefile2:81: recipe for target 'CMakeFiles/coverage.dir/all' failed
make[2]: *** [CMakeFiles/coverage.dir/all] Error 2
make[2]: Leaving directory '/home/martin/4Neuro'
CMakeFiles/Makefile2:88: recipe for target 'CMakeFiles/coverage.dir/rule' failed
make[1]: *** [CMakeFiles/coverage.dir/rule] Error 2
make[1]: Leaving directory '/home/martin/4Neuro'
Makefile:132: recipe for target 'coverage' failed
make: *** [coverage] Error 2
Ottava answered 10/9, 2018 at 10:16 Comment(11)
You can use ctest as the executable. It will run your unit test.Afraid
It seems that although the argument is declared as a multivalue argument, the further processing uses the first name provided to EXECUTABLE. Maybe you can just use the SETUP_TARGET_FOR_COVERAGE_LCOV command as many times as your test executables; each coverage target will get a different name. Not sure what happens with the results, but I'd guess they get combined (haven't used this module).Elitism
@Afraid I've tried to use ctest, as you suggested. It doesn't work so far - see my Edit, please.Ottava
@Elitism I'm afraid they'll not get combined, as you're supposed to make one after another if I understand it correctly.Ottava
In my project I have it EXECUTABLE ctest -j ${PROCESSOR_COUNT} and it picks two different unit test executables.Afraid
@Afraid And how do you list your test executables? Also using add_test() ?Ottava
@Afraid Unfortunately, mine still doesn't work... If you want to, you can have a look at Edit2Ottava
@Ottava have you found a solution to this issue? Im having the exact same error as you have in your "EDIT 2": No tests were found!!!; ctest runs fine.Foolish
@Foolish Unfortunately, I didn't and I stopped that project quite a while ago.Ottava
@Ottava I have managed to build a working setup. I posted it as an answer;Foolish
@Foolish Good job! ;)Ottava
F
3

I have managed to get a working setup that:

  1. Compiles debug and release code with different compiler flags
  2. Runs tests
  3. Creates code coverage and branch coverage html report

Prerequisits

Boost:

sudo apt-get install libboost-all-dev

CMake 3.21.0: (Go to https://cmake.org/download/ for latest)

sudo apt install build-essential libssl-dev
wget https://github.com/Kitware/CMake/releases/download/v3.21.0/cmake-3.21.0.tar.gz
tar -zxvf cmake-3.21.0.tar.gz
cd cmake-3.21.0
./bootstrap
make 
sudo make install 

Setup

Folder structure:

┌ mhcl
├──┬ build
│  ├── debug
│  └── release
├──┬ src
│  ├──┬ biginteger
│  │  ├── biginteger.cpp
│  │  └── biginteger.h
│  ├── CMakeLists.txt
│  └── main.cpp
├──┬ test
│  ├── CMakeLists.txt
│  ├── CodeCoverage.cmake
│  ├── test_biginteger_add.cpp
│  ├── test_biginteger_constructor.cpp
│  ├── test_biginteger_divide.cpp
│  └── test_biginteger_multiply.cpp
└── CMakeLists.txt

src/biginteger/biginteger.cpp:

...
void BigInteger::add(const BigInteger &summand2){
    if(isNegative() == summand2.isNegative()){
        add_digits(summand2);
    }else{
        subtract_digits(summand2);
    }
    if(getNumber(false) == "0") setNegative(false);
}
...

src/biginteger/biginteger.h:

#ifndef BIGINTEGER_H_INCLUDED
#define BIGINTEGER_H_INCLUDED

#include <iostream>
#include <string>
#include <algorithm>
#include <cstring>
#include <stdexcept>

class BigInteger{

    public:
        BigInteger(const char*);
...

mhcl/CMakeLists.txt:

cmake_minimum_required(VERSION 3.20)
add_compile_options(-Wall -Wextra -pedantic -Werror)
project(MHCL VERSION 0.1 DESCRIPTION "mhcl, a cryptographic library" LANGUAGES CXX)

set(CMAKE_CXX_FLAGS_DEBUG "-g -O0 -fprofile-arcs -ftest-coverage")
set(CMAKE_CXX_FLAGS_RELEASE "-O2")

add_subdirectory(test)
add_subdirectory(src) 
add_executable (demo src/main.cpp)
target_link_libraries (demo biginteger)

mhcl/src/CMakeLists.txt:

add_library(biginteger biginteger/biginteger.cpp biginteger/biginteger.h)

mhcl/src/main.cpp:

#include <iostream>
#include <string>
#include "biginteger/biginteger.h"
// this file is not really necessary for testing
int main(){
    BigInteger b("3");
    return 0;
}

mhcl/test/CMakeLists.txt:

IF(CMAKE_BUILD_TYPE MATCHES Debug)
    find_package (Boost COMPONENTS system filesystem unit_test_framework REQUIRED) # sudo apt-get install libboost-all-dev
    include_directories (${MHCL_SOURCE_DIR}/src ${Boost_INCLUDE_DIRS})

    add_executable (test_biginteger_constructor test_biginteger_constructor.cpp)
    target_link_libraries (test_biginteger_constructor biginteger ${Boost_FILESYSTEM_LIBRARY} ${Boost_SYSTEM_LIBRARY} ${Boost_UNIT_TEST_FRAMEWORK_LIBRARY})

    add_executable (test_biginteger_add test_biginteger_add.cpp)
    target_link_libraries (test_biginteger_add biginteger ${Boost_FILESYSTEM_LIBRARY} ${Boost_SYSTEM_LIBRARY} ${Boost_UNIT_TEST_FRAMEWORK_LIBRARY})

    add_executable (test_biginteger_multiply test_biginteger_multiply.cpp)
    target_link_libraries (test_biginteger_multiply biginteger ${Boost_FILESYSTEM_LIBRARY} ${Boost_SYSTEM_LIBRARY} ${Boost_UNIT_TEST_FRAMEWORK_LIBRARY})

    add_executable (test_biginteger_divide test_biginteger_divide.cpp)
    target_link_libraries (test_biginteger_divide biginteger ${Boost_FILESYSTEM_LIBRARY} ${Boost_SYSTEM_LIBRARY} ${Boost_UNIT_TEST_FRAMEWORK_LIBRARY})

    include(CTest)
    enable_testing()

    add_test(NAME test_biginteger_constructor COMMAND test_biginteger_constructor)
    add_test(NAME test_biginteger_add COMMAND test_biginteger_add)
    add_test(NAME test_biginteger_multiply COMMAND test_biginteger_multiply)
    add_test(NAME test_biginteger_divide COMMAND test_biginteger_divide)

    include(CodeCoverage.cmake)
    APPEND_COVERAGE_COMPILER_FLAGS()
    setup_target_for_coverage_gcovr_html(NAME coverage EXECUTABLE ctest --schedule-random -j 4 --test-dir test EXCLUDE "/usr/*" "/mnt/v/r3dapple.github.io/encryption/mhcl/test/*" "/mnt/v/r3dapple.github.io/encryption/mhcl/src/main.cpp" DEPENDENCIES test_biginteger_constructor test_biginteger_add test_biginteger_multiply test_biginteger_divide)
ENDIF()

mhcl/test/CodeCoverage.cmake:

https://github.com/bilke/cmake-modules/blob/master/CodeCoverage.cmake

mhcl/test_biginteger_add.cpp:

#define BOOST_TEST_MODULE BigIntegerTestAdd
#include <boost/test/unit_test.hpp>
#include "../src/biginteger/biginteger.h"

BOOST_AUTO_TEST_SUITE(IDENTITY_ELEMENT)
BOOST_AUTO_TEST_CASE(ADDITION_ZERO_LENGTH1_184_LENGTH2_1_SIGN1_PLUS_SIGN2_PLUS)
{
    BigInteger b("7941336097231331222328305438625646002846406186146402399842122390970234239963370898300943198440768677925436553855703282917116959906917075742261367262117888460342170898243453976126509330");
    b.add("0");
    BOOST_CHECK_EQUAL(b.getNumber(), "7941336097231331222328305438625646002846406186146402399842122390970234239963370898300943198440768677925436553855703282917116959906917075742261367262117888460342170898243453976126509330");
}
BOOST_AUTO_TEST_SUITE_END()
...

Usage

Build debug:

cd mhcl/build/debug && cmake -DCMAKE_BUILD_TYPE=Debug ../.. && make && make coverage

Your coverage report is under mhcl/build/debug/coverage/index.html gcov coverage

Build release:

cd mhcl/build/release && cmake -DCMAKE_BUILD_TYPE=Release ../.. && make
Foolish answered 17/7, 2021 at 17:40 Comment(0)
S
7

I had this problem too and struggled for quite awhile to find a solution. For me the fix was to move this CMake code above any other targets that are defined:

include(CodeCoverage.cmake)
APPEND_COVERAGE_COMPILER_FLAGS()

It looks like if it the targets are defined first then the compiler flags are not updated.

Saguache answered 26/4, 2019 at 23:14 Comment(0)
A
5

Ok, I tried to reproduce a minimal set of your setup.

I have:

.
├── CMakeLists.txt
├── CodeCoverage.cmake
├── test1.cpp
└── test2.cpp

Where CodeCoverage.cmake comes from https://github.com/bilke/cmake-modules/blob/master/CodeCoverage.cmake

CMakeLists.txt is:

cmake_minimum_required(VERSION 3.10)
find_package(Boost COMPONENTS system filesystem unit_test_framework REQUIRED)
include(CTest)
enable_testing()

add_executable(test1_test test1.cpp)
target_link_libraries(test1_test 
                      ${Boost_FILESYSTEM_LIBRARY}
                      ${Boost_SYSTEM_LIBRARY}
                      ${Boost_UNIT_TEST_FRAMEWORK_LIBRARY})
add_executable(test2_test test2.cpp)
target_link_libraries(test2_test
                      ${Boost_FILESYSTEM_LIBRARY}
                      ${Boost_SYSTEM_LIBRARY}
                      ${Boost_UNIT_TEST_FRAMEWORK_LIBRARY})

add_test(NAME test1_test COMMAND test1_test)
add_test(NAME test2_test COMMAND test2_test)

include(CodeCoverage.cmake)
APPEND_COVERAGE_COMPILER_FLAGS()
SETUP_TARGET_FOR_COVERAGE_LCOV(
        NAME coverage                 
        EXECUTABLE ctest -j ${n_cores} # Executable in PROJECT_BINARY_DIR
        DEPENDENCIES
            test1_test
            test2_test)

And test1.cpp (and test2.cpp) are

#define BOOST_TEST_MODULE test1

#ifndef BOOST_TEST_DYN_LINK
#define BOOST_TEST_DYN_LINK
#endif

#define BOOST_TEST_MAIN

#include <boost/test/unit_test.hpp>
#include <boost/test/output_test_stream.hpp>

#define BOOST_TEST_MODULE test1


BOOST_AUTO_TEST_SUITE(test1)

    BOOST_AUTO_TEST_CASE(test1__test) {
        BOOST_CHECK_EQUAL(1, 1);
    }

BOOST_AUTO_TEST_SUITE_END()

Now I do:

mkdir build
cd build
cmake ..

the output is:

-- The C compiler identification is GNU 7.3.0
-- The CXX compiler identification is GNU 7.3.0
-- Check for working C compiler: /usr/bin/cc
-- Check for working C compiler: /usr/bin/cc -- works
-- Detecting C compiler ABI info
-- Detecting C compiler ABI info - done
-- Detecting C compile features
-- Detecting C compile features - done
-- Check for working CXX compiler: /usr/bin/c++
-- Check for working CXX compiler: /usr/bin/c++ -- works
-- Detecting CXX compiler ABI info
-- Detecting CXX compiler ABI info - done
-- Detecting CXX compile features
-- Detecting CXX compile features - done
-- Boost version: 1.65.1
-- Found the following Boost libraries:
--   system
--   filesystem
--   unit_test_framework
CMake Warning at CodeCoverage.cmake:116 (message):
  Code coverage results with an optimised (non-Debug) build may be misleading
Call Stack (most recent call first):
  CMakeLists.txt:20 (include)


-- Appending code coverage compiler flags: -g -O0 --coverage -fprofile-arcs -ftest-coverage
-- Configuring done
-- Generating done
-- Build files have been written to: /home/jsantand/t/build

Finally running make coverage:

Scanning dependencies of target test1_test
[ 20%] Building CXX object CMakeFiles/test1_test.dir/test1.cpp.o
[ 40%] Linking CXX executable test1_test
[ 40%] Built target test1_test
Scanning dependencies of target test2_test
[ 60%] Building CXX object CMakeFiles/test2_test.dir/test2.cpp.o
[ 80%] Linking CXX executable test2_test
[ 80%] Built target test2_test
Scanning dependencies of target coverage
[100%] Resetting code coverage counters to zero.
Processing code coverage counters and generating report.
Deleting all .da files in . and subdirectories
Done.
Capturing coverage data from .
Found gcov version: 7.3.0
Scanning . for .gcno files ...
Found 2 graph files in .
Processing test1_test.dir/test1.cpp.gcno
Processing test2_test.dir/test2.cpp.gcno
Finished .info-file creation
Test project /home/jsantand/t/build
    Start 1: test1_test
1/2 Test #1: test1_test .......................   Passed    0.01 sec
    Start 2: test2_test
2/2 Test #2: test2_test .......................   Passed    0.01 sec

100% tests passed, 0 tests failed out of 2

Total Test time (real) =   0.02 sec
Capturing coverage data from .
Found gcov version: 7.3.0
Scanning . for .gcda files ...
Found 2 data files in .
Processing test1_test.dir/test1.cpp.gcda
Processing test2_test.dir/test2.cpp.gcda
Finished .info-file creation
Combining tracefiles.
Reading tracefile coverage.base
Reading tracefile coverage.info
Writing data to coverage.total
Summary coverage rate:
  lines......: 65.4% (229 of 350 lines)
  functions..: 68.3% (110 of 161 functions)
  branches...: no data found
Reading tracefile coverage.total
Deleted 0 files
Writing data to /home/jsantand/t/build/coverage.info.cleaned
Summary coverage rate:
  lines......: 65.4% (229 of 350 lines)
  functions..: 68.3% (110 of 161 functions)
  branches...: no data found
Reading data file /home/jsantand/t/build/coverage.info.cleaned
Found 37 entries.
Found common filename prefix "/usr/include"
Writing .css and .png files.
Generating output.
Processing file /home/jsantand/t/test1.cpp
Processing file /home/jsantand/t/test2.cpp
Processing file boost/type_index.hpp
Processing file boost/function/function_base.hpp
Processing file boost/function/function_template.hpp
Processing file boost/smart_ptr/shared_ptr.hpp
Processing file boost/smart_ptr/detail/sp_counted_base_std_atomic.hpp
Processing file boost/smart_ptr/detail/shared_count.hpp
Processing file boost/test/unit_test_suite.hpp
Processing file boost/test/unit_test.hpp
Processing file boost/test/unit_test_log.hpp
Processing file boost/test/tools/assertion_result.hpp
Processing file boost/test/tools/detail/print_helper.hpp
Processing file boost/test/tools/detail/fwd.hpp
Processing file boost/test/tools/old/impl.hpp
Processing file boost/test/tree/observer.hpp
Processing file boost/test/tree/test_unit.hpp
Processing file boost/test/tree/fixture.hpp
Processing file boost/test/tree/decorator.hpp
Processing file boost/test/utils/lazy_ostream.hpp
Processing file boost/test/utils/class_properties.hpp
Processing file boost/test/utils/trivial_singleton.hpp
Processing file boost/test/utils/wrap_stringstream.hpp
Processing file boost/test/utils/basic_cstring/bcs_char_traits.hpp
Processing file boost/test/utils/basic_cstring/basic_cstring.hpp
Processing file boost/type_index/type_index_facade.hpp
Processing file boost/type_index/stl_type_index.hpp
Processing file boost/type_traits/integral_constant.hpp
Processing file c++/7/typeinfo
Processing file c++/7/bits/ios_base.h
Processing file c++/7/bits/move.h
Processing file c++/7/bits/alloc_traits.h
Processing file c++/7/bits/stl_construct.h
Processing file c++/7/bits/stl_vector.h
Processing file c++/7/bits/atomic_base.h
Processing file c++/7/bits/allocator.h
Processing file c++/7/ext/new_allocator.h
Writing directory view page.
Overall coverage rate:
  lines......: 65.4% (229 of 350 lines)
  functions..: 68.3% (110 of 161 functions)
Lcov code coverage info report saved in coverage.info.
Open ./coverage/index.html in your browser to view the coverage report.
[100%] Built target coverage
Afraid answered 10/9, 2018 at 12:15 Comment(1)
Thank you very much! I have no idea, why my code still doesn't work, when it's basically the same as this one. Would you mind to look at my code ([email protected]:bes0030/4Neuro.git, branch coverage, basic compilation with build.sh) ? I'm curious if it will run on your computer.Ottava
F
3

I have managed to get a working setup that:

  1. Compiles debug and release code with different compiler flags
  2. Runs tests
  3. Creates code coverage and branch coverage html report

Prerequisits

Boost:

sudo apt-get install libboost-all-dev

CMake 3.21.0: (Go to https://cmake.org/download/ for latest)

sudo apt install build-essential libssl-dev
wget https://github.com/Kitware/CMake/releases/download/v3.21.0/cmake-3.21.0.tar.gz
tar -zxvf cmake-3.21.0.tar.gz
cd cmake-3.21.0
./bootstrap
make 
sudo make install 

Setup

Folder structure:

┌ mhcl
├──┬ build
│  ├── debug
│  └── release
├──┬ src
│  ├──┬ biginteger
│  │  ├── biginteger.cpp
│  │  └── biginteger.h
│  ├── CMakeLists.txt
│  └── main.cpp
├──┬ test
│  ├── CMakeLists.txt
│  ├── CodeCoverage.cmake
│  ├── test_biginteger_add.cpp
│  ├── test_biginteger_constructor.cpp
│  ├── test_biginteger_divide.cpp
│  └── test_biginteger_multiply.cpp
└── CMakeLists.txt

src/biginteger/biginteger.cpp:

...
void BigInteger::add(const BigInteger &summand2){
    if(isNegative() == summand2.isNegative()){
        add_digits(summand2);
    }else{
        subtract_digits(summand2);
    }
    if(getNumber(false) == "0") setNegative(false);
}
...

src/biginteger/biginteger.h:

#ifndef BIGINTEGER_H_INCLUDED
#define BIGINTEGER_H_INCLUDED

#include <iostream>
#include <string>
#include <algorithm>
#include <cstring>
#include <stdexcept>

class BigInteger{

    public:
        BigInteger(const char*);
...

mhcl/CMakeLists.txt:

cmake_minimum_required(VERSION 3.20)
add_compile_options(-Wall -Wextra -pedantic -Werror)
project(MHCL VERSION 0.1 DESCRIPTION "mhcl, a cryptographic library" LANGUAGES CXX)

set(CMAKE_CXX_FLAGS_DEBUG "-g -O0 -fprofile-arcs -ftest-coverage")
set(CMAKE_CXX_FLAGS_RELEASE "-O2")

add_subdirectory(test)
add_subdirectory(src) 
add_executable (demo src/main.cpp)
target_link_libraries (demo biginteger)

mhcl/src/CMakeLists.txt:

add_library(biginteger biginteger/biginteger.cpp biginteger/biginteger.h)

mhcl/src/main.cpp:

#include <iostream>
#include <string>
#include "biginteger/biginteger.h"
// this file is not really necessary for testing
int main(){
    BigInteger b("3");
    return 0;
}

mhcl/test/CMakeLists.txt:

IF(CMAKE_BUILD_TYPE MATCHES Debug)
    find_package (Boost COMPONENTS system filesystem unit_test_framework REQUIRED) # sudo apt-get install libboost-all-dev
    include_directories (${MHCL_SOURCE_DIR}/src ${Boost_INCLUDE_DIRS})

    add_executable (test_biginteger_constructor test_biginteger_constructor.cpp)
    target_link_libraries (test_biginteger_constructor biginteger ${Boost_FILESYSTEM_LIBRARY} ${Boost_SYSTEM_LIBRARY} ${Boost_UNIT_TEST_FRAMEWORK_LIBRARY})

    add_executable (test_biginteger_add test_biginteger_add.cpp)
    target_link_libraries (test_biginteger_add biginteger ${Boost_FILESYSTEM_LIBRARY} ${Boost_SYSTEM_LIBRARY} ${Boost_UNIT_TEST_FRAMEWORK_LIBRARY})

    add_executable (test_biginteger_multiply test_biginteger_multiply.cpp)
    target_link_libraries (test_biginteger_multiply biginteger ${Boost_FILESYSTEM_LIBRARY} ${Boost_SYSTEM_LIBRARY} ${Boost_UNIT_TEST_FRAMEWORK_LIBRARY})

    add_executable (test_biginteger_divide test_biginteger_divide.cpp)
    target_link_libraries (test_biginteger_divide biginteger ${Boost_FILESYSTEM_LIBRARY} ${Boost_SYSTEM_LIBRARY} ${Boost_UNIT_TEST_FRAMEWORK_LIBRARY})

    include(CTest)
    enable_testing()

    add_test(NAME test_biginteger_constructor COMMAND test_biginteger_constructor)
    add_test(NAME test_biginteger_add COMMAND test_biginteger_add)
    add_test(NAME test_biginteger_multiply COMMAND test_biginteger_multiply)
    add_test(NAME test_biginteger_divide COMMAND test_biginteger_divide)

    include(CodeCoverage.cmake)
    APPEND_COVERAGE_COMPILER_FLAGS()
    setup_target_for_coverage_gcovr_html(NAME coverage EXECUTABLE ctest --schedule-random -j 4 --test-dir test EXCLUDE "/usr/*" "/mnt/v/r3dapple.github.io/encryption/mhcl/test/*" "/mnt/v/r3dapple.github.io/encryption/mhcl/src/main.cpp" DEPENDENCIES test_biginteger_constructor test_biginteger_add test_biginteger_multiply test_biginteger_divide)
ENDIF()

mhcl/test/CodeCoverage.cmake:

https://github.com/bilke/cmake-modules/blob/master/CodeCoverage.cmake

mhcl/test_biginteger_add.cpp:

#define BOOST_TEST_MODULE BigIntegerTestAdd
#include <boost/test/unit_test.hpp>
#include "../src/biginteger/biginteger.h"

BOOST_AUTO_TEST_SUITE(IDENTITY_ELEMENT)
BOOST_AUTO_TEST_CASE(ADDITION_ZERO_LENGTH1_184_LENGTH2_1_SIGN1_PLUS_SIGN2_PLUS)
{
    BigInteger b("7941336097231331222328305438625646002846406186146402399842122390970234239963370898300943198440768677925436553855703282917116959906917075742261367262117888460342170898243453976126509330");
    b.add("0");
    BOOST_CHECK_EQUAL(b.getNumber(), "7941336097231331222328305438625646002846406186146402399842122390970234239963370898300943198440768677925436553855703282917116959906917075742261367262117888460342170898243453976126509330");
}
BOOST_AUTO_TEST_SUITE_END()
...

Usage

Build debug:

cd mhcl/build/debug && cmake -DCMAKE_BUILD_TYPE=Debug ../.. && make && make coverage

Your coverage report is under mhcl/build/debug/coverage/index.html gcov coverage

Build release:

cd mhcl/build/release && cmake -DCMAKE_BUILD_TYPE=Release ../.. && make
Foolish answered 17/7, 2021 at 17:40 Comment(0)
S
1

In CMake the order of your statements matters, and the order you should place them is not always straightforward. In case someone else still needs an answer to this, try this at the beginning of your root CMakeLists.txt, after the definition of your compiler properties. For example:

include(CTest)
enable_testing()
set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${PROJECT_SOURCE_DIR}/cmake")

include(CodeCoverage)
append_coverage_compiler_flags()
setup_target_for_coverage_gcovr_html(
    NAME coverage
    EXECUTABLE test_basics
    DEPENDENCIES test_basics mysqrt
)

Assumes your CodeCoverage.cmake lives under the cmake directory in your project. To generate a test coverage report:

mkdir build
cd build
cmake -DCMAKE_BUILD_TYPE:STRING=Debug
make coverage

Your report will be available under ./coverage/index.html.

Spousal answered 28/12, 2020 at 2:22 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.