From e72689859c224e55d9ec3cbe3fcf858a725f19a1 Mon Sep 17 00:00:00 2001 From: Sebastian Bergmann Date: Sun, 31 Mar 2024 10:50:02 +0200 Subject: [PATCH] Prepare error handler to be used in contexts other than test method execution (for instance data provider method execution for #5775) --- src/Framework/TestRunner.php | 2 +- src/Runner/ErrorHandler.php | 173 ++++++++++++++++++++--------------- 2 files changed, 101 insertions(+), 74 deletions(-) diff --git a/src/Framework/TestRunner.php b/src/Framework/TestRunner.php index e41a44bfcb..e8b50ddcdf 100644 --- a/src/Framework/TestRunner.php +++ b/src/Framework/TestRunner.php @@ -80,7 +80,7 @@ public function run(TestCase $test): void $skipped = false; if ($this->shouldErrorHandlerBeUsed($test)) { - ErrorHandler::instance()->enable(); + ErrorHandler::instance()->enableForTest(); } $collectCodeCoverage = CodeCoverage::instance()->isActive() && diff --git a/src/Runner/ErrorHandler.php b/src/Runner/ErrorHandler.php index ba0f41e154..99a2f2fa86 100644 --- a/src/Runner/ErrorHandler.php +++ b/src/Runner/ErrorHandler.php @@ -53,6 +53,7 @@ final class ErrorHandler private static ?self $instance = null; private ?Baseline $baseline = null; private bool $enabled = false; + private bool $enabledForTest = false; private ?int $originalErrorReportingLevel = null; private readonly Source $source; private readonly SourceFilter $sourceFilter; @@ -92,89 +93,103 @@ public function __invoke(int $errorNumber, string $errorString, string $errorFil switch ($errorNumber) { case E_NOTICE: case E_STRICT: - Event\Facade::emitter()->testTriggeredPhpNotice( - $test, - $errorString, - $errorFile, - $errorLine, - $suppressed, - $ignoredByBaseline, - ); + if ($this->enabledForTest) { + Event\Facade::emitter()->testTriggeredPhpNotice( + $test, + $errorString, + $errorFile, + $errorLine, + $suppressed, + $ignoredByBaseline, + ); + } break; case E_USER_NOTICE: - Event\Facade::emitter()->testTriggeredNotice( - $test, - $errorString, - $errorFile, - $errorLine, - $suppressed, - $ignoredByBaseline, - ); + if ($this->enabledForTest) { + Event\Facade::emitter()->testTriggeredNotice( + $test, + $errorString, + $errorFile, + $errorLine, + $suppressed, + $ignoredByBaseline, + ); + } break; case E_WARNING: - Event\Facade::emitter()->testTriggeredPhpWarning( - $test, - $errorString, - $errorFile, - $errorLine, - $suppressed, - $ignoredByBaseline, - ); + if ($this->enabledForTest) { + Event\Facade::emitter()->testTriggeredPhpWarning( + $test, + $errorString, + $errorFile, + $errorLine, + $suppressed, + $ignoredByBaseline, + ); + } break; case E_USER_WARNING: - Event\Facade::emitter()->testTriggeredWarning( - $test, - $errorString, - $errorFile, - $errorLine, - $suppressed, - $ignoredByBaseline, - ); + if ($this->enabledForTest) { + Event\Facade::emitter()->testTriggeredWarning( + $test, + $errorString, + $errorFile, + $errorLine, + $suppressed, + $ignoredByBaseline, + ); + } break; case E_DEPRECATED: - Event\Facade::emitter()->testTriggeredPhpDeprecation( - $test, - $errorString, - $errorFile, - $errorLine, - $suppressed, - $ignoredByBaseline, - $ignoredByTest, - $this->trigger($test, false), - ); + if ($this->enabledForTest) { + Event\Facade::emitter()->testTriggeredPhpDeprecation( + $test, + $errorString, + $errorFile, + $errorLine, + $suppressed, + $ignoredByBaseline, + $ignoredByTest, + $this->trigger($test, false), + ); + } break; case E_USER_DEPRECATED: - Event\Facade::emitter()->testTriggeredDeprecation( - $test, - $errorString, - $errorFile, - $errorLine, - $suppressed, - $ignoredByBaseline, - $ignoredByTest, - $this->trigger($test, true), - ); + if ($this->enabledForTest) { + Event\Facade::emitter()->testTriggeredDeprecation( + $test, + $errorString, + $errorFile, + $errorLine, + $suppressed, + $ignoredByBaseline, + $ignoredByTest, + $this->trigger($test, true), + ); + } break; case E_USER_ERROR: - Event\Facade::emitter()->testTriggeredError( - $test, - $errorString, - $errorFile, - $errorLine, - $suppressed, - ); + if ($this->enabledForTest) { + Event\Facade::emitter()->testTriggeredError( + $test, + $errorString, + $errorFile, + $errorLine, + $suppressed, + ); + } throw new ErrorException('E_USER_ERROR was triggered'); @@ -185,24 +200,13 @@ public function __invoke(int $errorNumber, string $errorString, string $errorFil return false; } - public function enable(): void + public function enableForTest(): void { - if ($this->enabled) { - return; - } - - $oldErrorHandler = set_error_handler($this); - - if ($oldErrorHandler !== null) { - restore_error_handler(); - + if (!$this->enable()) { return; } - $this->enabled = true; - $this->originalErrorReportingLevel = error_reporting(); - - error_reporting($this->originalErrorReportingLevel & self::UNHANDLEABLE_LEVELS); + $this->enabledForTest = true; } public function disable(): void @@ -216,6 +220,7 @@ public function disable(): void error_reporting(error_reporting() | $this->originalErrorReportingLevel); $this->enabled = false; + $this->enabledForTest = false; $this->originalErrorReportingLevel = null; } @@ -232,6 +237,28 @@ public function useDeprecationTriggers(array $deprecationTriggers): void $this->deprecationTriggers = $deprecationTriggers; } + private function enable(): bool + { + if ($this->enabled) { + return false; + } + + $oldErrorHandler = set_error_handler($this); + + if ($oldErrorHandler !== null) { + restore_error_handler(); + + return false; + } + + $this->enabled = true; + $this->originalErrorReportingLevel = error_reporting(); + + error_reporting($this->originalErrorReportingLevel & self::UNHANDLEABLE_LEVELS); + + return true; + } + /** * @psalm-param non-empty-string $file * @psalm-param positive-int $line