using System.Reflection; using ErsatzTV.Controllers.Api; using ErsatzTV.Controllers.Api.Requests; using ErsatzTV.Core; using ErsatzTV.Application.Maintenance; using LanguageExt; using MediatR; using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc.Routing; using NSubstitute; using NUnit.Framework; using Shouldly; using static LanguageExt.Prelude; namespace ErsatzTV.Tests.Controllers; [TestFixture] public class MediaItemsControllerTests { private MediaItemsController _controller = null!; private IMediator _mediator = null!; [SetUp] public void SetUp() { _mediator = Substitute.For(); _controller = new MediaItemsController(_mediator); } [Test] public void Controller_Should_Expose_Delete_Route_With_Stable_Operation_Name() { MethodInfo action = typeof(MediaItemsController).GetMethod(nameof(MediaItemsController.Delete)) ?? throw new AssertionException($"Missing action {nameof(MediaItemsController.Delete)}"); var attribute = action.GetCustomAttributes().Single(); attribute.Template.ShouldBe("/api/v1/media-items"); attribute.Name.ShouldBe("DeleteMediaItems"); } [Test] public async Task Delete_Should_Return_422_For_Empty_Ids() { IActionResult result = await _controller.Delete(new DeleteMediaItemsRequest([]), CancellationToken.None); var unprocessable = result.ShouldBeOfType(); unprocessable.StatusCode.ShouldBe(422); await _mediator.DidNotReceive().Send(Arg.Any(), Arg.Any()); } [Test] public async Task Delete_Should_Return_204_On_Success() { _mediator.Send(Arg.Any(), Arg.Any()) .Returns(Right(LanguageExt.Unit.Default)); IActionResult result = await _controller.Delete( new DeleteMediaItemsRequest([1, 2, 3]), CancellationToken.None); result.ShouldBeOfType(); await _mediator.Received(1).Send( Arg.Is(c => c.MediaItemIds.SequenceEqual(new[] { 1, 2, 3 })), Arg.Any()); } }