diff --git a/bin/pest b/bin/pest index 27374535..f73a728d 100755 --- a/bin/pest +++ b/bin/pest @@ -90,7 +90,7 @@ use Symfony\Component\Console\Output\ConsoleOutput; $result = $kernel->handle($originalArguments, $arguments); - $kernel->shutdown(); + $kernel->terminate(); } catch (Throwable|Error $e) { Panic::with($e); } diff --git a/src/Contracts/Plugins/Shutdownable.php b/src/Contracts/Plugins/Terminable.php similarity index 54% rename from src/Contracts/Plugins/Shutdownable.php rename to src/Contracts/Plugins/Terminable.php index 41b91fa7..a53a903f 100644 --- a/src/Contracts/Plugins/Shutdownable.php +++ b/src/Contracts/Plugins/Terminable.php @@ -7,10 +7,10 @@ /** * @internal */ -interface Shutdownable +interface Terminable { /** - * Shutdowns the plugin. + * Terminates the plugin. */ - public function shutdown(): void; + public function terminate(): void; } diff --git a/src/Exceptions/FatalException.php b/src/Exceptions/FatalException.php new file mode 100644 index 00000000..d5f9d31f --- /dev/null +++ b/src/Exceptions/FatalException.php @@ -0,0 +1,16 @@ + $this->shutdown()); + // } /** @@ -65,6 +71,8 @@ public static function boot(TestSuite $testSuite, InputInterface $input, OutputI $output, ); + register_shutdown_function(fn () => $kernel->shutdown()); + foreach (self::BOOTSTRAPPERS as $bootstrapper) { $bootstrapper = Container::getInstance()->get($bootstrapper); assert($bootstrapper instanceof Bootstrapper); @@ -110,16 +118,48 @@ public function handle(array $originalArguments, array $arguments): int } /** - * Shutdown the Kernel. + * Terminate the Kernel. */ - public function shutdown(): void + public function terminate(): void { $preBufferOutput = Container::getInstance()->get(KernelDump::class); assert($preBufferOutput instanceof KernelDump); - $preBufferOutput->shutdown(); + $preBufferOutput->terminate(); + + CallsTerminable::execute(); + } - CallsShutdown::execute(); + /** + * Shutdowns unexpectedly the Kernel. + */ + public function shutdown(): void + { + $this->terminate(); + + if (is_array($error = error_get_last())) { + $message = $error['message']; + $file = $error['file']; + $line = $error['line']; + + try { + $writer = new Writer(null, $this->output); + + $throwable = new FatalException($message); + + Reflection::setPropertyValue($throwable, 'line', $line); + Reflection::setPropertyValue($throwable, 'file', $file); + + $inspector = new Inspector($throwable); + + $writer->write($inspector); + } catch (Throwable) { // @phpstan-ignore-line + View::render('components.badge', [ + 'type' => 'ERROR', + 'content' => sprintf('%s in %s:%d', $message, $file, $line), + ]); + } + } } } diff --git a/src/KernelDump.php b/src/KernelDump.php index 39f2004b..150e44ae 100644 --- a/src/KernelDump.php +++ b/src/KernelDump.php @@ -48,9 +48,9 @@ public function disable(): void } /** - * Shutdown the output buffering. + * Terminate the output buffering. */ - public function shutdown(): void + public function terminate(): void { $this->disable(); } diff --git a/src/Plugins/Actions/CallsShutdown.php b/src/Plugins/Actions/CallsTerminable.php similarity index 56% rename from src/Plugins/Actions/CallsShutdown.php rename to src/Plugins/Actions/CallsTerminable.php index d694e2b8..619b9c0f 100644 --- a/src/Plugins/Actions/CallsShutdown.php +++ b/src/Plugins/Actions/CallsTerminable.php @@ -10,20 +10,20 @@ /** * @internal */ -final class CallsShutdown +final class CallsTerminable { /** * Executes the Plugin action. * - * Provides an opportunity for any plugins to shutdown. + * Provides an opportunity for any plugins to terminate. */ public static function execute(): void { - $plugins = Loader::getPlugins(Plugins\Shutdownable::class); + $plugins = Loader::getPlugins(Plugins\Terminable::class); - /** @var Plugins\Shutdownable $plugin */ + /** @var Plugins\Terminable $plugin */ foreach ($plugins as $plugin) { - $plugin->shutdown(); + $plugin->terminate(); } } } diff --git a/src/Plugins/Cache.php b/src/Plugins/Cache.php index a9d881ab..ea3abb78 100644 --- a/src/Plugins/Cache.php +++ b/src/Plugins/Cache.php @@ -36,11 +36,11 @@ public function handleArguments(array $arguments): array { if (! $this->hasArgument('--cache-directory', $arguments)) { - $cliConfiguration = (new CliConfigurationBuilder)->fromParameters([]); + $cliConfiguration = (new CliConfigurationBuilder)->fromParameters([]); $configurationFile = (new XmlConfigurationFileFinder)->find($cliConfiguration); - $xmlConfiguration = DefaultConfiguration::create(); + $xmlConfiguration = DefaultConfiguration::create(); - if ($configurationFile) { + if (is_string($configurationFile)) { $xmlConfiguration = (new Loader)->load($configurationFile); } diff --git a/src/Plugins/Only.php b/src/Plugins/Only.php index aa4556b8..95bc3ca3 100644 --- a/src/Plugins/Only.php +++ b/src/Plugins/Only.php @@ -4,13 +4,13 @@ namespace Pest\Plugins; -use Pest\Contracts\Plugins\Shutdownable; +use Pest\Contracts\Plugins\Terminable; use Pest\PendingCalls\TestCall; /** * @internal */ -final class Only implements Shutdownable +final class Only implements Terminable { /** * The temporary folder. @@ -26,7 +26,7 @@ final class Only implements Shutdownable /** * {@inheritDoc} */ - public function shutdown(): void + public function terminate(): void { $lockFile = self::TEMPORARY_FOLDER.DIRECTORY_SEPARATOR.'only.lock';