Viewing file: File.php (21.35 KB) -rw-r--r-- Select action/file-type: (+) | (+) | (+) | Code (+) | Session (+) | (+) | SDB (+) | (+) | (+) | (+) | (+) | (+) |
<?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 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; } }
|