+ public function testRunAllowsErrorListenersToSilenceTheException()
+ {
+ $dispatcher = $this->getDispatcher();
+ $dispatcher->addListener('console.error', function (ConsoleErrorEvent $event) {
+ $event->getOutput()->write('silenced.');
+
+ $event->setExitCode(0);
+ });
+
+ $dispatcher->addListener('console.command', function () {
+ throw new \RuntimeException('foo');
+ });
+
+ $application = new Application();
+ $application->setDispatcher($dispatcher);
+ $application->setAutoExit(false);
+
+ $application->register('foo')->setCode(function (InputInterface $input, OutputInterface $output) {
+ $output->write('foo.');
+ });
+
+ $tester = new ApplicationTester($application);
+ $tester->run(array('command' => 'foo'));
+ $this->assertContains('before.error.silenced.after.', $tester->getDisplay());
+ $this->assertEquals(ConsoleCommandEvent::RETURN_CODE_DISABLED, $tester->getStatusCode());
+ }
+
+ public function testConsoleErrorEventIsTriggeredOnCommandNotFound()
+ {
+ $dispatcher = new EventDispatcher();
+ $dispatcher->addListener('console.error', function (ConsoleErrorEvent $event) {
+ $this->assertNull($event->getCommand());
+ $this->assertInstanceOf(CommandNotFoundException::class, $event->getError());
+ $event->getOutput()->write('silenced command not found');
+ });
+
+ $application = new Application();
+ $application->setDispatcher($dispatcher);
+ $application->setAutoExit(false);
+
+ $tester = new ApplicationTester($application);
+ $tester->run(array('command' => 'unknown'));
+ $this->assertContains('silenced command not found', $tester->getDisplay());
+ $this->assertEquals(1, $tester->getStatusCode());
+ }
+
+ /**
+ * @group legacy
+ * @expectedDeprecation The "ConsoleEvents::EXCEPTION" event is deprecated since Symfony 3.3 and will be removed in 4.0. Listen to the "ConsoleEvents::ERROR" event instead.
+ */
+ public function testLegacyExceptionListenersAreStillTriggered()
+ {
+ $dispatcher = $this->getDispatcher();
+ $dispatcher->addListener('console.exception', function (ConsoleExceptionEvent $event) {
+ $event->getOutput()->write('caught.');
+
+ $event->setException(new \RuntimeException('replaced in caught.'));
+ });
+
+ $application = new Application();
+ $application->setDispatcher($dispatcher);
+ $application->setAutoExit(false);
+
+ $application->register('foo')->setCode(function (InputInterface $input, OutputInterface $output) {
+ throw new \RuntimeException('foo');
+ });
+
+ $tester = new ApplicationTester($application);
+ $tester->run(array('command' => 'foo'));
+ $this->assertContains('before.caught.error.after.', $tester->getDisplay());
+ $this->assertContains('replaced in caught.', $tester->getDisplay());
+ }
+
+ /**
+ * @requires PHP 7
+ */
+ public function testErrorIsRethrownIfNotHandledByConsoleErrorEvent()
+ {
+ $application = new Application();
+ $application->setAutoExit(false);
+ $application->setCatchExceptions(false);
+ $application->setDispatcher(new EventDispatcher());
+
+ $application->register('dym')->setCode(function (InputInterface $input, OutputInterface $output) {
+ new \UnknownClass();
+ });
+
+ $tester = new ApplicationTester($application);
+
+ try {
+ $tester->run(array('command' => 'dym'));
+ $this->fail('->run() should rethrow PHP errors if not handled via ConsoleErrorEvent.');
+ } catch (\Error $e) {
+ $this->assertSame($e->getMessage(), 'Class \'UnknownClass\' not found');
+ }
+ }
+