Skip to content

Commit

Permalink
Improved Cobertura report
Browse files Browse the repository at this point in the history
  • Loading branch information
jhoffland committed Dec 22, 2022
1 parent 709ee60 commit 51de9c8
Show file tree
Hide file tree
Showing 13 changed files with 808 additions and 310 deletions.
272 changes: 2 additions & 270 deletions src/Report/Cobertura.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,18 +9,11 @@
*/
namespace SebastianBergmann\CodeCoverage\Report;

use function basename;
use function count;
use function dirname;
use function file_put_contents;
use function preg_match;
use function range;
use function str_replace;
use function time;
use DOMImplementation;
use SebastianBergmann\CodeCoverage\CodeCoverage;
use SebastianBergmann\CodeCoverage\Driver\WriteOperationFailedException;
use SebastianBergmann\CodeCoverage\Node\File;
use SebastianBergmann\CodeCoverage\Report\Cobertura\CoberturaCoverage;
use SebastianBergmann\CodeCoverage\Util\Filesystem;

final class Cobertura
Expand All @@ -30,268 +23,7 @@ final class Cobertura
*/
public function process(CodeCoverage $coverage, ?string $target = null): string
{
$time = (string) time();

$report = $coverage->getReport();

$implementation = new DOMImplementation;

$documentType = $implementation->createDocumentType(
'coverage',
'',
'http://cobertura.sourceforge.net/xml/coverage-04.dtd'
);

$document = $implementation->createDocument('', '', $documentType);
$document->xmlVersion = '1.0';
$document->encoding = 'UTF-8';
$document->formatOutput = true;

$coverageElement = $document->createElement('coverage');

$linesValid = $report->numberOfExecutableLines();
$linesCovered = $report->numberOfExecutedLines();
$lineRate = $linesValid === 0 ? 0 : ($linesCovered / $linesValid);
$coverageElement->setAttribute('line-rate', (string) $lineRate);

$branchesValid = $report->numberOfExecutableBranches();
$branchesCovered = $report->numberOfExecutedBranches();
$branchRate = $branchesValid === 0 ? 0 : ($branchesCovered / $branchesValid);
$coverageElement->setAttribute('branch-rate', (string) $branchRate);

$coverageElement->setAttribute('lines-covered', (string) $report->numberOfExecutedLines());
$coverageElement->setAttribute('lines-valid', (string) $report->numberOfExecutableLines());
$coverageElement->setAttribute('branches-covered', (string) $report->numberOfExecutedBranches());
$coverageElement->setAttribute('branches-valid', (string) $report->numberOfExecutableBranches());
$coverageElement->setAttribute('complexity', '');
$coverageElement->setAttribute('version', '0.4');
$coverageElement->setAttribute('timestamp', $time);

$document->appendChild($coverageElement);

$sourcesElement = $document->createElement('sources');
$coverageElement->appendChild($sourcesElement);

$sourceElement = $document->createElement('source', $report->pathAsString());
$sourcesElement->appendChild($sourceElement);

$packagesElement = $document->createElement('packages');
$coverageElement->appendChild($packagesElement);

$complexity = 0;

foreach ($report as $item) {
if (!$item instanceof File) {
continue;
}

$packageElement = $document->createElement('package');
$packageComplexity = 0;

$packageElement->setAttribute('name', str_replace($report->pathAsString() . DIRECTORY_SEPARATOR, '', $item->pathAsString()));

$linesValid = $item->numberOfExecutableLines();
$linesCovered = $item->numberOfExecutedLines();
$lineRate = $linesValid === 0 ? 0 : ($linesCovered / $linesValid);

$packageElement->setAttribute('line-rate', (string) $lineRate);

$branchesValid = $item->numberOfExecutableBranches();
$branchesCovered = $item->numberOfExecutedBranches();
$branchRate = $branchesValid === 0 ? 0 : ($branchesCovered / $branchesValid);

$packageElement->setAttribute('branch-rate', (string) $branchRate);

$packageElement->setAttribute('complexity', '');
$packagesElement->appendChild($packageElement);

$classesElement = $document->createElement('classes');

$packageElement->appendChild($classesElement);

$classes = $item->classesAndTraits();
$coverageData = $item->lineCoverageData();

foreach ($classes as $className => $class) {
$complexity += $class['ccn'];
$packageComplexity += $class['ccn'];

if (!empty($class['package']['namespace'])) {
$className = $class['package']['namespace'] . '\\' . $className;
}

$linesValid = $class['executableLines'];
$linesCovered = $class['executedLines'];
$lineRate = $linesValid === 0 ? 0 : ($linesCovered / $linesValid);

$branchesValid = $class['executableBranches'];
$branchesCovered = $class['executedBranches'];
$branchRate = $branchesValid === 0 ? 0 : ($branchesCovered / $branchesValid);

$classElement = $document->createElement('class');

$classElement->setAttribute('name', $className);
$classElement->setAttribute('filename', str_replace($report->pathAsString() . DIRECTORY_SEPARATOR, '', $item->pathAsString()));
$classElement->setAttribute('line-rate', (string) $lineRate);
$classElement->setAttribute('branch-rate', (string) $branchRate);
$classElement->setAttribute('complexity', (string) $class['ccn']);

$classesElement->appendChild($classElement);

$methodsElement = $document->createElement('methods');

$classElement->appendChild($methodsElement);

$classLinesElement = $document->createElement('lines');

$classElement->appendChild($classLinesElement);

foreach ($class['methods'] as $methodName => $method) {
if ($method['executableLines'] === 0) {
continue;
}

preg_match("/\((.*?)\)/", $method['signature'], $signature);

$linesValid = $method['executableLines'];
$linesCovered = $method['executedLines'];
$lineRate = $linesValid === 0 ? 0 : ($linesCovered / $linesValid);

$branchesValid = $method['executableBranches'];
$branchesCovered = $method['executedBranches'];
$branchRate = $branchesValid === 0 ? 0 : ($branchesCovered / $branchesValid);

$methodElement = $document->createElement('method');

$methodElement->setAttribute('name', $methodName);
$methodElement->setAttribute('signature', $signature[1]);
$methodElement->setAttribute('line-rate', (string) $lineRate);
$methodElement->setAttribute('branch-rate', (string) $branchRate);
$methodElement->setAttribute('complexity', (string) $method['ccn']);

$methodLinesElement = $document->createElement('lines');

$methodElement->appendChild($methodLinesElement);

foreach (range($method['startLine'], $method['endLine']) as $line) {
if (!isset($coverageData[$line]) || $coverageData[$line] === null) {
continue;
}
$methodLineElement = $document->createElement('line');

$methodLineElement->setAttribute('number', (string) $line);
$methodLineElement->setAttribute('hits', (string) count($coverageData[$line]));

$methodLinesElement->appendChild($methodLineElement);

$classLineElement = $methodLineElement->cloneNode();

$classLinesElement->appendChild($classLineElement);
}

$methodsElement->appendChild($methodElement);
}
}

if ($report->numberOfFunctions() === 0) {
$packageElement->setAttribute('complexity', (string) $packageComplexity);

continue;
}

$functionsComplexity = 0;
$functionsLinesValid = 0;
$functionsLinesCovered = 0;
$functionsBranchesValid = 0;
$functionsBranchesCovered = 0;

$classElement = $document->createElement('class');
$classElement->setAttribute('name', basename($item->pathAsString()));
$classElement->setAttribute('filename', str_replace($report->pathAsString() . DIRECTORY_SEPARATOR, '', $item->pathAsString()));

$methodsElement = $document->createElement('methods');

$classElement->appendChild($methodsElement);

$classLinesElement = $document->createElement('lines');

$classElement->appendChild($classLinesElement);

$functions = $report->functions();

foreach ($functions as $functionName => $function) {
if ($function['executableLines'] === 0) {
continue;
}

$complexity += $function['ccn'];
$packageComplexity += $function['ccn'];
$functionsComplexity += $function['ccn'];

$linesValid = $function['executableLines'];
$linesCovered = $function['executedLines'];
$lineRate = $linesValid === 0 ? 0 : ($linesCovered / $linesValid);

$functionsLinesValid += $linesValid;
$functionsLinesCovered += $linesCovered;

$branchesValid = $function['executableBranches'];
$branchesCovered = $function['executedBranches'];
$branchRate = $branchesValid === 0 ? 0 : ($branchesCovered / $branchesValid);

$functionsBranchesValid += $branchesValid;
$functionsBranchesCovered += $branchesValid;

$methodElement = $document->createElement('method');

$methodElement->setAttribute('name', $functionName);
$methodElement->setAttribute('signature', $function['signature']);
$methodElement->setAttribute('line-rate', (string) $lineRate);
$methodElement->setAttribute('branch-rate', (string) $branchRate);
$methodElement->setAttribute('complexity', (string) $function['ccn']);

$methodLinesElement = $document->createElement('lines');

$methodElement->appendChild($methodLinesElement);

foreach (range($function['startLine'], $function['endLine']) as $line) {
if (!isset($coverageData[$line]) || $coverageData[$line] === null) {
continue;
}
$methodLineElement = $document->createElement('line');

$methodLineElement->setAttribute('number', (string) $line);
$methodLineElement->setAttribute('hits', (string) count($coverageData[$line]));

$methodLinesElement->appendChild($methodLineElement);

$classLineElement = $methodLineElement->cloneNode();

$classLinesElement->appendChild($classLineElement);
}

$methodsElement->appendChild($methodElement);
}

$packageElement->setAttribute('complexity', (string) $packageComplexity);

if ($functionsLinesValid === 0) {
continue;
}

$lineRate = $functionsLinesCovered / $functionsLinesValid;
$branchRate = $functionsBranchesValid === 0 ? 0 : ($functionsBranchesCovered / $functionsBranchesValid);

$classElement->setAttribute('line-rate', (string) $lineRate);
$classElement->setAttribute('branch-rate', (string) $branchRate);
$classElement->setAttribute('complexity', (string) $functionsComplexity);

$classesElement->appendChild($classElement);
}

$coverageElement->setAttribute('complexity', (string) $complexity);

$buffer = $document->saveXML();
$buffer = CoberturaCoverage::create($coverage->getReport())->generateDocument()->saveXML();

if ($target !== null) {
Filesystem::createDirectory(dirname($target));
Expand Down
Loading

0 comments on commit 51de9c8

Please sign in to comment.