using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; using API.Entities.Enums; using API.Helpers; using API.Helpers.Builders; using Xunit; namespace API.Tests.Helpers; public class PersonHelperTests : AbstractDbTest { protected override async Task ResetDb() { Context.Series.RemoveRange(Context.Series.ToList()); Context.Person.RemoveRange(Context.Person.ToList()); Context.Library.RemoveRange(Context.Library.ToList()); Context.Series.RemoveRange(Context.Series.ToList()); await Context.SaveChangesAsync(); } // 1. Test adding new people and keeping existing ones [Fact] public async Task UpdateChapterPeopleAsync_AddNewPeople_ExistingPersonRetained() { await ResetDb(); var library = new LibraryBuilder("My Library") .Build(); UnitOfWork.LibraryRepository.Add(library); await UnitOfWork.CommitAsync(); var existingPerson = new PersonBuilder("Joe Shmo").Build(); var chapter = new ChapterBuilder("1").Build(); // Create an existing person and assign them to the series with a role var series = new SeriesBuilder("Test 1") .WithLibraryId(library.Id) .WithFormat(MangaFormat.Archive) .WithMetadata(new SeriesMetadataBuilder() .WithPerson(existingPerson, PersonRole.Editor) .Build()) .WithVolume(new VolumeBuilder("1").WithChapter(chapter).Build()) .Build(); UnitOfWork.SeriesRepository.Add(series); await UnitOfWork.CommitAsync(); // Call UpdateChapterPeopleAsync with one existing and one new person await PersonHelper.UpdateChapterPeopleAsync(chapter, new List { "Joe Shmo", "New Person" }, PersonRole.Editor, UnitOfWork); // Assert existing person retained and new person added var people = await UnitOfWork.PersonRepository.GetAllPeople(); Assert.Contains(people, p => p.Name == "Joe Shmo"); Assert.Contains(people, p => p.Name == "New Person"); var chapterPeople = chapter.People.Select(cp => cp.Person.Name).ToList(); Assert.Contains("Joe Shmo", chapterPeople); Assert.Contains("New Person", chapterPeople); } // 2. Test removing a person no longer in the list [Fact] public async Task UpdateChapterPeopleAsync_RemovePeople() { await ResetDb(); var library = new LibraryBuilder("My Library") .Build(); UnitOfWork.LibraryRepository.Add(library); await UnitOfWork.CommitAsync(); var existingPerson1 = new PersonBuilder("Joe Shmo").Build(); var existingPerson2 = new PersonBuilder("Jane Doe").Build(); var chapter = new ChapterBuilder("1") .WithPerson(existingPerson1, PersonRole.Editor) .WithPerson(existingPerson2, PersonRole.Editor) .Build(); var series = new SeriesBuilder("Test 1") .WithLibraryId(library.Id) .WithVolume(new VolumeBuilder("1") .WithChapter(chapter) .Build()) .Build(); UnitOfWork.SeriesRepository.Add(series); await UnitOfWork.CommitAsync(); // Call UpdateChapterPeopleAsync with only one person await PersonHelper.UpdateChapterPeopleAsync(chapter, new List { "Joe Shmo" }, PersonRole.Editor, UnitOfWork); // PersonHelper does not remove the Person from the global DbSet itself await UnitOfWork.PersonRepository.RemoveAllPeopleNoLongerAssociated(); var people = await UnitOfWork.PersonRepository.GetAllPeople(); Assert.DoesNotContain(people, p => p.Name == "Jane Doe"); var chapterPeople = chapter.People.Select(cp => cp.Person.Name).ToList(); Assert.Contains("Joe Shmo", chapterPeople); Assert.DoesNotContain("Jane Doe", chapterPeople); } // 3. Test no changes when the list of people is the same [Fact] public async Task UpdateChapterPeopleAsync_NoChanges() { await ResetDb(); var library = new LibraryBuilder("My Library") .Build(); UnitOfWork.LibraryRepository.Add(library); await UnitOfWork.CommitAsync(); var existingPerson = new PersonBuilder("Joe Shmo").Build(); var chapter = new ChapterBuilder("1").WithPerson(existingPerson, PersonRole.Editor).Build(); var series = new SeriesBuilder("Test 1") .WithLibraryId(library.Id) .WithVolume(new VolumeBuilder("1") .WithChapter(chapter) .Build()) .Build(); UnitOfWork.SeriesRepository.Add(series); await UnitOfWork.CommitAsync(); // Call UpdateChapterPeopleAsync with the same list await PersonHelper.UpdateChapterPeopleAsync(chapter, new List { "Joe Shmo" }, PersonRole.Editor, UnitOfWork); var people = await UnitOfWork.PersonRepository.GetAllPeople(); Assert.Contains(people, p => p.Name == "Joe Shmo"); var chapterPeople = chapter.People.Select(cp => cp.Person.Name).ToList(); Assert.Contains("Joe Shmo", chapterPeople); Assert.Single(chapter.People); // No duplicate entries } // 4. Test multiple roles for a person [Fact] public async Task UpdateChapterPeopleAsync_MultipleRoles() { await ResetDb(); var library = new LibraryBuilder("My Library") .Build(); UnitOfWork.LibraryRepository.Add(library); await UnitOfWork.CommitAsync(); var person = new PersonBuilder("Joe Shmo").Build(); var chapter = new ChapterBuilder("1").WithPerson(person, PersonRole.Writer).Build(); var series = new SeriesBuilder("Test 1") .WithLibraryId(library.Id) .WithVolume(new VolumeBuilder("1") .WithChapter(chapter) .Build()) .Build(); UnitOfWork.SeriesRepository.Add(series); await UnitOfWork.CommitAsync(); // Add same person as Editor await PersonHelper.UpdateChapterPeopleAsync(chapter, new List { "Joe Shmo" }, PersonRole.Editor, UnitOfWork); // Ensure that the same person is assigned with two roles var chapterPeople = chapter .People .Where(cp => cp.Person.Name == "Joe Shmo") .ToList(); Assert.Equal(2, chapterPeople.Count); // One for each role Assert.Contains(chapterPeople, cp => cp.Role == PersonRole.Writer); Assert.Contains(chapterPeople, cp => cp.Role == PersonRole.Editor); } [Fact] public async Task UpdateChapterPeopleAsync_MatchOnAlias_NoChanges() { await ResetDb(); var library = new LibraryBuilder("My Library") .Build(); UnitOfWork.LibraryRepository.Add(library); await UnitOfWork.CommitAsync(); var person = new PersonBuilder("Joe Doe") .WithAlias("Jonny Doe") .Build(); var chapter = new ChapterBuilder("1") .WithPerson(person, PersonRole.Editor) .Build(); var series = new SeriesBuilder("Test 1") .WithLibraryId(library.Id) .WithVolume(new VolumeBuilder("1") .WithChapter(chapter) .Build()) .Build(); UnitOfWork.SeriesRepository.Add(series); await UnitOfWork.CommitAsync(); // Add on Name await PersonHelper.UpdateChapterPeopleAsync(chapter, new List { "Joe Doe" }, PersonRole.Editor, UnitOfWork); await UnitOfWork.CommitAsync(); var allPeople = await UnitOfWork.PersonRepository.GetAllPeople(); Assert.Single(allPeople); // Add on alias await PersonHelper.UpdateChapterPeopleAsync(chapter, new List { "Jonny Doe" }, PersonRole.Editor, UnitOfWork); await UnitOfWork.CommitAsync(); allPeople = await UnitOfWork.PersonRepository.GetAllPeople(); Assert.Single(allPeople); } // TODO: Unit tests for series }