Created
June 26, 2022 18:31
-
-
Save bodik/0f03c4e0a2c1d87245af5dccfface4ac to your computer and use it in GitHub Desktop.
Symfony coverage generator
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php // phpcs:disable PSR1.Files.SideEffects.FoundWithSymbols | |
/** | |
* coverage-checker2.php, improved version | |
* https://ocramius.github.io/blog/automated-code-coverage-check-for-github-pull-requests-with-travis | |
*/ | |
namespace CoverageChecker; | |
use InvalidArgumentException; | |
use SimpleXmlElement; | |
/** | |
* coverage checker inspired by pycoverage output | |
*/ | |
class CoverageChecker | |
{ | |
/** | |
* https://stackoverflow.com/questions/13592547/how-to-group-numbers-in-ranges-using-php | |
*/ | |
public static function formatSequence(array $numbers): string | |
{ | |
$groups = []; | |
$result = []; | |
sort($numbers); | |
for ($i = 0; $i < count($numbers); $i++) { | |
if ($i > 0 && ($numbers[$i - 1] === $numbers[$i] - 1)) { | |
array_push($groups[count($groups) - 1], $numbers[$i]); | |
} else { | |
/* First value or no match, create a new group */ | |
array_push($groups, [$numbers[$i]]); | |
} | |
} | |
foreach ($groups as $group) { | |
if (count($group) === 1) { | |
/* Single value */ | |
array_push($result, $group[0]); | |
} else { | |
/* Range of values, minimum in [0], maximum in [count($group) - 1] */ | |
array_push($result, "${group[0]}-${group[count($group) - 1]}"); | |
} | |
} | |
return implode(',', $result); | |
} | |
/** | |
* return overall coverage statistic | |
*/ | |
public static function overallCoverage(SimpleXMLElement $xml): float | |
{ | |
$metrics = $xml->xpath('//metrics'); | |
$totalElements = 0; | |
$checkedElements = 0; | |
foreach ($metrics as $metric) { | |
$totalElements += (int) $metric['elements']; | |
$checkedElements += (int) $metric['coveredelements']; | |
} | |
return ($checkedElements / $totalElements) * 100; | |
} | |
/** | |
* return coverage statistics array for single file | |
*/ | |
public static function fileCoverage(SimpleXMLElement $fileElem): array | |
{ | |
$name = (string) $fileElem['name']; | |
$metrics = $fileElem->xpath('./metrics')[0]; | |
/* elements = conditionals + statements */ | |
$elements = (int) $metrics['elements']; | |
$coveredelements = (int) $metrics['coveredelements']; | |
$miss = $elements - $coveredelements; | |
if ($elements === 0) { | |
$coverage = 100; | |
} else { | |
$coverage = ($coveredelements / $elements) * 100; | |
} | |
$missedLines = array_map( | |
function ($item) { | |
return (int) $item['num']; | |
}, | |
$fileElem->xpath('./line[@count="0"]') | |
); | |
$missing = self::formatSequence($missedLines); | |
return [$name, $elements, $miss, $coverage, $missing]; | |
} | |
/** | |
* main | |
*/ | |
public static function main(string $inputFile, int $percentage): int | |
{ | |
if (!file_exists($inputFile)) { | |
throw new InvalidArgumentException('Invalid input file provided'); | |
} | |
if (($percentage < 0) || ($percentage > 100)) { | |
throw new InvalidArgumentException('Invalid pecrentage'); | |
} | |
$xmldata = new SimpleXMLElement(file_get_contents($inputFile)); | |
$covdata = array_map(['self', 'fileCoverage'], $xmldata->xpath('//file')); | |
$filenames = array_map( | |
function ($item) { | |
return $item[0]; | |
}, | |
$covdata | |
); | |
$longestFilename = max(array_map('strlen', $filenames)); | |
$coverage = self::overallCoverage($xmldata); | |
$fmt = "%-${longestFilename}s %5s %5s %5s%% %s\n"; | |
vprintf($fmt, ['Filename', 'Stmts', 'Miss', 'Cover', 'Missing']); | |
printf("%s\n", str_repeat('-', $longestFilename + 34)); | |
foreach ($covdata as $item) { | |
vprintf($fmt, $item); | |
} | |
printf("%s\n", str_repeat('-', $longestFilename + 34)); | |
vprintf($fmt, ['TOTAL', '', '', sprintf('%.2f', $coverage), '']); | |
if ($coverage < $percentage) { | |
return 1; | |
} | |
return 0; | |
} | |
} | |
CoverageChecker::main($argv[1], (int) $argv[2]); |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
coverage: | |
vendor/bin/simple-phpunit --stop-on-error --coverage-clove .coverage.clove | |
php bin/coverage_checker.php .coverage.clove 100 | tee .coverage.log |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment