ldc-file-storage-service/tests/Unit/Config/StorageServiceConfigTest.php

512 lines
17 KiB
PHP

<?php
declare(strict_types=1);
namespace Uwil\Storage\Tests\Unit\Config;
use Illuminate\Support\Facades\Storage;
use Uwil\Storage\Config\StorageServiceConfig;
use Uwil\Storage\Exceptions\UnexpectedStorageException;
use Uwil\Storage\Lib\ValueObjects\DiskName;
covers(StorageServiceConfig::class);
describe('StorageServiceConfig instantiation', function (): void {
it('can instantiate with valid configuration', function (): void {
// GIVEN
$defaultDisk = 'local';
$eligibleDisks = ['local'];
$laravelExistingDisks = [(object) ['disk' => 'local', 'driver' => 'local']];
$allowedExtensions = ['jpg', 'png', 'pdf'];
// WHEN
$config = new StorageServiceConfig(
defaultDisk: $defaultDisk,
eligibleDisks: $eligibleDisks,
laravelExistingDisks: $laravelExistingDisks,
allowedExtensions: $allowedExtensions
);
// THEN
expect($config)->toBeInstanceOf(StorageServiceConfig::class)
->and($config->getDefaultDisk())->toBeInstanceOf(DiskName::class)
->and($config->getDefaultDisk()->value)->toBe('local')
->and($config->getEligibleDisks())->toHaveCount(1)
->and($config->getEligibleDisks()[0]->value)->toBe('local')
->and($config->getAllowedExtensions())->toBe(['jpg', 'png', 'pdf']);
});
});
describe('StorageServiceConfig disk validation', function (): void {
it('throws exception if default disk does not exist', function (): void {
// GIVEN
$defaultDisk = 'non_existent_disk';
$eligibleDisks = ['local'];
$laravelExistingDisks = [(object) ['disk' => 'local', 'driver' => 'local']];
$allowedExtensions = ['pdf'];
// WHEN
$action = fn () => new StorageServiceConfig(
defaultDisk: $defaultDisk,
eligibleDisks: $eligibleDisks,
laravelExistingDisks: $laravelExistingDisks,
allowedExtensions: $allowedExtensions
);
// THEN
expect($action)->toThrow(
UnexpectedStorageException::class,
'Default disk does not exist'
);
});
it('throws exception if an eligible disk does not exist', function (): void {
// GIVEN
$defaultDisk = 'local';
$eligibleDisks = ['local', 'unknown_disk'];
$laravelExistingDisks = [(object) ['disk' => 'local', 'driver' => 'local']];
$allowedExtensions = ['pdf'];
// WHEN
$action = fn () => new StorageServiceConfig(
defaultDisk: $defaultDisk,
eligibleDisks: $eligibleDisks,
laravelExistingDisks: $laravelExistingDisks,
allowedExtensions: $allowedExtensions
);
// THEN
expect($action)->toThrow(
UnexpectedStorageException::class,
'Eligible disk unknown_disk does not exist'
);
});
it('throws exception if a Laravel existing disk does not exist', function (): void {
// GIVEN
$defaultDisk = 'local';
$eligibleDisks = ['local'];
$laravelExistingDisks = [
(object) ['disk' => 'local', 'driver' => 'local'],
(object) ['disk' => 'phantom_disk', 'driver' => 'local'],
];
$allowedExtensions = ['pdf'];
// WHEN
$action = fn () => new StorageServiceConfig(
defaultDisk: $defaultDisk,
eligibleDisks: $eligibleDisks,
laravelExistingDisks: $laravelExistingDisks,
allowedExtensions: $allowedExtensions
);
// THEN
expect($action)->toThrow(
UnexpectedStorageException::class,
'Laravel existing disk phantom_disk does not exist'
);
});
it('throws exception if laravelExistingDisks is empty', function (): void {
// GIVEN
$defaultDisk = 'local';
$eligibleDisks = ['local'];
$laravelExistingDisks = [];
$allowedExtensions = ['pdf'];
// WHEN
$action = fn () => new StorageServiceConfig(
defaultDisk: $defaultDisk,
eligibleDisks: $eligibleDisks,
laravelExistingDisks: $laravelExistingDisks,
allowedExtensions: $allowedExtensions
);
// THEN
expect($action)->toThrow(
UnexpectedStorageException::class,
'Laravel existing disks cannot be empty'
);
});
it('throws exception if eligibleDisks is empty', function (): void {
// GIVEN
$defaultDisk = 'local';
$eligibleDisks = [];
$laravelExistingDisks = [(object) ['disk' => 'local', 'driver' => 'local']];
$allowedExtensions = ['pdf'];
// WHEN
$action = fn () => new StorageServiceConfig(
defaultDisk: $defaultDisk,
eligibleDisks: $eligibleDisks,
laravelExistingDisks: $laravelExistingDisks,
allowedExtensions: $allowedExtensions
);
// THEN
expect($action)->toThrow(
UnexpectedStorageException::class,
'Eligible disks cannot be empty'
);
});
it('throws exception if no eligible disks exist in Laravel existing disks', function (): void {
// GIVEN
$defaultDisk = 'local';
$eligibleDisks = ['public'];
$laravelExistingDisks = [(object) ['disk' => 'local', 'driver' => 'local']];
$allowedExtensions = ['pdf'];
// WHEN
$action = fn () => new StorageServiceConfig(
defaultDisk: $defaultDisk,
eligibleDisks: $eligibleDisks,
laravelExistingDisks: $laravelExistingDisks,
allowedExtensions: $allowedExtensions
);
// THEN
expect($action)->toThrow(
UnexpectedStorageException::class,
'No eligible disks exist in Laravel existing disks'
);
});
it('throws exception if default disk does not exist in Laravel existing disks', function (): void {
// GIVEN
$defaultDisk = 'local';
$eligibleDisks = ['public'];
$laravelExistingDisks = [(object) ['disk' => 'public', 'driver' => 'local']];
$allowedExtensions = ['pdf'];
// WHEN
$action = fn () => new StorageServiceConfig(
defaultDisk: $defaultDisk,
eligibleDisks: $eligibleDisks,
laravelExistingDisks: $laravelExistingDisks,
allowedExtensions: $allowedExtensions
);
// THEN
expect($action)->toThrow(
UnexpectedStorageException::class,
'Default disk does not exist in Laravel existing disks'
);
});
});
describe('StorageServiceConfig allowed extensions validation', function (): void {
it('throws exception if allowedExtensions is empty', function (): void {
// GIVEN
$defaultDisk = 'local';
$eligibleDisks = ['local'];
$laravelExistingDisks = [(object) ['disk' => 'local', 'driver' => 'local']];
$allowedExtensions = [];
// WHEN
$action = fn () => new StorageServiceConfig(
defaultDisk: $defaultDisk,
eligibleDisks: $eligibleDisks,
laravelExistingDisks: $laravelExistingDisks,
allowedExtensions: $allowedExtensions
);
// THEN
expect($action)->toThrow(
UnexpectedStorageException::class,
'Allowed extensions cannot be empty'
);
});
it('throws exception if an allowed extension is empty or invalid', function (string $invalidExtension): void {
// GIVEN
$defaultDisk = 'local';
$eligibleDisks = ['local'];
$laravelExistingDisks = [(object) ['disk' => 'local', 'driver' => 'local']];
$allowedExtensions = ['jpg', $invalidExtension];
// WHEN
$action = fn () => new StorageServiceConfig(
defaultDisk: $defaultDisk,
eligibleDisks: $eligibleDisks,
laravelExistingDisks: $laravelExistingDisks,
allowedExtensions: $allowedExtensions
);
// THEN
expect($action)->toThrow(
UnexpectedStorageException::class,
"Allowed extension {$invalidExtension} is not valid"
);
})->with([
'empty string' => '',
'whitespace' => ' ',
]);
it('throws exception if an allowed extension is forbidden (svg or xml)', function (string $forbidden): void {
// GIVEN
$defaultDisk = 'local';
$eligibleDisks = ['local'];
$laravelExistingDisks = [(object) ['disk' => 'local', 'driver' => 'local']];
$allowedExtensions = ['jpg', $forbidden];
// WHEN
$action = fn () => new StorageServiceConfig(
defaultDisk: $defaultDisk,
eligibleDisks: $eligibleDisks,
laravelExistingDisks: $laravelExistingDisks,
allowedExtensions: $allowedExtensions
);
// THEN
expect($action)->toThrow(
UnexpectedStorageException::class,
"Extension '{$forbidden}' is forbidden: XML/SVG sanitization is currently not supported."
);
})->with([
'svg' => 'svg',
'svg with .' => '.svg',
'SVG upper' => 'SVG',
'xml' => 'xml',
'xml with .' => '.xml',
'XML upper' => 'XML',
]);
});
describe('StorageServiceConfig isDiskEligible', function (): void {
it('returns true when checking eligible disk with string or DiskName', function (): void {
// GIVEN
$config = new StorageServiceConfig(
defaultDisk: 'local',
eligibleDisks: ['local'],
laravelExistingDisks: [(object) ['disk' => 'local', 'driver' => 'local']],
allowedExtensions: ['pdf']
);
$diskNameVo = new DiskName('local', 'local');
// WHEN
$eligibleFromString = $config->isDiskEligible('local');
$eligibleFromVo = $config->isDiskEligible($diskNameVo);
// THEN
expect($eligibleFromString)->toBeTrue()
->and($eligibleFromVo)->toBeTrue();
});
it('returns false when checking non-eligible disk', function (): void {
// GIVEN
$config = new StorageServiceConfig(
defaultDisk: 'local',
eligibleDisks: ['local'],
laravelExistingDisks: [(object) ['disk' => 'local', 'driver' => 'local']],
allowedExtensions: ['pdf']
);
// WHEN
$isEligible = $config->isDiskEligible('public');
// THEN
expect($isEligible)->toBeFalse();
});
});
describe('StorageServiceConfig isExtensionAllowed', function (): void {
it('returns true for allowed extensions regardless of case or leading dot', function (string $extension): void {
// GIVEN
$config = new StorageServiceConfig(
defaultDisk: 'local',
eligibleDisks: ['local'],
laravelExistingDisks: [(object) ['disk' => 'local', 'driver' => 'local']],
allowedExtensions: ['jpg', 'png', 'pdf']
);
// WHEN
$isAllowed = $config->isExtensionAllowed($extension);
// THEN
expect($isAllowed)->toBeTrue();
})->with([
'exact' => 'jpg',
'with dot' => '.jpg',
'uppercase' => 'PNG',
'upper dot' => '.PDF',
]);
it('returns false for non-allowed extensions', function (string $extension): void {
// GIVEN
$config = new StorageServiceConfig(
defaultDisk: 'local',
eligibleDisks: ['local'],
laravelExistingDisks: [(object) ['disk' => 'local', 'driver' => 'local']],
allowedExtensions: ['jpg', 'png', 'pdf']
);
// WHEN
$isAllowed = $config->isExtensionAllowed($extension);
// THEN
expect($isAllowed)->toBeFalse();
})->with([
'exe' => 'exe',
'zip' => 'zip',
'svg' => 'svg',
'xml' => 'xml',
'.svg' => '.svg',
]);
});
describe('StorageServiceConfig prefix validation and retrieval', function (): void {
it('returns null when prefix is omitted or null', function (?string $prefix): void {
// GIVEN
$config = new StorageServiceConfig(
defaultDisk: 'local',
eligibleDisks: ['local'],
laravelExistingDisks: [(object) ['disk' => 'local', 'driver' => 'local']],
allowedExtensions: ['pdf'],
prefix: $prefix
);
// THEN
expect($config->getPrefix())->toBeNull();
})->with([
'null' => null,
'empty' => '',
'spaces' => ' ',
'slashes' => '///',
]);
it('trims leading and trailing slashes and spaces from prefix', function (string $input, string $expected): void {
// GIVEN
$config = new StorageServiceConfig(
defaultDisk: 'local',
eligibleDisks: ['local'],
laravelExistingDisks: [(object) ['disk' => 'local', 'driver' => 'local']],
allowedExtensions: ['pdf'],
prefix: $input
);
// THEN
expect($config->getPrefix())->toBe($expected);
})->with([
'simple' => ['media', 'media'],
'leading slash' => ['/media', 'media'],
'trailing slash' => ['media/', 'media'],
'both slashes' => ['/media/', 'media'],
'nested' => ['/uploads/images/', 'uploads/images'],
'with spaces' => [' media ', 'media'],
]);
it('throws exception if prefix contains invalid sequences', function (string $invalidPrefix): void {
// GIVEN
$action = fn () => new StorageServiceConfig(
defaultDisk: 'local',
eligibleDisks: ['local'],
laravelExistingDisks: [(object) ['disk' => 'local', 'driver' => 'local']],
allowedExtensions: ['pdf'],
prefix: $invalidPrefix
);
// THEN
expect($action)->toThrow(UnexpectedStorageException::class);
})->with([
'dot dot' => '../media',
'nested dot dot' => 'media/../sub',
'backslash' => 'media\\sub',
'double slash' => 'media//sub',
]);
});
describe('StorageServiceConfig real driver resolution', function (): void {
it('resolves direct drivers of default and eligible disks', function (): void {
// GIVEN
Storage::fake('s3');
// WHEN
$config = new StorageServiceConfig(
defaultDisk: 'local',
eligibleDisks: ['local', 's3'],
laravelExistingDisks: [
(object) ['disk' => 'local', 'driver' => 'local'],
(object) ['disk' => 's3', 'driver' => 's3'],
],
allowedExtensions: ['pdf']
);
$localDisk = new DiskName('local', 'local');
$s3Disk = new DiskName('s3', 's3');
// THEN
expect($config->getRealDriver($localDisk))->toBe('local')
->and($config->isS3Driver($localDisk))->toBeFalse()
->and($config->getRealDriver($s3Disk))->toBe('s3')
->and($config->isS3Driver($s3Disk))->toBeTrue();
});
it('resolves the underlying driver of a scoped disk at boot', function (): void {
// GIVEN
config()->set('filesystems.disks.s3_parent', ['driver' => 's3']);
config()->set('filesystems.disks.media', [
'driver' => 'scoped',
'disk' => 's3_parent',
'prefix' => 'media',
]);
Storage::fake('media');
// WHEN
$config = new StorageServiceConfig(
defaultDisk: 'media',
eligibleDisks: ['media'],
laravelExistingDisks: [(object) ['disk' => 'media', 'driver' => 'scoped']],
allowedExtensions: ['pdf']
);
$media = new DiskName('media', 'scoped');
// THEN
expect($config->getRealDriver($media))->toBe('s3')
->and($config->isS3Driver($media))->toBeTrue();
});
it('fails at boot when a scoped disk is misconfigured', function (): void {
// GIVEN
config()->set('filesystems.disks.broken', ['driver' => 'scoped']);
Storage::fake('broken');
// WHEN
$action = fn () => new StorageServiceConfig(
defaultDisk: 'local',
eligibleDisks: ['local', 'broken'],
laravelExistingDisks: [
(object) ['disk' => 'local', 'driver' => 'local'],
(object) ['disk' => 'broken', 'driver' => 'scoped'],
],
allowedExtensions: ['pdf']
);
// THEN
expect($action)->toThrow(
UnexpectedStorageException::class,
"Scoped disk 'broken' is missing a valid parent 'disk' configuration."
);
});
it('throws when asking the driver of a disk that is neither default nor eligible', function (): void {
// GIVEN
$config = new StorageServiceConfig(
defaultDisk: 'local',
eligibleDisks: ['local'],
laravelExistingDisks: [(object) ['disk' => 'local', 'driver' => 'local']],
allowedExtensions: ['pdf']
);
Storage::fake('other');
$other = new DiskName('other', 'local');
// WHEN
$action = fn () => $config->getRealDriver($other);
// THEN
expect($action)->toThrow(
UnexpectedStorageException::class,
'Disk other is neither the default nor an eligible disk'
);
});
});