diff options
Diffstat (limited to 'vendor/phpunit/php-code-coverage/src/Node/File.php')
-rw-r--r-- | vendor/phpunit/php-code-coverage/src/Node/File.php | 651 |
1 files changed, 651 insertions, 0 deletions
diff --git a/vendor/phpunit/php-code-coverage/src/Node/File.php b/vendor/phpunit/php-code-coverage/src/Node/File.php new file mode 100644 index 000000000..af3764e41 --- /dev/null +++ b/vendor/phpunit/php-code-coverage/src/Node/File.php @@ -0,0 +1,651 @@ +<?php declare(strict_types=1); +/* + * This file is part of phpunit/php-code-coverage. + * + * (c) Sebastian Bergmann <[email protected]> + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace SebastianBergmann\CodeCoverage\Node; + +use function array_filter; +use function count; +use function range; + +/** + * @internal This class is not covered by the backward compatibility promise for phpunit/php-code-coverage + */ +final class File extends AbstractNode +{ + /** + * @var array + */ + private $lineCoverageData; + + /** + * @var array + */ + private $functionCoverageData; + + /** + * @var array + */ + private $testData; + + /** + * @var int + */ + private $numExecutableLines = 0; + + /** + * @var int + */ + 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 + */ + private $classes = []; + + /** + * @var array + */ + private $traits = []; + + /** + * @var array + */ + private $functions = []; + + /** + * @psalm-var array{linesOfCode: int, commentLinesOfCode: int, nonCommentLinesOfCode: int} + */ + private $linesOfCode; + + /** + * @var int + */ + private $numClasses; + + /** + * @var int + */ + private $numTestedClasses = 0; + + /** + * @var int + */ + private $numTraits; + + /** + * @var int + */ + private $numTestedTraits = 0; + + /** + * @var int + */ + private $numMethods; + + /** + * @var int + */ + private $numTestedMethods; + + /** + * @var int + */ + private $numTestedFunctions; + + /** + * @var array + */ + private $codeUnitsByLine = []; + + /** + * @psalm-param array{linesOfCode: int, commentLinesOfCode: int, nonCommentLinesOfCode: int} $linesOfCode + */ + public function __construct(string $name, AbstractNode $parent, array $lineCoverageData, array $functionCoverageData, array $testData, array $classes, array $traits, array $functions, array $linesOfCode) + { + parent::__construct($name, $parent); + + $this->lineCoverageData = $lineCoverageData; + $this->functionCoverageData = $functionCoverageData; + $this->testData = $testData; + $this->linesOfCode = $linesOfCode; + + $this->calculateStatistics($classes, $traits, $functions); + } + + public function count(): int + { + return 1; + } + + public function lineCoverageData(): array + { + return $this->lineCoverageData; + } + + public function functionCoverageData(): array + { + return $this->functionCoverageData; + } + + public function testData(): array + { + return $this->testData; + } + + public function classes(): array + { + return $this->classes; + } + + public function traits(): array + { + return $this->traits; + } + + public function functions(): array + { + return $this->functions; + } + + /** + * @psalm-return array{linesOfCode: int, commentLinesOfCode: int, nonCommentLinesOfCode: int} + */ + public function linesOfCode(): array + { + return $this->linesOfCode; + } + + public function numberOfExecutableLines(): int + { + return $this->numExecutableLines; + } + + public function numberOfExecutedLines(): int + { + return $this->numExecutedLines; + } + + 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; + + foreach ($this->classes as $class) { + foreach ($class['methods'] as $method) { + if ($method['executableLines'] > 0) { + $this->numClasses++; + + continue 2; + } + } + } + } + + return $this->numClasses; + } + + public function numberOfTestedClasses(): int + { + return $this->numTestedClasses; + } + + public function numberOfTraits(): int + { + if ($this->numTraits === null) { + $this->numTraits = 0; + + foreach ($this->traits as $trait) { + foreach ($trait['methods'] as $method) { + if ($method['executableLines'] > 0) { + $this->numTraits++; + + continue 2; + } + } + } + } + + return $this->numTraits; + } + + public function numberOfTestedTraits(): int + { + return $this->numTestedTraits; + } + + public function numberOfMethods(): int + { + if ($this->numMethods === null) { + $this->numMethods = 0; + + foreach ($this->classes as $class) { + foreach ($class['methods'] as $method) { + if ($method['executableLines'] > 0) { + $this->numMethods++; + } + } + } + + foreach ($this->traits as $trait) { + foreach ($trait['methods'] as $method) { + if ($method['executableLines'] > 0) { + $this->numMethods++; + } + } + } + } + + return $this->numMethods; + } + + public function numberOfTestedMethods(): int + { + if ($this->numTestedMethods === null) { + $this->numTestedMethods = 0; + + foreach ($this->classes as $class) { + foreach ($class['methods'] as $method) { + if ($method['executableLines'] > 0 && + $method['coverage'] === 100) { + $this->numTestedMethods++; + } + } + } + + foreach ($this->traits as $trait) { + foreach ($trait['methods'] as $method) { + if ($method['executableLines'] > 0 && + $method['coverage'] === 100) { + $this->numTestedMethods++; + } + } + } + } + + return $this->numTestedMethods; + } + + public function numberOfFunctions(): int + { + return count($this->functions); + } + + public function numberOfTestedFunctions(): int + { + if ($this->numTestedFunctions === null) { + $this->numTestedFunctions = 0; + + foreach ($this->functions as $function) { + if ($function['executableLines'] > 0 && + $function['coverage'] === 100) { + $this->numTestedFunctions++; + } + } + } + + return $this->numTestedFunctions; + } + + private function calculateStatistics(array $classes, array $traits, array $functions): void + { + foreach (range(1, $this->linesOfCode['linesOfCode']) as $lineNumber) { + $this->codeUnitsByLine[$lineNumber] = []; + } + + $this->processClasses($classes); + $this->processTraits($traits); + $this->processFunctions($functions); + + foreach (range(1, $this->linesOfCode['linesOfCode']) as $lineNumber) { + if (isset($this->lineCoverageData[$lineNumber])) { + foreach ($this->codeUnitsByLine[$lineNumber] as &$codeUnit) { + $codeUnit['executableLines']++; + } + + unset($codeUnit); + + $this->numExecutableLines++; + + if (count($this->lineCoverageData[$lineNumber]) > 0) { + foreach ($this->codeUnitsByLine[$lineNumber] as &$codeUnit) { + $codeUnit['executedLines']++; + } + + unset($codeUnit); + + $this->numExecutedLines++; + } + } + } + + foreach ($this->traits as &$trait) { + foreach ($trait['methods'] as &$method) { + $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['coverage'] = $methodBranchCoverage ?: $methodLineCoverage; + $method['crap'] = (new CrapIndex($method['ccn'], $methodPathCoverage ?: $methodLineCoverage))->asString(); + + $trait['ccn'] += $method['ccn']; + } + + unset($method); + + $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++; + } + } + + unset($trait); + + foreach ($this->classes as &$class) { + foreach ($class['methods'] as &$method) { + $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['coverage'] = $methodBranchCoverage ?: $methodLineCoverage; + $method['crap'] = (new CrapIndex($method['ccn'], $methodPathCoverage ?: $methodLineCoverage))->asString(); + + $class['ccn'] += $method['ccn']; + } + + unset($method); + + $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++; + } + } + + 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++; + } + } + } + + private function processClasses(array $classes): void + { + $link = $this->id() . '.html#'; + + foreach ($classes as $className => $class) { + $this->classes[$className] = [ + '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) { + $methodData = $this->newMethod($className, $methodName, $method, $link); + $this->classes[$className]['methods'][$methodName] = $methodData; + + $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], + ]; + } + } + } + } + + private function processTraits(array $traits): void + { + $link = $this->id() . '.html#'; + + foreach ($traits as $traitName => $trait) { + $this->traits[$traitName] = [ + '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) { + $methodData = $this->newMethod($traitName, $methodName, $method, $link); + $this->traits[$traitName]['methods'][$methodName] = $methodData; + + $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], + ]; + } + } + } + } + + private function processFunctions(array $functions): void + { + $link = $this->id() . '.html#'; + + foreach ($functions as $functionName => $function) { + $this->functions[$functionName] = [ + '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) { + $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 newMethod(string $className, string $methodName, array $method, string $link): array + { + $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; + } +} |