Comic Rework, New Scanner, Foundation Overahul (is this a full release?) (#2780)
This commit is contained in:
parent
d7e9e7c832
commit
7552c3f5fa
182 changed files with 27630 additions and 3046 deletions
217
API.Tests/Parsers/BasicParserTests.cs
Normal file
217
API.Tests/Parsers/BasicParserTests.cs
Normal file
|
|
@ -0,0 +1,217 @@
|
|||
using System.IO.Abstractions.TestingHelpers;
|
||||
using API.Entities.Enums;
|
||||
using API.Services;
|
||||
using API.Services.Tasks.Scanner.Parser;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using NSubstitute;
|
||||
using Xunit;
|
||||
|
||||
namespace API.Tests.Parsers;
|
||||
|
||||
public class BasicParserTests
|
||||
{
|
||||
private readonly BasicParser _parser;
|
||||
private readonly ILogger<DirectoryService> _dsLogger = Substitute.For<ILogger<DirectoryService>>();
|
||||
private const string RootDirectory = "C:/Books/";
|
||||
|
||||
public BasicParserTests()
|
||||
{
|
||||
var fileSystem = new MockFileSystem();
|
||||
fileSystem.AddDirectory("C:/Books/");
|
||||
fileSystem.AddFile("C:/Books/Harry Potter/Harry Potter - Vol 1.epub", new MockFileData(""));
|
||||
|
||||
fileSystem.AddFile("C:/Books/Accel World/Accel World - Volume 1.cbz", new MockFileData(""));
|
||||
fileSystem.AddFile("C:/Books/Accel World/Accel World - Volume 1 Chapter 2.cbz", new MockFileData(""));
|
||||
fileSystem.AddFile("C:/Books/Accel World/Accel World - Chapter 3.cbz", new MockFileData(""));
|
||||
fileSystem.AddFile("C:/Books/Accel World/Accel World Gaiden SP01.cbz", new MockFileData(""));
|
||||
|
||||
|
||||
fileSystem.AddFile("C:/Books/Accel World/cover.png", new MockFileData(""));
|
||||
|
||||
fileSystem.AddFile("C:/Books/Batman/Batman #1.cbz", new MockFileData(""));
|
||||
|
||||
var ds = new DirectoryService(_dsLogger, fileSystem);
|
||||
_parser = new BasicParser(ds, new ImageParser(ds));
|
||||
}
|
||||
|
||||
#region Parse_Books
|
||||
|
||||
|
||||
|
||||
#endregion
|
||||
|
||||
#region Parse_Manga
|
||||
|
||||
/// <summary>
|
||||
/// Tests that when there is a loose leaf cover in the manga library, that it is ignored
|
||||
/// </summary>
|
||||
[Fact]
|
||||
public void Parse_MangaLibrary_JustCover_ShouldReturnNull()
|
||||
{
|
||||
var actual = _parser.Parse(@"C:/Books/Accel World/cover.png", "C:/Books/Accel World/",
|
||||
RootDirectory, LibraryType.Manga, null);
|
||||
Assert.Null(actual);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Tests that when there is a loose leaf cover in the manga library, that it is ignored
|
||||
/// </summary>
|
||||
[Fact]
|
||||
public void Parse_MangaLibrary_OtherImage_ShouldReturnNull()
|
||||
{
|
||||
var actual = _parser.Parse(@"C:/Books/Accel World/page 01.png", "C:/Books/Accel World/",
|
||||
RootDirectory, LibraryType.Manga, null);
|
||||
Assert.NotNull(actual);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Tests that when there is a volume and chapter in filename, it appropriately parses
|
||||
/// </summary>
|
||||
[Fact]
|
||||
public void Parse_MangaLibrary_VolumeAndChapterInFilename()
|
||||
{
|
||||
var actual = _parser.Parse("C:/Books/Mujaki no Rakuen/Mujaki no Rakuen Vol12 ch76.cbz", "C:/Books/Mujaki no Rakuen/",
|
||||
RootDirectory, LibraryType.Manga, null);
|
||||
Assert.NotNull(actual);
|
||||
|
||||
Assert.Equal("Mujaki no Rakuen", actual.Series);
|
||||
Assert.Equal("12", actual.Volumes);
|
||||
Assert.Equal("76", actual.Chapters);
|
||||
Assert.False(actual.IsSpecial);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Tests that when there is a volume in filename, it appropriately parses
|
||||
/// </summary>
|
||||
[Fact]
|
||||
public void Parse_MangaLibrary_JustVolumeInFilename()
|
||||
{
|
||||
var actual = _parser.Parse("C:/Books/Shimoneta to Iu Gainen ga Sonzai Shinai Taikutsu na Sekai Man-hen/Vol 1.cbz",
|
||||
"C:/Books/Shimoneta to Iu Gainen ga Sonzai Shinai Taikutsu na Sekai Man-hen/",
|
||||
RootDirectory, LibraryType.Manga, null);
|
||||
Assert.NotNull(actual);
|
||||
|
||||
Assert.Equal("Shimoneta to Iu Gainen ga Sonzai Shinai Taikutsu na Sekai Man-hen", actual.Series);
|
||||
Assert.Equal("1", actual.Volumes);
|
||||
Assert.Equal(Parser.DefaultChapter, actual.Chapters);
|
||||
Assert.False(actual.IsSpecial);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Tests that when there is a chapter only in filename, it appropriately parses
|
||||
/// </summary>
|
||||
[Fact]
|
||||
public void Parse_MangaLibrary_JustChapterInFilename()
|
||||
{
|
||||
var actual = _parser.Parse("C:/Books/Beelzebub/Beelzebub_01_[Noodles].zip",
|
||||
"C:/Books/Beelzebub/",
|
||||
RootDirectory, LibraryType.Manga, null);
|
||||
Assert.NotNull(actual);
|
||||
|
||||
Assert.Equal("Beelzebub", actual.Series);
|
||||
Assert.Equal(Parser.LooseLeafVolume, actual.Volumes);
|
||||
Assert.Equal("1", actual.Chapters);
|
||||
Assert.False(actual.IsSpecial);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Tests that when there is a SP Marker in filename, it appropriately parses
|
||||
/// </summary>
|
||||
[Fact]
|
||||
public void Parse_MangaLibrary_SpecialMarkerInFilename()
|
||||
{
|
||||
var actual = _parser.Parse("C:/Books/Summer Time Rendering/Specials/Record 014 (between chapter 083 and ch084) SP11.cbr",
|
||||
"C:/Books/Summer Time Rendering/",
|
||||
RootDirectory, LibraryType.Manga, null);
|
||||
Assert.NotNull(actual);
|
||||
|
||||
Assert.Equal("Summer Time Rendering", actual.Series);
|
||||
Assert.Equal(Parser.SpecialVolume, actual.Volumes);
|
||||
Assert.Equal(Parser.DefaultChapter, actual.Chapters);
|
||||
Assert.True(actual.IsSpecial);
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Tests that when the filename parses as a speical, it appropriately parses
|
||||
/// </summary>
|
||||
[Fact]
|
||||
public void Parse_MangaLibrary_SpecialInFilename()
|
||||
{
|
||||
var actual = _parser.Parse("C:/Books/Summer Time Rendering/Specials/Volume Omake.cbr",
|
||||
"C:/Books/Summer Time Rendering/",
|
||||
RootDirectory, LibraryType.Manga, null);
|
||||
Assert.NotNull(actual);
|
||||
|
||||
Assert.Equal("Summer Time Rendering", actual.Series);
|
||||
Assert.Equal("Volume Omake", actual.Title);
|
||||
Assert.Equal(Parser.SpecialVolume, actual.Volumes);
|
||||
Assert.Equal(Parser.DefaultChapter, actual.Chapters);
|
||||
Assert.True(actual.IsSpecial);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Tests that when there is an edition in filename, it appropriately parses
|
||||
/// </summary>
|
||||
[Fact]
|
||||
public void Parse_MangaLibrary_EditionInFilename()
|
||||
{
|
||||
var actual = _parser.Parse("C:/Books/Air Gear/Air Gear Omnibus v01 (2016) (Digital) (Shadowcat-Empire).cbz",
|
||||
"C:/Books/Air Gear/",
|
||||
RootDirectory, LibraryType.Manga, null);
|
||||
Assert.NotNull(actual);
|
||||
|
||||
Assert.Equal("Air Gear", actual.Series);
|
||||
Assert.Equal("1", actual.Volumes);
|
||||
Assert.Equal(Parser.DefaultChapter, actual.Chapters);
|
||||
Assert.False(actual.IsSpecial);
|
||||
Assert.Equal("Omnibus", actual.Edition);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Parse_Books
|
||||
/// <summary>
|
||||
/// Tests that when there is a volume in filename, it appropriately parses
|
||||
/// </summary>
|
||||
[Fact]
|
||||
public void Parse_MangaBooks_JustVolumeInFilename()
|
||||
{
|
||||
var actual = _parser.Parse("C:/Books/Epubs/Harrison, Kim - The Good, The Bad, and the Undead - Hollows Vol 2.5.epub",
|
||||
"C:/Books/Epubs/",
|
||||
RootDirectory, LibraryType.Manga, null);
|
||||
Assert.NotNull(actual);
|
||||
|
||||
Assert.Equal("Harrison, Kim - The Good, The Bad, and the Undead - Hollows", actual.Series);
|
||||
Assert.Equal("2.5", actual.Volumes);
|
||||
Assert.Equal(Parser.DefaultChapter, actual.Chapters);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region IsApplicable
|
||||
/// <summary>
|
||||
/// Tests that this Parser can only be used on images and Image library type
|
||||
/// </summary>
|
||||
[Fact]
|
||||
public void IsApplicable_Fails_WhenNonMatchingLibraryType()
|
||||
{
|
||||
Assert.False(_parser.IsApplicable("something.cbz", LibraryType.Image));
|
||||
Assert.False(_parser.IsApplicable("something.cbz", LibraryType.ComicVine));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Tests that this Parser can only be used on images and Image library type
|
||||
/// </summary>
|
||||
[Fact]
|
||||
public void IsApplicable_Success_WhenMatchingLibraryType()
|
||||
{
|
||||
Assert.True(_parser.IsApplicable("something.png", LibraryType.Manga));
|
||||
Assert.True(_parser.IsApplicable("something.png", LibraryType.Comic));
|
||||
Assert.True(_parser.IsApplicable("something.pdf", LibraryType.Book));
|
||||
Assert.True(_parser.IsApplicable("something.epub", LibraryType.LightNovel));
|
||||
}
|
||||
|
||||
|
||||
#endregion
|
||||
}
|
||||
74
API.Tests/Parsers/BookParserTests.cs
Normal file
74
API.Tests/Parsers/BookParserTests.cs
Normal file
|
|
@ -0,0 +1,74 @@
|
|||
using System.IO.Abstractions.TestingHelpers;
|
||||
using API.Data.Metadata;
|
||||
using API.Entities.Enums;
|
||||
using API.Services;
|
||||
using API.Services.Tasks.Scanner.Parser;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using NSubstitute;
|
||||
using Xunit;
|
||||
|
||||
namespace API.Tests.Parsers;
|
||||
|
||||
public class BookParserTests
|
||||
{
|
||||
private readonly BookParser _parser;
|
||||
private readonly ILogger<DirectoryService> _dsLogger = Substitute.For<ILogger<DirectoryService>>();
|
||||
private const string RootDirectory = "C:/Books/";
|
||||
|
||||
public BookParserTests()
|
||||
{
|
||||
var fileSystem = new MockFileSystem();
|
||||
fileSystem.AddDirectory("C:/Books/");
|
||||
fileSystem.AddFile("C:/Books/Harry Potter/Harry Potter - Vol 1.epub", new MockFileData(""));
|
||||
fileSystem.AddFile("C:/Books/Adam Freeman - Pro ASP.NET Core 6.epub", new MockFileData(""));
|
||||
fileSystem.AddFile("C:/Books/My Fav Book SP01.epub", new MockFileData(""));
|
||||
var ds = new DirectoryService(_dsLogger, fileSystem);
|
||||
_parser = new BookParser(ds, Substitute.For<IBookService>(), new BasicParser(ds, new ImageParser(ds)));
|
||||
}
|
||||
|
||||
#region Parse
|
||||
|
||||
// TODO: I'm not sure how to actually test this as it relies on an epub parser to actually do anything
|
||||
|
||||
/// <summary>
|
||||
/// Tests that if there is a Series Folder then Chapter folder, the code appropriately identifies the Series name and Chapter
|
||||
/// </summary>
|
||||
// [Fact]
|
||||
// public void Parse_SeriesWithDirectoryName()
|
||||
// {
|
||||
// var actual = _parser.Parse("C:/Books/Harry Potter/Harry Potter - Vol 1.epub", "C:/Books/Birds of Prey/",
|
||||
// RootDirectory, LibraryType.Book, new ComicInfo()
|
||||
// {
|
||||
// Series = "Harry Potter",
|
||||
// Volume = "1"
|
||||
// });
|
||||
//
|
||||
// Assert.NotNull(actual);
|
||||
// Assert.Equal("Harry Potter", actual.Series);
|
||||
// Assert.Equal("1", actual.Volumes);
|
||||
// }
|
||||
|
||||
#endregion
|
||||
|
||||
#region IsApplicable
|
||||
/// <summary>
|
||||
/// Tests that this Parser can only be used on images and Image library type
|
||||
/// </summary>
|
||||
[Fact]
|
||||
public void IsApplicable_Fails_WhenNonMatchingLibraryType()
|
||||
{
|
||||
Assert.False(_parser.IsApplicable("something.cbz", LibraryType.Manga));
|
||||
Assert.False(_parser.IsApplicable("something.cbz", LibraryType.Book));
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Tests that this Parser can only be used on images and Image library type
|
||||
/// </summary>
|
||||
[Fact]
|
||||
public void IsApplicable_Success_WhenMatchingLibraryType()
|
||||
{
|
||||
Assert.True(_parser.IsApplicable("something.epub", LibraryType.Image));
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
115
API.Tests/Parsers/ComicVineParserTests.cs
Normal file
115
API.Tests/Parsers/ComicVineParserTests.cs
Normal file
|
|
@ -0,0 +1,115 @@
|
|||
using System.IO.Abstractions.TestingHelpers;
|
||||
using API.Data.Metadata;
|
||||
using API.Entities.Enums;
|
||||
using API.Services;
|
||||
using API.Services.Tasks.Scanner.Parser;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using NSubstitute;
|
||||
using Xunit;
|
||||
|
||||
namespace API.Tests.Parsers;
|
||||
|
||||
public class ComicVineParserTests
|
||||
{
|
||||
private readonly ComicVineParser _parser;
|
||||
private readonly ILogger<DirectoryService> _dsLogger = Substitute.For<ILogger<DirectoryService>>();
|
||||
private const string RootDirectory = "C:/Comics/";
|
||||
|
||||
public ComicVineParserTests()
|
||||
{
|
||||
var fileSystem = new MockFileSystem();
|
||||
fileSystem.AddDirectory("C:/Comics/");
|
||||
fileSystem.AddDirectory("C:/Comics/Birds of Prey (2002)");
|
||||
fileSystem.AddFile("C:/Comics/Birds of Prey (2002)/Birds of Prey 001 (2002).cbz", new MockFileData(""));
|
||||
fileSystem.AddFile("C:/Comics/DC Comics/Birds of Prey (1999)/Birds of Prey 001 (1999).cbz", new MockFileData(""));
|
||||
fileSystem.AddFile("C:/Comics/DC Comics/Blood Syndicate/Blood Syndicate 001 (1999).cbz", new MockFileData(""));
|
||||
var ds = new DirectoryService(_dsLogger, fileSystem);
|
||||
_parser = new ComicVineParser(ds);
|
||||
}
|
||||
|
||||
#region Parse
|
||||
|
||||
/// <summary>
|
||||
/// Tests that when Series and Volume are filled out, Kavita uses that for the Series Name
|
||||
/// </summary>
|
||||
[Fact]
|
||||
public void Parse_SeriesWithComicInfo()
|
||||
{
|
||||
var actual = _parser.Parse("C:/Comics/Birds of Prey (2002)/Birds of Prey 001 (2002).cbz", "C:/Comics/Birds of Prey (2002)/",
|
||||
RootDirectory, LibraryType.ComicVine, new ComicInfo()
|
||||
{
|
||||
Series = "Birds of Prey",
|
||||
Volume = "2002"
|
||||
});
|
||||
|
||||
Assert.NotNull(actual);
|
||||
Assert.Equal("Birds of Prey (2002)", actual.Series);
|
||||
Assert.Equal("2002", actual.Volumes);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Tests that no ComicInfo, take the Directory Name if it matches "Series (2002)" or "Series (2)"
|
||||
/// </summary>
|
||||
[Fact]
|
||||
public void Parse_SeriesWithDirectoryNameAsSeriesYear()
|
||||
{
|
||||
var actual = _parser.Parse("C:/Comics/Birds of Prey (2002)/Birds of Prey 001 (2002).cbz", "C:/Comics/Birds of Prey (2002)/",
|
||||
RootDirectory, LibraryType.ComicVine, null);
|
||||
|
||||
Assert.NotNull(actual);
|
||||
Assert.Equal("Birds of Prey (2002)", actual.Series);
|
||||
Assert.Equal("2002", actual.Volumes);
|
||||
Assert.Equal("1", actual.Chapters);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Tests that no ComicInfo, take a directory name up to root if it matches "Series (2002)" or "Series (2)"
|
||||
/// </summary>
|
||||
[Fact]
|
||||
public void Parse_SeriesWithADirectoryNameAsSeriesYear()
|
||||
{
|
||||
var actual = _parser.Parse("C:/Comics/DC Comics/Birds of Prey (1999)/Birds of Prey 001 (1999).cbz", "C:/Comics/DC Comics/",
|
||||
RootDirectory, LibraryType.ComicVine, null);
|
||||
|
||||
Assert.NotNull(actual);
|
||||
Assert.Equal("Birds of Prey (1999)", actual.Series);
|
||||
Assert.Equal("1999", actual.Volumes);
|
||||
Assert.Equal("1", actual.Chapters);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Tests that no ComicInfo and nothing matches Series (Volume), then just take the directory name as the Series
|
||||
/// </summary>
|
||||
[Fact]
|
||||
public void Parse_FallbackToDirectoryNameOnly()
|
||||
{
|
||||
var actual = _parser.Parse("C:/Comics/DC Comics/Blood Syndicate/Blood Syndicate 001 (1999).cbz", "C:/Comics/DC Comics/",
|
||||
RootDirectory, LibraryType.ComicVine, null);
|
||||
|
||||
Assert.NotNull(actual);
|
||||
Assert.Equal("Blood Syndicate", actual.Series);
|
||||
Assert.Equal(Parser.LooseLeafVolume, actual.Volumes);
|
||||
Assert.Equal("1", actual.Chapters);
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region IsApplicable
|
||||
/// <summary>
|
||||
/// Tests that this Parser can only be used on ComicVine type
|
||||
/// </summary>
|
||||
[Fact]
|
||||
public void IsApplicable_Fails_WhenNonMatchingLibraryType()
|
||||
{
|
||||
Assert.False(_parser.IsApplicable("", LibraryType.Comic));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Tests that this Parser can only be used on ComicVine type
|
||||
/// </summary>
|
||||
[Fact]
|
||||
public void IsApplicable_Success_WhenMatchingLibraryType()
|
||||
{
|
||||
Assert.True(_parser.IsApplicable("", LibraryType.ComicVine));
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
503
API.Tests/Parsers/DefaultParserTests.cs
Normal file
503
API.Tests/Parsers/DefaultParserTests.cs
Normal file
|
|
@ -0,0 +1,503 @@
|
|||
using System.Collections.Generic;
|
||||
using System.IO.Abstractions.TestingHelpers;
|
||||
using API.Entities.Enums;
|
||||
using API.Services;
|
||||
using API.Services.Tasks.Scanner.Parser;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using NSubstitute;
|
||||
using Xunit;
|
||||
using Xunit.Abstractions;
|
||||
|
||||
namespace API.Tests.Parsers;
|
||||
|
||||
public class DefaultParserTests
|
||||
{
|
||||
private readonly ITestOutputHelper _testOutputHelper;
|
||||
private readonly DefaultParser _defaultParser;
|
||||
|
||||
public DefaultParserTests(ITestOutputHelper testOutputHelper)
|
||||
{
|
||||
_testOutputHelper = testOutputHelper;
|
||||
var directoryService = new DirectoryService(Substitute.For<ILogger<DirectoryService>>(), new MockFileSystem());
|
||||
_defaultParser = new BasicParser(directoryService, new ImageParser(directoryService));
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
#region ParseFromFallbackFolders
|
||||
[Theory]
|
||||
[InlineData("C:/", "C:/Love Hina/Love Hina - Special.cbz", "Love Hina")]
|
||||
[InlineData("C:/", "C:/Love Hina/Specials/Ani-Hina Art Collection.cbz", "Love Hina")]
|
||||
[InlineData("C:/", "C:/Mujaki no Rakuen Something/Mujaki no Rakuen Vol12 ch76.cbz", "Mujaki no Rakuen")]
|
||||
[InlineData("C:/", "C:/Something Random/Mujaki no Rakuen SP01.cbz", "Something Random")]
|
||||
public void ParseFromFallbackFolders_FallbackShouldParseSeries(string rootDir, string inputPath, string expectedSeries)
|
||||
{
|
||||
var actual = _defaultParser.Parse(inputPath, rootDir, rootDir, LibraryType.Manga, null);
|
||||
if (actual == null)
|
||||
{
|
||||
Assert.NotNull(actual);
|
||||
return;
|
||||
}
|
||||
|
||||
Assert.Equal(expectedSeries, actual.Series);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData("/manga/Btooom!/Vol.1/Chapter 1/1.cbz", new [] {"Btooom!", "1", "1"})]
|
||||
[InlineData("/manga/Btooom!/Vol.1 Chapter 2/1.cbz", new [] {"Btooom!", "1", "2"})]
|
||||
[InlineData("/manga/Monster/Ch. 001-016 [MangaPlus] [Digital] [amit34521]/Monster Ch. 001 [MangaPlus] [Digital] [amit34521]/13.jpg", new [] {"Monster", API.Services.Tasks.Scanner.Parser.Parser.LooseLeafVolume, "1"})]
|
||||
[InlineData("/manga/Hajime no Ippo/Artbook/Hajime no Ippo - Artbook.cbz", new [] {"Hajime no Ippo", API.Services.Tasks.Scanner.Parser.Parser.LooseLeafVolume, API.Services.Tasks.Scanner.Parser.Parser.DefaultChapter})]
|
||||
public void ParseFromFallbackFolders_ShouldParseSeriesVolumeAndChapter(string inputFile, string[] expectedParseInfo)
|
||||
{
|
||||
const string rootDirectory = "/manga/";
|
||||
var actual = new ParserInfo {Series = "", Chapters = Parser.DefaultChapter, Volumes = Parser.LooseLeafVolume};
|
||||
_defaultParser.ParseFromFallbackFolders(inputFile, rootDirectory, LibraryType.Manga, ref actual);
|
||||
Assert.Equal(expectedParseInfo[0], actual.Series);
|
||||
Assert.Equal(expectedParseInfo[1], actual.Volumes);
|
||||
Assert.Equal(expectedParseInfo[2], actual.Chapters);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData("/manga/Btooom!/Vol.1/Chapter 1/1.cbz", "Btooom!")]
|
||||
[InlineData("/manga/Btooom!/Vol.1 Chapter 2/1.cbz", "Btooom!")]
|
||||
[InlineData("/manga/Monster #8 (Digital)/Ch. 001-016 [MangaPlus] [Digital] [amit34521]/Monster #8 Ch. 001 [MangaPlus] [Digital] [amit34521]/13.jpg", "manga")]
|
||||
[InlineData("/manga/Monster (Digital)/Ch. 001-016 [MangaPlus] [Digital] [amit34521]/Monster Ch. 001 [MangaPlus] [Digital] [amit34521]/13.jpg", "Monster")]
|
||||
[InlineData("/manga/Foo 50/Specials/Foo 50 SP01.cbz", "Foo 50")]
|
||||
[InlineData("/manga/Foo 50 (kiraa)/Specials/Foo 50 SP01.cbz", "Foo 50")]
|
||||
[InlineData("/manga/Btooom!/Specials/Just a special SP01.cbz", "Btooom!")]
|
||||
public void ParseFromFallbackFolders_ShouldUseExistingSeriesName(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<ILogger<DirectoryService>>(), fs);
|
||||
var parser = new BasicParser(ds, new ImageParser(ds));
|
||||
var actual = parser.Parse(inputFile, rootDirectory, rootDirectory, LibraryType.Manga, null);
|
||||
_defaultParser.ParseFromFallbackFolders(inputFile, rootDirectory, LibraryType.Manga, ref actual);
|
||||
Assert.Equal(expectedParseInfo, actual.Series);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData("/manga/Btooom!/Specials/Art Book.cbz", "Btooom!")]
|
||||
[InlineData("/manga/Hajime no Ippo/Artbook/Hajime no Ippo - Artbook.cbz", "Hajime no Ippo")]
|
||||
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<ILogger<DirectoryService>>(), fs);
|
||||
var parser = new BasicParser(ds, new ImageParser(ds));
|
||||
var actual = parser.Parse(inputFile, rootDirectory, rootDirectory, LibraryType.Manga, null);
|
||||
_defaultParser.ParseFromFallbackFolders(inputFile, rootDirectory, LibraryType.Manga, ref actual);
|
||||
Assert.Equal(expectedParseInfo, actual.Series);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
#region Parse
|
||||
|
||||
|
||||
[Fact]
|
||||
public void Parse_ParseInfo_Manga()
|
||||
{
|
||||
const string rootPath = @"E:/Manga/";
|
||||
var expected = new Dictionary<string, ParserInfo>();
|
||||
|
||||
var filepath = @"E:/Manga/Mujaki no Rakuen/Mujaki no Rakuen Vol12 ch76.cbz";
|
||||
expected.Add(filepath, new ParserInfo
|
||||
{
|
||||
Series = "Mujaki no Rakuen", Volumes = "12",
|
||||
Chapters = "76", Filename = "Mujaki no Rakuen Vol12 ch76.cbz", Format = MangaFormat.Archive,
|
||||
FullFilePath = filepath
|
||||
});
|
||||
|
||||
filepath = @"E:/Manga/Shimoneta to Iu Gainen ga Sonzai Shinai Taikutsu na Sekai Man-hen/Vol 1.cbz";
|
||||
expected.Add(filepath, new ParserInfo
|
||||
{
|
||||
Series = "Shimoneta to Iu Gainen ga Sonzai Shinai Taikutsu na Sekai Man-hen", Volumes = "1",
|
||||
Chapters = API.Services.Tasks.Scanner.Parser.Parser.DefaultChapter, Filename = "Vol 1.cbz", Format = MangaFormat.Archive,
|
||||
FullFilePath = filepath
|
||||
});
|
||||
|
||||
filepath = @"E:\Manga\Beelzebub\Beelzebub_01_[Noodles].zip";
|
||||
expected.Add(filepath, new ParserInfo
|
||||
{
|
||||
Series = "Beelzebub", Volumes = Parser.LooseLeafVolume,
|
||||
Chapters = "1", Filename = "Beelzebub_01_[Noodles].zip", Format = MangaFormat.Archive,
|
||||
FullFilePath = filepath
|
||||
});
|
||||
|
||||
// Note: Lots of duplicates here. I think I can move them to the ParserTests itself
|
||||
filepath = @"E:\Manga\Ichinensei ni Nacchattara\Ichinensei_ni_Nacchattara_v01_ch01_[Taruby]_v1.1.zip";
|
||||
expected.Add(filepath, new ParserInfo
|
||||
{
|
||||
Series = "Ichinensei ni Nacchattara", Volumes = "1",
|
||||
Chapters = "1", Filename = "Ichinensei_ni_Nacchattara_v01_ch01_[Taruby]_v1.1.zip", Format = MangaFormat.Archive,
|
||||
FullFilePath = filepath
|
||||
});
|
||||
|
||||
filepath = @"E:\Manga\Tenjo Tenge (Color)\Tenjo Tenge {Full Contact Edition} v01 (2011) (Digital) (ASTC).cbz";
|
||||
expected.Add(filepath, new ParserInfo
|
||||
{
|
||||
Series = "Tenjo Tenge {Full Contact Edition}", Volumes = "1", Edition = "",
|
||||
Chapters = API.Services.Tasks.Scanner.Parser.Parser.DefaultChapter, Filename = "Tenjo Tenge {Full Contact Edition} v01 (2011) (Digital) (ASTC).cbz", Format = MangaFormat.Archive,
|
||||
FullFilePath = filepath
|
||||
});
|
||||
|
||||
filepath = @"E:\Manga\Akame ga KILL! ZERO (2016-2019) (Digital) (LuCaZ)\Akame ga KILL! ZERO v01 (2016) (Digital) (LuCaZ).cbz";
|
||||
expected.Add(filepath, new ParserInfo
|
||||
{
|
||||
Series = "Akame ga KILL! ZERO", Volumes = "1", Edition = "",
|
||||
Chapters = API.Services.Tasks.Scanner.Parser.Parser.DefaultChapter, Filename = "Akame ga KILL! ZERO v01 (2016) (Digital) (LuCaZ).cbz", Format = MangaFormat.Archive,
|
||||
FullFilePath = filepath
|
||||
});
|
||||
|
||||
filepath = @"E:\Manga\Dorohedoro\Dorohedoro v01 (2010) (Digital) (LostNerevarine-Empire).cbz";
|
||||
expected.Add(filepath, new ParserInfo
|
||||
{
|
||||
Series = "Dorohedoro", Volumes = "1", Edition = "",
|
||||
Chapters = API.Services.Tasks.Scanner.Parser.Parser.DefaultChapter, Filename = "Dorohedoro v01 (2010) (Digital) (LostNerevarine-Empire).cbz", Format = MangaFormat.Archive,
|
||||
FullFilePath = filepath
|
||||
});
|
||||
|
||||
filepath = @"E:\Manga\APOSIMZ\APOSIMZ 040 (2020) (Digital) (danke-Empire).cbz";
|
||||
expected.Add(filepath, new ParserInfo
|
||||
{
|
||||
Series = "APOSIMZ", Volumes = API.Services.Tasks.Scanner.Parser.Parser.LooseLeafVolume, Edition = "",
|
||||
Chapters = "40", Filename = "APOSIMZ 040 (2020) (Digital) (danke-Empire).cbz", Format = MangaFormat.Archive,
|
||||
FullFilePath = filepath
|
||||
});
|
||||
|
||||
filepath = @"E:\Manga\Corpse Party Musume\Kedouin Makoto - Corpse Party Musume, Chapter 09.cbz";
|
||||
expected.Add(filepath, new ParserInfo
|
||||
{
|
||||
Series = "Kedouin Makoto - Corpse Party Musume", Volumes = API.Services.Tasks.Scanner.Parser.Parser.LooseLeafVolume, Edition = "",
|
||||
Chapters = "9", Filename = "Kedouin Makoto - Corpse Party Musume, Chapter 09.cbz", Format = MangaFormat.Archive,
|
||||
FullFilePath = filepath
|
||||
});
|
||||
|
||||
filepath = @"E:\Manga\Goblin Slayer\Goblin Slayer - Brand New Day 006.5 (2019) (Digital) (danke-Empire).cbz";
|
||||
expected.Add(filepath, new ParserInfo
|
||||
{
|
||||
Series = "Goblin Slayer - Brand New Day", Volumes = API.Services.Tasks.Scanner.Parser.Parser.LooseLeafVolume, Edition = "",
|
||||
Chapters = "6.5", Filename = "Goblin Slayer - Brand New Day 006.5 (2019) (Digital) (danke-Empire).cbz", Format = MangaFormat.Archive,
|
||||
FullFilePath = filepath
|
||||
});
|
||||
|
||||
filepath = @"E:\Manga\Summer Time Rendering\Specials\Record 014 (between chapter 083 and ch084) SP11.cbr";
|
||||
expected.Add(filepath, new ParserInfo
|
||||
{
|
||||
Series = "Summer Time Rendering", Volumes = API.Services.Tasks.Scanner.Parser.Parser.SpecialVolume, Edition = "",
|
||||
Chapters = API.Services.Tasks.Scanner.Parser.Parser.DefaultChapter, Filename = "Record 014 (between chapter 083 and ch084) SP11.cbr", Format = MangaFormat.Archive,
|
||||
FullFilePath = filepath, IsSpecial = true
|
||||
});
|
||||
|
||||
filepath = @"E:\Manga\Seraph of the End\Seraph of the End - Vampire Reign 093 (2020) (Digital) (LuCaZ).cbz";
|
||||
expected.Add(filepath, new ParserInfo
|
||||
{
|
||||
Series = "Seraph of the End - Vampire Reign", Volumes = API.Services.Tasks.Scanner.Parser.Parser.LooseLeafVolume, Edition = "",
|
||||
Chapters = "93", Filename = "Seraph of the End - Vampire Reign 093 (2020) (Digital) (LuCaZ).cbz", Format = MangaFormat.Archive,
|
||||
FullFilePath = filepath, IsSpecial = false
|
||||
});
|
||||
|
||||
filepath = @"E:\Manga\Kono Subarashii Sekai ni Bakuen wo!\Vol. 00 Ch. 000.cbz";
|
||||
expected.Add(filepath, new ParserInfo
|
||||
{
|
||||
Series = "Kono Subarashii Sekai ni Bakuen wo!", Volumes = "0", Edition = "",
|
||||
Chapters = "0", Filename = "Vol. 00 Ch. 000.cbz", Format = MangaFormat.Archive,
|
||||
FullFilePath = filepath, IsSpecial = false
|
||||
});
|
||||
|
||||
filepath = @"E:\Manga\Toukyou Akazukin\Vol. 01 Ch. 001.cbz";
|
||||
expected.Add(filepath, new ParserInfo
|
||||
{
|
||||
Series = "Toukyou Akazukin", Volumes = "1", Edition = "",
|
||||
Chapters = "1", Filename = "Vol. 01 Ch. 001.cbz", Format = MangaFormat.Archive,
|
||||
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);
|
||||
|
||||
filepath = @"E:\Manga\The Beginning After the End\Chapter 001.cbz";
|
||||
expected.Add(filepath, new ParserInfo
|
||||
{
|
||||
Series = "The Beginning After the End", Volumes = API.Services.Tasks.Scanner.Parser.Parser.LooseLeafVolume, Edition = "",
|
||||
Chapters = "1", Filename = "Chapter 001.cbz", Format = MangaFormat.Archive,
|
||||
FullFilePath = filepath, IsSpecial = false
|
||||
});
|
||||
|
||||
filepath = @"E:\Manga\Air Gear\Air Gear Omnibus v01 (2016) (Digital) (Shadowcat-Empire).cbz";
|
||||
expected.Add(filepath, new ParserInfo
|
||||
{
|
||||
Series = "Air Gear", Volumes = "1", Edition = "Omnibus",
|
||||
Chapters = API.Services.Tasks.Scanner.Parser.Parser.DefaultChapter, Filename = "Air Gear Omnibus v01 (2016) (Digital) (Shadowcat-Empire).cbz", Format = MangaFormat.Archive,
|
||||
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 = API.Services.Tasks.Scanner.Parser.Parser.DefaultChapter, 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)
|
||||
{
|
||||
var expectedInfo = expected[file];
|
||||
var actual = _defaultParser.Parse(file, rootPath, rootPath, LibraryType.Manga, null);
|
||||
if (expectedInfo == null)
|
||||
{
|
||||
Assert.Null(actual);
|
||||
continue;
|
||||
}
|
||||
Assert.NotNull(actual);
|
||||
_testOutputHelper.WriteLine($"Validating {file}");
|
||||
Assert.Equal(expectedInfo.Format, actual.Format);
|
||||
_testOutputHelper.WriteLine("Format ✓");
|
||||
Assert.Equal(expectedInfo.Series, actual.Series);
|
||||
_testOutputHelper.WriteLine("Series ✓");
|
||||
Assert.Equal(expectedInfo.Chapters, actual.Chapters);
|
||||
_testOutputHelper.WriteLine("Chapters ✓");
|
||||
Assert.Equal(expectedInfo.Volumes, actual.Volumes);
|
||||
_testOutputHelper.WriteLine("Volumes ✓");
|
||||
Assert.Equal(expectedInfo.Edition, actual.Edition);
|
||||
_testOutputHelper.WriteLine("Edition ✓");
|
||||
Assert.Equal(expectedInfo.Filename, actual.Filename);
|
||||
_testOutputHelper.WriteLine("Filename ✓");
|
||||
Assert.Equal(expectedInfo.FullFilePath, actual.FullFilePath);
|
||||
_testOutputHelper.WriteLine("FullFilePath ✓");
|
||||
}
|
||||
}
|
||||
|
||||
//[Fact]
|
||||
public void Parse_ParseInfo_Manga_ImageOnly()
|
||||
{
|
||||
// Images don't have root path as E:\Manga, but rather as the path of the folder
|
||||
|
||||
// Note: Fallback to folder will parse Monster #8 and get Monster
|
||||
var filepath = @"E:\Manga\Monster #8\Ch. 001-016 [MangaPlus] [Digital] [amit34521]\Monster #8 Ch. 001 [MangaPlus] [Digital] [amit34521]\13.jpg";
|
||||
var expectedInfo2 = new ParserInfo
|
||||
{
|
||||
Series = "Monster #8", Volumes = API.Services.Tasks.Scanner.Parser.Parser.LooseLeafVolume, Edition = "",
|
||||
Chapters = "8", Filename = "13.jpg", Format = MangaFormat.Image,
|
||||
FullFilePath = filepath, IsSpecial = false
|
||||
};
|
||||
var actual2 = _defaultParser.Parse(filepath, @"E:\Manga\Monster #8", "E:/Manga", LibraryType.Manga, null);
|
||||
Assert.NotNull(actual2);
|
||||
_testOutputHelper.WriteLine($"Validating {filepath}");
|
||||
Assert.Equal(expectedInfo2.Format, actual2.Format);
|
||||
_testOutputHelper.WriteLine("Format ✓");
|
||||
Assert.Equal(expectedInfo2.Series, actual2.Series);
|
||||
_testOutputHelper.WriteLine("Series ✓");
|
||||
Assert.Equal(expectedInfo2.Chapters, actual2.Chapters);
|
||||
_testOutputHelper.WriteLine("Chapters ✓");
|
||||
Assert.Equal(expectedInfo2.Volumes, actual2.Volumes);
|
||||
_testOutputHelper.WriteLine("Volumes ✓");
|
||||
Assert.Equal(expectedInfo2.Edition, actual2.Edition);
|
||||
_testOutputHelper.WriteLine("Edition ✓");
|
||||
Assert.Equal(expectedInfo2.Filename, actual2.Filename);
|
||||
_testOutputHelper.WriteLine("Filename ✓");
|
||||
Assert.Equal(expectedInfo2.FullFilePath, actual2.FullFilePath);
|
||||
_testOutputHelper.WriteLine("FullFilePath ✓");
|
||||
|
||||
filepath = @"E:\Manga\Extra layer for no reason\Just Images the second\Vol19\ch. 186\Vol. 19 p106.gif";
|
||||
expectedInfo2 = new ParserInfo
|
||||
{
|
||||
Series = "Just Images the second", Volumes = "19", Edition = "",
|
||||
Chapters = "186", Filename = "Vol. 19 p106.gif", Format = MangaFormat.Image,
|
||||
FullFilePath = filepath, IsSpecial = false
|
||||
};
|
||||
|
||||
actual2 = _defaultParser.Parse(filepath, @"E:\Manga\Extra layer for no reason\", "E:/Manga",LibraryType.Manga, null);
|
||||
Assert.NotNull(actual2);
|
||||
_testOutputHelper.WriteLine($"Validating {filepath}");
|
||||
Assert.Equal(expectedInfo2.Format, actual2.Format);
|
||||
_testOutputHelper.WriteLine("Format ✓");
|
||||
Assert.Equal(expectedInfo2.Series, actual2.Series);
|
||||
_testOutputHelper.WriteLine("Series ✓");
|
||||
Assert.Equal(expectedInfo2.Chapters, actual2.Chapters);
|
||||
_testOutputHelper.WriteLine("Chapters ✓");
|
||||
Assert.Equal(expectedInfo2.Volumes, actual2.Volumes);
|
||||
_testOutputHelper.WriteLine("Volumes ✓");
|
||||
Assert.Equal(expectedInfo2.Edition, actual2.Edition);
|
||||
_testOutputHelper.WriteLine("Edition ✓");
|
||||
Assert.Equal(expectedInfo2.Filename, actual2.Filename);
|
||||
_testOutputHelper.WriteLine("Filename ✓");
|
||||
Assert.Equal(expectedInfo2.FullFilePath, actual2.FullFilePath);
|
||||
_testOutputHelper.WriteLine("FullFilePath ✓");
|
||||
|
||||
filepath = @"E:\Manga\Extra layer for no reason\Just Images the second\Blank Folder\Vol19\ch. 186\Vol. 19 p106.gif";
|
||||
expectedInfo2 = new ParserInfo
|
||||
{
|
||||
Series = "Just Images the second", Volumes = "19", Edition = "",
|
||||
Chapters = "186", Filename = "Vol. 19 p106.gif", Format = MangaFormat.Image,
|
||||
FullFilePath = filepath, IsSpecial = false
|
||||
};
|
||||
|
||||
actual2 = _defaultParser.Parse(filepath, @"E:\Manga\Extra layer for no reason\", "E:/Manga", LibraryType.Manga, null);
|
||||
Assert.NotNull(actual2);
|
||||
_testOutputHelper.WriteLine($"Validating {filepath}");
|
||||
Assert.Equal(expectedInfo2.Format, actual2.Format);
|
||||
_testOutputHelper.WriteLine("Format ✓");
|
||||
Assert.Equal(expectedInfo2.Series, actual2.Series);
|
||||
_testOutputHelper.WriteLine("Series ✓");
|
||||
Assert.Equal(expectedInfo2.Chapters, actual2.Chapters);
|
||||
_testOutputHelper.WriteLine("Chapters ✓");
|
||||
Assert.Equal(expectedInfo2.Volumes, actual2.Volumes);
|
||||
_testOutputHelper.WriteLine("Volumes ✓");
|
||||
Assert.Equal(expectedInfo2.Edition, actual2.Edition);
|
||||
_testOutputHelper.WriteLine("Edition ✓");
|
||||
Assert.Equal(expectedInfo2.Filename, actual2.Filename);
|
||||
_testOutputHelper.WriteLine("Filename ✓");
|
||||
Assert.Equal(expectedInfo2.FullFilePath, actual2.FullFilePath);
|
||||
_testOutputHelper.WriteLine("FullFilePath ✓");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Parse_ParseInfo_Manga_WithSpecialsFolder()
|
||||
{
|
||||
const string rootPath = @"E:/Manga/";
|
||||
var filesystem = new MockFileSystem();
|
||||
filesystem.AddDirectory("E:/Manga");
|
||||
filesystem.AddDirectory("E:/Foo 50");
|
||||
filesystem.AddDirectory("E:/Foo 50/Specials");
|
||||
filesystem.AddFile(@"E:/Manga/Foo 50/Foo 50 v1.cbz", new MockFileData(""));
|
||||
filesystem.AddFile(@"E:/Manga/Foo 50/Specials/Foo 50 SP01.cbz", new MockFileData(""));
|
||||
|
||||
var ds = new DirectoryService(Substitute.For<ILogger<DirectoryService>>(), filesystem);
|
||||
var parser = new BasicParser(ds, new ImageParser(ds));
|
||||
|
||||
var filepath = @"E:/Manga/Foo 50/Foo 50 v1.cbz";
|
||||
// There is a bad parse for series like "Foo 50", so we have parsed chapter as 50
|
||||
var expected = new ParserInfo
|
||||
{
|
||||
Series = "Foo 50", Volumes = "1",
|
||||
Chapters = "50", Filename = "Foo 50 v1.cbz", Format = MangaFormat.Archive,
|
||||
FullFilePath = filepath
|
||||
};
|
||||
|
||||
var actual = parser.Parse(filepath, rootPath, rootPath, LibraryType.Manga, null);
|
||||
|
||||
Assert.NotNull(actual);
|
||||
_testOutputHelper.WriteLine($"Validating {filepath}");
|
||||
Assert.Equal(expected.Format, actual.Format);
|
||||
_testOutputHelper.WriteLine("Format ✓");
|
||||
Assert.Equal(expected.Series, actual.Series);
|
||||
_testOutputHelper.WriteLine("Series ✓");
|
||||
Assert.Equal(expected.Chapters, actual.Chapters);
|
||||
_testOutputHelper.WriteLine("Chapters ✓");
|
||||
Assert.Equal(expected.Volumes, actual.Volumes);
|
||||
_testOutputHelper.WriteLine("Volumes ✓");
|
||||
Assert.Equal(expected.Edition, actual.Edition);
|
||||
_testOutputHelper.WriteLine("Edition ✓");
|
||||
Assert.Equal(expected.Filename, actual.Filename);
|
||||
_testOutputHelper.WriteLine("Filename ✓");
|
||||
Assert.Equal(expected.FullFilePath, actual.FullFilePath);
|
||||
_testOutputHelper.WriteLine("FullFilePath ✓");
|
||||
Assert.Equal(expected.IsSpecial, actual.IsSpecial);
|
||||
_testOutputHelper.WriteLine("IsSpecial ✓");
|
||||
|
||||
filepath = @"E:/Manga/Foo 50/Specials/Foo 50 SP01.cbz";
|
||||
expected = new ParserInfo
|
||||
{
|
||||
Series = "Foo 50", Volumes = API.Services.Tasks.Scanner.Parser.Parser.SpecialVolume, IsSpecial = true,
|
||||
Chapters = "50", Filename = "Foo 50 SP01.cbz", Format = MangaFormat.Archive,
|
||||
FullFilePath = filepath
|
||||
};
|
||||
|
||||
actual = parser.Parse(filepath, rootPath, rootPath, LibraryType.Manga, null);
|
||||
Assert.NotNull(actual);
|
||||
_testOutputHelper.WriteLine($"Validating {filepath}");
|
||||
Assert.Equal(expected.Format, actual.Format);
|
||||
_testOutputHelper.WriteLine("Format ✓");
|
||||
Assert.Equal(expected.Series, actual.Series);
|
||||
_testOutputHelper.WriteLine("Series ✓");
|
||||
Assert.Equal(expected.Chapters, actual.Chapters);
|
||||
_testOutputHelper.WriteLine("Chapters ✓");
|
||||
Assert.Equal(expected.Volumes, actual.Volumes);
|
||||
_testOutputHelper.WriteLine("Volumes ✓");
|
||||
Assert.Equal(expected.Edition, actual.Edition);
|
||||
_testOutputHelper.WriteLine("Edition ✓");
|
||||
Assert.Equal(expected.Filename, actual.Filename);
|
||||
_testOutputHelper.WriteLine("Filename ✓");
|
||||
Assert.Equal(expected.FullFilePath, actual.FullFilePath);
|
||||
_testOutputHelper.WriteLine("FullFilePath ✓");
|
||||
Assert.Equal(expected.IsSpecial, actual.IsSpecial);
|
||||
_testOutputHelper.WriteLine("IsSpecial ✓");
|
||||
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Parse_ParseInfo_Comic()
|
||||
{
|
||||
const string rootPath = "E:/Comics/";
|
||||
var expected = new Dictionary<string, ParserInfo>();
|
||||
var filepath = @"E:/Comics/Teen Titans/Teen Titans v1 Annual 01 (1967) SP01.cbr";
|
||||
expected.Add(filepath, new ParserInfo
|
||||
{
|
||||
Series = "Teen Titans", Volumes = API.Services.Tasks.Scanner.Parser.Parser.SpecialVolume,
|
||||
Chapters = API.Services.Tasks.Scanner.Parser.Parser.DefaultChapter, Filename = "Teen Titans v1 Annual 01 (1967) SP01.cbr", Format = MangaFormat.Archive,
|
||||
FullFilePath = filepath
|
||||
});
|
||||
|
||||
// Fallback test with bad naming
|
||||
filepath = @"E:\Comics\Comics\Babe\Babe Vol.1 #1-4\Babe 01.cbr";
|
||||
expected.Add(filepath, new ParserInfo
|
||||
{
|
||||
Series = "Babe", Volumes = API.Services.Tasks.Scanner.Parser.Parser.LooseLeafVolume, Edition = "",
|
||||
Chapters = "1", Filename = "Babe 01.cbr", Format = MangaFormat.Archive,
|
||||
FullFilePath = filepath, IsSpecial = false
|
||||
});
|
||||
|
||||
filepath = @"E:\Comics\Comics\Publisher\Batman the Detective (2021)\Batman the Detective - v6 - 11 - (2021).cbr";
|
||||
expected.Add(filepath, new ParserInfo
|
||||
{
|
||||
Series = "Batman the Detective", Volumes = "6", Edition = "",
|
||||
Chapters = "11", Filename = "Batman the Detective - v6 - 11 - (2021).cbr", Format = MangaFormat.Archive,
|
||||
FullFilePath = filepath, IsSpecial = false
|
||||
});
|
||||
|
||||
filepath = @"E:\Comics\Comics\Batman - The Man Who Laughs #1 (2005)\Batman - The Man Who Laughs #1 (2005).cbr";
|
||||
expected.Add(filepath, new ParserInfo
|
||||
{
|
||||
Series = "Batman - The Man Who Laughs", Volumes = API.Services.Tasks.Scanner.Parser.Parser.LooseLeafVolume, Edition = "",
|
||||
Chapters = "1", Filename = "Batman - The Man Who Laughs #1 (2005).cbr", Format = MangaFormat.Archive,
|
||||
FullFilePath = filepath, IsSpecial = false
|
||||
});
|
||||
|
||||
foreach (var file in expected.Keys)
|
||||
{
|
||||
var expectedInfo = expected[file];
|
||||
var actual = _defaultParser.Parse(file, rootPath, rootPath, LibraryType.Comic, null);
|
||||
if (expectedInfo == null)
|
||||
{
|
||||
Assert.Null(actual);
|
||||
continue;
|
||||
}
|
||||
Assert.NotNull(actual);
|
||||
_testOutputHelper.WriteLine($"Validating {file}");
|
||||
Assert.Equal(expectedInfo.Format, actual.Format);
|
||||
_testOutputHelper.WriteLine("Format ✓");
|
||||
Assert.Equal(expectedInfo.Series, actual.Series);
|
||||
_testOutputHelper.WriteLine("Series ✓");
|
||||
Assert.Equal(expectedInfo.Chapters, actual.Chapters);
|
||||
_testOutputHelper.WriteLine("Chapters ✓");
|
||||
Assert.Equal(expectedInfo.Volumes, actual.Volumes);
|
||||
_testOutputHelper.WriteLine("Volumes ✓");
|
||||
Assert.Equal(expectedInfo.Edition, actual.Edition);
|
||||
_testOutputHelper.WriteLine("Edition ✓");
|
||||
Assert.Equal(expectedInfo.Filename, actual.Filename);
|
||||
_testOutputHelper.WriteLine("Filename ✓");
|
||||
Assert.Equal(expectedInfo.FullFilePath, actual.FullFilePath);
|
||||
_testOutputHelper.WriteLine("FullFilePath ✓");
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
97
API.Tests/Parsers/ImageParserTests.cs
Normal file
97
API.Tests/Parsers/ImageParserTests.cs
Normal file
|
|
@ -0,0 +1,97 @@
|
|||
using System.IO.Abstractions.TestingHelpers;
|
||||
using API.Entities.Enums;
|
||||
using API.Services;
|
||||
using API.Services.Tasks.Scanner.Parser;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using NSubstitute;
|
||||
using Xunit;
|
||||
|
||||
namespace API.Tests.Parsers;
|
||||
|
||||
public class ImageParserTests
|
||||
{
|
||||
private readonly ImageParser _parser;
|
||||
private readonly ILogger<DirectoryService> _dsLogger = Substitute.For<ILogger<DirectoryService>>();
|
||||
private const string RootDirectory = "C:/Comics/";
|
||||
|
||||
public ImageParserTests()
|
||||
{
|
||||
var fileSystem = new MockFileSystem();
|
||||
fileSystem.AddDirectory("C:/Comics/");
|
||||
fileSystem.AddDirectory("C:/Comics/Birds of Prey (2002)");
|
||||
fileSystem.AddFile("C:/Comics/Birds of Prey/Chapter 01/01.jpg", new MockFileData(""));
|
||||
fileSystem.AddFile("C:/Comics/DC Comics/Birds of Prey/Chapter 01/01.jpg", new MockFileData(""));
|
||||
var ds = new DirectoryService(_dsLogger, fileSystem);
|
||||
_parser = new ImageParser(ds);
|
||||
}
|
||||
|
||||
#region Parse
|
||||
|
||||
/// <summary>
|
||||
/// Tests that if there is a Series Folder then Chapter folder, the code appropriately identifies the Series name and Chapter
|
||||
/// </summary>
|
||||
[Fact]
|
||||
public void Parse_SeriesWithDirectoryName()
|
||||
{
|
||||
var actual = _parser.Parse("C:/Comics/Birds of Prey/Chapter 01/01.jpg", "C:/Comics/Birds of Prey/",
|
||||
RootDirectory, LibraryType.Image, null);
|
||||
|
||||
Assert.NotNull(actual);
|
||||
Assert.Equal("Birds of Prey", actual.Series);
|
||||
Assert.Equal("1", actual.Chapters);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Tests that if there is a Series Folder only, the code appropriately identifies the Series name from folder
|
||||
/// </summary>
|
||||
[Fact]
|
||||
public void Parse_SeriesWithNoNestedChapter()
|
||||
{
|
||||
var actual = _parser.Parse("C:/Comics/Birds of Prey/Chapter 01 page 01.jpg", "C:/Comics/",
|
||||
RootDirectory, LibraryType.Image, null);
|
||||
|
||||
Assert.NotNull(actual);
|
||||
Assert.Equal("Birds of Prey", actual.Series);
|
||||
Assert.Equal(Parser.DefaultChapter, actual.Chapters);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Tests that if there is a Series Folder only, the code appropriately identifies the Series name from folder and everything else as a
|
||||
/// </summary>
|
||||
[Fact]
|
||||
public void Parse_SeriesWithLooseImages()
|
||||
{
|
||||
var actual = _parser.Parse("C:/Comics/Birds of Prey/page 01.jpg", "C:/Comics/",
|
||||
RootDirectory, LibraryType.Image, null);
|
||||
|
||||
Assert.NotNull(actual);
|
||||
Assert.Equal("Birds of Prey", actual.Series);
|
||||
Assert.Equal(Parser.DefaultChapter, actual.Chapters);
|
||||
Assert.True(actual.IsSpecial);
|
||||
}
|
||||
|
||||
|
||||
#endregion
|
||||
|
||||
#region IsApplicable
|
||||
/// <summary>
|
||||
/// Tests that this Parser can only be used on images and Image library type
|
||||
/// </summary>
|
||||
[Fact]
|
||||
public void IsApplicable_Fails_WhenNonMatchingLibraryType()
|
||||
{
|
||||
Assert.False(_parser.IsApplicable("something.cbz", LibraryType.Manga));
|
||||
Assert.False(_parser.IsApplicable("something.cbz", LibraryType.Image));
|
||||
Assert.False(_parser.IsApplicable("something.epub", LibraryType.Image));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Tests that this Parser can only be used on images and Image library type
|
||||
/// </summary>
|
||||
[Fact]
|
||||
public void IsApplicable_Success_WhenMatchingLibraryType()
|
||||
{
|
||||
Assert.True(_parser.IsApplicable("something.png", LibraryType.Image));
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
71
API.Tests/Parsers/PdfParserTests.cs
Normal file
71
API.Tests/Parsers/PdfParserTests.cs
Normal file
|
|
@ -0,0 +1,71 @@
|
|||
using System.IO.Abstractions.TestingHelpers;
|
||||
using API.Entities.Enums;
|
||||
using API.Services;
|
||||
using API.Services.Tasks.Scanner.Parser;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using NSubstitute;
|
||||
using Xunit;
|
||||
|
||||
namespace API.Tests.Parsers;
|
||||
|
||||
public class PdfParserTests
|
||||
{
|
||||
private readonly PdfParser _parser;
|
||||
private readonly ILogger<DirectoryService> _dsLogger = Substitute.For<ILogger<DirectoryService>>();
|
||||
private const string RootDirectory = "C:/Books/";
|
||||
|
||||
public PdfParserTests()
|
||||
{
|
||||
var fileSystem = new MockFileSystem();
|
||||
fileSystem.AddDirectory("C:/Books/");
|
||||
fileSystem.AddDirectory("C:/Books/Birds of Prey (2002)");
|
||||
fileSystem.AddFile("C:/Books/A Dictionary of Japanese Food - Ingredients and Culture/A Dictionary of Japanese Food - Ingredients and Culture.pdf", new MockFileData(""));
|
||||
fileSystem.AddFile("C:/Comics/DC Comics/Birds of Prey/Chapter 01/01.jpg", new MockFileData(""));
|
||||
var ds = new DirectoryService(_dsLogger, fileSystem);
|
||||
_parser = new PdfParser(ds);
|
||||
}
|
||||
|
||||
#region Parse
|
||||
|
||||
/// <summary>
|
||||
/// Tests that if there is a Series Folder then Chapter folder, the code appropriately identifies the Series name and Chapter
|
||||
/// </summary>
|
||||
[Fact]
|
||||
public void Parse_Book_SeriesWithDirectoryName()
|
||||
{
|
||||
var actual = _parser.Parse("C:/Books/A Dictionary of Japanese Food - Ingredients and Culture/A Dictionary of Japanese Food - Ingredients and Culture.pdf",
|
||||
"C:/Books/A Dictionary of Japanese Food - Ingredients and Culture/",
|
||||
RootDirectory, LibraryType.Book, null);
|
||||
|
||||
Assert.NotNull(actual);
|
||||
Assert.Equal("A Dictionary of Japanese Food - Ingredients and Culture", actual.Series);
|
||||
Assert.Equal(Parser.DefaultChapter, actual.Chapters);
|
||||
Assert.True(actual.IsSpecial);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region IsApplicable
|
||||
/// <summary>
|
||||
/// Tests that this Parser can only be used on pdfs
|
||||
/// </summary>
|
||||
[Fact]
|
||||
public void IsApplicable_Fails_WhenNonMatchingLibraryType()
|
||||
{
|
||||
Assert.False(_parser.IsApplicable("something.cbz", LibraryType.Manga));
|
||||
Assert.False(_parser.IsApplicable("something.cbz", LibraryType.Image));
|
||||
Assert.False(_parser.IsApplicable("something.epub", LibraryType.Image));
|
||||
Assert.False(_parser.IsApplicable("something.png", LibraryType.Book));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Tests that this Parser can only be used on pdfs
|
||||
/// </summary>
|
||||
[Fact]
|
||||
public void IsApplicable_Success_WhenMatchingLibraryType()
|
||||
{
|
||||
Assert.True(_parser.IsApplicable("something.pdf", LibraryType.Book));
|
||||
Assert.True(_parser.IsApplicable("something.pdf", LibraryType.Manga));
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue