From fadfae60eabfce00af8738aa480f22d4babd8835 Mon Sep 17 00:00:00 2001 From: Ian Nelson Date: Fri, 30 May 2025 16:53:16 +0100 Subject: [PATCH] fix: DTOSS-9177 - unit tests for ValidationRunner --- .../Validation/ValidationRunner.cs | 10 +- .../Validation/ValidationRunnerTests.cs | 219 ++++++++++++++++++ .../Functions/FileTransformFunctionTests.cs | 19 -- .../ValidationErrorComparer.cs | 20 ++ 4 files changed, 244 insertions(+), 24 deletions(-) create mode 100644 tests/ServiceLayer.Mesh.Tests/FileTypes/NbssAppointmentEvents/Validation/ValidationRunnerTests.cs create mode 100644 tests/ServiceLayer.Mesh.Tests/ValidationErrorComparer.cs diff --git a/src/ServiceLayer.Mesh/FileTypes/NbssAppointmentEvents/Validation/ValidationRunner.cs b/src/ServiceLayer.Mesh/FileTypes/NbssAppointmentEvents/Validation/ValidationRunner.cs index 1aa776e..351c24c 100644 --- a/src/ServiceLayer.Mesh/FileTypes/NbssAppointmentEvents/Validation/ValidationRunner.cs +++ b/src/ServiceLayer.Mesh/FileTypes/NbssAppointmentEvents/Validation/ValidationRunner.cs @@ -11,6 +11,11 @@ public IList Validate(ParsedFile file) { var errors = new List(); + foreach (var validator in fileValidators) + { + errors.AddRange(validator.Validate(file)); + } + foreach (var dataRecord in file.DataRecords) { foreach (var recordValidator in recordValidators) @@ -19,11 +24,6 @@ public IList Validate(ParsedFile file) } } - foreach (var validator in fileValidators) - { - errors.AddRange(validator.Validate(file)); - } - return errors; } } diff --git a/tests/ServiceLayer.Mesh.Tests/FileTypes/NbssAppointmentEvents/Validation/ValidationRunnerTests.cs b/tests/ServiceLayer.Mesh.Tests/FileTypes/NbssAppointmentEvents/Validation/ValidationRunnerTests.cs new file mode 100644 index 0000000..329e020 --- /dev/null +++ b/tests/ServiceLayer.Mesh.Tests/FileTypes/NbssAppointmentEvents/Validation/ValidationRunnerTests.cs @@ -0,0 +1,219 @@ +using Moq; +using ServiceLayer.Mesh.FileTypes.NbssAppointmentEvents.Models; +using ServiceLayer.Mesh.FileTypes.NbssAppointmentEvents.Validation; + +namespace ServiceLayer.Mesh.Tests.FileTypes.NbssAppointmentEvents.Validation; + +public class ValidationRunnerTests +{ + [Fact] + public void Validate_FileAndRecordValidatorsReturnErrors_ReturnsAllErrors() + { + // Arrange + var file = new ParsedFile + { + DataRecords = [new FileDataRecord(), new FileDataRecord()] + }; + + var fileValidationError1 = BuildValidationError(ValidationErrorScope.File); + var fileValidationError2 = BuildValidationError(ValidationErrorScope.File); + var fileValidationError3 = BuildValidationError(ValidationErrorScope.File); + var recordValidationError1 = BuildValidationError(ValidationErrorScope.Record); + var recordValidationError2 = BuildValidationError(ValidationErrorScope.Record); + var recordValidationError3 = BuildValidationError(ValidationErrorScope.Record); + + var expectedErrors = new List + { + fileValidationError1, fileValidationError2, fileValidationError3, + recordValidationError1, recordValidationError2, recordValidationError3, + recordValidationError1, recordValidationError2, recordValidationError3, + }; + + var fileValidator1 = new Mock(); + fileValidator1 + .Setup(v => v.Validate(file)) + .Returns([fileValidationError1, fileValidationError2]); + + var fileValidator2 = new Mock(); + fileValidator2 + .Setup(v => v.Validate(file)) + .Returns([fileValidationError3]); + + var recordValidator1 = new Mock(); + recordValidator1 + .Setup(v => v.Validate(It.IsAny())) + .Returns([recordValidationError1]); + + var recordValidator2 = new Mock(); + recordValidator2 + .Setup(v => v.Validate(It.IsAny())) + .Returns([recordValidationError2, recordValidationError3]); + + var runner = new ValidationRunner( + [fileValidator1.Object, fileValidator2.Object], + [recordValidator1.Object, recordValidator2.Object]); + + // Act + var results = runner.Validate(file); + + // Assert + Assert.Equal(expectedErrors, results, new ValidationErrorComparer()); + } + + [Fact] + public void Validate_OnlyRecordValidatorsReturnErrors_ReturnsAllErrors() + { + // Arrange + var file = new ParsedFile + { + DataRecords = [new FileDataRecord(), new FileDataRecord()] + }; + + var recordValidationError1 = BuildValidationError(ValidationErrorScope.Record); + var recordValidationError2 = BuildValidationError(ValidationErrorScope.Record); + var recordValidationError3 = BuildValidationError(ValidationErrorScope.Record); + + var expectedErrors = new List + { + recordValidationError1, recordValidationError2, recordValidationError3, + recordValidationError1, recordValidationError2, recordValidationError3, + }; + + var fileValidator1 = new Mock(); + fileValidator1 + .Setup(v => v.Validate(file)) + .Returns([]); + + var fileValidator2 = new Mock(); + fileValidator2 + .Setup(v => v.Validate(file)) + .Returns([]); + + var recordValidator1 = new Mock(); + recordValidator1 + .Setup(v => v.Validate(It.IsAny())) + .Returns([recordValidationError1]); + + var recordValidator2 = new Mock(); + recordValidator2 + .Setup(v => v.Validate(It.IsAny())) + .Returns([recordValidationError2, recordValidationError3]); + + var runner = new ValidationRunner( + [fileValidator1.Object, fileValidator2.Object], + [recordValidator1.Object, recordValidator2.Object]); + + // Act + var results = runner.Validate(file); + + // Assert + Assert.Equal(expectedErrors, results, new ValidationErrorComparer()); + } + + [Fact] + public void Validate_OnlyFileValidatorsReturnErrors_ReturnsAllErrors() + { + // Arrange + var file = new ParsedFile + { + DataRecords = [new FileDataRecord(), new FileDataRecord()] + }; + + var fileValidationError1 = BuildValidationError(ValidationErrorScope.File); + var fileValidationError2 = BuildValidationError(ValidationErrorScope.File); + var fileValidationError3 = BuildValidationError(ValidationErrorScope.File); + + var expectedErrors = new List + { + fileValidationError1, fileValidationError2, fileValidationError3 + }; + + var fileValidator1 = new Mock(); + fileValidator1 + .Setup(v => v.Validate(file)) + .Returns([fileValidationError1, fileValidationError2]); + + var fileValidator2 = new Mock(); + fileValidator2 + .Setup(v => v.Validate(file)) + .Returns([fileValidationError3]); + + var recordValidator1 = new Mock(); + recordValidator1 + .Setup(v => v.Validate(It.IsAny())) + .Returns([]); + + var recordValidator2 = new Mock(); + recordValidator2 + .Setup(v => v.Validate(It.IsAny())) + .Returns([]); + + var runner = new ValidationRunner( + [fileValidator1.Object, fileValidator2.Object], + [recordValidator1.Object, recordValidator2.Object]); + + // Act + var results = runner.Validate(file); + + // Assert + Assert.Equal(expectedErrors, results, new ValidationErrorComparer()); + } + + [Fact] + public void Validate_FileAndRecordValidatorsReturnNoErrors_ReturnsNoErrors() + { + // Arrange + var file = new ParsedFile + { + DataRecords = [new FileDataRecord(), new FileDataRecord()] + }; + + var fileValidator1 = new Mock(); + fileValidator1 + .Setup(v => v.Validate(file)) + .Returns([]); + + var fileValidator2 = new Mock(); + fileValidator2 + .Setup(v => v.Validate(file)) + .Returns([]); + + var recordValidator1 = new Mock(); + recordValidator1 + .Setup(v => v.Validate(It.IsAny())) + .Returns([]); + + var recordValidator2 = new Mock(); + recordValidator2 + .Setup(v => v.Validate(It.IsAny())) + .Returns([]); + + var runner = new ValidationRunner( + [fileValidator1.Object, fileValidator2.Object], + [recordValidator1.Object, recordValidator2.Object]); + + // Act + var results = runner.Validate(file); + + // Assert + Assert.Empty(results); + } + + private static ValidationError BuildValidationError(ValidationErrorScope scope) + { + var validationError = new ValidationError + { + Code = Guid.NewGuid().ToString(), + Error = Guid.NewGuid().ToString(), + Field = Guid.NewGuid().ToString(), + Scope = scope + }; + + if (scope == ValidationErrorScope.Record) + { + validationError.RowNumber = 1; + } + + return validationError; + } +} diff --git a/tests/ServiceLayer.Mesh.Tests/Functions/FileTransformFunctionTests.cs b/tests/ServiceLayer.Mesh.Tests/Functions/FileTransformFunctionTests.cs index 75966e5..9a66f51 100644 --- a/tests/ServiceLayer.Mesh.Tests/Functions/FileTransformFunctionTests.cs +++ b/tests/ServiceLayer.Mesh.Tests/Functions/FileTransformFunctionTests.cs @@ -205,23 +205,4 @@ private static List DeserializeValidationErrorsFromMeshFile(Mes ValidationErrorJsonOptions ) ?? []; } - - private class ValidationErrorComparer : IEqualityComparer - { - public bool Equals(ValidationError? x, ValidationError? y) - { - if (ReferenceEquals(x, y)) return true; - if (x is null || y is null) return false; - - return x.Field == y.Field && - x.Error == y.Error && - x.Code == y.Code && - x.RowNumber == y.RowNumber; - } - - public int GetHashCode(ValidationError obj) - { - return HashCode.Combine(obj.Field, obj.Error, obj.Code, obj.RowNumber); - } - } } diff --git a/tests/ServiceLayer.Mesh.Tests/ValidationErrorComparer.cs b/tests/ServiceLayer.Mesh.Tests/ValidationErrorComparer.cs new file mode 100644 index 0000000..15bbc73 --- /dev/null +++ b/tests/ServiceLayer.Mesh.Tests/ValidationErrorComparer.cs @@ -0,0 +1,20 @@ +namespace ServiceLayer.Mesh.Tests; + +public class ValidationErrorComparer : IEqualityComparer +{ + public bool Equals(ValidationError? x, ValidationError? y) + { + if (ReferenceEquals(x, y)) return true; + if (x is null || y is null) return false; + + return x.Field == y.Field && + x.Error == y.Error && + x.Code == y.Code && + x.RowNumber == y.RowNumber; + } + + public int GetHashCode(ValidationError obj) + { + return HashCode.Combine(obj.Field, obj.Error, obj.Code, obj.RowNumber); + } +}