/vendor/phpunit/php-code-coverage/src/RawCodeCoverageData.php
https://gitlab.com/jjpa2018/dashboard · PHP · 227 lines · 151 code · 36 blank · 40 comment · 13 complexity · 006356e880fe76f64ab63af3a3e22a36 MD5 · raw file
- <?php declare(strict_types=1);
- /*
- * This file is part of phpunit/php-code-coverage.
- *
- * (c) Sebastian Bergmann <sebastian@phpunit.de>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
- namespace SebastianBergmann\CodeCoverage;
- use function array_diff;
- use function array_diff_key;
- use function array_flip;
- use function array_intersect;
- use function array_intersect_key;
- use function count;
- use function file;
- use function in_array;
- use function range;
- use SebastianBergmann\CodeCoverage\Driver\Driver;
- use SebastianBergmann\CodeCoverage\StaticAnalysis\UncoveredFileAnalyser;
- /**
- * @internal This class is not covered by the backward compatibility promise for phpunit/php-code-coverage
- */
- final class RawCodeCoverageData
- {
- /**
- * @var array<string, array<int>>
- */
- private static $emptyLineCache = [];
- /**
- * @var array
- *
- * @see https://xdebug.org/docs/code_coverage for format
- */
- private $lineCoverage;
- /**
- * @var array
- *
- * @see https://xdebug.org/docs/code_coverage for format
- */
- private $functionCoverage;
- public static function fromXdebugWithoutPathCoverage(array $rawCoverage): self
- {
- return new self($rawCoverage, []);
- }
- public static function fromXdebugWithPathCoverage(array $rawCoverage): self
- {
- $lineCoverage = [];
- $functionCoverage = [];
- foreach ($rawCoverage as $file => $fileCoverageData) {
- $lineCoverage[$file] = $fileCoverageData['lines'];
- $functionCoverage[$file] = $fileCoverageData['functions'];
- }
- return new self($lineCoverage, $functionCoverage);
- }
- public static function fromXdebugWithMixedCoverage(array $rawCoverage): self
- {
- $lineCoverage = [];
- $functionCoverage = [];
- foreach ($rawCoverage as $file => $fileCoverageData) {
- if (!isset($fileCoverageData['functions'])) {
- // Current file does not have functions, so line coverage
- // is stored in $fileCoverageData, not in $fileCoverageData['lines']
- $lineCoverage[$file] = $fileCoverageData;
- continue;
- }
- $lineCoverage[$file] = $fileCoverageData['lines'];
- $functionCoverage[$file] = $fileCoverageData['functions'];
- }
- return new self($lineCoverage, $functionCoverage);
- }
- public static function fromUncoveredFile(string $filename, UncoveredFileAnalyser $uncoveredFileAnalyser): self
- {
- $lineCoverage = [];
- foreach ($uncoveredFileAnalyser->executableLinesIn($filename) as $line) {
- $lineCoverage[$line] = Driver::LINE_NOT_EXECUTED;
- }
- return new self([$filename => $lineCoverage], []);
- }
- private function __construct(array $lineCoverage, array $functionCoverage)
- {
- $this->lineCoverage = $lineCoverage;
- $this->functionCoverage = $functionCoverage;
- $this->skipEmptyLines();
- }
- public function clear(): void
- {
- $this->lineCoverage = $this->functionCoverage = [];
- }
- public function lineCoverage(): array
- {
- return $this->lineCoverage;
- }
- public function functionCoverage(): array
- {
- return $this->functionCoverage;
- }
- public function removeCoverageDataForFile(string $filename): void
- {
- unset($this->lineCoverage[$filename], $this->functionCoverage[$filename]);
- }
- /**
- * @param int[] $lines
- */
- public function keepCoverageDataOnlyForLines(string $filename, array $lines): void
- {
- if (!isset($this->lineCoverage[$filename])) {
- return;
- }
- $this->lineCoverage[$filename] = array_intersect_key(
- $this->lineCoverage[$filename],
- array_flip($lines)
- );
- if (isset($this->functionCoverage[$filename])) {
- foreach ($this->functionCoverage[$filename] as $functionName => $functionData) {
- foreach ($functionData['branches'] as $branchId => $branch) {
- if (count(array_diff(range($branch['line_start'], $branch['line_end']), $lines)) > 0) {
- unset($this->functionCoverage[$filename][$functionName]['branches'][$branchId]);
- foreach ($functionData['paths'] as $pathId => $path) {
- if (in_array($branchId, $path['path'], true)) {
- unset($this->functionCoverage[$filename][$functionName]['paths'][$pathId]);
- }
- }
- }
- }
- }
- }
- }
- /**
- * @param int[] $lines
- */
- public function removeCoverageDataForLines(string $filename, array $lines): void
- {
- if (empty($lines)) {
- return;
- }
- if (!isset($this->lineCoverage[$filename])) {
- return;
- }
- $this->lineCoverage[$filename] = array_diff_key(
- $this->lineCoverage[$filename],
- array_flip($lines)
- );
- if (isset($this->functionCoverage[$filename])) {
- foreach ($this->functionCoverage[$filename] as $functionName => $functionData) {
- foreach ($functionData['branches'] as $branchId => $branch) {
- if (count(array_intersect($lines, range($branch['line_start'], $branch['line_end']))) > 0) {
- unset($this->functionCoverage[$filename][$functionName]['branches'][$branchId]);
- foreach ($functionData['paths'] as $pathId => $path) {
- if (in_array($branchId, $path['path'], true)) {
- unset($this->functionCoverage[$filename][$functionName]['paths'][$pathId]);
- }
- }
- }
- }
- }
- }
- }
- /**
- * At the end of a file, the PHP interpreter always sees an implicit return. Where this occurs in a file that has
- * e.g. a class definition, that line cannot be invoked from a test and results in confusing coverage. This engine
- * implementation detail therefore needs to be masked which is done here by simply ensuring that all empty lines
- * are skipped over for coverage purposes.
- *
- * @see https://github.com/sebastianbergmann/php-code-coverage/issues/799
- */
- private function skipEmptyLines(): void
- {
- foreach ($this->lineCoverage as $filename => $coverage) {
- foreach ($this->getEmptyLinesForFile($filename) as $emptyLine) {
- unset($this->lineCoverage[$filename][$emptyLine]);
- }
- }
- }
- private function getEmptyLinesForFile(string $filename): array
- {
- if (!isset(self::$emptyLineCache[$filename])) {
- self::$emptyLineCache[$filename] = [];
- if (is_file($filename)) {
- $sourceLines = explode("\n", file_get_contents($filename));
- foreach ($sourceLines as $line => $source) {
- if (trim($source) === '') {
- self::$emptyLineCache[$filename][] = ($line + 1);
- }
- }
- }
- }
- return self::$emptyLineCache[$filename];
- }
- }