Rational PurifyPlusLinux

 

Table of Contents

 

C/C++/Java Code Coverage

Block Coverage

Statement Blocks (or Simple Blocks)

Decisions - Implicit Blocks

Loops  - Logical Blocks

Function, Unit or Method Coverage

Procedure Entries (C), Inputs to Procedures (C++/Java)

Procedure Entries and Exits (Return and Terminal Statements) (C),

             Procedure Inputs, Outputs and Returns, and Terminal Instructions (C++/Java)

Potentially Terminal Statements

Non-coverable Statements

How to read a Coverage Report

            Seq line

 

 

C/C++/Java Code Coverage

 

 

Source-code coverage consists of identifying which portions of a program are

executed or not during a given test case. Source-code coverage is recognized as one of

the most effective ways of assessing the efficiency of the test cases applied to a

software application.

 

When not explicitly mentioned coverage rules are valid for all the languages.

 

Here a table reporting all types of Coverage performed by PuryfyPlus.

 

Block Coverage

 

 

When analyzing C/C++/Java source code, Code Coverage can provide the following block

coverage:

 

Statement Blocks (or Simple Blocks)

 

 

Statement blocks are the C/C++/Java method blocks, blocks introduced by control

instructions:

 

Java Example

public class StatementBlocks

{

public static void func( String _message )

throws UnsupportedOperationException

{

throw new UnsupportedOperationException(_message);

}

public static void main( String[] args )

throws Exception

{

try {

  if ( false )

  {

func( "Hello" );

  }

  else

  {

throw new Exception("bad luck");

  }

}

catch ( UnsupportedOperationException _E )

{

System.out.println( _E.toString() );

}

catch ( Exception _E )

{

System.out.println( _E.toString() );

throw _E ;

} //potentially terminal statement

return ; //sequence block

}

}

 

C++ Example

int main ( ) /* -

BLOCK */

{

try {

  if ( 0 )

  {

func ( "Hello" );

  }

  else

  {

throw UnLucky ( );

  }

}

catch ( Overflow & o ) {

cout << o.String << '\n';

}

catch ( UnLucky & u ) {

throw u;

} /* potentially terminal statement */

return 0; /* sequence block */

}

 

 

Each simple block is a branch. Every C++/Java function/method contains at least one simple block

corresponding to its main body.

 

Decisions (Implicit Blocks)

 

 

Implicit blocks are introduced by IF statements without an ELSE statement, and a

SWITCH statement without a DEFAULT statement.

 

Java Example

public class MathOp

{

static final int WHITE=0;

static final int LIGHTGRAY=1;

static final int RED=2;

static final int PINK=3;

static final int BLUE=4;

static final int GREEN=5;

// power of 10

public static int powerOf10( int _value, int _max )

{

int result = _value, i;

if( _value==0 ) return 0; //implicit else

for( i = 0; i < 10; i++ )

{

result = ( _max / 10 ) < result ? 10*result : _max ;

}

return result;

}

// Near color function

int nearColor( int _color )

{

switch( _color )

{

case WHITE:

case LIGHTGRAY:

return WHITE ;

case RED:

case PINK:

return RED;

//implicit default:

}

return _color ;

}

}

 

Each implicit block represents a branch.

Since the sum of all possible decision paths includes implicit blocks as well as simple

blocks, reports provide the total number of simple and implicit blocks as a figure and

a percentage after the term decisions.

 

For C: Code Coverage places this information in the Decisions report.

 

Loops (Logical Blocks)

 

 

Three branches are created in a FOR or WHILE loop:

 

For C++/Java:

 

 

Two branches are created in a DO/WHILE loop, as the output condition is tested after the block has been executed:

 

 

 

For C:

 

 

In a DO...WHILE loop, because the output condition is tested after the block has been executed, two further branches are created:

 

 

Java Example

public class LogicalBlocks

{

public static int tryFiveTimes()

{

int result, i=0;

while ( ( ( result=resourcesAvailable() )<= 0)

&& ( ++i < 5 ) );

// while define 3 logical blocks

return result;

}

public static int resourcesAvailable()

{

return (_free_resources_++);

}

public static int _free_resources_=0;

public static void main( String[] argv )

{

//first call: '0 loop' block is reach

_free_resources_=1;

tryFiveTimes();

//second call: '1 loop' blocks are reach

_free_resources_=0;

tryFiveTimes();

//third call: '2 loops or more' blocks are reach

_free_resources_=-10;

tryFiveTimes();

}

}

 

Function, Unit or Method Coverage

When analyzing source code, PurifyPlus for Linux can provide the following function/Unit/Method coverage:

 

Procedure Entries (C), Inputs to Procedures (C++/Java)

Inputs identify the C/C++/Java methods executed.

 

Java Example

public class Inputs

{

public static int method()

{

return 5;

}

public static void main( String[] argv )

{

System.out.println("Value:"+method());

}

}

 

C Example

/* Factorial function */

/* -proc */

int factorial ( int a )

{

if ( a > 0 ) return a * factorial ( a - 1 );

else return 1;

}

 

One branch per C/C++/Java method is defined.

 

 

Procedure Entries and Exits (Return and Terminal Statements) (C),

Procedure Inputs, Outputs and Returns, and Terminal Instructions (C++/Java)

These include the standard output (if coverable), all return instructions, and calls to

exit(), abort(), or terminate(), as well as the input.

 

Java Example

public class InputsOutputsAndReturn

{

public static void method0( int _selector )

{

if ( _selector < 0 )

{

return ;

}

}

public static int method1( int _selector )

{

if( _selector < 0 ) return 0;

switch( _selector )

{

case 1: return 0;

case 2: break;

case 3: case 4: case 5: return 1;

}

return (_selector/2);

}

public static void main( String[] argv )

{

method0( 3 );

System.out.println("Value:"+method1( 5 ));

System.exit( 0 );

}

}

 

At least two branches per C/C++/Java method are defined. The input is always enumerated,

as is the output if it can be covered.

 

For C++ : If it cannot, it is preceded by a terminal

instruction involving returns or by a call to exit(), abort(), or terminate().

 

For C: If it cannot, it is preceded by a terminal instruction involving returns or an exit.

 

 

Potentially Terminal Statements

The following decision statements are potentially terminal if they contain at least one

statement that transfers program control out of its sequence (RETURN, THROW,

GOTO, BREAK, CONTINUE) or that terminates the execution (EXIT).

 

 

Non-coverable Statements

 

Java:

A Java statement is non coverable if the statement can never possibly be executed.

Code Coverage detects non-coverable statements during instrumentation and

produces an error message that specifies the source file and line location of each noncoverable

statement.

 

C++:

A C++ statement is non-coverable if the statement can never possibly be executed.

Code Coverage detects non-coverable statements during instrumentation and

produces a warning message that specifies the source file and line location of each

non-coverable statement.

 

C:

Some C statements are considered non coverable if they follow a terminal

instruction, a CONTINUE, or a BREAK, and are not a GOTO label. Code Coverage

detects non-coverable statements during instrumentation and produces a warning

message that specifies the source file and line location of each non-coverable

statement.

 

 

How to read a Coverage Report

 

Consider a text Coverage summary as follows:


FileName.cpp:
    int main (int, char **) :
            Statement blocks ............   0.0% (0/14)
                /then/do, line 57
                /then, line 56
                /seq, line 64
                /then/do, line 68
                /then, line 67
                /else, line 72
                /try/do, line 79
                /try, line 78
                /catch/do, line 90
                /catch, line 89
                /try, line 97
                /catch/do, line 103
                /catch, line 102
                /, line 49
            Implicit blocks .............   0.0% (0/1)
                /else, line 59
            Decisions ...................   0.0% (0/15)
            Loops .......................   0.0% (0/10)
                /then/do/1, line 57
                /then/do/2+, line 57
                /then/do/1, line 68
                /then/do/2+, line 68
                /try/do/1, line 79
                /try/do/2+, line 79
                /catch/do/1, line 90
                /catch/do/2+, line 90
                /catch/do/1, line 103
                /catch/do/2+, line 103



 

This report shows for each function found in the source file the coverage rate (here, the code is not covered at all).

The percentage is calculated by dividing the available blocks by the number of the covered ones.
Here, we have 14 Statement blocks, of which none was hit.

After this Block summary, every uncovered block is mentioned, identified by its nature.

Whithin a then statement, there is a do block: /then/do . For each block, the line number of the source file is referenced.

 

A simple '/' denotes the root block.

Because the sum of all possible decision paths includes implicit blocks as well as statement blocks, reports provide the total number of simple and implicit blocks as a

figure and as a percentage. Code Coverage places this information in the Decisions report.

 

A loop is considered as covered, if it was executed once without entering into it (for if or for loops only), and entered once ("1"),

and repeated once or more times ("2+").

 
Here another Coverage example:

 

void alma.scheduling.planning_mode_sim.simulator.ControlSimulator.initialize() :

                                    Hit .........................    yes

                                    Functions and exits ......... 100.0% (2/2)

                                    Statement blocks ............  66.7% (2/3)

                                                /catch, line 100

                                    Implicit blocks .............   none

                                    Decisions ...................  66.7% (2/3)

                                    Loops .......................  33.3% (1/3)

                                                /try/for/0, line 94

                                                /try/for/1, line 94

 

 

In this coloured code not covered lines are listed in red.

 

85        public void initialize() throws ComponentLifecycleException {

86                    super.initialize();

87                    try {

88                                clock = (ClockSimulator)m_containerServices.getComponent(Container.CLOCK);

89                                //weather = new WeatherModel ();

90                                // There are no subarrays and all antennas are idle.

91                                subarray = new ArrayList ();

92                                int numberAntennas = data.getInt(Tag.numberAntennas);

93                                antennaList = new Antenna [numberAntennas];

94                                for (int i = 0; i < numberAntennas; ++i) {

95                                            antennaList[i] = new Antenna (i);

96                                }

97                                archive = (ArchiveSimulator)m_containerServices.getComponent(Container.ARCHIVE);

98                                setUpTimeInSec = data.getSetUpTimeInSec();

99                                changeProjectTimeInSec = data.getChangeProjectTimeInSec();

100                  } catch (Exception err) {

101                              m_state.setState(ComponentState.ERROR);

102                                                            m_logger.severe("Control.error " + err.toString());

103                                                            throw new ComponentLifecycleException("Control "

                              + Level.SEVERE + " " + err.toString());

104                  }

 

 

 

Seq line

The "seq" means that although the line belongs to the same block as another, between the two lines of the block there is a potentially terminal instruction. Example:

 

 

int divide (int a, int b)
{
        int result;
        result = 0;
        if (b == 0)
            exit (1);  
        result = a / b;      <<<===             seq generated here as there if b is zero then exit will                                                       be called and this statement will never be executed.

        return (result);
}