using System.Security.Claims; using Api.SeaHavenIndustries.Controllers; using Api.SeaHavenIndustries.DTOs; using Data.SeaHavenIndustries; using FluentAssertions; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Mvc; using Microsoft.Extensions.Logging; using Moq; using SeaHaven.Services.DTOs; using SeaHaven.Services.Interfaces; using Xunit; namespace Api.SeaHavenIndustries.Tests; public class FollowUpControllerTests { private static FollowUpController NewController(Mock service) { var controller = new FollowUpController(service.Object, Mock.Of>()) { ControllerContext = new ControllerContext { HttpContext = new DefaultHttpContext { User = new ClaimsPrincipal(new ClaimsIdentity(new[] { new Claim(ClaimTypes.NameIdentifier, "user-1") }, "Test")) } } }; return controller; } private static FollowUpController NewControllerNoUser(Mock service) => new(service.Object, Mock.Of>()) { ControllerContext = new ControllerContext { HttpContext = new DefaultHttpContext { User = new ClaimsPrincipal(new ClaimsIdentity()) } } }; private static object Prop(object source, string name) => source.GetType().GetProperty(name)!.GetValue(source)!; [Fact] public async Task GetFollowUps_ReturnsPaginationEnvelopeWithMappedRows() { var service = new Mock(); service.Setup(s => s.GetFollowUpListAsync(1, 12, "", "Open", It.IsAny())) .ReturnsAsync(new PagedResult { Items = new List { new() { Id = 1, Reason = "R", CreatedByName = "Me" } }, TotalCount = 1, Page = 1, PageSize = 12 }); var result = await NewController(service).GetFollowUps(); var ok = result.Should().BeOfType().Subject; var envelope = ok.Value.Should().BeOfType().Subject; envelope.PageSize.Should().Be(12); envelope.TotalCount.Should().Be(1); } [Fact] public async Task GetById_WhenMissing_ReturnsNotFound() { var service = new Mock(); service.Setup(s => s.GetFollowUpDetailAsync(9, It.IsAny())) .ReturnsAsync((FollowUpDetailDTO?)null); var result = await NewController(service).GetById(9, CancellationToken.None); result.Should().BeOfType(); } [Fact] public async Task Create_WhenNoUser_ReturnsUnauthorized() { var service = new Mock(); var result = await NewControllerNoUser(service).Create(new FollowUp_DTO { Reason = "x" }, CancellationToken.None); var unauthorized = result.Should().BeOfType().Subject; unauthorized.Value.Should().BeOfType().Subject.Message.Should().Be("User not authenticated"); service.Verify(s => s.CreateOpenFollowUpAsync(It.IsAny(), It.IsAny(), It.IsAny()), Times.Never); } [Fact] public async Task Create_WhenAuthenticated_ReturnsCreatedWithId() { var service = new Mock(); service.Setup(s => s.CreateOpenFollowUpAsync(It.IsAny(), "user-1", It.IsAny())) .ReturnsAsync(42); var result = await NewController(service).Create(new FollowUp_DTO { Reason = "x" }, CancellationToken.None); var ok = result.Should().BeOfType().Subject; var response = ok.Value.Should().BeOfType().Subject; response.Status.Should().Be("200"); response.Message.Should().Be("Follow Up created"); ((object?)response.Data).Should().Be(42); } [Fact] public async Task Complete_WhenMissing_ReturnsNotFound() { var service = new Mock(); service.Setup(s => s.SetFollowUpStatusAsync(3, "Completed", It.IsAny())) .ReturnsAsync(false); var result = await NewController(service).Complete(3, CancellationToken.None); result.Should().BeOfType(); } [Fact] public async Task Delete_WhenMissing_ReturnsNotFoundEnvelope() { var service = new Mock(); service.Setup(s => s.RemoveFollowUpAsync(8, It.IsAny())) .ReturnsAsync(false); var result = await NewController(service).Delete(8, CancellationToken.None); var notFound = result.Should().BeOfType().Subject; notFound.Value.Should().BeOfType().Subject.Message.Should().Be("Follow Up not found"); } }