ldc-file-storage-service/tests/Unit/Lib/PathGenerators/DateHashPathGeneratorTest.php

164 lines
5.4 KiB
PHP
Raw Permalink Normal View History

<?php
declare(strict_types=1);
namespace Uwil\Storage\Tests\Unit\Lib\PathGenerators;
use Uwil\Storage\Config\StorageServiceConfig;
use Uwil\Storage\Lib\PathGenerators\DateHashPathGenerator;
use Uwil\Storage\Lib\ValueObjects\DiskName;
use Uwil\Storage\Lib\ValueObjects\FileStream;
use Uwil\Storage\Lib\ValueObjects\SanitizedFile;
use Uwil\Storage\Lib\ValueObjects\StorageFilePath;
covers(DateHashPathGenerator::class);
describe('DateHashPathGenerator generation without directory', function (): void {
it('generates a storage file path with UTC date segments and hash prefix', function (): void {
// GIVEN
$generator = new DateHashPathGenerator();
$disk = new DiskName('local', 'local');
$sanitizedFile = new SanitizedFile(
originalName: 'document.pdf',
sanitizedName: 'document.pdf',
contents: FileStream::fromString('test content')
);
$expectedYear = gmdate('Y');
$expectedMonth = gmdate('m');
$expectedDay = gmdate('d');
$expectedHash = substr(hash('sha256', 'document.pdf'), 0, 2);
// WHEN
$result = $generator->generate($disk, $sanitizedFile);
// THEN
expect($result)->toBeInstanceOf(StorageFilePath::class);
$pattern = sprintf(
'#^%s/%s/%s/%s/document-[a-f0-9]{8}\.pdf$#',
$expectedYear,
$expectedMonth,
$expectedDay,
$expectedHash
);
expect($result->value)->toMatch($pattern);
});
it('generates a path for a file without extension', function (): void {
// GIVEN
$generator = new DateHashPathGenerator();
$disk = new DiskName('local', 'local');
$sanitizedFile = new SanitizedFile(
originalName: 'LICENSE',
sanitizedName: 'LICENSE',
contents: FileStream::fromString('MIT License')
);
$expectedHash = substr(hash('sha256', 'LICENSE'), 0, 2);
// WHEN
$result = $generator->generate($disk, $sanitizedFile);
// THEN
expect($result)->toBeInstanceOf(StorageFilePath::class);
$pattern = sprintf(
'#^%s/%s/%s/%s/license-[a-f0-9]{8}$#',
gmdate('Y'),
gmdate('m'),
gmdate('d'),
$expectedHash
);
expect($result->value)->toMatch($pattern);
});
it('generates unique paths for identical files generated consecutively', function (): void {
// GIVEN
$generator = new DateHashPathGenerator();
$disk = new DiskName('local', 'local');
$sanitizedFile = new SanitizedFile(
originalName: 'photo.jpg',
sanitizedName: 'photo.jpg',
contents: FileStream::fromString('image bytes')
);
// WHEN
$path1 = $generator->generate($disk, $sanitizedFile);
$path2 = $generator->generate($disk, $sanitizedFile);
// THEN
expect($path1->value)->not->toBe($path2->value);
});
});
describe('DateHashPathGenerator generation with prefix', function (): void {
it('prepends the configured prefix to the path', function (): void {
// GIVEN
$config = new StorageServiceConfig(
defaultDisk: 'local',
eligibleDisks: ['local'],
laravelExistingDisks: [(object) ['disk' => 'local', 'driver' => 'local']],
allowedExtensions: ['png'],
prefix: 'avatars/users'
);
$generator = new DateHashPathGenerator($config);
$disk = new DiskName('local', 'local');
$sanitizedFile = new SanitizedFile(
originalName: 'avatar.png',
sanitizedName: 'avatar.png',
contents: FileStream::fromString('image data')
);
// WHEN
$result = $generator->generate($disk, $sanitizedFile);
// THEN
$expectedHash = substr(hash('sha256', 'avatar.png'), 0, 2);
$pattern = sprintf(
'#^avatars/users/%s/%s/%s/%s/avatar-[a-f0-9]{8}\.png$#',
gmdate('Y'),
gmdate('m'),
gmdate('d'),
$expectedHash
);
expect($result->value)->toMatch($pattern);
});
});
describe('DateHashPathGenerator filename slugging', function (): void {
it('slugs filename containing underscores or mixed case', function (): void {
// GIVEN
$generator = new DateHashPathGenerator();
$disk = new DiskName('local', 'local');
$sanitizedFile = new SanitizedFile(
originalName: 'My_Monthly_Report_2026.csv',
sanitizedName: 'My_Monthly_Report_2026.csv',
contents: FileStream::fromString('a,b,c')
);
// WHEN
$result = $generator->generate($disk, $sanitizedFile);
// THEN
expect($result->value)->toMatch('#/my-monthly-report-2026-[a-f0-9]{8}\.csv$#');
});
it('falls back to "file" when filename produces an empty slug', function (): void {
// GIVEN
$generator = new DateHashPathGenerator();
$disk = new DiskName('local', 'local');
$sanitizedFile = new SanitizedFile(
originalName: '.env.backup',
sanitizedName: '.backup',
contents: FileStream::fromString('KEY=VAL')
);
// WHEN
$result = $generator->generate($disk, $sanitizedFile);
// THEN
expect($result->value)->toMatch('#/file-[a-f0-9]{8}\.backup$#');
});
});