namespace Application.Tests.Validators; using Application.Enrollments.Commands; using Application.Students.Commands; using Domain.Ports.Repositories; using FluentAssertions; using FluentValidation.TestHelper; using NSubstitute; using Xunit; public class CreateStudentValidatorTests { private readonly IStudentRepository _studentRepository; private readonly CreateStudentValidator _validator; public CreateStudentValidatorTests() { _studentRepository = Substitute.For(); _studentRepository.EmailExistsAsync(Arg.Any(), Arg.Any(), Arg.Any()) .Returns(false); _validator = new CreateStudentValidator(_studentRepository); } [Fact] public async Task Validate_WithValidCommand_ShouldNotHaveErrors() { // Arrange var command = new CreateStudentCommand("John Doe", "john@example.com"); // Act var result = await _validator.TestValidateAsync(command); // Assert result.ShouldNotHaveAnyValidationErrors(); } [Fact] public async Task Validate_WithEmptyName_ShouldHaveError() { // Arrange var command = new CreateStudentCommand("", "john@example.com"); // Act var result = await _validator.TestValidateAsync(command); // Assert result.ShouldHaveValidationErrorFor(x => x.Name); } [Fact] public async Task Validate_WithEmptyEmail_ShouldHaveError() { // Arrange var command = new CreateStudentCommand("John Doe", ""); // Act var result = await _validator.TestValidateAsync(command); // Assert result.ShouldHaveValidationErrorFor(x => x.Email); } [Fact] public async Task Validate_WithInvalidEmail_ShouldHaveError() { // Arrange var command = new CreateStudentCommand("John Doe", "invalid-email"); // Act var result = await _validator.TestValidateAsync(command); // Assert result.ShouldHaveValidationErrorFor(x => x.Email); } [Fact] public async Task Validate_WithExistingEmail_ShouldHaveError() { // Arrange _studentRepository.EmailExistsAsync("existing@example.com", null, Arg.Any()) .Returns(true); var command = new CreateStudentCommand("John Doe", "existing@example.com"); // Act var result = await _validator.TestValidateAsync(command); // Assert result.ShouldHaveValidationErrorFor(x => x.Email) .WithErrorMessage("Email already exists"); } [Fact] public async Task Validate_WithNameTooLong_ShouldHaveError() { // Arrange var longName = new string('A', 101); var command = new CreateStudentCommand(longName, "john@example.com"); // Act var result = await _validator.TestValidateAsync(command); // Assert result.ShouldHaveValidationErrorFor(x => x.Name); } [Fact] public async Task Validate_WithNameTooShort_ShouldHaveError() { // Arrange var command = new CreateStudentCommand("AB", "john@example.com"); // Act var result = await _validator.TestValidateAsync(command); // Assert result.ShouldHaveValidationErrorFor(x => x.Name) .WithErrorMessage("Name must be at least 3 characters"); } [Theory] [InlineData("")] [InlineData("John")] [InlineData("javascript:alert(1)")] public async Task Validate_WithDangerousName_ShouldHaveError(string dangerousName) { // Arrange var command = new CreateStudentCommand(dangerousName, "john@example.com"); // Act var result = await _validator.TestValidateAsync(command); // Assert result.ShouldHaveValidationErrorFor(x => x.Name); } [Theory] [InlineData("John123")] [InlineData("John@Doe")] [InlineData("John#Doe")] public async Task Validate_WithInvalidCharactersInName_ShouldHaveError(string invalidName) { // Arrange var command = new CreateStudentCommand(invalidName, "john@example.com"); // Act var result = await _validator.TestValidateAsync(command); // Assert result.ShouldHaveValidationErrorFor(x => x.Name) .WithErrorMessage("Name contains invalid characters"); } [Theory] [InlineData("María García")] [InlineData("José O'Brien")] [InlineData("Ana-María López")] [InlineData("Dr. Juan Pérez")] public async Task Validate_WithValidSpecialCharactersInName_ShouldPass(string validName) { // Arrange var command = new CreateStudentCommand(validName, "john@example.com"); // Act var result = await _validator.TestValidateAsync(command); // Assert result.ShouldNotHaveValidationErrorFor(x => x.Name); } [Fact] public async Task Validate_WithEmailTooLong_ShouldHaveError() { // Arrange var longEmail = new string('a', 250) + "@example.com"; var command = new CreateStudentCommand("John Doe", longEmail); // Act var result = await _validator.TestValidateAsync(command); // Assert result.ShouldHaveValidationErrorFor(x => x.Email); } } public class UpdateStudentValidatorTests { private readonly IStudentRepository _studentRepository; private readonly UpdateStudentValidator _validator; public UpdateStudentValidatorTests() { _studentRepository = Substitute.For(); _studentRepository.EmailExistsAsync(Arg.Any(), Arg.Any(), Arg.Any()) .Returns(false); _validator = new UpdateStudentValidator(_studentRepository); } [Fact] public async Task Validate_WithValidCommand_ShouldNotHaveErrors() { // Arrange var command = new UpdateStudentCommand(1, "John Doe", "john@example.com"); // Act var result = await _validator.TestValidateAsync(command); // Assert result.ShouldNotHaveAnyValidationErrors(); } [Fact] public async Task Validate_WithInvalidId_ShouldHaveError() { // Arrange var command = new UpdateStudentCommand(0, "John Doe", "john@example.com"); // Act var result = await _validator.TestValidateAsync(command); // Assert result.ShouldHaveValidationErrorFor(x => x.Id); } [Fact] public async Task Validate_WithNegativeId_ShouldHaveError() { // Arrange var command = new UpdateStudentCommand(-1, "John Doe", "john@example.com"); // Act var result = await _validator.TestValidateAsync(command); // Assert result.ShouldHaveValidationErrorFor(x => x.Id); } } public class EnrollStudentValidatorTests { private readonly EnrollStudentValidator _validator; public EnrollStudentValidatorTests() { _validator = new EnrollStudentValidator(); } [Fact] public async Task Validate_WithValidCommand_ShouldNotHaveErrors() { // Arrange var command = new EnrollStudentCommand(1, 1); // Act var result = await _validator.TestValidateAsync(command); // Assert result.ShouldNotHaveAnyValidationErrors(); } [Fact] public async Task Validate_WithInvalidStudentId_ShouldHaveError() { // Arrange var command = new EnrollStudentCommand(0, 1); // Act var result = await _validator.TestValidateAsync(command); // Assert result.ShouldHaveValidationErrorFor(x => x.StudentId); } [Fact] public async Task Validate_WithInvalidSubjectId_ShouldHaveError() { // Arrange var command = new EnrollStudentCommand(1, 0); // Act var result = await _validator.TestValidateAsync(command); // Assert result.ShouldHaveValidationErrorFor(x => x.SubjectId); } } public class UnenrollStudentValidatorTests { private readonly UnenrollStudentValidator _validator; public UnenrollStudentValidatorTests() { _validator = new UnenrollStudentValidator(); } [Fact] public async Task Validate_WithValidCommand_ShouldNotHaveErrors() { // Arrange var command = new UnenrollStudentCommand(1); // Act var result = await _validator.TestValidateAsync(command); // Assert result.ShouldNotHaveAnyValidationErrors(); } [Fact] public async Task Validate_WithInvalidEnrollmentId_ShouldHaveError() { // Arrange var command = new UnenrollStudentCommand(0); // Act var result = await _validator.TestValidateAsync(command); // Assert result.ShouldHaveValidationErrorFor(x => x.EnrollmentId); } }