using Microsoft.EntityFrameworkCore; using TeleWave.Application.Library.Collections.AddShowsToCollection; using TeleWave.Application.Library.Collections.Suggest; using TeleWave.Application.Tests.Support; using TeleWave.Domain.Library; using Xunit; namespace TeleWave.Application.Tests.Library; /// /// Сборка франшиз: предложения по метаданным и по названиям плюс массовое добавление в коллекцию. /// Ошибка здесь означает чужой фильм в середине франшизы, поэтому осторожность важнее полноты. /// public class CollectionSuggestionsTests { [Fact] public async Task SuggestsFranchise_FromMetadata() { var fixture = new TestDb(); var first = Movie("Гарри Поттер и философский камень", 2001, franchise: "1241"); var second = Movie("Гарри Поттер и тайная комната", 2002, franchise: "1241"); var other = Movie("Совсем другое", 1999, franchise: "777"); await SeedAsync(fixture, first, second, other); var suggestions = await BuildAsync(fixture); var franchise = Assert.Single( suggestions, s => s.Source == CollectionSuggestionSource.Metadata ); Assert.Equal("Франшиза 1241", franchise.Name); // Порядок — по году: это и есть порядок просмотра. Assert.Equal([first.Id, second.Id], franchise.Parts.Select(p => p.ShowId)); } [Fact] public async Task SuggestsByName_WhenMetadataMissing() { var fixture = new TestDb(); var first = Movie("Рокки", 1976); var second = Movie("Рокки 2", 1979); await SeedAsync(fixture, first, second); var suggestions = await BuildAsync(fixture); var guess = Assert.Single( suggestions, s => s.Source == CollectionSuggestionSource.NameGuess ); Assert.Equal(2, guess.Parts.Count); } [Fact] public async Task DoesNotGuess_OnShortCommonStart() { // «Человек-паук» и «Человек дождя» — не франшиза, хотя начало совпадает. var fixture = new TestDb(); await SeedAsync(fixture, Movie("Человек дождя", 1988), Movie("Человек-слон", 1980)); var suggestions = await BuildAsync(fixture); Assert.DoesNotContain(suggestions, s => s.Source == CollectionSuggestionSource.NameGuess); } [Fact] public async Task SkipsShows_AlreadyInCollections() { var fixture = new TestDb(); var first = Movie("Рокки", 1976, franchise: "1241"); var second = Movie("Рокки 2", 1979, franchise: "1241"); var collection = Collection.Create("Рокки"); collection.AddShow(first.Id); await using (var seed = fixture.New()) { seed.Shows.AddRange(first, second); seed.Collections.Add(collection); await seed.SaveChangesAsync(CancellationToken.None); } var suggestions = await BuildAsync(fixture); // Одна часть уже разобрана — на франшизу оставшегося не хватает. Assert.Empty(suggestions); } [Fact] public async Task AddShowsToCollection_CreatesNewAndOrdersByYear() { var fixture = new TestDb(); var later = Movie("Вторая", 1979); var earlier = Movie("Первая", 1976); await SeedAsync(fixture, later, earlier); await using var db = fixture.New(); var result = await new AddShowsToCollectionCommandHandler(db).Handle( new AddShowsToCollectionCommand([later.Id, earlier.Id], NewCollectionName: "Франшиза"), CancellationToken.None ); Assert.True(result.IsSuccess); await db.SaveChangesAsync(CancellationToken.None); await using var check = fixture.New(); var collection = check.Collections.Include(c => c.Items).Single(); Assert.Equal(2, result.Value.Added); Assert.Equal( [earlier.Id, later.Id], collection.Items.OrderBy(i => i.Position).Select(i => i.ShowId) ); } private static Show Movie(string name, int? year, string? franchise = null) { var show = Show.Create(name, ShowKind.Single); if (franchise is not null) show.ApplyMetadata( "tmdb", Guid.NewGuid().ToString("N"), null, year, null, new MetadataFranchise(franchise, $"Франшиза {franchise}") ); else show.ApplyMetadata("manual", Guid.NewGuid().ToString("N"), null, year, null); return show; } private static async Task SeedAsync(TestDb fixture, params Show[] shows) { await using var seed = fixture.New(); seed.Shows.AddRange(shows); await seed.SaveChangesAsync(CancellationToken.None); } private static async Task> BuildAsync(TestDb fixture) { await using var db = fixture.New(); return await new CollectionSuggestionBuilder(db).BuildAsync(CancellationToken.None); } }