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));
}
}