using System.Security.Claims; using Data.SeaHavenIndustries; using FluentAssertions; using Microsoft.EntityFrameworkCore; using SeaHaven.DataServices.Implementation; using SeaHaven.Services.Exceptions; using SeaHaven.Services.Helpers; using SeaHaven.Services.Implementation; using Xunit; namespace Api.SeaHavenIndustries.Tests; public class DashboardServiceTests { private static ApplicationDbContext NewContext() { var options = new DbContextOptionsBuilder() .UseInMemoryDatabase(databaseName: Guid.NewGuid().ToString()) .Options; return new ApplicationDbContext(options); } private static DashboardService NewService(ApplicationDbContext ctx) { var resolver = new WorkOrderAccountResolver( new AccountDataService(ctx), new LocationDataService(ctx)); return new DashboardService(new DashboardDataService(ctx), resolver); } private static ClaimsPrincipal AccountUser(int accountId) { var claims = new[] { new Claim(SeaHavenClaimTypes.AccountId, accountId.ToString()), new Claim(ClaimTypes.Role, "Dispatcher") }; return new ClaimsPrincipal(new ClaimsIdentity(claims, "test")); } private static ClaimsPrincipal OrgWideUser() { var claims = new[] { new Claim(SeaHavenClaimTypes.OrgScope, SeaHavenClaimTypes.OrgScopeAll), new Claim(ClaimTypes.Role, "Admin") }; return new ClaimsPrincipal(new ClaimsIdentity(claims, "test")); } [Fact] public async Task GetStatsAsync_CountsByStatusExcludingTemplates() { using var ctx = NewContext(); ctx.workOrders.AddRange( new WorkOrder { AccountId = 1, Status = "Open", istemplate = false }, new WorkOrder { AccountId = 1, Status = "Open", istemplate = false, AssignTo = "u1" }, new WorkOrder { AccountId = 1, Status = "In Progress" }, new WorkOrder { AccountId = 1, Status = "On Hold" }, new WorkOrder { AccountId = 1, Status = "Done" }, new WorkOrder { AccountId = 1, Status = "Done" }, new WorkOrder { AccountId = 1, Status = "Open", istemplate = true }, new WorkOrder { AccountId = 1, Status = "Cancelled" }, new WorkOrder { AccountId = 2, Status = "Open" }, new WorkOrder { Status = "Open" } ); ctx.SaveChanges(); var stats = await NewService(ctx).GetStatsAsync(AccountUser(1), CancellationToken.None); stats.Total.Should().Be(7); stats.Open.Should().Be(4); stats.NotDispatched.Should().Be(1); stats.Completed.Should().Be(2); } [Fact] public async Task GetStatsAsync_OrgWideUserSeesAllNonTemplateOrders() { using var ctx = NewContext(); ctx.workOrders.AddRange( new WorkOrder { AccountId = 1, Status = "Open" }, new WorkOrder { AccountId = 2, Status = "Done" }, new WorkOrder { Status = "Open", istemplate = true }); ctx.SaveChanges(); var stats = await NewService(ctx).GetStatsAsync(OrgWideUser(), CancellationToken.None); stats.Total.Should().Be(2); stats.Open.Should().Be(1); stats.Completed.Should().Be(1); } [Fact] public async Task GetStatsAsync_MissingScopeFailsClosed() { using var ctx = NewContext(); var user = new ClaimsPrincipal(new ClaimsIdentity(new[] { new Claim(ClaimTypes.Role, "Dispatcher") }, "test")); var act = () => NewService(ctx).GetStatsAsync(user, CancellationToken.None); var exception = await act.Should().ThrowAsync(); exception.Which.Code.Should().Be("Forbidden"); } }