Changeset 42

Show
Ignore:
Timestamp:
03/10/06 14:14:29 (2 years ago)
Author:
mrook
Message:

Another big update to code coverage tasks

  • Fix inconsistent reporting
  • Add statement counts
  • Use XDEBUG_CC_UNUSED to pre-generate info about executable statements
Files:

Legend:

Unmodified
Added
Removed
Modified
Copied
Moved
  • trunk/classes/phing/tasks/ext/coverage/CoverageReportTask.php

    r41 r42  
    195195        } 
    196196 
    197         protected function transformSourceFile($basename, $filename, $coverageInformation, $classStartLine = 1) 
     197        protected function transformSourceFile($filename, $coverageInformation, $classStartLine = 1) 
    198198        { 
    199199                $sourceElement = $this->doc->createElement('sourcefile'); 
    200                 $sourceElement->setAttribute('name', $basename); 
     200                $sourceElement->setAttribute('name', basename($filename)); 
    201201 
    202202                $filelines = $this->highlightSourceFile($filename); 
     
    224224                return $sourceElement; 
    225225        } 
    226  
    227         protected function transformCoverageInformation($basename, $filename, $coverageInformation) 
     226         
     227        protected function filterCovered($var) 
     228        { 
     229                return ($var >= 0); 
     230        } 
     231 
     232        protected function transformCoverageInformation($filename, $coverageInformation) 
    228233        { 
    229234                $classes = PHPUnit2Util::getDefinedClasses($filename, $this->classpath); 
    230                          
    231                 foreach ($classes as $classname) 
    232                 { 
    233                         $reflection = new ReflectionClass($classname); 
    234235                 
    235                         $methods = $reflection->getMethods(); 
    236  
    237                         $classElement = $this->doc->createElement('class'); 
    238                         $classElement->setAttribute('name', $reflection->getName()); 
    239  
    240                         $this->addClassToPackage($reflection->getName(), $classElement); 
    241  
    242                         $methodscovered = 0; 
    243                         $methodcount = 0; 
    244  
    245                         reset($coverageInformation); 
    246  
    247                         foreach ($methods as $method) 
     236                if (is_array($classes)) 
     237                { 
     238                        foreach ($classes as $classname) 
    248239                        { 
    249                                 // PHP5 reflection considers methods of a parent class to be part of a subclass, we don't 
    250                                 if ($method->getDeclaringClass()->getName() != $reflection->getName()) 
     240                                $reflection = new ReflectionClass($classname); 
     241                                 
     242                                $methods = $reflection->getMethods(); 
     243                                 
     244                                $classElement = $this->doc->createElement('class'); 
     245                                $classElement->setAttribute('name', $reflection->getName()); 
     246                                 
     247                                $this->addClassToPackage($reflection->getName(), $classElement); 
     248 
     249                                $classStartLine = $reflection->getStartLine(); 
     250                                 
     251                                $methodscovered = 0; 
     252                                $methodcount = 0; 
     253                                 
     254                                end($coverageInformation); 
     255                                unset($coverageInformation[key($coverageInformation)]); 
     256                                 
     257                                // Strange PHP5 reflection bug, classes without parent class or implemented interfaces seem to start one line off 
     258                                if ($reflection->getParentClass() == NULL && count($reflection->getInterfaces()) == 0) 
    251259                                { 
    252                                         continue
     260                                        unset($coverageInformation[$classStartLine + 1])
    253261                                } 
    254  
    255                                 // small fix for XDEBUG_CC_UNUSED 
    256                                 if (isset($coverageInformation[$method->getStartLine()])) 
     262                                else 
    257263                                { 
    258                                         unset($coverageInformation[$method->getStartLine()]); 
     264                                        unset($coverageInformation[$classStartLine]); 
    259265                                } 
    260  
    261                                 if (isset($coverageInformation[$method->getEndLine()])) 
     266                                 
     267                                reset($coverageInformation);                             
     268                                 
     269                                foreach ($methods as $method) 
    262270                                { 
    263                                         unset($coverageInformation[$method->getEndLine()]); 
     271                                        // PHP5 reflection considers methods of a parent class to be part of a subclass, we don't 
     272                                        if ($method->getDeclaringClass()->getName() != $reflection->getName()) 
     273                                        { 
     274                                                continue; 
     275                                        } 
     276 
     277                                        // small fix for XDEBUG_CC_UNUSED 
     278                                        if (isset($coverageInformation[$method->getStartLine()])) 
     279                                        { 
     280                                                unset($coverageInformation[$method->getStartLine()]); 
     281                                        } 
     282 
     283                                        if (isset($coverageInformation[$method->getEndLine()])) 
     284                                        { 
     285                                                unset($coverageInformation[$method->getEndLine()]); 
     286                                        } 
     287 
     288                                        if ($method->isAbstract()) 
     289                                        { 
     290                                                continue; 
     291                                        } 
     292 
     293                                        $linenr = key($coverageInformation); 
     294 
     295                                        while ($linenr < $method->getStartLine()) 
     296                                        { 
     297                                                next($coverageInformation); 
     298                                                $linenr = key($coverageInformation); 
     299                                        } 
     300 
     301                                        if (current($coverageInformation) > 0 && $method->getStartLine() <= $linenr && $linenr <= $method->getEndLine()) 
     302                                        { 
     303                                                $methodscovered++; 
     304                                        } 
     305 
     306                                        $methodcount++; 
    264307                                } 
    265308 
    266                                 if ($method->isAbstract()) 
    267                                 { 
    268                                         continue; 
    269                                 } 
    270  
    271                                 $linenr = key($coverageInformation); 
    272  
    273                                 while ($linenr < $method->getStartLine() && current($coverageInformation) > 0) 
    274                                 { 
    275                                         next($coverageInformation); 
    276                                         $linenr = key($coverageInformation); 
    277                                 } 
    278  
    279                                 if ($method->getStartLine() <= $linenr && $linenr <= $method->getEndLine()) 
    280                                 { 
    281                                         $methodscovered++; 
    282                                 } 
    283  
    284                                 $methodcount++; 
     309                                $statementcount = count($coverageInformation); 
     310                                $statementscovered = count(array_filter($coverageInformation, array($this, 'filterCovered'))); 
     311 
     312                                $classElement->appendChild($this->transformSourceFile($filename, $coverageInformation, $classStartLine)); 
     313 
     314                                $classElement->setAttribute('methodcount', $methodcount); 
     315                                $classElement->setAttribute('methodscovered', $methodscovered); 
     316                                $classElement->setAttribute('statementcount', $statementcount); 
     317                                $classElement->setAttribute('statementscovered', $statementscovered); 
     318                                $classElement->setAttribute('totalcount', $methodcount + $statementcount); 
     319                                $classElement->setAttribute('totalcovered', $methodscovered + $statementscovered); 
    285320                        } 
    286  
    287                         $classStartLine = $reflection->getStartLine(); 
    288  
    289                         $classElement->appendChild($this->transformSourceFile($basename, $filename, $coverageInformation, $classStartLine)); 
    290  
    291                         $classElement->setAttribute('methodcount', $methodcount); 
    292                         $classElement->setAttribute('methodscovered', $methodscovered); 
    293321                } 
    294322        } 
     
    301329                $totalmethodscovered = 0; 
    302330 
     331                $totalstatementcount = 0; 
     332                $totalstatementscovered = 0; 
     333 
    303334                foreach ($packages as $package) 
    304335                { 
    305336                        $methodcount = 0; 
    306337                        $methodscovered = 0; 
     338 
     339                        $statementcount = 0; 
     340                        $statementscovered = 0; 
    307341 
    308342                        $classes = $package->getElementsByTagName('class'); 
     
    312346                                $methodcount += $class->getAttribute('methodcount'); 
    313347                                $methodscovered += $class->getAttribute('methodscovered'); 
     348 
     349                                $statementcount += $class->getAttribute('statementcount'); 
     350                                $statementscovered += $class->getAttribute('statementscovered'); 
    314351                        } 
    315352 
     
    317354                        $package->setAttribute('methodscovered', $methodscovered); 
    318355 
     356                        $package->setAttribute('statementcount', $statementcount); 
     357                        $package->setAttribute('statementscovered', $statementscovered); 
     358 
     359                        $package->setAttribute('totalcount', $methodcount + $statementcount); 
     360                        $package->setAttribute('totalcovered', $methodscovered + $statementscovered); 
     361 
    319362                        $totalmethodcount += $methodcount; 
    320363                        $totalmethodscovered += $methodscovered; 
     364 
     365                        $totalstatementcount += $statementcount; 
     366                        $totalstatementscovered += $statementscovered; 
    321367                } 
    322368 
    323369                $this->doc->documentElement->setAttribute('methodcount', $totalmethodcount); 
    324370                $this->doc->documentElement->setAttribute('methodscovered', $totalmethodscovered); 
     371 
     372                $this->doc->documentElement->setAttribute('statementcount', $totalstatementcount); 
     373                $this->doc->documentElement->setAttribute('statementscovered', $totalstatementscovered); 
     374 
     375                $this->doc->documentElement->setAttribute('totalcount', $totalmethodcount + $totalstatementcount); 
     376                $this->doc->documentElement->setAttribute('totalcovered', $totalmethodscovered + $totalstatementscovered); 
    325377        } 
    326378 
     
    338390                        $file = unserialize($props->getProperty($filename)); 
    339391 
    340                         $this->transformCoverageInformation($file['basename'], $file['fullname'], $file['coverage']); 
     392                        $this->transformCoverageInformation($file['fullname'], $file['coverage']); 
    341393                } 
    342394                 
  • trunk/classes/phing/tasks/ext/coverage/CoverageSetupTask.php

    r34 r42  
    2424require_once 'phing/system/io/Writer.php'; 
    2525require_once 'phing/system/util/Properties.php'; 
     26require_once 'phing/tasks/ext/coverage/CoverageMerger.php'; 
    2627 
    2728/** 
     
    4041        /** the filename of the coverage database */ 
    4142        private $database = "coverage.db"; 
     43 
     44        /** the classpath to use (optional) */ 
     45        private $classpath = NULL; 
    4246 
    4347        /** 
     
    6165        } 
    6266 
     67        function setClasspath(Path $classpath) 
     68        { 
     69                if ($this->classpath === null) 
     70                { 
     71                        $this->classpath = $classpath; 
     72                } 
     73                else 
     74                { 
     75                        $this->classpath->append($classpath); 
     76                } 
     77        } 
     78 
     79        function createClasspath() 
     80        { 
     81                $this->classpath = new Path(); 
     82                return $this->classpath; 
     83        } 
     84         
    6385        /** 
    6486         * Iterate over all filesets and return the filename of all files 
     
    85107                                        $fs = new PhingFile(realpath($ds->getBaseDir()), $file); 
    86108                                         
    87                                         $files[] = array('key' => strtolower($fs->getAbsolutePath()), 'fullname' => $fs->getAbsolutePath(), 'basename' => $file); 
     109                                        $files[] = array('key' => strtolower($fs->getAbsolutePath()), 'fullname' => $fs->getAbsolutePath()); 
    88110                                } 
    89111                        } 
     
    111133                foreach ($files as $file) 
    112134                { 
    113                         $basename = $file['basename']; 
    114135                        $fullname = $file['fullname']; 
    115136                        $filename = $file['key']; 
    116137                         
    117                         $props->setProperty($filename, serialize(array('basename' => $basename, 'fullname' => $fullname, 'coverage' => array()))); 
     138                        $props->setProperty($filename, serialize(array('fullname' => $fullname, 'coverage' => array()))); 
    118139                } 
    119140 
     
    123144 
    124145                $this->project->setProperty('coverage.database', $dbfile->getAbsolutePath()); 
     146         
     147                foreach ($files as $file) 
     148                { 
     149                        $fullname = $file['fullname']; 
     150                         
     151                        xdebug_start_code_coverage(XDEBUG_CC_UNUSED); 
     152                         
     153                        Phing::__import($fullname, $this->classpath); 
     154                         
     155                        $coverage = xdebug_get_code_coverage(); 
     156                         
     157                        xdebug_stop_code_coverage(); 
     158                         
     159                        CoverageMerger::merge($this->project, array($coverage)); 
     160                } 
    125161        } 
    126162} 
  • trunk/etc/coverage-frames.xsl

    r1 r42  
    238238                            <a target="classFrame" href="{$link}"><xsl:value-of select="@name"/></a> 
    239239                            <xsl:choose> 
    240                                                                 <xsl:when test="@methodcount=0"> 
     240                                                                <xsl:when test="@totalcount=0"> 
    241241                                                                        <i> (-)</i> 
    242242                                                                </xsl:when> 
    243243                                                                <xsl:otherwise> 
    244                                                                         <i> (<xsl:value-of select="format-number(@methodscovered div @methodcount, '0.0%')"/>)</i> 
     244                                                                        <i> (<xsl:value-of select="format-number(@totalcovered div @totalcount, '0.0%')"/>)</i> 
    245245                                                                </xsl:otherwise> 
    246246                                                        </xsl:choose> 
     
    299299            <tr> 
    300300                <th width="100%" nowrap="nowrap"></th> 
    301                 <th width="350" colspan="2" nowrap="nowrap">Methods covered</th> 
     301                <th>Statements</th> 
     302                <th>Methods</th> 
     303                <th width="350" colspan="2" nowrap="nowrap">Total coverage</th> 
    302304            </tr> 
    303305            <tr class="a"> 
    304         <td>Total coverage</td> 
     306               <td><b>Project</b></td> 
    305307                <xsl:call-template name="stats.formatted"/> 
    306308            </tr> 
     
    310312            <tr> 
    311313                <th width="100%">Packages</th> 
    312                 <th width="350" colspan="2" nowrap="nowrap">Methods covered</th> 
     314                <th>Statements</th> 
     315                <th>Methods</th> 
     316                <th width="350" colspan="2" nowrap="nowrap">Total coverage</th> 
    313317            </tr> 
    314318            <!-- display packages and sort them via their coverage rate --> 
    315319            <xsl:for-each select="package"> 
    316                 <xsl:sort data-type="number" select="@methodscovered div @methodcount"/> 
     320                <xsl:sort data-type="number" select="@totalcovered div @totalcount"/> 
    317321                <tr> 
    318322                  <xsl:call-template name="alternate-row"/> 
     
    380384                            <a href="{@name}.html" target="classFrame"><xsl:value-of select="@name"/></a> 
    381385                            <xsl:choose> 
    382                                                                 <xsl:when test="@methodcount=0"> 
     386                                                                <xsl:when test="@totalcount=0"> 
    383387                                                                        <i> (-)</i> 
    384388                                                                </xsl:when> 
    385389                                                                <xsl:otherwise> 
    386                                         <i>(<xsl:value-of select="format-number(@methodscovered div @methodcount, '0.0%')"/>)</i> 
     390                                        <i>(<xsl:value-of select="format-number(@totalcovered div @totalcount, '0.0%')"/>)</i> 
    387391                                </xsl:otherwise> 
    388392                            </xsl:choose> 
     
    418422                <tr> 
    419423                    <th width="100%">Package</th> 
    420                     <th width="350" colspan="2" nowrap="nowrap">Methods covered</th> 
     424                    <th>Statements</th> 
     425                    <th>Methods</th> 
     426                    <th width="350" colspan="2" nowrap="nowrap">Total coverage</th> 
    421427                </tr> 
    422428                <xsl:apply-templates select="." mode="stats"/> 
     
    428434                    <tr> 
    429435                        <th width="100%">Classes</th> 
    430                         <th width="350" colspan="2" nowrap="nowrap">Methods covered</th> 
     436                        <th>Statements</th> 
     437                        <th>Methods</th> 
     438                        <th width="350" colspan="2" nowrap="nowrap">Total coverage</th> 
    431439                    </tr> 
    432440                    <xsl:apply-templates select="class" mode="stats"> 
    433                         <xsl:sort data-type="number" select="@methodscovered div @methodcount"/> 
     441                        <xsl:sort data-type="number" select="@totalcovered div @totalcount"/> 
    434442                    </xsl:apply-templates> 
    435443                </xsl:if> 
     
    463471                <tr> 
    464472                    <th width="100%">Source file</th> 
    465                     <th width="250" colspan="2" nowrap="nowrap">Methods covered</th> 
     473                    <th>Statements</th> 
     474                    <th>Methods</th> 
     475                    <th width="250" colspan="2" nowrap="nowrap">Total coverage</th> 
    466476                </tr> 
    467477                <tr> 
     
    526536<xsl:template name="stats.formatted"> 
    527537    <xsl:choose> 
     538        <xsl:when test="@statementcount=0"> 
     539            <td>-</td> 
     540        </xsl:when> 
     541        <xsl:otherwise> 
     542            <td> 
     543            <xsl:value-of select="format-number(@statementscovered div @statementcount,'0.0%')"/> 
     544            </td> 
     545        </xsl:otherwise> 
     546    </xsl:choose> 
     547    <xsl:choose> 
    528548        <xsl:when test="@methodcount=0"> 
     549            <td>-</td> 
     550        </xsl:when> 
     551        <xsl:otherwise> 
     552            <td> 
     553            <xsl:value-of select="format-number(@methodscovered div @methodcount,'0.0%')"/> 
     554            </td> 
     555        </xsl:otherwise> 
     556    </xsl:choose> 
     557    <xsl:choose> 
     558        <xsl:when test="@totalcount=0"> 
    529559            <td>-</td> 
    530560            <td> 
     
    538568        <xsl:otherwise> 
    539569            <td> 
    540             <xsl:value-of select="format-number(@methodscovered div @methodcount,'0.0%')"/> 
     570            <xsl:value-of select="format-number(@totalcovered div @totalcount,'0.0%')"/> 
    541571            </td> 
    542572            <td> 
    543             <xsl:variable name="leftwidth"><xsl:value-of select="format-number((@methodscovered * 200) div @methodcount,'0')"/></xsl:variable> 
    544             <xsl:variable name="rightwidth"><xsl:value-of select="format-number(200 - (@methodscovered * 200) div @methodcount,'0')"/></xsl:variable> 
     573            <xsl:variable name="leftwidth"><xsl:value-of select="format-number((@totalcovered * 200) div @totalcount,'0')"/></xsl:variable> 
     574            <xsl:variable name="rightwidth"><xsl:value-of select="format-number(200 - (@totalcovered * 200) div @totalcount,'0')"/></xsl:variable> 
    545575            <table cellspacing="0" cellpadding="0" border="0" width="100%" style="display: inline"> 
    546576                <tr>