Skip to content

Commit f2dfe43

Browse files
authored
Merge pull request #28 from jmrieger/2-add-branch-coverage-in-text-reporter
2 add branch coverage in text reporter
2 parents d8222de + 4cd54ee commit f2dfe43

File tree

4 files changed

+166
-51
lines changed

4 files changed

+166
-51
lines changed

src/CodeCoverage.php

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -619,11 +619,13 @@ private function initializeFilesThatAreSeenTheFirstTime(array $data): void
619619
foreach ($fileData['lines'] as $lineNumber => $flag) {
620620
if ($flag === Driver::LINE_NOT_EXECUTABLE) {
621621
$this->data[$file]['lines'][$lineNumber] = null;
622+
} else {
623+
$this->addCoverageLinePathCovered($file, $lineNumber, false);
622624
}
625+
623626
}
624627

625628
foreach ($fileData['functions'] as $functionName => $functionData) {
626-
// @todo - should this have a helper to merge covered paths?
627629
$this->data[$file]['paths'][$functionName] = $functionData['paths'];
628630

629631
foreach ($functionData['branches'] as $branchIndex => $branchData) {
@@ -837,7 +839,6 @@ private function addUncoveredFilesFromWhitelist(): void
837839
for ($line = 1; $line <= $lines; $line++) {
838840
$data[$uncoveredFile]['lines'][$line] = Driver::LINE_NOT_EXECUTED;
839841
}
840-
// @todo - do the same here with functions and paths
841842
}
842843

843844
$this->append($data, 'UNCOVERED_FILES_FROM_WHITELIST');
@@ -1190,9 +1191,9 @@ private function initializeData(): void
11901191
continue;
11911192
}
11921193

1193-
foreach (\array_keys($fileCoverage) as $key) {
1194-
if ($fileCoverage[$key] === Driver::LINE_EXECUTED) {
1195-
$fileCoverage[$key] = Driver::LINE_NOT_EXECUTED;
1194+
foreach (\array_keys($fileCoverage['lines']) as $key) {
1195+
if ($fileCoverage['lines'][$key] === Driver::LINE_EXECUTED) {
1196+
$fileCoverage['lines'][$key] = Driver::LINE_NOT_EXECUTED;
11961197
}
11971198
}
11981199

src/Node/File.php

Lines changed: 25 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -377,16 +377,21 @@ private function calculateStatistics(): void
377377
unset($tokens);
378378

379379
foreach (\range(1, $this->linesOfCode['loc']) as $lineNumber) {
380-
if (isset($this->coverageData['lines'][$lineNumber])) {
381-
foreach ($this->codeUnitsByLine[$lineNumber] as &$codeUnit) {
382-
$codeUnit['executableLines']++;
383-
}
380+
// Check to see if we've identified this line as executed, not executed, or not executable
381+
if (\array_key_exists($lineNumber, $this->coverageData['lines'])) {
382+
// If the element is null, that indicates this line is not executable
383+
if ($this->coverageData['lines'][$lineNumber] !== null) {
384+
foreach ($this->codeUnitsByLine[$lineNumber] as &$codeUnit) {
385+
$codeUnit['executableLines']++;
386+
}
387+
388+
unset($codeUnit);
384389

385-
unset($codeUnit);
390+
$this->numExecutableLines++;
391+
}
386392

387-
$this->numExecutableLines++;
388393

389-
if (\count($this->coverageData['lines'][$lineNumber]) > 0) {
394+
if ($this->coverageData['lines'][$lineNumber]['pathCovered'] === true) {
390395
foreach ($this->codeUnitsByLine[$lineNumber] as &$codeUnit) {
391396
$codeUnit['executedLines']++;
392397
}
@@ -472,6 +477,19 @@ private function calcAndApplyClassAggregate(
472477
foreach ($classOrTrait['methods'] as &$method) {
473478
$methodName = $method['methodName'];
474479

480+
if ($method['executableLines'] > 0) {
481+
$method['coverage'] = ($method['executedLines'] / $method['executableLines']) * 100;
482+
} else {
483+
$method['coverage'] = 100;
484+
}
485+
486+
$method['crap'] = $this->crap(
487+
$method['ccn'],
488+
$method['coverage']
489+
);
490+
491+
$classOrTrait['ccn'] += $method['ccn'];
492+
475493
if (isset($this->coverageData['paths'])) {
476494
$methodCoveragePath = $methodName;
477495

@@ -499,19 +517,6 @@ private function calcAndApplyClassAggregate(
499517
$this->numTestedPaths += $numExexutedPaths;
500518
}
501519

502-
if ($method['executableLines'] > 0) {
503-
$method['coverage'] = ($method['executedLines'] /
504-
$method['executableLines']) * 100;
505-
} else {
506-
$method['coverage'] = 100;
507-
}
508-
509-
$method['crap'] = $this->crap(
510-
$method['ccn'],
511-
$method['coverage']
512-
);
513-
514-
$classOrTrait['ccn'] += $method['ccn'];
515520
}
516521

517522
if (isset($this->coverageData['branches'])) {

src/Report/Text.php

Lines changed: 134 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -70,12 +70,18 @@ final class Text
7070
*/
7171
private $showOnlySummary;
7272

73-
public function __construct(int $lowUpperBound = 50, int $highLowerBound = 90, bool $showUncoveredFiles = false, bool $showOnlySummary = false)
73+
/**
74+
* @var bool
75+
*/
76+
private $determineBranchCoverage;
77+
78+
public function __construct(int $lowUpperBound = 50, int $highLowerBound = 90, bool $showUncoveredFiles = false, bool $showOnlySummary = false, bool $determineBranchCoverage = false)
7479
{
75-
$this->lowUpperBound = $lowUpperBound;
76-
$this->highLowerBound = $highLowerBound;
77-
$this->showUncoveredFiles = $showUncoveredFiles;
78-
$this->showOnlySummary = $showOnlySummary;
80+
$this->lowUpperBound = $lowUpperBound;
81+
$this->highLowerBound = $highLowerBound;
82+
$this->showUncoveredFiles = $showUncoveredFiles;
83+
$this->showOnlySummary = $showOnlySummary;
84+
$this->determineBranchCoverage = $determineBranchCoverage;
7985
}
8086

8187
public function process(CodeCoverage $coverage, bool $showColors = false): string
@@ -84,12 +90,14 @@ public function process(CodeCoverage $coverage, bool $showColors = false): strin
8490
$report = $coverage->getReport();
8591

8692
$colors = [
87-
'header' => '',
88-
'classes' => '',
89-
'methods' => '',
90-
'lines' => '',
91-
'reset' => '',
92-
'eol' => '',
93+
'header' => '',
94+
'classes' => '',
95+
'methods' => '',
96+
'lines' => '',
97+
'branches' => '',
98+
'paths' => '',
99+
'reset' => '',
100+
'eol' => '',
93101
];
94102

95103
if ($showColors) {
@@ -108,13 +116,25 @@ public function process(CodeCoverage $coverage, bool $showColors = false): strin
108116
$report->getNumExecutableLines()
109117
);
110118

119+
if ($this->determineBranchCoverage) {
120+
$colors['branches'] = $this->getCoverageColor(
121+
$report->getNumTestedBranches(),
122+
$report->getNumBranches()
123+
);
124+
125+
$colors['paths'] = $this->getCoverageColor(
126+
$report->getNumTestedPaths(),
127+
$report->getNumPaths()
128+
);
129+
}
130+
111131
$colors['reset'] = self::COLOR_RESET;
112132
$colors['header'] = self::COLOR_HEADER;
113133
$colors['eol'] = self::COLOR_EOL;
114134
}
115135

116136
$classes = \sprintf(
117-
' Classes: %6s (%d/%d)',
137+
' Classes: %6s (%d/%d)',
118138
Util::percent(
119139
$report->getNumTestedClassesAndTraits(),
120140
$report->getNumClassesAndTraits(),
@@ -125,7 +145,7 @@ public function process(CodeCoverage $coverage, bool $showColors = false): strin
125145
);
126146

127147
$methods = \sprintf(
128-
' Methods: %6s (%d/%d)',
148+
' Methods: %6s (%d/%d)',
129149
Util::percent(
130150
$report->getNumTestedMethods(),
131151
$report->getNumMethods(),
@@ -136,7 +156,7 @@ public function process(CodeCoverage $coverage, bool $showColors = false): strin
136156
);
137157

138158
$lines = \sprintf(
139-
' Lines: %6s (%d/%d)',
159+
' Lines: %6s (%d/%d)',
140160
Util::percent(
141161
$report->getNumExecutedLines(),
142162
$report->getNumExecutableLines(),
@@ -146,6 +166,33 @@ public function process(CodeCoverage $coverage, bool $showColors = false): strin
146166
$report->getNumExecutableLines()
147167
);
148168

169+
$paths = '';
170+
$branches = '';
171+
172+
if ($this->determineBranchCoverage) {
173+
$branches = \sprintf(
174+
' Branches: %6s (%d/%d)',
175+
Util::percent(
176+
$report->getNumTestedBranches(),
177+
$report->getNumBranches(),
178+
true
179+
),
180+
$report->getNumTestedBranches(),
181+
$report->getNumBranches()
182+
);
183+
184+
$paths = \sprintf(
185+
' Paths: %6s (%d/%d)',
186+
Util::percent(
187+
$report->getNumTestedPaths(),
188+
$report->getNumPaths(),
189+
true
190+
),
191+
$report->getNumTestedPaths(),
192+
$report->getNumPaths()
193+
);
194+
}
195+
149196
$padding = \max(\array_map('strlen', [$classes, $methods, $lines]));
150197

151198
if ($this->showOnlySummary) {
@@ -167,12 +214,22 @@ public function process(CodeCoverage $coverage, bool $showColors = false): strin
167214
$output .= $this->format($colors['methods'], $padding, $methods);
168215
$output .= $this->format($colors['lines'], $padding, $lines);
169216

217+
if ($this->determineBranchCoverage) {
218+
$output .= $this->format($colors['branches'], $padding, $branches);
219+
$output .= $this->format($colors['paths'], $padding, $paths);
220+
}
221+
170222
if ($this->showOnlySummary) {
171223
return $output . \PHP_EOL;
172224
}
173225

174226
$classCoverage = [];
175227

228+
$maxMethods = 0;
229+
$maxLines = 0;
230+
$maxBranches = 0;
231+
$maxPaths = 0;
232+
176233
foreach ($report as $item) {
177234
if (!$item instanceof File) {
178235
continue;
@@ -185,21 +242,56 @@ public function process(CodeCoverage $coverage, bool $showColors = false): strin
185242
$coveredClassStatements = 0;
186243
$coveredMethods = 0;
187244
$classMethods = 0;
245+
$classPaths = 0;
246+
$coveredClassPaths = 0;
247+
$classBranches = 0;
248+
$coveredClassBranches = 0;
188249

189250
foreach ($class['methods'] as $method) {
190-
if ($method['executableLines'] == 0) {
251+
if ($method['executableLines'] === 0) {
191252
continue;
192253
}
193254

194255
$classMethods++;
195256
$classStatements += $method['executableLines'];
196257
$coveredClassStatements += $method['executedLines'];
197258

198-
if ($method['coverage'] == 100) {
259+
if ($this->determineBranchCoverage) {
260+
$classPaths += $method['executablePaths'];
261+
$coveredClassPaths += $method['executedPaths'];
262+
$classBranches += $method['executableBranches'];
263+
$coveredClassBranches += $method['executedBranches'];
264+
}
265+
266+
if ($method['coverage'] === 100) {
199267
$coveredMethods++;
200268
}
201269
}
202270

271+
$maxMethods = \max(
272+
$maxMethods,
273+
\strlen((string) $classMethods),
274+
\strlen((string) $coveredMethods)
275+
);
276+
$maxLines = \max(
277+
$maxLines,
278+
\strlen((string) $classStatements),
279+
\strlen((string) $coveredClassStatements)
280+
);
281+
282+
if ($this->determineBranchCoverage) {
283+
$maxBranches = \max(
284+
$maxBranches,
285+
\strlen((string) $classBranches),
286+
\strlen((string) $coveredClassBranches)
287+
);
288+
$maxPaths = \max(
289+
$maxPaths,
290+
\strlen((string) $classPaths),
291+
\strlen((string) $coveredClassPaths)
292+
);
293+
}
294+
203295
$namespace = '';
204296

205297
if (!empty($class['package']['namespace'])) {
@@ -215,27 +307,44 @@ public function process(CodeCoverage $coverage, bool $showColors = false): strin
215307
'methodCount' => $classMethods,
216308
'statementsCovered' => $coveredClassStatements,
217309
'statementCount' => $classStatements,
310+
'pathsCovered' => $coveredClassPaths,
311+
'pathCount' => $classPaths,
312+
'branchesCovered' => $coveredClassBranches,
313+
'branchCount' => $classBranches,
218314
];
219315
}
220316
}
221317

222318
\ksort($classCoverage);
223319

224-
$methodColor = '';
225-
$linesColor = '';
226-
$resetColor = '';
320+
$methodColor = '';
321+
$linesColor = '';
322+
$resetColor = '';
323+
$pathsColor = '';
324+
$branchesColor = '';
227325

228326
foreach ($classCoverage as $fullQualifiedPath => $classInfo) {
229-
if ($this->showUncoveredFiles || $classInfo['statementsCovered'] != 0) {
327+
if ($this->showUncoveredFiles || $classInfo['statementsCovered'] !== 0) {
230328
if ($showColors) {
231-
$methodColor = $this->getCoverageColor($classInfo['methodsCovered'], $classInfo['methodCount']);
232-
$linesColor = $this->getCoverageColor($classInfo['statementsCovered'], $classInfo['statementCount']);
233-
$resetColor = $colors['reset'];
329+
$methodColor = $this->getCoverageColor($classInfo['methodsCovered'], $classInfo['methodCount']);
330+
$linesColor = $this->getCoverageColor($classInfo['statementsCovered'], $classInfo['statementCount']);
331+
332+
if ($this->determineBranchCoverage) {
333+
$branchesColor = $this->getCoverageColor($classInfo['branchesCovered'], $classInfo['branchCount']);
334+
$pathsColor = $this->getCoverageColor($classInfo['pathsCovered'], $classInfo['pathCount']);
335+
}
336+
$resetColor = $colors['reset'];
234337
}
235338

236339
$output .= \PHP_EOL . $fullQualifiedPath . \PHP_EOL
237-
. ' ' . $methodColor . 'Methods: ' . $this->printCoverageCounts($classInfo['methodsCovered'], $classInfo['methodCount'], 2) . $resetColor . ' '
238-
. ' ' . $linesColor . 'Lines: ' . $this->printCoverageCounts($classInfo['statementsCovered'], $classInfo['statementCount'], 3) . $resetColor;
340+
. ' ' . $methodColor . 'Methods: ' . $this->printCoverageCounts($classInfo['methodsCovered'], $classInfo['methodCount'], $maxMethods) . $resetColor . ' '
341+
. ' ' . $linesColor . 'Lines: ' . $this->printCoverageCounts($classInfo['statementsCovered'], $classInfo['statementCount'], $maxLines) . $resetColor;
342+
343+
if ($this->determineBranchCoverage) {
344+
$output .= ''
345+
. ' ' . $branchesColor . 'Branches: ' . $this->printCoverageCounts($classInfo['branchesCovered'], $classInfo['branchCount'], $maxBranches) . $resetColor . ' '
346+
. ' ' . $pathsColor . 'Paths: ' . $this->printCoverageCounts($classInfo['pathsCovered'], $classInfo['pathCount'], $maxPaths) . $resetColor;
347+
}
239348
}
240349
}
241350

src/Util.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ final class Util
2020
public static function percent(float $a, float $b, bool $asString = false, bool $fixedWidth = false)
2121
{
2222
if ($asString && $b == 0) {
23-
return '';
23+
return $fixedWidth ? ' ' : '';
2424
}
2525

2626
$percent = 100;

0 commit comments

Comments
 (0)