I run the C++ code to get code coverage results as is in this post.
#include <iostream>
using namespace std;
int testfunction(int input)
{
if (input > 0) {
return 1;
}
else {
return 0;
}
}
int main()
{
testfunction(-1);
testfunction(1);
}
The code coverage result says there are three blocks in the main(), and four blocks in the testfunction(). What does the block mean? How does are there the 3/4 blocks in main/testfunction?
When I modified the code as follows,
int main()
{
testfunction(1);
testfunction(1);
}
or as follows
int main()
{
testfunction(-1);
testfunction(-1);
}
I have this result.
And it seems that the testfunction()
has four blocks.
I got hints from this post.
A block policy is an all-risk insurance policy providing coverage against risks faced by goods transported or stored by third parties. Commonly found in commercial insurance, a block policy is designed to protect businesses from property damage.
On the Test menu, select Analyze Code Coverage for All Tests. You can also run code coverage from the Test Explorer tool window. Show Code Coverage Coloring in the Code Coverage Results window. By default, code that is covered by tests is highlighted in light blue.
#1) Parasoft JTest Its report provides a good picture of code covered and thereby minimizes risks. Key Features: It is used for Java-based applications. It is a multi-tasking tool which includes Data flow analysis, Unit testing, Static analysis, runtime error detection, code coverage testing etc.
The technical term for a block in code coverage is basic block. To crib directly from the Wikipedia entry:
The code in a basic block has one entry point, meaning no code within it is the destination of a jump instruction anywhere in the program, and it has one exit point, meaning only the last instruction can cause the program to begin executing code in a different basic block. Under these circumstances, whenever the first instruction in a basic block is executed, the rest of the instructions are necessarily executed exactly once, in order.
A basic block is important in code coverage because we can insert a probe at the beginning of the basic block. When this probe is hit, we know that all of the following instructions in that basic block will be executed (due to the properties of a basic block).
Unfortunately, with compilers (and especially with optimizations), it's not always apparent how source code maps to basic blocks. The easiest way to tell is to look at the generated assembly. For example, let's look at your original main
& testfunction
:
For main
, I see the assembly below (interleaved with the original source). Similarly to what Peter does here, I have noted where the basic blocks start.
int main()
{
013B2D20 push ebp <--- Block 0 (initial)
013B2D21 mov ebp,esp
013B2D23 sub esp,40h
013B2D26 push ebx
013B2D27 push esi
013B2D28 push edi
testfunction(-1);
013B2D29 push 0FFFFFFFFh
013B2D2B call testfunction (013B10CDh)
013B2D30 add esp,4 <--- Block 1 (due to call)
testfunction(1);
013B2D33 push 1
013B2D35 call testfunction (013B10CDh)
013B2D3A add esp,4 <--- Block 2 (due to call)
}
013B2D3D xor eax,eax
013B2D3F pop edi
013B2D40 pop esi
013B2D41 pop ebx
013B2D42 mov esp,ebp
013B2D44 pop ebp
013B2D45 ret
We see that main
has three basic blocks: one initial block, and the other two because of the function calls. Looking at the code, this seems reasonable. testfunction
is a little tougher. Just looking at the source, there appears to be three blocks:
input > 0
)return 1
)return 0
)However, because of the actual generated assembly, there are four blocks. I'm assuming you built your code with optimizations disabled. When I build with VS2010 in the Debug configuration (optimizations disabled), I see the following disassembly for testfunction
:
int testfunction(int input)
{
013B2CF0 push ebp <--- Block 0 (initial)
013B2CF1 mov ebp,esp
013B2CF3 sub esp,40h
013B2CF6 push ebx
013B2CF7 push esi
013B2CF8 push edi
if (input > 0) {
013B2CF9 cmp dword ptr [input],0
013B2CFD jle testfunction+18h (013B2D08h)
return 1;
013B2CFF mov eax,1 <--- Block 1 (due to jle branch)
013B2D04 jmp testfunction+1Ah (013B2D0Ah)
}
else {
013B2D06 jmp testfunction+1Ah (013B2D0Ah) <--- Not a block (unreachable code)
return 0;
013B2D08 xor eax,eax <--- Block 2 (due to jmp branch @ 013B2D04)
}
}
013B2D0A pop edi <--- Block 3 (due to being jump target from 013B2D04)
013B2D0B pop esi
013B2D0C pop ebx
013B2D0D mov esp,ebp
013B2D0F pop ebp
013B2D10 ret
Here, we have four blocks:
Had the compiler duplicated the function epilog in both the condition true and condition false branches, you would only see three blocks. Also, interestingly, the compiler inserted a spurious jmp
instruction at 013B2D06
. Because it's unreachable code, it's not treated as a basic block.
In general, all of this analysis is overkill since the overall code coverage metric will tell you what you need to know. This answer was just to highlight why the number of blocks isn't always obvious or what's expected.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With