using Api.SeaHavenIndustries.Controllers; using Api.SeaHavenIndustries.DTOs; using Data.SeaHavenIndustries; using FluentAssertions; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Mvc; using Microsoft.EntityFrameworkCore; using Moq; using SeaHaven.Services.DTOs; using SeaHaven.Services.Interfaces; using System.Security.Claims; using System.Text.Json; using Xunit; namespace Api.SeaHavenIndustries.Tests; public class VendorControllerTests { private static VendorController NewController(Mock service) { var controller = new VendorController( service.Object, db: null!, zipDistance: null!, vendorTokens: null!, config: null!); controller.ControllerContext = new ControllerContext { HttpContext = new DefaultHttpContext { User = new ClaimsPrincipal(new ClaimsIdentity(new[] { new Claim(ClaimTypes.NameIdentifier, "42") }, "Test")) } }; return controller; } [Fact] public async Task Update_WithoutIsActive_PassesNullToServiceToPreserveStatus() { var service = new Mock(); service.Setup(x => x.UpdateVendorAsync(It.IsAny(), It.IsAny(), It.IsAny())) .ReturnsAsync(new VendorDTO()); var controller = NewController(service); var model = new EditVendor_DTO { Id = 8, CompanyName = "Updated Name" }; var result = await controller.Update(8, model); result.Should().BeOfType(); service.Verify(x => x.UpdateVendorAsync( 8, It.Is(dto => dto.IsActive == null), "42"), Times.Once); } [Fact] public async Task Update_WithExplicitIsActive_ForwardsValueUnchanged() { var service = new Mock(); service.Setup(x => x.UpdateVendorAsync(It.IsAny(), It.IsAny(), It.IsAny())) .ReturnsAsync(new VendorDTO()); var controller = NewController(service); var model = new EditVendor_DTO { Id = 8, CompanyName = "Updated Name", IsActive = false }; await controller.Update(8, model); service.Verify(x => x.UpdateVendorAsync( 8, It.Is(dto => dto.IsActive == false), "42"), Times.Once); } [Fact] public async Task Create_WithoutIsActive_DefaultsToActive() { var service = new Mock(); service.Setup(x => x.CreateVendorAsync(It.IsAny(), It.IsAny())) .ReturnsAsync(new VendorDTO()); var controller = NewController(service); var model = new Vendor_DTO { CompanyName = "New Co" }; await controller.Create(model); service.Verify(x => x.CreateVendorAsync( It.Is(dto => dto.IsActive == true), "42"), Times.Once); } [Theory] [InlineData(true, "Active Co", "Inactive Co")] [InlineData(false, "Inactive Co", "Active Co")] public async Task GetFacets_WithStatus_ReturnsOnlyMatchingVendors( bool isActive, string expected, string excluded) { var options = new DbContextOptionsBuilder() .UseInMemoryDatabase(Guid.NewGuid().ToString()) .Options; await using var context = new ApplicationDbContext(options); context.Vendors.AddRange( new Vendor { CompanyName = "Active Co", IsActive = true, IsDeleted = false }, new Vendor { CompanyName = "Inactive Co", IsActive = false, IsDeleted = false }); await context.SaveChangesAsync(); var controller = new VendorController( Mock.Of(), context, zipDistance: null!, vendorTokens: null!, config: null!); var result = await controller.GetFacets(isActive); var payload = JsonSerializer.Serialize( result.Should().BeOfType().Subject.Value); payload.Should().Contain(expected); payload.Should().NotContain(excluded); } [Fact] public async Task GetFacets_WithoutStatus_PreservesGlobalFacetLookup() { var options = new DbContextOptionsBuilder() .UseInMemoryDatabase(Guid.NewGuid().ToString()) .Options; await using var context = new ApplicationDbContext(options); context.Vendors.AddRange( new Vendor { CompanyName = "Active Co", IsActive = true, IsDeleted = false }, new Vendor { CompanyName = "Inactive Co", IsActive = false, IsDeleted = false }); await context.SaveChangesAsync(); var controller = new VendorController( Mock.Of(), context, zipDistance: null!, vendorTokens: null!, config: null!); var result = await controller.GetFacets(); var payload = JsonSerializer.Serialize( result.Should().BeOfType().Subject.Value); payload.Should().Contain("Active Co"); payload.Should().Contain("Inactive Co"); } }