using Microsoft.Extensions.Options; using NSubstitute; using TeleWave.Application.Broadcast.Bumpers; using TeleWave.Application.Common.Interfaces; using TeleWave.Application.Streaming; using TeleWave.Application.Tests.Support; using TeleWave.Domain.Broadcast; using TeleWave.Domain.Images; using TeleWave.Domain.Library; using TeleWave.Domain.Media; using Xunit; namespace TeleWave.Application.Tests.Broadcast; /// /// Восстановление спецификации для фонового рендерера. Текст берётся из кэша как есть: время показа /// и пара соседей задним числом не восстанавливаются, а ffmpeg запускается уже после записи ленты. /// public class BumperSpecLoaderTests { private static readonly IReadOnlyList Lines = [ new(BumperLineStyle.Label, BumperLineColor.Accent, "СЕЙЧАС"), new(BumperLineStyle.Title, BumperLineColor.Text, "Симпсоны"), ]; private static BumperSpecLoader NewLoader( Infrastructure.Persistence.AppDbContext db, IBumperTemplateStorage? storage = null, IImageStore? images = null ) => new( db, storage ?? Substitute.For(), images ?? Substitute.For(), Options.Create(new BumperOptions()), Options.Create(new StreamingOptions { SegmentSeconds = 5 }) ); [Fact] public async Task Load_UnknownAsset_ReturnsNull() { var fixture = new TestDb(); await using var db = fixture.New(); Assert.Null(await NewLoader(db).LoadAsync(Guid.NewGuid(), CancellationToken.None)); } [Fact] public async Task Load_RestoresRenderedTextAndPaths() { var fixture = new TestDb(); var template = BumperTemplate.Create("Блок", "Текст 1"); template.UpdateStyle( new BumperStyle("Блок", BumperFont.Serif, "0x111111", "0x222222", "0x333333", "white") ); template.SetAudio(".mp3", 12); var background = Image.Create(ImageCategory.BumperBackground, ".png", "bg.png"); template.SetBackgroundImage(background.Id); var poster = Image.Create(ImageCategory.ShowPoster, ".jpg", "poster.jpg"); var show = Show.Create("Терминатор", ShowKind.Single); show.ApplyMetadata("tmdb", "1", null, 1991, poster.Id); var asset = MediaAsset.RegisterGenerated("Блок: СЕЙЧАС / Симпсоны"); var cache = BumperAsset.Create( template.Id, template.Variants[0].Id, "sig", BumperRenderedText.ToJson(Lines), show.Id, asset.Id ); await using (var seed = fixture.New()) { seed.BumperTemplates.Add(template); seed.Images.AddRange(background, poster); seed.Shows.Add(show); seed.MediaAssets.Add(asset); seed.BumperAssets.Add(cache); await seed.SaveChangesAsync(CancellationToken.None); } var storage = Substitute.For(); storage.AudioPath(template.Id, ".mp3").Returns("/media/bumpers/audio.mp3"); var images = Substitute.For(); images.ResolvePath(background.Id, ".png").Returns("/media/images/bg.png"); images.ResolvePath(poster.Id, ".jpg").Returns("/media/images/poster.jpg"); await using var db = fixture.New(); var spec = await NewLoader(db, storage, images).LoadAsync(asset.Id, CancellationToken.None); Assert.NotNull(spec); Assert.Equal(Lines, spec.Lines); Assert.Equal("/media/bumpers/audio.mp3", spec.MusicFile); Assert.Equal("/media/images/bg.png", spec.BackgroundFile); Assert.Equal("/media/images/poster.jpg", spec.PosterFile); Assert.Equal("0x333333", spec.AccentColor); // Длина звука 12 с выравнивается вверх до кратности сегменту (5 с). Assert.Equal(15, spec.DurationSeconds); } [Fact] public async Task Load_TemplateGone_ReturnsNull() { var fixture = new TestDb(); var asset = MediaAsset.RegisterGenerated("Заставка"); var cache = BumperAsset.Create( Guid.NewGuid(), Guid.NewGuid(), "sig", BumperRenderedText.ToJson(Lines), null, asset.Id ); await using (var seed = fixture.New()) { seed.MediaAssets.Add(asset); seed.BumperAssets.Add(cache); await seed.SaveChangesAsync(CancellationToken.None); } await using var db = fixture.New(); // Блок удалили, пока ассет ждал рендера — рендерить нечем, и это не авария. Assert.Null(await NewLoader(db).LoadAsync(asset.Id, CancellationToken.None)); } }