Lcov/Gcov Branch Coverage with C++ Producing Branches All Over the Place

Does Branch coverage implies Condition Coverage?

If you're talking specifically about the gcov tools, the branch coverage is really counting the points at which the end of each basic block is reached. See Understanding branches in gcov files.

Condition coverage is something different. See Is it possible to check condition coverage with gcov? (The answer is no, it's not, at least not with just gcov.) As Marc Gilsse's comment notes, you can use gcov -a to count executions through each basic block, and use that as a reasonable approximation—but it's not the same thing.

C++'s exceptions make dealing with branch coverage messy; see LCOV/GCOV branch coverage with C++ producing branches all over the place. This means you won't necessarily be able to cover all branches in the first place.

See also, e.g., Understanding blocks in gcov files.

Understand control flow graph in lcov branch coverage output

Please refer the answer [here] as below[1]:

The short form, is that lcov's interaction with branching, especially with inline calls, can find some of the hidden branches in the code, that are beyond your control.

For example, templated functions (of which std::cout << "foo" is one)
can be inlined efficiently by the compiler. Which means that any
branches present in that code can also be seen by the compiler. This
of course lets the compiler do a more thorough optimization. This is
the branch you are seeing here. It's not in code you wrote, but in
code the template instantiated for you.

In particular, most formatted output functions on basic_ostream are
going to ensure that the stream is in a good state prior to doing the
formatting or inserting work.

When I'm doing branch analysis, I tend to disregard branch misses on
functions like this. There are several similar places in C++ which
branches are detected by gcov/lcov, but are only implementation
details. I try to focus on the branches under my control.

the reason here is the same, QString::number() is a static function and it calls a inline function [QString::setNum][2] which had many branch inside.

Can check below as an example to illustrate this:

foo.h

extern void foo(int);

class Bar {
public:
inline bool doCheckInt(int a) { return a > 0 && a < 2; }

static bool checkParam(int a) {
Bar bar;
return bar.doCheckInt(a);

}
};

foo.cpp

#include "foo.h"
#include <iostream>

void foo(int num)
{
if (Bar::checkParam(num)) {
std::cout << "when num is equal to 1..." << std::endl;
} else if (num == 2){
std::cout << "when num is equal to 2..." << std::endl;
} else {
std::cout << "when num is equal to "<< num << std::endl;
}
}

main.c

#include <stdio.h>
#include "foo.h"


int main(void)
{
printf("Start calling foo() ...\n");
foo(1);
foo(2);
return 0;
}

after compile and generate code coverage report(relate method refered [here][3]), can get below coverage report for function foo():

[![foo_coverage][4]][4]

we can find that foo have total 8 branchs(2 X 2 X 2), and the two foo(1), foo(2) hit 5 of the branchs.
[1]: https://stackoverflow.com/a/69164983/4277805
[2]: https://github.com/radekp/qt/blob/master/src/corelib/tools/qstring.h
[3]: https://shenxianpeng.github.io/2021/07/gcov-example/
[4]: https://i.stack.imgur.com/n6huJ.png



Related Topics



Leave a reply



Submit