From b87a1f51c699044bd3c328ab136c9b07183805a2 Mon Sep 17 00:00:00 2001 From: Bogdan Date: Sat, 18 Jul 2026 20:00:19 +0200 Subject: [PATCH 1/2] test: add GDHandler unit tests for save and security coverage --- tests/system/Images/GDHandlerTest.php | 73 +++++++++++++++++++++++++++ 1 file changed, 73 insertions(+) diff --git a/tests/system/Images/GDHandlerTest.php b/tests/system/Images/GDHandlerTest.php index d85d1a142ffd..383673e1977c 100644 --- a/tests/system/Images/GDHandlerTest.php +++ b/tests/system/Images/GDHandlerTest.php @@ -19,7 +19,9 @@ use CodeIgniter\Test\CIUnitTestCase; use org\bovigo\vfs\vfsStream; use org\bovigo\vfs\vfsStreamDirectory; +use org\bovigo\vfs\vfsStreamFile; use PHPUnit\Framework\Attributes\Group; +use Throwable; /** * Unit testing for the GD image handler. @@ -463,4 +465,75 @@ public function testClearMetadataReturnsSelf(): void $this->assertSame($this->handler, $result); } + + public function testSaveFailed(): void + { + foreach (['gif', 'jpeg', 'png', 'webp'] as $type) { + if ($type === 'webp' && ! function_exists('imagecreatefromwebp')) { + $this->markTestSkipped('webp is not supported.'); + } + + $this->handler->withFile($this->origin . 'ci-logo.' . $type); + $this->handler->getResource(); // make sure resource is loaded + + try { + $this->handler->save($this->start . 'wontwork/ci-logo.' . $type); + $this->fail('Exception should have been thrown for ' . $type); + } catch (Throwable $e) { + $this->assertInstanceOf(ImageException::class, $e); + $this->assertSame(lang('Images.saveFailed'), $e->getMessage()); + } + } + } + + public function testImageCopyTargetWithMaxQuality(): void + { + foreach (['gif', 'jpeg', 'png', 'webp'] as $type) { + if ($type === 'webp' && ! function_exists('imagecreatefromwebp')) { + $this->markTestSkipped('webp is not supported.'); + } + + $this->handler->withFile($this->origin . 'ci-logo.' . $type); + $this->assertTrue($this->handler->save($this->start . 'work/ci-logo.' . $type, 100)); + $this->assertTrue($this->root->hasChild('work/ci-logo.' . $type)); + + /** @var vfsStreamFile $child */ + $child = $this->root->getChild('work/ci-logo.' . $type); + + $this->assertSame( + file_get_contents($this->origin . 'ci-logo.' . $type), + $child->getContent(), + ); + } + } + + public function testSaveUnsupportedImageType(): void + { + $this->handler->withFile($this->path); + + // Force an invalid image type to ensure proper exception handling + $image = $this->handler->getFile(); + $image->imageType = 9999; + + $this->expectException(ImageException::class); + $this->expectExceptionMessage(lang('Images.unsupportedImageCreate')); + + // save() should throw an exception instead of fatal error in GD + $this->handler->save($this->start . 'work/ci-logo.jpg'); + } + + public function testProcessUnsupportedImageType(): void + { + $this->handler->withFile($this->path); + + // Force an invalid image type to trigger getImageResource default case + $image = $this->handler->getFile(); + $image->imageType = 9999; + + $this->expectException(ImageException::class); + $this->expectExceptionMessage('Ima'); + + // Calling any process function that triggers ensureResource/createImage + $this->handler->resize(10, 10); + } } From 1bc83dc17e07ab2719200d41f9e44f660c4a1f10 Mon Sep 17 00:00:00 2001 From: Bogdan Date: Sun, 19 Jul 2026 21:59:09 +0200 Subject: [PATCH 2/2] test: add tests for GDHandler unsupported image type --- tests/system/Images/GDHandlerTest.php | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/tests/system/Images/GDHandlerTest.php b/tests/system/Images/GDHandlerTest.php index 383673e1977c..cb57f50007ef 100644 --- a/tests/system/Images/GDHandlerTest.php +++ b/tests/system/Images/GDHandlerTest.php @@ -511,14 +511,14 @@ public function testSaveUnsupportedImageType(): void { $this->handler->withFile($this->path); - // Force an invalid image type to ensure proper exception handling + // Force an invalid image type to trigger getImageResource() default case $image = $this->handler->getFile(); $image->imageType = 9999; $this->expectException(ImageException::class); $this->expectExceptionMessage(lang('Images.unsupportedImageCreate')); - // save() should throw an exception instead of fatal error in GD + // save() calls ensureResource() -> getImageResource(), which should throw $this->handler->save($this->start . 'work/ci-logo.jpg'); } @@ -526,14 +526,14 @@ public function testProcessUnsupportedImageType(): void { $this->handler->withFile($this->path); - // Force an invalid image type to trigger getImageResource default case + // Force an invalid image type to trigger getImageResource() default case $image = $this->handler->getFile(); $image->imageType = 9999; $this->expectException(ImageException::class); - $this->expectExceptionMessage('Ima'); + $this->expectExceptionMessage(lang('Images.unsupportedImageCreate')); - // Calling any process function that triggers ensureResource/createImage + // resize() calls ensureResource() -> getImageResource(), which should throw $this->handler->resize(10, 10); } }