feat: ajout de la fonctionnalité de conversion de fichiers de bande dessinée, permettant la conversion de fichiers CBR en CBZ. Intégration d'un service de conversion, d'une API pour gérer les téléchargements, et mise en place de validations pour les fichiers uploadés. Tests unitaires ajoutés pour garantir le bon fonctionnement de cette nouvelle fonctionnalité.
This commit is contained in:
parent
b4bfa48d00
commit
7a05934116
@@ -53,7 +53,8 @@
|
||||
"symfony/webpack-encore-bundle": "^2.1",
|
||||
"symfony/yaml": "7.0.*",
|
||||
"twig/extra-bundle": "^2.12|^3.0",
|
||||
"twig/twig": "^2.12|^3.0"
|
||||
"twig/twig": "^2.12|^3.0",
|
||||
"vich/uploader-bundle": "^2.7"
|
||||
},
|
||||
"config": {
|
||||
"allow-plugins": {
|
||||
|
||||
@@ -22,4 +22,5 @@ return [
|
||||
Symfony\UX\Turbo\TurboBundle::class => ['all' => true],
|
||||
DAMA\DoctrineTestBundle\DAMADoctrineTestBundle::class => ['test' => true],
|
||||
Symfony\UX\React\ReactBundle::class => ['all' => true],
|
||||
Vich\UploaderBundle\VichUploaderBundle::class => ['all' => true],
|
||||
];
|
||||
|
||||
@@ -6,6 +6,8 @@ api_platform:
|
||||
jsonld: ['application/ld+json']
|
||||
html: ['text/html']
|
||||
jsonhal: ['application/hal+json']
|
||||
multipart: ['multipart/form-data']
|
||||
cbz: ['application/x-cbz']
|
||||
swagger:
|
||||
api_keys:
|
||||
access_token:
|
||||
@@ -30,6 +32,7 @@ api_platform:
|
||||
- '%kernel.project_dir%/src/Domain/Manga/Infrastructure/ApiPlatform/Resource'
|
||||
- '%kernel.project_dir%/src/Domain/Setting/Infrastructure/ApiPlatform/Resource'
|
||||
- '%kernel.project_dir%/src/Domain/Reader/Infrastructure/ApiPlatform/Resource'
|
||||
- '%kernel.project_dir%/src/Domain/Conversion/Infrastructure/ApiPlatform/Resource'
|
||||
- '%kernel.project_dir%/src/Domain/Shared/Infrastructure/ApiPlatform/Resource'
|
||||
patch_formats:
|
||||
json: ['application/merge-patch+json']
|
||||
|
||||
10
config/packages/vich_uploader.yaml
Normal file
10
config/packages/vich_uploader.yaml
Normal file
@@ -0,0 +1,10 @@
|
||||
vich_uploader:
|
||||
db_driver: orm
|
||||
|
||||
mappings:
|
||||
conversion_uploads:
|
||||
uri_prefix: /uploads/conversions
|
||||
upload_destination: '%kernel.project_dir%/public/tmp/conversions'
|
||||
namer: Vich\UploaderBundle\Naming\UniqidNamer
|
||||
delete_on_update: true
|
||||
delete_on_remove: true
|
||||
@@ -6,6 +6,8 @@
|
||||
parameters:
|
||||
cache_adapter: 'cache.adapter.filesystem'
|
||||
|
||||
imports:
|
||||
|
||||
services:
|
||||
# default configuration for services in *this* file
|
||||
_defaults:
|
||||
@@ -49,6 +51,10 @@ services:
|
||||
arguments:
|
||||
$projectDir: '%kernel.project_dir%'
|
||||
|
||||
App\Domain\Conversion\Infrastructure\Service\ConversionService:
|
||||
arguments:
|
||||
$projectDir: '%kernel.project_dir%'
|
||||
|
||||
App\Service\CbrToCbzConverter:
|
||||
arguments:
|
||||
$projectDir: '%kernel.project_dir%'
|
||||
@@ -73,7 +79,7 @@ services:
|
||||
arguments:
|
||||
$client: '@App\Client\MangadexClient'
|
||||
|
||||
# Scrapers
|
||||
# Scraper Service
|
||||
App\Service\Scraper\HtmlScraper:
|
||||
tags: [ 'app.scraper' ]
|
||||
|
||||
|
||||
@@ -0,0 +1,12 @@
|
||||
<?php
|
||||
|
||||
namespace App\Domain\Conversion\Application\Command;
|
||||
|
||||
final readonly class ConvertFileCommand
|
||||
{
|
||||
public function __construct(
|
||||
public string $filePath,
|
||||
public string $originalFilename,
|
||||
public int $fileSize
|
||||
) {}
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
<?php
|
||||
|
||||
namespace App\Domain\Conversion\Application\CommandHandler;
|
||||
|
||||
use App\Domain\Conversion\Application\Command\ConvertFileCommand;
|
||||
use App\Domain\Conversion\Application\Response\ConversionResponse;
|
||||
use App\Domain\Conversion\Domain\Contract\ConversionServiceInterface;
|
||||
use App\Domain\Conversion\Domain\Exception\ConversionException;
|
||||
use App\Domain\Conversion\Domain\Model\ConversionRequest;
|
||||
|
||||
final readonly class ConvertFileCommandHandler
|
||||
{
|
||||
private const MAX_FILE_SIZE = 150 * 1024 * 1024; // 150MB
|
||||
|
||||
public function __construct(
|
||||
private ConversionServiceInterface $conversionService
|
||||
) {}
|
||||
|
||||
public function handle(ConvertFileCommand $command): ConversionResponse
|
||||
{
|
||||
$this->validateCommand($command);
|
||||
|
||||
$request = new ConversionRequest(
|
||||
filePath: $command->filePath,
|
||||
originalFilename: $command->originalFilename,
|
||||
fileSize: $command->fileSize
|
||||
);
|
||||
|
||||
$result = $this->conversionService->convert($request);
|
||||
|
||||
return ConversionResponse::fromConversionResult($result);
|
||||
}
|
||||
|
||||
private function validateCommand(ConvertFileCommand $command): void
|
||||
{
|
||||
if (!file_exists($command->filePath)) {
|
||||
throw ConversionException::fileNotFound($command->filePath);
|
||||
}
|
||||
|
||||
if ($command->fileSize > self::MAX_FILE_SIZE) {
|
||||
throw ConversionException::fileSizeExceedsLimit($command->fileSize, self::MAX_FILE_SIZE);
|
||||
}
|
||||
|
||||
$extension = strtolower(pathinfo($command->originalFilename, PATHINFO_EXTENSION));
|
||||
$allowedExtensions = ['cbr', 'cbz', 'zip', 'rar'];
|
||||
|
||||
if (!in_array($extension, $allowedExtensions)) {
|
||||
throw ConversionException::invalidFileFormat($command->originalFilename);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
<?php
|
||||
|
||||
namespace App\Domain\Conversion\Application\Response;
|
||||
|
||||
use App\Domain\Conversion\Domain\Model\ConversionResult;
|
||||
|
||||
final readonly class ConversionResponse
|
||||
{
|
||||
public function __construct(
|
||||
public string $convertedFilePath,
|
||||
public string $outputFilename,
|
||||
public int $originalFileSize,
|
||||
public int $convertedFileSize
|
||||
) {}
|
||||
|
||||
public static function fromConversionResult(ConversionResult $result): self
|
||||
{
|
||||
return new self(
|
||||
convertedFilePath: $result->getConvertedFilePath(),
|
||||
outputFilename: $result->getOutputFilename(),
|
||||
originalFileSize: $result->getOriginalFileSize(),
|
||||
convertedFileSize: $result->getConvertedFileSize()
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
<?php
|
||||
|
||||
namespace App\Domain\Conversion\Domain\Contract;
|
||||
|
||||
use App\Domain\Conversion\Domain\Model\ConversionRequest;
|
||||
use App\Domain\Conversion\Domain\Model\ConversionResult;
|
||||
|
||||
interface ConversionServiceInterface
|
||||
{
|
||||
public function convert(ConversionRequest $request): ConversionResult;
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
<?php
|
||||
|
||||
namespace App\Domain\Conversion\Domain\Exception;
|
||||
|
||||
use RuntimeException;
|
||||
|
||||
class ConversionException extends RuntimeException
|
||||
{
|
||||
public static function fileNotFound(string $filePath): self
|
||||
{
|
||||
return new self(sprintf('File not found: %s', $filePath));
|
||||
}
|
||||
|
||||
public static function invalidFileFormat(string $filename): self
|
||||
{
|
||||
return new self(sprintf('Invalid file format for: %s. Only CBR, CBZ, ZIP and RAR files are supported.', $filename));
|
||||
}
|
||||
|
||||
public static function conversionFailed(string $reason): self
|
||||
{
|
||||
return new self(sprintf('Conversion failed: %s', $reason));
|
||||
}
|
||||
|
||||
public static function fileSizeExceedsLimit(int $fileSize, int $maxSize): self
|
||||
{
|
||||
return new self(sprintf(
|
||||
'File size (%d bytes) exceeds the maximum limit of %d bytes',
|
||||
$fileSize,
|
||||
$maxSize
|
||||
));
|
||||
}
|
||||
}
|
||||
33
src/Domain/Conversion/Domain/Model/ConversionRequest.php
Normal file
33
src/Domain/Conversion/Domain/Model/ConversionRequest.php
Normal file
@@ -0,0 +1,33 @@
|
||||
<?php
|
||||
|
||||
namespace App\Domain\Conversion\Domain\Model;
|
||||
|
||||
final readonly class ConversionRequest
|
||||
{
|
||||
public function __construct(
|
||||
private string $filePath,
|
||||
private string $originalFilename,
|
||||
private int $fileSize
|
||||
) {}
|
||||
|
||||
public function getFilePath(): string
|
||||
{
|
||||
return $this->filePath;
|
||||
}
|
||||
|
||||
public function getOriginalFilename(): string
|
||||
{
|
||||
return $this->originalFilename;
|
||||
}
|
||||
|
||||
public function getFileSize(): int
|
||||
{
|
||||
return $this->fileSize;
|
||||
}
|
||||
|
||||
public function getOutputFilename(): string
|
||||
{
|
||||
$pathInfo = pathinfo($this->originalFilename, PATHINFO_FILENAME);
|
||||
return $pathInfo . '.cbz';
|
||||
}
|
||||
}
|
||||
33
src/Domain/Conversion/Domain/Model/ConversionResult.php
Normal file
33
src/Domain/Conversion/Domain/Model/ConversionResult.php
Normal file
@@ -0,0 +1,33 @@
|
||||
<?php
|
||||
|
||||
namespace App\Domain\Conversion\Domain\Model;
|
||||
|
||||
final readonly class ConversionResult
|
||||
{
|
||||
public function __construct(
|
||||
private string $convertedFilePath,
|
||||
private string $outputFilename,
|
||||
private int $originalFileSize,
|
||||
private int $convertedFileSize
|
||||
) {}
|
||||
|
||||
public function getConvertedFilePath(): string
|
||||
{
|
||||
return $this->convertedFilePath;
|
||||
}
|
||||
|
||||
public function getOutputFilename(): string
|
||||
{
|
||||
return $this->outputFilename;
|
||||
}
|
||||
|
||||
public function getOriginalFileSize(): int
|
||||
{
|
||||
return $this->originalFileSize;
|
||||
}
|
||||
|
||||
public function getConvertedFileSize(): int
|
||||
{
|
||||
return $this->convertedFileSize;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,100 @@
|
||||
<?php
|
||||
|
||||
namespace App\Domain\Conversion\Infrastructure\ApiPlatform\Controller;
|
||||
|
||||
use App\Domain\Conversion\Application\Command\ConvertFileCommand;
|
||||
use App\Domain\Conversion\Application\CommandHandler\ConvertFileCommandHandler;
|
||||
use App\Domain\Conversion\Domain\Exception\ConversionException;
|
||||
use App\Domain\Conversion\Infrastructure\ApiPlatform\Resource\ConvertFileResource;
|
||||
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
use Symfony\Component\HttpKernel\Attribute\AsController;
|
||||
use Symfony\Component\HttpKernel\Exception\BadRequestHttpException;
|
||||
|
||||
#[AsController]
|
||||
final class ConvertFileController extends AbstractController
|
||||
{
|
||||
public function __construct(
|
||||
private readonly ConvertFileCommandHandler $commandHandler
|
||||
) {}
|
||||
|
||||
public function __invoke(Request $request): Response
|
||||
{
|
||||
$uploadedFile = $request->files->get('file');
|
||||
if (!$uploadedFile) {
|
||||
return $this->json([
|
||||
['propertyPath' => 'file', 'message' => 'Please upload a file']
|
||||
], 422);
|
||||
}
|
||||
|
||||
// Validation manuelle pour éviter les règles automatiques de Symfony
|
||||
$errors = $this->validateFile($uploadedFile);
|
||||
if (!empty($errors)) {
|
||||
return $this->json($errors, 422);
|
||||
}
|
||||
|
||||
try {
|
||||
// Créer la commande
|
||||
$command = new ConvertFileCommand(
|
||||
filePath: $uploadedFile->getPathname(),
|
||||
originalFilename: $uploadedFile->getClientOriginalName(),
|
||||
fileSize: $uploadedFile->getSize()
|
||||
);
|
||||
|
||||
// Exécuter la conversion
|
||||
$response = $this->commandHandler->handle($command);
|
||||
|
||||
// Retourner le fichier converti
|
||||
$fileContent = file_get_contents($response->convertedFilePath);
|
||||
|
||||
return new Response(
|
||||
content: $fileContent,
|
||||
status: 200,
|
||||
headers: [
|
||||
'Content-Type' => 'application/x-cbz',
|
||||
'Content-Disposition' => sprintf('attachment; filename=%s', $response->outputFilename),
|
||||
]
|
||||
);
|
||||
|
||||
} catch (ConversionException $e) {
|
||||
return $this->json(['error' => $e->getMessage()], 400);
|
||||
}
|
||||
}
|
||||
|
||||
private function validateFile($uploadedFile): array
|
||||
{
|
||||
$errors = [];
|
||||
|
||||
// Vérifier si le fichier est valide
|
||||
if (!$uploadedFile->isValid()) {
|
||||
$errors[] = [
|
||||
'propertyPath' => 'file',
|
||||
'message' => 'The uploaded file is not valid: ' . $uploadedFile->getErrorMessage()
|
||||
];
|
||||
return $errors;
|
||||
}
|
||||
|
||||
// Vérifier la taille (150MB max)
|
||||
$maxSize = 150 * 1024 * 1024; // 150MB en bytes
|
||||
if ($uploadedFile->getSize() > $maxSize) {
|
||||
$errors[] = [
|
||||
'propertyPath' => 'file',
|
||||
'message' => 'The uploaded file is too large. Allowed size is 150MB.'
|
||||
];
|
||||
}
|
||||
|
||||
// Vérifier l'extension
|
||||
$allowedExtensions = ['cbr', 'cbz', 'zip', 'rar'];
|
||||
$extension = strtolower($uploadedFile->getClientOriginalExtension());
|
||||
|
||||
if (!in_array($extension, $allowedExtensions)) {
|
||||
$errors[] = [
|
||||
'propertyPath' => 'file',
|
||||
'message' => 'Please upload a valid CBR or CBZ file'
|
||||
];
|
||||
}
|
||||
|
||||
return $errors;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,66 @@
|
||||
<?php
|
||||
|
||||
namespace App\Domain\Conversion\Infrastructure\ApiPlatform\Resource;
|
||||
|
||||
use ApiPlatform\Metadata\ApiResource;
|
||||
use ApiPlatform\Metadata\Post;
|
||||
use ApiPlatform\OpenApi\Model;
|
||||
use App\Domain\Conversion\Infrastructure\ApiPlatform\Controller\ConvertFileController;
|
||||
use Symfony\Component\HttpFoundation\File\File;
|
||||
use Symfony\Component\Validator\Constraints as Assert;
|
||||
|
||||
#[ApiResource(
|
||||
shortName: 'Conversion',
|
||||
operations: [
|
||||
new Post(
|
||||
uriTemplate: '/conversions/convert',
|
||||
controller: ConvertFileController::class,
|
||||
deserialize: false,
|
||||
openapiContext: [
|
||||
'summary' => 'Convert comic book file to CBZ',
|
||||
'description' => 'Converts a CBR or CBZ file to CBZ format and returns the converted file for download',
|
||||
'requestBody' => [
|
||||
'content' => [
|
||||
'multipart/form-data' => [
|
||||
'schema' => [
|
||||
'type' => 'object',
|
||||
'required' => ['file'],
|
||||
'properties' => [
|
||||
'file' => [
|
||||
'type' => 'string',
|
||||
'format' => 'binary',
|
||||
'description' => 'Comic book file to convert (CBR, CBZ, max 150MB)'
|
||||
]
|
||||
]
|
||||
]
|
||||
]
|
||||
]
|
||||
],
|
||||
'responses' => [
|
||||
'200' => [
|
||||
'description' => 'File converted successfully',
|
||||
'content' => [
|
||||
'application/x-cbz' => [
|
||||
'schema' => [
|
||||
'type' => 'string',
|
||||
'format' => 'binary'
|
||||
]
|
||||
]
|
||||
]
|
||||
]
|
||||
]
|
||||
]
|
||||
)
|
||||
]
|
||||
)]
|
||||
class ConvertFileResource
|
||||
{
|
||||
public ?File $file = null;
|
||||
|
||||
public ?string $fileName = null;
|
||||
|
||||
// Propriétés pour la réponse
|
||||
public mixed $fileContent = null;
|
||||
public ?string $filename = null;
|
||||
public ?string $originalConvertedFilePath = null;
|
||||
}
|
||||
@@ -0,0 +1,91 @@
|
||||
<?php
|
||||
|
||||
namespace App\Domain\Conversion\Infrastructure\Service;
|
||||
|
||||
use App\Domain\Conversion\Domain\Contract\ConversionServiceInterface;
|
||||
use App\Domain\Conversion\Domain\Exception\ConversionException;
|
||||
use App\Domain\Conversion\Domain\Model\ConversionRequest;
|
||||
use App\Domain\Conversion\Domain\Model\ConversionResult;
|
||||
use Symfony\Component\Filesystem\Filesystem;
|
||||
use Symfony\Component\Process\Process;
|
||||
|
||||
final class ConversionService implements ConversionServiceInterface
|
||||
{
|
||||
private readonly string $tempDir;
|
||||
private readonly Filesystem $filesystem;
|
||||
|
||||
public function __construct(string $projectDir)
|
||||
{
|
||||
$this->tempDir = $projectDir . '/public/tmp';
|
||||
$this->filesystem = new Filesystem();
|
||||
}
|
||||
|
||||
public function convert(ConversionRequest $request): ConversionResult
|
||||
{
|
||||
try {
|
||||
$convertedFilePath = $this->convertCbrToCbz($request->getFilePath());
|
||||
|
||||
$convertedFileSize = file_exists($convertedFilePath) ? filesize($convertedFilePath) : 0;
|
||||
|
||||
return new ConversionResult(
|
||||
convertedFilePath: $convertedFilePath,
|
||||
outputFilename: $request->getOutputFilename(),
|
||||
originalFileSize: $request->getFileSize(),
|
||||
convertedFileSize: $convertedFileSize
|
||||
);
|
||||
} catch (\Exception $e) {
|
||||
throw ConversionException::conversionFailed($e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
private function convertCbrToCbz(string $cbrPath): string
|
||||
{
|
||||
$tempDir = $this->tempDir . '/' . uniqid('cbr_conversion_');
|
||||
$this->filesystem->mkdir($tempDir);
|
||||
|
||||
$extractDir = $tempDir . '/extract';
|
||||
$this->filesystem->mkdir($extractDir);
|
||||
|
||||
// Essayer d'extraire avec unrar-free
|
||||
$process = new Process(['unrar-free', 'x', $cbrPath, $extractDir]);
|
||||
$process->run();
|
||||
|
||||
// Si unrar échoue, essayer avec 7z
|
||||
if (!$process->isSuccessful()) {
|
||||
$process = new Process(['7z', 'x', $cbrPath, "-o$extractDir"]);
|
||||
$process->run();
|
||||
|
||||
if (!$process->isSuccessful()) {
|
||||
throw new \RuntimeException("Extraction failed: " . $process->getErrorOutput());
|
||||
}
|
||||
}
|
||||
|
||||
// Créer le CBZ
|
||||
$cbzFileName = pathinfo($cbrPath, PATHINFO_FILENAME) . '.cbz';
|
||||
$cbzPath = $this->tempDir . '/' . $cbzFileName;
|
||||
$zip = new \ZipArchive();
|
||||
if ($zip->open($cbzPath, \ZipArchive::CREATE) !== true) {
|
||||
throw new \RuntimeException("Cannot create ZIP file");
|
||||
}
|
||||
|
||||
$files = new \RecursiveIteratorIterator(
|
||||
new \RecursiveDirectoryIterator($extractDir),
|
||||
\RecursiveIteratorIterator::LEAVES_ONLY
|
||||
);
|
||||
|
||||
foreach ($files as $file) {
|
||||
if (!$file->isDir()) {
|
||||
$filePath = $file->getRealPath();
|
||||
$relativePath = substr($filePath, strlen($extractDir) + 1);
|
||||
$zip->addFile($filePath, $relativePath);
|
||||
}
|
||||
}
|
||||
|
||||
$zip->close();
|
||||
|
||||
// Nettoyer le dossier temporaire d'extraction
|
||||
$this->filesystem->remove($tempDir);
|
||||
|
||||
return $cbzPath;
|
||||
}
|
||||
}
|
||||
162
tests/Feature/Conversion/ConvertFileTest.php
Normal file
162
tests/Feature/Conversion/ConvertFileTest.php
Normal file
@@ -0,0 +1,162 @@
|
||||
<?php
|
||||
|
||||
namespace App\Tests\Feature\Conversion;
|
||||
|
||||
use App\Tests\Feature\AbstractApiTestCase;
|
||||
use Symfony\Component\HttpFoundation\File\UploadedFile;
|
||||
use Zenstruck\Foundry\Test\ResetDatabase;
|
||||
|
||||
class ConvertFileTest extends AbstractApiTestCase
|
||||
{
|
||||
use ResetDatabase;
|
||||
|
||||
public function testConvertCbrToCbzSuccess(): void
|
||||
{
|
||||
// Given - Créer un fichier CBR temporaire pour le test
|
||||
$tempCbrFile = $this->createTestCbrFile();
|
||||
|
||||
// When - Envoyer la requête avec VichUploader et la syntaxe correcte
|
||||
$client = static::createClient();
|
||||
|
||||
$uploadedFile = new UploadedFile(
|
||||
$tempCbrFile,
|
||||
'test-manga.cbr',
|
||||
'application/x-cbr', // Type MIME attendu par la validation
|
||||
null,
|
||||
true
|
||||
);
|
||||
|
||||
$client->request('POST', '/api/conversions/convert', [
|
||||
'headers' => ['Content-Type' => 'multipart/form-data'],
|
||||
'extra' => [
|
||||
'files' => [
|
||||
'file' => $uploadedFile,
|
||||
],
|
||||
]
|
||||
]);
|
||||
|
||||
// Then - Vérifier la réponse
|
||||
$this->assertResponseIsSuccessful();
|
||||
$this->assertResponseHeaderSame('Content-Type', 'application/x-cbz');
|
||||
$this->assertResponseHeaderSame('Content-Disposition', 'attachment; filename=test-manga.cbz');
|
||||
|
||||
// Vérifier que la réponse contient le fichier converti
|
||||
$content = $client->getResponse()->getContent();
|
||||
$this->assertNotEmpty($content);
|
||||
|
||||
// Nettoyer le fichier temporaire
|
||||
if (file_exists($tempCbrFile)) {
|
||||
unlink($tempCbrFile);
|
||||
}
|
||||
}
|
||||
|
||||
public function testConvertWithoutFileReturnsError(): void
|
||||
{
|
||||
// When - Envoyer une requête sans fichier
|
||||
$client = static::createClient();
|
||||
$client->request('POST', '/api/conversions/convert', [
|
||||
'headers' => ['Content-Type' => 'multipart/form-data'],
|
||||
]);
|
||||
|
||||
// Then - Vérifier l'erreur de validation
|
||||
$this->assertResponseStatusCodeSame(422);
|
||||
}
|
||||
|
||||
public function testConvertWithInvalidFileFormatReturnsError(): void
|
||||
{
|
||||
// Given - Créer un fichier non-CBR pour le test
|
||||
$tempFile = tempnam(sys_get_temp_dir(), 'test_invalid_');
|
||||
file_put_contents($tempFile, 'invalid content');
|
||||
|
||||
$uploadedFile = new UploadedFile(
|
||||
$tempFile,
|
||||
'test.txt',
|
||||
'text/plain',
|
||||
null,
|
||||
true
|
||||
);
|
||||
|
||||
// When - Envoyer la requête avec un fichier invalide
|
||||
$client = static::createClient();
|
||||
$client->request('POST', '/api/conversions/convert', [
|
||||
'headers' => ['Content-Type' => 'multipart/form-data'],
|
||||
'extra' => [
|
||||
'files' => [
|
||||
'file' => $uploadedFile,
|
||||
],
|
||||
]
|
||||
]);
|
||||
|
||||
// Then - Vérifier l'erreur de validation
|
||||
$this->assertResponseStatusCodeSame(422);
|
||||
|
||||
// Nettoyer le fichier temporaire
|
||||
if (file_exists($tempFile)) {
|
||||
unlink($tempFile);
|
||||
}
|
||||
}
|
||||
|
||||
public function testConvertWithFileTooLargeReturnsError(): void
|
||||
{
|
||||
// Given - Créer un fichier trop volumineux (simulation)
|
||||
$tempLargeFile = tempnam(sys_get_temp_dir(), 'test_large_');
|
||||
|
||||
// Créer un fichier de plus de 150MB (pour déclencher l'erreur de taille)
|
||||
// On simule juste en créant un fichier et en modifiant sa taille déclarée
|
||||
file_put_contents($tempLargeFile, str_repeat('x', 1024 * 1024)); // 1MB de contenu
|
||||
|
||||
// Mock de l'UploadedFile avec une taille déclarée trop importante
|
||||
$uploadedFile = new UploadedFile(
|
||||
$tempLargeFile,
|
||||
'large-file.cbr',
|
||||
'application/x-cbr', // Type MIME attendu par la validation
|
||||
150 * 1024 * 1024 + 1 // 150MB + 1 byte
|
||||
);
|
||||
|
||||
// When - Envoyer la requête avec un fichier trop volumineux
|
||||
$client = static::createClient();
|
||||
$client->request('POST', '/api/conversions/convert', [
|
||||
'headers' => ['Content-Type' => 'multipart/form-data'],
|
||||
'extra' => [
|
||||
'files' => [
|
||||
'file' => $uploadedFile,
|
||||
],
|
||||
]
|
||||
]);
|
||||
|
||||
// Then - Vérifier l'erreur de validation
|
||||
$this->assertResponseStatusCodeSame(422);
|
||||
|
||||
// Nettoyer le fichier temporaire
|
||||
if (file_exists($tempLargeFile)) {
|
||||
unlink($tempLargeFile);
|
||||
}
|
||||
}
|
||||
|
||||
private function createTestCbrFile(): string
|
||||
{
|
||||
// Créer un fichier CBR temporaire pour les tests
|
||||
$tempFile = tempnam(sys_get_temp_dir(), 'test_cbr_');
|
||||
|
||||
// Pour les tests, on peut simplement créer un fichier avec une extension .cbr
|
||||
// En production, ce serait un vrai fichier RAR
|
||||
$newPath = $tempFile . '.cbr';
|
||||
rename($tempFile, $newPath);
|
||||
|
||||
// Utiliser un fichier CBZ existant comme base et le renommer en CBR pour les tests
|
||||
$existingCbzFile = __DIR__ . '/../../Fixtures/chapter.cbz';
|
||||
if (file_exists($existingCbzFile)) {
|
||||
copy($existingCbzFile, $newPath);
|
||||
} else {
|
||||
// Fallback: créer un fichier ZIP simple avec extension CBR
|
||||
// Un fichier CBR est essentiellement un fichier RAR, mais pour les tests on peut simuler avec un ZIP
|
||||
$zip = new \ZipArchive();
|
||||
if ($zip->open($newPath, \ZipArchive::CREATE) === TRUE) {
|
||||
$zip->addFromString('test.txt', 'Test content for CBR simulation');
|
||||
$zip->close();
|
||||
}
|
||||
}
|
||||
|
||||
return $newPath;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user