using FluentAssertions; using ProposalSystem.Application.DTOs; using ProposalSystem.Application.Validators; using Xunit; namespace ProposalSystem.Tests.Validators; /// /// PR4: Tests for customer email format validation on both Create and Update DTOs. /// Ensures the ContactEmail field, when provided, must be a valid email address. /// public class CustomerEmailValidatorTests { private readonly CreateCustomerValidator _createValidator = new(); private readonly UpdateCustomerValidator _updateValidator = new(); #region CreateCustomerValidator — ContactEmail [Fact(DisplayName = "Create: null ContactEmail passes validation")] public void Create_NullEmail_Passes() { var request = new CreateCustomerRequest("Acme Corp", null, null); var result = _createValidator.Validate(request); result.IsValid.Should().BeTrue(); } [Fact(DisplayName = "Create: valid ContactEmail passes validation")] public void Create_ValidEmail_Passes() { var request = new CreateCustomerRequest("Acme Corp", null, "john@example.com"); var result = _createValidator.Validate(request); result.IsValid.Should().BeTrue(); } [Theory(DisplayName = "Create: invalid ContactEmail fails validation")] [InlineData("not-an-email")] [InlineData("missing@")] [InlineData("@no-local.com")] public void Create_InvalidEmail_Fails(string email) { var request = new CreateCustomerRequest("Acme Corp", null, email); var result = _createValidator.Validate(request); result.IsValid.Should().BeFalse(); result.Errors.Should().Contain(e => e.PropertyName == "ContactEmail"); } [Fact(DisplayName = "Create: ContactEmail exceeding 320 chars fails")] public void Create_EmailTooLong_Fails() { var longEmail = new string('a', 310) + "@example.com"; // 322 chars var request = new CreateCustomerRequest("Acme Corp", null, longEmail); var result = _createValidator.Validate(request); result.IsValid.Should().BeFalse(); result.Errors.Should().Contain(e => e.PropertyName == "ContactEmail"); } #endregion #region UpdateCustomerValidator — ContactEmail [Fact(DisplayName = "Update: null ContactEmail passes validation")] public void Update_NullEmail_Passes() { var request = new UpdateCustomerRequest(null, null, null); var result = _updateValidator.Validate(request); result.IsValid.Should().BeTrue(); } [Fact(DisplayName = "Update: valid ContactEmail passes validation")] public void Update_ValidEmail_Passes() { var request = new UpdateCustomerRequest(null, null, "john@example.com"); var result = _updateValidator.Validate(request); result.IsValid.Should().BeTrue(); } [Theory(DisplayName = "Update: invalid ContactEmail fails validation")] [InlineData("not-an-email")] [InlineData("missing@")] [InlineData("@no-local.com")] public void Update_InvalidEmail_Fails(string email) { var request = new UpdateCustomerRequest(null, null, email); var result = _updateValidator.Validate(request); result.IsValid.Should().BeFalse(); result.Errors.Should().Contain(e => e.PropertyName == "ContactEmail"); } [Fact(DisplayName = "Update: name exceeding 200 chars fails")] public void Update_NameTooLong_Fails() { var request = new UpdateCustomerRequest(new string('X', 201), null, null); var result = _updateValidator.Validate(request); result.IsValid.Should().BeFalse(); result.Errors.Should().Contain(e => e.PropertyName == "Name"); } #endregion }