class Application
Same name in this branch
- 11.1.x vendor/phar-io/manifest/src/values/Application.php \PharIo\Manifest\Application
- 11.1.x vendor/composer/composer/src/Composer/Console/Application.php \Composer\Console\Application
- 11.1.x vendor/symfony/console/Application.php \Symfony\Component\Console\Application
@no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit
@internal This class is not covered by the backward compatibility promise for PHPUnit
Hierarchy
- class \PHPUnit\TextUI\Application
Expanded class hierarchy of Application
4 string references to 'Application'
- ManifestDocumentMapper::mapType in vendor/
phar-io/ manifest/ src/ ManifestDocumentMapper.php - ManifestSerializer::addContains in vendor/
phar-io/ manifest/ src/ ManifestSerializer.php - SMimeEncrypter::encrypt in vendor/
symfony/ mime/ Crypto/ SMimeEncrypter.php - Status::reportNoRestart in vendor/
composer/ xdebug-handler/ src/ Status.php - No restart status message
File
-
vendor/
phpunit/ phpunit/ src/ TextUI/ Application.php, line 86
Namespace
PHPUnit\TextUIView source
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 (!$configuration->debug() && !$extensionReplacesOutput) {
$this->writeRuntimeInformation($printer, $configuration);
$this->writePharExtensionInformation($printer, $pharExtensions);
$this->writeRandomSeedInformation($printer, $configuration);
$printer->print(PHP_EOL);
}
if ($configuration->debug()) {
EventFacade::instance()->registerTracer(new EventLogger('php://stdout', false));
}
$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()) {
try {
OutputFacade::printerFor($configuration->logfileTestdoxHtml())
->print((new TestDoxHtmlRenderer())->render($testDoxResult));
} catch (DirectoryDoesNotExistException|InvalidSocketException $e) {
EventFacade::emitter()->testRunnerTriggeredWarning(sprintf('Cannot log test results in TestDox HTML format to "%s": %s', $configuration->logfileTestdoxHtml(), $e->getMessage()));
}
}
if ($testDoxResult !== null && $configuration->hasLogfileTestdoxText()) {
try {
OutputFacade::printerFor($configuration->logfileTestdoxText())
->print((new TestDoxTextRenderer())->render($testDoxResult));
} catch (DirectoryDoesNotExistException|InvalidSocketException $e) {
EventFacade::emitter()->testRunnerTriggeredWarning(sprintf('Cannot log test results in TestDox plain text format to "%s": %s', $configuration->logfileTestdoxText(), $e->getMessage()));
}
}
$result = TestResultFacade::result();
if (!$extensionReplacesResultOutput && !$configuration->debug()) {
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->failOnPhpunitDeprecation(), $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, bool $requiresResultCollectedFromEvents = false) : never {
if ($requiresResultCollectedFromEvents) {
try {
TestResultFacade::init();
EventFacade::instance()->seal();
$resultCollectedFromEvents = TestResultFacade::result();
} catch (EventFacadeIsSealedException|UnknownSubscriberTypeException) {
}
}
print Version::getVersionString() . PHP_EOL . PHP_EOL;
$result = $command->execute();
print $result->output();
$shellExitCode = $result->shellExitCode();
if (isset($resultCollectedFromEvents) && $resultCollectedFromEvents->hasTestTriggeredPhpunitErrorEvents()) {
$shellExitCode = Result::EXCEPTION;
print PHP_EOL . PHP_EOL . 'There were errors:' . PHP_EOL;
foreach ($resultCollectedFromEvents->testTriggeredPhpunitErrorEvents() as $events) {
foreach ($events as $event) {
print PHP_EOL . trim($event->message()) . PHP_EOL;
}
}
}
exit($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 === false) {
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 === false) {
$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(new PhpDownloader(), Version::majorVersionNumber(), Version::id()));
}
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), true);
}
if ($cliConfiguration->listTests()) {
$this->execute(new ListTestsAsTextCommand($testSuite), true);
}
if ($cliConfiguration->hasListTestsXml()) {
$this->execute(new ListTestsAsXmlCommand($cliConfiguration->listTestsXml(), $testSuite), true);
}
}
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()) {
try {
new JunitXmlLogger(OutputFacade::printerFor($configuration->logfileJunit()), EventFacade::instance());
} catch (DirectoryDoesNotExistException|InvalidSocketException $e) {
EventFacade::emitter()->testRunnerTriggeredWarning(sprintf('Cannot log test results in JUnit XML format to "%s": %s', $configuration->logfileJunit(), $e->getMessage()));
}
}
if ($configuration->hasLogfileTeamcity()) {
try {
new TeamCityLogger(DefaultPrinter::from($configuration->logfileTeamcity()), EventFacade::instance());
} catch (DirectoryDoesNotExistException|InvalidSocketException $e) {
EventFacade::emitter()->testRunnerTriggeredWarning(sprintf('Cannot log test results in TeamCity format to "%s": %s', $configuration->logfileTeamcity(), $e->getMessage()));
}
}
}
/**
* @throws EventFacadeIsSealedException
* @throws UnknownSubscriberTypeException
*/
private function testDoxResultCollector(Configuration $configuration) : ?TestDoxResultCollector {
if ($configuration->hasLogfileTestdoxHtml() || $configuration->hasLogfileTestdoxText() || $configuration->outputIsTestDox()) {
return new TestDoxResultCollector(EventFacade::instance(), $configuration->source());
}
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;
if ($t->getPrevious()) {
$t = $t->getPrevious();
}
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);
}
}