Skip to content

Commit

Permalink
Encapsulate raw coverage data from drivers
Browse files Browse the repository at this point in the history
  • Loading branch information
dvdoug authored and sebastianbergmann committed May 14, 2020
1 parent 0be1afd commit 3203df5
Show file tree
Hide file tree
Showing 10 changed files with 405 additions and 81 deletions.
78 changes: 39 additions & 39 deletions src/CodeCoverage.php
Original file line number Diff line number Diff line change
Expand Up @@ -255,7 +255,7 @@ public function start($id, bool $clear = false): void
* @throws InvalidArgumentException
* @throws \ReflectionException
*/
public function stop(bool $append = true, $linesToBeCovered = [], array $linesToBeUsed = [], bool $ignoreForceCoversAnnotation = false): array
public function stop(bool $append = true, $linesToBeCovered = [], array $linesToBeUsed = [], bool $ignoreForceCoversAnnotation = false): RawCodeCoverageData
{
if (!\is_array($linesToBeCovered) && $linesToBeCovered !== false) {
throw InvalidArgumentException::create(
Expand Down Expand Up @@ -285,7 +285,7 @@ public function stop(bool $append = true, $linesToBeCovered = [], array $linesTo
* @throws \SebastianBergmann\CodeCoverage\InvalidArgumentException
* @throws RuntimeException
*/
public function append(array $data, $id = null, bool $append = true, $linesToBeCovered = [], array $linesToBeUsed = [], bool $ignoreForceCoversAnnotation = false): void
public function append(RawCodeCoverageData $rawData, $id = null, bool $append = true, $linesToBeCovered = [], array $linesToBeUsed = [], bool $ignoreForceCoversAnnotation = false): void
{
if ($id === null) {
$id = $this->currentId;
Expand All @@ -295,24 +295,24 @@ public function append(array $data, $id = null, bool $append = true, $linesToBeC
throw new RuntimeException;
}

$this->applyWhitelistFilter($data);
$this->applyIgnoredLinesFilter($data);
$this->initializeFilesThatAreSeenTheFirstTime($data);
$this->applyWhitelistFilter($rawData);
$this->applyIgnoredLinesFilter($rawData);
$this->initializeFilesThatAreSeenTheFirstTime($rawData);

if (!$append) {
return;
}

if ($id !== 'UNCOVERED_FILES_FROM_WHITELIST') {
$this->applyCoversAnnotationFilter(
$data,
$rawData,
$linesToBeCovered,
$linesToBeUsed,
$ignoreForceCoversAnnotation
);
}

if (empty($data)) {
if (empty($rawData->getLineData())) {
return;
}

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

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

foreach ($data as $file => $lines) {
foreach ($rawData->getLineData() as $file => $lines) {
if (!$this->filter->isFile($file)) {
continue;
}
Expand Down Expand Up @@ -499,15 +499,15 @@ private function getLinePriority($data, $line)
* @throws MissingCoversAnnotationException
* @throws UnintentionallyCoveredCodeException
*/
private function applyCoversAnnotationFilter(array &$data, $linesToBeCovered, array $linesToBeUsed, bool $ignoreForceCoversAnnotation): void
private function applyCoversAnnotationFilter(RawCodeCoverageData $rawData, $linesToBeCovered, array $linesToBeUsed, bool $ignoreForceCoversAnnotation): void
{
if ($linesToBeCovered === false ||
($this->forceCoversAnnotation && empty($linesToBeCovered) && !$ignoreForceCoversAnnotation)) {
if ($this->checkForMissingCoversAnnotation) {
throw new MissingCoversAnnotationException;
}

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

return;
}
Expand All @@ -519,49 +519,49 @@ private function applyCoversAnnotationFilter(array &$data, $linesToBeCovered, ar
if ($this->checkForUnintentionallyCoveredCode &&
(!$this->currentId instanceof TestCase ||
(!$this->currentId->isMedium() && !$this->currentId->isLarge()))) {
$this->performUnintentionallyCoveredCodeCheck($data, $linesToBeCovered, $linesToBeUsed);
$this->performUnintentionallyCoveredCodeCheck($rawData, $linesToBeCovered, $linesToBeUsed);
}

if ($this->checkForUnexecutedCoveredCode) {
$this->performUnexecutedCoveredCodeCheck($data, $linesToBeCovered, $linesToBeUsed);
$this->performUnexecutedCoveredCodeCheck($rawData, $linesToBeCovered, $linesToBeUsed);
}

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

foreach (\array_keys($data) as $filename) {
$_linesToBeCovered = \array_flip($linesToBeCovered[$filename]);
$data[$filename] = \array_intersect_key($data[$filename], $_linesToBeCovered);
foreach (\array_keys($filesWithNoCoverage) as $fileWithNoCoverage) {
$rawData->removeCoverageDataForFile($fileWithNoCoverage);
}

if (\is_array($linesToBeCovered)) {
foreach ($linesToBeCovered as $fileToBeCovered => $includedLines) {
$rawData->keepCoverageDataOnlyForLines($fileToBeCovered, $includedLines);
}
}
}

private function applyWhitelistFilter(array &$data): void
private function applyWhitelistFilter(RawCodeCoverageData $data): void
{
foreach (\array_keys($data) as $filename) {
foreach (\array_keys($data->getLineData()) as $filename) {
if ($this->filter->isFiltered($filename)) {
unset($data[$filename]);
$data->removeCoverageDataForFile($filename);
}
}
}

/**
* @throws \SebastianBergmann\CodeCoverage\InvalidArgumentException
*/
private function applyIgnoredLinesFilter(array &$data): void
private function applyIgnoredLinesFilter(RawCodeCoverageData $data): void
{
foreach (\array_keys($data) as $filename) {
if (!$this->filter->isFile($filename)) {
continue;
}

foreach ($this->getLinesToBeIgnored($filename) as $line) {
unset($data[$filename][$line]);
}
foreach (\array_keys($data->getLineData()) as $filename) {
$data->removeCoverageDataForLines($filename, $this->getLinesToBeIgnored($filename));
}
}

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

Expand Down Expand Up @@ -602,7 +602,7 @@ private function addUncoveredFilesFromWhitelist(): void
}
}

$this->append($data, 'UNCOVERED_FILES_FROM_WHITELIST');
$this->append(new RawCodeCoverageData($data), 'UNCOVERED_FILES_FROM_WHITELIST');
}

private function getLinesToBeIgnored(string $fileName): array
Expand Down Expand Up @@ -793,7 +793,7 @@ private function getLinesToBeIgnoredInner(string $fileName): array
* @throws \ReflectionException
* @throws UnintentionallyCoveredCodeException
*/
private function performUnintentionallyCoveredCodeCheck(array &$data, array $linesToBeCovered, array $linesToBeUsed): void
private function performUnintentionallyCoveredCodeCheck(RawCodeCoverageData $data, array $linesToBeCovered, array $linesToBeUsed): void
{
$allowedLines = $this->getAllowedLines(
$linesToBeCovered,
Expand All @@ -802,7 +802,7 @@ private function performUnintentionallyCoveredCodeCheck(array &$data, array $lin

$unintentionallyCoveredUnits = [];

foreach ($data as $file => $_data) {
foreach ($data->getLineData() as $file => $_data) {
foreach ($_data as $line => $flag) {
if ($flag === 1 && !isset($allowedLines[$file][$line])) {
$unintentionallyCoveredUnits[] = $this->wizard->lookup($file, $line);
Expand All @@ -822,9 +822,9 @@ private function performUnintentionallyCoveredCodeCheck(array &$data, array $lin
/**
* @throws CoveredCodeNotExecutedException
*/
private function performUnexecutedCoveredCodeCheck(array &$data, array $linesToBeCovered, array $linesToBeUsed): void
private function performUnexecutedCoveredCodeCheck(RawCodeCoverageData $rawData, array $linesToBeCovered, array $linesToBeUsed): void
{
$executedCodeUnits = $this->coverageToCodeUnits($data);
$executedCodeUnits = $this->coverageToCodeUnits($rawData);
$message = '';

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

$data = [];

foreach ($this->driver->stop() as $file => $fileCoverage) {
foreach ($this->driver->stop()->getLineData() as $file => $fileCoverage) {
if ($this->filter->isFiltered($file)) {
continue;
}
Expand All @@ -972,15 +972,15 @@ private function initializeData(): void
$data[$file] = $fileCoverage;
}

$this->append($data, 'UNCOVERED_FILES_FROM_WHITELIST');
$this->append(new RawCodeCoverageData($data), 'UNCOVERED_FILES_FROM_WHITELIST');
}
}

private function coverageToCodeUnits(array $data): array
private function coverageToCodeUnits(RawCodeCoverageData $rawData): array
{
$codeUnits = [];

foreach ($data as $filename => $lines) {
foreach ($rawData->getLineData() as $filename => $lines) {
foreach ($lines as $line => $flag) {
if ($flag === 1) {
$codeUnits[] = $this->wizard->lookup($filename, $line);
Expand Down
4 changes: 3 additions & 1 deletion src/Driver/Driver.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@
*/
namespace SebastianBergmann\CodeCoverage\Driver;

use SebastianBergmann\CodeCoverage\RawCodeCoverageData;

/**
* Interface for code coverage drivers.
*/
Expand Down Expand Up @@ -43,5 +45,5 @@ public function start(bool $determineUnusedAndDead = true): void;
/**
* Stop collection of code coverage information.
*/
public function stop(): array;
public function stop(): RawCodeCoverageData;
}
5 changes: 3 additions & 2 deletions src/Driver/PCOV.php
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
namespace SebastianBergmann\CodeCoverage\Driver;

use SebastianBergmann\CodeCoverage\Filter;
use SebastianBergmann\CodeCoverage\RawCodeCoverageData;

/**
* Driver for PCOV code coverage functionality.
Expand Down Expand Up @@ -37,14 +38,14 @@ public function start(bool $determineUnusedAndDead = true): void
/**
* Stop collection of code coverage information.
*/
public function stop(): array
public function stop(): RawCodeCoverageData
{
\pcov\stop();

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

\pcov\clear();

return $collect;
return new RawCodeCoverageData($collect);
}
}
5 changes: 3 additions & 2 deletions src/Driver/PHPDBG.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
*/
namespace SebastianBergmann\CodeCoverage\Driver;

use SebastianBergmann\CodeCoverage\RawCodeCoverageData;
use SebastianBergmann\CodeCoverage\RuntimeException;

/**
Expand Down Expand Up @@ -45,7 +46,7 @@ public function start(bool $determineUnusedAndDead = true): void
/**
* Stop collection of code coverage information.
*/
public function stop(): array
public function stop(): RawCodeCoverageData
{
static $fetchedLines = [];

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

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

return $this->detectExecutedLines($fetchedLines, $dbgData);
return new RawCodeCoverageData($this->detectExecutedLines($fetchedLines, $dbgData));
}

/**
Expand Down
5 changes: 3 additions & 2 deletions src/Driver/Xdebug.php
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
namespace SebastianBergmann\CodeCoverage\Driver;

use SebastianBergmann\CodeCoverage\Filter;
use SebastianBergmann\CodeCoverage\RawCodeCoverageData;
use SebastianBergmann\CodeCoverage\RuntimeException;

/**
Expand Down Expand Up @@ -48,12 +49,12 @@ public function start(bool $determineUnusedAndDead = true): void
/**
* Stop collection of code coverage information.
*/
public function stop(): array
public function stop(): RawCodeCoverageData
{
$data = \xdebug_get_code_coverage();

\xdebug_stop_code_coverage();

return $data;
return new RawCodeCoverageData($data);
}
}
26 changes: 26 additions & 0 deletions src/Exception/UnknownCoverageDataFormatException.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
<?php declare(strict_types=1);
/*
* This file is part of phpunit/php-code-coverage.
*
* (c) Sebastian Bergmann <[email protected]>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace SebastianBergmann\CodeCoverage;

/**
* Exception that is raised when a driver supplies coverage data in a format that cannot be handled.
*/
final class UnknownCoverageDataFormatException extends RuntimeException
{
public static function create(string $filename): self
{
return new self(
\sprintf(
'Coverage data for file "%s" must be in Xdebug-compatible format, see https://xdebug.org/docs/code_coverage',
$filename
)
);
}
}
Loading

0 comments on commit 3203df5

Please sign in to comment.