using BuildFlow.Platform.Application.Roles.Commands; using BuildFlow.Platform.Application.Roles.Handlers; using BuildFlow.Platform.Application.Users.Commands; using BuildFlow.Platform.Application.Users.Handlers; using BuildFlow.Platform.Application.Users.Queries; using BuildFlow.Platform.Infrastructure.Persistence; using BuildFlow.Shared.Domain.Errors; using BuildFlow.Shared.Domain.Exceptions; using FluentAssertions; using Microsoft.EntityFrameworkCore; using Xunit; namespace BuildFlow.Platform.Tests.Users; /// /// [SOP-PLATFORM] Users 模块 6 个 Handler 覆盖测试。 /// 覆盖: GetList / GetById / GetNames / Create / Update / Delete。 /// 飞书矩阵: platform/Users 子域(6 Handler 零覆盖→全补)。 /// public class UsersHandlerTests { private static PlatformDbContext CreateDb([System.Runtime.CompilerServices.CallerMemberName] string name = "") => PlatformTestDb.CreateDbContext(name); private static async Task SeedUserRole(PlatformDbContext db) => await new CreateRoleCommandHandler(db).Handle(new CreateRoleCommand("User", null), CancellationToken.None); #region GetUserList [Fact] public async Task GetUserList_ReturnsAll() { var db = CreateDb(); await PlatformTestDb.SeedUserAsync(db, Guid.NewGuid(), "u1"); await PlatformTestDb.SeedUserAsync(db, Guid.NewGuid(), "u2"); var result = await new GetUserListQueryHandler(db) .Handle(new GetUserListQuery(null), CancellationToken.None); result.Should().HaveCount(2); } [Fact] public async Task GetUserList_SearchFilters() { var db = CreateDb(); await PlatformTestDb.SeedUserAsync(db, Guid.NewGuid(), "searchme"); await PlatformTestDb.SeedUserAsync(db, Guid.NewGuid(), "otherguy"); var result = await new GetUserListQueryHandler(db) .Handle(new GetUserListQuery("searchme"), CancellationToken.None); result.Should().ContainSingle(); result[0].Username.Should().Be("searchme"); } #endregion #region GetUserById [Fact] public async Task GetUserById_Existing_ReturnsDto() { var db = CreateDb(); var user = await PlatformTestDb.SeedUserAsync(db, Guid.NewGuid(), "bob"); var result = await new GetUserByIdQueryHandler(db) .Handle(new GetUserByIdQuery(user.Id), CancellationToken.None); result.Username.Should().Be("bob"); } [Fact] public async Task GetUserById_NonExistent_ThrowsNotFound() { var db = CreateDb(); var act = async () => await new GetUserByIdQueryHandler(db) .Handle(new GetUserByIdQuery(Guid.NewGuid()), CancellationToken.None); var ex = await act.Should().ThrowAsync(); ex.Which.Code.Should().Be(ErrorCode.NotFound); } #endregion #region GetUserNames [Fact] public async Task GetUserNames_EmptyIds_ReturnsEmpty() { var db = CreateDb(); var result = await new GetUserNamesQueryHandler(db) .Handle(new GetUserNamesQuery(new List()), CancellationToken.None); result.Should().BeEmpty(); } [Fact] public async Task GetUserNames_WithIds_ReturnsMap() { var db = CreateDb(); var user = await PlatformTestDb.SeedUserAsync(db, Guid.NewGuid(), "namer"); var result = await new GetUserNamesQueryHandler(db) .Handle(new GetUserNamesQuery(new List { user.Id }), CancellationToken.None); result.Should().ContainKey(user.Id); result[user.Id].Should().Be("namer"); } #endregion #region CreateUser [Fact] public async Task CreateUser_Valid_ReturnsDtoAndAssignsUserRole() { var db = CreateDb(); await SeedUserRole(db); var result = await new CreateUserCommandHandler(db) .Handle(new CreateUserCommand("alice", "alice@test.local", "Pass@123"), CancellationToken.None); result.Username.Should().Be("alice"); result.Roles.Should().Contain("User"); (await db.Users.CountAsync()).Should().Be(1); } [Fact] public async Task CreateUser_DuplicateUsername_ThrowsBusiness() { var db = CreateDb(); await SeedUserRole(db); await new CreateUserCommandHandler(db) .Handle(new CreateUserCommand("alice", "alice@test.local", "Pass@123"), CancellationToken.None); var act = async () => await new CreateUserCommandHandler(db) .Handle(new CreateUserCommand("alice", "other@test.local", "Pass@123"), CancellationToken.None); var ex = await act.Should().ThrowAsync(); ex.Which.Code.Should().Be(ErrorCode.AlreadyExists); } #endregion #region UpdateUser [Fact] public async Task UpdateUser_Existing_UpdatesFields() { var db = CreateDb(); var user = await PlatformTestDb.SeedUserAsync(db, Guid.NewGuid(), "carol"); var result = await new UpdateUserCommandHandler(db) .Handle(new UpdateUserCommand(user.Id, "carol2@test.local", null, false), CancellationToken.None); result.Email.Should().Be("carol2@test.local"); result.IsActive.Should().BeFalse(); } [Fact] public async Task UpdateUser_NonExistent_ThrowsNotFound() { var db = CreateDb(); var act = async () => await new UpdateUserCommandHandler(db) .Handle(new UpdateUserCommand(Guid.NewGuid(), null, null, null), CancellationToken.None); var ex = await act.Should().ThrowAsync(); ex.Which.Code.Should().Be(ErrorCode.NotFound); } #endregion #region DeleteUser [Fact] public async Task DeleteUser_Existing_Removes() { var db = CreateDb(); var user = await PlatformTestDb.SeedUserAsync(db, Guid.NewGuid(), "dave"); await new DeleteUserCommandHandler(db).Handle(new DeleteUserCommand(user.Id), CancellationToken.None); (await db.Users.CountAsync()).Should().Be(0); } [Fact] public async Task DeleteUser_NonExistent_ThrowsNotFound() { var db = CreateDb(); var act = async () => await new DeleteUserCommandHandler(db) .Handle(new DeleteUserCommand(Guid.NewGuid()), CancellationToken.None); var ex = await act.Should().ThrowAsync(); ex.Which.Code.Should().Be(ErrorCode.NotFound); } #endregion }