using Api.SeaHavenIndustries.Controllers; using Data.SeaHavenIndustries.Enums; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc.ActionConstraints; using Microsoft.AspNetCore.Mvc.Controllers; using Microsoft.AspNetCore.Mvc.Infrastructure; using Microsoft.Extensions.DependencyInjection; using Moq; using SeaHaven.DataServices.Dto; using SeaHaven.DataServices.Interfaces; using SeaHaven.Services.Constants; using SeaHaven.Services.DTOs; using SeaHaven.Services.Implementation; using SeaHaven.Services.Interfaces; using System.Security.Claims; using System.Text.Json; using Xunit; namespace Api.SeaHavenIndustries.Tests; public sealed class TeamMemberPermissionsEndpointTests { [Fact] public async Task Signed_in_caller_receives_their_effective_keys_as_a_permissions_array() { var data = new Mock(); data.Setup(d => d.GetUserAsync("u1", It.IsAny())) .ReturnsAsync(new TeamPermissionUserData { UserId = "u1", RoleName = "Dispatcher", Overrides = new Dictionary { [TeamPermissionKeys.CreateCompletionDocTemplates] = UserPermissionState.Allow } }); var controller = Controller(data.Object, new ClaimsPrincipal(new ClaimsIdentity( new[] { new Claim(ClaimTypes.NameIdentifier, "u1") }, "Bearer"))); var ok = Assert.IsType(await controller.GetMyPermissions(CancellationToken.None)); var json = JsonSerializer.Serialize(ok.Value, new JsonSerializerOptions(JsonSerializerDefaults.Web)); using var document = JsonDocument.Parse(json); var keys = document.RootElement.GetProperty("permissions").EnumerateArray() .Select(element => element.GetString()).ToList(); Assert.Contains(TeamPermissionKeys.CreateCompletionDocTemplates, keys); Assert.DoesNotContain(TeamPermissionKeys.DeleteCompletionDocTemplates, keys); } [Fact] public async Task Unauthenticated_caller_gets_401_without_data_access() { var data = new Mock(MockBehavior.Strict); var controller = Controller(data.Object, new ClaimsPrincipal(new ClaimsIdentity())); var result = Assert.IsType(await controller.GetMyPermissions(CancellationToken.None)); Assert.Equal(StatusCodes.Status401Unauthorized, result.StatusCode); } [Fact] public void Route_is_get_me_permissions_and_requires_authentication() { var services = new ServiceCollection(); services.AddLogging(); services.AddMvcCore().AddApplicationPart(typeof(TeamMemberController).Assembly); using var provider = services.BuildServiceProvider(); var descriptor = provider .GetRequiredService() .ActionDescriptors.Items .OfType() .Single(d => d.ControllerTypeInfo == typeof(TeamMemberController) && d.ActionName == nameof(TeamMemberController.GetMyPermissions)); var methods = descriptor.ActionConstraints!.OfType() .SelectMany(c => c.HttpMethods); Assert.Equal(new[] { "GET" }, methods); Assert.Equal("api/team-members/me/permissions", descriptor.AttributeRouteInfo!.Template); Assert.NotEmpty(typeof(TeamMemberController).GetCustomAttributes(typeof(AuthorizeAttribute), true)); Assert.Empty(descriptor.MethodInfo.GetCustomAttributes(typeof(AllowAnonymousAttribute), true)); } private static TeamMemberController Controller( ITeamPermissionOverrideDataService data, ClaimsPrincipal user) => new(Mock.Of(), new TeamPermissionService(data, new TeamPermissionPolicy())) { ControllerContext = new ControllerContext { HttpContext = new DefaultHttpContext { User = user } } }; }