using TeleWave.Application.Streaming.ListPublicChannels; using TeleWave.Application.Tests.Support; using TeleWave.Domain.Broadcast; using TeleWave.Domain.Library; using TeleWave.Domain.Media; using Xunit; namespace TeleWave.Application.Tests.Streaming; /// /// Витрина зрителя: только включённые каналы, порядок по номеру и обложка того, что идёт прямо /// сейчас. Выключенный канал не должен просачиваться в публичную выдачу. /// public class ListPublicChannelsTests { private static readonly DateTimeOffset T0 = new(2026, 1, 1, 0, 0, 0, TimeSpan.Zero); [Fact] public async Task List_ReturnsEnabledChannelsOrderedByNumber() { var fixture = new TestDb(); var numbered = Channel.Create("Второй", "two", T0); numbered.UpdateTimeSettings( 2, Channel.DefaultUtcOffsetMinutes, Channel.DefaultDayStartTime ); var first = Channel.Create("Первый", "one", T0); first.UpdateTimeSettings(1, Channel.DefaultUtcOffsetMinutes, Channel.DefaultDayStartTime); var unnumbered = Channel.Create("Аврора", "aurora", T0); var disabled = Channel.Create("Выключенный", "off", T0); foreach (var channel in new[] { numbered, first, unnumbered }) channel.UpdateSettings(channel.Name, isEnabled: true, null, null); disabled.UpdateSettings("Выключенный", isEnabled: false, null, null); await using (var seed = fixture.New()) { seed.Channels.AddRange(numbered, first, unnumbered, disabled); await seed.SaveChangesAsync(CancellationToken.None); } await using var db = fixture.New(); var channels = await new ListPublicChannelsQueryHandler(db).Handle( new ListPublicChannelsQuery(), CancellationToken.None ); // Ненумерованный уходит в конец: на телевизоре порядок задаёт номер. Assert.Equal(["Первый", "Второй", "Аврора"], channels.Select(c => c.Name).ToArray()); Assert.Null(channels[^1].Number); Assert.All(channels, c => Assert.Null(c.CurrentShowId)); } [Fact] public async Task List_AddsCurrentProgramCover() { var fixture = new TestDb(); var channel = Channel.Create("Первый", "one", T0); channel.UpdateSettings("Первый", isEnabled: true, null, null); var logoId = Guid.NewGuid(); channel.UpdateViewerSettings(logoId, LogoCorner.TopRight, 0.5, showClock: true, 0.3); var show = Show.Create("Сейчас в эфире", ShowKind.Series); show.SetPosterImage(Guid.NewGuid()); var asset = MediaAsset.Register("now.mkv", ".mkv", MediaSource.Upload); var now = DateTimeOffset.UtcNow; var current = ScheduleEntry.Program( channel.Id, asset.Id, now.AddMinutes(-5), now.AddMinutes(25), show.Id, 0 ); // Прошедшая запись того же канала не должна перебить текущую. var past = ScheduleEntry.Program( channel.Id, asset.Id, now.AddHours(-2), now.AddHours(-1), Guid.NewGuid(), 0 ); await using (var seed = fixture.New()) { seed.Channels.Add(channel); seed.Shows.Add(show); seed.MediaAssets.Add(asset); seed.ScheduleEntries.AddRange(current, past); await seed.SaveChangesAsync(CancellationToken.None); } await using var db = fixture.New(); var channels = await new ListPublicChannelsQueryHandler(db).Handle( new ListPublicChannelsQuery(), CancellationToken.None ); var dto = Assert.Single(channels); Assert.Equal(show.Id, dto.CurrentShowId); Assert.Equal("Сейчас в эфире", dto.CurrentShowName); Assert.Equal(show.PosterImageId, dto.CurrentShowPosterImageId); Assert.Equal(logoId, dto.LogoImageId); Assert.Equal(LogoCorner.TopRight, dto.LogoCorner); Assert.Equal(0.5, dto.LogoOpacity); Assert.True(dto.ShowClock); Assert.Equal(0.3, dto.AnalogFilterStrength); } [Fact] public async Task List_WithoutEnabledChannels_ReturnsEmpty() { var fixture = new TestDb(); await using var db = fixture.New(); var channels = await new ListPublicChannelsQueryHandler(db).Handle( new ListPublicChannelsQuery(), CancellationToken.None ); Assert.Empty(channels); } }