using FluentValidation; using NSubstitute; using SIGCM2.Application.Abstractions.Persistence; using SIGCM2.Application.Permisos.GetByRol; using SIGCM2.Domain.Entities; using SIGCM2.Domain.Exceptions; namespace SIGCM2.Application.Tests.Permisos.GetByRol; public class GetRolPermisosQueryHandlerTests { private readonly IRolRepository _rolRepository = Substitute.For(); private readonly IRolPermisoRepository _rolPermisoRepository = Substitute.For(); private readonly GetRolPermisosQueryHandler _handler; public GetRolPermisosQueryHandlerTests() { _handler = new GetRolPermisosQueryHandler(_rolRepository, _rolPermisoRepository); } private static Rol MakeRol(int id, string codigo) => new(id, codigo, codigo, null, true, DateTime.UtcNow, null); private static Permiso MakePermiso(int id, string codigo, string modulo) => Permiso.ForRead(id, codigo, codigo, null, modulo, true, DateTime.UtcNow); [Fact] public async Task Handle_ExistingRol_ReturnsMappedPermisoDtos() { var now = new DateTime(2026, 4, 15, 10, 0, 0, DateTimeKind.Utc); _rolRepository.GetByCodigoAsync("cajero").Returns(MakeRol(5, "cajero")); _rolPermisoRepository.GetByRolCodigoAsync("cajero").Returns(new List { MakePermiso(1, "ventas:contado:crear", "ventas"), MakePermiso(2, "ventas:contado:cobrar", "ventas"), MakePermiso(3, "ventas:contado:facturar","ventas"), MakePermiso(4, "ventas:contado:modificar","ventas"), }); var result = await _handler.Handle(new GetRolPermisosQuery("cajero")); Assert.Equal(4, result.Count); Assert.Contains(result, r => r.Codigo == "ventas:contado:crear"); } [Fact] public async Task Handle_RolWithNoPermisos_ReturnsEmptyList() { _rolRepository.GetByCodigoAsync("reportes").Returns(MakeRol(3, "reportes")); _rolPermisoRepository.GetByRolCodigoAsync("reportes").Returns(new List()); var result = await _handler.Handle(new GetRolPermisosQuery("reportes")); Assert.Empty(result); } [Fact] public async Task Handle_NonExistentRol_ThrowsRolNotFoundException() { _rolRepository.GetByCodigoAsync("inexistente").Returns((Rol?)null); var ex = await Assert.ThrowsAsync( () => _handler.Handle(new GetRolPermisosQuery("inexistente"))); Assert.Equal("inexistente", ex.Codigo); } [Fact] public async Task Handle_NonExistentRol_DoesNotCallRolPermisoRepository() { _rolRepository.GetByCodigoAsync("ghost").Returns((Rol?)null); await Assert.ThrowsAsync( () => _handler.Handle(new GetRolPermisosQuery("ghost"))); await _rolPermisoRepository.DidNotReceive().GetByRolCodigoAsync(Arg.Any()); } [Fact] public async Task Handle_AdminRol_Returns18Permisos() { _rolRepository.GetByCodigoAsync("admin").Returns(MakeRol(1, "admin")); var adminPermisos = Enumerable.Range(1, 18) .Select(i => MakePermiso(i, $"modulo{i}:accion{i}", $"modulo{i}")) .ToList(); _rolPermisoRepository.GetByRolCodigoAsync("admin").Returns(adminPermisos); var result = await _handler.Handle(new GetRolPermisosQuery("admin")); Assert.Equal(18, result.Count); } } public class GetRolPermisosQueryValidatorTests { private readonly IValidator _validator = new GetRolPermisosQueryValidator(); [Theory] [InlineData("ROL-INVALIDO")] [InlineData("ROL:INVALIDO")] [InlineData("123abc")] [InlineData("UPPER")] [InlineData("con espacio")] [InlineData("")] public async Task Validate_InvalidCodigoFormat_ReturnsInvalid(string codigo) { var result = await _validator.ValidateAsync(new GetRolPermisosQuery(codigo)); Assert.False(result.IsValid); } [Theory] [InlineData("admin")] [InlineData("cajero")] [InlineData("rol_valido")] [InlineData("abc123")] public async Task Validate_ValidCodigoFormat_ReturnsValid(string codigo) { var result = await _validator.ValidateAsync(new GetRolPermisosQuery(codigo)); Assert.True(result.IsValid); } }