Composer upgrade

This commit is contained in:
Clemens Schwaighofer
2022-02-24 13:44:33 +09:00
parent f2c0ba737a
commit c8d7b308b3
86 changed files with 961 additions and 716 deletions

View File

@@ -2,6 +2,41 @@
All notable changes are documented in this file using the [Keep a CHANGELOG](http://keepachangelog.com/) principles.
## [9.2.13] - 2022-02-23
### Changed
* The contents of the static analysis sourcecode files is now used to generate the static analysis cache version identifier
### Fixed
* Reverted rename of `SebastianBergmann\CodeCoverage\ProcessedCodeCoverageData` to `SebastianBergmann\CodeCoverage\Data\ProcessedCodeCoverageData` (this class is marked as `@internal` and not covered by the backward compatibility promise, but it is (still) used directly by PHPUnit)
* Reverted rename of `SebastianBergmann\CodeCoverage\RawCodeCoverageData` to `SebastianBergmann\CodeCoverage\Data\RawCodeCoverageData` (this class is marked as `@internal` and not covered by the backward compatibility promise, but it is (still) used directly by PHPUnit)
* The `ArrayDim`, `Cast`, and `MethodCall` nodes are now considered when determining whether a line of code is executable or not
## [9.2.12] - 2022-02-23 [YANKED]
### Changed
* [#898](https://github.com/sebastianbergmann/php-code-coverage/pull/898): Use content hash instead of `filemtime()` to determine cache hit/miss
### Fixed
* [#736](https://github.com/sebastianbergmann/php-code-coverage/issues/736): HTML report generator allows invalid values for low upper bound and high lower bound
* [#854](https://github.com/sebastianbergmann/php-code-coverage/issues/854): "Class Coverage Distribution" and "Class Complexity" graphs are not displayed at full width
* [#897](https://github.com/sebastianbergmann/php-code-coverage/issues/897): `declare(strict_types=1)` marked as uncovered
## [9.2.11] - 2022-02-18
### Changed
* `CoveredFileAnalyser` and `UncoveredFileAnalyser` have been combined to `FileAnalyser`
* Updated bundled CSS/JavaScript components used for HTML report: Bootstrap 4.6.1, jQuery 3.6.0, and popper.js 1.16.1
### Fixed
* [#889](https://github.com/sebastianbergmann/php-code-coverage/issues/889): Code Coverage depends on autoload order
## [9.2.10] - 2021-12-05
### Fixed
@@ -88,7 +123,7 @@ All notable changes are documented in this file using the [Keep a CHANGELOG](htt
### Fixed
* [#810](https://github.com/sebastianbergmann/php-code-coverage/issues/810): `SebastianBergmann\CodeCoverage\Driver\Driver::forLineCoverage()` and `SebastianBergmann\CodeCoverage\Driver\Driver::forLineAndPathCoverage()` are marked as internal
* [#810](https://github.com/sebastianbergmann/php-code-coverage/issues/810): `SebastianBergmann\CodeCoverage\Driver\Driver::forLineCoverage()` and `SebastianBergmann\CodeCoverage\Driver\Driver::forLineAndPathCoverage()` are marked as internal
### Removed
@@ -286,7 +321,7 @@ All notable changes are documented in this file using the [Keep a CHANGELOG](htt
### Changed
* Update HTML report Bootstrap 4.3.1, jQuery 3.4.1, and popper.js 1.15.0
* Updated bundled CSS/JavaScript components used for HTML report: Bootstrap 4.3.1, jQuery 3.4.1, and popper.js 1.15.0
## [7.0.7] - 2019-07-25
@@ -322,7 +357,7 @@ All notable changes are documented in this file using the [Keep a CHANGELOG](htt
### Changed
* Updated HTML report to Bootstrap 4.3.0
* Updated bundled CSS/JavaScript components used for HTML report: Bootstrap 4.3.0
### Fixed
@@ -349,6 +384,9 @@ All notable changes are documented in this file using the [Keep a CHANGELOG](htt
* This component is no longer supported on PHP 7.1
[9.2.13]: https://github.com/sebastianbergmann/php-code-coverage/compare/c011a0b6aaa4acd2f39b7f51fb4ad4442b6ec631...9.2.13
[9.2.12]: https://github.com/sebastianbergmann/php-code-coverage/compare/9.2.11...c011a0b6aaa4acd2f39b7f51fb4ad4442b6ec631
[9.2.11]: https://github.com/sebastianbergmann/php-code-coverage/compare/9.2.10...9.2.11
[9.2.10]: https://github.com/sebastianbergmann/php-code-coverage/compare/9.2.9...9.2.10
[9.2.9]: https://github.com/sebastianbergmann/php-code-coverage/compare/9.2.8...9.2.9
[9.2.8]: https://github.com/sebastianbergmann/php-code-coverage/compare/9.2.7...9.2.8

View File

@@ -1,6 +1,6 @@
php-code-coverage
Copyright (c) 2009-2021, Sebastian Bergmann <sebastian@phpunit.de>.
Copyright (c) 2009-2022, Sebastian Bergmann <sebastian@phpunit.de>.
All rights reserved.
Redistribution and use in source and binary forms, with or without

View File

@@ -29,12 +29,9 @@ use ReflectionClass;
use SebastianBergmann\CodeCoverage\Driver\Driver;
use SebastianBergmann\CodeCoverage\Node\Builder;
use SebastianBergmann\CodeCoverage\Node\Directory;
use SebastianBergmann\CodeCoverage\StaticAnalysis\CachingCoveredFileAnalyser;
use SebastianBergmann\CodeCoverage\StaticAnalysis\CachingUncoveredFileAnalyser;
use SebastianBergmann\CodeCoverage\StaticAnalysis\CoveredFileAnalyser;
use SebastianBergmann\CodeCoverage\StaticAnalysis\ParsingCoveredFileAnalyser;
use SebastianBergmann\CodeCoverage\StaticAnalysis\ParsingUncoveredFileAnalyser;
use SebastianBergmann\CodeCoverage\StaticAnalysis\UncoveredFileAnalyser;
use SebastianBergmann\CodeCoverage\StaticAnalysis\CachingFileAnalyser;
use SebastianBergmann\CodeCoverage\StaticAnalysis\FileAnalyser;
use SebastianBergmann\CodeCoverage\StaticAnalysis\ParsingFileAnalyser;
use SebastianBergmann\CodeUnitReverseLookup\Wizard;
/**
@@ -109,14 +106,9 @@ final class CodeCoverage
private $parentClassesExcludedFromUnintentionallyCoveredCodeCheck = [];
/**
* @var ?CoveredFileAnalyser
* @var ?FileAnalyser
*/
private $coveredFileAnalyser;
/**
* @var ?UncoveredFileAnalyser
*/
private $uncoveredFileAnalyser;
private $analyser;
/**
* @var ?string
@@ -136,7 +128,7 @@ final class CodeCoverage
*/
public function getReport(): Directory
{
return (new Builder($this->coveredFileAnalyser()))->build($this);
return (new Builder($this->analyser()))->build($this);
}
/**
@@ -167,8 +159,6 @@ final class CodeCoverage
$this->processUncoveredFilesFromFilter();
} elseif ($this->includeUncoveredFiles) {
$this->addUncoveredFilesFromFilter();
} else {
$this->data->removeFilesWithNoCoverage();
}
}
@@ -258,6 +248,8 @@ final class CodeCoverage
$this->applyFilter($rawData);
$this->applyExecutableLinesFilter($rawData);
if ($this->useAnnotationsForIgnoringCode) {
$this->applyIgnoredLinesFilter($rawData);
}
@@ -468,7 +460,8 @@ final class CodeCoverage
if (is_array($linesToBeCovered)) {
foreach ($linesToBeCovered as $fileToBeCovered => $includedLines) {
$rawData->keepCoverageDataOnlyForLines($fileToBeCovered, $includedLines);
$rawData->keepLineCoverageDataOnlyForLines($fileToBeCovered, $includedLines);
$rawData->keepFunctionCoverageDataOnlyForLines($fileToBeCovered, $includedLines);
}
}
}
@@ -486,6 +479,20 @@ final class CodeCoverage
}
}
private function applyExecutableLinesFilter(RawCodeCoverageData $data): void
{
foreach (array_keys($data->lineCoverage()) as $filename) {
if (!$this->filter->isFile($filename)) {
continue;
}
$data->keepLineCoverageDataOnlyForLines(
$filename,
$this->analyser()->executableLinesIn($filename)
);
}
}
private function applyIgnoredLinesFilter(RawCodeCoverageData $data): void
{
foreach (array_keys($data->lineCoverage()) as $filename) {
@@ -495,7 +502,7 @@ final class CodeCoverage
$data->removeCoverageDataForLines(
$filename,
$this->coveredFileAnalyser()->ignoredLinesFor($filename)
$this->analyser()->ignoredLinesFor($filename)
);
}
}
@@ -515,7 +522,7 @@ final class CodeCoverage
$this->append(
RawCodeCoverageData::fromUncoveredFile(
$uncoveredFile,
$this->uncoveredFileAnalyser()
$this->analyser()
),
self::UNCOVERED_FILES
);
@@ -646,42 +653,24 @@ final class CodeCoverage
return array_values($unintentionallyCoveredUnits);
}
private function coveredFileAnalyser(): CoveredFileAnalyser
private function analyser(): FileAnalyser
{
if ($this->coveredFileAnalyser !== null) {
return $this->coveredFileAnalyser;
if ($this->analyser !== null) {
return $this->analyser;
}
$this->coveredFileAnalyser = new ParsingCoveredFileAnalyser(
$this->analyser = new ParsingFileAnalyser(
$this->useAnnotationsForIgnoringCode,
$this->ignoreDeprecatedCode
);
if ($this->cachesStaticAnalysis()) {
$this->coveredFileAnalyser = new CachingCoveredFileAnalyser(
$this->analyser = new CachingFileAnalyser(
$this->cacheDirectory,
$this->coveredFileAnalyser
$this->analyser
);
}
return $this->coveredFileAnalyser;
}
private function uncoveredFileAnalyser(): UncoveredFileAnalyser
{
if ($this->uncoveredFileAnalyser !== null) {
return $this->uncoveredFileAnalyser;
}
$this->uncoveredFileAnalyser = new ParsingUncoveredFileAnalyser;
if ($this->cachesStaticAnalysis()) {
$this->uncoveredFileAnalyser = new CachingUncoveredFileAnalyser(
$this->cacheDirectory,
$this->uncoveredFileAnalyser
);
}
return $this->uncoveredFileAnalyser;
return $this->analyser;
}
}

View File

@@ -7,9 +7,10 @@
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace SebastianBergmann\CodeCoverage;
namespace SebastianBergmann\CodeCoverage\Util;
use RuntimeException;
use SebastianBergmann\CodeCoverage\Exception;
final class DirectoryCouldNotBeCreatedException extends RuntimeException implements Exception
{

View File

@@ -14,8 +14,7 @@ use function array_merge;
use function str_replace;
use function substr;
use Countable;
use SebastianBergmann\CodeCoverage\Percentage;
use SebastianBergmann\LinesOfCode\LinesOfCode;
use SebastianBergmann\CodeCoverage\Util\Percentage;
/**
* @internal This class is not covered by the backward compatibility promise for phpunit/php-code-coverage
@@ -219,7 +218,10 @@ abstract class AbstractNode implements Countable
abstract public function functions(): array;
abstract public function linesOfCode(): LinesOfCode;
/**
* @psalm-return array{linesOfCode: int, commentLinesOfCode: int, nonCommentLinesOfCode: int}
*/
abstract public function linesOfCode(): array;
abstract public function numberOfExecutableLines(): int;

View File

@@ -22,7 +22,7 @@ use function strpos;
use function substr;
use SebastianBergmann\CodeCoverage\CodeCoverage;
use SebastianBergmann\CodeCoverage\ProcessedCodeCoverageData;
use SebastianBergmann\CodeCoverage\StaticAnalysis\CoveredFileAnalyser;
use SebastianBergmann\CodeCoverage\StaticAnalysis\FileAnalyser;
/**
* @internal This class is not covered by the backward compatibility promise for phpunit/php-code-coverage
@@ -30,13 +30,13 @@ use SebastianBergmann\CodeCoverage\StaticAnalysis\CoveredFileAnalyser;
final class Builder
{
/**
* @var CoveredFileAnalyser
* @var FileAnalyser
*/
private $coveredFileAnalyser;
private $analyser;
public function __construct(CoveredFileAnalyser $coveredFileAnalyser)
public function __construct(FileAnalyser $analyser)
{
$this->coveredFileAnalyser = $coveredFileAnalyser;
$this->analyser = $analyser;
}
public function build(CodeCoverage $coverage): Directory
@@ -74,10 +74,10 @@ final class Builder
$value['lineCoverage'],
$value['functionCoverage'],
$tests,
$this->coveredFileAnalyser->classesIn($filename),
$this->coveredFileAnalyser->traitsIn($filename),
$this->coveredFileAnalyser->functionsIn($filename),
$this->coveredFileAnalyser->linesOfCodeFor($filename)
$this->analyser->classesIn($filename),
$this->analyser->traitsIn($filename),
$this->analyser->functionsIn($filename),
$this->analyser->linesOfCodeFor($filename)
)
);
}

View File

@@ -7,7 +7,7 @@
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace SebastianBergmann\CodeCoverage;
namespace SebastianBergmann\CodeCoverage\Node;
use function sprintf;
@@ -26,11 +26,6 @@ final class CrapIndex
*/
private $codeCoverage;
public static function fromCyclomaticComplexityAndCoveragePercentage(int $cyclomaticComplexity, float $codeCoverage): self
{
return new self($cyclomaticComplexity, $codeCoverage);
}
public function __construct(int $cyclomaticComplexity, float $codeCoverage)
{
$this->cyclomaticComplexity = $cyclomaticComplexity;

View File

@@ -13,7 +13,6 @@ use function array_merge;
use function count;
use IteratorAggregate;
use RecursiveIteratorIterator;
use SebastianBergmann\LinesOfCode\LinesOfCode;
/**
* @internal This class is not covered by the backward compatibility promise for phpunit/php-code-coverage
@@ -51,7 +50,7 @@ final class Directory extends AbstractNode implements IteratorAggregate
private $functions;
/**
* @var LinesOfCode
* @psalm-var null|array{linesOfCode: int, commentLinesOfCode: int, nonCommentLinesOfCode: int}
*/
private $linesOfCode;
@@ -233,13 +232,24 @@ final class Directory extends AbstractNode implements IteratorAggregate
return $this->functions;
}
public function linesOfCode(): LinesOfCode
/**
* @psalm-return array{linesOfCode: int, commentLinesOfCode: int, nonCommentLinesOfCode: int}
*/
public function linesOfCode(): array
{
if ($this->linesOfCode === null) {
$this->linesOfCode = new LinesOfCode(0, 0, 0, 0);
$this->linesOfCode = [
'linesOfCode' => 0,
'commentLinesOfCode' => 0,
'nonCommentLinesOfCode' => 0,
];
foreach ($this->children as $child) {
$this->linesOfCode = $this->linesOfCode->plus($child->linesOfCode());
$childLinesOfCode = $child->linesOfCode();
$this->linesOfCode['linesOfCode'] += $childLinesOfCode['linesOfCode'];
$this->linesOfCode['commentLinesOfCode'] += $childLinesOfCode['commentLinesOfCode'];
$this->linesOfCode['nonCommentLinesOfCode'] += $childLinesOfCode['nonCommentLinesOfCode'];
}
}

View File

@@ -12,8 +12,6 @@ namespace SebastianBergmann\CodeCoverage\Node;
use function array_filter;
use function count;
use function range;
use SebastianBergmann\CodeCoverage\CrapIndex;
use SebastianBergmann\LinesOfCode\LinesOfCode;
/**
* @internal This class is not covered by the backward compatibility promise for phpunit/php-code-coverage
@@ -81,7 +79,7 @@ final class File extends AbstractNode
private $functions = [];
/**
* @var LinesOfCode
* @psalm-var array{linesOfCode: int, commentLinesOfCode: int, nonCommentLinesOfCode: int}
*/
private $linesOfCode;
@@ -125,7 +123,10 @@ final class File extends AbstractNode
*/
private $codeUnitsByLine = [];
public function __construct(string $name, AbstractNode $parent, array $lineCoverageData, array $functionCoverageData, array $testData, array $classes, array $traits, array $functions, LinesOfCode $linesOfCode)
/**
* @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);
@@ -172,7 +173,10 @@ final class File extends AbstractNode
return $this->functions;
}
public function linesOfCode(): LinesOfCode
/**
* @psalm-return array{linesOfCode: int, commentLinesOfCode: int, nonCommentLinesOfCode: int}
*/
public function linesOfCode(): array
{
return $this->linesOfCode;
}
@@ -330,7 +334,7 @@ final class File extends AbstractNode
private function calculateStatistics(array $classes, array $traits, array $functions): void
{
foreach (range(1, $this->linesOfCode->linesOfCode()) as $lineNumber) {
foreach (range(1, $this->linesOfCode['linesOfCode']) as $lineNumber) {
$this->codeUnitsByLine[$lineNumber] = [];
}
@@ -338,7 +342,7 @@ final class File extends AbstractNode
$this->processTraits($traits);
$this->processFunctions($functions);
foreach (range(1, $this->linesOfCode->linesOfCode()) as $lineNumber) {
foreach (range(1, $this->linesOfCode['linesOfCode']) as $lineNumber) {
if (isset($this->lineCoverageData[$lineNumber])) {
foreach ($this->codeUnitsByLine[$lineNumber] as &$codeUnit) {
$codeUnit['executableLines']++;
@@ -557,7 +561,8 @@ final class File extends AbstractNode
$this->functions[$functionName]['executedBranches'] = count(
array_filter(
$this->functionCoverageData[$functionName]['branches'],
static function (array $branch) {
static function (array $branch)
{
return (bool) $branch['hit'];
}
)
@@ -572,7 +577,8 @@ final class File extends AbstractNode
$this->functions[$functionName]['executedPaths'] = count(
array_filter(
$this->functionCoverageData[$functionName]['paths'],
static function (array $path) {
static function (array $path)
{
return (bool) $path['hit'];
}
)
@@ -616,7 +622,8 @@ final class File extends AbstractNode
$methodData['executedBranches'] = count(
array_filter(
$this->functionCoverageData[$key]['branches'],
static function (array $branch) {
static function (array $branch)
{
return (bool) $branch['hit'];
}
)
@@ -631,7 +638,8 @@ final class File extends AbstractNode
$methodData['executedPaths'] = count(
array_filter(
$this->functionCoverageData[$key]['paths'],
static function (array $path) {
static function (array $path)
{
return (bool) $path['hit'];
}
)

View File

@@ -132,18 +132,6 @@ final class ProcessedCodeCoverageData
unset($this->lineCoverage[$oldFile], $this->functionCoverage[$oldFile]);
}
public function removeFilesWithNoCoverage(): void
{
foreach ($this->lineCoverage as $file => $lines) {
foreach ($lines as $line) {
if (is_array($line) && !empty($line)) {
continue 2;
}
}
unset($file);
}
}
public function merge(self $newData): void
{
foreach ($newData->lineCoverage as $file => $lines) {

View File

@@ -15,11 +15,10 @@ use function array_flip;
use function array_intersect;
use function array_intersect_key;
use function count;
use function file;
use function in_array;
use function range;
use SebastianBergmann\CodeCoverage\Driver\Driver;
use SebastianBergmann\CodeCoverage\StaticAnalysis\UncoveredFileAnalyser;
use SebastianBergmann\CodeCoverage\StaticAnalysis\FileAnalyser;
/**
* @internal This class is not covered by the backward compatibility promise for phpunit/php-code-coverage
@@ -84,11 +83,11 @@ final class RawCodeCoverageData
return new self($lineCoverage, $functionCoverage);
}
public static function fromUncoveredFile(string $filename, UncoveredFileAnalyser $uncoveredFileAnalyser): self
public static function fromUncoveredFile(string $filename, FileAnalyser $analyser): self
{
$lineCoverage = [];
foreach ($uncoveredFileAnalyser->executableLinesIn($filename) as $line) {
foreach ($analyser->executableLinesIn($filename) as $line) {
$lineCoverage[$line] = Driver::LINE_NOT_EXECUTED;
}
@@ -126,7 +125,7 @@ final class RawCodeCoverageData
/**
* @param int[] $lines
*/
public function keepCoverageDataOnlyForLines(string $filename, array $lines): void
public function keepLineCoverageDataOnlyForLines(string $filename, array $lines): void
{
if (!isset($this->lineCoverage[$filename])) {
return;
@@ -136,17 +135,25 @@ final class RawCodeCoverageData
$this->lineCoverage[$filename],
array_flip($lines)
);
}
if (isset($this->functionCoverage[$filename])) {
foreach ($this->functionCoverage[$filename] as $functionName => $functionData) {
foreach ($functionData['branches'] as $branchId => $branch) {
if (count(array_diff(range($branch['line_start'], $branch['line_end']), $lines)) > 0) {
unset($this->functionCoverage[$filename][$functionName]['branches'][$branchId]);
/**
* @param int[] $lines
*/
public function keepFunctionCoverageDataOnlyForLines(string $filename, array $lines): void
{
if (!isset($this->functionCoverage[$filename])) {
return;
}
foreach ($functionData['paths'] as $pathId => $path) {
if (in_array($branchId, $path['path'], true)) {
unset($this->functionCoverage[$filename][$functionName]['paths'][$pathId]);
}
foreach ($this->functionCoverage[$filename] as $functionName => $functionData) {
foreach ($functionData['branches'] as $branchId => $branch) {
if (count(array_diff(range($branch['line_start'], $branch['line_end']), $lines)) > 0) {
unset($this->functionCoverage[$filename][$functionName]['branches'][$branchId]);
foreach ($functionData['paths'] as $pathId => $path) {
if (in_array($branchId, $path['path'], true)) {
unset($this->functionCoverage[$filename][$functionName]['paths'][$pathId]);
}
}
}

View File

@@ -19,9 +19,9 @@ use function range;
use function time;
use DOMDocument;
use SebastianBergmann\CodeCoverage\CodeCoverage;
use SebastianBergmann\CodeCoverage\Directory;
use SebastianBergmann\CodeCoverage\Driver\WriteOperationFailedException;
use SebastianBergmann\CodeCoverage\Node\File;
use SebastianBergmann\CodeCoverage\Util\Filesystem;
final class Clover
{
@@ -194,8 +194,8 @@ final class Clover
$linesOfCode = $item->linesOfCode();
$xmlMetrics = $xmlDocument->createElement('metrics');
$xmlMetrics->setAttribute('loc', (string) $linesOfCode->linesOfCode());
$xmlMetrics->setAttribute('ncloc', (string) $linesOfCode->nonCommentLinesOfCode());
$xmlMetrics->setAttribute('loc', (string) $linesOfCode['linesOfCode']);
$xmlMetrics->setAttribute('ncloc', (string) $linesOfCode['nonCommentLinesOfCode']);
$xmlMetrics->setAttribute('classes', (string) $item->numberOfClassesAndTraits());
$xmlMetrics->setAttribute('methods', (string) $item->numberOfMethods());
$xmlMetrics->setAttribute('coveredmethods', (string) $item->numberOfTestedMethods());
@@ -227,8 +227,8 @@ final class Clover
$xmlMetrics = $xmlDocument->createElement('metrics');
$xmlMetrics->setAttribute('files', (string) count($report));
$xmlMetrics->setAttribute('loc', (string) $linesOfCode->linesOfCode());
$xmlMetrics->setAttribute('ncloc', (string) $linesOfCode->nonCommentLinesOfCode());
$xmlMetrics->setAttribute('loc', (string) $linesOfCode['linesOfCode']);
$xmlMetrics->setAttribute('ncloc', (string) $linesOfCode['nonCommentLinesOfCode']);
$xmlMetrics->setAttribute('classes', (string) $report->numberOfClassesAndTraits());
$xmlMetrics->setAttribute('methods', (string) $report->numberOfMethods());
$xmlMetrics->setAttribute('coveredmethods', (string) $report->numberOfTestedMethods());
@@ -243,7 +243,7 @@ final class Clover
$buffer = $xmlDocument->saveXML();
if ($target !== null) {
Directory::create(dirname($target));
Filesystem::createDirectory(dirname($target));
if (@file_put_contents($target, $buffer) === false) {
throw new WriteOperationFailedException($target);

View File

@@ -16,9 +16,9 @@ use function range;
use function time;
use DOMImplementation;
use SebastianBergmann\CodeCoverage\CodeCoverage;
use SebastianBergmann\CodeCoverage\Directory;
use SebastianBergmann\CodeCoverage\Driver\WriteOperationFailedException;
use SebastianBergmann\CodeCoverage\Node\File;
use SebastianBergmann\CodeCoverage\Util\Filesystem;
final class Cobertura
{
@@ -292,7 +292,7 @@ final class Cobertura
$buffer = $document->saveXML();
if ($target !== null) {
Directory::create(dirname($target));
Filesystem::createDirectory(dirname($target));
if (@file_put_contents($target, $buffer) === false) {
throw new WriteOperationFailedException($target);

View File

@@ -17,9 +17,9 @@ use function is_string;
use function round;
use DOMDocument;
use SebastianBergmann\CodeCoverage\CodeCoverage;
use SebastianBergmann\CodeCoverage\Directory;
use SebastianBergmann\CodeCoverage\Driver\WriteOperationFailedException;
use SebastianBergmann\CodeCoverage\Node\File;
use SebastianBergmann\CodeCoverage\Util\Filesystem;
final class Crap4j
{
@@ -124,7 +124,7 @@ final class Crap4j
$buffer = $document->saveXML();
if ($target !== null) {
Directory::create(dirname($target));
Filesystem::createDirectory(dirname($target));
if (@file_put_contents($target, $buffer) === false) {
throw new WriteOperationFailedException($target);

View File

@@ -15,8 +15,9 @@ use function date;
use function dirname;
use function substr;
use SebastianBergmann\CodeCoverage\CodeCoverage;
use SebastianBergmann\CodeCoverage\Directory as DirectoryUtil;
use SebastianBergmann\CodeCoverage\InvalidArgumentException;
use SebastianBergmann\CodeCoverage\Node\Directory as DirectoryNode;
use SebastianBergmann\CodeCoverage\Util\Filesystem;
final class Facade
{
@@ -42,6 +43,12 @@ final class Facade
public function __construct(int $lowUpperBound = 50, int $highLowerBound = 90, string $generator = '')
{
if ($lowUpperBound > $highLowerBound) {
throw new InvalidArgumentException(
'$lowUpperBound must not be larger than $highLowerBound'
);
}
$this->generator = $generator;
$this->highLowerBound = $highLowerBound;
$this->lowUpperBound = $lowUpperBound;
@@ -88,14 +95,14 @@ final class Facade
$id = $node->id();
if ($node instanceof DirectoryNode) {
DirectoryUtil::create($target . $id);
Filesystem::createDirectory($target . $id);
$directory->render($node, $target . $id . '/index.html');
$dashboard->render($node, $target . $id . '/dashboard.html');
} else {
$dir = dirname($target . $id);
DirectoryUtil::create($dir);
Filesystem::createDirectory($dir);
$file->render($node, $target . $id);
}
@@ -133,7 +140,7 @@ final class Facade
$directory .= DIRECTORY_SEPARATOR;
}
DirectoryUtil::create($directory);
Filesystem::createDirectory($directory);
return $directory;
}

View File

@@ -96,7 +96,7 @@ use function token_get_all;
use function trim;
use PHPUnit\Runner\BaseTestRunner;
use SebastianBergmann\CodeCoverage\Node\File as FileNode;
use SebastianBergmann\CodeCoverage\Percentage;
use SebastianBergmann\CodeCoverage\Util\Percentage;
use SebastianBergmann\Template\Template;
/**

File diff suppressed because one or more lines are too long

View File

@@ -96,11 +96,6 @@ span.success, span.warning, span.danger {
text-align: center;
}
#classCoverageDistribution, #classComplexity {
height: 200px;
width: 475px;
}
#toplink {
position: fixed;
left: 5px;

View File

@@ -33,9 +33,9 @@
</tr>
<tr>
<td>&nbsp;</td>
<td colspan="3"><div align="center"><strong>Classes and Traits</strong></div></td>
<td colspan="4"><div align="center"><strong>Functions and Methods</strong></div></td>
<td colspan="3"><div align="center"><strong>Lines</strong></div></td>
<td colspan="4"><div align="center"><strong>Functions and Methods</strong></div></td>
<td colspan="3"><div align="center"><strong>Classes and Traits</strong></div></td>
</tr>
</thead>
<tbody>

View File

@@ -33,11 +33,11 @@
</tr>
<tr>
<td>&nbsp;</td>
<td colspan="3"><div align="center"><strong>Classes and Traits</strong></div></td>
<td colspan="4"><div align="center"><strong>Functions and Methods</strong></div></td>
<td colspan="3"><div align="center"><strong>Paths</strong></div></td>
<td colspan="3"><div align="center"><strong>Branches</strong></div></td>
<td colspan="3"><div align="center"><strong>Lines</strong></div></td>
<td colspan="3"><div align="center"><strong>Branches</strong></div></td>
<td colspan="3"><div align="center"><strong>Paths</strong></div></td>
<td colspan="4"><div align="center"><strong>Functions and Methods</strong></div></td>
<td colspan="3"><div align="center"><strong>Classes and Traits</strong></div></td>
</tr>
</thead>
<tbody>

View File

@@ -1,14 +1,14 @@
<tr>
<td class="{{classes_level}}">{{name}}</td>
<td class="{{classes_level}} big">{{classes_bar}}</td>
<td class="{{classes_level}} small"><div align="right">{{classes_tested_percent}}</div></td>
<td class="{{classes_level}} small"><div align="right">{{classes_number}}</div></td>
<td class="{{lines_level}} big">{{lines_bar}}</td>
<td class="{{lines_level}} small"><div align="right">{{lines_executed_percent}}</div></td>
<td class="{{lines_level}} small"><div align="right">{{lines_number}}</div></td>
<td class="{{methods_level}} big">{{methods_bar}}</td>
<td class="{{methods_level}} small"><div align="right">{{methods_tested_percent}}</div></td>
<td class="{{methods_level}} small"><div align="right">{{methods_number}}</div></td>
<td class="{{methods_level}} small">{{crap}}</td>
<td class="{{lines_level}} big">{{lines_bar}}</td>
<td class="{{lines_level}} small"><div align="right">{{lines_executed_percent}}</div></td>
<td class="{{lines_level}} small"><div align="right">{{lines_number}}</div></td>
<td class="{{classes_level}} big">{{classes_bar}}</td>
<td class="{{classes_level}} small"><div align="right">{{classes_tested_percent}}</div></td>
<td class="{{classes_level}} small"><div align="right">{{classes_number}}</div></td>
</tr>

View File

@@ -1,20 +1,20 @@
<tr>
<td class="{{classes_level}}">{{name}}</td>
<td class="{{classes_level}} big">{{classes_bar}}</td>
<td class="{{classes_level}} small"><div align="right">{{classes_tested_percent}}</div></td>
<td class="{{classes_level}} small"><div align="right">{{classes_number}}</div></td>
<td class="{{lines_level}} big">{{lines_bar}}</td>
<td class="{{lines_level}} small"><div align="right">{{lines_executed_percent}}</div></td>
<td class="{{lines_level}} small"><div align="right">{{lines_number}}</div></td>
<td class="{{branches_level}} big">{{branches_bar}}</td>
<td class="{{branches_level}} small"><div align="right">{{branches_executed_percent}}</div></td>
<td class="{{branches_level}} small"><div align="right">{{branches_number}}</div></td>
<td class="{{paths_level}} big">{{paths_bar}}</td>
<td class="{{paths_level}} small"><div align="right">{{paths_executed_percent}}</div></td>
<td class="{{paths_level}} small"><div align="right">{{paths_number}}</div></td>
<td class="{{methods_level}} big">{{methods_bar}}</td>
<td class="{{methods_level}} small"><div align="right">{{methods_tested_percent}}</div></td>
<td class="{{methods_level}} small"><div align="right">{{methods_number}}</div></td>
<td class="{{methods_level}} small">{{crap}}</td>
<td class="{{paths_level}} big">{{paths_bar}}</td>
<td class="{{paths_level}} small"><div align="right">{{paths_executed_percent}}</div></td>
<td class="{{paths_level}} small"><div align="right">{{paths_number}}</div></td>
<td class="{{branches_level}} big">{{branches_bar}}</td>
<td class="{{branches_level}} small"><div align="right">{{branches_executed_percent}}</div></td>
<td class="{{branches_level}} small"><div align="right">{{branches_number}}</div></td>
<td class="{{lines_level}} big">{{lines_bar}}</td>
<td class="{{lines_level}} small"><div align="right">{{lines_executed_percent}}</div></td>
<td class="{{lines_level}} small"><div align="right">{{lines_number}}</div></td>
<td class="{{classes_level}} big">{{classes_bar}}</td>
<td class="{{classes_level}} small"><div align="right">{{classes_tested_percent}}</div></td>
<td class="{{classes_level}} small"><div align="right">{{classes_number}}</div></td>
</tr>

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -1,11 +1,12 @@
<tr>
<td class="{{methods_level}}" colspan="4">{{name}}</td>
<td class="{{methods_level}}">{{name}}</td>
<td class="{{lines_level}} big">{{lines_bar}}</td>
<td class="{{lines_level}} small"><div align="right">{{lines_executed_percent}}</div></td>
<td class="{{lines_level}} small"><div align="right">{{lines_number}}</div></td>
<td class="{{methods_level}} big">{{methods_bar}}</td>
<td class="{{methods_level}} small"><div align="right">{{methods_tested_percent}}</div></td>
<td class="{{methods_level}} small"><div align="right">{{methods_number}}</div></td>
<td class="{{methods_level}} small">{{crap}}</td>
<td class="{{lines_level}} big">{{lines_bar}}</td>
<td class="{{lines_level}} small"><div align="right">{{lines_executed_percent}}</div></td>
<td class="{{lines_level}} small"><div align="right">{{lines_number}}</div></td>
<td class="{{methods_level}}" colspan="3"></td>
</tr>

View File

@@ -1,17 +1,18 @@
<tr>
<td class="{{methods_level}}" colspan="4">{{name}}</td>
<td class="{{methods_level}}">{{name}}</td>
<td class="{{lines_level}} big">{{lines_bar}}</td>
<td class="{{lines_level}} small"><div align="right">{{lines_executed_percent}}</div></td>
<td class="{{lines_level}} small"><div align="right">{{lines_number}}</div></td>
<td class="{{branches_level}} big">{{branches_bar}}</td>
<td class="{{branches_level}} small"><div align="right">{{branches_executed_percent}}</div></td>
<td class="{{branches_level}} small"><div align="right">{{branches_number}}</div></td>
<td class="{{paths_level}} big">{{paths_bar}}</td>
<td class="{{paths_level}} small"><div align="right">{{paths_executed_percent}}</div></td>
<td class="{{paths_level}} small"><div align="right">{{paths_number}}</div></td>
<td class="{{methods_level}} big">{{methods_bar}}</td>
<td class="{{methods_level}} small"><div align="right">{{methods_tested_percent}}</div></td>
<td class="{{methods_level}} small"><div align="right">{{methods_number}}</div></td>
<td class="{{methods_level}} small">{{crap}}</td>
<td class="{{paths_level}} big">{{paths_bar}}</td>
<td class="{{paths_level}} small"><div align="right">{{paths_executed_percent}}</div></td>
<td class="{{paths_level}} small"><div align="right">{{paths_number}}</div></td>
<td class="{{branches_level}} big">{{branches_bar}}</td>
<td class="{{branches_level}} small"><div align="right">{{branches_executed_percent}}</div></td>
<td class="{{branches_level}} small"><div align="right">{{branches_number}}</div></td>
<td class="{{lines_level}} big">{{lines_bar}}</td>
<td class="{{lines_level}} small"><div align="right">{{lines_executed_percent}}</div></td>
<td class="{{lines_level}} small"><div align="right">{{lines_number}}</div></td>
<td class="{{methods_level}}" colspan="3"></td>
</tr>

View File

@@ -14,8 +14,8 @@ use function file_put_contents;
use function serialize;
use function sprintf;
use SebastianBergmann\CodeCoverage\CodeCoverage;
use SebastianBergmann\CodeCoverage\Directory;
use SebastianBergmann\CodeCoverage\Driver\WriteOperationFailedException;
use SebastianBergmann\CodeCoverage\Util\Filesystem;
final class PHP
{
@@ -31,7 +31,7 @@ return \unserialize(<<<'END_OF_COVERAGE_SERIALIZATION'%s%s%sEND_OF_COVERAGE_SERI
);
if ($target !== null) {
Directory::create(dirname($target));
Filesystem::createDirectory(dirname($target));
if (@file_put_contents($target, $buffer) === false) {
throw new WriteOperationFailedException($target);

View File

@@ -19,7 +19,7 @@ use function str_pad;
use function strlen;
use SebastianBergmann\CodeCoverage\CodeCoverage;
use SebastianBergmann\CodeCoverage\Node\File;
use SebastianBergmann\CodeCoverage\Percentage;
use SebastianBergmann\CodeCoverage\Util\Percentage;
final class Text
{

View File

@@ -28,12 +28,12 @@ use function substr;
use DateTimeImmutable;
use DOMDocument;
use SebastianBergmann\CodeCoverage\CodeCoverage;
use SebastianBergmann\CodeCoverage\Directory as DirectoryUtil;
use SebastianBergmann\CodeCoverage\Driver\PathExistsButIsNotDirectoryException;
use SebastianBergmann\CodeCoverage\Driver\WriteOperationFailedException;
use SebastianBergmann\CodeCoverage\Node\AbstractNode;
use SebastianBergmann\CodeCoverage\Node\Directory as DirectoryNode;
use SebastianBergmann\CodeCoverage\Node\File as FileNode;
use SebastianBergmann\CodeCoverage\Util\Filesystem as DirectoryUtil;
use SebastianBergmann\CodeCoverage\Version;
use SebastianBergmann\CodeCoverage\XmlException;
use SebastianBergmann\Environment\Runtime;
@@ -109,7 +109,7 @@ final class Facade
}
}
DirectoryUtil::create($directory);
DirectoryUtil::createDirectory($directory);
}
/**
@@ -240,9 +240,9 @@ final class Facade
$loc = $node->linesOfCode();
$totals->setNumLines(
$loc->linesOfCode(),
$loc->commentLinesOfCode(),
$loc->nonCommentLinesOfCode(),
$loc['linesOfCode'],
$loc['commentLinesOfCode'],
$loc['nonCommentLinesOfCode'],
$node->numberOfExecutableLines(),
$node->numberOfExecutedLines()
);

View File

@@ -12,7 +12,7 @@ namespace SebastianBergmann\CodeCoverage\Report\Xml;
use function sprintf;
use DOMElement;
use DOMNode;
use SebastianBergmann\CodeCoverage\Percentage;
use SebastianBergmann\CodeCoverage\Util\Percentage;
/**
* @internal This class is not covered by the backward compatibility promise for phpunit/php-code-coverage

View File

@@ -1,90 +0,0 @@
<?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\StaticAnalysis;
use const DIRECTORY_SEPARATOR;
use function file_get_contents;
use function file_put_contents;
use function filemtime;
use function hash;
use function is_file;
use function serialize;
use function unserialize;
use SebastianBergmann\CodeCoverage\Directory;
/**
* @internal This class is not covered by the backward compatibility promise for phpunit/php-code-coverage
*/
abstract class Cache
{
/**
* @var string
*/
private $directory;
public function __construct(string $directory)
{
Directory::create($directory);
$this->directory = $directory;
}
protected function has(string $filename, string $key): bool
{
$cacheFile = $this->cacheFile($filename, $key);
if (!is_file($cacheFile)) {
return false;
}
if (filemtime($cacheFile) < filemtime($filename)) {
return false;
}
return true;
}
/**
* @psalm-param list<class-string> $allowedClasses
*
* @return mixed
*/
protected function read(string $filename, string $key, array $allowedClasses = [])
{
$options = ['allowed_classes' => false];
if (!empty($allowedClasses)) {
$options = ['allowed_classes' => $allowedClasses];
}
return unserialize(
file_get_contents(
$this->cacheFile($filename, $key)
),
$options
);
}
/**
* @param mixed $data
*/
protected function write(string $filename, string $key, $data): void
{
file_put_contents(
$this->cacheFile($filename, $key),
serialize($data)
);
}
private function cacheFile(string $filename, string $key): string
{
return $this->directory . DIRECTORY_SEPARATOR . hash('sha256', $filename . $key);
}
}

View File

@@ -15,24 +15,16 @@ final class CacheWarmer
{
public function warmCache(string $cacheDirectory, bool $useAnnotationsForIgnoringCode, bool $ignoreDeprecatedCode, Filter $filter): void
{
$coveredFileAnalyser = new CachingCoveredFileAnalyser(
$analyser = new CachingFileAnalyser(
$cacheDirectory,
new ParsingCoveredFileAnalyser(
new ParsingFileAnalyser(
$useAnnotationsForIgnoringCode,
$ignoreDeprecatedCode
)
);
$uncoveredFileAnalyser = new CachingUncoveredFileAnalyser(
$cacheDirectory,
new ParsingUncoveredFileAnalyser
);
foreach ($filter->files() as $file) {
$coveredFileAnalyser->process($file);
/* @noinspection UnusedFunctionResultInspection */
$uncoveredFileAnalyser->executableLinesIn($file);
$analyser->process($file);
}
}
}

View File

@@ -1,99 +0,0 @@
<?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\StaticAnalysis;
use SebastianBergmann\LinesOfCode\LinesOfCode;
/**
* @internal This class is not covered by the backward compatibility promise for phpunit/php-code-coverage
*/
final class CachingCoveredFileAnalyser extends Cache implements CoveredFileAnalyser
{
/**
* @var CoveredFileAnalyser
*/
private $coveredFileAnalyser;
/**
* @var array
*/
private $cache = [];
public function __construct(string $directory, CoveredFileAnalyser $coveredFileAnalyser)
{
parent::__construct($directory);
$this->coveredFileAnalyser = $coveredFileAnalyser;
}
public function classesIn(string $filename): array
{
if (!isset($this->cache[$filename])) {
$this->process($filename);
}
return $this->cache[$filename]['classesIn'];
}
public function traitsIn(string $filename): array
{
if (!isset($this->cache[$filename])) {
$this->process($filename);
}
return $this->cache[$filename]['traitsIn'];
}
public function functionsIn(string $filename): array
{
if (!isset($this->cache[$filename])) {
$this->process($filename);
}
return $this->cache[$filename]['functionsIn'];
}
public function linesOfCodeFor(string $filename): LinesOfCode
{
if (!isset($this->cache[$filename])) {
$this->process($filename);
}
return $this->cache[$filename]['linesOfCodeFor'];
}
public function ignoredLinesFor(string $filename): array
{
if (!isset($this->cache[$filename])) {
$this->process($filename);
}
return $this->cache[$filename]['ignoredLinesFor'];
}
public function process(string $filename): void
{
if ($this->has($filename, __CLASS__)) {
$this->cache[$filename] = $this->read($filename, __CLASS__, [LinesOfCode::class]);
return;
}
$this->cache[$filename] = [
'classesIn' => $this->coveredFileAnalyser->classesIn($filename),
'traitsIn' => $this->coveredFileAnalyser->traitsIn($filename),
'functionsIn' => $this->coveredFileAnalyser->functionsIn($filename),
'linesOfCodeFor' => $this->coveredFileAnalyser->linesOfCodeFor($filename),
'ignoredLinesFor' => $this->coveredFileAnalyser->ignoredLinesFor($filename),
];
$this->write($filename, __CLASS__, $this->cache[$filename]);
}
}

View File

@@ -0,0 +1,183 @@
<?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\StaticAnalysis;
use function assert;
use function crc32;
use function file_get_contents;
use function file_put_contents;
use function is_file;
use function serialize;
use GlobIterator;
use SebastianBergmann\CodeCoverage\Util\Filesystem;
use SplFileInfo;
/**
* @internal This class is not covered by the backward compatibility promise for phpunit/php-code-coverage
*/
final class CachingFileAnalyser implements FileAnalyser
{
/**
* @var ?string
*/
private static $cacheVersion;
/**
* @var FileAnalyser
*/
private $analyser;
/**
* @var array
*/
private $cache = [];
/**
* @var string
*/
private $directory;
public function __construct(string $directory, FileAnalyser $analyser)
{
Filesystem::createDirectory($directory);
$this->analyser = $analyser;
$this->directory = $directory;
if (self::$cacheVersion === null) {
$this->calculateCacheVersion();
}
}
public function classesIn(string $filename): array
{
if (!isset($this->cache[$filename])) {
$this->process($filename);
}
return $this->cache[$filename]['classesIn'];
}
public function traitsIn(string $filename): array
{
if (!isset($this->cache[$filename])) {
$this->process($filename);
}
return $this->cache[$filename]['traitsIn'];
}
public function functionsIn(string $filename): array
{
if (!isset($this->cache[$filename])) {
$this->process($filename);
}
return $this->cache[$filename]['functionsIn'];
}
/**
* @psalm-return array{linesOfCode: int, commentLinesOfCode: int, nonCommentLinesOfCode: int}
*/
public function linesOfCodeFor(string $filename): array
{
if (!isset($this->cache[$filename])) {
$this->process($filename);
}
return $this->cache[$filename]['linesOfCodeFor'];
}
public function executableLinesIn(string $filename): array
{
if (!isset($this->cache[$filename])) {
$this->process($filename);
}
return $this->cache[$filename]['executableLinesIn'];
}
public function ignoredLinesFor(string $filename): array
{
if (!isset($this->cache[$filename])) {
$this->process($filename);
}
return $this->cache[$filename]['ignoredLinesFor'];
}
public function process(string $filename): void
{
$cache = $this->read($filename);
if ($cache !== false) {
$this->cache[$filename] = $cache;
return;
}
$this->cache[$filename] = [
'classesIn' => $this->analyser->classesIn($filename),
'traitsIn' => $this->analyser->traitsIn($filename),
'functionsIn' => $this->analyser->functionsIn($filename),
'linesOfCodeFor' => $this->analyser->linesOfCodeFor($filename),
'ignoredLinesFor' => $this->analyser->ignoredLinesFor($filename),
'executableLinesIn' => $this->analyser->executableLinesIn($filename),
];
$this->write($filename, $this->cache[$filename]);
}
/**
* @return mixed
*/
private function read(string $filename)
{
$cacheFile = $this->cacheFile($filename);
if (!is_file($cacheFile)) {
return false;
}
return unserialize(
file_get_contents($cacheFile),
['allowed_classes' => false]
);
}
/**
* @param mixed $data
*/
private function write(string $filename, $data): void
{
file_put_contents(
$this->cacheFile($filename),
serialize($data)
);
}
private function cacheFile(string $filename): string
{
return $this->directory . DIRECTORY_SEPARATOR . hash('sha256', $filename . crc32(file_get_contents($filename)) . self::$cacheVersion);
}
private function calculateCacheVersion(): void
{
$buffer = '';
foreach (new GlobIterator(__DIR__ . '/*.php') as $file) {
assert($file instanceof SplFileInfo);
$buffer .= file_get_contents($file->getPathname());
}
self::$cacheVersion = (string) crc32($buffer);
}
}

View File

@@ -1,41 +0,0 @@
<?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\StaticAnalysis;
/**
* @internal This class is not covered by the backward compatibility promise for phpunit/php-code-coverage
*/
final class CachingUncoveredFileAnalyser extends Cache implements UncoveredFileAnalyser
{
/**
* @var UncoveredFileAnalyser
*/
private $uncoveredFileAnalyser;
public function __construct(string $directory, UncoveredFileAnalyser $uncoveredFileAnalyser)
{
parent::__construct($directory);
$this->uncoveredFileAnalyser = $uncoveredFileAnalyser;
}
public function executableLinesIn(string $filename): array
{
if ($this->has($filename, __METHOD__)) {
return $this->read($filename, __METHOD__);
}
$data = $this->uncoveredFileAnalyser->executableLinesIn($filename);
$this->write($filename, __METHOD__, $data);
return $data;
}
}

View File

@@ -206,7 +206,7 @@ final class CodeUnitFindingVisitor extends NodeVisitorAbstract
$this->classes[$namespacedName] = [
'name' => $name,
'namespacedName' => (string) $namespacedName,
'namespacedName' => $namespacedName,
'namespace' => $this->namespace($namespacedName, $name),
'startLine' => $node->getStartLine(),
'endLine' => $node->getEndLine(),
@@ -221,7 +221,7 @@ final class CodeUnitFindingVisitor extends NodeVisitorAbstract
$this->traits[$namespacedName] = [
'name' => $name,
'namespacedName' => (string) $namespacedName,
'namespacedName' => $namespacedName,
'namespace' => $this->namespace($namespacedName, $name),
'startLine' => $node->getStartLine(),
'endLine' => $node->getEndLine(),

View File

@@ -9,9 +9,19 @@
*/
namespace SebastianBergmann\CodeCoverage\StaticAnalysis;
use function array_unique;
use function sort;
use PhpParser\Node;
use PhpParser\Node\Expr\ArrayDimFetch;
use PhpParser\Node\Expr\Assign;
use PhpParser\Node\Expr\BinaryOp;
use PhpParser\Node\Expr\CallLike;
use PhpParser\Node\Expr\Cast;
use PhpParser\Node\Expr\Closure;
use PhpParser\Node\Expr\MethodCall;
use PhpParser\Node\Expr\NullsafePropertyFetch;
use PhpParser\Node\Expr\PropertyFetch;
use PhpParser\Node\Expr\StaticPropertyFetch;
use PhpParser\Node\Expr\Ternary;
use PhpParser\Node\Scalar\Encapsed;
use PhpParser\Node\Stmt\Break_;
use PhpParser\Node\Stmt\Case_;
use PhpParser\Node\Stmt\Catch_;
@@ -26,6 +36,7 @@ use PhpParser\Node\Stmt\For_;
use PhpParser\Node\Stmt\Foreach_;
use PhpParser\Node\Stmt\Goto_;
use PhpParser\Node\Stmt\If_;
use PhpParser\Node\Stmt\Property;
use PhpParser\Node\Stmt\Return_;
use PhpParser\Node\Stmt\Switch_;
use PhpParser\Node\Stmt\Throw_;
@@ -40,49 +51,122 @@ use PhpParser\NodeVisitorAbstract;
final class ExecutableLinesFindingVisitor extends NodeVisitorAbstract
{
/**
* @psalm-var list<int>
* @psalm-var array<int, int>
*/
private $executableLines = [];
/**
* @psalm-var array<int, int>
*/
private $propertyLines = [];
public function enterNode(Node $node): void
{
$this->savePropertyLines($node);
if (!$this->isExecutable($node)) {
return;
}
$this->executableLines[] = $node->getStartLine();
foreach ($this->getLines($node) as $line) {
if (isset($this->propertyLines[$line])) {
return;
}
$this->executableLines[$line] = $line;
}
}
/**
* @psalm-return list<int>
* @psalm-return array<int, int>
*/
public function executableLines(): array
{
$executableLines = array_unique($this->executableLines);
sort($this->executableLines);
sort($executableLines);
return $this->executableLines;
}
return $executableLines;
private function savePropertyLines(Node $node): void
{
if (!$node instanceof Property && !$node instanceof Node\Stmt\ClassConst) {
return;
}
foreach (range($node->getStartLine(), $node->getEndLine()) as $index) {
$this->propertyLines[$index] = $index;
}
}
/**
* @return int[]
*/
private function getLines(Node $node): array
{
if ($node instanceof Cast ||
$node instanceof PropertyFetch ||
$node instanceof NullsafePropertyFetch ||
$node instanceof StaticPropertyFetch) {
return [$node->getEndLine()];
}
if ($node instanceof ArrayDimFetch) {
if (null === $node->dim) {
return [];
}
return [$node->dim->getStartLine()];
}
if ($node instanceof MethodCall) {
return [$node->name->getStartLine()];
}
if ($node instanceof Ternary) {
$lines = [$node->cond->getStartLine()];
if (null !== $node->if) {
$lines[] = $node->if->getStartLine();
}
$lines[] = $node->else->getStartLine();
return $lines;
}
return [$node->getStartLine()];
}
private function isExecutable(Node $node): bool
{
return $node instanceof Break_ ||
return $node instanceof Assign ||
$node instanceof ArrayDimFetch ||
$node instanceof BinaryOp ||
$node instanceof Break_ ||
$node instanceof CallLike ||
$node instanceof Case_ ||
$node instanceof Cast ||
$node instanceof Catch_ ||
$node instanceof Closure ||
$node instanceof Continue_ ||
$node instanceof Do_ ||
$node instanceof Echo_ ||
$node instanceof ElseIf_ ||
$node instanceof Else_ ||
$node instanceof Encapsed ||
$node instanceof Expression ||
$node instanceof Finally_ ||
$node instanceof Foreach_ ||
$node instanceof For_ ||
$node instanceof Foreach_ ||
$node instanceof Goto_ ||
$node instanceof If_ ||
$node instanceof MethodCall ||
$node instanceof NullsafePropertyFetch ||
$node instanceof PropertyFetch ||
$node instanceof Return_ ||
$node instanceof StaticPropertyFetch ||
$node instanceof Switch_ ||
$node instanceof Ternary ||
$node instanceof Throw_ ||
$node instanceof TryCatch ||
$node instanceof Unset_ ||

View File

@@ -9,12 +9,10 @@
*/
namespace SebastianBergmann\CodeCoverage\StaticAnalysis;
use SebastianBergmann\LinesOfCode\LinesOfCode;
/**
* @internal This class is not covered by the backward compatibility promise for phpunit/php-code-coverage
*/
interface CoveredFileAnalyser
interface FileAnalyser
{
public function classesIn(string $filename): array;
@@ -22,7 +20,12 @@ interface CoveredFileAnalyser
public function functionsIn(string $filename): array;
public function linesOfCodeFor(string $filename): LinesOfCode;
/**
* @psalm-return array{linesOfCode: int, commentLinesOfCode: int, nonCommentLinesOfCode: int}
*/
public function linesOfCodeFor(string $filename): array;
public function executableLinesIn(string $filename): array;
public function ignoredLinesFor(string $filename): array;
}

View File

@@ -18,7 +18,6 @@ use PhpParser\Node\Stmt\ClassMethod;
use PhpParser\Node\Stmt\Function_;
use PhpParser\Node\Stmt\Interface_;
use PhpParser\Node\Stmt\Trait_;
use PhpParser\NodeTraverser;
use PhpParser\NodeVisitorAbstract;
/**
@@ -47,18 +46,18 @@ final class IgnoredLinesFindingVisitor extends NodeVisitorAbstract
$this->ignoreDeprecated = $ignoreDeprecated;
}
public function enterNode(Node $node): ?int
public function enterNode(Node $node): void
{
if (!$node instanceof Class_ &&
!$node instanceof Trait_ &&
!$node instanceof Interface_ &&
!$node instanceof ClassMethod &&
!$node instanceof Function_) {
return null;
return;
}
if ($node instanceof Class_ && $node->isAnonymous()) {
return null;
return;
}
// Workaround for https://bugs.xdebug.org/view.php?id=1798
@@ -69,17 +68,17 @@ final class IgnoredLinesFindingVisitor extends NodeVisitorAbstract
}
if (!$this->useAnnotationsForIgnoringCode) {
return null;
return;
}
if ($node instanceof Interface_) {
return null;
return;
}
$docComment = $node->getDocComment();
if ($docComment === null) {
return null;
return;
}
if (strpos($docComment->getText(), '@codeCoverageIgnore') !== false) {
@@ -95,12 +94,6 @@ final class IgnoredLinesFindingVisitor extends NodeVisitorAbstract
range($node->getStartLine(), $node->getEndLine())
);
}
if ($node instanceof ClassMethod || $node instanceof Function_) {
return NodeTraverser::DONT_TRAVERSE_CHILDREN;
}
return null;
}
/**

View File

@@ -25,12 +25,11 @@ use PhpParser\NodeVisitor\ParentConnectingVisitor;
use PhpParser\ParserFactory;
use SebastianBergmann\CodeCoverage\ParserException;
use SebastianBergmann\LinesOfCode\LineCountingVisitor;
use SebastianBergmann\LinesOfCode\LinesOfCode;
/**
* @internal This class is not covered by the backward compatibility promise for phpunit/php-code-coverage
*/
final class ParsingCoveredFileAnalyser implements CoveredFileAnalyser
final class ParsingFileAnalyser implements FileAnalyser
{
/**
* @var array
@@ -48,7 +47,7 @@ final class ParsingCoveredFileAnalyser implements CoveredFileAnalyser
private $functions = [];
/**
* @var LinesOfCode[]
* @var array<string,array{linesOfCode: int, commentLinesOfCode: int, nonCommentLinesOfCode: int}>
*/
private $linesOfCode = [];
@@ -57,6 +56,11 @@ final class ParsingCoveredFileAnalyser implements CoveredFileAnalyser
*/
private $ignoredLines = [];
/**
* @var array
*/
private $executableLines = [];
/**
* @var bool
*/
@@ -94,13 +98,23 @@ final class ParsingCoveredFileAnalyser implements CoveredFileAnalyser
return $this->functions[$filename];
}
public function linesOfCodeFor(string $filename): LinesOfCode
/**
* @psalm-return array{linesOfCode: int, commentLinesOfCode: int, nonCommentLinesOfCode: int}
*/
public function linesOfCodeFor(string $filename): array
{
$this->analyse($filename);
return $this->linesOfCode[$filename];
}
public function executableLinesIn(string $filename): array
{
$this->analyse($filename);
return $this->executableLines[$filename];
}
public function ignoredLinesFor(string $filename): array
{
$this->analyse($filename);
@@ -134,16 +148,18 @@ final class ParsingCoveredFileAnalyser implements CoveredFileAnalyser
assert($nodes !== null);
$traverser = new NodeTraverser;
$codeUnitFindingVisitor = new CodeUnitFindingVisitor;
$lineCountingVisitor = new LineCountingVisitor($linesOfCode);
$ignoredLinesFindingVisitor = new IgnoredLinesFindingVisitor($this->useAnnotationsForIgnoringCode, $this->ignoreDeprecatedCode);
$traverser = new NodeTraverser;
$codeUnitFindingVisitor = new CodeUnitFindingVisitor;
$lineCountingVisitor = new LineCountingVisitor($linesOfCode);
$ignoredLinesFindingVisitor = new IgnoredLinesFindingVisitor($this->useAnnotationsForIgnoringCode, $this->ignoreDeprecatedCode);
$executableLinesFindingVisitor = new ExecutableLinesFindingVisitor;
$traverser->addVisitor(new NameResolver);
$traverser->addVisitor(new ParentConnectingVisitor);
$traverser->addVisitor($codeUnitFindingVisitor);
$traverser->addVisitor($lineCountingVisitor);
$traverser->addVisitor($ignoredLinesFindingVisitor);
$traverser->addVisitor($executableLinesFindingVisitor);
/* @noinspection UnusedFunctionResultInspection */
$traverser->traverse($nodes);
@@ -161,11 +177,11 @@ final class ParsingCoveredFileAnalyser implements CoveredFileAnalyser
}
// @codeCoverageIgnoreEnd
$this->classes[$filename] = $codeUnitFindingVisitor->classes();
$this->traits[$filename] = $codeUnitFindingVisitor->traits();
$this->functions[$filename] = $codeUnitFindingVisitor->functions();
$this->linesOfCode[$filename] = $lineCountingVisitor->result();
$this->ignoredLines[$filename] = [];
$this->classes[$filename] = $codeUnitFindingVisitor->classes();
$this->traits[$filename] = $codeUnitFindingVisitor->traits();
$this->functions[$filename] = $codeUnitFindingVisitor->functions();
$this->executableLines[$filename] = $executableLinesFindingVisitor->executableLines();
$this->ignoredLines[$filename] = [];
$this->findLinesIgnoredByLineBasedAnnotations($filename, $source, $this->useAnnotationsForIgnoringCode);
@@ -177,6 +193,14 @@ final class ParsingCoveredFileAnalyser implements CoveredFileAnalyser
);
sort($this->ignoredLines[$filename]);
$result = $lineCountingVisitor->result();
$this->linesOfCode[$filename] = [
'linesOfCode' => $result->linesOfCode(),
'commentLinesOfCode' => $result->commentLinesOfCode(),
'nonCommentLinesOfCode' => $result->nonCommentLinesOfCode(),
];
}
private function findLinesIgnoredByLineBasedAnnotations(string $filename, string $source, bool $useAnnotationsForIgnoringCode): void

View File

@@ -1,51 +0,0 @@
<?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\StaticAnalysis;
use PhpParser\Error;
use PhpParser\Lexer;
use PhpParser\NodeTraverser;
use PhpParser\ParserFactory;
/**
* @internal This class is not covered by the backward compatibility promise for phpunit/php-code-coverage
*/
final class ParsingUncoveredFileAnalyser implements UncoveredFileAnalyser
{
public function executableLinesIn(string $filename): array
{
$parser = (new ParserFactory)->create(
ParserFactory::PREFER_PHP7,
new Lexer
);
try {
$nodes = $parser->parse(file_get_contents($filename));
assert($nodes !== null);
$traverser = new NodeTraverser;
$visitor = new ExecutableLinesFindingVisitor;
$traverser->addVisitor($visitor);
/* @noinspection UnusedFunctionResultInspection */
$traverser->traverse($nodes);
return $visitor->executableLines();
// @codeCoverageIgnoreStart
} catch (Error $error) {
}
// @codeCoverageIgnoreEnd
return [];
}
}

View File

@@ -1,18 +0,0 @@
<?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\StaticAnalysis;
/**
* @internal This class is not covered by the backward compatibility promise for phpunit/php-code-coverage
*/
interface UncoveredFileAnalyser
{
public function executableLinesIn(string $filename): array;
}

View File

@@ -7,7 +7,7 @@
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace SebastianBergmann\CodeCoverage;
namespace SebastianBergmann\CodeCoverage\Util;
use function is_dir;
use function mkdir;
@@ -16,12 +16,12 @@ use function sprintf;
/**
* @internal This class is not covered by the backward compatibility promise for phpunit/php-code-coverage
*/
final class Directory
final class Filesystem
{
/**
* @throws DirectoryCouldNotBeCreatedException
*/
public static function create(string $directory): void
public static function createDirectory(string $directory): void
{
$success = !(!is_dir($directory) && !@mkdir($directory, 0777, true) && !is_dir($directory));

View File

@@ -7,7 +7,7 @@
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace SebastianBergmann\CodeCoverage;
namespace SebastianBergmann\CodeCoverage\Util;
use function sprintf;

View File

@@ -22,7 +22,7 @@ final class Version
public static function id(): string
{
if (self::$version === null) {
self::$version = (new VersionId('9.2.10', dirname(__DIR__)))->getVersion();
self::$version = (new VersionId('9.2.13', dirname(__DIR__)))->getVersion();
}
return self::$version;

View File

@@ -2,6 +2,23 @@
All notable changes of the PHPUnit 8.5 release series are documented in this file using the [Keep a CHANGELOG](https://keepachangelog.com/) principles.
## [8.5.24] - 2022-MM-DD
### Changed
* [#4874](https://github.com/sebastianbergmann/phpunit/pull/4874): `PHP_FLOAT_EPSILON` is now used instead of hardcoded `0.0000000001` in `PHPUnit\Framework\Constraint\IsIdentical`
### Fixed
* When the HTML code coverage report's configured low upper bound is larger than the high lower bound then the default values are used instead
## [8.5.23] - 2022-01-21
### Fixed
* [#4799](https://github.com/sebastianbergmann/phpunit/pull/4799): Memory leaks in `PHPUnit\Framework\TestSuite` class
* [#4857](https://github.com/sebastianbergmann/phpunit/pull/4857): Result of `debug_backtrace()` is not used correctly
## [8.5.22] - 2021-12-25
### Changed
@@ -190,6 +207,8 @@ All notable changes of the PHPUnit 8.5 release series are documented in this fil
* [#3967](https://github.com/sebastianbergmann/phpunit/issues/3967): Cannot double interface that extends interface that extends `\Throwable`
* [#3968](https://github.com/sebastianbergmann/phpunit/pull/3968): Test class run in a separate PHP process are passing when `exit` called inside
[8.5.24]: https://github.com/sebastianbergmann/phpunit/compare/8.5.23...8.5
[8.5.23]: https://github.com/sebastianbergmann/phpunit/compare/8.5.22...8.5.23
[8.5.22]: https://github.com/sebastianbergmann/phpunit/compare/8.5.21...8.5.22
[8.5.21]: https://github.com/sebastianbergmann/phpunit/compare/8.5.20...8.5.21
[8.5.20]: https://github.com/sebastianbergmann/phpunit/compare/8.5.19...8.5.20

View File

@@ -2,6 +2,37 @@
All notable changes of the PHPUnit 9.5 release series are documented in this file using the [Keep a CHANGELOG](https://keepachangelog.com/) principles.
## [9.5.16] - 2022-02-23
### Changed
* Reverted sync with API change in (now yanked) phpunit/php-code-coverage 9.2.12
## [9.5.15] - 2022-02-23 [YANKED]
### Fixed
* When the HTML code coverage report's configured low upper bound is larger than the high lower bound then the default values are used instead
## [9.5.14] - 2022-02-18
### Changed
* [#4874](https://github.com/sebastianbergmann/phpunit/pull/4874): `PHP_FLOAT_EPSILON` is now used instead of hardcoded `0.0000000001` in `PHPUnit\Framework\Constraint\IsIdentical`
## [9.5.13] - 2022-01-24
### Fixed
* [#4871](https://github.com/sebastianbergmann/phpunit/issues/4871): Class `SebastianBergmann\CodeCoverage\Filter` is not found during PHPT tests when PHPUnit is used from PHAR
## [9.5.12] - 2022-01-21
### Fixed
* [#4799](https://github.com/sebastianbergmann/phpunit/pull/4799): Memory leaks in `PHPUnit\Framework\TestSuite` class
* [#4857](https://github.com/sebastianbergmann/phpunit/pull/4857): Result of `debug_backtrace()` is not used correctly
## [9.5.11] - 2021-12-25
### Changed
@@ -103,6 +134,11 @@ All notable changes of the PHPUnit 9.5 release series are documented in this fil
* [#4535](https://github.com/sebastianbergmann/phpunit/issues/4535): `getMockFromWsdl()` does not handle methods that do not have parameters correctly
[9.5.16]: https://github.com/sebastianbergmann/phpunit/compare/dc738383c519243b0a967f63943a848d3fd861aa...9.5.16
[9.5.15]: https://github.com/sebastianbergmann/phpunit/compare/9.5.14...dc738383c519243b0a967f63943a848d3fd861aa
[9.5.14]: https://github.com/sebastianbergmann/phpunit/compare/9.5.13...9.5.14
[9.5.13]: https://github.com/sebastianbergmann/phpunit/compare/9.5.12...9.5.13
[9.5.12]: https://github.com/sebastianbergmann/phpunit/compare/9.5.11...9.5.12
[9.5.11]: https://github.com/sebastianbergmann/phpunit/compare/9.5.10...9.5.11
[9.5.10]: https://github.com/sebastianbergmann/phpunit/compare/9.5.9...9.5.10
[9.5.9]: https://github.com/sebastianbergmann/phpunit/compare/9.5.8...9.5.9

View File

@@ -1,6 +1,6 @@
PHPUnit
Copyright (c) 2001-2021, Sebastian Bergmann <sebastian@phpunit.de>.
Copyright (c) 2001-2022, Sebastian Bergmann <sebastian@phpunit.de>.
All rights reserved.
Redistribution and use in source and binary forms, with or without

View File

@@ -33,7 +33,7 @@
"phar-io/manifest": "^2.0.3",
"phar-io/version": "^3.0.2",
"phpspec/prophecy": "^1.12.1",
"phpunit/php-code-coverage": "^9.2.7",
"phpunit/php-code-coverage": "^9.2.13",
"phpunit/php-file-iterator": "^3.0.5",
"phpunit/php-invoker": "^3.1.1",
"phpunit/php-text-template": "^2.0.3",

View File

@@ -179,7 +179,7 @@ abstract class Constraint implements Countable, SelfDescribing
* Returns the description of the failure when this constraint appears in
* context of an $operator expression.
*
* The purpose of this method is to provide meaningful failue description
* The purpose of this method is to provide meaningful failure description
* in context of operators such as LogicalNot. Native PHPUnit constraints
* are supported out of the box by LogicalNot, but externally developed
* ones had no way to provide correct messages in this context.

View File

@@ -9,6 +9,7 @@
*/
namespace PHPUnit\Framework\Constraint;
use const PHP_FLOAT_EPSILON;
use function abs;
use function get_class;
use function is_array;
@@ -26,11 +27,6 @@ use SebastianBergmann\Comparator\ComparisonFailure;
*/
final class IsIdentical extends Constraint
{
/**
* @var float
*/
private const EPSILON = 0.0000000001;
/**
* @var mixed
*/
@@ -59,7 +55,7 @@ final class IsIdentical extends Constraint
if (is_float($this->value) && is_float($other) &&
!is_infinite($this->value) && !is_infinite($other) &&
!is_nan($this->value) && !is_nan($other)) {
$success = abs($this->value - $other) < self::EPSILON;
$success = abs($this->value - $other) < PHP_FLOAT_EPSILON;
} else {
$success = $this->value === $other;
}

View File

@@ -21,14 +21,18 @@ final class InvalidArgumentException extends Exception
{
public static function create(int $argument, string $type): self
{
$stack = debug_backtrace();
$stack = debug_backtrace();
$function = $stack[1]['function'];
if (isset($stack[1]['class'])) {
$function = sprintf('%s::%s', $stack[1]['class'], $stack[1]['function']);
}
return new self(
sprintf(
'Argument #%d of %s::%s() must be %s %s',
'Argument #%d of %s() must be %s %s',
$argument,
$stack[1]['class'],
$stack[1]['function'],
$function,
in_array(lcfirst($type)[0], ['a', 'e', 'i', 'o', 'u'], true) ? 'an' : 'a',
$type
)

View File

@@ -12,74 +12,34 @@ namespace PHPUnit\Framework;
use Throwable;
/**
* @deprecated Use the `TestHook` interfaces instead
* This interface, as well as the associated mechanism for extending PHPUnit,
* will be removed in PHPUnit 10. There is no alternative available in this
* version of PHPUnit.
*
* @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit
*
* @deprecated
* @see https://github.com/sebastianbergmann/phpunit/issues/4676
*/
interface TestListener
{
/**
* An error occurred.
*
* @deprecated Use `AfterTestErrorHook::executeAfterTestError` instead
*/
public function addError(Test $test, Throwable $t, float $time): void;
/**
* A warning occurred.
*
* @deprecated Use `AfterTestWarningHook::executeAfterTestWarning` instead
*/
public function addWarning(Test $test, Warning $e, float $time): void;
/**
* A failure occurred.
*
* @deprecated Use `AfterTestFailureHook::executeAfterTestFailure` instead
*/
public function addFailure(Test $test, AssertionFailedError $e, float $time): void;
/**
* Incomplete test.
*
* @deprecated Use `AfterIncompleteTestHook::executeAfterIncompleteTest` instead
*/
public function addIncompleteTest(Test $test, Throwable $t, float $time): void;
/**
* Risky test.
*
* @deprecated Use `AfterRiskyTestHook::executeAfterRiskyTest` instead
*/
public function addRiskyTest(Test $test, Throwable $t, float $time): void;
/**
* Skipped test.
*
* @deprecated Use `AfterSkippedTestHook::executeAfterSkippedTest` instead
*/
public function addSkippedTest(Test $test, Throwable $t, float $time): void;
/**
* A test suite started.
*/
public function startTestSuite(TestSuite $suite): void;
/**
* A test suite ended.
*/
public function endTestSuite(TestSuite $suite): void;
/**
* A test started.
*
* @deprecated Use `BeforeTestHook::executeBeforeTest` instead
*/
public function startTest(Test $test): void;
/**
* A test ended.
*
* @deprecated Use `AfterTestHook::executeAfterTest` instead
*/
public function endTest(Test $test, float $time): void;
}

View File

@@ -755,8 +755,8 @@ final class TestResult implements Countable
sprintf(
'%s in %s:%s',
$e->getMessage(),
$frame['file'],
$frame['line']
$frame['file'] ?? $e->getFile(),
$frame['line'] ?? $e->getLine()
)
);
} catch (Warning $e) {

View File

@@ -10,7 +10,6 @@
namespace PHPUnit\Framework;
use const PHP_EOL;
use function array_diff;
use function array_keys;
use function array_map;
use function array_merge;
@@ -128,9 +127,9 @@ class TestSuite implements IteratorAggregate, Reorderable, SelfDescribing, Test
private $iteratorFilter;
/**
* @var string[]
* @var int
*/
private $declaredClasses;
private $declaredClassesPointer;
/**
* @psalm-var array<int,string>
@@ -167,7 +166,7 @@ class TestSuite implements IteratorAggregate, Reorderable, SelfDescribing, Test
);
}
$this->declaredClasses = get_declared_classes();
$this->declaredClassesPointer = count(get_declared_classes());
if (!$theClass instanceof ReflectionClass) {
if (class_exists($theClass, true)) {
@@ -390,7 +389,7 @@ class TestSuite implements IteratorAggregate, Reorderable, SelfDescribing, Test
if (is_file($filename) && substr($filename, -5) === '.phpt') {
$this->addTest(new PhptTestCase($filename));
$this->declaredClasses = get_declared_classes();
$this->declaredClassesPointer = count(get_declared_classes());
return;
}
@@ -400,7 +399,7 @@ class TestSuite implements IteratorAggregate, Reorderable, SelfDescribing, Test
// The given file may contain further stub classes in addition to the
// test class itself. Figure out the actual test class.
$filename = FileLoader::checkAndLoad($filename);
$newClasses = array_diff(get_declared_classes(), $this->declaredClasses);
$newClasses = array_slice(get_declared_classes(), $this->declaredClassesPointer);
// The diff is empty in case a parent class (with test methods) is added
// AFTER a child class that inherited from it. To account for that case,
@@ -410,8 +409,8 @@ class TestSuite implements IteratorAggregate, Reorderable, SelfDescribing, Test
// On the assumption that test classes are defined first in files,
// process discovered classes in approximate LIFO order, so as to
// avoid unnecessary reflection.
$this->foundClasses = array_merge($newClasses, $this->foundClasses);
$this->declaredClasses = get_declared_classes();
$this->foundClasses = array_merge($newClasses, $this->foundClasses);
$this->declaredClassesPointer = count(get_declared_classes());
}
// The test class's name must match the filename, either in full, or as

View File

@@ -10,7 +10,13 @@
namespace PHPUnit\Runner;
/**
* This interface, as well as the associated mechanism for extending PHPUnit,
* will be removed in PHPUnit 10. There is no alternative available in this
* version of PHPUnit.
*
* @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit
*
* @see https://github.com/sebastianbergmann/phpunit/issues/4676
*/
interface AfterIncompleteTestHook extends TestHook
{

View File

@@ -10,7 +10,13 @@
namespace PHPUnit\Runner;
/**
* This interface, as well as the associated mechanism for extending PHPUnit,
* will be removed in PHPUnit 10. There is no alternative available in this
* version of PHPUnit.
*
* @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit
*
* @see https://github.com/sebastianbergmann/phpunit/issues/4676
*/
interface AfterLastTestHook extends Hook
{

View File

@@ -10,7 +10,13 @@
namespace PHPUnit\Runner;
/**
* This interface, as well as the associated mechanism for extending PHPUnit,
* will be removed in PHPUnit 10. There is no alternative available in this
* version of PHPUnit.
*
* @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit
*
* @see https://github.com/sebastianbergmann/phpunit/issues/4676
*/
interface AfterRiskyTestHook extends TestHook
{

View File

@@ -10,7 +10,13 @@
namespace PHPUnit\Runner;
/**
* This interface, as well as the associated mechanism for extending PHPUnit,
* will be removed in PHPUnit 10. There is no alternative available in this
* version of PHPUnit.
*
* @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit
*
* @see https://github.com/sebastianbergmann/phpunit/issues/4676
*/
interface AfterSkippedTestHook extends TestHook
{

View File

@@ -10,7 +10,13 @@
namespace PHPUnit\Runner;
/**
* This interface, as well as the associated mechanism for extending PHPUnit,
* will be removed in PHPUnit 10. There is no alternative available in this
* version of PHPUnit.
*
* @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit
*
* @see https://github.com/sebastianbergmann/phpunit/issues/4676
*/
interface AfterSuccessfulTestHook extends TestHook
{

View File

@@ -10,7 +10,13 @@
namespace PHPUnit\Runner;
/**
* This interface, as well as the associated mechanism for extending PHPUnit,
* will be removed in PHPUnit 10. There is no alternative available in this
* version of PHPUnit.
*
* @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit
*
* @see https://github.com/sebastianbergmann/phpunit/issues/4676
*/
interface AfterTestErrorHook extends TestHook
{

View File

@@ -10,7 +10,13 @@
namespace PHPUnit\Runner;
/**
* This interface, as well as the associated mechanism for extending PHPUnit,
* will be removed in PHPUnit 10. There is no alternative available in this
* version of PHPUnit.
*
* @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit
*
* @see https://github.com/sebastianbergmann/phpunit/issues/4676
*/
interface AfterTestFailureHook extends TestHook
{

View File

@@ -10,7 +10,13 @@
namespace PHPUnit\Runner;
/**
* This interface, as well as the associated mechanism for extending PHPUnit,
* will be removed in PHPUnit 10. There is no alternative available in this
* version of PHPUnit.
*
* @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit
*
* @see https://github.com/sebastianbergmann/phpunit/issues/4676
*/
interface AfterTestHook extends TestHook
{

View File

@@ -10,7 +10,13 @@
namespace PHPUnit\Runner;
/**
* This interface, as well as the associated mechanism for extending PHPUnit,
* will be removed in PHPUnit 10. There is no alternative available in this
* version of PHPUnit.
*
* @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit
*
* @see https://github.com/sebastianbergmann/phpunit/issues/4676
*/
interface AfterTestWarningHook extends TestHook
{

View File

@@ -10,7 +10,13 @@
namespace PHPUnit\Runner;
/**
* This interface, as well as the associated mechanism for extending PHPUnit,
* will be removed in PHPUnit 10. There is no alternative available in this
* version of PHPUnit.
*
* @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit
*
* @see https://github.com/sebastianbergmann/phpunit/issues/4676
*/
interface BeforeFirstTestHook extends Hook
{

View File

@@ -10,7 +10,13 @@
namespace PHPUnit\Runner;
/**
* This interface, as well as the associated mechanism for extending PHPUnit,
* will be removed in PHPUnit 10. There is no alternative available in this
* version of PHPUnit.
*
* @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit
*
* @see https://github.com/sebastianbergmann/phpunit/issues/4676
*/
interface BeforeTestHook extends TestHook
{

View File

@@ -10,7 +10,13 @@
namespace PHPUnit\Runner;
/**
* This interface, as well as the associated mechanism for extending PHPUnit,
* will be removed in PHPUnit 10. There is no alternative available in this
* version of PHPUnit.
*
* @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit
*
* @see https://github.com/sebastianbergmann/phpunit/issues/4676
*/
interface Hook
{

View File

@@ -10,7 +10,13 @@
namespace PHPUnit\Runner;
/**
* This interface, as well as the associated mechanism for extending PHPUnit,
* will be removed in PHPUnit 10. There is no alternative available in this
* version of PHPUnit.
*
* @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit
*
* @see https://github.com/sebastianbergmann/phpunit/issues/4676
*/
interface TestHook extends Hook
{

View File

@@ -41,7 +41,7 @@ final class Version
}
if (self::$version === '') {
self::$version = (new VersionId('9.5.11', dirname(__DIR__, 2)))->getVersion();
self::$version = (new VersionId('9.5.16', dirname(__DIR__, 2)))->getVersion();
}
return self::$version;

View File

@@ -93,11 +93,6 @@ final class TestRunner extends BaseTestRunner
public const EXCEPTION_EXIT = 2;
/**
* @var bool
*/
private static $versionStringPrinted = false;
/**
* @var CodeCoverageFilter
*/
@@ -334,8 +329,6 @@ final class TestRunner extends BaseTestRunner
Version::getVersionString() . "\n"
);
self::$versionStringPrinted = true;
foreach ($arguments['listeners'] as $listener) {
$result->addListener($listener);
}
@@ -1142,6 +1135,11 @@ final class TestRunner extends BaseTestRunner
$arguments['timeoutForMediumTests'] = $arguments['timeoutForMediumTests'] ?? 10;
$arguments['timeoutForSmallTests'] = $arguments['timeoutForSmallTests'] ?? 1;
$arguments['verbose'] = $arguments['verbose'] ?? false;
if ($arguments['reportLowUpperBound'] > $arguments['reportHighLowerBound']) {
$arguments['reportLowUpperBound'] = 50;
$arguments['reportHighLowerBound'] = 90;
}
}
private function processSuiteFilters(TestSuite $suite, array $arguments): void