Skip to content

Commit 6208dce

Browse files
committed
Encapsulate raw coverage data from drivers
1 parent 0be1afd commit 6208dce

10 files changed

+405
-81
lines changed

src/CodeCoverage.php

+39-39
Original file line numberDiff line numberDiff line change
@@ -255,7 +255,7 @@ public function start($id, bool $clear = false): void
255255
* @throws InvalidArgumentException
256256
* @throws \ReflectionException
257257
*/
258-
public function stop(bool $append = true, $linesToBeCovered = [], array $linesToBeUsed = [], bool $ignoreForceCoversAnnotation = false): array
258+
public function stop(bool $append = true, $linesToBeCovered = [], array $linesToBeUsed = [], bool $ignoreForceCoversAnnotation = false): RawCodeCoverageData
259259
{
260260
if (!\is_array($linesToBeCovered) && $linesToBeCovered !== false) {
261261
throw InvalidArgumentException::create(
@@ -285,7 +285,7 @@ public function stop(bool $append = true, $linesToBeCovered = [], array $linesTo
285285
* @throws \SebastianBergmann\CodeCoverage\InvalidArgumentException
286286
* @throws RuntimeException
287287
*/
288-
public function append(array $data, $id = null, bool $append = true, $linesToBeCovered = [], array $linesToBeUsed = [], bool $ignoreForceCoversAnnotation = false): void
288+
public function append(RawCodeCoverageData $rawData, $id = null, bool $append = true, $linesToBeCovered = [], array $linesToBeUsed = [], bool $ignoreForceCoversAnnotation = false): void
289289
{
290290
if ($id === null) {
291291
$id = $this->currentId;
@@ -295,24 +295,24 @@ public function append(array $data, $id = null, bool $append = true, $linesToBeC
295295
throw new RuntimeException;
296296
}
297297

298-
$this->applyWhitelistFilter($data);
299-
$this->applyIgnoredLinesFilter($data);
300-
$this->initializeFilesThatAreSeenTheFirstTime($data);
298+
$this->applyWhitelistFilter($rawData);
299+
$this->applyIgnoredLinesFilter($rawData);
300+
$this->initializeFilesThatAreSeenTheFirstTime($rawData);
301301

302302
if (!$append) {
303303
return;
304304
}
305305

306306
if ($id !== 'UNCOVERED_FILES_FROM_WHITELIST') {
307307
$this->applyCoversAnnotationFilter(
308-
$data,
308+
$rawData,
309309
$linesToBeCovered,
310310
$linesToBeUsed,
311311
$ignoreForceCoversAnnotation
312312
);
313313
}
314314

315-
if (empty($data)) {
315+
if (empty($rawData->getLineData())) {
316316
return;
317317
}
318318

@@ -339,7 +339,7 @@ public function append(array $data, $id = null, bool $append = true, $linesToBeC
339339

340340
$this->tests[$id] = ['size' => $size, 'status' => $status];
341341

342-
foreach ($data as $file => $lines) {
342+
foreach ($rawData->getLineData() as $file => $lines) {
343343
if (!$this->filter->isFile($file)) {
344344
continue;
345345
}
@@ -499,15 +499,15 @@ private function getLinePriority($data, $line)
499499
* @throws MissingCoversAnnotationException
500500
* @throws UnintentionallyCoveredCodeException
501501
*/
502-
private function applyCoversAnnotationFilter(array &$data, $linesToBeCovered, array $linesToBeUsed, bool $ignoreForceCoversAnnotation): void
502+
private function applyCoversAnnotationFilter(RawCodeCoverageData $rawData, $linesToBeCovered, array $linesToBeUsed, bool $ignoreForceCoversAnnotation): void
503503
{
504504
if ($linesToBeCovered === false ||
505505
($this->forceCoversAnnotation && empty($linesToBeCovered) && !$ignoreForceCoversAnnotation)) {
506506
if ($this->checkForMissingCoversAnnotation) {
507507
throw new MissingCoversAnnotationException;
508508
}
509509

510-
$data = [];
510+
$rawData->clear();
511511

512512
return;
513513
}
@@ -519,49 +519,49 @@ private function applyCoversAnnotationFilter(array &$data, $linesToBeCovered, ar
519519
if ($this->checkForUnintentionallyCoveredCode &&
520520
(!$this->currentId instanceof TestCase ||
521521
(!$this->currentId->isMedium() && !$this->currentId->isLarge()))) {
522-
$this->performUnintentionallyCoveredCodeCheck($data, $linesToBeCovered, $linesToBeUsed);
522+
$this->performUnintentionallyCoveredCodeCheck($rawData, $linesToBeCovered, $linesToBeUsed);
523523
}
524524

525525
if ($this->checkForUnexecutedCoveredCode) {
526-
$this->performUnexecutedCoveredCodeCheck($data, $linesToBeCovered, $linesToBeUsed);
526+
$this->performUnexecutedCoveredCodeCheck($rawData, $linesToBeCovered, $linesToBeUsed);
527527
}
528528

529-
$data = \array_intersect_key($data, $linesToBeCovered);
529+
$rawLineData = $rawData->getLineData();
530+
$filesWithNoCoverage = \array_diff_key($rawLineData, $linesToBeCovered);
530531

531-
foreach (\array_keys($data) as $filename) {
532-
$_linesToBeCovered = \array_flip($linesToBeCovered[$filename]);
533-
$data[$filename] = \array_intersect_key($data[$filename], $_linesToBeCovered);
532+
foreach (\array_keys($filesWithNoCoverage) as $fileWithNoCoverage) {
533+
$rawData->removeCoverageDataForFile($fileWithNoCoverage);
534+
}
535+
536+
if (\is_array($linesToBeCovered)) {
537+
foreach ($linesToBeCovered as $fileToBeCovered => $includedLines) {
538+
$rawData->keepCoverageDataOnlyForLines($fileToBeCovered, $includedLines);
539+
}
534540
}
535541
}
536542

537-
private function applyWhitelistFilter(array &$data): void
543+
private function applyWhitelistFilter(RawCodeCoverageData $data): void
538544
{
539-
foreach (\array_keys($data) as $filename) {
545+
foreach (\array_keys($data->getLineData()) as $filename) {
540546
if ($this->filter->isFiltered($filename)) {
541-
unset($data[$filename]);
547+
$data->removeCoverageDataForFile($filename);
542548
}
543549
}
544550
}
545551

546552
/**
547553
* @throws \SebastianBergmann\CodeCoverage\InvalidArgumentException
548554
*/
549-
private function applyIgnoredLinesFilter(array &$data): void
555+
private function applyIgnoredLinesFilter(RawCodeCoverageData $data): void
550556
{
551-
foreach (\array_keys($data) as $filename) {
552-
if (!$this->filter->isFile($filename)) {
553-
continue;
554-
}
555-
556-
foreach ($this->getLinesToBeIgnored($filename) as $line) {
557-
unset($data[$filename][$line]);
558-
}
557+
foreach (\array_keys($data->getLineData()) as $filename) {
558+
$data->removeCoverageDataForLines($filename, $this->getLinesToBeIgnored($filename));
559559
}
560560
}
561561

562-
private function initializeFilesThatAreSeenTheFirstTime(array $data): void
562+
private function initializeFilesThatAreSeenTheFirstTime(RawCodeCoverageData $data): void
563563
{
564-
foreach ($data as $file => $lines) {
564+
foreach ($data->getLineData() as $file => $lines) {
565565
if (!isset($this->data[$file]) && $this->filter->isFile($file)) {
566566
$this->data[$file] = [];
567567

@@ -602,7 +602,7 @@ private function addUncoveredFilesFromWhitelist(): void
602602
}
603603
}
604604

605-
$this->append($data, 'UNCOVERED_FILES_FROM_WHITELIST');
605+
$this->append(new RawCodeCoverageData($data), 'UNCOVERED_FILES_FROM_WHITELIST');
606606
}
607607

608608
private function getLinesToBeIgnored(string $fileName): array
@@ -793,7 +793,7 @@ private function getLinesToBeIgnoredInner(string $fileName): array
793793
* @throws \ReflectionException
794794
* @throws UnintentionallyCoveredCodeException
795795
*/
796-
private function performUnintentionallyCoveredCodeCheck(array &$data, array $linesToBeCovered, array $linesToBeUsed): void
796+
private function performUnintentionallyCoveredCodeCheck(RawCodeCoverageData $data, array $linesToBeCovered, array $linesToBeUsed): void
797797
{
798798
$allowedLines = $this->getAllowedLines(
799799
$linesToBeCovered,
@@ -802,7 +802,7 @@ private function performUnintentionallyCoveredCodeCheck(array &$data, array $lin
802802

803803
$unintentionallyCoveredUnits = [];
804804

805-
foreach ($data as $file => $_data) {
805+
foreach ($data->getLineData() as $file => $_data) {
806806
foreach ($_data as $line => $flag) {
807807
if ($flag === 1 && !isset($allowedLines[$file][$line])) {
808808
$unintentionallyCoveredUnits[] = $this->wizard->lookup($file, $line);
@@ -822,9 +822,9 @@ private function performUnintentionallyCoveredCodeCheck(array &$data, array $lin
822822
/**
823823
* @throws CoveredCodeNotExecutedException
824824
*/
825-
private function performUnexecutedCoveredCodeCheck(array &$data, array $linesToBeCovered, array $linesToBeUsed): void
825+
private function performUnexecutedCoveredCodeCheck(RawCodeCoverageData $rawData, array $linesToBeCovered, array $linesToBeUsed): void
826826
{
827-
$executedCodeUnits = $this->coverageToCodeUnits($data);
827+
$executedCodeUnits = $this->coverageToCodeUnits($rawData);
828828
$message = '';
829829

830830
foreach ($this->linesToCodeUnits($linesToBeCovered) as $codeUnit) {
@@ -958,7 +958,7 @@ private function initializeData(): void
958958

959959
$data = [];
960960

961-
foreach ($this->driver->stop() as $file => $fileCoverage) {
961+
foreach ($this->driver->stop()->getLineData() as $file => $fileCoverage) {
962962
if ($this->filter->isFiltered($file)) {
963963
continue;
964964
}
@@ -972,15 +972,15 @@ private function initializeData(): void
972972
$data[$file] = $fileCoverage;
973973
}
974974

975-
$this->append($data, 'UNCOVERED_FILES_FROM_WHITELIST');
975+
$this->append(new RawCodeCoverageData($data), 'UNCOVERED_FILES_FROM_WHITELIST');
976976
}
977977
}
978978

979-
private function coverageToCodeUnits(array $data): array
979+
private function coverageToCodeUnits(RawCodeCoverageData $rawData): array
980980
{
981981
$codeUnits = [];
982982

983-
foreach ($data as $filename => $lines) {
983+
foreach ($rawData->getLineData() as $filename => $lines) {
984984
foreach ($lines as $line => $flag) {
985985
if ($flag === 1) {
986986
$codeUnits[] = $this->wizard->lookup($filename, $line);

src/Driver/Driver.php

+3-1
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@
99
*/
1010
namespace SebastianBergmann\CodeCoverage\Driver;
1111

12+
use SebastianBergmann\CodeCoverage\RawCodeCoverageData;
13+
1214
/**
1315
* Interface for code coverage drivers.
1416
*/
@@ -43,5 +45,5 @@ public function start(bool $determineUnusedAndDead = true): void;
4345
/**
4446
* Stop collection of code coverage information.
4547
*/
46-
public function stop(): array;
48+
public function stop(): RawCodeCoverageData;
4749
}

src/Driver/PCOV.php

+3-2
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
namespace SebastianBergmann\CodeCoverage\Driver;
1111

1212
use SebastianBergmann\CodeCoverage\Filter;
13+
use SebastianBergmann\CodeCoverage\RawCodeCoverageData;
1314

1415
/**
1516
* Driver for PCOV code coverage functionality.
@@ -37,14 +38,14 @@ public function start(bool $determineUnusedAndDead = true): void
3738
/**
3839
* Stop collection of code coverage information.
3940
*/
40-
public function stop(): array
41+
public function stop(): RawCodeCoverageData
4142
{
4243
\pcov\stop();
4344

4445
$collect = \pcov\collect(\pcov\inclusive, $this->filter->getWhitelist());
4546

4647
\pcov\clear();
4748

48-
return $collect;
49+
return new RawCodeCoverageData($collect);
4950
}
5051
}

src/Driver/PHPDBG.php

+3-2
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
*/
1010
namespace SebastianBergmann\CodeCoverage\Driver;
1111

12+
use SebastianBergmann\CodeCoverage\RawCodeCoverageData;
1213
use SebastianBergmann\CodeCoverage\RuntimeException;
1314

1415
/**
@@ -45,7 +46,7 @@ public function start(bool $determineUnusedAndDead = true): void
4546
/**
4647
* Stop collection of code coverage information.
4748
*/
48-
public function stop(): array
49+
public function stop(): RawCodeCoverageData
4950
{
5051
static $fetchedLines = [];
5152

@@ -71,7 +72,7 @@ public function stop(): array
7172

7273
$fetchedLines = \array_merge($fetchedLines, $sourceLines);
7374

74-
return $this->detectExecutedLines($fetchedLines, $dbgData);
75+
return new RawCodeCoverageData($this->detectExecutedLines($fetchedLines, $dbgData));
7576
}
7677

7778
/**

src/Driver/Xdebug.php

+3-2
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
namespace SebastianBergmann\CodeCoverage\Driver;
1111

1212
use SebastianBergmann\CodeCoverage\Filter;
13+
use SebastianBergmann\CodeCoverage\RawCodeCoverageData;
1314
use SebastianBergmann\CodeCoverage\RuntimeException;
1415

1516
/**
@@ -48,12 +49,12 @@ public function start(bool $determineUnusedAndDead = true): void
4849
/**
4950
* Stop collection of code coverage information.
5051
*/
51-
public function stop(): array
52+
public function stop(): RawCodeCoverageData
5253
{
5354
$data = \xdebug_get_code_coverage();
5455

5556
\xdebug_stop_code_coverage();
5657

57-
return $data;
58+
return new RawCodeCoverageData($data);
5859
}
5960
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
<?php declare(strict_types=1);
2+
/*
3+
* This file is part of phpunit/php-code-coverage.
4+
*
5+
* (c) Sebastian Bergmann <[email protected]>
6+
*
7+
* For the full copyright and license information, please view the LICENSE
8+
* file that was distributed with this source code.
9+
*/
10+
namespace SebastianBergmann\CodeCoverage;
11+
12+
/**
13+
* Exception that is raised when a driver supplies coverage data in a format that cannot be handled.
14+
*/
15+
final class UnknownCoverageDataFormatException extends RuntimeException
16+
{
17+
public static function create(string $filename): self
18+
{
19+
return new self(
20+
\sprintf(
21+
'Coverage data for file "%s" must be in Xdebug-compatible format, see https://xdebug.org/docs/code_coverage',
22+
$filename
23+
)
24+
);
25+
}
26+
}

0 commit comments

Comments
 (0)