using BuildFlow.Platform.Application.Permissions.Commands; using BuildFlow.Platform.Application.Permissions.DTOs; using BuildFlow.Platform.Application.Permissions.Handlers; using BuildFlow.Platform.Application.Permissions.Queries; using BuildFlow.Platform.Domain.Entities; using BuildFlow.Platform.Infrastructure.Persistence; using BuildFlow.Shared.Domain.Exceptions; using FluentAssertions; using Microsoft.EntityFrameworkCore; using Xunit; namespace BuildFlow.Platform.Tests.Permissions; /// /// [SOP-PLATFORM] 权限管理全 Handler 覆盖测试。 /// 覆盖:Create / Update / Delete / GetList / GetById / GetTree。 /// 飞书矩阵: platform/Permissions 子域(6 Handler 零覆盖→全补) /// public class PermissionHandlerTests { private static PlatformDbContext CreateDb([System.Runtime.CompilerServices.CallerMemberName] string name = "") => PlatformTestDb.CreateDbContext(name); private static Permission NewPermission(string code, string? group = "TestGroup") => PlatformTestDb.WithAudit(new Permission { Name = $"权限_{code}", Code = code, Description = "desc", Group = group }); [Fact] public async Task Create_Valid_ReturnsDto() { var db = CreateDb(); var handler = new CreatePermissionCommandHandler(db); var result = await handler.Handle( new CreatePermissionCommand("创建用户", "user:create", "描述", "UserManagement"), CancellationToken.None); result.Code.Should().Be("user:create"); result.Name.Should().Be("创建用户"); (await db.Permissions.CountAsync()).Should().Be(1); } [Fact] public async Task Create_DuplicateCode_ThrowsBusiness() { var db = CreateDb(); db.Permissions.Add(NewPermission("user:create")); await db.SaveChangesAsync(); var handler = new CreatePermissionCommandHandler(db); var act = async () => await handler.Handle( new CreatePermissionCommand("重复", "user:create", null, null), CancellationToken.None); await act.Should().ThrowAsync("Code 唯一,重复应拒绝"); } [Fact] public async Task Update_Existing_OverwritesNullableFields() { var db = CreateDb(); var p = NewPermission("user:read"); db.Permissions.Add(p); await db.SaveChangesAsync(); var handler = new UpdatePermissionCommandHandler(db); var result = await handler.Handle( new UpdatePermissionCommand(p.Id, "新名称", "新描述", "NewGroup"), CancellationToken.None); result.Name.Should().Be("新名称"); result.Description.Should().Be("新描述"); result.Group.Should().Be("NewGroup"); result.Code.Should().Be("user:read", "Code 不可改"); } [Fact] public async Task Update_NonExistent_ThrowsNotFound() { var db = CreateDb(); var handler = new UpdatePermissionCommandHandler(db); var act = async () => await handler.Handle( new UpdatePermissionCommand(Guid.NewGuid(), "x", null, null), CancellationToken.None); await act.Should().ThrowAsync(); } [Fact] public async Task Delete_Existing_RemovesAndUnlinksRoles() { var db = CreateDb(); var p = NewPermission("user:delete"); var role = PlatformTestDb.WithAudit(new Role { Name = "Admin" }); var link = new RolePermission { Role = role, Permission = p }; db.Permissions.Add(p); db.Roles.Add(role); db.RolePermissions.Add(link); await db.SaveChangesAsync(); var handler = new DeletePermissionCommandHandler(db); await handler.Handle(new DeletePermissionCommand(p.Id), CancellationToken.None); (await db.Permissions.AnyAsync(x => x.Id == p.Id)).Should().BeFalse("软删后不可见"); } [Fact] public async Task Delete_NonExistent_ThrowsNotFound() { var db = CreateDb(); var handler = new DeletePermissionCommandHandler(db); var act = async () => await handler.Handle(new DeletePermissionCommand(Guid.NewGuid()), CancellationToken.None); await act.Should().ThrowAsync(); } [Fact] public async Task GetList_ReturnsAll() { var db = CreateDb(); db.Permissions.AddRange(NewPermission("p1"), NewPermission("p2")); await db.SaveChangesAsync(); var handler = new GetPermissionListQueryHandler(db); var result = await handler.Handle(new GetPermissionListQuery(), CancellationToken.None); result.Should().HaveCount(2); } [Fact] public async Task GetById_Existing_ReturnsDto() { var db = CreateDb(); var p = NewPermission("user:read"); db.Permissions.Add(p); await db.SaveChangesAsync(); var handler = new GetPermissionByIdQueryHandler(db); var result = await handler.Handle(new GetPermissionByIdQuery(p.Id), CancellationToken.None); result.Code.Should().Be("user:read"); } [Fact] public async Task GetById_NonExistent_ThrowsNotFound() { var db = CreateDb(); var handler = new GetPermissionByIdQueryHandler(db); var act = async () => await handler.Handle(new GetPermissionByIdQuery(Guid.NewGuid()), CancellationToken.None); await act.Should().ThrowAsync(); } [Fact] public async Task GetTree_GroupsByGroupField() { var db = CreateDb(); db.Permissions.AddRange( NewPermission("a:1", "GroupA"), NewPermission("a:2", "GroupA"), NewPermission("b:1", "GroupB")); await db.SaveChangesAsync(); var handler = new GetPermissionTreeQueryHandler(db); var tree = await handler.Handle(new GetPermissionTreeQuery(), CancellationToken.None); tree.Should().HaveCount(2); tree.First(g => g.Group == "GroupA").Permissions.Should().HaveCount(2); tree.First(g => g.Group == "GroupB").Permissions.Should().HaveCount(1); } [Fact] public async Task GetTree_NullGroup_GoesToUngrouped() { var db = CreateDb(); db.Permissions.Add(NewPermission("no:group", null)); await db.SaveChangesAsync(); var handler = new GetPermissionTreeQueryHandler(db); var tree = await handler.Handle(new GetPermissionTreeQuery(), CancellationToken.None); tree.Should().ContainSingle(); tree[0].Group.Should().Be("未分组"); } }