using System.Text; using NSubstitute; using TeleWave.Application.Common.Interfaces; using TeleWave.Application.Library.Genres; using TeleWave.Application.Metadata; using TeleWave.Application.Tests.Support; using TeleWave.Domain.Images; using TeleWave.Domain.Library; using Xunit; namespace TeleWave.Application.Tests.Metadata; /// /// Применение метаданных: постер в реестр изображений, жанры, франшиза и отказы. Общий путь для /// точечного и массового применения — расхождение между ними отлаживать было бы нечем. /// public class ShowMetadataApplierTests { [Fact] public async Task RegistersPoster_InImageRegistry() { var fixture = new TestDb(); var show = Show.Create("Шоу", ShowKind.Single); await SeedAsync(fixture, show); var downloader = Substitute.For(); downloader .DownloadAsync("https://poster", Arg.Any()) .Returns(new DownloadedImage(Encoding.UTF8.GetBytes("img"), ".jpg")); var store = Substitute.For(); await using var db = fixture.New(); var result = await Applier(db, Meta(posterUrl: "https://poster"), downloader, store) .ApplyAsync(await LoadAsync(db, show.Id), "tmdb", "42", CancellationToken.None); Assert.True(result.IsSuccess); await db.SaveChangesAsync(CancellationToken.None); await using var check = fixture.New(); var image = check.Images.Single(); Assert.Equal(ImageCategory.ShowPoster, image.Category); Assert.Equal(image.Id, check.Shows.Single().PosterImageId); await store .Received(1) .SaveAsync(image.Id, ".jpg", Arg.Any(), Arg.Any()); } [Fact] public async Task KeepsPoster_WhenDownloadFails() { // Источник отдал ссылку, но картинка не скачалась — это не повод валить применение. var fixture = new TestDb(); var show = Show.Create("Шоу", ShowKind.Single); await SeedAsync(fixture, show); var downloader = Substitute.For(); downloader .DownloadAsync(Arg.Any(), Arg.Any()) .Returns((DownloadedImage?)null); await using var db = fixture.New(); var result = await Applier(db, Meta(posterUrl: "https://poster"), downloader) .ApplyAsync(await LoadAsync(db, show.Id), "tmdb", "42", CancellationToken.None); Assert.True(result.IsSuccess); Assert.Empty(db.Images); } [Fact] public async Task RemembersFranchise_FromSource() { var fixture = new TestDb(); var show = Show.Create("Рокки", ShowKind.Single); await SeedAsync(fixture, show); await using var db = fixture.New(); await Applier(db, Meta(franchise: new MetadataFranchise("1241", "Рокки"))) .ApplyAsync(await LoadAsync(db, show.Id), "tmdb", "42", CancellationToken.None); await db.SaveChangesAsync(CancellationToken.None); await using var check = fixture.New(); var stored = check.Shows.Single(); Assert.Equal("1241", stored.FranchiseExternalId); Assert.Equal("Рокки", stored.FranchiseName); } [Fact] public async Task Fails_WhenProviderUnavailable() { var fixture = new TestDb(); var show = Show.Create("Шоу", ShowKind.Single); await SeedAsync(fixture, show); await using var db = fixture.New(); var resolver = Substitute.For(); var applier = new ShowMetadataApplier( db, resolver, Substitute.For(), Substitute.For(), new GenreMatcher(db) ); var result = await applier.ApplyAsync( await LoadAsync(db, show.Id), "tmdb", "42", CancellationToken.None ); Assert.False(result.IsSuccess); } [Fact] public async Task Fails_WhenSourceKnowsNothing() { var fixture = new TestDb(); var show = Show.Create("Шоу", ShowKind.Single); await SeedAsync(fixture, show); await using var db = fixture.New(); var result = await Applier(db, meta: null) .ApplyAsync(await LoadAsync(db, show.Id), "tmdb", "42", CancellationToken.None); Assert.False(result.IsSuccess); } private static ShowMetadata Meta( string? posterUrl = null, MetadataFranchise? franchise = null ) => new("42", "Шоу", 2000, "описание", posterUrl, [], null, franchise); private static ShowMetadataApplier Applier( Infrastructure.Persistence.AppDbContext db, ShowMetadata? meta, IImageDownloader? downloader = null, IImageStore? store = null ) { var provider = Substitute.For(); provider .GetShowAsync(Arg.Any(), Arg.Any(), Arg.Any()) .Returns(meta); var resolver = Substitute.For(); resolver.Resolve("tmdb").Returns(provider); return new ShowMetadataApplier( db, resolver, downloader ?? Substitute.For(), store ?? Substitute.For(), new GenreMatcher(db) ); } private static async Task SeedAsync(TestDb fixture, Show show) { await using var seed = fixture.New(); seed.Shows.Add(show); await seed.SaveChangesAsync(CancellationToken.None); } private static async Task LoadAsync( Infrastructure.Persistence.AppDbContext db, Guid showId ) => await Microsoft.EntityFrameworkCore.EntityFrameworkQueryableExtensions.FirstAsync( db.Shows, s => s.Id == showId ); }