From d342d7c9aef22a14135570d6854d25eb571597bc Mon Sep 17 00:00:00 2001 From: James Croft Date: Tue, 26 Apr 2022 20:25:33 +0100 Subject: [PATCH 1/8] Added FluentValidation project with FluentValidatorCollection --- MADE.NET.sln | 122 +++++++++++- .../FluentValidatorCollection{T}.cs | 92 ++++++++++ ...DE.Data.Validation.FluentValidation.csproj | 22 +++ .../IValidatorCollection.cs | 35 ++++ .../MADE.Data.Validation.csproj | 2 +- .../ValidatorCollection.cs | 2 +- ...a.Validation.FluentValidation.Tests.csproj | 27 +++ .../Tests/FluentValidatorCollectionTests.cs | 173 ++++++++++++++++++ 8 files changed, 471 insertions(+), 4 deletions(-) create mode 100644 src/MADE.Data.Validation.FluentValidation/FluentValidatorCollection{T}.cs create mode 100644 src/MADE.Data.Validation.FluentValidation/MADE.Data.Validation.FluentValidation.csproj create mode 100644 src/MADE.Data.Validation/IValidatorCollection.cs create mode 100644 tests/MADE.Data.Validation.FluentValidation.Tests/MADE.Data.Validation.FluentValidation.Tests.csproj create mode 100644 tests/MADE.Data.Validation.FluentValidation.Tests/Tests/FluentValidatorCollectionTests.cs diff --git a/MADE.NET.sln b/MADE.NET.sln index 6aa92622..9b7662ac 100644 --- a/MADE.NET.sln +++ b/MADE.NET.sln @@ -1,7 +1,7 @@  Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio Version 16 -VisualStudioVersion = 16.0.31624.102 +# Visual Studio Version 17 +VisualStudioVersion = 17.1.32228.430 MinimumVisualStudioVersion = 10.0.40219.1 Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{01380FB8-F8A7-4416-AABA-5407574B7723}" EndProject @@ -45,6 +45,10 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MADE.Data.EFCore", "src\MAD EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MADE.Foundation", "src\MADE.Foundation\MADE.Foundation.csproj", "{C8DF10B0-D157-47CF-BD10-9EE1D06BEB9A}" EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MADE.Data.Validation.FluentValidation", "src\MADE.Data.Validation.FluentValidation\MADE.Data.Validation.FluentValidation.csproj", "{BBAB544A-BFB2-4755-8F09-8E150D3638F3}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MADE.Data.Validation.FluentValidation.Tests", "tests\MADE.Data.Validation.FluentValidation.Tests\MADE.Data.Validation.FluentValidation.Tests.csproj", "{D8C1B3CC-B5BA-4946-944E-D898AB4DFF6E}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Ad-Hoc|Any CPU = Ad-Hoc|Any CPU @@ -1141,6 +1145,118 @@ Global {C8DF10B0-D157-47CF-BD10-9EE1D06BEB9A}.Release|x64.Build.0 = Release|Any CPU {C8DF10B0-D157-47CF-BD10-9EE1D06BEB9A}.Release|x86.ActiveCfg = Release|Any CPU {C8DF10B0-D157-47CF-BD10-9EE1D06BEB9A}.Release|x86.Build.0 = Release|Any CPU + {BBAB544A-BFB2-4755-8F09-8E150D3638F3}.Ad-Hoc|Any CPU.ActiveCfg = Debug|Any CPU + {BBAB544A-BFB2-4755-8F09-8E150D3638F3}.Ad-Hoc|Any CPU.Build.0 = Debug|Any CPU + {BBAB544A-BFB2-4755-8F09-8E150D3638F3}.Ad-Hoc|ARM.ActiveCfg = Debug|Any CPU + {BBAB544A-BFB2-4755-8F09-8E150D3638F3}.Ad-Hoc|ARM.Build.0 = Debug|Any CPU + {BBAB544A-BFB2-4755-8F09-8E150D3638F3}.Ad-Hoc|ARM64.ActiveCfg = Debug|Any CPU + {BBAB544A-BFB2-4755-8F09-8E150D3638F3}.Ad-Hoc|ARM64.Build.0 = Debug|Any CPU + {BBAB544A-BFB2-4755-8F09-8E150D3638F3}.Ad-Hoc|iPhone.ActiveCfg = Debug|Any CPU + {BBAB544A-BFB2-4755-8F09-8E150D3638F3}.Ad-Hoc|iPhone.Build.0 = Debug|Any CPU + {BBAB544A-BFB2-4755-8F09-8E150D3638F3}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Debug|Any CPU + {BBAB544A-BFB2-4755-8F09-8E150D3638F3}.Ad-Hoc|iPhoneSimulator.Build.0 = Debug|Any CPU + {BBAB544A-BFB2-4755-8F09-8E150D3638F3}.Ad-Hoc|x64.ActiveCfg = Debug|Any CPU + {BBAB544A-BFB2-4755-8F09-8E150D3638F3}.Ad-Hoc|x64.Build.0 = Debug|Any CPU + {BBAB544A-BFB2-4755-8F09-8E150D3638F3}.Ad-Hoc|x86.ActiveCfg = Debug|Any CPU + {BBAB544A-BFB2-4755-8F09-8E150D3638F3}.Ad-Hoc|x86.Build.0 = Debug|Any CPU + {BBAB544A-BFB2-4755-8F09-8E150D3638F3}.AppStore|Any CPU.ActiveCfg = Debug|Any CPU + {BBAB544A-BFB2-4755-8F09-8E150D3638F3}.AppStore|Any CPU.Build.0 = Debug|Any CPU + {BBAB544A-BFB2-4755-8F09-8E150D3638F3}.AppStore|ARM.ActiveCfg = Debug|Any CPU + {BBAB544A-BFB2-4755-8F09-8E150D3638F3}.AppStore|ARM.Build.0 = Debug|Any CPU + {BBAB544A-BFB2-4755-8F09-8E150D3638F3}.AppStore|ARM64.ActiveCfg = Debug|Any CPU + {BBAB544A-BFB2-4755-8F09-8E150D3638F3}.AppStore|ARM64.Build.0 = Debug|Any CPU + {BBAB544A-BFB2-4755-8F09-8E150D3638F3}.AppStore|iPhone.ActiveCfg = Debug|Any CPU + {BBAB544A-BFB2-4755-8F09-8E150D3638F3}.AppStore|iPhone.Build.0 = Debug|Any CPU + {BBAB544A-BFB2-4755-8F09-8E150D3638F3}.AppStore|iPhoneSimulator.ActiveCfg = Debug|Any CPU + {BBAB544A-BFB2-4755-8F09-8E150D3638F3}.AppStore|iPhoneSimulator.Build.0 = Debug|Any CPU + {BBAB544A-BFB2-4755-8F09-8E150D3638F3}.AppStore|x64.ActiveCfg = Debug|Any CPU + {BBAB544A-BFB2-4755-8F09-8E150D3638F3}.AppStore|x64.Build.0 = Debug|Any CPU + {BBAB544A-BFB2-4755-8F09-8E150D3638F3}.AppStore|x86.ActiveCfg = Debug|Any CPU + {BBAB544A-BFB2-4755-8F09-8E150D3638F3}.AppStore|x86.Build.0 = Debug|Any CPU + {BBAB544A-BFB2-4755-8F09-8E150D3638F3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {BBAB544A-BFB2-4755-8F09-8E150D3638F3}.Debug|Any CPU.Build.0 = Debug|Any CPU + {BBAB544A-BFB2-4755-8F09-8E150D3638F3}.Debug|ARM.ActiveCfg = Debug|Any CPU + {BBAB544A-BFB2-4755-8F09-8E150D3638F3}.Debug|ARM.Build.0 = Debug|Any CPU + {BBAB544A-BFB2-4755-8F09-8E150D3638F3}.Debug|ARM64.ActiveCfg = Debug|Any CPU + {BBAB544A-BFB2-4755-8F09-8E150D3638F3}.Debug|ARM64.Build.0 = Debug|Any CPU + {BBAB544A-BFB2-4755-8F09-8E150D3638F3}.Debug|iPhone.ActiveCfg = Debug|Any CPU + {BBAB544A-BFB2-4755-8F09-8E150D3638F3}.Debug|iPhone.Build.0 = Debug|Any CPU + {BBAB544A-BFB2-4755-8F09-8E150D3638F3}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU + {BBAB544A-BFB2-4755-8F09-8E150D3638F3}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU + {BBAB544A-BFB2-4755-8F09-8E150D3638F3}.Debug|x64.ActiveCfg = Debug|Any CPU + {BBAB544A-BFB2-4755-8F09-8E150D3638F3}.Debug|x64.Build.0 = Debug|Any CPU + {BBAB544A-BFB2-4755-8F09-8E150D3638F3}.Debug|x86.ActiveCfg = Debug|Any CPU + {BBAB544A-BFB2-4755-8F09-8E150D3638F3}.Debug|x86.Build.0 = Debug|Any CPU + {BBAB544A-BFB2-4755-8F09-8E150D3638F3}.Release|Any CPU.ActiveCfg = Release|Any CPU + {BBAB544A-BFB2-4755-8F09-8E150D3638F3}.Release|Any CPU.Build.0 = Release|Any CPU + {BBAB544A-BFB2-4755-8F09-8E150D3638F3}.Release|ARM.ActiveCfg = Release|Any CPU + {BBAB544A-BFB2-4755-8F09-8E150D3638F3}.Release|ARM.Build.0 = Release|Any CPU + {BBAB544A-BFB2-4755-8F09-8E150D3638F3}.Release|ARM64.ActiveCfg = Release|Any CPU + {BBAB544A-BFB2-4755-8F09-8E150D3638F3}.Release|ARM64.Build.0 = Release|Any CPU + {BBAB544A-BFB2-4755-8F09-8E150D3638F3}.Release|iPhone.ActiveCfg = Release|Any CPU + {BBAB544A-BFB2-4755-8F09-8E150D3638F3}.Release|iPhone.Build.0 = Release|Any CPU + {BBAB544A-BFB2-4755-8F09-8E150D3638F3}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU + {BBAB544A-BFB2-4755-8F09-8E150D3638F3}.Release|iPhoneSimulator.Build.0 = Release|Any CPU + {BBAB544A-BFB2-4755-8F09-8E150D3638F3}.Release|x64.ActiveCfg = Release|Any CPU + {BBAB544A-BFB2-4755-8F09-8E150D3638F3}.Release|x64.Build.0 = Release|Any CPU + {BBAB544A-BFB2-4755-8F09-8E150D3638F3}.Release|x86.ActiveCfg = Release|Any CPU + {BBAB544A-BFB2-4755-8F09-8E150D3638F3}.Release|x86.Build.0 = Release|Any CPU + {D8C1B3CC-B5BA-4946-944E-D898AB4DFF6E}.Ad-Hoc|Any CPU.ActiveCfg = Debug|Any CPU + {D8C1B3CC-B5BA-4946-944E-D898AB4DFF6E}.Ad-Hoc|Any CPU.Build.0 = Debug|Any CPU + {D8C1B3CC-B5BA-4946-944E-D898AB4DFF6E}.Ad-Hoc|ARM.ActiveCfg = Debug|Any CPU + {D8C1B3CC-B5BA-4946-944E-D898AB4DFF6E}.Ad-Hoc|ARM.Build.0 = Debug|Any CPU + {D8C1B3CC-B5BA-4946-944E-D898AB4DFF6E}.Ad-Hoc|ARM64.ActiveCfg = Debug|Any CPU + {D8C1B3CC-B5BA-4946-944E-D898AB4DFF6E}.Ad-Hoc|ARM64.Build.0 = Debug|Any CPU + {D8C1B3CC-B5BA-4946-944E-D898AB4DFF6E}.Ad-Hoc|iPhone.ActiveCfg = Debug|Any CPU + {D8C1B3CC-B5BA-4946-944E-D898AB4DFF6E}.Ad-Hoc|iPhone.Build.0 = Debug|Any CPU + {D8C1B3CC-B5BA-4946-944E-D898AB4DFF6E}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Debug|Any CPU + {D8C1B3CC-B5BA-4946-944E-D898AB4DFF6E}.Ad-Hoc|iPhoneSimulator.Build.0 = Debug|Any CPU + {D8C1B3CC-B5BA-4946-944E-D898AB4DFF6E}.Ad-Hoc|x64.ActiveCfg = Debug|Any CPU + {D8C1B3CC-B5BA-4946-944E-D898AB4DFF6E}.Ad-Hoc|x64.Build.0 = Debug|Any CPU + {D8C1B3CC-B5BA-4946-944E-D898AB4DFF6E}.Ad-Hoc|x86.ActiveCfg = Debug|Any CPU + {D8C1B3CC-B5BA-4946-944E-D898AB4DFF6E}.Ad-Hoc|x86.Build.0 = Debug|Any CPU + {D8C1B3CC-B5BA-4946-944E-D898AB4DFF6E}.AppStore|Any CPU.ActiveCfg = Debug|Any CPU + {D8C1B3CC-B5BA-4946-944E-D898AB4DFF6E}.AppStore|Any CPU.Build.0 = Debug|Any CPU + {D8C1B3CC-B5BA-4946-944E-D898AB4DFF6E}.AppStore|ARM.ActiveCfg = Debug|Any CPU + {D8C1B3CC-B5BA-4946-944E-D898AB4DFF6E}.AppStore|ARM.Build.0 = Debug|Any CPU + {D8C1B3CC-B5BA-4946-944E-D898AB4DFF6E}.AppStore|ARM64.ActiveCfg = Debug|Any CPU + {D8C1B3CC-B5BA-4946-944E-D898AB4DFF6E}.AppStore|ARM64.Build.0 = Debug|Any CPU + {D8C1B3CC-B5BA-4946-944E-D898AB4DFF6E}.AppStore|iPhone.ActiveCfg = Debug|Any CPU + {D8C1B3CC-B5BA-4946-944E-D898AB4DFF6E}.AppStore|iPhone.Build.0 = Debug|Any CPU + {D8C1B3CC-B5BA-4946-944E-D898AB4DFF6E}.AppStore|iPhoneSimulator.ActiveCfg = Debug|Any CPU + {D8C1B3CC-B5BA-4946-944E-D898AB4DFF6E}.AppStore|iPhoneSimulator.Build.0 = Debug|Any CPU + {D8C1B3CC-B5BA-4946-944E-D898AB4DFF6E}.AppStore|x64.ActiveCfg = Debug|Any CPU + {D8C1B3CC-B5BA-4946-944E-D898AB4DFF6E}.AppStore|x64.Build.0 = Debug|Any CPU + {D8C1B3CC-B5BA-4946-944E-D898AB4DFF6E}.AppStore|x86.ActiveCfg = Debug|Any CPU + {D8C1B3CC-B5BA-4946-944E-D898AB4DFF6E}.AppStore|x86.Build.0 = Debug|Any CPU + {D8C1B3CC-B5BA-4946-944E-D898AB4DFF6E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {D8C1B3CC-B5BA-4946-944E-D898AB4DFF6E}.Debug|Any CPU.Build.0 = Debug|Any CPU + {D8C1B3CC-B5BA-4946-944E-D898AB4DFF6E}.Debug|ARM.ActiveCfg = Debug|Any CPU + {D8C1B3CC-B5BA-4946-944E-D898AB4DFF6E}.Debug|ARM.Build.0 = Debug|Any CPU + {D8C1B3CC-B5BA-4946-944E-D898AB4DFF6E}.Debug|ARM64.ActiveCfg = Debug|Any CPU + {D8C1B3CC-B5BA-4946-944E-D898AB4DFF6E}.Debug|ARM64.Build.0 = Debug|Any CPU + {D8C1B3CC-B5BA-4946-944E-D898AB4DFF6E}.Debug|iPhone.ActiveCfg = Debug|Any CPU + {D8C1B3CC-B5BA-4946-944E-D898AB4DFF6E}.Debug|iPhone.Build.0 = Debug|Any CPU + {D8C1B3CC-B5BA-4946-944E-D898AB4DFF6E}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU + {D8C1B3CC-B5BA-4946-944E-D898AB4DFF6E}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU + {D8C1B3CC-B5BA-4946-944E-D898AB4DFF6E}.Debug|x64.ActiveCfg = Debug|Any CPU + {D8C1B3CC-B5BA-4946-944E-D898AB4DFF6E}.Debug|x64.Build.0 = Debug|Any CPU + {D8C1B3CC-B5BA-4946-944E-D898AB4DFF6E}.Debug|x86.ActiveCfg = Debug|Any CPU + {D8C1B3CC-B5BA-4946-944E-D898AB4DFF6E}.Debug|x86.Build.0 = Debug|Any CPU + {D8C1B3CC-B5BA-4946-944E-D898AB4DFF6E}.Release|Any CPU.ActiveCfg = Release|Any CPU + {D8C1B3CC-B5BA-4946-944E-D898AB4DFF6E}.Release|Any CPU.Build.0 = Release|Any CPU + {D8C1B3CC-B5BA-4946-944E-D898AB4DFF6E}.Release|ARM.ActiveCfg = Release|Any CPU + {D8C1B3CC-B5BA-4946-944E-D898AB4DFF6E}.Release|ARM.Build.0 = Release|Any CPU + {D8C1B3CC-B5BA-4946-944E-D898AB4DFF6E}.Release|ARM64.ActiveCfg = Release|Any CPU + {D8C1B3CC-B5BA-4946-944E-D898AB4DFF6E}.Release|ARM64.Build.0 = Release|Any CPU + {D8C1B3CC-B5BA-4946-944E-D898AB4DFF6E}.Release|iPhone.ActiveCfg = Release|Any CPU + {D8C1B3CC-B5BA-4946-944E-D898AB4DFF6E}.Release|iPhone.Build.0 = Release|Any CPU + {D8C1B3CC-B5BA-4946-944E-D898AB4DFF6E}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU + {D8C1B3CC-B5BA-4946-944E-D898AB4DFF6E}.Release|iPhoneSimulator.Build.0 = Release|Any CPU + {D8C1B3CC-B5BA-4946-944E-D898AB4DFF6E}.Release|x64.ActiveCfg = Release|Any CPU + {D8C1B3CC-B5BA-4946-944E-D898AB4DFF6E}.Release|x64.Build.0 = Release|Any CPU + {D8C1B3CC-B5BA-4946-944E-D898AB4DFF6E}.Release|x86.ActiveCfg = Release|Any CPU + {D8C1B3CC-B5BA-4946-944E-D898AB4DFF6E}.Release|x86.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -1165,6 +1281,8 @@ Global {1CDB43BD-71F9-46C6-816C-4EFC9FA2ED1C} = {69149D0F-BB09-411B-88F0-A1E845058D70} {3A5D7EA4-5AD9-4D34-87E6-B34416CA928E} = {01380FB8-F8A7-4416-AABA-5407574B7723} {C8DF10B0-D157-47CF-BD10-9EE1D06BEB9A} = {01380FB8-F8A7-4416-AABA-5407574B7723} + {BBAB544A-BFB2-4755-8F09-8E150D3638F3} = {01380FB8-F8A7-4416-AABA-5407574B7723} + {D8C1B3CC-B5BA-4946-944E-D898AB4DFF6E} = {69149D0F-BB09-411B-88F0-A1E845058D70} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {3921AD86-E6C0-4436-8880-2D9EDFAD6151} diff --git a/src/MADE.Data.Validation.FluentValidation/FluentValidatorCollection{T}.cs b/src/MADE.Data.Validation.FluentValidation/FluentValidatorCollection{T}.cs new file mode 100644 index 00000000..97001eff --- /dev/null +++ b/src/MADE.Data.Validation.FluentValidation/FluentValidatorCollection{T}.cs @@ -0,0 +1,92 @@ +// MADE Apps licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +namespace MADE.Data.Validation +{ + using System; + using System.Collections.Generic; + using FluentValidation; + + /// + /// Defines a list of objects that can be accessed by index. + /// + /// The type of item being validated. + public class FluentValidatorCollection : List>, IValidatorCollection + where T : class + { + private readonly List feedbackMessages = new(); + + /// Initializes a new instance of the class that is empty and has the default initial capacity. + public FluentValidatorCollection() + { + } + + /// Initializes a new instance of the class that contains elements copied from the specified collection and has sufficient capacity to accommodate the number of elements copied. + /// The collection whose elements are copied to the new list. + /// collection is null. + public FluentValidatorCollection(IEnumerable> collection) + : base(collection) + { + } + + /// + /// Initializes a new instance of the class that is empty and has the specified initial capacity. + /// The number of elements that the new list can initially store. + /// capacity is less than 0. + public FluentValidatorCollection(int capacity) + : base(capacity) + { + } + + /// + /// Occurs when the input value is validated against the collection of validators. + /// + public event InputValidatedEventHandler Validated; + + /// + /// Gets or sets a value indicating whether the data provided is in an invalid state. + /// + public bool IsInvalid { get; set; } + + /// + /// Gets or sets a value indicating whether the data is dirty. + /// + public bool IsDirty { get; set; } + + /// + /// Gets the validator feedback messages for ones which are invalid. + /// + public IEnumerable FeedbackMessages => this.feedbackMessages; + + /// + /// Executes data validation on the provided against the validators provided. + /// + /// The value to be validated. + /// Potentially thrown by the delegate callback. + public void Validate(object value) + { + this.feedbackMessages.Clear(); + + this.IsDirty = true; + + this.ForEach(validator => + { + var result = validator.Validate(value as T); + if (!result.IsValid) + { + IsInvalid = true; + } + + if (result.Errors != null) + { + foreach (var message in result.Errors) + { + this.feedbackMessages.Add(message.ErrorMessage); + } + } + }); + + this.Validated?.Invoke(this, new InputValidatedEventArgs(this.IsInvalid, this.IsDirty)); + } + } +} \ No newline at end of file diff --git a/src/MADE.Data.Validation.FluentValidation/MADE.Data.Validation.FluentValidation.csproj b/src/MADE.Data.Validation.FluentValidation/MADE.Data.Validation.FluentValidation.csproj new file mode 100644 index 00000000..b3fb294e --- /dev/null +++ b/src/MADE.Data.Validation.FluentValidation/MADE.Data.Validation.FluentValidation.csproj @@ -0,0 +1,22 @@ + + + + netstandard2.0 + true + MADE.NET Data Validation (FluentValidation) + + This package includes extended support for FluentValidation validators in MADE.NET. + + MADE Data Validation FluentValidation + MADE.Data.Validation + + + + + + + + + + + \ No newline at end of file diff --git a/src/MADE.Data.Validation/IValidatorCollection.cs b/src/MADE.Data.Validation/IValidatorCollection.cs new file mode 100644 index 00000000..77ce3c75 --- /dev/null +++ b/src/MADE.Data.Validation/IValidatorCollection.cs @@ -0,0 +1,35 @@ +// MADE Apps licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +namespace MADE.Data.Validation +{ + using System.Collections; + using System.Collections.Generic; + + /// + /// Defines an interface for a collection of validators. + /// + public interface IValidatorCollection : IList + { + /// + /// Gets or sets a value indicating whether the data provided is in an invalid state. + /// + bool IsInvalid { get; set; } + + /// + /// Gets or sets a value indicating whether the data is dirty. + /// + bool IsDirty { get; set; } + + /// + /// Gets the validator feedback messages for ones which are invalid. + /// + IEnumerable FeedbackMessages { get; } + + /// + /// Executes data validation on the provided against the validators provided. + /// + /// The value to be validated. + void Validate(object value); + } +} \ No newline at end of file diff --git a/src/MADE.Data.Validation/MADE.Data.Validation.csproj b/src/MADE.Data.Validation/MADE.Data.Validation.csproj index 6c7441e6..e9a691b0 100644 --- a/src/MADE.Data.Validation/MADE.Data.Validation.csproj +++ b/src/MADE.Data.Validation/MADE.Data.Validation.csproj @@ -1,7 +1,7 @@ - uap10.0.17763;netstandard2.0 + netstandard2.0 true MADE.NET Data Validation diff --git a/src/MADE.Data.Validation/ValidatorCollection.cs b/src/MADE.Data.Validation/ValidatorCollection.cs index fca8d774..bbe57e67 100644 --- a/src/MADE.Data.Validation/ValidatorCollection.cs +++ b/src/MADE.Data.Validation/ValidatorCollection.cs @@ -11,7 +11,7 @@ namespace MADE.Data.Validation /// /// Defines a list of objects that can be accessed by index. /// - public class ValidatorCollection : List + public class ValidatorCollection : List, IValidatorCollection { /// Initializes a new instance of the class that is empty and has the default initial capacity. public ValidatorCollection() diff --git a/tests/MADE.Data.Validation.FluentValidation.Tests/MADE.Data.Validation.FluentValidation.Tests.csproj b/tests/MADE.Data.Validation.FluentValidation.Tests/MADE.Data.Validation.FluentValidation.Tests.csproj new file mode 100644 index 00000000..a0a9c256 --- /dev/null +++ b/tests/MADE.Data.Validation.FluentValidation.Tests/MADE.Data.Validation.FluentValidation.Tests.csproj @@ -0,0 +1,27 @@ + + + + net6.0;net5.0 + false + + + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/tests/MADE.Data.Validation.FluentValidation.Tests/Tests/FluentValidatorCollectionTests.cs b/tests/MADE.Data.Validation.FluentValidation.Tests/Tests/FluentValidatorCollectionTests.cs new file mode 100644 index 00000000..88e8ddca --- /dev/null +++ b/tests/MADE.Data.Validation.FluentValidation.Tests/Tests/FluentValidatorCollectionTests.cs @@ -0,0 +1,173 @@ +namespace MADE.Data.Validation.FluentValidation.Tests.Tests +{ + using System; + using System.Collections.Generic; + using System.Diagnostics.CodeAnalysis; + using System.Linq; + using global::FluentValidation; + using MADE.Testing; + using NUnit.Framework; + using Shouldly; + + [ExcludeFromCodeCoverage] + [TestFixture] + public class FluentValidatorCollectionTests + { + public class WhenInitializing + { + [Test] + public void ShouldBeEmptyIfDefaultConstructor() + { + // Act + var collection = new FluentValidatorCollection(); + + // Assert + collection.Count.ShouldBe(0); + } + + [Test] + public void ShouldContainItemsIfInitializedAsEnumerable() + { + // Arrange + IEnumerable> validators = new List> + { + new PersonValidator() + }; + + // Act + var collection = new FluentValidatorCollection(validators); + + // Assert + collection.Count.ShouldBe(validators.Count()); + collection.ToList().ShouldBeEquivalentTo(validators); + } + } + + public class WhenAddingItems + { + [Test] + public void ShouldAddRangeOfItems() + { + // Arrange + IEnumerable> validators = new List> + { + new PersonValidator() + }; + + var collection = new FluentValidatorCollection(); + + // Act + collection.AddRange(validators); + + // Assert + foreach (AbstractValidator item in validators) + { + collection.ShouldContain(item); + } + } + + [Test] + public void ShouldAddSingleItem() + { + // Arrange + var objectToAdd = new PersonValidator(); + + // Act + var collection = new FluentValidatorCollection { objectToAdd }; + + // Assert + collection.ShouldContain(objectToAdd); + } + } + + public class WhenValidating + { + [Test] + public void ShouldBeDirtyOnceValidated() + { + // Arrange + var value = new Person(); + + var collection = new FluentValidatorCollection { new PersonValidator() }; + + // Act + collection.Validate(value); + + // Assert + collection.IsDirty.ShouldBe(true); + } + + [Test] + public void ShouldBeValidIfValidValue() + { + // Arrange + var value = new Person { Name = "Joe Bloggs", DateOfBirth = new DateTime(1992, 01, 01) }; + + var collection = new FluentValidatorCollection { new PersonValidator() }; + + // Act + collection.Validate(value); + + // Assert + collection.IsInvalid.ShouldBe(false); + } + + [Test] + public void ShouldBeInvalidIfInvalidValue() + { + // Arrange + var value = new Person(); + + var collection = new FluentValidatorCollection { new PersonValidator() }; + + // Act + collection.Validate(value); + + // Assert + collection.IsInvalid.ShouldBe(true); + } + + [Test] + public void ShouldHaveFeedbackMessagesIfInvalidValue() + { + // Arrange + var value = new Person + { + Name = "Joe Bloggs", + DateOfBirth = DateTime.UtcNow.AddDays(1) // Invalid birth date + }; + + var collection = new FluentValidatorCollection { new PersonValidator() }; + + // Act + collection.Validate(value); + + // Assert + collection.FeedbackMessages.ShouldNotBeEmpty(); + collection.FeedbackMessages.Count().ShouldBe(1); + collection.FeedbackMessages.FirstOrDefault().ShouldBe(PersonValidator.DateOfBirthValidationMessage); + } + } + } + + public class Person + { + public string Name { get; set; } + + public DateTime? DateOfBirth { get; set; } + } + + public class PersonValidator : AbstractValidator + { + public const string DateOfBirthValidationMessage = "Please specify a valid date of birth"; + + public PersonValidator() + { + this.RuleFor(x => x.Name).NotEmpty(); + this.RuleFor(x => x.DateOfBirth) + .NotNull() + .LessThanOrEqualTo(DateTime.UtcNow) + .WithMessage(DateOfBirthValidationMessage); + } + } +} \ No newline at end of file From a94192f0ccbc3cbd8bcb5d433094aff325b04564 Mon Sep 17 00:00:00 2001 From: James Croft Date: Tue, 26 Apr 2022 20:25:51 +0100 Subject: [PATCH 2/8] Updated required package target frameworks --- src/MADE.Collections/MADE.Collections.csproj | 2 +- src/MADE.Foundation/MADE.Foundation.csproj | 2 +- tests/MADE.Collections.Tests/MADE.Collections.Tests.csproj | 5 ++--- .../MADE.Data.Converters.Tests.csproj | 5 ++--- .../MADE.Data.Validation.Tests.csproj | 5 ++--- tests/MADE.Diagnostics.Tests/MADE.Diagnostics.Tests.csproj | 5 ++--- tests/MADE.Networking.Tests/MADE.Networking.Tests.csproj | 5 ++--- tests/MADE.Web.Tests/MADE.Web.Tests.csproj | 5 ++--- 8 files changed, 14 insertions(+), 20 deletions(-) diff --git a/src/MADE.Collections/MADE.Collections.csproj b/src/MADE.Collections/MADE.Collections.csproj index bd83a88b..1c1dc1a7 100644 --- a/src/MADE.Collections/MADE.Collections.csproj +++ b/src/MADE.Collections/MADE.Collections.csproj @@ -1,7 +1,7 @@ - uap10.0.17763;netstandard2.0 + netstandard2.0 true MADE.NET Collections diff --git a/src/MADE.Foundation/MADE.Foundation.csproj b/src/MADE.Foundation/MADE.Foundation.csproj index 61285596..ca94de7b 100644 --- a/src/MADE.Foundation/MADE.Foundation.csproj +++ b/src/MADE.Foundation/MADE.Foundation.csproj @@ -1,7 +1,7 @@ - uap10.0.17763;MonoAndroid10.0;xamarinios10;netstandard2.0;xamarinmac20 + netstandard2.0 true MADE.NET Foundation diff --git a/tests/MADE.Collections.Tests/MADE.Collections.Tests.csproj b/tests/MADE.Collections.Tests/MADE.Collections.Tests.csproj index 2d03ee7d..e4c5e5cc 100644 --- a/tests/MADE.Collections.Tests/MADE.Collections.Tests.csproj +++ b/tests/MADE.Collections.Tests/MADE.Collections.Tests.csproj @@ -1,8 +1,7 @@ - + - net5.0 - + net6.0;net5.0 false diff --git a/tests/MADE.Data.Converters.Tests/MADE.Data.Converters.Tests.csproj b/tests/MADE.Data.Converters.Tests/MADE.Data.Converters.Tests.csproj index aac84e4c..2c3bc5b5 100644 --- a/tests/MADE.Data.Converters.Tests/MADE.Data.Converters.Tests.csproj +++ b/tests/MADE.Data.Converters.Tests/MADE.Data.Converters.Tests.csproj @@ -1,8 +1,7 @@ - + - net5.0 - + net6.0;net5.0 false diff --git a/tests/MADE.Data.Validation.Tests/MADE.Data.Validation.Tests.csproj b/tests/MADE.Data.Validation.Tests/MADE.Data.Validation.Tests.csproj index d9ba4c0d..372b5bf8 100644 --- a/tests/MADE.Data.Validation.Tests/MADE.Data.Validation.Tests.csproj +++ b/tests/MADE.Data.Validation.Tests/MADE.Data.Validation.Tests.csproj @@ -1,8 +1,7 @@ - + - net5.0 - + net6.0;net5.0 false diff --git a/tests/MADE.Diagnostics.Tests/MADE.Diagnostics.Tests.csproj b/tests/MADE.Diagnostics.Tests/MADE.Diagnostics.Tests.csproj index b27c70b5..1953b2e8 100644 --- a/tests/MADE.Diagnostics.Tests/MADE.Diagnostics.Tests.csproj +++ b/tests/MADE.Diagnostics.Tests/MADE.Diagnostics.Tests.csproj @@ -1,8 +1,7 @@ - + - net5.0 - + net6.0;net5.0 false diff --git a/tests/MADE.Networking.Tests/MADE.Networking.Tests.csproj b/tests/MADE.Networking.Tests/MADE.Networking.Tests.csproj index 2afd97f2..b19edf2c 100644 --- a/tests/MADE.Networking.Tests/MADE.Networking.Tests.csproj +++ b/tests/MADE.Networking.Tests/MADE.Networking.Tests.csproj @@ -1,8 +1,7 @@ - + - net5.0 - + net6.0;net5.0 false diff --git a/tests/MADE.Web.Tests/MADE.Web.Tests.csproj b/tests/MADE.Web.Tests/MADE.Web.Tests.csproj index 9f73c485..abac3069 100644 --- a/tests/MADE.Web.Tests/MADE.Web.Tests.csproj +++ b/tests/MADE.Web.Tests/MADE.Web.Tests.csproj @@ -1,8 +1,7 @@ - + - net5.0 - + net6.0;net5.0 false From 47a86a2be53848e9aa60111b0bf1f99433934b82 Mon Sep 17 00:00:00 2001 From: James Croft Date: Tue, 26 Apr 2022 20:59:09 +0100 Subject: [PATCH 3/8] Updated documentation for data validation for FluentValidation --- docs/articles/features/data-validation.md | 18 ++++++++++++++---- docs/articles/intro.md | 1 + docs/index.md | 4 ++-- 3 files changed, 17 insertions(+), 6 deletions(-) diff --git a/docs/articles/features/data-validation.md b/docs/articles/features/data-validation.md index e6f924e6..0b16caf8 100644 --- a/docs/articles/features/data-validation.md +++ b/docs/articles/features/data-validation.md @@ -5,7 +5,7 @@ title: Using the Data Validation package # Using the Data Validation package -The Data Validation package is designed to provide out-of-the-box data validation to applications built with C#. +The Data Validation package is designed to provide out-of-the-box data validation to applications built with C#. ## Validating an object using the ValidatorCollection @@ -13,7 +13,7 @@ Data validation can be implemented in so many different ways. MADE provides the Using the `MADE.Data.Validation.ValidatorCollection` based on a `List` type, you can construct a collection of `IValidator` instances which can be used to validate values. -For example, you might want a collection of validators that ensure that a value is provided, it has a minimum length, and it contains only alphanumeric characters. +For example, you might want a collection of validators that ensure that a value is provided, it has a minimum length, and it contains only alphanumeric characters. Instead of implementing your own custom validation in your application, you can take advantage of the built-in `IValidator` implementation of this package and utilize them with the `ValidatorCollection`. @@ -102,7 +102,7 @@ The implementation splits the IP address into each nibble and validates them bas ### MaxValueValidator -The `MaxValueValidator` validates an `IComparable` value is less than a configurable maximum value. +The `MaxValueValidator` validates an `IComparable` value is less than a configurable maximum value. The maximum can be configured by setting the `Max` value. @@ -110,7 +110,7 @@ The in-box `System` types which implement the `IComparable` interface can be [fo ### MinValueValidator -The `MinValueValidator` validates an `IComparable` value is greater than a configurable minimum value. +The `MinValueValidator` validates an `IComparable` value is greater than a configurable minimum value. The minimum can be configured by setting the `Min` value. @@ -191,3 +191,13 @@ namespace MADE.Data.Validation.Validators ``` If there is a common data validator you think is missing from MADE.NET, [raise a tracking item on GitHub](https://github.com/MADE-Apps/MADE.NET/issues/new/choose) and we'll get it implemented. + +## Using FluentValidation with MADE.NET + +The `MADE.Data.Validation.FluentValidation` package provides an easy way to take advantage of validation with the [FluentValidation](https://fluentvalidation.net/) library validator framework. + +### Validating an object using the FluentValidatorCollection + +Using the `MADE.Data.Validation.FluentValidatorCollection` based on a `List` type, you can construct a collection of `AbstractValidator` instances which can be used to validate values. + +This way, you can bring FluentValidation's out-of-the-box validators or your own custom validators based on the `AbstractValidator` type and get all the benefits of using the existing MADE.NET validation framework. This is great for example with input validator controls that currently support the MADE.NET validation framework! diff --git a/docs/articles/intro.md b/docs/articles/intro.md index 78ae7879..2ffce0c4 100644 --- a/docs/articles/intro.md +++ b/docs/articles/intro.md @@ -29,6 +29,7 @@ dotnet add package MADE.Collections | MADE.Data.Converters | [![NuGet](https://img.shields.io/nuget/v/MADE.Data.Converters)](https://www.nuget.org/packages/MADE.Data.Converters/) | | MADE.Data.EFCore | [![NuGet](https://img.shields.io/nuget/v/MADE.Data.EFCore)](https://www.nuget.org/packages/MADE.Data.EFCore/) | | MADE.Data.Validation | [![NuGet](https://img.shields.io/nuget/v/MADE.Data.Validation)](https://www.nuget.org/packages/MADE.Data.Validation/) | +| MADE.Data.Validation.FluentValidation | [![NuGet](https://img.shields.io/nuget/v/MADE.Data.Validation.FluentValidation)](https://www.nuget.org/packages/MADE.Data.Validation.FluentValidation/) | | MADE.Diagnostics | [![NuGet](https://img.shields.io/nuget/v/MADE.Diagnostics)](https://www.nuget.org/packages/MADE.Diagnostics/) | | MADE.Media.Image | [![NuGet](https://img.shields.io/nuget/v/MADE.Media.Image)](https://www.nuget.org/packages/MADE.Media.Image/) | | MADE.Networking | [![NuGet](https://img.shields.io/nuget/v/MADE.Networking)](https://www.nuget.org/packages/MADE.Networking/) | diff --git a/docs/index.md b/docs/index.md index 604f45b1..47643481 100644 --- a/docs/index.md +++ b/docs/index.md @@ -106,7 +106,7 @@ title: Make App Development Easier
- v1.4.0 + v1.5.0
@@ -122,7 +122,7 @@ title: Make App Development Easier
- 225k+ + 275k+
From c1ec6aaac9d6cedbae43e5c55ac062a3ed2691dd Mon Sep 17 00:00:00 2001 From: James Croft Date: Tue, 26 Apr 2022 21:13:21 +0100 Subject: [PATCH 4/8] Reverted csproj changes to tests --- tests/MADE.Collections.Tests/MADE.Collections.Tests.csproj | 4 ++-- .../MADE.Data.Converters.Tests.csproj | 4 ++-- .../MADE.Data.Validation.FluentValidation.Tests.csproj | 4 ++-- .../MADE.Data.Validation.Tests.csproj | 4 ++-- tests/MADE.Diagnostics.Tests/MADE.Diagnostics.Tests.csproj | 4 ++-- tests/MADE.Networking.Tests/MADE.Networking.Tests.csproj | 4 ++-- tests/MADE.Web.Tests/MADE.Web.Tests.csproj | 4 ++-- 7 files changed, 14 insertions(+), 14 deletions(-) diff --git a/tests/MADE.Collections.Tests/MADE.Collections.Tests.csproj b/tests/MADE.Collections.Tests/MADE.Collections.Tests.csproj index e4c5e5cc..ea4862fc 100644 --- a/tests/MADE.Collections.Tests/MADE.Collections.Tests.csproj +++ b/tests/MADE.Collections.Tests/MADE.Collections.Tests.csproj @@ -1,7 +1,7 @@ - + - net6.0;net5.0 + net6.0 false diff --git a/tests/MADE.Data.Converters.Tests/MADE.Data.Converters.Tests.csproj b/tests/MADE.Data.Converters.Tests/MADE.Data.Converters.Tests.csproj index 2c3bc5b5..0bd36bee 100644 --- a/tests/MADE.Data.Converters.Tests/MADE.Data.Converters.Tests.csproj +++ b/tests/MADE.Data.Converters.Tests/MADE.Data.Converters.Tests.csproj @@ -1,7 +1,7 @@ - + - net6.0;net5.0 + net6.0 false diff --git a/tests/MADE.Data.Validation.FluentValidation.Tests/MADE.Data.Validation.FluentValidation.Tests.csproj b/tests/MADE.Data.Validation.FluentValidation.Tests/MADE.Data.Validation.FluentValidation.Tests.csproj index a0a9c256..f2dc5e79 100644 --- a/tests/MADE.Data.Validation.FluentValidation.Tests/MADE.Data.Validation.FluentValidation.Tests.csproj +++ b/tests/MADE.Data.Validation.FluentValidation.Tests/MADE.Data.Validation.FluentValidation.Tests.csproj @@ -1,7 +1,7 @@ - + - net6.0;net5.0 + net6.0 false diff --git a/tests/MADE.Data.Validation.Tests/MADE.Data.Validation.Tests.csproj b/tests/MADE.Data.Validation.Tests/MADE.Data.Validation.Tests.csproj index 372b5bf8..822da442 100644 --- a/tests/MADE.Data.Validation.Tests/MADE.Data.Validation.Tests.csproj +++ b/tests/MADE.Data.Validation.Tests/MADE.Data.Validation.Tests.csproj @@ -1,7 +1,7 @@ - + - net6.0;net5.0 + net6.0 false diff --git a/tests/MADE.Diagnostics.Tests/MADE.Diagnostics.Tests.csproj b/tests/MADE.Diagnostics.Tests/MADE.Diagnostics.Tests.csproj index 1953b2e8..942c3256 100644 --- a/tests/MADE.Diagnostics.Tests/MADE.Diagnostics.Tests.csproj +++ b/tests/MADE.Diagnostics.Tests/MADE.Diagnostics.Tests.csproj @@ -1,7 +1,7 @@ - + - net6.0;net5.0 + net6.0 false diff --git a/tests/MADE.Networking.Tests/MADE.Networking.Tests.csproj b/tests/MADE.Networking.Tests/MADE.Networking.Tests.csproj index b19edf2c..40f80ed3 100644 --- a/tests/MADE.Networking.Tests/MADE.Networking.Tests.csproj +++ b/tests/MADE.Networking.Tests/MADE.Networking.Tests.csproj @@ -1,7 +1,7 @@ - + - net6.0;net5.0 + net6.0 false diff --git a/tests/MADE.Web.Tests/MADE.Web.Tests.csproj b/tests/MADE.Web.Tests/MADE.Web.Tests.csproj index abac3069..74101e25 100644 --- a/tests/MADE.Web.Tests/MADE.Web.Tests.csproj +++ b/tests/MADE.Web.Tests/MADE.Web.Tests.csproj @@ -1,7 +1,7 @@ - + - net6.0;net5.0 + net6.0 false From 2bb3d91b374803bdc7501a453562abba155b4fd7 Mon Sep 17 00:00:00 2001 From: James Croft Date: Wed, 27 Apr 2022 06:48:02 +0100 Subject: [PATCH 5/8] Updated CI to use main solution file for building --- .github/workflows/ci.yml | 2 +- MADE.NET.NoSamples.slnf | 26 -------------------------- 2 files changed, 1 insertion(+), 27 deletions(-) delete mode 100644 MADE.NET.NoSamples.slnf diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index c8148607..a6a14a6b 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -30,7 +30,7 @@ jobs: env: BUILD_CONFIG: 'Release' - SOLUTION: 'MADE.NET.NoSamples.slnf' + SOLUTION: 'MADE.NET.sln' runs-on: windows-latest diff --git a/MADE.NET.NoSamples.slnf b/MADE.NET.NoSamples.slnf deleted file mode 100644 index 890bca2b..00000000 --- a/MADE.NET.NoSamples.slnf +++ /dev/null @@ -1,26 +0,0 @@ -{ - "solution": { - "path": "MADE.NET.sln", - "projects": [ - "src\\MADE.Collections\\MADE.Collections.csproj", - "src\\MADE.Data.Converters\\MADE.Data.Converters.csproj", - "src\\MADE.Data.EFCore\\MADE.Data.EFCore.csproj", - "src\\MADE.Data.Validation\\MADE.Data.Validation.csproj", - "src\\MADE.Diagnostics\\MADE.Diagnostics.csproj", - "src\\MADE.Foundation\\MADE.Foundation.csproj", - "src\\MADE.Media.Image\\MADE.Media.Image.csproj", - "src\\MADE.Networking\\MADE.Networking.csproj", - "src\\MADE.Runtime\\MADE.Runtime.csproj", - "src\\MADE.Testing\\MADE.Testing.csproj", - "src\\MADE.Threading\\MADE.Threading.csproj", - "src\\MADE.Web\\MADE.Web.csproj", - "src\\MADE.Web.Mvc\\MADE.Web.Mvc.csproj", - "tests\\MADE.Collections.Tests\\MADE.Collections.Tests.csproj", - "tests\\MADE.Data.Converters.Tests\\MADE.Data.Converters.Tests.csproj", - "tests\\MADE.Data.Validation.Tests\\MADE.Data.Validation.Tests.csproj", - "tests\\MADE.Diagnostics.Tests\\MADE.Diagnostics.Tests.csproj", - "tests\\MADE.Networking.Tests\\MADE.Networking.Tests.csproj", - "tests\\MADE.Web.Tests\\MADE.Web.Tests.csproj" - ] - } -} \ No newline at end of file From a0d0d1e8601ac56002cb193ed80dddbe3854527f Mon Sep 17 00:00:00 2001 From: James Croft Date: Wed, 27 Apr 2022 06:48:36 +0100 Subject: [PATCH 6/8] Updated coverlet package --- tests/MADE.Collections.Tests/MADE.Collections.Tests.csproj | 2 +- .../MADE.Data.Converters.Tests.csproj | 2 +- .../MADE.Data.Validation.FluentValidation.Tests.csproj | 2 +- .../MADE.Data.Validation.Tests.csproj | 2 +- tests/MADE.Diagnostics.Tests/MADE.Diagnostics.Tests.csproj | 2 +- tests/MADE.Networking.Tests/MADE.Networking.Tests.csproj | 2 +- tests/MADE.Web.Tests/MADE.Web.Tests.csproj | 2 +- 7 files changed, 7 insertions(+), 7 deletions(-) diff --git a/tests/MADE.Collections.Tests/MADE.Collections.Tests.csproj b/tests/MADE.Collections.Tests/MADE.Collections.Tests.csproj index ea4862fc..478881a6 100644 --- a/tests/MADE.Collections.Tests/MADE.Collections.Tests.csproj +++ b/tests/MADE.Collections.Tests/MADE.Collections.Tests.csproj @@ -7,7 +7,7 @@ - + all runtime; build; native; contentfiles; analyzers; buildtransitive diff --git a/tests/MADE.Data.Converters.Tests/MADE.Data.Converters.Tests.csproj b/tests/MADE.Data.Converters.Tests/MADE.Data.Converters.Tests.csproj index 0bd36bee..5d853ea2 100644 --- a/tests/MADE.Data.Converters.Tests/MADE.Data.Converters.Tests.csproj +++ b/tests/MADE.Data.Converters.Tests/MADE.Data.Converters.Tests.csproj @@ -7,7 +7,7 @@ - + all runtime; build; native; contentfiles; analyzers; buildtransitive diff --git a/tests/MADE.Data.Validation.FluentValidation.Tests/MADE.Data.Validation.FluentValidation.Tests.csproj b/tests/MADE.Data.Validation.FluentValidation.Tests/MADE.Data.Validation.FluentValidation.Tests.csproj index f2dc5e79..b5b92d6b 100644 --- a/tests/MADE.Data.Validation.FluentValidation.Tests/MADE.Data.Validation.FluentValidation.Tests.csproj +++ b/tests/MADE.Data.Validation.FluentValidation.Tests/MADE.Data.Validation.FluentValidation.Tests.csproj @@ -7,7 +7,7 @@ - + all runtime; build; native; contentfiles; analyzers; buildtransitive diff --git a/tests/MADE.Data.Validation.Tests/MADE.Data.Validation.Tests.csproj b/tests/MADE.Data.Validation.Tests/MADE.Data.Validation.Tests.csproj index 822da442..f07f1f26 100644 --- a/tests/MADE.Data.Validation.Tests/MADE.Data.Validation.Tests.csproj +++ b/tests/MADE.Data.Validation.Tests/MADE.Data.Validation.Tests.csproj @@ -7,7 +7,7 @@ - + all runtime; build; native; contentfiles; analyzers; buildtransitive diff --git a/tests/MADE.Diagnostics.Tests/MADE.Diagnostics.Tests.csproj b/tests/MADE.Diagnostics.Tests/MADE.Diagnostics.Tests.csproj index 942c3256..66957bc4 100644 --- a/tests/MADE.Diagnostics.Tests/MADE.Diagnostics.Tests.csproj +++ b/tests/MADE.Diagnostics.Tests/MADE.Diagnostics.Tests.csproj @@ -7,7 +7,7 @@ - + all runtime; build; native; contentfiles; analyzers; buildtransitive diff --git a/tests/MADE.Networking.Tests/MADE.Networking.Tests.csproj b/tests/MADE.Networking.Tests/MADE.Networking.Tests.csproj index 40f80ed3..e311023d 100644 --- a/tests/MADE.Networking.Tests/MADE.Networking.Tests.csproj +++ b/tests/MADE.Networking.Tests/MADE.Networking.Tests.csproj @@ -7,7 +7,7 @@ - + all runtime; build; native; contentfiles; analyzers; buildtransitive diff --git a/tests/MADE.Web.Tests/MADE.Web.Tests.csproj b/tests/MADE.Web.Tests/MADE.Web.Tests.csproj index 74101e25..1b03ce8a 100644 --- a/tests/MADE.Web.Tests/MADE.Web.Tests.csproj +++ b/tests/MADE.Web.Tests/MADE.Web.Tests.csproj @@ -7,7 +7,7 @@ - + all runtime; build; native; contentfiles; analyzers; buildtransitive From 8504af28017456bf64a12803b6127be34dfb9abc Mon Sep 17 00:00:00 2001 From: James Croft Date: Wed, 27 Apr 2022 09:24:58 +0100 Subject: [PATCH 7/8] Updated CI --- .github/workflows/ci.yml | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index a6a14a6b..50516f42 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -55,11 +55,8 @@ jobs: with: dotnet-version: 6.0.x - - name: Setup NuGet - uses: NuGet/setup-nuget@v1.0.5 - - name: Restore dependencies - run: nuget restore $SOLUTION + run: dotnet restore $SOLUTION - name: Setup MSBuild uses: microsoft/setup-msbuild@v1.0.2 From 3ced1656dcc84c4d62ea70051755a3220c08fb98 Mon Sep 17 00:00:00 2001 From: James Croft Date: Wed, 27 Apr 2022 10:16:00 +0100 Subject: [PATCH 8/8] Updated FluentValidatorCollection to support interface to allow for complex collections --- .../FluentValidatorCollection{T}.cs | 5 +- .../Tests/FluentValidatorCollectionTests.cs | 57 +++++++++++++++++++ 2 files changed, 59 insertions(+), 3 deletions(-) diff --git a/src/MADE.Data.Validation.FluentValidation/FluentValidatorCollection{T}.cs b/src/MADE.Data.Validation.FluentValidation/FluentValidatorCollection{T}.cs index 97001eff..818e1965 100644 --- a/src/MADE.Data.Validation.FluentValidation/FluentValidatorCollection{T}.cs +++ b/src/MADE.Data.Validation.FluentValidation/FluentValidatorCollection{T}.cs @@ -11,8 +11,7 @@ namespace MADE.Data.Validation /// Defines a list of objects that can be accessed by index. /// /// The type of item being validated. - public class FluentValidatorCollection : List>, IValidatorCollection - where T : class + public class FluentValidatorCollection : List>, IValidatorCollection { private readonly List feedbackMessages = new(); @@ -71,7 +70,7 @@ public void Validate(object value) this.ForEach(validator => { - var result = validator.Validate(value as T); + var result = validator.Validate((T)value); if (!result.IsValid) { IsInvalid = true; diff --git a/tests/MADE.Data.Validation.FluentValidation.Tests/Tests/FluentValidatorCollectionTests.cs b/tests/MADE.Data.Validation.FluentValidation.Tests/Tests/FluentValidatorCollectionTests.cs index 88e8ddca..44689a2f 100644 --- a/tests/MADE.Data.Validation.FluentValidation.Tests/Tests/FluentValidatorCollectionTests.cs +++ b/tests/MADE.Data.Validation.FluentValidation.Tests/Tests/FluentValidatorCollectionTests.cs @@ -4,7 +4,10 @@ namespace MADE.Data.Validation.FluentValidation.Tests.Tests using System.Collections.Generic; using System.Diagnostics.CodeAnalysis; using System.Linq; + using System.Threading; + using System.Threading.Tasks; using global::FluentValidation; + using global::FluentValidation.Results; using MADE.Testing; using NUnit.Framework; using Shouldly; @@ -147,6 +150,32 @@ public void ShouldHaveFeedbackMessagesIfInvalidValue() collection.FeedbackMessages.Count().ShouldBe(1); collection.FeedbackMessages.FirstOrDefault().ShouldBe(PersonValidator.DateOfBirthValidationMessage); } + + [Test] + public void ShouldValidateComplexObjectWithMultipleValidators() + { + // Arrange + var value = new Staff + { + Name = "Joe Bloggs", + JobTitle = null, // Invalid job title + Department = "Build", + DateOfBirth = DateTime.UtcNow.AddDays(1) // Invalid birth date + }; + + var collection = new FluentValidatorCollection { new PersonValidator(), new StaffValidator() }; + + // Act + collection.Validate(value); + + // Assert + collection.FeedbackMessages.ShouldNotBeEmpty(); + collection.FeedbackMessages.Count().ShouldBe(2); + collection.FeedbackMessages.FirstOrDefault(x => x.Equals(PersonValidator.DateOfBirthValidationMessage, + StringComparison.InvariantCultureIgnoreCase)).ShouldNotBeNull(); + collection.FeedbackMessages.FirstOrDefault(x => x.Equals(StaffValidator.JobTitleValidationMessage, + StringComparison.InvariantCultureIgnoreCase)).ShouldNotBeNull(); + } } } @@ -157,6 +186,13 @@ public class Person public DateTime? DateOfBirth { get; set; } } + public class Staff : Person + { + public string JobTitle { get; set; } + + public string Department { get; set; } + } + public class PersonValidator : AbstractValidator { public const string DateOfBirthValidationMessage = "Please specify a valid date of birth"; @@ -170,4 +206,25 @@ public PersonValidator() .WithMessage(DateOfBirthValidationMessage); } } + + public class StaffValidator : AbstractValidator, IValidator + { + public const string JobTitleValidationMessage = "Please specify a job title"; + + public StaffValidator() + { + this.RuleFor(x => x.JobTitle).NotEmpty().WithMessage(JobTitleValidationMessage); + this.RuleFor(x => x.Department).NotEmpty(); + } + + public ValidationResult Validate(Person instance) + { + return base.Validate(instance as Staff); + } + + public Task ValidateAsync(Person instance, CancellationToken cancellation = new()) + { + return base.ValidateAsync(instance as Staff, cancellation); + } + } } \ No newline at end of file