Generating Code Coverage Report For Cross-Compilation Project with Conan, CMake, and GTest

Van C. Ngo · February 2, 2020

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:

  1. Developing the software as the design documents,
  2. Writing unit test cases to check the functionality of the code implementation,
  3. Using these test cases to check the possible code coverage, and
  4. 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.

Thumper

Thumper

Thumper

Code

The example project can be obtained at cross-cov-gtest.