Files
speedBB/tests/Unit/ThreadControllerUnitTest.php
tracer 160430e128
All checks were successful
CI/CD Pipeline / test (push) Successful in 10s
CI/CD Pipeline / deploy (push) Successful in 25s
Add extensive controller and model tests
2026-02-07 22:14:42 +01:00

227 lines
6.9 KiB
PHP

<?php
use App\Http\Controllers\ThreadController;
use App\Models\Attachment;
use App\Models\AttachmentGroup;
use App\Models\Forum;
use App\Models\Post;
use App\Models\Thread;
use App\Models\User;
use App\Models\Role;
use App\Models\Setting;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Storage;
function makeForumForThreadController(): Forum
{
$category = Forum::create([
'name' => 'Category',
'description' => null,
'type' => 'category',
'parent_id' => null,
'position' => 1,
]);
return Forum::create([
'name' => 'Forum',
'description' => null,
'type' => 'forum',
'parent_id' => $category->id,
'position' => 1,
]);
}
it('returns unauthorized for update when no user', function (): void {
$controller = new ThreadController();
$forum = makeForumForThreadController();
$thread = Thread::create([
'forum_id' => $forum->id,
'user_id' => null,
'title' => 'Thread',
'body' => 'Body',
]);
$request = Request::create("/api/threads/{$thread->id}", 'PATCH', [
'title' => 'New',
]);
$request->setUserResolver(fn () => null);
$response = $controller->update($request, $thread);
expect($response->getStatusCode())->toBe(401);
});
it('returns unauthorized for updateSolved when no user', function (): void {
$controller = new ThreadController();
$forum = makeForumForThreadController();
$thread = Thread::create([
'forum_id' => $forum->id,
'user_id' => null,
'title' => 'Thread',
'body' => 'Body',
]);
$request = Request::create("/api/threads/{$thread->id}/solved", 'PATCH', [
'solved' => true,
]);
$request->setUserResolver(fn () => null);
$response = $controller->updateSolved($request, $thread);
expect($response->getStatusCode())->toBe(401);
});
it('serializes threads with attachments, group colors, and inline images', function (): void {
Storage::fake('public');
$forum = makeForumForThreadController();
$role = Role::create(['name' => 'ROLE_HELPER', 'color' => '#ff0000']);
$user = User::factory()->create([
'avatar_path' => 'avatars/u.png',
'location' => 'Somewhere',
]);
$user->roles()->attach($role);
Setting::updateOrCreate(['key' => 'attachments.display_images_inline'], ['value' => '1']);
$thread = Thread::create([
'forum_id' => $forum->id,
'user_id' => $user->id,
'title' => 'Thread',
'body' => 'See [attachment]image.png[/attachment]',
]);
$post = Post::create([
'thread_id' => $thread->id,
'user_id' => $user->id,
'body' => 'Reply',
]);
$group = AttachmentGroup::create([
'name' => 'Images',
'max_size_kb' => 100,
'is_active' => true,
]);
$attachment = Attachment::create([
'thread_id' => $thread->id,
'post_id' => null,
'attachment_extension_id' => null,
'attachment_group_id' => $group->id,
'user_id' => $user->id,
'disk' => 'local',
'path' => 'attachments/threads/'.$thread->id.'/image.png',
'thumbnail_path' => 'attachments/threads/'.$thread->id.'/thumbs/image.png',
'original_name' => 'image.png',
'extension' => 'png',
'mime_type' => 'image/png',
'size_bytes' => 10,
]);
$thread->load(['user.roles', 'attachments.group', 'latestPost']);
$controller = new ThreadController();
$ref = new ReflectionMethod($controller, 'serializeThread');
$ref->setAccessible(true);
$payload = $ref->invoke($controller, $thread);
expect($payload['user_avatar_url'])->not->toBeNull();
expect($payload['user_group_color'])->toBe('#ff0000');
expect($payload['attachments'][0]['group']['name'])->toBe('Images');
expect($payload['attachments'][0]['thumbnail_url'])->toContain('/thumbnail');
expect($payload['body_html'])->toContain('<img');
expect($payload['last_post_id'])->toBe($post->id);
});
it('replaces attachment tags with links when inline images disabled', function (): void {
Setting::updateOrCreate(['key' => 'attachments.display_images_inline'], ['value' => '0']);
$forum = makeForumForThreadController();
$thread = Thread::create([
'forum_id' => $forum->id,
'user_id' => null,
'title' => 'Thread',
'body' => 'See [attachment]doc.pdf[/attachment]',
]);
$attachment = 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,
]);
$controller = new ThreadController();
$ref = new ReflectionMethod($controller, 'replaceAttachmentTags');
$ref->setAccessible(true);
$result = $ref->invoke($controller, $thread->body, collect([$attachment]));
expect($result)->toContain('[url=');
expect($result)->toContain('doc.pdf');
});
it('returns body unchanged when no attachments are present', function (): void {
$controller = new ThreadController();
$ref = new ReflectionMethod($controller, 'replaceAttachmentTags');
$ref->setAccessible(true);
$result = $ref->invoke($controller, 'No attachments', []);
expect($result)->toBe('No attachments');
});
it('returns original tag when attachment name does not match', function (): void {
$forum = makeForumForThreadController();
$thread = Thread::create([
'forum_id' => $forum->id,
'user_id' => null,
'title' => 'Thread',
'body' => 'See [attachment]missing.pdf[/attachment]',
]);
$attachment = 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,
]);
$controller = new ThreadController();
$ref = new ReflectionMethod($controller, 'replaceAttachmentTags');
$ref->setAccessible(true);
$result = $ref->invoke($controller, $thread->body, collect([$attachment]));
expect($result)->toContain('[attachment]missing.pdf[/attachment]');
});
it('returns body unchanged when attachment map is empty', function (): void {
$controller = new ThreadController();
$ref = new ReflectionMethod($controller, 'replaceAttachmentTags');
$ref->setAccessible(true);
$attachment = new Attachment([
'original_name' => '',
]);
$result = $ref->invoke($controller, 'Body', collect([$attachment]));
expect($result)->toBe('Body');
});