Jelajahi Sumber

-- Date: 2010/02/10
Reference: noref
Issue type: feature
Severity: Major
Module(s): gcov bridge
Description: Collection of coverage statistic added

avkonst 15 tahun lalu
induk
melakukan
fa1d31d842
6 mengubah file dengan 346 tambahan dan 36 penghapusan
  1. 53 0
      changelog.txt
  2. 22 0
      lib/SWI/Launcher.pm
  3. 121 16
      lib/SWI/Processor.pm
  4. 9 6
      project.html
  5. 140 12
      swi_config_sample.xml
  6. 1 2
      swi_main.pl

+ 53 - 0
changelog.txt

@@ -0,0 +1,53 @@
+#
+#    Software Index, Copyright 2010, Software Index Project Team
+#    Link: http://swi.sourceforge.net
+#
+#    This file is part of Software Index Tool.
+#
+#    Software Index is free software: you can redistribute it and/or modify
+#    it under the terms of the GNU General Public License as published by
+#    the Free Software Foundation, version 3 of the License.
+#
+#    Software Index is distributed in the hope that it will be useful,
+#    but WITHOUT ANY WARRANTY; without even the implied warranty of
+#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+#    GNU General Public License for more details.
+#
+#    You should have received a copy of the GNU General Public License
+#    along with Software Index.  If not, see <http://www.gnu.org/licenses/>.
+#
+
+____________________________________________
+
+
+-- 2010/02/11: VERSION 0.9.0 released for internal beta testing
+
+       -- Date:         2010/02/10
+          Reference:    noref
+          Issue type:   feature
+          Severity:     Major
+          Module(s):    gcov bridge
+          Description:  Collection of coverage statistic added
+
+       -- Date:         2010/01/31
+          Reference:    noref
+          Issue type:   feature
+          Severity:     Critical
+          Module(s):    Parser
+          Description:  C++ language support added
+
+       -- Date:         2010/01/10
+          Reference:    noref
+          Issue type:   bug
+          Severity:     Critical
+          Module(s):    Parser
+          Description:  C language parser becomes loyal with code formating
+
+____________________________________________
+
+
+-- 2009/08/22: VERSION 0.8.0 released for internal beta testing
+____________________________________________
+
+
+-- 2009/07/13: VERSION 0.7.0 released for internal alpha testing

+ 22 - 0
lib/SWI/Launcher.pm

@@ -498,6 +498,28 @@ sub swiConfigurationValidate
                     $module->{'swi:indexer:dup'}->{'swi:globalcode'} = 'off';
                 }
 
+                if ( !defined( $module->{'swi:indexer:gcov'} )
+                    || ref( $module->{'swi:indexer:gcov'} ) ne 'HASH' )
+                {
+                    $module->{'swi:indexer:gcov'} = {};
+                }
+                if ( !defined( $module->{'swi:indexer:gcov'}->{'swi:enabled'} ) )
+                {
+                    $module->{'swi:indexer:gcov'}->{'swi:enabled'} = 'off';
+                }
+                if ( !defined( $module->{'swi:indexer:gcov'}->{'swi:filepattern'} ) )
+                {
+                    $module->{'swi:indexer:gcov'}->{'swi:filepattern'} = '.*';
+                }
+                if ( !defined( $module->{'swi:indexer:gcov'}->{'swi:sourcefile'} ) )
+                {
+                    $module->{'swi:indexer:gcov'}->{'swi:sourcefile'} = '(.*)[.][cChH][pP]?[pP]?';
+                }
+                if ( !defined( $module->{'swi:indexer:gcov'}->{'swi:gcdafile'} ) )
+                {
+                    $module->{'swi:indexer:gcov'}->{'swi:gcdafile'} = '${1}.gcda';
+                }
+
                 $moduleId++;
             }
         }

+ 121 - 16
lib/SWI/Processor.pm

@@ -232,7 +232,7 @@ sub swiProcess
         {
             if ( $file =~ m/$swiGlobalInclude/ )
             {
-                if ($swiGlobalExclude ne ""
+                if (   $swiGlobalExclude ne ""
                     && $file =~ m/$swiGlobalExclude/ )
                 {
                     next;
@@ -244,7 +244,9 @@ sub swiProcess
                     $swiGlobalPreprocessorRules,
                     $swiGlobalScanerRules,
                     $config->{"swi:modules"}->{"swi:module"}[$moduleId]
-                      ->{"swi:indexer:dup"}
+                      ->{"swi:indexer:dup"},
+                    $config->{"swi:modules"}->{"swi:module"}[$moduleId]
+                      ->{"swi:indexer:gcov"}
                 );
             }
         }
@@ -415,6 +417,7 @@ sub swiParse
     my $preprocessorRules = shift();
     my $scanerRules       = shift();
     my $dupfinderSettings = shift();
+    my $gcovSettings      = shift();
 
     STATUS("Parsing file: '$location/$file'.");
 
@@ -466,10 +469,18 @@ sub swiParse
         $globalBlock_Purified
     );
 
-    # Add coverage statistic
-    my $fh = new FileHandle( $location . "/" . $file, "r" )
-      or die("Can not open input file '$location/$file'!");
-
+    if ( $gcovSettings->{'swi:enabled'} eq 'on' )
+    {
+        my $filePattern = $gcovSettings->{'swi:filepattern'};
+        if ( $file =~ m/$filePattern/ )
+        {
+            swiSourceIndexGcovAdd(
+                $location, $file, $functionsData,
+                $gcovSettings->{'swi:sourcefile'},
+                $gcovSettings->{'swi:gcdafile'}
+            );
+        }
+    }
 
     return $functionsData;
 }
@@ -528,19 +539,22 @@ sub swiSourceCodeScan
 
     while ( $code =~ m/$search/g )
     {
-        
+
         my $matchPre = $`;
         my $matchStr = $&;
 
         my $linePos = swiMatchPatternCount( $matchPre . $matchStr, '\n' ) + 1;
         my $messageString = eval( 'my $tmp = "' . $message . '";' );
-        
-        push(@result, {
-                        'swi:ref:type'  => 'scan',
-                        'swi:scan:file' => $file,
-                        'swi:scan:line' => $linePos + $offset,
-                        'swi:scan:message' => $messageString
-                    });
+
+        push(
+            @result,
+            {
+                'swi:ref:type'     => 'scan',
+                'swi:scan:file'    => $file,
+                'swi:scan:line'    => $linePos + $offset,
+                'swi:scan:message' => $messageString
+            }
+        );
     }
 
     return @result;
@@ -707,6 +721,7 @@ s/($regexpCodeContainerDelimeter)?($regexpCodeContainerIdentifier$regexpCodeCont
             {
                 $block->{'commentshead'} .= $block_Comment[$i] . "\n";
             }
+
             # functionname created above
             $block->{'functionhead'} = substr(
                 $block_Purified,
@@ -853,7 +868,8 @@ s/($regexpCodeContainerDelimeter)?($regexpCodeContainerIdentifier$regexpCodeCont
                 push(
                     @{ $function->{'swi:reference'} },
                     swiSourceCodeScan(
-                        $file, $function->{'swi:line:headerstart'},
+                        $file,
+                        $function->{'swi:line:headerstart'},
                         $block->{ $rule->{'swi:codecontent'} },
                         $rule->{'swi:searchpattern'},
                         $rule->{'swi:messagepattern'}
@@ -972,6 +988,79 @@ m/duplication: file: '(.*)' function: '(.*)' possition: '(.*)' size: '(.*)'/
     return $filesData;
 }
 
+sub swiSourceIndexGcovAdd
+{
+    my $location      = shift();
+    my $file          = shift();
+    my $functionsData = shift();
+    my $filePattern   = shift();
+    my @listTmp       = $file =~ m/$filePattern/;
+    my $gcdaFile      = eval( 'my $tmp = "' . shift() . '";' );
+
+    # Add coverage statistic
+    my $fh = new FileHandle( $location . "/" . $gcdaFile, "r" );
+    if ( !defined($fh) )
+    {
+        STATUS("gcda file is not found '$location/$gcdaFile'.");
+    }
+    else
+    {
+        my $gcovCommand = 'gcov -f -b $location/$gcdaFile';
+        STATUS("Calling command '$gcovCommand'...");
+
+        my $gcovData = `$gcovCommand`;
+        my @covData  = split( "\n\n", $gcovData );
+
+        foreach (@covData)
+        {
+            next if ( $_ =~ m/^File/ );
+            my (
+                $functionName,  $linesExec, $linesTotal, $branchesExec,
+                $branchesTotal, $takenOnce, $callsExec,  $callsTotal
+              )
+              = ( $_ =~
+m/^Function\s+\'(.*)\'\s+Lines\s+executed:(.*)%\s+of\s+(.*)\s+Branches\s+executed:(.*)%\s+of\s+(.*)\s+Taken\s+at\s+least\s+once:(.*)%\s+of\s+.*\s+Calls\s+executed:(.*)%\s+of\s+(.*)/
+              );
+
+            if ( defined( $functionsData->{$functionName} ) )
+            {
+                $functionsData->{$functionName}->{'swi:statistic'}
+                  ->{'swi:coverage'} = {
+                    'swi:gsum:lines'    => { 'swi:exact' => $linesTotal },
+                    'swi:gsum:branches' => { 'swi:exact' => $branchesTotal },
+                    'swi:gsum:calls'    => { 'swi:exact' => $callsTotal },
+                    'swi:gcov:lines'    => {
+                        'swi:exact' =>
+                          swiUtil_Round( $linesExec * $linesTotal / 100 )
+                    },
+                    'swi:gcov:branches' => {
+                        'swi:exact' =>
+                          swiUtil_Round( $branchesExec * $branchesTotal / 100 )
+                    },
+                    'swi:gcov:takenonce' => {
+                        'swi:exact' =>
+                          swiUtil_Round( $takenOnce * $branchesTotal / 100 )
+                    },
+                    'swi:gcov:calls' => {
+                        'swi:exact' =>
+                          swiUtil_Round( $callsExec * $callsTotal / 100 )
+                    }
+                  };
+            }
+            else
+            {
+                STATUS(
+"Parsing of source file is incorrect or gcda file is corrupted."
+                );
+                STATUS(
+"gcov reports the data for '$functionName' function but SWI parser did not detect it"
+                );
+                $exitCode++;
+            }
+        }
+    }
+}
+
 sub swiSourceCodeParse
 {
     my $file         = shift();
@@ -1100,7 +1189,10 @@ m/^($regexpCodeFunctionModifier)*($regexpCodeFunctionIdentifier)($regexpCodeFunc
                             );
                             my $counter = 2;
                             while (
-                                defined( $result->{ $word . " (" . $counter . ")" } ) )
+                                defined(
+                                    $result->{ $word . " (" . $counter . ")" }
+                                )
+                              )
                             {
                                 $counter++;
                             }
@@ -1500,4 +1592,17 @@ sub swiUtilDirectoryCleanUp
     }
 }
 
+sub swiUtil_Round
+{
+    my $float = shift();
+    if ( ( $float - int($float) ) > 0.5 )
+    {
+        return int( $float + 1.0 );
+    }
+    else
+    {
+        return int($float);
+    }
+}
+
 return 1;

+ 9 - 6
project.html

@@ -35,7 +35,7 @@
   <tr>
     <td width="350"><img src="images/logo_project.jpg" alt="Software Index Project Page" width="350" height="128" /></td>
     <td valign="bottom">      <div align="right">
-      <p><a href="http://sourceforge.net/projects/swi"><img src="http://sflogo.sourceforge.net/sflogo.php?group_id=275098&amp;type=10" alt="Get Software Index at SourceForge.net. Fast, secure and Free Open Source software downloads" width="80" height="15" border="0" /></a></p>
+      <p><a href="http://sourceforge.net/projects/swi"><img src="http://sflogo.sourceforge.net/sflogo.php?group_id=275605&amp;type=10" alt="Get Software Index at SourceForge.net. Fast, secure and Free Open Source software downloads" width="80" height="15" border="0" /></a></p>
       <p>&nbsp;</p>
       <p><a href="#Description">Description</a> | <a href="#Download">Download &amp; Installation </a> | <a href="#License">License</a> | <a href="#Documentation">Documentation</a> | <a href="#Getsupport">Get support </a>| <a href="#Fordevelopers">For developers</a></p>
     </div></td>
@@ -55,14 +55,17 @@
                 <li>Number of <span class="normalImportance">executable symbols</span> and <span class="normalImportance">lines</span> </li>
                 <li>Number of <span class="normalImportance">symbols</span> and <span class="normalImportance">lines in comments</span></li>
                 <li>Number of <span class="normalImportance">symbols</span> and<span class="normalImportance"> lines in initial source file</span></li>
-                <li>Number of <span class="normalImportance">lines in specific comments</span> (header descriptions before functions)  </li>
+                <li>Number of <span class="normalImportance">lines in specific comments</span><br />
+                (header descriptions before functions)  </li>
                 <li>Number of <span class="normalImportance">symbols in name</span> of a function </li>
                 <li>Number of <span class="normalImportance">blocks</span></li>
                 <li>Maximum <span class="normalImportance">indent level</span> (depth level) </li>
                 <li><span class="normalImportance">Cyclomatic complexity</span> (McCabe's / Mayer's) index </li>
                 <li>Number of <span class="normalImportance">functions, files, modules</span></li>
                 <li>Number of symbols in <span class="normalImportance">duplicated fragments</span></li>
-            </ul>
+                <li><span class="normalImportance">Code coverage</span> indexes<br />
+                (line coverage, branch coverage and entry/exit coverage data from external gcov tool) </li>
+          </ul>
           <h4>Parsing, scaning and searching can be performed for the different content:</h4>
           <ul>
             <li><span class="normalImportance">initial</span>         - the initial source content</li>
@@ -113,7 +116,7 @@
             <li>C++ (beta version) </li>
           </ul>
           <h3><a id="Download"></a>Download &amp; Installation</h3>
-          <p>For the installation of the <span class="normalImportance">Software Index</span> <a href="http://sourceforge.net/projects/swi/files/">download</a> the archive with all required modules and unpack it to some folder.</p>
+          <p>For the installation of the <span class="normalImportance">Software Index</span> <a href="http://sourceforge.net/projects/swi/files/">download</a> the archive with all required modules and unpack it to some folder. Also, you have got an option to get the <a href="http://swi.svn.sourceforge.net/viewvc/swi/">source code</a> from the version conrol sytem.</p>
           <p><em class="highImportance">Warning:</em> <span class="normalImportance">Software Index</span> has an internal tool (dupindex) which should be compiled for the target platform.
             By default, the distributable archive includes the compiled binary for PC Windows (x86) platform.
             Recompile it if you need (only one file: dupindex.cpp), using g++ or some other C++ compiler for your specific platform. There is a project configuration file for users of Microsoft Visual Studio 2008. </p>
@@ -129,10 +132,10 @@
                 <li>IPC::Open3</li>
                 <li> XML::Simple (included to the distributable archive with <span class="normalImportance">Software Index</span>)</li>
                 <li> String::CRC::Cksum (included to the distributable archive with <span class="normalImportance">Software Index</span>)</li>
-              </ul>
+                </ul>
             </li>
+            <li>gcov (optional, it is needed if you like to collect coverage statistic)</li>
           </ul>
-          <p>Also, you have got an option to get the <a href="http://swi.svn.sourceforge.net/viewvc/swi/">source code</a> from the version conrol sytem.</p>
           <h3><a name="License" id="Download"></a>License</h3>
           <p> This program is free software; you can redistribute it and/or modify 
             it under the terms of the GNU General Public License as published by 

+ 140 - 12
swi_config_sample.xml

@@ -57,7 +57,7 @@
         If you workflow assumes history records in project files,
         this is the place to keep your records
         
-        The section can be missed.
+        The section is optional.
     -->
     <swi:history>
       <!-- Section 'swi:revision' can be repeated several times -->
@@ -80,13 +80,13 @@
   <!--
       The 'swi:general' section configures global settings for the tool.
       
-      The section can be missed.
+      The section is optional.
   -->
   <swi:general>
     <!--
         Filtering of the debug information
         
-        The section can be missed.
+        The section is optional.
     -->
     <swi:debug>
      <!--
@@ -121,7 +121,7 @@
       <!--
           Section 'swi:files' which files to process and which to miss.
           
-          The section can be missed.
+          The section is optional.
       -->
       <swi:files>
         <!--
@@ -250,10 +250,10 @@
           As a result, the functions will be detected with the correct names:
               'leftButtonClick' and 'rightButtonClick' accordingly.
           
-          'swi:preprocessor' section can be missed.
+          'swi:preprocessor' section is optional.
       -->
       <swi:preprocessor>
-        <!-- Section 'swi:rule' can be missed or repeated several times -->
+        <!-- Section 'swi:rule' is optional or can be repeated several times -->
         <swi:rule>
           <!--
               This option is a regular expression.
@@ -326,7 +326,7 @@
           the error report looks like this:
               file.c:2: warning: Noname 'struct' detected.
               
-          'swi:scaner' section can be missed.
+          'swi:scaner' section is optional.
       -->
       <swi:scanner>
         <!-- Section 'swi:rule' can be missed or repeated several times -->
@@ -438,7 +438,7 @@
               
           Cumulative types (swi:average, swi:min, swi:max and swi:total) are reported if they are applicable.
           
-          'swi:indexer:common' section can be missed.
+          'swi:indexer:common' section is optional.
       -->
       <swi:indexer:common>
         <!-- No settings currently available -->
@@ -471,7 +471,7 @@
           This internal tool also collects pointers to duplicated fragments and prints them.
           Also, they can be easily extracted from the final report for other needs.
           
-          'swi:indexer:dup' section can be missed.
+          'swi:indexer:dup' section is optional.
       -->
       <swi:indexer:dup>
         <!--
@@ -545,7 +545,135 @@
         <swi:globalcode>on</swi:globalcode>
       </swi:indexer:dup>
 
-    </swi:module>
+      <!--
+          gcc/g++ compilers in combination with gcov tool are able to report
+          statement and branch coverage information and statistics.
+          Software Index has a bridge to this information which is configured
+          in the 'swi:indexer:gcov' section below.
+          
+          Note: the feature works only if 'gcov' is visible in PATH environment.
+          
+          The short summary about possible coverage metrics:
+          
+          * Function coverage
+            Has each function in the program been executed?
+
+          * Statement coverage
+            Has each line of the source code been executed?
+            If at least one statement is executed, 'Function coverage' metric
+            is equal to 100% (i.e. a function is executed at least once)
+
+          * Decision coverage
+            Has each control structure (such as an if statement) evaluated both to true
+            and false?
+
+          * Condition coverage
+            Has each boolean sub-expression evaluated both to true and false?
+            More 'strict' metric than 'Decision coverage'.
+          
+          * Modified Condition/Decision Coverage (MC/DC)
+            Has every condition in a decision taken on all possible outcomes at least
+            once? Has each condition been shown to affect that decision outcome
+            independently?
+
+          * Path coverage
+            Has every possible route through a given part of the code been executed?
+
+          * Entry/exit coverage
+            Has every possible call and return of the function been executed?
+          
+          The coverage statistic is reported by the following indexes:
+          
+              STATICTIC-GROUP / STATISTIC-NAME     - DESCRIPTION (*)
+              =============== / ================== - ============================
+              swi:coverage    / swi:gsum:lines     - Total number of executable lines/statements
+                                                     (from point of compiler view)
+              swi:coverage    / swi:gsum:branches  - Total number of branches
+              swi:coverage    / swi:gsum:calls     - Total number of calls
+              swi:coverage    / swi:gcov:lines     - Number of executed lines
+                                                     (the same as 'Statement coverage' metric in the list above)
+              swi:coverage    / swi:gcov:branches  - Number of exected branches
+                                                     (no analogue in the list of coverage metrics above;
+                                                     incremented by 2 for a boolean condition (2 branches)
+                                                     if a condition is evaluated at least once
+                                                     and resulted either in true OR in false)
+              swi:coverage    / swi:gcov:takenonce - Number of branches executed at least once
+                                                     (the same as 'Condition coverage' metric in the list above;
+                                                     a boolean condition (2 branches) is totaly covered
+                                                     if a boolean sub-expression evaluated both
+                                                     to true and false at least once)
+              swi:coverage    / swi:gcov:calls     - Number of exectuted calls
+                                                     (the same as 'Entry/exit coverage' metric in the list above)
+          
+          (*) For more details about reported numbers see the documentation for 'gcov' tool.
+              
+          The statistic is reported incombination with the following types:
+          
+              STATICTIC-TYPE  - DESCRIPTION
+              =============== - ============================
+              swi:exact       - exact value
+              swi:average     - average value within a distribution
+              swi:min         - minimum value within a distribution
+              swi:max         - maximum value within a distribution
+              swi:total       - sum of values within a distribution
+          
+          Cumulative types (swi:average, swi:min, swi:max and swi:total) are reported if they are applicable.
+
+          'swi:indexer:gcov' section is optional.
+          If it is missed coverage statistic is not collected.
+      -->
+      <swi:indexer:gcov>
+        <!--
+            The 'swi:enabled' option activates/deativates the collection of coverage statistic:
+            
+                on  - active
+                off - inactive, coverage statistic is not collected and not reported
+            
+            By default, the this is not enabled
+        -->
+        <swi:enabled>on</swi:enabled>
+        <!--
+            This option is a regular expression.
+            If name of file which is under processing is mathced by this expression,
+            coverage statistic is retrieved for this file.
+            Otherwise, coverage statistic is not reported.
+            
+            By default, all files are affected.
+        -->
+        <swi:filepattern>.*</swi:filepattern>
+        <!--
+            The coverage statistic is avaialble in 'gcda' files.
+            gcov tool reads these files and reports the information.
+            
+            Every source file, if it is touched by gcov, has
+            corresponding gcda file.
+            
+            For example, if the initial source file is 'file.c' and
+            the compiled binary file is 'file.o', the
+            corresponding 'gcda' file with coverage data is 'file.gcda'
+            
+            Two options below define how to map
+            the initial source file to the file with coverage data.
+            
+            'swi:sourcefile' is a regular expression. It is applied to name of a file.
+            This operation gives variables ${1}, ${2}, ... according
+            to regexp hooks.
+            'swi:gcdafile' constructs the corresponding 'gcda' file.
+            
+            The example below demostrates the case of mapping:
+                 from 'file.c' to 'file.gcda'
+                 from 'otehrfile.h' to 'otherfile.gcda'
+                 and so on...
+            
+            If the 'gcda' file is not found, coverage statistic is not collected and not reported.
+            
+            The example below demonstrates the default mapping scheme options are missed.
+        -->
+        <swi:sourcefile>(.*)[.][cChH][pP]?[pP]?</swi:sourcefile>
+        <swi:gcdafile>${1}.gcda</swi:gcdafile>
+      </swi:indexer:gcov>
+
+      </swi:module>
     
     <!--
         Add here the next 'swi:module' section.
@@ -655,7 +783,7 @@
               cloned     - 'off'
               unmodified - 'off'
               
-          'swi:error' section can be missed.
+          'swi:error' section is optional.
       -->
       <swi:error>
         <swi:added>on</swi:added>
@@ -724,7 +852,7 @@
       STATISTIC-GROUP / STATISTIC-NAME / STATISTIC-TYPE
       (See sections 'swi:indexer:common' and 'swi:indexer:dup' above)
       
-      'swi:limits' section can be missed.
+      'swi:limits' section is optional.
   -->
   <swi:limits>
     <!-- 

+ 1 - 2
swi_main.pl

@@ -109,8 +109,7 @@ if (   !defined( $ARGV[0] )
     exit 0;
 }
 
-if (   !defined( $ARGV[0] )
-    || $ARGV[0] eq "-sample"
+if (   $ARGV[0] eq "-sample"
     || $ARGV[0] eq "--sample"
     || $ARGV[0] eq "-s" )
 {