Chris@0: Chris@0: * Chris@0: * For the full copyright and license information, please view the LICENSE Chris@0: * file that was distributed with this source code. Chris@0: */ Chris@0: Chris@0: /** Chris@0: * Generates human readable output from an PHP_CodeCoverage object. Chris@0: * Chris@0: * The output gets put into a text file our written to the CLI. Chris@0: * Chris@0: * @since Class available since Release 1.1.0 Chris@0: */ Chris@0: class PHP_CodeCoverage_Report_Text Chris@0: { Chris@0: protected $lowUpperBound; Chris@0: protected $highLowerBound; Chris@0: protected $showUncoveredFiles; Chris@0: protected $showOnlySummary; Chris@0: Chris@0: protected $colors = array( Chris@0: 'green' => "\x1b[30;42m", Chris@0: 'yellow' => "\x1b[30;43m", Chris@0: 'red' => "\x1b[37;41m", Chris@0: 'header' => "\x1b[1;37;40m", Chris@0: 'reset' => "\x1b[0m", Chris@0: 'eol' => "\x1b[2K", Chris@0: ); Chris@0: Chris@0: public function __construct($lowUpperBound, $highLowerBound, $showUncoveredFiles, $showOnlySummary) Chris@0: { Chris@0: $this->lowUpperBound = $lowUpperBound; Chris@0: $this->highLowerBound = $highLowerBound; Chris@0: $this->showUncoveredFiles = $showUncoveredFiles; Chris@0: $this->showOnlySummary = $showOnlySummary; Chris@0: } Chris@0: Chris@0: /** Chris@0: * @param PHP_CodeCoverage $coverage Chris@0: * @param bool $showColors Chris@0: * @return string Chris@0: */ Chris@0: public function process(PHP_CodeCoverage $coverage, $showColors = false) Chris@0: { Chris@0: $output = PHP_EOL . PHP_EOL; Chris@0: $report = $coverage->getReport(); Chris@0: unset($coverage); Chris@0: Chris@0: $colors = array( Chris@0: 'header' => '', Chris@0: 'classes' => '', Chris@0: 'methods' => '', Chris@0: 'lines' => '', Chris@0: 'reset' => '', Chris@0: 'eol' => '' Chris@0: ); Chris@0: Chris@0: if ($showColors) { Chris@0: $colors['classes'] = $this->getCoverageColor( Chris@0: $report->getNumTestedClassesAndTraits(), Chris@0: $report->getNumClassesAndTraits() Chris@0: ); Chris@0: $colors['methods'] = $this->getCoverageColor( Chris@0: $report->getNumTestedMethods(), Chris@0: $report->getNumMethods() Chris@0: ); Chris@0: $colors['lines'] = $this->getCoverageColor( Chris@0: $report->getNumExecutedLines(), Chris@0: $report->getNumExecutableLines() Chris@0: ); Chris@0: $colors['reset'] = $this->colors['reset']; Chris@0: $colors['header'] = $this->colors['header']; Chris@0: $colors['eol'] = $this->colors['eol']; Chris@0: } Chris@0: Chris@0: $classes = sprintf( Chris@0: ' Classes: %6s (%d/%d)', Chris@0: PHP_CodeCoverage_Util::percent( Chris@0: $report->getNumTestedClassesAndTraits(), Chris@0: $report->getNumClassesAndTraits(), Chris@0: true Chris@0: ), Chris@0: $report->getNumTestedClassesAndTraits(), Chris@0: $report->getNumClassesAndTraits() Chris@0: ); Chris@0: Chris@0: $methods = sprintf( Chris@0: ' Methods: %6s (%d/%d)', Chris@0: PHP_CodeCoverage_Util::percent( Chris@0: $report->getNumTestedMethods(), Chris@0: $report->getNumMethods(), Chris@0: true Chris@0: ), Chris@0: $report->getNumTestedMethods(), Chris@0: $report->getNumMethods() Chris@0: ); Chris@0: Chris@0: $lines = sprintf( Chris@0: ' Lines: %6s (%d/%d)', Chris@0: PHP_CodeCoverage_Util::percent( Chris@0: $report->getNumExecutedLines(), Chris@0: $report->getNumExecutableLines(), Chris@0: true Chris@0: ), Chris@0: $report->getNumExecutedLines(), Chris@0: $report->getNumExecutableLines() Chris@0: ); Chris@0: Chris@0: $padding = max(array_map('strlen', array($classes, $methods, $lines))); Chris@0: Chris@0: if ($this->showOnlySummary) { Chris@0: $title = 'Code Coverage Report Summary:'; Chris@0: $padding = max($padding, strlen($title)); Chris@0: Chris@0: $output .= $this->format($colors['header'], $padding, $title); Chris@0: } else { Chris@0: $date = date(' Y-m-d H:i:s', $_SERVER['REQUEST_TIME']); Chris@0: $title = 'Code Coverage Report:'; Chris@0: Chris@0: $output .= $this->format($colors['header'], $padding, $title); Chris@0: $output .= $this->format($colors['header'], $padding, $date); Chris@0: $output .= $this->format($colors['header'], $padding, ''); Chris@0: $output .= $this->format($colors['header'], $padding, ' Summary:'); Chris@0: } Chris@0: Chris@0: $output .= $this->format($colors['classes'], $padding, $classes); Chris@0: $output .= $this->format($colors['methods'], $padding, $methods); Chris@0: $output .= $this->format($colors['lines'], $padding, $lines); Chris@0: Chris@0: if ($this->showOnlySummary) { Chris@0: return $output . PHP_EOL; Chris@0: } Chris@0: Chris@0: $classCoverage = array(); Chris@0: Chris@0: foreach ($report as $item) { Chris@0: if (!$item instanceof PHP_CodeCoverage_Report_Node_File) { Chris@0: continue; Chris@0: } Chris@0: Chris@0: $classes = $item->getClassesAndTraits(); Chris@0: Chris@0: foreach ($classes as $className => $class) { Chris@0: $classStatements = 0; Chris@0: $coveredClassStatements = 0; Chris@0: $coveredMethods = 0; Chris@0: $classMethods = 0; Chris@0: Chris@0: foreach ($class['methods'] as $method) { Chris@0: if ($method['executableLines'] == 0) { Chris@0: continue; Chris@0: } Chris@0: Chris@0: $classMethods++; Chris@0: $classStatements += $method['executableLines']; Chris@0: $coveredClassStatements += $method['executedLines']; Chris@0: if ($method['coverage'] == 100) { Chris@0: $coveredMethods++; Chris@0: } Chris@0: } Chris@0: Chris@0: if (!empty($class['package']['namespace'])) { Chris@0: $namespace = '\\' . $class['package']['namespace'] . '::'; Chris@0: } elseif (!empty($class['package']['fullPackage'])) { Chris@0: $namespace = '@' . $class['package']['fullPackage'] . '::'; Chris@0: } else { Chris@0: $namespace = ''; Chris@0: } Chris@0: Chris@0: $classCoverage[$namespace . $className] = array( Chris@0: 'namespace' => $namespace, Chris@0: 'className ' => $className, Chris@0: 'methodsCovered' => $coveredMethods, Chris@0: 'methodCount' => $classMethods, Chris@0: 'statementsCovered' => $coveredClassStatements, Chris@0: 'statementCount' => $classStatements, Chris@0: ); Chris@0: } Chris@0: } Chris@0: Chris@0: ksort($classCoverage); Chris@0: Chris@0: $methodColor = ''; Chris@0: $linesColor = ''; Chris@0: $resetColor = ''; Chris@0: Chris@0: foreach ($classCoverage as $fullQualifiedPath => $classInfo) { Chris@0: if ($classInfo['statementsCovered'] != 0 || Chris@0: $this->showUncoveredFiles) { Chris@0: if ($showColors) { Chris@0: $methodColor = $this->getCoverageColor($classInfo['methodsCovered'], $classInfo['methodCount']); Chris@0: $linesColor = $this->getCoverageColor($classInfo['statementsCovered'], $classInfo['statementCount']); Chris@0: $resetColor = $colors['reset']; Chris@0: } Chris@0: Chris@0: $output .= PHP_EOL . $fullQualifiedPath . PHP_EOL Chris@0: . ' ' . $methodColor . 'Methods: ' . $this->printCoverageCounts($classInfo['methodsCovered'], $classInfo['methodCount'], 2) . $resetColor . ' ' Chris@0: . ' ' . $linesColor . 'Lines: ' . $this->printCoverageCounts($classInfo['statementsCovered'], $classInfo['statementCount'], 3) . $resetColor Chris@0: ; Chris@0: } Chris@0: } Chris@0: Chris@0: return $output . PHP_EOL; Chris@0: } Chris@0: Chris@0: protected function getCoverageColor($numberOfCoveredElements, $totalNumberOfElements) Chris@0: { Chris@0: $coverage = PHP_CodeCoverage_Util::percent( Chris@0: $numberOfCoveredElements, Chris@0: $totalNumberOfElements Chris@0: ); Chris@0: Chris@0: if ($coverage >= $this->highLowerBound) { Chris@0: return $this->colors['green']; Chris@0: } elseif ($coverage > $this->lowUpperBound) { Chris@0: return $this->colors['yellow']; Chris@0: } Chris@0: Chris@0: return $this->colors['red']; Chris@0: } Chris@0: Chris@0: protected function printCoverageCounts($numberOfCoveredElements, $totalNumberOfElements, $presicion) Chris@0: { Chris@0: $format = '%' . $presicion . 's'; Chris@0: Chris@0: return PHP_CodeCoverage_Util::percent( Chris@0: $numberOfCoveredElements, Chris@0: $totalNumberOfElements, Chris@0: true, Chris@0: true Chris@0: ) . Chris@0: ' (' . sprintf($format, $numberOfCoveredElements) . '/' . Chris@0: sprintf($format, $totalNumberOfElements) . ')'; Chris@0: } Chris@0: Chris@0: private function format($color, $padding, $string) Chris@0: { Chris@0: $reset = $color ? $this->colors['reset'] : ''; Chris@0: Chris@0: return $color . str_pad($string, $padding) . $reset . PHP_EOL; Chris@0: } Chris@0: }