<?php
class PHP_CodeCoverage_Report_Text {
protected $outputStream;
protected $lowUpperBound;
protected $highLowerBound;
protected $showUncoveredFiles;
protected $colors = array(
'green' => "\33[30;42m",
'yellow' => "\33[30;43m",
'red' => "\33[37;41m",
'header' => "\33[47;40m",
'reset' => "\33[0m",
'eol' => "\33[2K",
);
public function __construct(PHPUnit_Util_Printer $outputStream, $lowUpperBound, $highLowerBound, $showUncoveredFiles) {
$this->outputStream = $outputStream;
$this->lowUpperBound = $lowUpperBound;
$this->highLowerBound = $highLowerBound;
$this->showUncoveredFiles = $showUncoveredFiles;
}
public function process(PHP_CodeCoverage $coverage, $showColors = FALSE) {
$output = '';
$report = $coverage
->getReport();
unset($coverage);
$colors = array(
'header' => '',
'classes' => '',
'methods' => '',
'lines' => '',
'reset' => '',
'eol' => '',
);
if ($showColors) {
$colors['classes'] = $this
->getCoverageColor($report
->getNumTestedClassesAndTraits(), $report
->getNumClassesAndTraits());
$colors['methods'] = $this
->getCoverageColor($report
->getNumTestedMethods(), $report
->getNumMethods());
$colors['lines'] = $this
->getCoverageColor($report
->getNumExecutedLines(), $report
->getNumExecutableLines());
$colors['reset'] = $this->colors['reset'];
$colors['header'] = $this->colors['header'];
$colors['eol'] = $this->colors['eol'];
}
$output .= PHP_EOL . PHP_EOL . $colors['header'] . 'Code Coverage Report ';
$output .= PHP_EOL . date(' Y-m-d H:i:s', $_SERVER['REQUEST_TIME']) . PHP_EOL;
$output .= PHP_EOL . ' Summary: ' . PHP_EOL . $colors['reset'] . $colors['classes'] . $colors['eol'] . ' Classes: ' . PHP_CodeCoverage_Util::percent($report
->getNumTestedClassesAndTraits(), $report
->getNumClassesAndTraits(), TRUE) . ' (' . $report
->getNumTestedClassesAndTraits() . '/' . $report
->getNumClassesAndTraits() . ')' . PHP_EOL . $colors['eol'] . $colors['methods'] . $colors['eol'] . ' Methods: ' . PHP_CodeCoverage_Util::percent($report
->getNumTestedMethods(), $report
->getNumMethods(), TRUE) . ' (' . $report
->getNumTestedMethods() . '/' . $report
->getNumMethods() . ')' . PHP_EOL . $colors['eol'] . $colors['lines'] . $colors['eol'] . ' Lines: ' . PHP_CodeCoverage_Util::percent($report
->getNumExecutedLines(), $report
->getNumExecutableLines(), TRUE) . ' (' . $report
->getNumExecutedLines() . '/' . $report
->getNumExecutableLines() . ')' . PHP_EOL . $colors['reset'] . $colors['eol'];
$classCoverage = array();
foreach ($report as $item) {
if (!$item instanceof PHP_CodeCoverage_Report_Node_File) {
continue;
}
$classes = $item
->getClassesAndTraits();
$coverage = $item
->getCoverageData();
$lines = array();
$ignoredLines = $item
->getIgnoredLines();
foreach ($classes as $className => $class) {
$classStatements = 0;
$coveredClassStatements = 0;
$coveredMethods = 0;
foreach ($class['methods'] as $method) {
$methodCount = 0;
$methodLines = 0;
$methodLinesCovered = 0;
for ($i = $method['startLine']; $i <= $method['endLine']; $i++) {
if (isset($ignoredLines[$i])) {
continue;
}
$add = TRUE;
$count = 0;
if (isset($coverage[$i])) {
if ($coverage[$i] !== NULL) {
$classStatements++;
$methodLines++;
}
else {
$add = FALSE;
}
$count = count($coverage[$i]);
if ($count > 0) {
$coveredClassStatements++;
$methodLinesCovered++;
}
}
else {
$add = FALSE;
}
$methodCount = max($methodCount, $count);
if ($add) {
$lines[$i] = array(
'count' => $count,
'type' => 'stmt',
);
}
}
if ($methodCount > 0) {
$coveredMethods++;
}
}
if (!empty($class['package']['namespace'])) {
$namespace = '\\' . $class['package']['namespace'] . '::';
}
else {
if (!empty($class['package']['fullPackage'])) {
$namespace = '@' . $class['package']['fullPackage'] . '::';
}
else {
$namespace = '';
}
}
$classCoverage[$namespace . $className] = array(
'namespace' => $namespace,
'className ' => $className,
'methodsCovered' => $coveredMethods,
'methodCount' => count($class['methods']),
'statementsCovered' => $coveredClassStatements,
'statementCount' => $classStatements,
);
}
}
ksort($classCoverage);
$methodColor = '';
$linesColor = '';
$resetColor = '';
foreach ($classCoverage as $fullQualifiedPath => $classInfo) {
if ($classInfo['statementsCovered'] != 0 || $this->showUncoveredFiles) {
if ($showColors) {
$methodColor = $this
->getCoverageColor($classInfo['methodsCovered'], $classInfo['methodCount']);
$linesColor = $this
->getCoverageColor($classInfo['statementsCovered'], $classInfo['statementCount']);
$resetColor = $colors['reset'];
}
$output .= PHP_EOL . $fullQualifiedPath . PHP_EOL . ' ' . $methodColor . 'Methods: ' . $this
->printCoverageCounts($classInfo['methodsCovered'], $classInfo['methodCount'], 2) . $resetColor . ' ' . ' ' . $linesColor . 'Lines: ' . $this
->printCoverageCounts($classInfo['statementsCovered'], $classInfo['statementCount'], 3) . $resetColor;
}
}
$this->outputStream
->write($output . PHP_EOL);
}
protected function getCoverageColor($numberOfCoveredElements, $totalNumberOfElements) {
$coverage = PHP_CodeCoverage_Util::percent($numberOfCoveredElements, $totalNumberOfElements);
if ($coverage > $this->highLowerBound) {
return $this->colors['green'];
}
else {
if ($coverage > $this->lowUpperBound) {
return $this->colors['yellow'];
}
}
return $this->colors['red'];
}
protected function printCoverageCounts($numberOfCoveredElements, $totalNumberOfElements, $presicion) {
$format = '%' . $presicion . 's';
return PHP_CodeCoverage_Util::percent($numberOfCoveredElements, $totalNumberOfElements, TRUE, TRUE) . ' (' . sprintf($format, $numberOfCoveredElements) . '/' . sprintf($format, $totalNumberOfElements) . ')';
}
}