One Hat Cyber Team
Your IP:
216.73.216.30
Server IP:
198.54.114.155
Server:
Linux server71.web-hosting.com 4.18.0-513.18.1.lve.el8.x86_64 #1 SMP Thu Feb 22 12:55:50 UTC 2024 x86_64
Server Software:
LiteSpeed
PHP Version:
5.6.40
Create File
|
Create Folder
Execute
Dir :
~
/
proc
/
self
/
root
/
proc
/
thread-self
/
cwd
/
Edit File:
Runner.tar
TestSuiteLoader.php 0000644 00000007412 15111200074 0010330 0 ustar 00 <?php declare(strict_types=1); /* * This file is part of PHPUnit. * * (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 PHPUnit\Runner; use function array_diff; use function array_values; use function basename; use function class_exists; use function get_declared_classes; use function realpath; use function str_ends_with; use function strpos; use function strtolower; use function substr; use PHPUnit\Framework\TestCase; use ReflectionClass; /** * @internal This class is not covered by the backward compatibility promise for PHPUnit */ final class TestSuiteLoader { /** * @psalm-var list<class-string> */ private static array $declaredClasses = []; /** * @psalm-var array<non-empty-string, list<class-string>> */ private static array $fileToClassesMap = []; /** * @throws Exception */ public function load(string $suiteClassFile): ReflectionClass { $suiteClassFile = realpath($suiteClassFile); $suiteClassName = $this->classNameFromFileName($suiteClassFile); $loadedClasses = $this->loadSuiteClassFile($suiteClassFile); foreach ($loadedClasses as $className) { /** @noinspection PhpUnhandledExceptionInspection */ $class = new ReflectionClass($className); if ($class->isAnonymous()) { continue; } if ($class->getFileName() !== $suiteClassFile) { continue; } if (!$class->isSubclassOf(TestCase::class)) { continue; } if (!str_ends_with(strtolower($class->getShortName()), strtolower($suiteClassName))) { continue; } if (!$class->isAbstract()) { return $class; } $e = new ClassIsAbstractException($class->getName(), $suiteClassFile); } if (isset($e)) { throw $e; } if (!class_exists($suiteClassName)) { throw new ClassCannotBeFoundException($suiteClassName, $suiteClassFile); } throw new ClassDoesNotExtendTestCaseException($suiteClassName, $suiteClassFile); } private function classNameFromFileName(string $suiteClassFile): string { $className = basename($suiteClassFile, '.php'); $dotPos = strpos($className, '.'); if ($dotPos !== false) { $className = substr($className, 0, $dotPos); } return $className; } /** * @psalm-return list<class-string> */ private function loadSuiteClassFile(string $suiteClassFile): array { if (isset(self::$fileToClassesMap[$suiteClassFile])) { return self::$fileToClassesMap[$suiteClassFile]; } if (empty(self::$declaredClasses)) { self::$declaredClasses = get_declared_classes(); } require_once $suiteClassFile; $loadedClasses = array_values( array_diff( get_declared_classes(), self::$declaredClasses, ), ); foreach ($loadedClasses as $loadedClass) { /** @noinspection PhpUnhandledExceptionInspection */ $class = new ReflectionClass($loadedClass); if (!isset(self::$fileToClassesMap[$class->getFileName()])) { self::$fileToClassesMap[$class->getFileName()] = []; } self::$fileToClassesMap[$class->getFileName()][] = $class->getName(); } self::$declaredClasses = get_declared_classes(); if (empty($loadedClasses)) { return self::$declaredClasses; } return $loadedClasses; } } Filter/TestIdFilterIterator.php 0000644 00000003300 15111200075 0012542 0 ustar 00 <?php declare(strict_types=1); /* * This file is part of PHPUnit. * * (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 PHPUnit\Runner\Filter; use function in_array; use PHPUnit\Event\TestData\MoreThanOneDataSetFromDataProviderException; use PHPUnit\Event\TestData\NoDataSetFromDataProviderException; use PHPUnit\Framework\Test; use PHPUnit\Framework\TestCase; use PHPUnit\Framework\TestSuite; use PHPUnit\Runner\PhptTestCase; use RecursiveFilterIterator; use RecursiveIterator; /** * @internal This class is not covered by the backward compatibility promise for PHPUnit */ final class TestIdFilterIterator extends RecursiveFilterIterator { /** * @psalm-var non-empty-list<non-empty-string> */ private readonly array $testIds; /** * @psalm-param RecursiveIterator<int, Test> $iterator * @psalm-param non-empty-list<non-empty-string> $testIds */ public function __construct(RecursiveIterator $iterator, array $testIds) { parent::__construct($iterator); $this->testIds = $testIds; } public function accept(): bool { $test = $this->getInnerIterator()->current(); if ($test instanceof TestSuite) { return true; } if (!$test instanceof TestCase && !$test instanceof PhptTestCase) { return false; } try { return in_array($test->valueObjectForEvents()->id(), $this->testIds, true); } catch (MoreThanOneDataSetFromDataProviderException|NoDataSetFromDataProviderException) { return false; } } } Filter/GroupFilterIterator.php 0000644 00000003166 15111200075 0012454 0 ustar 00 <?php declare(strict_types=1); /* * This file is part of PHPUnit. * * (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 PHPUnit\Runner\Filter; use function array_map; use function array_push; use function in_array; use function spl_object_id; use PHPUnit\Framework\Test; use PHPUnit\Framework\TestSuite; use RecursiveFilterIterator; use RecursiveIterator; /** * @internal This class is not covered by the backward compatibility promise for PHPUnit */ abstract class GroupFilterIterator extends RecursiveFilterIterator { /** * @psalm-var list<int> */ protected array $groupTests = []; /** * @psalm-param RecursiveIterator<int, Test> $iterator * @psalm-param list<non-empty-string> $groups */ public function __construct(RecursiveIterator $iterator, array $groups, TestSuite $suite) { parent::__construct($iterator); foreach ($suite->groupDetails() as $group => $tests) { if (in_array((string) $group, $groups, true)) { $testHashes = array_map( 'spl_object_id', $tests, ); array_push($this->groupTests, ...$testHashes); } } } public function accept(): bool { $test = $this->getInnerIterator()->current(); if ($test instanceof TestSuite) { return true; } return $this->doAccept(spl_object_id($test)); } abstract protected function doAccept(int $id): bool; } Filter/Factory.php 0000644 00000003726 15111200075 0010111 0 ustar 00 <?php declare(strict_types=1); /* * This file is part of PHPUnit. * * (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 PHPUnit\Runner\Filter; use function assert; use FilterIterator; use Iterator; use PHPUnit\Framework\TestSuite; use ReflectionClass; /** * @internal This class is not covered by the backward compatibility promise for PHPUnit */ final class Factory { /** * @psalm-var array<int,array{0: ReflectionClass, 1: array|string}> */ private array $filters = []; /** * @psalm-param list<non-empty-string> $testIds */ public function addTestIdFilter(array $testIds): void { $this->filters[] = [ new ReflectionClass(TestIdFilterIterator::class), $testIds, ]; } /** * @psalm-param list<non-empty-string> $groups */ public function addExcludeGroupFilter(array $groups): void { $this->filters[] = [ new ReflectionClass(ExcludeGroupFilterIterator::class), $groups, ]; } /** * @psalm-param list<non-empty-string> $groups */ public function addIncludeGroupFilter(array $groups): void { $this->filters[] = [ new ReflectionClass(IncludeGroupFilterIterator::class), $groups, ]; } /** * @psalm-param non-empty-string $name */ public function addNameFilter(string $name): void { $this->filters[] = [ new ReflectionClass(NameFilterIterator::class), $name, ]; } public function factory(Iterator $iterator, TestSuite $suite): FilterIterator { foreach ($this->filters as $filter) { [$class, $arguments] = $filter; $iterator = $class->newInstance($iterator, $arguments, $suite); } assert($iterator instanceof FilterIterator); return $iterator; } } Filter/NameFilterIterator.php 0000644 00000007427 15111200075 0012244 0 ustar 00 <?php declare(strict_types=1); /* * This file is part of PHPUnit. * * (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 PHPUnit\Runner\Filter; use function end; use function implode; use function preg_match; use function sprintf; use function str_replace; use Exception; use PHPUnit\Framework\SelfDescribing; use PHPUnit\Framework\Test; use PHPUnit\Framework\TestCase; use PHPUnit\Framework\TestSuite; use RecursiveFilterIterator; use RecursiveIterator; /** * @internal This class is not covered by the backward compatibility promise for PHPUnit */ final class NameFilterIterator extends RecursiveFilterIterator { private ?string $filter = null; private ?int $filterMin = null; private ?int $filterMax = null; /** * @psalm-param RecursiveIterator<int, Test> $iterator * @psalm-param non-empty-string $filter * * @throws Exception */ public function __construct(RecursiveIterator $iterator, string $filter) { parent::__construct($iterator); $this->setFilter($filter); } public function accept(): bool { $test = $this->getInnerIterator()->current(); if ($test instanceof TestSuite) { return true; } $tmp = $this->describe($test); if ($tmp[0] !== '') { $name = implode('::', $tmp); } else { $name = $tmp[1]; } $accepted = @preg_match($this->filter, $name, $matches); if ($accepted && isset($this->filterMax)) { $set = end($matches); $accepted = $set >= $this->filterMin && $set <= $this->filterMax; } return (bool) $accepted; } /** * @throws Exception */ private function setFilter(string $filter): void { if (@preg_match($filter, '') === false) { // Handles: // * testAssertEqualsSucceeds#4 // * testAssertEqualsSucceeds#4-8 if (preg_match('/^(.*?)#(\d+)(?:-(\d+))?$/', $filter, $matches)) { if (isset($matches[3]) && $matches[2] < $matches[3]) { $filter = sprintf( '%s.*with data set #(\d+)$', $matches[1], ); $this->filterMin = (int) $matches[2]; $this->filterMax = (int) $matches[3]; } else { $filter = sprintf( '%s.*with data set #%s$', $matches[1], $matches[2], ); } } // Handles: // * testDetermineJsonError@JSON_ERROR_NONE // * testDetermineJsonError@JSON.* elseif (preg_match('/^(.*?)@(.+)$/', $filter, $matches)) { $filter = sprintf( '%s.*with data set "%s"$', $matches[1], $matches[2], ); } // Escape delimiters in regular expression. Do NOT use preg_quote, // to keep magic characters. $filter = sprintf( '/%s/i', str_replace( '/', '\\/', $filter, ), ); } $this->filter = $filter; } /** * @psalm-return array{0: string, 1: string} */ private function describe(Test $test): array { if ($test instanceof TestCase) { return [$test::class, $test->nameWithDataSet()]; } if ($test instanceof SelfDescribing) { return ['', $test->toString()]; } return ['', $test::class]; } } Filter/ExcludeGroupFilterIterator.php 0000644 00000001122 15111200075 0013754 0 ustar 00 <?php declare(strict_types=1); /* * This file is part of PHPUnit. * * (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 PHPUnit\Runner\Filter; use function in_array; /** * @internal This class is not covered by the backward compatibility promise for PHPUnit */ final class ExcludeGroupFilterIterator extends GroupFilterIterator { protected function doAccept(int $id): bool { return !in_array($id, $this->groupTests, true); } } Filter/IncludeGroupFilterIterator.php 0000644 00000001121 15111200075 0013745 0 ustar 00 <?php declare(strict_types=1); /* * This file is part of PHPUnit. * * (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 PHPUnit\Runner\Filter; use function in_array; /** * @internal This class is not covered by the backward compatibility promise for PHPUnit */ final class IncludeGroupFilterIterator extends GroupFilterIterator { protected function doAccept(int $id): bool { return in_array($id, $this->groupTests, true); } } TestSuiteSorter.php 0000644 00000023311 15111200075 0010375 0 ustar 00 <?php declare(strict_types=1); /* * This file is part of PHPUnit. * * (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 PHPUnit\Runner; use function array_diff; use function array_merge; use function array_reverse; use function array_splice; use function count; use function in_array; use function max; use function shuffle; use function usort; use PHPUnit\Framework\DataProviderTestSuite; use PHPUnit\Framework\Reorderable; use PHPUnit\Framework\Test; use PHPUnit\Framework\TestCase; use PHPUnit\Framework\TestSuite; use PHPUnit\Runner\ResultCache\NullResultCache; use PHPUnit\Runner\ResultCache\ResultCache; /** * @internal This class is not covered by the backward compatibility promise for PHPUnit */ final class TestSuiteSorter { /** * @var int */ public const ORDER_DEFAULT = 0; /** * @var int */ public const ORDER_RANDOMIZED = 1; /** * @var int */ public const ORDER_REVERSED = 2; /** * @var int */ public const ORDER_DEFECTS_FIRST = 3; /** * @var int */ public const ORDER_DURATION = 4; /** * @var int */ public const ORDER_SIZE = 5; private const SIZE_SORT_WEIGHT = [ 'small' => 1, 'medium' => 2, 'large' => 3, 'unknown' => 4, ]; /** * @psalm-var array<string, int> Associative array of (string => DEFECT_SORT_WEIGHT) elements */ private array $defectSortOrder = []; private readonly ResultCache $cache; /** * @psalm-var array<string> A list of normalized names of tests before reordering */ private array $originalExecutionOrder = []; /** * @psalm-var array<string> A list of normalized names of tests affected by reordering */ private array $executionOrder = []; public function __construct(?ResultCache $cache = null) { $this->cache = $cache ?? new NullResultCache; } /** * @throws Exception */ public function reorderTestsInSuite(Test $suite, int $order, bool $resolveDependencies, int $orderDefects, bool $isRootTestSuite = true): void { $allowedOrders = [ self::ORDER_DEFAULT, self::ORDER_REVERSED, self::ORDER_RANDOMIZED, self::ORDER_DURATION, self::ORDER_SIZE, ]; if (!in_array($order, $allowedOrders, true)) { throw new InvalidOrderException; } $allowedOrderDefects = [ self::ORDER_DEFAULT, self::ORDER_DEFECTS_FIRST, ]; if (!in_array($orderDefects, $allowedOrderDefects, true)) { throw new InvalidOrderException; } if ($isRootTestSuite) { $this->originalExecutionOrder = $this->calculateTestExecutionOrder($suite); } if ($suite instanceof TestSuite) { foreach ($suite as $_suite) { $this->reorderTestsInSuite($_suite, $order, $resolveDependencies, $orderDefects, false); } if ($orderDefects === self::ORDER_DEFECTS_FIRST) { $this->addSuiteToDefectSortOrder($suite); } $this->sort($suite, $order, $resolveDependencies, $orderDefects); } if ($isRootTestSuite) { $this->executionOrder = $this->calculateTestExecutionOrder($suite); } } public function getOriginalExecutionOrder(): array { return $this->originalExecutionOrder; } public function getExecutionOrder(): array { return $this->executionOrder; } private function sort(TestSuite $suite, int $order, bool $resolveDependencies, int $orderDefects): void { if (empty($suite->tests())) { return; } if ($order === self::ORDER_REVERSED) { $suite->setTests($this->reverse($suite->tests())); } elseif ($order === self::ORDER_RANDOMIZED) { $suite->setTests($this->randomize($suite->tests())); } elseif ($order === self::ORDER_DURATION) { $suite->setTests($this->sortByDuration($suite->tests())); } elseif ($order === self::ORDER_SIZE) { $suite->setTests($this->sortBySize($suite->tests())); } if ($orderDefects === self::ORDER_DEFECTS_FIRST) { $suite->setTests($this->sortDefectsFirst($suite->tests())); } if ($resolveDependencies && !($suite instanceof DataProviderTestSuite)) { $tests = $suite->tests(); $suite->setTests($this->resolveDependencies($tests)); } } private function addSuiteToDefectSortOrder(TestSuite $suite): void { $max = 0; foreach ($suite->tests() as $test) { if (!$test instanceof Reorderable) { continue; } if (!isset($this->defectSortOrder[$test->sortId()])) { $this->defectSortOrder[$test->sortId()] = $this->cache->status($test->sortId())->asInt(); $max = max($max, $this->defectSortOrder[$test->sortId()]); } } $this->defectSortOrder[$suite->sortId()] = $max; } private function reverse(array $tests): array { return array_reverse($tests); } private function randomize(array $tests): array { shuffle($tests); return $tests; } private function sortDefectsFirst(array $tests): array { usort( $tests, fn ($left, $right) => $this->cmpDefectPriorityAndTime($left, $right), ); return $tests; } private function sortByDuration(array $tests): array { usort( $tests, fn ($left, $right) => $this->cmpDuration($left, $right), ); return $tests; } private function sortBySize(array $tests): array { usort( $tests, fn ($left, $right) => $this->cmpSize($left, $right), ); return $tests; } /** * Comparator callback function to sort tests for "reach failure as fast as possible". * * 1. sort tests by defect weight defined in self::DEFECT_SORT_WEIGHT * 2. when tests are equally defective, sort the fastest to the front * 3. do not reorder successful tests */ private function cmpDefectPriorityAndTime(Test $a, Test $b): int { if (!($a instanceof Reorderable && $b instanceof Reorderable)) { return 0; } $priorityA = $this->defectSortOrder[$a->sortId()] ?? 0; $priorityB = $this->defectSortOrder[$b->sortId()] ?? 0; if ($priorityB <=> $priorityA) { // Sort defect weight descending return $priorityB <=> $priorityA; } if ($priorityA || $priorityB) { return $this->cmpDuration($a, $b); } // do not change execution order return 0; } /** * Compares test duration for sorting tests by duration ascending. */ private function cmpDuration(Test $a, Test $b): int { if (!($a instanceof Reorderable && $b instanceof Reorderable)) { return 0; } return $this->cache->time($a->sortId()) <=> $this->cache->time($b->sortId()); } /** * Compares test size for sorting tests small->medium->large->unknown. */ private function cmpSize(Test $a, Test $b): int { $sizeA = ($a instanceof TestCase || $a instanceof DataProviderTestSuite) ? $a->size()->asString() : 'unknown'; $sizeB = ($b instanceof TestCase || $b instanceof DataProviderTestSuite) ? $b->size()->asString() : 'unknown'; return self::SIZE_SORT_WEIGHT[$sizeA] <=> self::SIZE_SORT_WEIGHT[$sizeB]; } /** * Reorder Tests within a TestCase in such a way as to resolve as many dependencies as possible. * The algorithm will leave the tests in original running order when it can. * For more details see the documentation for test dependencies. * * Short description of algorithm: * 1. Pick the next Test from remaining tests to be checked for dependencies. * 2. If the test has no dependencies: mark done, start again from the top * 3. If the test has dependencies but none left to do: mark done, start again from the top * 4. When we reach the end add any leftover tests to the end. These will be marked 'skipped' during execution. * * @psalm-param array<DataProviderTestSuite|TestCase> $tests * * @psalm-return array<DataProviderTestSuite|TestCase> */ private function resolveDependencies(array $tests): array { $newTestOrder = []; $i = 0; $provided = []; do { if ([] === array_diff($tests[$i]->requires(), $provided)) { $provided = array_merge($provided, $tests[$i]->provides()); $newTestOrder = array_merge($newTestOrder, array_splice($tests, $i, 1)); $i = 0; } else { $i++; } } while (!empty($tests) && ($i < count($tests))); return array_merge($newTestOrder, $tests); } private function calculateTestExecutionOrder(Test $suite): array { $tests = []; if ($suite instanceof TestSuite) { foreach ($suite->tests() as $test) { if (!$test instanceof TestSuite && $test instanceof Reorderable) { $tests[] = $test->sortId(); } else { $tests = array_merge($tests, $this->calculateTestExecutionOrder($test)); } } } return $tests; } } PhptTestCase.php 0000644 00000056205 15111200075 0007624 0 ustar 00 <?php declare(strict_types=1); /* * This file is part of PHPUnit. * * (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 PHPUnit\Runner; use const DEBUG_BACKTRACE_IGNORE_ARGS; use const DIRECTORY_SEPARATOR; use function array_merge; use function basename; use function debug_backtrace; use function defined; use function dirname; use function explode; use function extension_loaded; use function file; use function file_get_contents; use function file_put_contents; use function is_array; use function is_file; use function is_readable; use function is_string; use function ltrim; use function preg_match; use function preg_replace; use function preg_split; use function realpath; use function rtrim; use function str_contains; use function str_replace; use function str_starts_with; use function strncasecmp; use function substr; use function trim; use function unlink; use function unserialize; use function var_export; use PHPUnit\Event\Code\Phpt; use PHPUnit\Event\Code\ThrowableBuilder; use PHPUnit\Event\Facade as EventFacade; use PHPUnit\Event\NoPreviousThrowableException; use PHPUnit\Framework\Assert; use PHPUnit\Framework\AssertionFailedError; use PHPUnit\Framework\ExecutionOrderDependency; use PHPUnit\Framework\ExpectationFailedException; use PHPUnit\Framework\IncompleteTestError; use PHPUnit\Framework\PhptAssertionFailedError; use PHPUnit\Framework\Reorderable; use PHPUnit\Framework\SelfDescribing; use PHPUnit\Framework\Test; use PHPUnit\TextUI\Configuration\Registry as ConfigurationRegistry; use PHPUnit\Util\PHP\AbstractPhpProcess; use SebastianBergmann\CodeCoverage\Data\RawCodeCoverageData; use SebastianBergmann\CodeCoverage\InvalidArgumentException; use SebastianBergmann\CodeCoverage\StaticAnalysisCacheNotConfiguredException; use SebastianBergmann\CodeCoverage\Test\TestSize\TestSize; use SebastianBergmann\CodeCoverage\Test\TestStatus\TestStatus; use SebastianBergmann\CodeCoverage\TestIdMissingException; use SebastianBergmann\CodeCoverage\UnintentionallyCoveredCodeException; use SebastianBergmann\Template\Template; use Throwable; /** * @internal This class is not covered by the backward compatibility promise for PHPUnit */ final class PhptTestCase implements Reorderable, SelfDescribing, Test { /** * @psalm-var non-empty-string */ private readonly string $filename; private readonly AbstractPhpProcess $phpUtil; private string $output = ''; /** * Constructs a test case with the given filename. * * @psalm-param non-empty-string $filename * * @throws Exception */ public function __construct(string $filename, AbstractPhpProcess $phpUtil = null) { if (!is_file($filename)) { throw new FileDoesNotExistException($filename); } $this->filename = $filename; $this->phpUtil = $phpUtil ?: AbstractPhpProcess::factory(); } /** * Counts the number of test cases executed by run(TestResult result). */ public function count(): int { return 1; } /** * Runs a test and collects its result in a TestResult instance. * * @throws \PHPUnit\Framework\Exception * @throws \SebastianBergmann\CodeCoverage\ReflectionException * @throws \SebastianBergmann\Template\InvalidArgumentException * @throws Exception * @throws InvalidArgumentException * @throws NoPreviousThrowableException * @throws StaticAnalysisCacheNotConfiguredException * @throws TestIdMissingException * @throws UnintentionallyCoveredCodeException * * @noinspection RepetitiveMethodCallsInspection */ public function run(): void { $emitter = EventFacade::emitter(); $emitter->testPreparationStarted( $this->valueObjectForEvents(), ); try { $sections = $this->parse(); } catch (Exception $e) { $emitter->testPrepared($this->valueObjectForEvents()); $emitter->testErrored($this->valueObjectForEvents(), ThrowableBuilder::from($e)); $emitter->testFinished($this->valueObjectForEvents(), 0); return; } $code = $this->render($sections['FILE']); $xfail = false; $settings = $this->parseIniSection($this->settings(CodeCoverage::instance()->isActive())); $emitter->testPrepared($this->valueObjectForEvents()); if (isset($sections['INI'])) { $settings = $this->parseIniSection($sections['INI'], $settings); } if (isset($sections['ENV'])) { $env = $this->parseEnvSection($sections['ENV']); $this->phpUtil->setEnv($env); } $this->phpUtil->setUseStderrRedirection(true); if ($this->shouldTestBeSkipped($sections, $settings)) { return; } if (isset($sections['XFAIL'])) { $xfail = trim($sections['XFAIL']); } if (isset($sections['STDIN'])) { $this->phpUtil->setStdin($sections['STDIN']); } if (isset($sections['ARGS'])) { $this->phpUtil->setArgs($sections['ARGS']); } if (CodeCoverage::instance()->isActive()) { $codeCoverageCacheDirectory = null; if (CodeCoverage::instance()->codeCoverage()->cachesStaticAnalysis()) { $codeCoverageCacheDirectory = CodeCoverage::instance()->codeCoverage()->cacheDirectory(); } $this->renderForCoverage( $code, CodeCoverage::instance()->codeCoverage()->collectsBranchAndPathCoverage(), $codeCoverageCacheDirectory, ); } $jobResult = $this->phpUtil->runJob($code, $this->stringifyIni($settings)); $this->output = $jobResult['stdout'] ?? ''; if (CodeCoverage::instance()->isActive() && ($coverage = $this->cleanupForCoverage())) { CodeCoverage::instance()->codeCoverage()->start($this->filename, TestSize::large()); CodeCoverage::instance()->codeCoverage()->append( $coverage, $this->filename, true, TestStatus::unknown(), [], [], ); } try { $this->assertPhptExpectation($sections, $this->output); } catch (AssertionFailedError $e) { $failure = $e; if ($xfail !== false) { $failure = new IncompleteTestError($xfail, 0, $e); } elseif ($e instanceof ExpectationFailedException) { $comparisonFailure = $e->getComparisonFailure(); if ($comparisonFailure) { $diff = $comparisonFailure->getDiff(); } else { $diff = $e->getMessage(); } $hint = $this->getLocationHintFromDiff($diff, $sections); $trace = array_merge($hint, debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS)); $failure = new PhptAssertionFailedError( $e->getMessage(), 0, $trace[0]['file'], $trace[0]['line'], $trace, $comparisonFailure ? $diff : '', ); } if ($failure instanceof IncompleteTestError) { $emitter->testMarkedAsIncomplete($this->valueObjectForEvents(), ThrowableBuilder::from($failure)); } else { $emitter->testFailed($this->valueObjectForEvents(), ThrowableBuilder::from($failure), null); } } catch (Throwable $t) { $emitter->testErrored($this->valueObjectForEvents(), ThrowableBuilder::from($t)); } $this->runClean($sections, CodeCoverage::instance()->isActive()); $emitter->testFinished($this->valueObjectForEvents(), 1); } /** * Returns the name of the test case. */ public function getName(): string { return $this->toString(); } /** * Returns a string representation of the test case. */ public function toString(): string { return $this->filename; } public function usesDataProvider(): bool { return false; } public function numberOfAssertionsPerformed(): int { return 1; } public function output(): string { return $this->output; } public function hasOutput(): bool { return !empty($this->output); } public function sortId(): string { return $this->filename; } /** * @psalm-return list<ExecutionOrderDependency> */ public function provides(): array { return []; } /** * @psalm-return list<ExecutionOrderDependency> */ public function requires(): array { return []; } /** * @internal This method is not covered by the backward compatibility promise for PHPUnit */ public function valueObjectForEvents(): Phpt { return new Phpt($this->filename); } /** * Parse --INI-- section key value pairs and return as array. */ private function parseIniSection(array|string $content, array $ini = []): array { if (is_string($content)) { $content = explode("\n", trim($content)); } foreach ($content as $setting) { if (!str_contains($setting, '=')) { continue; } $setting = explode('=', $setting, 2); $name = trim($setting[0]); $value = trim($setting[1]); if ($name === 'extension' || $name === 'zend_extension') { if (!isset($ini[$name])) { $ini[$name] = []; } $ini[$name][] = $value; continue; } $ini[$name] = $value; } return $ini; } private function parseEnvSection(string $content): array { $env = []; foreach (explode("\n", trim($content)) as $e) { $e = explode('=', trim($e), 2); if (!empty($e[0]) && isset($e[1])) { $env[$e[0]] = $e[1]; } } return $env; } /** * @throws Exception * @throws ExpectationFailedException */ private function assertPhptExpectation(array $sections, string $output): void { $assertions = [ 'EXPECT' => 'assertEquals', 'EXPECTF' => 'assertStringMatchesFormat', 'EXPECTREGEX' => 'assertMatchesRegularExpression', ]; $actual = preg_replace('/\r\n/', "\n", trim($output)); foreach ($assertions as $sectionName => $sectionAssertion) { if (isset($sections[$sectionName])) { $sectionContent = preg_replace('/\r\n/', "\n", trim($sections[$sectionName])); $expected = $sectionName === 'EXPECTREGEX' ? "/{$sectionContent}/" : $sectionContent; Assert::$sectionAssertion($expected, $actual); return; } } throw new InvalidPhptFileException; } private function shouldTestBeSkipped(array $sections, array $settings): bool { if (!isset($sections['SKIPIF'])) { return false; } $skipif = $this->render($sections['SKIPIF']); $jobResult = $this->phpUtil->runJob($skipif, $this->stringifyIni($settings)); if (!strncasecmp('skip', ltrim($jobResult['stdout']), 4)) { $message = ''; if (preg_match('/^\s*skip\s*(.+)\s*/i', $jobResult['stdout'], $skipMatch)) { $message = substr($skipMatch[1], 2); } EventFacade::emitter()->testSkipped( $this->valueObjectForEvents(), $message, ); EventFacade::emitter()->testFinished($this->valueObjectForEvents(), 0); return true; } return false; } private function runClean(array $sections, bool $collectCoverage): void { $this->phpUtil->setStdin(''); $this->phpUtil->setArgs(''); if (isset($sections['CLEAN'])) { $cleanCode = $this->render($sections['CLEAN']); $this->phpUtil->runJob($cleanCode, $this->settings($collectCoverage)); } } /** * @throws Exception */ private function parse(): array { $sections = []; $section = ''; $unsupportedSections = [ 'CGI', 'COOKIE', 'DEFLATE_POST', 'EXPECTHEADERS', 'EXTENSIONS', 'GET', 'GZIP_POST', 'HEADERS', 'PHPDBG', 'POST', 'POST_RAW', 'PUT', 'REDIRECTTEST', 'REQUEST', ]; $lineNr = 0; foreach (file($this->filename) as $line) { $lineNr++; if (preg_match('/^--([_A-Z]+)--/', $line, $result)) { $section = $result[1]; $sections[$section] = ''; $sections[$section . '_offset'] = $lineNr; continue; } if (empty($section)) { throw new InvalidPhptFileException; } $sections[$section] .= $line; } if (isset($sections['FILEEOF'])) { $sections['FILE'] = rtrim($sections['FILEEOF'], "\r\n"); unset($sections['FILEEOF']); } $this->parseExternal($sections); if (!$this->validate($sections)) { throw new InvalidPhptFileException; } foreach ($unsupportedSections as $section) { if (isset($sections[$section])) { throw new UnsupportedPhptSectionException($section); } } return $sections; } /** * @throws Exception */ private function parseExternal(array &$sections): void { $allowSections = [ 'FILE', 'EXPECT', 'EXPECTF', 'EXPECTREGEX', ]; $testDirectory = dirname($this->filename) . DIRECTORY_SEPARATOR; foreach ($allowSections as $section) { if (isset($sections[$section . '_EXTERNAL'])) { $externalFilename = trim($sections[$section . '_EXTERNAL']); if (!is_file($testDirectory . $externalFilename) || !is_readable($testDirectory . $externalFilename)) { throw new PhptExternalFileCannotBeLoadedException( $section, $testDirectory . $externalFilename, ); } $sections[$section] = file_get_contents($testDirectory . $externalFilename); } } } private function validate(array $sections): bool { $requiredSections = [ 'FILE', [ 'EXPECT', 'EXPECTF', 'EXPECTREGEX', ], ]; foreach ($requiredSections as $section) { if (is_array($section)) { $foundSection = false; foreach ($section as $anySection) { if (isset($sections[$anySection])) { $foundSection = true; break; } } if (!$foundSection) { return false; } continue; } if (!isset($sections[$section])) { return false; } } return true; } private function render(string $code): string { return str_replace( [ '__DIR__', '__FILE__', ], [ "'" . dirname($this->filename) . "'", "'" . $this->filename . "'", ], $code, ); } private function getCoverageFiles(): array { $baseDir = dirname(realpath($this->filename)) . DIRECTORY_SEPARATOR; $basename = basename($this->filename, 'phpt'); return [ 'coverage' => $baseDir . $basename . 'coverage', 'job' => $baseDir . $basename . 'php', ]; } /** * @throws \SebastianBergmann\Template\InvalidArgumentException */ private function renderForCoverage(string &$job, bool $pathCoverage, ?string $codeCoverageCacheDirectory): void { $files = $this->getCoverageFiles(); $template = new Template( __DIR__ . '/../Util/PHP/Template/PhptTestCase.tpl', ); $composerAutoload = '\'\''; if (defined('PHPUNIT_COMPOSER_INSTALL')) { $composerAutoload = var_export(PHPUNIT_COMPOSER_INSTALL, true); } $phar = '\'\''; if (defined('__PHPUNIT_PHAR__')) { $phar = var_export(__PHPUNIT_PHAR__, true); } if ($codeCoverageCacheDirectory === null) { $codeCoverageCacheDirectory = 'null'; } else { $codeCoverageCacheDirectory = "'" . $codeCoverageCacheDirectory . "'"; } $bootstrap = ''; if (ConfigurationRegistry::get()->hasBootstrap()) { $bootstrap = ConfigurationRegistry::get()->bootstrap(); } $template->setVar( [ 'bootstrap' => $bootstrap, 'composerAutoload' => $composerAutoload, 'phar' => $phar, 'job' => $files['job'], 'coverageFile' => $files['coverage'], 'driverMethod' => $pathCoverage ? 'forLineAndPathCoverage' : 'forLineCoverage', 'codeCoverageCacheDirectory' => $codeCoverageCacheDirectory, ], ); file_put_contents($files['job'], $job); $job = $template->render(); } private function cleanupForCoverage(): RawCodeCoverageData { $coverage = RawCodeCoverageData::fromXdebugWithoutPathCoverage([]); $files = $this->getCoverageFiles(); if (is_file($files['coverage'])) { $buffer = @file_get_contents($files['coverage']); if ($buffer !== false) { $coverage = @unserialize($buffer); if ($coverage === false) { $coverage = RawCodeCoverageData::fromXdebugWithoutPathCoverage([]); } } } foreach ($files as $file) { @unlink($file); } return $coverage; } private function stringifyIni(array $ini): array { $settings = []; foreach ($ini as $key => $value) { if (is_array($value)) { foreach ($value as $val) { $settings[] = $key . '=' . $val; } continue; } $settings[] = $key . '=' . $value; } return $settings; } private function getLocationHintFromDiff(string $message, array $sections): array { $needle = ''; $previousLine = ''; $block = 'message'; foreach (preg_split('/\r\n|\r|\n/', $message) as $line) { $line = trim($line); if ($block === 'message' && $line === '--- Expected') { $block = 'expected'; } if ($block === 'expected' && $line === '@@ @@') { $block = 'diff'; } if ($block === 'diff') { if (str_starts_with($line, '+')) { $needle = $this->getCleanDiffLine($previousLine); break; } if (str_starts_with($line, '-')) { $needle = $this->getCleanDiffLine($line); break; } } if (!empty($line)) { $previousLine = $line; } } return $this->getLocationHint($needle, $sections); } private function getCleanDiffLine(string $line): string { if (preg_match('/^[\-+]([\'\"]?)(.*)\1$/', $line, $matches)) { $line = $matches[2]; } return $line; } private function getLocationHint(string $needle, array $sections): array { $needle = trim($needle); if (empty($needle)) { return [[ 'file' => realpath($this->filename), 'line' => 1, ]]; } $search = [ // 'FILE', 'EXPECT', 'EXPECTF', 'EXPECTREGEX', ]; foreach ($search as $section) { if (!isset($sections[$section])) { continue; } if (isset($sections[$section . '_EXTERNAL'])) { $externalFile = trim($sections[$section . '_EXTERNAL']); return [ [ 'file' => realpath(dirname($this->filename) . DIRECTORY_SEPARATOR . $externalFile), 'line' => 1, ], [ 'file' => realpath($this->filename), 'line' => ($sections[$section . '_EXTERNAL_offset'] ?? 0) + 1, ], ]; } $sectionOffset = $sections[$section . '_offset'] ?? 0; $offset = $sectionOffset + 1; foreach (preg_split('/\r\n|\r|\n/', $sections[$section]) as $line) { if (str_contains($line, $needle)) { return [ [ 'file' => realpath($this->filename), 'line' => $offset, ], ]; } $offset++; } } return [ [ 'file' => realpath($this->filename), 'line' => 1, ], ]; } /** * @psalm-return list<string> */ private function settings(bool $collectCoverage): array { $settings = [ 'allow_url_fopen=1', 'auto_append_file=', 'auto_prepend_file=', 'disable_functions=', 'display_errors=1', 'docref_ext=.html', 'docref_root=', 'error_append_string=', 'error_prepend_string=', 'error_reporting=-1', 'html_errors=0', 'log_errors=0', 'open_basedir=', 'output_buffering=Off', 'output_handler=', 'report_memleaks=0', 'report_zend_debug=0', ]; if (extension_loaded('pcov')) { if ($collectCoverage) { $settings[] = 'pcov.enabled=1'; } else { $settings[] = 'pcov.enabled=0'; } } if (extension_loaded('xdebug')) { if ($collectCoverage) { $settings[] = 'xdebug.mode=coverage'; } else { $settings[] = 'xdebug.mode=off'; } } return $settings; } } CodeCoverage.php 0000644 00000033203 15111200075 0007574 0 ustar 00 <?php declare(strict_types=1); /* * This file is part of PHPUnit. * * (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 PHPUnit\Runner; use function file_put_contents; use function sprintf; use PHPUnit\Event\Facade as EventFacade; use PHPUnit\Event\TestData\MoreThanOneDataSetFromDataProviderException; use PHPUnit\Event\TestData\NoDataSetFromDataProviderException; use PHPUnit\Framework\TestCase; use PHPUnit\TextUI\Configuration\CodeCoverageFilterRegistry; use PHPUnit\TextUI\Configuration\Configuration; use PHPUnit\TextUI\Output\Printer; use SebastianBergmann\CodeCoverage\Driver\Driver; use SebastianBergmann\CodeCoverage\Driver\Selector; use SebastianBergmann\CodeCoverage\Exception as CodeCoverageException; use SebastianBergmann\CodeCoverage\Filter; use SebastianBergmann\CodeCoverage\Report\Clover as CloverReport; use SebastianBergmann\CodeCoverage\Report\Cobertura as CoberturaReport; use SebastianBergmann\CodeCoverage\Report\Crap4j as Crap4jReport; use SebastianBergmann\CodeCoverage\Report\Html\Colors; use SebastianBergmann\CodeCoverage\Report\Html\CustomCssFile; use SebastianBergmann\CodeCoverage\Report\Html\Facade as HtmlReport; use SebastianBergmann\CodeCoverage\Report\PHP as PhpReport; use SebastianBergmann\CodeCoverage\Report\Text as TextReport; use SebastianBergmann\CodeCoverage\Report\Thresholds; use SebastianBergmann\CodeCoverage\Report\Xml\Facade as XmlReport; use SebastianBergmann\CodeCoverage\Test\TestSize\TestSize; use SebastianBergmann\CodeCoverage\Test\TestStatus\TestStatus; use SebastianBergmann\Comparator\Comparator; use SebastianBergmann\Timer\NoActiveTimerException; use SebastianBergmann\Timer\Timer; /** * @internal This class is not covered by the backward compatibility promise for PHPUnit */ final class CodeCoverage { private static ?self $instance = null; private ?\SebastianBergmann\CodeCoverage\CodeCoverage $codeCoverage = null; private ?Driver $driver = null; private bool $collecting = false; private ?TestCase $test = null; private ?Timer $timer = null; /** * @psalm-var array<string,list<int>> */ private array $linesToBeIgnored = []; public static function instance(): self { if (self::$instance === null) { self::$instance = new self; } return self::$instance; } public function init(Configuration $configuration, CodeCoverageFilterRegistry $codeCoverageFilterRegistry, bool $extensionRequiresCodeCoverageCollection): void { $codeCoverageFilterRegistry->init($configuration); if (!$configuration->hasCoverageReport() && !$extensionRequiresCodeCoverageCollection) { return; } $this->activate($codeCoverageFilterRegistry->get(), $configuration->pathCoverage()); if (!$this->isActive()) { return; } if ($configuration->hasCoverageCacheDirectory()) { $this->codeCoverage()->cacheStaticAnalysis($configuration->coverageCacheDirectory()); } $this->codeCoverage()->excludeSubclassesOfThisClassFromUnintentionallyCoveredCodeCheck(Comparator::class); if ($configuration->strictCoverage()) { $this->codeCoverage()->enableCheckForUnintentionallyCoveredCode(); } if ($configuration->ignoreDeprecatedCodeUnitsFromCodeCoverage()) { $this->codeCoverage()->ignoreDeprecatedCode(); } else { $this->codeCoverage()->doNotIgnoreDeprecatedCode(); } if ($configuration->disableCodeCoverageIgnore()) { $this->codeCoverage()->disableAnnotationsForIgnoringCode(); } else { $this->codeCoverage()->enableAnnotationsForIgnoringCode(); } if ($configuration->includeUncoveredFiles()) { $this->codeCoverage()->includeUncoveredFiles(); } else { $this->codeCoverage()->excludeUncoveredFiles(); } if ($codeCoverageFilterRegistry->get()->isEmpty()) { if (!$codeCoverageFilterRegistry->configured()) { EventFacade::emitter()->testRunnerTriggeredWarning( 'No filter is configured, code coverage will not be processed', ); } else { EventFacade::emitter()->testRunnerTriggeredWarning( 'Incorrect filter configuration, code coverage will not be processed', ); } $this->deactivate(); } } /** * @psalm-assert-if-true !null $this->instance */ public function isActive(): bool { return $this->codeCoverage !== null; } public function codeCoverage(): \SebastianBergmann\CodeCoverage\CodeCoverage { return $this->codeCoverage; } public function driver(): Driver { return $this->driver; } /** * @throws MoreThanOneDataSetFromDataProviderException * @throws NoDataSetFromDataProviderException */ public function start(TestCase $test): void { if ($this->collecting) { return; } $size = TestSize::unknown(); if ($test->size()->isSmall()) { $size = TestSize::small(); } elseif ($test->size()->isMedium()) { $size = TestSize::medium(); } elseif ($test->size()->isLarge()) { $size = TestSize::large(); } $this->test = $test; $this->codeCoverage->start( $test->valueObjectForEvents()->id(), $size, ); $this->collecting = true; } public function stop(bool $append = true, array|false $linesToBeCovered = [], array $linesToBeUsed = []): void { if (!$this->collecting) { return; } $status = TestStatus::unknown(); if ($this->test !== null) { if ($this->test->status()->isSuccess()) { $status = TestStatus::success(); } else { $status = TestStatus::failure(); } } /* @noinspection UnusedFunctionResultInspection */ $this->codeCoverage->stop($append, $status, $linesToBeCovered, $linesToBeUsed, $this->linesToBeIgnored); $this->test = null; $this->collecting = false; } public function deactivate(): void { $this->driver = null; $this->codeCoverage = null; $this->test = null; } public function generateReports(Printer $printer, Configuration $configuration): void { if (!$this->isActive()) { return; } if ($configuration->hasCoveragePhp()) { $this->codeCoverageGenerationStart($printer, 'PHP'); try { $writer = new PhpReport; $writer->process($this->codeCoverage(), $configuration->coveragePhp()); $this->codeCoverageGenerationSucceeded($printer); unset($writer); } catch (CodeCoverageException $e) { $this->codeCoverageGenerationFailed($printer, $e); } } if ($configuration->hasCoverageClover()) { $this->codeCoverageGenerationStart($printer, 'Clover XML'); try { $writer = new CloverReport; $writer->process($this->codeCoverage(), $configuration->coverageClover()); $this->codeCoverageGenerationSucceeded($printer); unset($writer); } catch (CodeCoverageException $e) { $this->codeCoverageGenerationFailed($printer, $e); } } if ($configuration->hasCoverageCobertura()) { $this->codeCoverageGenerationStart($printer, 'Cobertura XML'); try { $writer = new CoberturaReport; $writer->process($this->codeCoverage(), $configuration->coverageCobertura()); $this->codeCoverageGenerationSucceeded($printer); unset($writer); } catch (CodeCoverageException $e) { $this->codeCoverageGenerationFailed($printer, $e); } } if ($configuration->hasCoverageCrap4j()) { $this->codeCoverageGenerationStart($printer, 'Crap4J XML'); try { $writer = new Crap4jReport($configuration->coverageCrap4jThreshold()); $writer->process($this->codeCoverage(), $configuration->coverageCrap4j()); $this->codeCoverageGenerationSucceeded($printer); unset($writer); } catch (CodeCoverageException $e) { $this->codeCoverageGenerationFailed($printer, $e); } } if ($configuration->hasCoverageHtml()) { $this->codeCoverageGenerationStart($printer, 'HTML'); try { $customCssFile = CustomCssFile::default(); if ($configuration->hasCoverageHtmlCustomCssFile()) { $customCssFile = CustomCssFile::from($configuration->coverageHtmlCustomCssFile()); } $writer = new HtmlReport( sprintf( ' and <a href="https://phpunit.de/">PHPUnit %s</a>', Version::id(), ), Colors::from( $configuration->coverageHtmlColorSuccessLow(), $configuration->coverageHtmlColorSuccessMedium(), $configuration->coverageHtmlColorSuccessHigh(), $configuration->coverageHtmlColorWarning(), $configuration->coverageHtmlColorDanger(), ), Thresholds::from( $configuration->coverageHtmlLowUpperBound(), $configuration->coverageHtmlHighLowerBound(), ), $customCssFile, ); $writer->process($this->codeCoverage(), $configuration->coverageHtml()); $this->codeCoverageGenerationSucceeded($printer); unset($writer); } catch (CodeCoverageException $e) { $this->codeCoverageGenerationFailed($printer, $e); } } if ($configuration->hasCoverageText()) { $processor = new TextReport( Thresholds::default(), $configuration->coverageTextShowUncoveredFiles(), $configuration->coverageTextShowOnlySummary(), ); $textReport = $processor->process($this->codeCoverage(), $configuration->colors()); if ($configuration->coverageText() === 'php://stdout') { $printer->print($textReport); } else { file_put_contents($configuration->coverageText(), $textReport); } } if ($configuration->hasCoverageXml()) { $this->codeCoverageGenerationStart($printer, 'PHPUnit XML'); try { $writer = new XmlReport(Version::id()); $writer->process($this->codeCoverage(), $configuration->coverageXml()); $this->codeCoverageGenerationSucceeded($printer); unset($writer); } catch (CodeCoverageException $e) { $this->codeCoverageGenerationFailed($printer, $e); } } } /** * @psalm-param array<string,list<int>> $linesToBeIgnored */ public function ignoreLines(array $linesToBeIgnored): void { $this->linesToBeIgnored = $linesToBeIgnored; } /** * @psalm-return array<string,list<int>> */ public function linesToBeIgnored(): array { return $this->linesToBeIgnored; } private function activate(Filter $filter, bool $pathCoverage): void { try { if ($pathCoverage) { $this->driver = (new Selector)->forLineAndPathCoverage($filter); } else { $this->driver = (new Selector)->forLineCoverage($filter); } $this->codeCoverage = new \SebastianBergmann\CodeCoverage\CodeCoverage( $this->driver, $filter, ); } catch (CodeCoverageException $e) { EventFacade::emitter()->testRunnerTriggeredWarning( $e->getMessage(), ); } } private function codeCoverageGenerationStart(Printer $printer, string $format): void { $printer->print( sprintf( "\nGenerating code coverage report in %s format ... ", $format, ), ); $this->timer()->start(); } /** * @throws NoActiveTimerException */ private function codeCoverageGenerationSucceeded(Printer $printer): void { $printer->print( sprintf( "done [%s]\n", $this->timer()->stop()->asString(), ), ); } /** * @throws NoActiveTimerException */ private function codeCoverageGenerationFailed(Printer $printer, CodeCoverageException $e): void { $printer->print( sprintf( "failed [%s]\n%s\n", $this->timer()->stop()->asString(), $e->getMessage(), ), ); } private function timer(): Timer { if ($this->timer === null) { $this->timer = new Timer; } return $this->timer; } } Baseline/Issue.php 0000644 00000006500 15111200075 0010060 0 ustar 00 <?php declare(strict_types=1); /* * This file is part of PHPUnit. * * (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 PHPUnit\Runner\Baseline; use function assert; use function file; use function is_file; use function sha1; use PHPUnit\Runner\FileDoesNotExistException; /** * @internal This class is not covered by the backward compatibility promise for PHPUnit */ final class Issue { /** * @psalm-var non-empty-string */ private readonly string $file; /** * @psalm-var positive-int */ private readonly int $line; /** * @psalm-var non-empty-string */ private readonly string $hash; /** * @psalm-var non-empty-string */ private readonly string $description; /** * @psalm-param non-empty-string $file * @psalm-param positive-int $line * @psalm-param ?non-empty-string $hash * @psalm-param non-empty-string $description * * @throws FileDoesNotExistException * @throws FileDoesNotHaveLineException */ public static function from(string $file, int $line, ?string $hash, string $description): self { if ($hash === null) { $hash = self::calculateHash($file, $line); } return new self($file, $line, $hash, $description); } /** * @psalm-param non-empty-string $file * @psalm-param positive-int $line * @psalm-param non-empty-string $hash * @psalm-param non-empty-string $description */ private function __construct(string $file, int $line, string $hash, string $description) { $this->file = $file; $this->line = $line; $this->hash = $hash; $this->description = $description; } /** * @psalm-return non-empty-string */ public function file(): string { return $this->file; } /** * @psalm-return positive-int */ public function line(): int { return $this->line; } /** * @psalm-return non-empty-string */ public function hash(): string { return $this->hash; } /** * @psalm-return non-empty-string */ public function description(): string { return $this->description; } public function equals(self $other): bool { return $this->file() === $other->file() && $this->line() === $other->line() && $this->hash() === $other->hash() && $this->description() === $other->description(); } /** * @psalm-param non-empty-string $file * @psalm-param positive-int $line * * @psalm-return non-empty-string * * @throws FileDoesNotExistException * @throws FileDoesNotHaveLineException */ private static function calculateHash(string $file, int $line): string { if (!is_file($file)) { throw new FileDoesNotExistException($file); } $lines = file($file, FILE_IGNORE_NEW_LINES); $key = $line - 1; if (!isset($lines[$key])) { throw new FileDoesNotHaveLineException($file, $line); } $hash = sha1($lines[$key]); assert(!empty($hash)); return $hash; } } Baseline/Writer.php 0000644 00000003516 15111200075 0010250 0 ustar 00 <?php declare(strict_types=1); /* * This file is part of PHPUnit. * * (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 PHPUnit\Runner\Baseline; use function assert; use function dirname; use function file_put_contents; use XMLWriter; /** * @internal This class is not covered by the backward compatibility promise for PHPUnit */ final class Writer { /** * @psalm-param non-empty-string $baselineFile */ public function write(string $baselineFile, Baseline $baseline): void { $pathCalculator = new RelativePathCalculator(dirname($baselineFile)); $writer = new XMLWriter; $writer->openMemory(); $writer->setIndent(true); $writer->startDocument(); $writer->startElement('files'); $writer->writeAttribute('version', (string) Baseline::VERSION); foreach ($baseline->groupedByFileAndLine() as $file => $lines) { assert(!empty($file)); $writer->startElement('file'); $writer->writeAttribute('path', $pathCalculator->calculate($file)); foreach ($lines as $line => $issues) { $writer->startElement('line'); $writer->writeAttribute('number', (string) $line); $writer->writeAttribute('hash', $issues[0]->hash()); foreach ($issues as $issue) { $writer->startElement('issue'); $writer->writeCData($issue->description()); $writer->endElement(); } $writer->endElement(); } $writer->endElement(); } $writer->endElement(); file_put_contents($baselineFile, $writer->outputMemory()); } } Baseline/Exception/FileDoesNotHaveLineException.php 0000644 00000001432 15111200075 0016373 0 ustar 00 <?php declare(strict_types=1); /* * This file is part of PHPUnit. * * (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 PHPUnit\Runner\Baseline; use function sprintf; use PHPUnit\Runner\Exception; use RuntimeException; /** * @internal This class is not covered by the backward compatibility promise for PHPUnit */ final class FileDoesNotHaveLineException extends RuntimeException implements Exception { public function __construct(string $file, int $line) { parent::__construct( sprintf( 'File "%s" does not have line %d', $file, $line, ), ); } } Baseline/Exception/CannotLoadBaselineException.php 0000644 00000001021 15111200075 0016263 0 ustar 00 <?php declare(strict_types=1); /* * This file is part of PHPUnit. * * (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 PHPUnit\Runner\Baseline; use PHPUnit\Runner\Exception; use RuntimeException; /** * @internal This class is not covered by the backward compatibility promise for PHPUnit */ final class CannotLoadBaselineException extends RuntimeException implements Exception { } Baseline/Generator.php 0000644 00000004674 15111200075 0010730 0 ustar 00 <?php declare(strict_types=1); /* * This file is part of PHPUnit. * * (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 PHPUnit\Runner\Baseline; use PHPUnit\Event\EventFacadeIsSealedException; use PHPUnit\Event\Facade; use PHPUnit\Event\Test\DeprecationTriggered; use PHPUnit\Event\Test\NoticeTriggered; use PHPUnit\Event\Test\PhpDeprecationTriggered; use PHPUnit\Event\Test\PhpNoticeTriggered; use PHPUnit\Event\Test\PhpWarningTriggered; use PHPUnit\Event\Test\WarningTriggered; use PHPUnit\Event\UnknownSubscriberTypeException; use PHPUnit\Runner\FileDoesNotExistException; use PHPUnit\TextUI\Configuration\Source; use PHPUnit\TextUI\Configuration\SourceFilter; /** * @internal This class is not covered by the backward compatibility promise for PHPUnit */ final class Generator { private Baseline $baseline; private readonly Source $source; /** * @throws EventFacadeIsSealedException * @throws UnknownSubscriberTypeException */ public function __construct(Facade $facade, Source $source) { $facade->registerSubscribers( new TestTriggeredDeprecationSubscriber($this), new TestTriggeredNoticeSubscriber($this), new TestTriggeredPhpDeprecationSubscriber($this), new TestTriggeredPhpNoticeSubscriber($this), new TestTriggeredPhpWarningSubscriber($this), new TestTriggeredWarningSubscriber($this), ); $this->baseline = new Baseline; $this->source = $source; } public function baseline(): Baseline { return $this->baseline; } /** * @throws FileDoesNotExistException * @throws FileDoesNotHaveLineException */ public function testTriggeredIssue(DeprecationTriggered|NoticeTriggered|PhpDeprecationTriggered|PhpNoticeTriggered|PhpWarningTriggered|WarningTriggered $event): void { if (!$this->source->ignoreSuppressionOfPhpWarnings() && $event->wasSuppressed()) { return; } if ($this->source->restrictWarnings() && !(new SourceFilter)->includes($this->source, $event->file())) { return; } $this->baseline->add( Issue::from( $event->file(), $event->line(), null, $event->message(), ), ); } } Baseline/Baseline.php 0000644 00000002712 15111200075 0010513 0 ustar 00 <?php declare(strict_types=1); /* * This file is part of PHPUnit. * * (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 PHPUnit\Runner\Baseline; /** * @internal This class is not covered by the backward compatibility promise for PHPUnit */ final class Baseline { public const VERSION = 1; /** * @psalm-var array<non-empty-string, array<positive-int, list<Issue>>> */ private array $issues = []; public function add(Issue $issue): void { if (!isset($this->issues[$issue->file()])) { $this->issues[$issue->file()] = []; } if (!isset($this->issues[$issue->file()][$issue->line()])) { $this->issues[$issue->file()][$issue->line()] = []; } $this->issues[$issue->file()][$issue->line()][] = $issue; } public function has(Issue $issue): bool { if (!isset($this->issues[$issue->file()][$issue->line()])) { return false; } foreach ($this->issues[$issue->file()][$issue->line()] as $_issue) { if ($_issue->equals($issue)) { return true; } } return false; } /** * @psalm-return array<string, array<positive-int, list<Issue>>> */ public function groupedByFileAndLine(): array { return $this->issues; } } Baseline/RelativePathCalculator.php 0000644 00000005267 15111200075 0013403 0 ustar 00 <?php declare(strict_types=1); /* * This file is part of PHPUnit. * * (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 PHPUnit\Runner\Baseline; use function array_fill; use function array_merge; use function array_slice; use function assert; use function count; use function explode; use function implode; use function str_replace; use function strpos; use function substr; use function trim; /** * @internal This class is not covered by the backward compatibility promise for PHPUnit * * @see Copied from https://github.com/phpstan/phpstan-src/blob/1.10.33/src/File/ParentDirectoryRelativePathHelper.php */ final class RelativePathCalculator { /** * @psalm-var non-empty-string $baselineDirectory */ private readonly string $baselineDirectory; /** * @psalm-param non-empty-string $baselineDirectory */ public function __construct(string $baselineDirectory) { $this->baselineDirectory = $baselineDirectory; } /** * @psalm-param non-empty-string $filename * * @psalm-return non-empty-string */ public function calculate(string $filename): string { $result = implode('/', $this->parts($filename)); assert($result !== ''); return $result; } /** * @psalm-param non-empty-string $filename * * @psalm-return list<non-empty-string> */ public function parts(string $filename): array { $schemePosition = strpos($filename, '://'); if ($schemePosition !== false) { $filename = substr($filename, $schemePosition + 3); assert($filename !== ''); } $parentParts = explode('/', trim(str_replace('\\', '/', $this->baselineDirectory), '/')); $parentPartsCount = count($parentParts); $filenameParts = explode('/', trim(str_replace('\\', '/', $filename), '/')); $filenamePartsCount = count($filenameParts); $i = 0; for (; $i < $filenamePartsCount; $i++) { if ($parentPartsCount < $i + 1) { break; } $parentPath = implode('/', array_slice($parentParts, 0, $i + 1)); $filenamePath = implode('/', array_slice($filenameParts, 0, $i + 1)); if ($parentPath !== $filenamePath) { break; } } if ($i === 0) { return [$filename]; } $dotsCount = $parentPartsCount - $i; assert($dotsCount >= 0); return array_merge(array_fill(0, $dotsCount, '..'), array_slice($filenameParts, $i)); } } Baseline/Subscriber/TestTriggeredNoticeSubscriber.php 0000644 00000001523 15111200075 0017035 0 ustar 00 <?php declare(strict_types=1); /* * This file is part of PHPUnit. * * (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 PHPUnit\Runner\Baseline; use PHPUnit\Event\Test\NoticeTriggered; use PHPUnit\Event\Test\NoticeTriggeredSubscriber; use PHPUnit\Runner\FileDoesNotExistException; /** * @internal This class is not covered by the backward compatibility promise for PHPUnit */ final class TestTriggeredNoticeSubscriber extends Subscriber implements NoticeTriggeredSubscriber { /** * @throws FileDoesNotExistException * @throws FileDoesNotHaveLineException */ public function notify(NoticeTriggered $event): void { $this->generator()->testTriggeredIssue($event); } } Baseline/Subscriber/Subscriber.php 0000644 00000001221 15111200075 0013171 0 ustar 00 <?php declare(strict_types=1); /* * This file is part of PHPUnit. * * (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 PHPUnit\Runner\Baseline; /** * @internal This class is not covered by the backward compatibility promise for PHPUnit */ abstract class Subscriber { private readonly Generator $generator; public function __construct(Generator $generator) { $this->generator = $generator; } protected function generator(): Generator { return $this->generator; } } Baseline/Subscriber/TestTriggeredPhpWarningSubscriber.php 0000644 00000001547 15111200075 0017677 0 ustar 00 <?php declare(strict_types=1); /* * This file is part of PHPUnit. * * (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 PHPUnit\Runner\Baseline; use PHPUnit\Event\Test\PhpWarningTriggered; use PHPUnit\Event\Test\PhpWarningTriggeredSubscriber; use PHPUnit\Runner\FileDoesNotExistException; /** * @internal This class is not covered by the backward compatibility promise for PHPUnit */ final class TestTriggeredPhpWarningSubscriber extends Subscriber implements PhpWarningTriggeredSubscriber { /** * @throws FileDoesNotExistException * @throws FileDoesNotHaveLineException */ public function notify(PhpWarningTriggered $event): void { $this->generator()->testTriggeredIssue($event); } } Baseline/Subscriber/TestTriggeredDeprecationSubscriber.php 0000644 00000001554 15111200075 0020055 0 ustar 00 <?php declare(strict_types=1); /* * This file is part of PHPUnit. * * (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 PHPUnit\Runner\Baseline; use PHPUnit\Event\Test\DeprecationTriggered; use PHPUnit\Event\Test\DeprecationTriggeredSubscriber; use PHPUnit\Runner\FileDoesNotExistException; /** * @internal This class is not covered by the backward compatibility promise for PHPUnit */ final class TestTriggeredDeprecationSubscriber extends Subscriber implements DeprecationTriggeredSubscriber { /** * @throws FileDoesNotExistException * @throws FileDoesNotHaveLineException */ public function notify(DeprecationTriggered $event): void { $this->generator()->testTriggeredIssue($event); } } Baseline/Subscriber/TestTriggeredWarningSubscriber.php 0000644 00000001530 15111200075 0017217 0 ustar 00 <?php declare(strict_types=1); /* * This file is part of PHPUnit. * * (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 PHPUnit\Runner\Baseline; use PHPUnit\Event\Test\WarningTriggered; use PHPUnit\Event\Test\WarningTriggeredSubscriber; use PHPUnit\Runner\FileDoesNotExistException; /** * @internal This class is not covered by the backward compatibility promise for PHPUnit */ final class TestTriggeredWarningSubscriber extends Subscriber implements WarningTriggeredSubscriber { /** * @throws FileDoesNotExistException * @throws FileDoesNotHaveLineException */ public function notify(WarningTriggered $event): void { $this->generator()->testTriggeredIssue($event); } } Baseline/Subscriber/TestTriggeredPhpNoticeSubscriber.php 0000644 00000001542 15111200075 0017506 0 ustar 00 <?php declare(strict_types=1); /* * This file is part of PHPUnit. * * (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 PHPUnit\Runner\Baseline; use PHPUnit\Event\Test\PhpNoticeTriggered; use PHPUnit\Event\Test\PhpNoticeTriggeredSubscriber; use PHPUnit\Runner\FileDoesNotExistException; /** * @internal This class is not covered by the backward compatibility promise for PHPUnit */ final class TestTriggeredPhpNoticeSubscriber extends Subscriber implements PhpNoticeTriggeredSubscriber { /** * @throws FileDoesNotExistException * @throws FileDoesNotHaveLineException */ public function notify(PhpNoticeTriggered $event): void { $this->generator()->testTriggeredIssue($event); } } Baseline/Subscriber/TestTriggeredPhpDeprecationSubscriber.php 0000644 00000001573 15111200075 0020526 0 ustar 00 <?php declare(strict_types=1); /* * This file is part of PHPUnit. * * (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 PHPUnit\Runner\Baseline; use PHPUnit\Event\Test\PhpDeprecationTriggered; use PHPUnit\Event\Test\PhpDeprecationTriggeredSubscriber; use PHPUnit\Runner\FileDoesNotExistException; /** * @internal This class is not covered by the backward compatibility promise for PHPUnit */ final class TestTriggeredPhpDeprecationSubscriber extends Subscriber implements PhpDeprecationTriggeredSubscriber { /** * @throws FileDoesNotExistException * @throws FileDoesNotHaveLineException */ public function notify(PhpDeprecationTriggered $event): void { $this->generator()->testTriggeredIssue($event); } } Baseline/Reader.php 0000644 00000005773 15111200075 0010205 0 ustar 00 <?php declare(strict_types=1); /* * This file is part of PHPUnit. * * (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 PHPUnit\Runner\Baseline; use function assert; use function dirname; use function file_exists; use function realpath; use function sprintf; use function str_replace; use function trim; use DOMElement; use DOMXPath; use PHPUnit\Util\Xml\Loader as XmlLoader; use PHPUnit\Util\Xml\XmlException; /** * @internal This class is not covered by the backward compatibility promise for PHPUnit */ final class Reader { /** * @psalm-param non-empty-string $baselineFile * * @throws CannotLoadBaselineException */ public function read(string $baselineFile): Baseline { if (!file_exists($baselineFile)) { throw new CannotLoadBaselineException( sprintf( 'Cannot read baseline %s, file does not exist', $baselineFile, ), ); } try { $document = (new XmlLoader)->loadFile($baselineFile); } catch (XmlException $e) { throw new CannotLoadBaselineException( sprintf( 'Cannot read baseline: %s', trim($e->getMessage()), ), ); } $version = (int) $document->documentElement->getAttribute('version'); if ($version !== Baseline::VERSION) { throw new CannotLoadBaselineException( sprintf( 'Cannot read baseline %s, version %d is not supported', $baselineFile, $version, ), ); } $baseline = new Baseline; $baselineDirectory = dirname(realpath($baselineFile)); $xpath = new DOMXPath($document); foreach ($xpath->query('file') as $fileElement) { assert($fileElement instanceof DOMElement); $file = $baselineDirectory . DIRECTORY_SEPARATOR . str_replace('/', DIRECTORY_SEPARATOR, $fileElement->getAttribute('path')); foreach ($xpath->query('line', $fileElement) as $lineElement) { assert($lineElement instanceof DOMElement); $line = (int) $lineElement->getAttribute('number'); $hash = $lineElement->getAttribute('hash'); foreach ($xpath->query('issue', $lineElement) as $issueElement) { assert($issueElement instanceof DOMElement); $description = $issueElement->textContent; assert(!empty($file)); assert($line > 0); assert(!empty($hash)); assert(!empty($description)); $baseline->add(Issue::from($file, $line, $hash, $description)); } } } return $baseline; } } TestResult/Issue.php 0000644 00000005144 15111200075 0010457 0 ustar 00 <?php declare(strict_types=1); /* * This file is part of PHPUnit. * * (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 PHPUnit\TestRunner\TestResult\Issues; use PHPUnit\Event\Code\Test; /** * @internal This class is not covered by the backward compatibility promise for PHPUnit */ final class Issue { /** * @psalm-var non-empty-string */ private readonly string $file; /** * @psalm-var positive-int */ private readonly int $line; /** * @psalm-var non-empty-string */ private readonly string $description; /** * @psalm-var non-empty-array<non-empty-string, array{test: Test, count: int}> */ private array $triggeringTests; /** * @psalm-param non-empty-string $file * @psalm-param positive-int $line * @psalm-param non-empty-string $description */ public static function from(string $file, int $line, string $description, Test $triggeringTest): self { return new self($file, $line, $description, $triggeringTest); } /** * @psalm-param non-empty-string $file * @psalm-param positive-int $line * @psalm-param non-empty-string $description */ private function __construct(string $file, int $line, string $description, Test $triggeringTest) { $this->file = $file; $this->line = $line; $this->description = $description; $this->triggeringTests = [ $triggeringTest->id() => [ 'test' => $triggeringTest, 'count' => 1, ], ]; } public function triggeredBy(Test $test): void { if (isset($this->triggeringTests[$test->id()])) { $this->triggeringTests[$test->id()]['count']++; return; } $this->triggeringTests[$test->id()] = [ 'test' => $test, 'count' => 1, ]; } /** * @psalm-return non-empty-string */ public function file(): string { return $this->file; } /** * @psalm-return positive-int */ public function line(): int { return $this->line; } /** * @psalm-return non-empty-string */ public function description(): string { return $this->description; } /** * @psalm-return non-empty-array<non-empty-string, array{test: Test, count: int}> */ public function triggeringTests(): array { return $this->triggeringTests; } } TestResult/Facade.php 0000644 00000005500 15111200075 0010526 0 ustar 00 <?php declare(strict_types=1); /* * This file is part of PHPUnit. * * (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 PHPUnit\TestRunner\TestResult; use PHPUnit\Event\EventFacadeIsSealedException; use PHPUnit\Event\Facade as EventFacade; use PHPUnit\Event\UnknownSubscriberTypeException; use PHPUnit\TextUI\Configuration\Registry as ConfigurationRegistry; /** * @internal This class is not covered by the backward compatibility promise for PHPUnit */ final class Facade { private static ?Collector $collector = null; /** * @throws EventFacadeIsSealedException * @throws UnknownSubscriberTypeException */ public static function init(): void { self::collector(); } /** * @throws EventFacadeIsSealedException * @throws UnknownSubscriberTypeException */ public static function result(): TestResult { return self::collector()->result(); } /** * @throws EventFacadeIsSealedException * @throws UnknownSubscriberTypeException */ public static function shouldStop(): bool { $configuration = ConfigurationRegistry::get(); $collector = self::collector(); if (($configuration->stopOnDefect() || $configuration->stopOnError()) && $collector->hasErroredTests()) { return true; } if (($configuration->stopOnDefect() || $configuration->stopOnFailure()) && $collector->hasFailedTests()) { return true; } if (($configuration->stopOnDefect() || $configuration->stopOnWarning()) && $collector->hasWarnings()) { return true; } if (($configuration->stopOnDefect() || $configuration->stopOnRisky()) && $collector->hasRiskyTests()) { return true; } if ($configuration->stopOnDeprecation() && $collector->hasDeprecations()) { return true; } if ($configuration->stopOnNotice() && $collector->hasNotices()) { return true; } if ($configuration->stopOnIncomplete() && $collector->hasIncompleteTests()) { return true; } if ($configuration->stopOnSkipped() && $collector->hasSkippedTests()) { return true; } return false; } /** * @throws EventFacadeIsSealedException * @throws UnknownSubscriberTypeException */ private static function collector(): Collector { if (self::$collector === null) { $configuration = ConfigurationRegistry::get(); self::$collector = new Collector( EventFacade::instance(), $configuration->source(), ); } return self::$collector; } } TestResult/PassedTests.php 0000644 00000006074 15111200076 0011635 0 ustar 00 <?php declare(strict_types=1); /* * This file is part of PHPUnit. * * (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 PHPUnit\TestRunner\TestResult; use function array_merge; use function assert; use function in_array; use PHPUnit\Event\Code\TestMethod; use PHPUnit\Event\TestData\NoDataSetFromDataProviderException; use PHPUnit\Framework\TestSize\Known; use PHPUnit\Framework\TestSize\TestSize; use PHPUnit\Metadata\Api\Groups; /** * @internal This class is not covered by the backward compatibility promise for PHPUnit */ final class PassedTests { private static ?self $instance = null; /** * @psalm-var list<class-string> */ private array $passedTestClasses = []; /** * @psalm-var array<string,array{returnValue: mixed, size: TestSize}> */ private array $passedTestMethods = []; public static function instance(): self { if (self::$instance !== null) { return self::$instance; } self::$instance = new self; return self::$instance; } /** * @psalm-param class-string $className */ public function testClassPassed(string $className): void { $this->passedTestClasses[] = $className; } /** * @throws NoDataSetFromDataProviderException */ public function testMethodPassed(TestMethod $test, mixed $returnValue): void { $size = (new Groups)->size( $test->className(), $test->methodName(), ); $this->passedTestMethods[$test->className() . '::' . $test->methodName()] = [ 'returnValue' => $returnValue, 'size' => $size, ]; } public function import(self $other): void { $this->passedTestClasses = array_merge( $this->passedTestClasses, $other->passedTestClasses, ); $this->passedTestMethods = array_merge( $this->passedTestMethods, $other->passedTestMethods, ); } /** * @psalm-param class-string $className */ public function hasTestClassPassed(string $className): bool { return in_array($className, $this->passedTestClasses, true); } public function hasTestMethodPassed(string $method): bool { return isset($this->passedTestMethods[$method]); } public function isGreaterThan(string $method, TestSize $other): bool { if ($other->isUnknown()) { return false; } assert($other instanceof Known); $size = $this->passedTestMethods[$method]['size']; if ($size->isUnknown()) { return false; } assert($size instanceof Known); return $size->isGreaterThan($other); } public function returnValue(string $method): mixed { if (isset($this->passedTestMethods[$method])) { return $this->passedTestMethods[$method]['returnValue']; } return null; } } TestResult/TestResult.php 0000644 00000037552 15111200076 0011516 0 ustar 00 <?php declare(strict_types=1); /* * This file is part of PHPUnit. * * (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 PHPUnit\TestRunner\TestResult; use function count; use PHPUnit\Event\Test\BeforeFirstTestMethodErrored; use PHPUnit\Event\Test\ConsideredRisky; use PHPUnit\Event\Test\Errored; use PHPUnit\Event\Test\Failed; use PHPUnit\Event\Test\MarkedIncomplete; use PHPUnit\Event\Test\PhpunitDeprecationTriggered; use PHPUnit\Event\Test\PhpunitErrorTriggered; use PHPUnit\Event\Test\PhpunitWarningTriggered; use PHPUnit\Event\Test\Skipped as TestSkipped; use PHPUnit\Event\TestRunner\DeprecationTriggered as TestRunnerDeprecationTriggered; use PHPUnit\Event\TestRunner\WarningTriggered as TestRunnerWarningTriggered; use PHPUnit\Event\TestSuite\Skipped as TestSuiteSkipped; use PHPUnit\TestRunner\TestResult\Issues\Issue; /** * @internal This class is not covered by the backward compatibility promise for PHPUnit */ final class TestResult { private readonly int $numberOfTests; private readonly int $numberOfTestsRun; private readonly int $numberOfAssertions; /** * @psalm-var list<BeforeFirstTestMethodErrored|Errored> */ private readonly array $testErroredEvents; /** * @psalm-var list<Failed> */ private readonly array $testFailedEvents; /** * @psalm-var list<MarkedIncomplete> */ private readonly array $testMarkedIncompleteEvents; /** * @psalm-var list<TestSuiteSkipped> */ private readonly array $testSuiteSkippedEvents; /** * @psalm-var list<TestSkipped> */ private readonly array $testSkippedEvents; /** * @psalm-var array<string,list<ConsideredRisky>> */ private readonly array $testConsideredRiskyEvents; /** * @psalm-var array<string,list<PhpunitDeprecationTriggered>> */ private readonly array $testTriggeredPhpunitDeprecationEvents; /** * @psalm-var array<string,list<PhpunitErrorTriggered>> */ private readonly array $testTriggeredPhpunitErrorEvents; /** * @psalm-var array<string,list<PhpunitWarningTriggered>> */ private readonly array $testTriggeredPhpunitWarningEvents; /** * @psalm-var list<TestRunnerDeprecationTriggered> */ private readonly array $testRunnerTriggeredDeprecationEvents; /** * @psalm-var list<TestRunnerWarningTriggered> */ private readonly array $testRunnerTriggeredWarningEvents; /** * @psalm-var list<Issue> */ private readonly array $errors; /** * @psalm-var list<Issue> */ private readonly array $deprecations; /** * @psalm-var list<Issue> */ private readonly array $notices; /** * @psalm-var list<Issue> */ private readonly array $warnings; /** * @psalm-var list<Issue> */ private readonly array $phpDeprecations; /** * @psalm-var list<Issue> */ private readonly array $phpNotices; /** * @psalm-var list<Issue> */ private readonly array $phpWarnings; /** * @psalm-var non-negative-int */ private readonly int $numberOfIssuesIgnoredByBaseline; /** * @psalm-param list<BeforeFirstTestMethodErrored|Errored> $testErroredEvents * @psalm-param list<Failed> $testFailedEvents * @psalm-param array<string,list<ConsideredRisky>> $testConsideredRiskyEvents * @psalm-param list<TestSuiteSkipped> $testSuiteSkippedEvents * @psalm-param list<TestSkipped> $testSkippedEvents * @psalm-param list<MarkedIncomplete> $testMarkedIncompleteEvents * @psalm-param array<string,list<PhpunitDeprecationTriggered>> $testTriggeredPhpunitDeprecationEvents * @psalm-param array<string,list<PhpunitErrorTriggered>> $testTriggeredPhpunitErrorEvents * @psalm-param array<string,list<PhpunitWarningTriggered>> $testTriggeredPhpunitWarningEvents * @psalm-param list<TestRunnerDeprecationTriggered> $testRunnerTriggeredDeprecationEvents * @psalm-param list<TestRunnerWarningTriggered> $testRunnerTriggeredWarningEvents * @psalm-param list<Issue> $errors * @psalm-param list<Issue> $deprecations * @psalm-param list<Issue> $notices * @psalm-param list<Issue> $warnings * @psalm-param list<Issue> $phpDeprecations * @psalm-param list<Issue> $phpNotices * @psalm-param list<Issue> $phpWarnings * @psalm-param non-negative-int $numberOfIssuesIgnoredByBaseline */ public function __construct(int $numberOfTests, int $numberOfTestsRun, int $numberOfAssertions, array $testErroredEvents, array $testFailedEvents, array $testConsideredRiskyEvents, array $testSuiteSkippedEvents, array $testSkippedEvents, array $testMarkedIncompleteEvents, array $testTriggeredPhpunitDeprecationEvents, array $testTriggeredPhpunitErrorEvents, array $testTriggeredPhpunitWarningEvents, array $testRunnerTriggeredDeprecationEvents, array $testRunnerTriggeredWarningEvents, array $errors, array $deprecations, array $notices, array $warnings, array $phpDeprecations, array $phpNotices, array $phpWarnings, int $numberOfIssuesIgnoredByBaseline) { $this->numberOfTests = $numberOfTests; $this->numberOfTestsRun = $numberOfTestsRun; $this->numberOfAssertions = $numberOfAssertions; $this->testErroredEvents = $testErroredEvents; $this->testFailedEvents = $testFailedEvents; $this->testConsideredRiskyEvents = $testConsideredRiskyEvents; $this->testSuiteSkippedEvents = $testSuiteSkippedEvents; $this->testSkippedEvents = $testSkippedEvents; $this->testMarkedIncompleteEvents = $testMarkedIncompleteEvents; $this->testTriggeredPhpunitDeprecationEvents = $testTriggeredPhpunitDeprecationEvents; $this->testTriggeredPhpunitErrorEvents = $testTriggeredPhpunitErrorEvents; $this->testTriggeredPhpunitWarningEvents = $testTriggeredPhpunitWarningEvents; $this->testRunnerTriggeredDeprecationEvents = $testRunnerTriggeredDeprecationEvents; $this->testRunnerTriggeredWarningEvents = $testRunnerTriggeredWarningEvents; $this->errors = $errors; $this->deprecations = $deprecations; $this->notices = $notices; $this->warnings = $warnings; $this->phpDeprecations = $phpDeprecations; $this->phpNotices = $phpNotices; $this->phpWarnings = $phpWarnings; $this->numberOfIssuesIgnoredByBaseline = $numberOfIssuesIgnoredByBaseline; } public function numberOfTestsRun(): int { return $this->numberOfTestsRun; } public function numberOfAssertions(): int { return $this->numberOfAssertions; } /** * @psalm-return list<BeforeFirstTestMethodErrored|Errored> */ public function testErroredEvents(): array { return $this->testErroredEvents; } public function numberOfTestErroredEvents(): int { return count($this->testErroredEvents); } public function hasTestErroredEvents(): bool { return $this->numberOfTestErroredEvents() > 0; } /** * @psalm-return list<Failed> */ public function testFailedEvents(): array { return $this->testFailedEvents; } public function numberOfTestFailedEvents(): int { return count($this->testFailedEvents); } public function hasTestFailedEvents(): bool { return $this->numberOfTestFailedEvents() > 0; } /** * @psalm-return array<string,list<ConsideredRisky>> */ public function testConsideredRiskyEvents(): array { return $this->testConsideredRiskyEvents; } public function numberOfTestsWithTestConsideredRiskyEvents(): int { return count($this->testConsideredRiskyEvents); } public function hasTestConsideredRiskyEvents(): bool { return $this->numberOfTestsWithTestConsideredRiskyEvents() > 0; } /** * @psalm-return list<TestSuiteSkipped> */ public function testSuiteSkippedEvents(): array { return $this->testSuiteSkippedEvents; } public function numberOfTestSuiteSkippedEvents(): int { return count($this->testSuiteSkippedEvents); } public function hasTestSuiteSkippedEvents(): bool { return $this->numberOfTestSuiteSkippedEvents() > 0; } /** * @psalm-return list<TestSkipped> */ public function testSkippedEvents(): array { return $this->testSkippedEvents; } public function numberOfTestSkippedEvents(): int { return count($this->testSkippedEvents); } public function hasTestSkippedEvents(): bool { return $this->numberOfTestSkippedEvents() > 0; } /** * @psalm-return list<MarkedIncomplete> */ public function testMarkedIncompleteEvents(): array { return $this->testMarkedIncompleteEvents; } public function numberOfTestMarkedIncompleteEvents(): int { return count($this->testMarkedIncompleteEvents); } public function hasTestMarkedIncompleteEvents(): bool { return $this->numberOfTestMarkedIncompleteEvents() > 0; } /** * @psalm-return array<string,list<PhpunitDeprecationTriggered>> */ public function testTriggeredPhpunitDeprecationEvents(): array { return $this->testTriggeredPhpunitDeprecationEvents; } public function numberOfTestsWithTestTriggeredPhpunitDeprecationEvents(): int { return count($this->testTriggeredPhpunitDeprecationEvents); } public function hasTestTriggeredPhpunitDeprecationEvents(): bool { return $this->numberOfTestsWithTestTriggeredPhpunitDeprecationEvents() > 0; } /** * @psalm-return array<string,list<PhpunitErrorTriggered>> */ public function testTriggeredPhpunitErrorEvents(): array { return $this->testTriggeredPhpunitErrorEvents; } public function numberOfTestsWithTestTriggeredPhpunitErrorEvents(): int { return count($this->testTriggeredPhpunitErrorEvents); } public function hasTestTriggeredPhpunitErrorEvents(): bool { return $this->numberOfTestsWithTestTriggeredPhpunitErrorEvents() > 0; } /** * @psalm-return array<string,list<PhpunitWarningTriggered>> */ public function testTriggeredPhpunitWarningEvents(): array { return $this->testTriggeredPhpunitWarningEvents; } public function numberOfTestsWithTestTriggeredPhpunitWarningEvents(): int { return count($this->testTriggeredPhpunitWarningEvents); } public function hasTestTriggeredPhpunitWarningEvents(): bool { return $this->numberOfTestsWithTestTriggeredPhpunitWarningEvents() > 0; } /** * @psalm-return list<TestRunnerDeprecationTriggered> */ public function testRunnerTriggeredDeprecationEvents(): array { return $this->testRunnerTriggeredDeprecationEvents; } public function numberOfTestRunnerTriggeredDeprecationEvents(): int { return count($this->testRunnerTriggeredDeprecationEvents); } public function hasTestRunnerTriggeredDeprecationEvents(): bool { return $this->numberOfTestRunnerTriggeredDeprecationEvents() > 0; } /** * @psalm-return list<TestRunnerWarningTriggered> */ public function testRunnerTriggeredWarningEvents(): array { return $this->testRunnerTriggeredWarningEvents; } public function numberOfTestRunnerTriggeredWarningEvents(): int { return count($this->testRunnerTriggeredWarningEvents); } public function hasTestRunnerTriggeredWarningEvents(): bool { return $this->numberOfTestRunnerTriggeredWarningEvents() > 0; } public function wasSuccessful(): bool { return $this->wasSuccessfulIgnoringPhpunitWarnings() && !$this->hasTestTriggeredPhpunitErrorEvents() && !$this->hasTestRunnerTriggeredWarningEvents() && !$this->hasTestTriggeredPhpunitWarningEvents(); } public function wasSuccessfulIgnoringPhpunitWarnings(): bool { return !$this->hasTestErroredEvents() && !$this->hasTestFailedEvents(); } public function wasSuccessfulAndNoTestHasIssues(): bool { return $this->wasSuccessful() && !$this->hasTestsWithIssues(); } public function hasTestsWithIssues(): bool { return $this->hasRiskyTests() || $this->hasIncompleteTests() || $this->hasDeprecations() || !empty($this->errors) || $this->hasNotices() || $this->hasWarnings(); } /** * @psalm-return list<Issue> */ public function errors(): array { return $this->errors; } /** * @psalm-return list<Issue> */ public function deprecations(): array { return $this->deprecations; } /** * @psalm-return list<Issue> */ public function notices(): array { return $this->notices; } /** * @psalm-return list<Issue> */ public function warnings(): array { return $this->warnings; } /** * @psalm-return list<Issue> */ public function phpDeprecations(): array { return $this->phpDeprecations; } /** * @psalm-return list<Issue> */ public function phpNotices(): array { return $this->phpNotices; } /** * @psalm-return list<Issue> */ public function phpWarnings(): array { return $this->phpWarnings; } public function hasTests(): bool { return $this->numberOfTests > 0; } public function hasErrors(): bool { return $this->numberOfErrors() > 0; } public function numberOfErrors(): int { return $this->numberOfTestErroredEvents() + count($this->errors) + $this->numberOfTestsWithTestTriggeredPhpunitErrorEvents(); } public function hasDeprecations(): bool { return $this->numberOfDeprecations() > 0; } public function numberOfDeprecations(): int { return count($this->deprecations) + count($this->phpDeprecations) + count($this->testTriggeredPhpunitDeprecationEvents) + count($this->testRunnerTriggeredDeprecationEvents); } public function hasNotices(): bool { return $this->numberOfNotices() > 0; } public function numberOfNotices(): int { return count($this->notices) + count($this->phpNotices); } public function hasWarnings(): bool { return $this->numberOfWarnings() > 0; } public function numberOfWarnings(): int { return count($this->warnings) + count($this->phpWarnings) + count($this->testTriggeredPhpunitWarningEvents) + count($this->testRunnerTriggeredWarningEvents); } public function hasIncompleteTests(): bool { return !empty($this->testMarkedIncompleteEvents); } public function hasRiskyTests(): bool { return !empty($this->testConsideredRiskyEvents); } public function hasSkippedTests(): bool { return !empty($this->testSkippedEvents); } public function hasIssuesIgnoredByBaseline(): bool { return $this->numberOfIssuesIgnoredByBaseline > 0; } /** * @psalm-return non-negative-int */ public function numberOfIssuesIgnoredByBaseline(): int { return $this->numberOfIssuesIgnoredByBaseline; } } TestResult/Collector.php 0000644 00000045440 15111200076 0011321 0 ustar 00 <?php declare(strict_types=1); /* * This file is part of PHPUnit. * * (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 PHPUnit\TestRunner\TestResult; use function array_values; use function assert; use function implode; use function str_contains; use PHPUnit\Event\Code\TestMethod; use PHPUnit\Event\EventFacadeIsSealedException; use PHPUnit\Event\Facade; use PHPUnit\Event\Test\BeforeFirstTestMethodErrored; use PHPUnit\Event\Test\ConsideredRisky; use PHPUnit\Event\Test\DeprecationTriggered; use PHPUnit\Event\Test\Errored; use PHPUnit\Event\Test\ErrorTriggered; use PHPUnit\Event\Test\Failed; use PHPUnit\Event\Test\Finished; use PHPUnit\Event\Test\MarkedIncomplete; use PHPUnit\Event\Test\NoticeTriggered; use PHPUnit\Event\Test\PhpDeprecationTriggered; use PHPUnit\Event\Test\PhpNoticeTriggered; use PHPUnit\Event\Test\PhpunitDeprecationTriggered; use PHPUnit\Event\Test\PhpunitErrorTriggered; use PHPUnit\Event\Test\PhpunitWarningTriggered; use PHPUnit\Event\Test\PhpWarningTriggered; use PHPUnit\Event\Test\Skipped as TestSkipped; use PHPUnit\Event\Test\WarningTriggered; use PHPUnit\Event\TestData\NoDataSetFromDataProviderException; use PHPUnit\Event\TestRunner\DeprecationTriggered as TestRunnerDeprecationTriggered; use PHPUnit\Event\TestRunner\ExecutionStarted; use PHPUnit\Event\TestRunner\WarningTriggered as TestRunnerWarningTriggered; use PHPUnit\Event\TestSuite\Finished as TestSuiteFinished; use PHPUnit\Event\TestSuite\Skipped as TestSuiteSkipped; use PHPUnit\Event\TestSuite\Started as TestSuiteStarted; use PHPUnit\Event\TestSuite\TestSuiteForTestClass; use PHPUnit\Event\TestSuite\TestSuiteForTestMethodWithDataProvider; use PHPUnit\Event\UnknownSubscriberTypeException; use PHPUnit\TestRunner\TestResult\Issues\Issue; use PHPUnit\TextUI\Configuration\Source; use PHPUnit\TextUI\Configuration\SourceFilter; /** * @internal This class is not covered by the backward compatibility promise for PHPUnit */ final class Collector { private readonly Source $source; private int $numberOfTests = 0; private int $numberOfTestsRun = 0; private int $numberOfAssertions = 0; private bool $prepared = false; private bool $currentTestSuiteForTestClassFailed = false; /** * @psalm-var non-negative-int */ private int $numberOfIssuesIgnoredByBaseline = 0; /** * @psalm-var list<BeforeFirstTestMethodErrored|Errored> */ private array $testErroredEvents = []; /** * @psalm-var list<Failed> */ private array $testFailedEvents = []; /** * @psalm-var list<MarkedIncomplete> */ private array $testMarkedIncompleteEvents = []; /** * @psalm-var list<TestSuiteSkipped> */ private array $testSuiteSkippedEvents = []; /** * @psalm-var list<TestSkipped> */ private array $testSkippedEvents = []; /** * @psalm-var array<string,list<ConsideredRisky>> */ private array $testConsideredRiskyEvents = []; /** * @psalm-var array<string,list<PhpunitDeprecationTriggered>> */ private array $testTriggeredPhpunitDeprecationEvents = []; /** * @psalm-var array<string,list<PhpunitErrorTriggered>> */ private array $testTriggeredPhpunitErrorEvents = []; /** * @psalm-var array<string,list<PhpunitWarningTriggered>> */ private array $testTriggeredPhpunitWarningEvents = []; /** * @psalm-var list<TestRunnerWarningTriggered> */ private array $testRunnerTriggeredWarningEvents = []; /** * @psalm-var list<TestRunnerDeprecationTriggered> */ private array $testRunnerTriggeredDeprecationEvents = []; /** * @psalm-var array<non-empty-string, Issue> */ private array $errors = []; /** * @psalm-var array<non-empty-string, Issue> */ private array $deprecations = []; /** * @psalm-var array<non-empty-string, Issue> */ private array $notices = []; /** * @psalm-var array<non-empty-string, Issue> */ private array $warnings = []; /** * @psalm-var array<non-empty-string, Issue> */ private array $phpDeprecations = []; /** * @psalm-var array<non-empty-string, Issue> */ private array $phpNotices = []; /** * @psalm-var array<non-empty-string, Issue> */ private array $phpWarnings = []; /** * @throws EventFacadeIsSealedException * @throws UnknownSubscriberTypeException */ public function __construct(Facade $facade, Source $source) { $facade->registerSubscribers( new ExecutionStartedSubscriber($this), new TestSuiteSkippedSubscriber($this), new TestSuiteStartedSubscriber($this), new TestSuiteFinishedSubscriber($this), new TestPreparedSubscriber($this), new TestFinishedSubscriber($this), new BeforeTestClassMethodErroredSubscriber($this), new TestErroredSubscriber($this), new TestFailedSubscriber($this), new TestMarkedIncompleteSubscriber($this), new TestSkippedSubscriber($this), new TestConsideredRiskySubscriber($this), new TestTriggeredDeprecationSubscriber($this), new TestTriggeredErrorSubscriber($this), new TestTriggeredNoticeSubscriber($this), new TestTriggeredPhpDeprecationSubscriber($this), new TestTriggeredPhpNoticeSubscriber($this), new TestTriggeredPhpunitDeprecationSubscriber($this), new TestTriggeredPhpunitErrorSubscriber($this), new TestTriggeredPhpunitWarningSubscriber($this), new TestTriggeredPhpWarningSubscriber($this), new TestTriggeredWarningSubscriber($this), new TestRunnerTriggeredDeprecationSubscriber($this), new TestRunnerTriggeredWarningSubscriber($this), ); $this->source = $source; } public function result(): TestResult { return new TestResult( $this->numberOfTests, $this->numberOfTestsRun, $this->numberOfAssertions, $this->testErroredEvents, $this->testFailedEvents, $this->testConsideredRiskyEvents, $this->testSuiteSkippedEvents, $this->testSkippedEvents, $this->testMarkedIncompleteEvents, $this->testTriggeredPhpunitDeprecationEvents, $this->testTriggeredPhpunitErrorEvents, $this->testTriggeredPhpunitWarningEvents, $this->testRunnerTriggeredDeprecationEvents, $this->testRunnerTriggeredWarningEvents, array_values($this->errors), array_values($this->deprecations), array_values($this->notices), array_values($this->warnings), array_values($this->phpDeprecations), array_values($this->phpNotices), array_values($this->phpWarnings), $this->numberOfIssuesIgnoredByBaseline, ); } public function executionStarted(ExecutionStarted $event): void { $this->numberOfTests = $event->testSuite()->count(); } public function testSuiteSkipped(TestSuiteSkipped $event): void { $testSuite = $event->testSuite(); if (!$testSuite->isForTestClass()) { return; } $this->testSuiteSkippedEvents[] = $event; } public function testSuiteStarted(TestSuiteStarted $event): void { $testSuite = $event->testSuite(); if (!$testSuite->isForTestClass()) { return; } $this->currentTestSuiteForTestClassFailed = false; } /** * @throws NoDataSetFromDataProviderException */ public function testSuiteFinished(TestSuiteFinished $event): void { if ($this->currentTestSuiteForTestClassFailed) { return; } $testSuite = $event->testSuite(); if ($testSuite->isWithName()) { return; } if ($testSuite->isForTestMethodWithDataProvider()) { assert($testSuite instanceof TestSuiteForTestMethodWithDataProvider); $test = $testSuite->tests()->asArray()[0]; assert($test instanceof TestMethod); PassedTests::instance()->testMethodPassed($test, null); return; } assert($testSuite instanceof TestSuiteForTestClass); PassedTests::instance()->testClassPassed($testSuite->className()); } public function testPrepared(): void { $this->prepared = true; } public function testFinished(Finished $event): void { $this->numberOfAssertions += $event->numberOfAssertionsPerformed(); $this->numberOfTestsRun++; $this->prepared = false; } public function beforeTestClassMethodErrored(BeforeFirstTestMethodErrored $event): void { $this->testErroredEvents[] = $event; $this->numberOfTestsRun++; } public function testErrored(Errored $event): void { $this->testErroredEvents[] = $event; $this->currentTestSuiteForTestClassFailed = true; /* * @todo Eliminate this special case */ if (str_contains($event->asString(), 'Test was run in child process and ended unexpectedly')) { return; } if (!$this->prepared) { $this->numberOfTestsRun++; } } public function testFailed(Failed $event): void { $this->testFailedEvents[] = $event; $this->currentTestSuiteForTestClassFailed = true; } public function testMarkedIncomplete(MarkedIncomplete $event): void { $this->testMarkedIncompleteEvents[] = $event; } public function testSkipped(TestSkipped $event): void { $this->testSkippedEvents[] = $event; if (!$this->prepared) { $this->numberOfTestsRun++; } } public function testConsideredRisky(ConsideredRisky $event): void { if (!isset($this->testConsideredRiskyEvents[$event->test()->id()])) { $this->testConsideredRiskyEvents[$event->test()->id()] = []; } $this->testConsideredRiskyEvents[$event->test()->id()][] = $event; } public function testTriggeredDeprecation(DeprecationTriggered $event): void { if ($event->ignoredByBaseline()) { $this->numberOfIssuesIgnoredByBaseline++; return; } if (!$this->source->ignoreSuppressionOfDeprecations() && $event->wasSuppressed()) { return; } if ($this->source->restrictDeprecations() && !(new SourceFilter)->includes($this->source, $event->file())) { return; } $id = $this->issueId($event); if (!isset($this->deprecations[$id])) { $this->deprecations[$id] = Issue::from( $event->file(), $event->line(), $event->message(), $event->test(), ); return; } $this->deprecations[$id]->triggeredBy($event->test()); } public function testTriggeredPhpDeprecation(PhpDeprecationTriggered $event): void { if ($event->ignoredByBaseline()) { $this->numberOfIssuesIgnoredByBaseline++; return; } if (!$this->source->ignoreSuppressionOfPhpDeprecations() && $event->wasSuppressed()) { return; } if ($this->source->restrictDeprecations() && !(new SourceFilter)->includes($this->source, $event->file())) { return; } $id = $this->issueId($event); if (!isset($this->phpDeprecations[$id])) { $this->phpDeprecations[$id] = Issue::from( $event->file(), $event->line(), $event->message(), $event->test(), ); return; } $this->phpDeprecations[$id]->triggeredBy($event->test()); } public function testTriggeredPhpunitDeprecation(PhpunitDeprecationTriggered $event): void { if (!isset($this->testTriggeredPhpunitDeprecationEvents[$event->test()->id()])) { $this->testTriggeredPhpunitDeprecationEvents[$event->test()->id()] = []; } $this->testTriggeredPhpunitDeprecationEvents[$event->test()->id()][] = $event; } public function testTriggeredError(ErrorTriggered $event): void { if (!$this->source->ignoreSuppressionOfErrors() && $event->wasSuppressed()) { return; } $id = $this->issueId($event); if (!isset($this->errors[$id])) { $this->errors[$id] = Issue::from( $event->file(), $event->line(), $event->message(), $event->test(), ); return; } $this->errors[$id]->triggeredBy($event->test()); } public function testTriggeredNotice(NoticeTriggered $event): void { if ($event->ignoredByBaseline()) { $this->numberOfIssuesIgnoredByBaseline++; return; } if (!$this->source->ignoreSuppressionOfNotices() && $event->wasSuppressed()) { return; } if ($this->source->restrictNotices() && !(new SourceFilter)->includes($this->source, $event->file())) { return; } $id = $this->issueId($event); if (!isset($this->notices[$id])) { $this->notices[$id] = Issue::from( $event->file(), $event->line(), $event->message(), $event->test(), ); return; } $this->notices[$id]->triggeredBy($event->test()); } public function testTriggeredPhpNotice(PhpNoticeTriggered $event): void { if ($event->ignoredByBaseline()) { $this->numberOfIssuesIgnoredByBaseline++; return; } if (!$this->source->ignoreSuppressionOfPhpNotices() && $event->wasSuppressed()) { return; } if ($this->source->restrictNotices() && !(new SourceFilter)->includes($this->source, $event->file())) { return; } $id = $this->issueId($event); if (!isset($this->phpNotices[$id])) { $this->phpNotices[$id] = Issue::from( $event->file(), $event->line(), $event->message(), $event->test(), ); return; } $this->phpNotices[$id]->triggeredBy($event->test()); } public function testTriggeredWarning(WarningTriggered $event): void { if ($event->ignoredByBaseline()) { $this->numberOfIssuesIgnoredByBaseline++; return; } if (!$this->source->ignoreSuppressionOfWarnings() && $event->wasSuppressed()) { return; } if ($this->source->restrictWarnings() && !(new SourceFilter)->includes($this->source, $event->file())) { return; } $id = $this->issueId($event); if (!isset($this->warnings[$id])) { $this->warnings[$id] = Issue::from( $event->file(), $event->line(), $event->message(), $event->test(), ); return; } $this->warnings[$id]->triggeredBy($event->test()); } public function testTriggeredPhpWarning(PhpWarningTriggered $event): void { if ($event->ignoredByBaseline()) { $this->numberOfIssuesIgnoredByBaseline++; return; } if (!$this->source->ignoreSuppressionOfPhpWarnings() && $event->wasSuppressed()) { return; } if ($this->source->restrictWarnings() && !(new SourceFilter)->includes($this->source, $event->file())) { return; } $id = $this->issueId($event); if (!isset($this->phpWarnings[$id])) { $this->phpWarnings[$id] = Issue::from( $event->file(), $event->line(), $event->message(), $event->test(), ); return; } $this->phpWarnings[$id]->triggeredBy($event->test()); } public function testTriggeredPhpunitError(PhpunitErrorTriggered $event): void { if (!isset($this->testTriggeredPhpunitErrorEvents[$event->test()->id()])) { $this->testTriggeredPhpunitErrorEvents[$event->test()->id()] = []; } $this->testTriggeredPhpunitErrorEvents[$event->test()->id()][] = $event; } public function testTriggeredPhpunitWarning(PhpunitWarningTriggered $event): void { if (!isset($this->testTriggeredPhpunitWarningEvents[$event->test()->id()])) { $this->testTriggeredPhpunitWarningEvents[$event->test()->id()] = []; } $this->testTriggeredPhpunitWarningEvents[$event->test()->id()][] = $event; } public function testRunnerTriggeredDeprecation(TestRunnerDeprecationTriggered $event): void { $this->testRunnerTriggeredDeprecationEvents[] = $event; } public function testRunnerTriggeredWarning(TestRunnerWarningTriggered $event): void { $this->testRunnerTriggeredWarningEvents[] = $event; } public function hasErroredTests(): bool { return !empty($this->testErroredEvents); } public function hasFailedTests(): bool { return !empty($this->testFailedEvents); } public function hasRiskyTests(): bool { return !empty($this->testConsideredRiskyEvents); } public function hasSkippedTests(): bool { return !empty($this->testSkippedEvents); } public function hasIncompleteTests(): bool { return !empty($this->testMarkedIncompleteEvents); } public function hasDeprecations(): bool { return !empty($this->deprecations) || !empty($this->phpDeprecations) || !empty($this->testTriggeredPhpunitDeprecationEvents) || !empty($this->testRunnerTriggeredDeprecationEvents); } public function hasNotices(): bool { return !empty($this->notices) || !empty($this->phpNotices); } public function hasWarnings(): bool { return !empty($this->warnings) || !empty($this->phpWarnings) || !empty($this->testTriggeredPhpunitWarningEvents) || !empty($this->testRunnerTriggeredWarningEvents); } /** * @psalm-return non-empty-string */ private function issueId(DeprecationTriggered|ErrorTriggered|NoticeTriggered|PhpDeprecationTriggered|PhpNoticeTriggered|PhpWarningTriggered|WarningTriggered $event): string { return implode(':', [$event->file(), $event->line(), $event->message()]); } } TestResult/Subscriber/TestTriggeredErrorSubscriber.php 0000644 00000001301 15111200076 0017274 0 ustar 00 <?php declare(strict_types=1); /* * This file is part of PHPUnit. * * (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 PHPUnit\TestRunner\TestResult; use PHPUnit\Event\Test\ErrorTriggered; use PHPUnit\Event\Test\ErrorTriggeredSubscriber; /** * @internal This class is not covered by the backward compatibility promise for PHPUnit */ final class TestTriggeredErrorSubscriber extends Subscriber implements ErrorTriggeredSubscriber { public function notify(ErrorTriggered $event): void { $this->collector()->testTriggeredError($event); } } TestResult/Subscriber/TestSuiteSkippedSubscriber.php 0000644 00000001253 15111200076 0016765 0 ustar 00 <?php declare(strict_types=1); /* * This file is part of PHPUnit. * * (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 PHPUnit\TestRunner\TestResult; use PHPUnit\Event\TestSuite\Skipped; use PHPUnit\Event\TestSuite\SkippedSubscriber; /** * @internal This class is not covered by the backward compatibility promise for PHPUnit */ final class TestSuiteSkippedSubscriber extends Subscriber implements SkippedSubscriber { public function notify(Skipped $event): void { $this->collector()->testSuiteSkipped($event); } } TestResult/Subscriber/TestSkippedSubscriber.php 0000644 00000001227 15111200076 0015754 0 ustar 00 <?php declare(strict_types=1); /* * This file is part of PHPUnit. * * (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 PHPUnit\TestRunner\TestResult; use PHPUnit\Event\Test\Skipped; use PHPUnit\Event\Test\SkippedSubscriber; /** * @internal This class is not covered by the backward compatibility promise for PHPUnit */ final class TestSkippedSubscriber extends Subscriber implements SkippedSubscriber { public function notify(Skipped $event): void { $this->collector()->testSkipped($event); } } TestResult/Subscriber/TestTriggeredPhpunitWarningSubscriber.php 0000644 00000001367 15111200076 0021174 0 ustar 00 <?php declare(strict_types=1); /* * This file is part of PHPUnit. * * (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 PHPUnit\TestRunner\TestResult; use PHPUnit\Event\Test\PhpunitWarningTriggered; use PHPUnit\Event\Test\PhpunitWarningTriggeredSubscriber; /** * @internal This class is not covered by the backward compatibility promise for PHPUnit */ final class TestTriggeredPhpunitWarningSubscriber extends Subscriber implements PhpunitWarningTriggeredSubscriber { public function notify(PhpunitWarningTriggered $event): void { $this->collector()->testTriggeredPhpunitWarning($event); } } TestResult/Subscriber/TestTriggeredPhpunitDeprecationSubscriber.php 0000644 00000001417 15111200076 0022020 0 ustar 00 <?php declare(strict_types=1); /* * This file is part of PHPUnit. * * (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 PHPUnit\TestRunner\TestResult; use PHPUnit\Event\Test\PhpunitDeprecationTriggered; use PHPUnit\Event\Test\PhpunitDeprecationTriggeredSubscriber; /** * @internal This class is not covered by the backward compatibility promise for PHPUnit */ final class TestTriggeredPhpunitDeprecationSubscriber extends Subscriber implements PhpunitDeprecationTriggeredSubscriber { public function notify(PhpunitDeprecationTriggered $event): void { $this->collector()->testTriggeredPhpunitDeprecation($event); } } TestResult/Subscriber/ExecutionStartedSubscriber.php 0000644 00000001403 15111200076 0017003 0 ustar 00 <?php declare(strict_types=1); /* * This file is part of PHPUnit. * * (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 PHPUnit\TestRunner\TestResult; use PHPUnit\Event\TestRunner\ExecutionStarted; use PHPUnit\Event\TestRunner\ExecutionStartedSubscriber as TestRunnerExecutionStartedSubscriber; /** * @internal This class is not covered by the backward compatibility promise for PHPUnit */ final class ExecutionStartedSubscriber extends Subscriber implements TestRunnerExecutionStartedSubscriber { public function notify(ExecutionStarted $event): void { $this->collector()->executionStarted($event); } } TestResult/Subscriber/TestTriggeredNoticeSubscriber.php 0000644 00000001307 15111200076 0017432 0 ustar 00 <?php declare(strict_types=1); /* * This file is part of PHPUnit. * * (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 PHPUnit\TestRunner\TestResult; use PHPUnit\Event\Test\NoticeTriggered; use PHPUnit\Event\Test\NoticeTriggeredSubscriber; /** * @internal This class is not covered by the backward compatibility promise for PHPUnit */ final class TestTriggeredNoticeSubscriber extends Subscriber implements NoticeTriggeredSubscriber { public function notify(NoticeTriggered $event): void { $this->collector()->testTriggeredNotice($event); } } TestResult/Subscriber/Subscriber.php 0000644 00000001227 15111200076 0013574 0 ustar 00 <?php declare(strict_types=1); /* * This file is part of PHPUnit. * * (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 PHPUnit\TestRunner\TestResult; /** * @internal This class is not covered by the backward compatibility promise for PHPUnit */ abstract class Subscriber { private readonly Collector $collector; public function __construct(Collector $collector) { $this->collector = $collector; } protected function collector(): Collector { return $this->collector; } } TestResult/Subscriber/TestTriggeredPhpunitErrorSubscriber.php 0000644 00000001353 15111200076 0020653 0 ustar 00 <?php declare(strict_types=1); /* * This file is part of PHPUnit. * * (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 PHPUnit\TestRunner\TestResult; use PHPUnit\Event\Test\PhpunitErrorTriggered; use PHPUnit\Event\Test\PhpunitErrorTriggeredSubscriber; /** * @internal This class is not covered by the backward compatibility promise for PHPUnit */ final class TestTriggeredPhpunitErrorSubscriber extends Subscriber implements PhpunitErrorTriggeredSubscriber { public function notify(PhpunitErrorTriggered $event): void { $this->collector()->testTriggeredPhpunitError($event); } } TestResult/Subscriber/TestTriggeredPhpWarningSubscriber.php 0000644 00000001337 15111200076 0020271 0 ustar 00 <?php declare(strict_types=1); /* * This file is part of PHPUnit. * * (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 PHPUnit\TestRunner\TestResult; use PHPUnit\Event\Test\PhpWarningTriggered; use PHPUnit\Event\Test\PhpWarningTriggeredSubscriber; /** * @internal This class is not covered by the backward compatibility promise for PHPUnit */ final class TestTriggeredPhpWarningSubscriber extends Subscriber implements PhpWarningTriggeredSubscriber { public function notify(PhpWarningTriggered $event): void { $this->collector()->testTriggeredPhpWarning($event); } } TestResult/Subscriber/TestTriggeredDeprecationSubscriber.php 0000644 00000001345 15111200076 0020450 0 ustar 00 <?php declare(strict_types=1); /* * This file is part of PHPUnit. * * (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 PHPUnit\TestRunner\TestResult; use PHPUnit\Event\Test\DeprecationTriggered; use PHPUnit\Event\Test\DeprecationTriggeredSubscriber; /** * @internal This class is not covered by the backward compatibility promise for PHPUnit */ final class TestTriggeredDeprecationSubscriber extends Subscriber implements DeprecationTriggeredSubscriber { public function notify(DeprecationTriggered $event): void { $this->collector()->testTriggeredDeprecation($event); } } TestResult/Subscriber/TestRunnerTriggeredDeprecationSubscriber.php 0000644 00000001375 15111200076 0021645 0 ustar 00 <?php declare(strict_types=1); /* * This file is part of PHPUnit. * * (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 PHPUnit\TestRunner\TestResult; use PHPUnit\Event\TestRunner\DeprecationTriggered; use PHPUnit\Event\TestRunner\DeprecationTriggeredSubscriber; /** * @internal This class is not covered by the backward compatibility promise for PHPUnit */ final class TestRunnerTriggeredDeprecationSubscriber extends Subscriber implements DeprecationTriggeredSubscriber { public function notify(DeprecationTriggered $event): void { $this->collector()->testRunnerTriggeredDeprecation($event); } } TestResult/Subscriber/TestSuiteFinishedSubscriber.php 0000644 00000001462 15111200077 0017122 0 ustar 00 <?php declare(strict_types=1); /* * This file is part of PHPUnit. * * (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 PHPUnit\TestRunner\TestResult; use PHPUnit\Event\TestData\NoDataSetFromDataProviderException; use PHPUnit\Event\TestSuite\Finished; use PHPUnit\Event\TestSuite\FinishedSubscriber; /** * @internal This class is not covered by the backward compatibility promise for PHPUnit */ final class TestSuiteFinishedSubscriber extends Subscriber implements FinishedSubscriber { /** * @throws NoDataSetFromDataProviderException */ public function notify(Finished $event): void { $this->collector()->testSuiteFinished($event); } } TestResult/Subscriber/TestMarkedIncompleteSubscriber.php 0000644 00000001315 15111200077 0017577 0 ustar 00 <?php declare(strict_types=1); /* * This file is part of PHPUnit. * * (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 PHPUnit\TestRunner\TestResult; use PHPUnit\Event\Test\MarkedIncomplete; use PHPUnit\Event\Test\MarkedIncompleteSubscriber; /** * @internal This class is not covered by the backward compatibility promise for PHPUnit */ final class TestMarkedIncompleteSubscriber extends Subscriber implements MarkedIncompleteSubscriber { public function notify(MarkedIncomplete $event): void { $this->collector()->testMarkedIncomplete($event); } } TestResult/Subscriber/TestConsideredRiskySubscriber.php 0000644 00000001307 15111200077 0017456 0 ustar 00 <?php declare(strict_types=1); /* * This file is part of PHPUnit. * * (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 PHPUnit\TestRunner\TestResult; use PHPUnit\Event\Test\ConsideredRisky; use PHPUnit\Event\Test\ConsideredRiskySubscriber; /** * @internal This class is not covered by the backward compatibility promise for PHPUnit */ final class TestConsideredRiskySubscriber extends Subscriber implements ConsideredRiskySubscriber { public function notify(ConsideredRisky $event): void { $this->collector()->testConsideredRisky($event); } } TestResult/Subscriber/TestTriggeredWarningSubscriber.php 0000644 00000001315 15111200077 0017616 0 ustar 00 <?php declare(strict_types=1); /* * This file is part of PHPUnit. * * (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 PHPUnit\TestRunner\TestResult; use PHPUnit\Event\Test\WarningTriggered; use PHPUnit\Event\Test\WarningTriggeredSubscriber; /** * @internal This class is not covered by the backward compatibility promise for PHPUnit */ final class TestTriggeredWarningSubscriber extends Subscriber implements WarningTriggeredSubscriber { public function notify(WarningTriggered $event): void { $this->collector()->testTriggeredWarning($event); } } TestResult/Subscriber/TestFailedSubscriber.php 0000644 00000001221 15111200077 0015534 0 ustar 00 <?php declare(strict_types=1); /* * This file is part of PHPUnit. * * (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 PHPUnit\TestRunner\TestResult; use PHPUnit\Event\Test\Failed; use PHPUnit\Event\Test\FailedSubscriber; /** * @internal This class is not covered by the backward compatibility promise for PHPUnit */ final class TestFailedSubscriber extends Subscriber implements FailedSubscriber { public function notify(Failed $event): void { $this->collector()->testFailed($event); } } TestResult/Subscriber/TestSuiteStartedSubscriber.php 0000644 00000001253 15111200077 0016775 0 ustar 00 <?php declare(strict_types=1); /* * This file is part of PHPUnit. * * (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 PHPUnit\TestRunner\TestResult; use PHPUnit\Event\TestSuite\Started; use PHPUnit\Event\TestSuite\StartedSubscriber; /** * @internal This class is not covered by the backward compatibility promise for PHPUnit */ final class TestSuiteStartedSubscriber extends Subscriber implements StartedSubscriber { public function notify(Started $event): void { $this->collector()->testSuiteStarted($event); } } TestResult/Subscriber/TestFinishedSubscriber.php 0000644 00000001235 15111200077 0016106 0 ustar 00 <?php declare(strict_types=1); /* * This file is part of PHPUnit. * * (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 PHPUnit\TestRunner\TestResult; use PHPUnit\Event\Test\Finished; use PHPUnit\Event\Test\FinishedSubscriber; /** * @internal This class is not covered by the backward compatibility promise for PHPUnit */ final class TestFinishedSubscriber extends Subscriber implements FinishedSubscriber { public function notify(Finished $event): void { $this->collector()->testFinished($event); } } TestResult/Subscriber/TestErroredSubscriber.php 0000644 00000001227 15111200077 0015760 0 ustar 00 <?php declare(strict_types=1); /* * This file is part of PHPUnit. * * (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 PHPUnit\TestRunner\TestResult; use PHPUnit\Event\Test\Errored; use PHPUnit\Event\Test\ErroredSubscriber; /** * @internal This class is not covered by the backward compatibility promise for PHPUnit */ final class TestErroredSubscriber extends Subscriber implements ErroredSubscriber { public function notify(Errored $event): void { $this->collector()->testErrored($event); } } TestResult/Subscriber/TestRunnerTriggeredWarningSubscriber.php 0000644 00000001345 15111200077 0021013 0 ustar 00 <?php declare(strict_types=1); /* * This file is part of PHPUnit. * * (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 PHPUnit\TestRunner\TestResult; use PHPUnit\Event\TestRunner\WarningTriggered; use PHPUnit\Event\TestRunner\WarningTriggeredSubscriber; /** * @internal This class is not covered by the backward compatibility promise for PHPUnit */ final class TestRunnerTriggeredWarningSubscriber extends Subscriber implements WarningTriggeredSubscriber { public function notify(WarningTriggered $event): void { $this->collector()->testRunnerTriggeredWarning($event); } } TestResult/Subscriber/TestPreparedSubscriber.php 0000644 00000001227 15111200077 0016120 0 ustar 00 <?php declare(strict_types=1); /* * This file is part of PHPUnit. * * (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 PHPUnit\TestRunner\TestResult; use PHPUnit\Event\Test\Prepared; use PHPUnit\Event\Test\PreparedSubscriber; /** * @internal This class is not covered by the backward compatibility promise for PHPUnit */ final class TestPreparedSubscriber extends Subscriber implements PreparedSubscriber { public function notify(Prepared $event): void { $this->collector()->testPrepared(); } } TestResult/Subscriber/BeforeTestClassMethodErroredSubscriber.php 0000644 00000001415 15111200077 0021231 0 ustar 00 <?php declare(strict_types=1); /* * This file is part of PHPUnit. * * (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 PHPUnit\TestRunner\TestResult; use PHPUnit\Event\Test\BeforeFirstTestMethodErrored; use PHPUnit\Event\Test\BeforeFirstTestMethodErroredSubscriber; /** * @internal This class is not covered by the backward compatibility promise for PHPUnit */ final class BeforeTestClassMethodErroredSubscriber extends Subscriber implements BeforeFirstTestMethodErroredSubscriber { public function notify(BeforeFirstTestMethodErrored $event): void { $this->collector()->beforeTestClassMethodErrored($event); } } TestResult/Subscriber/TestTriggeredPhpNoticeSubscriber.php 0000644 00000001331 15111200077 0020100 0 ustar 00 <?php declare(strict_types=1); /* * This file is part of PHPUnit. * * (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 PHPUnit\TestRunner\TestResult; use PHPUnit\Event\Test\PhpNoticeTriggered; use PHPUnit\Event\Test\PhpNoticeTriggeredSubscriber; /** * @internal This class is not covered by the backward compatibility promise for PHPUnit */ final class TestTriggeredPhpNoticeSubscriber extends Subscriber implements PhpNoticeTriggeredSubscriber { public function notify(PhpNoticeTriggered $event): void { $this->collector()->testTriggeredPhpNotice($event); } } TestResult/Subscriber/TestTriggeredPhpDeprecationSubscriber.php 0000644 00000001367 15111200077 0021125 0 ustar 00 <?php declare(strict_types=1); /* * This file is part of PHPUnit. * * (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 PHPUnit\TestRunner\TestResult; use PHPUnit\Event\Test\PhpDeprecationTriggered; use PHPUnit\Event\Test\PhpDeprecationTriggeredSubscriber; /** * @internal This class is not covered by the backward compatibility promise for PHPUnit */ final class TestTriggeredPhpDeprecationSubscriber extends Subscriber implements PhpDeprecationTriggeredSubscriber { public function notify(PhpDeprecationTriggered $event): void { $this->collector()->testTriggeredPhpDeprecation($event); } } ErrorHandler.php 0000644 00000012261 15111200077 0007640 0 ustar 00 <?php declare(strict_types=1); /* * This file is part of PHPUnit. * * (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 PHPUnit\Runner; use const E_DEPRECATED; use const E_NOTICE; use const E_STRICT; use const E_USER_DEPRECATED; use const E_USER_NOTICE; use const E_USER_WARNING; use const E_WARNING; use function error_reporting; use function restore_error_handler; use function set_error_handler; use PHPUnit\Event; use PHPUnit\Event\Code\NoTestCaseObjectOnCallStackException; use PHPUnit\Runner\Baseline\Baseline; use PHPUnit\Runner\Baseline\Issue; use PHPUnit\Util\ExcludeList; /** * @internal This class is not covered by the backward compatibility promise for PHPUnit */ final class ErrorHandler { private static ?self $instance = null; private ?Baseline $baseline = null; private bool $enabled = false; public static function instance(): self { return self::$instance ?? self::$instance = new self; } /** * @throws NoTestCaseObjectOnCallStackException */ public function __invoke(int $errorNumber, string $errorString, string $errorFile, int $errorLine): bool { $suppressed = !($errorNumber & error_reporting()); if ($suppressed && (new ExcludeList)->isExcluded($errorFile)) { return false; } $ignoredByBaseline = $this->ignoredByBaseline($errorFile, $errorLine, $errorString); switch ($errorNumber) { case E_NOTICE: case E_STRICT: Event\Facade::emitter()->testTriggeredPhpNotice( Event\Code\TestMethodBuilder::fromCallStack(), $errorString, $errorFile, $errorLine, $suppressed, $ignoredByBaseline, ); break; case E_USER_NOTICE: Event\Facade::emitter()->testTriggeredNotice( Event\Code\TestMethodBuilder::fromCallStack(), $errorString, $errorFile, $errorLine, $suppressed, $ignoredByBaseline, ); break; case E_WARNING: Event\Facade::emitter()->testTriggeredPhpWarning( Event\Code\TestMethodBuilder::fromCallStack(), $errorString, $errorFile, $errorLine, $suppressed, $ignoredByBaseline, ); break; case E_USER_WARNING: Event\Facade::emitter()->testTriggeredWarning( Event\Code\TestMethodBuilder::fromCallStack(), $errorString, $errorFile, $errorLine, $suppressed, $ignoredByBaseline, ); break; case E_DEPRECATED: Event\Facade::emitter()->testTriggeredPhpDeprecation( Event\Code\TestMethodBuilder::fromCallStack(), $errorString, $errorFile, $errorLine, $suppressed, $ignoredByBaseline, ); break; case E_USER_DEPRECATED: Event\Facade::emitter()->testTriggeredDeprecation( Event\Code\TestMethodBuilder::fromCallStack(), $errorString, $errorFile, $errorLine, $suppressed, $ignoredByBaseline, ); break; case E_USER_ERROR: Event\Facade::emitter()->testTriggeredError( Event\Code\TestMethodBuilder::fromCallStack(), $errorString, $errorFile, $errorLine, $suppressed, ); break; default: return false; } return true; } public function enable(): void { if ($this->enabled) { return; } $oldErrorHandler = set_error_handler($this); if ($oldErrorHandler !== null) { restore_error_handler(); return; } $this->enabled = true; } public function disable(): void { if (!$this->enabled) { return; } restore_error_handler(); $this->enabled = false; } public function use(Baseline $baseline): void { $this->baseline = $baseline; } /** * @psalm-param non-empty-string $file * @psalm-param positive-int $line * @psalm-param non-empty-string $description */ private function ignoredByBaseline(string $file, int $line, string $description): bool { if ($this->baseline === null) { return false; } return $this->baseline->has(Issue::from($file, $line, null, $description)); } } Extension/ExtensionBootstrapper.php 0000644 00000005240 15111200077 0013605 0 ustar 00 <?php declare(strict_types=1); /* * This file is part of PHPUnit. * * (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 PHPUnit\Runner\Extension; use function assert; use function class_exists; use function class_implements; use function in_array; use function sprintf; use PHPUnit\Event; use PHPUnit\Event\Facade as EventFacade; use PHPUnit\TextUI\Configuration\Configuration; use ReflectionClass; use Throwable; /** * @internal This class is not covered by the backward compatibility promise for PHPUnit */ final class ExtensionBootstrapper { private readonly Configuration $configuration; private readonly Facade $facade; public function __construct(Configuration $configuration, Facade $facade) { $this->configuration = $configuration; $this->facade = $facade; } /** * @psalm-param class-string $className * @psalm-param array<string, string> $parameters */ public function bootstrap(string $className, array $parameters): void { if (!class_exists($className)) { EventFacade::emitter()->testRunnerTriggeredWarning( sprintf( 'Cannot bootstrap extension because class %s does not exist', $className, ), ); return; } if (!in_array(Extension::class, class_implements($className), true)) { EventFacade::emitter()->testRunnerTriggeredWarning( sprintf( 'Cannot bootstrap extension because class %s does not implement interface %s', $className, Extension::class, ), ); return; } try { $instance = (new ReflectionClass($className))->newInstance(); assert($instance instanceof Extension); $instance->bootstrap( $this->configuration, $this->facade, ParameterCollection::fromArray($parameters), ); } catch (Throwable $t) { EventFacade::emitter()->testRunnerTriggeredWarning( sprintf( 'Bootstrapping of extension %s failed: %s%s%s', $className, $t->getMessage(), PHP_EOL, $t->getTraceAsString(), ), ); return; } Event\Facade::emitter()->testRunnerBootstrappedExtension( $className, $parameters, ); } } Extension/Facade.php 0000644 00000005316 15111200077 0010373 0 ustar 00 <?php declare(strict_types=1); /* * This file is part of PHPUnit. * * (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 PHPUnit\Runner\Extension; use PHPUnit\Event\EventFacadeIsSealedException; use PHPUnit\Event\Facade as EventFacade; use PHPUnit\Event\Subscriber; use PHPUnit\Event\Tracer\Tracer; use PHPUnit\Event\UnknownSubscriberTypeException; /** * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit */ final class Facade { private bool $replacesOutput = false; private bool $replacesProgressOutput = false; private bool $replacesResultOutput = false; private bool $requiresCodeCoverageCollection = false; private bool $requiresExportOfObjects = false; /** * @throws EventFacadeIsSealedException * @throws UnknownSubscriberTypeException */ public function registerSubscribers(Subscriber ...$subscribers): void { EventFacade::instance()->registerSubscribers(...$subscribers); } /** * @throws EventFacadeIsSealedException * @throws UnknownSubscriberTypeException */ public function registerSubscriber(Subscriber $subscriber): void { EventFacade::instance()->registerSubscriber($subscriber); } /** * @throws EventFacadeIsSealedException */ public function registerTracer(Tracer $tracer): void { EventFacade::instance()->registerTracer($tracer); } public function replaceOutput(): void { $this->replacesOutput = true; } public function replacesOutput(): bool { return $this->replacesOutput; } public function replaceProgressOutput(): void { $this->replacesProgressOutput = true; } public function replacesProgressOutput(): bool { return $this->replacesOutput || $this->replacesProgressOutput; } public function replaceResultOutput(): void { $this->replacesResultOutput = true; } public function replacesResultOutput(): bool { return $this->replacesOutput || $this->replacesResultOutput; } public function requireCodeCoverageCollection(): void { $this->requiresCodeCoverageCollection = true; } public function requiresCodeCoverageCollection(): bool { return $this->requiresCodeCoverageCollection; } public function requireExportOfObjects(): void { $this->requiresExportOfObjects = true; } public function requiresExportOfObjects(): bool { return $this->requiresExportOfObjects; } } Extension/PharLoader.php 0000644 00000010752 15111200077 0011251 0 ustar 00 <?php declare(strict_types=1); /* * This file is part of PHPUnit. * * (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 PHPUnit\Runner\Extension; use function count; use function explode; use function extension_loaded; use function implode; use function is_file; use function sprintf; use function str_contains; use PharIo\Manifest\ApplicationName; use PharIo\Manifest\Exception as ManifestException; use PharIo\Manifest\ManifestLoader; use PharIo\Version\Version as PharIoVersion; use PHPUnit\Event; use PHPUnit\Runner\Version; use SebastianBergmann\FileIterator\Facade as FileIteratorFacade; use Throwable; /** * @internal This class is not covered by the backward compatibility promise for PHPUnit */ final class PharLoader { /** * @psalm-param non-empty-string $directory * * @psalm-return list<string> */ public function loadPharExtensionsInDirectory(string $directory): array { $pharExtensionLoaded = extension_loaded('phar'); $loadedExtensions = []; foreach ((new FileIteratorFacade)->getFilesAsArray($directory, '.phar') as $file) { if (!$pharExtensionLoaded) { Event\Facade::emitter()->testRunnerTriggeredWarning( sprintf( 'Cannot load extension from %s because the PHAR extension is not available', $file, ), ); continue; } if (!is_file('phar://' . $file . '/manifest.xml')) { Event\Facade::emitter()->testRunnerTriggeredWarning( sprintf( '%s is not an extension for PHPUnit', $file, ), ); continue; } try { $applicationName = new ApplicationName('phpunit/phpunit'); $version = new PharIoVersion($this->phpunitVersion()); $manifest = ManifestLoader::fromFile('phar://' . $file . '/manifest.xml'); if (!$manifest->isExtensionFor($applicationName)) { Event\Facade::emitter()->testRunnerTriggeredWarning( sprintf( '%s is not an extension for PHPUnit', $file, ), ); continue; } if (!$manifest->isExtensionFor($applicationName, $version)) { Event\Facade::emitter()->testRunnerTriggeredWarning( sprintf( '%s is not compatible with PHPUnit %s', $file, Version::series(), ), ); continue; } } catch (ManifestException $e) { Event\Facade::emitter()->testRunnerTriggeredWarning( sprintf( 'Cannot load extension from %s: %s', $file, $e->getMessage(), ), ); continue; } try { /** @psalm-suppress UnresolvableInclude */ @require $file; } catch (Throwable $t) { Event\Facade::emitter()->testRunnerTriggeredWarning( sprintf( 'Cannot load extension from %s: %s', $file, $t->getMessage(), ), ); continue; } $loadedExtensions[] = $manifest->getName()->asString() . ' ' . $manifest->getVersion()->getVersionString(); Event\Facade::emitter()->testRunnerLoadedExtensionFromPhar( $file, $manifest->getName()->asString(), $manifest->getVersion()->getVersionString(), ); } return $loadedExtensions; } private function phpunitVersion(): string { $version = Version::id(); if (!str_contains($version, '-')) { return $version; } $parts = explode('.', explode('-', $version)[0]); if (count($parts) === 2) { $parts[] = 0; } return implode('.', $parts); } } Extension/ParameterCollection.php 0000644 00000002352 15111200077 0013161 0 ustar 00 <?php declare(strict_types=1); /* * This file is part of PHPUnit. * * (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 PHPUnit\Runner\Extension; use function array_key_exists; use PHPUnit\Runner\ParameterDoesNotExistException; /** * @psalm-immutable * * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit */ final class ParameterCollection { private readonly array $parameters; /** * @psalm-param array<string, string> $parameters */ public static function fromArray(array $parameters): self { return new self($parameters); } private function __construct(array $parameters) { $this->parameters = $parameters; } public function has(string $name): bool { return array_key_exists($name, $this->parameters); } /** * @throws ParameterDoesNotExistException */ public function get(string $name): string { if (!$this->has($name)) { throw new ParameterDoesNotExistException($name); } return $this->parameters[$name]; } } Extension/Extension.php 0000644 00000001120 15111200077 0011171 0 ustar 00 <?php declare(strict_types=1); /* * This file is part of PHPUnit. * * (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 PHPUnit\Runner\Extension; use PHPUnit\TextUI\Configuration\Configuration; /** * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit */ interface Extension { public function bootstrap(Configuration $configuration, Facade $facade, ParameterCollection $parameters): void; } Exception/DirectoryCannotBeCreatedException.php 0000644 00000001335 15111200077 0015734 0 ustar 00 <?php declare(strict_types=1); /* * This file is part of PHPUnit. * * (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 PHPUnit\Runner; use function sprintf; use RuntimeException; /** * @internal This class is not covered by the backward compatibility promise for PHPUnit */ final class DirectoryCannotBeCreatedException extends RuntimeException implements Exception { public function __construct(string $directory) { parent::__construct( sprintf( 'Cannot create directory "%s"', $directory, ), ); } } Exception/UnsupportedPhptSectionException.php 0000644 00000001344 15111200077 0015577 0 ustar 00 <?php declare(strict_types=1); /* * This file is part of PHPUnit. * * (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 PHPUnit\Runner; use function sprintf; use RuntimeException; /** * @internal This class is not covered by the backward compatibility promise for PHPUnit */ final class UnsupportedPhptSectionException extends RuntimeException implements Exception { public function __construct(string $section) { parent::__construct( sprintf( 'PHPUnit does not support PHPT %s sections', $section, ), ); } } Exception/NoIgnoredEventException.php 0000644 00000000746 15111200077 0013761 0 ustar 00 <?php declare(strict_types=1); /* * This file is part of PHPUnit. * * (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 PHPUnit\Runner; use RuntimeException; /** * @internal This class is not covered by the backward compatibility promise for PHPUnit */ final class NoIgnoredEventException extends RuntimeException implements Exception { } Exception/ParameterDoesNotExistException.php 0000644 00000001321 15111200077 0015312 0 ustar 00 <?php declare(strict_types=1); /* * This file is part of PHPUnit. * * (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 PHPUnit\Runner; use function sprintf; use RuntimeException; /** * @internal This class is not covered by the backward compatibility promise for PHPUnit */ final class ParameterDoesNotExistException extends RuntimeException implements Exception { public function __construct(string $name) { parent::__construct( sprintf( 'Parameter "%s" does not exist', $name, ), ); } } Exception/ClassIsAbstractException.php 0000644 00000001400 15111200077 0014104 0 ustar 00 <?php declare(strict_types=1); /* * This file is part of PHPUnit. * * (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 PHPUnit\Runner; use function sprintf; use RuntimeException; /** * @internal This class is not covered by the backward compatibility promise for PHPUnit */ final class ClassIsAbstractException extends RuntimeException implements Exception { public function __construct(string $className, string $file) { parent::__construct( sprintf( 'Class %s declared in %s is abstract', $className, $file, ), ); } } Exception/InvalidOrderException.php 0000644 00000000744 15111200077 0013453 0 ustar 00 <?php declare(strict_types=1); /* * This file is part of PHPUnit. * * (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 PHPUnit\Runner; use RuntimeException; /** * @internal This class is not covered by the backward compatibility promise for PHPUnit */ final class InvalidOrderException extends RuntimeException implements Exception { } Exception/Exception.php 0000644 00000000654 15111200077 0011150 0 ustar 00 <?php declare(strict_types=1); /* * This file is part of PHPUnit. * * (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 PHPUnit\Runner; /** * @internal This class is not covered by the backward compatibility promise for PHPUnit */ interface Exception extends \PHPUnit\Exception { } Exception/FileDoesNotExistException.php 0000644 00000001307 15111200077 0014255 0 ustar 00 <?php declare(strict_types=1); /* * This file is part of PHPUnit. * * (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 PHPUnit\Runner; use function sprintf; use RuntimeException; /** * @internal This class is not covered by the backward compatibility promise for PHPUnit */ final class FileDoesNotExistException extends RuntimeException implements Exception { public function __construct(string $file) { parent::__construct( sprintf( 'File "%s" does not exist', $file, ), ); } } Exception/ClassDoesNotExtendTestCaseException.php 0000644 00000001452 15111200077 0016233 0 ustar 00 <?php declare(strict_types=1); /* * This file is part of PHPUnit. * * (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 PHPUnit\Runner; use function sprintf; use RuntimeException; /** * @internal This class is not covered by the backward compatibility promise for PHPUnit */ final class ClassDoesNotExtendTestCaseException extends RuntimeException implements Exception { public function __construct(string $className, string $file) { parent::__construct( sprintf( 'Class %s declared in %s does not extend PHPUnit\Framework\TestCase', $className, $file, ), ); } } Exception/ReflectionException.php 0000644 00000000742 15111200077 0013161 0 ustar 00 <?php declare(strict_types=1); /* * This file is part of PHPUnit. * * (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 PHPUnit\Runner; use RuntimeException; /** * @internal This class is not covered by the backward compatibility promise for PHPUnit */ final class ReflectionException extends RuntimeException implements Exception { } Exception/PhptExternalFileCannotBeLoadedException.php 0000644 00000001434 15111200100 0017012 0 ustar 00 <?php declare(strict_types=1); /* * This file is part of PHPUnit. * * (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 PHPUnit\Runner; use function sprintf; use RuntimeException; /** * @internal This class is not covered by the backward compatibility promise for PHPUnit */ final class PhptExternalFileCannotBeLoadedException extends RuntimeException implements Exception { public function __construct(string $section, string $file) { parent::__construct( sprintf( 'Could not load --%s-- %s for PHPT file', $section . '_EXTERNAL', $file, ), ); } } Exception/ClassCannotBeFoundException.php 0000644 00000001376 15111200100 0014531 0 ustar 00 <?php declare(strict_types=1); /* * This file is part of PHPUnit. * * (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 PHPUnit\Runner; use function sprintf; use RuntimeException; /** * @internal This class is not covered by the backward compatibility promise for PHPUnit */ final class ClassCannotBeFoundException extends RuntimeException implements Exception { public function __construct(string $className, string $file) { parent::__construct( sprintf( 'Class %s cannot be found in %s', $className, $file, ), ); } } Exception/InvalidPhptFileException.php 0000644 00000000747 15111200100 0014101 0 ustar 00 <?php declare(strict_types=1); /* * This file is part of PHPUnit. * * (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 PHPUnit\Runner; use RuntimeException; /** * @internal This class is not covered by the backward compatibility promise for PHPUnit */ final class InvalidPhptFileException extends RuntimeException implements Exception { } GarbageCollection/GarbageCollectionHandler.php 0000644 00000004244 15111200100 0015444 0 ustar 00 <?php declare(strict_types=1); /* * This file is part of PHPUnit. * * (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 PHPUnit\Runner\GarbageCollection; use function gc_collect_cycles; use function gc_disable; use function gc_enable; use PHPUnit\Event\EventFacadeIsSealedException; use PHPUnit\Event\Facade; use PHPUnit\Event\UnknownSubscriberTypeException; /** * @internal This class is not covered by the backward compatibility promise for PHPUnit */ final class GarbageCollectionHandler { private readonly Facade $facade; private readonly int $threshold; private int $tests = 0; /** * @throws EventFacadeIsSealedException * @throws UnknownSubscriberTypeException */ public function __construct(Facade $facade, int $threshold) { $this->facade = $facade; $this->threshold = $threshold; $this->registerSubscribers(); } public function executionStarted(): void { gc_disable(); $this->facade->emitter()->testRunnerDisabledGarbageCollection(); gc_collect_cycles(); $this->facade->emitter()->testRunnerTriggeredGarbageCollection(); } public function executionFinished(): void { gc_collect_cycles(); $this->facade->emitter()->testRunnerTriggeredGarbageCollection(); gc_enable(); $this->facade->emitter()->testRunnerEnabledGarbageCollection(); } public function testFinished(): void { $this->tests++; if ($this->tests === $this->threshold) { gc_collect_cycles(); $this->facade->emitter()->testRunnerTriggeredGarbageCollection(); $this->tests = 0; } } /** * @throws EventFacadeIsSealedException * @throws UnknownSubscriberTypeException */ private function registerSubscribers(): void { $this->facade->registerSubscribers( new ExecutionStartedSubscriber($this), new ExecutionFinishedSubscriber($this), new TestFinishedSubscriber($this), ); } } GarbageCollection/Subscriber/ExecutionFinishedSubscriber.php 0000644 00000001644 15111200100 0020347 0 ustar 00 <?php declare(strict_types=1); /* * This file is part of PHPUnit. * * (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 PHPUnit\Runner\GarbageCollection; use PHPUnit\Event\InvalidArgumentException; use PHPUnit\Event\TestRunner\ExecutionFinished; use PHPUnit\Event\TestRunner\ExecutionFinishedSubscriber as TestRunnerExecutionFinishedSubscriber; /** * @internal This class is not covered by the backward compatibility promise for PHPUnit */ final class ExecutionFinishedSubscriber extends Subscriber implements TestRunnerExecutionFinishedSubscriber { /** * @throws \PHPUnit\Framework\InvalidArgumentException * @throws InvalidArgumentException */ public function notify(ExecutionFinished $event): void { $this->handler()->executionFinished(); } } GarbageCollection/Subscriber/ExecutionStartedSubscriber.php 0000644 00000001635 15111200100 0020224 0 ustar 00 <?php declare(strict_types=1); /* * This file is part of PHPUnit. * * (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 PHPUnit\Runner\GarbageCollection; use PHPUnit\Event\InvalidArgumentException; use PHPUnit\Event\TestRunner\ExecutionStarted; use PHPUnit\Event\TestRunner\ExecutionStartedSubscriber as TestRunnerExecutionStartedSubscriber; /** * @internal This class is not covered by the backward compatibility promise for PHPUnit */ final class ExecutionStartedSubscriber extends Subscriber implements TestRunnerExecutionStartedSubscriber { /** * @throws \PHPUnit\Framework\InvalidArgumentException * @throws InvalidArgumentException */ public function notify(ExecutionStarted $event): void { $this->handler()->executionStarted(); } } GarbageCollection/Subscriber/Subscriber.php 0000644 00000001273 15111200100 0015007 0 ustar 00 <?php declare(strict_types=1); /* * This file is part of PHPUnit. * * (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 PHPUnit\Runner\GarbageCollection; /** * @internal This class is not covered by the backward compatibility promise for PHPUnit */ abstract class Subscriber { private readonly GarbageCollectionHandler $handler; public function __construct(GarbageCollectionHandler $handler) { $this->handler = $handler; } protected function handler(): GarbageCollectionHandler { return $this->handler; } } GarbageCollection/Subscriber/TestFinishedSubscriber.php 0000644 00000001467 15111200100 0017326 0 ustar 00 <?php declare(strict_types=1); /* * This file is part of PHPUnit. * * (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 PHPUnit\Runner\GarbageCollection; use PHPUnit\Event\InvalidArgumentException; use PHPUnit\Event\Test\Finished; use PHPUnit\Event\Test\FinishedSubscriber; /** * @internal This class is not covered by the backward compatibility promise for PHPUnit */ final class TestFinishedSubscriber extends Subscriber implements FinishedSubscriber { /** * @throws \PHPUnit\Framework\InvalidArgumentException * @throws InvalidArgumentException */ public function notify(Finished $event): void { $this->handler()->testFinished(); } } ResultCache/NullResultCache.php 0000644 00000001622 15111200100 0012472 0 ustar 00 <?php declare(strict_types=1); /* * This file is part of PHPUnit. * * (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 PHPUnit\Runner\ResultCache; use PHPUnit\Framework\TestStatus\TestStatus; /** * @internal This class is not covered by the backward compatibility promise for PHPUnit */ final class NullResultCache implements ResultCache { public function setStatus(string $id, TestStatus $status): void { } public function status(string $id): TestStatus { return TestStatus::unknown(); } public function setTime(string $id, float $time): void { } public function time(string $id): float { return 0; } public function load(): void { } public function persist(): void { } } ResultCache/ResultCacheHandler.php 0000644 00000010250 15111200100 0013132 0 ustar 00 <?php declare(strict_types=1); /* * This file is part of PHPUnit. * * (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 PHPUnit\Runner\ResultCache; use function round; use PHPUnit\Event\Event; use PHPUnit\Event\EventFacadeIsSealedException; use PHPUnit\Event\Facade; use PHPUnit\Event\Telemetry\HRTime; use PHPUnit\Event\Test\ConsideredRisky; use PHPUnit\Event\Test\Errored; use PHPUnit\Event\Test\Failed; use PHPUnit\Event\Test\Finished; use PHPUnit\Event\Test\MarkedIncomplete; use PHPUnit\Event\Test\Prepared; use PHPUnit\Event\Test\Skipped; use PHPUnit\Event\UnknownSubscriberTypeException; use PHPUnit\Framework\InvalidArgumentException; use PHPUnit\Framework\TestStatus\TestStatus; /** * @internal This class is not covered by the backward compatibility promise for PHPUnit */ final class ResultCacheHandler { private readonly ResultCache $cache; private ?HRTime $time = null; private int $testSuite = 0; /** * @throws EventFacadeIsSealedException * @throws UnknownSubscriberTypeException */ public function __construct(ResultCache $cache, Facade $facade) { $this->cache = $cache; $this->registerSubscribers($facade); } public function testSuiteStarted(): void { $this->testSuite++; } public function testSuiteFinished(): void { $this->testSuite--; if ($this->testSuite === 0) { $this->cache->persist(); } } public function testPrepared(Prepared $event): void { $this->time = $event->telemetryInfo()->time(); } public function testMarkedIncomplete(MarkedIncomplete $event): void { $this->cache->setStatus( $event->test()->id(), TestStatus::incomplete($event->throwable()->message()), ); } public function testConsideredRisky(ConsideredRisky $event): void { $this->cache->setStatus( $event->test()->id(), TestStatus::risky($event->message()), ); } public function testErrored(Errored $event): void { $this->cache->setStatus( $event->test()->id(), TestStatus::error($event->throwable()->message()), ); } public function testFailed(Failed $event): void { $this->cache->setStatus( $event->test()->id(), TestStatus::failure($event->throwable()->message()), ); } /** * @throws \PHPUnit\Event\InvalidArgumentException * @throws InvalidArgumentException */ public function testSkipped(Skipped $event): void { $this->cache->setStatus( $event->test()->id(), TestStatus::skipped($event->message()), ); $this->cache->setTime($event->test()->id(), $this->duration($event)); } /** * @throws \PHPUnit\Event\InvalidArgumentException * @throws InvalidArgumentException */ public function testFinished(Finished $event): void { $this->cache->setTime($event->test()->id(), $this->duration($event)); $this->time = null; } /** * @throws \PHPUnit\Event\InvalidArgumentException * @throws InvalidArgumentException */ private function duration(Event $event): float { if ($this->time === null) { return 0.0; } return round($event->telemetryInfo()->time()->duration($this->time)->asFloat(), 3); } /** * @throws EventFacadeIsSealedException * @throws UnknownSubscriberTypeException */ private function registerSubscribers(Facade $facade): void { $facade->registerSubscribers( new TestSuiteStartedSubscriber($this), new TestSuiteFinishedSubscriber($this), new TestPreparedSubscriber($this), new TestMarkedIncompleteSubscriber($this), new TestConsideredRiskySubscriber($this), new TestErroredSubscriber($this), new TestFailedSubscriber($this), new TestSkippedSubscriber($this), new TestFinishedSubscriber($this), ); } } ResultCache/DefaultResultCache.php 0000644 00000007017 15111200100 0013150 0 ustar 00 <?php declare(strict_types=1); /* * This file is part of PHPUnit. * * (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 PHPUnit\Runner\ResultCache; use const DIRECTORY_SEPARATOR; use function array_keys; use function assert; use function dirname; use function file_get_contents; use function file_put_contents; use function is_array; use function is_dir; use function is_file; use function json_decode; use function json_encode; use PHPUnit\Framework\TestStatus\TestStatus; use PHPUnit\Runner\DirectoryCannotBeCreatedException; use PHPUnit\Runner\Exception; use PHPUnit\Util\Filesystem; /** * @internal This class is not covered by the backward compatibility promise for PHPUnit */ final class DefaultResultCache implements ResultCache { /** * @var int */ private const VERSION = 1; /** * @var string */ private const DEFAULT_RESULT_CACHE_FILENAME = '.phpunit.result.cache'; private readonly string $cacheFilename; /** * @psalm-var array<string, TestStatus> */ private array $defects = []; /** * @psalm-var array<string, float> */ private array $times = []; public function __construct(?string $filepath = null) { if ($filepath !== null && is_dir($filepath)) { $filepath .= DIRECTORY_SEPARATOR . self::DEFAULT_RESULT_CACHE_FILENAME; } $this->cacheFilename = $filepath ?? $_ENV['PHPUNIT_RESULT_CACHE'] ?? self::DEFAULT_RESULT_CACHE_FILENAME; } public function setStatus(string $id, TestStatus $status): void { if ($status->isSuccess()) { return; } $this->defects[$id] = $status; } public function status(string $id): TestStatus { return $this->defects[$id] ?? TestStatus::unknown(); } public function setTime(string $id, float $time): void { $this->times[$id] = $time; } public function time(string $id): float { return $this->times[$id] ?? 0.0; } public function load(): void { if (!is_file($this->cacheFilename)) { return; } $data = json_decode( file_get_contents($this->cacheFilename), true, ); if ($data === null) { return; } if (!isset($data['version'])) { return; } if ($data['version'] !== self::VERSION) { return; } assert(isset($data['defects']) && is_array($data['defects'])); assert(isset($data['times']) && is_array($data['times'])); foreach (array_keys($data['defects']) as $test) { $data['defects'][$test] = TestStatus::from($data['defects'][$test]); } $this->defects = $data['defects']; $this->times = $data['times']; } /** * @throws Exception */ public function persist(): void { if (!Filesystem::createDirectory(dirname($this->cacheFilename))) { throw new DirectoryCannotBeCreatedException($this->cacheFilename); } $data = [ 'version' => self::VERSION, 'defects' => [], 'times' => $this->times, ]; foreach ($this->defects as $test => $status) { $data['defects'][$test] = $status->asInt(); } file_put_contents( $this->cacheFilename, json_encode($data), LOCK_EX, ); } } ResultCache/ResultCache.php 0000644 00000001373 15111200100 0011642 0 ustar 00 <?php declare(strict_types=1); /* * This file is part of PHPUnit. * * (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 PHPUnit\Runner\ResultCache; use PHPUnit\Framework\TestStatus\TestStatus; /** * @internal This class is not covered by the backward compatibility promise for PHPUnit */ interface ResultCache { public function setStatus(string $id, TestStatus $status): void; public function status(string $id): TestStatus; public function setTime(string $id, float $time): void; public function time(string $id): float; public function load(): void; public function persist(): void; } ResultCache/Subscriber/TestSkippedSubscriber.php 0000644 00000001461 15111200100 0016024 0 ustar 00 <?php declare(strict_types=1); /* * This file is part of PHPUnit. * * (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 PHPUnit\Runner\ResultCache; use PHPUnit\Event\InvalidArgumentException; use PHPUnit\Event\Test\Skipped; use PHPUnit\Event\Test\SkippedSubscriber; /** * @internal This class is not covered by the backward compatibility promise for PHPUnit */ final class TestSkippedSubscriber extends Subscriber implements SkippedSubscriber { /** * @throws \PHPUnit\Framework\InvalidArgumentException * @throws InvalidArgumentException */ public function notify(Skipped $event): void { $this->handler()->testSkipped($event); } } ResultCache/Subscriber/Subscriber.php 0000644 00000001243 15111200100 0013642 0 ustar 00 <?php declare(strict_types=1); /* * This file is part of PHPUnit. * * (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 PHPUnit\Runner\ResultCache; /** * @internal This class is not covered by the backward compatibility promise for PHPUnit */ abstract class Subscriber { private readonly ResultCacheHandler $handler; public function __construct(ResultCacheHandler $handler) { $this->handler = $handler; } protected function handler(): ResultCacheHandler { return $this->handler; } } ResultCache/Subscriber/TestSuiteFinishedSubscriber.php 0000644 00000001246 15111200100 0017171 0 ustar 00 <?php declare(strict_types=1); /* * This file is part of PHPUnit. * * (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 PHPUnit\Runner\ResultCache; use PHPUnit\Event\TestSuite\Finished; use PHPUnit\Event\TestSuite\FinishedSubscriber; /** * @internal This class is not covered by the backward compatibility promise for PHPUnit */ final class TestSuiteFinishedSubscriber extends Subscriber implements FinishedSubscriber { public function notify(Finished $event): void { $this->handler()->testSuiteFinished(); } } ResultCache/Subscriber/TestMarkedIncompleteSubscriber.php 0000644 00000001310 15111200100 0017641 0 ustar 00 <?php declare(strict_types=1); /* * This file is part of PHPUnit. * * (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 PHPUnit\Runner\ResultCache; use PHPUnit\Event\Test\MarkedIncomplete; use PHPUnit\Event\Test\MarkedIncompleteSubscriber; /** * @internal This class is not covered by the backward compatibility promise for PHPUnit */ final class TestMarkedIncompleteSubscriber extends Subscriber implements MarkedIncompleteSubscriber { public function notify(MarkedIncomplete $event): void { $this->handler()->testMarkedIncomplete($event); } } ResultCache/Subscriber/TestConsideredRiskySubscriber.php 0000644 00000001302 15111200100 0017520 0 ustar 00 <?php declare(strict_types=1); /* * This file is part of PHPUnit. * * (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 PHPUnit\Runner\ResultCache; use PHPUnit\Event\Test\ConsideredRisky; use PHPUnit\Event\Test\ConsideredRiskySubscriber; /** * @internal This class is not covered by the backward compatibility promise for PHPUnit */ final class TestConsideredRiskySubscriber extends Subscriber implements ConsideredRiskySubscriber { public function notify(ConsideredRisky $event): void { $this->handler()->testConsideredRisky($event); } } ResultCache/Subscriber/TestFailedSubscriber.php 0000644 00000001214 15111200100 0015605 0 ustar 00 <?php declare(strict_types=1); /* * This file is part of PHPUnit. * * (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 PHPUnit\Runner\ResultCache; use PHPUnit\Event\Test\Failed; use PHPUnit\Event\Test\FailedSubscriber; /** * @internal This class is not covered by the backward compatibility promise for PHPUnit */ final class TestFailedSubscriber extends Subscriber implements FailedSubscriber { public function notify(Failed $event): void { $this->handler()->testFailed($event); } } ResultCache/Subscriber/TestSuiteStartedSubscriber.php 0000644 00000001240 15111200100 0017040 0 ustar 00 <?php declare(strict_types=1); /* * This file is part of PHPUnit. * * (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 PHPUnit\Runner\ResultCache; use PHPUnit\Event\TestSuite\Started; use PHPUnit\Event\TestSuite\StartedSubscriber; /** * @internal This class is not covered by the backward compatibility promise for PHPUnit */ final class TestSuiteStartedSubscriber extends Subscriber implements StartedSubscriber { public function notify(Started $event): void { $this->handler()->testSuiteStarted(); } } ResultCache/Subscriber/TestFinishedSubscriber.php 0000644 00000001467 15111200100 0016164 0 ustar 00 <?php declare(strict_types=1); /* * This file is part of PHPUnit. * * (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 PHPUnit\Runner\ResultCache; use PHPUnit\Event\InvalidArgumentException; use PHPUnit\Event\Test\Finished; use PHPUnit\Event\Test\FinishedSubscriber; /** * @internal This class is not covered by the backward compatibility promise for PHPUnit */ final class TestFinishedSubscriber extends Subscriber implements FinishedSubscriber { /** * @throws \PHPUnit\Framework\InvalidArgumentException * @throws InvalidArgumentException */ public function notify(Finished $event): void { $this->handler()->testFinished($event); } } ResultCache/Subscriber/TestErroredSubscriber.php 0000644 00000001222 15111200100 0016022 0 ustar 00 <?php declare(strict_types=1); /* * This file is part of PHPUnit. * * (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 PHPUnit\Runner\ResultCache; use PHPUnit\Event\Test\Errored; use PHPUnit\Event\Test\ErroredSubscriber; /** * @internal This class is not covered by the backward compatibility promise for PHPUnit */ final class TestErroredSubscriber extends Subscriber implements ErroredSubscriber { public function notify(Errored $event): void { $this->handler()->testErrored($event); } } ResultCache/Subscriber/TestPreparedSubscriber.php 0000644 00000001230 15111200100 0016161 0 ustar 00 <?php declare(strict_types=1); /* * This file is part of PHPUnit. * * (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 PHPUnit\Runner\ResultCache; use PHPUnit\Event\Test\Prepared; use PHPUnit\Event\Test\PreparedSubscriber; /** * @internal This class is not covered by the backward compatibility promise for PHPUnit */ final class TestPreparedSubscriber extends Subscriber implements PreparedSubscriber { public function notify(Prepared $event): void { $this->handler()->testPrepared($event); } } Version.php 0000644 00000002722 15111200100 0006662 0 ustar 00 <?php declare(strict_types=1); /* * This file is part of PHPUnit. * * (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 PHPUnit\Runner; use function array_slice; use function dirname; use function explode; use function implode; use function str_contains; use SebastianBergmann\Version as VersionId; /** * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit */ final class Version { private static string $pharVersion = ''; private static string $version = ''; /** * Returns the current version of PHPUnit. */ public static function id(): string { if (self::$pharVersion !== '') { return self::$pharVersion; } if (self::$version === '') { self::$version = (new VersionId('10.4.2', dirname(__DIR__, 2)))->asString(); } return self::$version; } public static function series(): string { if (str_contains(self::id(), '-')) { $version = explode('-', self::id(), 2)[0]; } else { $version = self::id(); } return implode('.', array_slice(explode('.', $version), 0, 2)); } public static function getVersionString(): string { return 'PHPUnit ' . self::id() . ' by Sebastian Bergmann and contributors.'; } }
Simpan