Mint ChannelDetailResponseModel (faithful detail DTO exposing the raw editable field set the channel editor reads: raw FFmpegProfileId/WatermarkId/FallbackFillerId ids, the mode enums, logo, playoutCount, id) and route GetById/Create/Update through it, replacing the lean list ChannelResponseModel that resolved the profile to a name and dropped the editable ids (a functional regression for draftFromChannel). The lean ChannelResponseModel stays unchanged for GET /api/channels. webEncodedName dropped (SPA never reads it). Logo is mirrored as a Core ChannelLogoResponseModel since the Application ArtworkContentTypeModel can't be referenced from Core. Repoint the hand-written SPA client aliases now that the VMs are gone from the schema: Channel -> ChannelDetailResponseModel, MediaCollection/SmartCollection -> *ResponseModel, ProgramSchedule -> ProgramScheduleResponseModel. Fix #288 honest-nullability test fallout in search.test.ts (null -> [] for now-non-null id arrays). Include the already-on-disk playouts.ts WithDayNames removal and regenerate v1.json + v1.d.ts + endpoint-index.md (authoritative final regen; the reset endpoint's {channelNumber}->{id} re-key surfaces in the generated docs and the OpenApi error-contract test). Refs #288 #197 Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
74 lines
2.7 KiB
C#
74 lines
2.7 KiB
C#
using ErsatzTV.Application.Channels;
|
|
using ErsatzTV.Core.Api.Channels;
|
|
using ErsatzTV.Core.Domain;
|
|
using ErsatzTV.Core.Interfaces.Repositories;
|
|
using LanguageExt;
|
|
using NSubstitute;
|
|
using NUnit.Framework;
|
|
using Shouldly;
|
|
|
|
namespace ErsatzTV.Tests.Application.Channels;
|
|
|
|
[TestFixture]
|
|
public class GetChannelByIdForApiHandlerTests
|
|
{
|
|
[Test]
|
|
public async Task Should_Project_DetailResponseModel_When_Found()
|
|
{
|
|
IChannelRepository repository = Substitute.For<IChannelRepository>();
|
|
repository.GetChannel(7)
|
|
.Returns(Option<Channel>.Some(new Channel(Guid.NewGuid())
|
|
{
|
|
Id = 7,
|
|
Number = "7.1",
|
|
SortNumber = 7.1,
|
|
Name = "Retro Cartoons",
|
|
Group = "Kids",
|
|
Categories = "animation",
|
|
FFmpegProfileId = 3,
|
|
FFmpegProfile = new FFmpegProfile { Name = "HLS 720p" },
|
|
Artwork = [],
|
|
PreferredAudioLanguageCode = "eng",
|
|
StreamingMode = StreamingMode.HttpLiveStreamingSegmenter,
|
|
WatermarkId = 11,
|
|
FallbackFillerId = 12,
|
|
IsEnabled = false,
|
|
ShowInEpg = false
|
|
}));
|
|
var handler = new GetChannelByIdForApiHandler(repository);
|
|
|
|
Option<ChannelDetailResponseModel> result =
|
|
await handler.Handle(new GetChannelByIdForApi(7), CancellationToken.None);
|
|
|
|
result.IsSome.ShouldBeTrue();
|
|
ChannelDetailResponseModel channel = result.IfNone(() => throw new InvalidOperationException());
|
|
channel.Id.ShouldBe(7);
|
|
channel.Number.ShouldBe("7.1");
|
|
channel.Name.ShouldBe("Retro Cartoons");
|
|
channel.Group.ShouldBe("Kids");
|
|
channel.Categories.ShouldBe("animation");
|
|
// Detail model exposes the raw editable ids the editor re-drafts (not a resolved name).
|
|
channel.FFmpegProfileId.ShouldBe(3);
|
|
channel.WatermarkId.ShouldBe(11);
|
|
channel.FallbackFillerId.ShouldBe(12);
|
|
channel.PreferredAudioLanguageCode.ShouldBe("eng");
|
|
channel.StreamingMode.ShouldBe(StreamingMode.HttpLiveStreamingSegmenter);
|
|
channel.PlayoutCount.ShouldBe(0);
|
|
channel.IsEnabled.ShouldBeFalse();
|
|
channel.ShowInEpg.ShouldBeFalse();
|
|
}
|
|
|
|
[Test]
|
|
public async Task Should_Return_None_When_Missing()
|
|
{
|
|
IChannelRepository repository = Substitute.For<IChannelRepository>();
|
|
repository.GetChannel(Arg.Any<int>()).Returns(Option<Channel>.None);
|
|
var handler = new GetChannelByIdForApiHandler(repository);
|
|
|
|
Option<ChannelDetailResponseModel> result =
|
|
await handler.Handle(new GetChannelByIdForApi(99), CancellationToken.None);
|
|
|
|
result.IsNone.ShouldBeTrue();
|
|
}
|
|
}
|