Files
michaelschiemer/tests/Feature/ShowImageControllerTest.php

197 lines
5.8 KiB
PHP

<?php
declare(strict_types=1);
use App\Application\Media\ShowImage;
use App\Domain\Media\Image;
use App\Domain\Media\ImageRepository;
use App\Domain\Media\ImageVariantRepository;
use App\Framework\Core\PathProvider;
use App\Framework\Core\ValueObjects\FileSize;
use App\Framework\Core\ValueObjects\Hash;
use App\Framework\Exception\FrameworkException;
use App\Framework\Filesystem\ValueObjects\FilePath;
use App\Framework\Http\HttpRequest;
use App\Framework\Http\MimeType;
use App\Framework\Id\Ulid\Ulid;
use App\Framework\Router\Result\FileResult;
beforeEach(function () {
// Create test directory and file
$this->testDir = '/tmp/test_show_image';
if (! is_dir($this->testDir)) {
mkdir($this->testDir, 0755, true);
}
$this->testImagePath = $this->testDir . '/test-show.jpg';
file_put_contents($this->testImagePath, 'fake-jpeg-content');
// Mock repositories
$this->imageRepository = Mockery::mock(ImageRepository::class);
$this->imageVariantRepository = Mockery::mock(ImageVariantRepository::class);
$this->pathProvider = Mockery::mock(PathProvider::class);
// Create controller
$this->controller = new ShowImage(
$this->pathProvider,
$this->imageRepository,
$this->imageVariantRepository
);
// Test image entity
$this->testImage = new Image(
ulid: Ulid::generate(),
filename: 'test-show.jpg',
originalFilename: 'original.jpg',
mimeType: MimeType::fromString('image/jpeg'),
fileSize: FileSize::fromBytes(strlen('fake-jpeg-content')),
width: 300,
height: 400,
hash: Hash::fromString('test-hash'),
path: FilePath::create($this->testDir),
altText: 'Test show image'
);
});
afterEach(function () {
if (file_exists($this->testImagePath)) {
unlink($this->testImagePath);
}
if (is_dir($this->testDir)) {
rmdir($this->testDir);
}
Mockery::close();
});
it('can serve existing image file', function () {
// Arrange
$filename = 'test-show.jpg';
$request = Mockery::mock(HttpRequest::class);
$this->imageRepository
->shouldReceive('findByFilename')
->with($filename)
->andReturn($this->testImage);
// Act
$result = $this->controller->__invoke($filename, $request);
// Assert
expect($result)->toBeInstanceOf(FileResult::class);
});
it('falls back to image variant repository when image not found', function () {
// Arrange
$filename = 'variant-image.jpg';
$request = Mockery::mock(HttpRequest::class);
$this->imageRepository
->shouldReceive('findByFilename')
->with($filename)
->andReturn(null);
$this->imageVariantRepository
->shouldReceive('findByFilename')
->with($filename)
->andReturn($this->testImage);
// Act
$result = $this->controller->__invoke($filename, $request);
// Assert
expect($result)->toBeInstanceOf(FileResult::class);
});
it('throws exception when image not found in either repository', function () {
// Arrange
$filename = 'nonexistent.jpg';
$request = Mockery::mock(HttpRequest::class);
$this->imageRepository
->shouldReceive('findByFilename')
->with($filename)
->andReturn(null);
$this->imageVariantRepository
->shouldReceive('findByFilename')
->with($filename)
->andReturn(null);
// Act & Assert
expect(fn () => $this->controller->__invoke($filename, $request))
->toThrow(FrameworkException::class, 'Image not found: nonexistent.jpg');
});
it('throws exception when image file does not exist on filesystem', function () {
// Arrange
$filename = 'missing-file.jpg';
$request = Mockery::mock(HttpRequest::class);
$missingFileImage = new Image(
ulid: Ulid::generate(),
filename: 'missing-file.jpg',
originalFilename: 'original.jpg',
mimeType: MimeType::fromString('image/jpeg'),
fileSize: FileSize::fromBytes(100),
width: 300,
height: 400,
hash: Hash::fromString('test-hash'),
path: FilePath::create('/nonexistent/path'),
altText: 'Missing file'
);
$this->imageRepository
->shouldReceive('findByFilename')
->with($filename)
->andReturn($missingFileImage);
// Act & Assert
expect(fn () => $this->controller->__invoke($filename, $request))
->toThrow(FrameworkException::class, 'Image file not found on filesystem');
});
it('determines correct MIME type based on file extension', function () {
// Test JPEG
$jpegFilename = 'test.jpg';
$jpegImage = $this->testImage->withFilename($jpegFilename);
$request = Mockery::mock(HttpRequest::class);
$this->imageRepository
->shouldReceive('findByFilename')
->with($jpegFilename)
->andReturn($jpegImage);
$result = $this->controller->__invoke($jpegFilename, $request);
expect($result)->toBeInstanceOf(FileResult::class);
});
it('handles different image file extensions', function () {
$extensions = [
'test.png' => 'image/png',
'test.gif' => 'image/gif',
'test.webp' => 'image/webp',
'test.avif' => 'image/avif',
'test.unknown' => 'image/jpeg', // fallback
];
foreach ($extensions as $filename => $expectedMime) {
// Create test file for each extension
$testPath = $this->testDir . '/' . $filename;
file_put_contents($testPath, 'fake-content');
$testImage = $this->testImage->withFilename($filename);
$request = Mockery::mock(HttpRequest::class);
$this->imageRepository
->shouldReceive('findByFilename')
->with($filename)
->andReturn($testImage);
$result = $this->controller->__invoke($filename, $request);
expect($result)->toBeInstanceOf(FileResult::class);
// Clean up
unlink($testPath);
}
});