Files
radicall/tests/Feature/Services/FileStorageServiceTest.php
T

183 lines
6.7 KiB
PHP

<?php
namespace Tests\Feature\Services;
use App\Enums\MediaDiskEnum;
use App\Models\Medium;
use App\Services\FileStorageService;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Illuminate\Http\UploadedFile;
use Illuminate\Support\Facades\Storage;
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
use Tests\TestCase;
class FileStorageServiceTest extends TestCase
{
use RefreshDatabase;
protected FileStorageService $service;
protected function setUp(): void
{
parent::setUp();
Storage::fake('public');
Storage::fake('private');
$this->service = app(FileStorageService::class);
}
protected function storedMedium(string $disk = 'private', string $content = 'hello'): Medium
{
$medium = Medium::factory()->create(['disk' => $disk, 'path' => 'files/sample.txt', 'filename' => 'sample.txt', 'mime_type' => 'text/plain']);
Storage::disk($disk)->put($medium->path, $content);
return $medium;
}
public function test_store_file_saves_public_file_and_medium_with_url(): void
{
$file = UploadedFile::fake()->create('My Scan.pdf', 12, 'application/pdf');
$medium = $this->service->storeFile($file);
$this->assertSame(MediaDiskEnum::Public, $medium->disk);
$this->assertMatchesRegularExpression('/^\d+_[A-Za-z0-9]{6}_my-scan\.pdf$/', $medium->filename);
$this->assertSame('files/' . $medium->filename, $medium->path);
$this->assertSame(Storage::disk('public')->url($medium->path), $medium->url);
$this->assertSame(12 * 1024, $medium->size);
$this->assertSame('application/pdf', $medium->mime_type);
Storage::disk('public')->assertExists($medium->path);
}
public function test_store_file_saves_private_file_without_url_in_custom_directory(): void
{
$medium = $this->service->storeFile(UploadedFile::fake()->image('x.png'), 'private', 'reports');
$this->assertSame(MediaDiskEnum::Private, $medium->disk);
$this->assertNull($medium->url);
$this->assertStringStartsWith('reports/', $medium->path);
Storage::disk('private')->assertExists($medium->path);
Storage::disk('public')->assertMissing($medium->path);
}
public function test_store_file_generates_distinct_filenames_for_same_upload_name(): void
{
$first = $this->service->storeFile(UploadedFile::fake()->image('same.png'));
$second = $this->service->storeFile(UploadedFile::fake()->image('same.png'));
$this->assertNotSame($first->filename, $second->filename);
}
public function test_move_to_disk_moves_file_from_private_to_public_and_sets_url(): void
{
$medium = $this->storedMedium('private');
$this->assertTrue($this->service->moveToDisk($medium, 'public'));
$medium->refresh();
$this->assertSame(MediaDiskEnum::Public, $medium->disk);
$this->assertSame(Storage::disk('public')->url('files/sample.txt'), $medium->url);
Storage::disk('public')->assertExists('files/sample.txt');
Storage::disk('private')->assertMissing('files/sample.txt');
$this->assertSame('hello', Storage::disk('public')->get('files/sample.txt'));
}
public function test_move_to_disk_moves_file_to_private_and_clears_url(): void
{
$medium = $this->storedMedium('public');
$medium->update(['url' => 'http://example.test/files/sample.txt']);
$this->assertTrue($this->service->moveToDisk($medium, 'private'));
$medium->refresh();
$this->assertSame(MediaDiskEnum::Private, $medium->disk);
$this->assertNull($medium->url);
Storage::disk('private')->assertExists('files/sample.txt');
Storage::disk('public')->assertMissing('files/sample.txt');
}
public function test_move_to_disk_returns_true_without_changes_for_same_disk(): void
{
$medium = $this->storedMedium('private');
$this->assertTrue($this->service->moveToDisk($medium, 'private'));
Storage::disk('private')->assertExists('files/sample.txt');
}
public function test_move_to_disk_returns_false_when_source_file_is_missing(): void
{
$medium = Medium::factory()->private()->create(['path' => 'files/missing.txt']);
$this->assertFalse($this->service->moveToDisk($medium, 'public'));
$this->assertSame(MediaDiskEnum::Private, $medium->fresh()->disk);
}
public function test_delete_medium_removes_file_and_record(): void
{
$medium = $this->storedMedium('private');
$this->service->deleteMedium($medium);
Storage::disk('private')->assertMissing('files/sample.txt');
$this->assertDatabaseMissing('media', ['id' => $medium->id]);
}
public function test_delete_medium_removes_record_even_when_file_is_missing(): void
{
$medium = Medium::factory()->private()->create(['path' => 'files/missing.txt']);
$this->service->deleteMedium($medium);
$this->assertDatabaseMissing('media', ['id' => $medium->id]);
}
public function test_download_file_returns_attachment_for_private_existing_file(): void
{
$medium = $this->storedMedium('private');
$response = $this->service->downloadFile($medium);
$this->assertStringContainsString('attachment', $response->headers->get('Content-Disposition'));
$this->assertStringContainsString('sample.txt', $response->headers->get('Content-Disposition'));
}
public function test_download_file_aborts_for_public_medium(): void
{
$medium = $this->storedMedium('public');
$this->expectException(NotFoundHttpException::class);
$this->service->downloadFile($medium);
}
public function test_download_file_aborts_when_file_is_missing(): void
{
$medium = Medium::factory()->private()->create(['path' => 'files/missing.txt']);
$this->expectException(NotFoundHttpException::class);
$this->service->downloadFile($medium);
}
public function test_serve_file_returns_inline_content_with_mime_type(): void
{
$medium = $this->storedMedium('private', 'inline body');
$response = $this->service->serveFile($medium);
$this->assertSame(200, $response->getStatusCode());
$this->assertSame('inline body', $response->getContent());
$this->assertSame('text/plain', $response->headers->get('Content-Type'));
$this->assertSame('inline; filename="sample.txt"', $response->headers->get('Content-Disposition'));
}
public function test_serve_file_aborts_for_public_medium(): void
{
$medium = $this->storedMedium('public');
$this->expectException(NotFoundHttpException::class);
$this->service->serveFile($medium);
}
}