upgrade to laravel 8.x

This commit is contained in:
2021-05-30 08:20:41 +00:00
parent 41b78a0599
commit 3ad6ed8bfa
2333 changed files with 113904 additions and 59058 deletions

View File

@@ -1,6 +1,6 @@
<?php declare(strict_types=1);
/*
* This file is part of the php-code-coverage package.
* This file is part of phpunit/php-code-coverage.
*
* (c) Sebastian Bergmann <sebastian@phpunit.de>
*
@@ -9,12 +9,18 @@
*/
namespace SebastianBergmann\CodeCoverage\Node;
use SebastianBergmann\CodeCoverage\Util;
use const DIRECTORY_SEPARATOR;
use function array_merge;
use function str_replace;
use function substr;
use Countable;
use SebastianBergmann\CodeCoverage\Percentage;
use SebastianBergmann\LinesOfCode\LinesOfCode;
/**
* Base class for nodes in the code coverage information tree.
* @internal This class is not covered by the backward compatibility promise for phpunit/php-code-coverage
*/
abstract class AbstractNode implements \Countable
abstract class AbstractNode implements Countable
{
/**
* @var string
@@ -24,12 +30,12 @@ abstract class AbstractNode implements \Countable
/**
* @var string
*/
private $path;
private $pathAsString;
/**
* @var array
*/
private $pathArray;
private $pathAsArray;
/**
* @var AbstractNode
@@ -43,31 +49,31 @@ abstract class AbstractNode implements \Countable
public function __construct(string $name, self $parent = null)
{
if (\substr($name, -1) == \DIRECTORY_SEPARATOR) {
$name = \substr($name, 0, -1);
if (substr($name, -1) === DIRECTORY_SEPARATOR) {
$name = substr($name, 0, -1);
}
$this->name = $name;
$this->parent = $parent;
}
public function getName(): string
public function name(): string
{
return $this->name;
}
public function getId(): string
public function id(): string
{
if ($this->id === null) {
$parent = $this->getParent();
$parent = $this->parent();
if ($parent === null) {
$this->id = 'index';
} else {
$parentId = $parent->getId();
$parentId = $parent->id();
if ($parentId === 'index') {
$this->id = \str_replace(':', '_', $this->name);
$this->id = str_replace(':', '_', $this->name);
} else {
$this->id = $parentId . '/' . $this->name;
}
@@ -77,252 +83,169 @@ abstract class AbstractNode implements \Countable
return $this->id;
}
public function getPath(): string
public function pathAsString(): string
{
if ($this->path === null) {
if ($this->parent === null || $this->parent->getPath() === null || $this->parent->getPath() === false) {
$this->path = $this->name;
} else {
$this->path = $this->parent->getPath() . \DIRECTORY_SEPARATOR . $this->name;
}
}
return $this->path;
}
public function getPathAsArray(): array
{
if ($this->pathArray === null) {
if ($this->pathAsString === null) {
if ($this->parent === null) {
$this->pathArray = [];
$this->pathAsString = $this->name;
} else {
$this->pathArray = $this->parent->getPathAsArray();
$this->pathAsString = $this->parent->pathAsString() . DIRECTORY_SEPARATOR . $this->name;
}
$this->pathArray[] = $this;
}
return $this->pathArray;
return $this->pathAsString;
}
public function getParent(): ?self
public function pathAsArray(): array
{
if ($this->pathAsArray === null) {
if ($this->parent === null) {
$this->pathAsArray = [];
} else {
$this->pathAsArray = $this->parent->pathAsArray();
}
$this->pathAsArray[] = $this;
}
return $this->pathAsArray;
}
public function parent(): ?self
{
return $this->parent;
}
/**
* Returns the percentage of classes that has been tested.
*
* @return int|string
*/
public function getTestedClassesPercent(bool $asString = true)
public function percentageOfTestedClasses(): Percentage
{
return Util::percent(
$this->getNumTestedClasses(),
$this->getNumClasses(),
$asString
return Percentage::fromFractionAndTotal(
$this->numberOfTestedClasses(),
$this->numberOfClasses(),
);
}
/**
* Returns the percentage of traits that has been tested.
*
* @return int|string
*/
public function getTestedTraitsPercent(bool $asString = true)
public function percentageOfTestedTraits(): Percentage
{
return Util::percent(
$this->getNumTestedTraits(),
$this->getNumTraits(),
$asString
return Percentage::fromFractionAndTotal(
$this->numberOfTestedTraits(),
$this->numberOfTraits(),
);
}
/**
* Returns the percentage of classes and traits that has been tested.
*
* @return int|string
*/
public function getTestedClassesAndTraitsPercent(bool $asString = true)
public function percentageOfTestedClassesAndTraits(): Percentage
{
return Util::percent(
$this->getNumTestedClassesAndTraits(),
$this->getNumClassesAndTraits(),
$asString
return Percentage::fromFractionAndTotal(
$this->numberOfTestedClassesAndTraits(),
$this->numberOfClassesAndTraits(),
);
}
/**
* Returns the percentage of functions that has been tested.
*
* @return int|string
*/
public function getTestedFunctionsPercent(bool $asString = true)
public function percentageOfTestedFunctions(): Percentage
{
return Util::percent(
$this->getNumTestedFunctions(),
$this->getNumFunctions(),
$asString
return Percentage::fromFractionAndTotal(
$this->numberOfTestedFunctions(),
$this->numberOfFunctions(),
);
}
/**
* Returns the percentage of methods that has been tested.
*
* @return int|string
*/
public function getTestedMethodsPercent(bool $asString = true)
public function percentageOfTestedMethods(): Percentage
{
return Util::percent(
$this->getNumTestedMethods(),
$this->getNumMethods(),
$asString
return Percentage::fromFractionAndTotal(
$this->numberOfTestedMethods(),
$this->numberOfMethods(),
);
}
/**
* Returns the percentage of functions and methods that has been tested.
*
* @return int|string
*/
public function getTestedFunctionsAndMethodsPercent(bool $asString = true)
public function percentageOfTestedFunctionsAndMethods(): Percentage
{
return Util::percent(
$this->getNumTestedFunctionsAndMethods(),
$this->getNumFunctionsAndMethods(),
$asString
return Percentage::fromFractionAndTotal(
$this->numberOfTestedFunctionsAndMethods(),
$this->numberOfFunctionsAndMethods(),
);
}
/**
* Returns the percentage of executed lines.
*
* @return int|string
*/
public function getLineExecutedPercent(bool $asString = true)
public function percentageOfExecutedLines(): Percentage
{
return Util::percent(
$this->getNumExecutedLines(),
$this->getNumExecutableLines(),
$asString
return Percentage::fromFractionAndTotal(
$this->numberOfExecutedLines(),
$this->numberOfExecutableLines(),
);
}
/**
* Returns the number of classes and traits.
*/
public function getNumClassesAndTraits(): int
public function percentageOfExecutedBranches(): Percentage
{
return $this->getNumClasses() + $this->getNumTraits();
return Percentage::fromFractionAndTotal(
$this->numberOfExecutedBranches(),
$this->numberOfExecutableBranches()
);
}
/**
* Returns the number of tested classes and traits.
*/
public function getNumTestedClassesAndTraits(): int
public function percentageOfExecutedPaths(): Percentage
{
return $this->getNumTestedClasses() + $this->getNumTestedTraits();
return Percentage::fromFractionAndTotal(
$this->numberOfExecutedPaths(),
$this->numberOfExecutablePaths()
);
}
/**
* Returns the classes and traits of this node.
*/
public function getClassesAndTraits(): array
public function numberOfClassesAndTraits(): int
{
return \array_merge($this->getClasses(), $this->getTraits());
return $this->numberOfClasses() + $this->numberOfTraits();
}
/**
* Returns the number of functions and methods.
*/
public function getNumFunctionsAndMethods(): int
public function numberOfTestedClassesAndTraits(): int
{
return $this->getNumFunctions() + $this->getNumMethods();
return $this->numberOfTestedClasses() + $this->numberOfTestedTraits();
}
/**
* Returns the number of tested functions and methods.
*/
public function getNumTestedFunctionsAndMethods(): int
public function classesAndTraits(): array
{
return $this->getNumTestedFunctions() + $this->getNumTestedMethods();
return array_merge($this->classes(), $this->traits());
}
/**
* Returns the functions and methods of this node.
*/
public function getFunctionsAndMethods(): array
public function numberOfFunctionsAndMethods(): int
{
return \array_merge($this->getFunctions(), $this->getMethods());
return $this->numberOfFunctions() + $this->numberOfMethods();
}
/**
* Returns the classes of this node.
*/
abstract public function getClasses(): array;
public function numberOfTestedFunctionsAndMethods(): int
{
return $this->numberOfTestedFunctions() + $this->numberOfTestedMethods();
}
/**
* Returns the traits of this node.
*/
abstract public function getTraits(): array;
abstract public function classes(): array;
/**
* Returns the functions of this node.
*/
abstract public function getFunctions(): array;
abstract public function traits(): array;
/**
* Returns the LOC/CLOC/NCLOC of this node.
*/
abstract public function getLinesOfCode(): array;
abstract public function functions(): array;
/**
* Returns the number of executable lines.
*/
abstract public function getNumExecutableLines(): int;
abstract public function linesOfCode(): LinesOfCode;
/**
* Returns the number of executed lines.
*/
abstract public function getNumExecutedLines(): int;
abstract public function numberOfExecutableLines(): int;
/**
* Returns the number of classes.
*/
abstract public function getNumClasses(): int;
abstract public function numberOfExecutedLines(): int;
/**
* Returns the number of tested classes.
*/
abstract public function getNumTestedClasses(): int;
abstract public function numberOfExecutableBranches(): int;
/**
* Returns the number of traits.
*/
abstract public function getNumTraits(): int;
abstract public function numberOfExecutedBranches(): int;
/**
* Returns the number of tested traits.
*/
abstract public function getNumTestedTraits(): int;
abstract public function numberOfExecutablePaths(): int;
/**
* Returns the number of methods.
*/
abstract public function getNumMethods(): int;
abstract public function numberOfExecutedPaths(): int;
/**
* Returns the number of tested methods.
*/
abstract public function getNumTestedMethods(): int;
abstract public function numberOfClasses(): int;
/**
* Returns the number of functions.
*/
abstract public function getNumFunctions(): int;
abstract public function numberOfTestedClasses(): int;
/**
* Returns the number of tested functions.
*/
abstract public function getNumTestedFunctions(): int;
abstract public function numberOfTraits(): int;
abstract public function numberOfTestedTraits(): int;
abstract public function numberOfMethods(): int;
abstract public function numberOfTestedMethods(): int;
abstract public function numberOfFunctions(): int;
abstract public function numberOfTestedFunctions(): int;
}

View File

@@ -1,6 +1,6 @@
<?php declare(strict_types=1);
/*
* This file is part of the php-code-coverage package.
* This file is part of phpunit/php-code-coverage.
*
* (c) Sebastian Bergmann <sebastian@phpunit.de>
*
@@ -9,14 +9,40 @@
*/
namespace SebastianBergmann\CodeCoverage\Node;
use const DIRECTORY_SEPARATOR;
use function array_shift;
use function basename;
use function count;
use function dirname;
use function explode;
use function implode;
use function is_file;
use function str_replace;
use function strpos;
use function substr;
use SebastianBergmann\CodeCoverage\CodeCoverage;
use SebastianBergmann\CodeCoverage\ProcessedCodeCoverageData;
use SebastianBergmann\CodeCoverage\StaticAnalysis\CoveredFileAnalyser;
/**
* @internal This class is not covered by the backward compatibility promise for phpunit/php-code-coverage
*/
final class Builder
{
/**
* @var CoveredFileAnalyser
*/
private $coveredFileAnalyser;
public function __construct(CoveredFileAnalyser $coveredFileAnalyser)
{
$this->coveredFileAnalyser = $coveredFileAnalyser;
}
public function build(CodeCoverage $coverage): Directory
{
$files = $coverage->getData();
$commonPath = $this->reducePaths($files);
$data = clone $coverage->getData(); // clone because path munging is destructive to the original data
$commonPath = $this->reducePaths($data);
$root = new Directory(
$commonPath,
null
@@ -24,28 +50,41 @@ final class Builder
$this->addItems(
$root,
$this->buildDirectoryStructure($files),
$coverage->getTests(),
$coverage->getCacheTokens()
$this->buildDirectoryStructure($data),
$coverage->getTests()
);
return $root;
}
private function addItems(Directory $root, array $items, array $tests, bool $cacheTokens): void
private function addItems(Directory $root, array $items, array $tests): void
{
foreach ($items as $key => $value) {
$key = (string) $key;
if (\substr($key, -2) === '/f') {
$key = \substr($key, 0, -2);
if (substr($key, -2) === '/f') {
$key = substr($key, 0, -2);
$filename = $root->pathAsString() . DIRECTORY_SEPARATOR . $key;
if (\file_exists($root->getPath() . \DIRECTORY_SEPARATOR . $key)) {
$root->addFile($key, $value, $tests, $cacheTokens);
if (is_file($filename)) {
$root->addFile(
new File(
$key,
$root,
$value['lineCoverage'],
$value['functionCoverage'],
$tests,
$this->coveredFileAnalyser->classesIn($filename),
$this->coveredFileAnalyser->traitsIn($filename),
$this->coveredFileAnalyser->functionsIn($filename),
$this->coveredFileAnalyser->linesOfCodeFor($filename)
)
);
}
} else {
$child = $root->addDirectory($key);
$this->addItems($child, $value, $tests, $cacheTokens);
$this->addItems($child, $value, $tests);
}
}
}
@@ -90,14 +129,14 @@ final class Builder
* )
* </code>
*/
private function buildDirectoryStructure(array $files): array
private function buildDirectoryStructure(ProcessedCodeCoverageData $data): array
{
$result = [];
foreach ($files as $path => $file) {
$path = \explode(\DIRECTORY_SEPARATOR, $path);
foreach ($data->coveredFiles() as $originalPath) {
$path = explode(DIRECTORY_SEPARATOR, $originalPath);
$pointer = &$result;
$max = \count($path);
$max = count($path);
for ($i = 0; $i < $max; $i++) {
$type = '';
@@ -109,7 +148,10 @@ final class Builder
$pointer = &$pointer[$path[$i] . $type];
}
$pointer = $file;
$pointer = [
'lineCoverage' => $data->lineCoverage()[$originalPath] ?? [],
'functionCoverage' => $data->functionCoverage()[$originalPath] ?? [],
];
}
return $result;
@@ -152,41 +194,39 @@ final class Builder
* )
* </code>
*/
private function reducePaths(array &$files): string
private function reducePaths(ProcessedCodeCoverageData $coverage): string
{
if (empty($files)) {
if (empty($coverage->coveredFiles())) {
return '.';
}
$commonPath = '';
$paths = \array_keys($files);
$paths = $coverage->coveredFiles();
if (\count($files) === 1) {
$commonPath = \dirname($paths[0]) . \DIRECTORY_SEPARATOR;
$files[\basename($paths[0])] = $files[$paths[0]];
unset($files[$paths[0]]);
if (count($paths) === 1) {
$commonPath = dirname($paths[0]) . DIRECTORY_SEPARATOR;
$coverage->renameFile($paths[0], basename($paths[0]));
return $commonPath;
}
$max = \count($paths);
$max = count($paths);
for ($i = 0; $i < $max; $i++) {
// strip phar:// prefixes
if (\strpos($paths[$i], 'phar://') === 0) {
$paths[$i] = \substr($paths[$i], 7);
$paths[$i] = \str_replace('/', \DIRECTORY_SEPARATOR, $paths[$i]);
if (strpos($paths[$i], 'phar://') === 0) {
$paths[$i] = substr($paths[$i], 7);
$paths[$i] = str_replace('/', DIRECTORY_SEPARATOR, $paths[$i]);
}
$paths[$i] = \explode(\DIRECTORY_SEPARATOR, $paths[$i]);
$paths[$i] = explode(DIRECTORY_SEPARATOR, $paths[$i]);
if (empty($paths[$i][0])) {
$paths[$i][0] = \DIRECTORY_SEPARATOR;
$paths[$i][0] = DIRECTORY_SEPARATOR;
}
}
$done = false;
$max = \count($paths);
$max = count($paths);
while (!$done) {
for ($i = 0; $i < $max - 1; $i++) {
@@ -202,26 +242,23 @@ final class Builder
if (!$done) {
$commonPath .= $paths[0][0];
if ($paths[0][0] !== \DIRECTORY_SEPARATOR) {
$commonPath .= \DIRECTORY_SEPARATOR;
if ($paths[0][0] !== DIRECTORY_SEPARATOR) {
$commonPath .= DIRECTORY_SEPARATOR;
}
for ($i = 0; $i < $max; $i++) {
\array_shift($paths[$i]);
array_shift($paths[$i]);
}
}
}
$original = \array_keys($files);
$max = \count($original);
$original = $coverage->coveredFiles();
$max = count($original);
for ($i = 0; $i < $max; $i++) {
$files[\implode(\DIRECTORY_SEPARATOR, $paths[$i])] = $files[$original[$i]];
unset($files[$original[$i]]);
$coverage->renameFile($original[$i], implode(DIRECTORY_SEPARATOR, $paths[$i]));
}
\ksort($files);
return \substr($commonPath, 0, -1);
return substr($commonPath, 0, -1);
}
}

View File

@@ -1,6 +1,6 @@
<?php declare(strict_types=1);
/*
* This file is part of the php-code-coverage package.
* This file is part of phpunit/php-code-coverage.
*
* (c) Sebastian Bergmann <sebastian@phpunit.de>
*
@@ -9,12 +9,16 @@
*/
namespace SebastianBergmann\CodeCoverage\Node;
use SebastianBergmann\CodeCoverage\InvalidArgumentException;
use function array_merge;
use function count;
use IteratorAggregate;
use RecursiveIteratorIterator;
use SebastianBergmann\LinesOfCode\LinesOfCode;
/**
* Represents a directory in the code coverage information tree.
* @internal This class is not covered by the backward compatibility promise for phpunit/php-code-coverage
*/
final class Directory extends AbstractNode implements \IteratorAggregate
final class Directory extends AbstractNode implements IteratorAggregate
{
/**
* @var AbstractNode[]
@@ -47,7 +51,7 @@ final class Directory extends AbstractNode implements \IteratorAggregate
private $functions;
/**
* @var array
* @var LinesOfCode
*/
private $linesOfCode;
@@ -66,6 +70,26 @@ final class Directory extends AbstractNode implements \IteratorAggregate
*/
private $numExecutedLines = -1;
/**
* @var int
*/
private $numExecutableBranches = -1;
/**
* @var int
*/
private $numExecutedBranches = -1;
/**
* @var int
*/
private $numExecutablePaths = -1;
/**
* @var int
*/
private $numExecutedPaths = -1;
/**
* @var int
*/
@@ -106,100 +130,70 @@ final class Directory extends AbstractNode implements \IteratorAggregate
*/
private $numTestedFunctions = -1;
/**
* Returns the number of files in/under this node.
*/
public function count(): int
{
if ($this->numFiles === -1) {
$this->numFiles = 0;
foreach ($this->children as $child) {
$this->numFiles += \count($child);
$this->numFiles += count($child);
}
}
return $this->numFiles;
}
/**
* Returns an iterator for this node.
*/
public function getIterator(): \RecursiveIteratorIterator
public function getIterator(): RecursiveIteratorIterator
{
return new \RecursiveIteratorIterator(
return new RecursiveIteratorIterator(
new Iterator($this),
\RecursiveIteratorIterator::SELF_FIRST
RecursiveIteratorIterator::SELF_FIRST
);
}
/**
* Adds a new directory.
*/
public function addDirectory(string $name): self
{
$directory = new self($name, $this);
$this->children[] = $directory;
$this->directories[] = &$this->children[\count($this->children) - 1];
$this->directories[] = &$this->children[count($this->children) - 1];
return $directory;
}
/**
* Adds a new file.
*
* @throws InvalidArgumentException
*/
public function addFile(string $name, array $coverageData, array $testData, bool $cacheTokens): File
public function addFile(File $file): void
{
$file = new File($name, $this, $coverageData, $testData, $cacheTokens);
$this->children[] = $file;
$this->files[] = &$this->children[\count($this->children) - 1];
$this->files[] = &$this->children[count($this->children) - 1];
$this->numExecutableLines = -1;
$this->numExecutedLines = -1;
return $file;
}
/**
* Returns the directories in this directory.
*/
public function getDirectories(): array
public function directories(): array
{
return $this->directories;
}
/**
* Returns the files in this directory.
*/
public function getFiles(): array
public function files(): array
{
return $this->files;
}
/**
* Returns the child nodes of this node.
*/
public function getChildNodes(): array
public function children(): array
{
return $this->children;
}
/**
* Returns the classes of this node.
*/
public function getClasses(): array
public function classes(): array
{
if ($this->classes === null) {
$this->classes = [];
foreach ($this->children as $child) {
$this->classes = \array_merge(
$this->classes = array_merge(
$this->classes,
$child->getClasses()
$child->classes()
);
}
}
@@ -207,18 +201,15 @@ final class Directory extends AbstractNode implements \IteratorAggregate
return $this->classes;
}
/**
* Returns the traits of this node.
*/
public function getTraits(): array
public function traits(): array
{
if ($this->traits === null) {
$this->traits = [];
foreach ($this->children as $child) {
$this->traits = \array_merge(
$this->traits = array_merge(
$this->traits,
$child->getTraits()
$child->traits()
);
}
}
@@ -226,18 +217,15 @@ final class Directory extends AbstractNode implements \IteratorAggregate
return $this->traits;
}
/**
* Returns the functions of this node.
*/
public function getFunctions(): array
public function functions(): array
{
if ($this->functions === null) {
$this->functions = [];
foreach ($this->children as $child) {
$this->functions = \array_merge(
$this->functions = array_merge(
$this->functions,
$child->getFunctions()
$child->functions()
);
}
}
@@ -245,180 +233,195 @@ final class Directory extends AbstractNode implements \IteratorAggregate
return $this->functions;
}
/**
* Returns the LOC/CLOC/NCLOC of this node.
*/
public function getLinesOfCode(): array
public function linesOfCode(): LinesOfCode
{
if ($this->linesOfCode === null) {
$this->linesOfCode = ['loc' => 0, 'cloc' => 0, 'ncloc' => 0];
$this->linesOfCode = new LinesOfCode(0, 0, 0, 0);
foreach ($this->children as $child) {
$linesOfCode = $child->getLinesOfCode();
$this->linesOfCode['loc'] += $linesOfCode['loc'];
$this->linesOfCode['cloc'] += $linesOfCode['cloc'];
$this->linesOfCode['ncloc'] += $linesOfCode['ncloc'];
$this->linesOfCode = $this->linesOfCode->plus($child->linesOfCode());
}
}
return $this->linesOfCode;
}
/**
* Returns the number of executable lines.
*/
public function getNumExecutableLines(): int
public function numberOfExecutableLines(): int
{
if ($this->numExecutableLines === -1) {
$this->numExecutableLines = 0;
foreach ($this->children as $child) {
$this->numExecutableLines += $child->getNumExecutableLines();
$this->numExecutableLines += $child->numberOfExecutableLines();
}
}
return $this->numExecutableLines;
}
/**
* Returns the number of executed lines.
*/
public function getNumExecutedLines(): int
public function numberOfExecutedLines(): int
{
if ($this->numExecutedLines === -1) {
$this->numExecutedLines = 0;
foreach ($this->children as $child) {
$this->numExecutedLines += $child->getNumExecutedLines();
$this->numExecutedLines += $child->numberOfExecutedLines();
}
}
return $this->numExecutedLines;
}
/**
* Returns the number of classes.
*/
public function getNumClasses(): int
public function numberOfExecutableBranches(): int
{
if ($this->numExecutableBranches === -1) {
$this->numExecutableBranches = 0;
foreach ($this->children as $child) {
$this->numExecutableBranches += $child->numberOfExecutableBranches();
}
}
return $this->numExecutableBranches;
}
public function numberOfExecutedBranches(): int
{
if ($this->numExecutedBranches === -1) {
$this->numExecutedBranches = 0;
foreach ($this->children as $child) {
$this->numExecutedBranches += $child->numberOfExecutedBranches();
}
}
return $this->numExecutedBranches;
}
public function numberOfExecutablePaths(): int
{
if ($this->numExecutablePaths === -1) {
$this->numExecutablePaths = 0;
foreach ($this->children as $child) {
$this->numExecutablePaths += $child->numberOfExecutablePaths();
}
}
return $this->numExecutablePaths;
}
public function numberOfExecutedPaths(): int
{
if ($this->numExecutedPaths === -1) {
$this->numExecutedPaths = 0;
foreach ($this->children as $child) {
$this->numExecutedPaths += $child->numberOfExecutedPaths();
}
}
return $this->numExecutedPaths;
}
public function numberOfClasses(): int
{
if ($this->numClasses === -1) {
$this->numClasses = 0;
foreach ($this->children as $child) {
$this->numClasses += $child->getNumClasses();
$this->numClasses += $child->numberOfClasses();
}
}
return $this->numClasses;
}
/**
* Returns the number of tested classes.
*/
public function getNumTestedClasses(): int
public function numberOfTestedClasses(): int
{
if ($this->numTestedClasses === -1) {
$this->numTestedClasses = 0;
foreach ($this->children as $child) {
$this->numTestedClasses += $child->getNumTestedClasses();
$this->numTestedClasses += $child->numberOfTestedClasses();
}
}
return $this->numTestedClasses;
}
/**
* Returns the number of traits.
*/
public function getNumTraits(): int
public function numberOfTraits(): int
{
if ($this->numTraits === -1) {
$this->numTraits = 0;
foreach ($this->children as $child) {
$this->numTraits += $child->getNumTraits();
$this->numTraits += $child->numberOfTraits();
}
}
return $this->numTraits;
}
/**
* Returns the number of tested traits.
*/
public function getNumTestedTraits(): int
public function numberOfTestedTraits(): int
{
if ($this->numTestedTraits === -1) {
$this->numTestedTraits = 0;
foreach ($this->children as $child) {
$this->numTestedTraits += $child->getNumTestedTraits();
$this->numTestedTraits += $child->numberOfTestedTraits();
}
}
return $this->numTestedTraits;
}
/**
* Returns the number of methods.
*/
public function getNumMethods(): int
public function numberOfMethods(): int
{
if ($this->numMethods === -1) {
$this->numMethods = 0;
foreach ($this->children as $child) {
$this->numMethods += $child->getNumMethods();
$this->numMethods += $child->numberOfMethods();
}
}
return $this->numMethods;
}
/**
* Returns the number of tested methods.
*/
public function getNumTestedMethods(): int
public function numberOfTestedMethods(): int
{
if ($this->numTestedMethods === -1) {
$this->numTestedMethods = 0;
foreach ($this->children as $child) {
$this->numTestedMethods += $child->getNumTestedMethods();
$this->numTestedMethods += $child->numberOfTestedMethods();
}
}
return $this->numTestedMethods;
}
/**
* Returns the number of functions.
*/
public function getNumFunctions(): int
public function numberOfFunctions(): int
{
if ($this->numFunctions === -1) {
$this->numFunctions = 0;
foreach ($this->children as $child) {
$this->numFunctions += $child->getNumFunctions();
$this->numFunctions += $child->numberOfFunctions();
}
}
return $this->numFunctions;
}
/**
* Returns the number of tested functions.
*/
public function getNumTestedFunctions(): int
public function numberOfTestedFunctions(): int
{
if ($this->numTestedFunctions === -1) {
$this->numTestedFunctions = 0;
foreach ($this->children as $child) {
$this->numTestedFunctions += $child->getNumTestedFunctions();
$this->numTestedFunctions += $child->numberOfTestedFunctions();
}
}

View File

@@ -1,6 +1,6 @@
<?php declare(strict_types=1);
/*
* This file is part of the php-code-coverage package.
* This file is part of phpunit/php-code-coverage.
*
* (c) Sebastian Bergmann <sebastian@phpunit.de>
*
@@ -9,15 +9,26 @@
*/
namespace SebastianBergmann\CodeCoverage\Node;
use function array_filter;
use function count;
use function range;
use SebastianBergmann\CodeCoverage\CrapIndex;
use SebastianBergmann\LinesOfCode\LinesOfCode;
/**
* Represents a file in the code coverage information tree.
* @internal This class is not covered by the backward compatibility promise for phpunit/php-code-coverage
*/
final class File extends AbstractNode
{
/**
* @var array
*/
private $coverageData;
private $lineCoverageData;
/**
* @var array
*/
private $functionCoverageData;
/**
* @var array
@@ -34,6 +45,26 @@ final class File extends AbstractNode
*/
private $numExecutedLines = 0;
/**
* @var int
*/
private $numExecutableBranches = 0;
/**
* @var int
*/
private $numExecutedBranches = 0;
/**
* @var int
*/
private $numExecutablePaths = 0;
/**
* @var int
*/
private $numExecutedPaths = 0;
/**
* @var array
*/
@@ -50,9 +81,9 @@ final class File extends AbstractNode
private $functions = [];
/**
* @var array
* @var LinesOfCode
*/
private $linesOfCode = [];
private $linesOfCode;
/**
* @var int
@@ -89,103 +120,94 @@ final class File extends AbstractNode
*/
private $numTestedFunctions;
/**
* @var bool
*/
private $cacheTokens;
/**
* @var array
*/
private $codeUnitsByLine = [];
public function __construct(string $name, AbstractNode $parent, array $coverageData, array $testData, bool $cacheTokens)
public function __construct(string $name, AbstractNode $parent, array $lineCoverageData, array $functionCoverageData, array $testData, array $classes, array $traits, array $functions, LinesOfCode $linesOfCode)
{
parent::__construct($name, $parent);
$this->coverageData = $coverageData;
$this->testData = $testData;
$this->cacheTokens = $cacheTokens;
$this->lineCoverageData = $lineCoverageData;
$this->functionCoverageData = $functionCoverageData;
$this->testData = $testData;
$this->linesOfCode = $linesOfCode;
$this->calculateStatistics();
$this->calculateStatistics($classes, $traits, $functions);
}
/**
* Returns the number of files in/under this node.
*/
public function count(): int
{
return 1;
}
/**
* Returns the code coverage data of this node.
*/
public function getCoverageData(): array
public function lineCoverageData(): array
{
return $this->coverageData;
return $this->lineCoverageData;
}
/**
* Returns the test data of this node.
*/
public function getTestData(): array
public function functionCoverageData(): array
{
return $this->functionCoverageData;
}
public function testData(): array
{
return $this->testData;
}
/**
* Returns the classes of this node.
*/
public function getClasses(): array
public function classes(): array
{
return $this->classes;
}
/**
* Returns the traits of this node.
*/
public function getTraits(): array
public function traits(): array
{
return $this->traits;
}
/**
* Returns the functions of this node.
*/
public function getFunctions(): array
public function functions(): array
{
return $this->functions;
}
/**
* Returns the LOC/CLOC/NCLOC of this node.
*/
public function getLinesOfCode(): array
public function linesOfCode(): LinesOfCode
{
return $this->linesOfCode;
}
/**
* Returns the number of executable lines.
*/
public function getNumExecutableLines(): int
public function numberOfExecutableLines(): int
{
return $this->numExecutableLines;
}
/**
* Returns the number of executed lines.
*/
public function getNumExecutedLines(): int
public function numberOfExecutedLines(): int
{
return $this->numExecutedLines;
}
/**
* Returns the number of classes.
*/
public function getNumClasses(): int
public function numberOfExecutableBranches(): int
{
return $this->numExecutableBranches;
}
public function numberOfExecutedBranches(): int
{
return $this->numExecutedBranches;
}
public function numberOfExecutablePaths(): int
{
return $this->numExecutablePaths;
}
public function numberOfExecutedPaths(): int
{
return $this->numExecutedPaths;
}
public function numberOfClasses(): int
{
if ($this->numClasses === null) {
$this->numClasses = 0;
@@ -204,18 +226,12 @@ final class File extends AbstractNode
return $this->numClasses;
}
/**
* Returns the number of tested classes.
*/
public function getNumTestedClasses(): int
public function numberOfTestedClasses(): int
{
return $this->numTestedClasses;
}
/**
* Returns the number of traits.
*/
public function getNumTraits(): int
public function numberOfTraits(): int
{
if ($this->numTraits === null) {
$this->numTraits = 0;
@@ -234,18 +250,12 @@ final class File extends AbstractNode
return $this->numTraits;
}
/**
* Returns the number of tested traits.
*/
public function getNumTestedTraits(): int
public function numberOfTestedTraits(): int
{
return $this->numTestedTraits;
}
/**
* Returns the number of methods.
*/
public function getNumMethods(): int
public function numberOfMethods(): int
{
if ($this->numMethods === null) {
$this->numMethods = 0;
@@ -270,10 +280,7 @@ final class File extends AbstractNode
return $this->numMethods;
}
/**
* Returns the number of tested methods.
*/
public function getNumTestedMethods(): int
public function numberOfTestedMethods(): int
{
if ($this->numTestedMethods === null) {
$this->numTestedMethods = 0;
@@ -300,18 +307,12 @@ final class File extends AbstractNode
return $this->numTestedMethods;
}
/**
* Returns the number of functions.
*/
public function getNumFunctions(): int
public function numberOfFunctions(): int
{
return \count($this->functions);
return count($this->functions);
}
/**
* Returns the number of tested functions.
*/
public function getNumTestedFunctions(): int
public function numberOfTestedFunctions(): int
{
if ($this->numTestedFunctions === null) {
$this->numTestedFunctions = 0;
@@ -327,32 +328,18 @@ final class File extends AbstractNode
return $this->numTestedFunctions;
}
private function calculateStatistics(): void
private function calculateStatistics(array $classes, array $traits, array $functions): void
{
if ($this->cacheTokens) {
$tokens = \PHP_Token_Stream_CachingFactory::get($this->getPath());
} else {
$tokens = new \PHP_Token_Stream($this->getPath());
}
$this->linesOfCode = $tokens->getLinesOfCode();
foreach (\range(1, $this->linesOfCode['loc']) as $lineNumber) {
foreach (range(1, $this->linesOfCode->linesOfCode()) as $lineNumber) {
$this->codeUnitsByLine[$lineNumber] = [];
}
try {
$this->processClasses($tokens);
$this->processTraits($tokens);
$this->processFunctions($tokens);
} catch (\OutOfBoundsException $e) {
// This can happen with PHP_Token_Stream if the file is syntactically invalid,
// and probably affects a file that wasn't executed.
}
unset($tokens);
$this->processClasses($classes);
$this->processTraits($traits);
$this->processFunctions($functions);
foreach (\range(1, $this->linesOfCode['loc']) as $lineNumber) {
if (isset($this->coverageData[$lineNumber])) {
foreach (range(1, $this->linesOfCode->linesOfCode()) as $lineNumber) {
if (isset($this->lineCoverageData[$lineNumber])) {
foreach ($this->codeUnitsByLine[$lineNumber] as &$codeUnit) {
$codeUnit['executableLines']++;
}
@@ -361,7 +348,7 @@ final class File extends AbstractNode
$this->numExecutableLines++;
if (\count($this->coverageData[$lineNumber]) > 0) {
if (count($this->lineCoverageData[$lineNumber]) > 0) {
foreach ($this->codeUnitsByLine[$lineNumber] as &$codeUnit) {
$codeUnit['executedLines']++;
}
@@ -375,134 +362,111 @@ final class File extends AbstractNode
foreach ($this->traits as &$trait) {
foreach ($trait['methods'] as &$method) {
if ($method['executableLines'] > 0) {
$method['coverage'] = ($method['executedLines'] /
$method['executableLines']) * 100;
} else {
$method['coverage'] = 100;
}
$methodLineCoverage = $method['executableLines'] ? ($method['executedLines'] / $method['executableLines']) * 100 : 100;
$methodBranchCoverage = $method['executableBranches'] ? ($method['executedBranches'] / $method['executableBranches']) * 100 : 0;
$methodPathCoverage = $method['executablePaths'] ? ($method['executedPaths'] / $method['executablePaths']) * 100 : 0;
$method['crap'] = $this->crap(
$method['ccn'],
$method['coverage']
);
$method['coverage'] = $methodBranchCoverage ?: $methodLineCoverage;
$method['crap'] = (new CrapIndex($method['ccn'], $methodPathCoverage ?: $methodLineCoverage))->asString();
$trait['ccn'] += $method['ccn'];
}
unset($method);
if ($trait['executableLines'] > 0) {
$trait['coverage'] = ($trait['executedLines'] /
$trait['executableLines']) * 100;
$traitLineCoverage = $trait['executableLines'] ? ($trait['executedLines'] / $trait['executableLines']) * 100 : 100;
$traitBranchCoverage = $trait['executableBranches'] ? ($trait['executedBranches'] / $trait['executableBranches']) * 100 : 0;
$traitPathCoverage = $trait['executablePaths'] ? ($trait['executedPaths'] / $trait['executablePaths']) * 100 : 0;
if ($trait['coverage'] === 100) {
$this->numTestedClasses++;
}
} else {
$trait['coverage'] = 100;
$trait['coverage'] = $traitBranchCoverage ?: $traitLineCoverage;
$trait['crap'] = (new CrapIndex($trait['ccn'], $traitPathCoverage ?: $traitLineCoverage))->asString();
if ($trait['executableLines'] > 0 && $trait['coverage'] === 100) {
$this->numTestedClasses++;
}
$trait['crap'] = $this->crap(
$trait['ccn'],
$trait['coverage']
);
}
unset($trait);
foreach ($this->classes as &$class) {
foreach ($class['methods'] as &$method) {
if ($method['executableLines'] > 0) {
$method['coverage'] = ($method['executedLines'] /
$method['executableLines']) * 100;
} else {
$method['coverage'] = 100;
}
$methodLineCoverage = $method['executableLines'] ? ($method['executedLines'] / $method['executableLines']) * 100 : 100;
$methodBranchCoverage = $method['executableBranches'] ? ($method['executedBranches'] / $method['executableBranches']) * 100 : 0;
$methodPathCoverage = $method['executablePaths'] ? ($method['executedPaths'] / $method['executablePaths']) * 100 : 0;
$method['crap'] = $this->crap(
$method['ccn'],
$method['coverage']
);
$method['coverage'] = $methodBranchCoverage ?: $methodLineCoverage;
$method['crap'] = (new CrapIndex($method['ccn'], $methodPathCoverage ?: $methodLineCoverage))->asString();
$class['ccn'] += $method['ccn'];
}
unset($method);
if ($class['executableLines'] > 0) {
$class['coverage'] = ($class['executedLines'] /
$class['executableLines']) * 100;
$classLineCoverage = $class['executableLines'] ? ($class['executedLines'] / $class['executableLines']) * 100 : 100;
$classBranchCoverage = $class['executableBranches'] ? ($class['executedBranches'] / $class['executableBranches']) * 100 : 0;
$classPathCoverage = $class['executablePaths'] ? ($class['executedPaths'] / $class['executablePaths']) * 100 : 0;
if ($class['coverage'] === 100) {
$this->numTestedClasses++;
}
} else {
$class['coverage'] = 100;
$class['coverage'] = $classBranchCoverage ?: $classLineCoverage;
$class['crap'] = (new CrapIndex($class['ccn'], $classPathCoverage ?: $classLineCoverage))->asString();
if ($class['executableLines'] > 0 && $class['coverage'] === 100) {
$this->numTestedClasses++;
}
$class['crap'] = $this->crap(
$class['ccn'],
$class['coverage']
);
}
unset($class);
foreach ($this->functions as &$function) {
if ($function['executableLines'] > 0) {
$function['coverage'] = ($function['executedLines'] /
$function['executableLines']) * 100;
} else {
$function['coverage'] = 100;
}
$functionLineCoverage = $function['executableLines'] ? ($function['executedLines'] / $function['executableLines']) * 100 : 100;
$functionBranchCoverage = $function['executableBranches'] ? ($function['executedBranches'] / $function['executableBranches']) * 100 : 0;
$functionPathCoverage = $function['executablePaths'] ? ($function['executedPaths'] / $function['executablePaths']) * 100 : 0;
$function['coverage'] = $functionBranchCoverage ?: $functionLineCoverage;
$function['crap'] = (new CrapIndex($function['ccn'], $functionPathCoverage ?: $functionLineCoverage))->asString();
if ($function['coverage'] === 100) {
$this->numTestedFunctions++;
}
$function['crap'] = $this->crap(
$function['ccn'],
$function['coverage']
);
}
}
private function processClasses(\PHP_Token_Stream $tokens): void
private function processClasses(array $classes): void
{
$classes = $tokens->getClasses();
$link = $this->getId() . '.html#';
$link = $this->id() . '.html#';
foreach ($classes as $className => $class) {
if (\strpos($className, 'anonymous') === 0) {
continue;
}
if (!empty($class['package']['namespace'])) {
$className = $class['package']['namespace'] . '\\' . $className;
}
$this->classes[$className] = [
'className' => $className,
'methods' => [],
'startLine' => $class['startLine'],
'executableLines' => 0,
'executedLines' => 0,
'ccn' => 0,
'coverage' => 0,
'crap' => 0,
'package' => $class['package'],
'link' => $link . $class['startLine'],
'className' => $className,
'namespace' => $class['namespace'],
'methods' => [],
'startLine' => $class['startLine'],
'executableLines' => 0,
'executedLines' => 0,
'executableBranches' => 0,
'executedBranches' => 0,
'executablePaths' => 0,
'executedPaths' => 0,
'ccn' => 0,
'coverage' => 0,
'crap' => 0,
'link' => $link . $class['startLine'],
];
foreach ($class['methods'] as $methodName => $method) {
if (\strpos($methodName, 'anonymous') === 0) {
continue;
}
$methodData = $this->newMethod($className, $methodName, $method, $link);
$this->classes[$className]['methods'][$methodName] = $methodData;
$this->classes[$className]['methods'][$methodName] = $this->newMethod($methodName, $method, $link);
$this->classes[$className]['executableBranches'] += $methodData['executableBranches'];
$this->classes[$className]['executedBranches'] += $methodData['executedBranches'];
$this->classes[$className]['executablePaths'] += $methodData['executablePaths'];
$this->classes[$className]['executedPaths'] += $methodData['executedPaths'];
foreach (\range($method['startLine'], $method['endLine']) as $lineNumber) {
$this->numExecutableBranches += $methodData['executableBranches'];
$this->numExecutedBranches += $methodData['executedBranches'];
$this->numExecutablePaths += $methodData['executablePaths'];
$this->numExecutedPaths += $methodData['executedPaths'];
foreach (range($method['startLine'], $method['endLine']) as $lineNumber) {
$this->codeUnitsByLine[$lineNumber] = [
&$this->classes[$className],
&$this->classes[$className]['methods'][$methodName],
@@ -512,33 +476,43 @@ final class File extends AbstractNode
}
}
private function processTraits(\PHP_Token_Stream $tokens): void
private function processTraits(array $traits): void
{
$traits = $tokens->getTraits();
$link = $this->getId() . '.html#';
$link = $this->id() . '.html#';
foreach ($traits as $traitName => $trait) {
$this->traits[$traitName] = [
'traitName' => $traitName,
'methods' => [],
'startLine' => $trait['startLine'],
'executableLines' => 0,
'executedLines' => 0,
'ccn' => 0,
'coverage' => 0,
'crap' => 0,
'package' => $trait['package'],
'link' => $link . $trait['startLine'],
'traitName' => $traitName,
'namespace' => $trait['namespace'],
'methods' => [],
'startLine' => $trait['startLine'],
'executableLines' => 0,
'executedLines' => 0,
'executableBranches' => 0,
'executedBranches' => 0,
'executablePaths' => 0,
'executedPaths' => 0,
'ccn' => 0,
'coverage' => 0,
'crap' => 0,
'link' => $link . $trait['startLine'],
];
foreach ($trait['methods'] as $methodName => $method) {
if (\strpos($methodName, 'anonymous') === 0) {
continue;
}
$methodData = $this->newMethod($traitName, $methodName, $method, $link);
$this->traits[$traitName]['methods'][$methodName] = $methodData;
$this->traits[$traitName]['methods'][$methodName] = $this->newMethod($methodName, $method, $link);
$this->traits[$traitName]['executableBranches'] += $methodData['executableBranches'];
$this->traits[$traitName]['executedBranches'] += $methodData['executedBranches'];
$this->traits[$traitName]['executablePaths'] += $methodData['executablePaths'];
$this->traits[$traitName]['executedPaths'] += $methodData['executedPaths'];
foreach (\range($method['startLine'], $method['endLine']) as $lineNumber) {
$this->numExecutableBranches += $methodData['executableBranches'];
$this->numExecutedBranches += $methodData['executedBranches'];
$this->numExecutablePaths += $methodData['executablePaths'];
$this->numExecutedPaths += $methodData['executedPaths'];
foreach (range($method['startLine'], $method['endLine']) as $lineNumber) {
$this->codeUnitsByLine[$lineNumber] = [
&$this->traits[$traitName],
&$this->traits[$traitName]['methods'][$methodName],
@@ -548,64 +522,122 @@ final class File extends AbstractNode
}
}
private function processFunctions(\PHP_Token_Stream $tokens): void
private function processFunctions(array $functions): void
{
$functions = $tokens->getFunctions();
$link = $this->getId() . '.html#';
$link = $this->id() . '.html#';
foreach ($functions as $functionName => $function) {
if (\strpos($functionName, 'anonymous') === 0) {
continue;
}
$this->functions[$functionName] = [
'functionName' => $functionName,
'signature' => $function['signature'],
'startLine' => $function['startLine'],
'executableLines' => 0,
'executedLines' => 0,
'ccn' => $function['ccn'],
'coverage' => 0,
'crap' => 0,
'link' => $link . $function['startLine'],
'functionName' => $functionName,
'namespace' => $function['namespace'],
'signature' => $function['signature'],
'startLine' => $function['startLine'],
'endLine' => $function['endLine'],
'executableLines' => 0,
'executedLines' => 0,
'executableBranches' => 0,
'executedBranches' => 0,
'executablePaths' => 0,
'executedPaths' => 0,
'ccn' => $function['ccn'],
'coverage' => 0,
'crap' => 0,
'link' => $link . $function['startLine'],
];
foreach (\range($function['startLine'], $function['endLine']) as $lineNumber) {
foreach (range($function['startLine'], $function['endLine']) as $lineNumber) {
$this->codeUnitsByLine[$lineNumber] = [&$this->functions[$functionName]];
}
if (isset($this->functionCoverageData[$functionName]['branches'])) {
$this->functions[$functionName]['executableBranches'] = count(
$this->functionCoverageData[$functionName]['branches']
);
$this->functions[$functionName]['executedBranches'] = count(
array_filter(
$this->functionCoverageData[$functionName]['branches'],
static function (array $branch) {
return (bool) $branch['hit'];
}
)
);
}
if (isset($this->functionCoverageData[$functionName]['paths'])) {
$this->functions[$functionName]['executablePaths'] = count(
$this->functionCoverageData[$functionName]['paths']
);
$this->functions[$functionName]['executedPaths'] = count(
array_filter(
$this->functionCoverageData[$functionName]['paths'],
static function (array $path) {
return (bool) $path['hit'];
}
)
);
}
$this->numExecutableBranches += $this->functions[$functionName]['executableBranches'];
$this->numExecutedBranches += $this->functions[$functionName]['executedBranches'];
$this->numExecutablePaths += $this->functions[$functionName]['executablePaths'];
$this->numExecutedPaths += $this->functions[$functionName]['executedPaths'];
}
}
private function crap(int $ccn, float $coverage): string
private function newMethod(string $className, string $methodName, array $method, string $link): array
{
if ($coverage === 0.0) {
return (string) ($ccn ** 2 + $ccn);
}
if ($coverage >= 95) {
return (string) $ccn;
}
return \sprintf(
'%01.2F',
$ccn ** 2 * (1 - $coverage / 100) ** 3 + $ccn
);
}
private function newMethod(string $methodName, array $method, string $link): array
{
return [
'methodName' => $methodName,
'visibility' => $method['visibility'],
'signature' => $method['signature'],
'startLine' => $method['startLine'],
'endLine' => $method['endLine'],
'executableLines' => 0,
'executedLines' => 0,
'ccn' => $method['ccn'],
'coverage' => 0,
'crap' => 0,
'link' => $link . $method['startLine'],
$methodData = [
'methodName' => $methodName,
'visibility' => $method['visibility'],
'signature' => $method['signature'],
'startLine' => $method['startLine'],
'endLine' => $method['endLine'],
'executableLines' => 0,
'executedLines' => 0,
'executableBranches' => 0,
'executedBranches' => 0,
'executablePaths' => 0,
'executedPaths' => 0,
'ccn' => $method['ccn'],
'coverage' => 0,
'crap' => 0,
'link' => $link . $method['startLine'],
];
$key = $className . '->' . $methodName;
if (isset($this->functionCoverageData[$key]['branches'])) {
$methodData['executableBranches'] = count(
$this->functionCoverageData[$key]['branches']
);
$methodData['executedBranches'] = count(
array_filter(
$this->functionCoverageData[$key]['branches'],
static function (array $branch) {
return (bool) $branch['hit'];
}
)
);
}
if (isset($this->functionCoverageData[$key]['paths'])) {
$methodData['executablePaths'] = count(
$this->functionCoverageData[$key]['paths']
);
$methodData['executedPaths'] = count(
array_filter(
$this->functionCoverageData[$key]['paths'],
static function (array $path) {
return (bool) $path['hit'];
}
)
);
}
return $methodData;
}
}

View File

@@ -1,6 +1,6 @@
<?php declare(strict_types=1);
/*
* This file is part of the php-code-coverage package.
* This file is part of phpunit/php-code-coverage.
*
* (c) Sebastian Bergmann <sebastian@phpunit.de>
*
@@ -9,10 +9,13 @@
*/
namespace SebastianBergmann\CodeCoverage\Node;
use function count;
use RecursiveIterator;
/**
* Recursive iterator for node object graphs.
* @internal This class is not covered by the backward compatibility promise for phpunit/php-code-coverage
*/
final class Iterator implements \RecursiveIterator
final class Iterator implements RecursiveIterator
{
/**
* @var int
@@ -26,7 +29,7 @@ final class Iterator implements \RecursiveIterator
public function __construct(Directory $node)
{
$this->nodes = $node->getChildNodes();
$this->nodes = $node->children();
}
/**
@@ -42,7 +45,7 @@ final class Iterator implements \RecursiveIterator
*/
public function valid(): bool
{
return $this->position < \count($this->nodes);
return $this->position < count($this->nodes);
}
/**
@@ -56,7 +59,7 @@ final class Iterator implements \RecursiveIterator
/**
* Returns the current element.
*/
public function current(): AbstractNode
public function current(): ?AbstractNode
{
return $this->valid() ? $this->nodes[$this->position] : null;
}