Chris@0
|
1 <?php
|
Chris@0
|
2 /*
|
Chris@0
|
3 * This file is part of the PHP_CodeCoverage package.
|
Chris@0
|
4 *
|
Chris@0
|
5 * (c) Sebastian Bergmann <sebastian@phpunit.de>
|
Chris@0
|
6 *
|
Chris@0
|
7 * For the full copyright and license information, please view the LICENSE
|
Chris@0
|
8 * file that was distributed with this source code.
|
Chris@0
|
9 */
|
Chris@0
|
10
|
Chris@0
|
11 /**
|
Chris@0
|
12 * Generates human readable output from an PHP_CodeCoverage object.
|
Chris@0
|
13 *
|
Chris@0
|
14 * The output gets put into a text file our written to the CLI.
|
Chris@0
|
15 *
|
Chris@0
|
16 * @since Class available since Release 1.1.0
|
Chris@0
|
17 */
|
Chris@0
|
18 class PHP_CodeCoverage_Report_Text
|
Chris@0
|
19 {
|
Chris@0
|
20 protected $lowUpperBound;
|
Chris@0
|
21 protected $highLowerBound;
|
Chris@0
|
22 protected $showUncoveredFiles;
|
Chris@0
|
23 protected $showOnlySummary;
|
Chris@0
|
24
|
Chris@0
|
25 protected $colors = array(
|
Chris@0
|
26 'green' => "\x1b[30;42m",
|
Chris@0
|
27 'yellow' => "\x1b[30;43m",
|
Chris@0
|
28 'red' => "\x1b[37;41m",
|
Chris@0
|
29 'header' => "\x1b[1;37;40m",
|
Chris@0
|
30 'reset' => "\x1b[0m",
|
Chris@0
|
31 'eol' => "\x1b[2K",
|
Chris@0
|
32 );
|
Chris@0
|
33
|
Chris@0
|
34 public function __construct($lowUpperBound, $highLowerBound, $showUncoveredFiles, $showOnlySummary)
|
Chris@0
|
35 {
|
Chris@0
|
36 $this->lowUpperBound = $lowUpperBound;
|
Chris@0
|
37 $this->highLowerBound = $highLowerBound;
|
Chris@0
|
38 $this->showUncoveredFiles = $showUncoveredFiles;
|
Chris@0
|
39 $this->showOnlySummary = $showOnlySummary;
|
Chris@0
|
40 }
|
Chris@0
|
41
|
Chris@0
|
42 /**
|
Chris@0
|
43 * @param PHP_CodeCoverage $coverage
|
Chris@0
|
44 * @param bool $showColors
|
Chris@0
|
45 * @return string
|
Chris@0
|
46 */
|
Chris@0
|
47 public function process(PHP_CodeCoverage $coverage, $showColors = false)
|
Chris@0
|
48 {
|
Chris@0
|
49 $output = PHP_EOL . PHP_EOL;
|
Chris@0
|
50 $report = $coverage->getReport();
|
Chris@0
|
51 unset($coverage);
|
Chris@0
|
52
|
Chris@0
|
53 $colors = array(
|
Chris@0
|
54 'header' => '',
|
Chris@0
|
55 'classes' => '',
|
Chris@0
|
56 'methods' => '',
|
Chris@0
|
57 'lines' => '',
|
Chris@0
|
58 'reset' => '',
|
Chris@0
|
59 'eol' => ''
|
Chris@0
|
60 );
|
Chris@0
|
61
|
Chris@0
|
62 if ($showColors) {
|
Chris@0
|
63 $colors['classes'] = $this->getCoverageColor(
|
Chris@0
|
64 $report->getNumTestedClassesAndTraits(),
|
Chris@0
|
65 $report->getNumClassesAndTraits()
|
Chris@0
|
66 );
|
Chris@0
|
67 $colors['methods'] = $this->getCoverageColor(
|
Chris@0
|
68 $report->getNumTestedMethods(),
|
Chris@0
|
69 $report->getNumMethods()
|
Chris@0
|
70 );
|
Chris@0
|
71 $colors['lines'] = $this->getCoverageColor(
|
Chris@0
|
72 $report->getNumExecutedLines(),
|
Chris@0
|
73 $report->getNumExecutableLines()
|
Chris@0
|
74 );
|
Chris@0
|
75 $colors['reset'] = $this->colors['reset'];
|
Chris@0
|
76 $colors['header'] = $this->colors['header'];
|
Chris@0
|
77 $colors['eol'] = $this->colors['eol'];
|
Chris@0
|
78 }
|
Chris@0
|
79
|
Chris@0
|
80 $classes = sprintf(
|
Chris@0
|
81 ' Classes: %6s (%d/%d)',
|
Chris@0
|
82 PHP_CodeCoverage_Util::percent(
|
Chris@0
|
83 $report->getNumTestedClassesAndTraits(),
|
Chris@0
|
84 $report->getNumClassesAndTraits(),
|
Chris@0
|
85 true
|
Chris@0
|
86 ),
|
Chris@0
|
87 $report->getNumTestedClassesAndTraits(),
|
Chris@0
|
88 $report->getNumClassesAndTraits()
|
Chris@0
|
89 );
|
Chris@0
|
90
|
Chris@0
|
91 $methods = sprintf(
|
Chris@0
|
92 ' Methods: %6s (%d/%d)',
|
Chris@0
|
93 PHP_CodeCoverage_Util::percent(
|
Chris@0
|
94 $report->getNumTestedMethods(),
|
Chris@0
|
95 $report->getNumMethods(),
|
Chris@0
|
96 true
|
Chris@0
|
97 ),
|
Chris@0
|
98 $report->getNumTestedMethods(),
|
Chris@0
|
99 $report->getNumMethods()
|
Chris@0
|
100 );
|
Chris@0
|
101
|
Chris@0
|
102 $lines = sprintf(
|
Chris@0
|
103 ' Lines: %6s (%d/%d)',
|
Chris@0
|
104 PHP_CodeCoverage_Util::percent(
|
Chris@0
|
105 $report->getNumExecutedLines(),
|
Chris@0
|
106 $report->getNumExecutableLines(),
|
Chris@0
|
107 true
|
Chris@0
|
108 ),
|
Chris@0
|
109 $report->getNumExecutedLines(),
|
Chris@0
|
110 $report->getNumExecutableLines()
|
Chris@0
|
111 );
|
Chris@0
|
112
|
Chris@0
|
113 $padding = max(array_map('strlen', array($classes, $methods, $lines)));
|
Chris@0
|
114
|
Chris@0
|
115 if ($this->showOnlySummary) {
|
Chris@0
|
116 $title = 'Code Coverage Report Summary:';
|
Chris@0
|
117 $padding = max($padding, strlen($title));
|
Chris@0
|
118
|
Chris@0
|
119 $output .= $this->format($colors['header'], $padding, $title);
|
Chris@0
|
120 } else {
|
Chris@0
|
121 $date = date(' Y-m-d H:i:s', $_SERVER['REQUEST_TIME']);
|
Chris@0
|
122 $title = 'Code Coverage Report:';
|
Chris@0
|
123
|
Chris@0
|
124 $output .= $this->format($colors['header'], $padding, $title);
|
Chris@0
|
125 $output .= $this->format($colors['header'], $padding, $date);
|
Chris@0
|
126 $output .= $this->format($colors['header'], $padding, '');
|
Chris@0
|
127 $output .= $this->format($colors['header'], $padding, ' Summary:');
|
Chris@0
|
128 }
|
Chris@0
|
129
|
Chris@0
|
130 $output .= $this->format($colors['classes'], $padding, $classes);
|
Chris@0
|
131 $output .= $this->format($colors['methods'], $padding, $methods);
|
Chris@0
|
132 $output .= $this->format($colors['lines'], $padding, $lines);
|
Chris@0
|
133
|
Chris@0
|
134 if ($this->showOnlySummary) {
|
Chris@0
|
135 return $output . PHP_EOL;
|
Chris@0
|
136 }
|
Chris@0
|
137
|
Chris@0
|
138 $classCoverage = array();
|
Chris@0
|
139
|
Chris@0
|
140 foreach ($report as $item) {
|
Chris@0
|
141 if (!$item instanceof PHP_CodeCoverage_Report_Node_File) {
|
Chris@0
|
142 continue;
|
Chris@0
|
143 }
|
Chris@0
|
144
|
Chris@0
|
145 $classes = $item->getClassesAndTraits();
|
Chris@0
|
146
|
Chris@0
|
147 foreach ($classes as $className => $class) {
|
Chris@0
|
148 $classStatements = 0;
|
Chris@0
|
149 $coveredClassStatements = 0;
|
Chris@0
|
150 $coveredMethods = 0;
|
Chris@0
|
151 $classMethods = 0;
|
Chris@0
|
152
|
Chris@0
|
153 foreach ($class['methods'] as $method) {
|
Chris@0
|
154 if ($method['executableLines'] == 0) {
|
Chris@0
|
155 continue;
|
Chris@0
|
156 }
|
Chris@0
|
157
|
Chris@0
|
158 $classMethods++;
|
Chris@0
|
159 $classStatements += $method['executableLines'];
|
Chris@0
|
160 $coveredClassStatements += $method['executedLines'];
|
Chris@0
|
161 if ($method['coverage'] == 100) {
|
Chris@0
|
162 $coveredMethods++;
|
Chris@0
|
163 }
|
Chris@0
|
164 }
|
Chris@0
|
165
|
Chris@0
|
166 if (!empty($class['package']['namespace'])) {
|
Chris@0
|
167 $namespace = '\\' . $class['package']['namespace'] . '::';
|
Chris@0
|
168 } elseif (!empty($class['package']['fullPackage'])) {
|
Chris@0
|
169 $namespace = '@' . $class['package']['fullPackage'] . '::';
|
Chris@0
|
170 } else {
|
Chris@0
|
171 $namespace = '';
|
Chris@0
|
172 }
|
Chris@0
|
173
|
Chris@0
|
174 $classCoverage[$namespace . $className] = array(
|
Chris@0
|
175 'namespace' => $namespace,
|
Chris@0
|
176 'className ' => $className,
|
Chris@0
|
177 'methodsCovered' => $coveredMethods,
|
Chris@0
|
178 'methodCount' => $classMethods,
|
Chris@0
|
179 'statementsCovered' => $coveredClassStatements,
|
Chris@0
|
180 'statementCount' => $classStatements,
|
Chris@0
|
181 );
|
Chris@0
|
182 }
|
Chris@0
|
183 }
|
Chris@0
|
184
|
Chris@0
|
185 ksort($classCoverage);
|
Chris@0
|
186
|
Chris@0
|
187 $methodColor = '';
|
Chris@0
|
188 $linesColor = '';
|
Chris@0
|
189 $resetColor = '';
|
Chris@0
|
190
|
Chris@0
|
191 foreach ($classCoverage as $fullQualifiedPath => $classInfo) {
|
Chris@0
|
192 if ($classInfo['statementsCovered'] != 0 ||
|
Chris@0
|
193 $this->showUncoveredFiles) {
|
Chris@0
|
194 if ($showColors) {
|
Chris@0
|
195 $methodColor = $this->getCoverageColor($classInfo['methodsCovered'], $classInfo['methodCount']);
|
Chris@0
|
196 $linesColor = $this->getCoverageColor($classInfo['statementsCovered'], $classInfo['statementCount']);
|
Chris@0
|
197 $resetColor = $colors['reset'];
|
Chris@0
|
198 }
|
Chris@0
|
199
|
Chris@0
|
200 $output .= PHP_EOL . $fullQualifiedPath . PHP_EOL
|
Chris@0
|
201 . ' ' . $methodColor . 'Methods: ' . $this->printCoverageCounts($classInfo['methodsCovered'], $classInfo['methodCount'], 2) . $resetColor . ' '
|
Chris@0
|
202 . ' ' . $linesColor . 'Lines: ' . $this->printCoverageCounts($classInfo['statementsCovered'], $classInfo['statementCount'], 3) . $resetColor
|
Chris@0
|
203 ;
|
Chris@0
|
204 }
|
Chris@0
|
205 }
|
Chris@0
|
206
|
Chris@0
|
207 return $output . PHP_EOL;
|
Chris@0
|
208 }
|
Chris@0
|
209
|
Chris@0
|
210 protected function getCoverageColor($numberOfCoveredElements, $totalNumberOfElements)
|
Chris@0
|
211 {
|
Chris@0
|
212 $coverage = PHP_CodeCoverage_Util::percent(
|
Chris@0
|
213 $numberOfCoveredElements,
|
Chris@0
|
214 $totalNumberOfElements
|
Chris@0
|
215 );
|
Chris@0
|
216
|
Chris@0
|
217 if ($coverage >= $this->highLowerBound) {
|
Chris@0
|
218 return $this->colors['green'];
|
Chris@0
|
219 } elseif ($coverage > $this->lowUpperBound) {
|
Chris@0
|
220 return $this->colors['yellow'];
|
Chris@0
|
221 }
|
Chris@0
|
222
|
Chris@0
|
223 return $this->colors['red'];
|
Chris@0
|
224 }
|
Chris@0
|
225
|
Chris@0
|
226 protected function printCoverageCounts($numberOfCoveredElements, $totalNumberOfElements, $presicion)
|
Chris@0
|
227 {
|
Chris@0
|
228 $format = '%' . $presicion . 's';
|
Chris@0
|
229
|
Chris@0
|
230 return PHP_CodeCoverage_Util::percent(
|
Chris@0
|
231 $numberOfCoveredElements,
|
Chris@0
|
232 $totalNumberOfElements,
|
Chris@0
|
233 true,
|
Chris@0
|
234 true
|
Chris@0
|
235 ) .
|
Chris@0
|
236 ' (' . sprintf($format, $numberOfCoveredElements) . '/' .
|
Chris@0
|
237 sprintf($format, $totalNumberOfElements) . ')';
|
Chris@0
|
238 }
|
Chris@0
|
239
|
Chris@0
|
240 private function format($color, $padding, $string)
|
Chris@0
|
241 {
|
Chris@0
|
242 $reset = $color ? $this->colors['reset'] : '';
|
Chris@0
|
243
|
Chris@0
|
244 return $color . str_pad($string, $padding) . $reset . PHP_EOL;
|
Chris@0
|
245 }
|
Chris@0
|
246 }
|