imageRepository = Mockery::mock(ImageRepository::class); $this->uploadSecurityService = Mockery::mock(); $this->imageProcessor = Mockery::mock(); $this->imageVariantRepository = Mockery::mock(); $this->ulidGenerator = Mockery::mock(); $this->pathProvider = Mockery::mock(); $this->clock = Mockery::mock(); $this->controller = new ImageApiController( $this->imageRepository, $this->uploadSecurityService, $this->imageProcessor, $this->imageVariantRepository, $this->ulidGenerator, $this->pathProvider, $this->clock ); // Test images $this->testImages = [ new Image( ulid: Ulid::fromString('01ABCDEFGHIJKLMNOPQRSTUVWX'), filename: 'image1.jpg', originalFilename: 'original1.jpg', mimeType: MimeType::fromString('image/jpeg'), fileSize: FileSize::fromBytes(1024), width: 800, height: 600, hash: Hash::fromString('hash1'), path: FilePath::create('/test/path'), altText: 'Test image 1' ), new Image( ulid: Ulid::fromString('01BCDEFGHIJKLMNOPQRSTUVWY'), filename: 'image2.png', originalFilename: 'original2.png', mimeType: MimeType::fromString('image/png'), fileSize: FileSize::fromBytes(2048), width: 400, height: 300, hash: Hash::fromString('hash2'), path: FilePath::create('/test/path'), altText: 'Test image 2' ), ]; }); afterEach(function () { Mockery::close(); }); it('can get paginated list of images', function () { // Arrange $request = Mockery::mock(HttpRequest::class); $request->queryParams = [ 'limit' => '10', 'offset' => '0', ]; $this->imageRepository ->shouldReceive('findAll') ->with(10, 0, null) ->andReturn($this->testImages); $this->imageRepository ->shouldReceive('count') ->with(null) ->andReturn(2); // Act $response = $this->controller->getImages($request); // Assert expect($response)->toBeInstanceOf(JsonResponse::class); $data = $response->getData(); expect($data['images'])->toHaveCount(2); expect($data['pagination']['total'])->toBe(2); expect($data['pagination']['limit'])->toBe(10); expect($data['pagination']['offset'])->toBe(0); expect($data['pagination']['has_more'])->toBeFalse(); }); it('can search images with query parameter', function () { // Arrange $request = Mockery::mock(HttpRequest::class); $request->queryParams = [ 'limit' => '50', 'offset' => '0', 'search' => 'test', ]; $this->imageRepository ->shouldReceive('findAll') ->with(50, 0, 'test') ->andReturn([$this->testImages[0]]); $this->imageRepository ->shouldReceive('count') ->with('test') ->andReturn(1); // Act $response = $this->controller->getImages($request); // Assert $data = $response->getData(); expect($data['images'])->toHaveCount(1); expect($data['pagination']['total'])->toBe(1); }); it('returns correct image URLs pointing to ShowImage controller', function () { // Arrange $request = Mockery::mock(HttpRequest::class); $request->queryParams = []; $this->imageRepository ->shouldReceive('findAll') ->andReturn([$this->testImages[0]]); $this->imageRepository ->shouldReceive('count') ->andReturn(1); // Act $response = $this->controller->getImages($request); // Assert $data = $response->getData(); $image = $data['images'][0]; expect($image['url'])->toBe('/images/image1.jpg'); expect($image['thumbnail_url'])->toBe('/images/image1.jpg'); // Same for non-thumbnail }); it('generates correct thumbnail URLs for original images', function () { // Test with original filename $originalImage = new Image( ulid: Ulid::generate(), filename: 'test_original.jpg', originalFilename: 'test.jpg', mimeType: MimeType::fromString('image/jpeg'), fileSize: FileSize::fromBytes(1024), width: 800, height: 600, hash: Hash::fromString('hash'), path: FilePath::create('/test'), altText: 'Test' ); $request = Mockery::mock(HttpRequest::class); $request->queryParams = []; $this->imageRepository ->shouldReceive('findAll') ->andReturn([$originalImage]); $this->imageRepository ->shouldReceive('count') ->andReturn(1); $response = $this->controller->getImages($request); $data = $response->getData(); $image = $data['images'][0]; expect($image['url'])->toBe('/images/test_original.jpg'); expect($image['thumbnail_url'])->toBe('/images/test_thumbnail.jpg'); }); it('can get single image by ULID', function () { // Arrange $ulid = '01ABCDEFGHIJKLMNOPQRSTUVWX'; $testImage = $this->testImages[0]; $this->imageRepository ->shouldReceive('findByUlid') ->with($ulid) ->andReturn($testImage); // Act $response = $this->controller->getImage($ulid); // Assert expect($response)->toBeInstanceOf(JsonResponse::class); $data = $response->getData(); expect($data['ulid'])->toBe($ulid); expect($data['filename'])->toBe('image1.jpg'); expect($data['url'])->toBe('/media/images/test/path/image1.jpg'); }); it('throws NotFound exception when image ULID not found', function () { // Arrange $ulid = 'NONEXISTENT_ULID_123456789'; $this->imageRepository ->shouldReceive('findByUlid') ->with($ulid) ->andReturn(null); // Act & Assert expect(fn () => $this->controller->getImage($ulid)) ->toThrow(NotFound::class, "Image with ULID {$ulid} not found"); }); it('can search images with advanced parameters', function () { // Arrange $request = Mockery::mock(HttpRequest::class); $request->queryParams = [ 'q' => 'landscape', 'type' => 'jpeg', 'min_width' => '800', 'min_height' => '600', ]; $this->imageRepository ->shouldReceive('search') ->with('landscape', 'jpeg', 800, 600) ->andReturn([$this->testImages[0]]); // Act $response = $this->controller->searchImages($request); // Assert expect($response)->toBeInstanceOf(JsonResponse::class); $data = $response->getData(); expect($data['results'])->toHaveCount(1); expect($data['count'])->toBe(1); }); it('handles empty search results', function () { // Arrange $request = Mockery::mock(HttpRequest::class); $request->queryParams = ['q' => 'nonexistent']; $this->imageRepository ->shouldReceive('search') ->andReturn([]); // Act $response = $this->controller->searchImages($request); // Assert $data = $response->getData(); expect($data['results'])->toBeEmpty(); expect($data['count'])->toBe(0); });