gcovr/SonarQube saying simple C++ function is only half covered

1.4k views Asked by At

We are running gcovr on our codebase which is (FTR) then fed into SonarQube (cxx-plugin). There are many places where there is a report of less than 100% coverage, even though there are no obvious branches so it should be surely 0 or 100%. Take for example the following:

std::string quote(const std::string& str, const std::string& quote_str) {
    return quote_str + str + quote_str;
}

On SonarQube, the first line is reported as "Fully covered". The second line is reported as "Partially covered by tests (1 of 2 conditions)". The third line is not mentioned - as expected. Question is as to what are the conditions that (I guess) gcovr is seeing on the return line that I can't.

I have tried a suggestion from Why gcc 4.1 + gcov reports 100% branch coverage and newer (4.4, 4.6, 4.8) reports 50% for "p = new class;" line? (adding --exclude-throw-branches) and have even tried adding --exclude-unreachable-branches. Seems to make no difference.

Looking at the generated xml output, I notice that both the first few lines are showing 57 hits with branch="false". I am wondering where the "1 of 2 conditions" comes from and perhaps it is SonarQube?

Has anybody else seen this or have a solution?

Update

I didn't mention this to start with, because it did not seem relevent, but we are using clang v11 (not gcc), and thus "llvm-cov gcov" (not gcov itself) below gcovr. As reflected below, seems this is important.

2

There are 2 answers

0
johnfo On BEST ANSWER

I did write an earlier comment that it is perhaps sonarqube but I've had another look:) I think your comments about the possible values is flawed because these are standard C++ strings (not C ones) so effectively can't be NULL as such. However there is a possible OOM exception on the add - you are probably right that the non-followed branch is this exception.

I did some experiments comparing the gcovr output using the --exclude-throw-branches and --exclude-unreachable-branches. Basically it made no difference on the gcovr report for this line, although it did make some difference on other lines.

I am not sure I mentioned that we are using clang rather than (say) gcc. I guess that might make a difference. Not sure. Whatever the reflection does seem to be that this is a gcov/gcovr issue and not sonarqube. I had originally assumed that made no difference. Seems it does. From what I can work out, "llvm-com gcov" (the subcommand of llvm-cov that simulates gcov) does not generate the tags to show that some branches reflect throws. I've looked at the output locally - I probably need to compare with gcc and gcov. However that seems to be the real problem.

0
agabrys On

perhaps it is SonarQube?

SonarQube doesn't calculate code coverage information. It only displays reports generated by other tools. If anything is incorrect, you have to analyze the used coverage tool configuration.

where the "1 of 2 conditions" comes from

They come for the coverage tool. The expressions has more branches because the method could be executed with the following values:

+---------------------+
|   str   | quote_str |
+---------------------+
|   NULL  |   NULL    |
|   NULL  |  string   |
|  string |   NULL    |
|  string |  string   |
+---------------------+

As you see some exceptions could be thrown. I believe you checked only the happy path where no exceptions are thrown, so that is the reason why only 1 of 2 conditions is covered.

As you mentioned in the comment, it is possible to disable conditions related to exceptions by adding --exclude-throw-branches. I have no big experience in C++ code (I'm a Java developer), but I would prefer to has lower code coverage and be aware of potential exceptions instead of seeing 100% coverage and hit unexpected issues in the runtime.