Files
SIG-CM2.0/tests/SIGCM2.Application.Tests/Usuarios/Create/CreateUsuarioCommandValidatorTests.cs
dmolinari 34b714750a feat(api): UDT-004 dominio + repositorio + application roles (tdd)
- Migraciones V003 (tabla Rol + 8 seeds canonicos) y V004 (drop CK + FK Usuario.Rol)
- Dominio: Rol entity + 3 excepciones (RolNotFound/AlreadyExists/InUse)
- Infraestructura: RolRepository (Dapper) con List/Get/ExistsActive/Add/Update/HasActiveUsuarios
- Application: CRUD queries y commands (List, Get, Create, Update, Deactivate) + validators (codigo regex ^[a-z][a-z0-9_]*$)
- Validator UDT-003: whitelist alineada a codigos canonicos (full IRolRepository lookup diferido a Phase 5.1)
- Tests: 169 application + 15 api (todos verdes). Respawn configurado para re-seedear Rol canonical post-reset.
- Estricto TDD: RED/GREEN/TRIANGULATE en todos los handlers nuevos.
2026-04-15 12:31:29 -03:00

199 lines
7.3 KiB
C#

using FluentValidation.TestHelper;
using SIGCM2.Application.Auth;
using SIGCM2.Application.Usuarios.Create;
namespace SIGCM2.Application.Tests.Usuarios.Create;
public class CreateUsuarioCommandValidatorTests
{
private static CreateUsuarioCommandValidator BuildValidator(AuthOptions? opts = null) =>
new(opts ?? new AuthOptions());
private static CreateUsuarioCommand ValidCommand() => new(
Username: "operador1",
Password: "Secreto123",
Nombre: "Juan",
Apellido: "Pérez",
Email: null,
Rol: "cajero");
// ── Happy paths ──────────────────────────────────────────────────────────
[Fact]
public void Validate_ValidCommand_NoErrors()
{
var result = BuildValidator().TestValidate(ValidCommand());
result.ShouldNotHaveAnyValidationErrors();
}
[Fact]
public void Validate_NullEmail_IsValid()
{
var cmd = ValidCommand() with { Email = null };
BuildValidator().TestValidate(cmd).ShouldNotHaveAnyValidationErrors();
}
[Fact]
public void Validate_ValidEmailPresent_NoErrors()
{
var cmd = ValidCommand() with { Email = "juan@example.com" };
BuildValidator().TestValidate(cmd).ShouldNotHaveAnyValidationErrors();
}
// ── Username ─────────────────────────────────────────────────────────────
[Fact]
public void Validate_EmptyUsername_HasError()
{
var cmd = ValidCommand() with { Username = "" };
BuildValidator().TestValidate(cmd).ShouldHaveValidationErrorFor(c => c.Username);
}
[Fact]
public void Validate_UsernameTooShort_HasError()
{
var cmd = ValidCommand() with { Username = "ab" };
BuildValidator().TestValidate(cmd).ShouldHaveValidationErrorFor(c => c.Username);
}
[Fact]
public void Validate_UsernameTooLong_HasError()
{
var cmd = ValidCommand() with { Username = new string('a', 51) };
BuildValidator().TestValidate(cmd).ShouldHaveValidationErrorFor(c => c.Username);
}
[Theory]
[InlineData("abc")] // 3 chars — boundary valid
[InlineData("user.name")] // dot allowed
[InlineData("user-name")] // dash allowed
[InlineData("user_name")] // underscore allowed
[InlineData("user123")] // alphanumeric
public void Validate_UsernameValidFormats_NoError(string username)
{
var cmd = ValidCommand() with { Username = username };
BuildValidator().TestValidate(cmd).ShouldNotHaveValidationErrorFor(c => c.Username);
}
[Theory]
[InlineData("user name")] // space not allowed
[InlineData("user@name")] // @ not allowed
[InlineData("user#1")] // # not allowed
public void Validate_UsernameInvalidChars_HasError(string username)
{
var cmd = ValidCommand() with { Username = username };
BuildValidator().TestValidate(cmd).ShouldHaveValidationErrorFor(c => c.Username);
}
// ── Password ─────────────────────────────────────────────────────────────
[Fact]
public void Validate_EmptyPassword_HasError()
{
var cmd = ValidCommand() with { Password = "" };
BuildValidator().TestValidate(cmd).ShouldHaveValidationErrorFor(c => c.Password);
}
[Fact]
public void Validate_PasswordTooShort_HasError()
{
var cmd = ValidCommand() with { Password = "Ab1cd5" }; // 6 chars < 8
BuildValidator().TestValidate(cmd).ShouldHaveValidationErrorFor(c => c.Password);
}
[Fact]
public void Validate_PasswordNoLetter_HasError()
{
var cmd = ValidCommand() with { Password = "12345678" }; // digits only
BuildValidator().TestValidate(cmd).ShouldHaveValidationErrorFor(c => c.Password);
}
[Fact]
public void Validate_PasswordNoDigit_HasError()
{
var cmd = ValidCommand() with { Password = "abcdefgh" }; // letters only
BuildValidator().TestValidate(cmd).ShouldHaveValidationErrorFor(c => c.Password);
}
[Fact]
public void Validate_PasswordExactMinLength_NoError()
{
var cmd = ValidCommand() with { Password = "Secre123" }; // exactly 8, letter + digit
BuildValidator().TestValidate(cmd).ShouldNotHaveValidationErrorFor(c => c.Password);
}
// ── Nombre / Apellido ────────────────────────────────────────────────────
[Fact]
public void Validate_EmptyNombre_HasError()
{
var cmd = ValidCommand() with { Nombre = "" };
BuildValidator().TestValidate(cmd).ShouldHaveValidationErrorFor(c => c.Nombre);
}
[Fact]
public void Validate_EmptyApellido_HasError()
{
var cmd = ValidCommand() with { Apellido = "" };
BuildValidator().TestValidate(cmd).ShouldHaveValidationErrorFor(c => c.Apellido);
}
[Fact]
public void Validate_NombreTooLong_HasError()
{
var cmd = ValidCommand() with { Nombre = new string('a', 101) };
BuildValidator().TestValidate(cmd).ShouldHaveValidationErrorFor(c => c.Nombre);
}
[Fact]
public void Validate_ApellidoTooLong_HasError()
{
var cmd = ValidCommand() with { Apellido = new string('a', 101) };
BuildValidator().TestValidate(cmd).ShouldHaveValidationErrorFor(c => c.Apellido);
}
// ── Rol ──────────────────────────────────────────────────────────────────
[Theory]
[InlineData("admin")]
[InlineData("cajero")]
[InlineData("operador_ctacte")]
[InlineData("picadora")]
[InlineData("jefe_publicidad")]
[InlineData("productor")]
[InlineData("diagramacion")]
[InlineData("reportes")]
public void Validate_ValidRoles_NoError(string rol)
{
var cmd = ValidCommand() with { Rol = rol };
BuildValidator().TestValidate(cmd).ShouldNotHaveValidationErrorFor(c => c.Rol);
}
[Theory]
[InlineData("superuser")]
[InlineData("ADMIN")] // case-sensitive
[InlineData("root")]
[InlineData("")]
public void Validate_InvalidRol_HasError(string rol)
{
var cmd = ValidCommand() with { Rol = rol };
BuildValidator().TestValidate(cmd).ShouldHaveValidationErrorFor(c => c.Rol);
}
// ── Email ────────────────────────────────────────────────────────────────
[Fact]
public void Validate_InvalidEmail_HasError()
{
var cmd = ValidCommand() with { Email = "not-an-email" };
BuildValidator().TestValidate(cmd).ShouldHaveValidationErrorFor(c => c.Email);
}
[Fact]
public void Validate_EmailTooLong_HasError()
{
var cmd = ValidCommand() with { Email = new string('a', 145) + "@b.com" }; // >150
BuildValidator().TestValidate(cmd).ShouldHaveValidationErrorFor(c => c.Email);
}
}