In this post, I will talk about a common approach for generating unit test code coverage report for cross-compilation, e.g. embedded programming, with the following tools:
- Conan
- CMake
- GTest
Introduction
Usually project development cycle will be the following steps:
- Developing the software as the design documents,
- Writing unit test cases to check the functionality of the code implementation,
- Using these test cases to check the possible code coverage, and
- Generating reports with the above and try to maximize the code coverage percentile by covering more test cases and hitting more lines of codes in the implementation.
Configurations
Assume that we are wiring embedded C/C++ code, especially, our target platform is QNX aarch64
, armv7
, or x86_64
. The build tools are Conan and CMake. The unit tests framework is Google test - GTest. This document talks about the step 4 above and explains how to write unit test with a simple example code, and how to set up GNU GCOV and LCOV and other required tools for generating reports.
The configurations of the build tools, unit framework are already provided in the attachments. Here, we are only interested in the step of generating code coverage report for QNX platform cross-compilation code.
Cross-Compilation Code Coverage
First, let’s say we want to write a simple program which gives you the biggest number of given three numbers as follows.
// greatestof3.h
#ifndef _GREATEST_OF_3_H
#define _GREATEST_OF_3_H
int GreatestOfThree(int a,int b,int c);
#endif // _GREATEST_OF_3_H
// greatestof3.cpp
#include <greatestof3.h>
#include<iostream>
using namespace std;
int GreatestOfThree(int a,int b,int c)
{
if((a>b) && (a>c))
{
//for a > b and a>c case
return a;
}
else if(b>c)
{
//for b>c case
return b;
}
else
{
return c;
}
return 0;
}
// main_test.cpp
#include "greatestof3.h"
#include "gtest/gtest.h"
TEST(GreaterTest,AisGreater)
{
EXPECT_EQ(3,GreatestOfThree(3,1,2));
};
TEST(GreaterTest,BisGreater)
{
EXPECT_EQ(3,GreatestOfThree(1,3,2));
};
TEST(GreaterTest,CisGreater)
{
EXPECT_EQ(3,GreatestOfThree(1,2,3));
};
int main(int argc,char**argv)
{
testing::InitGoogleTest(&argc, argv);
return RUN_ALL_TESTS();
}
Now, we will generate coverage report for the tests above. So, for this task we are using the tool, called GCOV. Usually, it will come with GCC-based compilers such as qcc and q++ inbuilt, so no need to install separately.
To use this tool, one must add flags -fprofile-arcs -ftest-coverage
into the compliation command. These flags will generate an executable with coverage flag enabled. Note that the flags are already added in the project configuration in the attachments. You can find it in the CMake compiler configuration file. In order to generate the code coverage, we perform the following steps.
Generating gcno Files
We compile the code with the following command to obtains the coverage flag information, the generated *.gcno
files in the build directory. As the compilation result, we also get the executable file of the tests, called greatestof3
.
# create a build directory
mkdir cross-cov-gtest
# compile the code to generate *.gcno files for QNX aarch64 platform
cmake -DCONAN_PROFILE=../cross-cov-gtest/profile/qnx-aarch64 -DCMAKE_TOOLCHAIN_FILE=../cross-cov-gtest/cmake/qnx-aarch64.cmake ../cross-cov-gtest
Running Tests on Target Platform
We will run the executable on the target platform to get the coverage information which is embedded in the generated *.gcda
files. Run the following command in QNX on the target platform.
# Stripping elements from the path found in the object files, use 9999 for sure because we don't know exactly how depth the build directory
GCOV_PREFIX_STRIP=9999 ./greatestof3
Transfer gcda Files to Host Machine
Nest step, we need to copy the generated *.gcda
files back to the build directory on the host machine. For example, if the main_test.gcno
file is in the directory $HOME/Working/mycode/c_c++/cross-cov-gtest/src
. Then copy the generated file main_test.gcda
into this directory.
Generate Code Coverage Reports
Go the build directory that contains the main_test.cpp
, e.g. $HOME/Working/mycode/c_c++/cross-cov-gtest/src
, run the following command.
# Generate code coverage for main_test in generated files *.gcov
gcov main_test
In the same directory, run the following command to generate code coverage in html format.
# Generate reports in html format
lcov --capture --directory . --output-file main_coverage.info
genhtml main_coverage.info --output-directory out
If you open the index.html file in the out directory. Then you can see something similar to the followings.
Code
The example project can be obtained at cross-cov-gtest.