First, as a team, review the test cases and the code and determine if you got 100% code coverage or not and if any of the test cases are not unique and cover the same code. Do not spend much time on this, as you pretty much said so with your previous exercise result.
Second, we are going to use cmake
to generate a Makefile instead of creating one directly. That is going to make it easier for changing the build. To convert, go to GitHub and accept the pull request. Once done, all of you will have to do a git pull
to get these changes into your code.
To prepare for the build:
cmake
from the build directory referencing the CMakeLists.txt in the parent directory.
You will build and run the program from the build directory. You will edit the files of the project in the parent directory.
The following assumes you are in your build directory.
The tool gcov
can, with code compiled with the appropriate flags, produce a report that shows precisely how many times each line of code is called in a run of the program, and from that, we can get code coverage. So, we want to run the gcov
program with our test program and see the code coverage of the function dotProduct()
in the file dotProduct.cpp .
Note: Once you run cmake referencing the source directory, i.e., cmake ..
, it remembers the source directory and you can then just reference the build directory, i.e., cmake .
. This is nice because your build directory might not be a subdirectory of your source, and the commands still work. However, you do have to reference the source directory, i.e., cmake ..
, the first time.
To produce the gcov
report, do the following:
cmake
to add the option --coverage
to the flags provided to the compiler:
The CMake variable CMAKE_CXX_FLAGS
is the option passed to the compiler.cmake
so that make
will output the commands it is executing (instead of hiding them from you):
The CMake variable CMAKE_MAKE_VERBOSE
controls whether make
will show the commands it uses to build the program. Note: ninja
will not work here. This is one exception to ninja
being a drop-in replacement for make
.
Note that cmake
caches its settings. They are in the file CMakeCache.txt. This is why the previous CMAKE_CXX_FLAGS
setting still holds.--coverage
.
Record in your notes the command line for the compile up to the first argument after the --coverage
.CMAKE_VERBOSE_MAKEFILE
as it is annoying getting that much output with every make
command:gcov
to get the report.
Carefully view the output of the program to find where dotProduct.cpp is and the line that starts with Lines executed:
. You can safely rerun this command. You will then see how much code coverage your test program produced. Record in your notes this percentage.
You should find a file dotProduct.cpp.gcov in your build directory..gcda
and .gcno
files. A command to do this is (I strongly recommend copy and paste):
View the file dotProduct.cpp.gcov in an editor. You will see lines such as:
Columns are separated by ":". Column 2 is the line number, and Column 3 is the source code. Column 1 is the number of times that line of code was executed, or a -
if it is not an executable line (i.e., comment or whitespace). If you see a #####
, that means that that line of code was never executed. So, therefore, you do not have 100% code coverage.
Correctly rerunning all of the above commands is repetitive and open to mistakes. So let's automate it by taking the above lines and making them targets in our CMake. Add the following code at the end of your CMakeLists.txt file.
Commit this change to the repository with the commit message:
Any time you make changes to the cmake
file CMakeLists.txt, rerun cmake:
Now, the sequence to run the coverage for the tests is the following:
To fix this problem, you will have to change the file dotProduct.cpp. Look carefully at the lines of code that were not executed, any conditional statements that had to be true to reach that unexecuted line, and your test cases.
The change to dotProduct.cpp is to rearrange some lines. Make this change, build the program, run the test program, and make sure the tests still pass. If the tests all pass, commit the change to the file dotProduct.cpp:
Now, rerun the coverage using our new make
targets. Continue making changes to your test cases until you get 100% code coverage. Record in your notes any additional test cases.
This sequence is more complex than it needs to be:
If the build file would run the target coverage-clean
before every test, then we would not have to remember to do so. Any knowledge we can put into the build file make
s everything easier to repeat. So change the test
target the CMakeLists.txt so that it DEPENDS
on the target coverage-clean
:
Since CMakeLists.txt changed, rerun cmake
.
Now, the new sequence of commands is:
An even further automation is to automatically run the target test
whenever you run the target coverage-report
. So running a new report is one command. See if you can get this working.
Commit these automation changes to the repository:
Using the coverage, find the percentage of the code in dotProduct.cpp covered by each test case. Do this by commenting out all but one test case at a time and then running a coverage report. Record in your notes the new percentages and how they compare to what you manually calculated.