Added abstraction layeer IHtmlLoader. Finished reorganizing test project folder structure.

This commit is contained in:
2025-06-09 00:09:59 -04:00
parent b5d22c3c7e
commit c26ed11bfc
30 changed files with 1966 additions and 132 deletions

View File

@@ -13,16 +13,17 @@
<None Remove="Sources\MangaDex\Api\Manga-Chapter-Response.json" />
<None Remove="Sources\MangaDex\Api\Manga-Cover-Art-Response.json" />
<None Remove="Sources\MangaDex\Api\Manga-Search-Response-2.json" />
<None Remove="Sources\NatoManga\Api\Manga-Chapter-Response.html" />
<None Remove="WebCrawlers\Samples\MangaNato - Please Go Home, Akutsu-San!.htm" />
</ItemGroup>
<ItemGroup>
<Content Include="WebCrawlers\NatoManga\SampleMangaPage.html">
<EmbeddedResource Include="Sources\NatoManga\Metadata\Manga-Response.html">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Include="WebCrawlers\Samples\MangaNato - Please Go Home, Akutsu-San!.htm">
</EmbeddedResource>
<EmbeddedResource Include="Sources\MangaNato\Metadata\Manga-Response.html">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
</EmbeddedResource>
</ItemGroup>
<ItemGroup>
@@ -30,6 +31,7 @@
<EmbeddedResource Include="Sources\MangaDex\Api\Manga-Cover-Art-Response.json" />
<EmbeddedResource Include="Sources\MangaDex\Api\Manga-Search-Response-2.json" />
<EmbeddedResource Include="Sources\MangaDex\Api\Manga-Search-Response.json" />
<EmbeddedResource Include="Sources\NatoManga\Metadata\Manga-Chapter-Response.html" />
<EmbeddedResource Include="Sources\NatoManga\Api\Manga-Search-Response.json" />
<EmbeddedResource Include="Sources\MangaDex\Api\Manga-Feed-Response.json" />
<EmbeddedResource Include="Sources\MangaDex\Api\Manga-Response.json" />
@@ -59,4 +61,9 @@
<Using Include="Xunit" />
</ItemGroup>
<ItemGroup>
<Folder Include="WebCrawlers\NatoManga\" />
<Folder Include="WebCrawlers\Samples\" />
</ItemGroup>
</Project>

View File

@@ -17,12 +17,16 @@ public class MangaPipelineTests(TestDbContextFactory factory) : IClassFixture<Te
var sourceManga = new SourceManga
{
Title = "Fullmetal Alchemist",
Title = new()
{
Name = "Fullmetal Alchemist",
Language = Language.English
},
AlternateTitles =
[
new()
{
Title = "Hagane no Renkinjutsushi",
Name = "Hagane no Renkinjutsushi",
Language = Language.Romaji
}
],
@@ -49,7 +53,10 @@ public class MangaPipelineTests(TestDbContextFactory factory) : IClassFixture<Te
await pipeline.RunAsync(request);
context.Mangas.ShouldHaveSingleItem();
context.MangaTitles.ShouldHaveSingleItem();
context.MangaTitles.Count().ShouldBe(2);
context.MangaTitles.Where(mt => mt.IsPrimary).ShouldHaveSingleItem();
context.MangaTitles.Where(mt => mt.IsPrimary).First().Name.ShouldBe("Fullmetal Alchemist");
context.MangaTitles.Where(mt => mt.IsPrimary).First().Language.ShouldBe(Language.English);
context.Genres.Count().ShouldBe(2);
context.MangaChapters.ShouldHaveSingleItem();
}

View File

@@ -1,4 +1,4 @@
using MangaReader.Core.HttpService;
using MangaReader.Core.Http;
using MangaReader.Core.Sources.MangaDex.Api;
using MangaReader.Tests.Utilities;
using NSubstitute;

View File

@@ -229,23 +229,23 @@ public class MangaDexMetadataTests
SourceManga? sourceManga = await metadataProvider.GetMangaAsync("https://mangadex.org/title/ee96e2b7-9af2-4864-9656-649f4d3b6fec/gals-can-t-be-kind-to-otaku", CancellationToken.None);
sourceManga.ShouldNotBeNull();
sourceManga.Title.ShouldBe("Gals Cant Be Kind to Otaku!?");
sourceManga.Title.Name.ShouldBe("Gals Cant Be Kind to Otaku!?");
sourceManga.AlternateTitles.Count.ShouldBe(5);
sourceManga.AlternateTitles[0].Title.ShouldBe("オタクに優しいギャルはいない!?");
sourceManga.AlternateTitles[0].Name.ShouldBe("オタクに優しいギャルはいない!?");
sourceManga.AlternateTitles[0].Language.ShouldBe(Language.Japanese);
sourceManga.AlternateTitles[1].Title.ShouldBe("Otaku ni Yasashii Gal wa Inai!?");
sourceManga.AlternateTitles[1].Name.ShouldBe("Otaku ni Yasashii Gal wa Inai!?");
sourceManga.AlternateTitles[1].Language.ShouldBe(Language.Romaji);
sourceManga.AlternateTitles[2].Title.ShouldBe("Otaku ni Yasashii Gyaru ha Inai!?");
sourceManga.AlternateTitles[2].Name.ShouldBe("Otaku ni Yasashii Gyaru ha Inai!?");
sourceManga.AlternateTitles[2].Language.ShouldBe(Language.Romaji);
sourceManga.AlternateTitles[3].Title.ShouldBe("Gal Can't Be Kind to Otaku!?");
sourceManga.AlternateTitles[3].Name.ShouldBe("Gal Can't Be Kind to Otaku!?");
sourceManga.AlternateTitles[3].Language.ShouldBe(Language.English);
sourceManga.AlternateTitles[4].Title.ShouldBe("Gals Can't Be Kind To A Geek!?");
sourceManga.AlternateTitles[4].Name.ShouldBe("Gals Can't Be Kind To A Geek!?");
sourceManga.AlternateTitles[4].Language.ShouldBe(Language.English);
sourceManga.Genres.Count.ShouldBe(5);

View File

@@ -1,47 +1,35 @@
using HtmlAgilityPack;
using MangaReader.Core.Http;
using MangaReader.Core.Metadata;
using MangaReader.Core.Sources.MangaNato.Metadata;
using MangaReader.Tests.Utilities;
using NSubstitute;
using Shouldly;
using System.Data;
using System.Xml.Linq;
namespace MangaReader.Tests.WebCrawlers;
namespace MangaReader.Tests.Sources.MangaNato.Metadata;
public class UnitTest1
public class MangaNatoMetadataTests
{
class TestMangaNatoWebCrawler : MangaNatoWebCrawler
{
protected override Task<HtmlDocument> GetHtmlDocumentAsync(string url, CancellationToken cancellationToken)
{
HtmlWeb web = new()
{
UsingCacheIfExists = false
};
return Task.FromResult(web.Load(url));
}
}
private readonly string samplesPath;
private readonly string mangaNatoSampleFilePath;
public UnitTest1()
{
samplesPath = Path.Combine(AppContext.BaseDirectory, "WebCrawlers", "Samples");
mangaNatoSampleFilePath = Path.Combine(samplesPath, "MangaNato - Please Go Home, Akutsu-San!.htm");
}
[Fact]
public async Task Get_Manga()
{
var webCrawler = new TestMangaNatoWebCrawler();
var manga = await webCrawler.GetMangaAsync(mangaNatoSampleFilePath, CancellationToken.None);
string mangaHtml = await ReadJsonResourceAsync("Manga-Response.html");
IHttpService httpService = Substitute.For<IHttpService>();
httpService.GetStringAsync(Arg.Any<string>(), CancellationToken.None)
.Returns(Task.FromResult(mangaHtml));
HtmlLoader htmlLoader = new(httpService);
MangaNatoWebCrawler webCrawler = new(htmlLoader);
SourceManga? manga = await webCrawler.GetMangaAsync("/test-url", CancellationToken.None);
manga.ShouldNotBeNull();
manga.Title.ShouldBe("Please Go Home, Akutsu-San!");
manga.Title.Name.ShouldBe("Please Go Home, Akutsu-San!");
manga.AlternateTitles.Select(x => x.Title).ShouldBe([
manga.AlternateTitles.Select(x => x.Name).ShouldBe([
"Kaette kudasai! Akutsu-san",
"Yankee Musume",
"ヤンキー娘",
@@ -62,8 +50,8 @@ public class UnitTest1
manga.Votes.ShouldBe(15979);
//manga.Description.ShouldStartWith("Ooyama-kun normally doesnt get involved with Akutsu-san, a delinquent girl in his class");
manga.Description.ShouldStartWith("Ooyama-kun normally doesnt get involved with Akutsu-san, a delinquent girl in his class");
manga.Description.ShouldEndWith("Artist's Pixiv: https://www.pixiv.net/member.php?id=133935");
manga.Description?.Name.ShouldStartWith("Ooyama-kun normally doesnt get involved with Akutsu-san, a delinquent girl in his class");
manga.Description?.Name.ShouldEndWith("Artist's Pixiv: https://www.pixiv.net/member.php?id=133935");
manga.Chapters.Count.ShouldBe(236);
@@ -79,4 +67,9 @@ public class UnitTest1
manga.Chapters[235].Views.ShouldBe(232_200);
manga.Chapters[235].UploadDate.ShouldBe(new DateTime(2021, 8, 24, 1, 8, 0));
}
private static async Task<string> ReadJsonResourceAsync(string resourceName)
{
return await ResourceHelper.ReadJsonResourceAsync($"MangaReader.Tests.Sources.MangaNato.Metadata.{resourceName}");
}
}

View File

@@ -1,4 +1,4 @@
using MangaReader.Core.HttpService;
using MangaReader.Core.Http;
using MangaReader.Core.Sources.NatoManga.Api;
using MangaReader.Tests.Utilities;
using NSubstitute;
@@ -34,6 +34,9 @@ public class NatoMangaClientTests
httpService.GetStringAsync(Arg.Any<string>(), CancellationToken.None)
.Returns(Task.FromResult(searchResultJson));
httpService.GetStringAsync(Arg.Any<string>(), Arg.Any<IDictionary<string,string>>(), CancellationToken.None)
.Returns(Task.FromResult(searchResultJson));
NatoMangaClient natoMangaClient = new(httpService);
NatoMangaSearchResult[] searchResults = await natoMangaClient.SearchAsync("Gal Can't Be Kind", CancellationToken.None);

File diff suppressed because one or more lines are too long

View File

@@ -1,35 +1,32 @@
using HtmlAgilityPack;
using MangaReader.Core.Http;
using MangaReader.Core.Metadata;
using MangaReader.Core.Sources.NatoManga.Metadata;
using MangaReader.Tests.Utilities;
using NSubstitute;
using Shouldly;
namespace MangaReader.Tests.WebCrawlers.NatoManga;
namespace MangaReader.Tests.Sources.NatoManga.Metadata;
public class NatoMangaWebCrawlerTests
{
class TestNatoMangaWebCrawler : NatoMangaWebCrawler
{
protected override Task<HtmlDocument> GetHtmlDocumentAsync(string url, CancellationToken cancellationToken)
{
HtmlWeb web = new()
{
UsingCacheIfExists = false
};
return Task.FromResult(web.Load(url));
}
}
[Fact]
public async Task Get_Manga()
{
string sampleFilePath = Path.Combine(AppContext.BaseDirectory, "WebCrawlers", "NatoManga", "SampleMangaPage.html");
string mangaHtml = await ReadJsonResourceAsync("Manga-Response.html");
var webCrawler = new TestNatoMangaWebCrawler();
var manga = await webCrawler.GetMangaAsync(sampleFilePath, CancellationToken.None);
IHttpService httpService = Substitute.For<IHttpService>();
httpService.GetStringAsync(Arg.Any<string>(), CancellationToken.None)
.Returns(Task.FromResult(mangaHtml));
HtmlLoader htmlLoader = new(httpService);
NatoMangaWebCrawler webCrawler = new(htmlLoader);
SourceManga? manga = await webCrawler.GetMangaAsync("/test-url", CancellationToken.None);
manga.ShouldNotBeNull();
manga.Title.ShouldBe("Gal Cant Be Kind to Otaku!?");
manga.Title.Name.ShouldBe("Gal Cant Be Kind to Otaku!?");
//manga.AlternateTitles.ShouldBe([
// "Kaette kudasai! Akutsu-san",
@@ -63,4 +60,9 @@ public class NatoMangaWebCrawlerTests
//manga.Chapters[235].Views.ShouldBe(232_200);
//manga.Chapters[235].UploadDate.ShouldBe(new DateTime(2021, 8, 24, 1, 8, 0));
}
private static async Task<string> ReadJsonResourceAsync(string resourceName)
{
return await ResourceHelper.ReadJsonResourceAsync($"MangaReader.Tests.Sources.NatoManga.Metadata.{resourceName}");
}
}