ldc-file-storage-service/tests/Unit/Lib/ValueObjects/SanitizedFileTest.php

163 lines
5.3 KiB
PHP
Raw Normal View History

<?php
declare(strict_types=1);
namespace Uwil\Storage\Tests\Unit\Lib\ValueObjects;
use Uwil\Storage\Exceptions\UnexpectedStorageException;
use Uwil\Storage\Lib\ValueObjects\FileStream;
use Uwil\Storage\Lib\ValueObjects\SanitizedFile;
covers(SanitizedFile::class);
describe('SanitizedFile instantiation', function (): void {
it('can instantiate with all valid parameters', function (): void {
// GIVEN
$stream = FileStream::fromString('file content');
$originalName = 'My Document (1).pdf';
$sanitizedName = 'my-document-1.pdf';
$mimeType = 'application/pdf';
$size = 12;
// WHEN
$vo = new SanitizedFile(
originalName: $originalName,
sanitizedName: $sanitizedName,
contents: $stream,
mimeType: $mimeType,
size: $size
);
// THEN
expect($vo)->toBeInstanceOf(SanitizedFile::class)
->and($vo->originalName)->toBe($originalName)
->and($vo->sanitizedName)->toBe($sanitizedName)
->and($vo->contents)->toBe($stream)
->and($vo->mimeType)->toBe($mimeType)
->and($vo->size)->toBe($size);
});
it('can instantiate with default optional parameters as null', function (): void {
// GIVEN
$stream = FileStream::fromString('another content');
$originalName = 'photo.png';
$sanitizedName = 'photo.png';
// WHEN
$vo = new SanitizedFile(
originalName: $originalName,
sanitizedName: $sanitizedName,
contents: $stream
);
// THEN
expect($vo)->toBeInstanceOf(SanitizedFile::class)
->and($vo->originalName)->toBe($originalName)
->and($vo->sanitizedName)->toBe($sanitizedName)
->and($vo->contents)->toBe($stream)
->and($vo->mimeType)->toBeNull()
->and($vo->size)->toBeNull();
});
});
describe('SanitizedFile originalName validation', function (): void {
it('throws exception if originalName is empty or only whitespace', function (string $invalidName): void {
// GIVEN
$stream = FileStream::fromString('dummy');
$sanitizedName = 'valid-name.txt';
// WHEN
$action = fn () => new SanitizedFile(
originalName: $invalidName,
sanitizedName: $sanitizedName,
contents: $stream
);
// THEN
expect($action)->toThrow(
UnexpectedStorageException::class,
'Original name cannot be empty.'
);
})->with([
'empty string' => '',
'spaces only' => ' ',
'tabs and newlines' => "\t \n \r",
]);
});
describe('SanitizedFile sanitizedName validation', function (): void {
it('throws exception if sanitizedName is empty or only whitespace', function (string $invalidName): void {
// GIVEN
$stream = FileStream::fromString('dummy');
$originalName = 'valid_original.txt';
// WHEN
$action = fn () => new SanitizedFile(
originalName: $originalName,
sanitizedName: $invalidName,
contents: $stream
);
// THEN
expect($action)->toThrow(
UnexpectedStorageException::class,
'Sanitized name cannot be empty.'
);
})->with([
'empty string' => '',
'spaces only' => ' ',
'tabs and newlines' => "\t \n",
]);
it('throws exception if sanitizedName contains invalid characters', function (string $invalidName): void {
// GIVEN
$stream = FileStream::fromString('dummy');
$originalName = 'original.txt';
// WHEN
$action = fn () => new SanitizedFile(
originalName: $originalName,
sanitizedName: $invalidName,
contents: $stream
);
// THEN
expect($action)->toThrow(
UnexpectedStorageException::class,
'Sanitized name contains invalid characters.'
);
})->with([
'contains space' => 'file name.txt',
'contains slash' => 'dir/file.txt',
'contains backslash' => 'dir\\file.txt',
'contains question' => 'file?.txt',
'contains hash' => 'file#name.txt',
'contains at symbol' => 'file@name.txt',
'contains accented é' => 'été.pdf',
'contains parenthesis' => 'file(1).pdf',
'contains emoji' => 'file🔥.txt',
]);
it('accepts valid sanitizedName containing allowed characters', function (string $validName): void {
// GIVEN
$stream = FileStream::fromString('dummy');
$originalName = 'original.txt';
// WHEN
$vo = new SanitizedFile(
originalName: $originalName,
sanitizedName: $validName,
contents: $stream
);
// THEN
expect($vo)->toBeInstanceOf(SanitizedFile::class)
->and($vo->sanitizedName)->toBe($validName);
})->with([
'lowercase alphanumeric' => 'abc123.txt',
'uppercase letters' => 'FILE_NAME.PDF',
'hyphens and dots' => 'my-custom-file.tar.gz',
'underscores' => 'report_final_2026.csv',
]);
});