Spaces:
Sleeping
Sleeping
processmaker-community / processmaker-files /thirdparty /phing /tasks /ext /coverage /CoverageReportTask.php
| /** | |
| * $Id: CoverageReportTask.php 3076 2006-12-18 08:52:12Z fabien $ | |
| * | |
| * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | |
| * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | |
| * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | |
| * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | |
| * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | |
| * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | |
| * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | |
| * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | |
| * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | |
| * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | |
| * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |
| * | |
| * This software consists of voluntary contributions made by many individuals | |
| * and is licensed under the LGPL. For more information please see | |
| * <http://phing.info>. | |
| */ | |
| require_once 'phing/TaskPhing.php'; | |
| require_once 'phing/system/io/PhingFile.php'; | |
| require_once 'phing/system/io/Writer.php'; | |
| require_once 'phing/system/util/Properties.php'; | |
| require_once 'phing/tasks/ext/phpunit2/PHPUnit2Util.php'; | |
| require_once 'phing/tasks/ext/coverage/CoverageReportTransformer.php'; | |
| /** | |
| * Transforms information in a code coverage database to XML | |
| * | |
| * @author Michiel Rook <michiel.rook@gmail.com> | |
| * @version $Id: CoverageReportTask.php 3076 2006-12-18 08:52:12Z fabien $ | |
| * @package phing.tasks.ext.coverage | |
| * @since 2.1.0 | |
| */ | |
| class CoverageReportTask extends TaskPhing | |
| { | |
| private $outfile = "coverage.xml"; | |
| private $transformers = array(); | |
| /** the classpath to use (optional) */ | |
| private $classpath = NULL; | |
| /** the path to the GeSHi library (optional) */ | |
| private $geshipath = ""; | |
| /** the path to the GeSHi language files (optional) */ | |
| private $geshilanguagespath = ""; | |
| function setClasspath(Path $classpath) | |
| { | |
| if ($this->classpath === null) | |
| { | |
| $this->classpath = $classpath; | |
| } | |
| else | |
| { | |
| $this->classpath->append($classpath); | |
| } | |
| } | |
| function createClasspath() | |
| { | |
| $this->classpath = new Path(); | |
| return $this->classpath; | |
| } | |
| function setGeshiPath($path) | |
| { | |
| $this->geshipath = $path; | |
| } | |
| function setGeshiLanguagesPath($path) | |
| { | |
| $this->geshilanguagespath = $path; | |
| } | |
| function __construct() | |
| { | |
| $this->doc = new DOMDocument(); | |
| $this->doc->encoding = 'UTF-8'; | |
| $this->doc->formatOutput = true; | |
| $this->doc->appendChild($this->doc->createElement('snapshot')); | |
| } | |
| function setOutfile($outfile) | |
| { | |
| $this->outfile = $outfile; | |
| } | |
| /** | |
| * Generate a report based on the XML created by this task | |
| */ | |
| function createReport() | |
| { | |
| $transformer = new CoverageReportTransformer($this); | |
| $this->transformers[] = $transformer; | |
| return $transformer; | |
| } | |
| protected function getPackageElement($packageName) | |
| { | |
| $packages = $this->doc->documentElement->getElementsByTagName('package'); | |
| foreach ($packages as $package) | |
| { | |
| if ($package->getAttribute('name') == $packageName) | |
| { | |
| return $package; | |
| } | |
| } | |
| return NULL; | |
| } | |
| protected function addClassToPackage($classname, $element) | |
| { | |
| $packageName = PHPUnit2Util::getPackageName($classname); | |
| $package = $this->getPackageElement($packageName); | |
| if ($package === NULL) | |
| { | |
| $package = $this->doc->createElement('package'); | |
| $package->setAttribute('name', $packageName); | |
| $this->doc->documentElement->appendChild($package); | |
| } | |
| $package->appendChild($element); | |
| } | |
| protected function stripDiv($source) | |
| { | |
| $openpos = strpos($source, "<div"); | |
| $closepos = strpos($source, ">", $openpos); | |
| $line = substr($source, $closepos + 1); | |
| $tagclosepos = strpos($line, "</div>"); | |
| $line = substr($line, 0, $tagclosepos); | |
| return $line; | |
| } | |
| protected function highlightSourceFile($filename) | |
| { | |
| if ($this->geshipath) | |
| { | |
| require_once $this->geshipath . '/geshi.php'; | |
| $source = file_get_contents($filename); | |
| $geshi = new GeSHi($source, 'php', $this->geshilanguagespath); | |
| $geshi->enable_line_numbers(GESHI_NORMAL_LINE_NUMBERS); | |
| $geshi->enable_strict_mode(true); | |
| $geshi->enable_classes(true); | |
| $geshi->set_url_for_keyword_group(3, ''); | |
| $html = $geshi->parse_code(); | |
| $lines = explode("<li>|</li>", $html); | |
| // skip first and last line | |
| array_pop($lines); | |
| array_shift($lines); | |
| $lines = array_filter($lines); | |
| $lines = array_map(array($this, 'stripDiv'), $lines); | |
| return $lines; | |
| } | |
| else | |
| { | |
| $lines = file($filename); | |
| for ($i = 0; $i < count($lines); $i++) | |
| { | |
| $line = $lines[$i]; | |
| $line = rtrim($line); | |
| $lines[$i] = utf8_encode($line); | |
| } | |
| return $lines; | |
| } | |
| } | |
| protected function transformSourceFile($filename, $coverageInformation, $classStartLine = 1) | |
| { | |
| $sourceElement = $this->doc->createElement('sourcefile'); | |
| $sourceElement->setAttribute('name', basename($filename)); | |
| $filelines = $this->highlightSourceFile($filename); | |
| $linenr = 1; | |
| foreach ($filelines as $line) | |
| { | |
| $lineElement = $this->doc->createElement('sourceline'); | |
| $lineElement->setAttribute('coveredcount', (isset($coverageInformation[$linenr]) ? $coverageInformation[$linenr] : '0')); | |
| if ($linenr == $classStartLine) | |
| { | |
| $lineElement->setAttribute('startclass', 1); | |
| } | |
| $textnode = $this->doc->createTextNode($line); | |
| $lineElement->appendChild($textnode); | |
| $sourceElement->appendChild($lineElement); | |
| $linenr++; | |
| } | |
| return $sourceElement; | |
| } | |
| protected function filterCovered($var) | |
| { | |
| return ($var >= 0); | |
| } | |
| protected function transformCoverageInformation($filename, $coverageInformation) | |
| { | |
| // Strip last line of coverage information | |
| end($coverageInformation); | |
| unset($coverageInformation[key($coverageInformation)]); | |
| $classes = PHPUnit2Util::getDefinedClasses($filename, $this->classpath); | |
| if (is_array($classes)) | |
| { | |
| foreach ($classes as $classname) | |
| { | |
| $reflection = new ReflectionClass($classname); | |
| $methods = $reflection->getMethods(); | |
| $classElement = $this->doc->createElement('class'); | |
| $classElement->setAttribute('name', $reflection->getName()); | |
| $this->addClassToPackage($reflection->getName(), $classElement); | |
| $classStartLine = $reflection->getStartLine(); | |
| $methodscovered = 0; | |
| $methodcount = 0; | |
| // Strange PHP5 reflection bug, classes without parent class or implemented interfaces seem to start one line off | |
| if ($reflection->getParentClass() == NULL && count($reflection->getInterfaces()) == 0) | |
| { | |
| unset($coverageInformation[$classStartLine + 1]); | |
| } | |
| else | |
| { | |
| unset($coverageInformation[$classStartLine]); | |
| } | |
| reset($coverageInformation); | |
| foreach ($methods as $method) | |
| { | |
| // PHP5 reflection considers methods of a parent class to be part of a subclass, we don't | |
| if ($method->getDeclaringClass()->getName() != $reflection->getName()) | |
| { | |
| continue; | |
| } | |
| // small fix for XDEBUG_CC_UNUSED | |
| if (isset($coverageInformation[$method->getStartLine()])) | |
| { | |
| unset($coverageInformation[$method->getStartLine()]); | |
| } | |
| if (isset($coverageInformation[$method->getEndLine()])) | |
| { | |
| unset($coverageInformation[$method->getEndLine()]); | |
| } | |
| if ($method->isAbstract()) | |
| { | |
| continue; | |
| } | |
| $linenr = key($coverageInformation); | |
| while ($linenr !== null && $linenr < $method->getStartLine()) | |
| { | |
| next($coverageInformation); | |
| $linenr = key($coverageInformation); | |
| } | |
| if (current($coverageInformation) > 0 && $method->getStartLine() <= $linenr && $linenr <= $method->getEndLine()) | |
| { | |
| $methodscovered++; | |
| } | |
| $methodcount++; | |
| } | |
| $statementcount = count($coverageInformation); | |
| $statementscovered = count(array_filter($coverageInformation, array($this, 'filterCovered'))); | |
| $classElement->appendChild($this->transformSourceFile($filename, $coverageInformation, $classStartLine)); | |
| $classElement->setAttribute('methodcount', $methodcount); | |
| $classElement->setAttribute('methodscovered', $methodscovered); | |
| $classElement->setAttribute('statementcount', $statementcount); | |
| $classElement->setAttribute('statementscovered', $statementscovered); | |
| $classElement->setAttribute('totalcount', $methodcount + $statementcount); | |
| $classElement->setAttribute('totalcovered', $methodscovered + $statementscovered); | |
| } | |
| } | |
| } | |
| protected function calculateStatistics() | |
| { | |
| $packages = $this->doc->documentElement->getElementsByTagName('package'); | |
| $totalmethodcount = 0; | |
| $totalmethodscovered = 0; | |
| $totalstatementcount = 0; | |
| $totalstatementscovered = 0; | |
| foreach ($packages as $package) | |
| { | |
| $methodcount = 0; | |
| $methodscovered = 0; | |
| $statementcount = 0; | |
| $statementscovered = 0; | |
| $classes = $package->getElementsByTagName('class'); | |
| foreach ($classes as $class) | |
| { | |
| $methodcount += $class->getAttribute('methodcount'); | |
| $methodscovered += $class->getAttribute('methodscovered'); | |
| $statementcount += $class->getAttribute('statementcount'); | |
| $statementscovered += $class->getAttribute('statementscovered'); | |
| } | |
| $package->setAttribute('methodcount', $methodcount); | |
| $package->setAttribute('methodscovered', $methodscovered); | |
| $package->setAttribute('statementcount', $statementcount); | |
| $package->setAttribute('statementscovered', $statementscovered); | |
| $package->setAttribute('totalcount', $methodcount + $statementcount); | |
| $package->setAttribute('totalcovered', $methodscovered + $statementscovered); | |
| $totalmethodcount += $methodcount; | |
| $totalmethodscovered += $methodscovered; | |
| $totalstatementcount += $statementcount; | |
| $totalstatementscovered += $statementscovered; | |
| } | |
| $this->doc->documentElement->setAttribute('methodcount', $totalmethodcount); | |
| $this->doc->documentElement->setAttribute('methodscovered', $totalmethodscovered); | |
| $this->doc->documentElement->setAttribute('statementcount', $totalstatementcount); | |
| $this->doc->documentElement->setAttribute('statementscovered', $totalstatementscovered); | |
| $this->doc->documentElement->setAttribute('totalcount', $totalmethodcount + $totalstatementcount); | |
| $this->doc->documentElement->setAttribute('totalcovered', $totalmethodscovered + $totalstatementscovered); | |
| } | |
| function main() | |
| { | |
| $this->log("Transforming coverage report"); | |
| $database = new PhingFile($this->project->getProperty('coverage.database')); | |
| $props = new Properties(); | |
| $props->load($database); | |
| foreach ($props->keys() as $filename) | |
| { | |
| $file = unserialize($props->getProperty($filename)); | |
| $this->transformCoverageInformation($file['fullname'], $file['coverage']); | |
| } | |
| $this->calculateStatistics(); | |
| $this->doc->save($this->outfile); | |
| foreach ($this->transformers as $transformer) | |
| { | |
| $transformer->setXmlDocument($this->doc); | |
| $transformer->transform(); | |
| } | |
| } | |
| } | |