using FluentAssertions; using ProposalSystem.Application.DTOs; using ProposalSystem.Application.Validators; using ProposalSystem.Domain.Entities; using Xunit; namespace ProposalSystem.Tests.Validators; /// /// Tests for CreateProposalValidator — validates request payloads before /// they hit the service layer. /// public class CreateProposalValidatorTests { private readonly CreateProposalValidator _sut = new(); [Fact(DisplayName = "Valid proposal request passes validation")] public void ValidRequest_Passes() { var request = new CreateProposalRequest( WorkOrderNumber: "WO-001", CustomerName: "Acme Corp", CustomerAddress: "123 Main St, Suite 100", ScopeOfWork: "Replace HVAC system in building B", ServiceCategory: ServiceCategory.HVAC, Priority: Priority.Standard, Notes: "Initial assessment complete" ); var result = _sut.Validate(request); result.IsValid.Should().BeTrue(); } [Theory(DisplayName = "Empty required fields fail validation")] [InlineData("", "Customer", "Address", "Scope")] [InlineData("WO-001", "", "Address", "Scope")] [InlineData("WO-001", "Customer", "", "Scope")] [InlineData("WO-001", "Customer", "Address", "")] public void EmptyRequiredFields_Fail(string wo, string name, string address, string scope) { var request = new CreateProposalRequest(wo, name, address, scope, ServiceCategory.General, Priority.Standard, null); var result = _sut.Validate(request); result.IsValid.Should().BeFalse(); } [Fact(DisplayName = "WorkOrderNumber exceeding 50 chars fails")] public void WorkOrderNumber_TooLong_Fails() { var request = new CreateProposalRequest( WorkOrderNumber: new string('X', 51), CustomerName: "Customer", CustomerAddress: "Address", ScopeOfWork: "Scope", ServiceCategory: ServiceCategory.General, Priority: Priority.Standard, Notes: null ); var result = _sut.Validate(request); result.IsValid.Should().BeFalse(); result.Errors.Should().Contain(e => e.PropertyName == "WorkOrderNumber"); } [Fact(DisplayName = "CustomerName exceeding 200 chars fails")] public void CustomerName_TooLong_Fails() { var request = new CreateProposalRequest( WorkOrderNumber: "WO-001", CustomerName: new string('X', 201), CustomerAddress: "Address", ScopeOfWork: "Scope", ServiceCategory: ServiceCategory.General, Priority: Priority.Standard, Notes: null ); var result = _sut.Validate(request); result.IsValid.Should().BeFalse(); result.Errors.Should().Contain(e => e.PropertyName == "CustomerName"); } [Fact(DisplayName = "ScopeOfWork exceeding 10000 chars fails")] public void ScopeOfWork_TooLong_Fails() { var request = new CreateProposalRequest( WorkOrderNumber: "WO-001", CustomerName: "Customer", CustomerAddress: "Address", ScopeOfWork: new string('X', 10001), ServiceCategory: ServiceCategory.General, Priority: Priority.Standard, Notes: null ); var result = _sut.Validate(request); result.IsValid.Should().BeFalse(); result.Errors.Should().Contain(e => e.PropertyName == "ScopeOfWork"); } [Fact(DisplayName = "Notes exceeding 5000 chars fails")] public void Notes_TooLong_Fails() { var request = new CreateProposalRequest( WorkOrderNumber: "WO-001", CustomerName: "Customer", CustomerAddress: "Address", ScopeOfWork: "Scope", ServiceCategory: ServiceCategory.General, Priority: Priority.Standard, Notes: new string('X', 5001) ); var result = _sut.Validate(request); result.IsValid.Should().BeFalse(); result.Errors.Should().Contain(e => e.PropertyName == "Notes"); } [Fact(DisplayName = "Null notes are valid")] public void NullNotes_Passes() { var request = new CreateProposalRequest( WorkOrderNumber: "WO-001", CustomerName: "Customer", CustomerAddress: "Address", ScopeOfWork: "Scope", ServiceCategory: ServiceCategory.General, Priority: Priority.Standard, Notes: null ); var result = _sut.Validate(request); result.IsValid.Should().BeTrue(); } [Fact(DisplayName = "Invalid ServiceCategory enum value fails")] public void InvalidServiceCategory_Fails() { var request = new CreateProposalRequest( WorkOrderNumber: "WO-001", CustomerName: "Customer", CustomerAddress: "Address", ScopeOfWork: "Scope", ServiceCategory: (ServiceCategory)999, Priority: Priority.Standard, Notes: null ); var result = _sut.Validate(request); result.IsValid.Should().BeFalse(); result.Errors.Should().Contain(e => e.PropertyName == "ServiceCategory"); } [Fact(DisplayName = "Invalid Priority enum value fails")] public void InvalidPriority_Fails() { var request = new CreateProposalRequest( WorkOrderNumber: "WO-001", CustomerName: "Customer", CustomerAddress: "Address", ScopeOfWork: "Scope", ServiceCategory: ServiceCategory.General, Priority: (Priority)999, Notes: null ); var result = _sut.Validate(request); result.IsValid.Should().BeFalse(); result.Errors.Should().Contain(e => e.PropertyName == "Priority"); } }