.NET 7 + Spring Cleaning (#1677)

* Updated to net7.0

* Updated GA to .net 7

* Updated System.IO.Abstractions to use New factory.

* Converted Regex into SourceGenerator in Parser.

* Updated more regex to source generators.

* Enabled Nullability and more regex changes throughout codebase.

* Parser is 100% GeneratedRegexified

* Lots of nullability code

* Enabled nullability for all repositories.

* Fixed another unit test

* Refactored some code around and took care of some todos.

* Updating code for nullability and cleaning up methods that aren't used anymore. Refctored all uses of Parser.Normalize() to use new extension

* More nullability exercises. 500 warnings to go.

* Fixed a bug where custom file uploads for entities wouldn't save in webP.

* Nullability is done for all DTOs

* Fixed all unit tests and nullability for the project. Only OPDS is left which will be done with an upcoming OPDS enhancement.

* Use localization in book service after validating

* Code smells

* Switched to preview build of swashbuckle for .net7 support

* Fixed up merge issues

* Disable emulate comic book when on single page reader

* Fixed a regression where double page renderer wouldn't layout the images correctly

* Updated to swashbuckle which support .net 7

* Fixed a bad GA action

* Some code cleanup

* More code smells

* Took care of most of nullable issues

* Fixed a broken test due to having more than one test run in parallel

* I'm really not sure why the unit tests are failing or are so extremely slow on .net 7

* Updated all dependencies

* Fixed up build and removed hardcoded framework from build scripts. (this merge removes Regex Source generators). Unit tests are completely busted.

* Unit tests and code cleanup. Needs shakeout now.

* Adjusted Series model since a few fields are not-nullable. Removed dead imports on the project.

* Refactored to use Builder pattern for all unit tests.

* Switched nullability down to warnings. It wasn't possible to switch due to constraint issues in DB Migration.
This commit is contained in:
Joe Milazzo 2023-03-05 14:55:13 -06:00 committed by GitHub
parent 76fe3fd64a
commit 5d1dd7b3f0
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
283 changed files with 4221 additions and 4593 deletions

View file

@ -3,124 +3,31 @@ using System.Linq;
using API.Comparators;
using API.Entities;
using API.Entities.Enums;
using API.Entities.Metadata;
using API.Extensions;
using API.Parser;
using API.Services.Tasks.Scanner;
using API.Tests.Helpers.Builders;
using Xunit;
namespace API.Tests.Extensions;
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)
{
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()
};
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)
{
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 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 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<Volume>()
{
new Volume()
{
Number = 0,
Name = API.Services.Tasks.Scanner.Parser.Parser.DefaultVolume,
Chapters = new List<Chapter>()
{
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",
}
},
}
}
};
var series = new SeriesBuilder("Test 1")
.WithFormat(MangaFormat.Archive)
.WithVolume(new VolumeBuilder("0")
.WithName(API.Services.Tasks.Scanner.Parser.Parser.DefaultVolume)
.WithChapter(new ChapterBuilder(API.Services.Tasks.Scanner.Parser.Parser.DefaultChapter)
.WithCoverImage("Special 1")
.WithIsSpecial(true)
.Build())
.WithChapter(new ChapterBuilder(API.Services.Tasks.Scanner.Parser.Parser.DefaultChapter)
.WithCoverImage("Special 2")
.WithIsSpecial(true)
.Build())
.Build())
.Build();
Assert.Equal("Special 1", series.GetCoverImage());
@ -129,33 +36,20 @@ public class SeriesExtensionsTests
[Fact]
public void GetCoverImage_MultipleSpecials_Books()
{
var series = new Series()
{
Format = MangaFormat.Epub,
Volumes = new List<Volume>()
{
new Volume()
{
Number = 0,
Name = API.Services.Tasks.Scanner.Parser.Parser.DefaultVolume,
Chapters = new List<Chapter>()
{
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",
}
},
}
}
};
var series = new SeriesBuilder("Test 1")
.WithFormat(MangaFormat.Archive)
.WithVolume(new VolumeBuilder("0")
.WithName(API.Services.Tasks.Scanner.Parser.Parser.DefaultVolume)
.WithChapter(new ChapterBuilder(API.Services.Tasks.Scanner.Parser.Parser.DefaultChapter)
.WithCoverImage("Special 1")
.WithIsSpecial(true)
.Build())
.WithChapter(new ChapterBuilder(API.Services.Tasks.Scanner.Parser.Parser.DefaultChapter)
.WithCoverImage("Special 2")
.WithIsSpecial(true)
.Build())
.Build())
.Build();
Assert.Equal("Special 1", series.GetCoverImage());
}
@ -163,33 +57,20 @@ public class SeriesExtensionsTests
[Fact]
public void GetCoverImage_JustChapters_Comics()
{
var series = new Series()
{
Format = MangaFormat.Archive,
Volumes = new List<Volume>()
{
new Volume()
{
Number = 0,
Name = API.Services.Tasks.Scanner.Parser.Parser.DefaultVolume,
Chapters = new List<Chapter>()
{
new Chapter()
{
IsSpecial = false,
Number = "2.5",
CoverImage = "Special 1",
},
new Chapter()
{
IsSpecial = false,
Number = "2",
CoverImage = "Special 2",
}
},
}
}
};
var series = new SeriesBuilder("Test 1")
.WithFormat(MangaFormat.Archive)
.WithVolume(new VolumeBuilder("0")
.WithName(API.Services.Tasks.Scanner.Parser.Parser.DefaultVolume)
.WithChapter(new ChapterBuilder("2.5")
.WithIsSpecial(false)
.WithCoverImage("Special 1")
.Build())
.WithChapter(new ChapterBuilder("2")
.WithIsSpecial(false)
.WithCoverImage("Special 2")
.Build())
.Build())
.Build();
foreach (var vol in series.Volumes)
{
@ -202,39 +83,24 @@ public class SeriesExtensionsTests
[Fact]
public void GetCoverImage_JustChaptersAndSpecials_Comics()
{
var series = new Series()
{
Format = MangaFormat.Archive,
Volumes = new List<Volume>()
{
new Volume()
{
Number = 0,
Name = API.Services.Tasks.Scanner.Parser.Parser.DefaultVolume,
Chapters = new List<Chapter>()
{
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",
}
},
}
}
};
var series = new SeriesBuilder("Test 1")
.WithFormat(MangaFormat.Archive)
.WithVolume(new VolumeBuilder("0")
.WithName(API.Services.Tasks.Scanner.Parser.Parser.DefaultVolume)
.WithChapter(new ChapterBuilder("2.5")
.WithIsSpecial(false)
.WithCoverImage("Special 1")
.Build())
.WithChapter(new ChapterBuilder("2")
.WithIsSpecial(false)
.WithCoverImage("Special 2")
.Build())
.WithChapter(new ChapterBuilder("0")
.WithIsSpecial(true)
.WithCoverImage("Special 3")
.Build())
.Build())
.Build();
foreach (var vol in series.Volumes)
{
@ -247,54 +113,31 @@ public class SeriesExtensionsTests
[Fact]
public void GetCoverImage_VolumesChapters_Comics()
{
var series = new Series()
{
Format = MangaFormat.Archive,
Volumes = new List<Volume>()
{
new Volume()
{
Number = 0,
Name = API.Services.Tasks.Scanner.Parser.Parser.DefaultVolume,
Chapters = new List<Chapter>()
{
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<Chapter>()
{
new Chapter()
{
IsSpecial = false,
Number = "0",
CoverImage = "Volume 1",
},
},
}
}
};
var series = new SeriesBuilder("Test 1")
.WithFormat(MangaFormat.Archive)
.WithVolume(new VolumeBuilder("0")
.WithName(API.Services.Tasks.Scanner.Parser.Parser.DefaultVolume)
.WithChapter(new ChapterBuilder("2.5")
.WithIsSpecial(false)
.WithCoverImage("Special 1")
.Build())
.WithChapter(new ChapterBuilder("2")
.WithIsSpecial(false)
.WithCoverImage("Special 2")
.Build())
.WithChapter(new ChapterBuilder("0")
.WithIsSpecial(true)
.WithCoverImage("Special 3")
.Build())
.Build())
.WithVolume(new VolumeBuilder("1")
.WithNumber(1)
.WithChapter(new ChapterBuilder("0")
.WithIsSpecial(false)
.WithCoverImage("Volume 1")
.Build())
.Build())
.Build();
foreach (var vol in series.Volumes)
{
@ -307,54 +150,31 @@ public class SeriesExtensionsTests
[Fact]
public void GetCoverImage_VolumesChaptersAndSpecials_Comics()
{
var series = new Series()
{
Format = MangaFormat.Archive,
Volumes = new List<Volume>()
{
new Volume()
{
Number = 0,
Name = API.Services.Tasks.Scanner.Parser.Parser.DefaultVolume,
Chapters = new List<Chapter>()
{
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<Chapter>()
{
new Chapter()
{
IsSpecial = false,
Number = "0",
CoverImage = "Volume 1",
},
},
}
}
};
var series = new SeriesBuilder("Test 1")
.WithFormat(MangaFormat.Archive)
.WithVolume(new VolumeBuilder("0")
.WithName(API.Services.Tasks.Scanner.Parser.Parser.DefaultVolume)
.WithChapter(new ChapterBuilder("2.5")
.WithIsSpecial(false)
.WithCoverImage("Special 1")
.Build())
.WithChapter(new ChapterBuilder("2")
.WithIsSpecial(false)
.WithCoverImage("Special 2")
.Build())
.WithChapter(new ChapterBuilder("0")
.WithIsSpecial(true)
.WithCoverImage("Special 3")
.Build())
.Build())
.WithVolume(new VolumeBuilder("1")
.WithNumber(1)
.WithChapter(new ChapterBuilder("0")
.WithIsSpecial(false)
.WithCoverImage("Volume 1")
.Build())
.Build())
.Build();
foreach (var vol in series.Volumes)
{