diff --git a/system/Common.php b/system/Common.php index bcf2a5c14db9..ea0c476423a0 100644 --- a/system/Common.php +++ b/system/Common.php @@ -185,10 +185,14 @@ function command(string $command) $params[$arg] = $value; } - ob_start(); - service('commands')->run($command, $params); + try { + ob_start(); + service('commands')->run($command, $params); - return ob_get_clean(); + return ob_get_contents(); + } finally { + ob_end_clean(); + } } } diff --git a/tests/_support/Commands/DestructiveCommand.php b/tests/_support/Commands/DestructiveCommand.php new file mode 100644 index 000000000000..723b880b0cd4 --- /dev/null +++ b/tests/_support/Commands/DestructiveCommand.php @@ -0,0 +1,31 @@ + + * + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. + */ + +namespace Tests\Support\Commands; + +use RuntimeException; + +/** + * @internal + */ +final class DestructiveCommand extends AbstractInfo +{ + protected $group = 'demo'; + protected $name = 'app:destructive'; + protected $description = 'This command is destructive.'; + + public function run(array $params): never + { + throw new RuntimeException('This command is destructive and should not be run.'); + } +} diff --git a/tests/system/Commands/CommandTest.php b/tests/system/Commands/CommandTest.php index 1c6e81033e63..6b668d2640c5 100644 --- a/tests/system/Commands/CommandTest.php +++ b/tests/system/Commands/CommandTest.php @@ -19,6 +19,7 @@ use CodeIgniter\Test\StreamFilterTrait; use PHPUnit\Framework\Attributes\DataProvider; use PHPUnit\Framework\Attributes\Group; +use RuntimeException; use Tests\Support\Commands\AppInfo; use Tests\Support\Commands\ParamsReveal; @@ -136,6 +137,13 @@ public function testInexistentCommandsButWithManyAlternatives(): void $this->assertStringContainsString(':clear', $this->getBuffer()); } + public function testDestructiveCommandIsNotRisky(): void + { + $this->expectException(RuntimeException::class); + + command('app:destructive'); + } + /** * @param list $expected */ diff --git a/tests/system/Commands/Translation/LocalizationSyncTest.php b/tests/system/Commands/Translation/LocalizationSyncTest.php index f6dc00764eac..d485b19fd9b2 100644 --- a/tests/system/Commands/Translation/LocalizationSyncTest.php +++ b/tests/system/Commands/Translation/LocalizationSyncTest.php @@ -171,7 +171,6 @@ public function testSyncWithNullableOriginalLangValue(): void TEXT_WRAP; file_put_contents(self::$languageTestPath . self::$locale . '/SyncInvalid.php', $langWithNullValue); - ob_get_flush(); $this->expectException(LogicException::class); $this->expectExceptionMessageMatches('/Only "array" or "string" is allowed/'); @@ -192,7 +191,6 @@ public function testSyncWithIntegerOriginalLangValue(): void TEXT_WRAP; file_put_contents(self::$languageTestPath . self::$locale . '/SyncInvalid.php', $langWithIntegerValue); - ob_get_flush(); $this->expectException(LogicException::class); $this->expectExceptionMessageMatches('/Only "array" or "string" is allowed/'); diff --git a/user_guide_src/source/changelogs/v4.7.3.rst b/user_guide_src/source/changelogs/v4.7.3.rst index be42d6379b8d..50418133d15e 100644 --- a/user_guide_src/source/changelogs/v4.7.3.rst +++ b/user_guide_src/source/changelogs/v4.7.3.rst @@ -33,6 +33,7 @@ Bugs Fixed ********** - **Autoloader:** Fixed a bug where ``Autoloader::unregister()`` (used during tests) silently failed to remove handlers from the SPL autoload stack, causing closures to accumulate permanently. +- **Common:** Fixed a bug where the ``command()`` helper function did not properly clean up output buffers, which could lead to risky tests when exceptions were thrown. See the repo's `CHANGELOG.md `_