diff --git a/API.Tests/Repository/GenreRepositoryTests.cs b/API.Tests/Repository/GenreRepositoryTests.cs index f8e62295b..d197a91ba 100644 --- a/API.Tests/Repository/GenreRepositoryTests.cs +++ b/API.Tests/Repository/GenreRepositoryTests.cs @@ -14,24 +14,6 @@ namespace API.Tests.Repository; public class GenreRepositoryTests : AbstractDbTest { - private static readonly Genre SharedSeriesChaptersGenre = new GenreBuilder("Shared Series Chapter Genre").Build(); - private static readonly Genre SharedSeriesGenre = new GenreBuilder("Shared Series Genre").Build(); - private static readonly Genre SharedChaptersGenre = new GenreBuilder("Shared Chapters Genre").Build(); - private static readonly Genre Lib0SeriesChaptersGenre = new GenreBuilder("Lib0 Series Chapter Genre").Build(); - private static readonly Genre Lib0SeriesGenre = new GenreBuilder("Lib0 Series Genre").Build(); - private static readonly Genre Lib0ChaptersGenre = new GenreBuilder("Lib0 Chapters Genre").Build(); - private static readonly Genre Lib1SeriesChaptersGenre = new GenreBuilder("Lib1 Series Chapter Genre").Build(); - private static readonly Genre Lib1SeriesGenre = new GenreBuilder("Lib1 Series Genre").Build(); - private static readonly Genre Lib1ChaptersGenre = new GenreBuilder("Lib1 Chapters Genre").Build(); - private static readonly Genre Lib1ChapterAgeGenre = new GenreBuilder("Lib1 Chapter Age Genre").Build(); - - private static readonly List AllGenres = - [ - SharedSeriesChaptersGenre, SharedSeriesGenre, SharedChaptersGenre, - Lib0SeriesChaptersGenre, Lib0SeriesGenre, Lib0ChaptersGenre, - Lib1SeriesChaptersGenre, Lib1SeriesGenre, Lib1ChaptersGenre, Lib1ChapterAgeGenre - ]; - private AppUser _fullAccess; private AppUser _restrictedAccess; private AppUser _restrictedAgeAccess; @@ -43,7 +25,32 @@ public class GenreRepositoryTests : AbstractDbTest await Context.SaveChangesAsync(); } - private async Task SeedDb() + private TestGenreSet CreateTestGenres() + { + return new TestGenreSet + { + SharedSeriesChaptersGenre = new GenreBuilder("Shared Series Chapter Genre").Build(), + SharedSeriesGenre = new GenreBuilder("Shared Series Genre").Build(), + SharedChaptersGenre = new GenreBuilder("Shared Chapters Genre").Build(), + Lib0SeriesChaptersGenre = new GenreBuilder("Lib0 Series Chapter Genre").Build(), + Lib0SeriesGenre = new GenreBuilder("Lib0 Series Genre").Build(), + Lib0ChaptersGenre = new GenreBuilder("Lib0 Chapters Genre").Build(), + Lib1SeriesChaptersGenre = new GenreBuilder("Lib1 Series Chapter Genre").Build(), + Lib1SeriesGenre = new GenreBuilder("Lib1 Series Genre").Build(), + Lib1ChaptersGenre = new GenreBuilder("Lib1 Chapters Genre").Build(), + Lib1ChapterAgeGenre = new GenreBuilder("Lib1 Chapter Age Genre").Build() + }; + } + + private async Task SeedDbWithGenres(TestGenreSet genres) + { + await CreateTestUsers(); + await AddGenresToContext(genres); + await CreateLibrariesWithGenres(genres); + await AssignLibrariesToUsers(); + } + + private async Task CreateTestUsers() { _fullAccess = new AppUserBuilder("amelia", "amelia@example.com").Build(); _restrictedAccess = new AppUserBuilder("mila", "mila@example.com").Build(); @@ -55,21 +62,28 @@ public class GenreRepositoryTests : AbstractDbTest Context.Users.Add(_restrictedAccess); Context.Users.Add(_restrictedAgeAccess); await Context.SaveChangesAsync(); + } - Context.Genre.AddRange(AllGenres); + private async Task AddGenresToContext(TestGenreSet genres) + { + var allGenres = genres.GetAllGenres(); + Context.Genre.AddRange(allGenres); await Context.SaveChangesAsync(); + } + private async Task CreateLibrariesWithGenres(TestGenreSet genres) + { var lib0 = new LibraryBuilder("lib0") .WithSeries(new SeriesBuilder("lib0-s0") .WithMetadata(new SeriesMetadataBuilder() - .WithGenres([SharedSeriesChaptersGenre, SharedSeriesGenre, Lib0SeriesChaptersGenre, Lib0SeriesGenre]) + .WithGenres([genres.SharedSeriesChaptersGenre, genres.SharedSeriesGenre, genres.Lib0SeriesChaptersGenre, genres.Lib0SeriesGenre]) .Build()) .WithVolume(new VolumeBuilder("1") .WithChapter(new ChapterBuilder("1") - .WithGenres([SharedSeriesChaptersGenre, SharedChaptersGenre, Lib0SeriesChaptersGenre, Lib0ChaptersGenre]) + .WithGenres([genres.SharedSeriesChaptersGenre, genres.SharedChaptersGenre, genres.Lib0SeriesChaptersGenre, genres.Lib0ChaptersGenre]) .Build()) .WithChapter(new ChapterBuilder("2") - .WithGenres([SharedSeriesChaptersGenre, SharedChaptersGenre, Lib1SeriesChaptersGenre, Lib1ChaptersGenre]) + .WithGenres([genres.SharedSeriesChaptersGenre, genres.SharedChaptersGenre, genres.Lib1SeriesChaptersGenre, genres.Lib1ChaptersGenre]) .Build()) .Build()) .Build()) @@ -78,35 +92,43 @@ public class GenreRepositoryTests : AbstractDbTest var lib1 = new LibraryBuilder("lib1") .WithSeries(new SeriesBuilder("lib1-s0") .WithMetadata(new SeriesMetadataBuilder() - .WithGenres([SharedSeriesChaptersGenre, SharedSeriesGenre, Lib1SeriesChaptersGenre, Lib1SeriesGenre]) + .WithGenres([genres.SharedSeriesChaptersGenre, genres.SharedSeriesGenre, genres.Lib1SeriesChaptersGenre, genres.Lib1SeriesGenre]) .WithAgeRating(AgeRating.Mature17Plus) .Build()) .WithVolume(new VolumeBuilder("1") .WithChapter(new ChapterBuilder("1") - .WithGenres([SharedSeriesChaptersGenre, SharedChaptersGenre, Lib1SeriesChaptersGenre, Lib1ChaptersGenre]) + .WithGenres([genres.SharedSeriesChaptersGenre, genres.SharedChaptersGenre, genres.Lib1SeriesChaptersGenre, genres.Lib1ChaptersGenre]) .Build()) .WithChapter(new ChapterBuilder("2") - .WithGenres([SharedSeriesChaptersGenre, SharedChaptersGenre, Lib1SeriesChaptersGenre, Lib1ChaptersGenre, Lib1ChapterAgeGenre]) + .WithGenres([genres.SharedSeriesChaptersGenre, genres.SharedChaptersGenre, genres.Lib1SeriesChaptersGenre, genres.Lib1ChaptersGenre, genres.Lib1ChapterAgeGenre]) .WithAgeRating(AgeRating.Mature17Plus) .Build()) .Build()) .Build()) .WithSeries(new SeriesBuilder("lib1-s1") .WithMetadata(new SeriesMetadataBuilder() - .WithGenres([SharedSeriesChaptersGenre, SharedSeriesGenre, Lib1SeriesChaptersGenre, Lib1SeriesGenre]) + .WithGenres([genres.SharedSeriesChaptersGenre, genres.SharedSeriesGenre, genres.Lib1SeriesChaptersGenre, genres.Lib1SeriesGenre]) .Build()) .WithVolume(new VolumeBuilder("1") .WithChapter(new ChapterBuilder("1") - .WithGenres([SharedSeriesChaptersGenre, SharedChaptersGenre, Lib1SeriesChaptersGenre, Lib1ChaptersGenre]) + .WithGenres([genres.SharedSeriesChaptersGenre, genres.SharedChaptersGenre, genres.Lib1SeriesChaptersGenre, genres.Lib1ChaptersGenre]) .Build()) .WithChapter(new ChapterBuilder("2") - .WithGenres([SharedSeriesChaptersGenre, SharedChaptersGenre, Lib1SeriesChaptersGenre, Lib1ChaptersGenre]) + .WithGenres([genres.SharedSeriesChaptersGenre, genres.SharedChaptersGenre, genres.Lib1SeriesChaptersGenre, genres.Lib1ChaptersGenre]) .Build()) .Build()) .Build()) .Build(); + Context.Library.Add(lib0); + Context.Library.Add(lib1); await Context.SaveChangesAsync(); + } + + private async Task AssignLibrariesToUsers() + { + var lib0 = Context.Library.First(l => l.Name == "lib0"); + var lib1 = Context.Library.First(l => l.Name == "lib1"); _fullAccess.Libraries.Add(lib0); _fullAccess.Libraries.Add(lib1); @@ -121,62 +143,138 @@ public class GenreRepositoryTests : AbstractDbTest return g => g.Id == genre.Id; } - [Fact] - public async Task GetBrowseableGenre() + private static void AssertGenrePresent(IEnumerable genres, Genre expectedGenre) { - await ResetDb(); - await SeedDb(); + Assert.Contains(genres, ContainsGenreCheck(expectedGenre)); + } + private static void AssertGenreNotPresent(IEnumerable genres, Genre expectedGenre) + { + Assert.DoesNotContain(genres, ContainsGenreCheck(expectedGenre)); + } + + private static BrowseGenreDto GetGenreDto(IEnumerable genres, Genre genre) + { + return genres.First(dto => dto.Id == genre.Id); + } + + [Fact] + public async Task GetBrowseableGenre_FullAccess_ReturnsAllGenresWithCorrectCounts() + { + // Arrange + await ResetDb(); + var genres = CreateTestGenres(); + await SeedDbWithGenres(genres); + + // Act var fullAccessGenres = await UnitOfWork.GenreRepository.GetBrowseableGenre(_fullAccess.Id, new UserParams()); - Assert.Equal(AllGenres.Count, fullAccessGenres.TotalCount); - foreach (var genre in AllGenres) + + // Assert + Assert.Equal(genres.GetAllGenres().Count, fullAccessGenres.TotalCount); + + foreach (var genre in genres.GetAllGenres()) { - Assert.Contains(fullAccessGenres, ContainsGenreCheck(genre)); + AssertGenrePresent(fullAccessGenres, genre); } - // 1 lib0 series, 2 lib1 series - Assert.Equal(3, fullAccessGenres.First(dto => dto.Id == SharedSeriesChaptersGenre.Id).SeriesCount); - Assert.Equal(6, fullAccessGenres.First(dto => dto.Id == SharedSeriesChaptersGenre.Id).ChapterCount); - Assert.Equal(1, fullAccessGenres.First(dto => dto.Id == Lib0SeriesGenre.Id).SeriesCount); + // Verify counts - 1 lib0 series, 2 lib1 series = 3 total series + Assert.Equal(3, GetGenreDto(fullAccessGenres, genres.SharedSeriesChaptersGenre).SeriesCount); + Assert.Equal(6, GetGenreDto(fullAccessGenres, genres.SharedSeriesChaptersGenre).ChapterCount); + Assert.Equal(1, GetGenreDto(fullAccessGenres, genres.Lib0SeriesGenre).SeriesCount); + } + [Fact] + public async Task GetBrowseableGenre_RestrictedAccess_ReturnsOnlyAccessibleGenres() + { + // Arrange + await ResetDb(); + var genres = CreateTestGenres(); + await SeedDbWithGenres(genres); + // Act var restrictedAccessGenres = await UnitOfWork.GenreRepository.GetBrowseableGenre(_restrictedAccess.Id, new UserParams()); + // Assert - Should see: 3 shared + 4 library 1 specific = 7 genres Assert.Equal(7, restrictedAccessGenres.TotalCount); - Assert.Contains(restrictedAccessGenres, ContainsGenreCheck(SharedSeriesChaptersGenre)); - Assert.Contains(restrictedAccessGenres, ContainsGenreCheck(SharedSeriesGenre)); - Assert.Contains(restrictedAccessGenres, ContainsGenreCheck(SharedChaptersGenre)); - Assert.Contains(restrictedAccessGenres, ContainsGenreCheck(Lib1SeriesChaptersGenre)); - Assert.Contains(restrictedAccessGenres, ContainsGenreCheck(Lib1SeriesGenre)); - Assert.Contains(restrictedAccessGenres, ContainsGenreCheck(Lib1ChaptersGenre)); - Assert.Contains(restrictedAccessGenres, ContainsGenreCheck(Lib1ChapterAgeGenre)); + // Verify shared and Library 1 genres are present + AssertGenrePresent(restrictedAccessGenres, genres.SharedSeriesChaptersGenre); + AssertGenrePresent(restrictedAccessGenres, genres.SharedSeriesGenre); + AssertGenrePresent(restrictedAccessGenres, genres.SharedChaptersGenre); + AssertGenrePresent(restrictedAccessGenres, genres.Lib1SeriesChaptersGenre); + AssertGenrePresent(restrictedAccessGenres, genres.Lib1SeriesGenre); + AssertGenrePresent(restrictedAccessGenres, genres.Lib1ChaptersGenre); + AssertGenrePresent(restrictedAccessGenres, genres.Lib1ChapterAgeGenre); - // 2 lib1 series - Assert.Equal(2, restrictedAccessGenres.First(dto => dto.Id == SharedSeriesChaptersGenre.Id).SeriesCount); - Assert.Equal(4, restrictedAccessGenres.First(dto => dto.Id == SharedSeriesChaptersGenre.Id).ChapterCount); - Assert.Equal(2, restrictedAccessGenres.First(dto => dto.Id == Lib1SeriesGenre.Id).SeriesCount); - Assert.Equal(4, restrictedAccessGenres.First(dto => dto.Id == Lib1ChaptersGenre.Id).ChapterCount); - Assert.Equal(1, restrictedAccessGenres.First(dto => dto.Id == Lib1ChapterAgeGenre.Id).ChapterCount); + // Verify Library 0 specific genres are not present + AssertGenreNotPresent(restrictedAccessGenres, genres.Lib0SeriesChaptersGenre); + AssertGenreNotPresent(restrictedAccessGenres, genres.Lib0SeriesGenre); + AssertGenreNotPresent(restrictedAccessGenres, genres.Lib0ChaptersGenre); + // Verify counts - 2 lib1 series + Assert.Equal(2, GetGenreDto(restrictedAccessGenres, genres.SharedSeriesChaptersGenre).SeriesCount); + Assert.Equal(4, GetGenreDto(restrictedAccessGenres, genres.SharedSeriesChaptersGenre).ChapterCount); + Assert.Equal(2, GetGenreDto(restrictedAccessGenres, genres.Lib1SeriesGenre).SeriesCount); + Assert.Equal(4, GetGenreDto(restrictedAccessGenres, genres.Lib1ChaptersGenre).ChapterCount); + Assert.Equal(1, GetGenreDto(restrictedAccessGenres, genres.Lib1ChapterAgeGenre).ChapterCount); + } + [Fact] + public async Task GetBrowseableGenre_RestrictedAgeAccess_FiltersAgeRestrictedContent() + { + // Arrange + await ResetDb(); + var genres = CreateTestGenres(); + await SeedDbWithGenres(genres); + + // Act var restrictedAgeAccessGenres = await UnitOfWork.GenreRepository.GetBrowseableGenre(_restrictedAgeAccess.Id, new UserParams()); + // Assert - Should see: 3 shared + 3 lib1 specific = 6 genres (age-restricted genre filtered out) Assert.Equal(6, restrictedAgeAccessGenres.TotalCount); - Assert.Contains(restrictedAccessGenres, ContainsGenreCheck(SharedSeriesChaptersGenre)); - Assert.Contains(restrictedAccessGenres, ContainsGenreCheck(SharedSeriesGenre)); - Assert.Contains(restrictedAccessGenres, ContainsGenreCheck(SharedChaptersGenre)); - Assert.Contains(restrictedAccessGenres, ContainsGenreCheck(Lib1SeriesChaptersGenre)); - Assert.Contains(restrictedAccessGenres, ContainsGenreCheck(Lib1SeriesGenre)); - Assert.Contains(restrictedAccessGenres, ContainsGenreCheck(Lib1ChaptersGenre)); - Assert.DoesNotContain(restrictedAgeAccessGenres, ContainsGenreCheck(Lib1ChapterAgeGenre)); + // Verify accessible genres are present + AssertGenrePresent(restrictedAgeAccessGenres, genres.SharedSeriesChaptersGenre); + AssertGenrePresent(restrictedAgeAccessGenres, genres.SharedSeriesGenre); + AssertGenrePresent(restrictedAgeAccessGenres, genres.SharedChaptersGenre); + AssertGenrePresent(restrictedAgeAccessGenres, genres.Lib1SeriesChaptersGenre); + AssertGenrePresent(restrictedAgeAccessGenres, genres.Lib1SeriesGenre); + AssertGenrePresent(restrictedAgeAccessGenres, genres.Lib1ChaptersGenre); - Assert.Equal(1, restrictedAgeAccessGenres.First(dto => dto.Id == SharedSeriesChaptersGenre.Id).SeriesCount); - Assert.Equal(1, restrictedAgeAccessGenres.First(dto => dto.Id == Lib1SeriesGenre.Id).SeriesCount); + // Verify age-restricted genre is filtered out + AssertGenreNotPresent(restrictedAgeAccessGenres, genres.Lib1ChapterAgeGenre); - // These values are a "bug". And should be 2, however chapters are not filtered out when their series is - Assert.Equal(3, restrictedAgeAccessGenres.First(dto => dto.Id == SharedSeriesChaptersGenre.Id).ChapterCount); - Assert.Equal(3, restrictedAgeAccessGenres.First(dto => dto.Id == Lib1ChaptersGenre.Id).ChapterCount); + // Verify counts - 1 series lib1 (age-restricted series filtered out) + Assert.Equal(1, GetGenreDto(restrictedAgeAccessGenres, genres.SharedSeriesChaptersGenre).SeriesCount); + Assert.Equal(1, GetGenreDto(restrictedAgeAccessGenres, genres.Lib1SeriesGenre).SeriesCount); + + // These values represent a bug - chapters are not properly filtered when their series is age-restricted + // Should be 2, but currently returns 3 due to the filtering issue + Assert.Equal(3, GetGenreDto(restrictedAgeAccessGenres, genres.SharedSeriesChaptersGenre).ChapterCount); + Assert.Equal(3, GetGenreDto(restrictedAgeAccessGenres, genres.Lib1ChaptersGenre).ChapterCount); + } + + private class TestGenreSet + { + public Genre SharedSeriesChaptersGenre { get; set; } + public Genre SharedSeriesGenre { get; set; } + public Genre SharedChaptersGenre { get; set; } + public Genre Lib0SeriesChaptersGenre { get; set; } + public Genre Lib0SeriesGenre { get; set; } + public Genre Lib0ChaptersGenre { get; set; } + public Genre Lib1SeriesChaptersGenre { get; set; } + public Genre Lib1SeriesGenre { get; set; } + public Genre Lib1ChaptersGenre { get; set; } + public Genre Lib1ChapterAgeGenre { get; set; } + + public List GetAllGenres() + { + return + [ + SharedSeriesChaptersGenre, SharedSeriesGenre, SharedChaptersGenre, + Lib0SeriesChaptersGenre, Lib0SeriesGenre, Lib0ChaptersGenre, + Lib1SeriesChaptersGenre, Lib1SeriesGenre, Lib1ChaptersGenre, Lib1ChapterAgeGenre + ]; + } } }