One Hat Cyber Team
Your IP:
216.73.216.176
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
/
thread-self
/
root
/
proc
/
self
/
cwd
/
Edit File:
TextUI.tar
TestSuiteFilterProcessor.php 0000644 00000005011 15111303725 0012247 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\TextUI; use function array_map; use PHPUnit\Event; use PHPUnit\Framework\TestSuite; use PHPUnit\Runner\Filter\Factory; use PHPUnit\TextUI\Configuration\Configuration; use PHPUnit\TextUI\Configuration\FilterNotConfiguredException; /** * @internal This class is not covered by the backward compatibility promise for PHPUnit */ final class TestSuiteFilterProcessor { private Factory $filterFactory; public function __construct(Factory $factory = new Factory) { $this->filterFactory = $factory; } /** * @throws Event\RuntimeException * @throws FilterNotConfiguredException */ public function process(Configuration $configuration, TestSuite $suite): void { if (!$configuration->hasFilter() && !$configuration->hasGroups() && !$configuration->hasExcludeGroups() && !$configuration->hasTestsCovering() && !$configuration->hasTestsUsing()) { return; } if ($configuration->hasExcludeGroups()) { $this->filterFactory->addExcludeGroupFilter( $configuration->excludeGroups(), ); } if ($configuration->hasGroups()) { $this->filterFactory->addIncludeGroupFilter( $configuration->groups(), ); } if ($configuration->hasTestsCovering()) { $this->filterFactory->addIncludeGroupFilter( array_map( static fn (string $name): string => '__phpunit_covers_' . $name, $configuration->testsCovering(), ), ); } if ($configuration->hasTestsUsing()) { $this->filterFactory->addIncludeGroupFilter( array_map( static fn (string $name): string => '__phpunit_uses_' . $name, $configuration->testsUsing(), ), ); } if ($configuration->hasFilter()) { $this->filterFactory->addNameFilter( $configuration->filter(), ); } $suite->injectFilter($this->filterFactory); Event\Facade::emitter()->testSuiteFiltered( Event\TestSuite\TestSuiteBuilder::from($suite), ); } } ShellExitCodeCalculator.php 0000644 00000003754 15111303725 0011772 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\TextUI; use PHPUnit\TestRunner\TestResult\TestResult; /** * @internal This class is not covered by the backward compatibility promise for PHPUnit */ final class ShellExitCodeCalculator { private const SUCCESS_EXIT = 0; private const FAILURE_EXIT = 1; private const EXCEPTION_EXIT = 2; public function calculate(bool $failOnDeprecation, bool $failOnEmptyTestSuite, bool $failOnIncomplete, bool $failOnNotice, bool $failOnRisky, bool $failOnSkipped, bool $failOnWarning, TestResult $result): int { $returnCode = self::FAILURE_EXIT; if ($result->wasSuccessful()) { $returnCode = self::SUCCESS_EXIT; } if ($failOnEmptyTestSuite && !$result->hasTests()) { $returnCode = self::FAILURE_EXIT; } if ($result->wasSuccessfulIgnoringPhpunitWarnings()) { if ($failOnDeprecation && $result->hasDeprecations()) { $returnCode = self::FAILURE_EXIT; } if ($failOnIncomplete && $result->hasIncompleteTests()) { $returnCode = self::FAILURE_EXIT; } if ($failOnNotice && $result->hasNotices()) { $returnCode = self::FAILURE_EXIT; } if ($failOnRisky && $result->hasRiskyTests()) { $returnCode = self::FAILURE_EXIT; } if ($failOnSkipped && $result->hasSkippedTests()) { $returnCode = self::FAILURE_EXIT; } if ($failOnWarning && $result->hasWarnings()) { $returnCode = self::FAILURE_EXIT; } } if ($result->hasErrors()) { $returnCode = self::EXCEPTION_EXIT; } return $returnCode; } } Configuration/PhpHandler.php 0000644 00000007300 15111303725 0012107 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\TextUI\Configuration; use const PATH_SEPARATOR; use function constant; use function define; use function defined; use function getenv; use function implode; use function ini_get; use function ini_set; use function putenv; /** * @internal This class is not covered by the backward compatibility promise for PHPUnit */ final class PhpHandler { public function handle(Php $configuration): void { $this->handleIncludePaths($configuration->includePaths()); $this->handleIniSettings($configuration->iniSettings()); $this->handleConstants($configuration->constants()); $this->handleGlobalVariables($configuration->globalVariables()); $this->handleServerVariables($configuration->serverVariables()); $this->handleEnvVariables($configuration->envVariables()); $this->handleVariables('_POST', $configuration->postVariables()); $this->handleVariables('_GET', $configuration->getVariables()); $this->handleVariables('_COOKIE', $configuration->cookieVariables()); $this->handleVariables('_FILES', $configuration->filesVariables()); $this->handleVariables('_REQUEST', $configuration->requestVariables()); } private function handleIncludePaths(DirectoryCollection $includePaths): void { if (!$includePaths->isEmpty()) { $includePathsAsStrings = []; foreach ($includePaths as $includePath) { $includePathsAsStrings[] = $includePath->path(); } ini_set( 'include_path', implode(PATH_SEPARATOR, $includePathsAsStrings) . PATH_SEPARATOR . ini_get('include_path'), ); } } private function handleIniSettings(IniSettingCollection $iniSettings): void { foreach ($iniSettings as $iniSetting) { $value = $iniSetting->value(); if (defined($value)) { $value = (string) constant($value); } ini_set($iniSetting->name(), $value); } } private function handleConstants(ConstantCollection $constants): void { foreach ($constants as $constant) { if (!defined($constant->name())) { define($constant->name(), $constant->value()); } } } private function handleGlobalVariables(VariableCollection $variables): void { foreach ($variables as $variable) { $GLOBALS[$variable->name()] = $variable->value(); } } private function handleServerVariables(VariableCollection $variables): void { foreach ($variables as $variable) { $_SERVER[$variable->name()] = $variable->value(); } } private function handleVariables(string $target, VariableCollection $variables): void { foreach ($variables as $variable) { $GLOBALS[$target][$variable->name()] = $variable->value(); } } private function handleEnvVariables(VariableCollection $variables): void { foreach ($variables as $variable) { $name = $variable->name(); $value = $variable->value(); $force = $variable->force(); if ($force || getenv($name) === false) { putenv("{$name}={$value}"); } $value = getenv($name); if ($force || !isset($_ENV[$name])) { $_ENV[$name] = $value; } } } } Configuration/Merger.php 0000644 00000105454 15111303725 0011314 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\TextUI\Configuration; use const DIRECTORY_SEPARATOR; use function array_diff; use function assert; use function dirname; use function explode; use function is_int; use function realpath; use function time; use PHPUnit\Event\Facade as EventFacade; use PHPUnit\Runner\TestSuiteSorter; use PHPUnit\TextUI\CliArguments\Configuration as CliConfiguration; use PHPUnit\TextUI\XmlConfiguration\Configuration as XmlConfiguration; use PHPUnit\TextUI\XmlConfiguration\LoadedFromFileConfiguration; use PHPUnit\TextUI\XmlConfiguration\SchemaDetector; use PHPUnit\Util\Filesystem; use SebastianBergmann\CodeCoverage\Report\Html\Colors; use SebastianBergmann\CodeCoverage\Report\Thresholds; use SebastianBergmann\Environment\Console; use SebastianBergmann\Invoker\Invoker; /** * @internal This class is not covered by the backward compatibility promise for PHPUnit */ final class Merger { /** * @throws \PHPUnit\TextUI\CliArguments\Exception * @throws \PHPUnit\TextUI\XmlConfiguration\Exception * @throws NoCustomCssFileException */ public function merge(CliConfiguration $cliConfiguration, XmlConfiguration $xmlConfiguration): Configuration { $configurationFile = null; if ($xmlConfiguration->wasLoadedFromFile()) { assert($xmlConfiguration instanceof LoadedFromFileConfiguration); $configurationFile = $xmlConfiguration->filename(); } $bootstrap = null; if ($cliConfiguration->hasBootstrap()) { $bootstrap = $cliConfiguration->bootstrap(); } elseif ($xmlConfiguration->phpunit()->hasBootstrap()) { $bootstrap = $xmlConfiguration->phpunit()->bootstrap(); } if ($cliConfiguration->hasCacheResult()) { $cacheResult = $cliConfiguration->cacheResult(); } else { $cacheResult = $xmlConfiguration->phpunit()->cacheResult(); } $cacheDirectory = null; $coverageCacheDirectory = null; if ($cliConfiguration->hasCacheDirectory() && Filesystem::createDirectory($cliConfiguration->cacheDirectory())) { $cacheDirectory = realpath($cliConfiguration->cacheDirectory()); } elseif ($xmlConfiguration->phpunit()->hasCacheDirectory() && Filesystem::createDirectory($xmlConfiguration->phpunit()->cacheDirectory())) { $cacheDirectory = realpath($xmlConfiguration->phpunit()->cacheDirectory()); } if ($cacheDirectory !== null) { $coverageCacheDirectory = $cacheDirectory . DIRECTORY_SEPARATOR . 'code-coverage'; $testResultCacheFile = $cacheDirectory . DIRECTORY_SEPARATOR . 'test-results'; } if ($coverageCacheDirectory === null) { if ($cliConfiguration->hasCoverageCacheDirectory() && Filesystem::createDirectory($cliConfiguration->coverageCacheDirectory())) { $coverageCacheDirectory = realpath($cliConfiguration->coverageCacheDirectory()); } elseif ($xmlConfiguration->codeCoverage()->hasCacheDirectory()) { $coverageCacheDirectory = $xmlConfiguration->codeCoverage()->cacheDirectory()->path(); } } if (!isset($testResultCacheFile)) { if ($cliConfiguration->hasCacheResultFile()) { $testResultCacheFile = $cliConfiguration->cacheResultFile(); } elseif ($xmlConfiguration->phpunit()->hasCacheResultFile()) { $testResultCacheFile = $xmlConfiguration->phpunit()->cacheResultFile(); } elseif ($xmlConfiguration->wasLoadedFromFile()) { $testResultCacheFile = dirname(realpath($xmlConfiguration->filename())) . DIRECTORY_SEPARATOR . '.phpunit.result.cache'; } else { $candidate = realpath($_SERVER['PHP_SELF']); if ($candidate) { $testResultCacheFile = dirname($candidate) . DIRECTORY_SEPARATOR . '.phpunit.result.cache'; } else { $testResultCacheFile = '.phpunit.result.cache'; } } } if ($cliConfiguration->hasDisableCodeCoverageIgnore()) { $disableCodeCoverageIgnore = $cliConfiguration->disableCodeCoverageIgnore(); } else { $disableCodeCoverageIgnore = $xmlConfiguration->codeCoverage()->disableCodeCoverageIgnore(); } if ($cliConfiguration->hasFailOnDeprecation()) { $failOnDeprecation = $cliConfiguration->failOnDeprecation(); } else { $failOnDeprecation = $xmlConfiguration->phpunit()->failOnDeprecation(); } if ($cliConfiguration->hasFailOnEmptyTestSuite()) { $failOnEmptyTestSuite = $cliConfiguration->failOnEmptyTestSuite(); } else { $failOnEmptyTestSuite = $xmlConfiguration->phpunit()->failOnEmptyTestSuite(); } if ($cliConfiguration->hasFailOnIncomplete()) { $failOnIncomplete = $cliConfiguration->failOnIncomplete(); } else { $failOnIncomplete = $xmlConfiguration->phpunit()->failOnIncomplete(); } if ($cliConfiguration->hasFailOnNotice()) { $failOnNotice = $cliConfiguration->failOnNotice(); } else { $failOnNotice = $xmlConfiguration->phpunit()->failOnNotice(); } if ($cliConfiguration->hasFailOnRisky()) { $failOnRisky = $cliConfiguration->failOnRisky(); } else { $failOnRisky = $xmlConfiguration->phpunit()->failOnRisky(); } if ($cliConfiguration->hasFailOnSkipped()) { $failOnSkipped = $cliConfiguration->failOnSkipped(); } else { $failOnSkipped = $xmlConfiguration->phpunit()->failOnSkipped(); } if ($cliConfiguration->hasFailOnWarning()) { $failOnWarning = $cliConfiguration->failOnWarning(); } else { $failOnWarning = $xmlConfiguration->phpunit()->failOnWarning(); } if ($cliConfiguration->hasStopOnDefect()) { $stopOnDefect = $cliConfiguration->stopOnDefect(); } else { $stopOnDefect = $xmlConfiguration->phpunit()->stopOnDefect(); } if ($cliConfiguration->hasStopOnDeprecation()) { $stopOnDeprecation = $cliConfiguration->stopOnDeprecation(); } else { $stopOnDeprecation = $xmlConfiguration->phpunit()->stopOnDeprecation(); } if ($cliConfiguration->hasStopOnError()) { $stopOnError = $cliConfiguration->stopOnError(); } else { $stopOnError = $xmlConfiguration->phpunit()->stopOnError(); } if ($cliConfiguration->hasStopOnFailure()) { $stopOnFailure = $cliConfiguration->stopOnFailure(); } else { $stopOnFailure = $xmlConfiguration->phpunit()->stopOnFailure(); } if ($cliConfiguration->hasStopOnIncomplete()) { $stopOnIncomplete = $cliConfiguration->stopOnIncomplete(); } else { $stopOnIncomplete = $xmlConfiguration->phpunit()->stopOnIncomplete(); } if ($cliConfiguration->hasStopOnNotice()) { $stopOnNotice = $cliConfiguration->stopOnNotice(); } else { $stopOnNotice = $xmlConfiguration->phpunit()->stopOnNotice(); } if ($cliConfiguration->hasStopOnRisky()) { $stopOnRisky = $cliConfiguration->stopOnRisky(); } else { $stopOnRisky = $xmlConfiguration->phpunit()->stopOnRisky(); } if ($cliConfiguration->hasStopOnSkipped()) { $stopOnSkipped = $cliConfiguration->stopOnSkipped(); } else { $stopOnSkipped = $xmlConfiguration->phpunit()->stopOnSkipped(); } if ($cliConfiguration->hasStopOnWarning()) { $stopOnWarning = $cliConfiguration->stopOnWarning(); } else { $stopOnWarning = $xmlConfiguration->phpunit()->stopOnWarning(); } if ($cliConfiguration->hasStderr() && $cliConfiguration->stderr()) { $outputToStandardErrorStream = true; } else { $outputToStandardErrorStream = $xmlConfiguration->phpunit()->stderr(); } if ($cliConfiguration->hasColumns()) { $columns = $cliConfiguration->columns(); } else { $columns = $xmlConfiguration->phpunit()->columns(); } if ($columns === 'max') { $columns = (new Console)->getNumberOfColumns(); } if ($columns < 16) { $columns = 16; EventFacade::emitter()->testRunnerTriggeredWarning( 'Less than 16 columns requested, number of columns set to 16', ); } assert(is_int($columns)); $noExtensions = false; if ($cliConfiguration->hasNoExtensions() && $cliConfiguration->noExtensions()) { $noExtensions = true; } $pharExtensionDirectory = null; if ($xmlConfiguration->phpunit()->hasExtensionsDirectory()) { $pharExtensionDirectory = $xmlConfiguration->phpunit()->extensionsDirectory(); } $extensionBootstrappers = []; foreach ($xmlConfiguration->extensions() as $extension) { $extensionBootstrappers[] = [ 'className' => $extension->className(), 'parameters' => $extension->parameters(), ]; } if ($cliConfiguration->hasPathCoverage() && $cliConfiguration->pathCoverage()) { $pathCoverage = $cliConfiguration->pathCoverage(); } else { $pathCoverage = $xmlConfiguration->codeCoverage()->pathCoverage(); } $defaultColors = Colors::default(); $defaultThresholds = Thresholds::default(); $coverageClover = null; $coverageCobertura = null; $coverageCrap4j = null; $coverageCrap4jThreshold = 30; $coverageHtml = null; $coverageHtmlLowUpperBound = $defaultThresholds->lowUpperBound(); $coverageHtmlHighLowerBound = $defaultThresholds->highLowerBound(); $coverageHtmlColorSuccessLow = $defaultColors->successLow(); $coverageHtmlColorSuccessMedium = $defaultColors->successMedium(); $coverageHtmlColorSuccessHigh = $defaultColors->successHigh(); $coverageHtmlColorWarning = $defaultColors->warning(); $coverageHtmlColorDanger = $defaultColors->danger(); $coverageHtmlCustomCssFile = null; $coveragePhp = null; $coverageText = null; $coverageTextShowUncoveredFiles = false; $coverageTextShowOnlySummary = false; $coverageXml = null; $coverageFromXmlConfiguration = true; if ($cliConfiguration->hasNoCoverage() && $cliConfiguration->noCoverage()) { $coverageFromXmlConfiguration = false; } if ($cliConfiguration->hasCoverageClover()) { $coverageClover = $cliConfiguration->coverageClover(); } elseif ($coverageFromXmlConfiguration && $xmlConfiguration->codeCoverage()->hasClover()) { $coverageClover = $xmlConfiguration->codeCoverage()->clover()->target()->path(); } if ($cliConfiguration->hasCoverageCobertura()) { $coverageCobertura = $cliConfiguration->coverageCobertura(); } elseif ($coverageFromXmlConfiguration && $xmlConfiguration->codeCoverage()->hasCobertura()) { $coverageCobertura = $xmlConfiguration->codeCoverage()->cobertura()->target()->path(); } if ($xmlConfiguration->codeCoverage()->hasCrap4j()) { $coverageCrap4jThreshold = $xmlConfiguration->codeCoverage()->crap4j()->threshold(); } if ($cliConfiguration->hasCoverageCrap4J()) { $coverageCrap4j = $cliConfiguration->coverageCrap4J(); } elseif ($coverageFromXmlConfiguration && $xmlConfiguration->codeCoverage()->hasCrap4j()) { $coverageCrap4j = $xmlConfiguration->codeCoverage()->crap4j()->target()->path(); } if ($xmlConfiguration->codeCoverage()->hasHtml()) { $coverageHtmlHighLowerBound = $xmlConfiguration->codeCoverage()->html()->highLowerBound(); $coverageHtmlLowUpperBound = $xmlConfiguration->codeCoverage()->html()->lowUpperBound(); if ($coverageHtmlLowUpperBound > $coverageHtmlHighLowerBound) { $coverageHtmlLowUpperBound = $defaultThresholds->lowUpperBound(); $coverageHtmlHighLowerBound = $defaultThresholds->highLowerBound(); } $coverageHtmlColorSuccessLow = $xmlConfiguration->codeCoverage()->html()->colorSuccessLow(); $coverageHtmlColorSuccessMedium = $xmlConfiguration->codeCoverage()->html()->colorSuccessMedium(); $coverageHtmlColorSuccessHigh = $xmlConfiguration->codeCoverage()->html()->colorSuccessHigh(); $coverageHtmlColorWarning = $xmlConfiguration->codeCoverage()->html()->colorWarning(); $coverageHtmlColorDanger = $xmlConfiguration->codeCoverage()->html()->colorDanger(); if ($xmlConfiguration->codeCoverage()->html()->hasCustomCssFile()) { $coverageHtmlCustomCssFile = $xmlConfiguration->codeCoverage()->html()->customCssFile(); } } if ($cliConfiguration->hasCoverageHtml()) { $coverageHtml = $cliConfiguration->coverageHtml(); } elseif ($coverageFromXmlConfiguration && $xmlConfiguration->codeCoverage()->hasHtml()) { $coverageHtml = $xmlConfiguration->codeCoverage()->html()->target()->path(); } if ($cliConfiguration->hasCoveragePhp()) { $coveragePhp = $cliConfiguration->coveragePhp(); } elseif ($coverageFromXmlConfiguration && $xmlConfiguration->codeCoverage()->hasPhp()) { $coveragePhp = $xmlConfiguration->codeCoverage()->php()->target()->path(); } if ($xmlConfiguration->codeCoverage()->hasText()) { $coverageTextShowUncoveredFiles = $xmlConfiguration->codeCoverage()->text()->showUncoveredFiles(); $coverageTextShowOnlySummary = $xmlConfiguration->codeCoverage()->text()->showOnlySummary(); } if ($cliConfiguration->hasCoverageText()) { $coverageText = $cliConfiguration->coverageText(); } elseif ($coverageFromXmlConfiguration && $xmlConfiguration->codeCoverage()->hasText()) { $coverageText = $xmlConfiguration->codeCoverage()->text()->target()->path(); } if ($cliConfiguration->hasCoverageXml()) { $coverageXml = $cliConfiguration->coverageXml(); } elseif ($coverageFromXmlConfiguration && $xmlConfiguration->codeCoverage()->hasXml()) { $coverageXml = $xmlConfiguration->codeCoverage()->xml()->target()->path(); } if ($cliConfiguration->hasBackupGlobals()) { $backupGlobals = $cliConfiguration->backupGlobals(); } else { $backupGlobals = $xmlConfiguration->phpunit()->backupGlobals(); } if ($cliConfiguration->hasBackupStaticProperties()) { $backupStaticProperties = $cliConfiguration->backupStaticProperties(); } else { $backupStaticProperties = $xmlConfiguration->phpunit()->backupStaticProperties(); } if ($cliConfiguration->hasBeStrictAboutChangesToGlobalState()) { $beStrictAboutChangesToGlobalState = $cliConfiguration->beStrictAboutChangesToGlobalState(); } else { $beStrictAboutChangesToGlobalState = $xmlConfiguration->phpunit()->beStrictAboutChangesToGlobalState(); } if ($cliConfiguration->hasProcessIsolation()) { $processIsolation = $cliConfiguration->processIsolation(); } else { $processIsolation = $xmlConfiguration->phpunit()->processIsolation(); } if ($cliConfiguration->hasEnforceTimeLimit()) { $enforceTimeLimit = $cliConfiguration->enforceTimeLimit(); } else { $enforceTimeLimit = $xmlConfiguration->phpunit()->enforceTimeLimit(); } if ($enforceTimeLimit && !(new Invoker)->canInvokeWithTimeout()) { EventFacade::emitter()->testRunnerTriggeredWarning( 'The pcntl extension is required for enforcing time limits', ); } if ($cliConfiguration->hasDefaultTimeLimit()) { $defaultTimeLimit = $cliConfiguration->defaultTimeLimit(); } else { $defaultTimeLimit = $xmlConfiguration->phpunit()->defaultTimeLimit(); } $timeoutForSmallTests = $xmlConfiguration->phpunit()->timeoutForSmallTests(); $timeoutForMediumTests = $xmlConfiguration->phpunit()->timeoutForMediumTests(); $timeoutForLargeTests = $xmlConfiguration->phpunit()->timeoutForLargeTests(); if ($cliConfiguration->hasReportUselessTests()) { $reportUselessTests = $cliConfiguration->reportUselessTests(); } else { $reportUselessTests = $xmlConfiguration->phpunit()->beStrictAboutTestsThatDoNotTestAnything(); } if ($cliConfiguration->hasStrictCoverage()) { $strictCoverage = $cliConfiguration->strictCoverage(); } else { $strictCoverage = $xmlConfiguration->phpunit()->beStrictAboutCoverageMetadata(); } if ($cliConfiguration->hasDisallowTestOutput()) { $disallowTestOutput = $cliConfiguration->disallowTestOutput(); } else { $disallowTestOutput = $xmlConfiguration->phpunit()->beStrictAboutOutputDuringTests(); } if ($cliConfiguration->hasDisplayDetailsOnIncompleteTests()) { $displayDetailsOnIncompleteTests = $cliConfiguration->displayDetailsOnIncompleteTests(); } else { $displayDetailsOnIncompleteTests = $xmlConfiguration->phpunit()->displayDetailsOnIncompleteTests(); } if ($cliConfiguration->hasDisplayDetailsOnSkippedTests()) { $displayDetailsOnSkippedTests = $cliConfiguration->displayDetailsOnSkippedTests(); } else { $displayDetailsOnSkippedTests = $xmlConfiguration->phpunit()->displayDetailsOnSkippedTests(); } if ($cliConfiguration->hasDisplayDetailsOnTestsThatTriggerDeprecations()) { $displayDetailsOnTestsThatTriggerDeprecations = $cliConfiguration->displayDetailsOnTestsThatTriggerDeprecations(); } else { $displayDetailsOnTestsThatTriggerDeprecations = $xmlConfiguration->phpunit()->displayDetailsOnTestsThatTriggerDeprecations(); } if ($cliConfiguration->hasDisplayDetailsOnTestsThatTriggerErrors()) { $displayDetailsOnTestsThatTriggerErrors = $cliConfiguration->displayDetailsOnTestsThatTriggerErrors(); } else { $displayDetailsOnTestsThatTriggerErrors = $xmlConfiguration->phpunit()->displayDetailsOnTestsThatTriggerErrors(); } if ($cliConfiguration->hasDisplayDetailsOnTestsThatTriggerNotices()) { $displayDetailsOnTestsThatTriggerNotices = $cliConfiguration->displayDetailsOnTestsThatTriggerNotices(); } else { $displayDetailsOnTestsThatTriggerNotices = $xmlConfiguration->phpunit()->displayDetailsOnTestsThatTriggerNotices(); } if ($cliConfiguration->hasDisplayDetailsOnTestsThatTriggerWarnings()) { $displayDetailsOnTestsThatTriggerWarnings = $cliConfiguration->displayDetailsOnTestsThatTriggerWarnings(); } else { $displayDetailsOnTestsThatTriggerWarnings = $xmlConfiguration->phpunit()->displayDetailsOnTestsThatTriggerWarnings(); } if ($cliConfiguration->hasReverseList()) { $reverseDefectList = $cliConfiguration->reverseList(); } else { $reverseDefectList = $xmlConfiguration->phpunit()->reverseDefectList(); } $requireCoverageMetadata = $xmlConfiguration->phpunit()->requireCoverageMetadata(); $registerMockObjectsFromTestArgumentsRecursively = $xmlConfiguration->phpunit()->registerMockObjectsFromTestArgumentsRecursively(); if ($cliConfiguration->hasExecutionOrder()) { $executionOrder = $cliConfiguration->executionOrder(); } else { $executionOrder = $xmlConfiguration->phpunit()->executionOrder(); } $executionOrderDefects = TestSuiteSorter::ORDER_DEFAULT; if ($cliConfiguration->hasExecutionOrderDefects()) { $executionOrderDefects = $cliConfiguration->executionOrderDefects(); } elseif ($xmlConfiguration->phpunit()->defectsFirst()) { $executionOrderDefects = TestSuiteSorter::ORDER_DEFECTS_FIRST; } if ($cliConfiguration->hasResolveDependencies()) { $resolveDependencies = $cliConfiguration->resolveDependencies(); } else { $resolveDependencies = $xmlConfiguration->phpunit()->resolveDependencies(); } $colors = false; $colorsSupported = (new Console)->hasColorSupport(); if ($cliConfiguration->hasColors()) { if ($cliConfiguration->colors() === Configuration::COLOR_ALWAYS) { $colors = true; } elseif ($colorsSupported && $cliConfiguration->colors() === Configuration::COLOR_AUTO) { $colors = true; } } elseif ($xmlConfiguration->phpunit()->colors() === Configuration::COLOR_ALWAYS) { $colors = true; } elseif ($colorsSupported && $xmlConfiguration->phpunit()->colors() === Configuration::COLOR_AUTO) { $colors = true; } $logfileTeamcity = null; $logfileJunit = null; $logfileTestdoxHtml = null; $logfileTestdoxText = null; $loggingFromXmlConfiguration = true; if ($cliConfiguration->hasNoLogging() && $cliConfiguration->noLogging()) { $loggingFromXmlConfiguration = false; } if ($cliConfiguration->hasTeamcityLogfile()) { $logfileTeamcity = $cliConfiguration->teamcityLogfile(); } elseif ($loggingFromXmlConfiguration && $xmlConfiguration->logging()->hasTeamCity()) { $logfileTeamcity = $xmlConfiguration->logging()->teamCity()->target()->path(); } if ($cliConfiguration->hasJunitLogfile()) { $logfileJunit = $cliConfiguration->junitLogfile(); } elseif ($loggingFromXmlConfiguration && $xmlConfiguration->logging()->hasJunit()) { $logfileJunit = $xmlConfiguration->logging()->junit()->target()->path(); } if ($cliConfiguration->hasTestdoxHtmlFile()) { $logfileTestdoxHtml = $cliConfiguration->testdoxHtmlFile(); } elseif ($loggingFromXmlConfiguration && $xmlConfiguration->logging()->hasTestDoxHtml()) { $logfileTestdoxHtml = $xmlConfiguration->logging()->testDoxHtml()->target()->path(); } if ($cliConfiguration->hasTestdoxTextFile()) { $logfileTestdoxText = $cliConfiguration->testdoxTextFile(); } elseif ($loggingFromXmlConfiguration && $xmlConfiguration->logging()->hasTestDoxText()) { $logfileTestdoxText = $xmlConfiguration->logging()->testDoxText()->target()->path(); } $logEventsText = null; if ($cliConfiguration->hasLogEventsText()) { $logEventsText = $cliConfiguration->logEventsText(); } $logEventsVerboseText = null; if ($cliConfiguration->hasLogEventsVerboseText()) { $logEventsVerboseText = $cliConfiguration->logEventsVerboseText(); } $teamCityOutput = false; if ($cliConfiguration->hasTeamCityPrinter() && $cliConfiguration->teamCityPrinter()) { $teamCityOutput = true; } if ($cliConfiguration->hasTestDoxPrinter() && $cliConfiguration->testdoxPrinter()) { $testDoxOutput = true; } else { $testDoxOutput = $xmlConfiguration->phpunit()->testdoxPrinter(); } $noProgress = false; if ($cliConfiguration->hasNoProgress() && $cliConfiguration->noProgress()) { $noProgress = true; } $noResults = false; if ($cliConfiguration->hasNoResults() && $cliConfiguration->noResults()) { $noResults = true; } $noOutput = false; if ($cliConfiguration->hasNoOutput() && $cliConfiguration->noOutput()) { $noOutput = true; } $testsCovering = null; if ($cliConfiguration->hasTestsCovering()) { $testsCovering = $cliConfiguration->testsCovering(); } $testsUsing = null; if ($cliConfiguration->hasTestsUsing()) { $testsUsing = $cliConfiguration->testsUsing(); } $filter = null; if ($cliConfiguration->hasFilter()) { $filter = $cliConfiguration->filter(); } if ($cliConfiguration->hasGroups()) { $groups = $cliConfiguration->groups(); } else { $groups = $xmlConfiguration->groups()->include()->asArrayOfStrings(); } if ($cliConfiguration->hasExcludeGroups()) { $excludeGroups = $cliConfiguration->excludeGroups(); } else { $excludeGroups = $xmlConfiguration->groups()->exclude()->asArrayOfStrings(); } $excludeGroups = array_diff($excludeGroups, $groups); if ($cliConfiguration->hasRandomOrderSeed()) { $randomOrderSeed = $cliConfiguration->randomOrderSeed(); } else { $randomOrderSeed = time(); } if ($xmlConfiguration->wasLoadedFromFile() && $xmlConfiguration->hasValidationErrors()) { if ((new SchemaDetector)->detect($xmlConfiguration->filename())->detected()) { EventFacade::emitter()->testRunnerTriggeredDeprecation( 'Your XML configuration validates against a deprecated schema. Migrate your XML configuration using "--migrate-configuration"!', ); } else { EventFacade::emitter()->testRunnerTriggeredWarning( "Test results may not be as expected because the XML configuration file did not pass validation:\n" . $xmlConfiguration->validationErrors(), ); } } $includeUncoveredFiles = $xmlConfiguration->codeCoverage()->includeUncoveredFiles(); $includePaths = []; if ($cliConfiguration->hasIncludePath()) { foreach (explode(PATH_SEPARATOR, $cliConfiguration->includePath()) as $includePath) { $includePaths[] = new Directory($includePath); } } foreach ($xmlConfiguration->php()->includePaths() as $includePath) { $includePaths[] = $includePath; } $iniSettings = []; if ($cliConfiguration->hasIniSettings()) { foreach ($cliConfiguration->iniSettings() as $name => $value) { $iniSettings[] = new IniSetting($name, $value); } } foreach ($xmlConfiguration->php()->iniSettings() as $iniSetting) { $iniSettings[] = $iniSetting; } $includeTestSuite = ''; if ($cliConfiguration->hasTestSuite()) { $includeTestSuite = $cliConfiguration->testSuite(); } elseif ($xmlConfiguration->phpunit()->hasDefaultTestSuite()) { $includeTestSuite = $xmlConfiguration->phpunit()->defaultTestSuite(); } $excludeTestSuite = ''; if ($cliConfiguration->hasExcludedTestSuite()) { $excludeTestSuite = $cliConfiguration->excludedTestSuite(); } $testSuffixes = ['Test.php', '.phpt']; if ($cliConfiguration->hasTestSuffixes()) { $testSuffixes = $cliConfiguration->testSuffixes(); } $sourceIncludeDirectories = []; if ($cliConfiguration->hasCoverageFilter()) { foreach ($cliConfiguration->coverageFilter() as $directory) { $sourceIncludeDirectories[] = new FilterDirectory($directory, '', '.php'); } } if ($xmlConfiguration->codeCoverage()->hasNonEmptyListOfFilesToBeIncludedInCodeCoverageReport()) { foreach ($xmlConfiguration->codeCoverage()->directories() as $directory) { $sourceIncludeDirectories[] = $directory; } $sourceIncludeFiles = $xmlConfiguration->codeCoverage()->files(); $sourceExcludeDirectories = $xmlConfiguration->codeCoverage()->excludeDirectories(); $sourceExcludeFiles = $xmlConfiguration->codeCoverage()->excludeFiles(); } else { foreach ($xmlConfiguration->source()->includeDirectories() as $directory) { $sourceIncludeDirectories[] = $directory; } $sourceIncludeFiles = $xmlConfiguration->source()->includeFiles(); $sourceExcludeDirectories = $xmlConfiguration->source()->excludeDirectories(); $sourceExcludeFiles = $xmlConfiguration->source()->excludeFiles(); } $useBaseline = null; $generateBaseline = null; if (!$cliConfiguration->hasGenerateBaseline()) { if ($cliConfiguration->hasUseBaseline()) { $useBaseline = $cliConfiguration->useBaseline(); } elseif ($xmlConfiguration->source()->hasBaseline()) { $useBaseline = $xmlConfiguration->source()->baseline(); } } else { $generateBaseline = $cliConfiguration->generateBaseline(); } assert($useBaseline !== ''); assert($generateBaseline !== ''); return new Configuration( $cliConfiguration->arguments(), $configurationFile, $bootstrap, $cacheResult, $cacheDirectory, $coverageCacheDirectory, new Source( $useBaseline, $cliConfiguration->ignoreBaseline(), FilterDirectoryCollection::fromArray($sourceIncludeDirectories), $sourceIncludeFiles, $sourceExcludeDirectories, $sourceExcludeFiles, $xmlConfiguration->source()->restrictDeprecations(), $xmlConfiguration->source()->restrictNotices(), $xmlConfiguration->source()->restrictWarnings(), $xmlConfiguration->source()->ignoreSuppressionOfDeprecations(), $xmlConfiguration->source()->ignoreSuppressionOfPhpDeprecations(), $xmlConfiguration->source()->ignoreSuppressionOfErrors(), $xmlConfiguration->source()->ignoreSuppressionOfNotices(), $xmlConfiguration->source()->ignoreSuppressionOfPhpNotices(), $xmlConfiguration->source()->ignoreSuppressionOfWarnings(), $xmlConfiguration->source()->ignoreSuppressionOfPhpWarnings(), ), $testResultCacheFile, $coverageClover, $coverageCobertura, $coverageCrap4j, $coverageCrap4jThreshold, $coverageHtml, $coverageHtmlLowUpperBound, $coverageHtmlHighLowerBound, $coverageHtmlColorSuccessLow, $coverageHtmlColorSuccessMedium, $coverageHtmlColorSuccessHigh, $coverageHtmlColorWarning, $coverageHtmlColorDanger, $coverageHtmlCustomCssFile, $coveragePhp, $coverageText, $coverageTextShowUncoveredFiles, $coverageTextShowOnlySummary, $coverageXml, $pathCoverage, $xmlConfiguration->codeCoverage()->ignoreDeprecatedCodeUnits(), $disableCodeCoverageIgnore, $failOnDeprecation, $failOnEmptyTestSuite, $failOnIncomplete, $failOnNotice, $failOnRisky, $failOnSkipped, $failOnWarning, $stopOnDefect, $stopOnDeprecation, $stopOnError, $stopOnFailure, $stopOnIncomplete, $stopOnNotice, $stopOnRisky, $stopOnSkipped, $stopOnWarning, $outputToStandardErrorStream, $columns, $noExtensions, $pharExtensionDirectory, $extensionBootstrappers, $backupGlobals, $backupStaticProperties, $beStrictAboutChangesToGlobalState, $colors, $processIsolation, $enforceTimeLimit, $defaultTimeLimit, $timeoutForSmallTests, $timeoutForMediumTests, $timeoutForLargeTests, $reportUselessTests, $strictCoverage, $disallowTestOutput, $displayDetailsOnIncompleteTests, $displayDetailsOnSkippedTests, $displayDetailsOnTestsThatTriggerDeprecations, $displayDetailsOnTestsThatTriggerErrors, $displayDetailsOnTestsThatTriggerNotices, $displayDetailsOnTestsThatTriggerWarnings, $reverseDefectList, $requireCoverageMetadata, $registerMockObjectsFromTestArgumentsRecursively, $noProgress, $noResults, $noOutput, $executionOrder, $executionOrderDefects, $resolveDependencies, $logfileTeamcity, $logfileJunit, $logfileTestdoxHtml, $logfileTestdoxText, $logEventsText, $logEventsVerboseText, $teamCityOutput, $testDoxOutput, $testsCovering, $testsUsing, $filter, $groups, $excludeGroups, $randomOrderSeed, $includeUncoveredFiles, $xmlConfiguration->testSuite(), $includeTestSuite, $excludeTestSuite, $xmlConfiguration->phpunit()->hasDefaultTestSuite() ? $xmlConfiguration->phpunit()->defaultTestSuite() : null, $testSuffixes, new Php( DirectoryCollection::fromArray($includePaths), IniSettingCollection::fromArray($iniSettings), $xmlConfiguration->php()->constants(), $xmlConfiguration->php()->globalVariables(), $xmlConfiguration->php()->envVariables(), $xmlConfiguration->php()->postVariables(), $xmlConfiguration->php()->getVariables(), $xmlConfiguration->php()->cookieVariables(), $xmlConfiguration->php()->serverVariables(), $xmlConfiguration->php()->filesVariables(), $xmlConfiguration->php()->requestVariables(), ), $xmlConfiguration->phpunit()->controlGarbageCollector(), $xmlConfiguration->phpunit()->numberOfTestsBeforeGarbageCollection(), $generateBaseline, ); } } Configuration/SourceFilter.php 0000644 00000001112 15111303725 0012463 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\TextUI\Configuration; /** * @internal This class is not covered by the backward compatibility promise for PHPUnit */ final class SourceFilter { public function includes(Source $source, string $path): bool { $files = (new SourceMapper)->map($source); return isset($files[$path]); } } Configuration/TestSuiteBuilder.php 0000644 00000010157 15111303725 0013326 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\TextUI\Configuration; use function assert; use function count; use function is_dir; use function is_file; use function realpath; use function str_ends_with; use PHPUnit\Event\Facade as EventFacade; use PHPUnit\Exception; use PHPUnit\Framework\TestSuite; use PHPUnit\Runner\TestSuiteLoader; use PHPUnit\TextUI\RuntimeException; use PHPUnit\TextUI\TestDirectoryNotFoundException; use PHPUnit\TextUI\TestFileNotFoundException; use PHPUnit\TextUI\XmlConfiguration\TestSuiteMapper; use SebastianBergmann\FileIterator\Facade as FileIteratorFacade; /** * @internal This class is not covered by the backward compatibility promise for PHPUnit */ final class TestSuiteBuilder { /** * @throws \PHPUnit\Framework\Exception * @throws RuntimeException * @throws TestDirectoryNotFoundException * @throws TestFileNotFoundException */ public function build(Configuration $configuration): TestSuite { if ($configuration->hasCliArguments()) { $arguments = []; foreach ($configuration->cliArguments() as $cliArgument) { $argument = realpath($cliArgument); if (!$argument) { throw new TestFileNotFoundException($cliArgument); } $arguments[] = $argument; } if (count($arguments) === 1) { $testSuite = $this->testSuiteFromPath( $arguments[0], $configuration->testSuffixes(), ); } else { $testSuite = $this->testSuiteFromPathList( $arguments, $configuration->testSuffixes(), ); } } if (!isset($testSuite)) { $xmlConfigurationFile = $configuration->hasConfigurationFile() ? $configuration->configurationFile() : 'Root Test Suite'; assert(!empty($xmlConfigurationFile)); $testSuite = (new TestSuiteMapper)->map( $xmlConfigurationFile, $configuration->testSuite(), $configuration->includeTestSuite(), $configuration->excludeTestSuite(), ); } EventFacade::emitter()->testSuiteLoaded(\PHPUnit\Event\TestSuite\TestSuiteBuilder::from($testSuite)); return $testSuite; } /** * @psalm-param non-empty-string $path * @psalm-param list<non-empty-string> $suffixes * @psalm-param ?TestSuite $suite * * @throws \PHPUnit\Framework\Exception */ private function testSuiteFromPath(string $path, array $suffixes, ?TestSuite $suite = null): TestSuite { if (is_dir($path)) { $files = (new FileIteratorFacade)->getFilesAsArray($path, $suffixes); $suite = $suite ?: TestSuite::empty('CLI Arguments'); $suite->addTestFiles($files); return $suite; } if (is_file($path) && str_ends_with($path, '.phpt')) { $suite = $suite ?: TestSuite::empty($path); $suite->addTestFile($path); return $suite; } try { $testClass = (new TestSuiteLoader)->load($path); } catch (Exception $e) { print $e->getMessage() . PHP_EOL; exit(1); } if (!$suite) { return TestSuite::fromClassReflector($testClass); } $suite->addTestSuite($testClass); return $suite; } /** * @psalm-param list<non-empty-string> $paths * @psalm-param list<non-empty-string> $suffixes * * @throws \PHPUnit\Framework\Exception */ private function testSuiteFromPathList(array $paths, array $suffixes): TestSuite { $suite = TestSuite::empty('CLI Arguments'); foreach ($paths as $path) { $this->testSuiteFromPath($path, $suffixes, $suite); } return $suite; } } Configuration/Exception/NoPharExtensionDirectoryException.php 0000644 00000000776 15111303725 0020662 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\TextUI\Configuration; use RuntimeException; /** * @internal This class is not covered by the backward compatibility promise for PHPUnit */ final class NoPharExtensionDirectoryException extends RuntimeException implements Exception { } Configuration/Exception/NoCacheDirectoryException.php 0000644 00000000766 15111303725 0017075 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\TextUI\Configuration; use RuntimeException; /** * @internal This class is not covered by the backward compatibility promise for PHPUnit */ final class NoCacheDirectoryException extends RuntimeException implements Exception { } Configuration/Exception/CodeCoverageReportNotConfiguredException.php 0000644 00000001005 15111303725 0022104 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\TextUI\Configuration; use RuntimeException; /** * @internal This class is not covered by the backward compatibility promise for PHPUnit */ final class CodeCoverageReportNotConfiguredException extends RuntimeException implements Exception { } Configuration/Exception/ConfigurationCannotBeBuiltException.php 0000644 00000001000 15111303725 0021107 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\TextUI\Configuration; use RuntimeException; /** * @internal This class is not covered by the backward compatibility promise for PHPUnit */ final class ConfigurationCannotBeBuiltException extends RuntimeException implements Exception { } Configuration/Exception/Exception.php 0000644 00000000705 15111303726 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\TextUI\Configuration; /** * @internal This interface is not covered by the backward compatibility promise for PHPUnit */ interface Exception extends \PHPUnit\TextUI\Exception { } Configuration/Exception/NoBootstrapException.php 0000644 00000000761 15111303726 0016156 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\TextUI\Configuration; use RuntimeException; /** * @internal This class is not covered by the backward compatibility promise for PHPUnit */ final class NoBootstrapException extends RuntimeException implements Exception { } Configuration/Exception/NoConfigurationFileException.php 0000644 00000000771 15111303726 0017611 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\TextUI\Configuration; use RuntimeException; /** * @internal This class is not covered by the backward compatibility promise for PHPUnit */ final class NoConfigurationFileException extends RuntimeException implements Exception { } Configuration/Exception/CannotFindSchemaException.php 0000644 00000001045 15111303726 0017044 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\TextUI\XmlConfiguration; use PHPUnit\TextUI\Configuration\Exception; use RuntimeException; /** * @internal This class is not covered by the backward compatibility promise for PHPUnit */ final class CannotFindSchemaException extends RuntimeException implements Exception { } Configuration/Exception/NoDefaultTestSuiteException.php 0000644 00000000770 15111303726 0017437 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\TextUI\Configuration; use RuntimeException; /** * @internal This class is not covered by the backward compatibility promise for PHPUnit */ final class NoDefaultTestSuiteException extends RuntimeException implements Exception { } Configuration/Exception/NoCliArgumentException.php 0000644 00000000763 15111303726 0016415 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\TextUI\Configuration; use RuntimeException; /** * @internal This class is not covered by the backward compatibility promise for PHPUnit */ final class NoCliArgumentException extends RuntimeException implements Exception { } Configuration/Exception/NoCustomCssFileException.php 0000644 00000000765 15111303726 0016730 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\TextUI\Configuration; use RuntimeException; /** * @internal This class is not covered by the backward compatibility promise for PHPUnit */ final class NoCustomCssFileException extends RuntimeException implements Exception { } Configuration/Exception/IncludePathNotConfiguredException.php 0000644 00000000776 15111303726 0020601 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\TextUI\Configuration; use RuntimeException; /** * @internal This class is not covered by the backward compatibility promise for PHPUnit */ final class IncludePathNotConfiguredException extends RuntimeException implements Exception { } Configuration/Exception/LoggingNotConfiguredException.php 0000644 00000000772 15111303726 0017763 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\TextUI\Configuration; use RuntimeException; /** * @internal This class is not covered by the backward compatibility promise for PHPUnit */ final class LoggingNotConfiguredException extends RuntimeException implements Exception { } Configuration/Exception/FilterNotConfiguredException.php 0000644 00000000771 15111303726 0017621 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\TextUI\Configuration; use RuntimeException; /** * @internal This class is not covered by the backward compatibility promise for PHPUnit */ final class FilterNotConfiguredException extends RuntimeException implements Exception { } Configuration/Exception/NoCoverageCacheDirectoryException.php 0000644 00000000776 15111303726 0020553 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\TextUI\Configuration; use RuntimeException; /** * @internal This class is not covered by the backward compatibility promise for PHPUnit */ final class NoCoverageCacheDirectoryException extends RuntimeException implements Exception { } Configuration/Exception/NoBaselineException.php 0000644 00000000760 15111303726 0015722 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\TextUI\Configuration; use RuntimeException; /** * @internal This class is not covered by the backward compatibility promise for PHPUnit */ final class NoBaselineException extends RuntimeException implements Exception { } Configuration/Builder.php 0000644 00000003271 15111303726 0011454 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\TextUI\Configuration; use PHPUnit\TextUI\CliArguments\Builder as CliConfigurationBuilder; use PHPUnit\TextUI\CliArguments\Exception as CliConfigurationException; use PHPUnit\TextUI\CliArguments\XmlConfigurationFileFinder; use PHPUnit\TextUI\XmlConfiguration\DefaultConfiguration; use PHPUnit\TextUI\XmlConfiguration\Exception as XmlConfigurationException; use PHPUnit\TextUI\XmlConfiguration\Loader; /** * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit * * @codeCoverageIgnore */ final class Builder { /** * @throws ConfigurationCannotBeBuiltException */ public function build(array $argv): Configuration { try { $cliConfiguration = (new CliConfigurationBuilder)->fromParameters($argv); $configurationFile = (new XmlConfigurationFileFinder)->find($cliConfiguration); $xmlConfiguration = DefaultConfiguration::create(); if ($configurationFile) { $xmlConfiguration = (new Loader)->load($configurationFile); } return Registry::init( $cliConfiguration, $xmlConfiguration, ); } catch (CliConfigurationException|XmlConfigurationException $e) { throw new ConfigurationCannotBeBuiltException( $e->getMessage(), $e->getCode(), $e, ); } } } Configuration/Configuration.php 0000644 00000117327 15111303726 0012705 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\TextUI\Configuration; /** * @psalm-immutable * * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit */ final class Configuration { public const COLOR_NEVER = 'never'; public const COLOR_AUTO = 'auto'; public const COLOR_ALWAYS = 'always'; public const COLOR_DEFAULT = self::COLOR_NEVER; /** * @psalm-var list<non-empty-string> */ private readonly array $cliArguments; private readonly ?string $configurationFile; private readonly ?string $bootstrap; private readonly bool $cacheResult; private readonly ?string $cacheDirectory; private readonly ?string $coverageCacheDirectory; private readonly Source $source; private readonly bool $pathCoverage; private readonly ?string $coverageClover; private readonly ?string $coverageCobertura; private readonly ?string $coverageCrap4j; private readonly int $coverageCrap4jThreshold; private readonly ?string $coverageHtml; private readonly int $coverageHtmlLowUpperBound; private readonly int $coverageHtmlHighLowerBound; private readonly string $coverageHtmlColorSuccessLow; private readonly string $coverageHtmlColorSuccessMedium; private readonly string $coverageHtmlColorSuccessHigh; private readonly string $coverageHtmlColorWarning; private readonly string $coverageHtmlColorDanger; private readonly ?string $coverageHtmlCustomCssFile; private readonly ?string $coveragePhp; private readonly ?string $coverageText; private readonly bool $coverageTextShowUncoveredFiles; private readonly bool $coverageTextShowOnlySummary; private readonly ?string $coverageXml; private readonly string $testResultCacheFile; private readonly bool $ignoreDeprecatedCodeUnitsFromCodeCoverage; private readonly bool $disableCodeCoverageIgnore; private readonly bool $failOnDeprecation; private readonly bool $failOnEmptyTestSuite; private readonly bool $failOnIncomplete; private readonly bool $failOnNotice; private readonly bool $failOnRisky; private readonly bool $failOnSkipped; private readonly bool $failOnWarning; private readonly bool $stopOnDefect; private readonly bool $stopOnDeprecation; private readonly bool $stopOnError; private readonly bool $stopOnFailure; private readonly bool $stopOnIncomplete; private readonly bool $stopOnNotice; private readonly bool $stopOnRisky; private readonly bool $stopOnSkipped; private readonly bool $stopOnWarning; private readonly bool $outputToStandardErrorStream; private readonly int $columns; private readonly bool $noExtensions; /** * @psalm-var ?non-empty-string */ private readonly ?string $pharExtensionDirectory; /** * @psalm-var list<array{className: class-string, parameters: array<string, string>}> */ private readonly array $extensionBootstrappers; private readonly bool $backupGlobals; private readonly bool $backupStaticProperties; private readonly bool $beStrictAboutChangesToGlobalState; private readonly bool $colors; private readonly bool $processIsolation; private readonly bool $enforceTimeLimit; private readonly int $defaultTimeLimit; private readonly int $timeoutForSmallTests; private readonly int $timeoutForMediumTests; private readonly int $timeoutForLargeTests; private readonly bool $reportUselessTests; private readonly bool $strictCoverage; private readonly bool $disallowTestOutput; private readonly bool $displayDetailsOnIncompleteTests; private readonly bool $displayDetailsOnSkippedTests; private readonly bool $displayDetailsOnTestsThatTriggerDeprecations; private readonly bool $displayDetailsOnTestsThatTriggerErrors; private readonly bool $displayDetailsOnTestsThatTriggerNotices; private readonly bool $displayDetailsOnTestsThatTriggerWarnings; private readonly bool $reverseDefectList; private readonly bool $requireCoverageMetadata; private readonly bool $registerMockObjectsFromTestArgumentsRecursively; private readonly bool $noProgress; private readonly bool $noResults; private readonly bool $noOutput; private readonly int $executionOrder; private readonly int $executionOrderDefects; private readonly bool $resolveDependencies; private readonly ?string $logfileTeamcity; private readonly ?string $logfileJunit; private readonly ?string $logfileTestdoxHtml; private readonly ?string $logfileTestdoxText; private readonly ?string $logEventsText; private readonly ?string $logEventsVerboseText; private readonly ?array $testsCovering; private readonly ?array $testsUsing; private readonly bool $teamCityOutput; private readonly bool $testDoxOutput; private readonly ?string $filter; private readonly ?array $groups; private readonly ?array $excludeGroups; private readonly int $randomOrderSeed; private readonly bool $includeUncoveredFiles; private readonly TestSuiteCollection $testSuite; private readonly string $includeTestSuite; private readonly string $excludeTestSuite; private readonly ?string $defaultTestSuite; /** * @psalm-var non-empty-list<non-empty-string> */ private readonly array $testSuffixes; private readonly Php $php; private readonly bool $controlGarbageCollector; private readonly int $numberOfTestsBeforeGarbageCollection; private readonly ?string $generateBaseline; /** * @psalm-param list<non-empty-string> $cliArguments * @psalm-param ?non-empty-string $pharExtensionDirectory * @psalm-param non-empty-list<non-empty-string> $testSuffixes * @psalm-param list<array{className: class-string, parameters: array<string, string>}> $extensionBootstrappers */ public function __construct(array $cliArguments, ?string $configurationFile, ?string $bootstrap, bool $cacheResult, ?string $cacheDirectory, ?string $coverageCacheDirectory, Source $source, string $testResultCacheFile, ?string $coverageClover, ?string $coverageCobertura, ?string $coverageCrap4j, int $coverageCrap4jThreshold, ?string $coverageHtml, int $coverageHtmlLowUpperBound, int $coverageHtmlHighLowerBound, string $coverageHtmlColorSuccessLow, string $coverageHtmlColorSuccessMedium, string $coverageHtmlColorSuccessHigh, string $coverageHtmlColorWarning, string $coverageHtmlColorDanger, ?string $coverageHtmlCustomCssFile, ?string $coveragePhp, ?string $coverageText, bool $coverageTextShowUncoveredFiles, bool $coverageTextShowOnlySummary, ?string $coverageXml, bool $pathCoverage, bool $ignoreDeprecatedCodeUnitsFromCodeCoverage, bool $disableCodeCoverageIgnore, bool $failOnDeprecation, bool $failOnEmptyTestSuite, bool $failOnIncomplete, bool $failOnNotice, bool $failOnRisky, bool $failOnSkipped, bool $failOnWarning, bool $stopOnDefect, bool $stopOnDeprecation, bool $stopOnError, bool $stopOnFailure, bool $stopOnIncomplete, bool $stopOnNotice, bool $stopOnRisky, bool $stopOnSkipped, bool $stopOnWarning, bool $outputToStandardErrorStream, int|string $columns, bool $noExtensions, ?string $pharExtensionDirectory, array $extensionBootstrappers, bool $backupGlobals, bool $backupStaticProperties, bool $beStrictAboutChangesToGlobalState, bool $colors, bool $processIsolation, bool $enforceTimeLimit, int $defaultTimeLimit, int $timeoutForSmallTests, int $timeoutForMediumTests, int $timeoutForLargeTests, bool $reportUselessTests, bool $strictCoverage, bool $disallowTestOutput, bool $displayDetailsOnIncompleteTests, bool $displayDetailsOnSkippedTests, bool $displayDetailsOnTestsThatTriggerDeprecations, bool $displayDetailsOnTestsThatTriggerErrors, bool $displayDetailsOnTestsThatTriggerNotices, bool $displayDetailsOnTestsThatTriggerWarnings, bool $reverseDefectList, bool $requireCoverageMetadata, bool $registerMockObjectsFromTestArgumentsRecursively, bool $noProgress, bool $noResults, bool $noOutput, int $executionOrder, int $executionOrderDefects, bool $resolveDependencies, ?string $logfileTeamcity, ?string $logfileJunit, ?string $logfileTestdoxHtml, ?string $logfileTestdoxText, ?string $logEventsText, ?string $logEventsVerboseText, bool $teamCityOutput, bool $testDoxOutput, ?array $testsCovering, ?array $testsUsing, ?string $filter, ?array $groups, ?array $excludeGroups, int $randomOrderSeed, bool $includeUncoveredFiles, TestSuiteCollection $testSuite, string $includeTestSuite, string $excludeTestSuite, ?string $defaultTestSuite, array $testSuffixes, Php $php, bool $controlGarbageCollector, int $numberOfTestsBeforeGarbageCollection, ?string $generateBaseline) { $this->cliArguments = $cliArguments; $this->configurationFile = $configurationFile; $this->bootstrap = $bootstrap; $this->cacheResult = $cacheResult; $this->cacheDirectory = $cacheDirectory; $this->coverageCacheDirectory = $coverageCacheDirectory; $this->source = $source; $this->testResultCacheFile = $testResultCacheFile; $this->coverageClover = $coverageClover; $this->coverageCobertura = $coverageCobertura; $this->coverageCrap4j = $coverageCrap4j; $this->coverageCrap4jThreshold = $coverageCrap4jThreshold; $this->coverageHtml = $coverageHtml; $this->coverageHtmlLowUpperBound = $coverageHtmlLowUpperBound; $this->coverageHtmlHighLowerBound = $coverageHtmlHighLowerBound; $this->coverageHtmlColorSuccessLow = $coverageHtmlColorSuccessLow; $this->coverageHtmlColorSuccessMedium = $coverageHtmlColorSuccessMedium; $this->coverageHtmlColorSuccessHigh = $coverageHtmlColorSuccessHigh; $this->coverageHtmlColorWarning = $coverageHtmlColorWarning; $this->coverageHtmlColorDanger = $coverageHtmlColorDanger; $this->coverageHtmlCustomCssFile = $coverageHtmlCustomCssFile; $this->coveragePhp = $coveragePhp; $this->coverageText = $coverageText; $this->coverageTextShowUncoveredFiles = $coverageTextShowUncoveredFiles; $this->coverageTextShowOnlySummary = $coverageTextShowOnlySummary; $this->coverageXml = $coverageXml; $this->pathCoverage = $pathCoverage; $this->ignoreDeprecatedCodeUnitsFromCodeCoverage = $ignoreDeprecatedCodeUnitsFromCodeCoverage; $this->disableCodeCoverageIgnore = $disableCodeCoverageIgnore; $this->failOnDeprecation = $failOnDeprecation; $this->failOnEmptyTestSuite = $failOnEmptyTestSuite; $this->failOnIncomplete = $failOnIncomplete; $this->failOnNotice = $failOnNotice; $this->failOnRisky = $failOnRisky; $this->failOnSkipped = $failOnSkipped; $this->failOnWarning = $failOnWarning; $this->stopOnDefect = $stopOnDefect; $this->stopOnDeprecation = $stopOnDeprecation; $this->stopOnError = $stopOnError; $this->stopOnFailure = $stopOnFailure; $this->stopOnIncomplete = $stopOnIncomplete; $this->stopOnNotice = $stopOnNotice; $this->stopOnRisky = $stopOnRisky; $this->stopOnSkipped = $stopOnSkipped; $this->stopOnWarning = $stopOnWarning; $this->outputToStandardErrorStream = $outputToStandardErrorStream; $this->columns = $columns; $this->noExtensions = $noExtensions; $this->pharExtensionDirectory = $pharExtensionDirectory; $this->extensionBootstrappers = $extensionBootstrappers; $this->backupGlobals = $backupGlobals; $this->backupStaticProperties = $backupStaticProperties; $this->beStrictAboutChangesToGlobalState = $beStrictAboutChangesToGlobalState; $this->colors = $colors; $this->processIsolation = $processIsolation; $this->enforceTimeLimit = $enforceTimeLimit; $this->defaultTimeLimit = $defaultTimeLimit; $this->timeoutForSmallTests = $timeoutForSmallTests; $this->timeoutForMediumTests = $timeoutForMediumTests; $this->timeoutForLargeTests = $timeoutForLargeTests; $this->reportUselessTests = $reportUselessTests; $this->strictCoverage = $strictCoverage; $this->disallowTestOutput = $disallowTestOutput; $this->displayDetailsOnIncompleteTests = $displayDetailsOnIncompleteTests; $this->displayDetailsOnSkippedTests = $displayDetailsOnSkippedTests; $this->displayDetailsOnTestsThatTriggerDeprecations = $displayDetailsOnTestsThatTriggerDeprecations; $this->displayDetailsOnTestsThatTriggerErrors = $displayDetailsOnTestsThatTriggerErrors; $this->displayDetailsOnTestsThatTriggerNotices = $displayDetailsOnTestsThatTriggerNotices; $this->displayDetailsOnTestsThatTriggerWarnings = $displayDetailsOnTestsThatTriggerWarnings; $this->reverseDefectList = $reverseDefectList; $this->requireCoverageMetadata = $requireCoverageMetadata; $this->registerMockObjectsFromTestArgumentsRecursively = $registerMockObjectsFromTestArgumentsRecursively; $this->noProgress = $noProgress; $this->noResults = $noResults; $this->noOutput = $noOutput; $this->executionOrder = $executionOrder; $this->executionOrderDefects = $executionOrderDefects; $this->resolveDependencies = $resolveDependencies; $this->logfileTeamcity = $logfileTeamcity; $this->logfileJunit = $logfileJunit; $this->logfileTestdoxHtml = $logfileTestdoxHtml; $this->logfileTestdoxText = $logfileTestdoxText; $this->logEventsText = $logEventsText; $this->logEventsVerboseText = $logEventsVerboseText; $this->teamCityOutput = $teamCityOutput; $this->testDoxOutput = $testDoxOutput; $this->testsCovering = $testsCovering; $this->testsUsing = $testsUsing; $this->filter = $filter; $this->groups = $groups; $this->excludeGroups = $excludeGroups; $this->randomOrderSeed = $randomOrderSeed; $this->includeUncoveredFiles = $includeUncoveredFiles; $this->testSuite = $testSuite; $this->includeTestSuite = $includeTestSuite; $this->excludeTestSuite = $excludeTestSuite; $this->defaultTestSuite = $defaultTestSuite; $this->testSuffixes = $testSuffixes; $this->php = $php; $this->controlGarbageCollector = $controlGarbageCollector; $this->numberOfTestsBeforeGarbageCollection = $numberOfTestsBeforeGarbageCollection; $this->generateBaseline = $generateBaseline; } /** * @psalm-assert-if-true !empty $this->cliArguments */ public function hasCliArguments(): bool { return !empty($this->cliArguments); } /** * @psalm-return list<non-empty-string> */ public function cliArguments(): array { return $this->cliArguments; } /** * @psalm-assert-if-true !empty $this->cliArguments * * @deprecated Use hasCliArguments() instead */ public function hasCliArgument(): bool { return !empty($this->cliArguments); } /** * @throws NoCliArgumentException * * @return non-empty-string * * @deprecated Use cliArguments()[0] instead */ public function cliArgument(): string { if (!$this->hasCliArguments()) { throw new NoCliArgumentException; } return $this->cliArguments[0]; } /** * @psalm-assert-if-true !null $this->configurationFile */ public function hasConfigurationFile(): bool { return $this->configurationFile !== null; } /** * @throws NoConfigurationFileException */ public function configurationFile(): string { if (!$this->hasConfigurationFile()) { throw new NoConfigurationFileException; } return $this->configurationFile; } /** * @psalm-assert-if-true !null $this->bootstrap */ public function hasBootstrap(): bool { return $this->bootstrap !== null; } /** * @throws NoBootstrapException */ public function bootstrap(): string { if (!$this->hasBootstrap()) { throw new NoBootstrapException; } return $this->bootstrap; } public function cacheResult(): bool { return $this->cacheResult; } /** * @psalm-assert-if-true !null $this->cacheDirectory */ public function hasCacheDirectory(): bool { return $this->cacheDirectory !== null; } /** * @throws NoCacheDirectoryException */ public function cacheDirectory(): string { if (!$this->hasCacheDirectory()) { throw new NoCacheDirectoryException; } return $this->cacheDirectory; } /** * @psalm-assert-if-true !null $this->coverageCacheDirectory */ public function hasCoverageCacheDirectory(): bool { return $this->coverageCacheDirectory !== null; } /** * @throws NoCoverageCacheDirectoryException */ public function coverageCacheDirectory(): string { if (!$this->hasCoverageCacheDirectory()) { throw new NoCoverageCacheDirectoryException; } return $this->coverageCacheDirectory; } public function source(): Source { return $this->source; } /** * @deprecated Use source()->restrictDeprecations() instead */ public function restrictDeprecations(): bool { return $this->source()->restrictDeprecations(); } /** * @deprecated Use source()->restrictNotices() instead */ public function restrictNotices(): bool { return $this->source()->restrictNotices(); } /** * @deprecated Use source()->restrictWarnings() instead */ public function restrictWarnings(): bool { return $this->source()->restrictWarnings(); } /** * @deprecated Use source()->notEmpty() instead */ public function hasNonEmptyListOfFilesToBeIncludedInCodeCoverageReport(): bool { return $this->source->notEmpty(); } /** * @deprecated Use source()->includeDirectories() instead */ public function coverageIncludeDirectories(): FilterDirectoryCollection { return $this->source()->includeDirectories(); } /** * @deprecated Use source()->includeFiles() instead */ public function coverageIncludeFiles(): FileCollection { return $this->source()->includeFiles(); } /** * @deprecated Use source()->excludeDirectories() instead */ public function coverageExcludeDirectories(): FilterDirectoryCollection { return $this->source()->excludeDirectories(); } /** * @deprecated Use source()->excludeFiles() instead */ public function coverageExcludeFiles(): FileCollection { return $this->source()->excludeFiles(); } public function testResultCacheFile(): string { return $this->testResultCacheFile; } public function ignoreDeprecatedCodeUnitsFromCodeCoverage(): bool { return $this->ignoreDeprecatedCodeUnitsFromCodeCoverage; } public function disableCodeCoverageIgnore(): bool { return $this->disableCodeCoverageIgnore; } public function pathCoverage(): bool { return $this->pathCoverage; } public function hasCoverageReport(): bool { return $this->hasCoverageClover() || $this->hasCoverageCobertura() || $this->hasCoverageCrap4j() || $this->hasCoverageHtml() || $this->hasCoveragePhp() || $this->hasCoverageText() || $this->hasCoverageXml(); } /** * @psalm-assert-if-true !null $this->coverageClover */ public function hasCoverageClover(): bool { return $this->coverageClover !== null; } /** * @throws CodeCoverageReportNotConfiguredException */ public function coverageClover(): string { if (!$this->hasCoverageClover()) { throw new CodeCoverageReportNotConfiguredException; } return $this->coverageClover; } /** * @psalm-assert-if-true !null $this->coverageCobertura */ public function hasCoverageCobertura(): bool { return $this->coverageCobertura !== null; } /** * @throws CodeCoverageReportNotConfiguredException */ public function coverageCobertura(): string { if (!$this->hasCoverageCobertura()) { throw new CodeCoverageReportNotConfiguredException; } return $this->coverageCobertura; } /** * @psalm-assert-if-true !null $this->coverageCrap4j */ public function hasCoverageCrap4j(): bool { return $this->coverageCrap4j !== null; } /** * @throws CodeCoverageReportNotConfiguredException */ public function coverageCrap4j(): string { if (!$this->hasCoverageCrap4j()) { throw new CodeCoverageReportNotConfiguredException; } return $this->coverageCrap4j; } public function coverageCrap4jThreshold(): int { return $this->coverageCrap4jThreshold; } /** * @psalm-assert-if-true !null $this->coverageHtml */ public function hasCoverageHtml(): bool { return $this->coverageHtml !== null; } /** * @throws CodeCoverageReportNotConfiguredException */ public function coverageHtml(): string { if (!$this->hasCoverageHtml()) { throw new CodeCoverageReportNotConfiguredException; } return $this->coverageHtml; } public function coverageHtmlLowUpperBound(): int { return $this->coverageHtmlLowUpperBound; } public function coverageHtmlHighLowerBound(): int { return $this->coverageHtmlHighLowerBound; } public function coverageHtmlColorSuccessLow(): string { return $this->coverageHtmlColorSuccessLow; } public function coverageHtmlColorSuccessMedium(): string { return $this->coverageHtmlColorSuccessMedium; } public function coverageHtmlColorSuccessHigh(): string { return $this->coverageHtmlColorSuccessHigh; } public function coverageHtmlColorWarning(): string { return $this->coverageHtmlColorWarning; } public function coverageHtmlColorDanger(): string { return $this->coverageHtmlColorDanger; } /** * @psalm-assert-if-true !null $this->coverageHtmlCustomCssFile */ public function hasCoverageHtmlCustomCssFile(): bool { return $this->coverageHtmlCustomCssFile !== null; } /** * @throws NoCustomCssFileException */ public function coverageHtmlCustomCssFile(): string { if (!$this->hasCoverageHtmlCustomCssFile()) { throw new NoCustomCssFileException; } return $this->coverageHtmlCustomCssFile; } /** * @psalm-assert-if-true !null $this->coveragePhp */ public function hasCoveragePhp(): bool { return $this->coveragePhp !== null; } /** * @throws CodeCoverageReportNotConfiguredException */ public function coveragePhp(): string { if (!$this->hasCoveragePhp()) { throw new CodeCoverageReportNotConfiguredException; } return $this->coveragePhp; } /** * @psalm-assert-if-true !null $this->coverageText */ public function hasCoverageText(): bool { return $this->coverageText !== null; } /** * @throws CodeCoverageReportNotConfiguredException */ public function coverageText(): string { if (!$this->hasCoverageText()) { throw new CodeCoverageReportNotConfiguredException; } return $this->coverageText; } public function coverageTextShowUncoveredFiles(): bool { return $this->coverageTextShowUncoveredFiles; } public function coverageTextShowOnlySummary(): bool { return $this->coverageTextShowOnlySummary; } /** * @psalm-assert-if-true !null $this->coverageXml */ public function hasCoverageXml(): bool { return $this->coverageXml !== null; } /** * @throws CodeCoverageReportNotConfiguredException */ public function coverageXml(): string { if (!$this->hasCoverageXml()) { throw new CodeCoverageReportNotConfiguredException; } return $this->coverageXml; } public function failOnDeprecation(): bool { return $this->failOnDeprecation; } public function failOnEmptyTestSuite(): bool { return $this->failOnEmptyTestSuite; } public function failOnIncomplete(): bool { return $this->failOnIncomplete; } public function failOnNotice(): bool { return $this->failOnNotice; } public function failOnRisky(): bool { return $this->failOnRisky; } public function failOnSkipped(): bool { return $this->failOnSkipped; } public function failOnWarning(): bool { return $this->failOnWarning; } public function stopOnDefect(): bool { return $this->stopOnDefect; } public function stopOnDeprecation(): bool { return $this->stopOnDeprecation; } public function stopOnError(): bool { return $this->stopOnError; } public function stopOnFailure(): bool { return $this->stopOnFailure; } public function stopOnIncomplete(): bool { return $this->stopOnIncomplete; } public function stopOnNotice(): bool { return $this->stopOnNotice; } public function stopOnRisky(): bool { return $this->stopOnRisky; } public function stopOnSkipped(): bool { return $this->stopOnSkipped; } public function stopOnWarning(): bool { return $this->stopOnWarning; } public function outputToStandardErrorStream(): bool { return $this->outputToStandardErrorStream; } public function columns(): int { return $this->columns; } /** * @deprecated Use noExtensions() instead */ public function loadPharExtensions(): bool { return $this->noExtensions; } public function noExtensions(): bool { return $this->noExtensions; } /** * @psalm-assert-if-true !null $this->pharExtensionDirectory */ public function hasPharExtensionDirectory(): bool { return $this->pharExtensionDirectory !== null; } /** * @psalm-return non-empty-string * * @throws NoPharExtensionDirectoryException */ public function pharExtensionDirectory(): string { if (!$this->hasPharExtensionDirectory()) { throw new NoPharExtensionDirectoryException; } return $this->pharExtensionDirectory; } /** * @psalm-return list<array{className: class-string, parameters: array<string, string>}> */ public function extensionBootstrappers(): array { return $this->extensionBootstrappers; } public function backupGlobals(): bool { return $this->backupGlobals; } public function backupStaticProperties(): bool { return $this->backupStaticProperties; } public function beStrictAboutChangesToGlobalState(): bool { return $this->beStrictAboutChangesToGlobalState; } public function colors(): bool { return $this->colors; } public function processIsolation(): bool { return $this->processIsolation; } public function enforceTimeLimit(): bool { return $this->enforceTimeLimit; } public function defaultTimeLimit(): int { return $this->defaultTimeLimit; } public function timeoutForSmallTests(): int { return $this->timeoutForSmallTests; } public function timeoutForMediumTests(): int { return $this->timeoutForMediumTests; } public function timeoutForLargeTests(): int { return $this->timeoutForLargeTests; } public function reportUselessTests(): bool { return $this->reportUselessTests; } public function strictCoverage(): bool { return $this->strictCoverage; } public function disallowTestOutput(): bool { return $this->disallowTestOutput; } public function displayDetailsOnIncompleteTests(): bool { return $this->displayDetailsOnIncompleteTests; } public function displayDetailsOnSkippedTests(): bool { return $this->displayDetailsOnSkippedTests; } public function displayDetailsOnTestsThatTriggerDeprecations(): bool { return $this->displayDetailsOnTestsThatTriggerDeprecations; } public function displayDetailsOnTestsThatTriggerErrors(): bool { return $this->displayDetailsOnTestsThatTriggerErrors; } public function displayDetailsOnTestsThatTriggerNotices(): bool { return $this->displayDetailsOnTestsThatTriggerNotices; } public function displayDetailsOnTestsThatTriggerWarnings(): bool { return $this->displayDetailsOnTestsThatTriggerWarnings; } public function reverseDefectList(): bool { return $this->reverseDefectList; } public function requireCoverageMetadata(): bool { return $this->requireCoverageMetadata; } public function registerMockObjectsFromTestArgumentsRecursively(): bool { return $this->registerMockObjectsFromTestArgumentsRecursively; } public function noProgress(): bool { return $this->noProgress; } public function noResults(): bool { return $this->noResults; } public function noOutput(): bool { return $this->noOutput; } public function executionOrder(): int { return $this->executionOrder; } public function executionOrderDefects(): int { return $this->executionOrderDefects; } public function resolveDependencies(): bool { return $this->resolveDependencies; } /** * @psalm-assert-if-true !null $this->logfileTeamcity */ public function hasLogfileTeamcity(): bool { return $this->logfileTeamcity !== null; } /** * @throws LoggingNotConfiguredException */ public function logfileTeamcity(): string { if (!$this->hasLogfileTeamcity()) { throw new LoggingNotConfiguredException; } return $this->logfileTeamcity; } /** * @psalm-assert-if-true !null $this->logfileJunit */ public function hasLogfileJunit(): bool { return $this->logfileJunit !== null; } /** * @throws LoggingNotConfiguredException */ public function logfileJunit(): string { if (!$this->hasLogfileJunit()) { throw new LoggingNotConfiguredException; } return $this->logfileJunit; } /** * @psalm-assert-if-true !null $this->logfileTestdoxHtml */ public function hasLogfileTestdoxHtml(): bool { return $this->logfileTestdoxHtml !== null; } /** * @throws LoggingNotConfiguredException */ public function logfileTestdoxHtml(): string { if (!$this->hasLogfileTestdoxHtml()) { throw new LoggingNotConfiguredException; } return $this->logfileTestdoxHtml; } /** * @psalm-assert-if-true !null $this->logfileTestdoxText */ public function hasLogfileTestdoxText(): bool { return $this->logfileTestdoxText !== null; } /** * @throws LoggingNotConfiguredException */ public function logfileTestdoxText(): string { if (!$this->hasLogfileTestdoxText()) { throw new LoggingNotConfiguredException; } return $this->logfileTestdoxText; } /** * @psalm-assert-if-true !null $this->logEventsText */ public function hasLogEventsText(): bool { return $this->logEventsText !== null; } /** * @throws LoggingNotConfiguredException */ public function logEventsText(): string { if (!$this->hasLogEventsText()) { throw new LoggingNotConfiguredException; } return $this->logEventsText; } /** * @psalm-assert-if-true !null $this->logEventsVerboseText */ public function hasLogEventsVerboseText(): bool { return $this->logEventsVerboseText !== null; } /** * @throws LoggingNotConfiguredException */ public function logEventsVerboseText(): string { if (!$this->hasLogEventsVerboseText()) { throw new LoggingNotConfiguredException; } return $this->logEventsVerboseText; } public function outputIsTeamCity(): bool { return $this->teamCityOutput; } public function outputIsTestDox(): bool { return $this->testDoxOutput; } /** * @psalm-assert-if-true !empty $this->testsCovering */ public function hasTestsCovering(): bool { return !empty($this->testsCovering); } /** * @psalm-return list<string> * * @throws FilterNotConfiguredException */ public function testsCovering(): array { if (!$this->hasTestsCovering()) { throw new FilterNotConfiguredException; } return $this->testsCovering; } /** * @psalm-assert-if-true !empty $this->testsUsing */ public function hasTestsUsing(): bool { return !empty($this->testsUsing); } /** * @psalm-return list<string> * * @throws FilterNotConfiguredException */ public function testsUsing(): array { if (!$this->hasTestsUsing()) { throw new FilterNotConfiguredException; } return $this->testsUsing; } /** * @psalm-assert-if-true !null $this->filter */ public function hasFilter(): bool { return $this->filter !== null; } /** * @throws FilterNotConfiguredException */ public function filter(): string { if (!$this->hasFilter()) { throw new FilterNotConfiguredException; } return $this->filter; } /** * @psalm-assert-if-true !empty $this->groups */ public function hasGroups(): bool { return !empty($this->groups); } /** * @throws FilterNotConfiguredException */ public function groups(): array { if (!$this->hasGroups()) { throw new FilterNotConfiguredException; } return $this->groups; } /** * @psalm-assert-if-true !empty $this->excludeGroups */ public function hasExcludeGroups(): bool { return !empty($this->excludeGroups); } /** * @throws FilterNotConfiguredException */ public function excludeGroups(): array { if (!$this->hasExcludeGroups()) { throw new FilterNotConfiguredException; } return $this->excludeGroups; } public function randomOrderSeed(): int { return $this->randomOrderSeed; } public function includeUncoveredFiles(): bool { return $this->includeUncoveredFiles; } public function testSuite(): TestSuiteCollection { return $this->testSuite; } public function includeTestSuite(): string { return $this->includeTestSuite; } public function excludeTestSuite(): string { return $this->excludeTestSuite; } /** * @psalm-assert-if-true !null $this->defaultTestSuite */ public function hasDefaultTestSuite(): bool { return $this->defaultTestSuite !== null; } /** * @throws NoDefaultTestSuiteException */ public function defaultTestSuite(): string { if (!$this->hasDefaultTestSuite()) { throw new NoDefaultTestSuiteException; } return $this->defaultTestSuite; } /** * @psalm-return non-empty-list<non-empty-string> */ public function testSuffixes(): array { return $this->testSuffixes; } public function php(): Php { return $this->php; } public function controlGarbageCollector(): bool { return $this->controlGarbageCollector; } public function numberOfTestsBeforeGarbageCollection(): int { return $this->numberOfTestsBeforeGarbageCollection; } /** * @psalm-assert-if-true !null $this->generateBaseline */ public function hasGenerateBaseline(): bool { return $this->generateBaseline !== null; } /** * @throws NoBaselineException */ public function generateBaseline(): string { if (!$this->hasGenerateBaseline()) { throw new NoBaselineException; } return $this->generateBaseline; } } Configuration/Xml/Migration/MigrationBuilder.php 0000644 00000006100 15111303727 0016012 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\TextUI\XmlConfiguration; use function array_key_exists; use function sprintf; use function version_compare; /** * @internal This class is not covered by the backward compatibility promise for PHPUnit */ final class MigrationBuilder { private const AVAILABLE_MIGRATIONS = [ '8.5' => [ RemoveLogTypes::class, ], '9.2' => [ RemoveCacheTokensAttribute::class, IntroduceCoverageElement::class, MoveAttributesFromRootToCoverage::class, MoveAttributesFromFilterWhitelistToCoverage::class, MoveWhitelistIncludesToCoverage::class, MoveWhitelistExcludesToCoverage::class, RemoveEmptyFilter::class, CoverageCloverToReport::class, CoverageCrap4jToReport::class, CoverageHtmlToReport::class, CoveragePhpToReport::class, CoverageTextToReport::class, CoverageXmlToReport::class, ConvertLogTypes::class, ], '9.5' => [ RemoveListeners::class, RemoveTestSuiteLoaderAttributes::class, RemoveCacheResultFileAttribute::class, RemoveCoverageElementCacheDirectoryAttribute::class, RemoveCoverageElementProcessUncoveredFilesAttribute::class, IntroduceCacheDirectoryAttribute::class, RenameBackupStaticAttributesAttribute::class, RemoveBeStrictAboutResourceUsageDuringSmallTestsAttribute::class, RemoveBeStrictAboutTodoAnnotatedTestsAttribute::class, RemovePrinterAttributes::class, RemoveVerboseAttribute::class, RenameForceCoversAnnotationAttribute::class, RenameBeStrictAboutCoversAnnotationAttribute::class, RemoveConversionToExceptionsAttributes::class, RemoveNoInteractionAttribute::class, RemoveLoggingElements::class, RemoveTestDoxGroupsElement::class, ], '10.0' => [ MoveCoverageDirectoriesToSource::class, ], ]; /** * @throws MigrationBuilderException */ public function build(string $fromVersion): array { if (!array_key_exists($fromVersion, self::AVAILABLE_MIGRATIONS)) { throw new MigrationBuilderException( sprintf( 'Migration from schema version %s is not supported', $fromVersion, ), ); } $stack = [new UpdateSchemaLocation]; foreach (self::AVAILABLE_MIGRATIONS as $version => $migrations) { if (version_compare($version, $fromVersion, '<')) { continue; } foreach ($migrations as $migration) { $stack[] = new $migration; } } return $stack; } } Configuration/Xml/Migration/SnapshotNodeList.php 0000644 00000002146 15111303727 0016021 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\TextUI\XmlConfiguration; use function count; use ArrayIterator; use Countable; use DOMNode; use DOMNodeList; use IteratorAggregate; /** * @internal This class is not covered by the backward compatibility promise for PHPUnit * * @template-implements IteratorAggregate<int, DOMNode> */ final class SnapshotNodeList implements Countable, IteratorAggregate { /** * @psalm-var list<DOMNode> */ private array $nodes = []; public static function fromNodeList(DOMNodeList $list): self { $snapshot = new self; foreach ($list as $node) { $snapshot->nodes[] = $node; } return $snapshot; } public function count(): int { return count($this->nodes); } public function getIterator(): ArrayIterator { return new ArrayIterator($this->nodes); } } Configuration/Xml/Migration/MigrationException.php 0000644 00000000773 15111303727 0016374 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\TextUI\XmlConfiguration; use RuntimeException; /** * @internal This class is not covered by the backward compatibility promise for PHPUnit */ final class MigrationException extends RuntimeException implements \PHPUnit\Exception { } Configuration/Xml/Migration/Migrations/RemoveCacheTokensAttribute.php 0000644 00000001420 15111303727 0022117 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\TextUI\XmlConfiguration; use function assert; use DOMDocument; use DOMElement; /** * @internal This class is not covered by the backward compatibility promise for PHPUnit */ final class RemoveCacheTokensAttribute implements Migration { public function migrate(DOMDocument $document): void { $root = $document->documentElement; assert($root instanceof DOMElement); if ($root->hasAttribute('cacheTokens')) { $root->removeAttribute('cacheTokens'); } } } Configuration/Xml/Migration/Migrations/RemoveNoInteractionAttribute.php 0000644 00000001426 15111303727 0022512 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\TextUI\XmlConfiguration; use function assert; use DOMDocument; use DOMElement; /** * @internal This class is not covered by the backward compatibility promise for PHPUnit */ final class RemoveNoInteractionAttribute implements Migration { public function migrate(DOMDocument $document): void { $root = $document->documentElement; assert($root instanceof DOMElement); if ($root->hasAttribute('noInteraction')) { $root->removeAttribute('noInteraction'); } } } Configuration/Xml/Migration/Migrations/RenameForceCoversAnnotationAttribute.php 0000644 00000002003 15111303727 0024153 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\TextUI\XmlConfiguration; use function assert; use DOMDocument; use DOMElement; /** * @internal This class is not covered by the backward compatibility promise for PHPUnit */ final class RenameForceCoversAnnotationAttribute implements Migration { public function migrate(DOMDocument $document): void { $root = $document->documentElement; assert($root instanceof DOMElement); if ($root->hasAttribute('requireCoverageMetadata')) { return; } if (!$root->hasAttribute('forceCoversAnnotation')) { return; } $root->setAttribute('requireCoverageMetadata', $root->getAttribute('forceCoversAnnotation')); $root->removeAttribute('forceCoversAnnotation'); } } Configuration/Xml/Migration/Migrations/Migration.php 0000644 00000000756 15111303727 0016632 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\TextUI\XmlConfiguration; use DOMDocument; /** * @internal This class is not covered by the backward compatibility promise for PHPUnit */ interface Migration { public function migrate(DOMDocument $document): void; } Configuration/Xml/Migration/Migrations/RemoveBeStrictAboutTodoAnnotatedTestsAttribute.php 0000644 00000001514 15111303727 0026155 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\TextUI\XmlConfiguration; use function assert; use DOMDocument; use DOMElement; /** * @internal This class is not covered by the backward compatibility promise for PHPUnit */ final class RemoveBeStrictAboutTodoAnnotatedTestsAttribute implements Migration { public function migrate(DOMDocument $document): void { $root = $document->documentElement; assert($root instanceof DOMElement); if ($root->hasAttribute('beStrictAboutTodoAnnotatedTests')) { $root->removeAttribute('beStrictAboutTodoAnnotatedTests'); } } } Configuration/Xml/Migration/Migrations/IntroduceCacheDirectoryAttribute.php 0000644 00000001474 15111303727 0023330 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\TextUI\XmlConfiguration; use function assert; use DOMDocument; use DOMElement; /** * @internal This class is not covered by the backward compatibility promise for PHPUnit */ final class IntroduceCacheDirectoryAttribute implements Migration { public function migrate(DOMDocument $document): void { $root = $document->documentElement; assert($root instanceof DOMElement); if ($root->hasAttribute('cacheDirectory')) { return; } $root->setAttribute('cacheDirectory', '.phpunit.cache'); } } Configuration/Xml/Migration/Migrations/RemoveConversionToExceptionsAttributes.php 0000644 00000002356 15111303727 0024616 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\TextUI\XmlConfiguration; use function assert; use DOMDocument; use DOMElement; /** * @internal This class is not covered by the backward compatibility promise for PHPUnit */ final class RemoveConversionToExceptionsAttributes implements Migration { public function migrate(DOMDocument $document): void { $root = $document->documentElement; assert($root instanceof DOMElement); if ($root->hasAttribute('convertDeprecationsToExceptions')) { $root->removeAttribute('convertDeprecationsToExceptions'); } if ($root->hasAttribute('convertErrorsToExceptions')) { $root->removeAttribute('convertErrorsToExceptions'); } if ($root->hasAttribute('convertNoticesToExceptions')) { $root->removeAttribute('convertNoticesToExceptions'); } if ($root->hasAttribute('convertWarningsToExceptions')) { $root->removeAttribute('convertWarningsToExceptions'); } } } Configuration/Xml/Migration/Migrations/MoveWhitelistIncludesToCoverage.php 0000644 00000002627 15111303727 0023151 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\TextUI\XmlConfiguration; use DOMDocument; use DOMElement; /** * @internal This class is not covered by the backward compatibility promise for PHPUnit */ final class MoveWhitelistIncludesToCoverage implements Migration { /** * @throws MigrationException */ public function migrate(DOMDocument $document): void { $whitelist = $document->getElementsByTagName('whitelist')->item(0); if ($whitelist === null) { return; } $coverage = $document->getElementsByTagName('coverage')->item(0); if (!$coverage instanceof DOMElement) { throw new MigrationException('Unexpected state - No coverage element'); } $include = $document->createElement('include'); $coverage->appendChild($include); foreach (SnapshotNodeList::fromNodeList($whitelist->childNodes) as $child) { if (!$child instanceof DOMElement) { continue; } if (!($child->nodeName === 'directory' || $child->nodeName === 'file')) { continue; } $include->appendChild($child); } } } Configuration/Xml/Migration/Migrations/LogToReportMigration.php 0000644 00000004152 15111303727 0020765 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\TextUI\XmlConfiguration; use function sprintf; use DOMDocument; use DOMElement; use DOMXPath; /** * @internal This class is not covered by the backward compatibility promise for PHPUnit */ abstract class LogToReportMigration implements Migration { /** * @throws MigrationException */ public function migrate(DOMDocument $document): void { $coverage = $document->getElementsByTagName('coverage')->item(0); if (!$coverage instanceof DOMElement) { throw new MigrationException('Unexpected state - No coverage element'); } $logNode = $this->findLogNode($document); if ($logNode === null) { return; } $reportChild = $this->toReportFormat($logNode); $report = $coverage->getElementsByTagName('report')->item(0); if ($report === null) { $report = $coverage->appendChild($document->createElement('report')); } $report->appendChild($reportChild); $logNode->parentNode->removeChild($logNode); } protected function migrateAttributes(DOMElement $src, DOMElement $dest, array $attributes): void { foreach ($attributes as $attr) { if (!$src->hasAttribute($attr)) { continue; } $dest->setAttribute($attr, $src->getAttribute($attr)); $src->removeAttribute($attr); } } abstract protected function forType(): string; abstract protected function toReportFormat(DOMElement $logNode): DOMElement; private function findLogNode(DOMDocument $document): ?DOMElement { $logNode = (new DOMXPath($document))->query( sprintf('//logging/log[@type="%s"]', $this->forType()), )->item(0); if (!$logNode instanceof DOMElement) { return null; } return $logNode; } } Configuration/Xml/Migration/Migrations/RemoveCoverageElementProcessUncoveredFilesAttribute.php 0000644 00000001575 15111303730 0027177 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\TextUI\XmlConfiguration; use DOMDocument; use DOMElement; /** * @internal This class is not covered by the backward compatibility promise for PHPUnit */ final class RemoveCoverageElementProcessUncoveredFilesAttribute implements Migration { public function migrate(DOMDocument $document): void { $node = $document->getElementsByTagName('coverage')->item(0); if (!$node instanceof DOMElement || $node->parentNode === null) { return; } if ($node->hasAttribute('processUncoveredFiles')) { $node->removeAttribute('processUncoveredFiles'); } } } Configuration/Xml/Migration/Migrations/CoveragePhpToReport.php 0000644 00000001444 15111303730 0020570 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\TextUI\XmlConfiguration; use DOMElement; /** * @internal This class is not covered by the backward compatibility promise for PHPUnit */ final class CoveragePhpToReport extends LogToReportMigration { protected function forType(): string { return 'coverage-php'; } protected function toReportFormat(DOMElement $logNode): DOMElement { $php = $logNode->ownerDocument->createElement('php'); $php->setAttribute('outputFile', $logNode->getAttribute('target')); return $php; } } Configuration/Xml/Migration/Migrations/MoveAttributesFromRootToCoverage.php 0000644 00000002572 15111303730 0023315 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\TextUI\XmlConfiguration; use function assert; use DOMDocument; use DOMElement; /** * @internal This class is not covered by the backward compatibility promise for PHPUnit */ final class MoveAttributesFromRootToCoverage implements Migration { /** * @throws MigrationException */ public function migrate(DOMDocument $document): void { $map = [ 'disableCodeCoverageIgnore' => 'disableCodeCoverageIgnore', 'ignoreDeprecatedCodeUnitsFromCodeCoverage' => 'ignoreDeprecatedCodeUnits', ]; $root = $document->documentElement; assert($root instanceof DOMElement); $coverage = $document->getElementsByTagName('coverage')->item(0); if (!$coverage instanceof DOMElement) { throw new MigrationException('Unexpected state - No coverage element'); } foreach ($map as $old => $new) { if (!$root->hasAttribute($old)) { continue; } $coverage->setAttribute($new, $root->getAttribute($old)); $root->removeAttribute($old); } } } Configuration/Xml/Migration/Migrations/MoveWhitelistExcludesToCoverage.php 0000644 00000004105 15111303730 0023142 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\TextUI\XmlConfiguration; use function assert; use function in_array; use DOMDocument; use DOMElement; /** * @internal This class is not covered by the backward compatibility promise for PHPUnit */ final class MoveWhitelistExcludesToCoverage implements Migration { /** * @throws MigrationException */ public function migrate(DOMDocument $document): void { $whitelist = $document->getElementsByTagName('whitelist')->item(0); if ($whitelist === null) { return; } $excludeNodes = SnapshotNodeList::fromNodeList($whitelist->getElementsByTagName('exclude')); if ($excludeNodes->count() === 0) { return; } $coverage = $document->getElementsByTagName('coverage')->item(0); if (!$coverage instanceof DOMElement) { throw new MigrationException('Unexpected state - No coverage element'); } $targetExclude = $coverage->getElementsByTagName('exclude')->item(0); if ($targetExclude === null) { $targetExclude = $coverage->appendChild( $document->createElement('exclude'), ); } foreach ($excludeNodes as $excludeNode) { assert($excludeNode instanceof DOMElement); foreach (SnapshotNodeList::fromNodeList($excludeNode->childNodes) as $child) { if (!$child instanceof DOMElement || !in_array($child->nodeName, ['directory', 'file'], true)) { continue; } $targetExclude->appendChild($child); } if ($excludeNode->getElementsByTagName('*')->count() !== 0) { throw new MigrationException('Dangling child elements in exclude found.'); } $whitelist->removeChild($excludeNode); } } } Configuration/Xml/Migration/Migrations/RemoveLoggingElements.php 0000644 00000002412 15111303730 0021123 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\TextUI\XmlConfiguration; use DOMDocument; use DOMElement; use DOMXPath; /** * @internal This class is not covered by the backward compatibility promise for PHPUnit */ final class RemoveLoggingElements implements Migration { public function migrate(DOMDocument $document): void { $this->removeTestDoxElement($document); $this->removeTextElement($document); } private function removeTestDoxElement(DOMDocument $document): void { $node = (new DOMXPath($document))->query('logging/testdoxXml')->item(0); if (!$node instanceof DOMElement || $node->parentNode === null) { return; } $node->parentNode->removeChild($node); } private function removeTextElement(DOMDocument $document): void { $node = (new DOMXPath($document))->query('logging/text')->item(0); if (!$node instanceof DOMElement || $node->parentNode === null) { return; } $node->parentNode->removeChild($node); } } Configuration/Xml/Migration/Migrations/CoverageTextToReport.php 0000644 00000001611 15111303730 0020761 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\TextUI\XmlConfiguration; use DOMElement; /** * @internal This class is not covered by the backward compatibility promise for PHPUnit */ final class CoverageTextToReport extends LogToReportMigration { protected function forType(): string { return 'coverage-text'; } protected function toReportFormat(DOMElement $logNode): DOMElement { $text = $logNode->ownerDocument->createElement('text'); $text->setAttribute('outputFile', $logNode->getAttribute('target')); $this->migrateAttributes($logNode, $text, ['showUncoveredFiles', 'showOnlySummary']); return $text; } } Configuration/Xml/Migration/Migrations/RemoveEmptyFilter.php 0000644 00000003032 15111303730 0020303 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\TextUI\XmlConfiguration; use function sprintf; use DOMDocument; use DOMElement; /** * @internal This class is not covered by the backward compatibility promise for PHPUnit */ final class RemoveEmptyFilter implements Migration { /** * @throws MigrationException */ public function migrate(DOMDocument $document): void { $whitelist = $document->getElementsByTagName('whitelist')->item(0); if ($whitelist instanceof DOMElement) { $this->ensureEmpty($whitelist); $whitelist->parentNode->removeChild($whitelist); } $filter = $document->getElementsByTagName('filter')->item(0); if ($filter instanceof DOMElement) { $this->ensureEmpty($filter); $filter->parentNode->removeChild($filter); } } /** * @throws MigrationException */ private function ensureEmpty(DOMElement $element): void { if ($element->attributes->length > 0) { throw new MigrationException(sprintf('%s element has unexpected attributes', $element->nodeName)); } if ($element->getElementsByTagName('*')->length > 0) { throw new MigrationException(sprintf('%s element has unexpected children', $element->nodeName)); } } } Configuration/Xml/Migration/Migrations/RemoveListeners.php 0000644 00000001406 15111303730 0020012 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\TextUI\XmlConfiguration; use DOMDocument; use DOMElement; /** * @internal This class is not covered by the backward compatibility promise for PHPUnit */ final class RemoveListeners implements Migration { public function migrate(DOMDocument $document): void { $node = $document->getElementsByTagName('listeners')->item(0); if (!$node instanceof DOMElement || $node->parentNode === null) { return; } $node->parentNode->removeChild($node); } } Configuration/Xml/Migration/Migrations/RemoveTestDoxGroupsElement.php 0000644 00000001425 15111303730 0022147 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\TextUI\XmlConfiguration; use DOMDocument; use DOMElement; /** * @internal This class is not covered by the backward compatibility promise for PHPUnit */ final class RemoveTestDoxGroupsElement implements Migration { public function migrate(DOMDocument $document): void { $node = $document->getElementsByTagName('testdoxGroups')->item(0); if (!$node instanceof DOMElement || $node->parentNode === null) { return; } $node->parentNode->removeChild($node); } } Configuration/Xml/Migration/Migrations/MoveCoverageDirectoriesToSource.php 0000644 00000002544 15111303730 0023133 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\TextUI\XmlConfiguration; use function assert; use DOMDocument; use DOMElement; use DOMXPath; /** * @internal This class is not covered by the backward compatibility promise for PHPUnit */ final class MoveCoverageDirectoriesToSource implements Migration { /** * @throws MigrationException */ public function migrate(DOMDocument $document): void { $source = $document->getElementsByTagName('source')->item(0); if ($source !== null) { return; } $coverage = $document->getElementsByTagName('coverage')->item(0); if ($coverage === null) { return; } $root = $document->documentElement; assert($root instanceof DOMElement); $source = $document->createElement('source'); $root->appendChild($source); $xpath = new DOMXPath($document); foreach (['include', 'exclude'] as $element) { foreach (SnapshotNodeList::fromNodeList($xpath->query('//coverage/' . $element)) as $node) { $source->appendChild($node); } } } } Configuration/Xml/Migration/Migrations/RenameBackupStaticAttributesAttribute.php 0000644 00000002005 15111303730 0024320 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\TextUI\XmlConfiguration; use function assert; use DOMDocument; use DOMElement; /** * @internal This class is not covered by the backward compatibility promise for PHPUnit */ final class RenameBackupStaticAttributesAttribute implements Migration { public function migrate(DOMDocument $document): void { $root = $document->documentElement; assert($root instanceof DOMElement); if ($root->hasAttribute('backupStaticProperties')) { return; } if (!$root->hasAttribute('backupStaticAttributes')) { return; } $root->setAttribute('backupStaticProperties', $root->getAttribute('backupStaticAttributes')); $root->removeAttribute('backupStaticAttributes'); } } Configuration/Xml/Migration/Migrations/RemoveCoverageElementCacheDirectoryAttribute.php 0000644 00000001550 15111303730 0025604 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\TextUI\XmlConfiguration; use DOMDocument; use DOMElement; /** * @internal This class is not covered by the backward compatibility promise for PHPUnit */ final class RemoveCoverageElementCacheDirectoryAttribute implements Migration { public function migrate(DOMDocument $document): void { $node = $document->getElementsByTagName('coverage')->item(0); if (!$node instanceof DOMElement || $node->parentNode === null) { return; } if ($node->hasAttribute('cacheDirectory')) { $node->removeAttribute('cacheDirectory'); } } } Configuration/Xml/Migration/Migrations/RemovePrinterAttributes.php 0000644 00000001577 15111303730 0021545 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\TextUI\XmlConfiguration; use function assert; use DOMDocument; use DOMElement; /** * @internal This class is not covered by the backward compatibility promise for PHPUnit */ final class RemovePrinterAttributes implements Migration { public function migrate(DOMDocument $document): void { $root = $document->documentElement; assert($root instanceof DOMElement); if ($root->hasAttribute('printerClass')) { $root->removeAttribute('printerClass'); } if ($root->hasAttribute('printerFile')) { $root->removeAttribute('printerFile'); } } } Configuration/Xml/Migration/Migrations/RemoveVerboseAttribute.php 0000644 00000001404 15111303730 0021331 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\TextUI\XmlConfiguration; use function assert; use DOMDocument; use DOMElement; /** * @internal This class is not covered by the backward compatibility promise for PHPUnit */ final class RemoveVerboseAttribute implements Migration { public function migrate(DOMDocument $document): void { $root = $document->documentElement; assert($root instanceof DOMElement); if ($root->hasAttribute('verbose')) { $root->removeAttribute('verbose'); } } } Configuration/Xml/Migration/Migrations/RemoveCacheResultFileAttribute.php 0000644 00000001434 15111303730 0022731 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\TextUI\XmlConfiguration; use function assert; use DOMDocument; use DOMElement; /** * @internal This class is not covered by the backward compatibility promise for PHPUnit */ final class RemoveCacheResultFileAttribute implements Migration { public function migrate(DOMDocument $document): void { $root = $document->documentElement; assert($root instanceof DOMElement); if ($root->hasAttribute('cacheResultFile')) { $root->removeAttribute('cacheResultFile'); } } } Configuration/Xml/Migration/Migrations/CoverageHtmlToReport.php 0000644 00000001610 15111303730 0020740 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\TextUI\XmlConfiguration; use DOMElement; /** * @internal This class is not covered by the backward compatibility promise for PHPUnit */ final class CoverageHtmlToReport extends LogToReportMigration { protected function forType(): string { return 'coverage-html'; } protected function toReportFormat(DOMElement $logNode): DOMElement { $html = $logNode->ownerDocument->createElement('html'); $html->setAttribute('outputDirectory', $logNode->getAttribute('target')); $this->migrateAttributes($logNode, $html, ['lowUpperBound', 'highLowerBound']); return $html; } } Configuration/Xml/Migration/Migrations/IntroduceCoverageElement.php 0000644 00000001342 15111303730 0021605 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\TextUI\XmlConfiguration; use DOMDocument; /** * @internal This class is not covered by the backward compatibility promise for PHPUnit */ final class IntroduceCoverageElement implements Migration { public function migrate(DOMDocument $document): void { $coverage = $document->createElement('coverage'); $document->documentElement->insertBefore( $coverage, $document->documentElement->firstChild, ); } } Configuration/Xml/Migration/Migrations/ConvertLogTypes.php 0000644 00000002764 15111303730 0020003 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\TextUI\XmlConfiguration; use DOMDocument; use DOMElement; /** * @internal This class is not covered by the backward compatibility promise for PHPUnit */ final class ConvertLogTypes implements Migration { public function migrate(DOMDocument $document): void { $logging = $document->getElementsByTagName('logging')->item(0); if (!$logging instanceof DOMElement) { return; } $types = [ 'junit' => 'junit', 'teamcity' => 'teamcity', 'testdox-html' => 'testdoxHtml', 'testdox-text' => 'testdoxText', 'testdox-xml' => 'testdoxXml', 'plain' => 'text', ]; $logNodes = []; foreach ($logging->getElementsByTagName('log') as $logNode) { if (!isset($types[$logNode->getAttribute('type')])) { continue; } $logNodes[] = $logNode; } foreach ($logNodes as $oldNode) { $newLogNode = $document->createElement($types[$oldNode->getAttribute('type')]); $newLogNode->setAttribute('outputFile', $oldNode->getAttribute('target')); $logging->replaceChild($newLogNode, $oldNode); } } } Configuration/Xml/Migration/Migrations/CoverageCrap4jToReport.php 0000644 00000001573 15111303730 0021167 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\TextUI\XmlConfiguration; use DOMElement; /** * @internal This class is not covered by the backward compatibility promise for PHPUnit */ final class CoverageCrap4jToReport extends LogToReportMigration { protected function forType(): string { return 'coverage-crap4j'; } protected function toReportFormat(DOMElement $logNode): DOMElement { $crap4j = $logNode->ownerDocument->createElement('crap4j'); $crap4j->setAttribute('outputFile', $logNode->getAttribute('target')); $this->migrateAttributes($logNode, $crap4j, ['threshold']); return $crap4j; } } Configuration/Xml/Migration/Migrations/RenameBeStrictAboutCoversAnnotationAttribute.php 0000644 00000002057 15111303730 0025632 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\TextUI\XmlConfiguration; use function assert; use DOMDocument; use DOMElement; /** * @internal This class is not covered by the backward compatibility promise for PHPUnit */ final class RenameBeStrictAboutCoversAnnotationAttribute implements Migration { public function migrate(DOMDocument $document): void { $root = $document->documentElement; assert($root instanceof DOMElement); if ($root->hasAttribute('beStrictAboutCoverageMetadata')) { return; } if (!$root->hasAttribute('beStrictAboutCoversAnnotation')) { return; } $root->setAttribute('beStrictAboutCoverageMetadata', $root->getAttribute('beStrictAboutCoversAnnotation')); $root->removeAttribute('beStrictAboutCoversAnnotation'); } } Configuration/Xml/Migration/Migrations/RemoveLogTypes.php 0000644 00000002050 15111303730 0017604 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\TextUI\XmlConfiguration; use function assert; use DOMDocument; use DOMElement; /** * @internal This class is not covered by the backward compatibility promise for PHPUnit */ final class RemoveLogTypes implements Migration { public function migrate(DOMDocument $document): void { $logging = $document->getElementsByTagName('logging')->item(0); if (!$logging instanceof DOMElement) { return; } foreach (SnapshotNodeList::fromNodeList($logging->getElementsByTagName('log')) as $logNode) { assert($logNode instanceof DOMElement); switch ($logNode->getAttribute('type')) { case 'json': case 'tap': $logging->removeChild($logNode); } } } } Configuration/Xml/Migration/Migrations/RemoveBeStrictAboutResourceUsageDuringSmallTestsAttribute.php0000644 00000001555 15111303730 0030327 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\TextUI\XmlConfiguration; use function assert; use DOMDocument; use DOMElement; /** * @internal This class is not covered by the backward compatibility promise for PHPUnit */ final class RemoveBeStrictAboutResourceUsageDuringSmallTestsAttribute implements Migration { public function migrate(DOMDocument $document): void { $root = $document->documentElement; assert($root instanceof DOMElement); if ($root->hasAttribute('beStrictAboutResourceUsageDuringSmallTests')) { $root->removeAttribute('beStrictAboutResourceUsageDuringSmallTests'); } } } Configuration/Xml/Migration/Migrations/UpdateSchemaLocation.php 0000644 00000001626 15111303730 0020724 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\TextUI\XmlConfiguration; use function assert; use DOMDocument; use DOMElement; use PHPUnit\Runner\Version; /** * @internal This class is not covered by the backward compatibility promise for PHPUnit */ final class UpdateSchemaLocation implements Migration { public function migrate(DOMDocument $document): void { $root = $document->documentElement; assert($root instanceof DOMElement); $root->setAttributeNS( 'http://www.w3.org/2001/XMLSchema-instance', 'xsi:noNamespaceSchemaLocation', 'https://schema.phpunit.de/' . Version::series() . '/phpunit.xsd', ); } } Configuration/Xml/Migration/Migrations/RemoveTestSuiteLoaderAttributes.php 0000644 00000001647 15111303730 0023200 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\TextUI\XmlConfiguration; use function assert; use DOMDocument; use DOMElement; /** * @internal This class is not covered by the backward compatibility promise for PHPUnit */ final class RemoveTestSuiteLoaderAttributes implements Migration { public function migrate(DOMDocument $document): void { $root = $document->documentElement; assert($root instanceof DOMElement); if ($root->hasAttribute('testSuiteLoaderClass')) { $root->removeAttribute('testSuiteLoaderClass'); } if ($root->hasAttribute('testSuiteLoaderFile')) { $root->removeAttribute('testSuiteLoaderFile'); } } } Configuration/Xml/Migration/Migrations/MoveAttributesFromFilterWhitelistToCoverage.php 0000644 00000002625 15111303730 0025513 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\TextUI\XmlConfiguration; use DOMDocument; use DOMElement; /** * @internal This class is not covered by the backward compatibility promise for PHPUnit */ final class MoveAttributesFromFilterWhitelistToCoverage implements Migration { /** * @throws MigrationException */ public function migrate(DOMDocument $document): void { $whitelist = $document->getElementsByTagName('whitelist')->item(0); if (!$whitelist) { return; } $coverage = $document->getElementsByTagName('coverage')->item(0); if (!$coverage instanceof DOMElement) { throw new MigrationException('Unexpected state - No coverage element'); } $map = [ 'addUncoveredFilesFromWhitelist' => 'includeUncoveredFiles', 'processUncoveredFilesFromWhitelist' => 'processUncoveredFiles', ]; foreach ($map as $old => $new) { if (!$whitelist->hasAttribute($old)) { continue; } $coverage->setAttribute($new, $whitelist->getAttribute($old)); $whitelist->removeAttribute($old); } } } Configuration/Xml/Migration/Migrations/CoverageXmlToReport.php 0000644 00000001451 15111303730 0020577 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\TextUI\XmlConfiguration; use DOMElement; /** * @internal This class is not covered by the backward compatibility promise for PHPUnit */ final class CoverageXmlToReport extends LogToReportMigration { protected function forType(): string { return 'coverage-xml'; } protected function toReportFormat(DOMElement $logNode): DOMElement { $xml = $logNode->ownerDocument->createElement('xml'); $xml->setAttribute('outputDirectory', $logNode->getAttribute('target')); return $xml; } } Configuration/Xml/Migration/Migrations/CoverageCloverToReport.php 0000644 00000001467 15111303730 0021300 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\TextUI\XmlConfiguration; use DOMElement; /** * @internal This class is not covered by the backward compatibility promise for PHPUnit */ final class CoverageCloverToReport extends LogToReportMigration { protected function forType(): string { return 'coverage-clover'; } protected function toReportFormat(DOMElement $logNode): DOMElement { $clover = $logNode->ownerDocument->createElement('clover'); $clover->setAttribute('outputFile', $logNode->getAttribute('target')); return $clover; } } Configuration/Xml/Migration/Migrator.php 0000644 00000002650 15111303730 0014336 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\TextUI\XmlConfiguration; use function sprintf; 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 Migrator { /** * @throws Exception * @throws MigrationBuilderException * @throws MigrationException * @throws XmlException */ public function migrate(string $filename): string { $origin = (new SchemaDetector)->detect($filename); if (!$origin->detected()) { throw new Exception( sprintf( '"%s" is not a valid PHPUnit XML configuration file that can be migrated', $filename, ), ); } $configurationDocument = (new XmlLoader)->loadFile($filename); foreach ((new MigrationBuilder)->build($origin->version()) as $migration) { $migration->migrate($configurationDocument); } $configurationDocument->formatOutput = true; $configurationDocument->preserveWhiteSpace = false; return $configurationDocument->saveXML(); } } Configuration/Xml/Migration/MigrationBuilderException.php 0000644 00000001002 15111303730 0017657 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\TextUI\XmlConfiguration; use RuntimeException; /** * @internal This class is not covered by the backward compatibility promise for PHPUnit */ final class MigrationBuilderException extends RuntimeException implements \PHPUnit\Exception { } Configuration/Xml/Validator/ValidationResult.php 0000644 00000003261 15111303730 0016036 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\TextUI\XmlConfiguration; use function sprintf; use function trim; /** * @internal This class is not covered by the backward compatibility promise for PHPUnit * * @psalm-immutable */ final class ValidationResult { /** * @psalm-var array<int,list<string>> */ private readonly array $validationErrors; /** * @psalm-param array<int,\LibXMLError> $errors */ public static function fromArray(array $errors): self { $validationErrors = []; foreach ($errors as $error) { if (!isset($validationErrors[$error->line])) { $validationErrors[$error->line] = []; } $validationErrors[$error->line][] = trim($error->message); } return new self($validationErrors); } private function __construct(array $validationErrors) { $this->validationErrors = $validationErrors; } public function hasValidationErrors(): bool { return !empty($this->validationErrors); } public function asString(): string { $buffer = ''; foreach ($this->validationErrors as $line => $validationErrorsOnLine) { $buffer .= sprintf(PHP_EOL . ' Line %d:' . PHP_EOL, $line); foreach ($validationErrorsOnLine as $validationError) { $buffer .= sprintf(' - %s' . PHP_EOL, $validationError); } } return $buffer; } } Configuration/Xml/Validator/Validator.php 0000644 00000001757 15111303730 0014502 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\TextUI\XmlConfiguration; use function file_get_contents; use function libxml_clear_errors; use function libxml_get_errors; use function libxml_use_internal_errors; use DOMDocument; /** * @internal This class is not covered by the backward compatibility promise for PHPUnit */ final class Validator { public function validate(DOMDocument $document, string $xsdFilename): ValidationResult { $originalErrorHandling = libxml_use_internal_errors(true); $document->schemaValidateSource(file_get_contents($xsdFilename)); $errors = libxml_get_errors(); libxml_clear_errors(); libxml_use_internal_errors($originalErrorHandling); return ValidationResult::fromArray($errors); } } Configuration/Xml/TestSuiteMapper.php 0000644 00000007736 15111303730 0013731 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\TextUI\XmlConfiguration; use const PHP_VERSION; use function array_merge; use function array_unique; use function explode; use function in_array; use function is_dir; use function is_file; use function str_contains; use function version_compare; use PHPUnit\Framework\Exception as FrameworkException; use PHPUnit\Framework\TestSuite as TestSuiteObject; use PHPUnit\TextUI\Configuration\TestSuiteCollection; use PHPUnit\TextUI\RuntimeException; use PHPUnit\TextUI\TestDirectoryNotFoundException; use PHPUnit\TextUI\TestFileNotFoundException; use SebastianBergmann\FileIterator\Facade; /** * @internal This class is not covered by the backward compatibility promise for PHPUnit */ final class TestSuiteMapper { /** * @psalm-param non-empty-string $xmlConfigurationFile, * * @throws RuntimeException * @throws TestDirectoryNotFoundException * @throws TestFileNotFoundException */ public function map(string $xmlConfigurationFile, TestSuiteCollection $configuration, string $filter, string $excludedTestSuites): TestSuiteObject { try { $filterAsArray = $filter ? explode(',', $filter) : []; $excludedFilterAsArray = $excludedTestSuites ? explode(',', $excludedTestSuites) : []; $result = TestSuiteObject::empty($xmlConfigurationFile); foreach ($configuration as $testSuiteConfiguration) { if (!empty($filterAsArray) && !in_array($testSuiteConfiguration->name(), $filterAsArray, true)) { continue; } if (!empty($excludedFilterAsArray) && in_array($testSuiteConfiguration->name(), $excludedFilterAsArray, true)) { continue; } $exclude = []; foreach ($testSuiteConfiguration->exclude()->asArray() as $file) { $exclude[] = $file->path(); } $files = []; foreach ($testSuiteConfiguration->directories() as $directory) { if (!str_contains($directory->path(), '*') && !is_dir($directory->path())) { throw new TestDirectoryNotFoundException($directory->path()); } if (!version_compare(PHP_VERSION, $directory->phpVersion(), $directory->phpVersionOperator()->asString())) { continue; } $files = array_merge( $files, (new Facade)->getFilesAsArray( $directory->path(), $directory->suffix(), $directory->prefix(), $exclude, ), ); } foreach ($testSuiteConfiguration->files() as $file) { if (!is_file($file->path())) { throw new TestFileNotFoundException($file->path()); } if (!version_compare(PHP_VERSION, $file->phpVersion(), $file->phpVersionOperator()->asString())) { continue; } $files[] = $file->path(); } if (!empty($files)) { $testSuite = TestSuiteObject::empty($testSuiteConfiguration->name()); $testSuite->addTestFiles(array_unique($files)); $result->addTest($testSuite); } } return $result; } catch (FrameworkException $e) { throw new RuntimeException( $e->getMessage(), $e->getCode(), $e, ); } } } Configuration/Xml/Exception.php 0000644 00000000762 15111303730 0012561 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\TextUI\XmlConfiguration; use RuntimeException; /** * @internal This class is not covered by the backward compatibility promise for PHPUnit */ final class Exception extends RuntimeException implements \PHPUnit\Exception { } Configuration/Xml/Generator.php 0000644 00000004003 15111303730 0012541 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\TextUI\XmlConfiguration; use function str_replace; /** * @internal This class is not covered by the backward compatibility promise for PHPUnit */ final class Generator { /** * @var string */ private const TEMPLATE = <<<'EOT' <?xml version="1.0" encoding="UTF-8"?> <phpunit xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="https://schema.phpunit.de/{phpunit_version}/phpunit.xsd" bootstrap="{bootstrap_script}" cacheDirectory="{cache_directory}" executionOrder="depends,defects" requireCoverageMetadata="true" beStrictAboutCoverageMetadata="true" beStrictAboutOutputDuringTests="true" failOnRisky="true" failOnWarning="true"> <testsuites> <testsuite name="default"> <directory>{tests_directory}</directory> </testsuite> </testsuites> <source restrictDeprecations="true" restrictNotices="true" restrictWarnings="true"> <include> <directory>{src_directory}</directory> </include> </source> </phpunit> EOT; public function generateDefaultConfiguration(string $phpunitVersion, string $bootstrapScript, string $testsDirectory, string $srcDirectory, string $cacheDirectory): string { return str_replace( [ '{phpunit_version}', '{bootstrap_script}', '{tests_directory}', '{src_directory}', '{cache_directory}', ], [ $phpunitVersion, $bootstrapScript, $testsDirectory, $srcDirectory, $cacheDirectory, ], self::TEMPLATE, ); } } Configuration/Xml/DefaultConfiguration.php 0000644 00000011217 15111303730 0014734 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\TextUI\XmlConfiguration; use PHPUnit\Runner\TestSuiteSorter; use PHPUnit\TextUI\Configuration\ConstantCollection; use PHPUnit\TextUI\Configuration\DirectoryCollection; use PHPUnit\TextUI\Configuration\ExtensionBootstrapCollection; use PHPUnit\TextUI\Configuration\FileCollection; use PHPUnit\TextUI\Configuration\FilterDirectoryCollection as CodeCoverageFilterDirectoryCollection; use PHPUnit\TextUI\Configuration\GroupCollection; use PHPUnit\TextUI\Configuration\IniSettingCollection; use PHPUnit\TextUI\Configuration\Php; use PHPUnit\TextUI\Configuration\Source; use PHPUnit\TextUI\Configuration\TestSuiteCollection; use PHPUnit\TextUI\Configuration\VariableCollection; use PHPUnit\TextUI\XmlConfiguration\CodeCoverage\CodeCoverage; use PHPUnit\TextUI\XmlConfiguration\Logging\Logging; /** * @internal This class is not covered by the backward compatibility promise for PHPUnit * * @psalm-immutable */ final class DefaultConfiguration extends Configuration { public static function create(): self { return new self( ExtensionBootstrapCollection::fromArray([]), new Source( null, false, CodeCoverageFilterDirectoryCollection::fromArray([]), FileCollection::fromArray([]), CodeCoverageFilterDirectoryCollection::fromArray([]), FileCollection::fromArray([]), false, false, false, false, false, false, false, false, false, false, ), new CodeCoverage( null, CodeCoverageFilterDirectoryCollection::fromArray([]), FileCollection::fromArray([]), CodeCoverageFilterDirectoryCollection::fromArray([]), FileCollection::fromArray([]), false, true, false, false, null, null, null, null, null, null, null, ), new Groups( GroupCollection::fromArray([]), GroupCollection::fromArray([]), ), new Logging( null, null, null, null, ), new Php( DirectoryCollection::fromArray([]), IniSettingCollection::fromArray([]), ConstantCollection::fromArray([]), VariableCollection::fromArray([]), VariableCollection::fromArray([]), VariableCollection::fromArray([]), VariableCollection::fromArray([]), VariableCollection::fromArray([]), VariableCollection::fromArray([]), VariableCollection::fromArray([]), VariableCollection::fromArray([]), ), new PHPUnit( null, true, null, 80, \PHPUnit\TextUI\Configuration\Configuration::COLOR_DEFAULT, false, false, false, false, false, false, false, false, false, null, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, null, false, false, true, false, false, 1, 1, 10, 60, null, TestSuiteSorter::ORDER_DEFAULT, true, false, false, false, false, false, false, 100, ), TestSuiteCollection::fromArray([]), ); } public function isDefault(): bool { return true; } } Configuration/Xml/Configuration.php 0000644 00000005155 15111303730 0013433 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\TextUI\XmlConfiguration; use PHPUnit\TextUI\Configuration\ExtensionBootstrapCollection; use PHPUnit\TextUI\Configuration\Php; use PHPUnit\TextUI\Configuration\Source; use PHPUnit\TextUI\Configuration\TestSuiteCollection; use PHPUnit\TextUI\XmlConfiguration\CodeCoverage\CodeCoverage; use PHPUnit\TextUI\XmlConfiguration\Logging\Logging; /** * @internal This class is not covered by the backward compatibility promise for PHPUnit * * @psalm-immutable */ abstract class Configuration { private readonly ExtensionBootstrapCollection $extensions; private readonly Source $source; private readonly CodeCoverage $codeCoverage; private readonly Groups $groups; private readonly Logging $logging; private readonly Php $php; private readonly PHPUnit $phpunit; private readonly TestSuiteCollection $testSuite; public function __construct(ExtensionBootstrapCollection $extensions, Source $source, CodeCoverage $codeCoverage, Groups $groups, Logging $logging, Php $php, PHPUnit $phpunit, TestSuiteCollection $testSuite) { $this->extensions = $extensions; $this->source = $source; $this->codeCoverage = $codeCoverage; $this->groups = $groups; $this->logging = $logging; $this->php = $php; $this->phpunit = $phpunit; $this->testSuite = $testSuite; } public function extensions(): ExtensionBootstrapCollection { return $this->extensions; } public function source(): Source { return $this->source; } public function codeCoverage(): CodeCoverage { return $this->codeCoverage; } public function groups(): Groups { return $this->groups; } public function logging(): Logging { return $this->logging; } public function php(): Php { return $this->php; } public function phpunit(): PHPUnit { return $this->phpunit; } public function testSuite(): TestSuiteCollection { return $this->testSuite; } /** * @psalm-assert-if-true DefaultConfiguration $this */ public function isDefault(): bool { return false; } /** * @psalm-assert-if-true LoadedFromFileConfiguration $this */ public function wasLoadedFromFile(): bool { return false; } } Configuration/Xml/LoadedFromFileConfiguration.php 0000644 00000003542 15111303730 0016166 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\TextUI\XmlConfiguration; use PHPUnit\TextUI\Configuration\ExtensionBootstrapCollection; use PHPUnit\TextUI\Configuration\Php; use PHPUnit\TextUI\Configuration\Source; use PHPUnit\TextUI\Configuration\TestSuiteCollection; use PHPUnit\TextUI\XmlConfiguration\CodeCoverage\CodeCoverage; use PHPUnit\TextUI\XmlConfiguration\Logging\Logging; /** * @internal This class is not covered by the backward compatibility promise for PHPUnit * * @psalm-immutable */ final class LoadedFromFileConfiguration extends Configuration { private readonly string $filename; private readonly ValidationResult $validationResult; public function __construct(string $filename, ValidationResult $validationResult, ExtensionBootstrapCollection $extensions, Source $source, CodeCoverage $codeCoverage, Groups $groups, Logging $logging, Php $php, PHPUnit $phpunit, TestSuiteCollection $testSuite) { $this->filename = $filename; $this->validationResult = $validationResult; parent::__construct( $extensions, $source, $codeCoverage, $groups, $logging, $php, $phpunit, $testSuite, ); } public function filename(): string { return $this->filename; } public function hasValidationErrors(): bool { return $this->validationResult->hasValidationErrors(); } public function validationErrors(): string { return $this->validationResult->asString(); } public function wasLoadedFromFile(): bool { return true; } } Configuration/Xml/SchemaFinder.php 0000644 00000002433 15111303730 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\TextUI\XmlConfiguration; use function defined; use function is_file; use function sprintf; use PHPUnit\Runner\Version; /** * @internal This class is not covered by the backward compatibility promise for PHPUnit */ final class SchemaFinder { /** * @throws CannotFindSchemaException */ public function find(string $version): string { if ($version === Version::series()) { $filename = $this->path() . 'phpunit.xsd'; } else { $filename = $this->path() . 'schema/' . $version . '.xsd'; } if (!is_file($filename)) { throw new CannotFindSchemaException( sprintf( 'Schema for PHPUnit %s is not available', $version, ), ); } return $filename; } private function path(): string { if (defined('__PHPUNIT_PHAR_ROOT__')) { return __PHPUNIT_PHAR_ROOT__ . '/'; } return __DIR__ . '/../../../../'; } } Configuration/Xml/CodeCoverage/CodeCoverage.php 0000644 00000017161 15111303730 0015500 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\TextUI\XmlConfiguration\CodeCoverage; use function count; use PHPUnit\TextUI\Configuration\Directory; use PHPUnit\TextUI\Configuration\FileCollection; use PHPUnit\TextUI\Configuration\FilterDirectoryCollection; use PHPUnit\TextUI\XmlConfiguration\CodeCoverage\Report\Clover; use PHPUnit\TextUI\XmlConfiguration\CodeCoverage\Report\Cobertura; use PHPUnit\TextUI\XmlConfiguration\CodeCoverage\Report\Crap4j; use PHPUnit\TextUI\XmlConfiguration\CodeCoverage\Report\Html; use PHPUnit\TextUI\XmlConfiguration\CodeCoverage\Report\Php; use PHPUnit\TextUI\XmlConfiguration\CodeCoverage\Report\Text; use PHPUnit\TextUI\XmlConfiguration\CodeCoverage\Report\Xml; use PHPUnit\TextUI\XmlConfiguration\Exception; /** * @internal This class is not covered by the backward compatibility promise for PHPUnit * * @psalm-immutable */ final class CodeCoverage { private readonly ?Directory $cacheDirectory; private readonly FilterDirectoryCollection $directories; private readonly FileCollection $files; private readonly FilterDirectoryCollection $excludeDirectories; private readonly FileCollection $excludeFiles; private readonly bool $pathCoverage; private readonly bool $includeUncoveredFiles; private readonly bool $ignoreDeprecatedCodeUnits; private readonly bool $disableCodeCoverageIgnore; private readonly ?Clover $clover; private readonly ?Cobertura $cobertura; private readonly ?Crap4j $crap4j; private readonly ?Html $html; private readonly ?Php $php; private readonly ?Text $text; private readonly ?Xml $xml; public function __construct(?Directory $cacheDirectory, FilterDirectoryCollection $directories, FileCollection $files, FilterDirectoryCollection $excludeDirectories, FileCollection $excludeFiles, bool $pathCoverage, bool $includeUncoveredFiles, bool $ignoreDeprecatedCodeUnits, bool $disableCodeCoverageIgnore, ?Clover $clover, ?Cobertura $cobertura, ?Crap4j $crap4j, ?Html $html, ?Php $php, ?Text $text, ?Xml $xml) { $this->cacheDirectory = $cacheDirectory; $this->directories = $directories; $this->files = $files; $this->excludeDirectories = $excludeDirectories; $this->excludeFiles = $excludeFiles; $this->pathCoverage = $pathCoverage; $this->includeUncoveredFiles = $includeUncoveredFiles; $this->ignoreDeprecatedCodeUnits = $ignoreDeprecatedCodeUnits; $this->disableCodeCoverageIgnore = $disableCodeCoverageIgnore; $this->clover = $clover; $this->cobertura = $cobertura; $this->crap4j = $crap4j; $this->html = $html; $this->php = $php; $this->text = $text; $this->xml = $xml; } /** * @psalm-assert-if-true !null $this->cacheDirectory * * @deprecated */ public function hasCacheDirectory(): bool { return $this->cacheDirectory !== null; } /** * @throws Exception * * @deprecated */ public function cacheDirectory(): Directory { if (!$this->hasCacheDirectory()) { throw new Exception( 'No cache directory has been configured', ); } return $this->cacheDirectory; } public function hasNonEmptyListOfFilesToBeIncludedInCodeCoverageReport(): bool { return count($this->directories) > 0 || count($this->files) > 0; } public function directories(): FilterDirectoryCollection { return $this->directories; } public function files(): FileCollection { return $this->files; } public function excludeDirectories(): FilterDirectoryCollection { return $this->excludeDirectories; } public function excludeFiles(): FileCollection { return $this->excludeFiles; } public function pathCoverage(): bool { return $this->pathCoverage; } public function includeUncoveredFiles(): bool { return $this->includeUncoveredFiles; } public function ignoreDeprecatedCodeUnits(): bool { return $this->ignoreDeprecatedCodeUnits; } public function disableCodeCoverageIgnore(): bool { return $this->disableCodeCoverageIgnore; } /** * @psalm-assert-if-true !null $this->clover */ public function hasClover(): bool { return $this->clover !== null; } /** * @throws Exception */ public function clover(): Clover { if (!$this->hasClover()) { throw new Exception( 'Code Coverage report "Clover XML" has not been configured', ); } return $this->clover; } /** * @psalm-assert-if-true !null $this->cobertura */ public function hasCobertura(): bool { return $this->cobertura !== null; } /** * @throws Exception */ public function cobertura(): Cobertura { if (!$this->hasCobertura()) { throw new Exception( 'Code Coverage report "Cobertura XML" has not been configured', ); } return $this->cobertura; } /** * @psalm-assert-if-true !null $this->crap4j */ public function hasCrap4j(): bool { return $this->crap4j !== null; } /** * @throws Exception */ public function crap4j(): Crap4j { if (!$this->hasCrap4j()) { throw new Exception( 'Code Coverage report "Crap4J" has not been configured', ); } return $this->crap4j; } /** * @psalm-assert-if-true !null $this->html */ public function hasHtml(): bool { return $this->html !== null; } /** * @throws Exception */ public function html(): Html { if (!$this->hasHtml()) { throw new Exception( 'Code Coverage report "HTML" has not been configured', ); } return $this->html; } /** * @psalm-assert-if-true !null $this->php */ public function hasPhp(): bool { return $this->php !== null; } /** * @throws Exception */ public function php(): Php { if (!$this->hasPhp()) { throw new Exception( 'Code Coverage report "PHP" has not been configured', ); } return $this->php; } /** * @psalm-assert-if-true !null $this->text */ public function hasText(): bool { return $this->text !== null; } /** * @throws Exception */ public function text(): Text { if (!$this->hasText()) { throw new Exception( 'Code Coverage report "Text" has not been configured', ); } return $this->text; } /** * @psalm-assert-if-true !null $this->xml */ public function hasXml(): bool { return $this->xml !== null; } /** * @throws Exception */ public function xml(): Xml { if (!$this->hasXml()) { throw new Exception( 'Code Coverage report "XML" has not been configured', ); } return $this->xml; } } Configuration/Xml/CodeCoverage/Report/Clover.php 0000644 00000001301 15111303730 0015644 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\TextUI\XmlConfiguration\CodeCoverage\Report; use PHPUnit\TextUI\Configuration\File; /** * @internal This class is not covered by the backward compatibility promise for PHPUnit * * @psalm-immutable */ final class Clover { private readonly File $target; public function __construct(File $target) { $this->target = $target; } public function target(): File { return $this->target; } } Configuration/Xml/CodeCoverage/Report/Html.php 0000644 00000005447 15111303730 0015335 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\TextUI\XmlConfiguration\CodeCoverage\Report; use PHPUnit\TextUI\Configuration\Directory; use PHPUnit\TextUI\Configuration\NoCustomCssFileException; /** * @internal This class is not covered by the backward compatibility promise for PHPUnit * * @psalm-immutable */ final class Html { private readonly Directory $target; private readonly int $lowUpperBound; private readonly int $highLowerBound; private readonly string $colorSuccessLow; private readonly string $colorSuccessMedium; private readonly string $colorSuccessHigh; private readonly string $colorWarning; private readonly string $colorDanger; private readonly ?string $customCssFile; public function __construct(Directory $target, int $lowUpperBound, int $highLowerBound, string $colorSuccessLow, string $colorSuccessMedium, string $colorSuccessHigh, string $colorWarning, string $colorDanger, ?string $customCssFile) { $this->target = $target; $this->lowUpperBound = $lowUpperBound; $this->highLowerBound = $highLowerBound; $this->colorSuccessLow = $colorSuccessLow; $this->colorSuccessMedium = $colorSuccessMedium; $this->colorSuccessHigh = $colorSuccessHigh; $this->colorWarning = $colorWarning; $this->colorDanger = $colorDanger; $this->customCssFile = $customCssFile; } public function target(): Directory { return $this->target; } public function lowUpperBound(): int { return $this->lowUpperBound; } public function highLowerBound(): int { return $this->highLowerBound; } public function colorSuccessLow(): string { return $this->colorSuccessLow; } public function colorSuccessMedium(): string { return $this->colorSuccessMedium; } public function colorSuccessHigh(): string { return $this->colorSuccessHigh; } public function colorWarning(): string { return $this->colorWarning; } public function colorDanger(): string { return $this->colorDanger; } /** * @psalm-assert-if-true !null $this->customCssFile */ public function hasCustomCssFile(): bool { return $this->customCssFile !== null; } /** * @throws NoCustomCssFileException */ public function customCssFile(): string { if (!$this->hasCustomCssFile()) { throw new NoCustomCssFileException; } return $this->customCssFile; } } Configuration/Xml/CodeCoverage/Report/Crap4j.php 0000644 00000001563 15111303730 0015547 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\TextUI\XmlConfiguration\CodeCoverage\Report; use PHPUnit\TextUI\Configuration\File; /** * @internal This class is not covered by the backward compatibility promise for PHPUnit * * @psalm-immutable */ final class Crap4j { private readonly File $target; private readonly int $threshold; public function __construct(File $target, int $threshold) { $this->target = $target; $this->threshold = $threshold; } public function target(): File { return $this->target; } public function threshold(): int { return $this->threshold; } } Configuration/Xml/CodeCoverage/Report/Text.php 0000644 00000002214 15111303730 0015342 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\TextUI\XmlConfiguration\CodeCoverage\Report; use PHPUnit\TextUI\Configuration\File; /** * @internal This class is not covered by the backward compatibility promise for PHPUnit * * @psalm-immutable */ final class Text { private readonly File $target; private readonly bool $showUncoveredFiles; private readonly bool $showOnlySummary; public function __construct(File $target, bool $showUncoveredFiles, bool $showOnlySummary) { $this->target = $target; $this->showUncoveredFiles = $showUncoveredFiles; $this->showOnlySummary = $showOnlySummary; } public function target(): File { return $this->target; } public function showUncoveredFiles(): bool { return $this->showUncoveredFiles; } public function showOnlySummary(): bool { return $this->showOnlySummary; } } Configuration/Xml/CodeCoverage/Report/Php.php 0000644 00000001276 15111303730 0015154 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\TextUI\XmlConfiguration\CodeCoverage\Report; use PHPUnit\TextUI\Configuration\File; /** * @internal This class is not covered by the backward compatibility promise for PHPUnit * * @psalm-immutable */ final class Php { private readonly File $target; public function __construct(File $target) { $this->target = $target; } public function target(): File { return $this->target; } } Configuration/Xml/CodeCoverage/Report/Cobertura.php 0000644 00000001304 15111303730 0016343 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\TextUI\XmlConfiguration\CodeCoverage\Report; use PHPUnit\TextUI\Configuration\File; /** * @internal This class is not covered by the backward compatibility promise for PHPUnit * * @psalm-immutable */ final class Cobertura { private readonly File $target; public function __construct(File $target) { $this->target = $target; } public function target(): File { return $this->target; } } Configuration/Xml/CodeCoverage/Report/Xml.php 0000644 00000001322 15111303730 0015155 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\TextUI\XmlConfiguration\CodeCoverage\Report; use PHPUnit\TextUI\Configuration\Directory; /** * @internal This class is not covered by the backward compatibility promise for PHPUnit * * @psalm-immutable */ final class Xml { private readonly Directory $target; public function __construct(Directory $target) { $this->target = $target; } public function target(): Directory { return $this->target; } } Configuration/Xml/PHPUnit.php 0000644 00000040173 15111303730 0012112 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\TextUI\XmlConfiguration; /** * @internal This class is not covered by the backward compatibility promise for PHPUnit * * @psalm-immutable */ final class PHPUnit { private readonly ?string $cacheDirectory; private readonly bool $cacheResult; private readonly ?string $cacheResultFile; private readonly int|string $columns; private readonly string $colors; private readonly bool $stderr; private readonly bool $displayDetailsOnIncompleteTests; private readonly bool $displayDetailsOnSkippedTests; private readonly bool $displayDetailsOnTestsThatTriggerDeprecations; private readonly bool $displayDetailsOnTestsThatTriggerErrors; private readonly bool $displayDetailsOnTestsThatTriggerNotices; private readonly bool $displayDetailsOnTestsThatTriggerWarnings; private readonly bool $reverseDefectList; private readonly bool $requireCoverageMetadata; private readonly ?string $bootstrap; private readonly bool $processIsolation; private readonly bool $failOnDeprecation; private readonly bool $failOnEmptyTestSuite; private readonly bool $failOnIncomplete; private readonly bool $failOnNotice; private readonly bool $failOnRisky; private readonly bool $failOnSkipped; private readonly bool $failOnWarning; private readonly bool $stopOnDefect; private readonly bool $stopOnDeprecation; private readonly bool $stopOnError; private readonly bool $stopOnFailure; private readonly bool $stopOnIncomplete; private readonly bool $stopOnNotice; private readonly bool $stopOnRisky; private readonly bool $stopOnSkipped; private readonly bool $stopOnWarning; /** * @psalm-var ?non-empty-string */ private readonly ?string $extensionsDirectory; private readonly bool $beStrictAboutChangesToGlobalState; private readonly bool $beStrictAboutOutputDuringTests; private readonly bool $beStrictAboutTestsThatDoNotTestAnything; private readonly bool $beStrictAboutCoverageMetadata; private readonly bool $enforceTimeLimit; private readonly int $defaultTimeLimit; private readonly int $timeoutForSmallTests; private readonly int $timeoutForMediumTests; private readonly int $timeoutForLargeTests; private readonly ?string $defaultTestSuite; private readonly int $executionOrder; private readonly bool $resolveDependencies; private readonly bool $defectsFirst; private readonly bool $backupGlobals; private readonly bool $backupStaticProperties; private readonly bool $registerMockObjectsFromTestArgumentsRecursively; private readonly bool $testdoxPrinter; private readonly bool $controlGarbageCollector; private readonly int $numberOfTestsBeforeGarbageCollection; /** * @psalm-param ?non-empty-string $extensionsDirectory */ public function __construct(?string $cacheDirectory, bool $cacheResult, ?string $cacheResultFile, int|string $columns, string $colors, bool $stderr, bool $displayDetailsOnIncompleteTests, bool $displayDetailsOnSkippedTests, bool $displayDetailsOnTestsThatTriggerDeprecations, bool $displayDetailsOnTestsThatTriggerErrors, bool $displayDetailsOnTestsThatTriggerNotices, bool $displayDetailsOnTestsThatTriggerWarnings, bool $reverseDefectList, bool $requireCoverageMetadata, ?string $bootstrap, bool $processIsolation, bool $failOnDeprecation, bool $failOnEmptyTestSuite, bool $failOnIncomplete, bool $failOnNotice, bool $failOnRisky, bool $failOnSkipped, bool $failOnWarning, bool $stopOnDefect, bool $stopOnDeprecation, bool $stopOnError, bool $stopOnFailure, bool $stopOnIncomplete, bool $stopOnNotice, bool $stopOnRisky, bool $stopOnSkipped, bool $stopOnWarning, ?string $extensionsDirectory, bool $beStrictAboutChangesToGlobalState, bool $beStrictAboutOutputDuringTests, bool $beStrictAboutTestsThatDoNotTestAnything, bool $beStrictAboutCoverageMetadata, bool $enforceTimeLimit, int $defaultTimeLimit, int $timeoutForSmallTests, int $timeoutForMediumTests, int $timeoutForLargeTests, ?string $defaultTestSuite, int $executionOrder, bool $resolveDependencies, bool $defectsFirst, bool $backupGlobals, bool $backupStaticProperties, bool $registerMockObjectsFromTestArgumentsRecursively, bool $testdoxPrinter, bool $controlGarbageCollector, int $numberOfTestsBeforeGarbageCollection) { $this->cacheDirectory = $cacheDirectory; $this->cacheResult = $cacheResult; $this->cacheResultFile = $cacheResultFile; $this->columns = $columns; $this->colors = $colors; $this->stderr = $stderr; $this->displayDetailsOnIncompleteTests = $displayDetailsOnIncompleteTests; $this->displayDetailsOnSkippedTests = $displayDetailsOnSkippedTests; $this->displayDetailsOnTestsThatTriggerDeprecations = $displayDetailsOnTestsThatTriggerDeprecations; $this->displayDetailsOnTestsThatTriggerErrors = $displayDetailsOnTestsThatTriggerErrors; $this->displayDetailsOnTestsThatTriggerNotices = $displayDetailsOnTestsThatTriggerNotices; $this->displayDetailsOnTestsThatTriggerWarnings = $displayDetailsOnTestsThatTriggerWarnings; $this->reverseDefectList = $reverseDefectList; $this->requireCoverageMetadata = $requireCoverageMetadata; $this->bootstrap = $bootstrap; $this->processIsolation = $processIsolation; $this->failOnDeprecation = $failOnDeprecation; $this->failOnEmptyTestSuite = $failOnEmptyTestSuite; $this->failOnIncomplete = $failOnIncomplete; $this->failOnNotice = $failOnNotice; $this->failOnRisky = $failOnRisky; $this->failOnSkipped = $failOnSkipped; $this->failOnWarning = $failOnWarning; $this->stopOnDefect = $stopOnDefect; $this->stopOnDeprecation = $stopOnDeprecation; $this->stopOnError = $stopOnError; $this->stopOnFailure = $stopOnFailure; $this->stopOnIncomplete = $stopOnIncomplete; $this->stopOnNotice = $stopOnNotice; $this->stopOnRisky = $stopOnRisky; $this->stopOnSkipped = $stopOnSkipped; $this->stopOnWarning = $stopOnWarning; $this->extensionsDirectory = $extensionsDirectory; $this->beStrictAboutChangesToGlobalState = $beStrictAboutChangesToGlobalState; $this->beStrictAboutOutputDuringTests = $beStrictAboutOutputDuringTests; $this->beStrictAboutTestsThatDoNotTestAnything = $beStrictAboutTestsThatDoNotTestAnything; $this->beStrictAboutCoverageMetadata = $beStrictAboutCoverageMetadata; $this->enforceTimeLimit = $enforceTimeLimit; $this->defaultTimeLimit = $defaultTimeLimit; $this->timeoutForSmallTests = $timeoutForSmallTests; $this->timeoutForMediumTests = $timeoutForMediumTests; $this->timeoutForLargeTests = $timeoutForLargeTests; $this->defaultTestSuite = $defaultTestSuite; $this->executionOrder = $executionOrder; $this->resolveDependencies = $resolveDependencies; $this->defectsFirst = $defectsFirst; $this->backupGlobals = $backupGlobals; $this->backupStaticProperties = $backupStaticProperties; $this->registerMockObjectsFromTestArgumentsRecursively = $registerMockObjectsFromTestArgumentsRecursively; $this->testdoxPrinter = $testdoxPrinter; $this->controlGarbageCollector = $controlGarbageCollector; $this->numberOfTestsBeforeGarbageCollection = $numberOfTestsBeforeGarbageCollection; } /** * @psalm-assert-if-true !null $this->cacheDirectory */ public function hasCacheDirectory(): bool { return $this->cacheDirectory !== null; } /** * @throws Exception */ public function cacheDirectory(): string { if (!$this->hasCacheDirectory()) { throw new Exception('Cache directory is not configured'); } return $this->cacheDirectory; } public function cacheResult(): bool { return $this->cacheResult; } /** * @psalm-assert-if-true !null $this->cacheResultFile * * @deprecated */ public function hasCacheResultFile(): bool { return $this->cacheResultFile !== null; } /** * @throws Exception * * @deprecated */ public function cacheResultFile(): string { if (!$this->hasCacheResultFile()) { throw new Exception('Cache result file is not configured'); } return $this->cacheResultFile; } public function columns(): int|string { return $this->columns; } public function colors(): string { return $this->colors; } public function stderr(): bool { return $this->stderr; } public function displayDetailsOnIncompleteTests(): bool { return $this->displayDetailsOnIncompleteTests; } public function displayDetailsOnSkippedTests(): bool { return $this->displayDetailsOnSkippedTests; } public function displayDetailsOnTestsThatTriggerDeprecations(): bool { return $this->displayDetailsOnTestsThatTriggerDeprecations; } public function displayDetailsOnTestsThatTriggerErrors(): bool { return $this->displayDetailsOnTestsThatTriggerErrors; } public function displayDetailsOnTestsThatTriggerNotices(): bool { return $this->displayDetailsOnTestsThatTriggerNotices; } public function displayDetailsOnTestsThatTriggerWarnings(): bool { return $this->displayDetailsOnTestsThatTriggerWarnings; } public function reverseDefectList(): bool { return $this->reverseDefectList; } public function requireCoverageMetadata(): bool { return $this->requireCoverageMetadata; } /** * @psalm-assert-if-true !null $this->bootstrap */ public function hasBootstrap(): bool { return $this->bootstrap !== null; } /** * @throws Exception */ public function bootstrap(): string { if (!$this->hasBootstrap()) { throw new Exception('Bootstrap script is not configured'); } return $this->bootstrap; } public function processIsolation(): bool { return $this->processIsolation; } public function failOnDeprecation(): bool { return $this->failOnDeprecation; } public function failOnEmptyTestSuite(): bool { return $this->failOnEmptyTestSuite; } public function failOnIncomplete(): bool { return $this->failOnIncomplete; } public function failOnNotice(): bool { return $this->failOnNotice; } public function failOnRisky(): bool { return $this->failOnRisky; } public function failOnSkipped(): bool { return $this->failOnSkipped; } public function failOnWarning(): bool { return $this->failOnWarning; } public function stopOnDefect(): bool { return $this->stopOnDefect; } public function stopOnDeprecation(): bool { return $this->stopOnDeprecation; } public function stopOnError(): bool { return $this->stopOnError; } public function stopOnFailure(): bool { return $this->stopOnFailure; } public function stopOnIncomplete(): bool { return $this->stopOnIncomplete; } public function stopOnNotice(): bool { return $this->stopOnNotice; } public function stopOnRisky(): bool { return $this->stopOnRisky; } public function stopOnSkipped(): bool { return $this->stopOnSkipped; } public function stopOnWarning(): bool { return $this->stopOnWarning; } /** * @psalm-assert-if-true !null $this->extensionsDirectory */ public function hasExtensionsDirectory(): bool { return $this->extensionsDirectory !== null; } /** * @psalm-return non-empty-string * * @throws Exception */ public function extensionsDirectory(): string { if (!$this->hasExtensionsDirectory()) { throw new Exception('Extensions directory is not configured'); } return $this->extensionsDirectory; } public function beStrictAboutChangesToGlobalState(): bool { return $this->beStrictAboutChangesToGlobalState; } public function beStrictAboutOutputDuringTests(): bool { return $this->beStrictAboutOutputDuringTests; } public function beStrictAboutTestsThatDoNotTestAnything(): bool { return $this->beStrictAboutTestsThatDoNotTestAnything; } public function beStrictAboutCoverageMetadata(): bool { return $this->beStrictAboutCoverageMetadata; } public function enforceTimeLimit(): bool { return $this->enforceTimeLimit; } public function defaultTimeLimit(): int { return $this->defaultTimeLimit; } public function timeoutForSmallTests(): int { return $this->timeoutForSmallTests; } public function timeoutForMediumTests(): int { return $this->timeoutForMediumTests; } public function timeoutForLargeTests(): int { return $this->timeoutForLargeTests; } /** * @psalm-assert-if-true !null $this->defaultTestSuite */ public function hasDefaultTestSuite(): bool { return $this->defaultTestSuite !== null; } /** * @throws Exception */ public function defaultTestSuite(): string { if (!$this->hasDefaultTestSuite()) { throw new Exception('Default test suite is not configured'); } return $this->defaultTestSuite; } public function executionOrder(): int { return $this->executionOrder; } public function resolveDependencies(): bool { return $this->resolveDependencies; } public function defectsFirst(): bool { return $this->defectsFirst; } public function backupGlobals(): bool { return $this->backupGlobals; } public function backupStaticProperties(): bool { return $this->backupStaticProperties; } public function registerMockObjectsFromTestArgumentsRecursively(): bool { return $this->registerMockObjectsFromTestArgumentsRecursively; } public function testdoxPrinter(): bool { return $this->testdoxPrinter; } public function controlGarbageCollector(): bool { return $this->controlGarbageCollector; } public function numberOfTestsBeforeGarbageCollection(): int { return $this->numberOfTestsBeforeGarbageCollection; } } Configuration/Xml/Loader.php 0000644 00000111613 15111303730 0012027 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\TextUI\XmlConfiguration; use const DIRECTORY_SEPARATOR; use const PHP_VERSION; use function assert; use function defined; use function dirname; use function explode; use function is_numeric; use function preg_match; use function realpath; use function str_contains; use function str_starts_with; use function strlen; use function strtolower; use function substr; use function trim; use DOMDocument; use DOMElement; use DOMXPath; use PHPUnit\Runner\TestSuiteSorter; use PHPUnit\Runner\Version; use PHPUnit\TextUI\Configuration\Constant; use PHPUnit\TextUI\Configuration\ConstantCollection; use PHPUnit\TextUI\Configuration\Directory; use PHPUnit\TextUI\Configuration\DirectoryCollection; use PHPUnit\TextUI\Configuration\ExtensionBootstrap; use PHPUnit\TextUI\Configuration\ExtensionBootstrapCollection; use PHPUnit\TextUI\Configuration\File; use PHPUnit\TextUI\Configuration\FileCollection; use PHPUnit\TextUI\Configuration\FilterDirectory; use PHPUnit\TextUI\Configuration\FilterDirectoryCollection; use PHPUnit\TextUI\Configuration\Group; use PHPUnit\TextUI\Configuration\GroupCollection; use PHPUnit\TextUI\Configuration\IniSetting; use PHPUnit\TextUI\Configuration\IniSettingCollection; use PHPUnit\TextUI\Configuration\Php; use PHPUnit\TextUI\Configuration\Source; use PHPUnit\TextUI\Configuration\TestDirectory; use PHPUnit\TextUI\Configuration\TestDirectoryCollection; use PHPUnit\TextUI\Configuration\TestFile; use PHPUnit\TextUI\Configuration\TestFileCollection; use PHPUnit\TextUI\Configuration\TestSuite as TestSuiteConfiguration; use PHPUnit\TextUI\Configuration\TestSuiteCollection; use PHPUnit\TextUI\Configuration\Variable; use PHPUnit\TextUI\Configuration\VariableCollection; use PHPUnit\TextUI\XmlConfiguration\CodeCoverage\CodeCoverage; use PHPUnit\TextUI\XmlConfiguration\CodeCoverage\Report\Clover; use PHPUnit\TextUI\XmlConfiguration\CodeCoverage\Report\Cobertura; use PHPUnit\TextUI\XmlConfiguration\CodeCoverage\Report\Crap4j; use PHPUnit\TextUI\XmlConfiguration\CodeCoverage\Report\Html as CodeCoverageHtml; use PHPUnit\TextUI\XmlConfiguration\CodeCoverage\Report\Php as CodeCoveragePhp; use PHPUnit\TextUI\XmlConfiguration\CodeCoverage\Report\Text as CodeCoverageText; use PHPUnit\TextUI\XmlConfiguration\CodeCoverage\Report\Xml as CodeCoverageXml; use PHPUnit\TextUI\XmlConfiguration\Logging\Junit; use PHPUnit\TextUI\XmlConfiguration\Logging\Logging; use PHPUnit\TextUI\XmlConfiguration\Logging\TeamCity; use PHPUnit\TextUI\XmlConfiguration\Logging\TestDox\Html as TestDoxHtml; use PHPUnit\TextUI\XmlConfiguration\Logging\TestDox\Text as TestDoxText; use PHPUnit\Util\VersionComparisonOperator; use PHPUnit\Util\Xml\Loader as XmlLoader; use PHPUnit\Util\Xml\XmlException; use SebastianBergmann\CodeCoverage\Report\Html\Colors; use SebastianBergmann\CodeCoverage\Report\Thresholds; /** * @internal This class is not covered by the backward compatibility promise for PHPUnit */ final class Loader { /** * @throws Exception */ public function load(string $filename): LoadedFromFileConfiguration { try { $document = (new XmlLoader)->loadFile($filename); } catch (XmlException $e) { throw new Exception( $e->getMessage(), $e->getCode(), $e, ); } $xpath = new DOMXPath($document); try { $xsdFilename = (new SchemaFinder)->find(Version::series()); } catch (CannotFindSchemaException $e) { throw new Exception( $e->getMessage(), $e->getCode(), $e, ); } $configurationFileRealpath = realpath($filename); return new LoadedFromFileConfiguration( $configurationFileRealpath, (new Validator)->validate($document, $xsdFilename), $this->extensions($xpath), $this->source($configurationFileRealpath, $xpath), $this->codeCoverage($configurationFileRealpath, $xpath), $this->groups($xpath), $this->logging($configurationFileRealpath, $xpath), $this->php($configurationFileRealpath, $xpath), $this->phpunit($configurationFileRealpath, $document), $this->testSuite($configurationFileRealpath, $xpath), ); } private function logging(string $filename, DOMXPath $xpath): Logging { $junit = null; $element = $this->element($xpath, 'logging/junit'); if ($element) { $junit = new Junit( new File( $this->toAbsolutePath( $filename, (string) $this->getStringAttribute($element, 'outputFile'), ), ), ); } $teamCity = null; $element = $this->element($xpath, 'logging/teamcity'); if ($element) { $teamCity = new TeamCity( new File( $this->toAbsolutePath( $filename, (string) $this->getStringAttribute($element, 'outputFile'), ), ), ); } $testDoxHtml = null; $element = $this->element($xpath, 'logging/testdoxHtml'); if ($element) { $testDoxHtml = new TestDoxHtml( new File( $this->toAbsolutePath( $filename, (string) $this->getStringAttribute($element, 'outputFile'), ), ), ); } $testDoxText = null; $element = $this->element($xpath, 'logging/testdoxText'); if ($element) { $testDoxText = new TestDoxText( new File( $this->toAbsolutePath( $filename, (string) $this->getStringAttribute($element, 'outputFile'), ), ), ); } return new Logging( $junit, $teamCity, $testDoxHtml, $testDoxText, ); } private function extensions(DOMXPath $xpath): ExtensionBootstrapCollection { $extensionBootstrappers = []; foreach ($xpath->query('extensions/bootstrap') as $bootstrap) { assert($bootstrap instanceof DOMElement); $parameters = []; foreach ($xpath->query('parameter', $bootstrap) as $parameter) { assert($parameter instanceof DOMElement); $parameters[$parameter->getAttribute('name')] = $parameter->getAttribute('value'); } $extensionBootstrappers[] = new ExtensionBootstrap( $bootstrap->getAttribute('class'), $parameters, ); } return ExtensionBootstrapCollection::fromArray($extensionBootstrappers); } /** * @psalm-return non-empty-string */ private function toAbsolutePath(string $filename, string $path): string { $path = trim($path); if (str_starts_with($path, '/')) { return $path; } // Matches the following on Windows: // - \\NetworkComputer\Path // - \\.\D: // - \\.\c: // - C:\Windows // - C:\windows // - C:/windows // - c:/windows if (defined('PHP_WINDOWS_VERSION_BUILD') && !empty($path) && ($path[0] === '\\' || (strlen($path) >= 3 && preg_match('#^[A-Z]:[/\\\]#i', substr($path, 0, 3))))) { return $path; } if (str_contains($path, '://')) { return $path; } return dirname($filename) . DIRECTORY_SEPARATOR . $path; } private function source(string $filename, DOMXPath $xpath): Source { $baseline = null; $restrictDeprecations = false; $restrictNotices = false; $restrictWarnings = false; $ignoreSuppressionOfDeprecations = false; $ignoreSuppressionOfPhpDeprecations = false; $ignoreSuppressionOfErrors = false; $ignoreSuppressionOfNotices = false; $ignoreSuppressionOfPhpNotices = false; $ignoreSuppressionOfWarnings = false; $ignoreSuppressionOfPhpWarnings = false; $element = $this->element($xpath, 'source'); if ($element) { $baseline = $this->getStringAttribute($element, 'baseline'); if ($baseline !== null) { $baseline = $this->toAbsolutePath($filename, $baseline); } $restrictDeprecations = $this->getBooleanAttribute($element, 'restrictDeprecations', false); $restrictNotices = $this->getBooleanAttribute($element, 'restrictNotices', false); $restrictWarnings = $this->getBooleanAttribute($element, 'restrictWarnings', false); $ignoreSuppressionOfDeprecations = $this->getBooleanAttribute($element, 'ignoreSuppressionOfDeprecations', false); $ignoreSuppressionOfPhpDeprecations = $this->getBooleanAttribute($element, 'ignoreSuppressionOfPhpDeprecations', false); $ignoreSuppressionOfErrors = $this->getBooleanAttribute($element, 'ignoreSuppressionOfErrors', false); $ignoreSuppressionOfNotices = $this->getBooleanAttribute($element, 'ignoreSuppressionOfNotices', false); $ignoreSuppressionOfPhpNotices = $this->getBooleanAttribute($element, 'ignoreSuppressionOfPhpNotices', false); $ignoreSuppressionOfWarnings = $this->getBooleanAttribute($element, 'ignoreSuppressionOfWarnings', false); $ignoreSuppressionOfPhpWarnings = $this->getBooleanAttribute($element, 'ignoreSuppressionOfPhpWarnings', false); } return new Source( $baseline, false, $this->readFilterDirectories($filename, $xpath, 'source/include/directory'), $this->readFilterFiles($filename, $xpath, 'source/include/file'), $this->readFilterDirectories($filename, $xpath, 'source/exclude/directory'), $this->readFilterFiles($filename, $xpath, 'source/exclude/file'), $restrictDeprecations, $restrictNotices, $restrictWarnings, $ignoreSuppressionOfDeprecations, $ignoreSuppressionOfPhpDeprecations, $ignoreSuppressionOfErrors, $ignoreSuppressionOfNotices, $ignoreSuppressionOfPhpNotices, $ignoreSuppressionOfWarnings, $ignoreSuppressionOfPhpWarnings, ); } private function codeCoverage(string $filename, DOMXPath $xpath): CodeCoverage { $cacheDirectory = null; $pathCoverage = false; $includeUncoveredFiles = true; $ignoreDeprecatedCodeUnits = false; $disableCodeCoverageIgnore = false; $element = $this->element($xpath, 'coverage'); if ($element) { $cacheDirectory = $this->getStringAttribute($element, 'cacheDirectory'); if ($cacheDirectory !== null) { $cacheDirectory = new Directory( $this->toAbsolutePath($filename, $cacheDirectory), ); } $pathCoverage = $this->getBooleanAttribute( $element, 'pathCoverage', false, ); $includeUncoveredFiles = $this->getBooleanAttribute( $element, 'includeUncoveredFiles', true, ); $ignoreDeprecatedCodeUnits = $this->getBooleanAttribute( $element, 'ignoreDeprecatedCodeUnits', false, ); $disableCodeCoverageIgnore = $this->getBooleanAttribute( $element, 'disableCodeCoverageIgnore', false, ); } $clover = null; $element = $this->element($xpath, 'coverage/report/clover'); if ($element) { $clover = new Clover( new File( $this->toAbsolutePath( $filename, (string) $this->getStringAttribute($element, 'outputFile'), ), ), ); } $cobertura = null; $element = $this->element($xpath, 'coverage/report/cobertura'); if ($element) { $cobertura = new Cobertura( new File( $this->toAbsolutePath( $filename, (string) $this->getStringAttribute($element, 'outputFile'), ), ), ); } $crap4j = null; $element = $this->element($xpath, 'coverage/report/crap4j'); if ($element) { $crap4j = new Crap4j( new File( $this->toAbsolutePath( $filename, (string) $this->getStringAttribute($element, 'outputFile'), ), ), $this->getIntegerAttribute($element, 'threshold', 30), ); } $html = null; $element = $this->element($xpath, 'coverage/report/html'); if ($element) { $defaultColors = Colors::default(); $defaultThresholds = Thresholds::default(); $html = new CodeCoverageHtml( new Directory( $this->toAbsolutePath( $filename, (string) $this->getStringAttribute($element, 'outputDirectory'), ), ), $this->getIntegerAttribute($element, 'lowUpperBound', $defaultThresholds->lowUpperBound()), $this->getIntegerAttribute($element, 'highLowerBound', $defaultThresholds->highLowerBound()), $this->getStringAttributeWithDefault($element, 'colorSuccessLow', $defaultColors->successLow()), $this->getStringAttributeWithDefault($element, 'colorSuccessMedium', $defaultColors->successMedium()), $this->getStringAttributeWithDefault($element, 'colorSuccessHigh', $defaultColors->successHigh()), $this->getStringAttributeWithDefault($element, 'colorWarning', $defaultColors->warning()), $this->getStringAttributeWithDefault($element, 'colorDanger', $defaultColors->danger()), $this->getStringAttribute($element, 'customCssFile'), ); } $php = null; $element = $this->element($xpath, 'coverage/report/php'); if ($element) { $php = new CodeCoveragePhp( new File( $this->toAbsolutePath( $filename, (string) $this->getStringAttribute($element, 'outputFile'), ), ), ); } $text = null; $element = $this->element($xpath, 'coverage/report/text'); if ($element) { $text = new CodeCoverageText( new File( $this->toAbsolutePath( $filename, (string) $this->getStringAttribute($element, 'outputFile'), ), ), $this->getBooleanAttribute($element, 'showUncoveredFiles', false), $this->getBooleanAttribute($element, 'showOnlySummary', false), ); } $xml = null; $element = $this->element($xpath, 'coverage/report/xml'); if ($element) { $xml = new CodeCoverageXml( new Directory( $this->toAbsolutePath( $filename, (string) $this->getStringAttribute($element, 'outputDirectory'), ), ), ); } return new CodeCoverage( $cacheDirectory, $this->readFilterDirectories($filename, $xpath, 'coverage/include/directory'), $this->readFilterFiles($filename, $xpath, 'coverage/include/file'), $this->readFilterDirectories($filename, $xpath, 'coverage/exclude/directory'), $this->readFilterFiles($filename, $xpath, 'coverage/exclude/file'), $pathCoverage, $includeUncoveredFiles, $ignoreDeprecatedCodeUnits, $disableCodeCoverageIgnore, $clover, $cobertura, $crap4j, $html, $php, $text, $xml, ); } private function getBoolean(string $value, bool|string $default): bool|string { if (strtolower($value) === 'false') { return false; } if (strtolower($value) === 'true') { return true; } return $default; } private function readFilterDirectories(string $filename, DOMXPath $xpath, string $query): FilterDirectoryCollection { $directories = []; foreach ($xpath->query($query) as $directoryNode) { assert($directoryNode instanceof DOMElement); $directoryPath = $directoryNode->textContent; if (!$directoryPath) { continue; } $directories[] = new FilterDirectory( $this->toAbsolutePath($filename, $directoryPath), $directoryNode->hasAttribute('prefix') ? $directoryNode->getAttribute('prefix') : '', $directoryNode->hasAttribute('suffix') ? $directoryNode->getAttribute('suffix') : '.php', ); } return FilterDirectoryCollection::fromArray($directories); } private function readFilterFiles(string $filename, DOMXPath $xpath, string $query): FileCollection { $files = []; foreach ($xpath->query($query) as $file) { $filePath = $file->textContent; if ($filePath) { $files[] = new File($this->toAbsolutePath($filename, $filePath)); } } return FileCollection::fromArray($files); } private function groups(DOMXPath $xpath): Groups { $include = []; $exclude = []; foreach ($xpath->query('groups/include/group') as $group) { $include[] = new Group($group->textContent); } foreach ($xpath->query('groups/exclude/group') as $group) { $exclude[] = new Group($group->textContent); } return new Groups( GroupCollection::fromArray($include), GroupCollection::fromArray($exclude), ); } private function getBooleanAttribute(DOMElement $element, string $attribute, bool $default): bool { if (!$element->hasAttribute($attribute)) { return $default; } return (bool) $this->getBoolean( $element->getAttribute($attribute), false, ); } private function getIntegerAttribute(DOMElement $element, string $attribute, int $default): int { if (!$element->hasAttribute($attribute)) { return $default; } return $this->getInteger( $element->getAttribute($attribute), $default, ); } private function getStringAttribute(DOMElement $element, string $attribute): ?string { if (!$element->hasAttribute($attribute)) { return null; } return $element->getAttribute($attribute); } private function getStringAttributeWithDefault(DOMElement $element, string $attribute, string $default): string { if (!$element->hasAttribute($attribute)) { return $default; } return $element->getAttribute($attribute); } private function getInteger(string $value, int $default): int { if (is_numeric($value)) { return (int) $value; } return $default; } private function php(string $filename, DOMXPath $xpath): Php { $includePaths = []; foreach ($xpath->query('php/includePath') as $includePath) { $path = $includePath->textContent; if ($path) { $includePaths[] = new Directory($this->toAbsolutePath($filename, $path)); } } $iniSettings = []; foreach ($xpath->query('php/ini') as $ini) { assert($ini instanceof DOMElement); $iniSettings[] = new IniSetting( $ini->getAttribute('name'), $ini->getAttribute('value'), ); } $constants = []; foreach ($xpath->query('php/const') as $const) { assert($const instanceof DOMElement); $value = $const->getAttribute('value'); $constants[] = new Constant( $const->getAttribute('name'), $this->getBoolean($value, $value), ); } $variables = [ 'var' => [], 'env' => [], 'post' => [], 'get' => [], 'cookie' => [], 'server' => [], 'files' => [], 'request' => [], ]; foreach (['var', 'env', 'post', 'get', 'cookie', 'server', 'files', 'request'] as $array) { foreach ($xpath->query('php/' . $array) as $var) { assert($var instanceof DOMElement); $name = $var->getAttribute('name'); $value = $var->getAttribute('value'); $force = false; $verbatim = false; if ($var->hasAttribute('force')) { $force = (bool) $this->getBoolean($var->getAttribute('force'), false); } if ($var->hasAttribute('verbatim')) { $verbatim = $this->getBoolean($var->getAttribute('verbatim'), false); } if (!$verbatim) { $value = $this->getBoolean($value, $value); } $variables[$array][] = new Variable($name, $value, $force); } } return new Php( DirectoryCollection::fromArray($includePaths), IniSettingCollection::fromArray($iniSettings), ConstantCollection::fromArray($constants), VariableCollection::fromArray($variables['var']), VariableCollection::fromArray($variables['env']), VariableCollection::fromArray($variables['post']), VariableCollection::fromArray($variables['get']), VariableCollection::fromArray($variables['cookie']), VariableCollection::fromArray($variables['server']), VariableCollection::fromArray($variables['files']), VariableCollection::fromArray($variables['request']), ); } private function phpunit(string $filename, DOMDocument $document): PHPUnit { $executionOrder = TestSuiteSorter::ORDER_DEFAULT; $defectsFirst = false; $resolveDependencies = $this->getBooleanAttribute($document->documentElement, 'resolveDependencies', true); if ($document->documentElement->hasAttribute('executionOrder')) { foreach (explode(',', $document->documentElement->getAttribute('executionOrder')) as $order) { switch ($order) { case 'default': $executionOrder = TestSuiteSorter::ORDER_DEFAULT; $defectsFirst = false; $resolveDependencies = true; break; case 'depends': $resolveDependencies = true; break; case 'no-depends': $resolveDependencies = false; break; case 'defects': $defectsFirst = true; break; case 'duration': $executionOrder = TestSuiteSorter::ORDER_DURATION; break; case 'random': $executionOrder = TestSuiteSorter::ORDER_RANDOMIZED; break; case 'reverse': $executionOrder = TestSuiteSorter::ORDER_REVERSED; break; case 'size': $executionOrder = TestSuiteSorter::ORDER_SIZE; break; } } } $cacheDirectory = $this->getStringAttribute($document->documentElement, 'cacheDirectory'); if ($cacheDirectory !== null) { $cacheDirectory = $this->toAbsolutePath($filename, $cacheDirectory); } $cacheResultFile = $this->getStringAttribute($document->documentElement, 'cacheResultFile'); if ($cacheResultFile !== null) { $cacheResultFile = $this->toAbsolutePath($filename, $cacheResultFile); } $bootstrap = $this->getStringAttribute($document->documentElement, 'bootstrap'); if ($bootstrap !== null) { $bootstrap = $this->toAbsolutePath($filename, $bootstrap); } $extensionsDirectory = $this->getStringAttribute($document->documentElement, 'extensionsDirectory'); if ($extensionsDirectory !== null) { $extensionsDirectory = $this->toAbsolutePath($filename, $extensionsDirectory); } $backupStaticProperties = false; if ($document->documentElement->hasAttribute('backupStaticProperties')) { $backupStaticProperties = $this->getBooleanAttribute($document->documentElement, 'backupStaticProperties', false); } elseif ($document->documentElement->hasAttribute('backupStaticAttributes')) { $backupStaticProperties = $this->getBooleanAttribute($document->documentElement, 'backupStaticAttributes', false); } $requireCoverageMetadata = false; if ($document->documentElement->hasAttribute('requireCoverageMetadata')) { $requireCoverageMetadata = $this->getBooleanAttribute($document->documentElement, 'requireCoverageMetadata', false); } elseif ($document->documentElement->hasAttribute('forceCoversAnnotation')) { $requireCoverageMetadata = $this->getBooleanAttribute($document->documentElement, 'forceCoversAnnotation', false); } $beStrictAboutCoverageMetadata = false; if ($document->documentElement->hasAttribute('beStrictAboutCoverageMetadata')) { $beStrictAboutCoverageMetadata = $this->getBooleanAttribute($document->documentElement, 'beStrictAboutCoverageMetadata', false); } elseif ($document->documentElement->hasAttribute('forceCoversAnnotation')) { $beStrictAboutCoverageMetadata = $this->getBooleanAttribute($document->documentElement, 'beStrictAboutCoversAnnotation', false); } return new PHPUnit( $cacheDirectory, $this->getBooleanAttribute($document->documentElement, 'cacheResult', true), $cacheResultFile, $this->getColumns($document), $this->getColors($document), $this->getBooleanAttribute($document->documentElement, 'stderr', false), $this->getBooleanAttribute($document->documentElement, 'displayDetailsOnIncompleteTests', false), $this->getBooleanAttribute($document->documentElement, 'displayDetailsOnSkippedTests', false), $this->getBooleanAttribute($document->documentElement, 'displayDetailsOnTestsThatTriggerDeprecations', false), $this->getBooleanAttribute($document->documentElement, 'displayDetailsOnTestsThatTriggerErrors', false), $this->getBooleanAttribute($document->documentElement, 'displayDetailsOnTestsThatTriggerNotices', false), $this->getBooleanAttribute($document->documentElement, 'displayDetailsOnTestsThatTriggerWarnings', false), $this->getBooleanAttribute($document->documentElement, 'reverseDefectList', false), $requireCoverageMetadata, $bootstrap, $this->getBooleanAttribute($document->documentElement, 'processIsolation', false), $this->getBooleanAttribute($document->documentElement, 'failOnDeprecation', false), $this->getBooleanAttribute($document->documentElement, 'failOnEmptyTestSuite', false), $this->getBooleanAttribute($document->documentElement, 'failOnIncomplete', false), $this->getBooleanAttribute($document->documentElement, 'failOnNotice', false), $this->getBooleanAttribute($document->documentElement, 'failOnRisky', false), $this->getBooleanAttribute($document->documentElement, 'failOnSkipped', false), $this->getBooleanAttribute($document->documentElement, 'failOnWarning', false), $this->getBooleanAttribute($document->documentElement, 'stopOnDefect', false), $this->getBooleanAttribute($document->documentElement, 'stopOnDeprecation', false), $this->getBooleanAttribute($document->documentElement, 'stopOnError', false), $this->getBooleanAttribute($document->documentElement, 'stopOnFailure', false), $this->getBooleanAttribute($document->documentElement, 'stopOnIncomplete', false), $this->getBooleanAttribute($document->documentElement, 'stopOnNotice', false), $this->getBooleanAttribute($document->documentElement, 'stopOnRisky', false), $this->getBooleanAttribute($document->documentElement, 'stopOnSkipped', false), $this->getBooleanAttribute($document->documentElement, 'stopOnWarning', false), $extensionsDirectory, $this->getBooleanAttribute($document->documentElement, 'beStrictAboutChangesToGlobalState', false), $this->getBooleanAttribute($document->documentElement, 'beStrictAboutOutputDuringTests', false), $this->getBooleanAttribute($document->documentElement, 'beStrictAboutTestsThatDoNotTestAnything', true), $beStrictAboutCoverageMetadata, $this->getBooleanAttribute($document->documentElement, 'enforceTimeLimit', false), $this->getIntegerAttribute($document->documentElement, 'defaultTimeLimit', 1), $this->getIntegerAttribute($document->documentElement, 'timeoutForSmallTests', 1), $this->getIntegerAttribute($document->documentElement, 'timeoutForMediumTests', 10), $this->getIntegerAttribute($document->documentElement, 'timeoutForLargeTests', 60), $this->getStringAttribute($document->documentElement, 'defaultTestSuite'), $executionOrder, $resolveDependencies, $defectsFirst, $this->getBooleanAttribute($document->documentElement, 'backupGlobals', false), $backupStaticProperties, $this->getBooleanAttribute($document->documentElement, 'registerMockObjectsFromTestArgumentsRecursively', false), $this->getBooleanAttribute($document->documentElement, 'testdox', false), $this->getBooleanAttribute($document->documentElement, 'controlGarbageCollector', false), $this->getIntegerAttribute($document->documentElement, 'numberOfTestsBeforeGarbageCollection', 100), ); } private function getColors(DOMDocument $document): string { $colors = \PHPUnit\TextUI\Configuration\Configuration::COLOR_DEFAULT; if ($document->documentElement->hasAttribute('colors')) { /* only allow boolean for compatibility with previous versions 'always' only allowed from command line */ if ($this->getBoolean($document->documentElement->getAttribute('colors'), false)) { $colors = \PHPUnit\TextUI\Configuration\Configuration::COLOR_AUTO; } else { $colors = \PHPUnit\TextUI\Configuration\Configuration::COLOR_NEVER; } } return $colors; } private function getColumns(DOMDocument $document): int|string { $columns = 80; if ($document->documentElement->hasAttribute('columns')) { $columns = $document->documentElement->getAttribute('columns'); if ($columns !== 'max') { $columns = $this->getInteger($columns, 80); } } return $columns; } private function testSuite(string $filename, DOMXPath $xpath): TestSuiteCollection { $testSuites = []; foreach ($this->getTestSuiteElements($xpath) as $element) { $exclude = []; foreach ($element->getElementsByTagName('exclude') as $excludeNode) { $excludeFile = $excludeNode->textContent; if ($excludeFile) { $exclude[] = new File($this->toAbsolutePath($filename, $excludeFile)); } } $directories = []; foreach ($element->getElementsByTagName('directory') as $directoryNode) { assert($directoryNode instanceof DOMElement); $directory = $directoryNode->textContent; if (empty($directory)) { continue; } $prefix = ''; if ($directoryNode->hasAttribute('prefix')) { $prefix = $directoryNode->getAttribute('prefix'); } $suffix = 'Test.php'; if ($directoryNode->hasAttribute('suffix')) { $suffix = $directoryNode->getAttribute('suffix'); } $phpVersion = PHP_VERSION; if ($directoryNode->hasAttribute('phpVersion')) { $phpVersion = $directoryNode->getAttribute('phpVersion'); } $phpVersionOperator = new VersionComparisonOperator('>='); if ($directoryNode->hasAttribute('phpVersionOperator')) { $phpVersionOperator = new VersionComparisonOperator($directoryNode->getAttribute('phpVersionOperator')); } $directories[] = new TestDirectory( $this->toAbsolutePath($filename, $directory), $prefix, $suffix, $phpVersion, $phpVersionOperator, ); } $files = []; foreach ($element->getElementsByTagName('file') as $fileNode) { assert($fileNode instanceof DOMElement); $file = $fileNode->textContent; if (empty($file)) { continue; } $phpVersion = PHP_VERSION; if ($fileNode->hasAttribute('phpVersion')) { $phpVersion = $fileNode->getAttribute('phpVersion'); } $phpVersionOperator = new VersionComparisonOperator('>='); if ($fileNode->hasAttribute('phpVersionOperator')) { $phpVersionOperator = new VersionComparisonOperator($fileNode->getAttribute('phpVersionOperator')); } $files[] = new TestFile( $this->toAbsolutePath($filename, $file), $phpVersion, $phpVersionOperator, ); } $name = $element->getAttribute('name'); assert(!empty($name)); $testSuites[] = new TestSuiteConfiguration( $name, TestDirectoryCollection::fromArray($directories), TestFileCollection::fromArray($files), FileCollection::fromArray($exclude), ); } return TestSuiteCollection::fromArray($testSuites); } /** * @psalm-return list<DOMElement> */ private function getTestSuiteElements(DOMXPath $xpath): array { $elements = []; $testSuiteNodes = $xpath->query('testsuites/testsuite'); if ($testSuiteNodes->length === 0) { $testSuiteNodes = $xpath->query('testsuite'); } if ($testSuiteNodes->length === 1) { $element = $testSuiteNodes->item(0); assert($element instanceof DOMElement); $elements[] = $element; } else { foreach ($testSuiteNodes as $testSuiteNode) { assert($testSuiteNode instanceof DOMElement); $elements[] = $testSuiteNode; } } return $elements; } private function element(DOMXPath $xpath, string $element): ?DOMElement { $nodes = $xpath->query($element); if ($nodes->length === 1) { $node = $nodes->item(0); assert($node instanceof DOMElement); return $node; } return null; } } Configuration/Xml/Logging/Junit.php 0000644 00000001264 15111303730 0013300 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\TextUI\XmlConfiguration\Logging; use PHPUnit\TextUI\Configuration\File; /** * @internal This class is not covered by the backward compatibility promise for PHPUnit * * @psalm-immutable */ final class Junit { private readonly File $target; public function __construct(File $target) { $this->target = $target; } public function target(): File { return $this->target; } } Configuration/Xml/Logging/TeamCity.php 0000644 00000001267 15111303730 0013731 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\TextUI\XmlConfiguration\Logging; use PHPUnit\TextUI\Configuration\File; /** * @internal This class is not covered by the backward compatibility promise for PHPUnit * * @psalm-immutable */ final class TeamCity { private readonly File $target; public function __construct(File $target) { $this->target = $target; } public function target(): File { return $this->target; } } Configuration/Xml/Logging/TestDox/Html.php 0000644 00000001273 15111303730 0014505 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\TextUI\XmlConfiguration\Logging\TestDox; use PHPUnit\TextUI\Configuration\File; /** * @internal This class is not covered by the backward compatibility promise for PHPUnit * * @psalm-immutable */ final class Html { private readonly File $target; public function __construct(File $target) { $this->target = $target; } public function target(): File { return $this->target; } } Configuration/Xml/Logging/TestDox/Text.php 0000644 00000001273 15111303730 0014525 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\TextUI\XmlConfiguration\Logging\TestDox; use PHPUnit\TextUI\Configuration\File; /** * @internal This class is not covered by the backward compatibility promise for PHPUnit * * @psalm-immutable */ final class Text { private readonly File $target; public function __construct(File $target) { $this->target = $target; } public function target(): File { return $this->target; } } Configuration/Xml/Logging/Logging.php 0000644 00000004727 15111303730 0013604 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\TextUI\XmlConfiguration\Logging; use PHPUnit\TextUI\XmlConfiguration\Exception; use PHPUnit\TextUI\XmlConfiguration\Logging\TestDox\Html as TestDoxHtml; use PHPUnit\TextUI\XmlConfiguration\Logging\TestDox\Text as TestDoxText; /** * @internal This class is not covered by the backward compatibility promise for PHPUnit * * @psalm-immutable */ final class Logging { private readonly ?Junit $junit; private readonly ?TeamCity $teamCity; private readonly ?TestDoxHtml $testDoxHtml; private readonly ?TestDoxText $testDoxText; public function __construct(?Junit $junit, ?TeamCity $teamCity, ?TestDoxHtml $testDoxHtml, ?TestDoxText $testDoxText) { $this->junit = $junit; $this->teamCity = $teamCity; $this->testDoxHtml = $testDoxHtml; $this->testDoxText = $testDoxText; } public function hasJunit(): bool { return $this->junit !== null; } /** * @throws Exception */ public function junit(): Junit { if ($this->junit === null) { throw new Exception('Logger "JUnit XML" is not configured'); } return $this->junit; } public function hasTeamCity(): bool { return $this->teamCity !== null; } /** * @throws Exception */ public function teamCity(): TeamCity { if ($this->teamCity === null) { throw new Exception('Logger "Team City" is not configured'); } return $this->teamCity; } public function hasTestDoxHtml(): bool { return $this->testDoxHtml !== null; } /** * @throws Exception */ public function testDoxHtml(): TestDoxHtml { if ($this->testDoxHtml === null) { throw new Exception('Logger "TestDox HTML" is not configured'); } return $this->testDoxHtml; } public function hasTestDoxText(): bool { return $this->testDoxText !== null; } /** * @throws Exception */ public function testDoxText(): TestDoxText { if ($this->testDoxText === null) { throw new Exception('Logger "TestDox Text" is not configured'); } return $this->testDoxText; } } Configuration/Xml/SchemaDetector/SchemaDetector.php 0000644 00000002005 15111303730 0016377 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\TextUI\XmlConfiguration; use PHPUnit\Util\Xml\Loader; use PHPUnit\Util\Xml\XmlException; /** * @internal This class is not covered by the backward compatibility promise for PHPUnit */ final class SchemaDetector { /** * @throws XmlException */ public function detect(string $filename): SchemaDetectionResult { $document = (new Loader)->loadFile($filename); foreach (['10.0', '9.5', '9.2', '8.5'] as $candidate) { $schema = (new SchemaFinder)->find($candidate); if (!(new Validator)->validate($document, $schema)->hasValidationErrors()) { return new SuccessfulSchemaDetectionResult($candidate); } } return new FailedSchemaDetectionResult; } } Configuration/Xml/SchemaDetector/SuccessfulSchemaDetectionResult.php 0000644 00000001417 15111303730 0022011 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\TextUI\XmlConfiguration; /** * @internal This class is not covered by the backward compatibility promise for PHPUnit * * @psalm-immutable */ final class SuccessfulSchemaDetectionResult extends SchemaDetectionResult { private readonly string $version; public function __construct(string $version) { $this->version = $version; } public function detected(): bool { return true; } public function version(): string { return $this->version; } } Configuration/Xml/SchemaDetector/FailedSchemaDetectionResult.php 0000644 00000000753 15111303730 0021060 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\TextUI\XmlConfiguration; /** * @internal This class is not covered by the backward compatibility promise for PHPUnit * * @psalm-immutable */ final class FailedSchemaDetectionResult extends SchemaDetectionResult { } Configuration/Xml/SchemaDetector/SchemaDetectionResult.php 0000644 00000001330 15111303730 0017743 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\TextUI\XmlConfiguration; use PHPUnit\Util\Xml\XmlException; /** * @internal This class is not covered by the backward compatibility promise for PHPUnit * * @psalm-immutable */ abstract class SchemaDetectionResult { public function detected(): bool { return false; } /** * @throws XmlException */ public function version(): string { throw new XmlException('No supported schema was detected'); } } Configuration/Xml/Groups.php 0000644 00000002144 15111303730 0012076 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\TextUI\XmlConfiguration; use PHPUnit\TextUI\Configuration\GroupCollection; /** * @internal This class is not covered by the backward compatibility promise for PHPUnit * * @psalm-immutable */ final class Groups { private readonly GroupCollection $include; private readonly GroupCollection $exclude; public function __construct(GroupCollection $include, GroupCollection $exclude) { $this->include = $include; $this->exclude = $exclude; } public function hasInclude(): bool { return !$this->include->isEmpty(); } public function include(): GroupCollection { return $this->include; } public function hasExclude(): bool { return !$this->exclude->isEmpty(); } public function exclude(): GroupCollection { return $this->exclude; } } Configuration/Value/ExtensionBootstrapCollection.php 0000644 00000002537 15111303730 0017027 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\TextUI\Configuration; use IteratorAggregate; /** * @template-implements IteratorAggregate<int, ExtensionBootstrap> * * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit * * @psalm-immutable */ final class ExtensionBootstrapCollection implements IteratorAggregate { /** * @psalm-var list<ExtensionBootstrap> */ private readonly array $extensionBootstraps; /** * @psalm-param list<ExtensionBootstrap> $extensionBootstraps */ public static function fromArray(array $extensionBootstraps): self { return new self(...$extensionBootstraps); } private function __construct(ExtensionBootstrap ...$extensionBootstraps) { $this->extensionBootstraps = $extensionBootstraps; } /** * @psalm-return list<ExtensionBootstrap> */ public function asArray(): array { return $this->extensionBootstraps; } public function getIterator(): ExtensionBootstrapCollectionIterator { return new ExtensionBootstrapCollectionIterator($this); } } Configuration/Value/Variable.php 0000644 00000001706 15111303730 0012663 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\TextUI\Configuration; /** * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit * * @psalm-immutable */ final class Variable { private readonly string $name; private readonly mixed $value; private readonly bool $force; public function __construct(string $name, mixed $value, bool $force) { $this->name = $name; $this->value = $value; $this->force = $force; } public function name(): string { return $this->name; } public function value(): mixed { return $this->value; } public function force(): bool { return $this->force; } } Configuration/Value/TestSuiteCollection.php 0000644 00000002652 15111303730 0015104 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\TextUI\Configuration; use function count; use Countable; use IteratorAggregate; /** * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit * * @psalm-immutable * * @template-implements IteratorAggregate<int, TestSuite> */ final class TestSuiteCollection implements Countable, IteratorAggregate { /** * @psalm-var list<TestSuite> */ private readonly array $testSuites; /** * @psalm-param list<TestSuite> $testSuites */ public static function fromArray(array $testSuites): self { return new self(...$testSuites); } private function __construct(TestSuite ...$testSuites) { $this->testSuites = $testSuites; } /** * @psalm-return list<TestSuite> */ public function asArray(): array { return $this->testSuites; } public function count(): int { return count($this->testSuites); } public function getIterator(): TestSuiteCollectionIterator { return new TestSuiteCollectionIterator($this); } public function isEmpty(): bool { return $this->count() === 0; } } Configuration/Value/FileCollectionIterator.php 0000644 00000002462 15111303730 0015543 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\TextUI\Configuration; use function count; use function iterator_count; use Countable; use Iterator; /** * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit * * @template-implements Iterator<int, File> */ final class FileCollectionIterator implements Countable, Iterator { /** * @psalm-var list<File> */ private readonly array $files; private int $position = 0; public function __construct(FileCollection $files) { $this->files = $files->asArray(); } public function count(): int { return iterator_count($this); } public function rewind(): void { $this->position = 0; } public function valid(): bool { return $this->position < count($this->files); } public function key(): int { return $this->position; } public function current(): File { return $this->files[$this->position]; } public function next(): void { $this->position++; } } Configuration/Value/Source.php 0000644 00000012721 15111303730 0012375 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\TextUI\Configuration; /** * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit * * @psalm-immutable */ final class Source { /** * @psalm-var non-empty-string */ private readonly ?string $baseline; private readonly bool $ignoreBaseline; private readonly FilterDirectoryCollection $includeDirectories; private readonly FileCollection $includeFiles; private readonly FilterDirectoryCollection $excludeDirectories; private readonly FileCollection $excludeFiles; private readonly bool $restrictDeprecations; private readonly bool $restrictNotices; private readonly bool $restrictWarnings; private readonly bool $ignoreSuppressionOfDeprecations; private readonly bool $ignoreSuppressionOfPhpDeprecations; private readonly bool $ignoreSuppressionOfErrors; private readonly bool $ignoreSuppressionOfNotices; private readonly bool $ignoreSuppressionOfPhpNotices; private readonly bool $ignoreSuppressionOfWarnings; private readonly bool $ignoreSuppressionOfPhpWarnings; /** * @psalm-param non-empty-string $baseline */ public function __construct(?string $baseline, bool $ignoreBaseline, FilterDirectoryCollection $includeDirectories, FileCollection $includeFiles, FilterDirectoryCollection $excludeDirectories, FileCollection $excludeFiles, bool $restrictDeprecations, bool $restrictNotices, bool $restrictWarnings, bool $ignoreSuppressionOfDeprecations, bool $ignoreSuppressionOfPhpDeprecations, bool $ignoreSuppressionOfErrors, bool $ignoreSuppressionOfNotices, bool $ignoreSuppressionOfPhpNotices, bool $ignoreSuppressionOfWarnings, bool $ignoreSuppressionOfPhpWarnings) { $this->baseline = $baseline; $this->ignoreBaseline = $ignoreBaseline; $this->includeDirectories = $includeDirectories; $this->includeFiles = $includeFiles; $this->excludeDirectories = $excludeDirectories; $this->excludeFiles = $excludeFiles; $this->restrictDeprecations = $restrictDeprecations; $this->restrictNotices = $restrictNotices; $this->restrictWarnings = $restrictWarnings; $this->ignoreSuppressionOfDeprecations = $ignoreSuppressionOfDeprecations; $this->ignoreSuppressionOfPhpDeprecations = $ignoreSuppressionOfPhpDeprecations; $this->ignoreSuppressionOfErrors = $ignoreSuppressionOfErrors; $this->ignoreSuppressionOfNotices = $ignoreSuppressionOfNotices; $this->ignoreSuppressionOfPhpNotices = $ignoreSuppressionOfPhpNotices; $this->ignoreSuppressionOfWarnings = $ignoreSuppressionOfWarnings; $this->ignoreSuppressionOfPhpWarnings = $ignoreSuppressionOfPhpWarnings; } /** * @psalm-assert-if-true !null $this->baseline */ public function useBaseline(): bool { return $this->hasBaseline() && !$this->ignoreBaseline; } /** * @psalm-assert-if-true !null $this->baseline */ public function hasBaseline(): bool { return $this->baseline !== null; } /** * @psalm-return non-empty-string * * @throws NoBaselineException */ public function baseline(): string { if (!$this->hasBaseline()) { throw new NoBaselineException; } return $this->baseline; } public function includeDirectories(): FilterDirectoryCollection { return $this->includeDirectories; } public function includeFiles(): FileCollection { return $this->includeFiles; } public function excludeDirectories(): FilterDirectoryCollection { return $this->excludeDirectories; } public function excludeFiles(): FileCollection { return $this->excludeFiles; } public function notEmpty(): bool { return $this->includeDirectories->notEmpty() || $this->includeFiles->notEmpty(); } public function restrictDeprecations(): bool { return $this->restrictDeprecations; } public function restrictNotices(): bool { return $this->restrictNotices; } public function restrictWarnings(): bool { return $this->restrictWarnings; } public function ignoreSuppressionOfDeprecations(): bool { return $this->ignoreSuppressionOfDeprecations; } public function ignoreSuppressionOfPhpDeprecations(): bool { return $this->ignoreSuppressionOfPhpDeprecations; } public function ignoreSuppressionOfErrors(): bool { return $this->ignoreSuppressionOfErrors; } public function ignoreSuppressionOfNotices(): bool { return $this->ignoreSuppressionOfNotices; } public function ignoreSuppressionOfPhpNotices(): bool { return $this->ignoreSuppressionOfPhpNotices; } public function ignoreSuppressionOfWarnings(): bool { return $this->ignoreSuppressionOfWarnings; } public function ignoreSuppressionOfPhpWarnings(): bool { return $this->ignoreSuppressionOfPhpWarnings; } } Configuration/Value/TestFile.php 0000644 00000002266 15111303730 0012657 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\TextUI\Configuration; use PHPUnit\Util\VersionComparisonOperator; /** * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit * * @psalm-immutable */ final class TestFile { private readonly string $path; private readonly string $phpVersion; private readonly VersionComparisonOperator $phpVersionOperator; public function __construct(string $path, string $phpVersion, VersionComparisonOperator $phpVersionOperator) { $this->path = $path; $this->phpVersion = $phpVersion; $this->phpVersionOperator = $phpVersionOperator; } public function path(): string { return $this->path; } public function phpVersion(): string { return $this->phpVersion; } public function phpVersionOperator(): VersionComparisonOperator { return $this->phpVersionOperator; } } Configuration/Value/ConstantCollection.php 0000644 00000002503 15111303730 0014737 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\TextUI\Configuration; use function count; use Countable; use IteratorAggregate; /** * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit * * @psalm-immutable * * @template-implements IteratorAggregate<int, Constant> */ final class ConstantCollection implements Countable, IteratorAggregate { /** * @psalm-var list<Constant> */ private readonly array $constants; /** * @psalm-param list<Constant> $constants */ public static function fromArray(array $constants): self { return new self(...$constants); } private function __construct(Constant ...$constants) { $this->constants = $constants; } /** * @psalm-return list<Constant> */ public function asArray(): array { return $this->constants; } public function count(): int { return count($this->constants); } public function getIterator(): ConstantCollectionIterator { return new ConstantCollectionIterator($this); } } Configuration/Value/VariableCollectionIterator.php 0000644 00000002536 15111303730 0016413 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\TextUI\Configuration; use function count; use function iterator_count; use Countable; use Iterator; /** * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit * * @template-implements Iterator<int, Variable> */ final class VariableCollectionIterator implements Countable, Iterator { /** * @psalm-var list<Variable> */ private readonly array $variables; private int $position = 0; public function __construct(VariableCollection $variables) { $this->variables = $variables->asArray(); } public function count(): int { return iterator_count($this); } public function rewind(): void { $this->position = 0; } public function valid(): bool { return $this->position < count($this->variables); } public function key(): int { return $this->position; } public function current(): Variable { return $this->variables[$this->position]; } public function next(): void { $this->position++; } } Configuration/Value/TestSuiteCollectionIterator.php 0000644 00000002551 15111303730 0016614 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\TextUI\Configuration; use function count; use function iterator_count; use Countable; use Iterator; /** * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit * * @template-implements Iterator<int, TestSuite> */ final class TestSuiteCollectionIterator implements Countable, Iterator { /** * @psalm-var list<TestSuite> */ private readonly array $testSuites; private int $position = 0; public function __construct(TestSuiteCollection $testSuites) { $this->testSuites = $testSuites->asArray(); } public function count(): int { return iterator_count($this); } public function rewind(): void { $this->position = 0; } public function valid(): bool { return $this->position < count($this->testSuites); } public function key(): int { return $this->position; } public function current(): TestSuite { return $this->testSuites[$this->position]; } public function next(): void { $this->position++; } } Configuration/Value/TestDirectoryCollection.php 0000644 00000002723 15111303730 0015756 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\TextUI\Configuration; use function count; use Countable; use IteratorAggregate; /** * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit * * @psalm-immutable * * @template-implements IteratorAggregate<int, TestDirectory> */ final class TestDirectoryCollection implements Countable, IteratorAggregate { /** * @psalm-var list<TestDirectory> */ private readonly array $directories; /** * @psalm-param list<TestDirectory> $directories */ public static function fromArray(array $directories): self { return new self(...$directories); } private function __construct(TestDirectory ...$directories) { $this->directories = $directories; } /** * @psalm-return list<TestDirectory> */ public function asArray(): array { return $this->directories; } public function count(): int { return count($this->directories); } public function getIterator(): TestDirectoryCollectionIterator { return new TestDirectoryCollectionIterator($this); } public function isEmpty(): bool { return $this->count() === 0; } } Configuration/Value/Directory.php 0000644 00000001217 15111303730 0013077 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\TextUI\Configuration; /** * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit * * @psalm-immutable */ final class Directory { private readonly string $path; public function __construct(string $path) { $this->path = $path; } public function path(): string { return $this->path; } } Configuration/Value/IniSetting.php 0000644 00000001461 15111303730 0013211 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\TextUI\Configuration; /** * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit * * @psalm-immutable */ final class IniSetting { private readonly string $name; private readonly string $value; public function __construct(string $name, string $value) { $this->name = $name; $this->value = $value; } public function name(): string { return $this->name; } public function value(): string { return $this->value; } } Configuration/Value/TestDirectory.php 0000644 00000003303 15111303730 0013735 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\TextUI\Configuration; use PHPUnit\Util\VersionComparisonOperator; /** * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit * * @psalm-immutable */ final class TestDirectory { /** * @psalm-var non-empty-string */ private readonly string $path; private readonly string $prefix; private readonly string $suffix; private readonly string $phpVersion; private readonly VersionComparisonOperator $phpVersionOperator; /** * @psalm-param non-empty-string $path */ public function __construct(string $path, string $prefix, string $suffix, string $phpVersion, VersionComparisonOperator $phpVersionOperator) { $this->path = $path; $this->prefix = $prefix; $this->suffix = $suffix; $this->phpVersion = $phpVersion; $this->phpVersionOperator = $phpVersionOperator; } /** * @psalm-return non-empty-string */ public function path(): string { return $this->path; } public function prefix(): string { return $this->prefix; } public function suffix(): string { return $this->suffix; } public function phpVersion(): string { return $this->phpVersion; } public function phpVersionOperator(): VersionComparisonOperator { return $this->phpVersionOperator; } } Configuration/Value/File.php 0000644 00000001456 15111303730 0012017 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\TextUI\Configuration; /** * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit * * @psalm-immutable */ final class File { /** * @psalm-var non-empty-string */ private readonly string $path; /** * @psalm-param non-empty-string $path */ public function __construct(string $path) { $this->path = $path; } /** * @psalm-return non-empty-string */ public function path(): string { return $this->path; } } Configuration/Value/DirectoryCollectionIterator.php 0000644 00000002557 15111303730 0016635 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\TextUI\Configuration; use function count; use function iterator_count; use Countable; use Iterator; /** * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit * * @template-implements Iterator<int, Directory> */ final class DirectoryCollectionIterator implements Countable, Iterator { /** * @psalm-var list<Directory> */ private readonly array $directories; private int $position = 0; public function __construct(DirectoryCollection $directories) { $this->directories = $directories->asArray(); } public function count(): int { return iterator_count($this); } public function rewind(): void { $this->position = 0; } public function valid(): bool { return $this->position < count($this->directories); } public function key(): int { return $this->position; } public function current(): Directory { return $this->directories[$this->position]; } public function next(): void { $this->position++; } } Configuration/Value/FilterDirectory.php 0000644 00000002207 15111303730 0014245 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\TextUI\Configuration; /** * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit * * @psalm-immutable */ final class FilterDirectory { /** * @psalm-var non-empty-string */ private readonly string $path; private readonly string $prefix; private readonly string $suffix; /** * @psalm-param non-empty-string $path */ public function __construct(string $path, string $prefix, string $suffix) { $this->path = $path; $this->prefix = $prefix; $this->suffix = $suffix; } /** * @psalm-return non-empty-string */ public function path(): string { return $this->path; } public function prefix(): string { return $this->prefix; } public function suffix(): string { return $this->suffix; } } Configuration/Value/IniSettingCollection.php 0000644 00000002545 15111303730 0015231 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\TextUI\Configuration; use function count; use Countable; use IteratorAggregate; /** * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit * * @psalm-immutable * * @template-implements IteratorAggregate<int, IniSetting> */ final class IniSettingCollection implements Countable, IteratorAggregate { /** * @psalm-var list<IniSetting> */ private readonly array $iniSettings; /** * @psalm-param list<IniSetting> $iniSettings */ public static function fromArray(array $iniSettings): self { return new self(...$iniSettings); } private function __construct(IniSetting ...$iniSettings) { $this->iniSettings = $iniSettings; } /** * @psalm-return list<IniSetting> */ public function asArray(): array { return $this->iniSettings; } public function count(): int { return count($this->iniSettings); } public function getIterator(): IniSettingCollectionIterator { return new IniSettingCollectionIterator($this); } } Configuration/Value/TestFileCollectionIterator.php 0000644 00000002506 15111303730 0016402 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\TextUI\Configuration; use function count; use function iterator_count; use Countable; use Iterator; /** * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit * * @template-implements Iterator<int, TestFile> */ final class TestFileCollectionIterator implements Countable, Iterator { /** * @psalm-var list<TestFile> */ private readonly array $files; private int $position = 0; public function __construct(TestFileCollection $files) { $this->files = $files->asArray(); } public function count(): int { return iterator_count($this); } public function rewind(): void { $this->position = 0; } public function valid(): bool { return $this->position < count($this->files); } public function key(): int { return $this->position; } public function current(): TestFile { return $this->files[$this->position]; } public function next(): void { $this->position++; } } Configuration/Value/TestDirectoryCollectionIterator.php 0000644 00000002603 15111303730 0017465 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\TextUI\Configuration; use function count; use function iterator_count; use Countable; use Iterator; /** * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit * * @template-implements Iterator<int, TestDirectory> */ final class TestDirectoryCollectionIterator implements Countable, Iterator { /** * @psalm-var list<TestDirectory> */ private readonly array $directories; private int $position = 0; public function __construct(TestDirectoryCollection $directories) { $this->directories = $directories->asArray(); } public function count(): int { return iterator_count($this); } public function rewind(): void { $this->position = 0; } public function valid(): bool { return $this->position < count($this->directories); } public function key(): int { return $this->position; } public function current(): TestDirectory { return $this->directories[$this->position]; } public function next(): void { $this->position++; } } Configuration/Value/GroupCollection.php 0000644 00000002740 15111303730 0014245 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\TextUI\Configuration; use IteratorAggregate; /** * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit * * @psalm-immutable * * @template-implements IteratorAggregate<int, Group> */ final class GroupCollection implements IteratorAggregate { /** * @psalm-var list<Group> */ private readonly array $groups; /** * @psalm-param list<Group> $groups */ public static function fromArray(array $groups): self { return new self(...$groups); } private function __construct(Group ...$groups) { $this->groups = $groups; } /** * @psalm-return list<Group> */ public function asArray(): array { return $this->groups; } /** * @psalm-return list<string> */ public function asArrayOfStrings(): array { $result = []; foreach ($this->groups as $group) { $result[] = $group->name(); } return $result; } public function isEmpty(): bool { return empty($this->groups); } public function getIterator(): GroupCollectionIterator { return new GroupCollectionIterator($this); } } Configuration/Value/FilterDirectoryCollection.php 0000644 00000002752 15111303730 0016266 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\TextUI\Configuration; use function count; use Countable; use IteratorAggregate; /** * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit * * @psalm-immutable * * @template-implements IteratorAggregate<int, FilterDirectory> */ final class FilterDirectoryCollection implements Countable, IteratorAggregate { /** * @psalm-var list<FilterDirectory> */ private readonly array $directories; /** * @psalm-param list<FilterDirectory> $directories */ public static function fromArray(array $directories): self { return new self(...$directories); } private function __construct(FilterDirectory ...$directories) { $this->directories = $directories; } /** * @psalm-return list<FilterDirectory> */ public function asArray(): array { return $this->directories; } public function count(): int { return count($this->directories); } public function notEmpty(): bool { return !empty($this->directories); } public function getIterator(): FilterDirectoryCollectionIterator { return new FilterDirectoryCollectionIterator($this); } } Configuration/Value/FileCollection.php 0000644 00000002526 15111303730 0014032 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\TextUI\Configuration; use function count; use Countable; use IteratorAggregate; /** * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit * * @psalm-immutable * * @template-implements IteratorAggregate<int, File> */ final class FileCollection implements Countable, IteratorAggregate { /** * @psalm-var list<File> */ private readonly array $files; /** * @psalm-param list<File> $files */ public static function fromArray(array $files): self { return new self(...$files); } private function __construct(File ...$files) { $this->files = $files; } /** * @psalm-return list<File> */ public function asArray(): array { return $this->files; } public function count(): int { return count($this->files); } public function notEmpty(): bool { return !empty($this->files); } public function getIterator(): FileCollectionIterator { return new FileCollectionIterator($this); } } Configuration/Value/VariableCollection.php 0000644 00000002503 15111303730 0014673 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\TextUI\Configuration; use function count; use Countable; use IteratorAggregate; /** * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit * * @psalm-immutable * * @template-implements IteratorAggregate<int, Variable> */ final class VariableCollection implements Countable, IteratorAggregate { /** * @psalm-var list<Variable> */ private readonly array $variables; /** * @psalm-param list<Variable> $variables */ public static function fromArray(array $variables): self { return new self(...$variables); } private function __construct(Variable ...$variables) { $this->variables = $variables; } /** * @psalm-return list<Variable> */ public function asArray(): array { return $this->variables; } public function count(): int { return count($this->variables); } public function getIterator(): VariableCollectionIterator { return new VariableCollectionIterator($this); } } Configuration/Value/GroupCollectionIterator.php 0000644 00000002475 15111303730 0015764 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\TextUI\Configuration; use function count; use function iterator_count; use Countable; use Iterator; /** * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit * * @template-implements Iterator<int, Group> */ final class GroupCollectionIterator implements Countable, Iterator { /** * @psalm-var list<Group> */ private readonly array $groups; private int $position = 0; public function __construct(GroupCollection $groups) { $this->groups = $groups->asArray(); } public function count(): int { return iterator_count($this); } public function rewind(): void { $this->position = 0; } public function valid(): bool { return $this->position < count($this->groups); } public function key(): int { return $this->position; } public function current(): Group { return $this->groups[$this->position]; } public function next(): void { $this->position++; } } Configuration/Value/ConstantCollectionIterator.php 0000644 00000002536 15111303730 0016457 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\TextUI\Configuration; use function count; use function iterator_count; use Countable; use Iterator; /** * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit * * @template-implements Iterator<int, Constant> */ final class ConstantCollectionIterator implements Countable, Iterator { /** * @psalm-var list<Constant> */ private readonly array $constants; private int $position = 0; public function __construct(ConstantCollection $constants) { $this->constants = $constants->asArray(); } public function count(): int { return iterator_count($this); } public function rewind(): void { $this->position = 0; } public function valid(): bool { return $this->position < count($this->constants); } public function key(): int { return $this->position; } public function current(): Constant { return $this->constants[$this->position]; } public function next(): void { $this->position++; } } Configuration/Value/Group.php 0000644 00000001213 15111303730 0012223 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\TextUI\Configuration; /** * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit * * @psalm-immutable */ final class Group { private readonly string $name; public function __construct(string $name) { $this->name = $name; } public function name(): string { return $this->name; } } Configuration/Value/DirectoryCollection.php 0000644 00000002663 15111303730 0015121 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\TextUI\Configuration; use function count; use Countable; use IteratorAggregate; /** * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit * * @psalm-immutable * * @template-implements IteratorAggregate<int, Directory> */ final class DirectoryCollection implements Countable, IteratorAggregate { /** * @psalm-var list<Directory> */ private readonly array $directories; /** * @psalm-param list<Directory> $directories */ public static function fromArray(array $directories): self { return new self(...$directories); } private function __construct(Directory ...$directories) { $this->directories = $directories; } /** * @psalm-return list<Directory> */ public function asArray(): array { return $this->directories; } public function count(): int { return count($this->directories); } public function getIterator(): DirectoryCollectionIterator { return new DirectoryCollectionIterator($this); } public function isEmpty(): bool { return $this->count() === 0; } } Configuration/Value/FilterDirectoryCollectionIterator.php 0000644 00000002615 15111303730 0017776 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\TextUI\Configuration; use function count; use function iterator_count; use Countable; use Iterator; /** * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit * * @template-implements Iterator<int, FilterDirectory> */ final class FilterDirectoryCollectionIterator implements Countable, Iterator { /** * @psalm-var list<FilterDirectory> */ private readonly array $directories; private int $position = 0; public function __construct(FilterDirectoryCollection $directories) { $this->directories = $directories->asArray(); } public function count(): int { return iterator_count($this); } public function rewind(): void { $this->position = 0; } public function valid(): bool { return $this->position < count($this->directories); } public function key(): int { return $this->position; } public function current(): FilterDirectory { return $this->directories[$this->position]; } public function next(): void { $this->position++; } } Configuration/Value/Php.php 0000644 00000006232 15111303730 0011664 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\TextUI\Configuration; /** * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit * * @psalm-immutable */ final class Php { private readonly DirectoryCollection $includePaths; private readonly IniSettingCollection $iniSettings; private readonly ConstantCollection $constants; private readonly VariableCollection $globalVariables; private readonly VariableCollection $envVariables; private readonly VariableCollection $postVariables; private readonly VariableCollection $getVariables; private readonly VariableCollection $cookieVariables; private readonly VariableCollection $serverVariables; private readonly VariableCollection $filesVariables; private readonly VariableCollection $requestVariables; public function __construct(DirectoryCollection $includePaths, IniSettingCollection $iniSettings, ConstantCollection $constants, VariableCollection $globalVariables, VariableCollection $envVariables, VariableCollection $postVariables, VariableCollection $getVariables, VariableCollection $cookieVariables, VariableCollection $serverVariables, VariableCollection $filesVariables, VariableCollection $requestVariables) { $this->includePaths = $includePaths; $this->iniSettings = $iniSettings; $this->constants = $constants; $this->globalVariables = $globalVariables; $this->envVariables = $envVariables; $this->postVariables = $postVariables; $this->getVariables = $getVariables; $this->cookieVariables = $cookieVariables; $this->serverVariables = $serverVariables; $this->filesVariables = $filesVariables; $this->requestVariables = $requestVariables; } public function includePaths(): DirectoryCollection { return $this->includePaths; } public function iniSettings(): IniSettingCollection { return $this->iniSettings; } public function constants(): ConstantCollection { return $this->constants; } public function globalVariables(): VariableCollection { return $this->globalVariables; } public function envVariables(): VariableCollection { return $this->envVariables; } public function postVariables(): VariableCollection { return $this->postVariables; } public function getVariables(): VariableCollection { return $this->getVariables; } public function cookieVariables(): VariableCollection { return $this->cookieVariables; } public function serverVariables(): VariableCollection { return $this->serverVariables; } public function filesVariables(): VariableCollection { return $this->filesVariables; } public function requestVariables(): VariableCollection { return $this->requestVariables; } } Configuration/Value/TestSuite.php 0000644 00000002703 15111303730 0013065 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\TextUI\Configuration; /** * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit * * @psalm-immutable */ final class TestSuite { /** * @psalm-var non-empty-string */ private readonly string $name; private readonly TestDirectoryCollection $directories; private readonly TestFileCollection $files; private readonly FileCollection $exclude; /** * @psalm-param non-empty-string $name */ public function __construct(string $name, TestDirectoryCollection $directories, TestFileCollection $files, FileCollection $exclude) { $this->name = $name; $this->directories = $directories; $this->files = $files; $this->exclude = $exclude; } /** * @psalm-return non-empty-string */ public function name(): string { return $this->name; } public function directories(): TestDirectoryCollection { return $this->directories; } public function files(): TestFileCollection { return $this->files; } public function exclude(): FileCollection { return $this->exclude; } } Configuration/Value/TestFileCollection.php 0000644 00000002565 15111303730 0014675 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\TextUI\Configuration; use function count; use Countable; use IteratorAggregate; /** * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit * * @psalm-immutable * * @template-implements IteratorAggregate<int, TestFile> */ final class TestFileCollection implements Countable, IteratorAggregate { /** * @psalm-var list<TestFile> */ private readonly array $files; /** * @psalm-param list<TestFile> $files */ public static function fromArray(array $files): self { return new self(...$files); } private function __construct(TestFile ...$files) { $this->files = $files; } /** * @psalm-return list<TestFile> */ public function asArray(): array { return $this->files; } public function count(): int { return count($this->files); } public function getIterator(): TestFileCollectionIterator { return new TestFileCollectionIterator($this); } public function isEmpty(): bool { return $this->count() === 0; } } Configuration/Value/IniSettingCollectionIterator.php 0000644 00000002564 15111303730 0016744 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\TextUI\Configuration; use function count; use function iterator_count; use Countable; use Iterator; /** * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit * * @template-implements Iterator<int, IniSetting> */ final class IniSettingCollectionIterator implements Countable, Iterator { /** * @psalm-var list<IniSetting> */ private readonly array $iniSettings; private int $position = 0; public function __construct(IniSettingCollection $iniSettings) { $this->iniSettings = $iniSettings->asArray(); } public function count(): int { return iterator_count($this); } public function rewind(): void { $this->position = 0; } public function valid(): bool { return $this->position < count($this->iniSettings); } public function key(): int { return $this->position; } public function current(): IniSetting { return $this->iniSettings[$this->position]; } public function next(): void { $this->position++; } } Configuration/Value/ExtensionBootstrap.php 0000644 00000002266 15111303730 0015012 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\TextUI\Configuration; /** * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit * * @psalm-immutable */ final class ExtensionBootstrap { /** * @psalm-var class-string */ private readonly string $className; /** * @psalm-var array<string,string> */ private readonly array $parameters; /** * @psalm-param class-string $className * @psalm-param array<string,string> $parameters */ public function __construct(string $className, array $parameters) { $this->className = $className; $this->parameters = $parameters; } /** * @psalm-return class-string */ public function className(): string { return $this->className; } /** * @psalm-return array<string,string> */ public function parameters(): array { return $this->parameters; } } Configuration/Value/ExtensionBootstrapCollectionIterator.php 0000644 00000002714 15111303730 0020536 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\TextUI\Configuration; use function count; use function iterator_count; use Countable; use Iterator; /** * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit * * @template-implements Iterator<int, ExtensionBootstrap> */ final class ExtensionBootstrapCollectionIterator implements Countable, Iterator { /** * @psalm-var list<ExtensionBootstrap> */ private readonly array $extensionBootstraps; private int $position = 0; public function __construct(ExtensionBootstrapCollection $extensionBootstraps) { $this->extensionBootstraps = $extensionBootstraps->asArray(); } public function count(): int { return iterator_count($this); } public function rewind(): void { $this->position = 0; } public function valid(): bool { return $this->position < count($this->extensionBootstraps); } public function key(): int { return $this->position; } public function current(): ExtensionBootstrap { return $this->extensionBootstraps[$this->position]; } public function next(): void { $this->position++; } } Configuration/Value/Constant.php 0000644 00000001476 15111303730 0012733 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\TextUI\Configuration; /** * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit * * @psalm-immutable */ final class Constant { private readonly string $name; private readonly bool|string $value; public function __construct(string $name, bool|string $value) { $this->name = $name; $this->value = $value; } public function name(): string { return $this->name; } public function value(): bool|string { return $this->value; } } Configuration/Cli/XmlConfigurationFileFinder.php 0000644 00000003355 15111303730 0016013 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\TextUI\CliArguments; use function getcwd; use function is_dir; use function is_file; use function realpath; /** * @internal This class is not covered by the backward compatibility promise for PHPUnit */ final class XmlConfigurationFileFinder { public function find(Configuration $configuration): false|string { $useDefaultConfiguration = $configuration->useDefaultConfiguration(); if ($configuration->hasConfigurationFile()) { if (is_dir($configuration->configurationFile())) { $candidate = $this->configurationFileInDirectory($configuration->configurationFile()); if ($candidate) { return $candidate; } return false; } return $configuration->configurationFile(); } if ($useDefaultConfiguration) { $candidate = $this->configurationFileInDirectory(getcwd()); if ($candidate) { return $candidate; } } return false; } private function configurationFileInDirectory(string $directory): false|string { $candidates = [ $directory . '/phpunit.xml', $directory . '/phpunit.dist.xml', $directory . '/phpunit.xml.dist', ]; foreach ($candidates as $candidate) { if (is_file($candidate)) { return realpath($candidate); } } return false; } } Configuration/Cli/Exception.php 0000644 00000000756 15111303730 0012533 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\TextUI\CliArguments; use RuntimeException; /** * @internal This class is not covered by the backward compatibility promise for PHPUnit */ final class Exception extends RuntimeException implements \PHPUnit\Exception { } Configuration/Cli/Builder.php 0000644 00000063654 15111303730 0012171 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\TextUI\CliArguments; use function array_map; use function basename; use function explode; use function getcwd; use function is_file; use function is_numeric; use function sprintf; use PHPUnit\Runner\TestSuiteSorter; use SebastianBergmann\CliParser\Exception as CliParserException; use SebastianBergmann\CliParser\Parser as CliParser; /** * @internal This class is not covered by the backward compatibility promise for PHPUnit */ final class Builder { private const LONG_OPTIONS = [ 'atleast-version=', 'bootstrap=', 'cache-result', 'do-not-cache-result', 'cache-directory=', 'cache-result-file=', 'check-version', 'colors==', 'columns=', 'configuration=', 'coverage-cache=', 'warm-coverage-cache', 'coverage-filter=', 'coverage-clover=', 'coverage-cobertura=', 'coverage-crap4j=', 'coverage-html=', 'coverage-php=', 'coverage-text==', 'coverage-xml=', 'path-coverage', 'disallow-test-output', 'display-incomplete', 'display-skipped', 'display-deprecations', 'display-errors', 'display-notices', 'display-warnings', 'default-time-limit=', 'enforce-time-limit', 'exclude-group=', 'filter=', 'generate-baseline=', 'use-baseline=', 'ignore-baseline', 'generate-configuration', 'globals-backup', 'group=', 'covers=', 'uses=', 'help', 'resolve-dependencies', 'ignore-dependencies', 'include-path=', 'list-groups', 'list-suites', 'list-tests', 'list-tests-xml=', 'log-junit=', 'log-teamcity=', 'migrate-configuration', 'no-configuration', 'no-coverage', 'no-logging', 'no-extensions', 'no-output', 'no-progress', 'no-results', 'order-by=', 'process-isolation', 'dont-report-useless-tests', 'random-order', 'random-order-seed=', 'reverse-order', 'reverse-list', 'static-backup', 'stderr', 'fail-on-deprecation', 'fail-on-empty-test-suite', 'fail-on-incomplete', 'fail-on-notice', 'fail-on-risky', 'fail-on-skipped', 'fail-on-warning', 'stop-on-defect', 'stop-on-deprecation', 'stop-on-error', 'stop-on-failure', 'stop-on-incomplete', 'stop-on-notice', 'stop-on-risky', 'stop-on-skipped', 'stop-on-warning', 'strict-coverage', 'disable-coverage-ignore', 'strict-global-state', 'teamcity', 'testdox', 'testdox-html=', 'testdox-text=', 'test-suffix=', 'testsuite=', 'exclude-testsuite=', 'log-events-text=', 'log-events-verbose-text=', 'version', ]; private const SHORT_OPTIONS = 'd:c:h'; /** * @throws Exception */ public function fromParameters(array $parameters): Configuration { try { $options = (new CliParser)->parse( $parameters, self::SHORT_OPTIONS, self::LONG_OPTIONS, ); } catch (CliParserException $e) { throw new Exception( $e->getMessage(), $e->getCode(), $e, ); } $atLeastVersion = null; $backupGlobals = null; $backupStaticProperties = null; $beStrictAboutChangesToGlobalState = null; $bootstrap = null; $cacheDirectory = null; $cacheResult = null; $cacheResultFile = null; $checkVersion = false; $colors = null; $columns = null; $configuration = null; $coverageCacheDirectory = null; $warmCoverageCache = false; $coverageFilter = null; $coverageClover = null; $coverageCobertura = null; $coverageCrap4J = null; $coverageHtml = null; $coveragePhp = null; $coverageText = null; $coverageTextShowUncoveredFiles = null; $coverageTextShowOnlySummary = null; $coverageXml = null; $pathCoverage = null; $defaultTimeLimit = null; $disableCodeCoverageIgnore = null; $disallowTestOutput = null; $displayIncomplete = null; $displaySkipped = null; $displayDeprecations = null; $displayErrors = null; $displayNotices = null; $displayWarnings = null; $enforceTimeLimit = null; $excludeGroups = null; $executionOrder = null; $executionOrderDefects = null; $failOnDeprecation = null; $failOnEmptyTestSuite = null; $failOnIncomplete = null; $failOnNotice = null; $failOnRisky = null; $failOnSkipped = null; $failOnWarning = null; $stopOnDefect = null; $stopOnDeprecation = null; $stopOnError = null; $stopOnFailure = null; $stopOnIncomplete = null; $stopOnNotice = null; $stopOnRisky = null; $stopOnSkipped = null; $stopOnWarning = null; $filter = null; $generateBaseline = null; $useBaseline = null; $ignoreBaseline = false; $generateConfiguration = false; $migrateConfiguration = false; $groups = null; $testsCovering = null; $testsUsing = null; $help = false; $includePath = null; $iniSettings = []; $junitLogfile = null; $listGroups = false; $listSuites = false; $listTests = false; $listTestsXml = null; $noCoverage = null; $noExtensions = null; $noOutput = null; $noProgress = null; $noResults = null; $noLogging = null; $processIsolation = null; $randomOrderSeed = null; $reportUselessTests = null; $resolveDependencies = null; $reverseList = null; $stderr = null; $strictCoverage = null; $teamcityLogfile = null; $testdoxHtmlFile = null; $testdoxTextFile = null; $testSuffixes = null; $testSuite = null; $excludeTestSuite = null; $useDefaultConfiguration = true; $version = false; $logEventsText = null; $logEventsVerboseText = null; $printerTeamCity = null; $printerTestDox = null; foreach ($options[0] as $option) { switch ($option[0]) { case '--colors': $colors = $option[1] ?: \PHPUnit\TextUI\Configuration\Configuration::COLOR_AUTO; break; case '--bootstrap': $bootstrap = $option[1]; break; case '--cache-directory': $cacheDirectory = $option[1]; break; case '--cache-result': $cacheResult = true; break; case '--do-not-cache-result': $cacheResult = false; break; case '--cache-result-file': $cacheResultFile = $option[1]; break; case '--columns': if (is_numeric($option[1])) { $columns = (int) $option[1]; } elseif ($option[1] === 'max') { $columns = 'max'; } break; case 'c': case '--configuration': $configuration = $option[1]; break; case '--coverage-cache': $coverageCacheDirectory = $option[1]; break; case '--warm-coverage-cache': $warmCoverageCache = true; break; case '--coverage-clover': $coverageClover = $option[1]; break; case '--coverage-cobertura': $coverageCobertura = $option[1]; break; case '--coverage-crap4j': $coverageCrap4J = $option[1]; break; case '--coverage-html': $coverageHtml = $option[1]; break; case '--coverage-php': $coveragePhp = $option[1]; break; case '--coverage-text': if ($option[1] === null) { $option[1] = 'php://stdout'; } $coverageText = $option[1]; $coverageTextShowUncoveredFiles = false; $coverageTextShowOnlySummary = false; break; case '--coverage-xml': $coverageXml = $option[1]; break; case '--path-coverage': $pathCoverage = true; break; case 'd': $tmp = explode('=', $option[1]); if (isset($tmp[0])) { if (isset($tmp[1])) { $iniSettings[$tmp[0]] = $tmp[1]; } else { $iniSettings[$tmp[0]] = '1'; } } break; case 'h': case '--help': $help = true; break; case '--filter': $filter = $option[1]; break; case '--testsuite': $testSuite = $option[1]; break; case '--exclude-testsuite': $excludeTestSuite = $option[1]; break; case '--generate-baseline': $generateBaseline = $option[1]; if (basename($generateBaseline) === $generateBaseline) { $generateBaseline = getcwd() . DIRECTORY_SEPARATOR . $generateBaseline; } break; case '--use-baseline': $useBaseline = $option[1]; if (!is_file($useBaseline) && basename($useBaseline) === $useBaseline) { $useBaseline = getcwd() . DIRECTORY_SEPARATOR . $useBaseline; } break; case '--ignore-baseline': $ignoreBaseline = true; break; case '--generate-configuration': $generateConfiguration = true; break; case '--migrate-configuration': $migrateConfiguration = true; break; case '--group': $groups = explode(',', $option[1]); break; case '--exclude-group': $excludeGroups = explode(',', $option[1]); break; case '--covers': $testsCovering = array_map('strtolower', explode(',', $option[1])); break; case '--uses': $testsUsing = array_map('strtolower', explode(',', $option[1])); break; case '--test-suffix': $testSuffixes = explode(',', $option[1]); break; case '--include-path': $includePath = $option[1]; break; case '--list-groups': $listGroups = true; break; case '--list-suites': $listSuites = true; break; case '--list-tests': $listTests = true; break; case '--list-tests-xml': $listTestsXml = $option[1]; break; case '--log-junit': $junitLogfile = $option[1]; break; case '--log-teamcity': $teamcityLogfile = $option[1]; break; case '--order-by': foreach (explode(',', $option[1]) as $order) { switch ($order) { case 'default': $executionOrder = TestSuiteSorter::ORDER_DEFAULT; $executionOrderDefects = TestSuiteSorter::ORDER_DEFAULT; $resolveDependencies = true; break; case 'defects': $executionOrderDefects = TestSuiteSorter::ORDER_DEFECTS_FIRST; break; case 'depends': $resolveDependencies = true; break; case 'duration': $executionOrder = TestSuiteSorter::ORDER_DURATION; break; case 'no-depends': $resolveDependencies = false; break; case 'random': $executionOrder = TestSuiteSorter::ORDER_RANDOMIZED; break; case 'reverse': $executionOrder = TestSuiteSorter::ORDER_REVERSED; break; case 'size': $executionOrder = TestSuiteSorter::ORDER_SIZE; break; default: throw new Exception( sprintf( 'unrecognized --order-by option: %s', $order, ), ); } } break; case '--process-isolation': $processIsolation = true; break; case '--stderr': $stderr = true; break; case '--fail-on-deprecation': $failOnDeprecation = true; break; case '--fail-on-empty-test-suite': $failOnEmptyTestSuite = true; break; case '--fail-on-incomplete': $failOnIncomplete = true; break; case '--fail-on-notice': $failOnNotice = true; break; case '--fail-on-risky': $failOnRisky = true; break; case '--fail-on-skipped': $failOnSkipped = true; break; case '--fail-on-warning': $failOnWarning = true; break; case '--stop-on-defect': $stopOnDefect = true; break; case '--stop-on-deprecation': $stopOnDeprecation = true; break; case '--stop-on-error': $stopOnError = true; break; case '--stop-on-failure': $stopOnFailure = true; break; case '--stop-on-incomplete': $stopOnIncomplete = true; break; case '--stop-on-notice': $stopOnNotice = true; break; case '--stop-on-risky': $stopOnRisky = true; break; case '--stop-on-skipped': $stopOnSkipped = true; break; case '--stop-on-warning': $stopOnWarning = true; break; case '--teamcity': $printerTeamCity = true; break; case '--testdox': $printerTestDox = true; break; case '--testdox-html': $testdoxHtmlFile = $option[1]; break; case '--testdox-text': $testdoxTextFile = $option[1]; break; case '--no-configuration': $useDefaultConfiguration = false; break; case '--no-extensions': $noExtensions = true; break; case '--no-coverage': $noCoverage = true; break; case '--no-logging': $noLogging = true; break; case '--no-output': $noOutput = true; break; case '--no-progress': $noProgress = true; break; case '--no-results': $noResults = true; break; case '--globals-backup': $backupGlobals = true; break; case '--static-backup': $backupStaticProperties = true; break; case '--atleast-version': $atLeastVersion = $option[1]; break; case '--version': $version = true; break; case '--dont-report-useless-tests': $reportUselessTests = false; break; case '--strict-coverage': $strictCoverage = true; break; case '--disable-coverage-ignore': $disableCodeCoverageIgnore = true; break; case '--strict-global-state': $beStrictAboutChangesToGlobalState = true; break; case '--disallow-test-output': $disallowTestOutput = true; break; case '--display-incomplete': $displayIncomplete = true; break; case '--display-skipped': $displaySkipped = true; break; case '--display-deprecations': $displayDeprecations = true; break; case '--display-errors': $displayErrors = true; break; case '--display-notices': $displayNotices = true; break; case '--display-warnings': $displayWarnings = true; break; case '--default-time-limit': $defaultTimeLimit = (int) $option[1]; break; case '--enforce-time-limit': $enforceTimeLimit = true; break; case '--reverse-list': $reverseList = true; break; case '--check-version': $checkVersion = true; break; case '--coverage-filter': if ($coverageFilter === null) { $coverageFilter = []; } $coverageFilter[] = $option[1]; break; case '--random-order': $executionOrder = TestSuiteSorter::ORDER_RANDOMIZED; break; case '--random-order-seed': $randomOrderSeed = (int) $option[1]; break; case '--resolve-dependencies': $resolveDependencies = true; break; case '--ignore-dependencies': $resolveDependencies = false; break; case '--reverse-order': $executionOrder = TestSuiteSorter::ORDER_REVERSED; break; case '--log-events-text': $logEventsText = $option[1]; break; case '--log-events-verbose-text': $logEventsVerboseText = $option[1]; break; } } if (empty($iniSettings)) { $iniSettings = null; } if (empty($coverageFilter)) { $coverageFilter = null; } return new Configuration( $options[1], $atLeastVersion, $backupGlobals, $backupStaticProperties, $beStrictAboutChangesToGlobalState, $bootstrap, $cacheDirectory, $cacheResult, $cacheResultFile, $checkVersion, $colors, $columns, $configuration, $coverageClover, $coverageCobertura, $coverageCrap4J, $coverageHtml, $coveragePhp, $coverageText, $coverageTextShowUncoveredFiles, $coverageTextShowOnlySummary, $coverageXml, $pathCoverage, $coverageCacheDirectory, $warmCoverageCache, $defaultTimeLimit, $disableCodeCoverageIgnore, $disallowTestOutput, $enforceTimeLimit, $excludeGroups, $executionOrder, $executionOrderDefects, $failOnDeprecation, $failOnEmptyTestSuite, $failOnIncomplete, $failOnNotice, $failOnRisky, $failOnSkipped, $failOnWarning, $stopOnDefect, $stopOnDeprecation, $stopOnError, $stopOnFailure, $stopOnIncomplete, $stopOnNotice, $stopOnRisky, $stopOnSkipped, $stopOnWarning, $filter, $generateBaseline, $useBaseline, $ignoreBaseline, $generateConfiguration, $migrateConfiguration, $groups, $testsCovering, $testsUsing, $help, $includePath, $iniSettings, $junitLogfile, $listGroups, $listSuites, $listTests, $listTestsXml, $noCoverage, $noExtensions, $noOutput, $noProgress, $noResults, $noLogging, $processIsolation, $randomOrderSeed, $reportUselessTests, $resolveDependencies, $reverseList, $stderr, $strictCoverage, $teamcityLogfile, $testdoxHtmlFile, $testdoxTextFile, $testSuffixes, $testSuite, $excludeTestSuite, $useDefaultConfiguration, $displayIncomplete, $displaySkipped, $displayDeprecations, $displayErrors, $displayNotices, $displayWarnings, $version, $coverageFilter, $logEventsText, $logEventsVerboseText, $printerTeamCity, $printerTestDox, ); } } Configuration/Cli/Configuration.php 0000644 00000145024 15111303730 0013402 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\TextUI\CliArguments; /** * @internal This class is not covered by the backward compatibility promise for PHPUnit * * @psalm-immutable */ final class Configuration { /** * @psalm-var list<non-empty-string> */ private readonly array $arguments; private readonly ?string $atLeastVersion; private readonly ?bool $backupGlobals; private readonly ?bool $backupStaticProperties; private readonly ?bool $beStrictAboutChangesToGlobalState; private readonly ?string $bootstrap; private readonly ?string $cacheDirectory; private readonly ?bool $cacheResult; private readonly ?string $cacheResultFile; private readonly bool $checkVersion; private readonly ?string $colors; private readonly null|int|string $columns; private readonly ?string $configurationFile; private readonly ?array $coverageFilter; private readonly ?string $coverageClover; private readonly ?string $coverageCobertura; private readonly ?string $coverageCrap4J; private readonly ?string $coverageHtml; private readonly ?string $coveragePhp; private readonly ?string $coverageText; private readonly ?bool $coverageTextShowUncoveredFiles; private readonly ?bool $coverageTextShowOnlySummary; private readonly ?string $coverageXml; private readonly ?bool $pathCoverage; private readonly ?string $coverageCacheDirectory; private readonly bool $warmCoverageCache; private readonly ?int $defaultTimeLimit; private readonly ?bool $disableCodeCoverageIgnore; private readonly ?bool $disallowTestOutput; private readonly ?bool $enforceTimeLimit; private readonly ?array $excludeGroups; private readonly ?int $executionOrder; private readonly ?int $executionOrderDefects; private readonly ?bool $failOnDeprecation; private readonly ?bool $failOnEmptyTestSuite; private readonly ?bool $failOnIncomplete; private readonly ?bool $failOnNotice; private readonly ?bool $failOnRisky; private readonly ?bool $failOnSkipped; private readonly ?bool $failOnWarning; private readonly ?bool $stopOnDefect; private readonly ?bool $stopOnDeprecation; private readonly ?bool $stopOnError; private readonly ?bool $stopOnFailure; private readonly ?bool $stopOnIncomplete; private readonly ?bool $stopOnNotice; private readonly ?bool $stopOnRisky; private readonly ?bool $stopOnSkipped; private readonly ?bool $stopOnWarning; private readonly ?string $filter; private readonly ?string $generateBaseline; private readonly ?string $useBaseline; private readonly bool $ignoreBaseline; private readonly bool $generateConfiguration; private readonly bool $migrateConfiguration; private readonly ?array $groups; private readonly ?array $testsCovering; private readonly ?array $testsUsing; private readonly bool $help; private readonly ?string $includePath; private readonly ?array $iniSettings; private readonly ?string $junitLogfile; private readonly bool $listGroups; private readonly bool $listSuites; private readonly bool $listTests; private readonly ?string $listTestsXml; private readonly ?bool $noCoverage; private readonly ?bool $noExtensions; private readonly ?bool $noOutput; private readonly ?bool $noProgress; private readonly ?bool $noResults; private readonly ?bool $noLogging; private readonly ?bool $processIsolation; private readonly ?int $randomOrderSeed; private readonly ?bool $reportUselessTests; private readonly ?bool $resolveDependencies; private readonly ?bool $reverseList; private readonly ?bool $stderr; private readonly ?bool $strictCoverage; private readonly ?string $teamcityLogfile; private readonly ?bool $teamCityPrinter; private readonly ?string $testdoxHtmlFile; private readonly ?string $testdoxTextFile; private readonly ?bool $testdoxPrinter; /** * @psalm-var ?non-empty-list<non-empty-string> */ private readonly ?array $testSuffixes; private readonly ?string $testSuite; private readonly ?string $excludeTestSuite; private readonly bool $useDefaultConfiguration; private readonly ?bool $displayDetailsOnIncompleteTests; private readonly ?bool $displayDetailsOnSkippedTests; private readonly ?bool $displayDetailsOnTestsThatTriggerDeprecations; private readonly ?bool $displayDetailsOnTestsThatTriggerErrors; private readonly ?bool $displayDetailsOnTestsThatTriggerNotices; private readonly ?bool $displayDetailsOnTestsThatTriggerWarnings; private readonly bool $version; private readonly ?string $logEventsText; private readonly ?string $logEventsVerboseText; /** * @psalm-param list<non-empty-string> $arguments * @psalm-param ?non-empty-list<non-empty-string> $testSuffixes */ public function __construct(array $arguments, ?string $atLeastVersion, ?bool $backupGlobals, ?bool $backupStaticProperties, ?bool $beStrictAboutChangesToGlobalState, ?string $bootstrap, ?string $cacheDirectory, ?bool $cacheResult, ?string $cacheResultFile, bool $checkVersion, ?string $colors, null|int|string $columns, ?string $configurationFile, ?string $coverageClover, ?string $coverageCobertura, ?string $coverageCrap4J, ?string $coverageHtml, ?string $coveragePhp, ?string $coverageText, ?bool $coverageTextShowUncoveredFiles, ?bool $coverageTextShowOnlySummary, ?string $coverageXml, ?bool $pathCoverage, ?string $coverageCacheDirectory, bool $warmCoverageCache, ?int $defaultTimeLimit, ?bool $disableCodeCoverageIgnore, ?bool $disallowTestOutput, ?bool $enforceTimeLimit, ?array $excludeGroups, ?int $executionOrder, ?int $executionOrderDefects, ?bool $failOnDeprecation, ?bool $failOnEmptyTestSuite, ?bool $failOnIncomplete, ?bool $failOnNotice, ?bool $failOnRisky, ?bool $failOnSkipped, ?bool $failOnWarning, ?bool $stopOnDefect, ?bool $stopOnDeprecation, ?bool $stopOnError, ?bool $stopOnFailure, ?bool $stopOnIncomplete, ?bool $stopOnNotice, ?bool $stopOnRisky, ?bool $stopOnSkipped, ?bool $stopOnWarning, ?string $filter, ?string $generateBaseline, ?string $useBaseline, bool $ignoreBaseline, bool $generateConfiguration, bool $migrateConfiguration, ?array $groups, ?array $testsCovering, ?array $testsUsing, bool $help, ?string $includePath, ?array $iniSettings, ?string $junitLogfile, bool $listGroups, bool $listSuites, bool $listTests, ?string $listTestsXml, ?bool $noCoverage, ?bool $noExtensions, ?bool $noOutput, ?bool $noProgress, ?bool $noResults, ?bool $noLogging, ?bool $processIsolation, ?int $randomOrderSeed, ?bool $reportUselessTests, ?bool $resolveDependencies, ?bool $reverseList, ?bool $stderr, ?bool $strictCoverage, ?string $teamcityLogfile, ?string $testdoxHtmlFile, ?string $testdoxTextFile, ?array $testSuffixes, ?string $testSuite, ?string $excludeTestSuite, bool $useDefaultConfiguration, ?bool $displayDetailsOnIncompleteTests, ?bool $displayDetailsOnSkippedTests, ?bool $displayDetailsOnTestsThatTriggerDeprecations, ?bool $displayDetailsOnTestsThatTriggerErrors, ?bool $displayDetailsOnTestsThatTriggerNotices, ?bool $displayDetailsOnTestsThatTriggerWarnings, bool $version, ?array $coverageFilter, ?string $logEventsText, ?string $logEventsVerboseText, ?bool $printerTeamCity, ?bool $printerTestDox) { $this->arguments = $arguments; $this->atLeastVersion = $atLeastVersion; $this->backupGlobals = $backupGlobals; $this->backupStaticProperties = $backupStaticProperties; $this->beStrictAboutChangesToGlobalState = $beStrictAboutChangesToGlobalState; $this->bootstrap = $bootstrap; $this->cacheDirectory = $cacheDirectory; $this->cacheResult = $cacheResult; $this->cacheResultFile = $cacheResultFile; $this->checkVersion = $checkVersion; $this->colors = $colors; $this->columns = $columns; $this->configurationFile = $configurationFile; $this->coverageFilter = $coverageFilter; $this->coverageClover = $coverageClover; $this->coverageCobertura = $coverageCobertura; $this->coverageCrap4J = $coverageCrap4J; $this->coverageHtml = $coverageHtml; $this->coveragePhp = $coveragePhp; $this->coverageText = $coverageText; $this->coverageTextShowUncoveredFiles = $coverageTextShowUncoveredFiles; $this->coverageTextShowOnlySummary = $coverageTextShowOnlySummary; $this->coverageXml = $coverageXml; $this->pathCoverage = $pathCoverage; $this->coverageCacheDirectory = $coverageCacheDirectory; $this->warmCoverageCache = $warmCoverageCache; $this->defaultTimeLimit = $defaultTimeLimit; $this->disableCodeCoverageIgnore = $disableCodeCoverageIgnore; $this->disallowTestOutput = $disallowTestOutput; $this->enforceTimeLimit = $enforceTimeLimit; $this->excludeGroups = $excludeGroups; $this->executionOrder = $executionOrder; $this->executionOrderDefects = $executionOrderDefects; $this->failOnDeprecation = $failOnDeprecation; $this->failOnEmptyTestSuite = $failOnEmptyTestSuite; $this->failOnIncomplete = $failOnIncomplete; $this->failOnNotice = $failOnNotice; $this->failOnRisky = $failOnRisky; $this->failOnSkipped = $failOnSkipped; $this->failOnWarning = $failOnWarning; $this->stopOnDefect = $stopOnDefect; $this->stopOnDeprecation = $stopOnDeprecation; $this->stopOnError = $stopOnError; $this->stopOnFailure = $stopOnFailure; $this->stopOnIncomplete = $stopOnIncomplete; $this->stopOnNotice = $stopOnNotice; $this->stopOnRisky = $stopOnRisky; $this->stopOnSkipped = $stopOnSkipped; $this->stopOnWarning = $stopOnWarning; $this->filter = $filter; $this->generateBaseline = $generateBaseline; $this->useBaseline = $useBaseline; $this->ignoreBaseline = $ignoreBaseline; $this->generateConfiguration = $generateConfiguration; $this->migrateConfiguration = $migrateConfiguration; $this->groups = $groups; $this->testsCovering = $testsCovering; $this->testsUsing = $testsUsing; $this->help = $help; $this->includePath = $includePath; $this->iniSettings = $iniSettings; $this->junitLogfile = $junitLogfile; $this->listGroups = $listGroups; $this->listSuites = $listSuites; $this->listTests = $listTests; $this->listTestsXml = $listTestsXml; $this->noCoverage = $noCoverage; $this->noExtensions = $noExtensions; $this->noOutput = $noOutput; $this->noProgress = $noProgress; $this->noResults = $noResults; $this->noLogging = $noLogging; $this->processIsolation = $processIsolation; $this->randomOrderSeed = $randomOrderSeed; $this->reportUselessTests = $reportUselessTests; $this->resolveDependencies = $resolveDependencies; $this->reverseList = $reverseList; $this->stderr = $stderr; $this->strictCoverage = $strictCoverage; $this->teamcityLogfile = $teamcityLogfile; $this->testdoxHtmlFile = $testdoxHtmlFile; $this->testdoxTextFile = $testdoxTextFile; $this->testSuffixes = $testSuffixes; $this->testSuite = $testSuite; $this->excludeTestSuite = $excludeTestSuite; $this->useDefaultConfiguration = $useDefaultConfiguration; $this->displayDetailsOnIncompleteTests = $displayDetailsOnIncompleteTests; $this->displayDetailsOnSkippedTests = $displayDetailsOnSkippedTests; $this->displayDetailsOnTestsThatTriggerDeprecations = $displayDetailsOnTestsThatTriggerDeprecations; $this->displayDetailsOnTestsThatTriggerErrors = $displayDetailsOnTestsThatTriggerErrors; $this->displayDetailsOnTestsThatTriggerNotices = $displayDetailsOnTestsThatTriggerNotices; $this->displayDetailsOnTestsThatTriggerWarnings = $displayDetailsOnTestsThatTriggerWarnings; $this->version = $version; $this->logEventsText = $logEventsText; $this->logEventsVerboseText = $logEventsVerboseText; $this->teamCityPrinter = $printerTeamCity; $this->testdoxPrinter = $printerTestDox; } /** * @psalm-return list<non-empty-string> */ public function arguments(): array { return $this->arguments; } /** * @psalm-assert-if-true !null $this->atLeastVersion */ public function hasAtLeastVersion(): bool { return $this->atLeastVersion !== null; } /** * @throws Exception */ public function atLeastVersion(): string { if (!$this->hasAtLeastVersion()) { throw new Exception; } return $this->atLeastVersion; } /** * @psalm-assert-if-true !null $this->backupGlobals */ public function hasBackupGlobals(): bool { return $this->backupGlobals !== null; } /** * @throws Exception */ public function backupGlobals(): bool { if (!$this->hasBackupGlobals()) { throw new Exception; } return $this->backupGlobals; } /** * @psalm-assert-if-true !null $this->backupStaticProperties */ public function hasBackupStaticProperties(): bool { return $this->backupStaticProperties !== null; } /** * @throws Exception */ public function backupStaticProperties(): bool { if (!$this->hasBackupStaticProperties()) { throw new Exception; } return $this->backupStaticProperties; } /** * @psalm-assert-if-true !null $this->beStrictAboutChangesToGlobalState */ public function hasBeStrictAboutChangesToGlobalState(): bool { return $this->beStrictAboutChangesToGlobalState !== null; } /** * @throws Exception */ public function beStrictAboutChangesToGlobalState(): bool { if (!$this->hasBeStrictAboutChangesToGlobalState()) { throw new Exception; } return $this->beStrictAboutChangesToGlobalState; } /** * @psalm-assert-if-true !null $this->bootstrap */ public function hasBootstrap(): bool { return $this->bootstrap !== null; } /** * @throws Exception */ public function bootstrap(): string { if (!$this->hasBootstrap()) { throw new Exception; } return $this->bootstrap; } /** * @psalm-assert-if-true !null $this->cacheDirectory */ public function hasCacheDirectory(): bool { return $this->cacheDirectory !== null; } /** * @throws Exception */ public function cacheDirectory(): string { if (!$this->hasCacheDirectory()) { throw new Exception; } return $this->cacheDirectory; } /** * @psalm-assert-if-true !null $this->cacheResult */ public function hasCacheResult(): bool { return $this->cacheResult !== null; } /** * @throws Exception */ public function cacheResult(): bool { if (!$this->hasCacheResult()) { throw new Exception; } return $this->cacheResult; } /** * @psalm-assert-if-true !null $this->cacheResultFile * * @deprecated */ public function hasCacheResultFile(): bool { return $this->cacheResultFile !== null; } /** * @throws Exception * * @deprecated */ public function cacheResultFile(): string { if (!$this->hasCacheResultFile()) { throw new Exception; } return $this->cacheResultFile; } public function checkVersion(): bool { return $this->checkVersion; } /** * @psalm-assert-if-true !null $this->colors */ public function hasColors(): bool { return $this->colors !== null; } /** * @throws Exception */ public function colors(): string { if (!$this->hasColors()) { throw new Exception; } return $this->colors; } /** * @psalm-assert-if-true !null $this->columns */ public function hasColumns(): bool { return $this->columns !== null; } /** * @throws Exception */ public function columns(): int|string { if (!$this->hasColumns()) { throw new Exception; } return $this->columns; } /** * @psalm-assert-if-true !null $this->configurationFile */ public function hasConfigurationFile(): bool { return $this->configurationFile !== null; } /** * @throws Exception */ public function configurationFile(): string { if (!$this->hasConfigurationFile()) { throw new Exception; } return $this->configurationFile; } /** * @psalm-assert-if-true !null $this->coverageFilter */ public function hasCoverageFilter(): bool { return $this->coverageFilter !== null; } /** * @throws Exception */ public function coverageFilter(): array { if (!$this->hasCoverageFilter()) { throw new Exception; } return $this->coverageFilter; } /** * @psalm-assert-if-true !null $this->coverageClover */ public function hasCoverageClover(): bool { return $this->coverageClover !== null; } /** * @throws Exception */ public function coverageClover(): string { if (!$this->hasCoverageClover()) { throw new Exception; } return $this->coverageClover; } /** * @psalm-assert-if-true !null $this->coverageCobertura */ public function hasCoverageCobertura(): bool { return $this->coverageCobertura !== null; } /** * @throws Exception */ public function coverageCobertura(): string { if (!$this->hasCoverageCobertura()) { throw new Exception; } return $this->coverageCobertura; } /** * @psalm-assert-if-true !null $this->coverageCrap4J */ public function hasCoverageCrap4J(): bool { return $this->coverageCrap4J !== null; } /** * @throws Exception */ public function coverageCrap4J(): string { if (!$this->hasCoverageCrap4J()) { throw new Exception; } return $this->coverageCrap4J; } /** * @psalm-assert-if-true !null $this->coverageHtml */ public function hasCoverageHtml(): bool { return $this->coverageHtml !== null; } /** * @throws Exception */ public function coverageHtml(): string { if (!$this->hasCoverageHtml()) { throw new Exception; } return $this->coverageHtml; } /** * @psalm-assert-if-true !null $this->coveragePhp */ public function hasCoveragePhp(): bool { return $this->coveragePhp !== null; } /** * @throws Exception */ public function coveragePhp(): string { if (!$this->hasCoveragePhp()) { throw new Exception; } return $this->coveragePhp; } /** * @psalm-assert-if-true !null $this->coverageText */ public function hasCoverageText(): bool { return $this->coverageText !== null; } /** * @throws Exception */ public function coverageText(): string { if (!$this->hasCoverageText()) { throw new Exception; } return $this->coverageText; } /** * @psalm-assert-if-true !null $this->coverageTextShowUncoveredFiles */ public function hasCoverageTextShowUncoveredFiles(): bool { return $this->coverageTextShowUncoveredFiles !== null; } /** * @throws Exception */ public function coverageTextShowUncoveredFiles(): bool { if (!$this->hasCoverageTextShowUncoveredFiles()) { throw new Exception; } return $this->coverageTextShowUncoveredFiles; } /** * @psalm-assert-if-true !null $this->coverageTextShowOnlySummary */ public function hasCoverageTextShowOnlySummary(): bool { return $this->coverageTextShowOnlySummary !== null; } /** * @throws Exception */ public function coverageTextShowOnlySummary(): bool { if (!$this->hasCoverageTextShowOnlySummary()) { throw new Exception; } return $this->coverageTextShowOnlySummary; } /** * @psalm-assert-if-true !null $this->coverageXml */ public function hasCoverageXml(): bool { return $this->coverageXml !== null; } /** * @throws Exception */ public function coverageXml(): string { if (!$this->hasCoverageXml()) { throw new Exception; } return $this->coverageXml; } /** * @psalm-assert-if-true !null $this->pathCoverage */ public function hasPathCoverage(): bool { return $this->pathCoverage !== null; } /** * @throws Exception */ public function pathCoverage(): bool { if (!$this->hasPathCoverage()) { throw new Exception; } return $this->pathCoverage; } /** * @psalm-assert-if-true !null $this->coverageCacheDirectory * * @deprecated */ public function hasCoverageCacheDirectory(): bool { return $this->coverageCacheDirectory !== null; } /** * @throws Exception * * @deprecated */ public function coverageCacheDirectory(): string { if (!$this->hasCoverageCacheDirectory()) { throw new Exception; } return $this->coverageCacheDirectory; } public function warmCoverageCache(): bool { return $this->warmCoverageCache; } /** * @psalm-assert-if-true !null $this->defaultTimeLimit */ public function hasDefaultTimeLimit(): bool { return $this->defaultTimeLimit !== null; } /** * @throws Exception */ public function defaultTimeLimit(): int { if (!$this->hasDefaultTimeLimit()) { throw new Exception; } return $this->defaultTimeLimit; } /** * @psalm-assert-if-true !null $this->disableCodeCoverageIgnore */ public function hasDisableCodeCoverageIgnore(): bool { return $this->disableCodeCoverageIgnore !== null; } /** * @throws Exception */ public function disableCodeCoverageIgnore(): bool { if (!$this->hasDisableCodeCoverageIgnore()) { throw new Exception; } return $this->disableCodeCoverageIgnore; } /** * @psalm-assert-if-true !null $this->disallowTestOutput */ public function hasDisallowTestOutput(): bool { return $this->disallowTestOutput !== null; } /** * @throws Exception */ public function disallowTestOutput(): bool { if (!$this->hasDisallowTestOutput()) { throw new Exception; } return $this->disallowTestOutput; } /** * @psalm-assert-if-true !null $this->enforceTimeLimit */ public function hasEnforceTimeLimit(): bool { return $this->enforceTimeLimit !== null; } /** * @throws Exception */ public function enforceTimeLimit(): bool { if (!$this->hasEnforceTimeLimit()) { throw new Exception; } return $this->enforceTimeLimit; } /** * @psalm-assert-if-true !null $this->excludeGroups */ public function hasExcludeGroups(): bool { return $this->excludeGroups !== null; } /** * @throws Exception */ public function excludeGroups(): array { if (!$this->hasExcludeGroups()) { throw new Exception; } return $this->excludeGroups; } /** * @psalm-assert-if-true !null $this->executionOrder */ public function hasExecutionOrder(): bool { return $this->executionOrder !== null; } /** * @throws Exception */ public function executionOrder(): int { if (!$this->hasExecutionOrder()) { throw new Exception; } return $this->executionOrder; } /** * @psalm-assert-if-true !null $this->executionOrderDefects */ public function hasExecutionOrderDefects(): bool { return $this->executionOrderDefects !== null; } /** * @throws Exception */ public function executionOrderDefects(): int { if (!$this->hasExecutionOrderDefects()) { throw new Exception; } return $this->executionOrderDefects; } /** * @psalm-assert-if-true !null $this->failOnDeprecation */ public function hasFailOnDeprecation(): bool { return $this->failOnDeprecation !== null; } /** * @throws Exception */ public function failOnDeprecation(): bool { if (!$this->hasFailOnDeprecation()) { throw new Exception; } return $this->failOnDeprecation; } /** * @psalm-assert-if-true !null $this->failOnEmptyTestSuite */ public function hasFailOnEmptyTestSuite(): bool { return $this->failOnEmptyTestSuite !== null; } /** * @throws Exception */ public function failOnEmptyTestSuite(): bool { if (!$this->hasFailOnEmptyTestSuite()) { throw new Exception; } return $this->failOnEmptyTestSuite; } /** * @psalm-assert-if-true !null $this->failOnIncomplete */ public function hasFailOnIncomplete(): bool { return $this->failOnIncomplete !== null; } /** * @throws Exception */ public function failOnIncomplete(): bool { if (!$this->hasFailOnIncomplete()) { throw new Exception; } return $this->failOnIncomplete; } /** * @psalm-assert-if-true !null $this->failOnNotice */ public function hasFailOnNotice(): bool { return $this->failOnNotice !== null; } /** * @throws Exception */ public function failOnNotice(): bool { if (!$this->hasFailOnNotice()) { throw new Exception; } return $this->failOnNotice; } /** * @psalm-assert-if-true !null $this->failOnRisky */ public function hasFailOnRisky(): bool { return $this->failOnRisky !== null; } /** * @throws Exception */ public function failOnRisky(): bool { if (!$this->hasFailOnRisky()) { throw new Exception; } return $this->failOnRisky; } /** * @psalm-assert-if-true !null $this->failOnSkipped */ public function hasFailOnSkipped(): bool { return $this->failOnSkipped !== null; } /** * @throws Exception */ public function failOnSkipped(): bool { if (!$this->hasFailOnSkipped()) { throw new Exception; } return $this->failOnSkipped; } /** * @psalm-assert-if-true !null $this->failOnWarning */ public function hasFailOnWarning(): bool { return $this->failOnWarning !== null; } /** * @throws Exception */ public function failOnWarning(): bool { if (!$this->hasFailOnWarning()) { throw new Exception; } return $this->failOnWarning; } /** * @psalm-assert-if-true !null $this->stopOnDefect */ public function hasStopOnDefect(): bool { return $this->stopOnDefect !== null; } /** * @throws Exception */ public function stopOnDefect(): bool { if (!$this->hasStopOnDefect()) { throw new Exception; } return $this->stopOnDefect; } /** * @psalm-assert-if-true !null $this->stopOnDeprecation */ public function hasStopOnDeprecation(): bool { return $this->stopOnDeprecation !== null; } /** * @throws Exception */ public function stopOnDeprecation(): bool { if (!$this->hasStopOnDeprecation()) { throw new Exception; } return $this->stopOnDeprecation; } /** * @psalm-assert-if-true !null $this->stopOnError */ public function hasStopOnError(): bool { return $this->stopOnError !== null; } /** * @throws Exception */ public function stopOnError(): bool { if (!$this->hasStopOnError()) { throw new Exception; } return $this->stopOnError; } /** * @psalm-assert-if-true !null $this->stopOnFailure */ public function hasStopOnFailure(): bool { return $this->stopOnFailure !== null; } /** * @throws Exception */ public function stopOnFailure(): bool { if (!$this->hasStopOnFailure()) { throw new Exception; } return $this->stopOnFailure; } /** * @psalm-assert-if-true !null $this->stopOnIncomplete */ public function hasStopOnIncomplete(): bool { return $this->stopOnIncomplete !== null; } /** * @throws Exception */ public function stopOnIncomplete(): bool { if (!$this->hasStopOnIncomplete()) { throw new Exception; } return $this->stopOnIncomplete; } /** * @psalm-assert-if-true !null $this->stopOnNotice */ public function hasStopOnNotice(): bool { return $this->stopOnNotice !== null; } /** * @throws Exception */ public function stopOnNotice(): bool { if (!$this->hasStopOnNotice()) { throw new Exception; } return $this->stopOnNotice; } /** * @psalm-assert-if-true !null $this->stopOnRisky */ public function hasStopOnRisky(): bool { return $this->stopOnRisky !== null; } /** * @throws Exception */ public function stopOnRisky(): bool { if (!$this->hasStopOnRisky()) { throw new Exception; } return $this->stopOnRisky; } /** * @psalm-assert-if-true !null $this->stopOnSkipped */ public function hasStopOnSkipped(): bool { return $this->stopOnSkipped !== null; } /** * @throws Exception */ public function stopOnSkipped(): bool { if (!$this->hasStopOnSkipped()) { throw new Exception; } return $this->stopOnSkipped; } /** * @psalm-assert-if-true !null $this->stopOnWarning */ public function hasStopOnWarning(): bool { return $this->stopOnWarning !== null; } /** * @throws Exception */ public function stopOnWarning(): bool { if (!$this->hasStopOnWarning()) { throw new Exception; } return $this->stopOnWarning; } /** * @psalm-assert-if-true !null $this->filter */ public function hasFilter(): bool { return $this->filter !== null; } /** * @throws Exception */ public function filter(): string { if (!$this->hasFilter()) { throw new Exception; } return $this->filter; } /** * @psalm-assert-if-true !null $this->generateBaseline */ public function hasGenerateBaseline(): bool { return $this->generateBaseline !== null; } /** * @throws Exception */ public function generateBaseline(): string { if (!$this->hasGenerateBaseline()) { throw new Exception; } return $this->generateBaseline; } /** * @psalm-assert-if-true !null $this->useBaseline */ public function hasUseBaseline(): bool { return $this->useBaseline !== null; } /** * @throws Exception */ public function useBaseline(): string { if (!$this->hasUseBaseline()) { throw new Exception; } return $this->useBaseline; } public function ignoreBaseline(): bool { return $this->ignoreBaseline; } public function generateConfiguration(): bool { return $this->generateConfiguration; } public function migrateConfiguration(): bool { return $this->migrateConfiguration; } /** * @psalm-assert-if-true !null $this->groups */ public function hasGroups(): bool { return $this->groups !== null; } /** * @throws Exception */ public function groups(): array { if (!$this->hasGroups()) { throw new Exception; } return $this->groups; } /** * @psalm-assert-if-true !null $this->testsCovering */ public function hasTestsCovering(): bool { return $this->testsCovering !== null; } /** * @throws Exception */ public function testsCovering(): array { if (!$this->hasTestsCovering()) { throw new Exception; } return $this->testsCovering; } /** * @psalm-assert-if-true !null $this->testsUsing */ public function hasTestsUsing(): bool { return $this->testsUsing !== null; } /** * @throws Exception */ public function testsUsing(): array { if (!$this->hasTestsUsing()) { throw new Exception; } return $this->testsUsing; } public function help(): bool { return $this->help; } /** * @psalm-assert-if-true !null $this->includePath */ public function hasIncludePath(): bool { return $this->includePath !== null; } /** * @throws Exception */ public function includePath(): string { if (!$this->hasIncludePath()) { throw new Exception; } return $this->includePath; } /** * @psalm-assert-if-true !null $this->iniSettings */ public function hasIniSettings(): bool { return $this->iniSettings !== null; } /** * @throws Exception */ public function iniSettings(): array { if (!$this->hasIniSettings()) { throw new Exception; } return $this->iniSettings; } /** * @psalm-assert-if-true !null $this->junitLogfile */ public function hasJunitLogfile(): bool { return $this->junitLogfile !== null; } /** * @throws Exception */ public function junitLogfile(): string { if (!$this->hasJunitLogfile()) { throw new Exception; } return $this->junitLogfile; } public function listGroups(): bool { return $this->listGroups; } public function listSuites(): bool { return $this->listSuites; } public function listTests(): bool { return $this->listTests; } /** * @psalm-assert-if-true !null $this->listTestsXml */ public function hasListTestsXml(): bool { return $this->listTestsXml !== null; } /** * @throws Exception */ public function listTestsXml(): string { if (!$this->hasListTestsXml()) { throw new Exception; } return $this->listTestsXml; } /** * @psalm-assert-if-true !null $this->noCoverage */ public function hasNoCoverage(): bool { return $this->noCoverage !== null; } /** * @throws Exception */ public function noCoverage(): bool { if (!$this->hasNoCoverage()) { throw new Exception; } return $this->noCoverage; } /** * @psalm-assert-if-true !null $this->noExtensions */ public function hasNoExtensions(): bool { return $this->noExtensions !== null; } /** * @throws Exception */ public function noExtensions(): bool { if (!$this->hasNoExtensions()) { throw new Exception; } return $this->noExtensions; } /** * @psalm-assert-if-true !null $this->noOutput */ public function hasNoOutput(): bool { return $this->noOutput !== null; } /** * @throws Exception */ public function noOutput(): bool { if ($this->noOutput === null) { throw new Exception; } return $this->noOutput; } /** * @psalm-assert-if-true !null $this->noProgress */ public function hasNoProgress(): bool { return $this->noProgress !== null; } /** * @throws Exception */ public function noProgress(): bool { if ($this->noProgress === null) { throw new Exception; } return $this->noProgress; } /** * @psalm-assert-if-true !null $this->noResults */ public function hasNoResults(): bool { return $this->noResults !== null; } /** * @throws Exception */ public function noResults(): bool { if ($this->noResults === null) { throw new Exception; } return $this->noResults; } /** * @psalm-assert-if-true !null $this->noLogging */ public function hasNoLogging(): bool { return $this->noLogging !== null; } /** * @throws Exception */ public function noLogging(): bool { if (!$this->hasNoLogging()) { throw new Exception; } return $this->noLogging; } /** * @psalm-assert-if-true !null $this->processIsolation */ public function hasProcessIsolation(): bool { return $this->processIsolation !== null; } /** * @throws Exception */ public function processIsolation(): bool { if (!$this->hasProcessIsolation()) { throw new Exception; } return $this->processIsolation; } /** * @psalm-assert-if-true !null $this->randomOrderSeed */ public function hasRandomOrderSeed(): bool { return $this->randomOrderSeed !== null; } /** * @throws Exception */ public function randomOrderSeed(): int { if (!$this->hasRandomOrderSeed()) { throw new Exception; } return $this->randomOrderSeed; } /** * @psalm-assert-if-true !null $this->reportUselessTests */ public function hasReportUselessTests(): bool { return $this->reportUselessTests !== null; } /** * @throws Exception */ public function reportUselessTests(): bool { if (!$this->hasReportUselessTests()) { throw new Exception; } return $this->reportUselessTests; } /** * @psalm-assert-if-true !null $this->resolveDependencies */ public function hasResolveDependencies(): bool { return $this->resolveDependencies !== null; } /** * @throws Exception */ public function resolveDependencies(): bool { if (!$this->hasResolveDependencies()) { throw new Exception; } return $this->resolveDependencies; } /** * @psalm-assert-if-true !null $this->reverseList */ public function hasReverseList(): bool { return $this->reverseList !== null; } /** * @throws Exception */ public function reverseList(): bool { if (!$this->hasReverseList()) { throw new Exception; } return $this->reverseList; } /** * @psalm-assert-if-true !null $this->stderr */ public function hasStderr(): bool { return $this->stderr !== null; } /** * @throws Exception */ public function stderr(): bool { if (!$this->hasStderr()) { throw new Exception; } return $this->stderr; } /** * @psalm-assert-if-true !null $this->strictCoverage */ public function hasStrictCoverage(): bool { return $this->strictCoverage !== null; } /** * @throws Exception */ public function strictCoverage(): bool { if (!$this->hasStrictCoverage()) { throw new Exception; } return $this->strictCoverage; } /** * @psalm-assert-if-true !null $this->teamcityLogfile */ public function hasTeamcityLogfile(): bool { return $this->teamcityLogfile !== null; } /** * @throws Exception */ public function teamcityLogfile(): string { if (!$this->hasTeamcityLogfile()) { throw new Exception; } return $this->teamcityLogfile; } /** * @psalm-assert-if-true !null $this->teamcityPrinter */ public function hasTeamCityPrinter(): bool { return $this->teamCityPrinter !== null; } /** * @throws Exception */ public function teamCityPrinter(): bool { if (!$this->hasTeamCityPrinter()) { throw new Exception; } return $this->teamCityPrinter; } /** * @psalm-assert-if-true !null $this->testdoxHtmlFile */ public function hasTestdoxHtmlFile(): bool { return $this->testdoxHtmlFile !== null; } /** * @throws Exception */ public function testdoxHtmlFile(): string { if (!$this->hasTestdoxHtmlFile()) { throw new Exception; } return $this->testdoxHtmlFile; } /** * @psalm-assert-if-true !null $this->testdoxTextFile */ public function hasTestdoxTextFile(): bool { return $this->testdoxTextFile !== null; } /** * @throws Exception */ public function testdoxTextFile(): string { if (!$this->hasTestdoxTextFile()) { throw new Exception; } return $this->testdoxTextFile; } /** * @psalm-assert-if-true !null $this->testdoxPrinter */ public function hasTestDoxPrinter(): bool { return $this->testdoxPrinter !== null; } /** * @throws Exception */ public function testdoxPrinter(): bool { if (!$this->hasTestdoxPrinter()) { throw new Exception; } return $this->testdoxPrinter; } /** * @psalm-assert-if-true !null $this->testSuffixes */ public function hasTestSuffixes(): bool { return $this->testSuffixes !== null; } /** * @psalm-return non-empty-list<non-empty-string> * * @throws Exception */ public function testSuffixes(): array { if (!$this->hasTestSuffixes()) { throw new Exception; } return $this->testSuffixes; } /** * @psalm-assert-if-true !null $this->testSuite */ public function hasTestSuite(): bool { return $this->testSuite !== null; } /** * @throws Exception */ public function testSuite(): string { if (!$this->hasTestSuite()) { throw new Exception; } return $this->testSuite; } /** * @psalm-assert-if-true !null $this->excludedTestSuite */ public function hasExcludedTestSuite(): bool { return $this->excludeTestSuite !== null; } /** * @throws Exception */ public function excludedTestSuite(): string { if (!$this->hasExcludedTestSuite()) { throw new Exception; } return $this->excludeTestSuite; } public function useDefaultConfiguration(): bool { return $this->useDefaultConfiguration; } /** * @psalm-assert-if-true !null $this->displayDetailsOnIncompleteTests */ public function hasDisplayDetailsOnIncompleteTests(): bool { return $this->displayDetailsOnIncompleteTests !== null; } /** * @throws Exception */ public function displayDetailsOnIncompleteTests(): bool { if (!$this->hasDisplayDetailsOnIncompleteTests()) { throw new Exception; } return $this->displayDetailsOnIncompleteTests; } /** * @psalm-assert-if-true !null $this->displayDetailsOnSkippedTests */ public function hasDisplayDetailsOnSkippedTests(): bool { return $this->displayDetailsOnSkippedTests !== null; } /** * @throws Exception */ public function displayDetailsOnSkippedTests(): bool { if (!$this->hasDisplayDetailsOnSkippedTests()) { throw new Exception; } return $this->displayDetailsOnSkippedTests; } /** * @psalm-assert-if-true !null $this->displayDetailsOnTestsThatTriggerDeprecations */ public function hasDisplayDetailsOnTestsThatTriggerDeprecations(): bool { return $this->displayDetailsOnTestsThatTriggerDeprecations !== null; } /** * @throws Exception */ public function displayDetailsOnTestsThatTriggerDeprecations(): bool { if (!$this->hasDisplayDetailsOnTestsThatTriggerDeprecations()) { throw new Exception; } return $this->displayDetailsOnTestsThatTriggerDeprecations; } /** * @psalm-assert-if-true !null $this->displayDetailsOnTestsThatTriggerErrors */ public function hasDisplayDetailsOnTestsThatTriggerErrors(): bool { return $this->displayDetailsOnTestsThatTriggerErrors !== null; } /** * @throws Exception */ public function displayDetailsOnTestsThatTriggerErrors(): bool { if (!$this->hasDisplayDetailsOnTestsThatTriggerErrors()) { throw new Exception; } return $this->displayDetailsOnTestsThatTriggerErrors; } /** * @psalm-assert-if-true !null $this->displayDetailsOnTestsThatTriggerNotices */ public function hasDisplayDetailsOnTestsThatTriggerNotices(): bool { return $this->displayDetailsOnTestsThatTriggerNotices !== null; } /** * @throws Exception */ public function displayDetailsOnTestsThatTriggerNotices(): bool { if (!$this->hasDisplayDetailsOnTestsThatTriggerNotices()) { throw new Exception; } return $this->displayDetailsOnTestsThatTriggerNotices; } /** * @psalm-assert-if-true !null $this->displayDetailsOnTestsThatTriggerWarnings */ public function hasDisplayDetailsOnTestsThatTriggerWarnings(): bool { return $this->displayDetailsOnTestsThatTriggerWarnings !== null; } /** * @throws Exception */ public function displayDetailsOnTestsThatTriggerWarnings(): bool { if (!$this->hasDisplayDetailsOnTestsThatTriggerWarnings()) { throw new Exception; } return $this->displayDetailsOnTestsThatTriggerWarnings; } public function version(): bool { return $this->version; } /** * @psalm-assert-if-true !null $this->logEventsText */ public function hasLogEventsText(): bool { return $this->logEventsText !== null; } /** * @throws Exception */ public function logEventsText(): string { if (!$this->hasLogEventsText()) { throw new Exception; } return $this->logEventsText; } /** * @psalm-assert-if-true !null $this->logEventsVerboseText */ public function hasLogEventsVerboseText(): bool { return $this->logEventsVerboseText !== null; } /** * @throws Exception */ public function logEventsVerboseText(): string { if (!$this->hasLogEventsVerboseText()) { throw new Exception; } return $this->logEventsVerboseText; } } Configuration/CodeCoverageFilterRegistry.php 0000644 00000003226 15111303730 0015306 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\TextUI\Configuration; use function array_keys; use function assert; use SebastianBergmann\CodeCoverage\Filter; /** * CLI options and XML configuration are static within a single PHPUnit process. * It is therefore okay to use a Singleton registry here. * * @internal This class is not covered by the backward compatibility promise for PHPUnit */ final class CodeCoverageFilterRegistry { private static ?self $instance = null; private ?Filter $filter = null; private bool $configured = false; public static function instance(): self { if (self::$instance === null) { self::$instance = new self; } return self::$instance; } public function get(): Filter { assert($this->filter !== null); return $this->filter; } public function init(Configuration $configuration, bool $force = false): void { if (!$configuration->hasCoverageReport() && !$force) { return; } if ($this->configured && !$force) { return; } $this->filter = new Filter; if ($configuration->source()->notEmpty()) { $this->filter->includeFiles(array_keys((new SourceMapper)->map($configuration->source()))); $this->configured = true; } } public function configured(): bool { return $this->configured; } } Configuration/Registry.php 0000644 00000006157 15111303730 0011677 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\TextUI\Configuration; use function assert; use function file_get_contents; use function file_put_contents; use function serialize; use function unserialize; use PHPUnit\Event\Facade as EventFacade; use PHPUnit\TextUI\CliArguments\Configuration as CliConfiguration; use PHPUnit\TextUI\XmlConfiguration\Configuration as XmlConfiguration; use PHPUnit\Util\VersionComparisonOperator; /** * CLI options and XML configuration are static within a single PHPUnit process. * It is therefore okay to use a Singleton registry here. * * @internal This class is not covered by the backward compatibility promise for PHPUnit */ final class Registry { private static ?Configuration $instance = null; public static function saveTo(string $path): bool { $result = file_put_contents( $path, serialize(self::get()), ); if ($result) { return true; } return false; } /** * This method is used by the "run test(s) in separate process" templates. * * @noinspection PhpUnused */ public static function loadFrom(string $path): void { self::$instance = unserialize( file_get_contents($path), [ 'allowed_classes' => [ Configuration::class, Php::class, ConstantCollection::class, Constant::class, IniSettingCollection::class, IniSetting::class, VariableCollection::class, Variable::class, DirectoryCollection::class, Directory::class, FileCollection::class, File::class, FilterDirectoryCollection::class, FilterDirectory::class, TestDirectoryCollection::class, TestDirectory::class, TestFileCollection::class, TestFile::class, TestSuiteCollection::class, TestSuite::class, VersionComparisonOperator::class, Source::class, ], ], ); } public static function get(): Configuration { assert(self::$instance instanceof Configuration); return self::$instance; } /** * @throws \PHPUnit\TextUI\CliArguments\Exception * @throws \PHPUnit\TextUI\XmlConfiguration\Exception * @throws NoCustomCssFileException */ public static function init(CliConfiguration $cliConfiguration, XmlConfiguration $xmlConfiguration): Configuration { self::$instance = (new Merger)->merge($cliConfiguration, $xmlConfiguration); EventFacade::emitter()->testRunnerConfigured(self::$instance); return self::$instance; } } Configuration/SourceMapper.php 0000644 00000004624 15111303730 0012471 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\TextUI\Configuration; use function realpath; use SebastianBergmann\FileIterator\Facade as FileIteratorFacade; use SplObjectStorage; /** * @internal This class is not covered by the backward compatibility promise for PHPUnit */ final class SourceMapper { /** * @psalm-var SplObjectStorage<Source, array<non-empty-string, true>> */ private static ?SplObjectStorage $files = null; /** * @psalm-return array<non-empty-string, true> */ public function map(Source $source): array { if (self::$files === null) { self::$files = new SplObjectStorage; } if (isset(self::$files[$source])) { return self::$files[$source]; } $files = []; foreach ($source->includeDirectories() as $directory) { foreach ((new FileIteratorFacade)->getFilesAsArray($directory->path(), $directory->suffix(), $directory->prefix()) as $file) { $file = realpath($file); if (!$file) { continue; } $files[$file] = true; } } foreach ($source->includeFiles() as $file) { $file = realpath($file->path()); if (!$file) { continue; } $files[$file] = true; } foreach ($source->excludeDirectories() as $directory) { foreach ((new FileIteratorFacade)->getFilesAsArray($directory->path(), $directory->suffix(), $directory->prefix()) as $file) { $file = realpath($file); if (!$file) { continue; } if (!isset($files[$file])) { continue; } unset($files[$file]); } } foreach ($source->excludeFiles() as $file) { $file = realpath($file->path()); if (!$file) { continue; } if (!isset($files[$file])) { continue; } unset($files[$file]); } self::$files[$source] = $files; return $files; } } Help.php 0000644 00000034060 15111303730 0006142 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\TextUI; use const PHP_EOL; use function count; use function explode; use function max; use function preg_replace_callback; use function str_pad; use function str_repeat; use function strlen; use function wordwrap; use PHPUnit\Util\Color; use SebastianBergmann\Environment\Console; /** * @internal This class is not covered by the backward compatibility promise for PHPUnit */ final class Help { private const LEFT_MARGIN = ' '; private const HELP_TEXT = [ 'Usage' => [ ['text' => 'phpunit [options] <directory|file> ...'], ], 'Configuration' => [ ['arg' => '--bootstrap <file>', 'desc' => 'A PHP script that is included before the tests run'], ['arg' => '-c|--configuration <file>', 'desc' => 'Read configuration from XML file'], ['arg' => '--no-configuration', 'desc' => 'Ignore default configuration file (phpunit.xml)'], ['arg' => '--no-extensions', 'desc' => 'Do not load PHPUnit extensions'], ['arg' => '--include-path <path(s)>', 'desc' => 'Prepend PHP\'s include_path with given path(s)'], ['arg' => '-d <key[=value]>', 'desc' => 'Sets a php.ini value'], ['arg' => '--cache-directory <dir>', 'desc' => 'Specify cache directory'], ['arg' => '--generate-configuration', 'desc' => 'Generate configuration file with suggested settings'], ['arg' => '--migrate-configuration', 'desc' => 'Migrate configuration file to current format'], ['arg' => '--generate-baseline <file>', 'desc' => 'Generate baseline for issues'], ['arg' => '--use-baseline <file>', 'desc' => 'Use baseline to ignore issues'], ['arg' => '--ignore-baseline', 'desc' => 'Do not use baseline to ignore issues'], ], 'Selection' => [ ['arg' => '--list-suites', 'desc' => 'List available test suites'], ['arg' => '--testsuite <name>', 'desc' => 'Only run tests from the specified test suite(s)'], ['arg' => '--exclude-testsuite <name>', 'desc' => 'Exclude tests from the specified test suite(s)'], ['arg' => '--list-groups', 'desc' => 'List available test groups'], ['arg' => '--group <name>', 'desc' => 'Only run tests from the specified group(s)'], ['arg' => '--exclude-group <name>', 'desc' => 'Exclude tests from the specified group(s)'], ['arg' => '--covers <name>', 'desc' => 'Only run tests that intend to cover <name>'], ['arg' => '--uses <name>', 'desc' => 'Only run tests that intend to use <name>'], ['arg' => '--list-tests', 'desc' => 'List available tests'], ['arg' => '--list-tests-xml <file>', 'desc' => 'List available tests in XML format'], ['arg' => '--filter <pattern>', 'desc' => 'Filter which tests to run'], ['arg' => '--test-suffix <suffixes>', 'desc' => 'Only search for test in files with specified suffix(es). Default: Test.php,.phpt'], ], 'Execution' => [ ['arg' => '--process-isolation', 'desc' => 'Run each test in a separate PHP process'], ['arg' => '--globals-backup', 'desc' => 'Backup and restore $GLOBALS for each test'], ['arg' => '--static-backup', 'desc' => 'Backup and restore static properties for each test'], ['spacer' => ''], ['arg' => '--strict-coverage', 'desc' => 'Be strict about code coverage metadata'], ['arg' => '--strict-global-state', 'desc' => 'Be strict about changes to global state'], ['arg' => '--disallow-test-output', 'desc' => 'Be strict about output during tests'], ['arg' => '--enforce-time-limit', 'desc' => 'Enforce time limit based on test size'], ['arg' => '--default-time-limit <sec>', 'desc' => 'Timeout in seconds for tests that have no declared size'], ['arg' => '--dont-report-useless-tests', 'desc' => 'Do not report tests that do not test anything'], ['spacer' => ''], ['arg' => '--stop-on-defect', 'desc' => 'Stop after first error, failure, warning, or risky test'], ['arg' => '--stop-on-error', 'desc' => 'Stop after first error'], ['arg' => '--stop-on-failure', 'desc' => 'Stop after first failure'], ['arg' => '--stop-on-warning', 'desc' => 'Stop after first warning'], ['arg' => '--stop-on-risky', 'desc' => 'Stop after first risky test'], ['arg' => '--stop-on-deprecation', 'desc' => 'Stop after first test that triggered a deprecation'], ['arg' => '--stop-on-notice', 'desc' => 'Stop after first test that triggered a notice'], ['arg' => '--stop-on-skipped', 'desc' => 'Stop after first skipped test'], ['arg' => '--stop-on-incomplete', 'desc' => 'Stop after first incomplete test'], ['spacer' => ''], ['arg' => '--fail-on-warning', 'desc' => 'Signal failure using shell exit code when a warning was triggered'], ['arg' => '--fail-on-risky', 'desc' => 'Signal failure using shell exit code when a test was considered risky'], ['arg' => '--fail-on-deprecation', 'desc' => 'Signal failure using shell exit code when a deprecation was triggered'], ['arg' => '--fail-on-notice', 'desc' => 'Signal failure using shell exit code when a notice was triggered'], ['arg' => '--fail-on-skipped', 'desc' => 'Signal failure using shell exit code when a test was skipped'], ['arg' => '--fail-on-incomplete', 'desc' => 'Signal failure using shell exit code when a test was marked incomplete'], ['spacer' => ''], ['arg' => '--cache-result', 'desc' => 'Write test results to cache file'], ['arg' => '--do-not-cache-result', 'desc' => 'Do not write test results to cache file'], ['spacer' => ''], ['arg' => '--order-by <order>', 'desc' => 'Run tests in order: default|defects|depends|duration|no-depends|random|reverse|size'], ['arg' => '--random-order-seed <N>', 'desc' => 'Use the specified random seed when running tests in random order'], ], 'Reporting' => [ ['arg' => '--colors <flag>', 'desc' => 'Use colors in output ("never", "auto" or "always")'], ['arg' => '--columns <n>', 'desc' => 'Number of columns to use for progress output'], ['arg' => '--columns max', 'desc' => 'Use maximum number of columns for progress output'], ['arg' => '--stderr', 'desc' => 'Write to STDERR instead of STDOUT'], ['spacer' => ''], ['arg' => '--no-progress', 'desc' => 'Disable output of test execution progress'], ['arg' => '--no-results', 'desc' => 'Disable output of test results'], ['arg' => '--no-output', 'desc' => 'Disable all output'], ['spacer' => ''], ['arg' => '--display-incomplete', 'desc' => 'Display details for incomplete tests'], ['arg' => '--display-skipped', 'desc' => 'Display details for skipped tests'], ['arg' => '--display-deprecations', 'desc' => 'Display details for deprecations triggered by tests'], ['arg' => '--display-errors', 'desc' => 'Display details for errors triggered by tests'], ['arg' => '--display-notices', 'desc' => 'Display details for notices triggered by tests'], ['arg' => '--display-warnings', 'desc' => 'Display details for warnings triggered by tests'], ['arg' => '--reverse-list', 'desc' => 'Print defects in reverse order'], ['spacer' => ''], ['arg' => '--teamcity', 'desc' => 'Replace default progress and result output with TeamCity format'], ['arg' => '--testdox', 'desc' => 'Replace default result output with TestDox format'], ], 'Logging' => [ ['arg' => '--log-junit <file>', 'desc' => 'Write test results in JUnit XML format to file'], ['arg' => '--log-teamcity <file>', 'desc' => 'Write test results in TeamCity format to file'], ['arg' => '--testdox-html <file>', 'desc' => 'Write test results in TestDox format (HTML) to file'], ['arg' => '--testdox-text <file>', 'desc' => 'Write test results in TestDox format (plain text) to file'], ['arg' => '--log-events-text <file>', 'desc' => 'Stream events as plain text to file'], ['arg' => '--log-events-verbose-text <file>', 'desc' => 'Stream events as plain text with extended information to file'], ['arg' => '--no-logging', 'desc' => 'Ignore logging configured in the XML configuration file'], ], 'Code Coverage' => [ ['arg' => '--coverage-clover <file>', 'desc' => 'Write code coverage report in Clover XML format to file'], ['arg' => '--coverage-cobertura <file>', 'desc' => 'Write code coverage report in Cobertura XML format to file'], ['arg' => '--coverage-crap4j <file>', 'desc' => 'Write code coverage report in Crap4J XML format to file'], ['arg' => '--coverage-html <dir>', 'desc' => 'Write code coverage report in HTML format to directory'], ['arg' => '--coverage-php <file>', 'desc' => 'Write serialized code coverage data to file'], ['arg' => '--coverage-text=<file>', 'desc' => 'Write code coverage report in text format to file [default: standard output]'], ['arg' => '--coverage-xml <dir>', 'desc' => 'Write code coverage report in XML format to directory'], ['arg' => '--warm-coverage-cache', 'desc' => 'Warm static analysis cache'], ['arg' => '--coverage-filter <dir>', 'desc' => 'Include <dir> in code coverage reporting'], ['arg' => '--path-coverage', 'desc' => 'Report path coverage in addition to line coverage'], ['arg' => '--disable-coverage-ignore', 'desc' => 'Disable metadata for ignoring code coverage'], ['arg' => '--no-coverage', 'desc' => 'Ignore code coverage reporting configured in the XML configuration file'], ], 'Miscellaneous' => [ ['arg' => '-h|--help', 'desc' => 'Prints this usage information'], ['arg' => '--version', 'desc' => 'Prints the version and exits'], ['arg' => '--atleast-version <min>', 'desc' => 'Checks that version is greater than <min> and exits'], ['arg' => '--check-version', 'desc' => 'Check whether PHPUnit is the latest version and exits'], ], ]; private int $lengthOfLongestOptionName = 0; private readonly int $columnsAvailableForDescription; private ?bool $hasColor; public function __construct(?int $width = null, ?bool $withColor = null) { if ($width === null) { $width = (new Console)->getNumberOfColumns(); } if ($withColor === null) { $this->hasColor = (new Console)->hasColorSupport(); } else { $this->hasColor = $withColor; } foreach (self::HELP_TEXT as $options) { foreach ($options as $option) { if (isset($option['arg'])) { $this->lengthOfLongestOptionName = max($this->lengthOfLongestOptionName, isset($option['arg']) ? strlen($option['arg']) : 0); } } } $this->columnsAvailableForDescription = $width - $this->lengthOfLongestOptionName - 4; } public function generate(): string { if ($this->hasColor) { return $this->writeWithColor(); } return $this->writeWithoutColor(); } private function writeWithoutColor(): string { $buffer = ''; foreach (self::HELP_TEXT as $section => $options) { $buffer .= "{$section}:" . PHP_EOL; if ($section !== 'Usage') { $buffer .= PHP_EOL; } foreach ($options as $option) { if (isset($option['spacer'])) { $buffer .= PHP_EOL; } if (isset($option['text'])) { $buffer .= self::LEFT_MARGIN . $option['text'] . PHP_EOL; } if (isset($option['arg'])) { $arg = str_pad($option['arg'], $this->lengthOfLongestOptionName); $buffer .= self::LEFT_MARGIN . $arg . ' ' . $option['desc'] . PHP_EOL; } } $buffer .= PHP_EOL; } return $buffer; } private function writeWithColor(): string { $buffer = ''; foreach (self::HELP_TEXT as $section => $options) { $buffer .= Color::colorize('fg-yellow', "{$section}:") . PHP_EOL; if ($section !== 'Usage') { $buffer .= PHP_EOL; } foreach ($options as $option) { if (isset($option['spacer'])) { $buffer .= PHP_EOL; } if (isset($option['text'])) { $buffer .= self::LEFT_MARGIN . $option['text'] . PHP_EOL; } if (isset($option['arg'])) { $arg = Color::colorize('fg-green', str_pad($option['arg'], $this->lengthOfLongestOptionName)); $arg = preg_replace_callback( '/(<[^>]+>)/', static fn ($matches) => Color::colorize('fg-cyan', $matches[0]), $arg, ); $desc = explode(PHP_EOL, wordwrap($option['desc'], $this->columnsAvailableForDescription, PHP_EOL)); $buffer .= self::LEFT_MARGIN . $arg . ' ' . $desc[0] . PHP_EOL; for ($i = 1; $i < count($desc); $i++) { $buffer .= str_repeat(' ', $this->lengthOfLongestOptionName + 3) . $desc[$i] . PHP_EOL; } } } $buffer .= PHP_EOL; } return $buffer; } } Command/Result.php 0000644 00000002161 15111303730 0010103 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\TextUI\Command; /** * @psalm-immutable * * @internal This class is not covered by the backward compatibility promise for PHPUnit */ final class Result { public const SUCCESS = 0; public const FAILURE = 1; public const EXCEPTION = 2; public const CRASH = 255; private readonly string $output; private readonly int $shellExitCode; public static function from(string $output = '', int $shellExitCode = self::SUCCESS): self { return new self($output, $shellExitCode); } private function __construct(string $output, int $shellExitCode) { $this->output = $output; $this->shellExitCode = $shellExitCode; } public function output(): string { return $this->output; } public function shellExitCode(): int { return $this->shellExitCode; } } Command/Commands/ShowVersionCommand.php 0000644 00000001010 15111303730 0014143 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\TextUI\Command; /** * @internal This class is not covered by the backward compatibility promise for PHPUnit */ final class ShowVersionCommand implements Command { public function execute(): Result { return Result::from(); } } Command/Commands/ListTestSuitesCommand.php 0000644 00000003776 15111303730 0014652 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\TextUI\Command; use function sprintf; use PHPUnit\TextUI\Configuration\Registry; use PHPUnit\TextUI\Configuration\TestSuiteCollection; /** * @internal This class is not covered by the backward compatibility promise for PHPUnit */ final class ListTestSuitesCommand implements Command { private readonly TestSuiteCollection $suites; public function __construct(TestSuiteCollection $suites) { $this->suites = $suites; } public function execute(): Result { $buffer = $this->warnAboutConflictingOptions(); $buffer .= 'Available test suite(s):' . PHP_EOL; foreach ($this->suites as $suite) { $buffer .= sprintf( ' - %s' . PHP_EOL, $suite->name(), ); } return Result::from($buffer); } private function warnAboutConflictingOptions(): string { $buffer = ''; $configuration = Registry::get(); if ($configuration->hasFilter()) { $buffer .= 'The --filter and --list-suites options cannot be combined, --filter is ignored' . PHP_EOL; } if ($configuration->hasGroups()) { $buffer .= 'The --group and --list-suites options cannot be combined, --group is ignored' . PHP_EOL; } if ($configuration->hasExcludeGroups()) { $buffer .= 'The --exclude-group and --list-suites options cannot be combined, --exclude-group is ignored' . PHP_EOL; } if ($configuration->includeTestSuite() !== '') { $buffer .= 'The --testsuite and --list-suites options cannot be combined, --exclude-group is ignored' . PHP_EOL; } if (!empty($buffer)) { $buffer .= PHP_EOL; } return $buffer; } } Command/Commands/AtLeastVersionCommand.php 0000644 00000001523 15111303730 0014571 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\TextUI\Command; use function version_compare; use PHPUnit\Runner\Version; /** * @internal This class is not covered by the backward compatibility promise for PHPUnit */ final class AtLeastVersionCommand implements Command { private readonly string $version; public function __construct(string $version) { $this->version = $version; } public function execute(): Result { if (version_compare(Version::id(), $this->version, '>=')) { return Result::from(); } return Result::from('', Result::FAILURE); } } Command/Commands/ListGroupsCommand.php 0000644 00000004224 15111303730 0014002 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\TextUI\Command; use function sort; use function sprintf; use function str_starts_with; use PHPUnit\Framework\TestSuite; use PHPUnit\TextUI\Configuration\Registry; /** * @internal This class is not covered by the backward compatibility promise for PHPUnit */ final class ListGroupsCommand implements Command { private readonly TestSuite $suite; public function __construct(TestSuite $suite) { $this->suite = $suite; } public function execute(): Result { $buffer = $this->warnAboutConflictingOptions(); $buffer .= 'Available test group(s):' . PHP_EOL; $groups = $this->suite->groups(); sort($groups); foreach ($groups as $group) { if (str_starts_with($group, '__phpunit_')) { continue; } $buffer .= sprintf( ' - %s' . PHP_EOL, $group, ); } return Result::from($buffer); } private function warnAboutConflictingOptions(): string { $buffer = ''; $configuration = Registry::get(); if ($configuration->hasFilter()) { $buffer .= 'The --filter and --list-groups options cannot be combined, --filter is ignored' . PHP_EOL; } if ($configuration->hasGroups()) { $buffer .= 'The --group and --list-groups options cannot be combined, --group is ignored' . PHP_EOL; } if ($configuration->hasExcludeGroups()) { $buffer .= 'The --exclude-group and --list-groups options cannot be combined, --exclude-group is ignored' . PHP_EOL; } if ($configuration->includeTestSuite() !== '') { $buffer .= 'The --testsuite and --list-groups options cannot be combined, --exclude-group is ignored' . PHP_EOL; } if (!empty($buffer)) { $buffer .= PHP_EOL; } return $buffer; } } Command/Commands/ShowHelpCommand.php 0000644 00000001410 15111303730 0013412 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\TextUI\Command; use PHPUnit\TextUI\Help; /** * @internal This class is not covered by the backward compatibility promise for PHPUnit */ final class ShowHelpCommand implements Command { private readonly int $shellExitCode; public function __construct(int $shellExitCode) { $this->shellExitCode = $shellExitCode; } public function execute(): Result { return Result::from( (new Help)->generate(), $this->shellExitCode, ); } } Command/Commands/ListTestsAsTextCommand.php 0000644 00000004451 15111303730 0014760 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\TextUI\Command; use function sprintf; use function str_replace; use PHPUnit\Framework\TestCase; use PHPUnit\Framework\TestSuite; use PHPUnit\Runner\PhptTestCase; use PHPUnit\TextUI\Configuration\Registry; use RecursiveIteratorIterator; /** * @internal This class is not covered by the backward compatibility promise for PHPUnit */ final class ListTestsAsTextCommand implements Command { private readonly TestSuite $suite; public function __construct(TestSuite $suite) { $this->suite = $suite; } public function execute(): Result { $buffer = $this->warnAboutConflictingOptions(); $buffer .= 'Available test(s):' . PHP_EOL; foreach (new RecursiveIteratorIterator($this->suite) as $test) { if ($test instanceof TestCase) { $name = sprintf( '%s::%s', $test::class, str_replace(' with data set ', '', $test->nameWithDataSet()), ); } elseif ($test instanceof PhptTestCase) { $name = $test->getName(); } else { continue; } $buffer .= sprintf( ' - %s' . PHP_EOL, $name, ); } return Result::from($buffer); } private function warnAboutConflictingOptions(): string { $buffer = ''; $configuration = Registry::get(); if ($configuration->hasFilter()) { $buffer .= 'The --filter and --list-tests options cannot be combined, --filter is ignored' . PHP_EOL; } if ($configuration->hasGroups()) { $buffer .= 'The --group and --list-tests options cannot be combined, --group is ignored' . PHP_EOL; } if ($configuration->hasExcludeGroups()) { $buffer .= 'The --exclude-group and --list-tests options cannot be combined, --exclude-group is ignored' . PHP_EOL; } if (!empty($buffer)) { $buffer .= PHP_EOL; } return $buffer; } } Command/Commands/MigrateConfigurationCommand.php 0000644 00000002560 15111303730 0016010 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\TextUI\Command; use function copy; use function file_put_contents; use PHPUnit\TextUI\XmlConfiguration\Migrator; use Throwable; /** * @internal This class is not covered by the backward compatibility promise for PHPUnit */ final class MigrateConfigurationCommand implements Command { private readonly string $filename; public function __construct(string $filename) { $this->filename = $filename; } public function execute(): Result { copy($this->filename, $this->filename . '.bak'); $buffer = 'Created backup: ' . $this->filename . '.bak' . PHP_EOL; $shellExitCode = Result::SUCCESS; try { file_put_contents( $this->filename, (new Migrator)->migrate($this->filename), ); $buffer .= 'Migrated configuration: ' . $this->filename . PHP_EOL; } catch (Throwable $t) { $buffer .= 'Migration failed: ' . $t->getMessage() . PHP_EOL; $shellExitCode = Result::FAILURE; } return Result::from($buffer, $shellExitCode); } } Command/Commands/VersionCheckCommand.php 0000644 00000002317 15111303730 0014253 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\TextUI\Command; use function file_get_contents; use function sprintf; use function version_compare; use PHPUnit\Runner\Version; /** * @internal This class is not covered by the backward compatibility promise for PHPUnit * * @codeCoverageIgnore */ final class VersionCheckCommand implements Command { public function execute(): Result { $latestVersion = file_get_contents('https://phar.phpunit.de/latest-version-of/phpunit'); $isOutdated = version_compare($latestVersion, Version::id(), '>'); if ($isOutdated) { return Result::from( sprintf( 'You are not using the latest version of PHPUnit.' . PHP_EOL . 'The latest version is PHPUnit %s.' . PHP_EOL, $latestVersion, ), ); } return Result::from( 'You are using the latest version of PHPUnit.' . PHP_EOL, ); } } Command/Commands/ListTestsAsXmlCommand.php 0000644 00000010122 15111303730 0014564 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\TextUI\Command; use function file_put_contents; use function implode; use function sprintf; use function str_replace; use PHPUnit\Framework\TestCase; use PHPUnit\Framework\TestSuite; use PHPUnit\Runner\PhptTestCase; use PHPUnit\TextUI\Configuration\Registry; use RecursiveIteratorIterator; use XMLWriter; /** * @internal This class is not covered by the backward compatibility promise for PHPUnit */ final class ListTestsAsXmlCommand implements Command { private readonly string $filename; private readonly TestSuite $suite; public function __construct(string $filename, TestSuite $suite) { $this->filename = $filename; $this->suite = $suite; } public function execute(): Result { $buffer = $this->warnAboutConflictingOptions(); $writer = new XMLWriter; $writer->openMemory(); $writer->setIndent(true); $writer->startDocument(); $writer->startElement('tests'); $currentTestCase = null; foreach (new RecursiveIteratorIterator($this->suite) as $test) { if ($test instanceof TestCase) { if ($test::class !== $currentTestCase) { if ($currentTestCase !== null) { $writer->endElement(); } $writer->startElement('testCaseClass'); $writer->writeAttribute('name', $test::class); $currentTestCase = $test::class; } $writer->startElement('testCaseMethod'); $writer->writeAttribute('id', $test->valueObjectForEvents()->id()); $writer->writeAttribute('name', $test->name()); $writer->writeAttribute('groups', implode(',', $test->groups())); /** * @deprecated https://github.com/sebastianbergmann/phpunit/issues/5481 */ if (!empty($test->dataSetAsString())) { $writer->writeAttribute( 'dataSet', str_replace( ' with data set ', '', $test->dataSetAsString(), ), ); } $writer->endElement(); continue; } if ($test instanceof PhptTestCase) { if ($currentTestCase !== null) { $writer->endElement(); $currentTestCase = null; } $writer->startElement('phptFile'); $writer->writeAttribute('path', $test->getName()); $writer->endElement(); } } if ($currentTestCase !== null) { $writer->endElement(); } $writer->endElement(); file_put_contents($this->filename, $writer->outputMemory()); $buffer .= sprintf( 'Wrote list of tests that would have been run to %s' . PHP_EOL, $this->filename, ); return Result::from($buffer); } private function warnAboutConflictingOptions(): string { $buffer = ''; $configuration = Registry::get(); if ($configuration->hasFilter()) { $buffer .= 'The --filter and --list-tests-xml options cannot be combined, --filter is ignored' . PHP_EOL; } if ($configuration->hasGroups()) { $buffer .= 'The --group and --list-tests-xml options cannot be combined, --group is ignored' . PHP_EOL; } if ($configuration->hasExcludeGroups()) { $buffer .= 'The --exclude-group and --list-tests-xml options cannot be combined, --exclude-group is ignored' . PHP_EOL; } if (!empty($buffer)) { $buffer .= PHP_EOL; } return $buffer; } } Command/Commands/GenerateConfigurationCommand.php 0000644 00000004401 15111303730 0016146 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\TextUI\Command; use function fgets; use function file_put_contents; use function getcwd; use function trim; use PHPUnit\Runner\Version; use PHPUnit\TextUI\XmlConfiguration\Generator; /** * @internal This class is not covered by the backward compatibility promise for PHPUnit */ final class GenerateConfigurationCommand implements Command { public function execute(): Result { print 'Generating phpunit.xml in ' . getcwd() . PHP_EOL . PHP_EOL; print 'Bootstrap script (relative to path shown above; default: vendor/autoload.php): '; $bootstrapScript = $this->read(); print 'Tests directory (relative to path shown above; default: tests): '; $testsDirectory = $this->read(); print 'Source directory (relative to path shown above; default: src): '; $src = $this->read(); print 'Cache directory (relative to path shown above; default: .phpunit.cache): '; $cacheDirectory = $this->read(); if ($bootstrapScript === '') { $bootstrapScript = 'vendor/autoload.php'; } if ($testsDirectory === '') { $testsDirectory = 'tests'; } if ($src === '') { $src = 'src'; } if ($cacheDirectory === '') { $cacheDirectory = '.phpunit.cache'; } $generator = new Generator; file_put_contents( 'phpunit.xml', $generator->generateDefaultConfiguration( Version::series(), $bootstrapScript, $testsDirectory, $src, $cacheDirectory, ), ); /* @noinspection MissingDirectorySeparatorInspection */ print PHP_EOL . 'Generated phpunit.xml in ' . getcwd() . '.' . PHP_EOL; print 'Make sure to exclude the ' . $cacheDirectory . ' directory from version control.' . PHP_EOL; return Result::from(); } private function read(): string { return trim(fgets(STDIN)); } } Command/Commands/WarmCodeCoverageCacheCommand.php 0000644 00000004626 15111303730 0015776 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\TextUI\Command; use function printf; use PHPUnit\TextUI\Configuration\CodeCoverageFilterRegistry; use PHPUnit\TextUI\Configuration\Configuration; use PHPUnit\TextUI\Configuration\NoCoverageCacheDirectoryException; use SebastianBergmann\CodeCoverage\StaticAnalysis\CacheWarmer; use SebastianBergmann\Timer\NoActiveTimerException; use SebastianBergmann\Timer\Timer; /** * @internal This class is not covered by the backward compatibility promise for PHPUnit */ final class WarmCodeCoverageCacheCommand implements Command { private readonly Configuration $configuration; private readonly CodeCoverageFilterRegistry $codeCoverageFilterRegistry; public function __construct(Configuration $configuration, CodeCoverageFilterRegistry $codeCoverageFilterRegistry) { $this->configuration = $configuration; $this->codeCoverageFilterRegistry = $codeCoverageFilterRegistry; } /** * @throws NoActiveTimerException * @throws NoCoverageCacheDirectoryException */ public function execute(): Result { if (!$this->configuration->hasCoverageCacheDirectory()) { return Result::from( 'Cache for static analysis has not been configured' . PHP_EOL, Result::FAILURE, ); } $this->codeCoverageFilterRegistry->init($this->configuration, true); if (!$this->codeCoverageFilterRegistry->configured()) { return Result::from( 'Filter for code coverage has not been configured' . PHP_EOL, Result::FAILURE, ); } $timer = new Timer; $timer->start(); print 'Warming cache for static analysis ... '; (new CacheWarmer)->warmCache( $this->configuration->coverageCacheDirectory(), !$this->configuration->disableCodeCoverageIgnore(), $this->configuration->ignoreDeprecatedCodeUnitsFromCodeCoverage(), $this->codeCoverageFilterRegistry->get(), ); printf( '[%s]%s', $timer->stop()->asString(), \PHP_EOL, ); return Result::from(); } } Command/Command.php 0000644 00000000676 15111303730 0010214 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\TextUI\Command; /** * @internal This class is not covered by the backward compatibility promise for PHPUnit */ interface Command { public function execute(): Result; } Output/Printer/DefaultPrinter.php 0000644 00000005447 15111303730 0013134 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\TextUI\Output; use function assert; use function count; use function dirname; use function explode; use function fclose; use function fopen; use function fsockopen; use function fwrite; use function sprintf; use function str_replace; use function str_starts_with; use PHPUnit\TextUI\DirectoryDoesNotExistException; use PHPUnit\TextUI\InvalidSocketException; use PHPUnit\Util\Filesystem; /** * @internal This class is not covered by the backward compatibility promise for PHPUnit */ final class DefaultPrinter implements Printer { /** * @psalm-var closed-resource|resource */ private $stream; private readonly bool $isPhpStream; private bool $isOpen; /** * @throws DirectoryDoesNotExistException * @throws InvalidSocketException */ public static function from(string $out): self { return new self($out); } /** * @throws DirectoryDoesNotExistException * @throws InvalidSocketException */ public static function standardOutput(): self { return new self('php://stdout'); } /** * @throws DirectoryDoesNotExistException * @throws InvalidSocketException */ public static function standardError(): self { return new self('php://stderr'); } /** * @throws DirectoryDoesNotExistException * @throws InvalidSocketException */ private function __construct(string $out) { if (str_starts_with($out, 'socket://')) { $tmp = explode(':', str_replace('socket://', '', $out)); if (count($tmp) !== 2) { throw new InvalidSocketException( sprintf( '"%s" does not match "socket://hostname:port" format', $out, ), ); } $this->stream = fsockopen($tmp[0], (int) $tmp[1]); $this->isOpen = true; return; } $this->isPhpStream = str_starts_with($out, 'php://'); if (!$this->isPhpStream && !Filesystem::createDirectory(dirname($out))) { throw new DirectoryDoesNotExistException(dirname($out)); } $this->stream = fopen($out, 'wb'); $this->isOpen = true; } public function print(string $buffer): void { assert($this->isOpen); fwrite($this->stream, $buffer); } public function flush(): void { if ($this->isOpen && $this->isPhpStream) { fclose($this->stream); $this->isOpen = false; } } } Output/Printer/NullPrinter.php 0000644 00000001032 15111303730 0012444 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\TextUI\Output; /** * @internal This class is not covered by the backward compatibility promise for PHPUnit */ final class NullPrinter implements Printer { public function print(string $buffer): void { } public function flush(): void { } } Output/Printer/Printer.php 0000644 00000000757 15111303730 0011626 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\TextUI\Output; /** * @internal This interface is not covered by the backward compatibility promise for PHPUnit */ interface Printer { public function print(string $buffer): void; public function flush(): void; } Output/Facade.php 0000644 00000017655 15111303730 0007730 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\TextUI\Output; use function assert; use PHPUnit\Event\EventFacadeIsSealedException; use PHPUnit\Event\Facade as EventFacade; use PHPUnit\Event\UnknownSubscriberTypeException; use PHPUnit\Logging\TeamCity\TeamCityLogger; use PHPUnit\Logging\TestDox\TestResultCollection; use PHPUnit\TestRunner\TestResult\TestResult; use PHPUnit\TextUI\Configuration\Configuration; use PHPUnit\TextUI\DirectoryDoesNotExistException; use PHPUnit\TextUI\InvalidSocketException; use PHPUnit\TextUI\Output\Default\ProgressPrinter\ProgressPrinter as DefaultProgressPrinter; use PHPUnit\TextUI\Output\Default\ResultPrinter as DefaultResultPrinter; use PHPUnit\TextUI\Output\Default\UnexpectedOutputPrinter; use PHPUnit\TextUI\Output\TestDox\ResultPrinter as TestDoxResultPrinter; use SebastianBergmann\Timer\Duration; use SebastianBergmann\Timer\ResourceUsageFormatter; /** * @internal This class is not covered by the backward compatibility promise for PHPUnit */ final class Facade { private static ?Printer $printer = null; private static ?DefaultResultPrinter $defaultResultPrinter = null; private static ?TestDoxResultPrinter $testDoxResultPrinter = null; private static ?SummaryPrinter $summaryPrinter = null; private static bool $defaultProgressPrinter = false; /** * @throws EventFacadeIsSealedException * @throws UnknownSubscriberTypeException */ public static function init(Configuration $configuration, bool $extensionReplacesProgressOutput, bool $extensionReplacesResultOutput): Printer { self::createPrinter($configuration); assert(self::$printer !== null); self::createUnexpectedOutputPrinter(); if (!$extensionReplacesProgressOutput) { self::createProgressPrinter($configuration); } if (!$extensionReplacesResultOutput) { self::createResultPrinter($configuration); self::createSummaryPrinter($configuration); } if ($configuration->outputIsTeamCity()) { new TeamCityLogger( DefaultPrinter::standardOutput(), EventFacade::instance(), ); } return self::$printer; } /** * @psalm-param ?array<string, TestResultCollection> $testDoxResult */ public static function printResult(TestResult $result, ?array $testDoxResult, Duration $duration): void { assert(self::$printer !== null); if ($result->numberOfTestsRun() > 0) { if (self::$defaultProgressPrinter) { self::$printer->print(PHP_EOL . PHP_EOL); } self::$printer->print((new ResourceUsageFormatter)->resourceUsage($duration) . PHP_EOL . PHP_EOL); } if (self::$testDoxResultPrinter !== null && $testDoxResult !== null) { self::$testDoxResultPrinter->print($testDoxResult); } if (self::$defaultResultPrinter !== null) { self::$defaultResultPrinter->print($result); } if (self::$summaryPrinter !== null) { self::$summaryPrinter->print($result); } } /** * @throws DirectoryDoesNotExistException * @throws InvalidSocketException */ public static function printerFor(string $target): Printer { if ($target === 'php://stdout') { if (!self::$printer instanceof NullPrinter) { return self::$printer; } return DefaultPrinter::standardOutput(); } return DefaultPrinter::from($target); } private static function createPrinter(Configuration $configuration): void { $printerNeeded = false; if ($configuration->outputIsTeamCity()) { $printerNeeded = true; } if ($configuration->outputIsTestDox()) { $printerNeeded = true; } if (!$configuration->noOutput() && !$configuration->noProgress()) { $printerNeeded = true; } if (!$configuration->noOutput() && !$configuration->noResults()) { $printerNeeded = true; } if ($printerNeeded) { if ($configuration->outputToStandardErrorStream()) { self::$printer = DefaultPrinter::standardError(); return; } self::$printer = DefaultPrinter::standardOutput(); return; } self::$printer = new NullPrinter; } private static function createProgressPrinter(Configuration $configuration): void { assert(self::$printer !== null); if (!self::useDefaultProgressPrinter($configuration)) { return; } new DefaultProgressPrinter( self::$printer, EventFacade::instance(), $configuration->colors(), $configuration->columns(), $configuration->source(), ); self::$defaultProgressPrinter = true; } private static function useDefaultProgressPrinter(Configuration $configuration): bool { if ($configuration->noOutput()) { return false; } if ($configuration->noProgress()) { return false; } if ($configuration->outputIsTeamCity()) { return false; } return true; } private static function createResultPrinter(Configuration $configuration): void { assert(self::$printer !== null); if ($configuration->outputIsTestDox()) { self::$defaultResultPrinter = new DefaultResultPrinter( self::$printer, true, true, true, false, false, false, false, false, false, false, false, false, false, ); } if ($configuration->outputIsTestDox()) { self::$testDoxResultPrinter = new TestDoxResultPrinter( self::$printer, $configuration->colors(), ); } if ($configuration->noOutput() || $configuration->noResults()) { return; } if (self::$defaultResultPrinter !== null) { return; } self::$defaultResultPrinter = new DefaultResultPrinter( self::$printer, true, true, true, true, true, true, $configuration->displayDetailsOnIncompleteTests(), $configuration->displayDetailsOnSkippedTests(), $configuration->displayDetailsOnTestsThatTriggerDeprecations(), $configuration->displayDetailsOnTestsThatTriggerErrors(), $configuration->displayDetailsOnTestsThatTriggerNotices(), $configuration->displayDetailsOnTestsThatTriggerWarnings(), $configuration->reverseDefectList(), ); } private static function createSummaryPrinter(Configuration $configuration): void { assert(self::$printer !== null); if (($configuration->noOutput() || $configuration->noResults()) && !($configuration->outputIsTeamCity() || $configuration->outputIsTestDox())) { return; } self::$summaryPrinter = new SummaryPrinter( self::$printer, $configuration->colors(), ); } /** * @throws EventFacadeIsSealedException * @throws UnknownSubscriberTypeException */ private static function createUnexpectedOutputPrinter(): void { assert(self::$printer !== null); new UnexpectedOutputPrinter(self::$printer, EventFacade::instance()); } } Output/TestDox/ResultPrinter.php 0000644 00000023444 15111303730 0012772 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\TextUI\Output\TestDox; use const PHP_EOL; use function array_map; use function assert; use function explode; use function implode; use function preg_match; use function preg_split; use function rtrim; use function str_starts_with; use function trim; use PHPUnit\Event\Code\Throwable; use PHPUnit\Event\TestData\NoDataSetFromDataProviderException; use PHPUnit\Framework\TestStatus\TestStatus; use PHPUnit\Logging\TestDox\TestResult as TestDoxTestResult; use PHPUnit\Logging\TestDox\TestResultCollection; use PHPUnit\TextUI\Output\Printer; use PHPUnit\Util\Color; /** * @internal This class is not covered by the backward compatibility promise for PHPUnit */ final class ResultPrinter { private readonly Printer $printer; private readonly bool $colors; public function __construct(Printer $printer, bool $colors) { $this->printer = $printer; $this->colors = $colors; } /** * @psalm-param array<string, TestResultCollection> $tests */ public function print(array $tests): void { foreach ($tests as $prettifiedClassName => $_tests) { $this->printPrettifiedClassName($prettifiedClassName); foreach ($_tests as $test) { $this->printTestResult($test); } $this->printer->print(PHP_EOL); } } public function flush(): void { $this->printer->flush(); } /** * @psalm-param string $prettifiedClassName */ private function printPrettifiedClassName(string $prettifiedClassName): void { $buffer = $prettifiedClassName; if ($this->colors) { $buffer = Color::colorizeTextBox('underlined', $buffer); } $this->printer->print($buffer . PHP_EOL); } /** * @throws NoDataSetFromDataProviderException */ private function printTestResult(TestDoxTestResult $test): void { $this->printTestResultHeader($test); $this->printTestResultBody($test); } /** * @throws NoDataSetFromDataProviderException */ private function printTestResultHeader(TestDoxTestResult $test): void { $buffer = ' ' . $this->symbolFor($test->status()) . ' '; if ($this->colors) { $this->printer->print( Color::colorizeTextBox( $this->colorFor($test->status()), $buffer, ), ); } else { $this->printer->print($buffer); } $this->printer->print($test->test()->testDox()->prettifiedMethodName($this->colors) . PHP_EOL); } private function printTestResultBody(TestDoxTestResult $test): void { if ($test->status()->isSuccess()) { return; } if (!$test->hasThrowable()) { return; } $this->printTestResultBodyStart($test); $this->printThrowable($test); $this->printTestResultBodyEnd($test); } private function printTestResultBodyStart(TestDoxTestResult $test): void { $this->printer->print( $this->prefixLines( $this->prefixFor('start', $test->status()), '', ), ); $this->printer->print(PHP_EOL); } private function printTestResultBodyEnd(TestDoxTestResult $test): void { $this->printer->print(PHP_EOL); $this->printer->print( $this->prefixLines( $this->prefixFor('last', $test->status()), '', ), ); $this->printer->print(PHP_EOL); } private function printThrowable(TestDoxTestResult $test): void { $throwable = $test->throwable(); assert($throwable instanceof Throwable); $message = trim($throwable->description()); $stackTrace = $this->formatStackTrace($throwable->stackTrace()); $diff = ''; if (!empty($message) && $this->colors) { ['message' => $message, 'diff' => $diff] = $this->colorizeMessageAndDiff( $message, $this->messageColorFor($test->status()), ); } if (!empty($message)) { $this->printer->print( $this->prefixLines( $this->prefixFor('message', $test->status()), $message, ), ); $this->printer->print(PHP_EOL); } if (!empty($diff)) { $this->printer->print( $this->prefixLines( $this->prefixFor('diff', $test->status()), $diff, ), ); $this->printer->print(PHP_EOL); } if (!empty($stackTrace)) { if (!empty($message) || !empty($diff)) { $prefix = $this->prefixFor('default', $test->status()); } else { $prefix = $this->prefixFor('trace', $test->status()); } $this->printer->print( $this->prefixLines($prefix, PHP_EOL . $stackTrace), ); } } /** * @psalm-return array{message: string, diff: string} */ private function colorizeMessageAndDiff(string $buffer, string $style): array { $lines = $buffer ? array_map('\rtrim', explode(PHP_EOL, $buffer)) : []; $message = []; $diff = []; $insideDiff = false; foreach ($lines as $line) { if ($line === '--- Expected') { $insideDiff = true; } if (!$insideDiff) { $message[] = $line; } else { if (str_starts_with($line, '-')) { $line = Color::colorize('fg-red', Color::visualizeWhitespace($line, true)); } elseif (str_starts_with($line, '+')) { $line = Color::colorize('fg-green', Color::visualizeWhitespace($line, true)); } elseif ($line === '@@ @@') { $line = Color::colorize('fg-cyan', $line); } $diff[] = $line; } } $message = implode(PHP_EOL, $message); $diff = implode(PHP_EOL, $diff); if (!empty($message)) { $message = Color::colorizeTextBox($style, $message); } return [ 'message' => $message, 'diff' => $diff, ]; } private function formatStackTrace(string $stackTrace): string { if (!$this->colors) { return rtrim($stackTrace); } $lines = []; $previousPath = ''; foreach (explode(PHP_EOL, $stackTrace) as $line) { if (preg_match('/^(.*):(\d+)$/', $line, $matches)) { $lines[] = Color::colorizePath($matches[1], $previousPath) . Color::dim(':') . Color::colorize('fg-blue', $matches[2]) . "\n"; $previousPath = $matches[1]; continue; } $lines[] = $line; $previousPath = ''; } return rtrim(implode('', $lines)); } private function prefixLines(string $prefix, string $message): string { return implode( PHP_EOL, array_map( static fn (string $line) => ' ' . $prefix . ($line ? ' ' . $line : ''), preg_split('/\r\n|\r|\n/', $message), ), ); } /** * @psalm-param 'default'|'start'|'message'|'diff'|'trace'|'last' $type */ private function prefixFor(string $type, TestStatus $status): string { if (!$this->colors) { return '│'; } return Color::colorize( $this->colorFor($status), match ($type) { 'default' => '│', 'start' => '┐', 'message' => '├', 'diff' => '┊', 'trace' => '╵', 'last' => '┴', }, ); } private function colorFor(TestStatus $status): string { if ($status->isSuccess()) { return 'fg-green'; } if ($status->isError()) { return 'fg-yellow'; } if ($status->isFailure()) { return 'fg-red'; } if ($status->isSkipped()) { return 'fg-cyan'; } if ($status->isRisky() || $status->isIncomplete() || $status->isWarning()) { return 'fg-yellow'; } return 'fg-blue'; } private function messageColorFor(TestStatus $status): string { if ($status->isSuccess()) { return ''; } if ($status->isError()) { return 'bg-yellow,fg-black'; } if ($status->isFailure()) { return 'bg-red,fg-white'; } if ($status->isSkipped()) { return 'fg-cyan'; } if ($status->isRisky() || $status->isIncomplete() || $status->isWarning()) { return 'fg-yellow'; } return 'fg-white,bg-blue'; } private function symbolFor(TestStatus $status): string { if ($status->isSuccess()) { return '✔'; } if ($status->isError() || $status->isFailure()) { return '✘'; } if ($status->isSkipped()) { return '↩'; } if ($status->isRisky()) { return '☢'; } if ($status->isIncomplete()) { return '∅'; } if ($status->isWarning()) { return '⚠'; } return '?'; } } Output/Default/ProgressPrinter/ProgressPrinter.php 0000644 00000027527 15111303730 0016470 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\TextUI\Output\Default\ProgressPrinter; use function floor; use function sprintf; use function str_contains; use function str_repeat; use function strlen; use PHPUnit\Event\EventFacadeIsSealedException; use PHPUnit\Event\Facade; use PHPUnit\Event\Test\DeprecationTriggered; use PHPUnit\Event\Test\Errored; use PHPUnit\Event\Test\ErrorTriggered; 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\TestRunner\ExecutionStarted; use PHPUnit\Event\UnknownSubscriberTypeException; use PHPUnit\Framework\TestStatus\TestStatus; use PHPUnit\TextUI\Configuration\Source; use PHPUnit\TextUI\Configuration\SourceFilter; use PHPUnit\TextUI\Output\Printer; use PHPUnit\Util\Color; /** * @internal This class is not covered by the backward compatibility promise for PHPUnit */ final class ProgressPrinter { private readonly Printer $printer; private readonly bool $colors; private readonly int $numberOfColumns; private readonly Source $source; private int $column = 0; private int $numberOfTests = 0; private int $numberOfTestsWidth = 0; private int $maxColumn = 0; private int $numberOfTestsRun = 0; private ?TestStatus $status = null; private bool $prepared = false; /** * @throws EventFacadeIsSealedException * @throws UnknownSubscriberTypeException */ public function __construct(Printer $printer, Facade $facade, bool $colors, int $numberOfColumns, Source $source) { $this->printer = $printer; $this->colors = $colors; $this->numberOfColumns = $numberOfColumns; $this->source = $source; $this->registerSubscribers($facade); } public function testRunnerExecutionStarted(ExecutionStarted $event): void { $this->numberOfTestsRun = 0; $this->numberOfTests = $event->testSuite()->count(); $this->numberOfTestsWidth = strlen((string) $this->numberOfTests); $this->column = 0; $this->maxColumn = $this->numberOfColumns - strlen(' / (XXX%)') - (2 * $this->numberOfTestsWidth); } public function beforeTestClassMethodErrored(): void { $this->printProgressForError(); $this->updateTestStatus(TestStatus::error()); } public function testPrepared(): void { $this->prepared = true; } public function testSkipped(): void { if (!$this->prepared) { $this->printProgressForSkipped(); } else { $this->updateTestStatus(TestStatus::skipped()); } } public function testMarkedIncomplete(): void { $this->updateTestStatus(TestStatus::incomplete()); } public function testTriggeredNotice(NoticeTriggered $event): void { if ($event->ignoredByBaseline()) { return; } if ($this->source->restrictNotices() && !(new SourceFilter)->includes($this->source, $event->file())) { return; } if (!$this->source->ignoreSuppressionOfNotices() && $event->wasSuppressed()) { return; } $this->updateTestStatus(TestStatus::notice()); } public function testTriggeredPhpNotice(PhpNoticeTriggered $event): void { if ($event->ignoredByBaseline()) { return; } if ($this->source->restrictNotices() && !(new SourceFilter)->includes($this->source, $event->file())) { return; } if (!$this->source->ignoreSuppressionOfPhpNotices() && $event->wasSuppressed()) { return; } $this->updateTestStatus(TestStatus::notice()); } public function testTriggeredDeprecation(DeprecationTriggered $event): void { if ($event->ignoredByBaseline()) { return; } if ($this->source->restrictDeprecations() && !(new SourceFilter)->includes($this->source, $event->file())) { return; } if (!$this->source->ignoreSuppressionOfDeprecations() && $event->wasSuppressed()) { return; } $this->updateTestStatus(TestStatus::deprecation()); } public function testTriggeredPhpDeprecation(PhpDeprecationTriggered $event): void { if ($event->ignoredByBaseline()) { return; } if ($this->source->restrictDeprecations() && !(new SourceFilter)->includes($this->source, $event->file())) { return; } if (!$this->source->ignoreSuppressionOfPhpDeprecations() && $event->wasSuppressed()) { return; } $this->updateTestStatus(TestStatus::deprecation()); } public function testTriggeredPhpunitDeprecation(): void { $this->updateTestStatus(TestStatus::deprecation()); } public function testConsideredRisky(): void { $this->updateTestStatus(TestStatus::risky()); } public function testTriggeredWarning(WarningTriggered $event): void { if ($event->ignoredByBaseline()) { return; } if ($this->source->restrictWarnings() && !(new SourceFilter)->includes($this->source, $event->file())) { return; } if (!$this->source->ignoreSuppressionOfWarnings() && $event->wasSuppressed()) { return; } $this->updateTestStatus(TestStatus::warning()); } public function testTriggeredPhpWarning(PhpWarningTriggered $event): void { if ($event->ignoredByBaseline()) { return; } if ($this->source->restrictWarnings() && !(new SourceFilter)->includes($this->source, $event->file())) { return; } if (!$this->source->ignoreSuppressionOfPhpWarnings() && $event->wasSuppressed()) { return; } $this->updateTestStatus(TestStatus::warning()); } public function testTriggeredPhpunitWarning(): void { $this->updateTestStatus(TestStatus::warning()); } public function testTriggeredError(ErrorTriggered $event): void { if (!$this->source->ignoreSuppressionOfErrors() && $event->wasSuppressed()) { return; } $this->updateTestStatus(TestStatus::error()); } public function testFailed(): void { $this->updateTestStatus(TestStatus::failure()); } public function testErrored(Errored $event): void { /* * @todo Eliminate this special case */ if (str_contains($event->asString(), 'Test was run in child process and ended unexpectedly')) { $this->updateTestStatus(TestStatus::error()); return; } if (!$this->prepared) { $this->printProgressForError(); } else { $this->updateTestStatus(TestStatus::error()); } } public function testFinished(): void { if ($this->status === null) { $this->printProgressForSuccess(); } elseif ($this->status->isSkipped()) { $this->printProgressForSkipped(); } elseif ($this->status->isIncomplete()) { $this->printProgressForIncomplete(); } elseif ($this->status->isRisky()) { $this->printProgressForRisky(); } elseif ($this->status->isNotice()) { $this->printProgressForNotice(); } elseif ($this->status->isDeprecation()) { $this->printProgressForDeprecation(); } elseif ($this->status->isWarning()) { $this->printProgressForWarning(); } elseif ($this->status->isFailure()) { $this->printProgressForFailure(); } else { $this->printProgressForError(); } $this->status = null; $this->prepared = false; } /** * @throws EventFacadeIsSealedException * @throws UnknownSubscriberTypeException */ private function registerSubscribers(Facade $facade): void { $facade->registerSubscribers( new BeforeTestClassMethodErroredSubscriber($this), new TestConsideredRiskySubscriber($this), new TestErroredSubscriber($this), new TestFailedSubscriber($this), new TestFinishedSubscriber($this), new TestMarkedIncompleteSubscriber($this), new TestPreparedSubscriber($this), new TestRunnerExecutionStartedSubscriber($this), new TestSkippedSubscriber($this), new TestTriggeredDeprecationSubscriber($this), new TestTriggeredNoticeSubscriber($this), new TestTriggeredPhpDeprecationSubscriber($this), new TestTriggeredPhpNoticeSubscriber($this), new TestTriggeredPhpunitDeprecationSubscriber($this), new TestTriggeredPhpunitWarningSubscriber($this), new TestTriggeredPhpWarningSubscriber($this), new TestTriggeredWarningSubscriber($this), ); } private function updateTestStatus(TestStatus $status): void { if ($this->status !== null && $this->status->isMoreImportantThan($status)) { return; } $this->status = $status; } private function printProgressForSuccess(): void { $this->printProgress('.'); } private function printProgressForSkipped(): void { $this->printProgressWithColor('fg-cyan, bold', 'S'); } private function printProgressForIncomplete(): void { $this->printProgressWithColor('fg-yellow, bold', 'I'); } private function printProgressForNotice(): void { $this->printProgressWithColor('fg-yellow, bold', 'N'); } private function printProgressForDeprecation(): void { $this->printProgressWithColor('fg-yellow, bold', 'D'); } private function printProgressForRisky(): void { $this->printProgressWithColor('fg-yellow, bold', 'R'); } private function printProgressForWarning(): void { $this->printProgressWithColor('fg-yellow, bold', 'W'); } private function printProgressForFailure(): void { $this->printProgressWithColor('bg-red, fg-white', 'F'); } private function printProgressForError(): void { $this->printProgressWithColor('fg-red, bold', 'E'); } private function printProgressWithColor(string $color, string $progress): void { if ($this->colors) { $progress = Color::colorizeTextBox($color, $progress); } $this->printProgress($progress); } private function printProgress(string $progress): void { $this->printer->print($progress); $this->column++; $this->numberOfTestsRun++; if ($this->column === $this->maxColumn || $this->numberOfTestsRun === $this->numberOfTests) { if ($this->numberOfTestsRun === $this->numberOfTests) { $this->printer->print(str_repeat(' ', $this->maxColumn - $this->column)); } $this->printer->print( sprintf( ' %' . $this->numberOfTestsWidth . 'd / %' . $this->numberOfTestsWidth . 'd (%3s%%)', $this->numberOfTestsRun, $this->numberOfTests, floor(($this->numberOfTestsRun / $this->numberOfTests) * 100), ), ); if ($this->column === $this->maxColumn) { $this->column = 0; $this->printer->print("\n"); } } } } Output/Default/ProgressPrinter/Subscriber/TestTriggeredErrorSubscriber.php 0000644 00000001317 15111303730 0023222 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\TextUI\Output\Default\ProgressPrinter; 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->printer()->testTriggeredError($event); } } Output/Default/ProgressPrinter/Subscriber/TestSkippedSubscriber.php 0000644 00000001237 15111303730 0021674 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\TextUI\Output\Default\ProgressPrinter; 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->printer()->testSkipped(); } } Output/Default/ProgressPrinter/Subscriber/TestTriggeredPhpunitWarningSubscriber.php 0000644 00000001377 15111303730 0025114 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\TextUI\Output\Default\ProgressPrinter; 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->printer()->testTriggeredPhpunitWarning(); } } Output/Default/ProgressPrinter/Subscriber/TestTriggeredPhpunitDeprecationSubscriber.php 0000644 00000001427 15111303730 0025740 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\TextUI\Output\Default\ProgressPrinter; 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->printer()->testTriggeredPhpunitDeprecation(); } } Output/Default/ProgressPrinter/Subscriber/TestTriggeredNoticeSubscriber.php 0000644 00000001325 15111303730 0023351 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\TextUI\Output\Default\ProgressPrinter; 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->printer()->testTriggeredNotice($event); } } Output/Default/ProgressPrinter/Subscriber/Subscriber.php 0000644 00000001255 15111303730 0017514 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\TextUI\Output\Default\ProgressPrinter; /** * @internal This class is not covered by the backward compatibility promise for PHPUnit */ abstract class Subscriber { private readonly ProgressPrinter $printer; public function __construct(ProgressPrinter $printer) { $this->printer = $printer; } protected function printer(): ProgressPrinter { return $this->printer; } } Output/Default/ProgressPrinter/Subscriber/TestTriggeredPhpWarningSubscriber.php 0000644 00000001355 15111303730 0024210 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\TextUI\Output\Default\ProgressPrinter; 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->printer()->testTriggeredPhpWarning($event); } } Output/Default/ProgressPrinter/Subscriber/TestTriggeredDeprecationSubscriber.php 0000644 00000001363 15111303730 0024367 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\TextUI\Output\Default\ProgressPrinter; 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->printer()->testTriggeredDeprecation($event); } } Output/Default/ProgressPrinter/Subscriber/TestMarkedIncompleteSubscriber.php 0000644 00000001325 15111303730 0023516 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\TextUI\Output\Default\ProgressPrinter; 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->printer()->testMarkedIncomplete(); } } Output/Default/ProgressPrinter/Subscriber/TestConsideredRiskySubscriber.php 0000644 00000001317 15111303730 0023375 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\TextUI\Output\Default\ProgressPrinter; 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->printer()->testConsideredRisky(); } } Output/Default/ProgressPrinter/Subscriber/TestRunnerExecutionStartedSubscriber.php 0000644 00000001363 15111303730 0024761 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\TextUI\Output\Default\ProgressPrinter; use PHPUnit\Event\TestRunner\ExecutionStarted; use PHPUnit\Event\TestRunner\ExecutionStartedSubscriber; /** * @internal This class is not covered by the backward compatibility promise for PHPUnit */ final class TestRunnerExecutionStartedSubscriber extends Subscriber implements ExecutionStartedSubscriber { public function notify(ExecutionStarted $event): void { $this->printer()->testRunnerExecutionStarted($event); } } Output/Default/ProgressPrinter/Subscriber/TestTriggeredWarningSubscriber.php 0000644 00000001333 15111303730 0023534 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\TextUI\Output\Default\ProgressPrinter; 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->printer()->testTriggeredWarning($event); } } Output/Default/ProgressPrinter/Subscriber/TestFailedSubscriber.php 0000644 00000001231 15111303730 0021453 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\TextUI\Output\Default\ProgressPrinter; 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->printer()->testFailed(); } } Output/Default/ProgressPrinter/Subscriber/TestFinishedSubscriber.php 0000644 00000001245 15111303730 0022025 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\TextUI\Output\Default\ProgressPrinter; 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->printer()->testFinished(); } } Output/Default/ProgressPrinter/Subscriber/TestErroredSubscriber.php 0000644 00000001245 15111303730 0021676 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\TextUI\Output\Default\ProgressPrinter; 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->printer()->testErrored($event); } } Output/Default/ProgressPrinter/Subscriber/TestPreparedSubscriber.php 0000644 00000001245 15111303730 0022036 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\TextUI\Output\Default\ProgressPrinter; 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->printer()->testPrepared(); } } Output/Default/ProgressPrinter/Subscriber/BeforeTestClassMethodErroredSubscriber.php 0000644 00000001425 15111303730 0025150 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\TextUI\Output\Default\ProgressPrinter; 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->printer()->beforeTestClassMethodErrored(); } } Output/Default/ProgressPrinter/Subscriber/TestTriggeredPhpNoticeSubscriber.php 0000644 00000001347 15111303730 0024025 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\TextUI\Output\Default\ProgressPrinter; 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->printer()->testTriggeredPhpNotice($event); } } Output/Default/ProgressPrinter/Subscriber/TestTriggeredPhpDeprecationSubscriber.php 0000644 00000001405 15111303730 0025034 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\TextUI\Output\Default\ProgressPrinter; 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->printer()->testTriggeredPhpDeprecation($event); } } Output/Default/ResultPrinter.php 0000644 00000050234 15111303730 0012761 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\TextUI\Output\Default; use const PHP_EOL; use function array_keys; use function array_merge; use function array_reverse; use function array_unique; use function assert; use function count; use function explode; use function ksort; use function range; use function sprintf; use function str_starts_with; use function strlen; use function substr; use function trim; use PHPUnit\Event\Code\Test; use PHPUnit\Event\Code\TestMethod; use PHPUnit\Event\Test\BeforeFirstTestMethodErrored; use PHPUnit\Event\Test\ConsideredRisky; use PHPUnit\Event\Test\DeprecationTriggered; use PHPUnit\Event\Test\ErrorTriggered; 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\WarningTriggered; use PHPUnit\Event\TestData\NoDataSetFromDataProviderException; use PHPUnit\TestRunner\TestResult\Issues\Issue; use PHPUnit\TestRunner\TestResult\TestResult; use PHPUnit\TextUI\Output\Printer; /** * @internal This class is not covered by the backward compatibility promise for PHPUnit */ final class ResultPrinter { private readonly Printer $printer; private readonly bool $displayPhpunitErrors; private readonly bool $displayPhpunitWarnings; private readonly bool $displayTestsWithErrors; private readonly bool $displayTestsWithFailedAssertions; private readonly bool $displayRiskyTests; private readonly bool $displayPhpunitDeprecations; private readonly bool $displayDetailsOnIncompleteTests; private readonly bool $displayDetailsOnSkippedTests; private readonly bool $displayDetailsOnTestsThatTriggerDeprecations; private readonly bool $displayDetailsOnTestsThatTriggerErrors; private readonly bool $displayDetailsOnTestsThatTriggerNotices; private readonly bool $displayDetailsOnTestsThatTriggerWarnings; private readonly bool $displayDefectsInReverseOrder; private bool $listPrinted = false; public function __construct(Printer $printer, bool $displayPhpunitErrors, bool $displayPhpunitWarnings, bool $displayPhpunitDeprecations, bool $displayTestsWithErrors, bool $displayTestsWithFailedAssertions, bool $displayRiskyTests, bool $displayDetailsOnIncompleteTests, bool $displayDetailsOnSkippedTests, bool $displayDetailsOnTestsThatTriggerDeprecations, bool $displayDetailsOnTestsThatTriggerErrors, bool $displayDetailsOnTestsThatTriggerNotices, bool $displayDetailsOnTestsThatTriggerWarnings, bool $displayDefectsInReverseOrder) { $this->printer = $printer; $this->displayPhpunitErrors = $displayPhpunitErrors; $this->displayPhpunitWarnings = $displayPhpunitWarnings; $this->displayPhpunitDeprecations = $displayPhpunitDeprecations; $this->displayTestsWithErrors = $displayTestsWithErrors; $this->displayTestsWithFailedAssertions = $displayTestsWithFailedAssertions; $this->displayRiskyTests = $displayRiskyTests; $this->displayDetailsOnIncompleteTests = $displayDetailsOnIncompleteTests; $this->displayDetailsOnSkippedTests = $displayDetailsOnSkippedTests; $this->displayDetailsOnTestsThatTriggerDeprecations = $displayDetailsOnTestsThatTriggerDeprecations; $this->displayDetailsOnTestsThatTriggerErrors = $displayDetailsOnTestsThatTriggerErrors; $this->displayDetailsOnTestsThatTriggerNotices = $displayDetailsOnTestsThatTriggerNotices; $this->displayDetailsOnTestsThatTriggerWarnings = $displayDetailsOnTestsThatTriggerWarnings; $this->displayDefectsInReverseOrder = $displayDefectsInReverseOrder; } public function print(TestResult $result): void { if ($this->displayPhpunitErrors) { $this->printPhpunitErrors($result); } if ($this->displayPhpunitWarnings) { $this->printTestRunnerWarnings($result); } if ($this->displayPhpunitDeprecations) { $this->printTestRunnerDeprecations($result); } if ($this->displayTestsWithErrors) { $this->printTestsWithErrors($result); } if ($this->displayTestsWithFailedAssertions) { $this->printTestsWithFailedAssertions($result); } if ($this->displayPhpunitWarnings) { $this->printDetailsOnTestsThatTriggeredPhpunitWarnings($result); } if ($this->displayPhpunitDeprecations) { $this->printDetailsOnTestsThatTriggeredPhpunitDeprecations($result); } if ($this->displayRiskyTests) { $this->printRiskyTests($result); } if ($this->displayDetailsOnIncompleteTests) { $this->printIncompleteTests($result); } if ($this->displayDetailsOnSkippedTests) { $this->printSkippedTestSuites($result); $this->printSkippedTests($result); } if ($this->displayDetailsOnTestsThatTriggerErrors) { $this->printIssueList('error', $result->errors()); } if ($this->displayDetailsOnTestsThatTriggerWarnings) { $this->printIssueList('PHP warning', $result->phpWarnings()); $this->printIssueList('warning', $result->warnings()); } if ($this->displayDetailsOnTestsThatTriggerNotices) { $this->printIssueList('PHP notice', $result->phpNotices()); $this->printIssueList('notice', $result->notices()); } if ($this->displayDetailsOnTestsThatTriggerDeprecations) { $this->printIssueList('PHP deprecation', $result->phpDeprecations()); $this->printIssueList('deprecation', $result->deprecations()); } } public function flush(): void { $this->printer->flush(); } private function printPhpunitErrors(TestResult $result): void { if (!$result->hasTestTriggeredPhpunitErrorEvents()) { return; } $elements = $this->mapTestsWithIssuesEventsToElements($result->testTriggeredPhpunitErrorEvents()); $this->printListHeaderWithNumber($elements['numberOfTestsWithIssues'], 'PHPUnit error'); $this->printList($elements['elements']); } private function printDetailsOnTestsThatTriggeredPhpunitDeprecations(TestResult $result): void { if (!$result->hasTestTriggeredPhpunitDeprecationEvents()) { return; } $elements = $this->mapTestsWithIssuesEventsToElements($result->testTriggeredPhpunitDeprecationEvents()); $this->printListHeaderWithNumberOfTestsAndNumberOfIssues( $elements['numberOfTestsWithIssues'], $elements['numberOfIssues'], 'PHPUnit deprecation', ); $this->printList($elements['elements']); } private function printTestRunnerWarnings(TestResult $result): void { if (!$result->hasTestRunnerTriggeredWarningEvents()) { return; } $elements = []; foreach ($result->testRunnerTriggeredWarningEvents() as $event) { $elements[] = [ 'title' => $event->message(), 'body' => '', ]; } $this->printListHeaderWithNumber(count($elements), 'PHPUnit test runner warning'); $this->printList($elements); } private function printTestRunnerDeprecations(TestResult $result): void { if (!$result->hasTestRunnerTriggeredDeprecationEvents()) { return; } $elements = []; foreach ($result->testRunnerTriggeredDeprecationEvents() as $event) { $elements[] = [ 'title' => $event->message(), 'body' => '', ]; } $this->printListHeaderWithNumber(count($elements), 'PHPUnit test runner deprecation'); $this->printList($elements); } private function printDetailsOnTestsThatTriggeredPhpunitWarnings(TestResult $result): void { if (!$result->hasTestTriggeredPhpunitWarningEvents()) { return; } $elements = $this->mapTestsWithIssuesEventsToElements($result->testTriggeredPhpunitWarningEvents()); $this->printListHeaderWithNumberOfTestsAndNumberOfIssues( $elements['numberOfTestsWithIssues'], $elements['numberOfIssues'], 'PHPUnit warning', ); $this->printList($elements['elements']); } private function printTestsWithErrors(TestResult $result): void { if (!$result->hasTestErroredEvents()) { return; } $elements = []; foreach ($result->testErroredEvents() as $event) { if ($event instanceof BeforeFirstTestMethodErrored) { $title = $event->testClassName(); } else { $title = $this->name($event->test()); } $elements[] = [ 'title' => $title, 'body' => $event->throwable()->asString(), ]; } $this->printListHeaderWithNumber(count($elements), 'error'); $this->printList($elements); } private function printTestsWithFailedAssertions(TestResult $result): void { if (!$result->hasTestFailedEvents()) { return; } $elements = []; foreach ($result->testFailedEvents() as $event) { $body = $event->throwable()->asString(); if (str_starts_with($body, 'AssertionError: ')) { $body = substr($body, strlen('AssertionError: ')); } $elements[] = [ 'title' => $this->name($event->test()), 'body' => $body, ]; } $this->printListHeaderWithNumber(count($elements), 'failure'); $this->printList($elements); } private function printRiskyTests(TestResult $result): void { if (!$result->hasTestConsideredRiskyEvents()) { return; } $elements = $this->mapTestsWithIssuesEventsToElements($result->testConsideredRiskyEvents()); $this->printListHeaderWithNumber($elements['numberOfTestsWithIssues'], 'risky test'); $this->printList($elements['elements']); } private function printIncompleteTests(TestResult $result): void { if (!$result->hasTestMarkedIncompleteEvents()) { return; } $elements = []; foreach ($result->testMarkedIncompleteEvents() as $event) { $elements[] = [ 'title' => $this->name($event->test()), 'body' => $event->throwable()->asString(), ]; } $this->printListHeaderWithNumber(count($elements), 'incomplete test'); $this->printList($elements); } private function printSkippedTestSuites(TestResult $result): void { if (!$result->hasTestSuiteSkippedEvents()) { return; } $elements = []; foreach ($result->testSuiteSkippedEvents() as $event) { $elements[] = [ 'title' => $event->testSuite()->name(), 'body' => $event->message(), ]; } $this->printListHeaderWithNumber(count($elements), 'skipped test suite'); $this->printList($elements); } private function printSkippedTests(TestResult $result): void { if (!$result->hasTestSkippedEvents()) { return; } $elements = []; foreach ($result->testSkippedEvents() as $event) { $elements[] = [ 'title' => $this->name($event->test()), 'body' => $event->message(), ]; } $this->printListHeaderWithNumber(count($elements), 'skipped test'); $this->printList($elements); } /** * @psalm-param non-empty-string $type * @psalm-param list<Issue> $issues */ private function printIssueList(string $type, array $issues): void { if (empty($issues)) { return; } $numberOfUniqueIssues = count($issues); $triggeringTests = []; foreach ($issues as $issue) { $triggeringTests = array_merge($triggeringTests, array_keys($issue->triggeringTests())); } $numberOfTests = count(array_unique($triggeringTests)); unset($triggeringTests); $this->printListHeader( sprintf( '%d test%s triggered %d %s%s:' . PHP_EOL . PHP_EOL, $numberOfTests, $numberOfTests !== 1 ? 's' : '', $numberOfUniqueIssues, $type, $numberOfUniqueIssues !== 1 ? 's' : '', ), ); $i = 1; foreach ($issues as $issue) { $title = sprintf( '%s:%d', $issue->file(), $issue->line(), ); $body = trim($issue->description()) . PHP_EOL . PHP_EOL . 'Triggered by:'; $triggeringTests = $issue->triggeringTests(); ksort($triggeringTests); foreach ($triggeringTests as $triggeringTest) { $body .= PHP_EOL . PHP_EOL . '* ' . $triggeringTest['test']->id(); if ($triggeringTest['count'] > 1) { $body .= sprintf( ' (%d times)', $triggeringTest['count'], ); } if ($triggeringTest['test']->isTestMethod()) { $body .= PHP_EOL . ' ' . $triggeringTest['test']->file() . ':' . $triggeringTest['test']->line(); } } $this->printIssueListElement($i++, $title, $body); $this->printer->print(PHP_EOL); } } private function printListHeaderWithNumberOfTestsAndNumberOfIssues(int $numberOfTestsWithIssues, int $numberOfIssues, string $type): void { $this->printListHeader( sprintf( "%d test%s triggered %d %s%s:\n\n", $numberOfTestsWithIssues, $numberOfTestsWithIssues !== 1 ? 's' : '', $numberOfIssues, $type, $numberOfIssues !== 1 ? 's' : '', ), ); } private function printListHeaderWithNumber(int $number, string $type): void { $this->printListHeader( sprintf( "There %s %d %s%s:\n\n", ($number === 1) ? 'was' : 'were', $number, $type, ($number === 1) ? '' : 's', ), ); } private function printListHeader(string $header): void { if ($this->listPrinted) { $this->printer->print("--\n\n"); } $this->listPrinted = true; $this->printer->print($header); } /** * @psalm-param list<array{title: string, body: string}> $elements */ private function printList(array $elements): void { $i = 1; if ($this->displayDefectsInReverseOrder) { $elements = array_reverse($elements); } foreach ($elements as $element) { $this->printListElement($i++, $element['title'], $element['body']); } $this->printer->print("\n"); } private function printListElement(int $number, string $title, string $body): void { $body = trim($body); $this->printer->print( sprintf( "%s%d) %s\n%s%s", $number > 1 ? "\n" : '', $number, $title, $body, !empty($body) ? "\n" : '', ), ); } private function printIssueListElement(int $number, string $title, string $body): void { $body = trim($body); $this->printer->print( sprintf( "%d) %s\n%s%s", $number, $title, $body, !empty($body) ? "\n" : '', ), ); } /** * @throws NoDataSetFromDataProviderException */ private function name(Test $test): string { if ($test->isTestMethod()) { assert($test instanceof TestMethod); return $test->nameWithClass(); } return $test->name(); } /** * @psalm-param array<string,list<ConsideredRisky|DeprecationTriggered|PhpDeprecationTriggered|PhpunitDeprecationTriggered|ErrorTriggered|NoticeTriggered|PhpNoticeTriggered|WarningTriggered|PhpWarningTriggered|PhpunitErrorTriggered|PhpunitWarningTriggered>> $events * * @psalm-return array{numberOfTestsWithIssues: int, numberOfIssues: int, elements: list<array{title: string, body: string}>} */ private function mapTestsWithIssuesEventsToElements(array $events): array { $elements = []; $issues = 0; foreach ($events as $reasons) { $test = $reasons[0]->test(); $testLocation = $this->testLocation($test); $title = $this->name($test); $body = ''; $first = true; $single = count($reasons) === 1; foreach ($reasons as $reason) { if ($first) { $first = false; } else { $body .= PHP_EOL; } $body .= $this->reasonMessage($reason, $single); $body .= $this->reasonLocation($reason, $single); $issues++; } if (!empty($testLocation)) { $body .= $testLocation; } $elements[] = [ 'title' => $title, 'body' => $body, ]; } return [ 'numberOfTestsWithIssues' => count($events), 'numberOfIssues' => $issues, 'elements' => $elements, ]; } private function testLocation(Test $test): string { if (!$test->isTestMethod()) { return ''; } assert($test instanceof TestMethod); return sprintf( '%s%s:%d%s', PHP_EOL, $test->file(), $test->line(), PHP_EOL, ); } private function reasonMessage(ConsideredRisky|DeprecationTriggered|ErrorTriggered|NoticeTriggered|PhpDeprecationTriggered|PhpNoticeTriggered|PhpunitDeprecationTriggered|PhpunitErrorTriggered|PhpunitWarningTriggered|PhpWarningTriggered|WarningTriggered $reason, bool $single): string { $message = trim($reason->message()); if ($single) { return $message . PHP_EOL; } $lines = explode(PHP_EOL, $message); $buffer = '* ' . $lines[0] . PHP_EOL; if (count($lines) > 1) { foreach (range(1, count($lines) - 1) as $line) { $buffer .= ' ' . $lines[$line] . PHP_EOL; } } return $buffer; } private function reasonLocation(ConsideredRisky|DeprecationTriggered|ErrorTriggered|NoticeTriggered|PhpDeprecationTriggered|PhpNoticeTriggered|PhpunitDeprecationTriggered|PhpunitErrorTriggered|PhpunitWarningTriggered|PhpWarningTriggered|WarningTriggered $reason, bool $single): string { if (!$reason instanceof DeprecationTriggered && !$reason instanceof PhpDeprecationTriggered && !$reason instanceof ErrorTriggered && !$reason instanceof NoticeTriggered && !$reason instanceof PhpNoticeTriggered && !$reason instanceof WarningTriggered && !$reason instanceof PhpWarningTriggered) { return ''; } return sprintf( '%s%s:%d%s', $single ? '' : ' ', $reason->file(), $reason->line(), PHP_EOL, ); } } Output/Default/UnexpectedOutputPrinter.php 0000644 00000002065 15111303730 0015027 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\TextUI\Output\Default; use PHPUnit\Event\EventFacadeIsSealedException; use PHPUnit\Event\Facade; use PHPUnit\Event\Test\PrintedUnexpectedOutput; use PHPUnit\Event\Test\PrintedUnexpectedOutputSubscriber; use PHPUnit\Event\UnknownSubscriberTypeException; use PHPUnit\TextUI\Output\Printer; final class UnexpectedOutputPrinter implements PrintedUnexpectedOutputSubscriber { private readonly Printer $printer; /** * @throws EventFacadeIsSealedException * @throws UnknownSubscriberTypeException */ public function __construct(Printer $printer, Facade $facade) { $this->printer = $printer; $facade->registerSubscriber($this); } public function notify(PrintedUnexpectedOutput $event): void { $this->printer->print($event->output()); } } Output/SummaryPrinter.php 0000644 00000013024 15111303730 0011550 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\TextUI\Output; use function sprintf; use PHPUnit\TestRunner\TestResult\TestResult; use PHPUnit\Util\Color; /** * @internal This class is not covered by the backward compatibility promise for PHPUnit */ final class SummaryPrinter { private readonly Printer $printer; private readonly bool $colors; private bool $countPrinted = false; public function __construct(Printer $printer, bool $colors) { $this->printer = $printer; $this->colors = $colors; } public function print(TestResult $result): void { if ($result->numberOfTestsRun() === 0) { $this->printWithColor( 'fg-black, bg-yellow', 'No tests executed!', ); return; } if ($result->wasSuccessfulAndNoTestHasIssues() && !$result->hasTestSuiteSkippedEvents() && !$result->hasTestSkippedEvents()) { $this->printWithColor( 'fg-black, bg-green', sprintf( 'OK (%d test%s, %d assertion%s)', $result->numberOfTestsRun(), $result->numberOfTestsRun() === 1 ? '' : 's', $result->numberOfAssertions(), $result->numberOfAssertions() === 1 ? '' : 's', ), ); $this->printNumberOfIssuesIgnoredByBaseline($result); return; } $color = 'fg-black, bg-yellow'; if ($result->wasSuccessful()) { if (!$result->hasTestsWithIssues()) { $this->printWithColor( $color, 'OK, but some tests were skipped!', ); } else { $this->printWithColor( $color, 'OK, but there were issues!', ); } } else { if ($result->hasTestErroredEvents() || $result->hasTestTriggeredPhpunitErrorEvents()) { $color = 'fg-white, bg-red'; $this->printWithColor( $color, 'ERRORS!', ); } elseif ($result->hasTestFailedEvents()) { $color = 'fg-white, bg-red'; $this->printWithColor( $color, 'FAILURES!', ); } elseif ($result->hasWarnings()) { $this->printWithColor( $color, 'WARNINGS!', ); } elseif ($result->hasDeprecations()) { $this->printWithColor( $color, 'DEPRECATIONS!', ); } elseif ($result->hasNotices()) { $this->printWithColor( $color, 'NOTICES!', ); } } $this->printCountString($result->numberOfTestsRun(), 'Tests', $color, true); $this->printCountString($result->numberOfAssertions(), 'Assertions', $color, true); $this->printCountString($result->numberOfErrors(), 'Errors', $color); $this->printCountString($result->numberOfTestFailedEvents(), 'Failures', $color); $this->printCountString($result->numberOfWarnings(), 'Warnings', $color); $this->printCountString($result->numberOfDeprecations(), 'Deprecations', $color); $this->printCountString($result->numberOfNotices(), 'Notices', $color); $this->printCountString($result->numberOfTestSuiteSkippedEvents() + $result->numberOfTestSkippedEvents(), 'Skipped', $color); $this->printCountString($result->numberOfTestMarkedIncompleteEvents(), 'Incomplete', $color); $this->printCountString($result->numberOfTestsWithTestConsideredRiskyEvents(), 'Risky', $color); $this->printWithColor($color, '.'); $this->printNumberOfIssuesIgnoredByBaseline($result); } private function printCountString(int $count, string $name, string $color, bool $always = false): void { if ($always || $count > 0) { $this->printWithColor( $color, sprintf( '%s%s: %d', $this->countPrinted ? ', ' : '', $name, $count, ), false, ); $this->countPrinted = true; } } private function printWithColor(string $color, string $buffer, bool $lf = true): void { if ($this->colors) { $buffer = Color::colorizeTextBox($color, $buffer); } $this->printer->print($buffer); if ($lf) { $this->printer->print(PHP_EOL); } } private function printNumberOfIssuesIgnoredByBaseline(TestResult $result): void { if ($result->hasIssuesIgnoredByBaseline()) { $this->printer->print( sprintf( '%s%d issue%s %s ignored by baseline.%s', PHP_EOL, $result->numberOfIssuesIgnoredByBaseline(), $result->numberOfIssuesIgnoredByBaseline() > 1 ? 's' : '', $result->numberOfIssuesIgnoredByBaseline() > 1 ? 'were' : 'was', PHP_EOL, ), ); } } } Exception/ExtensionsNotConfiguredException.php 0000644 00000000757 15111303730 0015723 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\TextUI; use RuntimeException; /** * @internal This class is not covered by the backward compatibility promise for PHPUnit */ final class ExtensionsNotConfiguredException extends RuntimeException implements Exception { } Exception/InvalidSocketException.php 0000644 00000001343 15111303730 0013624 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\TextUI; use function sprintf; use RuntimeException; /** * @internal This class is not covered by the backward compatibility promise for PHPUnit */ final class InvalidSocketException extends RuntimeException implements Exception { public function __construct(string $socket) { parent::__construct( sprintf( '"%s" does not match "socket://hostname:port" format', $socket, ), ); } } Exception/Exception.php 0000644 00000000667 15111303730 0011154 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\TextUI; use Throwable; /** * @internal This interface is not covered by the backward compatibility promise for PHPUnit */ interface Exception extends Throwable { } Exception/TestFileNotFoundException.php 0000644 00000001307 15111303730 0014261 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\TextUI; use function sprintf; use RuntimeException; /** * @internal This class is not covered by the backward compatibility promise for PHPUnit */ final class TestFileNotFoundException extends RuntimeException implements Exception { public function __construct(string $path) { parent::__construct( sprintf( 'Test file "%s" not found', $path, ), ); } } Exception/RuntimeException.php 0000644 00000000711 15111303730 0012506 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\TextUI; /** * @internal This class is not covered by the backward compatibility promise for PHPUnit */ final class RuntimeException extends \RuntimeException implements Exception { } Exception/TestDirectoryNotFoundException.php 0000644 00000001321 15111303730 0015342 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\TextUI; use function sprintf; use RuntimeException; /** * @internal This class is not covered by the backward compatibility promise for PHPUnit */ final class TestDirectoryNotFoundException extends RuntimeException implements Exception { public function __construct(string $path) { parent::__construct( sprintf( 'Test directory "%s" not found', $path, ), ); } } Exception/DirectoryDoesNotExistException.php 0000644 00000001364 15111303730 0015345 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\TextUI; use function sprintf; use RuntimeException; /** * @internal This class is not covered by the backward compatibility promise for PHPUnit */ final class DirectoryDoesNotExistException extends RuntimeException implements Exception { public function __construct(string $directory) { parent::__construct( sprintf( 'Directory "%s" does not exist and could not be created', $directory, ), ); } } Exception/ReflectionException.php 0000644 00000000742 15111303730 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\TextUI; use RuntimeException; /** * @internal This class is not covered by the backward compatibility promise for PHPUnit */ final class ReflectionException extends RuntimeException implements Exception { } TestRunner.php 0000644 00000004660 15111303730 0007366 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\TextUI; use function mt_srand; use PHPUnit\Event; use PHPUnit\Framework\TestSuite; use PHPUnit\Runner\Filter\Factory; use PHPUnit\Runner\ResultCache\ResultCache; use PHPUnit\Runner\TestSuiteSorter; use PHPUnit\TextUI\Configuration\Configuration; use Throwable; /** * @internal This class is not covered by the backward compatibility promise for PHPUnit */ final class TestRunner { /** * @throws RuntimeException */ public function run(Configuration $configuration, ResultCache $resultCache, TestSuite $suite): void { try { Event\Facade::emitter()->testRunnerStarted(); if ($configuration->executionOrder() === TestSuiteSorter::ORDER_RANDOMIZED) { mt_srand($configuration->randomOrderSeed()); } if ($configuration->executionOrder() !== TestSuiteSorter::ORDER_DEFAULT || $configuration->executionOrderDefects() !== TestSuiteSorter::ORDER_DEFAULT || $configuration->resolveDependencies()) { $resultCache->load(); (new TestSuiteSorter($resultCache))->reorderTestsInSuite( $suite, $configuration->executionOrder(), $configuration->resolveDependencies(), $configuration->executionOrderDefects(), ); Event\Facade::emitter()->testSuiteSorted( $configuration->executionOrder(), $configuration->executionOrderDefects(), $configuration->resolveDependencies(), ); } (new TestSuiteFilterProcessor(new Factory))->process($configuration, $suite); Event\Facade::emitter()->testRunnerExecutionStarted( Event\TestSuite\TestSuiteBuilder::from($suite), ); $suite->run(); Event\Facade::emitter()->testRunnerExecutionFinished(); Event\Facade::emitter()->testRunnerFinished(); } catch (Throwable $t) { throw new RuntimeException( $t->getMessage(), (int) $t->getCode(), $t, ); } } } Application.php 0000644 00000054147 15111303730 0007525 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\TextUI; use const PHP_EOL; use function is_file; use function is_readable; use function printf; use function realpath; use function sprintf; use function trim; use function unlink; use PHPUnit\Event\EventFacadeIsSealedException; use PHPUnit\Event\Facade as EventFacade; use PHPUnit\Event\UnknownSubscriberTypeException; use PHPUnit\Framework\TestSuite; use PHPUnit\Logging\EventLogger; use PHPUnit\Logging\JUnit\JunitXmlLogger; use PHPUnit\Logging\TeamCity\TeamCityLogger; use PHPUnit\Logging\TestDox\HtmlRenderer as TestDoxHtmlRenderer; use PHPUnit\Logging\TestDox\PlainTextRenderer as TestDoxTextRenderer; use PHPUnit\Logging\TestDox\TestResultCollector as TestDoxResultCollector; use PHPUnit\Metadata\Api\CodeCoverage as CodeCoverageMetadataApi; use PHPUnit\Runner\Baseline\CannotLoadBaselineException; use PHPUnit\Runner\Baseline\Generator as BaselineGenerator; use PHPUnit\Runner\Baseline\Reader; use PHPUnit\Runner\Baseline\Writer; use PHPUnit\Runner\CodeCoverage; use PHPUnit\Runner\ErrorHandler; use PHPUnit\Runner\Extension\ExtensionBootstrapper; use PHPUnit\Runner\Extension\Facade as ExtensionFacade; use PHPUnit\Runner\Extension\PharLoader; use PHPUnit\Runner\GarbageCollection\GarbageCollectionHandler; use PHPUnit\Runner\ResultCache\DefaultResultCache; use PHPUnit\Runner\ResultCache\NullResultCache; use PHPUnit\Runner\ResultCache\ResultCache; use PHPUnit\Runner\ResultCache\ResultCacheHandler; use PHPUnit\Runner\TestSuiteSorter; use PHPUnit\Runner\Version; use PHPUnit\TestRunner\TestResult\Facade as TestResultFacade; use PHPUnit\TextUI\CliArguments\Builder; use PHPUnit\TextUI\CliArguments\Configuration as CliConfiguration; use PHPUnit\TextUI\CliArguments\Exception as ArgumentsException; use PHPUnit\TextUI\CliArguments\XmlConfigurationFileFinder; use PHPUnit\TextUI\Command\AtLeastVersionCommand; use PHPUnit\TextUI\Command\GenerateConfigurationCommand; use PHPUnit\TextUI\Command\ListGroupsCommand; use PHPUnit\TextUI\Command\ListTestsAsTextCommand; use PHPUnit\TextUI\Command\ListTestsAsXmlCommand; use PHPUnit\TextUI\Command\ListTestSuitesCommand; use PHPUnit\TextUI\Command\MigrateConfigurationCommand; use PHPUnit\TextUI\Command\Result; use PHPUnit\TextUI\Command\ShowHelpCommand; use PHPUnit\TextUI\Command\ShowVersionCommand; use PHPUnit\TextUI\Command\VersionCheckCommand; use PHPUnit\TextUI\Command\WarmCodeCoverageCacheCommand; use PHPUnit\TextUI\Configuration\CodeCoverageFilterRegistry; use PHPUnit\TextUI\Configuration\Configuration; use PHPUnit\TextUI\Configuration\PhpHandler; use PHPUnit\TextUI\Configuration\Registry; use PHPUnit\TextUI\Configuration\TestSuiteBuilder; use PHPUnit\TextUI\Output\DefaultPrinter; use PHPUnit\TextUI\Output\Facade as OutputFacade; use PHPUnit\TextUI\Output\Printer; use PHPUnit\TextUI\XmlConfiguration\Configuration as XmlConfiguration; use PHPUnit\TextUI\XmlConfiguration\DefaultConfiguration; use PHPUnit\TextUI\XmlConfiguration\Loader; use SebastianBergmann\Timer\Timer; use Throwable; /** * @internal This class is not covered by the backward compatibility promise for PHPUnit */ final class Application { public function run(array $argv): int { try { EventFacade::emitter()->applicationStarted(); $cliConfiguration = $this->buildCliConfiguration($argv); $pathToXmlConfigurationFile = (new XmlConfigurationFileFinder)->find($cliConfiguration); $this->executeCommandsThatOnlyRequireCliConfiguration($cliConfiguration, $pathToXmlConfigurationFile); $xmlConfiguration = $this->loadXmlConfiguration($pathToXmlConfigurationFile); $configuration = Registry::init( $cliConfiguration, $xmlConfiguration, ); (new PhpHandler)->handle($configuration->php()); if ($configuration->hasBootstrap()) { $this->loadBootstrapScript($configuration->bootstrap()); } $this->executeCommandsThatRequireCompleteConfiguration($configuration, $cliConfiguration); $testSuite = $this->buildTestSuite($configuration); $this->executeCommandsThatRequireCliConfigurationAndTestSuite($cliConfiguration, $testSuite); $this->executeHelpCommandWhenThereIsNothingElseToDo($configuration, $testSuite); $pharExtensions = null; $extensionRequiresCodeCoverageCollection = false; $extensionReplacesOutput = false; $extensionReplacesProgressOutput = false; $extensionReplacesResultOutput = false; $extensionRequiresExportOfObjects = false; if (!$configuration->noExtensions()) { if ($configuration->hasPharExtensionDirectory()) { $pharExtensions = (new PharLoader)->loadPharExtensionsInDirectory( $configuration->pharExtensionDirectory(), ); } $bootstrappedExtensions = $this->bootstrapExtensions($configuration); $extensionRequiresCodeCoverageCollection = $bootstrappedExtensions['requiresCodeCoverageCollection']; $extensionReplacesOutput = $bootstrappedExtensions['replacesOutput']; $extensionReplacesProgressOutput = $bootstrappedExtensions['replacesProgressOutput']; $extensionReplacesResultOutput = $bootstrappedExtensions['replacesResultOutput']; $extensionRequiresExportOfObjects = $bootstrappedExtensions['requiresExportOfObjects']; } if ($extensionRequiresExportOfObjects) { EventFacade::emitter()->exportObjects(); } CodeCoverage::instance()->init( $configuration, CodeCoverageFilterRegistry::instance(), $extensionRequiresCodeCoverageCollection, ); if (CodeCoverage::instance()->isActive()) { CodeCoverage::instance()->ignoreLines( (new CodeCoverageMetadataApi)->linesToBeIgnored($testSuite), ); } $printer = OutputFacade::init( $configuration, $extensionReplacesProgressOutput, $extensionReplacesResultOutput, ); if (!$extensionReplacesOutput) { $this->writeRuntimeInformation($printer, $configuration); $this->writePharExtensionInformation($printer, $pharExtensions); $this->writeRandomSeedInformation($printer, $configuration); $printer->print(PHP_EOL); } $this->registerLogfileWriters($configuration); $testDoxResultCollector = $this->testDoxResultCollector($configuration); TestResultFacade::init(); $resultCache = $this->initializeTestResultCache($configuration); if ($configuration->controlGarbageCollector()) { new GarbageCollectionHandler( EventFacade::instance(), $configuration->numberOfTestsBeforeGarbageCollection(), ); } $baselineGenerator = $this->configureBaseline($configuration); EventFacade::instance()->seal(); $timer = new Timer; $timer->start(); $runner = new TestRunner; $runner->run( $configuration, $resultCache, $testSuite, ); $duration = $timer->stop(); $testDoxResult = null; if (isset($testDoxResultCollector)) { $testDoxResult = $testDoxResultCollector->testMethodsGroupedByClass(); } if ($testDoxResult !== null && $configuration->hasLogfileTestdoxHtml()) { OutputFacade::printerFor($configuration->logfileTestdoxHtml())->print( (new TestDoxHtmlRenderer)->render($testDoxResult), ); } if ($testDoxResult !== null && $configuration->hasLogfileTestdoxText()) { OutputFacade::printerFor($configuration->logfileTestdoxText())->print( (new TestDoxTextRenderer)->render($testDoxResult), ); } $result = TestResultFacade::result(); if (!$extensionReplacesResultOutput) { OutputFacade::printResult($result, $testDoxResult, $duration); } CodeCoverage::instance()->generateReports($printer, $configuration); if (isset($baselineGenerator)) { (new Writer)->write( $configuration->generateBaseline(), $baselineGenerator->baseline(), ); $printer->print( sprintf( PHP_EOL . 'Baseline written to %s.' . PHP_EOL, realpath($configuration->generateBaseline()), ), ); } $shellExitCode = (new ShellExitCodeCalculator)->calculate( $configuration->failOnDeprecation(), $configuration->failOnEmptyTestSuite(), $configuration->failOnIncomplete(), $configuration->failOnNotice(), $configuration->failOnRisky(), $configuration->failOnSkipped(), $configuration->failOnWarning(), $result, ); EventFacade::emitter()->applicationFinished($shellExitCode); return $shellExitCode; // @codeCoverageIgnoreStart } catch (Throwable $t) { $this->exitWithCrashMessage($t); } // @codeCoverageIgnoreEnd } private function execute(Command\Command $command): never { print Version::getVersionString() . PHP_EOL . PHP_EOL; $result = $command->execute(); print $result->output(); exit($result->shellExitCode()); } private function loadBootstrapScript(string $filename): void { if (!is_readable($filename)) { $this->exitWithErrorMessage( sprintf( 'Cannot open bootstrap script "%s"', $filename, ), ); } try { include_once $filename; } catch (Throwable $t) { $message = sprintf( 'Error in bootstrap script: %s:%s%s%s%s', $t::class, PHP_EOL, $t->getMessage(), PHP_EOL, $t->getTraceAsString(), ); while ($t = $t->getPrevious()) { $message .= sprintf( '%s%sPrevious error: %s:%s%s%s%s', PHP_EOL, PHP_EOL, $t::class, PHP_EOL, $t->getMessage(), PHP_EOL, $t->getTraceAsString(), ); } $this->exitWithErrorMessage($message); } EventFacade::emitter()->testRunnerBootstrapFinished($filename); } private function buildCliConfiguration(array $argv): CliConfiguration { try { $cliConfiguration = (new Builder)->fromParameters($argv); } catch (ArgumentsException $e) { $this->exitWithErrorMessage($e->getMessage()); } return $cliConfiguration; } private function loadXmlConfiguration(false|string $configurationFile): XmlConfiguration { if (!$configurationFile) { return DefaultConfiguration::create(); } try { return (new Loader)->load($configurationFile); } catch (Throwable $e) { $this->exitWithErrorMessage($e->getMessage()); } } private function buildTestSuite(Configuration $configuration): TestSuite { try { return (new TestSuiteBuilder)->build($configuration); } catch (Exception $e) { $this->exitWithErrorMessage($e->getMessage()); } } /** * @psalm-return array{requiresCodeCoverageCollection: bool, replacesOutput: bool, replacesProgressOutput: bool, replacesResultOutput: bool, requiresExportOfObjects: bool} */ private function bootstrapExtensions(Configuration $configuration): array { $facade = new ExtensionFacade; $extensionBootstrapper = new ExtensionBootstrapper( $configuration, $facade, ); foreach ($configuration->extensionBootstrappers() as $bootstrapper) { $extensionBootstrapper->bootstrap( $bootstrapper['className'], $bootstrapper['parameters'], ); } return [ 'requiresCodeCoverageCollection' => $facade->requiresCodeCoverageCollection(), 'replacesOutput' => $facade->replacesOutput(), 'replacesProgressOutput' => $facade->replacesProgressOutput(), 'replacesResultOutput' => $facade->replacesResultOutput(), 'requiresExportOfObjects' => $facade->requiresExportOfObjects(), ]; } private function executeCommandsThatOnlyRequireCliConfiguration(CliConfiguration $cliConfiguration, false|string $configurationFile): void { if ($cliConfiguration->generateConfiguration()) { $this->execute(new GenerateConfigurationCommand); } if ($cliConfiguration->migrateConfiguration()) { if (!$configurationFile) { $this->exitWithErrorMessage('No configuration file found to migrate'); } $this->execute(new MigrateConfigurationCommand(realpath($configurationFile))); } if ($cliConfiguration->hasAtLeastVersion()) { $this->execute(new AtLeastVersionCommand($cliConfiguration->atLeastVersion())); } if ($cliConfiguration->version()) { $this->execute(new ShowVersionCommand); } if ($cliConfiguration->checkVersion()) { $this->execute(new VersionCheckCommand); } if ($cliConfiguration->help()) { $this->execute(new ShowHelpCommand(Result::SUCCESS)); } } private function executeCommandsThatRequireCliConfigurationAndTestSuite(CliConfiguration $cliConfiguration, TestSuite $testSuite): void { if ($cliConfiguration->listGroups()) { $this->execute(new ListGroupsCommand($testSuite)); } if ($cliConfiguration->listTests()) { $this->execute(new ListTestsAsTextCommand($testSuite)); } if ($cliConfiguration->hasListTestsXml()) { $this->execute( new ListTestsAsXmlCommand( $cliConfiguration->listTestsXml(), $testSuite, ), ); } } private function executeCommandsThatRequireCompleteConfiguration(Configuration $configuration, CliConfiguration $cliConfiguration): void { if ($cliConfiguration->listSuites()) { $this->execute(new ListTestSuitesCommand($configuration->testSuite())); } if ($cliConfiguration->warmCoverageCache()) { $this->execute(new WarmCodeCoverageCacheCommand($configuration, CodeCoverageFilterRegistry::instance())); } } private function executeHelpCommandWhenThereIsNothingElseToDo(Configuration $configuration, TestSuite $testSuite): void { if ($testSuite->isEmpty() && !$configuration->hasCliArguments() && $configuration->testSuite()->isEmpty()) { $this->execute(new ShowHelpCommand(Result::FAILURE)); } } private function writeRuntimeInformation(Printer $printer, Configuration $configuration): void { $printer->print(Version::getVersionString() . PHP_EOL . PHP_EOL); $runtime = 'PHP ' . PHP_VERSION; if (CodeCoverage::instance()->isActive()) { $runtime .= ' with ' . CodeCoverage::instance()->driver()->nameAndVersion(); } $this->writeMessage($printer, 'Runtime', $runtime); if ($configuration->hasConfigurationFile()) { $this->writeMessage( $printer, 'Configuration', $configuration->configurationFile(), ); } } /** * @psalm-param ?list<string> $pharExtensions */ private function writePharExtensionInformation(Printer $printer, ?array $pharExtensions): void { if ($pharExtensions === null) { return; } foreach ($pharExtensions as $extension) { $this->writeMessage( $printer, 'Extension', $extension, ); } } private function writeMessage(Printer $printer, string $type, string $message): void { $printer->print( sprintf( "%-15s%s\n", $type . ':', $message, ), ); } private function writeRandomSeedInformation(Printer $printer, Configuration $configuration): void { if ($configuration->executionOrder() === TestSuiteSorter::ORDER_RANDOMIZED) { $this->writeMessage( $printer, 'Random Seed', (string) $configuration->randomOrderSeed(), ); } } /** * @throws EventFacadeIsSealedException * @throws UnknownSubscriberTypeException */ private function registerLogfileWriters(Configuration $configuration): void { if ($configuration->hasLogEventsText()) { if (is_file($configuration->logEventsText())) { unlink($configuration->logEventsText()); } EventFacade::instance()->registerTracer( new EventLogger( $configuration->logEventsText(), false, ), ); } if ($configuration->hasLogEventsVerboseText()) { if (is_file($configuration->logEventsVerboseText())) { unlink($configuration->logEventsVerboseText()); } EventFacade::instance()->registerTracer( new EventLogger( $configuration->logEventsVerboseText(), true, ), ); EventFacade::emitter()->exportObjects(); } if ($configuration->hasLogfileJunit()) { new JunitXmlLogger( OutputFacade::printerFor($configuration->logfileJunit()), EventFacade::instance(), ); } if ($configuration->hasLogfileTeamcity()) { new TeamCityLogger( DefaultPrinter::from( $configuration->logfileTeamcity(), ), EventFacade::instance(), ); } } /** * @throws EventFacadeIsSealedException * @throws UnknownSubscriberTypeException */ private function testDoxResultCollector(Configuration $configuration): ?TestDoxResultCollector { if ($configuration->hasLogfileTestdoxHtml() || $configuration->hasLogfileTestdoxText() || $configuration->outputIsTestDox()) { return new TestDoxResultCollector(EventFacade::instance()); } return null; } /** * @throws EventFacadeIsSealedException * @throws UnknownSubscriberTypeException */ private function initializeTestResultCache(Configuration $configuration): ResultCache { if ($configuration->cacheResult()) { $cache = new DefaultResultCache($configuration->testResultCacheFile()); new ResultCacheHandler($cache, EventFacade::instance()); return $cache; } return new NullResultCache; } /** * @throws EventFacadeIsSealedException * @throws UnknownSubscriberTypeException */ private function configureBaseline(Configuration $configuration): ?BaselineGenerator { if ($configuration->hasGenerateBaseline()) { return new BaselineGenerator( EventFacade::instance(), $configuration->source(), ); } if ($configuration->source()->useBaseline()) { /** @psalm-suppress MissingThrowsDocblock */ $baselineFile = $configuration->source()->baseline(); $baseline = null; try { $baseline = (new Reader)->read($baselineFile); } catch (CannotLoadBaselineException $e) { EventFacade::emitter()->testRunnerTriggeredWarning($e->getMessage()); } if ($baseline !== null) { ErrorHandler::instance()->use($baseline); } } return null; } /** * @codeCoverageIgnore */ private function exitWithCrashMessage(Throwable $t): never { $message = $t->getMessage(); if (empty(trim($message))) { $message = '(no message)'; } printf( '%s%sAn error occurred inside PHPUnit.%s%sMessage: %s', PHP_EOL, PHP_EOL, PHP_EOL, PHP_EOL, $message, ); $first = true; do { printf( '%s%s: %s:%d%s%s%s%s', PHP_EOL, $first ? 'Location' : 'Caused by', $t->getFile(), $t->getLine(), PHP_EOL, PHP_EOL, $t->getTraceAsString(), PHP_EOL, ); $first = false; } while ($t = $t->getPrevious()); exit(Result::CRASH); } private function exitWithErrorMessage(string $message): never { print Version::getVersionString() . PHP_EOL . PHP_EOL . $message . PHP_EOL; exit(Result::EXCEPTION); } }
Simpan