When using unit-tests to add robustness to development projects, it is nice (even important) to be able to see which parts of your code is actually being tested.
If you are using
This creates a
The key is that when a program built with
This scribble is divided into three parts:
1. A general outline of the steps to create a clean coverage
report, which should apply to any
2. How I arrived at these steps (cheating a bit for brevity)
3. Finally I'll summarize the working script, an implementation of
the general outline.
The point of
First, a quick note on my
This completely separates the
I should also mention that my
rm -rf . /build export LDFLAGS= "-lgcov -fprofile-arcs" export CPPFLAGS= "-fprofile-arcs -ftest-coverage" nice scons -j6 --tests # --tests is a custom option that builds tests |
Let's skip
# Run tests for i in . /bin/tests/ * ; do $i ; done # Process coverage files lcov -c -d . /build -o coverage.run # Generate html report (make sure ./html folder exists) genhtml -o . /html/ coverage.run |
The result is quite messy. For some reason, it includes coverage
on
# Extract (-e) from coverage.run data from files in cwd lcov -e coverage.run "`pwd`/*" -o coverage.run.filtered genhtml -o . /html/ coverage.run.filtered |
Much better. It still incorrectly lists directories that don't
exist. Also, when browsing to the individual source files, it only shows
the error message
Turns out that
# Process coverage files lcov -b . -c -d . /build -o coverage.run # Extract (-e) from coverage.run data from files in cwd lcov -e coverage.run "`pwd`/*" -o coverage.run.filtered # Generate html report (make sure ./html folder exists) genhtml -o . /html/ coverage.run.filtered |
Almost there. Unit test files are still included in the coverage
report. Since these will always have
Above we extracted our project files, now let's further
remove all
# Remove (-r) from coverage.run.filtered all Test*.* files lcov -r coverage.run.filtered "`pwd`/*/Test*.*" -o coverage.run.filtered genhtml -o . /html/ coverage.run.filtered |
Only relevant data now. However, I know that there are several
files that are not tested at all, and don't show up. Even a whole
directory (
This is where
# Process *.gcno files lcov -b . -c -i -d . /build -o coverage.init # Run tests like before for i in . /bin/tests/ * ; do $i ; done # Process coverage from executed tests lcov -b . -c -d . /build -o coverage.run # Merge coverage.init and coverage.run lcov -a coverage.init -a coverage.run -o coverage.total # Filter like before, and also remove main.cpp lcov -e coverage.total "`pwd`/*" -o coverage.total.filtered lcov -r coverage.total.filtered "`pwd`/*/Test*.*" -o coverage.total.filtered lcov -r coverage.total.filtered "`pwd`/build/main.cpp" -o coverage.total.filtered genhtml -o . /html/ coverage.total.filtered |
Finally, it shows my hitherto sloppy test coverage in all earnestness.
The
sed 's/\/build\//\/src\//g' coverage.total.filtered > coverage.total.final genhtml -o . /html/ coverage.total.final |
That's right, a simple search-and-replace does the trick!
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 | #!/bin/bash # Step 1: Clean all build files rm -rf . /build # Step 2: Re-compile whole project, including tests export LDFLAGS= "-lgcov -fprofile-arcs" export CPPFLAGS= "-fprofile-arcs -ftest-coverage" nice scons -j6 --tests # Step 3: Generate initial coverage information lcov -b . -c -i -d . /build -o .coverage.wtest.base # Step 4: Run all tests: export LD_LIBRARY_PATH= $LD_LIBRARY_PATH : `pwd` /lib for i in . /bin/tests/ * ; do $i ; done # Step 5: Generate coverage based on executed tests lcov -b . -c -d . /build -o .coverage.wtest.run # Step 6: Merge coverage tracefiles lcov -a .coverage.wtest.base -a .coverage.wtest.run -o .coverage.total # Step 7: Filtering, extracting project files lcov -e .coverage.total "`pwd`/*" -o .coverage.total.filtered # Step 8: Filtering, removing test-files and main.cpp lcov -r .coverage.total.filtered "`pwd`/build/main.cpp" -o .coverage.total.filtered lcov -r .coverage.total.filtered "`pwd`/*/Test*.*" -o .coverage.total.filtered # Extra: Replace /build/ with /src/ to unify directories sed 's/\/build\//\/src\//g' .coverage.total.filtered > .coverage.total # Extra: Clear up previous data, create html folder if [[ -d . /html/ ]] ; then rm -rf . /html/ * else mkdir html fi # Step 9: Generate webpage genhtml -o . /html/ .coverage.total # Extra: Preserve coverage file in coveragehistory folder [[ -d . /coveragehistory/ ]] || mkdir coveragehistory cp .coverage.total . /coveragehistory/ `date +'%Y.%m.%d-coverage'` # Cleanup rm .coverage.* |
Note: As of