Using Code Coverage

You can use the code coverage tool to measure how many lines a particular process executes during a test or benchmark. This analysis task finds areas of code that were not covered by your test cases.



After you run code coverage, you can use the resulting analysis to create additional test cases that increase coverage. You can also use the analysis to determine a quantitative measure of code coverage, which is a direct measure of the quality of your tests. This means that if an area of code is not being covered by any test case, it could contain a bug that won’t be revealed.

Block coverage

The code coverage tool uses the gcov metrics that the gcc compiler produces. The IDE presents these metrics as line coverage, and shows which lines are fully covered, partially covered, and not covered at all. The IDE also presents percentages of coverage in terms of the actual code covered, and not just lines. Although the gcc compiler produces metrics for branch coverage, the IDE doesn't provide this information.

The coverage metrics provide basic block coverage, or line coverage, which describes whether a block of code is executed. A block of code does not have any branch point within it, so that the path of execution enters from the beginning and exits at the end.

The IDE tracks the number of times that the block of code has been executed, and uses this information to determine the total coverage for a particular file or function. It also uses this information to show line coverage by analyzing the blocks on each line and determining the level of coverage for each line.

How the coverage tool works

The code coverage tool works in conjunction with the compiler (gcc), the QNX C library (libc), and optionally the remote target agent (qconn). When code coverage is enabled for a program, the compiler instruments the code so that at run time, each branch execution to a basic block is counted. During the build, the IDE produces data files in order to recreate the program's flow graph and to provide line locations of each block.

CAUTION:
Since the IDE creates secondary data files at compilation time, you must be careful when building your programs in a multitargeted build environment, such as the QNX Neutrino.
You must either:
  • ensure that the last compiled binary is the one you're collecting coverage data on,

    or:

  • enable only one architecture and one variant (debug or release).

Note also that the compiler's optimizations could produce unexpected results, so you should perform coverage tests on an unoptimized, debug-enabled build.

When you build an application with the Build with Code Coverage build option enabled and then launch it using a C/C++ QNX Qconn (IP) launch configuration, the instrumented code linked into the process connects to qconn, allowing the coverage data to be read from the process's data space. However, if you launch a coverage-built process with coverage disabled in the launch configuration, this causes the process to write the coverage information to a data file (.gcda) at run time, rather than read it from the process's data space. Later, you can import the data into the code coverage tool. For information about importing gcc coverage data from a project, see Import gcc code coverage data from a project.

Note: If you want to instrument a static library with code coverage, you must also instrument your binary with code coverage, or link with the code coverage library using the following option in the linker command:
-lgcov

This option will link in the ${QNX_HOST}/usr/lib/gcc/target/version/libcov.a library.

Once a coverage session has begun, you can immediately view the data. The QNX Code Coverage perspective contains a Code Coverage Sessions view that lists previous as well as currently active sessions. You can explore each session and browse the corresponding source files that have received coverage data.

Note: Code Coverage might not work as expected because the code coverage data for C++ projects includes other functions that are also in the source file, such as static initializer and global constructor functions. In addition, the files included by include statements aren't included in the overall coverage total; only those functions that are in the original source are included for code coverage.