create('document.txt', 10, 'text/plain'); $result = $service->createForUpload($file, 'misc', 'local'); expect($result)->toBeNull(); }); it('creates thumbnail for large images', function (): void { if (!function_exists('imagecreatetruecolor')) { $this->markTestSkipped('GD extension not available.'); } Storage::fake('local'); Setting::updateOrCreate(['key' => 'attachments.create_thumbnails'], ['value' => 'true']); Setting::updateOrCreate(['key' => 'attachments.thumbnail_max_width'], ['value' => '100']); Setting::updateOrCreate(['key' => 'attachments.thumbnail_max_height'], ['value' => '100']); Setting::updateOrCreate(['key' => 'attachments.thumbnail_quality'], ['value' => '80']); $service = new AttachmentThumbnailService(); $file = UploadedFile::fake()->image('photo.jpg', 800, 600); $result = $service->createForUpload($file, 'threads/10', 'local'); expect($result)->not->toBeNull(); expect($result)->toHaveKeys(['path', 'mime', 'size']); Storage::disk('local')->assertExists($result['path']); }); it('skips thumbnail when disabled or too small', function (): void { if (!function_exists('imagecreatetruecolor')) { $this->markTestSkipped('GD extension not available.'); } Storage::fake('local'); Setting::updateOrCreate(['key' => 'attachments.create_thumbnails'], ['value' => 'false']); Setting::updateOrCreate(['key' => 'attachments.thumbnail_max_width'], ['value' => '300']); Setting::updateOrCreate(['key' => 'attachments.thumbnail_max_height'], ['value' => '300']); $service = new AttachmentThumbnailService(); $file = UploadedFile::fake()->image('small.jpg', 100, 100); $result = $service->createForUpload($file, 'threads/1', 'local'); expect($result)->toBeNull(); }); it('skips thumbnail when image is within size limits', function (): void { if (!function_exists('imagecreatetruecolor')) { $this->markTestSkipped('GD extension not available.'); } Storage::fake('local'); Setting::updateOrCreate(['key' => 'attachments.create_thumbnails'], ['value' => 'true']); Setting::updateOrCreate(['key' => 'attachments.thumbnail_max_width'], ['value' => '300']); Setting::updateOrCreate(['key' => 'attachments.thumbnail_max_height'], ['value' => '300']); $service = new AttachmentThumbnailService(); $file = UploadedFile::fake()->image('small.jpg', 100, 100); $result = $service->createForUpload($file, 'threads/1', 'local'); expect($result)->toBeNull(); }); it('returns null when max dimensions are invalid', function (): void { if (!function_exists('imagecreatetruecolor')) { $this->markTestSkipped('GD extension not available.'); } Storage::fake('local'); Setting::updateOrCreate(['key' => 'attachments.create_thumbnails'], ['value' => 'true']); Setting::updateOrCreate(['key' => 'attachments.thumbnail_max_width'], ['value' => '0']); Setting::updateOrCreate(['key' => 'attachments.thumbnail_max_height'], ['value' => '0']); $service = new AttachmentThumbnailService(); $file = UploadedFile::fake()->image('photo.jpg', 800, 600); $result = $service->createForUpload($file, 'threads/1', 'local'); expect($result)->toBeNull(); }); it('returns null for invalid image payloads', function (): void { Storage::fake('local'); Setting::updateOrCreate(['key' => 'attachments.create_thumbnails'], ['value' => 'true']); Setting::updateOrCreate(['key' => 'attachments.thumbnail_max_width'], ['value' => '100']); Setting::updateOrCreate(['key' => 'attachments.thumbnail_max_height'], ['value' => '100']); $service = new AttachmentThumbnailService(); $file = UploadedFile::fake()->create('bad.jpg', 10, 'image/jpeg'); $result = $service->createForUpload($file, 'threads/1', 'local'); expect($result)->toBeNull(); }); it('creates thumbnail for existing attachments', function (): void { if (!function_exists('imagecreatetruecolor')) { $this->markTestSkipped('GD extension not available.'); } Storage::fake('local'); Setting::updateOrCreate(['key' => 'attachments.create_thumbnails'], ['value' => 'true']); Setting::updateOrCreate(['key' => 'attachments.thumbnail_max_width'], ['value' => '100']); Setting::updateOrCreate(['key' => 'attachments.thumbnail_max_height'], ['value' => '100']); $category = \App\Models\Forum::create([ 'name' => 'Category', 'description' => null, 'type' => 'category', 'parent_id' => null, 'position' => 1, ]); $forum = \App\Models\Forum::create([ 'name' => 'Forum', 'description' => null, 'type' => 'forum', 'parent_id' => $category->id, 'position' => 1, ]); $thread = \App\Models\Thread::create([ 'forum_id' => $forum->id, 'user_id' => null, 'title' => 'Thread', 'body' => 'Body', ]); $image = UploadedFile::fake()->image('photo.jpg', 800, 600); $path = "attachments/threads/{$thread->id}/photo.jpg"; Storage::disk('local')->put($path, file_get_contents($image->getPathname())); $attachment = \App\Models\Attachment::create([ 'thread_id' => $thread->id, 'post_id' => null, 'attachment_extension_id' => null, 'attachment_group_id' => null, 'user_id' => null, 'disk' => 'local', 'path' => $path, 'original_name' => 'photo.jpg', 'extension' => 'jpg', 'mime_type' => 'image/jpeg', 'size_bytes' => 1234, ]); $service = new AttachmentThumbnailService(); $result = $service->createForAttachment($attachment, true); expect($result)->not->toBeNull(); Storage::disk('local')->assertExists($result['path']); }); it('returns null for attachments without stored files', function (): void { Storage::fake('local'); $category = \App\Models\Forum::create([ 'name' => 'Category', 'description' => null, 'type' => 'category', 'parent_id' => null, 'position' => 1, ]); $forum = \App\Models\Forum::create([ 'name' => 'Forum', 'description' => null, 'type' => 'forum', 'parent_id' => $category->id, 'position' => 1, ]); $thread = \App\Models\Thread::create([ 'forum_id' => $forum->id, 'user_id' => null, 'title' => 'Thread', 'body' => 'Body', ]); $attachment = \App\Models\Attachment::create([ 'thread_id' => $thread->id, 'post_id' => null, 'attachment_extension_id' => null, 'attachment_group_id' => null, 'user_id' => null, 'disk' => 'local', 'path' => "attachments/threads/{$thread->id}/missing.jpg", 'original_name' => 'missing.jpg', 'extension' => 'jpg', 'mime_type' => 'image/jpeg', 'size_bytes' => 10, ]); $service = new AttachmentThumbnailService(); $result = $service->createForAttachment($attachment, true); expect($result)->toBeNull(); }); it('returns null when thumbnail already exists and not forcing', function (): void { Storage::fake('local'); $category = \App\Models\Forum::create([ 'name' => 'Category', 'description' => null, 'type' => 'category', 'parent_id' => null, 'position' => 1, ]); $forum = \App\Models\Forum::create([ 'name' => 'Forum', 'description' => null, 'type' => 'forum', 'parent_id' => $category->id, 'position' => 1, ]); $thread = \App\Models\Thread::create([ 'forum_id' => $forum->id, 'user_id' => null, 'title' => 'Thread', 'body' => 'Body', ]); $attachment = \App\Models\Attachment::create([ 'thread_id' => $thread->id, 'post_id' => null, 'attachment_extension_id' => null, 'attachment_group_id' => null, 'user_id' => null, 'disk' => 'local', 'path' => "attachments/threads/{$thread->id}/photo.jpg", 'thumbnail_path' => "attachments/threads/{$thread->id}/thumbs/existing.jpg", 'original_name' => 'photo.jpg', 'extension' => 'jpg', 'mime_type' => 'image/jpeg', 'size_bytes' => 10, ]); Storage::disk('local')->put($attachment->thumbnail_path, 'thumb'); $service = new AttachmentThumbnailService(); $result = $service->createForAttachment($attachment, false); expect($result)->toBeNull(); }); it('returns null for non-image attachments', function (): void { Storage::fake('local'); $category = \App\Models\Forum::create([ 'name' => 'Category', 'description' => null, 'type' => 'category', 'parent_id' => null, 'position' => 1, ]); $forum = \App\Models\Forum::create([ 'name' => 'Forum', 'description' => null, 'type' => 'forum', 'parent_id' => $category->id, 'position' => 1, ]); $thread = \App\Models\Thread::create([ 'forum_id' => $forum->id, 'user_id' => null, 'title' => 'Thread', 'body' => 'Body', ]); $attachment = \App\Models\Attachment::create([ 'thread_id' => $thread->id, 'post_id' => null, 'attachment_extension_id' => null, 'attachment_group_id' => null, 'user_id' => null, 'disk' => 'local', 'path' => "attachments/threads/{$thread->id}/doc.pdf", 'original_name' => 'doc.pdf', 'extension' => 'pdf', 'mime_type' => 'application/pdf', 'size_bytes' => 10, ]); $service = new AttachmentThumbnailService(); $result = $service->createForAttachment($attachment, true); expect($result)->toBeNull(); }); it('uses post scope when creating thumbnails', function (): void { if (!function_exists('imagecreatetruecolor')) { $this->markTestSkipped('GD extension not available.'); } Storage::fake('local'); Setting::updateOrCreate(['key' => 'attachments.create_thumbnails'], ['value' => 'true']); Setting::updateOrCreate(['key' => 'attachments.thumbnail_max_width'], ['value' => '100']); Setting::updateOrCreate(['key' => 'attachments.thumbnail_max_height'], ['value' => '100']); $category = \App\Models\Forum::create([ 'name' => 'Category', 'description' => null, 'type' => 'category', 'parent_id' => null, 'position' => 1, ]); $forum = \App\Models\Forum::create([ 'name' => 'Forum', 'description' => null, 'type' => 'forum', 'parent_id' => $category->id, 'position' => 1, ]); $thread = \App\Models\Thread::create([ 'forum_id' => $forum->id, 'user_id' => null, 'title' => 'Thread', 'body' => 'Body', ]); $post = \App\Models\Post::create([ 'thread_id' => $thread->id, 'user_id' => null, 'body' => 'Post', ]); $image = UploadedFile::fake()->image('photo.png', 800, 600); $path = "attachments/posts/{$post->id}/photo.png"; Storage::disk('local')->put($path, file_get_contents($image->getPathname())); $attachment = \App\Models\Attachment::create([ 'thread_id' => null, 'post_id' => $post->id, 'attachment_extension_id' => null, 'attachment_group_id' => null, 'user_id' => null, 'disk' => 'local', 'path' => $path, 'original_name' => 'photo.png', 'extension' => 'png', 'mime_type' => 'image/png', 'size_bytes' => 1234, ]); $service = new AttachmentThumbnailService(); $result = $service->createForAttachment($attachment, true); expect($result)->not->toBeNull(); expect($result['path'])->toContain("attachments/posts/{$post->id}/thumbs/"); }); it('returns null when mime is unsupported even if image data is valid', function (): void { if (!function_exists('imagecreatetruecolor')) { $this->markTestSkipped('GD extension not available.'); } Storage::fake('local'); Setting::updateOrCreate(['key' => 'attachments.create_thumbnails'], ['value' => 'true']); Setting::updateOrCreate(['key' => 'attachments.thumbnail_max_width'], ['value' => '100']); Setting::updateOrCreate(['key' => 'attachments.thumbnail_max_height'], ['value' => '100']); $category = \App\Models\Forum::create([ 'name' => 'Category', 'description' => null, 'type' => 'category', 'parent_id' => null, 'position' => 1, ]); $forum = \App\Models\Forum::create([ 'name' => 'Forum', 'description' => null, 'type' => 'forum', 'parent_id' => $category->id, 'position' => 1, ]); $thread = \App\Models\Thread::create([ 'forum_id' => $forum->id, 'user_id' => null, 'title' => 'Thread', 'body' => 'Body', ]); $image = UploadedFile::fake()->image('photo.png', 800, 600); $path = "attachments/threads/{$thread->id}/photo.png"; Storage::disk('local')->put($path, file_get_contents($image->getPathname())); $attachment = \App\Models\Attachment::create([ 'thread_id' => $thread->id, 'post_id' => null, 'attachment_extension_id' => null, 'attachment_group_id' => null, 'user_id' => null, 'disk' => 'local', 'path' => $path, 'original_name' => 'photo.png', 'extension' => 'png', 'mime_type' => 'image/avif', 'size_bytes' => 1234, ]); $service = new AttachmentThumbnailService(); $result = $service->createForAttachment($attachment, true); expect($result)->toBeNull(); }); it('creates thumbnails for gif images', function (): void { if (!function_exists('imagecreatetruecolor')) { $this->markTestSkipped('GD extension not available.'); } if (!function_exists('imagegif')) { $this->markTestSkipped('GIF support not available.'); } Storage::fake('local'); Setting::updateOrCreate(['key' => 'attachments.create_thumbnails'], ['value' => 'true']); Setting::updateOrCreate(['key' => 'attachments.thumbnail_max_width'], ['value' => '100']); Setting::updateOrCreate(['key' => 'attachments.thumbnail_max_height'], ['value' => '100']); $service = new AttachmentThumbnailService(); $file = UploadedFile::fake()->image('photo.gif', 800, 600); $result = $service->createForUpload($file, 'threads/1', 'local'); expect($result)->not->toBeNull(); Storage::disk('local')->assertExists($result['path']); });