Upgrade framework
This commit is contained in:
@@ -1,21 +1,25 @@
|
||||
<?php
|
||||
<?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>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
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\Util\Percentage;
|
||||
|
||||
/**
|
||||
* 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
|
||||
@@ -25,12 +29,12 @@ abstract class AbstractNode implements \Countable
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
private $path;
|
||||
private $pathAsString;
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
private $pathArray;
|
||||
private $pathAsArray;
|
||||
|
||||
/**
|
||||
* @var AbstractNode
|
||||
@@ -42,15 +46,9 @@ abstract class AbstractNode implements \Countable
|
||||
*/
|
||||
private $id;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param string $name
|
||||
* @param AbstractNode $parent
|
||||
*/
|
||||
public function __construct($name, AbstractNode $parent = null)
|
||||
public function __construct(string $name, self $parent = null)
|
||||
{
|
||||
if (substr($name, -1) == '/') {
|
||||
if (substr($name, -1) === DIRECTORY_SEPARATOR) {
|
||||
$name = substr($name, 0, -1);
|
||||
}
|
||||
|
||||
@@ -58,28 +56,22 @@ abstract class AbstractNode implements \Countable
|
||||
$this->parent = $parent;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getName()
|
||||
public function name(): string
|
||||
{
|
||||
return $this->name;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getId()
|
||||
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') {
|
||||
if ($parentId === 'index') {
|
||||
$this->id = str_replace(':', '_', $this->name);
|
||||
} else {
|
||||
$this->id = $parentId . '/' . $this->name;
|
||||
@@ -90,253 +82,172 @@ abstract class AbstractNode implements \Countable
|
||||
return $this->id;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getPath()
|
||||
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() . '/' . $this->name;
|
||||
}
|
||||
}
|
||||
|
||||
return $this->path;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
public function getPathAsArray()
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return AbstractNode
|
||||
*/
|
||||
public function getParent()
|
||||
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.
|
||||
*
|
||||
* @param bool $asString
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function getTestedClassesPercent($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.
|
||||
*
|
||||
* @param bool $asString
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function getTestedTraitsPercent($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 traits that has been tested.
|
||||
*
|
||||
* @param bool $asString
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function getTestedClassesAndTraitsPercent($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 methods that has been tested.
|
||||
*
|
||||
* @param bool $asString
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function getTestedMethodsPercent($asString = true)
|
||||
public function percentageOfTestedFunctions(): Percentage
|
||||
{
|
||||
return Util::percent(
|
||||
$this->getNumTestedMethods(),
|
||||
$this->getNumMethods(),
|
||||
$asString
|
||||
return Percentage::fromFractionAndTotal(
|
||||
$this->numberOfTestedFunctions(),
|
||||
$this->numberOfFunctions(),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the percentage of executed lines.
|
||||
*
|
||||
* @param bool $asString
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function getLineExecutedPercent($asString = true)
|
||||
public function percentageOfTestedMethods(): Percentage
|
||||
{
|
||||
return Util::percent(
|
||||
$this->getNumExecutedLines(),
|
||||
$this->getNumExecutableLines(),
|
||||
$asString
|
||||
return Percentage::fromFractionAndTotal(
|
||||
$this->numberOfTestedMethods(),
|
||||
$this->numberOfMethods(),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the number of classes and traits.
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function getNumClassesAndTraits()
|
||||
public function percentageOfTestedFunctionsAndMethods(): Percentage
|
||||
{
|
||||
return $this->getNumClasses() + $this->getNumTraits();
|
||||
return Percentage::fromFractionAndTotal(
|
||||
$this->numberOfTestedFunctionsAndMethods(),
|
||||
$this->numberOfFunctionsAndMethods(),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the number of tested classes and traits.
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function getNumTestedClassesAndTraits()
|
||||
public function percentageOfExecutedLines(): Percentage
|
||||
{
|
||||
return $this->getNumTestedClasses() + $this->getNumTestedTraits();
|
||||
return Percentage::fromFractionAndTotal(
|
||||
$this->numberOfExecutedLines(),
|
||||
$this->numberOfExecutableLines(),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the classes and traits of this node.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getClassesAndTraits()
|
||||
public function percentageOfExecutedBranches(): Percentage
|
||||
{
|
||||
return array_merge($this->getClasses(), $this->getTraits());
|
||||
return Percentage::fromFractionAndTotal(
|
||||
$this->numberOfExecutedBranches(),
|
||||
$this->numberOfExecutableBranches()
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the classes of this node.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
abstract public function getClasses();
|
||||
public function percentageOfExecutedPaths(): Percentage
|
||||
{
|
||||
return Percentage::fromFractionAndTotal(
|
||||
$this->numberOfExecutedPaths(),
|
||||
$this->numberOfExecutablePaths()
|
||||
);
|
||||
}
|
||||
|
||||
public function numberOfClassesAndTraits(): int
|
||||
{
|
||||
return $this->numberOfClasses() + $this->numberOfTraits();
|
||||
}
|
||||
|
||||
public function numberOfTestedClassesAndTraits(): int
|
||||
{
|
||||
return $this->numberOfTestedClasses() + $this->numberOfTestedTraits();
|
||||
}
|
||||
|
||||
public function classesAndTraits(): array
|
||||
{
|
||||
return array_merge($this->classes(), $this->traits());
|
||||
}
|
||||
|
||||
public function numberOfFunctionsAndMethods(): int
|
||||
{
|
||||
return $this->numberOfFunctions() + $this->numberOfMethods();
|
||||
}
|
||||
|
||||
public function numberOfTestedFunctionsAndMethods(): int
|
||||
{
|
||||
return $this->numberOfTestedFunctions() + $this->numberOfTestedMethods();
|
||||
}
|
||||
|
||||
abstract public function classes(): array;
|
||||
|
||||
abstract public function traits(): array;
|
||||
|
||||
abstract public function functions(): array;
|
||||
|
||||
/**
|
||||
* Returns the traits of this node.
|
||||
*
|
||||
* @return array
|
||||
* @psalm-return array{linesOfCode: int, commentLinesOfCode: int, nonCommentLinesOfCode: int}
|
||||
*/
|
||||
abstract public function getTraits();
|
||||
abstract public function linesOfCode(): array;
|
||||
|
||||
/**
|
||||
* Returns the functions of this node.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
abstract public function getFunctions();
|
||||
abstract public function numberOfExecutableLines(): int;
|
||||
|
||||
/**
|
||||
* Returns the LOC/CLOC/NCLOC of this node.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
abstract public function getLinesOfCode();
|
||||
abstract public function numberOfExecutedLines(): int;
|
||||
|
||||
/**
|
||||
* Returns the number of executable lines.
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
abstract public function getNumExecutableLines();
|
||||
abstract public function numberOfExecutableBranches(): int;
|
||||
|
||||
/**
|
||||
* Returns the number of executed lines.
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
abstract public function getNumExecutedLines();
|
||||
abstract public function numberOfExecutedBranches(): int;
|
||||
|
||||
/**
|
||||
* Returns the number of classes.
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
abstract public function getNumClasses();
|
||||
abstract public function numberOfExecutablePaths(): int;
|
||||
|
||||
/**
|
||||
* Returns the number of tested classes.
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
abstract public function getNumTestedClasses();
|
||||
abstract public function numberOfExecutedPaths(): int;
|
||||
|
||||
/**
|
||||
* Returns the number of traits.
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
abstract public function getNumTraits();
|
||||
abstract public function numberOfClasses(): int;
|
||||
|
||||
/**
|
||||
* Returns the number of tested traits.
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
abstract public function getNumTestedTraits();
|
||||
abstract public function numberOfTestedClasses(): int;
|
||||
|
||||
/**
|
||||
* Returns the number of methods.
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
abstract public function getNumMethods();
|
||||
abstract public function numberOfTraits(): int;
|
||||
|
||||
/**
|
||||
* Returns the number of tested methods.
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
abstract public function getNumTestedMethods();
|
||||
abstract public function numberOfTestedTraits(): int;
|
||||
|
||||
/**
|
||||
* Returns the number of functions.
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
abstract public function getNumFunctions();
|
||||
abstract public function numberOfMethods(): int;
|
||||
|
||||
/**
|
||||
* Returns the number of tested functions.
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
abstract public function getNumTestedFunctions();
|
||||
abstract public function numberOfTestedMethods(): int;
|
||||
|
||||
abstract public function numberOfFunctions(): int;
|
||||
|
||||
abstract public function numberOfTestedFunctions(): int;
|
||||
}
|
||||
|
||||
@@ -1,28 +1,48 @@
|
||||
<?php
|
||||
<?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>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
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\FileAnalyser;
|
||||
|
||||
class Builder
|
||||
/**
|
||||
* @internal This class is not covered by the backward compatibility promise for phpunit/php-code-coverage
|
||||
*/
|
||||
final class Builder
|
||||
{
|
||||
/**
|
||||
* @param CodeCoverage $coverage
|
||||
*
|
||||
* @return Directory
|
||||
* @var FileAnalyser
|
||||
*/
|
||||
public function build(CodeCoverage $coverage)
|
||||
private $analyser;
|
||||
|
||||
public function __construct(FileAnalyser $analyser)
|
||||
{
|
||||
$files = $coverage->getData();
|
||||
$commonPath = $this->reducePaths($files);
|
||||
$this->analyser = $analyser;
|
||||
}
|
||||
|
||||
public function build(CodeCoverage $coverage): Directory
|
||||
{
|
||||
$data = clone $coverage->getData(); // clone because path munging is destructive to the original data
|
||||
$commonPath = $this->reducePaths($data);
|
||||
$root = new Directory(
|
||||
$commonPath,
|
||||
null
|
||||
@@ -30,32 +50,41 @@ class Builder
|
||||
|
||||
$this->addItems(
|
||||
$root,
|
||||
$this->buildDirectoryStructure($files),
|
||||
$coverage->getTests(),
|
||||
$coverage->getCacheTokens()
|
||||
$this->buildDirectoryStructure($data),
|
||||
$coverage->getTests()
|
||||
);
|
||||
|
||||
return $root;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Directory $root
|
||||
* @param array $items
|
||||
* @param array $tests
|
||||
* @param bool $cacheTokens
|
||||
*/
|
||||
private function addItems(Directory $root, array $items, array $tests, $cacheTokens)
|
||||
private function addItems(Directory $root, array $items, array $tests): void
|
||||
{
|
||||
foreach ($items as $key => $value) {
|
||||
if (substr($key, -2) == '/f') {
|
||||
$key = substr($key, 0, -2);
|
||||
$key = (string) $key;
|
||||
|
||||
if (file_exists($root->getPath() . DIRECTORY_SEPARATOR . $key)) {
|
||||
$root->addFile($key, $value, $tests, $cacheTokens);
|
||||
if (substr($key, -2) === '/f') {
|
||||
$key = substr($key, 0, -2);
|
||||
$filename = $root->pathAsString() . DIRECTORY_SEPARATOR . $key;
|
||||
|
||||
if (is_file($filename)) {
|
||||
$root->addFile(
|
||||
new File(
|
||||
$key,
|
||||
$root,
|
||||
$value['lineCoverage'],
|
||||
$value['functionCoverage'],
|
||||
$tests,
|
||||
$this->analyser->classesIn($filename),
|
||||
$this->analyser->traitsIn($filename),
|
||||
$this->analyser->functionsIn($filename),
|
||||
$this->analyser->linesOfCodeFor($filename)
|
||||
)
|
||||
);
|
||||
}
|
||||
} else {
|
||||
$child = $root->addDirectory($key);
|
||||
$this->addItems($child, $value, $tests, $cacheTokens);
|
||||
|
||||
$this->addItems($child, $value, $tests);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -99,31 +128,30 @@ class Builder
|
||||
* )
|
||||
* )
|
||||
* </code>
|
||||
*
|
||||
* @param array $files
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
private function buildDirectoryStructure($files)
|
||||
private function buildDirectoryStructure(ProcessedCodeCoverageData $data): array
|
||||
{
|
||||
$result = [];
|
||||
|
||||
foreach ($files as $path => $file) {
|
||||
$path = explode('/', $path);
|
||||
foreach ($data->coveredFiles() as $originalPath) {
|
||||
$path = explode(DIRECTORY_SEPARATOR, $originalPath);
|
||||
$pointer = &$result;
|
||||
$max = count($path);
|
||||
|
||||
for ($i = 0; $i < $max; $i++) {
|
||||
if ($i == ($max - 1)) {
|
||||
$type = '';
|
||||
|
||||
if ($i === ($max - 1)) {
|
||||
$type = '/f';
|
||||
} else {
|
||||
$type = '';
|
||||
}
|
||||
|
||||
$pointer = &$pointer[$path[$i] . $type];
|
||||
}
|
||||
|
||||
$pointer = $file;
|
||||
$pointer = [
|
||||
'lineCoverage' => $data->lineCoverage()[$originalPath] ?? [],
|
||||
'functionCoverage' => $data->functionCoverage()[$originalPath] ?? [],
|
||||
];
|
||||
}
|
||||
|
||||
return $result;
|
||||
@@ -165,25 +193,19 @@ class Builder
|
||||
* )
|
||||
* )
|
||||
* </code>
|
||||
*
|
||||
* @param array $files
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
private function reducePaths(&$files)
|
||||
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]) . '/';
|
||||
$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;
|
||||
}
|
||||
@@ -194,7 +216,7 @@ class Builder
|
||||
// strip phar:// prefixes
|
||||
if (strpos($paths[$i], 'phar://') === 0) {
|
||||
$paths[$i] = substr($paths[$i], 7);
|
||||
$paths[$i] = strtr($paths[$i], '/', DIRECTORY_SEPARATOR);
|
||||
$paths[$i] = str_replace('/', DIRECTORY_SEPARATOR, $paths[$i]);
|
||||
}
|
||||
$paths[$i] = explode(DIRECTORY_SEPARATOR, $paths[$i]);
|
||||
|
||||
@@ -209,9 +231,10 @@ class Builder
|
||||
while (!$done) {
|
||||
for ($i = 0; $i < $max - 1; $i++) {
|
||||
if (!isset($paths[$i][0]) ||
|
||||
!isset($paths[$i+1][0]) ||
|
||||
$paths[$i][0] != $paths[$i+1][0]) {
|
||||
!isset($paths[$i + 1][0]) ||
|
||||
$paths[$i][0] !== $paths[$i + 1][0]) {
|
||||
$done = true;
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -219,7 +242,7 @@ class Builder
|
||||
if (!$done) {
|
||||
$commonPath .= $paths[0][0];
|
||||
|
||||
if ($paths[0][0] != DIRECTORY_SEPARATOR) {
|
||||
if ($paths[0][0] !== DIRECTORY_SEPARATOR) {
|
||||
$commonPath .= DIRECTORY_SEPARATOR;
|
||||
}
|
||||
|
||||
@@ -229,16 +252,13 @@ class Builder
|
||||
}
|
||||
}
|
||||
|
||||
$original = array_keys($files);
|
||||
$original = $coverage->coveredFiles();
|
||||
$max = count($original);
|
||||
|
||||
for ($i = 0; $i < $max; $i++) {
|
||||
$files[implode('/', $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);
|
||||
}
|
||||
}
|
||||
|
||||
50
vendor/phpunit/php-code-coverage/src/Node/CrapIndex.php
vendored
Normal file
50
vendor/phpunit/php-code-coverage/src/Node/CrapIndex.php
vendored
Normal file
@@ -0,0 +1,50 @@
|
||||
<?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\Node;
|
||||
|
||||
use function sprintf;
|
||||
|
||||
/**
|
||||
* @internal This class is not covered by the backward compatibility promise for phpunit/php-code-coverage
|
||||
*/
|
||||
final class CrapIndex
|
||||
{
|
||||
/**
|
||||
* @var int
|
||||
*/
|
||||
private $cyclomaticComplexity;
|
||||
|
||||
/**
|
||||
* @var float
|
||||
*/
|
||||
private $codeCoverage;
|
||||
|
||||
public function __construct(int $cyclomaticComplexity, float $codeCoverage)
|
||||
{
|
||||
$this->cyclomaticComplexity = $cyclomaticComplexity;
|
||||
$this->codeCoverage = $codeCoverage;
|
||||
}
|
||||
|
||||
public function asString(): string
|
||||
{
|
||||
if ($this->codeCoverage === 0.0) {
|
||||
return (string) ($this->cyclomaticComplexity ** 2 + $this->cyclomaticComplexity);
|
||||
}
|
||||
|
||||
if ($this->codeCoverage >= 95) {
|
||||
return (string) $this->cyclomaticComplexity;
|
||||
}
|
||||
|
||||
return sprintf(
|
||||
'%01.2F',
|
||||
$this->cyclomaticComplexity ** 2 * (1 - $this->codeCoverage / 100) ** 3 + $this->cyclomaticComplexity
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -1,21 +1,23 @@
|
||||
<?php
|
||||
<?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>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace SebastianBergmann\CodeCoverage\Node;
|
||||
|
||||
use SebastianBergmann\CodeCoverage\InvalidArgumentException;
|
||||
use function array_merge;
|
||||
use function count;
|
||||
use IteratorAggregate;
|
||||
use RecursiveIteratorIterator;
|
||||
|
||||
/**
|
||||
* 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
|
||||
*/
|
||||
class Directory extends AbstractNode implements \IteratorAggregate
|
||||
final class Directory extends AbstractNode implements IteratorAggregate
|
||||
{
|
||||
/**
|
||||
* @var AbstractNode[]
|
||||
@@ -48,9 +50,9 @@ class Directory extends AbstractNode implements \IteratorAggregate
|
||||
private $functions;
|
||||
|
||||
/**
|
||||
* @var array
|
||||
* @psalm-var null|array{linesOfCode: int, commentLinesOfCode: int, nonCommentLinesOfCode: int}
|
||||
*/
|
||||
private $linesOfCode = null;
|
||||
private $linesOfCode;
|
||||
|
||||
/**
|
||||
* @var int
|
||||
@@ -67,6 +69,26 @@ 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
|
||||
*/
|
||||
@@ -107,14 +129,9 @@ class Directory extends AbstractNode implements \IteratorAggregate
|
||||
*/
|
||||
private $numTestedFunctions = -1;
|
||||
|
||||
/**
|
||||
* Returns the number of files in/under this node.
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function count()
|
||||
public function count(): int
|
||||
{
|
||||
if ($this->numFiles == -1) {
|
||||
if ($this->numFiles === -1) {
|
||||
$this->numFiles = 0;
|
||||
|
||||
foreach ($this->children as $child) {
|
||||
@@ -125,27 +142,15 @@ class Directory extends AbstractNode implements \IteratorAggregate
|
||||
return $this->numFiles;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an iterator for this node.
|
||||
*
|
||||
* @return \RecursiveIteratorIterator
|
||||
*/
|
||||
public function getIterator()
|
||||
public function getIterator(): RecursiveIteratorIterator
|
||||
{
|
||||
return new \RecursiveIteratorIterator(
|
||||
return new RecursiveIteratorIterator(
|
||||
new Iterator($this),
|
||||
\RecursiveIteratorIterator::SELF_FIRST
|
||||
RecursiveIteratorIterator::SELF_FIRST
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a new directory.
|
||||
*
|
||||
* @param string $name
|
||||
*
|
||||
* @return Directory
|
||||
*/
|
||||
public function addDirectory($name)
|
||||
public function addDirectory(string $name): self
|
||||
{
|
||||
$directory = new self($name, $this);
|
||||
|
||||
@@ -155,73 +160,31 @@ class Directory extends AbstractNode implements \IteratorAggregate
|
||||
return $directory;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a new file.
|
||||
*
|
||||
* @param string $name
|
||||
* @param array $coverageData
|
||||
* @param array $testData
|
||||
* @param bool $cacheTokens
|
||||
*
|
||||
* @return File
|
||||
*
|
||||
* @throws InvalidArgumentException
|
||||
*/
|
||||
public function addFile($name, array $coverageData, array $testData, $cacheTokens)
|
||||
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->numExecutableLines = -1;
|
||||
$this->numExecutedLines = -1;
|
||||
|
||||
return $file;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the directories in this directory.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getDirectories()
|
||||
public function directories(): array
|
||||
{
|
||||
return $this->directories;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the files in this directory.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getFiles()
|
||||
public function files(): array
|
||||
{
|
||||
return $this->files;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the child nodes of this node.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getChildNodes()
|
||||
public function children(): array
|
||||
{
|
||||
return $this->children;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the classes of this node.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getClasses()
|
||||
public function classes(): array
|
||||
{
|
||||
if ($this->classes === null) {
|
||||
$this->classes = [];
|
||||
@@ -229,7 +192,7 @@ class Directory extends AbstractNode implements \IteratorAggregate
|
||||
foreach ($this->children as $child) {
|
||||
$this->classes = array_merge(
|
||||
$this->classes,
|
||||
$child->getClasses()
|
||||
$child->classes()
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -237,12 +200,7 @@ class Directory extends AbstractNode implements \IteratorAggregate
|
||||
return $this->classes;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the traits of this node.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getTraits()
|
||||
public function traits(): array
|
||||
{
|
||||
if ($this->traits === null) {
|
||||
$this->traits = [];
|
||||
@@ -250,7 +208,7 @@ class Directory extends AbstractNode implements \IteratorAggregate
|
||||
foreach ($this->children as $child) {
|
||||
$this->traits = array_merge(
|
||||
$this->traits,
|
||||
$child->getTraits()
|
||||
$child->traits()
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -258,12 +216,7 @@ class Directory extends AbstractNode implements \IteratorAggregate
|
||||
return $this->traits;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the functions of this node.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getFunctions()
|
||||
public function functions(): array
|
||||
{
|
||||
if ($this->functions === null) {
|
||||
$this->functions = [];
|
||||
@@ -271,7 +224,7 @@ class Directory extends AbstractNode implements \IteratorAggregate
|
||||
foreach ($this->children as $child) {
|
||||
$this->functions = array_merge(
|
||||
$this->functions,
|
||||
$child->getFunctions()
|
||||
$child->functions()
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -280,201 +233,205 @@ class Directory extends AbstractNode implements \IteratorAggregate
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the LOC/CLOC/NCLOC of this node.
|
||||
*
|
||||
* @return array
|
||||
* @psalm-return array{linesOfCode: int, commentLinesOfCode: int, nonCommentLinesOfCode: int}
|
||||
*/
|
||||
public function getLinesOfCode()
|
||||
public function linesOfCode(): array
|
||||
{
|
||||
if ($this->linesOfCode === null) {
|
||||
$this->linesOfCode = ['loc' => 0, 'cloc' => 0, 'ncloc' => 0];
|
||||
$this->linesOfCode = [
|
||||
'linesOfCode' => 0,
|
||||
'commentLinesOfCode' => 0,
|
||||
'nonCommentLinesOfCode' => 0,
|
||||
];
|
||||
|
||||
foreach ($this->children as $child) {
|
||||
$linesOfCode = $child->getLinesOfCode();
|
||||
$childLinesOfCode = $child->linesOfCode();
|
||||
|
||||
$this->linesOfCode['loc'] += $linesOfCode['loc'];
|
||||
$this->linesOfCode['cloc'] += $linesOfCode['cloc'];
|
||||
$this->linesOfCode['ncloc'] += $linesOfCode['ncloc'];
|
||||
$this->linesOfCode['linesOfCode'] += $childLinesOfCode['linesOfCode'];
|
||||
$this->linesOfCode['commentLinesOfCode'] += $childLinesOfCode['commentLinesOfCode'];
|
||||
$this->linesOfCode['nonCommentLinesOfCode'] += $childLinesOfCode['nonCommentLinesOfCode'];
|
||||
}
|
||||
}
|
||||
|
||||
return $this->linesOfCode;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the number of executable lines.
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function getNumExecutableLines()
|
||||
public function numberOfExecutableLines(): int
|
||||
{
|
||||
if ($this->numExecutableLines == -1) {
|
||||
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.
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function getNumExecutedLines()
|
||||
public function numberOfExecutedLines(): int
|
||||
{
|
||||
if ($this->numExecutedLines == -1) {
|
||||
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.
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function getNumClasses()
|
||||
public function numberOfExecutableBranches(): int
|
||||
{
|
||||
if ($this->numClasses == -1) {
|
||||
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.
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function getNumTestedClasses()
|
||||
public function numberOfTestedClasses(): int
|
||||
{
|
||||
if ($this->numTestedClasses == -1) {
|
||||
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.
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function getNumTraits()
|
||||
public function numberOfTraits(): int
|
||||
{
|
||||
if ($this->numTraits == -1) {
|
||||
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.
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function getNumTestedTraits()
|
||||
public function numberOfTestedTraits(): int
|
||||
{
|
||||
if ($this->numTestedTraits == -1) {
|
||||
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.
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function getNumMethods()
|
||||
public function numberOfMethods(): int
|
||||
{
|
||||
if ($this->numMethods == -1) {
|
||||
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.
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function getNumTestedMethods()
|
||||
public function numberOfTestedMethods(): int
|
||||
{
|
||||
if ($this->numTestedMethods == -1) {
|
||||
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.
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function getNumFunctions()
|
||||
public function numberOfFunctions(): int
|
||||
{
|
||||
if ($this->numFunctions == -1) {
|
||||
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.
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function getNumTestedFunctions()
|
||||
public function numberOfTestedFunctions(): int
|
||||
{
|
||||
if ($this->numTestedFunctions == -1) {
|
||||
if ($this->numTestedFunctions === -1) {
|
||||
$this->numTestedFunctions = 0;
|
||||
|
||||
foreach ($this->children as $child) {
|
||||
$this->numTestedFunctions += $child->getNumTestedFunctions();
|
||||
$this->numTestedFunctions += $child->numberOfTestedFunctions();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
739
vendor/phpunit/php-code-coverage/src/Node/File.php
vendored
739
vendor/phpunit/php-code-coverage/src/Node/File.php
vendored
@@ -1,26 +1,32 @@
|
||||
<?php
|
||||
<?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>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace SebastianBergmann\CodeCoverage\Node;
|
||||
|
||||
use SebastianBergmann\CodeCoverage\InvalidArgumentException;
|
||||
use function array_filter;
|
||||
use function count;
|
||||
use function range;
|
||||
|
||||
/**
|
||||
* 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
|
||||
*/
|
||||
class File extends AbstractNode
|
||||
final class File extends AbstractNode
|
||||
{
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
private $coverageData;
|
||||
private $lineCoverageData;
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
private $functionCoverageData;
|
||||
|
||||
/**
|
||||
* @var array
|
||||
@@ -37,6 +43,26 @@ 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
|
||||
*/
|
||||
@@ -53,14 +79,14 @@ class File extends AbstractNode
|
||||
private $functions = [];
|
||||
|
||||
/**
|
||||
* @var array
|
||||
* @psalm-var array{linesOfCode: int, commentLinesOfCode: int, nonCommentLinesOfCode: int}
|
||||
*/
|
||||
private $linesOfCode = [];
|
||||
private $linesOfCode;
|
||||
|
||||
/**
|
||||
* @var int
|
||||
*/
|
||||
private $numClasses = null;
|
||||
private $numClasses;
|
||||
|
||||
/**
|
||||
* @var int
|
||||
@@ -70,7 +96,7 @@ class File extends AbstractNode
|
||||
/**
|
||||
* @var int
|
||||
*/
|
||||
private $numTraits = null;
|
||||
private $numTraits;
|
||||
|
||||
/**
|
||||
* @var int
|
||||
@@ -80,158 +106,112 @@ class File extends AbstractNode
|
||||
/**
|
||||
* @var int
|
||||
*/
|
||||
private $numMethods = null;
|
||||
private $numMethods;
|
||||
|
||||
/**
|
||||
* @var int
|
||||
*/
|
||||
private $numTestedMethods = null;
|
||||
private $numTestedMethods;
|
||||
|
||||
/**
|
||||
* @var int
|
||||
*/
|
||||
private $numTestedFunctions = null;
|
||||
private $numTestedFunctions;
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
private $startLines = [];
|
||||
private $codeUnitsByLine = [];
|
||||
|
||||
/**
|
||||
* @var array
|
||||
* @psalm-param array{linesOfCode: int, commentLinesOfCode: int, nonCommentLinesOfCode: int} $linesOfCode
|
||||
*/
|
||||
private $endLines = [];
|
||||
|
||||
/**
|
||||
* @var bool
|
||||
*/
|
||||
private $cacheTokens;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param string $name
|
||||
* @param AbstractNode $parent
|
||||
* @param array $coverageData
|
||||
* @param array $testData
|
||||
* @param bool $cacheTokens
|
||||
*
|
||||
* @throws InvalidArgumentException
|
||||
*/
|
||||
public function __construct($name, AbstractNode $parent, array $coverageData, array $testData, $cacheTokens)
|
||||
public function __construct(string $name, AbstractNode $parent, array $lineCoverageData, array $functionCoverageData, array $testData, array $classes, array $traits, array $functions, array $linesOfCode)
|
||||
{
|
||||
if (!is_bool($cacheTokens)) {
|
||||
throw InvalidArgumentException::create(
|
||||
1,
|
||||
'boolean'
|
||||
);
|
||||
}
|
||||
|
||||
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.
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function count()
|
||||
public function count(): int
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the code coverage data of this node.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getCoverageData()
|
||||
public function lineCoverageData(): array
|
||||
{
|
||||
return $this->coverageData;
|
||||
return $this->lineCoverageData;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the test data of this node.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getTestData()
|
||||
public function functionCoverageData(): array
|
||||
{
|
||||
return $this->functionCoverageData;
|
||||
}
|
||||
|
||||
public function testData(): array
|
||||
{
|
||||
return $this->testData;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the classes of this node.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getClasses()
|
||||
public function classes(): array
|
||||
{
|
||||
return $this->classes;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the traits of this node.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getTraits()
|
||||
public function traits(): array
|
||||
{
|
||||
return $this->traits;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the functions of this node.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getFunctions()
|
||||
public function functions(): array
|
||||
{
|
||||
return $this->functions;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the LOC/CLOC/NCLOC of this node.
|
||||
*
|
||||
* @return array
|
||||
* @psalm-return array{linesOfCode: int, commentLinesOfCode: int, nonCommentLinesOfCode: int}
|
||||
*/
|
||||
public function getLinesOfCode()
|
||||
public function linesOfCode(): array
|
||||
{
|
||||
return $this->linesOfCode;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the number of executable lines.
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function getNumExecutableLines()
|
||||
public function numberOfExecutableLines(): int
|
||||
{
|
||||
return $this->numExecutableLines;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the number of executed lines.
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function getNumExecutedLines()
|
||||
public function numberOfExecutedLines(): int
|
||||
{
|
||||
return $this->numExecutedLines;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the number of classes.
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function getNumClasses()
|
||||
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;
|
||||
@@ -250,22 +230,12 @@ class File extends AbstractNode
|
||||
return $this->numClasses;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the number of tested classes.
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function getNumTestedClasses()
|
||||
public function numberOfTestedClasses(): int
|
||||
{
|
||||
return $this->numTestedClasses;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the number of traits.
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function getNumTraits()
|
||||
public function numberOfTraits(): int
|
||||
{
|
||||
if ($this->numTraits === null) {
|
||||
$this->numTraits = 0;
|
||||
@@ -284,22 +254,12 @@ class File extends AbstractNode
|
||||
return $this->numTraits;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the number of tested traits.
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function getNumTestedTraits()
|
||||
public function numberOfTestedTraits(): int
|
||||
{
|
||||
return $this->numTestedTraits;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the number of methods.
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function getNumMethods()
|
||||
public function numberOfMethods(): int
|
||||
{
|
||||
if ($this->numMethods === null) {
|
||||
$this->numMethods = 0;
|
||||
@@ -324,12 +284,7 @@ class File extends AbstractNode
|
||||
return $this->numMethods;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the number of tested methods.
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function getNumTestedMethods()
|
||||
public function numberOfTestedMethods(): int
|
||||
{
|
||||
if ($this->numTestedMethods === null) {
|
||||
$this->numTestedMethods = 0;
|
||||
@@ -337,7 +292,7 @@ class File extends AbstractNode
|
||||
foreach ($this->classes as $class) {
|
||||
foreach ($class['methods'] as $method) {
|
||||
if ($method['executableLines'] > 0 &&
|
||||
$method['coverage'] == 100) {
|
||||
$method['coverage'] === 100) {
|
||||
$this->numTestedMethods++;
|
||||
}
|
||||
}
|
||||
@@ -346,7 +301,7 @@ class File extends AbstractNode
|
||||
foreach ($this->traits as $trait) {
|
||||
foreach ($trait['methods'] as $method) {
|
||||
if ($method['executableLines'] > 0 &&
|
||||
$method['coverage'] == 100) {
|
||||
$method['coverage'] === 100) {
|
||||
$this->numTestedMethods++;
|
||||
}
|
||||
}
|
||||
@@ -356,29 +311,19 @@ class File extends AbstractNode
|
||||
return $this->numTestedMethods;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the number of functions.
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function getNumFunctions()
|
||||
public function numberOfFunctions(): int
|
||||
{
|
||||
return count($this->functions);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the number of tested functions.
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function getNumTestedFunctions()
|
||||
public function numberOfTestedFunctions(): int
|
||||
{
|
||||
if ($this->numTestedFunctions === null) {
|
||||
$this->numTestedFunctions = 0;
|
||||
|
||||
foreach ($this->functions as $function) {
|
||||
if ($function['executableLines'] > 0 &&
|
||||
$function['coverage'] == 100) {
|
||||
$function['coverage'] === 100) {
|
||||
$this->numTestedFunctions++;
|
||||
}
|
||||
}
|
||||
@@ -387,336 +332,320 @@ class File extends AbstractNode
|
||||
return $this->numTestedFunctions;
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculates coverage statistics for the file.
|
||||
*/
|
||||
protected function calculateStatistics()
|
||||
private function calculateStatistics(array $classes, array $traits, array $functions): void
|
||||
{
|
||||
$classStack = $functionStack = [];
|
||||
|
||||
if ($this->cacheTokens) {
|
||||
$tokens = \PHP_Token_Stream_CachingFactory::get($this->getPath());
|
||||
} else {
|
||||
$tokens = new \PHP_Token_Stream($this->getPath());
|
||||
foreach (range(1, $this->linesOfCode['linesOfCode']) as $lineNumber) {
|
||||
$this->codeUnitsByLine[$lineNumber] = [];
|
||||
}
|
||||
|
||||
$this->processClasses($tokens);
|
||||
$this->processTraits($tokens);
|
||||
$this->processFunctions($tokens);
|
||||
$this->linesOfCode = $tokens->getLinesOfCode();
|
||||
unset($tokens);
|
||||
$this->processClasses($classes);
|
||||
$this->processTraits($traits);
|
||||
$this->processFunctions($functions);
|
||||
|
||||
for ($lineNumber = 1; $lineNumber <= $this->linesOfCode['loc']; $lineNumber++) {
|
||||
if (isset($this->startLines[$lineNumber])) {
|
||||
// Start line of a class.
|
||||
if (isset($this->startLines[$lineNumber]['className'])) {
|
||||
if (isset($currentClass)) {
|
||||
$classStack[] = &$currentClass;
|
||||
}
|
||||
|
||||
$currentClass = &$this->startLines[$lineNumber];
|
||||
} // Start line of a trait.
|
||||
elseif (isset($this->startLines[$lineNumber]['traitName'])) {
|
||||
$currentTrait = &$this->startLines[$lineNumber];
|
||||
} // Start line of a method.
|
||||
elseif (isset($this->startLines[$lineNumber]['methodName'])) {
|
||||
$currentMethod = &$this->startLines[$lineNumber];
|
||||
} // Start line of a function.
|
||||
elseif (isset($this->startLines[$lineNumber]['functionName'])) {
|
||||
if (isset($currentFunction)) {
|
||||
$functionStack[] = &$currentFunction;
|
||||
}
|
||||
|
||||
$currentFunction = &$this->startLines[$lineNumber];
|
||||
}
|
||||
}
|
||||
|
||||
if (isset($this->coverageData[$lineNumber])) {
|
||||
if (isset($currentClass)) {
|
||||
$currentClass['executableLines']++;
|
||||
foreach (range(1, $this->linesOfCode['linesOfCode']) as $lineNumber) {
|
||||
if (isset($this->lineCoverageData[$lineNumber])) {
|
||||
foreach ($this->codeUnitsByLine[$lineNumber] as &$codeUnit) {
|
||||
$codeUnit['executableLines']++;
|
||||
}
|
||||
|
||||
if (isset($currentTrait)) {
|
||||
$currentTrait['executableLines']++;
|
||||
}
|
||||
|
||||
if (isset($currentMethod)) {
|
||||
$currentMethod['executableLines']++;
|
||||
}
|
||||
|
||||
if (isset($currentFunction)) {
|
||||
$currentFunction['executableLines']++;
|
||||
}
|
||||
unset($codeUnit);
|
||||
|
||||
$this->numExecutableLines++;
|
||||
|
||||
if (count($this->coverageData[$lineNumber]) > 0) {
|
||||
if (isset($currentClass)) {
|
||||
$currentClass['executedLines']++;
|
||||
if (count($this->lineCoverageData[$lineNumber]) > 0) {
|
||||
foreach ($this->codeUnitsByLine[$lineNumber] as &$codeUnit) {
|
||||
$codeUnit['executedLines']++;
|
||||
}
|
||||
|
||||
if (isset($currentTrait)) {
|
||||
$currentTrait['executedLines']++;
|
||||
}
|
||||
|
||||
if (isset($currentMethod)) {
|
||||
$currentMethod['executedLines']++;
|
||||
}
|
||||
|
||||
if (isset($currentFunction)) {
|
||||
$currentFunction['executedLines']++;
|
||||
}
|
||||
unset($codeUnit);
|
||||
|
||||
$this->numExecutedLines++;
|
||||
}
|
||||
}
|
||||
|
||||
if (isset($this->endLines[$lineNumber])) {
|
||||
// End line of a class.
|
||||
if (isset($this->endLines[$lineNumber]['className'])) {
|
||||
unset($currentClass);
|
||||
|
||||
if ($classStack) {
|
||||
end($classStack);
|
||||
$key = key($classStack);
|
||||
$currentClass = &$classStack[$key];
|
||||
unset($classStack[$key]);
|
||||
}
|
||||
} // End line of a trait.
|
||||
elseif (isset($this->endLines[$lineNumber]['traitName'])) {
|
||||
unset($currentTrait);
|
||||
} // End line of a method.
|
||||
elseif (isset($this->endLines[$lineNumber]['methodName'])) {
|
||||
unset($currentMethod);
|
||||
} // End line of a function.
|
||||
elseif (isset($this->endLines[$lineNumber]['functionName'])) {
|
||||
unset($currentFunction);
|
||||
|
||||
if ($functionStack) {
|
||||
end($functionStack);
|
||||
$key = key($functionStack);
|
||||
$currentFunction = &$functionStack[$key];
|
||||
unset($functionStack[$key]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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'];
|
||||
}
|
||||
|
||||
if ($trait['executableLines'] > 0) {
|
||||
$trait['coverage'] = ($trait['executedLines'] /
|
||||
$trait['executableLines']) * 100;
|
||||
unset($method);
|
||||
|
||||
if ($trait['coverage'] == 100) {
|
||||
$this->numTestedClasses++;
|
||||
}
|
||||
} else {
|
||||
$trait['coverage'] = 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;
|
||||
|
||||
$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'];
|
||||
}
|
||||
|
||||
if ($class['executableLines'] > 0) {
|
||||
$class['coverage'] = ($class['executedLines'] /
|
||||
$class['executableLines']) * 100;
|
||||
unset($method);
|
||||
|
||||
if ($class['coverage'] == 100) {
|
||||
$this->numTestedClasses++;
|
||||
}
|
||||
} else {
|
||||
$class['coverage'] = 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;
|
||||
|
||||
$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) {
|
||||
$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++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param \PHP_Token_Stream $tokens
|
||||
*/
|
||||
protected function processClasses(\PHP_Token_Stream $tokens)
|
||||
private function processClasses(array $classes): void
|
||||
{
|
||||
$classes = $tokens->getClasses();
|
||||
unset($tokens);
|
||||
|
||||
$link = $this->getId() . '.html#';
|
||||
$link = $this->id() . '.html#';
|
||||
|
||||
foreach ($classes as $className => $class) {
|
||||
$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'],
|
||||
];
|
||||
|
||||
$this->startLines[$class['startLine']] = &$this->classes[$className];
|
||||
$this->endLines[$class['endLine']] = &$this->classes[$className];
|
||||
|
||||
foreach ($class['methods'] as $methodName => $method) {
|
||||
$this->classes[$className]['methods'][$methodName] = $this->newMethod($methodName, $method, $link);
|
||||
$methodData = $this->newMethod($className, $methodName, $method, $link);
|
||||
$this->classes[$className]['methods'][$methodName] = $methodData;
|
||||
|
||||
$this->startLines[$method['startLine']] = &$this->classes[$className]['methods'][$methodName];
|
||||
$this->endLines[$method['endLine']] = &$this->classes[$className]['methods'][$methodName];
|
||||
$this->classes[$className]['executableBranches'] += $methodData['executableBranches'];
|
||||
$this->classes[$className]['executedBranches'] += $methodData['executedBranches'];
|
||||
$this->classes[$className]['executablePaths'] += $methodData['executablePaths'];
|
||||
$this->classes[$className]['executedPaths'] += $methodData['executedPaths'];
|
||||
|
||||
$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],
|
||||
];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param \PHP_Token_Stream $tokens
|
||||
*/
|
||||
protected function processTraits(\PHP_Token_Stream $tokens)
|
||||
private function processTraits(array $traits): void
|
||||
{
|
||||
$traits = $tokens->getTraits();
|
||||
unset($tokens);
|
||||
|
||||
$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'],
|
||||
];
|
||||
|
||||
$this->startLines[$trait['startLine']] = &$this->traits[$traitName];
|
||||
$this->endLines[$trait['endLine']] = &$this->traits[$traitName];
|
||||
|
||||
foreach ($trait['methods'] as $methodName => $method) {
|
||||
$this->traits[$traitName]['methods'][$methodName] = $this->newMethod($methodName, $method, $link);
|
||||
$methodData = $this->newMethod($traitName, $methodName, $method, $link);
|
||||
$this->traits[$traitName]['methods'][$methodName] = $methodData;
|
||||
|
||||
$this->startLines[$method['startLine']] = &$this->traits[$traitName]['methods'][$methodName];
|
||||
$this->endLines[$method['endLine']] = &$this->traits[$traitName]['methods'][$methodName];
|
||||
$this->traits[$traitName]['executableBranches'] += $methodData['executableBranches'];
|
||||
$this->traits[$traitName]['executedBranches'] += $methodData['executedBranches'];
|
||||
$this->traits[$traitName]['executablePaths'] += $methodData['executablePaths'];
|
||||
$this->traits[$traitName]['executedPaths'] += $methodData['executedPaths'];
|
||||
|
||||
$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],
|
||||
];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param \PHP_Token_Stream $tokens
|
||||
*/
|
||||
protected function processFunctions(\PHP_Token_Stream $tokens)
|
||||
private function processFunctions(array $functions): void
|
||||
{
|
||||
$functions = $tokens->getFunctions();
|
||||
unset($tokens);
|
||||
|
||||
$link = $this->getId() . '.html#';
|
||||
$link = $this->id() . '.html#';
|
||||
|
||||
foreach ($functions as $functionName => $function) {
|
||||
$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'],
|
||||
];
|
||||
|
||||
$this->startLines[$function['startLine']] = &$this->functions[$functionName];
|
||||
$this->endLines[$function['endLine']] = &$this->functions[$functionName];
|
||||
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'];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculates the Change Risk Anti-Patterns (CRAP) index for a unit of code
|
||||
* based on its cyclomatic complexity and percentage of code coverage.
|
||||
*
|
||||
* @param int $ccn
|
||||
* @param float $coverage
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function crap($ccn, $coverage)
|
||||
private function newMethod(string $className, string $methodName, array $method, string $link): array
|
||||
{
|
||||
if ($coverage == 0) {
|
||||
return (string) (pow($ccn, 2) + $ccn);
|
||||
}
|
||||
|
||||
if ($coverage >= 95) {
|
||||
return (string) $ccn;
|
||||
}
|
||||
|
||||
return sprintf(
|
||||
'%01.2F',
|
||||
pow($ccn, 2) * pow(1 - $coverage/100, 3) + $ccn
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $methodName
|
||||
* @param array $method
|
||||
* @param string $link
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
private function newMethod($methodName, array $method, $link)
|
||||
{
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,19 +1,21 @@
|
||||
<?php
|
||||
<?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>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
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
|
||||
*/
|
||||
class Iterator implements \RecursiveIterator
|
||||
final class Iterator implements RecursiveIterator
|
||||
{
|
||||
/**
|
||||
* @var int
|
||||
@@ -25,48 +27,39 @@ class Iterator implements \RecursiveIterator
|
||||
*/
|
||||
private $nodes;
|
||||
|
||||
/**
|
||||
* @param Directory $node
|
||||
*/
|
||||
public function __construct(Directory $node)
|
||||
{
|
||||
$this->nodes = $node->getChildNodes();
|
||||
$this->nodes = $node->children();
|
||||
}
|
||||
|
||||
/**
|
||||
* Rewinds the Iterator to the first element.
|
||||
*/
|
||||
public function rewind()
|
||||
public function rewind(): void
|
||||
{
|
||||
$this->position = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if there is a current element after calls to rewind() or next().
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function valid()
|
||||
public function valid(): bool
|
||||
{
|
||||
return $this->position < count($this->nodes);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the key of the current element.
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function key()
|
||||
public function key(): int
|
||||
{
|
||||
return $this->position;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the current element.
|
||||
*
|
||||
* @return \PHPUnit_Framework_Test
|
||||
*/
|
||||
public function current()
|
||||
public function current(): ?AbstractNode
|
||||
{
|
||||
return $this->valid() ? $this->nodes[$this->position] : null;
|
||||
}
|
||||
@@ -74,29 +67,23 @@ class Iterator implements \RecursiveIterator
|
||||
/**
|
||||
* Moves forward to next element.
|
||||
*/
|
||||
public function next()
|
||||
public function next(): void
|
||||
{
|
||||
$this->position++;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the sub iterator for the current element.
|
||||
*
|
||||
* @return Iterator
|
||||
*/
|
||||
public function getChildren()
|
||||
public function getChildren(): self
|
||||
{
|
||||
return new self(
|
||||
$this->nodes[$this->position]
|
||||
);
|
||||
return new self($this->nodes[$this->position]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether the current element has children.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function hasChildren()
|
||||
public function hasChildren(): bool
|
||||
{
|
||||
return $this->nodes[$this->position] instanceof Directory;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user