Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Encapsulate raw coverage data from drivers #748

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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