generate($disk, $sanitizedFile); // THEN expect($result)->toBeInstanceOf(StorageFilePath::class); $filename = $result->value; expect($filename)->toMatch('#^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}\.png$#'); $uuidOnly = pathinfo($filename, PATHINFO_FILENAME); expect(Str::isUuid($uuidOnly))->toBeTrue(); }); it('generates a storage file path without extension when file has no extension', function (): void { // GIVEN $generator = new UuidPathGenerator(); $disk = new DiskName('local', 'local'); $sanitizedFile = new SanitizedFile( originalName: 'DOCKERFILE', sanitizedName: 'DOCKERFILE', contents: FileStream::fromString('FROM php:8.5') ); // WHEN $result = $generator->generate($disk, $sanitizedFile); // THEN expect($result)->toBeInstanceOf(StorageFilePath::class) ->and(Str::isUuid($result->value))->toBeTrue(); }); it('generates unique paths on successive calls for the same file', function (): void { // GIVEN $generator = new UuidPathGenerator(); $disk = new DiskName('local', 'local'); $sanitizedFile = new SanitizedFile( originalName: 'data.json', sanitizedName: 'data.json', contents: FileStream::fromString('{}') ); // WHEN $path1 = $generator->generate($disk, $sanitizedFile); $path2 = $generator->generate($disk, $sanitizedFile); // THEN expect($path1->value)->not->toBe($path2->value); }); }); describe('UuidPathGenerator generation with directory', function (): void { it('prepends the given directory to the generated UUID filename', function (): void { // GIVEN $generator = new UuidPathGenerator(); $disk = new DiskName('local', 'local'); $sanitizedFile = new SanitizedFile( originalName: 'invoice.pdf', sanitizedName: 'invoice.pdf', contents: FileStream::fromString('PDF DATA') ); $directory = 'billing/invoices'; // WHEN $result = $generator->generate($disk, $sanitizedFile, $directory); // THEN expect($result)->toBeInstanceOf(StorageFilePath::class) ->and($result->value)->toStartWith('billing/invoices/') ->and($result->value)->toMatch('#^billing/invoices/[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}\.pdf$#'); }); it('trims leading and trailing slashes from the directory', function (string $directory): void { // GIVEN $generator = new UuidPathGenerator(); $disk = new DiskName('local', 'local'); $sanitizedFile = new SanitizedFile( originalName: 'file.txt', sanitizedName: 'file.txt', contents: FileStream::fromString('text') ); // WHEN $result = $generator->generate($disk, $sanitizedFile, $directory); // THEN expect($result->value)->toStartWith('custom/path/'); })->with([ 'leading slash' => '/custom/path', 'trailing slash' => 'custom/path/', 'both slashes' => '/custom/path/', 'multiple outer slashes' => '///custom/path///', ]); it('ignores empty or slash-only directory', function (string $directory): void { // GIVEN $generator = new UuidPathGenerator(); $disk = new DiskName('local', 'local'); $sanitizedFile = new SanitizedFile( originalName: 'file.txt', sanitizedName: 'file.txt', contents: FileStream::fromString('text') ); // WHEN $result = $generator->generate($disk, $sanitizedFile, $directory); // THEN expect($result->value)->toMatch('#^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}\.txt$#'); })->with([ 'empty string' => '', 'single slash' => '/', 'multi slashes' => '///', ]); });