diff --git a/.github/workflows/sonar-scan.yml b/.github/workflows/sonar-scan.yml
index 21a4b50d5..e0f98f393 100644
--- a/.github/workflows/sonar-scan.yml
+++ b/.github/workflows/sonar-scan.yml
@@ -123,7 +123,7 @@ jobs:
develop:
name: Build Nightly Docker if Develop push
- needs: [ build, test, version ]
+ needs: [ build, version ]
runs-on: ubuntu-latest
if: ${{ github.event_name == 'push' && github.ref == 'refs/heads/develop' }}
steps:
@@ -232,7 +232,7 @@ jobs:
stable:
name: Build Stable Docker if Main push
- needs: [ build, test ]
+ needs: [ build ]
runs-on: ubuntu-latest
if: ${{ github.event_name == 'push' && github.ref == 'refs/heads/main' }}
steps:
diff --git a/.gitignore b/.gitignore
index 9e470748b..078b6108c 100644
--- a/.gitignore
+++ b/.gitignore
@@ -530,3 +530,4 @@ API.Tests/TestResults/
UI/Web/.vscode/settings.json
/API.Tests/Services/Test Data/ArchiveService/CoverImages/output/*
UI/Web/.angular/
+BenchmarkDotNet.Artifacts
\ No newline at end of file
diff --git a/API.Benchmark/API.Benchmark.csproj b/API.Benchmark/API.Benchmark.csproj
index 31af4f2c6..11ef151a2 100644
--- a/API.Benchmark/API.Benchmark.csproj
+++ b/API.Benchmark/API.Benchmark.csproj
@@ -10,15 +10,21 @@
-
-
+
+
-
+
Always
-
+
+
+
+
+ Data
+ Always
+
diff --git a/API.Benchmark/ArchiveSerivceBenchmark.cs b/API.Benchmark/ArchiveSerivceBenchmark.cs
deleted file mode 100644
index c60a4271f..000000000
--- a/API.Benchmark/ArchiveSerivceBenchmark.cs
+++ /dev/null
@@ -1,8 +0,0 @@
-namespace API.Benchmark
-{
- public class ArchiveSerivceBenchmark
- {
- // Benchmark to test default GetNumberOfPages from archive
- // vs a new method where I try to open the archive and return said stream
- }
-}
diff --git a/API.Benchmark/ArchiveServiceBenchmark.cs b/API.Benchmark/ArchiveServiceBenchmark.cs
new file mode 100644
index 000000000..d8418ee26
--- /dev/null
+++ b/API.Benchmark/ArchiveServiceBenchmark.cs
@@ -0,0 +1,54 @@
+using System;
+using System.IO.Abstractions;
+using Microsoft.Extensions.Logging.Abstractions;
+using API.Services;
+using BenchmarkDotNet.Attributes;
+using BenchmarkDotNet.Order;
+
+namespace API.Benchmark;
+
+[StopOnFirstError]
+[MemoryDiagnoser]
+[RankColumn]
+[Orderer(SummaryOrderPolicy.FastestToSlowest)]
+[SimpleJob(launchCount: 1, warmupCount: 5, targetCount: 20)]
+public class ArchiveServiceBenchmark
+{
+ private readonly ArchiveService _archiveService;
+ private readonly IDirectoryService _directoryService;
+ private readonly IImageService _imageService;
+
+ public ArchiveServiceBenchmark()
+ {
+ _directoryService = new DirectoryService(null, new FileSystem());
+ _imageService = new ImageService(null, _directoryService);
+ _archiveService = new ArchiveService(new NullLogger(), _directoryService, _imageService);
+ }
+
+ [Benchmark(Baseline = true)]
+ public void TestGetComicInfo_baseline()
+ {
+ if (_archiveService.GetComicInfo("Data/ComicInfo.zip") == null) {
+ throw new Exception("ComicInfo not found");
+ }
+ }
+
+ [Benchmark]
+ public void TestGetComicInfo_duplicate()
+ {
+ if (_archiveService.GetComicInfo("Data/ComicInfo_duplicateInfos.zip") == null) {
+ throw new Exception("ComicInfo not found");
+ }
+ }
+
+ [Benchmark]
+ public void TestGetComicInfo_outside_root()
+ {
+ if (_archiveService.GetComicInfo("Data/ComicInfo_outside_root.zip") == null) {
+ throw new Exception("ComicInfo not found");
+ }
+ }
+
+ // Benchmark to test default GetNumberOfPages from archive
+ // vs a new method where I try to open the archive and return said stream
+}
diff --git a/API.Benchmark/CleanTitleBenchmark.cs b/API.Benchmark/CleanTitleBenchmark.cs
new file mode 100644
index 000000000..90310a9ef
--- /dev/null
+++ b/API.Benchmark/CleanTitleBenchmark.cs
@@ -0,0 +1,26 @@
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Text.RegularExpressions;
+using BenchmarkDotNet.Attributes;
+using BenchmarkDotNet.Order;
+
+namespace API.Benchmark;
+
+[MemoryDiagnoser]
+public static class CleanTitleBenchmarks
+{
+ private static IList _names;
+
+ [GlobalSetup]
+ public static void LoadData() => _names = File.ReadAllLines("Data/Comics.txt");
+
+ [Benchmark]
+ public static void TestCleanTitle()
+ {
+ foreach (var name in _names)
+ {
+ Services.Tasks.Scanner.Parser.Parser.CleanTitle(name, true);
+ }
+ }
+}
diff --git a/API.Benchmark/Data/Comics.txt b/API.Benchmark/Data/Comics.txt
new file mode 100644
index 000000000..05eb2d52f
--- /dev/null
+++ b/API.Benchmark/Data/Comics.txt
@@ -0,0 +1,112 @@
+One-Star Squadron 02 (of 06) (2022) (digital) (Son of Ultron-Empire).cbz
+Batman & the Monster Men 06 (2006) (Kryptonia-DCP).cbr
+Hauteville House -07- Expedition Vanikoro.cbr
+Fantastic Four v3 #020.cbz
+Thunderbolts 053.cbr
+Moon Knight 010 2007 Red Lion-DCP .cbr
+New X-Men 037.cbr
+X-Men - Deadly Genesis 02 (2006) (BigBlue-DCP).cbr
+Incredible Hercules 128.cbr
+JLA - Year One 03 of 12.cbr
+Daredevil v2 082 (2006) (Reiu-DCP).cbr
+069 - Iron Man v4 035 (2009) (Minutemen-ZonesDiva).cbr
+2000AD prog 2285 (2022) (digital) (Minutemen-juvecube).cbz
+Tanguy et Laverdure - Intégrale - T07.cbz
+Excalibur 026 (2022) (Digital) (Zone-Empire).cbz
+DC vs. Vampires - Killers 001 (2022) (Webrip) (The Last Kryptonian-DCP).cbz
+By the Horns 003 (2021) (Digital) (Mephisto-Empire).cbz
+Incredible Hulks 630 (2011) (Minutemen-Fiji).cbz
+Red Robin 010 (2010) (Minutemen-OTT).cbr
+Les Droits de lHomme - OneShot - Collectif.cbz
+Tout Gaston - Intégrale.cbr
+Good Night, Hem (2021) (Digital) (Dipole-Empire).cbz
+Bunny Mask - The Hollow Inside 001 (2022) (Digital) (Mephisto-Empire).cbz
+Les MYTHICS - T14 - Avarice.cbr
+Fantastic Four Special 01 (2006) (Nascent-DCP).cbr
+Sonjaversal 006 (2021) (5 covers) (digital) (The Seeker-Empire).cbz
+The Flash 779 (2022) (Digital) (Zone-Empire).cbz
+Supergirl and the Legion of Super-Heroes 020 (2006) (CamelotScans-DCP).cbr
+Time Before Time 015 (2022) (Digital) (Zone-Empire).cbz
+Union Jack 02 (2006) (Red Lion-DCP).cbr
+Le Corps est un Vêtement que l'on quitte.pdf
+Helmet of Fate - Black Alice 01 (2007) (Racerx-DCP).cbz
+Villains United 003 [2005] (Team-DCP).cbr
+Punisher 002.cbr
+Grendel - Devil's Odyssey 008 (2021) (digital) (NeverAngel-Empire).cbz
+Uncanny X-Force 05.1 (2011) (Minutemen-Megatonic).cbz
+Orcs & Gobelins - T14 - Shaaka.cbr
+Les grands personnages de l'histoire en bandes dessinées - T67 - Suffren - La Bataille de Gondelou.cbz
+Batman Adventures 013 (Jorl - Dcp).cbr
+Norse Mythology II 003 (2021) (digital) (Son of Ultron-Empire).cbz
+Ghost Rider 012 (2007) (Team-DCP).cbr
+Once & Future 021 (2021) (digital) (Son of Ultron-Empire).cbz
+The Seven Deadly Sins #1_ Seven Deadly Her - Nakaba Suzuki.epub
+Kimagure Orange Road Omnibus #5_ Vol. 5 - Izumi Matsumoto.cbz
+Booster Gold 36 2010 Minutemen-Oracle Saxon .cbr
+New X-Men 023 (2006) (Reiu-DCP).cbr
+World of Betty and Veronica Comics Digest 016 (2022) (Forsythe-DCP).cbz
+Deadpool Team-Up 889 (2010) (noads) (LegionNever-CPS).cbr
+Les bêtes de black city - T03 - le feu de la vengeance.cbr
+The Brother of All Men 002 (2022) (digital) (Son of Ultron-Empire).cbz
+DC Fifty-Two (52) Week One (2006) (Kryptonia-DCP).cbr
+Heroes For Hire v2 09 (2007) (DarthScanner-DCP).cbr
+Doom Patrol v4 012 [2005] (Bchry-DCP).cbr
+Black Panther's Prey #1(Aieiebrazoff-DCP)-Repack.cbz
+Hello Neighbor 02 - The Raven Brooks Disaster (2021) (Digital Rip) (Hourman-DCP).cbz
+Grimm Spotlight - Cinderella vs. Zombies (2021) (digital) (The Seeker-Empire).cbz
+Black's Myth 001 (2021) (digital) (Son of Ultron-Empire).cbz
+Donjon Antipodes T02 +10001 Le Coffre aux Âmes.pdf
+Ghost Rider 016 (2007) (Noads) (Team-DCP).cbr
+JLA Classified 38 (2007) (Wolfrider-DCP).cbr
+Olive 003 - On the Trail of the Nerpa (2021) (digital) (Mr Norrell-Empire).cbz
+Avengers v3 #054.cbz
+Doctor Strange - The Oath 01 (2006) (Kryptonia-DCP).cbr
+Red Robin 006 2010 Minutemen-DTermined.cbr
+056 - She-Hulk v2 032 (2008) (2 covers) (Minutemen-ReZone).cbr
+DC Fifty-Two (52) Week 030 (2007) (Kryptonia-DCP).cbr
+Detective Comics 1055 (2022) (Webrip) (The Last Kryptonian-DCP).cbz
+Spider-Man vs. Vampires 01 2010 Minutemen-DTs .cbz
+Grim 003 (2022) (digital) (Son of Ultron-Empire).cbz
+Wastelanders - Star-Lord 001 (2022) (Digital) (Zone-Empire).cbz
+Superman [2003-38] Adventures of Superman 621.cbr
+Elektra - Black, White & Blood 001 (2022) (Digital) (Zone-Empire).cbz
+Félix #15 - Heroic Album -1950- Le Tueur Fantome.cbz
+Ms. Marvel v2 09 (2006) (Team-DCP).cbr
+Stray Dogs - Dog Days 002 (2022) (digital) (Son of Ultron-Empire).cbz
+My Date With Monsters 002 (2021) (Digital) (Mephisto-Empire).cbz
+Friendly Neighborhood Spider-Man 02 (2006) (Variant Cvr) (Wildcarde1-DCP).cbr
+Acriboréa -T03- Des millions de soleils.cbr
+X-Men: Phoenix - Endsong 05 (of 5) [2005] (Team-DCP).cbr
+Usagi Yojimbo - Lone Goat and Kid 006 (2022) (digital) (Son of Ultron-Empire).cbz
+Robyn Hood Annual - The Swarm (2021) (digital) (The Seeker-Empire).cbz
+Azrael #025.cbr
+Nita Hawes' Nightmare Blog 002 (2021) (Digital) (Zone-Empire).cbz
+Dark Avengers-Uncanny X-Men - Utopia 001.cbr
+Naughty List 004 (2022) (digital) (Son of Ultron-Empire).cbz
+Atalante - La Légende-04-L'Envol Des Boréades.cbz
+Warlord of Mars 02 (6 covers).cbr
+Action Comics 857 (2007) (CamelotScans-DCP).cbr
+War For Earth - 3 002 (2022) (Webrip) (The Last Kryptonian-DCP).cbz
+Oracle - T04 - Le Malformé.cbz
+Battle Angel Alita #9_ Vol. 9 - Yukito Kishiro.epub
+Les aventuriers de l'intermonde - T01 - Mission Athènes.cbz
+Captain_America_and_The_Secret_Avengers_(2011)_(Minutemen-DTermined).cbr
+She-Hulk 002 (2022) (Digital) (Zone-Empire).cbz
+infinity inc 01 (2007) (racerx-dcp).cbz
+Wonder Girl 004 (2021) (digital) (Son of Ultron-Empire).cbz
+SEULS - T07 - Les Terres Basses.cbr
+Out of Body 003 (2021) (digital) (Son of Ultron-Empire).cbz
+Power Girl 09.cbr
+Thor 614 (2 covers) (2010) (noads) (Archangel & FP-CPS).cbr
+Iron Man 011 (2021) (Digital) (Zone-Empire).cbz
+Ms. Marvel - Beyond the Limit 002 (2022) (Digital) (Zone-Empire).cbz
+Ultimate X-Men #038.cbr
+Excalibur 022 (2021) (Digital) (Zone-Empire).cbz
+New Avengers 025 (2006) (Fixed) (Team-DCP).cbr
+T06.2 - Topkapi.pdf
+Thor Corps 2 of 4.cbr
+Shang-Chi - Brothers & Sisters Infinity Comic 003 (2021) (Digital-Mobile) (Infinity-Empire) (WebP).cbz
+X-Men To Serve And Protect 01 of 04 2010 .cbr
+08A - Blue Beetle 020.cbz
+The Joker Presents - A Puzzlebox Director's Cut 013 (2021) (digital) (Son of Ultron-Empire).cbz
+Alice Matheson - T01 - Jour Z.cbz
diff --git a/API.Benchmark/ParserBenchmarks.cs b/API.Benchmark/ParserBenchmarks.cs
index 63adc6985..d7706a3f4 100644
--- a/API.Benchmark/ParserBenchmarks.cs
+++ b/API.Benchmark/ParserBenchmarks.cs
@@ -5,75 +5,74 @@ using System.Text.RegularExpressions;
using BenchmarkDotNet.Attributes;
using BenchmarkDotNet.Order;
-namespace API.Benchmark
+namespace API.Benchmark;
+
+[MemoryDiagnoser]
+[Orderer(SummaryOrderPolicy.FastestToSlowest)]
+[RankColumn]
+public class ParserBenchmarks
{
- [MemoryDiagnoser]
- [Orderer(SummaryOrderPolicy.FastestToSlowest)]
- [RankColumn]
- public class ParserBenchmarks
+ private readonly IList _names;
+
+ private static readonly Regex NormalizeRegex = new Regex(@"[^a-zA-Z0-9]",
+ RegexOptions.IgnoreCase | RegexOptions.Compiled,
+ TimeSpan.FromMilliseconds(300));
+
+ private static readonly Regex IsEpub = new Regex(@"\.epub",
+ RegexOptions.IgnoreCase | RegexOptions.Compiled,
+ TimeSpan.FromMilliseconds(300));
+
+ public ParserBenchmarks()
{
- private readonly IList _names;
-
- private static readonly Regex NormalizeRegex = new Regex(@"[^a-zA-Z0-9]",
- RegexOptions.IgnoreCase | RegexOptions.Compiled,
- TimeSpan.FromMilliseconds(300));
-
- private static readonly Regex IsEpub = new Regex(@"\.epub",
- RegexOptions.IgnoreCase | RegexOptions.Compiled,
- TimeSpan.FromMilliseconds(300));
-
- public ParserBenchmarks()
- {
- // Read all series from SeriesNamesForNormalization.txt
- _names = File.ReadAllLines("Data/SeriesNamesForNormalization.txt");
- Console.WriteLine($"Performing benchmark on {_names.Count} series");
- }
-
- private static string Normalize(string name)
- {
- // ReSharper disable once UnusedVariable
- var ret = NormalizeRegex.Replace(name, string.Empty).ToLower();
- var normalized = NormalizeRegex.Replace(name, string.Empty).ToLower();
- return string.IsNullOrEmpty(normalized) ? name : normalized;
- }
-
-
-
- [Benchmark]
- public void TestNormalizeName()
- {
- foreach (var name in _names)
- {
- Normalize(name);
- }
- }
-
-
- [Benchmark]
- public void TestIsEpub()
- {
- foreach (var name in _names)
- {
- if ((name).ToLower() == ".epub")
- {
- /* No Operation */
- }
- }
- }
-
- [Benchmark]
- public void TestIsEpub_New()
- {
- foreach (var name in _names)
- {
-
- if (Path.GetExtension(name).Equals(".epub", StringComparison.InvariantCultureIgnoreCase))
- {
- /* No Operation */
- }
- }
- }
-
-
+ // Read all series from SeriesNamesForNormalization.txt
+ _names = File.ReadAllLines("Data/SeriesNamesForNormalization.txt");
+ Console.WriteLine($"Performing benchmark on {_names.Count} series");
}
+
+ private static string Normalize(string name)
+ {
+ // ReSharper disable once UnusedVariable
+ var ret = NormalizeRegex.Replace(name, string.Empty).ToLower();
+ var normalized = NormalizeRegex.Replace(name, string.Empty).ToLower();
+ return string.IsNullOrEmpty(normalized) ? name : normalized;
+ }
+
+
+
+ [Benchmark]
+ public void TestNormalizeName()
+ {
+ foreach (var name in _names)
+ {
+ Normalize(name);
+ }
+ }
+
+
+ [Benchmark]
+ public void TestIsEpub()
+ {
+ foreach (var name in _names)
+ {
+ if ((name).ToLower() == ".epub")
+ {
+ /* No Operation */
+ }
+ }
+ }
+
+ [Benchmark]
+ public void TestIsEpub_New()
+ {
+ foreach (var name in _names)
+ {
+
+ if (Path.GetExtension(name).Equals(".epub", StringComparison.InvariantCultureIgnoreCase))
+ {
+ /* No Operation */
+ }
+ }
+ }
+
+
}
diff --git a/API.Benchmark/Program.cs b/API.Benchmark/Program.cs
index 4a659a1b8..76ed97c70 100644
--- a/API.Benchmark/Program.cs
+++ b/API.Benchmark/Program.cs
@@ -1,22 +1,14 @@
using BenchmarkDotNet.Running;
-namespace API.Benchmark
-{
- ///
- /// To build this, cd into API.Benchmark directory and run
- /// dotnet build -c Release
- /// then copy the outputted dll
- /// dotnet copied_string\API.Benchmark.dll
- ///
- public static class Program
- {
- private static void Main(string[] args)
- {
- //BenchmarkRunner.Run();
- //BenchmarkRunner.Run();
- //BenchmarkRunner.Run();
- BenchmarkRunner.Run();
+namespace API.Benchmark;
- }
- }
+///
+/// To build this, cd into API.Benchmark directory and run
+/// dotnet build -c Release
+/// then copy the outputted dll
+/// dotnet copied_string\API.Benchmark.dll
+///
+public static class Program
+{
+ private static void Main(string[] args) => BenchmarkSwitcher.FromAssembly(typeof(Program).Assembly).Run(args);
}
diff --git a/API.Benchmark/TestBenchmark.cs b/API.Benchmark/TestBenchmark.cs
index c5d2d18e1..0b4880690 100644
--- a/API.Benchmark/TestBenchmark.cs
+++ b/API.Benchmark/TestBenchmark.cs
@@ -6,61 +6,60 @@ using API.Extensions;
using BenchmarkDotNet.Attributes;
using BenchmarkDotNet.Order;
-namespace API.Benchmark
+namespace API.Benchmark;
+
+///
+/// This is used as a scratchpad for testing
+///
+[MemoryDiagnoser]
+[Orderer(SummaryOrderPolicy.FastestToSlowest)]
+[RankColumn]
+public class TestBenchmark
{
- ///
- /// This is used as a scratchpad for testing
- ///
- [MemoryDiagnoser]
- [Orderer(SummaryOrderPolicy.FastestToSlowest)]
- [RankColumn]
- public class TestBenchmark
+ private static IEnumerable GenerateVolumes(int max)
{
- private static IEnumerable GenerateVolumes(int max)
+ var random = new Random();
+ var maxIterations = random.Next(max) + 1;
+ var list = new List();
+ for (var i = 0; i < maxIterations; i++)
{
- var random = new Random();
- var maxIterations = random.Next(max) + 1;
- var list = new List();
- for (var i = 0; i < maxIterations; i++)
+ list.Add(new VolumeDto()
{
- list.Add(new VolumeDto()
- {
- Number = random.Next(10) > 5 ? 1 : 0,
- Chapters = GenerateChapters()
- });
- }
-
- return list;
- }
-
- private static List GenerateChapters()
- {
- var list = new List();
- for (var i = 1; i < 40; i++)
- {
- list.Add(new ChapterDto()
- {
- Range = i + string.Empty
- });
- }
-
- return list;
- }
-
- private static void SortSpecialChapters(IEnumerable volumes)
- {
- foreach (var v in volumes.Where(vDto => vDto.Number == 0))
- {
- v.Chapters = v.Chapters.OrderByNatural(x => x.Range).ToList();
- }
- }
-
- [Benchmark]
- public void TestSortSpecialChapters()
- {
- var volumes = GenerateVolumes(10);
- SortSpecialChapters(volumes);
+ Number = random.Next(10) > 5 ? 1 : 0,
+ Chapters = GenerateChapters()
+ });
}
+ return list;
}
+
+ private static List GenerateChapters()
+ {
+ var list = new List();
+ for (var i = 1; i < 40; i++)
+ {
+ list.Add(new ChapterDto()
+ {
+ Range = i + string.Empty
+ });
+ }
+
+ return list;
+ }
+
+ private static void SortSpecialChapters(IEnumerable volumes)
+ {
+ foreach (var v in volumes.Where(vDto => vDto.Number == 0))
+ {
+ v.Chapters = v.Chapters.OrderByNatural(x => x.Range).ToList();
+ }
+ }
+
+ [Benchmark]
+ public void TestSortSpecialChapters()
+ {
+ var volumes = GenerateVolumes(10);
+ SortSpecialChapters(volumes);
+ }
+
}
diff --git a/API.Tests/API.Tests.csproj b/API.Tests/API.Tests.csproj
index fba1b24f8..6380fc95f 100644
--- a/API.Tests/API.Tests.csproj
+++ b/API.Tests/API.Tests.csproj
@@ -7,10 +7,10 @@
-
-
+
+
-
+
runtime; build; native; contentfiles; analyzers; buildtransitive
diff --git a/API.Tests/BasicTest.cs b/API.Tests/BasicTest.cs
new file mode 100644
index 000000000..fb2f2bbf0
--- /dev/null
+++ b/API.Tests/BasicTest.cs
@@ -0,0 +1,118 @@
+using System.Collections.Generic;
+using System.Data.Common;
+using System.IO.Abstractions.TestingHelpers;
+using System.Linq;
+using System.Threading.Tasks;
+using API.Data;
+using API.Entities;
+using API.Entities.Enums;
+using API.Helpers;
+using API.Services;
+using AutoMapper;
+using Microsoft.Data.Sqlite;
+using Microsoft.EntityFrameworkCore;
+using Microsoft.EntityFrameworkCore.Infrastructure;
+using Microsoft.Extensions.Logging;
+using NSubstitute;
+
+namespace API.Tests;
+
+public abstract class BasicTest
+{
+ private readonly DbConnection _connection;
+ protected readonly DataContext _context;
+ protected readonly IUnitOfWork _unitOfWork;
+
+
+ protected const string CacheDirectory = "C:/kavita/config/cache/";
+ protected const string CoverImageDirectory = "C:/kavita/config/covers/";
+ protected const string BackupDirectory = "C:/kavita/config/backups/";
+ protected const string LogDirectory = "C:/kavita/config/logs/";
+ protected const string BookmarkDirectory = "C:/kavita/config/bookmarks/";
+ protected const string TempDirectory = "C:/kavita/config/temp/";
+
+ protected BasicTest()
+ {
+ var contextOptions = new DbContextOptionsBuilder()
+ .UseSqlite(CreateInMemoryDatabase())
+ .Options;
+ _connection = RelationalOptionsExtension.Extract(contextOptions).Connection;
+
+ _context = new DataContext(contextOptions);
+ Task.Run(SeedDb).GetAwaiter().GetResult();
+
+ var config = new MapperConfiguration(cfg => cfg.AddProfile());
+ var mapper = config.CreateMapper();
+
+ _unitOfWork = new UnitOfWork(_context, mapper, null);
+ }
+
+ private static DbConnection CreateInMemoryDatabase()
+ {
+ var connection = new SqliteConnection("Filename=:memory:");
+
+ connection.Open();
+
+ return connection;
+ }
+
+ private async Task SeedDb()
+ {
+ await _context.Database.MigrateAsync();
+ var filesystem = CreateFileSystem();
+
+ await Seed.SeedSettings(_context, new DirectoryService(Substitute.For>(), filesystem));
+
+ var setting = await _context.ServerSetting.Where(s => s.Key == ServerSettingKey.CacheDirectory).SingleAsync();
+ setting.Value = CacheDirectory;
+
+ setting = await _context.ServerSetting.Where(s => s.Key == ServerSettingKey.BackupDirectory).SingleAsync();
+ setting.Value = BackupDirectory;
+
+ setting = await _context.ServerSetting.Where(s => s.Key == ServerSettingKey.BookmarkDirectory).SingleAsync();
+ setting.Value = BookmarkDirectory;
+
+ setting = await _context.ServerSetting.Where(s => s.Key == ServerSettingKey.TotalLogs).SingleAsync();
+ setting.Value = "10";
+
+ _context.ServerSetting.Update(setting);
+
+ _context.Library.Add(new Library()
+ {
+ Name = "Manga",
+ Folders = new List()
+ {
+ new FolderPath()
+ {
+ Path = "C:/data/"
+ }
+ }
+ });
+ return await _context.SaveChangesAsync() > 0;
+ }
+
+ protected async Task ResetDb()
+ {
+ _context.Series.RemoveRange(_context.Series.ToList());
+ _context.Users.RemoveRange(_context.Users.ToList());
+ _context.AppUserBookmark.RemoveRange(_context.AppUserBookmark.ToList());
+
+ await _context.SaveChangesAsync();
+ }
+
+ protected static MockFileSystem CreateFileSystem()
+ {
+ var fileSystem = new MockFileSystem();
+ fileSystem.Directory.SetCurrentDirectory("C:/kavita/");
+ fileSystem.AddDirectory("C:/kavita/config/");
+ fileSystem.AddDirectory(CacheDirectory);
+ fileSystem.AddDirectory(CoverImageDirectory);
+ fileSystem.AddDirectory(BackupDirectory);
+ fileSystem.AddDirectory(BookmarkDirectory);
+ fileSystem.AddDirectory(LogDirectory);
+ fileSystem.AddDirectory(TempDirectory);
+ fileSystem.AddDirectory("C:/data/");
+
+ return fileSystem;
+ }
+}
diff --git a/API.Tests/Comparers/ChapterSortComparerTest.cs b/API.Tests/Comparers/ChapterSortComparerTest.cs
index 11fecf2c2..220be052d 100644
--- a/API.Tests/Comparers/ChapterSortComparerTest.cs
+++ b/API.Tests/Comparers/ChapterSortComparerTest.cs
@@ -2,18 +2,17 @@
using API.Comparators;
using Xunit;
-namespace API.Tests.Comparers
+namespace API.Tests.Comparers;
+
+public class ChapterSortComparerTest
{
- public class ChapterSortComparerTest
+ [Theory]
+ [InlineData(new[] {1, 2, 0}, new[] {1, 2, 0})]
+ [InlineData(new[] {3, 1, 2}, new[] {1, 2, 3})]
+ [InlineData(new[] {1, 0, 0}, new[] {1, 0, 0})]
+ public void ChapterSortTest(int[] input, int[] expected)
{
- [Theory]
- [InlineData(new[] {1, 2, 0}, new[] {1, 2, 0})]
- [InlineData(new[] {3, 1, 2}, new[] {1, 2, 3})]
- [InlineData(new[] {1, 0, 0}, new[] {1, 0, 0})]
- public void ChapterSortTest(int[] input, int[] expected)
- {
- Assert.Equal(expected, input.OrderBy(f => f, new ChapterSortComparer()).ToArray());
- }
-
+ Assert.Equal(expected, input.OrderBy(f => f, new ChapterSortComparer()).ToArray());
}
-}
\ No newline at end of file
+
+}
diff --git a/API.Tests/Comparers/StringLogicalComparerTest.cs b/API.Tests/Comparers/StringLogicalComparerTest.cs
index 3d13e43ac..13f88243d 100644
--- a/API.Tests/Comparers/StringLogicalComparerTest.cs
+++ b/API.Tests/Comparers/StringLogicalComparerTest.cs
@@ -2,33 +2,32 @@
using API.Comparators;
using Xunit;
-namespace API.Tests.Comparers
-{
- public class StringLogicalComparerTest
- {
- [Theory]
- [InlineData(
- new[] {"x1.jpg", "x10.jpg", "x3.jpg", "x4.jpg", "x11.jpg"},
- new[] {"x1.jpg", "x3.jpg", "x4.jpg", "x10.jpg", "x11.jpg"}
- )]
- [InlineData(
- new[] {"a.jpg", "aaa.jpg", "1.jpg", },
- new[] {"1.jpg", "a.jpg", "aaa.jpg"}
- )]
- [InlineData(
- new[] {"a.jpg", "aaa.jpg", "1.jpg", "!cover.png"},
- new[] {"!cover.png", "1.jpg", "a.jpg", "aaa.jpg"}
- )]
- public void StringComparer(string[] input, string[] expected)
- {
- Array.Sort(input, StringLogicalComparer.Compare);
+namespace API.Tests.Comparers;
- var i = 0;
- foreach (var s in input)
- {
- Assert.Equal(s, expected[i]);
- i++;
- }
+public class StringLogicalComparerTest
+{
+ [Theory]
+ [InlineData(
+ new[] {"x1.jpg", "x10.jpg", "x3.jpg", "x4.jpg", "x11.jpg"},
+ new[] {"x1.jpg", "x3.jpg", "x4.jpg", "x10.jpg", "x11.jpg"}
+ )]
+ [InlineData(
+ new[] {"a.jpg", "aaa.jpg", "1.jpg", },
+ new[] {"1.jpg", "a.jpg", "aaa.jpg"}
+ )]
+ [InlineData(
+ new[] {"a.jpg", "aaa.jpg", "1.jpg", "!cover.png"},
+ new[] {"!cover.png", "1.jpg", "a.jpg", "aaa.jpg"}
+ )]
+ public void StringComparer(string[] input, string[] expected)
+ {
+ Array.Sort(input, StringLogicalComparer.Compare);
+
+ var i = 0;
+ foreach (var s in input)
+ {
+ Assert.Equal(s, expected[i]);
+ i++;
}
}
}
diff --git a/API.Tests/Converters/CronConverterTests.cs b/API.Tests/Converters/CronConverterTests.cs
index 813d82426..4d26edef7 100644
--- a/API.Tests/Converters/CronConverterTests.cs
+++ b/API.Tests/Converters/CronConverterTests.cs
@@ -1,19 +1,18 @@
using API.Helpers.Converters;
using Xunit;
-namespace API.Tests.Converters
+namespace API.Tests.Converters;
+
+public class CronConverterTests
{
- public class CronConverterTests
+ [Theory]
+ [InlineData("daily", "0 0 * * *")]
+ [InlineData("disabled", "0 0 31 2 *")]
+ [InlineData("weekly", "0 0 * * 1")]
+ [InlineData("", "0 0 31 2 *")]
+ [InlineData("sdfgdf", "")]
+ public void ConvertTest(string input, string expected)
{
- [Theory]
- [InlineData("daily", "0 0 * * *")]
- [InlineData("disabled", "0 0 31 2 *")]
- [InlineData("weekly", "0 0 * * 1")]
- [InlineData("", "0 0 31 2 *")]
- [InlineData("sdfgdf", "")]
- public void ConvertTest(string input, string expected)
- {
- Assert.Equal(expected, CronConverter.ConvertToCronNotation(input));
- }
+ Assert.Equal(expected, CronConverter.ConvertToCronNotation(input));
}
}
diff --git a/API.Tests/Entities/ComicInfoTests.cs b/API.Tests/Entities/ComicInfoTests.cs
index 325299cf8..ea8b0187d 100644
--- a/API.Tests/Entities/ComicInfoTests.cs
+++ b/API.Tests/Entities/ComicInfoTests.cs
@@ -35,4 +35,62 @@ public class ComicInfoTests
Assert.Equal(AgeRating.RatingPending, ComicInfo.ConvertAgeRatingToEnum("rating pending"));
}
#endregion
+
+
+ #region CalculatedCount
+
+ [Fact]
+ public void CalculatedCount_ReturnsVolumeCount()
+ {
+ var ci = new ComicInfo()
+ {
+ Number = "5",
+ Volume = "10",
+ Count = 10
+ };
+
+ Assert.Equal(5, ci.CalculatedCount());
+ }
+
+ [Fact]
+ public void CalculatedCount_ReturnsNoCountWhenCountNotSet()
+ {
+ var ci = new ComicInfo()
+ {
+ Number = "5",
+ Volume = "10",
+ Count = 0
+ };
+
+ Assert.Equal(5, ci.CalculatedCount());
+ }
+
+ [Fact]
+ public void CalculatedCount_ReturnsNumberCount()
+ {
+ var ci = new ComicInfo()
+ {
+ Number = "5",
+ Volume = "",
+ Count = 10
+ };
+
+ Assert.Equal(5, ci.CalculatedCount());
+ }
+
+ [Fact]
+ public void CalculatedCount_ReturnsNumberCount_OnlyWholeNumber()
+ {
+ var ci = new ComicInfo()
+ {
+ Number = "5.7",
+ Volume = "",
+ Count = 10
+ };
+
+ Assert.Equal(5, ci.CalculatedCount());
+ }
+
+
+ #endregion
}
diff --git a/API.Tests/Entities/SeriesTest.cs b/API.Tests/Entities/SeriesTest.cs
index 70897b49f..0b49bd3dd 100644
--- a/API.Tests/Entities/SeriesTest.cs
+++ b/API.Tests/Entities/SeriesTest.cs
@@ -1,27 +1,26 @@
using API.Data;
using Xunit;
-namespace API.Tests.Entities
+namespace API.Tests.Entities;
+
+///
+/// Tests for
+///
+public class SeriesTest
{
- ///
- /// Tests for
- ///
- public class SeriesTest
+ [Theory]
+ [InlineData("Darker than Black")]
+ public void CreateSeries(string name)
{
- [Theory]
- [InlineData("Darker than Black")]
- public void CreateSeries(string name)
- {
- var key = API.Services.Tasks.Scanner.Parser.Parser.Normalize(name);
- var series = DbFactory.Series(name);
- Assert.Equal(0, series.Id);
- Assert.Equal(0, series.Pages);
- Assert.Equal(name, series.Name);
- Assert.Null(series.CoverImage);
- Assert.Equal(name, series.LocalizedName);
- Assert.Equal(name, series.SortName);
- Assert.Equal(name, series.OriginalName);
- Assert.Equal(key, series.NormalizedName);
- }
+ var key = API.Services.Tasks.Scanner.Parser.Parser.Normalize(name);
+ var series = DbFactory.Series(name);
+ Assert.Equal(0, series.Id);
+ Assert.Equal(0, series.Pages);
+ Assert.Equal(name, series.Name);
+ Assert.Null(series.CoverImage);
+ Assert.Equal(name, series.LocalizedName);
+ Assert.Equal(name, series.SortName);
+ Assert.Equal(name, series.OriginalName);
+ Assert.Equal(key, series.NormalizedName);
}
-}
\ No newline at end of file
+}
diff --git a/API.Tests/Extensions/ChapterListExtensionsTests.cs b/API.Tests/Extensions/ChapterListExtensionsTests.cs
index a1beddf09..f6ea62408 100644
--- a/API.Tests/Extensions/ChapterListExtensionsTests.cs
+++ b/API.Tests/Extensions/ChapterListExtensionsTests.cs
@@ -1,3 +1,4 @@
+using System;
using System.Collections.Generic;
using System.Linq;
using API.Entities;
@@ -6,140 +7,180 @@ using API.Extensions;
using API.Parser;
using Xunit;
-namespace API.Tests.Extensions
+namespace API.Tests.Extensions;
+
+public class ChapterListExtensionsTests
{
- public class ChapterListExtensionsTests
+ private static Chapter CreateChapter(string range, string number, MangaFile file, bool isSpecial)
{
- private static Chapter CreateChapter(string range, string number, MangaFile file, bool isSpecial)
+ return new Chapter()
{
- return new Chapter()
- {
- Range = range,
- Number = number,
- Files = new List() {file},
- IsSpecial = isSpecial
- };
- }
+ Range = range,
+ Number = number,
+ Files = new List() {file},
+ IsSpecial = isSpecial
+ };
+ }
- private static MangaFile CreateFile(string file, MangaFormat format)
+ private static MangaFile CreateFile(string file, MangaFormat format)
+ {
+ return new MangaFile()
{
- return new MangaFile()
- {
- FilePath = file,
- Format = format
- };
- }
-
- [Fact]
- public void GetAnyChapterByRange_Test_ShouldBeNull()
- {
- var info = new ParserInfo()
- {
- Chapters = "0",
- Edition = "",
- Format = MangaFormat.Archive,
- FullFilePath = "/manga/darker than black.cbz",
- Filename = "darker than black.cbz",
- IsSpecial = false,
- Series = "darker than black",
- Title = "darker than black",
- Volumes = "0"
- };
-
- var chapterList = new List()
- {
- CreateChapter("darker than black - Some special", "0", CreateFile("/manga/darker than black - special.cbz", MangaFormat.Archive), true)
- };
-
- var actualChapter = chapterList.GetChapterByRange(info);
-
- Assert.NotEqual(chapterList[0], actualChapter);
-
- }
-
- [Fact]
- public void GetAnyChapterByRange_Test_ShouldBeNotNull()
- {
- var info = new ParserInfo()
- {
- Chapters = "0",
- Edition = "",
- Format = MangaFormat.Archive,
- FullFilePath = "/manga/darker than black.cbz",
- Filename = "darker than black.cbz",
- IsSpecial = true,
- Series = "darker than black",
- Title = "darker than black",
- Volumes = "0"
- };
-
- var chapterList = new List()
- {
- CreateChapter("darker than black", "0", CreateFile("/manga/darker than black.cbz", MangaFormat.Archive), true)
- };
-
- var actualChapter = chapterList.GetChapterByRange(info);
-
- Assert.Equal(chapterList[0], actualChapter);
- }
-
- [Fact]
- public void GetChapterByRange_On_Duplicate_Files_Test_Should_Not_Error()
- {
- var info = new ParserInfo()
- {
- Chapters = "0",
- Edition = "",
- Format = MangaFormat.Archive,
- FullFilePath = "/manga/detective comics #001.cbz",
- Filename = "detective comics #001.cbz",
- IsSpecial = true,
- Series = "detective comics",
- Title = "detective comics",
- Volumes = "0"
- };
-
- var chapterList = new List()
- {
- CreateChapter("detective comics", "0", CreateFile("/manga/detective comics #001.cbz", MangaFormat.Archive), true),
- CreateChapter("detective comics", "0", CreateFile("/manga/detective comics #001.cbz", MangaFormat.Archive), true)
- };
-
- var actualChapter = chapterList.GetChapterByRange(info);
-
- Assert.Equal(chapterList[0], actualChapter);
-
- }
-
- #region GetFirstChapterWithFiles
+ FilePath = file,
+ Format = format
+ };
+ }
[Fact]
- public void GetFirstChapterWithFiles_ShouldReturnAllChapters()
+ public void GetAnyChapterByRange_Test_ShouldBeNull()
+ {
+ var info = new ParserInfo()
{
- var chapterList = new List()
- {
- CreateChapter("darker than black", "0", CreateFile("/manga/darker than black.cbz", MangaFormat.Archive), true),
- CreateChapter("darker than black", "1", CreateFile("/manga/darker than black.cbz", MangaFormat.Archive), false),
- };
+ Chapters = "0",
+ Edition = "",
+ Format = MangaFormat.Archive,
+ FullFilePath = "/manga/darker than black.cbz",
+ Filename = "darker than black.cbz",
+ IsSpecial = false,
+ Series = "darker than black",
+ Title = "darker than black",
+ Volumes = "0"
+ };
- Assert.Equal(chapterList.First(), chapterList.GetFirstChapterWithFiles());
- }
-
- [Fact]
- public void GetFirstChapterWithFiles_ShouldReturnSecondChapter()
+ var chapterList = new List()
{
- var chapterList = new List()
- {
- CreateChapter("darker than black", "0", CreateFile("/manga/darker than black.cbz", MangaFormat.Archive), true),
- CreateChapter("darker than black", "1", CreateFile("/manga/darker than black.cbz", MangaFormat.Archive), false),
- };
+ CreateChapter("darker than black - Some special", "0", CreateFile("/manga/darker than black - special.cbz", MangaFormat.Archive), true)
+ };
- chapterList.First().Files = new List();
+ var actualChapter = chapterList.GetChapterByRange(info);
- Assert.Equal(chapterList.Last(), chapterList.GetFirstChapterWithFiles());
- }
+ Assert.NotEqual(chapterList[0], actualChapter);
-
- #endregion
}
+
+ [Fact]
+ public void GetAnyChapterByRange_Test_ShouldBeNotNull()
+ {
+ var info = new ParserInfo()
+ {
+ Chapters = "0",
+ Edition = "",
+ Format = MangaFormat.Archive,
+ FullFilePath = "/manga/darker than black.cbz",
+ Filename = "darker than black.cbz",
+ IsSpecial = true,
+ Series = "darker than black",
+ Title = "darker than black",
+ Volumes = "0"
+ };
+
+ var chapterList = new List()
+ {
+ CreateChapter("darker than black", "0", CreateFile("/manga/darker than black.cbz", MangaFormat.Archive), true)
+ };
+
+ var actualChapter = chapterList.GetChapterByRange(info);
+
+ Assert.Equal(chapterList[0], actualChapter);
+ }
+
+ [Fact]
+ public void GetChapterByRange_On_Duplicate_Files_Test_Should_Not_Error()
+ {
+ var info = new ParserInfo()
+ {
+ Chapters = "0",
+ Edition = "",
+ Format = MangaFormat.Archive,
+ FullFilePath = "/manga/detective comics #001.cbz",
+ Filename = "detective comics #001.cbz",
+ IsSpecial = true,
+ Series = "detective comics",
+ Title = "detective comics",
+ Volumes = "0"
+ };
+
+ var chapterList = new List()
+ {
+ CreateChapter("detective comics", "0", CreateFile("/manga/detective comics #001.cbz", MangaFormat.Archive), true),
+ CreateChapter("detective comics", "0", CreateFile("/manga/detective comics #001.cbz", MangaFormat.Archive), true)
+ };
+
+ var actualChapter = chapterList.GetChapterByRange(info);
+
+ Assert.Equal(chapterList[0], actualChapter);
+ }
+
+ #region GetFirstChapterWithFiles
+
+ [Fact]
+ public void GetFirstChapterWithFiles_ShouldReturnAllChapters()
+ {
+ var chapterList = new List()
+ {
+ CreateChapter("darker than black", "0", CreateFile("/manga/darker than black.cbz", MangaFormat.Archive), true),
+ CreateChapter("darker than black", "1", CreateFile("/manga/darker than black.cbz", MangaFormat.Archive), false),
+ };
+
+ Assert.Equal(chapterList.First(), chapterList.GetFirstChapterWithFiles());
+ }
+
+ [Fact]
+ public void GetFirstChapterWithFiles_ShouldReturnSecondChapter()
+ {
+ var chapterList = new List()
+ {
+ CreateChapter("darker than black", "0", CreateFile("/manga/darker than black.cbz", MangaFormat.Archive), true),
+ CreateChapter("darker than black", "1", CreateFile("/manga/darker than black.cbz", MangaFormat.Archive), false),
+ };
+
+ chapterList.First().Files = new List();
+
+ Assert.Equal(chapterList.Last(), chapterList.GetFirstChapterWithFiles());
+ }
+
+
+ #endregion
+
+ #region MinimumReleaseYear
+
+ [Fact]
+ public void MinimumReleaseYear_ZeroIfNoChapters()
+ {
+ var chapterList = new List();
+
+ Assert.Equal(0, chapterList.MinimumReleaseYear());
+ }
+
+ [Fact]
+ public void MinimumReleaseYear_ZeroIfNoValidDates()
+ {
+ var chapterList = new List()
+ {
+ CreateChapter("detective comics", "0", CreateFile("/manga/detective comics #001.cbz", MangaFormat.Archive), true),
+ CreateChapter("detective comics", "0", CreateFile("/manga/detective comics #001.cbz", MangaFormat.Archive), true)
+ };
+
+ chapterList[0].ReleaseDate = new DateTime(10, 1, 1);
+ chapterList[1].ReleaseDate = DateTime.MinValue;
+
+ Assert.Equal(0, chapterList.MinimumReleaseYear());
+ }
+
+ [Fact]
+ public void MinimumReleaseYear_MinValidReleaseYear()
+ {
+ var chapterList = new List()
+ {
+ CreateChapter("detective comics", "0", CreateFile("/manga/detective comics #001.cbz", MangaFormat.Archive), true),
+ CreateChapter("detective comics", "0", CreateFile("/manga/detective comics #001.cbz", MangaFormat.Archive), true)
+ };
+
+ chapterList[0].ReleaseDate = new DateTime(2002, 1, 1);
+ chapterList[1].ReleaseDate = new DateTime(2012, 2, 1);
+
+ Assert.Equal(2002, chapterList.MinimumReleaseYear());
+ }
+
+ #endregion
}
diff --git a/API.Tests/Extensions/EnumerableExtensionsTests.cs b/API.Tests/Extensions/EnumerableExtensionsTests.cs
index 0f04ac9d7..e115d45f3 100644
--- a/API.Tests/Extensions/EnumerableExtensionsTests.cs
+++ b/API.Tests/Extensions/EnumerableExtensionsTests.cs
@@ -1,4 +1,7 @@
-using System.Linq;
+using System.Collections.Generic;
+using System.Linq;
+using API.Data.Misc;
+using API.Entities.Enums;
using API.Extensions;
using Xunit;
@@ -132,4 +135,33 @@ public class EnumerableExtensionsTests
i++;
}
}
+
+ [Theory]
+ [InlineData(true, 2)]
+ [InlineData(false, 1)]
+ public void RestrictAgainstAgeRestriction_ShouldRestrictEverythingAboveTeen(bool includeUnknowns, int expectedCount)
+ {
+ var items = new List()
+ {
+ new RecentlyAddedSeries()
+ {
+ AgeRating = AgeRating.Teen,
+ },
+ new RecentlyAddedSeries()
+ {
+ AgeRating = AgeRating.Unknown,
+ },
+ new RecentlyAddedSeries()
+ {
+ AgeRating = AgeRating.X18Plus,
+ },
+ };
+
+ var filtered = items.RestrictAgainstAgeRestriction(new AgeRestriction()
+ {
+ AgeRating = AgeRating.Teen,
+ IncludeUnknowns = includeUnknowns
+ });
+ Assert.Equal(expectedCount, filtered.Count());
+ }
}
diff --git a/API.Tests/Extensions/FileInfoExtensionsTests.cs b/API.Tests/Extensions/FileInfoExtensionsTests.cs
index 5e17ecaeb..e708356a9 100644
--- a/API.Tests/Extensions/FileInfoExtensionsTests.cs
+++ b/API.Tests/Extensions/FileInfoExtensionsTests.cs
@@ -4,30 +4,29 @@ using System.IO;
using API.Extensions;
using Xunit;
-namespace API.Tests.Extensions
+namespace API.Tests.Extensions;
+
+public class FileInfoExtensionsTests
{
- public class FileInfoExtensionsTests
+ private static readonly string TestDirectory = Path.Join(Directory.GetCurrentDirectory(), "../../../Extensions/Test Data/");
+
+ [Fact]
+ public void HasFileBeenModifiedSince_ShouldBeFalse()
{
- private static readonly string TestDirectory = Path.Join(Directory.GetCurrentDirectory(), "../../../Extensions/Test Data/");
+ var filepath = Path.Join(TestDirectory, "not modified.txt");
+ var date = new FileInfo(filepath).LastWriteTime;
+ Assert.False(new FileInfo(filepath).HasFileBeenModifiedSince(date));
+ File.ReadAllText(filepath);
+ Assert.False(new FileInfo(filepath).HasFileBeenModifiedSince(date));
+ }
- [Fact]
- public void HasFileBeenModifiedSince_ShouldBeFalse()
- {
- var filepath = Path.Join(TestDirectory, "not modified.txt");
- var date = new FileInfo(filepath).LastWriteTime;
- Assert.False(new FileInfo(filepath).HasFileBeenModifiedSince(date));
- File.ReadAllText(filepath);
- Assert.False(new FileInfo(filepath).HasFileBeenModifiedSince(date));
- }
-
- [Fact]
- public void HasFileBeenModifiedSince_ShouldBeTrue()
- {
- var filepath = Path.Join(TestDirectory, "modified on run.txt");
- var date = new FileInfo(filepath).LastWriteTime;
- Assert.False(new FileInfo(filepath).HasFileBeenModifiedSince(date));
- File.AppendAllLines(filepath, new[] { DateTime.Now.ToString(CultureInfo.InvariantCulture) });
- Assert.True(new FileInfo(filepath).HasFileBeenModifiedSince(date));
- }
+ [Fact]
+ public void HasFileBeenModifiedSince_ShouldBeTrue()
+ {
+ var filepath = Path.Join(TestDirectory, "modified on run.txt");
+ var date = new FileInfo(filepath).LastWriteTime;
+ Assert.False(new FileInfo(filepath).HasFileBeenModifiedSince(date));
+ File.AppendAllLines(filepath, new[] { DateTime.Now.ToString(CultureInfo.InvariantCulture) });
+ Assert.True(new FileInfo(filepath).HasFileBeenModifiedSince(date));
}
}
diff --git a/API.Tests/Extensions/ParserInfoListExtensionsTests.cs b/API.Tests/Extensions/ParserInfoListExtensionsTests.cs
index ff20403b1..b6a5ca362 100644
--- a/API.Tests/Extensions/ParserInfoListExtensionsTests.cs
+++ b/API.Tests/Extensions/ParserInfoListExtensionsTests.cs
@@ -5,49 +5,49 @@ using API.Entities.Enums;
using API.Extensions;
using API.Parser;
using API.Services;
+using API.Services.Tasks.Scanner.Parser;
using API.Tests.Helpers;
using Microsoft.Extensions.Logging;
using NSubstitute;
using Xunit;
-namespace API.Tests.Extensions
+namespace API.Tests.Extensions;
+
+public class ParserInfoListExtensions
{
- public class ParserInfoListExtensions
+ private readonly IDefaultParser _defaultParser;
+ public ParserInfoListExtensions()
{
- private readonly IDefaultParser _defaultParser;
- public ParserInfoListExtensions()
+ _defaultParser =
+ new DefaultParser(new DirectoryService(Substitute.For>(),
+ new MockFileSystem()));
+ }
+
+ [Theory]
+ [InlineData(new[] {"1", "1", "3-5", "5", "8", "0", "0"}, new[] {"1", "3-5", "5", "8", "0"})]
+ public void DistinctVolumesTest(string[] volumeNumbers, string[] expectedNumbers)
+ {
+ var infos = volumeNumbers.Select(n => new ParserInfo() {Volumes = n}).ToList();
+ Assert.Equal(expectedNumbers, infos.DistinctVolumes());
+ }
+
+ [Theory]
+ [InlineData(new[] {@"Cynthia The Mission - c000-006 (v06) [Desudesu&Brolen].zip"}, new[] {@"E:\Manga\Cynthia the Mission\Cynthia The Mission - c000-006 (v06) [Desudesu&Brolen].zip"}, true)]
+ [InlineData(new[] {@"Cynthia The Mission - c000-006 (v06-07) [Desudesu&Brolen].zip"}, new[] {@"E:\Manga\Cynthia the Mission\Cynthia The Mission - c000-006 (v06) [Desudesu&Brolen].zip"}, true)]
+ [InlineData(new[] {@"Cynthia The Mission v20 c12-20 [Desudesu&Brolen].zip"}, new[] {@"E:\Manga\Cynthia the Mission\Cynthia The Mission - c000-006 (v06) [Desudesu&Brolen].zip"}, false)]
+ public void HasInfoTest(string[] inputInfos, string[] inputChapters, bool expectedHasInfo)
+ {
+ var infos = new List();
+ foreach (var filename in inputInfos)
{
- _defaultParser =
- new DefaultParser(new DirectoryService(Substitute.For>(),
- new MockFileSystem()));
+ infos.Add(_defaultParser.Parse(
+ filename,
+ string.Empty));
}
- [Theory]
- [InlineData(new[] {"1", "1", "3-5", "5", "8", "0", "0"}, new[] {"1", "3-5", "5", "8", "0"})]
- public void DistinctVolumesTest(string[] volumeNumbers, string[] expectedNumbers)
- {
- var infos = volumeNumbers.Select(n => new ParserInfo() {Volumes = n}).ToList();
- Assert.Equal(expectedNumbers, infos.DistinctVolumes());
- }
+ var files = inputChapters.Select(s => EntityFactory.CreateMangaFile(s, MangaFormat.Archive, 199)).ToList();
+ var chapter = EntityFactory.CreateChapter("0-6", false, files);
- [Theory]
- [InlineData(new[] {@"Cynthia The Mission - c000-006 (v06) [Desudesu&Brolen].zip"}, new[] {@"E:\Manga\Cynthia the Mission\Cynthia The Mission - c000-006 (v06) [Desudesu&Brolen].zip"}, true)]
- [InlineData(new[] {@"Cynthia The Mission - c000-006 (v06-07) [Desudesu&Brolen].zip"}, new[] {@"E:\Manga\Cynthia the Mission\Cynthia The Mission - c000-006 (v06) [Desudesu&Brolen].zip"}, true)]
- [InlineData(new[] {@"Cynthia The Mission v20 c12-20 [Desudesu&Brolen].zip"}, new[] {@"E:\Manga\Cynthia the Mission\Cynthia The Mission - c000-006 (v06) [Desudesu&Brolen].zip"}, false)]
- public void HasInfoTest(string[] inputInfos, string[] inputChapters, bool expectedHasInfo)
- {
- var infos = new List();
- foreach (var filename in inputInfos)
- {
- infos.Add(_defaultParser.Parse(
- filename,
- string.Empty));
- }
-
- var files = inputChapters.Select(s => EntityFactory.CreateMangaFile(s, MangaFormat.Archive, 199)).ToList();
- var chapter = EntityFactory.CreateChapter("0-6", false, files);
-
- Assert.Equal(expectedHasInfo, infos.HasInfo(chapter));
- }
+ Assert.Equal(expectedHasInfo, infos.HasInfo(chapter));
}
}
diff --git a/API.Tests/Extensions/QueryableExtensionsTests.cs b/API.Tests/Extensions/QueryableExtensionsTests.cs
new file mode 100644
index 000000000..ee1ada416
--- /dev/null
+++ b/API.Tests/Extensions/QueryableExtensionsTests.cs
@@ -0,0 +1,284 @@
+using System.Collections.Generic;
+using System.Linq;
+using API.Data.Misc;
+using API.Entities;
+using API.Entities.Enums;
+using API.Entities.Metadata;
+using API.Extensions;
+using Xunit;
+
+namespace API.Tests.Extensions;
+
+public class QueryableExtensionsTests
+{
+ [Theory]
+ [InlineData(true, 2)]
+ [InlineData(false, 1)]
+ public void RestrictAgainstAgeRestriction_Series_ShouldRestrictEverythingAboveTeen(bool includeUnknowns, int expectedCount)
+ {
+ var items = new List()
+ {
+ new Series()
+ {
+ Metadata = new SeriesMetadata()
+ {
+ AgeRating = AgeRating.Teen,
+ }
+ },
+ new Series()
+ {
+ Metadata = new SeriesMetadata()
+ {
+ AgeRating = AgeRating.Unknown,
+ }
+ },
+ new Series()
+ {
+ Metadata = new SeriesMetadata()
+ {
+ AgeRating = AgeRating.X18Plus,
+ }
+ },
+ };
+
+ var filtered = items.AsQueryable().RestrictAgainstAgeRestriction(new AgeRestriction()
+ {
+ AgeRating = AgeRating.Teen,
+ IncludeUnknowns = includeUnknowns
+ });
+ Assert.Equal(expectedCount, filtered.Count());
+ }
+
+ [Theory]
+ [InlineData(true, 2)]
+ [InlineData(false, 1)]
+ public void RestrictAgainstAgeRestriction_CollectionTag_ShouldRestrictEverythingAboveTeen(bool includeUnknowns, int expectedCount)
+ {
+ var items = new List()
+ {
+ new CollectionTag()
+ {
+ SeriesMetadatas = new List()
+ {
+ new SeriesMetadata()
+ {
+ AgeRating = AgeRating.Teen,
+ }
+ }
+ },
+ new CollectionTag()
+ {
+ SeriesMetadatas = new List()
+ {
+ new SeriesMetadata()
+ {
+ AgeRating = AgeRating.Unknown,
+ },
+ new SeriesMetadata()
+ {
+ AgeRating = AgeRating.Teen,
+ }
+ }
+ },
+ new CollectionTag()
+ {
+ SeriesMetadatas = new List()
+ {
+ new SeriesMetadata()
+ {
+ AgeRating = AgeRating.X18Plus,
+ }
+ }
+ },
+ };
+
+ var filtered = items.AsQueryable().RestrictAgainstAgeRestriction(new AgeRestriction()
+ {
+ AgeRating = AgeRating.Teen,
+ IncludeUnknowns = includeUnknowns
+ });
+ Assert.Equal(expectedCount, filtered.Count());
+ }
+
+ [Theory]
+ [InlineData(true, 2)]
+ [InlineData(false, 1)]
+ public void RestrictAgainstAgeRestriction_Genre_ShouldRestrictEverythingAboveTeen(bool includeUnknowns, int expectedCount)
+ {
+ var items = new List()
+ {
+ new Genre()
+ {
+ SeriesMetadatas = new List()
+ {
+ new SeriesMetadata()
+ {
+ AgeRating = AgeRating.Teen,
+ }
+ }
+ },
+ new Genre()
+ {
+ SeriesMetadatas = new List()
+ {
+ new SeriesMetadata()
+ {
+ AgeRating = AgeRating.Unknown,
+ },
+ new SeriesMetadata()
+ {
+ AgeRating = AgeRating.Teen,
+ }
+ }
+ },
+ new Genre()
+ {
+ SeriesMetadatas = new List()
+ {
+ new SeriesMetadata()
+ {
+ AgeRating = AgeRating.X18Plus,
+ }
+ }
+ },
+ };
+
+ var filtered = items.AsQueryable().RestrictAgainstAgeRestriction(new AgeRestriction()
+ {
+ AgeRating = AgeRating.Teen,
+ IncludeUnknowns = includeUnknowns
+ });
+ Assert.Equal(expectedCount, filtered.Count());
+ }
+
+ [Theory]
+ [InlineData(true, 2)]
+ [InlineData(false, 1)]
+ public void RestrictAgainstAgeRestriction_Tag_ShouldRestrictEverythingAboveTeen(bool includeUnknowns, int expectedCount)
+ {
+ var items = new List()
+ {
+ new Tag()
+ {
+ SeriesMetadatas = new List()
+ {
+ new SeriesMetadata()
+ {
+ AgeRating = AgeRating.Teen,
+ }
+ }
+ },
+ new Tag()
+ {
+ SeriesMetadatas = new List()
+ {
+ new SeriesMetadata()
+ {
+ AgeRating = AgeRating.Unknown,
+ },
+ new SeriesMetadata()
+ {
+ AgeRating = AgeRating.Teen,
+ }
+ }
+ },
+ new Tag()
+ {
+ SeriesMetadatas = new List()
+ {
+ new SeriesMetadata()
+ {
+ AgeRating = AgeRating.X18Plus,
+ }
+ }
+ },
+ };
+
+ var filtered = items.AsQueryable().RestrictAgainstAgeRestriction(new AgeRestriction()
+ {
+ AgeRating = AgeRating.Teen,
+ IncludeUnknowns = includeUnknowns
+ });
+ Assert.Equal(expectedCount, filtered.Count());
+ }
+
+ [Theory]
+ [InlineData(true, 2)]
+ [InlineData(false, 1)]
+ public void RestrictAgainstAgeRestriction_Person_ShouldRestrictEverythingAboveTeen(bool includeUnknowns, int expectedCount)
+ {
+ var items = new List()
+ {
+ new Person()
+ {
+ SeriesMetadatas = new List()
+ {
+ new SeriesMetadata()
+ {
+ AgeRating = AgeRating.Teen,
+ }
+ }
+ },
+ new Person()
+ {
+ SeriesMetadatas = new List()
+ {
+ new SeriesMetadata()
+ {
+ AgeRating = AgeRating.Unknown,
+ },
+ new SeriesMetadata()
+ {
+ AgeRating = AgeRating.Teen,
+ }
+ }
+ },
+ new Person()
+ {
+ SeriesMetadatas = new List()
+ {
+ new SeriesMetadata()
+ {
+ AgeRating = AgeRating.X18Plus,
+ }
+ }
+ },
+ };
+
+ var filtered = items.AsQueryable().RestrictAgainstAgeRestriction(new AgeRestriction()
+ {
+ AgeRating = AgeRating.Teen,
+ IncludeUnknowns = includeUnknowns
+ });
+ Assert.Equal(expectedCount, filtered.Count());
+ }
+
+ [Theory]
+ [InlineData(true, 2)]
+ [InlineData(false, 1)]
+ public void RestrictAgainstAgeRestriction_ReadingList_ShouldRestrictEverythingAboveTeen(bool includeUnknowns, int expectedCount)
+ {
+ var items = new List()
+ {
+ new ReadingList()
+ {
+ AgeRating = AgeRating.Teen,
+ },
+ new ReadingList()
+ {
+ AgeRating = AgeRating.Unknown,
+ },
+ new ReadingList()
+ {
+ AgeRating = AgeRating.X18Plus
+ },
+ };
+
+ var filtered = items.AsQueryable().RestrictAgainstAgeRestriction(new AgeRestriction()
+ {
+ AgeRating = AgeRating.Teen,
+ IncludeUnknowns = includeUnknowns
+ });
+ Assert.Equal(expectedCount, filtered.Count());
+ }
+}
diff --git a/API.Tests/Extensions/SeriesExtensionsTests.cs b/API.Tests/Extensions/SeriesExtensionsTests.cs
index b339b306d..f8dce8876 100644
--- a/API.Tests/Extensions/SeriesExtensionsTests.cs
+++ b/API.Tests/Extensions/SeriesExtensionsTests.cs
@@ -1,4 +1,6 @@
-using System.Linq;
+using System.Collections.Generic;
+using System.Linq;
+using API.Comparators;
using API.Entities;
using API.Entities.Enums;
using API.Entities.Metadata;
@@ -7,86 +9,360 @@ using API.Parser;
using API.Services.Tasks.Scanner;
using Xunit;
-namespace API.Tests.Extensions
+namespace API.Tests.Extensions;
+
+public class SeriesExtensionsTests
{
- public class SeriesExtensionsTests
+ [Theory]
+ [InlineData(new [] {"Darker than Black", "Darker Than Black", "Darker than Black"}, new [] {"Darker than Black"}, true)]
+ [InlineData(new [] {"Darker than Black", "Darker Than Black", "Darker than Black"}, new [] {"Darker_than_Black"}, true)]
+ [InlineData(new [] {"Darker than Black", "Darker Than Black", "Darker than Black"}, new [] {"Darker then Black!"}, false)]
+ [InlineData(new [] {"Salem's Lot", "Salem's Lot", "Salem's Lot"}, new [] {"Salem's Lot"}, true)]
+ [InlineData(new [] {"Salem's Lot", "Salem's Lot", "Salem's Lot"}, new [] {"salems lot"}, true)]
+ [InlineData(new [] {"Salem's Lot", "Salem's Lot", "Salem's Lot"}, new [] {"salem's lot"}, true)]
+ // Different normalizations pass as we check normalization against an on-the-fly calculation so we don't delete series just because we change how normalization works
+ [InlineData(new [] {"Salem's Lot", "Salem's Lot", "Salem's Lot", "salems lot"}, new [] {"salem's lot"}, true)]
+ [InlineData(new [] {"Rent-a-Girlfriend", "Rent-a-Girlfriend", "Kanojo, Okarishimasu", "rentagirlfriend"}, new [] {"Kanojo, Okarishimasu"}, true)]
+ public void NameInListTest(string[] seriesInput, string[] list, bool expected)
{
- [Theory]
- [InlineData(new [] {"Darker than Black", "Darker Than Black", "Darker than Black"}, new [] {"Darker than Black"}, true)]
- [InlineData(new [] {"Darker than Black", "Darker Than Black", "Darker than Black"}, new [] {"Darker_than_Black"}, true)]
- [InlineData(new [] {"Darker than Black", "Darker Than Black", "Darker than Black"}, new [] {"Darker then Black!"}, false)]
- [InlineData(new [] {"Salem's Lot", "Salem's Lot", "Salem's Lot"}, new [] {"Salem's Lot"}, true)]
- [InlineData(new [] {"Salem's Lot", "Salem's Lot", "Salem's Lot"}, new [] {"salems lot"}, true)]
- [InlineData(new [] {"Salem's Lot", "Salem's Lot", "Salem's Lot"}, new [] {"salem's lot"}, true)]
- // Different normalizations pass as we check normalization against an on-the-fly calculation so we don't delete series just because we change how normalization works
- [InlineData(new [] {"Salem's Lot", "Salem's Lot", "Salem's Lot", "salems lot"}, new [] {"salem's lot"}, true)]
- [InlineData(new [] {"Rent-a-Girlfriend", "Rent-a-Girlfriend", "Kanojo, Okarishimasu", "rentagirlfriend"}, new [] {"Kanojo, Okarishimasu"}, true)]
- public void NameInListTest(string[] seriesInput, string[] list, bool expected)
+ var series = new Series()
{
- var series = new Series()
- {
- Name = seriesInput[0],
- LocalizedName = seriesInput[1],
- OriginalName = seriesInput[2],
- NormalizedName = seriesInput.Length == 4 ? seriesInput[3] : API.Services.Tasks.Scanner.Parser.Parser.Normalize(seriesInput[0]),
- Metadata = new SeriesMetadata()
- };
+ Name = seriesInput[0],
+ LocalizedName = seriesInput[1],
+ OriginalName = seriesInput[2],
+ NormalizedName = seriesInput.Length == 4 ? seriesInput[3] : API.Services.Tasks.Scanner.Parser.Parser.Normalize(seriesInput[0]),
+ Metadata = new SeriesMetadata()
+ };
- Assert.Equal(expected, series.NameInList(list));
- }
+ Assert.Equal(expected, series.NameInList(list));
+ }
- [Theory]
- [InlineData(new [] {"Darker than Black", "Darker Than Black", "Darker than Black"}, new [] {"Darker than Black"}, MangaFormat.Archive, true)]
- [InlineData(new [] {"Darker than Black", "Darker Than Black", "Darker than Black"}, new [] {"Darker_than_Black"}, MangaFormat.Archive, true)]
- [InlineData(new [] {"Darker than Black", "Darker Than Black", "Darker than Black"}, new [] {"Darker then Black!"}, MangaFormat.Archive, false)]
- [InlineData(new [] {"Salem's Lot", "Salem's Lot", "Salem's Lot"}, new [] {"Salem's Lot"}, MangaFormat.Archive, true)]
- [InlineData(new [] {"Salem's Lot", "Salem's Lot", "Salem's Lot"}, new [] {"salems lot"}, MangaFormat.Archive, true)]
- [InlineData(new [] {"Salem's Lot", "Salem's Lot", "Salem's Lot"}, new [] {"salem's lot"}, MangaFormat.Archive, true)]
- // Different normalizations pass as we check normalization against an on-the-fly calculation so we don't delete series just because we change how normalization works
- [InlineData(new [] {"Salem's Lot", "Salem's Lot", "Salem's Lot", "salems lot"}, new [] {"salem's lot"}, MangaFormat.Archive, true)]
- [InlineData(new [] {"Rent-a-Girlfriend", "Rent-a-Girlfriend", "Kanojo, Okarishimasu", "rentagirlfriend"}, new [] {"Kanojo, Okarishimasu"}, MangaFormat.Archive, true)]
- public void NameInListParserInfoTest(string[] seriesInput, string[] list, MangaFormat format, bool expected)
+ [Theory]
+ [InlineData(new [] {"Darker than Black", "Darker Than Black", "Darker than Black"}, new [] {"Darker than Black"}, MangaFormat.Archive, true)]
+ [InlineData(new [] {"Darker than Black", "Darker Than Black", "Darker than Black"}, new [] {"Darker_than_Black"}, MangaFormat.Archive, true)]
+ [InlineData(new [] {"Darker than Black", "Darker Than Black", "Darker than Black"}, new [] {"Darker then Black!"}, MangaFormat.Archive, false)]
+ [InlineData(new [] {"Salem's Lot", "Salem's Lot", "Salem's Lot"}, new [] {"Salem's Lot"}, MangaFormat.Archive, true)]
+ [InlineData(new [] {"Salem's Lot", "Salem's Lot", "Salem's Lot"}, new [] {"salems lot"}, MangaFormat.Archive, true)]
+ [InlineData(new [] {"Salem's Lot", "Salem's Lot", "Salem's Lot"}, new [] {"salem's lot"}, MangaFormat.Archive, true)]
+ // Different normalizations pass as we check normalization against an on-the-fly calculation so we don't delete series just because we change how normalization works
+ [InlineData(new [] {"Salem's Lot", "Salem's Lot", "Salem's Lot", "salems lot"}, new [] {"salem's lot"}, MangaFormat.Archive, true)]
+ [InlineData(new [] {"Rent-a-Girlfriend", "Rent-a-Girlfriend", "Kanojo, Okarishimasu", "rentagirlfriend"}, new [] {"Kanojo, Okarishimasu"}, MangaFormat.Archive, true)]
+ public void NameInListParserInfoTest(string[] seriesInput, string[] list, MangaFormat format, bool expected)
+ {
+ var series = new Series()
{
- var series = new Series()
- {
- Name = seriesInput[0],
- LocalizedName = seriesInput[1],
- OriginalName = seriesInput[2],
- NormalizedName = seriesInput.Length == 4 ? seriesInput[3] : API.Services.Tasks.Scanner.Parser.Parser.Normalize(seriesInput[0]),
- Metadata = new SeriesMetadata(),
- };
+ Name = seriesInput[0],
+ LocalizedName = seriesInput[1],
+ OriginalName = seriesInput[2],
+ NormalizedName = seriesInput.Length == 4 ? seriesInput[3] : API.Services.Tasks.Scanner.Parser.Parser.Normalize(seriesInput[0]),
+ Metadata = new SeriesMetadata(),
+ };
- var parserInfos = list.Select(s => new ParsedSeries()
- {
- Name = s,
- NormalizedName = API.Services.Tasks.Scanner.Parser.Parser.Normalize(s),
- }).ToList();
-
- // This doesn't do any checks against format
- Assert.Equal(expected, series.NameInList(parserInfos));
- }
-
-
- [Theory]
- [InlineData(new [] {"Darker than Black", "Darker Than Black", "Darker than Black"}, "Darker than Black", true)]
- [InlineData(new [] {"Rent-a-Girlfriend", "Rent-a-Girlfriend", "Kanojo, Okarishimasu", "rentagirlfriend"}, "Kanojo, Okarishimasu", true)]
- [InlineData(new [] {"Rent-a-Girlfriend", "Rent-a-Girlfriend", "Kanojo, Okarishimasu", "rentagirlfriend"}, "Rent", false)]
- public void NameInParserInfoTest(string[] seriesInput, string parserSeries, bool expected)
+ var parserInfos = list.Select(s => new ParsedSeries()
{
- var series = new Series()
+ Name = s,
+ NormalizedName = API.Services.Tasks.Scanner.Parser.Parser.Normalize(s),
+ }).ToList();
+
+ // This doesn't do any checks against format
+ Assert.Equal(expected, series.NameInList(parserInfos));
+ }
+
+
+ [Theory]
+ [InlineData(new [] {"Darker than Black", "Darker Than Black", "Darker than Black"}, "Darker than Black", true)]
+ [InlineData(new [] {"Rent-a-Girlfriend", "Rent-a-Girlfriend", "Kanojo, Okarishimasu", "rentagirlfriend"}, "Kanojo, Okarishimasu", true)]
+ [InlineData(new [] {"Rent-a-Girlfriend", "Rent-a-Girlfriend", "Kanojo, Okarishimasu", "rentagirlfriend"}, "Rent", false)]
+ public void NameInParserInfoTest(string[] seriesInput, string parserSeries, bool expected)
+ {
+ var series = new Series()
+ {
+ Name = seriesInput[0],
+ LocalizedName = seriesInput[1],
+ OriginalName = seriesInput[2],
+ NormalizedName = seriesInput.Length == 4 ? seriesInput[3] : API.Services.Tasks.Scanner.Parser.Parser.Normalize(seriesInput[0]),
+ Metadata = new SeriesMetadata()
+ };
+ var info = new ParserInfo
+ {
+ Series = parserSeries
+ };
+
+ Assert.Equal(expected, series.NameInParserInfo(info));
+ }
+
+ [Fact]
+ public void GetCoverImage_MultipleSpecials_Comics()
+ {
+ var series = new Series()
+ {
+ Format = MangaFormat.Archive,
+ Volumes = new List()
{
- Name = seriesInput[0],
- LocalizedName = seriesInput[1],
- OriginalName = seriesInput[2],
- NormalizedName = seriesInput.Length == 4 ? seriesInput[3] : API.Services.Tasks.Scanner.Parser.Parser.Normalize(seriesInput[0]),
- Metadata = new SeriesMetadata()
- };
- var info = new ParserInfo();
- info.Series = parserSeries;
-
- Assert.Equal(expected, series.NameInParserInfo(info));
- }
+ new Volume()
+ {
+ Number = 0,
+ Name = API.Services.Tasks.Scanner.Parser.Parser.DefaultVolume,
+ Chapters = new List()
+ {
+ new Chapter()
+ {
+ IsSpecial = true,
+ Number = API.Services.Tasks.Scanner.Parser.Parser.DefaultChapter,
+ CoverImage = "Special 1",
+ },
+ new Chapter()
+ {
+ IsSpecial = true,
+ Number = API.Services.Tasks.Scanner.Parser.Parser.DefaultChapter,
+ CoverImage = "Special 2",
+ }
+ },
+ }
+ }
+ };
+ Assert.Equal("Special 1", series.GetCoverImage());
}
+
+ [Fact]
+ public void GetCoverImage_MultipleSpecials_Books()
+ {
+ var series = new Series()
+ {
+ Format = MangaFormat.Epub,
+ Volumes = new List()
+ {
+ new Volume()
+ {
+ Number = 0,
+ Name = API.Services.Tasks.Scanner.Parser.Parser.DefaultVolume,
+ Chapters = new List()
+ {
+ new Chapter()
+ {
+ IsSpecial = true,
+ Number = API.Services.Tasks.Scanner.Parser.Parser.DefaultChapter,
+ CoverImage = "Special 1",
+ },
+ new Chapter()
+ {
+ IsSpecial = true,
+ Number = API.Services.Tasks.Scanner.Parser.Parser.DefaultChapter,
+ CoverImage = "Special 2",
+ }
+ },
+ }
+ }
+ };
+
+ Assert.Equal("Special 1", series.GetCoverImage());
+ }
+
+ [Fact]
+ public void GetCoverImage_JustChapters_Comics()
+ {
+ var series = new Series()
+ {
+ Format = MangaFormat.Archive,
+ Volumes = new List()
+ {
+ new Volume()
+ {
+ Number = 0,
+ Name = API.Services.Tasks.Scanner.Parser.Parser.DefaultVolume,
+ Chapters = new List()
+ {
+ new Chapter()
+ {
+ IsSpecial = false,
+ Number = "2.5",
+ CoverImage = "Special 1",
+ },
+ new Chapter()
+ {
+ IsSpecial = false,
+ Number = "2",
+ CoverImage = "Special 2",
+ }
+ },
+ }
+ }
+ };
+
+ foreach (var vol in series.Volumes)
+ {
+ vol.CoverImage = vol.Chapters.MinBy(x => double.Parse(x.Number), ChapterSortComparerZeroFirst.Default)?.CoverImage;
+ }
+
+ Assert.Equal("Special 2", series.GetCoverImage());
+ }
+
+ [Fact]
+ public void GetCoverImage_JustChaptersAndSpecials_Comics()
+ {
+ var series = new Series()
+ {
+ Format = MangaFormat.Archive,
+ Volumes = new List()
+ {
+ new Volume()
+ {
+ Number = 0,
+ Name = API.Services.Tasks.Scanner.Parser.Parser.DefaultVolume,
+ Chapters = new List()
+ {
+ new Chapter()
+ {
+ IsSpecial = false,
+ Number = "2.5",
+ CoverImage = "Special 1",
+ },
+ new Chapter()
+ {
+ IsSpecial = false,
+ Number = "2",
+ CoverImage = "Special 2",
+ },
+ new Chapter()
+ {
+ IsSpecial = true,
+ Number = API.Services.Tasks.Scanner.Parser.Parser.DefaultChapter,
+ CoverImage = "Special 3",
+ }
+ },
+ }
+ }
+ };
+
+ foreach (var vol in series.Volumes)
+ {
+ vol.CoverImage = vol.Chapters.MinBy(x => double.Parse(x.Number), ChapterSortComparerZeroFirst.Default)?.CoverImage;
+ }
+
+ Assert.Equal("Special 2", series.GetCoverImage());
+ }
+
+ [Fact]
+ public void GetCoverImage_VolumesChapters_Comics()
+ {
+ var series = new Series()
+ {
+ Format = MangaFormat.Archive,
+ Volumes = new List()
+ {
+ new Volume()
+ {
+ Number = 0,
+ Name = API.Services.Tasks.Scanner.Parser.Parser.DefaultVolume,
+ Chapters = new List()
+ {
+ new Chapter()
+ {
+ IsSpecial = false,
+ Number = "2.5",
+ CoverImage = "Special 1",
+ },
+ new Chapter()
+ {
+ IsSpecial = false,
+ Number = "2",
+ CoverImage = "Special 2",
+ },
+ new Chapter()
+ {
+ IsSpecial = true,
+ Number = API.Services.Tasks.Scanner.Parser.Parser.DefaultChapter,
+ CoverImage = "Special 3",
+ }
+ },
+ },
+ new Volume()
+ {
+ Number = 1,
+ Name = "1",
+ Chapters = new List()
+ {
+ new Chapter()
+ {
+ IsSpecial = false,
+ Number = "0",
+ CoverImage = "Volume 1",
+ },
+
+ },
+ }
+ }
+ };
+
+ foreach (var vol in series.Volumes)
+ {
+ vol.CoverImage = vol.Chapters.MinBy(x => double.Parse(x.Number), ChapterSortComparerZeroFirst.Default)?.CoverImage;
+ }
+
+ Assert.Equal("Volume 1", series.GetCoverImage());
+ }
+
+ [Fact]
+ public void GetCoverImage_VolumesChaptersAndSpecials_Comics()
+ {
+ var series = new Series()
+ {
+ Format = MangaFormat.Archive,
+ Volumes = new List()
+ {
+ new Volume()
+ {
+ Number = 0,
+ Name = API.Services.Tasks.Scanner.Parser.Parser.DefaultVolume,
+ Chapters = new List()
+ {
+ new Chapter()
+ {
+ IsSpecial = false,
+ Number = "2.5",
+ CoverImage = "Special 1",
+ },
+ new Chapter()
+ {
+ IsSpecial = false,
+ Number = "2",
+ CoverImage = "Special 2",
+ },
+ new Chapter()
+ {
+ IsSpecial = true,
+ Number = API.Services.Tasks.Scanner.Parser.Parser.DefaultChapter,
+ CoverImage = "Special 3",
+ }
+ },
+ },
+ new Volume()
+ {
+ Number = 1,
+ Name = "1",
+ Chapters = new List()
+ {
+ new Chapter()
+ {
+ IsSpecial = false,
+ Number = "0",
+ CoverImage = "Volume 1",
+ },
+
+ },
+ }
+ }
+ };
+
+ foreach (var vol in series.Volumes)
+ {
+ vol.CoverImage = vol.Chapters.MinBy(x => double.Parse(x.Number), ChapterSortComparerZeroFirst.Default)?.CoverImage;
+ }
+
+ Assert.Equal("Volume 1", series.GetCoverImage());
+ }
+
+
}
diff --git a/API.Tests/Helpers/CacheHelperTests.cs b/API.Tests/Helpers/CacheHelperTests.cs
index 723742bc6..d78ed1601 100644
--- a/API.Tests/Helpers/CacheHelperTests.cs
+++ b/API.Tests/Helpers/CacheHelperTests.cs
@@ -165,7 +165,7 @@ public class CacheHelperTests
FilePath = TestCoverArchive,
LastModified = filesystemFile.LastWriteTime.DateTime
};
- Assert.True(cacheHelper.HasFileNotChangedSinceCreationOrLastScan(chapter, false, file));
+ Assert.True(cacheHelper.IsFileUnmodifiedSinceCreationOrLastScan(chapter, false, file));
}
[Fact]
@@ -195,7 +195,7 @@ public class CacheHelperTests
FilePath = TestCoverArchive,
LastModified = filesystemFile.LastWriteTime.DateTime
};
- Assert.True(cacheHelper.HasFileNotChangedSinceCreationOrLastScan(chapter, false, file));
+ Assert.True(cacheHelper.IsFileUnmodifiedSinceCreationOrLastScan(chapter, false, file));
}
[Fact]
@@ -225,15 +225,16 @@ public class CacheHelperTests
FilePath = TestCoverArchive,
LastModified = filesystemFile.LastWriteTime.DateTime
};
- Assert.False(cacheHelper.HasFileNotChangedSinceCreationOrLastScan(chapter, true, file));
+ Assert.False(cacheHelper.IsFileUnmodifiedSinceCreationOrLastScan(chapter, true, file));
}
[Fact]
- public void HasFileNotChangedSinceCreationOrLastScan_ModifiedSinceLastScan()
+ public void IsFileUnmodifiedSinceCreationOrLastScan_ModifiedSinceLastScan()
{
var filesystemFile = new MockFileData("")
{
- LastWriteTime = DateTimeOffset.Now
+ LastWriteTime = DateTimeOffset.Now,
+ CreationTime = DateTimeOffset.Now
};
var fileSystem = new MockFileSystem(new Dictionary
{
@@ -246,8 +247,8 @@ public class CacheHelperTests
var chapter = new Chapter()
{
- Created = filesystemFile.LastWriteTime.DateTime.Subtract(TimeSpan.FromMinutes(10)),
- LastModified = filesystemFile.LastWriteTime.DateTime.Subtract(TimeSpan.FromMinutes(10))
+ Created = DateTime.Now.Subtract(TimeSpan.FromMinutes(10)),
+ LastModified = DateTime.Now.Subtract(TimeSpan.FromMinutes(10))
};
var file = new MangaFile()
@@ -255,7 +256,7 @@ public class CacheHelperTests
FilePath = Path.Join(TestCoverImageDirectory, TestCoverArchive),
LastModified = filesystemFile.LastWriteTime.DateTime
};
- Assert.False(cacheHelper.HasFileNotChangedSinceCreationOrLastScan(chapter, false, file));
+ Assert.False(cacheHelper.IsFileUnmodifiedSinceCreationOrLastScan(chapter, false, file));
}
[Fact]
@@ -276,8 +277,8 @@ public class CacheHelperTests
var chapter = new Chapter()
{
- Created = filesystemFile.LastWriteTime.DateTime.Subtract(TimeSpan.FromMinutes(10)),
- LastModified = filesystemFile.LastWriteTime.DateTime
+ Created = DateTime.Now.Subtract(TimeSpan.FromMinutes(10)),
+ LastModified = DateTime.Now
};
var file = new MangaFile()
@@ -285,7 +286,7 @@ public class CacheHelperTests
FilePath = Path.Join(TestCoverImageDirectory, TestCoverArchive),
LastModified = filesystemFile.LastWriteTime.DateTime
};
- Assert.False(cacheHelper.HasFileNotChangedSinceCreationOrLastScan(chapter, false, file));
+ Assert.False(cacheHelper.IsFileUnmodifiedSinceCreationOrLastScan(chapter, false, file));
}
}
diff --git a/API.Tests/Helpers/EntityFactory.cs b/API.Tests/Helpers/EntityFactory.cs
index 55d947cf5..2f46cc1f4 100644
--- a/API.Tests/Helpers/EntityFactory.cs
+++ b/API.Tests/Helpers/EntityFactory.cs
@@ -4,80 +4,79 @@ using API.Entities;
using API.Entities.Enums;
using API.Entities.Metadata;
-namespace API.Tests.Helpers
+namespace API.Tests.Helpers;
+
+///
+/// Used to help quickly create DB entities for Unit Testing
+///
+public static class EntityFactory
{
- ///
- /// Used to help quickly create DB entities for Unit Testing
- ///
- public static class EntityFactory
+ public static Series CreateSeries(string name)
{
- public static Series CreateSeries(string name)
+ return new Series()
{
- return new Series()
- {
- Name = name,
- SortName = name,
- LocalizedName = name,
- NormalizedName = API.Services.Tasks.Scanner.Parser.Parser.Normalize(name),
- Volumes = new List(),
- Metadata = new SeriesMetadata()
- };
- }
+ Name = name,
+ SortName = name,
+ LocalizedName = name,
+ NormalizedName = API.Services.Tasks.Scanner.Parser.Parser.Normalize(name),
+ Volumes = new List(),
+ Metadata = new SeriesMetadata()
+ };
+ }
- public static Volume CreateVolume(string volumeNumber, List chapters = null)
+ public static Volume CreateVolume(string volumeNumber, List chapters = null)
+ {
+ var chaps = chapters ?? new List();
+ var pages = chaps.Count > 0 ? chaps.Max(c => c.Pages) : 0;
+ return new Volume()
{
- var chaps = chapters ?? new List();
- var pages = chaps.Count > 0 ? chaps.Max(c => c.Pages) : 0;
- return new Volume()
- {
- Name = volumeNumber,
- Number = (int) API.Services.Tasks.Scanner.Parser.Parser.MinNumberFromRange(volumeNumber),
- Pages = pages,
- Chapters = chaps
- };
- }
+ Name = volumeNumber,
+ Number = (int) API.Services.Tasks.Scanner.Parser.Parser.MinNumberFromRange(volumeNumber),
+ Pages = pages,
+ Chapters = chaps
+ };
+ }
- public static Chapter CreateChapter(string range, bool isSpecial, List files = null, int pageCount = 0)
+ public static Chapter CreateChapter(string range, bool isSpecial, List files = null, int pageCount = 0)
+ {
+ return new Chapter()
{
- return new Chapter()
- {
- IsSpecial = isSpecial,
- Range = range,
- Number = API.Services.Tasks.Scanner.Parser.Parser.MinNumberFromRange(range) + string.Empty,
- Files = files ?? new List(),
- Pages = pageCount,
+ IsSpecial = isSpecial,
+ Range = range,
+ Number = API.Services.Tasks.Scanner.Parser.Parser.MinNumberFromRange(range) + string.Empty,
+ Files = files ?? new List(),
+ Pages = pageCount,
- };
- }
+ };
+ }
- public static MangaFile CreateMangaFile(string filename, MangaFormat format, int pages)
+ public static MangaFile CreateMangaFile(string filename, MangaFormat format, int pages)
+ {
+ return new MangaFile()
{
- return new MangaFile()
- {
- FilePath = filename,
- Format = format,
- Pages = pages
- };
- }
+ FilePath = filename,
+ Format = format,
+ Pages = pages
+ };
+ }
- public static SeriesMetadata CreateSeriesMetadata(ICollection collectionTags)
+ public static SeriesMetadata CreateSeriesMetadata(ICollection collectionTags)
+ {
+ return new SeriesMetadata()
{
- return new SeriesMetadata()
- {
- CollectionTags = collectionTags
- };
- }
+ CollectionTags = collectionTags
+ };
+ }
- public static CollectionTag CreateCollectionTag(int id, string title, string summary, bool promoted)
+ public static CollectionTag CreateCollectionTag(int id, string title, string summary, bool promoted)
+ {
+ return new CollectionTag()
{
- return new CollectionTag()
- {
- Id = id,
- NormalizedTitle = API.Services.Tasks.Scanner.Parser.Parser.Normalize(title).ToUpper(),
- Title = title,
- Summary = summary,
- Promoted = promoted
- };
- }
+ Id = id,
+ NormalizedTitle = API.Services.Tasks.Scanner.Parser.Parser.Normalize(title).ToUpper(),
+ Title = title,
+ Summary = summary,
+ Promoted = promoted
+ };
}
}
diff --git a/API.Tests/Helpers/ParserInfoFactory.cs b/API.Tests/Helpers/ParserInfoFactory.cs
index 4b4a8e22a..793b764b0 100644
--- a/API.Tests/Helpers/ParserInfoFactory.cs
+++ b/API.Tests/Helpers/ParserInfoFactory.cs
@@ -6,68 +6,67 @@ using API.Entities.Enums;
using API.Parser;
using API.Services.Tasks.Scanner;
-namespace API.Tests.Helpers
+namespace API.Tests.Helpers;
+
+public static class ParserInfoFactory
{
- public static class ParserInfoFactory
+ public static ParserInfo CreateParsedInfo(string series, string volumes, string chapters, string filename, bool isSpecial)
{
- public static ParserInfo CreateParsedInfo(string series, string volumes, string chapters, string filename, bool isSpecial)
+ return new ParserInfo()
{
- return new ParserInfo()
- {
- Chapters = chapters,
- Edition = "",
- Format = MangaFormat.Archive,
- FullFilePath = Path.Join(@"/manga/", filename),
- Filename = filename,
- IsSpecial = isSpecial,
- Title = Path.GetFileNameWithoutExtension(filename),
- Series = series,
- Volumes = volumes
- };
- }
+ Chapters = chapters,
+ Edition = "",
+ Format = MangaFormat.Archive,
+ FullFilePath = Path.Join(@"/manga/", filename),
+ Filename = filename,
+ IsSpecial = isSpecial,
+ Title = Path.GetFileNameWithoutExtension(filename),
+ Series = series,
+ Volumes = volumes
+ };
+ }
- public static void AddToParsedInfo(IDictionary> collectedSeries, ParserInfo info)
+ public static void AddToParsedInfo(IDictionary> collectedSeries, ParserInfo info)
+ {
+ var existingKey = collectedSeries.Keys.FirstOrDefault(ps =>
+ ps.Format == info.Format && ps.NormalizedName == API.Services.Tasks.Scanner.Parser.Parser.Normalize(info.Series));
+ existingKey ??= new ParsedSeries()
{
- var existingKey = collectedSeries.Keys.FirstOrDefault(ps =>
- ps.Format == info.Format && ps.NormalizedName == API.Services.Tasks.Scanner.Parser.Parser.Normalize(info.Series));
- existingKey ??= new ParsedSeries()
+ Format = info.Format,
+ Name = info.Series,
+ NormalizedName = API.Services.Tasks.Scanner.Parser.Parser.Normalize(info.Series)
+ };
+ if (collectedSeries.GetType() == typeof(ConcurrentDictionary<,>))
+ {
+ ((ConcurrentDictionary>) collectedSeries).AddOrUpdate(existingKey, new List() {info}, (_, oldValue) =>
{
- Format = info.Format,
- Name = info.Series,
- NormalizedName = API.Services.Tasks.Scanner.Parser.Parser.Normalize(info.Series)
- };
- if (collectedSeries.GetType() == typeof(ConcurrentDictionary<,>))
- {
- ((ConcurrentDictionary>) collectedSeries).AddOrUpdate(existingKey, new List() {info}, (_, oldValue) =>
+ oldValue ??= new List();
+ if (!oldValue.Contains(info))
{
- oldValue ??= new List();
- if (!oldValue.Contains(info))
- {
- oldValue.Add(info);
- }
+ oldValue.Add(info);
+ }
- return oldValue;
- });
+ return oldValue;
+ });
+ }
+ else
+ {
+ if (!collectedSeries.ContainsKey(existingKey))
+ {
+ collectedSeries.Add(existingKey, new List() {info});
}
else
{
- if (!collectedSeries.ContainsKey(existingKey))
+ var list = collectedSeries[existingKey];
+ if (!list.Contains(info))
{
- collectedSeries.Add(existingKey, new List() {info});
- }
- else
- {
- var list = collectedSeries[existingKey];
- if (!list.Contains(info))
- {
- list.Add(info);
- }
-
- collectedSeries[existingKey] = list;
+ list.Add(info);
}
+ collectedSeries[existingKey] = list;
}
}
+
}
}
diff --git a/API.Tests/Helpers/TestCaseGenerator.cs b/API.Tests/Helpers/TestCaseGenerator.cs
index 41b99e5e4..833da0502 100644
--- a/API.Tests/Helpers/TestCaseGenerator.cs
+++ b/API.Tests/Helpers/TestCaseGenerator.cs
@@ -1,53 +1,52 @@
using System.IO;
-namespace API.Tests.Helpers
+namespace API.Tests.Helpers;
+
+///
+/// Given a -testcase.txt file, will generate a folder with fake archive or book files. These files are just renamed txt files.
+/// This currently is broken - you cannot create files from a unit test it seems
+///
+public static class TestCaseGenerator
{
- ///
- /// Given a -testcase.txt file, will generate a folder with fake archive or book files. These files are just renamed txt files.
- /// This currently is broken - you cannot create files from a unit test it seems
- ///
- public static class TestCaseGenerator
+ public static string GenerateFiles(string directory, string fileToExpand)
{
- public static string GenerateFiles(string directory, string fileToExpand)
+ //var files = Directory.GetFiles(directory, fileToExpand);
+ var file = new FileInfo(fileToExpand);
+ if (!file.Exists && file.Name.EndsWith("-testcase.txt")) return string.Empty;
+
+ var baseDirectory = TestCaseGenerator.CreateTestBase(fileToExpand, directory);
+ var filesToCreate = File.ReadLines(file.FullName);
+ foreach (var fileToCreate in filesToCreate)
{
- //var files = Directory.GetFiles(directory, fileToExpand);
- var file = new FileInfo(fileToExpand);
- if (!file.Exists && file.Name.EndsWith("-testcase.txt")) return string.Empty;
-
- var baseDirectory = TestCaseGenerator.CreateTestBase(fileToExpand, directory);
- var filesToCreate = File.ReadLines(file.FullName);
- foreach (var fileToCreate in filesToCreate)
- {
- // var folders = DirectoryService.GetFoldersTillRoot(directory, fileToCreate);
- // foreach (var VARIABLE in COLLECTION)
- // {
- //
- // }
- File.Create(fileToCreate);
- }
-
-
-
-
- return baseDirectory;
+ // var folders = DirectoryService.GetFoldersTillRoot(directory, fileToCreate);
+ // foreach (var VARIABLE in COLLECTION)
+ // {
+ //
+ // }
+ File.Create(fileToCreate);
}
- ///
- /// Creates and returns a new base directory for data creation for a given testcase
- ///
- ///
- ///
- ///
- private static string CreateTestBase(string file, string rootDirectory)
- {
- var baseDir = file.Split("-testcase.txt")[0];
- var newDirectory = Path.Join(rootDirectory, baseDir);
- if (!Directory.Exists(newDirectory))
- {
- new DirectoryInfo(newDirectory).Create();
- }
- return newDirectory;
- }
+
+
+ return baseDirectory;
}
-}
\ No newline at end of file
+
+ ///
+ /// Creates and returns a new base directory for data creation for a given testcase
+ ///
+ ///
+ ///
+ ///
+ private static string CreateTestBase(string file, string rootDirectory)
+ {
+ var baseDir = file.Split("-testcase.txt")[0];
+ var newDirectory = Path.Join(rootDirectory, baseDir);
+ if (!Directory.Exists(newDirectory))
+ {
+ new DirectoryInfo(newDirectory).Create();
+ }
+
+ return newDirectory;
+ }
+}
diff --git a/API.Tests/Parser/BookParserTests.cs b/API.Tests/Parser/BookParserTests.cs
index 23b9c6e63..003dbfecc 100644
--- a/API.Tests/Parser/BookParserTests.cs
+++ b/API.Tests/Parser/BookParserTests.cs
@@ -1,43 +1,42 @@
using Xunit;
-namespace API.Tests.Parser
+namespace API.Tests.Parser;
+
+public class BookParserTests
{
- public class BookParserTests
+ [Theory]
+ [InlineData("Gifting The Wonderful World With Blessings! - 3 Side Stories [yuNS][Unknown]", "Gifting The Wonderful World With Blessings!")]
+ [InlineData("BBC Focus 00 The Science of Happiness 2nd Edition (2018)", "BBC Focus 00 The Science of Happiness 2nd Edition")]
+ [InlineData("Faust - Volume 01 [Del Rey][Scans_Compressed]", "Faust")]
+ public void ParseSeriesTest(string filename, string expected)
{
- [Theory]
- [InlineData("Gifting The Wonderful World With Blessings! - 3 Side Stories [yuNS][Unknown]", "Gifting The Wonderful World With Blessings!")]
- [InlineData("BBC Focus 00 The Science of Happiness 2nd Edition (2018)", "BBC Focus 00 The Science of Happiness 2nd Edition")]
- [InlineData("Faust - Volume 01 [Del Rey][Scans_Compressed]", "Faust")]
- public void ParseSeriesTest(string filename, string expected)
- {
- Assert.Equal(expected, API.Services.Tasks.Scanner.Parser.Parser.ParseSeries(filename));
- }
-
- [Theory]
- [InlineData("Harrison, Kim - Dates from Hell - Hollows Vol 2.5.epub", "2.5")]
- [InlineData("Faust - Volume 01 [Del Rey][Scans_Compressed]", "1")]
- public void ParseVolumeTest(string filename, string expected)
- {
- Assert.Equal(expected, API.Services.Tasks.Scanner.Parser.Parser.ParseVolume(filename));
- }
-
- // [Theory]
- // [InlineData("@font-face{font-family:'syyskuu_repaleinen';src:url(data:font/opentype;base64,AAEAAAA", "@font-face{font-family:'syyskuu_repaleinen';src:url(data:font/opentype;base64,AAEAAAA")]
- // [InlineData("@font-face{font-family:'syyskuu_repaleinen';src:url('fonts/font.css')", "@font-face{font-family:'syyskuu_repaleinen';src:url('TEST/fonts/font.css')")]
- // public void ReplaceFontSrcUrl(string input, string expected)
- // {
- // var apiBase = "TEST/";
- // var actual = API.Parser.Parser.FontSrcUrlRegex.Replace(input, "$1" + apiBase + "$2" + "$3");
- // Assert.Equal(expected, actual);
- // }
- //
- // [Theory]
- // [InlineData("@import url('font.css');", "@import url('TEST/font.css');")]
- // public void ReplaceImportSrcUrl(string input, string expected)
- // {
- // var apiBase = "TEST/";
- // var actual = API.Parser.Parser.CssImportUrlRegex.Replace(input, "$1" + apiBase + "$2" + "$3");
- // Assert.Equal(expected, actual);
- // }
+ Assert.Equal(expected, API.Services.Tasks.Scanner.Parser.Parser.ParseSeries(filename));
}
+
+ [Theory]
+ [InlineData("Harrison, Kim - Dates from Hell - Hollows Vol 2.5.epub", "2.5")]
+ [InlineData("Faust - Volume 01 [Del Rey][Scans_Compressed]", "1")]
+ public void ParseVolumeTest(string filename, string expected)
+ {
+ Assert.Equal(expected, API.Services.Tasks.Scanner.Parser.Parser.ParseVolume(filename));
+ }
+
+ // [Theory]
+ // [InlineData("@font-face{font-family:'syyskuu_repaleinen';src:url(data:font/opentype;base64,AAEAAAA", "@font-face{font-family:'syyskuu_repaleinen';src:url(data:font/opentype;base64,AAEAAAA")]
+ // [InlineData("@font-face{font-family:'syyskuu_repaleinen';src:url('fonts/font.css')", "@font-face{font-family:'syyskuu_repaleinen';src:url('TEST/fonts/font.css')")]
+ // public void ReplaceFontSrcUrl(string input, string expected)
+ // {
+ // var apiBase = "TEST/";
+ // var actual = API.Parser.Parser.FontSrcUrlRegex.Replace(input, "$1" + apiBase + "$2" + "$3");
+ // Assert.Equal(expected, actual);
+ // }
+ //
+ // [Theory]
+ // [InlineData("@import url('font.css');", "@import url('TEST/font.css');")]
+ // public void ReplaceImportSrcUrl(string input, string expected)
+ // {
+ // var apiBase = "TEST/";
+ // var actual = API.Parser.Parser.CssImportUrlRegex.Replace(input, "$1" + apiBase + "$2" + "$3");
+ // Assert.Equal(expected, actual);
+ // }
}
diff --git a/API.Tests/Parser/ComicParserTests.cs b/API.Tests/Parser/ComicParserTests.cs
index 74a2b8bb2..fa0448ff9 100644
--- a/API.Tests/Parser/ComicParserTests.cs
+++ b/API.Tests/Parser/ComicParserTests.cs
@@ -1,196 +1,209 @@
using System.IO.Abstractions.TestingHelpers;
using API.Parser;
using API.Services;
+using API.Services.Tasks.Scanner.Parser;
using Microsoft.Extensions.Logging;
using NSubstitute;
using Xunit;
using Xunit.Abstractions;
-namespace API.Tests.Parser
+namespace API.Tests.Parser;
+
+public class ComicParserTests
{
- public class ComicParserTests
+ private readonly ITestOutputHelper _testOutputHelper;
+ private readonly DefaultParser _defaultParser;
+
+ public ComicParserTests(ITestOutputHelper testOutputHelper)
{
- private readonly ITestOutputHelper _testOutputHelper;
- private readonly DefaultParser _defaultParser;
+ _testOutputHelper = testOutputHelper;
+ _defaultParser =
+ new DefaultParser(new DirectoryService(Substitute.For>(),
+ new MockFileSystem()));
+ }
- public ComicParserTests(ITestOutputHelper testOutputHelper)
- {
- _testOutputHelper = testOutputHelper;
- _defaultParser =
- new DefaultParser(new DirectoryService(Substitute.For>(),
- new MockFileSystem()));
- }
+ [Theory]
+ [InlineData("04 - Asterix the Gladiator (1964) (Digital-Empire) (WebP by Doc MaKS)", "Asterix the Gladiator")]
+ [InlineData("The First Asterix Frieze (WebP by Doc MaKS)", "The First Asterix Frieze")]
+ [InlineData("Batman & Catwoman - Trail of the Gun 01", "Batman & Catwoman - Trail of the Gun")]
+ [InlineData("Batman & Daredevil - King of New York", "Batman & Daredevil - King of New York")]
+ [InlineData("Batman & Grendel (1996) 01 - Devil's Bones", "Batman & Grendel")]
+ [InlineData("Batman & Robin the Teen Wonder #0", "Batman & Robin the Teen Wonder")]
+ [InlineData("Batman & Wildcat (1 of 3)", "Batman & Wildcat")]
+ [InlineData("Batman And Superman World's Finest #01", "Batman And Superman World's Finest")]
+ [InlineData("Babe 01", "Babe")]
+ [InlineData("Scott Pilgrim 01 - Scott Pilgrim's Precious Little Life (2004)", "Scott Pilgrim")]
+ [InlineData("Teen Titans v1 001 (1966-02) (digital) (OkC.O.M.P.U.T.O.-Novus)", "Teen Titans")]
+ [InlineData("Scott Pilgrim 02 - Scott Pilgrim vs. The World (2005)", "Scott Pilgrim")]
+ [InlineData("Wolverine - Origins 003 (2006) (digital) (Minutemen-PhD)", "Wolverine - Origins")]
+ [InlineData("Invincible Vol 01 Family matters (2005) (Digital).cbr", "Invincible")]
+ [InlineData("Amazing Man Comics chapter 25", "Amazing Man Comics")]
+ [InlineData("Amazing Man Comics issue #25", "Amazing Man Comics")]
+ [InlineData("Teen Titans v1 038 (1972) (c2c).cbr", "Teen Titans")]
+ [InlineData("Batman Beyond 02 (of 6) (1999)", "Batman Beyond")]
+ [InlineData("Batman Beyond - Return of the Joker (2001)", "Batman Beyond - Return of the Joker")]
+ [InlineData("Invincible 033.5 - Marvel Team-Up 14 (2006) (digital) (Minutemen-Slayer)", "Invincible")]
+ [InlineData("Batman Wayne Family Adventures - Ep. 001 - Moving In", "Batman Wayne Family Adventures")]
+ [InlineData("Saga 001 (2012) (Digital) (Empire-Zone).cbr", "Saga")]
+ [InlineData("spawn-123", "spawn")]
+ [InlineData("spawn-chapter-123", "spawn")]
+ [InlineData("Spawn 062 (1997) (digital) (TLK-EMPIRE-HD).cbr", "Spawn")]
+ [InlineData("Batman Beyond 04 (of 6) (1999)", "Batman Beyond")]
+ [InlineData("Batman Beyond 001 (2012)", "Batman Beyond")]
+ [InlineData("Batman Beyond 2.0 001 (2013)", "Batman Beyond 2.0")]
+ [InlineData("Batman - Catwoman 001 (2021) (Webrip) (The Last Kryptonian-DCP)", "Batman - Catwoman")]
+ [InlineData("Chew v1 - Taster´s Choise (2012) (Digital) (1920) (Kingpin-Empire)", "Chew")]
+ [InlineData("Chew Script Book (2011) (digital-Empire) SP04", "Chew Script Book")]
+ [InlineData("Batman - Detective Comics - Rebirth Deluxe Edition Book 02 (2018) (digital) (Son of Ultron-Empire)", "Batman - Detective Comics - Rebirth Deluxe Edition Book")]
+ [InlineData("Cyberpunk 2077 - Your Voice #01", "Cyberpunk 2077 - Your Voice")]
+ [InlineData("Cyberpunk 2077 #01", "Cyberpunk 2077")]
+ [InlineData("Cyberpunk 2077 - Trauma Team #04.cbz", "Cyberpunk 2077 - Trauma Team")]
+ [InlineData("Batgirl Vol.2000 #57 (December, 2004)", "Batgirl")]
+ [InlineData("Batgirl V2000 #57", "Batgirl")]
+ [InlineData("Fables 021 (2004) (Digital) (Nahga-Empire)", "Fables")]
+ [InlineData("2000 AD 0366 [1984-04-28] (flopbie)", "2000 AD")]
+ [InlineData("Daredevil - v6 - 10 - (2019)", "Daredevil")]
+ [InlineData("Batman - The Man Who Laughs #1 (2005)", "Batman - The Man Who Laughs")]
+ [InlineData("Demon 012 (Sep 1973) c2c", "Demon")]
+ [InlineData("Dragon Age - Until We Sleep 01 (of 03)", "Dragon Age - Until We Sleep")]
+ [InlineData("Green Lantern v2 017 - The Spy-Eye that doomed Green Lantern v2", "Green Lantern")]
+ [InlineData("Green Lantern - Circle of Fire Special - Adam Strange (2000)", "Green Lantern - Circle of Fire - Adam Strange")]
+ [InlineData("Identity Crisis Extra - Rags Morales Sketches (2005)", "Identity Crisis - Rags Morales Sketches")]
+ [InlineData("Daredevil - t6 - 10 - (2019)", "Daredevil")]
+ [InlineData("Batgirl T2000 #57", "Batgirl")]
+ [InlineData("Teen Titans t1 001 (1966-02) (digital) (OkC.O.M.P.U.T.O.-Novus)", "Teen Titans")]
+ [InlineData("Conquistador_-Tome_2", "Conquistador")]
+ [InlineData("Max_l_explorateur-_Tome_0", "Max l explorateur")]
+ [InlineData("Chevaliers d'Héliopolis T3 - Rubedo, l'oeuvre au rouge (Jodorowsky & Jérémy)", "Chevaliers d'Héliopolis")]
+ [InlineData("Bd Fr-Aldebaran-Antares-t6", "Aldebaran-Antares")]
+ [InlineData("Tintin - T22 Vol 714 pour Sydney", "Tintin")]
+ [InlineData("Fables 2010 Vol. 1 Legends in Exile", "Fables 2010")]
+ [InlineData("Kebab Том 1 Глава 1", "Kebab")]
+ [InlineData("Манга Глава 1", "Манга")]
+ public void ParseComicSeriesTest(string filename, string expected)
+ {
+ Assert.Equal(expected, API.Services.Tasks.Scanner.Parser.Parser.ParseComicSeries(filename));
+ }
- [Theory]
- [InlineData("04 - Asterix the Gladiator (1964) (Digital-Empire) (WebP by Doc MaKS)", "Asterix the Gladiator")]
- [InlineData("The First Asterix Frieze (WebP by Doc MaKS)", "The First Asterix Frieze")]
- [InlineData("Batman & Catwoman - Trail of the Gun 01", "Batman & Catwoman - Trail of the Gun")]
- [InlineData("Batman & Daredevil - King of New York", "Batman & Daredevil - King of New York")]
- [InlineData("Batman & Grendel (1996) 01 - Devil's Bones", "Batman & Grendel")]
- [InlineData("Batman & Robin the Teen Wonder #0", "Batman & Robin the Teen Wonder")]
- [InlineData("Batman & Wildcat (1 of 3)", "Batman & Wildcat")]
- [InlineData("Batman And Superman World's Finest #01", "Batman And Superman World's Finest")]
- [InlineData("Babe 01", "Babe")]
- [InlineData("Scott Pilgrim 01 - Scott Pilgrim's Precious Little Life (2004)", "Scott Pilgrim")]
- [InlineData("Teen Titans v1 001 (1966-02) (digital) (OkC.O.M.P.U.T.O.-Novus)", "Teen Titans")]
- [InlineData("Scott Pilgrim 02 - Scott Pilgrim vs. The World (2005)", "Scott Pilgrim")]
- [InlineData("Wolverine - Origins 003 (2006) (digital) (Minutemen-PhD)", "Wolverine - Origins")]
- [InlineData("Invincible Vol 01 Family matters (2005) (Digital).cbr", "Invincible")]
- [InlineData("Amazing Man Comics chapter 25", "Amazing Man Comics")]
- [InlineData("Amazing Man Comics issue #25", "Amazing Man Comics")]
- [InlineData("Teen Titans v1 038 (1972) (c2c).cbr", "Teen Titans")]
- [InlineData("Batman Beyond 02 (of 6) (1999)", "Batman Beyond")]
- [InlineData("Batman Beyond - Return of the Joker (2001)", "Batman Beyond - Return of the Joker")]
- [InlineData("Invincible 033.5 - Marvel Team-Up 14 (2006) (digital) (Minutemen-Slayer)", "Invincible")]
- [InlineData("Batman Wayne Family Adventures - Ep. 001 - Moving In", "Batman Wayne Family Adventures")]
- [InlineData("Saga 001 (2012) (Digital) (Empire-Zone).cbr", "Saga")]
- [InlineData("spawn-123", "spawn")]
- [InlineData("spawn-chapter-123", "spawn")]
- [InlineData("Spawn 062 (1997) (digital) (TLK-EMPIRE-HD).cbr", "Spawn")]
- [InlineData("Batman Beyond 04 (of 6) (1999)", "Batman Beyond")]
- [InlineData("Batman Beyond 001 (2012)", "Batman Beyond")]
- [InlineData("Batman Beyond 2.0 001 (2013)", "Batman Beyond 2.0")]
- [InlineData("Batman - Catwoman 001 (2021) (Webrip) (The Last Kryptonian-DCP)", "Batman - Catwoman")]
- [InlineData("Chew v1 - Taster´s Choise (2012) (Digital) (1920) (Kingpin-Empire)", "Chew")]
- [InlineData("Chew Script Book (2011) (digital-Empire) SP04", "Chew Script Book")]
- [InlineData("Batman - Detective Comics - Rebirth Deluxe Edition Book 02 (2018) (digital) (Son of Ultron-Empire)", "Batman - Detective Comics - Rebirth Deluxe Edition Book")]
- [InlineData("Cyberpunk 2077 - Your Voice #01", "Cyberpunk 2077 - Your Voice")]
- [InlineData("Cyberpunk 2077 #01", "Cyberpunk 2077")]
- [InlineData("Cyberpunk 2077 - Trauma Team #04.cbz", "Cyberpunk 2077 - Trauma Team")]
- [InlineData("Batgirl Vol.2000 #57 (December, 2004)", "Batgirl")]
- [InlineData("Batgirl V2000 #57", "Batgirl")]
- [InlineData("Fables 021 (2004) (Digital) (Nahga-Empire)", "Fables")]
- [InlineData("2000 AD 0366 [1984-04-28] (flopbie)", "2000 AD")]
- [InlineData("Daredevil - v6 - 10 - (2019)", "Daredevil")]
- [InlineData("Batman - The Man Who Laughs #1 (2005)", "Batman - The Man Who Laughs")]
- [InlineData("Demon 012 (Sep 1973) c2c", "Demon")]
- [InlineData("Dragon Age - Until We Sleep 01 (of 03)", "Dragon Age - Until We Sleep")]
- [InlineData("Green Lantern v2 017 - The Spy-Eye that doomed Green Lantern v2", "Green Lantern")]
- [InlineData("Green Lantern - Circle of Fire Special - Adam Strange (2000)", "Green Lantern - Circle of Fire - Adam Strange")]
- [InlineData("Identity Crisis Extra - Rags Morales Sketches (2005)", "Identity Crisis - Rags Morales Sketches")]
- [InlineData("Daredevil - t6 - 10 - (2019)", "Daredevil")]
- [InlineData("Batgirl T2000 #57", "Batgirl")]
- [InlineData("Teen Titans t1 001 (1966-02) (digital) (OkC.O.M.P.U.T.O.-Novus)", "Teen Titans")]
- [InlineData("Conquistador_-Tome_2", "Conquistador")]
- [InlineData("Max_l_explorateur-_Tome_0", "Max l explorateur")]
- [InlineData("Chevaliers d'Héliopolis T3 - Rubedo, l'oeuvre au rouge (Jodorowsky & Jérémy)", "Chevaliers d'Héliopolis")]
- [InlineData("Bd Fr-Aldebaran-Antares-t6", "Aldebaran-Antares")]
- [InlineData("Tintin - T22 Vol 714 pour Sydney", "Tintin")]
- [InlineData("Fables 2010 Vol. 1 Legends in Exile", "Fables 2010")]
- public void ParseComicSeriesTest(string filename, string expected)
- {
- Assert.Equal(expected, API.Services.Tasks.Scanner.Parser.Parser.ParseComicSeries(filename));
- }
+ [Theory]
+ [InlineData("01 Spider-Man & Wolverine 01.cbr", "0")]
+ [InlineData("04 - Asterix the Gladiator (1964) (Digital-Empire) (WebP by Doc MaKS)", "0")]
+ [InlineData("The First Asterix Frieze (WebP by Doc MaKS)", "0")]
+ [InlineData("Batman & Catwoman - Trail of the Gun 01", "0")]
+ [InlineData("Batman & Daredevil - King of New York", "0")]
+ [InlineData("Batman & Grendel (1996) 01 - Devil's Bones", "0")]
+ [InlineData("Batman & Robin the Teen Wonder #0", "0")]
+ [InlineData("Batman & Wildcat (1 of 3)", "0")]
+ [InlineData("Batman And Superman World's Finest #01", "0")]
+ [InlineData("Babe 01", "0")]
+ [InlineData("Scott Pilgrim 01 - Scott Pilgrim's Precious Little Life (2004)", "0")]
+ [InlineData("Teen Titans v1 001 (1966-02) (digital) (OkC.O.M.P.U.T.O.-Novus)", "1")]
+ [InlineData("Scott Pilgrim 02 - Scott Pilgrim vs. The World (2005)", "0")]
+ [InlineData("Superman v1 024 (09-10 1943)", "1")]
+ [InlineData("Amazing Man Comics chapter 25", "0")]
+ [InlineData("Invincible 033.5 - Marvel Team-Up 14 (2006) (digital) (Minutemen-Slayer)", "0")]
+ [InlineData("Cyberpunk 2077 - Trauma Team 04.cbz", "0")]
+ [InlineData("spawn-123", "0")]
+ [InlineData("spawn-chapter-123", "0")]
+ [InlineData("Spawn 062 (1997) (digital) (TLK-EMPIRE-HD).cbr", "0")]
+ [InlineData("Batman Beyond 04 (of 6) (1999)", "0")]
+ [InlineData("Batman Beyond 001 (2012)", "0")]
+ [InlineData("Batman Beyond 2.0 001 (2013)", "0")]
+ [InlineData("Batman - Catwoman 001 (2021) (Webrip) (The Last Kryptonian-DCP)", "0")]
+ [InlineData("Chew v1 - Taster´s Choise (2012) (Digital) (1920) (Kingpin-Empire)", "1")]
+ [InlineData("Chew Script Book (2011) (digital-Empire) SP04", "0")]
+ [InlineData("Batgirl Vol.2000 #57 (December, 2004)", "2000")]
+ [InlineData("Batgirl V2000 #57", "2000")]
+ [InlineData("Fables 021 (2004) (Digital) (Nahga-Empire).cbr", "0")]
+ [InlineData("Cyberpunk 2077 - Trauma Team 04.cbz", "0")]
+ [InlineData("2000 AD 0366 [1984-04-28] (flopbie)", "0")]
+ [InlineData("Daredevil - v6 - 10 - (2019)", "6")]
+ // Tome Tests
+ [InlineData("Daredevil - t6 - 10 - (2019)", "6")]
+ [InlineData("Batgirl T2000 #57", "2000")]
+ [InlineData("Teen Titans t1 001 (1966-02) (digital) (OkC.O.M.P.U.T.O.-Novus)", "1")]
+ [InlineData("Conquistador_Tome_2", "2")]
+ [InlineData("Max_l_explorateur-_Tome_0", "0")]
+ [InlineData("Chevaliers d'Héliopolis T3 - Rubedo, l'oeuvre au rouge (Jodorowsky & Jérémy)", "3")]
+ [InlineData("Adventure Time (2012)/Adventure Time #1 (2012)", "0")]
+ [InlineData("Adventure Time TPB (2012)/Adventure Time v01 (2012).cbz", "1")]
+ // Russian Tests
+ [InlineData("Kebab Том 1 Глава 3", "1")]
+ [InlineData("Манга Глава 2", "0")]
+ public void ParseComicVolumeTest(string filename, string expected)
+ {
+ Assert.Equal(expected, API.Services.Tasks.Scanner.Parser.Parser.ParseComicVolume(filename));
+ }
- [Theory]
- [InlineData("01 Spider-Man & Wolverine 01.cbr", "0")]
- [InlineData("04 - Asterix the Gladiator (1964) (Digital-Empire) (WebP by Doc MaKS)", "0")]
- [InlineData("The First Asterix Frieze (WebP by Doc MaKS)", "0")]
- [InlineData("Batman & Catwoman - Trail of the Gun 01", "0")]
- [InlineData("Batman & Daredevil - King of New York", "0")]
- [InlineData("Batman & Grendel (1996) 01 - Devil's Bones", "0")]
- [InlineData("Batman & Robin the Teen Wonder #0", "0")]
- [InlineData("Batman & Wildcat (1 of 3)", "0")]
- [InlineData("Batman And Superman World's Finest #01", "0")]
- [InlineData("Babe 01", "0")]
- [InlineData("Scott Pilgrim 01 - Scott Pilgrim's Precious Little Life (2004)", "0")]
- [InlineData("Teen Titans v1 001 (1966-02) (digital) (OkC.O.M.P.U.T.O.-Novus)", "1")]
- [InlineData("Scott Pilgrim 02 - Scott Pilgrim vs. The World (2005)", "0")]
- [InlineData("Superman v1 024 (09-10 1943)", "1")]
- [InlineData("Amazing Man Comics chapter 25", "0")]
- [InlineData("Invincible 033.5 - Marvel Team-Up 14 (2006) (digital) (Minutemen-Slayer)", "0")]
- [InlineData("Cyberpunk 2077 - Trauma Team 04.cbz", "0")]
- [InlineData("spawn-123", "0")]
- [InlineData("spawn-chapter-123", "0")]
- [InlineData("Spawn 062 (1997) (digital) (TLK-EMPIRE-HD).cbr", "0")]
- [InlineData("Batman Beyond 04 (of 6) (1999)", "0")]
- [InlineData("Batman Beyond 001 (2012)", "0")]
- [InlineData("Batman Beyond 2.0 001 (2013)", "0")]
- [InlineData("Batman - Catwoman 001 (2021) (Webrip) (The Last Kryptonian-DCP)", "0")]
- [InlineData("Chew v1 - Taster´s Choise (2012) (Digital) (1920) (Kingpin-Empire)", "1")]
- [InlineData("Chew Script Book (2011) (digital-Empire) SP04", "0")]
- [InlineData("Batgirl Vol.2000 #57 (December, 2004)", "2000")]
- [InlineData("Batgirl V2000 #57", "2000")]
- [InlineData("Fables 021 (2004) (Digital) (Nahga-Empire).cbr", "0")]
- [InlineData("Cyberpunk 2077 - Trauma Team 04.cbz", "0")]
- [InlineData("2000 AD 0366 [1984-04-28] (flopbie)", "0")]
- [InlineData("Daredevil - v6 - 10 - (2019)", "6")]
- // Tome Tests
- [InlineData("Daredevil - t6 - 10 - (2019)", "6")]
- [InlineData("Batgirl T2000 #57", "2000")]
- [InlineData("Teen Titans t1 001 (1966-02) (digital) (OkC.O.M.P.U.T.O.-Novus)", "1")]
- [InlineData("Conquistador_Tome_2", "2")]
- [InlineData("Max_l_explorateur-_Tome_0", "0")]
- [InlineData("Chevaliers d'Héliopolis T3 - Rubedo, l'oeuvre au rouge (Jodorowsky & Jérémy)", "3")]
- [InlineData("Adventure Time (2012)/Adventure Time #1 (2012)", "0")]
- [InlineData("Adventure Time TPB (2012)/Adventure Time v01 (2012).cbz", "1")]
- public void ParseComicVolumeTest(string filename, string expected)
- {
- Assert.Equal(expected, API.Services.Tasks.Scanner.Parser.Parser.ParseComicVolume(filename));
- }
-
- [Theory]
- [InlineData("01 Spider-Man & Wolverine 01.cbr", "1")]
- [InlineData("04 - Asterix the Gladiator (1964) (Digital-Empire) (WebP by Doc MaKS)", "0")]
- [InlineData("The First Asterix Frieze (WebP by Doc MaKS)", "0")]
- [InlineData("Batman & Catwoman - Trail of the Gun 01", "1")]
- [InlineData("Batman & Daredevil - King of New York", "0")]
- [InlineData("Batman & Grendel (1996) 01 - Devil's Bones", "1")]
- [InlineData("Batman & Robin the Teen Wonder #0", "0")]
- [InlineData("Batman & Wildcat (1 of 3)", "1")]
- [InlineData("Batman & Wildcat (2 of 3)", "2")]
- [InlineData("Batman And Superman World's Finest #01", "1")]
- [InlineData("Babe 01", "1")]
- [InlineData("Scott Pilgrim 01 - Scott Pilgrim's Precious Little Life (2004)", "1")]
- [InlineData("Teen Titans v1 001 (1966-02) (digital) (OkC.O.M.P.U.T.O.-Novus)", "1")]
- [InlineData("Superman v1 024 (09-10 1943)", "24")]
- [InlineData("Invincible 070.5 - Invincible Returns 1 (2010) (digital) (Minutemen-InnerDemons).cbr", "70.5")]
- [InlineData("Amazing Man Comics chapter 25", "25")]
- [InlineData("Invincible 033.5 - Marvel Team-Up 14 (2006) (digital) (Minutemen-Slayer)", "33.5")]
- [InlineData("Batman Wayne Family Adventures - Ep. 014 - Moving In", "14")]
- [InlineData("Saga 001 (2012) (Digital) (Empire-Zone)", "1")]
- [InlineData("spawn-123", "123")]
- [InlineData("spawn-chapter-123", "123")]
- [InlineData("Spawn 062 (1997) (digital) (TLK-EMPIRE-HD).cbr", "62")]
- [InlineData("Batman Beyond 04 (of 6) (1999)", "4")]
- [InlineData("Invincible 052 (c2c) (2008) (Minutemen-TheCouple)", "52")]
- [InlineData("Y - The Last Man #001", "1")]
- [InlineData("Batman Beyond 001 (2012)", "1")]
- [InlineData("Batman Beyond 2.0 001 (2013)", "1")]
- [InlineData("Batman - Catwoman 001 (2021) (Webrip) (The Last Kryptonian-DCP)", "1")]
- [InlineData("Chew v1 - Taster´s Choise (2012) (Digital) (1920) (Kingpin-Empire)", "0")]
- [InlineData("Chew Script Book (2011) (digital-Empire) SP04", "0")]
- [InlineData("Batgirl Vol.2000 #57 (December, 2004)", "57")]
- [InlineData("Batgirl V2000 #57", "57")]
- [InlineData("Fables 021 (2004) (Digital) (Nahga-Empire).cbr", "21")]
- [InlineData("Cyberpunk 2077 - Trauma Team #04.cbz", "4")]
- [InlineData("2000 AD 0366 [1984-04-28] (flopbie)", "366")]
- [InlineData("Daredevil - v6 - 10 - (2019)", "10")]
- [InlineData("Batman Beyond 2016 - Chapter 001.cbz", "1")]
- [InlineData("Adventure Time (2012)/Adventure Time #1 (2012)", "1")]
- [InlineData("Adventure Time TPB (2012)/Adventure Time v01 (2012).cbz", "0")]
- public void ParseComicChapterTest(string filename, string expected)
- {
- Assert.Equal(expected, API.Services.Tasks.Scanner.Parser.Parser.ParseComicChapter(filename));
- }
+ [Theory]
+ [InlineData("01 Spider-Man & Wolverine 01.cbr", "1")]
+ [InlineData("04 - Asterix the Gladiator (1964) (Digital-Empire) (WebP by Doc MaKS)", "0")]
+ [InlineData("The First Asterix Frieze (WebP by Doc MaKS)", "0")]
+ [InlineData("Batman & Catwoman - Trail of the Gun 01", "1")]
+ [InlineData("Batman & Daredevil - King of New York", "0")]
+ [InlineData("Batman & Grendel (1996) 01 - Devil's Bones", "1")]
+ [InlineData("Batman & Robin the Teen Wonder #0", "0")]
+ [InlineData("Batman & Wildcat (1 of 3)", "1")]
+ [InlineData("Batman & Wildcat (2 of 3)", "2")]
+ [InlineData("Batman And Superman World's Finest #01", "1")]
+ [InlineData("Babe 01", "1")]
+ [InlineData("Scott Pilgrim 01 - Scott Pilgrim's Precious Little Life (2004)", "1")]
+ [InlineData("Teen Titans v1 001 (1966-02) (digital) (OkC.O.M.P.U.T.O.-Novus)", "1")]
+ [InlineData("Superman v1 024 (09-10 1943)", "24")]
+ [InlineData("Invincible 070.5 - Invincible Returns 1 (2010) (digital) (Minutemen-InnerDemons).cbr", "70.5")]
+ [InlineData("Amazing Man Comics chapter 25", "25")]
+ [InlineData("Invincible 033.5 - Marvel Team-Up 14 (2006) (digital) (Minutemen-Slayer)", "33.5")]
+ [InlineData("Batman Wayne Family Adventures - Ep. 014 - Moving In", "14")]
+ [InlineData("Saga 001 (2012) (Digital) (Empire-Zone)", "1")]
+ [InlineData("spawn-123", "123")]
+ [InlineData("spawn-chapter-123", "123")]
+ [InlineData("Spawn 062 (1997) (digital) (TLK-EMPIRE-HD).cbr", "62")]
+ [InlineData("Batman Beyond 04 (of 6) (1999)", "4")]
+ [InlineData("Invincible 052 (c2c) (2008) (Minutemen-TheCouple)", "52")]
+ [InlineData("Y - The Last Man #001", "1")]
+ [InlineData("Batman Beyond 001 (2012)", "1")]
+ [InlineData("Batman Beyond 2.0 001 (2013)", "1")]
+ [InlineData("Batman - Catwoman 001 (2021) (Webrip) (The Last Kryptonian-DCP)", "1")]
+ [InlineData("Chew v1 - Taster´s Choise (2012) (Digital) (1920) (Kingpin-Empire)", "0")]
+ [InlineData("Chew Script Book (2011) (digital-Empire) SP04", "0")]
+ [InlineData("Batgirl Vol.2000 #57 (December, 2004)", "57")]
+ [InlineData("Batgirl V2000 #57", "57")]
+ [InlineData("Fables 021 (2004) (Digital) (Nahga-Empire).cbr", "21")]
+ [InlineData("Cyberpunk 2077 - Trauma Team #04.cbz", "4")]
+ [InlineData("2000 AD 0366 [1984-04-28] (flopbie)", "366")]
+ [InlineData("Daredevil - v6 - 10 - (2019)", "10")]
+ [InlineData("Batman Beyond 2016 - Chapter 001.cbz", "1")]
+ [InlineData("Adventure Time (2012)/Adventure Time #1 (2012)", "1")]
+ [InlineData("Adventure Time TPB (2012)/Adventure Time v01 (2012).cbz", "0")]
+ [InlineData("Kebab Том 1 Глава 3", "3")]
+ [InlineData("Манга Глава 2", "2")]
+ [InlineData("Манга 2 Глава", "2")]
+ [InlineData("Манга Том 1 2 Глава", "2")]
+ public void ParseComicChapterTest(string filename, string expected)
+ {
+ Assert.Equal(expected, API.Services.Tasks.Scanner.Parser.Parser.ParseComicChapter(filename));
+ }
- [Theory]
- [InlineData("Batman - Detective Comics - Rebirth Deluxe Edition Book 02 (2018) (digital) (Son of Ultron-Empire)", true)]
- [InlineData("Zombie Tramp vs. Vampblade TPB (2016) (Digital) (TheArchivist-Empire)", true)]
- [InlineData("Baldwin the Brave & Other Tales Special SP1.cbr", true)]
- [InlineData("Mouse Guard Specials - Spring 1153 - Fraggle Rock FCBD 2010", true)]
- [InlineData("Boule et Bill - THS -Bill à disparu", true)]
- [InlineData("Asterix - HS - Les 12 travaux d'Astérix", true)]
- [InlineData("Sillage Hors Série - Le Collectionneur - Concordance-DKFR", true)]
- [InlineData("laughs", false)]
- [InlineData("Annual Days of Summer", false)]
- [InlineData("Adventure Time 2013 Annual #001 (2013)", true)]
- [InlineData("Adventure Time 2013_Annual_#001 (2013)", true)]
- [InlineData("Adventure Time 2013_-_Annual #001 (2013)", true)]
- public void ParseComicSpecialTest(string input, bool expected)
- {
- Assert.Equal(expected, !string.IsNullOrEmpty(API.Services.Tasks.Scanner.Parser.Parser.ParseComicSpecial(input)));
- }
+ [Theory]
+ [InlineData("Batman - Detective Comics - Rebirth Deluxe Edition Book 02 (2018) (digital) (Son of Ultron-Empire)", true)]
+ [InlineData("Zombie Tramp vs. Vampblade TPB (2016) (Digital) (TheArchivist-Empire)", true)]
+ [InlineData("Baldwin the Brave & Other Tales Special SP1.cbr", true)]
+ [InlineData("Mouse Guard Specials - Spring 1153 - Fraggle Rock FCBD 2010", true)]
+ [InlineData("Boule et Bill - THS -Bill à disparu", true)]
+ [InlineData("Asterix - HS - Les 12 travaux d'Astérix", true)]
+ [InlineData("Sillage Hors Série - Le Collectionneur - Concordance-DKFR", true)]
+ [InlineData("laughs", false)]
+ [InlineData("Annual Days of Summer", false)]
+ [InlineData("Adventure Time 2013 Annual #001 (2013)", true)]
+ [InlineData("Adventure Time 2013_Annual_#001 (2013)", true)]
+ [InlineData("Adventure Time 2013_-_Annual #001 (2013)", true)]
+ [InlineData("G.I. Joe - A Real American Hero Yearbook 004 Reprint (2021)", false)]
+ [InlineData("Mazebook 001", false)]
+ [InlineData("X-23 One Shot (2010)", true)]
+ [InlineData("Casus Belli v1 Hors-Série 21 - Mousquetaires et Sorcellerie", true)]
+ public void IsComicSpecialTest(string input, bool expected)
+ {
+ Assert.Equal(expected, API.Services.Tasks.Scanner.Parser.Parser.IsComicSpecial(input));
}
}
diff --git a/API.Tests/Parser/DefaultParserTests.cs b/API.Tests/Parser/DefaultParserTests.cs
index f32838dd3..2640aa6c2 100644
--- a/API.Tests/Parser/DefaultParserTests.cs
+++ b/API.Tests/Parser/DefaultParserTests.cs
@@ -3,6 +3,7 @@ using System.IO.Abstractions.TestingHelpers;
using API.Entities.Enums;
using API.Parser;
using API.Services;
+using API.Services.Tasks.Scanner.Parser;
using Microsoft.Extensions.Logging;
using NSubstitute;
using Xunit;
@@ -77,6 +78,21 @@ public class DefaultParserTests
Assert.Equal(expectedParseInfo, actual.Series);
}
+ [Theory]
+ [InlineData("/manga/Btooom!/Specials/Art Book.cbz", "Btooom!")]
+ public void ParseFromFallbackFolders_ShouldUseExistingSeriesName_NewScanLoop(string inputFile, string expectedParseInfo)
+ {
+ const string rootDirectory = "/manga/";
+ var fs = new MockFileSystem();
+ fs.AddDirectory(rootDirectory);
+ fs.AddFile(inputFile, new MockFileData(""));
+ var ds = new DirectoryService(Substitute.For>(), fs);
+ var parser = new DefaultParser(ds);
+ var actual = parser.Parse(inputFile, rootDirectory);
+ _defaultParser.ParseFromFallbackFolders(inputFile, rootDirectory, LibraryType.Manga, ref actual);
+ Assert.Equal(expectedParseInfo, actual.Series);
+ }
+
#endregion
@@ -87,6 +103,7 @@ public class DefaultParserTests
{
const string rootPath = @"E:/Manga/";
var expected = new Dictionary();
+
var filepath = @"E:/Manga/Mujaki no Rakuen/Mujaki no Rakuen Vol12 ch76.cbz";
expected.Add(filepath, new ParserInfo
{
@@ -199,14 +216,6 @@ public class DefaultParserTests
FullFilePath = filepath, IsSpecial = false
});
- filepath = @"E:\Manga\Harrison, Kim - The Good, The Bad, and the Undead - Hollows Vol 2.5.epub";
- expected.Add(filepath, new ParserInfo
- {
- Series = "Harrison, Kim - The Good, The Bad, and the Undead - Hollows", Volumes = "2.5", Edition = "",
- Chapters = "0", Filename = "Harrison, Kim - The Good, The Bad, and the Undead - Hollows Vol 2.5.epub", Format = MangaFormat.Epub,
- FullFilePath = filepath, IsSpecial = false
- });
-
// If an image is cover exclusively, ignore it
filepath = @"E:\Manga\Seraph of the End\cover.png";
expected.Add(filepath, null);
@@ -219,11 +228,12 @@ public class DefaultParserTests
FullFilePath = filepath, IsSpecial = false
});
+ // Note: Fallback to folder will parse Monster #8 and get Monster
filepath = @"E:\Manga\Monster #8\Ch. 001-016 [MangaPlus] [Digital] [amit34521]\Monster #8 Ch. 001 [MangaPlus] [Digital] [amit34521]\13.jpg";
expected.Add(filepath, new ParserInfo
{
- Series = "Monster #8", Volumes = "0", Edition = "",
- Chapters = "1", Filename = "13.jpg", Format = MangaFormat.Archive,
+ Series = "Monster", Volumes = "0", Edition = "",
+ Chapters = "1", Filename = "13.jpg", Format = MangaFormat.Image,
FullFilePath = filepath, IsSpecial = false
});
@@ -235,6 +245,29 @@ public class DefaultParserTests
FullFilePath = filepath, IsSpecial = false
});
+ filepath = @"E:\Manga\Extra layer for no reason\Just Images the second\Vol19\ch186\Vol. 19 p106.gif";
+ expected.Add(filepath, new ParserInfo
+ {
+ Series = "Just Images the second", Volumes = "19", Edition = "",
+ Chapters = "186", Filename = "Vol. 19 p106.gif", Format = MangaFormat.Image,
+ FullFilePath = filepath, IsSpecial = false
+ });
+
+ filepath = @"E:\Manga\Extra layer for no reason\Just Images the second\Blank Folder\Vol19\ch186\Vol. 19 p106.gif";
+ expected.Add(filepath, new ParserInfo
+ {
+ Series = "Just Images the second", Volumes = "19", Edition = "",
+ Chapters = "186", Filename = "Vol. 19 p106.gif", Format = MangaFormat.Image,
+ FullFilePath = filepath, IsSpecial = false
+ });
+
+ filepath = @"E:\Manga\Harrison, Kim - The Good, The Bad, and the Undead - Hollows Vol 2.5.epub";
+ expected.Add(filepath, new ParserInfo
+ {
+ Series = "Harrison, Kim - The Good, The Bad, and the Undead - Hollows", Volumes = "2.5", Edition = "",
+ Chapters = "0", Filename = "Harrison, Kim - The Good, The Bad, and the Undead - Hollows Vol 2.5.epub", Format = MangaFormat.Epub,
+ FullFilePath = filepath, IsSpecial = false
+ });
foreach (var file in expected.Keys)
{
@@ -243,7 +276,7 @@ public class DefaultParserTests
if (expectedInfo == null)
{
Assert.Null(actual);
- return;
+ continue;
}
Assert.NotNull(actual);
_testOutputHelper.WriteLine($"Validating {file}");
@@ -383,7 +416,7 @@ public class DefaultParserTests
if (expectedInfo == null)
{
Assert.Null(actual);
- return;
+ continue;
}
Assert.NotNull(actual);
_testOutputHelper.WriteLine($"Validating {file}");
diff --git a/API.Tests/Parser/MangaParserTests.cs b/API.Tests/Parser/MangaParserTests.cs
index 12e312661..89b1112f5 100644
--- a/API.Tests/Parser/MangaParserTests.cs
+++ b/API.Tests/Parser/MangaParserTests.cs
@@ -1,321 +1,334 @@
+using System.Runtime.InteropServices;
using API.Entities.Enums;
using Xunit;
using Xunit.Abstractions;
-namespace API.Tests.Parser
+namespace API.Tests.Parser;
+
+public class MangaParserTests
{
- public class MangaParserTests
+ private readonly ITestOutputHelper _testOutputHelper;
+
+ public MangaParserTests(ITestOutputHelper testOutputHelper)
{
- private readonly ITestOutputHelper _testOutputHelper;
-
- public MangaParserTests(ITestOutputHelper testOutputHelper)
- {
- _testOutputHelper = testOutputHelper;
- }
-
- [Theory]
- [InlineData("Killing Bites Vol. 0001 Ch. 0001 - Galactica Scanlations (gb)", "1")]
- [InlineData("My Girlfriend Is Shobitch v01 - ch. 09 - pg. 008.png", "1")]
- [InlineData("Historys Strongest Disciple Kenichi_v11_c90-98.zip", "11")]
- [InlineData("B_Gata_H_Kei_v01[SlowManga&OverloadScans]", "1")]
- [InlineData("BTOOOM! v01 (2013) (Digital) (Shadowcat-Empire)", "1")]
- [InlineData("Gokukoku no Brynhildr - c001-008 (v01) [TrinityBAKumA]", "1")]
- [InlineData("Dance in the Vampire Bund v16-17 (Digital) (NiceDragon)", "16-17")]
- [InlineData("Akame ga KILL! ZERO v01 (2016) (Digital) (LuCaZ).cbz", "1")]
- [InlineData("v001", "1")]
- [InlineData("Vol 1", "1")]
- [InlineData("vol_356-1", "356")] // Mangapy syntax
- [InlineData("No Volume", "0")]
- [InlineData("U12 (Under 12) Vol. 0001 Ch. 0001 - Reiwa Scans (gb)", "1")]
- [InlineData("[Suihei Kiki]_Kasumi_Otoko_no_Ko_[Taruby]_v1.1.zip", "1")]
- [InlineData("Tonikaku Cawaii [Volume 11].cbz", "11")]
- [InlineData("[WS]_Ichiban_Ushiro_no_Daimaou_v02_ch10.zip", "2")]
- [InlineData("[xPearse] Kyochuu Rettou Volume 1 [English] [Manga] [Volume Scans]", "1")]
- [InlineData("Tower Of God S01 014 (CBT) (digital).cbz", "1")]
- [InlineData("Tenjou_Tenge_v17_c100[MT].zip", "17")]
- [InlineData("Shimoneta - Manmaru Hen - c001-006 (v01) [Various].zip", "1")]
- [InlineData("Future Diary v02 (2009) (Digital) (Viz).cbz", "2")]
- [InlineData("Mujaki no Rakuen Vol12 ch76", "12")]
- [InlineData("Ichinensei_ni_Nacchattara_v02_ch11_[Taruby]_v1.3.zip", "2")]
- [InlineData("Dorohedoro v01 (2010) (Digital) (LostNerevarine-Empire).cbz", "1")]
- [InlineData("Dorohedoro v11 (2013) (Digital) (LostNerevarine-Empire).cbz", "11")]
- [InlineData("Dorohedoro v12 (2013) (Digital) (LostNerevarine-Empire).cbz", "12")]
- [InlineData("Yumekui_Merry_v01_c01[Bakayarou-Kuu].rar", "1")]
- [InlineData("Yumekui-Merry_DKThias_Chapter11v2.zip", "0")]
- [InlineData("Itoshi no Karin - c001-006x1 (v01) [Renzokusei Scans]", "1")]
- [InlineData("Kedouin Makoto - Corpse Party Musume, Chapter 12", "0")]
- [InlineData("VanDread-v01-c001[MD].zip", "1")]
- [InlineData("Ichiban_Ushiro_no_Daimaou_v04_ch27_[VISCANS].zip", "4")]
- [InlineData("Mob Psycho 100 v02 (2019) (Digital) (Shizu).cbz", "2")]
- [InlineData("Kodomo no Jikan vol. 1.cbz", "1")]
- [InlineData("Kodomo no Jikan vol. 10.cbz", "10")]
- [InlineData("Kedouin Makoto - Corpse Party Musume, Chapter 12 [Dametrans][v2]", "0")]
- [InlineData("Vagabond_v03", "3")]
- [InlineData("Mujaki No Rakune Volume 10.cbz", "10")]
- [InlineData("Umineko no Naku Koro ni - Episode 3 - Banquet of the Golden Witch #02.cbz", "0")]
- [InlineData("Volume 12 - Janken Boy is Coming!.cbz", "12")]
- [InlineData("[dmntsf.net] One Piece - Digital Colored Comics Vol. 20 Ch. 177 - 30 Million vs 81 Million.cbz", "20")]
- [InlineData("Gantz.V26.cbz", "26")]
- [InlineData("NEEDLESS_Vol.4_-Simeon_6_v2[SugoiSugoi].rar", "4")]
- [InlineData("[Hidoi]_Amaenaideyo_MS_vol01_chp02.rar", "1")]
- [InlineData("NEEDLESS_Vol.4_-_Simeon_6_v2_[SugoiSugoi].rar", "4")]
- [InlineData("Okusama wa Shougakusei c003 (v01) [bokuwaNEET]", "1")]
- [InlineData("Sword Art Online Vol 10 - Alicization Running [Yen Press] [LuCaZ] {r2}.epub", "10")]
- [InlineData("Noblesse - Episode 406 (52 Pages).7z", "0")]
- [InlineData("X-Men v1 #201 (September 2007).cbz", "1")]
- [InlineData("Hentai Ouji to Warawanai Neko. - Vol. 06 Ch. 034.5", "6")]
- [InlineData("The 100 Girlfriends Who Really, Really, Really, Really, Really Love You - Vol. 03 Ch. 023.5 - Volume 3 Extras.cbz", "3")]
- [InlineData("The 100 Girlfriends Who Really, Really, Really, Really, Really Love You - Vol. 03.5 Ch. 023.5 - Volume 3 Extras.cbz", "3.5")]
- [InlineData("幽游白书完全版 第03卷 天下", "3")]
- [InlineData("阿衰online 第1册", "1")]
- [InlineData("【TFO汉化&Petit汉化】迷你偶像漫画卷2第25话", "2")]
- [InlineData("63권#200", "63")]
- [InlineData("시즌34삽화2", "34")]
- [InlineData("スライム倒して300年、知らないうちにレベルMAXになってました 1巻", "1")]
- [InlineData("スライム倒して300年、知らないうちにレベルMAXになってました 1-3巻", "1-3")]
- public void ParseVolumeTest(string filename, string expected)
- {
- Assert.Equal(expected, API.Services.Tasks.Scanner.Parser.Parser.ParseVolume(filename));
- }
-
- [Theory]
- [InlineData("Killing Bites Vol. 0001 Ch. 0001 - Galactica Scanlations (gb)", "Killing Bites")]
- [InlineData("My Girlfriend Is Shobitch v01 - ch. 09 - pg. 008.png", "My Girlfriend Is Shobitch")]
- [InlineData("Historys Strongest Disciple Kenichi_v11_c90-98.zip", "Historys Strongest Disciple Kenichi")]
- [InlineData("B_Gata_H_Kei_v01[SlowManga&OverloadScans]", "B Gata H Kei")]
- [InlineData("BTOOOM! v01 (2013) (Digital) (Shadowcat-Empire)", "BTOOOM!")]
- [InlineData("Gokukoku no Brynhildr - c001-008 (v01) [TrinityBAKumA]", "Gokukoku no Brynhildr")]
- [InlineData("Dance in the Vampire Bund v16-17 (Digital) (NiceDragon)", "Dance in the Vampire Bund")]
- [InlineData("v001", "")]
- [InlineData("U12 (Under 12) Vol. 0001 Ch. 0001 - Reiwa Scans (gb)", "U12")]
- [InlineData("Akame ga KILL! ZERO (2016-2019) (Digital) (LuCaZ)", "Akame ga KILL! ZERO")]
- [InlineData("APOSIMZ 017 (2018) (Digital) (danke-Empire).cbz", "APOSIMZ")]
- [InlineData("Akiiro Bousou Biyori - 01.jpg", "Akiiro Bousou Biyori")]
- [InlineData("Beelzebub_172_RHS.zip", "Beelzebub")]
- [InlineData("Dr. STONE 136 (2020) (Digital) (LuCaZ).cbz", "Dr. STONE")]
- [InlineData("Cynthia the Mission 29.rar", "Cynthia the Mission")]
- [InlineData("Darling in the FranXX - Volume 01.cbz", "Darling in the FranXX")]
- [InlineData("Darwin's Game - Volume 14 (F).cbz", "Darwin's Game")]
- [InlineData("[BAA]_Darker_than_Black_c7.zip", "Darker than Black")]
- [InlineData("Kedouin Makoto - Corpse Party Musume, Chapter 19 [Dametrans].zip", "Kedouin Makoto - Corpse Party Musume")]
- [InlineData("Kedouin Makoto - Corpse Party Musume, Chapter 01", "Kedouin Makoto - Corpse Party Musume")]
- [InlineData("[WS]_Ichiban_Ushiro_no_Daimaou_v02_ch10.zip", "Ichiban Ushiro no Daimaou")]
- [InlineData("[xPearse] Kyochuu Rettou Volume 1 [English] [Manga] [Volume Scans]", "Kyochuu Rettou")]
- [InlineData("Loose_Relation_Between_Wizard_and_Apprentice_c07[AN].zip", "Loose Relation Between Wizard and Apprentice")]
- [InlineData("Tower Of God S01 014 (CBT) (digital).cbz", "Tower Of God")]
- [InlineData("Tenjou_Tenge_c106[MT].zip", "Tenjou Tenge")]
- [InlineData("Tenjou_Tenge_v17_c100[MT].zip", "Tenjou Tenge")]
- [InlineData("Shimoneta - Manmaru Hen - c001-006 (v01) [Various].zip", "Shimoneta - Manmaru Hen")]
- [InlineData("Future Diary v02 (2009) (Digital) (Viz).cbz", "Future Diary")]
- [InlineData("Tonikaku Cawaii [Volume 11].cbz", "Tonikaku Cawaii")]
- [InlineData("Mujaki no Rakuen Vol12 ch76", "Mujaki no Rakuen")]
- [InlineData("Knights of Sidonia c000 (S2 LE BD Omake - BLAME!) [Habanero Scans]", "Knights of Sidonia")]
- [InlineData("Vol 1.cbz", "")]
- [InlineData("Ichinensei_ni_Nacchattara_v01_ch01_[Taruby]_v1.1.zip", "Ichinensei ni Nacchattara")]
- [InlineData("Chrno_Crusade_Dragon_Age_All_Stars[AS].zip", "")]
- [InlineData("Ichiban_Ushiro_no_Daimaou_v04_ch34_[VISCANS].zip", "Ichiban Ushiro no Daimaou")]
- [InlineData("Rent a Girlfriend v01.cbr", "Rent a Girlfriend")]
- [InlineData("Yumekui_Merry_v01_c01[Bakayarou-Kuu].rar", "Yumekui Merry")]
- [InlineData("Itoshi no Karin - c001-006x1 (v01) [Renzokusei Scans]", "Itoshi no Karin")]
- [InlineData("Tonikaku Kawaii Vol-1 (Ch 01-08)", "Tonikaku Kawaii")]
- [InlineData("Tonikaku Kawaii (Ch 59-67) (Ongoing)", "Tonikaku Kawaii")]
- [InlineData("7thGARDEN v01 (2016) (Digital) (danke).cbz", "7thGARDEN")]
- [InlineData("Kedouin Makoto - Corpse Party Musume, Chapter 12", "Kedouin Makoto - Corpse Party Musume")]
- [InlineData("Kedouin Makoto - Corpse Party Musume, Chapter 09", "Kedouin Makoto - Corpse Party Musume")]
- [InlineData("Goblin Slayer Side Story - Year One 025.5", "Goblin Slayer Side Story - Year One")]
- [InlineData("Goblin Slayer - Brand New Day 006.5 (2019) (Digital) (danke-Empire)", "Goblin Slayer - Brand New Day")]
- [InlineData("Kedouin Makoto - Corpse Party Musume, Chapter 01 [Dametrans][v2]", "Kedouin Makoto - Corpse Party Musume")]
- [InlineData("Vagabond_v03", "Vagabond")]
- [InlineData("[AN] Mahoutsukai to Deshi no Futekisetsu na Kankei Chp. 1", "Mahoutsukai to Deshi no Futekisetsu na Kankei")]
- [InlineData("Beelzebub_Side_Story_02_RHS.zip", "Beelzebub Side Story")]
- [InlineData("[BAA]_Darker_than_Black_Omake-1.zip", "Darker than Black")]
- [InlineData("Baketeriya ch01-05.zip", "Baketeriya")]
- [InlineData("[PROzess]Kimi_ha_midara_na_Boku_no_Joou_-_Ch01", "Kimi ha midara na Boku no Joou")]
- [InlineData("[SugoiSugoi]_NEEDLESS_Vol.2_-_Disk_The_Informant_5_[ENG].rar", "NEEDLESS")]
- [InlineData("Fullmetal Alchemist chapters 101-108.cbz", "Fullmetal Alchemist")]
- [InlineData("To Love Ru v09 Uncensored (Ch.071-079).cbz", "To Love Ru")]
- [InlineData("[dmntsf.net] One Piece - Digital Colored Comics Vol. 20 Ch. 177 - 30 Million vs 81 Million.cbz", "One Piece - Digital Colored Comics")]
- [InlineData("Corpse Party -The Anthology- Sachikos game of love Hysteric Birthday 2U Chapter 01", "Corpse Party -The Anthology- Sachikos game of love Hysteric Birthday 2U")]
- [InlineData("Vol03_ch15-22.rar", "")]
- [InlineData("Love Hina - Special.cbz", "")] // This has to be a fallback case
- [InlineData("Ani-Hina Art Collection.cbz", "")] // This has to be a fallback case
- [InlineData("Magi - Ch.252-005.cbz", "Magi")]
- [InlineData("Umineko no Naku Koro ni - Episode 1 - Legend of the Golden Witch #1", "Umineko no Naku Koro ni")]
- [InlineData("Kimetsu no Yaiba - Digital Colored Comics c162 Three Victorious Stars.cbz", "Kimetsu no Yaiba - Digital Colored Comics")]
- [InlineData("[Hidoi]_Amaenaideyo_MS_vol01_chp02.rar", "Amaenaideyo MS")]
- [InlineData("NEEDLESS_Vol.4_-_Simeon_6_v2_[SugoiSugoi].rar", "NEEDLESS")]
- [InlineData("Okusama wa Shougakusei c003 (v01) [bokuwaNEET]", "Okusama wa Shougakusei")]
- [InlineData("VanDread-v01-c001[MD].zip", "VanDread")]
- [InlineData("Momo The Blood Taker - Chapter 027 Violent Emotion.cbz", "Momo The Blood Taker")]
- [InlineData("Kiss x Sis - Ch.15 - The Angst of a 15 Year Old Boy.cbz", "Kiss x Sis")]
- [InlineData("Green Worldz - Chapter 112 Final Chapter (End).cbz", "Green Worldz")]
- [InlineData("Noblesse - Episode 406 (52 Pages).7z", "Noblesse")]
- [InlineData("X-Men v1 #201 (September 2007).cbz", "X-Men")]
- [InlineData("Kodoja #001 (March 2016)", "Kodoja")]
- [InlineData("Boku No Kokoro No Yabai Yatsu - Chapter 054 I Prayed At The Shrine (V0).cbz", "Boku No Kokoro No Yabai Yatsu")]
- [InlineData("Kiss x Sis - Ch.36 - A Cold Home Visit.cbz", "Kiss x Sis")]
- [InlineData("Seraph of the End - Vampire Reign 093 (2020) (Digital) (LuCaZ)", "Seraph of the End - Vampire Reign")]
- [InlineData("Grand Blue Dreaming - SP02 Extra (2019) (Digital) (danke-Empire).cbz", "Grand Blue Dreaming")]
- [InlineData("Yuusha Ga Shinda! - Vol.tbd Chapter 27.001 V2 Infection ①.cbz", "Yuusha Ga Shinda!")]
- [InlineData("Seraph of the End - Vampire Reign 093 (2020) (Digital) (LuCaZ).cbz", "Seraph of the End - Vampire Reign")]
- [InlineData("Getsuyoubi no Tawawa - Ch. 001 - Ai-chan, Part 1", "Getsuyoubi no Tawawa")]
- [InlineData("Please Go Home, Akutsu-San! - Chapter 038.5 - Volume Announcement.cbz", "Please Go Home, Akutsu-San!")]
- [InlineData("Killing Bites - Vol 11 Chapter 050 Save Me, Nunupi!.cbz", "Killing Bites")]
- [InlineData("Mad Chimera World - Volume 005 - Chapter 026.cbz", "Mad Chimera World")]
- [InlineData("Hentai Ouji to Warawanai Neko. - Vol. 06 Ch. 034.5", "Hentai Ouji to Warawanai Neko.")]
- [InlineData("The 100 Girlfriends Who Really, Really, Really, Really, Really Love You - Vol. 03 Ch. 023.5 - Volume 3 Extras.cbz", "The 100 Girlfriends Who Really, Really, Really, Really, Really Love You")]
- [InlineData("Kimi no Koto ga Daidaidaidaidaisuki na 100-nin no Kanojo Chapter 1-10", "Kimi no Koto ga Daidaidaidaidaisuki na 100-nin no Kanojo")]
- [InlineData("The Duke of Death and His Black Maid - Ch. 177 - The Ball (3).cbz", "The Duke of Death and His Black Maid")]
- [InlineData("The Duke of Death and His Black Maid - Vol. 04 Ch. 054.5 - V4 Omake", "The Duke of Death and His Black Maid")]
- [InlineData("Vol. 04 Ch. 054.5", "")]
- [InlineData("Great_Teacher_Onizuka_v16[TheSpectrum]", "Great Teacher Onizuka")]
- [InlineData("[Renzokusei]_Kimi_wa_Midara_na_Boku_no_Joou_Ch5_Final_Chapter", "Kimi wa Midara na Boku no Joou")]
- [InlineData("Battle Royale, v01 (2000) [TokyoPop] [Manga-Sketchbook]", "Battle Royale")]
- [InlineData("Kaiju No. 8 036 (2021) (Digital)", "Kaiju No. 8")]
- [InlineData("Seraph of the End - Vampire Reign 093 (2020) (Digital) (LuCaZ).cbz", "Seraph of the End - Vampire Reign")]
- [InlineData("Love Hina - Volume 01 [Scans].pdf", "Love Hina")]
- [InlineData("It's Witching Time! 001 (Digital) (Anonymous1234)", "It's Witching Time!")]
- [InlineData("Zettai Karen Children v02 c003 - The Invisible Guardian (2) [JS Scans]", "Zettai Karen Children")]
- [InlineData("My Charms Are Wasted on Kuroiwa Medaka - Ch. 37.5 - Volume Extras", "My Charms Are Wasted on Kuroiwa Medaka")]
- [InlineData("Highschool of the Dead - Full Color Edition v02 [Uasaha] (Yen Press)", "Highschool of the Dead - Full Color Edition")]
- [InlineData("諌山創] 進撃の巨人 第23巻", "諌山創] 進撃の巨人")]
- [InlineData("(一般コミック) [奥浩哉] いぬやしき 第09巻", "いぬやしき")]
- [InlineData("Highschool of the Dead - 02", "Highschool of the Dead")]
- public void ParseSeriesTest(string filename, string expected)
- {
- Assert.Equal(expected, API.Services.Tasks.Scanner.Parser.Parser.ParseSeries(filename));
- }
-
- [Theory]
- [InlineData("Killing Bites Vol. 0001 Ch. 0001 - Galactica Scanlations (gb)", "1")]
- [InlineData("My Girlfriend Is Shobitch v01 - ch. 09 - pg. 008.png", "9")]
- [InlineData("Historys Strongest Disciple Kenichi_v11_c90-98.zip", "90-98")]
- [InlineData("B_Gata_H_Kei_v01[SlowManga&OverloadScans]", "0")]
- [InlineData("BTOOOM! v01 (2013) (Digital) (Shadowcat-Empire)", "0")]
- [InlineData("Gokukoku no Brynhildr - c001-008 (v01) [TrinityBAKumA]", "1-8")]
- [InlineData("Dance in the Vampire Bund v16-17 (Digital) (NiceDragon)", "0")]
- [InlineData("c001", "1")]
- [InlineData("[Suihei Kiki]_Kasumi_Otoko_no_Ko_[Taruby]_v1.12.zip", "12")]
- [InlineData("Adding volume 1 with File: Ana Satsujin Vol. 1 Ch. 5 - Manga Box (gb).cbz", "5")]
- [InlineData("Hinowa ga CRUSH! 018 (2019) (Digital) (LuCaZ).cbz", "18")]
- [InlineData("Cynthia The Mission - c000-006 (v06) [Desudesu&Brolen].zip", "0-6")]
- [InlineData("[WS]_Ichiban_Ushiro_no_Daimaou_v02_ch10.zip", "10")]
- [InlineData("Loose_Relation_Between_Wizard_and_Apprentice_c07[AN].zip", "7")]
- [InlineData("Tower Of God S01 014 (CBT) (digital).cbz", "14")]
- [InlineData("Tenjou_Tenge_c106[MT].zip", "106")]
- [InlineData("Tenjou_Tenge_v17_c100[MT].zip", "100")]
- [InlineData("Shimoneta - Manmaru Hen - c001-006 (v01) [Various].zip", "1-6")]
- [InlineData("Mujaki no Rakuen Vol12 ch76", "76")]
- [InlineData("Beelzebub_01_[Noodles].zip", "1")]
- [InlineData("Yumekui-Merry_DKThias_Chapter21.zip", "21")]
- [InlineData("Yumekui_Merry_v01_c01[Bakayarou-Kuu].rar", "1")]
- [InlineData("Yumekui-Merry_DKThias_Chapter11v2.zip", "11")]
- [InlineData("Yumekui-Merry DKThiasScanlations Chapter51v2", "51")]
- [InlineData("Yumekui-Merry_DKThiasScanlations&RenzokuseiScans_Chapter61", "61")]
- [InlineData("Goblin Slayer Side Story - Year One 017.5", "17.5")]
- [InlineData("Beelzebub_53[KSH].zip", "53")]
- [InlineData("Black Bullet - v4 c20.5 [batoto]", "20.5")]
- [InlineData("Itoshi no Karin - c001-006x1 (v01) [Renzokusei Scans]", "1-6")]
- [InlineData("APOSIMZ 040 (2020) (Digital) (danke-Empire).cbz", "40")]
- [InlineData("Kedouin Makoto - Corpse Party Musume, Chapter 12", "12")]
- [InlineData("Vol 1", "0")]
- [InlineData("VanDread-v01-c001[MD].zip", "1")]
- [InlineData("Goblin Slayer Side Story - Year One 025.5", "25.5")]
- [InlineData("Kedouin Makoto - Corpse Party Musume, Chapter 01", "1")]
- [InlineData("To Love Ru v11 Uncensored (Ch.089-097+Omake)", "89-97")]
- [InlineData("To Love Ru v18 Uncensored (Ch.153-162.5)", "153-162.5")]
- [InlineData("[AN] Mahoutsukai to Deshi no Futekisetsu na Kankei Chp. 1", "1")]
- [InlineData("Beelzebub_Side_Story_02_RHS.zip", "2")]
- [InlineData("[PROzess]Kimi_ha_midara_na_Boku_no_Joou_-_Ch01", "1")]
- [InlineData("Fullmetal Alchemist chapters 101-108.cbz", "101-108")]
- [InlineData("Umineko no Naku Koro ni - Episode 3 - Banquet of the Golden Witch #02.cbz", "2")]
- [InlineData("To Love Ru v09 Uncensored (Ch.071-079).cbz", "71-79")]
- [InlineData("Corpse Party -The Anthology- Sachikos game of love Hysteric Birthday 2U Extra Chapter.rar", "0")]
- [InlineData("Beelzebub_153b_RHS.zip", "153.5")]
- [InlineData("Beelzebub_150-153b_RHS.zip", "150-153.5")]
- [InlineData("Transferred to another world magical swordsman v1.1", "1")]
- [InlineData("Transferred to another world magical swordsman v1.2", "2")]
- [InlineData("Kiss x Sis - Ch.15 - The Angst of a 15 Year Old Boy.cbz", "15")]
- [InlineData("Kiss x Sis - Ch.12 - 1 , 2 , 3P!.cbz", "12")]
- [InlineData("Umineko no Naku Koro ni - Episode 1 - Legend of the Golden Witch #1", "1")]
- [InlineData("Kiss x Sis - Ch.00 - Let's Start from 0.cbz", "0")]
- [InlineData("[Hidoi]_Amaenaideyo_MS_vol01_chp02.rar", "2")]
- [InlineData("Okusama wa Shougakusei c003 (v01) [bokuwaNEET]", "3")]
- [InlineData("Tomogui Kyoushitsu - Chapter 006 Game 005 - Fingernails On Right Hand (Part 002).cbz", "6")]
- [InlineData("Noblesse - Episode 406 (52 Pages).7z", "406")]
- [InlineData("X-Men v1 #201 (September 2007).cbz", "201")]
- [InlineData("Kodoja #001 (March 2016)", "1")]
- [InlineData("Noblesse - Episode 429 (74 Pages).7z", "429")]
- [InlineData("Boku No Kokoro No Yabai Yatsu - Chapter 054 I Prayed At The Shrine (V0).cbz", "54")]
- [InlineData("Ijousha No Ai - Vol.01 Chapter 029 8 Years Ago", "29")]
- [InlineData("Kedouin Makoto - Corpse Party Musume, Chapter 09.cbz", "9")]
- [InlineData("Hentai Ouji to Warawanai Neko. - Vol. 06 Ch. 034.5", "34.5")]
- [InlineData("Kimi no Koto ga Daidaidaidaidaisuki na 100-nin no Kanojo Chapter 1-10", "1-10")]
- [InlineData("Deku_&_Bakugo_-_Rising_v1_c1.1.cbz", "1.1")]
- [InlineData("Chapter 63 - The Promise Made for 520 Cenz.cbr", "63")]
- [InlineData("Harrison, Kim - The Good, The Bad, and the Undead - Hollows Vol 2.5.epub", "0")]
- [InlineData("Kaiju No. 8 036 (2021) (Digital)", "36")]
- [InlineData("Samurai Jack Vol. 01 - The threads of Time", "0")]
- [InlineData("【TFO汉化&Petit汉化】迷你偶像漫画第25话", "25")]
- [InlineData("이세계에서 고아원을 열었지만, 어째서인지 아무도 독립하려 하지 않는다 38-1화 ", "38")]
- [InlineData("[ハレム]ナナとカオル ~高校生のSMごっこ~ 第10話", "10")]
- public void ParseChaptersTest(string filename, string expected)
- {
- Assert.Equal(expected, API.Services.Tasks.Scanner.Parser.Parser.ParseChapter(filename));
- }
-
-
- [Theory]
- [InlineData("Tenjou Tenge Omnibus", "Omnibus")]
- [InlineData("Tenjou Tenge {Full Contact Edition}", "")]
- [InlineData("Tenjo Tenge {Full Contact Edition} v01 (2011) (Digital) (ASTC).cbz", "")]
- [InlineData("Wotakoi - Love is Hard for Otaku Omnibus v01 (2018) (Digital) (danke-Empire)", "Omnibus")]
- [InlineData("To Love Ru v01 Uncensored (Ch.001-007)", "Uncensored")]
- [InlineData("Chobits Omnibus Edition v01 [Dark Horse]", "Omnibus Edition")]
- [InlineData("[dmntsf.net] One Piece - Digital Colored Comics Vol. 20 Ch. 177 - 30 Million vs 81 Million.cbz", "")]
- [InlineData("AKIRA - c003 (v01) [Full Color] [Darkhorse].cbz", "")]
- [InlineData("Love Hina Omnibus v05 (2015) (Digital-HD) (Asgard-Empire).cbz", "Omnibus")]
- public void ParseEditionTest(string input, string expected)
- {
- Assert.Equal(expected, API.Services.Tasks.Scanner.Parser.Parser.ParseEdition(input));
- }
- [Theory]
- [InlineData("Beelzebub Special OneShot - Minna no Kochikame x Beelzebub (2016) [Mangastream].cbz", true)]
- [InlineData("Beelzebub_Omake_June_2012_RHS", true)]
- [InlineData("Beelzebub_Side_Story_02_RHS.zip", false)]
- [InlineData("Darker than Black Shikkoku no Hana Special [Simple Scans].zip", true)]
- [InlineData("Darker than Black Shikkoku no Hana Fanbook Extra [Simple Scans].zip", true)]
- [InlineData("Corpse Party -The Anthology- Sachikos game of love Hysteric Birthday 2U Extra Chapter", true)]
- [InlineData("Ani-Hina Art Collection.cbz", true)]
- [InlineData("Gifting The Wonderful World With Blessings! - 3 Side Stories [yuNS][Unknown]", true)]
- [InlineData("A Town Where You Live - Bonus Chapter.zip", true)]
- [InlineData("Yuki Merry - 4-Komga Anthology", false)]
- [InlineData("Beastars - SP01", false)]
- [InlineData("Beastars SP01", false)]
- [InlineData("The League of Extraordinary Gentlemen", false)]
- [InlineData("The League of Extra-ordinary Gentlemen", false)]
- public void ParseMangaSpecialTest(string input, bool expected)
- {
- Assert.Equal(expected, !string.IsNullOrEmpty(API.Services.Tasks.Scanner.Parser.Parser.ParseMangaSpecial(input)));
- }
-
- [Theory]
- [InlineData("image.png", MangaFormat.Image)]
- [InlineData("image.cbz", MangaFormat.Archive)]
- [InlineData("image.txt", MangaFormat.Unknown)]
- public void ParseFormatTest(string inputFile, MangaFormat expected)
- {
- Assert.Equal(expected, API.Services.Tasks.Scanner.Parser.Parser.ParseFormat(inputFile));
- }
-
- [Theory]
- [InlineData("Gifting The Wonderful World With Blessings! - 3 Side Stories [yuNS][Unknown].epub", "Side Stories")]
- public void ParseSpecialTest(string inputFile, string expected)
- {
- Assert.Equal(expected, API.Services.Tasks.Scanner.Parser.Parser.ParseMangaSpecial(inputFile));
- }
-
-
-
+ _testOutputHelper = testOutputHelper;
}
+
+ [Theory]
+ [InlineData("Killing Bites Vol. 0001 Ch. 0001 - Galactica Scanlations (gb)", "1")]
+ [InlineData("My Girlfriend Is Shobitch v01 - ch. 09 - pg. 008.png", "1")]
+ [InlineData("Historys Strongest Disciple Kenichi_v11_c90-98.zip", "11")]
+ [InlineData("B_Gata_H_Kei_v01[SlowManga&OverloadScans]", "1")]
+ [InlineData("BTOOOM! v01 (2013) (Digital) (Shadowcat-Empire)", "1")]
+ [InlineData("Gokukoku no Brynhildr - c001-008 (v01) [TrinityBAKumA]", "1")]
+ [InlineData("Dance in the Vampire Bund v16-17 (Digital) (NiceDragon)", "16-17")]
+ [InlineData("Akame ga KILL! ZERO v01 (2016) (Digital) (LuCaZ).cbz", "1")]
+ [InlineData("v001", "1")]
+ [InlineData("Vol 1", "1")]
+ [InlineData("vol_356-1", "356")] // Mangapy syntax
+ [InlineData("No Volume", "0")]
+ [InlineData("U12 (Under 12) Vol. 0001 Ch. 0001 - Reiwa Scans (gb)", "1")]
+ [InlineData("[Suihei Kiki]_Kasumi_Otoko_no_Ko_[Taruby]_v1.1.zip", "1.1")]
+ [InlineData("Tonikaku Cawaii [Volume 11].cbz", "11")]
+ [InlineData("[WS]_Ichiban_Ushiro_no_Daimaou_v02_ch10.zip", "2")]
+ [InlineData("[xPearse] Kyochuu Rettou Volume 1 [English] [Manga] [Volume Scans]", "1")]
+ [InlineData("Tower Of God S01 014 (CBT) (digital).cbz", "1")]
+ [InlineData("Tenjou_Tenge_v17_c100[MT].zip", "17")]
+ [InlineData("Shimoneta - Manmaru Hen - c001-006 (v01) [Various].zip", "1")]
+ [InlineData("Future Diary v02 (2009) (Digital) (Viz).cbz", "2")]
+ [InlineData("Mujaki no Rakuen Vol12 ch76", "12")]
+ [InlineData("Ichinensei_ni_Nacchattara_v02_ch11_[Taruby]_v1.3.zip", "2")]
+ [InlineData("Dorohedoro v01 (2010) (Digital) (LostNerevarine-Empire).cbz", "1")]
+ [InlineData("Dorohedoro v11 (2013) (Digital) (LostNerevarine-Empire).cbz", "11")]
+ [InlineData("Yumekui_Merry_v01_c01[Bakayarou-Kuu].rar", "1")]
+ [InlineData("Yumekui-Merry_DKThias_Chapter11v2.zip", "0")]
+ [InlineData("Itoshi no Karin - c001-006x1 (v01) [Renzokusei Scans]", "1")]
+ [InlineData("Kedouin Makoto - Corpse Party Musume, Chapter 12", "0")]
+ [InlineData("VanDread-v01-c001[MD].zip", "1")]
+ [InlineData("Ichiban_Ushiro_no_Daimaou_v04_ch27_[VISCANS].zip", "4")]
+ [InlineData("Mob Psycho 100 v02 (2019) (Digital) (Shizu).cbz", "2")]
+ [InlineData("Kodomo no Jikan vol. 1.cbz", "1")]
+ [InlineData("Kodomo no Jikan vol. 10.cbz", "10")]
+ [InlineData("Kedouin Makoto - Corpse Party Musume, Chapter 12 [Dametrans][v2]", "0")]
+ [InlineData("Vagabond_v03", "3")]
+ [InlineData("Mujaki No Rakune Volume 10.cbz", "10")]
+ [InlineData("Umineko no Naku Koro ni - Episode 3 - Banquet of the Golden Witch #02.cbz", "0")]
+ [InlineData("Volume 12 - Janken Boy is Coming!.cbz", "12")]
+ [InlineData("[dmntsf.net] One Piece - Digital Colored Comics Vol. 20 Ch. 177 - 30 Million vs 81 Million.cbz", "20")]
+ [InlineData("Gantz.V26.cbz", "26")]
+ [InlineData("NEEDLESS_Vol.4_-Simeon_6_v2[SugoiSugoi].rar", "4")]
+ [InlineData("[Hidoi]_Amaenaideyo_MS_vol01_chp02.rar", "1")]
+ [InlineData("NEEDLESS_Vol.4_-_Simeon_6_v2_[SugoiSugoi].rar", "4")]
+ [InlineData("Okusama wa Shougakusei c003 (v01) [bokuwaNEET]", "1")]
+ [InlineData("Sword Art Online Vol 10 - Alicization Running [Yen Press] [LuCaZ] {r2}.epub", "10")]
+ [InlineData("Noblesse - Episode 406 (52 Pages).7z", "0")]
+ [InlineData("X-Men v1 #201 (September 2007).cbz", "1")]
+ [InlineData("Hentai Ouji to Warawanai Neko. - Vol. 06 Ch. 034.5", "6")]
+ [InlineData("The 100 Girlfriends Who Really, Really, Really, Really, Really Love You - Vol. 03 Ch. 023.5 - Volume 3 Extras.cbz", "3")]
+ [InlineData("The 100 Girlfriends Who Really, Really, Really, Really, Really Love You - Vol. 03.5 Ch. 023.5 - Volume 3 Extras.cbz", "3.5")]
+ [InlineData("幽游白书完全版 第03卷 天下", "3")]
+ [InlineData("阿衰online 第1册", "1")]
+ [InlineData("【TFO汉化&Petit汉化】迷你偶像漫画卷2第25话", "2")]
+ [InlineData("スライム倒して300年、知らないうちにレベルMAXになってました 1巻", "1")]
+ [InlineData("スライム倒して300年、知らないうちにレベルMAXになってました 1-3巻", "1-3")]
+ [InlineData("Dance in the Vampire Bund {Special Edition} v03.5 (2019) (Digital) (KG Manga)", "3.5")]
+ [InlineData("Kebab Том 1 Глава 3", "1")]
+ [InlineData("Манга Глава 2", "0")]
+ [InlineData("Манга Тома 1-4", "1-4")]
+ [InlineData("Манга Том 1-4", "1-4")]
+ [InlineData("조선왕조실톡 106화", "106")]
+ [InlineData("죽음 13회", "13")]
+ [InlineData("동의보감 13장", "13")]
+ [InlineData("몰?루 아카이브 7.5권", "7.5")]
+ [InlineData("63권#200", "63")]
+ [InlineData("시즌34삽화2", "34")]
+ public void ParseVolumeTest(string filename, string expected)
+ {
+ Assert.Equal(expected, API.Services.Tasks.Scanner.Parser.Parser.ParseVolume(filename));
+ }
+
+ [Theory]
+ [InlineData("Killing Bites Vol. 0001 Ch. 0001 - Galactica Scanlations (gb)", "Killing Bites")]
+ [InlineData("My Girlfriend Is Shobitch v01 - ch. 09 - pg. 008.png", "My Girlfriend Is Shobitch")]
+ [InlineData("Historys Strongest Disciple Kenichi_v11_c90-98.zip", "Historys Strongest Disciple Kenichi")]
+ [InlineData("B_Gata_H_Kei_v01[SlowManga&OverloadScans]", "B Gata H Kei")]
+ [InlineData("BTOOOM! v01 (2013) (Digital) (Shadowcat-Empire)", "BTOOOM!")]
+ [InlineData("Gokukoku no Brynhildr - c001-008 (v01) [TrinityBAKumA]", "Gokukoku no Brynhildr")]
+ [InlineData("Dance in the Vampire Bund v16-17 (Digital) (NiceDragon)", "Dance in the Vampire Bund")]
+ [InlineData("v001", "")]
+ [InlineData("U12 (Under 12) Vol. 0001 Ch. 0001 - Reiwa Scans (gb)", "U12")]
+ [InlineData("Akame ga KILL! ZERO (2016-2019) (Digital) (LuCaZ)", "Akame ga KILL! ZERO")]
+ [InlineData("APOSIMZ 017 (2018) (Digital) (danke-Empire).cbz", "APOSIMZ")]
+ [InlineData("Akiiro Bousou Biyori - 01.jpg", "Akiiro Bousou Biyori")]
+ [InlineData("Beelzebub_172_RHS.zip", "Beelzebub")]
+ [InlineData("Dr. STONE 136 (2020) (Digital) (LuCaZ).cbz", "Dr. STONE")]
+ [InlineData("Cynthia the Mission 29.rar", "Cynthia the Mission")]
+ [InlineData("Darling in the FranXX - Volume 01.cbz", "Darling in the FranXX")]
+ [InlineData("Darwin's Game - Volume 14 (F).cbz", "Darwin's Game")]
+ [InlineData("[BAA]_Darker_than_Black_c7.zip", "Darker than Black")]
+ [InlineData("Kedouin Makoto - Corpse Party Musume, Chapter 19 [Dametrans].zip", "Kedouin Makoto - Corpse Party Musume")]
+ [InlineData("Kedouin Makoto - Corpse Party Musume, Chapter 01", "Kedouin Makoto - Corpse Party Musume")]
+ [InlineData("[WS]_Ichiban_Ushiro_no_Daimaou_v02_ch10.zip", "Ichiban Ushiro no Daimaou")]
+ [InlineData("[xPearse] Kyochuu Rettou Volume 1 [English] [Manga] [Volume Scans]", "Kyochuu Rettou")]
+ [InlineData("Loose_Relation_Between_Wizard_and_Apprentice_c07[AN].zip", "Loose Relation Between Wizard and Apprentice")]
+ [InlineData("Tower Of God S01 014 (CBT) (digital).cbz", "Tower Of God")]
+ [InlineData("Tenjou_Tenge_c106[MT].zip", "Tenjou Tenge")]
+ [InlineData("Tenjou_Tenge_v17_c100[MT].zip", "Tenjou Tenge")]
+ [InlineData("Shimoneta - Manmaru Hen - c001-006 (v01) [Various].zip", "Shimoneta - Manmaru Hen")]
+ [InlineData("Future Diary v02 (2009) (Digital) (Viz).cbz", "Future Diary")]
+ [InlineData("Tonikaku Cawaii [Volume 11].cbz", "Tonikaku Cawaii")]
+ [InlineData("Mujaki no Rakuen Vol12 ch76", "Mujaki no Rakuen")]
+ [InlineData("Knights of Sidonia c000 (S2 LE BD Omake - BLAME!) [Habanero Scans]", "Knights of Sidonia")]
+ [InlineData("Vol 1.cbz", "")]
+ [InlineData("Ichinensei_ni_Nacchattara_v01_ch01_[Taruby]_v1.1.zip", "Ichinensei ni Nacchattara")]
+ [InlineData("Chrno_Crusade_Dragon_Age_All_Stars[AS].zip", "")]
+ [InlineData("Ichiban_Ushiro_no_Daimaou_v04_ch34_[VISCANS].zip", "Ichiban Ushiro no Daimaou")]
+ [InlineData("Rent a Girlfriend v01.cbr", "Rent a Girlfriend")]
+ [InlineData("Yumekui_Merry_v01_c01[Bakayarou-Kuu].rar", "Yumekui Merry")]
+ [InlineData("Itoshi no Karin - c001-006x1 (v01) [Renzokusei Scans]", "Itoshi no Karin")]
+ [InlineData("Tonikaku Kawaii Vol-1 (Ch 01-08)", "Tonikaku Kawaii")]
+ [InlineData("Tonikaku Kawaii (Ch 59-67) (Ongoing)", "Tonikaku Kawaii")]
+ [InlineData("7thGARDEN v01 (2016) (Digital) (danke).cbz", "7thGARDEN")]
+ [InlineData("Kedouin Makoto - Corpse Party Musume, Chapter 12", "Kedouin Makoto - Corpse Party Musume")]
+ [InlineData("Kedouin Makoto - Corpse Party Musume, Chapter 09", "Kedouin Makoto - Corpse Party Musume")]
+ [InlineData("Goblin Slayer Side Story - Year One 025.5", "Goblin Slayer Side Story - Year One")]
+ [InlineData("Goblin Slayer - Brand New Day 006.5 (2019) (Digital) (danke-Empire)", "Goblin Slayer - Brand New Day")]
+ [InlineData("Kedouin Makoto - Corpse Party Musume, Chapter 01 [Dametrans][v2]", "Kedouin Makoto - Corpse Party Musume")]
+ [InlineData("Vagabond_v03", "Vagabond")]
+ [InlineData("[AN] Mahoutsukai to Deshi no Futekisetsu na Kankei Chp. 1", "Mahoutsukai to Deshi no Futekisetsu na Kankei")]
+ [InlineData("Beelzebub_Side_Story_02_RHS.zip", "Beelzebub Side Story")]
+ [InlineData("[BAA]_Darker_than_Black_Omake-1.zip", "Darker than Black")]
+ [InlineData("Baketeriya ch01-05.zip", "Baketeriya")]
+ [InlineData("[PROzess]Kimi_ha_midara_na_Boku_no_Joou_-_Ch01", "Kimi ha midara na Boku no Joou")]
+ [InlineData("[SugoiSugoi]_NEEDLESS_Vol.2_-_Disk_The_Informant_5_[ENG].rar", "NEEDLESS")]
+ [InlineData("Fullmetal Alchemist chapters 101-108.cbz", "Fullmetal Alchemist")]
+ [InlineData("To Love Ru v09 Uncensored (Ch.071-079).cbz", "To Love Ru")]
+ [InlineData("[dmntsf.net] One Piece - Digital Colored Comics Vol. 20 Ch. 177 - 30 Million vs 81 Million.cbz", "One Piece - Digital Colored Comics")]
+ [InlineData("Corpse Party -The Anthology- Sachikos game of love Hysteric Birthday 2U Chapter 01", "Corpse Party -The Anthology- Sachikos game of love Hysteric Birthday 2U")]
+ [InlineData("Vol03_ch15-22.rar", "")]
+ [InlineData("Love Hina - Special.cbz", "")] // This has to be a fallback case
+ [InlineData("Ani-Hina Art Collection.cbz", "")] // This has to be a fallback case
+ [InlineData("Magi - Ch.252-005.cbz", "Magi")]
+ [InlineData("Umineko no Naku Koro ni - Episode 1 - Legend of the Golden Witch #1", "Umineko no Naku Koro ni")]
+ [InlineData("Kimetsu no Yaiba - Digital Colored Comics c162 Three Victorious Stars.cbz", "Kimetsu no Yaiba - Digital Colored Comics")]
+ [InlineData("[Hidoi]_Amaenaideyo_MS_vol01_chp02.rar", "Amaenaideyo MS")]
+ [InlineData("NEEDLESS_Vol.4_-_Simeon_6_v2_[SugoiSugoi].rar", "NEEDLESS")]
+ [InlineData("Okusama wa Shougakusei c003 (v01) [bokuwaNEET]", "Okusama wa Shougakusei")]
+ [InlineData("VanDread-v01-c001[MD].zip", "VanDread")]
+ [InlineData("Momo The Blood Taker - Chapter 027 Violent Emotion.cbz", "Momo The Blood Taker")]
+ [InlineData("Kiss x Sis - Ch.15 - The Angst of a 15 Year Old Boy.cbz", "Kiss x Sis")]
+ [InlineData("Green Worldz - Chapter 112 Final Chapter (End).cbz", "Green Worldz")]
+ [InlineData("Noblesse - Episode 406 (52 Pages).7z", "Noblesse")]
+ [InlineData("X-Men v1 #201 (September 2007).cbz", "X-Men")]
+ [InlineData("Kodoja #001 (March 2016)", "Kodoja")]
+ [InlineData("Boku No Kokoro No Yabai Yatsu - Chapter 054 I Prayed At The Shrine (V0).cbz", "Boku No Kokoro No Yabai Yatsu")]
+ [InlineData("Kiss x Sis - Ch.36 - A Cold Home Visit.cbz", "Kiss x Sis")]
+ [InlineData("Seraph of the End - Vampire Reign 093 (2020) (Digital) (LuCaZ)", "Seraph of the End - Vampire Reign")]
+ [InlineData("Grand Blue Dreaming - SP02 Extra (2019) (Digital) (danke-Empire).cbz", "Grand Blue Dreaming")]
+ [InlineData("Yuusha Ga Shinda! - Vol.tbd Chapter 27.001 V2 Infection ①.cbz", "Yuusha Ga Shinda!")]
+ [InlineData("Seraph of the End - Vampire Reign 093 (2020) (Digital) (LuCaZ).cbz", "Seraph of the End - Vampire Reign")]
+ [InlineData("Getsuyoubi no Tawawa - Ch. 001 - Ai-chan, Part 1", "Getsuyoubi no Tawawa")]
+ [InlineData("Please Go Home, Akutsu-San! - Chapter 038.5 - Volume Announcement.cbz", "Please Go Home, Akutsu-San!")]
+ [InlineData("Killing Bites - Vol 11 Chapter 050 Save Me, Nunupi!.cbz", "Killing Bites")]
+ [InlineData("Mad Chimera World - Volume 005 - Chapter 026.cbz", "Mad Chimera World")]
+ [InlineData("Hentai Ouji to Warawanai Neko. - Vol. 06 Ch. 034.5", "Hentai Ouji to Warawanai Neko.")]
+ [InlineData("The 100 Girlfriends Who Really, Really, Really, Really, Really Love You - Vol. 03 Ch. 023.5 - Volume 3 Extras.cbz", "The 100 Girlfriends Who Really, Really, Really, Really, Really Love You")]
+ [InlineData("Kimi no Koto ga Daidaidaidaidaisuki na 100-nin no Kanojo Chapter 1-10", "Kimi no Koto ga Daidaidaidaidaisuki na 100-nin no Kanojo")]
+ [InlineData("The Duke of Death and His Black Maid - Ch. 177 - The Ball (3).cbz", "The Duke of Death and His Black Maid")]
+ [InlineData("The Duke of Death and His Black Maid - Vol. 04 Ch. 054.5 - V4 Omake", "The Duke of Death and His Black Maid")]
+ [InlineData("Vol. 04 Ch. 054.5", "")]
+ [InlineData("Great_Teacher_Onizuka_v16[TheSpectrum]", "Great Teacher Onizuka")]
+ [InlineData("[Renzokusei]_Kimi_wa_Midara_na_Boku_no_Joou_Ch5_Final_Chapter", "Kimi wa Midara na Boku no Joou")]
+ [InlineData("Battle Royale, v01 (2000) [TokyoPop] [Manga-Sketchbook]", "Battle Royale")]
+ [InlineData("Kaiju No. 8 036 (2021) (Digital)", "Kaiju No. 8")]
+ [InlineData("Seraph of the End - Vampire Reign 093 (2020) (Digital) (LuCaZ).cbz", "Seraph of the End - Vampire Reign")]
+ [InlineData("Love Hina - Volume 01 [Scans].pdf", "Love Hina")]
+ [InlineData("It's Witching Time! 001 (Digital) (Anonymous1234)", "It's Witching Time!")]
+ [InlineData("Zettai Karen Children v02 c003 - The Invisible Guardian (2) [JS Scans]", "Zettai Karen Children")]
+ [InlineData("My Charms Are Wasted on Kuroiwa Medaka - Ch. 37.5 - Volume Extras", "My Charms Are Wasted on Kuroiwa Medaka")]
+ [InlineData("Highschool of the Dead - Full Color Edition v02 [Uasaha] (Yen Press)", "Highschool of the Dead - Full Color Edition")]
+ [InlineData("諌山創] 進撃の巨人 第23巻", "諌山創] 進撃の巨人")]
+ [InlineData("(一般コミック) [奥浩哉] いぬやしき 第09巻", "いぬやしき")]
+ [InlineData("Highschool of the Dead - 02", "Highschool of the Dead")]
+ [InlineData("Kebab Том 1 Глава 3", "Kebab")]
+ [InlineData("Манга Глава 2", "Манга")]
+ [InlineData("Манга Глава 2-2", "Манга")]
+ [InlineData("Манга Том 1 3-4 Глава", "Манга")]
+ [InlineData("Esquire 6권 2021년 10월호", "Esquire")]
+ public void ParseSeriesTest(string filename, string expected)
+ {
+ Assert.Equal(expected, API.Services.Tasks.Scanner.Parser.Parser.ParseSeries(filename));
+ }
+
+ [Theory]
+ [InlineData("Killing Bites Vol. 0001 Ch. 0001 - Galactica Scanlations (gb)", "1")]
+ [InlineData("My Girlfriend Is Shobitch v01 - ch. 09 - pg. 008.png", "9")]
+ [InlineData("Historys Strongest Disciple Kenichi_v11_c90-98.zip", "90-98")]
+ [InlineData("B_Gata_H_Kei_v01[SlowManga&OverloadScans]", "0")]
+ [InlineData("BTOOOM! v01 (2013) (Digital) (Shadowcat-Empire)", "0")]
+ [InlineData("Gokukoku no Brynhildr - c001-008 (v01) [TrinityBAKumA]", "1-8")]
+ [InlineData("Dance in the Vampire Bund v16-17 (Digital) (NiceDragon)", "0")]
+ [InlineData("c001", "1")]
+ [InlineData("[Suihei Kiki]_Kasumi_Otoko_no_Ko_[Taruby]_v1.12.zip", "0")]
+ [InlineData("Adding volume 1 with File: Ana Satsujin Vol. 1 Ch. 5 - Manga Box (gb).cbz", "5")]
+ [InlineData("Hinowa ga CRUSH! 018 (2019) (Digital) (LuCaZ).cbz", "18")]
+ [InlineData("Cynthia The Mission - c000-006 (v06) [Desudesu&Brolen].zip", "0-6")]
+ [InlineData("[WS]_Ichiban_Ushiro_no_Daimaou_v02_ch10.zip", "10")]
+ [InlineData("Loose_Relation_Between_Wizard_and_Apprentice_c07[AN].zip", "7")]
+ [InlineData("Tower Of God S01 014 (CBT) (digital).cbz", "14")]
+ [InlineData("Tenjou_Tenge_c106[MT].zip", "106")]
+ [InlineData("Tenjou_Tenge_v17_c100[MT].zip", "100")]
+ [InlineData("Shimoneta - Manmaru Hen - c001-006 (v01) [Various].zip", "1-6")]
+ [InlineData("Mujaki no Rakuen Vol12 ch76", "76")]
+ [InlineData("Beelzebub_01_[Noodles].zip", "1")]
+ [InlineData("Yumekui-Merry_DKThias_Chapter21.zip", "21")]
+ [InlineData("Yumekui_Merry_v01_c01[Bakayarou-Kuu].rar", "1")]
+ [InlineData("Yumekui-Merry_DKThias_Chapter11v2.zip", "11")]
+ [InlineData("Yumekui-Merry DKThiasScanlations Chapter51v2", "51")]
+ [InlineData("Yumekui-Merry_DKThiasScanlations&RenzokuseiScans_Chapter61", "61")]
+ [InlineData("Goblin Slayer Side Story - Year One 017.5", "17.5")]
+ [InlineData("Beelzebub_53[KSH].zip", "53")]
+ [InlineData("Black Bullet - v4 c20.5 [batoto]", "20.5")]
+ [InlineData("Itoshi no Karin - c001-006x1 (v01) [Renzokusei Scans]", "1-6")]
+ [InlineData("APOSIMZ 040 (2020) (Digital) (danke-Empire).cbz", "40")]
+ [InlineData("Kedouin Makoto - Corpse Party Musume, Chapter 12", "12")]
+ [InlineData("Vol 1", "0")]
+ [InlineData("VanDread-v01-c001[MD].zip", "1")]
+ [InlineData("Goblin Slayer Side Story - Year One 025.5", "25.5")]
+ [InlineData("Kedouin Makoto - Corpse Party Musume, Chapter 01", "1")]
+ [InlineData("To Love Ru v11 Uncensored (Ch.089-097+Omake)", "89-97")]
+ [InlineData("To Love Ru v18 Uncensored (Ch.153-162.5)", "153-162.5")]
+ [InlineData("[AN] Mahoutsukai to Deshi no Futekisetsu na Kankei Chp. 1", "1")]
+ [InlineData("Beelzebub_Side_Story_02_RHS.zip", "2")]
+ [InlineData("[PROzess]Kimi_ha_midara_na_Boku_no_Joou_-_Ch01", "1")]
+ [InlineData("Fullmetal Alchemist chapters 101-108.cbz", "101-108")]
+ [InlineData("Umineko no Naku Koro ni - Episode 3 - Banquet of the Golden Witch #02.cbz", "2")]
+ [InlineData("To Love Ru v09 Uncensored (Ch.071-079).cbz", "71-79")]
+ [InlineData("Corpse Party -The Anthology- Sachikos game of love Hysteric Birthday 2U Extra Chapter.rar", "0")]
+ [InlineData("Beelzebub_153b_RHS.zip", "153.5")]
+ [InlineData("Beelzebub_150-153b_RHS.zip", "150-153.5")]
+ [InlineData("Transferred to another world magical swordsman v1.1", "0")]
+ [InlineData("Kiss x Sis - Ch.15 - The Angst of a 15 Year Old Boy.cbz", "15")]
+ [InlineData("Kiss x Sis - Ch.12 - 1 , 2 , 3P!.cbz", "12")]
+ [InlineData("Umineko no Naku Koro ni - Episode 1 - Legend of the Golden Witch #1", "1")]
+ [InlineData("Kiss x Sis - Ch.00 - Let's Start from 0.cbz", "0")]
+ [InlineData("[Hidoi]_Amaenaideyo_MS_vol01_chp02.rar", "2")]
+ [InlineData("Okusama wa Shougakusei c003 (v01) [bokuwaNEET]", "3")]
+ [InlineData("Tomogui Kyoushitsu - Chapter 006 Game 005 - Fingernails On Right Hand (Part 002).cbz", "6")]
+ [InlineData("Noblesse - Episode 406 (52 Pages).7z", "406")]
+ [InlineData("X-Men v1 #201 (September 2007).cbz", "201")]
+ [InlineData("Kodoja #001 (March 2016)", "1")]
+ [InlineData("Noblesse - Episode 429 (74 Pages).7z", "429")]
+ [InlineData("Boku No Kokoro No Yabai Yatsu - Chapter 054 I Prayed At The Shrine (V0).cbz", "54")]
+ [InlineData("Ijousha No Ai - Vol.01 Chapter 029 8 Years Ago", "29")]
+ [InlineData("Kedouin Makoto - Corpse Party Musume, Chapter 09.cbz", "9")]
+ [InlineData("Hentai Ouji to Warawanai Neko. - Vol. 06 Ch. 034.5", "34.5")]
+ [InlineData("Kimi no Koto ga Daidaidaidaidaisuki na 100-nin no Kanojo Chapter 1-10", "1-10")]
+ [InlineData("Deku_&_Bakugo_-_Rising_v1_c1.1.cbz", "1.1")]
+ [InlineData("Chapter 63 - The Promise Made for 520 Cenz.cbr", "63")]
+ [InlineData("Harrison, Kim - The Good, The Bad, and the Undead - Hollows Vol 2.5.epub", "0")]
+ [InlineData("Kaiju No. 8 036 (2021) (Digital)", "36")]
+ [InlineData("Samurai Jack Vol. 01 - The threads of Time", "0")]
+ [InlineData("【TFO汉化&Petit汉化】迷你偶像漫画第25话", "25")]
+ [InlineData("자유록 13회#2", "13")]
+ [InlineData("이세계에서 고아원을 열었지만, 어째서인지 아무도 독립하려 하지 않는다 38-1화 ", "38")]
+ [InlineData("[ハレム]ナナとカオル ~高校生のSMごっこ~ 第10話", "10")]
+ [InlineData("Dance in the Vampire Bund {Special Edition} v03.5 (2019) (Digital) (KG Manga)", "0")]
+ [InlineData("Kebab Том 1 Глава 3", "3")]
+ [InlineData("Манга Глава 2", "2")]
+ [InlineData("Манга 2 Глава", "2")]
+ [InlineData("Манга Том 1 2 Глава", "2")]
+ public void ParseChaptersTest(string filename, string expected)
+ {
+ Assert.Equal(expected, API.Services.Tasks.Scanner.Parser.Parser.ParseChapter(filename));
+ }
+
+
+ [Theory]
+ [InlineData("Tenjou Tenge Omnibus", "Omnibus")]
+ [InlineData("Tenjou Tenge {Full Contact Edition}", "")]
+ [InlineData("Tenjo Tenge {Full Contact Edition} v01 (2011) (Digital) (ASTC).cbz", "")]
+ [InlineData("Wotakoi - Love is Hard for Otaku Omnibus v01 (2018) (Digital) (danke-Empire)", "Omnibus")]
+ [InlineData("To Love Ru v01 Uncensored (Ch.001-007)", "Uncensored")]
+ [InlineData("Chobits Omnibus Edition v01 [Dark Horse]", "Omnibus Edition")]
+ [InlineData("Chobits_Omnibus_Edition_v01_[Dark_Horse]", "Omnibus Edition")]
+ [InlineData("[dmntsf.net] One Piece - Digital Colored Comics Vol. 20 Ch. 177 - 30 Million vs 81 Million.cbz", "")]
+ [InlineData("AKIRA - c003 (v01) [Full Color] [Darkhorse].cbz", "")]
+ [InlineData("Love Hina Omnibus v05 (2015) (Digital-HD) (Asgard-Empire).cbz", "Omnibus")]
+ public void ParseEditionTest(string input, string expected)
+ {
+ Assert.Equal(expected, API.Services.Tasks.Scanner.Parser.Parser.ParseEdition(input));
+ }
+ [Theory]
+ [InlineData("Beelzebub Special OneShot - Minna no Kochikame x Beelzebub (2016) [Mangastream].cbz", true)]
+ [InlineData("Beelzebub_Omake_June_2012_RHS", true)]
+ [InlineData("Beelzebub_Side_Story_02_RHS.zip", false)]
+ [InlineData("Darker than Black Shikkoku no Hana Special [Simple Scans].zip", true)]
+ [InlineData("Darker than Black Shikkoku no Hana Fanbook Extra [Simple Scans].zip", true)]
+ [InlineData("Corpse Party -The Anthology- Sachikos game of love Hysteric Birthday 2U Extra Chapter", true)]
+ [InlineData("Ani-Hina Art Collection.cbz", true)]
+ [InlineData("Gifting The Wonderful World With Blessings! - 3 Side Stories [yuNS][Unknown]", true)]
+ [InlineData("A Town Where You Live - Bonus Chapter.zip", true)]
+ [InlineData("Yuki Merry - 4-Komga Anthology", false)]
+ [InlineData("Beastars - SP01", false)]
+ [InlineData("Beastars SP01", false)]
+ [InlineData("The League of Extraordinary Gentlemen", false)]
+ [InlineData("The League of Extra-ordinary Gentlemen", false)]
+ [InlineData("Gifting The Wonderful World With Blessings! - 3 Side Stories [yuNS][Unknown].epub", true)]
+ [InlineData("Dr. Ramune - Mysterious Disease Specialist v01 (2020) (Digital) (danke-Empire).cbz", false)]
+ public void IsMangaSpecialTest(string input, bool expected)
+ {
+ Assert.Equal(expected, API.Services.Tasks.Scanner.Parser.Parser.IsMangaSpecial(input));
+ }
+
+ [Theory]
+ [InlineData("image.png", MangaFormat.Image)]
+ [InlineData("image.cbz", MangaFormat.Archive)]
+ [InlineData("image.txt", MangaFormat.Unknown)]
+ public void ParseFormatTest(string inputFile, MangaFormat expected)
+ {
+ Assert.Equal(expected, API.Services.Tasks.Scanner.Parser.Parser.ParseFormat(inputFile));
+ }
+
+
}
diff --git a/API.Tests/Parser/ParserInfoTests.cs b/API.Tests/Parser/ParserInfoTests.cs
index 16906cf55..ee4881eff 100644
--- a/API.Tests/Parser/ParserInfoTests.cs
+++ b/API.Tests/Parser/ParserInfoTests.cs
@@ -2,109 +2,108 @@
using API.Parser;
using Xunit;
-namespace API.Tests.Parser
+namespace API.Tests.Parser;
+
+public class ParserInfoTests
{
- public class ParserInfoTests
+ [Fact]
+ public void MergeFromTest()
{
- [Fact]
- public void MergeFromTest()
+ var p1 = new ParserInfo()
{
- var p1 = new ParserInfo()
- {
- Chapters = "0",
- Edition = "",
- Format = MangaFormat.Archive,
- FullFilePath = "/manga/darker than black.cbz",
- IsSpecial = false,
- Series = "darker than black",
- Title = "darker than black",
- Volumes = "0"
- };
+ Chapters = "0",
+ Edition = "",
+ Format = MangaFormat.Archive,
+ FullFilePath = "/manga/darker than black.cbz",
+ IsSpecial = false,
+ Series = "darker than black",
+ Title = "darker than black",
+ Volumes = "0"
+ };
- var p2 = new ParserInfo()
- {
- Chapters = "1",
- Edition = "",
- Format = MangaFormat.Archive,
- FullFilePath = "/manga/darker than black.cbz",
- IsSpecial = false,
- Series = "darker than black",
- Title = "Darker Than Black",
- Volumes = "0"
- };
-
- var expected = new ParserInfo()
- {
- Chapters = "1",
- Edition = "",
- Format = MangaFormat.Archive,
- FullFilePath = "/manga/darker than black.cbz",
- IsSpecial = false,
- Series = "darker than black",
- Title = "darker than black",
- Volumes = "0"
- };
- p1.Merge(p2);
-
- AssertSame(expected, p1);
-
- }
-
- [Fact]
- public void MergeFromTest2()
+ var p2 = new ParserInfo()
{
- var p1 = new ParserInfo()
- {
- Chapters = "1",
- Edition = "",
- Format = MangaFormat.Archive,
- FullFilePath = "/manga/darker than black.cbz",
- IsSpecial = true,
- Series = "darker than black",
- Title = "darker than black",
- Volumes = "0"
- };
+ Chapters = "1",
+ Edition = "",
+ Format = MangaFormat.Archive,
+ FullFilePath = "/manga/darker than black.cbz",
+ IsSpecial = false,
+ Series = "darker than black",
+ Title = "Darker Than Black",
+ Volumes = "0"
+ };
- var p2 = new ParserInfo()
- {
- Chapters = "0",
- Edition = "",
- Format = MangaFormat.Archive,
- FullFilePath = "/manga/darker than black.cbz",
- IsSpecial = false,
- Series = "darker than black",
- Title = "Darker Than Black",
- Volumes = "1"
- };
-
- var expected = new ParserInfo()
- {
- Chapters = "1",
- Edition = "",
- Format = MangaFormat.Archive,
- FullFilePath = "/manga/darker than black.cbz",
- IsSpecial = true,
- Series = "darker than black",
- Title = "darker than black",
- Volumes = "1"
- };
- p1.Merge(p2);
-
- AssertSame(expected, p1);
-
- }
-
-
- private static void AssertSame(ParserInfo expected, ParserInfo actual)
+ var expected = new ParserInfo()
{
- Assert.Equal(expected.Chapters, actual.Chapters);
- Assert.Equal(expected.Volumes, actual.Volumes);
- Assert.Equal(expected.Edition, actual.Edition);
- Assert.Equal(expected.Filename, actual.Filename);
- Assert.Equal(expected.Format, actual.Format);
- Assert.Equal(expected.Series, actual.Series);
- Assert.Equal(expected.IsSpecial, actual.IsSpecial);
- Assert.Equal(expected.FullFilePath, actual.FullFilePath);
- }
+ Chapters = "1",
+ Edition = "",
+ Format = MangaFormat.Archive,
+ FullFilePath = "/manga/darker than black.cbz",
+ IsSpecial = false,
+ Series = "darker than black",
+ Title = "darker than black",
+ Volumes = "0"
+ };
+ p1.Merge(p2);
+
+ AssertSame(expected, p1);
+
+ }
+
+ [Fact]
+ public void MergeFromTest2()
+ {
+ var p1 = new ParserInfo()
+ {
+ Chapters = "1",
+ Edition = "",
+ Format = MangaFormat.Archive,
+ FullFilePath = "/manga/darker than black.cbz",
+ IsSpecial = true,
+ Series = "darker than black",
+ Title = "darker than black",
+ Volumes = "0"
+ };
+
+ var p2 = new ParserInfo()
+ {
+ Chapters = "0",
+ Edition = "",
+ Format = MangaFormat.Archive,
+ FullFilePath = "/manga/darker than black.cbz",
+ IsSpecial = false,
+ Series = "darker than black",
+ Title = "Darker Than Black",
+ Volumes = "1"
+ };
+
+ var expected = new ParserInfo()
+ {
+ Chapters = "1",
+ Edition = "",
+ Format = MangaFormat.Archive,
+ FullFilePath = "/manga/darker than black.cbz",
+ IsSpecial = true,
+ Series = "darker than black",
+ Title = "darker than black",
+ Volumes = "1"
+ };
+ p1.Merge(p2);
+
+ AssertSame(expected, p1);
+
+ }
+
+
+ private static void AssertSame(ParserInfo expected, ParserInfo actual)
+ {
+ Assert.Equal(expected.Chapters, actual.Chapters);
+ Assert.Equal(expected.Volumes, actual.Volumes);
+ Assert.Equal(expected.Edition, actual.Edition);
+ Assert.Equal(expected.Filename, actual.Filename);
+ Assert.Equal(expected.Format, actual.Format);
+ Assert.Equal(expected.Series, actual.Series);
+ Assert.Equal(expected.IsSpecial, actual.IsSpecial);
+ Assert.Equal(expected.FullFilePath, actual.FullFilePath);
}
}
diff --git a/API.Tests/Parser/ParserTest.cs b/API.Tests/Parser/ParserTest.cs
index c1ef966c9..e2f06465b 100644
--- a/API.Tests/Parser/ParserTest.cs
+++ b/API.Tests/Parser/ParserTest.cs
@@ -2,233 +2,291 @@ using System.Linq;
using Xunit;
using static API.Services.Tasks.Scanner.Parser.Parser;
-namespace API.Tests.Parser
+namespace API.Tests.Parser;
+
+public class ParserTests
{
- public class ParserTests
+ [Theory]
+ [InlineData("Joe Shmo, Green Blue", "Joe Shmo, Green Blue")]
+ [InlineData("Shmo, Joe", "Shmo, Joe")]
+ [InlineData(" Joe Shmo ", "Joe Shmo")]
+ public void CleanAuthorTest(string input, string expected)
{
- [Theory]
- [InlineData("Joe Shmo, Green Blue", "Joe Shmo, Green Blue")]
- [InlineData("Shmo, Joe", "Shmo, Joe")]
- [InlineData(" Joe Shmo ", "Joe Shmo")]
- public void CleanAuthorTest(string input, string expected)
- {
- Assert.Equal(expected, CleanAuthor(input));
- }
+ Assert.Equal(expected, CleanAuthor(input));
+ }
- [Theory]
- [InlineData("", "")]
- [InlineData("DEAD Tube Prologue", "DEAD Tube Prologue")]
- [InlineData("DEAD Tube Prologue SP01", "DEAD Tube Prologue")]
- [InlineData("DEAD_Tube_Prologue SP01", "DEAD Tube Prologue")]
- public void CleanSpecialTitleTest(string input, string expected)
- {
- Assert.Equal(expected, CleanSpecialTitle(input));
- }
+ [Theory]
+ [InlineData("", "")]
+ [InlineData("DEAD Tube Prologue", "DEAD Tube Prologue")]
+ [InlineData("DEAD Tube Prologue SP01", "DEAD Tube Prologue")]
+ [InlineData("DEAD_Tube_Prologue SP01", "DEAD Tube Prologue")]
+ public void CleanSpecialTitleTest(string input, string expected)
+ {
+ Assert.Equal(expected, CleanSpecialTitle(input));
+ }
- [Theory]
- [InlineData("Beastars - SP01", true)]
- [InlineData("Beastars SP01", true)]
- [InlineData("Beastars Special 01", false)]
- [InlineData("Beastars Extra 01", false)]
- [InlineData("Batman Beyond - Return of the Joker (2001) SP01", true)]
- public void HasSpecialTest(string input, bool expected)
- {
- Assert.Equal(expected, HasSpecialMarker(input));
- }
+ [Theory]
+ [InlineData("Beastars - SP01", true)]
+ [InlineData("Beastars SP01", true)]
+ [InlineData("Beastars Special 01", false)]
+ [InlineData("Beastars Extra 01", false)]
+ [InlineData("Batman Beyond - Return of the Joker (2001) SP01", true)]
+ public void HasSpecialTest(string input, bool expected)
+ {
+ Assert.Equal(expected, HasSpecialMarker(input));
+ }
- [Theory]
- [InlineData("0001", "1")]
- [InlineData("1", "1")]
- [InlineData("0013", "13")]
- public void RemoveLeadingZeroesTest(string input, string expected)
- {
- Assert.Equal(expected, RemoveLeadingZeroes(input));
- }
+ [Theory]
+ [InlineData("0001", "1")]
+ [InlineData("1", "1")]
+ [InlineData("0013", "13")]
+ public void RemoveLeadingZeroesTest(string input, string expected)
+ {
+ Assert.Equal(expected, RemoveLeadingZeroes(input));
+ }
- [Theory]
- [InlineData("1", "001")]
- [InlineData("10", "010")]
- [InlineData("100", "100")]
- public void PadZerosTest(string input, string expected)
- {
- Assert.Equal(expected, PadZeros(input));
- }
+ [Theory]
+ [InlineData("1", "001")]
+ [InlineData("10", "010")]
+ [InlineData("100", "100")]
+ public void PadZerosTest(string input, string expected)
+ {
+ Assert.Equal(expected, PadZeros(input));
+ }
- [Theory]
- [InlineData("Hello_I_am_here", false, "Hello I am here")]
- [InlineData("Hello_I_am_here ", false, "Hello I am here")]
- [InlineData("[ReleaseGroup] The Title", false, "The Title")]
- [InlineData("[ReleaseGroup]_The_Title", false, "The Title")]
- [InlineData("-The Title", false, "The Title")]
- [InlineData("- The Title", false, "The Title")]
- [InlineData("[Suihei Kiki]_Kasumi_Otoko_no_Ko_[Taruby]_v1.1", false, "Kasumi Otoko no Ko v1.1")]
- [InlineData("Batman - Detective Comics - Rebirth Deluxe Edition Book 04 (2019) (digital) (Son of Ultron-Empire)", true, "Batman - Detective Comics - Rebirth Deluxe Edition")]
- [InlineData("Something - Full Color Edition", false, "Something - Full Color Edition")]
- public void CleanTitleTest(string input, bool isComic, string expected)
- {
- Assert.Equal(expected, CleanTitle(input, isComic));
- }
+ [Theory]
+ [InlineData("Hello_I_am_here", false, "Hello I am here")]
+ [InlineData("Hello_I_am_here ", false, "Hello I am here")]
+ [InlineData("[ReleaseGroup] The Title", false, "The Title")]
+ [InlineData("[ReleaseGroup]_The_Title", false, "The Title")]
+ [InlineData("-The Title", false, "The Title")]
+ [InlineData("- The Title", false, "The Title")]
+ [InlineData("[Suihei Kiki]_Kasumi_Otoko_no_Ko_[Taruby]_v1.1", false, "Kasumi Otoko no Ko v1.1")]
+ [InlineData("Batman - Detective Comics - Rebirth Deluxe Edition Book 04 (2019) (digital) (Son of Ultron-Empire)", true, "Batman - Detective Comics - Rebirth Deluxe Edition")]
+ [InlineData("Something - Full Color Edition", false, "Something - Full Color Edition")]
+ [InlineData("Witchblade 089 (2005) (Bittertek-DCP) (Top Cow (Image Comics))", true, "Witchblade 089")]
+ [InlineData("(C99) Kami-sama Hiroimashita. (SSSS.GRIDMAN)", false, "Kami-sama Hiroimashita.")]
+ [InlineData("Dr. Ramune - Mysterious Disease Specialist v01 (2020) (Digital) (danke-Empire)", false, "Dr. Ramune - Mysterious Disease Specialist v01")]
+ [InlineData("Magic Knight Rayearth {Omnibus Edition}", false, "Magic Knight Rayearth {}")]
+ [InlineData("Magic Knight Rayearth {Omnibus Version}", false, "Magic Knight Rayearth { Version}")]
+ public void CleanTitleTest(string input, bool isComic, string expected)
+ {
+ Assert.Equal(expected, CleanTitle(input, isComic));
+ }
- [Theory]
- [InlineData("src: url(fonts/AvenirNext-UltraLight.ttf)", true)]
- [InlineData("src: url(ideal-sans-serif.woff)", true)]
- [InlineData("src: local(\"Helvetica Neue Bold\")", true)]
- [InlineData("src: url(\"/fonts/OpenSans-Regular-webfont.woff2\")", true)]
- [InlineData("src: local(\"/fonts/OpenSans-Regular-webfont.woff2\")", true)]
- [InlineData("src: url(data:application/x-font-woff", false)]
- public void FontCssRewriteMatches(string input, bool expectedMatch)
- {
- Assert.Equal(expectedMatch, FontSrcUrlRegex.Matches(input).Count > 0);
- }
+ [Theory]
+ [InlineData("src: url(fonts/AvenirNext-UltraLight.ttf)", true)]
+ [InlineData("src: url(ideal-sans-serif.woff)", true)]
+ [InlineData("src: local(\"Helvetica Neue Bold\")", true)]
+ [InlineData("src: url(\"/fonts/OpenSans-Regular-webfont.woff2\")", true)]
+ [InlineData("src: local(\"/fonts/OpenSans-Regular-webfont.woff2\")", true)]
+ [InlineData("src: url(data:application/x-font-woff", false)]
+ public void FontCssRewriteMatches(string input, bool expectedMatch)
+ {
+ Assert.Equal(expectedMatch, FontSrcUrlRegex.Matches(input).Count > 0);
+ }
- [Theory]
- [InlineData("src: url(fonts/AvenirNext-UltraLight.ttf)", new [] {"src: url(", "fonts/AvenirNext-UltraLight.ttf", ")"})]
- [InlineData("src: url(ideal-sans-serif.woff)", new [] {"src: url(", "ideal-sans-serif.woff", ")"})]
- [InlineData("src: local(\"Helvetica Neue Bold\")", new [] {"src: local(\"", "Helvetica Neue Bold", "\")"})]
- [InlineData("src: url(\"/fonts/OpenSans-Regular-webfont.woff2\")", new [] {"src: url(\"", "/fonts/OpenSans-Regular-webfont.woff2", "\")"})]
- [InlineData("src: local(\"/fonts/OpenSans-Regular-webfont.woff2\")", new [] {"src: local(\"", "/fonts/OpenSans-Regular-webfont.woff2", "\")"})]
- public void FontCssCorrectlySeparates(string input, string[] expected)
- {
- Assert.Equal(expected, FontSrcUrlRegex.Match(input).Groups.Values.Select(g => g.Value).Where((_, i) => i > 0).ToArray());
- }
+ [Theory]
+ [InlineData("src: url(fonts/AvenirNext-UltraLight.ttf)", new [] {"src: url(", "fonts/AvenirNext-UltraLight.ttf", ")"})]
+ [InlineData("src: url(ideal-sans-serif.woff)", new [] {"src: url(", "ideal-sans-serif.woff", ")"})]
+ [InlineData("src: local(\"Helvetica Neue Bold\")", new [] {"src: local(\"", "Helvetica Neue Bold", "\")"})]
+ [InlineData("src: url(\"/fonts/OpenSans-Regular-webfont.woff2\")", new [] {"src: url(\"", "/fonts/OpenSans-Regular-webfont.woff2", "\")"})]
+ [InlineData("src: local(\"/fonts/OpenSans-Regular-webfont.woff2\")", new [] {"src: local(\"", "/fonts/OpenSans-Regular-webfont.woff2", "\")"})]
+ public void FontCssCorrectlySeparates(string input, string[] expected)
+ {
+ Assert.Equal(expected, FontSrcUrlRegex.Match(input).Groups.Values.Select(g => g.Value).Where((_, i) => i > 0).ToArray());
+ }
- [Theory]
- [InlineData("test.cbz", true)]
- [InlineData("test.cbr", true)]
- [InlineData("test.zip", true)]
- [InlineData("test.rar", true)]
- [InlineData("test.rar.!qb", false)]
- [InlineData("[shf-ma-khs-aqs]negi_pa_vol15007.jpg", false)]
- public void IsArchiveTest(string input, bool expected)
- {
- Assert.Equal(expected, IsArchive(input));
- }
+ [Theory]
+ [InlineData("test.cbz", true)]
+ [InlineData("test.cbr", true)]
+ [InlineData("test.zip", true)]
+ [InlineData("test.rar", true)]
+ [InlineData("test.rar.!qb", false)]
+ [InlineData("[shf-ma-khs-aqs]negi_pa_vol15007.jpg", false)]
+ public void IsArchiveTest(string input, bool expected)
+ {
+ Assert.Equal(expected, IsArchive(input));
+ }
- [Theory]
- [InlineData("test.epub", true)]
- [InlineData("test.pdf", true)]
- [InlineData("test.mobi", false)]
- [InlineData("test.djvu", false)]
- [InlineData("test.zip", false)]
- [InlineData("test.rar", false)]
- [InlineData("test.epub.!qb", false)]
- [InlineData("[shf-ma-khs-aqs]negi_pa_vol15007.ebub", false)]
- public void IsBookTest(string input, bool expected)
- {
- Assert.Equal(expected, IsBook(input));
- }
+ [Theory]
+ [InlineData("test.epub", true)]
+ [InlineData("test.pdf", true)]
+ [InlineData("test.mobi", false)]
+ [InlineData("test.djvu", false)]
+ [InlineData("test.zip", false)]
+ [InlineData("test.rar", false)]
+ [InlineData("test.epub.!qb", false)]
+ [InlineData("[shf-ma-khs-aqs]negi_pa_vol15007.ebub", false)]
+ public void IsBookTest(string input, bool expected)
+ {
+ Assert.Equal(expected, IsBook(input));
+ }
- [Theory]
- [InlineData("test.epub", true)]
- [InlineData("test.EPUB", true)]
- [InlineData("test.mobi", false)]
- [InlineData("test.epub.!qb", false)]
- [InlineData("[shf-ma-khs-aqs]negi_pa_vol15007.ebub", false)]
- public void IsEpubTest(string input, bool expected)
- {
- Assert.Equal(expected, IsEpub(input));
- }
+ [Theory]
+ [InlineData("test.epub", true)]
+ [InlineData("test.EPUB", true)]
+ [InlineData("test.mobi", false)]
+ [InlineData("test.epub.!qb", false)]
+ [InlineData("[shf-ma-khs-aqs]negi_pa_vol15007.ebub", false)]
+ public void IsEpubTest(string input, bool expected)
+ {
+ Assert.Equal(expected, IsEpub(input));
+ }
- [Theory]
- [InlineData("12-14", 12)]
- [InlineData("24", 24)]
- [InlineData("18-04", 4)]
- [InlineData("18-04.5", 4.5)]
- [InlineData("40", 40)]
- [InlineData("40a-040b", 0)]
- [InlineData("40.1_a", 0)]
- public void MinimumNumberFromRangeTest(string input, float expected)
- {
- Assert.Equal(expected, MinNumberFromRange(input));
- }
+ [Theory]
+ [InlineData("12-14", 12)]
+ [InlineData("24", 24)]
+ [InlineData("18-04", 4)]
+ [InlineData("18-04.5", 4.5)]
+ [InlineData("40", 40)]
+ [InlineData("40a-040b", 0)]
+ [InlineData("40.1_a", 0)]
+ [InlineData("3.5", 3.5)]
+ [InlineData("3.5-4.0", 3.5)]
+ [InlineData("asdfasdf", 0.0)]
+ public void MinimumNumberFromRangeTest(string input, float expected)
+ {
+ Assert.Equal(expected, MinNumberFromRange(input));
+ }
- [Theory]
- [InlineData("12-14", 14)]
- [InlineData("24", 24)]
- [InlineData("18-04", 18)]
- [InlineData("18-04.5", 18)]
- [InlineData("40", 40)]
- [InlineData("40a-040b", 0)]
- [InlineData("40.1_a", 0)]
- public void MaximumNumberFromRangeTest(string input, float expected)
- {
- Assert.Equal(expected, MaxNumberFromRange(input));
- }
+ [Theory]
+ [InlineData("12-14", 14)]
+ [InlineData("24", 24)]
+ [InlineData("18-04", 18)]
+ [InlineData("18-04.5", 18)]
+ [InlineData("40", 40)]
+ [InlineData("40a-040b", 0)]
+ [InlineData("40.1_a", 0)]
+ [InlineData("3.5", 3.5)]
+ [InlineData("3.5-4.0", 4.0)]
+ [InlineData("asdfasdf", 0.0)]
+ public void MaximumNumberFromRangeTest(string input, float expected)
+ {
+ Assert.Equal(expected, MaxNumberFromRange(input));
+ }
- [Theory]
- [InlineData("Darker Than Black", "darkerthanblack")]
- [InlineData("Darker Than Black - Something", "darkerthanblacksomething")]
- [InlineData("Darker Than_Black", "darkerthanblack")]
- [InlineData("Citrus", "citrus")]
- [InlineData("Citrus+", "citrus+")]
- [InlineData("Again!!!!", "again")]
- [InlineData("카비타", "카비타")]
- [InlineData("06", "06")]
- [InlineData("", "")]
- public void NormalizeTest(string input, string expected)
- {
- Assert.Equal(expected, Normalize(input));
- }
+ [Theory]
+ [InlineData("Darker Than Black", "darkerthanblack")]
+ [InlineData("Darker Than Black - Something", "darkerthanblacksomething")]
+ [InlineData("Darker Than_Black", "darkerthanblack")]
+ [InlineData("Citrus", "citrus")]
+ [InlineData("Citrus+", "citrus+")]
+ [InlineData("Again", "again")]
+ [InlineData("카비타", "카비타")]
+ [InlineData("06", "06")]
+ [InlineData("", "")]
+ public void NormalizeTest(string input, string expected)
+ {
+ Assert.Equal(expected, Normalize(input));
+ }
- [Theory]
- [InlineData("test.jpg", true)]
- [InlineData("test.jpeg", true)]
- [InlineData("test.png", true)]
- [InlineData(".test.jpg", false)]
- [InlineData("!test.jpg", true)]
- [InlineData("test.webp", true)]
- [InlineData("test.gif", true)]
- public void IsImageTest(string filename, bool expected)
- {
- Assert.Equal(expected, IsImage(filename));
- }
+ [Theory]
+ [InlineData("test.jpg", true)]
+ [InlineData("test.jpeg", true)]
+ [InlineData("test.png", true)]
+ [InlineData(".test.jpg", false)]
+ [InlineData("!test.jpg", true)]
+ [InlineData("test.webp", true)]
+ [InlineData("test.gif", true)]
+ public void IsImageTest(string filename, bool expected)
+ {
+ Assert.Equal(expected, IsImage(filename));
+ }
- [Theory]
- [InlineData("Love Hina - Special.jpg", false)]
- [InlineData("folder.jpg", true)]
- [InlineData("DearS_v01_cover.jpg", true)]
- [InlineData("DearS_v01_covers.jpg", false)]
- [InlineData("!cover.jpg", true)]
- [InlineData("cover.jpg", true)]
- [InlineData("cover.png", true)]
- [InlineData("ch1/cover.png", true)]
- [InlineData("ch1/backcover.png", false)]
- [InlineData("backcover.png", false)]
- [InlineData("back_cover.png", false)]
- public void IsCoverImageTest(string inputPath, bool expected)
- {
- Assert.Equal(expected, IsCoverImage(inputPath));
- }
+ [Theory]
+ [InlineData("Love Hina - Special.jpg", false)]
+ [InlineData("folder.jpg", true)]
+ [InlineData("DearS_v01_cover.jpg", true)]
+ [InlineData("DearS_v01_covers.jpg", false)]
+ [InlineData("!cover.jpg", true)]
+ [InlineData("cover.jpg", true)]
+ [InlineData("cover.png", true)]
+ [InlineData("ch1/cover.png", true)]
+ [InlineData("ch1/backcover.png", false)]
+ [InlineData("backcover.png", false)]
+ [InlineData("back_cover.png", false)]
+ public void IsCoverImageTest(string inputPath, bool expected)
+ {
+ Assert.Equal(expected, IsCoverImage(inputPath));
+ }
- [Theory]
- [InlineData("__MACOSX/Love Hina - Special.jpg", true)]
- [InlineData("TEST/Love Hina - Special.jpg", false)]
- [InlineData("__macosx/Love Hina/", false)]
- [InlineData("MACOSX/Love Hina/", false)]
- [InlineData("._Love Hina/Love Hina/", true)]
- [InlineData("@Recently-Snapshot/Love Hina/", true)]
- [InlineData("@recycle/Love Hina/", true)]
- [InlineData("E:/Test/__MACOSX/Love Hina/", true)]
- public void HasBlacklistedFolderInPathTest(string inputPath, bool expected)
- {
- Assert.Equal(expected, HasBlacklistedFolderInPath(inputPath));
- }
+ [Theory]
+ [InlineData("__MACOSX/Love Hina - Special.jpg", true)]
+ [InlineData("TEST/Love Hina - Special.jpg", false)]
+ [InlineData("__macosx/Love Hina/", false)]
+ [InlineData("MACOSX/Love Hina/", false)]
+ [InlineData("._Love Hina/Love Hina/", true)]
+ [InlineData("@Recently-Snapshot/Love Hina/", true)]
+ [InlineData("@recycle/Love Hina/", true)]
+ [InlineData("E:/Test/__MACOSX/Love Hina/", true)]
+ public void HasBlacklistedFolderInPathTest(string inputPath, bool expected)
+ {
+ Assert.Equal(expected, HasBlacklistedFolderInPath(inputPath));
+ }
- [Theory]
- [InlineData("/manga/1/1/1", "/manga/1/1/1")]
- [InlineData("/manga/1/1/1.jpg", "/manga/1/1/1.jpg")]
- [InlineData(@"/manga/1/1\1.jpg", @"/manga/1/1/1.jpg")]
- [InlineData("/manga/1/1//1", "/manga/1/1/1")]
- [InlineData("/manga/1\\1\\1", "/manga/1/1/1")]
- [InlineData("C:/manga/1\\1\\1.jpg", "C:/manga/1/1/1.jpg")]
- public void NormalizePathTest(string inputPath, string expected)
- {
- Assert.Equal(expected, NormalizePath(inputPath));
- }
+ [Theory]
+ [InlineData("/manga/1/1/1", "/manga/1/1/1")]
+ [InlineData("/manga/1/1/1.jpg", "/manga/1/1/1.jpg")]
+ [InlineData(@"/manga/1/1\1.jpg", @"/manga/1/1/1.jpg")]
+ [InlineData("/manga/1/1//1", "/manga/1/1/1")]
+ [InlineData("/manga/1\\1\\1", "/manga/1/1/1")]
+ [InlineData("C:/manga/1\\1\\1.jpg", "C:/manga/1/1/1.jpg")]
+ public void NormalizePathTest(string inputPath, string expected)
+ {
+ Assert.Equal(expected, NormalizePath(inputPath));
+ }
+
+ [Theory]
+ [InlineData("The quick brown fox jumps over the lazy dog")]
+ [InlineData("(The quick brown fox jumps over the lazy dog)")]
+ [InlineData("()The quick brown fox jumps over the lazy dog")]
+ [InlineData("The ()quick brown fox jumps over the lazy dog")]
+ [InlineData("The (quick (brown)) fox jumps over the lazy dog")]
+ [InlineData("The (quick (brown) fox jumps over the lazy dog)")]
+ public void BalancedParenTestMatches(string input)
+ {
+ Assert.Matches($@"^{BalancedParen}$", input);
+ }
+
+ [Theory]
+ [InlineData("(The quick brown fox jumps over the lazy dog")]
+ [InlineData("The quick brown fox jumps over the lazy dog)")]
+ [InlineData("The )(quick brown fox jumps over the lazy dog")]
+ [InlineData("The quick (brown)) fox jumps over the lazy dog")]
+ [InlineData("The quick (brown) fox jumps over the lazy dog)")]
+ [InlineData("(The ))(quick (brown) fox jumps over the lazy dog")]
+ public void BalancedParenTestDoesNotMatch(string input)
+ {
+ Assert.DoesNotMatch($@"^{BalancedParen}$", input);
+ }
+
+ [Theory]
+ [InlineData("The quick brown fox jumps over the lazy dog")]
+ [InlineData("[The quick brown fox jumps over the lazy dog]")]
+ [InlineData("[]The quick brown fox jumps over the lazy dog")]
+ [InlineData("The []quick brown fox jumps over the lazy dog")]
+ [InlineData("The [quick [brown]] fox jumps over the lazy dog")]
+ [InlineData("The [quick [brown] fox jumps over the lazy dog]")]
+ public void BalancedBrackTestMatches(string input)
+ {
+ Assert.Matches($@"^{BalancedBrack}$", input);
+ }
+
+ [Theory]
+ [InlineData("[The quick brown fox jumps over the lazy dog")]
+ [InlineData("The quick brown fox jumps over the lazy dog]")]
+ [InlineData("The ][quick brown fox jumps over the lazy dog")]
+ [InlineData("The quick [brown]] fox jumps over the lazy dog")]
+ [InlineData("The quick [brown] fox jumps over the lazy dog]")]
+ [InlineData("[The ]][quick [brown] fox jumps over the lazy dog")]
+ public void BalancedBrackTestDoesNotMatch(string input)
+ {
+ Assert.DoesNotMatch($@"^{BalancedBrack}$", input);
}
}
diff --git a/API.Tests/Repository/SeriesRepositoryTests.cs b/API.Tests/Repository/SeriesRepositoryTests.cs
index 65491d333..fe285641e 100644
--- a/API.Tests/Repository/SeriesRepositoryTests.cs
+++ b/API.Tests/Repository/SeriesRepositoryTests.cs
@@ -140,12 +140,12 @@ public class SeriesRepositoryTests
[InlineData("Heion Sedai no Idaten-tachi", "", MangaFormat.Archive, "The Idaten Deities Know Only Peace")] // Matching on localized name in DB
[InlineData("Heion Sedai no Idaten-tachi", "", MangaFormat.Pdf, null)]
- public async Task GetFullSeriesByAnyName_Should(string seriesName, string localizedName, string? expected)
+ public async Task GetFullSeriesByAnyName_Should(string seriesName, MangaFormat format, string localizedName, string? expected)
{
var firstSeries = await _unitOfWork.SeriesRepository.GetSeriesByIdAsync(1);
var series =
await _unitOfWork.SeriesRepository.GetFullSeriesByAnyName(seriesName, localizedName,
- 1, MangaFormat.Unknown);
+ 1, format);
if (expected == null)
{
Assert.Null(series);
@@ -157,4 +157,6 @@ public class SeriesRepositoryTests
}
}
+
+ //public async Task
}
diff --git a/API.Tests/Services/ArchiveServiceTests.cs b/API.Tests/Services/ArchiveServiceTests.cs
index 2521d17af..f399cb790 100644
--- a/API.Tests/Services/ArchiveServiceTests.cs
+++ b/API.Tests/Services/ArchiveServiceTests.cs
@@ -14,317 +14,347 @@ using NSubstitute.Extensions;
using Xunit;
using Xunit.Abstractions;
-namespace API.Tests.Services
+namespace API.Tests.Services;
+
+public class ArchiveServiceTests
{
- public class ArchiveServiceTests
+ private readonly ITestOutputHelper _testOutputHelper;
+ private readonly ArchiveService _archiveService;
+ private readonly ILogger _logger = Substitute.For>();
+ private readonly ILogger _directoryServiceLogger = Substitute.For>();
+ private readonly IDirectoryService _directoryService = new DirectoryService(Substitute.For>(), new FileSystem());
+
+ public ArchiveServiceTests(ITestOutputHelper testOutputHelper)
{
- private readonly ITestOutputHelper _testOutputHelper;
- private readonly ArchiveService _archiveService;
- private readonly ILogger _logger = Substitute.For>();
- private readonly ILogger _directoryServiceLogger = Substitute.For>();
- private readonly IDirectoryService _directoryService = new DirectoryService(Substitute.For>(), new FileSystem());
-
- public ArchiveServiceTests(ITestOutputHelper testOutputHelper)
- {
- _testOutputHelper = testOutputHelper;
- _archiveService = new ArchiveService(_logger, _directoryService, new ImageService(Substitute.For>(), _directoryService));
- }
-
- [Theory]
- [InlineData("flat file.zip", false)]
- [InlineData("file in folder in folder.zip", true)]
- [InlineData("file in folder.zip", true)]
- [InlineData("file in folder_alt.zip", true)]
- public void ArchiveNeedsFlatteningTest(string archivePath, bool expected)
- {
- var testDirectory = Path.Join(Directory.GetCurrentDirectory(), "../../../Services/Test Data/ArchiveService/Archives");
- var file = Path.Join(testDirectory, archivePath);
- using ZipArchive archive = ZipFile.OpenRead(file);
- Assert.Equal(expected, _archiveService.ArchiveNeedsFlattening(archive));
- }
-
- [Theory]
- [InlineData("non existent file.zip", false)]
- [InlineData("winrar.rar", true)]
- [InlineData("empty.zip", true)]
- [InlineData("flat file.zip", true)]
- [InlineData("file in folder in folder.zip", true)]
- [InlineData("file in folder.zip", true)]
- [InlineData("file in folder_alt.zip", true)]
- public void IsValidArchiveTest(string archivePath, bool expected)
- {
- var testDirectory = Path.Join(Directory.GetCurrentDirectory(), "../../../Services/Test Data/ArchiveService/Archives");
- Assert.Equal(expected, _archiveService.IsValidArchive(Path.Join(testDirectory, archivePath)));
- }
-
- [Theory]
- [InlineData("non existent file.zip", 0)]
- [InlineData("winrar.rar", 0)]
- [InlineData("empty.zip", 0)]
- [InlineData("flat file.zip", 1)]
- [InlineData("file in folder in folder.zip", 1)]
- [InlineData("file in folder.zip", 1)]
- [InlineData("file in folder_alt.zip", 1)]
- [InlineData("macos_none.zip", 0)]
- [InlineData("macos_one.zip", 1)]
- [InlineData("macos_native.zip", 21)]
- [InlineData("macos_withdotunder_one.zip", 1)]
- public void GetNumberOfPagesFromArchiveTest(string archivePath, int expected)
- {
- var testDirectory = Path.Join(Directory.GetCurrentDirectory(), "../../../Services/Test Data/ArchiveService/Archives");
- var sw = Stopwatch.StartNew();
- Assert.Equal(expected, _archiveService.GetNumberOfPagesFromArchive(Path.Join(testDirectory, archivePath)));
- _testOutputHelper.WriteLine($"Processed Original in {sw.ElapsedMilliseconds} ms");
- }
-
-
-
- [Theory]
- [InlineData("non existent file.zip", ArchiveLibrary.NotSupported)]
- [InlineData("winrar.rar", ArchiveLibrary.SharpCompress)]
- [InlineData("empty.zip", ArchiveLibrary.Default)]
- [InlineData("flat file.zip", ArchiveLibrary.Default)]
- [InlineData("file in folder in folder.zip", ArchiveLibrary.Default)]
- [InlineData("file in folder.zip", ArchiveLibrary.Default)]
- [InlineData("file in folder_alt.zip", ArchiveLibrary.Default)]
- public void CanOpenArchive(string archivePath, ArchiveLibrary expected)
- {
- var sw = Stopwatch.StartNew();
- var testDirectory = Path.Join(Directory.GetCurrentDirectory(), "../../../Services/Test Data/ArchiveService/Archives");
-
- Assert.Equal(expected, _archiveService.CanOpen(Path.Join(testDirectory, archivePath)));
- _testOutputHelper.WriteLine($"Processed Original in {sw.ElapsedMilliseconds} ms");
- }
-
-
- [Theory]
- [InlineData("non existent file.zip", 0)]
- [InlineData("winrar.rar", 0)]
- [InlineData("empty.zip", 0)]
- [InlineData("flat file.zip", 1)]
- [InlineData("file in folder in folder.zip", 1)]
- [InlineData("file in folder.zip", 1)]
- [InlineData("file in folder_alt.zip", 1)]
- public void CanExtractArchive(string archivePath, int expectedFileCount)
- {
-
- var testDirectory = Path.Join(Directory.GetCurrentDirectory(), "../../../Services/Test Data/ArchiveService/Archives");
- var extractDirectory = Path.Join(Directory.GetCurrentDirectory(), "../../../Services/Test Data/ArchiveService/Archives/Extraction");
-
- _directoryService.ClearAndDeleteDirectory(extractDirectory);
-
- var sw = Stopwatch.StartNew();
- _archiveService.ExtractArchive(Path.Join(testDirectory, archivePath), extractDirectory);
- var di1 = new DirectoryInfo(extractDirectory);
- Assert.Equal(expectedFileCount, di1.Exists ? _directoryService.GetFiles(extractDirectory, searchOption:SearchOption.AllDirectories).Count() : 0);
- _testOutputHelper.WriteLine($"Processed in {sw.ElapsedMilliseconds} ms");
-
- _directoryService.ClearAndDeleteDirectory(extractDirectory);
- }
-
-
- [Theory]
- [InlineData(new [] {"folder.jpg"}, "folder.jpg")]
- [InlineData(new [] {"vol1/"}, "")]
- [InlineData(new [] {"folder.jpg", "vol1/folder.jpg"}, "folder.jpg")]
- [InlineData(new [] {"cover.jpg", "vol1/folder.jpg"}, "cover.jpg")]
- [InlineData(new [] {"__MACOSX/cover.jpg", "vol1/page 01.jpg"}, "")]
- [InlineData(new [] {"Akame ga KILL! ZERO - c055 (v10) - p000 [Digital] [LuCaZ].jpg", "Akame ga KILL! ZERO - c055 (v10) - p000 [Digital] [LuCaZ].jpg", "Akame ga KILL! ZERO - c060 (v10) - p200 [Digital] [LuCaZ].jpg", "folder.jpg"}, "folder.jpg")]
- public void FindFolderEntry(string[] files, string expected)
- {
- var foundFile = ArchiveService.FindFolderEntry(files);
- Assert.Equal(expected, string.IsNullOrEmpty(foundFile) ? "" : foundFile);
- }
-
- [Theory]
- [InlineData(new [] {"folder.jpg"}, "folder.jpg")]
- [InlineData(new [] {"vol1/"}, "")]
- [InlineData(new [] {"folder.jpg", "vol1/folder.jpg"}, "folder.jpg")]
- [InlineData(new [] {"cover.jpg", "vol1/folder.jpg"}, "cover.jpg")]
- [InlineData(new [] {"page 2.jpg", "page 10.jpg"}, "page 2.jpg")]
- [InlineData(new [] {"__MACOSX/cover.jpg", "vol1/page 01.jpg"}, "vol1/page 01.jpg")]
- [InlineData(new [] {"Akame ga KILL! ZERO - c055 (v10) - p000 [Digital] [LuCaZ].jpg", "Akame ga KILL! ZERO - c055 (v10) - p000 [Digital] [LuCaZ].jpg", "Akame ga KILL! ZERO - c060 (v10) - p200 [Digital] [LuCaZ].jpg", "folder.jpg"}, "Akame ga KILL! ZERO - c055 (v10) - p000 [Digital] [LuCaZ].jpg")]
- [InlineData(new [] {"001.jpg", "001 - chapter 1/001.jpg"}, "001.jpg")]
- [InlineData(new [] {"chapter 1/001.jpg", "chapter 2/002.jpg", "somefile.jpg"}, "somefile.jpg")]
- public void FindFirstEntry(string[] files, string expected)
- {
- var foundFile = ArchiveService.FirstFileEntry(files, string.Empty);
- Assert.Equal(expected, string.IsNullOrEmpty(foundFile) ? "" : foundFile);
- }
-
-
- [Theory]
- [InlineData("v10.cbz", "v10.expected.png")]
- [InlineData("v10 - with folder.cbz", "v10 - with folder.expected.png")]
- [InlineData("v10 - nested folder.cbz", "v10 - nested folder.expected.png")]
- [InlineData("macos_native.zip", "macos_native.png")]
- [InlineData("v10 - duplicate covers.cbz", "v10 - duplicate covers.expected.png")]
- [InlineData("sorting.zip", "sorting.expected.png")]
- [InlineData("test.zip", "test.expected.jpg")]
- public void GetCoverImage_Default_Test(string inputFile, string expectedOutputFile)
- {
- var ds = Substitute.For(_directoryServiceLogger, new FileSystem());
- var imageService = new ImageService(Substitute.For>(), ds);
- var archiveService = Substitute.For(_logger, ds, imageService);
-
- var testDirectory = Path.GetFullPath(Path.Join(Directory.GetCurrentDirectory(), "../../../Services/Test Data/ArchiveService/CoverImages"));
- var expectedBytes = Image.Thumbnail(Path.Join(testDirectory, expectedOutputFile), 320).WriteToBuffer(".png");
-
- archiveService.Configure().CanOpen(Path.Join(testDirectory, inputFile)).Returns(ArchiveLibrary.Default);
-
- var outputDir = Path.Join(testDirectory, "output");
- _directoryService.ClearDirectory(outputDir);
- _directoryService.ExistOrCreate(outputDir);
-
- var coverImagePath = archiveService.GetCoverImage(Path.Join(testDirectory, inputFile),
- Path.GetFileNameWithoutExtension(inputFile) + "_output", outputDir);
- var actual = File.ReadAllBytes(Path.Join(outputDir, coverImagePath));
-
-
- Assert.Equal(expectedBytes, actual);
- _directoryService.ClearAndDeleteDirectory(outputDir);
- }
-
-
- [Theory]
- [InlineData("v10.cbz", "v10.expected.png")]
- [InlineData("v10 - with folder.cbz", "v10 - with folder.expected.png")]
- [InlineData("v10 - nested folder.cbz", "v10 - nested folder.expected.png")]
- [InlineData("macos_native.zip", "macos_native.png")]
- [InlineData("v10 - duplicate covers.cbz", "v10 - duplicate covers.expected.png")]
- [InlineData("sorting.zip", "sorting.expected.png")]
- public void GetCoverImage_SharpCompress_Test(string inputFile, string expectedOutputFile)
- {
- var imageService = new ImageService(Substitute.For>(), _directoryService);
- var archiveService = Substitute.For(_logger,
- new DirectoryService(_directoryServiceLogger, new FileSystem()), imageService);
- var testDirectory = API.Services.Tasks.Scanner.Parser.Parser.NormalizePath(Path.GetFullPath(Path.Join(Directory.GetCurrentDirectory(), "../../../Services/Test Data/ArchiveService/CoverImages")));
-
- var outputDir = Path.Join(testDirectory, "output");
- _directoryService.ClearDirectory(outputDir);
- _directoryService.ExistOrCreate(outputDir);
-
- archiveService.Configure().CanOpen(Path.Join(testDirectory, inputFile)).Returns(ArchiveLibrary.SharpCompress);
- var coverOutputFile = archiveService.GetCoverImage(Path.Join(testDirectory, inputFile),
- Path.GetFileNameWithoutExtension(inputFile), outputDir);
- var actualBytes = File.ReadAllBytes(Path.Join(outputDir, coverOutputFile));
- var expectedBytes = File.ReadAllBytes(Path.Join(testDirectory, expectedOutputFile));
- Assert.Equal(expectedBytes, actualBytes);
-
- _directoryService.ClearAndDeleteDirectory(outputDir);
- }
-
- [Theory]
- [InlineData("Archives/macos_native.zip")]
- [InlineData("Formats/One File with DB_Supported.zip")]
- public void CanParseCoverImage(string inputFile)
- {
- var imageService = Substitute.For();
- imageService.WriteCoverThumbnail(Arg.Any(), Arg.Any(), Arg.Any()).Returns(x => "cover.jpg");
- var archiveService = new ArchiveService(_logger, _directoryService, imageService);
- var testDirectory = Path.Join(Directory.GetCurrentDirectory(), "../../../Services/Test Data/ArchiveService/");
- var inputPath = Path.GetFullPath(Path.Join(testDirectory, inputFile));
- var outputPath = Path.Join(testDirectory, Path.GetFileNameWithoutExtension(inputFile) + "_output");
- new DirectoryInfo(outputPath).Create();
- var expectedImage = archiveService.GetCoverImage(inputPath, inputFile, outputPath);
- Assert.Equal("cover.jpg", expectedImage);
- new DirectoryInfo(outputPath).Delete();
- }
-
- #region ShouldHaveComicInfo
-
- [Fact]
- public void ShouldHaveComicInfo()
- {
- var testDirectory = Path.Join(Directory.GetCurrentDirectory(), "../../../Services/Test Data/ArchiveService/ComicInfos");
- var archive = Path.Join(testDirectory, "ComicInfo.zip");
- const string summaryInfo = "By all counts, Ryouta Sakamoto is a loser when he's not holed up in his room, bombing things into oblivion in his favorite online action RPG. But his very own uneventful life is blown to pieces when he's abducted and taken to an uninhabited island, where he soon learns the hard way that he's being pitted against others just like him in a explosives-riddled death match! How could this be happening? Who's putting them up to this? And why!? The name, not to mention the objective, of this very real survival game is eerily familiar to Ryouta, who has mastered its virtual counterpart-BTOOOM! Can Ryouta still come out on top when he's playing for his life!?";
-
- var comicInfo = _archiveService.GetComicInfo(archive);
- Assert.NotNull(comicInfo);
- Assert.Equal(summaryInfo, comicInfo.Summary);
- }
-
- [Fact]
- public void ShouldHaveComicInfo_WithAuthors()
- {
- var testDirectory = Path.Join(Directory.GetCurrentDirectory(), "../../../Services/Test Data/ArchiveService/ComicInfos");
- var archive = Path.Join(testDirectory, "ComicInfo_authors.zip");
-
- var comicInfo = _archiveService.GetComicInfo(archive);
- Assert.NotNull(comicInfo);
- Assert.Equal("Junya Inoue", comicInfo.Writer);
- }
-
- [Fact]
- public void ShouldHaveComicInfo_TopLevelFileOnly()
- {
- var testDirectory = Path.Join(Directory.GetCurrentDirectory(), "../../../Services/Test Data/ArchiveService/ComicInfos");
- var archive = Path.Join(testDirectory, "ComicInfo_duplicateInfos.zip");
-
- var comicInfo = _archiveService.GetComicInfo(archive);
- Assert.NotNull(comicInfo);
- Assert.Equal("BTOOOM!", comicInfo.Series);
- }
-
- #endregion
-
- #region CanParseComicInfo
-
- [Fact]
- public void CanParseComicInfo()
- {
- var testDirectory = Path.Join(Directory.GetCurrentDirectory(), "../../../Services/Test Data/ArchiveService/ComicInfos");
- var archive = Path.Join(testDirectory, "ComicInfo.zip");
- var actual = _archiveService.GetComicInfo(archive);
- var expected = new ComicInfo()
- {
- Publisher = "Yen Press",
- Genre = "Manga, Movies & TV",
- Summary =
- "By all counts, Ryouta Sakamoto is a loser when he's not holed up in his room, bombing things into oblivion in his favorite online action RPG. But his very own uneventful life is blown to pieces when he's abducted and taken to an uninhabited island, where he soon learns the hard way that he's being pitted against others just like him in a explosives-riddled death match! How could this be happening? Who's putting them up to this? And why!? The name, not to mention the objective, of this very real survival game is eerily familiar to Ryouta, who has mastered its virtual counterpart-BTOOOM! Can Ryouta still come out on top when he's playing for his life!?",
- PageCount = 194,
- LanguageISO = "en",
- Notes = "Scraped metadata from Comixology [CMXDB450184]",
- Series = "BTOOOM!",
- Title = "v01",
- Web = "https://www.comixology.com/BTOOOM/digital-comic/450184"
- };
-
- Assert.NotStrictEqual(expected, actual);
- }
-
- #endregion
-
- #region FindCoverImageFilename
-
- [Theory]
- [InlineData(new string[] {}, "", null)]
- [InlineData(new [] {"001.jpg", "002.jpg"}, "Test.zip", "001.jpg")]
- [InlineData(new [] {"001.jpg", "!002.jpg"}, "Test.zip", "!002.jpg")]
- [InlineData(new [] {"001.jpg", "!001.jpg"}, "Test.zip", "!001.jpg")]
- [InlineData(new [] {"001.jpg", "cover.jpg"}, "Test.zip", "cover.jpg")]
- [InlineData(new [] {"001.jpg", "Chapter 20/cover.jpg", "Chapter 21/0001.jpg"}, "Test.zip", "Chapter 20/cover.jpg")]
- [InlineData(new [] {"._/001.jpg", "._/cover.jpg", "010.jpg"}, "Test.zip", "010.jpg")]
- [InlineData(new [] {"001.txt", "002.txt", "a.jpg"}, "Test.zip", "a.jpg")]
- public void FindCoverImageFilename(string[] filenames, string archiveName, string expected)
- {
- Assert.Equal(expected, ArchiveService.FindCoverImageFilename(archiveName, filenames));
- }
-
-
- #endregion
-
- #region CreateZipForDownload
-
- //[Fact]
- public void CreateZipForDownloadTest()
- {
- var fileSystem = new MockFileSystem();
- var ds = new DirectoryService(Substitute.For>(), fileSystem);
- //_archiveService.CreateZipForDownload(new []{}, outputDirectory)
- }
-
- #endregion
+ _testOutputHelper = testOutputHelper;
+ _archiveService = new ArchiveService(_logger, _directoryService, new ImageService(Substitute.For>(), _directoryService));
}
+
+ [Theory]
+ [InlineData("flat file.zip", false)]
+ [InlineData("file in folder in folder.zip", true)]
+ [InlineData("file in folder.zip", true)]
+ [InlineData("file in folder_alt.zip", true)]
+ public void ArchiveNeedsFlatteningTest(string archivePath, bool expected)
+ {
+ var testDirectory = Path.Join(Directory.GetCurrentDirectory(), "../../../Services/Test Data/ArchiveService/Archives");
+ var file = Path.Join(testDirectory, archivePath);
+ using var archive = ZipFile.OpenRead(file);
+ Assert.Equal(expected, _archiveService.ArchiveNeedsFlattening(archive));
+ }
+
+ [Theory]
+ [InlineData("non existent file.zip", false)]
+ [InlineData("winrar.rar", true)]
+ [InlineData("empty.zip", true)]
+ [InlineData("flat file.zip", true)]
+ [InlineData("file in folder in folder.zip", true)]
+ [InlineData("file in folder.zip", true)]
+ [InlineData("file in folder_alt.zip", true)]
+ public void IsValidArchiveTest(string archivePath, bool expected)
+ {
+ var testDirectory = Path.Join(Directory.GetCurrentDirectory(), "../../../Services/Test Data/ArchiveService/Archives");
+ Assert.Equal(expected, _archiveService.IsValidArchive(Path.Join(testDirectory, archivePath)));
+ }
+
+ [Theory]
+ [InlineData("non existent file.zip", 0)]
+ [InlineData("winrar.rar", 0)]
+ [InlineData("empty.zip", 0)]
+ [InlineData("flat file.zip", 1)]
+ [InlineData("file in folder in folder.zip", 1)]
+ [InlineData("file in folder.zip", 1)]
+ [InlineData("file in folder_alt.zip", 1)]
+ [InlineData("macos_none.zip", 0)]
+ [InlineData("macos_one.zip", 1)]
+ [InlineData("macos_native.zip", 21)]
+ [InlineData("macos_withdotunder_one.zip", 1)]
+ public void GetNumberOfPagesFromArchiveTest(string archivePath, int expected)
+ {
+ var testDirectory = Path.Join(Directory.GetCurrentDirectory(), "../../../Services/Test Data/ArchiveService/Archives");
+ var sw = Stopwatch.StartNew();
+ Assert.Equal(expected, _archiveService.GetNumberOfPagesFromArchive(Path.Join(testDirectory, archivePath)));
+ _testOutputHelper.WriteLine($"Processed Original in {sw.ElapsedMilliseconds} ms");
+ }
+
+
+
+ [Theory]
+ [InlineData("non existent file.zip", ArchiveLibrary.NotSupported)]
+ [InlineData("winrar.rar", ArchiveLibrary.SharpCompress)]
+ [InlineData("empty.zip", ArchiveLibrary.Default)]
+ [InlineData("flat file.zip", ArchiveLibrary.Default)]
+ [InlineData("file in folder in folder.zip", ArchiveLibrary.Default)]
+ [InlineData("file in folder.zip", ArchiveLibrary.Default)]
+ [InlineData("file in folder_alt.zip", ArchiveLibrary.Default)]
+ public void CanOpenArchive(string archivePath, ArchiveLibrary expected)
+ {
+ var sw = Stopwatch.StartNew();
+ var testDirectory = Path.Join(Directory.GetCurrentDirectory(), "../../../Services/Test Data/ArchiveService/Archives");
+
+ Assert.Equal(expected, _archiveService.CanOpen(Path.Join(testDirectory, archivePath)));
+ _testOutputHelper.WriteLine($"Processed Original in {sw.ElapsedMilliseconds} ms");
+ }
+
+
+ [Theory]
+ [InlineData("non existent file.zip", 0)]
+ [InlineData("winrar.rar", 0)]
+ [InlineData("empty.zip", 0)]
+ [InlineData("flat file.zip", 1)]
+ [InlineData("file in folder in folder.zip", 1)]
+ [InlineData("file in folder.zip", 1)]
+ [InlineData("file in folder_alt.zip", 1)]
+ public void CanExtractArchive(string archivePath, int expectedFileCount)
+ {
+
+ var testDirectory = Path.Join(Directory.GetCurrentDirectory(), "../../../Services/Test Data/ArchiveService/Archives");
+ var extractDirectory = Path.Join(Directory.GetCurrentDirectory(), "../../../Services/Test Data/ArchiveService/Archives/Extraction");
+
+ _directoryService.ClearAndDeleteDirectory(extractDirectory);
+
+ var sw = Stopwatch.StartNew();
+ _archiveService.ExtractArchive(Path.Join(testDirectory, archivePath), extractDirectory);
+ var di1 = new DirectoryInfo(extractDirectory);
+ Assert.Equal(expectedFileCount, di1.Exists ? _directoryService.GetFiles(extractDirectory, searchOption:SearchOption.AllDirectories).Count() : 0);
+ _testOutputHelper.WriteLine($"Processed in {sw.ElapsedMilliseconds} ms");
+
+ _directoryService.ClearAndDeleteDirectory(extractDirectory);
+ }
+
+
+ [Theory]
+ [InlineData(new [] {"folder.jpg"}, "folder.jpg")]
+ [InlineData(new [] {"vol1/"}, "")]
+ [InlineData(new [] {"folder.jpg", "vol1/folder.jpg"}, "folder.jpg")]
+ [InlineData(new [] {"cover.jpg", "vol1/folder.jpg"}, "cover.jpg")]
+ [InlineData(new [] {"__MACOSX/cover.jpg", "vol1/page 01.jpg"}, "")]
+ [InlineData(new [] {"Akame ga KILL! ZERO - c055 (v10) - p000 [Digital] [LuCaZ].jpg", "Akame ga KILL! ZERO - c055 (v10) - p000 [Digital] [LuCaZ].jpg", "Akame ga KILL! ZERO - c060 (v10) - p200 [Digital] [LuCaZ].jpg", "folder.jpg"}, "folder.jpg")]
+ public void FindFolderEntry(string[] files, string expected)
+ {
+ var foundFile = ArchiveService.FindFolderEntry(files);
+ Assert.Equal(expected, string.IsNullOrEmpty(foundFile) ? "" : foundFile);
+ }
+
+ [Theory]
+ [InlineData(new [] {"folder.jpg"}, "folder.jpg")]
+ [InlineData(new [] {"vol1/"}, "")]
+ [InlineData(new [] {"folder.jpg", "vol1/folder.jpg"}, "folder.jpg")]
+ [InlineData(new [] {"cover.jpg", "vol1/folder.jpg"}, "cover.jpg")]
+ [InlineData(new [] {"page 2.jpg", "page 10.jpg"}, "page 2.jpg")]
+ [InlineData(new [] {"__MACOSX/cover.jpg", "vol1/page 01.jpg"}, "vol1/page 01.jpg")]
+ [InlineData(new [] {"Akame ga KILL! ZERO - c055 (v10) - p000 [Digital] [LuCaZ].jpg", "Akame ga KILL! ZERO - c055 (v10) - p000 [Digital] [LuCaZ].jpg", "Akame ga KILL! ZERO - c060 (v10) - p200 [Digital] [LuCaZ].jpg", "folder.jpg"}, "Akame ga KILL! ZERO - c055 (v10) - p000 [Digital] [LuCaZ].jpg")]
+ [InlineData(new [] {"001.jpg", "001 - chapter 1/001.jpg"}, "001.jpg")]
+ [InlineData(new [] {"chapter 1/001.jpg", "chapter 2/002.jpg", "somefile.jpg"}, "somefile.jpg")]
+ public void FindFirstEntry(string[] files, string expected)
+ {
+ var foundFile = ArchiveService.FirstFileEntry(files, string.Empty);
+ Assert.Equal(expected, string.IsNullOrEmpty(foundFile) ? "" : foundFile);
+ }
+
+
+ [Theory]
+ [InlineData("v10.cbz", "v10.expected.png")]
+ [InlineData("v10 - with folder.cbz", "v10 - with folder.expected.png")]
+ [InlineData("v10 - nested folder.cbz", "v10 - nested folder.expected.png")]
+ [InlineData("macos_native.zip", "macos_native.png")]
+ [InlineData("v10 - duplicate covers.cbz", "v10 - duplicate covers.expected.png")]
+ [InlineData("sorting.zip", "sorting.expected.png")]
+ [InlineData("test.zip", "test.expected.jpg")]
+ public void GetCoverImage_Default_Test(string inputFile, string expectedOutputFile)
+ {
+ var ds = Substitute.For(_directoryServiceLogger, new FileSystem());
+ var imageService = new ImageService(Substitute.For>(), ds);
+ var archiveService = Substitute.For(_logger, ds, imageService);
+
+ var testDirectory = Path.GetFullPath(Path.Join(Directory.GetCurrentDirectory(), "../../../Services/Test Data/ArchiveService/CoverImages"));
+ var expectedBytes = Image.Thumbnail(Path.Join(testDirectory, expectedOutputFile), 320).WriteToBuffer(".png");
+
+ archiveService.Configure().CanOpen(Path.Join(testDirectory, inputFile)).Returns(ArchiveLibrary.Default);
+
+ var outputDir = Path.Join(testDirectory, "output");
+ _directoryService.ClearDirectory(outputDir);
+ _directoryService.ExistOrCreate(outputDir);
+
+ var coverImagePath = archiveService.GetCoverImage(Path.Join(testDirectory, inputFile),
+ Path.GetFileNameWithoutExtension(inputFile) + "_output", outputDir);
+ var actual = File.ReadAllBytes(Path.Join(outputDir, coverImagePath));
+
+
+ Assert.Equal(expectedBytes, actual);
+ _directoryService.ClearAndDeleteDirectory(outputDir);
+ }
+
+
+ [Theory]
+ [InlineData("v10.cbz", "v10.expected.png")]
+ [InlineData("v10 - with folder.cbz", "v10 - with folder.expected.png")]
+ [InlineData("v10 - nested folder.cbz", "v10 - nested folder.expected.png")]
+ [InlineData("macos_native.zip", "macos_native.png")]
+ [InlineData("v10 - duplicate covers.cbz", "v10 - duplicate covers.expected.png")]
+ [InlineData("sorting.zip", "sorting.expected.png")]
+ public void GetCoverImage_SharpCompress_Test(string inputFile, string expectedOutputFile)
+ {
+ var imageService = new ImageService(Substitute.For>(), _directoryService);
+ var archiveService = Substitute.For(_logger,
+ new DirectoryService(_directoryServiceLogger, new FileSystem()), imageService);
+ var testDirectory = API.Services.Tasks.Scanner.Parser.Parser.NormalizePath(Path.GetFullPath(Path.Join(Directory.GetCurrentDirectory(), "../../../Services/Test Data/ArchiveService/CoverImages")));
+
+ var outputDir = Path.Join(testDirectory, "output");
+ _directoryService.ClearDirectory(outputDir);
+ _directoryService.ExistOrCreate(outputDir);
+
+ archiveService.Configure().CanOpen(Path.Join(testDirectory, inputFile)).Returns(ArchiveLibrary.SharpCompress);
+ var coverOutputFile = archiveService.GetCoverImage(Path.Join(testDirectory, inputFile),
+ Path.GetFileNameWithoutExtension(inputFile), outputDir);
+ var actualBytes = File.ReadAllBytes(Path.Join(outputDir, coverOutputFile));
+ var expectedBytes = File.ReadAllBytes(Path.Join(testDirectory, expectedOutputFile));
+ Assert.Equal(expectedBytes, actualBytes);
+
+ _directoryService.ClearAndDeleteDirectory(outputDir);
+ }
+
+ [Theory]
+ [InlineData("Archives/macos_native.zip")]
+ [InlineData("Formats/One File with DB_Supported.zip")]
+ public void CanParseCoverImage(string inputFile)
+ {
+ var imageService = Substitute.For();
+ imageService.WriteCoverThumbnail(Arg.Any(), Arg.Any(), Arg.Any()).Returns(x => "cover.jpg");
+ var archiveService = new ArchiveService(_logger, _directoryService, imageService);
+ var testDirectory = Path.Join(Directory.GetCurrentDirectory(), "../../../Services/Test Data/ArchiveService/");
+ var inputPath = Path.GetFullPath(Path.Join(testDirectory, inputFile));
+ var outputPath = Path.Join(testDirectory, Path.GetFileNameWithoutExtension(inputFile) + "_output");
+ new DirectoryInfo(outputPath).Create();
+ var expectedImage = archiveService.GetCoverImage(inputPath, inputFile, outputPath);
+ Assert.Equal("cover.jpg", expectedImage);
+ new DirectoryInfo(outputPath).Delete();
+ }
+
+ #region ShouldHaveComicInfo
+
+ [Fact]
+ public void ShouldHaveComicInfo()
+ {
+ var testDirectory = Path.Join(Directory.GetCurrentDirectory(), "../../../Services/Test Data/ArchiveService/ComicInfos");
+ var archive = Path.Join(testDirectory, "ComicInfo.zip");
+ const string summaryInfo = "By all counts, Ryouta Sakamoto is a loser when he's not holed up in his room, bombing things into oblivion in his favorite online action RPG. But his very own uneventful life is blown to pieces when he's abducted and taken to an uninhabited island, where he soon learns the hard way that he's being pitted against others just like him in a explosives-riddled death match! How could this be happening? Who's putting them up to this? And why!? The name, not to mention the objective, of this very real survival game is eerily familiar to Ryouta, who has mastered its virtual counterpart-BTOOOM! Can Ryouta still come out on top when he's playing for his life!?";
+
+ var comicInfo = _archiveService.GetComicInfo(archive);
+ Assert.NotNull(comicInfo);
+ Assert.Equal(summaryInfo, comicInfo.Summary);
+ }
+
+ [Fact]
+ public void ShouldHaveComicInfo_WithAuthors()
+ {
+ var testDirectory = Path.Join(Directory.GetCurrentDirectory(), "../../../Services/Test Data/ArchiveService/ComicInfos");
+ var archive = Path.Join(testDirectory, "ComicInfo_authors.zip");
+
+ var comicInfo = _archiveService.GetComicInfo(archive);
+ Assert.NotNull(comicInfo);
+ Assert.Equal("Junya Inoue", comicInfo.Writer);
+ }
+
+ [Theory]
+ [InlineData("ComicInfo_duplicateInfos.zip")]
+ [InlineData("ComicInfo_duplicateInfos_reversed.zip")]
+ [InlineData("ComicInfo_duplicateInfos.rar")]
+ public void ShouldHaveComicInfo_TopLevelFileOnly(string filename)
+ {
+ var testDirectory = Path.Join(Directory.GetCurrentDirectory(), "../../../Services/Test Data/ArchiveService/ComicInfos");
+ var archive = Path.Join(testDirectory, filename);
+
+ var comicInfo = _archiveService.GetComicInfo(archive);
+ Assert.NotNull(comicInfo);
+ Assert.Equal("BTOOOM!", comicInfo.Series);
+ }
+
+ [Fact]
+ public void ShouldHaveComicInfo_OutsideRoot()
+ {
+ var testDirectory = Path.Join(Directory.GetCurrentDirectory(), "../../../Services/Test Data/ArchiveService/ComicInfos");
+ var archive = Path.Join(testDirectory, "ComicInfo_outside_root.zip");
+
+ var comicInfo = _archiveService.GetComicInfo(archive);
+ Assert.NotNull(comicInfo);
+ Assert.Equal("BTOOOM! - Duplicate", comicInfo.Series);
+ }
+
+ #endregion
+
+ #region CanParseComicInfo
+
+ [Fact]
+ public void CanParseComicInfo()
+ {
+ var testDirectory = Path.Join(Directory.GetCurrentDirectory(), "../../../Services/Test Data/ArchiveService/ComicInfos");
+ var archive = Path.Join(testDirectory, "ComicInfo.zip");
+ var comicInfo = _archiveService.GetComicInfo(archive);
+
+ Assert.NotNull(comicInfo);
+ Assert.Equal("Yen Press", comicInfo.Publisher);
+ Assert.Equal("Manga, Movies & TV", comicInfo.Genre);
+ Assert.Equal("By all counts, Ryouta Sakamoto is a loser when he's not holed up in his room, bombing things into oblivion in his favorite online action RPG. But his very own uneventful life is blown to pieces when he's abducted and taken to an uninhabited island, where he soon learns the hard way that he's being pitted against others just like him in a explosives-riddled death match! How could this be happening? Who's putting them up to this? And why!? The name, not to mention the objective, of this very real survival game is eerily familiar to Ryouta, who has mastered its virtual counterpart-BTOOOM! Can Ryouta still come out on top when he's playing for his life!?",
+ comicInfo.Summary);
+ Assert.Equal(194, comicInfo.PageCount);
+ Assert.Equal("en", comicInfo.LanguageISO);
+ Assert.Equal("Scraped metadata from Comixology [CMXDB450184]", comicInfo.Notes);
+ Assert.Equal("BTOOOM!", comicInfo.Series);
+ Assert.Equal("v01", comicInfo.Title);
+ Assert.Equal("https://www.comixology.com/BTOOOM/digital-comic/450184", comicInfo.Web);
+ }
+
+ #endregion
+
+ #region CanParseComicInfo_DefaultNumberIsBlank
+
+ [Fact]
+ public void CanParseComicInfo_DefaultNumberIsBlank()
+ {
+ var testDirectory = Path.Join(Directory.GetCurrentDirectory(), "../../../Services/Test Data/ArchiveService/ComicInfos");
+ var archive = Path.Join(testDirectory, "ComicInfo2.zip");
+ var comicInfo = _archiveService.GetComicInfo(archive);
+
+ Assert.NotNull(comicInfo);
+ Assert.Equal("Hellboy", comicInfo.Series);
+ Assert.Equal("The Right Hand of Doom", comicInfo.Title);
+ Assert.Equal("", comicInfo.Number);
+ Assert.Equal(0, comicInfo.Count);
+ Assert.Equal("4", comicInfo.Volume);
+ }
+
+
+ #endregion
+
+ #region FindCoverImageFilename
+
+ [Theory]
+ [InlineData(new string[] {}, "", null)]
+ [InlineData(new [] {"001.jpg", "002.jpg"}, "Test.zip", "001.jpg")]
+ [InlineData(new [] {"001.jpg", "!002.jpg"}, "Test.zip", "!002.jpg")]
+ [InlineData(new [] {"001.jpg", "!001.jpg"}, "Test.zip", "!001.jpg")]
+ [InlineData(new [] {"001.jpg", "cover.jpg"}, "Test.zip", "cover.jpg")]
+ [InlineData(new [] {"001.jpg", "Chapter 20/cover.jpg", "Chapter 21/0001.jpg"}, "Test.zip", "Chapter 20/cover.jpg")]
+ [InlineData(new [] {"._/001.jpg", "._/cover.jpg", "010.jpg"}, "Test.zip", "010.jpg")]
+ [InlineData(new [] {"001.txt", "002.txt", "a.jpg"}, "Test.zip", "a.jpg")]
+ public void FindCoverImageFilename(string[] filenames, string archiveName, string expected)
+ {
+ Assert.Equal(expected, ArchiveService.FindCoverImageFilename(archiveName, filenames));
+ }
+
+
+ #endregion
+
+ #region CreateZipForDownload
+
+ //[Fact]
+ public void CreateZipForDownloadTest()
+ {
+ var fileSystem = new MockFileSystem();
+ var ds = new DirectoryService(Substitute.For>(), fileSystem);
+ //_archiveService.CreateZipForDownload(new []{}, outputDirectory)
+ }
+
+ #endregion
}
diff --git a/API.Tests/Services/BackupServiceTests.cs b/API.Tests/Services/BackupServiceTests.cs
index ad7f8b9f9..783e0b62d 100644
--- a/API.Tests/Services/BackupServiceTests.cs
+++ b/API.Tests/Services/BackupServiceTests.cs
@@ -135,17 +135,9 @@ public class BackupServiceTests
filesystem.AddFile($"{LogDirectory}kavita1.log", new MockFileData(""));
var ds = new DirectoryService(Substitute.For>(), filesystem);
- var inMemorySettings = new Dictionary {
- {"Logging:File:Path", "config/logs/kavita.log"},
- {"Logging:File:MaxRollingFiles", "0"},
- };
- IConfiguration configuration = new ConfigurationBuilder()
- .AddInMemoryCollection(inMemorySettings)
- .Build();
+ var backupService = new BackupService(_logger, _unitOfWork, ds, _messageHub);
- var backupService = new BackupService(_logger, _unitOfWork, ds, configuration, _messageHub);
-
- var backupLogFiles = backupService.GetLogFiles(0, LogDirectory).ToList();
+ var backupLogFiles = backupService.GetLogFiles(false).ToList();
Assert.Single(backupLogFiles);
Assert.Equal(API.Services.Tasks.Scanner.Parser.Parser.NormalizePath($"{LogDirectory}kavita.log"), API.Services.Tasks.Scanner.Parser.Parser.NormalizePath(backupLogFiles.First()));
}
@@ -155,20 +147,12 @@ public class BackupServiceTests
{
var filesystem = CreateFileSystem();
filesystem.AddFile($"{LogDirectory}kavita.log", new MockFileData(""));
- filesystem.AddFile($"{LogDirectory}kavita1.log", new MockFileData(""));
+ filesystem.AddFile($"{LogDirectory}kavita20200213.log", new MockFileData(""));
var ds = new DirectoryService(Substitute.For>(), filesystem);
- var inMemorySettings = new Dictionary {
- {"Logging:File:Path", "config/logs/kavita.log"},
- {"Logging:File:MaxRollingFiles", "1"},
- };
- IConfiguration configuration = new ConfigurationBuilder()
- .AddInMemoryCollection(inMemorySettings)
- .Build();
+ var backupService = new BackupService(_logger, _unitOfWork, ds, _messageHub);
- var backupService = new BackupService(_logger, _unitOfWork, ds, configuration, _messageHub);
-
- var backupLogFiles = backupService.GetLogFiles(1, LogDirectory).Select(API.Services.Tasks.Scanner.Parser.Parser.NormalizePath).ToList();
+ var backupLogFiles = backupService.GetLogFiles().Select(API.Services.Tasks.Scanner.Parser.Parser.NormalizePath).ToList();
Assert.NotEmpty(backupLogFiles.Where(file => file.Equals(API.Services.Tasks.Scanner.Parser.Parser.NormalizePath($"{LogDirectory}kavita.log")) || file.Equals(API.Services.Tasks.Scanner.Parser.Parser.NormalizePath($"{LogDirectory}kavita1.log"))));
}
diff --git a/API.Tests/Services/BookServiceTests.cs b/API.Tests/Services/BookServiceTests.cs
index f8b726ac5..38a5da896 100644
--- a/API.Tests/Services/BookServiceTests.cs
+++ b/API.Tests/Services/BookServiceTests.cs
@@ -5,54 +5,53 @@ using Microsoft.Extensions.Logging;
using NSubstitute;
using Xunit;
-namespace API.Tests.Services
+namespace API.Tests.Services;
+
+public class BookServiceTests
{
- public class BookServiceTests
+ private readonly IBookService _bookService;
+ private readonly ILogger _logger = Substitute.For>();
+
+ public BookServiceTests()
{
- private readonly IBookService _bookService;
- private readonly ILogger _logger = Substitute.For>();
-
- public BookServiceTests()
- {
- var directoryService = new DirectoryService(Substitute.For>(), new FileSystem());
- _bookService = new BookService(_logger, directoryService, new ImageService(Substitute.For>(), directoryService));
- }
-
- [Theory]
- [InlineData("The Golden Harpoon; Or, Lost Among the Floes A Story of the Whaling Grounds.epub", 16)]
- [InlineData("Non-existent file.epub", 0)]
- [InlineData("Non an ebub.pdf", 0)]
- [InlineData("test_ſ.pdf", 1)] // This is dependent on Docnet bug https://github.com/GowenGit/docnet/issues/80
- [InlineData("test.pdf", 1)]
- public void GetNumberOfPagesTest(string filePath, int expectedPages)
- {
- var testDirectory = Path.Join(Directory.GetCurrentDirectory(), "../../../Services/Test Data/BookService");
- Assert.Equal(expectedPages, _bookService.GetNumberOfPages(Path.Join(testDirectory, filePath)));
- }
-
- [Fact]
- public void ShouldHaveComicInfo()
- {
- var testDirectory = Path.Join(Directory.GetCurrentDirectory(), "../../../Services/Test Data/BookService");
- var archive = Path.Join(testDirectory, "The Golden Harpoon; Or, Lost Among the Floes A Story of the Whaling Grounds.epub");
- const string summaryInfo = "Book Description";
-
- var comicInfo = _bookService.GetComicInfo(archive);
- Assert.NotNull(comicInfo);
- Assert.Equal(summaryInfo, comicInfo.Summary);
- Assert.Equal("genre1, genre2", comicInfo.Genre);
- }
-
- [Fact]
- public void ShouldHaveComicInfo_WithAuthors()
- {
- var testDirectory = Path.Join(Directory.GetCurrentDirectory(), "../../../Services/Test Data/BookService");
- var archive = Path.Join(testDirectory, "The Golden Harpoon; Or, Lost Among the Floes A Story of the Whaling Grounds.epub");
-
- var comicInfo = _bookService.GetComicInfo(archive);
- Assert.NotNull(comicInfo);
- Assert.Equal("Roger Starbuck,Junya Inoue", comicInfo.Writer);
- }
-
+ var directoryService = new DirectoryService(Substitute.For>(), new FileSystem());
+ _bookService = new BookService(_logger, directoryService, new ImageService(Substitute.For>(), directoryService));
}
+
+ [Theory]
+ [InlineData("The Golden Harpoon; Or, Lost Among the Floes A Story of the Whaling Grounds.epub", 16)]
+ [InlineData("Non-existent file.epub", 0)]
+ [InlineData("Non an ebub.pdf", 0)]
+ [InlineData("test_ſ.pdf", 1)] // This is dependent on Docnet bug https://github.com/GowenGit/docnet/issues/80
+ [InlineData("test.pdf", 1)]
+ public void GetNumberOfPagesTest(string filePath, int expectedPages)
+ {
+ var testDirectory = Path.Join(Directory.GetCurrentDirectory(), "../../../Services/Test Data/BookService");
+ Assert.Equal(expectedPages, _bookService.GetNumberOfPages(Path.Join(testDirectory, filePath)));
+ }
+
+ [Fact]
+ public void ShouldHaveComicInfo()
+ {
+ var testDirectory = Path.Join(Directory.GetCurrentDirectory(), "../../../Services/Test Data/BookService");
+ var archive = Path.Join(testDirectory, "The Golden Harpoon; Or, Lost Among the Floes A Story of the Whaling Grounds.epub");
+ const string summaryInfo = "Book Description";
+
+ var comicInfo = _bookService.GetComicInfo(archive);
+ Assert.NotNull(comicInfo);
+ Assert.Equal(summaryInfo, comicInfo.Summary);
+ Assert.Equal("genre1, genre2", comicInfo.Genre);
+ }
+
+ [Fact]
+ public void ShouldHaveComicInfo_WithAuthors()
+ {
+ var testDirectory = Path.Join(Directory.GetCurrentDirectory(), "../../../Services/Test Data/BookService");
+ var archive = Path.Join(testDirectory, "The Golden Harpoon; Or, Lost Among the Floes A Story of the Whaling Grounds.epub");
+
+ var comicInfo = _bookService.GetComicInfo(archive);
+ Assert.NotNull(comicInfo);
+ Assert.Equal("Roger Starbuck,Junya Inoue", comicInfo.Writer);
+ }
+
}
diff --git a/API.Tests/Services/BookmarkServiceTests.cs b/API.Tests/Services/BookmarkServiceTests.cs
index 88f0fc587..97c07a281 100644
--- a/API.Tests/Services/BookmarkServiceTests.cs
+++ b/API.Tests/Services/BookmarkServiceTests.cs
@@ -410,7 +410,7 @@ public class BookmarkServiceTests
#region Misc
[Fact]
- public async Task ShouldNotDeleteBookmarkOnChapterDeletion()
+ public async Task ShouldNotDeleteBookmark_OnChapterDeletion()
{
var filesystem = CreateFileSystem();
filesystem.AddFile($"{CacheDirectory}1/0001.jpg", new MockFileData("123"));
@@ -462,8 +462,6 @@ public class BookmarkServiceTests
var ds = new DirectoryService(Substitute.For>(), filesystem);
- var bookmarkService = Create(ds);
- var user = await _unitOfWork.UserRepository.GetUserByIdAsync(1, AppUserIncludes.Bookmarks);
var vol = await _unitOfWork.VolumeRepository.GetVolumeAsync(1);
vol.Chapters = new List();
@@ -475,5 +473,72 @@ public class BookmarkServiceTests
Assert.NotNull(await _unitOfWork.UserRepository.GetBookmarkAsync(1));
}
+
+ [Fact]
+ public async Task ShouldNotDeleteBookmark_OnVolumeDeletion()
+ {
+ var filesystem = CreateFileSystem();
+ filesystem.AddFile($"{CacheDirectory}1/0001.jpg", new MockFileData("123"));
+ filesystem.AddFile($"{BookmarkDirectory}1/1/0001.jpg", new MockFileData("123"));
+
+ // Delete all Series to reset state
+ await ResetDB();
+ var series = new Series()
+ {
+ Name = "Test",
+ Library = new Library()
+ {
+ Name = "Test LIb",
+ Type = LibraryType.Manga,
+ },
+ Volumes = new List()
+ {
+ new Volume()
+ {
+ Chapters = new List()
+ {
+ new Chapter()
+ {
+
+ }
+ }
+ }
+ }
+ };
+
+ _context.Series.Add(series);
+
+
+ _context.AppUser.Add(new AppUser()
+ {
+ UserName = "Joe",
+ Bookmarks = new List()
+ {
+ new AppUserBookmark()
+ {
+ Page = 1,
+ ChapterId = 1,
+ FileName = $"1/1/0001.jpg",
+ SeriesId = 1,
+ VolumeId = 1
+ }
+ }
+ });
+
+ await _context.SaveChangesAsync();
+
+ var user = await _unitOfWork.UserRepository.GetUserByIdAsync(1, AppUserIncludes.Bookmarks);
+ Assert.NotEmpty(user.Bookmarks);
+
+ series.Volumes = new List();
+ _unitOfWork.SeriesRepository.Update(series);
+ await _unitOfWork.CommitAsync();
+
+
+ var ds = new DirectoryService(Substitute.For>(), filesystem);
+ Assert.Single(ds.GetFiles(BookmarkDirectory, searchOption:SearchOption.AllDirectories));
+ Assert.NotNull(await _unitOfWork.UserRepository.GetBookmarkAsync(1));
+ }
+
#endregion
}
diff --git a/API.Tests/Services/CacheServiceTests.cs b/API.Tests/Services/CacheServiceTests.cs
index a812e5bdd..e3be8dce5 100644
--- a/API.Tests/Services/CacheServiceTests.cs
+++ b/API.Tests/Services/CacheServiceTests.cs
@@ -20,501 +20,500 @@ using Microsoft.Extensions.Logging;
using NSubstitute;
using Xunit;
-namespace API.Tests.Services
+namespace API.Tests.Services;
+
+internal class MockReadingItemServiceForCacheService : IReadingItemService
{
- internal class MockReadingItemServiceForCacheService : IReadingItemService
+ private readonly DirectoryService _directoryService;
+
+ public MockReadingItemServiceForCacheService(DirectoryService directoryService)
{
- private readonly DirectoryService _directoryService;
-
- public MockReadingItemServiceForCacheService(DirectoryService directoryService)
- {
- _directoryService = directoryService;
- }
-
- public ComicInfo GetComicInfo(string filePath)
- {
- return null;
- }
-
- public int GetNumberOfPages(string filePath, MangaFormat format)
- {
- return 1;
- }
-
- public string GetCoverImage(string fileFilePath, string fileName, MangaFormat format)
- {
- return string.Empty;
- }
-
- public void Extract(string fileFilePath, string targetDirectory, MangaFormat format, int imageCount = 1)
- {
- throw new System.NotImplementedException();
- }
-
- public ParserInfo Parse(string path, string rootPath, LibraryType type)
- {
- throw new System.NotImplementedException();
- }
-
- public ParserInfo ParseFile(string path, string rootPath, LibraryType type)
- {
- throw new System.NotImplementedException();
- }
+ _directoryService = directoryService;
}
- public class CacheServiceTests
+
+ public ComicInfo GetComicInfo(string filePath)
{
- private readonly ILogger _logger = Substitute.For>();
- private readonly IUnitOfWork _unitOfWork;
- private readonly IHubContext _messageHub = Substitute.For>();
-
- private readonly DbConnection _connection;
- private readonly DataContext _context;
-
- private const string CacheDirectory = "C:/kavita/config/cache/";
- private const string CoverImageDirectory = "C:/kavita/config/covers/";
- private const string BackupDirectory = "C:/kavita/config/backups/";
- private const string DataDirectory = "C:/data/";
-
- public CacheServiceTests()
- {
- var contextOptions = new DbContextOptionsBuilder()
- .UseSqlite(CreateInMemoryDatabase())
- .Options;
- _connection = RelationalOptionsExtension.Extract(contextOptions).Connection;
-
- _context = new DataContext(contextOptions);
- Task.Run(SeedDb).GetAwaiter().GetResult();
-
- _unitOfWork = new UnitOfWork(_context, Substitute.For(), null);
- }
-
- #region Setup
-
- private static DbConnection CreateInMemoryDatabase()
- {
- var connection = new SqliteConnection("Filename=:memory:");
-
- connection.Open();
-
- return connection;
- }
-
- public void Dispose() => _connection.Dispose();
-
- private async Task SeedDb()
- {
- await _context.Database.MigrateAsync();
- var filesystem = CreateFileSystem();
-
- await Seed.SeedSettings(_context, new DirectoryService(Substitute.For>(), filesystem));
-
- var setting = await _context.ServerSetting.Where(s => s.Key == ServerSettingKey.CacheDirectory).SingleAsync();
- setting.Value = CacheDirectory;
-
- setting = await _context.ServerSetting.Where(s => s.Key == ServerSettingKey.BackupDirectory).SingleAsync();
- setting.Value = BackupDirectory;
-
- _context.ServerSetting.Update(setting);
-
- _context.Library.Add(new Library()
- {
- Name = "Manga",
- Folders = new List()
- {
- new FolderPath()
- {
- Path = "C:/data/"
- }
- }
- });
- return await _context.SaveChangesAsync() > 0;
- }
-
- private async Task ResetDB()
- {
- _context.Series.RemoveRange(_context.Series.ToList());
-
- await _context.SaveChangesAsync();
- }
-
- private static MockFileSystem CreateFileSystem()
- {
- var fileSystem = new MockFileSystem();
- fileSystem.Directory.SetCurrentDirectory("C:/kavita/");
- fileSystem.AddDirectory("C:/kavita/config/");
- fileSystem.AddDirectory(CacheDirectory);
- fileSystem.AddDirectory(CoverImageDirectory);
- fileSystem.AddDirectory(BackupDirectory);
- fileSystem.AddDirectory(DataDirectory);
-
- return fileSystem;
- }
-
- #endregion
-
- #region Ensure
-
- [Fact]
- public async Task Ensure_DirectoryAlreadyExists_DontExtractAnything()
- {
- var filesystem = CreateFileSystem();
- filesystem.AddFile($"{DataDirectory}Test v1.zip", new MockFileData(""));
- filesystem.AddDirectory($"{CacheDirectory}1/");
- var ds = new DirectoryService(Substitute.For>(), filesystem);
- var cleanupService = new CacheService(_logger, _unitOfWork, ds,
- new ReadingItemService(Substitute.For(),
- Substitute.For(), Substitute.For(), ds), Substitute.For());
-
- await ResetDB();
- var s = DbFactory.Series("Test");
- var v = DbFactory.Volume("1");
- var c = new Chapter()
- {
- Number = "1",
- Files = new List()
- {
- new MangaFile()
- {
- Format = MangaFormat.Archive,
- FilePath = $"{DataDirectory}Test v1.zip",
- }
- }
- };
- v.Chapters.Add(c);
- s.Volumes.Add(v);
- s.LibraryId = 1;
- _context.Series.Add(s);
-
- await _context.SaveChangesAsync();
-
- await cleanupService.Ensure(1);
- Assert.Empty(ds.GetFiles(filesystem.Path.Join(CacheDirectory, "1"), searchOption:SearchOption.AllDirectories));
- }
-
- // [Fact]
- // public async Task Ensure_DirectoryAlreadyExists_ExtractsImages()
- // {
- // // TODO: Figure out a way to test this
- // var filesystem = CreateFileSystem();
- // filesystem.AddFile($"{DataDirectory}Test v1.zip", new MockFileData(""));
- // filesystem.AddDirectory($"{CacheDirectory}1/");
- // var ds = new DirectoryService(Substitute.For>(), filesystem);
- // var archiveService = Substitute.For();
- // archiveService.ExtractArchive($"{DataDirectory}Test v1.zip",
- // filesystem.Path.Join(CacheDirectory, "1"));
- // var cleanupService = new CacheService(_logger, _unitOfWork, ds,
- // new ReadingItemService(archiveService, Substitute.For(), Substitute.For(), ds));
- //
- // await ResetDB();
- // var s = DbFactory.Series("Test");
- // var v = DbFactory.Volume("1");
- // var c = new Chapter()
- // {
- // Number = "1",
- // Files = new List()
- // {
- // new MangaFile()
- // {
- // Format = MangaFormat.Archive,
- // FilePath = $"{DataDirectory}Test v1.zip",
- // }
- // }
- // };
- // v.Chapters.Add(c);
- // s.Volumes.Add(v);
- // s.LibraryId = 1;
- // _context.Series.Add(s);
- //
- // await _context.SaveChangesAsync();
- //
- // await cleanupService.Ensure(1);
- // Assert.Empty(ds.GetFiles(filesystem.Path.Join(CacheDirectory, "1"), searchOption:SearchOption.AllDirectories));
- // }
-
-
- #endregion
-
- #region CleanupChapters
-
- [Fact]
- public void CleanupChapters_AllFilesShouldBeDeleted()
- {
- var filesystem = CreateFileSystem();
- filesystem.AddDirectory($"{CacheDirectory}1/");
- filesystem.AddFile($"{CacheDirectory}1/001.jpg", new MockFileData(""));
- filesystem.AddFile($"{CacheDirectory}1/002.jpg", new MockFileData(""));
- filesystem.AddFile($"{CacheDirectory}3/003.jpg", new MockFileData(""));
- var ds = new DirectoryService(Substitute.For>(), filesystem);
- var cleanupService = new CacheService(_logger, _unitOfWork, ds,
- new ReadingItemService(Substitute.For(),
- Substitute.For(), Substitute.For(), ds), Substitute.For());
-
- cleanupService.CleanupChapters(new []{1, 3});
- Assert.Empty(ds.GetFiles(CacheDirectory, searchOption:SearchOption.AllDirectories));
- }
-
-
- #endregion
-
- #region GetCachedEpubFile
-
- [Fact]
- public void GetCachedEpubFile_ShouldReturnFirstEpub()
- {
- var filesystem = CreateFileSystem();
- filesystem.AddDirectory($"{CacheDirectory}1/");
- filesystem.AddFile($"{DataDirectory}1.epub", new MockFileData(""));
- filesystem.AddFile($"{DataDirectory}2.epub", new MockFileData(""));
- var ds = new DirectoryService(Substitute.For>(), filesystem);
- var cs = new CacheService(_logger, _unitOfWork, ds,
- new ReadingItemService(Substitute.For(),
- Substitute.For(), Substitute.For(), ds), Substitute.For());
-
- var c = new Chapter()
- {
- Files = new List()
- {
- new MangaFile()
- {
- FilePath = $"{DataDirectory}1.epub"
- },
- new MangaFile()
- {
- FilePath = $"{DataDirectory}2.epub"
- }
- }
- };
- cs.GetCachedFile(c);
- Assert.Same($"{DataDirectory}1.epub", cs.GetCachedFile(c));
- }
-
- #endregion
-
- #region GetCachedPagePath
-
- [Fact]
- public void GetCachedPagePath_ReturnNullIfNoFiles()
- {
- var filesystem = CreateFileSystem();
- filesystem.AddDirectory($"{CacheDirectory}1/");
- filesystem.AddFile($"{DataDirectory}1.zip", new MockFileData(""));
- filesystem.AddFile($"{DataDirectory}2.zip", new MockFileData(""));
-
- var c = new Chapter()
- {
- Id = 1,
- Files = new List()
- };
-
- var fileIndex = 0;
- foreach (var file in c.Files)
- {
- for (var i = 0; i < file.Pages - 1; i++)
- {
- filesystem.AddFile($"{CacheDirectory}1/{fileIndex}/{i+1}.jpg", new MockFileData(""));
- }
-
- fileIndex++;
- }
-
- var ds = new DirectoryService(Substitute.For>(), filesystem);
- var cs = new CacheService(_logger, _unitOfWork, ds,
- new ReadingItemService(Substitute.For(),
- Substitute.For(), Substitute.For(), ds), Substitute.For());
-
- // Flatten to prepare for how GetFullPath expects
- ds.Flatten($"{CacheDirectory}1/");
-
- var path = cs.GetCachedPagePath(c, 11);
- Assert.Equal(string.Empty, path);
- }
-
- [Fact]
- public void GetCachedPagePath_GetFileFromFirstFile()
- {
- var filesystem = CreateFileSystem();
- filesystem.AddDirectory($"{CacheDirectory}1/");
- filesystem.AddFile($"{DataDirectory}1.zip", new MockFileData(""));
- filesystem.AddFile($"{DataDirectory}2.zip", new MockFileData(""));
-
- var c = new Chapter()
- {
- Id = 1,
- Files = new List()
- {
- new MangaFile()
- {
- Id = 1,
- FilePath = $"{DataDirectory}1.zip",
- Pages = 10
-
- },
- new MangaFile()
- {
- Id = 2,
- FilePath = $"{DataDirectory}2.zip",
- Pages = 5
- }
- }
- };
-
- var fileIndex = 0;
- foreach (var file in c.Files)
- {
- for (var i = 0; i < file.Pages; i++)
- {
- filesystem.AddFile($"{CacheDirectory}1/00{fileIndex}_00{i+1}.jpg", new MockFileData(""));
- }
-
- fileIndex++;
- }
-
- var ds = new DirectoryService(Substitute.For>(), filesystem);
- var cs = new CacheService(_logger, _unitOfWork, ds,
- new ReadingItemService(Substitute.For(),
- Substitute.For(), Substitute.For(), ds), Substitute.For());
-
- // Flatten to prepare for how GetFullPath expects
- ds.Flatten($"{CacheDirectory}1/");
-
- Assert.Equal(ds.FileSystem.Path.GetFullPath($"{CacheDirectory}/1/000_001.jpg"), ds.FileSystem.Path.GetFullPath(cs.GetCachedPagePath(c, 0)));
-
- }
-
-
- [Fact]
- public void GetCachedPagePath_GetLastPageFromSingleFile()
- {
- var filesystem = CreateFileSystem();
- filesystem.AddDirectory($"{CacheDirectory}1/");
- filesystem.AddFile($"{DataDirectory}1.zip", new MockFileData(""));
-
- var c = new Chapter()
- {
- Id = 1,
- Files = new List()
- {
- new MangaFile()
- {
- Id = 1,
- FilePath = $"{DataDirectory}1.zip",
- Pages = 10
-
- }
- }
- };
- c.Pages = c.Files.Sum(f => f.Pages);
-
- var fileIndex = 0;
- foreach (var file in c.Files)
- {
- for (var i = 0; i < file.Pages; i++)
- {
- filesystem.AddFile($"{CacheDirectory}1/{fileIndex}/{i+1}.jpg", new MockFileData(""));
- }
-
- fileIndex++;
- }
-
- var ds = new DirectoryService(Substitute.For>(), filesystem);
- var cs = new CacheService(_logger, _unitOfWork, ds,
- new ReadingItemService(Substitute.For(),
- Substitute.For(), Substitute.For(), ds), Substitute.For());
-
- // Flatten to prepare for how GetFullPath expects
- ds.Flatten($"{CacheDirectory}1/");
-
- // Remember that we start at 0, so this is the 10th file
- var path = cs.GetCachedPagePath(c, c.Pages);
- Assert.Equal(ds.FileSystem.Path.GetFullPath($"{CacheDirectory}/1/000_0{c.Pages}.jpg"), ds.FileSystem.Path.GetFullPath(path));
- }
-
- [Fact]
- public void GetCachedPagePath_GetFileFromSecondFile()
- {
- var filesystem = CreateFileSystem();
- filesystem.AddDirectory($"{CacheDirectory}1/");
- filesystem.AddFile($"{DataDirectory}1.zip", new MockFileData(""));
- filesystem.AddFile($"{DataDirectory}2.zip", new MockFileData(""));
-
- var c = new Chapter()
- {
- Id = 1,
- Files = new List()
- {
- new MangaFile()
- {
- Id = 1,
- FilePath = $"{DataDirectory}1.zip",
- Pages = 10
-
- },
- new MangaFile()
- {
- Id = 2,
- FilePath = $"{DataDirectory}2.zip",
- Pages = 5
- }
- }
- };
-
- var fileIndex = 0;
- foreach (var file in c.Files)
- {
- for (var i = 0; i < file.Pages; i++)
- {
- filesystem.AddFile($"{CacheDirectory}1/{fileIndex}/{i+1}.jpg", new MockFileData(""));
- }
-
- fileIndex++;
- }
-
- var ds = new DirectoryService(Substitute.For>(), filesystem);
- var cs = new CacheService(_logger, _unitOfWork, ds,
- new ReadingItemService(Substitute.For(),
- Substitute.For(), Substitute.For(), ds), Substitute.For());
-
- // Flatten to prepare for how GetFullPath expects
- ds.Flatten($"{CacheDirectory}1/");
-
- // Remember that we start at 0, so this is the page + 1 file
- var path = cs.GetCachedPagePath(c, 10);
- Assert.Equal(ds.FileSystem.Path.GetFullPath($"{CacheDirectory}/1/001_001.jpg"), ds.FileSystem.Path.GetFullPath(path));
- }
-
- #endregion
-
- #region ExtractChapterFiles
-
- // [Fact]
- // public void ExtractChapterFiles_ShouldExtractOnlyImages()
- // {
- // const string testDirectory = "/manga/";
- // var fileSystem = new MockFileSystem();
- // for (var i = 0; i < 10; i++)
- // {
- // fileSystem.AddFile($"{testDirectory}file_{i}.zip", new MockFileData(""));
- // }
- //
- // fileSystem.AddDirectory(CacheDirectory);
- //
- // var ds = new DirectoryService(Substitute.For>(), fileSystem);
- // var cs = new CacheService(_logger, _unitOfWork, ds,
- // new MockReadingItemServiceForCacheService(ds));
- //
- //
- // cs.ExtractChapterFiles(CacheDirectory, new List()
- // {
- // new MangaFile()
- // {
- // ChapterId = 1,
- // Format = MangaFormat.Archive,
- // Pages = 2,
- // FilePath =
- // }
- // })
- // }
-
- #endregion
+ return null;
+ }
+
+ public int GetNumberOfPages(string filePath, MangaFormat format)
+ {
+ return 1;
+ }
+
+ public string GetCoverImage(string fileFilePath, string fileName, MangaFormat format)
+ {
+ return string.Empty;
+ }
+
+ public void Extract(string fileFilePath, string targetDirectory, MangaFormat format, int imageCount = 1)
+ {
+ throw new System.NotImplementedException();
+ }
+
+ public ParserInfo Parse(string path, string rootPath, LibraryType type)
+ {
+ throw new System.NotImplementedException();
+ }
+
+ public ParserInfo ParseFile(string path, string rootPath, LibraryType type)
+ {
+ throw new System.NotImplementedException();
}
}
+public class CacheServiceTests
+{
+ private readonly ILogger _logger = Substitute.For>();
+ private readonly IUnitOfWork _unitOfWork;
+ private readonly IHubContext _messageHub = Substitute.For>();
+
+ private readonly DbConnection _connection;
+ private readonly DataContext _context;
+
+ private const string CacheDirectory = "C:/kavita/config/cache/";
+ private const string CoverImageDirectory = "C:/kavita/config/covers/";
+ private const string BackupDirectory = "C:/kavita/config/backups/";
+ private const string DataDirectory = "C:/data/";
+
+ public CacheServiceTests()
+ {
+ var contextOptions = new DbContextOptionsBuilder()
+ .UseSqlite(CreateInMemoryDatabase())
+ .Options;
+ _connection = RelationalOptionsExtension.Extract(contextOptions).Connection;
+
+ _context = new DataContext(contextOptions);
+ Task.Run(SeedDb).GetAwaiter().GetResult();
+
+ _unitOfWork = new UnitOfWork(_context, Substitute.For(), null);
+ }
+
+ #region Setup
+
+ private static DbConnection CreateInMemoryDatabase()
+ {
+ var connection = new SqliteConnection("Filename=:memory:");
+
+ connection.Open();
+
+ return connection;
+ }
+
+ public void Dispose() => _connection.Dispose();
+
+ private async Task SeedDb()
+ {
+ await _context.Database.MigrateAsync();
+ var filesystem = CreateFileSystem();
+
+ await Seed.SeedSettings(_context, new DirectoryService(Substitute.For>(), filesystem));
+
+ var setting = await _context.ServerSetting.Where(s => s.Key == ServerSettingKey.CacheDirectory).SingleAsync();
+ setting.Value = CacheDirectory;
+
+ setting = await _context.ServerSetting.Where(s => s.Key == ServerSettingKey.BackupDirectory).SingleAsync();
+ setting.Value = BackupDirectory;
+
+ _context.ServerSetting.Update(setting);
+
+ _context.Library.Add(new Library()
+ {
+ Name = "Manga",
+ Folders = new List()
+ {
+ new FolderPath()
+ {
+ Path = "C:/data/"
+ }
+ }
+ });
+ return await _context.SaveChangesAsync() > 0;
+ }
+
+ private async Task ResetDB()
+ {
+ _context.Series.RemoveRange(_context.Series.ToList());
+
+ await _context.SaveChangesAsync();
+ }
+
+ private static MockFileSystem CreateFileSystem()
+ {
+ var fileSystem = new MockFileSystem();
+ fileSystem.Directory.SetCurrentDirectory("C:/kavita/");
+ fileSystem.AddDirectory("C:/kavita/config/");
+ fileSystem.AddDirectory(CacheDirectory);
+ fileSystem.AddDirectory(CoverImageDirectory);
+ fileSystem.AddDirectory(BackupDirectory);
+ fileSystem.AddDirectory(DataDirectory);
+
+ return fileSystem;
+ }
+
+ #endregion
+
+ #region Ensure
+
+ [Fact]
+ public async Task Ensure_DirectoryAlreadyExists_DontExtractAnything()
+ {
+ var filesystem = CreateFileSystem();
+ filesystem.AddFile($"{DataDirectory}Test v1.zip", new MockFileData(""));
+ filesystem.AddDirectory($"{CacheDirectory}1/");
+ var ds = new DirectoryService(Substitute.For>(), filesystem);
+ var cleanupService = new CacheService(_logger, _unitOfWork, ds,
+ new ReadingItemService(Substitute.For(),
+ Substitute.For(), Substitute.For(), ds), Substitute.For());
+
+ await ResetDB();
+ var s = DbFactory.Series("Test");
+ var v = DbFactory.Volume("1");
+ var c = new Chapter()
+ {
+ Number = "1",
+ Files = new List()
+ {
+ new MangaFile()
+ {
+ Format = MangaFormat.Archive,
+ FilePath = $"{DataDirectory}Test v1.zip",
+ }
+ }
+ };
+ v.Chapters.Add(c);
+ s.Volumes.Add(v);
+ s.LibraryId = 1;
+ _context.Series.Add(s);
+
+ await _context.SaveChangesAsync();
+
+ await cleanupService.Ensure(1);
+ Assert.Empty(ds.GetFiles(filesystem.Path.Join(CacheDirectory, "1"), searchOption:SearchOption.AllDirectories));
+ }
+
+ // [Fact]
+ // public async Task Ensure_DirectoryAlreadyExists_ExtractsImages()
+ // {
+ // // TODO: Figure out a way to test this
+ // var filesystem = CreateFileSystem();
+ // filesystem.AddFile($"{DataDirectory}Test v1.zip", new MockFileData(""));
+ // filesystem.AddDirectory($"{CacheDirectory}1/");
+ // var ds = new DirectoryService(Substitute.For>(), filesystem);
+ // var archiveService = Substitute.For();
+ // archiveService.ExtractArchive($"{DataDirectory}Test v1.zip",
+ // filesystem.Path.Join(CacheDirectory, "1"));
+ // var cleanupService = new CacheService(_logger, _unitOfWork, ds,
+ // new ReadingItemService(archiveService, Substitute.For(), Substitute.For(), ds));
+ //
+ // await ResetDB();
+ // var s = DbFactory.Series("Test");
+ // var v = DbFactory.Volume("1");
+ // var c = new Chapter()
+ // {
+ // Number = "1",
+ // Files = new List()
+ // {
+ // new MangaFile()
+ // {
+ // Format = MangaFormat.Archive,
+ // FilePath = $"{DataDirectory}Test v1.zip",
+ // }
+ // }
+ // };
+ // v.Chapters.Add(c);
+ // s.Volumes.Add(v);
+ // s.LibraryId = 1;
+ // _context.Series.Add(s);
+ //
+ // await _context.SaveChangesAsync();
+ //
+ // await cleanupService.Ensure(1);
+ // Assert.Empty(ds.GetFiles(filesystem.Path.Join(CacheDirectory, "1"), searchOption:SearchOption.AllDirectories));
+ // }
+
+
+ #endregion
+
+ #region CleanupChapters
+
+ [Fact]
+ public void CleanupChapters_AllFilesShouldBeDeleted()
+ {
+ var filesystem = CreateFileSystem();
+ filesystem.AddDirectory($"{CacheDirectory}1/");
+ filesystem.AddFile($"{CacheDirectory}1/001.jpg", new MockFileData(""));
+ filesystem.AddFile($"{CacheDirectory}1/002.jpg", new MockFileData(""));
+ filesystem.AddFile($"{CacheDirectory}3/003.jpg", new MockFileData(""));
+ var ds = new DirectoryService(Substitute.For>(), filesystem);
+ var cleanupService = new CacheService(_logger, _unitOfWork, ds,
+ new ReadingItemService(Substitute.For(),
+ Substitute.For(), Substitute.For(), ds), Substitute.For());
+
+ cleanupService.CleanupChapters(new []{1, 3});
+ Assert.Empty(ds.GetFiles(CacheDirectory, searchOption:SearchOption.AllDirectories));
+ }
+
+
+ #endregion
+
+ #region GetCachedEpubFile
+
+ [Fact]
+ public void GetCachedEpubFile_ShouldReturnFirstEpub()
+ {
+ var filesystem = CreateFileSystem();
+ filesystem.AddDirectory($"{CacheDirectory}1/");
+ filesystem.AddFile($"{DataDirectory}1.epub", new MockFileData(""));
+ filesystem.AddFile($"{DataDirectory}2.epub", new MockFileData(""));
+ var ds = new DirectoryService(Substitute.For>(), filesystem);
+ var cs = new CacheService(_logger, _unitOfWork, ds,
+ new ReadingItemService(Substitute.For(),
+ Substitute.For(), Substitute.For(), ds), Substitute.For());
+
+ var c = new Chapter()
+ {
+ Files = new List()
+ {
+ new MangaFile()
+ {
+ FilePath = $"{DataDirectory}1.epub"
+ },
+ new MangaFile()
+ {
+ FilePath = $"{DataDirectory}2.epub"
+ }
+ }
+ };
+ cs.GetCachedFile(c);
+ Assert.Same($"{DataDirectory}1.epub", cs.GetCachedFile(c));
+ }
+
+ #endregion
+
+ #region GetCachedPagePath
+
+ [Fact]
+ public void GetCachedPagePath_ReturnNullIfNoFiles()
+ {
+ var filesystem = CreateFileSystem();
+ filesystem.AddDirectory($"{CacheDirectory}1/");
+ filesystem.AddFile($"{DataDirectory}1.zip", new MockFileData(""));
+ filesystem.AddFile($"{DataDirectory}2.zip", new MockFileData(""));
+
+ var c = new Chapter()
+ {
+ Id = 1,
+ Files = new List()
+ };
+
+ var fileIndex = 0;
+ foreach (var file in c.Files)
+ {
+ for (var i = 0; i < file.Pages - 1; i++)
+ {
+ filesystem.AddFile($"{CacheDirectory}1/{fileIndex}/{i+1}.jpg", new MockFileData(""));
+ }
+
+ fileIndex++;
+ }
+
+ var ds = new DirectoryService(Substitute.For>(), filesystem);
+ var cs = new CacheService(_logger, _unitOfWork, ds,
+ new ReadingItemService(Substitute.For(),
+ Substitute.For(), Substitute.For(), ds), Substitute.For());
+
+ // Flatten to prepare for how GetFullPath expects
+ ds.Flatten($"{CacheDirectory}1/");
+
+ var path = cs.GetCachedPagePath(c, 11);
+ Assert.Equal(string.Empty, path);
+ }
+
+ [Fact]
+ public void GetCachedPagePath_GetFileFromFirstFile()
+ {
+ var filesystem = CreateFileSystem();
+ filesystem.AddDirectory($"{CacheDirectory}1/");
+ filesystem.AddFile($"{DataDirectory}1.zip", new MockFileData(""));
+ filesystem.AddFile($"{DataDirectory}2.zip", new MockFileData(""));
+
+ var c = new Chapter()
+ {
+ Id = 1,
+ Files = new List()
+ {
+ new MangaFile()
+ {
+ Id = 1,
+ FilePath = $"{DataDirectory}1.zip",
+ Pages = 10
+
+ },
+ new MangaFile()
+ {
+ Id = 2,
+ FilePath = $"{DataDirectory}2.zip",
+ Pages = 5
+ }
+ }
+ };
+
+ var fileIndex = 0;
+ foreach (var file in c.Files)
+ {
+ for (var i = 0; i < file.Pages; i++)
+ {
+ filesystem.AddFile($"{CacheDirectory}1/00{fileIndex}_00{i+1}.jpg", new MockFileData(""));
+ }
+
+ fileIndex++;
+ }
+
+ var ds = new DirectoryService(Substitute.For>(), filesystem);
+ var cs = new CacheService(_logger, _unitOfWork, ds,
+ new ReadingItemService(Substitute.For(),
+ Substitute.For(), Substitute.For(), ds), Substitute.For());
+
+ // Flatten to prepare for how GetFullPath expects
+ ds.Flatten($"{CacheDirectory}1/");
+
+ Assert.Equal(ds.FileSystem.Path.GetFullPath($"{CacheDirectory}/1/000_001.jpg"), ds.FileSystem.Path.GetFullPath(cs.GetCachedPagePath(c, 0)));
+
+ }
+
+
+ [Fact]
+ public void GetCachedPagePath_GetLastPageFromSingleFile()
+ {
+ var filesystem = CreateFileSystem();
+ filesystem.AddDirectory($"{CacheDirectory}1/");
+ filesystem.AddFile($"{DataDirectory}1.zip", new MockFileData(""));
+
+ var c = new Chapter()
+ {
+ Id = 1,
+ Files = new List