Files
michaelschiemer/tests/Feature/ShowImageControllerTest.php
Michael Schiemer 5050c7d73a docs: consolidate documentation into organized structure
- Move 12 markdown files from root to docs/ subdirectories
- Organize documentation by category:
  • docs/troubleshooting/ (1 file)  - Technical troubleshooting guides
  • docs/deployment/      (4 files) - Deployment and security documentation
  • docs/guides/          (3 files) - Feature-specific guides
  • docs/planning/        (4 files) - Planning and improvement proposals

Root directory cleanup:
- Reduced from 16 to 4 markdown files in root
- Only essential project files remain:
  • CLAUDE.md (AI instructions)
  • README.md (Main project readme)
  • CLEANUP_PLAN.md (Current cleanup plan)
  • SRC_STRUCTURE_IMPROVEMENTS.md (Structure improvements)

This improves:
 Documentation discoverability
 Logical organization by purpose
 Clean root directory
 Better maintainability
2025-10-05 11:05:04 +02:00

196 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\Http\HttpRequest;
use App\Framework\Router\Result\FileResult;
use App\Framework\Exception\FrameworkException;
use App\Framework\Filesystem\FilePath;
use App\Framework\Http\MimeType;
use App\Framework\Core\ValueObjects\FileSize;
use App\Framework\Core\ValueObjects\Hash;
use App\Framework\Ulid\Ulid;
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);
}
});