From 9e774013ac7309898691fc1e7bb42b3f57e91868 Mon Sep 17 00:00:00 2001 From: Wilmer Arambula Date: Mon, 25 Aug 2025 08:06:38 -0400 Subject: [PATCH 1/6] test(http): Move `testRenderExceptionSetsDisplayErrorsInDebugMode` from `ApplicationTest` to `ApplicationErrorHandlerTest` for better organization. --- .../stateless/ApplicationErrorHandlerTest.php | 63 ++++++++++++++++++ tests/http/stateless/ApplicationTest.php | 66 +------------------ 2 files changed, 64 insertions(+), 65 deletions(-) diff --git a/tests/http/stateless/ApplicationErrorHandlerTest.php b/tests/http/stateless/ApplicationErrorHandlerTest.php index b8a1099e..945fbca4 100644 --- a/tests/http/stateless/ApplicationErrorHandlerTest.php +++ b/tests/http/stateless/ApplicationErrorHandlerTest.php @@ -346,6 +346,68 @@ static function ($errno, $errstr, $errfile, $errline) use (&$warningsCaptured): } } + /** + * @throws InvalidConfigException if the configuration is invalid or incomplete. + */ + #[RequiresPhpExtension('runkit7')] + public function testRenderExceptionSetsDisplayErrorsInDebugMode(): void + { + @\runkit_constant_redefine('YII_ENV_TEST', false); + + $initialBufferLevel = ob_get_level(); + + $_SERVER = [ + 'REQUEST_METHOD' => 'GET', + 'REQUEST_URI' => 'site/trigger-exception', + ]; + + $originalDisplayErrors = ini_get('display_errors'); + + try { + $app = $this->statelessApplication( + [ + 'components' => [ + 'errorHandler' => [ + 'discardExistingOutput' => true, + 'errorAction' => null, + ], + ], + ], + ); + + $response = $app->handle(FactoryHelper::createServerRequestCreator()->createFromGlobals()); + + self::assertSame( + 500, + $response->getStatusCode(), + "Expected HTTP '500' for route 'site/trigger-exception'.", + ); + self::assertSame( + 'text/html; charset=UTF-8', + $response->getHeaderLine('Content-Type'), + "Expected Content-Type 'text/html; charset=UTF-8' for route 'site/trigger-exception'.", + ); + self::assertSame( + '1', + ini_get('display_errors'), + "'display_errors' should be set to '1' when YII_DEBUG mode is enabled and rendering exception view.", + ); + self::assertStringContainsString( + 'yii\base\Exception: Exception error message.', + $response->getBody()->getContents(), + 'Response should contain exception details when YII_DEBUG mode is enabled.', + ); + } finally { + ini_set('display_errors', $originalDisplayErrors); + + while (ob_get_level() < $initialBufferLevel) { + ob_start(); + } + + @\runkit_constant_redefine('YII_ENV_TEST', true); + } + } + /** * @throws InvalidConfigException if the configuration is invalid or incomplete. * @@ -606,4 +668,5 @@ public function testThrowNotFoundHttpExceptionWhenStrictParsingEnabledAndRouteIs $app->request->resolve(); } + } diff --git a/tests/http/stateless/ApplicationTest.php b/tests/http/stateless/ApplicationTest.php index f4b367ce..f4923db8 100644 --- a/tests/http/stateless/ApplicationTest.php +++ b/tests/http/stateless/ApplicationTest.php @@ -4,16 +4,11 @@ namespace yii2\extensions\psrbridge\tests\http\stateless; -use PHPUnit\Framework\Attributes\{Group, RequiresPhpExtension}; +use PHPUnit\Framework\Attributes\{Group}; use yii\base\InvalidConfigException; use yii2\extensions\psrbridge\tests\support\FactoryHelper; use yii2\extensions\psrbridge\tests\TestCase; -use function ini_get; -use function ini_set; -use function ob_get_level; -use function ob_start; - #[Group('http')] final class ApplicationTest extends TestCase { @@ -24,65 +19,6 @@ protected function tearDown(): void parent::tearDown(); } - /** - * @throws InvalidConfigException if the configuration is invalid or incomplete. - */ - #[RequiresPhpExtension('runkit7')] - public function testRenderExceptionSetsDisplayErrorsInDebugMode(): void - { - @\runkit_constant_redefine('YII_ENV_TEST', false); - - $initialBufferLevel = ob_get_level(); - - $_SERVER = [ - 'REQUEST_METHOD' => 'GET', - 'REQUEST_URI' => 'site/trigger-exception', - ]; - - $originalDisplayErrors = ini_get('display_errors'); - - try { - $app = $this->statelessApplication( - [ - 'components' => [ - 'errorHandler' => ['errorAction' => null], - ], - ], - ); - - $response = $app->handle(FactoryHelper::createServerRequestCreator()->createFromGlobals()); - - self::assertSame( - 500, - $response->getStatusCode(), - "Expected HTTP '500' for route 'site/trigger-exception'.", - ); - self::assertSame( - 'text/html; charset=UTF-8', - $response->getHeaderLine('Content-Type'), - "Expected Content-Type 'text/html; charset=UTF-8' for route 'site/trigger-exception'.", - ); - self::assertSame( - '1', - ini_get('display_errors'), - "'display_errors' should be set to '1' when YII_DEBUG mode is enabled and rendering exception view.", - ); - self::assertStringContainsString( - 'yii\base\Exception: Exception error message.', - $response->getBody()->getContents(), - 'Response should contain exception details when YII_DEBUG mode is enabled.', - ); - } finally { - ini_set('display_errors', $originalDisplayErrors); - - while (ob_get_level() < $initialBufferLevel) { - ob_start(); - } - - @\runkit_constant_redefine('YII_ENV_TEST', true); - } - } - /** * @throws InvalidConfigException if the configuration is invalid or incomplete. */ From 29c44885c89eb238e1baa5b10e407ef549e251d3 Mon Sep 17 00:00:00 2001 From: Wilmer Arambula Date: Mon, 25 Aug 2025 12:07:01 +0000 Subject: [PATCH 2/6] Apply fixes from StyleCI --- tests/http/stateless/ApplicationErrorHandlerTest.php | 1 - 1 file changed, 1 deletion(-) diff --git a/tests/http/stateless/ApplicationErrorHandlerTest.php b/tests/http/stateless/ApplicationErrorHandlerTest.php index 945fbca4..c6685e67 100644 --- a/tests/http/stateless/ApplicationErrorHandlerTest.php +++ b/tests/http/stateless/ApplicationErrorHandlerTest.php @@ -668,5 +668,4 @@ public function testThrowNotFoundHttpExceptionWhenStrictParsingEnabledAndRouteIs $app->request->resolve(); } - } From 219a237e49c17e5ec85227051c3ca779bfd3d10d Mon Sep 17 00:00:00 2001 From: Wilmer Arambula Date: Mon, 25 Aug 2025 08:19:16 -0400 Subject: [PATCH 3/6] test(http): Enhance output buffer handling in `ApplicationErrorHandlerTest`. --- .../stateless/ApplicationErrorHandlerTest.php | 38 +++++++++++-------- 1 file changed, 23 insertions(+), 15 deletions(-) diff --git a/tests/http/stateless/ApplicationErrorHandlerTest.php b/tests/http/stateless/ApplicationErrorHandlerTest.php index c6685e67..dd27402b 100644 --- a/tests/http/stateless/ApplicationErrorHandlerTest.php +++ b/tests/http/stateless/ApplicationErrorHandlerTest.php @@ -19,6 +19,7 @@ use function is_array; use function ob_get_level; use function ob_start; +use function PHPSTORM_META\map; use function restore_error_handler; use function set_error_handler; use function str_contains; @@ -361,19 +362,22 @@ public function testRenderExceptionSetsDisplayErrorsInDebugMode(): void 'REQUEST_URI' => 'site/trigger-exception', ]; + ob_start(); + echo "buffer content that should be cleared"; + ob_start(); + echo "nested buffer content"; + $originalDisplayErrors = ini_get('display_errors'); try { - $app = $this->statelessApplication( - [ - 'components' => [ - 'errorHandler' => [ - 'discardExistingOutput' => true, - 'errorAction' => null, - ], + $app = $this->statelessApplication([ + 'components' => [ + 'errorHandler' => [ + 'discardExistingOutput' => true, + 'errorAction' => null, ], ], - ); + ]); $response = $app->handle(FactoryHelper::createServerRequestCreator()->createFromGlobals()); @@ -390,20 +394,24 @@ public function testRenderExceptionSetsDisplayErrorsInDebugMode(): void self::assertSame( '1', ini_get('display_errors'), - "'display_errors' should be set to '1' when YII_DEBUG mode is enabled and rendering exception view.", + "'display_errors' should be set to '1' in debug mode when rendering exception.", ); - self::assertStringContainsString( - 'yii\base\Exception: Exception error message.', - $response->getBody()->getContents(), - 'Response should contain exception details when YII_DEBUG mode is enabled.', + + $buffersAfterTest = ob_get_level(); + + self::assertLessThanOrEqual( + $initialBufferLevel, + $buffersAfterTest, + "'clearOutput()'' should properly clean output buffers", ); - } finally { - ini_set('display_errors', $originalDisplayErrors); + } finally { while (ob_get_level() < $initialBufferLevel) { ob_start(); } + ini_set('display_errors', $originalDisplayErrors); + @\runkit_constant_redefine('YII_ENV_TEST', true); } } From 9369a4c941042d60ea5297bea0c836ef94aca40a Mon Sep 17 00:00:00 2001 From: Wilmer Arambula Date: Mon, 25 Aug 2025 12:19:46 +0000 Subject: [PATCH 4/6] Apply fixes from StyleCI --- tests/http/stateless/ApplicationErrorHandlerTest.php | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/tests/http/stateless/ApplicationErrorHandlerTest.php b/tests/http/stateless/ApplicationErrorHandlerTest.php index dd27402b..6c18bd7f 100644 --- a/tests/http/stateless/ApplicationErrorHandlerTest.php +++ b/tests/http/stateless/ApplicationErrorHandlerTest.php @@ -19,7 +19,6 @@ use function is_array; use function ob_get_level; use function ob_start; -use function PHPSTORM_META\map; use function restore_error_handler; use function set_error_handler; use function str_contains; @@ -363,9 +362,9 @@ public function testRenderExceptionSetsDisplayErrorsInDebugMode(): void ]; ob_start(); - echo "buffer content that should be cleared"; + echo 'buffer content that should be cleared'; ob_start(); - echo "nested buffer content"; + echo 'nested buffer content'; $originalDisplayErrors = ini_get('display_errors'); @@ -404,7 +403,6 @@ public function testRenderExceptionSetsDisplayErrorsInDebugMode(): void $buffersAfterTest, "'clearOutput()'' should properly clean output buffers", ); - } finally { while (ob_get_level() < $initialBufferLevel) { ob_start(); From b67f777d7efc3928137edb765210117d9b80e219 Mon Sep 17 00:00:00 2001 From: Wilmer Arambula Date: Mon, 25 Aug 2025 08:48:30 -0400 Subject: [PATCH 5/6] test(http): Improve variable naming and refactor output buffer assertions in `testRenderExceptionPassesExceptionParameterToTemplateView`. --- .../stateless/ApplicationErrorHandlerTest.php | 72 ++++++++++--------- 1 file changed, 39 insertions(+), 33 deletions(-) diff --git a/tests/http/stateless/ApplicationErrorHandlerTest.php b/tests/http/stateless/ApplicationErrorHandlerTest.php index 6c18bd7f..bbe500f8 100644 --- a/tests/http/stateless/ApplicationErrorHandlerTest.php +++ b/tests/http/stateless/ApplicationErrorHandlerTest.php @@ -354,7 +354,7 @@ public function testRenderExceptionSetsDisplayErrorsInDebugMode(): void { @\runkit_constant_redefine('YII_ENV_TEST', false); - $initialBufferLevel = ob_get_level(); + $bufferBeforeLevel = ob_get_level(); $_SERVER = [ 'REQUEST_METHOD' => 'GET', @@ -368,50 +368,56 @@ public function testRenderExceptionSetsDisplayErrorsInDebugMode(): void $originalDisplayErrors = ini_get('display_errors'); - try { - $app = $this->statelessApplication([ + $app = $this->statelessApplication( + [ 'components' => [ 'errorHandler' => [ 'discardExistingOutput' => true, 'errorAction' => null, ], ], - ]); - - $response = $app->handle(FactoryHelper::createServerRequestCreator()->createFromGlobals()); + ], + ); - self::assertSame( - 500, - $response->getStatusCode(), - "Expected HTTP '500' for route 'site/trigger-exception'.", - ); - self::assertSame( - 'text/html; charset=UTF-8', - $response->getHeaderLine('Content-Type'), - "Expected Content-Type 'text/html; charset=UTF-8' for route 'site/trigger-exception'.", - ); - self::assertSame( - '1', - ini_get('display_errors'), - "'display_errors' should be set to '1' in debug mode when rendering exception.", - ); + $response = $app->handle(FactoryHelper::createServerRequestCreator()->createFromGlobals()); - $buffersAfterTest = ob_get_level(); + self::assertSame( + 500, + $response->getStatusCode(), + "Expected HTTP '500' for route 'site/trigger-exception'.", + ); + self::assertSame( + 'text/html; charset=UTF-8', + $response->getHeaderLine('Content-Type'), + "Expected Content-Type 'text/html; charset=UTF-8' for route 'site/trigger-exception'.", + ); + self::assertSame( + '1', + ini_get('display_errors'), + "'display_errors' should be set to '1' in debug mode when rendering exception.", + ); - self::assertLessThanOrEqual( - $initialBufferLevel, - $buffersAfterTest, - "'clearOutput()'' should properly clean output buffers", - ); - } finally { - while (ob_get_level() < $initialBufferLevel) { - ob_start(); - } + $bufferAfterLevel = ob_get_level(); - ini_set('display_errors', $originalDisplayErrors); + self::assertLessThanOrEqual( + $bufferBeforeLevel, + $bufferAfterLevel, + "'clearOutput()' should properly clean output buffers", + ); - @\runkit_constant_redefine('YII_ENV_TEST', true); + while (ob_get_level() < $bufferBeforeLevel) { + ob_start(); } + + self::assertSame( + $bufferBeforeLevel, + ob_get_level(), + 'Output buffers should be restored to initial level.', + ); + + ini_set('display_errors', $originalDisplayErrors); + + @\runkit_constant_redefine('YII_ENV_TEST', true); } /** From 3913cf4e98a0deaf6af3f7b55ad7ff9342b68e24 Mon Sep 17 00:00:00 2001 From: Wilmer Arambula Date: Mon, 25 Aug 2025 08:52:25 -0400 Subject: [PATCH 6/6] refactor(http): Remove code coverage ignore comments in `ErrorHandler` output cleaning. --- src/http/ErrorHandler.php | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/http/ErrorHandler.php b/src/http/ErrorHandler.php index a85f5518..61072954 100644 --- a/src/http/ErrorHandler.php +++ b/src/http/ErrorHandler.php @@ -86,9 +86,7 @@ public function clearOutput(): void while ($currentLevel > $minLevel) { if (@ob_end_clean() === false) { - // @codeCoverageIgnoreStart ob_clean(); - // @codeCoverageIgnoreEnd } $currentLevel = ob_get_level();