- PHP 8.3 → 8.4 (Dockerfile + composer.json) - Symfony 7.0 → 8.0 (tous les composants symfony/*) - API Platform 3.x → 4.x : migration openapiContext → openapi: new Operation(...) - Doctrine DBAL 3 → 4 : suppression use_savepoints, replace prepare/executeQuery - Doctrine ORM 2.x → 3.x : ClassMetadataInfo → ClassMetadata, setParameters → setParameter - Doctrine Bundle 2.x → 3.x, Fixtures Bundle 3.x → 4.x - zenstruck/foundry 1.x → 2.x : ModelFactory → PersistentObjectFactory, getDefaults → defaults - phpmd/phpmd 2.x → 3.x-dev (seule version supportant Symfony 8) - phparkitect 0.3 → 0.8 : NotDependsOnTheseNamespaces prend un array - symfony/mercure-bundle 0.3 → 0.4, symfony/monolog-bundle 3 → 4 - Suppression de runtime/frankenphp-symfony (intégré nativement dans symfony/runtime 8) - worker.Caddyfile : suppression de APP_RUNTIME (détection automatique Symfony 8) - Routes errors.xml/wdt.xml/profiler.xml → .php (Symfony 8 supprime le XML) - Types::ARRAY → Types::JSON dans Entity/Manga.php (DBAL 4 retire array type) - Suppression de src/Schedule.php (doublon vide avec MonitoringSchedule) - Tests : hydra:Collection → Collection, hydra:member → member (API Platform 4)
297 lines
11 KiB
PHP
297 lines
11 KiB
PHP
<?php
|
|
|
|
declare(strict_types=1);
|
|
|
|
namespace Tests\Domain\Manga\Infrastructure\Service;
|
|
|
|
use App\Domain\Manga\Infrastructure\Service\FilenameAnalyzer;
|
|
use PHPUnit\Framework\TestCase;
|
|
|
|
class FilenameAnalyzerTest extends TestCase
|
|
{
|
|
private FilenameAnalyzer $analyzer;
|
|
|
|
protected function setUp(): void
|
|
{
|
|
$this->analyzer = new FilenameAnalyzer();
|
|
}
|
|
|
|
public function testItAnalyzesOnePieceFilenameCorrectly(): void
|
|
{
|
|
// Given
|
|
$filename = 'one-piece_vol108_ch1094.cbz';
|
|
|
|
// When
|
|
$result = $this->analyzer->analyze($filename);
|
|
|
|
// Then
|
|
$this->assertEquals('one-piece', $result->getTitle()->getValue());
|
|
$this->assertEquals(1094.0, $result->getChapterNumber()->getValue());
|
|
$this->assertEquals(108.0, $result->getVolumeNumber()->getValue());
|
|
$this->assertTrue($result->hasChapterNumber());
|
|
$this->assertTrue($result->hasVolumeNumber());
|
|
}
|
|
|
|
public function testItHandlesDifferentFilenameFormats(): void
|
|
{
|
|
$testCases = [
|
|
// Format underscore
|
|
[
|
|
'filename' => 'attack-on-titan_vol32_ch130.cbz',
|
|
'expectedTitle' => 'attack-on-titan',
|
|
'expectedChapter' => 130.0,
|
|
'expectedVolume' => 32.0,
|
|
],
|
|
// Format avec espaces
|
|
[
|
|
'filename' => 'Dragon Ball vol 1 ch 5.cbz',
|
|
'expectedTitle' => 'Dragon Ball',
|
|
'expectedChapter' => 5.0,
|
|
'expectedVolume' => 1.0,
|
|
],
|
|
// Format avec tirets
|
|
[
|
|
'filename' => 'my-hero-academia-vol15-ch150.cbr',
|
|
'expectedTitle' => 'my-hero-academia',
|
|
'expectedChapter' => 150.0,
|
|
'expectedVolume' => 15.0,
|
|
],
|
|
// Format chapitre décimal
|
|
[
|
|
'filename' => 'naruto_vol50_ch456.5.cbz',
|
|
'expectedTitle' => 'naruto',
|
|
'expectedChapter' => 456.5,
|
|
'expectedVolume' => 50.0,
|
|
],
|
|
];
|
|
|
|
foreach ($testCases as $case) {
|
|
$result = $this->analyzer->analyze($case['filename']);
|
|
|
|
$this->assertEquals($case['expectedTitle'], $result->getTitle()->getValue(),
|
|
"Failed for filename: {$case['filename']}");
|
|
$this->assertEquals($case['expectedChapter'], $result->getChapterNumber()->getValue(),
|
|
"Failed chapter extraction for: {$case['filename']}");
|
|
$this->assertEquals($case['expectedVolume'], $result->getVolumeNumber()->getValue(),
|
|
"Failed volume extraction for: {$case['filename']}");
|
|
}
|
|
}
|
|
|
|
public function testItExtractsAndCleansTitle(): void
|
|
{
|
|
// Given
|
|
$filename = 'one-piece_vol108_ch1094.cbz';
|
|
|
|
// When
|
|
$result = $this->analyzer->analyze($filename);
|
|
|
|
// Then - should extract and clean the title
|
|
$this->assertEquals('one-piece', $result->getTitle()->getValue());
|
|
$this->assertNotEmpty($result->getTitle()->getValue(), 'Title should not be empty');
|
|
}
|
|
|
|
public function testItHandlesFilesWithoutVolumeOrChapter(): void
|
|
{
|
|
$testCases = [
|
|
[
|
|
'filename' => 'one-piece.cbz',
|
|
'expectedTitle' => 'one-piece',
|
|
],
|
|
[
|
|
'filename' => 'manga_title_only.cbr',
|
|
'expectedTitle' => 'manga_title_only',
|
|
],
|
|
];
|
|
|
|
foreach ($testCases as $case) {
|
|
$result = $this->analyzer->analyze($case['filename']);
|
|
|
|
$this->assertEquals($case['expectedTitle'], $result->getTitle()->getValue());
|
|
$this->assertFalse($result->hasChapterNumber());
|
|
$this->assertFalse($result->hasVolumeNumber());
|
|
$this->assertNull($result->getChapterNumber());
|
|
$this->assertNull($result->getVolumeNumber());
|
|
}
|
|
}
|
|
|
|
public function testItHandlesCbzAndCbrExtensions(): void
|
|
{
|
|
// Given
|
|
$testCases = [
|
|
['filename' => 'one-piece.cbz', 'expectedTitle' => 'one-piece'],
|
|
['filename' => 'manga.cbr', 'expectedTitle' => 'manga'],
|
|
['filename' => 'test.CBZ', 'expectedTitle' => 'test'],
|
|
['filename' => 'test.CBR', 'expectedTitle' => 'test'],
|
|
];
|
|
|
|
foreach ($testCases as $case) {
|
|
// When
|
|
$result = $this->analyzer->analyze($case['filename']);
|
|
|
|
// Then - L'extension est enlevée et le titre est extrait
|
|
$this->assertEquals($case['expectedTitle'], $result->getTitle()->getValue());
|
|
}
|
|
}
|
|
|
|
public function testItCleansCommonPatterns(): void
|
|
{
|
|
$testCases = [
|
|
[
|
|
'filename' => 'one-piece-scan-fr_vol108_ch1094.cbz',
|
|
'cleanedTitle' => 'one-piece',
|
|
],
|
|
[
|
|
'filename' => 'manga-raw-jp_vol1_ch1.cbz',
|
|
'cleanedTitle' => 'manga',
|
|
],
|
|
];
|
|
|
|
foreach ($testCases as $case) {
|
|
$result = $this->analyzer->analyze($case['filename']);
|
|
$title = $result->getTitle()->getValue();
|
|
|
|
// Vérifie que le titre est nettoyé
|
|
$this->assertEquals($case['cleanedTitle'], $title,
|
|
"Title should be cleaned for {$case['filename']}");
|
|
|
|
// Vérifie que le titre nettoyé ne contient pas les mots indésirables
|
|
$this->assertDoesNotMatchRegularExpression('/\b(?:scan|raw|fr|en|jp|hq|lq)\b/i', $title,
|
|
"Cleaned title should not contain unwanted patterns for {$case['filename']}");
|
|
}
|
|
}
|
|
|
|
public function testItHandlesFilenameWithOnlyVolume(): void
|
|
{
|
|
$testCases = [
|
|
[
|
|
'filename' => 'one-piece_vol108.cbz',
|
|
'expectedTitle' => 'one-piece',
|
|
'expectedVolume' => 108.0,
|
|
],
|
|
[
|
|
'filename' => 'attack-on-titan vol 32.cbz',
|
|
'expectedTitle' => 'attack-on-titan',
|
|
'expectedVolume' => 32.0,
|
|
],
|
|
[
|
|
'filename' => 'naruto-tome-50.cbz',
|
|
'expectedTitle' => 'naruto',
|
|
'expectedVolume' => 50.0,
|
|
],
|
|
[
|
|
'filename' => 'bleach_t15.cbz',
|
|
'expectedTitle' => 'bleach',
|
|
'expectedVolume' => 15.0,
|
|
],
|
|
];
|
|
|
|
foreach ($testCases as $case) {
|
|
$result = $this->analyzer->analyze($case['filename']);
|
|
|
|
$this->assertEquals($case['expectedTitle'], $result->getTitle()->getValue(),
|
|
"Failed title extraction for: {$case['filename']}");
|
|
$this->assertEquals($case['expectedVolume'], $result->getVolumeNumber()->getValue(),
|
|
"Failed volume extraction for: {$case['filename']}");
|
|
$this->assertFalse($result->hasChapterNumber(),
|
|
"Should not have chapter for: {$case['filename']}");
|
|
}
|
|
}
|
|
|
|
public function testItHandlesFilenameWithOnlyChapter(): void
|
|
{
|
|
$testCases = [
|
|
[
|
|
'filename' => 'naruto_ch456.cbz',
|
|
'expectedTitle' => 'naruto',
|
|
'expectedChapter' => 456.0,
|
|
],
|
|
[
|
|
'filename' => 'my-hero-academia ch 150.cbz',
|
|
'expectedTitle' => 'my-hero-academia',
|
|
'expectedChapter' => 150.0,
|
|
],
|
|
[
|
|
'filename' => 'bleach-chap-200.cbz',
|
|
'expectedTitle' => 'bleach',
|
|
'expectedChapter' => 200.0,
|
|
],
|
|
[
|
|
'filename' => 'one-piece_chapter_1094.cbz',
|
|
'expectedTitle' => 'one-piece',
|
|
'expectedChapter' => 1094.0,
|
|
],
|
|
];
|
|
|
|
foreach ($testCases as $case) {
|
|
$result = $this->analyzer->analyze($case['filename']);
|
|
|
|
$this->assertEquals($case['expectedTitle'], $result->getTitle()->getValue(),
|
|
"Failed title extraction for: {$case['filename']}");
|
|
$this->assertEquals($case['expectedChapter'], $result->getChapterNumber()->getValue(),
|
|
"Failed chapter extraction for: {$case['filename']}");
|
|
$this->assertFalse($result->hasVolumeNumber(),
|
|
"Should not have volume for: {$case['filename']}");
|
|
}
|
|
}
|
|
|
|
public function testItHandlesFullDashPatterns(): void
|
|
{
|
|
$testCases = [
|
|
[
|
|
'filename' => 'berserk-volume-42.cbz',
|
|
'expectedTitle' => 'berserk',
|
|
'expectedVolume' => 42.0,
|
|
],
|
|
[
|
|
'filename' => 'berserk-chapter-100.cbz',
|
|
'expectedTitle' => 'berserk',
|
|
'expectedChapter' => 100.0,
|
|
],
|
|
[
|
|
'filename' => 'berserk-chapitre-100.cbz',
|
|
'expectedTitle' => 'berserk',
|
|
'expectedChapter' => 100.0,
|
|
],
|
|
[
|
|
'filename' => 'berserk-volume-42-chapter-100.cbz',
|
|
'expectedTitle' => 'berserk',
|
|
'expectedVolume' => 42.0,
|
|
'expectedChapter' => 100.0,
|
|
],
|
|
[
|
|
'filename' => 'berserk-chapitre-100-volume-42.cbz',
|
|
'expectedTitle' => 'berserk',
|
|
'expectedVolume' => 42.0,
|
|
'expectedChapter' => 100.0,
|
|
],
|
|
];
|
|
|
|
foreach ($testCases as $case) {
|
|
$result = $this->analyzer->analyze($case['filename']);
|
|
|
|
$this->assertEquals($case['expectedTitle'], $result->getTitle()->getValue(),
|
|
"Failed title extraction for: {$case['filename']}");
|
|
|
|
if (isset($case['expectedVolume'])) {
|
|
$this->assertTrue($result->hasVolumeNumber(),
|
|
"Should have volume for: {$case['filename']}");
|
|
$this->assertEquals($case['expectedVolume'], $result->getVolumeNumber()->getValue(),
|
|
"Failed volume extraction for: {$case['filename']}");
|
|
} else {
|
|
$this->assertFalse($result->hasVolumeNumber(),
|
|
"Should not have volume for: {$case['filename']}");
|
|
}
|
|
|
|
if (isset($case['expectedChapter'])) {
|
|
$this->assertTrue($result->hasChapterNumber(),
|
|
"Should have chapter for: {$case['filename']}");
|
|
$this->assertEquals($case['expectedChapter'], $result->getChapterNumber()->getValue(),
|
|
"Failed chapter extraction for: {$case['filename']}");
|
|
} else {
|
|
$this->assertFalse($result->hasChapterNumber(),
|
|
"Should not have chapter for: {$case['filename']}");
|
|
}
|
|
}
|
|
}
|
|
}
|