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); } }