5 * Copyright (c) 2009-2011, Sebastian Bergmann <sb@sebastian-bergmann.de>.
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
12 * * Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
15 * * Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in
17 * the documentation and/or other materials provided with the
20 * * Neither the name of Sebastian Bergmann nor the names of his
21 * contributors may be used to endorse or promote products derived
22 * from this software without specific prior written permission.
24 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
25 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
26 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
27 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
28 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
29 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
30 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
31 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
32 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
33 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
34 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
35 * POSSIBILITY OF SUCH DAMAGE.
38 * @package CodeCoverage
39 * @author Sebastian Bergmann <sb@sebastian-bergmann.de>
40 * @copyright 2009-2011 Sebastian Bergmann <sb@sebastian-bergmann.de>
41 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
42 * @link http://github.com/sebastianbergmann/php-code-coverage
43 * @since File available since Release 1.1.0
47 * Generates human readable output from an PHP_CodeCoverage object.
49 * The output gets put into a text file our written to the CLI.
52 * @package CodeCoverage
53 * @author Sebastian Bergmann <sb@sebastian-bergmann.de>
54 * @copyright 2009-2011 Sebastian Bergmann <sb@sebastian-bergmann.de>
55 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
56 * @version Release: 1.1.1
57 * @link http://github.com/sebastianbergmann/php-code-coverage
58 * @since Class available since Release 1.1.0
60 class PHP_CodeCoverage_Report_Text
62 protected $outputStream;
64 protected $lowUpperBound;
65 protected $highLowerBound;
66 protected $showUncoveredFiles;
68 protected $colors = array(
69 'green' => "\x1b[30;42m",
70 'yellow' => "\x1b[30;43m",
71 'red' => "\x1b[37;41m",
72 'header' => "\x1b[47;40m",
77 public function __construct(PHPUnit_Util_Printer $outputStream, $title, $lowUpperBound, $highLowerBound, $showUncoveredFiles)
79 $this->outputStream = $outputStream;
80 $this->title = $title;
81 $this->lowUpperBound = $lowUpperBound;
82 $this->highLowerBound = $highLowerBound;
83 $this->showUncoveredFiles = $showUncoveredFiles;
87 * @param PHP_CodeCoverage $coverage
88 * @param string $target
92 public function process(PHP_CodeCoverage $coverage, $showColors = FALSE)
96 $report = $coverage->getReport();
109 $colors['classes'] = $this->getCoverageColor(
110 $report->getNumTestedClasses(),
111 $report->getNumClasses()
113 $colors['methods'] = $this->getCoverageColor(
114 $report->getNumTestedMethods(),
115 $report->getNumMethods()
117 $colors['lines'] = $this->getCoverageColor(
118 $report->getNumExecutedLines(),
119 $report->getNumExecutableLines()
121 $colors['reset'] = $this->colors['reset'];
122 $colors['header'] = $this->colors['header'];
123 $colors['eol'] = $this->colors['eol'];
126 $output .= PHP_EOL . PHP_EOL .
127 $colors['header'] . 'Code Coverage Report ';
130 $output .= 'for "' . $this->title . '"';
134 date(' Y-m-d H:i:s', $_SERVER['REQUEST_TIME']) .
137 $output .= PHP_EOL . ' Summary: ' . PHP_EOL . $colors['reset']
138 . $colors['classes'] . $colors['eol'] . ' Classes: ' . PHP_CodeCoverage_Util::percent($report->getNumTestedClasses(), $report->getNumClasses(), TRUE)
139 . ' (' . $report->getNumTestedClasses() . '/' . $report->getNumClasses() . ')' . PHP_EOL . $colors ['eol']
140 . $colors['methods'] . $colors['eol'] . ' Methods: ' . PHP_CodeCoverage_Util::percent($report->getNumTestedMethods(), $report->getNumMethods(), TRUE)
141 . ' (' . $report->getNumTestedMethods() . '/' . $report->getNumMethods() . ')' . PHP_EOL . $colors ['eol']
142 . $colors['lines'] . $colors['eol'] . ' Lines: ' . PHP_CodeCoverage_Util::percent($report->getNumExecutedLines(), $report->getNumExecutableLines(), TRUE)
143 . ' (' . $report->getNumExecutedLines() . '/' . $report->getNumExecutableLines() . ')' . PHP_EOL . $colors['reset'] . $colors ['eol'];
145 $classCoverage = array();
147 foreach ($report as $item) {
148 if (!$item instanceof PHP_CodeCoverage_Report_Node_File) {
152 $classes = array_merge($item->getClasses(), $item->getTraits());
153 $coverage = $item->getCoverageData();
155 $ignoredLines = $item->getIgnoredLines();
157 foreach ($classes as $className => $class) {
158 $classStatements = 0;
159 $coveredClassStatements = 0;
162 foreach ($class['methods'] as $methodName => $method) {
165 $methodLinesCovered = 0;
167 for ($i = $method['startLine'];
168 $i <= $method['endLine'];
170 if (isset($ignoredLines[$i])) {
177 if (isset($coverage[$i])) {
178 if ($coverage[$i] !== NULL) {
185 $count = count($coverage[$i]);
188 $coveredClassStatements++;
189 $methodLinesCovered++;
195 $methodCount = max($methodCount, $count);
199 'count' => $count, 'type' => 'stmt'
204 if ($methodCount > 0) {
210 if (!empty($class['package']['namespace'])) {
211 $namespace = '\\' . $class['package']['namespace'] . '::';
214 else if (!empty($class['package']['fullPackage'])) {
215 $namespace = '@' . $class['package']['fullPackage'] . '::';
222 $classCoverage[$namespace . $className] = array(
223 'namespace' => $namespace,
224 'className ' => $className,
225 'methodsCovered' => $coveredMethods,
226 'methodCount' => count($class['methods']),
227 'statementsCovered' => $coveredClassStatements,
228 'statementCount' => $classStatements,
233 ksort($classCoverage);
239 foreach ($classCoverage as $fullQualifiedPath => $classInfo) {
240 if ($classInfo['statementsCovered'] != 0 ||
241 $this->showUncoveredFiles) {
244 $methodColor = $this->getCoverageColor($classInfo['methodsCovered'], $classInfo['methodCount']);
245 $linesColor = $this->getCoverageColor($classInfo['statementsCovered'], $classInfo['statementCount']);
246 $resetColor = $colors['reset'];
249 $output .= PHP_EOL . $fullQualifiedPath . PHP_EOL
250 . ' ' . $methodColor . 'Methods: ' . $this->printCoverageCounts($classInfo['methodsCovered'], $classInfo['methodCount'], 2) . $resetColor . ' '
251 . ' ' . $linesColor . 'Lines: ' . $this->printCoverageCounts($classInfo['statementsCovered'], $classInfo['statementCount'], 3) . $resetColor
256 $this->outputStream->write($output);
259 protected function getCoverageColor($numberOfCoveredElements, $totalNumberOfElements)
261 $coverage = PHP_CodeCoverage_Util::percent(
262 $numberOfCoveredElements, $totalNumberOfElements
265 if ($coverage > $this->highLowerBound) {
266 return $this->colors['green'];
269 else if ($coverage > $this->lowUpperBound) {
270 return $this->colors['yellow'];
273 return $this->colors['red'];
276 protected function printCoverageCounts($numberOfCoveredElements, $totalNumberOfElements, $presicion)
278 $format = '%' . $presicion . 's';
280 return PHP_CodeCoverage_Util::percent(
281 $numberOfCoveredElements, $totalNumberOfElements, TRUE, TRUE
283 ' (' . sprintf($format, $numberOfCoveredElements) . '/' .
284 sprintf($format, $totalNumberOfElements) . ')';